aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS3
-rw-r--r--ChangeLog991
-rw-r--r--INSTALL21
-rw-r--r--INSTALL-cross378
-rw-r--r--Makeconf468
-rw-r--r--Makefile134
-rw-r--r--NEWS696
-rw-r--r--README19
-rw-r--r--README.CVS29
-rw-r--r--SETUP11
-rw-r--r--TODO345
-rw-r--r--aclocal.m482
-rw-r--r--auth/ChangeLog148
-rw-r--r--auth/Makefile5
-rw-r--r--auth/auth.c302
-rw-r--r--benchmarks/ChangeLog9
-rw-r--r--benchmarks/forks.c18
-rw-r--r--boot/ChangeLog586
-rw-r--r--boot/Makefile15
-rw-r--r--boot/boot.c852
-rw-r--r--boot/boot_script.c199
-rw-r--r--boot/boot_script.h40
-rw-r--r--boot/tcattr.c592
-rw-r--r--boot/userland-boot.c108
-rw-r--r--bsdfsck/ChangeLog98
-rw-r--r--bsdfsck/fsck.h2
-rw-r--r--bsdfsck/preen.c2
-rw-r--r--bsdfsck/utilities.c2
-rwxr-xr-xconfig.guess1479
-rw-r--r--config.make.in54
-rwxr-xr-xconfig.sub1606
-rw-r--r--config/ChangeLog113
-rw-r--r--config/Makefile42
-rw-r--r--config/fstab5
-rw-r--r--config/group2
-rw-r--r--config/login-.bash_login4
-rw-r--r--config/login-.bashrc6
-rw-r--r--config/login-README5
-rw-r--r--config/passwd9
-rw-r--r--config/protocols103
-rw-r--r--config/resolv.conf3
-rw-r--r--config/root-.bash_login5
-rw-r--r--config/root-.bashrc18
-rw-r--r--config/root-.profile16
-rw-r--r--config/services183
-rw-r--r--config/shells16
-rw-r--r--config/ttys12
-rwxr-xr-xconfigure5868
-rw-r--r--configure.in223
-rw-r--r--console-client/Makefile93
-rw-r--r--console-client/bdf.c990
-rw-r--r--console-client/bdf.h272
-rw-r--r--console-client/bell.h56
-rw-r--r--console-client/console.c642
-rw-r--r--console-client/current-vcs.c223
-rw-r--r--console-client/display.h154
-rw-r--r--console-client/driver.c361
-rw-r--r--console-client/driver.h289
-rw-r--r--console-client/generic-speaker.c554
-rw-r--r--console-client/input.h99
-rw-r--r--console-client/kbd-repeat.c258
-rw-r--r--console-client/mach-inputdev.h138
-rw-r--r--console-client/ncursesw.c745
-rw-r--r--console-client/pc-kbd.c1194
-rw-r--r--console-client/pc-mouse.c509
-rw-r--r--console-client/timer.c210
-rw-r--r--console-client/timer.h72
-rw-r--r--console-client/trans.c892
-rw-r--r--console-client/trans.h81
-rw-r--r--console-client/unicode.h350
-rw-r--r--console-client/vga-dynacolor.c322
-rw-r--r--console-client/vga-dynacolor.h108
-rw-r--r--console-client/vga-dynafont.c1072
-rw-r--r--console-client/vga-dynafont.h83
-rw-r--r--console-client/vga-hw.h139
-rw-r--r--console-client/vga-support.c442
-rw-r--r--console-client/vga-support.h89
-rw-r--r--console-client/vga.c840
-rw-r--r--console/Makefile47
-rw-r--r--console/README.UTF8143
-rw-r--r--console/console.c2093
-rw-r--r--console/display.c2138
-rw-r--r--console/display.h84
-rw-r--r--console/hurd.ti164
-rw-r--r--console/input.c277
-rw-r--r--console/input.h58
-rw-r--r--console/motd.UTF84
-rw-r--r--console/mutations.h27
-rw-r--r--console/pager.c221
-rw-r--r--console/pager.h47
-rw-r--r--console/priv.h (renamed from libmom/deallocate-memory.c)30
-rw-r--r--daemons/ChangeLog62
-rw-r--r--daemons/Makefile25
-rw-r--r--daemons/console-run.c220
-rw-r--r--daemons/getty.c49
-rw-r--r--daemons/lmail.c542
-rw-r--r--daemons/rc.sh60
-rw-r--r--daemons/runsystem.sh142
-rw-r--r--daemons/runttys.c502
-rw-r--r--defpager/ChangeLog5
-rw-r--r--defpager/Makefile10
-rw-r--r--defpager/backing.c131
-rw-r--r--defpager/defpager.c143
-rw-r--r--defpager/wiring.c111
-rw-r--r--devio/ChangeLog265
-rw-r--r--devio/MAKEDEV80
-rw-r--r--devio/dev.c227
-rw-r--r--devio/dev.h147
-rw-r--r--devio/devio.c359
-rw-r--r--devio/devpager.c257
-rw-r--r--devio/iostate.c79
-rw-r--r--devio/iostate.h67
-rw-r--r--devio/mem.c57
-rw-r--r--devio/mem.h33
-rw-r--r--devio/open.c90
-rw-r--r--devio/rdwr.c471
-rw-r--r--devio/window.c171
-rw-r--r--devio/window.h84
-rw-r--r--doc/ChangeLog4
-rw-r--r--doc/Makefile47
-rw-r--r--doc/gpl.texinfo396
-rw-r--r--doc/hurd.texi5047
-rw-r--r--doc/navigating54
-rw-r--r--doc/version.texi1
-rw-r--r--exec/ChangeLog643
-rw-r--r--exec/Makefile26
-rw-r--r--exec/core.c264
-rw-r--r--exec/do-bunzip2.c1745
-rw-r--r--exec/elfcore.c630
-rw-r--r--exec/exec.c752
-rw-r--r--exec/execmutations.h2
-rw-r--r--exec/exectrans.c81
-rw-r--r--exec/gcore.c88
-rw-r--r--exec/hashexec.c205
-rw-r--r--exec/hostarch.c77
-rw-r--r--exec/main.c153
-rw-r--r--exec/priv.h71
-rw-r--r--ext2fs/ChangeLog588
-rw-r--r--ext2fs/Makefile18
-rw-r--r--ext2fs/balloc.c149
-rw-r--r--ext2fs/bitmap.c55
-rw-r--r--ext2fs/devio.c51
-rw-r--r--ext2fs/dir.c469
-rw-r--r--ext2fs/ext2_fs.h506
-rw-r--r--ext2fs/ext2_fs_i.h32
-rw-r--r--ext2fs/ext2fs.c196
-rw-r--r--ext2fs/ext2fs.h190
-rw-r--r--ext2fs/getblk.c38
-rw-r--r--ext2fs/hyper.c107
-rw-r--r--ext2fs/ialloc.c38
-rw-r--r--ext2fs/inode.c378
-rw-r--r--ext2fs/msg.c7
-rw-r--r--ext2fs/pager.c301
-rw-r--r--ext2fs/storeinfo.c207
-rw-r--r--ext2fs/truncate.c51
-rw-r--r--ext2fs/xinl.c2
-rw-r--r--fatfs/Makefile30
-rw-r--r--fatfs/dir.c999
-rw-r--r--fatfs/fat.c761
-rw-r--r--fatfs/fat.h399
-rw-r--r--fatfs/fatfs.h128
-rw-r--r--fatfs/inode.c784
-rw-r--r--fatfs/main.c281
-rw-r--r--fatfs/node-create.c204
-rw-r--r--fatfs/pager.c1022
-rw-r--r--fatfs/virt-inode.c235
-rw-r--r--fatfs/virt-inode.h69
-rw-r--r--fstests/ChangeLog47
-rw-r--r--fstests/fstests.c46
-rw-r--r--fstests/timertest.c24
-rw-r--r--ftpfs/Makefile (renamed from devio/Makefile)22
-rw-r--r--ftpfs/ccache.c293
-rw-r--r--ftpfs/ccache.h73
-rw-r--r--ftpfs/conn.c106
-rw-r--r--ftpfs/dir.c885
-rw-r--r--ftpfs/fs.c86
-rw-r--r--ftpfs/ftpfs.c430
-rw-r--r--ftpfs/ftpfs.h250
-rw-r--r--ftpfs/host.c154
-rw-r--r--ftpfs/ncache.c87
-rw-r--r--ftpfs/netfs.c463
-rw-r--r--ftpfs/node.c114
-rw-r--r--hostmux/Makefile30
-rw-r--r--hostmux/hostmux-xinl.c (renamed from libmom/priv.h)15
-rw-r--r--hostmux/hostmux.c169
-rw-r--r--hostmux/hostmux.h95
-rw-r--r--hostmux/leaf.c124
-rw-r--r--hostmux/mux.c457
-rw-r--r--hostmux/node.c127
-rw-r--r--hostmux/stubs.c145
-rw-r--r--hurd.boot4
-rw-r--r--hurd/=pending-changes16
-rw-r--r--hurd/ChangeLog844
-rw-r--r--hurd/Makefile57
-rw-r--r--hurd/auth.defs5
-rw-r--r--hurd/auth_reply.defs9
-rw-r--r--hurd/auth_request.defs36
-rwxr-xr-xhurd/configure2182
-rw-r--r--hurd/configure.ac11
-rw-r--r--hurd/console.h309
-rw-r--r--hurd/crash_reply.defs4
-rw-r--r--hurd/default_pager.defs95
-rw-r--r--hurd/default_pager_reply.defs17
-rw-r--r--hurd/default_pager_types.h (renamed from libdiskfs/init-loop.c)20
-rw-r--r--hurd/exec.defs16
-rw-r--r--hurd/fs.defs63
-rw-r--r--hurd/fs_notify.defs31
-rw-r--r--hurd/fsys.defs10
-rw-r--r--hurd/fsys_reply.defs29
-rw-r--r--hurd/gensym.awk78
-rw-r--r--hurd/hurd_types.defs54
-rw-r--r--hurd/hurd_types.h63
-rw-r--r--hurd/iioctl.defs179
-rwxr-xr-xhurd/install-headers.in22
-rw-r--r--hurd/io.defs32
-rw-r--r--hurd/io_reply.defs68
-rw-r--r--hurd/io_request.defs16
-rw-r--r--hurd/ioctl-decode.h15
-rw-r--r--hurd/ioctl-tmpl.sym13
-rw-r--r--hurd/ioctl.awk127
-rw-r--r--hurd/ioctl_types.h4
-rw-r--r--hurd/ioctls.defs48
-rw-r--r--hurd/kdioctl.defs (renamed from libtrivfs/interrupt.c)41
-rw-r--r--hurd/msg.defs6
-rw-r--r--hurd/msg_reply.defs8
-rw-r--r--hurd/newterm.defs8
-rw-r--r--hurd/password.defs50
-rw-r--r--hurd/paths.h7
-rw-r--r--hurd/pfinet.defs77
-rw-r--r--hurd/process.defs41
-rw-r--r--hurd/process_reply.defs13
-rw-r--r--hurd/process_request.defs45
-rw-r--r--hurd/socket.defs8
-rw-r--r--hurd/startup.defs6
-rw-r--r--hurd/startup_reply.defs10
-rw-r--r--hurd/subsystems1
-rw-r--r--hurd/term.defs13
-rw-r--r--hurd/tioctl.defs11
-rw-r--r--hurd/version.h88
-rw-r--r--include/ChangeLog4
-rw-r--r--include/Makefile16
-rw-r--r--include/sys/procfs.h120
-rw-r--r--init/ChangeLog491
-rw-r--r--init/Makefile18
-rw-r--r--init/init.c1355
-rw-r--r--init/stubs.c139
-rw-r--r--install-sh519
-rw-r--r--isofs/EXTENSIONS16
-rw-r--r--isofs/Makefile31
-rw-r--r--isofs/ext.c60
-rw-r--r--isofs/inode.c634
-rw-r--r--isofs/iso9660.h125
-rw-r--r--isofs/isofs.h94
-rw-r--r--isofs/lookup.c457
-rw-r--r--isofs/main.c170
-rw-r--r--isofs/pager.c352
-rw-r--r--isofs/rr.c649
-rw-r--r--isofs/rr.h266
-rw-r--r--libcons/Makefile38
-rw-r--r--libcons/cons-lookup.c107
-rw-r--r--libcons/cons-switch.c88
-rw-r--r--libcons/cons.h331
-rw-r--r--libcons/demuxer.c (renamed from libmom/refs-identical.c)16
-rw-r--r--libcons/dir-changed.c129
-rw-r--r--libcons/extra-version.c (renamed from libihash/priv.h)11
-rw-r--r--libcons/file-changed.c366
-rw-r--r--libcons/init-init.c97
-rw-r--r--libcons/init-loop.c32
-rw-r--r--libcons/mutations.h (renamed from libmom/memory-init.c)19
-rw-r--r--libcons/opts-std-startup.c229
-rw-r--r--libcons/opts-version.c44
-rw-r--r--libcons/priv.h93
-rw-r--r--libcons/vcons-add.c (renamed from libmom/mach-port-set.c)20
-rw-r--r--libcons/vcons-close.c (renamed from pfinet/devices.c)52
-rw-r--r--libcons/vcons-destroy.c52
-rw-r--r--libcons/vcons-event.c (renamed from libmom/fetch-mach-port.c)16
-rw-r--r--libcons/vcons-input.c64
-rw-r--r--libcons/vcons-move-mouse.c103
-rw-r--r--libcons/vcons-open.c175
-rw-r--r--libcons/vcons-refresh.c76
-rw-r--r--libcons/vcons-remove.c31
-rw-r--r--libcons/vcons-scrollback.c164
-rw-r--r--libdirmgt/ChangeLog5
-rw-r--r--libdiskfs/=exc.c141
-rw-r--r--libdiskfs/ChangeLog2492
-rw-r--r--libdiskfs/Makefile44
-rw-r--r--libdiskfs/boot-parse.c193
-rw-r--r--libdiskfs/boot-start.c384
-rw-r--r--libdiskfs/conch-fetch.c4
-rw-r--r--libdiskfs/console.c30
-rw-r--r--libdiskfs/dev-globals.c46
-rw-r--r--libdiskfs/dev-io.c54
-rw-r--r--libdiskfs/dev-open.c66
-rw-r--r--libdiskfs/dir-chg.c50
-rw-r--r--libdiskfs/dir-clear.c2
-rw-r--r--libdiskfs/dir-init.c10
-rw-r--r--libdiskfs/dir-link.c30
-rw-r--r--libdiskfs/dir-lookup.c246
-rw-r--r--libdiskfs/dir-mkdir.c7
-rw-r--r--libdiskfs/dir-mkfile.c35
-rw-r--r--libdiskfs/dir-readdir.c10
-rw-r--r--libdiskfs/dir-rename.c24
-rw-r--r--libdiskfs/dir-renamed.c62
-rw-r--r--libdiskfs/dir-rmdir.c60
-rw-r--r--libdiskfs/dir-unlink.c18
-rw-r--r--libdiskfs/direnter.c9
-rw-r--r--libdiskfs/dirremove.c17
-rw-r--r--libdiskfs/dirrewrite.c13
-rw-r--r--libdiskfs/disk-pager.c68
-rw-r--r--libdiskfs/diskfs-pager.h20
-rw-r--r--libdiskfs/diskfs.h600
-rw-r--r--libdiskfs/extern-inline.c (renamed from libdiskfs/ports-consts.c)8
-rw-r--r--libdiskfs/extra-version.c (renamed from libmom/wire-memory.c)12
-rw-r--r--libdiskfs/fhandle.h36
-rw-r--r--libdiskfs/file-access.c6
-rw-r--r--libdiskfs/file-chauthor.c5
-rw-r--r--libdiskfs/file-chflags.c12
-rw-r--r--libdiskfs/file-chg.c50
-rw-r--r--libdiskfs/file-chmod.c56
-rw-r--r--libdiskfs/file-chown.c36
-rw-r--r--libdiskfs/file-exec.c152
-rw-r--r--libdiskfs/file-get-fs-opts.c22
-rw-r--r--libdiskfs/file-get-trans.c42
-rw-r--r--libdiskfs/file-get-transcntl.c9
-rw-r--r--libdiskfs/file-getcontrol.c40
-rw-r--r--libdiskfs/file-getfh.c68
-rw-r--r--libdiskfs/file-inv-trans.c160
-rw-r--r--libdiskfs/file-reparent.c70
-rw-r--r--libdiskfs/file-set-size.c12
-rw-r--r--libdiskfs/file-set-trans.c16
-rw-r--r--libdiskfs/file-statfs.c22
-rw-r--r--libdiskfs/file-utimes.c30
-rw-r--r--libdiskfs/filedev.c135
-rw-r--r--libdiskfs/fsmutations.h10
-rw-r--r--libdiskfs/fsys-getfile.c126
-rw-r--r--libdiskfs/fsys-getroot.c101
-rw-r--r--libdiskfs/fsys-options.c16
-rw-r--r--libdiskfs/ifsock.c2
-rw-r--r--libdiskfs/init-first.c22
-rw-r--r--libdiskfs/init-init.c21
-rw-r--r--libdiskfs/init-main.c78
-rw-r--r--libdiskfs/init-startup.c116
-rw-r--r--libdiskfs/io-duplicate.c3
-rw-r--r--libdiskfs/io-identity.c34
-rw-r--r--libdiskfs/io-map-cntl.c6
-rw-r--r--libdiskfs/io-map.c13
-rw-r--r--libdiskfs/io-pathconf.c56
-rw-r--r--libdiskfs/io-prenotify.c6
-rw-r--r--libdiskfs/io-read.c44
-rw-r--r--libdiskfs/io-reauthenticate.c63
-rw-r--r--libdiskfs/io-restrict-auth.c43
-rw-r--r--libdiskfs/io-revoke.c59
-rw-r--r--libdiskfs/io-seek.c64
-rw-r--r--libdiskfs/io-stat.c17
-rw-r--r--libdiskfs/io-version.c10
-rw-r--r--libdiskfs/io-write.c13
-rw-r--r--libdiskfs/lithp.h3
-rw-r--r--libdiskfs/lookup.c191
-rw-r--r--libdiskfs/machdev.c92
-rw-r--r--libdiskfs/name-cache.c128
-rw-r--r--libdiskfs/node-create.c68
-rw-r--r--libdiskfs/node-drop.c28
-rw-r--r--libdiskfs/node-make.c17
-rw-r--r--libdiskfs/node-nput.c75
-rw-r--r--libdiskfs/node-nputl.c (renamed from libmom/make-memory-readonly.c)30
-rw-r--r--libdiskfs/node-nref.c40
-rw-r--r--libdiskfs/node-nrefl.c (renamed from libmom/ref-destroy.c)15
-rw-r--r--libdiskfs/node-nrele.c65
-rw-r--r--libdiskfs/node-nrelel.c (renamed from libmom/make-memory-readwrite.c)31
-rw-r--r--libdiskfs/node-rdwr.c2
-rw-r--r--libdiskfs/node-times.c64
-rw-r--r--libdiskfs/notify-stubs.c71
-rw-r--r--libdiskfs/opts-append-std.c42
-rw-r--r--libdiskfs/opts-common.c28
-rw-r--r--libdiskfs/opts-get.c9
-rw-r--r--libdiskfs/opts-runtime.c3
-rw-r--r--libdiskfs/opts-set.c4
-rw-r--r--libdiskfs/opts-std-runtime.c47
-rw-r--r--libdiskfs/opts-std-startup.c125
-rw-r--r--libdiskfs/opts-version.c17
-rw-r--r--libdiskfs/ourfs_notify.defs5
-rw-r--r--libdiskfs/peropen-make.c44
-rw-r--r--libdiskfs/peropen-rele.c22
-rw-r--r--libdiskfs/ports-clean.c29
-rw-r--r--libdiskfs/priv.h68
-rw-r--r--libdiskfs/protid-make.c46
-rw-r--r--libdiskfs/protid-rele.c8
-rw-r--r--libdiskfs/rdwr-internal.c13
-rw-r--r--libdiskfs/readonly-changed.c (renamed from libdiskfs/opts-runtime-parse.c)19
-rw-r--r--libdiskfs/readonly.c30
-rw-r--r--libdiskfs/shutdown.c25
-rw-r--r--libdiskfs/sync-default.c6
-rw-r--r--libdiskfs/sync-interval.c19
-rw-r--r--libdiskfs/trans-callback.c37
-rw-r--r--libfshelp/ChangeLog430
-rw-r--r--libfshelp/Makefile15
-rw-r--r--libfshelp/delegate.c18
-rw-r--r--libfshelp/exec-reauth.c19
-rw-r--r--libfshelp/fetch-root.c151
-rw-r--r--libfshelp/fshelp.h110
-rw-r--r--libfshelp/get-identity.c16
-rw-r--r--libfshelp/lock-acquire.c14
-rw-r--r--libfshelp/perms-access.c43
-rw-r--r--libfshelp/perms-checkdirmod.c (renamed from libmom/unuse-memory.c)39
-rw-r--r--libfshelp/perms-iscontroller.c38
-rw-r--r--libfshelp/perms-isowner.c (renamed from libmom/reserve-memory-anywhere.c)35
-rw-r--r--libfshelp/set-options.c6
-rw-r--r--libfshelp/start-translator-long.c166
-rw-r--r--libfshelp/start-translator.c17
-rw-r--r--libfshelp/touch.c49
-rw-r--r--libfshelp/translated.c28
-rw-r--r--libftpconn/Makefile34
-rw-r--r--libftpconn/addr.c79
-rw-r--r--libftpconn/cmd.c169
-rw-r--r--libftpconn/create.c87
-rw-r--r--libftpconn/cwd.c113
-rw-r--r--libftpconn/errs.c (renamed from libdiskfs/init-completed.c)24
-rw-r--r--libftpconn/fname.c78
-rw-r--r--libftpconn/ftpconn.h394
-rw-r--r--libftpconn/names.c238
-rw-r--r--libftpconn/open.c252
-rw-r--r--libftpconn/priv.h98
-rw-r--r--libftpconn/reply.c241
-rw-r--r--libftpconn/rmt.c94
-rw-r--r--libftpconn/set-type.c60
-rw-r--r--libftpconn/stats.c80
-rw-r--r--libftpconn/unix.c772
-rw-r--r--libftpconn/xfer.c280
-rw-r--r--libftpconn/xinl.c24
-rw-r--r--libhurdbugaddr/Makefile (renamed from libmom/Makefile)27
-rw-r--r--libhurdbugaddr/bugaddr.c (renamed from utils/sync.c)17
-rw-r--r--libihash/ChangeLog21
-rw-r--r--libihash/Makefile16
-rw-r--r--libihash/ihash.c558
-rw-r--r--libihash/ihash.h270
-rw-r--r--libihash/primes.c145
-rw-r--r--libiohelp/ChangeLog37
-rw-r--r--libiohelp/Makefile16
-rw-r--r--libiohelp/handle_io_release_conch.c7
-rw-r--r--libiohelp/iohelp.h70
-rw-r--r--libiohelp/iouser-create.c111
-rw-r--r--libiohelp/iouser-dup.c (renamed from libdiskfs/notify-nosenders.c)51
-rw-r--r--libiohelp/iouser-free.c (renamed from libdiskfs/ports-soft.c)13
-rw-r--r--libiohelp/iouser-reauth.c106
-rw-r--r--libiohelp/iouser-restrict.c83
-rw-r--r--libiohelp/return-buffer.c (renamed from libfshelp/return-buffer.c)14
-rw-r--r--libiohelp/shared.c (renamed from libdiskfs/io-interrupt.c)26
-rw-r--r--libmom/ChangeLog31
-rw-r--r--libmom/allocate-address.c50
-rw-r--r--libmom/mom-errors.h47
-rw-r--r--libmom/mom-kerndep.h41
-rw-r--r--libmom/mom.h132
-rw-r--r--libnetfs/ChangeLog253
-rw-r--r--libnetfs/Makefile36
-rw-r--r--libnetfs/append-args.c (renamed from libnetfs/get-options.c)8
-rw-r--r--libnetfs/append-std-options.c12
-rw-r--r--libnetfs/dir-link.c2
-rw-r--r--libnetfs/dir-lookup.c272
-rw-r--r--libnetfs/dir-mkdir.c4
-rw-r--r--libnetfs/dir-mkfile.c34
-rw-r--r--libnetfs/dir-readdir.c16
-rw-r--r--libnetfs/dir-rename.c2
-rw-r--r--libnetfs/dir-rmdir.c4
-rw-r--r--libnetfs/dir-unlink.c4
-rw-r--r--libnetfs/file-chauthor.c4
-rw-r--r--libnetfs/file-check-access.c6
-rw-r--r--libnetfs/file-chflags.c4
-rw-r--r--libnetfs/file-chmod.c6
-rw-r--r--libnetfs/file-chown.c4
-rw-r--r--libnetfs/file-exec.c92
-rw-r--r--libnetfs/file-get-fs-options.c20
-rw-r--r--libnetfs/file-get-storage-info-default.c (renamed from libmom/allocate-memory.c)56
-rw-r--r--libnetfs/file-get-storage-info.c51
-rw-r--r--libnetfs/file-get-translator.c50
-rw-r--r--libnetfs/file-getcontrol.c43
-rw-r--r--libnetfs/file-reparent.c74
-rw-r--r--libnetfs/file-set-size.c4
-rw-r--r--libnetfs/file-set-translator.c73
-rw-r--r--libnetfs/file-statfs.c2
-rw-r--r--libnetfs/file-sync.c2
-rw-r--r--libnetfs/file-syncfs.c4
-rw-r--r--libnetfs/file-utimes.c21
-rw-r--r--libnetfs/fsstubs.c20
-rw-r--r--libnetfs/fsys-get-options.c22
-rw-r--r--libnetfs/fsys-getroot.c61
-rw-r--r--libnetfs/fsys-goaway.c (renamed from libmom/reserve-memory.c)46
-rw-r--r--libnetfs/fsys-set-options.c4
-rw-r--r--libnetfs/fsys-syncfs.c13
-rw-r--r--libnetfs/fsysstubs.c20
-rw-r--r--libnetfs/init-loop.c4
-rw-r--r--libnetfs/init-startup.c32
-rw-r--r--libnetfs/io-duplicate.c11
-rw-r--r--libnetfs/io-identity.c14
-rw-r--r--libnetfs/io-pathconf.c70
-rw-r--r--libnetfs/io-read.c65
-rw-r--r--libnetfs/io-readable.c4
-rw-r--r--libnetfs/io-reauthenticate.c60
-rw-r--r--libnetfs/io-restrict-auth.c62
-rw-r--r--libnetfs/io-revoke.c60
-rw-r--r--libnetfs/io-seek.c43
-rw-r--r--libnetfs/io-select.c5
-rw-r--r--libnetfs/io-stat.c31
-rw-r--r--libnetfs/io-version.c (renamed from libdiskfs/interrupt.c)25
-rw-r--r--libnetfs/io-write.c17
-rw-r--r--libnetfs/make-node.c4
-rw-r--r--libnetfs/make-peropen.c27
-rw-r--r--libnetfs/make-protid.c4
-rw-r--r--libnetfs/misc.h6
-rw-r--r--libnetfs/mutations.h4
-rw-r--r--libnetfs/netfs.h431
-rw-r--r--libnetfs/nput.c38
-rw-r--r--libnetfs/nref.c (renamed from libmom/unreserve-memory.c)12
-rw-r--r--libnetfs/nrele.c (renamed from libmom/error-trans.c)29
-rw-r--r--libnetfs/priv.h11
-rw-r--r--libnetfs/release-peropen.c15
-rw-r--r--libnetfs/release-protid.c12
-rw-r--r--libnetfs/runtime-argp.c3
-rw-r--r--libnetfs/set-get-trans.c47
-rw-r--r--libnetfs/shutdown.c114
-rw-r--r--libnetfs/std-runtime-argp.c1
-rw-r--r--libnetfs/std-startup-argp.c1
-rw-r--r--libnetfs/trans-callback.c83
-rw-r--r--libnetfs/unparse-runtime-options.c33
-rw-r--r--libpager/ChangeLog374
-rw-r--r--libpager/Makefile3
-rw-r--r--libpager/data-init.c34
-rw-r--r--libpager/data-request.c38
-rw-r--r--libpager/data-return.c57
-rw-r--r--libpager/data-unlock.c13
-rw-r--r--libpager/demuxer.c16
-rw-r--r--libpager/lock-object.c21
-rw-r--r--libpager/mark-error.c24
-rw-r--r--libpager/notify-stubs.c43
-rw-r--r--libpager/object-create.c73
-rw-r--r--libpager/object-terminate.c22
-rw-r--r--libpager/offer-page.c30
-rw-r--r--libpager/pagemap.c38
-rw-r--r--libpager/pager-memcpy.c195
-rw-r--r--libpager/pager.h10
-rw-r--r--libpager/priv.h35
-rw-r--r--libpager/seqnos.c26
-rw-r--r--libpager/stubs.c18
-rw-r--r--libpipe/ChangeLog137
-rw-r--r--libpipe/Makefile7
-rw-r--r--libpipe/pipe-funcs.c2
-rw-r--r--libpipe/pipe.c57
-rw-r--r--libpipe/pipe.h83
-rw-r--r--libpipe/pq-funcs.c2
-rw-r--r--libpipe/pq.c64
-rw-r--r--libpipe/pq.h68
-rw-r--r--libports/ChangeLog438
-rw-r--r--libports/Makefile18
-rw-r--r--libports/bucket-iterate.c52
-rw-r--r--libports/claim-right.c37
-rw-r--r--libports/class-iterate.c (renamed from libmom/copy-ref.c)28
-rw-r--r--libports/complete-deallocate.c2
-rw-r--r--libports/create-bucket.c28
-rw-r--r--libports/create-class.c11
-rw-r--r--libports/create-internal.c20
-rw-r--r--libports/dead-name.c2
-rw-r--r--libports/destroy-right.c19
-rw-r--r--libports/end-rpc.c14
-rw-r--r--libports/get-right.c27
-rw-r--r--libports/get-send-right.c (renamed from libports/allocate-port.c)30
-rw-r--r--libports/import-port.c2
-rw-r--r--libports/inhibit-all-rpcs.c32
-rw-r--r--libports/inhibit-bucket-rpcs.c16
-rw-r--r--libports/inhibit-class-rpcs.c11
-rw-r--r--libports/inhibit-port-rpcs.c11
-rw-r--r--libports/init.c8
-rw-r--r--libports/intern-external-port.c37
-rw-r--r--libports/interrupt-notified-rpcs.c10
-rw-r--r--libports/interrupt-on-notify.c17
-rw-r--r--libports/interrupt-rpcs.c7
-rw-r--r--libports/interrupted.c75
-rw-r--r--libports/lookup-port.c4
-rw-r--r--libports/manage-multithread.c24
-rw-r--r--libports/manage-one-thread.c2
-rw-r--r--libports/notify-dead-name.c6
-rw-r--r--libports/port-deref.c8
-rw-r--r--libports/ports.h87
-rw-r--r--libports/reallocate-from-external.c6
-rw-r--r--libports/reallocate-port.c11
-rw-r--r--libports/resume-all-rpcs.c2
-rw-r--r--libports/resume-bucket-rpcs.c2
-rw-r--r--libports/resume-class-rpcs.c2
-rw-r--r--libports/resume-port-rpcs.c2
-rw-r--r--libports/transfer-right.c16
-rw-r--r--libps/ChangeLog761
-rw-r--r--libps/Makefile9
-rw-r--r--libps/common.h6
-rw-r--r--libps/context.c74
-rw-r--r--libps/filters.c12
-rw-r--r--libps/fmt.c60
-rw-r--r--libps/host.c52
-rw-r--r--libps/proclist.c27
-rw-r--r--libps/procstat.c340
-rw-r--r--libps/ps.h345
-rw-r--r--libps/spec.c225
-rw-r--r--libps/tty.c24
-rw-r--r--libps/user.c5
-rw-r--r--libps/write.c4
-rw-r--r--libshouldbeinlibc/=argz.c190
-rw-r--r--libshouldbeinlibc/=argz.h89
-rw-r--r--libshouldbeinlibc/=envz.c171
-rw-r--r--libshouldbeinlibc/=envz.h55
-rw-r--r--libshouldbeinlibc/=line.c147
-rw-r--r--libshouldbeinlibc/=line.h128
-rw-r--r--libshouldbeinlibc/=path-lookup.c120
-rw-r--r--libshouldbeinlibc/ChangeLog614
-rw-r--r--libshouldbeinlibc/Makefile20
-rw-r--r--libshouldbeinlibc/argp-help.c908
-rw-r--r--libshouldbeinlibc/argp-parse.c662
-rw-r--r--libshouldbeinlibc/argp-pv.c27
-rw-r--r--libshouldbeinlibc/argp-pvh.c30
-rw-r--r--libshouldbeinlibc/argp.h356
-rw-r--r--libshouldbeinlibc/cacheq.c9
-rw-r--r--libshouldbeinlibc/exec-reauth.c20
-rw-r--r--libshouldbeinlibc/fsysops.c11
-rw-r--r--libshouldbeinlibc/idvec-auth.c40
-rw-r--r--libshouldbeinlibc/idvec-funcs.c2
-rw-r--r--libshouldbeinlibc/idvec-impgids.c127
-rw-r--r--libshouldbeinlibc/idvec-rep.c164
-rw-r--r--libshouldbeinlibc/idvec-verify.c362
-rw-r--r--libshouldbeinlibc/idvec.c189
-rw-r--r--libshouldbeinlibc/idvec.h151
-rw-r--r--libshouldbeinlibc/localhost.c23
-rw-r--r--libshouldbeinlibc/maptime-funcs.c5
-rw-r--r--libshouldbeinlibc/maptime.c67
-rw-r--r--libshouldbeinlibc/maptime.h27
-rw-r--r--libshouldbeinlibc/options.c231
-rw-r--r--libshouldbeinlibc/options.h79
-rw-r--r--libshouldbeinlibc/portinfo.c52
-rw-r--r--libshouldbeinlibc/portinfo.h2
-rw-r--r--libshouldbeinlibc/portxlate.c33
-rw-r--r--libshouldbeinlibc/timefmt.c1
-rw-r--r--libshouldbeinlibc/ugids-argp.c175
-rw-r--r--libshouldbeinlibc/ugids-auth.c53
-rw-r--r--libshouldbeinlibc/ugids-imply.c (renamed from libdiskfs/ports-idle.c)35
-rw-r--r--libshouldbeinlibc/ugids-merge.c109
-rw-r--r--libshouldbeinlibc/ugids-posix.c95
-rw-r--r--libshouldbeinlibc/ugids-rep.c118
-rw-r--r--libshouldbeinlibc/ugids-subtract.c130
-rw-r--r--libshouldbeinlibc/ugids-verify-auth.c190
-rw-r--r--libshouldbeinlibc/ugids-verify.c70
-rw-r--r--libshouldbeinlibc/ugids-xinl.c23
-rw-r--r--libshouldbeinlibc/ugids.c97
-rw-r--r--libshouldbeinlibc/ugids.h229
-rw-r--r--libshouldbeinlibc/wire.c65
-rw-r--r--libshouldbeinlibc/xportinfo.c13
-rw-r--r--libstore/ChangeLog152
-rw-r--r--libstore/Makefile75
-rw-r--r--libstore/argp.c425
-rw-r--r--libstore/bunzip2.c13
-rw-r--r--libstore/clone.c25
-rw-r--r--libstore/copy.c267
-rw-r--r--libstore/create.c41
-rw-r--r--libstore/decode.c125
-rw-r--r--libstore/derive.c37
-rw-r--r--libstore/device.c326
-rw-r--r--libstore/enc.c41
-rw-r--r--libstore/encode.c87
-rw-r--r--libstore/file.c284
-rw-r--r--libstore/flags.c26
-rw-r--r--libstore/gunzip.c55
-rw-r--r--libstore/kids.c234
-rw-r--r--libstore/make.c80
-rw-r--r--libstore/map.c79
-rw-r--r--libstore/memobj.c197
-rw-r--r--libstore/module.c178
-rw-r--r--libstore/mvol.c158
-rw-r--r--libstore/nbd.c529
-rw-r--r--libstore/null.c109
-rw-r--r--libstore/open.c65
-rw-r--r--libstore/part.c197
-rw-r--r--libstore/rdwr.c152
-rw-r--r--libstore/remap.c345
-rw-r--r--libstore/set.c22
-rw-r--r--libstore/std.c37
-rw-r--r--libstore/store.h573
-rw-r--r--libstore/storecat.c29
-rw-r--r--libstore/stripe.c145
-rw-r--r--libstore/task.c205
-rw-r--r--libstore/typed.c177
-rw-r--r--libstore/unknown.c231
-rw-r--r--libstore/unzipstore.c267
-rw-r--r--libstore/url.c92
-rw-r--r--libstore/xinl.c2
-rw-r--r--libstore/zero.c196
-rw-r--r--libthreads/ChangeLog269
-rw-r--r--libthreads/Makefile23
-rw-r--r--libthreads/alpha/csw.S200
-rw-r--r--libthreads/alpha/cthreads.h61
-rw-r--r--libthreads/alpha/lock.S84
-rw-r--r--libthreads/alpha/thread.c100
-rw-r--r--libthreads/call.c28
-rw-r--r--libthreads/cancel-cond.c4
-rw-r--r--libthreads/cprocs.c325
-rw-r--r--libthreads/cthread_data.c77
-rw-r--r--libthreads/cthread_internals.h177
-rw-r--r--libthreads/cthreads.c196
-rw-r--r--libthreads/cthreads.h412
-rw-r--r--libthreads/i386/csw.S76
-rw-r--r--libthreads/i386/cthreads.h50
-rw-r--r--libthreads/i386/lock.s28
-rw-r--r--libthreads/i386/thread.c105
-rw-r--r--libthreads/libthreads.map27
-rw-r--r--libthreads/lockfile.c65
-rw-r--r--libthreads/malloc.c438
-rw-r--r--libthreads/mig_support.c108
-rw-r--r--libthreads/options.h44
-rw-r--r--libthreads/rwlock.c8
-rw-r--r--libthreads/rwlock.h38
-rw-r--r--libthreads/stack.c118
-rw-r--r--libthreads/sync.c9
-rw-r--r--libtreefs/Makefile4
-rw-r--r--libtreefs/dir-lookup.c4
-rw-r--r--libtreefs/mig-decls.h9
-rw-r--r--libtreefs/s-file.c4
-rw-r--r--libtreefs/trans-start.c5
-rw-r--r--libtreefs/treefs.h59
-rw-r--r--libtreefs/xinl.c3
-rw-r--r--libtrivfs/ChangeLog665
-rw-r--r--libtrivfs/Makefile25
-rw-r--r--libtrivfs/append-args.c (renamed from libtrivfs/get-options.c)9
-rw-r--r--libtrivfs/cntl-classes.c (renamed from devio/ptypes.h)13
-rw-r--r--libtrivfs/cntl-clean.c7
-rw-r--r--libtrivfs/cntl-create.c46
-rw-r--r--libtrivfs/dir-chg.c5
-rw-r--r--libtrivfs/dir-link.c9
-rw-r--r--libtrivfs/dir-lookup.c58
-rw-r--r--libtrivfs/dir-mkdir.c7
-rw-r--r--libtrivfs/dir-mkfile.c5
-rw-r--r--libtrivfs/dir-readdir.c8
-rw-r--r--libtrivfs/dir-rename.c7
-rw-r--r--libtrivfs/dir-rmdir.c9
-rw-r--r--libtrivfs/dir-unlink.c7
-rw-r--r--libtrivfs/dyn-classes.c269
-rw-r--r--libtrivfs/file-access.c17
-rw-r--r--libtrivfs/file-chauthor.c6
-rw-r--r--libtrivfs/file-chflags.c7
-rw-r--r--libtrivfs/file-chg.c5
-rw-r--r--libtrivfs/file-chmod.c5
-rw-r--r--libtrivfs/file-chown.c8
-rw-r--r--libtrivfs/file-exec.c9
-rw-r--r--libtrivfs/file-get-fs-options.c20
-rw-r--r--libtrivfs/file-get-storage-info.c3
-rw-r--r--libtrivfs/file-get-trans.c10
-rw-r--r--libtrivfs/file-get-transcntl.c5
-rw-r--r--libtrivfs/file-getcontrol.c7
-rw-r--r--libtrivfs/file-getfh.c9
-rw-r--r--libtrivfs/file-getlinknode.c5
-rw-r--r--libtrivfs/file-lock.c6
-rw-r--r--libtrivfs/file-reparent.c34
-rw-r--r--libtrivfs/file-set-size.c5
-rw-r--r--libtrivfs/file-set-trans.c10
-rw-r--r--libtrivfs/file-statfs.c7
-rw-r--r--libtrivfs/file-sync.c5
-rw-r--r--libtrivfs/file-syncfs.c5
-rw-r--r--libtrivfs/file-utimes.c5
-rw-r--r--libtrivfs/fsmutations.h10
-rw-r--r--libtrivfs/fsys-forward.c7
-rw-r--r--libtrivfs/fsys-get-options.c20
-rw-r--r--libtrivfs/fsys-getroot.c60
-rw-r--r--libtrivfs/fsys-goaway.c5
-rw-r--r--libtrivfs/fsys-set-options.c5
-rw-r--r--libtrivfs/fsys-stubs.c13
-rw-r--r--libtrivfs/fsys-syncfs.c5
-rw-r--r--libtrivfs/handle-port.c48
-rw-r--r--libtrivfs/io-async-icky.c6
-rw-r--r--libtrivfs/io-async.c6
-rw-r--r--libtrivfs/io-duplicate.c10
-rw-r--r--libtrivfs/io-identity.c11
-rw-r--r--libtrivfs/io-map.c6
-rw-r--r--libtrivfs/io-modes-get.c8
-rw-r--r--libtrivfs/io-modes-off.c5
-rw-r--r--libtrivfs/io-modes-on.c5
-rw-r--r--libtrivfs/io-owner-get.c6
-rw-r--r--libtrivfs/io-owner-mod.c6
-rw-r--r--libtrivfs/io-pathconf.c10
-rw-r--r--libtrivfs/io-read.c7
-rw-r--r--libtrivfs/io-readable.c5
-rw-r--r--libtrivfs/io-reauthenticate.c88
-rw-r--r--libtrivfs/io-restrict-auth.c100
-rw-r--r--libtrivfs/io-revoke.c (renamed from libtrivfs/file-inv.c)24
-rw-r--r--libtrivfs/io-seek.c5
-rw-r--r--libtrivfs/io-select.c5
-rw-r--r--libtrivfs/io-stat.c9
-rw-r--r--libtrivfs/io-stubs.c15
-rw-r--r--libtrivfs/io-version.c8
-rw-r--r--libtrivfs/io-write.c9
-rw-r--r--libtrivfs/migsupport.c52
-rw-r--r--libtrivfs/nosenders.c43
-rw-r--r--libtrivfs/notify-stubs.c53
-rw-r--r--libtrivfs/open.c20
-rw-r--r--libtrivfs/priv.h16
-rw-r--r--libtrivfs/protid-classes.c (renamed from libdiskfs/ports-noports.c)17
-rw-r--r--libtrivfs/protid-clean.c5
-rw-r--r--libtrivfs/protid-dup.c15
-rw-r--r--libtrivfs/startup.c7
-rw-r--r--libtrivfs/times.c14
-rw-r--r--libtrivfs/trivfs.h143
-rw-r--r--login/ChangeLog15
-rw-r--r--login/utmp.c22
-rw-r--r--mach-defpager/Makefile40
-rw-r--r--mach-defpager/default_pager.c3918
-rw-r--r--mach-defpager/default_pager.h43
-rw-r--r--mach-defpager/file_io.h69
-rw-r--r--mach-defpager/kalloc.c299
-rw-r--r--mach-defpager/kalloc.h (renamed from libnetfs/parse-runtime-options.c)24
-rw-r--r--mach-defpager/main.c180
-rw-r--r--mach-defpager/queue.h316
-rw-r--r--mach-defpager/setup.c307
-rw-r--r--mach-defpager/wiring.c176
-rw-r--r--mach-defpager/wiring.h35
-rw-r--r--mkbootfs/ChangeLog22
-rw-r--r--mkbootfs/mkbootfs.c184
-rwxr-xr-xmove-if-change17
-rw-r--r--nfs/ChangeLog170
-rw-r--r--nfs/Makefile16
-rw-r--r--nfs/cache.c129
-rw-r--r--nfs/cred.c116
-rw-r--r--nfs/main.c116
-rw-r--r--nfs/mount.c195
-rw-r--r--nfs/mount.h9
-rw-r--r--nfs/name-cache.c305
-rw-r--r--nfs/nfs-spec.h168
-rw-r--r--nfs/nfs.c555
-rw-r--r--nfs/nfs.h85
-rw-r--r--nfs/ops.c1416
-rw-r--r--nfs/pager.c448
-rw-r--r--nfs/rpc.c282
-rw-r--r--nfs/rpcsvc/mount.h81
-rw-r--r--nfs/rpcsvc/nfs_prot.h343
-rw-r--r--nfs/storage-info.c104
-rw-r--r--nfsd/Makefile4
-rw-r--r--nfsd/cache.c381
-rw-r--r--nfsd/fsys.c91
-rw-r--r--nfsd/loop.c326
-rw-r--r--nfsd/main.c34
-rw-r--r--nfsd/nfsd.h33
-rw-r--r--nfsd/ops.c405
-rw-r--r--nfsd/proctables.c57
-rw-r--r--nfsd/xdr.c116
-rw-r--r--pfinet/ChangeLog250
-rw-r--r--pfinet/Makefile211
-rw-r--r--pfinet/README55
-rw-r--r--pfinet/asm/bitops.h135
-rw-r--r--pfinet/asm/segment.h21
-rw-r--r--pfinet/asm/system.h10
-rw-r--r--pfinet/config.h54
-rw-r--r--pfinet/dummy.c138
-rw-r--r--pfinet/ethernet.c304
-rw-r--r--pfinet/glue-include/asm/atomic.h27
-rw-r--r--pfinet/glue-include/asm/bitops.h37
-rw-r--r--pfinet/glue-include/asm/byteorder.h155
-rw-r--r--pfinet/glue-include/asm/delay.h1
-rw-r--r--pfinet/glue-include/asm/errno.h3
-rw-r--r--pfinet/glue-include/asm/hardirq.h1
-rw-r--r--pfinet/glue-include/asm/init.h3
-rw-r--r--pfinet/glue-include/asm/segment.h (renamed from config/hostname)0
-rw-r--r--pfinet/glue-include/asm/spinlock.h75
-rw-r--r--pfinet/glue-include/asm/system.h20
-rw-r--r--pfinet/glue-include/asm/types.h1
-rw-r--r--pfinet/glue-include/asm/uaccess.h53
-rw-r--r--pfinet/glue-include/linux/autoconf.h (renamed from pfinet/linux/autoconf.h)0
-rw-r--r--pfinet/glue-include/linux/binfmts.h1
-rw-r--r--pfinet/glue-include/linux/config.h1
-rw-r--r--pfinet/glue-include/linux/errno.h13
-rw-r--r--pfinet/glue-include/linux/fcntl.h (renamed from pfinet/linux/fcntl.h)0
-rw-r--r--pfinet/glue-include/linux/fs.h21
-rw-r--r--pfinet/glue-include/linux/if.h3
-rw-r--r--pfinet/glue-include/linux/in.h44
-rw-r--r--pfinet/glue-include/linux/in6.h110
-rw-r--r--pfinet/glue-include/linux/interrupt.h44
-rw-r--r--pfinet/glue-include/linux/ioctl.h1
-rw-r--r--pfinet/glue-include/linux/ipv6.h117
-rw-r--r--pfinet/glue-include/linux/kernel.h78
-rw-r--r--pfinet/glue-include/linux/limits.h8
-rw-r--r--pfinet/glue-include/linux/major.h (renamed from pfinet/linux/major.h)0
-rw-r--r--pfinet/glue-include/linux/malloc.h27
-rw-r--r--pfinet/glue-include/linux/mm.h38
-rw-r--r--pfinet/glue-include/linux/param.h (renamed from pfinet/linux/param.h)0
-rw-r--r--pfinet/glue-include/linux/personality.h1
-rw-r--r--pfinet/glue-include/linux/poll.h24
-rw-r--r--pfinet/glue-include/linux/proc_fs.h (renamed from pfinet/linux/config.h)0
-rw-r--r--pfinet/glue-include/linux/sched.h204
-rw-r--r--pfinet/glue-include/linux/slab.h (renamed from pfinet/linux/sockios.h)0
-rw-r--r--pfinet/glue-include/linux/socket.h152
-rw-r--r--pfinet/glue-include/linux/sockios.h (renamed from pfinet/linux/un.h)0
-rw-r--r--pfinet/glue-include/linux/stat.h (renamed from pfinet/linux/stat.h)0
-rw-r--r--pfinet/glue-include/linux/string.h (renamed from pfinet/linux/string.h)0
-rw-r--r--pfinet/glue-include/linux/termios.h (renamed from pfinet/linux/termios.h)0
-rw-r--r--pfinet/glue-include/linux/time.h10
-rw-r--r--pfinet/glue-include/linux/timer.h (renamed from pfinet/linux/timer.h)13
-rw-r--r--pfinet/glue-include/linux/timex.h0
-rw-r--r--pfinet/glue-include/linux/types.h31
-rw-r--r--pfinet/glue-include/linux/un.h0
-rw-r--r--pfinet/glue-include/linux/version.h3
-rw-r--r--pfinet/glue-include/linux/wait.h32
-rw-r--r--pfinet/iioctl-ops.c400
-rw-r--r--pfinet/io-ops.c374
-rw-r--r--pfinet/kmem_cache.c88
-rw-r--r--pfinet/linux-inet/af_inet.c1578
-rw-r--r--pfinet/linux-inet/arp.c1295
-rw-r--r--pfinet/linux-inet/arp.h18
-rw-r--r--pfinet/linux-inet/datagram.c210
-rw-r--r--pfinet/linux-inet/dev.c1449
-rw-r--r--pfinet/linux-inet/dev_mcast.c169
-rw-r--r--pfinet/linux-inet/devinet.c213
-rw-r--r--pfinet/linux-inet/eth.h35
-rw-r--r--pfinet/linux-inet/icmp.c774
-rw-r--r--pfinet/linux-inet/igmp.c390
-rw-r--r--pfinet/linux-inet/ip.c2427
-rw-r--r--pfinet/linux-inet/ip.h130
-rw-r--r--pfinet/linux-inet/ip_fw.c1016
-rw-r--r--pfinet/linux-inet/ipx.c1947
-rw-r--r--pfinet/linux-inet/p8022.c98
-rw-r--r--pfinet/linux-inet/p8022.h2
-rw-r--r--pfinet/linux-inet/p8023.c35
-rw-r--r--pfinet/linux-inet/packet.c410
-rw-r--r--pfinet/linux-inet/protocol.c177
-rw-r--r--pfinet/linux-inet/protocol.h59
-rw-r--r--pfinet/linux-inet/psnap.c123
-rw-r--r--pfinet/linux-inet/psnap.h2
-rw-r--r--pfinet/linux-inet/raw.c319
-rw-r--r--pfinet/linux-inet/route.c684
-rw-r--r--pfinet/linux-inet/route.h54
-rw-r--r--pfinet/linux-inet/skbuff.c573
-rw-r--r--pfinet/linux-inet/sock.c574
-rw-r--r--pfinet/linux-inet/sock.h316
-rw-r--r--pfinet/linux-inet/tcp.c5120
-rw-r--r--pfinet/linux-inet/tcp.h142
-rw-r--r--pfinet/linux-inet/timer.c264
-rw-r--r--pfinet/linux-inet/udp.c740
-rw-r--r--pfinet/linux-src/arch/alpha/lib/checksum.c169
-rw-r--r--pfinet/linux-src/arch/alpha/lib/csum_partial_copy.c384
-rw-r--r--pfinet/linux-src/arch/arm/lib/checksum.S730
-rw-r--r--pfinet/linux-src/arch/i386/lib/checksum.S447
-rw-r--r--pfinet/linux-src/arch/i386/lib/old-checksum.c19
-rw-r--r--pfinet/linux-src/arch/m68k/lib/checksum.c420
-rw-r--r--pfinet/linux-src/arch/ppc/lib/checksum.S194
-rw-r--r--pfinet/linux-src/arch/s390/lib/checksum.c56
-rw-r--r--pfinet/linux-src/arch/sparc/lib/checksum.S581
-rw-r--r--pfinet/linux-src/arch/sparc64/lib/checksum.S278
-rw-r--r--pfinet/linux-src/include/asm-alpha/checksum.h90
-rw-r--r--pfinet/linux-src/include/asm-arm/checksum.h162
-rw-r--r--pfinet/linux-src/include/asm-i386/checksum.h211
-rw-r--r--pfinet/linux-src/include/asm-m68k/checksum.h154
-rw-r--r--pfinet/linux-src/include/asm-mips/checksum.h255
-rw-r--r--pfinet/linux-src/include/asm-ppc/checksum.h113
-rw-r--r--pfinet/linux-src/include/asm-s390/checksum.h188
-rw-r--r--pfinet/linux-src/include/asm-sparc/checksum.h252
-rw-r--r--pfinet/linux-src/include/asm-sparc64/checksum.h207
-rw-r--r--pfinet/linux-src/include/linux/a.out.h268
-rw-r--r--pfinet/linux-src/include/linux/acct.h88
-rw-r--r--pfinet/linux-src/include/linux/adfs_fs.h175
-rw-r--r--pfinet/linux-src/include/linux/adfs_fs_i.h17
-rw-r--r--pfinet/linux-src/include/linux/adfs_fs_sb.h33
-rw-r--r--pfinet/linux-src/include/linux/affs_fs.h115
-rw-r--r--pfinet/linux-src/include/linux/affs_fs_i.h47
-rw-r--r--pfinet/linux-src/include/linux/affs_fs_sb.h74
-rw-r--r--pfinet/linux-src/include/linux/affs_hardblocks.h66
-rw-r--r--pfinet/linux-src/include/linux/amifd.h61
-rw-r--r--pfinet/linux-src/include/linux/amifdreg.h81
-rw-r--r--pfinet/linux-src/include/linux/amigaffs.h228
-rw-r--r--pfinet/linux-src/include/linux/apm_bios.h144
-rw-r--r--pfinet/linux-src/include/linux/arcdevice.h354
-rw-r--r--pfinet/linux-src/include/linux/atalk.h180
-rw-r--r--pfinet/linux-src/include/linux/atari_rootsec.h34
-rw-r--r--pfinet/linux-src/include/linux/auto_fs.h83
-rw-r--r--pfinet/linux-src/include/linux/awe_voice.h524
-rw-r--r--pfinet/linux-src/include/linux/ax25.h98
-rw-r--r--pfinet/linux-src/include/linux/b1lli.h136
-rw-r--r--pfinet/linux-src/include/linux/b1pcmcia.h36
-rw-r--r--pfinet/linux-src/include/linux/baycom.h39
-rw-r--r--pfinet/linux-src/include/linux/binfmts.h77
-rw-r--r--pfinet/linux-src/include/linux/bios32.h34
-rw-r--r--pfinet/linux-src/include/linux/bitops.h72
-rw-r--r--pfinet/linux-src/include/linux/blk.h489
-rw-r--r--pfinet/linux-src/include/linux/blkdev.h94
-rw-r--r--pfinet/linux-src/include/linux/bpqether.h41
-rw-r--r--pfinet/linux-src/include/linux/busmouse.h104
-rw-r--r--pfinet/linux-src/include/linux/capability.h337
-rw-r--r--pfinet/linux-src/include/linux/capi.h127
-rw-r--r--pfinet/linux-src/include/linux/cd1400.h292
-rw-r--r--pfinet/linux-src/include/linux/cdk.h486
-rw-r--r--pfinet/linux-src/include/linux/cdrom.h433
-rw-r--r--pfinet/linux-src/include/linux/coda.h800
-rw-r--r--pfinet/linux-src/include/linux/coda_cache.h77
-rw-r--r--pfinet/linux-src/include/linux/coda_fs_i.h56
-rw-r--r--pfinet/linux-src/include/linux/coda_linux.h143
-rw-r--r--pfinet/linux-src/include/linux/coda_opstats.h94
-rw-r--r--pfinet/linux-src/include/linux/coda_proc.h145
-rw-r--r--pfinet/linux-src/include/linux/coda_psdev.h131
-rw-r--r--pfinet/linux-src/include/linux/coff.h351
-rw-r--r--pfinet/linux-src/include/linux/comstats.h119
-rw-r--r--pfinet/linux-src/include/linux/concap.h109
-rw-r--r--pfinet/linux-src/include/linux/config.h6
-rw-r--r--pfinet/linux-src/include/linux/console.h115
-rw-r--r--pfinet/linux-src/include/linux/console_struct.h109
-rw-r--r--pfinet/linux-src/include/linux/consolemap.h15
-rw-r--r--pfinet/linux-src/include/linux/ctype.h54
-rw-r--r--pfinet/linux-src/include/linux/cyclades.h814
-rw-r--r--pfinet/linux-src/include/linux/dcache.h196
-rw-r--r--pfinet/linux-src/include/linux/delay.h37
-rw-r--r--pfinet/linux-src/include/linux/devpts_fs.h74
-rw-r--r--pfinet/linux-src/include/linux/digi1.h100
-rw-r--r--pfinet/linux-src/include/linux/digiFep1.h136
-rw-r--r--pfinet/linux-src/include/linux/digiPCI.h42
-rw-r--r--pfinet/linux-src/include/linux/dio.h204
-rw-r--r--pfinet/linux-src/include/linux/dirent.h11
-rw-r--r--pfinet/linux-src/include/linux/dlists.h108
-rw-r--r--pfinet/linux-src/include/linux/dmascc.h43
-rw-r--r--pfinet/linux-src/include/linux/dtlk.h104
-rw-r--r--pfinet/linux-src/include/linux/efs_dir.h42
-rw-r--r--pfinet/linux-src/include/linux/efs_fs.h67
-rw-r--r--pfinet/linux-src/include/linux/efs_fs_i.h68
-rw-r--r--pfinet/linux-src/include/linux/efs_fs_sb.h63
-rw-r--r--pfinet/linux-src/include/linux/efs_vh.h70
-rw-r--r--pfinet/linux-src/include/linux/elf.h601
-rw-r--r--pfinet/linux-src/include/linux/elfcore.h88
-rw-r--r--pfinet/linux-src/include/linux/epca.h170
-rw-r--r--pfinet/linux-src/include/linux/epcaconfig.h8
-rw-r--r--pfinet/linux-src/include/linux/errno.h16
-rw-r--r--pfinet/linux-src/include/linux/errqueue.h44
-rw-r--r--pfinet/linux-src/include/linux/etherdevice.h56
-rw-r--r--pfinet/linux-src/include/linux/ext2_fs.h624
-rw-r--r--pfinet/linux-src/include/linux/ext2_fs_i.h42
-rw-r--r--pfinet/linux-src/include/linux/ext2_fs_sb.h66
-rw-r--r--pfinet/linux-src/include/linux/fat_cvf.h49
-rw-r--r--pfinet/linux-src/include/linux/fb.h494
-rw-r--r--pfinet/linux-src/include/linux/fcdevice.h40
-rw-r--r--pfinet/linux-src/include/linux/fcntl.h6
-rw-r--r--pfinet/linux-src/include/linux/fd.h378
-rw-r--r--pfinet/linux-src/include/linux/fddidevice.h39
-rw-r--r--pfinet/linux-src/include/linux/fdreg.h143
-rw-r--r--pfinet/linux-src/include/linux/file.h71
-rw-r--r--pfinet/linux-src/include/linux/filter.h140
-rw-r--r--pfinet/linux-src/include/linux/firewall.h61
-rw-r--r--pfinet/linux-src/include/linux/fs.h910
-rw-r--r--pfinet/linux-src/include/linux/ftape-header-segment.h122
-rw-r--r--pfinet/linux-src/include/linux/ftape-vendors.h137
-rw-r--r--pfinet/linux-src/include/linux/ftape.h212
-rw-r--r--pfinet/linux-src/include/linux/genhd.h267
-rw-r--r--pfinet/linux-src/include/linux/ghash.h218
-rw-r--r--pfinet/linux-src/include/linux/hayesesp.h127
-rw-r--r--pfinet/linux-src/include/linux/hdlcdrv.h383
-rw-r--r--pfinet/linux-src/include/linux/hdreg.h282
-rw-r--r--pfinet/linux-src/include/linux/hfmodem.h256
-rw-r--r--pfinet/linux-src/include/linux/hfs_fs.h337
-rw-r--r--pfinet/linux-src/include/linux/hfs_fs_i.h43
-rw-r--r--pfinet/linux-src/include/linux/hfs_fs_sb.h53
-rw-r--r--pfinet/linux-src/include/linux/hfs_sysdep.h245
-rw-r--r--pfinet/linux-src/include/linux/hippidevice.h58
-rw-r--r--pfinet/linux-src/include/linux/hpfs_fs.h13
-rw-r--r--pfinet/linux-src/include/linux/hpfs_fs_i.h24
-rw-r--r--pfinet/linux-src/include/linux/hpfs_fs_sb.h32
-rw-r--r--pfinet/linux-src/include/linux/i2c.h190
-rw-r--r--pfinet/linux-src/include/linux/icmp.h (renamed from pfinet/linux/icmp.h)35
-rw-r--r--pfinet/linux-src/include/linux/icmpv6.h149
-rw-r--r--pfinet/linux-src/include/linux/if.h (renamed from pfinet/linux/if.h)50
-rw-r--r--pfinet/linux-src/include/linux/if_arcnet.h63
-rw-r--r--pfinet/linux-src/include/linux/if_arp.h (renamed from pfinet/linux/if_arp.h)46
-rw-r--r--pfinet/linux-src/include/linux/if_cablemodem.h22
-rw-r--r--pfinet/linux-src/include/linux/if_ec.h47
-rw-r--r--pfinet/linux-src/include/linux/if_eql.h81
-rw-r--r--pfinet/linux-src/include/linux/if_ether.h98
-rw-r--r--pfinet/linux-src/include/linux/if_fc.h50
-rw-r--r--pfinet/linux-src/include/linux/if_fddi.h223
-rw-r--r--pfinet/linux-src/include/linux/if_frad.h201
-rw-r--r--pfinet/linux-src/include/linux/if_hippi.h157
-rw-r--r--pfinet/linux-src/include/linux/if_ltalk.h12
-rw-r--r--pfinet/linux-src/include/linux/if_packet.h50
-rw-r--r--pfinet/linux-src/include/linux/if_plip.h28
-rw-r--r--pfinet/linux-src/include/linux/if_ppp.h143
-rw-r--r--pfinet/linux-src/include/linux/if_pppvar.h135
-rw-r--r--pfinet/linux-src/include/linux/if_shaper.h64
-rw-r--r--pfinet/linux-src/include/linux/if_slip.h30
-rw-r--r--pfinet/linux-src/include/linux/if_strip.h25
-rw-r--r--pfinet/linux-src/include/linux/if_tr.h100
-rw-r--r--pfinet/linux-src/include/linux/if_tunnel.h29
-rw-r--r--pfinet/linux-src/include/linux/igmp.h129
-rw-r--r--pfinet/linux-src/include/linux/in.h189
-rw-r--r--pfinet/linux-src/include/linux/in6.h193
-rw-r--r--pfinet/linux-src/include/linux/in_route.h32
-rw-r--r--pfinet/linux-src/include/linux/in_systm.h32
-rw-r--r--pfinet/linux-src/include/linux/inet.h52
-rw-r--r--pfinet/linux-src/include/linux/inetdevice.h128
-rw-r--r--pfinet/linux-src/include/linux/init.h68
-rw-r--r--pfinet/linux-src/include/linux/interrupt.h84
-rw-r--r--pfinet/linux-src/include/linux/ioctl.h7
-rw-r--r--pfinet/linux-src/include/linux/ioport.h35
-rw-r--r--pfinet/linux-src/include/linux/ip.h138
-rw-r--r--pfinet/linux-src/include/linux/ip_fw.h193
-rw-r--r--pfinet/linux-src/include/linux/ip_masq.h140
-rw-r--r--pfinet/linux-src/include/linux/ipc.h49
-rw-r--r--pfinet/linux-src/include/linux/ipsec.h69
-rw-r--r--pfinet/linux-src/include/linux/ipv6.h123
-rw-r--r--pfinet/linux-src/include/linux/ipv6_route.h56
-rw-r--r--pfinet/linux-src/include/linux/ipx.h (renamed from pfinet/linux/ipx.h)33
-rw-r--r--pfinet/linux-src/include/linux/irda.h120
-rw-r--r--pfinet/linux-src/include/linux/isdn.h936
-rw-r--r--pfinet/linux-src/include/linux/isdn_divertif.h62
-rw-r--r--pfinet/linux-src/include/linux/isdn_ppp.h236
-rw-r--r--pfinet/linux-src/include/linux/isdnif.h631
-rw-r--r--pfinet/linux-src/include/linux/isicom.h310
-rw-r--r--pfinet/linux-src/include/linux/iso_fs.h230
-rw-r--r--pfinet/linux-src/include/linux/iso_fs_i.h14
-rw-r--r--pfinet/linux-src/include/linux/iso_fs_sb.h31
-rw-r--r--pfinet/linux-src/include/linux/istallion.h134
-rw-r--r--pfinet/linux-src/include/linux/ixjuser.h629
-rw-r--r--pfinet/linux-src/include/linux/joystick.h280
-rw-r--r--pfinet/linux-src/include/linux/kbd_diacr.h8
-rw-r--r--pfinet/linux-src/include/linux/kbd_kern.h164
-rw-r--r--pfinet/linux-src/include/linux/kbd_ll.h12
-rw-r--r--pfinet/linux-src/include/linux/kd.h180
-rw-r--r--pfinet/linux-src/include/linux/kdev_t.h114
-rw-r--r--pfinet/linux-src/include/linux/kernel.h96
-rw-r--r--pfinet/linux-src/include/linux/kernel_stat.h50
-rw-r--r--pfinet/linux-src/include/linux/kernelcapi.h140
-rw-r--r--pfinet/linux-src/include/linux/keyboard.h430
-rw-r--r--pfinet/linux-src/include/linux/kmod.h12
-rw-r--r--pfinet/linux-src/include/linux/lapb.h56
-rw-r--r--pfinet/linux-src/include/linux/limits.h19
-rw-r--r--pfinet/linux-src/include/linux/linkage.h54
-rw-r--r--pfinet/linux-src/include/linux/linux_logo.h1445
-rw-r--r--pfinet/linux-src/include/linux/list.h99
-rw-r--r--pfinet/linux-src/include/linux/lists.h62
-rw-r--r--pfinet/linux-src/include/linux/locks.h62
-rw-r--r--pfinet/linux-src/include/linux/loop.h130
-rw-r--r--pfinet/linux-src/include/linux/lp.h188
-rw-r--r--pfinet/linux-src/include/linux/lp_intern.h22
-rw-r--r--pfinet/linux-src/include/linux/lp_m68k.h135
-rw-r--r--pfinet/linux-src/include/linux/lp_mfc.h14
-rw-r--r--pfinet/linux-src/include/linux/major.h135
-rw-r--r--pfinet/linux-src/include/linux/malloc.h5
-rw-r--r--pfinet/linux-src/include/linux/mc146818rtc.h149
-rw-r--r--pfinet/linux-src/include/linux/mca.h100
-rw-r--r--pfinet/linux-src/include/linux/md.h300
-rw-r--r--pfinet/linux-src/include/linux/minix_fs.h127
-rw-r--r--pfinet/linux-src/include/linux/minix_fs_i.h14
-rw-r--r--pfinet/linux-src/include/linux/minix_fs_sb.h26
-rw-r--r--pfinet/linux-src/include/linux/miscdevice.h43
-rw-r--r--pfinet/linux-src/include/linux/mm.h392
-rw-r--r--pfinet/linux-src/include/linux/mman.h8
-rw-r--r--pfinet/linux-src/include/linux/modsetver.h10
-rw-r--r--pfinet/linux-src/include/linux/module.h287
-rw-r--r--pfinet/linux-src/include/linux/mount.h47
-rw-r--r--pfinet/linux-src/include/linux/mpp.h18
-rw-r--r--pfinet/linux-src/include/linux/mroute.h223
-rw-r--r--pfinet/linux-src/include/linux/msdos_fs.h336
-rw-r--r--pfinet/linux-src/include/linux/msdos_fs_i.h39
-rw-r--r--pfinet/linux-src/include/linux/msdos_fs_sb.h59
-rw-r--r--pfinet/linux-src/include/linux/msg.h81
-rw-r--r--pfinet/linux-src/include/linux/mtio.h373
-rw-r--r--pfinet/linux-src/include/linux/nbd.h85
-rw-r--r--pfinet/linux-src/include/linux/ncp.h204
-rw-r--r--pfinet/linux-src/include/linux/ncp_fs.h331
-rw-r--r--pfinet/linux-src/include/linux/ncp_fs_i.h36
-rw-r--r--pfinet/linux-src/include/linux/ncp_fs_sb.h96
-rw-r--r--pfinet/linux-src/include/linux/ncp_mount.h45
-rw-r--r--pfinet/linux-src/include/linux/net.h (renamed from pfinet/linux/net.h)112
-rw-r--r--pfinet/linux-src/include/linux/netbeui.h16
-rw-r--r--pfinet/linux-src/include/linux/netdevice.h466
-rw-r--r--pfinet/linux-src/include/linux/netlink.h158
-rw-r--r--pfinet/linux-src/include/linux/netrom.h34
-rw-r--r--pfinet/linux-src/include/linux/nfs.h226
-rw-r--r--pfinet/linux-src/include/linux/nfs3.h252
-rw-r--r--pfinet/linux-src/include/linux/nfs_fs.h284
-rw-r--r--pfinet/linux-src/include/linux/nfs_fs_i.h71
-rw-r--r--pfinet/linux-src/include/linux/nfs_fs_sb.h31
-rw-r--r--pfinet/linux-src/include/linux/nfs_mount.h53
-rw-r--r--pfinet/linux-src/include/linux/nfsiod.h52
-rw-r--r--pfinet/linux-src/include/linux/nls.h56
-rw-r--r--pfinet/linux-src/include/linux/notifier.h (renamed from pfinet/linux/notifier.h)23
-rw-r--r--pfinet/linux-src/include/linux/ntfs_fs.h7
-rw-r--r--pfinet/linux-src/include/linux/ntfs_fs_i.h83
-rw-r--r--pfinet/linux-src/include/linux/ntfs_fs_sb.h44
-rw-r--r--pfinet/linux-src/include/linux/nubus.h96
-rw-r--r--pfinet/linux-src/include/linux/nvram.h18
-rw-r--r--pfinet/linux-src/include/linux/openpic.h362
-rw-r--r--pfinet/linux-src/include/linux/pagemap.h156
-rw-r--r--pfinet/linux-src/include/linux/param.h6
-rw-r--r--pfinet/linux-src/include/linux/parport.h396
-rw-r--r--pfinet/linux-src/include/linux/parport_pc.h152
-rw-r--r--pfinet/linux-src/include/linux/pc_keyb.h130
-rw-r--r--pfinet/linux-src/include/linux/pci.h1359
-rw-r--r--pfinet/linux-src/include/linux/personality.h57
-rw-r--r--pfinet/linux-src/include/linux/pg.h63
-rw-r--r--pfinet/linux-src/include/linux/phonedev.h26
-rw-r--r--pfinet/linux-src/include/linux/pipe_fs_i.h34
-rw-r--r--pfinet/linux-src/include/linux/pkt_cls.h146
-rw-r--r--pfinet/linux-src/include/linux/pkt_sched.h277
-rw-r--r--pfinet/linux-src/include/linux/poll.h107
-rw-r--r--pfinet/linux-src/include/linux/posix_types.h48
-rw-r--r--pfinet/linux-src/include/linux/ppp-comp.h198
-rw-r--r--pfinet/linux-src/include/linux/ppp.h4
-rw-r--r--pfinet/linux-src/include/linux/ppp_defs.h182
-rw-r--r--pfinet/linux-src/include/linux/prctl.h9
-rw-r--r--pfinet/linux-src/include/linux/proc_fs.h472
-rw-r--r--pfinet/linux-src/include/linux/ps2esdi.h98
-rw-r--r--pfinet/linux-src/include/linux/ptrace.h26
-rw-r--r--pfinet/linux-src/include/linux/qic117.h290
-rw-r--r--pfinet/linux-src/include/linux/qnx4_fs.h123
-rw-r--r--pfinet/linux-src/include/linux/qnx4_fs_i.h38
-rw-r--r--pfinet/linux-src/include/linux/qnx4_fs_sb.h27
-rw-r--r--pfinet/linux-src/include/linux/qnxtypes.h28
-rw-r--r--pfinet/linux-src/include/linux/quota.h209
-rw-r--r--pfinet/linux-src/include/linux/quotaops.h134
-rw-r--r--pfinet/linux-src/include/linux/raid0.h27
-rw-r--r--pfinet/linux-src/include/linux/raid1.h49
-rw-r--r--pfinet/linux-src/include/linux/raid5.h110
-rw-r--r--pfinet/linux-src/include/linux/random.h73
-rw-r--r--pfinet/linux-src/include/linux/reboot.h52
-rw-r--r--pfinet/linux-src/include/linux/resource.h60
-rw-r--r--pfinet/linux-src/include/linux/rocket.h55
-rw-r--r--pfinet/linux-src/include/linux/romfs_fs.h62
-rw-r--r--pfinet/linux-src/include/linux/romfs_fs_i.h11
-rw-r--r--pfinet/linux-src/include/linux/romfs_fs_sb.h10
-rw-r--r--pfinet/linux-src/include/linux/rose.h87
-rw-r--r--pfinet/linux-src/include/linux/route.h70
-rw-r--r--pfinet/linux-src/include/linux/rpcsock.h121
-rw-r--r--pfinet/linux-src/include/linux/rtnetlink.h673
-rw-r--r--pfinet/linux-src/include/linux/sc26198.h533
-rw-r--r--pfinet/linux-src/include/linux/scc.h258
-rw-r--r--pfinet/linux-src/include/linux/sched.h813
-rw-r--r--pfinet/linux-src/include/linux/sdla.h339
-rw-r--r--pfinet/linux-src/include/linux/sdla_chdlc.h808
-rw-r--r--pfinet/linux-src/include/linux/sdla_fr.h638
-rw-r--r--pfinet/linux-src/include/linux/sdla_ppp.h573
-rw-r--r--pfinet/linux-src/include/linux/sdla_x25.h625
-rw-r--r--pfinet/linux-src/include/linux/sdladrv.h77
-rw-r--r--pfinet/linux-src/include/linux/sdlapci.h68
-rw-r--r--pfinet/linux-src/include/linux/sdlasfm.h104
-rw-r--r--pfinet/linux-src/include/linux/securebits.h30
-rw-r--r--pfinet/linux-src/include/linux/selection.h44
-rw-r--r--pfinet/linux-src/include/linux/sem.h114
-rw-r--r--pfinet/linux-src/include/linux/serial.h142
-rw-r--r--pfinet/linux-src/include/linux/serial167.h175
-rw-r--r--pfinet/linux-src/include/linux/serialP.h119
-rw-r--r--pfinet/linux-src/include/linux/serial_reg.h144
-rw-r--r--pfinet/linux-src/include/linux/shm.h79
-rw-r--r--pfinet/linux-src/include/linux/signal.h212
-rw-r--r--pfinet/linux-src/include/linux/skbuff.h584
-rw-r--r--pfinet/linux-src/include/linux/slab.h71
-rw-r--r--pfinet/linux-src/include/linux/smb.h123
-rw-r--r--pfinet/linux-src/include/linux/smb_fs.h240
-rw-r--r--pfinet/linux-src/include/linux/smb_fs_i.h35
-rw-r--r--pfinet/linux-src/include/linux/smb_fs_sb.h50
-rw-r--r--pfinet/linux-src/include/linux/smb_mount.h25
-rw-r--r--pfinet/linux-src/include/linux/smbno.h278
-rw-r--r--pfinet/linux-src/include/linux/smp.h86
-rw-r--r--pfinet/linux-src/include/linux/smp_lock.h17
-rw-r--r--pfinet/linux-src/include/linux/socket.h280
-rw-r--r--pfinet/linux-src/include/linux/sockios.h109
-rw-r--r--pfinet/linux-src/include/linux/sound.h15
-rw-r--r--pfinet/linux-src/include/linux/soundcard.h1270
-rw-r--r--pfinet/linux-src/include/linux/soundmodem.h90
-rw-r--r--pfinet/linux-src/include/linux/stallion.h156
-rw-r--r--pfinet/linux-src/include/linux/stat.h57
-rw-r--r--pfinet/linux-src/include/linux/stddef.h14
-rw-r--r--pfinet/linux-src/include/linux/string.h43
-rw-r--r--pfinet/linux-src/include/linux/swap.h175
-rw-r--r--pfinet/linux-src/include/linux/swapctl.h35
-rw-r--r--pfinet/linux-src/include/linux/synclink.h255
-rw-r--r--pfinet/linux-src/include/linux/sys.h30
-rw-r--r--pfinet/linux-src/include/linux/sysctl.h559
-rw-r--r--pfinet/linux-src/include/linux/sysrq.h40
-rw-r--r--pfinet/linux-src/include/linux/sysv_fs.h414
-rw-r--r--pfinet/linux-src/include/linux/sysv_fs_i.h16
-rw-r--r--pfinet/linux-src/include/linux/sysv_fs_sb.h122
-rw-r--r--pfinet/linux-src/include/linux/tasks.h25
-rw-r--r--pfinet/linux-src/include/linux/tcp.h (renamed from pfinet/linux/tcp.h)80
-rw-r--r--pfinet/linux-src/include/linux/telephony.h200
-rw-r--r--pfinet/linux-src/include/linux/termios.h7
-rw-r--r--pfinet/linux-src/include/linux/time.h92
-rw-r--r--pfinet/linux-src/include/linux/timer.h96
-rw-r--r--pfinet/linux-src/include/linux/times.h11
-rw-r--r--pfinet/linux-src/include/linux/timex.h277
-rw-r--r--pfinet/linux-src/include/linux/tpqic02.h739
-rw-r--r--pfinet/linux-src/include/linux/tqueue.h124
-rw-r--r--pfinet/linux-src/include/linux/trdevice.h (renamed from pfinet/linux/etherdevice.h)21
-rw-r--r--pfinet/linux-src/include/linux/tty.h417
-rw-r--r--pfinet/linux-src/include/linux/tty_driver.h227
-rw-r--r--pfinet/linux-src/include/linux/tty_flip.h35
-rw-r--r--pfinet/linux-src/include/linux/tty_ldisc.h138
-rw-r--r--pfinet/linux-src/include/linux/types.h108
-rw-r--r--pfinet/linux-src/include/linux/udp.h (renamed from pfinet/linux/udp.h)8
-rw-r--r--pfinet/linux-src/include/linux/ufs_fs.h571
-rw-r--r--pfinet/linux-src/include/linux/ufs_fs_i.h32
-rw-r--r--pfinet/linux-src/include/linux/ufs_fs_sb.h245
-rw-r--r--pfinet/linux-src/include/linux/uio.h37
-rw-r--r--pfinet/linux-src/include/linux/ultrasound.h103
-rw-r--r--pfinet/linux-src/include/linux/umsdos_fs.h188
-rw-r--r--pfinet/linux-src/include/linux/umsdos_fs.p118
-rw-r--r--pfinet/linux-src/include/linux/umsdos_fs_i.h75
-rw-r--r--pfinet/linux-src/include/linux/un.h11
-rw-r--r--pfinet/linux-src/include/linux/unistd.h11
-rw-r--r--pfinet/linux-src/include/linux/user.h1
-rw-r--r--pfinet/linux-src/include/linux/utime.h9
-rw-r--r--pfinet/linux-src/include/linux/uts.h23
-rw-r--r--pfinet/linux-src/include/linux/utsname.h36
-rw-r--r--pfinet/linux-src/include/linux/vfs.h6
-rw-r--r--pfinet/linux-src/include/linux/video_decoder.h37
-rw-r--r--pfinet/linux-src/include/linux/video_encoder.h21
-rw-r--r--pfinet/linux-src/include/linux/videodev.h293
-rw-r--r--pfinet/linux-src/include/linux/videotext.h144
-rw-r--r--pfinet/linux-src/include/linux/vmalloc.h24
-rw-r--r--pfinet/linux-src/include/linux/vt.h54
-rw-r--r--pfinet/linux-src/include/linux/vt_buffer.h83
-rw-r--r--pfinet/linux-src/include/linux/vt_kern.h94
-rw-r--r--pfinet/linux-src/include/linux/wait.h33
-rw-r--r--pfinet/linux-src/include/linux/wanpipe.h372
-rw-r--r--pfinet/linux-src/include/linux/wanrouter.h476
-rw-r--r--pfinet/linux-src/include/linux/watchdog.h40
-rw-r--r--pfinet/linux-src/include/linux/wavefront.h675
-rw-r--r--pfinet/linux-src/include/linux/wireless.h448
-rw-r--r--pfinet/linux-src/include/linux/wrapper.h40
-rw-r--r--pfinet/linux-src/include/linux/x25.h93
-rw-r--r--pfinet/linux-src/include/linux/yam.h82
-rw-r--r--pfinet/linux-src/include/linux/zftape.h87
-rw-r--r--pfinet/linux-src/include/linux/zorro.h736
-rw-r--r--pfinet/linux-src/include/net/addrconf.h158
-rw-r--r--pfinet/linux-src/include/net/af_unix.h35
-rw-r--r--pfinet/linux-src/include/net/arp.h24
-rw-r--r--pfinet/linux-src/include/net/atalkcall.h2
-rw-r--r--pfinet/linux-src/include/net/ax25.h349
-rw-r--r--pfinet/linux-src/include/net/ax25call.h2
-rw-r--r--pfinet/linux-src/include/net/br.h331
-rw-r--r--pfinet/linux-src/include/net/checksum.h110
-rw-r--r--pfinet/linux-src/include/net/datalink.h (renamed from pfinet/linux-inet/datalink.h)3
-rw-r--r--pfinet/linux-src/include/net/dst.h178
-rw-r--r--pfinet/linux-src/include/net/flow.h101
-rw-r--r--pfinet/linux-src/include/net/icmp.h (renamed from pfinet/linux-inet/icmp.h)20
-rw-r--r--pfinet/linux-src/include/net/if_inet6.h134
-rw-r--r--pfinet/linux-src/include/net/inet_common.h45
-rw-r--r--pfinet/linux-src/include/net/ip.h267
-rw-r--r--pfinet/linux-src/include/net/ip6_fib.h177
-rw-r--r--pfinet/linux-src/include/net/ip6_fw.h54
-rw-r--r--pfinet/linux-src/include/net/ip6_route.h111
-rw-r--r--pfinet/linux-src/include/net/ip_fib.h257
-rw-r--r--pfinet/linux-src/include/net/ip_masq.h362
-rw-r--r--pfinet/linux-src/include/net/ip_masq_mod.h86
-rw-r--r--pfinet/linux-src/include/net/ipconfig.h21
-rw-r--r--pfinet/linux-src/include/net/ipip.h33
-rw-r--r--pfinet/linux-src/include/net/ipv6.h325
-rw-r--r--pfinet/linux-src/include/net/ipx.h (renamed from pfinet/linux-inet/ipx.h)44
-rw-r--r--pfinet/linux-src/include/net/ipxcall.h (renamed from pfinet/linux-inet/ipxcall.h)0
-rw-r--r--pfinet/linux-src/include/net/lapb.h150
-rw-r--r--pfinet/linux-src/include/net/lapbcall.h2
-rw-r--r--pfinet/linux-src/include/net/llc.h135
-rw-r--r--pfinet/linux-src/include/net/llc_frame.h98
-rw-r--r--pfinet/linux-src/include/net/llc_name.h7
-rw-r--r--pfinet/linux-src/include/net/llc_state.h4
-rw-r--r--pfinet/linux-src/include/net/llccall.h3
-rw-r--r--pfinet/linux-src/include/net/ndisc.h123
-rw-r--r--pfinet/linux-src/include/net/neighbour.h272
-rw-r--r--pfinet/linux-src/include/net/netbeuicall.h2
-rw-r--r--pfinet/linux-src/include/net/netrom.h181
-rw-r--r--pfinet/linux-src/include/net/nrcall.h2
-rw-r--r--pfinet/linux-src/include/net/p8022.h7
-rw-r--r--pfinet/linux-src/include/net/p8022call.h (renamed from pfinet/linux-inet/p8022call.h)0
-rw-r--r--pfinet/linux-src/include/net/pkt_cls.h93
-rw-r--r--pfinet/linux-src/include/net/pkt_sched.h407
-rw-r--r--pfinet/linux-src/include/net/profile.h311
-rw-r--r--pfinet/linux-src/include/net/protocol.h82
-rw-r--r--pfinet/linux-src/include/net/psnap.h7
-rw-r--r--pfinet/linux-src/include/net/psnapcall.h (renamed from pfinet/linux-inet/psnapcall.h)0
-rw-r--r--pfinet/linux-src/include/net/rarp.h (renamed from pfinet/linux-inet/rarp.h)6
-rw-r--r--pfinet/linux-src/include/net/raw.h (renamed from pfinet/linux-inet/raw.h)22
-rw-r--r--pfinet/linux-src/include/net/rawv6.h27
-rw-r--r--pfinet/linux-src/include/net/rose.h241
-rw-r--r--pfinet/linux-src/include/net/rosecall.h2
-rw-r--r--pfinet/linux-src/include/net/route.h153
-rw-r--r--pfinet/linux-src/include/net/scm.h67
-rw-r--r--pfinet/linux-src/include/net/slhc.h6
-rw-r--r--pfinet/linux-src/include/net/slhc_vj.h187
-rw-r--r--pfinet/linux-src/include/net/snmp.h (renamed from pfinet/linux-inet/snmp.h)78
-rw-r--r--pfinet/linux-src/include/net/sock.h950
-rw-r--r--pfinet/linux-src/include/net/spx.h93
-rw-r--r--pfinet/linux-src/include/net/spxcall.h2
-rw-r--r--pfinet/linux-src/include/net/tcp.h1097
-rw-r--r--pfinet/linux-src/include/net/transp_v6.h46
-rw-r--r--pfinet/linux-src/include/net/udp.h (renamed from pfinet/linux-inet/udp.h)40
-rw-r--r--pfinet/linux-src/include/net/x25.h221
-rw-r--r--pfinet/linux-src/include/net/x25call.h2
-rw-r--r--pfinet/linux-src/net/core/Makefile41
-rw-r--r--pfinet/linux-src/net/core/datagram.c249
-rw-r--r--pfinet/linux-src/net/core/dev.c2071
-rw-r--r--pfinet/linux-src/net/core/dev_mcast.c252
-rw-r--r--pfinet/linux-src/net/core/dst.c145
-rw-r--r--pfinet/linux-src/net/core/filter.c454
-rw-r--r--pfinet/linux-src/net/core/firewall.c160
-rw-r--r--pfinet/linux-src/net/core/iovec.c278
-rw-r--r--pfinet/linux-src/net/core/neighbour.c1394
-rw-r--r--pfinet/linux-src/net/core/profile.c305
-rw-r--r--pfinet/linux-src/net/core/rtnetlink.c512
-rw-r--r--pfinet/linux-src/net/core/scm.c280
-rw-r--r--pfinet/linux-src/net/core/skbuff.c385
-rw-r--r--pfinet/linux-src/net/core/sock.c1051
-rw-r--r--pfinet/linux-src/net/core/sysctl_net_core.c61
-rw-r--r--pfinet/linux-src/net/core/utils.c66
-rw-r--r--pfinet/linux-src/net/ethernet/Makefile33
-rw-r--r--pfinet/linux-src/net/ethernet/eth.c (renamed from pfinet/linux-inet/eth.c)166
-rw-r--r--pfinet/linux-src/net/ethernet/pe2.c (renamed from pfinet/linux-inet/pe2.c)15
-rw-r--r--pfinet/linux-src/net/ethernet/sysctl_net_ether.c13
-rw-r--r--pfinet/linux-src/net/ipv4/Config.in85
-rw-r--r--pfinet/linux-src/net/ipv4/Makefile116
-rw-r--r--pfinet/linux-src/net/ipv4/af_inet.c1167
-rw-r--r--pfinet/linux-src/net/ipv4/arp.c1191
-rw-r--r--pfinet/linux-src/net/ipv4/devinet.c1121
-rw-r--r--pfinet/linux-src/net/ipv4/fib_frontend.c628
-rw-r--r--pfinet/linux-src/net/ipv4/fib_hash.c885
-rw-r--r--pfinet/linux-src/net/ipv4/fib_rules.c419
-rw-r--r--pfinet/linux-src/net/ipv4/fib_semantics.c991
-rw-r--r--pfinet/linux-src/net/ipv4/icmp.c1156
-rw-r--r--pfinet/linux-src/net/ipv4/igmp.c698
-rw-r--r--pfinet/linux-src/net/ipv4/ip_forward.c292
-rw-r--r--pfinet/linux-src/net/ipv4/ip_fragment.c593
-rw-r--r--pfinet/linux-src/net/ipv4/ip_fw.c1773
-rw-r--r--pfinet/linux-src/net/ipv4/ip_gre.c1223
-rw-r--r--pfinet/linux-src/net/ipv4/ip_input.c551
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq.c2570
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_app.c603
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_autofw.c448
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_cuseeme.c264
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_ftp.c393
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_irc.c345
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_mfw.c770
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_mod.c322
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_portfw.c509
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_quake.c322
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_raudio.c578
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_user.c473
-rw-r--r--pfinet/linux-src/net/ipv4/ip_masq_vdolive.c294
-rw-r--r--pfinet/linux-src/net/ipv4/ip_nat_dumb.c158
-rw-r--r--pfinet/linux-src/net/ipv4/ip_options.c620
-rw-r--r--pfinet/linux-src/net/ipv4/ip_output.c992
-rw-r--r--pfinet/linux-src/net/ipv4/ip_sockglue.c739
-rw-r--r--pfinet/linux-src/net/ipv4/ipconfig.c970
-rw-r--r--pfinet/linux-src/net/ipv4/ipip.c870
-rw-r--r--pfinet/linux-src/net/ipv4/ipmr.c1609
-rw-r--r--pfinet/linux-src/net/ipv4/proc.c (renamed from pfinet/linux-inet/proc.c)312
-rw-r--r--pfinet/linux-src/net/ipv4/protocol.c211
-rw-r--r--pfinet/linux-src/net/ipv4/rarp.c (renamed from pfinet/linux-inet/rarp.c)295
-rw-r--r--pfinet/linux-src/net/ipv4/raw.c573
-rw-r--r--pfinet/linux-src/net/ipv4/route.c2050
-rw-r--r--pfinet/linux-src/net/ipv4/syncookies.c203
-rw-r--r--pfinet/linux-src/net/ipv4/sysctl_net_ipv4.c210
-rw-r--r--pfinet/linux-src/net/ipv4/tcp.c1886
-rw-r--r--pfinet/linux-src/net/ipv4/tcp_input.c2432
-rw-r--r--pfinet/linux-src/net/ipv4/tcp_ipv4.c2052
-rw-r--r--pfinet/linux-src/net/ipv4/tcp_output.c1143
-rw-r--r--pfinet/linux-src/net/ipv4/tcp_timer.c595
-rw-r--r--pfinet/linux-src/net/ipv4/timer.c127
-rw-r--r--pfinet/linux-src/net/ipv4/udp.c1200
-rw-r--r--pfinet/linux-src/net/ipv4/utils.c (renamed from pfinet/linux-inet/utils.c)16
-rw-r--r--pfinet/linux-src/net/ipv6/addrconf.c1964
-rw-r--r--pfinet/linux-src/net/ipv6/af_inet6.c642
-rw-r--r--pfinet/linux-src/net/ipv6/datagram_ipv6.c434
-rw-r--r--pfinet/linux-src/net/ipv6/exthdrs.c771
-rw-r--r--pfinet/linux-src/net/ipv6/icmpv6.c676
-rw-r--r--pfinet/linux-src/net/ipv6/ip6_fib.c1205
-rw-r--r--pfinet/linux-src/net/ipv6/ip6_flowlabel.c627
-rw-r--r--pfinet/linux-src/net/ipv6/ip6_input.c284
-rw-r--r--pfinet/linux-src/net/ipv6/ip6_output.c720
-rw-r--r--pfinet/linux-src/net/ipv6/ipv6_sockglue.c439
-rw-r--r--pfinet/linux-src/net/ipv6/mcast.c711
-rw-r--r--pfinet/linux-src/net/ipv6/ndisc.c1217
-rw-r--r--pfinet/linux-src/net/ipv6/protocol_ipv6.c117
-rw-r--r--pfinet/linux-src/net/ipv6/raw_ipv6.c691
-rw-r--r--pfinet/linux-src/net/ipv6/reassembly.c492
-rw-r--r--pfinet/linux-src/net/ipv6/route_ipv6.c1974
-rw-r--r--pfinet/linux-src/net/ipv6/tcp_ipv6.c1767
-rw-r--r--pfinet/linux-src/net/ipv6/udp_ipv6.c967
-rw-r--r--pfinet/linux/errno.h8
-rw-r--r--pfinet/linux/if_ether.h80
-rw-r--r--pfinet/linux/igmp.h67
-rw-r--r--pfinet/linux/in.h1
-rw-r--r--pfinet/linux/inet.h6
-rw-r--r--pfinet/linux/interrupt.h11
-rw-r--r--pfinet/linux/ip.h121
-rw-r--r--pfinet/linux/ip_fw.h147
-rw-r--r--pfinet/linux/kernel.h44
-rw-r--r--pfinet/linux/malloc.h10
-rw-r--r--pfinet/linux/mm.h16
-rw-r--r--pfinet/linux/netdevice.h235
-rw-r--r--pfinet/linux/route.h69
-rw-r--r--pfinet/linux/sched.h81
-rw-r--r--pfinet/linux/skbuff.h286
-rw-r--r--pfinet/linux/socket.h27
-rw-r--r--pfinet/linux/time.h13
-rw-r--r--pfinet/linux/types.h16
-rw-r--r--pfinet/linux/wait.h23
-rw-r--r--pfinet/loopback.c130
-rw-r--r--pfinet/main.c382
-rw-r--r--pfinet/mapped-time.h27
-rw-r--r--pfinet/misc.c146
-rw-r--r--pfinet/mutations.h2
-rw-r--r--pfinet/options.c356
-rw-r--r--pfinet/pfinet-ops.c93
-rw-r--r--pfinet/pfinet.h73
-rw-r--r--pfinet/sched.c84
-rw-r--r--pfinet/socket-ops.c450
-rw-r--r--pfinet/socket.c107
-rw-r--r--pfinet/stubs.c73
-rw-r--r--pfinet/timer-emul.c58
-rw-r--r--pfinet/tunnel.c635
-rw-r--r--pflocal/ChangeLog248
-rw-r--r--pflocal/Makefile5
-rw-r--r--pflocal/connq.c34
-rw-r--r--pflocal/connq.h3
-rw-r--r--pflocal/io.c73
-rw-r--r--pflocal/mig-decls.h16
-rw-r--r--pflocal/pf.c51
-rw-r--r--pflocal/pflocal.c12
-rw-r--r--pflocal/sock.c58
-rw-r--r--pflocal/sock.h17
-rw-r--r--pflocal/socket.c61
-rw-r--r--pflocal/sserver.c5
-rw-r--r--proc/ChangeLog867
-rw-r--r--proc/Makefile4
-rw-r--r--proc/cpu-types.c38
-rw-r--r--proc/hash.c53
-rw-r--r--proc/host.c371
-rw-r--r--proc/info.c285
-rw-r--r--proc/main.c70
-rw-r--r--proc/mgt.c484
-rw-r--r--proc/msg.c55
-rw-r--r--proc/notify.c12
-rw-r--r--proc/pgrp.c115
-rw-r--r--proc/primes.c135
-rw-r--r--proc/proc.h77
-rw-r--r--proc/stubs.c208
-rw-r--r--proc/wait.c183
-rw-r--r--release/=announce-0.057
-rw-r--r--release/=announce-0.170
-rw-r--r--release/=announce-0.262
-rw-r--r--release/ChangeLog110
-rw-r--r--release/INSTALL-GRUB-MBR40
-rw-r--r--release/INSTALL-binary107
-rw-r--r--release/Makefile52
-rw-r--r--release/SETUP47
-rw-r--r--release/SOURCES.0.04
-rw-r--r--release/SOURCES.0.2110
-rw-r--r--release/bfloppy-special.copy1
-rw-r--r--release/bfloppy.boot14
-rw-r--r--release/bfloppy.copy11
-rw-r--r--release/bfloppy1-special.copy1
-rw-r--r--release/bfloppy1.copy7
-rw-r--r--release/bfloppy1.grub29
-rw-r--r--release/bfloppy2-special.copy2
-rw-r--r--release/bfloppy2.boot14
-rw-r--r--release/bfloppy2.copy4
-rw-r--r--release/checklist54
-rw-r--r--release/dist-README5
-rw-r--r--release/menu.lst27
-rwxr-xr-xrelease/mkemptyso.sh5
-rw-r--r--release/mkfsimage.sh412
-rwxr-xr-xrelease/mksmallso.sh48
-rw-r--r--release/release-steps8
-rw-r--r--release/rfloppy-special.copy3
-rw-r--r--release/rfloppy.copy175
-rw-r--r--release/rfloppy.group1
-rw-r--r--release/rfloppy.nss19
-rw-r--r--release/rfloppy.passwd1
-rw-r--r--release/servers.boot10
-rw-r--r--release/tool-Makefile141
-rw-r--r--storeio/Makefile29
-rw-r--r--storeio/dev.c473
-rw-r--r--storeio/dev.h127
-rw-r--r--storeio/io.c (renamed from devio/io.c)335
-rw-r--r--storeio/open.c127
-rw-r--r--storeio/open.h (renamed from devio/open.h)37
-rw-r--r--storeio/pager.c265
-rw-r--r--storeio/storeio.c425
-rw-r--r--sutils/ChangeLog60
-rw-r--r--sutils/MAKEDEV.sh204
-rw-r--r--sutils/Makefile30
-rw-r--r--sutils/clookup.c24
-rwxr-xr-xsutils/e2os.sh153
-rw-r--r--sutils/fsck.c174
-rw-r--r--sutils/fstab.c479
-rw-r--r--sutils/fstab.h64
-rw-r--r--sutils/halt.c14
-rw-r--r--sutils/losetup.sh66
-rw-r--r--sutils/reboot.c18
-rw-r--r--sutils/swapoff.c2
-rw-r--r--sutils/swapon.c536
-rw-r--r--sutils/update.c7
-rw-r--r--tasks126
-rw-r--r--term/ChangeLog405
-rw-r--r--term/Makefile11
-rw-r--r--term/devio.c458
-rw-r--r--term/hurdio.c628
-rw-r--r--term/main.c428
-rw-r--r--term/munge.c44
-rw-r--r--term/ptyio.c169
-rw-r--r--term/term.h133
-rw-r--r--term/users.c819
-rw-r--r--term/xinl.c2
-rw-r--r--tmpfs/Makefile29
-rw-r--r--tmpfs/dir.c307
-rw-r--r--tmpfs/node.c590
-rw-r--r--tmpfs/pager-stubs.c88
-rw-r--r--tmpfs/tmpfs.c402
-rw-r--r--tmpfs/tmpfs.h85
-rw-r--r--trans/ChangeLog324
-rw-r--r--trans/Makefile39
-rw-r--r--trans/bogus-fifo.c1
-rw-r--r--trans/crash.c230
-rw-r--r--trans/devport.c185
-rw-r--r--trans/fakeroot.c925
-rw-r--r--trans/fifo.c188
-rw-r--r--trans/firmlink.c277
-rw-r--r--trans/fwd.c14
-rw-r--r--trans/hello-mt.c331
-rw-r--r--trans/hello.c291
-rw-r--r--trans/ifsock.c38
-rw-r--r--trans/magic.c589
-rw-r--r--trans/new-fifo.c100
-rw-r--r--trans/null.c142
-rw-r--r--trans/password.c224
-rw-r--r--trans/proxy-defpager.c278
-rw-r--r--trans/streamio.c1161
-rw-r--r--trans/symlink.c97
-rw-r--r--ufs-fsck/ChangeLog256
-rw-r--r--ufs-fsck/Makefile8
-rw-r--r--ufs-fsck/dir.c102
-rw-r--r--ufs-fsck/fsck.h14
-rw-r--r--ufs-fsck/main.c5
-rw-r--r--ufs-fsck/pass1.c78
-rw-r--r--ufs-fsck/pass1b.c10
-rw-r--r--ufs-fsck/pass2.c51
-rw-r--r--ufs-fsck/pass5.c80
-rw-r--r--ufs-fsck/setup.c21
-rw-r--r--ufs-fsck/utilities.c46
-rw-r--r--ufs-utils/ChangeLog109
-rw-r--r--ufs-utils/Makefile3
-rw-r--r--ufs-utils/dlabel.c20
-rw-r--r--ufs-utils/mkfs.c55
-rw-r--r--ufs-utils/stati.c3
-rw-r--r--ufs/ChangeLog1591
-rw-r--r--ufs/Makefile17
-rw-r--r--ufs/alloc.c101
-rw-r--r--ufs/consts.c10
-rw-r--r--ufs/devio.c70
-rw-r--r--ufs/dir.c314
-rw-r--r--ufs/dir.h13
-rw-r--r--ufs/hyper.c85
-rw-r--r--ufs/inode.c335
-rw-r--r--ufs/main.c105
-rw-r--r--ufs/mapbuf.c36
-rw-r--r--ufs/pager.c90
-rw-r--r--ufs/pokeloc.c2
-rw-r--r--ufs/sizes.c40
-rw-r--r--ufs/ufs.h60
-rw-r--r--ufs/xinl.c2
-rw-r--r--usermux/Makefile (renamed from mkbootfs/Makefile)22
-rw-r--r--usermux/leaf.c152
-rw-r--r--usermux/mux.c502
-rw-r--r--usermux/node.c129
-rw-r--r--usermux/stubs.c143
-rw-r--r--usermux/usermux-xinl.c (renamed from libmom/hash-ref.c)18
-rw-r--r--usermux/usermux.c156
-rw-r--r--usermux/usermux.h99
-rw-r--r--utils/ChangeLog1152
-rw-r--r--utils/Makefile72
-rw-r--r--utils/addauth.c100
-rw-r--r--utils/devprobe.c29
-rw-r--r--utils/fakeauth.c434
-rw-r--r--utils/fakeroot.sh63
-rw-r--r--utils/frobauth-mod.c162
-rw-r--r--utils/frobauth.c282
-rw-r--r--utils/frobauth.doc83
-rw-r--r--utils/frobauth.h71
-rw-r--r--utils/fsysopts.c18
-rw-r--r--utils/ftpcp.c397
-rw-r--r--utils/ftpdir.c329
-rw-r--r--utils/gcore.c107
-rw-r--r--utils/hurdids.c156
-rw-r--r--utils/ids.c196
-rw-r--r--utils/login.c424
-rw-r--r--utils/mount.c582
-rwxr-xr-xutils/mount.sh73
-rw-r--r--utils/msgport.c661
-rw-r--r--utils/nonsugid.c63
-rw-r--r--utils/old-ps.c183
-rw-r--r--utils/old-settrans.c104
-rw-r--r--utils/parse.c185
-rw-r--r--utils/parse.h63
-rw-r--r--utils/pids.c231
-rw-r--r--utils/pids.h47
-rw-r--r--utils/portinfo.c30
-rw-r--r--utils/ps.c472
-rw-r--r--utils/psout.c42
-rw-r--r--utils/psout.h12
-rw-r--r--utils/rmauth.c121
-rw-r--r--utils/rpctrace.c1238
-rw-r--r--utils/setauth.c134
-rw-r--r--utils/settrans.c171
-rw-r--r--utils/shd.c82
-rw-r--r--utils/showtrans.c34
-rw-r--r--utils/storecat.c73
-rw-r--r--utils/storeinfo.c87
-rw-r--r--utils/storeread.c (renamed from libstore/storeread.c)56
-rw-r--r--utils/su.c481
-rw-r--r--utils/sush.sh91
-rw-r--r--utils/syncfs.c80
-rw-r--r--utils/unsu.c90
-rw-r--r--utils/uptime.sh62
-rw-r--r--utils/vminfo.c241
-rw-r--r--utils/vmstat.c332
-rw-r--r--utils/w.c195
-rw-r--r--utils/x.c4
-rw-r--r--version.h.in29
1717 files changed, 252489 insertions, 70495 deletions
diff --git a/BUGS b/BUGS
index 1c58c181..dd1307ef 100644
--- a/BUGS
+++ b/BUGS
@@ -31,3 +31,6 @@ permission; this will cause a failure of vm_wire if the current
permission is later promoted.
Patch for MiG dealing when sreplyport and mach_port_poly_t are used together.
+
+Install Linux and NetBSD physical CPU reset code in place of current
+Mach version.
diff --git a/ChangeLog b/ChangeLog
index 20c956c6..053477ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,929 +1,62 @@
-Fri Aug 2 11:02:11 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * Released source version 0.0.
-
- * Makefile (cp-linked-files): Add missing hyphen to rule.
- (dist): Delete directory named for VERSION, not old var DATE.
- Build tar file from SRCDIR to avoid embedding an odd pathname in
- the archive.
-
-Tue Jul 30 13:54:47 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * Makeconf (top_srcdirinc): Don't define EWOULDBLOCK anymore.
-
-Sat Jul 20 15:42:43 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (lndist): Find DISTFILES in $(srcdir).
- * Makefile (date): Delete vare.
- (version, dirname): New vars.
- (dist): Operate in $(srcdir). Use $(dirname) for the tar dir name.
- (hurd-snap): Create in $(srcdir).
-
-Thu Jul 18 00:40:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (install): Depend on $(includedir)/$(installhdrsubdir).
- (install-headers): Likewise.
- ($(includedir)/$(installhdrsubdir)): New rule.
-
- * Makeconf (vpath -l%): Tell make where to find -l libraries.
-
-Wed Jul 17 22:49:50 1996 Roland McGrath <roland@baalperazim.frob.com>
-
- * build.mkcf.in: Use top_srcdir instead of srcdir.
-
-Wed Jul 17 14:28:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf: gs/install-hdrs/install-headers/g
- * Makefile: Likewise.
-
-Tue Jul 16 11:35:48 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (CFLAGS): Define EWOULDBLOCK here to work around new
- libc bug.
-
-Sat Jul 13 20:34:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (other-subdirs): Add `include'.
- * Makeconf (install-hdrs) [library]: Depend on installed copies of
- headers.
- (install-hdrs): Provide default target.
- * Makefile (%-install-hdrs, install-hdrs): New targets.
- * INSTALL: Discourage cross-building; include instructions for
- libc/hurd co-installation.
- * README: Discourage cross-building.
-
- * Makefile (install): Install $(other-subdirs) too.
-
-Fri Jul 12 14:18:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (install) [doinst==one || doinst==many]: Include
- file-specific options in call to INSTALL_PROGRAM.
-
-Mon Jul 8 00:54:56 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Removed *.h.
-
- * Makefile (DIST_FILES): Removed INSTALL-binary; now in
- ./release/.
- (other-subdirs): Add `release'.
- * release: New directory.
-
- * Makeconf: disable excessive cleverness for now...
-
-Sun Jul 7 22:41:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (lib-subdirs): Move libthreads up before libpager.
- * Makeconf (libs) [library]: Depend on add-to-librecord instead of
- $(targets).
- (install) [library]: Add dependency on add-to-librecord.
- (add-to-librecord) [library]: Depend on $(targets).
- (librecord) [MAKELEVEL == 0]: Define and export.
- (include librecord): New inclusion.
- ($(librecord)): New target.
- (add-to-librecord): New target.
-
-Thu Jun 27 09:51:44 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * config.make.in (installationdirlist): New variable.
- * Makeconf (MKINSTALLDIRS): New variable.
- (install) [all versions]: Add dependency on the directory being
- installed into.
- ($(installationdirlist)): New dependency.
-
- * Makefile (linked-files, lf-inst): New variables.
- (cp-linked-files): Use implicit rule.
- ($(lfinst)): New implicit rule.
- * mkinstalldirs: New symlink to /gd/gnu/lib program.
-
- * Makefile (distclean): Add config.cache.
-
- * Makefile (lndist-cthreads-h): Delet target.
- (lndist): Remove `lndist-cthreads-h'.
-
-Fri Jun 21 12:28:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makeconf ($(target)): Get rid of -defsym hack for ___brk_addr
- (there's a hack in libc now).
-
-Thu Jun 20 14:33:01 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (prog-subdirs): Add `daemons'.
- * daemons: New directory.
- * config.make.in (libexecdir): New variable.
-
-Mon Jun 17 11:24:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf ($(target)): Add bletcherous hack to deal with undefined
- (and unused) libc symbol.
-
- * Makefile (prog-subdirs): init.trim -> init.
- (other-subdirs): Delete init; add config.
- * init.trim: Renamed to be init.
- * init: Sluffed into olds.
-
- * config: New directory.
-
-Mon Jun 17 10:30:54 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makeconf (CPPFLAGS): Add -I$(top_srcdir)/include.
- (INSTALLED_LOCAL_HEADERS): Split into two cases based on
- $(installhdrsubdir).
- ($(INSTALLED_LOCAL_HEADERS)) [$(installhdrsubdir) == .]: Linked to
- $(top_srcdir)/include. Prefix ../ to link contents.
- * include: New directory.
-
- * Makefile (prog-subdirs): Rename fsck to ufs-fsck. Add sutils.
- * ufs-fsck: Renamed from fsck.
- * sutils: New directory.
-
-Thu Jun 13 17:14:44 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * config.make.in (localstatedir, sharedstatedir): Add variables.
-
-Fri May 24 15:16:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (lib-subdirs): Add libmom.
- * libmom: New directory.
-
-Sat May 11 17:00:19 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * Makeconf: Add .PHONY spec for phony targets.
-
-Thu May 9 12:19:08 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Add *.h.
-
- * Makeconf (INSTALLED_LOCAL_HEADERS): New variable that $(libs)
- depends on. This arranges to make sure that headers exported by
- this library always get installed eventually into the source
- directory as symlinks.
-
-Mon May 6 16:25:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * libiohelp: Renamed from `libioserver'.
- * Makefile (lib-subdirs): libioserver -> libiohelp.
-
-Tue Apr 30 22:06:05 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Add build.mkcf.in.
- * build.mkcf.in: New file.
- * configure.in (makefiles): Add Makeconf:build.mkcf.in.
-
- * Makefile (srcdir): Set to . if undefined. Find Makeconf in
- $(srcdir).
-
-Tue Apr 30 09:27:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf ($(target)): Don't depend on $(OBJS) or $(OTHERLIBS) in
- the main build rule. Add new rule specifying such a dependency
- only when doinst is one.
-
-Sun Apr 28 19:02:56 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * Makeconf (make-deps): New canned sequence. Remove gcc-lib hdrs from
- deps. Use atomic mv for output.
- (%.d: %.c, %.d: %.S): Use $(make-deps).
-
-Fri Apr 26 09:25:48 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (OBJS): Provide default definition.
- (_objs): Delete variable; replace references with $(OBJS).
-
- * Makefile (cp-linked-files): New target.
- (lndist): Add `cp-linked-files'.
-
-Thu Apr 25 03:13:51 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * Makeconf: Use -include for generated dep files.
-
-Thu Apr 11 16:18:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * INSTALL-binary: Renamed from README-binary.
-
-Thu Apr 11 16:13:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Add SETUP.
-
-Thu Apr 11 16:06:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * README: Rewritten for a new purpose.
- * INSTALL-cross: Renamed from INSTALL.
- * INSTALL: New file.
-
-Mon Mar 25 03:09:09 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * configure.in: After CC tool check, invoke AC_PROG_CC to set default
- CFLAGS and test for GCC. Barf if not GCC.
-
-Thu Mar 21 11:41:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (CFLAGS): Always turn on -g and -O3.
-
-Wed Mar 20 15:30:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (vpath %.defs): Make that $(includedir)/mach and
- $(includedir)/device.
- (CPPFLAGS): Add -D_GNU_SOURCE.
-
-Wed Mar 20 15:29:21 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * Makeconf (vpath %.defs): Use $(includedir) to locate mach files.
-
-Tue Feb 27 14:48:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (prog-subdirs): Change `newfs' to `ufs-utils'.
-
- * Makeconf ($(target): %): Add $(target-suffix) to destination name.
-
-Thu Nov 30 10:57:21 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (prog-subdirs): Added pfinet.
-
-Tue Nov 21 14:34:04 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makeconf (top_srcdirinc, srcdirinc): New variables.
- (CPPFLAGS): Use new vars $(top_srcdirinc) and $(srcdirinc) to avoid
- ugly duplication of `.' and `..' in compile lines when possible.
-
-Tue Oct 24 17:24:36 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Replace hurd.boot.in with hurd.boot
- (hurd.boot): Target removed.
- (clean-misc): Don't remove hurd.boot.
- (all): Don't depend on it.
- * hurd.boot: Renamed back from hurd.boot.in.
- Name ufs and ld.so as they will be found in an installed Hurd
- filesystem.
-
-Tue Oct 10 23:31:26 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (rpath): New variable.
- ($(target)): Use it in link command.
- ($(libname).so): Likewise.
- Use $^ instead of $+.
-
-Sat Oct 7 05:02:17 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf ($(libname).so): Pass $(LDFLAGS) and $($@-LDFLAGS).
-
-Wed Oct 4 16:21:33 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (%_pic.o: %.c): Use $(COMPILE.c) instead of its
- contents. Pass -DPIC.
- (%_pic.o: %.S): New rule.
-
-Sat Sep 23 02:45:18 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (top_srcdir): Define properly in parent directory.
-
- * Makefile (other-subdirs): Remove lib.
-
-Fri Sep 22 14:26:12 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * build.mk.in (VPATH): New variable.
-
-Thu Sep 21 19:07:44 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (hurd.boot): New target.
- (all): Depend on hurd.boot
- (DIST_FILES): Add build.mk.in and hurd.boot.in.
- (clean-misc, distclean): New targets.
- (clean): Depend on clean-misc.
-
- * hurd.boot.in: Renamed from hurd.boot; use @exec_prefix@ instead
- of hardcoded dir. Added some comments.
- * build.mk.in: New file.
- * configure.in: If not in $srcdir, produce */Makefile from
- build.mk.in.
-
-Thu Sep 21 14:28:26 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (prog-subdirs): Removed `pfinet'.
-
- * term, newterm: Renamed `term' to be `term.old'; renamed
- `newterm' to be `term', thus installing the new version.
-
-Wed Sep 20 20:10:54 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hurd.boot: Run ld.so with arg of /hurd/exec, instead of running
- exec/exec. Now exec can be dynamically linked.
-
-Tue Sep 19 13:40:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makeconf (LDFLAGS): Variable removed.
-
-Tue Sep 19 02:33:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (libthreads-libsubst): Variable removed.
-
-Sat Sep 16 14:17:08 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * configure.in: New file.
- * config.make.in: New file.
- * Maketools: File removed.
- * Makefile (DIST_FILES): Remove Maketools.
- Add config.make.in, configure.in, configure.
- * Makeconf: Include $(..)config.make for configure-generated
- parameters.
- No longer include Maketools.
- (prefix, exec_prefix, srcdir, hurddir, bindir, sbindir, libdir,
- infodir, includedir): Variables removed.
- (..): New variable.
- (srcdir, top_srcdir): Set if not already set.
- (CPPFLAGS): Append -I's for . and .. and $(srcdir) and $(top_srcdir).
- (CFLAGS): Remove -g.
- Change miscellaneous uses of $(srcdir) to $(top_srcdir).
- (vpath %.defs): Remove $(crossheaders) dirs from path.
-
-Sat Sep 16 13:26:59 1995 Miles Bader <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (sbindir): New variable.
- (installationdir): Don't set if already set.
-
-Mon Sep 11 12:06:44 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Maketools (CCVERSION): Changed to 2.7.1.
- (CCVERSION-duality.gnu.ai.mit.edu): Removed.
-
-Fri Sep 1 13:02:12 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makeconf (libsubst, libsubst-override, _libsubst): New vars.
- ($(target): %): Replace each library reference with $(_libsubst).
- (libthreads-libsubst): New variable.
- [$(makemode)==library] (targets): Default to both .a and .so libraries.
- [$(makemode)==library] (all, install): Make and install $(targets)
- instead of the explicit default list of them.
- [$(makemode)==library] (libs): New target.
- (../%.a ../%.so): Make the `libs' target instead of an explicit
- list of libraries.
-
-Mon Aug 28 17:22:24 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hurd.boot: Use ${boot-args} preset variable.
- Use $(...) for action directives.
-
-Mon Aug 28 15:52:16 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (inclusion of .d files based on OBJS): Only deal with
- .o files in $(OBJS).
-
-Mon Aug 28 09:59:04 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makeconf (TAGS): Automagically find all the files to scan from
- the dependency information.
- (DEP_SRCS): Sort in reverse order so that local files come first.
-
-Fri Aug 25 08:02:04 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makeconf ($(libname).so): Use the linker -soname option to
- specify what library name should be recorded by users.
- (__libext, __libext-static, _libext): New variables.
- ($(target): %): Link against the absolute library with the
- appropiate extension do determine whether shared or not, instead
- of using -L...-l syntax.
-
-Thu Aug 24 10:09:59 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makeconf (HURDLIBS-files, HURDLIBS-libs): Removed.
- ($(targets): %): The same rule now used for both many and one
- cases. Get the things to be linked against entirely from the
- dependency list, and munge it to convert library pathnames to
- -L...-l pairs.
- Stop using *HURDLIBS as the mechanism for passing in libraries to
- be linked against. Now you should just put the pathname in the
- dependency list of the target, along with the object files, etc.
- [$(doinst)==many] (target): Set this from $(targets).
- ($(sort $(HURDLIBS-files))): Rule deleted.
- (../%.a ../%.so): New rule, replacing the previous one.
-
-Wed Aug 23 17:55:04 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Add hurd.boot.
- * hurd.boot: New file.
-
-Tue Aug 22 17:04:19 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makeconf ($(addprefix $(installationdir)/,$(targets)),): Use
- INSTALL_PROGRAM, not INSTALL_BIN.
- * Maketools (INSTALL_BIN): Changed to INSTALL_PROGRAM.
-
- * Makeconf (HURDLIBS-libs): Re-enable the -L... version, but using
- -Wl,-L... instead to avoid gcc hosage.
- (HURDLIBS-files): Use both the target specific and general values
- of HURDLIBS.
- Get rid of the merging of all target-specific HURDLIBS into the
- general HURDLIBS, as the former are use properly now.
- [$(doinst)==one] ($(target)): Don't explicitly link with $(libc).
- [$(doinst)==many] ($(targets): %:): Depend on the .o file of the
- same name, and on all the hurd library files, and on all
- appropriate other libraries. Use $^ instead of $+ as we now get
- all the libraries from the various HURDLIBS instead of from the
- dependencies list, and this allows us to put %.o in our
- dependencies without worrying about duplicating what the user has
- done. Don't explicitly link with $(libc).
-
- * Makeconf [$(makemode)==library]: Use $(installhdrsubdir) to
- determine where headers in $(installhdrs) should be installed,
- instead of a constant `hurd'.
-
-Fri Aug 18 21:53:17 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * Makeconf [$(doinst)==many]: Depend on what's in plain OTHERLIBS
- as well as the target specific $@-OTHERLIBS.
-
-Mon Aug 7 16:29:53 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * Makefile (prog-subdirs): Remove pipes.
-
-Fri Aug 4 14:49:25 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * README-binary: Say to run /hurd/pflocal instead of /hurd/pipes.
-
-Wed Jul 26 14:30:17 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (lib-subdirs): Added libpipe.
- (prog-subdirs): Added pflocal.
- * libpipe: New directory.
-
-Sun Jul 23 15:57:50 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Removed `missing'.
- (dist): Include date in snapshot name.
-
-Sat Jul 22 14:19:36 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (%-lndist, %-clean, %-TAGS): Set no_deps in recursive
- make.
- * Makeconf: Don't include dependency files if no_deps is set.
-
-Tue Jul 18 20:09:35 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makeconf (%.d: %.c): Include the _pic.o files if we are making a
- library.
-
-Wed Jul 12 11:41:19 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (lib-subdirs): Removed `libnetserv'.
- * libnetserv: Move to old.
- * pfinet: Move to old; start new directory.
-
-Fri Jul 7 17:34:54 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf [$(doinst)==many] ($(targets) installation rule): Fix typo.
-
-Fri Jul 7 00:29:12 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (install) [doinst == one || doinst == many]: Don't
- install files if they already exist and are up to date.
-
-Thu Jul 6 14:45:30 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Maketools (OBJCOPY): New var.
-
- * Makeconf (HURDLIBS-libs): Comment out path-search rule here; I
- don't yet trust -L to work right; particularly inside linker
- parens.
-
- * Makeconf (%.d:%.c %.d:%.S): Repair sed line to include more
- context.
-
- * Makeconf (Building targets) [doinst == many]: Don't try and
- build $(special-targets).
-
- * Makeconf: Delete now-unneeeded explicit dependencies.
-
- * Makeconf (clean): Add dependency files to be removed.
-
- * cthreads.h: New link to libthreads/cthreads.h to make sure we
- get the local copy instead of the one in the include dir.
- * Makefile (lndist): Add new dependency.
- (lndist-cthreads-h): Rule to create the cthreads.h link.
-
- * Makeconf ($(target) [doinst == one]): Don't explicitly depend on
- libc. Too hairy for now.
-
- * Makeconf: Added many new rules for automatic dependency
- generation.
-
- * Makeconf (install) [makemode == library]: Install libraries and
- headers as separate targets.
-
-Wed Jul 5 17:41:33 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf: Make things work nicer for $(doinst)==many by allowing
- per-target HURDLIBS and LDFLAGS values.
-
- * Makefile (prog-subdirs): Removed `pflocal'.
-
-Thu Jun 29 15:14:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (cleantarg) [makemode == library]: Add $(libname).so.
- (`Building Hurd libraries'): Make simpler rule that doesn't need
- allibs.
- (alllibs): Delete variable.
- (all) [makemode == library]: Add $(libname).so.
- (install) [makemode == library]: Install $(libname.so) too.
- ($(libname).so) [makemode == library]: New rule to build shared
- library.
- (%_pic.o): New rule to build pic object files.
-
-Wed Jun 28 15:06:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (HURDLIBS-libs): Restore variable definition.
- ($(target)) [doinst == one]: Use HURDLIBS-libs instead of
- HURDLIBS-files.
- (HURDLIBS-files): Compute names automatically. Dike out
- per-library variables up above.
-
- * Makefile (prog-subdirs): Removed dev.trim.
-
-Thu Jun 22 11:47:05 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (libihash): New variable.
- (alllibs): Add libihash.
-
-Mon Jun 19 21:34:14 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (CFLAGS): Omit -Wno-parentheses.
-
-Tue Jun 6 13:18:14 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (lib-subdirs): Added libihash.
- * libihash: New directory.
-
-Thu May 18 03:34:31 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (LDFLAGS): Append -static.
-
-Fri May 12 18:39:21 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (prog-subdirs): Removed mkbootfs.
-
-Fri May 5 09:46:01 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makeconf: Make MIGCOMUFLAGS & <target>-MIGCOMUFLAGS actually work.
-
-Fri Apr 21 11:44:05 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Maketools (INSTALL_BIN): Reverse Miles's last change.
-
-Wed Apr 12 11:12:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (install [$(makemode) == library]): Use `$(RANLIB)',
- not `ranlib'.
-
-Tue Apr 11 10:51:22 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Add README-binary.
- * README: Small doc fix.
- * INSTALL: Many changes.
- * README-binary: New file.
-
- * Makeconf (prefix): Change to /home/gd4/hurdinst.
-
- * Makefile (all, install): Do lib-subdirs too.
-
- * Makefile (prog-subdirs): Added devio, newfs, ext2fs, benchmarks,
- pfinet, tmpfs, defpager, login, and nfs.
- (other-subdirs): Added lib.
- (lib-subdirs): Added libps, libnetserv, libdirmgt, and libnetfs.
- (subdirs-nodist): Remove libnetserv.
-
- * devio, lib, libps, ext2fs: New directories (actually created
- several weeks before this log entry).
-
-Mon Apr 10 14:38:26 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Maketools (INSTALL_BIN): Use /gd4/hurd-cross/install-stripped to
- install binaries stripped.
-
- * Makeconf (prefix, exec_prefix): Point at the currently correct place.
-
-Fri Apr 7 18:14:01 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * ext2fs: Delete directory and its contents.
- * Makefile (subdirs-nodist, other-subdirs): Delete `ext2fs'.
-
-Wed Apr 5 12:59:10 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (clean): Only clean in working-prog-subdirs.
-
- * Makeconf (hurdinst, hurdroot): Deleted vars. Replaced usages
- with $(prefix) and derivatives.
- (hurdroot-douglas.gnu.ai.mit.edu, hurdroot-ernst.gnu.ai.mit.edu,
- hostname, hurdrootdev): Deleted vars.
- (hurdsource): Replaced with `srcdir'.
- (startup, libc): Deleted vars; now in Maketools.
- (prefix, exec_prefix): New vars.
- (hurddir, bindir, libdir, infodir, includedir): New vars.
- ($(hurdroot), $(hurdroot)/mounted): Deleted rules.
- (vpath %.defs): Look in $(crossheaders), not installation dir.
- * Maketools (crossdir, startup, libc, crossheaders): New vars.
- (MIGCOM): Use $(crossdir) instead of literal string.
-
-Fri Mar 31 23:45:11 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf [makemode=library] (install): Only do $(installhdrs) if
- defined.
- * Makeconf [makemode=library] (install): Use $(INSTALL_DATA).
- * Maketools (INSTALL, INSTALL_DATA, INSTALL_BIN): Define normally
- using `install'.
-
-Mon Mar 20 14:02:08 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makeconf (libps): New variable.
- (alllibs): Add libps.
-
- * ps, libps: New directories.
-
- * Makeconf: Doc fix.
-
- * Maketools (CC): Specify `$(CCTARGET)-gcc' instead of just `gcc'.
-
-Thu Feb 16 00:43:43 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (CPPFLAGS, CFLAGS): Set with += so Makefiles can add things.
-
- * Maketools (hostname): New variable, so CCVERSION actually works.
-
-Wed Feb 15 22:40:25 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Maketools (CCVERSION-duality.gnu.ai.mit.edu): New variable.
-
-Sat Feb 11 03:59:15 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Maketools (INSTALL_BIN): Use objcopy.
-
-Wed Dec 14 07:31:46 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makeconf (libnetserv): New variable.
- (alllibs): Added `libnetserv'.
-
-Thu Nov 24 07:36:57 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Remove gcc-specs.
-
-Tue Nov 22 22:29:41 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf ($(target)): Use normal linking with -Wl,-( $+ -Wl,-).
-
-Wed Nov 16 14:52:20 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Maketools (MIG, MIGCOM): Never define using rsh; use
- /usr/local/i386-gnu/....
-
-Tue Nov 8 14:27:58 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makeconf (link-objects): Mention libgcc.a explicitly here.
- * Maketools (CCVERSION): Upgrade default to version 2.6.2.
-
-Thu Nov 3 17:17:15 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Renamed `fsck' to `bsdfsck'; renamed `newfsck' to `fsck'.
- * Makefile (prog-subdirs): Added bsdfsck.
-
-Tue Nov 1 13:15:28 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (hurdroot): Don't set if already defined.
-
-Fri Oct 14 17:43:46 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * newfsck: New directory.
-
-Fri Sep 23 15:57:45 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (working-prog-subdirs): New variable, omits dirs
- containing a file BROKEN.
- (all, install): Use that instead of $(prog-subdirs).
-
-Fri Sep 16 10:16:19 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makeconf (libc): Now that libc.a is a linker script, do the
- Right Thing here.
- ($(target)): Here too.
-
-Thu Sep 8 12:20:05 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makefile (prog-subdirs): Added `fsck'.
-
- * Makefile (DIST_FILES): Added `INSTALL'.
- * INSTALL: New file.
-
-Tue Aug 30 11:29:50 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (other-subdirs): Add libnetserv.
- (lib-subdirs): Remove libnetserv.
-
-Tue Aug 23 09:35:44 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makeconf (link-objects): Don't use -v anymore.
-
-Fri Aug 19 01:36:11 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (link-objects): Don't put $(OBJS) inside -( ... -).
-
-Tue Aug 16 14:21:46 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makeconf (link-objects): Don't use $^; it omits duplicates.
-
-Tue Aug 16 00:47:08 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (link-objects): Define with hair to use -( ... -).
-
-Mon Aug 15 21:24:42 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * gcc-specs: Updated; now expects gcc configured for
- {i386,mips}-gnu target and libc installed in
- /usr/local/{i386,mips}-gnu/{lib,include} or wherever configured.
- (cpp): Grok only -posix.
- (lib): Use -( ... -) hack.
- (startfile): Use normal defn.
- (predefines): Remove `hurd'; `gnu' is enough.
-
- * Makeconf (link-objects): New variable.
- ($(target)): Use it in place of other objects variables.
- Depend on $(libc).
-
- * Maketools (BUILD_CC): Set this instead of HOST_CC.
-
-Wed Aug 10 13:59:40 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * netinet: New directory.
-
-Wed Aug 10 13:41:54 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Maketools (LD): Find ld in $(tooldir) instead of $(ccdir).
-
-Mon Aug 8 15:37:29 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * libnetserv: New directory.
- * Makefile (lib-subdirs): Added `libnetserv'.
-
- * Makeconf (distfiles): Don't set with :=.
- * Makefile (dist): Fix typo.
-
-Fri Aug 5 15:23:49 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makeconf (machdefs, devicedefs): Deleted vars.
- (vpath %.defs): Added $(includedir)/device.
-
- * Makeconf (install) [doinst == many]: Repair shell syntax.
-
- * sh.trim, ps, su: Deleted directories.
-
-Mon Aug 1 19:41:06 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Maketools (CC): Add -pipe.
-
-Sun Jul 31 21:12:40 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Maketools (tooldir): Use /usr/local/i386-gnu/bin.
- (CCVERSION): Use 2.6.0.
- (INSTALL_BIN): Use objcopy -S.
-
-Sat Jul 23 01:35:03 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf: Removed all the hairy mig rules.
- Replaced with two pattern rules and a vpath %.defs directive.
- Rationalized use of flag variables; add dash after interface name
- in computed flag variable names.
-
- * gcc-specs (predefines): Remove -Asystem(hurd); `gnu' is enough.
-
- * Makeconf ($(target)): Pass $(LDFLAGS) like a sane person.
-
-Fri Jul 22 19:42:53 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makeconf (HURDLIBS-files): New variable.
- ($(target)): Use that instead of $($(HURDLIBS)). (mib braino.)
- (distfiles): Use $(DIST_FILES) instead of just DIST_FILES.
- (TAGS): Use a substitution reference instead of several function
- invocations.
-
-Fri Jul 22 10:18:33 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (other-subdirs): Removed `i386'.
- * i386: Deleted directory.
- * machine: Deleted symlink.
-
- * Makeconf (CFLAGS): Use += instead of :=.
- (TAGS): New var OTHERTAGS for source not in the usual places.
-
-Thu Jul 21 15:09:34 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makeconf (CPPFLAGS): Remove -I. and add -I$(hurdsource) in
- accord with reorganization.
- (libthreads,libports,libioserver,libpager,libfshelp,libdiskfs,
- libtrivfs): Changed to find libraries in local (uninstalled)
- locations.
- ($(hurdsource)/lib%/lib%.a): Define this instead of bogus rules for
- each installed library and header file separately.
- (%_S.h, %Server.c): New implicit rules for Hurd and Mach
- interfaces; associated variables.
- (makemode): New variable parent should set.
- (doinst, installationdir): New vars.
- (install, $(target), $(libname).a): New targets.
- (TAGS): Rewritten with new variable names.
-
- * Makefile (prog-subdirs): Removed sh.trim, ps, and su. Added
- utils. Removed ifsock and symlink. Added trans.
-
-Wed Jul 20 16:27:50 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Maketools (MIGHOSTCCVERSION, MIGCCTYPE, MIGHOSTCC): Deleted
- variables.
-
-Tue Jul 19 12:25:06 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (other-subdirs): Added ext2fs.
- (subdirs-nodist): New variable.
- (dist): Don't include things in subdirs-nodist.
-
- * gcc-specs (cpp): Use -idirafter instead of -I in searching for
- our substitute /usr/include.
- (lib): Don't look for libmalloc.
-
- * Maketools (CCTARGET): Changed to be i386-gnu.
- (CPP): Use $(CC) instead of calling CPP directly.
- * Makeconf (CPPFLAGS): Deleted -nostdinc and -I flags.
- (link): Deleted macro.
- (ldflags, gccheaders, libgcc): Deleted variables.
-
- * Makeconf (malloc): Deleted variable.
- (link): Deleted $(malloc) and `-u _malloc'.
-
-Tue Jul 12 15:23:43 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (other-subdirs): Moved dev here from $(prog-subdirs).
- (prog-subdirs): Added dev.trim.
-
-Tue Jul 5 14:07:02 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Snapshot published.
-
- * Makefile (prog-subdirs): Added dev, su, symlink.
- (DIST_FILES): Added tasks and ChangeLog.
-
- * Makeconf (TAGS): New target.
- * Makefile (%-TAGS): New target.
- (TAGS): New target.
-
- (other-subdirs): Moved tmpfs here from $(prog-subdirs).
-
-Mon Jun 20 15:03:14 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Maketools (INSTALL_BIN): New macro.
-
-Sat Jun 18 12:34:04 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * Maketools (MIGCOM): Fix mib's losing command to propagate umask
- through rsh to the remote migcom run.
-
-Wed May 25 12:55:35 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makeconf (libtrivfs): New variable.
- ($(libtrivfs), $(includedir/hurd/trivfs.h)): New targets.
-
-Tue May 24 16:15:30 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Maketools (MIGHOSTCC, CC): Don't use -pipe any more.
-
-Wed May 18 13:02:44 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * tasks: New file.
-
-Tue May 17 19:51:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Snapshot published.
-
- * gcc-specs: New file.
- * Makefile (DIST_FILES): Added gcc-specs.
-
-Fri May 6 13:24:42 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Maketools (MIGHOSTCCVERSION, MIGHOSTCCTYPE, MIGHOSTCC):
- New variables.
- (mighost): Fully canonicalize name.
-
-Thu May 5 19:34:57 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makeconf (malloc): Changed to point to libmalloc.a; installed
- there by libthreads/Makefile.
-
-Thu May 5 07:10:49 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makeconf (malloc): Pass -u _malloc and reference $(libthreads).
-
- * Makeconf (headers): Variable renamed to includedir; all uses changed.
- (CPPFLAGS): Add -I. before other -Is.
-
-Wed May 4 07:07:16 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Maketools (machine): Define variable.
-
-Wed Apr 27 01:54:34 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile (LIB_SUBDIRS, PROG_SUBDIRS, OTHER_SUBDIRS, SUBDIRS):
- Renamed to less annoying names, not in ALL GRATUITOUS CAPS.
- (lib-subdirs): Fixed name of libthreads.
-
+2772f5c6a6a51cf946fd95bf6ffe254273157a21 is the last commit imported from CVS.
+All commits after that one have valid author and committer information.
+
+Use this to examine the change log for earlier changes:
+
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:auth/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:benchmarks/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:boot/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:bsdfsck/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:config/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:console-client/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:console/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:daemons/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:defpager/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:doc/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:exec/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:ext2fs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:fatfs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:fstests/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:ftpfs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:hostmux/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:hurd/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:include/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:init/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:isofs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libcons/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libdirmgt/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libdiskfs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libfshelp/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libftpconn/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libhurdbugaddr/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libihash/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libiohelp/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libnetfs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libpager/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libpipe/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libports/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libps/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libshouldbeinlibc/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libstore/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libthreads/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:libtrivfs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:login/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:mach-defpager/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:nfs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:nfsd/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:pfinet/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:pflocal/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:proc/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:release/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:serverboot/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:storeio/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:sutils/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:term/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:tmpfs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:trans/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:ufs-fsck/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:ufs-utils/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:ufs/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:usermux/ChangeLog
+ $ git show 2772f5c6a6a51cf946fd95bf6ffe254273157a21:utils/ChangeLog
diff --git a/INSTALL b/INSTALL
index 1a88cf73..22692258 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,5 +1,5 @@
-*- Text -*-
-GNU Hurd 0.0
+GNU Hurd 0.2
This is the Hurd. Welcome.
@@ -19,8 +19,9 @@ want to use is already installed, and you know both it and this
version of the Hurd will interoperate together, then see the
instructions "Bulding the Hurd by itself" below.
-The Hurd version 0.0 is known to work with version 1.93 of the GNU C
-Library.
+The Hurd version 0.2 has been verified to work with versions 2.0.3 and
+2.0.4 of the GNU C library. (But note that version 2.0.3 has some
+easily-fixed bugs in compilation for the i386-gnu target.)
Bug reports for the GNU Hurd should be sent to the mailing list
`bug-hurd@prep.ai.mit.edu'. Please do not send requests for
@@ -30,9 +31,6 @@ Instead, send requests for assistance to the mailing list
request to `bug-hurd-request@prep.ai.mit.edu' or
`help-hurd-request@prep.ai.mit.edu' respectively.
-If any of these address should fail, send your message to
-`tower@gnu.ai.mit.edu' and ask him to forward it properly.
-
Configuring the Hurd
====================
@@ -58,18 +56,21 @@ called `autoconf'. You only need `configure.in' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
-Building the Hurd, Mach4, and libc together
+Building the Hurd, GNUmach, and libc together
===========================================
-1. Configure mach4.
+1. Configure GNUmach.
3. Do `make install' in <mach4-build>/mig. ONLY.
4. Do `make install' in <mach4-build>/include. ONLY.
+ This may have installed an include file called mach_init.h. If so,
+ delete it; you want to use the one that libc will install, and if
+ this file exists, libc might not install its version.
5. Configure the Hurd with `configure'.
-6. In the Hurd directory, type `make install-hdrs'.
+6. In the Hurd directory, type `make install-headers no_deps=t'.
7. Configure libc.
@@ -88,7 +89,7 @@ Building the Hurd and libc together
1. `cd' to the directory containing the Hurd's source code and type
`./configure' to configure the Hurd.
-2. Type `make install-hdrs' to install the Hurd's header files.
+2. Type `make install-headers no_deps=t' to install the Hurd's header files.
3. Follow the instructions in the GNU C Library for configuring and
installing GNU libc.
diff --git a/INSTALL-cross b/INSTALL-cross
index 16ace324..f91d1195 100644
--- a/INSTALL-cross
+++ b/INSTALL-cross
@@ -1,36 +1,137 @@
- === Hey, Emacs! This is -*- Text -*- !!! ===
-Last update 11 Apr 1996 by Michael I. Bushnell, p/BSG (mib@gnu.ai.mit.edu).
+Cross-compiling the GNU Hurd -*- Outline -*-
+* READ HERE!
+The procedure described below -- albeit not completely obsolete, of course --
+is outdated a bit. If you attempt to build a cross compiler, have a look at
+<http://www.bddebian.com/~wiki/hurd/building/cross-compiling/> for now.
+
+Last update 1998-06-01 Gordon Matzigkeit <gord@gnu.org>.
+Previous update 1996-04-11 Thomas Bushnell, n/BSG <thomas@gnu.org>.
+
+* Introduction
These are instructions for building the Hurd as in cross-development
environment. Unless you are building the Hurd on an already running
Hurd system, you will need these directions to build the Hurd from any
other kind of system. Even if you are using a Mach system (Lites,
say) you will *STILL* need to follow these directions; this is still
-cross-compilation.
-
-
-
-I:
-
-First you must have GCC and binutils installed. We use GCC 2.7.2 and
-recent Cygnus binutils snapshots. You need to configure binutils and
-GCC for the i486-gnu target. In order to build the GNU C library for
-the Hurd, you will need gawk installed. You should install GCC and
-binutils as the instructions for these programs indicate. The Hurd
-makefiles depend on having them installed correctly as
-cross-development tools. Even if you are building the Hurd on a 486,
-even if it's running a different Mach-based OS, you are still cross
-compiling. Don't attempt to use tools that have been configured for
-something other than i486-gnu.
-
-Install things in /usr/local, as the Makefiles do by default. If you
-change $(prefix) when installing the cross-development tools, then
-random problems might happen. I cannot stress to highly that you are
-much better off doing things in the ordinary default way.
-
+cross-compilation.
-II:
+IMPORTANT: If you are not prepared to fix bugs without begging other
+people for help, or you lack patience, then this process is *not for
+you*! Go get a binary distribution... downloading 80MB of files over
+a 9600 baud PPP connection takes far less time and effort than
+cross-compiling, especially when you consider that the size of the
+source code for all the packages in the Hurd binary distribution is
+larger than the distribution itself.
+
+You will need *at least* 500 MB of free disk space for the build
+process. More is always better.
+
+NOTE: On the other hand, do not be sloppy with any of these
+instructions, until you have tried following them exactly, and they
+didn't work for you the first time. There are all sorts of pitfalls
+and untested paths, so it is better not to be creative with things
+(like trying to install the cross-compiler somewhere other than
+/usr/local). Expect random problems if you deviate from these
+instructions. You have been warned.
+
+In other words, follow these instructions closely, but not blindly.
+
+You may wish to create build logs, so that you can trace any problems
+after you let a compilation run unattended. To do this, background
+and redirect all make output to a file (i.e. `nohup make -k >&
+make.out &'). If you wish to monitor the build, you can use a command
+like `tail -f make.out'. After the build completes, simply search the
+log for `***' (i.e. `grep '\*\*\*' make.out'), and you'll find any
+errors.
+
+* Cross-compiler tools
+
+First you must install a cross-GCC and binutils. Currently, GCC 2.8.1
+and binutils version 2.9.1 are the minimum suggested versions.
+
+Even if you are building the Hurd on a 586, even if it's running a
+different Mach-based OS, you are still cross-compiling. Don't attempt
+to use tools that have been configured for something other than
+i586-gnu (unless, of course, you are trying to port the Hurd to a
+different processor).
+
+** Binutils
+
+The cross-binutils installation is quite straightforward. Just
+configure, build and install them with commands like:
+
+$ [cd to top of binutils source tree]
+$ mkdir obj
+$ cd obj
+$ ../configure --prefix=/usr/local --target=i586-gnu
+[...]
+$ make
+[...]
+$ su
+Password:
+# make install
+[...]
+#
+
+The above instructions show you how to create a new build
+subdirectory, `obj', and then configure and build the package there.
+You should get used to this process, because some of the Hurd packages
+will not build properly in any other way.
+
+This installation should be smooth. If you see any strange errors
+during the build process, you should investigate them, since they are
+probably bugs.
+
+** GCC (attempt #1)
+
+Bootstrapping a GCC cross-compiler is only slightly more difficult
+than installing a cross-binutils. GCC has a few interdependencies
+with the Hurd libc, such as the creation of the `libgcc2.a' library.
+
+Therefore, the first time you try compiling and installing GCC, you
+will need to kludge things so that you can get a mostly-working
+compiler, then come back and redo them to get a fully-working
+compiler.
+
+There is a bug when creating a cross-compiler on certain platforms.
+In order to avoid this bug, you should copy a working `float.h' header
+file from a known working GCC installation for the same processor. On
+a GNU/Linux machine using gcc-2.7.2.1, `float.h' can be found in
+`/usr/lib/gcc-lib/i386-linux/2.7.2.1/include/float.h'. In general,
+you can find it in
+`$(prefix)/lib/gcc-lib/$(host)/$(VERSION)/include/float.h'. You will
+need to copy this file into the `include' subdirectory of the unpacked
+GCC distribution, overwriting the old `include/float.h' if it exists.
+
+The build process should look something like the following. Be sure
+to use the `-k' and `LANGUAGES=c' make arguments this time around, or
+else the build will fail in random places:
+
+$ [cd to top of gcc source tree]
+$ cp /usr/lib/gcc-lib/i386-linux/2.7.2.1/include/float.h include/float.h
+$ mkdir obj
+$ cd obj
+$ ../configure --prefix=/usr/local --target=i586-gnu --with-gnu-as --with-gnu-ld
+[...]
+$ make -k CFLAGS="-g -O2" LANGUAGES=c
+[... fails while trying to build libgcc2.a]
+$ su
+Password:
+# make -k install LANGUAGES=c
+[again, fails on libgcc2.a]
+#
+
+If the build fails anywhere except on libgcc2, you have a problem.
+Investigate it. Otherwise, you should now have a mostly-working
+cross-compiler suite in /usr/local.
+
+NOTE: Do not delete the GCC compile tree. You will need it later in
+order to finish the installation. If you choose to delete it, you
+will have to repeat this step in its entirety.
+
+* Set up the Hurd root
You need space to "install" the compiled Hurd, its libraries, include
files, and binaries that will run on the Hurd. In these instructions,
@@ -40,72 +141,188 @@ are finished.
This space needs to be accessible to the machine doing the
cross-compilation, because the libc and include files that go in the
-Hurd's root filesystem are also the ones that are needed during
+Hurd's root filesystem are the same ones that are needed during
cross-compilation.
We strongly advise that this directory not be put in /usr/local. This
-will tend to cause confusion.
-
-If you followed the directions in (I) above, then in
-/usr/local/i486-gnu you already have a number of cross-development
-tools. (ar, ranlib, ld, as and so forth.) This is the place where
-the compiler looks for cross-development stuff. So now make two
-symlinks, named /usr/local/i486-gnu/include and
-/usr/local/i486-gnu/lib, and point them at foo/include and foo/lib,
-where `foo' is the name of you Hurd installation staging area. If you
-don't do this, you will lose. Do it now.
-
-
-III:
+will tend to cause confusion. It would be a good idea to create a new
+filesystem, and mount it on your cross-compilation machine as /hurd.
+
+If you followed the directions above, then in /usr/local/i586-gnu you
+already have a number of cross-development tools (ar, ranlib, ld, as
+and so forth). This is the place where the compiler looks for
+cross-development stuff. So now make two symlinks, named
+/usr/local/i586-gnu/include and /usr/local/i586-gnu/lib, and point
+them at /hurd/include and /hurd/lib, where `/hurd' is the name of your
+Hurd installation staging area.
+
+If /usr/local/i586-gnu/include or /usr/local/i586-gnu/lib already
+exists, you should move their contents to your Hurd installation
+staging area before creating the symlinks.
+
+If you don't do these steps, you will lose. Do them now.
+
+* Install Mach
+
+Get the latest gnumach distribution, and configure it to cross
+compile. You should read the README in order to determine which
+device driver options you should use. You should also specify your
+current build platform... in the following example, we are
+cross-compiling from an i586-linux-gnu machine:
+
+$ [cd to top of gnumach source tree]
+$ mkdir obj
+$ cd obj
+$ CC=i586-gnu-gcc ../configure --build=i586-linux-gnu --host=i586-gnu \
+ --enable-com --enable-floppy --enable-ide --enable-aha152x
+[...]
+$ make
+[...]
+$ su
+Password:
+# make install prefix=/hurd
+[...]
+#
+
+Besides building the Mach kernel, this step installs several Mach
+headers and interface files into the staging area. These files are
+required for cross-compilation.
+
+* Install a cross-MiG
+
+This process can be confusing, because there are so many different
+varieties of cross-compilers:
+
+1) When you were building Mach, above, the build process needed a MiG
+which can could run on the build machine, but create code for GNU.
+This is called `local-mig' in the Mach Makefiles.
+
+2) Then, when you installed Mach, you also installed a MiG which can
+run on GNU and create code for GNU. This is called `cross-mig' in the
+Makefiles.
+
+3) Now, you need to install a version of MiG like #1, so that you can
+use it to build the C library and the Hurd. Unfortunately, the shell
+script wrapper used in #1 is not appropriate for installation, so you
+need to generate Yet-Another-MiG:
+
+# make install-local-mig prefix=/usr/local
+[...]
+#
+
+Be sure to set the `prefix' variable as indicated, or you will
+accidentally clobber the MiG you installed in the previous step.
+
+* Build the GNU C library
+
+In order to build the GNU C library for the Hurd, you will need recent
+versions of several tools, including gawk. See the glibc INSTALL file
+for more details.
+
+** Install Hurd headers
+
+The Hurd interface definitions and include files need to be visible to
+the cross-compiler so that the C library can use them.
+
+$ [cd to top of hurd source tree]
+$ mkdir obj
+$ cd obj
+$ ../configure --build=i586-linux-gnu --host=i586-gnu \
+ --prefix=/hurd --disable-profile
+[...]
+$ su
+Password:
+# make install-headers no_deps=t
+[...]
+#
+
+This step may spout a few warning messages, but you don't need to
+worry about them, because you aren't interested in compiling any of
+the Hurd (yet).
+
+
+** Build and install C library
+
+Configure, compile, and install the core GNU C library (note that we
+reset the `install_root' variable instead of `prefix'):
+
+$ [cd to top of glibc source tree]
+$ mkdir obj
+$ cd obj
+$ ../configure --build=i586-linux-gnu --host=i586-gnu \
+ --prefix= --enable-add-ons=crypt --disable-profile
+[...]
+$ make -k
+[... fails when trying to link programs]
+$ su
+Password:
+# make -k install install_root=/hurd
+[... again, fails]
+#
+
+This process fails because the cross-GCC you installed is missing
+libgcc2.a, which is required to link working programs. Do not delete
+the libc source files... you will need them again very soon.
+
+** Finish GCC install
+
+If you were silly, and deleted the GCC source tree, you need to go
+back to the first GCC build step and follow those instructions again
+(which should successfully build and install the entire C
+cross-compiler).
+
+Otherwise, there are now enough headers to finish installing the GCC
+cross-compiler, so do it:
+
+$ [cd to top of gcc source tree]
+$ cd obj
+$ make -k
+[...]
+$ su
+Password:
+# make -k install
+[...]
+#
-You should get MiG from the Utah mach4 distribution, and build it to
-cross compile. Set MIG appropriately in Maketools (usually to
-"i486-gnu-mig"). Install it as /usr/local/i486-gnu/bin/mig, install
-migcom as /usr/local/i486-gnu/lib/migcom. (Note that the last
-pathname, because of the symlink you made in step II, is actually
-somewhere in the Hurd installation staging area directory. This is
-strictly wrong, because the running Hurd won't be able to use that
-migcom. Don't worry, just remember when you boot the Hurd that this
-one program won't work quite right. We intend to fix this later.)
+This time there should be no failures.
+** Finish libc install
-IV:
+Now there is a fully-working GCC, so the libc programs can be built.
+Continue the build process:
-MAKE VERY SURE that gcc, for all Hurd work, does not use a gcc include
-directory with fixincludes processed files. Your special GCC include
-directory should have *only* GCC include files. GCC should do this by
-default, but you might want to check in
-/usr/local/lib/gcc-lib/i486-gnu/CCVERSION/include to make sure.
+$ [cd to top of glibc source tree]
+$ cd obj
+$ make -k
+[...]
+$ su
+Password:
+# make -k install install_root=/hurd
+[...]
+#
+There should be no errors or warnings from this step.
-V:
-Now, make the GNU C library. Please read its own installation
-instructions, but here is a brief summary.
+* Install the Hurd
-Configure the GNU library with a command like:
+Since you already configured the Hurd in a previous step, you can now
+build and install it:
-configure i486-gnu --with-mach=FOO --with-hurd=BAR --prefix=BAZ
+$ [cd to top of hurd source tree]
+$ cd obj
+$ make -k
+[...]
+$ su
+Password:
+# make -k install prefix=/hurd
+[...]
+#
-FOO should be the top level source directory of your Mach source.
-BAR should be the top level Hurd source directory.
-BAZ should be the installation staging area you have chosen.
-
-Build and install the library with `make install'.
-
-
-VI:
-
-Configure the Hurd with a command like:
-
-"CC=gcc -b i486-gnu" configure i486-gnu --prefix=BAZ
-
-BAZ is, again, the name of your installation staging area.
-
-Build and install the Hurd with `make install'.
-
-
-VII:
+This step should complete with no problems.
+
+
+* Final details
Now in your Hurd staging area are the complete binaries for the Hurd
and its programs, and the C library and its associated programs. You
@@ -114,6 +331,5 @@ have no shell yet. In general, you can build most GNU packages
without too much hassle using your cross compilers. In this way you
can build up as much of a binary distribution as you like.
-See the file `INSTALL-binary' for instructions on running your new
-binaries.
-
+See the file `INSTALL-binary' for instructions on bootstrapping and
+running your new binaries.
diff --git a/Makeconf b/Makeconf
index 036de787..b6134ef4 100644
--- a/Makeconf
+++ b/Makeconf
@@ -12,20 +12,25 @@
# SRCS (all actual source code)
# LCLHDRS (all source headers in this directory [NOT MiG created])
# OBJS (all .o files used to produce some target).
+# HURDLIBS (all Hurd libraries used; with no directory name or `lib' attached)
+# For types `server' and `utility' an automatic dependency will be
+# written for these, and type `library' will include a .so dependency.
+# Types `servers' and `utilities'; you have to do it yourself.
# Types `server' and `utility' should define
-# OTHERLIBS (all other libraries used)
-# target (the name of the program built)
+# target (the name of the program built)
+# OTHERLIBS (all libraries used)
# Types `servers' and `utilities' should define
-# targets (the names of all the programs built)
-# special-targets (targets which should not be built the normal way
-# and have their own rules)
+# targets (the names of all the programs built)
+# special-targets (targets which should not be built the normal way
+# and have their own rules)
# Type `library' should define
-# libname (the name of the library, without .a.)
-# installhdrs (header files that should be installed in /include)
-# installhdrsubdir (the subdirectory they should go in, default `hurd')
+# libname (the name of the library, without .a.)
+# installhdrs (header files that should be installed in /include)
+# installhdrsubdir (the subdirectory they should go in, default `hurd')
+# and must not define $(targets).
# Put this first so it's the default
all:
@@ -47,9 +52,37 @@ top_srcdir = ..
endif
endif
+# Generic compiler options, appended to whatever the particular makefile set.
+# The config.make file will append the values chosed by configure.
+INCLUDES = -I. $(srcdirinc)
+ifneq (.,$(dir))
+INCLUDES += -I.. $(top_srcdirinc)
+endif
+INCLUDES += -I$(..)include -I$(top_srcdir)/include
+CPPFLAGS += $(INCLUDES) \
+ -D_GNU_SOURCE -D_IO_MTSAFE_IO -D_FILE_OFFSET_BITS=64 \
+ $($*-CPPFLAGS)
+CFLAGS += -std=gnu99 $(gnu89-inline-CFLAGS) -Wall -g -O3 \
+ $($*-CFLAGS)
+
# Include the configure-generated file of parameters.
# This sets up variables for build tools and installation directories.
+ifneq (,$(wildcard $(..)config.make))
include $(..)config.make
+# Set a flag for the makefiles to indicated config.make was included.
+configured = yes
+endif
+
+# If we're not configured, don't do deps; then `make TAGS' and such can work.
+ifndef configured
+no_deps = t
+endif
+
+# Test build options set by configure.
+ifeq (no,$(build-profiled))
+no_prof = t
+endif
+
# Flags for compilation.
# It is important to have this inclusion first; that picks up our
@@ -65,116 +98,187 @@ top_srcdirinc=
else
top_srcdirinc=-I$(top_srcdir)
endif
-CPPFLAGS += -I. $(srcdirinc) -I.. $(top_srcdirinc) -I$(top_srcdir)/include -D_GNU_SOURCE
-CFLAGS += -Wall -g -O3
+# More useful version of HURDLIBS
+library_deps=$(foreach lib,$(HURDLIBS),$(..)lib$(lib)/lib$(lib).so)
# Local programs:
MKINSTALLDIRS = $(top_srcdir)/mkinstalldirs
-# Decode makemode:
-
+# Decode makemode.
+# After this section, $(targets) and $(progtarg) will be defined,
+# and everything else should use only those and not $(target).
+# targets will have all the (one or more) targets that should be installed;
+# progtarg will have all the (one or more) programs that should be linked;
+# linktarg will have the complete set of linked targets, including both
+# .static versions of $(progtarg) and/or shared library object targets.
ifeq ($(makemode),server)
doinst := one
- installationdir := $(hurddir)
+ makemode-instdir := hurd
clean := yes
- cleantarg := $(target)
+ targets = $(target)
+ progtarg = $(targets)
endif
ifeq ($(makemode),utility)
doinst := one
- ifndef installationdir
- installationdir := $(bindir)
- endif
+ makemode-instdir := bin
clean := yes
- cleantarg := $(target)
+ targets = $(target)
endif
ifeq ($(makemode),servers)
doinst := many
- installationdir := $(hurddir)
+ makemode-instdir := hurd
clean := yes
- cleantarg := $(targets)
+ progtarg := $(targets)
endif
ifeq ($(makemode),utilities)
doinst := many
- ifndef installationdir
- installationdir := $(bindir)
- endif
+ makemode-instdir := bin
clean := yes
- cleantarg := $(targets)
+ progtarg := $(targets)
endif
ifeq ($(makemode),library)
+
+ linktarg := $(libname).so.$(hurd-version)
+
clean := yes
- cleantarg := $(libname).a $(libname).so
+ cleantarg := $(linktarg) $(addprefix $(libname),.a _p.a _pic.a \
+ .so .so.$(hurd-version))
+
+ targets := $(libname).a $(libname).so
+ ifneq ($(no_pic),t)
+ targets += $(libname)_pic.a
+ endif
+ ifneq ($(no_prof),t)
+ targets += $(libname)_p.a
+ endif
+
ifndef installhdrsubdir
installhdrsubdir = hurd
endif
- ifndef targets
- targets = $(libname).a $(libname).so
+
+else
+
+ ifeq ($(makemode),misc)
+ ifndef doinst
+ doinst := many
+ endif
+ ifeq ($(doinst),one)
+ targets = $(target)
+ endif
+ ifeq (,$(installationdir))
+ ifneq (,$(targets))
+ ?Error subdir Makefile must define installationdir
+ else
+ makemode-instdir := NOINSTALL
+ endif
+ endif
+ else # server/utility modes
+ progtarg := $(filter-out $(special-targets),$(targets))
+ linktarg := $(progtarg) $(progtarg:=.static)
endif
+
endif
-
+ifndef installationdir
+installationdir := $($(makemode-instdir)dir)
+endif
+ifeq ($(cleantarg),)
+ cleantarg := $(linktarg)
+endif
+
+
+# This is a hack to give all hurd utilities a default bug-reporting
+# address (defined in libhurdbugaddr/bugaddr.c).
+BUGADDR = $(..)libhurdbugaddr/libhurdbugaddr.a
+BUGADDR_REF = -uargp_program_bug_address
+
# Standard targets
-.PHONY: all install libs relink clean
+.PHONY: all install libs relink clean objs
-# Installation
-ifeq ($(doinst),one)
-all: $(target)
-install: $(installationdir)/$(target) $(installationdir)
-$(installationdir)/$(target): $(target)
- $(INSTALL_PROGRAM) $(INSTALL-$<-ops) $< $@
+# Just build all the object files.
+objs: $(OBJS)
+ifneq ($(no_prof),t)
+objs: $(OBJS:%.o=%_p.o)
endif
+ifeq ($(makemode),library)
+ifneq ($(no_pic),t)
+objs: $(OBJS:%.o=%_pic.o)
+endif
+endif
+
+# Installation
+ifneq ($(makemode),library)
-ifeq ($(doinst),many)
-all: $(targets)
-install: $(addprefix $(installationdir)/,$(targets)) $(installationdir)
-$(addprefix $(installationdir)/,$(targets)): $(installationdir)/%: %
+# not library
+installable := $(sort $(linktarg) $(targets))
+install-targets := $(targets) $(filter $(build-static:=.static),$(linktarg))
+all: $(install-targets)
+install: $(installationdir) $(addprefix $(installationdir)/,$(install-targets))
+$(addprefix $(installationdir)/,$(installable)): $(installationdir)/%: %
$(INSTALL_PROGRAM) $(INSTALL-$<-ops) $< $@
-endif
+else
+
+# library (several parts, library itself, headers, etc.)
-ifeq ($(makemode),library)
all: libs
install libs: add-to-librecord
add-to-librecord: $(targets)
-install: $(addprefix $(libdir)/,$(targets)) $(addprefix $(includedir)/$(installhdrsubdir)/,$(installhdrs)) $(libdir) $(includedir) $(includedir)/$(installhdrsubdir)
+install: $(libdir) $(includedir)/$(installhdrsubdir) $(libdir)/$(libname).so.$(hurd-version) $(addprefix $(libdir)/,$(targets)) $(addprefix $(includedir)/$(installhdrsubdir)/,$(installhdrs))
-install-headers: $(includedir)/$(installhdrsubdir) $(addprefix $(includedir)/$(installhdrsubdir)/,$(installhdrs)) $(includedir)
+install-headers: $(includedir)/$(installhdrsubdir) $(addprefix $(includedir)/$(installhdrsubdir)/,$(installhdrs))
-$(includedir)/$(installhdrsubdir):
- $(MKINSTALLDIRS) $@
+$(includedir)/$(installhdrsubdir): $(includedir)
+ @$(MKINSTALLDIRS) $@
# Arrange to have the headers installed locally anytime we build the library.
# Not quite perfect, but at least it does end up getting done; and once done
# it never needs to be repeated for a particular header.
-ifeq ($(installhdrsubdir),.)
-INSTALLED_LOCAL_HEADERS=$(addprefix $(top_srcdir)/include/,$(installhdrs))
-$(INSTALLED_LOCAL_HEADERS): $(top_srcdir)/include/%:
- ln -s ../$(dir)/$* $@
-else
-INSTALLED_LOCAL_HEADERS=$(addprefix $(top_srcdir)/$(installhdrsubdir)/,$(installhdrs))
-$(INSTALLED_LOCAL_HEADERS): $(top_srcdir)/$(installhdrsubdir)/%:
- ln -s ../$(dir)/$* $@
-endif
+local-installhdrsubdir = include/$(installhdrsubdir)
+INSTALLED_LOCAL_HEADERS := $(installhdrs:%=../$(local-installhdrsubdir)/%)
+$(INSTALLED_LOCAL_HEADERS): ../$(local-installhdrsubdir)/%: ../config.make
+ @rm -f $@
+ @test -d $(@D)/ || $(MKINSTALLDIRS) $(@D)
+ echo '#include "../$(dir)/$*"' > $@
libs: $(INSTALLED_LOCAL_HEADERS)
+# Make sure we make those before compiling, since -MG will be unhelpful.
+$(patsubst %.o,%.d,$(filter %.o,$(OBJS))): $(INSTALLED_LOCAL_HEADERS)
-$(libdir)/$(libname).a: $(libname).a
- $(INSTALL_DATA) $(libname).a $(libdir)/$(libname).a
- $(RANLIB) $(libdir)/$(libname).a
-$(libdir)/$(libname).so: $(libname).so
- $(INSTALL_DATA) $(libname).so $(libdir)/$(libname).so
+# The installed local headers referring to our own files will use
+# relative names with ../$(dir) and make won't notice that's us.
+../$(dir)/%: % ;
+
+$(addprefix $(libdir)/$(libname),_p.a .a _pic.a): $(libdir)/%: %
+ $(INSTALL_DATA) $< $@
+ $(RANLIB) $@
+
+$(libdir)/$(libname).so.$(hurd-version): $(libname).so.$(hurd-version)
+ $(INSTALL_DATA) $< $@
+
+$(libdir)/$(libname).so: $(libdir)/$(libname).so.$(hurd-version)
+ ln -f -s $(<F) $@
$(addprefix $(includedir)/$(installhdrsubdir)/,$(installhdrs)): $(includedir)/$(installhdrsubdir)/%: %
$(INSTALL_DATA) $< $@
+# Arrange to have the shared libraries available locally in one single
+# directory. This is not used by the build system itself, but is just for easy
+# testing.
+local-libdir = lib
+../$(local-libdir)/$(libname).so.$(hurd-version): $(libname).so.$(hurd-version)
+ @test -d $(@D)/ || $(MKINSTALLDIRS) $(@D)
+ ln -sf ../$(dir)/$< $@
+libs: ../$(local-libdir)/$(libname).so.$(hurd-version)
+
endif
# Provide default.
@@ -183,26 +287,20 @@ install-headers:
# Making installation directories
$(installationdirlist): %:
- $(MKINSTALLDIRS) $@
+ @$(MKINSTALLDIRS) $@
# Building the target
-ifeq ($(OBJS),)
-OBJS=%.o
-endif
-
-ifeq ($(doinst),many)
- target = $(filter-out $(special-targets),$(targets))
-endif
+ifneq ($(makemode),misc)
ifeq ($(doinst),one)
-$(target): $(OBJS) $(OTHERLIBS)
+$(linktarg): $(OBJS) $(OTHERLIBS) $(library_deps)
endif
# Determine which sort of library we should link against from whether -static
# is used in LDFLAGS.
__libext=.so
__libext-static=.a
-_libext=$(__libext$(findstring -static,$(LDFLAGS) $($@-LDFLAGS)))
+_libext=$(__libext$(findstring -static,$(LDFLAGS) $($*-LDFLAGS)))
libsubst=$(basename ${lib})$(_libext)
libsubst-override=${$(notdir $(basename ${lib}))-libsubst}
@@ -212,25 +310,85 @@ _libsubst=${libsubst$(patsubst %,-override,${libsubst-override})}
# dependencies of other shared objects it encounters.
rpath := -Wl,-rpath-link=.:$(subst $. ,:,$(dir $(wildcard ../lib*/lib*.so)))
-$(target): %$(target-suffix):
- $(CC) $(rpath) $(CFLAGS) $($@-CFLAGS) $(LDFLAGS) $($@-LDFLAGS) -o $@ \
- '-Wl,-(' $(filter %.o,$^) \
- $(foreach lib,$(filter-out %.o,$+),${_libsubst}) \
+# Main rule to link executables
+#
+# (prof-depend is a special kind of run not normally used; see the rules
+# below for %.prof_d which uses it.)
+ifeq ($(prof-depend),)
+
+define link-executable
+$(CC) $(rpath) $(CFLAGS) $($*-CFLAGS) $(LDFLAGS) $($*-LDFLAGS) \
+ $(BUGADDR_REF) \
+ -o $@
+endef
+$(progtarg): %$(target-suffix): $(BUGADDR)
+ $(link-executable) \
+ $(filter %.o,$^) \
+ '-Wl,-(' $(foreach lib,$(filter-out %.o,$^),${_libsubst}) \
+ $($*-LDLIBS) $(LDLIBS) \
'-Wl,-)'
+$(addsuffix .static,$(progtarg)): %$(target-suffix).static: $(BUGADDR)
+ $(link-executable) -static \
+ '-Wl,-(' $(patsubst %.so,%.a,$^) $($*-LDLIBS) $(LDLIBS) \
+ '-Wl,-)' \
+ $(and $(filter %/libstore_part.a,$^), $(PARTED_LIBS))
+endif
+
+# Just like above, but tell how to make .prof versions of programs.
+$(addsuffix .prof,$(progtarg)): %$(target-suffix).prof: $(BUGADDR)
+ $(CC) -pg $(CFLAGS) $($*-CFLAGS) $(LDFLAGS) $($*-LDFLAGS) \
+ $(BUGADDR_REF) -static \
+ -o $@ \
+ '-Wl,-(' $^ $($*-LDLIBS) $(LDLIBS) \
+ '-Wl,-)'
+
ifeq ($(makemode),library)
$(libname).a: $(OBJS)
rm -f $(libname).a
$(AR) r $@ $^
$(RANLIB) $@
-$(libname).so: $(patsubst %.o,%_pic.o,$(OBJS))
- $(CC) -shared -Wl,-soname=$(libname).so -o $(libname).so \
- $(rpath) $(CFLAGS) $(LDFLAGS) $($@-LDFLAGS) $^
+$(libname)_p.a: $(patsubst %.o,%_p.o,$(OBJS))
+ rm -f $(libname)_p.a
+ $(AR) r $@ $^
+ $(RANLIB) $@
+
+$(libname)_pic.a: $(patsubst %.o,%_pic.o,$(OBJS))
+ rm -f $(libname)_pic.a
+ $(AR) r $@ $^
+ $(RANLIB) $@
+
+# The shared object needs to be findable in the build directory as
+# libfoo.so.VERSION (i.e. its soname) so that ld finds it when looking
+# for dependencies of other shared libraries.
+# But we also need the libfoo.so name that -lfoo looks for, so
+# we make that a symlink.
+$(libname).so.$(hurd-version): $(patsubst %.o,%_pic.o,$(OBJS)) $(library_deps)
+ $(CC) -shared -Wl,-soname=$@ -o $@ \
+ $(rpath) $(CFLAGS) $(LDFLAGS) $($(libname).so-LDFLAGS) \
+ '-Wl,-(' $(filter-out %.map,$^) \
+ $($(libname).so-LDLIBS) $(LDLIBS) \
+ '-Wl,-)' $(filter %.map,$^)
+
+$(libname).so: $(libname).so.$(hurd-version)
+ ln -f -s $< $@
endif
+# Providing directory dependencies
+ifneq ($(makemode),library)
+hurd-bug-addr-dir-dep = libhurdbugaddr
+endif
+
+endif # makemode != misc
+
+directory-depend: $(..)$(dir).d
+$(..)$(dir).d: $(srcdir)/Makefile
+ rm -f $@
+ echo $(dir): $(hurd-bug-addr-dir-dep) $(addprefix lib,$(HURDLIBS)) > $@
+
# Making a snapshot
-distfiles = Makefile ChangeLog $(SRCS) $(LCLHDRS) $(DIST_FILES)
+distfiles = Makefile $(SRCS) $(LCLHDRS) $(DIST_FILES)
lndist: $(distfiles) $(top_srcdir)/hurd-snap/$(dir) FORCE
ln $(addprefix $(srcdir)/,$(distfiles)) $(top_srcdir)/hurd-snap/$(dir)
@@ -243,21 +401,40 @@ endif
# TAGS files
ifneq ($(dir),.)
+ifdef configured
+ifneq ($(OBJS:.o=.d),)
DEP_SRCS = sed -e 's/^.*://' -e 's/ \\$$//' | tr ' ' '\012'| \
- sed -n -e 's@^$(srcdir)@&@p' -e 's@^[^/]@&@p' | sort -ur
-TAGS: $(OBJS:.o=.d) $(OTHERTAGS)
+ sed -n -e 's@^$(srcdir)@&@p' -e 's@^[^/]@&@p' | sort -ur
+TAGSFILES=$(OBJS:.o=.d) $(OTHERTAGS)
+else
+TAGSFILES=$(OTHERTAGS)
+endif
+else
+TAGSFILES=$(SRCS) $(OTHERTAGS)
+endif
+
+TAGS: $(TAGSFILES)
+ifeq ($(strip ($(TAGSFILES))),)
+# no tags, but parent will include this file, so make empty one.
+ > $@
+else
+ifdef DEP_SRCS
cat $(OBJS:.o=.d) | $(DEP_SRCS) | etags -o $@ - $(OTHERTAGS)
+else
+ etags -o $@ $^
+endif
+endif
endif
# Cleaning
ifeq ($(clean),yes)
clean:
- rm -f *.d *.*_d *.o *Server.c *User.c *_S.h *_U.h $(cleantarg)
-ifneq ($(makemode),library)
+ rm -f *.d *.o *Server.c *User.c *_S.h *_U.h *.[su]defsi \
+ $(cleantarg)
relink:
- rm -f $(cleantarg)
-endif
+ rm -f $(linktarg)
endif
+
clean:
relink:
@@ -268,7 +445,7 @@ relink:
# We record which libraries have been built in this run in the file
# $(librecord). That file contains a series of lines like
# `../libfoo/libfoo.a ../libfoo/libfoo.so: ; /bin/true'
-# that serve to inhibit the pattern rule which follows from doing anything.
+# that serve to inhibit the pattern rule which follows from doing anything.
# Above, when we make `libs' in library directories, we always append
# to $(librecord), so that future make invocations don't bother repeating
# the effort.
@@ -291,24 +468,39 @@ relink:
# Building libraries from other directories. We force both libraries to be
# built if either is, because it will use the appropriate one even if the other
-# is specified in someone's dependency list.
-../%.a ../%.so: FORCE
- $(MAKE) -C $(dir $@) libs
+# is specified in someone's dependency list.
+#../%.a ../%.so: FORCE
+# $(MAKE) -C $(dir $@) libs
# Tell make where to find other -l libraries that we use
vpath libutil.% $(libdir)/
+# The libstore_%.a files fetch symbols from libstore.so
+ifneq ($(dir),libstore)
+$(boot-store-types:%=../libstore/libstore_%.a): ../libstore/libstore.so
+endif
-# Default rule to build PIC object files.
+# Default rules to build PIC object files.
%_pic.o: %.c
$(COMPILE.c) $< -DPIC -fPIC -o $@
%_pic.o: %.S
$(COMPILE.S) $< -DPIC -o $@
+
+# Default rules to build profiled object files.
+%_p.o: %.c
+ $(COMPILE.c) $< -DPROF -pg -o $@
+
+%_p.o: %.S
+ $(COMPILE.S) $< -DPROF -o $@
# How to build RPC stubs
+# We always need this setting, because libc does not include the bogus names.
+MIGCOMFLAGS := -subrprefix __
+
# User settable variables:
+# mig-sheader-prefix prepend to foo_S.h for name of foo.defs stub header
# MIGSFLAGS flags to CPP when building server stubs and headers
# foo-MIGSFLAGS same, but only for interface `foo'
# MIGCOMSFLAGS flags to MiG when building server stubs and headers
@@ -320,19 +512,53 @@ vpath libutil.% $(libdir)/
# CPPFLAGS flags to CPP
# Implicit rules for building server and user stubs from mig .defs files.
-%_S.h %Server.c: %.defs
- $(CPP) $(CPPFLAGS) $(MIGSFLAGS) $($*-MIGSFLAGS) -DSERVERPREFIX=S_ $< \
- | $(MIGCOM) $(MIGCOMSFLAGS) $($*-MIGCOMSFLAGS) \
- -sheader $*_S.h -server $*Server.c \
- -user /dev/null -header /dev/null
-%_U.h %User.c: %.defs
- $(CPP) $(CPPFLAGS) $(MIGUFLAGS) $($*-MIGUFLAGS) $< \
- | $(MIGCOM) $(MIGCOMUFLAGS) $($*-MIGCOMUFLAGS) \
- -user $*User.c -server /dev/null -header $*_U.h
+# These chained rules could be (and used to be) single rules using pipes.
+# But it's convenient to be able to explicitly make the intermediate
+# files when you want to deal with a problem in the MiG stub generator.
+
+%.sdefsi %.sdefs.d: %.defs
+ $(CPP) $(CPPFLAGS) $(MIGSFLAGS) $($*-MIGSFLAGS) -DSERVERPREFIX=S_ \
+ -MD -MF $*.sdefs.d.new \
+ $< -o $*.sdefsi
+ sed -e 's/[^:]*:/$*Server.c $(mig-sheader-prefix)$*_S.h:/' \
+ < $*.sdefs.d.new > $*.sdefs.d
+ rm $*.sdefs.d.new
+
+$(mig-sheader-prefix)%_S.h %Server.c: %.sdefsi
+ $(MIGCOM) $(MIGCOMFLAGS) $(MIGCOMSFLAGS) $($*-MIGCOMSFLAGS) \
+ -sheader $(mig-sheader-prefix)$*_S.h -server $*Server.c \
+ -user /dev/null -header /dev/null < $<
+
+%.udefsi %.udefs.d: %.defs
+ $(CPP) $(CPPFLAGS) $(MIGUFLAGS) $($*-MIGUFLAGS) \
+ -MD -MF $*.udefs.d.new \
+ $< -o $*.udefsi
+ sed -e 's/[^:]*:/$*User.c $*_U.h:/' \
+ < $*.udefs.d.new > $*.udefs.d
+ rm $*.udefs.d.new
+
+%_U.h %User.c: %.udefsi
+ $(MIGCOM) $(MIGCOMFLAGS) $(MIGCOMUFLAGS) $($*-MIGCOMUFLAGS) < $< \
+ -user $*User.c -server /dev/null -header $*_U.h
# Where to find .defs files.
-vpath %.defs $(top_srcdir)/hurd $(includedir)/mach $(includedir)/device
+vpath %.defs $(top_srcdir)/hurd
+
+# These we want to find in the libc include directory...
+mach_defs_names = bootstrap exc mach mach4 \
+ mach_host mach_port mach_timer_reply memory_object \
+ memory_object_default notify
+device_defs_names = dev_forward device device_reply device_request
+
+mach_defs = $(addsuffix .defs,$(mach_defs_names))
+device_defs = $(addsuffix .defs,$(device_defs_names))
+
+$(mach_defs): %.defs:
+ echo '#include <mach/$@>' > $@
+$(device_defs): %.defs:
+ echo '#include <device/$@>' > $@
+
FORCE:
@@ -345,13 +571,17 @@ FORCE:
ifneq ($(no_deps),t)
-# For each file generated by MiG we need a .d file.
+# The MIG stubs depend on their definition files.
# These lines assume that every Makefile that uses a foo_S.h or foo_U.h file
# also mentions the associated fooServer.o or fooUser.o file.
--include $(subst Server.o,.migs_d,$(filter %Server.o,$(OBJS))) /dev/null
--include $(subst User.o,.migu_d,$(filter %User.o,$(OBJS))) /dev/null
--include $(subst Server.o,.migsh_d,$(filter %Server.o,$(OBJS))) /dev/null
--include $(subst User.o,.miguh_d,$(filter %User.o,$(OBJS))) /dev/null
+-include $(subst Server.o,.sdefs.d,$(filter %Server.o,$(OBJS))) /dev/null
+-include $(subst User.o,.udefs.d,$(filter %User.o,$(OBJS))) /dev/null
+
+ifneq ($(prof-depend),t)
+ifneq ($(no_prof),t)
+-include $(addsuffix .prof_d,$(progtarg)) /dev/null
+endif
+endif
# For each .o file we need a .d file.
-include $(subst .o,.d,$(filter %.o,$(OBJS))) /dev/null
@@ -360,28 +590,18 @@ endif
# Here is how to build those dependency files
-# Dependencies for fooServer.c files.
-%.migs_d: %.defs
- (set -e; $(CPP) $(CPPFLAGS) $(MIGSFLAGS) $($*-MIGSFLAGS) \
- -DSERVERPREFIX=S_ -M -MG $< | \
- sed -e 's/\.defs\.o:/Server\.c $@:/' > $@)
-
-# Dependencies for fooUser.c files.
-%.migu_d: %.defs
- (set -e; $(CPP) $(CPPFLAGS) $(MIGUFLAGS) $($*-MIGUFLAGS) \
- -M -MG $< | \
- sed -e 's/\.defs\.o:/User\.c $@:/' > $@)
-
-# The associated .h files are build by the same CCP, so a simple massaging
-# of the previous two will work.
-%.migsh_d: %.migs_d
- sed -e 's/Server\.c/_S\.h/' -e 's/migs_d/migsh_d/' < $< > $@
-%.miguh_d: %.migu_d
- sed -e 's/User\.c/_U\.h/' -e 's/migu_d/miguh_d/' < $< > $@
+%.prof_d: $(srcdir)/Makefile
+ $(MAKE) $* prof-depend=t
+
+ifeq ($(prof-depend),t)
+$(progtarg): %: FORCE
+ rm -f $@.prof_d
+ echo $@.prof: $(subst .so,_p.a,$(subst .o,_p.o,$(filter-out FORCE,$+))) > $@.prof_d
+endif
define make-deps
set -e; $(CC) $(CFLAGS) $(CPPFLAGS) -M -MG $< | \
-sed > $@.new -e 's/$*\.o:/$*.o $*_pic.o $@:/' \
+sed > $@.new -e 's/$*\.o:/$*.o $*_pic.o $*_p.o $@:/' \
-e 's% [^ ]*/gcc-lib/[^ ]*\.h%%g'
mv -f $@.new $@
endef
@@ -398,3 +618,7 @@ endef
%.d: %.s
echo '$*.o: $<' > $@
+# Rule to make executable shell scripts from .sh files.
+%: %.sh
+ sed -e 's/STANDARD_HURD_VERSION_\(.[^_]*\)_/\1 (GNU Hurd) $(hurd-version)/' < $< > $@
+ chmod +x $@
diff --git a/Makefile b/Makefile
index 3c953b7f..e0ba0523 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
#
-# Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+# Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2004,
+# 2006, 2009, 2011 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
@@ -18,62 +19,67 @@
dir := .
makemode := misc
-ifndef srcdir
-srcdir = .
-endif
+include ./Makeconf
+
+DIST_FILES = ChangeLog COPYING Makeconf config.make.in configure.in configure \
+ move-if-change hurd.boot build.mk.in build.mkcf.in aclocal.m4 \
+ README NEWS tasks INSTALL INSTALL-cross version.h.in
-include $(srcdir)/Makeconf
+
+## Subdirectories of this directory should all be mentioned here
+# Hurd libraries
lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
libpager libfshelp libdiskfs libtrivfs libps \
- libnetfs libpipe libstore libmom
-prog-subdirs = auth boot exec fstests init \
- proc term ufs utils sutils trans ufs-fsck \
- devio ufs-utils ext2fs benchmarks pflocal defpager \
- login nfs pfinet daemons
+ libnetfs libpipe libstore libhurdbugaddr libftpconn libcons
+
+# Hurd programs
+prog-subdirs = auth proc exec init term \
+ ufs ext2fs isofs tmpfs fatfs \
+ storeio pflocal pfinet defpager mach-defpager \
+ login daemons boot console \
+ hostmux usermux ftpfs trans \
+ console-client utils sutils ufs-fsck ufs-utils \
+ benchmarks fstests
+
+ifeq ($(HAVE_SUN_RPC),yes)
+prog-subdirs += nfs nfsd
+endif
+
+# Other directories
other-subdirs = hurd doc config release include
+
+# All the subdirectories together
subdirs = $(lib-subdirs) $(prog-subdirs) $(other-subdirs)
+
+# Any subdirectories here that we don't want to distribute to the world
subdirs-nodist =
+
+# This allows the creation of a file BROKEN in any of the prog-subdirs;
+# that will prevent this top level Makefile from attempting to make it.
working-prog-subdirs := $(filter-out \
$(patsubst %/,%,\
$(dir $(wildcard $(prog-subdirs:=/BROKEN)))),\
$(prog-subdirs))
-DIST_FILES = COPYING Makeconf config.make.in configure.in configure \
- hurd.boot build.mk.in build.mkcf.in SETUP \
- README NEWS tasks INSTALL INSTALL-cross
-
-all: $(addsuffix -all,$(lib-subdirs) $(working-prog-subdirs))
-
-%-all:
- $(MAKE) -C $* all
-
-%-lndist: $(top_srcdir)/hurd-snap
- $(MAKE) -C $* lndist no_deps=t
-
-%-clean:
- $(MAKE) -C $* clean no_deps=t
-%-relink:
- $(MAKE) -C $* relink
-%-install:
- $(MAKE) -C $* install
+$(subdirs): version.h
-%-install-headers:
- $(MAKE) -C $* install-headers
+version.h: version.h.in
+ sed -e 's/MASTER_HURD_VERSION/\"$(hurd-version)\"/' < $< > $@
-%-TAGS:
- $(MAKE) -C $* TAGS no_deps=t
+
+## GNU Coding Standards targets (not all are here yet), and some other
+## similar sorts of things
-$(srcdir)/hurd-snap:
- mkdir $(srcdir)/hurd-snap
+all: $(lib-subdirs) $(working-prog-subdirs)
+# Create a distribution tar file. Set make variable `version' on the
+# command line; otherwise the tar file will be a dated snapshot.
ifeq ($(version),)
-version:=$(shell date +%y%m%d)
-dirname:=hurd-snap
-else
-dirname:=hurd
+version:=$(shell date +%Y%m%d)
endif
+dirname:=hurd
dist: $(srcdir)/hurd-snap $(addsuffix -lndist,$(filter-out $(subdirs-nodist), $(subdirs))) lndist
mv $(srcdir)/hurd-snap $(srcdir)/$(dirname)-$(version)
@@ -82,7 +88,9 @@ dist: $(srcdir)/hurd-snap $(addsuffix -lndist,$(filter-out $(subdirs-nodist), $(
clean: $(addsuffix -clean,$(lib-subdirs)) $(addsuffix -clean,$(working-prog-subdirs)) clean-misc
-relink: $(addsuffix -relink,$(prog-subdirs))
+relink: $(addsuffix -relink,$(lib-subdirs) $(prog-subdirs))
+
+objs: $(addsuffix -objs,$(lib-subdirs) $(prog-subdirs))
install: $(addsuffix -install,$(lib-subdirs) $(working-prog-subdirs) \
$(other-subdirs))
@@ -91,6 +99,38 @@ install-headers: $(addsuffix -install-headers,$(lib-subdirs) \
$(working-prog-subdirs)\
$(other-subdirs))
+TAGS: $(addsuffix -TAGS,$(working-prog-subdirs) $(lib-subdirs))
+ etags -o $@ $(patsubst %-TAGS,-i %/TAGS,$^)
+
+## Targets used by the main targets above.
+$(prog-subdirs) $(lib-subdirs): FORCE
+ $(MAKE) -C $@ all
+FORCE:
+
+%-lndist: $(top_srcdir)/hurd-snap
+ $(MAKE) -C $* lndist no_deps=t
+
+%-clean:
+ $(MAKE) -C $* clean no_deps=t
+
+%-relink:
+ $(MAKE) -C $* relink no_deps=t
+
+%-objs:
+ $(MAKE) -C $* objs
+
+%-install:
+ $(MAKE) -C $* install
+
+%-install-headers:
+ $(MAKE) -C $* install-headers
+
+%-TAGS:
+ $(MAKE) -C $* TAGS no_deps=t
+
+$(srcdir)/hurd-snap:
+ mkdir $(srcdir)/hurd-snap
+
lndist: cp-linked-files
linked-files = install-sh config.guess config.sub mkinstalldirs
@@ -99,8 +139,6 @@ cp-linked-files: $(lf-inst)
$(lf-inst): $(srcdir)/hurd-snap/%: $(srcdir)/%
cp $< $@
-TAGS: $(addsuffix -TAGS,$(prog-subdirs) $(lib-subdirs))
-
.PHONY: clean-misc distclean
clean-misc:
@@ -109,3 +147,17 @@ distclean: clean
ifneq (.,${srcdir})
rm -f Makefile
endif
+
+
+## Directory dependencies
+#
+# Some directories depend on others, so we need to find out exactly
+# what they are. This does that for us.
+
+ifneq ($(no_deps),t)
+-include $(addsuffix .d,$(subdirs))
+endif
+
+# How to build them
+$(addsuffix .d,$(subdirs)): %.d: $(top_srcdir)/%/Makefile
+ $(MAKE) -C $* directory-depend no_deps=t
diff --git a/NEWS b/NEWS
index fe2f2649..26cffe1e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,575 +1,251 @@
-*- Text -*-
-April 15, 1995
+XXX this needs much work, trolling through ChangeLogs.
+
+Many, many, many bugs have been fixed, including some resource
+consumption problems and race conditions. The system can compile
+itself as well as most external applications. The amount of stress
+the system can tolerate has increased a lot.
-It's hard to summarize, so much has happened.
+The new ftpfs translator can be used to transparently access FTP
+servers through the filesystem. Together with the new hostmux
+translator, which can invoke host-specific translators like ftpfs,
+this leads to a very comfortable way to use FTP archives on the Hurd.
-We have NFS, a network, and jillions of stuff. Basically things just
-work. Except for a jillion little nits, this is very nearly an alpha
-release. Not quite, but nearly.
+A new translator usermux can invoke user specific translators. It can
+be used to provide a symlink to all users home directories in a single
+place (similar to amd/automount).
+The tmpfs translator can be used to store files and directories in RAM
+without any overhead of a real filesystem. The amount of memory
+allocated equals the amount of space occupied, and an upper limit can
+be defined.
+
+Shadow passwords are now supported. If the password field in
+/etc/passwd contains the string "x", the crypted password is looked up
+in /etc/shadow instead. A new password server distributes auth ports
+after password verification.
+
+The pfinet server uses the Linux 2.2.12 IP stack now. It supports the
+new interface types dummy and tun which provide a bottomless sink and
+IP tunnel interface respectively. It also supports all common network
+ioctls now.
+
+The Hurd can now access CD-ROMs containing an ISO9660 file format with
+the new iso9660fs translator. Rock Ridge extensions are supported, as
+well as some GNU extensions to store GNU specific file system
+attributes in such filesystems.
+
+Two new translators, hello and hello-mt, illustrate how to implement
+simple trivfs based filesystems in the Hurd.
+
+A new utility `rpctrace' aids in debugging the Hurd by listing all
+invoked RPCs with message id and port right information.
+
+The Hurd does no longer contain the utility `su', which is included in
+the GNU shellutils package. `setauth --save' can also be used as a
+replacement.
+
+The init script mechanism became more flexible, as it was splitted
+into several files. This allows to plug in different styles of init
+procedures by just hooking them into /libexec/runsystem.
+The ext2fs server understands the sparse_super filesystem option, and
+can deal with the filetype option (but won't make use of this itself).
-
-The `boot' program now accepts an option ``-D DIR'' which specifies a
-directory prefix for the file names given in the boot script (hurd.boot).
-So the way to boot is now:
- $ boot.a -D .../hurd-image hurd.boot sd0a
-
-
-October 5, 1995
-
-The Hurd distribution now uses a `configure' script in the standard GNU
-style. As with other GNU packages, you can configure in the source
-directory or in a separate build directory (though not both with the same
-source directory); all you should need to do is `configure i386-gnu'. The
-Hurd does not compile in any file names using $(prefix), so you can specify
-the prefix where you will install things with the `--prefix' option; e.g.,
-`configure --prefix=/gd4/hurdinst i386-gnu'. You should no longer need to
-edit any makefiles. You can choose the tool names by setting variables in
-the environment when running configure (CC, LD, AR, RANLIB, OBJCOPY, MIG);
-the default is to search your $PATH for HOST-TOOL (e.g. i386-gnu-gcc), and
-failing that just TOOL (e.g. gcc), so you will win automagically if you
-simply use the same host alias in the `configure' command line as you used
-for the target alias to configure gcc and binutils (i.e. i386-gnu).
-
-The file_truncate RPC (in fs.defs) has been renamed file_set_size and
-now is expected to extend files as well as truncate them, in the
-manner of recent BSD releases' ftruncate. file_pathconf has been
-moved from fs.defs to io.defs and renamed io_pathconf. The `core'
-interface has been renamed `crash'.
-
-We are now using a new terminal driver that is multi-threaded. It is
-also much more simple internally than the older version, but otherwise
-supports no new features.
-
-Everything is now dynamically linked except the bootstrap filesystem. Any
-old statically linked binaries should be replaced. WARNING: In the next
-snapshot changes in the exec server may prevent older statically linked
-binaries from running.
-
-The exec server by default now only supports ELF; if you have older
-a.out binaries you want to run, you need to reenable BFD support in
-the exec Makefile. (Old a.out binaries should be replaced anyhow,
-with dynamically linked ELF binaries, for the reasons in described in
-the warning above.)
-
-The bootstrap hack in the directory boot now understands boot scripts;
-this kind of boot script will also be used by an upcoming release of
-Mach4. Also, because the exec server is now dynamically linked, it is
-necessary to install the exec server itself on the Hurd partition (in
-/hurd/exec); that was not necessary before, so it is possible that old
-working Hurd partitions might not have it.
-
-Some problems and trivial bugs in fsck are fixed.
-
-A few bugs in libdiskfs, libpipe, pflocal, and trans were fixed of no
-particular consequence.
-
-Shutdown of filesystems now works reliably and safely.
-
-Libports now provides stubs to do the normal thing for the interrupt and
-notify interfaces. Because of the interruption semantic, cthreads
-multiplexing of multiple cthreads onto fewer kernel threads can no longer
-be used; this means that ports_manage_port_operations_multithread no longer
-pays attention to the WIRE_CTHREADS flag.
-
-Cthreads now supports an implication semantic for conditions; this
-enables a condition variable to be created which is the disjunction of
-other condition variables.
-
-Trivfs now supports errors and blocking on open much better.
-
-A rare but serious bug in the pager has been fixed; along with this,
-another minor deficiency in the kernel has become apparent.
-
-The Makefiles are more generic and deal with shared libraries better.
-
-A serious bug has been fixed in ext2fs.
-
-
-
-July 23, 1995
-
-Shared libraries now work; use -static to link programs and avoid the
-shared libraries. The Hurd programs are normally built static; this
-will probably change soon.
-
-The ext2fs server now works, as do the tools to manipulate ext2fs
-filesystems. A snapshot of the tools will be made soon under separate
-cover. Many thanks to Ted Ts'o for his valuable work on the tools.
-
-Readers of the Makefiles will notice that we now generate dependencies
-automatically.
-
-The old netserv library is gone.
-
-The `boot' hack has been modified slightly to avoid the normalq libc startup
-files, because they no longer work with UX.
-
-Some small bugs have been fixed in the devio server.
-
-The ports library has been totally rewritten; new features permit
-servers to have greater control over thread RPC's and port creation.
-
-The fshelp library now does most of the work for translator
-interaction; it's simpler now too. Filesystems have much less work to
-do; the relevant code in libdiskfs is now understanble instead of
-unparseable chaos.
-
-The ports library provides for timeouts; the diskfs library almost
-uses it, but because of a bug, it's disabled for now.
-
-Filesystems are now expected to sync themselves if necessary; the new
-fsys_set_options RPC provides for changeing (or cancelling) the sync
-intervale. The diskfs library does this for you. The update program
-is no longer necessary.
-
-A small bug in the proc server has been hacked around; the real fix
-will come later.
-
-Many important bugs in the C library have been fixed since the last
-snapshot; perhaps all of them. ;-)
-
-
-
-June 6, 1995
-
-The Hurd has switched to using the ELF object file format instead of a.out.
-You will need a very recent snapshot of GCC and binutils (we are using the
-950606 versions); the `i386-gnu' configuration now uses ELF, we are dumping
-a.out entirely.
-
-The exec server now understands the ELF format directly (not through BFD),
-because BFD has some deficiencies in its treatment of ELF. The direct
-support for a.out has been ripped out completely. The exec server can
-still support BFD as an optional addition, if compiled with -DBFD; this is
-now the only way to run a.out executables. But if you only want to run new
-ELF binaries, then you can omit -DBFD and needn't bother building the BFD
-library to build the Hurd. The support for gzip'd executables is now
-conditional on -DGZIP; it adds a pretty small amount of code. Our
-makefiles use both -DGZIP and -DBFD by default; edit exec/Makefile if you
-wnat to omit BFD or gzip support. (Probably soon we will omit -DBFD by
-default because it will make the exec server much smaller, but we just
-switched and still have run a.out binaries lying around we'd like to
-continue being able to run.)
-
-Because everything is now in ELF, the procedure to create an executable of
-the `boot' program that can run on UX is rather hairy. Do `make boot.a' in
-the boot directory and run `boot/boot.a', which is an a.out executable.
-`boot/boot' is a weirdo ELF executable that UX cannot understand.
-
-The startup sequence has changed; the exec server image is no longer
-embedded in the filesystem image. The `boot' program loads both the
-filesystem and the exec server into separate tasks and runs the filesystem,
-passing it the task port of the exec server, which it starts running when
-it's ready for it. This closey approximates the eventual plan for booting
-the system, wherein the boot loader will load the multiple program files as
-well as the kernel, and the kernel will set up the two tasks. However,
-changes are needed in the Mach bootstrap process to read ELF binaries and
-to start multiple servers, so for the moment native booting is broken.
-
-April 12, 1995
-
-Many bugfixes and changes. Now includes a fancy ps, settrans, and
-showtrans; separate translators for all the programs in /dev (and a
-MAKEDEV script). Also the provisional source for network servers and
-some other snippets of code are now being distributed. The trivfs
-library is now multithreaded.
-
-The old dev.trim is still being distributed, but you shouldn't use it.
-
-A serious bug that broke the filesystem's state after enough exec
-failures (of the bad format sort) happen. A deadlock or two was also
-found and fixed.
-
-December 13, 1994
-
-The exec server now recognizes gzip'd binaries and uncompresses them into
-memory to execute them. (This has allowed a useful number of binaries to
-fit on a 1.44MB floppy.)
-
-November 24, 1994:
-
-Program changes:
-
-term could hang in delivery of terminal signals; fixed.
-
-pipes now handles io_select.
-
-These fixes allow GNU Emacs to work under the Hurd, with subprocesses.
-
-November 11, 1994:
-
-Structural changes:
-
-Our sources are now under RCS. That shouldn't affect you at all,
-except that the file in the distribution will now be mostly mode 0444
-by default.
-
-
-Interface changes:
-
-`dealloc' flags have been added to many MiG interfaces broadly to fix
-a class of bugs.
-
+Several utilities have new options. All store based filesystems can
+be configured with --no-suid, --no-exec, --bootflags, --boot-command
+and --no-cache. The null translator also can be full now (--full).
+The magic translator can provide an empty directory.
-Library changes:
+The crash server supports several modes of operation, it can suspend
+or kill a crashing task. Core dumping is planned for but not
+implemented yet. Users can set their own crash server using an
+environment variable.
-Synchronous locks were hanging in some cases; to avoid it for now,
-they are never done at all. (Of course, this is really a bug that
-needs fixed; the current change is purely for the sake of running the
-system.)
+The new fakeroot translator appears to give transparent access to the
+underlying directory node. However, all accesses are made using the
+credentials of the translator regardless of the client and the
+translator fakes success for chown and chmod operations, reporting the
+faked IDs and modes in later stat calls.
-Some bugs in translator startup in libfshelp have been fixed.
+The new fakeauth program runs a command with a fake authentication
+handle that claims to be root or any arbitrary identity derived from
+that handle, but in fact is always just a proxy for your real
+authentication handle.
-Bootstrapping in libdiskfs is cleared up. A bug in io_read that cause
-a crash if you gave an offset past the file size has been fixed.
-Non-root filesystems can now contact the execserver.
+The features provided by the fakeroot translator and fakeauth are
+combined in the new fakeroot program.
+The proc server can show the start time of processes.
-Program changes:
+* sync -> syncfs, takes args
-The `boot' hack can now start the first task in one of three ways: the
-way it was before, which is pretty Hurd-ish; just like the kernel
-starts the first task; and just like CMU's `boostrap' user program
-starts the CMU multiserver. Also, `boot' always passes a -f flag so
-that other programs can no we aren't really running native.
+* Default pager (serverboot) understands Linux (mkswap) signature pages.
+ New boot script function $(add-raw-paging-file) inhibits looking for the
+ signature page. New function $(add-linux-paging-file) checks for the
+ page and refuses to use the swap partition or paging file if there is no
+ valid Linux signature page. A stand-alone default pager `mach-defpager'
+ is implemented which supports the same features. With
+ "die $(serverboot)"
+ in the boot script, serverboot doesn't become the default pager.
-The execserver now registers itself properly on /servers/exec and can
-thus be used by non-bootstrap filesystems.
+* libstore uses off64_t internally, allowing large stores to be
+ handled properly. The zero store supports suffix b, k/K, m/M, g/G
+ for blocks, kilo-, mega- and gigabytes resp. when specifying the
+ store size. The remap store understands N+ as the end of the store
+ starting from block N. A new store type `bunzip2' uncompresses
+ stores in the bzip2 format into memory.
-Init uses symbolic names for /bin/sh and /dev/console rather than
-hardcoded strings. The STANDALONE macro is gone; the behavior is the
-same but depends on the presence or absence of -f in the boot flags.
+* msgport, ping
-Some minor bugs in proc have been fixed.
-
-The terminal driver now sends SIGWINCH properly. Changing to and from
-ICANON now moves the terminal input queues around properly.
-
-The filesystem now uses one pager to map the disk and little pagers to
-map files. Some hair is new to keep data from showing up in both
-pagers; generally the code is much simpler and cleaner now. (Faster,
-too.) The DT_* type information is currently unused due to an
-implementation difficulty. Some workarounds have been installed to
-avoid some kernel bugs.
-
-Large writes to the pipes server used to crash it; they don't any
-longer.
-
-The /dev server now has hardcoded into it more disks and it's easier
-to add more yourself. Also work around a kernel bug.
-
-New utilities: clri, sync, halt, reboot. The output of ps has been
-cleaned up a little.
-
-Fsck has been rewritten; there are still bugs in creating directories.
-(That code is only used if /lost+found is absent, so it's still
-useful.) The old version is renamed to bsdfsck.
+The Hurd interfaces have been changed to support large files.
+The new proxy-defpager translator grants unprivileged users access to
+the default pager.
+9 June 1997
+Version 0.2
-September 8, 1994:
-
-Structural changes:
-
-No significant structural changes have been made.
-
-
-Interface changes:
+Summary of important externally visible changes since version 0.1:
-term.defs has a new RPC `termctty_open_terminal', necessary for
-implementing /dev/tty.
+Many, many bugs have been fixed, including some resource consumption
+problems. The system can now compile itself, and stay running the
+whole time. It is quite reliable, and is used here for regular
+computing tasks now.
-The filesystem lookup retry mechanism has been altered slightly.
-FS_RETRY_NONE is gone. If the retry pathname is empty, then no retry
-is necessary, and the returned port should be used, after
-reauthenticating it if FS_RETRY_REAUTH was set. Uniformly Hurd
-servers attach no special meaning to leading / in filenames, the
-result is that leading / (to Hurd servers) is a NOP.
+New programs addauth, rmauth, unsu, su, and setauth modify the uid
+sets of running programs. Using addauth you can add root to your
+emacs, write a file, and then use rmauth to take the uid back. (Of
+course, passwords are required when necessary.) New program `ids'
+will tell you what all the user ids are that a program has. Note that
+in the Hurd a program can have several user ids all at once, just like
+Unix supports having several group ids. Now that you can dynamically
+change the ids of running programs, system administration (among other
+things) becomes much easier.
-The authentication protocol now passes a second port for rendezvous
-rather than an int; this cleans up a slight security hole. The I/O
-and proc protocols have been changed accordingly.
+Two new programs, ftpcp and ftpdir, can be used to fetch files using
+FTP with a simple command line interface.
-The args to file_set_translator have been cleaned up.
+We have moved the `serverboot' bootstrapper and default pager from
+Mach into the Hurd source distribution, so that Mach can avoid
+distributing user programs. We hope to phase out use of serverboot
+entirely at some point. Along with this, we made serverboot much
+quieter.
-All routines that used to say `path' no longer do; in GNU we always
-call these filenames.
+We now build profiling versions of the Hurd libraries, and the
+makefiles have targets to build profiling executables as desired.
+We have added `lmail', a /bin/mail replacement for use with sendmail
+to do local mail delivery.
-Library changes:
+The idle threads of the kernel no longer count in `ps' towards the
+total run time of the kernel process. This means that the kernel will
+now sort into the right location for `u' format output.
-libdiskfs and libfshelp now do passive translator startup properly.
+Several oddities in NFS client behavior have been fixed to produce
+more sensible results.
-Setuid execution is now done by libdiskfs.
+The "loopback" device is now supported (automatically) inside pfinet.
+It should now be possible to use pfinet with no ethernet at all.
-A little work has been done in libpager towards implementing a default
-pager, bit it's not complete yet.
+Filesystems now use `store' library; the contents of the filesystem
+can be nearly anywhere (including another file somewhere).
+Some annoying bugs in tty behavior have been fixed. Some still
+remain, unfortunately.
-Program changes:
+New translator `firmlink' is like a cross between a symlink and a hard
+link.
-A braino in the auth server was fixed, and it uses the new auth
-protocol.
-The boot program no longer spins; it uses multiple threads. It also
-takes nice command line args. ufs and init only pause for debugger
-attach if you give boot the -d flag. Init now expects passive
-translators to be set for /dev and it looks prettier.
+Programmer visible changes:
-The kludgy dev server now also works for (1) disk.
+Filesystems support a new "reparenting" feature. This makes `..' from
+the "reparented" node return whatever the user wishes, for a given
+`open' regime. This enables the "firmlink" translator to work, and
+will also be important in implementing shadow filesystems.
-Some exec server bugs in EXEC_NEWTASK were fixed.
+The fshelp library now managed UID sets itself, and contains functions
+to do permission checks in the usual way. Now it's much easier to be
+sure every filesystem implements the same permission checks.
-There is now a port of fsck, and two new programs: settrans and
-opendisk.
-
-The proc server now has a better prime number generator, and some
-small bugs have been fixed.
-
-The terminal driver now does job control and other signals correctly.
-
-Some minor improvements have been made in ufs.
+The trivfs library has had its static initializations replaced with
+spiffy dynamic ones.
+New library `libftpconn' is used to manage FTP connections. We are
+already using this library for some local system administration tasks,
+and are making it the basis of the (as yet unfinished) ftpfs
+filesystem for the Hurd.
-August 8, 1994:
-
-Structural changes:
-
-Makefiles have been vastly improved and are simpler. The programs
-`su', `ps', and `sh' have been moved from separate dirs into `utils';
-the programs `symlink' and `ifsock' have been moved into `trans'.
+6 September 1996
+Version 0.1.
-Several changes were made to GCC use. You should definitely get GCC
-version 2.6.0 now. Version 2.6.1 will have distributed the proper
-`specs' file for the i386-gnu target, but it isn't quite ready yet, so
-you still have to copy hurd/gcc-specs into
-gcc-lib/i386-gnu/2.6.0/specs.
+Summary of important externally visible changes since version 0.0:
+Many miscellaneous bugs have been fixed.
-Interface changes:
+Missing source files in 0.0 have been correctly added to the
+distribution.
-The tioctl.defs suite is complete now.
+Configuration now knows that various 386 equivalents use the same
+assembly files.
-INTR RPC's have been changed; individual RPC's are no longer marked
-INTR. Rather, entire interfaces are marked `INTR_INTERFACE' if they
-conform to the library's signalling/interruption expectations.
+There is now an nfsd; it has not be well-tested. It would be nice if
+some people would run it and try things out. It does not yet support
+Hurd-specific features.
-There is a new magical retry type (for dir_pathtrans and fsys_getroot)
-called `machtype' and a new one `/'; the former is for @sys tweaks and
-the latter cleans up the retry of root-based symlinks a bit.
+Exec now compiles correctly even when you don't have BFD installed.
-There is a new interface `login.defs'.
+Ext2fs format interpretation problems have been fixed. This means it
+can be suitably used to boot with.
-The "dotdot node" is no longer passed at fsys_startup time; instead,
-it is passed by fsys_getroot.
+init now properly understands SIGHUP and SIGTERM, and does the right
+thing correctly.
+Much code has been written in nfs towards supporting version 3 of the
+protocol, but it's not done yet. Don't try and turn it on.
-Library changes:
+Version information in uname is now calculated differently.
-The ports library now does death-timeouts for multi-threaded servers;
-it doesn't actually work right yet, however. Also the ports library
-has new features (soft vs. hard ports; no outstanding ports
-notifications) that enable server-death to be done cleanly. (I hope;
-libdiskfs and ufs haven't yet been changed to use it, so libports
-might not actually have the right facilities yet.)
+Some improvements have been made in the SETUP script.
-The translator startup routines in libfshelp have been vastly improved
-(so that they can actually be used).
+sync, reboot, and halt now do argument parsing and understand --help
+and --version.
-Numerous bugfixes in libdiskfs, particularly relating to translator
-usage. Use new magical retry type `/' when appropriate. Use new
-dotdot node protocol. O_FSYNC and O_NOATIME are now honored properly.
-Alternative methods of storing symlinks are now supported through new
-hooks.
+The new `e2os' program has been added to change the "creator OS" field
+on an ext2fs filesystem.
-The new dotdot protocol is now used by libtrivfs. Also, users of the
-library are now able to set the atime and mtime when necessary.
+Bugs in term and libtrivfs have been fixed, allowing emacs shell mode
+to work cleanly. Other minor bugs have also been fixed.
-The special threads version of malloc has been placed back in
-libthreads now that the C library uses a Mach-safe version on its own.
+ufs and ext2fs now do directory search rotoring to speed repeated and
+sequential directory lookups.
+ufs now notes correctly if a disk cannot be written to and turns on
+the readonly flag automatically in this case. (Useful for floppies.)
-Program changes:
+ufs statfs information (printed by df) should now be correct.
-The `boot' program no longer implements the tioctl interface now that
-the terminal driver works.
-
-A bug was fixed in the handling of pgrps in `proc'.
-
-Many bugfixes in term. The tioctl interface is now implemented. EOF
-processing is fixed; break characters now work right. Signals and
-interruption are now done correctly. VDISCARD works.
-
-Ufs has Some bigs fixed in dir.c. Filesystem upgraded to BSD 4.4.
-There are now some compatibility flags.
-
-New program dev.trim does a very minimal /dev (but doesn't work yet).
-New program dev is an initial (but poor) attempt at a real /dev.
+A serious bug in ufs fsck when dealing with large directories has been
+fixed.
+A new program `vminfo' prints the virtual memory map of task.
+All disk filesystems (ufs and ext2fs) now do directory name caching of
+`..' which was not previously done. In addition, you can now set the
+cache size to be large, and then do experiments and see what the cache
+hit rate would have been for various smaller sizes. This should help
+in optimizing the size of the cache.
+A port leak in the pager library has been fixed; previously ufs leaked
+two ports per file used until the kernel's limit (about 30,000) was
+reached.
-July 5, 1994:
-
-The Hurd now runs all the programs in the GNU fileutils, textutils,
-and shellutils distributions, with the exception of who. Most
-importantly it runs GNU Hello. Also, emacs works (with the kludgy
-`boot' terminal driver) and bash works.
-
-The simple pipes server works; it will be replaced eventually by the
-pflocal server (which isn't done yet). The terminal driver is limping
-but working. It doesn't support terminal ioctls yet. A minor bug in
-auth has been fixed. boot interprets more Hurd protocols; this was
-done to get emacs functioning. Some more-or-less serious bugs in exec
-were fixed; they were found by running emacs (a quite large executable
-indeed). At bootstrap time, init starts pipes and term itself;
-eventually these will be passive translators, but we don't want to
-write the new disk format until we're self-hosting or fsck and UX will
-get confused. The file proc/primes.c has been documented; thanks go
-to Jim Blandy. Some bugs in proc dealing with pgrp and wait were
-fixed; a nasty hash table bug was also fixed. The simple shell can do
-pipes. Several serious bugs in ufs were fixed dealing with extension
-of large files and writes of data not aligned on block boundaries.
-The ufs pager was over-serialized; that's been fixed. Directory
-lookups and modifications now use mapped I/O directly; this is an
-important speed-up. The structure of the pager lockes has been
-changed significantly. UFS now supports Mach copying mode
-MEMORY_OBJECT_COPY_DELAY; this significantly improves process startup
-time.
-
-Some minor changes have been made to several interfaces. The
-interface for fs.defs:dir_readdir has been totally changed. There are
-some new fs.defs interfaces: file_check_access, file_notice_changes,
-dir_notice_changes. The fsys.defs:fsys_getroot interface was changed
-to work correctly. process.defs:proc_setprocargs is renamed, and a
-fetch function proc_get_arg_locations is added. The ifsock.defs
-interface was simplified.
-
-Several bugs were fixed in libdiskfs. The new dir_readdir interface
-requires new support from format-specific code. Some race conditions
-have been fixed. dir-pathtrans.c now deals correctly with multiple
-slashes in a row. A new concept called "light references" allows
-pagers to remain active without preventing truncate-on-nolinks from
-working right. New interfaces in fs.defs are implemented (except
-file_notice_changes). Active translator usage has been fixed to work
-correctly, but passive translators are still untested. libdiskfs now
-thinks it supports S_IFSOCK nodes, but that's untested (of course)
-because pflocal isn't done yet.
-
-The passive translator startup interface in libfshelp has been
-radically simplified. The pager library now lets other code set and
-changee the attributes on objects, synchronously if desired. An
-init/terminate race condition was fixed. The ports library now
-allows single-threaded users to work right (they didn't before). The
-trivfs library works; see the ifsock server for a simple example of
-its use. See term or pipes for more complex examples.
-
-There is a task list in the file `tasks'; let me know if you are
-interested in working on one of these.
-
-
-May 17, 1994:
-
-The Hurd now runs all the programs in the GNU fileutils and textutils
-distributions. All the programs in shellutils run normally except
-who, false, groups, nohup, true, and nice. We can't tell if tty is
-working right because the necessary support isn't set up (so it just
-prints `not a tty'. Some minor filesystem bugs have been fixed,
-including several brainos in disk allocation and total lossage in
-symlink interpretation. No bugs are now known.
-
-The library now supports signals; the program `timertest' is one test
-program we've used.
-
-All the core servers register their version with proc and register
-themselves as essential tasks with init. This enables proc to compute
-proper uname version strings and enables init to crash the system if
-one of the core servers dies.
-
-Boot is set up with a special hack to detect the RPC's that emacs uses
-to go into and out of raw mode; this will hopefully enable us to run
-emacs soon.
-
-There is a kludgy server called `pipes' (not yet completed) which
-implements just those parts of the local-domain socket server that the
-library uses in implementing the `pipe' function. This will enable us
-to have a real shell somewhat before needing the local domain socket
-server.
-
-More work on trivfs has happened; this will be needed by pipes.
-
-Cthreads is now in the Hurd distribution; this will make it much
-easier to install. The GNU C library depends on some changes we have
-made to this version of C threads and will not work with other
-versions you might have. (Several files in other versions of CMU
-Cthreads are not in this distibution [notably spin locks]; those are
-now in the GNU C library.)
-
-The installation hints in README have changed considerably; read them
-again.
-
-I'm now keeping ChangeLogs; you can examine them for more detailed
-information.
-
-
-
-April 5, 1994:
-
-The Hurd now bootstraps. Auth and proc start successfully; init
-prints "Init has completed" where it would run the shell.
-
-There are the beginnings of some documentation in the new doc
-directory.
-
-
-
-March 25, 1994:
-
-The Makefiles now are set up for cross-compilation; see README and the
-comments in Makeconf and Maketools for more information.
-
-The new diskfs library is complete. The filesystem using it runs as
-well as the previous version. Interested folk: please examine the
-diskfs interface, and see if it can be used for your favorite
-filesystem; I'd like it to be as general as possible.
-
-The proc server and auth servers link completely but have not been
-tested. The init.trim directory holds a lightweight version of init
-suitable for use before the C library support for file descriptors,
-exec, and so forth works; this version of init compiles and links.
-The primary effort right now is booting init, proc, and auth.
-
-Work has been suspended on tmpfs for the time being, it not being
-necessary for a running system. Some new FS calls have been added,
-notably dir_mkfile.
-
-
-Feb 1, 1994:
-
-Much filesystem code has been split out into new libraries, most
-notably, libpager, which now contains the implementation of the
-complex multi-threaded pager previously in the filesystem.
-
-libdiskfs will continue this process, with everything related to
-filesystems based on disks (or other real substrates), but format
-independent. libfshelp will have routines for starting translators,
-keeping track of flock, and so forth; it will be useful for any
-implementor of the fs protocol. ufs currently does not use either of
-these, but will when they are done.
-
-tmpfs and init.trim are in progress. tmpfs will be memory-only for
-things like /tmp, and is currently waiting for the fshelp library to
-be finished. init.trim will be a scaled down init, useful for testing
-bootstrapping before there is enough library support to run the real
-init. Currently this is waiting on fixing some crucial ld bugs.
-(When those are fixed, work will begin in earnest on bootstrapping
-auth, proc, and init.)
-
-
+6 August 1996
+Version 0.0
+Initial release
diff --git a/README b/README
index e28202a2..69c8dad0 100644
--- a/README
+++ b/README
@@ -1,20 +1,28 @@
-*- Text -*-
-GNU Hurd version 0.0.
+GNU Hurd version 0.2.
This is the Hurd. Welcome.
+This version of the GNU Hurd runs on various ix86 machines, including
+i386, i486, i586 (pentium), i686 (hexium [pentium pro]).
+
For instructions on compiling and installing the GNU Hurd from an
already running Hurd system, see the file `INSTALL'.
It is possible to cross-build the Hurd; the file INSTALL-cross
contains some past instructions for doing so, but it's too much
trouble to maintain these instructions and keep them up to date. Your
-best bet is to start with a running Hurd system already.
+best bet is to start with a running Hurd system already. If you do
+decide to cross compile, you will need to examine the instructions in
+INSTALL for building Mach, libc, and the Hurd together, and follow
+them. The instructions in INSTALL-cross are quite out-of-date, but
+they contain some useful hints buried amongst the errors, so we have
+left the file for those who find it useful.
Please note that this directory also contains a fair amount of
-not-yet-working code. The makefiles build only the working code by
-default.
+not-yet-working code. By default, the makefiles build only the
+working code.
Bug reports for the GNU Hurd should be sent to the mailing list
`bug-hurd@prep.ai.mit.edu'. Please do not send requests for
@@ -24,9 +32,6 @@ Instead, send requests for assistance to the mailing list
request to `bug-hurd-request@prep.ai.mit.edu' or
`help-hurd-request@prep.ai.mit.edu' respectively.
-If any of these address should fail, send your message to
-`tower@gnu.ai.mit.edu' and ask him to forward it properly.
-
The GNU Hurd is free software. All of it, including the libraries in
this distribution, is covered by the GNU General Public License, found
in the file COPYING.
diff --git a/README.CVS b/README.CVS
new file mode 100644
index 00000000..92a2392d
--- /dev/null
+++ b/README.CVS
@@ -0,0 +1,29 @@
+-*- Text -*-
+GNU Hurd CVS version.
+
+
+This is the Hurd. Welcome.
+
+For installation instructions, you might try your luck with the files
+README, INSTALL, and INSTALL-cross. However, they have not been
+updated for a long time.
+
+For now, this file documents the version requirements for the CVS
+version of the Hurd. Other combinations might work, but the stated
+minimum requirements are best tested by the developers.
+
+GNU MiG at least 1.3
+GNU Mach at least 1.3
+GNU C library CVS from 2004-03-09 or later
+GNU C compiler at least 3.3.2
+
+Optionally, a Sun RPC implementation is needed to build the NFS
+translator and daemon:
+
+GNU C library at most 2.13
+TI-RPC (currently fails to build on GNU, see
+ <http://lists.debian.org/debian-hurd/2010/12/msg00007.html>.)
+
+Obviously, you also need somewhat recent versions of binutils, make,
+bash and some other tools. No hard requirements are currently known
+for these, though.
diff --git a/SETUP b/SETUP
deleted file mode 100644
index 13101df8..00000000
--- a/SETUP
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# Setup critical hurd translators
-
-set -v
-
-# Set up the PFLOCAL server so we can do pipes
-/bin/settrans -c /servers/socket/1 /hurd/pflocal
-
-# Setup crucial devices
-cd /dev
-/bin/sh ./MAKEDEV std
diff --git a/TODO b/TODO
index 3d146107..b541f38f 100644
--- a/TODO
+++ b/TODO
@@ -1,232 +1,303 @@
-*- Mode: Outline -*-
-Things to be done on Hurd, that we should probably not punt to a volunteer.
+Before working on anything in this file, it's very important that you
+make contact with the core Hurd developers. Things herein might be
+slightly out of date or otherwise not easy to understand at first
+glance. So write to <bug-hurd@gnu.org> first.
-See `tasks', the exported task list.
+Priorities:
+ Check the end of this file for a task list referring to the next
+ public release.
+
+ Reported bugs generally have top priority.
+ Non-reported and non-encountered bugs (things we know don't work,
+ but don't really impede things) have lower priority.
+ Things in this file are ranked with one to three !; the more, the
+ higher priority.
-* RMS dictates:
-** O_RDONLY==0
-** "user-friendly" naming scheme for /dev
+See `tasks', the exported task list.
-* Emacs M-x shell seems to start all the ptys.
-* Settle termcap v. curses with rms et. al.
* Contents of =pending-changes.
-* Make sure all the pieces of the Hurd have adequate version stuff.
-* syslogify everything
-* fix root dependencies in filesystem, network, etc.
-* Profile things
-* Make for easier installation
+* Make sure all the pieces of the Hurd have adequate version stuff. !
+* fix root dependencies in filesystem, network, etc. !
+* Profile things !!
* Write coding standards suggestions for Hurd
+* Implement file_fetch_dir
+* Conform to coding standards (esp. CFLAGS setting)
+* Internationalization !
+* Use hostid in /etc/rc and mention it in installation instructions,
+ when suitable sh-utils is released.
+* "user-friendly" naming scheme for /dev
-* Fix emacs/src/unexelf.c to deal with occasional lack of mmap
+* Fix emacs/src/unexelf.c to deal with occasional lack of mmap !
+
+* Currently libshouldbeinlibc (idvec, etc) and password.defs and login
+ all think there is one user per-uid, and that ain't necessarily so.
+ Needs fixed. !
* Libraries
** general:
-*** fsys_get_options should return: prog name in argv[0]; non-option program args, e.g. the diskfs device, or nfs mount
-
-** libmom work:
-*** Hack interface definitions so that args are mom-ish
-*** Change libports and libpager to be mom-ish
-*** Change servers to be mom-ish
+*** implement all the pathconf things from Posix.1 right.
+*** implement an soversion and symbol-versioning scheme similar to libc's.
** libc:
+*** !!!! Do these for libc 2.3 (ask Roland for details):
+**** nix hurdmalloc, use special arena with new _int_malloc
+**** TLS support
+**** avoid sbrk altogether in malloc (don't link it in at all for static)?
+**** maybe hack libio to use _hurd_fd_read et al directly as stdio used to
+*** (once vm_remap exists) implement mremap
+*** when a session leader _exits, it should SIGHUP, TIOCDRAIN, and revoke. !!!
+ [it is still under discussion exactly where to address this,
+ so don't do it in libc yet]
*** Version of tmpfile that takes a directory
-*** Hurd versions of tmpfile that don't create transient files
*** flink
-*** make sure profiling works
-*** implement revoke once io_revoke is added.
+*** make sure profiling works !!
+*** many functions that are syscalls in unix can potentially leak send rights
+ if a signal handler longjmp's out past them. They should probably all
+ be using HURD_CRITICAL_SECTION to avoid this. !!
+** items relocated from libc/hurd/STATUS:
+*** We are not sure about possible races between setpgrp (A, pgrp) from
+ process B vs process A receiving proc_newids.
+*** does sigaltstack/sigstack really work? -- NO
+*** hurdmalloc kludge
+*** think more about environment variable use viz security
+*** SIGINFO handler?
+*** itimers could be implemented better
+*** mmap cannot do MAP_NOEXTEND.
+*** unimplemented calls(?)
+ acct
+ getfh
+ getfsstat
+ madvise
+ mincore
+ mount
+ msync
+ sstk
+ swapon
+ unmount
+
** libports:
*** Get rid of general `uninibited-rpcs' mechanism in libports, & just
- special-case interrupt_operation.
-*** Drop wire parms to manage-operations; instead have a new-thread hook
- function.
-*** Add ports_create_port_noinstall to ports.h.
+ special-case interrupt_operation. !
** libstore:
-*** test it and make diskfs use it.
+*** Add lock protocol for mutable stores.
+*** Creating/opening stores with STORE_INACTIVE should work (and then the hack
+ in storeio/dev.c should be removed).
** libfsserver/libnetfs:
*** convert libnetfs to libfsserver
** libnetfs
-*** Support --readonly, --writable, and --update
+*** Support --readonly, --writable, and --update !
+*** Implement dir_reparent.
** libpager:
-*** Put user-defined fns into a callback struct passed to pager_create.
+*** Put user-defined fns into a callback struct passed to pager_create. !
*** Make libpager paging interface able to read/write multiple pages at once.
-*** Check all users of pager-create.c to make sure they DTRT when it returns
- null.
+*** Remove pagers from portset if there are too many incoming requests to
+ avoid forking too many threads. !
+*** flush functions don't actually force pending delayed copies. (and in
+ fact, they seem to block if a delayed copy is wired down) !
** libshouldbeinlibc:
*** Merge contents of libshouldbeinlibc that belong there into libc.
Rename the rest to libhurdutil or somesuch.
-*** argp: finde some way to flag certain long options as only matching
- exactly (add this as OPT_EXACT); use this on the built in option
- --program-name.
-*** Rewrite argp to do its own parsing. Preferably, split up libc's
- getopt into more primitive functions, which both argp and getopt
- can call.
-
** libdiskfs
-*** detect write-protected media and turn on diskfs_readonly
+*** file_chflags does not do proper permission checking (non-root isn't
+ supposed to be able to change the low bits)
*** Add the short-circuited-but-not-builtin translator startup code from
dir-lookup to fsys_getroot. Compare and match carefully these two
routines and then share common code.
-*** Handle dead name notifications on execserver ports.
+*** Implement Posix O_SYNC, O_DSYNC, and O_RSYNC under the right
+ names; change libc header to match current Posix.
+*** Handle dead name notifications on execserver ports. !
*** Deal correctly with setting the translators on /servers/exec.
*** Implement file_notice_changes.
-*** Implement async I/O.
+*** Implement async I/O. !
*** Think of a way to have when-to-sync-nodes be more flexible so it can
be done right for each format.
-*** Check when-to-sync-nodes carefully against BSD 4.4 ufs implementation.
-*** Provide for MNT_SYNCHRONOUS, MNT_NOEXEC, MNT_NOSUID, MNT_NODEV, etc.
-*** Implement io_restrict_auth correctly.
-*** Use libstore.
-*** Use off_t correctly.
+*** Check when-to-sync-nodes carefully against BSD 4.4 ufs implementation. !
+*** Provide for MNT_NODEV, etc. !
+*** Implement io_restrict_auth correctly. !
+*** Use off_t correctly. !!
*** Add a consistent message printing facility for filesystems to use
- (syslog, but takes special care when the root file system?).
-*** Some of diskfs_readonly_changed in ufs/ext2fs should be in generic
- routines.
-*** fsys_get_options should return the disk name.
+ (syslog, but takes special care when the root file system?). !!
+*** Some of diskfs_readonly_changed in ufs/ext2fs should be in generic
+ routines. !
** libfshelp
-*** Put functions here to deal with directory and file change notifications?
-*** Translator startup should provide a more useful stdin/stdout than nothing?
-*** Add functions to do permission checking and change libdiskfs et. al.
- to use them.
-
-** libpager
-*** Change interface to be more efficient with multi-page data-return calls.
-*** Remove pagers from portset if there are too many incoming requests to
- avoid forking too many threads.
-*** flush functions don't actually force pending delayed copies. (and in
- fact, they seem to block if a delayed copy is wired down)
+*** Put functions here to deal with directory and file change notifications !!!
+*** Translator startup should provide a more useful stdin/stdout than nothing !
** libtrivfs
*** Allow for read/write/exec to be passed down.
-*** Implement file_exec when appropriate.
+*** Implement file_exec when appropriate. !!
*** Provide for the visible owner, etc., to be held in command-line args
- instead of the underlying node, when it's important.
+ instead of the underlying node, when it's important. !!
** libps
-*** Wizzior columnation (autosizing?)
+*** Add option to print values times with a delay,
+ and to print values relative to last printing.
+*** Whizzier columnation (autosizing?)
*** Make getters more robust.
-
* Servers
-** write default pager
-** Implement goaway in all the servers that don't already have it.
-** (init) sleep on spinning gettys
+** finish default pager in defpager !!
+** Implement goaway in all the servers that don't already have it. !!
+** (init) sleep on spinning gettys !
** Add calls to various servers to return interesting statistical information.
-** Test new-fifo & make it fifo.
+** Test new-fifo & make it fifo. !
** Login/utmp?
** fifos are flaky. ?? Details ??
-** pflocal: make peer addresses work?
+** implement io_revoke for things in trans/ that need it. !
+
+** pflocal
+*** make peer addresses work?
+*** implement io_revoke on sockets !
+
+** term:
+*** find a way to reduce duplicate signals from repeated VINTR input
+*** when a session leader exits, netbsd SIGHUP's the terminal, drains output,
+ and then revokes it. (See Posix.1-1996, p. 184, l. 64-68.)
+*** when a session leader sets the ospeed to 0, netbsd SIGHUP's the termianl.
+*** enforce session leader / controlling terminal uniqueness rules. !
+ (1: if a terminal is matched to a session, then another session
+ can't make it its controlling terminal;
+ 2: tcsetpgrp to a pgrp that's not in the right sessions must
+ fail;
+ 3: when a session leader exits, the association has to be torn
+ down; bsd does SIGHUP + drain + revoke.)
+
+** exec:
+*** either resurrect or excise BFD exec server
+ (needs stdio magic converted to use libio when libc converts)
** proc:
*** Add a version of proc_wait usable by non-parent processes, and use it in
gdb; maybe just a flag WNOREAP to proc_wait that doesn't reap and allows
- anyone to use it.
+ anyone to use it. !!
*** Add proc_get_tty() [returns tty opened with no flags], so that ps can be
- non-suid.
-*** Remove hostname/hostid functions
-*** add timeouts to all the msg_* calls proc makes.
+ non-suid. !
+*** add timeouts to all the msg_* calls proc makes. !
** pfinet
*** Allow multiple pfinets to arp on the same ethernet interface for different
- IP addresses.
-*** Register a shutdown notification to close TCP channels.
+ IP addresses. !!
+*** Diagnose why shutdown doesn't close TCP channels properly or reliably. !
+*** select for read on a UDP socket seems never to return. !!!
+*** Undefined functions at the end of pfinet/io-ops.c. !!
+*** Implement io_revoke on sockets. !
+*** Implement SO_LINGER correctly (close() should return EWOULDBLOCK if not all
+ packets could be delivered). !
** nfs
-*** Implement async I/O
-*** Finish work to turn on paging.
-*** Finish excl arg work in link and rename.
-
-** devio:
-*** Make a server (/servers/devio?) to share multiple devio nodes?
-*** Use libstore.
-*** Make block devices work again.
-*** MAKEDEV should be able to make physical terminal devs.
-*** Get rid of global DEVICE variable and use the trivfs control hack.
+*** Implement async I/O !!
+*** Finish work to turn on paging. !!
+*** Implement TCP nfs. !
+*** Implement V3 nfs.
+*** Implement nqnfs. !
+*** Add Hurd-specific calls. !!
+*** errors in mount_root should get reflected more usefully to users. !
+
+** storeio:
+*** Make a server (/servers/storeio?) to share multiple storeio nodes
*** Serverify, ala new-fifo.
+*** implement io_revoke !
** ufs:
*** Implement clustering, a la 4.4-lite sys/kern/vfs_cluster.c.
-*** Make file_get_storage_info work for files with indirect blocks.
+*** Make file_get_storage_info work for files with indirect blocks. !!
*** Optimizations:
- pager.c/inode.c/libdiskfs count pager refs separately and then save
- mappings in _diskfs_rdwr_internal and dir.c
-*** Problems with DT_* hack:
+ pager.c/inode.c/libdiskfs count pager refs separately and then
+ save mappings in _diskfs_rdwr_internal and dir.c !
+*** Problems with DT_* hack: !
**** Fix multiple-links DT_* bug.
**** Deal with change of type which should update directory.
**** Type is also wrong for translated nodes...
-*** Roland sez: ENOSPC detection flaky in ufs. Try write of >page,
- non-page-multiple, when free space allows write size but not
+*** Roland sez: ENOSPC detection flaky in ufs. Try write of >page,
+ non-page-multiple, when free space allows write size but not
round_page (write size).
** ext2fs
-*** Support chflags/st_flags and convert to/from ext2 flags on disk.
-*** Try to write directories with 512-byte record boundaries.
-*** Maybe file_pager_write_page should be able to accurately reproduce holes...
-*** Add byte-swapping.
-
-** crash
-*** Write core files.
+*** Try to write directories with 512-byte record boundaries. !!
+*** Maybe file_pager_write_page should be able to accurately reproduce holes
+*** Add byte-swapping. !!
+*** If the target of a symlink is the empty string, stat seems to spin forever !!!
-** init
-*** SIGHUP and SIGQUIT don't seem to do the right thing.
+** arla -- port it
* Utilities
-** Write a real mount program.
-** settrans needs an option to make the active go away without using goaway.
-** Make id, et. al. work with no/multiple uids.
-** Make things work with the `nobody' mode bits: chmod, ls, ...
-** Make things work better with translators, e.g., tar...
+** Make id, et. al. work with no/multiple uids. !!!
+** Make things work with the `nobody' mode bits: chmod, ls, ... !
+** Make things work with filesystem extensions (author, etc.): ls!!!
+** Make things work better with translators, e.g., tar... !!!
** Fix bash to turn on interrupts around syscalls more generally,
- especially chdir.
-** Make su work.
-** Bug: `hostname' command with no /etc/hostname hangs the system with disk light going.
-** talk doesn't work
+ especially chdir. !!
+** talk doesn't work !!
** login: Make --retry work correctly when invoked via a suid shell
script by other than root (it doesn't now if the script specifies
--retry="$0" because the exec server will use /dev/fd/N for name,
- and child_lookup() doesn't supply more than fds 0-2).
-** fsck should use (not-yet-added) fsys_get_options returned device instead
- of /etc/fstab.
+ and child_lookup() doesn't supply more than fds 0-2). !!
+** Make w use utmp's tty instead of the process's
+** fsck:
+*** fsck should use fsys_get_options returned device instead of /etc/fstab !!
+
+** settrans:
+*** needs an option to make the active go away without using goaway. !
** ps:
-*** ps should timeout quickly (one second?) on non-responsive message ports.
+*** ps should timeout quickly (one second?) on non-responsive message ports. !
*** help displays for: stat letters, format specs.
-*** Add head/tail options; --match?
+*** --match option?
+*** fetch and print task (and thread?) startup times.
** gdb:
-*** Add various mach convenience features (vminfo, &c).
+*** Add various mach convenience features (vminfo, &c). !!
*** Be even more vigilant about noticing new threads. In particular:
-**** For mach-indep thread commands, before validating against
- internal thread list.
-*** read core files
-
-** nfsd -- fix remaining bugs
-*** Add necessary support to filesystems
-
-** fsck.ufs -- zero-length directories and attachment into lost+found still
- don't work.
-
-
+**** For mach-indep thread commands, before validating against
+ internal thread list. !!!
+*** read core files !!
+*** Gdb doesn't work right if it doesn't have permission to frob the
+ inferior process (for instance, if it's a set[ug]id program), but
+ doesn't give a meaningful error message. Try `break main' in /bin/login.
+
+** nfsd
+*** Implement TCP nfs. !
+*** Implement V3 nfs. !
+*** Implement nqnfs. !
+*** Add Hurd-specific calls. !!
+*** writes don't seem to work properly !!!
+*** Report statfs correctly. !!
* Mach:
-** Have some analogue of /dev/klog that syslogd can get kernel messages from
- (maybe there is already?); the boot file system, and other people deeming
- it too risk to attempt to contact syslogd can use it too?
-** Add a startup timestamp to tasks, and have some way of fetching it.
-
-
-* TODO for version 0.0:
-
-** Compile released libc.
-** Make the release version of SOURCES.
+** Have the at-close actions on devices be more directly controllable
+ by users by deleting the current at-close actions and replacing
+ them with suitable device_set_status calls.
+** Specify and implement vm_remap.
+
+======
+
+???
+ [I'm not sure of the preconditions for this; it usually seems to happen to
+ new login shells (but not often enough to really get a handle on it).
+ If the command is repeated, then it usually works correctly.]
+ login> ps aux|head
+ bash: /bin/head: (ipc/send) invalid msg-header
+ Broken pipe
+ [bash only seems to print error messages in this particular format if an
+ execve fails]
+
+ I've also had it happen in shells that have been around a while. -thomas
+
+ I just saw it happen in make output; there the particular error
+ happens only when execvp fails. -thomas
+???
+
+* Next release:
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 00000000..2e615504
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,82 @@
+dnl These modifications are to allow for an empty cross compiler tree.
+dnl In the situation that cross-linking is impossible, the variable
+dnl `cross_linkable' will be substituted with "yes".
+
+dnl
+AC_DEFUN([hurd_MIG_RETCODE], [dnl
+# See if mig groks `retcode'.
+AC_CACHE_CHECK(whether $MIG supports the retcode keyword, hurd_cv_mig_retcode,
+[cat > conftest.defs <<\EOF
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+subsystem foobar 1000;
+type reply_port_t = polymorphic | MACH_MSG_TYPE_PORT_SEND_ONCE
+ ctype: mach_port_t;
+simpleroutine foobar_reply (
+ reply_port: reply_port_t;
+ err: kern_return_t, RetCode);
+EOF
+if AC_TRY_COMMAND([CC="${CC}" ${MIG-false} -n conftest.defs 1>&AS_MESSAGE_LOG_FD()]); then
+ hurd_cv_mig_retcode=yes
+else
+ hurd_cv_mig_retcode=no
+fi
+rm -f conftest*])
+if test $hurd_cv_mig_retcode = yes; then
+ AC_DEFINE(HAVE_MIG_RETCODE)
+fi])
+
+dnl The following check is based on a similar check in GNU inetutils 1.4.0.
+dnl
+dnl hurd_LIB_NCURSESW -- check for, and configure, ncursesw
+dnl
+dnl If libncursesw is found to exist on this system and the --disable-ncursesw
+dnl flag wasn't specified, defines LIBNCURSESW with the appropriate linker
+dnl specification, and possibly defines NCURSESW_INCLUDE with the appropriate
+dnl -I flag to get access to ncursesw include files.
+dnl
+AC_DEFUN([hurd_LIB_NCURSESW], [
+ AC_ARG_ENABLE(ncursesw, [ --disable-ncursesw Do not use ncursesw],
+ , enable_ncursesw=yes)
+ if test "$enable_ncursesw" = yes; then
+ AC_CHECK_LIB(ncursesw, initscr, LIBNCURSESW="-lncursesw")
+ if test "$LIBNCURSESW"; then
+ AC_ARG_WITH(ncursesw-include-dir,
+[ --with-ncursesw-include-dir=DIR
+ Set directory containing the include files for
+ use with -lncursesw, when it isn't installed as
+ the default curses library. If DIR is "none",
+ then no special ncursesw include files are used.
+ --without-ncursesw-include-dir
+ Equivalent to --with-ncursesw-include-dir=none])dnl
+ if test "${with_ncursesw_include_dir+set}" = set; then
+ AC_MSG_CHECKING(for ncursesw include dir)
+ case "$with_ncursesw_include_dir" in
+ no|none)
+ hurd_cv_includedir_ncursesw=none;;
+ *)
+ hurd_cv_includedir_ncursesw="$with_ncursesw_include_dir";;
+ esac
+ AC_MSG_RESULT($hurd_cv_includedir_ncursesw)
+ else
+ AC_CACHE_CHECK(for ncursesw include dir,
+ hurd_cv_includedir_ncursesw,
+ for D in $includedir $prefix/include /local/include /usr/local/include /include /usr/include; do
+ if test -d $D/ncursesw; then
+ hurd_cv_includedir_ncursesw="$D/ncursesw"
+ break
+ fi
+ test "$hurd_cv_includedir_ncursesw" \
+ || hurd_cv_includedir_ncursesw=none
+ done)
+ fi
+ if test "$hurd_cv_includedir_ncursesw" = none; then
+ NCURSESW_INCLUDE=""
+ else
+ NCURSESW_INCLUDE="-I$hurd_cv_includedir_ncursesw"
+ fi
+ fi
+ fi
+ AC_SUBST(NCURSESW_INCLUDE)
+ AC_SUBST(LIBNCURSESW)])dnl
+
diff --git a/auth/ChangeLog b/auth/ChangeLog
deleted file mode 100644
index 2f82a470..00000000
--- a/auth/ChangeLog
+++ /dev/null
@@ -1,148 +0,0 @@
-Fri Jul 19 00:35:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * auth.c (S_auth_makeauth): Deallocate initial reference to
- NEWAUTH after *NEWHANDLE has been set.
-
-Thu Jul 18 19:31:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * auth.c (S_auth_makeauth): It's fine if a passed in auth port is
- not one we know about; just make the loops across AUTHS deal
- properly with null values. Only deallocate the AUTHPTS passed in
- if we don't encounter any errors. Always deallocate the
- references in the AUTHS array. ISUID and GROUPMEMBER functions
- should check both effective and auxiliary members of AUTH.
- (struct pending): Delete member `passthrough_type'.
- (S_auth_user_authenticate): Always use MOVE_SEND to send pass
- through port back to user.
- (S_auth_server_authenticate): Don't bother initializing
- U.passthrough_type or S.passthrough_type.
-
-Sat Jul 6 23:16:42 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * auth.c (AUTH_VERSION): New macro.
- (argp_program_version): New variable.
- (auth_version): Variable removed.
- (main): Call argp_parse to get defaults.
- Use AUTH_VERSION instead of auth_version.
- <argp.h>: New include.
- <idvec.h>: Changed from <hurd/idvec.h>.
-
-Wed Jun 26 14:22:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * auth.c (S_auth_makeauth): Don't special-case the 0 explicit ids
- case (it used to merge in all the ids from passed in auth-handles
- in that case).
-
-Mon May 6 14:22:13 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * auth.c (auth_version): Upgrade to 0.0.
-
-Sat May 4 22:40:42 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * auth.c (S_auth_user_authenticate, S_auth_server_authenticate):
- Use ports_interrupt_self_on_port_death instead of
- cancel_on_dead_name. Hurd_condition_wait returns a boolean, not
- an error_t, so supply EINTR ourselves.
- (cancel_on_dead_name): Function removed.
-
-Fri May 3 17:07:45 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * auth.c (S_auth_server_authenticate, S_auth_user_authenticate):
- Remove IGNORED arg.
-
-Tue Apr 30 21:16:07 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * auth.c (S_auth_makeauth): Increment NAUTHS for first elt.
- (main): Initialize the ihash tables, dammit.
-
-Thu Apr 25 02:57:53 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * auth.c: Rewritten.
- * authmutations.h: New file.
- * Makefile (LCLHDRS): Add it, remove auth_mig.h.
- (OBJS): Remove auth_replyUser.o, notifyServer.o.
- (auth): Depend on libports, libihash, libthreads, libshouldbeinlibc.
-
- * auth_mig.h: Rewritten.
- * Makefile (OBJS): Add auth_replyUser.o.
-
-Thu Jul 6 15:29:43 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Fri Nov 18 07:34:11 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Add notifyServer.o.
- (auth.o): Depend on notify_S.h.
- * auth.c: Include "notify_S.h". Remove _S_ from all
- do_mach_notify_* server routines.
-
-Wed Sep 7 13:14:41 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * auth.c (isuid): Look for TEST in the uid arrays, not the gid arrays.
-
-Tue Sep 6 14:33:02 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * auth.c (auth_nosenders): Remove auth struct from allapts
- list correctly.
-
-Thu Aug 25 13:24:24 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * auth.c (struct saved_user): Use second rendezvous port in place
- of rend_int.
- (strut saved_server): Likewise.
- (S_auth_user_authenticate): Replace int arg with secondary
- rendezvous port. Check it instead of old rend_int for match.
- Deallocate it (twice) if we are completing the auth transaction
- here. Store it in U in place of the old int.
- (S_auth_server_authenticate): Likewise, mutatis mutandis.
-
-Mon Aug 15 11:52:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * auth.c (main): Make startup_essential_task the last thing we
- do before processing messages.
-
-Thu Jul 21 18:39:38 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
- * auth.c: Include "auth_reply_U.h" instead of "auth_reply.h".
-
-Tue Jul 19 12:32:54 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (auth): Don't use variable $(link) anymore.
-
-Tue Jul 5 14:18:23 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (SRCS, TAGSHDRS): New variables.
-
-Mon Jun 20 15:04:42 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (install): Use $(INSTALL_BIN) instead of cp.
-
-Thu May 19 15:18:52 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * auth.c (auth_nosenders): Take auth off of allapts list
- before destroying it.
-
-Thu May 12 15:28:50 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * auth.c (main): Declare args ARGC and ARGV; pass ARGV in call
- to _hurd_proc_init.
-
-Mon May 9 16:50:09 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * auth.c (auth_version): New variable.
- (main): Call proc_register_version.
-
-Thu May 5 07:42:28 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
-Fri Apr 29 16:50:50 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * auth.c (main): Fetch hostpriv arg and provide it to
- startup_essential_task in accord with interface change to
- startup.defs.
-
-
diff --git a/auth/Makefile b/auth/Makefile
index 74eb135d..da7f8e23 100644
--- a/auth/Makefile
+++ b/auth/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1991, 93, 94, 95, 96 Free Software Foundation, Inc.
+# Copyright (C) 1991, 93, 94, 95, 96, 2000 Free Software Foundation, Inc.
# This file is part of the GNU Hurd.
#
# The GNU Hurd is free software; you can redistribute it and/or modify
@@ -22,10 +22,9 @@ SRCS = auth.c
OBJS = auth.o authServer.o auth_replyUser.o
LCLHDRS = authmutations.h auth_mig.h
target = auth
+HURDLIBS = threads ports ihash shouldbeinlibc
MIGSFLAGS = -imacros $(srcdir)/authmutations.h
include ../Makeconf
-auth: ../libports/libports.so ../libthreads/libthreads.so \
- ../libihash/libihash.so ../libshouldbeinlibc/libshouldbeinlibc.so
diff --git a/auth/auth.c b/auth/auth.c
index d77c484e..11db0f8f 100644
--- a/auth/auth.c
+++ b/auth/auth.c
@@ -1,5 +1,5 @@
/* Authentication server.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,98,99,2002 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -18,6 +18,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <mach.h>
@@ -29,12 +30,13 @@
#include <idvec.h>
#include <assert.h>
#include <argp.h>
+#include <error.h>
+#include <version.h>
#include "auth_S.h"
#include "auth_reply_U.h"
-#define AUTH_VERSION "0.0"
+const char *argp_program_version = STANDARD_HURD_VERSION(auth);
-char *argp_program_version = "auth " AUTH_VERSION " (GNU " HURD_RELEASE ")";
/* Auth handles are server ports with sets of ids. */
struct authhandle
@@ -81,7 +83,8 @@ auth_port_to_handle (auth_t auth)
/* id management. */
-inline void idvec_copyout (struct idvec *idvec, uid_t **ids, uid_t *nids)
+static inline void
+idvec_copyout (struct idvec *idvec, uid_t **ids, size_t *nids)
{
if (idvec->num > *nids)
*ids = idvec->ids;
@@ -98,13 +101,13 @@ inline void idvec_copyout (struct idvec *idvec, uid_t **ids, uid_t *nids)
kern_return_t
S_auth_getids (struct authhandle *auth,
uid_t **euids,
- u_int *neuids,
+ size_t *neuids,
uid_t **auids,
- u_int *nauids,
+ size_t *nauids,
uid_t **egids,
- u_int *negids,
+ size_t *negids,
uid_t **agids,
- u_int *nagids)
+ size_t *nagids)
{
if (! auth)
return EOPNOTSUPP;
@@ -117,17 +120,17 @@ S_auth_getids (struct authhandle *auth,
/* Implement auth_makeauth as described in <hurd/auth.defs>. */
kern_return_t
S_auth_makeauth (struct authhandle *auth,
- mach_port_t *authpts, u_int nauths,
- uid_t *euids, u_int neuids,
- uid_t *auids, u_int nauids,
- uid_t *egids, u_int negids,
- uid_t *agids, u_int nagids,
+ mach_port_t *authpts, size_t nauths,
+ uid_t *euids, size_t neuids,
+ uid_t *auids, size_t nauids,
+ uid_t *egids, size_t negids,
+ uid_t *agids, size_t nagids,
mach_port_t *newhandle)
{
struct authhandle *newauth, *auths[1 + nauths];
int hasroot = 0;
error_t err;
- u_int i, j;
+ size_t i, j;
if (!auth)
return EOPNOTSUPP;
@@ -137,7 +140,7 @@ S_auth_makeauth (struct authhandle *auth,
/* Fetch the auth structures for all the ports passed in. */
for (i = 0; i < nauths; i++)
auths[i + 1] = auth_port_to_handle (authpts[i]);
-
+
++nauths;
/* Verify that the union of the handles passed in either contains euid 0
@@ -248,15 +251,22 @@ S_auth_makeauth (struct authhandle *auth,
/* Transaction handling. */
-/* Table of pending transactions keyed on RENDEZVOUS. */
-struct ihash *pending_users, *pending_servers;
-struct mutex pending_lock = MUTEX_INITIALIZER;
-
-/* A pending transaction. */
-struct pending
+/* Since the user is responsible for freeing the rendezvous port, it has to
+ * wait for the server to have finished transmitting uids.
+ *
+ * The server thus waits for the user to give it uids (unless it was already
+ * there), transmits them and provides the passthrough port.
+ *
+ * The user gives the uids and waits for the passthrough port from the server.
+ *
+ * If the user is early, it has to tell the server it arrived.
+ */
+
+/* A pending user. */
+struct pending_user
{
- void **locp; /* Position in one of the ihash tables. */
- struct condition wakeup; /* The waiter is blocked on this condition. */
+ hurd_ihash_locp_t locp; /* Position in the pending_users ihash table. */
+ struct condition wakeup; /* The reader is blocked on this condition. */
/* The user's auth handle. */
struct authhandle *user;
@@ -265,76 +275,87 @@ struct pending
mach_port_t passthrough;
};
+/* A pending server. */
+struct pending_server
+ {
+ hurd_ihash_locp_t locp; /* Position in the pending_servers ihash table. */
+ struct condition wakeup; /* The server is blocked on this condition. */
+ };
+
+/* Table of pending transactions keyed on RENDEZVOUS. */
+struct hurd_ihash pending_users
+ = HURD_IHASH_INITIALIZER (offsetof (struct pending_user, locp));
+struct hurd_ihash pending_servers
+ = HURD_IHASH_INITIALIZER (offsetof (struct pending_server, locp));
+struct mutex pending_lock = MUTEX_INITIALIZER;
+
/* Implement auth_user_authenticate as described in <hurd/auth.defs>. */
kern_return_t
S_auth_user_authenticate (struct authhandle *userauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
mach_port_t rendezvous,
mach_port_t *newport,
mach_msg_type_name_t *newporttype)
{
- struct pending *s;
+ struct pending_server *s;
+ struct pending_user u;
+ error_t err;
if (! userauth)
return EOPNOTSUPP;
- mutex_lock (&pending_lock);
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
- /* Look for this port in the server list. */
- s = ihash_find (pending_servers, rendezvous);
- if (s)
- {
- /* Found it! Extract the port. */
- *newport = s->passthrough;
- *newporttype = MACH_MSG_TYPE_MOVE_SEND;
+ u.user = userauth;
+ condition_init (&u.wakeup);
- /* Remove it from the pending list. */
- ihash_locp_remove (pending_servers, s->locp);
+ mutex_lock (&pending_lock);
- /* Give the server the auth port and wake the RPC up.
- We need to add a ref in case the port dies. */
- s->user = userauth;
- ports_port_ref (userauth);
+ err = hurd_ihash_add (&pending_users, rendezvous, &u);
+ if (err) {
+ mutex_unlock (&pending_lock);
+ return err;
+ }
+
+ /* Give the server the auth port.
+ We need to add a ref in case the port dies. */
+ ports_port_ref (userauth);
+
+ /* Look for this rendezvous in the server list. */
+ s = hurd_ihash_find (&pending_servers, rendezvous);
+ if (s) {
+ /* Found it! */
+
+ /* Remove it from the pending list. */
+ hurd_ihash_locp_remove (&pending_servers, s->locp);
+
+ /* Tell it we eventually arrived. */
+ condition_signal (&s->wakeup);
+ }
+
+ ports_interrupt_self_on_port_death (userauth, rendezvous);
+ /* Wait for server answer. */
+ if (hurd_condition_wait (&u.wakeup, &pending_lock) &&
+ hurd_ihash_find (&pending_users, rendezvous))
+ /* We were interrupted; remove our record. */
+ {
+ hurd_ihash_locp_remove (&pending_users, u.locp);
+ err = EINTR;
+ }
- condition_signal (&s->wakeup);
- mutex_unlock (&pending_lock);
+ mutex_unlock (&pending_lock);
+ if (! err)
+ {
+ /* Extract the port. */
+ *newport = u.passthrough;
+ *newporttype = MACH_MSG_TYPE_MOVE_SEND;
mach_port_deallocate (mach_task_self (), rendezvous);
- return 0;
}
- else
- {
- /* No pending server RPC for this port.
- Create a pending user RPC record. */
- struct pending u;
- error_t err;
- err = ihash_add (pending_users, rendezvous, &u, &u.locp);
- if (! err)
- {
- /* Store the user auth port and wait for the server RPC to wake
- us up. */
- u.user = userauth;
- condition_init (&u.wakeup);
- ports_interrupt_self_on_port_death (userauth, rendezvous);
- if (hurd_condition_wait (&u.wakeup, &pending_lock))
- /* We were interrupted; remove our record. */
- {
- ihash_locp_remove (pending_users, u.locp);
- err = EINTR;
- }
- }
- /* The server side has already removed U from the ihash table. */
- mutex_unlock (&pending_lock);
-
- if (! err)
- {
- /* The server RPC has set the port and signalled U.wakeup. */
- *newport = u.passthrough;
- *newporttype = MACH_MSG_TYPE_MOVE_SEND;
- mach_port_deallocate (mach_task_self (), rendezvous);
- }
- return err;
- }
+ return err;
}
/* Implement auth_server_authenticate as described in <hurd/auth.defs>. */
@@ -346,79 +367,89 @@ S_auth_server_authenticate (struct authhandle *serverauth,
mach_port_t newport,
mach_msg_type_name_t newport_type,
uid_t **euids,
- u_int *neuids,
+ size_t *neuids,
uid_t **auids,
- u_int *nauids,
+ size_t *nauids,
uid_t **egids,
- u_int *negids,
+ size_t *negids,
uid_t **agids,
- u_int *nagids)
+ size_t *nagids)
{
- struct pending *u;
+ struct pending_user *u;
struct authhandle *user;
+ error_t err;
if (! serverauth)
return EOPNOTSUPP;
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
+
mutex_lock (&pending_lock);
- /* Look for this port in the user list. */
- u = ihash_find (pending_users, rendezvous);
+ /* Look for this rendezvous in the user list. */
+ u = hurd_ihash_find (&pending_users, rendezvous);
+ if (! u)
+ {
+ /* User not here yet, have to wait for it. */
+ struct pending_server s;
+ condition_init (&s.wakeup);
+ err = hurd_ihash_add (&pending_servers, rendezvous, &s);
+ if (! err)
+ {
+ ports_interrupt_self_on_port_death (serverauth, rendezvous);
+ if (hurd_condition_wait (&s.wakeup, &pending_lock) &&
+ hurd_ihash_find (&pending_servers, rendezvous))
+ /* We were interrupted; remove our record. */
+ {
+ hurd_ihash_locp_remove (&pending_servers, s.locp);
+ err = EINTR;
+ }
+ else
+ {
+ u = hurd_ihash_find (&pending_users, rendezvous);
+ if (! u)
+ /* User still not here, odd! */
+ err = EINTR;
+ }
+ }
+ }
+
if (u)
{
+ error_t err2;
+
/* Remove it from the pending list. */
- ihash_locp_remove (pending_users, u->locp);
+ hurd_ihash_locp_remove (&pending_users, u->locp);
- /* Found it! We must add a ref because the one held by the
- user RPC might die as soon as we unlock pending_lock. */
+ /* Found it! */
user = u->user;
- ports_port_ref (user);
+
+ mutex_unlock (&pending_lock);
+
+ /* Tell third party. */
+ err2 = auth_server_authenticate_reply (reply, reply_type, 0,
+ user->euids.ids, user->euids.num,
+ user->auids.ids, user->auids.num,
+ user->egids.ids, user->egids.num,
+ user->agids.ids, user->agids.num);
+
+ if (err2)
+ mach_port_deallocate (mach_task_self (), reply);
+
+ mutex_lock (&pending_lock);
/* Give the user the new port and wake the RPC up. */
u->passthrough = newport;
condition_signal (&u->wakeup);
- mutex_unlock (&pending_lock);
}
- else
- {
- /* No pending user RPC for this port.
- Create a pending server RPC record. */
- struct pending s;
- error_t err;
-
- err = ihash_add (pending_servers, rendezvous, &s, &s.locp);
- if (! err)
- {
- /* Store the new port and wait for the user RPC to wake us up. */
- s.passthrough = newport;
- condition_init (&s.wakeup);
- ports_interrupt_self_on_port_death (serverauth, rendezvous);
- if (hurd_condition_wait (&s.wakeup, &pending_lock))
- /* We were interrupted; remove our record. */
- {
- ihash_locp_remove (pending_servers, s.locp);
- err = EINTR;
- }
- }
- /* The user side has already removed S from the ihash table. */
- mutex_unlock (&pending_lock);
- if (err)
- return err;
+ mutex_unlock (&pending_lock);
- /* The user RPC has set the port (with a ref) and signalled S.wakeup. */
- user = s.user;
- }
+ if (err)
+ return err;
- /* Extract the ids. We must use a separate reply stub so
- we can deref the user auth handle after the reply uses its
- contents. */
- auth_server_authenticate_reply (reply, reply_type, 0,
- user->euids.ids, user->euids.num,
- user->auids.ids, user->auids.num,
- user->egids.ids, user->egids.num,
- user->agids.ids, user->agids.num);
ports_port_deref (user);
mach_port_deallocate (mach_task_self (), rendezvous);
return MIG_NO_REPLY;
@@ -444,8 +475,9 @@ main (int argc, char **argv)
process_t proc;
mach_port_t hostpriv, masterdev;
struct authhandle *firstauth;
+ struct argp argp = { 0, 0, 0, "Hurd standard authentication server." };
- argp_parse (0, argc, argv, 0, 0, 0);
+ argp_parse (&argp, argc, argv, 0, 0, 0);
auth_bucket = ports_create_bucket ();
authhandle_portclass = ports_create_class (&destroy_authhandle, 0);
@@ -460,16 +492,21 @@ main (int argc, char **argv)
idvec_merge (&firstauth->agids, &firstauth->auids);
/* Fetch our bootstrap port and contact the bootstrap filesystem. */
- task_get_bootstrap_port (mach_task_self (), &boot);
- startup_authinit (boot, ports_get_right (firstauth),
- MACH_MSG_TYPE_MAKE_SEND, &proc);
+ err = task_get_bootstrap_port (mach_task_self (), &boot);
+ assert_perror (err);
+ if (boot == MACH_PORT_NULL)
+ error (2, 0, "auth server can only be run by init during boot");
+ err = startup_authinit (boot, ports_get_right (firstauth),
+ MACH_MSG_TYPE_MAKE_SEND, &proc);
+ if (err)
+ error (2, err, "cannot contact init for bootstrap");
/* Register ourselves with the proc server and then start signals. */
proc_getprivports (proc, &hostpriv, &masterdev);
- proc_register_version (proc, hostpriv, "auth", HURD_RELEASE, AUTH_VERSION);
+ proc_register_version (proc, hostpriv, "auth", "", HURD_VERSION);
mach_port_deallocate (mach_task_self (), masterdev);
_hurd_port_set (&_hurd_ports[INIT_PORT_PROC], proc);
- _hurd_proc_init (argv);
+ _hurd_proc_init (argv, NULL, 0);
/* Init knows intimately that we will be ready for messages
as soon as this returns. */
@@ -478,16 +515,9 @@ main (int argc, char **argv)
mach_port_deallocate (mach_task_self (), boot);
mach_port_deallocate (mach_task_self (), hostpriv);
- /* Allocate the hash tables. */
- err = ihash_create (&pending_users);
- assert_perror (err);
- err = ihash_create (&pending_servers);
- assert_perror (err);
-
/* Be a server. */
while (1)
ports_manage_port_operations_multithread (auth_bucket,
auth_demuxer,
- 30 * 1000, 0,
- 0, MACH_PORT_NULL);
+ 30 * 1000, 0, 0);
}
diff --git a/benchmarks/ChangeLog b/benchmarks/ChangeLog
deleted file mode 100644
index a46fe1e8..00000000
--- a/benchmarks/ChangeLog
+++ /dev/null
@@ -1,9 +0,0 @@
-Wed Apr 12 11:25:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (OBJS): New var.
-
-Tue Apr 11 11:17:32 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Rewrote in accordance with new scheme.
-
-
diff --git a/benchmarks/forks.c b/benchmarks/forks.c
index 2bb98a88..ed8e53e1 100644
--- a/benchmarks/forks.c
+++ b/benchmarks/forks.c
@@ -1,5 +1,11 @@
/* From 4.4 BSD sys/tests/benchmarks/forks.c. */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/wait.h>
+
/*
* Benchmark program to calculate fork+wait
* overhead (approximately). Process
@@ -8,15 +14,17 @@
* in calculating exec overhead.
*/
+int
main(argc, argv)
+ int argc;
char *argv[];
{
register int nforks, i;
char *cp;
int pid, child, status, brksize;
- int starttime, endtime;
+ time_t starttime, endtime;
- if (argc < 2) {
+ if (argc < 3) {
printf("usage: %s number-of-forks sbrk-size\n", argv[0]);
exit(1);
}
@@ -30,10 +38,10 @@ main(argc, argv)
printf("%s: bad size to sbrk\n", argv[2]);
exit(3);
}
-
+
time (&starttime);
cp = (char *)sbrk(brksize);
- if ((int)cp == -1) {
+ if (cp == (void *)-1) {
perror("sbrk");
exit(4);
}
@@ -51,6 +59,6 @@ main(argc, argv)
;
}
time (&endtime);
- printf ("Time: %d seconds.\n", endtime - starttime);
+ printf ("Time: %d seconds.\n", (int) (endtime - starttime));
exit(0);
}
diff --git a/boot/ChangeLog b/boot/ChangeLog
deleted file mode 100644
index 19d13d51..00000000
--- a/boot/ChangeLog
+++ /dev/null
@@ -1,586 +0,0 @@
-Thu Aug 1 14:38:38 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * boot_script.h (safe_gets): Declare second parm as type `int'.
- * boot.c (safe_gets): Likewise.
-
-Sun Jul 7 21:10:08 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * boot.c (S_io_reauthenticate): Don't use unsafe MOVE_SEND in
- auth_server_authenticate.
-
-Fri May 10 16:11:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot.c (S_io_identity): Typo.
-
-Fri May 10 09:18:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * boot.c (S_io_identity): New function.
-
-Thu May 9 18:57:34 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * boot.c (S_io_select): No longer has TAG parm.
-
- * boot.c (S_io_reauthenticate): Use new interface.
-
-Sun Apr 28 22:50:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot.c (main): Use select instead of SIGIO.
-
-Mon Apr 15 12:57:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (uxboot): Permit errors because people might not have
- the a.out-mach3 target installed, and that's OK for many users.
-
- * Makefile (uxboot.0): Find frank1.ld in #(srcdir).
-
- * boot_script.h (safe_gets): Add decl.
- * boot_script.c: Include <stdio.h>.
-
-Wed Apr 3 18:54:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ux.c (printf): Add %d.
-
-Wed Mar 27 11:30:29 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot.c [notanymore] (S_tioctl_tiocgeta, S_tioctl_tiocseta,
- S_tioctl_tiocsetaf, term_modes, term_ccs, term_speeds):
- Functions & variables removed.
- * Makefile (COMMON-OBJS): Remove tcattr.o.
- (SRCS): Remove tcattr.c.
-
-Thu Mar 14 10:10:20 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * Makefile (boot): Depend on libthreads.so, nothing wrong with shared
- libs.
- (uxboot.0, uxboot.1): Use automatic vars in cmds instead of gratuitous
- redundancy.
- (LDFLAGS-uxboot.0): Remove useless indirection through variable.
-
-Wed Feb 14 16:50:05 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot.c [!UX]
- (orig_tty_state): New variable.
- (init_termstate, restore_termstate): New hurd versions of these funcs.
- * ux.c (init_termstate, restore_termstate, term_sgb, localbits):
- Moved here from boot.c
-
-Tue Feb 13 18:49:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot.c (load_image, boot_script_read_file, main): Use O_RDONLY,
- not 0 (kind of ironic, this...).
- (load_image): Give the filename with the error message (and a newline).
-
- * ux.h (O_RDONLY, O_WRONLY, O_RDWR): New macros.
-
- * ux.c, ux.h: New files.
- * boot.c: Move all the ux-specific grot into ux.c & ux.h.
- If UX is defined, include "ux.h", else define hurdish stuff.
- (main): Use get_privileged_ports instead of task_by_pid.
- (load_image, boot_script_read_file, main, do_mach_notify_no_senders,
- do_mach_notify_dead_name): Use host_exit instead of uxexit.
- (boot_script_read_file): Use host_stat instead of uxstat.
- (init_termstate, S_tioctl_tiocseta): Use sg_flags fld in struct sgttyb.
-
- * Makefile (all): Depend on `boot' and `uxboot'.
- (COMMON-OBJS, UX-OBJS): New macros.
- (OBJS): Inherit most names from $(COMMON-OBJS).
- (LCLHDRS): Add ux.h.
- (LDFLAGS): Use target-specific value.
- (uxboot.0-LDFLAGS): New macro (with contents from old LDFLAGS).
- (uxboot.o, uxboot.0): New targets.
- (uxboot): Target renamed from boot.a.
-
-Sun Dec 10 18:05:14 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot.c (read_reply): Don't call clear_should_read(), just do
- things ourselves.
- (should_read_lock): Variable deleted.
- (service_sigio): Function deleted.
- (main): Use read_reply to service SIGIO again, not service_sigio.
-
- * boot.c (service_sigio): New function, replacing set_should_read.
- Calls read_reply() itself too.
- (unlock_readlock): New function.
- (ds_device_read, ds_device_read_inband, S_io_read): Call
- unlock_readlock instead of directly unlocking READLOCK.
- (request_server, main): Don't call read_reply() anymore.
-
- * boot.c (should_read): New variable.
- (main): SIGIO uses set_should_read instead of read_reply.
- Call read_reply() after sigpause() returns.
- (read_reply): Call clear_should_read(), and don't do anything if
- SHOULD_READ wasn't set.
- (set_should_read): New function.
- (clear_should_read): New function.
- (request_server): Call read_reply() before returning.
-
-Sat Dec 9 19:01:10 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot.c (S_io_read, ds_device_read_inband, ds_device_read): Don't
- block SIGIO.
- (main): Don't trap SIGMSG & SIGEMSG.
-
-Mon Dec 4 23:54:18 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c (main): Request no-senders notification on
- pseudo_master_device_port.
- Deallocate our send right to it when we no longer need it.
- (do_mach_notify_no_senders): Exit only when both pseudo_console and
- pseudo_master_device_port have no senders.
- (ds_device_read_inband): Unlock readlock properly.
-
-Thu Nov 30 15:58:47 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * boot.c (readlock): New variable.
- (read_reply): Check FIONREAD before dequeueing QR so that we don't
- abandon requests. Lock READLOCK around FIONREAD/read pair.
- (ds_device_read): Lock READLOCK around FIONREAD/read pair.
- (ds_device_read_inband): Likewise.
- (S_io_read): Likewise.
-
-Nov 22 16:25:01 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c (request_server): Don't call exec_server.
- (S_exec_*): Functions removed.
- (boot_script_task_port): Variable removed.
- (boot_script_task_*, boot_script_port_*): Functions removed.
-
-Tue Nov 14 12:07:24 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Remove execServer.o.
-
-Thu Sep 28 14:47:46 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot_script.c (read_file): Pass CMD->path for file name.
- (CHECK_CMDLINE_LEN): Update ARGV pointers after reallocating the line
- buffer.
-
-Wed Sep 27 14:01:03 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c (struct uxstat): New type.
- (uxfstat): Renamed from fstat; use struct uxstat * for arg.
- (boot_script_read_file): Use those.
- Return the memory object port, not zero.
-
- * boot.c (fstat): New syscall function.
-
- * boot_script.c (read_file): New function.
- (builtin_symbols): Add $(read-file) builtin.
- * boot_script.h (boot_script_read_file): Declare it.
- * boot.c (close): New syscall function.
- (defpager): New variable.
- (main): Set it up.
- (boot_script_read_file): New function.
- (useropen_dir): New variable.
- (useropen): New function.
- (load_image): Call it instead of open.
- (main): Grok -D arg to set useropen_dir.
-
-Sat Sep 23 00:53:51 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * syscall.S: Restore entry SP before return.
-
- * boot.c (main): Use static const for constant strings.
- On boot script error, write script line with error msg.
-
- * boot_script.c (boot_script_parse_line): Ignore line beginning
- with #.
-
- * boot.c (S_io_pathconf): New function.
-
- * Makefile (LDFLAGS): Add -static.
-
-Fri Sep 22 14:14:23 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * mach-crt0.c (__data_start): New variable.
-
-Tue Aug 29 10:41:29 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * boot.c (mig_dealloc_reply_port): Remove __ from call to
- mach_port_mod_refs.
- (main): Look for -d in bootstrap_args, not (nonexistent)
- boot_args. Remove `const' keyword from decl of MSG.
-
- * boot.c (sigblock, sigsetmask): New functions.
- (sigmask): New macro.
- (ds_device_read): Block SIGIO around critical section.
- (ds_device_read_inband): Likewise.
- (S_io_read): Likewise.
-
-Mon Aug 28 17:16:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot_script.h, boot_script.c: Updated by Shantanu Goel, to
- accept action keywords only inside $(...) and only variable values
- inside ${...}.
- * boot.c: Updated for changes in boot_script.h protocol by
- Shantanu Goel.
- (main): Use boot_script_set_variable instead of magic variables.
- Under -d, pause between parsing bootscript and executing it.
-
-Wed Aug 23 16:08:04 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- New script-driven boot mechanism, mostly implemented by Shantanu Goel.
- * Makefile (SRCS): Add boot_script.c.
- (OBJS): Add boot_script.o.
- (LCLHDRS): New variable.
- (HURDLIBS): Variable removed.
- (boot): Depend on ../libthreads/libthreads.a.
- * boot_script.c, boot_script.h: New files.
- * boot.c (boot_like_kernel, boot_like_cmudef, boot_like_hurd):
- Variables removed.
- (main): Don't interpret switches. Instead of servers, take
- command line argument of boot script file name. Read the file and
- use boot_script functions to parse and execute its directives.
- (boot_script_*): New variables and functions for boot_script callbacks.
-
-Sun Jul 30 23:50:53 1995 Michael I. Bushnell, p/BSG <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: DISTFILES -> DIST_FILES.
-
-Sat Jul 8 11:37:32 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * boot.c (free_reply_ports, free_reply_ports_lock): New variables.
- (__mig_get_reply_port, __mig_put_reply_port, __mig_dealloc_reply_port,
- mig_get_reply_port, mig_put_reply_port, mig_dealloc_reply_port):
- Provide better versions of these routines that won't leak reply ports.
-
-Fri Jul 7 15:55:18 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * mach-crt0.c: New file, from mach4-i386/libmach/standalone.
- * boot.c (mach_init_routine): New variable, wanted by mach-crt0.o.
- (__mig_get_reply_port, __mig_dealloc_reply_port, __mig_put_reply_port):
- New functions, to avoid using hurdish versions.
- * Makefile (OBJS): Add mach-crt0.o.
- (SRCS): Add mach-crt0.c.
- (LDFLAGS): Add -nostartfiles (as we now use mach-crt0.o).
-
-Thu Jul 6 15:30:18 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (boot.1, boot.a): Use $(LD) and $(OBJCOPY) instead of
- explicit names.
-
- * boot.c: Include <mach/mig_support.h>.
- (S_io_reauthenticate): Cast first arg to mig_deallocate.
- (load_image): Cast second arg to read.
- * tcattr.c: Undo last change; add private decl of ioctl.
-
- * boot.c (bootdevice): Initialize to hard-coded `sd0a' instead of
- DEFAULT_BOOTDEVICE.
-
- * Makefile (all): Depend on boot.a too.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Wed May 31 10:02:11 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (DISTFILES): New variable; include frank1.ld and
- frankemul.ld.
- (CPPFLAGS): Variable removed.
- (LDFLAGS): Append -T frank1.ld.
- (boot.1, boot.a): New targets.
-
- * syscall.S: Omit .globl decl for errno; it caused some as
- complaint.
-
-Mon May 22 11:48:58 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * sigvec.S: Remove copyright notice.
-
-Wed May 17 13:10:27 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * boot.c (load_image): Make sure we actually allocate enough
- memory to read into, including the offset into the buffer at which
- the segment is read.
-
- * sigvec.S (sigreturn, _sigreturn, sigvec): Remove the explicit
- underscore prefixes from these names, now that we're using elf.
- Instead we use the various macros from <i386/asm.h>. Also, return
- errors correctly. [Also added a copyright notice]
-
-Sat May 13 03:37:24 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c (load_image): Fixed alignment calculation in ELF segment
- loading.
-
- * syscall.S: Include i386/asm.h and use ENTRY and EXT macros,
- instead of explicit _s.
-
-Fri May 12 18:36:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c (load_image): Grok ELF executables as well as a.out.
- (main): Load multiple servers. Suspend all but the first.
- The first gets an extra arg, its name for the task port of the
- second.
-
-Wed Apr 12 09:18:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile: Don't try and install boot in /usr/local/bin.
-
-Wed Apr 5 17:25:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c: Don't include <errno.h>. Define `errno' variable.
- * Makefile (SRCS): Add syscall.S.
- (OBJS): Add syscall.o.
- * syscall.S: Check for errors.
-
-Thu Jan 19 01:21:24 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c (S_io_select): Updated to new io_select protocol.
-
-Fri Dec 9 01:23:22 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c: Use mach_msg_type_number_t in place of unsigned int and
- int.
-
-Fri Nov 11 14:05:43 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * boot.c (main): Always set `f' flag (signifying "fake" because we
- aren't a real native bootstrap).
-
-Thu Nov 3 17:26:37 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (boot.o): Depend on bootstrap_S.h.
-
-Fri Oct 28 17:08:12 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot.c (main): Create the thread before setting it up.
- (bootstrap_compat): Make a send right for psuedo_master_device_port.
- (main): Explicitly clear NEWTASK's bootstrap port for boot_like_kernel.
- (main): Format strings for port names for boot_like_kernel.
-
-Fri Oct 28 15:26:48 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * boot.c (boot_like_kernel, boot_like_cmudef, boot_like_hurd): New
- global vars.
- (set_mach_stack_args): New function.
- (main): If the -k flag is given, set BOOT_LIKE_KERNEL.
- If the -p flag is given, set BOOT_LIKE_CMUDEF. If neither is
- given, set BOOT_LIKE_HURD.
- Only set a bootstrap port if BOOT_LIKE_CMUDEF or BOOT_LIKE_HURD.
- If BOOT_LIKE_KERNEL or BOOT_LIKE_CMUDEF, set up the stack the
- Mach way using set_mach_stack_args.
- (request_server): Declare and call bootstrap_server.
- (do_bootstrap_priveleged_ports, bootstrap_compat): New functions.
- * Makefile (OBJS): Require bootstrapServer.o.
- * bootstrap.defs: New file.
-
-Tue Aug 30 11:41:33 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * boot.c (S_io_reauthenticate): Use new authentication protocol.
-
-Mon Aug 22 13:43:32 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * boot.c: Include <cthreads.h>.
- (main): Run msg_thread fork; don't call
- mach_msg_server_timeout here. Use sigpause instead of getpid.
- (msg_thread): New function.
- (queuelock): New variable.
- (queue_read): Acquire queuelock.
- (read_reply): Acquire queuelock.
- * Makefile (HURDLIBS): New var to get threads.
-
-Thu Aug 18 18:04:36 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * boot.c (restore_termstate): New function.
- (do_mach_notify_no_senders): Call restore_termstate before exiting.
-
- * boot.c (main): New var `usagemsg'; print it if args are wrong.
- Allow flags and disk device to be given on command line.
- New var `bootfile'.
- (bootdevice, bootstrap_args): New vars.
- (load_image): Exit nicely if the startup file can't be found.
- (S_exec_startup): Use `bootdevice' instead of hardcoded name.
- Use `bootstrap_args' instead of hardcoded "-x".
- (main): Only do `pausing' hack if -d was provided.
-
- * Makefile (CPPFLAGS): Define DEFAULT_BOOTDEVICE.
-
- * Makefile (/usr/local/bin/boot): Depend on boot.
-
- * boot.c (S_termctty_open_terminal): New "function".
- (S_io_select): Added `rettype' arg.
-
-Sat Jul 23 02:58:05 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (io-MIGSFLAGS): Renamed from ioMIGSFLAGS.
-
-Fri Jul 22 15:10:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * boot.c (request_server): Remove S_ from io_server and
- term_server.
-
-Thu Jul 21 19:00:36 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten to use new scheme.
- * boot.c: Include io_reply_U.h and device_reply_U.h instead
- of io_repl.h and device_reply.h.
-
-Wed Jul 20 13:19:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * boot.c: Comment out bits relating to tioctl interface.
- * Makefile: Likewise.
-
-Tue Jul 19 12:41:46 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (boot): Don't use variable $(link) anymore.
-
-Tue Jul 5 14:19:36 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (SRCS): New variable.
-
-Sun Jul 3 17:20:07 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * tcattr.c: New file.
- * boot.c (S_tioctl_tiocgeta): Call tcgetattr.
- (S_tioctl_tiocseta): Call tcsetattr.
- * Makefile (OBJS): Add tcattr.o.
- (DIST_FILES): Add tcattr.c.
-
-Fri Jul 1 11:16:27 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * boot.c (init_termstate): Enter raw mode here.
-
-Fri Jun 24 14:27:56 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * boot.c (S_term_open_ctty): Renamed from term_become_ctty.
- Deleted SIGPT arg. Add msg type arg for NEWTTY.
-
-Fri Jun 17 13:46:07 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * boot.c (request_server): Remove S_ prefix from exec_server
- and notify_server.
-
-Fri Jun 17 00:12:16 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * Makefile (boot.o): Depend on term_S.h.
-
-Tue Jun 14 01:28:10 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * boot.c (request_server): Add S_ prefix to demuxer functions.
-
-Wed Jun 8 18:02:19 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * boot.c (S_tioctl_tiocseta): Turn off ECHO.
- (S_io_select): Implement.
-
-Tue Jun 7 04:33:42 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * Makefile (tioctlServer.o): Depend on ../hurd/ioctl_types.h.
-
-Mon Jun 6 20:33:39 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * boot.c (authserver): New variable.
- (S_io_reauthenticate): Do auth_server_authenticate and throw away
- the returned info.
- (S_exec_init): Set authserver to the passed port.
-
-Sat Jun 4 02:32:03 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * boot.c: Include term_S.h and tioctl_S.h.
- (S_term_getctty): New function.
- (S_term_*): Stub functions.
- (request_server): Use S_term_server.
-
- * Makefile (termServer.c term_S.h): New rule.
- (OBJS): Add termServer.o.
-
- * boot.c (S_exec_setexecdata, S_exec_exec): Fix prototypes.
-
-Tue May 17 18:44:29 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * boot.c (ds_device_write): DATA arg is char *; don't dereference
- it in call to write.
-
-Mon May 16 14:34:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * boot.c (fsname): New variable.
- (main): Set fsname to argv[1].
- (S_exec_startup): Include fsname in child's argv[0].
-
- * boot.c (init_termstate): Add forward declaration.
- (struct sigvec): Make SV_HANDLER member void (*)().
- (sigvec): Add declaration to avoid warning.
-
-Tue May 10 18:14:39 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * boot.c (tioctl_tiocseta, tioctl_tiocsetw, tioctl_tiocsetf,
- tioctl_tiocgeta, init_termstate): New functions.
- (term_modes, term_ccs, term_speeds, term_sgb, localbits): Nev
- vars.
- Also added new bits from ioctl.h.
- (main): Call init_termstate.
- (request_server): Call tioctl_server.
- * Makefile (tioctlServer.c tioctl_S.h): New targets.
- (OBJS): Include tioctlServer.o.
- (boot.o): Depend on tioctl_S.h
-
-Fri May 6 13:56:58 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * boot.c (main): Restore braindamage of yesterday relating to
- signals; that is, restore declaration of VEC and calls to sigvec.
- * Makefile (DIST_FILES): Add sigvec.S.
-
-Thu May 5 13:16:42 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makefile (device_replyUser.c): Mention that this build
- device_reply.h as well.
- (boot.o): Add dependency on device_reply.h and io_repl.h.
-
- * boot.c: Include <stdlib.h> for malloc and free prototypes.
- Include <string.h> for bcopy and bzero prototypes.
- Include <stdio.h> for sprintf prototype.
- Include "device_reply.h" for its prototypes.
- Include "io_reply.h" for its prototypes.
- Declare return type for all the server functions that were lacking
- such.
- (sigpause): Declare type of MASK.
- (ioctl): Declare third arg to be generic pointer, not char *.
- (request_server): Declare MiG functions we call.
- (load_image): Delete unused variable STACKADDR.
- (main): Comment out declaration of VEC.
- Comment out calls to sigvec.
- Cast STARTPC in call to __mach_setup_thread.
- Delete unused variable TIMEOUT.
- (read_reply): Cast BUF correctly in call to ds_device_read_reply.
- (S_exec_startup): Delete unused variable DTABLE.
- (ds_device_write): Double cast arg to write to avoid warning.
- (S_io_read): Order args to vm_allocate properly; cast DATA arg.
- Check *datalen properly for unsigned type.
-
- * boot.c: Renamed _exit to uxexit to avoid library name clash.
- (do_mach_notify_dead_name, do_mach_notify_no_senders):
- Call uxexit instead of _exit.
-
- * boot.c (S_io_async, S_io_get_icky_async_id, S_io_map_cntl):
- Expect new type arg for returned port.
- (S_io_prenotify, S_io_postnotify): START and END args are now
- vm_offset_t.
-
- * boot.c: Change error_t to kern_return_t because error_t
- is now unsigned and conflicts with MiG's use of kern_return_t.
-
- * Makefile (io_S.h, ioServer.c): Punt mungio hack; use
- -DREPLY_PORTS.
- * boot.c: Changed all io server stubs to expect reply ports.
-
- * mungio: removed file.
- * Makefile (DIST_FILES): Removed mungio.
-
- * boot.c (load_image): Only read from the image file the actual
- amount being read, not that amount rounded to the nearest page.
- Otherwise, the first bit of the BSS will not be zero, but will be
- whatever is in the front of the symbol section of the a.out.
-
-Thu May 5 07:43:06 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
-Mon May 2 16:47:49 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * boot.c (S_io_readable): Implement io_readable fully.
-
-Fri Apr 1 17:55:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile (OBJS): Remove boot_machdep.o.
-
diff --git a/boot/Makefile b/boot/Makefile
index 30838e5d..6c787cfd 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1993,94,95,96,97,2001 Free Software Foundation, Inc.
# This file is part of the GNU Hurd.
#
# The GNU Hurd is free software; you can redistribute it and/or modify
@@ -18,16 +18,18 @@
dir := boot
makemode := utility
-SRCS = mach-crt0.c boot.c ux.c sigvec.S syscall.S boot_script.c
+SRCS = mach-crt0.c boot.c ux.c sigvec.S syscall.S \
+ boot_script.c userland-boot.c
COMMON-OBJS = notifyServer.o ourdeviceServer.o \
ioServer.o io_replyUser.o device_replyUser.o \
- termServer.o bootstrapServer.o boot_script.o
+ termServer.o bootstrapServer.o boot_script.o userland-boot.o
OBJS = boot.o $(COMMON-OBJS)
UX-OBJS = mach-crt0.o uxboot.o sigvec.o syscall.o ux.o $(COMMON-OBJS)
LCLHDRS = boot_script.h ux.h
target = boot
io-MIGSFLAGS=-DREPLY_PORTS
DIST_FILES=frank1.ld frankemul.ld
+HURDLIBS=store shouldbeinlibc threads
include ../Makeconf
@@ -36,12 +38,11 @@ include ../Makeconf
#/usr/local/bin/uxboot: uxboot
# cp $< $@
-all: boot uxboot
+all: boot # uxboot
-ourdevice.defs: $(includedir)/device/device.defs
- sed -e '/out device : device_t/s/device_t/mach_port_send_t/' $< > $@
+ourdevice.defs: device.defs
+ $(CPP) $(CPPFLAGS) -x c $< | sed -e '/out[ ]*device[ ]*:[ ]*device_t/s/device_t/mach_port_send_t/' > $@
-boot: ../libthreads/libthreads.so
uxboot.o: boot.c
$(COMPILE.c) -DUX $< -o $@
diff --git a/boot/boot.c b/boot/boot.c
index dcf3bccc..2b143844 100644
--- a/boot/boot.c
+++ b/boot/boot.c
@@ -1,6 +1,7 @@
/* Load a task using the single server, and then run it
as if we were the kernel.
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,2006
+ Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -30,14 +31,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <string.h>
#include <stdio.h>
#include <cthreads.h>
-#include <varargs.h>
-#include <fcntlbits.h>
+#include <fcntl.h>
#include <elf.h>
#include <mach/mig_support.h>
#include <mach/default_pager.h>
+#include <argp.h>
+#include <hurd/store.h>
+#include <sys/mman.h>
+#include <version.h>
#include "notify_S.h"
-#include "exec_S.h"
#include "ourdevice_S.h"
#include "io_S.h"
#include "device_reply_U.h"
@@ -51,6 +54,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/auth.h>
#ifdef UX
+#undef STORE /* We can't use libstore when under UX. */
+#else
+#define STORE
+#endif
+
+#ifdef UX
#include "ux.h"
@@ -64,8 +73,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <termios.h>
#include <error.h>
#include <hurd.h>
+#include <assert.h>
static struct termios orig_tty_state;
+static int isig;
+static char *kernel_command_line;
static void
init_termstate ()
@@ -77,6 +89,8 @@ init_termstate ()
orig_tty_state = tty_state;
cfmakeraw (&tty_state);
+ if (isig)
+ tty_state.c_lflag |= ISIG;
if (tcsetattr (0, 0, &tty_state) < 0)
error (11, errno, "tcsetattr");
@@ -97,9 +111,11 @@ typedef struct stat host_stat_t;
mach_port_t privileged_host_port, master_device_port, defpager;
mach_port_t pseudo_master_device_port;
mach_port_t receive_set;
-mach_port_t pseudo_console;
+mach_port_t pseudo_console, pseudo_root;
auth_t authserver;
+struct store *root_store;
+
spin_lock_t queuelock = SPIN_LOCK_INITIALIZER;
spin_lock_t readlock = SPIN_LOCK_INITIALIZER;
@@ -118,10 +134,10 @@ void restore_termstate ();
char *fsname;
-char *bootstrap_args;
-char *bootdevice = "sd0a";
+char bootstrap_args[100] = "-";
+char *bootdevice = 0;
+char *bootscript = 0;
-void set_mach_stack_args ();
void safe_gets (char *buf, int buf_len)
{
@@ -219,7 +235,8 @@ load_image (task_t t,
vm_size_t offs = ph->p_offset & (ph->p_align - 1);
vm_size_t bufsz = round_page (ph->p_filesz + offs);
- vm_allocate (mach_task_self (), &buf, bufsz, 1);
+ buf = (vm_address_t) mmap (0, bufsz,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
lseek (fd, ph->p_offset, SEEK_SET);
read (fd, (void *)(buf + offs), ph->p_filesz);
@@ -231,7 +248,7 @@ load_image (task_t t,
vm_allocate (t, (vm_address_t*)&ph->p_vaddr, ph->p_memsz, 0);
vm_write (t, ph->p_vaddr, buf, bufsz);
- vm_deallocate (mach_task_self (), buf, bufsz);
+ munmap ((caddr_t) buf, bufsz);
vm_protect (t, ph->p_vaddr, ph->p_memsz, 0,
((ph->p_flags & PF_R) ? VM_PROT_READ : 0) |
((ph->p_flags & PF_W) ? VM_PROT_WRITE : 0) |
@@ -253,15 +270,15 @@ load_image (task_t t,
amount = headercruft + hdr.a.a_text + hdr.a.a_data;
rndamount = round_page (amount);
- vm_allocate (mach_task_self (), (u_int *)&buf, rndamount, 1);
+ buf = mmap (0, rndamount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
lseek (fd, sizeof hdr.a - headercruft, SEEK_SET);
read (fd, buf, amount);
vm_allocate (t, &base, rndamount, 0);
- vm_write (t, base, (u_int) buf, rndamount);
+ vm_write (t, base, (vm_address_t) buf, rndamount);
if (magic != OMAGIC)
vm_protect (t, base, trunc_page (headercruft + hdr.a.a_text),
0, VM_PROT_READ | VM_PROT_EXECUTE);
- vm_deallocate (mach_task_self (), (u_int)buf, rndamount);
+ munmap ((caddr_t) buf, rndamount);
bssstart = base + hdr.a.a_text + hdr.a.a_data + headercruft;
bsspagestart = round_page (bssstart);
@@ -278,18 +295,6 @@ void msg_thread ();
/* Callbacks for boot_script.c; see boot_script.h. */
-void *
-boot_script_malloc (int size)
-{
- return malloc (size);
-}
-
-void
-boot_script_free (void *ptr, int size)
-{
- free (ptr);
-}
-
mach_port_t
boot_script_read_file (const char *filename)
{
@@ -324,116 +329,243 @@ boot_script_read_file (const char *filename)
vm_map (mach_task_self (), &region, round_page (st.st_size),
0, 1, memobj, 0, 0, VM_PROT_ALL, VM_PROT_ALL, VM_INHERIT_NONE);
read (fd, (char *) region, st.st_size);
- vm_deallocate (mach_task_self (), region, round_page (st.st_size));
+ munmap ((caddr_t) region, round_page (st.st_size));
close (fd);
return memobj;
}
int
-boot_script_exec_cmd (mach_port_t task, char *path, int argc,
+boot_script_exec_cmd (void *hook,
+ mach_port_t task, char *path, int argc,
char **argv, char *strings, int stringlen)
{
char *args, *p;
int arg_len, i;
- unsigned reg_size;
+ size_t reg_size;
void *arg_pos;
vm_offset_t stack_start, stack_end;
vm_address_t startpc, str_start;
thread_t thread;
- struct i386_thread_state regs;
write (2, path, strlen (path));
+ for (i = 1; i < argc; ++i)
+ {
+ write (2, " ", 1);
+ write (2, argv[i], strlen (argv[i]));
+ }
write (2, "\r\n", 2);
startpc = load_image (task, path);
- thread_create (task, &thread);
arg_len = stringlen + (argc + 2) * sizeof (char *) + sizeof (integer_t);
arg_len += 5 * sizeof (int);
stack_end = VM_MAX_ADDRESS;
stack_start = VM_MAX_ADDRESS - 16 * 1024 * 1024;
vm_allocate (task, &stack_start, stack_end - stack_start, FALSE);
- reg_size = i386_THREAD_STATE_COUNT;
- thread_get_state (thread, i386_THREAD_STATE,
- (thread_state_t) &regs, &reg_size);
- regs.eip = (int) startpc;
- regs.uesp = (int) ((stack_end - arg_len) & ~(sizeof (int) - 1));
- thread_set_state (thread, i386_THREAD_STATE,
- (thread_state_t) &regs, reg_size);
- arg_pos = (void *) regs.uesp;
- vm_allocate (mach_task_self (), (vm_address_t *) &args,
- stack_end - trunc_page ((vm_offset_t) arg_pos), TRUE);
+ arg_pos = (void *) ((stack_end - arg_len) & ~(sizeof (natural_t) - 1));
+ args = mmap (0, stack_end - trunc_page ((vm_offset_t) arg_pos),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
str_start = ((vm_address_t) arg_pos
+ (argc + 2) * sizeof (char *) + sizeof (integer_t));
p = args + ((vm_address_t) arg_pos & (vm_page_size - 1));
- *((int *) p)++ = argc;
+ *(int *) p = argc;
+ p = (void *) p + sizeof (int);
for (i = 0; i < argc; i++)
- *((char **) p)++ = argv[i] - strings + (char *) str_start;
- *((char **) p)++ = 0;
- *((char **) p)++ = 0;
+ {
+ *(char **) p = argv[i] - strings + (char *) str_start;
+ p = (void *) p + sizeof (char *);
+ }
+ *(char **) p = 0;
+ p = (void *) p + sizeof (char *);
+ *(char **) p = 0;
+ p = (void *) p + sizeof (char *);
memcpy (p, strings, stringlen);
bzero (args, (vm_offset_t) arg_pos & (vm_page_size - 1));
vm_write (task, trunc_page ((vm_offset_t) arg_pos), (vm_address_t) args,
stack_end - trunc_page ((vm_offset_t) arg_pos));
- vm_deallocate (mach_task_self (), (vm_address_t) args,
- stack_end - trunc_page ((vm_offset_t) arg_pos));
+ munmap ((caddr_t) args,
+ stack_end - trunc_page ((vm_offset_t) arg_pos));
+
+ thread_create (task, &thread);
+#ifdef i386_THREAD_STATE_COUNT
+ {
+ struct i386_thread_state regs;
+ reg_size = i386_THREAD_STATE_COUNT;
+ thread_get_state (thread, i386_THREAD_STATE,
+ (thread_state_t) &regs, &reg_size);
+ regs.eip = (int) startpc;
+ regs.uesp = (int) arg_pos;
+ thread_set_state (thread, i386_THREAD_STATE,
+ (thread_state_t) &regs, reg_size);
+ }
+#elif defined(ALPHA_THREAD_STATE_COUNT)
+ {
+ struct alpha_thread_state regs;
+ reg_size = ALPHA_THREAD_STATE_COUNT;
+ thread_get_state (thread, ALPHA_THREAD_STATE,
+ (thread_state_t) &regs, &reg_size);
+ regs.r30 = (natural_t) arg_pos;
+ regs.pc = (natural_t) startpc;
+ thread_set_state (thread, ALPHA_THREAD_STATE,
+ (thread_state_t) &regs, reg_size);
+ }
+#else
+# error needs to be ported
+#endif
+
thread_resume (thread);
mach_port_deallocate (mach_task_self (), thread);
return 0;
}
+const char *argp_program_version = STANDARD_HURD_VERSION (boot);
+
+static struct argp_option options[] =
+{
+ { "boot-root", 'D', "DIR", 0,
+ "Root of a directory tree in which to find files specified in BOOT-SCRIPT" },
+ { "single-user", 's', 0, 0,
+ "Boot in single user mode" },
+ { "kernel-command-line", 'c', "COMMAND LINE", 0,
+ "Simulated multiboot command line to supply" },
+ { "pause" , 'd', 0, 0,
+ "Pause for user confirmation at various times during booting" },
+ { "isig", 'I', 0, 0,
+ "Do not disable terminal signals, so you can suspend and interrupt boot."},
+ { "device", 'f', "device_name=device_file", 0,
+ "Specify a device file used by subhurd and its virtual name."},
+ { 0 }
+};
+static char args_doc[] = "BOOT-SCRIPT";
+static char doc[] = "Boot a second hurd";
+
+struct dev_map
+{
+ char *name;
+ mach_port_t port;
+ struct dev_map *next;
+};
+
+static struct dev_map *dev_map_head;
+
+static struct dev_map *add_dev_map (char *dev_name, char *dev_file)
+{
+ struct dev_map *map = malloc (sizeof (*map));
+
+ assert (map);
+ map->name = dev_name;
+ map->port = file_name_lookup (dev_file, 0, 0);
+ if (map->port == MACH_PORT_NULL)
+ error (1, errno, "file_name_lookup: %s", dev_file);
+ map->next = dev_map_head;
+ dev_map_head = map;
+ return map;
+}
+
+static struct dev_map *lookup_dev (char *dev_name)
+{
+ struct dev_map *map;
+
+ for (map = dev_map_head; map; map = map->next)
+ {
+ if (strcmp (map->name, dev_name) == 0)
+ return map;
+ }
+ return NULL;
+}
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ char *dev_file;
+
+ switch (key)
+ {
+ size_t len;
+
+ case 'c': kernel_command_line = arg; break;
+
+ case 'D': useropen_dir = arg; break;
+
+ case 'I': isig = 1; break;
+
+ case 's': case 'd':
+ len = strlen (bootstrap_args);
+ if (len >= sizeof bootstrap_args - 1)
+ argp_error (state, "Too many bootstrap args");
+ bootstrap_args[len++] = key;
+ bootstrap_args[len] = '\0';
+ break;
+
+ case 'f':
+ dev_file = strchr (arg, '=');
+ if (dev_file == NULL)
+ return ARGP_ERR_UNKNOWN;
+ *dev_file = 0;
+ add_dev_map (arg, dev_file+1);
+ break;
+
+ case ARGP_KEY_ARG:
+ if (state->arg_num == 0)
+ bootscript = arg;
+ else
+ return ARGP_ERR_UNKNOWN;
+ break;
+
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input; break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
int
main (int argc, char **argv, char **envp)
{
+ error_t err;
mach_port_t foo;
- static const char usagemsg[]
- = "Usage: boot [-D dir] [SWITCHES] SCRIPT ROOT-DEVICE\n";
char *buf = 0;
- char *bootscript;
int i, len;
- char *newargs;
+ char *root_store_name;
+ const struct argp_child kids[] = { { &store_argp }, { 0 }};
+ struct argp argp = { options, parse_opt, args_doc, doc, kids };
+ struct store_argp_params store_argp_params = { 0 };
+
+ argp_parse (&argp, argc, argv, 0, 0, &store_argp_params);
+ err = store_parsed_name (store_argp_params.result, &root_store_name);
+ if (err)
+ error (2, err, "store_parsed_name");
+
+ err = store_parsed_open (store_argp_params.result, 0, &root_store);
+ if (err)
+ error (4, err, "%s", root_store_name);
get_privileged_ports (&privileged_host_port, &master_device_port);
defpager = MACH_PORT_NULL;
vm_set_default_memory_manager (privileged_host_port, &defpager);
- if (argc < 2 || (argv[1][0] == '-' && argc < 3))
- {
- usage:
- write (2, usagemsg, sizeof usagemsg);
- host_exit (1);
- }
+ strcat (bootstrap_args, "f");
- if (!strcmp (argv[1], "-D"))
- {
- if (argc < 4)
- goto usage;
- useropen_dir = argv[2];
- argv += 2;
- }
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
+ &receive_set);
- if (argv[1][0] != '-')
- {
- bootstrap_args = "-x";
- bootscript = argv[1];
- bootdevice = argv[2];
- }
+ if (root_store->class == &store_device_class && root_store->name
+ && (root_store->flags & STORE_ENFORCED)
+ && root_store->num_runs == 1 && root_store->runs[0].start == 0)
+ /* Let known device nodes pass through directly. */
+ bootdevice = root_store->name;
else
+ /* Pass a magic value that we can use to do I/O to ROOT_STORE. */
{
- bootstrap_args = argv[1];
- bootscript = argv[2];
- bootdevice = argv[3];
+ bootdevice = "pseudo-root";
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &pseudo_root);
+ mach_port_move_member (mach_task_self (), pseudo_root, receive_set);
}
- newargs = malloc (strlen (bootstrap_args) + 2);
- strcpy (newargs, bootstrap_args);
- strcat (newargs, "f");
- bootstrap_args = newargs;
-
- mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
- &receive_set);
-
mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
&pseudo_master_device_port);
mach_port_insert_right (mach_task_self (),
@@ -458,13 +590,21 @@ main (int argc, char **argv, char **envp)
if (foo != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self (), foo);
+ if (kernel_command_line == 0)
+ asprintf (&kernel_command_line, "%s %s root=%s",
+ argv[0], bootstrap_args, bootdevice);
+
/* Initialize boot script variables. */
if (boot_script_set_variable ("host-port", VAL_PORT,
(int) privileged_host_port)
|| boot_script_set_variable ("device-port", VAL_PORT,
- (int) pseudo_master_device_port)
- || boot_script_set_variable ("root-device", VAL_STR, (int) bootdevice)
- || boot_script_set_variable ("boot-args", VAL_STR, (int) bootstrap_args))
+ (integer_t) pseudo_master_device_port)
+ || boot_script_set_variable ("kernel-command-line", VAL_STR,
+ (integer_t) kernel_command_line)
+ || boot_script_set_variable ("root-device",
+ VAL_STR, (integer_t) bootdevice)
+ || boot_script_set_variable ("boot-args",
+ VAL_STR, (integer_t) bootstrap_args))
{
static const char msg[] = "error setting variable";
@@ -472,10 +612,38 @@ main (int argc, char **argv, char **envp)
host_exit (1);
}
+ /* Turn each `FOO=BAR' word in the command line into a boot script
+ variable ${FOO} with value BAR. */
+ {
+ int len = strlen (kernel_command_line) + 1;
+ char *s = memcpy (alloca (len), kernel_command_line, len);
+ char *word;
+
+ while ((word = strsep (&s, " \t")) != 0)
+ {
+ char *eq = strchr (word, '=');
+ if (eq == 0)
+ continue;
+ *eq++ = '\0';
+ err = boot_script_set_variable (word, VAL_STR, (integer_t) eq);
+ if (err)
+ {
+ char *msg;
+ asprintf (&msg, "cannot set boot-script variable %s: %s\n",
+ word, boot_script_error_string (err));
+ assert (msg);
+ write (2, msg, strlen (msg));
+ free (msg);
+ host_exit (1);
+ }
+ }
+ }
+
/* Parse the boot script. */
{
char *p, *line;
- static const char filemsg[] = "Can't open boot script";
+ static const char filemsg[] = "Can't open boot script\n";
+ static const char memmsg[] = "Not enough memory\n";
int amt, fd, err;
fd = open (bootscript, O_RDONLY, 0);
@@ -485,6 +653,11 @@ main (int argc, char **argv, char **envp)
host_exit (1);
}
p = buf = malloc (500);
+ if (!buf)
+ {
+ write (2, memmsg, sizeof (memmsg));
+ host_exit (1);
+ }
len = 500;
amt = 0;
while (1)
@@ -500,6 +673,11 @@ main (int argc, char **argv, char **envp)
len += 500;
newbuf = realloc (buf, len);
+ if (!newbuf)
+ {
+ write (2, memmsg, sizeof (memmsg));
+ host_exit (1);
+ }
p = newbuf + (p - buf);
buf = newbuf;
}
@@ -510,7 +688,7 @@ main (int argc, char **argv, char **envp)
while (p < buf + amt && *p != '\n')
p++;
*p = '\0';
- err = boot_script_parse_line (line);
+ err = boot_script_parse_line (0, line);
if (err)
{
char *str;
@@ -552,6 +730,7 @@ main (int argc, char **argv, char **envp)
int i = strlen (str);
write (2, str, i);
+ write (2, "\n", 1);
host_exit (1);
}
free (buf);
@@ -568,206 +747,13 @@ main (int argc, char **argv, char **envp)
FD_SET (0, &rmask);
if (select (1, &rmask, 0, 0, 0) == 1)
read_reply ();
- else
- { /* We hosed */
- perror ("select");
- exit (5);
- }
+ else /* We hosed */
+ error (5, errno, "select");
}
/* mach_msg_server (request_server, __vm_page_size * 2, receive_set); */
}
-/* Set up stack args the Mach way */
-void
-set_mach_stack_args (user_task,
- user_thread,
- startpc,
- va_alist)
- task_t user_task;
- thread_t user_thread;
- char *startpc;
- va_dcl
-{
- /* This code is lifted from .../mk/bootstrap/load.c. */
- va_list argv_ptr;
- char * arg_ptr;
-
- int arg_len;
- int arg_count;
- char * arg_pos;
- unsigned int arg_item_len;
-
- /*
- * Calculate the size of the argument list.
- */
- va_start(argv_ptr);
- arg_len = 0;
- arg_count = 0;
- for (;;) {
- arg_ptr = va_arg(argv_ptr, char *);
- if (arg_ptr == (char *)0)
- break;
- arg_count++;
- arg_len += strlen(arg_ptr) + 1; /* space for '\0' */
- }
- va_end(argv_ptr);
- /*
- * Add space for:
- * arg_count
- * pointers to arguments
- * trailing 0 pointer
- * dummy 0 pointer to environment variables
- * and align to integer boundary
- */
- arg_len += sizeof(integer_t) + (2 + arg_count) * sizeof(char *);
- arg_len = (arg_len + (sizeof(integer_t) - 1)) & ~(sizeof(integer_t)-1);
-
-
- /* This small piece is from .../mk/bootstrap/i386/exec.c. */
- {
- vm_offset_t stack_start;
- vm_offset_t stack_end;
- struct i386_thread_state regs;
- unsigned int reg_size;
-
-#define STACK_SIZE (1024 * 1024 * 16)
-
- /*
- * Add space for 5 ints to arguments, for
- * PS program. XXX
- */
- arg_len += 5 * sizeof(int);
-
- /*
- * Allocate stack.
- */
- stack_end = VM_MAX_ADDRESS;
- stack_start = VM_MAX_ADDRESS - STACK_SIZE;
- (void)vm_allocate(user_task,
- &stack_start,
- (vm_size_t)(stack_end - stack_start),
- FALSE);
-
- reg_size = i386_THREAD_STATE_COUNT;
- (void)thread_get_state(user_thread,
- i386_THREAD_STATE,
- (thread_state_t)&regs,
- &reg_size);
-
- regs.eip = (int) startpc;
- regs.uesp = (int)((stack_end - arg_len) & ~(sizeof(int)-1));
-
- (void)thread_set_state(user_thread,
- i386_THREAD_STATE,
- (thread_state_t)&regs,
- reg_size);
-
- arg_pos = (void *) regs.uesp;
- }
-
- /*
- * Copy out the arguments.
- */
- {
- vm_offset_t u_arg_start;
- /* user start of argument list block */
- vm_offset_t k_arg_start;
- /* kernel start of argument list block */
- vm_offset_t u_arg_page_start;
- /* user start of args, page-aligned */
- vm_size_t arg_page_size;
- /* page_aligned size of args */
- vm_offset_t k_arg_page_start;
- /* kernel start of args, page-aligned */
-
- register
- char ** k_ap; /* kernel arglist address */
- char * u_cp; /* user argument string address */
- register
- char * k_cp; /* kernel argument string address */
- register
- int i;
-
- /*
- * Get address of argument list in user space
- */
- u_arg_start = (vm_offset_t)arg_pos;
-
- /*
- * Round to page boundaries, and allocate kernel copy
- */
- u_arg_page_start = trunc_page(u_arg_start);
- arg_page_size = (vm_size_t)(round_page(u_arg_start + arg_len)
- - u_arg_page_start);
-
- vm_allocate(mach_task_self(),
- &k_arg_page_start,
- (vm_size_t)arg_page_size,
- TRUE);
-
- /*
- * Set up addresses corresponding to user pointers
- * in the kernel block
- */
- k_arg_start = k_arg_page_start + (u_arg_start - u_arg_page_start);
-
- k_ap = (char **)k_arg_start;
-
- /*
- * Start the strings after the arg-count and pointers
- */
- u_cp = (char *)u_arg_start + arg_count * sizeof(char *)
- + 2 * sizeof(char *)
- + sizeof(integer_t);
- k_cp = (char *)k_arg_start + arg_count * sizeof(char *)
- + 2 * sizeof(char *)
- + sizeof(integer_t);
-
- /*
- * first the argument count
- */
- *k_ap++ = (char *)(natural_t)arg_count;
-
- /*
- * Then the strings and string pointers for each argument
- */
- va_start(argv_ptr);
- for (i = 0; i < arg_count; i++) {
- arg_ptr = va_arg(argv_ptr, char *);
- arg_item_len = strlen(arg_ptr) + 1; /* include trailing 0 */
-
- /* set string pointer */
- *k_ap++ = u_cp;
-
- /* copy string */
- bcopy(arg_ptr, k_cp, arg_item_len);
- k_cp += arg_item_len;
- u_cp += arg_item_len;
- }
- va_end(argv_ptr);
-
- /*
- * last, the trailing 0 argument and a null environment pointer.
- */
- *k_ap++ = (char *)0;
- *k_ap = (char *)0;
-
- /*
- * Now write all of this to user space.
- */
- (void) vm_write(user_task,
- u_arg_page_start,
- k_arg_page_start,
- arg_page_size);
-
- (void) vm_deallocate(mach_task_self(),
- k_arg_page_start,
- arg_page_size);
- }
-}
-
-
void
msg_thread()
{
@@ -793,7 +779,7 @@ struct qr
struct qr *qrhead, *qrtail;
/* Queue a read for later reply. */
-void
+kern_return_t
queue_read (enum read_type type,
mach_port_t reply_port,
mach_msg_type_name_t reply_type,
@@ -801,9 +787,12 @@ queue_read (enum read_type type,
{
struct qr *qr;
+ qr = malloc (sizeof (struct qr));
+ if (!qr)
+ return D_NO_MEMORY;
+
spin_lock (&queuelock);
- qr = malloc (sizeof (struct qr));
qr->type = type;
qr->reply_port = reply_port;
qr->reply_type = reply_type;
@@ -815,6 +804,7 @@ queue_read (enum read_type type,
qrhead = qrtail = qr;
spin_unlock (&queuelock);
+ return D_SUCCESS;
}
/* TRUE if there's data available on stdin, which should be used to satisfy
@@ -837,7 +827,7 @@ read_reply ()
if (! spin_try_lock (&readlock))
return;
- /* Since we're commited to servicing the read, no one else need do so. */
+ /* Since we're committed to servicing the read, no one else need do so. */
should_read = 0;
ioctl (0, FIONREAD, &avail);
@@ -864,7 +854,7 @@ read_reply ()
spin_unlock (&queuelock);
if (qr->type == DEV_READ)
- vm_allocate (mach_task_self (), (vm_address_t *)&buf, qr->amount, 1);
+ buf = mmap (0, qr->amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
else
buf = alloca (qr->amount);
amtread = read (0, buf, qr->amount);
@@ -1000,6 +990,8 @@ ds_device_open (mach_port_t master_port,
mach_port_t *device,
mach_msg_type_name_t *devicetype)
{
+ struct dev_map *map;
+
if (master_port != pseudo_master_device_port)
return D_INVALID_OPERATION;
@@ -1015,6 +1007,20 @@ ds_device_open (mach_port_t master_port,
*devicetype = MACH_MSG_TYPE_MAKE_SEND;
return 0;
}
+ else if (strcmp (name, "pseudo-root") == 0)
+ /* Magic root device. */
+ {
+ *device = pseudo_root;
+ *devicetype = MACH_MSG_TYPE_MAKE_SEND;
+ return 0;
+ }
+
+ map = lookup_dev (name);
+ if (map)
+ {
+ *devicetype = MACH_MSG_TYPE_MOVE_SEND;
+ return device_open (map->port, mode, "", device);
+ }
*devicetype = MACH_MSG_TYPE_MOVE_SEND;
return device_open (master_device_port, mode, name, device);
@@ -1023,7 +1029,7 @@ ds_device_open (mach_port_t master_port,
kern_return_t
ds_device_close (device_t device)
{
- if (device != pseudo_console)
+ if (device != pseudo_console && device != pseudo_root)
return D_NO_SUCH_DEVICE;
return 0;
}
@@ -1035,24 +1041,34 @@ ds_device_write (device_t device,
dev_mode_t mode,
recnum_t recnum,
io_buf_ptr_t data,
- unsigned int datalen,
+ size_t datalen,
int *bytes_written)
{
- if (device != pseudo_console)
- return D_NO_SUCH_DEVICE;
-
-#if 0
- if (console_send_rights)
+ if (device == pseudo_console)
{
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
- }
+#if 0
+ if (console_send_rights)
+ {
+ mach_port_mod_refs (mach_task_self (), pseudo_console,
+ MACH_PORT_TYPE_SEND, -console_send_rights);
+ console_send_rights = 0;
+ }
#endif
- *bytes_written = write (1, data, datalen);
+ *bytes_written = write (1, data, datalen);
- return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+ return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+ }
+ else if (device == pseudo_root)
+ {
+ size_t wrote;
+ if (store_write (root_store, recnum, data, datalen, &wrote) != 0)
+ return D_IO_ERROR;
+ *bytes_written = wrote;
+ return D_SUCCESS;
+ }
+ else
+ return D_NO_SUCH_DEVICE;
}
kern_return_t
@@ -1062,24 +1078,34 @@ ds_device_write_inband (device_t device,
dev_mode_t mode,
recnum_t recnum,
io_buf_ptr_inband_t data,
- unsigned int datalen,
+ size_t datalen,
int *bytes_written)
{
- if (device != pseudo_console)
- return D_NO_SUCH_DEVICE;
-
-#if 0
- if (console_send_rights)
+ if (device == pseudo_console)
{
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
- }
+#if 0
+ if (console_send_rights)
+ {
+ mach_port_mod_refs (mach_task_self (), pseudo_console,
+ MACH_PORT_TYPE_SEND, -console_send_rights);
+ console_send_rights = 0;
+ }
#endif
- *bytes_written = write (1, data, datalen);
+ *bytes_written = write (1, data, datalen);
- return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+ return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS);
+ }
+ else if (device == pseudo_root)
+ {
+ size_t wrote;
+ if (store_write (root_store, recnum, data, datalen, &wrote) != 0)
+ return D_IO_ERROR;
+ *bytes_written = wrote;
+ return D_SUCCESS;
+ }
+ else
+ return D_NO_SUCH_DEVICE;
}
kern_return_t
@@ -1090,37 +1116,51 @@ ds_device_read (device_t device,
recnum_t recnum,
int bytes_wanted,
io_buf_ptr_t *data,
- unsigned int *datalen)
+ size_t *datalen)
{
- int avail;
-
- if (device != pseudo_console)
- return D_NO_SUCH_DEVICE;
+ if (device == pseudo_console)
+ {
+ int avail;
#if 0
- if (console_send_rights)
- {
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
- }
+ if (console_send_rights)
+ {
+ mach_port_mod_refs (mach_task_self (), pseudo_console,
+ MACH_PORT_TYPE_SEND, -console_send_rights);
+ console_send_rights = 0;
+ }
#endif
- spin_lock (&readlock);
- ioctl (0, FIONREAD, &avail);
- if (avail)
- {
- vm_allocate (mach_task_self (), (pointer_t *)data, bytes_wanted, 1);
- *datalen = read (0, *data, bytes_wanted);
- unlock_readlock ();
- return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
+ spin_lock (&readlock);
+ ioctl (0, FIONREAD, &avail);
+ if (avail)
+ {
+ *data = mmap (0, bytes_wanted, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ *datalen = read (0, *data, bytes_wanted);
+ unlock_readlock ();
+ return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
+ }
+ else
+ {
+ kern_return_t err;
+
+ unlock_readlock ();
+ err = queue_read (DEV_READ, reply_port, reply_type, bytes_wanted);
+ if (err)
+ return err;
+ return MIG_NO_REPLY;
+ }
}
- else
+ else if (device == pseudo_root)
{
- unlock_readlock ();
- queue_read (DEV_READ, reply_port, reply_type, bytes_wanted);
- return MIG_NO_REPLY;
+ *datalen = 0;
+ return
+ (store_read (root_store, recnum, bytes_wanted, (void **)data, datalen) == 0
+ ? D_SUCCESS
+ : D_IO_ERROR);
}
+ else
+ return D_NO_SUCH_DEVICE;
}
kern_return_t
@@ -1131,43 +1171,70 @@ ds_device_read_inband (device_t device,
recnum_t recnum,
int bytes_wanted,
io_buf_ptr_inband_t data,
- unsigned int *datalen)
+ size_t *datalen)
{
- int avail;
-
- if (device != pseudo_console)
- return D_NO_SUCH_DEVICE;
+ if (device == pseudo_console)
+ {
+ int avail;
#if 0
- if (console_send_rights)
- {
- mach_port_mod_refs (mach_task_self (), pseudo_console,
- MACH_PORT_TYPE_SEND, -console_send_rights);
- console_send_rights = 0;
- }
+ if (console_send_rights)
+ {
+ mach_port_mod_refs (mach_task_self (), pseudo_console,
+ MACH_PORT_TYPE_SEND, -console_send_rights);
+ console_send_rights = 0;
+ }
#endif
- spin_lock (&readlock);
- ioctl (0, FIONREAD, &avail);
- if (avail)
- {
- *datalen = read (0, data, bytes_wanted);
- unlock_readlock ();
- return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
+ spin_lock (&readlock);
+ ioctl (0, FIONREAD, &avail);
+ if (avail)
+ {
+ *datalen = read (0, data, bytes_wanted);
+ unlock_readlock ();
+ return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS);
+ }
+ else
+ {
+ kern_return_t err;
+
+ unlock_readlock ();
+ err = queue_read (DEV_READI, reply_port, reply_type, bytes_wanted);
+ if (err)
+ return err;
+ return MIG_NO_REPLY;
+ }
}
- else
+ else if (device == pseudo_root)
{
- unlock_readlock ();
- queue_read (DEV_READI, reply_port, reply_type, bytes_wanted);
- return MIG_NO_REPLY;
+ error_t err;
+ void *returned = data;
+
+ *datalen = bytes_wanted;
+ err =
+ store_read (root_store, recnum, bytes_wanted, (void **)&returned, datalen);
+
+ if (! err)
+ {
+ if (returned != data)
+ {
+ bcopy (returned, (void *)data, *datalen);
+ munmap ((caddr_t) returned, *datalen);
+ }
+ return D_SUCCESS;
+ }
+ else
+ return D_IO_ERROR;
}
+ else
+ return D_NO_SUCH_DEVICE;
}
kern_return_t
ds_xxx_device_set_status (device_t device,
dev_flavor_t flavor,
dev_status_t status,
- u_int statu_cnt)
+ size_t statu_cnt)
{
if (device != pseudo_console)
return D_NO_SUCH_DEVICE;
@@ -1178,9 +1245,9 @@ kern_return_t
ds_xxx_device_get_status (device_t device,
dev_flavor_t flavor,
dev_status_t status,
- u_int *statuscnt)
+ size_t *statuscnt)
{
- if (device != pseudo_console)
+ if (device != pseudo_console && device != pseudo_root)
return D_NO_SUCH_DEVICE;
return D_INVALID_OPERATION;
}
@@ -1190,9 +1257,9 @@ ds_xxx_device_set_filter (device_t device,
mach_port_t rec,
int pri,
filter_array_t filt,
- unsigned int len)
+ size_t len)
{
- if (device != pseudo_console)
+ if (device != pseudo_console && device != pseudo_root)
return D_NO_SUCH_DEVICE;
return D_INVALID_OPERATION;
}
@@ -1205,7 +1272,7 @@ ds_device_map (device_t device,
memory_object_t *pager,
int unmap)
{
- if (device != pseudo_console)
+ if (device != pseudo_console && device != pseudo_root)
return D_NO_SUCH_DEVICE;
return D_INVALID_OPERATION;
}
@@ -1214,9 +1281,9 @@ kern_return_t
ds_device_set_status (device_t device,
dev_flavor_t flavor,
dev_status_t status,
- unsigned int statuslen)
+ size_t statuslen)
{
- if (device != pseudo_console)
+ if (device != pseudo_console && device != pseudo_root)
return D_NO_SUCH_DEVICE;
return D_INVALID_OPERATION;
}
@@ -1225,11 +1292,25 @@ kern_return_t
ds_device_get_status (device_t device,
dev_flavor_t flavor,
dev_status_t status,
- unsigned int *statuslen)
+ size_t *statuslen)
{
- if (device != pseudo_console)
+ if (device == pseudo_console)
+ return D_INVALID_OPERATION;
+ else if (device == pseudo_root)
+ if (flavor == DEV_GET_SIZE)
+ if (*statuslen < DEV_GET_SIZE_COUNT)
+ return D_INVALID_SIZE;
+ else
+ {
+ status[DEV_GET_SIZE_DEVICE_SIZE] = root_store->size;
+ status[DEV_GET_SIZE_RECORD_SIZE] = root_store->block_size;
+ *statuslen = DEV_GET_SIZE_COUNT;
+ return D_SUCCESS;
+ }
+ else
+ return D_INVALID_OPERATION;
+ else
return D_NO_SUCH_DEVICE;
- return D_INVALID_OPERATION;
}
kern_return_t
@@ -1237,9 +1318,9 @@ ds_device_set_filter (device_t device,
mach_port_t receive_port,
int priority,
filter_array_t filter,
- unsigned int filterlen)
+ size_t filterlen)
{
- if (device != pseudo_console)
+ if (device != pseudo_console && device != pseudo_root)
return D_NO_SUCH_DEVICE;
return D_INVALID_OPERATION;
}
@@ -1383,15 +1464,18 @@ S_io_read (mach_port_t object,
if (avail)
{
if (amount > *datalen)
- vm_allocate (mach_task_self (), (vm_address_t *) data, amount, 1);
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
*datalen = read (0, *data, amount);
unlock_readlock ();
return *datalen == -1 ? errno : 0;
}
else
{
+ kern_return_t err;
unlock_readlock ();
- queue_read (IO_READ, reply_port, reply_type, amount);
+ err = queue_read (IO_READ, reply_port, reply_type, amount);
+ if (err)
+ return err;
return MIG_NO_REPLY;
}
}
@@ -1554,11 +1638,16 @@ S_io_reauthenticate (mach_port_t object,
{
uid_t *gu, *au;
gid_t *gg, *ag;
- unsigned int gulen = 0, aulen = 0, gglen = 0, aglen = 0;
+ size_t gulen = 0, aulen = 0, gglen = 0, aglen = 0;
+ error_t err;
+
+ err = mach_port_insert_right (mach_task_self (), object, object,
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
if (! auth_server_authenticate (authserver,
rend, MACH_MSG_TYPE_COPY_SEND,
- object, MACH_MSG_TYPE_MAKE_SEND,
+ object, MACH_MSG_TYPE_COPY_SEND,
&gu, &gulen,
&au, &aulen,
&gg, &gglen,
@@ -1570,6 +1659,7 @@ S_io_reauthenticate (mach_port_t object,
mig_deallocate ((vm_address_t) au, aulen * sizeof *gu);
}
mach_port_deallocate (mach_task_self (), rend);
+ mach_port_deallocate (mach_task_self (), object);
return 0;
}
@@ -1581,9 +1671,9 @@ S_io_restrict_auth (mach_port_t object,
mach_port_t *newobject,
mach_msg_type_name_t *newobjtype,
uid_t *uids,
- u_int nuids,
+ size_t nuids,
uid_t *gids,
- u_int ngids)
+ size_t ngids)
{
if (object != pseudo_console)
return EOPNOTSUPP;
@@ -1730,7 +1820,14 @@ S_io_identity (mach_port_t obj,
mach_msg_type_name_t *idtype,
mach_port_t *fsid,
mach_msg_type_name_t *fsidtype,
- int *fileno)
+ ino_t *fileno)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_io_revoke (mach_port_t obj,
+ mach_port_t reply, mach_msg_type_name_t replyPoly)
{
return EOPNOTSUPP;
}
@@ -1791,6 +1888,13 @@ kern_return_t S_term_get_nodename
)
{ return EOPNOTSUPP; }
+kern_return_t S_term_get_peername
+(
+ io_t terminal,
+ string_t name
+)
+{ return EOPNOTSUPP; }
+
kern_return_t S_term_set_filenode
(
io_t terminal,
diff --git a/boot/boot_script.c b/boot/boot_script.c
index 618830f2..6fd449b2 100644
--- a/boot/boot_script.c
+++ b/boot/boot_script.c
@@ -2,15 +2,13 @@
/* Written by Shantanu Goel (goel@cs.columbia.edu). */
-#include <mach.h>
-#include <stdio.h>
+#include <mach/mach_types.h>
+#if !KERNEL || OSKIT_MACH
+#include <string.h>
+#endif
#include "boot_script.h"
-extern void *malloc (int size);
-extern void free (void *ptr);
-
-
/* This structure describes a symbol. */
struct sym
{
@@ -21,7 +19,7 @@ struct sym
int type;
/* Symbol value. */
- int val;
+ integer_t val;
/* For function symbols; type of value returned by function. */
int ret_type;
@@ -35,8 +33,8 @@ struct sym
/* Additional values symbols can take.
These are only used internally. */
-#define VAL_SYM 3 /* symbol table entry */
-#define VAL_FUNC 4 /* function pointer */
+#define VAL_SYM 10 /* symbol table entry */
+#define VAL_FUNC 11 /* function pointer */
/* This structure describes an argument. */
struct arg
@@ -48,7 +46,7 @@ struct arg
int type;
/* Argument value. */
- int val;
+ integer_t val;
};
/* List of commands. */
@@ -68,72 +66,37 @@ static int symtab_alloc = 0;
/* Next available slot in `symtab'. */
static int symtab_index = 0;
-
-void memset (void *str, char c, int size);
-/* Create a task. */
+/* Create a task and suspend it. */
static int
create_task (struct cmd *cmd, int *val)
{
- if (task_create (mach_task_self (), 0, (task_t *) &cmd->task) ||
- task_suspend (cmd->task))
- {
- printf ("(bootstrap): %s: Cannot create task\n", cmd->path);
- return BOOT_SCRIPT_MACH_ERROR;
- }
+ int err = boot_script_task_create (cmd);
*val = (int) cmd->task;
- return 0;
+ return err;
}
/* Resume a task. */
static int
resume_task (struct cmd *cmd, int *val)
{
- if (task_resume (cmd->task))
- {
- printf ("(bootstrap): %s: Cannot resume task\n", cmd->path);
- return BOOT_SCRIPT_MACH_ERROR;
- }
- return 0;
+ return boot_script_task_resume (cmd);
}
/* Resume a task when the user hits return. */
static int
prompt_resume_task (struct cmd *cmd, int *val)
{
- char c;
-
- printf ("Hit return to resume %s...", cmd->path);
- safe_gets (&c, 1);
-
- if (task_resume (cmd->task))
- {
- printf ("(bootstrap): %s: Cannot resume task\n", cmd->path);
- return BOOT_SCRIPT_MACH_ERROR;
- }
-
- return 0;
-}
-
-static int
-read_file (struct cmd *cmd, int *val)
-{
- *val = boot_script_read_file (cmd->path);
- if (*val == 0)
- {
- printf ("(bootstrap): %s: Cannot read boot script\n", cmd->path);
- return BOOT_SCRIPT_MACH_ERROR;
- }
- return 0;
+ return boot_script_prompt_task_resume (cmd);
}
/* List of builtin symbols. */
static struct sym builtin_symbols[] =
{
- { "task-create", VAL_FUNC, (int) create_task, VAL_PORT, 0 },
- { "task-resume", VAL_FUNC, (int) resume_task, VAL_NONE, 1 },
- { "prompt-task-resume", VAL_FUNC, (int) prompt_resume_task, VAL_NONE, 1 },
- { "read-file", VAL_FUNC, (int) read_file, VAL_PORT, 0 },
+ { "task-create", VAL_FUNC, (integer_t) create_task, VAL_TASK, 0 },
+ { "task-resume", VAL_FUNC, (integer_t) resume_task, VAL_NONE, 1 },
+ { "prompt-task-resume",
+ VAL_FUNC, (integer_t) prompt_resume_task, VAL_NONE, 1 },
};
#define NUM_BUILTIN (sizeof (builtin_symbols) / sizeof (builtin_symbols[0]))
@@ -144,23 +107,18 @@ static void
free_cmd (struct cmd *cmd, int aborting)
{
if (cmd->task)
- {
- if (aborting)
- task_terminate (cmd->task);
- else
- mach_port_deallocate (mach_task_self (), cmd->task);
- }
+ boot_script_free_task (cmd->task, aborting);
if (cmd->args)
{
int i;
-
for (i = 0; i < cmd->args_index; i++)
- free (cmd->args[i]);
- free (cmd->args);
+ boot_script_free (cmd->args[i], sizeof *cmd->args[i]);
+ boot_script_free (cmd->args, sizeof cmd->args[0] * cmd->args_alloc);
}
if (cmd->exec_funcs)
- free (cmd->exec_funcs);
- free (cmd);
+ boot_script_free (cmd->exec_funcs,
+ sizeof cmd->exec_funcs[0] * cmd->exec_funcs_alloc);
+ boot_script_free (cmd, sizeof *cmd);
}
/* Free all storage allocated by the parser.
@@ -172,13 +130,13 @@ cleanup (int aborting)
for (i = 0; i < cmds_index; i++)
free_cmd (cmds[i], aborting);
- free (cmds);
+ boot_script_free (cmds, sizeof cmds[0] * cmds_alloc);
cmds = 0;
cmds_index = cmds_alloc = 0;
for (i = 0; i < symtab_index; i++)
- free (symtab[i]);
- free (symtab);
+ boot_script_free (symtab[i], sizeof *symtab[i]);
+ boot_script_free (symtab, sizeof symtab[0] * symtab_alloc);
symtab = 0;
symtab_index = symtab_alloc = 0;
}
@@ -196,7 +154,7 @@ add_list (void *ptr, void ***ptr_list, int *alloc, int *index, int incr)
void **p;
*alloc += incr;
- p = malloc (*alloc * sizeof (void *));
+ p = boot_script_malloc (*alloc * sizeof (void *));
if (! p)
{
*alloc -= incr;
@@ -205,7 +163,7 @@ add_list (void *ptr, void ***ptr_list, int *alloc, int *index, int incr)
if (*ptr_list)
{
memcpy (p, *ptr_list, *index * sizeof (void *));
- free (*ptr_list);
+ boot_script_free (*ptr_list, (*alloc - incr) * sizeof (void *));
}
*ptr_list = p;
}
@@ -217,20 +175,20 @@ add_list (void *ptr, void ***ptr_list, int *alloc, int *index, int incr)
/* Create an argument with TEXT, value type TYPE, and value VAL.
Add the argument to the argument list of CMD. */
static struct arg *
-add_arg (struct cmd *cmd, char *text, int type, int val)
+add_arg (struct cmd *cmd, const char *text, int textlen, int type, int val)
{
struct arg *arg;
- arg = malloc (sizeof (struct arg));
+ arg = boot_script_malloc (sizeof (struct arg) + textlen);
if (arg)
{
- arg->text = text;
+ arg->text = text == 0 ? 0 : memcpy (arg + 1, text, textlen);
arg->type = type;
arg->val = val;
if (add_list (arg, (void ***) &cmd->args,
&cmd->args_alloc, &cmd->args_index, 5))
{
- free (arg);
+ boot_script_free (arg, sizeof *arg);
return 0;
}
}
@@ -255,14 +213,14 @@ sym_enter (const char *name)
{
struct sym *sym;
- sym = malloc (sizeof (struct sym));
+ sym = boot_script_malloc (sizeof (struct sym));
if (sym)
{
memset (sym, 0, sizeof (struct sym));
sym->name = name;
if (add_list (sym, (void ***) &symtab, &symtab_alloc, &symtab_index, 20))
{
- free (sym);
+ boot_script_free (sym, sizeof *sym);
return 0;
}
}
@@ -271,7 +229,7 @@ sym_enter (const char *name)
/* Parse the command line CMDLINE. */
int
-boot_script_parse_line (char *cmdline)
+boot_script_parse_line (void *hook, char *cmdline)
{
char *p, *q;
int error;
@@ -285,22 +243,28 @@ boot_script_parse_line (char *cmdline)
/* Ignore comment line. */
return 0;
+#if 0
if (*p && *p != ' ' && *p != '\t' && *p != '\n')
- printf ("(bootstrap): %s\n", cmdline);
+ {
+ printf ("(bootstrap): %s\n", cmdline);
+ }
+#endif
for (q = p; *q && *q != ' ' && *q != '\t' && *q != '\n'; q++)
;
if (p == q)
- return 0;
- *q = '\0';
+ return 0;
+
+ *q++ = '\0';
/* Allocate a command structure. */
- cmd = malloc (sizeof (struct cmd));
+ cmd = boot_script_malloc (sizeof (struct cmd) + (q - p));
if (! cmd)
return BOOT_SCRIPT_NOMEM;
memset (cmd, 0, sizeof (struct cmd));
- cmd->path = p;
- p = q + 1;
+ cmd->hook = hook;
+ cmd->path = memcpy (cmd + 1, p, q - p);
+ p = q;
for (arg = 0;;)
{
@@ -333,7 +297,8 @@ boot_script_parse_line (char *cmdline)
for (p += 2;;)
{
char c;
- int i, val, type;
+ int i, type;
+ integer_t val;
struct sym *s;
/* Parse symbol name. */
@@ -388,7 +353,7 @@ boot_script_parse_line (char *cmdline)
if (! s->run_on_exec)
{
(error
- = ((*((int (*) (struct cmd *, int *)) s->val))
+ = ((*((int (*) (struct cmd *, integer_t *)) s->val))
(cmd, &val)));
if (error)
goto bad;
@@ -410,7 +375,7 @@ boot_script_parse_line (char *cmdline)
else if (s->type == VAL_NONE)
{
type = VAL_SYM;
- val = (int) s;
+ val = (integer_t) s;
}
else
{
@@ -443,7 +408,7 @@ boot_script_parse_line (char *cmdline)
associated with an argument. */
if (! arg && end_char == '}')
{
- if (! add_arg (cmd, 0, type, val))
+ if (! add_arg (cmd, 0, 0, type, val))
{
error = BOOT_SCRIPT_NOMEM;
goto bad;
@@ -472,7 +437,7 @@ boot_script_parse_line (char *cmdline)
*q = '\0';
/* Add argument to list. */
- arg = add_arg (cmd, p, VAL_NONE, 0);
+ arg = add_arg (cmd, p, q + 1 - p, VAL_NONE, 0);
if (! arg)
{
error = BOOT_SCRIPT_NOMEM;
@@ -491,6 +456,7 @@ boot_script_parse_line (char *cmdline)
}
}
+
bad:
free_cmd (cmd, 1);
cleanup (1);
@@ -505,7 +471,7 @@ boot_script_parse_line (char *cmdline)
char *ptr; \
int alloc, i; \
alloc = cmdline_alloc + len - (cmdline_alloc - cmdline_index) + 100; \
- ptr = malloc (alloc); \
+ ptr = boot_script_malloc (alloc); \
if (! ptr) \
{ \
error = BOOT_SCRIPT_NOMEM; \
@@ -514,7 +480,7 @@ boot_script_parse_line (char *cmdline)
memcpy (ptr, cmdline, cmdline_index); \
for (i = 0; i < argc; ++i) \
argv[i] = ptr + (argv[i] - cmdline); \
- free (cmdline); \
+ boot_script_free (cmdline, cmdline_alloc); \
cmdline = ptr; \
cmdline_alloc = alloc; \
} \
@@ -540,7 +506,7 @@ boot_script_exec ()
/* Allocate a command line and copy command name. */
cmdline_index = strlen (cmd->path) + 1;
cmdline_alloc = cmdline_index + 100;
- cmdline = malloc (cmdline_alloc);
+ cmdline = boot_script_malloc (cmdline_alloc);
if (! cmdline)
{
cleanup (1);
@@ -549,10 +515,10 @@ boot_script_exec ()
memcpy (cmdline, cmd->path, cmdline_index);
/* Allocate argument vector. */
- argv = malloc (sizeof (char *) * (cmd->args_index + 2));
+ argv = boot_script_malloc (sizeof (char *) * (cmd->args_index + 2));
if (! argv)
{
- free (cmdline);
+ boot_script_free (cmdline, cmdline_alloc);
cleanup (1);
return BOOT_SCRIPT_NOMEM;
}
@@ -582,6 +548,7 @@ boot_script_exec ()
{
char *p, buf[50];
int len;
+ mach_port_t name;
if (arg->type == VAL_SYM)
{
@@ -607,19 +574,21 @@ boot_script_exec ()
len = strlen (p);
break;
+ case VAL_TASK:
case VAL_PORT:
- /* Insert send right. */
- if ((mach_port_insert_right
- (cmd->task, (mach_port_t) arg->val,
- (mach_port_t) arg->val, MACH_MSG_TYPE_COPY_SEND)))
- {
- printf ("(bootstrap): %s: Cannot insert port right %d\n",
- cmd->path, arg->val);
- error = BOOT_SCRIPT_MACH_ERROR;
- goto done;
- }
-
- i = arg->val;
+ if (arg->type == VAL_TASK)
+ /* Insert send right to task port. */
+ error = boot_script_insert_task_port
+ (cmd, (task_t) arg->val, &name);
+ else
+ /* Insert send right. */
+ error = boot_script_insert_right (cmd,
+ (mach_port_t) arg->val,
+ &name);
+ if (error)
+ goto done;
+
+ i = name;
p = buf + sizeof (buf);
len = 0;
do
@@ -648,7 +617,7 @@ boot_script_exec ()
argv[argc] = 0;
/* Execute the command. */
- if (boot_script_exec_cmd (cmd->task, cmd->path,
+ if (boot_script_exec_cmd (cmd->hook, cmd->task, cmd->path,
argc, argv, cmdline, cmdline_index))
{
error = BOOT_SCRIPT_EXEC_ERROR;
@@ -658,8 +627,8 @@ boot_script_exec ()
error = 0;
done:
- free (cmdline);
- free (argv);
+ boot_script_free (cmdline, cmdline_alloc);
+ boot_script_free (argv, sizeof (char *) * (cmd->args_index + 2));
if (error)
{
cleanup (1);
@@ -676,7 +645,7 @@ boot_script_exec ()
for (i = 0; i < cmd->exec_funcs_index; i++)
{
struct sym *sym = cmd->exec_funcs[i];
- int error = ((*((int (*) (struct cmd *, int *)) sym->val))
+ int error = ((*((int (*) (struct cmd *, integer_t *)) sym->val))
(cmd, 0));
if (error)
{
@@ -693,7 +662,7 @@ boot_script_exec ()
/* Create an entry for the variable NAME with TYPE and value VAL,
in the symbol table. */
int
-boot_script_set_variable (const char *name, int type, int val)
+boot_script_set_variable (const char *name, int type, integer_t val)
{
struct sym *sym = sym_enter (name);
@@ -709,14 +678,15 @@ boot_script_set_variable (const char *name, int type, int val)
/* Define the function NAME, which will return type RET_TYPE. */
int
boot_script_define_function (const char *name, int ret_type,
- int (*func) (const struct cmd *cmd, int *val))
+ int (*func) (const struct cmd *cmd,
+ integer_t *val))
{
struct sym *sym = sym_enter (name);
if (sym)
{
sym->type = VAL_FUNC;
- sym->val = (int) func;
+ sym->val = (integer_t) func;
sym->ret_type = ret_type;
sym->run_on_exec = ret_type == VAL_NONE;
}
@@ -761,7 +731,8 @@ boot_script_error_string (int err)
#include <stdio.h>
int
-boot_script_exec_cmd (mach_port_t task, char *path, int argc,
+boot_script_exec_cmd (void *hook,
+ mach_port_t task, char *path, int argc,
char **argv, char *strings, int stringlen)
{
int i;
@@ -805,7 +776,7 @@ main (int argc, char **argv)
int i, err;
i = strlen (p) + 1;
- err = boot_script_parse_line (p);
+ err = boot_script_parse_line (0, p);
if (err)
{
fprintf (stderr, "error %s\n", boot_script_error_string (err));
diff --git a/boot/boot_script.h b/boot/boot_script.h
index d2db1a14..62458693 100644
--- a/boot/boot_script.h
+++ b/boot/boot_script.h
@@ -1,5 +1,8 @@
/* Definitions for boot script parser for Mach. */
+#ifndef _boot_script_h
+#define _boot_script_h
+
/* Written by Shantanu Goel (goel@cs.columbia.edu). */
/* Error codes returned by boot_script_parse_line()
@@ -18,15 +21,19 @@
#define VAL_NONE 0 /* none -- function runs at exec time */
#define VAL_STR 1 /* string */
#define VAL_PORT 2 /* port */
+#define VAL_TASK 3 /* task port */
/* This structure describes a command. */
struct cmd
{
+ /* Cookie passed in to boot_script_parse_line. */
+ void *hook;
+
/* Path of executable. */
char *path;
/* Task port. */
- mach_port_t task;
+ task_t task;
/* Argument list. */
struct arg **args;
@@ -48,19 +55,37 @@ struct cmd
};
+/* The user must define these functions, we work like malloc and free. */
+void *boot_script_malloc (unsigned int);
+void boot_script_free (void *, unsigned int);
+
/* The user must define this function. Load the image of the
executable specified by PATH in TASK. Create a thread
in TASK and point it at the executable's entry point. Initialize
TASK's stack with argument vector ARGV of length ARGC whose
strings are STRINGS. STRINGS has length STRINGLEN.
Return 0 for success, non-zero otherwise. */
-int boot_script_exec_cmd (mach_port_t task, char *path, int argc,
+int boot_script_exec_cmd (void *hook,
+ task_t task, char *path, int argc,
char **argv, char *strings, int stringlen);
/* The user must define this function. Load the contents of FILE
into a fresh anonymous memory object and return the memory object port. */
mach_port_t boot_script_read_file (const char *file);
+/* The user must define this functions to perform the corresponding
+ Mach task manipulations. */
+int boot_script_task_create (struct cmd *); /* task_create + task_suspend */
+int boot_script_task_resume (struct cmd *);
+int boot_script_prompt_task_resume (struct cmd *);
+int boot_script_insert_right (struct cmd *, mach_port_t, mach_port_t *namep);
+int boot_script_insert_task_port (struct cmd *, task_t, mach_port_t *namep);
+
+/* The user must define this function to clean up the `task_t'
+ returned by boot_script_task_create. */
+void boot_script_free_task (task_t task, int aborting);
+
+
/* Parse the command line LINE. This causes the command line to be
converted into an internal format. Returns 0 for success, non-zero
otherwise.
@@ -68,7 +93,7 @@ mach_port_t boot_script_read_file (const char *file);
NOTE: The parser writes into the line so it must not be a string constant.
It is also the responsibility of the caller not to deallocate the line
across calls to the parser. */
-int boot_script_parse_line (char *cmdline);
+int boot_script_parse_line (void *hook, char *cmdline);
/* Execute the command lines prevously parsed.
Returns 0 for success, non-zero otherwise. */
@@ -77,14 +102,15 @@ int boot_script_exec (void);
/* Create an entry in the symbol table for variable NAME,
whose type is TYPE and value is VAL. Returns 0 on success,
non-zero otherwise. */
-int boot_script_set_variable (const char *name, int type, int val);
+int boot_script_set_variable (const char *name, int type, integer_t val);
/* Define the function NAME, which will return type RET_TYPE. */
int boot_script_define_function (const char *name, int ret_type,
- int (*func) (const struct cmd *cmd, int *val));
+ int (*func) (const struct cmd *cmd,
+ integer_t *val));
/* Returns a string describing the error ERR. */
char *boot_script_error_string (int err);
-
-void safe_gets (char *, int);
+
+#endif /* _boot_script_h */
diff --git a/boot/tcattr.c b/boot/tcattr.c
deleted file mode 100644
index fcd3293e..00000000
--- a/boot/tcattr.c
+++ /dev/null
@@ -1,592 +0,0 @@
-/* Copyright (C) 1991, 1993, 1995 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., 675 Mass Ave,
-Cambridge, MA 02139, USA. */
-
-#include <errno.h>
-#include <stddef.h>
-#include <termios.h>
-
-#undef B0
-#undef B50
-#undef B75
-#undef B110
-#undef B134
-#undef B150
-#undef B200
-#undef B300
-#undef B600
-#undef B1200
-#undef B1800
-#undef B2400
-#undef B4800
-#undef B9600
-#undef B19200
-#undef B38400
-#undef EXTA
-#undef EXTB
-#undef ECHO
-#undef TOSTOP
-#undef NOFLSH
-#undef MDMBUF
-#undef FLUSHO
-#undef PENDIN
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-#undef CERASE
-#undef CKILL
-#undef CINTR
-#undef CQUIT
-#undef CSTART
-#undef CSTOP
-#undef CEOF
-#undef CEOT
-#undef CBRK
-#undef CSUSP
-#undef CDSUSP
-#undef CRPRNT
-#undef CFLUSH
-#undef CWERASE
-#undef CLNEXT
-#undef CSTATUS
-
-#define IOCPARM_MASK 0x7f
-#define IOC_OUT 0x40000000
-#define IOC_IN 0x80000000
-#define _IOR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
-#define _IOW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)
-#define FIONREAD _IOR('f', 127, int)
-#define FIOASYNC _IOW('f', 125, int)
-#define TIOCGETP _IOR('t', 8, struct sgttyb)
-#define TIOCLGET _IOR('t', 124, int)
-#define TIOCLSET _IOW('t', 125, int)
-#define TIOCSETN _IOW('t', 10, struct sgttyb)
-#define TIOCSETP _IOW('t', 9,struct sgttyb)/* set parameters -- stty */
-#define TIOCFLUSH _IOW('t', 16, int) /* flush buffers */
-#define TIOCSETC _IOW('t',17,struct tchars)/* set special characters */
-#define TIOCGETC _IOR('t',18,struct tchars)/* get special characters */
-#define TANDEM 0x00000001 /* send stopc on out q full */
-#define CBREAK 0x00000002 /* half-cooked mode */
-#define LCASE 0x00000004 /* simulate lower case */
-#define ECHO 0x00000008 /* echo input */
-#define CRMOD 0x00000010 /* map \r to \r\n on output */
-#define RAW 0x00000020 /* no i/o processing */
-#define ODDP 0x00000040 /* get/send odd parity */
-#define EVENP 0x00000080 /* get/send even parity */
-#define ANYP 0x000000c0 /* get any parity/send none */
-#define PRTERA 0x00020000 /* \ ... / erase */
-#define CRTERA 0x00040000 /* " \b " to wipe out char */
-#define TILDE 0x00080000 /* hazeltine tilde kludge */
-#define MDMBUF 0x00100000 /* start/stop output on carrier intr */
-#define LITOUT 0x00200000 /* literal output */
-#define TOSTOP 0x00400000 /* SIGSTOP on background output */
-#define FLUSHO 0x00800000 /* flush output to terminal */
-#define NOHANG 0x01000000 /* no SIGHUP on carrier drop */
-#define L001000 0x02000000
-#define CRTKIL 0x04000000 /* kill line with " \b " */
-#define PASS8 0x08000000
-#define CTLECH 0x10000000 /* echo control chars as ^X */
-#define PENDIN 0x20000000 /* tp->t_rawq needs reread */
-#define DECCTQ 0x40000000 /* only ^Q starts after ^S */
-#define NOFLSH 0x80000000 /* no output flush on signal */
-#define TIOCLSET _IOW('t', 125, int) /* set entire local mode word */
-#define TIOCLGET _IOR('t', 124, int) /* get local modes */
-#define LCRTBS (CRTBS>>16)
-#define LPRTERA (PRTERA>>16)
-#define LCRTERA (CRTERA>>16)
-#define LTILDE (TILDE>>16)
-#define LMDMBUF (MDMBUF>>16)
-#define LLITOUT (LITOUT>>16)
-#define LTOSTOP (TOSTOP>>16)
-#define LFLUSHO (FLUSHO>>16)
-#define LNOHANG (NOHANG>>16)
-#define LCRTKIL (CRTKIL>>16)
-#define LPASS8 (PASS8>>16)
-#define LCTLECH (CTLECH>>16)
-#define LPENDIN (PENDIN>>16)
-#define LDECCTQ (DECCTQ>>16)
-#define LNOFLSH (NOFLSH>>16)
-#define TIOCSLTC _IOW('t',117,struct ltchars)/* set local special chars */
-#define TIOCGLTC _IOR('t',116,struct ltchars)/* get local special chars */
-
-
-#if defined(TIOCGETC) || defined(TIOCSETC)
-/* Type of ARG for TIOCGETC and TIOCSETC requests. */
-struct tchars
-{
- char t_intrc; /* Interrupt character. */
- char t_quitc; /* Quit character. */
- char t_startc; /* Start-output character. */
- char t_stopc; /* Stop-output character. */
- char t_eofc; /* End-of-file character. */
- char t_brkc; /* Input delimiter character. */
-};
-
-#define _IOT_tchars /* Hurd ioctl type field. */ \
- _IOT (_IOTS (char), 6, 0, 0, 0, 0)
-#endif
-
-#if defined(TIOCGLTC) || defined(TIOCSLTC)
-/* Type of ARG for TIOCGLTC and TIOCSLTC requests. */
-struct ltchars
-{
- char t_suspc; /* Suspend character. */
- char t_dsuspc; /* Delayed suspend character. */
- char t_rprntc; /* Reprint-line character. */
- char t_flushc; /* Flush-output character. */
- char t_werasc; /* Word-erase character. */
- char t_lnextc; /* Literal-next character. */
-};
-
-#define _IOT_ltchars /* Hurd ioctl type field. */ \
- _IOT (_IOTS (char), 6, 0, 0, 0, 0)
-#endif
-
-/* Type of ARG for TIOCGETP and TIOCSETP requests (and gtty and stty). */
-struct sgttyb
-{
- char sg_ispeed; /* Input speed. */
- char sg_ospeed; /* Output speed. */
- char sg_erase; /* Erase character. */
- char sg_kill; /* Kill character. */
- short int sg_flags; /* Mode flags. */
-};
-
-
-
-
-const speed_t __bsd_speeds[] =
- {
- 0,
- 50,
- 75,
- 110,
- 134,
- 150,
- 200,
- 300,
- 600,
- 1200,
- 1800,
- 2400,
- 4800,
- 9600,
- 19200,
- 38400,
- };
-
-extern int ioctl ();
-
-/* Set the state of FD to *TERMIOS_P. */
-int
-tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
-{
- struct sgttyb buf;
- struct tchars tchars;
- struct ltchars ltchars;
- int local;
-#ifdef TIOCGETX
- int extra;
-#endif
- size_t i;
-
- if (ioctl(fd, TIOCGETP, &buf) < 0 ||
- ioctl(fd, TIOCGETC, &tchars) < 0 ||
- ioctl(fd, TIOCGLTC, &ltchars) < 0 ||
-#ifdef TIOCGETX
- ioctl(fd, TIOCGETX, &extra) < 0 ||
-#endif
- ioctl(fd, TIOCLGET, &local) < 0)
- return -1;
-
- if (termios_p == NULL)
- {
- errno = EINVAL;
- return -1;
- }
-
- buf.sg_ispeed = buf.sg_ospeed = -1;
- for (i = 0; i <= sizeof (__bsd_speeds) / sizeof (__bsd_speeds[0]); ++i)
- {
- if (__bsd_speeds[i] == termios_p->__ispeed)
- buf.sg_ispeed = i;
- if (__bsd_speeds[i] == termios_p->__ospeed)
- buf.sg_ospeed = i;
- }
- if (buf.sg_ispeed == -1 || buf.sg_ospeed == -1)
- {
- errno = EINVAL;
- return -1;
- }
-
- buf.sg_flags &= ~(CBREAK|RAW);
- if (!(termios_p->c_lflag & ICANON))
- buf.sg_flags |= (termios_p->c_cflag & ISIG) ? CBREAK : RAW;
-#ifdef LPASS8
- if (termios_p->c_oflag & CS8)
- local |= LPASS8;
- else
- local &= ~LPASS8;
-#endif
- if (termios_p->c_lflag & _NOFLSH)
- local |= LNOFLSH;
- else
- local &= ~LNOFLSH;
- if (termios_p->c_oflag & OPOST)
- local &= ~LLITOUT;
- else
- local |= LLITOUT;
-#ifdef TIOCGETX
- if (termios_p->c_lflag & ISIG)
- extra &= ~NOISIG;
- else
- extra |= NOISIG;
- if (termios_p->c_cflag & CSTOPB)
- extra |= STOPB;
- else
- extra &= ~STOPB;
-#endif
- if (termios_p->c_iflag & ICRNL)
- buf.sg_flags |= CRMOD;
- else
- buf.sg_flags &= ~CRMOD;
- if (termios_p->c_iflag & IXOFF)
- buf.sg_flags |= TANDEM;
- else
- buf.sg_flags &= ~TANDEM;
-
- buf.sg_flags &= ~(ODDP|EVENP);
- if (!(termios_p->c_cflag & PARENB))
- buf.sg_flags |= ODDP | EVENP;
- else if (termios_p->c_cflag & PARODD)
- buf.sg_flags |= ODDP;
- else
- buf.sg_flags |= EVENP;
-
- if (termios_p->c_lflag & _ECHO)
- buf.sg_flags |= ECHO;
- else
- buf.sg_flags &= ~ECHO;
- if (termios_p->c_lflag & ECHOE)
- local |= LCRTERA;
- else
- local &= ~LCRTERA;
- if (termios_p->c_lflag & ECHOK)
- local |= LCRTKIL;
- else
- local &= ~LCRTKIL;
- if (termios_p->c_lflag & _TOSTOP)
- local |= LTOSTOP;
- else
- local &= ~LTOSTOP;
-
- buf.sg_erase = termios_p->c_cc[VERASE];
- buf.sg_kill = termios_p->c_cc[VKILL];
- tchars.t_eofc = termios_p->c_cc[VEOF];
- tchars.t_intrc = termios_p->c_cc[VINTR];
- tchars.t_quitc = termios_p->c_cc[VQUIT];
- ltchars.t_suspc = termios_p->c_cc[VSUSP];
- tchars.t_startc = termios_p->c_cc[VSTART];
- tchars.t_stopc = termios_p->c_cc[VSTOP];
-
- if (ioctl(fd, TIOCSETP, &buf) < 0 ||
- ioctl(fd, TIOCSETC, &tchars) < 0 ||
- ioctl(fd, TIOCSLTC, &ltchars) < 0 ||
-#ifdef TIOCGETX
- ioctl(fd, TIOCSETX, &extra) < 0 ||
-#endif
- ioctl(fd, TIOCLSET, &local) < 0)
- return -1;
- return 0;
-}
-
-
-#undef tcgetattr
-
-/* Put the state of FD into *TERMIOS_P. */
-int
-tcgetattr (int fd, struct termios *termios_p)
-{
- struct sgttyb buf;
- struct tchars tchars;
- struct ltchars ltchars;
- int local;
-#ifdef TIOCGETX
- int extra;
-#endif
-
- if (termios_p == NULL)
- {
- errno = EINVAL;
- return -1;
- }
-
- if (ioctl(fd, TIOCGETP, &buf) < 0 ||
- ioctl(fd, TIOCGETC, &tchars) < 0 ||
- ioctl(fd, TIOCGLTC, &ltchars) < 0 ||
-#ifdef TIOCGETX
- ioctl(fd, TIOCGETX, &extra) < 0 ||
-#endif
- ioctl(fd, TIOCLGET, &local) < 0)
- return -1;
-
- termios_p->__ispeed = __bsd_speeds[(unsigned char) buf.sg_ispeed];
- termios_p->__ospeed = __bsd_speeds[(unsigned char) buf.sg_ospeed];
-
- termios_p->c_iflag = 0;
- termios_p->c_oflag = 0;
- termios_p->c_cflag = 0;
- termios_p->c_lflag = 0;
- termios_p->c_oflag |= CREAD | HUPCL;
-#ifdef LPASS8
- if (local & LPASS8)
- termios_p->c_oflag |= CS8;
- else
-#endif
- termios_p->c_oflag |= CS7;
- if (!(buf.sg_flags & RAW))
- {
- termios_p->c_iflag |= IXON;
- termios_p->c_cflag |= OPOST;
-#ifndef NOISIG
- termios_p->c_lflag |= ISIG;
-#endif
- }
- if ((buf.sg_flags & (CBREAK|RAW)) == 0)
- termios_p->c_lflag |= ICANON;
- if (!(buf.sg_flags & RAW) && !(local & LLITOUT))
- termios_p->c_oflag |= OPOST;
- if (buf.sg_flags & CRMOD)
- termios_p->c_iflag |= ICRNL;
- if (buf.sg_flags & TANDEM)
- termios_p->c_iflag |= IXOFF;
-#ifdef TIOCGETX
- if (!(extra & NOISIG))
- termios_p->c_lflag |= ISIG;
- if (extra & STOPB)
- termios_p->c_cflag |= CSTOPB;
-#endif
-
- switch (buf.sg_flags & (EVENP|ODDP))
- {
- case EVENP|ODDP:
- break;
- case ODDP:
- termios_p->c_cflag |= PARODD;
- default:
- termios_p->c_cflag |= PARENB;
- termios_p->c_iflag |= IGNPAR | INPCK;
- break;
- }
- if (buf.sg_flags & ECHO)
- termios_p->c_lflag |= _ECHO;
- if (local & LCRTERA)
- termios_p->c_lflag |= ECHOE;
- if (local & LCRTKIL)
- termios_p->c_lflag |= ECHOK;
- if (local & LTOSTOP)
- termios_p->c_lflag |= _TOSTOP;
- if (local & LNOFLSH)
- termios_p->c_lflag |= _NOFLSH;
-
- termios_p->c_cc[VEOF] = tchars.t_eofc;
- termios_p->c_cc[VEOL] = '\n';
- termios_p->c_cc[VERASE] = buf.sg_erase;
- termios_p->c_cc[VKILL] = buf.sg_kill;
- termios_p->c_cc[VINTR] = tchars.t_intrc;
- termios_p->c_cc[VQUIT] = tchars.t_quitc;
- termios_p->c_cc[VSTART] = tchars.t_startc;
- termios_p->c_cc[VSTOP] = tchars.t_stopc;
- termios_p->c_cc[VSUSP] = ltchars.t_suspc;
- termios_p->c_cc[VMIN] = -1;
- termios_p->c_cc[VTIME] = -1;
-
- return 0;
-}
diff --git a/boot/userland-boot.c b/boot/userland-boot.c
new file mode 100644
index 00000000..d048c00e
--- /dev/null
+++ b/boot/userland-boot.c
@@ -0,0 +1,108 @@
+/* boot_script.c support functions for running in a Mach user task.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include "boot_script.h"
+
+void *
+boot_script_malloc (unsigned int size)
+{
+ return malloc (size);
+}
+
+void
+boot_script_free (void *ptr, unsigned int size)
+{
+ free (ptr);
+}
+
+
+int
+boot_script_task_create (struct cmd *cmd)
+{
+ error_t err = task_create (mach_task_self (), 0, &cmd->task);
+ if (err)
+ {
+ error (0, err, "%s: task_create", cmd->path);
+ return BOOT_SCRIPT_MACH_ERROR;
+ }
+ err = task_suspend (cmd->task);
+ if (err)
+ {
+ error (0, err, "%s: task_resume", cmd->path);
+ return BOOT_SCRIPT_MACH_ERROR;
+ }
+ return 0;
+}
+
+int
+boot_script_task_resume (struct cmd *cmd)
+{
+ error_t err = task_resume (cmd->task);
+ if (err)
+ {
+ error (0, err, "%s: task_resume", cmd->path);
+ return BOOT_SCRIPT_MACH_ERROR;
+ }
+ return 0;
+}
+
+int
+boot_script_prompt_task_resume (struct cmd *cmd)
+{
+ char xx[5];
+
+ printf ("Hit return to resume %s...", cmd->path);
+ fgets (xx, sizeof xx, stdin);
+
+ return boot_script_task_resume (cmd);
+}
+
+void
+boot_script_free_task (task_t task, int aborting)
+{
+ if (aborting)
+ task_terminate (task);
+ else
+ mach_port_deallocate (mach_task_self (), task);
+}
+
+int
+boot_script_insert_right (struct cmd *cmd, mach_port_t port, mach_port_t *name)
+{
+ error_t err = mach_port_insert_right (cmd->task,
+ port, port, MACH_MSG_TYPE_COPY_SEND);
+ if (err)
+ {
+ error (0, err, "%s: mach_port_insert_right", cmd->path);
+ return BOOT_SCRIPT_MACH_ERROR;
+ }
+ *name = port;
+ return 0;
+}
+
+int
+boot_script_insert_task_port (struct cmd *cmd, task_t task, mach_port_t *name)
+{
+ return boot_script_insert_right (cmd, task, name);
+}
diff --git a/bsdfsck/ChangeLog b/bsdfsck/ChangeLog
deleted file mode 100644
index 0a948518..00000000
--- a/bsdfsck/ChangeLog
+++ /dev/null
@@ -1,98 +0,0 @@
-Thu Jul 6 15:30:43 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (tables.o): Delete target.
- (vpath tables.c): Tell where to find tables.c.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Thu Nov 3 17:18:35 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (dir): Changed to bsdfsck.
- (target): Changed to bsdfsck.
-
-Thu Oct 6 13:19:25 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * dir.c (dircheck): Fix from Charles Hannum: dircheck() shouldn't
- be looking at d_type or d_namlen in blank entries *at all*. Not
- only is it wrong, but it causes a serious problem on little-endian
- machines, since after -c2 conversion, d_type will often be > 15.
-
-Wed Oct 5 12:53:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * pass1.c (checkinode) [mode == 0]: Check that di_trans
- is also clear here.
-
- * fsck.h (IFTODT): Provide macro here.
- * inode.c: Not here.
-
-Tue Oct 4 22:42:54 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * inode.c (ckinode) [dino.di_trans set]: Only call IDESC->id_func
- if IDESC->id_type is ADDR (meaning call function for each block).
- If it's DATA, then that means call dirscan on each data block,
- something entirely different.
-
- * inode.c (IFTODT): Provide macro.
-
-Fri Sep 30 21:28:57 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Define.
-
-Fri Sep 16 10:57:04 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * fsck.h (direct): Define macro.
-
-Thu Sep 1 14:51:23 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (ckinode): Don't pay attention to fs_maxsymlinklen
- if it's -1.
- * pass1.c (checkinode): Likewise.
-
- * fsck.h (DI_MODE): Use | not & for bitwise disjunction.
-
-Fri Aug 26 12:35:21 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * main.c (main): Don't call checkblock.
-
- * pass5.c (ffs_fragacct): Copy in function from ../ufs/subr.c.
-
- * inode.c (ckinode): Call IDESC->id_func for passive translator
- if it's set.
-
-Thu Aug 25 11:07:05 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * setup.c: Don't include <disklabel.h>.
- (setup): Comment out variable LP and label fetching code.
- (calcsb, getdisklabel): Comment out functions. Replace
- calcsb with one returning constant zero.
-
- * main.c: Don't include <sys/mount.h> or <fstab.h>.
- (main): Don't run checkfstab; just print an error in that case.
- (docheck): Comment out this function.
- (checkfilesys): Comment out special code for HOTROOT.
-
-Wed Aug 24 11:11:23 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * fsck.h (NBBY): Define macro.
-
-Tue Aug 23 15:54:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * dir.c (fileerror): Use DI_MODE instead of di_mode member.
- (adjust): Likewise.
- (linkup): Likewise.
- * inode.c (ckinode): Likewise.
- (clri): Likewise.
- (pinode): Likewise.
- * pass1.c (checkinode): Likewise.
- * pass2.c (pass2check): Likewise.
- * utilities.c (ftypeok): Likewise.
-
- * inode.c (allocino): Set di_model and di_modeh instead of di_mode.
- * pass1.c (checkinode): Likewise.
- * pass2.c (pass2): Likewise.
-
- * fsck.h (DIRSIZ): Replace ufs version with old BSD version.
- (struct dirtemplate, struct odirtemplate): Proved old BSD types.
- (DEV_BSIZE, MAXPATHLEN): Provide definitions.
- (DI_MODE): New macro.
diff --git a/bsdfsck/fsck.h b/bsdfsck/fsck.h
index c418f66c..04bb7698 100644
--- a/bsdfsck/fsck.h
+++ b/bsdfsck/fsck.h
@@ -209,7 +209,7 @@ struct inodesc {
* To check if a block has been found as a duplicate it is only
* necessary to search from duplist through muldup. To find the
* total number of times that a block has been found as a duplicate
- * the entire list must be searched for occurences of the block
+ * the entire list must be searched for occurrences of the block
* in question. The following diagram shows a sample list where
* w (found twice), x (found once), y (found three times), and z
* (found once) are duplicate block numbers:
diff --git a/bsdfsck/preen.c b/bsdfsck/preen.c
index 7893a5e1..5650f900 100644
--- a/bsdfsck/preen.c
+++ b/bsdfsck/preen.c
@@ -51,7 +51,7 @@ struct part {
struct part *next; /* forward link of partitions on disk */
char *name; /* device name */
char *fsname; /* mounted filesystem name */
- long auxdata; /* auxillary data for application */
+ long auxdata; /* auxiliary data for application */
} *badlist, **badnext = &badlist;
struct disk {
diff --git a/bsdfsck/utilities.c b/bsdfsck/utilities.c
index 2141e7f8..1c281b1b 100644
--- a/bsdfsck/utilities.c
+++ b/bsdfsck/utilities.c
@@ -520,7 +520,7 @@ errexit(s1, s2, s3, s4)
}
/*
- * An unexpected inconsistency occured.
+ * An unexpected inconsistency occurred.
* Die if preening, otherwise just print message and continue.
*/
/* VARARGS1 */
diff --git a/config.guess b/config.guess
new file mode 100755
index 00000000..17690aea
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1479 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2006-01-02'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ x86:Interix*:[345]*)
+ echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+ exit ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^CPU/{s: ::g;p;}'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^CPU/{s: ::g;p;}'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #if defined(__INTEL_COMPILER) || defined(__PGI)
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '/^LIBC/{s: ::g;p;}'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.make.in b/config.make.in
index 4dbe7513..fe4b1e65 100644
--- a/config.make.in
+++ b/config.make.in
@@ -1,7 +1,16 @@
# @configure_input@
+# What version of the Hurd is this?
+hurd-version := @PACKAGE_VERSION@
+
# Machine architecture.
machine = @host_cpu@
+asm_syntax = @asm_syntax@
+
+# Build options.
+build-profiled = @enable_profile@
+build-static = @enable_static_progs@
+boot-store-types = @boot_store_types@
# Prefix prepended to names of machine-independent installed files.
prefix = @prefix@
@@ -9,20 +18,22 @@ prefix = @prefix@
exec_prefix = @exec_prefix@
# Directories where things get installed.
-hurddir = $(exec_prefix)/hurd
-libdir = $(exec_prefix)/lib
-bindir = $(exec_prefix)/bin
-sbindir = $(exec_prefix)/sbin
-includedir = $(exec_prefix)/include
-libexecdir = $(exec_prefix)/libexec
-infodir = $(prefix)/info
-sysconfdir = $(prefix)/etc
-localstatedir = $(prefix)/var
-sharedstatedir = $(prefix)/com
+hurddir = ${exec_prefix}/hurd
+libdir = @libdir@
+bindir = @bindir@
+sbindir = @sbindir@
+includedir = @includedir@
+libexecdir = @libexecdir@
+bootdir = ${exec_prefix}/boot
+infodir = @infodir@
+sysconfdir = @sysconfdir@
+localstatedir = @localstatedir@
+sharedstatedir = @sharedstatedir@
+datadir = @datadir@
# All of those directories together:
installationdirlist = $(hurddir) $(libdir) $(bindir) $(sbindir) \
- $(includedir) $(libexecdir) $(infodir) $(sysconfdir) \
+ $(includedir) $(libexecdir) $(bootdir) $(infodir) $(sysconfdir) \
$(localstatedir) $(sharedstatedir)
@@ -35,13 +46,32 @@ AR = @AR@
RANLIB = @RANLIB@
MIG = @MIG@
MIGCOM = $(MIG) -cc cat - /dev/null
+AWK = @AWK@
-# Compilation flags. Append these to the definitions already made by
+# Compilation flags. Append these to the definitions already made by
# the specific Makefile.
CPPFLAGS += @CPPFLAGS@ @DEFS@
CFLAGS += @CFLAGS@
LDFLAGS += @LDFLAGS@
+gnu89-inline-CFLAGS = @libc_cv_gnu89_inline@
+
+# `yes' or `no' to indicate if ld --version-script is available.
+VERSIONING = @VERSIONING@
+
+# If a separate libcrypt is available, use it.
+LIBCRYPT = @LIBCRYPT@
+
+# How to link against Parted libraries, if at all.
+PARTED_LIBS = @PARTED_LIBS@
+
+# How to compile and link against ncursesw.
+LIBNCURSESW = @LIBNCURSESW@
+NCURSESW_INCLUDE = @NCURSESW_INCLUDE@
+
+# Whether Sun RPC support is available.
+HAVE_SUN_RPC = @HAVE_SUN_RPC@
+
# Installation tools.
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/config.sub b/config.sub
new file mode 100755
index 00000000..a4e8a94a
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1606 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+timestamp='2006-01-02'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32r | m32rle | m68000 | m68k | m88k | maxq | mb | microblaze | mcore \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | mt \
+ | msp430 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m32c)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ m32c-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config/ChangeLog b/config/ChangeLog
deleted file mode 100644
index 1214cc91..00000000
--- a/config/ChangeLog
+++ /dev/null
@@ -1,113 +0,0 @@
-Mon Aug 5 13:43:28 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * Makefile (SYSCONFFILES): Add `resolv.conf'.
- * resolv.conf: New file.
-
-Fri Aug 2 11:07:18 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Put `root-' before ROOTDOTS and `login-'
- before LOGINDOTS.
-
-Wed Jul 31 12:11:02 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * passwd (games): Have no password.
- * Makefile (SYSCONFFILES): Add `group'.
- * group: New file.
-
-Mon Jul 29 14:43:54 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * passwd: mib -> thomas.
-
-Wed Jul 24 15:23:29 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * root-.profile: But do \ ` inside "s.
-
-Sat Jul 20 02:13:52 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ttys (console): Change type to `pc3'.
- (com0): Renamed from tty00.
-
-Fri Jul 19 11:02:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * root-.profile: Don't \ ' inside "s.
- Advise to use `sush root', not su.
-
- * passwd (games): New user.
-
-Thu Jul 18 17:24:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * root-.profile: Echo usual noisy message.
-
- * fstab: Comment out example entry so it doesn't get incorrectly
- used by accident.
-
-Wed Jul 17 17:09:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * root-.bashrc: Fixup test and source of user's .root_bashrc.
- * root-.profile: Likewise.
-
-Tue Jul 16 11:12:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * passwd (root): Group should be `0'.
-
- * Makefile: Prettier installation of dotfiles for root and login.
-
-Mon Jul 15 19:16:30 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ttys: Comment out tty00 entry.
-
-Sat Jul 13 18:06:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile: Always touch /dev/null. If OVERRIDE_CONF, then
- $(installed_rootdots) and $(installed_conf) depend on it.
- $(installed_logins) always depend on /dev/null.
-
- * Makefile (DIST_FILES): New variable. Move rules to past
- `include ../Makeconf'.
-
- * Makefile (ROOTDOTS, installed_rootdots): New variables.
- (install): Depend on $(installed_rootdots).
- ($(installed_rootdots): New target.
- * root-.bash_login, root-.bashrc, root-.profile: New files.
-
- * Makefile (LOGINDOTS, installed_logins): New variables.
- (install): Depend on $(installed_logins).
- ($(installed_logins)): New rule.
- * login-.bash_login, login-.bashrc, login-.hushlogin,
- login-.profile, login-README: New files.
-
- * passwd, fstab: New files.
- * hostname: New (empty) file.
- * Makefile (SYSCONFFILES): Add hostname, fstab, and passwd.
-
-Thu Jun 20 14:46:39 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (install): Install symlink for rc.
-
- * Makefile (SYSCONFFILES): Removed `rc'.
- * rc: Removed to daemons/rc.sh.
-
-Wed Jun 19 15:25:15 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * rc: Print date before running fsck. Comment out pty permission
- frobbing.
-
-Tue Jun 18 22:40:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * rc: Understand special more status codes for signals from fsck.
- Fix some messages. Factor out date.
-
-Mon Jun 17 13:45:40 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * motd: Drop first line.
- * rc: Comment out motd update.
-
- * ttys: Fixup getty spec.
-
- * protocols: Updated from RFC 1700.
-
- * Makefile (SYSCONFFILES): Add protocols services shells motd ttys
-
- * rc: Update /etc/motd.
- (autoboot) Make root readonly before fscking it.
- Clean /var/run and make utmp.
diff --git a/config/Makefile b/config/Makefile
index adad800f..2cdcd818 100644
--- a/config/Makefile
+++ b/config/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1996 Free Software Foundation, Inc.
+#
+# Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc.
# Written by Michael I. Bushnell, p/BSG.
#
# This file is part of the GNU Hurd.
@@ -25,52 +25,32 @@ makemode := misc
# to overwrite an existing file. Print a warning for such files.
# If override_conf is set to `t' then install even on top of existing
# files.
-SYSCONFFILES = protocols services shells motd ttys hostname fstab passwd \
- group resolv.conf
+SYSCONFFILES = motd ttys
+
installed_conf = $(addprefix $(sysconfdir)/,$(SYSCONFFILES))
LOGINDOTS = .bash_login .bashrc .hushlogin .profile README
installed_logins = $(addprefix $(sysconfdir)/login/,$(LOGINDOTS))
-ROOTDOTS = .bash_login .bashrc .profile
-installed_rootdots = $(addprefix $(prefix)/root/,$(ROOTDOTS))
-
-# Mere symlinks are installed for these
-LINKEDCONFFILES = rc
-installed_links = $(addprefix $(sysconfdir)/,$(LINKEDCONFFILES))
-
-DIST_FILES=$(SYSCONFFILES) \
- $(addprefix login-,$(LOGINDOTS)) \
- $(addprefix root-,$(ROOTDOTS))
+DIST_FILES=$(SYSCONFFILES) $(addprefix login-,$(LOGINDOTS))
-foo=$(shell touch /dev/null)
+FORCE:
ifeq ($(override_conf),t)
-$(installed_rootdots): /dev/null
-$(installed_conf): /dev/null
+$(installed_conf): FORCE
+$(installed_logins): FORCE
endif
-$(installed_logins): /dev/null
-
include ../Makeconf
-install: $(installed_conf) $(installed_links) $(installed_logins) \
- $(installed_rootdots)
-
-$(installed_rootdots): $(prefix)/root
-$(installed_logins): $(sysconfdir)/login
+install: $(sysconfdir) $(sysconfdir)/login \
+ $(installed_conf) $(installed_logins)
-$(prefix)/root $(sysconfdir)/login: %:
+$(sysconfdir)/login: %:
mkdir -p $@
-$(installed_rootdots): $(prefix)/root/%: root-%
- $(INSTALL_DATA) $< $(prefix)/root/$*
-
$(installed_logins): $(sysconfdir)/login/%: login-%
$(INSTALL_DATA) $< $(sysconfdir)/login/$*
$(installed_conf): $(sysconfdir)/%: %
$(INSTALL_DATA) $< $(sysconfdir)/$*
-
-$(sysconfdir)/rc:
- ln -s ../libexec/rc $(sysconfdir)/rc
diff --git a/config/fstab b/config/fstab
deleted file mode 100644
index 618ba992..00000000
--- a/config/fstab
+++ /dev/null
@@ -1,5 +0,0 @@
-# Format:
-#
-# Disk device Mount point Format rw/ro dump fsckpassno
-#
-#/dev/rsd0a / ufs rw 1 1
diff --git a/config/group b/config/group
deleted file mode 100644
index 071b94b7..00000000
--- a/config/group
+++ /dev/null
@@ -1,2 +0,0 @@
-wheel:*:0:wheel
-games:*:13:games
diff --git a/config/login-.bash_login b/config/login-.bash_login
index 19e522b2..eecad52a 100644
--- a/config/login-.bash_login
+++ b/config/login-.bash_login
@@ -1,2 +1,2 @@
-. .bashrc
-. .profile
+. ~/.bashrc
+. ~/.profile
diff --git a/config/login-.bashrc b/config/login-.bashrc
index fbe6f4fc..cc2447fb 100644
--- a/config/login-.bashrc
+++ b/config/login-.bashrc
@@ -2,10 +2,10 @@
alias login='exec login -p -R-p -R-aHOME -R-aMOTD -R-e_LOGIN_RETRY=yes'
alias logon=login
alias l=login
+alias su=login
+
# quick login -- don't act like a login shell, but do cd to $HOME
alias ql='exec login -pSL -aMOTD -R-p -R-aHOME -R-aMOTD -R-e_LOGIN_RETRY=yes'
-# su -- don't even cd to $HOME
-alias su='exec login --program-name=su -pSL -aHOME -aMOTD -R-p -R-aHOME -R-aMOTD -R-e_LOGIN_RETRY=yes'
-alias sush=su
+
alias help='cat $HOME/README'
alias '?'=help
diff --git a/config/login-README b/config/login-README
index 43930a5c..9855ecf5 100644
--- a/config/login-README
+++ b/config/login-README
@@ -3,7 +3,8 @@ privileges. To login as a user with a userid of USER, use the command:
login USER
-other special commands:
+other useful commands:
ql USER # quick login -- just start a shell in USER's home directory
- su USER # set-user -- start a new shell as USER, but don't cd to $HOME
+ su USER # set the id of the current (login) shell to USER
+ # (use the `unsu' command to undo this, or just exit the shell)
diff --git a/config/passwd b/config/passwd
deleted file mode 100644
index 060af7e4..00000000
--- a/config/passwd
+++ /dev/null
@@ -1,9 +0,0 @@
-root::0:0:Lord of the Files:/root:/bin/bash
-roland::5281:0:Roland McGrath:/home/fsf/roland:/bin/bash
-thomas::9107:11:Thomas Bushnell n/BSG,,,:/home/gd3/thomas:/bin/bash
-miles::9427:10:Miles Bader:/home/gd3/miles:/bin/bash
-silly:*:65535:65535:Silly!:/:/bin/false
-login::-1:-1:Not logged in:/etc/login:/bin/bash
-hag::31013:10:Daniel Hagerty,,,:/home/fsf/hag:/bin/bash
-sgw::6289:11:stephen g. wadlow:/home/gp2/sgw:/bin/bash
-games:*:7:13:Games:/games:
diff --git a/config/protocols b/config/protocols
deleted file mode 100644
index d217ea49..00000000
--- a/config/protocols
+++ /dev/null
@@ -1,103 +0,0 @@
-#
-# Internet (IP) protocols
-#
-# $Id: protocols,v 1.2 1996/06/17 19:16:28 mib Exp $
-#
-# Updated for GNU from RFC 1700, October 1994.
-#
-ip 0 IP # internet protocol, pseudo protocol number
-icmp 1 ICMP # internet control message protocol
-igmp 2 IGMP # Internet Group Management
-ggp 3 GGP # gateway-gateway protocol
-ipencap 4 IP-ENCAP ip-encap # IP encapsulated in IP (officially ``IP'')
-st 5 ST # ST datagram mode
-tcp 6 TCP # transmission control protocol
-ucl 7 UCL # "University College, London" (who knows?)
-egp 8 EGP # exterior gateway protocol
-igp 9 IGP # Any private interior gateway
-bbn-rcc-mon 10 BBN-RCC-MON # BBN RCC Monitoring
-nvp-ii 11 NVP-II # Network Voice Protocol
-pup 12 PUP # PARC universal packet protocol
-argus 13 ARGUS # ARGUS
-emcon 14 EMCON # EMCON
-xnet 15 XNET # Cross Net Debugger
-chaos 16 CHAOS # Chaosnet
-udp 17 UDP # user datagram protocol
-mux 18 MUX # multiplexing
-dcn-meas 19 DCN-MEAS # DCN Measurement Subsystems
-hmp 20 HMP # host monitoring protocol
-prm 21 PRM # packet radio measurement
-xns-idp 22 XNS-IDP # Xerox NS IDP
-trunk-1 23 TRUNK-1 # Trunk 1
-trunk-2 24 TRUNK-2 # Trunk 2
-leaf-1 25 LEAF-1 # Leaf 1
-leaf-2 26 LEAF-2 # Leaf 2
-rdp 27 RDP # "reliable datagram" protocol
-irtp 28 IRTP # Internet Reliable Transaction Protocol
-iso-tp4 29 ISO-TP4 # ISO Transport Protocol class 4
-netblt 30 NETBLT # Net Bulk Data Transfer
-mfe-nsp 31 MFE-NSP # MFE Network Services Protocol
-merit-inp 32 MERIT-INP # MERIT Internodal Protocol
-sep 33 SEP # Sequential Exchange Protocol
-3pc 34 3PC # Third Party Connect Protocol
-idpr 35 IDPR # Inter-Domain Policy Routing Protocol
-xtp 36 XTP # Xpress Tranfer Protocol
-ddp 37 DDP # Datagram Delivery Protocol
-idpr-cmtp 38 IDPR-CMTP # IDPR Control Message Transport
-tp++ 39 TP++ # TP++ Transport Protocol
-il 40 IL # IL Transport Protocol
-sip 41 SIP # Simple Internet Protocol
-sdrp 42 SDRP # Source Demand Routing Protocol
-sip-sr 43 SIP-SL # SIP Source Route
-sip-frag 44 SIP-FRAG # SIP Fragment
-idrp 45 IDRP # Inter-Domain Routing Protocol
-rsvp 46 RSVP # Reservation Protocol
-gre 47 GRE # General Routing Encapsulation
-mhrp 48 MHRP # Mobile Host Routing Protocol
-bna 49 BNA # BNA
-sipp-esp 50 SIPP-ESP # SIPP Encap Security Payload
-sipp-ah 51 SIPP-AH # SIPP Authentication Header
-i-nlsp 52 I-NLSP # Integrated Net Layer Security TUBA
-swipe 53 SWIPE # IP with Encryption
-nhrp 54 NHRP # NBMA Next Hop Resolution
-
-internal 61 # any host internal protocol
-cftp 62 CFTP # CFTP
-lan 53 LAN # any local network protocol
-sat-expak 64 SAT-EXPAK # SATNET and Backroom EXPAK
-kryptolan 65 KRYPTOLAN # Kryptolan
-rvd 66 RVD # MIT Remote Virtual Disk Protocol
-ippc 67 IPPC # Internet Pluribus Packet Core
-dfs 68 DFS # any distributed file system
-sat-mon 69 SAT-MON # SATNET Monitoring
-visa 70 VISA # VISA Protocol
-ipcv 71 IPCV # Internet Packet Core Utility
-cpnx 72 CPNX # Computer Protocol Network Executive
-cphb 73 CPHB # Computer Protocol Heart Beat
-wsn 74 WSN # Wang Span Network
-pvp 75 PVP # Packet Video Protocol
-br-sat-mon 76 BR-SAT-MON # Backroom SATNET Monitoring
-sun-nd 77 SUN-ND # SUN ND PROTOCOL-Temporary
-wb-mon 78 WB-MON # WIDEBAND Monitoring
-wb-expak 79 WB-EXPAK # WIDEBAND EXPAK
-iso-ip 80 ISO-IP # ISO Internet Protocol
-vmtp 81 VMTP # Versatile Message Transport
-secure-vmtp 82 SECURE-VMTP # SECURE-VMTP
-vines 83 VINES # VINES
-ttp 84 TTP # TTP
-nsfnet-igp 85 NSFNET-IGP # NSFNET-IGP
-dgp 86 DGP # Dissimilar Gateway Protocol
-tcf 87 TCF # TCF
-igrp 88 IGRP # IGRP
-ospf 89 OSPFIGP # Open Shortest Path First IGP
-sprite-rpc 90 SPRITE-RPC sprite # Sprite RPC Protocol
-larp 91 LARP # Locus Address Resolution Protocol
-mtp 92 MTP # Multicast Transport Protocol
-ax.25 93 AX.25 # AX.25 Frames
-ipip 94 IPIP # Yet Another IP encapsulation
-micp 95 MICP # Mobile Internetworking Control Pro
-scc-sp 96 SCC-SP # Semaphore Communications Sec. Pro
-etherip 97 ETHERIP # Ethernet-within-IP Encapsulation
-encap 98 ENCAP # Yet Another IP encapsulation
-encrypt 99 # any private encryption scheme
-gmtp 100 GMTP # GMTP
diff --git a/config/resolv.conf b/config/resolv.conf
deleted file mode 100644
index 7d5296c6..00000000
--- a/config/resolv.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-domain my.domain.here
-lookup bind file
-nameserver NN.NN.NN.NN
diff --git a/config/root-.bash_login b/config/root-.bash_login
deleted file mode 100644
index efc6a7da..00000000
--- a/config/root-.bash_login
+++ /dev/null
@@ -1,5 +0,0 @@
-export PATH=/sbin:/bin:/local/bin
-
-. ~/.bashrc
-. ~/.profile
-
diff --git a/config/root-.bashrc b/config/root-.bashrc
deleted file mode 100644
index 3973e692..00000000
--- a/config/root-.bashrc
+++ /dev/null
@@ -1,18 +0,0 @@
-# Execute the user's rootrc file if it exists instead of this one.
-
-case "$USER" in
- "" | root)
- UHOME="";;
- *)
- UHOME="`eval echo ~$USER`";;
-esac
-
-if [ "$UHOME" -a -r "$UHOME/.root_bashrc" ]; then
- . "$UHOME/.root_bashrc"
-else
- # define some handy aliases
- alias j jobs -l
- alias c clear
- alias z suspend
- alias d dirs
-fi
diff --git a/config/root-.profile b/config/root-.profile
deleted file mode 100644
index c8bc40ba..00000000
--- a/config/root-.profile
+++ /dev/null
@@ -1,16 +0,0 @@
-# Execute the user's .root_profile file if it exists rather than this one.
-
-case "$USER" in
- "" | root)
- UHOME="";;
- *)
- UHOME="`eval echo ~$USER`";;
-esac
-
-if [ "$UHOME" -a -r "$UHOME/.root_profile" ]; then
- . "$UHOME/.root_profile"
-else
- PATH=/sbin:/bin:/local/bin
- export PATH
- echo "Don't login as root; use \`sush root'."
-fi
diff --git a/config/services b/config/services
deleted file mode 100644
index d6f6ddf0..00000000
--- a/config/services
+++ /dev/null
@@ -1,183 +0,0 @@
-#
-# Network services, Internet style
-#
-# Note that it is presently the policy of IANA to assign a single well-known
-# port number for both TCP and UDP; hence, most entries here have two entries
-# even if the protocol doesn't support UDP operations.
-# Updated from RFC 1340, ``Assigned Numbers'' (July 1992). Not all ports
-# are included, only the more common ones.
-#
-#
-tcpmux 1/tcp # TCP port service multiplexer
-echo 7/tcp
-echo 7/udp
-discard 9/tcp sink null
-discard 9/udp sink null
-systat 11/tcp users
-daytime 13/tcp
-daytime 13/udp
-netstat 15/tcp
-qotd 17/tcp quote
-msp 18/tcp # message send protocol
-msp 18/udp # message send protocol
-chargen 19/tcp ttytst source
-chargen 19/udp ttytst source
-ftp-data 20/tcp # default ftp data port
-ftp 21/tcp
-# 22 - unassigned
-telnet 23/tcp
-# 24 - private
-smtp 25/tcp mail
-# 26 - unassigned
-time 37/tcp timserver
-time 37/udp timserver
-rlp 39/udp resource # resource location
-nameserver 42/tcp name # IEN 116
-whois 43/tcp nicname
-domain 53/tcp nameserver # name-domain server
-domain 53/udp nameserver
-mtp 57/tcp # deprecated
-bootps 67/tcp # BOOTP server
-bootps 67/udp
-bootpc 68/tcp # BOOTP client
-bootpc 68/udp
-tftp 69/udp
-gopher 70/tcp # Internet Gopher
-gopher 70/udp
-rje 77/tcp netrjs
-finger 79/tcp
-www 80/tcp http # WorldWideWeb HTTP
-www 80/udp # HyperText Transfer Protocol
-link 87/tcp ttylink
-kerberos 88/tcp krb5 # Kerberos v5
-kerberos 88/udp
-supdup 95/tcp
-# 100 - reserved
-hostnames 101/tcp hostname # usually from sri-nic
-iso-tsap 102/tcp tsap # part of ISODE.
-csnet-ns 105/tcp cso-ns # also used by CSO name server
-csnet-ns 105/udp cso-ns
-rtelnet 107/tcp # Remote Telnet
-rtelnet 107/udp
-pop2 109/tcp postoffice # POP version 2
-pop2 109/udp
-pop3 110/tcp # POP version 3
-pop3 110/udp
-sunrpc 111/tcp
-sunrpc 111/udp
-auth 113/tcp authentication tap ident
-sftp 115/tcp
-uucp-path 117/tcp
-nntp 119/tcp readnews untp # USENET News Transfer Protocol
-ntp 123/tcp
-ntp 123/udp # Network Time Protocol
-netbios-ns 137/tcp # NETBIOS Name Service
-netbios-ns 137/udp
-netbios-dgm 138/tcp # NETBIOS Datagram Service
-netbios-dgm 138/udp
-netbios-ssn 139/tcp # NETBIOS session service
-netbios-ssn 139/udp
-imap2 143/tcp # Interim Mail Access Proto v2
-imap2 143/udp
-snmp 161/udp # Simple Net Mgmt Proto
-snmp-trap 162/udp snmptrap # Traps for SNMP
-cmip-man 163/tcp # ISO mgmt over IP (CMOT)
-cmip-man 163/udp
-cmip-agent 164/tcp
-cmip-agent 164/udp
-xdmcp 177/tcp # X Display Mgr. Control Proto
-xdmcp 177/udp
-nextstep 178/tcp NeXTStep NextStep # NeXTStep window
-nextstep 178/udp NeXTStep NextStep # server
-bgp 179/tcp # Border Gateway Proto.
-bgp 179/udp
-prospero 191/tcp # Cliff Neuman's Prospero
-prospero 191/udp
-irc 194/tcp # Internet Relay Chat
-irc 194/udp
-smux 199/tcp # SNMP Unix Multiplexer
-smux 199/udp
-at-rtmp 201/tcp # AppleTalk routing
-at-rtmp 201/udp
-at-nbp 202/tcp # AppleTalk name binding
-at-nbp 202/udp
-at-echo 204/tcp # AppleTalk echo
-at-echo 204/udp
-at-zis 206/tcp # AppleTalk zone information
-at-zis 206/udp
-z3950 210/tcp wais # NISO Z39.50 database
-z3950 210/udp wais
-ipx 213/tcp # IPX
-ipx 213/udp
-imap3 220/tcp # Interactive Mail Access
-imap3 220/udp # Protocol v3
-ulistserv 372/tcp # UNIX Listserv
-ulistserv 372/udp
-#
-# UNIX specific services
-#
-exec 512/tcp
-biff 512/udp comsat
-login 513/tcp
-who 513/udp whod
-shell 514/tcp cmd # no passwords used
-syslog 514/udp
-printer 515/tcp spooler # line printer spooler
-talk 517/udp
-ntalk 518/udp
-route 520/udp router routed # RIP
-timed 525/udp timeserver
-tempo 526/tcp newdate
-courier 530/tcp rpc
-conference 531/tcp chat
-netnews 532/tcp readnews
-netwall 533/udp # -for emergency broadcasts
-uucp 540/tcp uucpd # uucp daemon
-remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem
-#
-webster 765/tcp # Network dictionary
-webster 765/udp
-#
-# From ``Assigned Numbers'':
-#
-#> The Registered Ports are not controlled by the IANA and on most systems
-#> can be used by ordinary user processes or programs executed by ordinary
-#> users.
-#
-#> Ports are used in the TCP [45,106] to name the ends of logical
-#> connections which carry long term conversations. For the purpose of
-#> providing services to unknown callers, a service contact port is
-#> defined. This list specifies the port used by the server process as its
-#> contact port. While the IANA can not control uses of these ports it
-#> does register or list uses of these ports as a convienence to the
-#> community.
-#
-ingreslock 1524/tcp
-ingreslock 1524/udp
-prospero-np 1525/tcp # Prospero non-privileged
-prospero-np 1525/udp
-rfe 5002/tcp # Radio Free Ethernet
-rfe 5002/udp # Actually uses UDP only
-#
-#
-# Kerberos (Project Athena/MIT) services
-# Note that these are for Kerberos v4, and are unofficial. Sites running
-# v4 should uncomment these and comment out the v5 entries above.
-#
-klogin 543/tcp # Kerberos `rlogin'
-kshell 544/tcp krcmd # Kerberos `rsh'
-kerberos-adm 749/tcp # Kerberos `kadmin' (v5)
-#kerberos 750/udp kdc # Kerberos (server) udp
-#kerberos 750/tcp kdc # Kerberos (server) tcp
-krbupdate 760/tcp kreg # Kerberos registration
-kpasswd 761/tcp kpwd # Kerberos `passwd'
-eklogin 2105/tcp # Kerberos encrypted `rlogin'
-#
-# Unofficial but necessary (for NetBSD) services
-#
-supfilesrv 871/tcp # SUP server
-supfiledbg 1127/tcp # SUP debugging
-#
-# GNU Finger services
-cfinger 2003/tcp # GNU's finger data collection point
-ofinger 1023/tcp # OS Issue finger daemon
diff --git a/config/shells b/config/shells
deleted file mode 100644
index 6c681235..00000000
--- a/config/shells
+++ /dev/null
@@ -1,16 +0,0 @@
-# List of acceptable shells for chsh/passwd -s
-# Ftpd will not allow users to connect who do not have one of these shells.
-#
-# Yes, emacs is in /etc/shells. Surprised?
-#
-/bin/sh
-/bin/bash
-/bin/kibosh
-/bin/kish
-/bin/ash
-/bin/emacs
-/bin/es
-/bin/rc
-/bin/tcsh
-/bin/zsh
-/bin/csh
diff --git a/config/ttys b/config/ttys
index f4446e7f..2b3464d1 100644
--- a/config/ttys
+++ b/config/ttys
@@ -2,7 +2,13 @@
# and restartsthem when they die. Note that in GNU, unlike in BSD, there
# is no need to list pseudo-ttys here.
-# name program type status comments
+# name program type status comments
-console "/libexec/getty 9600" pc3 on secure trusted console
-#com0 "/libexec/getty 9600" dialup on secure
+console "/libexec/getty 9600" mach-gnu-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/configure b/configure
new file mode 100755
index 00000000..1fab7980
--- /dev/null
+++ b/configure
@@ -0,0 +1,5868 @@
+#! /bin/sh
+# From configure.in Id: configure.in,v 1.38 2008/11/17 11:34:18 tschwinge Exp .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.67 for GNU Hurd 0.3.
+#
+# Report bugs to <bug-hurd@gnu.org>.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org and bug-hurd@gnu.org
+$0: about your system, including any error possibly output
+$0: before this message. Then install a modern shell, or
+$0: manually run the script under such a shell if you do
+$0: have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='GNU Hurd'
+PACKAGE_TARNAME='hurd'
+PACKAGE_VERSION='0.3'
+PACKAGE_STRING='GNU Hurd 0.3'
+PACKAGE_BUGREPORT='bug-hurd@gnu.org'
+PACKAGE_URL='http://www.gnu.org/software/hurd/'
+
+ac_unique_file="hurd/hurd_types.h"
+ac_default_prefix=
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+HAVE_SUN_RPC
+LIBNCURSESW
+NCURSESW_INCLUDE
+boot_store_types
+PARTED_LIBS
+EGREP
+GREP
+CPP
+libc_cv_gnu89_inline
+VERSIONING
+LIBCRYPT
+MIG
+RANLIB
+AR
+OBJCOPY
+LD
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+AWK
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+enable_static_progs
+enable_profile
+asm_syntax
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_profile
+enable_static_progs
+with_parted
+enable_boot_store_types
+enable_ncursesw
+with_ncursesw_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used" >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures GNU Hurd 0.3 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/hurd]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of GNU Hurd 0.3:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-profile do not build profiled libraries and programs
+ --enable-static-progs=PROGRAMS...
+ build statically-linked PROGRAM.static versions
+ of (only) the listed programs ext2fs,ufs
+ --enable-boot-store-types=TYPES...
+ list of store types included in statically
+ linked filesystems used for booting
+ --disable-ncursesw Do not use ncursesw
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-parted disable user-space partition stores
+ --with-ncursesw-include-dir=DIR
+ Set directory containing the include files for
+ use with -lncursesw, when it isn't installed as
+ the default curses library. If DIR is "none",
+ then no special ncursesw include files are used.
+ --without-ncursesw-include-dir
+ Equivalent to --with-ncursesw-include-dir=none
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <bug-hurd@gnu.org>.
+GNU Hurd home page: <http://www.gnu.org/software/hurd/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+GNU Hurd configure 0.3
+generated by GNU Autoconf 2.67
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval "test \"\${$3+set}\"" = set; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ------------------------------- ##
+## Report this to bug-hurd@gnu.org ##
+## ------------------------------- ##"
+ ) | sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval "test \"\${$3+set}\"" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by GNU Hurd $as_me 0.3, which was
+generated by GNU Autoconf 2.67. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+case "$host_os" in
+gnu*) ;;
+none) as_fn_error $? "
+*** You must specify a host of $host_cpu-gnu or $host_cpu-$host_vendor-gnu
+*** to configure; you will need to use the same host specification
+*** to configure other packages for the GNU/Hurd system." "$LINENO" 5 ;;
+*) as_fn_error $? "this is the gnu os, host cannot be $host_os
+*** Host configuration must be \`MACHINE-gnu' or \`MACHINE-VENDOR-gnu'.
+*** To cross-compile, you must specify both --host and --build;
+*** for example \`--build=$host --host=$host_cpu-gnu'.
+*** Run $0 --help for more information." "$LINENO" 5 ;;
+esac
+
+case "$host_cpu" in
+alpha*)
+ asm_syntax=alpha
+ ;;
+arm*)
+ asm_syntax=arm
+ ;;
+m68k | m680?0)
+ asm_syntax=m68k
+ ;;
+mips*)
+ asm_syntax=mips
+ ;;
+i?86)
+ asm_syntax=i386
+ ;;
+powerpc*)
+ asm_syntax=ppc
+ ;;
+sparc64* | ultrasparc*)
+ asm_syntax=sparc64
+ ;;
+sparc*)
+ asm_syntax=sparc
+ ;;
+*)
+ asm_syntax="$host_cpu"
+ ;;
+esac
+
+
+test -r "$srcdir/libthreads/$asm_syntax/cthreads.h" || {
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unsupported CPU type $host_cpu" >&5
+$as_echo "$as_me: WARNING: unsupported CPU type $host_cpu" >&2;}
+}
+
+# Check whether --enable-profile was given.
+if test "${enable_profile+set}" = set; then :
+ enableval=$enable_profile;
+fi
+
+
+
+# Check whether --enable-static-progs was given.
+if test "${enable_static_progs+set}" = set; then :
+ enableval=$enable_static_progs;
+fi
+
+case "$enable_static_progs" in
+'no') enable_static_progs= ;; # we got --disable-static
+'') enable_static_progs='ext2fs,ufs' ;;
+esac
+# Convert comma/space-separated list into space-separated list.
+enable_static_progs=`echo "$enable_static_progs" | sed 's/[, ][, ]*/ /g'`
+
+
+# Don't needlessly overwrite files that whose contents haven't changed. This
+# helps for avoinding unneccessary recompilation cycles when keeping
+# cross-compilation toolchains up-to-date. Thus, unconditionally use the
+# supplied `install-sh', as the GNU Coreutils one doesn't provide this
+# functionality yet (TODO: change that). TODO: $ac_abs_top_builddir et al. are
+# not yet available here, that's why we use `readlink' (but only if available).
+INSTALL="$SHELL $(readlink -f "$ac_install_sh")"\ -C || unset INSTALL
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Require GCC.
+if test x$GCC != xyes; then
+ as_fn_error $? "this code uses GNU C extensions, you must compile with GCC" "$LINENO" 5
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ld; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_LD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LD"; then
+ ac_cv_prog_LD="$LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LD="${ac_tool_prefix}ld"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LD=$ac_cv_prog_LD
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LD"; then
+ ac_ct_LD=$LD
+ # Extract the first word of "ld", so it can be a program name with args.
+set dummy ld; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_LD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LD"; then
+ ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_LD="ld"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LD=$ac_cv_prog_ac_ct_LD
+if test -n "$ac_ct_LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5
+$as_echo "$ac_ct_LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LD" = x; then
+ LD=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LD=$ac_ct_LD
+ fi
+else
+ LD="$ac_cv_prog_LD"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objcopy", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objcopy; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJCOPY+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJCOPY"; then
+ ac_cv_prog_OBJCOPY="$OBJCOPY" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJCOPY="${ac_tool_prefix}objcopy"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJCOPY=$ac_cv_prog_OBJCOPY
+if test -n "$OBJCOPY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5
+$as_echo "$OBJCOPY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJCOPY"; then
+ ac_ct_OBJCOPY=$OBJCOPY
+ # Extract the first word of "objcopy", so it can be a program name with args.
+set dummy objcopy; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJCOPY+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJCOPY"; then
+ ac_cv_prog_ac_ct_OBJCOPY="$ac_ct_OBJCOPY" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJCOPY="objcopy"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJCOPY=$ac_cv_prog_ac_ct_OBJCOPY
+if test -n "$ac_ct_OBJCOPY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJCOPY" >&5
+$as_echo "$ac_ct_OBJCOPY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJCOPY" = x; then
+ OBJCOPY=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJCOPY=$ac_ct_OBJCOPY
+ fi
+else
+ OBJCOPY="$ac_cv_prog_OBJCOPY"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}mig", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mig; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_MIG+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MIG"; then
+ ac_cv_prog_MIG="$MIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_MIG="${ac_tool_prefix}mig"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+MIG=$ac_cv_prog_MIG
+if test -n "$MIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MIG" >&5
+$as_echo "$MIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MIG"; then
+ ac_ct_MIG=$MIG
+ # Extract the first word of "mig", so it can be a program name with args.
+set dummy mig; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_MIG+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_MIG"; then
+ ac_cv_prog_ac_ct_MIG="$ac_ct_MIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_MIG="mig"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MIG=$ac_cv_prog_ac_ct_MIG
+if test -n "$ac_ct_MIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MIG" >&5
+$as_echo "$ac_ct_MIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_MIG" = x; then
+ MIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ MIG=$ac_ct_MIG
+ fi
+else
+ MIG="$ac_cv_prog_MIG"
+fi
+
+# Require MiG.
+if test x${MIG} = x; then
+ as_fn_error $? "
+*** You need GNU MiG to compile the GNU Hurd, please see
+*** http://www.gnu.org/software/hurd/mig.html for further details, or
+*** download it directly from the main GNU server (ftp.gnu.org) or any
+*** GNU mirror." "$LINENO" 5
+fi
+
+
+
+# See if there's a separate libcrypt (many systems put crypt there).
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5
+$as_echo_n "checking for crypt in -lcrypt... " >&6; }
+if test "${ac_cv_lib_crypt_crypt+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char crypt ();
+int
+main ()
+{
+return crypt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_crypt_crypt=yes
+else
+ ac_cv_lib_crypt_crypt=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5
+$as_echo "$ac_cv_lib_crypt_crypt" >&6; }
+if test "x$ac_cv_lib_crypt_crypt" = x""yes; then :
+ LIBCRYPT=-lcrypt
+fi
+
+
+
+# See if mig groks `retcode'.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $MIG supports the retcode keyword" >&5
+$as_echo_n "checking whether $MIG supports the retcode keyword... " >&6; }
+if test "${hurd_cv_mig_retcode+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat > conftest.defs <<\EOF
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+subsystem foobar 1000;
+type reply_port_t = polymorphic | MACH_MSG_TYPE_PORT_SEND_ONCE
+ ctype: mach_port_t;
+simpleroutine foobar_reply (
+ reply_port: reply_port_t;
+ err: kern_return_t, RetCode);
+EOF
+if { ac_try='CC="${CC}" ${MIG-false} -n conftest.defs 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ hurd_cv_mig_retcode=yes
+else
+ hurd_cv_mig_retcode=no
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hurd_cv_mig_retcode" >&5
+$as_echo "$hurd_cv_mig_retcode" >&6; }
+if test $hurd_cv_mig_retcode = yes; then
+ $as_echo "#define HAVE_MIG_RETCODE 1" >>confdefs.h
+
+fi
+
+# See if --version-script is available.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld --version-script" >&5
+$as_echo_n "checking for ld --version-script... " >&6; }
+if test "${hurd_cv_ld_version_script_option+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat > conftest.c <<\EOF
+void foobar() {}
+EOF
+cat > conftest.map <<\EOF
+VERS_1 {
+ global: sym;
+};
+
+VERS_2 {
+ global: sym;
+} VERS_1;
+EOF
+
+if { ac_try='eval $ac_compile 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; } &&
+ { ac_try='${CC-cc} $CFLAGS -shared -o conftest.so conftest.o
+ -nostartfiles -nostdlib
+ -Wl,--version-script,conftest.map
+ 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ hurd_cv_ld_version_script_option=yes
+else
+ hurd_cv_ld_version_script_option=no
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hurd_cv_ld_version_script_option" >&5
+$as_echo "$hurd_cv_ld_version_script_option" >&6; }
+
+# See if libc was built with --enable-libio.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libio" >&5
+$as_echo_n "checking for libio... " >&6; }
+if test "${hurd_cv_libio+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+#ifndef _STDIO_USES_IOSTREAM
+# error No libio found.
+#endif
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ hurd_cv_libio=yes
+else
+ hurd_cv_libio=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hurd_cv_libio" >&5
+$as_echo "$hurd_cv_libio" >&6; }
+
+# The versions of the symbols in libthreads have to match those in
+# libc.so. Since the symbols in a libc that includes libio will be
+# versioned differently from the ones in a libc that uses stdio, this
+# isn't easy to accomplish. Instead we leave things unversioned if
+# libio isn't found.
+if test $hurd_cv_libio = yes; then
+ VERSIONING=$hurd_cv_ld_version_script_option
+else
+ VERSIONING=no
+fi
+
+
+# Check if libc contains getgrouplist and/or uselocale.
+for ac_func in getgrouplist uselocale
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+# From glibc HEAD, 2007-11-07.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fgnu89-inline" >&5
+$as_echo_n "checking for -fgnu89-inline... " >&6; }
+if test "${libc_cv_gnu89_inline+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat > conftest.c <<EOF
+int foo;
+#ifdef __GNUC_GNU_INLINE__
+main () { return 0;}
+#else
+#error
+#endif
+EOF
+if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -S -std=gnu99 -fgnu89-inline
+ -o conftest.s conftest.c 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then
+ libc_cv_gnu89_inline=yes
+else
+ libc_cv_gnu89_inline=no
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gnu89_inline" >&5
+$as_echo "$libc_cv_gnu89_inline" >&6; }
+if test $libc_cv_gnu89_inline = yes; then
+ libc_cv_gnu89_inline=-fgnu89-inline
+else
+ libc_cv_gnu89_inline=
+fi
+
+
+
+# Insist on libparted unless the user declines explicitely
+
+# Check whether --with-parted was given.
+if test "${with_parted+set}" = set; then :
+ withval=$with_parted;
+else
+ with_parted=yes
+fi
+
+
+PARTED_LIBS=
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+if test "x$with_parted" != xno; then :
+
+ ac_fn_c_check_header_mongrel "$LINENO" "parted/parted.h" "ac_cv_header_parted_parted_h" "$ac_includes_default"
+if test "x$ac_cv_header_parted_parted_h" = x""yes; then :
+ $as_echo "#define HAVE_PARTED_PARTED_H 1" >>confdefs.h
+
+else
+
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Please install required libraries or use --without-parted.
+See \`config.log' for more details" "$LINENO" 5; }
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ped_device_read in -lparted" >&5
+$as_echo_n "checking for ped_device_read in -lparted... " >&6; }
+if test "${ac_cv_lib_parted_ped_device_read+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lparted $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ped_device_read ();
+int
+main ()
+{
+return ped_device_read ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_parted_ped_device_read=yes
+else
+ ac_cv_lib_parted_ped_device_read=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_parted_ped_device_read" >&5
+$as_echo "$ac_cv_lib_parted_ped_device_read" >&6; }
+if test "x$ac_cv_lib_parted_ped_device_read" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPARTED 1
+_ACEOF
+
+ LIBS="-lparted $LIBS"
+
+else
+
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Please install required libraries or use --without-parted.
+See \`config.log' for more details" "$LINENO" 5; }
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate in -luuid" >&5
+$as_echo_n "checking for uuid_generate in -luuid... " >&6; }
+if test "${ac_cv_lib_uuid_uuid_generate+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-luuid $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char uuid_generate ();
+int
+main ()
+{
+return uuid_generate ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_uuid_uuid_generate=yes
+else
+ ac_cv_lib_uuid_uuid_generate=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate" >&5
+$as_echo "$ac_cv_lib_uuid_uuid_generate" >&6; }
+if test "x$ac_cv_lib_uuid_uuid_generate" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBUUID 1
+_ACEOF
+
+ LIBS="-luuid $LIBS"
+
+else
+
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Please install required libraries or use --without-parted.
+See \`config.log' for more details" "$LINENO" 5; }
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+ LIBS="-ldl $LIBS"
+
+else
+
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Please install required libraries or use --without-parted.
+See \`config.log' for more details" "$LINENO" 5; }
+
+fi
+
+ PARTED_LIBS="-lparted -luuid -ldl"
+
+fi
+
+
+# Check whether --enable-boot-store-types was given.
+if test "${enable_boot_store_types+set}" = set; then :
+ enableval=$enable_boot_store_types;
+fi
+if test -z "$enable_boot_store_types"; then
+ boot_store_types='device remap gunzip bunzip2'
+ test -z "$PARTED_LIBS" || boot_store_types="$boot_store_types part"
+elif test "x$enable_boot_store_types" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: you probably wanted --disable-static-progs" >&5
+$as_echo "$as_me: WARNING: you probably wanted --disable-static-progs" >&2;}
+else
+ boot_store_types="$enable_boot_store_types"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking boot store types" >&5
+$as_echo_n "checking boot store types... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_store_types" >&5
+$as_echo "$boot_store_types" >&6; }
+
+# Check for ncursesw, which is needed for the console-curses client.
+
+ # Check whether --enable-ncursesw was given.
+if test "${enable_ncursesw+set}" = set; then :
+ enableval=$enable_ncursesw;
+else
+ enable_ncursesw=yes
+fi
+
+ if test "$enable_ncursesw" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncursesw" >&5
+$as_echo_n "checking for initscr in -lncursesw... " >&6; }
+if test "${ac_cv_lib_ncursesw_initscr+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lncursesw $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char initscr ();
+int
+main ()
+{
+return initscr ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ncursesw_initscr=yes
+else
+ ac_cv_lib_ncursesw_initscr=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_initscr" >&5
+$as_echo "$ac_cv_lib_ncursesw_initscr" >&6; }
+if test "x$ac_cv_lib_ncursesw_initscr" = x""yes; then :
+ LIBNCURSESW="-lncursesw"
+fi
+
+ if test "$LIBNCURSESW"; then
+
+# Check whether --with-ncursesw-include-dir was given.
+if test "${with_ncursesw_include_dir+set}" = set; then :
+ withval=$with_ncursesw_include_dir;
+fi
+ if test "${with_ncursesw_include_dir+set}" = set; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ncursesw include dir" >&5
+$as_echo_n "checking for ncursesw include dir... " >&6; }
+ case "$with_ncursesw_include_dir" in
+ no|none)
+ hurd_cv_includedir_ncursesw=none;;
+ *)
+ hurd_cv_includedir_ncursesw="$with_ncursesw_include_dir";;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hurd_cv_includedir_ncursesw" >&5
+$as_echo "$hurd_cv_includedir_ncursesw" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ncursesw include dir" >&5
+$as_echo_n "checking for ncursesw include dir... " >&6; }
+if test "${hurd_cv_includedir_ncursesw+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ for D in $includedir $prefix/include /local/include /usr/local/include /include /usr/include; do
+ if test -d $D/ncursesw; then
+ hurd_cv_includedir_ncursesw="$D/ncursesw"
+ break
+ fi
+ test "$hurd_cv_includedir_ncursesw" \
+ || hurd_cv_includedir_ncursesw=none
+ done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hurd_cv_includedir_ncursesw" >&5
+$as_echo "$hurd_cv_includedir_ncursesw" >&6; }
+ fi
+ if test "$hurd_cv_includedir_ncursesw" = none; then
+ NCURSESW_INCLUDE=""
+ else
+ NCURSESW_INCLUDE="-I$hurd_cv_includedir_ncursesw"
+ fi
+ fi
+ fi
+
+
+
+# Check for Sun RPC headers and library.
+ac_fn_c_check_header_mongrel "$LINENO" "rpc/types.h" "ac_cv_header_rpc_types_h" "$ac_includes_default"
+if test "x$ac_cv_header_rpc_types_h" = x""yes; then :
+ HAVE_SUN_RPC=yes
+else
+ HAVE_SUN_RPC=no
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clnt_create" >&5
+$as_echo_n "checking for library containing clnt_create... " >&6; }
+if test "${ac_cv_search_clnt_create+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clnt_create ();
+int
+main ()
+{
+return clnt_create ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' ; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_clnt_create=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if test "${ac_cv_search_clnt_create+set}" = set; then :
+ break
+fi
+done
+if test "${ac_cv_search_clnt_create+set}" = set; then :
+
+else
+ ac_cv_search_clnt_create=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clnt_create" >&5
+$as_echo "$ac_cv_search_clnt_create" >&6; }
+ac_res=$ac_cv_search_clnt_create
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+ :
+else
+ HAVE_SUN_RPC=no
+fi
+
+
+
+if test -f ./$ac_unique_file; then
+ # Configuring in source directory; don't create any Makefiles.
+ makefiles=
+else
+ # We are configuring in a separate build tree.
+ # Create a Makefile in the top-level build directory and
+ # one for each subdirectory Makefile in the source.
+ makefiles="Makeconf:build.mkcf.in \
+ `cd $srcdir; for file in Makefile */Makefile; do \
+ echo ${file}:build.mk.in; done`"
+fi
+
+ac_config_files="$ac_config_files config.make ${makefiles}"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by GNU Hurd $as_me 0.3, which was
+generated by GNU Autoconf 2.67. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-hurd@gnu.org>.
+GNU Hurd home page: <http://www.gnu.org/software/hurd/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+GNU Hurd config.status 0.3
+configured by $0, generated by GNU Autoconf 2.67,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.make") CONFIG_FILES="$CONFIG_FILES config.make" ;;
+ "${makefiles}") CONFIG_FILES="$CONFIG_FILES ${makefiles}" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp=
+ trap 'exit_status=$?
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
diff --git a/configure.in b/configure.in
index 01c41005..05b959b0 100644
--- a/configure.in
+++ b/configure.in
@@ -1,21 +1,88 @@
dnl Process this file with autoconf to produce a configure script.
-AC_REVISION([$Id: configure.in,v 1.5 1996/05/01 02:19:03 roland Exp $])
-AC_PREREQ(2.4) dnl Minimum Autoconf version required.
-AC_INIT(hurd/hurd_types.h) dnl A distinctive file to look for in srcdir.
+AC_REVISION([$Id: configure.in,v 1.38 2008/11/17 11:34:18 tschwinge Exp $])
+AC_PREREQ(2.54) dnl Minimum Autoconf version required.
+AC_INIT([GNU Hurd], [0.3], [bug-hurd@gnu.org])
+AC_CONFIG_SRCDIR([hurd/hurd_types.h]) dnl File to look for in srcdir.
AC_PREFIX_DEFAULT() dnl Default to empty prefix, not /usr/local.
AC_CANONICAL_HOST
case "$host_os" in
gnu*) ;;
-*) AC_MSG_ERROR([sorry, this is the gnu os, not $host_os]) ;;
+none) AC_MSG_ERROR([
+*** You must specify a host of $host_cpu-gnu or $host_cpu-$host_vendor-gnu
+*** to configure; you will need to use the same host specification
+*** to configure other packages for the GNU/Hurd system.]) ;;
+*) AC_MSG_ERROR([this is the gnu os, host cannot be $host_os
+*** Host configuration must be \`MACHINE-gnu' or \`MACHINE-VENDOR-gnu'.
+*** To cross-compile, you must specify both --host and --build;
+*** for example \`--build=$host --host=$host_cpu-gnu'.
+*** Run $0 --help for more information.]) ;;
esac
+case "$host_cpu" in
+alpha*)
+ asm_syntax=alpha
+ ;;
+arm*)
+ asm_syntax=arm
+ ;;
+m68k | m680?0)
+ asm_syntax=m68k
+ ;;
+mips*)
+ asm_syntax=mips
+ ;;
+i?86)
+ asm_syntax=i386
+ ;;
+powerpc*)
+ asm_syntax=ppc
+ ;;
+sparc64* | ultrasparc*)
+ asm_syntax=sparc64
+ ;;
+sparc*)
+ asm_syntax=sparc
+ ;;
+*)
+ asm_syntax="$host_cpu"
+ ;;
+esac
+AC_SUBST(asm_syntax)
+
+test -r "$srcdir/libthreads/$asm_syntax/cthreads.h" || {
+ AC_MSG_WARN([unsupported CPU type $host_cpu])
+}
+
+AC_ARG_ENABLE(profile,
+[ --disable-profile do not build profiled libraries and programs])
+AC_SUBST(enable_profile)
+
+define([default_static],['ext2fs,ufs'])dnl
+AC_ARG_ENABLE(static-progs,
+[ --enable-static-progs=PROGRAMS...
+ build statically-linked PROGRAM.static versions
+ of (only) the listed programs ]dnl
+changequote(',')[default_static]changequote([,]))
+case "$enable_static_progs" in
+'no') enable_static_progs= ;; # we got --disable-static
+'') enable_static_progs=default_static ;;
+esac
+# Convert comma/space-separated list into space-separated list.
+enable_static_progs=`echo "$enable_static_progs" | sed 's/[[, ]][[, ]]*/ /g'`
+AC_SUBST(enable_static_progs)
+
+[# Don't needlessly overwrite files that whose contents haven't changed. This
+# helps for avoinding unneccessary recompilation cycles when keeping
+# cross-compilation toolchains up-to-date. Thus, unconditionally use the
+# supplied `install-sh', as the GNU Coreutils one doesn't provide this
+# functionality yet (TODO: change that). TODO: $ac_abs_top_builddir et al. are
+# not yet available here, that's why we use `readlink' (but only if available).
+INSTALL="$SHELL $(readlink -f "$ac_install_sh")"\ -C || unset INSTALL]
AC_PROG_INSTALL
+AC_PROG_AWK
-AC_CHECK_TOOL(CC, gcc)
-# That check handles cross-compilation well, but AC_PROG_CC tests for GCC
-# and sets default CFLAGS nicely for us, so do that too.
AC_PROG_CC
# Require GCC.
if test x$GCC != xyes; then
@@ -27,11 +94,148 @@ AC_CHECK_TOOL(OBJCOPY, objcopy)
AC_CHECK_TOOL(AR, ar)
AC_CHECK_TOOL(RANLIB, ranlib)
AC_CHECK_TOOL(MIG, mig)
+# Require MiG.
+if test x${MIG} = x; then
+ AC_MSG_ERROR([
+*** You need GNU MiG to compile the GNU Hurd, please see
+*** http://www.gnu.org/software/hurd/mig.html for further details, or
+*** download it directly from the main GNU server (ftp.gnu.org) or any
+*** GNU mirror.])
+fi
dnl Let these propagate from the environment.
AC_SUBST(CFLAGS) AC_SUBST(CPPFLAGS) AC_SUBST(LDFLAGS)
-if test $srcdir = .; then
+# See if there's a separate libcrypt (many systems put crypt there).
+AC_CHECK_LIB(crypt, crypt, LIBCRYPT=-lcrypt)
+AC_SUBST(LIBCRYPT)
+
+hurd_MIG_RETCODE
+
+# See if --version-script is available.
+AC_CACHE_CHECK(for ld --version-script, hurd_cv_ld_version_script_option, [dnl
+cat > conftest.c <<\EOF
+void foobar() {}
+EOF
+cat > conftest.map <<\EOF
+VERS_1 {
+ global: sym;
+};
+
+VERS_2 {
+ global: sym;
+} VERS_1;
+EOF
+
+if AC_TRY_COMMAND([eval $ac_compile 1>&AS_MESSAGE_LOG_FD()]) &&
+ AC_TRY_COMMAND([${CC-cc} $CFLAGS -shared -o conftest.so conftest.o
+ -nostartfiles -nostdlib
+ -Wl,--version-script,conftest.map
+ 1>&AS_MESSAGE_LOG_FD()]); then
+ hurd_cv_ld_version_script_option=yes
+else
+ hurd_cv_ld_version_script_option=no
+fi
+rm -f conftest*])
+
+# See if libc was built with --enable-libio.
+AC_CACHE_CHECK([for libio],
+ hurd_cv_libio,
+ AC_TRY_COMPILE([#include <stdio.h>
+#ifndef _STDIO_USES_IOSTREAM
+# error No libio found.
+#endif],,
+ hurd_cv_libio=yes,
+ hurd_cv_libio=no))
+
+# The versions of the symbols in libthreads have to match those in
+# libc.so. Since the symbols in a libc that includes libio will be
+# versioned differently from the ones in a libc that uses stdio, this
+# isn't easy to accomplish. Instead we leave things unversioned if
+# libio isn't found.
+if test $hurd_cv_libio = yes; then
+ VERSIONING=$hurd_cv_ld_version_script_option
+else
+ VERSIONING=no
+fi
+AC_SUBST(VERSIONING)
+
+# Check if libc contains getgrouplist and/or uselocale.
+AC_CHECK_FUNCS(getgrouplist uselocale)
+
+
+# From glibc HEAD, 2007-11-07.
+AC_CACHE_CHECK(for -fgnu89-inline, libc_cv_gnu89_inline, [dnl
+cat > conftest.c <<EOF
+int foo;
+#ifdef __GNUC_GNU_INLINE__
+main () { return 0;}
+#else
+#error
+#endif
+EOF
+if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -S -std=gnu99 -fgnu89-inline
+ -o conftest.s conftest.c 1>&AS_MESSAGE_LOG_FD])
+then
+ libc_cv_gnu89_inline=yes
+else
+ libc_cv_gnu89_inline=no
+fi
+rm -f conftest*])
+if test $libc_cv_gnu89_inline = yes; then
+ libc_cv_gnu89_inline=-fgnu89-inline
+else
+ libc_cv_gnu89_inline=
+fi
+AC_SUBST(libc_cv_gnu89_inline)
+
+
+# Insist on libparted unless the user declines explicitely
+AC_ARG_WITH([parted],
+ [AS_HELP_STRING([--without-parted], [disable user-space partition stores])],
+ [],
+ [with_parted=yes])
+
+PARTED_LIBS=
+AC_DEFUN([PARTED_FAIL], [
+ AC_MSG_FAILURE([Please install required libraries or use --without-parted.])
+])
+AS_IF([test "x$with_parted" != xno], [
+ AC_CHECK_HEADER([parted/parted.h],
+ [AC_DEFINE(HAVE_PARTED_PARTED_H)],
+ [PARTED_FAIL])
+ AC_CHECK_LIB([parted], [ped_device_read], [], [PARTED_FAIL])
+ AC_CHECK_LIB([uuid], [uuid_generate], [], [PARTED_FAIL])
+ AC_CHECK_LIB([dl], [dlopen], [], [PARTED_FAIL])
+ PARTED_LIBS="-lparted -luuid -ldl"
+])
+AC_SUBST([PARTED_LIBS])
+
+AC_ARG_ENABLE(boot-store-types,
+[ --enable-boot-store-types=TYPES...
+ list of store types included in statically
+ linked filesystems used for booting])dnl
+if test -z "$enable_boot_store_types"; then
+ boot_store_types='device remap gunzip bunzip2'
+ test -z "$PARTED_LIBS" || boot_store_types="$boot_store_types part"
+elif test "x$enable_boot_store_types" = xno; then
+ AC_MSG_WARN([you probably wanted --disable-static-progs])
+else
+ boot_store_types="$enable_boot_store_types"
+fi
+AC_SUBST(boot_store_types)dnl
+AC_MSG_CHECKING(boot store types)
+AC_MSG_RESULT($boot_store_types)
+
+# Check for ncursesw, which is needed for the console-curses client.
+hurd_LIB_NCURSESW
+
+# Check for Sun RPC headers and library.
+AC_CHECK_HEADER([rpc/types.h], [HAVE_SUN_RPC=yes], [HAVE_SUN_RPC=no])
+AC_SEARCH_LIBS([clnt_create], [], [:], [HAVE_SUN_RPC=no])
+AC_SUBST([HAVE_SUN_RPC])
+
+if test -f ./$ac_unique_file; then
# Configuring in source directory; don't create any Makefiles.
makefiles=
else
@@ -43,7 +247,8 @@ else
echo ${file}:build.mk.in; done`"
fi
-AC_OUTPUT(config.make ${makefiles})
+AC_CONFIG_FILES([config.make ${makefiles}])
+AC_OUTPUT
dnl Local Variables:
dnl comment-start: "dnl "
diff --git a/console-client/Makefile b/console-client/Makefile
new file mode 100644
index 00000000..22a492a9
--- /dev/null
+++ b/console-client/Makefile
@@ -0,0 +1,93 @@
+#
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004,
+# 2005, 2008, 2010 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 := console-client
+makemode := utilities
+
+targets = console
+CONSOLE_SRCS = console.c timer.c driver.c trans.c
+VGA_SO_SRCS = bdf.c vga-dynafont.c vga-dynacolor.c vga-support.c vga.c
+PC_KBD_SO_SRCS = pc-kbd.c kbd-repeat.c
+PC_MOUSE_SO_SRCS = pc-mouse.c
+GENERIC_SPEAKER_SO_SRCS = generic-speaker.c
+CURRENT_VCS_SO_SRCS = current-vcs.c
+ifneq ($(LIBNCURSESW),)
+NCURSESW_SO_SRCS = ncursesw.c
+endif
+SRCS = $(CONSOLE_SRCS) \
+ $(VGA_SO_SRCS) $(PC_KBD_SO_SRCS) $(PC_MOUSE_SO_SRCS) \
+ $(GENERIC_SPEAKER_SO_SRCS) $(CURRENT_VCS_SO_SRCS) $(NCURSESW_SO_SRCS)
+LCLHDRS = timer.h driver.h display.h input.h bell.h \
+ unicode.h bdf.h mach-inputdev.h \
+ vga-dynafont.h vga-dynacolor.h vga-hw.h vga-support.h \
+ trans.h
+
+OBJS = $(SRCS:.c=.o) kdioctlServer.o
+HURDLIBS = cons threads ports netfs fshelp iohelp ihash shouldbeinlibc
+LDLIBS = -ldl
+module-dir = $(libdir)/hurd/console
+console-LDFLAGS = -Wl,-E
+
+# In seeking, thou shalt find it!
+CPPFLAGS += -DQUAERENDO_INVENIETIS
+
+include ../Makeconf
+
+driver-CPPFLAGS = -D'CONSOLE_DEFPATH="$(module-dir)\0"' \
+ -D'CONSOLE_SONAME_SUFFIX=".so.$(hurd-version)"'
+
+console: $(CONSOLE_SRCS:.c=.o) \
+ ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a \
+ ../libcons/libcons.a ../libports/libports.a \
+ ../libthreads/libthreads.a ../libshouldbeinlibc/libshouldbeinlibc.a
+
+modules = vga pc_kbd generic_speaker pc_mouse current_vcs
+
+vga-CPPFLAGS = -DDEFAULT_VGA_FONT_DIR=\"${datadir}/hurd/\"
+vga.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(VGA_SO_SRCS))
+pc_kbd.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(PC_KBD_SO_SRCS)) \
+ kdioctlServer_pic.o
+pc_mouse.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(PC_MOUSE_SO_SRCS))
+generic_speaker.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(GENERIC_SPEAKER_SO_SRCS))
+current_vcs.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(CURRENT_VCS_SO_SRCS))
+
+ifneq ($(LIBNCURSESW),)
+modules += ncursesw
+ncursesw.so.$(hurd-version): $(patsubst %.c,%_pic.o,$(NCURSESW_SO_SRCS))
+ncursesw-CPPFLAGS = $(NCURSESW_INCLUDE)
+ncursesw-LDLIBS = $(LIBNCURSESW)
+endif
+
+all: $(addsuffix .so.$(hurd-version), $(modules))
+
+cleantarg += $(addsuffix .so.$(hurd-version), $(modules))
+
+install: $(module-dir) $(addprefix $(module-dir)/,$(addsuffix .so.$(hurd-version),$(modules)))
+
+$(module-dir):
+ @$(MKINSTALLDIRS) $@
+
+$(module-dir)/%: %
+ $(INSTALL_DATA) $< $@
+
+# You can use this rule to make a dynamically-loadable version of any
+# of the modules.
+%.so.$(hurd-version):
+ $(CC) -shared -Wl,-soname=$@ -o $@ $(rpath) \
+ $(CFLAGS) $($*-CFLAGS) $(LDFLAGS) \
+ '-Wl,-(' $($*-LDLIBS) '-Wl,-)' $^
diff --git a/console-client/bdf.c b/console-client/bdf.c
new file mode 100644
index 00000000..f62a2473
--- /dev/null
+++ b/console-client/bdf.c
@@ -0,0 +1,990 @@
+/* bdf.c - Parser for the Adobe Glyph Bitmap Distribution Format (BDF).
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann <marcus@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <search.h>
+
+#include "bdf.h"
+
+
+/* Return a statically allocated string describing the BDF error value
+ ERR. */
+const char *
+bdf_strerror (bdf_error_t err)
+{
+ switch (err)
+ {
+ case BDF_NO_ERROR:
+ return "Success";
+ case BDF_SYSTEM_ERROR:
+ return "System error";
+ case BDF_SYNTAX_ERROR:
+ return "Syntax error";
+ case BDF_INVALID_ARGUMENT:
+ return "Invalid Argument";
+ case BDF_COUNT_MISMATCH:
+ return "Count mismatch";
+ default:
+ return "Unknown error";
+ }
+}
+
+
+/* Copy the string starting from ARG and return the pointer to it in
+ STRING. If QUOTED is true, outer double quotes are stripped, and
+ two consecutive double quotes within the string are replaced by one
+ douple quotes. */
+static bdf_error_t
+parse_string (char *arg, char **string, int quoted)
+{
+ if (quoted)
+ {
+ char *value = ++arg;
+ do
+ {
+ value = strchr (value, '"');
+ if (!value)
+ return BDF_INVALID_ARGUMENT;
+ else if (*(value + 1) == '"')
+ {
+ char *copyp = value++;
+ while (*(++copyp))
+ *(copyp - 1) = *copyp;
+ *(copyp - 1) = 0;
+ }
+ }
+ while (*value != '"' || *(value + 1) == '"');
+ *value = 0;
+ }
+
+ *string = strdup (arg);
+ if (!*string)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+
+/* Parse the string STR for format TEMPLATE, and require an exact
+ match. Set err if a parsing error occurs. TEMPLATE must be a
+ string constant. */
+#define parse_template(str, template, rest...) \
+ do \
+ { \
+ int parse_template_count = -1; \
+ sscanf (str, template " %n", rest, &parse_template_count); \
+ if (parse_template_count == -1 || *(str + parse_template_count)) \
+ err = BDF_SYNTAX_ERROR; \
+ } \
+ while (0)
+
+
+#define hex2nr(c) (((c) >= '0' && (c) <= '9') ? (c) - '0' \
+ : (((c) >= 'a' && (c) <= 'f') ? (c) - 'a' + 10 \
+ : (((c) >= 'A' && (c) <= 'F') ? (c) - 'A' + 10 : 0)))
+
+/* Convert a two-digit hex number starting from LINE to a char and
+ return the result in BYTE. */
+static bdf_error_t
+parse_hexbyte (char *line, unsigned char *byte)
+{
+ if (!isxdigit (*line) || !isxdigit(*(line + 1)))
+ return BDF_SYNTAX_ERROR;
+ else
+ *byte = (hex2nr (*line) << 4) + hex2nr (*(line + 1));
+ return 0;
+}
+
+
+/* Like getline(), but keeps track of line count in COUNT, skips
+ COMMENT lines, and removes whitespace at the beginning and end of a
+ line. */
+static int
+next_line (char **line, int *size, FILE *file, int *count)
+{
+ int len;
+
+ do
+ {
+ len = getline (line, size, file);
+ if (len >= 0)
+ {
+ char *cline = *line;
+ if (count)
+ (*count)++;
+ if (!strncmp (cline, "COMMENT", 7))
+ len = 0;
+ else
+ while (len > 0 && (cline[len - 1] == '\n' || cline[len - 1] == '\r'
+ || cline[len - 1] == ' '
+ || cline[len - 1] == '\t'))
+ cline[--len] = 0;
+ }
+ }
+ while (len <= 0 && !feof (file) && !ferror (file));
+ return len;
+}
+
+
+/* Isolate the next white-space separated argument from the current
+ line, and set ARGP to the beginning of the next argument. It is an
+ error if there is no further argument. */
+static bdf_error_t
+find_arg (char **argp)
+{
+ char *arg = *argp;
+
+ arg = strchr (arg, ' ');
+ if (arg)
+ {
+ *(arg++) = 0;
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+ }
+ if (!arg || !*arg)
+ return BDF_SYNTAX_ERROR;
+ *argp = arg;
+ return 0;
+}
+
+
+/* Read the font from stream FILE, and return it in FONT. If
+ LINECOUNT is not zero, it will contain the number of lines in the
+ file at success, and the line an error occurred at failure. */
+bdf_error_t
+bdf_read (FILE *filep, bdf_font_t *font, int *linecount)
+{
+ bdf_error_t err = 0;
+ char *line = 0;
+ int line_size = 0;
+ int len;
+ int done = 0;
+ bdf_font_t bdf;
+ struct
+ {
+ /* Current line. */
+ enum { START, FONT, PROPERTIES, GLYPHS, GLYPH, BITMAP } location;
+ /* The number of properties parsed so far. */
+ int properties;
+ /* The number of glyphs parsed so far. */
+ int glyphs;
+
+ /* True if we have seen a SIZE keyword so far. */
+ unsigned int has_size : 1;
+ /* True if we have seen a FONTBOUNDINGBOX keyword so far. */
+ unsigned int has_fbbx : 1;
+ /* True if we have seen a METRICSSET keyword so far. */
+ unsigned int has_metricsset : 1;
+
+ /* Current glyph. */
+ struct bdf_glyph *glyph;
+ /* True if we have seen an ENCODING keyword for the glyph. */
+ unsigned int glyph_has_encoding : 1;
+ /* True if we have seen an BBX keyword for the glyph. */
+ unsigned int glyph_has_bbx : 1;
+ /* Width of the glyph in bytes. */
+ unsigned int glyph_bwidth;
+ /* Height of the glyph in pixel. */
+ unsigned int glyph_bheight;
+ /* How many bitmap lines have been parsed already. */
+ unsigned int glyph_blines;
+ } parser = { location: START, properties: 0, glyphs: 0,
+ has_size: 0, has_fbbx: 0 };
+
+ bdf = calloc (1, sizeof *bdf);
+ if (!bdf)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ if (linecount)
+ *linecount = 0;
+
+ while (!err && (len = next_line (&line, &line_size, filep, linecount)) >= 0)
+ {
+ switch (parser.location)
+ {
+ case START:
+ {
+ /* This is the start of the file, only comments are allowed
+ until STARTFONT is encountered. */
+ char *arg = line;
+ err = find_arg (&arg);
+
+ if (err)
+ continue;
+ if (!strcmp (line, "STARTFONT"))
+ {
+ char *minor = strchr (arg, '.');
+ if (minor)
+ *(minor++) = '\0';
+ parser.location = FONT;
+ parse_template (arg, "%i", &bdf->version_maj);
+ if (minor)
+ parse_template (minor, "%i", &bdf->version_min);
+ else
+ bdf->version_min = 0;
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case FONT:
+ {
+ /* This is the global header before the CHARS. */
+ char *arg = line;
+ err = find_arg (&arg);
+
+ if (err)
+ continue;
+ else if (!bdf->has_content_version
+ && !strcmp (line, "CONTENTVERSION"))
+ {
+ bdf->has_content_version = 1;
+ parse_template (arg, "%i", &bdf->content_version);
+ }
+ else if (!bdf->name && !strcmp (line, "FONT"))
+ err = parse_string (arg, &bdf->name, 0);
+ else if (!parser.has_size
+ && !strcmp (line, "SIZE"))
+ {
+ parser.has_size = 1;
+ parse_template (arg, "%i%i%i", &bdf->point_size,
+ &bdf->res_x, &bdf->res_y);
+ }
+ else if (!parser.has_fbbx && !strcmp (line, "FONTBOUNDINGBOX"))
+ {
+ parser.has_fbbx = 1;
+ parse_template (arg, "%i%i%i%i", &bdf->bbox.width,
+ &bdf->bbox.height, &bdf->bbox.offx,
+ &bdf->bbox.offy);
+ }
+ else if (!parser.has_metricsset && !strcmp (line, "METRICSSET"))
+ {
+ parser.has_metricsset = 1;
+ parse_template (arg, "%i", &bdf->metricsset);
+ if (!err && (bdf->metricsset < 0
+ || bdf->metricsset > 2))
+ err = BDF_INVALID_ARGUMENT;
+ }
+ else if (!bdf->properties && !strcmp (line, "STARTPROPERTIES"))
+ {
+ parser.location = PROPERTIES;
+ parse_template (arg, "%i", &bdf->properties_count);
+ if (!err && (bdf->properties_count <= 0))
+ err = BDF_INVALID_ARGUMENT;
+ if (err)
+ goto leave;
+ bdf->__properties_allocated = bdf->properties_count;
+ bdf->properties = calloc (bdf->properties_count,
+ sizeof (struct bdf_property));
+ if (!bdf->properties)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ else if (!strcmp (line, "CHARS"))
+ {
+ /* This marks the end of the first section, so check
+ for mandatory global options. */
+ if (!bdf->name || !parser.has_size || !parser.has_fbbx)
+ err = BDF_SYNTAX_ERROR;
+ else
+ {
+ parser.location = GLYPHS;
+ parse_template (arg, "%i", &bdf->glyphs_count);
+ if (!err && (bdf->glyphs_count < 0))
+ err = BDF_INVALID_ARGUMENT;
+ if (!err)
+ {
+ bdf->__glyphs_allocated = bdf->glyphs_count;
+ bdf->glyphs = calloc (bdf->glyphs_count,
+ sizeof (struct bdf_glyph));
+ if (!bdf->glyphs)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ }
+ }
+ else if (!bdf->has_swidth && !strcmp (line, "SWIDTH"))
+ {
+ bdf->has_swidth = 1;
+ parse_template (arg, "%i%i", &bdf->swidth.x, &bdf->swidth.y);
+ }
+ else if (!bdf->has_dwidth && !strcmp (line, "DWIDTH"))
+ {
+ bdf->has_dwidth = 1;
+ parse_template (arg, "%i%i", &bdf->dwidth.x, &bdf->dwidth.y);
+ }
+ else if (!bdf->has_swidth1 && !strcmp (line, "SWIDTH1"))
+ {
+ bdf->has_swidth1 = 1;
+ parse_template (arg, "%i%i", &bdf->swidth1.x, &bdf->swidth1.y);
+ }
+ else if (!bdf->has_dwidth1 && !strcmp (line, "DWIDTH1"))
+ {
+ bdf->has_dwidth1 = 1;
+ parse_template (arg, "%i%i", &bdf->dwidth1.x, &bdf->dwidth1.y);
+ }
+ else if (!bdf->has_vvector && !strcmp (line, "VVECTOR"))
+ {
+ bdf->has_vvector = 1;
+ parse_template (arg, "%i%i", &bdf->vvector.x, &bdf->vvector.y);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case PROPERTIES:
+ /* This is the property list in the global header, between
+ STARTPROPERTIES and ENDPROPERTIES. */
+ if (!strcmp (line, "ENDPROPERTIES"))
+ {
+ parser.location = FONT;
+ if (parser.properties != bdf->properties_count)
+ err = BDF_COUNT_MISMATCH;
+ }
+ else
+ {
+ if (parser.properties == bdf->properties_count)
+ err = BDF_COUNT_MISMATCH;
+ else
+ {
+ struct bdf_property *prop
+ = &bdf->properties[parser.properties++];
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+
+ err = parse_string (line, &prop->name, 0);
+ if (!err)
+ {
+ if (*arg == '"')
+ {
+ prop->type = BDF_PROPERTY_STRING;
+ err = parse_string (arg, &prop->value.string, 1);
+ }
+ else
+ {
+ prop->type = BDF_PROPERTY_NUMBER;
+ parse_template (arg, "%i", &prop->value.number);
+ }
+ }
+ }
+ }
+ break;
+
+ case GLYPHS:
+ /* This is the second section of the file, containing the
+ glyphs. */
+ if (!strcmp (line, "ENDFONT"))
+ {
+ if (parser.glyphs != bdf->glyphs_count)
+ err = BDF_COUNT_MISMATCH;
+ done = 1;
+ }
+ else
+ {
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+ else if (!strcmp (line, "STARTCHAR"))
+ {
+ if (parser.glyphs == bdf->glyphs_count)
+ err = BDF_COUNT_MISMATCH;
+
+ parser.location = GLYPH;
+ parser.glyph = &bdf->glyphs[parser.glyphs++];
+ parser.glyph_has_encoding = 0;
+ parser.glyph_has_bbx = 0;
+ parser.glyph_blines = 0;
+ err = parse_string (arg, &(parser.glyph->name), 0);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case GLYPH:
+ /* This is a glyph, but not its bitmap yet. */
+ if (!strcmp (line, "BITMAP"))
+ {
+ if (!parser.glyph_has_encoding
+ || !parser.glyph_has_bbx
+
+ /* In writing mode 0, SWIDTH and DWIDTH are mandatory. */
+ || (bdf->metricsset != 1
+ && (!(parser.glyph->has_swidth || bdf->has_swidth)
+ || !(parser.glyph->has_dwidth || bdf->has_dwidth)))
+
+ /* In writing mode 1, SWIDTH1, DWIDTH1 and VVECTOR
+ are mandatory. */
+ || (bdf->metricsset != 0
+ && (!(parser.glyph->has_swidth1 || bdf->has_swidth1)
+ || !(parser.glyph->has_dwidth1 || bdf->has_dwidth1)
+ || !(parser.glyph->has_vvector
+ || bdf->has_vvector))))
+ err = BDF_SYNTAX_ERROR;
+
+ parser.location = BITMAP;
+ parser.glyph->bitmap = malloc (parser.glyph_bwidth
+ * parser.glyph_bheight);
+ if (!parser.glyph->bitmap)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ else
+ {
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+ else if (!parser.glyph_has_encoding
+ && !strcmp (line, "ENCODING"))
+ {
+ parser.glyph_has_encoding = 1;
+ parse_template (arg, "%i", &parser.glyph->encoding);
+ if (err == BDF_SYNTAX_ERROR)
+ {
+ err = 0;
+ parse_template (arg, "%i%i", &parser.glyph->encoding,
+ &parser.glyph->internal_encoding);
+ if (!err && parser.glyph->encoding != -1)
+ err = BDF_SYNTAX_ERROR;
+ }
+ }
+ else if (!parser.glyph_has_bbx && !strcmp (line, "BBX"))
+ {
+ parser.glyph_has_bbx = 1;
+ parse_template (arg, "%i%i%i%i", &parser.glyph->bbox.width,
+ &parser.glyph->bbox.height,
+ &parser.glyph->bbox.offx,
+ &parser.glyph->bbox.offy);
+ if (!err)
+ {
+ parser.glyph_bwidth = (parser.glyph->bbox.width + 7) / 8;
+ parser.glyph_bheight = parser.glyph->bbox.height;
+ }
+ }
+ else if (!parser.glyph->has_swidth && !strcmp (line, "SWIDTH"))
+ {
+ parser.glyph->has_swidth = 1;
+ parse_template (arg, "%i%i", &parser.glyph->swidth.x,
+ &parser.glyph->swidth.y);
+ }
+ else if (!parser.glyph->has_dwidth && !strcmp (line, "DWIDTH"))
+ {
+ parser.glyph->has_dwidth = 1;
+ parse_template (arg, "%i%i", &parser.glyph->dwidth.x,
+ &parser.glyph->dwidth.y);
+ }
+ else if (!parser.glyph->has_swidth1 && !strcmp (line, "SWIDTH1"))
+ {
+ parser.glyph->has_swidth1 = 1;
+ parse_template (arg, "%i%i", &parser.glyph->swidth1.x,
+ &parser.glyph->swidth1.y);
+ }
+ else if (!parser.glyph->has_dwidth1 && !strcmp (line, "DWIDTH1"))
+ {
+ parser.glyph->has_dwidth1 = 1;
+ parse_template (arg, "%i%i", &parser.glyph->dwidth1.x,
+ &parser.glyph->dwidth1.y);
+ }
+ else if (!parser.glyph->has_vvector && !strcmp (line, "VVECTOR"))
+ {
+ parser.glyph->has_vvector = 1;
+ parse_template (arg, "%i%i", &parser.glyph->vvector.x,
+ &parser.glyph->vvector.y);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case BITMAP:
+ /* This is the bitmap of a glyph. */
+ if (!strcmp (line, "ENDCHAR"))
+ {
+ if (parser.glyph_blines != parser.glyph_bheight)
+ err = BDF_COUNT_MISMATCH;
+ parser.location = GLYPHS;
+ parser.glyph = 0;
+ }
+ else
+ {
+ if (strlen (line) != 2 * parser.glyph_bwidth)
+ err = BDF_SYNTAX_ERROR;
+ else if (parser.glyph_blines == parser.glyph_bheight)
+ err = BDF_COUNT_MISMATCH;
+ else
+ {
+ char *number = line;
+ unsigned char *bline = parser.glyph->bitmap
+ + parser.glyph_bwidth * parser.glyph_blines++;
+
+ do
+ {
+ err = parse_hexbyte (number, bline);
+ number += 2;
+ bline++;
+ }
+ while (!err && *number);
+ }
+ }
+ break;
+ }
+ }
+ while (!err && !done && !feof (filep) && !ferror (filep));
+
+ leave:
+ if (ferror (filep))
+ err = ferror (filep);
+ if (err)
+ free (bdf);
+ else
+ *font = bdf;
+ return err;
+}
+
+
+/* Destroy the BDF font object and release all associated
+ resources. */
+void
+bdf_destroy (bdf_font_t font)
+{
+ int i;
+ for (i = 0; i < font->glyphs_count; i++)
+ free (font->glyphs[i].name);
+ free (font->glyphs);
+ for (i = 0; i < font->properties_count; i++)
+ {
+ free (font->properties[i].name);
+ if (font->properties[i].type == BDF_PROPERTY_STRING)
+ free (font->properties[i].value.string);
+ }
+ free (font->properties);
+ free (font->name);
+}
+
+
+bdf_error_t
+bdf_new (bdf_font_t *font, int version_maj, int version_min,
+ const char *name, int point_size, int res_x, int res_y,
+ int bbox_width, int bbox_height, int bbox_offx, int bbox_offy,
+ int metricsset)
+{
+ bdf_font_t bdf;
+
+ if (!font
+ || (version_maj != 2)
+ || (version_min != 1 && version_min != 2)
+ || !name)
+ return BDF_INVALID_ARGUMENT;
+
+ bdf = calloc (1, sizeof *bdf);
+ if (!bdf)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ bdf->version_maj = version_maj;
+ bdf->version_min = version_min;
+ bdf->name = strdup (name);
+ if (!name)
+ {
+ free (bdf);
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ bdf->point_size = point_size;
+ bdf->res_x = res_x;
+ bdf->res_y = res_y;
+ bdf->bbox.width = bbox_width;
+ bdf->bbox.height = bbox_height;
+ bdf->bbox.offx = bbox_offx;
+ bdf->bbox.offy = bbox_offy;
+ bdf->metricsset = metricsset;
+ *font = bdf;
+ return 0;
+}
+
+
+#define bdf_set_something(what) \
+bdf_error_t \
+bdf_set_##what (bdf_font_t font, int glyph, int x, int y) \
+{ \
+ if (x < 0 || y < 0 || glyph > font->glyphs_count - 1) \
+ return BDF_INVALID_ARGUMENT; \
+ if (glyph < 0) \
+ { \
+ font->has_##what = 1; \
+ font->what.x = x; \
+ font->what.y = y; \
+ } \
+ else \
+ { \
+ font->glyphs[glyph].has_##what = 1; \
+ font->glyphs[glyph].what.x = x; \
+ font->glyphs[glyph].what.y = y; \
+ } \
+ return 0; \
+}
+
+bdf_set_something (swidth)
+bdf_set_something (dwidth)
+bdf_set_something (swidth1)
+bdf_set_something (dwidth1)
+bdf_set_something (vvector)
+
+
+static bdf_error_t
+expand_properties (bdf_font_t font, int count)
+{
+ if (font->__properties_allocated == font->properties_count)
+ {
+ struct bdf_property *new;
+ new = realloc (font->properties,
+ (font->__properties_allocated + count)
+ * sizeof (struct bdf_property));
+ if (!new)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->__properties_allocated += count;
+ font->properties = new;
+ }
+ return 0;
+}
+
+
+/* Add a new string property to the font FONT. */
+bdf_error_t
+bdf_add_string_property (bdf_font_t font, const char *name, const char *value)
+{
+ bdf_error_t err;
+ struct bdf_property *prop;
+
+ err = expand_properties (font, 16);
+ if (err)
+ {
+ err = expand_properties (font, 1);
+ if (err)
+ return err;
+ }
+
+ prop = &font->properties[font->properties_count];
+ prop->type = BDF_PROPERTY_STRING;
+ prop->name = strdup (name);
+ if (prop->name)
+ prop->value.string = strdup (value);
+ if (!prop->name || !prop->value.string)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->properties_count++;
+ return 0;
+}
+
+
+/* Add a new number property to the font FONT. */
+bdf_error_t
+bdf_add_number_property (bdf_font_t font, const char *name, int value)
+{
+ bdf_error_t err;
+ struct bdf_property *prop;
+
+ err = expand_properties (font, 16);
+ if (err)
+ {
+ err = expand_properties (font, 1);
+ if (err)
+ return err;
+ }
+
+ prop = &font->properties[font->properties_count];
+ prop->type = BDF_PROPERTY_NUMBER;
+ prop->name = strdup (name);
+ if (!prop->name)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ prop->value.number = value;
+ font->properties_count++;
+ return 0;
+}
+
+
+static bdf_error_t
+expand_glyphs (bdf_font_t font, int count)
+{
+ if (font->__glyphs_allocated == font->glyphs_count)
+ {
+ struct bdf_glyph *new;
+ new = realloc (font->glyphs,
+ (font->__glyphs_allocated + count)
+ * sizeof (struct bdf_glyph));
+ if (!new)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->__glyphs_allocated += count;
+ font->glyphs = new;
+ }
+ return 0;
+}
+
+
+/* Add a new glyph with the specified paramters to the font FONT. If
+ encoding is -1, internal_encoding specifies the internal
+ encoding. All other parameters are mandatory. */
+bdf_error_t
+bdf_add_glyph (bdf_font_t font, const char *name, int encoding,
+ int internal_encoding, int bbox_width, int bbox_height,
+ int bbox_offx, int bbox_offy, const unsigned char *bitmap)
+{
+ bdf_error_t err;
+ struct bdf_glyph *glyph;
+ int bsize;
+
+ err = expand_glyphs (font, 64);
+ if (err)
+ {
+ err = expand_glyphs (font, 1);
+ if (err)
+ return err;
+ }
+
+ glyph = &font->glyphs[font->glyphs_count];
+ memset (glyph, 0, sizeof (*glyph));
+
+ glyph->name = strdup (name);
+ if (!glyph->name)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ glyph->encoding = encoding;
+ if (encoding == -1)
+ glyph->internal_encoding = internal_encoding;
+ glyph->bbox.width = bbox_width;
+ glyph->bbox.height = bbox_height;
+ glyph->bbox.offx = bbox_offx;
+ glyph->bbox.offy = bbox_offy;
+ bsize = ((bbox_width + 7) / 8) * bbox_height;
+ glyph->bitmap = malloc (bsize);
+ if (!glyph->bitmap)
+ {
+ free (glyph->name);
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ memcpy (glyph->bitmap, bitmap, bsize);
+ font->glyphs_count++;
+ return 0;
+}
+
+
+/* Write the font FONT in BDF format to stream FILEP. */
+bdf_error_t
+bdf_write (FILE *filep, bdf_font_t font)
+{
+ int index;
+
+ if (font->version_maj != 2
+ || (font->version_min != 1 && font->version_min != 2))
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "STARTFONT %i.%i\n", font->version_maj, font->version_min);
+
+ if (!font->name)
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "FONT %s\n", font->name);
+ fprintf (filep, "SIZE %i %i %i\n", font->point_size,
+ font->res_x, font->res_y);
+ fprintf (filep, "FONTBOUNDINGBOX %i %i %i %i\n",
+ font->bbox.width, font->bbox.height,
+ font->bbox.offx, font->bbox.offy);
+ if (font->has_swidth)
+ fprintf (filep, "SWIDTH %i %i\n", font->swidth.x, font->swidth.y);
+ if (font->has_dwidth)
+ fprintf (filep, "DWIDTH %i %i\n", font->dwidth.x, font->dwidth.y);
+ if (font->has_swidth1)
+ fprintf (filep, "SWIDTH1 %i %i\n", font->swidth1.x, font->swidth1.y);
+ if (font->has_dwidth1)
+ fprintf (filep, "DWIDTH1 %i %i\n", font->dwidth1.x, font->dwidth1.y);
+ if (font->has_vvector)
+ fprintf (filep, "VVECTOR %i %i\n", font->vvector.x, font->vvector.y);
+ if (font->properties_count < 0)
+ return BDF_INVALID_ARGUMENT;
+ /* XXX We always print out a properties block for xmbdfed's sake. */
+ fprintf (filep, "STARTPROPERTIES %i\n", font->properties_count);
+ if (font->properties_count > 0)
+ {
+ fprintf (filep, "STARTPROPERTIES %i\n", font->properties_count);
+ for (index = 0; index < font->properties_count; index++)
+ {
+ struct bdf_property *prop = &font->properties[index];
+
+ if (prop->type == BDF_PROPERTY_NUMBER)
+ fprintf (filep, "%s %i\n", prop->name, prop->value.number);
+ else
+ {
+ char *val = prop->value.string;
+
+ fprintf (filep, "%s \"", prop->name);
+ while (*val)
+ {
+ fputc (*val, filep);
+ if (*(val++) == '"')
+ fputc ('"', filep);
+ }
+ fprintf (filep, "\"\n");
+ }
+ }
+ }
+ fprintf (filep, "ENDPROPERTIES\n");
+ if (font->glyphs_count <= 0)
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "CHARS %i\n", font->glyphs_count);
+
+ for (index = 0; index < font->glyphs_count; index++)
+ {
+ struct bdf_glyph *glyph = &font->glyphs[index];
+ unsigned char *bitmap;
+ int row, col;
+
+ fprintf (filep, "STARTCHAR %s\n", glyph->name);
+ if (glyph->encoding != -1)
+ fprintf (filep, "ENCODING %i\n", glyph->encoding);
+ else
+ fprintf (filep, "ENCODING %i %i\n", glyph->encoding,
+ glyph->internal_encoding);
+ if (glyph->has_swidth)
+ fprintf (filep, "SWIDTH %i %i\n", glyph->swidth.x, glyph->swidth.y);
+ if (glyph->has_dwidth)
+ fprintf (filep, "DWIDTH %i %i\n", glyph->dwidth.x, glyph->dwidth.y);
+ if (glyph->has_swidth1)
+ fprintf (filep, "SWIDTH1 %i %i\n", glyph->swidth1.x, glyph->swidth1.y);
+ if (glyph->has_dwidth1)
+ fprintf (filep, "DWIDTH1 %i %i\n", glyph->dwidth1.x, glyph->dwidth1.y);
+ if (glyph->has_vvector)
+ fprintf (filep, "VVECTOR %i %i\n", glyph->vvector.x, glyph->vvector.y);
+ fprintf (filep, "BBX %i %i %i %i\n", glyph->bbox.width,
+ glyph->bbox.height, glyph->bbox.offx, glyph->bbox.offy);
+ fprintf (filep, "BITMAP\n");
+ bitmap = glyph->bitmap;
+ for (row = 0; row < glyph->bbox.height; row++)
+ {
+ for (col = 0; col < (glyph->bbox.width + 7) / 8; col++)
+ fprintf (filep, "%02X", *(bitmap++));
+ fputc ('\n', filep);
+ }
+ fprintf (filep, "ENDCHAR\n");
+ }
+ fprintf (filep, "ENDFONT\n");
+ if (ferror (filep))
+ {
+ errno = ferror (filep);
+ return BDF_SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+
+/* The function returns -1 if the encoding of glyph A is lower than
+ the encoding of glyph B, 1 if it is the other way round, and 0 if
+ the encoding of both glyphs is the same. */
+int
+bdf_compare_glyphs (const void *a, const void *b)
+{
+ struct bdf_glyph *first = (struct bdf_glyph *) a;
+ struct bdf_glyph *second = (struct bdf_glyph *) b;
+
+ if (first->encoding < second->encoding)
+ return -1;
+ else if (first->encoding > second->encoding)
+ return 1;
+ else
+ {
+ if (first->encoding == -1)
+ {
+ if (first->internal_encoding < second->internal_encoding)
+ return -1;
+ else if (first->internal_encoding > second->internal_encoding)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+}
+
+
+/* Sort the glyphs in the font FONT. This must be called before using
+ bdf_find_glyphs, after the font has been created or after new
+ glyphs have been added to the font. */
+void
+bdf_sort_glyphs (bdf_font_t font)
+{
+ qsort (font->glyphs, font->glyphs_count, sizeof (struct bdf_glyph),
+ bdf_compare_glyphs);
+}
+
+
+/* Find the glyph with the encoding ENC (and INTERNAL_ENC, if ENC is
+ -1) in the font FONT. Requires that the glyphs in the font are
+ sorted. */
+struct bdf_glyph *
+bdf_find_glyph (bdf_font_t font, int enc, int internal_enc)
+{
+ struct bdf_glyph key = { encoding: enc, internal_encoding: internal_enc };
+ return bsearch (&key, font->glyphs, font->glyphs_count,
+ sizeof (struct bdf_glyph), bdf_compare_glyphs);
+}
diff --git a/console-client/bdf.h b/console-client/bdf.h
new file mode 100644
index 00000000..17cd0235
--- /dev/null
+++ b/console-client/bdf.h
@@ -0,0 +1,272 @@
+/* bdf.h - Parser for the Adobe Glyph Bitmap Distribution Format (BDF).
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann <marcus@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _BDF_H_
+#define _BDF_H_
+
+#include <stdio.h>
+
+/* Version 2.2 of the Glyph Bitmap Distribution Format Specification
+ was released by Adobe 22 March 1993 and is a superset of version 2.1.
+
+ The format of a BDF file is a human-readable ASCII text file.
+ Every line consists of a keyword, which may be followed by one or
+ more arguments. The specification is vague about the exact data
+ types of the arguments, so we treat a string as an 8-bit string
+ which must not contain a binary null, and a number like an integer
+ as an int. Leading and trailing white space are removed, multiple
+ spaces that separate arguments are replaced by a single white
+ space, and empty lines are ignored. */
+
+
+/* Possible error values returned by the BDF functions. */
+typedef enum
+{
+ /* No error occurred. This is guaranteed to be zero. */
+ BDF_NO_ERROR = 0,
+
+ /* A system error occurred. The caller should consult errno. */
+ BDF_SYSTEM_ERROR,
+
+ /* All following errors indicate that the file is not a valid BDF
+ file. */
+ BDF_SYNTAX_ERROR,
+
+ /* An argument is out of range or of an invalid type. */
+ BDF_INVALID_ARGUMENT,
+
+ /* The number of properties, glyphs or bitmap lines is
+ incorrect. */
+ BDF_COUNT_MISMATCH
+} bdf_error_t;
+
+/* Return a statically allocated string describing the error value ERR. */
+const char *bdf_strerror (bdf_error_t err);
+
+
+/* A property in the BDF font file is an unspecified KEYWORD VALUE
+ pair in a line after STARTPROPERTIES and before ENDPROPERTIES.
+ VALUE can be an integer or a string in double quotes (two
+ consecutives double quotes can be used to include a double quote in
+ the string. */
+struct bdf_property
+{
+ /* The property name. */
+ char *name;
+
+ /* The type indicates which member of the union is valid. */
+ enum { BDF_PROPERTY_NUMBER, BDF_PROPERTY_STRING } type;
+ union
+ {
+ int number;
+ char *string;
+ } value;
+};
+typedef struct bdf_property *bdf_property_t;
+
+/* The bounding box of a font or a glyph within. */
+struct bdf_bbox
+{
+ int width;
+ int height;
+ int offx;
+ int offy;
+};
+
+/* A vector, used for displacement and resolution. */
+struct bdf_vector
+{
+ int x;
+ int y;
+};
+
+/* A single glyph in the font. */
+struct bdf_glyph
+{
+ /* The name of the glyph. */
+ char *name;
+
+ /* The Adode Standard Encoding of the glyph, or -1 if not
+ available. */
+ int encoding;
+
+ /* If encoding is -1, internal_encoding contains the internal
+ encoding of the glyph. The internal encoding is private to the
+ font and the application. */
+ int internal_encoding;
+
+ /* The bounding box of the glyph. The width of the bounding box,
+ divided by 8 (rounding up), specifies how many bytes are used in
+ the bitmap for each row of the glyph. The height specifies the
+ number of rows. */
+ struct bdf_bbox bbox;
+
+ /* The bitmap of the glyph, row-by-row from top to bottom, and
+ byte-by-byte within a row from left to right. Within a byte, the
+ most significant bit is left in the glyph. */
+ unsigned char *bitmap;
+
+ /* If the writing direction is horizontal, SWIDTH and DWIDTH are
+ relevant. If the writing direction is vertical, SWIDTH1, DWIDTH1
+ and VVECTOR are relevant. Relevant values have to be specified
+ here, or font-wide in the global section. A global value can be
+ overridden for individual glyphs. */
+ int has_swidth : 1;
+ int has_dwidth : 1;
+ int has_swidth1 : 1;
+ int has_dwidth1 : 1;
+ int has_vvector : 1;
+ struct bdf_vector swidth;
+ struct bdf_vector dwidth;
+ struct bdf_vector swidth1;
+ struct bdf_vector dwidth1;
+ struct bdf_vector vvector;
+};
+
+/* A font is a set of glyphs with some font-wide attributes. */
+struct bdf_font
+{
+ /* The version of the font format. Should be 2.1 or 2.2. It is
+ split up into major and minor component to make precise
+ comparison possible. */
+ int version_maj;
+ int version_min;
+
+ /* The font name. */
+ char *name;
+
+ /* The content version, if available. The content version indicates
+ the revision of the appearance of the glyphs within the font. */
+ int has_content_version : 1;
+ int content_version;
+
+ /* The point size of the font in device pixels. */
+ int point_size;
+
+ /* The resolution of the display the font is intended for (dpi).
+ This is needed if you want to scale the glyphs for a different
+ device than they were intended for. */
+ int res_x;
+ int res_y;
+
+ /* The global bounding box parameters. */
+ struct bdf_bbox bbox;
+
+ int __properties_allocated;
+ int properties_count;
+ struct bdf_property *properties;
+ int __glyphs_allocated;
+ int glyphs_count;
+ struct bdf_glyph *glyphs;
+
+ /* The metricsset. If 0, the font has a horizontal writing
+ direction. If 1, the font has a vertical writing direction. If
+ 2, the font has a mixed writing direction. */
+ int metricsset;
+
+ /* The following have the same meaning as the corresponding members
+ in the glyph structure and specify a font wide default which must
+ be used if the glyph does not provide its own values. */
+ int has_swidth : 1;
+ int has_dwidth : 1;
+ int has_swidth1 : 1;
+ int has_dwidth1 : 1;
+ int has_vvector : 1;
+ struct bdf_vector swidth;
+ struct bdf_vector dwidth;
+ struct bdf_vector swidth1;
+ struct bdf_vector dwidth1;
+ struct bdf_vector vvector;
+};
+typedef struct bdf_font *bdf_font_t;
+
+
+/* Read the font from stream FILE, and return it in FONT. If
+ LINECOUNT is not zero, it will contain the number of lines in the
+ file at success, and the current line an error occurred at
+ failure. */
+bdf_error_t bdf_read (FILE *file, bdf_font_t *font, int *linecount);
+
+/* Destroy the BDF font object and release all associated
+ resources. */
+void bdf_destroy (bdf_font_t font);
+
+/* Create a new font object with the specified mandatory
+ parameters. */
+bdf_error_t bdf_new (bdf_font_t *font, int version_maj, int version_min,
+ const char *name, int point_size, int res_x, int res_y,
+ int bbox_width, int bbox_height, int bbox_offx,
+ int bbox_offy, int metricsset);
+
+/* Set the SWIDTH of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_swidth (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the DWIDTH of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_dwidth (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the SWIDTH1 of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_swidth1 (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the DWIDTH1 of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_dwidth1 (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the VVECTOR of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_vvector (bdf_font_t font, int glyph, int x, int y);
+
+/* Add a new string property to the font FONT. */
+bdf_error_t bdf_add_string_property (bdf_font_t font, const char *name,
+ const char *value);
+
+/* Add a new number property to the font FONT. */
+bdf_error_t bdf_add_number_property (bdf_font_t font, const char *name,
+ int value);
+
+/* Add a new glyph with the specified paramters to the font FONT. If
+ encoding is -1, internal_encoding specifies the internal
+ encoding. All other parameters are mandatory. */
+bdf_error_t bdf_add_glyph (bdf_font_t font, const char *name, int encoding,
+ int internal_encoding, int bbox_width,
+ int bbox_height, int bbox_offx, int bbox_offy,
+ const unsigned char *bitmap);
+
+/* Write the font FONT in BDF format to stream FILEP. */
+bdf_error_t bdf_write (FILE *filep, bdf_font_t font);
+
+/* The function returns -1 if the encoding of glyph A is lower than
+ the encoding of glyph B, 1 if it is the other way round, and 0 if
+ the encoding of both glyphs is the same. */
+int bdf_compare_glyphs (const void *a, const void *b);
+
+/* Sort the glyphs in the font FONT. This must be called before using
+ bdf_find_glyphs, after the font has been created or after new
+ glyphs have been added to the font. */
+void bdf_sort_glyphs (bdf_font_t font);
+
+/* Find the glyph with the encoding ENC (and INTERNAL_ENC, if ENC is
+ -1) in the font FONT. Requires that the glyphs in the font are
+ sorted. */
+struct bdf_glyph *bdf_find_glyph (bdf_font_t font, int enc, int internal_enc);
+
+#endif /* _BDF_H_ */
diff --git a/console-client/bell.h b/console-client/bell.h
new file mode 100644
index 00000000..8235cca1
--- /dev/null
+++ b/console-client/bell.h
@@ -0,0 +1,56 @@
+/* bell.h - The interface to and for a bell driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _BELL_H_
+#define _BELL_H_ 1
+
+#include <errno.h>
+
+
+/* The bell drivers are set up by the driver's initialization routine
+ and added to the console client with driver_add_bell. All
+ subsequent operations on the display are fully synchronized by the
+ caller. The driver deinitialization routine should call
+ driver_remove_bell. */
+
+/* Forward declaration. */
+struct bell_ops;
+typedef struct bell_ops *bell_ops_t;
+
+/* Add the bell HANDLE with the operations OPS to the console client.
+ As soon as this is called, operations on this bell may be
+ performed, even before the function returns. */
+error_t driver_add_bell (bell_ops_t ops, void *handle);
+
+/* Remove the bell HANDLE with the operations OPS from the console
+ client. As soon as this function returns, no operations will be
+ performed on the bell anymore. */
+error_t driver_remove_bell (bell_ops_t ops, void *handle);
+
+struct bell_ops
+{
+ /* Beep! the bell HANDLE. */
+ error_t (*beep) (void *handle);
+
+ /* Do not use, do not remove. */
+ void (*deprecated) (void *handle, unsigned int key);
+};
+
+#endif /* _BELL_H_ */
diff --git a/console-client/console.c b/console-client/console.c
new file mode 100644
index 00000000..06a8c1ac
--- /dev/null
+++ b/console-client/console.c
@@ -0,0 +1,642 @@
+/* console.c -- A pluggable console client.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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 */
+
+#include <argp.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <wchar.h>
+#include <error.h>
+#include <assert.h>
+
+#include <cthreads.h>
+
+#include <hurd/console.h>
+#include <hurd/cons.h>
+
+#include <version.h>
+
+#include "driver.h"
+#include "timer.h"
+#include "trans.h"
+
+const char *cons_client_name = "console";
+const char *cons_client_version = HURD_VERSION;
+
+/* The default node on which the console node is started. */
+#define DEFAULT_CONSOLE_NODE "/dev/cons"
+
+
+/* The global lock protects the active_vcons variable, and thus all
+ operations on the virtual console that is currently active. */
+static struct mutex global_lock;
+
+/* The active virtual console. This is the one currently
+ displayed. */
+static vcons_t active_vcons = NULL;
+
+/* Contains the VT id when switched away. */
+static int saved_id = 0;
+
+/* The console, used to switch back. */
+static cons_t saved_cons;
+
+/* The file name of the node on which the console translator is
+ set. */
+static char *console_node;
+
+
+/* Callbacks for input source drivers. */
+
+/* Returns current console ID. */
+error_t
+console_current_id (int *cur)
+{
+ vcons_t vcons;
+
+ mutex_lock (&global_lock);
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return ENODEV;
+ }
+ *cur = vcons->id;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+/* Switch the active console to console ID or DELTA (relative to the
+ active console). */
+error_t
+console_switch (int id, int delta)
+{
+ error_t err = 0;
+ vcons_t vcons;
+ vcons_t new_vcons;
+
+ /* We must give up our global lock before we can call back into
+ libcons. This is because cons_switch will lock CONS, and as
+ other functions in libcons lock CONS while calling back into our
+ functions which take the global lock (like cons_vcons_add), we
+ would deadlock. So we acquire a reference for VCONS to make sure
+ it isn't deallocated while we are outside of the global lock. We
+ also know that */
+
+ mutex_lock (&global_lock);
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return EINVAL;
+ }
+ ports_port_ref (vcons);
+ mutex_unlock (&global_lock);
+
+ err = cons_switch (vcons, id, delta, &new_vcons);
+ if (!err)
+ {
+ mutex_lock (&global_lock);
+ if (active_vcons != new_vcons)
+ {
+ cons_vcons_close (active_vcons);
+ active_vcons = new_vcons;
+ }
+ mutex_unlock (&new_vcons->lock);
+ ports_port_deref (vcons);
+ mutex_unlock (&global_lock);
+ }
+ return err;
+}
+
+
+/* Enter SIZE bytes from the buffer BUF into the currently active
+ console. This can be called by the input driver at any time. */
+error_t
+console_input (char *buf, size_t size)
+{
+ error_t err = 0;
+ vcons_t vcons;
+
+ mutex_lock (&global_lock);
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return EINVAL;
+ }
+ ports_port_ref (vcons);
+ mutex_unlock (&global_lock);
+
+ if (vcons)
+ {
+ err = cons_vcons_input (vcons, buf, size);
+ ports_port_deref (vcons);
+ }
+ return err;
+}
+
+
+/* Report the mouse event EV to the currently active console. This
+ can be called by the input driver at any time. */
+error_t
+console_move_mouse (mouse_event_t ev)
+{
+ error_t err;
+ vcons_t vcons;
+
+ mutex_lock (&global_lock);
+
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return EINVAL;
+ }
+ ports_port_ref (vcons);
+ mutex_unlock (&global_lock);
+
+ if (vcons)
+ {
+ err = cons_vcons_move_mouse (vcons, ev);
+ ports_port_deref (vcons);
+ }
+
+ mutex_unlock (&global_lock);
+
+ return 0;
+}
+
+
+/* Scroll the active console by TYPE and VALUE as specified by
+ cons_vcons_scrollback. */
+int
+console_scrollback (cons_scroll_t type, float value)
+{
+ int nr = 0;
+ vcons_t vcons;
+
+ mutex_lock (&global_lock);
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return EINVAL;
+ }
+ ports_port_ref (vcons);
+ mutex_unlock (&global_lock);
+
+ if (vcons)
+ {
+ nr = cons_vcons_scrollback (vcons, type, value);
+ ports_port_deref (vcons);
+ }
+ return nr;
+}
+
+
+/* Switch away from the console an external use of the console like
+ XFree. */
+void
+console_switch_away (void)
+{
+ mutex_lock (&global_lock);
+
+ driver_iterate
+ if (driver->ops->save_status)
+ driver->ops->save_status (driver->handle);
+
+ saved_id = active_vcons->id;
+ saved_cons = active_vcons->cons;
+ cons_vcons_close (active_vcons);
+ active_vcons = NULL;
+ mutex_unlock (&global_lock);
+}
+
+/* Switch back to the console client from an external user of the
+ console like XFree. */
+void
+console_switch_back (void)
+{
+ vcons_list_t conslist;
+ mutex_lock (&global_lock);
+
+ driver_iterate
+ if (driver->ops->restore_status)
+ driver->ops->restore_status (driver->handle);
+
+ if (saved_cons)
+ {
+ error_t err;
+
+ err = cons_lookup (saved_cons, saved_id, 1, &conslist);
+ if (err)
+ {
+ mutex_unlock (&global_lock);
+ return;
+ }
+
+ err = cons_vcons_open (saved_cons, conslist, &active_vcons);
+ if (err)
+ {
+ mutex_unlock (&global_lock);
+ return;
+ }
+
+ conslist->vcons = active_vcons;
+ saved_cons = NULL;
+ mutex_unlock (&active_vcons->lock);
+ }
+ mutex_unlock (&global_lock);
+}
+
+
+/* Exit the console client. Does not return. */
+void
+console_exit (void)
+{
+ driver_fini ();
+ exit (0);
+}
+
+/* Signal an error to the user. */
+void console_error (const wchar_t *const err_msg)
+{
+ mutex_lock (&global_lock);
+ bell_iterate
+ if (bell->ops->beep)
+ bell->ops->beep (bell->handle);
+ mutex_unlock (&global_lock);
+}
+
+#if QUAERENDO_INVENIETIS
+void
+console_deprecated (int key)
+{
+ mutex_lock (&global_lock);
+ input_iterate
+ if (input->ops->deprecated)
+ (*input->ops->deprecated) (input->handle, key);
+ display_iterate
+ if (display->ops->deprecated)
+ (*display->ops->deprecated) (display->handle, key);
+ bell_iterate
+ if (bell->ops->deprecated)
+ (*bell->ops->deprecated) (bell->handle, key);
+ mutex_unlock (&global_lock);
+}
+#endif /* QUAERENDO_INVENIETIS */
+
+
+/* Callbacks for libcons. */
+
+/* The user may define this function. It is called after a
+ virtual console entry was added. CONS is locked. */
+void
+cons_vcons_add (cons_t cons, vcons_list_t vcons_entry)
+{
+ error_t err = 0;
+ mutex_lock (&global_lock);
+ if (!active_vcons)
+ {
+ vcons_t vcons;
+
+ /* The first virtual console added to the list is automatically
+ opened after startup. */
+ err = cons_vcons_open (cons, vcons_entry, &vcons);
+ if (!err)
+ {
+ vcons_entry->vcons = vcons;
+ active_vcons = vcons;
+ mutex_unlock (&vcons->lock);
+ }
+ }
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user may define this function. Make the changes from
+ cons_vcons_write, cons_vcons_set_cursor_pos,
+ cons_vcons_set_cursor_status and cons_vcons_scroll active. VCONS
+ is locked and will have been continuously locked from the first
+ change since the last update on. This is the latest possible point
+ the user must make the changes visible from. The user can always
+ make the changes visible at a more convenient, earlier time. */
+void
+cons_vcons_update (vcons_t vcons)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->update)
+ display->ops->update (display->handle);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Set the cursor on virtual
+ console VCONS, which is locked, to position COL and ROW. */
+void
+cons_vcons_set_cursor_pos (vcons_t vcons, uint32_t col, uint32_t row)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->set_cursor_pos)
+ display->ops->set_cursor_pos (display->handle, col, row);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Set the cursor status of
+ virtual console VCONS, which is locked, to STATUS. */
+void
+cons_vcons_set_cursor_status (vcons_t vcons, uint32_t status)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->set_cursor_status)
+ display->ops->set_cursor_status (display->handle, status);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Scroll the content of virtual
+ console VCONS, which is locked, up by DELTA if DELTA is positive or
+ down by -DELTA if DELTA is negative. DELTA will never be zero, and
+ the absolute value if DELTA will be smaller than or equal to the
+ height of the screen matrix.
+
+ See <hurd/cons.h> for more information about this function. */
+void
+cons_vcons_scroll (vcons_t vcons, int delta)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->scroll)
+ display->ops->scroll (display->handle, delta);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Deallocate the scarce
+ resources (like font glyph slots, colors etc) in the LENGTH entries
+ of the screen matrix starting from position COL and ROW. This call
+ is immediately followed by a subsequent cons_vcons_write call with
+ the same LENGTH, COL and ROW arguments, and should help to make the
+ write successful. If there are no scarce resources, the caller
+ might do nothing. */
+void cons_vcons_clear (vcons_t vcons, size_t length,
+ uint32_t col, uint32_t row)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->clear)
+ display->ops->clear (display->handle, length, col, row);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Write LENGTH characters
+ starting from STR on the virtual console VCONS, which is locked,
+ starting from position COL and ROW. */
+void
+cons_vcons_write (vcons_t vcons, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->write)
+ display->ops->write (display->handle, str, length, col, row);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Make the virtual console
+ VCONS, which is locked, beep audibly. */
+void
+cons_vcons_beep (vcons_t vcons)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ bell_iterate
+ if (bell->ops->beep)
+ bell->ops->beep (bell->handle);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Make the virtual console
+ VCONS, which is locked, flash visibly. */
+void
+cons_vcons_flash (vcons_t vcons)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->flash)
+ display->ops->flash (display->handle);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Notice the current status of
+ the scroll lock flag. */
+void
+cons_vcons_set_scroll_lock (vcons_t vcons, int onoff)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ input_iterate
+ if (input->ops->set_scroll_lock_status)
+ input->ops->set_scroll_lock_status (input->handle, onoff);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Clear the existing screen
+ matrix and set the size of the screen matrix to the dimension COL x
+ ROW. This call will be immediately followed by a call to
+ cons_vcons_write that covers the whole new screen matrix. */
+error_t
+cons_vcons_set_dimension (vcons_t vcons, uint32_t col, uint32_t row)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->set_dimension)
+ display->ops->set_dimension (display->handle, col, row);
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+
+error_t
+cons_vcons_set_mousecursor_pos (vcons_t vcons, float x, float y)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->set_mousecursor_pos)
+ display->ops->set_mousecursor_pos (display->handle, x, y);
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+
+error_t
+cons_vcons_set_mousecursor_status (vcons_t vcons, int status)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->set_mousecursor_status)
+ display->ops->set_mousecursor_status (display->handle, status);
+ mutex_unlock (&global_lock);
+ return 0;
+
+}
+
+
+/* Console-specific options. */
+static const struct argp_option
+options[] =
+ {
+ {"driver-path", 'D', "PATH", 0, "Specify search path for driver modules" },
+ {"driver", 'd', "NAME", 0, "Add driver NAME to the console" },
+ {"console-node", 'c', "FILE", OPTION_ARG_OPTIONAL,
+ "Set a translator on the node FILE (default: " DEFAULT_CONSOLE_NODE ")" },
+ {0}
+ };
+
+/* Parse a command line option. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ static int devcount = 0;
+ error_t err;
+
+ switch (key)
+ {
+ case 'D':
+ {
+ char *s;
+ char *d;
+
+ if (driver_path)
+ free (driver_path);
+ driver_path = malloc (strlen (arg) + 2);
+ if (!driver_path)
+ {
+ argp_failure (state, 1, ENOMEM, "adding driver path failed");
+ return EINVAL;
+ }
+ s = arg;
+ d = driver_path;
+ while (*s)
+ {
+ *(d++) = (*s == ':') ? '\0' : *s;
+ s++;
+ }
+ *(d++) = '\0';
+ *d = '\0';
+ }
+ break;
+
+ case 'd':
+ err = driver_add (arg /* XXX */, arg,
+ state->argc, state->argv, &state->next, 0);
+ if (err)
+ {
+ argp_failure (state, 1, err, "loading driver `%s' failed", arg);
+ return EINVAL;
+ }
+ devcount++;
+ break;
+
+ case 'c':
+ console_node = arg ? arg : DEFAULT_CONSOLE_NODE;
+ if (!console_node)
+ return ENOMEM;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ if (!devcount)
+ {
+ argp_error (state, "at least one --driver argument required");
+ return EINVAL;
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Add our startup arguments to the standard cons set. */
+static const struct argp_child startup_children[] =
+ { { &cons_startup_argp }, { 0 } };
+static struct argp startup_argp = {options, parse_opt, 0,
+ 0, startup_children};
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ char *errname;
+
+ driver_init ();
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&startup_argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ err = driver_start (&errname);
+ if (err)
+ error (1, err, "Starting driver %s failed", errname);
+
+ mutex_init (&global_lock);
+
+ err = cons_init ();
+ if (err)
+ {
+ driver_fini ();
+ error (1, err, "Console library initialization failed");
+ }
+
+ err = timer_init ();
+ if (err)
+ {
+ driver_fini ();
+ error (1, err, "Timer thread initialization failed");
+ }
+
+ if (console_node)
+ console_setup_node (console_node);
+
+ cons_server_loop ();
+
+ /* Never reached. */
+ driver_fini ();
+ return 0;
+}
diff --git a/console-client/current-vcs.c b/console-client/current-vcs.c
new file mode 100644
index 00000000..1b63e0ba
--- /dev/null
+++ b/console-client/current-vcs.c
@@ -0,0 +1,223 @@
+/* current-vcs.c -- Add a "current vcs" symlink to the cons node.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Written by Samuel Thibault.
+
+ 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 */
+
+#include <argp.h>
+#include <driver.h>
+#include <input.h>
+#include <stdio.h>
+#include <error.h>
+#include <sys/mman.h>
+
+#include "trans.h"
+
+
+/* We use the same infrastructure as the kbd and mouse repeaters. */
+
+/* The default name of the node of the repeater. */
+#define DEFAULT_REPEATER_NODE "vcs"
+
+/* The name of the repeater node. */
+static char *repeater_node = DEFAULT_REPEATER_NODE;
+
+/* The repeater node. */
+static consnode_t vcs_node;
+
+
+/* Callbacks for vcs console node. */
+
+/* Reading the link to get current vcs, returns length of path (trailing \0
+ excluded). */
+static error_t
+vcs_readlink (struct iouser *user, struct node *np, char *buf)
+{
+ int cur;
+ error_t ret = 0;
+
+ ret = console_current_id (&cur);
+ if (!ret)
+ {
+ if (!buf)
+ ret = snprintf (NULL, 0, "%s/%d", cons_file, cur);
+ else
+ ret = sprintf (buf, "%s/%d", cons_file, cur);
+
+ if (ret < 0)
+ ret = errno;
+ }
+ return ret;
+}
+
+static error_t
+vcs_read (struct protid *user, char **data,
+ mach_msg_type_number_t * datalen, off_t offset,
+ mach_msg_type_number_t amount)
+{
+ int err;
+ int size;
+ char *buf;
+
+ if (amount > 0)
+ {
+ size = vcs_readlink (user->user, NULL, NULL);
+ if (size < 0)
+ return size;
+
+ buf = alloca (size);
+
+ err = vcs_readlink (user->user, NULL, buf);
+
+ if (err < 0)
+ return err;
+
+ if (offset + amount > size)
+ amount = size - offset;
+ if (amount < 0)
+ amount = 0;
+
+ if (*datalen < amount)
+ {
+ *data = mmap (0, amount, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ return ENOMEM;
+ }
+
+ memcpy (*data, buf + offset, amount);
+ *datalen = amount;
+ }
+ return 0;
+}
+
+/* Making a link to set current vcs.
+ Relative values perform relative switches. */
+static error_t
+vcs_mksymlink (struct iouser *user, struct node *np, char *name)
+{
+ char *c, *d;
+ int vt, delta = 0;
+
+ c = strrchr (name, '/');
+ if (!c)
+ c = name;
+ else
+ c++;
+ if (!*c)
+ return EINVAL;
+
+ if (*c == '-' || *c == '+')
+ delta = 1;
+
+ vt = strtol (c, &d, 10);
+ if (*d)
+ /* Bad number. */
+ return EINVAL;
+
+ if (!vt)
+ return 0;
+ return console_switch (delta ? 0 : vt, delta ? vt : 0);
+}
+
+
+static const char doc[] = "Current VCS Driver";
+
+static const struct argp_option options[] =
+ {
+ { "repeater", 'r', "NODE", OPTION_ARG_OPTIONAL,
+ "Set a current vcs translator on NODE (default: " DEFAULT_REPEATER_NODE ")"},
+ { 0 }
+ };
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ int *pos = (int *) state->input;
+
+ switch (key)
+ {
+ case 'r':
+ repeater_node = arg ? arg: DEFAULT_REPEATER_NODE;
+ break;
+
+ case ARGP_KEY_END:
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ *pos = state->next;
+ return 0;
+}
+
+static struct argp argp = {options, parse_opt, 0, doc};
+
+/* Initialize the current VCS driver. */
+static error_t
+current_vcs_init (void **handle, int no_exit, int argc, char *argv[], int *next)
+{
+ error_t err;
+ int pos = 1;
+
+ /* Parse the arguments. */
+ err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_EXIT
+ | ARGP_SILENT, 0, &pos);
+ *next += pos - 1;
+
+ if (err && err != EINVAL)
+ return err;
+
+ return 0;
+}
+
+static error_t
+current_vcs_start (void *handle)
+{
+ error_t err;
+
+ err = console_create_consnode (repeater_node, &vcs_node);
+ if (err)
+ return err;
+
+ vcs_node->read = vcs_read;
+ vcs_node->write = NULL;
+ vcs_node->select = NULL;
+ vcs_node->open = NULL;
+ vcs_node->close = NULL;
+ vcs_node->demuxer = NULL;
+ vcs_node->readlink = vcs_readlink;
+ vcs_node->mksymlink = vcs_mksymlink;
+ console_register_consnode (vcs_node);
+
+ return 0;
+}
+
+static error_t
+current_vcs_fini (void *handle, int force)
+{
+ console_unregister_consnode (vcs_node);
+ console_destroy_consnode (vcs_node);
+ return 0;
+}
+
+
+struct driver_ops driver_current_vcs_ops =
+ {
+ current_vcs_init,
+ current_vcs_start,
+ current_vcs_fini
+ };
+
diff --git a/console-client/display.h b/console-client/display.h
new file mode 100644
index 00000000..1e73bdee
--- /dev/null
+++ b/console-client/display.h
@@ -0,0 +1,154 @@
+/* display.h - The interface to and for a display driver.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_ 1
+
+#include <errno.h>
+#include <stdint.h>
+
+#include <hurd/console.h>
+
+
+/* The display drivers are set up by the driver's initialization
+ routine and added to the console client with driver_add_display.
+ All subsequent operations on the display are fully synchronized by
+ the caller. The driver deinitialization routine should call
+ driver_remove_display. */
+
+/* Forward declaration. */
+struct display_ops;
+typedef struct display_ops *display_ops_t;
+
+/* Add the display HANDLE with the operations OPS to the console
+ client. As soon as this is called, operations on this display may
+ be performed, even before the function returns. */
+error_t driver_add_display (display_ops_t ops, void *handle);
+
+/* Remove the display HANDLE with the operations OPS from the console
+ client. As soon as this function returns, no operations will be
+ performed on the display anymore. */
+error_t driver_remove_display (display_ops_t ops, void *handle);
+
+
+struct display_ops
+{
+ /* Set the cursor's position on display HANDLE to column COL and row
+ ROW. The home position (COL and ROW both being 0) is the upper
+ left corner of the screen matrix. COL will be smaller than the
+ width and ROW will be smaller than the height of the display.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*set_cursor_pos) (void *handle, uint32_t col, uint32_t row);
+
+
+ /* Set the cursor's state to STATE on display HANDLE. The possible
+ values for STATE are defined by the CONS_CURSOR_* symbols in
+ <hurd/console.h>.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*set_cursor_status) (void *handle, uint32_t state);
+
+
+ /* Scroll the display by DELTA lines up if DELTA is positive, and by
+ -DELTA lines down if DELTA is negative. DELTA will never be
+ zero, and the absolute value if DELTA will be smaller than or
+ equal to the height of the screen matrix.
+
+ The area that becomes free will be filled in a subsequent write
+ call. The purpose of the function is two-fold: It is called with
+ an absolute value of DELTA smaller than the screen height to
+ perform scrolling. It is called with an absolute value of DELTA
+ equal to the screen height to prepare a full refresh of the
+ screen. In the latter case the driver should not really perform
+ any scrolling. Instead it might deallocate limited resources
+ (like display glyph slots and palette colors) if that helps to
+ perform the subsequent write. It goes without saying that the
+ same deallocation, if any, should be performed on the area that
+ will be filled with the scrolled in content.
+
+ XXX Possibly need a function to invalidate scrollback buffer, or
+ in general to signal a switch of the console so state can be
+ reset. Only do this if we make guarantees about validity of
+ scrollback buffer, of course.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*scroll) (void *handle, int delta);
+
+ /* Deallocate the scarce resources (like font glyph slots, colors
+ etc) in the LENGTH entries of the screen matrix starting from
+ position COL and ROW. This call is immediately followed by calls
+ to write which cover the same area. If there are no scarce
+ resources, the caller might do nothing. */
+ error_t (*clear) (void *handle, size_t length, uint32_t col, uint32_t row);
+
+ /* Write the text STR with LENGTH characters to column COL and row
+ ROW on display HANDLE. LENGTH can be longer than the width of
+ the screen matrix minus COL. In this case the driver should
+ automatically wrap around the edge. However, LENGTH will never
+ be so huge that the whole text starting from COL and ROW will go
+ beyond the lower right corner of the screen matrix.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*write) (void *handle, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row);
+
+ /* Flush all the past changes on display HANDLE that have not been
+ flushed yet. This should make all past changes visible to the
+ user. The driver is free to make them visible earlier, but it
+ must happen before returning from this call.
+
+ The purpose of this function is to group several related change
+ operations together, but also several change operations which
+ occur in rapid succession. The first grouping is essential to
+ make it possible for a driver to implement double buffering. The
+ second grouping is important to keep up performance if there is a
+ lot of activity on the screen matrix. */
+ error_t (*update) (void *handle);
+
+ /* Flash the display HANDLE once. This should be done
+ immediately. */
+ error_t (*flash) (void *handle);
+
+ /* Do not use, do not remove. */
+ void (*deprecated) (void *handle, int key);
+
+ /* Change the dimension of the physical screen to one that can
+ display the vcons with the size of WIDTH * HEIGHT and clear the
+ old screen. If the physical screen already has the right
+ resolution do nothing. This function is always followed by a
+ write that covers the whole new screen. */
+ error_t (*set_dimension) (void *handle, unsigned int width,
+ unsigned int height);
+
+ /* Move the mouse cursor to the position X, Y. If the mouse cursor
+ is visible, update its position. */
+ error_t (*set_mousecursor_pos) (void *handle, float x, float y);
+
+ /* If STATUS is set to 0, hide the mouse cursor, otherwise show
+ it. */
+ error_t (*set_mousecursor_status) (void *handle, int status);
+};
+
+#endif /* _DISPLAY_H_ */
diff --git a/console-client/driver.c b/console-client/driver.c
new file mode 100644
index 00000000..7f799f0a
--- /dev/null
+++ b/console-client/driver.c
@@ -0,0 +1,361 @@
+/* driver.c - The console client driver code.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <dlfcn.h>
+
+#include <cthreads.h>
+
+#include "driver.h"
+
+
+/* The number of entries by which we grow a driver or component list
+ if we need more space. */
+#define LIST_GROW 4
+
+/* The path where we search for drivers, in addition to the default
+ path. The directories are separated by '\0' and terminated with an
+ empty string. XXX Should use argz or something. XXX Should get a
+ protective lock. */
+char *driver_path;
+
+/* The driver list lock, the list itself, its current length and the
+ total number of entries in the list. */
+struct mutex driver_list_lock;
+driver_t driver_list;
+size_t driver_list_len;
+size_t driver_list_alloc;
+
+
+/* Initialize the driver framework. */
+error_t
+driver_init (void)
+{
+ mutex_init (&driver_list_lock);
+ mutex_init (&display_list_lock);
+ mutex_init (&input_list_lock);
+ mutex_init (&bell_list_lock);
+ return 0;
+}
+
+
+/* Deinitialize and unload all loaded drivers and deinitialize the
+ driver framework. */
+error_t
+driver_fini (void)
+{
+ unsigned int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ {
+ driver_list[i].ops->fini (driver_list[i].handle, 1);
+ dlclose (driver_list[i].module);
+ free (driver_list[i].name);
+ free (driver_list[i].driver);
+ }
+ driver_list_len = 0;
+ mutex_unlock (&driver_list_lock);
+ return 0;
+}
+
+
+/* Load, intialize and (if START is non-zero) start the driver DRIVER
+ under the given NAME (which must be unique among all loaded
+ drivers) with arguments ARGZ with length ARGZ_LEN. This function
+ will grab the driver list lock. The driver itself might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_add (const char *const name, const char *const driver,
+ int argc, char *argv[], int *next, int start)
+{
+ error_t err;
+ static char cons_defpath[] = CONSOLE_DEFPATH;
+ driver_ops_t ops;
+ char *filename = NULL;
+ char *modname;
+ void *shobj = NULL;
+ driver_t drv;
+ unsigned int i;
+ char *dir = driver_path;
+ int defpath = 0;
+ char *opt_backup;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ if (driver_list[i].name && !strcmp (driver_list[i].name, name))
+ {
+ mutex_unlock (&driver_list_lock);
+ return EEXIST;
+ }
+
+ if (!dir || !*dir)
+ {
+ dir = cons_defpath;
+ defpath = 1;
+ }
+
+ while (dir)
+ {
+ if (filename)
+ free (filename);
+ if (asprintf (&filename,
+ "%s/%s%s", dir, driver, CONSOLE_SONAME_SUFFIX) < 0)
+ {
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ errno = 0;
+ shobj = dlopen (filename, RTLD_LAZY);
+ if (!shobj)
+ {
+ const char *errstring = dlerror (); /* Must always call or it leaks! */
+ if (errno != ENOENT)
+ {
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return errno ?: EGRATUITOUS;
+ }
+ }
+ else
+ break;
+
+ dir += strlen (dir) + 1;
+ if (!*dir)
+ {
+ if (defpath)
+ break;
+ else
+ {
+ dir = cons_defpath;
+ defpath = 1;
+ }
+ }
+ }
+
+ if (!shobj)
+ {
+ if (filename)
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOENT;
+ }
+
+ if (asprintf (&modname, "driver_%s_ops", driver) < 0)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ ops = dlsym (shobj, modname);
+ free (modname);
+ if (!ops || !ops->init)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return EGRATUITOUS;
+ }
+
+ if (driver_list_len == driver_list_alloc)
+ {
+ size_t new_alloc = driver_list_alloc + LIST_GROW;
+ driver_t new_list = realloc (driver_list,
+ new_alloc * sizeof (*driver_list));
+ if (!new_list)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return errno;
+ }
+ driver_list = new_list;
+ driver_list_alloc = new_alloc;
+ }
+ drv = &driver_list[driver_list_len];
+
+ drv->name = strdup (name);
+ drv->driver = strdup (driver);
+ drv->filename = filename;
+ drv->ops = ops;
+ drv->module = shobj;
+ if (!drv->name || !drv->driver)
+ {
+ if (drv->name)
+ free (drv->name);
+ if (drv->driver)
+ free (drv->driver);
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ opt_backup = argv[*next - 1];
+ argv[*next - 1] = (char *) name;
+ /* If we will start the driver, the init function must not exit. */
+ err = (*drv->ops->init) (&drv->handle, start, argc - (*next - 1),
+ argv + *next - 1, next);
+ argv[*next - 1] = opt_backup;
+
+ if (!err && start && drv->ops->start)
+ err = (*drv->ops->start) (drv->handle);
+ if (err)
+ {
+ free (drv->name);
+ free (drv->driver);
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return err;
+ }
+
+ driver_list_len++;
+ mutex_unlock (&driver_list_lock);
+ return 0;
+}
+
+
+/* Start all drivers. Only used once at start up, after all the
+ option parsing and driver initialization.
+
+ Returns 0 on success, and the name of a driver if it initializing
+ that driver fails. */
+error_t
+driver_start (char **name)
+{
+ error_t err = 0;
+ int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ {
+ if (driver_list[i].ops->start)
+ err = (*driver_list[i].ops->start) (driver_list[i].handle);
+ if (err)
+ {
+ *name = driver_list[i].name;
+ while (i > 0)
+ {
+ i--;
+ (*driver_list[i].ops->fini) (driver_list[i].handle, 1);
+ }
+ break;
+ }
+ }
+ mutex_unlock (&driver_list_lock);
+ return err;
+}
+
+
+/* Deinitialize and unload the driver with the name NAME. This
+ function will grab the driver list lock. The driver might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_remove (const char *const name)
+{
+ error_t err;
+ unsigned int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ if (driver_list[i].name && !strcmp (driver_list[i].name, name))
+ {
+ err = driver_list[i].ops->fini (driver_list[i].handle, 0);
+ if (!err)
+ {
+ dlclose (driver_list[i].module);
+ free (driver_list[i].name);
+ free (driver_list[i].driver);
+ free (driver_list[i].filename);
+ while (i + 1 < driver_list_len)
+ {
+ driver_list[i] = driver_list[i + 1];
+ i++;
+ }
+ driver_list_len--;
+ }
+ mutex_unlock (&driver_list_lock);
+ return err;
+ }
+ mutex_unlock (&driver_list_lock);
+ return ESRCH;
+}
+
+#define ADD_REMOVE_COMPONENT(component) \
+struct mutex component##_list_lock; \
+component##_t component##_list; \
+size_t component##_list_len; \
+size_t component##_list_alloc; \
+ \
+error_t \
+driver_add_##component (component##_ops_t ops, void *handle) \
+{ \
+ mutex_lock (&component##_list_lock); \
+ if (component##_list_len == component##_list_alloc) \
+ { \
+ size_t new_alloc = component##_list_alloc + LIST_GROW; \
+ component##_t new_list = realloc (component##_list, \
+ new_alloc \
+ * sizeof (*component##_list)); \
+ if (!new_list) \
+ { \
+ mutex_unlock (&component##_list_lock); \
+ return errno; \
+ } \
+ component##_list = new_list; \
+ component##_list_alloc = new_alloc; \
+ } \
+ component##_list[component##_list_len].ops = ops; \
+ component##_list[component##_list_len].handle = handle; \
+ component##_list_len++; \
+ mutex_unlock (&component##_list_lock); \
+ return 0; \
+} \
+ \
+error_t \
+driver_remove_##component (component##_ops_t ops, void *handle) \
+{ \
+ unsigned int i; \
+ \
+ mutex_lock (&component##_list_lock); \
+ for (i = 0; i < component##_list_len; i++) \
+ if (component##_list[i].ops == ops \
+ && component##_list[i].handle == handle) \
+ { \
+ while (i + 1 < component##_list_len) \
+ { \
+ component##_list[i] = component##_list[i + 1]; \
+ i++; \
+ } \
+ component##_list_len--; \
+ } \
+ mutex_unlock (&component##_list_lock); \
+ return 0; \
+}
+
+ADD_REMOVE_COMPONENT (display)
+ADD_REMOVE_COMPONENT (input)
+ADD_REMOVE_COMPONENT (bell)
diff --git a/console-client/driver.h b/console-client/driver.h
new file mode 100644
index 00000000..aacd5890
--- /dev/null
+++ b/console-client/driver.h
@@ -0,0 +1,289 @@
+/* driver.h - The interface to and for a console client driver.
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _CONSOLE_DRIVER_H_
+#define _CONSOLE_DRIVER_H_ 1
+
+#include <errno.h>
+#include <stddef.h>
+
+#include "display.h"
+#include "input.h"
+#include "bell.h"
+
+
+/* The path where we search for drivers, in addition to the default
+ path. The directories are separated by '\0' and terminated with an
+ empty string. XXX Should use argz or something. XXX Should get a
+ protective lock. */
+extern char *driver_path;
+
+
+/* The driver framework allows loading and unloading of new drivers.
+ It also provides some operations on the loaded drivers. The device
+ framework module does its own locking, so all operations can be run
+ at any time by any thread. */
+
+/* Initialize the driver framework. */
+error_t driver_init (void);
+
+/* Deinitialize and unload all loaded drivers and deinitialize the
+ driver framework. */
+error_t driver_fini (void);
+
+/* Forward declaration. */
+struct driver_ops;
+typedef struct driver_ops *driver_ops_t;
+
+/* Load, initialize and (if START is non-zero) start the driver DRIVER
+ under the given NAME (which must be unique among all loaded
+ drivers) with arguments ARGC, ARGV and NEXT (see
+ parse_startup_args). This function will grab the driver list lock.
+ The driver itself might try to grab the display, input source and
+ bell list locks as well. */
+error_t driver_add (const char *const name, const char *const driver,
+ int argc, char *argv[], int *next, int start);
+
+/* Start all drivers. Only used once at start up, after all the
+ option parsing and driver initialization.
+
+ Returns 0 on success, and the error if it initializing that driver
+ fails (NAME points to the driver name then). */
+error_t driver_start (char **name);
+
+/* Deinitialize and unload the driver with the name NAME. This
+ function will grab the driver list lock. The driver might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_remove (const char *const name);
+
+/* Iterate over all loaded drivers. This macro will grab the driver
+ list lock. You use it with a block:
+
+ driver_iterate
+ {
+ printf ("%s\n", driver->ops->name);
+ }
+
+ Or even just:
+
+ driver_iterate printf ("%s\n", driver->ops->name);
+
+ The variable DRIVER is provided by the macro. */
+#define driver_iterate \
+ for (driver_t driver = (mutex_lock (&driver_list_lock), \
+ &driver_list[0]); \
+ driver < &driver_list[driver_list_len] \
+ || (mutex_unlock (&driver_list_lock), 0); \
+ driver++)
+
+
+struct driver_ops
+{
+ /* Initialize an instance of the driver and return a handle for it
+ in HANDLE. The options in ARGC, ARGV and NEXT should be
+ processed and validated.
+
+ If NO_EXIT is zero, the function might exit on fatal errors or
+ invalid arguments. The drawback is that it must NOT allocate any
+ resources that need to be freed or deallocated explicitely before
+ exiting the program either, because other driver instances are
+ also allowed to exit without prior notice at some later time.
+ Allocation and initialization of such resources (like the video
+ card) must be delayed until the start() function is called (see
+ below).
+
+ If NO_EXIT is non-zero, the function must not exit, but report
+ all errors back to the caller. In this case, it is guaranteed
+ that the START function is called immediately after this function
+ returns, and that the driver is properly unloaded with fini() at
+ some later time.
+
+ The above behaviour, and the split into an init() and a start()
+ function, was carefully designed to allow the init() function the
+ optimal use of argp at startup and at run time to parse options.
+
+ ARGV[*NEXT] is the next argument to be parsed. ARGC is the
+ number of total arguments in ARGV. The function should increment
+ *NEXT for each argument parsed. The function should not reorder
+ arguments, nor should it parse non-option arguments. It should
+ also not parse over any single "--" argument.
+
+ Every driver must implement this function.
+
+ If NO_EXIT is zero, the function should return zero on success
+ and otherwise either terminate or return an appropriate error
+ value. If it returns, either the program terminates because of
+ other errors, or the function start() is called.
+
+ If NO_EXIT is non-zero, the function should return zero on
+ success and an appropriate error value otherwise. If it returns
+ success, the function start() will be called next, otherwise
+ nothing happens. */
+ error_t (*init) (void **handle, int no_exit,
+ int argc, char *argv[], int *next);
+
+ /* Activate the driver instance. This function should load all the
+ display, input and bell river components for this driver
+ instance.
+
+ If successful, the function should return zero. In this case it
+ is guaranteed that fini() will be called before the program
+ terminates. If not successful, the function should free all
+ resources associated with HANDLE and return non-zero. */
+ error_t (*start) (void *handle);
+
+ /* Deinitialize the driver. This should remove all the individual
+ drivers installed by init() and release all resources. It should
+ also reset all hardware devices into the state they had before
+ calling init(), as far as applicable. HANDLE is provided as
+ returned by init().
+
+ The function is allowed to fail if FORCE is 0. If FORCE is not
+ 0, the driver should remove itself no matter what. */
+ error_t (*fini) (void *handle, int force);
+
+
+ /* Save the status of the hardware. */
+ void (*save_status) (void *handle);
+
+ /* Restore the status of the hardware. */
+ void (*restore_status) (void *handle);
+};
+
+
+/* The driver structure. */
+struct driver
+{
+ /* The unique name of the driver. */
+ char *name;
+
+ /* The plugin name. */
+ char *driver;
+
+ /* The filename that was identified as providing the plugin. */
+ char *filename;
+
+ driver_ops_t ops;
+ void *handle;
+
+ /* The following members are private to the driver support code. Do
+ not use. */
+
+ /* The shared object handle as returned by dlopen(). */
+ void *module;
+};
+typedef struct driver *driver_t;
+
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex driver_list_lock;
+extern driver_t driver_list;
+extern size_t driver_list_len;
+
+
+/* Iterate over all loaded displays. This macro will grab the display
+ list lock. You use it with a block, just like driver_iterate.
+
+ display_iterate display->ops->flash (display->handle);
+
+ The variable DISPLAY is provided by the macro. */
+#define display_iterate \
+ for (display_t display = (mutex_lock (&display_list_lock), \
+ &display_list[0]); \
+ display < &display_list[display_list_len] \
+ || (mutex_unlock (&display_list_lock), 0); \
+ display++)
+
+
+/* The display structure. */
+struct display
+{
+ display_ops_t ops;
+ void *handle;
+};
+typedef struct display *display_t;
+
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex display_list_lock;
+extern display_t display_list;
+extern size_t display_list_len;
+
+
+/* Iterate over all loaded inputs. This macro will grab the input
+ list lock. You use it with a block, just like driver_iterate.
+
+ input_iterate input->ops->set_scroll_lock_status (input->handle, 0);
+
+ The variable INPUT is provided by the macro. */
+#define input_iterate \
+ for (input_t input = (mutex_lock (&input_list_lock), &input_list[0]); \
+ input < &input_list[input_list_len] \
+ || (mutex_unlock (&input_list_lock), 0); \
+ input++)
+
+
+/* The input structure. */
+struct input
+{
+ input_ops_t ops;
+ void *handle;
+};
+typedef struct input *input_t;
+
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex input_list_lock;
+extern input_t input_list;
+extern size_t input_list_len;
+
+
+/* Iterate over all loaded bells. This macro will grab the bell list
+ lock. You use it with a block, just like driver_iterate.
+
+ bell_iterate bell->ops->beep (bell->handle);
+
+ The variable BELL is provided by the macro. */
+#define bell_iterate \
+ for (bell_t bell = (mutex_lock (&bell_list_lock), &bell_list[0]); \
+ bell < &bell_list[bell_list_len] \
+ || (mutex_unlock (&bell_list_lock), 0); \
+ bell++)
+
+
+/* The bell structure, needed by the macro above. Don't use it
+ directly. */
+struct bell
+{
+ bell_ops_t ops;
+ void *handle;
+};
+typedef struct bell *bell_t;
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex bell_list_lock;
+extern bell_t bell_list;
+extern size_t bell_list_len;
+
+#endif /* _CONSOLE_DRIVER_H_ */
diff --git a/console-client/generic-speaker.c b/console-client/generic-speaker.c
new file mode 100644
index 00000000..5d8f509c
--- /dev/null
+++ b/console-client/generic-speaker.c
@@ -0,0 +1,554 @@
+/* generic-speaker.c - The simple speaker bell driver.
+ Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <sys/io.h>
+#include <string.h>
+#include <argp.h>
+
+#include <cthreads.h>
+
+#include "driver.h"
+#include "timer.h"
+
+/* This driver should work on IA32, IA64, Alpha, PowerPC, MIPS and ARM
+ architectures. It requires a Programmable Interrupt Timer (PIT) at
+ I/O ports 0x40 - 0x43 and a speaker that can be connected to timer
+ 2 at I/O port 0x61. */
+
+/* The beep timer. */
+static struct timer_list generic_speaker_timer;
+
+/* Forward declaration. */
+static struct bell_ops generic_speaker_ops;
+
+
+/* The speaker port. */
+#define SPEAKER 0x61
+
+/* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
+ from timer 2. */
+#define SPEAKER_TMR2 0x01
+
+/* If SPEAKER_TMR2 is not set, this provides direct input into the
+ speaker. Otherwise, this enables or disables the output from the
+ timer. */
+#define SPEAKER_DATA 0x02
+
+
+/* The PIT channel value ports. You can write to and read from them.
+ Do not mess with timer 0 or 1. */
+#define PIT_COUNTER_0 0x40
+#define PIT_COUNTER_1 0x41
+#define PIT_COUNTER_2 0x42
+
+/* The frequency of the PIT clock. */
+#define PIT_FREQUENCY 0x1234dd
+
+/* The PIT control port. You can only write to it. Do not mess with
+ timer 0 or 1. */
+#define PIT_CTRL 0x43
+#define PIT_CTRL_SELECT_MASK 0xc0
+#define PIT_CTRL_SELECT_0 0x00
+#define PIT_CTRL_SELECT_1 0x40
+#define PIT_CTRL_SELECT_2 0x80
+
+/* Read and load control. */
+#define PIT_CTRL_READLOAD_MASK 0x30
+#define PIT_CTRL_COUNTER_LATCH 0x00 /* Hold timer value until read. */
+#define PIT_CTRL_READLOAD_LSB 0x10 /* Read/load the LSB. */
+#define PIT_CTRL_READLOAD_MSB 0x20 /* Read/load the MSB. */
+#define PIT_CTRL_READLOAD_WORD 0x30 /* Read/load the LSB then the MSB. */
+
+/* Mode control. */
+#define PIT_CTRL_MODE_MASK 0x0e
+
+/* Interrupt on terminal count. Setting the mode sets output to low.
+ When counter is set and terminated, output is set to high. */
+#define PIT_CTRL_INTR_ON_TERM 0x00
+
+/* Programmable one-shot. When loading counter, output is set to
+ high. When counter terminated, output is set to low. Can be
+ triggered again from that point on by setting the gate pin to
+ high. */
+#define PIT_CTRL_PROGR_ONE_SHOT 0x02
+
+/* Rate generator. Output is low for one period of the counter, and
+ high for the other. */
+#define PIT_CTRL_RATE_GEN 0x04
+
+/* Square wave generator. Output is low for one half of the period,
+ and high for the other half. */
+#define PIT_CTRL_SQUAREWAVE_GEN 0x06
+
+/* Software triggered strobe. Setting the mode sets output to high.
+ When counter is set and terminated, output is set to low. */
+#define PIT_CTRL_SOFTSTROBE 0x08
+
+/* Hardware triggered strobe. Like software triggered strobe, but
+ only starts the counter when the gate pin is set to high. */
+#define PIT_CTRL_HARDSTROBE 0x0a
+
+
+/* Count mode. */
+#define PIT_CTRL_COUNT_MASK 0x01
+#define PIT_CTRL_COUNT_BINARY 0x00 /* 16-bit binary counter. */
+#define PIT_CTRL_COUNT_BCD 0x01 /* 4-decade BCD counter. */
+
+
+/* Let's be loud! */
+
+/* The 12th root of 2. Sort of. */
+#define T_TEMP_SCALE 1.0594630943592952645
+#define T_DOWN_ONE_HALF(x) ((short) (x / T_TEMP_SCALE))
+#define T_UP_ONE_HALF(x) ((short) (x * T_TEMP_SCALE))
+#define T_DOWN_ONE_OCTAVE(x) ((short) (x / 2))
+#define T_UP_ONE_OCTAVE(x) ((short) (x * 2))
+#define T_REST ((short) 0)
+#define T_FINE ((short) (-1))
+
+#define T_b_3 T_UP_ONE_OCTAVE (T_b_2)
+#define T_b_F_3 T_UP_ONE_OCTAVE (T_b_F_2)
+#define T_a_S_3 T_b_F_3
+#define T_a_3 T_UP_ONE_OCTAVE (T_a_2)
+#define T_a_F_3 T_UP_ONE_OCTAVE (T_a_F_2)
+#define T_g_S_3 T_a_F_3
+#define T_g_3 T_UP_ONE_OCTAVE (T_g_2)
+#define T_g_F_3 T_f_S_3
+#define T_f_S_3 T_UP_ONE_OCTAVE (T_f_S_2)
+#define T_f_3 T_UP_ONE_OCTAVE (T_f_2)
+#define T_e_3 T_UP_ONE_OCTAVE (T_e_2)
+#define T_e_F_3 T_UP_ONE_OCTAVE (T_e_F_2)
+#define T_d_S_3 T_e_F_3
+#define T_d_3 T_UP_ONE_OCTAVE (T_d_2)
+#define T_d_F_3 T_c_S_3
+#define T_c_S_3 T_UP_ONE_OCTAVE (T_c_S_2)
+#define T_c_3 T_UP_ONE_OCTAVE (T_c_2)
+
+#define T_b_2 T_UP_ONE_OCTAVE (T_b_1)
+#define T_b_F_2 T_UP_ONE_OCTAVE (T_b_F_1)
+#define T_a_S_2 T_b_F_2
+#define T_a_2 T_UP_ONE_OCTAVE (T_a_1)
+#define T_a_F_2 T_UP_ONE_OCTAVE (T_a_F_1)
+#define T_g_S_2 T_a_F_2
+#define T_g_2 T_UP_ONE_OCTAVE (T_g_1)
+#define T_g_F_2 T_f_S_2
+#define T_f_S_2 T_UP_ONE_OCTAVE (T_f_S_1)
+#define T_f_2 T_UP_ONE_OCTAVE (T_f_1)
+#define T_e_2 T_UP_ONE_OCTAVE (T_e_1)
+#define T_e_F_2 T_UP_ONE_OCTAVE (T_e_F_1)
+#define T_d_S_2 T_e_F_2
+#define T_d_2 T_UP_ONE_OCTAVE (T_d_1)
+#define T_d_F_2 T_c_S_2
+#define T_c_S_2 T_UP_ONE_OCTAVE (T_c_S_1)
+#define T_c_2 T_UP_ONE_OCTAVE (T_c_1)
+
+#define T_b_1 T_UP_ONE_HALF (T_b_F_1)
+#define T_b_F_1 T_UP_ONE_HALF (T_a_1)
+#define T_a_S_1 T_b_F_1
+#define T_a_1 ((short) (440))
+#define T_a_F_1 T_DOWN_ONE_HALF (T_a_1)
+#define T_g_S_1 T_a_F_1
+#define T_g_1 T_DOWN_ONE_HALF (T_a_F_1)
+#define T_g_F_1 T_f_S_1
+#define T_f_S_1 T_DOWN_ONE_HALF (T_g_1)
+#define T_f_1 T_DOWN_ONE_HALF (T_f_S_1)
+#define T_e_1 T_DOWN_ONE_HALF (T_f_1)
+#define T_e_F_1 T_DOWN_ONE_HALF (T_e_1)
+#define T_d_S_1 T_e_F_1
+#define T_d_1 T_DOWN_ONE_HALF (T_e_F_1)
+#define T_d_F_1 T_c_S_1
+#define T_c_S_1 T_DOWN_ONE_HALF (T_d_1)
+#define T_c_1 T_DOWN_ONE_HALF (T_c_S_1)
+
+#define T_b T_DOWN_ONE_OCTAVE (T_b_1)
+#define T_b_F T_DOWN_ONE_OCTAVE (T_b_F_1)
+#define T_a_S T_b_F
+#define T_a T_DOWN_ONE_OCTAVE (T_a_1)
+#define T_a_F T_DOWN_ONE_OCTAVE (T_a_F_1)
+#define T_g_S T_a_F
+#define T_g T_DOWN_ONE_OCTAVE (T_g_1)
+#define T_g_F T_f_S
+#define T_f_S T_DOWN_ONE_OCTAVE (T_f_S_1)
+#define T_f T_DOWN_ONE_OCTAVE (T_f_1)
+#define T_e T_DOWN_ONE_OCTAVE (T_e_1)
+#define T_e_F T_DOWN_ONE_OCTAVE (T_e_F_1)
+#define T_d_S T_e_F
+#define T_d T_DOWN_ONE_OCTAVE (T_d_1)
+#define T_d_F T_c_S
+#define T_c_S T_DOWN_ONE_OCTAVE (T_c_S_1)
+#define T_c T_DOWN_ONE_OCTAVE (T_c_1)
+
+struct note
+{
+ short pitch;
+ short duration;
+};
+
+struct melody
+{
+ char *name;
+ int measure;
+ struct note *next;
+ struct note note[];
+};
+
+#define BELL_CLASSIC "classic"
+#define BELL_LINUX "linux"
+#define BELL_ALARM "alarm"
+#define BELL_CMAJOR "cmajor"
+
+static struct melody beep1 =
+ { BELL_CLASSIC, 160, NULL, {
+ /* The classical bell. */
+ { T_a_1, 4 }, { T_FINE, 0 }
+ } };
+
+static struct melody beep2 =
+ { BELL_LINUX, 60, NULL, {
+ /* The Linux bell. */
+ { 750, 1 }, { T_FINE, 0 }
+ } };
+
+static struct melody beep3 =
+ { BELL_ALARM, 160, NULL, {
+ /* The tritonus. Quite alarming. */
+ { T_f_2, 2 }, { T_b_1, 4 }, { T_FINE, 0 }
+ } };
+
+static struct melody beep4 =
+ { BELL_CMAJOR, 160, NULL, {
+ /* C-Major chord. A bit playful. */
+ { T_c_2, 2 }, { T_e_2, 2 }, { T_g_2, 2 },
+ { T_FINE, 0 }
+ } };
+
+static struct melody *beep[] = { &beep1, &beep2, &beep3, &beep4 };
+static int active_beep;
+
+#if QUAERENDO_INVENIETIS
+struct melody tune1 =
+ { "FSF Song", 160, NULL, {
+ /* The Free Software Song. Measure: 7/4. */
+ { T_d_2, 16 }, { T_c_2, 8 }, { T_b_1, 16 }, { T_a_1, 16 },
+ { T_b_1, 16 }, { T_c_2, 8 }, { T_b_1, 8 }, { T_a_1, 8 }, { T_g_1, 16 },
+ { T_g_1, 24 }, { T_a_1, 24 }, { T_b_1, 8 },
+ { T_c_2, 24 }, { T_b_1, 14 }, { T_REST, 2 }, { T_b_1, 8 }, { T_d_2, 8 },
+ { T_a_1, 22 }, { T_REST, 2 }, { T_a_1, 32 },
+ { T_c_2, 16 }, { T_d_2, 8 }, { T_c_2, 16 }, { T_b_1, 24 },
+ { T_d_2, 16 }, { T_c_2, 8 }, { T_b_1, 16 }, { T_a_1, 16 },
+ { T_b_1, 16 }, { T_c_2, 8 }, { T_b_1, 8 }, { T_a_1, 8 }, { T_g_1, 16 },
+ { T_g_1, 24 }, { T_a_1, 24 }, { T_b_1, 8 },
+ { T_c_2, 24 }, { T_b_1, 14 }, { T_REST, 2 }, { T_b_1, 8 }, { T_d_2, 8 },
+ { T_a_1, 22 }, { T_REST, 2 }, { T_a_1, 30 }, { T_REST, 2 },
+ { T_a_1, 56 }, { T_FINE, 0 }
+ } };
+
+struct melody tune2 =
+ { "I Feel Pretty", 160, NULL, {
+ /* I feel pretty. Measure: 3/4. By Leonard Bernstein. */
+ { T_c_1, 8 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 20 },
+ { T_REST, 8 }, { T_c_1, 8 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 20 },
+ { T_REST, 8 }, { T_c_1, 8 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 12 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 12 }, { T_f_1, 8 },
+ { T_c_2, 32 },
+ { T_b_F_1,8 }, { T_a_1, 8 },
+ { T_g_1, 4 }, { T_f_1, 20 },
+ { T_REST, 8 }, { T_g_1, 8 }, { T_a_1, 8 },
+ { T_b_F_1,12}, { T_a_1, 4 }, { T_g_1, 4 }, { T_f_1, 4 },
+ { T_e_1, 16 }, { T_d_1, 3 }, { T_e_1, 2 }, { T_d_1, 3 },
+ { T_c_1, 56 }, { T_FINE, 0 }
+ } };
+
+struct melody tune3 =
+ { "Summertime", 120, NULL, {
+ /* Summertime. Measure: 4/4. By George & Ira Gershwin. */
+ { T_b_1, 8 }, { T_g_1, 8 },
+ { T_b_1, 36 }, { T_REST, 4 }, { T_a_1, 6 }, { T_g_1, 2 },
+ { T_a_1, 6 }, { T_b_1, 2 }, { T_g_1, 8 },
+ { T_e_1, 16 }, { T_b, 24 }, { T_REST, 8 },
+ { T_b_1, 8 }, { T_g_1, 8 },
+ { T_a_1, 3 }, { T_REST, 1 }, { T_a_1, 28 },
+ { T_REST, 8 }, { T_g_1, 6 }, { T_e_1, 2 },
+ { T_g_1, 6 }, { T_e_1, 2 }, { T_g_1, 8 },
+ { T_f_S_1,48}, { T_REST, 4 }, { T_b_1, 8 }, { T_g_1, 4 },
+ { T_b_1, 3 }, { T_REST, 1 }, { T_b_1, 7 }, { T_REST, 1 }, { T_b_1, 20 },
+ { T_REST, 8 }, { T_a_1, 6 }, { T_g_1, 2 },
+ { T_a_1, 6 }, { T_b_1, 2 }, { T_g_1, 8 },
+ { T_e_1, 16 }, { T_b, 32 }, { T_REST, 8 },
+ { T_b, 8 }, { T_d_1, 8 }, { T_b, 4 },
+ { T_d_1, 4 }, { T_e_1, 8 }, { T_g_1, 8 },
+ /* Keen attempt at a glissando. */
+ { T_b_1, 2 }, { T_b_1 + (T_b_1 - T_a_1) / 3, 1 },
+ { T_b_1 + 2 * (T_b_1 - T_a_1) / 3, 1 },
+ { T_a_1, 12 }, { T_g_1, 15 }, { T_REST, 1 },
+ { T_g_1, 4 }, { T_e_1, 68 },
+ { T_FINE, 0 }
+ } };
+
+struct melody tune4 =
+ { "Indiana Jones Theme", 250, NULL, {
+ /* Indiana Jones Theme. Measure: 4/4. By John Williams. */
+ { T_e_1, 4 }, { T_REST, 8 }, { T_f_1, 4 },
+ { T_g_1, 4 }, { T_REST, 4 }, { T_c_2, 24 },
+ { T_REST, 16 }, { T_d_1, 4 }, { T_REST, 8 }, { T_e_1, 4 },
+ { T_f_1, 32 },
+ { T_REST, 16 }, { T_g_1, 4 }, { T_REST, 8 }, { T_a_1, 4 },
+ { T_b_1, 4 }, { T_REST, 4 }, { T_f_2, 24 },
+ { T_REST, 16 }, { T_a_1, 4 }, { T_REST, 8 }, { T_b_1, 4 },
+ { T_c_2, 8 }, { T_REST, 8 }, { T_d_2, 12 }, { T_REST, 4 },
+ { T_e_2, 8 }, { T_REST, 8 },
+ { T_e_1, 4 }, { T_REST, 8 }, { T_f_1, 4 },
+ { T_g_1, 4 }, { T_REST, 4 }, { T_c_2, 24 },
+ { T_REST, 16 }, { T_d_2, 4 }, { T_REST, 8 }, { T_e_2, 4 },
+ { T_f_2, 32 },
+ { T_REST, 16 }, { T_g_1, 4 }, { T_REST, 8 }, { T_g_1, 4 },
+ { T_e_2, 16 }, { T_d_2, 4 }, { T_REST, 8 }, { T_g_1, 4 },
+ { T_e_2, 16 }, { T_d_2, 4 }, { T_REST, 8 }, { T_g_1, 4 },
+ { T_f_2, 16 }, { T_e_2, 4 }, { T_REST, 8 }, { T_d_2, 4 },
+ { T_c_2, 32 }, { T_FINE, 0 }
+ } };
+
+struct melody *tune[] = { &tune1, &tune2, &tune3, &tune4 };
+#endif /* QUAERENDO_INVENIETIS */
+
+
+static void
+beep_off (void)
+{
+ unsigned char status;
+
+ status = inb (SPEAKER) & ~(SPEAKER_TMR2 | SPEAKER_DATA);
+ outb (status, SPEAKER);
+}
+
+static void
+beep_on (short pitch)
+{
+ unsigned char status;
+ unsigned int counter;
+
+ if (pitch < 20)
+ pitch = 20;
+ else if (pitch > 20000)
+ pitch = 20000;
+
+ counter = PIT_FREQUENCY / pitch;
+
+ /* Program timer 2. */
+ outb (PIT_CTRL_SELECT_2 | PIT_CTRL_READLOAD_WORD
+ | PIT_CTRL_SQUAREWAVE_GEN | PIT_CTRL_COUNT_BINARY, PIT_CTRL);
+ outb (counter & 0xff, PIT_COUNTER_2); /* LSB */
+ outb ((counter >> 8) & 0xff, PIT_COUNTER_2); /* MSB */
+
+ /* Start speaker. */
+ status = inb (SPEAKER) | SPEAKER_TMR2 | SPEAKER_DATA;
+ outb (status, SPEAKER);
+}
+
+
+static int
+next_note (void *handle)
+{
+ struct melody *melody = handle;
+
+ switch (melody->next->pitch)
+ {
+ case T_FINE:
+ beep_off ();
+ return 0;
+
+ case T_REST:
+ beep_off ();
+ break;
+
+ default:
+ beep_on (melody->next->pitch);
+ break;
+ }
+
+ generic_speaker_timer.expires
+ += (60 * HZ * melody->next->duration / (8 * melody->measure));
+ melody->next++;
+ return 1;
+}
+
+
+static const char doc[] = "Generic speaker driver";
+
+static const struct argp_option options[] =
+ {
+ {"bell-style", 'b', "BELL", 0, "Use one of the bells: "
+ BELL_CLASSIC ", " BELL_LINUX ", " BELL_ALARM
+ " or " BELL_CMAJOR},
+ { 0 }
+ };
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ int *pos = (int *) state->input;
+
+ switch (key)
+ {
+ case 'b':
+ {
+ unsigned int i;
+ int found = 0;
+
+ for (i = 0; i < sizeof (*beep); i++)
+ {
+ if (! strcasecmp (beep[i]->name, arg))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (! found)
+ argp_usage (state);
+
+ active_beep = i;
+ break;
+ }
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ /* Save which option comes after the last accepted option. */
+ *pos = state->next;
+ return 0;
+}
+
+static struct argp argp = {options, parse_opt, 0, doc};
+
+/* Initialization of the generic speaker driver. */
+static error_t
+generic_speaker_init (void **handle, int no_exit,
+ int argc, char *argv[], int *next)
+{
+ error_t err;
+ int pos = 1;
+
+ /* Parse the arguments. */
+ err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_EXIT
+ | ARGP_SILENT, 0 , &pos);
+ *next += pos - 1;
+
+ if (err && err != EINVAL)
+ return err;
+
+ timer_clear (&generic_speaker_timer);
+ generic_speaker_timer.fnc = &next_note;
+
+ return 0;
+}
+
+
+/* Start the driver. */
+static error_t
+generic_speaker_start (void *handle)
+{
+ error_t err;
+
+ if (ioperm (SPEAKER, 1, 1) < 0)
+ return errno;
+ if (ioperm (PIT_COUNTER_2, PIT_CTRL - PIT_COUNTER_2 + 1, 1) < 0)
+ return errno;
+
+ beep_off ();
+
+ err = driver_add_bell (&generic_speaker_ops, NULL);
+ /* XXX We can not disable the I/O ports on error as there might be
+ concurrent users of it. */
+ return err;
+}
+
+
+/* Deinitialization of the generic speaker driver. */
+static error_t
+generic_speaker_fini (void *handle, int force)
+{
+ driver_remove_bell (&generic_speaker_ops, NULL);
+
+ /* XXX We can not disable the I/O ports as there might be concurrent
+ users of it. */
+ if (timer_remove (&generic_speaker_timer))
+ beep_off ();
+ return 0;
+}
+
+
+/* Beep! */
+static error_t
+generic_speaker_beep (void *handle)
+{
+ if (timer_remove (&generic_speaker_timer))
+ beep_off ();
+ generic_speaker_timer.fnc_data = beep[active_beep];
+ beep[active_beep]->next = &beep[active_beep]->note[1];
+ beep_on (beep[active_beep]->note[0].pitch);
+ generic_speaker_timer.expires = fetch_jiffies ()
+ + (60 * HZ * beep[active_beep]->note[0].duration
+ / (8 * beep[active_beep]->measure));
+ timer_add (&generic_speaker_timer);
+ return 0;
+}
+
+#if QUAERENDO_INVENIETIS
+static void
+generic_speaker_play_melody (void *handle, unsigned int key)
+{
+ if (key < 0 || key >= sizeof (tune) / sizeof (tune[0]))
+ return;
+
+ if (timer_remove (&generic_speaker_timer))
+ beep_off ();
+ generic_speaker_timer.fnc_data = tune[key];
+ tune[key]->next = &tune[key]->note[1];
+ beep_on (tune[key]->note[0].pitch);
+ generic_speaker_timer.expires = fetch_jiffies ()
+ + (60 * HZ * tune[key]->note[0].duration / (8 * tune[key]->measure));
+ timer_add (&generic_speaker_timer);
+ return;
+}
+#endif /* QUAERENDO_INVENIETIS */
+
+
+struct driver_ops driver_generic_speaker_ops =
+ {
+ generic_speaker_init,
+ generic_speaker_start,
+ generic_speaker_fini
+ };
+
+static struct bell_ops generic_speaker_ops =
+ {
+ generic_speaker_beep,
+#if QUAERENDO_INVENIETIS
+ generic_speaker_play_melody
+#else
+ NULL
+#endif
+ };
diff --git a/console-client/input.h b/console-client/input.h
new file mode 100644
index 00000000..351fa34a
--- /dev/null
+++ b/console-client/input.h
@@ -0,0 +1,99 @@
+/* input.h - The interface to and for an input driver.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _INPUT_H_
+#define _INPUT_H_ 1
+
+#include <errno.h>
+#include <stddef.h>
+
+#include <hurd/cons.h>
+
+
+/* The input drivers are set up by the driver's initialization routine
+ and added to the console client with driver_add_input. All
+ subsequent operations on the display are fully synchronized by the
+ caller. The driver deinitialization routine should call
+ driver_remove_input. */
+
+/* Forward declaration. */
+struct input_ops;
+typedef struct input_ops *input_ops_t;
+
+/* Add the input source HANDLE with the operations OPS to the console
+ client. As soon as this is called, operations on this input source
+ may be performed, even before the function returns. */
+error_t driver_add_input (input_ops_t ops, void *handle);
+
+/* Remove the input HANDLE with the operations OPS from the console
+ client. As soon as this function returns, no operations will be
+ performed on the input source anymore. */
+error_t driver_remove_input (input_ops_t ops, void *handle);
+
+/* Enter SIZE bytes from the buffer BUF into the currently active
+ console. This can be called by the input driver at any time. */
+error_t console_input (char *buf, size_t size);
+
+/* Scroll the active console by TYPE and VALUE as specified by
+ cons_vcons_scrollback. */
+int console_scrollback (cons_scroll_t type, float value);
+
+/* Returns current console ID. */
+error_t console_current_id (int *cur);
+
+/* Switch the active console to console ID or DELTA (relative to the
+ active console). */
+error_t console_switch (int id, int delta);
+
+/* Signal an error to the user. */
+void console_error (const wchar_t *const err_msg);
+
+/* Exit the console client. Does not return. */
+void console_exit (void);
+
+/* Switch away from the console an external use of the console like
+ XFree. */
+void console_switch_away (void);
+
+/* Switch back to the console client from an external user of the
+ console like XFree. */
+void console_switch_back (void);
+
+/* Report the mouse event EV to the currently active console. This
+ can be called by the input driver at any time. */
+error_t console_move_mouse (mouse_event_t ev);
+
+
+#if QUAERENDO_INVENIETIS
+/* Do not use, do not remove. */
+void console_deprecated (int key);
+#endif
+
+
+struct input_ops
+{
+ /* Set the status of the scroll lock indication. */
+ error_t (*set_scroll_lock_status) (void *handle, int onoff);
+
+ /* Do not use, do not remove. */
+ void (*deprecated) (void *handle, int key);
+};
+
+#endif /* _INPUT_H_ */
diff --git a/console-client/kbd-repeat.c b/console-client/kbd-repeat.c
new file mode 100644
index 00000000..4bf9268e
--- /dev/null
+++ b/console-client/kbd-repeat.c
@@ -0,0 +1,258 @@
+/* kbd-repeat.c - Keyboard repeater.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Written by Marco Gerards.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd/netfs.h>
+#include <stdlib.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "kdioctl_S.h"
+#include "mach-inputdev.h"
+#include "input.h"
+
+/* The amount of keyboard events that can be stored in the keyboard buffer. */
+#define KBDEVTBUFSZ 20
+
+/* The size of the keyboard buffer in bytes. */
+#define KBDBUFSZ (KBDEVTBUFSZ * sizeof (kd_event))
+
+/* Return the position of X in the buffer. */
+#define KBDBUF_POS(x) ((x) % KBDBUFSZ)
+
+/* The keyboard buffer. */
+static struct kbdbuf
+{
+ char keybuffer[KBDBUFSZ];
+ int pos;
+ size_t size;
+ struct condition readcond;
+ struct condition writecond;
+} kbdbuf;
+
+/* Wakeup for select */
+static struct condition select_alert;
+
+/* The global lock */
+static struct mutex global_lock;
+
+/* Amount of times the device was opened. Normally this translator
+ should be only opened once. */
+int kbd_repeater_opened;
+
+
+/* Place the keyboard event KEY in the keyboard buffer. */
+void
+kbd_repeat_key (kd_event *key)
+{
+ kd_event *ev;
+
+ mutex_lock (&global_lock);
+ while (kbdbuf.size + sizeof (kd_event) > KBDBUFSZ)
+ {
+ /* The input buffer is full, wait until there is some space. */
+ if (hurd_condition_wait (&kbdbuf.writecond, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ /* Interrupt, silently continue. */
+ }
+ }
+ ev = (kd_event *) &kbdbuf.keybuffer[KBDBUF_POS (kbdbuf.pos
+ + kbdbuf.size)];
+ kbdbuf.size += sizeof (kd_event);
+ memcpy (ev, key, sizeof (kd_event));
+
+ condition_broadcast (&kbdbuf.readcond);
+ mutex_unlock (&global_lock);
+}
+
+
+static error_t
+repeater_select (struct protid *cred, mach_port_t reply,
+ mach_msg_type_name_t replytype, int *type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (*type & ~SELECT_READ)
+ return EINVAL;
+
+ if (*type == 0)
+ return 0;
+
+ mutex_lock (&global_lock);
+ while (1)
+ {
+ if (kbdbuf.size > 0)
+ {
+ *type = SELECT_READ;
+ mutex_unlock (&global_lock);
+
+ return 0;
+ }
+
+ ports_interrupt_self_on_port_death (cred, reply);
+ if (hurd_condition_wait (&select_alert, &global_lock))
+ {
+ *type = 0;
+ mutex_unlock (&global_lock);
+
+ return EINTR;
+ }
+ }
+}
+
+
+static error_t
+repeater_read (struct protid *cred, char **data,
+ mach_msg_type_number_t *datalen, off_t offset,
+ mach_msg_type_number_t amount)
+{
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openstat & O_READ))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+ while (amount > kbdbuf.size)
+ {
+ if (cred->po->openstat & O_NONBLOCK && amount > kbdbuf.size)
+ {
+ mutex_unlock (&global_lock);
+ return EWOULDBLOCK;
+ }
+
+ if (hurd_condition_wait (&kbdbuf.readcond, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ }
+
+ if (amount > 0)
+ {
+ char *keydata;
+ unsigned int i = 0;
+
+ /* Allocate a buffer when this is required. */
+ if (*datalen < amount)
+ {
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ {
+ mutex_unlock (&global_lock);
+ return ENOMEM;
+ }
+ }
+
+ /* Copy the bytes to the user's buffer and remove them from the
+ keyboard buffer. */
+ keydata = *data;
+ while (i != amount)
+ {
+ keydata[i++] = kbdbuf.keybuffer[kbdbuf.pos++];
+ kbdbuf.pos = KBDBUF_POS (kbdbuf.pos);
+ }
+ kbdbuf.size -= amount;
+ condition_broadcast (&kbdbuf.writecond);
+ }
+
+ *datalen = amount;
+ mutex_unlock (&global_lock);
+
+ return 0;
+}
+
+
+static void
+repeater_open (void)
+{
+ /* Make sure the console does not access the hardware anymore. */
+ if (! kbd_repeater_opened)
+ console_switch_away ();
+ kbd_repeater_opened++;
+}
+
+
+static void
+repeater_close (void)
+{
+ kbd_repeater_opened--;
+
+ /* Allow the console to access the hardware again. */
+ if (! kbd_repeater_opened)
+ {
+ console_switch_back ();
+ kbdbuf.pos = 0;
+ kbdbuf.size = 0;
+ }
+}
+
+
+/* Set the repeater translator. The node will be named NODENAME and
+ NODE will be filled with information about this node. */
+error_t
+kbd_setrepeater (const char *nodename, consnode_t *cn)
+{
+ extern int kdioctl_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ error_t err;
+
+ err = console_create_consnode (nodename, cn);
+ if (err)
+ return err;
+
+ (*cn)->read = repeater_read;
+ (*cn)->write = 0;
+ (*cn)->select = repeater_select;
+ (*cn)->open = repeater_open;
+ (*cn)->close = repeater_close;
+ (*cn)->demuxer = kdioctl_server;
+
+ mutex_init (&global_lock);
+
+ condition_init (&kbdbuf.readcond);
+ condition_init (&kbdbuf.writecond);
+
+ condition_init (&select_alert);
+ condition_implies (&kbdbuf.readcond, &select_alert);
+
+ console_register_consnode (*cn);
+
+ return 0;
+}
+
+
+/* Some RPC calls for controlling the keyboard. These calls are just
+ ignored and just exist to make XFree happy. */
+
+kern_return_t
+S_kdioctl_kdskbdmode (io_t port, int mode)
+{
+ return 0;
+}
+
+
+kern_return_t
+S_kdioctl_kdgkbdmode (io_t port, int *mode)
+{
+ return 0;
+}
diff --git a/console-client/mach-inputdev.h b/console-client/mach-inputdev.h
new file mode 100644
index 00000000..985e1e1d
--- /dev/null
+++ b/console-client/mach-inputdev.h
@@ -0,0 +1,138 @@
+/* mach-inputdev.h - Interfaces for the PC pc-kbd and mouse input drivers.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marco Gerards.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* This gross stuff is cut & pasted from Mach sources, as Mach doesn't
+ export the interface we are using here. */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _INPUTDEV_H_
+#define _INPUTDEV_H_ 1
+
+#include <trans.h>
+
+typedef u_short kev_type; /* kd event type */
+
+/* (used for event records) */
+struct mouse_motion {
+ short mm_deltaX; /* units? */
+ short mm_deltaY;
+};
+typedef u_char Scancode;
+
+typedef struct {
+ kev_type type; /* see below */
+ struct timeval time; /* timestamp */
+ union { /* value associated with event */
+ boolean_t up; /* MOUSE_LEFT .. MOUSE_RIGHT */
+ Scancode sc; /* KEYBD_EVENT */
+ struct mouse_motion mmotion; /* MOUSE_MOTION */
+ } value;
+} kd_event;
+#define m_deltaX mmotion.mm_deltaX
+#define m_deltaY mmotion.mm_deltaY
+
+/*
+ * kd_event ID's.
+ */
+#define MOUSE_LEFT 1 /* mouse left button up/down */
+#define MOUSE_MIDDLE 2
+#define MOUSE_RIGHT 3
+#define MOUSE_MOTION 4 /* mouse motion */
+#define KEYBD_EVENT 5 /* key up/down */
+
+
+#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */
+#define IOC_OUT 0x40000000 /* copy out parameters */
+#define IOC_IN 0x80000000U /* copy in parameters */
+
+#ifndef _IOC
+#define _IOC(inout,group,num,len) \
+ (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
+#endif
+#ifndef _IOR
+#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
+#endif
+#ifndef _IOW
+#define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t))
+#endif
+
+#define KDSKBDMODE _IOW('K', 1, int) /* set keyboard mode */
+#define KB_EVENT 1
+#define KB_ASCII 2
+
+#define KDGKBDTYPE _IOR('K', 2, int) /* get keyboard type */
+#define KB_VANILLAKB 0
+
+#define KDSETLEDS _IOW('K', 5, int) /* set keyboard leds */
+
+/*
+ * Low 3 bits of minor are the com port #.
+ * The high 5 bits of minor are the mouse type
+ */
+#define MOUSE_SYSTEM_MOUSE 0
+#define MICROSOFT_MOUSE 1
+#define IBM_MOUSE 2
+#define NO_MOUSE 3
+#define LOGITECH_TRACKMAN 4
+#define MICROSOFT_MOUSE7 5
+
+#define DEV_COM0 "com0"
+#define DEV_COM1 "com1"
+
+/* End of Mach code. */
+
+
+/* Amount of times the device was opened. Normally this translator
+ should be only opened once. */
+extern int kbd_repeater_opened;
+
+/* Place the keyboard event KEY in the keyboard buffer. */
+void kbd_repeat_key (kd_event *key);
+
+/* Set the repeater translator. The node will be named NODENAME and
+ NODE will be filled with information about this node. */
+error_t kbd_setrepeater (const char *nodename, consnode_t *node);
+
+#endif /* _INPUTDEV_H_ */
diff --git a/console-client/ncursesw.c b/console-client/ncursesw.c
new file mode 100644
index 00000000..a34026a2
--- /dev/null
+++ b/console-client/ncursesw.c
@@ -0,0 +1,745 @@
+/* ncursesw.c - The ncursesw console driver.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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 */
+
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <wchar.h>
+
+/* The makefiles make sure that this program is compiled with
+ -I${prefix}/ncursesw. */
+#include <curses.h>
+
+#include <cthreads.h>
+#include <hurd/console.h>
+
+#include "driver.h"
+
+
+/* ncurses is not thread-safe. This lock protects all calls into the
+ ncurses library. */
+static struct mutex ncurses_lock;
+
+/* The current width and height the ncursesw driver is using. */
+static unsigned int current_width;
+static unsigned int current_height;
+
+/* The window on which the console is shown. */
+static WINDOW *conspad;
+
+/* The upper left corner shown in the pad. */
+static unsigned int padx;
+static unsigned int pady;
+
+/* Autoscroll is on or off. Autoscroll makes scrolling dependent on
+ the cursor position. */
+static int autoscroll;
+
+/* Forward declaration. */
+static struct display_ops ncursesw_display_ops;
+static struct input_ops ncursesw_input_ops;
+static struct bell_ops ncursesw_bell_ops;
+
+struct curses_kc_to_cons_kc
+{
+ int curses;
+ char *cons;
+};
+
+static struct curses_kc_to_cons_kc keycodes[] =
+ {
+ { KEY_BREAK, NULL }, /* XXX */
+ { KEY_DOWN, CONS_KEY_DOWN },
+ { KEY_UP, CONS_KEY_UP },
+ { KEY_RIGHT, CONS_KEY_RIGHT },
+ { KEY_LEFT, CONS_KEY_LEFT },
+ { KEY_HOME, CONS_KEY_HOME },
+ { KEY_BACKSPACE, CONS_KEY_BACKSPACE },
+ { KEY_F(1), CONS_KEY_F1 },
+ { KEY_F(2), CONS_KEY_F2 },
+ { KEY_F(3), CONS_KEY_F3 },
+ { KEY_F(4), CONS_KEY_F4 },
+ { KEY_F(5), CONS_KEY_F5 },
+ { KEY_F(6), CONS_KEY_F6 },
+ { KEY_F(7), CONS_KEY_F7 },
+ { KEY_F(8), CONS_KEY_F8 },
+ { KEY_F(9), CONS_KEY_F9 },
+ { KEY_F(10), CONS_KEY_F10 },
+ { KEY_DL, NULL }, /* XXX Delete line. */
+ { KEY_IL, NULL }, /* XXX Insert line. */
+ { KEY_DC, CONS_KEY_DC },
+ { KEY_IC, CONS_KEY_IC },
+ { KEY_EIC, NULL }, /* XXX Exit insert mode. */
+ { KEY_CLEAR, NULL }, /* XXX Clear screen. */
+ { KEY_EOS, NULL }, /* XXX Clear to end of screen. */
+ { KEY_EOL, NULL }, /* XXX Clear to end of line. */
+ { KEY_SF, NULL }, /* XXX Scroll one line forward. */
+ { KEY_SR, NULL }, /* XXX Scroll one line backward. */
+ { KEY_NPAGE, CONS_KEY_NPAGE },
+ { KEY_PPAGE, CONS_KEY_PPAGE },
+ { KEY_STAB, NULL }, /* XXX Set tab. */
+ { KEY_CTAB, NULL }, /* XXX Clear tab. */
+ { KEY_CATAB, NULL }, /* XXX Clear all tabs. */
+ { KEY_ENTER, NULL }, /* XXX Enter or send. */
+ { KEY_SRESET, NULL }, /* XXX Soft (partial) reset. */
+ { KEY_RESET, NULL }, /* XXX Reset or hard reset. */
+ { KEY_PRINT, NULL }, /* XXX Print or copy. */
+ { KEY_LL, NULL }, /* XXX Home down or bottom (lower left). */
+ { KEY_A1, NULL }, /* XXX Upper left of keypad. */
+ { KEY_A3, NULL }, /* XXX Upper right of keypad. */
+ { KEY_B2, NULL }, /* XXX Center of keypad. */
+ { KEY_C1, NULL }, /* XXX Lower left of keypad. */
+ { KEY_C3, NULL }, /* XXX Lower right of keypad. */
+ { KEY_BTAB, CONS_KEY_BTAB },
+ { KEY_BEG, NULL }, /* XXX Beg(inning) key. */
+ { KEY_CANCEL, NULL }, /* XXX Cancel key. */
+ { KEY_CLOSE, NULL }, /* XXX Close key. */
+ { KEY_COMMAND, NULL }, /* XXX Cmd (command) key. */
+ { KEY_COPY, NULL }, /* XXX Copy key. */
+ { KEY_CREATE, NULL }, /* XXX Create key. */
+ { KEY_END, CONS_KEY_END },
+ { KEY_EXIT, NULL }, /* XXX Exit key. */
+ { KEY_FIND, NULL }, /* XXX Find key. */
+ { KEY_HELP, NULL }, /* XXX Help key. */
+ { KEY_MARK, NULL }, /* XXX Mark key. */
+ { KEY_MESSAGE, NULL }, /* XXX Message key. */
+ { KEY_MOUSE, NULL }, /* XXX Mouse event read. */
+ { KEY_MOVE, NULL }, /* XXX Move key. */
+ { KEY_NEXT, NULL }, /* XXX Next object key. */
+ { KEY_OPEN, NULL }, /* XXX Open key. */
+ { KEY_OPTIONS, NULL }, /* XXX Options key. */
+ { KEY_PREVIOUS, NULL }, /* XXX Previous object key. */
+ { KEY_REDO, NULL }, /* XXX Redo key. */
+ { KEY_REFERENCE, NULL }, /* XXX Ref(erence) key. */
+ { KEY_REFRESH, NULL }, /* XXX Refresh key. */
+ { KEY_REPLACE, NULL }, /* XXX Replace key. */
+ { KEY_RESIZE, NULL }, /* XXX Screen resized. */
+ { KEY_RESTART, NULL }, /* XXX Restart key. */
+ { KEY_RESUME, NULL }, /* XXX Resume key. */
+ { KEY_SAVE, NULL }, /* XXX Save key. */
+ { KEY_SBEG, NULL }, /* XXX Shifted beginning key. */
+ { KEY_SCANCEL, NULL }, /* XXX Shifted cancel key. */
+ { KEY_SCOMMAND, NULL }, /* XXX Shifted command key. */
+ { KEY_SCOPY, NULL }, /* XXX Shifted copy key. */
+ { KEY_SCREATE, NULL }, /* XXX Shifted create key. */
+ { KEY_SDC, NULL }, /* XXX Shifted delete char key. */
+ { KEY_SDL, NULL }, /* XXX Shifted delete line key. */
+ { KEY_SELECT, NULL }, /* XXX Select key. */
+ { KEY_SEND, NULL }, /* XXX Shifted end key. */
+ { KEY_SEOL, NULL }, /* XXX Shifted clear line key. */
+ { KEY_SEXIT, NULL }, /* XXX Shifted exit key. */
+ { KEY_SFIND, NULL }, /* XXX Shifted find key. */
+ { KEY_SHELP, NULL }, /* XXX Shifted help key. */
+ { KEY_SHOME, NULL }, /* XXX Shifted home key. */
+ { KEY_SIC, NULL }, /* XXX Shifted input key. */
+ { KEY_SLEFT, NULL }, /* XXX Shifted left arrow key. */
+ { KEY_SMESSAGE, NULL }, /* XXX Shifted message key. */
+ { KEY_SMOVE, NULL }, /* XXX Shifted move key. */
+ { KEY_SNEXT, NULL }, /* XXX Shifted next key. */
+ { KEY_SOPTIONS, NULL }, /* XXX Shifted options key. */
+ { KEY_SPREVIOUS, NULL }, /* XXX Shifted prev key. */
+ { KEY_SPRINT, NULL }, /* XXX Shifted print key. */
+ { KEY_SREDO, NULL }, /* XXX Shifted redo key. */
+ { KEY_SREPLACE, NULL }, /* XXX Shifted replace key. */
+ { KEY_SRIGHT, NULL }, /* XXX Shifted right arrow. */
+ { KEY_SRSUME, NULL }, /* XXX Shifted resume key. */
+ { KEY_SSAVE, NULL }, /* XXX Shifted save key. */
+ { KEY_SSUSPEND, NULL }, /* XXX Shifted suspend key. */
+ { KEY_SUNDO, NULL }, /* XXX Shifted undo key. */
+ { KEY_SUSPEND, NULL }, /* XXX Suspend key. */
+ { KEY_UNDO, NULL } /* XXX Undo key. */
+ };
+
+static int
+ucs4_to_altchar (wchar_t chr, chtype *achr)
+{
+ switch (chr)
+ {
+ case CONS_CHAR_RARROW:
+ *achr = ACS_RARROW;
+ break;
+ case CONS_CHAR_LARROW:
+ *achr = ACS_LARROW;
+ break;
+ case CONS_CHAR_UARROW:
+ *achr = ACS_UARROW;
+ break;
+ case CONS_CHAR_DARROW:
+ *achr = ACS_DARROW;
+ break;
+ case CONS_CHAR_BLOCK:
+ *achr = ACS_BLOCK;
+ break;
+ case CONS_CHAR_LANTERN:
+ *achr = ACS_LANTERN;
+ break;
+ case CONS_CHAR_DIAMOND:
+ *achr = ACS_DIAMOND;
+ break;
+ case CONS_CHAR_CKBOARD:
+ *achr = ACS_CKBOARD;
+ break;
+ case CONS_CHAR_DEGREE:
+ *achr = ACS_DEGREE;
+ break;
+ case CONS_CHAR_PLMINUS:
+ *achr = ACS_PLMINUS;
+ break;
+ case CONS_CHAR_BOARD:
+ *achr = ACS_BOARD;
+ break;
+ case CONS_CHAR_LRCORNER:
+ *achr = ACS_LRCORNER;
+ break;
+ case CONS_CHAR_URCORNER:
+ *achr = ACS_URCORNER;
+ break;
+ case CONS_CHAR_ULCORNER:
+ *achr = ACS_ULCORNER;
+ break;
+ case CONS_CHAR_LLCORNER:
+ *achr = ACS_LLCORNER;
+ break;
+ case CONS_CHAR_PLUS:
+ *achr = ACS_PLUS;
+ break;
+ case CONS_CHAR_S1:
+ *achr = ACS_S1;
+ break;
+ case CONS_CHAR_S3:
+ *achr = ACS_S3;
+ break;
+ case CONS_CHAR_HLINE:
+ *achr = ACS_HLINE;
+ break;
+ case CONS_CHAR_S7:
+ *achr = ACS_S7;
+ break;
+ case CONS_CHAR_S9:
+ *achr = ACS_S9;
+ break;
+ case CONS_CHAR_LTEE:
+ *achr = ACS_LTEE;
+ break;
+ case CONS_CHAR_RTEE:
+ *achr = ACS_RTEE;
+ break;
+ case CONS_CHAR_BTEE:
+ *achr = ACS_BTEE;
+ break;
+ case CONS_CHAR_TTEE:
+ *achr = ACS_TTEE;
+ break;
+ case CONS_CHAR_VLINE:
+ *achr = ACS_VLINE;
+ break;
+ case CONS_CHAR_LEQUAL:
+ *achr = ACS_LEQUAL;
+ break;
+ case CONS_CHAR_GEQUAL:
+ *achr = ACS_GEQUAL;
+ break;
+ case CONS_CHAR_PI:
+ *achr = ACS_PI;
+ break;
+ case CONS_CHAR_NEQUAL:
+ *achr = ACS_NEQUAL;
+ break;
+ case CONS_CHAR_STERLING:
+ *achr = ACS_STERLING;
+ break;
+ case CONS_CHAR_BULLET:
+ *achr = ACS_BULLET;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static error_t
+refresh_screen (void)
+{
+ /* It is possible */
+ if (!current_width && !current_height)
+ return 0;
+ return prefresh (conspad, pady, padx, 0, 0,
+ (current_height <= (unsigned int) LINES
+ ? current_height : (unsigned int) LINES) - 1,
+ (current_width <= (unsigned int) COLS
+ ? current_width : (unsigned int) COLS) - 1);
+}
+
+static any_t
+input_loop (any_t unused)
+{
+ int fd = 0;
+ fd_set rfds;
+ int w_escaped = 0;
+
+ FD_ZERO (&rfds);
+ FD_SET (fd, &rfds);
+
+ while (1)
+ {
+ int ret;
+
+ FD_SET (fd, &rfds);
+
+ ret = select (fd + 1, &rfds, 0, 0, 0);
+ if (ret == 1)
+ {
+ char buffer[100];
+ char *buf = buffer;
+ size_t size = 0;
+
+ mutex_lock (&ncurses_lock);
+ while ((ret = wgetch (conspad)) != ERR)
+ {
+ unsigned int i;
+ int found;
+
+ if (w_escaped)
+ {
+ switch (ret)
+ {
+ case 'x':
+ mutex_unlock (&ncurses_lock);
+ console_exit ();
+ break;
+ case 23: /* ^W */
+ assert (size < 100);
+ buf[size++] = ret;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* Avoid a dead lock. */
+ mutex_unlock (&ncurses_lock);
+ console_switch (1 + (ret - '1'), 0);
+ mutex_lock (&ncurses_lock);
+ break;
+ case 'j':
+ /* Scroll pad to left. */
+ if (padx > 0)
+ {
+ padx--;
+ refresh_screen ();
+ }
+ break;
+ case 'k':
+ /* Scroll pad down. */
+ if (pady < current_height - LINES)
+ {
+ pady++;
+ refresh_screen ();
+ }
+ break;
+ case 'l':
+ /* Scroll pad to right. */
+ if (padx < current_width - COLS)
+ {
+ padx++;
+ refresh_screen ();
+ }
+ break;
+ case 'i':
+ /* Scroll pad up. */
+ if (pady > 0)
+ {
+ pady--;
+ refresh_screen ();
+ }
+ break;
+ case 'a':
+ /* Switch autoscroll on/off. */
+ autoscroll = !autoscroll;
+ break;
+ default:
+ break;
+ }
+ w_escaped = 0;
+ }
+ else
+ switch (ret)
+ {
+ case 23: /* ^W */
+ w_escaped = 1;
+ break;
+ default:
+ found = 0;
+ for (i = 0; i < sizeof (keycodes) / sizeof (keycodes[0]);
+ i++)
+ {
+ if (keycodes[i].curses == ret)
+ {
+ if (keycodes[i].cons)
+ {
+ assert (size
+ < 101 - strlen (keycodes[i].cons));
+ strcpy (&buf[size], keycodes[i].cons);
+ size += strlen (keycodes[i].cons);
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ {
+ assert (size < 100);
+ buf[size++] = ret;
+ }
+ break;
+ }
+ }
+ mutex_unlock (&ncurses_lock);
+ if (size)
+ console_input (buf, size);
+ }
+ }
+}
+
+static inline attr_t
+conchar_attr_to_attr (conchar_attr_t attr)
+{
+ return ((attr.intensity == CONS_ATTR_INTENSITY_BOLD
+ ? A_BOLD : (attr.intensity == CONS_ATTR_INTENSITY_DIM
+ ? A_DIM : A_NORMAL))
+ | (attr.underlined ? A_UNDERLINE : 0)
+ | (attr.reversed ? A_REVERSE : 0)
+ | (attr.blinking ? A_BLINK: 0)
+ | (attr.concealed ? A_INVIS : 0));
+}
+
+static inline short
+conchar_attr_to_color_pair (conchar_attr_t attr)
+{
+ return COLOR_PAIR (attr.bgcol << 3 | attr.fgcol);
+}
+
+static void
+mvwputsn (conchar_t *str, size_t len, off_t x, off_t y)
+{
+ cchar_t chr;
+ wchar_t wch[2] = { L'\0', L'\0' };
+ uint32_t last_attr = * (uint32_t *) &str->attr;
+ attr_t attr = conchar_attr_to_attr (str->attr);
+ short color_pair = conchar_attr_to_color_pair (str->attr);
+
+ wmove (conspad, y, x);
+ while (len)
+ {
+ int ret;
+ chtype ac;
+
+ if (last_attr != *(uint32_t *) &str->attr)
+ {
+ last_attr = * (uint32_t *) &str->attr;
+ attr = conchar_attr_to_attr (str->attr);
+ color_pair = conchar_attr_to_color_pair (str->attr);
+ }
+
+ if (ucs4_to_altchar (str->chr, &ac))
+ waddch (conspad, ac | attr | color_pair);
+ else
+ {
+ wch[0] = str->chr;
+ ret = setcchar (&chr, wch, attr, color_pair, NULL);
+#if 0
+ if (ret == ERR)
+ {
+ printf ("setcchar failed: %s\n", strerror (errno));
+ printf ("[%lc]\n", wch[0]);
+ assert (!"Do something if setcchar fails.");
+ }
+#endif
+ ret = wadd_wch (conspad, &chr);
+#if 0
+ if (ret == ERR)
+ {
+ printf ("add_wch failed: %i, %s\n", ret, strerror (errno));
+ printf ("[%lc]\n", wch[0]);
+ assert (!"Do something if add_wchr fails.");
+ }
+#endif
+ }
+ len--;
+ str++;
+ }
+}
+
+
+static error_t
+ncursesw_update (void *handle)
+{
+ mutex_lock (&ncurses_lock);
+ refresh_screen ();
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_set_cursor_pos (void *handle, uint32_t col, uint32_t row)
+{
+ mutex_lock (&ncurses_lock);
+ assert (current_width && current_height);
+ if (autoscroll)
+ {
+ /* Autoscroll to the right. */
+ if (col > COLS + padx)
+ {
+ padx += COLS / 2;
+ if (padx > COLS + current_width)
+ padx = current_width - COLS;
+ refresh_screen ();
+ }
+ /* Autoscroll to the left. */
+ else if (col < padx)
+ {
+ padx -= COLS / 2;
+ if (padx < 0)
+ padx = 0;
+ refresh_screen ();
+ }
+ /* Autoscroll down. */
+ if (row > LINES + pady)
+ {
+ pady += LINES / 2;
+ if (pady > LINES + current_height)
+ pady = current_height - LINES;
+ refresh_screen ();
+ }
+ /* Autoscroll up. */
+ else if (row < pady)
+ {
+ pady -= LINES / 2;
+ if (pady < 0)
+ pady = 0;
+ refresh_screen ();
+ }
+ }
+
+ wmove (conspad, row, col);
+
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_set_cursor_status (void *handle, uint32_t status)
+{
+ mutex_lock (&ncurses_lock);
+
+ /* If the cursor is invisible and switching to one visible state is
+ impossible, switch to the other visible state or else the cursor
+ will not be shown at all. */
+ if (curs_set (status) == -1 && status)
+ curs_set (status == 1 ? 2 : 1);
+
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_scroll (void *handle, int delta)
+{
+ /* XXX We don't support scrollback for now. */
+ assert (delta >= 0);
+
+ mutex_lock (&ncurses_lock);
+ idlok (conspad, TRUE);
+ scrollok (conspad, TRUE);
+ wscrl (conspad, delta);
+ idlok (conspad, FALSE);
+ scrollok (conspad, FALSE);
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_write (void *handle, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row)
+{
+ int x;
+ int y;
+
+ mutex_lock (&ncurses_lock);
+ getyx (conspad, y, x);
+ mvwputsn (str, length, col, row);
+ wmove (conspad, y, x);
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_flash (void *handle)
+{
+ mutex_lock (&ncurses_lock);
+ flash ();
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+/* Bell driver operations. */
+error_t
+ncursesw_beep (void *handle)
+{
+ mutex_lock (&ncurses_lock);
+ beep ();
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+
+static error_t
+ncursesw_driver_init (void **handle, int no_exit,
+ int argc, char *argv[], int *next)
+{
+ mutex_init (&ncurses_lock);
+ return 0;
+}
+
+static error_t
+ncursesw_driver_start (void *handle)
+{
+ error_t err;
+ int i;
+
+ initscr ();
+ start_color ();
+ for (i = 0; i < 64; i++)
+ init_pair (i, i & 7, i >> 3);
+ raw ();
+ noecho ();
+ nonl ();
+
+ /* Create a new pad with the size minimal size. This pad will be
+ resized by ncursesw_set_dimension. */
+ conspad = newpad (1, 1);
+ if (!conspad)
+ return errno;
+
+ intrflush (conspad, FALSE);
+ nodelay (conspad, TRUE);
+ wtimeout (conspad, 1);
+ keypad (conspad, TRUE);
+
+ err = driver_add_display (&ncursesw_display_ops, NULL);
+ if (err)
+ {
+ endwin ();
+ return err;
+ }
+ err = driver_add_input (&ncursesw_input_ops, NULL);
+ if (err)
+ {
+ err = driver_remove_display (&ncursesw_display_ops, NULL);
+ endwin ();
+ return err;
+ }
+ err = driver_add_bell (&ncursesw_bell_ops, NULL);
+ if (err)
+ {
+ err = driver_remove_input (&ncursesw_input_ops, NULL);
+ err = driver_remove_display (&ncursesw_display_ops, NULL);
+ endwin ();
+ return err;
+ }
+
+ cthread_detach (cthread_fork (input_loop, NULL));
+
+ return 0;
+}
+
+/* Destroy the display HANDLE. */
+static error_t
+ncursesw_driver_fini (void *handle, int force)
+{
+ /* XXX Cancel the input thread. */
+ mutex_lock (&ncurses_lock);
+ driver_remove_display (&ncursesw_display_ops, NULL);
+ driver_remove_input (&ncursesw_input_ops, NULL);
+ driver_remove_bell (&ncursesw_bell_ops, NULL);
+ mutex_unlock (&ncurses_lock);
+
+ endwin ();
+ return 0;
+}
+
+static error_t
+ncursesw_set_dimension (void *handle, unsigned int width, unsigned int height)
+{
+ mutex_lock (&ncurses_lock);
+ if (width != current_width || height != current_height)
+ {
+ wresize (conspad, height, width);
+ padx = 0;
+ pady = 0;
+ }
+ current_width = width;
+ current_height = height;
+ mutex_unlock(&ncurses_lock);
+ return 0;
+}
+
+
+struct driver_ops driver_ncursesw_ops =
+ {
+ ncursesw_driver_init,
+ ncursesw_driver_start,
+ ncursesw_driver_fini,
+ };
+
+static struct display_ops ncursesw_display_ops =
+ {
+ ncursesw_set_cursor_pos,
+ ncursesw_set_cursor_status,
+ ncursesw_scroll,
+ NULL,
+ ncursesw_write,
+ ncursesw_update,
+ ncursesw_flash,
+ NULL,
+ ncursesw_set_dimension
+ };
+
+static struct input_ops ncursesw_input_ops =
+ {
+ NULL,
+ NULL
+ };
+
+static struct bell_ops ncursesw_bell_ops =
+ {
+ ncursesw_beep,
+ NULL
+ };
diff --git a/console-client/pc-kbd.c b/console-client/pc-kbd.c
new file mode 100644
index 00000000..d66e94b3
--- /dev/null
+++ b/console-client/pc-kbd.c
@@ -0,0 +1,1194 @@
+/* pc-kbd.c - The PC Keyboard input driver.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <iconv.h>
+#include <sys/mman.h>
+#include <argp.h>
+
+#include <device/device.h>
+#include <cthreads.h>
+
+#include <hurd/console.h>
+#include <hurd/cons.h>
+
+#include "driver.h"
+#include "mach-inputdev.h"
+
+
+/* The default name of the node of the repeater. */
+#define DEFAULT_REPEATER_NODE "kbd"
+
+/* The keyboard device in the kernel. */
+static device_t kbd_dev;
+
+/* The converter. */
+static iconv_t cd;
+
+/* The status of various LEDs. */
+struct {
+ int scroll_lock : 1;
+ int num_lock : 1;
+ int caps_lock : 1;
+} led_state;
+
+/* True if we are in the GNU Mach v1 compatibility mode. */
+int gnumach_v1_compat;
+
+/* Forward declaration. */
+static struct input_ops pc_kbd_ops;
+
+/* The name of the repeater node. */
+static char *repeater_node;
+
+/* The repeater node. */
+static consnode_t cnode;
+
+/* A list of scan codes generated by the keyboard, in the set 2 encoding. */
+enum scancode
+ {
+ SC_F9 = 0x01,
+ SC_F5 = 0x03,
+ SC_F3 = 0x04,
+ SC_F1 = 0x05,
+ SC_F2 = 0x06,
+ SC_F12 = 0x07,
+ SC_F10 = 0x09,
+ SC_F8 = 0x0A,
+ SC_F6 = 0x0B,
+ SC_F4 = 0x0C,
+ SC_TAB = 0x0D,
+ SC_BACKQUOTE = 0x0E, /* ` */
+ SC_LEFT_ALT = 0x11,
+ SC_LEFT_SHIFT = 0x12,
+ SC_LEFT_CTRL = 0x14,
+ SC_Q = 0x15,
+ SC_1 = 0x16,
+ SC_Z = 0x1A,
+ SC_S = 0x1B,
+ SC_A = 0x1C,
+ SC_W = 0x1D,
+ SC_2 = 0x1E,
+ SC_C = 0x21,
+ SC_X = 0x22,
+ SC_D = 0x23,
+ SC_E = 0x24,
+ SC_4 = 0x25,
+ SC_3 = 0x26,
+ SC_SPACE = 0x29,
+ SC_V = 0x2A,
+ SC_F = 0x2B,
+ SC_T = 0x2C,
+ SC_R = 0x2D,
+ SC_5 = 0x2E,
+ SC_N = 0x31,
+ SC_B = 0x32,
+ SC_H = 0x33,
+ SC_G = 0x34,
+ SC_Y = 0x35,
+ SC_6 = 0x36,
+ SC_M = 0x3A,
+ SC_J = 0x3B,
+ SC_U = 0x3C,
+ SC_7 = 0x3D,
+ SC_8 = 0x3E,
+ SC_COMMA = 0x41, /* , */
+ SC_K = 0x42,
+ SC_I = 0x43,
+ SC_O = 0x44,
+ SC_0 = 0x45,
+ SC_9 = 0x46,
+ SC_PERIOD = 0x49, /* . */
+ SC_SLASH = 0x4A, /* / */
+ SC_L = 0x4B,
+ SC_SEMICOLON = 0x4C, /* ; */
+ SC_P = 0x4D,
+ SC_MINUS = 0x4E, /* - */
+ SC_APOSTROPHE = 0x52, /* ' */
+ SC_LEFT_BRACKET = 0x54, /* [ */
+ SC_EQUAL = 0x55, /* = */
+ SC_CAPSLOCK = 0x58,
+ SC_RIGHT_SHIFT = 0x59,
+ SC_ENTER = 0x5A,
+ SC_RIGHT_BRACKET = 0x5B, /* ] */
+ SC_BACKSLASH = 0x5D, /* \ */
+ SC_BACKSPACE = 0x66,
+ SC_PAD_1 = 0x69,
+ SC_PAD_4 = 0x6B,
+ SC_PAD_7 = 0x6C,
+ SC_PAD_0 = 0x70,
+ SC_PAD_DECIMAL = 0x71,
+ SC_PAD_2 = 0x72,
+ SC_PAD_5 = 0x73,
+ SC_PAD_6 = 0x74,
+ SC_PAD_8 = 0x75,
+ SC_ESC = 0x76,
+ SC_NUMLOCK = 0x77,
+ SC_F11 = 0x78,
+ SC_PAD_PLUS = 0x79,
+ SC_PAD_3 = 0x7A,
+ SC_PAD_MINUS = 0x7B,
+ SC_PAD_ASTERISK = 0x7C,
+ SC_PAD_9 = 0x7D,
+ SC_SCROLLLOCK = 0x7E,
+ SC_F7 = 0x83,
+ SC_EXTENDED1 = 0xE0, /* One code follows. */
+ SC_EXTENDED2 = 0xE1, /* Two codes follow (only used for Pause). */
+ SC_ERROR = 0xFF, /* Too many keys held down. */
+ SC_FLAG_UP = 0xF000 /* ORed to basic scancode. */
+ };
+
+/* In set 2 function keys don't have a logical order. This macro can
+ determine if a function key was pressed. */
+#define IS_FUNC_KEY(c) ((sc >= SC_F9 && sc <= SC_F4) || \
+ sc == SC_F7 || sc == SC_F11)
+
+/* Codes which can follow SC_EXTENDED1. */
+enum scancode_x1
+ {
+ SC_X1_RIGHT_ALT = 0x11,
+ SC_X1_PRTSC = 0x12,
+/* SC_X1_PRTSC = 0x7C, */
+ SC_X1_RIGHT_CTRL = 0x14,
+ SC_X1_LEFT_GUI = 0x1F,
+ SC_X1_RIGHT_GUI = 0x27,
+ SC_X1_APPS = 0x2F,
+ SC_X1_POWER = 0x37,
+ SC_X1_SLEEP = 0x3F,
+ SC_X1_PAD_SLASH = 0x4A,
+ SC_X1_PAD_ENTER = 0x5A,
+ SC_X1_WAKEUP = 0x5E,
+ SC_X1_END = 0x69,
+ SC_X1_LEFT = 0x6B,
+ SC_X1_HOME = 0x6C,
+ SC_X1_INS = 0x70,
+ SC_X1_DEL = 0x71,
+ SC_X1_DOWN = 0x72,
+ SC_X1_RIGHT = 0x74,
+ SC_X1_UP = 0x75,
+ SC_X1_PGDN = 0x7A,
+ SC_X1_PGUP = 0x7D
+ };
+
+/* Codes which can follow SC_EXTENDED2. */
+enum scancode_x2
+ {
+ SC_X2_BREAK = 0x1477,
+ };
+
+
+/* Scancode to Unicode mapping. The empty string stands for the NULL
+ character. */
+char *sc_to_kc[][7] =
+ {
+ /*None, Shift, Ctrl, LAlt, S+LAlt, C+LAlt, RAlt */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_F9, 0, 0, 0, 0, 0, 0 }, /* SC_F9. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_F5, CONS_KEY_F17, 0, 0, 0, 0, 0 }, /* SC_F5. */
+ { CONS_KEY_F3, CONS_KEY_F15, 0, 0, 0, 0, 0 }, /* SC_F3. */
+ { CONS_KEY_F1, CONS_KEY_F13, 0, 0, 0, 0, 0 }, /* SC_F1. */
+ { CONS_KEY_F2, CONS_KEY_F14, 0, 0, 0, 0, 0 }, /* SC_F2. */
+ { CONS_KEY_F12, 0, 0, 0, 0, 0, 0 }, /* SC_F12. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_F10, 0, 0, 0, 0, 0, 0 }, /* SC_F10. */
+ { CONS_KEY_F8, CONS_KEY_F20, 0, 0, 0, 0, 0 }, /* SC_F8. */
+ { CONS_KEY_F6, CONS_KEY_F18, 0, 0, 0, 0, 0 }, /* SC_F6. */
+ { CONS_KEY_F4, CONS_KEY_F16, 0, 0, 0, 0, 0 }, /* SC_F4. */
+ { "\t", "\t", "\t", "\e\t", "\e\t", "\e\t", "\t" }, /* SC_TAB. */
+ { "`", "~", 0, "\e`", "\e~", 0, 0 }, /* SC_BACKQUOTE. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_ALT. XXX */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_SHIFT. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_CTRL. XXX */
+ { "q", "Q", "\x11", "\eq", "\eQ", "\e\x11", "q" }, /* SC_Q. */
+ { "1", "!", 0, "\e1", "\e!", 0, "1" }, /* SC_1. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "z", "Z", "\x1a", "\ez", "\eZ", "\e\x1a", "z" }, /* SC_Z. */
+ { "s", "S", "\x13", "\es", "\eS", "\e\x13", "s" }, /* SC_S. */
+ { "a", "A", "\x01", "\ea", "\eA", "\e\x01", "a" }, /* SC_A. */
+ { "w", "W", "\x17", "\ew", "\eW", "\e\x17", "w" }, /* SC_W. */
+ { "2", "@", "", "\e2", "\e@", 0, "2" }, /* SC_2. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "c", "C", "\x03", "\ec", "\eC", "\e\x03", "\xc2\xa2" }, /* SC_C. */
+ { "x", "X", "\x18", "\ex", "\eX", "\e\x18", "x" }, /* SC_X. */
+ { "d", "D", "\x04", "\ed", "\eD", "\e\x04", "d" }, /* SC_D. */
+ { "e", "E", "\x05", "\ee", "\eE", "\e\x05","\xe2\x82\xac" }, /* SC_E. */
+ { "4", "$", "\x1c", "\e4", "\e$", "\e\x1c", "4" }, /* SC_4. */
+ { "3", "#", "\e", "\e3", "\e#", 0, "3" }, /* SC_3. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { " ", " ", "", "\e ", "\e ", /*XXX*/0, " " }, /* SC_SPACE. */
+ { "v", "V", "\x16", "\ev", "\eV", "\e\x16", "v" }, /* SC_V. */
+ { "f", "F", "\x06", "\ef", "\eF", "\e\x06", "f" }, /* SC_F. */
+ { "t", "T", "\x14", "\et", "\eT", "\e\x14", "t" }, /* SC_T. */
+ { "r", "R", "\x12", "\er", "\eR", "\e\x12", "r" }, /* SC_R. */
+ { "5", "%", "\x1d", "\e5", "\e%", 0, "5" }, /* SC_5. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "n", "N", "\x0e", "\en", "\eN", "\e\x0e", "n" }, /* SC_N. */
+ { "b", "B", "\x02", "\eb", "\eB", "\e\x02", "b" }, /* SC_B. */
+ { "h", "H", "\x08", "\eh", "\eH", "\e\x08", "h" }, /* SC_H. */
+ { "g", "G", "\x07", "\eg", "\eG", "\e\x07", "g" }, /* SC_G. */
+ { "y", "Y", "\x19", "\ey", "\eY", "\e\x19", "y" }, /* SC_Y. */
+ { "6", "^", "\x1e", "\e6", "\e^", 0, "6" }, /* SC_6. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "m", "M", "\x0d", "\em", "\eM", "\e\x0d", "m" }, /* SC_M. */
+ { "j", "J", "\x0a", "\ej", "\eJ", "\e\x0a", "j" }, /* SC_J. */
+ { "u", "U", "\x15", "\eu", "\eU", "\e\x15", "u" }, /* SC_U. */
+ { "7", "&", "\x1f", "\e7", "\e&", "\e\x1f", "7" }, /* SC_7. */
+ { "8", "*", "\x7f", "\e8", "\e*", 0, "8" }, /* SC_8. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { ",", "<", 0, "\e,", "\e<", 0, 0 }, /* SC_COMMA. */
+ { "k", "K", "\x0b", "\ek", "\eK", "\e\x0b", "k" }, /* SC_K. */
+ { "i", "I", "\x09", "\ei", "\eI", "\e\x09", "i" }, /* SC_I. */
+ { "o", "O", "\x0f", "\eo", "\eO", "\e\x0f", "o" }, /* SC_O. */
+ { "0", ")", 0, "\e0", "\e)", 0, "0" }, /* SC_0. */
+ { "9", "(", 0, "\e9", "\e(", 0, "9" }, /* SC_9. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { ".", ">", 0, "\e.", "\e>", 0, 0 }, /* SC_PERIOD. */
+ { "/", "?", "\x7f", "\e/", "\e?", 0, 0 }, /* SC_SLASH. */
+ { "l", "L", "\x0c", "\el", "\eL", "\e\x0c", "l" }, /* SC_L. */
+ { ";", ":", 0, "\e;", "\e:", 0, 0 }, /* SC_SEMICOLON. */
+ { "p", "P", "\x10", "\ep", "\eP", "\e\x10", "p" }, /* SC_P. */
+ { "-", "_", "\x1f", "\e-", "\e_", "\e\x1f", "-" }, /* SC_MINUS. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "'", "\"", "\x07", "\e'", "\e\"", 0, 0 }, /* SC_APOSTROPHE. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "[", "{", "\e", "\e[", "\e{", 0, 0 }, /* SC_LEFT_BRACKET. */
+ { "=", "+", 0, "\e=", "\e+", 0, "=" }, /* SC_EQUAL. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_CAPSLOCK. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_RIGHT_SHIFT. */
+ {"\x0d","\x0d", "\x0d","\e\x0d","\e\x0d","\e\x0d","\x0d" }, /* SC_ENTER. */
+ { "]", "}", "\x1d", "\e]", "\e}", "\e\x1d", "~" }, /* SC_RIGHT_BRACKET. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "\\", "|", "\x1c", "\e\\", "\e|", 0, 0 }, /* SC_BACKSLASH. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_BACKSPACE, CONS_KEY_BACKSPACE, CONS_KEY_BACKSPACE,
+ "\e" CONS_KEY_BACKSPACE, "\e" CONS_KEY_BACKSPACE,
+ "\e" CONS_KEY_BACKSPACE, CONS_KEY_BACKSPACE }, /* SC_BACKSPACE. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_END, CONS_KEY_END, CONS_KEY_END, 0, 0, 0, 0 }, /* SC_PAD_1. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT, 0, 0, 0, 0 }, /* SC_PAD_4. */
+ { CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME, 0, 0, 0, 0 }, /* SC_PAD_7. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC, 0, 0, 0, 0 }, /* SC_PAD_0. */
+ { CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC, 0, 0, 0, 0 }, /* SC_PAD_DECIMAL. */
+ { CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN, 0, 0, 0, 0 }, /* SC_PAD_2. */
+ {/* XXX */ "\e[G", "\e[G", "\e[G", 0, 0, 0, 0 }, /* SC_PAD_5. */
+ { CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT,0, 0, 0, 0 }, /* SC_PAD_6. */
+ { CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP, 0, 0, 0, 0 }, /* SC_PAD_8. */
+ { "\e", "\e", "\e", "\e\e", "\e\e", "\e\e", "\e" }, /* SC_ESC. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_NUMLOCK. */
+ { CONS_KEY_F11, 0, 0, 0, 0, 0, 0 }, /* SC_F11. */
+ { "+", "+", "+", "+", "+", "+", "+" }, /* SC_PAD_PLUS. */
+ { CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE,0, 0, 0, 0 }, /* SC_PAD_3. */
+ { "-", "-", "-", "-", "-", "-", "-" }, /* SC_PAD_MINUS. */
+ { "*", "*", "*", "*", "*", "*", "*" }, /* SC_PAD_ASTERISK. XXX */
+ { CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE,0, 0, 0, 0 }, /* SC_PAD_9. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_SCROLLLOCK. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_F7, CONS_KEY_F19, 0, 0, 0, 0, 0 } /* SC_F7. */
+ };
+
+char *sc_x1_to_kc[][7] =
+ {
+ /* None, Shift, Ctrl, LAlt, S+LAlt, C+LAlt, RAlt */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_RIGHT_ALT. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_PRTSC. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_RIGHT_CTRL. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_LEFT_GUI. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_RIGHT_GUI. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_APPS. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_POWER. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_SLEEP. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { "/", "/", "/", "/", "/", "/", 0 }, /* SC_X1_PAD_SLASH. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "\n", "\n", "\n", "\n", "\n", "\n", 0 }, /* SC_X1_PAD_ENTER. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_WAKEUP. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_END, CONS_KEY_END, CONS_KEY_END, CONS_KEY_END,
+ CONS_KEY_END, CONS_KEY_END, CONS_KEY_END }, /* SC_X1_END. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT,
+ CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT }, /* SC_X1_LEFT. */
+ { CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME,
+ CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME }, /* SC_X1_HOME. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC,
+ CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC }, /* SC_X1_INS. */
+ { CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC,
+ CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC }, /* SC_X1_DEL. */
+ { CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN,
+ CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN }, /* SC_X1_DOWN. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT,
+ CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT }, /* SC_X1_RIGHT. */
+ { CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP,
+ CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP }, /* SC_X1_UP. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE,
+ CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE }, /* SC_X1_PGDN. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE,
+ CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE } /* SC_X1_PGUP. */
+ };
+
+char *sc_x2_to_kc[][7] =
+ {
+ /* We don't add all those zero entries here. It's just one key,
+ so it's special cased. */
+ { "\e[P", "\e[P", "\e[P", "\e[P", "\e[P", "\e[P","\e[P" }, /* SC_X1_BREAK. */
+ };
+
+
+/* GNU Mach v1 compatibility code. */
+
+/* This is a conversion table from i8042 scancode set 1 to set 2. */
+enum scancode sc_set1_to_set2[] =
+ {
+ 0x00,
+ SC_ESC,
+ SC_1,
+ SC_2,
+ SC_3,
+ SC_4,
+ SC_5,
+ SC_6,
+ SC_7,
+ SC_8,
+ SC_9,
+ SC_0,
+ SC_MINUS,
+ SC_EQUAL,
+ SC_BACKSPACE,
+ SC_TAB,
+ SC_Q,
+ SC_W,
+ SC_E,
+ SC_R,
+ SC_T,
+ SC_Y,
+ SC_U,
+ SC_I,
+ SC_O,
+ SC_P,
+ SC_LEFT_BRACKET,
+ SC_RIGHT_BRACKET,
+ SC_ENTER,
+ SC_LEFT_CTRL,
+ SC_A,
+ SC_S,
+ SC_D,
+ SC_F,
+ SC_G,
+ SC_H,
+ SC_J,
+ SC_K,
+ SC_L,
+ SC_SEMICOLON,
+ SC_APOSTROPHE,
+ SC_BACKQUOTE,
+ SC_LEFT_SHIFT,
+ SC_BACKSLASH,
+ SC_Z,
+ SC_X,
+ SC_C,
+ SC_V,
+ SC_B,
+ SC_N,
+ SC_M,
+ SC_COMMA,
+ SC_PERIOD,
+ SC_SLASH,
+ SC_RIGHT_SHIFT,
+ SC_PAD_ASTERISK,
+ SC_LEFT_ALT,
+ SC_SPACE,
+ SC_CAPSLOCK,
+ SC_F1,
+ SC_F2,
+ SC_F3,
+ SC_F4,
+ SC_F5,
+ SC_F6,
+ SC_F7,
+ SC_F8,
+ SC_F9,
+ SC_F10,
+ SC_NUMLOCK,
+ SC_SCROLLLOCK,
+ SC_PAD_7,
+ SC_PAD_8,
+ SC_PAD_9,
+ SC_PAD_MINUS,
+ SC_PAD_4,
+ SC_PAD_5,
+ SC_PAD_6,
+ SC_PAD_PLUS,
+ SC_PAD_1,
+ SC_PAD_2,
+ SC_PAD_3,
+ SC_PAD_0,
+ SC_PAD_DECIMAL,
+ 0x00, /* XXX SYSREQ */
+ 0x00,
+ 0x00,
+ SC_F11,
+ SC_F12,
+ };
+
+/* Conversion table for codes which can follow SC_EXTENDED1. */
+enum scancode sc_set1_to_set2_x1[] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ SC_X1_PAD_ENTER,
+ SC_X1_RIGHT_CTRL,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ SC_X1_PAD_SLASH,
+ 0x00,
+ SC_X1_PRTSC,
+ SC_X1_RIGHT_ALT,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, /* XXX SC_X1_BREAK */
+ SC_X1_HOME,
+ SC_X1_UP,
+ SC_X1_PGUP,
+ 0x00,
+ SC_X1_LEFT,
+ 0x00,
+ SC_X1_RIGHT,
+ 0x00,
+ SC_X1_END,
+ SC_X1_DOWN,
+ SC_X1_PGDN,
+ SC_X1_INS,
+ SC_X1_DEL
+ };
+
+static enum scancode
+gnumach_v1_input_next ()
+{
+ kd_event data_buf;
+ int up;
+ enum scancode sc;
+
+ do
+ {
+ /* io_buf_ptr_t is (char *), not (void *). So I have a few
+ casts to quiet warnings. */
+ mach_msg_type_number_t data_cnt = sizeof (data_buf);
+ error_t err = device_read_inband (kbd_dev, 0, -1, sizeof (kd_event),
+ (void *) &data_buf, &data_cnt);
+
+ /* XXX The error occurred likely because KBD_DEV was closed, so
+ terminate. */
+ if (err)
+ return 0;
+
+ if (kbd_repeater_opened && data_buf.type == KEYBD_EVENT)
+ {
+ kbd_repeat_key (&data_buf);
+ data_buf.type = 0;
+ continue;
+ }
+ }
+ while (data_buf.type != KEYBD_EVENT);
+
+ /* Some fixed codes which are the same in set 1 and set 2, and have
+ the UP flag set. */
+ if (data_buf.value.sc == SC_EXTENDED1
+ || data_buf.value.sc == SC_EXTENDED2
+ || data_buf.value.sc == SC_ERROR)
+ return data_buf.value.sc;
+
+#define SC_SET1_FLAG_UP 0x80
+ up = data_buf.value.sc & SC_SET1_FLAG_UP;
+ sc = sc_set1_to_set2[data_buf.value.sc &~ SC_SET1_FLAG_UP];
+
+ return sc | (up ? SC_FLAG_UP : 0);
+}
+
+
+static void
+update_leds (void)
+{
+ error_t err;
+
+ if (gnumach_v1_compat)
+ {
+ int led = (led_state.scroll_lock ? 1 : 0)
+ | (led_state.num_lock ? 2 : 0)
+ | (led_state.caps_lock ? 4 : 0);
+
+ err = device_set_status (kbd_dev, KDSETLEDS, &led, 1);
+ /* Just ignore the error, GNUMach 1.3 and older cannot set the
+ keyboard LEDs. */
+ }
+ else
+ {
+ char leds[2];
+ mach_msg_type_number_t data_cnt = 2;
+
+ leds[0] = '\xed';
+ leds[1] = (led_state.scroll_lock ? 1 : 0)
+ | (led_state.num_lock ? 2 : 0)
+ | (led_state.caps_lock ? 4 : 0);
+
+ err = device_write_inband (kbd_dev, 0, -1, (void *) leds, 2, &data_cnt);
+ if (!err && data_cnt == 1)
+ err = device_write_inband (kbd_dev, 0, -1, (void *) &leds[1], 1,
+ &data_cnt);
+ }
+}
+
+static enum scancode
+input_next ()
+{
+ enum scancode sc = 0;
+ unsigned char next;
+
+ /* GNU Mach v1 does provide keyboard input in a different format. */
+ if (gnumach_v1_compat)
+ return gnumach_v1_input_next ();
+
+ /* XXX This should read several characters at once. */
+ do
+ {
+ mach_msg_type_number_t data_cnt = 1;
+ error_t err = device_read_inband (kbd_dev, 0, -1, 1,
+ (void *) &next, &data_cnt);
+
+ /* XXX The error occurred likely because KBD_DEV was closed, so
+ terminate. */
+ if (err)
+ return 0;
+
+ if (next == 0xF0)
+ /* XXX Magic constant. */
+ sc |= SC_FLAG_UP;
+ }
+ while (next == 0xF0); /* XXX Magic constant. */
+
+ sc |= next;
+ return sc;
+}
+
+
+/* The input loop. */
+static any_t
+input_loop (any_t unused)
+{
+ while (1)
+ {
+ enum scancode fsc = input_next ();
+ enum scancode sc = fsc & ~SC_FLAG_UP;
+ int down = !(fsc & SC_FLAG_UP);
+ char buf[100];
+ size_t size = 0;
+ int modifier = -1;
+
+ static struct {
+ wchar_t direct;
+ unsigned int extended : 2;
+ unsigned int left_shift : 1;
+ unsigned int right_shift : 1;
+ unsigned int caps_lock : 1;
+ unsigned int caps_lock_pressed : 1;
+ unsigned int left_ctrl : 1;
+ unsigned int right_ctrl : 1;
+ unsigned int left_alt : 1;
+ unsigned int right_alt : 1;
+ unsigned int num_lock : 1;
+ unsigned int num_lock_pressed : 1;
+ } state;
+
+ if (!state.left_alt && !state.right_alt)
+ {
+ if (state.left_ctrl || state.right_ctrl)
+ modifier = 2;
+ else if (state.left_shift || state.right_shift)
+ modifier = 1;
+ else
+ modifier = 0;
+ }
+ else if (state.left_alt)
+ {
+ if (state.left_ctrl || state.right_ctrl)
+ modifier = 5;
+ if (state.left_shift || state.right_shift)
+ modifier = 4;
+ else
+ modifier = 3;
+ }
+ else if (state.right_alt)
+ {
+ if (!state.left_ctrl && !state.right_ctrl
+ && !state.left_shift && !state.right_shift)
+ modifier = 6;
+ }
+
+ if (!state.extended)
+ {
+ if (fsc == SC_EXTENDED1)
+ state.extended = 1;
+ else if (fsc == SC_EXTENDED2)
+ state.extended = 2;
+ else if (sc == SC_LEFT_SHIFT)
+ state.left_shift = down;
+ else if (sc == SC_RIGHT_SHIFT)
+ state.right_shift = down;
+ else if (sc == SC_CAPSLOCK)
+ {
+ if (down && !state.caps_lock_pressed)
+ {
+ state.caps_lock = !state.caps_lock;
+ state.caps_lock_pressed = 1;
+ led_state.caps_lock = state.caps_lock;
+ update_leds ();
+ }
+ else if (!down)
+ state.caps_lock_pressed = 0;
+ }
+ else if (sc == SC_LEFT_CTRL)
+ state.left_ctrl = down;
+ else if (sc == SC_LEFT_ALT)
+ state.left_alt = down;
+ else if (state.left_alt && down && IS_FUNC_KEY (sc))
+ {
+ /* The virtual console to switch to. */
+ int vc = 0;
+
+ /* Check if a function key was pressed.
+ Choose the virtual console corresponding to that key. */
+ switch (sc)
+ {
+ case SC_F1:
+ vc = 1;
+ break;
+ case SC_F2:
+ vc = 2;
+ break;
+ case SC_F3:
+ vc = 3;
+ break;
+ case SC_F4:
+ vc = 4;
+ break;
+ case SC_F5:
+ vc = 5;
+ break;
+ case SC_F6:
+ vc = 6;
+ break;
+ case SC_F7:
+ vc = 7;
+ break;
+ case SC_F8:
+ vc = 8;
+ break;
+ case SC_F9:
+ vc = 9;
+ break;
+ case SC_F10:
+ vc = 10;
+ break;
+ case SC_F11:
+ vc = 11;
+ break;
+ case SC_F12:
+ vc = 12;
+ break;
+ /* No function key was pressed, don't
+ switch to another vc. */
+ default:
+ vc = 0;
+ }
+
+ if (vc)
+ console_switch (vc, 0);
+ }
+ else if (state.left_alt && state.left_ctrl && down && sc == SC_BACKSPACE)
+ console_exit ();
+ else if (state.right_alt && down && sc == SC_PAD_0) /* XXX */
+ state.direct = (state.direct << 4) | 0x0;
+ else if (state.right_alt && down && sc == SC_PAD_1) /* XXX */
+ state.direct = (state.direct << 4) | 0x1;
+ else if (state.right_alt && down && sc == SC_PAD_2) /* XXX */
+ state.direct = (state.direct << 4) | 0x2;
+ else if (state.right_alt && down && sc == SC_PAD_3) /* XXX */
+ state.direct = (state.direct << 4) | 0x3;
+ else if (state.right_alt && down && sc == SC_PAD_4) /* XXX */
+ state.direct = (state.direct << 4) | 0x4;
+ else if (state.right_alt && down && sc == SC_PAD_5) /* XXX */
+ state.direct = (state.direct << 4) | 0x5;
+ else if (state.right_alt && down && sc == SC_PAD_6) /* XXX */
+ state.direct = (state.direct << 4) | 0x6;
+ else if (state.right_alt && down && sc == SC_PAD_7) /* XXX */
+ state.direct = (state.direct << 4) | 0x7;
+ else if (state.right_alt && down && sc == SC_PAD_8) /* XXX */
+ state.direct = (state.direct << 4) | 0x8;
+ else if (state.right_alt && down && sc == SC_PAD_9) /* XXX */
+ state.direct = (state.direct << 4) | 0x9;
+ else if (state.right_alt && down && sc == SC_NUMLOCK) /* XXX */
+ state.direct = (state.direct << 4) | 0xa;
+ else if (state.right_alt && down && sc == SC_PAD_ASTERISK) /* XXX */
+ state.direct = (state.direct << 4) | 0xc;
+ else if (state.right_alt && down && sc == SC_PAD_MINUS) /* XXX */
+ state.direct = (state.direct << 4) | 0xd;
+ else if (state.right_alt && down && sc == SC_PAD_PLUS) /* XXX */
+ state.direct = (state.direct << 4) | 0xe;
+ else if (sc == SC_NUMLOCK)
+ {
+ if (down && !state.num_lock_pressed)
+ {
+ state.num_lock = !state.num_lock;
+ state.num_lock_pressed = 1;
+ led_state.num_lock = state.num_lock;
+ update_leds ();
+ }
+ else if (!down)
+ state.num_lock_pressed = 0;
+ }
+ else if (down && sc < sizeof (sc_to_kc)/sizeof (sc_to_kc[0]))
+ {
+#if QUAERENDO_INVENIETIS
+ if (state.left_alt && state.right_alt
+ && sc_to_kc[sc][0][0] >= '0' && sc_to_kc[sc][0][0] <= '9'
+ && sc_to_kc[sc][0][1] == '\0')
+ console_deprecated (sc_to_kc[sc][0][0] - '0');
+ else
+#endif
+ {
+ /* Special rule for caps lock. */
+ if (modifier == 0 && state.caps_lock
+ && sc_to_kc[sc][modifier]
+ && sc_to_kc[sc][modifier][0] >= 'a'
+ && sc_to_kc[sc][modifier][0] <= 'z'
+ && sc_to_kc[sc][modifier][1] == '\0')
+ modifier = 1;
+ else if (state.num_lock && sc == SC_PAD_0)
+ {
+ modifier = 0;
+ sc = SC_0;
+ }
+ else if (state.num_lock && sc == SC_PAD_1)
+ {
+ modifier = 0;
+ sc = SC_1;
+ }
+ else if (state.num_lock && sc == SC_PAD_2)
+ {
+ modifier = 0;
+ sc = SC_2;
+ }
+ else if (state.num_lock && sc == SC_PAD_3)
+ {
+ modifier = 0;
+ sc = SC_3;
+ }
+ else if (state.num_lock && sc == SC_PAD_4)
+ {
+ modifier = 0;
+ sc = SC_4;
+ }
+ else if (state.num_lock && sc == SC_PAD_5)
+ {
+ modifier = 0;
+ sc = SC_5;
+ }
+ else if (state.num_lock && sc == SC_PAD_6)
+ {
+ modifier = 0;
+ sc = SC_6;
+ }
+ else if (state.num_lock && sc == SC_PAD_7)
+ {
+ modifier = 0;
+ sc = SC_7;
+ }
+ else if (state.num_lock && sc == SC_PAD_8)
+ {
+ modifier = 0;
+ sc = SC_8;
+ }
+ else if (state.num_lock && sc == SC_PAD_9)
+ {
+ modifier = 0;
+ sc = SC_9;
+ }
+ else if (state.num_lock && sc == SC_PAD_DECIMAL)
+ {
+ modifier = 0;
+ sc = SC_PERIOD;
+ }
+
+ if (modifier >= 0 && sc_to_kc[sc][modifier])
+ {
+ if (!sc_to_kc[sc][modifier][0])
+ {
+ /* Special meaning, emit NUL. */
+ assert (size < 100);
+ buf[size++] = '\0';
+ }
+ else
+ {
+ assert (size
+ < 101 - strlen(sc_to_kc[sc][modifier]));
+ strcpy (&buf[size], sc_to_kc[sc][modifier]);
+ size += strlen (sc_to_kc[sc][modifier]);
+ }
+ }
+ }
+ }
+ }
+ else if (state.extended == 1)
+ {
+ state.extended = 0;
+ if (sc == SC_X1_RIGHT_CTRL)
+ state.right_ctrl = down;
+ else if (sc == SC_X1_RIGHT_ALT)
+ {
+ state.right_alt = down;
+
+ /* Handle the AltGR+Keypad direct input. */
+ if (down)
+ state.direct = (wchar_t) 0;
+ else
+ {
+ if (state.direct != (wchar_t) 0)
+ {
+ char *buffer = &buf[size];
+ size_t left = sizeof (buf) - size;
+ char *inbuf = (char *) &state.direct;
+ size_t inbufsize = sizeof (wchar_t);
+ size_t nr;
+
+ nr = iconv (cd, &inbuf, &inbufsize, &buffer, &left);
+ if (nr == (size_t) -1)
+ {
+ if (errno == E2BIG)
+ console_error (L"Input buffer overflow");
+ else if (errno == EILSEQ)
+ console_error
+ (L"Input contained invalid byte sequence");
+ else if (errno == EINVAL)
+ console_error
+ (L"Input contained incomplete byte sequence");
+ else
+ console_error
+ (L"Input caused unexpected error");
+ }
+ size = sizeof (buf) - left;
+ }
+ }
+ }
+ else if (state.right_alt && down && sc == SC_X1_PAD_SLASH) /* XXX */
+ state.direct = (state.direct << 4) | 0xb;
+ else if (state.right_alt && down && sc == SC_X1_PAD_ENTER) /* XXX */
+ state.direct = (state.direct << 4) | 0xf;
+ else if (state.left_alt && down && sc == SC_X1_RIGHT) /* XXX */
+ console_switch (0, 1);
+ else if (state.left_alt && down && sc == SC_X1_LEFT) /* XXX */
+ console_switch (0, -1);
+ else if (state.left_alt && down && sc == SC_X1_UP) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_LINES, 1);
+ else if (state.left_alt && down && sc == SC_X1_DOWN) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_LINES, -1);
+ else if ((state.right_shift || state.left_shift)
+ && down && sc == SC_X1_PGUP) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_SCREENS, 0.5);
+ else if ((state.right_shift || state.left_shift)
+ && down && sc == SC_X1_PGDN) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_SCREENS, -0.5);
+ else if (down && sc < sizeof (sc_x1_to_kc)/sizeof (sc_x1_to_kc[0]))
+ {
+ if (modifier >= 0 && sc_x1_to_kc[sc][modifier])
+ {
+ assert (size < 101 - strlen(sc_x1_to_kc[sc][modifier]));
+ strcpy (&buf[size], sc_x1_to_kc[sc][modifier]);
+ size += strlen (sc_x1_to_kc[sc][modifier]);
+ }
+ }
+ }
+ else if (state.extended == 2)
+ state.extended = 3;
+ else if (state.extended == 3)
+ state.extended = 0;
+
+ if (size)
+ console_input (buf, size);
+ }
+ return 0;
+}
+
+
+
+
+static const char doc[] = "PC Keyboard Driver";
+
+static const struct argp_option options[] =
+ {
+ {"repeat", 'r', "NODE", OPTION_ARG_OPTIONAL,
+ "Set a repeater translator on NODE (default: " DEFAULT_REPEATER_NODE ")"},
+ { 0 }
+ };
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ int *pos = (int *) state->input;
+
+ switch (key)
+ {
+ case 'r':
+ repeater_node = arg ? arg: DEFAULT_REPEATER_NODE;
+ break;
+
+ case ARGP_KEY_END:
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ *pos = state->next;
+ return 0;
+}
+
+static struct argp argp = {options, parse_opt, 0, doc};
+
+/* Initialize the PC keyboard driver. */
+static error_t
+pc_kbd_init (void **handle, int no_exit, int argc, char *argv[], int *next)
+{
+ error_t err;
+ int pos = 1;
+
+ /* Parse the arguments. */
+ err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_EXIT
+ | ARGP_SILENT, 0 , &pos);
+ *next += pos - 1;
+
+ if (err && err != EINVAL)
+ return err;
+
+
+ return 0;
+}
+
+
+/* Start the PC keyboard driver. */
+static error_t
+pc_kbd_start (void *handle)
+{
+ error_t err;
+ device_t device_master;
+
+ cd = iconv_open ("UTF-8", "WCHAR_T");
+ if (cd == (iconv_t) -1)
+ return errno;
+
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ {
+ iconv_close (cd);
+ return err;
+ }
+
+ err = device_open (device_master, D_READ | D_WRITE, "@>=kbd", &kbd_dev);
+ if (err == D_NO_SUCH_DEVICE)
+ {
+ /* GNU Mach v1 has a different device. */
+ gnumach_v1_compat = 1;
+ err = device_open (device_master, D_READ, "kbd", &kbd_dev);
+ }
+
+ mach_port_deallocate (mach_task_self (), device_master);
+ if (err)
+ {
+ iconv_close (cd);
+ return err;
+ }
+
+ if (gnumach_v1_compat)
+ {
+ int data = KB_EVENT;
+ err = device_set_status (kbd_dev, KDSKBDMODE, &data, 1);
+ if (err)
+ {
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+ return err;
+ }
+ }
+ update_leds ();
+
+ err = driver_add_input (&pc_kbd_ops, NULL);
+ if (err)
+ {
+ if (gnumach_v1_compat)
+ {
+ int data = KB_ASCII;
+ device_set_status (kbd_dev, KDSKBDMODE, &data, 1);
+ }
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+ return err;
+ }
+
+ if (repeater_node)
+ kbd_setrepeater (repeater_node, &cnode);
+
+ cthread_detach (cthread_fork (input_loop, NULL));
+
+ return 0;
+}
+
+/* Deinitialize the PC keyboard driver. */
+static error_t
+pc_kbd_fini (void *handle, int force)
+{
+ driver_remove_input (&pc_kbd_ops, NULL);
+ if (gnumach_v1_compat)
+ {
+ int data = KB_ASCII;
+ device_set_status (kbd_dev, KDSKBDMODE, &data, 1);
+ }
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+
+ console_unregister_consnode (cnode);
+ console_destroy_consnode (cnode);
+
+ return 0;
+}
+
+
+/* Set the scroll lock status indication (Scroll LED) to ONOFF. */
+static error_t
+pc_kbd_set_scroll_lock_status (void *handle, int onoff)
+{
+ led_state.scroll_lock = onoff;
+ update_leds ();
+ return 0;
+}
+
+
+struct driver_ops driver_pc_kbd_ops =
+ {
+ pc_kbd_init,
+ pc_kbd_start,
+ pc_kbd_fini
+ };
+
+static struct input_ops pc_kbd_ops =
+ {
+ pc_kbd_set_scroll_lock_status,
+ NULL
+ };
diff --git a/console-client/pc-mouse.c b/console-client/pc-mouse.c
new file mode 100644
index 00000000..cf8987bf
--- /dev/null
+++ b/console-client/pc-mouse.c
@@ -0,0 +1,509 @@
+/* pc-mouse.c - Mouse driver.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Written by Marco Gerards.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <argp.h>
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <device/device.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include "driver.h"
+#include "mach-inputdev.h"
+
+static struct input_ops pc_mouse_ops;
+
+/* Default to the protocol I use :). */
+static int majordev = IBM_MOUSE;
+static int minordev = 0;
+
+static device_t mousedev;
+
+
+/* The default name of the node of the repeater. */
+#define DEFAULT_REPEATER_NODE "mouse"
+
+/* The amount of mouse events that can be stored in the event buffer. */
+#define MOUSEDEVTBUFSZ 256
+
+/* The size of the event buffer in bytes. */
+#define MOUSEBUFSZ (MOUSEDEVTBUFSZ * sizeof (kd_event))
+
+/* Return the position of X in the buffer. */
+#define MOUSEBUF_POS(x) ((x) % MOUSEBUFSZ)
+
+/* The mouse sensitivity. */
+#define STRINGIFY(x) STRINGIFY_1(x)
+#define STRINGIFY_1(x) #x
+#define DEFAULT_MOUSE_SENS 1.0
+#define DEFAULT_MOUSE_SENS_STRING STRINGIFY(DEFAULT_MOUSE_SENS)
+
+/* The mouse event buffer. */
+static struct mousebuf
+{
+ char evtbuffer[MOUSEBUFSZ];
+ int pos;
+ size_t size;
+ struct condition readcond;
+ struct condition writecond;
+} mousebuf;
+
+/* Wakeup for select */
+static struct condition select_alert;
+
+/* The global lock */
+static struct mutex global_lock;
+
+/* Amount of times the device was opened. Normally this translator
+ should be only opened once. */
+static int mouse_repeater_opened;
+
+/* The name of the repeater node. */
+static char *repeater_node;
+
+/* The repeater node. */
+static consnode_t cnode;
+
+/* The mouse sensitivity. */
+float mouse_sens = DEFAULT_MOUSE_SENS;
+
+/* Place the mouse event EVNT in the mouse event buffer. */
+static void
+repeat_event (kd_event *evt)
+{
+ kd_event *ev;
+
+ mutex_lock (&global_lock);
+ while (mousebuf.size + sizeof (kd_event) > MOUSEBUFSZ)
+ {
+ /* The input buffer is full, wait until there is some space. */
+ if (hurd_condition_wait (&mousebuf.writecond, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ /* Interrupt, silently continue. */
+ }
+ }
+ ev = (kd_event *) &mousebuf.evtbuffer[MOUSEBUF_POS (mousebuf.pos
+ + mousebuf.size)];
+ mousebuf.size += sizeof (kd_event);
+ memcpy (ev, evt, sizeof (kd_event));
+
+ condition_broadcast (&mousebuf.readcond);
+ mutex_unlock (&global_lock);
+}
+
+
+static error_t
+repeater_select (struct protid *cred, mach_port_t reply,
+ mach_msg_type_name_t replytype, int *type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (*type & ~SELECT_READ)
+ return EINVAL;
+
+ if (*type == 0)
+ return 0;
+
+ mutex_lock (&global_lock);
+ while (1)
+ {
+ if (mousebuf.size > 0)
+ {
+ *type = SELECT_READ;
+ mutex_unlock (&global_lock);
+
+ return 0;
+ }
+
+ ports_interrupt_self_on_port_death (cred, reply);
+ if (hurd_condition_wait (&select_alert, &global_lock))
+ {
+ *type = 0;
+ mutex_unlock (&global_lock);
+
+ return EINTR;
+ }
+ }
+}
+
+
+static void
+repeater_open (void)
+{
+ mouse_repeater_opened++;
+}
+
+
+static void
+repeater_close (void)
+{
+ mouse_repeater_opened--;
+ if (!mouse_repeater_opened)
+ {
+ mousebuf.pos = 0;
+ mousebuf.size = 0;
+ }
+}
+
+
+static error_t
+repeater_read (struct protid *cred, char **data,
+ mach_msg_type_number_t *datalen, off_t offset,
+ mach_msg_type_number_t amount)
+{
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openstat & O_READ))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+ while (!mousebuf.size)
+ {
+ if (cred->po->openstat & O_NONBLOCK && mousebuf.size == 0)
+ {
+ mutex_unlock (&global_lock);
+ return EWOULDBLOCK;
+ }
+
+ if (hurd_condition_wait (&mousebuf.readcond, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ }
+
+ amount = (amount / sizeof (kd_event) - 1) * sizeof (kd_event);
+ if (amount > mousebuf.size)
+ amount = mousebuf.size;
+
+ if (amount > 0)
+ {
+ char *mousedata;
+ unsigned int i = 0;
+
+ /* Allocate a buffer when this is required. */
+ if (*datalen < amount)
+ {
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ {
+ mutex_unlock (&global_lock);
+ return ENOMEM;
+ }
+ }
+
+ /* Copy the bytes to the user's buffer and remove them from the
+ mouse events buffer. */
+ mousedata = *data;
+ while (i != amount)
+ {
+ mousedata[i++] = mousebuf.evtbuffer[mousebuf.pos++];
+ mousebuf.pos = MOUSEBUF_POS (mousebuf.pos);
+ }
+ mousebuf.size -= amount;
+ condition_broadcast (&mousebuf.writecond);
+ }
+
+ *datalen = amount;
+ mutex_unlock (&global_lock);
+
+ return 0;
+}
+
+
+
+static any_t
+input_loop (any_t unused)
+{
+ kd_event *ev;
+ vm_offset_t buf;
+ mach_msg_type_number_t buf_size;
+
+ while (1)
+ {
+ struct mouse_event evt = { 0 };
+ device_read (mousedev, 0, 0, sizeof (kd_event),
+ (char **) &buf, &buf_size);
+ ev = (kd_event *) buf;
+
+ /* The repeater is set, send the event to the repeater. */
+ if (mouse_repeater_opened)
+ {
+ repeat_event (ev);
+ vm_deallocate (mach_task_self(), buf, buf_size);
+ continue;
+ }
+
+ evt.mouse_movement = CONS_VCONS_MOUSE_MOVE_REL;
+
+ switch (ev->type)
+ {
+ case MOUSE_LEFT:
+ evt.button = CONS_MOUSE_BUTTON1;
+ break;
+ case MOUSE_MIDDLE:
+ evt.button = CONS_MOUSE_BUTTON2;
+ break;
+ case MOUSE_RIGHT:
+ evt.button = CONS_MOUSE_BUTTON3;
+ break;
+
+ case MOUSE_MOTION:
+ evt.x = ev->value.mmotion.mm_deltaX * mouse_sens;
+ evt.y = -ev->value.mmotion.mm_deltaY * mouse_sens;
+ break;
+ }
+
+ if (ev->type > 0 && ev->type <= 3)
+ {
+ if (ev->value.up)
+ evt.mouse_button = CONS_VCONS_MOUSE_BUTTON_RELEASED;
+ else
+ evt.mouse_button = CONS_VCONS_MOUSE_BUTTON_PRESSED;
+ }
+
+ /* Generate a mouse movement event. */
+ console_move_mouse (&evt);
+ vm_deallocate (mach_task_self(), buf, buf_size);
+ }
+}
+
+
+#define PROTO_MOUSESYSTEM "mousesystem"
+#define PROTO_MICROSOFT "microsoft"
+#define PROTO_PS2 "ps/2"
+#define PROTO_NOMOUSE "nomouse"
+#define PROTO_LOGITECH "logitech"
+#define PROTO_MOUSE7 "mouse7"
+
+/* The supported mouse protocols. Be careful with adding more, the
+ protocols are carefully ordered so the index is the major device
+ number. */
+static char *mouse_protocols[] =
+ {
+ PROTO_MOUSESYSTEM,
+ PROTO_MICROSOFT,
+ PROTO_PS2,
+ PROTO_NOMOUSE,
+ PROTO_LOGITECH,
+ PROTO_MOUSE7
+ };
+
+static const char doc[] = "Mouse Driver";
+
+static const struct argp_option options[] =
+ {
+ { "protocol", 'p', "PROTOCOL", 0, "One of the protocols: "
+ PROTO_MOUSESYSTEM ", " PROTO_MICROSOFT ", " PROTO_PS2 ", "
+ PROTO_NOMOUSE ", " PROTO_LOGITECH ", " PROTO_MOUSE7 },
+ { "device", 'e', "DEVICE" , 0,
+ "One of the devices: " DEV_COM0 ", " DEV_COM1 },
+ { "sensitivity", 's', "SENSITIVITY", 0, "The mouse"
+ " sensitivity (default " DEFAULT_MOUSE_SENS_STRING "). A lower value"
+ " means more sensitive" },
+ { "repeat", 'r', "NODE", OPTION_ARG_OPTIONAL,
+ "Set a repeater translator on NODE (default: " DEFAULT_REPEATER_NODE ")"},
+ { 0 }
+ };
+
+static error_t setrepeater (const char *nodename);
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ int *pos = (int *) state->input;
+
+ switch (key)
+ {
+ case 'p':
+ {
+ unsigned int i;
+
+ for (i = 0; i < (sizeof (mouse_protocols) / sizeof (char *)); i++)
+ {
+ if (!strcasecmp (arg, mouse_protocols[i]))
+ {
+ majordev = i;
+ *pos = state->next;
+ return 0;
+ }
+ }
+ fprintf (stderr, "Unknown protocol `%s'\n", arg);
+ argp_usage (state);
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ case 'e':
+ {
+ if (!strcasecmp (DEV_COM0, arg))
+ minordev = 0;
+ else if (!strcasecmp (DEV_COM1, arg))
+ minordev = 1;
+ else
+ {
+ fprintf (stderr, "Unknown device `%s'\n", arg);
+ argp_usage (state);
+ return ARGP_ERR_UNKNOWN;
+ }
+ break;
+ }
+
+ case 'r':
+ repeater_node = arg ? arg : DEFAULT_REPEATER_NODE;
+ break;
+
+ case 's':
+ {
+ char *tail;
+
+ errno = 0;
+ mouse_sens = strtod (arg, &tail);
+ if (tail == NULL || tail == arg || *tail != '\0')
+ argp_error (state, "SENSITIVITY is not a number: %s", arg);
+ if (errno)
+ argp_error (state, "Overflow in argument SENSITIVITY %s", arg);
+ break;
+ }
+
+ case ARGP_KEY_END:
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ *pos = state->next;
+ return 0;
+}
+
+
+static struct argp argp = {options, parse_opt, 0, doc};
+
+static error_t
+pc_mouse_init (void **handle, int no_exit, int argc, char *argv[], int *next)
+{
+ error_t err;
+ int pos = 1;
+
+ /* Parse the arguments. */
+ err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_EXIT
+ | ARGP_SILENT, 0, &pos);
+ *next += pos - 1;
+ if (err && err != EINVAL)
+ return err;
+
+ return 0;
+}
+
+
+static error_t
+pc_mouse_start (void *handle)
+{
+ error_t err;
+ char device_name[9];
+ int devnum = majordev << 3 | minordev;
+ device_t device_master;
+
+ sprintf (device_name, "mouse%d", devnum);
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ return err;
+
+ err = device_open (device_master, D_READ, device_name, &mousedev);
+ mach_port_deallocate (mach_task_self (), device_master);
+ if (err)
+ return ENODEV;
+
+ err = driver_add_input (&pc_mouse_ops, NULL);
+ if (err)
+ {
+ device_close (mousedev);
+ mach_port_deallocate (mach_task_self (), mousedev);
+
+ return err;
+ }
+
+ cthread_detach (cthread_fork (input_loop, NULL));
+
+ if (repeater_node)
+ setrepeater (repeater_node);
+
+ return 0;
+}
+
+
+static error_t
+pc_mouse_fini (void *handle, int force)
+{
+ device_close (mousedev);
+ mach_port_deallocate (mach_task_self (), mousedev);
+ console_unregister_consnode (cnode);
+ console_destroy_consnode (cnode);
+
+ return 0;
+}
+
+
+
+struct driver_ops driver_pc_mouse_ops =
+ {
+ pc_mouse_init,
+ pc_mouse_start,
+ pc_mouse_fini
+ };
+
+static struct input_ops pc_mouse_ops =
+ {
+ NULL,
+ NULL
+ };
+
+
+/* Set make repeater translator node named NODENAME. */
+static error_t
+setrepeater (const char *nodename)
+{
+ error_t err;
+
+ err = console_create_consnode (nodename, &cnode);
+ if (err)
+ return err;
+
+ cnode->read = repeater_read;
+ cnode->write = 0;
+ cnode->select = repeater_select;
+ cnode->open = repeater_open;
+ cnode->close = repeater_close;
+ cnode->demuxer = 0;
+
+ mutex_init (&global_lock);
+
+ condition_init (&mousebuf.readcond);
+ condition_init (&mousebuf.writecond);
+
+ condition_init (&select_alert);
+ condition_implies (&mousebuf.readcond, &select_alert);
+
+ console_register_consnode (cnode);
+
+ return 0;
+}
diff --git a/console-client/timer.c b/console-client/timer.c
new file mode 100644
index 00000000..7bcdeab0
--- /dev/null
+++ b/console-client/timer.c
@@ -0,0 +1,210 @@
+/* timer.c - A timer module for Mach.
+ Copyright (C) 1995,96,2000,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <string.h>
+#include <maptime.h>
+
+#include <cthreads.h>
+
+#include "timer.h"
+
+/* The value of fetch_jiffies() at startup. */
+long long timer_root_jiffies;
+
+/* The mapped time. */
+volatile struct mapped_time_value *timer_mapped_time;
+
+
+/* The timer thread. */
+static thread_t timer_thread;
+
+/* The lock protects the timer list TIMERS. */
+static struct mutex timer_lock;
+
+/* A list of all active timers. */
+static struct timer_list *timers;
+
+
+static inline void
+timer_add_internal (struct timer_list *timer)
+{
+ struct timer_list **tp;
+
+ for (tp = &timers; *tp; tp = &(*tp)->next)
+ if ((*tp)->expires > timer->expires)
+ {
+ timer->next = *tp;
+ timer->next->prev = &timer->next;
+ timer->prev = tp;
+ *tp = timer;
+ break;
+ }
+ if (!*tp)
+ {
+ timer->next = 0;
+ timer->prev = tp;
+ *tp = timer;
+ }
+}
+
+
+/* Make the timer thread aware of new timers at the beginning of the
+ list. */
+static inline void
+kick_timer_thread (void)
+{
+ /* XXX This is a whacky notion. */
+ while (!timer_thread)
+ swtch_pri (0);
+
+ if (timer_thread != mach_thread_self ())
+ {
+ thread_suspend (timer_thread);
+ thread_abort (timer_thread);
+ thread_resume (timer_thread);
+ }
+}
+
+/* The timer thread. */
+static int
+timer_function (int this_is_a_pointless_variable_with_a_rather_long_name)
+{
+ mach_port_t recv = mach_reply_port ();
+ int wait = 0;
+
+ timer_thread = mach_thread_self ();
+
+ mutex_lock (&timer_lock);
+ while (1)
+ {
+ int jiff = fetch_jiffies ();
+
+ if (!timers)
+ wait = -1;
+ else if (timers->expires < jiff)
+ wait = 0;
+ else
+ wait = ((timers->expires - jiff) * 1000) / HZ;
+
+ mutex_unlock (&timer_lock);
+ mach_msg (NULL, (MACH_RCV_MSG | MACH_RCV_INTERRUPT
+ | (wait == -1 ? 0 : MACH_RCV_TIMEOUT)),
+ 0, 0, recv, wait, MACH_PORT_NULL);
+ mutex_lock (&timer_lock);
+
+ while (timers && timers->expires < fetch_jiffies ())
+ {
+ struct timer_list *tp;
+
+ tp = timers;
+
+ timers = timers->next;
+ if (timers)
+ timers->prev = &timers;
+
+ tp->next = 0;
+ tp->prev = 0;
+
+ if ((*tp->fnc) (tp->fnc_data))
+ timer_add_internal (tp);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Initialize the timer component. Must be called once at startup. */
+error_t
+timer_init (void)
+{
+ error_t err;
+ struct timeval tp;
+
+ mutex_init (&timer_lock);
+
+ err = maptime_map (0, 0, &timer_mapped_time);
+ if (err)
+ return err;
+
+ maptime_read (timer_mapped_time, &tp);
+
+ timer_root_jiffies = (long long) tp.tv_sec * HZ
+ + ((long long) tp.tv_usec * HZ) / 1000000;
+
+ cthread_detach (cthread_fork ((cthread_fn_t) timer_function, 0));
+ return 0;
+}
+
+
+/* Initialize the timer TIMER. */
+void
+timer_clear (struct timer_list *timer)
+{
+ memset (timer, 0, sizeof (struct timer_list));
+}
+
+/* Add the timer TIMER to the list. */
+void
+timer_add (struct timer_list *timer)
+{
+ mutex_lock (&timer_lock);
+ timer_add_internal (timer);
+
+ if (timers == timer)
+ kick_timer_thread ();
+
+ mutex_unlock (&timer_lock);
+}
+
+/* Remove the timer TIMER from the list. */
+int
+timer_remove (struct timer_list *timer)
+{
+ mutex_lock (&timer_lock);
+ if (timer->prev)
+ {
+ *timer->prev = timer->next;
+ if (timer->next)
+ timer->next->prev = timer->prev;
+
+ timer->next = 0;
+ timer->prev = 0;
+ mutex_unlock (&timer_lock);
+ return 1;
+ }
+ else
+ {
+ mutex_unlock (&timer_lock);
+ return 0;
+ }
+}
+
+/* Change the expiration time of the timer TIMER to EXPIRES. */
+void
+timer_change (struct timer_list *timer, long long expires)
+{
+ /* XXX Should optimize this. */
+ timer_remove (timer);
+ timer->expires = expires;
+ timer_add (timer);
+}
+
diff --git a/console-client/timer.h b/console-client/timer.h
new file mode 100644
index 00000000..4204192e
--- /dev/null
+++ b/console-client/timer.h
@@ -0,0 +1,72 @@
+/* timer.h - Interface to a timer module for Mach.
+ Copyright (C) 1995,96,2000,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include <errno.h>
+#include <maptime.h>
+
+
+/* Initialize the timer component. Must be called once at startup. */
+error_t timer_init (void);
+
+/* The data structure of a timer. A user can set the values EXPIRES,
+ DATA and FUNCTION, and should leave the other fields alone. */
+struct timer_list
+{
+ struct timer_list *next, **prev; /* things like to test "T->prev != NULL" */
+ long long expires;
+
+ /* The function to be called when the timer expires. If the
+ function returns a non-zero value, the timer is put back on the
+ list. */
+ int (*fnc) (void *);
+ void *fnc_data;
+};
+
+/* Initialize the timer TIMER. */
+void timer_clear (struct timer_list *timer);
+
+/* Add the timer TIMER to the list. */
+void timer_add (struct timer_list *timer);
+
+/* Remove the timer TIMER from the list. */
+int timer_remove (struct timer_list *timer);
+
+/* Change the expiration time of the timer TIMER to EXPIRES. */
+void timer_change (struct timer_list *timer, long long expires);
+
+extern inline long long
+fetch_jiffies ()
+{
+ extern volatile struct mapped_time_value *timer_mapped_time;
+ extern long long timer_root_jiffies;
+ struct timeval tv;
+ long long j;
+
+ maptime_read (timer_mapped_time, &tv);
+
+#define HZ 100
+ j = (long long) tv.tv_sec * HZ + ((long long) tv.tv_usec * HZ) / 1000000;
+ return j - timer_root_jiffies;
+}
+
+#endif /* _TIMER_H_ */
diff --git a/console-client/trans.c b/console-client/trans.c
new file mode 100644
index 00000000..a90b5c5d
--- /dev/null
+++ b/console-client/trans.c
@@ -0,0 +1,892 @@
+/* trans.c -- Control a translator node for the repeaters.
+
+ Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+
+ Written by Marco Gerards.
+
+ 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 */
+
+#include <fcntl.h>
+#include <maptime.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <hurd/hurd_types.h>
+#include <error.h>
+#include <version.h>
+
+#include "trans.h"
+
+
+char *netfs_server_name = "console";
+char *netfs_server_version = HURD_VERSION;
+int netfs_maxsymlinks = 0;
+
+/* Handy source of time. */
+static volatile struct mapped_time_value *console_maptime;
+
+static consnode_t node_list = 0;
+
+struct netnode
+{
+ consnode_t node;
+ char *symlink_path;
+};
+
+typedef mach_msg_header_t request_t;
+
+
+int
+console_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ int ret;
+ struct protid *user = (struct protid *) inp;
+ request_t *inop = (request_t *) inp;
+
+ ret = netfs_demuxer (inp, outp);
+ if (ret)
+ return ret;
+
+ user = ports_lookup_port (netfs_port_bucket, inop->msgh_local_port, netfs_protid_class);
+ if (!user)
+ return ret;
+
+ /* Don't do anything for the root node. */
+ if (user->po->np == netfs_root_node)
+ {
+ ports_port_deref (user);
+ return 0;
+ }
+
+ if (!ret && user->po->np->nn->node && user->po->np->nn->node->demuxer)
+ ret = user->po->np->nn->node->demuxer (inp, outp);
+
+ ports_port_deref (user);
+ return ret;
+}
+
+
+
+/* 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 *np, struct iouser *cred)
+{
+ return 0;
+}
+
+
+/* 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 *np,
+ uid_t uid, uid_t gid)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* 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 *np,
+ uid_t author)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* 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 *np,
+ mode_t mode)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* Attempt to turn NODE (user CRED) into a symlink with target NAME. */
+error_t
+netfs_attempt_mksymlink (struct iouser *cred, struct node *np,
+ char *name)
+{
+ if (!np->nn->node)
+ {
+ if (np->nn->symlink_path)
+ free (np->nn->symlink_path);
+ np->nn->symlink_path = strdup (name);
+ return 0;
+ }
+ else if (np->nn->node->mksymlink)
+ return np->nn->node->mksymlink (cred, np, name);
+ return EOPNOTSUPP;
+}
+
+
+/* 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 *np,
+ mode_t type, dev_t indexes)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* 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 *np,
+ int flags)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* This should attempt a utimes call for the user specified by CRED on
+ locked node NP, to change the atime to ATIME and the mtime to
+ MTIME. If ATIME or MTIME is null, then set to the current
+ time. */
+error_t
+netfs_attempt_utimes (struct iouser *cred, struct node *np,
+ struct timespec *atime, struct timespec *mtime)
+{
+ error_t err = fshelp_isowner (&np->nn_stat, cred);
+ int flags = TOUCH_CTIME;
+
+ if (! err)
+ {
+ if (mtime)
+ np->nn_stat.st_mtim = *mtime;
+ else
+ flags |= TOUCH_MTIME;
+
+ if (atime)
+ np->nn_stat.st_atim = *atime;
+ else
+ flags |= TOUCH_ATIME;
+
+ fshelp_touch (&np->nn_stat, flags, console_maptime);
+ }
+ return err;
+
+}
+
+
+/* This should attempt to set the size of the locked file NP (for user
+ CRED) to SIZE bytes long. */
+error_t
+netfs_attempt_set_size (struct iouser *cred, struct node *np,
+ loff_t size)
+{
+ return EOPNOTSUPP;
+}
+
+/* This should attempt to fetch filesystem status information for the
+ remote filesystem, for the user CRED. NP is locked. */
+error_t
+netfs_attempt_statfs (struct iouser *cred, struct node *np,
+ fsys_statfsbuf_t *st)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* This should sync the locked file NP completely to disk, for the
+ user CRED. If WAIT is set, return only after the sync is
+ completely finished. */
+error_t
+netfs_attempt_sync (struct iouser *cred, struct node *np,
+ int wait)
+{
+ return 0;
+}
+
+
+/* This should sync the entire remote filesystem. If WAIT is set,
+ return only after the sync is completely finished. */
+error_t
+netfs_attempt_syncfs (struct iouser *cred, int wait)
+{
+ return 0;
+}
+
+
+/* Lookup NAME in DIR (which is locked) for USER; set *NP to the found
+ name upon return. If the name was not found, then return ENOENT.
+ On any error, clear *NP. (*NP, if found, should be locked and a
+ reference to it generated. 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;
+ consnode_t cn;
+
+ *node = 0;
+ err = fshelp_access (&dir->nn_stat, S_IEXEC, user);
+ if (err)
+ goto out;
+
+ if (strcmp (name, ".") == 0)
+ {
+ /* Current directory -- just add an additional reference to DIR
+ and return it. */
+ netfs_nref (dir);
+ *node = dir;
+ goto out;
+ }
+
+ if (strcmp (name, "..") == 0)
+ {
+ err = EAGAIN;
+ goto out;
+ }
+
+ for (cn = node_list; cn; cn = cn->next)
+ if (!strcmp (name, cn->name))
+ {
+ if (cn->node == NULL)
+ {
+ struct netnode *nn = calloc (1, sizeof *nn);
+ if (nn == NULL)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+
+ *node = netfs_make_node (nn);
+
+ nn->node = cn;
+ (*node)->nn_stat = netfs_root_node->nn_stat;
+ (*node)->nn_stat.st_mode = (netfs_root_node->nn_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+ (*node)->nn_stat.st_ino = 5;
+ if (cn->readlink)
+ {
+ (*node)->nn_stat.st_mode |= S_IFLNK;
+ (*node)->nn_stat.st_size = cn->readlink (user, NULL, NULL);
+ }
+ else
+ {
+ (*node)->nn_stat.st_mode |= S_IFCHR;
+ (*node)->nn_stat.st_size = 0;
+ }
+ cn->node = *node;
+ goto out;
+ }
+ else
+ {
+ *node = cn->node;
+
+ netfs_nref (*node);
+ goto out;
+ }
+ }
+
+ err = ENOENT;
+
+ out:
+ mutex_unlock (&dir->lock);
+ if (err)
+ *node = 0;
+ else
+ mutex_lock (&(*node)->lock);
+
+ if (!err && *node != dir && (*node)->nn->node->open)
+ (*node)->nn->node->open ();
+
+ return err;
+}
+
+
+error_t
+netfs_S_io_seek (struct protid *user, off_t offset,
+ int whence, off_t *newoffset)
+{
+ /* XXX: Will all nodes be device nodes? */
+ if (!user)
+ return EOPNOTSUPP;
+ else
+ return ESPIPE;
+}
+
+
+error_t
+netfs_S_io_select (struct protid *user, mach_port_t reply,
+ mach_msg_type_name_t replytype, int *type)
+{
+ struct node *np;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ np = user->po->np;
+
+ if (np->nn->node && np->nn->node->select)
+ return np->nn->node->select (user, reply, replytype, type);
+ return EOPNOTSUPP;
+}
+
+
+/* Delete NAME in DIR (which is locked) for USER. */
+error_t
+netfs_attempt_unlink (struct iouser *user, struct node *dir,
+ char *name)
+{
+ error_t err;
+ consnode_t cn;
+
+ err = fshelp_access (&dir->nn_stat, S_IWRITE, user);
+ if (err)
+ return err;
+
+ for (cn = node_list; cn; cn = cn->next)
+ if (!strcmp (name, cn->name))
+ {
+ if (cn->mksymlink)
+ return 0;
+ else
+ break;
+ }
+ return EOPNOTSUPP;
+}
+
+
+/* Attempt to rename the directory FROMDIR to TODIR. Note that 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 EOPNOTSUPP;
+}
+
+
+/* Attempt to create a new directory named NAME in DIR (which is
+ locked) for USER with mode MODE. */
+error_t
+netfs_attempt_mkdir (struct iouser *user, struct node *dir,
+ char *name, mode_t mode)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* Attempt to remove directory named NAME in DIR (which is locked) for
+ USER. */
+error_t
+netfs_attempt_rmdir (struct iouser *user,
+ struct node *dir, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* 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. 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)
+{
+ error_t err;
+ consnode_t cn;
+
+ err = fshelp_access (&dir->nn_stat, S_IWRITE, user);
+ if (err)
+ return err;
+
+ if (!file->nn->node && file->nn->symlink_path)
+ {
+ for (cn = node_list; cn; cn = cn->next)
+ if (!strcmp (name, cn->name))
+ {
+ if (cn->mksymlink)
+ {
+ file->nn->node = cn;
+ cn->mksymlink (user, file, file->nn->symlink_path);
+ free (file->nn->symlink_path);
+ file->nn->symlink_path = NULL;
+ return 0;
+ }
+ else
+ break;
+ }
+ }
+ return EOPNOTSUPP;
+}
+
+
+/* Attempt to create an anonymous file related to DIR (which is
+ locked) for USER with MODE. Set *NP 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 **np)
+{
+ error_t err;
+ struct netnode *nn;
+
+ err = fshelp_access (&dir->nn_stat, S_IWRITE, user);
+ if (err)
+ {
+ *np = 0;
+ return err;
+ }
+
+ mutex_unlock (&dir->lock);
+
+ nn = calloc (1, sizeof (*nn));
+ if (!nn)
+ return ENOMEM;
+
+ *np = netfs_make_node (nn);
+ mutex_lock (&(*np)->lock);
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ return 0;
+}
+
+
+/* Attempt to create a file named NAME in DIR (which is locked) for
+ USER with MODE. Set *NP to the new node upon return. On any
+ error, clear *NP. *NP 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 **np)
+{
+ *np = 0;
+ mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+
+/* Read the contents of locked node NP (a symlink), for USER, into
+ BUF. */
+error_t
+netfs_attempt_readlink (struct iouser *user, struct node *np,
+ char *buf)
+{
+ if (np->nn->node && np->nn->node->readlink)
+ return np->nn->node->readlink (user, np, buf);
+ return EOPNOTSUPP;
+}
+
+
+/* Locked node NP 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 *np,
+ int flags, int newnode)
+{
+ error_t err = 0;
+
+ if (flags & O_READ)
+ err = fshelp_access (&np->nn_stat, S_IREAD, user);
+ if (!err && (flags & O_WRITE))
+ err = fshelp_access (&np->nn_stat, S_IWRITE, user);
+ if (!err && (flags & O_EXEC))
+ err = fshelp_access (&np->nn_stat, S_IEXEC, user);
+ return err;
+
+}
+
+
+/* This function will never be called. It is only used when a node is
+ a symlink or by io_read, which is overridden. */
+error_t
+netfs_attempt_read (struct iouser *cred, struct node *np,
+ loff_t offset, size_t *len, void *data)
+{
+ return EOPNOTSUPP;
+}
+
+
+/* This function will never be called. It is only called from
+ io_write, which is overridden. */
+error_t
+netfs_attempt_write (struct iouser *cred, struct node *np,
+ loff_t offset, size_t *len, void *data)
+{
+ return EOPNOTSUPP;
+}
+
+
+error_t
+netfs_S_io_read (struct protid *user,
+ char **data,
+ mach_msg_type_number_t *datalen,
+ off_t offset,
+ mach_msg_type_number_t amount)
+{
+ struct node *np;
+
+ if (!user)
+ return EOPNOTSUPP;
+ np = user->po->np;
+
+ if (np->nn->node && np->nn->node->read)
+ return np->nn->node->read (user, data, datalen, offset, amount);
+ return EOPNOTSUPP;
+}
+
+
+error_t
+netfs_S_io_write (struct protid *user,
+ char *data,
+ mach_msg_type_number_t datalen,
+ off_t offset,
+ mach_msg_type_number_t *amount)
+{
+ struct node *np;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ np = user->po->np;
+ if (np->nn->node && np->nn->node->write)
+ return np->nn->node->write (user, data, datalen, offset, amount);
+ return EOPNOTSUPP;
+}
+
+
+/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and
+ O_EXEC) in *TYPES for locked file NP and user CRED. */
+error_t
+netfs_report_access (struct iouser *cred, struct node *np,
+ int *types)
+{
+ *types = 0;
+ if (fshelp_access (&np->nn_stat, S_IREAD, cred) == 0)
+ *types |= O_READ;
+ if (fshelp_access (&np->nn_stat, S_IWRITE, cred) == 0)
+ *types |= O_WRITE;
+ if (fshelp_access (&np->nn_stat, S_IEXEC, cred) == 0)
+ *types |= O_EXEC;
+ return 0;
+
+}
+
+/* Node NP has no more references; free all its associated storage. */
+void netfs_node_norefs (struct node *np)
+
+{
+ if (np->nn->node)
+ {
+ if (np->nn->node->close)
+ np->nn->node->close ();
+ np->nn->node->node = 0;
+ }
+
+ if (np->nn->symlink_path)
+ free (np->nn->symlink_path);
+
+ spin_unlock (&netfs_node_refcnt_lock);
+ free (np->nn);
+ free (np);
+}
+
+
+/* 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))
+
+/* Fill the array *DATA of size BUFSIZE with up to NENTRIES dirents
+ from DIR (which is locked) starting with entry ENTRY for user CRED.
+ The number of entries in the array is stored in *AMT and the number
+ of bytes in *DATACNT. If the supplied buffer is not large enough
+ to hold the data, it should be grown. */
+error_t
+netfs_get_dirents (struct iouser *cred, struct node *dir,
+ int first_entry, int num_entries, char **data,
+ mach_msg_type_number_t *data_len,
+ vm_size_t max_data_len, int *data_entries)
+{
+ error_t err;
+ int count = 0;
+ size_t size = 0; /* Total size of our return block. */
+ consnode_t cn = node_list;
+ consnode_t first_node;
+
+
+ /* Add the length of a directory entry for NAME to SIZE and return true,
+ unless it would overflow MAX_DATA_LEN or NUM_ENTRIES, in which case
+ return false. */
+ int bump_size (const char *name)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ size_t new_size = size + DIRENT_LEN (strlen (name));
+ if (max_data_len > 0 && new_size > max_data_len)
+ return 0;
+ size = new_size;
+ count++;
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ if (dir != netfs_root_node)
+ return ENOTDIR;
+
+ for (first_node = node_list, count = 2;
+ first_node && first_entry > count;
+ first_node = first_node->next);
+ count++;
+
+ count = 0;
+
+ /* Make space for the `.' and `..' entries. */
+ if (first_entry == 0)
+ bump_size (".");
+ if (first_entry <= 1)
+ bump_size ("..");
+
+ for (cn = first_node; cn; cn = cn->next)
+ bump_size (cn->name);
+
+
+ /* Allocate it. */
+ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = ((void *) *data == (void *) -1) ? errno : 0;
+
+ if (! err)
+ /* Copy out the result. */
+ {
+ char *p = *data;
+
+ int add_dir_entry (const char *name, ino_t fileno, int type)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (name);
+ size_t sz = DIRENT_LEN (name_len);
+
+ if (sz > size)
+ return 0;
+ else
+ size -= sz;
+
+ hdr.d_fileno = fileno;
+ hdr.d_reclen = sz;
+ hdr.d_type = type;
+ hdr.d_namlen = name_len;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, name);
+ p += sz;
+
+ count++;
+
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ *data_len = size;
+ *data_entries = count;
+
+ count = 0;
+
+ /* Add `.' and `..' entries. */
+ if (first_entry == 0)
+ add_dir_entry (".", 2, DT_DIR);
+ if (first_entry <= 1)
+ add_dir_entry ("..", 2, DT_DIR);
+
+ /* Fill in the real directory entries. */
+ for (cn = first_node; cn; cn = cn->next)
+ if (!add_dir_entry (cn->name, cn->id, cn->readlink ? DT_LNK : DT_CHR))
+ break;
+ }
+
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, console_maptime);
+ return err;
+}
+
+
+
+static any_t
+console_client_translator (any_t unused)
+{
+ error_t err;
+
+ do
+ {
+ ports_manage_port_operations_multithread (netfs_port_bucket,
+ console_demuxer,
+ 1000 * 60 * 2,
+ 1000 * 60 * 10,
+ 0);
+ err = netfs_shutdown (0);
+ }
+ while (err);
+ return 0;
+}
+
+
+/* Create a node with the name NAME and return it in *CN. */
+error_t
+console_create_consnode (const char *name, consnode_t *cn)
+{
+ *cn = malloc (sizeof (struct consnode));
+ if (!*cn)
+ return ENOMEM;
+
+ (*cn)->name = strdup (name);
+ if (!(*cn)->name)
+ {
+ free (cn);
+ return ENOMEM;
+ }
+
+ (*cn)->readlink = NULL;
+ (*cn)->mksymlink = NULL;
+
+ return 0;
+}
+
+
+/* Destroy the node CN. */
+void
+console_destroy_consnode (consnode_t cn)
+{
+ if (!cn)
+ return;
+ free (cn->name);
+ free (cn);
+}
+
+
+/* Register the node CN with the translator. */
+void
+console_register_consnode (consnode_t cn)
+{
+ cn->node = 0;
+ cn->next = node_list;
+ node_list = cn;
+}
+
+
+/* Unregister the node CN from the translator. */
+void
+console_unregister_consnode (consnode_t cn)
+{
+ if (!cn)
+ return;
+
+ if (node_list == cn)
+ node_list = cn->next;
+ else
+ {
+ consnode_t prev = node_list;
+
+ for (prev = node_list; prev->next != cn; prev = prev->next)
+ ;
+
+ prev->next = cn->next;
+ }
+}
+
+
+error_t
+console_setup_node (char *path)
+{
+ mach_port_t underlying;
+ mach_port_t bootstrap;
+ error_t err;
+ struct stat ul_stat;
+ file_t node;
+ struct port_info *newpi;
+ mach_port_t right;
+
+ node = file_name_lookup (path, O_CREAT|O_NOTRANS, 0664);
+ if (node == MACH_PORT_NULL)
+ return errno;
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ netfs_init ();
+
+ /* Create the root node (some attributes initialized below). */
+ netfs_root_node = netfs_make_node (0);
+ if (! netfs_root_node)
+ error (1, ENOMEM, "Cannot create root node");
+
+ err = maptime_map (0, 0, &console_maptime);
+ if (err)
+ error (1, err, "Cannot map time");
+
+ err = ports_create_port (netfs_control_class, netfs_port_bucket, sizeof (struct port_info), &newpi);
+ right = ports_get_send_right (newpi);
+ err = file_set_translator (node, 0, FS_TRANS_EXCL | FS_TRANS_SET, 0, 0, 0,
+ right, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
+ underlying = node;
+
+ err = io_stat (node, &ul_stat);
+ if (err)
+ error (1, err, "Cannot stat underlying node");
+
+ netfs_root_node->nn_stat.st_ino = 2;
+ netfs_root_node->nn_stat.st_uid = ul_stat.st_uid;
+ netfs_root_node->nn_stat.st_gid = ul_stat.st_gid;
+ netfs_root_node->nn_stat.st_author = ul_stat.st_author;
+ netfs_root_node->nn_stat.st_mode = S_IFDIR | (ul_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+ netfs_root_node->nn_stat.st_fsid = getpid ();
+ netfs_root_node->nn_stat.st_nlink = 1;
+ netfs_root_node->nn_stat.st_size = 0;
+ netfs_root_node->nn_stat.st_blocks = 0;
+ netfs_root_node->nn_stat.st_fstype = FSTYPE_MISC;
+ netfs_root_node->nn_translated = 0;
+
+ /* If the underlying node isn't a directory, propagate read permission to
+ execute permission since we need that for lookups. */
+ if (! S_ISDIR (ul_stat.st_mode))
+ {
+ if (ul_stat.st_mode & S_IRUSR)
+ netfs_root_node->nn_stat.st_mode |= S_IXUSR;
+ if (ul_stat.st_mode & S_IRGRP)
+ netfs_root_node->nn_stat.st_mode |= S_IXGRP;
+ if (ul_stat.st_mode & S_IROTH)
+ netfs_root_node->nn_stat.st_mode |= S_IXOTH;
+ }
+
+ fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ console_maptime);
+
+ cthread_detach (cthread_fork (console_client_translator, NULL));
+
+ return 0;
+}
diff --git a/console-client/trans.h b/console-client/trans.h
new file mode 100644
index 00000000..f781e31f
--- /dev/null
+++ b/console-client/trans.h
@@ -0,0 +1,81 @@
+/* trans.h -- Control a translator node for the repeaters.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Written by Marco Gerards.
+
+ 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 */
+
+#include <hurd/netfs.h>
+
+struct consnode
+{
+ /* The filename of the node. */
+ char *name;
+
+ /* The id of the node. */
+ int id;
+
+ /* Cached if the node is already opened. */
+ struct node *node;
+
+ /* Read data from a node. This is exactly the same as io_read
+ does. */
+ error_t (*read) (struct protid *user, char **data,
+ mach_msg_type_number_t *datalen, off_t offset,
+ mach_msg_type_number_t amount);
+
+ /* Read data to a node. This is exactly the same as io_write
+ does. */
+ error_t (*write) (struct protid *user, char *data,
+ mach_msg_type_number_t datalen, off_t offset,
+ mach_msg_type_number_t *amount);
+
+ /* This is exactly the same as io_select does. */
+ error_t (*select) (struct protid *user, mach_port_t reply,
+ mach_msg_type_name_t replytype, int *type);
+
+ /* Called when the node is opened. */
+ void (*open) (void);
+
+ /* Called when the node is closed. */
+ void (*close) (void);
+
+ /* The demuxer used for this node. */
+ int (*demuxer) (mach_msg_header_t *inp, mach_msg_header_t *outp);
+
+ /* Called when the symlink is read */
+ error_t (*readlink) (struct iouser *user, struct node *np, char *buf);
+
+ /* Called when the symlink is written */
+ error_t (*mksymlink) (struct iouser *cred, struct node *np, char *name);
+
+ struct consnode *next;
+};
+
+typedef struct consnode *consnode_t;
+
+/* Register the node CN with the translator. */
+void console_register_consnode (consnode_t cn);
+
+/* Unregister the node CN from the translator. */
+void console_unregister_consnode (consnode_t cn);
+
+/* Create a node with the name NAME and return it in *CN. */
+error_t console_create_consnode (const char *name, consnode_t *cn);
+
+/* Destroy the node CN. */
+void console_destroy_consnode (consnode_t cn);
+
+/* Setup the translator for console client nodes on PATH. */
+error_t console_setup_node (char *path);
diff --git a/console-client/unicode.h b/console-client/unicode.h
new file mode 100644
index 00000000..386628c9
--- /dev/null
+++ b/console-client/unicode.h
@@ -0,0 +1,350 @@
+/* unicode.h - A list of useful Unicode characters.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _UNICODE_H_
+#define _UNICODE_H_
+
+#define UNICODE_NO_BREAK_SPACE ((wchar_t) 0x00a0)
+#define UNICODE_INVERTED_EXCLAMATION_MARK ((wchar_t) 0x00a1)
+#define UNICODE_CENT_SIGN ((wchar_t) 0x00a2)
+#define UNICODE_POUND_SIGN ((wchar_t) 0x00a3)
+#define UNICODE_CURRENCY_SIGN ((wchar_t) 0x00a4)
+#define UNICODE_YEN_SIGN ((wchar_t) 0x00a5)
+#define UNICODE_BROKEN_BAR ((wchar_t) 0x00a6)
+#define UNICODE_BROKEN_VERTICAL_BAR UNICODE_BROKEN_BAR
+#define UNICODE_SECTION_SIGN ((wchar_t) 0x00a7)
+#define UNICODE_DIARESIS ((wchar_t) 0x00a8)
+#define UNICODE_COPYRIGHT_SIGN ((wchar_t) 0x00a9)
+#define UNICODE_FEMININE_ORDINAL_INDICATOR ((wchar_t) 0x00aa)
+#define UNICODE_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK ((wchar_t) 0x00ab)
+#define UNICODE_LEFT_POINTING_GUILLEMET \
+ UNICODE_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK
+#define UNICODE_NOT_SIGN ((wchar_t) 0x00ac)
+#define UNICODE_SOFT_HYPHEN ((wchar_t) 0x00ad)
+#define UNICODE_REGISTERED_SIGN ((wchar_t) 0x00ae)
+#define UNICODE_REGISTERED_TRADE_MARK_SIGN UNICODE_REGISTERED_SIGN
+#define UNICODE_MACRON ((wchar_t) 0x00af)
+#define UNICODE_DEGREE_SIGN ((wchar_t) 0x00b0)
+#define UNICODE_PLUS_MINUS_SIGN ((wchar_t) 0x00b1)
+#define UNICODE_SUPERSCRIPT_TWO ((wchar_t) 0x00b2)
+#define UNICODE_SUPERSCRIPT_THREE ((wchar_t) 0x00b3)
+#define UNICODE_ACUTE_ACCENT ((wchar_t) 0x00b4)
+#define UNICODE_MICRO_SIGN ((wchar_t) 0x00b5)
+#define UNICODE_PILCROW_SIGN ((wchar_t) 0x00b6)
+#define UNICODE_PARAGRAPH_SIGN UNICODE_PILCROW_SIGN
+#define UNICODE_MIDDLE_DOT ((wchar_t) 0x00b7)
+#define UNICODE_CEDILLA ((wchar_t) 0x00b8)
+#define UNICODE_SUPERSCRIPT_ONE ((wchar_t) 0x00b9)
+#define UNICODE_MASCULINE_ORDINAL_INDICATOR ((wchar_t) 0x00ba)
+#define UNICODE_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK ((wchar_t) 0x00bb)
+#define UNICODE_RIGHT_POINTING_GUILLEMET \
+ UNICODE_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK
+#define UNICODE_VULGAR_FRACTION_ONE_QUARTER ((wchar_t) 0x00bc)
+#define UNICODE_VULGAR_FRACTION_ONE_HALF ((wchar_t) 0x00bd)
+#define UNICODE_VULGAR_FRACTION_THREE_QUARTERS ((wchar_t) 0x00be)
+#define UNICODE_INVERTED_QUESTION_MARK ((wchar_t) 0x00bf)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_GRAVE ((wchar_t) 0x00c0)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_ACUTE ((wchar_t) 0x00c1)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX ((wchar_t) 0x00c2)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_TILDE ((wchar_t) 0x00c3)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_DIARESIS ((wchar_t) 0x00c4)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE ((wchar_t) 0x00c5)
+#define UNICODE_LATIN_CAPITAL_LETTER_AE ((wchar_t) 0x00c6)
+#define UNICODE_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA ((wchar_t) 0x00c7)
+#define UNICODE_LATIN_CAPITAL_LIGATURE_AE UNICODE_LATIN_CAPITAL_LETTER_AE
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_GRAVE ((wchar_t) 0x00c8)
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_ACUTE ((wchar_t) 0x00c9)
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX ((wchar_t) 0x00ca)
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_DIARESIS ((wchar_t) 0x00cb)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_GRAVE ((wchar_t) 0x00cc)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_ACUTE ((wchar_t) 0x00cd)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX ((wchar_t) 0x00ce)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_DIARESIS ((wchar_t) 0x00cf)
+#define UNICODE_LATIN_CAPITAL_LETTER_ETH ((wchar_t) 0x00d0)
+#define UNICODE_LATIN_CAPITAL_LETTER_N_WITH_TILDE ((wchar_t) 0x00d1)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_GRAVE ((wchar_t) 0x00d2)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_ACUTE ((wchar_t) 0x00d3)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX ((wchar_t) 0x00d4)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_TILDE ((wchar_t) 0x00d5)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_DIARESIS ((wchar_t) 0x00d6)
+#define UNICODE_MULTIPLICATION_SIGN ((wchar_t) 0x00d7)
+#define UNICODE_CAPITAL_LETTER_O_WITH_STROKE ((wchar_t) 0x00d8)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_GRAVE ((wchar_t) 0x00d9)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_ACUTE ((wchar_t) 0x00da)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX ((wchar_t) 0x00db)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_DIARESIS ((wchar_t) 0x00dc)
+#define UNICODE_LATIN_CAPITAL_LETTER_Y_WITH_ACUTE ((wchar_t) 0x00dd)
+#define UNICODE_LATIN_CAPITAL_LETTER_THORN ((wchar_t) 0x00de)
+#define UNICODE_LATIN_SMALL_LETTER_SHARP_S ((wchar_t) 0x00df)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_GRAVE ((wchar_t) 0x00e0)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_ACUTE ((wchar_t) 0x00e1)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX ((wchar_t) 0x00e2)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_DIARESIS ((wchar_t) 0x00e4)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE ((wchar_t) 0x00e5)
+#define UNICODE_LATIN_SMALL_LETTER_AE ((wchar_t) 0x00e6)
+#define UNICODE_LATIN_SMALL_LIGATURE_AE UNICODE_LATIN_SMALL_LETTER_AE
+#define UNICODE_LATIN_SMALL_LETTER_C_WITH_CEDILLA ((wchar_t) 0x00e7)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_GRAVE ((wchar_t) 0x00e8)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_ACUTE ((wchar_t) 0x00e9)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX ((wchar_t) 0x00ea)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_DIARESIS ((wchar_t) 0x00eb)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_GRAVE ((wchar_t) 0x00ec)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_ACUTE ((wchar_t) 0x00ed)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX ((wchar_t) 0x00ee)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_DIARESIS ((wchar_t) 0x00ef)
+#define UNICODE_LATIN_SMALL_LETTER_ETH ((wchar_t) 0x00f0)
+#define UNICODE_LATIN_SMALL_LETTER_N_WITH_TILDE ((wchar_t) 0x00f1)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_GRAVE ((wchar_t) 0x00f2)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_ACUTE ((wchar_t) 0x00f3)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX ((wchar_t) 0x00f4)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_DIARESIS ((wchar_t) 0x00f6)
+#define UNICODE_DIVISION_SIGN ((wchar_t) 0x00f7)
+#define UNICODE_SMALL_LETTER_O_WITH_STROKE ((wchar_t) 0x00f8)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_GRAVE ((wchar_t) 0x00f9)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_ACUTE ((wchar_t) 0x00fa)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX ((wchar_t) 0x00fb)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_DIARESIS ((wchar_t) 0x00fc)
+#define UNICODE_LATIN_SMALL_LETTER_Y_WITH_ACUTE ((wchar_t) 0x00fd)
+#define UNICODE_LATIN_SMALL_LETTER_THORN ((wchar_t) 0x00fe)
+#define UNICODE_LATIN_SMALL_LETTER_Y_WITH_DIARESIS ((wchar_t) 0x00ff)
+
+#define UNICODE_LATIN_SMALL_LETTER_F_WITH_HOOK ((wchar_t) 0x0192)
+#define UNICODE_LATIN_SMALL_LETTER_SCRIPT_F \
+ UNICODE_LATIN_SMALL_LETTER_F_WITH_HOOK
+#define UNICODE_GREEK_CAPITAL_LETTER_GAMMA ((wchar_t) 0x0393)
+#define UNICODE_GREEK_CAPITAL_LETTER_OMICRON ((wchar_t) 0x039f)
+#define UNICODE_GREEK_CAPITAL_LETTER_SIGMA ((wchar_t) 0x03a3)
+#define UNICODE_GREEK_CAPITAL_LETTER_PHI ((wchar_t) 0x03a6)
+#define UNICODE_GREEK_CAPITAL_LETTER_OMEGA ((wchar_t) 0x03a9)
+#define UNICODE_GREEK_SMALL_LETTER_ALPHA ((wchar_t) 0x03b1)
+#define UNICODE_GREEK_SMALL_LETTER_BETA ((wchar_t) 0x03b2)
+#define UNICODE_GREEK_SMALL_LETTER_DELTA ((wchar_t) 0x03b4)
+#define UNICODE_GREEK_SMALL_LETTER_EPSILON ((wchar_t) 0x03b5)
+#define UNICODE_GREEK_SMALL_LETTER_MU ((wchar_t) 0x03bc)
+#define UNICODE_GREEK_SMALL_LETTER_PI ((wchar_t) 0x03c0)
+#define UNICODE_GREEK_SMALL_LETTER_SIGMA ((wchar_t) 0x03c3)
+#define UNICODE_GREEK_SMALL_LETTER_TAU ((wchar_t) 0x03c4)
+#define UNICODE_GREEK_SMALL_LETTER_PHI ((wchar_t) 0x03c6)
+
+#define UNICODE_BULLET ((wchar_t) 0x2022)
+#define UNICODE_DOUBLE_EXCLAMATION_MARK ((wchar_t) 0x203c)
+#define UNICODE_SUPERSCRIPT_LATIN_SMALL_LETTER ((wchar_t) 0x207f)
+#define UNICODE_PESETA_SIGN ((wchar_t) 0x20a7)
+
+#define UNICODE_LEFTWARDS_ARROW ((wchar_t) 0x2190)
+#define UNICODE_UPWARDS_ARROW ((wchar_t) 0x2191)
+#define UNICODE_RIGHTWARDS_ARROW ((wchar_t) 0x2192)
+#define UNICODE_DOWNWARDS_ARROW ((wchar_t) 0x2193)
+#define UNICODE_LEFT_RIGHT_ARROW ((wchar_t) 0x2194)
+#define UNICODE_UP_DOWN_ARROW ((wchar_t) 0x2195)
+#define UNICODE_UP_DOWN_ARROW_WITH_BASE ((wchar_t) 0x21a8)
+
+#define UNICODE_BULLET_OPERATOR ((wchar_t) 0x2219)
+#define UNICODE_SQUARE_ROOT ((wchar_t) 0x221a)
+#define UNICODE_INFINITY ((wchar_t) 0x221e)
+#define UNICODE_RIGHT_ANGLE ((wchar_t) 0x221f)
+#define UNICODE_INTERSECTION ((wchar_t) 0x2229)
+#define UNICODE_ALMOST_EQUAL_TO ((wchar_t) 0x2248)
+#define UNICODE_NOT_EQUAL_TO ((wchar_t) 0x2260)
+#define UNICODE_IDENTICAL_TO ((wchar_t) 0x2261)
+#define UNICODE_LESS_THAN_OR_EQUAL_TO ((wchar_t) 0x2264)
+#define UNICODE_GREATER_THAN_OR_EQUAL_TO ((wchar_t) 0x2265)
+
+#define UNICODE_HOUSE ((wchar_t) 0x2302)
+#define UNICODE_REVERSED_NOT_SIGN ((wchar_t) 0x2310)
+#define UNICODE_TOP_HALF_INTEGRAL ((wchar_t) 0x2320)
+#define UNICODE_BOTTOM_HALF_INTEGRAL ((wchar_t) 0x2321)
+
+#define UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL ((wchar_t) 0x2500)
+#define UNICODE_BOX_DRAWINGS_HEAVY_HORIZONTAL ((wchar_t) 0x2501)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL ((wchar_t) 0x2502)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT ((wchar_t) 0x250c)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_HEAVY ((wchar_t) 0x250d)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_LIGHT ((wchar_t) 0x250e)
+#define UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_RIGHT ((wchar_t) 0x250f)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT ((wchar_t) 0x2510)
+#define UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT ((wchar_t) 0x2514)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_HEAVY ((wchar_t) 0x2515)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_LIGHT ((wchar_t) 0x2516)
+#define UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_RIGHT ((wchar_t) 0x2517)
+#define UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_LEFT ((wchar_t) 0x2518)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT ((wchar_t) 0x251c)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_RIGHT_HEAVY ((wchar_t) 0x251d)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_UP_LIGHT ((wchar_t) 0x251e)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_UP_LIGHT ((wchar_t) 0x251f)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_RIGHT_LIGHT ((wchar_t) 0x2520)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_UP_HEAVY ((wchar_t) 0x2521)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_DOWN_HEAVY ((wchar_t) 0x2522)
+#define UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_RIGHT ((wchar_t) 0x2523)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT ((wchar_t) 0x2524)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL ((wchar_t) 0x252c)
+#define UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_DOWN_LIGHT ((wchar_t) 0x252d)
+#define UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_DOWN_LIGHT ((wchar_t) 0x252e)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_HORIZONTAL_HEAVY ((wchar_t) 0x252f)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_HORIZONTAL_LIGHT ((wchar_t) 0x2530)
+#define UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_DOWN_HEAVY ((wchar_t) 0x2531)
+#define UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_DOWN_HEAVY ((wchar_t) 0x2532)
+#define UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_HORIZONTAL ((wchar_t) 0x2533)
+#define UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL ((wchar_t) 0x2534)
+#define UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_UP_LIGHT ((wchar_t) 0x2535)
+#define UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_UP_LIGHT ((wchar_t) 0x2536)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_HORIZONTAL_HEAVY ((wchar_t) 0x2537)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_HORIZONTAL_LIGHT ((wchar_t) 0x2538)
+#define UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_UP_HEAVY ((wchar_t) 0x2539)
+#define UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_UP_HEAVY ((wchar_t) 0x253a)
+#define UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_HORIZONTAL ((wchar_t) 0x253b)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL ((wchar_t) 0x253c)
+#define UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_VERTICAL_LIGHT \
+ ((wchar_t) 0x253d)
+#define UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_VERTICAL_LIGHT \
+ ((wchar_t) 0x253e)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_HORIZONTAL_HEAVY \
+ ((wchar_t) 0x253f)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_DOWN_HORIZONTAL_LIGHT \
+ ((wchar_t) 0x2540)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_UP_HORIZONTAL_LIGHT \
+ ((wchar_t) 0x2541)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_HORIZONTAL_LIGHT \
+ ((wchar_t) 0x2542)
+#define UNICODE_BOX_DRAWINGS_LEFT_UP_HEAVY_AND_RIGHT_DOWN_LIGHT \
+ ((wchar_t) 0x2543)
+#define UNICODE_BOX_DRAWINGS_RIGHT_UP_HEAVY_AND_LEFT_DOWN_LIGHT \
+ ((wchar_t) 0x2544)
+#define UNICODE_BOX_DRAWINGS_LEFT_DOWN_HEAVY_AND_RIGHT_UP_LIGHT \
+ ((wchar_t) 0x2545)
+#define UNICODE_BOX_DRAWINGS_RIGHT_DOWN_HEAVY_AND_LEFT_UP_LIGHT \
+ ((wchar_t) 0x2546)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_UP_HORIZONTAL_HEAVY \
+ ((wchar_t) 0x2547)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_DOWN_HORIZONTAL_HEAVY \
+ ((wchar_t) 0x2548)
+#define UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_VERTICAL_HEAVY \
+ ((wchar_t) 0x2549)
+#define UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_VERTICAL_HEAVY \
+ ((wchar_t) 0x254a)
+#define UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_HORIZONTAL \
+ ((wchar_t) 0x254b)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL ((wchar_t) 0x2550)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL ((wchar_t) 0x2551)
+#define UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE ((wchar_t) 0x2552)
+#define UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE ((wchar_t) 0x2553)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT ((wchar_t) 0x2554)
+#define UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE ((wchar_t) 0x2555)
+#define UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE ((wchar_t) 0x2556)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT ((wchar_t) 0x2557)
+#define UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE ((wchar_t) 0x2558)
+#define UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE ((wchar_t) 0x2559)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT ((wchar_t) 0x255a)
+#define UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE ((wchar_t) 0x255b)
+#define UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE ((wchar_t) 0x255c)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_LEFT ((wchar_t) 0x255d)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE \
+ ((wchar_t) 0x255e)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE \
+ ((wchar_t) 0x255f)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT ((wchar_t) 0x2560)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE ((wchar_t) 0x2561)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE ((wchar_t) 0x2562)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT ((wchar_t) 0x2563)
+#define UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE \
+ ((wchar_t) 0x2564)
+#define UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE \
+ ((wchar_t) 0x2565)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL ((wchar_t) 0x2566)
+#define UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE ((wchar_t) 0x2567)
+#define UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE ((wchar_t) 0x2568)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL ((wchar_t) 0x2569)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE \
+ ((wchar_t) 0x256a)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE \
+ ((wchar_t) 0x256b)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL ((wchar_t) 0x256c)
+#define UNICODE_BOX_DRAWINGS_LIGHT_ARC_DOWN_AND_RIGHT ((wchar_t) 0x256d)
+#define UNICODE_BOX_DRAWINGS_LIGHT_ARC_UP_AND_RIGHT ((wchar_t) 0x2570)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_RIGHT_TO_LOWER_LEFT \
+ ((wchar_t) 0x2571)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_LEFT_TO_LOWER_RIGHT \
+ ((wchar_t) 0x2572)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_CROSS ((wchar_t) 0x2573)
+#define UNICODE_BOX_DRAWINGS_LIGHT_RIGHT ((wchar_t) 0x2576)
+#define UNICODE_BOX_DRAWINGS_HEAVY_RIGHT ((wchar_t) 0x257a)
+#define UNICODE_BOX_DRAWINGS_LIGHT_LEFT_AND_HEAVY_RIGHT ((wchar_t) 0x257c)
+#define UNICODE_BOX_DRAWINGS_HEAVY_LEFT_AND_LIGHT_RIGHT ((wchar_t) 0x257e)
+
+#define UNICODE_UPPER_HALF_BLOCK ((wchar_t) 0x2580)
+#define UNICODE_LOWER_ONE_EIGHTH_BLOCK ((wchar_t) 0x2581)
+#define UNICODE_LOWER_ONE_QUARTER_BLOCK ((wchar_t) 0x2582)
+#define UNICODE_LOWER_THREE_EIGHTHS_BLOCK ((wchar_t) 0x2583)
+#define UNICODE_LOWER_HALF_BLOCK ((wchar_t) 0x2584)
+#define UNICODE_LOWER_FIVE_EIGHTHS_BLOCK ((wchar_t) 0x2585)
+#define UNICODE_LOWER_THREE_QUARTERS_BLOCK ((wchar_t) 0x2586)
+#define UNICODE_LOWER_SEVEN_EIGHTHS_BLOCK ((wchar_t) 0x2587)
+#define UNICODE_FULL_BLOCK ((wchar_t) 0x2588)
+#define UNICODE_LEFT_HALF_BLOCK ((wchar_t) 0x258c)
+#define UNICODE_RIGHT_HALF_BLOCK ((wchar_t) 0x2590)
+#define UNICODE_LIGHT_SHADE ((wchar_t) 0x2591)
+#define UNICODE_MEDIUM_SHADE ((wchar_t) 0x2592)
+#define UNICODE_DARK_SHADE ((wchar_t) 0x2593)
+#define UNICODE_UPPER_ONE_EIGHTH_BLOCK ((wchar_t) 0x2594)
+#define UNICODE_RIGHT_ONE_EIGHTH_BLOCK ((wchar_t) 0x2595)
+#define UNICODE_QUADRANT_LOWER_LEFT ((wchar_t) 0x2596)
+#define UNICODE_QUADRANT_LOWER_RIGHT ((wchar_t) 0x2597)
+#define UNICODE_QUADRANT_UPPER_LEFT ((wchar_t) 0x2598)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_LEFT_AND_LOWER_RIGHT \
+ ((wchar_t) 0x2599)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_RIGHT ((wchar_t) 0x259a)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_LEFT \
+ ((wchar_t) 0x259b)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_RIGHT \
+ ((wchar_t) 0x259c)
+#define UNICODE_QUADRANT_UPPER_RIGHT ((wchar_t) 0x259d)
+#define UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT ((wchar_t) 0x259e)
+#define UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT_AND_LOWER_RIGHT \
+ ((wchar_t) 0x259f)
+
+#define UNICODE_BLACK_SQUARE ((wchar_t) 0x25a0)
+#define UNICODE_BLACK_RECTANGLE ((wchar_t) 0x25ac)
+#define UNICODE_BLACK_UP_POINTING_TRIANGLE ((wchar_t) 0x25b2)
+#define UNICODE_BLACK_RIGHT_POINTING_TRIANGLE ((wchar_t) 0x25b6)
+#define UNICODE_BLACK_DOWN_POINTING_TRIANGLE ((wchar_t) 0x25bc)
+#define UNICODE_BLACK_LEFT_POINTING_TRIANGLE ((wchar_t) 0x25c0)
+#define UNICODE_WHITE_CIRCLE ((wchar_t) 0x25cb)
+#define UNICODE_INVERSE_BULLET ((wchar_t) 0x25d8)
+#define UNICODE_INVERSE_WHITE_CIRCLE ((wchar_t) 0x25d9)
+
+#define UNICODE_WHITE_SMILING_FACE ((wchar_t) 0x263a)
+#define UNICODE_BLACK_SMILING_FACE ((wchar_t) 0x263b)
+#define UNICODE_WHITE_SUN_WITH_RAYS ((wchar_t) 0x263c)
+#define UNICODE_FEMALE_SIGN ((wchar_t) 0x2640)
+#define UNICODE_MALE_SIGN ((wchar_t) 0x2642)
+#define UNICODE_BLACK_SPADE_SUIT ((wchar_t) 0x2660)
+#define UNICODE_BLACK_CLUB_SUIT ((wchar_t) 0x2663)
+#define UNICODE_BLACK_HEART_SUIT ((wchar_t) 0x2665)
+#define UNICODE_BLACK_DIAMOND_SUIT ((wchar_t) 0x2666)
+#define UNICODE_EIGHTH_NOTE ((wchar_t) 0x266a)
+#define UNICODE_BEAMED_EIGHTH_NOTES ((wchar_t) 0x266b)
+
+#define UNICODE_PRIVATE_USE_AREA ((wchar_t) 0xe000)
+#define UNICODE_PRIVATE_USE_AREA_LAST ((wchar_t) 0xf8ff)
+
+#define UNICODE_REPLACEMENT_CHARACTER ((wchar_t) 0xfffd)
+
+#endif /* _UNICODE_H_ */
+
diff --git a/console-client/vga-dynacolor.c b/console-client/vga-dynacolor.c
new file mode 100644
index 00000000..9289e1eb
--- /dev/null
+++ b/console-client/vga-dynacolor.c
@@ -0,0 +1,322 @@
+/* vga-dynacolor.c - Dynamic color handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+
+#include <hurd/console.h>
+
+#include "vga-hw.h"
+#include "vga-support.h"
+#include "vga-dynacolor.h"
+
+
+dynacolor_t dynacolor_init_8 = DYNACOLOR_INIT_8;
+dynacolor_t dynacolor_init_16 = DYNACOLOR_INIT_16;
+
+static const unsigned char std_palette[16][DYNACOLOR_COMPONENTS] =
+ {
+ { 0, 0, 0 }, /* Black. */
+ { 42, 0, 0 }, /* Red. */
+ { 0, 42, 0 }, /* Green. */
+ { 42, 21, 0 }, /* Brown. */
+ { 0, 0, 42 }, /* Blue. */
+ { 42, 0, 42 }, /* Magenta. */
+ { 0, 42, 42 }, /* Cyan. */
+ { 42, 42, 42 }, /* White. */
+ { 21, 21, 21 }, /* Bright Black. */
+ { 63, 21, 21 }, /* Bright Red. */
+ { 21, 63, 21 }, /* Bright Green. */
+ { 63, 63, 21 }, /* Bright Yellow. */
+ { 21, 21, 63 }, /* Bright Blue. */
+ { 63, 21, 63 }, /* Bright Magenta. */
+ { 21, 63, 63 }, /* Bright Cyan. */
+ { 63, 63, 63 } /* Bright White. */
+ };
+
+/* The currently active (visible) dynafont. */
+static dynacolor_t *active_dynacolor;
+
+static unsigned char saved_palette[16][DYNACOLOR_COMPONENTS];
+
+/* We initialize this to the desired mapping for
+ vga_exchange_palette_attributes. */
+/* Palette index 0 is left as it is, for the border color. */
+static unsigned char saved_palette_attr[16] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+
+
+/* Initialize the dynacolor subsystem. */
+void
+dynacolor_init (void)
+{
+ /* Palette index 0 is left as it is, as it is also used for the
+ border color by default. */
+ vga_exchange_palette_attributes (0, saved_palette_attr, 16);
+ vga_read_palette (0, saved_palette[0], 16);
+
+ vga_write_palette (0, std_palette[0], 16);
+}
+
+
+/* Restore the original palette. */
+void
+dynacolor_fini (void)
+{
+ vga_write_palette (0, saved_palette[0], 16);
+ vga_exchange_palette_attributes (0, saved_palette_attr, 16);
+}
+
+
+/* Activate the dynamic color palette DC. */
+void
+dynacolor_activate (dynacolor_t *dc)
+{
+ if (dc == active_dynacolor)
+ return;
+
+ if (dc->ref[0] < 0 && (!active_dynacolor || active_dynacolor->ref[0] >= 0))
+ {
+ /* Switching from dynamic to static palette. */
+ vga_write_palette (0, std_palette[0], 16);
+ }
+ else if (dc->ref[0] >= 0
+ && (!active_dynacolor || active_dynacolor->ref[0] < 0))
+ {
+ /* Switching from static to dynamic palette. */
+ int i;
+ for (i = 0; i < 16; i++)
+ if (dc->col[i] >= 0)
+ {
+ vga_write_palette (dc->col[i], std_palette[i], 1);
+ vga_write_palette (8 + dc->col[i], std_palette[i], 1);
+ }
+ }
+ active_dynacolor = dc;
+}
+
+
+/* Try to allocate a slot for the color COL in the dynamic color
+ palette DC. Return the allocated slot number or -1 if no slot is
+ available. */
+signed char
+dynacolor_allocate (dynacolor_t *dc, unsigned char col)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (dc->ref[i] == 0)
+ {
+ /* We want to reuse slot i. Clear the old user. */
+ int j;
+
+ for (j = 0; j < 16; j++)
+ if (dc->col[j] == i)
+ {
+ dc->col[j] = -1;
+ break;
+ }
+
+ dc->ref[i] = 1;
+ dc->col[col] = i;
+ if (active_dynacolor == dc)
+ {
+ vga_write_palette (0 + i, std_palette[col], 1);
+ vga_write_palette (8 + i, std_palette[col], 1);
+ }
+ return i;
+ }
+ return -1;
+}
+
+
+/* This is a convenience function that looks up a replacement color
+ pair if the original colors are not available. The function always
+ succeeds. DC is the dynacolor to use for allocation, FGCOL and
+ BGCOL are the desired colors, and R_FGCOL and R_BGCOL are the
+ resulting colors. The function assumes that the caller already
+ tried to look up the desired colors before trying to replace them,
+ and that the result of the lookup is contained in R_FGCOL and
+ R_BGCOL.
+
+ Example:
+
+ res_bgcol = dynacolor_lookup (&dc, bgcol);
+ res_fgcol = dynacolor_lookup (&dc, fgcol);
+ if (res_bgcol == -1 || res_fgcol == -1)
+ dynacolor_replace_colors (&dc, fgcol, bgcol, &res_fgcol, &res_bgcol);
+
+ After the above code, res_fgcol and res_bgcol contain valid color
+ values. */
+void
+dynacolor_replace_colors (dynacolor_t *dc,
+ signed char fgcol, signed char bgcol,
+ signed char *r_fgcol, signed char *r_bgcol)
+{
+ /* Replacement colors. As we have 8 colors in our palette, and
+ one was already tried, we only need to try out 8 possible
+ replacements. Only the first seven can fail. But one is
+ possibly taken by the fore-/background color, so we actually
+ have to try up to nine. XXX Maybe we should have a table
+ based on pairs, but that increases the number of cases a
+ lot. */
+ /* Note that no color must occur twice in one replacement list,
+ and that the color to be replaced must not occur either. */
+ static signed char pref[16][9] =
+ {
+ /* Replacements for CONS_COLOR_BLACK. */
+ { CONS_COLOR_BLACK | (1 << 3), CONS_COLOR_BLUE,
+ CONS_COLOR_YELLOW, CONS_COLOR_RED, CONS_COLOR_MAGENTA,
+ CONS_COLOR_GREEN, CONS_COLOR_CYAN, CONS_COLOR_WHITE,
+ CONS_COLOR_BLUE | (1 << 3) },
+ /* Replacements for CONS_COLOR_RED. */
+ { CONS_COLOR_RED | (1 << 3), CONS_COLOR_YELLOW,
+ CONS_COLOR_MAGENTA, CONS_COLOR_BLUE, CONS_COLOR_CYAN,
+ CONS_COLOR_GREEN, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_GREEN. */
+ { CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_YELLOW, CONS_COLOR_BLUE, CONS_COLOR_RED,
+ CONS_COLOR_MAGENTA, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_YELLOW. */
+ { CONS_COLOR_YELLOW | (1 << 3), CONS_COLOR_RED,
+ CONS_COLOR_GREEN, CONS_COLOR_MAGENTA, CONS_COLOR_BLUE,
+ CONS_COLOR_CYAN, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_BLUE. */
+ { CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_MAGENTA, CONS_COLOR_RED, CONS_COLOR_GREEN,
+ CONS_COLOR_YELLOW, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_MAGENTA. */
+ { CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_RED,
+ CONS_COLOR_BLUE, CONS_COLOR_YELLOW, CONS_COLOR_CYAN,
+ CONS_COLOR_BLUE, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_CYAN. */
+ { CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_BLUE,
+ CONS_COLOR_MAGENTA, CONS_COLOR_GREEN, CONS_COLOR_RED,
+ CONS_COLOR_YELLOW, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_WHITE. */
+ { CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_GREEN, CONS_COLOR_YELLOW, CONS_COLOR_MAGENTA,
+ CONS_COLOR_RED, CONS_COLOR_BLUE, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_BLACK | (1 << 3). */
+ { CONS_COLOR_BLACK, CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_YELLOW | (1 << 3), CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_WHITE | (1 << 3),
+ CONS_COLOR_WHITE },
+ /* Replacements for CONS_COLOR_RED | (1 << 3). */
+ { CONS_COLOR_RED, CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_GREEN | (1 << 3). */
+ { CONS_COLOR_GREEN, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_YELLOW | (1 << 3), CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_RED | (1 << 3), CONS_COLOR_MAGENTA | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_YELLOW | (1 << 3). */
+ { CONS_COLOR_YELLOW, CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_MAGENTA | (1 << 3),
+ CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_BLUE | (1 << 3). */
+ { CONS_COLOR_BLUE, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_MAGENTA | (1 << 3). */
+ { CONS_COLOR_MAGENTA, CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_CYAN | (1 << 3). */
+ { CONS_COLOR_CYAN, CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_RED | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_WHITE | (1 << 3). */
+ { CONS_COLOR_WHITE, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_BLACK | (1 << 3) },
+ };
+
+ signed char res_fgcol = *r_fgcol;
+ signed char res_bgcol = *r_bgcol;
+ signed char new_bgcol = bgcol;
+ int i;
+
+ /* First get a background color. */
+ if (res_bgcol == -1)
+ {
+ for (i = 0; i < 9; i++)
+ {
+ /* If the foreground color is found, make sure to not
+ set the background to it. */
+ if (res_fgcol == -1 || pref[bgcol][i] != fgcol)
+ {
+ res_bgcol = dynacolor_lookup (*dc, pref[bgcol][i]);
+ if (res_bgcol >= 0)
+ break;
+ }
+ }
+
+ assert (res_bgcol >= 0);
+ new_bgcol = pref[bgcol][i];
+ }
+
+ if (fgcol == bgcol)
+ {
+ assert (res_fgcol == -1);
+ /* Acquire another reference. */
+ res_fgcol = dynacolor_lookup (*dc, new_bgcol);
+ }
+ else
+ assert (res_fgcol != res_bgcol);
+
+ if (res_fgcol == -1)
+ {
+ /* Now find a foreground color. */
+ for (i = 0; i < 9; i++)
+ {
+ if (pref[fgcol][i] != new_bgcol)
+ {
+ res_fgcol = dynacolor_lookup (*dc, pref[fgcol][i]);
+ if (res_fgcol >= 0)
+ break;
+ }
+ }
+ assert (res_fgcol >= 0);
+ }
+ *r_fgcol = res_fgcol;
+ *r_bgcol = res_bgcol;
+}
diff --git a/console-client/vga-dynacolor.h b/console-client/vga-dynacolor.h
new file mode 100644
index 00000000..304bcc1b
--- /dev/null
+++ b/console-client/vga-dynacolor.h
@@ -0,0 +1,108 @@
+/* vga-dynacolor.h - Interface to dynamic color handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_DYNACOLOR_H_
+#define _VGA_DYNACOLOR_H_ 1
+
+/* Every component can have up to 6 bits. */
+#define DYNACOLOR_COMPONENT_MAX 0x63
+
+/* The components are, in that order, red, green, blue. */
+#define DYNACOLOR_COMPONENTS 3
+
+/* The maximum number of colors. */
+#define DYNACOLOR_COLORS 8
+
+struct dynacolor
+{
+ int ref[8];
+ /* Reverse lookup, -1 denotes an unmapped color. */
+ signed char col[16];
+};
+
+typedef struct dynacolor dynacolor_t;
+
+/* We start with one reference for the black color so that it is
+ always available. It is also put in front so that it can be shared
+ as the border color. The importance of this is that for
+ non-standard font heights, we have some black-filled normal text
+ rows below the screen matrix, for which we must allocate a real
+ color slot :( */
+#define DYNACOLOR_INIT_8 { { 1, 0, 0, 0, 0, 0, 0, 0 }, \
+ { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }
+#define DYNACOLOR_INIT_16 { { -1 } }
+
+extern dynacolor_t dynacolor_init_8;
+extern dynacolor_t dynacolor_init_16;
+
+
+/* Initialize the dynacolor subsystem. */
+void dynacolor_init (void);
+
+/* Restore the original palette. */
+void dynacolor_fini (void);
+
+/* Activate the dynamic color palette DC. */
+void dynacolor_activate (dynacolor_t *dc);
+
+/* Try to allocate a slot for the color COL in the dynamic color
+ palette DC. Return the allocated slot number (with one reference)
+ or -1 if no slot is available. */
+signed char dynacolor_allocate (dynacolor_t *dc, unsigned char col);
+
+/* Get the slot number for color C in the dynamic color palette DC, or
+ -1 if we ran out of color slots. If successful, this allocates a
+ reference for the color. */
+#define dynacolor_lookup(dc,c) \
+ ((dc).ref[0] < 0 ? (c) : \
+ ((dc).col[(c)] >= 0 ? (dc).ref[(dc).col[(c)]]++, (dc).col[(c)] : \
+ dynacolor_allocate (&(dc), (c))))
+
+/* Add a reference to palette entry P in the dynamic font DC. */
+#define dynacolor_add_ref(dc,p) \
+ ((dc).ref[0] >= 0 && (dc).ref[p]++)
+
+/* Deallocate a reference for palette entry P in the dynamic font DC. */
+#define dynacolor_release(dc,p) \
+ ((dc).ref[0] >= 0 && (dc).ref[p]--)
+
+/* This is a convenience function that looks up a replacement color
+ pair if the original colors are not available. The function always
+ succeeds. DC is the dynacolor to use for allocation, FGCOL and
+ BGCOL are the desired colors, and R_FGCOL and R_BGCOL are the
+ resulting colors. The function assumes that the caller already
+ tried to look up the desired colors before trying to replace them,
+ and that the result of the lookup is contained in R_FGCOL and
+ R_BGCOL.
+
+ Example:
+
+ res_bgcol = dynacolor_lookup (&dc, bgcol);
+ res_fgcol = dynacolor_lookup (&dc, fgcol);
+ if (res_bgcol == -1 || res_fgcol == -1)
+ dynacolor_replace_colors (&dc, fgcol, bgcol, &res_fgcol, &res_bgcol);
+
+ After the above code, res_fgcol and res_bgcol contain valid color
+ values. */
+void dynacolor_replace_colors (dynacolor_t *dc,
+ signed char fgcol, signed char bgcol,
+ signed char *r_fgcol, signed char *r_bgcol);
+
+#endif /* _VGA_DYNACOLOR_H_ */
diff --git a/console-client/vga-dynafont.c b/console-client/vga-dynafont.c
new file mode 100644
index 00000000..834d0aca
--- /dev/null
+++ b/console-client/vga-dynafont.c
@@ -0,0 +1,1072 @@
+/* vga-dynafont.c - Dynamic font handling for VGA cards.
+ Copyright (C) 2002, 2010 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stddef.h>
+#include <assert.h>
+#include <malloc.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <hurd/ihash.h>
+#include <string.h>
+
+#include <hurd/console.h>
+#include "vga-hw.h"
+#include "vga-support.h"
+#include "bdf.h"
+#include "vga-dynafont.h"
+#include "unicode.h"
+
+
+/* The currently active (visible) dynafont. The original idea was to
+ use some sort of caching for multiple dynafonts using the 8 font
+ buffers on the graphic card, but the new idea is to share a common
+ state among all virtual consoles and do a full refresh on
+ switching. However, bits and pieces of the old idea are still
+ present, in case they become useful. */
+static dynafont_t active_dynafont;
+
+
+/* One glyph in a VGA font is 8 pixels wide and 32 pixels high. Only
+ the first N lines are visible, and N depends on the VGA register
+ settings. */
+typedef char vga_font_glyph[VGA_FONT_HEIGHT];
+
+
+/* For each glyph in the VGA font, one instance of this structure is
+ held in the dynafont. */
+struct mapped_character
+{
+ /* Reference count of the mapped character. If this drops zero, we
+ can remove the mapping at any time. */
+ int refs;
+
+ /* Remember the character this glyph belongs to, so the glyph can be
+ reloaded when the font is changed. This is actually a wchar_t
+ with some text attributes mixed into the high bits. */
+#define WCHAR_BOLD ((wchar_t) 0x20000000)
+#define WCHAR_ITALIC ((wchar_t) 0x10000000)
+#define WCHAR_MASK CONS_WCHAR_MASK
+ wchar_t character;
+
+ /* Used by libihash for fast removal of elements. */
+ hurd_ihash_locp_t locp;
+};
+
+
+struct dynafont
+{
+ /* The sorted font to take the glyphs from. */
+ bdf_font_t font;
+
+ /* The sorted font to take the italic glyphs from. */
+ bdf_font_t font_italic;
+
+ /* The sorted font to take the bold glyphs from. */
+ bdf_font_t font_bold;
+
+ /* The sorted font to take the bold and italic glyphs from. */
+ bdf_font_t font_bold_italic;
+
+ /* The size of the VGA font (256 or 512). Must be a power of 2! */
+ int size;
+
+ /* A hash containing a pointer to a struct mapped_character for each
+ UCS-4 character we map to a VGA font index. */
+ struct hurd_ihash charmap;
+
+ /* The struct mapped_characters are preallocated for all vga font
+ index values. This points to an array of SIZE such elements. */
+ struct mapped_character *charmap_data;
+
+ /* The last vga font index that had been free (or could be
+ reused). */
+ int vga_font_last_free_index;
+
+ /* The number of free slots in the VGA font. */
+ int vga_font_free_indices;
+
+ int use_lgc;
+
+ /* The last vga font index that had been free (or could be reused)
+ for horizontal line graphic characters. */
+ int vga_font_last_free_index_lgc;
+
+ /* The number of free slots in the VGA font for horizontal line
+ graphic charactes. */
+ int vga_font_free_indices_lgc;
+
+ /* The font memory as stored on the card. */
+ vga_font_glyph *vga_font;
+
+ /* The cursor size, standout or normal. */
+ int cursor_standout;
+};
+
+
+/* The VGA standard font follows IBM code page 437. The following
+ table maps this to unicode. For simplicity, a 1:1 mapping is
+ assumed. Ambiguities are special cased in create_system_font. */
+static
+wchar_t ibm437_to_unicode[VGA_FONT_SIZE] = {
+ 0, /* 0x00 */
+ UNICODE_WHITE_SMILING_FACE, /* 0x01 */
+ UNICODE_BLACK_SMILING_FACE, /* 0x02 */
+ UNICODE_BLACK_HEART_SUIT, /* 0x03 */
+ UNICODE_BLACK_DIAMOND_SUIT, /* 0x04 */
+ UNICODE_BLACK_CLUB_SUIT, /* 0x05 */
+ UNICODE_BLACK_SPADE_SUIT, /* 0x06 */
+ UNICODE_BULLET, /* 0x07 */
+ UNICODE_INVERSE_BULLET, /* 0x08 */
+ UNICODE_WHITE_CIRCLE, /* 0x09 */
+ UNICODE_INVERSE_WHITE_CIRCLE, /* 0x0a */
+ UNICODE_MALE_SIGN, /* 0x0b */
+ UNICODE_FEMALE_SIGN, /* 0x0c */
+ UNICODE_EIGHTH_NOTE, /* 0x0d */
+ UNICODE_BEAMED_EIGHTH_NOTES, /* 0x0e */
+ UNICODE_WHITE_SUN_WITH_RAYS, /* 0x0f */
+ UNICODE_BLACK_RIGHT_POINTING_TRIANGLE, /* 0x10 */
+ UNICODE_BLACK_LEFT_POINTING_TRIANGLE, /* 0x11 */
+ UNICODE_UP_DOWN_ARROW, /* 0x12 */
+ UNICODE_DOUBLE_EXCLAMATION_MARK, /* 0x13 */
+ UNICODE_PILCROW_SIGN, /* 0x14 */
+ UNICODE_SECTION_SIGN, /* 0x15 */
+ UNICODE_BLACK_RECTANGLE, /* 0x16 */
+ UNICODE_UP_DOWN_ARROW_WITH_BASE, /* 0x17 */
+ UNICODE_UPWARDS_ARROW, /* 0x18 */
+ UNICODE_DOWNWARDS_ARROW, /* 0x19 */
+ UNICODE_RIGHTWARDS_ARROW, /* 0x1a */
+ UNICODE_LEFTWARDS_ARROW, /* 0x1b */
+ UNICODE_RIGHT_ANGLE, /* 0x1c */
+ UNICODE_LEFT_RIGHT_ARROW, /* 0x1d */
+ UNICODE_BLACK_UP_POINTING_TRIANGLE, /* 0x1e */
+ UNICODE_BLACK_DOWN_POINTING_TRIANGLE, /* 0x1f */
+ ' ', '!', '"', '#', '$', '%', '&', '\'', /* 0x20 - 0x27 */
+ '(', ')', '*', '+', ',', '-', '.', '/', /* 0x28 - 0x2f */
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', /* 0x30 - 0x37 */
+ ':', ';', '<', '=', '>', '?', /* 0x38 - 0x3f */
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 - 0x47 */
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 0x48 - 0x4f */
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 - 0x57 */
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', /* 0x58 - 0x5f */
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 - 0x67 */
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 0x68 - 0x6f */
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 - 0x77 */
+ 'x', 'y', 'z', '{', '|', '}', '~', UNICODE_HOUSE, /* 0x78 - 0x7f */
+ UNICODE_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA, /* 0x80 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_DIARESIS, /* 0x81 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_ACUTE, /* 0x82 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX, /* 0x83 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_DIARESIS, /* 0x84 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_GRAVE, /* 0x85 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE, /* 0x86 */
+ UNICODE_LATIN_SMALL_LETTER_C_WITH_CEDILLA, /* 0x87 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX, /* 0x88 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_DIARESIS, /* 0x89 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_GRAVE, /* 0x8a */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_DIARESIS, /* 0x8b */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX, /* 0x8c */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_GRAVE, /* 0x8d */
+ UNICODE_LATIN_CAPITAL_LETTER_A_WITH_DIARESIS, /* 0x8e */
+ UNICODE_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE, /* 0x8f */
+ UNICODE_LATIN_CAPITAL_LETTER_E_WITH_ACUTE, /* 0x90 */
+ UNICODE_LATIN_SMALL_LETTER_AE, /* 0x91 */
+ UNICODE_LATIN_CAPITAL_LETTER_AE, /* 0x92 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX, /* 0x93 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_DIARESIS, /* 0x94 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_GRAVE, /* 0x95 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX, /* 0x96 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_GRAVE, /* 0x97 */
+ UNICODE_LATIN_SMALL_LETTER_Y_WITH_DIARESIS, /* 0x98 */
+ UNICODE_LATIN_CAPITAL_LETTER_O_WITH_DIARESIS, /* 0x99 */
+ UNICODE_LATIN_CAPITAL_LETTER_U_WITH_DIARESIS, /* 0x9a */
+ UNICODE_CENT_SIGN, /* 0x9b */
+ UNICODE_POUND_SIGN, /* 0x9c */
+ UNICODE_YEN_SIGN, /* 0x9d */
+ UNICODE_PESETA_SIGN, /* 0x9e */
+ UNICODE_LATIN_SMALL_LETTER_F_WITH_HOOK, /* 0x9f */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_ACUTE, /* 0xa0 */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_ACUTE, /* 0xa1 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_ACUTE, /* 0xa2 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_ACUTE, /* 0xa3 */
+ UNICODE_LATIN_SMALL_LETTER_N_WITH_TILDE, /* 0xa4 */
+ UNICODE_LATIN_CAPITAL_LETTER_N_WITH_TILDE, /* 0xa5 */
+ UNICODE_FEMININE_ORDINAL_INDICATOR, /* 0xa6 */
+ UNICODE_MASCULINE_ORDINAL_INDICATOR, /* 0xa7 */
+ UNICODE_INVERTED_QUESTION_MARK, /* 0xa8 */
+ UNICODE_REVERSED_NOT_SIGN, /* 0xa9 */
+ UNICODE_NOT_SIGN, /* 0xaa */
+ UNICODE_VULGAR_FRACTION_ONE_HALF, /* 0xab */
+ UNICODE_VULGAR_FRACTION_ONE_QUARTER, /* 0xac */
+ UNICODE_INVERTED_EXCLAMATION_MARK, /* 0xad */
+ UNICODE_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, /* 0xae */
+ UNICODE_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, /* 0xaf */
+ UNICODE_LIGHT_SHADE, /* 0xb0 */
+ UNICODE_MEDIUM_SHADE, /* 0xb1 */
+ UNICODE_DARK_SHADE, /* 0xb2 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL, /* 0xb3 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT, /* 0xb4 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE, /* 0xb5 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE, /* 0xb6 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE, /* 0xb7 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE, /* 0xb8 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT, /* 0xb9 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL, /* 0xba */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT, /* 0xbb */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_LEFT, /* 0xbc */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE, /* 0xbd */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE, /* 0xbe */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT, /* 0xbf */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, /* 0xc0 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL, /* 0xc1 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL, /* 0xc2 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT, /* 0xc3 */
+ UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL, /* 0xc4 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL, /* 0xc5 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE, /* 0xc6 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE, /* 0xc7 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT, /* 0xc8 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT, /* 0xc9 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL, /* 0xca */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL, /* 0xcb */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT, /* 0xcc */
+ UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL, /* 0xcd */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL,/* 0xce */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xcf */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd0 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xd1 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd2 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE, /* 0xd3 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE, /* 0xd4 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE, /* 0xd5 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE, /* 0xd6 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd7 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xd8 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, /* 0xd9 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, /* 0xda */
+ UNICODE_FULL_BLOCK, /* 0xdb */
+ UNICODE_LOWER_HALF_BLOCK, /* 0xdc */
+ UNICODE_LEFT_HALF_BLOCK, /* 0xdd */
+ UNICODE_RIGHT_HALF_BLOCK, /* 0xde */
+ UNICODE_UPPER_HALF_BLOCK, /* 0xdf */
+ UNICODE_GREEK_SMALL_LETTER_ALPHA, /* 0xe0 */
+ /* The next one: Also sz-ligature. */
+ UNICODE_GREEK_SMALL_LETTER_BETA, /* 0xe1 */
+ UNICODE_GREEK_CAPITAL_LETTER_GAMMA, /* 0xe2 */
+ UNICODE_GREEK_SMALL_LETTER_PI, /* 0xe3 */
+ UNICODE_GREEK_CAPITAL_LETTER_SIGMA, /* 0xe4 */
+ UNICODE_GREEK_SMALL_LETTER_SIGMA, /* 0xe5 */
+ /* The next one: Also micro. */
+ UNICODE_GREEK_SMALL_LETTER_MU, /* 0xe6 */
+ UNICODE_GREEK_SMALL_LETTER_TAU, /* 0xe7 */
+ UNICODE_GREEK_CAPITAL_LETTER_PHI, /* 0xe8 */
+ UNICODE_GREEK_CAPITAL_LETTER_OMICRON, /* 0xe9 */
+ UNICODE_GREEK_CAPITAL_LETTER_OMEGA, /* 0xea */
+ UNICODE_GREEK_SMALL_LETTER_DELTA, /* 0xeb */
+ UNICODE_INFINITY, /* 0xec */
+ UNICODE_GREEK_SMALL_LETTER_PHI, /* 0xed */
+ UNICODE_GREEK_SMALL_LETTER_EPSILON, /* 0xee */
+ UNICODE_INTERSECTION, /* 0xef */
+ UNICODE_IDENTICAL_TO, /* 0xf0 */
+ UNICODE_PLUS_MINUS_SIGN, /* 0xf1 */
+ UNICODE_GREATER_THAN_OR_EQUAL_TO, /* 0xf2 */
+ UNICODE_LESS_THAN_OR_EQUAL_TO, /* 0xf3 */
+ UNICODE_TOP_HALF_INTEGRAL, /* 0xf4 */
+ UNICODE_BOTTOM_HALF_INTEGRAL, /* 0xf5 */
+ UNICODE_DIVISION_SIGN, /* 0xf6 */
+ UNICODE_ALMOST_EQUAL_TO, /* 0xf7 */
+ UNICODE_DEGREE_SIGN, /* 0xf8 */
+ UNICODE_BULLET_OPERATOR, /* 0xf9 */
+ UNICODE_MIDDLE_DOT, /* 0xfa */
+ UNICODE_SQUARE_ROOT, /* 0xfb */
+ UNICODE_SUPERSCRIPT_LATIN_SMALL_LETTER, /* 0xfc */
+ UNICODE_SUPERSCRIPT_TWO, /* 0xfd */
+ UNICODE_BLACK_SQUARE, /* 0xfe */
+ UNICODE_NO_BREAK_SPACE /* 0xff */
+ };
+
+/* Read the VGA card's memory as IBM 437 font and create a Unicode BDF
+ font from it. If an error occurs, errno is set and NULL is
+ returned. */
+static bdf_font_t
+create_system_font (void)
+{
+ bdf_error_t bdferr;
+ bdf_font_t font;
+ unsigned char bitmap[VGA_FONT_SIZE][VGA_FONT_HEIGHT]; /* 8kB on stack. */
+ int width = vga_get_font_width ();
+ int i;
+
+ /* Add the glyph at position POS to the font for character
+ ENCODING. */
+ void vga_add_glyph (int pos, int encoding)
+ {
+ char name[16];
+ snprintf (name, sizeof (name), "VGA %i", pos);
+
+ if (width == 8)
+ bdferr = bdf_add_glyph (font, name, encoding,
+ 0, 8, 16, 0, 0, bitmap[pos]);
+ else
+ {
+ int i;
+ char glyph_bitmap[32];
+
+ for (i = 0; i < 16; i++)
+ {
+ glyph_bitmap[i * 2] = bitmap[pos][i];
+ if (pos >= VGA_FONT_LGC_BEGIN
+ && pos < VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ glyph_bitmap[i * 2 + 1]
+ = (bitmap[pos][i] & 1) ? 0x80 : 0;
+ else
+ glyph_bitmap[i * 2 + 1] = 0;
+ }
+ bdferr = bdf_add_glyph (font, name, encoding,
+ 0, 9, 16, 0, 0, glyph_bitmap);
+ }
+ }
+
+ /* The point size and resolution is arbitrary. */
+ bdferr = bdf_new (&font, 2, 2, "vga-system", 10, 100, 100,
+ width, 16, 0, 0, 0);
+ if (bdferr)
+ {
+ if (bdferr != BDF_SYSTEM_ERROR)
+ errno = EGRATUITOUS;
+ return NULL;
+ }
+
+ vga_read_font_buffer (0, 0, (unsigned char *) bitmap,
+ VGA_FONT_SIZE * VGA_FONT_HEIGHT);
+
+ for (i = 0; i < VGA_FONT_SIZE; i++)
+ if (ibm437_to_unicode[i])
+ {
+ vga_add_glyph (i, ibm437_to_unicode[i]);
+ if (bdferr)
+ break;
+
+ /* Some glyphs are ambivalent. */
+ if (ibm437_to_unicode[i] == UNICODE_GREEK_SMALL_LETTER_BETA)
+ vga_add_glyph (i, UNICODE_LATIN_SMALL_LETTER_SHARP_S);
+ else if (ibm437_to_unicode[i] == UNICODE_GREEK_SMALL_LETTER_MU)
+ vga_add_glyph (i, UNICODE_MICRO_SIGN);
+ if (bdferr)
+ break;
+ }
+
+ if (bdferr)
+ {
+ bdf_destroy (font);
+ if (bdferr != BDF_SYSTEM_ERROR)
+ errno = EGRATUITOUS;
+ return NULL;
+ }
+
+ return font;
+}
+
+
+#if QUAERENDO_INVENIETIS
+#define GNU_HEAD_BEGIN (UNICODE_PRIVATE_USE_AREA + 0x0f00)
+
+static void
+add_gnu_head (bdf_font_t font)
+{
+#define GNU_HEAD_WIDTH 6
+ static unsigned char gnu_head[][GNU_HEAD_WIDTH] =
+ {
+ { 255, 255, 255, 255, 255, 255 }, { 255, 0, 127, 255, 252, 31 },
+ { 252, 0, 31, 255, 224, 7 }, { 248, 0, 7, 255, 0, 3 },
+ { 240, 0, 15, 255, 128, 3 }, { 240, 31, 255, 255, 252, 1 },
+ { 224, 63, 241, 255, 255, 1 }, { 192, 127, 128, 96, 255, 129 },
+ { 192, 255, 0, 0, 63, 193 }, { 192, 254, 0, 0, 31, 193 },
+ { 192, 252, 0, 0, 15, 193 }, { 192, 248, 0, 0, 15, 193 },
+ { 192, 248, 0, 0, 7, 129 }, { 192, 96, 63, 131, 192, 1 },
+ { 192, 1, 227, 98, 112, 1 }, { 192, 3, 195, 244, 176, 3 },
+ { 224, 7, 221, 125, 248, 3 }, { 240, 15, 184, 124, 120, 7 },
+ { 240, 15, 248, 124, 60, 15 }, { 248, 15, 220, 254, 124, 127 },
+ { 252, 31, 223, 255, 254, 127 }, { 255, 159, 159, 255, 31, 191 },
+ { 255, 223, 159, 255, 35, 63 }, { 255, 191, 127, 195, 152, 127 },
+ { 255, 188, 255, 156, 199, 255 }, { 255, 96, 253, 134, 115, 255 },
+ { 254, 134, 251, 227, 251, 255 }, { 254, 46, 254, 249, 251, 255 },
+ { 255, 238, 126, 127, 231, 255 }, { 255, 239, 127, 127, 207, 255 },
+ { 255, 239, 63, 63, 231, 255 }, { 255, 247, 159, 158, 15, 255 },
+ { 255, 247, 207, 193, 159, 255 }, { 255, 247, 223, 255, 223, 255 },
+ { 255, 243, 199, 252, 31, 255 }, { 255, 251, 227, 224, 63, 255 },
+ { 255, 253, 241, 240, 255, 255 }, { 255, 252, 244, 126, 255, 255 },
+ { 255, 254, 121, 122, 255, 255 }, { 255, 255, 252, 48, 255, 255 },
+ { 255, 255, 252, 35, 255, 255 }, { 255, 255, 249, 1, 127, 255 },
+ { 255, 255, 251, 0, 127, 255 }, { 255, 255, 255, 128, 255, 255 },
+ { 255, 255, 255, 255, 255, 255 }
+ };
+ /* Height of a single glyph, truncated to fit VGA glyph slot. */
+ int height = (font->bbox.height > 32) ? 32 : font->bbox.height;
+ /* Width of a single glyph in byte. */
+ int width = (font->bbox.width + 7) / 8;
+ /* Number of rows in bitmap. */
+ int rows = sizeof (gnu_head) / sizeof (gnu_head[0]);
+ /* Number of rows of glyphs necessary. */
+ int nr = (rows + height - 1) / height;
+ int row, col;
+
+ /* Check that all those glyphs are free in the private area. */
+ if (nr * GNU_HEAD_WIDTH > GNU_HEAD_BEGIN - UNICODE_PRIVATE_USE_AREA + 1)
+ return;
+ for (int i = 0; i < nr * GNU_HEAD_WIDTH; i++)
+ if (bdf_find_glyph (font, (int) GNU_HEAD_BEGIN + i, 0)
+ || bdf_find_glyph (font, -1, (int) GNU_HEAD_BEGIN + i))
+ return;
+
+ for (row = 0; row < nr; row++)
+ for (col = 0; col < GNU_HEAD_WIDTH; col++)
+ {
+ char bitmap[font->bbox.height][width];
+ char name[] = "GNU Head ..........";
+
+ /* strlen ("GNU Head ") == 9. */
+ sprintf (&name[9], "%i", row * GNU_HEAD_WIDTH + col);
+
+ memset (bitmap, 0, sizeof (bitmap));
+ for (int j = 0; j < height && row * height + j < rows; j++)
+ bitmap[j][0] = gnu_head[row * height + j][col];
+
+ if (bdf_add_glyph (font, name,
+ GNU_HEAD_BEGIN + row * GNU_HEAD_WIDTH + col,
+ 0, font->bbox.width, font->bbox.height,
+ 0, 0, (unsigned char *) bitmap))
+ return;
+ }
+}
+#endif
+
+/* Create a new dynafont object, which uses glyphs from the font FONT
+ (which should be 8 or 9 pixels wide and 13 to 16 pixels high).
+ SIZE is either 256 or 512, and specifies the number of available
+ glyphs in the font cache. The object is returned in DYNAFONT.
+
+ The font is consumed. If FONT is the null pointer, the VGA card's
+ memory is converted to a font according to the VGA default map (IBM
+ Code Page 437). */
+error_t
+dynafont_new (bdf_font_t font, bdf_font_t font_italic, bdf_font_t font_bold,
+ bdf_font_t font_bold_italic, int size, dynafont_t *dynafont)
+{
+ dynafont_t df;
+ struct bdf_glyph *glyph = NULL;
+
+ if (!font)
+ font = create_system_font ();
+ if (!font || !font->bbox.height)
+ return errno;
+
+ df = malloc (sizeof *df);
+ if (!df)
+ return ENOMEM;
+
+#if QUAERENDO_INVENIETIS
+ add_gnu_head (font);
+#endif
+ bdf_sort_glyphs (font);
+ df->font = font;
+ df->font_italic = font_italic;
+ df->font_bold = font_bold;
+ df->font_bold_italic = font_bold_italic;
+ df->size = size;
+ df->cursor_standout = 0;
+
+ df->charmap_data = calloc (size, sizeof (struct mapped_character));
+ if (!df->charmap_data)
+ {
+ free (df);
+ return ENOMEM;
+ }
+
+ df->vga_font = malloc (sizeof (vga_font_glyph) * size);
+ if (!df->vga_font)
+ {
+ free (df->charmap_data);
+ free (df);
+ return ENOMEM;
+ }
+
+ hurd_ihash_init (&df->charmap, offsetof (struct mapped_character, locp));
+
+ if (df->font->bbox.width == 9)
+ {
+ /* 32 from 256 font slots are for horizontal line graphic
+ characters. */
+ df->use_lgc = 1;
+ df->vga_font_free_indices = df->size
+ - (df->size / 256) * VGA_FONT_LGC_COUNT;
+ df->vga_font_last_free_index = 0;
+ df->vga_font_free_indices_lgc = (df->size / 256) * VGA_FONT_LGC_COUNT;
+ df->vga_font_last_free_index_lgc = VGA_FONT_LGC_BEGIN;
+ }
+ else
+ {
+ df->use_lgc = 0;
+ df->vga_font_free_indices = df->size;
+ df->vga_font_last_free_index = 0;
+ df->vga_font_free_indices_lgc = 0;
+ df->vga_font_last_free_index_lgc = 0;
+ }
+
+ /* Ensure that ASCII is always available 1-to-1, for kernel messages. */
+ for (int c = ' '; c <= '~'; c++)
+ {
+ glyph = bdf_find_glyph (df->font, c, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1, c);
+ if (glyph)
+ {
+ struct mapped_character *chr = &df->charmap_data[c];
+ df->vga_font_free_indices--;
+ chr->refs = 1;
+
+ for (int i = 0; i < ((glyph->bbox.height > 32)
+ ? 32 : glyph->bbox.height); i++)
+ df->vga_font[c][i]
+ = glyph->bitmap[i * ((glyph->bbox.width + 7) / 8)];
+ if (glyph->bbox.height < 32)
+ memset (((char *) df->vga_font[c])
+ + glyph->bbox.height, 0, 32 - glyph->bbox.height);
+
+ /* Update the hash table. */
+ hurd_ihash_add (&df->charmap, c, chr);
+ }
+ }
+
+ /* Ensure that we always have the replacement character
+ available. */
+ {
+ struct mapped_character *chr = &df->charmap_data[FONT_INDEX_UNKNOWN];
+ df->vga_font_free_indices--;
+ chr->refs = 1;
+
+ glyph = bdf_find_glyph (df->font, UNICODE_REPLACEMENT_CHARACTER, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1, UNICODE_REPLACEMENT_CHARACTER);
+ if (glyph)
+ {
+ for (int i = 0; i < ((glyph->bbox.height > 32)
+ ? 32 : glyph->bbox.height); i++)
+ df->vga_font[FONT_INDEX_UNKNOWN][i]
+ = glyph->bitmap[i * ((glyph->bbox.width + 7) / 8)];
+ if (glyph->bbox.height < 32)
+ memset (((char *) df->vga_font[FONT_INDEX_UNKNOWN])
+ + glyph->bbox.height, 0, 32 - glyph->bbox.height);
+
+ /* Update the hash table. */
+ hurd_ihash_add (&df->charmap, UNICODE_REPLACEMENT_CHARACTER, chr);
+ }
+ else
+ {
+ int i;
+ char *gl = df->vga_font[FONT_INDEX_UNKNOWN];
+ /* XXX Take font height into account. */
+ gl[0] = 0x7E; /* ****** */
+ gl[1] = 0xC3; /* ** ** */
+ gl[2] = 0x99; /* * ** * */
+ gl[3] = 0x99; /* * ** * */
+ gl[4] = 0xF9; /* ***** * */
+ gl[5] = 0xF3; /* **** ** */
+ gl[6] = 0xF3; /* *** *** */
+ gl[7] = 0xE7; /* *** *** */
+ gl[8] = 0xFF; /* ******** */
+ gl[9] = 0xE7; /* *** *** */
+ gl[10] = 0xE7; /* *** *** */
+ gl[11] = 0x7E; /* ****** */
+ for (i = 12; i < 32; i++)
+ gl[i] = 0;
+ }
+ }
+
+ *dynafont = df;
+ return 0;
+}
+
+
+/* Release a dynafont object and its associated resources. */
+void
+dynafont_free (dynafont_t df)
+{
+ if (active_dynafont == df)
+ active_dynafont = NULL;
+
+ bdf_destroy (df->font);
+ if (df->font_italic)
+ bdf_destroy (df->font_italic);
+ if (df->font_bold)
+ bdf_destroy (df->font_bold);
+ if (df->font_bold_italic)
+ bdf_destroy (df->font_bold_italic);
+ hurd_ihash_destroy (&df->charmap);
+ free (df->charmap_data);
+ free (df->vga_font);
+ free (df);
+}
+
+
+/* Determine if CHR is a character that needs to be continuous in the
+ horizontal direction by repeating the last (eighth) column in
+ 9-pixel-width mode. */
+static inline int
+is_lgc (wchar_t chr)
+{
+ /* This list must be sorted for bsearch! */
+ static wchar_t horiz_glyphs[] =
+ {
+ UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL, /* 0x2500 */
+ UNICODE_BOX_DRAWINGS_HEAVY_HORIZONTAL, /* 0x2501 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, /* 0x250c */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_HEAVY, /* 0x250d */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_LIGHT, /* 0x250e */
+ UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_RIGHT, /* 0x250f */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, /* 0x2514 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_HEAVY, /* 0x2515 */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_LIGHT, /* 0x2516 */
+ UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_RIGHT, /* 0x2517 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT, /* 0x251c */
+ UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_RIGHT_HEAVY, /* 0x251d */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x251e */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x251f */
+ UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_RIGHT_LIGHT, /* 0x2520 */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_UP_HEAVY, /* 0x2521 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_DOWN_HEAVY, /* 0x2522 */
+ UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_RIGHT, /* 0x2523 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL, /* 0x252c */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_DOWN_LIGHT, /* 0x252d */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_DOWN_LIGHT, /* 0x252e */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x252f */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2530 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_DOWN_HEAVY, /* 0x2531 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_DOWN_HEAVY, /* 0x2532 */
+ UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_HORIZONTAL, /* 0x2533 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL, /* 0x2534 */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x2535 */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_UP_LIGHT, /* 0x2536 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x2537 */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2538 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_UP_HEAVY, /* 0x2539 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_UP_HEAVY, /* 0x253a */
+ UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_HORIZONTAL, /* 0x253b */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL, /* 0x253c */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_VERTICAL_LIGHT, /* 0x253d */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_VERTICAL_LIGHT, /* 0x253e */
+ UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x253f */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_DOWN_HORIZONTAL_LIGHT, /* 0x2540 */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_UP_HORIZONTAL_LIGHT, /* 0x2541 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2542 */
+ UNICODE_BOX_DRAWINGS_LEFT_UP_HEAVY_AND_RIGHT_DOWN_LIGHT, /* 0x2543 */
+ UNICODE_BOX_DRAWINGS_RIGHT_UP_HEAVY_AND_LEFT_DOWN_LIGHT, /* 0x2544 */
+ UNICODE_BOX_DRAWINGS_LEFT_DOWN_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x2545 */
+ UNICODE_BOX_DRAWINGS_RIGHT_DOWN_HEAVY_AND_LEFT_UP_LIGHT, /* 0x2546 */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_UP_HORIZONTAL_HEAVY, /* 0x2547 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_DOWN_HORIZONTAL_HEAVY, /* 0x2548 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_VERTICAL_HEAVY, /* 0x2549 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_VERTICAL_HEAVY, /* 0x254a */
+ UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_HORIZONTAL, /* 0x254b */
+ UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL, /* 0x2550 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE, /* 0x2552 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE, /* 0x2553 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT, /* 0x2554 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE, /* 0x2558 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE, /* 0x2559 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT, /* 0x255a */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE, /* 0x255e */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE, /* 0x255f */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT, /* 0x2560 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x2564 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x2565 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL, /* 0x2566 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x2567 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x2568 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL, /* 0x2569 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x256a */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x256b */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL, /* 0x256c */
+ UNICODE_BOX_DRAWINGS_LIGHT_ARC_DOWN_AND_RIGHT, /* 0x256d */
+ UNICODE_BOX_DRAWINGS_LIGHT_ARC_UP_AND_RIGHT, /* 0x2570 */
+#if 0
+ /* The diagonal lines don't look much better with or without the
+ ninth column. */
+ /* 0x2571 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_RIGHT_TO_LOWER_LEFT,
+ /* 0x2572 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_LEFT_TO_LOWER_RIGHT,
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_CROSS, /* 0x2573 */
+#endif
+ UNICODE_BOX_DRAWINGS_LIGHT_RIGHT, /* 0x2576 */
+ UNICODE_BOX_DRAWINGS_HEAVY_RIGHT, /* 0x257a */
+ UNICODE_BOX_DRAWINGS_LIGHT_LEFT_AND_HEAVY_RIGHT, /* 0x257c */
+ UNICODE_BOX_DRAWINGS_HEAVY_LEFT_AND_LIGHT_RIGHT, /* 0x257e */
+ UNICODE_UPPER_HALF_BLOCK, /* 0x2580 */
+ UNICODE_LOWER_ONE_EIGHTH_BLOCK, /* 0x2581 */
+ UNICODE_LOWER_ONE_QUARTER_BLOCK, /* 0x2582 */
+ UNICODE_LOWER_THREE_EIGHTHS_BLOCK, /* 0x2583 */
+ UNICODE_LOWER_HALF_BLOCK, /* 0x2584 */
+ UNICODE_LOWER_FIVE_EIGHTHS_BLOCK, /* 0x2585 */
+ UNICODE_LOWER_THREE_QUARTERS_BLOCK, /* 0x2586 */
+ UNICODE_LOWER_SEVEN_EIGHTHS_BLOCK, /* 0x2587 */
+ UNICODE_FULL_BLOCK, /* 0x2588 */
+ UNICODE_RIGHT_HALF_BLOCK, /* 0x2590 */
+#if 0
+ /* The shades don't look much better with or without the ninth
+ column. */
+ UNICODE_LIGHT_SHADE, /* 0x2591 */
+ UNICODE_MEDIUM_SHADE, /* 0x2592 */
+ UNICODE_DARK_SHADE, /* 0x2593 */
+#endif
+ UNICODE_BLACK_SQUARE, /* 0x25a0 */
+ UNICODE_UPPER_ONE_EIGHTH_BLOCK, /* 0x2594 */
+ UNICODE_RIGHT_ONE_EIGHTH_BLOCK, /* 0x2595 */
+ UNICODE_QUADRANT_LOWER_RIGHT, /* 0x2597 */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_LEFT_AND_LOWER_RIGHT, /* 0x2599 */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_RIGHT, /* 0x259a */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_LEFT, /* 0x259b */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_RIGHT, /* 0x259c */
+ UNICODE_QUADRANT_UPPER_RIGHT, /* 0x259d */
+ UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT, /* 0x259e */
+ UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT_AND_LOWER_RIGHT, /* 0x259f */
+ };
+
+ int cmp_wchar (const void *a, const void *b)
+ {
+ const wchar_t *wa = (const wchar_t *) a;
+ const wchar_t *wb = (const wchar_t *) b;
+ return (*wa > *wb) - (*wa < *wb);
+ }
+
+#if QUAERENDO_INVENIETIS
+ /* XXX The (maximum) size is hard coded. */
+ if (chr >= GNU_HEAD_BEGIN && chr <= GNU_HEAD_BEGIN + 50)
+ return 1;
+#endif
+
+ return bsearch (&chr, horiz_glyphs,
+ sizeof (horiz_glyphs) / sizeof (horiz_glyphs[0]),
+ sizeof (horiz_glyphs[0]), cmp_wchar) ? 1 : 0;
+}
+
+
+/* Try to look up glyph CHR in font FONT of dynafont DF with attribute
+ ATTR. This is a helper function for dynafont_lookup. Returns 1 on
+ success, 0 otherwise. */
+static int
+dynafont_lookup_internal (dynafont_t df, bdf_font_t font,
+ wchar_t wide_chr, wchar_t attr, int *rpos)
+{
+ /* When hashing the character, we mix in the font attribute. */
+ struct mapped_character *chr = hurd_ihash_find (&df->charmap,
+ (int) (wide_chr | attr));
+ int lgc;
+ struct bdf_glyph *glyph;
+ int pos;
+ int found = 0;
+
+ lgc = df->use_lgc ? is_lgc (wide_chr) : 0;
+
+ if (chr)
+ {
+ if (!chr->refs++)
+ {
+ if (lgc)
+ df->vga_font_free_indices_lgc--;
+ else
+ df->vga_font_free_indices--;
+ }
+ /* Return the index of CHR. */
+ *rpos = chr - df->charmap_data;
+ return 1;
+ }
+
+ /* The character is not currently mapped. Look for an empty slot
+ and add it. */
+ if ((lgc && !df->vga_font_free_indices_lgc)
+ || (!lgc && !df->vga_font_free_indices))
+ return 0;
+
+ glyph = bdf_find_glyph (font, (int) (wide_chr & ~CONS_WCHAR_CONTINUED), 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (font, -1, (int) (wide_chr & ~CONS_WCHAR_CONTINUED));
+ if (!glyph)
+ return 0;
+
+ if (lgc)
+ {
+ int start_pos = df->vga_font_last_free_index_lgc + 1;
+ if ((start_pos % VGA_FONT_SIZE)
+ == VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ {
+ start_pos += VGA_FONT_SIZE - VGA_FONT_LGC_COUNT;
+ start_pos %= df->size;
+ }
+ pos = start_pos;
+
+ do
+ {
+ if (df->charmap_data[pos].refs == 0)
+ {
+ found = 1;
+ break;
+ }
+ pos++;
+ if ((pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ {
+ pos += VGA_FONT_SIZE - VGA_FONT_LGC_COUNT;
+ pos %= df->size;
+ }
+ }
+ while (pos != start_pos);
+
+ assert (found);
+ df->vga_font_free_indices_lgc--;
+ df->vga_font_last_free_index_lgc = pos;
+ }
+ else
+ {
+ int start_pos = (df->vga_font_last_free_index + 1) % df->size;
+ if (df->use_lgc && (start_pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN)
+ start_pos += VGA_FONT_LGC_COUNT;
+ pos = start_pos;
+
+ do
+ {
+ if (df->charmap_data[pos].refs == 0)
+ {
+ found = 1;
+ break;
+ }
+ pos = (pos + 1) % df->size;
+ if (df->use_lgc && (pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN)
+ pos += VGA_FONT_LGC_COUNT;
+ }
+ while (pos != start_pos);
+
+ assert (found);
+ df->vga_font_free_indices--;
+ df->vga_font_last_free_index = pos;
+ }
+
+ /* Ok, we found a new entry, use it. */
+ chr = &df->charmap_data[pos];
+ chr->refs = 1;
+ chr->character = (wide_chr | attr);
+
+ /* Copy the glyph bitmap, taking into account double-width characters. */
+ {
+ int height = (glyph->bbox.height > 32) ? 32 : glyph->bbox.height;
+ int bwidth = (glyph->bbox.width + 7) / 8;
+ int ofs = (bwidth >= 2) && (wide_chr & CONS_WCHAR_CONTINUED);
+
+ for (int i = 0; i < height; i++)
+ df->vga_font[pos][i] = glyph->bitmap[i * bwidth + ofs];
+ if (height < 32)
+ memset (&df->vga_font[pos][height], 0, 32 - height);
+ }
+
+ if (active_dynafont == df)
+ vga_write_font_buffer (0, pos, df->vga_font[pos],
+ VGA_FONT_HEIGHT);
+ /* Update the hash table. */
+ if (chr->locp)
+ hurd_ihash_locp_remove (&df->charmap, chr->locp);
+ hurd_ihash_add (&df->charmap, (int) (wide_chr | attr), chr);
+ *rpos = pos;
+ return 1;
+}
+
+/* Look up the vga font index for an UCS-4 character. If not already
+ mapped, try to find space for a new entry and add the mapping.
+ Acquires an additional reference to the character. Might return
+ the glyph for the unrepresentable character if the glyph is ot
+ available for this character or no free slot is available right
+ now. In the former case, some information gets lost (to do
+ otherwise, one would have to either assign one of the scarce font
+ indices to each undisplayable character value on screen, or to
+ store the whole scrollback buffer as wide chars as well to recover
+ the lost info from that copy of the original text. */
+int
+dynafont_lookup (dynafont_t df, conchar_t *conchr)
+{
+ wchar_t attr = (conchr->attr.italic ? WCHAR_ITALIC : 0)
+ | (conchr->attr.bold ? WCHAR_BOLD : 0);
+ int found = 0;
+ int pos = FONT_INDEX_UNKNOWN;
+
+ if (attr == (WCHAR_BOLD | WCHAR_ITALIC) && df->font_bold_italic)
+ found = dynafont_lookup_internal (df, df->font_bold_italic,
+ conchr->chr, WCHAR_BOLD | WCHAR_ITALIC,
+ &pos);
+ /* This order will prefer bold over italic if both are requested but
+ are not available at the same time. The other order is just as
+ good. XXX. */
+ if (!found && (attr & WCHAR_BOLD) && df->font_bold)
+ found = dynafont_lookup_internal (df, df->font_bold,
+ conchr->chr, WCHAR_BOLD, &pos);
+ if (!found && (attr & WCHAR_ITALIC) && df->font_italic)
+ found = dynafont_lookup_internal (df, df->font_italic,
+ conchr->chr, WCHAR_ITALIC, &pos);
+ if (!found)
+ found = dynafont_lookup_internal (df, df->font, conchr->chr, 0, &pos);
+ if (!found)
+ {
+ df->charmap_data[FONT_INDEX_UNKNOWN].refs++;
+ pos = FONT_INDEX_UNKNOWN;
+ }
+ return pos;
+}
+
+
+/* Release a reference to the glyph VGA_FONT_INDEX in dynafont DF. */
+void
+dynafont_release (dynafont_t df, int vga_font_index)
+{
+ if (! --df->charmap_data[vga_font_index].refs)
+ {
+ if (df->use_lgc
+ && is_lgc (df->charmap_data[vga_font_index].character & WCHAR_MASK))
+ df->vga_font_free_indices_lgc++;
+ else
+ df->vga_font_free_indices++;
+ }
+}
+
+
+
+/* Set the cursor to normal if STANDOUT is zero, or to a block cursor
+ otherwise. */
+void
+dynafont_set_cursor (dynafont_t df, int standout)
+{
+ int height = (df->font->bbox.height > 32) ? 32 : df->font->bbox.height;
+
+ df->cursor_standout = standout;
+
+ if (df == active_dynafont)
+ {
+ if (standout)
+ vga_set_cursor_size (1, -1);
+ else
+ vga_set_cursor_size ((height >= 2) ? height - 2 : 0, -1);
+ }
+}
+
+
+/* Load the VGA font to the card and make it active. */
+void
+dynafont_activate (dynafont_t df)
+{
+ int height = (df->font->bbox.height > 32) ? 32 : df->font->bbox.height;
+
+ vga_write_font_buffer (0, 0, (char *) df->vga_font,
+ df->size * VGA_FONT_HEIGHT);
+ vga_select_font_buffer (0, (df->size == 512) ? 1 : 0);
+
+ /* XXX Changing the font height below 13 or above 16 will cause
+ display problems for the user if we don't also program the video
+ mode timings. The standard font height for 80x25 is 16. */
+ vga_set_font_height (height);
+ vga_set_font_width (df->font->bbox.width % 8 ? 9 : 8);
+
+ active_dynafont = df;
+ dynafont_set_cursor (df, df->cursor_standout);
+}
+
+
+#if 0
+/* XXX This code is deactivated because it needs to be changed to
+ allow the italic and bold code, too. */
+
+/* Change the font used by dynafont DF to FONT. This transformation
+ is initially loss-less, if the new font can't display some
+ characters on the screen, you can always go back to a font that
+ does and get the glyphs for those characters back. (However, the
+ comments in dynafont_lookup hold for glyphs looked up after the font
+ change.) */
+void
+dynafont_change_font (dynafont_t df, bdf_font_t font)
+{
+ int i;
+
+ df->font = font;
+ for (i = 0; i < df->size; i++)
+ {
+ /* If we don't derive the unknown or space glyph from the font,
+ we don't update it. */
+#ifndef ENCODING_UNKNOWN
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+ if (! df->charmap_data[i].refs)
+ {
+ /* The glyph is not used. If it is mapped, we need to
+ remove the mapping to invalidate the glyph. */
+ if (df->charmap_data[i].locp)
+ {
+
+ hurd_ihash_locp_remove (&df->charmap, df->charmap_data[i].locp);
+ df->charmap_data[i].locp = NULL;
+ }
+ }
+
+ else
+ {
+ /* The glyph is mapped and in use. We will not destroy the
+ mapping, but just override the glyph in the VGA font.
+ This way the user can recover from loading a bad font by
+ going back to a better one. */
+ struct bdf_glyph *glyph;
+ glyph = bdf_find_glyph (df->font,
+ (int) df->charmap_data[i].character, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1,
+ (int) df->charmap_data[i].character);
+ if (!glyph)
+ {
+#ifdef ENCODING_UNKNOWN
+ /* The new font doesn't have a representation for the
+ unknown glyph at the desired place, so keep the old
+ one. XXX Should load the built-in one here. */
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+ memcpy (df->vga_font[i], df->vga_font[FONT_INDEX_UNKNOWN], 32);
+ }
+ else
+ {
+ /* XXX Take font size and glyph size into account. */
+ for (int j = 0; j < ((glyph->bbox.height > 32)
+ ? 32 : glyph->bbox.height); j++)
+ df->vga_font[i][j]
+ = glyph->bitmap[j * ((glyph->bbox.width + 7) / 8)];
+ if (glyph->bbox.height < 32)
+ memset (((char *) df->vga_font[i]) + glyph->bbox.height,
+ 0, 32 - glyph->bbox.height);
+ }
+ }
+ }
+
+ if (active_dynafont == df)
+ /* Refresh the card info. */
+ dynafont_activate (df);
+}
+#endif
diff --git a/console-client/vga-dynafont.h b/console-client/vga-dynafont.h
new file mode 100644
index 00000000..c2bab700
--- /dev/null
+++ b/console-client/vga-dynafont.h
@@ -0,0 +1,83 @@
+/* vga-dynafont.h - Interface to the dynamic font handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_DYNAFONT_H_
+#define _VGA_DYNAFONT_H_ 1
+
+#include <wchar.h>
+
+#include "bdf.h"
+
+
+/* The dynafont interface does not do locking on its own, for maximum
+ efficiency it relies on locking by the caller (because usually the
+ caller has some other data structures to lock along with the
+ dynafont. However, it is safe to call two functions on different
+ dynafonts asynchronously. */
+typedef struct dynafont *dynafont_t;
+
+/* The representation for the unknown glyph is always at the same
+ location. */
+#define FONT_INDEX_UNKNOWN 0
+
+/* Create a new dynafont object, which uses glyphs from the font FONT
+ (which must be 8 pixels wide and up to 32 pixels heigh). SIZE is
+ either 256 or 512, and specifies the number of available glyphs in
+ the font cache. The object is returned in DYNAFONT. The caller
+ must ensure the integrity of FONT until the object is destroyed or
+ the font is changed with dynafont_change_font. */
+error_t dynafont_new (bdf_font_t font, bdf_font_t font_italic,
+ bdf_font_t font_bold, bdf_font_t font_bold_italic,
+ int size, dynafont_t *dynafont);
+
+/* Release a dynafont object and its associated resources. */
+void dynafont_free (dynafont_t df);
+
+/* Look up the vga font index for an UCS-4 character. If not already
+ mapped, try to find space for a new entry and add the mapping.
+ Acquires an additional reference to the character. Might return
+ the glyph for the unrepresentable character if the glyph is ot
+ available for this character or no free slot is available right
+ now. In the former case, some information gets lost (to do
+ otherwise, one would have to either assign one of the scarce font
+ indices to each undisplayable character value on screen, or to
+ store the whole scrollback buffer as wide chars as well to recover
+ the lost info from that copy of the original text. */
+int dynafont_lookup (dynafont_t df, conchar_t *chr);
+
+/* Release a reference to the glyph VGA_FONT_INDEX in dynafont DF. */
+void dynafont_release (dynafont_t df, int vga_font_index);
+
+/* Load the VGA font to the card and make it active. */
+void dynafont_activate (dynafont_t df);
+
+/* Set the cursor to normal if STANDOUT is zero, or to a block cursor
+ otherwise. */
+void dynafont_set_cursor (dynafont_t df, int standout);
+
+/* Change the font used by dynafont DF to FONT. This transformation
+ is initially loss-less, if the new font can't display some
+ characters on the screen, you can always go back to a font that
+ does and get the glyphs for those characters back. (However, the
+ comments in dynafont_lookup hold for glyphs looked up after the font
+ change.) */
+void dynafont_change_font (dynafont_t df, bdf_font_t font);
+
+#endif /* _VGA_DYNAFONT_H_ */
diff --git a/console-client/vga-hw.h b/console-client/vga-hw.h
new file mode 100644
index 00000000..7275b03e
--- /dev/null
+++ b/console-client/vga-hw.h
@@ -0,0 +1,139 @@
+/* vga-hw.h - Definitions for the VGA hardware.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_HW_H_
+#define _VGA_HW_H_ 1
+
+#define VGA_VIDEO_MEM_BASE_ADDR 0x0b8000
+#define VGA_VIDEO_MEM_LENGTH 0x004000
+
+#define VGA_FONT_BUFFER 8
+#define VGA_FONT_SIZE 256
+#define VGA_FONT_HEIGHT 32
+#define VGA_FONT_LGC_BEGIN 0xc0
+#define VGA_FONT_LGC_COUNT 32
+
+#define VGA_MIN_REG 0x3c0
+#define VGA_MAX_REG 0x3df
+
+/* The sequencer address register selects the sub-register of the
+ sequencer that is accessed through the sequencer data register. */
+#define VGA_SEQ_ADDR_REG 0x3c4
+#define VGA_SEQ_DATA_REG 0x3c5
+
+/* The reset subregister can be used to asynchronously or
+ synchronously halt or clear the sequencer. */
+#define VGA_SEQ_RESET_ADDR 0x00
+#define VGA_SEQ_RESET_ASYNC 0x10 /* Can cause loss of video data. */
+#define VGA_SEQ_RESET_SYNC 0x01
+#define VGA_SEQ_RESET_CLEAR 0x11 /* Sequencer can operate. */
+
+/* The clocking mode subregister. */
+#define VGA_SEQ_CLOCK_MODE_ADDR 0x01
+#define VGA_SEQ_CLOCK_MODE_8 0x01 /* 8-pixel width for fonts. */
+
+/* The map subregister specifies which planes are written to. */
+#define VGA_SEQ_MAP_ADDR 0x02
+#define VGA_SEQ_MAP_PLANE0 0x01
+#define VGA_SEQ_MAP_PLANE1 0x02
+#define VGA_SEQ_MAP_PLANE2 0x04
+#define VGA_SEQ_MAP_PLANE3 0x08
+
+/* The font subregister. */
+#define VGA_SEQ_FONT_ADDR 0x03
+
+/* The memory mode subregister specifies the way that memory is
+ accessed. */
+#define VGA_SEQ_MODE_ADDR 0x04
+#define VGA_SEQ_MODE_EXT 0x02 /* Access 265kB rather than 64kB. */
+#define VGA_SEQ_MODE_SEQUENTIAL 0x04 /* Sequential, not odd/even addr. */
+#define VGA_SEQ_MODE_CHAIN4 0x08 /* Chain 4 addressing. */
+
+
+/* The graphics address register selects the sub-register that is
+ accessed through the graphics data register. */
+#define VGA_GFX_ADDR_REG 0x3ce
+#define VGA_GFX_DATA_REG 0x3cf
+
+/* The map subregister selects the plane to read from. */
+#define VGA_GFX_MAP_ADDR 0x04
+#define VGA_GFX_MAP_PLANE0 0x00
+#define VGA_GFX_MAP_PLANE1 0x01
+#define VGA_GFX_MAP_PLANE2 0x02
+#define VGA_GFX_MAP_PLANE3 0x03
+
+/* The mode subregister selects the memory access mode. */
+#define VGA_GFX_MODE_ADDR 0x05
+#define VGA_GFX_MODE_SHIFT256 0x40
+#define VGA_GFX_MODE_SHIFT 0x20
+#define VGA_GFX_MODE_HOSTOE 0x10
+#define VGA_GFX_MODE_READ0 0x00
+#define VGA_GFX_MODE_READ1 0x08
+#define VGA_GFX_MODE_WRITE0 0x00
+#define VGA_GFX_MODE_WRITE1 0x01
+#define VGA_GFX_MODE_WRITE2 0x02
+#define VGA_GFX_MODE_WRITE3 0x03
+
+/* The miscellaneous subregister. */
+#define VGA_GFX_MISC_ADDR 0x06
+#define VGA_GFX_MISC_GFX 0x01 /* Switch on graphics mode. */
+#define VGA_GFX_MISC_CHAINOE 0x02
+#define VGA_GFX_MISC_A0TOBF 0x00
+#define VGA_GFX_MISC_A0TOAF 0x04
+#define VGA_GFX_MISC_B0TOB7 0x08
+#define VGA_GFX_MISC_B8TOBF 0x0c
+
+
+/* The CRTC Registers. XXX Depends on the I/O Address Select field.
+ However, the only need to use the other values is for compatibility
+ with monochrome adapters. */
+#define VGA_CRT_ADDR_REG 0x3d4
+#define VGA_CRT_DATA_REG 0x3d5
+
+/* The maximum scan line subregister. */
+#define VGA_CRT_MAX_SCAN_LINE 0x09
+
+/* The cursor start subregister. */
+#define VGA_CRT_CURSOR_START 0x0a
+#define VGA_CRT_CURSOR_DISABLE 0x20
+
+/* The cursor end subregister. */
+#define VGA_CRT_CURSOR_END 0x0b
+
+/* The cursor position subregisters. */
+#define VGA_CRT_CURSOR_HIGH 0x0e
+#define VGA_CRT_CURSOR_LOW 0x0f
+
+
+/* The DAC Registers. */
+#define VGA_DAC_WRITE_ADDR_REG 0x3c8
+#define VGA_DAC_READ_ADDR_REG 0x3c7
+#define VGA_DAC_DATA_REG 0x3c9
+
+
+/* The Attribute Registers. */
+#define VGA_ATTR_ADDR_DATA_REG 0x3c0
+#define VGA_ATTR_DATA_READ_REG 0x3c1
+
+
+/* Other junk. */
+#define VGA_INPUT_STATUS_1_REG 0x3da
+
+#endif /* _VGA_HW_H_ */
diff --git a/console-client/vga-support.c b/console-client/vga-support.c
new file mode 100644
index 00000000..2837a6e0
--- /dev/null
+++ b/console-client/vga-support.c
@@ -0,0 +1,442 @@
+/* vga-support.c - VGA hardware access.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <string.h>
+
+#include "vga-hw.h"
+#include "vga-support.h"
+
+
+/* The base of the video memory mapping. */
+char *vga_videomem;
+
+/* The saved state of the VGA card. */
+struct vga_state
+{
+ unsigned char seq_clock_mode;
+ unsigned char seq_map;
+ unsigned char seq_font;
+ unsigned char seq_mode;
+
+ unsigned char gfx_map;
+ unsigned char gfx_mode;
+ unsigned char gfx_misc;
+
+ unsigned char crt_max_scan_line;
+ unsigned char crt_cursor_start;
+ unsigned char crt_cursor_end;
+ unsigned char crt_cursor_high;
+ unsigned char crt_cursor_low;
+
+ char videomem[2 * 80 * 25];
+ unsigned char fontmem[2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT];
+};
+
+static struct vga_state *vga_state;
+
+
+error_t
+vga_init (void)
+{
+ error_t err;
+ int fd;
+
+ /* Acquire I/O port access. */
+ if (ioperm (VGA_MIN_REG, VGA_MAX_REG - VGA_MIN_REG + 1, 1) < 0)
+ {
+ /* GNU Mach v1 is broken in that it doesn't implement an I/O
+ perm interface and just allows all tasks to access any I/O
+ port. */
+ if (errno != EMIG_BAD_ID && errno != ENOSYS)
+ {
+ free (vga_state);
+ return errno;
+ }
+ }
+
+ fd = open ("/dev/mem", O_RDWR);
+ if (fd >= 0)
+ {
+ vga_videomem = mmap (0, VGA_VIDEO_MEM_LENGTH, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, VGA_VIDEO_MEM_BASE_ADDR);
+ err = errno;
+ close (fd);
+ if (vga_videomem == (void *) -1)
+ return err;
+ }
+ else
+ return errno;
+
+ /* Save the current state. */
+ vga_state = malloc (sizeof (*vga_state));
+ if (!vga_state)
+ return errno;
+
+ outb (VGA_SEQ_CLOCK_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_clock_mode = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_map = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_FONT_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_font = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_mode = inb (VGA_SEQ_DATA_REG);
+
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ vga_state->gfx_map = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ vga_state->gfx_mode = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ vga_state->gfx_misc = inb (VGA_GFX_DATA_REG);
+
+ outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG);
+ vga_state->crt_max_scan_line = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_start = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_end = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_high = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_low = inb (VGA_CRT_DATA_REG);
+
+ /* Read/write in interleaved mode. */
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (VGA_GFX_MISC_CHAINOE | VGA_GFX_MISC_B8TOBF, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb (VGA_GFX_MODE_HOSTOE, VGA_GFX_DATA_REG);
+
+ memcpy (vga_state->videomem, vga_videomem, 2 * 80 * 25);
+ vga_read_font_buffer (0, 0, vga_state->fontmem,
+ 2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT);
+
+ /* 80 cols, 25 rows, two bytes per cell and twice because with lower
+ max scan line we get more lines on the screen. */
+ memset (vga_videomem, 0, 80 * 25 * 2 * 2);
+
+ return 0;
+}
+
+
+/* Release the resources and privileges associated with the VGA
+ hardware access. */
+void
+vga_fini (void)
+{
+ /* Recover the saved state. */
+ vga_write_font_buffer (0, 0, vga_state->fontmem,
+ 2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT);
+ memcpy (vga_videomem, vga_state->videomem, 2 * 80 * 25);
+
+ /* Restore the registers. */
+ outb (VGA_SEQ_CLOCK_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_clock_mode, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_map, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_FONT_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_font, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_mode, VGA_SEQ_DATA_REG);
+
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ outb (vga_state->gfx_map, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb (vga_state->gfx_mode, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (vga_state->gfx_misc, VGA_GFX_DATA_REG);
+
+ outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_max_scan_line, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_start, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_end, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_high, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_low, VGA_CRT_DATA_REG);
+
+ ioperm (VGA_MIN_REG, VGA_MAX_REG - VGA_MIN_REG + 1, 0);
+ munmap (vga_videomem, VGA_VIDEO_MEM_LENGTH);
+}
+
+
+/* Access the font buffer BUFFER, starting from glyph INDEX, and
+ either read DATALEN bytes into DATA (if WRITE is 0) or write
+ DATALEN bytes from DATA (if WRITE is not 0). */
+static void
+vga_read_write_font_buffer (int write, int buffer, int index,
+ char *data, size_t datalen)
+{
+ char saved_seq_map;
+ char saved_seq_mode;
+ char saved_gfx_map;
+ char saved_gfx_mode;
+ char saved_gfx_misc;
+
+ int offset = buffer * VGA_FONT_SIZE + index * VGA_FONT_HEIGHT;
+ assert (offset >= 0 && offset + datalen <= VGA_VIDEO_MEM_LENGTH);
+
+ /* Select plane 2 for sequential writing. You might think it is not
+ necessary for reading, but it is. Likewise for read settings
+ when writing. Joy. */
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ saved_seq_map = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MAP_PLANE2, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ saved_seq_mode = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_SEQUENTIAL | VGA_SEQ_MODE_EXT, VGA_SEQ_DATA_REG);
+
+ /* Read sequentially from plane 2. */
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_map = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MAP_PLANE2, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_mode = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_READ0, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_misc = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_B8TOBF, VGA_GFX_DATA_REG);
+
+ if (write)
+ memcpy (vga_videomem + offset, data, datalen);
+ else
+ memcpy (data, vga_videomem + offset, datalen);
+
+ /* Restore sequencer and graphic register values. */
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ outb (saved_seq_map, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ outb (saved_seq_mode, VGA_SEQ_DATA_REG);
+
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_map, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_mode, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_misc, VGA_GFX_DATA_REG);
+}
+
+
+/* Write DATALEN bytes from DATA to the font buffer BUFFER, starting
+ from glyph INDEX. */
+void
+vga_write_font_buffer (int buffer, int index, char *data, size_t datalen)
+{
+ vga_read_write_font_buffer (1, buffer, index, data, datalen);
+}
+
+/* Read DATALEN bytes into DATA from the font buffer BUFFER, starting
+ from glyph INDEX. */
+void
+vga_read_font_buffer (int buffer, int index, char *data, size_t datalen)
+{
+ vga_read_write_font_buffer (0, buffer, index, data, datalen);
+}
+
+
+/* Set FONT_BUFFER_SUPP to FONT_BUFFER if the font is small. */
+void
+vga_select_font_buffer (int font_buffer, int font_buffer_supp)
+{
+ char font = ((font_buffer & 6) >> 1) | ((font_buffer & 1) << 4)
+ | ((font_buffer_supp & 6) << 1) | ((font_buffer_supp & 1) << 5);
+
+ outb (VGA_SEQ_FONT_ADDR, VGA_SEQ_ADDR_REG);
+ outb (font, VGA_SEQ_DATA_REG);
+}
+
+/* Set the font height in pixel. */
+void
+vga_set_font_height (int height)
+{
+ char saved;
+
+ outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG);
+ saved = inb (VGA_CRT_DATA_REG);
+ saved &= ~31;
+ saved |= (height - 1) & 31;
+ outb (saved, VGA_CRT_DATA_REG);
+}
+
+
+/* Get the font height in pixel. Can be 8 or 9. */
+int
+vga_get_font_width (void)
+{
+ outb (VGA_SEQ_CLOCK_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ return (inb (VGA_SEQ_DATA_REG) & VGA_SEQ_CLOCK_MODE_8) ? 8 : 9;
+}
+
+/* Set the font height in pixel. WIDTH can be 8 or 9. */
+void
+vga_set_font_width (int width)
+{
+ char saved;
+
+ if (width != 8 && width != 9)
+ return;
+
+ outb (VGA_SEQ_CLOCK_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ saved = inb (VGA_SEQ_DATA_REG);
+ if (width == 8)
+ saved |= VGA_SEQ_CLOCK_MODE_8;
+ else
+ saved &= ~VGA_SEQ_CLOCK_MODE_8;
+ outb (saved, VGA_SEQ_DATA_REG);
+}
+
+
+/* Enable (if ON is true) or disable (otherwise) the cursor. Expects
+ the VGA hardware to be locked. */
+void
+vga_display_cursor (int on)
+{
+ char crs_start;
+
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ crs_start = inb (VGA_CRT_DATA_REG);
+ if (on)
+ crs_start &= ~VGA_CRT_CURSOR_DISABLE;
+ else
+ crs_start |= VGA_CRT_CURSOR_DISABLE;
+ outb (crs_start, VGA_CRT_DATA_REG);
+}
+
+
+/* Set cursor size from START to END (set to -1 to not set one of the
+ values). */
+void
+vga_set_cursor_size (int start, int end)
+{
+ char saved;
+
+ if (start >= 0)
+ {
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ saved = inb (VGA_CRT_DATA_REG);
+ saved &= ~31;
+ saved |= start & 31;
+ outb (saved, VGA_CRT_DATA_REG);
+ }
+ if (end >= 0)
+ {
+ outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG);
+ saved = inb (VGA_CRT_DATA_REG);
+ saved &= ~31;
+ saved |= end & 31;
+ outb (saved, VGA_CRT_DATA_REG);
+ }
+}
+
+
+/* Set the cursor position to POS, which is (x_pos + y_pos * width). */
+void
+vga_set_cursor_pos (unsigned int pos)
+{
+ outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG);
+ outb (pos >> 8, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG);
+ outb (pos & 0xff, VGA_CRT_DATA_REG);
+}
+
+
+/* Read NR entries from the color palette, starting from INDEX. DATA
+ must be able to hold at least 3 * NR bytes and will contain the
+ desired colors in RGB form. Only the lower six bits of each
+ component are significant. */
+void
+vga_read_palette (unsigned char index, unsigned char *data, int nr)
+{
+ /* Every color has three components. */
+ nr *= 3;
+
+ outb (index, VGA_DAC_READ_ADDR_REG);
+ while (nr--)
+ *(data++) = inb (VGA_DAC_DATA_REG);
+}
+
+
+/* Write NR entries to the color palette, starting from INDEX. DATA
+ must be at least 3 * NR of bytes long and contains the desired
+ colors in RGB form. Only the lower six bits for each component are
+ significant. */
+void
+vga_write_palette (unsigned char index, const unsigned char *data, int nr)
+{
+ /* Every color has three components. */
+ nr *= 3;
+
+ outb (index, VGA_DAC_WRITE_ADDR_REG);
+ while (nr--)
+ outb (*(data++), VGA_DAC_DATA_REG);
+}
+
+
+/* Exchange NR entries in the internal palette with the values in
+ PALETTE_ATTR, starting from the internal palette entry INDEX (which
+ can be betweern 0 and 15). Only the lower six bits of each entry
+ in PALETTE_ATTR is significant.
+
+ The internal palette entry is used to look up a color in the
+ palette for the color attribute in text mode with the corresponding
+ value.
+
+ Example: The attribute byte specifies 3 as the foreground color.
+ This means that the character with this attribute gets the color of
+ the palette entry specified by the internal palette entry 3 (the
+ fourth one). */
+void
+vga_exchange_palette_attributes (unsigned char index,
+ unsigned char *palette_attr,
+ int nr)
+{
+ if (!nr)
+ return;
+
+ /* We want to read and change the palette attribute register. */
+ while (nr--)
+ {
+ unsigned char attr;
+
+ /* Side effect of reading the input status #1 register is to
+ reset the attribute mixed address/data register so that the
+ next write it expects is the address, not the data. */
+ inb (VGA_INPUT_STATUS_1_REG);
+
+ /* Set the address. */
+ outb (index++, VGA_ATTR_ADDR_DATA_REG);
+ attr = inb (VGA_ATTR_DATA_READ_REG);
+ outb ((attr & ~077) | (*palette_attr & 077), VGA_ATTR_ADDR_DATA_REG);
+ *(palette_attr++) = attr & 077;
+ }
+
+ /* Re-enable the screen, which was blanked during the palette
+ operation. */
+ inb (VGA_INPUT_STATUS_1_REG);
+ outb (0x20, VGA_ATTR_ADDR_DATA_REG);
+ outb (0x00, VGA_ATTR_ADDR_DATA_REG);
+}
diff --git a/console-client/vga-support.h b/console-client/vga-support.h
new file mode 100644
index 00000000..38c6248f
--- /dev/null
+++ b/console-client/vga-support.h
@@ -0,0 +1,89 @@
+/* vga-support.h - Interface for VGA hardware access.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_SUPPORT_H_
+#define _VGA_SUPPORT_H_ 1
+
+#include <errno.h>
+#include <sys/types.h>
+
+
+/* The VGA interface does not do locking on its own, for maximum
+ efficiency it relies on locking by the caller (because usually the
+ caller has some other data structures to lock along with the
+ VGA hardware. */
+
+/* The mapped video memory. */
+extern char *vga_videomem;
+
+/* Initialize the VGA hardware and set up the permissions and memory
+ mappings. */
+error_t vga_init (void);
+
+/* Release the resources and privileges associated with the VGA
+ hardware access. */
+void vga_fini (void);
+
+/* Write DATALEN bytes from DATA to the font buffer BUFFER, starting
+ from glyph index. */
+void vga_write_font_buffer (int buffer, int index,
+ char *data, size_t datalen);
+
+/* Read DATALEN bytes into DATA from the font buffer BUFFER, starting
+ from glyph INDEX. */
+void vga_read_font_buffer (int buffer, int index,
+ char *data, size_t datalen);
+
+/* Set FONT_BUFFER_SUPP to FONT_BUFFER if the font is small. */
+void vga_select_font_buffer (int font_buffer, int font_buffer_supp);
+
+/* Set the font height in pixel. */
+void vga_set_font_height (int height);
+
+/* Get the font height in pixel. Can be 8 or 9. */
+int vga_get_font_width (void);
+
+/* Set the font height in pixel. WIDTH can be 8 or 9. */
+void vga_set_font_width (int width);
+
+/* Enable (if ON is true) or disable (otherwise) the cursor. Expects
+ the VGA hardware to be locked. */
+void vga_display_cursor (int on);
+
+/* Set cursor size from START to END (set to -1 to not set one of the
+ values). */
+void vga_set_cursor_size (int start, int end);
+
+/* Set the cursor position to POS, which is (x_pos + y_pos *
+ width). */
+void vga_set_cursor_pos (unsigned int pos);
+
+/* Read NR entries from the color palette, starting from INDEX. */
+void vga_read_palette (unsigned char index, unsigned char *data, int nr);
+
+/* Write NR entries to the color palette, starting from INDEX. */
+void vga_write_palette (unsigned char index,
+ const unsigned char *data, int nr);
+
+void vga_exchange_palette_attributes (unsigned char index,
+ unsigned char *saved_palette_attr,
+ int nr);
+
+#endif /* _VGA_SUPPORT_H_ */
diff --git a/console-client/vga.c b/console-client/vga.c
new file mode 100644
index 00000000..9e8abb3a
--- /dev/null
+++ b/console-client/vga.c
@@ -0,0 +1,840 @@
+/* vga.c - The VGA device display driver.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <iconv.h>
+#include <argp.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <sys/io.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <cthreads.h>
+#include <hurd/console.h>
+
+#include "driver.h"
+#include "timer.h"
+
+#include "vga-hw.h"
+#include "vga-support.h"
+#include "bdf.h"
+#include "vga-dynafont.h"
+#include "vga-dynacolor.h"
+#include "unicode.h"
+
+
+#define VGA_DISP_WIDTH 80
+#define VGA_DISP_HEIGHT 25
+
+/* The font file. */
+#define DEFAULT_VGA_FONT DEFAULT_VGA_FONT_DIR "vga-system.bdf"
+static char *vga_display_font;
+
+#define DEFAULT_VGA_FONT_ITALIC DEFAULT_VGA_FONT_DIR "vga-system-italic.bdf"
+static char *vga_display_font_italic;
+
+#define DEFAULT_VGA_FONT_BOLD DEFAULT_VGA_FONT_DIR "vga-system-bold.bdf"
+static char *vga_display_font_bold;
+
+#define DEFAULT_VGA_FONT_BOLD_ITALIC \
+ DEFAULT_VGA_FONT_DIR "vga-system-bold-italic.bdf"
+static char *vga_display_font_bold_italic;
+
+/* If false use all colors, else use double font slots. */
+static int vga_display_max_glyphs;
+
+/* The timer used for flashing the screen. */
+static struct timer_list vga_display_timer;
+
+/* The lock that protects the color palette manipulation. */
+static struct mutex vga_display_lock;
+
+/* Forward declaration. */
+static struct display_ops vga_display_ops;
+
+/* The current width and height the ncursesw driver is using. */
+static unsigned int current_width;
+static unsigned int current_height;
+
+/* The cursor state to restore the state to. */
+static int cursor_state;
+
+/* Is set to 1 if the cursor moved out of the physical screen and the
+ cursor state should be hidden. */
+static int cursor_hidden;
+
+struct refchr
+{
+ unsigned int used : 1;
+ unsigned int chr : 9;
+ unsigned int attr : 8;
+};
+
+
+typedef struct vga_mousecursor
+{
+ float posx;
+ float posy;
+ char oldcolor;
+ int visible;
+ int enabled;
+} vga_mousecursor_t;
+
+struct vga_display
+{
+ /* The VGA font for this display. */
+ dynafont_t df;
+ int df_size;
+
+ /* The color palette. */
+ dynacolor_t dc;
+
+ unsigned int width;
+ unsigned int height;
+
+ /* Current attribute. */
+ int cur_conchar_attr_init;
+ conchar_attr_t cur_conchar_attr;
+ char cur_attr;
+
+ /* The state of the mouse cursor. */
+ vga_mousecursor_t mousecursor;
+
+ /* Remember for each cell on the display the glyph written to it and
+ the colors (in the upper byte) assigned. 0 means unassigned. */
+
+ struct refchr refmatrix[VGA_DISP_HEIGHT][VGA_DISP_WIDTH];
+};
+
+
+static void
+vga_display_invert_border (void)
+{
+ unsigned char col[3];
+
+ mutex_lock (&vga_display_lock);
+ vga_read_palette (0, col, 1);
+ col[0] = 0xff - col[0];
+ col[1] = 0xff - col[1];
+ col[2] = 0xff - col[2];
+ vga_write_palette (0, col, 1);
+ mutex_unlock (&vga_display_lock);
+}
+
+
+static int
+vga_display_flash_off (void *dummy)
+{
+ vga_display_invert_border ();
+ return 0;
+}
+
+
+static error_t
+vga_display_flash (void *handle)
+{
+ if (timer_remove (&vga_display_timer))
+ vga_display_invert_border ();
+ vga_display_invert_border ();
+ vga_display_timer.expires = fetch_jiffies () + 10;
+ timer_add (&vga_display_timer);
+ return 0;
+}
+
+
+static void
+hide_mousecursor (struct vga_display *disp)
+{
+ char *oldpos = vga_videomem + 2 * ((int) disp->mousecursor.posy * disp->width
+ + (int) disp->mousecursor.posx) + 1;
+
+ if (!disp->mousecursor.visible)
+ return;
+
+ /* First remove the old cursor. */
+ *oldpos = disp->mousecursor.oldcolor;
+ disp->mousecursor.visible = 0;
+}
+
+
+static void
+draw_mousecursor (struct vga_display *disp)
+{
+ char *newpos = vga_videomem + 2 * ((int) disp->mousecursor.posy * disp->width
+ + (int) disp->mousecursor.posx) + 1;
+
+ if (disp->mousecursor.visible)
+ return;
+
+ /* Draw the new cursor. */
+ disp->mousecursor.oldcolor = *newpos;
+ *newpos = (127) ^ *newpos;
+
+ disp->mousecursor.visible = 1;
+}
+
+
+static const char doc[] = "VGA Driver";
+
+static const struct argp_option options[] =
+ {
+ {"font", 'f', "FONT", 0, "Use FONT for normal text"},
+ {"font-italic", 'i', "FONT", 0, "Use FONT for italic text"},
+ {"font-bold", 'b', "FONT", 0, "Use FONT for bold text"},
+ {"font-bold-italic",'a', "FONT", 0,
+ "Use FONT for text that is both bold and italic"},
+ {"max-colors", 'm', 0 , 0,
+ "Prefer a lot of colors above a lot of glyphs"},
+ {"max-glyphs", 'g', 0 , 0,
+ "Prefer a lot of glyphs above a lot of colors"},
+ { 0 }
+ };
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ int *pos = (int *) state->input;
+
+ switch (key)
+ {
+ case 'f':
+ vga_display_font = strdup (arg);
+ if (! vga_display_font)
+ return 0;
+ break;
+
+ case 'i':
+ vga_display_font_italic = strdup (arg);
+ if (! vga_display_font_italic)
+ return 0;
+ break;
+
+ case 'b':
+ vga_display_font_bold = strdup (arg);
+ if (! vga_display_font_bold)
+ return 0;
+ break;
+
+ case 'a':
+ vga_display_font_bold_italic = strdup (arg);
+ if (! vga_display_font_bold_italic)
+ return 0;
+ break;
+
+ case 'm':
+ vga_display_max_glyphs = 0;
+ break;
+
+ case 'g':
+ vga_display_max_glyphs = 1;
+ break;
+
+ case ARGP_KEY_END:
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ *pos = state->next;
+ return 0;
+}
+
+static struct argp argp = {options, parse_opt, 0, doc};
+
+/* Initialize the subsystem. */
+static error_t
+vga_display_init (void **handle, int no_exit, int argc, char *argv[],
+ int *next)
+{
+ error_t err;
+ struct vga_display *disp;
+ int pos = 1;
+
+ /* XXX Assert that we are called only once. */
+ mutex_init (&vga_display_lock);
+ timer_clear (&vga_display_timer);
+ vga_display_timer.fnc = &vga_display_flash_off;
+
+ /* Parse the arguments. */
+ err = argp_parse (&argp, argc, argv, ARGP_IN_ORDER | ARGP_NO_EXIT
+ | ARGP_SILENT, 0, &pos);
+ *next += pos - 1;
+ if (err && err != EINVAL)
+ return err;
+
+ /* Create and initialize the display structure as much as
+ possible. */
+ disp = calloc (1, sizeof *disp);
+ if (!disp)
+ return ENOMEM;
+
+ disp->df_size = vga_display_max_glyphs ? 512 : 256;
+ disp->width = VGA_DISP_WIDTH;
+ disp->height = VGA_DISP_HEIGHT;
+
+ *handle = disp;
+ return 0;
+}
+
+
+/* Start the driver. */
+static error_t
+vga_display_start (void *handle)
+{
+ error_t err;
+ struct vga_display *disp = handle;
+ bdf_font_t font = NULL;
+ bdf_font_t font_italic = NULL;
+ bdf_font_t font_bold = NULL;
+ bdf_font_t font_bold_italic = NULL;
+ FILE *font_file;
+
+ err = vga_init ();
+ if (err)
+ return err;
+
+ dynacolor_init ();
+
+#define LOAD_FONT(x,y) \
+ do { \
+ font_file = fopen (vga_display_##x ?: DEFAULT_VGA_##y, "r"); \
+ if (font_file) \
+ { \
+ bdf_error_t bdferr = bdf_read (font_file, &x, NULL); \
+ if (bdferr) \
+ x = NULL; \
+ else \
+ bdf_sort_glyphs (x); \
+ fclose (font_file); \
+ } \
+ } while (0)
+
+ LOAD_FONT (font, FONT);
+ LOAD_FONT (font_italic, FONT_ITALIC);
+ LOAD_FONT (font_bold, FONT_BOLD);
+ LOAD_FONT (font_bold_italic, FONT_BOLD_ITALIC);
+
+ err = dynafont_new (font, font_italic, font_bold, font_bold_italic,
+ disp->df_size, &disp->df);
+ if (err)
+ {
+ free (disp);
+ vga_fini ();
+ return err;
+ }
+ dynafont_activate (disp->df);
+
+ disp->dc = (disp->df_size == 512) ? dynacolor_init_8 : dynacolor_init_16;
+ dynacolor_activate (&disp->dc);
+
+ err = driver_add_display (&vga_display_ops, disp);
+ if (err)
+ {
+ dynafont_free (disp->df);
+ dynacolor_fini ();
+ vga_fini ();
+ free (disp);
+ }
+ return err;
+}
+
+
+/* Destroy the display HANDLE. */
+static error_t
+vga_display_fini (void *handle, int force)
+{
+ struct vga_display *disp = handle;
+ driver_remove_display (&vga_display_ops, disp);
+ if (timer_remove (&vga_display_timer))
+ vga_display_flash_off (0);
+
+ dynafont_free (disp->df);
+ free (disp);
+ dynacolor_fini ();
+ vga_fini ();
+ if (vga_display_font)
+ free (vga_display_font);
+ if (vga_display_font_italic)
+ free (vga_display_font_italic);
+ if (vga_display_font_bold)
+ free (vga_display_font_bold);
+ if (vga_display_font_bold_italic)
+ free (vga_display_font_bold_italic);
+
+ return 0;
+}
+
+
+static void
+vga_display_restore_status (void *handle)
+{
+ /* Read/write in interleaved mode. This is not preserved by the
+ XFree VESA driver. */
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (VGA_GFX_MISC_CHAINOE | VGA_GFX_MISC_B8TOBF, VGA_GFX_DATA_REG);
+}
+
+
+/* Set the cursor's state to STATE on display HANDLE. */
+static error_t
+vga_display_set_cursor_status (void *handle, uint32_t state)
+{
+ struct vga_display *disp = handle;
+
+ /* Don't display the cursor if its location is not within the
+ physical screen. */
+ if (!cursor_hidden)
+ {
+ if (state != CONS_CURSOR_INVISIBLE)
+ dynafont_set_cursor (disp->df,
+ state == CONS_CURSOR_VERY_VISIBLE ? 1 : 0);
+
+ vga_display_cursor (state == CONS_CURSOR_INVISIBLE ? 0 : 1);
+ }
+
+ cursor_state = state;
+
+ return 0;
+}
+
+
+/* Set the cursor's position on display HANDLE to column COL and row
+ ROW. */
+static error_t
+vga_display_set_cursor_pos (void *handle, uint32_t col, uint32_t row)
+{
+ struct vga_display *disp = handle;
+ unsigned int pos = row * disp->width + col;
+
+ /* Make sure the cursor can only be moved to a position on te
+ physical screen. */
+ if (col < disp->width && row < disp->height)
+ {
+ vga_set_cursor_pos (pos);
+ if (cursor_hidden)
+ {
+ /* Restore the cursor. */
+ cursor_hidden = 0;
+ vga_display_set_cursor_status (handle, cursor_state);
+ }
+ }
+ else if (!cursor_hidden)
+ {
+ /* Hide the cursor. */
+ cursor_hidden = 1;
+ vga_display_cursor (CONS_CURSOR_INVISIBLE);
+ }
+
+ return 0;
+}
+
+
+/* Scroll the display by the desired amount. The area that becomes
+ free will be filled in a subsequent write call. */
+static error_t
+vga_display_scroll (void *handle, int delta)
+{
+ struct vga_display *disp = handle;
+ int count = abs(delta) * disp->width;
+ int i;
+ struct refchr *refpos;
+
+ hide_mousecursor (disp);
+
+ /* XXX: If the virtual console is bigger than the physical console it is
+ impossible to scroll because the data to scroll is not in memory. */
+ if (current_height > disp->height)
+ return ENOTSUP;
+
+ if (delta > 0)
+ {
+ memmove (vga_videomem, vga_videomem + 2 * count,
+ 2 * disp->width * (disp->height - delta));
+ refpos = &disp->refmatrix[0][0];
+ }
+ else
+ {
+ memmove (vga_videomem + 2 * count, vga_videomem,
+ 2 * disp->width * (disp->height + delta));
+ refpos = &disp->refmatrix[disp->height + delta][0];
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (refpos->used)
+ {
+ dynafont_release (disp->df, refpos->chr);
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_release (disp->dc, refpos->attr & 7);
+ dynacolor_release (disp->dc, (refpos->attr >> 4) & 7);
+ }
+ refpos++;
+ }
+
+ if (delta > 0)
+ {
+ memmove (&disp->refmatrix[0][0], &disp->refmatrix[0][0] + count,
+ sizeof (struct refchr) * disp->width * (disp->height - delta));
+ refpos = &disp->refmatrix[disp->height - delta][0];
+ }
+ else
+ {
+ memmove (&disp->refmatrix[0][0] + count, &disp->refmatrix[0][0],
+ sizeof (struct refchr) * disp->width * (disp->height + delta));
+ refpos = &disp->refmatrix[0][0];
+ }
+
+ for (i = 0; i < count; i++)
+ (refpos++)->used = 0;
+
+ return 0;
+}
+
+#if 0
+/* Change the font on the console CONSOLE to font. The old font will
+ not be accessed by the vga console subsystem anymore after this
+ call completed. */
+static void
+vga_display_change_font (void *handle, bdf_font_t font)
+{
+ struct vga_display *disp = handle;
+
+ dynafont_change_font (disp->df, font);
+}
+#endif
+
+
+static inline char
+vga_display_recalculate_attr (dynacolor_t *dc, conchar_attr_t attr)
+{
+ char vga_attr;
+ signed char res_fgcol;
+ signed char res_bgcol;
+ signed char fgcol;
+ signed char bgcol;
+
+ /* VGA has way too few bits for this stuff. The highest background
+ color bit is also the blinking bit if blinking is enabled. The
+ highest foreground color bit is the font selector bit,
+ unfortunately. Underlining is enabled if foreground is ?001 and
+ background ?000. */
+
+ /* Reversed means colors are reversed. Note that this does not
+ reverse the intensity. */
+ if (attr.reversed)
+ {
+ fgcol = attr.bgcol;
+ bgcol = attr.fgcol;
+ }
+ else
+ {
+ fgcol = attr.fgcol;
+ bgcol = attr.bgcol;
+ }
+
+ /* Set the foreground color. */
+ if (attr.concealed)
+ fgcol = bgcol;
+ else
+ {
+ /* Intensity bold and dim also affect the font selection bit. */
+ switch (attr.intensity)
+ {
+ case CONS_ATTR_INTENSITY_BOLD:
+ fgcol |= 1 << 3;
+ break;
+ case CONS_ATTR_INTENSITY_DIM:
+ fgcol = CONS_COLOR_BLACK | 1 << 3;
+ break;
+ case CONS_ATTR_INTENSITY_NORMAL:
+ break;
+ }
+ }
+
+ /* Try to get the colors as desired. This might change the palette,
+ so we need to take the lock (in case a flash operation times
+ out). */
+ mutex_lock (&vga_display_lock);
+ res_bgcol = dynacolor_lookup (*dc, bgcol);
+ res_fgcol = dynacolor_lookup (*dc, fgcol);
+ mutex_unlock (&vga_display_lock);
+ if (res_bgcol == -1 || res_fgcol == -1)
+ dynacolor_replace_colors (dc, fgcol, bgcol, &res_fgcol, &res_bgcol);
+ vga_attr = res_bgcol << 4 | res_fgcol;
+
+ vga_attr |= attr.blinking << 7;
+
+ /* XXX We can support underlined in a monochrome mode. */
+ return vga_attr;
+}
+
+
+/* Deallocate any scarce resources occupied by the LENGTH characters
+ from column COL and row ROW. */
+static error_t
+vga_display_clear (void *handle, size_t length, uint32_t col, uint32_t row)
+{
+ struct vga_display *disp = handle;
+ struct refchr *refpos = &disp->refmatrix[row][0];
+ int cols;
+
+ /* The column can be outside the physical screen, in that case
+ adjust the position. */
+ if (col >= disp->width)
+ {
+ col = disp->width - col;
+ row++;
+ }
+ refpos += col;
+
+ /* The first row is not in the physical screen, nothing has to be
+ done. */
+ if (row >= disp->height)
+ return 0;
+
+ /* The length cannot be used. Recalculate it to wrap the lines. */
+ cols = length / current_width;
+ length = (length % current_width) + cols * disp->width ;
+
+ /* Make sure the end of length is still in the physical screen. */
+ if (length > (disp->width * disp->height - (row * disp->width + col)) - col)
+ length = disp->width * disp->height - (row * disp->width + col) - col;
+
+ while (length > 0)
+ {
+ if (refpos->used)
+ {
+ dynafont_release (disp->df, refpos->chr);
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_release (disp->dc, refpos->attr & 7);
+ dynacolor_release (disp->dc, (refpos->attr >> 4) & 7);
+ refpos->used = 0;
+ }
+ refpos++;
+ length--;
+ }
+ return 0;
+}
+
+/* Write the text STR with LENGTH characters to column COL and row
+ ROW. */
+static error_t
+vga_display_write (void *handle, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row)
+{
+ struct vga_display *disp = handle;
+ char *pos;
+ struct refchr *refpos = &disp->refmatrix[row][col];
+ char *mouse_cursor_pos;
+
+ /* The starting column is outside the physical screen. */
+ if (disp->width < current_width && col >= disp->width)
+ {
+ size_t skip = current_width - disp->width;
+ str += skip;
+ length -= skip;
+ col = 0;
+ row++;
+ }
+
+ pos = vga_videomem + 2 * (row * disp->width + col);
+ mouse_cursor_pos = (vga_videomem + 2
+ * ((int) disp->mousecursor.posy
+ * disp->width + (int) disp->mousecursor.posx) + 1);
+
+ /* Although all references to the current fgcol or bgcol could have
+ been released here, for example due to a scroll operation, we
+ know that the color slots have not been reused yet, as no routine
+ but ours does color allocation. This ensures that cur_attr is
+ still valid. XXX consider recalculating the attribute for more
+ authentic (but less homogenous) colors anyway. */
+
+ while (length--)
+ {
+ int charval = dynafont_lookup (disp->df, str);
+ col++;
+
+ /* The virtual console is smaller than the physical screen. */
+ if (col > current_width)
+ {
+ size_t skip = disp->width - current_width;
+ pos += skip * 2;
+ refpos += skip;
+ col = 1;
+ row++;
+ }
+ /* The virtual console is bigger than the physical console. */
+ else if (disp->width < current_width && col == disp->width)
+ {
+ size_t skip = current_width - disp->width;
+ str += skip;
+ length -= skip;
+ col = 1;
+ row++;
+ }
+
+ /* The screen is filled until the bottom of the screen. */
+ if (row >= disp->height)
+ return 0;
+
+ if (!disp->cur_conchar_attr_init
+ || *(uint32_t *) &disp->cur_conchar_attr != *(uint32_t *) &str->attr)
+ {
+ if (!disp->cur_conchar_attr_init)
+ disp->cur_conchar_attr_init = 1;
+ disp->cur_conchar_attr = str->attr;
+ disp->cur_attr = vga_display_recalculate_attr (&disp->dc, str->attr);
+ }
+ else
+ {
+ /* Add two references to the colors. See comment above for
+ why we can assume that this will succeed. */
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_add_ref (disp->dc, disp->cur_attr & 7);
+ dynacolor_add_ref (disp->dc, (disp->cur_attr >> 4) & 7);
+ }
+
+ *(pos++) = charval & 0xff;
+
+ if (pos == mouse_cursor_pos)
+ disp->mousecursor.visible = 0;
+
+ *(pos++) = disp->cur_attr
+ | (disp->df_size == 512 ? (charval >> 5) & 0x8 : 0);
+
+ /* Perform reference counting. */
+ if (refpos->used)
+ {
+ dynafont_release (disp->df, refpos->chr);
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_release (disp->dc, refpos->attr & 7);
+ dynacolor_release (disp->dc, (refpos->attr >> 4) & 7);
+ }
+ refpos->used = 1;
+ refpos->chr = charval;
+ refpos->attr = disp->cur_attr;
+ refpos++;
+
+ /* Wrap around displayed area. */
+ str++;
+ }
+ return 0;
+}
+
+static error_t
+vga_set_dimension (void *handle, unsigned int width, unsigned int height)
+{
+ if (current_width && current_height)
+ vga_display_clear (handle, current_width * current_height, 0, 0);
+
+ current_width = width;
+ current_height = height;
+
+ /* FIXME: Should support greater dimensions by changing the video
+ mode. */
+
+ return 0;
+}
+
+
+static error_t
+vga_display_update (void *handle)
+{
+ struct vga_display *disp = handle;
+
+ if (disp->mousecursor.enabled)
+ draw_mousecursor (disp);
+
+ return 0;
+}
+
+
+static error_t
+vga_set_mousecursor_pos (void *handle, float x, float y)
+{
+ struct vga_display *disp = handle;
+
+ /* If the mouse did not move from the character position, don't
+ bother about updating the cursor position. */
+ if (disp->mousecursor.visible && x == (int) disp->mousecursor.posx
+ && y == (int) disp->mousecursor.posy)
+ return 0;
+
+ hide_mousecursor (disp);
+
+ disp->mousecursor.posx = x;
+ disp->mousecursor.posy = y;
+
+ if (disp->mousecursor.enabled)
+ draw_mousecursor (disp);
+
+ return 0;
+}
+
+
+static error_t
+vga_set_mousecursor_status (void *handle, int status)
+{
+ struct vga_display *disp = handle;
+
+ disp->mousecursor.enabled = status;
+ if (!status)
+ hide_mousecursor (disp);
+ else
+ draw_mousecursor (disp);
+
+ return 0;
+}
+
+
+
+struct driver_ops driver_vga_ops =
+ {
+ vga_display_init,
+ vga_display_start,
+ vga_display_fini,
+ NULL,
+ vga_display_restore_status
+ };
+
+static struct display_ops vga_display_ops =
+ {
+ vga_display_set_cursor_pos,
+ vga_display_set_cursor_status,
+ vga_display_scroll,
+ vga_display_clear,
+ vga_display_write,
+ vga_display_update,
+ vga_display_flash,
+ NULL,
+ vga_set_dimension,
+ vga_set_mousecursor_pos,
+ vga_set_mousecursor_status
+ };
diff --git a/console/Makefile b/console/Makefile
new file mode 100644
index 00000000..3eb4252e
--- /dev/null
+++ b/console/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2002, 2012 Free Software Foundation, Inc.
+# Written by Marcus Brinkmann.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+
+dir := console
+makemode := server
+
+target = console
+
+SRCS = console.c display.c pager.c input.c
+LCLHDRS = display.h pager.h input.h priv.h mutations.h
+DIST_FILES = hurd.ti motd.UTF8
+
+MIGSTUBS = notifyServer.o tioctlServer.o fs_notifyUser.o
+
+HURDLIBS = netfs fshelp iohelp pager threads ports ihash shouldbeinlibc
+OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
+
+MIGSFLAGS += -imacros $(srcdir)/mutations.h
+
+# This is the old monolithic version of the console server.
+#SRCS = main.c vcons.c focus.c vga-display.c vga.c dynafont.c bdf.c
+#LCLHDRS = focus.h input-drv.h vcons.h display-drv.h vga.h vga-hw.h \
+# dynafont.h bdf.h mutations.h priv.h
+#
+#HURDLIBS = trivfs fshelp iohelp threads ports ihash shouldbeinlibc
+#OBJS = $(subst .c,.o,$(SRCS)) tioctlServer.o
+#
+#MIGSFLAGS += -imacros $(srcdir)/mutations.h
+
+include ../Makeconf
diff --git a/console/README.UTF8 b/console/README.UTF8
new file mode 100644
index 00000000..91901e1b
--- /dev/null
+++ b/console/README.UTF8
@@ -0,0 +1,143 @@
+
+The console server supports any encoding supported by iconv, but uses
+Unicode internally. The default encoding is ISO8859-1, another useful
+variant is UTF-8. To configure the console server to use UTF-8 you
+have to use the `--encoding' argument:
+
+# settrans -fg /dev/vcs /hurd/console --encoding=UTF-8
+
+If you actually try this, you will notice two problems:
+
+1. You can not enter the letters in your locale, because the keyboard
+doesn't have the right layout. Keyboard maps come later. For now,
+you have to help yourself with the direct input with RightAlt. Maybe
+I will put a simple compose key feature in the pc_kbd driver, so that
+some western locales can be used more easily.
+
+2. If you bother to look up the unicode hex code and enter it with
+AltGr, the font can not display it! If you are using the ncursesw
+driver, do you use it while you are logged in from a working UTF-8
+terminal? If not, then this is your problem. An ncurses driver for
+non-UTF-8 terminals is on the TODO list. But if you use the VGA
+driver, you need to load a different font.
+
+This is because by default, the vga driver just reads the VGA card
+memory and takes the font that is stored there. This font has a
+limited characterset (256 characters, many graphical symbols among
+that), so you won't get more than a few western characters with that.
+
+Unicode support
+===============
+
+But you want it all. You want to read Middle Old English. You want
+to read Thai. Your Korean spam. Georgian script. Hebrew. And you
+can have it.
+
+You need a Unicode font. There are good ones provided by Markus Kuhn,
+the UCS fonts. Get them here:
+
+http://www.cl.cam.ac.uk/~mgk25/download/ucs-fonts.tar.gz
+
+(See also the web page at http://www.cl.cam.ac.uk/~mgk25/ucs-fonts.html).
+
+Now, load the font by providing it with the --font option to the vga
+driver. I suggest only the 8x13 and the 9x15 fonts, but feel free to
+try others, too. Note that the VGA text mode can not really display 9
+pixel wide characters. But as most characters have the ninth column
+empty, and the VGA text mode can display an empty column between two
+adjacent character cells, this trick allows us to display most of the
+9x15 font correctly. So you won't notice a difference until you come
+to very broad characters or special symbols, where you will see that
+the last column is cut off. (BTW, I wrote the dynafont code carefully
+to still support horizontal line graphic characters properly in 9
+pixel wide fonts. This is done by exploiting some special modes in
+the VGA hardware. This is why in 512 (256) glyph mode and 9 pixel
+wide fonts, you are limited to 448 (224) normal characters: 64 (32)
+slots are reserved for the horizontal line graphic characters so they
+are drawn continuously.)
+
+So, try the following:
+
+# console -d vga --font 8x13.bdf -d pc_kbd -d generic_speaker /dev/vcs
+
+or
+
+# console -d vga --font 9x15.bdf -d pc_kbd -d generic_speaker /dev/vcs
+
+If you are satisfied, copy your default font to
+/lib/hurd/fonts/vga-system.bdf, where it will be picked up
+automatically in favor to the graphic card's font.
+
+More about fonts
+================
+
+While we are talking about fonts, try also the 8x13O font with
+--font-italic and 8x13B or 9x15B font with --font-bold. You can save
+them in /lib/hurd/fonts/vga-system-bold.bdf and
+/lib/hurd/fonts/vga-system-italic.bdf, too.
+
+To activate those fonts on your virtual console, try the following:
+
+# echo `tput sitm`Hello slanted world.`tput ritm`
+
+and
+
+# echo `tput gsbom`Hello bold world.`tput grbom`
+
+I hope you like what you see. Imagine this in emacs font-lock mode.
+
+
+Unicode, finally
+================
+
+There are a few more steps necessary to make your Unicode environment
+ready:
+
+Add a Unicode locale to /etc/locale.gen, and generate the locale
+information for that! For example, I am living in Germany, and
+normally use de_DE with the encoding ISO8859-1. My Unicode locale is
+de_DE.UTF-8, so I am adding that to /etc/locale.gen:
+
+de_DE.UTF-8 UTF-8
+
+and rerun locale-gen:
+
+# locale-gen
+
+See also /share/i18n/SUPPORTED. You can also do this more conveniently with
+
+# dpkg-reconfigure locales
+
+Once you generated this, make it your default locale:
+
+# export LANG=de_DE.UTF-8
+
+If you have also loaded the unicode font above, you are set up. Try
+for example to view the examples/ files in the ucs-fonts package with
+less.
+
+# less fonts/examples/UTF_8-demo.txt
+
+You should see most of that file with the 9x15 font (a bit less with
+the 8x13 font).
+
+You should be able to do the above process with other encodings than
+UTF-8. But you should _always_ use a Unicode font, because the
+console client uses Unicode internally for everything.
+
+Application specific notes
+==========================
+
+If you enter unicode characters at the shell, libreadline loses track
+of the number of characters displayed (it is not aware of multi-byte
+encodings like UTF-8). This is fixed in readline 4.3 (which is not
+yet in Debian).
+
+If you use mutt, install mutt-utf8. For lynx, edit /etc/lynx.cfg,
+making sure that CHARACTER_SET is set to utf-8.
+
+If you use other applications, try to search with google for
+"application-name utf8" or "application-name unicode". Often you find
+what you need. The issues are the same for the GNU/Hurd and GNU/Linux
+systems, so most of the information can be shared, except how to setup
+the system console to support Unicode, of course.
diff --git a/console/console.c b/console/console.c
new file mode 100644
index 00000000..0b1f42c4
--- /dev/null
+++ b/console/console.c
@@ -0,0 +1,2093 @@
+/* console.c -- A console server.
+
+ Copyright (C) 1997, 1999, 2002, 2003, 2007, 2008, 2010
+ Free Software Foundation, Inc.
+
+ Written by Miles Bader and Marcus Brinkmann.
+
+ 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 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <rwlock.h>
+#include <maptime.h>
+#include <cthreads.h>
+
+#include <version.h>
+
+#include <mach.h>
+#include <hurd/netfs.h>
+#include <hurd/ioctl_types.h>
+/* We include console.h for the color numbers. */
+#include <hurd/console.h>
+
+#include "display.h"
+#include "input.h"
+
+#include "fs_notify_U.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (console);
+
+char *netfs_server_name = "console";
+char *netfs_server_version = HURD_VERSION;
+int netfs_maxsymlinks = 16; /* Arbitrary. */
+
+/* Handy source of time. */
+volatile struct mapped_time_value *console_maptime;
+
+#define DEFAULT_ENCODING "ISO-8859-1"
+#define DEFAULT_INTENSITY CONS_ATTR_INTENSITY_NORMAL
+#define DEFAULT_UNDERLINED 0
+#define DEFAULT_BLINKING 0
+#define DEFAULT_REVERSED 0
+#define DEFAULT_CONCEALED 0
+#define DEFAULT_WIDTH 80
+#define DEFAULT_HEIGHT 25
+#define DEFAULT_LINES 50
+/* Stringification of a macro. */
+#define STRX(s) #s
+#define STR(s) STRX(s)
+
+/* For the help output. */
+#define DEFAULT_ATTRIBUTE_NAME "normal"
+#define DEFAULT_FOREGROUND CONS_COLOR_WHITE
+/* For the help output. */
+#define DEFAULT_FOREGROUND_NAME "white"
+#define DEFAULT_BACKGROUND CONS_COLOR_BLACK
+/* For the help output. */
+#define DEFAULT_BACKGROUND_NAME "black"
+
+
+/* A handle for a console device. */
+typedef struct cons *cons_t;
+
+/* A handle for a virtual console device. */
+typedef struct vcons *vcons_t;
+
+struct vcons
+{
+ /* Protected by cons->lock. */
+ vcons_t next;
+ vcons_t prev;
+ /* We acquire one reference per netnode. */
+ int refcnt;
+
+ /* The following members remain constant over the lifetime of the
+ object and accesses don't need to be locked. */
+ int id;
+ char *name;
+ cons_t cons;
+ display_t display;
+ input_t input;
+
+ struct mutex lock;
+ /* Nodes in the filesystem referring to this virtual console. */
+ struct node *dir_node;
+ struct node *cons_node;
+ struct node *disp_node;
+ struct node *inpt_node;
+};
+
+/* Pending directory modification requests. */
+struct modreq
+{
+ mach_port_t port;
+ struct modreq *next;
+};
+
+struct cons
+{
+ /* The lock protects the console, all virtual consoles contained in
+ it and the reference counters. It also locks the configuration
+ parameters. */
+ struct mutex lock;
+ vcons_t vcons_list;
+ /* The encoding. */
+ char *encoding;
+ /* Default attributes. */
+ conchar_attr_t attribute;
+
+ /* Requester of directory modification notifications. */
+ struct modreq *dirmod_reqs;
+ unsigned int dirmod_tick;
+
+ struct node *node;
+ mach_port_t underlying;
+ /* A template for the stat information of all nodes. */
+ struct stat stat_template;
+
+ /* The amount of lines, width and height. */
+ unsigned int lines;
+ unsigned int width;
+ unsigned int height;
+};
+
+
+/* Requires CONS to be locked. */
+static void
+cons_notice_dirchange (cons_t cons, dir_changed_type_t type, char *name)
+{
+ error_t err;
+ struct modreq **preq = &cons->dirmod_reqs;
+
+ cons->dirmod_tick++;
+ while (*preq)
+ {
+ struct modreq *req = *preq;
+
+ err = dir_changed (req->port, cons->dirmod_tick, type, name);
+ if (err && err != MACH_SEND_TIMEOUT)
+ {
+ /* Remove notify port. */
+ *preq = req->next;
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ else
+ preq = &req->next;
+ }
+}
+
+
+/* Lookup the virtual console with number ID in the console CONS,
+ acquire a reference for it, and return it in R_VCONS. If CREATE is
+ true, the virtual console will be created if it doesn't exist yet.
+ If CREATE is true, and ID 0, the first free virtual console id is
+ used. */
+error_t
+vcons_lookup (cons_t cons, int id, int create, vcons_t *r_vcons)
+{
+ error_t err;
+ vcons_t previous_vcons = 0;
+ vcons_t vcons;
+
+ if (!id && !create)
+ return EINVAL;
+
+ mutex_lock (&cons->lock);
+ if (id)
+ {
+ if (cons->vcons_list && cons->vcons_list->id <= id)
+ {
+ previous_vcons = cons->vcons_list;
+ while (previous_vcons->next && previous_vcons->next->id <= id)
+ previous_vcons = previous_vcons->next;
+ if (previous_vcons->id == id)
+ {
+ previous_vcons->refcnt++;
+ mutex_unlock (&cons->lock);
+ *r_vcons = previous_vcons;
+ return 0;
+ }
+ }
+ else if (!create)
+ {
+ mutex_unlock (&cons->lock);
+ return ESRCH;
+ }
+ }
+ else
+ {
+ id = 1;
+ if (cons->vcons_list && cons->vcons_list->id == 1)
+ {
+ previous_vcons = cons->vcons_list;
+ while (previous_vcons && previous_vcons->id == id)
+ {
+ id++;
+ previous_vcons = previous_vcons->next;
+ }
+ }
+ }
+
+ vcons = calloc (1, sizeof (struct vcons));
+ if (!vcons)
+ {
+ mutex_unlock (&cons->lock);
+ return ENOMEM;
+ }
+ vcons->cons = cons;
+ vcons->refcnt = 1;
+ vcons->id = id;
+ asprintf (&vcons->name, "%i", id);
+ /* XXX Error checking. */
+
+ mutex_init (&vcons->lock);
+ err = display_create (&vcons->display, cons->encoding ?: DEFAULT_ENCODING,
+ cons->attribute, cons->lines, cons->width,
+ cons->height);
+ if (err)
+ {
+ free (vcons->name);
+ free (vcons);
+ mutex_unlock (&cons->lock);
+ return err;
+ }
+
+ err = input_create (&vcons->input, cons->encoding ?: DEFAULT_ENCODING);
+ if (err)
+ {
+ display_destroy (vcons->display);
+ free (vcons->name);
+ free (vcons);
+ mutex_unlock (&cons->lock);
+ return err;
+ }
+
+ /* Insert the virtual console into the doubly linked list. */
+ if (previous_vcons)
+ {
+ vcons->prev = previous_vcons;
+ if (previous_vcons->next)
+ {
+ previous_vcons->next->prev = vcons;
+ vcons->next = previous_vcons->next;
+ }
+ previous_vcons->next = vcons;
+ }
+ else
+ {
+ if (cons->vcons_list)
+ {
+ cons->vcons_list->prev = vcons;
+ vcons->next = cons->vcons_list;
+ }
+ cons->vcons_list = vcons;
+ }
+ cons_notice_dirchange (cons, DIR_CHANGED_NEW, vcons->name);
+
+ mutex_unlock (&cons->lock);
+ *r_vcons = vcons;
+ return 0;
+}
+
+/* Acquire an additional reference to the virtual console VCONS. */
+void
+vcons_ref (vcons_t vcons)
+{
+ cons_t cons = vcons->cons;
+
+ mutex_lock (&cons->lock);
+ vcons->refcnt++;
+ mutex_unlock (&cons->lock);
+}
+
+/* Release a reference to the virtual console VCONS. If this was the
+ last reference the virtual console is destroyed. */
+void
+vcons_release (vcons_t vcons)
+{
+ cons_t cons = vcons->cons;
+
+ mutex_lock (&cons->lock);
+ if (!--vcons->refcnt)
+ {
+ /* As we keep a reference for all input focus groups pointing to
+ the virtual console, and a reference for the active console,
+ we know that without references, this virtual console is
+ neither active nor used by any input group. */
+
+ if (vcons->prev)
+ vcons->prev->next = vcons->next;
+ else
+ cons->vcons_list = vcons->next;
+ if (vcons->next)
+ vcons->next->prev = vcons->prev;
+
+ cons_notice_dirchange (cons, DIR_CHANGED_UNLINK, vcons->name);
+
+ /* XXX Destroy the state. */
+ display_destroy (vcons->display);
+ input_destroy (vcons->input);
+ free (vcons->name);
+ free (vcons);
+ }
+ mutex_unlock (&cons->lock);
+}
+
+struct netnode
+{
+ /* The root node points to the console object. */
+ cons_t cons;
+
+ /* All other nodes point to the virtual console object. */
+ vcons_t vcons;
+};
+
+typedef enum
+ {
+ VCONS_NODE_DIR = 0,
+ VCONS_NODE_CONSOLE,
+ VCONS_NODE_DISPLAY,
+ VCONS_NODE_INPUT
+ } vcons_node_type;
+
+/* Make a new virtual node. Always consumes the ports. */
+static error_t
+new_node (struct node **np, vcons_t vcons, vcons_node_type type)
+{
+ struct netnode *nn = calloc (1, sizeof *nn);
+ if (nn == 0)
+ return ENOMEM;
+
+ nn->vcons = vcons;
+ *np = netfs_make_node (nn);
+ if (*np == 0)
+ {
+ free (nn);
+ return ENOMEM;
+ }
+ (*np)->nn_stat = vcons->cons->stat_template;
+ (*np)->nn_translated = 0;
+
+ switch (type)
+ {
+ case VCONS_NODE_DIR:
+ (*np)->nn_stat.st_ino = vcons->id << 2;
+ (*np)->nn_stat.st_mode |= S_IFDIR;
+ (*np)->nn_stat.st_size = 0;
+ break;
+ case VCONS_NODE_CONSOLE:
+ (*np)->nn_stat.st_ino = (vcons->id << 2) + 1;
+ (*np)->nn_stat.st_mode |= S_IFCHR; /* Don't set nn_translated! */
+ (*np)->nn_stat.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+ (*np)->nn_stat.st_size = 0;
+ break;
+ case VCONS_NODE_DISPLAY:
+ (*np)->nn_stat.st_ino = (vcons->id << 2) + 2;
+ (*np)->nn_stat.st_mode |= S_IFREG;
+ (*np)->nn_stat.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+ (*np)->nn_stat.st_size = display_get_size (vcons->display);
+ break;
+ case VCONS_NODE_INPUT:
+ (*np)->nn_stat.st_ino = (vcons->id << 2) + 3;
+ (*np)->nn_stat.st_mode |= S_IFIFO;
+ (*np)->nn_stat.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+ (*np)->nn_stat.st_size = 0;
+ break;
+ }
+
+ /* If the underlying node isn't a directory, propagate read permission to
+ execute permission since we need that for lookups. */
+ if (! S_ISDIR (vcons->cons->stat_template.st_mode)
+ && S_ISDIR ((*np)->nn_stat.st_mode))
+ {
+ if (vcons->cons->stat_template.st_mode & S_IRUSR)
+ (*np)->nn_stat.st_mode |= S_IXUSR;
+ if (vcons->cons->stat_template.st_mode & S_IRGRP)
+ (*np)->nn_stat.st_mode |= S_IXGRP;
+ if (vcons->cons->stat_template.st_mode & S_IROTH)
+ (*np)->nn_stat.st_mode |= S_IXOTH;
+ }
+
+ fshelp_touch (&(*np)->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ console_maptime);
+
+ return 0;
+}
+
+
+/* Node management. */
+
+/* Node NP has no more references; free all its associated
+ storage. */
+void
+netfs_node_norefs (struct node *np)
+{
+ vcons_t vcons = np->nn->vcons;
+
+ /* The root node does never go away. */
+ assert (!np->nn->cons && np->nn->vcons);
+
+ /* Avoid deadlock. */
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ /* Find the back reference to ourself in the virtual console
+ structure, and delete it. */
+ mutex_lock (&vcons->lock);
+ spin_lock (&netfs_node_refcnt_lock);
+ if (np->references)
+ {
+ /* Someone else got a reference while we were attempting to go
+ away. This can happen in netfs_attempt_lookup. In this
+ case, just unlock the node and do nothing else. */
+ mutex_unlock (&vcons->lock);
+ mutex_unlock (&np->lock);
+ return;
+ }
+ if (np == vcons->dir_node)
+ vcons->dir_node = 0;
+ else if (np == vcons->cons_node)
+ vcons->cons_node = 0;
+ else if (np == vcons->disp_node)
+ vcons->disp_node = 0;
+ else
+ {
+ assert (np == vcons->inpt_node);
+ vcons->inpt_node = 0;
+ }
+ mutex_unlock (&vcons->lock);
+
+ /* Release our reference. */
+ vcons_release (vcons);
+
+ free (np->nn);
+ free (np);
+}
+
+/* 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 **np)
+{
+ /* We create virtual consoles dynamically on the fly, so there is no
+ need for an explicit create operation. */
+ *np = 0;
+ mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+/* 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 = 0;
+ if (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 = fshelp_isowner (&node->nn_stat, cred);
+ int flags = TOUCH_CTIME;
+
+ if (! err)
+ {
+ if (mtime)
+ node->nn_stat.st_mtim = *mtime;
+ else
+ flags |= TOUCH_MTIME;
+
+ if (atime)
+ node->nn_stat.st_atim = *atime;
+ else
+ flags |= TOUCH_ATIME;
+
+ fshelp_touch (&node->nn_stat, flags, console_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)
+{
+ *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 0;
+}
+
+/* Make sure that NP->nn_stat is filled with the most current
+ information. CRED identifies the user responsible for the
+ operation. NP is locked. */
+error_t
+netfs_validate_stat (struct node *np, struct iouser *cred)
+{
+ /* We are always uptodate. */
+ return 0;
+}
+
+/* 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 *np, int wait)
+{
+ return 0;
+}
+
+
+/* Directory management. */
+
+/* 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;
+
+ *node = 0;
+ err = fshelp_access (&dir->nn_stat, S_IEXEC, user);
+ if (err)
+ goto out;
+
+ if (strcmp (name, ".") == 0)
+ {
+ /* Current directory -- just add an additional reference to DIR
+ and return it. */
+ netfs_nref (dir);
+ *node = dir;
+ goto out;
+ }
+
+ if (strcmp (name, "..") == 0)
+ {
+ /* Parent directory -- if this is the root directory, return
+ EAGAIN. Otherwise return the root node, because we know
+ that our hierarchy is only one level deep. */
+
+ if (dir->nn->cons)
+ err = EAGAIN;
+ else
+ {
+ netfs_nref (netfs_root_node);
+ *node = netfs_root_node;
+ }
+ goto out;
+ }
+
+ if (dir->nn->cons)
+ {
+ /* This is the root directory. Look up the desired virtual
+ console, creating it on the fly if necessary. */
+ vcons_t vcons;
+ int release_vcons = 0;
+ char *tail = NULL;
+ int id;
+ errno = 0;
+ id = strtol (name, &tail, 0);
+ if ((tail && *tail) || errno)
+ {
+ err = ENOENT;
+ goto out;
+ }
+ err = vcons_lookup (dir->nn->cons, id, 1, &vcons);
+ if (err == ESRCH || err == EINVAL)
+ err = ENOENT;
+ if (err)
+ goto out;
+
+ mutex_lock (&vcons->lock);
+ if (vcons->dir_node)
+ {
+ /* We already have a directory node for this virtual
+ console. Use that, acquire a reference for it, and drop
+ our extra reference to the virtual console. */
+ *node = vcons->dir_node;
+ netfs_nref (*node);
+ release_vcons = 1;
+ }
+ else
+ {
+ /* Create a new directory node, connsuming the reference to
+ the virtual console. */
+ err = new_node (node, vcons, VCONS_NODE_DIR);
+ if (!err)
+ vcons->dir_node = *node;
+ else
+ release_vcons = 1;
+ }
+ mutex_unlock (&vcons->lock);
+ if (release_vcons)
+ vcons_release (vcons);
+ }
+ else
+ {
+ /* This is a virtual console directory node. */
+ vcons_t vcons = dir->nn->vcons;
+ int ref_vcons = 0;
+ assert (dir == vcons->dir_node);
+
+ if (!strcmp (name, "console"))
+ {
+ mutex_lock (&vcons->lock);
+ if (vcons->cons_node)
+ {
+ *node = vcons->cons_node;
+ netfs_nref (*node);
+ }
+ else
+ {
+ err = new_node (node, vcons, VCONS_NODE_CONSOLE);
+ if (!err)
+ {
+ vcons->cons_node = *node;
+ ref_vcons = 1;
+ }
+ }
+ mutex_unlock (&vcons->lock);
+ }
+ else if (!strcmp (name, "display"))
+ {
+ mutex_lock (&vcons->lock);
+ if (vcons->disp_node)
+ {
+ *node = vcons->disp_node;
+ netfs_nref (*node);
+ }
+ else
+ {
+ err = new_node (node, vcons, VCONS_NODE_DISPLAY);
+ if (!err)
+ {
+ vcons->disp_node = *node;
+ ref_vcons = 1;
+ }
+ }
+ mutex_unlock (&vcons->lock);
+ }
+ else if (!strcmp (name, "input"))
+ {
+ mutex_lock (&vcons->lock);
+ if (vcons->inpt_node)
+ {
+ *node = vcons->inpt_node;
+ netfs_nref (*node);
+ }
+ else
+ {
+ err = new_node (node, vcons, VCONS_NODE_INPUT);
+ if (!err)
+ {
+ vcons->inpt_node = *node;
+ ref_vcons = 1;
+ }
+ }
+ mutex_unlock (&vcons->lock);
+ }
+ else
+ err = ENOENT;
+
+ if (ref_vcons)
+ vcons_ref (vcons);
+ }
+
+ if (!err)
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, console_maptime);
+
+ out:
+ mutex_unlock (&dir->lock);
+ if (err)
+ *node = 0;
+ else
+ mutex_lock (&(*node)->lock);
+
+ return err;
+}
+
+/* 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))
+
+/* Implement the netfs_get_dirents callback as described in
+ <hurd/netfs.h>. */
+error_t
+netfs_get_dirents (struct iouser *cred, struct node *dir,
+ int first_entry, int num_entries, char **data,
+ mach_msg_type_number_t *data_len,
+ vm_size_t max_data_len, int *data_entries)
+{
+ error_t err;
+ int count = 0;
+ size_t size = 0; /* Total size of our return block. */
+ struct vcons *first_vcons = NULL;
+ struct vcons *vcons;
+
+ /* Add the length of a directory entry for NAME to SIZE and return true,
+ unless it would overflow MAX_DATA_LEN or NUM_ENTRIES, in which case
+ return false. */
+ int bump_size (const char *name)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ size_t new_size = size + DIRENT_LEN (strlen (name));
+ if (max_data_len > 0 && new_size > max_data_len)
+ return 0;
+ size = new_size;
+ count++;
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ if (!dir->nn->cons && !(dir == dir->nn->vcons->dir_node))
+ return ENOTDIR;
+
+ if (dir->nn->cons)
+ {
+ mutex_lock (&dir->nn->cons->lock);
+
+ /* Find the first entry. */
+ for (first_vcons = dir->nn->cons->vcons_list, count = 2;
+ first_vcons && first_entry > count;
+ first_vcons = first_vcons->next)
+ count++;
+
+ count = 0;
+ }
+
+ /* Make space for the `.' and `..' entries. */
+ if (first_entry == 0)
+ bump_size (".");
+ if (first_entry <= 1)
+ bump_size ("..");
+
+ if (dir->nn->cons)
+ {
+ /* See how much space we need for the result. */
+ for (vcons = first_vcons; vcons; vcons = vcons->next)
+ if (!bump_size (vcons->name))
+ break;
+ }
+ else
+ {
+ if (first_entry <= 2)
+ bump_size ("console");
+ if (first_entry <= 3)
+ bump_size ("display");
+ if (first_entry <= 4)
+ bump_size ("input");
+ }
+
+ /* Allocate it. */
+ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = ((void *) *data == (void *) -1) ? errno : 0;
+
+ if (! err)
+ /* Copy out the result. */
+ {
+ char *p = *data;
+
+ int add_dir_entry (const char *name, ino_t fileno, int type)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (name);
+ size_t sz = DIRENT_LEN (name_len);
+
+ if (sz > size)
+ return 0;
+ else
+ size -= sz;
+
+ hdr.d_fileno = fileno;
+ hdr.d_reclen = sz;
+ hdr.d_type = type;
+ hdr.d_namlen = name_len;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, name);
+ p += sz;
+
+ count++;
+
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ *data_len = size;
+ *data_entries = count;
+
+ count = 0;
+
+ if (dir->nn->cons)
+ {
+ /* Add `.' and `..' entries. */
+ if (first_entry == 0)
+ add_dir_entry (".", 2, DT_DIR);
+ if (first_entry <= 1)
+ add_dir_entry ("..", 2, DT_DIR);
+
+ /* Fill in the real directory entries. */
+ for (vcons = first_vcons; vcons; vcons = vcons->next)
+ if (!add_dir_entry (vcons->name,
+ vcons->id << 2, DT_DIR))
+ break;
+ }
+ else
+ {
+ /* Add `.' and `..' entries. */
+ if (first_entry == 0)
+ add_dir_entry (".", dir->nn_stat.st_ino, DT_DIR);
+ if (first_entry <= 1)
+ add_dir_entry ("..", 2, DT_DIR);
+
+ if (first_entry <= 2)
+ add_dir_entry ("console", (dir->nn->vcons->id << 2) + 1, DT_REG);
+ if (first_entry <= 3)
+ add_dir_entry ("display", (dir->nn->vcons->id << 2) + 2, DT_REG);
+ if (first_entry <= 4)
+ add_dir_entry ("input", (dir->nn->vcons->id << 3) + 2, DT_FIFO);
+ }
+ }
+
+ if (dir->nn->cons)
+ mutex_unlock(&dir->nn->cons->lock);
+
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, console_maptime);
+ return err;
+}
+
+/* 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;
+}
+
+/* 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)
+{
+ cons_t cons = node->nn->cons;
+ vcons_t vcons;
+ error_t err;
+
+ if (!cons)
+ return EOPNOTSUPP;
+
+ err = file_chown (cons->underlying, uid, gid);
+ if (err)
+ return err;
+
+ /* Change NODE's owner. */
+ node->nn_stat.st_uid = uid;
+ node->nn_stat.st_gid = gid;
+
+ mutex_lock (&cons->lock);
+ cons->stat_template.st_uid = uid;
+ cons->stat_template.st_gid = gid;
+
+ /* Change the owner of each leaf node. */
+ for (vcons = cons->vcons_list; vcons; vcons = vcons->next)
+ {
+ if (vcons->dir_node)
+ {
+ vcons->dir_node->nn_stat.st_uid = uid;
+ vcons->dir_node->nn_stat.st_gid = gid;
+ }
+ if (vcons->cons_node)
+ {
+ vcons->cons_node->nn_stat.st_uid = uid;
+ vcons->cons_node->nn_stat.st_gid = gid;
+ }
+ if (vcons->disp_node)
+ {
+ vcons->disp_node->nn_stat.st_uid = uid;
+ vcons->disp_node->nn_stat.st_gid = gid;
+ }
+ if (vcons->inpt_node)
+ {
+ vcons->inpt_node->nn_stat.st_uid = uid;
+ vcons->inpt_node->nn_stat.st_gid = gid;
+ }
+ }
+ mutex_unlock (&cons->lock);
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, console_maptime);
+ return err;
+}
+
+/* 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)
+{
+ cons_t cons = node->nn->cons;
+ vcons_t vcons;
+ error_t err;
+
+ if (!cons)
+ return EOPNOTSUPP;
+
+ err = file_chauthor (cons->underlying, author);
+ if (err)
+ return err;
+
+ /* Change NODE's author. */
+ node->nn_stat.st_author = author;
+
+ mutex_lock (&cons->lock);
+ cons->stat_template.st_author = author;
+
+ /* Change the author of each leaf node. */
+ for (vcons = cons->vcons_list; vcons; vcons = vcons->next)
+ {
+ if (vcons->dir_node)
+ vcons->dir_node->nn_stat.st_author = author;
+ if (vcons->cons_node)
+ vcons->cons_node->nn_stat.st_author = author;
+ if (vcons->disp_node)
+ vcons->disp_node->nn_stat.st_author = author;
+ if (vcons->inpt_node)
+ vcons->inpt_node->nn_stat.st_author = author;
+ }
+ mutex_unlock (&cons->lock);
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, console_maptime);
+ return err;
+}
+
+/* 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)
+{
+ error_t err;
+
+ mode &= ~S_ITRANS;
+ if ((mode & S_IFMT) == 0)
+ mode |= (node->nn_stat.st_mode & S_IFMT);
+
+ if (!node->nn->cons || ((mode & S_IFMT) != (node->nn_stat.st_mode & S_IFMT)))
+ return EOPNOTSUPP;
+
+ err = file_chmod (node->nn->cons->underlying, mode & ~S_IFMT);
+ if (err)
+ return err;
+
+ node->nn_stat.st_mode = mode;
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, console_maptime);
+ return err;
+}
+
+
+/* The user must define this function. Attempt to turn locked node NP
+ (user CRED) into a symlink with target NAME. */
+error_t
+netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mkdev (struct iouser *cred, struct node *np,
+ mode_t type, dev_t indexes)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size)
+{
+ vcons_t vcons = np->nn->vcons;
+
+ if (!vcons || np == vcons->dir_node
+ || np == vcons->disp_node)
+ return EOPNOTSUPP;
+
+ assert (np == vcons->cons_node || np == vcons->inpt_node);
+ return 0;
+}
+
+error_t
+netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mkdir (struct iouser *user, struct node *dir,
+ char *name, mode_t mode)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_rename (struct iouser *user, struct node *fromdir,
+ char *fromname, struct node *todir,
+ char *toname, int excl)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_rmdir (struct iouser *user,
+ struct node *dir, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_link (struct iouser *user, struct node *dir,
+ struct node *file, char *name, int excl)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mkfile (struct iouser *user, struct node *dir,
+ mode_t mode, struct node **np)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_read (struct iouser *cred, struct node *np,
+ off_t offset, size_t *len, void *data)
+{
+ error_t err = 0;
+ vcons_t vcons = np->nn->vcons;
+ if (!vcons || np == vcons->dir_node
+ || np == vcons->inpt_node)
+ return EOPNOTSUPP;
+
+ mutex_unlock (&np->lock);
+ if (np == vcons->cons_node)
+ {
+ ssize_t amt = input_dequeue (vcons->input,
+ /* cred->po->openstat & O_NONBLOCK */ 0,
+ data, *len);
+ if (amt == -1)
+ err = errno;
+ else
+ *len = amt;
+ }
+ else
+ {
+ /* Pass display content to caller. */
+ ssize_t amt = *len;
+ assert (np == vcons->disp_node);
+
+ if (offset + amt > np->nn_stat.st_size)
+ amt = np->nn_stat.st_size - offset;
+ if (amt < 0)
+ amt = 0;
+ else
+ amt = display_read (vcons->display,
+ /* cred->po->openstat & O_NONBLOCK */ 0,
+ offset, data, amt);
+ if (amt == -1)
+ err = errno;
+ else
+ *len = amt;
+ }
+ mutex_lock (&np->lock);
+ return err;
+}
+
+error_t
+netfs_attempt_write (struct iouser *cred, struct node *np,
+ off_t offset, size_t *len, void *data)
+{
+ error_t err = 0;
+ vcons_t vcons = np->nn->vcons;
+ if (!vcons || np == vcons->dir_node
+ || np == vcons->disp_node)
+ return EOPNOTSUPP;
+
+ mutex_unlock (&np->lock);
+ if (np == vcons->cons_node)
+ {
+ /* The term server is writing to the console device. Feed the
+ data into the screen matrix display. */
+ int amt = display_output (vcons->display,
+ /* cred->po->openstat & O_NONBLOCK */ 0,
+ data, *len);
+ if (amt == -1)
+ err = errno;
+ else
+ *len = amt;
+ }
+ else
+ {
+ int amt;
+ /* The input driver is writing to the input device. Feed the
+ data into the input queue. */
+ assert (np == vcons->inpt_node);
+
+ amt = input_enqueue (vcons->input,
+ /* cred->po->openstat & O_NONBLOCK */ 1,
+ data, *len);
+ if (amt == -1)
+ err = errno;
+ else
+ *len = amt;
+ }
+ mutex_lock (&np->lock);
+ return err;
+}
+
+
+/* Implement io_map as described in <hurd/io.defs>. */
+kern_return_t
+netfs_S_io_map (struct protid *cred,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
+{
+ int flags;
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->disp_node)
+ return EOPNOTSUPP;
+
+ *wrobj = *rdobj = MACH_PORT_NULL;
+
+ flags = cred->po->openstat & (O_READ | O_WRITE);
+
+ mutex_lock (&np->lock);
+ switch (flags)
+ {
+ case O_READ | O_WRITE:
+ *wrobj = *rdobj = display_get_filemap (vcons->display,
+ VM_PROT_READ | VM_PROT_WRITE);
+ if (*wrobj == MACH_PORT_NULL)
+ goto error;
+ mach_port_mod_refs (mach_task_self (), *rdobj, MACH_PORT_RIGHT_SEND, 1);
+ break;
+ case O_READ:
+ *rdobj = display_get_filemap (vcons->display, VM_PROT_READ);
+ if (*rdobj == MACH_PORT_NULL)
+ goto error;
+ break;
+ case O_WRITE:
+ *wrobj = display_get_filemap (vcons->display, VM_PROT_WRITE);
+ if (*wrobj == MACH_PORT_NULL)
+ goto error;
+ break;
+ }
+ mutex_unlock (&np->lock);
+
+ *rdtype = MACH_MSG_TYPE_MOVE_SEND;
+ *wrtype = MACH_MSG_TYPE_MOVE_SEND;
+
+ return 0;
+
+ error:
+ mutex_unlock (&np->lock);
+ return errno;
+}
+
+
+kern_return_t
+netfs_S_dir_notice_changes (struct protid *cred, mach_port_t notify)
+{
+ error_t err;
+ cons_t cons;
+ struct modreq **preq;
+ struct modreq *req;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ cons = cred->po->np->nn->cons;
+ if (!cons)
+ return EOPNOTSUPP;
+
+ mutex_lock (&cons->lock);
+ /* We have to prevent that we accumulate dead-names in the
+ notification list. They are cleaned up in cons_notice_dirchange,
+ but that is not called often enough, so we also clean them up
+ here. This way, the maximum of dead-names will never exceed the
+ prior maximum of active clients. The better way would be to
+ request dead-name notifications, XXX. */
+ preq = &cons->dirmod_reqs;
+
+ while (*preq)
+ {
+ mach_port_type_t type;
+ req = *preq;
+
+ err = mach_port_type (mach_task_self (), req->port, &type);
+ if (!err && type == MACH_PORT_TYPE_DEAD_NAME)
+ {
+ /* Remove notify port. */
+ *preq = req->next;
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ else
+ preq = &req->next;
+ }
+
+ err = dir_changed (notify, cons->dirmod_tick, DIR_CHANGED_NULL, "");
+ if (err)
+ {
+ mutex_unlock (&cons->lock);
+ return err;
+ }
+ req = malloc (sizeof (struct modreq));
+ if (!req)
+ {
+ mutex_unlock (&cons->lock);
+ return errno;
+ }
+ req->port = notify;
+ req->next = cons->dirmod_reqs;
+ cons->dirmod_reqs = req;
+ mutex_unlock (&cons->lock);
+ return 0;
+}
+
+kern_return_t
+netfs_S_file_notice_changes (struct protid *cred, mach_port_t notify)
+{
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->disp_node)
+ return EOPNOTSUPP;
+
+ return display_notice_changes (vcons->display, notify);
+}
+
+
+static const char *color_names[CONS_COLOR_MAX + 1] =
+ {
+ [CONS_COLOR_BLACK] = "black",
+ [CONS_COLOR_RED] = "red",
+ [CONS_COLOR_GREEN] = "green",
+ [CONS_COLOR_YELLOW] = "yellow",
+ [CONS_COLOR_BLUE] = "blue",
+ [CONS_COLOR_MAGENTA] = "magenta",
+ [CONS_COLOR_CYAN] = "cyan",
+ [CONS_COLOR_WHITE] = "white"
+ };
+
+static const struct argp_option options[] =
+{
+ { "foreground", 'f', "COLOR", 0, "Set foreground color to"
+ " COLOR (default `" DEFAULT_FOREGROUND_NAME "')" },
+ { "background", 'b', "COLOR", 0, "Set background color to"
+ " COLOR (default `" DEFAULT_BACKGROUND_NAME "')" },
+ { "attribute", 'a', "ATTR[,...]", 0, "Set further default attributes"
+ " (default `" DEFAULT_ATTRIBUTE_NAME "')" },
+ { "encoding", 'e', "NAME", 0, "Set encoding of virtual consoles to"
+ " NAME (default `" DEFAULT_ENCODING "')" },
+ { "width", 'w', "WIDTH", 0, "Set width to WIDTH (default `"
+ STR(DEFAULT_WIDTH) "')" },
+ { "height", 'h', "HEIGHT", 0, "Set height to HEIGHT (default `"
+ STR(DEFAULT_HEIGHT) "')" },
+ { "lines", 'l', "LINES", 0, "Set amount of scrollback lines to LINES "
+ "(default `" STR(DEFAULT_LINES) "')" },
+ {0}
+};
+
+static error_t
+parse_color (const char *name, int *number)
+{
+ if (isdigit (*name))
+ {
+ long int nr;
+ char *tail;
+
+ errno = 0;
+
+ nr = strtol (name, &tail, 0);
+ if (errno || *tail || nr < 0 || nr > CONS_COLOR_MAX)
+ return EINVAL;
+ *number = nr;
+ return 0;
+ }
+ else
+ {
+ int i;
+ for (i = 0; i <= CONS_COLOR_MAX; i++)
+ if (!strcmp (color_names[i], name))
+ {
+ *number = i;
+ return 0;
+ }
+ return EINVAL;
+ }
+}
+
+static error_t
+parse_attributes (const char *name, conchar_attr_t *attr)
+{
+ while (*name)
+ {
+ int value = 1;
+
+ if (!strncmp (name, "not-", 4))
+ {
+ value = 0;
+ name += 4;
+ }
+
+ if (!strncmp (name, "normal", 6))
+ {
+ name += 6;
+ if (value != 1)
+ return EINVAL;
+ attr->intensity = CONS_ATTR_INTENSITY_NORMAL;
+ }
+ else if (!strncmp (name, "bright", 6))
+ {
+ name += 6;
+ if (value != 1)
+ return EINVAL;
+ attr->intensity = CONS_ATTR_INTENSITY_BOLD;
+ }
+ else if (!strncmp (name, "dim", 3))
+ {
+ name += 3;
+ if (value != 1)
+ return EINVAL;
+ attr->intensity = CONS_ATTR_INTENSITY_DIM;
+ }
+ else if (!strncmp (name, "underlined", 10))
+ {
+ name += 10;
+ attr->underlined = value;
+ }
+ else if (!strncmp (name, "blinking", 8))
+ {
+ name += 8;
+ attr->blinking = value;
+ }
+ else if (!strncmp (name, "concealed", 9))
+ {
+ name += 9;
+ attr->concealed = value;
+ }
+ else if (!strncmp (name, "italic", 6))
+ {
+ name += 6;
+ attr->italic = value;
+ }
+ else if (!strncmp (name, "bold", 4))
+ {
+ name += 4;
+ attr->bold = value;
+ }
+ else
+ return EINVAL;
+
+ if (name[0] == ',')
+ name++;
+ else if (name[0] != '\0')
+ return EINVAL;
+ }
+ return 0;
+}
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ cons_t cons = state->input ?: netfs_root_node->nn->cons;
+ error_t err;
+ int color = 0;
+ char *tail;
+
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case ARGP_KEY_INIT:
+ mutex_lock (&cons->lock);
+ break;
+
+ case ARGP_KEY_FINI:
+ mutex_unlock (&cons->lock);
+ break;
+
+ case 'f':
+ err = parse_color (arg, &color);
+ cons->attribute.fgcol = color;
+ if (err)
+ argp_error (state, "Invalid color name: %s", arg);
+ break;
+
+ case 'b':
+ err = parse_color (arg, &color);
+ cons->attribute.bgcol = color;
+ if (err)
+ argp_error (state, "Invalid color name: %s", arg);
+ break;
+
+ case 'a':
+ err = parse_attributes (arg, &cons->attribute);
+ if (err)
+ argp_error (state, "Invalid attribute specifier: %s", arg);
+ break;
+
+ case 'l':
+ errno = 0;
+ cons->lines = strtoul (arg, &tail, 0);
+ if (tail == NULL || tail == arg || *tail != '\0')
+ argp_error (state, "LINES is not a number: %s", arg);
+ if (errno)
+ argp_error (state, "Overflow in argument LINES %s", arg);
+ break;
+
+ case 'w':
+ errno = 0;
+ cons->width = strtoul (arg, &tail, 0);
+ if (tail == NULL || tail == arg || *tail != '\0')
+ argp_error (state, "WIDTH is not a number: %s", arg);
+ if (errno)
+ argp_error (state, "Overflow in argument WIDTH %s", arg);
+ break;
+
+ case 'h':
+ errno = 0;
+ cons->height = strtoul (arg, &tail, 0);
+ if (tail == NULL || tail == arg || *tail != '\0')
+ argp_error (state, "HEIGHT is not a number: %s", arg);
+ if (errno)
+ argp_error (state, "Overflow in argument HEIGHT %s", arg);
+ break;
+
+ case 'e':
+ /* XXX Check validity of encoding. Can we perform all necessary
+ conversions? */
+ {
+ char *new = strdup (arg);
+ if (!new)
+ return ENOMEM;
+ if (cons->encoding)
+ free (cons->encoding);
+ cons->encoding = new;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* Return an argz string describing the current options. Fill *ARGZ
+ with a pointer to newly malloced storage holding the list and *LEN
+ to the length of that storage. */
+error_t
+netfs_append_args (char **argz, size_t *argz_len)
+{
+ error_t err = 0;
+ cons_t cons = netfs_root_node->nn->cons;
+ /* The longest possible is 61 characters long:
+ "normal,not-underlined,not-blinking,not-reversed,not-concealed". */
+ char attr_str[80] = "--attribute=";
+ char *attr = &attr_str[12];
+ char *attrp = attr;
+
+ if (cons->encoding && strcmp (cons->encoding, DEFAULT_ENCODING))
+ {
+ char *buf;
+ if (asprintf (&buf, "--encoding=%s", cons->encoding) < 0)
+ err = ENOMEM;
+ else
+ err = argz_add (argz, argz_len, buf);
+
+ }
+ if (!err && cons->attribute.fgcol != DEFAULT_FOREGROUND)
+ {
+ char *buf;
+ if (asprintf (&buf, "--foreground=%s",
+ color_names[cons->attribute.fgcol]) < 0)
+ err = ENOMEM;
+ else
+ err = argz_add (argz, argz_len, buf);
+
+ }
+ if (!err && cons->attribute.bgcol != DEFAULT_BACKGROUND)
+ {
+ char *buf;
+ if (asprintf (&buf, "--background=%s",
+ color_names[cons->attribute.bgcol]) < 0)
+ err = ENOMEM;
+ else
+ err = argz_add (argz, argz_len, buf);
+ }
+ if (!err && cons->lines != DEFAULT_LINES)
+ {
+ char *buf;
+ if (asprintf (&buf, "--lines=%d", cons->lines) < 0)
+ err = ENOMEM;
+ else
+ err = argz_add (argz, argz_len, buf);
+ }
+ if (!err && cons->width != DEFAULT_WIDTH)
+ {
+ char *buf;
+ if (asprintf (&buf, "--width=%d", cons->lines) < 0)
+ err = ENOMEM;
+ else
+ err = argz_add (argz, argz_len, buf);
+ }
+ if (!err && cons->height != DEFAULT_HEIGHT)
+ {
+ char *buf;
+ if (asprintf (&buf, "--height=%d", cons->height) < 0)
+ err = ENOMEM;
+ else
+ err = argz_add (argz, argz_len, buf);
+ }
+ if (!err && cons->attribute.intensity != DEFAULT_INTENSITY)
+ {
+ if (attrp != attr)
+ *(attrp++) = ',';
+ switch (cons->attribute.intensity)
+ {
+ case CONS_ATTR_INTENSITY_NORMAL:
+ attrp = stpcpy (attrp, "normal");
+ break;
+ case CONS_ATTR_INTENSITY_BOLD:
+ attrp = stpcpy (attrp, "bold");
+ break;
+ case CONS_ATTR_INTENSITY_DIM:
+ attrp = stpcpy (attrp, "dim");
+ break;
+ }
+ }
+ if (!err && cons->attribute.underlined != DEFAULT_UNDERLINED)
+ {
+ if (attrp != attr)
+ *(attrp++) = ',';
+ if (!cons->attribute.underlined)
+ attrp = stpcpy (attrp, "not-");
+ attrp = stpcpy (attrp, "underlined");
+ }
+ if (!err && cons->attribute.blinking != DEFAULT_BLINKING)
+ {
+ if (attrp != attr)
+ *(attrp++) = ',';
+ if (!cons->attribute.blinking)
+ attrp = stpcpy (attrp, "not-");
+ attrp = stpcpy (attrp, "blinking");
+ }
+ if (!err && cons->attribute.reversed != DEFAULT_REVERSED)
+ {
+ if (attrp != attr)
+ *(attrp++) = ',';
+ if (!cons->attribute.reversed)
+ attrp = stpcpy (attrp, "not-");
+ attrp = stpcpy (attrp, "reversed");
+ }
+ if (!err && cons->attribute.concealed != DEFAULT_CONCEALED)
+ {
+ if (attrp != attr)
+ *(attrp++) = ',';
+ if (!cons->attribute.concealed)
+ attrp = stpcpy (attrp, "not-");
+ attrp = stpcpy (attrp, "concealed");
+ }
+ if (!err && attrp != attr)
+ err = argz_add (argz, argz_len, attr_str);
+
+ return err;
+}
+
+
+kern_return_t
+S_tioctl_tiocflush (struct protid *cred, int queue_selector)
+{
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openstat & (O_READ | O_WRITE)))
+ return EBADF;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->cons_node)
+ return EOPNOTSUPP;
+
+ if (!queue_selector)
+ queue_selector = O_READ | O_WRITE;
+
+ if (queue_selector & O_READ)
+ input_flush (vcons->input);
+ if (queue_selector & O_WRITE)
+ display_discard_output (vcons->display);
+
+ return 0;
+}
+
+kern_return_t
+S_tioctl_tiocgwinsz (struct protid *cred, struct winsize *size)
+{
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->cons_node)
+ return EOPNOTSUPP;
+
+ display_getsize (vcons->display, size);
+ return 0;
+}
+
+kern_return_t
+S_tioctl_tiocstart (struct protid *cred)
+{
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openstat & (O_READ | O_WRITE)))
+ return EBADF;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->cons_node)
+ return EOPNOTSUPP;
+
+ display_start_output (vcons->display);
+ return 0;
+}
+
+kern_return_t
+S_tioctl_tiocstop (struct protid *cred)
+{
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openstat & (O_READ | O_WRITE)))
+ return EBADF;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->cons_node)
+ return EOPNOTSUPP;
+
+ display_stop_output (vcons->display);
+ return 0;
+}
+
+
+kern_return_t
+S_tioctl_tiocoutq (struct protid *cred, int *queue_size)
+{
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openstat & (O_READ | O_WRITE)))
+ return EBADF;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->cons_node)
+ return EOPNOTSUPP;
+
+ *queue_size = display_pending_output (vcons->display);
+ return 0;
+}
+
+kern_return_t
+S_tioctl_tiocspgrp (struct protid *cred, int pgrp)
+{
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openstat & (O_READ | O_WRITE)))
+ return EBADF;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->cons_node)
+ return EOPNOTSUPP;
+
+ display_set_owner (vcons->display, -pgrp);
+ return 0;
+}
+
+kern_return_t
+S_tioctl_tiocgpgrp (struct protid *cred, int *pgrp)
+{
+ error_t err;
+ struct node *np;
+ vcons_t vcons;
+
+ if (!cred)
+ return EOPNOTSUPP;
+ if (!(cred->po->openstat & (O_READ | O_WRITE)))
+ return EBADF;
+
+ np = cred->po->np;
+ vcons = np->nn->vcons;
+ if (!vcons || np != vcons->cons_node)
+ return EOPNOTSUPP;
+
+ err = display_get_owner (vcons->display, pgrp);
+ if (!err)
+ *pgrp = -*pgrp;
+
+ return err;
+}
+
+kern_return_t
+S_tioctl_tiocmodg (io_t port, int *state)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocmods (io_t port, int state)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocexcl (io_t port)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocnxcl (io_t port)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocgeta (io_t port, tcflag_t *modes, cc_t *ccs, speed_t *speeds)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocseta (io_t port, tcflag_t *modes, cc_t *ccs, speed_t *speeds)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocsetaw (io_t port, tcflag_t *modes, cc_t *ccs, speed_t *speeds)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocsetaf (io_t port, tcflag_t *modes, cc_t *ccs,
+ speed_t *speeds)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocgetd (io_t port, int *disc)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocsetd (io_t port, int disc)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocdrain (io_t port)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocmget (io_t port, int *bits)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocmset (io_t port, int bits)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocsig (io_t port, int sig)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocext (io_t port, int mode)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocucntl (io_t port, int mode)
+
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocswinsz (struct protid *cred, struct winsize size)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocremote (struct protid *cred, int how)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocmbic (struct protid *cred, int bits)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocmbis (struct protid *cred, int bits)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocpkt (struct protid *cred, int mode)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocsti (struct protid *cred, char c)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tioccdtr (struct protid *cred)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocsdtr (struct protid *cred)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tioccbrk (struct protid *cred)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+S_tioctl_tiocsbrk (struct protid *cred)
+{
+ return EOPNOTSUPP;
+}
+
+
+int
+console_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ extern int netfs_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ extern int tioctl_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+
+ return (netfs_demuxer (inp, outp)
+ || tioctl_server (inp, outp));
+}
+
+const struct argp netfs_std_runtime_argp =
+ { options, parse_opt, NULL,
+ "A translator that provides virtual consoles." };
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct stat ul_stat;
+ cons_t cons;
+ struct netnode root_nn = { vcons: 0 };
+
+ cons = malloc (sizeof (struct cons));
+ if (!cons)
+ error (1, ENOMEM, "Cannot create console structure");
+ mutex_init (&cons->lock);
+ cons->encoding = NULL;
+ cons->width = DEFAULT_WIDTH;
+ cons->height = DEFAULT_HEIGHT;
+ cons->lines = DEFAULT_LINES;
+ cons->attribute.intensity = DEFAULT_INTENSITY;
+ cons->attribute.underlined = DEFAULT_UNDERLINED;
+ cons->attribute.blinking = DEFAULT_BLINKING;
+ cons->attribute.reversed = DEFAULT_REVERSED;
+ cons->attribute.concealed = DEFAULT_CONCEALED;
+ cons->attribute.fgcol = DEFAULT_FOREGROUND;
+ cons->attribute.bgcol = DEFAULT_BACKGROUND;
+ cons->vcons_list = NULL;
+ cons->dirmod_reqs = NULL;
+ cons->dirmod_tick = 0;
+ root_nn.cons = cons;
+
+ /* Parse our command line arguments. */
+ argp_parse (&netfs_std_runtime_argp, argc, argv, 0, 0, cons);
+
+ setlocale (LC_CTYPE, "C.UTF-8");
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+
+ netfs_init ();
+
+ display_init ();
+
+ /* Create the root node (some attributes initialized below). */
+ netfs_root_node = netfs_make_node (&root_nn);
+ if (! netfs_root_node)
+ error (2, ENOMEM, "Cannot create root node");
+
+ err = maptime_map (0, 0, &console_maptime);
+ if (err)
+ error (3, err, "Cannot map time");
+
+ cons->node = netfs_root_node;
+ cons->underlying = netfs_startup (bootstrap, O_READ);
+ if (cons->underlying == MACH_PORT_NULL)
+ error (4, 0, "Cannot get underlying node");
+
+ err = io_stat (cons->underlying, &ul_stat);
+ if (err)
+ error (5, err, "Cannot stat underlying node");
+
+ /* CONS.stat_template contains some fields that are inherited by all
+ nodes we create. */
+ cons->stat_template.st_uid = ul_stat.st_uid;
+ cons->stat_template.st_gid = ul_stat.st_gid;
+ cons->stat_template.st_author = ul_stat.st_author;
+ cons->stat_template.st_mode = (ul_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+ cons->stat_template.st_fsid = getpid ();
+ cons->stat_template.st_nlink = 1;
+ cons->stat_template.st_fstype = FSTYPE_MISC;
+
+ /* Initialize the root node's stat information. */
+ netfs_root_node->nn_stat = cons->stat_template;
+ netfs_root_node->nn_stat.st_ino = 2;
+ netfs_root_node->nn_stat.st_mode |= S_IFDIR;
+ netfs_root_node->nn_translated = 0;
+
+ /* If the underlying node isn't a directory, propagate read permission to
+ execute permission since we need that for lookups. */
+ if (! S_ISDIR (ul_stat.st_mode))
+ {
+ if (ul_stat.st_mode & S_IRUSR)
+ netfs_root_node->nn_stat.st_mode |= S_IXUSR;
+ if (ul_stat.st_mode & S_IRGRP)
+ netfs_root_node->nn_stat.st_mode |= S_IXGRP;
+ if (ul_stat.st_mode & S_IROTH)
+ netfs_root_node->nn_stat.st_mode |= S_IXOTH;
+ }
+
+ fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ console_maptime);
+
+ do
+ {
+ ports_manage_port_operations_multithread (netfs_port_bucket,
+ console_demuxer,
+ 1000 * 60 * 2,
+ 1000 * 60 * 10,
+ 0);
+ err = netfs_shutdown (0);
+ }
+ while (err);
+
+ exit (err);
+}
diff --git a/console/display.c b/console/display.c
new file mode 100644
index 00000000..e807c50f
--- /dev/null
+++ b/console/display.c
@@ -0,0 +1,2138 @@
+/* display.c - The display component of a virtual console.
+ Copyright (C) 1999 Kalle Olavi Niemitalo (emu.c from colortext 0.3).
+ Copyright (C) 2002, 2003, 2010 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann and Kalle Olavi Niemitalo.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <iconv.h>
+#include <argp.h>
+#include <string.h>
+#include <assert.h>
+#include <error.h>
+
+#include <cthreads.h>
+
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/console.h>
+
+#ifndef __STDC_ISO_10646__
+#error It is required that wchar_t is UCS-4.
+#endif
+
+#include "display.h"
+#include "pager.h"
+
+
+struct changes
+{
+ uint32_t flags;
+ struct
+ {
+ uint32_t col;
+ uint32_t row;
+ uint32_t status;
+ } cursor;
+ struct
+ {
+ uint32_t cur_line;
+ uint32_t scr_lines;
+ } screen;
+
+ uint32_t bell_audible;
+ uint32_t bell_visible;
+
+ off_t start;
+ off_t end;
+
+#define DISPLAY_CHANGE_CURSOR_POS 0x0001
+#define DISPLAY_CHANGE_CURSOR_STATUS 0x0002
+#define DISPLAY_CHANGE_SCREEN_CUR_LINE 0x0004
+#define DISPLAY_CHANGE_SCREEN_SCR_LINES 0x0008
+#define DISPLAY_CHANGE_BELL_AUDIBLE 0x0010
+#define DISPLAY_CHANGE_BELL_VISIBLE 0x0020
+#define DISPLAY_CHANGE_FLAGS 0x0030
+#define DISPLAY_CHANGE_MATRIX 0x0040
+ unsigned int which;
+};
+
+struct cursor
+{
+ uint32_t saved_x;
+ uint32_t saved_y;
+};
+typedef struct cursor *cursor_t;
+
+struct scrolling_region
+{
+ uint32_t top;
+ uint32_t bottom;
+};
+
+struct parse
+{
+ /* The parsing state of output characters, needed to handle escape
+ character sequences. */
+ enum
+ {
+ STATE_NORMAL = 0,
+ /* An escape character has just been parsed. */
+ STATE_ESC,
+ STATE_ESC_BRACKET_INIT,
+ STATE_ESC_BRACKET,
+ STATE_ESC_BRACKET_QUESTION,
+ STATE_ESC_BRACKET_RIGHT_ANGLE
+ } state;
+
+ /* How many parameters an escape sequence may have. */
+#define PARSE_MAX_PARAMS 10
+ int params[PARSE_MAX_PARAMS];
+ int nparams;
+};
+typedef struct parse *parse_t;
+
+struct output
+{
+ /* The state of the conversion of output characters. */
+ iconv_t cd;
+ /* The output queue holds the characters that are to be outputted.
+ The conversion routine might refuse to handle some incomplete
+ multi-byte or composed character at the end of the buffer, so we
+ have to keep them around. */
+ int stopped;
+ struct condition resumed;
+ char *buffer;
+ size_t allocated;
+ size_t size;
+
+ /* The parsing state of output characters. */
+ struct parse parse;
+};
+typedef struct output *output_t;
+
+struct attr
+{
+ conchar_attr_t attr_def;
+ conchar_attr_t current;
+ /* True if in alternate character set (ASCII graphic) mode. */
+ unsigned int altchar;
+};
+typedef struct attr *attr_t;
+
+/* Pending directory and file modification requests. */
+struct modreq
+{
+ mach_port_t port;
+ struct modreq *next;
+ /* If the port should have been notified, but it was blocking, we
+ set this. */
+ int pending;
+};
+
+/* For each display, a notification port is created to which the
+ kernel sends message accepted notifications. */
+struct notify
+{
+ struct port_info pi;
+ struct display *display;
+};
+
+struct display
+{
+ /* The lock for the virtual console display structure. */
+ struct mutex lock;
+
+ /* Indicates if OWNER_ID is initialized. */
+ int has_owner;
+ /* Specifies the ID of the process that should receive the WINCH
+ signal for this virtual console. */
+ int owner_id;
+
+ /* The pending changes. */
+ struct changes changes;
+
+ /* The state of the virtual console. */
+ /* The saved cursor position. */
+ struct cursor cursor;
+ /* The output queue and parser state. */
+ struct output output;
+ /* The current video attributes. */
+ struct attr attr;
+ /* Non-zero if we are in insert mode. */
+ int insert_mode;
+ /* Scrolling region. */
+ struct scrolling_region csr;
+
+ struct cons_display *user;
+
+ /* The pager for the USER member. */
+ struct user_pager user_pager;
+
+ /* A list of ports to send file change notifications to. */
+ struct modreq *filemod_reqs;
+ /* Those ports which currently have a pending notification. */
+ struct modreq *filemod_reqs_pending;
+ /* The notify port. */
+ struct notify *notify_port;
+};
+
+
+/* The bucket and class for notification messages. */
+static struct port_bucket *notify_bucket;
+static struct port_class *notify_class;
+
+#define msgh_request_port msgh_remote_port
+#define msgh_reply_port msgh_local_port
+
+/* SimpleRoutine file_changed */
+kern_return_t
+nowait_file_changed (mach_port_t notify_port, natural_t tickno,
+ file_changed_type_t change,
+ off_t start, off_t end, mach_port_t notify)
+{
+ typedef struct
+ {
+ mach_msg_header_t Head;
+ mach_msg_type_t ticknoType;
+ natural_t tickno;
+ mach_msg_type_t changeType;
+ file_changed_type_t change;
+ mach_msg_type_t startType;
+ loff_t start;
+ mach_msg_type_t endType;
+ loff_t end;
+ } Request;
+ union
+ {
+ Request In;
+ } Mess;
+ register Request *InP = &Mess.In;
+
+ static const mach_msg_type_t ticknoType = {
+ /* msgt_name = */ 2,
+ /* msgt_size = */ 32,
+ /* msgt_number = */ 1,
+ /* msgt_inline = */ TRUE,
+ /* msgt_longform = */ FALSE,
+ /* msgt_deallocate = */ FALSE,
+ /* msgt_unused = */ 0
+ };
+
+ static const mach_msg_type_t changeType = {
+ /* msgt_name = */ 2,
+ /* msgt_size = */ 32,
+ /* msgt_number = */ 1,
+ /* msgt_inline = */ TRUE,
+ /* msgt_longform = */ FALSE,
+ /* msgt_deallocate = */ FALSE,
+ /* msgt_unused = */ 0
+ };
+
+ static const mach_msg_type_t startType = {
+ /* msgt_name = */ 11,
+ /* msgt_size = */ 64,
+ /* msgt_number = */ 1,
+ /* msgt_inline = */ TRUE,
+ /* msgt_longform = */ FALSE,
+ /* msgt_deallocate = */ FALSE,
+ /* msgt_unused = */ 0
+ };
+
+ static const mach_msg_type_t endType = {
+ /* msgt_name = */ 11,
+ /* msgt_size = */ 64,
+ /* msgt_number = */ 1,
+ /* msgt_inline = */ TRUE,
+ /* msgt_longform = */ FALSE,
+ /* msgt_deallocate = */ FALSE,
+ /* msgt_unused = */ 0
+ };
+
+ InP->ticknoType = ticknoType;
+ InP->tickno = tickno;
+ InP->changeType = changeType;
+ InP->change = change;
+ InP->startType = startType;
+ InP->start = start;
+ InP->endType = endType;
+ InP->end = end;
+
+ InP->Head.msgh_bits = MACH_MSGH_BITS(19, 0);
+ /* msgh_size passed as argument. */
+ InP->Head.msgh_request_port = notify_port;
+ InP->Head.msgh_reply_port = MACH_PORT_NULL;
+ InP->Head.msgh_seqno = 0;
+ InP->Head.msgh_id = 20501;
+
+ if (notify == MACH_PORT_NULL)
+ return mach_msg (&InP->Head, MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
+ 64, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ else
+ return mach_msg (&InP->Head, MACH_SEND_MSG | MACH_SEND_NOTIFY,
+ 64, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+ notify);
+}
+
+/* Free the list of modification requests MR */
+static void
+free_modreqs (struct modreq *mr)
+{
+ struct modreq *tmp;
+ for (; mr; mr = tmp)
+ {
+ mach_port_t old;
+ /* Cancel the dead-name notification. */
+ mach_port_request_notification (mach_task_self (), mr->port,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+ mach_port_deallocate (mach_task_self (), old);
+
+ /* Deallocate the user's port. */
+ mach_port_deallocate (mach_task_self (), mr->port);
+ tmp = mr->next;
+ free (mr);
+ }
+}
+
+/* A port deleted notification is generated when we deallocate the
+ user's notify port before it is dead. */
+error_t
+do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name)
+{
+ /* As we cancel the dead-name notification before deallocating the
+ port, this should not happen. */
+ assert (0);
+}
+
+/* We request dead name notifications for the user ports. */
+error_t
+do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_name)
+{
+ struct notify *notify_port = ports_lookup_port (notify_bucket,
+ notify, notify_class);
+ struct display *display;
+ struct modreq **preq;
+ struct modreq *req;
+
+ if (!notify_port)
+ return EOPNOTSUPP;
+
+ display = notify_port->display;
+ mutex_lock (&display->lock);
+
+ /* Find request in pending queue. */
+ preq = &display->filemod_reqs_pending;
+ while (*preq && (*preq)->port != dead_name)
+ preq = &(*preq)->next;
+ if (! *preq)
+ {
+ /* Find request in queue. */
+ preq = &display->filemod_reqs;
+ while (*preq && (*preq)->port != dead_name)
+ preq = &(*preq)->next;
+ }
+
+ if (*preq)
+ {
+ req = *preq;
+ *preq = req->next;
+
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ mutex_unlock (&display->lock);
+
+ /* Drop gratuitous extra reference that the notification creates. */
+ mach_port_deallocate (mach_task_self (), dead_name);
+
+ return 0;
+}
+
+void do_mach_notify_port_destroyed (void) { assert (0); }
+
+error_t
+do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t count)
+{
+ return ports_do_mach_notify_no_senders (port, count);
+}
+
+kern_return_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return 0;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t send)
+{
+ struct notify *notify_port = ports_lookup_port (notify_bucket,
+ notify, notify_class);
+ struct display *display;
+ struct modreq **preq;
+ struct modreq *req;
+
+ if (!notify_port)
+ return EOPNOTSUPP;
+
+ /* If we deallocated the send right in display_destroy before the
+ notification was created. We have nothing to do in this
+ case. */
+ if (!send)
+ {
+ assert(0);
+ ports_port_deref (notify_port);
+ return 0;
+ }
+
+ display = notify_port->display;
+ mutex_lock (&display->lock);
+ /* Find request in pending queue. */
+ preq = &display->filemod_reqs_pending;
+ while (*preq && (*preq)->port != send)
+ preq = &(*preq)->next;
+ /* If we don't find the request, it was destroyed in
+ display_destroy. In this case, there is nothing left to do
+ here. */
+ if (! *preq)
+ {
+ assert(0);
+ mutex_unlock (&display->lock);
+ ports_port_deref (notify_port);
+ return 0;
+ }
+ req = *preq;
+
+ if (req->pending)
+ {
+ error_t err;
+ /* A request was desired while we were blocking. Send it now
+ and stay in pending queue. */
+ req->pending = 0;
+ err = nowait_file_changed (req->port, 0, FILE_CHANGED_WRITE, -1, -1,
+ notify);
+ if (err && err != MACH_SEND_WILL_NOTIFY)
+ {
+ mach_port_t old;
+ *preq = req->next;
+ mutex_unlock (&display->lock);
+
+ /* Cancel the dead-name notification. */
+ mach_port_request_notification (mach_task_self (), req->port,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+ mach_port_deallocate (mach_task_self (), old);
+
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ ports_port_deref (notify_port);
+ return err;
+ }
+ if (err == MACH_SEND_WILL_NOTIFY)
+ {
+ mutex_unlock (&display->lock);
+ return 0;
+ }
+ /* The message was successfully queued, fall through. */
+ }
+ /* Remove request from pending queue. */
+ *preq = req->next;
+ /* Insert request into active queue. */
+ req->next = display->filemod_reqs;
+ display->filemod_reqs = req;
+ mutex_unlock (&display->lock);
+ ports_port_deref (notify_port);
+ return 0;
+}
+
+/* A top-level function for the notification thread that just services
+ notification messages. */
+static void
+service_notifications (any_t arg)
+{
+ struct port_bucket *notify_bucket = arg;
+ extern int notify_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+
+ for (;;)
+ ports_manage_port_operations_one_thread (notify_bucket,
+ notify_server,
+ 1000 * 60 * 10);
+}
+
+error_t
+display_notice_changes (display_t display, mach_port_t notify)
+{
+ error_t err;
+ struct modreq *req;
+ mach_port_t notify_port;
+ mach_port_t old;
+
+ mutex_lock (&display->lock);
+ err = nowait_file_changed (notify, 0, FILE_CHANGED_NULL, 0, 0,
+ MACH_PORT_NULL);
+ if (err)
+ {
+ mutex_unlock (&display->lock);
+ return err;
+ }
+
+ req = malloc (sizeof (struct modreq));
+ if (!req)
+ {
+ mutex_unlock (&display->lock);
+ return errno;
+ }
+
+ notify_port = ports_get_right (display->notify_port);
+
+ /* Request dead-name notification for the user's port. */
+ err = mach_port_request_notification (mach_task_self (), notify,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ notify_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &old);
+ if (err)
+ {
+ free (req);
+ mutex_unlock (&display->lock);
+ return err;
+ }
+ assert (old == MACH_PORT_NULL);
+
+ req->port = notify;
+ req->pending = 0;
+ req->next = display->filemod_reqs;
+ display->filemod_reqs = req;
+ mutex_unlock (&display->lock);
+ return 0;
+}
+
+/* Requires DISPLAY to be locked. */
+static void
+display_notice_filechange (display_t display)
+{
+ error_t err;
+ struct modreq *req = display->filemod_reqs_pending;
+ struct modreq **preq = &display->filemod_reqs;
+ mach_port_t notify_port = ports_get_right (display->notify_port);
+
+ while (req)
+ {
+ req->pending = 1;
+ req = req->next;
+ }
+
+ while (*preq)
+ {
+ req = *preq;
+
+ err = nowait_file_changed (req->port, 0, FILE_CHANGED_WRITE, -1, -1,
+ notify_port);
+ if (err)
+ {
+ /* Remove notify port. */
+ *preq = req->next;
+
+ if (err == MACH_SEND_WILL_NOTIFY)
+ {
+ req->next = display->filemod_reqs_pending;
+ display->filemod_reqs_pending = req;
+ }
+ else
+ {
+ mach_port_t old;
+
+ /* Cancel the dead-name notification. */
+ mach_port_request_notification (mach_task_self (), req->port,
+ MACH_NOTIFY_DEAD_NAME, 0,
+ MACH_PORT_NULL, 0, &old);
+ mach_port_deallocate (mach_task_self (), old);
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ }
+ else
+ preq = &req->next;
+ }
+}
+
+static void
+display_flush_filechange (display_t display, unsigned int type)
+{
+ struct cons_display *user = display->user;
+ cons_change_t *next = &user->changes._buffer[user->changes.written
+ % _CONS_CHANGES_LENGTH];
+ int notify = 0;
+ int bump_written = 0;
+
+ if (type & DISPLAY_CHANGE_MATRIX
+ && display->changes.which & DISPLAY_CHANGE_MATRIX)
+ {
+ notify = 1;
+ next->matrix.start = display->changes.start;
+ next->matrix.end = display->changes.end;
+ user->changes.written++;
+ next = &user->changes._buffer[user->changes.written
+ % _CONS_CHANGES_LENGTH];
+ display->changes.which &= ~DISPLAY_CHANGE_MATRIX;
+ }
+
+ memset (next, 0, sizeof (cons_change_t));
+ next->what.not_matrix = 1;
+
+ if (type & DISPLAY_CHANGE_CURSOR_POS
+ && display->changes.which & DISPLAY_CHANGE_CURSOR_POS
+ && (display->changes.cursor.col != user->cursor.col
+ || display->changes.cursor.row != user->cursor.row))
+ {
+ notify = 1;
+ next->what.cursor_pos = 1;
+ bump_written = 1;
+ display->changes.which &= ~DISPLAY_CHANGE_CURSOR_POS;
+ }
+
+ if (type & DISPLAY_CHANGE_CURSOR_STATUS
+ && display->changes.which & DISPLAY_CHANGE_CURSOR_STATUS
+ && display->changes.cursor.status != user->cursor.status)
+ {
+ notify = 1;
+ next->what.cursor_status = 1;
+ bump_written = 1;
+ display->changes.which &= ~DISPLAY_CHANGE_CURSOR_STATUS;
+ }
+
+ if (type & DISPLAY_CHANGE_SCREEN_CUR_LINE
+ && display->changes.which & DISPLAY_CHANGE_SCREEN_CUR_LINE
+ && display->changes.screen.cur_line != user->screen.cur_line)
+ {
+ notify = 1;
+ next->what.screen_cur_line = 1;
+ bump_written = 1;
+ display->changes.which &= ~DISPLAY_CHANGE_SCREEN_CUR_LINE;
+ }
+
+ if (type & DISPLAY_CHANGE_SCREEN_SCR_LINES
+ && display->changes.which & DISPLAY_CHANGE_SCREEN_SCR_LINES
+ && display->changes.screen.scr_lines != user->screen.scr_lines)
+ {
+ notify = 1;
+ next->what.screen_scr_lines = 1;
+ bump_written = 1;
+ display->changes.which &= ~DISPLAY_CHANGE_SCREEN_SCR_LINES;
+ }
+
+ if (type & DISPLAY_CHANGE_BELL_AUDIBLE
+ && display->changes.which & DISPLAY_CHANGE_BELL_AUDIBLE
+ && display->changes.bell_audible != user->bell.audible)
+ {
+ notify = 1;
+ next->what.bell_audible = 1;
+ bump_written = 1;
+ display->changes.which &= ~DISPLAY_CHANGE_BELL_AUDIBLE;
+ }
+
+ if (type & DISPLAY_CHANGE_BELL_VISIBLE
+ && display->changes.which & DISPLAY_CHANGE_BELL_VISIBLE
+ && display->changes.bell_visible != user->bell.visible)
+ {
+ notify = 1;
+ next->what.bell_visible = 1;
+ bump_written = 1;
+ display->changes.which &= ~DISPLAY_CHANGE_BELL_VISIBLE;
+ }
+
+ if (type & DISPLAY_CHANGE_FLAGS
+ && display->changes.which & DISPLAY_CHANGE_FLAGS
+ && display->changes.flags != user->flags)
+ {
+ notify = 1;
+ next->what.flags = 1;
+ bump_written = 1;
+ display->changes.which &= ~DISPLAY_CHANGE_FLAGS;
+ }
+
+ if (bump_written)
+ user->changes.written++;
+ if (notify)
+ display_notice_filechange (display);
+}
+
+/* Record a change in the matrix ringbuffer. */
+static void
+display_record_filechange (display_t display, off_t start, off_t end)
+{
+ if (!(display->changes.which & DISPLAY_CHANGE_MATRIX))
+ {
+ display->changes.start = start;
+ display->changes.end = end;
+ display->changes.which |= DISPLAY_CHANGE_MATRIX;
+ }
+ else
+ {
+ off_t size = display->user->screen.width * display->user->screen.lines;
+ off_t rotate = display->changes.start;
+ off_t old_end = display->changes.end;
+ int disjunct = 0;
+
+ /* First rotate the buffer to reduce the number of cases. */
+ old_end -= rotate;
+ if (old_end < 0)
+ old_end += size;
+ start -= rotate;
+ if (start < 0)
+ start += size;
+ end -= rotate;
+ if (end < 0)
+ end += size;
+
+ /* Now the old region starts at 0 and ends at OLD_END. Try to
+ merge in the new region if it overlaps or touches the old
+ one. */
+ if (start <= end)
+ {
+ if (start <= old_end + 1)
+ {
+ start = 0;
+ if (old_end > end)
+ end = old_end;
+ }
+ else
+ {
+ if (end == size - 1)
+ end = old_end;
+ else
+ disjunct = 1;
+ }
+ }
+ else
+ {
+ if (start <= old_end + 1)
+ {
+ start = 0;
+ end = size - 1;
+ }
+ else
+ {
+ if (old_end > end)
+ end = old_end;
+ }
+ }
+ /* Now reverse the rotation. */
+ start += rotate;
+ if (start >= size)
+ start -= size;
+ end += rotate;
+ if (end >= size)
+ end -= size;
+
+ if (disjunct)
+ {
+ /* The regions are disjunct, so we have to flush the old
+ changes. */
+ display_flush_filechange (display, DISPLAY_CHANGE_MATRIX);
+ display->changes.which |= DISPLAY_CHANGE_MATRIX;
+ }
+ display->changes.start = start;
+ display->changes.end = end;
+ }
+}
+
+
+static void
+conchar_memset (conchar_t *conchar, wchar_t chr, conchar_attr_t attr,
+ size_t size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ {
+ conchar->chr = chr;
+ conchar->attr = attr;
+ conchar++;
+ }
+}
+
+
+static error_t
+user_create (display_t display, uint32_t width, uint32_t height,
+ uint32_t lines, wchar_t chr, conchar_attr_t attr)
+{
+ error_t err;
+ struct cons_display *user;
+ int npages = (round_page (sizeof (struct cons_display) + sizeof (conchar_t)
+ * width * lines)) / vm_page_size;
+
+ err = user_pager_create (&display->user_pager, npages, &display->user);
+ if (err)
+ return err;
+
+ user = display->user;
+ user->magic = CONS_MAGIC;
+ user->version = CONS_VERSION_MAJ << CONS_VERSION_MAJ_SHIFT | CONS_VERSION_AGE;
+ user->changes.buffer = offsetof (struct cons_display, changes._buffer)
+ / sizeof (uint32_t);
+ user->changes.length = _CONS_CHANGES_LENGTH;
+ user->screen.width = width;
+ user->screen.height = height;
+ user->screen.lines = lines;
+ user->screen.cur_line = 0;
+ user->screen.scr_lines = 0;
+ user->screen.matrix = sizeof (struct cons_display) / sizeof (uint32_t);
+ user->cursor.col = 0;
+ user->cursor.row = 0;
+ user->cursor.status = CONS_CURSOR_NORMAL;
+ conchar_memset (user->_matrix, chr, attr,
+ user->screen.width * user->screen.lines);
+ return 0;
+}
+
+static void
+user_destroy (display_t display)
+{
+ user_pager_destroy (&display->user_pager, display->user);
+}
+
+
+static void
+screen_fill (display_t display, size_t col1, size_t row1, size_t col2,
+ size_t row2, wchar_t chr, conchar_attr_t attr)
+{
+ struct cons_display *user = display->user;
+ off_t start = ((user->screen.cur_line % user->screen.lines) + row1)
+ * user->screen.width + col1;
+ off_t end = ((user->screen.cur_line % user->screen.lines) + row2)
+ * user->screen.width + col2;
+ off_t size = user->screen.width * user->screen.lines;
+
+ if (start >= size && end >= size)
+ {
+ start -= size;
+ end -= size;
+ }
+
+ if (end < size)
+ {
+ conchar_memset (user->_matrix + start, chr, attr, end - start + 1);
+ display_record_filechange (display, start, end);
+ }
+ else
+ {
+ conchar_memset (user->_matrix + start, chr, attr, size - start);
+ conchar_memset (user->_matrix, chr, attr, end - size + 1);
+ display_record_filechange (display, start, end - size);
+ }
+}
+
+static void
+screen_shift_left (display_t display, size_t col1, size_t row1, size_t col2,
+ size_t row2, size_t shift, wchar_t chr, conchar_attr_t attr)
+{
+ struct cons_display *user = display->user;
+ off_t start = ((user->screen.cur_line % user->screen.lines) + row1)
+ * user->screen.width + col1;
+ off_t end = ((user->screen.cur_line % user->screen.lines) + row2)
+ * user->screen.width + col2;
+ off_t size = user->screen.width * user->screen.lines;
+
+ if (start >= size && end >= size)
+ {
+ start -= size;
+ end -= size;
+ }
+
+ if (start + shift <= end)
+ {
+ /* Use a loop to copy the data. Using wmemmove and wmemset on
+ the chunks is tiresome, as there are many cases. */
+ off_t src = start + shift;
+ off_t dst = start;
+
+ while (src <= end)
+ user->_matrix[dst++ % size] = user->_matrix[src++ % size];
+ while (dst <= end)
+ {
+ user->_matrix[dst % size].chr = chr;
+ user->_matrix[dst++ % size].attr = attr;
+ }
+
+ display_record_filechange (display, start, end);
+ }
+ else
+ screen_fill (display, col1, row1, col2, row2, chr, attr);
+}
+
+static void
+screen_shift_right (display_t display, size_t col1, size_t row1, size_t col2,
+ size_t row2, size_t shift,
+ wchar_t chr, conchar_attr_t attr)
+{
+ struct cons_display *user = display->user;
+ off_t start = ((user->screen.cur_line % user->screen.lines) + row1)
+ * user->screen.width + col1;
+ off_t end = ((user->screen.cur_line % user->screen.lines) + row2)
+ * user->screen.width + col2;
+ off_t size = user->screen.width * user->screen.lines;
+
+ if (start >= size && end >= size)
+ {
+ start -= size;
+ end -= size;
+ }
+
+ if (start + shift <= end)
+ {
+ /* Use a loop to copy the data. Using wmemmove and wmemset on
+ the chunks is tiresome, as there are many cases. */
+ off_t src = end - shift;
+ off_t dst = end;
+
+ while (src >= start)
+ user->_matrix[dst-- % size] = user->_matrix[src-- % size];
+ while (dst >= start)
+ {
+ user->_matrix[dst % size].chr = chr;
+ user->_matrix[dst-- % size].attr = attr;
+ }
+
+ display_record_filechange (display, start, end);
+ }
+ else
+ screen_fill (display, col1, row1, col2, row2, chr, attr);
+}
+
+
+static error_t
+output_init (output_t output, const char *encoding)
+{
+ condition_init (&output->resumed);
+ output->stopped = 0;
+ output->buffer = NULL;
+ output->allocated = 0;
+ output->size = 0;
+
+ /* WCHAR_T happens to be UCS-4 on the GNU system. */
+ output->cd = iconv_open ("WCHAR_T", encoding);
+ if (output->cd == (iconv_t) -1)
+ return errno;
+ return 0;
+}
+
+static void
+output_deinit (output_t output)
+{
+ iconv_close (output->cd);
+}
+
+
+static void
+handle_esc_bracket_hl (display_t display, int code, int flag)
+{
+ switch (code)
+ {
+ case 4: /* ECMA-48 <SMIR>, <RMIR>. */
+ /* Insert mode: <smir>, <rmir>. */
+ display->insert_mode = flag ? 1 : 0;
+ break;
+ case 34:
+ /* Cursor standout: <cnorm>, <cvvis>. */
+ if (flag)
+ display->user->cursor.status = CONS_CURSOR_NORMAL;
+ else
+ display->user->cursor.status = CONS_CURSOR_VERY_VISIBLE;
+ /* XXX Flag cursor status change. */
+ break;
+ }
+}
+
+static void
+handle_esc_bracket_m (attr_t attr, int code)
+{
+ switch (code)
+ {
+ case 0:
+ /* All attributes off: <sgr0>. */
+ attr->current = attr->attr_def;
+ attr->altchar = 0;
+ break;
+ case 1:
+ /* Bold on: <bold>. */
+ attr->current.intensity = CONS_ATTR_INTENSITY_BOLD;
+ break;
+ case 2:
+ /* Dim on: <dim>. */
+ attr->current.intensity = CONS_ATTR_INTENSITY_DIM;
+ break;
+ case 3:
+ /* Italic on: <sitm>. */
+ attr->current.italic = 1;
+ break;
+ case 4:
+ /* Underline on: <smul>. */
+ attr->current.underlined = 1;
+ break;
+ case 5:
+ /* (Slow) blink on: <blink>. */
+ attr->current.blinking = 1;
+ break;
+ case 7:
+ /* Reverse video on: <rev>, <smso>. */
+ attr->current.reversed = 1;
+ break;
+ case 8:
+ /* Concealed on: <invis>. */
+ attr->current.concealed = 1;
+ break;
+ case 10:
+ /* Alternate character set mode off: <rmacs>. */
+ attr->altchar = 0;
+ break;
+ case 11:
+ /* Alternate character set mode on: <smacs>. */
+ attr->altchar = 1;
+ break;
+ case 21:
+ /* Normal intensity (switch off bright). */
+ attr->current.intensity = CONS_ATTR_INTENSITY_NORMAL;
+ break;
+ case 22:
+ /* Normal intensity (switch off dim). */
+ attr->current.intensity = CONS_ATTR_INTENSITY_NORMAL;
+ break;
+ case 23:
+ /* Italic off: <ritm>. */
+ attr->current.italic = 0;
+ break;
+ case 24:
+ /* Underline off: <rmul>. */
+ attr->current.underlined = 0;
+ break;
+ case 25:
+ /* Blink off. */
+ attr->current.blinking = 0;
+ break;
+ case 27:
+ /* Reverse video off: <rmso>. */
+ attr->current.reversed = 0;
+ break;
+ case 28:
+ /* Concealed off. */
+ attr->current.concealed = 0;
+ break;
+ case 30 ... 37:
+ /* Set foreground color: <setaf>. */
+ attr->current.fgcol = code - 30;
+ break;
+ case 39:
+ /* Default foreground color; ANSI?. */
+ attr->current.fgcol = attr->attr_def.fgcol;
+ break;
+ case 40 ... 47:
+ /* Set background color: <setab>. */
+ attr->current.bgcol = code - 40;
+ break;
+ case 49:
+ /* Default background color; ANSI?. */
+ attr->current.bgcol = attr->attr_def.bgcol;
+ break;
+ }
+}
+
+static
+void limit_cursor (display_t display)
+{
+ struct cons_display *user = display->user;
+
+ if (user->cursor.col >= user->screen.width)
+ user->cursor.col = user->screen.width - 1;
+ else if (user->cursor.col < 0)
+ user->cursor.col = 0;
+
+ if (user->cursor.row >= user->screen.height)
+ user->cursor.row = user->screen.height - 1;
+ else if (user->cursor.row < 0)
+ user->cursor.row = 0;
+
+ /* XXX Flag cursor change. */
+}
+
+
+static void
+linefeed (display_t display)
+{
+ struct cons_display *user = display->user;
+
+ if (display->csr.top == 0 && display->csr.bottom >= user->screen.height - 1)
+ {
+ /* No scrolling region active, do the normal scrolling activity. */
+ if (user->cursor.row < user->screen.height - 1)
+ {
+ user->cursor.row++;
+ /* XXX Flag cursor update. */
+ }
+ else
+ {
+ user->screen.cur_line++;
+
+ screen_fill (display, 0, user->screen.height - 1,
+ user->screen.width - 1, user->screen.height - 1,
+ L' ', display->attr.current);
+ if (user->screen.scr_lines <
+ user->screen.lines - user->screen.height)
+ user->screen.scr_lines++;
+ /* XXX Flag current line change. */
+ /* XXX Possibly flag change of length of scroll back buffer. */
+ }
+ }
+ else
+ {
+ /* With an active scrolling region, never actually scroll. Just
+ shift the scrolling region if necessary. */
+ if (user->cursor.row != display->csr.bottom
+ && user->cursor.row < user->screen.height - 1)
+ {
+ user->cursor.row++;
+ /* XXX Flag cursor update. */
+ }
+ else if (user->cursor.row == display->csr.bottom)
+ screen_shift_left (display, 0, display->csr.top,
+ user->screen.width - 1, display->csr.bottom,
+ user->screen.width,
+ L' ', display->attr.current);
+ }
+}
+
+static void
+horizontal_tab (display_t display)
+{
+ struct cons_display *user = display->user;
+
+ user->cursor.col = (user->cursor.col | 7) + 1;
+ if (user->cursor.col >= user->screen.width)
+ {
+ user->cursor.col = 0;
+ linefeed (display);
+ }
+ /* XXX Flag cursor update. */
+}
+
+static void
+handle_esc_bracket (display_t display, char op)
+{
+ struct cons_display *user = display->user;
+ parse_t parse = &display->output.parse;
+ int i;
+
+ switch (op)
+ {
+ case 'H': /* ECMA-48 <CUP>. */
+ case 'f': /* ECMA-48 <HVP>. */
+ /* Cursor position: <cup>. */
+ user->cursor.col = (parse->params[1] ?: 1) - 1;
+ user->cursor.row = (parse->params[0] ?: 1) - 1;
+ limit_cursor (display);
+ break;
+ case 'G': /* ECMA-48 <CHA>. */
+ case '`': /* ECMA-48 <HPA>. */
+ case '\'': /* VT100. */
+ /* Horizontal cursor position: <hpa>. */
+ user->cursor.col = (parse->params[0] ?: 1) - 1;
+ limit_cursor (display);
+ break;
+ case 'a': /* ECMA-48 <HPR>. */
+ /* Horizontal cursor position relative. */
+ user->cursor.col += (parse->params[1] ?: 1) - 1;
+ limit_cursor (display);
+ break;
+ case 'd': /* ECMA-48 <VPA>. */
+ /* Vertical cursor position: <vpa>. */
+ user->cursor.row = (parse->params[0] ?: 1) - 1;
+ limit_cursor (display);
+ break;
+ case 'F': /* ECMA-48 <CPL>. */
+ /* Beginning of previous line. */
+ user->cursor.col = 0;
+ /* Fall through. */
+ case 'A': /* ECMA-48 <CUU>. */
+ case 'k': /* ECMA-48 <VPB>. */
+ /* Cursor up: <cuu>, <cuu1>. */
+ user->cursor.row -= (parse->params[0] ?: 1);
+ limit_cursor (display);
+ break;
+ case 'E': /* ECMA-48 <CNL>. */
+ /* Beginning of next line. */
+ user->cursor.col = 0;
+ /* Fall through. */
+ case 'B': /* ECMA-48 <CUD>. */
+ case 'e': /* ECMA-48 <VPR>. */
+ /* Cursor down: <cud1>, <cud>. */
+ user->cursor.row += (parse->params[0] ?: 1);
+ limit_cursor (display);
+ break;
+ case 'C': /* ECMA-48 <CUF>. */
+ /* Cursor right: <cuf1>, <cuf>. */
+ user->cursor.col += (parse->params[0] ?: 1);
+ limit_cursor (display);
+ break;
+ case 'D': /* ECMA-48 <CUB>. */
+ /* Cursor left: <cub>, <cub1>. */
+ user->cursor.col -= (parse->params[0] ?: 1);
+ limit_cursor (display);
+ break;
+ case 'l':
+ /* Reset mode. */
+ for (i = 0; i < parse->nparams; i++)
+ handle_esc_bracket_hl (display, parse->params[i], 0);
+ break;
+ case 'h':
+ /* Set mode. */
+ for (i = 0; i < parse->nparams; i++)
+ handle_esc_bracket_hl (display, parse->params[i], 1);
+ break;
+ case 'm': /* ECMA-48 <SGR>. */
+ for (i = 0; i < parse->nparams; i++)
+ handle_esc_bracket_m (&display->attr, parse->params[i]);
+ break;
+ case 'J': /* ECMA-48 <ED>. */
+ switch (parse->params[0])
+ {
+ case 0:
+ /* Clear to end of screen: <ed>. */
+ screen_fill (display, user->cursor.col, user->cursor.row,
+ user->screen.width - 1, user->screen.height - 1,
+ L' ', display->attr.current);
+ break;
+ case 1:
+ /* Clear to beginning of screen. */
+ screen_fill (display, 0, 0,
+ user->cursor.col, user->cursor.row,
+ L' ', display->attr.current);
+ break;
+ case 2:
+ /* Clear entire screen. */
+ screen_fill (display, 0, 0,
+ user->screen.width - 1, user->screen.height - 1,
+ L' ', display->attr.current);
+ break;
+ }
+ break;
+ case 'K': /* ECMA-48 <EL>. */
+ switch (parse->params[0])
+ {
+ case 0:
+ /* Clear to end of line: <el>. */
+ screen_fill (display, user->cursor.col, user->cursor.row,
+ user->screen.width - 1, user->cursor.row,
+ L' ', display->attr.current);
+ break;
+ case 1:
+ /* Clear to beginning of line: <el1>. */
+ screen_fill (display, 0, user->cursor.row,
+ user->cursor.col, user->cursor.row,
+ L' ', display->attr.current);
+ break;
+ case 2:
+ /* Clear entire line. */
+ screen_fill (display, 0, user->cursor.row,
+ user->screen.width - 1, user->cursor.row,
+ L' ', display->attr.current);
+ break;
+ }
+ break;
+ case 'L': /* ECMA-48 <IL>. */
+ /* Insert line(s): <il1>, <il>. */
+ screen_shift_right (display, 0, user->cursor.row,
+ user->screen.width - 1,
+ (user->cursor.row <= display->csr.bottom)
+ ? display->csr.bottom : user->screen.height - 1,
+ (parse->params[0] ?: 1) * user->screen.width,
+ L' ', display->attr.current);
+ break;
+ case 'M': /* ECMA-48 <DL>. */
+ /* Delete line(s): <dl1>, <dl>. */
+ screen_shift_left (display, 0, user->cursor.row,
+ user->screen.width - 1,
+ (user->cursor.row <= display->csr.bottom)
+ ? display->csr.bottom : user->screen.height - 1,
+ (parse->params[0] ?: 1) * user->screen.width,
+ L' ', display->attr.current);
+ break;
+ case '@': /* ECMA-48 <ICH>. */
+ /* Insert character(s): <ich1>, <ich>. */
+ screen_shift_right (display, user->cursor.col, user->cursor.row,
+ user->screen.width - 1, user->cursor.row,
+ parse->params[0] ?: 1,
+ L' ', display->attr.current);
+ break;
+ case 'P': /* ECMA-48 <DCH>. */
+ /* Delete character(s): <dch1>, <dch>. */
+ screen_shift_left (display, user->cursor.col, user->cursor.row,
+ user->screen.width - 1, user->cursor.row,
+ parse->params[0] ?: 1,
+ L' ', display->attr.current);
+ break;
+ case 'r': /* VT100: Set scrolling region. */
+ if (!parse->params[1])
+ {
+ display->csr.top = 0;
+ display->csr.bottom = user->screen.height - 1;
+ }
+ else
+ {
+ if (parse->params[1] <= user->screen.height
+ && parse->params[0] < parse->params[1])
+ {
+ display->csr.top = parse->params[0] ? parse->params[0] - 1 : 0;
+ display->csr.bottom = parse->params[1] - 1;
+ user->cursor.col = 0;
+ user->cursor.row = 0;
+ /* XXX Flag cursor change. */
+ }
+ }
+ break;
+ case 'S': /* ECMA-48 <SU>. */
+ /* Scroll up: <ind>, <indn>. */
+ screen_shift_left (display, 0, display->csr.top,
+ user->screen.width - 1, display->csr.bottom,
+ (parse->params[0] ?: 1) * user->screen.width,
+ L' ', display->attr.current);
+ break;
+ case 'T': /* ECMA-48 <SD>. */
+ /* Scroll down: <ri>, <rin>. */
+ screen_shift_right (display, 0, display->csr.top,
+ user->screen.width - 1, display->csr.bottom,
+ (parse->params[0] ?: 1) * user->screen.width,
+ L' ', display->attr.current);
+ break;
+ case 'X': /* ECMA-48 <ECH>. */
+ /* Erase character(s): <ech>. */
+ {
+ int col = user->cursor.col;
+ if (parse->params[0] - 1 > 0)
+ col += parse->params[0] - 1;
+ if (col > user->screen.width - 1)
+ col = user->screen.width - 1;
+
+ screen_fill (display, user->cursor.col, user->cursor.row,
+ col, user->cursor.row, L' ', display->attr.current);
+ }
+ break;
+ case 'I': /* ECMA-48 <CHT>. */
+ /* Horizontal tab. */
+ if (!parse->params[0])
+ parse->params[0] = 1;
+ while (parse->params[0]--)
+ horizontal_tab (display);
+ break;
+ case 'Z': /* ECMA-48 <CBT>. */
+ /* Cursor backward tabulation: <cbt>. */
+ if (parse->params[0] > user->screen.height * (user->screen.width / 8))
+ {
+ user->cursor.col = 0;
+ user->cursor.row = 0;
+ }
+ else
+ {
+ int i = parse->params[0] ?: 1;
+
+ while (i--)
+ {
+ if (user->cursor.col == 0)
+ {
+ if (user->cursor.row == 0)
+ break;
+ else
+ {
+ user->cursor.col = user->screen.width - 1;
+ user->cursor.row--;
+ }
+ }
+ else
+ user->cursor.col--;
+ user->cursor.col &= ~7;
+ }
+ }
+ }
+}
+
+
+static void
+handle_esc_bracket_question_hl (display_t display, int code, int flag)
+{
+ switch (code)
+ {
+ case 25:
+ /* Cursor invisibility: <civis>, <cnorm>. */
+ if (flag)
+ display->user->cursor.status = CONS_CURSOR_NORMAL;
+ else
+ display->user->cursor.status = CONS_CURSOR_INVISIBLE;
+ /* XXX Flag cursor status change. */
+ break;
+ case 1000:
+ /* XTerm mouse tracking. */
+ if (flag)
+ display->user->flags |= CONS_FLAGS_TRACK_MOUSE;
+ else
+ display->user->flags &= ~CONS_FLAGS_TRACK_MOUSE;
+ /* XXX Flag flags change. */
+ break;
+ }
+}
+
+
+static void
+handle_esc_bracket_question (display_t display, char op)
+{
+ parse_t parse = &display->output.parse;
+
+ int i;
+ switch (op)
+ {
+ case 'l':
+ /* Reset mode. */
+ for (i = 0; i < parse->nparams; ++i)
+ handle_esc_bracket_question_hl (display, parse->params[i], 0);
+ break;
+ case 'h':
+ /* Set mode. */
+ for (i = 0; i < parse->nparams; ++i)
+ handle_esc_bracket_question_hl (display, parse->params[i], 1);
+ break;
+ }
+}
+
+
+static void
+handle_esc_bracket_right_angle_hl (display_t display, int code, int flag)
+{
+ switch (code)
+ {
+ case 1:
+ /* Bold: <gsbom>, <grbom>. This is a GNU extension. */
+ if (flag)
+ display->attr.current.bold = 1;
+ else
+ display->attr.current.bold = 0;
+ break;
+ }
+}
+
+
+static void
+handle_esc_bracket_right_angle (display_t display, char op)
+{
+ parse_t parse = &display->output.parse;
+
+ int i;
+ switch (op)
+ {
+ case 'l':
+ /* Reset mode. */
+ for (i = 0; i < parse->nparams; ++i)
+ handle_esc_bracket_right_angle_hl (display, parse->params[i], 0);
+ break;
+ case 'h':
+ /* Set mode. */
+ for (i = 0; i < parse->nparams; ++i)
+ handle_esc_bracket_right_angle_hl (display, parse->params[i], 1);
+ break;
+ }
+}
+
+
+static wchar_t
+altchar_to_ucs4 (wchar_t chr)
+{
+ /* Alternative character set frobbing. */
+ switch (chr)
+ {
+ case L'+':
+ return CONS_CHAR_RARROW;
+ case L',':
+ return CONS_CHAR_LARROW;
+ case L'-':
+ return CONS_CHAR_UARROW;
+ case L'.':
+ return CONS_CHAR_DARROW;
+ case L'0':
+ return CONS_CHAR_BLOCK;
+ case L'I':
+ return CONS_CHAR_LANTERN;
+ case L'`':
+ return CONS_CHAR_DIAMOND;
+ case L'a':
+ return CONS_CHAR_CKBOARD;
+ case L'f':
+ return CONS_CHAR_DEGREE;
+ case L'g':
+ return CONS_CHAR_PLMINUS;
+ case L'h':
+ return CONS_CHAR_BOARD;
+ case L'j':
+ return CONS_CHAR_LRCORNER;
+ case L'k':
+ return CONS_CHAR_URCORNER;
+ case L'l':
+ return CONS_CHAR_ULCORNER;
+ case L'm':
+ return CONS_CHAR_LLCORNER;
+ case L'n':
+ return CONS_CHAR_PLUS;
+ case L'o':
+ return CONS_CHAR_S1;
+ case L'p':
+ return CONS_CHAR_S3;
+ case L'q':
+ return CONS_CHAR_HLINE;
+ case L'r':
+ return CONS_CHAR_S7;
+ case L's':
+ return CONS_CHAR_S9;
+ case L't':
+ return CONS_CHAR_LTEE;
+ case L'u':
+ return CONS_CHAR_RTEE;
+ case L'v':
+ return CONS_CHAR_BTEE;
+ case L'w':
+ return CONS_CHAR_TTEE;
+ case L'x':
+ return CONS_CHAR_VLINE;
+ case L'y':
+ return CONS_CHAR_LEQUAL;
+ case L'z':
+ return CONS_CHAR_GEQUAL;
+ case L'{':
+ return CONS_CHAR_PI;
+ case L'|':
+ return CONS_CHAR_NEQUAL;
+ case L'}':
+ return CONS_CHAR_STERLING;
+ case L'~':
+ return CONS_CHAR_BULLET;
+ default:
+ return chr;
+ }
+}
+
+/* Display must be locked. */
+static void
+display_output_one (display_t display, wchar_t chr)
+{
+ struct cons_display *user = display->user;
+ parse_t parse = &display->output.parse;
+
+ switch (parse->state)
+ {
+ case STATE_NORMAL:
+ switch (chr)
+ {
+ case L'\r':
+ /* Carriage return: <cr>. */
+ if (user->cursor.col)
+ {
+ user->cursor.col = 0;
+ /* XXX Flag cursor update. */
+ }
+ break;
+ case L'\n':
+ /* Line feed. */
+ linefeed (display);
+ break;
+ case L'\b':
+ /* Backspace. */
+ if (user->cursor.col > 0 || user->cursor.row > 0)
+ {
+ if (user->cursor.col > 0)
+ user->cursor.col--;
+ else
+ {
+ /* This implements the <bw> functionality. */
+ user->cursor.col = user->screen.width - 1;
+ user->cursor.row--;
+ }
+ /* XXX Flag cursor update. */
+ }
+ break;
+ case L'\t':
+ /* Horizontal tab: <ht> */
+ horizontal_tab (display);
+ break;
+ case L'\033':
+ parse->state = STATE_ESC;
+ break;
+ case L'\0':
+ /* Padding character: <pad>. */
+ break;
+ case L'\a':
+ /* Audible bell. */
+ user->bell.audible++;
+ break;
+ default:
+ {
+ int line;
+ int idx;
+
+ if (user->cursor.col >= user->screen.width)
+ {
+ user->cursor.col = 0;
+ linefeed (display);
+ }
+
+ line = (user->screen.cur_line + user->cursor.row)
+ % user->screen.lines;
+ idx = line * user->screen.width + user->cursor.col;
+ int width, i;
+
+ width = wcwidth (chr);
+ if (width < 0)
+ width = 1;
+
+ if (display->insert_mode
+ && user->cursor.col < user->screen.width - width)
+ {
+ /* If in insert mode, do the same as <ich1>. */
+ screen_shift_right (display, user->cursor.col,
+ user->cursor.row,
+ user->screen.width - 1, user->cursor.row,
+ width, L' ', display->attr.current);
+ }
+
+ if (display->attr.altchar)
+ chr = altchar_to_ucs4 (chr);
+
+ for (i = 0; i < width; i++)
+ {
+ if (user->cursor.col >= user->screen.width)
+ break;
+ user->_matrix[idx+i].chr = chr;
+ user->_matrix[idx+i].attr = display->attr.current;
+ user->cursor.col++;
+ chr |= CONS_WCHAR_CONTINUED;
+ }
+
+ if (i > 0)
+ display_record_filechange (display, idx, idx + i - 1);
+
+ if (user->cursor.col > user->screen.width)
+ {
+ user->cursor.col = 0;
+ linefeed (display);
+ }
+ }
+ break;
+ }
+ break;
+
+ case STATE_ESC:
+ parse->state = STATE_NORMAL;
+ switch (chr)
+ {
+ case L'[':
+ parse->state = STATE_ESC_BRACKET_INIT;
+ break;
+ case L'M': /* ECMA-48 <RIS>. */
+ /* Reset: <rs2>. */
+ display->attr.current = display->attr.attr_def;
+ display->attr.altchar = 0;
+ display->insert_mode = 0;
+ display->csr.top = 0;
+ display->csr.bottom = user->screen.height - 1;
+ user->cursor.status = CONS_CURSOR_NORMAL;
+ /* Fall through. */
+ case L'c':
+ /* Clear screen and home cursor: <clear>. */
+ screen_fill (display, 0, 0,
+ user->screen.width - 1, user->screen.height - 1,
+ L' ', display->attr.current);
+ user->cursor.col = user->cursor.row = 0;
+ /* XXX Flag cursor change. */
+ break;
+ case L'E': /* ECMA-48 <NEL>. */
+ /* Newline. */
+ user->cursor.col = 0;
+ linefeed (display);
+ break;
+ case L'7': /* VT100: Save cursor and attributes. */
+ /* Save cursor position: <sc>. */
+ display->cursor.saved_x = user->cursor.col;
+ display->cursor.saved_y = user->cursor.row;
+ break;
+ case L'8': /* VT100: Restore cursor and attributes. */
+ /* Restore cursor position: <rc>. */
+ user->cursor.col = display->cursor.saved_x;
+ user->cursor.row = display->cursor.saved_y;
+ /* In case the screen was larger before: */
+ limit_cursor (display);
+ break;
+ case L'g':
+ /* Visible bell. */
+ user->bell.visible++;
+ break;
+ default:
+ /* Unsupported escape sequence. */
+ break;
+ }
+ break;
+
+ case STATE_ESC_BRACKET_INIT:
+ memset (&parse->params, 0, sizeof parse->params);
+ parse->nparams = 0;
+ if (chr == '?')
+ {
+ parse->state = STATE_ESC_BRACKET_QUESTION;
+ break; /* Consume the question mark. */
+ }
+ else if (chr == '>')
+ {
+ parse->state = STATE_ESC_BRACKET_RIGHT_ANGLE;
+ break; /* Consume the right angle. */
+ }
+ else
+ parse->state = STATE_ESC_BRACKET;
+ /* Fall through. */
+ case STATE_ESC_BRACKET:
+ case STATE_ESC_BRACKET_QUESTION:
+ case STATE_ESC_BRACKET_RIGHT_ANGLE:
+ if (chr >= '0' && chr <= '9')
+ parse->params[parse->nparams]
+ = parse->params[parse->nparams]*10 + chr - '0';
+ else if (chr == ';')
+ {
+ if (++(parse->nparams) >= PARSE_MAX_PARAMS)
+ parse->state = STATE_NORMAL; /* too many */
+ }
+ else
+ {
+ parse->nparams++;
+ if (parse->state == STATE_ESC_BRACKET)
+ handle_esc_bracket (display, chr);
+ else if (parse->state == STATE_ESC_BRACKET_RIGHT_ANGLE)
+ handle_esc_bracket_right_angle (display, chr);
+ else
+ handle_esc_bracket_question (display, chr);
+ parse->state = STATE_NORMAL;
+ }
+ break;
+ default:
+ abort ();
+ }
+}
+
+/* Output LENGTH bytes starting from BUFFER in the system encoding.
+ Set BUFFER and LENGTH to the new values. The exact semantics are
+ just as in the iconv interface. */
+static error_t
+display_output_some (display_t display, char **buffer, size_t *length)
+{
+#define CONV_OUTBUF_SIZE 256
+ error_t err = 0;
+
+ display->changes.cursor.col = display->user->cursor.col;
+ display->changes.cursor.row = display->user->cursor.row;
+ display->changes.cursor.status = display->user->cursor.status;
+ display->changes.screen.cur_line = display->user->screen.cur_line;
+ display->changes.screen.scr_lines = display->user->screen.scr_lines;
+ display->changes.bell_audible = display->user->bell.audible;
+ display->changes.bell_visible = display->user->bell.visible;
+ display->changes.flags = display->user->flags;
+ display->changes.which = ~DISPLAY_CHANGE_MATRIX;
+
+ while (!err && *length > 0)
+ {
+ size_t nconv;
+ wchar_t outbuf[CONV_OUTBUF_SIZE];
+ char *outptr = (char *) outbuf;
+ size_t outsize = CONV_OUTBUF_SIZE * sizeof (wchar_t);
+ error_t saved_err;
+ int i;
+
+ nconv = iconv (display->output.cd, buffer, length, &outptr, &outsize);
+ saved_err = errno;
+
+ /* First process all successfully converted characters. */
+ for (i = 0; i < CONV_OUTBUF_SIZE - outsize / sizeof (wchar_t); i++)
+ display_output_one (display, outbuf[i]);
+
+ if (nconv == (size_t) -1)
+ {
+ /* Conversion is not completed, look for recoverable
+ errors. */
+#define UNICODE_REPLACEMENT_CHARACTER ((wchar_t) 0xfffd)
+ if (saved_err == EILSEQ)
+ {
+ assert (*length);
+ (*length)--;
+ (*buffer)++;
+ display_output_one (display, UNICODE_REPLACEMENT_CHARACTER);
+ }
+ else if (saved_err == EINVAL)
+ /* This is only an unfinished byte sequence at the end of
+ the input buffer. */
+ break;
+ else if (saved_err != E2BIG)
+ err = saved_err;
+ }
+ }
+
+ display_flush_filechange (display, ~0);
+ return err;
+}
+
+
+/* Forward declaration. */
+void display_destroy_complete (void *pi);
+
+void
+display_init (void)
+{
+ user_pager_init ();
+
+ /* Create the notify bucket, and start to serve notifications. */
+ notify_bucket = ports_create_bucket ();
+ if (! notify_bucket)
+ error (5, errno, "Cannot create notify bucket");
+ notify_class = ports_create_class (display_destroy_complete, NULL);
+ if (! notify_class)
+ error (5, errno, "Cannot create notify class");
+
+ cthread_detach (cthread_fork ((cthread_fn_t) service_notifications,
+ (any_t) notify_bucket));
+}
+
+
+/* Create a new virtual console display, with the system encoding
+ being ENCODING. */
+error_t
+display_create (display_t *r_display, const char *encoding,
+ conchar_attr_t def_attr, unsigned int lines,
+ unsigned int width, unsigned int height)
+{
+ error_t err = 0;
+ display_t display;
+
+ *r_display = NULL;
+ display = calloc (1, sizeof *display);
+ if (!display)
+ return ENOMEM;
+
+ err = ports_create_port (notify_class, notify_bucket, sizeof (struct notify),
+ &display->notify_port);
+ if (err)
+ {
+ free (display);
+ return err;
+ }
+ display->notify_port->display = display;
+
+ mutex_init (&display->lock);
+ display->attr.attr_def = def_attr;
+ display->attr.current = display->attr.attr_def;
+ display->csr.bottom = height - 1;
+
+ err = user_create (display, width, height, lines, L' ',
+ display->attr.current);
+ if (err)
+ {
+ ports_destroy_right (display->notify_port);
+ free (display);
+ return err;
+ }
+
+ err = output_init (&display->output, encoding);
+ if (err)
+ {
+ user_destroy (display);
+ ports_destroy_right (display->notify_port);
+ free (display);
+ }
+ *r_display = display;
+ return err;
+}
+
+
+/* Destroy the display DISPLAY. */
+void
+display_destroy (display_t display)
+{
+ mutex_lock (&display->lock);
+ if (display->filemod_reqs_pending)
+ {
+ free_modreqs (display->filemod_reqs_pending);
+ display->filemod_reqs_pending = NULL;
+ }
+ if (display->filemod_reqs)
+ {
+ free_modreqs (display->filemod_reqs);
+ display->filemod_reqs = NULL;
+ }
+ ports_destroy_right (display->notify_port);
+ output_deinit (&display->output);
+ user_destroy (display);
+ mutex_unlock (&display->lock);
+
+ /* We can not free the display structure here, because it might
+ still be needed by pending modification requests when msg
+ accepted notifications are handled. So we have to wait until all
+ notifications have arrived and the notify port is completely
+ deallocated, which will invoke display_destroy_complete
+ below. */
+}
+
+
+/* Complete destruction of the display DISPLAY. */
+void
+display_destroy_complete (void *pi)
+{
+ struct display *display = ((struct notify *) pi)->display;
+ free (display);
+}
+
+
+/* Return the dimension of the display in bytes. */
+off_t
+display_get_size (display_t display)
+{
+ return sizeof (struct cons_display)
+ + (sizeof (conchar_t) * display->user->screen.width
+ * display->user->screen.lines);
+}
+
+
+/* Return the dimensions of the display DISPLAY in *WINSIZE. */
+void
+display_getsize (display_t display, struct winsize *winsize)
+{
+ mutex_lock (&display->lock);
+ winsize->ws_row = display->user->screen.height;
+ winsize->ws_col = display->user->screen.width;
+ winsize->ws_xpixel = 0;
+ winsize->ws_ypixel = 0;
+ mutex_unlock (&display->lock);
+}
+
+
+/* Set the owner of the display DISPLAY to PID. The owner receives
+ the SIGWINCH signal when the terminal size changes. */
+error_t
+display_set_owner (display_t display, pid_t pid)
+{
+ mutex_lock (&display->lock);
+ display->has_owner = 1;
+ display->owner_id = pid;
+ mutex_unlock (&display->lock);
+ return 0;
+}
+
+
+/* Return the owner of the display DISPLAY in PID. If there is no
+ owner, return ENOTTY. */
+error_t
+display_get_owner (display_t display, pid_t *pid)
+{
+ error_t err = 0;
+ mutex_lock (&display->lock);
+ if (!display->has_owner)
+ err = ENOTTY;
+ else
+ *pid = display->owner_id;
+ mutex_unlock (&display->lock);
+ return err;
+}
+
+/* Output DATALEN characters from the buffer DATA on display DISPLAY.
+ The DATA must be supplied in the system encoding configured for
+ DISPLAY. The function returns the amount of bytes written (might
+ be smaller than DATALEN) or -1 and the error number in errno. If
+ NONBLOCK is not zero, return with -1 and set errno to EWOULDBLOCK
+ if operation would block for a long time. */
+ssize_t
+display_output (display_t display, int nonblock, char *data, size_t datalen)
+{
+ output_t output = &display->output;
+ error_t err;
+ char *buffer;
+ size_t buffer_size;
+ ssize_t amount;
+
+ error_t ensure_output_buffer_size (size_t new_size)
+ {
+ /* Must be a power of two. */
+#define OUTPUT_ALLOCSIZE 32
+
+ if (output->allocated < new_size)
+ {
+ char *new_buffer;
+ new_size = (new_size + OUTPUT_ALLOCSIZE - 1)
+ & ~(OUTPUT_ALLOCSIZE - 1);
+ new_buffer = realloc (output->buffer, new_size);
+ if (!new_buffer)
+ return ENOMEM;
+ output->buffer = new_buffer;
+ output->allocated = new_size;
+ }
+ return 0;
+ }
+
+ mutex_lock (&display->lock);
+ while (output->stopped)
+ {
+ if (nonblock)
+ {
+ mutex_unlock (&display->lock);
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+ if (hurd_condition_wait (&output->resumed, &display->lock))
+ {
+ mutex_unlock (&display->lock);
+ errno = EINTR;
+ return -1;
+ }
+ }
+
+ if (output->size)
+ {
+ err = ensure_output_buffer_size (output->size + datalen);
+ if (err)
+ {
+ mutex_unlock (&display->lock);
+ errno = ENOMEM;
+ return -1;
+ }
+ buffer = output->buffer;
+ buffer_size = output->size;
+ memcpy (buffer + buffer_size, data, datalen);
+ buffer_size += datalen;
+ }
+ else
+ {
+ buffer = data;
+ buffer_size = datalen;
+ }
+ amount = buffer_size;
+ err = display_output_some (display, &buffer, &buffer_size);
+ amount -= buffer_size;
+
+ if (err && !amount)
+ {
+ mutex_unlock (&display->lock);
+ errno = err;
+ return err;
+ }
+ if (buffer_size)
+ {
+ /* If we used the caller's buffer DATA, the remaining bytes
+ might not fit in our internal output buffer. In this case we
+ can reallocate the buffer in VCONS without needing to update
+ OUTPUT (as it points into DATA). */
+ err = ensure_output_buffer_size (buffer_size);
+ if (err)
+ {
+ mutex_unlock (&display->lock);
+ return err;
+ }
+ memmove (output->buffer, buffer, buffer_size);
+ }
+ output->size = buffer_size;
+ amount += buffer_size;
+
+ mutex_unlock (&display->lock);
+ return amount;
+}
+
+
+ssize_t
+display_read (display_t display, int nonblock, off_t off,
+ char *data, size_t len)
+{
+ mutex_lock (&display->lock);
+ memcpy (data, ((char *) display->user) + off, len);
+ mutex_unlock (&display->lock);
+ return len;
+}
+
+
+/* Resume the output on the display DISPLAY. */
+void
+display_start_output (display_t display)
+{
+ mutex_lock (&display->lock);
+ if (display->output.stopped)
+ {
+ display->output.stopped = 0;
+ condition_broadcast (&display->output.resumed);
+ }
+ display->changes.flags = display->user->flags;
+ display->changes.which = DISPLAY_CHANGE_FLAGS;
+ display->user->flags &= ~CONS_FLAGS_SCROLL_LOCK;
+ display_flush_filechange (display, DISPLAY_CHANGE_FLAGS);
+ mutex_unlock (&display->lock);
+}
+
+
+/* Stop all output on the display DISPLAY. */
+void
+display_stop_output (display_t display)
+{
+ mutex_lock (&display->lock);
+ display->output.stopped = 1;
+ display->changes.flags = display->user->flags;
+ display->changes.which = DISPLAY_CHANGE_FLAGS;
+ display->user->flags |= CONS_FLAGS_SCROLL_LOCK;
+ display_flush_filechange (display, DISPLAY_CHANGE_FLAGS);
+ mutex_unlock (&display->lock);
+}
+
+
+/* Return the number of pending output bytes for DISPLAY. */
+size_t
+display_pending_output (display_t display)
+{
+ int output_size;
+ mutex_lock (&display->lock);
+ output_size = display->output.size;
+ mutex_unlock (&display->lock);
+ return output_size;
+}
+
+
+/* Flush the output buffer, discarding all pending data. */
+void
+display_discard_output (display_t display)
+{
+ mutex_lock (&display->lock);
+ display->output.size = 0;
+ mutex_unlock (&display->lock);
+}
+
+
+mach_port_t
+display_get_filemap (display_t display, vm_prot_t prot)
+{
+ mach_port_t memobj;
+ mutex_lock (&display->lock);
+ memobj = user_pager_get_filemap (&display->user_pager, prot);
+ mutex_unlock (&display->lock);
+ return memobj;
+}
diff --git a/console/display.h b/console/display.h
new file mode 100644
index 00000000..d64cf69e
--- /dev/null
+++ b/console/display.h
@@ -0,0 +1,84 @@
+/* display.h - Interface to the display component of a virtual console.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#include <sys/ioctl.h>
+
+struct display;
+typedef struct display *display_t;
+
+void display_init (void);
+
+/* Create a new virtual console display, with the system encoding
+ being ENCODING and the default colors being FOREGROUND and BACKGROUND. */
+error_t
+display_create (display_t *r_display, const char *encoding,
+ conchar_attr_t def_attr, unsigned int lines,
+ unsigned int width, unsigned int height);
+
+
+/* Destroy the display DISPLAY. */
+void display_destroy (display_t display);
+
+/* Return the dimension of the display in bytes. */
+off_t display_get_size (display_t display);
+
+/* Return the dimensions of the display DISPLAY in *WINSIZE. */
+void display_getsize (display_t display, struct winsize *winsize);
+
+/* Set the owner of the display DISPLAY to PID. The owner receives
+ the SIGWINCH signal when the terminal size changes. */
+error_t display_set_owner (display_t display, pid_t pid);
+
+/* Return the owner of the display DISPLAY in PID. If there is no
+ owner, return ENOTTY. */
+error_t display_get_owner (display_t display, pid_t *pid);
+
+/* Output DATALEN characters from the buffer DATA on display DISPLAY.
+ The DATA must be supplied in the system encoding configured for
+ DISPLAY. The function returns the amount of bytes written (might
+ be smaller than DATALEN) or -1 and the error number in errno. If
+ NONBLOCK is not zero, return with -1 and set errno to EWOULDBLOCK
+ if operation would block for a long time. */
+ssize_t display_output (display_t display, int nonblock, char *data,
+ size_t datalen);
+
+mach_port_t display_get_filemap (display_t display, vm_prot_t prot);
+
+ssize_t display_read (display_t display, int nonblock, off_t off,
+ char *data, size_t len);
+
+error_t display_notice_changes (display_t display, mach_port_t notify);
+
+/* Resume the output on the display DISPLAY. */
+void display_start_output (display_t display);
+
+/* Stop all output on the display DISPLAY. */
+void display_stop_output (display_t display);
+
+/* Return the number of pending output bytes for DISPLAY. */
+size_t display_pending_output (display_t display);
+
+/* Flush the output buffer, discarding all pending data. */
+void display_discard_output (display_t display);
+
+#endif /* DISPLAY_H */
diff --git a/console/hurd.ti b/console/hurd.ti
new file mode 100644
index 00000000..2508482a
--- /dev/null
+++ b/console/hurd.ti
@@ -0,0 +1,164 @@
+hurd|The GNU Hurd console server,
+# Over-all properties.
+# We use 8-bit characters
+ km,
+# Although we don't do XON/XOFF, we don't want padding characters.
+ xon,
+# Hard reset.
+ rs1=\EM,
+
+# Note about compatibility to vt100: We don't specify <xenl>, as we
+# don't have the eat_newline_glitch. We don't support setting or
+# removing tab stops (hts/tbc).
+
+# Cursor related capabilities.
+
+# Moving the cursor.
+# We have automatic margins.
+ am,
+# We wrap around the left edge.
+ bw,
+# Carriage return and newline.
+ cr=^M, nel=^M^J,
+# Move cursor to home position (to position P1, P2).
+ home=\E[H, cup=\E[%i%p1%d;%p2%dH,
+# Move cursor one character (P1 characters) backwards.
+# We use ^H instead \E[D for cub1, as only ^H implements <bw> and it
+# is one byte instead three.
+ cub1=^H, cub=\E[%p1%dD,
+# Move cursor one line (P1 lines) downwards.
+ cud1=\E[B, cud=\E[%p1%dB,
+# Move cursor one character (P1 characters) forwards.
+ cuf1=\E[C, cuf=\E[%p1%dC,
+# Move cursor one line (P1 lines) upwards.
+ cuu1=\E[A, cuu=\E[%p1%dA,
+# Set horizontal (vertical) cursor position to P1.
+ hpa=\E[%i%p1%dG, vpa=\E[%i%p1%dd,
+# Save (restore) cursor position.
+ sc=\E7, rc=\E8,
+# Set the scrolling region to lines P1 to P2.
+ csr=\E[%i%p1%d;%p2%dr,
+
+# Modifying cursor attributes.
+# Make cursor invisible, very visible or normal.
+ civis=\E[?25l, cvvis=\E[34l, cnorm=\E[?25h,
+
+# Tabulator stops.
+# We have tabulator stops every eight rows.
+ it#8,
+# Move cursor to next tabulator stop.
+ ht=^I,
+# Move cursor to previous tabulator stop.
+ cbt=\E[Z,
+# XXX When we implement this.
+# Set tab stop in the current column of every row.
+# hts=\EH,
+# Delete all tab stops.
+# tbc=\E[3g,
+
+
+# Screen editing capabilities.
+# Clear screen.
+ clear=\Ec,
+# Clear to end of screen.
+ ed=\E[J,
+# Clear to end (beginning) of line.
+ el=\E[K, el1=\E[1K,
+
+# Insert one character (P1 characters).
+# <ich1> not included because we have insert mode.
+# ich1=\E[@,
+ ich=\E[%p1%d@,
+# Enter (leave) insert mode.
+ smir=\E[4h, rmir=\E[4l,
+# It is save to move when in insert mode.
+ mir,
+# Delete one character (P1 characters).
+ dch1=\E[P, dch=\E[%p1%dP,
+# Erase the next N characters.
+ ech=\E[%p1%dX,
+# Insert one line (P1 lines).
+ il1=\E[L, il=\E[%p1%dL,
+# Delete one line (P1 lines).
+ dl1=\E[M, dl=\E[%p1%dM,
+# Scroll the whole screen one line (P1 lines) upwards. We don't use
+# ^J, because this could put things into the scrollback buffer.
+ ind=\E[S, indn=\E[%p1%dS,
+# Scroll the whole screen one line (P1 lines) downwards.
+ rin=\E[%p1%dT, ri=\E[T,
+
+
+# Bell capabilities.
+# Audible bell.
+ bel=^G,
+# Flash the screen (visible bell).
+ flash=\Eg,
+
+
+# Keycodes for special keys.
+# Backspace key.
+ kbs=\177,
+# Keycode for left, down, right and up arrow key.
+ kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA,
+# Keycodes for function keys.
+ kf1=\EOP, kf2=\EOQ, kf3=\EOR, kf4=\EOS, kf5=\E[15~,
+ kf6=\E[17~, kf7=\E[18~, kf8=\E[19~, kf9=\E[20~,
+ kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf13=\E[25~,
+ kf14=\E[26~, kf15=\E[28~, kf16=\E[29~, kf17=\E[31~,
+ kf18=\E[32~, kf19=\E[33~, kf20=\E[34~,
+# Keycode for backtab key.
+ kcbt=\E[Z,
+# Keycode for suspend key.
+ kspd=^Z,
+# Keycode for home (insert, delete, end) key.
+ khome=\E[1~, kich1=\E[2~, kdch1=\E[3~, kend=\E[4~,
+# Keycode for previous (next) page key.
+ kpp=\E[5~, knp=\E[6~,
+# Keycode for center of keypad area.
+ kb2=\E[G,
+# Mouse event has occurred.
+ kmous=\E[M,
+
+# Text attribute capabilities.
+ acsc=++\,\,--..00ii``aaffgghhjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
+
+# Color support.
+# We erase the screen with the current background color.
+ bce,
+# Number of colors and color pairs at the same time.
+ colors#8,
+ pairs#64,
+# Video attributes colliding with color.
+# ORed: A_STANDOUT 1, A_UNDERLINE 2, A_REVERSE 4, A_BLINK 8, A_DIM 16,
+# A_BOLD 32, A_INVIS 64
+# We don't define this as we do our own display optimization,
+# depending on the display driver. Alternatively, we could provide
+# different terminfo entries.
+# ncv#18,
+# Set background (foreground) color.
+ setab=\E[4%p1%dm, setaf=\E[3%p1%dm,
+# Set default color pair to its original value.
+ op=\E[39;49m,
+
+# Video attributes.
+# Overstrikes are erasable with a blank.
+ eo,
+# It is save to move when in standout mode.
+ msgr,
+# Enable dim (blinking, bold, invisible, reverse) attribute.
+ dim=\E[2m, blink=\E[5m, bold=\E[1m, invis=\E[8m, rev=\E[7m,
+# Enable (disable) standout mode.
+ smso=\E[7m, rmso=\E[27m,
+# Enable (disable) underline mode.
+ smul=\E[4m, rmul=\E[24m,
+# Enable (disable) italic mode.
+ sitm=\E[3m, ritm=\E[23m,
+# Enable (disable) real bold (not intensity bright) mode. This is a
+# GNU extension.
+ gsbom=\E[>1h, grbom=\E[>1l,
+# Enable (disable) alternative character set.
+ smacs=\E[11m, rmacs=\E[10m,
+# Set all attributes.
+ sgr=\E[0%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;11%;m,
+# Reset all attributes.
+ sgr0=\E[0m,
diff --git a/console/input.c b/console/input.c
new file mode 100644
index 00000000..14879d07
--- /dev/null
+++ b/console/input.c
@@ -0,0 +1,277 @@
+/* input.c - Input component of a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <iconv.h>
+#include <error.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/types.h>
+
+#include <cthreads.h>
+
+#include "input.h"
+
+struct input
+{
+ struct mutex lock;
+
+ struct condition data_available;
+ struct condition space_available;
+#define INPUT_QUEUE_SIZE 300
+ char buffer[INPUT_QUEUE_SIZE];
+ int full;
+ size_t size;
+
+ /* The state of the conversion of input characters. */
+ iconv_t cd;
+ /* The conversion routine might refuse to handle some incomplete
+ multi-byte or composed character at the end of the buffer, so we
+ have to keep them around. */
+ char *cd_buffer;
+ size_t cd_size;
+ size_t cd_allocated;
+};
+
+/* Create a new virtual console input queue, with the system encoding
+ being ENCODING. */
+error_t input_create (input_t *r_input, const char *encoding)
+{
+ input_t input = calloc (1, sizeof *input);
+ if (!input)
+ return ENOMEM;
+
+ mutex_init (&input->lock);
+ condition_init (&input->data_available);
+ condition_init (&input->space_available);
+
+ input->cd = iconv_open (encoding, "UTF-8");
+ if (input->cd == (iconv_t) -1)
+ {
+ free (input);
+ return errno;
+ }
+
+ *r_input = input;
+ return 0;
+}
+
+/* Destroy the input queue INPUT. */
+void input_destroy (input_t input)
+{
+ iconv_close (input->cd);
+ free (input);
+}
+
+/* Enter DATALEN characters from the buffer DATA into the input queue
+ INPUT. The DATA must be supplied in UTF-8 encoding (XXX UCS-4
+ would be nice, too, but it requires knowledge of endianess). The
+ function returns the amount of bytes written (might be smaller than
+ DATALEN) or -1 and the error number in errno. If NONBLOCK is not
+ zero, return with -1 and set errno to EWOULDBLOCK if operation
+ would block for a long time. */
+ssize_t input_enqueue (input_t input, int nonblock, char *data,
+ size_t datalen)
+{
+ error_t err = 0;
+ int was_empty;
+ int enqueued = 0;
+ char *buffer;
+ size_t buffer_size;
+ ssize_t amount;
+ size_t nconv;
+ char *outbuf;
+ size_t outbuf_size;
+
+ error_t ensure_cd_buffer_size (size_t new_size)
+ {
+ /* Must be a power of two. */
+#define CD_ALLOCSIZE 32
+
+ if (input->cd_allocated < new_size)
+ {
+ char *new_buffer;
+ new_size = (new_size + CD_ALLOCSIZE - 1)
+ & ~(CD_ALLOCSIZE - 1);
+ new_buffer = realloc (input->cd_buffer, new_size);
+ if (!new_buffer)
+ return ENOMEM;
+ input->cd_buffer = new_buffer;
+ input->cd_allocated = new_size;
+ }
+ return 0;
+ }
+
+ mutex_lock (&input->lock);
+ was_empty = !input->size;
+
+ while (datalen)
+ {
+ /* Make sure we are ready for writing (or at least can make a
+ honest attempt at it). */
+ while (input->full)
+ {
+ if (nonblock)
+ {
+ err = EWOULDBLOCK;
+ goto out;
+ }
+ if (hurd_condition_wait (&input->space_available, &input->lock))
+ {
+ err = EINTR;
+ goto out;
+ }
+ was_empty = !input->size;
+ }
+
+ /* Prepare the input buffer for iconv. */
+ if (input->cd_size)
+ {
+ err = ensure_cd_buffer_size (input->cd_size + datalen);
+ if (err)
+ goto out;
+ buffer = input->cd_buffer;
+ buffer_size = input->cd_size;
+ memcpy (buffer + buffer_size, data, datalen);
+ buffer_size += datalen;
+ }
+ else
+ {
+ buffer = data;
+ buffer_size = datalen;
+ }
+ /* Prepare output buffer for iconv. */
+ outbuf = &input->buffer[input->size];
+ outbuf_size = INPUT_QUEUE_SIZE - input->size;
+
+ amount = buffer_size;
+ nconv = iconv (input->cd, &buffer, &buffer_size, &outbuf, &outbuf_size);
+ amount -= buffer_size;
+
+ /* Calculate buffer progress. */
+ enqueued += amount;
+ data = buffer;
+ datalen = buffer_size;
+ input->size = INPUT_QUEUE_SIZE - outbuf_size;
+
+ if (nconv == (size_t) -1)
+ {
+ if (errno == E2BIG)
+ {
+ /* There is not enough space for more data in the outbuf
+ buffer. Mark the buffer as full, awake waiting
+ readers and go to sleep (above). */
+ input->full = 1;
+ if (was_empty)
+ condition_broadcast (&input->data_available);
+ /* Prevent calling condition_broadcast again if nonblock. */
+ was_empty = 0;
+ }
+ else
+ break;
+ }
+ }
+
+ /* XXX What should be done with invalid characters etc? */
+ if (errno == EINVAL && datalen)
+ {
+ /* The conversion stopped because of an incomplete byte sequence
+ at the end of the buffer. */
+ /* If we used the caller's buffer DATA, the remaining bytes
+ might not fit in our internal output buffer. In this case we
+ can reallocate the buffer in INPUT without needing to update
+ CD_BUFFER (as it points into DATA). */
+ err = ensure_cd_buffer_size (datalen);
+ if (err)
+ {
+ mutex_unlock (&input->lock);
+ errno = err;
+ return enqueued ?: -1;
+ }
+ memmove (input->cd_buffer, data, datalen);
+ }
+
+ out:
+ if (enqueued)
+ {
+ if (was_empty)
+ condition_broadcast (&input->data_available);
+ }
+ else
+ errno = err;
+ mutex_unlock (&input->lock);
+ return enqueued ?: -1;
+}
+
+/* Remove DATALEN characters from the input queue and put them in the
+ buffer DATA. The data will be supplied in the local encoding. The
+ function returns the amount of bytes removed (might be smaller than
+ DATALEN) or -1 and the error number in errno. If NONBLOCK is not
+ zero, return with -1 and set errno to EWOULDBLOCK if operation
+ would block for a long time. */
+ssize_t input_dequeue (input_t input, int nonblock, char *data,
+ size_t datalen)
+{
+ size_t amount = datalen;
+
+ mutex_lock (&input->lock);
+ while (!input->size)
+ {
+ if (nonblock)
+ {
+ mutex_unlock (&input->lock);
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+ if (hurd_condition_wait (&input->data_available, &input->lock))
+ {
+ mutex_unlock (&input->lock);
+ errno = EINTR;
+ return -1;
+ }
+ }
+
+ if (amount > input->size)
+ amount = input->size;
+ memcpy (data, input->buffer, amount);
+ memmove (input->buffer, input->buffer + amount, input->size - amount);
+ input->size -= amount;
+ if (amount && input->full)
+ {
+ input->full = 0;
+ condition_broadcast (&input->space_available);
+ }
+ mutex_unlock (&input->lock);
+ return amount;
+}
+
+
+/* Flush the input buffer, discarding all pending data. */
+void input_flush (input_t input)
+{
+ mutex_lock (&input->lock);
+ input->size = 0;
+ if (input->full)
+ {
+ input->full = 0;
+ condition_broadcast (&input->space_available);
+ }
+ mutex_unlock (&input->lock);
+}
diff --git a/console/input.h b/console/input.h
new file mode 100644
index 00000000..47de35e2
--- /dev/null
+++ b/console/input.h
@@ -0,0 +1,58 @@
+/* input.h - Interface to the input component of a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef INPUT_H
+#define INPUT_H
+
+#include <errno.h>
+
+struct input;
+typedef struct input *input_t;
+
+/* Create a new virtual console input queue, with the system encoding
+ being ENCODING. */
+error_t input_create (input_t *r_input, const char *encoding);
+
+/* Destroy the input queue INPUT. */
+void input_destroy (input_t input);
+
+/* Enter DATALEN characters from the buffer DATA into the input queue
+ INPUT. The DATA must be supplied in UTF-8 encoding (XXX UCS-4
+ would be nice, too, but it requires knowledge of endianess). The
+ function returns the amount of bytes written (might be smaller than
+ DATALEN) or -1 and the error number in errno. If NONBLOCK is not
+ zero, return with -1 and set errno to EWOULDBLOCK if operation
+ would block for a long time. */
+ssize_t input_enqueue (input_t input, int nonblock, char *data,
+ size_t datalen);
+
+/* Remove DATALEN characters from the input queue and put them in the
+ buffer DATA. The data will be supplied in the local encoding. The
+ function returns the amount of bytes removed (might be smaller than
+ DATALEN) or -1 and the error number in errno. If NONBLOCK is not
+ zero, return with -1 and set errno to EWOULDBLOCK if operation
+ would block for a long time. */
+ssize_t input_dequeue (input_t input, int nonblock, char *data,
+ size_t datalen);
+
+/* Flush the input buffer, discarding all pending data. */
+void input_flush (input_t input);
+
+#endif /* INPUT_H */
diff --git a/console/motd.UTF8 b/console/motd.UTF8
new file mode 100644
index 00000000..40a104be
--- /dev/null
+++ b/console/motd.UTF8
@@ -0,0 +1,4 @@
+î¼€î¼î¼‚
+
+î¼î¼Žî¼î¼î¼‘ This is the GNU Hurd. Welcome.
+
diff --git a/console/mutations.h b/console/mutations.h
new file mode 100644
index 00000000..a8183fc0
--- /dev/null
+++ b/console/mutations.h
@@ -0,0 +1,27 @@
+/* mutations.h - Automagic type transformation for MiG interfaces.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Only CPP macro definitions should go in this file. */
+
+#define IO_INTRAN protid_t begin_using_protid_port (io_t)
+#define IO_DESTRUCTOR end_using_protid_port (protid_t)
+
+#define TIOCTL_IMPORTS import "priv.h";
+
diff --git a/console/pager.c b/console/pager.c
new file mode 100644
index 00000000..092a8820
--- /dev/null
+++ b/console/pager.c
@@ -0,0 +1,221 @@
+/* pager.c - The pager for the display component of a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <error.h>
+
+#include <sys/mman.h>
+#include <cthreads.h>
+
+#include <hurd.h>
+#include <hurd/pager.h>
+#include <hurd/console.h>
+
+#include "pager.h"
+
+
+struct user_pager_info
+{
+ size_t memobj_npages;
+ vm_address_t memobj_pages[0];
+};
+
+
+/* We need a separate bucket for the pager ports. */
+static struct port_bucket *pager_bucket;
+
+
+/* Implement the pager_clear_user_data callback from the pager library. */
+void
+pager_clear_user_data (struct user_pager_info *upi)
+{
+ int idx;
+
+ for (idx = 0; idx < upi->memobj_npages; idx++)
+ if (upi->memobj_pages[idx])
+ vm_deallocate (mach_task_self (), upi->memobj_pages[idx], vm_page_size);
+ free (upi);
+}
+
+
+error_t
+pager_read_page (struct user_pager_info *upi, vm_offset_t page,
+ vm_address_t *buf, int *writelock)
+{
+ /* XXX clients should get a read only object. */
+ *writelock = 0;
+
+ if (upi->memobj_pages[page / vm_page_size] != (vm_address_t) NULL)
+ {
+ *buf = upi->memobj_pages[page / vm_page_size];
+ upi->memobj_pages[page / vm_page_size] = (vm_address_t) NULL;
+ }
+ else
+ *buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ return 0;
+}
+
+
+error_t
+pager_write_page (struct user_pager_info *upi, vm_offset_t page,
+ vm_address_t buf)
+{
+ assert (upi->memobj_pages[page / vm_page_size] == (vm_address_t) NULL);
+ upi->memobj_pages[page / vm_page_size] = buf;
+ return 0;
+}
+
+
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t address)
+{
+ assert (!"unlocking requested on unlocked page");
+ return 0;
+}
+
+
+/* Tell how big the file is. */
+error_t
+pager_report_extent (struct user_pager_info *upi,
+ vm_address_t *offset,
+ vm_size_t *size)
+{
+ *offset = 0;
+ *size = upi->memobj_npages * vm_page_size;
+ return 0;
+}
+
+
+void
+pager_dropweak (struct user_pager_info *upi)
+{
+}
+
+
+/* A top-level function for the paging thread that just services paging
+ requests. */
+static void
+service_paging_requests (any_t arg)
+{
+ struct port_bucket *pager_bucket = arg;
+ for (;;)
+ ports_manage_port_operations_multithread (pager_bucket,
+ pager_demuxer,
+ 1000 * 60 * 2,
+ 1000 * 60 * 10, 0);
+}
+
+
+/* Initialize the pager for the display component. */
+void
+user_pager_init (void)
+{
+ /* Create the pager bucket, and start to serve paging requests. */
+ pager_bucket = ports_create_bucket ();
+ if (! pager_bucket)
+ error (5, errno, "Cannot create pager bucket");
+
+ /* Make a thread to service paging requests. */
+ cthread_detach (cthread_fork ((cthread_fn_t) service_paging_requests,
+ (any_t) pager_bucket));
+}
+
+
+/* Create a new pager in USER_PAGER with NPAGES pages, and return a
+ mapping to the memory in *USER. */
+error_t
+user_pager_create (struct user_pager *user_pager, unsigned int npages,
+ struct cons_display **user)
+{
+ error_t err;
+ struct user_pager_info *upi;
+
+ upi = calloc (1, sizeof (struct user_pager_info)
+ + sizeof (vm_address_t) * npages);
+ if (!upi)
+ return errno;
+
+ upi->memobj_npages = npages;
+
+ /* XXX Are the values 1 and MEMORY_OBJECT_COPY_DELAY correct? */
+ user_pager->pager = pager_create (upi, pager_bucket,
+ 1, MEMORY_OBJECT_COPY_DELAY);
+ if (!user_pager->pager)
+ {
+ free (upi);
+ return errno;
+ }
+ user_pager->memobj = pager_get_port (user_pager->pager);
+ ports_port_deref (user_pager->pager);
+
+ mach_port_insert_right (mach_task_self (), user_pager->memobj,
+ user_pager->memobj, MACH_MSG_TYPE_MAKE_SEND);
+
+ err = vm_map (mach_task_self (),
+ (vm_address_t *) user,
+ (vm_size_t) npages * vm_page_size,
+ (vm_address_t) 0,
+ 1 /* ! (flags & MAP_FIXED) */,
+ user_pager->memobj, 0 /* (vm_offset_t) offset */,
+ 0 /* ! (flags & MAP_SHARED) */,
+ VM_PROT_READ | VM_PROT_WRITE,
+ VM_PROT_READ | VM_PROT_WRITE,
+ VM_INHERIT_NONE);
+ if (err)
+ {
+ /* UPI will be cleaned up by libpager. */
+ mach_port_deallocate (mach_task_self (), user_pager->memobj);
+ return err;
+ }
+
+ return 0;
+}
+
+
+/* Destroy the pager USER_PAGER and the mapping at USER. */
+void
+user_pager_destroy (struct user_pager *user_pager, struct cons_display *user)
+{
+ /* The pager will be deallocated by libpager. */
+ vm_deallocate (mach_task_self (), (vm_offset_t) user,
+ pager_get_upi (user_pager->pager)->memobj_npages
+ * vm_page_size);
+ mach_port_deallocate (mach_task_self (), user_pager->memobj);
+}
+
+
+/* Allocate a reference for the memory object backing the pager
+ USER_PAGER with protection PROT and return it. */
+mach_port_t
+user_pager_get_filemap (struct user_pager *user_pager, vm_prot_t prot)
+{
+ error_t err;
+
+ /* Add a reference for each call, the caller will deallocate it. */
+ err = mach_port_mod_refs (mach_task_self (), user_pager->memobj,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+
+ return user_pager->memobj;
+}
+
diff --git a/console/pager.h b/console/pager.h
new file mode 100644
index 00000000..974db961
--- /dev/null
+++ b/console/pager.h
@@ -0,0 +1,47 @@
+/* pager.h - Interface to the pager for display component of a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef PAGER_H
+#define PAGER_H
+
+struct user_pager
+{
+ struct pager *pager;
+ memory_object_t memobj;
+};
+
+/* Initialize the pager for the display component. */
+void user_pager_init (void);
+
+/* Create a new pager in USER_PAGER with NPAGES pages, and return a
+ mapping to the memory in *USER. */
+error_t user_pager_create (struct user_pager *user_pager, unsigned int npages,
+ struct cons_display **user);
+
+/* Destroy the pager USER_PAGER and the mapping at USER. */
+void user_pager_destroy (struct user_pager *user_pager,
+ struct cons_display *user);
+
+/* Allocate a reference for the memory object backing the pager
+ USER_PAGER with protection PROT and return it. */
+mach_port_t user_pager_get_filemap (struct user_pager *user_pager,
+ vm_prot_t prot);
+
+#endif /* PAGER_H_ */
diff --git a/libmom/deallocate-memory.c b/console/priv.h
index bf7acfdb..c03bbc46 100644
--- a/libmom/deallocate-memory.c
+++ b/console/priv.h
@@ -1,5 +1,6 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 2001, 2007 Free Software Foundation, Inc.
+
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,18 +19,19 @@
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 <hurd/hurd_types.h>
+
+#include <hurd/netfs.h>
+
+static inline struct protid * __attribute__ ((unused))
+begin_using_protid_port (file_t port)
+{
+ return ports_lookup_port (netfs_port_bucket, port, netfs_protid_class);
+}
-error_t
-mom_deallocate_memory (void *start, size_t len)
+static inline void __attribute__ ((unused))
+end_using_protid_port (struct protid *cred)
{
- error_t err;
-
- assert ((vm_address_t) start % vm_page_size == 0);
- assert (len % vm_page_size == 0);
-
- mutex_lock (&_mom_memory_lock);
- err = vm_deallocate (mach_task_self (), (vm_address_t) start, len);
- mutex_unlock (&_mom_memory_lock);
- return err;
+ if (cred)
+ ports_port_deref (cred);
}
diff --git a/daemons/ChangeLog b/daemons/ChangeLog
deleted file mode 100644
index de2a49c3..00000000
--- a/daemons/ChangeLog
+++ /dev/null
@@ -1,62 +0,0 @@
-Sat Jul 20 01:06:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * getty.c (main): Get the tty name from the right element in ARGV.
-
-Mon Jul 15 17:27:27 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * rc.sh: Create /var/run/uptime *after* clearing /var/run. Always
- create /var/run/mtab to keep e2fsck happy.
-
-Fri Jul 12 16:49:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * rc.sh: Only clean /tmp and /var/run if they are respectively
- directories.
-
-Sun Jul 7 10:39:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * getty.c (print_banner): Use basename instead of rolling our own.
-
-Sat Jul 6 13:58:40 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * getty.c (print_banner): Don't include directory in terminal
- name.
-
-Sat Jul 6 00:10:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * getty.c (print_banner): Use localhost instead of grotty loop.
- Make static.
- (main): Use syslog instead of error to report exec failure.
- * Makefile (getty): Depend on ../libshouldbeinlibc/libshouldbeinlibc.a.
-
-Fri Jul 5 22:02:16 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * getty.c: Include <sys/utsname.h> and <stdlib.h>.
- (print_banner): New function.
- (main): Call print_banner.
-
- * getty.c (main): Return something.
-
-Tue Jul 2 23:36:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * rc.sh: Touch /var/run/uptime file.
-
-Mon Jul 1 17:54:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * getty.c (main): Don't time out hardwired lines.
- Print an error if exec fails.
-
-Thu Jun 27 16:44:52 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * getty.c (main): Repair loop.
-
-Tue Jun 25 18:01:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * rc.sh: Use real fsck instead of kluge.
-
- * Makefile (%: %.sh): Make target writable.
-
-Thu Jun 20 14:38:58 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * rc.sh: Copied from ../config.
- * getty.c: Copied from ../utils.
- * Makefile: New file.
diff --git a/daemons/Makefile b/daemons/Makefile
index b089ac79..d16680ec 100644
--- a/daemons/Makefile
+++ b/daemons/Makefile
@@ -1,6 +1,6 @@
# Makefile for daemons
-#
-# Copyright (C) 1996 Free Software Foundation
+#
+# Copyright (C) 1996, 1999, 2008, 2010 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
@@ -20,20 +20,25 @@
dir := daemons
makemode := utilities
-targets = rc getty
-special-targets = rc
-SRCS = rc.sh getty.c
+targets = rc getty mail.local console-run runttys runsystem
+special-targets = rc runsystem
+SRCS = rc.sh runsystem.sh getty.c lmail.c console-run.c runttys.c
installationdir = $(libexecdir)
+HURDLIBS = fshelp ports shouldbeinlibc
OBJS = $(SRCS:.c=.o)
+getty-LDLIBS = -lutil
-libutil-libsubst = -lutil
+INSTALL-mail.local-ops = -o root -m 4755
include ../Makeconf
-%: %.sh
- cp $< $@ && chmod +w $@
+rc: rc.sh
+getty: getty.o ../libshouldbeinlibc/libshouldbeinlibc.a
+mail.local: lmail.o ../libshouldbeinlibc/libshouldbeinlibc.a
+console-run: console-run.o ../libfshelp/libfshelp.a ../libports/libports.a
-getty: ../libshouldbeinlibc/libshouldbeinlibc.a -lutil
+runttys: runttys.o
+runttys-LDLIBS = -lutil
-$(filter-out $(special-targets), $(targets)): %: %.o
+runsystem: runsystem.sh
diff --git a/daemons/console-run.c b/daemons/console-run.c
new file mode 100644
index 00000000..3ab2629a
--- /dev/null
+++ b/daemons/console-run.c
@@ -0,0 +1,220 @@
+/* Run a program on the console, trying hard to get the console open.
+ Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with 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 <unistd.h>
+#include <fcntl.h>
+#include <error.h>
+#include <paths.h>
+#include <hurd.h>
+#include <hurd/fshelp.h>
+#include <device/device.h>
+
+static mach_port_t
+get_console ()
+{
+ mach_port_t device_master, console;
+ error_t err = get_privileged_ports (0, &device_master);
+
+ if (err)
+ return MACH_PORT_NULL;
+
+ err = device_open (device_master, D_WRITE | D_READ, "console", &console);
+ if (err)
+ return MACH_PORT_NULL;
+
+ return console;
+}
+
+static int open_console (char **namep);
+
+int
+main (int argc, char **argv)
+{
+ mach_port_t consdev = get_console ();
+ char *consname;
+
+ if (consdev == MACH_PORT_NULL)
+ _exit (127);
+
+ stdin = stdout = NULL;
+ stderr = mach_open_devstream (consdev, "w");
+ if (!stderr)
+ _exit (127);
+
+ if (argc < 2)
+ error (1, 0, "Usage: %s PROGRAM [ARG...]", program_invocation_short_name);
+
+ if (open_console (&consname))
+ setenv ("FALLBACK_CONSOLE", consname, 1);
+
+ execv (argv[1], &argv[1]);
+ error (5, errno, "cannot execute %s", argv[1]);
+ /* NOTREACHED */
+ return 127;
+}
+
+/* Open /dev/console. If it isn't there, or it isn't a terminal, then
+ create /tmp/console and put the terminal on it. If we get EROFS,
+ in trying to create /tmp/console then as a last resort, put the
+ console on /tmp itself. If all fail, we exit.
+
+ Return nonzero if the vanilla open of /dev/console didn't work.
+ In any case, after the console has been opened, put it on fds 0, 1, 2. */
+static int
+open_console (char **namep)
+{
+#define TERMINAL_FIRST_TRY "/hurd/term\0/tmp/console\0device\0console"
+#define TERMINAL_SECOND_TRY "/hurd/term\0/tmp\0device\0console"
+ mach_port_t term, proc;
+ static char *termname;
+ struct stat st;
+ error_t err = 0;
+ int fd;
+ int fallback;
+
+ termname = _PATH_CONSOLE;
+ term = file_name_lookup (termname, O_RDWR, 0);
+ if (term != MACH_PORT_NULL)
+ err = io_stat (term, &st);
+ else
+ err = errno;
+ if (err)
+ error (0, err, "%s", termname);
+ else if (st.st_fstype != FSTYPE_TERM)
+ error (0, 0, "%s: Not a terminal", termname);
+
+ fallback = (term == MACH_PORT_NULL || err || st.st_fstype != FSTYPE_TERM);
+ if (fallback)
+ /* Start the terminal server ourselves. */
+ {
+ size_t argz_len; /* Length of args passed to translator. */
+ char *terminal; /* Name of term translator. */
+ mach_port_t control; /* Control port for term translator. */
+ int try;
+
+ error_t open_node (int flags,
+ mach_port_t *underlying,
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
+ {
+ term = file_name_lookup (termname, flags | O_CREAT|O_NOTRANS, 0666);
+ if (term == MACH_PORT_NULL)
+ {
+ error (0, errno, "%s", termname);
+ return errno;
+ }
+
+ *underlying = term;
+ *underlying_type = MACH_MSG_TYPE_COPY_SEND;
+
+ return 0;
+ }
+
+ terminal = TERMINAL_FIRST_TRY;
+ argz_len = sizeof TERMINAL_FIRST_TRY;
+ for (try = 1; try < 3; ++try)
+ {
+ if (try == 2)
+ {
+ terminal = TERMINAL_SECOND_TRY;
+ argz_len = sizeof TERMINAL_SECOND_TRY;
+ }
+
+ termname = terminal + strlen (terminal) + 1; /* first arg is name */
+
+ /* The callback to start_translator opens TERM as a side effect. */
+ err =
+ fshelp_start_translator (open_node, NULL, terminal, terminal,
+ argz_len, 3000, &control);
+ if (err)
+ {
+ error (0, err, "%s", terminal);
+ continue;
+ }
+
+ err = file_set_translator (term, 0, FS_TRANS_SET, 0, 0, 0,
+ control, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), control);
+ if (err)
+ {
+ error (0, err, "%s", termname);
+ continue;
+ }
+ mach_port_deallocate (mach_task_self (), term);
+
+ /* Now repeat the open. */
+ term = file_name_lookup (termname, O_RDWR, 0);
+ if (term == MACH_PORT_NULL)
+ {
+ error (0, errno, "%s", termname);
+ continue;
+ }
+ err = io_stat (term, &st);
+ if (err)
+ {
+ error (0, err, "%s", termname);
+ term = MACH_PORT_NULL;
+ continue;
+ }
+ if (st.st_fstype != FSTYPE_TERM)
+ {
+ error (0, 0, "%s: Not a terminal", termname);
+ term = MACH_PORT_NULL;
+ continue;
+ }
+
+ if (term != MACH_PORT_NULL)
+ {
+ error (0, 0, "Using temporary console %s", termname);
+ break;
+ }
+ }
+
+ if (term == MACH_PORT_NULL)
+ error (2, 0, "Cannot start console terminal");
+ }
+
+ fd = openport (term, O_RDWR);
+ if (fd < 0)
+ error (3, errno, "Cannot open console");
+
+ if (fd != 0)
+ {
+ dup2 (fd, 0);
+ close (fd);
+ }
+ dup2 (0, 1);
+ dup2 (0, 2);
+
+ if (setsid () == -1)
+ error (0, errno, "setsid");
+
+ /* Set the console to our pgrp. */
+ tcsetpgrp (0, getpid ());
+
+ /* Put us in a new login collection. */
+ proc = getproc ();
+ proc_make_login_coll (proc);
+ mach_port_deallocate (mach_task_self (), proc);
+
+ *namep = termname;
+ return fallback;
+}
diff --git a/daemons/getty.c b/daemons/getty.c
index 013c3e3a..5a2896d8 100644
--- a/daemons/getty.c
+++ b/daemons/getty.c
@@ -1,5 +1,7 @@
/* Stubby version of getty for Hurd
- Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Copyright (C) 1996, 1998, 1999, 2007 Free Software Foundation, Inc.
+
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,14 +30,36 @@
#include <error.h>
#include <sys/utsname.h>
#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+#include <sys/ioctl.h>
+#include <termios.h>
/* XXX */
-extern int login_tty (int);
extern char *localhost ();
-#define _PATH_DEV "/dev"
#define _PATH_LOGIN "/bin/login"
+/* Parse the terminal speed. */
+static void
+set_speed (int tty, char *speedstr)
+{
+ error_t err;
+ struct termios ttystat;
+ speed_t speed;
+ char *tail;
+
+ errno = 0;
+ speed = strtoul (speedstr, &tail, 0);
+ if (errno || *tail)
+ return;
+
+ err = tcgetattr (tty, &ttystat);
+ if (!err && !cfsetspeed (&ttystat, speed))
+ tcsetattr (tty, TCSAFLUSH, &ttystat);
+}
+
+
/* Print a suitable welcome banner */
static void
print_banner (int fd, char *ttyname)
@@ -62,7 +86,7 @@ main (int argc, char **argv)
char *arg;
openlog ("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
-
+
/* Nothing to do .... */
if (argc != 3)
{
@@ -72,16 +96,16 @@ main (int argc, char **argv)
}
/* Don't do anything with this for now. */
- linespec = argv[2];
+ linespec = argv[1];
tt = getttynam (argv[2]);
asprintf (&ttyname, "%s/%s", _PATH_DEV, argv[2]);
-
+
chown (ttyname, 0, 0);
chmod (ttyname, 0600);
revoke (ttyname);
sleep (2); /* leave DTR down for a bit */
-
+
do
{
tty = open (ttyname, O_RDWR);
@@ -94,18 +118,21 @@ main (int argc, char **argv)
}
while (tty == -1);
+ set_speed (tty, linespec);
+
print_banner (tty, ttyname);
- login_tty (tty);
-
+ if (login_tty (tty) == -1)
+ syslog (LOG_ERR, "cannot set controlling terminal to %s: %m", ttyname);
+
asprintf (&arg, "TERM=%s", tt ? tt->ty_type : "unknown");
if (tt && strcmp (tt->ty_type, "dialup") == 0)
/* Dialup lines time out (which is login's default). */
- execl (_PATH_LOGIN, "login", "-e", arg, 0);
+ execl (_PATH_LOGIN, "login", "-e", arg, NULL);
else
/* Hardwired lines don't. */
- execl (_PATH_LOGIN, "login", "-e", arg, "-aNOAUTH_TIMEOUT", 0);
+ execl (_PATH_LOGIN, "login", "-e", arg, "-aNOAUTH_TIMEOUT", NULL);
syslog (LOG_ERR, "%s: %m", _PATH_LOGIN);
diff --git a/daemons/lmail.c b/daemons/lmail.c
new file mode 100644
index 00000000..23c7b497
--- /dev/null
+++ b/daemons/lmail.c
@@ -0,0 +1,542 @@
+/* Local mail delivery
+
+ Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <sysexits.h>
+#include <paths.h>
+#include <argp.h>
+#include <hurd.h>
+#include <hurd/fd.h>
+#include <version.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+
+#define OPT_FILE -5
+#define OPT_REMOVE -6
+
+const char *argp_program_version = STANDARD_HURD_VERSION (mail.local);
+
+static const struct argp_option
+options[] =
+{
+ {"from", 'f', "USER", 0, "Record sender as USER"},
+ {0, 'd', 0, OPTION_ALIAS|OPTION_HIDDEN},
+ {0, 'r', 0, OPTION_ALIAS|OPTION_HIDDEN},
+ {"file", OPT_FILE, "FILE", 0, "Deliver FILE instead of standard input"},
+ {"remove", OPT_REMOVE, 0, 0, "Remove FILE after successful delivery"},
+ {"mail-dir",'m', "DIR", 0, "Look for mailboxes in DIR"},
+ {"use-lock-file",'l', 0, OPTION_HIDDEN,
+ "Use a lock file instead of flock for mailboxes"},
+ {0}
+};
+static const char args_doc[] = "USER...";
+static const char doc[] = "Deliver mail to the local mailboxes of USER...";
+
+#define HDR_PFX "From " /* Header, at the beginning of a line,
+ starting each msg in a mailbox. */
+#define ESC_PFX ">" /* Used to escape occurrences of HDR_PFX in
+ the msg body. */
+
+#define BMAX (64*1024) /* Chunk size for I/O. */
+
+struct params
+{
+ char *from; /* Who the mail is from. */
+ char *mail_dir; /* Mailbox directory. */
+};
+
+/* Convert the system error code ERR to an appropriate exit value. This
+ function currently only returns three sorts: success, temporary failure,
+ or error, with exit codes 0, EX_TEMPFAIL, or EX_UNAVAILABLE. The table of
+ temporary failures is from the bsd original of this program. */
+static int
+err_to_ex (error_t err)
+{
+ switch (err)
+ {
+ case 0:
+ return 0; /* Success */
+ /* Temporary failures: */
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+ case EWOULDBLOCK: /* Operation would block. */
+#endif
+ case EAGAIN: /* Resource temporarily unavailable */
+ case EDQUOT: /* Disc quota exceeded */
+ case EBUSY: /* Device busy */
+ case EPROCLIM: /* Too many processes */
+ case EUSERS: /* Too many users */
+ case ECONNABORTED: /* Software caused connection abort */
+ case ECONNREFUSED: /* Connection refused */
+ case ECONNRESET: /* Connection reset by peer */
+ case EDEADLK: /* Resource deadlock avoided */
+ case EFBIG: /* File too large */
+ case EHOSTDOWN: /* Host is down */
+ case EHOSTUNREACH: /* No route to host */
+ case EMFILE: /* Too many open files */
+ case ENETDOWN: /* Network is down */
+ case ENETRESET: /* Network dropped connection on reset */
+ case ENETUNREACH: /* Network is unreachable */
+ case ENFILE: /* Too many open files in system */
+ case ENOBUFS: /* No buffer space available */
+ case ENOMEM: /* Cannot allocate memory */
+ case ENOSPC: /* No space left on device */
+ case EROFS: /* Read-only file system */
+ case ESTALE: /* Stale NFS file handle */
+ case ETIMEDOUT: /* Connection timed out */
+ return EX_TEMPFAIL;
+ default:
+ return EX_UNAVAILABLE;
+ }
+}
+
+/* Print and syslog the given error message, with the system error string for
+ ERRNO appended. Return an appropriate exit code for ERRNO. */
+#define SYSERR(fmt, args...) \
+ ({ syslog (LOG_ERR, fmt ": %m" , ##args); err_to_ex (errno); })
+
+/* Print and syslog the given error message. Return the exit code
+ EX_UNAVAILABLE. */
+#define ERR(fmt, args...) \
+ ({ syslog (LOG_ERR, fmt , ##args); EX_UNAVAILABLE; })
+
+/* Print and syslog the given error message, with the system error string for
+ CODE appended. Return an appropriate exit code for CODE. */
+#define SYSERRX(code, fmt, args...) \
+ ({ error_t _code = (code); \
+ syslog (LOG_ERR, fmt ": %s" , ##args , strerror (_code)); \
+ err_to_ex (_code); })
+
+/* Block I/O functions. These are structured to allow the use of a read
+ method that avoids copying the data locally. */
+
+/* Free block allocated by bread. */
+static void
+bfree (char *blk, size_t blk_len)
+{
+ if (blk_len > 0)
+ munmap (blk, blk_len);
+}
+
+/* Read up to MAX chars from IN into BLK & BLK_LEN, which may be reused or
+ freed. */
+static int
+bread (int in, char *in_name, size_t max, char **blk, size_t *blk_len)
+{
+ char *orig_blk = *blk;
+ size_t orig_blk_len = *blk_len;
+ error_t err = HURD_DPORT_USE (in, io_read (port, blk, blk_len, -1, max));
+
+ if (err)
+ return SYSERRX (err, "%s", in_name);
+
+ if (*blk != orig_blk)
+ bfree (orig_blk, orig_blk_len);
+
+ return 0;
+}
+
+/* Write BLK & BLK_LEN to OUT. An exit status is returned. */
+static int
+bwrite (int out, char *out_name, const char *blk, size_t blk_len)
+{
+ while (blk_len > 0)
+ {
+ ssize_t wr = write (out, blk, blk_len);
+ if (wr < 0)
+ return SYSERR ("%s", out_name);
+ blk += wr;
+ blk_len -= wr;
+ }
+ return 0;
+}
+
+/* Copy from file descriptor IN to OUT. An exit status is returned. */
+static int
+copy (int in, char *in_name, int out, char *out_name)
+{
+ int ex = 0;
+ char *blk = 0;
+ size_t blk_len = 0;
+
+ do
+ {
+ ex = bread (in, in_name, BMAX, &blk, &blk_len);
+ if (! ex)
+ ex = bwrite (out, out_name, blk, blk_len);
+ }
+ while (blk_len > 0 && !ex);
+
+ bfree (blk, blk_len);
+
+ return ex;
+}
+
+static int
+write_header (int out, char *out_name, struct params *params)
+{
+ char *hdr;
+ size_t hdr_len;
+ struct timeval tv;
+ time_t time;
+ int ex = 0;
+
+ if (gettimeofday (&tv, 0) < 0)
+ return SYSERR ("gettimeofday");
+
+ /* Note that the string returned by ctime includes a terminating newline. */
+ time = tv.tv_sec;
+ hdr_len = asprintf (&hdr, "From %s %s", params->from, ctime (&time));
+ if (! hdr)
+ return SYSERRX (ENOMEM, "%s", out_name);
+
+ ex = bwrite (out, out_name, hdr, hdr_len);
+
+ free (hdr);
+
+ return ex;
+}
+
+/* Copy from file descriptor IN to OUT, making any changes needed to make the
+ contents a valid mailbox entry. These include:
+ (1) Prepending a `From ...' line, and appending a blank line.
+ (2) Replacing any occurrences of `From ' at the beginning of lines with
+ `>From '.
+ An exit status is returned. */
+static int
+process (int in, char *in_name, int out, char *out_name, struct params *params)
+{
+ /* The block currently being processed. */
+ char *blk = 0;
+ size_t blk_len = 0;
+ /* MATCH is the string we're looking for to escape, NL_MATCH is the same
+ string prefixed by a newline to ease searching (MATCH only matches at
+ the beginning of lines). */
+ const char *const nl_match = "\n" HDR_PFX, *const match = nl_match + 1;
+ /* The portion of MATCH that matched the end of the previous block. 0
+ means that there was at least a newline, so initializing MATCHED to 0
+ simulates a newline at the start of IN. */
+ ssize_t matched = 0;
+ int ex = write_header (out, out_name, params);
+
+#define match_len (sizeof HDR_PFX - 1)
+
+ if (ex)
+ return ex;
+
+#define BWRITE(p, p_len) \
+ ({ size_t _len = (p_len); \
+ if (_len > 0 && (ex = bwrite (out, out_name, p, _len))) \
+ break; })
+
+ do
+ {
+ char *start, *end;
+
+ ex = bread (in, in_name, BMAX, &blk, &blk_len);
+
+ if (matched >= 0)
+ /* The last block ended in a partial match, so see if we can complete
+ it in this block. */
+ {
+ if (blk_len >= match_len - matched
+ && memcmp (blk, match + matched, match_len - matched) == 0)
+ /* It matched; output the escape prefix before the match. */
+ BWRITE (ESC_PFX, sizeof ESC_PFX - 1);
+ /* Now we have to output the part of the preceding block that we
+ didn't do before because it was a partial match. */
+ BWRITE (match, matched);
+ /* Ok, we're all caught up. The portion of the match that's in
+ this block will be output as normal text. */
+ matched = -1;
+ }
+
+ /* Scan through the block looking for matches. */
+ for (start = end = blk; start < blk + blk_len; start = end)
+ {
+ /* Look for our match, prefixed by a newline. */
+ end = memmem (start, blk + blk_len - start, nl_match, match_len + 1);
+ if (end)
+ /* We found a match, output the escape prefix before it. */
+ {
+ end++; /* The newline should precede the escape. */
+ BWRITE (start, end - start); /* part of block before match. */
+ BWRITE (ESC_PFX, sizeof ESC_PFX - 1); /* escape prefix. */
+ }
+ else
+ {
+ end = blk + blk_len;
+ break;
+ }
+ }
+
+ /* Now see if there are any partial matches at the end. */
+ for (matched =
+ end - start < match_len + 1 ? end - start - 1 : match_len;
+ matched >= 0;
+ matched--)
+ if (memcmp (end - matched - 1, nl_match, matched + 1) == 0)
+ /* There's a partial match MATCHED characters long at the end of
+ this block, so delay outputting it until the next block can be
+ examined; we do output the preceding newline here, though. */
+ {
+ end -= matched;
+ break;
+ }
+
+ BWRITE (start, end - start);
+ }
+ while (blk_len > 0);
+
+ if (! ex)
+ ex = bwrite (out, out_name, "\n", 1); /* Append a blank line. */
+
+ bfree (blk, blk_len);
+
+ return ex;
+}
+
+/* Deliver flags. */
+#define D_PROCESS 0x1 /* Deliver */
+#define D_REWIND 0x2 /* Rewind MSG before using it. */
+
+/* Deliver the text from the file descriptor MSG to the mailbox of the user
+ RCPT in MAIL_DIR. FLAGS is from the set D_* above. An exit appropriate
+ exit code is returned. */
+static int
+deliver (int msg, char *msg_name, char *rcpt, int flags, struct params *params)
+{
+ char *mbox; /* Name of mailbox */
+ int fd; /* Opened mailbox */
+ struct stat stat;
+ int ex = 0; /* Exit status */
+ struct passwd *pw = getpwnam (rcpt); /* Details of recipient */
+
+ if (! pw)
+ return ERR ("%s: Unknown user", rcpt);
+
+ asprintf (&mbox, "%s/%s", params->mail_dir, rcpt);
+ if (! mbox)
+ return SYSERRX (ENOMEM, "%s", rcpt);
+
+ do
+ {
+ /* First try to open an existing mailbox. */
+ fd = open (mbox, O_WRONLY|O_APPEND|O_NOLINK|O_EXLOCK);
+ if (fd < 0 && errno == ENOENT)
+ /* There is none; try to create it. */
+ {
+ fd = open (mbox, O_WRONLY|O_APPEND|O_CREAT|O_EXCL|O_NOLINK|O_EXLOCK,
+ S_IRUSR|S_IWUSR);
+ if (fd >= 0)
+ /* Made a new mailbox! Set the owner and group appropiately. */
+ {
+ if (fchown (fd, pw->pw_uid, pw->pw_gid) < 0)
+ {
+ close (fd);
+ fd = -1; /* Propagate error. */
+ }
+ }
+ }
+ }
+ /* EEXIST can only be returned someone else created the mailbox between the
+ two opens above, so if we try again, the first open should work. */
+ while (fd < 0 && errno == EEXIST);
+
+ if (fd < 0 || fstat (fd, &stat) < 0)
+ ex = SYSERR ("%s", mbox);
+ else if (S_ISLNK (stat.st_mode) || stat.st_nlink != 1)
+ ex = ERR ("%s: Is linked", mbox);
+ else
+ {
+ if (flags & D_REWIND)
+ {
+ if (lseek (msg, 0L, SEEK_SET) < 0)
+ ex = SYSERR ("%s", msg_name);
+ }
+ if (! ex)
+ {
+ if (flags & D_PROCESS)
+ ex = process (msg, msg_name, fd, mbox, params);
+ else
+ ex = copy (msg, msg_name, fd, mbox);
+ }
+ }
+
+ if (fd >= 0)
+ {
+ if (fsync (fd) < 0 && !ex)
+ ex = SYSERR ("%s", mbox);
+ if (close (fd) < 0 && !ex)
+ ex = SYSERR ("%s", mbox);
+ }
+ free (mbox);
+
+ return ex;
+}
+
+/* Process from the file descriptor IN into a temporary file, which return a
+ descriptor to in CACHED; once *CACHED is closed, it will go away
+ permanently. The file pointer of *CACHED is at an undefined location. An
+ exit status is returned. */
+static int
+cache (int in, char *in_name, struct params *params, int *cached)
+{
+ int ex;
+ error_t err;
+ file_t file; /* Hurd port for temp file */
+ int fd; /* File descriptor for it */
+ file_t tmp_dir = file_name_lookup (_PATH_TMP, O_RDONLY, 0);
+
+ if (tmp_dir == MACH_PORT_NULL)
+ return SYSERR ("%s", _PATH_TMP);
+
+ /* Create FILE without actually putting it into TMP_DIR. */
+ err = dir_mkfile (tmp_dir, O_RDWR, 0600, &file);
+ if (err)
+ return SYSERRX (err, "%s", _PATH_TMP);
+
+ fd = _hurd_intern_fd (file, O_RDWR, 1);
+ if (fd < 0)
+ return SYSERR ("%s", _PATH_TMP);
+
+ ex = process (in, in_name, fd, _PATH_TMP, params);
+ if (! ex)
+ *cached = fd;
+ else
+ close (fd);
+
+ return ex;
+}
+
+int
+main (int argc, char **argv)
+{
+ int rcpt = 0; /* Index in ARGV of next recipient. */
+ char *file = 0; /* File containing message. */
+ int remove = 0; /* Remove file after successful delivery. */
+ int in = 0; /* Raw input file descriptor. */
+ int ex = 0; /* Exit status. */
+ struct params params = { from: 0, mail_dir: _PATH_MAILDIR };
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'd':
+ /* do nothing; compatibility */
+ break;
+ case 'f':
+ case 'r':
+ params.from = arg; break;
+ case OPT_FILE:
+ file = arg; break;
+ case OPT_REMOVE:
+ remove = 1; break;
+ case 'm':
+ params.mail_dir = arg; break;
+ case 'l':
+ argp_failure (state, EX_USAGE, EINVAL, "-l not supported");
+ case ARGP_KEY_NO_ARGS:
+ argp_error (state, "No recipients");
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ const struct argp argp = { options, parse_opt, args_doc, doc };
+
+ /* Parse arguments. */
+ argp_parse (&argp, argc, argv, 0, &rcpt, 0);
+
+ /* Use syslog to log errors. */
+ openlog ("mail.local", LOG_PERROR, LOG_MAIL);
+
+ if (! params.from)
+ /* No from address specified, use the current user. */
+ {
+ struct passwd *pw;
+ int uid = getuid ();
+
+ if (uid == -1)
+ exit (ERR ("No user id"));
+
+ pw = getpwuid (uid);
+ if (! pw)
+ exit (ERR ("%d: Unknown uid", uid));
+
+ params.from = strdup (pw->pw_name);
+ }
+
+ if (file)
+ /* Use FILE as the message contents. */
+ {
+ in = open (file, O_RDONLY);
+ if (in < 0)
+ exit (SYSERR ("%s", file));
+ }
+ else
+ /* Use standard input. */
+ in = 0;
+
+ if (rcpt == argc - 1)
+ /* Only a single recipient. */
+ ex = deliver (in, file ?: "-", argv[rcpt], D_PROCESS, &params);
+ else
+ /* Multiple recipients. */
+ {
+ int cached; /* Temporary processed input file. */
+
+ ex = cache (in, file ?: "-", &params, &cached);
+ if (! ex)
+ while (rcpt < argc)
+ {
+ /* Deliver to one recipient. */
+ int rex = deliver (cached, "message cache", argv[rcpt++],
+ D_REWIND, &params);
+
+ /* Merge the exit code for that recipient. Temporary failures
+ take precedence over hard failures and success, as
+ subsequently delivering duplicates (of the successful
+ messages) is preferable to not delivering the temporary
+ failures. */
+ if (ex != EX_TEMPFAIL)
+ {
+ if (rex == EX_TEMPFAIL)
+ ex = EX_TEMPFAIL;
+ else if (! ex)
+ ex = rex;
+ }
+ }
+ }
+
+ if (file && remove && !ex)
+ unlink (file);
+
+ exit (ex);
+}
diff --git a/daemons/rc.sh b/daemons/rc.sh
index b113dac1..57780945 100644
--- a/daemons/rc.sh
+++ b/daemons/rc.sh
@@ -1,8 +1,17 @@
-#!/bin/sh
+#!/bin/bash
+
PATH=/bin:/sbin
+# Start the default pager. It will bail if there is already one running.
+/hurd/mach-defpager
+
+# Set up swap space. This will complain if no default pager is functioning.
+swapon -a
+
+# Check filesystems.
if [ -r /fastboot ]
then
+ # ... or don't.
rm -f /fastboot
echo Fast boot ... skipping disk checks
elif [ $1x = autobootx ]
@@ -19,7 +28,7 @@ then
# Filesystem modified (but ok now)
1 | 2)
;;
- # Fsck couldn't fix it.
+ # Fsck couldn't fix it.
4 | 8)
echo "Automatic boot failed... help!"
exit 1
@@ -35,8 +44,8 @@ then
exit 1
;;
# Oh dear.
- *)
- echo "Unknown error during fsck"
+ *)
+ echo "Unknown error during fsck (exit status $?)"
exit 1
;;
esac
@@ -46,16 +55,40 @@ echo -n cleaning up left over files...
rm -f /etc/nologin
rm -f /var/lock/LCK.*
if test -d /tmp; then
- (cd /tmp; find . ! -name . ! -name lost+found ! -name quotas -exec rm -r {} \; )
+
+ # Forcibly remove all translators in the directory.
+ # It is then safe to attempt to remove files and descend directories.
+ # All parameters must begin with "./".
+ function remove_translators() {
+ local f
+ for f; do
+ settrans -pagfS "$f"
+ if [ -L "$f" ] || [ ! -d "$f" ]; then
+ rm "$f"
+ else
+ remove_translators "$f"/* "$f"/.[!.] "$f"/.??*
+ rmdir "$f"
+ fi
+ done
+ }
+
+ (cd /tmp
+ shopt -s nullglob
+ for f in * .[!.] .??*; do
+ case "$f" in
+ 'lost+found'|'quotas') ;;
+ *) remove_translators "./$f"
+ esac
+ done)
+
+ unset -f remove_translators # because it relies on nullglob
+
fi
if test -d /var/run; then
(cd /var/run && { rm -rf -- *; cp /dev/null utmp; chmod 644 utmp; })
fi
echo done
-# This file records when the system was booted.
-date > /var/run/uptime
-
# This file must exist for e2fsck to work. XXX
touch /var/run/mtab
@@ -72,9 +105,14 @@ touch /var/run/mtab
chmod 664 /etc/motd
echo -n starting daemons:
-/sbin/syslogd; echo -n ' syslogd'
-/sbin/inetd; echo -n ' inet'
-echo .
+/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 .
date
diff --git a/daemons/runsystem.sh b/daemons/runsystem.sh
new file mode 100644
index 00000000..c3cb2d62
--- /dev/null
+++ b/daemons/runsystem.sh
@@ -0,0 +1,142 @@
+#!/bin/bash
+#
+# This program is run by /hurd/init at boot time after the essential
+# servers are up, and is responsible for running the "userland" parts of a
+# normal system. This includes running the single-user shell as well as a
+# multi-user system. This program is expected never to exit.
+#
+
+
+###
+### Where to find programs, etc.
+###
+
+PATH=/bin:/sbin
+export PATH
+
+umask 022
+
+# If we lose badly, try to exec each of these in turn.
+fallback_shells='/bin/sh /bin/bash /bin/csh /bin/ash /bin/shd'
+
+# Shell used for normal single-user startup.
+SHELL=/bin/sh
+
+# Programs that do multi-user startup.
+RUNCOM=/libexec/rc
+RUNTTYS=/libexec/runttys
+# Signals that we should pass down to runttys.
+runttys_sigs='TERM INT HUP TSTP'
+
+###
+
+
+# If we get a SIGLOST, attempt to reopen the console in case
+# our console ports were revoked. This lets us print messages.
+function reopen_console ()
+{
+ exec 1>/dev/console 2>&1 || exit 3
+}
+trap 'reopen_console' SIGLOST
+
+
+# Call this when we are losing badly enough that we want to punt normal
+# startup entirely. We exec a single-user shell, so we will not come back
+# here. The only way to get to multi-user from that shell will be
+# explicitly exec this script or something like that.
+function singleuser ()
+{
+ test $# -eq 0 || echo "$0: $*"
+ for try in ${fallback_shells}; do
+ SHELL=${try}
+ exec ${SHELL}
+ done
+ exit 127
+}
+
+
+# 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.
+
+if [ "${FALLBACK_CONSOLE+set}" = set ]; then
+ singleuser "Running on fallback console ${FALLBACK_CONSOLE}"
+fi
+
+
+###
+### Normal startup procedures
+###
+
+# Parse the multiboot command line. We only pay attention to -s and -f.
+# The first argument is the kernel file name; skip that.
+shift
+flags=
+while [ $# -gt 0 ]; do
+ arg="$1"
+ shift
+ case "$arg" in
+ --*) ;;
+ *=*) ;;
+ -*)
+ flags="${flags}${arg#-}"
+ ;;
+ 'single'|'emergency') # Linux compat
+ flags="${flags}s"
+ ;;
+ 'fastboot')
+ flags="${flags}f"
+ ;;
+ esac
+done
+
+# Check boot flags.
+case "$flags" in
+*s*)
+ rc=false # force single-user
+ ;;
+*f*)
+ rc="${RUNCOM}" # fastboot
+ ;;
+*)
+ rc="${RUNCOM} autoboot" # multi-user default
+ ;;
+esac
+
+# Large infinite loop. If this script ever exits, init considers that
+# a serious bogosity and punts to a fallback single-user shell.
+# We handle here the normal transitions between single-user and multi-user.
+while : ; do
+
+ # Run the rc script. As long as it exits nonzero, punt to single-user.
+ # After the single-user shell exits, we will start over attempting to
+ # run rc; but later invocations strip the `autoboot' argument.
+ until $rc; do
+ rc=${RUNCOM}
+
+ # Run single-user shell and repeat as long as it dies with a signal.
+ until ${SHELL} || test $? -lt 128; do
+ :
+ done
+ done
+
+ # Now we are officially ready for normal multi-user operation.
+
+ # Trap certain signals and send them on to runttys. For this to work, we
+ # must run it asynchronously and wait for it with the `wait' built-in.
+ runttys_pid=0
+ for sig in $runttys_sigs; do
+ trap "kill -$sig \${runttys_pid}" $sig
+ done
+
+ # This program reads /etc/ttys and starts the programs it says to.
+ ${RUNTTYS} &
+ runttys_pid=$!
+
+ # Wait for runttys to die, meanwhile handling trapped signals.
+ wait
+
+ # Go back to the top of the infinite loop, as if booting single-user.
+ rc=false
+
+done
diff --git a/daemons/runttys.c b/daemons/runttys.c
new file mode 100644
index 00000000..7efb7b7a
--- /dev/null
+++ b/daemons/runttys.c
@@ -0,0 +1,502 @@
+/* /etc/ttys support for Hurd
+ Copyright (C) 1993,94,95,96,97,98,99,2001 Free Software Foundation, Inc.
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argz.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <ttyent.h>
+#include <unistd.h>
+#include <utmp.h>
+
+
+/* How long to wait after starting window specs before starting getty */
+#define WINDOW_DELAY 3 /* seconds */
+
+#define _PATH_LOGIN "/bin/login"
+
+
+/* All the ttys in /etc/ttys. */
+struct terminal
+{
+ char *name; /* Name of the terminal device file. */
+
+ /* argv lists for getty and window spec.
+ The first element is always the malloc'd argz the rest point into. */
+ char **getty_argv, **window_argv;
+
+ int on; /* Nonzero iff the line is "on". */
+ pid_t pid; /* Child running on this line. */
+ int read; /* Used during reread_ttys. */
+};
+
+static struct terminal *ttys;
+/* Number of live elements in ttys */
+static int nttys;
+/* Total number of elements in ttys */
+static int ttyslen;
+
+
+static void
+free_argvs (struct terminal *t)
+{
+ if (t->getty_argv)
+ {
+ free (t->getty_argv[0]);
+ free (t->getty_argv);
+ }
+ if (t->window_argv)
+ {
+ free (t->window_argv[0]);
+ free (t->window_argv);
+ }
+}
+
+/* Set up the getty and window fields of terminal spec T corresponding
+ to line TT. */
+static void
+setup_terminal (struct terminal *t, struct ttyent *tt)
+{
+ free_argvs (t);
+
+ if ((tt->ty_status & TTY_ON) && tt->ty_getty)
+ {
+ char **make_args (const char *line)
+ {
+ int argc;
+ char *argz, **argv;
+ size_t len;
+ argz_create_sep (line, ' ', &argz, &len);
+ argc = argz_count (argz, len);
+ argv = malloc ((argc + 1) * sizeof (char *));
+ if (argv == 0)
+ error (0, ENOMEM,
+ "cannot allocate argument vector for %s", t->name);
+ else
+ argz_extract (argz, len, argv);
+ return argv;
+ }
+
+ char *line;
+ asprintf (&line, "%s %s", tt->ty_getty, tt->ty_name);
+ if (line == 0)
+ {
+ error (0, ENOMEM,
+ "cannot allocate arguments for %s", t->name);
+ t->getty_argv = 0;
+ }
+ else
+ {
+ t->getty_argv = make_args (line);
+ free (line);
+ }
+ t->window_argv = tt->ty_window ? make_args (tt->ty_window) : 0;
+ }
+ else
+ t->getty_argv = t->window_argv = 0;
+}
+
+
+/* Add a new terminal spec for TT and return it. */
+static struct terminal *
+add_terminal (struct ttyent *tt)
+{
+ struct terminal *t;
+
+ if (nttys >= ttyslen)
+ {
+ struct terminal *newttys = realloc (ttys,
+ (ttyslen * 2) * sizeof ttys[0]);
+ if (newttys == 0)
+ {
+ error (0, ENOMEM, "cannot expand terminals table past %d", ttyslen);
+ return 0;
+ }
+ else
+ {
+ ttys = newttys;
+ memset (&ttys[nttys], 0, ttyslen);
+ ttyslen *= 2;
+ }
+ }
+
+ t = &ttys[nttys];
+ t->name = strdup (tt->ty_name);
+ if (t->name == 0)
+ {
+ error (0, ENOMEM, "cannot allocate entry for %s", tt->ty_name);
+ return 0;
+ }
+
+ nttys++;
+ setup_terminal (t, tt);
+ if (t->getty_argv)
+ t->on = 1;
+
+ return t;
+}
+
+/* Read /etc/ttys and initialize ttys array. Return non-zero if we fail. */
+int
+init_ttys (void)
+{
+ struct ttyent *tt;
+
+ ttyslen = 10;
+ nttys = 0;
+
+ ttys = calloc (ttyslen, sizeof ttys[0]);
+ if (ttys == 0)
+ error (2, ENOMEM, "cannot allocate table");
+
+ if (!setttyent ())
+ {
+ error (0, errno, "%s", _PATH_TTYS);
+ return 1;
+ }
+ while ((tt = getttyent ()))
+ {
+ if (!tt->ty_name)
+ continue;
+
+ add_terminal (tt);
+ }
+
+ endttyent ();
+ return 0;
+}
+
+/* Free everything in the terminal array */
+void
+free_ttys (void)
+{
+ int i;
+
+ for (i = 0; i < nttys; i++)
+ {
+ free_argvs (&ttys[i]);
+ free (ttys[i].name);
+ }
+ free (ttys);
+}
+
+/* Start a child process. */
+static pid_t
+run (char **argv, int do_setsid)
+{
+ pid_t pid;
+
+ pid = fork ();
+ if (pid < 0)
+ {
+ error (0, errno, "fork");
+ return 0;
+ }
+
+ if (pid > 0)
+ return pid;
+ else
+ {
+ if (do_setsid && setsid () == -1)
+ error (0, errno, "setsid");
+
+ errno = 0;
+ execv (argv[0], argv);
+ error (127, errno, "%s", argv[0]);
+ }
+
+ /* NOTREACHED */
+ return -1;
+}
+
+
+/* Start line T. Return non-zero if we didn't actually start anything. */
+static int
+startup_terminal (struct terminal *t)
+{
+ pid_t pid;
+ assert (t->on);
+ assert (t->getty_argv);
+
+ if (t->window_argv)
+ {
+ pid = run (t->window_argv, 1);
+ if (!pid)
+ goto error;
+
+ sleep (WINDOW_DELAY);
+ }
+
+ pid = run (t->getty_argv, 0);
+ if (pid == 0)
+ {
+ error:
+ t->pid = 0;
+ t->on = 0;
+ return 1;
+ }
+ else
+ {
+ t->pid = pid;
+ return 0;
+ }
+}
+
+/* For each line in /etc/ttys, start up the specified program. Return
+ non-zero if we fail. */
+int
+startup_ttys (void)
+{
+ int i;
+ int didone, fail;
+
+ didone = 0;
+
+ for (i = 0; i < nttys; i++)
+ if (ttys[i].on)
+ {
+ fail = startup_terminal (&ttys[i]);
+ if (!fail)
+ didone = 1;
+ }
+ return !didone;
+}
+
+/* Find the terminal spec corresponding to line LINE. */
+static struct terminal *
+find_line (char *line)
+{
+ int i;
+
+ for (i = 0; i < nttys; i++)
+ if (!strcmp (ttys[i].name, line))
+ return &ttys[i];
+ return 0;
+}
+
+/* PID has just exited; restart the terminal it's on if necessary. */
+void
+restart_terminal (pid_t pid)
+{
+ int i;
+
+ for (i = 0; i < nttys; i++)
+ if (pid == ttys[i].pid)
+ {
+ if (logout (ttys[i].name))
+ logwtmp (ttys[i].name, "", "");
+ ttys[i].pid = 0;
+ if (ttys[i].on)
+ startup_terminal (&ttys[i]);
+ }
+}
+
+/* Shutdown the things running on terminal spec T. */
+static void
+shutdown_terminal (struct terminal *t)
+{
+ kill (t->pid, SIGHUP);
+ revoke (t->name);
+}
+
+/* Re-read /etc/ttys. If a line has turned off, kill what's there.
+ If a line has turned on, start it. */
+void
+reread_ttys (void)
+{
+ struct ttyent *tt;
+ struct terminal *t;
+ int on;
+ int i;
+
+ if (!setttyent ())
+ {
+ error (0, errno, "%s", _PATH_TTYS);
+ return;
+ }
+
+ while ((tt = getttyent ()))
+ {
+ if (!tt->ty_name)
+ continue;
+
+ t = find_line (tt->ty_name);
+ on = tt->ty_getty && (tt->ty_status & TTY_ON);
+
+ if (t)
+ {
+ if (t->on && !on)
+ {
+ t->on = 0;
+ shutdown_terminal (t);
+ }
+ else if (!t->on && on)
+ {
+ t->on = 1;
+ setup_terminal (t, tt);
+ startup_terminal (t);
+ }
+ }
+ else
+ {
+ t = add_terminal (tt);
+ if (t == 0)
+ continue;
+ if (on)
+ startup_terminal (t);
+ }
+
+ t->read = 1;
+ }
+ endttyent ();
+
+ /* Scan tty entries; any that were not found and were on, turn off. */
+ for (i = 0; i < nttys; i++)
+ {
+ if (!ttys[i].read && ttys[i].on)
+ {
+ ttys[i].on = 0;
+ shutdown_terminal (&ttys[i]);
+ }
+ ttys[i].read = 0; /* Clear flag for next time. */
+ }
+}
+
+
+
+/** Main program and signal handlers. **/
+
+static sig_atomic_t pending_hup;
+static void
+sighup (int signo)
+{
+ pending_hup = 1;
+}
+
+static sig_atomic_t pending_term;
+static void
+sigterm (int signo)
+{
+ pending_term = 1;
+}
+
+#ifdef SIGLOST
+static void
+reopen_console (int signo)
+{
+ int fd;
+
+ close (0);
+ close (1);
+ close (2);
+
+ fd = open (_PATH_CONSOLE, O_RDWR);
+ if (fd < 0)
+ _exit (2);
+ if (fd != 0)
+ {
+ dup2 (fd, 0);
+ close (fd);
+ }
+ dup2 (0, 1);
+ dup2 (0, 2);
+}
+#endif
+
+int
+main ()
+{
+ int fail;
+ struct sigaction sa;
+
+ fail = init_ttys ();
+ if (fail)
+ return fail;
+
+ if (setsid () == -1)
+ error (0, errno, "setsid");
+
+ sa.sa_handler = sighup;
+ sa.sa_flags = 0; /* No SA_RESTART! */
+ sigemptyset(&sa.sa_mask);
+ if (sigaction (SIGHUP, &sa, NULL))
+ error (2, errno, "cannot set SIGHUP handler");
+ sa.sa_handler = sigterm;
+ if (sigaction (SIGTERM, &sa, NULL))
+ error (2, errno, "cannot set SIGTERM handler");
+
+#ifdef SIGLOST
+ /* We may generate SIGLOST signal from trying to talk to the console
+ after our port has been revoked or the term server has died. In that
+ case, reopen the console and restart. (Unfortunately this won't
+ restart the offending RPC on the new console port.) */
+ if (signal (SIGLOST, reopen_console) == SIG_ERR)
+ error (2, errno, "cannot set SIGLOST handler");
+#endif
+
+ /* Start up tty lines. */
+ startup_ttys ();
+
+ /* We will spend the rest of our life waiting for children to die. */
+ while (1)
+ {
+ error_t waiterr;
+ pid_t pid = waitpid (WAIT_ANY, NULL, WUNTRACED);
+ waiterr = errno;
+
+ /* Elicit a SIGLOST now if the console (on our stderr, i.e. fd 2) has
+ died. That way, the next error message emitted will actually make
+ it out to the console if it can be made it work at all. */
+ write (2, "", 0);
+
+ /* If a SIGTERM or SIGHUP arrived recently, it set a flag
+ and broke us out of being blocked in waitpid. */
+
+ if (pending_term)
+ {
+ pending_term = 0;
+ error (3, 0, "Got SIGTERM");
+ }
+ if (pending_hup)
+ {
+ pending_hup = 0;
+ reread_ttys ();
+ }
+
+ if (pid < 0)
+ {
+ if (waiterr == EINTR) /* A signal woke us. */
+ continue;
+ error (1, waiterr, "waitpid");
+ }
+
+ assert (pid > 0);
+
+ /* We have reaped a dead child. Restart that tty line. */
+ restart_terminal (pid);
+ }
+}
diff --git a/defpager/ChangeLog b/defpager/ChangeLog
deleted file mode 100644
index 75f34716..00000000
--- a/defpager/ChangeLog
+++ /dev/null
@@ -1,5 +0,0 @@
-Tue Apr 11 11:19:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: New file.
-
-
diff --git a/defpager/Makefile b/defpager/Makefile
index d774073e..8f92dd7c 100644
--- a/defpager/Makefile
+++ b/defpager/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 1995 Free Software Foundation
+# Copyright (C) 1995, 1996 Free Software Foundation
# Written by Michael I. Bushnell.
#
# This file is part of the GNU Hurd.
@@ -23,4 +23,12 @@ makemode := misc
SRCS = defpager.c
+subst-functions=__syscall_vm_allocate syscall_vm_allocate \
+ __vm_allocate_rpc vm_allocate_rpc \
+ __syscall_vm_map syscall_vm_map \
+ __vm_map_rpc vm_map_rpc
+comma=,
+LDFLAGS=-Wl,$(subst :,$(comma),$(strip $(subst-functions)))
+
include ../Makeconf
+
diff --git a/defpager/backing.c b/defpager/backing.c
new file mode 100644
index 00000000..5e6fbb65
--- /dev/null
+++ b/defpager/backing.c
@@ -0,0 +1,131 @@
+/* Backing store management for GNU Hurd.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <hurd/store.h>
+
+const struct store_class *const permitted_classes[] =
+{
+ &store_device_class, &store_ileave_class, &store_concat_class, 0
+};
+
+/* Allocation map, by PAGE. */
+/* If a bit is SET the corresponding PAGE is free. */
+char *bmap;
+
+/* Number of bytes in bmap */
+size_t bmap_len;
+
+/* Allocation rotor */
+char *bmap_rotor;
+
+struct mutex bmap_lock;
+
+error_t
+init_backing (char *name)
+{
+ error_t err;
+ int i;
+
+ err = store_open (name, STORE_NO_FILEIO, &permitted_classes, &backing_store);
+ if (err)
+ return err;
+
+ bmap_len = backing_store->size / vm_page_size / NBBY;
+ bmap = malloc (bmap_len);
+ for (i = 0; i < bmap_len; i++)
+ bmap[i] = 0xff;
+ bmap_rotor = bmap;
+
+ /* Mark the very first page as occupied. This makes sure we never
+ return zero offsets from allocate_backing_page (which
+ conventionally means that there is no space left. It also makes
+ sure we don't tromp on the misfeature in Linux of using the first
+ page for permanent data. */
+ *bmap_rotor |= 1;
+}
+
+int
+allocate_backing_page ()
+{
+ int wrapped;
+ int bit;
+ int pfn;
+
+ mutex_lock (&bmap_lock);
+
+ wrapped = (bmap_rotor == bmap);
+
+ while (!wrapped || bmap_rotor < bmap + bmap_len)
+ {
+ if (bmap[bmap_rotor])
+ break;
+ bmap_rotor++;
+ if (bmap_rotor >= bmap + bmap_len)
+ wrapped++;
+ }
+
+ if (wrapped == 2)
+ {
+ /* Didn't find one... */
+ mutex_unlock (&bmap_lock);
+ printf ("WARNING: Out of paging space; pageout failing.");
+ return 0;
+ }
+
+ /* Find which bit */
+ bit = ffs (*bmap_rotor);
+ assert (bit);
+ bit--;
+
+ /* Mark it */
+ *bmap_rotor |= 1 << bit;
+
+ /* Return the correct offset */
+ pfn = (bmap_rotor - bmap) * 8 + bit;
+
+ mutex_unlock (&bmap_lock);
+
+ return pfn * (vm_page_size / store->block_size);
+}
+
+
+void
+return_backing_pages (off_t *map, int maplen)
+{
+ int i;
+
+ mutex_lock (&bmap_lock);
+ for (i = 0; i < maplen; i++)
+ {
+ int pfn;
+ char *b;
+ int bit;
+
+ pfn = map[i] / (vm_page_size / store->block_size);
+ b = bmap + pfn & ~7;
+ bit = pfn & 7;
+
+ assert ((*b & (1 << bit)) == 0);
+ *b |= 1 << bit;
+ }
+ mutex_unlock (&bmap_lock);
+}
+
diff --git a/defpager/defpager.c b/defpager/defpager.c
index 60ca6c19..3a824cf1 100644
--- a/defpager/defpager.c
+++ b/defpager/defpager.c
@@ -1,6 +1,6 @@
/* Default pager for GNU Hurd.
- Copyright (C) 1994 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
This file is part of the GNU Hurd.
@@ -18,30 +18,119 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/*
- * Mach Operating System
- * Copyright (c) 1993-1989 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
+#include <hurd/pager.h>
+#include <hurd/store.h>
+struct user_pager_info
+{
+ /* Size of the object */
+ vm_size_t size;
+
+ /* One entry for each page of the object. */
+ off_t *map;
+};
+
+/* Expand the P->map as necessary to handle an incoming request of the
+ page at ADDR. */
+static inline void
+expand_map (struct user_pager_info *p, vm_offset_t addr)
+{
+ /* See if this is beyond the current extent */
+ if (page >= pager->size)
+ {
+ off_t *newmap;
+ vm_size_t newsize;
+
+ newsize = page + vm_page_size;
+ newmap = realloc (pager->map, size / vm_page_size * sizeof (off_t));
+
+ bzero (pager->map + pager->size / vm_page_size * sizeof (off_t),
+ (newsize - pager->size) / vm_page_size * sizeof (off_t));
+ pager->size = newsize;
+ pager->map = newmap;
+ }
+}
+
+error_t
+pager_read_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t *buf,
+ int *write_lock)
+{
+ int pfn = page / vm_page_size;
+ size_t nread;
+
+ /* We never request write locks. */
+ *write_lock = 0;
+
+ expand_map (pager, page);
+
+ if (!pager->map[pfn])
+ vm_allocate (mach_task_self (), buf, vm_page_size, 1);
+ else
+ {
+ store_read (backing_store, pager->map[pfn], vm_page_size,
+ (void **)buf, &nread);
+ if (nread != vm_page_size)
+ {
+ munmap ((caddr_t) *buf, nread);
+ return EIO;
+ }
+ }
+ return 0;
+}
+
+
+error_t
+pager_write_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t buf)
+{
+ int pfn = page / vm_page_size;
+ size_t nwritten;
+
+ expand_map (pager, page);
+
+ if (!pager->map[pfn])
+ pager->map[pfn] = allocate_backing_page ();
+
+ /* No more backing store. Oh dear. */
+ if (!pager->map[pfn])
+ return EIO;
+
+ err = store_write (backing_store, pager->map[pfn], (void *) buf,
+ vm_page_size, &nwritten);
+ if (!err && nwritten != vm_page_size)
+ err = EIO;
+ return err;
+}
+
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t address)
+{
+ return 0;
+}
+
+error_t
+pager_report_extent (struct user_pager_info *pager,
+ vm_address_t *offset,
+ vm_size_t *size)
+{
+ *offset = 0;
+ *size = pager->size;
+ return 0;
+}
+
+void
+pager_clear_user_data (struct user_pager_info *pager)
+{
+ return_backing_pages (pager->map, pager->size / vm_page_size);
+ free (pager->map);
+}
+
+void
+pager_dropweak (struct user_pager_info *pager)
+{
+}
diff --git a/defpager/wiring.c b/defpager/wiring.c
new file mode 100644
index 00000000..dda5d9d5
--- /dev/null
+++ b/defpager/wiring.c
@@ -0,0 +1,111 @@
+/* Memory wiring functions for default pager
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file uses the "wrap" feature of GNU ld. See the GNU ld
+ documentation for more information on how this works.
+ The list of functions we wrap is specified in Makefile as
+ $(subst-functions). */
+
+
+error_t
+__wrap___syscall_vm_allocate (task_t target_task,
+ vm_address_t *address,
+ vm_size_t size,
+ boolean_t anywhere)
+{
+ error_t err;
+
+ err = __real___syscall_vm_allocate (target_task, address, size, anywhere);
+ if (!err && target_task == mach_task_self ())
+ wire_segment (*address, size);
+ return err;
+}
+
+error_t
+__wrap___vm_allocate_rpc (task_t target_task,
+ vm_address_t *address,
+ vm_size_t size,
+ boolean_t anywhere)
+{
+ error_t err;
+
+ err = __real___vm_allocate_rpc (target_task, address, size, anywhere);
+ if (!err && target_task == mach_task_self ())
+ wire_segment (*address, size);
+ return err;
+}
+
+error_t
+__wrap___syscall_vm_map (mach_port_t target_task,
+ vm_address_t *address,
+ vm_size_t size,
+ vm_address_t mask,
+ boolean_t anywhere,
+ mach_port_t memory_object,
+ vm_offset_t offset,
+ boolean_t copy,
+ vm_prot_t cur_protection,
+ vm_prot_t max_protection,
+ vm_inherit_t inheritance)
+{
+ error_t err;
+
+ err = __real___syscall_vm_map (target_task, address, size, mask, anywhere,
+ memory_object, offset, copy, cur_protection,
+ max_protection, inheritance);
+ if (!err && target_task == mach_task_self ())
+ wire_segment (*address, size);
+ return err;
+}
+
+
+error_t
+__wrap___vm_map_rpc (mach_port_t target_task,
+ vm_address_t *address,
+ vm_size_t size,
+ vm_address_t mask,
+ boolean_t anywhere,
+ mach_port_t memory_object,
+ vm_offset_t offset,
+ boolean_t copy,
+ vm_prot_t cur_protection,
+ vm_prot_t max_protection,
+ vm_inherit_t inheritance)
+{
+ error_t err;
+
+ err = __real___vm_map_rpc (target_task, address, size, mask, anywhere,
+ memory_object, offset, copy, cur_protection,
+ mak_protection, inheritance);
+ if (!err && target_task == mach_task_self ())
+ wire_segment (*address, size);
+ return err;
+}
+
+/* And the non-__ versions too. */
+
+#define weak_alias(name,aliasname) \
+ extern typeof (name) aliasname __attribute__ ((weak, alias (#name)));
+
+weak_alias (__wrap___vm_map_rpc, __wrap_vm_map_rpc)
+weak_alias (__wrap___syscall_vm_map, __wrap_syscall_vm_map)
+weak_alias (__wrap___vm_allocate_rpc, __wrap_vm_allocate_rpc)
+weak_alias (__wrap___syscall_vm_allocate, __wrap_syscall_vm_allocate)
diff --git a/devio/ChangeLog b/devio/ChangeLog
deleted file mode 100644
index a38f283a..00000000
--- a/devio/ChangeLog
+++ /dev/null
@@ -1,265 +0,0 @@
-Fri Jul 19 15:55:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_get_storage_info): Return correct values for
- NUM_RUNS and NUM_OFFSETS.
-
-Thu Jul 18 18:33:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_get_storage_info): Fill in the array-length
- return values.
-
- * MAKEDEV: Add "com[0-9]".
-
-Wed Jul 17 10:00:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * MAKEDEV (st): New function.
- Use new st function (get rid of chmods).
- Accept disk device names without partitions, & with slice + partition.
-
-Sat Jun 15 14:13:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * MAKEDEV ([hrs]d*): Allow user to specify slice as well. Patch
- from Gord Matzigkeit, gord@enci.ucalgary.ca.
-
-Thu May 9 12:15:47 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_io_select): Remove TAG arg.
- (trivfs_S_file_get_storage_info): Fix param type.
-
-Tue May 7 16:41:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_get_storage_info): Swap PORTS_TYPE & NUM_PORTS.
-
-Mon May 6 20:14:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_get_storage_info): Enable new version.
-
-Fri May 3 15:09:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c [0] (trivfs_S_file_get_storage_info): Rewrite for new interface.
-
-Tue Apr 30 10:03:50 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (include ../Makeconf): BEFORE dependencies.
- ($(prefix)/dev/MAKEDEV): Find MAKEDEV in $(srcdir).
-
-Fri Feb 16 19:28:32 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * MAKEDEV: Add rule for `time', and add `time' to std.
-
-Tue Jan 30 12:34:28 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * MAKEDEV: Grok `tty'.
-
-Thu Jan 25 18:10:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devio.c (trivfs_goaway): Handle errors from ports_inhibit_class_rpcs.
- Allow rpcs to resume if we're going to return EBUSY.
-
-Tue Jan 16 16:19:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devio.c (trivfs_modify_stat): The peropen hook holds a struct
- open, not a struct dev.
-
-Fri Dec 29 23:41:39 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * MAKEDEV (std): Make `fd' one of the standard devices.
-
-Fri Dec 15 13:30:33 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * MAKEDEV (ST): Variable holding the proper settrans command,
- which use.
- (_CWD): Use this variable to pass down the current directory to
- sub MAKEDEVS.
- (console): Use the new term syntax.
- (tty[0-9]?|tty[0-9a-f]): New rule for normal ttys.
- ([pt]ty[pqPQ]?): New rule for ptys (both master and slave).
- ([pt]ty[pqPQ]): New rule for making sets of ptys.
-
-Mon Dec 4 15:17:14 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_set_size, trivfs_S_file_sync,
- trivfs_S_file_syncfs, trivfs_S_file_get_storage_info): Add totally
- gratuitous, annoying, and trouble-making reply-port args.
-
- * io.c (trivfs_S_file_get_storage_info): Use inline return if possible.
-
-Wed Nov 8 16:44:05 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_set_size): Renamed from trivfs_S_file_truncate.
-
-Sun Nov 5 10:00:56 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devio.c (main): Add FLAGS arg to trivfs_startup call.
-
-Sat Nov 4 20:03:05 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_get_storage_info): Add FLAGS argument.
-
-Fri Oct 6 17:25:37 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_get_storage_info): Change type of ADDRESSES
- to off_t **, and add BLOCK_SIZE parameter.
-
-Sun Oct 1 16:20:45 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devio.c (main, trivfs_S_fsys_syncfs): Get rid of debugging noise.
- * rdwr.c (open_write, open_read): Ditto.
- * dev.c (dev_open, dev_sync, dev_write, dev_read): Ditto.
- * io.c (trivfs_S_file_syncfs, trivfs_S_file_sync): Ditto.
- * devpager.c (pager_write_page, pager_read_page): Ditto.
- * window.c (position): Ditto.
-
-Tue Sep 26 15:33:14 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (trivfs_S_file_get_storage_info): New function.
- * dev.c (dev_open): Record NAME in the returned dev structure.
- * dev.h (struct dev): Add the NAME field.
-
-Thu Aug 24 10:28:00 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (devio): Put all dependencies here.
- (HURDLIBS): Removed.
-
-Tue Aug 22 10:45:31 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Add libshouldbeinlibc.
- (OBJS): Get rid of error.o.
- Get rid of rules dealing with error.o.
- ($(prefix)/dev/MAKEDEV): Use $(INSTALL_PROGRAM) instead of
- $(INSTALL_DATA) + `chmod +x'.
-
- * devio.c (trivfs_modify_stat): Get the device from CRED now that
- we have it.
-
-Mon Aug 21 16:34:29 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * devio.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
-
-Tue Aug 15 19:47:57 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * MAKEDEV ([hrs]d*): Fixed partition parsing: use glob pattern,
- not regexp.
-
-Sun Aug 13 10:57:03 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * devio.c (trivfs_peropen_create_hook): This now returns an error_t.
- (open_hook): And thus this does as well.
-
-Sat Jul 22 18:32:03 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * rdwr.c (open_read, open_write): Clean up STATE before returning
- with an error.
- * devpager.c (dev_get_memory_object): A new pager now comes with 1
- ref, so we allocate a ref ourselves when we're using an old one,
- and once we've created the send right, remove a reference.
-
-Mon Jul 10 15:15:45 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * rdwr.c (open_seek): New function.
- (raw_read, raw_write): Return EINVAL if *OFFS isn't a block boundary.
- * open.h: Add declaration for open_seek.
- * io.c (trivfs_S_io_seek): Call open_seek instead of doing ourselves.
-
-Sat Jul 8 18:35:17 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * MAKEDEV (fd): Put the fd server on `fd', not `stdin'.
- * MAKEDEV (console): Give /hurd/term a ttyname argument.
-
-Thu Jul 6 15:33:33 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * Makefile: Remove include dependencies.
-
-Wed Jun 28 19:22:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Add libihash.
-
- * iostate.c (io_state_sync): Remember that we've synced the buffer.
- * devpager.c (dev_stop_paging): New function.
- (pager_dropweak): New function.
- * dev.h (struct dev): Add the pager_port_bucket field.
- Declare dev_stop_paging ().
- * devio.c (trivfs_goaway): Make trivfs_goaway do the right thing.
- (clean_exit, close_device): Deleted functions.
- (thread_cancel): New function.
-
- * devpager.c (pager_port_type): Deleted var.
- (pager_port_bucket, pager_port_class): New vars.
- (dev_get_memory_object): Moved here from dev.c. Also, call
- init_dev_pager if necessary.
- (service_paging_requests): New function.
- (init_dev_pager): New function.
- * dev.c (dev_get_memory_object): Moved function to devpager.c.
-
- * devio.c (fsys_port_class, root_port_class, port_bucket): New vars.
- (trivfs_protid_portclasses, trivfs_cntl_portclasses,
- trivfs_protid_nportclasses, trivfs_cntl_nportclasses): New vars.
- (main): Initialize *portclasses vars, and convert to new trivfs lib.
- (trivfs_protid_porttypes, trivfs_cntl_porttypes,
- trivfs_protid_nporttypes, trivfs_cntl_nporttypes): Deleted vars.
- (trivfs_goaway): Convert args for new trivfs lib.
- (ports_cleanroutines): Delete var.
- (ports_demuxer, ports_notice_idle, ports_no_live_ports,
- ports_no_hard_ports): Delete functions.
- * ptypes.h: Deleted file.
-
-Wed Jun 28 15:51:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Repair mangled include-file dependencies.
-
-Fri Apr 21 14:17:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * MAKEDEV: Split out `std' into individual device-makers it calls.
- Rewrote /dev/fd stuff (still commented out). Use case built-in
- instead of expr program.
-
-Tue Apr 11 15:46:35 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): New var, for MAKEDEV.
- (install): Depend on $(prefix)/dev/MAKEDEV.
- ($(prefix)/dev/MAKEDEV): New target.
- * MAKEDEV: New file.
-
-Mon Apr 10 10:22:26 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * rdwr.c (open_write, open_read): Bounds check I/O.
-
- * io.c (trivfs_S_file_truncate): Always return 0, so O_TRUNC works.
-
- * devio.c (main, check_open_hook, close_device, trivfs_goaway):
- Add a new lock, device_lock, and use it to control access to the
- DEVICE variable.
- (open_hook, trivfs_modify_stat, trivfs_S_fys_syncfs): Copy DEVICE
- before using it, so it doesn't change underneath us.
-
- * devio.c (clean_exit): Add a new argument that says whether to
- aquire a lock before doing our work.
- (ports_notice_idle, ports_no_live_ports): Use it.
-
- * devio.c (close_device): New function, closes DEVICE cleanly.
- (clean_exit, ports_no_hard_ports): Use close_device.
-
- * devio.c (main): Use trivfs_startup instead of doing it manually.
-
- * devio.c (trivfs_goaway): Try and do it better, paying attention
- to flags, etc.; this still isn't right though, we may want to wait
- for the ports library to be fixed first.
-
- * devio.c (DEBUG): New macro, executes its arg with debug_lock locked.
- (most everything): use DEBUG instead of doing things manually.
-
- * open.c (open_create): Supply our dev's size when creating a window.
-
-Sun Apr 9 14:49:33 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * window.h: Add a new window field, max_pos. Rename the location
- field `pos'.
- * window.c (position): Use a shorter than normal window if
- necessary to avoid going past the end of the device.
- (window_create): Initialize the new MAX_POS field.
- (window_create, position, window_write, window_read): Rename the
- location field `pos'.
-
- * devpager.c (pager_read_page, pager_write_page): Read or write
- partial pages at the end of the device.
-
diff --git a/devio/MAKEDEV b/devio/MAKEDEV
deleted file mode 100644
index 7d13fe3b..00000000
--- a/devio/MAKEDEV
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/sh
-#
-# Make standard devices
-#
-
-PATH=/bin
-
-function st {
- NODE="$1"
- OWNER="$2"
- PERM="$3"
- shift 3
- settrans -cg "$NODE"
- chown "$OWNER" "$NODE"
- chmod "$PERM" "$NODE"
- settrans "$NODE" "$@"
-}
-
-_CWD=${_CWD:-`pwd`}
-export _CWD
-
-for I; do
- case "$I" in
- std)
- $0 console tty null zero fd time
- ;;
- console|tty[0-9][0-9a-f]|tty[0-9a-f]|com[0-9])
- st $I root 600 /hurd/term $_CWD/$I device $I;;
- null)
- st $I root 666 /hurd/null;;
- zero)
- st $I root 666 /hurd/null -z;;
- tty)
- st $I root 666 /hurd/magic tty;;
- fd)
- st $I root 666 /hurd/magic fd
- ln -f -s fd/0 stdin
- ln -f -s fd/1 stdout
- ln -f -s fd/2 stderr
- ;;
- time)
- st $I root 666 /hurd/devport time ;;
-
- # ptys
- [pt]ty[pqPQ]?)
- # Make one pty, both the master and slave halves
- ID="`expr substr $I 4 99`"
- st pty$ID root 640 /hurd/term $_CWD/pty$ID pty-master $_CWD/tty$ID
- st tty$ID root 640 /hurd/term $_CWD/tty$ID pty-slave $_CWD/pty$ID
- ;;
- [pt]ty[pqPQ])
- # Make a bunch of ptys
- $0 ${I}0 ${I}1 ${I}2 ${I}3 ${I}4 ${I}5 ${I}6 ${I}7
- $0 ${I}8 ${I}9 ${I}a ${I}b ${I}c ${I}d ${I}e ${I}f
- ;;
-
- fd*|mt*)
- st r$I root 640 /hurd/devio $I
- st $I root 640 /hurd/devio -b $I
- ;;
-
- [hrs]d*)
- case "$I" in
- [a-z][a-z][0-9][a-z] | [a-z][a-z][0-9]s[1-9] | [a-z][a-z][0-9]s[1-9][a-z] | [a-z][a-z][0-9])
- st r$I root 640 /hurd/devio $I
- st $I root 640 /hurd/devio -b $I
- ;;
- *)
- echo 1>&2 $0: $I: Illegal device name: must supply a device number
- exit 1
- ;;
- esac
- ;;
-
- *)
- echo >&2 $0: $I: Unknown device
- exit 1
- ;;
- esac
-done
diff --git a/devio/dev.c b/devio/dev.c
deleted file mode 100644
index 4d3b89cb..00000000
--- a/devio/dev.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/* Mach devices.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-#include <device/device.h>
-#include <assert.h>
-#include <hurd/pager.h>
-
-#include "dev.h"
-#include "iostate.h"
-
-/* ---------------------------------------------------------------- */
-
-/* Returns a pointer to a new device structure in DEV for the kernel device
- NAME, with the given FLAGS. If BLOCK_SIZE is non-zero, it should be the
- desired block size, and must be a multiple of the device block size.
- If an error occurs, the error code is returned, otherwise 0. */
-error_t
-dev_open(char *name, int flags, int block_size, struct dev **dev)
-{
- error_t err = 0;
- static mach_port_t device_master = MACH_PORT_NULL;
-
- *dev = malloc(sizeof (struct dev));
-
- if (!(flags & DEV_SERIAL))
- flags |= DEV_SEEKABLE;
-
- if (*dev == NULL)
- return ENOMEM;
-
- (*dev)->name = malloc (strlen (name) + 1);
- if ((*dev)->name)
- strcpy ((*dev)->name, name);
- else
- err = ENOMEM;
-
- (*dev)->port = MACH_PORT_NULL;
-
- if (!err && device_master == MACH_PORT_NULL)
- err = get_privileged_ports(NULL, &device_master);
-
- if (!err)
- err = device_open(device_master,
- D_READ | (flags & DEV_READONLY ? D_WRITE : 0),
- name, &(*dev)->port);
-
- if (!err)
- {
- int count = DEV_GET_SIZE_COUNT;
- int sizes[DEV_GET_SIZE_COUNT];
-
- /* Get info about the device: total size (in bytes) and block size (in
- bytes). Block size is unit in which device addressing is done. */
- err = device_get_status((*dev)->port, DEV_GET_SIZE, sizes, &count);
- if (!err)
- {
- (*dev)->size = sizes[DEV_GET_SIZE_DEVICE_SIZE];
- (*dev)->dev_block_size = sizes[DEV_GET_SIZE_RECORD_SIZE];
- }
- }
-
- if (!err)
- {
- if (block_size > 0)
- if (block_size > (*dev)->dev_block_size
- && block_size % (*dev)->dev_block_size == 0)
- (*dev)->block_size = block_size;
- else
- err = EINVAL;
- else
- (*dev)->block_size = (*dev)->dev_block_size;
-
- if ((*dev)->dev_block_size == 1)
- flags |= DEV_SERIAL;
-
- (*dev)->flags = flags;
- (*dev)->owner = 0;
- }
-
- if (!err)
- err = io_state_init(&(*dev)->io_state, *dev);
-
- if (err)
- {
- if ((*dev)->port != MACH_PORT_NULL)
- mach_port_deallocate(mach_task_self(), (*dev)->port);
- free(*dev);
- }
-
- return err;
-}
-
-/* Free DEV and any resources it consumes. */
-void
-dev_close(struct dev *dev)
-{
- if (!dev_is(dev, DEV_READONLY))
- {
- if (dev->pager != NULL)
- pager_shutdown(dev->pager);
- io_state_sync(&dev->io_state, dev);
- }
-
- device_close(dev->port);
- io_state_finalize(&dev->io_state);
-
- free(dev);
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Try and write out any pending writes to DEV. If WAIT is true, will wait
- for any paging activity to cease. */
-error_t
-dev_sync(struct dev *dev, int wait)
-{
- error_t err = 0;
-
- if (!dev_is(dev, DEV_READONLY))
- {
- struct io_state *ios = &dev->io_state;
-
- io_state_lock(ios);
-
- /* Sync any paged backing store. */
- if (dev->pager != NULL)
- pager_sync(dev->pager, wait);
-
- /* Write out any stuff buffered in our io_state. */
- err = io_state_sync(ios, dev);
-
- io_state_unlock(ios);
- }
-
- return err;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Writes AMOUNT bytes from the buffer pointed to by BUF to the device DEV.
- *OFFS is incremented to reflect the amount read/written. Both AMOUNT and
- *OFFS must be multiples of DEV's block size, and either BUF must be
- page-aligned, or dev_write_valid() must return true for these arguments.
- If an error occurs, the error code is returned, otherwise 0. */
-error_t
-dev_write(struct dev *dev,
- vm_address_t buf, vm_size_t amount, vm_offset_t *offs)
-{
- int bsize = dev->dev_block_size;
- vm_offset_t written = 0;
- vm_offset_t block = (bsize == 1 ? *offs : *offs / bsize);
- error_t err;
-
- assert(dev_write_valid(dev, buf, amount, *offs));
- assert(*offs % bsize == 0);
- assert(amount % bsize == 0);
-
- if (amount < IO_INBAND_MAX)
- err =
- device_write_inband (dev->port, 0, block,
- (io_buf_ptr_t)buf, amount, &written);
- else
- err =
- device_write (dev->port, 0, block, (io_buf_ptr_t)buf, amount, &written);
-
- if (!err)
- *offs += written;
-
- return err;
-}
-
-/* Reads AMOUNT bytes from DEV and returns it in BUF and BUF_LEN (using the
- standard mach out-array convention). *OFFS is incremented to reflect the
- amount read/written. Both LEN and *OFFS must be multiples of DEV's block
- size. If an error occurs, the error code is returned, otherwise 0. */
-error_t
-dev_read(struct dev *dev,
- vm_address_t *buf, vm_size_t *buf_len, vm_size_t amount,
- vm_offset_t *offs)
-{
- error_t err = 0;
- int bsize = dev->dev_block_size;
- vm_offset_t read = 0;
- vm_offset_t block = (bsize == 1 ? *offs : *offs / bsize);
-
- assert(*offs % bsize == 0);
- assert(amount % bsize == 0);
-
- if (amount < IO_INBAND_MAX)
- {
- if (*buf_len < amount)
- err = vm_allocate(mach_task_self(), buf, amount, 1);
- if (!err)
- err =
- device_read_inband(dev->port, 0, block,
- amount, (io_buf_ptr_t)*buf, &read);
- }
- else
- err =
- device_read(dev->port, 0, block, amount, (io_buf_ptr_t *)buf, &read);
-
- if (!err)
- {
- *offs += read;
- *buf_len = read;
- }
-
- return err;
-}
diff --git a/devio/dev.h b/devio/dev.h
deleted file mode 100644
index de51d788..00000000
--- a/devio/dev.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* A handle on a mach device.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#ifndef __DEV_H__
-#define __DEV_H__
-
-#include <mach.h>
-#include <device/device.h>
-
-#include "iostate.h"
-
-/* #define FAKE */
-#define MSG
-
-#ifdef MSG
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-extern FILE *debug;
-extern struct mutex debug_lock;
-#endif
-
-/* ---------------------------------------------------------------- */
-
-/* Information about a kernel device. */
-struct dev
-{
- /* The device port for the kernel device we're doing paging on. */
- device_t port;
- /* The mach device name which we opened. */
- char *name;
-
- /* The total size of DEV. */
- vm_size_t size;
-
- /* The block size of DEV. I/O to DEV must occur in multiples of
- block_size. */
- int dev_block_size;
- /* The block size in which we will do I/O; this must be a multiple of
- DEV_BLOCK_SIZE. */
- int block_size;
-
- /* Various attributes of this device (see below for the DEV_ flag bits).
- This field is constant. */
- int flags;
-
- /* Current state of our output stream -- location and the buffer used to do
- buffered i/o. */
- struct io_state io_state;
-
- /* The pager we're using to do disk i/o for us. If NULL, a pager hasn't
- been allocated yet. Lock the lock in IO_STATE if you want to update
- this field. */
- struct pager *pager;
- /* The port_bucket for paging ports. */
- struct port_bucket *pager_port_bucket;
-
- /* The current owner of the open device. For terminals, this affects
- controlling terminal behavior (see term_become_ctty). For all objects
- this affects old-style async IO. Negative values represent pgrps. This
- has nothing to do with the owner of a file (as returned by io_stat, and
- as used for various permission checks by filesystems). An owner of 0
- indicates that there is no owner. */
- pid_t owner;
-};
-
-/* Various bits to be set in the flags field. */
-
-/* True if this device should be used in `block' mode, with buffering of
- sub-block-size i/o. */
-#define DEV_BUFFERED 0x1
-/* True if this device only supports serial i/o (that is, there's only one
- read/write location, which must explicitly be moved to do i/o elsewhere.*/
-#define DEV_SERIAL 0x2
-/* True if we can change the current i/o location of a serial device. */
-#define DEV_SEEKABLE 0x4
-/* True if a device cannot be written on. */
-#define DEV_READONLY 0x8
-
-/* Returns TRUE if any of the flags in BITS are set for DEV. */
-#define dev_is(dev, bits) ((dev)->flags & (bits))
-
-/* Returns true if it's ok to call dev_write on these arguments, without
- first copying BUF to a page-aligned buffer. */
-#define dev_write_valid(dev, buf, len, offs) \
- ((len) <= IO_INBAND_MAX || (buf) % vm_page_size == 0)
-
-/* Returns a pointer to a new device structure in DEV for the kernel device
- NAME, with the given FLAGS. If BLOCK_SIZE is non-zero, it should be the
- desired block size, and must be a multiple of the device block size.
- If an error occurs, the error code is returned, otherwise 0. */
-error_t dev_open(char *name, int flags, int block_size, struct dev **dev);
-
-/* Free DEV and any resources it consumes. */
-void dev_close(struct dev *dev);
-
-/* Reads AMOUNT bytes from DEV and returns it in BUF and BUF_LEN (using the
- standard mach out-array convention). *OFFS is incremented to reflect the
- amount read/written. Both LEN and *OFFS must be multiples of DEV's block
- size. If an error occurs, the error code is returned, otherwise 0. */
-error_t dev_read(struct dev *dev,
- vm_address_t *buf, vm_size_t *buf_len, vm_size_t amount,
- vm_offset_t *offs);
-
-/* Writes AMOUNT bytes from the buffer pointed to by BUF to the device DEV.
- *OFFS is incremented to reflect the amount read/written. Both AMOUNT and
- *OFFS must be multiples of DEV's block size, and either BUF must be
- page-aligned, or dev_write_valid() must return true for these arguments.
- If an error occurs, the error code is returned, otherwise 0. */
-error_t dev_write(struct dev *dev,
- vm_address_t buf, vm_size_t amount, vm_offset_t *offs);
-
-/* Returns in MEMOBJ the port for a memory object backed by the storage on
- DEV. Returns 0 or the error code if an error occurred. */
-error_t dev_get_memory_object(struct dev *dev, memory_object_t *memobj);
-
-/* Try to stop all paging activity on DEV, returning true if we were
- successful. If NOSYNC is true, then we won't write back any (kernel)
- cached pages to the device. */
-int dev_stop_paging (struct dev *dev, int nosync);
-
-/* Try and write out any pending writes to DEV. If WAIT is true, will wait
- for any paging activity to cease. */
-error_t dev_sync(struct dev *dev, int wait);
-
-#ifdef MSG
-char *brep(vm_address_t buf, vm_size_t len);
-#endif
-
-#endif /* !__DEV_H__ */
diff --git a/devio/devio.c b/devio/devio.c
deleted file mode 100644
index f1eb428a..00000000
--- a/devio/devio.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/* A translator for doing I/O to mach kernel devices.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-#include <hurd/ports.h>
-#include <hurd/pager.h>
-#include <hurd/trivfs.h>
-#include <hurd/fsys.h>
-
-#include <stdio.h>
-#include <error.h>
-#include <getopt.h>
-#include <assert.h>
-#include <fcntl.h>
-
-#include "open.h"
-#include "dev.h"
-
-/* ---------------------------------------------------------------- */
-
-/* The port class of our file system control pointer. */
-struct port_class *fsys_port_class;
-/* The port class of the (only) root file port for the opened device. */
-struct port_class *root_port_class;
-
-/* A bucket to put all our ports in. */
-struct port_bucket *port_bucket;
-
-/* Trivfs noise. */
-struct port_class *trivfs_protid_portclasses[1];
-struct port_class *trivfs_cntl_portclasses[1];
-int trivfs_protid_nportclasses = 1;
-int trivfs_cntl_nportclasses = 1;
-
-/* ---------------------------------------------------------------- */
-
-#define USAGE "Usage: %s [OPTION...] DEVICE\n"
-
-static void
-usage(int status)
-{
- if (status != 0)
- fprintf(stderr, "Try `%s --help' for more information.\n",
- program_invocation_name);
- else
- {
- printf(USAGE, program_invocation_name);
- printf("\
-\n\
- -d, --devnum=NUM Give DEVICE a device number NUM\n\
- -r, --readonly Disable writing to DEVICE\n\
- -p, --seekable Enable seeking if DEVICE is serial\n\
- -s, --serial Indicate that DEVICE has a single R/W point\n\
- -b, --buffered, --block Open DEVICE in `block' mode, which allows reads\n\
- or writes less than a single block and buffers\n\
- I/O to the actual device. By default, all reads\n\
- and writes are made directly to the device,\n\
- with no buffering, and any sub-block-size I/O\n\
- is padded to the nearest full block.\n\
- -B NUM, --block-size=NUM Use a block size of NUM, which must be an integer\n\
- multiple of DEVICE's real block size\n\
-");
- }
-
- exit(status);
-}
-
-#define SHORT_OPTIONS "bB:d:D:?rpsu"
-
-static struct option options[] =
-{
- {"block-size", required_argument, 0, 'B'},
- {"help", no_argument, 0, '?'},
- {"devnum", required_argument, 0, 'm'},
- {"block", no_argument, 0, 'b'},
- {"buffered", no_argument, 0, 'b'},
- {"readonly", no_argument, 0, 'r'},
- {"seekable", no_argument, 0, 'p'},
- {"serial", no_argument, 0, 's'},
- {0, 0, 0, 0}
-};
-
-/* ---------------------------------------------------------------- */
-
-/* A struct dev for the open kernel device. */
-static struct dev *device = NULL;
-/* And a lock to arbitrate changes to it. */
-static struct mutex device_lock;
-
-/* Desired device parameters specified by the user. */
-static char *device_name = NULL;
-static int device_flags = 0;
-static int device_block_size = 0;
-
-/* A unixy device number to return when the device is stat'd. */
-static int device_number = 0;
-
-void main(int argc, char *argv[])
-{
- int opt;
- error_t err;
- mach_port_t bootstrap;
-
- while ((opt = getopt_long(argc, argv, SHORT_OPTIONS, options, 0)) != EOF)
- switch (opt)
- {
- case 'r': device_flags |= DEV_READONLY; break;
- case 's': device_flags |= DEV_SERIAL; break;
- case 'b': device_flags |= DEV_BUFFERED; break;
- case 'p': device_flags |= DEV_SEEKABLE; break;
- case 'B': device_block_size = atoi(optarg); break;
- case 'd': device_number = atoi(optarg); break;
- case '?': usage(0);
- default: usage(1);
- }
-
- if (device_flags & DEV_READONLY)
- /* Catch illegal writes at the point of open. */
- trivfs_allow_open &= ~O_WRITE;
-
- if (argv[optind] == NULL || argv[optind + 1] != NULL)
- {
- fprintf(stderr, USAGE, program_invocation_name);
- usage(1);
- }
-
- device_name = argv[optind];
-
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error(2, 0, "Must be started as a translator");
-
- fsys_port_class = ports_create_class (trivfs_clean_cntl, 0);
- root_port_class = ports_create_class (trivfs_clean_protid, 0);
- port_bucket = ports_create_bucket ();
- trivfs_protid_portclasses[0] = root_port_class;
- trivfs_cntl_portclasses[0] = fsys_port_class;
-
- /* Reply to our parent */
- err =
- trivfs_startup(bootstrap, 0,
- fsys_port_class, port_bucket,
- root_port_class, port_bucket,
- NULL);
- if (err)
- error(3, err, "Contacting parent");
-
- /* Open the device only when necessary. */
- device = NULL;
- mutex_init(&device_lock);
-
- /* Launch. */
- ports_manage_port_operations_multithread (port_bucket, trivfs_demuxer,
- 30*1000, 5*60*1000, 0, 0);
-
- exit(0);
-}
-
-/* Called whenever someone tries to open our node (even for a stat). We
- delay opening the kernel device until this point, as we can usefully
- return errors from here. */
-static error_t
-check_open_hook (struct trivfs_control *trivfs_control,
- uid_t *uids, u_int nuids,
- gid_t *gids, u_int ngids,
- int flags)
-{
- error_t err = 0;
-
- mutex_lock(&device_lock);
- if (device == NULL)
- /* Try and open the device. */
- {
- err = dev_open(device_name, device_flags, device_block_size, &device);
- if (err)
- device = NULL;
- if (err && (flags & (O_READ|O_WRITE)) == 0)
- /* If we're not opening for read or write, then just ignore the
- error, as this allows stat to word correctly. XXX */
- err = 0;
- }
- mutex_unlock(&device_lock);
-
- return err;
-}
-
-static error_t
-open_hook(struct trivfs_peropen *peropen)
-{
- struct dev *dev = device;
- if (dev)
- return open_create(dev, (struct open **)&peropen->hook);
- else
- return 0;
-}
-
-static void
-close_hook(struct trivfs_peropen *peropen)
-{
- if (peropen->hook)
- open_free(peropen->hook);
-}
-
-/* ---------------------------------------------------------------- */
-/* Trivfs hooks */
-
-int trivfs_fstype = FSTYPE_DEV;
-int trivfs_fsid = 0;
-
-int trivfs_support_read = 1;
-int trivfs_support_write = 1;
-int trivfs_support_exec = 0;
-
-int trivfs_allow_open = O_READ | O_WRITE;
-
-void
-trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
-{
- struct open *open = cred->po->hook;
-
- if (open)
- /* An open device. */
- {
- struct dev *dev = open->dev;
- vm_size_t size = dev->size;
-
- if (dev->block_size > 1)
- st->st_blksize = dev->block_size;
-
- st->st_size = size;
- st->st_blocks = size / 512;
-
- if (dev_is(dev, DEV_READONLY))
- st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
-
- st->st_mode &= ~S_IFMT;
- st->st_mode |= dev_is(dev, DEV_BUFFERED) ? S_IFBLK : S_IFCHR;
- }
- else
- /* Try and do things without an open device... */
- {
- st->st_blksize = device_block_size;
- st->st_size = 0;
- st->st_blocks = 0;
- st->st_mode &= ~S_IFMT;
- st->st_mode |= (device_flags & DEV_BUFFERED) ? S_IFBLK : S_IFCHR;
- if (device_flags & DEV_READONLY)
- st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
- }
-
- st->st_rdev = device_number;
-}
-
-error_t
-trivfs_goaway (struct trivfs_control *fsys, int flags)
-{
- error_t err;
- int force = (flags & FSYS_GOAWAY_FORCE);
- int nosync = (flags & FSYS_GOAWAY_NOSYNC);
-
- mutex_lock(&device_lock);
-
- if (device == NULL)
- exit (0);
-
- /* Wait until all pending rpcs are done. */
- err = ports_inhibit_class_rpcs (root_port_class);
- if (err == EINTR || (err && !force))
- {
- mutex_unlock (&device_lock);
- return err;
- }
-
- if (force && nosync)
- /* Exit with extreme prejudice. */
- exit (0);
-
- if (!force && ports_count_class (root_port_class) > 0)
- /* Still users, so don't exit. */
- goto busy;
-
- if (!nosync)
- /* Sync the device here, if necessary, so that closing it won't result in
- any I/O (which could get hung up trying to use one of our pagers). */
- dev_sync (device, 1);
-
- /* devpager_shutdown may sync the pagers as side-effect (if NOSYNC is 0),
- so we put that first in this test. */
- if (dev_stop_paging (device, nosync) || force)
- /* Bye-bye. */
- {
- if (!nosync)
- /* If NOSYNC is true, we don't close DEV, as that could cause data to
- be written back. */
- dev_close (device);
- exit (0);
- }
-
- busy:
- /* Allow normal operations to proceed. */
- ports_enable_class (root_port_class);
- ports_resume_class_rpcs (root_port_class);
- mutex_unlock(&device_lock);
-
- /* Complain that there are still users. */
- return EBUSY;
-}
-
-/* If this variable is set, it is called every time an open happens.
- UIDS, GIDS, and FLAGS are from the open; CNTL identifies the
- node being opened. This call need not check permissions on the underlying
- node. If the open call should block, then return EWOULDBLOCK. Other
- errors are immediately reflected to the user. If O_NONBLOCK
- is not set in FLAGS and EWOULDBLOCK is returned, then call
- trivfs_complete_open when all pending open requests for this
- file can complete. */
-error_t (*trivfs_check_open_hook)(struct trivfs_control *trivfs_control,
- uid_t *uids, u_int nuids,
- gid_t *gids, u_int ngids,
- int flags)
- = check_open_hook;
-
-/* If this variable is set, it is called every time a new peropen
- structure is created and initialized. */
-error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
-
-/* If this variable is set, it is called every time a peropen structure
- is about to be destroyed. */
-void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
-
-/* Sync this filesystem. */
-kern_return_t
-trivfs_S_fsys_syncfs (struct trivfs_control *cntl,
- mach_port_t reply, mach_msg_type_name_t replytype,
- int wait, int dochildren)
-{
- struct dev *dev = device;
- if (dev)
- return dev_sync(dev, wait);
- else
- return 0;
-}
diff --git a/devio/devpager.c b/devio/devpager.c
deleted file mode 100644
index 1f3b3ee1..00000000
--- a/devio/devpager.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* A pager interface for raw mach devices.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-#include <hurd/pager.h>
-#include <device/device.h>
-#include <assert.h>
-
-#include "dev.h"
-
-/* ---------------------------------------------------------------- */
-/* Pager library callbacks; see <hurd/pager.h> for more info. */
-
-/* For pager PAGER, read one page from offset PAGE. Set *BUF to be the
- address of the page, and set *WRITE_LOCK if the page must be provided
- read-only. The only permissable error returns are EIO, EDQUOT, and
- ENOSPC. */
-error_t
-pager_read_page(struct user_pager_info *upi,
- vm_offset_t page, vm_address_t *buf, int *writelock)
-{
- error_t err;
- int read; /* bytes actually read */
- int want = vm_page_size; /* bytes we want to read */
- struct dev *dev = (struct dev *)upi;
-
- if (page + want > dev->size)
- /* Read a partial page if necessary to avoid reading off the end. */
- want = dev->size - page;
-
- err = device_read(dev->port, 0, page / dev->dev_block_size, want,
- (io_buf_ptr_t *)buf, &read);
-
- if (!err && want < vm_page_size)
- /* Zero anything we didn't read. Allocation only happens in page-size
- multiples, so we know we can write there. */
- bzero((char *)*buf + want, vm_page_size - want);
-
- *writelock = (dev->flags & DEV_READONLY);
-
- if (err || read < want)
- return EIO;
- else
- return 0;
-}
-
-/* For pager PAGER, synchronously write one page from BUF to offset PAGE. In
- addition, vm_deallocate (or equivalent) BUF. The only permissable error
- returns are EIO, EDQUOT, and ENOSPC. */
-error_t
-pager_write_page(struct user_pager_info *upi,
- vm_offset_t page, vm_address_t buf)
-{
- struct dev *dev = (struct dev *)upi;
-
- if (dev->flags & DEV_READONLY)
- return EROFS;
- else
- {
- error_t err;
- int written;
- int want = vm_page_size;
-
- if (page + want > dev->size)
- /* Write a partial page if necessary to avoid reading off the end. */
- want = dev->size - page;
-
- err = device_write(dev->port, 0, page / dev->dev_block_size,
- (io_buf_ptr_t)buf, want, &written);
-
- vm_deallocate(mach_task_self(), buf, vm_page_size);
-
- if (err || written < want)
- return EIO;
- else
- return 0;
- }
-}
-
-/* A page should be made writable. */
-error_t
-pager_unlock_page(struct user_pager_info *upi, vm_offset_t address)
-{
- struct dev *dev = (struct dev *)upi;
-
- if (dev->flags & DEV_READONLY)
- return EROFS;
- else
- return 0;
-}
-
-/* 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. */
-error_t
-pager_report_extent(struct user_pager_info *upi,
- vm_address_t *offset, vm_size_t *size)
-{
- *offset = 0;
- *size = ((struct dev *)upi)->size;
- return 0;
-}
-
-/* This is called when a pager is being deallocated after all extant send
- rights have been destroyed. */
-void
-pager_clear_user_data(struct user_pager_info *upi)
-{
-}
-
-/* ---------------------------------------------------------------- */
-
-/* A top-level function for the paging thread that just services paging
- requests. */
-static void
-service_paging_requests (any_t arg)
-{
- struct dev *dev = (struct dev *)arg;
- for (;;)
- ports_manage_port_operations_multithread (dev->pager_port_bucket,
- pager_demuxer,
- 1000 * 30, 1000 * 60 * 5,
- 1, MACH_PORT_NULL);
-}
-
-/* Initialize paging for this device. */
-static void
-init_dev_paging (struct dev *dev)
-{
- dev->pager_port_bucket = ports_create_bucket ();
-
- /* Make a thread to service paging requests. */
- cthread_detach (cthread_fork ((cthread_fn_t)service_paging_requests,
- (any_t)dev));
-}
-
-void
-pager_dropweak (struct user_pager_info *upi __attribute__ ((unused)))
-{
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Try to stop all paging activity on DEV, returning true if we were
- successful. If NOSYNC is true, then we won't write back any (kernel)
- cached pages to the device. */
-int
-dev_stop_paging (struct dev *dev, int nosync)
-{
- int success = 1; /* Initially assume success. */
-
- io_state_lock(&dev->io_state);
-
- if (dev->pager != NULL)
- {
- int num_pagers = ports_count_bucket (dev->pager_port_bucket);
- if (num_pagers > 0 && !nosync)
- {
- error_t block_cache (void *arg)
- {
- struct pager *p = arg;
- pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_DELAY, 1);
- return 0;
- }
- error_t enable_cache (void *arg)
- {
- struct pager *p = arg;
- pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_DELAY, 0);
- return 0;
- }
-
- /* Loop through the pagers and turn off caching one by one,
- synchronously. That should cause termination of each pager. */
- ports_bucket_iterate (dev->pager_port_bucket, block_cache);
-
- /* Give it a second; the kernel doesn't actually shutdown
- immediately. XXX */
- sleep (1);
-
- num_pagers = ports_count_bucket (dev->pager_port_bucket);
- if (num_pagers > 0)
- /* Darn, there are actual honest users. Turn caching back on,
- and return failure. */
- {
- ports_bucket_iterate (dev->pager_port_bucket, enable_cache);
- success = 0;
- }
- }
-
- if (success && !nosync)
- /* shutdown the pager on DEV. If NOSYNC is set, we don't bother, for
- fear that this may result in I/O. In this case we've disabled
- rpcs on the pager's ports, so this will result in hanging... What
- do we do??? XXXX */
- pager_shutdown (dev->pager);
- }
-
- if (success)
- dev->pager = NULL;
-
- io_state_lock(&dev->io_state);
-
- return success;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Returns in MEMOBJ the port for a memory object backed by the storage on
- DEV. Returns 0 or the error code if an error occurred. */
-error_t
-dev_get_memory_object(struct dev *dev, memory_object_t *memobj)
-{
- if (dev_is(dev, DEV_SERIAL))
- return ENODEV;
-
- io_state_lock(&dev->io_state);
- if (dev->pager_port_bucket == NULL)
- init_dev_paging (dev);
- if (dev->pager == NULL)
- dev->pager =
- pager_create((struct user_pager_info *)dev, dev->pager_port_bucket,
- 1, MEMORY_OBJECT_COPY_DELAY);
- else
- ports_port_ref (dev->pager);
- io_state_unlock(&dev->io_state);
-
- if (dev->pager == NULL)
- return ENODEV; /* XXX ??? */
-
- *memobj = pager_get_port(dev->pager);
- ports_port_deref (dev->pager); /* Drop our original ref on PAGER. */
-
- if (*memobj != MACH_PORT_NULL)
- return
- mach_port_insert_right(mach_task_self(),
- *memobj, *memobj,
- MACH_MSG_TYPE_MAKE_SEND);
-
- return 0;
-}
diff --git a/devio/iostate.c b/devio/iostate.c
deleted file mode 100644
index fe40fcd2..00000000
--- a/devio/iostate.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* State for an I/O stream.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-
-#include "iostate.h"
-#include "dev.h"
-
-/* ---------------------------------------------------------------- */
-
-/* Initialize the io_state structure IOS to be used with the device DEV. If
- a memory allocation error occurs, ENOMEM is returned, otherwise 0. */
-error_t
-io_state_init(struct io_state *ios, struct dev *dev)
-{
- error_t err =
- vm_allocate(mach_task_self(),
- (vm_address_t *)&ios->buffer, dev->block_size, 1);
-
- ios->location = 0;
- ios->buffer_size = dev->block_size;
- ios->buffer_use = 0;
- mutex_init(&ios->lock);
-
- return err;
-}
-
-/* Frees all resources used by IOS. */
-void
-io_state_finalize(struct io_state *ios)
-{
- vm_deallocate(mach_task_self(), (vm_address_t)ios->buffer, ios->buffer_size);
-}
-
-/* If IOS's location isn't block aligned because writes have been buffered
- there, then sync the whole buffer out to the device. Any error that
- occurs while writing is returned, otherwise 0. */
-error_t
-io_state_sync(struct io_state *ios, struct dev *dev)
-{
- error_t err = 0;
-
- if (ios->buffer_use == IO_STATE_BUFFERED_WRITE)
- {
- vm_offset_t pos = ios->location;
- int block_offs = pos % dev->block_size;
-
- if (block_offs > 0)
- {
- bzero((char *)ios->buffer + block_offs,
- dev->block_size - block_offs);
- ios->location -= block_offs;
- err =
- dev_write(dev, ios->buffer, dev->block_size, &ios->location);
- }
-
- /* Remember that there's nothing left in the buffer. */
- ios->buffer_use = 0;
- }
-
- return err;
-}
diff --git a/devio/iostate.h b/devio/iostate.h
deleted file mode 100644
index 1795e153..00000000
--- a/devio/iostate.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* State for an I/O stream.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#ifndef __IOSTATE_H__
-#define __IOSTATE_H__
-
-/* ---------------------------------------------------------------- */
-
-enum io_state_buffer_use
-{
- /* 0 means nothing */
- IO_STATE_BUFFERED_WRITE = 1, IO_STATE_BUFFERED_READ = 2
-};
-
-struct io_state {
- /* What we think the current position is. */
- vm_offset_t location;
-
- /* The buffer in which we accumulate buffered i/o. */
- vm_address_t buffer;
- /* The size of BUFFER. */
- vm_size_t buffer_size;
-
- /* If LOCATION is not a multiple of the block size (and so points somewhere
- in the middle of BUFFER), this indicates why. */
- enum io_state_buffer_use buffer_use;
-
- /* Lock this if you want to read/modify LOCATION or BUFFER. */
- struct mutex lock;
-};
-
-#define io_state_lock(ios) mutex_lock(&(ios)->lock)
-#define io_state_unlock(ios) mutex_unlock(&(ios)->lock)
-
-/* Declare this to keep the parameter scope below sane. */
-struct dev;
-
-/* Initialize the io_state structure IOS to be used with the device DEV. If
- a memory allocation error occurs, ENOMEM is returned, otherwise 0. */
-error_t io_state_init(struct io_state *ios, struct dev *dev);
-
-/* Frees all resources used by IOS. */
-void io_state_finalize(struct io_state *ios);
-
-/* If IOS's location isn't block aligned because writes have been buffered
- there, then sync the whole buffer out to the device. Any error that
- occurs while writing is returned, otherwise 0. */
-error_t io_state_sync(struct io_state *ios, struct dev *dev);
-
-#endif /* !__IOSTATE_H__ */
diff --git a/devio/mem.c b/devio/mem.c
deleted file mode 100644
index 65caa19f..00000000
--- a/devio/mem.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Some random handy ops for dealing with rpcs that return memory.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-#include <string.h>
-
-/* ---------------------------------------------------------------- */
-
-/* Makes sure that BUF, points to a buffer with AMOUNT bytes available.
- *BUF_LEN should be the current length of *BUF, and if this isn't enough to
- hold AMOUNT bytes, then more is allocated and the new buffer is returned
- in *BUF and *BUF_LEN. If a memory allocation error occurs, the error code
- is returned, otherwise 0. */
-error_t
-allocate(vm_address_t *buf, vm_size_t *buf_len, vm_size_t amount)
-{
- if (*buf_len < amount)
- {
- error_t err = vm_allocate(mach_task_self(), buf, amount, 1);
- if (err)
- return err;
- }
-
- *buf_len = amount;
- return 0;
-}
-
-/* Deallocates any pages entirely within the last EXCESS bytes of the BUF_LEN
- long buffer, BUF. */
-error_t
-deallocate_excess(vm_address_t buf, vm_size_t buf_len, vm_size_t excess)
-{
- vm_size_t excess_pages = buf_len - round_page(buf_len - excess);
- if (excess_pages > 0)
- return
- vm_deallocate(mach_task_self(),
- round_page(buf + buf_len - excess), excess_pages);
- else
- return 0;
-}
diff --git a/devio/mem.h b/devio/mem.h
deleted file mode 100644
index e19b590c..00000000
--- a/devio/mem.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Some random handy memory ops that know about VM.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-/* For bcopy &c. */
-#include <string.h>
-
-/* Makes sure that BUF, points to a buffer with AMOUNT bytes available.
- *BUF_LEN should be the current length of *BUF, and if this isn't enough to
- hold AMOUNT bytes, then more is allocated and the new buffer is returned
- in *BUF and *BUF_LEN. If a memory allocation error occurs, the error code
- is returned, otherwise 0. */
-error_t allocate(vm_address_t *buf, vm_size_t *buf_len, vm_size_t amount);
-
-/* Deallocates any pages entirely within the last EXCESS bytes of the BUF_LEN
- long buffer, BUF. */
-error_t deallocate_excess(vm_address_t buf, vm_size_t buf_len, vm_size_t excess);
diff --git a/devio/open.c b/devio/open.c
deleted file mode 100644
index bab4fe99..00000000
--- a/devio/open.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Per-open information for devio.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-
-#include "open.h"
-#include "window.h"
-#include "dev.h"
-
-/* ---------------------------------------------------------------- */
-
-/* Returns a new per-open structure for the device DEV in OPEN. If an error
- occurs, the error-code is returned, otherwise 0. */
-error_t
-open_create(struct dev *dev, struct open **open)
-{
- error_t err;
-
- *open = malloc(sizeof(struct open));
-
- if (*open == NULL)
- return ENOMEM;
-
- (*open)->dev = dev;
-
- err = io_state_init(&(*open)->io_state, dev);
-
- if (!err && dev_is(dev, DEV_BUFFERED) && !dev_is(dev, DEV_SERIAL))
- /* A random-access buffered device -- use a pager to do i/o to it. */
- {
- mach_port_t memobj;
- err = dev_get_memory_object(dev, &memobj);
- if (!err)
- err =
- window_create(memobj, dev->size, 0, 0, dev_is(dev, DEV_READONLY),
- &(*open)->window); /* XXX sizes */
- if (err)
- {
- mach_port_destroy(mach_task_self(), memobj);
- io_state_finalize(&(*open)->io_state);
- }
- }
- else
- (*open)->window = NULL;
-
- if (err)
- free(*open);
-
- return err;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Free OPEN and any resources it holds. */
-void
-open_free(struct open *open)
-{
- io_state_finalize(&open->io_state);
- window_free(open->window);
- free(open);
-}
-
-
-/* ---------------------------------------------------------------- */
-
-/* Returns the appropiate io_state object for OPEN (which may be either
- per-open or a per-device depending on the device). */
-struct io_state *
-open_get_io_state(struct open *open)
-{
- return
- dev_is(open->dev, DEV_SERIAL) ? &open->dev->io_state : &open->io_state;
-}
diff --git a/devio/rdwr.c b/devio/rdwr.c
deleted file mode 100644
index 67f087a0..00000000
--- a/devio/rdwr.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/* Implements various types of I/O on top of raw devices.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-#include <assert.h>
-#include <string.h>
-
-#include "open.h"
-#include "dev.h"
-#include "mem.h"
-#include "window.h"
-
-/* ---------------------------------------------------------------- */
-
-/* Writes BUF to DEV, copying through an intermediate buffer to page-align
- it. If STAGING_BUF isn't 0, it is used as the copy buffer for
- small-enough transfers (staging_buf is assumed to be one block in length).
- AMOUNT is the actual amount written, and LEN is the amount of source
- material actually in BUF; if LEN is smaller than AMOUNT, the remainder is
- zero. */
-static error_t
-copying_block_write(struct dev *dev, vm_address_t staging_buf,
- vm_address_t buf, vm_size_t len, vm_size_t amount,
- vm_offset_t *offs)
-{
- error_t err = 0;
- vm_address_t copy_buf = staging_buf;
- vm_size_t copy_buf_len = dev->block_size;
-
- if (amount > dev->block_size || staging_buf == 0)
- {
- copy_buf_len = amount;
- err = vm_allocate(mach_task_self(), &copy_buf, copy_buf_len, 1);
- if (err)
- return err;
- }
-
- bcopy((char *)buf, (char *)copy_buf, len);
- if (len < amount && copy_buf == staging_buf)
- /* We need to zero the rest of the bloc, but only if we didn't
- vm_allocate it (in which case it will be zero-filled). */
- bzero((char *)buf + len, amount - len);
-
- err = dev_write(dev, copy_buf, amount, offs);
-
- if (copy_buf != staging_buf)
- vm_deallocate(mach_task_self(), copy_buf, copy_buf_len);
-
- return err;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Copies LEN bytes from BUF to DEV, using STAGING_BUF to do buffering of
- partial blocks, and returning the amount actually written in AMOUNT.
- *OFFS is incremented to reflect the amount read/written. If an error
- occurs, the error code is returned, otherwise 0. */
-error_t
-buffered_write(struct dev *dev, vm_address_t staging_buf,
- vm_address_t buf, vm_size_t len, vm_size_t *amount,
- vm_offset_t *offs)
-{
- error_t err = 0;
- int bsize = dev->block_size;
- int staging_buf_loc = *offs % bsize;
- int left_in_staging_buf = bsize - staging_buf_loc;
- vm_offset_t start_offs = *offs;
-
- if (left_in_staging_buf > 0)
- /* Write what's buffered from the last I/O. */
- {
- /* Amount of the current i/o we can put in the staging buffer. */
- int stage = (left_in_staging_buf > len ? len : left_in_staging_buf);
-
- bcopy((char *)buf, (char *)staging_buf + staging_buf_loc, stage);
-
- buf += stage;
- len -= stage;
- *offs += stage;
-
- if (stage == left_in_staging_buf)
- /* We've filled up STAGING_BUF so we can write it out now. */
- {
- /* Backup OFFS to reflect the beginning-of-block position. */
- *offs -= bsize;
- err = dev_write(dev, staging_buf, bsize, offs);
- }
- }
-
- if (!err && len > bsize)
- /* Enough i/o pending to do whole block transfers. */
- {
- /* The number of bytes at the end of the transfer that aren't a
- multiple of the block-size. We have to deal with these separately
- because device i/o must be in block multiples. */
- int excess = len % bsize;
- vm_size_t block_len = len - excess;
-
- if (dev_write_valid(dev, buf, block_len, offs))
- /* BUF is page-aligned, so we can do i/o directly to the device, or
- it is small enough that it doesn't matter. */
- err = dev_write(dev, buf, block_len, offs);
- else
- /* Argh! BUF isn't page aligned! We must filter the i/o though an
- intermediate buffer... */
- err = copying_block_write(dev, staging_buf,
- buf, block_len, block_len, offs);
-
- if (*offs - start_offs < left_in_staging_buf + block_len)
- /* Didn't write out all the blocks, so suppress buffering the rest. */
- len = 0;
- else
- len = excess;
- }
-
- /* At this point, LEN should be < BLOCK_SIZE, so we use buffering again. */
- if (!err && len > 0)
- {
- bcopy((char *)staging_buf, (char *)buf, len);
- *offs += len;
- }
-
- *amount = *offs - start_offs;
- if (*amount > 0)
- /* If an error occurred, but we successfully wrote *something*, then
- pretend nothing bad happened; the error will probably get caught next
- time. */
- err = 0;
-
- return err;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Reads AMOUNT bytes from DEV and returns them in BUF and BUF_LEN (using the
- standard mach out-array conventions), using STAGING_BUF to do buffering of
- partial blocks. *OFFS is incremented to reflect the amount read/written.
- If an error occurs, the error code is returned, otherwise 0. */
-error_t
-buffered_read (struct dev *dev, vm_address_t staging_buf,
- vm_address_t *buf, vm_size_t *buf_len, vm_size_t amount,
- vm_offset_t *offs)
-{
- error_t err = 0;
- int bsize = dev->block_size;
- vm_offset_t start_offs = *offs;
- int staging_buf_loc = *offs % bsize;
- int from_staging_buf = bsize - staging_buf_loc;
- vm_address_t block_buf = *buf;
- vm_size_t block_buf_size = *buf_len;
- vm_size_t block_amount = amount;
-
- if (staging_buf_loc > 0)
- {
- /* Read into a temporary buffer. */
- block_buf = 0;
- block_buf_size = 0;
-
- if (from_staging_buf > amount)
- from_staging_buf = amount;
-
- block_amount -= from_staging_buf;
- }
- else
- from_staging_buf = 0;
-
- /* Read any new block required. */
- if (block_amount > 0)
- {
- /* We read enough to get every full block of BLOCK_AMOUNT, plus an
- additional whole block if there's any more; we just copy any excess
- from that last block into STAGING_BUF for next time. */
- block_amount = ((block_amount + bsize - 1) / bsize) * bsize;
-
- err = dev_read(dev, &block_buf, &block_buf_size, block_amount, offs);
- if (err && staging_buf_loc > 0)
- /* We got an error, but don't abort, since we did get the bit from
- the buffer. */
- {
- err = 0;
- amount = from_staging_buf;
- block_amount = 0;
- }
-
- if (amount > *offs - start_offs)
- /* If we read less than we hoped, reflect this down below. */
- amount = *offs - start_offs;
- }
-
- if (staging_buf_loc > 0)
- /* Coalesce what we have in STAGING_BUF with what we read. */
- {
- err = allocate(buf, buf_len, amount);
- assert_perror(err);
- bcopy((char *)staging_buf + staging_buf_loc, (char *)*buf,
- from_staging_buf);
-
- if (block_amount > 0)
- bcopy((char *)block_buf, (char *)*buf + from_staging_buf,
- amount - from_staging_buf);
- }
- else
- /* Otherwise, BLOCK_BUF should already contain the correct data. */
- {
- *buf = block_buf;
- *buf_len = block_buf_size;
- }
-
- if (*offs - start_offs > amount)
- /* We've read too far, so put some amount from the end back into
- STAGING_BUF. */
- {
- int excess = (*offs - start_offs) - amount;
-
- bcopy((char *)block_buf + amount,
- (char *)staging_buf + bsize - excess,
- excess);
- *offs -= excess;
-
- if (excess >= vm_page_size)
- deallocate_excess(*buf, *buf_len, excess);
- *buf_len -= excess;
- }
-
- /* Deallocate any extra copy buffer if necessary. */
- if (*buf != block_buf)
- vm_deallocate(mach_task_self(), block_buf, block_buf_size);
-
- return err;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Write BUF_LEN bytes from BUF to DEV, padding with zeros as necessary to
- write whole blocks, and returning the amount actually written in AMOUNT.
- If successful, 0 is returned, otherwise an error code is returned. *OFFS
- is incremented by the change in device location. */
-error_t
-raw_write(struct dev *dev,
- vm_address_t buf, vm_size_t buf_len,
- vm_size_t *amount, vm_offset_t *offs)
-{
- error_t err;
- int bsize = dev->block_size;
- int block_amount = ((buf_len + bsize - 1) / bsize) * bsize;
- vm_offset_t start_offs = *offs;
-
- if (start_offs % bsize != 0)
- return EINVAL;
-
- if (block_amount == buf_len && dev_write_valid(dev, buf, block_amount, offs))
- /* BUF is page-aligned, so we can do i/o directly to the device, or
- it is small enough that it doesn't matter. */
- err = dev_write(dev, buf, block_amount, offs);
- else
- /* Argh! BUF isn't page aligned! We must filter the i/o though an
- intermediate buffer... [We use DEV's io_state buffer, as we know
- that the io_state is locked in open_rdwr, and it isn't otherwise
- used...] */
- err = copying_block_write(dev, dev->io_state.buffer,
- buf, buf_len, block_amount, offs);
-
- if (!err && *offs - start_offs < buf_len)
- *amount = *offs - start_offs;
- else
- *amount = buf_len;
-
- return err;
-}
-
-/* Read AMOUNT bytes from DEV into BUF and BUF_LEN; only whole blocks are
- read, but anything greater than *AMOUNT bytes is discarded. The standard
- mach out-array convention is used to return the data in BUF and BUF_LEN.
- If successful, 0 is returned, otherwise an error code is returned. *OFFS
- is incremented by the change in device location. */
-error_t
-raw_read(struct dev *dev,
- vm_address_t *buf, vm_size_t *buf_len,
- vm_size_t amount, vm_offset_t *offs)
-{
- error_t err;
- int bsize = dev->block_size;
- int block_amount = ((amount + bsize - 1) / bsize) * bsize;
-
- if (*offs % bsize != 0)
- return EINVAL;
-
- err = dev_read(dev, buf, buf_len, block_amount, offs);
- if (!err)
- {
- int excess = *buf_len - amount;
- if (excess > vm_page_size)
- deallocate_excess(*buf, *buf_len, excess);
- if (excess > 0)
- *buf_len = amount;
- }
-
- return err;
-}
-
-/* ---------------------------------------------------------------- */
-
-struct rdwr_state
-{
- struct dev *dev;
- off_t user_offs;
- vm_offset_t *offs_p;
- struct io_state *io_state;
-};
-
-/* Setup state needed for I/O to/from OPEN, putting it into STATE. OFFS
- should be the original user-supplied offset. */
-static void
-rdwr_state_init(struct rdwr_state *state, struct open *open, off_t offs)
-{
- state->dev = open->dev;
- state->io_state = open_get_io_state(open);
- state->user_offs = offs;
-
- if (dev_is(state->dev, DEV_SERIAL))
- /* For serial i/o, we always ignore the proffered offs, and use the
- actual device offset. */
- state->user_offs = -1;
-
- if (state->user_offs == -1 || !dev_is(state->dev, DEV_BUFFERED))
- /* If we're going to use some bit of IO_STATE, lock it first. This
- should only not happen if we're going to used windowed i/o with an
- explicit offset. */
- io_state_lock(state->io_state);
-
- if (state->user_offs == -1)
- state->offs_p = &state->io_state->location;
- else
- state->offs_p = (vm_offset_t *)&state->user_offs;
-}
-
-/* Destroy any state created by rdwr_state_init. */
-static void
-rdwr_state_finalize(struct rdwr_state *state)
-{
- if (state->user_offs == -1 || !dev_is(state->dev, DEV_BUFFERED))
- io_state_unlock(state->io_state);
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Writes up to LEN bytes from BUF to OPEN's device at device offset OFFS
- (which may be ignored if the device doesn't support random access),
- and returns the number of bytes written in AMOUNT. If no error occurs,
- zero is returned, otherwise the error code is returned. */
-error_t
-open_write(struct open *open, vm_address_t buf, vm_size_t len,
- vm_size_t *amount, off_t offs)
-{
- error_t err;
- struct rdwr_state state;
- struct dev *dev = open->dev;
-
- rdwr_state_init(&state, open, offs);
-
- offs = *state.offs_p;
- if (offs < 0)
- err = EINVAL;
- if (offs + len > dev->size)
- err = EIO;
- else if (!dev_is(dev, DEV_BUFFERED))
- err = raw_write(dev, buf, len, amount, state.offs_p);
- else if (dev_is(dev, DEV_SERIAL))
- {
- state.io_state->buffer_use = IO_STATE_BUFFERED_WRITE;
- err = buffered_write(dev, state.io_state->buffer, buf, len,
- amount, state.offs_p);
- }
- else
- err = window_write(open->window, buf, len, amount, state.offs_p);
-
- rdwr_state_finalize(&state);
-
- return err;
-}
-
-/* Reads up to AMOUNT bytes from the device into BUF and BUF_LEN using the
- standard mach out-array convention. If no error occurs, zero is returned,
- otherwise the error code is returned. */
-error_t
-open_read(struct open *open, vm_address_t *buf, vm_size_t *buf_len,
- vm_size_t amount, off_t offs)
-{
- error_t err;
- struct rdwr_state state;
- struct dev *dev = open->dev;
-
- rdwr_state_init(&state, open, offs);
-
- offs = *state.offs_p;
- if (offs < 0)
- err = EINVAL;
- if (offs + amount > dev->size)
- err = EIO;
- else if (!dev_is(dev, DEV_BUFFERED))
- err = raw_read(dev, buf, buf_len, amount, state.offs_p);
- else if (dev_is(dev, DEV_SERIAL))
- {
- state.io_state->buffer_use = IO_STATE_BUFFERED_READ;
- err = buffered_read(dev, state.io_state->buffer, buf, buf_len,
- amount, state.offs_p);
- }
- else
- err = window_read(open->window, buf, buf_len, amount, state.offs_p);
-
- rdwr_state_finalize(&state);
-
- return err;
-}
-
-/* Set OPEN's location to OFFS, interpreted according to WHENCE as by seek.
- The new absolute location is returned in NEW_OFFS (and may not be the same
- as OFFS). If no error occurs, zero is returned, otherwise the error code
- is returned. */
-error_t
-open_seek (struct open *open, off_t offs, int whence, off_t *new_offs)
-{
- error_t err = 0;
- struct io_state *io_state = open_get_io_state (open);
-
- if (!dev_is (open->dev, DEV_SEEKABLE))
- return ESPIPE;
-
- io_state_lock (io_state);
-
- switch (whence)
- {
- case SEEK_SET:
- *new_offs = offs; break;
- case SEEK_CUR:
- *new_offs = io_state->location + offs; break;
- case SEEK_END:
- *new_offs = open->dev->size - offs; break;
- default:
- err = EINVAL;
- }
-
- if (!err)
- {
- if (!dev_is (open->dev, DEV_BUFFERED))
- /* On unbuffered devices force seeks to the nearest block boundary. */
- *new_offs -= *new_offs % open->dev->block_size;
- io_state->location = *new_offs;
- }
-
- io_state_unlock (io_state);
-
- return err;
-}
diff --git a/devio/window.c b/devio/window.c
deleted file mode 100644
index f7df045d..00000000
--- a/devio/window.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/* Window management routines for buffered I/O using VM.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-
-#include "window.h"
-#include "mem.h"
-
-/* ---------------------------------------------------------------- */
-
-/* Create a VM window onto the memory object MEMOBJ, and return it in WIN.
- MIN_SIZE and MAX_SIZE are the minimum and maximum sizes that the window
- will shrink/grow to (a value of 0 will use some default). */
-error_t
-window_create(mach_port_t memobj, vm_offset_t max_pos,
- vm_size_t min_size, vm_size_t max_size, int read_only,
- struct window **win)
-{
- *win = malloc(sizeof(struct window));
- if (*win == NULL)
- return ENOMEM;
-
- if (min_size < max_size)
- min_size = max_size;
-
- (*win)->pos = 0;
- (*win)->max_pos = max_pos;
- (*win)->size = 0;
- (*win)->memobj = memobj;
- (*win)->min_size = (min_size < vm_page_size ? vm_page_size : min_size);
- (*win)->max_size = (max_size < vm_page_size ? vm_page_size : max_size);
- (*win)->read_only = read_only;
-
- return 0;
-}
-
-/* Free WIN and any resources it holds. */
-void
-window_free(struct window *win)
-{
- if (win->size > 0)
- vm_deallocate(mach_task_self(), win->buffer, win->size);
- mach_port_destroy(mach_task_self(), win->memobj);
- free(win);
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Makes sure that WIN's memory window contains at least positions POS
- through POS + LEN on the device WIN's mapping. If an error occurs in the
- process, the error code is returned (and WIN may not map the desired
- locations), otherwise 0. WIN is assumed to already be locked when this is
- called. */
-static error_t
-position(struct window *win, vm_offset_t pos, vm_size_t len)
-{
- vm_offset_t end = pos + len;
- vm_offset_t win_beg = win->pos;
- vm_offset_t win_end = win_beg + win->size;
-
- if (pos >= win_beg && end <= win_end)
- /* The request is totally satisfied by our current position. */
- return 0;
- else
-#if 0 /* XXXXXXX */
- if (end < win_beg || pos >= win_end)
- /* The desired locations are entirely outside our current window, so just
- trash it, and map a new buffer anywhere. */
-#endif
- {
- int prot = VM_PROT_READ | (win->read_only ? 0 : VM_PROT_WRITE);
-
- if (win->size > 0)
- vm_deallocate(mach_task_self(), win->buffer, win->size);
-
- win->pos = trunc_page(pos);
- win->size = round_page(len + (pos - win->pos));
- win->buffer = 0;
-
- if (win->size < win->min_size)
- win->size = win->min_size;
-
- if (win->pos + win->size > win->max_pos)
- win->size = win->max_pos - win->pos;
-
- return
- vm_map(mach_task_self(), &win->buffer, win->size, 0, 1,
- win->memobj, win->pos, 0, prot, prot, VM_INHERIT_NONE);
- }
-
- return 0;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Write up to BUF_LEN bytes from BUF to the device that WIN is a window on,
- at offset *OFFS, using memory-mapped buffered I/O. If successful, 0 is
- returned, otherwise an error code is returned. *OFFS is incremented by
- the amount sucessfully written. */
-error_t
-window_write(struct window *win,
- vm_address_t buf, vm_size_t buf_len, vm_size_t *amount,
- vm_offset_t *offs)
-{
- error_t err;
-
- mutex_lock(&win->lock);
-
- err = position(win, *offs, buf_len);
- if (!err)
- {
- bcopy((char *)buf,
- (char *)win->buffer + (*offs - win->pos),
- buf_len);
- *amount = buf_len;
- *offs += buf_len;
- }
-
- mutex_unlock(&win->lock);
-
- return err;
-}
-
-/* Read up to AMOUNT bytes from the device that WIN is a window on, at offset
- *OFFS, into BUF and BUF_LEN (using the standard mach out-array
- conventions), using memory-mapped buffered I/O. If successful, 0 is
- returned, otherwise an error code is returned. *OFFS is incremented by
- the amount sucessfully written. */
-error_t
-window_read(struct window *win,
- vm_address_t *buf, vm_size_t *buf_len,
- vm_size_t amount, vm_offset_t *offs)
-{
- error_t err;
-
- mutex_lock(&win->lock);
-
- err = position(win, *offs, amount);
- if (!err)
- {
- err = allocate(buf, buf_len, amount);
- if (!err)
- {
- bcopy((char *)win->buffer + (*offs - win->pos),
- (char *)*buf,
- amount);
- *offs += amount;
- }
- }
-
- mutex_unlock(&win->lock);
-
- return err;
-}
diff --git a/devio/window.h b/devio/window.h
deleted file mode 100644
index c15ebd9e..00000000
--- a/devio/window.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Window management routines for buffered I/O using VM.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#ifndef __WINDOW_H__
-#define __WINDOW_H__
-
-#include <mach.h>
-
-/* ---------------------------------------------------------------- */
-
-/* A structure describing a memory window used to do buffered random access
- device i/o through the device pager. */
-struct window
-{
- /* The currently allocated vm window backed by the device pager. */
- vm_address_t buffer;
-
- /* The device offset of the window. */
- vm_offset_t pos;
- /* The end of the device. */
- vm_offset_t max_pos;
-
- /* The length of the window (should be a multiple of __vm_page_size). If
- this is 0, this window isn't allocated. */
- vm_size_t size;
- /* If SIZE < MIN_SIZE we won't shrink the window. */
- vm_size_t min_size;
- /* If SIZE > MAX_SIZE, we'll try and shrink the window to fit. */
- vm_size_t max_size;
-
- /* The device pager providing backing store for this window. */
- mach_port_t memobj;
- /* True if the mapping should be read_only. */
- int read_only;
-
- /* Lock this if you want to read/write some field(s) here. */
- struct mutex lock;
-};
-
-/* Create a VM window onto the memory object MEMOBJ, and return it in WIN.
- MIN_SIZE and MAX_SIZE are the minimum and maximum sizes that the window
- will shrink/grow to. */
-error_t window_create(mach_port_t memobj, vm_offset_t max_pos,
- vm_size_t min_size, vm_size_t max_size, int read_only,
- struct window **win);
-
-/* Free WIN and any resources it holds. */
-void window_free(struct window *win);
-
-/* Write up to BUF_LEN bytes from BUF to the device that WIN is a window on,
- at offset *OFFS, using memory-mapped buffered I/O. If successful, 0 is
- returned, otherwise an error code is returned. *OFFS is incremented by
- the amount sucessfully written. */
-error_t window_write(struct window *win,
- vm_address_t buf, vm_size_t buf_len, vm_size_t *amount,
- vm_offset_t *offs);
-
-/* Read up to AMOUNT bytes from the device that WIN is a window on, at offset
- *OFFS, into BUF and BUF_LEN (using the standard mach out-array
- conventions), using memory-mapped buffered I/O. If successful, 0 is
- returned, otherwise an error code is returned. *OFFS is incremented by
- the amount sucessfully written. */
-error_t window_read(struct window *win,
- vm_address_t *buf, vm_size_t *buf_len,
- vm_size_t amount, vm_offset_t *offs);
-
-#endif /* !__WINDOW_H__ */
diff --git a/doc/ChangeLog b/doc/ChangeLog
deleted file mode 100644
index cdf28951..00000000
--- a/doc/ChangeLog
+++ /dev/null
@@ -1,4 +0,0 @@
-Mon Aug 8 15:50:17 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
-
diff --git a/doc/Makefile b/doc/Makefile
index d92d8de4..0c00976c 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1994 Free Software Foundation
+#
+# Copyright (C) 1994, 1998, 1999, 2003 Free Software Foundation
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -18,6 +18,47 @@
dir := doc
makemode := misc
-DIST_FILES = hurd.texi
+DIST_FILES := navigating gpl.texinfo hurd.texi version.texi
+targets = hurd.info $(wildcard hurd.info-*)
+installationdir = $(infodir)
+
+DVIPS = dvips
include ../Makeconf
+
+# For each .info file we need a .d file.
+-include $(patsubst %.info,%.d,$(filter %.info,$(targets))) /dev/null
+
+# Build dependencies from included files.
+%.d: %.texi
+ set -e; (echo "$*.info $*.dvi: \\"; grep '^@include ' $< | \
+ sed -e 's/^[^ ]*[ ]*\([^ ]*\).*$$/ \1 \\/'; \
+ echo) > $@.new
+ mv -f $@.new $@
+
+%.info: %.texi
+ @rm -f $@ $@-[0-9] $@-[0-9][0-9]
+ $(MAKEINFO) -I $(@D) -I $(<D) $<
+
+.PRECIOUS: %.dvi
+%.dvi: %.texi
+ TEXINPUTS=$(srcdir):$$TEXINPUTS \
+ MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
+
+%.ps: %.dvi
+ $(DVIPS) $< -o $@
+
+move-if-change = $(SHELL) $(top_srcdir)/move-if-change
+
+version.texi: stamp-version; @:
+stamp-version: $(top_srcdir)/Makeconf
+ echo '@set VERSION $(hurd-version)' > version.texi.new
+ $(move-if-change) version.texi.new version.texi
+ touch $@
+
+# XXX: the default lndist target will try to look for target files
+# in the source directory. Special case them.
+lndist: lndist-info-targets
+lndist-info-targets: hurd.info $(wildcard hurd.info-*)
+ ln $? $(top_srcdir)/hurd-snap/$(dir)
+
diff --git a/doc/gpl.texinfo b/doc/gpl.texinfo
new file mode 100644
index 00000000..a2f8db91
--- /dev/null
+++ b/doc/gpl.texinfo
@@ -0,0 +1,396 @@
+@setfilename gpl.info
+
+@unnumbered GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and an idea of what it does.}
+Copyright (C) 19@var{yy} @var{name of author}
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'. This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c'
+for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@smallexample
+@group
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written
+by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end group
+@end smallexample
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/doc/hurd.texi b/doc/hurd.texi
index c68b8008..ea73a4c6 100644
--- a/doc/hurd.texi
+++ b/doc/hurd.texi
@@ -1,17 +1,110 @@
\input texinfo @c -*-texinfo-*-
-@setfilename hurd.texi
+@setfilename hurd.info
-@ifinfo
-@format
-START-INFO-DIR-ENTRY
-* Hurd: (hurd). The interfaces of the GNU Hurd.
-END-INFO-DIR-ENTRY
-@end format
-@end ifinfo
+@c FIXME: might it be useful to have a glossary?
+@c tb: yes, indeed. very much so. If you provide a list of words,
+@c tb: then I'll write definitions.
-@ifinfo
-Copyright @copyright{} 1994 Free Software Foundation, Inc.
+@c FIXME: Please use the active voice whenever possible. There are
+@c a lot of sentences here that use passive voice, and it's therefore
+@c hard for me to tell who is doing what to whom. I have not changed
+@c those sentences because I did not know what to make the subject and
+@c what the object.
+@c tb: can you mark the unclear sentences so I can fix them up?
+
+@c FIXME: Be consistent with mood -- that is, when writing the
+@c descriptions of functions, either write them all as declaratives (as
+@c in "This function twiddles the frobs.") or as imperatives (as in
+@c "Twiddle the frobs."). As this now stands, some function definitions
+@c are imperative (such as ports_reallocate_port: `Destroy the receive right'), and some
+@c are declarative (such as ihash_set_cleanup: `Sets @var{ht}'s element
+@c cleanup function'). This inconsistency is confusing. A particularly
+@c confusing example is the description of `pager_unlock_page': it reads
+@c `A page should be made writable.'
+@c tb: This is, I think, a consequence of many of the sections having
+@c tb: been written by cut-and-paste from the header files (which is a
+@c tb: decent way to start, but the results do need patching up).
+
+@c FIXME: Might we want to use some sort of highlighting when we
+@c refer to libraries by an abbreviated version of their name? For
+@c example, we often refer to `fshelp', by
+@c which we mean the library `libfshelp.a'. On those few occasions when
+@c we bother to spell out its full name, we use `@code', as we should;
+@c but when we abbreviate the name to `fshelp', we use no highlighting
+@c at all. These un-highlighted abbreviated names look odd to me.
+@c tb: Yes, perhaps so. We should consult a Texinfo god for advice.
+
+@c FIXME: I think we should say `zero' instead of `NULL' or `NUL'.
+@c Currently, this document uses all three, which is confusing.
+@c tb: I see no uses of "NULL". "null" is used, as an adjective,
+@c tb: which is synonymous with "zero" for pointers, but has different
+@c tb: connotations. "NUL" is an ASCII character, and is explicitly
+@c tb: used only as such.
+
+
+@c FIXME: This document sometimes says something MUST be
+@c such-and-such, and other times says something SHOULD be
+@c such-and-such. It's not clear if you're using `must' and `should'
+@c interchangeably, or if instead the really mean different things.
+@c (Similarly for `may', `do', and `does'.) Also, when we say something
+@c MUST be such-and-such, I for one always wonder `what happens if it
+@c isn't'? For example, the description of `diskfs_create_protid' says
+@c `The node @code{@var{po}->np} must be locked.' I wonder `what
+@c happens if the node isn't locked?' I imagine other programmers will
+@c wonder that too; in that case, perhaps the description should say
+@c `The node @code{@var{po}->np} must be locked; otherwise the function
+@c returns ENAUGHTY'. A particularly confusing example is the paragraph
+@c in subsection I/O Object Ports, which begins `The uid and gid sets
+@c associated with a port may not be visibly shared with other ports,
+@c nor may they ever change. The server must fix the identification of
+@c a set of uids and gids with a particular port at the moment of the
+@c port's creation.'
+@c tb: If the node is not locked on entry to diskfs_create_protid,
+@c tb: then the user (the program linking against libdiskfs) is
+@c tb: violating the interface, and the results are Undefined. The
+@c tb: resulting filesystem will experience difficult-to-trace and
+@c tb: apparently random crashes and data corruption.
+@c tb: We don't WANT such functions to have to check for and return
+@c tb: error codes any more than we want scanf to try and diagnose
+@c tb: stray pointers. But this does not mean that all things are as
+@c tb: clear as they should be, either. "must" means "if you don't do
+@c tb: this, then you are violating the interface". "should" often
+@c tb: means the same same thing, sometimes it's looser. The real
+@c tb: issue here is that we should define exactly what the
+@c tb: consequences of violating an interface are. In the case of
+@c tb: library interfaces, it means that the resulting program's
+@c tb: behavior is undefined. In the case of server interfaces, it
+@c tb: means that one has Broken The Rules and that other programs
+@c tb: will behave in correspondingly bad ways. In any case, some
+@c tb: careful auditing and editing of this kind of thing needs to
+@c tb: happen, but not until we have written more actual text.
+
+
+
+@c Get the Hurd version we are documenting.
+@include version.texi
+
+@c Unify all our little indices for now.
+@defcodeindex sc
+@syncodeindex sc cp
+@syncodeindex fn cp
+@syncodeindex vr cp
+@syncodeindex tp cp
+@syncodeindex pg cp
+
+@dircategory Kernel
+@direntry
+* Hurd: (hurd). Using and programming the Hurd kernel servers.
+@end direntry
+
+@copying
+This file documents the GNU Hurd kernel component. This edition of the
+documentation was last updated for version @value{VERSION} of the Hurd.
+
+Copyright @copyright{} 1994, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
+2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+@quotation
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@@ -31,95 +124,1466 @@ permission notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions.
-@end ifinfo
+@end quotation
+@end copying
+
+@setchapternewpage none
+@settitle Hurd Reference Manual
-@setchapternewpage odd
-@settitle Hurd Interface Manual
@titlepage
@finalout
-@title The GNU Hurd Interface Manual
-@author Michael I. Bushnell
+@title The GNU Hurd Reference Manual
+@author Thomas Bushnell, BSG
+@author Gordon Matzigkeit
@page
@vskip 0pt plus 1filll
-Copyright @copyright{} 1994 Free Software Foundation, Inc.
+@insertcopying
+@end titlepage
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-are preserved on all copies.
+@ifnottex
+@node Top
+@top The GNU Hurd
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, provided also that
-the entire resulting derived work is distributed under the terms of a
-permission notice identical to this one.
+@insertcopying
+@end ifnottex
-Permission is granted to copy and distribute translations of this manual
-into another language, under the above conditions for modified versions.
-@end titlepage
+@menu
+* Introduction:: How to use this manual.
+* Bootstrap:: Turning a computer into a Hurd machine.
+* Foundations:: Basic features used throughout the Hurd.
+* Input and Output:: Reading and writing I/O channels.
+* Files:: Regular file and directory nodes.
+* Special Files:: Files with unusual Unix-compatible semantics.
+* Stores:: Generalized units of storage.
+* Stored Filesystems:: Filesystems for physical media.
+* Twisted Filesystems:: Providing new hierarchies for existing data.
+* Distributed Filesystems:: Sharing files between separate machines.
+* Networking:: Interconnecting with other machines.
+* Terminal Handling:: Helping people interact with the Hurd.
+* Running Programs:: Program execution and process management.
+* Authentication:: Verifying user and server privileges.
+* Index:: Guide to concepts, functions, and files.
-@node Top
-@top Introduction
+@detailmenu
+ --- The Detailed Node Listing ---
+
+Introduction
+
+* Audience:: The people for whom this manual is written.
+* Features:: Reasons to install and use the Hurd.
+* Overview:: Basic architecture of the Hurd.
+* History:: How the Hurd was born.
+* Copying:: The Hurd is free software.
+
+Bootstrap
+
+* Bootloader:: Starting the microkernel, or other OSes.
+* Server Bootstrap:: Waking up the Hurd.
+* Shutdown:: Letting the Hurd get some rest.
+
+Server Bootstrap
+
+* Recursive Bootstrap:: Running a Hurd under another Hurd.
+* Boot Scripts:: Describing server bootstrap relationships.
+* Invoking boot:: How to use the boot program.
+
+Foundations
+
+* Threads Library:: Every Hurd server and library is multithreaded.
+* Ports Library:: Managing server port receive rights.
+* Integer Hash Library:: Integer-keyed hash tables.
+* Misc Library:: Things that soon will be in the GNU C library.
+* Bug Address Library:: Where to report Hurd bugs.
+
+Ports Library
+
+* Buckets and Classes:: Basic units of port organization.
+* Port Rights:: Moving port rights to and from @code{libports}.
+* Port Metadata:: Managing port-related information.
+* Port References:: Guarding against leaks and lossage.
+* RPC Management:: Locking and interrupting RPC operations.
+
+Input and Output
+
+* Iohelp Library:: I/O authentication and lock management.
+* Pager Library:: Implementing multithreaded external pagers.
+* I/O Interface:: RPC-based input/output channels.
+
+Iohelp Library
+
+* I/O Users:: User authentication management.
+* Conch Management:: Deprecated shared I/O implementation.
+
+Pager Library
+
+* Pager Management:: High-level interface to external pagers.
+* Pager Callbacks:: Functions that the user must define.
+
+I/O Interface
+
+* I/O Object Ports:: How ports to I/O objects work.
+* Simple Operations:: Read, write, and seek.
+* Open Modes:: State bits that affect pieces of operation.
+* Asynchronous I/O:: How to be notified when I/O is possible.
+* Information Queries:: How to implement @code{io_stat} and
+ @code{io_server_version}.
+* Mapped Data:: Getting memory objects referring to the
+ data of an I/O object.
+
+Files
+
+* Translators:: Extending the Hurd filesystem hierarchy.
+* Trivfs Library:: Implementing single-file translators.
+* Fshelp Library:: Miscellaneous generic filesystem routines.
+* File Interface:: File ports implement the file interface.
+* Filesystem Interface:: Translator control interface.
+
+Translators
+
+* Invoking settrans:: Declaring how a node should be translated.
+* Invoking showtrans:: Displaying how nodes are translated.
+* Invoking mount:: Unix-compatible active filesystem translators.
+* Invoking fsysopts:: Modifying translation parameters at runtime.
+
+Trivfs Library
+
+* Trivfs Startup:: Writing a simple trivfs-based translator.
+* Trivfs Callbacks:: Mandatory user-defined trivfs functions.
+* Trivfs Options:: Optional user-defined trivfs functions.
+* Trivfs Ports:: Managing control and protid ports.
+
+Fshelp Library
+
+* Passive Translator Linkage:: Invoking passive translators.
+* Active Translator Linkage:: Managing active translators.
+* Fshelp Locking:: Implementing file locking.
+* Fshelp Permissions:: Standard file access permission policies.
+* Fshelp Misc:: Useful standalone routines.
+
+File Interface
+
+* File Overview:: Basic concepts for the file interface.
+* Changing Status:: Changing the owner (etc.) of a file.
+* Program Execution:: Executing files.
+* File Locking:: Implementing the @code{flock} call.
+* File Frobbing:: Other active calls on files.
+* Opening Files:: Looking up files in directories.
+* Modifying Directories:: Creating and deleting nodes.
+* Notifications:: File and directory change callbacks.
+* File Translators:: How to set and get translators.
+
+Stores
-This manual describes the interfaces that make up the GNU Hurd. It is
-assumed that the reader is familiar with the features of the Mach
-kernel, and with using the Hurd interfaces as a user, and all of the
-associated C library calls. It concentrates on requirements and advice
-for the writing of Hurd servers, as well as describing the libraries
-that come with the GNU Hurd.
+* Store Library:: An abstract interface to storage systems.
+
+Store Library
+
+* Store Arguments:: Parsing store command-line arguments.
+* Store Management:: Creating and manipulating stores.
+* Store I/O:: Reading and writing data to stores.
+* Store Classes:: Ready-to-use storage backends.
+* Store RPC Encoding:: Transferring store descriptors via RPC.
+
+Stored Filesystems
+
+* Repairing Filesystems:: Recovering from minor filesystem crashes.
+* Linux Extended 2 FS:: The popular Linux filesystem format.
+* BSD Unix FS:: The BSD Unix 4.x Fast File System.
+* ISO-9660 CD-ROM FS:: Standard CD-ROM format.
+* Diskfs Library:: Implementing new filesystem servers.
+
+Diskfs Library
+
+* Diskfs Startup:: Initializing stored filesystems.
+* Diskfs Arguments:: Parsing command-line arguments.
+* Diskfs Globals:: Global behaviour modification.
+* Diskfs Node Management:: Allocation, reference counting, I/O,
+ caching, and other disk node routines.
+* Diskfs Callbacks:: Mandatory user-defined diskfs functions.
+* Diskfs Options:: Optional user-defined diskfs functions.
+* Diskfs Internals:: Reimplementing small pieces of diskfs.
+
+Distributed Filesystems
+
+* File Transfer Protocol:: A distributed filesystem based on FTP.
+* Network File System:: Sun's NFS: a lousy, but common filesystem.
+
+File Transfer Protocol
+
+* FTP Connection Library:: Managing remote FTP server connections.
+
+Networking
+
+* Socket Interface:: Network communication I/O protocol.
+
+Authentication
+
+* Auth Interface:: Auth ports implement the auth interface.
+
+Auth Interface
+
+* Auth Protocol:: Bidirectional authentication.
+
+@end detailmenu
+@end menu
+
+
+@node Introduction
+@chapter Introduction
+
+The GNU Hurd@footnote{The name @dfn{Hurd} stands for ``Hird of
+Unix-Replacing Daemons.'' The name @dfn{Hird} stands for ``Hurd of
+Interfaces Representing Depth.''} is the GNU Project's replacement for
+the Unix kernel. The Hurd is a collection of servers that run on the
+Mach microkernel to implement file systems, network protocols, file
+access control, and other features that are normally implemented by the
+Unix kernel or similar kernels (such as Linux).
+
+@c FIXME: Might we want to define `server' and `Mach' in a
+@c glossary, and refer to those definitions here?
@menu
-* I/O interface:: The interface for reading and writing
- I/O channels
-* Shared I/O:: The interface for doing input and output
- using shared memory
-* File interface:: The interface for modifying file-specific
- characteristics
-* Filesystem interface:: Interfaces supported to control file-servers
-* Socket interface:: Interfaces used for manipulating sockets
-
-* Ports library:: A library to manage port rights for servers
-* Iohelp library:: A library to implement some common parts
- of the I/O and shared I/O interfaces.
-* Fshelp library:: A library to implement some common parts
- of the file interface.
-* Pager library:: A library to implement complex
- multi-threaded pagers.
-* Diskfs library:: A library to do almost all the work of
- implementing a disk-based filesystem.
-* Trivfs library:: A library to do the work of handling the
- file protocol for directory-less
- filesystems.
-* Mapped data:: Getting memory objects referring to the
- data of an I/O object.
-
-@node I/O interface
-@chapter I/O interface
-
-The I/O interface is used to interact with almost all servers in the GNU
-Hurd. It provides facilities for reading and writing I/O streams. The
-I/O interface facilities are described in <hurd/io.defs> and
-<hurd/shared.h> The latter portion of <hurd/io.defs> and all of
-<hurd/shared.h> describe how to implement shared-memory I/O operations,
-and are described later. The present chapter discusses RPC-based I/O
-operations.
+* Audience:: The people for whom this manual is written.
+* Features:: Reasons to install and use the Hurd.
+* Overview:: Basic architecture of the Hurd.
+* History:: How the Hurd was born.
+* Copying:: The Hurd is free software.
+@end menu
+
+
+@node Audience
+@section Audience
+
+This manual is designed to be useful to everybody who is interested in
+using, administering, or programming the Hurd.
+
+If you are an end-user and you are looking for help on running the Hurd,
+the first few chapters of this manual describe the essential parts of
+installing, starting up, and shutting down a Hurd workstation. If you
+need help with a specific program, the best way to use this manual is to
+find the program's name in the index and go directly to the appropriate
+section. You may also wish to try running @kbd{@var{program} --help},
+which will display a brief usage message for @var{program}
+(@pxref{Foundations}).
+
+The rest of this manual is a technical discussion of the Hurd servers
+and their implementation, and would not be helpful until you want to
+learn how to modify the Hurd.
+
+This manual is organized according to the subsystems of the Hurd, and
+each chapter begins with descriptions of utilities and servers that are
+related to that subsystem. If you are a system administrator, and you
+want to learn more about, say, the Hurd networking subsystem, you can
+skip to the networking chapter (@pxref{Networking}), and read about the
+related utilities and servers.
+
+Programmers who are interested in learning how to modify Hurd servers, or
+write new ones, should begin by learning about a microkernel to which the
+Hurd has been ported (currently only GNU Mach) and reading
+@ref{Foundations}. You should then familiarize yourself with a
+subsystem that interests you by reading about existing servers and the
+libraries they use. At that point, you should be able to study the
+source code of existing Hurd servers and understand how they use the
+Hurd libraries.
+
+The final level of mastery is learning the about the RPC interfaces
+which the Hurd libraries implement. The last section of each chapter
+describes any Hurd interfaces used in that subsystem. Those sections
+assume that you are perusing the referenced interface definitions as you
+read. After you have understood a given interface, you will be in a
+good position to improve the Hurd libraries, design your own interfaces,
+and implement new subsystems.
+
+
+@node Features
+@section Features
+
+The Hurd is not the most advanced operating system known to the planet
+(yet), but it does have a number of enticing features:
+
+@table @asis
+@item it's free software
+Anybody can use, modify, and redistribute it under the terms of the GNU
+General Public License (@pxref{Copying}). The Hurd is part of the GNU
+system, which is a complete operating system licensed under the GPL.
+
+@item it's compatible
+The Hurd provides a familiar programming and user environment. For all
+intents and purposes, the Hurd is a modern Unix-like kernel. The Hurd
+uses the GNU C Library, whose development closely tracks standards such
+as ANSI/ISO, BSD, POSIX, Single Unix, SVID, and X/Open.
+
+@item it's built to survive
+Unlike other popular kernel software, the Hurd has an object-oriented
+structure that allows it to evolve without compromising its design.
+This structure will help the Hurd undergo major redesign and
+modifications without having to be entirely rewritten.
+
+@item it's scalable
+The Hurd implementation is aggressively multithreaded so that it runs
+efficiently on both single processors and symmetric multiprocessors.
+The Hurd interfaces are designed to allow transparent network clusters
+(@dfn{collectives}), although this feature has not yet been implemented.
+
+@item it's extensible
+The Hurd is an attractive platform for learning how to become a kernel
+hacker or for implementing new ideas in kernel technology. Every part
+of the system is designed to be modified and extended.
+
+@item it's stable
+It is possible to develop and test new Hurd kernel components without
+rebooting the machine (not even accidentally). Running your own kernel
+components doesn't interfere with other users, and so no special system
+privileges are required. The mechanism for kernel extensions is secure
+by design: it is impossible to impose your changes upon other users
+unless they authorize them or you are the system administrator.
+
+@item it exists
+The Hurd is real software that works Right Now. It is not a research
+project or a proposal. You don't have to wait at all before you can
+start using and developing it.
+@end table
+
+
+@node Overview
+@section Overview
+
+An operating system kernel provides a framework for programs to share a
+computer's hardware resources securely and efficiently. This framework
+includes mechanisms for programs to communicate safely, even if they do
+not trust one another (@pxref{Ports Library}).
+
+The GNU Hurd divides up the work of the traditional kernel, and
+implements it in separate programs, or @dfn{kernel servers}. The Hurd
+formally defines the communication protocols that each of the servers
+understands, so that it is possible for different servers to implement
+the same interface.
+
+The GNU C Library provides a POSIX environment on the Hurd, by
+translating standard POSIX system calls into interactions with the
+appropriate Hurd server.
+
+
+@node History
+@section History
+
+Richard Stallman (RMS) started GNU in 1983, as a project to create a
+complete free operating system. In the text of the GNU Manifesto, he
+mentioned that there is a primitive kernel. In the first GNUsletter,
+Feb. 1986, he says that GNU's kernel is TRIX, which was developed at the
+Massachusetts Institute of Technology.
+
+By December of 1986, the Free Software Foundation (FSF) had ``started
+working on the changes needed to TRIX'' [Gnusletter, Jan. 1987].
+Shortly thereafter, the FSF began ``negotiating with Professor Rashid of
+Carnegie-Mellon University about working with them on the development of
+the Mach kernel'' [Gnusletter, June, 1987]. The text implies that the
+FSF wanted to use someone else's work, rather than have to fix TRIX.
+
+In [Gnusletter, Feb. 1988], RMS was talking about taking Mach and
+putting the Berkeley Sprite filesystem on top of it, ``after the parts
+of Berkeley Unix@dots{} have been replaced.''
+
+Six months later, the FSF is saying that ``if we can't get Mach, we'll
+use TRIX or Berkeley's Sprite.'' Here, they present Sprite as a
+full-kernel option, rather than just a filesystem.
+
+In January, 1990, they say ``we aren't doing any kernel work. It does
+not make sense for us to start a kernel project now, when we still hope
+to use Mach'' [Gnusletter, Jan. 1990]. Nothing significant occurs until
+1991, when a more detailed plan is announced:
+
+@display
+``We are still interested in a multi-process kernel running on top of
+Mach. The CMU lawyers are currently deciding if they can release Mach
+with distribution conditions that will enable us to distribute it. If
+they decide to do so, then we will probably start work. CMU has
+available under the same terms as Mach a single-server partial Unix
+emulator named Poe; it is rather slow and provides minimal
+functionality. We would probably begin by extending Poe to provide full
+functionality. Later we hope to have a modular emulator divided into
+multiple processes.'' [Gnusletter, Jan. 1991].
+@end display
+
+RMS explains the relationship between the Hurd and Linux in
+@uref{http://www.gnu.org/software/hurd/hurd-and-linux.html}, where he
+mentions that the FSF started developing the Hurd in 1990. As of
+[Gnusletter, Nov. 1991], the Hurd (running on Mach) is GNU's official
+kernel.
+
+
+@node Copying
+@section GNU General Public License
+
+@include gpl.texinfo
+
+
+@node Bootstrap
+@chapter Bootstrap
+
+Bootstrapping@footnote{The term @dfn{bootstrapping} refers to a Dutch
+legend about a boy who was able to fly by pulling himself up by his
+bootstraps. In computers, this term refers to any process where a
+simple system activates a more complicated system.} is the procedure by
+which your machine loads the microkernel and transfers control to the
+Hurd servers.
+
+
+@menu
+* Bootloader:: Starting the microkernel, or other OSes.
+* Server Bootstrap:: Waking up the Hurd.
+* Shutdown:: Letting the Hurd get some rest.
+@end menu
+
+@node Bootloader
+@section Bootloader
+
+The @dfn{bootloader} is the first software that runs on your machine.
+Many hardware architectures have a very simple startup routine which
+reads a very simple bootloader from the beginning of the internal hard
+disk, then transfers control to it. Other architectures have startup
+routines which are able to understand more of the contents of the hard
+disk, and directly start a more advanced bootloader.
+
+@cindex GRUB
+@cindex GRand Unified Bootloader
+GNU @dfn{GRUB}@footnote{The GRand Unified Bootloader, available
+from @uref{http://www.gnu.org/software/grub/}.} is the GNU bootloader.
+GNU GRUB provides advanced functionality, and is capable of loading several
+different kernels (such as Linux, DOS, and the *BSD family).
+
+From the standpoint of the Hurd, the bootloader is just a mechanism to
+get the microkernel running and transfer control to the Hurd servers.
+You will need to refer to your bootloader and microkernel documentation
+for more information about the details of this process.
+
+
+@node Server Bootstrap
+@section Server Bootstrap
+
+As it can be seen from the GNU GRUB configuration, the Hurd is
+bootstrapped by starting the GNU Mach microkernel and two programs:
+the root filesystem and the exec server.
+
+The @option{--multiboot-command-line} option tells the file system server that
+it is a root filesystem, which triggers it to run @command{/hurd/init} as PID
+1. @command{/hurd/init} starts the @command{/hurd/proc} and
+@command{/hurd/auth} servers. After the servers are launched
+@command{/hurd/init} starts the @command{/libexec/runsystem.sh} script to
+finish booting.
+
+After the Hurd has been booted, other sets of core Hurd servers can be
+started in parallel. They're called sub-Hurds or neighbor Hurds
+(@pxref{Recursive Bootstrap}).
+
+@menu
+* Recursive Bootstrap:: Running a Hurd under another Hurd.
+* Boot Scripts:: Describing server bootstrap relationships.
+* Invoking boot:: How to use the boot program.
+@end menu
+
+
+@node Recursive Bootstrap
+@subsection Recursive Bootstrap
+
+The @command{boot} program can be used to start a set of core Hurd servers
+while another Hurd is already running. You will rarely need to do this,
+and it requires superuser privileges to control the new Hurd (or allow
+it to access certain devices), but it is interesting to note that it can
+be done.
+
+Usually, you would make changes to only one server, and simply tell your
+programs to use it in order to test out your changes. This process can
+be applied even to the core servers. However, some changes have
+far-reaching effects, and so it is nice to be able to test those effects
+without having to reboot the machine.
+
+@c FIXME: `boot' synopsis
+
+Here are the steps you can follow to test out a new set of servers:
+
+@enumerate 1
+@item
+Create a pseudo-root device. Usually, you would do this by creating a
+new partition under your old Hurd, and initializing it with your
+favorite filesystem format. @command{boot} understands the regular
+@code{libstore} options (FIXME xref), so you may use a file or other
+store instead of a partition.
+
+@example
+$ @kbd{dd if=/dev/zero of=my-partition bs=1024k count=400}
+400+0 records in
+400+0 records out
+$ @kbd{mke2fs ./my-partition}
+mke2fs 1.18, 11-Nov-1999 for EXT2 FS 0.5b, 95/08/09
+my-partition is not a block special device.
+Proceed anyway? (y,n) @kbd{y}
+Filesystem label=
+OS type: GNU/Hurd
+Block size=1024 (log=0)
+Fragment size=1024 (log=0)
+102400 inodes, 409600 blocks
+20480 blocks (5.00%) reserved for the super user
+First data block=1
+50 block groups
+8192 blocks per group, 8192 fragments per group
+2048 inodes per group
+Superblock backups stored on blocks:
+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409
+
+Writing inode tables: done
+Writing superblocks and filesystem accounting information: done
+$
+@end example
+
+@item
+Copy the core servers, C library, your modified programs, and anything
+else you need onto the pseudo-root.
+
+@example
+$ @kbd{settrans -c ./my-root /hurd/ext2fs -r `pwd`/my-partition}
+$ @kbd{fsysopts ./my-root --writable}
+$ @kbd{cd my-root}
+$ @kbd{tar -zxpf /pub/debian/FIXME/gnu-20000929.tar.gz}
+$ @kbd{cd ..}
+$ @kbd{fsysopts ./my-root --readonly}
+@end example
+
+@item
+Create a new boot script (FIXME xref).
+
+@item
+Run @command{boot}.
+
+@example
+$ @kbd{boot -D ./my-boot ./my-boot/boot/servers.boot ./my-partition}
+[...]
+@end example
+
+@item
+Here is an example using a hard drive that already has a GNU/Hurd
+system installed on an ext2 filesystem on @file{/dev/hd2s1}.
+
+@example
+$ @kbd{settrans /mnt /hurd/ex2fs --readonly /dev/hd2s1}
+$ @kbd{boot -d -D /mnt -I /mnt/boot/servers.boot /dev/hd2s1}
+@end example
+
+@item
+See @pxref{Invoking boot} for help with boot.
+@end enumerate
+
+Note that it is impossible to share microkernel devices between the two
+running Hurds, so don't get any funny ideas. When you're finished
+testing your new Hurd, then you can run the @command{halt} or @command{reboot}
+programs to return control to the parent Hurd.
+
+@c FIXME: the `don't get any funny ideas' comment is confusing. Am
+@c I genuinely in some sort of danger if I contemplate sharing
+@c microkernel devices between two running Hurds?
+@c tb: not if you know what you are doing. But there is no clever
+@c device mediation going on. Two hurds, with two filesystems writing
+@c the same partition, will wreak havoc. Two hurds reading from the
+@c same terminal device will not share nicely.
+
+If you're satisfied with your new Hurd, you can arrange for your
+bootloader to start it, and reboot your machine. Then, you'll be in a
+safe place to overwrite your old Hurd with the new one, and reboot back
+to your old configuration (with the new Hurd servers).
+
+
+@node Boot Scripts
+@subsection Boot Scripts
+@pindex /boot/servers.boot
+@pindex servers.boot
+
+Boot Scripts are used to boot further Hurd systems in parallel to the first,
+and are parsed by @command{boot} to boot a sub-Hurd.
+@c See @file{/boot/servers.boot} for an example of a Hurd boot script.
+
+
+In that script, the variables @var{host-port} and @var{device-port} are
+integers which represent the microkernel host and device ports, respectively
+(and are used to initialize the @code{$@{host-port@}} and
+@code{$@{device-port@}} boot script variables). If these ports are not
+specified, then it is assumed that the Hurd is already running, and the current
+ports will be fetched from the procserver.
+@c (FIXME xref).
+
+@var{root-name} is the name of the microkernel device that should be used as
+the Hurd bootstrap filesystem.
+@c @code{serverboot} uses this name
+@c to locate the boot script (described above), and to initialize the
+@c @code{$@{root-device@}} script variable.
+
+
+FIXME: finish
+
+
+@node Invoking boot
+@subsection Invoking boot
+
+Usage: boot [@var{option}@dots{}] @var{boot-script} @var{device}@dots{}
+
+@table @code
+@item --kernel-command-line=@var{command line}
+@itemx -c
+Simulated multiboot command line to supply.
+
+@item --pause
+@itemx -d
+Pause for user confirmation at various times during booting.
+
+@item --boot-root=@var{dir}
+@itemx -D
+Root of a directory tree in which to find the files specified in
+@var{boot-script}.
+
+@item --interleave=@var{blocks}
+Interleave in runs of length @var{blocks}.
+
+@item --isig
+@itemx -I
+Do not disable terminal signals, so you can suspend and interrupt the
+boot program itself, rather than the programs running in the booted
+system.
+
+@item --layer
+@itemx -L
+Layer multiple devices for redundancy.
+
+@item --single-user
+@itemx -s
+Boot into single user mode.
+
+@item --store-type=@var{type}
+@itemx -T
+Each @var{device} names a store of type @var{type}.
+@end table
+
+Mandatory or optional arguments to long options are also mandatory or optional
+for any corresponding short options.
+
+If neither @option{--interleave} or @option{--layer} is specified, multiple
+@var{device}s are concatenated.
+
+
+@node Shutdown
+@section Shutdown
+@scindex halt
+@scindex reboot
+
+FIXME: finish
+
+
+@node Foundations
+@chapter Foundations
+
+Every Hurd program accepts the following optional arguments:
+
+@table @samp
+@item --help
+Display a brief usage message, then exit. This message is not a
+substitute for reading program documentation; rather, it provides useful
+reminders about specific command-line options that a program
+understands.
+
+@item --version
+Output program version information and exit.
+@end table
+
+The rest of this chapter provides a programmer's introduction to the
+Hurd. If you are not a programmer, then this chapter will not make much
+sense to you@dots{} you should consider skipping to descriptions of
+specific Hurd programs (@pxref{Audience}).
+
+The Hurd distribution includes many libraries in order to provide a
+useful set of tools for writing Hurd utilities and servers. Several of
+these libraries are useful not only for the Hurd, but also for writing
+microkernel-based programs in general. These fundamental libraries are
+not difficult to understand, and they are a good starting point, because
+the rest of the Hurd relies upon them quite heavily.
+
+@menu
+* Threads Library:: Every Hurd server and library is multithreaded.
+* Ports Library:: Managing server port receive rights.
+* Integer Hash Library:: Integer-keyed hash tables.
+* Misc Library:: Things that soon will be in the GNU C library.
+* Bug Address Library:: Where to report Hurd bugs.
+@end menu
+
+@node Threads Library
+@section Threads Library
+@scindex libthreads
+@scindex cthreads.h
+
+All Hurd servers and libraries are aggressively multithreaded in order
+to take full advantage of any multiprocessing capabilities provided by
+the microkernel and the underlying hardware. The Hurd threads library,
+@code{libthreads}, contains the default Hurd thread implementation, which
+is declared in @code{<cthreads.h>}.
+
+Currently (April 1998), the Hurd uses cthreads, which have already been
+documented thoroughly by CMU. Eventually, it will be migrated to use
+POSIX pthreads, which are documented in a lot of places.
+@c Thomas, 26-03-1998
+
+@c FIXME: it would be nice if we referred specifically to some of
+@c the places in which POSIX pthreads are documented.
+@c tb: yes, but alas we are only allowed to refer to free
+@c documentation, and IEEE Posix ain't that... ;-(
+
+Every single library in the Hurd distribution (including the GNU C
+library) is completely thread-safe, and the Hurd servers themselves are
+aggressively multithreaded.
+
+
+@node Ports Library
+@section Ports Library
+@scindex libports
+@scindex ports.h
+
+Ports are communication channels that are held by the kernel.
+
+A port has separate send rights and receive rights, which may be
+transferred from task to task via the kernel. Port rights are similar
+to Unix file descriptors: they are per-task integers which are used to
+identify ports when making kernel calls. Send rights are required in
+order to send an RPC request down a port, and receive rights are
+required to serve the RPC request. Receive rights may be aggregated
+into a single @dfn{portset}, which serve as useful organizational units.
+
+In a single-threaded RPC client, managing and categorizing ports is not
+a difficult process. However, in a complex multithreaded server, it is
+useful to have a more abstract interface to managing portsets, as well
+as maintaining server metadata.
+
+The Hurd ports library, @code{libports}, fills that need. The
+@code{libports} functions are declared in @code{<hurd/ports.h>}.
+
+@menu
+* Buckets and Classes:: Basic units of port organization.
+* Port Rights:: Moving port rights to and from @code{libports}.
+* Port Metadata:: Managing port-related information.
+* Port References:: Guarding against leaks and lossage.
+* RPC Management:: Locking and interrupting RPC operations.
+@end menu
+
+@node Buckets and Classes
+@subsection Buckets and Classes
+
+The @code{libports} @dfn{bucket} is simply a port set, with some
+metadata and a lock. All of the @code{libports} functions operate on
+buckets.
+
+@deftypefun {struct port_bucket *} ports_create_bucket (void)
+Create and return a new, empty bucket.
+@end deftypefun
+
+A port @dfn{class} is a collection of individual ports, which can be
+manipulated conveniently, and have enforced deallocation routines.
+Buckets and classes are entirely orthogonal: there is no requirement
+that all the ports in a class be in the same bucket, nor is there a
+requirement that all the ports in a bucket be in the same class.
+
+@deftypefun {struct port_class} ports_create_class (@w{void (*@var{clean_routine}) (void *@var{port})}, @w{void (*@var{dropweak_routine}) (void *@var{port})})
+Create and return a new port class. If nonzero, @var{clean_routine}
+will be called for each allocated port object in this class when it is
+being destroyed. If nonzero, @var{dropweak_routine} will be called to
+request weak references to be dropped. (If @var{dropweak_routine} is
+null, then weak references and hard references will be identical for
+ports of this class.)
+@end deftypefun
+
+Once you have created at least one bucket and class, you may create new
+ports, and store them in those buckets. There are a few different
+functions for port creation, depending on your application's
+requirements:
+
+@deftypefun error_t ports_create_port (@w{struct port_class *@var{class}}, @w{struct port_bucket *@var{bucket}}, @w{size_t @var{size}}, @w{void *@var{result}})
+Create and return in @var{result} a new port in @var{class} and
+@var{bucket}; @var{size} bytes will be allocated to hold the port
+structure and whatever private data the user desires.
+@end deftypefun
+
+@deftypefun error_t ports_create_port_noinstall (@w{struct port_class *@var{class}}, @w{struct port_bucket *@var{bucket}}, @w{size_t @var{size}}, @w{void *@var{result}})
+Just like @code{ports_create_port}, except don't actually put the port
+into the portset underlying @var{bucket}. This is intended to be used
+for cases where the port right must be given out before the port is
+fully initialized; with this call you are guaranteed that no RPC service
+will occur on the port until you have finished initializing it and
+installed it into the portset yourself.
+@end deftypefun
+
+@deftypefun error_t ports_import_port (@w{struct port_class *@var{class}}, @w{struct port_bucket *@var{bucket}}, @w{mach_port_t @var{port}}, @w{size_t @var{size}}, @w{void *@var{result}})
+For an existing @emph{receive} right, create and return in @var{result}
+a new port structure; @var{bucket}, @var{size}, and @var{class} args are
+as for @code{ports_create_port}.
+@end deftypefun
+
+
+@node Port Rights
+@subsection Port Rights
+
+The following functions move port receive rights to and from the port
+structure:
+
+@deftypefun void ports_reallocate_port (@w{void *@var{port}})
+Destroy the receive right currently associated with @var{port} and
+allocate a new one.
+@end deftypefun
+
+@deftypefun void ports_reallocate_from_external (@w{void *@var{port}}, @w{mach_port_t @var{receive}})
+Destroy the receive right currently associated with @var{port} and
+designate @var{receive} as the new one.
+@end deftypefun
+
+@deftypefun void ports_destroy_right (@w{void *@var{port}})
+Destroy the receive right currently associated with @var{port}. After
+this call, @code{ports_reallocate_port} and
+@code{ports_reallocate_from_external} may not be used.
+@end deftypefun
+
+@deftypefun mach_port_t ports_claim_right (@w{void *@var{port}})
+Return the receive right currently associated with @var{port}. The
+effects on @var{port} are the same as in @code{ports_destroy_right},
+except that the receive right itself is not affected. Note that in
+multi-threaded servers, messages might already have been dequeued for
+this port before it gets removed from the portset; such messages will
+get @code{EOPNOTSUPP} errors.
+@end deftypefun
+
+@deftypefun error_t ports_transfer_right (@w{void *@var{topt}}, @w{void *@var{frompt}})
+Transfer the receive right from @var{frompt} to @var{topt}.
+@var{frompt} ends up with a destroyed right (as if
+@code{ports_destroy_right} were called) and @var{topt}'s old right is
+destroyed (as if @code{ports_reallocate_from_external} were called).
+@end deftypefun
+
+@deftypefun mach_port_t ports_get_right (@w{void *@var{port}})
+Return the name of the receive right associated with @var{port}. The
+user is responsible for creating an ordinary send right from this name.
+@end deftypefun
+
+
+@node Port Metadata
+@subsection Port Metadata
+
+It is important to point out that the @var{port} argument to each of
+the @code{libports} functions is a @code{void *} and not a @code{struct
+port_info *}. This is done so that you may add arbitrary
+meta-information to your @code{libports}-managed ports. Simply define
+your own structure whose first element is a @code{struct port_info}, and
+then you can use pointers to these structures as the @var{port} argument
+to any @code{libports} function.
+
+The following functions are useful for maintaining metadata that is
+stored in your own custom ports structure:
+
+@deftypefun {void *} ports_lookup_port (@w{struct port_bucket *@var{bucket}}, @w{mach_port_t @var{port}}, @w{struct port_class *@var{class}})
+Look up @var{port} and return the associated port structure, allocating
+a reference. If the call fails, return zero. If @var{bucket} is nonzero,
+then it specifies a bucket to search; otherwise all buckets will be
+searched. If @var{class} is nonzero, then the lookup will fail if
+@var{port} is not in @var{class}.
+@end deftypefun
+
+@deftypefun error_t ports_bucket_iterate (@w{struct port_bucket *@var{bucket}}, @w{error_t (*@var{fun}) (void *@var{port})})
+Call @var{fun} once for each port in @var{bucket}. No guarantee is made
+about the order of iteration, which might vary from call to call. If
+FUN returns an error, then no further calls to FUN are made for any
+remaining ports, and the return value of FUN is returned from
+ports_bucket_iterate.
+@end deftypefun
+
+@node Port References
+@subsection Port References
+
+These functions maintain references to ports so that the port
+information structures may be freed if and only if they are no longer
+needed. It is your responsibility to tell @code{libports} when
+references to ports change.
+
+@deftypefun void ports_port_ref (@w{void *@var{port}})
+Allocate a hard reference to @var{port}.
+@end deftypefun
+
+@deftypefun void ports_port_deref (@w{void *@var{port}})
+Drop a hard reference to @var{port}.
+@end deftypefun
+
+@deftypefun void ports_no_senders (@w{void *@var{port}}, @w{mach_port_mscount_t @var{mscount}})
+The user is responsible for listening for no senders notifications; when
+one arrives, call this routine for the @var{port} the message was sent
+to, providing the @var{mscount} from the notification.
+@end deftypefun
+
+@deftypefun int ports_count_class (@w{struct port_class *@var{class}})
+Block creation of new ports in @var{class}. Return the number of ports
+currently in @var{class}.
+@end deftypefun
+
+@deftypefun int ports_count_bucket (@w{struct port_bucket *@var{bucket}})
+Block creation of new ports in @var{bucket}. Return the number of ports
+currently in @var{bucket}.
+@end deftypefun
+
+@deftypefun void ports_enable_class (@w{struct port_class *@var{class}})
+Permit suspended port creation (blocked by @code{ports_count_class}) to
+continue.
+@end deftypefun
+
+@deftypefun void ports_enable_bucket (@w{struct port_bucket *@var{bucket}})
+Permit suspended port creation (blocked by @code{ports_count_bucket}) to
+continue.
+@end deftypefun
+
+Weak references are not often used, as they are the same as hard
+references for port classes where @var{dropweak_routine} is null.
+@xref{Buckets and Classes}.
+
+@deftypefun void ports_port_ref_weak (@w{void *@var{port}})
+Allocate a weak reference to @var{port}.
+@end deftypefun
+
+@deftypefun void ports_port_deref_weak (@w{void *@var{port}})
+Drop a weak reference to @var{port}.
+@end deftypefun
+
+
+@node RPC Management
+@subsection RPC Management
+
+The rest of the @code{libports} functions are dedicated to controlling
+RPC operations. These functions help you do all the locking and thread
+cancellations that are required in order to build robust servers.
+
+@deftypefn {Typedef} typedef int (*ports_demuxer_type) (@w{mach_msg_header_t *@var{inp}}, @w{mach_msg_header_t *@var{outp}})
+Type of MiG demuxer routines.
+@end deftypefn
+
+@c FIXME: Should I know what `MiG' means?
+@c tb: Yeah, it's the Mach Interface Generator.
+
+@deftypefun error_t ports_begin_rpc (@w{void *@var{port}}, @w{mach_msg_id_t @var{msg_id}}, @w{struct rpc_info *@var{info}})
+Call this when an RPC is beginning on @var{port}. @var{info} should be
+allocated by the caller and will be used to hold dynamic state. If this
+RPC should be abandoned, return @code{EDIED}; otherwise we return zero.
+@end deftypefun
+
+@deftypefun void ports_end_rpc (@w{void *@var{port}}, @w{struct rpc_info *@var{info}})
+Call this when an RPC is concluding. The arguments must match the ones
+passed to the paired call to @code{ports_begin_rpc}.
+@end deftypefun
+
+@deftypefun void ports_manage_port_operations_one_thread (@w{struct port_bucket *@var{bucket}}, @w{ports_demuxer_type @var{demuxer}}, @w{int @var{timeout}})
+Begin handling operations for the ports in @var{bucket}, calling
+@var{demuxer} for each incoming message. Return if @var{timeout} is
+nonzero and no messages have been received for @var{timeout}
+milliseconds. Use only one thread (the calling thread).
+@end deftypefun
+
+@deftypefun void ports_manage_port_operations_multithread (@w{struct port_bucket *@var{bucket}}, @w{ports_demuxer_type @var{demuxer}}, @w{int @var{thread_timeout}}, @w{int @var{global_timeout}}, @w{void (*@var{hook}) (void)})
+Begin handling operations for the ports in @var{bucket}, calling
+@var{demuxer} for each incoming message. Return if @var{global_timeout}
+is nonzero and no messages have been received for @var{global_timeout}
+milliseconds. Create threads as necessary to handle incoming messages
+so that no port is starved because of sluggishness on another port. If
+@var{thread_timeout} is nonzero, then individual threads will die off
+if they handle no incoming messages for @var{local_timeout}
+milliseconds. If non-null, @var{hook} will be called in each new thread
+immediately after it is created.
+@end deftypefun
+
+@deftypefun error_t ports_inhibit_port_rpcs (@w{void *@var{port}})
+Interrupt any pending RPC on @var{port}. Wait for all pending RPCs to
+finish, and then block any new RPCs starting on that port.
+@end deftypefun
+
+@deftypefun error_t ports_inhibit_class_rpcs (@w{struct port_class *@var{class}})
+Similar to @code{ports_inhibit_port_rpcs}, but affects all ports in
+@var{class}.
+@end deftypefun
+
+@deftypefun error_t ports_inhibit_bucket_rpcs (@w{struct port_bucket *@var{bucket}})
+Similar to @code{ports_inhibit_port_rpcs}, but affects all ports in
+@var{bucket}.
+@end deftypefun
+
+@deftypefun error_t ports_inhibit_all_rpcs (void)
+Similar to @code{ports_inhibit_port_rpcs}, but affects all ports
+whatsoever.
+@end deftypefun
+
+@deftypefun void ports_resume_port_rpcs (@w{void *@var{port}})
+Reverse the effect of a previous @code{ports_inhibit_port_rpcs} for this
+@var{port}, allowing blocked RPCs to continue.
+@end deftypefun
+
+@deftypefun void ports_resume_class_rpcs (@w{struct port_class *@var{class}})
+Reverse the effect of a previous @code{ports_inhibit_class_rpcs} for
+@var{class}.
+@end deftypefun
+
+@deftypefun void ports_resume_bucket_rpcs (@w{struct port_bucket *@var{bucket}})
+Reverse the effect of a previous @code{ports_inhibit_bucket_rpcs} for
+@var{bucket}.
+@end deftypefun
+
+@deftypefun void ports_resume_all_rpcs (void)
+Reverse the effect of a previous @code{ports_inhibit_all_rpcs}.
+@end deftypefun
+
+@deftypefun void ports_interrupt_rpcs (@w{void *@var{port}})
+Cancel (with @code{thread_cancel}) any RPCs in progress on @var{port}.
+@end deftypefun
+
+@deftypefun int ports_self_interrupted (void)
+If the current thread's RPC has been interrupted with
+@code{ports_interrupt_rpcs}, return nonzero and clear the interrupted
+flag.
+@end deftypefun
+
+@deftypefun error_t ports_interrupt_rpc_on_notification (@w{void *@var{object}}, @w{struct rpc_info *@var{rpc}}, @w{mach_port_t @var{port}}, @w{mach_msg_id_t @var{what}})
+Arrange for @code{hurd_cancel} to be called on @var{rpc}'s thread if
+@var{object} gets notified that any of the things in @var{what} have
+happened to @var{port}. @var{rpc} should be an RPC on @var{object}.
+@end deftypefun
+
+@deftypefun error_t ports_interrupt_self_on_notification (@w{void *@var{object}}, @w{mach_port_t @var{port}}, @w{mach_msg_id_t @var{what}})
+Arrange for @code{hurd_cancel} to be called on the current thread, which
+should be an RPC on @var{object}, if @var{port} gets notified with the
+condition @var{what}.
+@end deftypefun
+
+@deftypefun error_t ports_interrupt_self_on_port_death (@w{void *@var{object}}, @w{mach_port_t @var{port}})
+Same as calling @code{ports_interrupt_self_on_notification} with
+@var{what} set to @code{MACH_NOTIFY_DEAD_NAME}.
+@end deftypefun
+
+@deftypefun void ports_interrupt_notified_rpcs (@w{void *@var{object}}, @w{mach_port_t @var{port}}, @w{mach_msg_id_t @var{what}})
+Interrupt any RPCs on @var{object} that have requested such.
+@end deftypefun
+
+@deftypefun void ports_dead_name (@w{void *@var{object}}, @w{mach_port_t @var{port}})
+Same as calling @code{ports_interrupt_notified_rpcs} with @var{what} set
+to @code{MACH_NOTIFY_DEAD_NAME}.
+@end deftypefun
+
+
+@node Integer Hash Library
+@section Integer Hash Library
+@scindex libihash
+@scindex ihash.h
+
+@code{libihash} provides integer-keyed hash tables, for arbitrary
+element data types. Such hash tables are frequently used when
+implementing sparse arrays or buffer caches.
+
+The following functions are declared in @code{<hurd/ihash.h>}:
+
+@deftypefun error_t ihash_create (@w{ihash_t *@var{ht}})
+Create an integer hash table and return it in @var{ht}. If a memory
+allocation error occurs, @code{ENOMEM} is returned, otherwise zero.
+@end deftypefun
+
+@deftypefun void ihash_free (@w{ihash_t @var{ht}})
+Free @var{ht} and all resources it consumes.
+@end deftypefun
+
+@deftypefun void ihash_set_cleanup (@w{ihash_t @var{ht}}, @w{void (*@var{cleanup}) (void *@var{value}, void *@var{arg})}, @w{void *@var{arg}})
+Sets @var{ht}'s element cleanup function to @var{cleanup}, and its
+second argument to @var{arg}. @var{cleanup} will be called on every
+element @var{value} to be subsequently overwritten or deleted, with
+@var{arg} as the second argument.
+@end deftypefun
+
+@deftypefun error_t ihash_add (@w{ihash_t @var{ht}}, @w{int @var{id}}, @w{void *@var{item}}, @w{void ***@var{locp}})
+Add @var{item} to the hash table @var{ht} under the integer key
+@var{id}. @var{locp} is the address of a pointer located in @var{item};
+If non-null, @var{locp} should point to a variable of type @code{void
+**}, and will be filled with a pointer that may be used as an argument
+to @code{ihash_locp_remove}. The variable pointed to by @var{locp} may
+be overwritten sometime between this call and when the element is
+deleted, so you cannot stash its value elsewhere and hope to use the
+stashed value with @code{ihash_locp_remove}. If a memory allocation
+error occurs, @code{ENOMEM} is returned, otherwise zero.
+@end deftypefun
+
+@deftypefun {void *} ihash_find (@w{ihash_t @var{ht}}, @w{int @var{id}})
+Find and return the item in hash table @var{ht} with key @var{id}.
+Returns null if the specified item doesn't exist.
+@end deftypefun
+
+@deftypefun error_t ihash_iterate (@w{ihash_t @var{ht}}, @w{error_t (*@var{fun}) (void *@var{value})})
+Call function @var{fun} on every element of @var{ht}. @var{fun}'s only
+arg, @var{value}, is a pointer to the value stored in the hash table. If
+@var{fun} ever returns nonzero, then iteration stops and
+@code{ihash_iterate} returns that value, otherwise it (eventually)
+returns 0.
+@end deftypefun
+
+@deftypefun int ihash_remove (@w{ihash_t @var{ht}}, @w{int @var{id}})
+Remove the entry with a key of @var{id} from @var{ht}. If there was no
+such element, then return zero, otherwise nonzero.
+@end deftypefun
+
+@deftypefun void ihash_locp_remove (@w{ihash_t @var{ht}}, @w{void **@var{ht_locp}})
+Remove the entry at @var{locp} from the hashtable @var{ht}. @var{locp}
+is as returned from an earlier call to @code{ihash_add}. This call
+should be faster than @code{ihash_remove}. @var{ht} can be null, in
+which case the call still succeeds, but no cleanup is done.
+@end deftypefun
+
+
+@node Misc Library
+@section Misc Library
+@scindex libshouldbeinlibc
+
+The GNU C library is constantly developing to meet the needs of the
+Hurd. However, because the C library needs to be very stable, it is
+irresponsible to add new functions to it without carefully specifying
+their interface, and testing them thoroughly.
+
+The Hurd distribution includes a library called
+@code{libshouldbeinlibc}, which serves as a proving ground for additions
+to the GNU C library. This library is in flux, as some functions are
+added to it by the Hurd developers and others are moved to the official
+C library.
+
+These functions aren't currently documented (other than in their header
+files), but complete documentation will be added to
+@iftex
+@emph{The GNU C Library Reference Manual}
+@end iftex
+@ifinfo
+@ref{Top, The GNU C Library Reference Manual,, libc},
+@end ifinfo
+when these functions become part of the GNU C library.
+
+
+@node Bug Address Library
+@section Bug Address Library
+@scindex libhurdbugaddr
+
+@code{libhurdbugaddr} exists only to define a single variable:
+
+@deftypevar {char *} argp_program_bug_address
+@code{argp_program_bug_address} is the default Hurd bug-reporting e-mail
+address, @email{bug-hurd@@gnu.org}. This address is displayed to the
+user when any of the standard Hurd servers and utilities are invoked
+using the @samp{--help} option.
+@end deftypevar
+
+
+@node Input and Output
+@chapter Input and Output
+
+There are no specific programs or servers associated with the I/O
+subsystem, since it is used to interact with almost all servers in the
+GNU Hurd. It provides facilities for reading and writing I/O channels,
+which are the underlying implementation of file and socket descriptors
+in the GNU C library.
@menu
-* I/O object ports:: How ports to I/O objects work
-* Simple operations:: Read, write, and seek
-* Open modes:: State bits that affect pieces of
- operation
-* Asynchronous I/O:: How to get notified when I/O is possible
-* Information queries:: How to implement io_stat and
- io_server_version
+* Iohelp Library:: I/O authentication and lock management.
+* Pager Library:: Implementing multithreaded external pagers.
+* I/O Interface:: RPC-based input/output channels.
@end menu
-@node I/O object ports
-@section I/O object ports
+@node Iohelp Library
+@section Iohelp Library
+@scindex libiohelp
+@scindex iohelp.h
+
+The @code{<hurd/iohelp.h>} file declares several functions which are
+useful for low-level I/O implementations. Most Hurd servers do not call
+these functions directly, but they are used by several of the Hurd
+filesystem and networking helper libraries. @code{libiohelp} requires
+@code{libthreads}.
+
+@menu
+* I/O Users:: User authentication management.
+* Conch Management:: Deprecated shared I/O implementation.
+@end menu
+
+@node I/O Users
+@subsection I/O Users
+
+Most I/O servers need to implement some kind of user authentication
+checking. In order to facilitate that process, @code{libiohelp} has
+some functions which encapsulate a set of idvecs (FIXME: xref to C
+library) in a single @code{struct iouser}.
+
+@deftypefun {struct iouser *} iohelp_create_iouser (@w{struct idvec *@var{uids}}, @w{struct idvec *@var{gids}})
+Create a new @var{iouser} for the specified @var{uids} and @var{gids}.
+@end deftypefun
+
+@deftypefun {struct iouser *} iohelp_dup_iouser (@w{struct iouser *@var{iouser}})
+Return a copy of @var{iouser}.
+@end deftypefun
+
+@deftypefun void iohelp_free_iouser (@w{struct iouser *@var{iouser}})
+Release a reference to @var{iouser}.
+@end deftypefun
+
+I/O reauthentication is a rather complex protocol involving the
+authserver as a trusted third party (@pxref{Auth Protocol}). In order
+to reduce the risk of flawed implementations, I/O reauthentication is
+encapsulated in the @code{iohelp_reauth} function:
+
+@deftypefun {struct iouser *} iohelp_reauth (@w{auth_t @var{authserver}}, @w{mach_port_t @var{rend_port}}, @w{mach_port_t @var{newright}}, @w{int @var{permit_failure}})
+Conduct a reauthentication transaction, and return a new @var{iouser}.
+@var{authserver} is the I/O server's auth port. The rendezvous port
+provided by the user is @var{rend_port}.
+
+If the transaction cannot be completed, return zero, unless
+@var{permit_failure} is nonzero. If @var{permit_failure} is nonzero,
+then should the transaction fail, return an @var{iouser} that has no
+ids. The new port to be sent to the user is @var{newright}.
+@end deftypefun
+
+
+@node Conch Management
+@subsection Conch Management
+
+@cindex conch
+@findex iohelp_initialize_conch
+@findex iohelp_handle_io_get_conch
+@findex iohelp_get_conch
+@findex iohelp_handle_io_release_conch
+@findex iohelp_verify_user_conch
+@findex iohelp_fetch_shared_data
+@findex iohelp_put_shared_data
+The @dfn{conch} is at the heart of the shared memory I/O system.
+Several Hurd libraries implement shared I/O, and so @code{libiohelp}
+contains functions to facilitate conch management.
+
+Everything about shared I/O is undocumented because it is not needed for
+adequate performance, and the RPC interface is simpler (@pxref{I/O
+Interface}). It is not useful for new libraries or servers to implement
+shared I/O.
+
+
+@node Pager Library
+@section Pager Library
+@scindex libpager
+@scindex pager.h
+
+@cindex XP (external pager)
+@cindex external pager (XP)
+The @dfn{external pager} (@dfn{XP}) microkernel interface allows
+applications to provide the backing store for a memory object, by
+converting hardware page faults into RPC requests. External pagers are
+required for memory-mapped I/O (@pxref{Mapped Data}) and stored
+filesystems (@pxref{Stored Filesystems}).
+
+The external pager interface is quite complex, so the Hurd pager library
+contains functions which aid in creating multithreaded external pagers.
+@code{libpager} is declared in @code{<hurd/pager.h>}, and requires only
+the threads and ports libraries.
+
+@menu
+* Pager Management:: High-level interface to external pagers.
+* Pager Callbacks:: Functions that the user must define.
+@end menu
+
+
+@node Pager Management
+@subsection Pager Management
+
+The pager library defines the @code{struct pager} data type in order to
+represent a multi-threaded pager. The general procedure for creating a
+pager is to define the functions listed in @ref{Pager Callbacks},
+allocate a @code{libports} bucket for the ports which will access the
+pager, and create at least one new @code{struct pager} with
+@code{pager_create}.
+
+@deftypefun {struct pager *} pager_create (@w{struct user_pager_info *@var{u_pager}}, @w{struct port_bucket *@var{bucket}}, @w{boolean_t @var{may_cache}}, @w{memory_object_copy_strategy_t @var{copy_strategy}})
+Create a new pager. The pager will have a port created for it (using
+@code{libports}, in @var{bucket}) and will be immediately ready to
+receive requests. @var{u_pager} will be provided to later calls to
+@code{pager_find_address}. The pager will have one user reference
+created. @var{may_cache} and @var{copy_strategy} are the original
+values of those attributes as for @code{memory_object_ready}. Users may
+create references to pagers by use of the relevant ports library
+functions. On errors, return null and set @code{errno}.
+@end deftypefun
+
+Once you are ready to turn over control to the pager library, you should
+call @code{ports_manage_port_operations_multithread} on the
+@var{bucket}, using @code{pager_demuxer} as the ports @var{demuxer}.
+This will handle all external pager RPCs, invoking your pager callbacks
+when necessary.
+
+@deftypefun int pager_demuxer (@w{mach_msg_header_t *@var{inp}}, @w{mach_msg_header_t *@var{outp}})
+Demultiplex incoming @code{libports} messages on pager ports.
+@end deftypefun
+
+The following functions are the body of the pager library, and provide a
+clean interface to pager functionality:
+
+@deftypefun void pager_sync (@w{struct pager *@var{pager}}, @w{int @var{wait}})
+@deftypefunx void pager_sync_some (@w{struct pager *@var{pager}}, @w{vm_address_t @var{start}}, @w{vm_size_t @var{len}}, @w{int @var{wait}})
+Write data from pager @var{pager} to its backing store. Wait for all
+the writes to complete if and only if @var{wait} is set.
+
+@code{pager_sync} writes all data; @code{pager_sync_some} only writes
+data starting at @var{start}, for @var{len} bytes.
+@end deftypefun
+
+@deftypefun void pager_flush (@w{struct pager *@var{pager}}, @w{int @var{wait}})
+@deftypefunx void pager_flush_some (@w{struct pager *@var{pager}}, @w{vm_address_t @var{start}}, @w{vm_size_t @var{len}}, @w{int @var{wait}})
+Flush data from the kernel for pager @var{pager} and force any pending
+delayed copies. Wait for all pages to be flushed if and only if
+@var{wait} is set.
+
+@code{pager_flush} flushes all data; @code{pager_flush_some} only
+flushes data starting at @var{start}, for @var{len} bytes.
+@end deftypefun
+
+@deftypefun void pager_return (@w{struct pager *@var{pager}}, @w{int @var{wait}})
+@deftypefunx void pager_return_some (@w{struct pager *@var{pager}}, @w{vm_address_t @var{start}}, @w{vm_size_t @var{len}}, @w{int @var{wait}})
+Flush data from the kernel for pager @var{pager} and force any pending
+delayed copies. Wait for all pages to be flushed if and only if
+@var{wait} is set. Have the kernel write back modifications.
+
+@code{pager_return} flushes and restores all data;
+@code{pager_return_some} only flushes and restores data starting at
+@var{start}, for @var{len} bytes.
+@end deftypefun
+
+@deftypefun void pager_offer_page (@w{struct pager *@var{pager}}, @w{int @var{precious}}, @w{int @var{writelock}}, @w{vm_offset_t @var{page}}, @w{vm_address_t @var{buf}})
+Offer a page of data to the kernel. If @var{precious} is set, then this
+page will be paged out at some future point, otherwise it might be
+dropped by the kernel. If the page is currently in core, the kernel
+might ignore this call.
+@end deftypefun
+
+attributes@deftypefun void pager_change_attributes (@w{struct pager *@var{pager}}, @w{boolean_t @var{may_cache}}, @w{memory_object_copy_strategy_t @var{copy_strategy}}, @w{int @var{wait}})
+Change the attributes of the memory object underlying pager @var{pager}.
+The @var{may_cache} and @var{copy_strategy} arguments are as for
+@code{memory_object_change_}. Wait for the kernel to report
+completion if and only if @var{wait} is set.
+@end deftypefun
+
+@deftypefun void pager_shutdown (@w{struct pager *@var{pager}})
+Force termination of a pager. After this returns, no more paging
+requests on the pager will be honoured, and the pager will be
+deallocated. The actual deallocation might occur asynchronously if
+there are currently outstanding paging requests that will complete
+first.
+@end deftypefun
+
+@deftypefun error_t pager_get_error (@w{struct pager *@var{p}}, @w{vm_address_t @var{addr}})
+Return the error code of the last page error for pager @var{p} at
+address @var{addr}.@footnote{Note that this function will be deleted
+when the Mach pager interface is fixed to provide this information.}
+@end deftypefun
+
+@deftypefun error_t pager_memcpy (@w{struct pager *@var{pager}}, @w{memory_object_t @var{memobj}}, @w{vm_offset_t @var{offset}}, @w{void *@var{other}}, @w{size_t *@var{size}}, @w{vm_prot_t @var{prot}})
+Try to copy @code{*@var{size}} bytes between the region @var{other}
+points to and the region at @var{offset} in the pager indicated by
+@var{pager} and @var{memobj}. If @var{prot} is @code{VM_PROT_READ},
+copying is from the pager to @var{other}; if @var{prot} contains
+@code{VM_PROT_WRITE}, copying is from @var{other} into the pager.
+@code{*@var{size}} is always filled in with the actual number of bytes
+successfully copied. Returns an error code if the pager-backed memory
+faults; if there is no fault, returns zero and @code{*@var{size}} will
+be unchanged.
+@end deftypefun
+
+These functions allow you to recover the internal @code{struct pager}
+state, in case the @code{libpager} interface doesn't provide an
+operation you need:
+
+@deftypefun {struct user_pager_info *} pager_get_upi (@w{struct pager *@var{p}})
+Return the @code{struct user_pager_info} associated with a pager.
+@end deftypefun
+
+@deftypefun mach_port_t pager_get_port (@w{struct pager *@var{pager}})
+Return the port (receive right) for requests to the pager. It is
+absolutely necessary that a new send right be created from this receive
+right.
+@end deftypefun
+
+
+@node Pager Callbacks
+@subsection Pager Callbacks
+
+Like several other Hurd libraries, @code{libpager} depends on you to
+implement application-specific callback functions. You @emph{must}
+define the following functions:
+
+@deftypefun error_t pager_read_page (@w{struct user_pager_info *@var{pager}}, @w{vm_offset_t @var{page}}, @w{vm_address_t *@var{buf}}, @w{int *@var{write_lock}})
+For pager @var{pager}, read one page from offset @var{page}. Set
+@code{*@var{buf}} to be the address of the page, and set
+@code{*@var{write_lock}} if the page must be provided read-only. The
+only permissible error returns are @code{EIO}, @code{EDQUOT}, and
+@code{ENOSPC}.
+@end deftypefun
+
+@deftypefun error_t pager_write_page (@w{struct user_pager_info *@var{pager}}, @w{vm_offset_t @var{page}}, @w{vm_address_t @var{buf}})
+For pager @var{pager}, synchronously write one page from @var{buf} to
+offset @var{page}. In addition, @code{vm_deallocate} (or equivalent)
+@var{buf}. The only permissible error returns are @code{EIO},
+@code{EDQUOT}, and @code{ENOSPC}.
+@end deftypefun
+
+@deftypefun error_t pager_unlock_page (@w{struct user_pager_info *@var{pager}}, @w{vm_offset_t @var{address}})
+A page should be made writable.
+@end deftypefun
+
+@deftypefun error_t pager_report_extent (@w{struct user_pager_info *@var{pager}}, @w{vm_address_t *@var{offset}}, @w{vm_size_t *@var{size}})
+This function should report in @code{*@var{offset}} and
+@code{*@var{size}} the minimum valid address the pager will accept and
+the size of the object.
+@end deftypefun
+
+@deftypefun void pager_clear_user_data (@w{struct user_pager_info *@var{pager}})
+This is called when a pager is being deallocated after all extant send
+rights have been destroyed.
+@end deftypefun
+
+@deftypefun void pager_dropweak (@w{struct user_pager_info *@var{p}})
+This will be called when the ports library wants to drop weak
+references. The pager library creates no weak references itself, so if
+the user doesn't either, then it is all right for this function to do
+nothing.
+@end deftypefun
+
+
+@node I/O Interface
+@section I/O Interface
+@scindex io.defs
+
+The I/O interface facilities are described in @code{<hurd/io.defs>}.
+This section discusses only RPC-based I/O operations.@footnote{The
+latter portion of @code{<hurd/io.defs>} and all of
+@code{<hurd/shared.h>} describe how to implement shared-memory I/O
+operations. However, shared I/O has been deprecated. @xref{Conch
+Management}, for more details.}
+
+@menu
+* I/O Object Ports:: How ports to I/O objects work.
+* Simple Operations:: Read, write, and seek.
+* Open Modes:: State bits that affect pieces of operation.
+* Asynchronous I/O:: How to be notified when I/O is possible.
+* Information Queries:: How to implement @code{io_stat} and
+ @code{io_server_version}.
+* Mapped Data:: Getting memory objects referring to the
+ data of an I/O object.
+@end menu
+
+@node I/O Object Ports
+@subsection I/O Object Ports
The I/O server must associate each I/O port with a particular set of
uids and gids, identifying the user who is responsible for operations on
the port. Every port to an I/O server should also support either the
-file protocol or the socket protocol; naked I/O ports are not allowed.
+file protocol (@pxref{File Interface}) or the socket protocol
+(@pxref{Socket Interface}); naked I/O ports are not allowed.
In addition, the server associates with each port a default file
pointer, a set of open mode bits, a pid (called the ``owner''), and some
@@ -131,481 +1595,3052 @@ with other ports, nor may they ever change. The server must fix the
identification of a set of uids and gids with a particular port at the
moment of the port's creation. The other characteristics of an I/O port
may be shared with other users. The I/O server interface does not
-generally specify in what way servers may share these other
-characteristics are shared (with the exception of the deprecated O_ASYNC
-interface); however, the file and socket interfaces make further
-requirements about what sharing is expected and prohibited from
-occurring.
-
-In general, users get send-rights to I/O ports by some mechanism that is
-external to the I/O protocol. (For example file servers give out I/O
-ports in response to the dir_pathtrans and fsys_getroot calls. Socket
-servers give out ports in response to the socket_create and
-socket_accept calles.) However, the I/O protocol provides methods of
-obtaining new ports that refer to the same underlying object as another
-port. In response to all of these calls, all underlying state
-(including, but not limited to, the default file poirter, open mode
-bits, and underlying object) must be shared between the old and new
-ports. In the following descriptions of these calls, the term
-"identical" means this kind of sharing. All these calls must return
-send-rights to a newly-constructed Mach port.
-
-The io_duplicate call simply returns another port which is identical
-to an existing port and has the same uid and gid set.
-
-The io_restrict_auth call returns another port, identical to the
+generally specify the way in which servers may share these other
+characteristics (with the exception of the deprecated
+@code{O_ASYNC} interface); however, the file and socket interfaces make
+further requirements about what sharing is required and what sharing is prohibited.
+
+In general, users get send rights to I/O ports by some mechanism that is
+external to the I/O protocol. (For example, fileservers give out I/O
+ports in response to the @code{dir_lookup} and @code{fsys_getroot}
+calls. Socket servers give out ports in response to the
+@code{socket_create} and @code{socket_accept} calls.) However, the I/O
+protocol provides methods of obtaining new ports that refer to the same
+underlying object as another port. In response to all of these calls,
+all underlying state (including, but not limited to, the default file
+pointer, open mode bits, and underlying object) must be shared between
+the old and new ports. In the following descriptions of these calls,
+the term ``identical'' means this kind of sharing. All these calls must
+return send rights to a newly-constructed Mach port.
+
+@c FIXME: should be say `Mach' above, or should we say
+@c `microkernel'?
+@c tb: We say Mach. Other kernels might have different rules, and we
+@c should document what we have now.
+
+@findex io_duplicate
+The @code{io_duplicate} call simply returns another port which is
+identical to an existing port and has the same uid and gid set.
+
+@findex io_restrict_auth
+The @code{io_restrict_auth} call returns another port, identical to the
provided port, but which has a smaller associated uid and gid set. The
uid and gid sets of the new port are the intersection of the set on the
existing port and the lists of uids and gids provided in the call.
-Users use the io_reauthenticate call when they wish to have an entirely
-new set of uids or gids associated with a port. In response to the
-io_reauthenticate call, the server must create a new port, and then make
-the call auth_server_authenticate to the auth server. The rendezvous
-port for the auth_server_authenticate call is the I/O port to which was
-made the io_reauthenticate call. The server provides rend_int parameter
-to the auth server as a copy from the corresponding parameter in the
-io_reauthenticate call. The I/O server also gives the auth server a new
-port; this must be a newly created port identical to the old port. The
-auth server will return the set of uids and gids associated with the
-user, and guarantees that the new port will go directly to the user that
-possessed the associated authentication port. The server then
-identifies the new port given out with the specified id's.
-
-@node Simple operations
-@section Simple operations
-
-Users write to I/O ports by calling the io_write RPC. They specify an
-offset parameter; if the object supports writing at arbitrary offsets,
-the server should honor this parameter. If -1 is passed as the offset,
-then the server should use the default file pointer. The server should
-return the amount of data which was successfully written. If the
-operation was interrupted after some but not all of the data was
-written, then it is considered to have succeeded and the server should
-return the amount written. If the port is not an I/O port at all, the
-server should reply with the error EOPNOTSUPP. If the port is an I/O
-port, but does not happen to support writing, then the correct error is
-EBADF.
-
-Users read from I/O ports by calling the io_read RPC. The specify the
-amount of data they wish to read and the offset. The offset has the
-same meaning as for io_write above. The server should return the data
-read. If the call is interrupted after same data has been read (and the
-operation is not idempotent) then the server should return the amount
-read, even if less than the amount requested. The server should return
-as much data as possible, but never more than requested by the user. If
-there is no data, but there might be later, the call should block until
-data becomes available. Indicate end-of-file conditions by returning
-zero bytes. If the call is interrupted after some data has been read,
-but the call is idempotent, then the server may return EINTR rather than
-actually filling the buffer (taking care that any modifications of the
-default file pointer have been reversed). Preferably, however, servers
-should return data if possible.
+@findex io_reauthenticate
+Users use the @code{io_reauthenticate} call when they wish to have an
+entirely new set of uids or gids associated with a port. In response to
+the @code{io_reauthenticate} call, the server must create a new port,
+and then make the call @code{auth_server_authenticate} to the auth
+server. The rendezvous port for the @code{auth_server_authenticate}
+call is the I/O port to which was made the @code{io_reauthenticate}
+call. The server provides the @var{rend_int} parameter to the auth
+server as a copy from the corresponding parameter in the
+@code{io_reauthenticate} call. The I/O server also gives the auth
+server a new port; this must be a newly created port identical to the
+old port. The authserver will return the set of uids and gids
+associated with the user, and guarantees that the new port will go
+directly to the user that possessed the associated authentication port.
+The server then identifies the new port given out with the specified
+ID's.
+
+@node Simple Operations
+@subsection Simple Operations
+
+@findex io_write
+Users write to I/O ports by calling the @code{io_write} RPC. They
+specify an @var{offset} parameter; if the object supports writing at
+arbitrary offsets, the server should honour this parameter. If @math{-1}
+is passed as the offset, then the server should use the default file
+pointer. The server should return the amount of data which was
+successfully written. If the operation was interrupted after some but
+not all of the data was written, then it is considered to have succeeded
+and the server should return the amount written. If the port is not an
+I/O port at all, the server should reply with the error
+@code{EOPNOTSUPP}. If the port is an I/O port, but does not happen to
+support writing, then the correct error is @code{EBADF}.
+
+@findex io_read
+Users read from I/O ports by calling the @code{io_read} RPC. They
+specify the amount of data they wish to read, and the offset. The offset
+has the same meaning as for @code{io_write} above. The server should
+return the data that was read. If the call is interrupted after some
+data has been read (and the operation is not idempotent) then the server
+should return the amount read, even if it was less than the amount requested.
+The server should return as much data as possible, but never more than
+requested by the user. If there is no data, but there might be later,
+the call should block until data becomes available. The server indicates
+end-of-file by returning zero bytes. If the call is
+interrupted after some data has been read, but the call is idempotent,
+then the server may return @code{EINTR} rather than actually filling the
+buffer (taking care that any modifications of the default file pointer
+have been reversed). Preferably, however, servers should return data.
There are two categories of objects: seekable and non-seekable.
-Seekable objects must accept arbitrary offset parameters in the io_read
-and io_write calls, and to implement the io_seek call. Nonseekable
-objects must ignore the offset parameters to io_read and io_write, and
-should return ESPIPE to the io_seek call.
+Seekable objects must accept arbitrary offset parameters in the
+@code{io_read} and @code{io_write} calls, and must implement the
+@code{io_seek} call. Non-seekable objects must ignore the offset
+parameters to @code{io_read} and @code{io_write}, and should return
+@code{ESPIPE} to the @code{io_seek} call.
-On seekable objects, io_seek changes the default file pointer for reads
-and writes. (See the C library manual for the interpretation of the
-WHENCE and OFFSET arguments.) It returns the new offset as modified by
-io_seek.
+@c FIXME: should that last `should' be replaced with `must'?
+@c tb: maybe, but perhaps not. There might be a reason to implement a
+@c semi-seekable object which permits some but not all of these
+@c operations. In the case of the Hurd interfaces (as opposed to
+@c libraries) I like to be a little looser about this. The rule is "do
+@c what the interface says unless you really understand it and have a
+@c good reason to do something different".
-The io_readable interface returns the amount of data which can be
-immediately read. For the special technical meaning of "immediately",
-see the description of asynchronous I/O. (*Note: Asynchronous I/O.)
+@findex io_seek
+On seekable objects, @code{io_seek} changes the default file pointer for
+reads and writes. (@xref{File Positioning, , , libc, The GNU C Library
+Reference Manual},
+for the interpretation of the @var{whence} and @var{offset} arguments.)
+It returns the new offset as modified by @code{io_seek}.
-@node Open modes
-@section Open modes
+@findex io_readable
+The @code{io_readable} interface returns the amount of data which can be
+immediately read. For the special technical meaning of ``immediately'',
+see @ref{Asynchronous I/O}.
+@node Open Modes
+@subsection Open Modes
+
+@findex io_set_all_openmodes
+@findex io_get_openmodes
+@findex io_set_some_openmodes
+@findex io_clear_some_openmodes
The server associates each port with a set of bits that affect its
-operation. The io_set_all_openmodes call modifies these bits and the
-io_get_openmodes call returns them. In addition, the
-io_set_some_openmodes and io_clear_some_openmodes do an atomic
-read/modify/write of the openmodes.
-
-The O_APPEND bit, when set, changes the behavior of io_write when it
-uses the default file pointer on seekable objects. When io_write is
-done on a port with the O_APPEND bit set, is must set the filepointer to
-one more than the "maximum correct value" (described below) before doing
-the write (which would then increment the file pointer as usual). The
-server must atomically bind this update to the actual data write with
-respect to other users of io_read, io_write, and io_seek.
-
-A "correct value" for the file pointer which, when provided to io_read,
-will successfully return at least one byte of data and not end-of-file.
-The "maximum correct value" referred to in the description of O_APPEND
-is the maximum such correct value. (For ordinary files [see the
-description of the file protocol for more information] this is the same
-as the current file size.)
-
-The O_FSYNC bit, when set, causes io_write not to delay writing data to
-underlying media in any fashion.
-
-The O_NONBLOCK bit, when set, prevents read and write from blocking.
-They should copy such data as is immediately available. If no data is
-immediately available they should return EWOULDBLOCK.
-
-The definition of "immediate" is more or less server dependent. Some
-servers (disk-based file servers, most notably) regard all data as
-immediatebly available. The one criterion is that something which must
-happen immediately may not wait for any user-synchronizable event.
-
-The O_ASYNC bit is deprecated; its use is documented in the following
-section. This bit must be shared between all users of the same
-underlying object.
+operation. The @code{io_set_all_openmodes} call modifies these bits and
+the @code{io_get_openmodes} call returns them. In addition, the
+@code{io_set_some_openmodes} and @code{io_clear_some_openmodes} do an
+atomic read/modify/write of the openmodes.
+
+The @code{O_APPEND} bit, when set, changes the behaviour of
+@code{io_write} when it uses the default file pointer on seekable
+objects. When @code{io_write} is done on a port with the
+@code{O_APPEND} bit set, is must set the file pointer to the current
+file size before doing the write (which would then increment the file
+pointer as usual). The @dfn{current file size} is the smallest offset
+which returns end-of-file when provided to @code{io_read}. The server
+must atomically bind this update to the actual data write with respect
+to other users of @code{io_read}, @code{io_write}, and @code{io_seek}.
+
+The @code{O_FSYNC} bit, when set, guarantees that @code{io_write} will
+not return until data is fully written to the underlying medium.
+
+The @code{O_NONBLOCK} bit, when set, prevents read and write from
+blocking. They should copy such data as is immediately available. If
+no data is immediately available they should return @code{EWOULDBLOCK}.
+
+The definition of ``immediately'' is more or less server-dependent.
+Some servers, notably stored filesystem servers (@pxref{Stored
+Filesystems}), regard all data as immediately available. The one
+criterion is that something which must happen @dfn{immediately} may not
+wait for any user-synchronizable event.
+
+The @code{O_ASYNC} bit is deprecated; its use is documented in the
+following section. This bit must be shared between all users of the
+same underlying object.
+
@node Asynchronous I/O
-@section Asynchronous I/O
+@subsection Asynchronous I/O
+@findex io_async
Users may wish to be notified when I/O can be done without blocking;
-they use the io_async call to indicate this to the server. In the
-io_async call the user provides a port on which will the server should
-send sig_post messages as I/O becomes possible. The server must return
-a port which will be the reference port in the sig_post messages. Each
-io_async call should generate a new reference port. (See the C library
-manual for information on how to send sig_post messages.)
-
-The server then sends one SIGIO signal to each registered async user
-everytime I/O becomes possible. I/O is possible if at least one byte
-can be read or written immediately. (The definition of ``immediately''
-must be the same as for the implementation of the O_NONBLOCK flag.) In
-addition, everytime a user calls io_read or io_write on a non-seekable
-object, or at the default file pointer on a seekable object, another
-signal should be sent to each user if I/O is still possible.
-
-Some objects may also define "urgent" conditions. Such servers should
-send the SIGURG signal to each registered async user anytime an urgent
-condition appears. After any RPC that has the possibility of clearing
-the urgent condition, the server should again send the signal to all
-registered users if the urgent condition is still present.
-
-A more fine-grained mechanism for doing async I/O is the io_select call.
-The user specifies the kind of access desired, and a send-once right.
-If I/O of the kind the user desires is immediately possible, then the
-server should return so indicating, and destroy the send-once right. If
-I/O is not immediately possible, the server should save the send-once
-right, and send a select_done message as soon as I/O becomes immediately
-possible. (Again, the definition of ``immediate'' must be the same for
-io_select, io_async, and O_NONBLOCK.)
-
-For compatibility, the I/O interface provides a deprecated feature
-(known as icky async I/O).. The calls io_mod_owner and io_get_owner set
-the ``owner'' of the object, providing either a pid or a pgrp (if the
-value isnegative). Whenever the I/O server is sending sig_post messages
-to all the io_async users, if the O_ASYNC bit is set, the server should
-also send a signal to the owning pid/pgrp. The ID port for this call
-should be different from all the io_async id ports given to users.
-Users may find out what ID port the server uses for this by calling
-io_get_icky_async_id.
-
-@node Information queries
-@section Information queries
-
-Users may call io_stat to find out information about the I/O object.
-Most of the fieds of a struct stat are meaningful only for files. All
-objects, however, must support the fields st_fstype, st_fsid, st_ino,
-st_atime, st_atime_usec, st_mtime_user, st_ctime, st_ctime_usec, and
-st_blksize.
-
-st_fstype, st_fsid, and st_ino must be unique for the underlying object
-across the entire system.
-
-st_atime and st_atime_usec hold the seconds and microseconds,
-respectively, of the system clock at the last time the object was
-read with io_read.
-
-st_mtime and st_mtime_usec hold the second and microseconds,
-respectively, of the system clock at the last time the object was
-written with io_write.
-
-Other appropriate operations may update the atime and the mtime as well;
-both the file and socket interfaces specify such operations.
-
-st_ctime and st_ctime_usec hold the seconds and microseconds,
-respectively, of the system clock at the last time permanent meta-data
-associated with the object was changed. The exact operations which
-couse such an update are server-dependent, but must include the creation
-of the object.
+they use the @code{io_async} call to indicate this to the server. In
+the @code{io_async} call the user provides a port on which will the
+server should send @code{sig_post} messages as I/O becomes possible.
+The server must return a port which will be the reference port in the
+@code{sig_post} messages. Each @code{io_async} call should generate a
+new reference port. (FIXME: xref the C library manual for information
+on how to send sig_post messages.)
+
+The server then sends one @code{SIGIO} signal to each registered async
+user every time I/O becomes possible. I/O is possible if at least one
+byte can be read or written immediately. The definition of
+``immediately'' must be the same as for the implementation of the
+@code{O_NONBLOCK} flag (@pxref{Open Modes}). In addition, every time a
+user calls @code{io_read} or @code{io_write} on a non-seekable object, or at the
+default file pointer on a seekable object, another signal should be sent
+to each user if I/O is still possible.
+
+Some objects may also define ``urgent'' conditions. Such servers should
+send the @code{SIGURG} signal to each registered async user anytime an
+urgent condition appears. After any RPC that has the possibility of
+clearing the urgent condition, the server should again send the signal
+to all registered users if the urgent condition is still present.
+
+@findex io_select
+A more fine-grained mechanism for doing async I/O is the
+@code{io_select} call. The user specifies the kind of access desired,
+and a send-once right. If I/O of the kind the user desires is
+immediately possible, then the server should return so indicating, and
+destroy the send-once right. If I/O is not immediately possible, the
+server should save the send-once right, and send a @code{select_done}
+message as soon as I/O becomes immediately possible. Again, the
+definition of ``immediately'' must be the same for @code{io_select},
+@code{io_async}, and @code{O_NONBLOCK} (@pxref{Open Modes}).
+
+@findex io_mod_owner
+@findex io_get_owner
+@findex io_get_icky_async_id
+For compatibility with 4.2 and 4.3 BSD, the I/O interface provides a
+deprecated feature (known as @dfn{icky async I/O}). The calls
+@code{io_mod_owner} and @code{io_get_owner} set the ``owner'' of the
+object, providing either a pid or a pgrp (if the value is negative).
+This implies that only one process at a time can do icky I/O on a given
+object. Whenever the I/O server is sending @code{sig_post} messages to
+all the @code{io_async} users, if the @code{O_ASYNC} bit is set, the
+server should also send a signal to the owning pid/pgrp. The ID port
+for this call should be different from all the @code{io_async} ID ports
+given to users. Users may find out what ID port the server uses for
+this by calling @code{io_get_icky_async_id}.
+
+@node Information Queries
+@subsection Information Queries
+
+@findex io_stat
+Users may call @code{io_stat} to find out information about the I/O
+object. Most of the fields of a @code{struct stat} are meaningful only
+for files. All objects, however, must support the fields
+@var{st_fstype}, @var{st_fsid}, @var{st_ino}, @var{st_atim},
+@var{st_mtim}, @var{st_ctim}, and @var{st_blksize}.
+
+@var{st_fstype}, @var{st_fsid}, and @var{st_ino} must be unique for
+the underlying object across the entire system.
+
+@var{st_atim} holds the timestamp of the system clock at the last time the
+object was read with @code{io_read}.
+
+@var{st_mtim} holds the timestamp of the system clock at the last time the
+object was written with @code{io_write}.
+
+Other appropriate operations may update the @var{atim} and the
+@var{mtim} as well; both the file and socket interfaces specify such
+operations.
+
+@var{st_ctim} holds the timestamp of the system clock at the last time
+permanent meta-data associated with the object was changed. The exact
+operations which cause such an update are server-dependent, but must
+include the creation of the object.
The server is permitted to delay the actual update of these times until
stat is called; before the server stores the times on permanent media
(if it ever does so) it should update them if necessary.
-st_blksize gives the optimal I/O size in bytes for io_read and io_write;
-users should endeavor to read and write amounts which are multiples of
-the optimal size, and to use offsets which are multiples of the optimal
-size
+@var{st_blksize} gives the optimal I/O size in bytes for @code{io_read}
+and @code{io_write}; users should endeavor to read and write amounts
+which are multiples of the optimal size, and to use offsets which are
+multiples of the optimal size.
-In addition, objects which are seekable should set st_size to the
-"maximum correct value" described above in the description of the
-O_APPEND flag.
+In addition, objects which are seekable should set @var{st_size} to the
+current file size as in the description of the @code{O_APPEND} flag
+(@pxref{Open Modes}).
-The st_uid and st_gid fields are unrelated to the ``owner'' as described
-above for icky async I/O.
+The @var{st_uid} and @var{st_gid} fields are unrelated to the ``owner''
+as described above for icky async I/O.
+@findex io_server_version
Users may find out the version of the server they are talking to by
-calling io_server_version; this should return strings and integers
-describing the version number of the server, as well as its name.
-
-@node Mapped data
-@section Mapped data
-
-Servers may optionally implement the io_map call; they may do so even if
-the do not implement the facilities described in the following chapter.
-The ports returned by io_map must implement the XP kernel interface and
-be suitable as arguments to vm_map.
-
-Seekable objects must allow access from 0 to the "maximum correct value"
-described for O_APPEND. Whether they provide access beyond such a point
-is server dependent; in addition, the meaning of such an object for a
-non-seekable object is server dependent. However, servers which
-implement the facilities of the next section must obey to certain
-requirements about which addresses in the memory objects provided by
-io_map must be valid. Simply put, any user following the rules
-described in the next chapter should not get any memory faults except as
-explicitly permitted by the next chapter.
-
-@node Shared I/O
-@chapter Shared I/O
-
-I/O servers may, optionally, provide the services described in this
-chapter in addition to the generic services described in the previous
-chapter. These facilities allow users to read and write I/O objects
-without making RPC's to the server in most circumstances.
+calling @code{io_server_version}; this should return strings and
+integers describing the version number of the server, as well as its
+name.
+
+@node Mapped Data
+@subsection Mapped Data
+
+@findex io_map
+Servers may optionally implement the @code{io_map} call. The ports
+returned by @code{io_map} must implement the external pager kernel
+interface (@pxref{Pager Library}) and be suitable as arguments to
+@code{vm_map}.
+
+Seekable objects must allow access from zero up to (but not including)
+the current file size as described for @code{O_APPEND} (@pxref{Open
+Modes}). Whether they provide access beyond such a point is
+server-dependent; in addition, the meaning of accessing a non-seekable
+object is server-dependent.
+
+
+@node Files
+@chapter Files
+
+A file is traditionally thought of as a quantity of disk storage. In
+the Hurd, files are an extension of the I/O interface, but they do not
+necessarily correspond to disk storage.
+
+Every file in the Hurd is represented by a port, which is connected to
+the server that manages the file. When a client wants to operate on a
+file, it makes RPC requests via a file port to its server process, which
+is commonly called a @dfn{translator}.
+
+@menu
+* Translators:: Extending the Hurd filesystem hierarchy.
+* Trivfs Library:: Implementing single-file translators.
+* Fshelp Library:: Miscellaneous generic filesystem routines.
+* File Interface:: File ports implement the file interface.
+* Filesystem Interface:: Translator control interface.
+@end menu
+
+
+@node Translators
+@section Translators
+
+The Hurd filesystem allows you to set translators on any file or
+directory that you own. A @dfn{translator} is any Hurd server which
+provides the basic filesystem interface. Translated nodes are somewhat
+like a cross between Unix symbolic links and mount points.
+
+Whenever a program tries to access the contents of a translated node,
+the filesystem server redirects the request to the appropriate
+translator (starting it if necessary). Then, the new translator
+services the client's request. The GNU C library makes this behaviour
+seamless from the client's perspective, so that standard Unix programs
+behave correctly under the Hurd.
+
+Translators run with the privileges of the translated node's
+@emph{owner}, so they cannot be used to compromise the security of the
+system. This also means that @emph{any} user can write their own
+translators, and provide other users with arbitrary
+filesystem-structured data, regardless of the data's actual source.
+Other chapters in this manual describe existing translators, and how you
+can modify them or write your own.
+
+The standard Hurd filesystem servers are constantly evolving to provide
+innovative features that users want. Here are a few examples of
+existing translators:
+
+@itemize @bullet
+@item
+Disk-based filesystem formats, such as @code{ext2fs}, @code{ufs}, and
+@code{iso9660fs} (@pxref{Stored Filesystems}).
+
+@item
+Network filesystems, such as @code{nfs} and @code{ftpfs}
+(@pxref{Distributed Filesystems}).
+
+@item
+Single files with dynamic content, such as FIXME: we need a good
+example.
+
+@item
+@c FIXME: reword
+Hurd servers which translate rendezvous filesystem nodes in standard
+locations, so that other programs can easily find them and use
+server-specific interfaces. For example, @code{pflocal} implements the
+filesystem interfaces, but it also provides a special Unix-domain socket
+RPC interface (FIXME xref). Programs can fetch a port to this
+translator simply by calling @code{file_name_lookup} (FIXME xref) on
+@file{/servers/socket/1}@footnote{The number 1 corresponds to the
+@code{PF_LOCAL} C library socket domain constant.}, then use Unix
+socket-specific RPCs on that port, rather than adhering to the file
+protocol.
+@end itemize
+
+This section focuses on the generic programs that you need to understand
+in order to use existing translators. Many other parts of this manual
+describe how you can write your own translators.
+
+@menu
+* Invoking settrans:: Declaring how a node should be translated.
+* Invoking showtrans:: Displaying how nodes are translated.
+* Invoking mount:: Unix-compatible active filesystem translators.
+* Invoking fsysopts:: Modifying translation parameters at runtime.
+@end menu
+
+
+@node Invoking settrans
+@subsection Invoking @code{settrans}
+@pindex settrans
+
+The @code{settrans} program allows you to set a translator on a file or
+directory. By default, the passive translator is set (see the
+@samp{--passive} option).
+
+The @code{settrans} program has the following synopsis:
+
+@example
+settrans [@var{option}]@dots{} @var{node} [@var{translator} @var{arg}@dots{}]
+@end example
+
+@noindent
+where @var{translator} is the absolute filename of the new translator
+program. Each @var{arg} is passed to @var{translator} when it starts.
+If @var{translator} is not specified, then @code{settrans} clears the
+existing translator rather than setting a new one.
+
+@code{settrans} accepts the following options:
+
+@table @samp
+@item -a
+@itemx --active
+Set @var{node}'s active translator. @dfn{Active translators} are
+started immediately and are not persistent: if the system is rebooted
+then they are lost.
+
+@item -c
+@itemx --create
+Create @var{node} as a zero-length file if it doesn't already exist.
+
+@item -L
+@itemx --dereference
+If @var{node} is already translated, stack the new translator on top of
+it (rather than replacing the existing translator).
+
+@item --help
+Display a brief usage message, then exit.
+
+@item -p
+@itemx --passive
+Set @var{node}'s passive translator. @dfn{Passive translators} are only
+activated by the underlying filesystem when clients try to use the
+@var{node}, and they shut down automatically after they are no longer
+active in order to conserve system resources.
+
+Passive translators are stored on the underlying filesystem media, and
+so they persist between system reboots. Not all filesystems support
+passive translators, due to limitations in their underlying media.
+Consult the filesystem-specific documentation to see if they are
+supported.
+
+If you are setting the passive translator, and @var{node} already has an
+active translator, then the following options apply:
+
+@table @samp
+@item -g
+@itemx --goaway
+Tell the active translator to go away. In this case, the following
+additional options apply:
+
+@table @samp
+@item -f
+@itemx --force
+If the active translator doesn't go away, then force it.
+
+@item -S
+@itemx --nosync
+Don't flush its contents to disk before terminating.
+
+@item -R
+@itemx --recursive
+Shut down all of the active translator's children, too.
+@end table
+
+
+@item -k
+@itemx --keep-active
+Leave the existing active translator running. The new translator will
+not be started unless the active translator has stopped.
+@end table
+
+@item -P
+@itemx --pause
+When starting an active translator, prompt and wait for a newline on
+standard input before completing the startup handshake. This is useful
+when debugging a translator, as it gives you time to start the debugger.
+
+@item -t @var{sec}
+@itemx --timeout=@var{sec}
+If the translator does not start up in @var{sec} seconds (the default is
+60), then return an error; if @var{sec} is 0, then never timeout.
+
+@item --version
+Output program version information and exit.
+
+@item -x
+@itemx --exclusive
+Only set the translator if there is none already.
+@end table
+
+
+@node Invoking showtrans
+@subsection Invoking @code{showtrans}
+
+The @code{showtrans} program allows you to show the passive translator
+setting on a file system node.
+
+The @code{showtrans} program has the following synopsis:
+
+@example
+showtrans [@var{option}]@dots{} @var{file}@dots{}
+@end example
+
+@code{showtrans} accepts the following options:
+
+@table @code
+@item -p
+@itemx --prefix
+Always display @var{filename}: before translators.
+
+@item -P
+@itemx --no-prefix
+Never display @var{filename}: before translators.
+@item -s
+@itemx --silent
+No output; useful when checking error status.
+@item -t
+@itemx --translated
+Only display files that have translators.
+@end table
+
+
+@node Invoking mount
+@subsection Invoking @code{mount}
+
+
+@node Invoking fsysopts
+@subsection Invoking @code{fsysopts}
+
+The @code{fsysopts} program allows you to retrieve or set command line
+options for running translator @var{filesys}.
+
+The @code{fsysopts} program has the following synopsis:
+
+@example
+fsysopts [@var{option}@dots{}] @var{filesys} [@var{fs_option}@dots{}]
+@end example
+
+@code{fsysopts} accepts the following options:
+
+@table @code
+
+@item -L
+@itemx --dereference
+If @var{filesys} is a symbolic link, follow it.
+
+@item -R
+@itemx --recursive
+Pass these options to any child translators.
+@end table
+
+The legal values for @var{fs_option} depends on @var{filesys}, but
+some common ones are:
+
+@table @code
+@item --readonly
+@item --writable
+@item --remount
+@item --sync[=@var{interval}]
+@item --nosync
+@end table
+
+If no options are supplied, @var{filesys}' current options are
+printed.
+
+The options passed as @var{fs_option}s are meant to augment or change those
+which are already set, they're not meant to completely replace the existing
+command line options. For example, passing @code{--readonly} to a file system
+server will change the server from writable to read-only, but will not touch
+the used backing store. Passing @code{--address=new_IP} to
+@file{/servers/socket/2} will change the local IP address to @var{new_IP}, but
+will not touch the interface, netmask and gateway settings.
+
+@node Trivfs Library
+@section Trivfs Library
+@scindex libtrivfs
+@scindex trivfs.h
+
+Certain translators do not need to be very complex, because they
+represent a single file rather than an entire directory hierarchy. The
+trivfs library, which is declared in @code{<hurd/trivfs.h>}, does most of
+the work of implementing this kind of translator. This library requires
+the iohelp and ports libraries.
+
+@menu
+* Trivfs Startup:: Writing a simple trivfs-based translator.
+* Trivfs Callbacks:: Mandatory user-defined trivfs functions.
+* Trivfs Options:: Optional user-defined trivfs functions.
+* Trivfs Ports:: Managing control and protid ports.
+@end menu
+
+@node Trivfs Startup
+@subsection Trivfs Startup
+
+In order to use the trivfs library, you will need to define the
+appropriate callbacks (@pxref{Trivfs Callbacks}). As with all Hurd
+servers, your trivfs-based translator should first parse any
+command-line options, in case the user is just asking for help. Trivfs
+uses argp (@pxref{Argp, , , libc, The GNU C Library Reference Manual})
+for parsing command-line arguments.
+
+Your translator should redefine the following functions and variables as
+necessary, and then call @code{argp_parse} with the relevant arguments:
+
+@deftypevar {extern struct argp *} trivfs_runtime_argp
+If this is defined or set to an argp structure, it will be used by the
+default @code{trivfs_set_options} to handle runtime options parsing.
+Redefining this is the normal way to add option parsing to a trivfs
+program.
+@end deftypevar
+
+@deftypefun error_t trivfs_set_options (@w{struct trivfs_control *@var{fsys}}, @w{char *@var{argz}}, @w{size_t @var{argz_len}})
+Set runtime options for @var{fsys} to @var{argz} and @var{argz_len}.
+The default definition for this routine simply uses
+@var{trivfs_runtime_argp} (supplying @var{fsys} as the argp input
+field).
+@end deftypefun
+
+@deftypefun error_t trivfs_append_args (@w{struct trivfs_control *@var{fsys}}, @w{char **@var{argz}}, @w{size_t *@var{argz_len}})
+Append to the malloced string @code{*@var{argz}} of length
+@code{*@var{argz_len}} a NUL-separated list of the arguments to this
+translator.
+@end deftypefun
+
+@c FIXME: Shouldn't `NUL-separated', above, be changed to
+@c `NUL-terminated' (or, as I prefer, `zero-terminated')?
+@c tb: no, it's a NUL-separated list. Something like:
+@c "foo\0bar\0baz\0quux"
+
+After your translator parses its command-line arguments, it should fetch
+its bootstrap port by using @code{task_get_bootstrap_port}. If this
+port is @code{MACH_PORT_NULL}, then your program wasn't started as a
+translator. Otherwise, you can use the bootstrap port to create a new
+control structure (and advertise its port) with @code{trivfs_startup}:
+
+@deftypefun error_t trivfs_startup (@w{mach_port_t @var{bootstrap}}, @w{int @var{flags}}, @w{struct port_class *@var{control_class}}, @w{struct port_bucket *@var{control_bucket}}, @w{struct port_class *@var{protid_class}}, @w{struct port_bucket *@var{protid_bucket}}, @w{struct trivfs_control **@var{control}})
+@deftypefunx error_t trivfs_create_control (@w{mach_port_t @var{bootstrap}}, @w{struct port_class *@var{control_class}}, @w{struct port_bucket *@var{control_bucket}}, @w{struct port_class *@var{protid_class}}, @w{struct port_bucket *@var{protid_bucket}}, @w{struct trivfs_control **@var{control}})
+@code{trivfs_startup} creates a new trivfs control port, advertises it
+to the underlying node @var{bootstrap} with @code{fsys_startup},
+returning the results of this call, and places its control structure in
+@code{*@var{control}}. @code{trivfs_create_control} does the same
+thing, except it doesn't advertise the control port to the underlying
+node. @var{control_class} and @var{control_bucket} are passed to
+@code{libports} to create the control port, and @var{protid_class} and
+@var{protid_bucket} are used when creating ports representing opens of
+this node; any of these may be zero, in which case an appropriate port
+class/bucket is created. If @var{control} is non-null, the trivfs
+control port is returned in it. @var{flags} (a bitmask of the
+appropriate @code{O_*} constants) specifies how to open the underlying
+node.
+@end deftypefun
+
+If you did not supply zeros as the class and bucket arguments to
+@code{trivfs_startup}, you will probably need to use the trivfs port
+management functions (@pxref{Trivfs Ports}).
+
+Once you have successfully called @code{trivfs_startup}, and have a
+pointer to the control structure stored in, say, the @var{fsys}
+variable, you are ready to call one of the
+@code{ports_manage_port_operations_*} functions using
+@code{@var{fsys}->pi.bucket} and @code{trivfs_demuxer}. This will
+handle any incoming filesystem requests, invoking your callbacks when
+necessary.
+
+@deftypefun int trivfs_demuxer (@w{mach_msg_header_t *@var{inp}}, @w{mach_msg_header_t *@var{outp}})
+Demultiplex incoming @code{libports} messages on trivfs ports.
+@end deftypefun
+
+The following functions are not usually necessary, but they allow you to
+use the trivfs library even when it is not possible to turn
+message-handling over to @code{trivfs_demuxer} and @code{libports}:
+
+@deftypefun {struct trivfs_control *} trivfs_begin_using_control (@w{mach_port_t @var{port}})
+@deftypefunx {struct trivfs_protid *} trivfs_begin_using_protid (@w{mach_port_t @var{port}})
+These functions can be used as @code{intran} functions for a MiG port
+type to have the stubs called with either the control or protid pointer.
+@end deftypefun
+
+@c FIXME: `intran' needs to be explained, or else there needs to be
+@c a cross-reference there.
+@c tb: `intran' is a keyword in MiG.
+
+@deftypefun void trivfs_end_using_control (@w{struct trivfs_control *@var{port}})
+@deftypefunx void trivfs_end_using_protid (@w{struct trivfs_protid *@var{port}})
+These can be used as `destructor' functions for a MiG port type, to have
+the stubs called with the control or protid pointer.
+@end deftypefun
+
+@deftypefun error_t trivfs_open (@w{struct trivfs_control *@var{fsys}}, @w{struct iouser *@var{user}}, @w{unsigned @var{flags}}, @w{mach_port_t @var{realnode}}, @w{struct trivfs_protid **@var{cred}})
+Return a new protid (that is, a port representing an open of this node)
+pointing to a new peropen in @var{cred}, with @var{realnode} as the
+underlying node reference, with the given identity, and open flags in
+@var{flags}. @var{cntl} is the trivfs control object.
+@end deftypefun
+
+@deftypefun error_t trivfs_protid_dup (@w{struct trivfs_protid *@var{cred}}, @w{struct trivfs_protid **@var{dup}})
+Return a duplicate of @var{cred} in @var{dup}, sharing the same peropen
+and hook. A non-null protid @var{hook} indicates that
+@var{trivfs_peropen_create_hook} created this protid (@pxref{Trivfs
+Options}).
+@end deftypefun
+
+@deftypefun error_t trivfs_set_atime (@w{struct trivfs_control *@var{cntl}})
+@deftypefunx error_t trivfs_set_mtime (@w{struct trivfs_control *@var{cntl}})
+Call these to set atime or mtime for the node to the current time.
+@end deftypefun
+
+
+@node Trivfs Callbacks
+@subsection Trivfs Callbacks
+
+Like several other Hurd libraries, @code{libtrivfs} requires that you
+define a number of application-specific callback functions and
+configuration variables. You @emph{must} define the following variables
+and functions:
+
+@deftypevar {extern int} trivfs_fstype
+@deftypevarx {extern int} trivfs_fsid
+These variables are returned in the @var{st_fstype} and @var{st_fsid}
+fields of @code{struct stat}. @var{trivfs_fstype} should be chosen
+from the @code{FSTYPE_*} constants found in @code{<hurd/hurd_types.h>}.
+@end deftypevar
+
+@deftypevar {extern int} trivfs_allow_open
+Set this to some bitwise OR combination of @code{O_READ},
+@code{O_WRITE}, and @code{O_EXEC}; trivfs will only allow opens of the
+specified modes.
+@end deftypevar
+
+@deftypevar {extern int} trivfs_support_read
+@deftypevarx {extern int} trivfs_support_write
+@deftypevarx {extern int} trivfs_support_exec
+Set these to nonzero if trivfs should allow read, write, or execute of
+the file. These variables are necessary because @var{trivfs_allow_open}
+is used only to validate opens, not actual operations.
+@end deftypevar
+
+@deftypefun void trivfs_modify_stat (@w{struct trivfs_protid *@var{cred}}, @w{struct stat *@var{stbuf}})
+This should modify a @code{struct stat} (as returned from the underlying
+node) for presentation to callers of @code{io_stat}. It is permissible
+for this function to do nothing, but it must still be defined.
+@end deftypefun
+
+@deftypefun error_t trivfs_goaway (@w{struct trivfs_control *@var{cntl}}, @w{int @var{flags}})
+This function is called when someone wants the filesystem @var{cntl} to
+go away. @var{flags} are from the set @code{FSYS_GOAWAY_*} found in
+@code{<hurd/hurd_types.h>}.
+@end deftypefun
+
+
+@node Trivfs Options
+@subsection Trivfs Options
+
+The functions and variables described in this subsection already have
+default definitions in @code{libtrivfs}, so you are not forced to define
+them; rather, they may be redefined on a case-by-case basis.
+
+@deftypevar {extern struct port_class *} trivfs_protid_portclasses []
+@deftypevarx {extern int} trivfs_protid_nportclasses
+@deftypevarx {extern struct port_class *} trivfs_cntl_portclasses []
+@deftypevarx {extern int} trivfs_cntl_nportclasses
+If you define these, they should be vectors (and the associated sizes)
+of port classes that will be translated into control and protid pointers
+for passing to RPCs, in addition to those passed to or created by
+@code{trivfs_create_control} (or @code{trivfs_startup}), which will
+automatically be recognized.
+@end deftypevar
+
+@deftypefn {Variable} error_t {(*trivfs_check_open_hook)} (@w{struct trivfs_control *@var{cntl}}, @w{struct iouser *@var{user}}, @w{int @var{flags}})
+If this variable is non-zero, it will be called every time an open happens.
+@var{user} and @var{flags} are from the open; @var{cntl} identifies the
+node being opened. This call need not check permissions on the
+underlying node. This call can block as necessary, unless
+@code{O_NONBLOCK} is set in @var{flags}. Any desired error can be
+returned, which will be reflected to the user and will prevent the open from
+succeeding.
+@end deftypefn
+
+@deftypefn {Variable} error_t (*trivfs_protid_create_hook) (@w{struct trivfs_protid *@var{prot}})
+@deftypefnx {Variable} error_t (*trivfs_peropen_create_hook) (@w{struct trivfs_peropen *@var{perop}})
+If these variables are non-zero, they will be called every time a new protid or
+peropen structure is created and initialized.
+@end deftypefn
+
+@deftypefn {Variable} void (*trivfs_protid_destroy_hook) (@w{struct trivfs_protid *@var{prot}})
+@deftypefnx {Variable} void (*trivfs_peropen_destroy_hook) (@w{struct trivfs_peropen *@var{perop}})
+If these variables is non-zero, they will be called every time a protid or
+peropen structure is about to be destroyed.
+@end deftypefn
+
+@deftypefn {Variable} error_t (*trivfs_getroot_hook) (@w{struct trivfs_control *@var{cntl}}, @w{mach_port_t @var{reply_port}}, @w{mach_msg_type_name_t @var{reply_port_type}}, @w{mach_port_t @var{dotdot}}, @w{uid_t *@var{uids}}, @w{u_int @var{nuids}}, @w{uid_t *@var{gids}}, @w{u_int @var{ngids}}, @w{int @var{flags}}, @w{retry_type *@var{do_retry}}, @w{char *@var{retry_name}}, @w{mach_port_t *@var{node}}, @w{mach_msg_type_name_t *@var{node_type}})
+If this variable is set, it will be called by @code{trivfs_S_fsys_getroot}
+before any other processing takes place. If the return value is
+@code{EAGAIN}, normal trivfs getroot processing continues, otherwise the
+RPC returns with that return value.
+@end deftypefn
+
+
+@node Trivfs Ports
+@subsection Trivfs Ports
+
+If you choose to allocate your own trivfs port classes and buckets, the
+following functions may come in handy:
+
+@deftypefun error_t trivfs_add_port_bucket (@w{struct port_bucket **@var{bucket}})
+Add the port bucket @code{*@var{bucket}} to the list of dynamically-
+allocated port buckets; if @code{*@var{bucket}} is zero, an attempt is
+made to allocate a new port bucket, which is then stored in
+@code{*@var{bucket}}.
+@c FIXME: what if the allocation attempt fails?
+@c tb: then an appropriate error (ENOMEM in this case) is returned.
+@c tb: Users are not supposed to assume they know all the possible error
+@c tb: returns. All functions that return error_t are like this.
+@end deftypefun
+
+@deftypefun void trivfs_remove_port_bucket (@w{struct port_bucket *@var{bucket}})
+Remove the previously added dynamic port bucket @var{bucket}, freeing it
+if it was allocated by @code{trivfs_add_port_bucket}.
+@end deftypefun
+
+@deftypefun error_t trivfs_add_control_port_class (@w{struct port_class **@var{class}})
+@deftypefunx error_t trivfs_add_protid_port_class (@w{struct port_class **@var{class}})
+Add the port class @code{*@var{class}} to the list of control or protid port
+classes recognized by trivfs; if @code{*@var{class}} is zero, an attempt is
+made to allocate a new port class, which is stored in @code{*@var{class}}.
+@end deftypefun
+
+@deftypefun void trivfs_remove_control_port_class (@w{struct port_class *@var{class}})
+@deftypefunx void trivfs_remove_protid_port_class (@w{struct port_class *@var{class}})
+Remove the previously added dynamic control or protid port class
+@var{class}, freeing it if it was allocated by
+@code{trivfs_add_control_port_class} or
+@code{trivfs_add_protid_port_class}.
+@end deftypefun
+
+Even if you do not use the above allocation functions, you may still be
+able to use the default trivfs cleanroutines:
+
+@deftypefun void trivfs_clean_cntl (@w{void *@var{port}})
+@deftypefunx void trivfs_clean_protid (@w{void *@var{port}})
+These functions should be installed as @code{libports} cleanroutines for
+control port classes and protid port classes, respectively.
+@end deftypefun
+
+
+@node Fshelp Library
+@section Fshelp Library
+@scindex libfshelp
+@scindex fshelp.h
+
+The fshelp library implements various things that are useful to most
+implementors of the file protocol. It presumes that you are using the
+iohelp library as well. @code{libfshelp} is divided into separate
+facilities which may be used independently. These functions are
+declared in @code{<hurd/fshelp.h>}.
+@c FIXME: perhaps `useful to most implementors' should read `generic
+@c to most implementations'
+
+@menu
+* Passive Translator Linkage:: Invoking passive translators.
+* Active Translator Linkage:: Managing active translators.
+* Fshelp Locking:: Implementing file locking.
+* Fshelp Permissions:: Standard file access permission policies.
+* Fshelp Misc:: Useful standalone routines.
+@end menu
+
+@node Passive Translator Linkage
+@subsection Passive Translator Linkage
+
+These routines are self-contained and start passive translators,
+returning the control port. They do not require multithreading or the
+ports library.
+
+@deftypefn {Typedef} typedef error_t (*fshelp_open_fn_t) (@w{int @var{flags}}, @w{file_t *@var{node}}, @w{mach_msg_type_name_t *@var{node_type}})
+A callback used by the translator starting functions.
+Given some open flags, opens the appropriate file, and
+returns the node port.
+@end deftypefn
+
+@deftypefun error_t fshelp_start_translator_long (@w{fshelp_open_fn_t @var{underlying_open_fn}}, @w{char *@var{name}}, @w{char *@var{argz}}, @w{int @var{argz_len}}, @w{mach_port_t *@var{fds}}, @w{mach_msg_type_name_t @var{fds_type}}, @w{int @var{fds_len}}, @w{mach_port_t *@var{ports}}, @w{mach_msg_type_name_t @var{ports_type}}, @w{int @var{ports_len}}, @w{int *@var{ints}}, @w{int @var{ints_len}}, @w{int @var{timeout}}, @w{fsys_t *@var{control}})
+Start a passive translator @var{name} with arguments @var{argz} (length
+@var{argz_len}). Initialize the initports to @var{ports} (length
+@var{ports_len}), the initints to @var{ints} (length @var{ints_len}),
+and the file descriptor table to @var{fds} (length @var{fds_len}).
+Return the control port in @code{*@var{control}}. If the translator doesn't
+respond or die in @var{timeout} milliseconds (if @var{timeout} is
+greater than zero), return an appropriate error. If the translator dies
+before responding, return @code{EDIED}.
+@end deftypefun
+
+@deftypefun error_t fshelp_start_translator (@w{fshelp_open_fn_t @var{underlying_open_fn}}, @w{char *@var{name}}, @w{char *@var{argz}}, @w{int @var{argz_len}}, @w{int @var{timeout}}, @w{fsys_t *@var{control}})
+Same as @code{fshelp_start_translator_long}, except the initports and
+ints are copied from our own state, @var{fd}[2] is copied from our own
+stderr, and the other fds are cleared. For full-service filesystems, it
+is almost always wrong to use @code{fshelp_start_translator}, because
+the current working directory of the translator will not then be as
+normally expected. (Current working directories of passive translators
+should be the directory they were found in.) In fact, full-service
+filesystems should usually start passive translators as a side-effect of
+calling @code{fshelp_fetch_root} (@pxref{Active Translator Linkage}).
+@end deftypefun
+
+@node Active Translator Linkage
+@subsection Active Translator Linkage
+
+These routines implement the linkage to active translators needed
+by any filesystem which supports them. They require the threads
+library and use the passive translator routines above, but they don't
+require the ports library at all.
+
+This interface is complex, because creating the ports and state
+necessary for @code{start_translator_long} is expensive. The caller to
+@code{fshelp_fetch_root} should not need to create them on every call,
+since usually there will be an existing active translator.
+
+@deftypefun void fshelp_transbox_init (@w{struct transbox *@var{transbox}}, @w{struct mutex *@var{lock}}, @w{void *@var{cookie}})
+Initialize a transbox, which contains state information for active
+translators.
+@end deftypefun
+
+@deftypefn {Typedef} typedef error_t (*fshelp_fetch_root_callback1_t) (@w{void *@var{cookie1}}, @w{void *@var{cookie2}}, @w{uid_t *@var{uid}}, @w{gid_t *@var{gid}}, @w{char **@var{argz}}, @w{size_t *@var{argz_len}})
+This routine is called by @code{fshelp_fetch_root} to fetch more
+information. Return the owner and group of the underlying translated
+file in @code{*@var{uid}} and @code{*@var{gid}}; point
+@code{*@var{argz}} at the entire passive translator specification for
+the file (setting @code{*@var{argz_len}} to the length). If there is no
+passive translator, then return @code{ENOENT}. @var{cookie1} is the
+cookie passed in @code{fshelp_transbox_init}. @var{cookie2} is the
+cookie passed in the call to @code{fshelp_fetch_root}.
+@end deftypefn
+
+@deftypefn {Typedef} typedef error_t (*fshelp_fetch_root_callback2_t) (@w{void *@var{cookie1}}, @w{void *@var{cookie2}}, @w{int @var{flags}}, @w{mach_port_t *@var{underlying}}, @w{mach_msg_type_name_t *@var{underlying_type}})
+This routine is called by @code{fshelp_fetch_root} to fetch more
+information. Return an unauthenticated node for the file itself in
+@code{*@var{underlying}} and @code{*@var{underlying_type}} (opened with
+@var{flags}). @var{cookie1} is the cookie passed in
+@code{fshelp_transbox_init}. @var{cookie2} is the cookie passed in the
+call to @code{fshelp_fetch_root}.
+@end deftypefn
+
+@deftypefun error_t fshelp_fetch_root (@w{struct transbox *@var{transbox}}, @w{void *@var{cookie}}, @w{file_t @var{dotdot}}, @w{struct iouser *@var{user}}, @w{int @var{flags}}, @w{fshelp_fetch_root_callback1_t @var{callback1}}, @w{fshelp_fetch_root_callback2_t @var{callback2}}, @w{retry_type *@var{retry}}, @w{char *@var{retryname}}, @w{mach_port_t *@var{root}})
+Fetch the root from @var{transbox}. @var{dotdot} is an unauthenticated
+port for the directory in which we are looking; @var{user} specifies the
+ids of the user responsible for the call. @var{flags} are as for
+@code{dir_lookup} (but @code{O_CREAT} and @code{O_EXCL} are not
+meaningful and are ignored). The transbox lock (as set by
+@code{fshelp_transbox_init}) must be held before the call, and will be
+held upon return, but may be released during the operation of the call.
+@end deftypefun
+
+@deftypefun int fshelp_translated (@w{struct transbox *@var{box}})
+Return true if and only if there is an active translator on this box.
+@end deftypefun
+
+@deftypefun error_t fshelp_set_active (@w{struct transbox *@var{box}}, @w{fsys_t @var{newactive}}, @w{int @var{excl}})
+Atomically replace the existing active translator port for this box with
+@var{newactive}. If @var{excl} is non-zero then don't modify an
+existing active transbox; return @code{EBUSY} instead.
+@end deftypefun
+
+@deftypefun error_t fshelp_fetch_control (@w{struct transbox *@var{box}}, @w{mach_port_t *@var{control}})
+Fetch the control port to make a request on it. It's a bad idea to use
+@code{fsys_getroot} with the result; use @code{fshelp_fetch_root}
+instead.
+@end deftypefun
+
+@deftypefun void fshelp_drop_transbox (@w{struct transbox *@var{box}})
+Clean transbox state so that deallocation or reuse is possible.
+@end deftypefun
+
+
+@node Fshelp Locking
+@subsection Fshelp Locking
+
+The @code{flock} call is in flux, as the current Hurd interface (as of
+version @value{VERSION}) is not suitable for implementing the POSIX
+record-locking semantics.
+
+
+@node Fshelp Permissions
+@subsection Fshelp Permissions
+
+These functions are designed to aid with user permission checking. It
+is a good idea to use these routines rather than to roll your own, so
+that Hurd users see consistent handling of file and directory permission
+bits.
+
+@deftypefun error_t fshelp_isowner (@w{struct stat *@var{st}}, @w{struct iouser *@var{user}})
+Check to see whether @var{user} should be considered the owner of the
+file identified by @var{st}. If so, return zero; otherwise return an
+appropriate error code.
+@end deftypefun
+
+@deftypefun error_t fshelp_access (@w{struct stat *@var{st}}, @w{int @var{op}}, @w{struct iouser *@var{user}})
+Check to see whether the user @var{user} can operate on the file
+identified by @var{st}. @var{op} is one of @code{S_IREAD},
+@code{S_IWRITE}, and @code{S_IEXEC}. If the access is permitted, return
+zero; otherwise return an appropriate error code.
+@end deftypefun
+
+@deftypefun error_t fshelp_checkdirmod (@w{struct stat *@var{dir}}, @w{struct stat *@var{st}}, @w{struct iouser *@var{user}})
+Check to see whether @var{user} is allowed to modify @var{dir} with respect to
+existing file @var{st}. If there is no existing file, then @var{st}
+should be set to zero. If the access is permissible, return zero;
+otherwise return an appropriate error code.
+@c FIXME: what does it mean to modify a directory with respect to an
+@c existing file?
+@c tb: If you delete a file, say, then you are modifying the directory
+@c tb: (not the file) but with respect to that file. This is relevant
+@c tb: in implementing the directory sticky-bit permissions algorithm.
+@end deftypefun
+
+@node Fshelp Misc
+@subsection Fshelp Misc
+
+The following functions are completely standalone:
+
+@deftypefun error_t fshelp_delegate_translation (@w{char *@var{server_name}}, @w{mach_port_t @var{requestor}}, @w{char **@var{argv}})
+Try to hand off responsibility from a translator to the server located
+on the node @var{server_name}. @var{requestor} is the translator's
+bootstrap port, and @var{argv} is the command line. If
+@var{server_name} is null, then a name is concocted by prepending
+@code{_servers} to @code{argv[0]} .
+@end deftypefun
+
+@deftypefun error_t fshelp_exec_reauth (@w{int @var{suid}}, @w{uid_t @var{uid}}, @w{int @var{sgid}}, @w{gid_t @var{gid}}, @w{auth_t @var{auth}}, error_t (*@var{get_file_ids}) (@w{struct idvec *@var{uids}}, @w{struct idvec *@var{gids}}), @w{mach_port_t *@var{ports}}, @w{mach_msg_type_number_t @var{num_ports}}, @w{mach_port_t *@var{fds}}, @w{mach_msg_type_number_t @var{num_fds}}, @w{int *@var{secure}})
+If @var{suid} or @var{sgid} is true, adds @var{uid} and/or @var{gid}
+respectively to the authentication in
+@code{@var{ports}[INIT_PORT_AUTH]}, and replaces it with the result.
+All the other ports in @var{ports} and @var{fds} are then
+reauthenticated, using any privileges available through @var{auth}. If
+the auth port in @code{@var{ports}[INIT_PORT_AUTH]} is bogus, and
+@var{get_file_ids} is non-null, it is called to get a list
+of uids and gids from the file to use as a replacement. If @var{secure}
+is non-null and any added ids are new, then the variable it points to is
+set to nonzero, otherwise zero. If either the uid or gid case fails,
+then the other may still apply.
+@end deftypefun
+
+@deftypefun error_t fshelp_get_identity (@w{struct port_bucket *@var{bucket}}, @w{ino_t @var{fileno}}, @w{mach_port_t *@var{pt}})
+Return an identity port in @code{*@var{pt}} for the node numbered
+@var{fileno}, suitable for returning from @code{io_identity}; exactly
+one send right must be created from the returned value. @var{fileno}
+should be the same value returned as the @var{fileno} out-parameter in
+@code{io_identity}, and in the enclosing directory (except for mount
+points), and in the @code{st_ino} stat field. @var{bucket} should be a
+@code{libports} port bucket; fshelp requires the caller to make sure
+port operations (for no-senders notifications) are used.
+@end deftypefun
+
+@deftypefun error_t fshelp_return_malloced_buffer (@w{char *@var{buf}}, @w{size_t @var{len}}, @w{char **@var{rbuf}}, @w{mach_msg_type_number_t *@var{rlen}})
+Put data from the malloced buffer @var{buf}, @var{len} bytes long, into
+@var{rbuf} (which is @var{rlen} bytes long), suitable for returning from
+an RPC. If @var{len} is greater than zero, @var{buf} is freed,
+regardless of whether an error is returned or not.
+@end deftypefun
+
+@deftypefun error_t fshelp_set_options (@w{struct argp *@var{argp}}, @w{int @var{flags}}, @w{char *@var{argz}}, @w{size_t @var{argz_len}}, @w{void *@var{input}})
+Invoke @code{argp_parse} in the standard way, with data from @var{argz}
+and @var{argz_len}.
+@end deftypefun
+
+@deftypefun void fshelp_touch (@w{struct stat *@var{st}}, @w{unsigned @var{what}}, @w{volatile struct mapped_time_value *@var{maptime}})
+Change the stat times of @var{node} as indicated by @var{what} to
+the current time. @var{what} is a bitmask of one or more of
+the @code{TOUCH_ATIME}, @code{TOUCH_MTIME}, and @code{TOUCH_CTIME}
+constants.
+@end deftypefun
+
+
+@node File Interface
+@section File Interface
+@scindex fs.defs
+
+This section documents the interface for operating on files.
+
+@menu
+* File Overview:: Basic concepts for the file interface.
+* Changing Status:: Changing the owner (etc.) of a file.
+* Program Execution:: Executing files.
+* File Locking:: Implementing the @code{flock} call.
+* File Frobbing:: Other active calls on files.
+* Opening Files:: Looking up files in directories.
+* Modifying Directories:: Creating and deleting nodes.
+* Notifications:: File and directory change callbacks.
+* File Translators:: How to set and get translators.
+@end menu
+
+@node File Overview
+@subsection File Overview
+
+The file interface is a superset of the I/O interface (@pxref{I/O
+Interface}). Servers which provide the file interface are required to
+support the I/O interface as well. All objects reachable in the
+filesystem are expected to provide the file interface, even if they do
+not contain data. (The @code{trivfs} library makes it easy to do so for
+ordinary sorts of cases. @xref{Trivfs Library}.)
+
+The interface definitions for the file interface are found in
+@code{<hurd/fs.defs>}.
+
+Files have various pieces of status information which are returned by
+@code{io_stat} (@pxref{Information Queries}). Most of this status
+information can be directly changed by various calls in the file
+interface; some of it should vary implicitly as the contents of the file
+change.
+
+Many of these calls have general rules associated with them describing
+how security and privilege should operate. The @code{diskfs} library
+(@pxref{Diskfs Library}) implements these rules for stored filesystems.
+These rules have also been implemented in the fshelp library
+(@pxref{Fshelp Library}). Trivfs-based servers generally have no need
+to implement these rules at all.
+
+In special cases, there may be a reason to implement a different
+security check from that specified here, or to implement a call to do
+something slightly different. But such cases must be carefully
+considered; make sure that you will not confuse innocent user programs
+through excessive cleverness.
+
+If some operation cannot be implemented (for example, @code{chauthor}
+over FTP), then the call should return @code{EOPNOTSUPP}. If it is
+merely difficult to implement a call, it is much better to figure out a
+way to implement it as a series of operations rather than to return
+errors to the user.
+
+@node Changing Status
+@subsection Changing Status
+
+There are several RPCs available for users to change much of the status
+information associated with a file. (The information is returned by the
+@code{io_stat} RPC; see @ref{Information Queries}.)
+
+All these operations are restricted to root and the owner of the file.
+When attempted by another user, they should return @code{EPERM}.
+
+@findex file_chown
+The @code{file_chown} RPC changes the owner and group of the file. Only
+root should be able to change the owner, and changing the group to a
+group the caller is not in should also be prohibited. Violating either
+of these conditions should return @code{EPERM}.
+
+@findex file_chauthor
+The @code{file_chauthor} RPC changes the author of the file. It should
+be legitimate to change the author to any value without restriction.
+
+@findex file_chmod
+The @code{file_chmod} RPC changes the file permission mode bits.
+
+@findex file_chflags
+The @code{file_chflags} RPC changes the flags of the file. It should be
+legitimate to change the flags to any value without restriction. No
+standard meanings have been assigned to the flags yet, but we intend to
+do so. Do not assume that the flags format we choose will map
+identically to that of some existing filesystem format.
+
+@findex file_utimes
+The @code{file_utimes} RPC changes the @var{atime} and @var{mtime} of
+the file. Making this call must cause the @var{ctime} to be updated as
+well, even if no actual change to either the @var{mtime} or the
+@var{atime} occurs.
+
+@findex file_set_size
+The @code{file_set_size} RPC is special; not only does it change the
+status word specifying the size of the file, but it also changes the
+actual contents of the file. If the file size is being reduced it
+should release secondary storage associated with the previous contents
+of the file. If the file is being extended, the new region added to the
+file must be zero-filled. Unlike the other RPCs in this section,
+@code{file_set_size} should be permitted to any user who is allowed to
+write the file.
+
+
+@node Program Execution
+@subsection Program Execution
+
+@findex file_exec
+Execution of programs on the Hurd is done through fileservers with the
+@code{file_exec} RPC. The fileserver is expected to verify that the
+user is allowed to execute the file, make whatever modifications to the
+ports are necessary for setuid execution, and then invoke the standard
+execserver found on @file{/servers/exec}.
+
+This section specifically addresses what fileservers are expected to do,
+with minimal attention to the other parts of the process. @xref{Running
+Programs}, for more general information.
+
+The file must be opened for execution; if it is not, @code{EBADF} should
+be returned. In addition, at least one of the execute bits must be on. A
+failure of this check should result in @code{EACCES}---not
+@code{ENOEXEC}. It is not proper for the fileserver ever to respond to
+the @code{file_exec} RPC with @code{ENOEXEC}.
+
+If either the setuid or setgid bits are set, the server needs to
+construct a new authentication handle with the additional new ID's.
+Then all the ports passed to @code{file_exec} need to be reauthenticated
+with the new handle. If the fileserver is unable to make the new
+authentication handle (for example, because it is not running as root)
+it is not acceptable to return an error; in such a case the server
+should simply silently fail to implement the setuid/setgid semantics.
+
+If the setuid/setgid transformation adds a new uid or gid to the user's
+authentication handle that was not previously present (as opposed to
+merely reordering them), then the @code{EXEC_SECURE} and
+@code{EXEC_NEWTASK} flags should both be added in the call to
+@code{exec_exec}.
+
+The server then needs to open a new port onto the executed file which
+will not share any file pointers with the port the user passed in,
+opened with @code{O_READ}. Finally, all the information (mutated
+appropriately for setuid/setgid) should be sent to the execserver with
+@code{exec_exec}. Whatever error code @code{exec_exec} returns should
+returned to the caller of @code{file_exec}.
+
+@node File Locking
+@subsection File Locking
+
+The @code{flock} call is in flux, as the current Hurd interface (as of
+version @value{VERSION}) is not suitable for implementing the POSIX
+record-locking semantics.
+
+@findex file_lock
+@findex file_lock_stat
+You should ignore the @code{file_lock} and @code{file_lock_stat} calls
+until the new record-locking interface is implemented.
+
+
+@node File Frobbing
+@subsection File Frobbing
+
+FIXME: Other active calls on files
+
+@code{file_sync}
+
+@code{file_getfh}
+
+@code{file_getlinknode}
+
+@code{file_check_access}
+
+These manipulate meta-information:
+
+@code{file_reparent}
+
+@code{file_statfs}
+
+@code{file_syncfs}
+
+@code{file_getcontrol}
+
+@code{file_get_storage_info}
+
+@code{file_get_fs_options}
+
+
+@node Opening Files
+@subsection Opening Files
+
+FIXME: Looking up files in directories
+
+@code{dir_lookup}
+
+@code{dir_readdir}
+
+@node Modifying Directories
+@subsection Modifying Directories
+
+@deftypefun kern_return_t dir_mkfile (@w{file_t @var{directory}}, @w{int @var{flags}}, @w{mode_t @var{mode}}, @w{mach_port_t *@var{newnode}})
+Create a new file in @var{directory} without linking it into the
+filesystem. You still must have write permission on the specified
+directory, even though it will not actually be written.
+
+The function returns a port to the new file in *@var{newnode}. Flags
+are the same as for @code{dir_lookup}, but @code{O_CREAT} and
+@code{O_TRUNC} are assumed even if not specified.
+@end deftypefun
+
+@deftypefun kern_return_t dir_mkdir (@w{file_t @var{directory}}, @w{char *@var{name}}, @w{mode_t @var{mode}})
+Create a new directory named @var{name} in @var{directory} with
+permission specified by @var{mode}.
+@end deftypefun
+
+@deftypefun kern_return_t dir_rmdir (@w{file_t @var{directory}}, @w{char *@var{name}})
+Remove the directory named @var{name} from @var{directory}.
+@end deftypefun
+
+@deftypefun kern_return_t dir_unlink (@w{file_t @var{directory}}, @w{char *@var{name}})
+Remove the non-directory node @var{name} from @var{directory}.
+@end deftypefun
+
+@deftypefun kern_return_t dir_link (@w{file_t @var{directory}}, @w{file_t @var{file}}, @w{char *@var{name}}, @w{int @var{excl}})
+Create a hard link in @var{directory}. If @var{excl} is set and
+@var{name} already exists in @var{directory}, then this function will
+fail. If @var{excl} is not set and @var{name} already exists the old
+file named @var{name} will be unlinked. If @var{directory} and
+@var{file} are not on the same filesystem, then @code{dir_link} might
+fail with @code{EXDEV}.
+@end deftypefun
+
+@deftypefun kern_return_t dir_rename (@w{file_t @var{olddirectory}}, @w{char *@var{oldname}}, @w{file_t @var{newdirectory}}, @w{char *@var{newname}}, @w{int @var{excl}})
+Move the node @var{oldname} in @var{olddirectory} to the node
+@var{newname} in @var{newdirectory}. If @var{excl} is set and
+@var{newname} already exists in @var{newdirectory}, then this function
+will fail. If @var{excl} is not set and @var{newname} already exists,
+the old file named @var{newname} will be unlinked. If
+@var{olddirectory} and @var{newdirectory} are not on the same
+filesystem, then @code{dir_rename} might fail with @code{EXDEV}.
+@end deftypefun
+
+@node Notifications
+@subsection Notifications
+
+FIXME: File and directory change callbacks
+
+File change notifications are not yet implemented, but directory
+notifications are.
+
+@code{file_notice_changes}
+
+@code{dir_notice_changes}
+
+@node File Translators
+@subsection File Translators
+
+FIXME: How to set and get translators
+
+@code{file_set_translator}
+
+@code{file_get_translator}
+
+@code{file_get_translator_cntl}
+
+
+@node Filesystem Interface
+@section Filesystem Interface
+@scindex fsys.defs
+
+The filesystem interface (described in @code{<hurd/fsys.defs>}) is
+supported by translator control ports.
+
+FIXME: finish
+
+
+@node Special Files
+@chapter Special Files
+
+In Unix, any file that does not act as a general-purpose unit of storage
+is called a @dfn{special file}. These are FIFOs, Unix-domain sockets,
+and device nodes. In the Hurd, there is no need for the ``special
+file'' distinction, since they are implemented by translators, just as
+regular files are.
+
+Nevertheless, the Hurd maintains this distinction, in order to provide
+backward compatibility for Unix programs (which do not know about
+translators). Studying the implementation of Hurd special files is a
+good way to introduce the idea of translators to people who are familiar
+with Unix.
+
+This chapter does not discuss @file{/dev/zero} or any of the
+microkernel-based devices, since these are translated by the generalized
+storeio server (FIXME xref).
+
+FIXME: finish
+
+@section fifo
+@section ifsock
+@section magic
+@section null
+
+
+FIXME: a chapter on libtreefs and libdirmgt will probably go here
+
+
+@node Stores
+@chapter Stores
+
+A @dfn{store} is a fixed-size block of storage, which can be read and
+perhaps written to. A store is more general than a file: it refers to
+any type of storage such as devices, files, memory, tasks, etc. Stores
+can also be representations of other stores, which may be combined and
+filtered in various ways.
+
+@menu
+* Store Library:: An abstract interface to storage systems.
+@end menu
+
+@section storeinfo, storecat, storeread
+@section storeio
+
+FIXME: finish
+
+@node Store Library
+@section Store Library
+@scindex libstore
+@scindex store.h
+
+The store library (which is declared in @code{<hurd/store.h>})
+implements many different backends which support the store abstraction.
+Hurd programs use @code{libstore} so that new storage types can be
+implemented with minimum impact.
+
+@menu
+* Store Arguments:: Parsing store command-line arguments.
+* Store Management:: Creating and manipulating stores.
+* Store I/O:: Reading and writing data to stores.
+* Store Classes:: Ready-to-use storage backends.
+* Store RPC Encoding:: Transferring store descriptors via RPC.
+@end menu
+
+
+@node Store Arguments
+@subsection Store Arguments
+
+FIXME: describe startup sequence
+
+@deftypevr {Structure} struct store_parsed
+The result of parsing a store, which should be enough information to
+open it, or return the arguments.
+@end deftypevr
+
+@deftypefn {Structure} struct store_argp_params @{ @w{struct store_parsed *@var{result}}; @w{const char *@var{default_type}}; @w{const struct store_class *const *@var{classes}}; @}
+This is the structure used to pass args back and forth from
+@var{store_argp}. @var{result} is the resulting parsed result. If
+@samp{--store-type} isn't specified, then @var{default_type} should be
+used as the store type; zero is equivalent to @code{"query"}.
+@var{classes} is set of classes used to validate store types and
+argument syntax.
+@end deftypefn
+
+@deftypevar {extern struct argp} store_argp
+This is an argument parser that may be used for parsing a simple command
+line specification for stores. The accompanying input parameter must be
+a pointer to a @code{struct store_argp_params}.
+@end deftypevar
+
+@deftypefun void store_parsed_free (@w{struct store_parsed *@var{parsed}})
+Free all resources used by @var{parsed}.
+@end deftypefun
+
+@deftypefun error_t store_parsed_open (@w{const struct store_parsed *@var{parsed}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Open the store specified by @var{parsed}, and return it in @var{store}.
+@end deftypefun
+
+@deftypefun error_t store_parsed_append_args (@w{const struct store_parsed *@var{parsed}}, @w{char **@var{argz}}, @w{size_t *@var{argz_len}})
+Add the arguments used to create @var{parsed} to @var{argz} and
+@var{argz_len}.
+@end deftypefun
+
+@deftypefun error_t store_parsed_name (@w{const struct store_parsed *@var{parsed}}, @w{char **@var{name}})
+Make an option string describing @var{parsed}, and return it in malloced
+storage in @var{name}.
+@end deftypefun
+
+
+@node Store Management
+@subsection Store Management
+
+The following functions provide basic management of stores:
+
+@deftypefun error_t store_create (@w{file_t @var{source}}, @w{int @var{flags}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{store}})
+Return a new store in @var{store}, which refers to the storage
+underlying @var{source}. @var{classes} is used to select classes
+specified by the provider; if zero, @var{store_std_classes} is used.
+@var{flags} is set with @code{store_set_flags}, with the exception of
+@code{STORE_INACTIVE}, which merely indicates that no attempt should be
+made to activate an inactive store; if @code{STORE_INACTIVE} is not
+specified, and the store returned for SOURCE is inactive, an attempt is
+made to activate it (failure of which causes an error to be returned).
+A reference to @var{source} is created (but may be destroyed with
+@code{store_close_source}).
+
+It is usually better to use a specific store open or create function
+such as @code{store_open} (@pxref{Store Classes}), since they are
+tailored to the needs of a specific store. Generally, you should only
+use @code{store_create} if you are defining your own store class, or you
+need options that are not provided by a more specific store creation
+function.
+@end deftypefun
+
+@deftypefun void store_close_source (@w{struct store *@var{store}})
+If @var{store} was created using @code{store_create}, remove the
+reference to the source from which it was created.
+@end deftypefun
+
+@deftypefun void store_free (@w{struct store *@var{store}})
+Clean up and deallocate @var{store}'s underlying stores.
+@end deftypefun
+
+@deftypefn {Structure} struct store_run @{ @w{store_offset_t @var{start}}, @var{length}; @}
+A @code{struct store_run} represents a contiguous region in a store's
+address range. These are used to designate active portions of a store.
+If @var{start} is -1, then the region is a @dfn{hole} (it is zero-filled
+and doesn't correspond to any real addresses).
+@end deftypefn
+
+@deftypefun error_t store_set_runs (@w{struct store *@var{store}}, @w{const struct store_run *@var{runs}}, @w{size_t @var{num_runs}})
+Set @var{store}'s current runs list to (a copy of) @var{runs} and
+@var{num_runs}.
+@end deftypefun
+
+@deftypefun error_t store_set_children (@w{struct store *@var{store}}, @w{struct store *const *@var{children}}, @w{size_t @var{num_children}})
+Set @var{store}'s current children to (a copy of) @var{children} and
+@var{num_children} (note that just the vector @var{children} is copied,
+not the actual children).
+@end deftypefun
+
+@deftypefun error_t store_children_name (@w{const struct store *@var{store}}, @w{char **@var{name}})
+Try to come up with a name for the children in @var{store}, combining
+the names of each child in a way that could be used to parse them with
+@code{store_open_children}. This is done heuristically, and so may not
+succeed. If a child doesn't have a name, @code{EINVAL} is returned.
+@end deftypefun
+
+@deftypefun error_t store_set_name (@w{struct store *@var{store}}, @w{const char *@var{name}})
+Sets the name associated with @var{store} to a copy of @var{name}.
+@end deftypefun
+
+@deftypefun error_t store_set_flags (@w{struct store *@var{store}}, @w{int @var{flags}})
+Add @var{flags} to @var{store}'s currently set flags.
+@end deftypefun
+
+@deftypefun error_t store_clear_flags (@w{struct store *@var{store}}, @w{int @var{flags}})
+Remove @var{flags} from @var{store}'s currently set flags.
+@end deftypefun
+
+@deftypefun error_t store_set_child_flags (@w{struct store *@var{store}}, @w{int @var{flags}})
+Set @var{flags} in all children of @var{store}, and if successful, add
+@var{flags} to @var{store}'s flags.
+@end deftypefun
+
+@deftypefun error_t store_clear_child_flags (@w{struct store *@var{store}}, @w{int @var{flags}})
+Clear @var{flags} in all children of @var{store}, and if successful,
+remove @var{flags} from @var{store}'s flags.
+@end deftypefun
+
+@deftypefun int store_is_securely_returnable (@w{struct store *@var{store}}, @w{int @var{open_flags}})
+Returns true if @var{store} can safely be returned to a user who has
+accessed it via a node using @var{open_flags}, without compromising
+security.
+@end deftypefun
+
+@deftypefun error_t store_clone (@w{struct store *@var{from}}, @w{struct store **@var{to}})
+Return a copy of @var{from} in @var{to}.
+@end deftypefun
+
+@deftypefun error_t store_remap (@w{struct store *@var{source}}, @w{const struct store_run *@var{runs}}, @w{size_t @var{num_runs}}, @w{struct store **@var{store}})
+Return a store in @var{store} that reflects the blocks in @var{runs} and
+@var{runs_len} from source; @var{source} is consumed, but not
+@var{runs}. Unlike the @code{store_remap_create} function, this may
+simply modify @var{source} and return it.
+@end deftypefun
+
+@c FIXME: what does `is consumed' mean?
+@c tb: gone; you can't use it any more. libstore has taken it over.
+
+@node Store I/O
+@subsection Store I/O
+
+The following functions allow you to read and modify the contents of a
+store:
+
+@deftypefun error_t store_map (@w{const struct store *@var{store}}, @w{vm_prot_t @var{prot}}, @w{mach_port_t *@var{memobj}})
+Return a memory object paging on @var{store}.
+@ignore @c FIXME: update if/when there are more pager-related functions
+If this call fails with @code{EOPNOTSUPP}, you can try calling some of
+the routines below to get a pager.
+@end ignore
+@end deftypefun
+
+@deftypefun error_t store_read (@w{struct store *@var{store}}, @w{store_offset_t @var{addr}}, @w{size_t @var{amount}}, @w{void **@var{buf}}, @w{size_t *@var{len}})
+Read @var{amount} bytes from @var{store} at @var{addr} into @var{buf}
+and @var{len} (which follows the usual Mach buffer-return semantics) to
+@var{store} at @var{addr}. @var{addr} is in @var{blocks} (as defined by
+@code{@var{store}->block_size}). Note that @var{len} is in bytes.
+@end deftypefun
+
+@c FIXME: should be say `Mach' above, or should we say
+@c `microkernel'?
+@c tb: nope, Mach-specific semantics.
+
+@deftypefun error_t store_write (@w{struct store *@var{store}}, @w{store_offset_t @var{addr}}, @w{void *@var{buf}}, @w{size_t @var{len}}, @w{size_t *@var{amount}})
+Write @var{len} bytes from @var{buf} to @var{store} at @var{addr}.
+Returns the amount written in @var{amount} (in bytes). @var{addr} is in
+@var{blocks} (as defined by @code{@var{store}->block_size}).
+@end deftypefun
+
+@deftypefun error_t store_set_size (@w{struct store *@var{store}}, @w{store_offset_t @var{newsize}})
+Set @var{store}'s size to @var{newsize} (in bytes).
+@end deftypefun
+
+@node Store Classes
+@subsection Store Classes
+
+The store library comes with a number of standard store class
+implementations:
+
+@deftypevar {extern const struct store_class *const} store_std_classes []
+This is a null-terminated vector of the standard store classes
+implemented by @code{libstore}.
+@end deftypevar
+
+If you are building your own class vectors, the following function may
+be useful:
+
+@deftypevar error_t store_concat_class_vectors (@w{struct store_class **@var{cv1}}, @w{struct store_class **@var{cv2}}, @w{struct store_class ***@var{concat}})
+Concatenate the store class vectors in @var{cv1} and @var{cv2}, and
+return a new (malloced) vector in @var{concat}.
+@end deftypevar
+
+@subsubsection @code{query} store
+@cindex @code{query} store
+
+@deftypevar {extern const struct store_class} store_query_class
+This store is a virtual store which queries a filesystem node, and
+delegates control to an appropriate store class.
+@end deftypevar
+
+@deftypefun error_t store_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{store}})
+Open the file @var{name}, and return a new store in @var{store}, which
+refers to the storage underlying it. @var{classes} is used to select
+classes specified by the provider; if it is zero, then
+@var{store_std_classes} is used. @var{flags} is set with
+@code{store_set_flags}. A reference to the open file is created (but
+may be destroyed with @code{store_close_source}).
+@end deftypefun
+
+@subsubsection @code{typed_open} store
+@cindex @code{typed_open} store
+
+@deftypevar {extern const struct store_class} store_typed_open_class
+This store is special in that it doesn't correspond to any specific
+store functions, rather it provides a way to interpret character strings
+as specifications for other stores.
+@end deftypevar
+
+@deftypefun error_t store_typed_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{store}})
+Open the store indicated by @var{name}, which should consist of a store
+type name followed by a @samp{:} and any type-specific name, returning the
+new store in @var{store}. @var{classes} is used to select classes
+specified by the type name; if it is zero, @var{store_std_classes} is
+used.
+@end deftypefun
+
+@deftypefun error_t store_open_children (@w{const char *@var{name}}, @w{int @var{flags}}, @w{const struct store_class *const *@var{classes}}, @w{struct store ***@var{stores}}, @w{size_t *@var{num_stores}})
+Parse multiple store names in @var{name}, and open each individually,
+returning all in the vector @var{stores}, and the number in
+@var{num_stores}. The syntax of @var{name} is a single non-alphanumeric
+separator character, followed by each child store name separated by the
+same separator; each child name is @samp{@var{type}:@var{name}} notation
+as parsed by @code{store_typed_open}. If every child uses the same
+@samp{@var{type}:} prefix, then it may be factored out and put before
+the child list instead (the two notations are differentiated by whether
+or not the first character of @var{name} is alphanumeric).
+@end deftypefun
+
+@subsubsection @code{device} store
+@cindex @code{device} store
+
+@cindex @code{device drivers}
+@deftypevar {extern const struct store_class} store_device_class
+This store is a simple wrapper for a microkernel device
+driver.@footnote{It is important to note that device drivers are not
+provided by the Hurd, but by the underlying microkernel. Hurd `devices'
+are just storeio-translated nodes which make the microkernel device
+drivers obey Hurd semantics. If you wish to implement a new device
+driver, you will need to consult the appropriate microkernel
+documentation.}
+@end deftypevar
+
+@deftypefun error_t store_device_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Open the device named @var{name}, and return the corresponding store in
+@var{store}.
+@end deftypefun
+
+@deftypefun error_t store_device_create (@w{device_t @var{device}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} referring to the microkernel device
+@var{device}. Consumes the @var{device} send right.
+@end deftypefun
+
+@subsubsection @code{file} store
+@cindex @code{file} store
+
+@deftypevar {extern const struct store_class} store_file_class
+This store reads and writes the contents of a Hurd file.
+@end deftypevar
+
+@deftypefun error_t store_file_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Open the file @var{name}, and return the corresponding store in @var{store}.
+@end deftypefun
+
+@deftypefun error_t store_file_create (@w{file_t @var{file}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} referring to the file @var{file}.
+Unlike @code{store_create}, this will always use file I/O, even it would
+be possible to be more direct. This may work in more cases, for instance
+if the file has holes. Consumes the @var{file} send right.
+@end deftypefun
+
+@subsubsection @code{task} store
+@cindex @code{task} store
+
+@deftypevar {extern const struct store_class} store_task_class
+This store provides access to the contents of a microkernel task.
+@end deftypevar
+
+@deftypevar error_t store_task_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Open the task @var{name} (@var{name} should be the task's pid), and
+return the corresponding store in @var{store}.
+@end deftypevar
+
+@deftypevar {error_t} store_task_create (@w{task_t @var{task}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} referring to the task @var{task},
+consuming the @var{task} send right.
+@end deftypevar
+
+@subsubsection @code{zero} store
+@cindex @code{zero} store
+
+@deftypevar {extern const struct store_class} store_zero_class
+Reads to this store always return zero-filled buffers, no matter what
+has been written into it. This store corresponds to the Unix
+@file{/dev/zero} device node.
+@end deftypevar
+
+@deftypefun error_t store_zero_create (@w{store_offset_t @var{size}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new zero store @var{size} bytes long in @var{store}.
+@end deftypefun
+
+@subsubsection @code{copy} store
+@cindex @code{copy} store
+
+@deftypevar {extern const struct store_class} store_copy_class
+This store provides a temporary copy of another store. This is useful
+if you want to provide writable data, but do not wish to modify the
+underlying store. All changes to a copy store are lost when it is
+closed.
+@end deftypevar
+
+@deftypefun error_t store_copy_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{store}})
+Open the copy store @var{name} (which consists of another store class
+name, a @samp{:}, and a name for the store class to open) and return the
+corresponding store in @var{store}. @var{classes} is used to select
+classes specified by the type name; if it is zero,
+@var{store_std_classes} is used.
+@end deftypefun
+
+@deftypefun error_t store_copy_create (@w{struct store *@var{from}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} which contains a snapshot of the
+contents of the store @var{from}; @var{from} is consumed.
+@end deftypefun
+
+@deftypefun error_t store_buffer_create (@w{void *@var{buf}}, @w{size_t @var{buf_len}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} which contains the memory buffer
+@var{buf}, of length @var{buf_len}. @var{buf} must be allocated with
+@code{vm_allocate}, and will be consumed.
+@end deftypefun
+
+@subsubsection @code{gunzip} store
+@cindex @code{gunzip} store
+
+@deftypevar {extern const struct store_class} store_gunzip_class
+This store provides transparent GNU zip decompression of a substore.
+Unfortunately, this store is currently read-only.
+@end deftypevar
+
+@deftypevar error_t store_gunzip_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{store}})
+Open the gunzip store @var{name} (which consists of another store class
+name, a @samp{:}, and a name for that store class to open), and return
+the corresponding store in @var{store}. @var{classes} is used to select
+classes specified by the type name; if it is zero,
+@var{store_std_classes} is used.
+@end deftypevar
+
+@deftypevar error_t store_gunzip_create (@w{struct store *@var{from}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} which contains a snapshot of the
+uncompressed contents of the store @var{from}; @var{from} is consumed.
+@var{block_size} is the desired block size of the result.
+@end deftypevar
+
+@subsubsection @code{concat} store
+@cindex @code{concat} store
+
+@cindex linear concatenation
+@cindex appending disks
+@cindex disks, appending
+@cindex disk concatenation
+@cindex concatenation, disk
+@deftypevar {extern const struct store_class} store_concat_class
+This class provides a linear concatenation storage mode. It creates a
+new virtual store which consists of several different substores appended
+to one another.
+
+This mode is designed to increase storage capacity, so that when one
+substore is filled, new data is transparently written to the next
+substore. Concatenation requires robust hardware, since a failure in
+any single substore will wipe out a large section of the data.
+@end deftypevar
+
+@deftypefun error_t store_concat_open (@w{const char *@var{name}}, @w{int @var{flags}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{store}})
+Return a new store that concatenates the stores created by opening all
+the individual stores described in @var{name}; for the syntax of
+@var{name}, see @code{store_open_children}.
+@end deftypefun
+
+@deftypefun error_t store_concat_create (@w{struct store * const *@var{stores}}, @w{size_t @var{num_stores}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} that concatenates all the stores in
+@var{stores} (@var{num_stores} of them). The stores in @var{stores} are
+consumed; that is, they will be freed when this store is freed. The
+@var{stores} @emph{array}, however, is copied, and so should be freed by
+the caller.
+@end deftypefun
+
+@subsubsection @code{ileave} store
+@cindex @code{ileave} store
+
+@cindex RAID-0
+@cindex striping, disk
+@cindex disk striping
+@cindex interleaving disks
+@cindex disks, interleaving
+@deftypevar {extern const struct store_class} store_ileave_class
+This class provides a RAID-0@footnote{``RAID'' stands for @dfn{Redundant Array of
+Independent Disks}: several disks used in
+parallel to achieve increased capacity, redundancy and/or
+performance.} storage mode (also called @dfn{disk striping}). It
+creates a new virtual store by interleaving the contents of several
+different substores.
+
+This RAID mode is designed to increase storage performance, since I/O
+will probably occur in parallel if the substores reside on different
+physical devices. Interleaving works best with evenly-yoked
+substores@dots{} if the stores are different sizes, some space will be
+not be used at the end of the larger stores; if the stores are different
+speeds, then I/O will have to wait for the slowest store; if some stores
+are not as reliable as others, failures will wipe out every @var{n}th
+storage block, where @var{n} is the number of substores.
+@end deftypevar
+
+@deftypefun error_t store_ileave_create (@w{struct store * const *@var{stripes}}, @w{size_t @w{num_stripes}}, @w{store_offset_t @var{interleave}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} that interleaves all the stores in
+@var{stripes} (@var{num_stripes} of them) every @var{interleave} bytes;
+@var{interleave} must be an integer multiple of each stripe's block
+size. The stores in @var{stripes} are consumed; that is, they will be
+freed when this store is freed. The @var{stripes} @emph{array},
+however, is copied, and so should be freed by the caller.
+@end deftypefun
+
+@subsubsection @code{mvol} store
+@cindex @code{mvol} store
+
+@deftypevar {extern const struct store_class} store_mvol_class
+This store provides access to multiple volumes using a single-volume
+device. One use of this store would be to provide a store which
+consists of multiple floppy disks when there is only a single disk
+drive. It works by remapping a single linear address range to multiple
+address ranges, and keeping track of the currently active range.
+Whenever a request maps to a range that is not active, a callback is
+made in order to switch to the new range.
+
+This class is not included in @var{store_std_classes}, because it
+requires an application-specific callback.
+@end deftypevar
+
+@deftypefun error_t store_mvol_create (@w{struct store *@var{phys}}, error_t (*@var{swap_vols}) (@w{struct store *@var{store}}, @w{size_t @var{new_vol}}, @w{ssize_t @var{old_vol}}), @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} that multiplexes multiple physical
+volumes from @var{phys} as one larger virtual volume. @var{swap_vols}
+is a function that will be called whenever reads or writes refer to a
+block which is not addressable on the currently active volume.
+@var{phys} is consumed.
+@end deftypefun
+
+@subsubsection @code{remap} store
+@pindex @code{remap} store
+
+@deftypevar {extern const struct store_class} store_remap_class
+This store translates I/O requests into different addresses on a
+different store.
+@end deftypevar
+
+@deftypefun error_t store_remap_create (@w{struct store *@var{source}}, @w{const struct store_run *@var{runs}}, @w{size_t @var{num_runs}}, @w{int @var{flags}}, @w{struct store **@var{store}})
+Return a new store in @var{store} that reflects the blocks in @var{runs}
+and @var{runs_len} from @var{source}; @var{source} is consumed, but
+@var{runs} is not. Unlike the @code{store_remap} function, this
+function always operates by creating a new store of type @samp{remap}
+which has @var{source} as a child, and so may be less efficient than
+@code{store_remap} for some types of stores.
+@end deftypefun
+
+
+@node Store RPC Encoding
+@subsection Store RPC Encoding
+
+The store library also provides some functions which help transfer
+stores between tasks via RPC:
+
+@deftypevr {Structure} struct store_enc
+This structure is used to hold the various bits that make up the
+representation of a store for transmission via RPC. See
+@code{<hurd/hurd_types.h>} for an explanation of the encodings for the
+various storage types.
+@end deftypevr
+
+@deftypefun void store_enc_init (@w{struct store_enc *@var{enc}}, @w{mach_port_t *@var{ports}}, @w{mach_msg_type_number_t @var{num_ports}}, @w{int *@var{ints}}, @w{mach_msg_type_number_t @var{num_ints}}, @w{off_t *@var{offsets}}, @w{mach_msg_type_number_t @var{num_offsets}}, @w{char *@var{data}}, @w{mach_msg_type_number_t @var{data_len}})
+Initialize @var{enc}. The given vector and sizes will be used for the
+encoding if they are big enough (otherwise new ones will be
+automatically allocated).
+@end deftypefun
+
+@deftypefun void store_enc_dealloc (@w{struct store_enc *@var{enc}})
+Deallocate storage used by the fields in @var{enc} (but nothing is done
+with @var{enc} itself).
+@end deftypefun
+
+@deftypefun void store_enc_return (@w{struct store_enc *@var{enc}}, @w{mach_port_t **@var{ports}}, @w{mach_msg_type_number_t *@var{num_ports}}, @w{int **@var{ints}}, @w{mach_msg_type_number_t *@var{num_ints}}, @w{off_t **@var{offsets}}, @w{mach_msg_type_number_t *@var{num_offsets}}, @w{char **@var{data}}, @w{mach_msg_type_number_t *@var{data_len}})
+Copy out the parameters from @var{enc} into the given variables suitably
+for returning from a @code{file_get_storage_info} RPC, and deallocate
+@var{enc}.
+@end deftypefun
+
+@deftypefun error_t store_return (@w{const struct store *@var{store}}, @w{mach_port_t **@var{ports}}, @w{mach_msg_type_number_t *@var{num_ports}}, @w{int **@var{ints}}, @w{mach_msg_type_number_t *@var{num_ints}}, @w{off_t **@var{offsets}}, @w{mach_msg_type_number_t *@var{num_offsets}}, @w{char **@var{data}}, @w{mach_msg_type_number_t *@var{data_len}})
+Encode @var{store} into the given return variables, suitably for
+returning from a @code{file_get_storage_info} RPC.
+@end deftypefun
+
+@deftypefun error_t store_encode (@w{const struct store *@var{store}}, @w{struct store_enc *@var{enc}})
+Encode @var{store} into @var{enc}, which should have been prepared with
+@code{store_enc_init}, or return an error. The contents of @var{enc}
+may then be returned as the value of @code{file_get_storage_info}; if
+for some reason this can't be done, @code{store_enc_dealloc} may be used
+to deallocate the memory used by the unsent vectors.
+@end deftypefun
+
+@deftypefun error_t store_decode (@w{struct store_enc *@var{enc}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{store}})
+Decode @var{enc}, either returning a new store in @var{store}, or an
+error. @var{classes} is the mapping from Hurd storage class ids to store
+classes; if it is zero, @var{store_std_classes} is used. If nothing
+else is to be done with @var{enc}, its contents may then be freed using
+@code{store_enc_dealloc}.
+@end deftypefun
+
+@deftypefun error_t store_allocate_child_encodings (@w{const struct store *@var{store}}, @w{struct store_enc *@var{enc}})
+Calls the @code{allocate_encoding} method in each child store of
+@var{store}, propagating any errors. If any child does not have such a
+method, @code{EOPNOTSUPP} is returned.
+@end deftypefun
+
+@deftypefun error_t store_encode_children (@w{const struct store *@var{store}}, @w{struct store_enc *@var{enc}})
+Calls the encode method in each child store of @var{store}, propagating
+any errors. If any child does not have such a method, @code{EOPNOTSUPP}
+is returned.
+@end deftypefun
+
+@deftypefun error_t store_decode_children (@w{struct store_enc *@var{enc}}, @w{int @var{num_children}}, @w{const struct store_class *const *@var{classes}}, @w{struct store **@var{children}})
+Decodes @var{num_children} from @var{enc}, storing the results into
+successive positions in @var{children}.
+@end deftypefun
+
+@deftypefun error_t store_with_decoded_runs (@w{struct store_enc *@var{enc}}, @w{size_t @var{num_runs}}, error_t (*@var{fun}) (@w{const struct store_run *@var{runs}}, @w{size_t @var{num_runs}}))
+Call @var{fun} with the vector @var{runs} of length @var{num_runs}
+extracted from @var{enc}.
+@end deftypefun
+
+@deftypefun error_t store_std_leaf_allocate_encoding (@w{const struct store *@var{store}}, @w{struct store_enc *@var{enc}})
+@deftypefunx error_t store_std_leaf_encode (@w{const struct store *@var{store}}, @w{struct store_enc *@var{enc}})
+Standard encoding used for most data-providing (as opposed to filtering)
+store classes.
+@end deftypefun
+
+@deftypefn {Typedef} typedef error_t (*store_std_leaf_create_t) (@w{mach_port_t @var{port}}, @w{int @var{flags}}, @w{size_t @var{block_size}}, @w{const struct store_run *@var{runs}}, @w{size_t @var{num_runs}}, @w{struct store **@var{store}})
+Creation function used by @code{store_std_leaf_decode}.
+@end deftypefn
+
+@deftypefun error_t store_std_leaf_decode (@w{struct store_enc *@var{enc}}, @w{store_std_leaf_create_t @var{create}}, @w{struct store **@var{store}})
+Decodes the standard leaf encoding which is common to various builtin
+formats, and calls @var{create} to actually create the store.
+@end deftypefun
+
+
+@node Stored Filesystems
+@chapter Stored Filesystems
+@cindex disk-based filesystems
+@cindex filesystems, disk-based
+
+Stored filesystems allow users to save and load persistent data from any
+random-access storage media, such as hard disks, floppy diskettes, and
+CD-ROMs. Stored filesystems are required for bootstrapping standalone
+workstations, as well.
+
+@menu
+* Repairing Filesystems:: Recovering from minor filesystem crashes.
+* Linux Extended 2 FS:: The popular Linux filesystem format.
+* BSD Unix FS:: The BSD Unix 4.x Fast File System.
+* ISO-9660 CD-ROM FS:: Standard CD-ROM format.
+* Diskfs Library:: Implementing new filesystem servers.
+@end menu
+
+
+@node Repairing Filesystems
+@section Repairing Filesystems
+@pindex fsck
+
+FIXME: finish
+
+
+@node Linux Extended 2 FS
+@section Linux Extended 2 FS
+@pindex ext2fs
+
+FIXME: finish
+
+
+@node BSD Unix FS
+@section BSD Unix FS
+@scindex ufs
+
+FIXME: finish
+
+
+@node ISO-9660 CD-ROM FS
+@section ISO-9660 CD-ROM FS
+@pindex iso9660fs
+
+FIXME: finish
+
+
+@node Diskfs Library
+@section Diskfs Library
+@scindex libdiskfs
+@scindex diskfs.h
+
+The diskfs library is declared in @code{<hurd/diskfs.h>}, and does a lot
+of the work of implementing stored filesystems. @code{libdiskfs}
+requires the threads, ports, iohelp, fshelp, and store libraries. You
+should understand all these libraries before you attempt to use diskfs,
+and you should also be familiar with the pager library (@pxref{Pager
+Library}).
+
+@scindex libstorefs
+For historical reasons, the library for implementing stored filesystems
+is called @code{libdiskfs} instead of @code{libstorefs}. Keep in mind,
+however, that diskfs is useful for filesystems which are implemented on
+any block-addressed storage device, since it uses the store library to
+do I/O.
+
+Note that stored filesystems can be tricky to implement, since the
+diskfs callback interfaces are not trivial. It really is best if you
+examine the source code of a similar existing filesystem server, and
+follow its example rather than trying to write your own from scratch.
@menu
-* Rules:: The rules users must obey in using
- shared I/O.
-* Examples:: Examples of the way different types
- of servers could implement shared I/O.
+* Diskfs Startup:: Initializing stored filesystems.
+* Diskfs Arguments:: Parsing command-line arguments.
+* Diskfs Globals:: Global behaviour modification.
+* Diskfs Node Management:: Allocation, reference counting, I/O,
+ caching, and other disk node routines.
+* Diskfs Callbacks:: Mandatory user-defined diskfs functions.
+* Diskfs Options:: Optional user-defined diskfs functions.
+* Diskfs Internals:: Reimplementing small pieces of diskfs.
@end menu
-@node Rules
-@section Rules
-Any server implementing the facilities of this chapter must also support
-the io_map call as described in the previous chapter.
+@node Diskfs Startup
+@subsection Diskfs Startup
+
+This subsection gives an outline of the general steps involved in
+implementing a filesystem server, to help refresh your memory and to
+offer explanations rather than to serve as a tutorial.
+
+The first thing a filesystem server should do is parse its command-line
+arguments (@pxref{Diskfs Arguments}). Then, the standard output and
+error streams should be redirected to the console, so that error
+messages are not lost if this is the bootstrap filesystem:
+
+@deftypefun void diskfs_console_stdio (void)
+Redirect error messages to the console, so that they can be seen by
+users.
+@end deftypefun
+
+The following is a list of the relevant functions which would be called
+during the rest of the server initialization. Again, you should refer
+to the implementation of an already-working filesystem if you have any
+questions about how these functions should be used:
+
+@deftypefun error_t diskfs_init_diskfs (void)
+Call this function after arguments have been parsed to initialize the
+library. You must call this before calling any other diskfs functions,
+and after parsing diskfs options.
+@end deftypefun
+
+@deftypefun void diskfs_spawn_first_thread (void)
+Call this after all format-specific initialization is done (except for
+setting @code{diskfs_root_node}); at this point the pagers should be
+ready to go.
+@end deftypefun
+
+@deftypefun mach_port_t diskfs_startup_diskfs (@w{mach_port_t @var{bootstrap}}, @w{int @var{flags}})
+Call this once the filesystem is fully initialized, to advertise the new
+filesystem control port to our parent filesystem. If @var{bootstrap} is set,
+diskfs will call @code{fsys_startup} on that port as appropriate and return
+the @var{realnode} from that call; otherwise we call
+@code{diskfs_start_bootstrap} and return @code{MACH_PORT_NULL}.
+@var{flags} specifies how to open @var{realnode} (from the @code{O_*} set).
+@end deftypefun
+
+You should not need to call the following function directly, since
+@code{diskfs_startup_diskfs} will do it for you, when appropriate:
+
+@deftypefun void diskfs_start_bootstrap (void)
+Start the Hurd bootstrap sequence as if we were the bootstrap filesystem
+(that is, @code{diskfs_boot_flags} is nonzero). All filesystem
+initialization must be complete before you call this function.
+@end deftypefun
+
+
+@node Diskfs Arguments
+@subsection Diskfs Arguments
+
+The following functions implement standard diskfs command-line and
+runtime argument parsing, using argp (@pxref{Argp, , , libc, The GNU C
+Library Reference Manual}):
+
+@deftypefun error_t diskfs_set_options (@w{char *@var{argz}}, @w{size_t @var{argz_len}})
+Parse and execute the runtime options specified by @var{argz} and
+@var{argz_len}. @code{EINVAL} is returned if some option is
+unrecognized. The default definition of this routine will parse them
+using @code{diskfs_runtime_argp}.
+@end deftypefun
+
+@deftypefun error_t diskfs_append_args (@w{char **@var{argz}}, @w{unsigned *@var{argz_len}})
+Append to the malloced string @code{*@var{argz}} of length
+@code{*@var{argz_len}} a NUL-separated list of the arguments to this
+translator. The default definition of this routine simply calls
+@code{diskfs_append_std_options}.
+@end deftypefun
+
+@deftypefun error_t diskfs_append_std_options (@w{char **@var{argz}}, @w{unsigned *@var{argz_len}})
+@emph{Appends} NUL-separated options describing the standard diskfs
+option state to @var{argz} and increments @var{argz_len} appropriately.
+Note that unlike @code{diskfs_get_options}, @var{argz} and
+@var{argz_len} must already have sane values.
+@end deftypefun
+
+@deftypevar {struct argp *} diskfs_runtime_argp
+If this is defined or set to an argp structure, it will be used by the
+default @code{diskfs_set_options} to handle runtime option parsing. The
+default definition is initialized to a pointer to
+@code{diskfs_std_runtime_argp}.
+@end deftypevar
+
+@deftypevar {const struct argp} diskfs_std_runtime_argp
+An argp for the standard diskfs runtime options. The default definition
+of @code{diskfs_runtime_argp} points to this, although the user can
+redefine that to chain this onto his own argp.
+@end deftypevar
+
+@deftypevar {const struct argp} diskfs_startup_argp
+An argp structure for the standard diskfs command line arguments. The
+user may call @code{argp_parse} on this to parse the command line, chain
+it onto the end of his own argp structure, or ignore it completely.
+@end deftypevar
+
+@deftypevar {const struct argp} diskfs_store_startup_argp
+An argp structure for the standard diskfs command line arguments plus a
+store specification. The address of a location in which to return the
+resulting @code{struct store_parsed} structure should be passed as the
+input argument to @code{argp_parse}; FIXME xref the declaration for
+STORE_ARGP.
+@end deftypevar
+
+
+@node Diskfs Globals
+@subsection Diskfs Globals
+
+The following functions and variables control the overall behaviour of
+the library. Your callback functions may need to refer to these, but
+you should not need to modify or redefine them.
+
+@deftypevar mach_port_t diskfs_default_pager
+@deftypevarx mach_port_t diskfs_exec_ctl
+@deftypevarx mach_port_t diskfs_exec
+@deftypevarx auth_t diskfs_auth_server_port
+These are the respective send rights to the default pager, execserver
+control port, execserver itself, and authserver.
+@end deftypevar
+
+@deftypevar mach_port_t diskfs_fsys_identity
+The @code{io_identity} identity port for the filesystem.
+@end deftypevar
+
+@deftypevar {char **} diskfs_argv
+The command line with which diskfs was started, set by the default argument parser.
+If you don't use it, set this yourself. This is only used for bootstrap
+file systems, to give the procserver.
+@end deftypevar
+
+@deftypevar {char *} diskfs_boot_flags
+When this is a bootstrap filesystem, the command line options passed from
+the kernel. If not a bootstrap filesystem, it is zero, so it can be used to
+distinguish between the two cases.
+@end deftypevar
+
+@deftypevar {struct rwlock} diskfs_fsys_lock
+Hold this lock while doing filesystem-level operations. Innocuous users
+can just hold a reader lock, but operations that might corrupt other
+threads should hold a writer lock.
+@end deftypevar
+
+@deftypevar {volatile struct mapped_time_value *} diskfs_mtime
+The current system time, as used by the diskfs routines. This is
+converted into a @code{struct timeval} by the @code{maptime_read}
+C library function (FIXME xref).
+@end deftypevar
+
+@deftypevar int diskfs_synchronous
+True if and only if we should do every operation synchronously. It
+is the format-specific code's responsibility to keep allocation
+information permanently in sync if this is set; the rest will
+be done by format-independent code.
+@end deftypevar
+
+@deftypefun error_t diskfs_set_sync_interval (@w{int @var{interval}})
+Establish a thread to sync the filesystem every @var{interval} seconds,
+or never, if @var{interval} is zero. If an error occurs creating the
+thread, it is returned, otherwise zero. Subsequent calls will create a
+new thread and (eventually) get rid of the old one; the old thread won't
+do any more syncs, regardless.
+@end deftypefun
+
+@deftypevar spin_lock_t diskfs_node_refcnt_lock
+Pager reference count lock.
+@end deftypevar
+
+@deftypevar int diskfs_readonly
+Set to zero if the filesystem is currently writable.
+@end deftypevar
+
+@deftypefun error_t diskfs_set_readonly (@w{int @var{readonly}})
+Change an active filesystem between read-only and writable modes,
+setting the global variable @var{diskfs_readonly} to reflect the current
+mode. If an error is returned, nothing will have changed.
+@var{diskfs_fsys_lock} should be held while calling this routine.
+@end deftypefun
+
+@deftypefun int diskfs_check_readonly (void)
+Check if the filesystem is readonly before an operation that writes it.
+Return nonzero if readonly, otherwise zero.
+@end deftypefun
+
+@deftypefun error_t diskfs_remount (void)
+Reread all in-core data structures from disk. This function can only be
+successful if @var{diskfs_readonly} is true. @var{diskfs_fsys_lock}
+should be held while calling this routine.
+@end deftypefun
+
+@deftypefun error_t diskfs_shutdown (@w{int @var{flags}})
+Shutdown the filesystem; @var{flags} are as for @code{fsys_shutdown}.
+@end deftypefun
+
+
+@node Diskfs Node Management
+@subsection Diskfs Node Management
+
+Every file or directory is a diskfs @dfn{node}. The following functions
+help your diskfs callbacks manage nodes and their references:
+
+@deftypefun void diskfs_drop_node (@w{struct node *@var{np}})
+Node @var{np} now has no more references; clean all state. The
+@var{diskfs_node_refcnt_lock} must be held, and will be released upon
+return. @var{np} must be locked.
+@end deftypefun
+
+@deftypefun void diskfs_node_update (@w{struct node *@var{np}}, @w{int @var{wait}})
+Set disk fields from @code{@var{np}->dn_stat}; update ctime, atime, and mtime
+if necessary. If @var{wait} is true, then return only after the
+physical media has been completely updated.
+@end deftypefun
+
+@deftypefun void diskfs_nref (@w{struct node *@var{np}})
+Add a hard reference to node @var{np}. If there were no hard references
+previously, then the node cannot be locked (because you must hold a hard
+reference to hold the lock).
+@end deftypefun
+
+@deftypefun void diskfs_nput (@w{struct node *@var{np}})
+Unlock node @var{np} and release a hard reference; if this is the last
+hard reference and there are no links to the file then request light
+references to be dropped.
+@end deftypefun
+
+@deftypefun void diskfs_nrele (@w{struct node *@var{np}})
+Release a hard reference on @var{np}. If @var{np} is locked by anyone,
+then this cannot be the last hard reference (because you must hold a
+hard reference in order to hold the lock). If this is the last hard
+reference and there are no links, then request light references to be
+dropped.
+@end deftypefun
+
+@deftypefun void diskfs_nref_light (@w{struct node *@var{np}})
+Add a light reference to a node.
+@end deftypefun
+
+@deftypefun void diskfs_nput_light (@w{struct node *@var{np}})
+Unlock node @var{np} and release a light reference.
+@end deftypefun
+
+@deftypefun void diskfs_nrele_light (@w{struct node *@var{np}})
+Release a light reference on @var{np}. If @var{np} is locked by anyone,
+then this cannot be the last reference (because you must hold a hard
+reference in order to hold the lock).
+@end deftypefun
+
+@deftypefun error_t diskfs_node_rdwr (@w{struct node *@var{np}}, @w{char *@var{data}}, @w{off_t @var{off}}, @w{size_t @var{amt}}, @w{int @var{direction}}, @w{struct protid *@var{cred}}, @w{size_t *@var{amtread}})
+This is called by other filesystem routines to read or write files, and
+extends them automatically, if necessary. @var{np} is the node to be
+read or written, and must be locked. @var{data} will be written or
+filled. @var{off} identifies where in the file the I/O is to take place
+(negative values are not allowed). @var{amt} is the size of @var{data}
+and tells how much to copy. @var{dir} is zero for reading or nonzero
+for writing. @var{cred} is the user doing the access (only used to
+validate attempted file extension). For reads, @code{*@var{amtread}} is
+filled with the amount actually read.
+@end deftypefun
+
+@deftypefun void diskfs_notice_dirchange (@w{struct node *@var{dp}}, @w{enum dir_changed_type @var{type}}, @w{char *@var{name}})
+Send notifications to users who have requested them for directory
+@var{dp} with @code{dir_notice_changes}. The type of modification and
+affected name are @var{type} and @var{name} respectively. This should
+be called by @code{diskfs_direnter}, @code{diskfs_dirremove},
+@code{diskfs_dirrewrite}, and anything else that changes the directory,
+after the change is fully completed.
+@end deftypefun
+
+@deftypefun {struct node *} diskfs_make_node (@w{struct disknode *@var{dn}})
+Create a new node structure with @var{ds} as its physical disknode. The
+new node will have one hard reference and no light references.
+@end deftypefun
+
+@c FIXME: It's odd that `hard' and `light' seem to be opposites when
+@c we're talking about references. Or is `weak' the opposite of `hard'?
+@c These terms need to be explained.
+@c tb: hard is opposite to both light and weak, but we don't use both
+@c tb: light and weak in the same context, so it's ok.
+
+These next node manipulation functions are not generally useful, but may
+come in handy if you need to redefine any diskfs functions.
+
+@deftypefun error_t diskfs_create_node (@w{struct node *@var{dir}}, @w{char *@var{name}}, @w{mode_t @var{mode}}, @w{struct node **@var{newnode}}, @w{struct protid *@var{cred}}, @w{struct dirstat *@var{ds}})
+Create a new node. Give it @var{mode}: if @var{mode} includes
+@code{IFDIR}, also initialize @file{.} and @file{..} in the new
+directory. Return the node in @var{npp}. @var{cred} identifies the
+user responsible for the call. If @var{name} is nonzero, then link the
+new node into @var{dir} with name @var{name}; @var{ds} is the result of
+a prior @code{diskfs_lookup} for creation (and @var{dir} has been held
+locked since). @var{dir} must always be provided as at least a hint for
+disk allocation strategies.
+@end deftypefun
+
+@deftypefun void diskfs_set_node_atime (@w{struct node *@var{np}})
+If disk is not readonly and the noatime option is not enabled, set
+@code{@var{np}->dn_set_atime}.
+@end deftypefun
+
+@deftypefun void diskfs_set_node_times (@w{struct node *@var{np}})
+If @code{@var{np}->dn_set_ctime} is set, then modify
+@code{@var{np}->dn_stat.st_ctim} appropriately; do the analogous
+operations for @code{st_atim} and @code{st_mtim} as well.
+@end deftypefun
+
+@deftypefun {struct node *} diskfs_check_lookup_cache (@w{struct node *@var{dir}}, @w{char *@var{name}})
+Scan the cache looking for @var{name} inside @var{dir}. If we don't
+know any entries at all, then return zero. If the entry is confirmed to
+not exist, then return -1. Otherwise, return @var{np} for the entry,
+with a newly-allocated reference.
+@end deftypefun
+
+@deftypefun error_t diskfs_cached_lookup (@w{int @var{cache_id}}, @w{struct node **@var{npp}})
+Return the node corresponding to @var{cache_id} in @code{*@var{npp}}.
+@end deftypefun
+
+@deftypefun void diskfs_enter_lookup_cache (@w{struct node *@var{dir}}, @w{struct node *@var{np}}, @w{char *@var{name}})
+Node @var{np} has just been found in @var{dir} with @var{name}. If
+@var{np} is null, that means that this name has been confirmed as absent
+in the directory.
+@end deftypefun
+
+@deftypefun void diskfs_purge_lookup_cache (@w{struct node *@var{dp}}, @w{struct node *@var{np}})
+Purge all references in the cache to @var{np} as a node inside directory
+@var{dp}.
+@end deftypefun
+
+
+@node Diskfs Callbacks
+@subsection Diskfs Callbacks
+
+Like several other Hurd libraries, @code{libdiskfs} depends on you to
+implement application-specific callback functions. You @emph{must}
+define the following functions and variables, but you should also look
+at @ref{Diskfs Options}, as there are several defaults which should be
+modified to provide good filesystem support:
+
+@deftypevr {Structure} struct dirstat
+You must define this type, which will hold information between a call to
+@code{diskfs_lookup} and a call to one of @code{diskfs_direnter},
+@code{diskfs_dirremove}, or @code{diskfs_dirrewrite}. It must contain
+enough information so that those calls work as described below.
+@end deftypevr
+
+@deftypevar const size_t diskfs_dirstat_size
+This must be the size in bytes of a @code{struct dirstat}.
+@end deftypevar
+
+@deftypevar int diskfs_link_max
+This is the maximum number of links to any one file, which must be a
+positive integer. The implementation of @code{dir_rename} does not know
+how to succeed if this is only one allowed link; on such formats you
+need to reimplement @code{dir_rename} yourself.
+@end deftypevar
+
+@deftypevar int diskfs_maxsymlinks
+This variable is a positive integer which is the maximum number of
+symbolic links which can be traversed within a single call to
+@code{dir_lookup}. If this is exceeded, @code{dir_lookup} will
+return @code{ELOOP}.
+@end deftypevar
+
+@deftypevar {struct node *} diskfs_root_node
+Set this to be the node of the root of the filesystem.
+@end deftypevar
+
+@deftypevar {char *} diskfs_server_name
+Set this to the name of the filesystem server.
+@end deftypevar
+
+@deftypevar {char *} diskfs_server_version
+Set this to be the server version string.
+@end deftypevar
+
+@deftypevar {char *} diskfs_disk_name
+This should be a string that somehow identifies the particular disk this
+filesystem is interpreting. It is generally only used to print messages
+or to distinguish instances of the same filesystem type from one
+another. If this filesystem accesses no external media, then define
+this to be zero.
+@end deftypevar
-Users of the shared I/O facilities must call io_map_cntl; this will
-return a memory object, called the shared page object. One page of this
-object should be mapped from offset zero into the user's address space.
-At the front of this page is a struct shared_io as described in
-<hurd/shared.h>. Frequent reference will be made to the members of this
-structure in this chapter, without further qualification. The shared
-page past the struct shared_io may be used by users as they wish.
+@deftypefun error_t diskfs_set_statfs (@w{fsys_statfsbuf_t *@var{statfsbuf}})
+Set @code{*@var{statfsbuf}} with appropriate values to reflect the
+current state of the filesystem.
+@end deftypefun
-Users should examine the shared_page_magic field; from it they can
-discover the byte ordering used by the server. Users should not blindly
-assume that the server uses the same byte ordering as they.
+@deftypefun error_t diskfs_lookup (@w{struct node *@var{dp}}, @w{const char *@var{name}}, @w{enum lookup_type @var{type}}, @w{struct node **@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}})
+@deftypefunx error_t diskfs_lookup_hard (@w{struct node *@var{dp}}, @w{const char *@var{name}}, @w{enum lookup_type @var{type}}, @w{struct node **@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}})
+You should not define @code{diskfs_lookup}, because it is simply a
+wrapper for @code{diskfs_lookup_hard}, and is already defined in
+@code{libdiskfs}.
-Only one shared user can be active on a given port at a time. If a user
-calls io_map_cntl on a port which already has an active shared user, the
-server should return EBUSY, at which point the user should call
-io_duplicate to obtain a new port, and call io_map_cntl there.
+Lookup in directory @var{dp} (which is locked) the name @var{name}.
+@var{type} will either be @code{LOOKUP}, @code{CREATE}, @code{RENAME},
+or @code{REMOVE}. @var{cred} identifies the user making the call.
+
+If the name is found, return zero, and (if @var{np} is nonzero) set
+@code{*@var{np}} to point to the node for it, which should be locked.
+If the name is not found, return @code{ENOENT}, and (if @var{np} is
+nonzero) set @code{*@var{np}} to zero. If @var{np} is zero, then the
+node found must not be locked, not even transitorily. Lookups for
+@code{REMOVE} and @code{RENAME} (which must often check permissions on
+the node being found) will always set @var{np}.
+
+If @var{ds} is nonzero then the behaviour varies depending on the
+requested lookup @var{type}:
+
+@table @code
+@item LOOKUP
+Set @code{*@var{ds}} to be ignored by @code{diskfs_drop_dirstat}
+
+@item CREATE
+On success, set @code{*@var{ds}} to be ignored by
+@code{diskfs_drop_dirstat}. @*
+On failure, set @code{*@var{ds}} for a future call to
+@code{diskfs_direnter}.
+
+@item RENAME
+On success, set @code{*@var{ds}} for a future call to
+@code{diskfs_dirrewrite}. @*
+On failure, set @code{*@var{ds}} for a future call to
+@code{diskfs_direnter}.
+
+@item REMOVE
+On success, set @code{*@var{ds}} for a future call to
+@code{diskfs_dirremove}. @*
+On failure, set @code{*@var{ds}} to be ignored by
+@code{diskfs_drop_dirstat}.
+@end table
+
+The caller of this function guarantees that if @var{ds} is nonzero, then
+either the appropriate call listed above or @code{diskfs_drop_dirstat}
+will be called with @var{ds} before the directory @var{dp} is unlocked,
+and guarantees that no lookup calls will be made on this directory
+between this lookup and the use (or destruction) of *DS.
+
+If you use the library's versions of @code{diskfs_rename_dir},
+@code{diskfs_clear_directory}, and @code{diskfs_init_dir}, then lookups
+for @file{..} might have the flag @code{SPEC_DOTDOT} ORed in. This has a
+special meaning depending on the requested lookup @var{type}:
+
+@table @code
+@item LOOKUP
+@var{dp} should be unlocked and its reference dropped before returning.
+
+@item CREATE
+Ignore this case, because @code{SPEC_DOTDOT} is guaranteed not to be
+given.
+
+@item RENAME
+@itemx REMOVE
+In both of these cases, the node being found (@code{*@var{np}}) is
+already held locked, so don't lock it or add a reference to it.
+@end table
+
+Return @code{ENOENT} if @var{name} isn't in the directory. Return
+@code{EAGAIN} if @var{name} refers to the @file{..} of this filesystem's
+root. Return @code{EIO} if appropriate.
+@end deftypefun
+
+@deftypefun error_t diskfs_direnter (@w{struct node *@var{dp}}, @w{char *@var{name}}, @w{struct node *@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}})
+@deftypefunx error_t diskfs_direnter_hard (@w{struct node *@var{dp}}, @w{char *@var{name}}, @w{struct node *@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}})
+You should not define @code{diskfs_direnter}, because it is simply a
+wrapper for @code{diskfs_direnter_hard}, and is already defined in
+@code{libdiskfs}.
+
+Add @var{np} to directory @var{dp} under the name @var{name}. This will
+only be called after an unsuccessful call to @code{diskfs_lookup} of type
+@code{CREATE} or @code{RENAME}; @var{dp} has been locked continuously
+since that call and @var{ds} is as that call set it, @var{np} is locked.
+@var{cred} identifies the user responsible for the call (to be used only
+to validate directory growth).
+@end deftypefun
+
+@deftypefun error_t diskfs_dirrewrite (@w{struct node *@var{dp}}, @w{struct node *@var{oldnp}}, @w{struct node *@var{np}}, @w{char *@var{name}}, @w{struct dirstat *@var{ds}})
+@deftypefunx error_t diskfs_dirrewrite_hard (@w{struct node *@var{dp}}, @w{struct node *@var{np}}, @w{struct dirstat *@var{ds}})
+You should not define @code{diskfs_dirrewrite}, because it is simply a
+wrapper for @code{diskfs_dirrewrite_hard}, and is already defined in
+@code{libdiskfs}.
+
+This will only be called after a successful call to @code{diskfs_lookup}
+of type @code{RENAME}; this call should change the name found in
+directory @var{dp} to point to node @var{np} instead of its previous
+referent. @var{dp} has been locked continuously since the call to
+@code{diskfs_lookup} and @var{ds} is as that call set it; @var{np} is
+locked.
+
+@code{diskfs_dirrewrite} has some additional specifications: @var{name}
+is the name within @var{dp} which used to correspond to the previous
+referent, @var{oldnp}; it is this reference which is being rewritten.
+@code{diskfs_dirrewrite} also calls @code{diskfs_notice_dirchange} if
+@code{@var{dp}->dirmod_reqs} is nonzero.
+@end deftypefun
+
+@deftypefun error_t diskfs_dirremove (@w{struct node *@var{dp}}, @w{struct node *@var{np}}, @w{char *@var{name}}, @w{struct dirstat *@var{ds}})
+@deftypefunx error_t diskfs_dirremove_hard (@w{struct node *@var{dp}}, @w{struct dirstat *@var{ds}})
+You should not define @code{diskfs_dirremove}, because it is simply a
+wrapper for @code{diskfs_dirremove_hard}, and is already defined in
+@code{libdiskfs}.
+
+This will only be called after a successful call to @code{diskfs_lookup}
+of type @code{REMOVE}; this call should remove the name found from the
+directory @var{ds}. @var{dp} has been locked continuously since the
+call to @code{diskfs_lookup} and @var{ds} is as that call set it.
+
+@code{diskfs_dirremove} has some additional specifications: this routine
+should call @code{diskfs_notice_dirchange} if
+@code{@var{dp}->dirmod_reqs} is nonzero. The entry being removed has
+name @var{name} and refers to @var{np}.
+@end deftypefun
+
+@deftypefun error_t diskfs_drop_dirstat (@w{struct node *@var{dp}}, @w{struct dirstat *@var{ds}})
+@var{ds} has been set by a previous call to @code{diskfs_lookup} on
+directory @var{dp}; this function is guaranteed to be called if
+@code{diskfs_direnter}, @code{diskfs_dirrewrite}, and
+@code{diskfs_dirremove} have not been called, and should free any state
+retained by a @code{struct dirstat}. @var{dp} has been locked
+continuously since the call to @code{diskfs_lookup}.
+@end deftypefun
+
+@deftypefun void diskfs_null_dirstat (@w{struct dirstat *@var{ds}})
+Initialize @var{ds} such that @code{diskfs_drop_dirstat} will ignore it.
+@end deftypefun
+
+@deftypefun error_t diskfs_get_directs (@w{struct node *@var{dp}}, @w{int @var{entry}}, @w{int @var{n}}, @w{char **@var{data}}, @w{u_int *@var{datacnt}}, @w{vm_size_t @var{bufsiz}}, @w{int *@var{amt}})
+Return @var{n} directory entries starting at @var{entry} from locked
+directory node @var{dp}. Fill @code{*@var{data}} with the entries;
+which currently points to @code{*@var{datacnt}} bytes. If it isn't big
+enough, @code{vm_allocate} into @code{*@var{data}}. Set
+@code{*@var{datacnt}} with the total size used. Fill @var{amt} with the
+number of entries copied. Regardless, never copy more than @var{bufsiz}
+bytes. If @var{bufsiz} is zero, then there is no limit on
+@code{*@var{datacnt}}; if @var{n} is -1, then there is no limit on
+@var{amt}.
+@end deftypefun
+
+@deftypefun int diskfs_dirempty (@w{struct node *@var{dp}}, @w{struct protid *@var{cred}})
+Return nonzero if locked directory @var{dp} is empty. If the user has
+not redefined @code{diskfs_clear_directory} and
+@code{diskfs_init_directory}, then `empty' means `only possesses entries
+labelled @file{.} and @file{..}. @var{cred} identifies the user making
+the call@dots{} if this user cannot search the directory, then this
+routine should fail.
+@end deftypefun
+
+@deftypefun error_t diskfs_get_translator (@w{struct node *@var{np}}, @w{char **@var{namep}}, @w{u_int *@var{namelen}})
+For locked node @var{np} (for which @code{diskfs_node_translated} is
+true) look up the name of its translator. Store the name into newly
+malloced storage and set @code{*@var{namelen}} to the total length.
+@end deftypefun
+
+@deftypefun error_t diskfs_set_translator (@w{struct node *@var{np}}, @w{char *@var{name}}, @w{u_int @var{namelen}}, @w{struct protid *@var{cred}})
+For locked node @var{np}, set the name of the translating program to be
+@var{name}, which is @var{namelen} bytes long. @var{cred} identifies
+the user responsible for the call.
+@end deftypefun
+
+@deftypefun error_t diskfs_truncate (@w{struct node *@var{np}}, @w{off_t @var{size}})
+Truncate locked node @var{np} to be @var{size} bytes long. If @var{np}
+is already less than or equal to @var{size} bytes long, do nothing. If
+this is a symlink (and @code{diskfs_shortcut_symlink} is set) then this
+should clear the symlink, even if @code{diskfs_create_symlink_hook}
+stores the link target elsewhere.
+@end deftypefun
+
+@deftypefun error_t diskfs_grow (@w{struct node *@var{np}}, @w{off_t @var{size}}, @w{struct protid *@var{cred}})
+Grow the disk allocated to locked node @var{np} to be at least
+@var{size} bytes, and set @code{@var{np}->allocsize} to the actual
+allocated size. If the allocated size is already @var{size} bytes, do
+nothing. @var{cred} identifies the user responsible for the call.
+@end deftypefun
+
+@deftypefun error_t diskfs_node_reload (@w{struct node *@var{node}})
+This function must reread all data specific to @var{node} from disk,
+without writing anything. It is always called with
+@var{diskfs_readonly} set to true.
+@end deftypefun
+
+@deftypefun error_t diskfs_reload_global_state (void)
+This function must invalidate all cached global state, and reread it as
+necessary from disk, without writing anything. It is always called with
+@var{diskfs_readonly} set to true. @code{diskfs_node_reload} is
+subsequently called on all active nodes, so this call doesn't need to
+reread any node-specific data.
+@end deftypefun
+
+@deftypefun error_t diskfs_node_iterate (error_t (*@var{fun}) (@w{struct node *@var{np}}))
+For each active node @var{np}, call @var{fun}. The node is to be locked
+around the call to @var{fun}. If @var{fun} returns nonzero for any
+node, then stop immediately, and return that value.
+@end deftypefun
+
+@deftypefun error_t diskfs_alloc_node (@w{struct node *@var{dp}}, @w{mode_t @var{mode}}, @w{struct node **@var{np}})
+Allocate a new node to be of mode @var{mode} in locked directory
+@var{dp}, but don't actually set the mode or modify the directory, since
+that will be done by the caller. The user responsible for the request
+can be identified with @var{cred}. Set @code{*@var{np}} to be the newly
+allocated node.
+@end deftypefun
+
+@deftypefun void diskfs_free_node (@w{struct node *@var{np}}, @w{mode_t @var{mode}})
+Free node @var{np}; the on-disk copy has already been synchronized with
+@code{diskfs_node_update} (where @code{@var{np}->dn_stat.st_mode} was
+zero). @var{np}'s mode used to be @var{mode}.
+@end deftypefun
+
+@deftypefun void diskfs_lost_hardrefs (@w{struct node *@var{np}})
+Locked node @var{np} has some light references but has just lost its
+last hard reference.
+@end deftypefun
+
+@deftypefun void diskfs_new_hardrefs (@w{struct node *@var{np}})
+Locked node @var{np} has just acquired a hard reference where it had
+none previously. Therefore, it is okay again to have light references
+without real users.
+@end deftypefun
+
+@deftypefun void diskfs_try_dropping_softrefs (@w{struct node *@var{np}})
+Node @var{np} has some light references, but has just lost its last hard
+references. Take steps so that if any light references can be freed,
+they are. Both @var{diskfs_node_refcnt_lock} and @var{np} are locked.
+This function will be called after @code{diskfs_lost_hardrefs}.
+@end deftypefun
+
+@deftypefun void diskfs_node_norefs (@w{struct node *@var{np}})
+Node @var{np} has no more references; free local state, including
+@code{*@var{np}} if it shouldn't be retained.
+@var{diskfs_node_refcnt_lock} is held.
+@end deftypefun
+
+@deftypefun error_t diskfs_set_hypermetadata (@w{int @var{wait}}, @w{int @var{clean}})
+Write any non-paged metadata from format-specific buffers to disk,
+asynchronously unless @var{wait} is nonzero. If @var{clean} is nonzero,
+then after this is written the filesystem will be absolutely clean, and
+it must be possible for the non-paged metadata to indicate that fact.
+@end deftypefun
+
+@deftypefun void diskfs_write_disknode (@w{struct node *@var{np}}, @w{int @var{wait}})
+Write the information in @code{@var{np}->dn_stat} and any associated
+format-specific information to the disk. If @var{wait} is true, then
+return only after the physical media has been completely updated.
+@end deftypefun
+
+@deftypefun void diskfs_file_update (@w{struct node *@var{np}}, @w{int @var{wait}})
+Write the contents and all associated metadata of file NP to disk.
+Generally, this will involve calling @code{diskfs_node_update} for much
+of the metadata. If @var{wait} is true, then return only after the
+physical media has been completely updated.
+@end deftypefun
+
+@deftypefun mach_port_t diskfs_get_filemap (@w{struct node *@var{np}}, @w{vm_prot_t @var{prot}})
+Return a memory object port (send right) for the file contents of
+@var{np}. @var{prot} is the maximum allowable access. On errors,
+return @code{MACH_PORT_NULL} and set @code{errno}.
+@end deftypefun
+
+@deftypefun {struct pager *} diskfs_get_filemap_pager_struct (@w{struct node *@var{np}})
+Return a @code{struct pager *} that refers to the pager returned by
+diskfs_get_filemap for locked node NP, suitable for use as an argument
+to @code{pager_memcpy}.
+@end deftypefun
+
+@deftypefun vm_prot_t diskfs_max_user_pager_prot (void)
+Return the bitwise OR of the maximum @code{prot} parameter (the second
+argument to @code{diskfs_get_filemap}) for all active user pagers.
+@end deftypefun
+
+@deftypefun int diskfs_pager_users (void)
+Return nonzero if there are pager ports exported that might be in use by
+users. Further pager creation should be blocked before this function
+returns zero.
+@end deftypefun
+
+@deftypefun void diskfs_sync_everything (@w{int @var{wait}})
+Sync all the pagers and write any data belonging on disk except for the
+hypermetadata. If @var{wait} is true, then return only after the
+physical media has been completely updated.
+@end deftypefun
+
+@deftypefun void diskfs_shutdown_pager (void)
+Shut down all pagers. This is irreversible, and is done when the
+filesystem is exiting.
+@end deftypefun
+
+
+@node Diskfs Options
+@subsection Diskfs Options
+
+The functions and variables described in this subsection already have
+default definitions in @code{libdiskfs}, so you are not forced to define
+them; rather, they may be redefined on a case-by-case basis.
+
+You should set the values of any option variables as soon as your program
+starts (before you make any calls to diskfs, such as argument parsing).
+
+@deftypevar int diskfs_hard_readonly
+You should set this variable to nonzero if the filesystem media can
+never be made writable.
+@end deftypevar
+
+@deftypevar {char *} diskfs_extra_version
+Set this to be any additional version specification that should be
+printed for --version.
+@end deftypevar
+
+@deftypevar int diskfs_shortcut_symlink
+This should be nonzero if and only if the filesystem format supports
+shortcutting symbolic link translation. The library guarantees that
+users will not be able to read or write the contents of the node
+directly, and the library will only do so if the symlink hook functions
+(@code{diskfs_create_symlink_hook} and @code{diskfs_read_symlink_hook})
+return @code{EINVAL} or are not defined. The library knows that the
+@code{dn_stat.st_size} field is the length of the symlink, even if the
+hook functions are used.
+@end deftypevar
+
+@deftypevar int diskfs_shortcut_chrdev
+@deftypevarx int diskfs_shortcut_blkdev
+@deftypevarx int diskfs_shortcut_fifo
+@deftypevarx int diskfs_shortcut_ifsock
+These variables should be nonzero if and only if the filesystem format
+supports shortcutting character device node, block device node, FIFO, or
+Unix-domain socket translation, respectively.
+@end deftypevar
+
+@deftypevar int diskfs_default_sync_interval
+@code{diskfs_set_sync_interval} is called with this value when the first
+diskfs thread is started up (in @code{diskfs_spawn_first_thread}). This
+variable has a default default value of 30, which causes disk buffers to
+be flushed at least every 30 seconds.
+@end deftypevar
+
+@deftypefun error_t diskfs_validate_mode_change (@w{struct node *@var{np}}, @w{mode_t @var{mode}})
+@deftypefunx error_t diskfs_validate_owner_change (@w{struct node *@var{np}}, @w{uid_t @var{uid}})
+@deftypefunx error_t diskfs_validate_group_change (@w{struct node *@var{np}}, @w{gid_t @var{gid}})
+@deftypefunx error_t diskfs_validate_author_change (@w{struct node *@var{np}}, @w{uid_t @var{author}})
+@deftypefunx error_t diskfs_validate_flags_change (@w{struct node *@var{np}}, @w{int @var{flags}})
+@deftypefunx error_t diskfs_validate_rdev_change (@w{struct node *@var{np}}, @w{dev_t @var{rdev}})
+Return zero if for the node @var{np} can be changed as requested. That
+is, if @var{np}'s mode can be changed to @var{mode}, owner to @var{uid},
+group to @var{gid}, author to @var{author}, flags to @var{flags}, or raw
+device number to @var{rdev}, respectively. Otherwise, return an error
+code.
+
+It must always be possible to clear the mode or the flags; diskfs will
+not ask for permission before doing so.
+@end deftypefun
+
+@deftypefun void diskfs_readonly_changed (@w{int @var{readonly}})
+This is called when the disk has been changed from read-only to
+read-write mode or vice-versa. @var{readonly} is the new state (which
+is also reflected in @var{diskfs_readonly}). This function is also
+called during initial startup if the filesystem is to be writable.
+@end deftypefun
+
+@deftypefn {Variable} error_t (*diskfs_create_symlink_hook) (@w{struct node *@var{np}}, @w{char *@var{target}})
+If this function pointer is nonzero (and @code{diskfs_shortcut_symlink}
+is set) it is called to set a symlink. If it returns @code{EINVAL} or
+isn't set, then the normal method (writing the contents into the file
+data) is used. If it returns any other error, it is returned to the
+user.
+@end deftypefn
+
+@deftypefn {Variable} error_t (*diskfs_read_symlink_hook) (@w{struct node *@var{np}}, @w{char *@var{target}})
+If this function pointer is nonzero (and @code{diskfs_shortcut_symlink}
+is set) it is called to read the contents of a symlink. If it returns
+@code{EINVAL} or isn't set, then the normal method (reading from the
+file data) is used. If it returns any other error, it is returned to
+the user.
+@end deftypefn
+
+@deftypefun error_t diskfs_rename_dir (@w{struct node *@var{fdp}}, @w{struct node *@var{fnp}}, @w{char *@var{fromname}}, @w{struct node *@var{tdp}}, @w{char *@var{toname}}, @w{struct protid *@var{fromcred}}, @w{struct protid *@var{tocred}})
+Rename directory node @var{fnp} (whose parent is @var{fdp}, and which
+has name @var{fromname} in that directory) to have name @var{toname}
+inside directory @var{tdp}. None of these nodes are locked, and none
+should be locked upon return. This routine is serialized, so it doesn't
+have to be reentrant. Directories will never be renamed except by this
+routine. @var{fromcred} is the user responsible for @var{fdp} and
+@var{fnp}. @var{tocred} is the user responsible for @var{tdp}. This
+routine assumes the usual convention where @file{.} and @file{..} are
+represented by ordinary links; if that is not true for your format, you
+have to redefine this function.
+@end deftypefun
+
+@deftypefun error_t diskfs_clear_directory (@w{struct node *@var{dp}}, @w{struct node *@var{pdp}}, @w{struct protid *@var{cred}})
+Clear the @file{.} and @file{..} entries from directory @var{dp}. Its
+parent is @var{pdp}, and the user responsible for this is identified by
+@var{cred}. Both directories must be locked. This routine assumes the
+usual convention where @file{.} and @file{..} are represented by
+ordinary links; if that is not true for your format, you have to
+redefine this function.
+@end deftypefun
+
+@deftypefun error_t diskfs_init_dir (@w{struct node *@var{dp}}, @w{struct node *@var{pdp}}, @w{struct protid *@var{cred}})
+Locked node @var{dp} is a new directory; add whatever links are
+necessary to give it structure; its parent is the (locked) node
+@var{pdp}. This routine may not call @code{diskfs_lookup} on @var{pdp}.
+The new directory must be clear within the meaning of
+@code{diskfs_dirempty}. This routine assumes the usual convention where
+@file{.} and @file{..} are represented by ordinary links; if that is not
+true for your format, you have to redefine this function. @var{cred}
+identifies the user making the call.
+@end deftypefun
+
+
+@node Diskfs Internals
+@subsection Diskfs Internals
+
+The library also exports the following functions, but they are not
+generally useful unless you are redefining other functions the library
+provides.
+
+@deftypefun error_t diskfs_create_protid (@w{struct peropen *@var{po}}, @w{struct iouser *@var{user}}, @w{struct protid **@var{cred}})
+Create and return a protid for an existing peropen @var{po} in
+@var{cred}, referring to user @var{user}. The node @code{@var{po}->np}
+must be locked.
+@end deftypefun
+
+@deftypefun error_t diskfs_start_protid (@w{struct peropen *@var{po}}, @w{struct protid **@var{cred}})
+Build and return in @var{cred} a protid which has no user
+identification, for peropen @var{po}. The node @code{@var{po}->np} must
+be locked.
+@end deftypefun
+
+@deftypefun void diskfs_finish_protid (@w{struct protid *@var{cred}}, @w{struct iouser *@var{user}})
+Finish building protid @var{cred} started with @code{diskfs_start_protid};
+the user to install is @var{user}.
+@end deftypefun
+
+@deftypefun void diskfs_protid_rele (@w{void *@var{arg}})
+Called when a protid @var{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
+free the structure.
+@end deftypefun
+
+@deftypefun {struct peropen *} diskfs_make_peropen (@w{struct node *@var{np}}, @w{int @var{flags}}, @w{struct peropen *@var{context}})
+Create and return a new peropen structure on node @var{np} with open
+flags @var{flags}. The initial values for the @code{root_parent},
+@code{shadow_root}, and @code{shadow_root_parent} fields are copied from
+@var{context} if it is nonzero, otherwise each of these values are
+set to zero.
+@end deftypefun
+
+@deftypefun void diskfs_release_peropen (@w{struct peropen *@var{po}})
+Decrement the reference count on @var{po}.
+@end deftypefun
+
+@deftypefun error_t diskfs_execboot_fsys_startup (@w{mach_port_t @var{port}}, @w{int @var{flags}}, @w{mach_port_t @var{ctl}}, @w{mach_port_t *@var{real}}, @w{mach_msg_type_name_t *@var{realpoly}})
+This function is called by @code{S_fsys_startup} for execserver
+bootstrap. The execserver is able to function without a real node,
+hence this fraud. Arguments are as for @code{fsys_startup} in
+@code{<hurd/fsys.defs>}.
+@end deftypefun
+
+@deftypefun int diskfs_demuxer (@w{mach_msg_header_t *@var{inp}}, @w{mach_msg_header_t *@var{outp}})
+Demultiplex incoming @code{libports} messages on diskfs ports.
+@end deftypefun
+
+@findex diskfs_S_*
+The diskfs library also provides functions to demultiplex the fs, io,
+fsys, interrupt, and notify interfaces. All the server routines have
+the prefix @code{diskfs_S_}. For those routines, @code{in} arguments of
+type @code{file_t} or @code{io_t} appear as @code{struct protid *} to
+the stub.
+
+
+@node Twisted Filesystems
+@chapter Twisted Filesystems
+
+In the Hurd, translators are capable of redirecting filesystem requests
+to other translators, which makes it possible to implement alternative
+views of the same underlying data. The translators described in this
+chapter do not provide direct access to any data; rather, they are
+organizational tools to help you simplify an existing physical
+filesystem layout.
+
+Be prudent with these translators: you may accidentally injure people
+who want their filesystems to be rigidly tree-structured.@footnote{You
+are lost in a maze of twisty little filesystems, all alike@dots{}.}
+
+FIXME: finish
+
+@section symlink, firmlink
+@section hostmux, usermux
+@section shadowfs
+
+
+@node Distributed Filesystems
+@chapter Distributed Filesystems
+
+Distributed filesystems are designed to share files between separate
+machines via a network connection of some sort. Their design is
+significantly different than stored filesystems (@pxref{Stored
+Filesystems}): they need to deal with the problems of network delays and
+failures, and may require complex authentication and replication
+protocols involving multiple file servers.
@menu
-* Conch:: How access to the shared page is mediated
-* Access rules:: Where in the io_map memory objects users
- may peek and poke
-* Behavior modification:: Modifications of behavior
-* Status notifications:: Calls users should make at certain
- times to keep the server abreast of the
- current state of the object
-* Violations:: When the rules are broken
+* File Transfer Protocol:: A distributed filesystem based on FTP.
+* Network File System:: Sun's NFS: a lousy, but common filesystem.
+@end menu
+
+
+@node File Transfer Protocol
+@section File Transfer Protocol
+@cindex FTP
+FIXME: finish
+
+@menu
+* FTP Connection Library:: Managing remote FTP server connections.
@end menu
-@node Conch
-@subsection Conch
-
-Access to the shared page is mediated through a facility known as the
-``conch''. The ``lock'' field of the shared page protects the
-conch_status field; users and the server must acquire this lock with
-spin_lock before they may modify or examine conch_status.
-
-If the conch_status field is USER_HAS_CONCH or USER_RELEASE_CONCH, then
-the user has the conch, and may access the shared page after releasing
-the spin lock. If the conch_status field is USER_COULD_HAVE_CONCH, then
-the user may immediately set conch_status to USER_HAS_CONCH, and proceed
-to access the shared page after releasing the spin lock. If the conch
-status is USER_HAS_NOT_CONCH, then the user should release the spin
-lock, and call io_get_conch. Upon return from io_get_conch, the user
-should reacquire the spin lock and check conch_status again.
-
-When the user is through accessing the shared page, the user should
-acquire the spin lock and examine the conch_status field. If it has
-been set to USER_RELEASE_CONCH, then the user should release the spin
-lock and call io_release_conch. Otherwise, the user should change
-conch_status from USER_HAS_CONCH to USER_COULD_HAVE_CONCH and then
-release the spin lock.
-
-The implementation of io_read and io_write must not modify the object
-data or the default file pointer except when the server is holding the
-conch; users who wish to be atomic with respect to those functions
-should be similarly reticent.
-
-The server must guarantee that at most one user of an underlying object
-has the conch at a time; the server may only have the conch if no user
-does. The server may not modify conch_status or the shared page if the
-status is USER_HAS_CONCH except to set it to USER_RELEASE_CONCH, thus
-requesting a call to io_release_conch.
-
-The server is permitted to modify any characteristics of the shared page
-anytime the conch_status is not USER_HAS_CONCH or USER_RELEASE_CONCH;
-users may not assume that the shared page has not changed even when only
-upgrading USER_COULD_HAVE_CONCH to USER_HAS_CONCH.
-
-@node Access rules
-@subsection Access rules
-
-The conch fields file_size, read_size, and prenotify_size affect which
-areas of the data objects may be accessed. In addition, for
-non-seekable objects, the file pointers rd_file_pointer,
-wr_file_pointer, and xx_file_pointer affect which areas may be accessed.
-
-For seekable objects, the user may read the read object from offset 0
-through the minimum of file_size and read_size.
-
-For seekable objects, the user may write the write object from offset 0
-through the prenotify_size.
-
-For nonseekable objects, the user may read the read object from
-rd_file_pointer through the minimum of file_size and read_size.
-
-For nonseekable objects, the user may write the write object from
-wr_file_pointer through prenotify_size.
-
-The server may permit access outside these regions, but need not
-preserve data for any length of time if so written. If the server
-wishes to deny such access, it issue faults with EIO. Servers may also
-issue faults on modifications of the write object for reasons such as
-EDQUOT and ENOSPC, as well as reporting hardware errors with EIO.
-Servers may only fault valid addresses in the read object in the event
-of hardware failure, giving EIO.
-
-Users should ignore the foo field if the value use_foo is clear in the
-shared page; this may result in there being no maximum valid address for
-a particular access. In that case, the user may access the object to
-the end of its virtual address space.
-
-If use_file_size is set, the user may increase the file_size, but may
-not decrease it, to indicate the new "maximum correct value" as
-described for O_APPEND. Normally when users write beyond the current
-file_size they should extend it at least to the end of the write.
-
-The xx_file_pointer for seekable objects must be the same as the default
-file pointer used by io_read and io_write.
-
-If use_read_size is set and the user wishes to read past read_size, she
-may call io_readsleep, which must return as soon as read_size is
-increased. The server should set read_block_reason anytime
-use_read_size is set; if read_block_reason is RBR_BUFFER_FULL, then the
-server is indicating that the read_size might never be increased until
-the rd_file_pointer is sufficiently increased.
-
-If the server has set use_prenotify_size and the user wishes to write
-past prenotify_size, she may call io_prenotify, specifying the maximum
-offset the user intends to write. The server should return when after
-increasing prenotify_size, but is not obligated to extend it as far as
-the user wishes. In addition, io_prenotify may return errors such as
-ENOSPC, indicating that the prenotify_size cannot be increased.
-
-Users of seekable objects may modify the xx_file_pointer at will
-(including pointing past read_size, file_size, or prenotify_size).
-Users of non-seekable objects, however, may only increase the
-rd_file_pointer and wr_file_pointer. In addition, they may not modify
-them to point past the valid data as described above. Failing to
-advance them at all may prevent the read_size or prenotify_size from
-being increased.
-
-If the server sets eof_notify, then the user may attempt to have the
-file_size to be increased by calling io_eofnotify after "noticing" the
-current file size limit. io_eofnotify must return immediately, but need
-not actually increase the file_size or clear user_file_size. (However,
-if it is impossible for io_eofnotify to ever do anything, then the
-server should not bother setting eof_notify.)
-
-@node Status notification
-@subsection Status notification
-
-The flag do_sigio requests the user to call io_sigio every time she
-changes the file pointers or the file_size.
-
-If the server sets use_postnotify_size, then the user should call
-io_postnotify after writing data that extends past postnotify_size. The
-server may buffer writes internally beyond postnotify_size for
-arbitrarily long periods until io_postnotify is called, regardless of
-the setting of the O_FSYNC bit.
-
-After modifying or reading the object contents, the user should set the
-written or accessed fields respectively. (Users who fail to set these
-fields will not thereby defeat the mtime/atime mechanism.)
-
-If the flag use_eof is set, then users should call io_eofnotify after
-reading up to the file_size and noticing it.
-
-@node Behavior modification
-@subsection Behavior modification
-
-The server flag append_mode is a copy of the O_APPEND open mode bit; if
-it is set, then the user should do writes at file_size and set the file
-pointer appropriately (this applies only if the user would be writing at
-the file pointer in the first place).
-
-Servers should implement the flag O_FSYNC by using the postnotify_size
-field.
+@subsection ftpcp, ftpdir
+@subsection ftpfs
+
+@node FTP Connection Library
+@subsection FTP Connection Library
+@scindex libftpconn
+@scindex ftpconn.h
-Servers should implement the io_async and O_ASYNC notifications by using
-the do_sigio field.
+FIXME: finish
-@node Violations
-@subsection Violations
-
-Users who hold the conch for too long while conch_status is set to
-USER_RELEASE_CONCH may have the conch stolen from them and their
-conch_status unilaterally downgraded to USER_HAS_NOT_CONCH by the
-server. Users who hold the spin lock for too long (where this ``too
-long'' is much much shorter than the previous one) may have the spin
-lock stolen from them by the server.
-
-Users who read or write outside the valid regions described above may
-get memory faults and may not expect data written to be saved in any
-fashion.
-
-Users who write the read object (when it is different from the write
-object) may or may not get faults; they may not expect such data to be
-saved in any fashion.
-
-Users who fail to call io_postnotify may cause data to be buffered for
-arbitrarily long periods.
-
-Users who reduce rd_file_pointer, wr_file_pointer, or file_size will
-have such modifications ignored.
-Users may not call any server functions (whether in the I/O protocol or
-another) while holding the conch except for those specified in this
-chapter. Such calls may block indefinitely or fail silently.
+@node Network File System
+@section Network File System
+@cindex NFS
+FIXME: finish
-@node File interface
-@chapter File interface
+@subsection nfsd
+@subsection nfs
-This chapter documents the interface for operating on files.
+
+@node Networking
+@chapter Networking
+
+FIXME: this subsystem is in flux @c Thomas, 26-03-1998
@menu
-* Changing Status:: Changing the owner (etc.) of a file
-* Program Execution:: Executing files
-* File locking:: Implementing the flock call
-* File frobbing:: Other active calls on files
-* Opening files:: Looking up files in directories
-* Modifying directories:: Creating and deleting nodes
-* Notifications:: File and directory change callbacks
-* Translators:: How to set and get translators
+* Socket Interface:: Network communication I/O protocol.
@end menu
+@section pfinet
+@section pflocal
+@section libpipe
+
+@node Socket Interface
+@section Socket Interface
+@scindex socket.defs
+
+FIXME: net frobbing stuff may be added to socket.defs
+@c Thomas, 26-03-1998
+
+
+@node Terminal Handling
+@chapter Terminal Handling
+
+FIXME: finish
+
+@section term
+@section term.defs
+
+
+@node Running Programs
+@chapter Running Programs
+
+FIXME: finish
+
+@section ps, w
+@section libps
+@section exec
+@section proc
+@section crash
+
+
+@node Authentication
+@chapter Authentication
+
+FIXME: finish
+
+@menu
+* Auth Interface:: Auth ports implement the auth interface.
+@end menu
+
+@section addauth, rmauth, setauth
+@section su, sush, unsu
+@section login, loginpr
+@section auth
+
+@node Auth Interface
+@section Auth Interface
+@scindex auth.defs
+
+FIXME: finish
+
+@menu
+* Auth Protocol:: Bidirectional authentication.
+@end menu
+
+@node Auth Protocol
+@subsection Auth Protocol
+
+FIXME: finish
+
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+@summarycontents
+@contents
@bye
diff --git a/doc/navigating b/doc/navigating
new file mode 100644
index 00000000..2d836255
--- /dev/null
+++ b/doc/navigating
@@ -0,0 +1,54 @@
+Some ideas on navigating and understanding the Hurd source code.
+
+First you must understand Mach IPC and MiG. Pay special attention to
+the way that various kinds of MiG calls manage memory; this is crucial
+to avoid leaks. The "Mach server writers' guide" explains all this.
+
+Most programs that make up the Hurd are built out of libraries; a
+solid understanding of the libraries that make up the source is
+essential. First start by reading the libports library specification
+(in libports/ports.h). This library manages the Mach ports that
+servers handle.
+
+Then start looking at some Hurd interfaces. A good place to start is
+to look at the proc server. There is only one proc server in a
+running system, but examine the way the interface (hurd/process.defs)
+is written and the way the proc server implements it.
+
+Then look at the auth server; make sure you understand how an auth
+transaction works. Again, by looking at the implementation, you can
+see a simple example.
+
+Filesystems are more complex; the interface specification is in
+hurd/io.defs and hurd/fs.defs. These interfaces are implemented by
+three different libraries: trivfs, diskfs, and netfs. trivfs
+implements single-node filesystems (that thus have no directories).
+Most trivfs filesystems don't even do any filesystem stuff at all.
+See, for example, the null translator (trans/null.c) for a simple
+example of using trivfs.
+
+diskfs is used for disk-based filesystems, with two in existence now:
+ext2fs and ufs. If you write another diskfs-based filesystem, you
+should DEFINITELY imitate the algorithms found in ext2fs and ufs; this
+is crucial to getting locking right.
+
+netfs is used for nfs and other such things: with directories, and all
+the actual filesystem operations being done by some other program (not
+necessarily over a network). The nfs implementation is fairly easy to
+understand.
+
+Examine some translators in the trans directory to see various simple
+examples.
+
+Also very important is to acquire familiarity with the Hurd and Mach
+calls provided in the GNU C library. Look at the header files in libc
+to see what they are, and read through them. Also examine parts of
+the libc implementation whenever you have any doubt about what an
+interface call should do: find where the C library uses that call, and
+that should help. It's worth, in fact, spending some time just
+exploring the implementation of various things in the hurd C library.
+
+You should take a look at all the libraries in the Hurd; spend time
+reading the code. Feel free to ask questions to help understand what
+you read.
+
diff --git a/doc/version.texi b/doc/version.texi
new file mode 100644
index 00000000..5df65c28
--- /dev/null
+++ b/doc/version.texi
@@ -0,0 +1 @@
+@set VERSION 0.2
diff --git a/exec/ChangeLog b/exec/ChangeLog
deleted file mode 100644
index d650dbd8..00000000
--- a/exec/ChangeLog
+++ /dev/null
@@ -1,643 +0,0 @@
-Sun Jul 7 21:13:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * exec.c (S_exec_exec): Don't use unsafe MOVE_SEND in call to
- interruptible exec_exec stub.
-
-Mon Jul 1 16:08:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Removed crash.c.
- * crash.c: Moved to ../trans.
-
-Thu Jun 20 15:43:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (exec): Link against fshelp too now.
-
- * exec.c (do_exec): Call proc_setowner *after* possible
- proc_reassign; otherwise it modifies the stub process's state and
- not the real process's.
-
-Wed Jun 19 14:08:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * exec.c (do_exec, S_exec_exec): Pass 0 for new LOOKUP arg to
- hurd_file_name_lookup.
- * hashexec.c (hurd_file_name_path_lookup): Declaration removed.
- (check_hashbang): Pass 0 for new LOOKUP arg to hurd_file_name_lookup.
-
-Wed Jun 12 21:17:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * gzip.h (basename): Comment out declaration; it conflicts with
- libc's.
-
- * exec.c (do_exec): If secure, set the owner with proc_setowner.
-
-Fri May 10 16:47:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hashexec.c (search_path): Don't make PATH or PFXED_NAME const.
-
-Fri May 10 09:20:26 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * exec.c (do_exec) [use1]: Use new auth_user_authenticate interface.
- * hashexec.c (check_hashbang) [userport/reauthenticate]: Likewise.
-
- * hashexec.c (check_hashbang) [setup_args/search_path]: Declare
- PATH to be `char const *'.
-
-Tue May 7 16:24:52 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * hashexec.c (check_hashbang): Use io_identity instead of io_stat to
- compare files.
-
-Mon May 6 14:26:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c (exec_version): Upgrade to 0.0.
-
-Fri May 3 14:16:17 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * exec.c (map): Use F->__offset and F->__target properly.
-
-Thu May 2 10:21:37 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * exec.c (map): Fix fencepost error in check of current mapping
- window. Request round_page (LEN) bytes in io_read to avoid many small
- reads.
-
- * exec.c (do_exec): Terminate OLDTASK if we get an error after killing
- its threads and deallocating its address space.
-
-Tue Apr 30 11:36:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * exec.c (check_gzip) [ziprderr]: Treat all read errors as
- ENOEXEC. First off, because that's what they are; also because
- some callers of read_error don't set errno at all.
-
-Mon Apr 29 15:11:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * exec.c (check_section): If the format makes no sense, return
- ENOEXEC, not EINVAL.
- (check_bfd): Likewise.
- (check_elf): Likewise.
- (check_elf_phdr): Likewise.
- (do_exec): Likewise.
-
- * exec.c (do_exec): Use correct args to ports_create_port.
-
-Sat Apr 27 06:02:42 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * crash.c: Use ports_create_port instead of ports_allocate_port, and
- notice the error.
- * exec.c: Likewise.
-
-Tue Apr 23 18:53:54 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * hashexec.c (check_hashbang: user_port): Use default root port when
- secure.
-
-Mon Apr 15 12:48:35 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Add elfcore.c, crash.c, and exectrans.c.
- (SRCS): That's hashexec.c, not .o.
-
- * Makefile (exec-MIGSFLAGS): Look for execmutations.h in
- $(srcdir).
-
-Mon Apr 8 15:49:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * exec.c (prepare): If io_map returns EOPNOTSUPP, suppress the
- error, and still setup E's stream.
- (prepare_and_check): If prepare returns an error, do no more.
-
-Thu Mar 28 14:06:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hashexec.c (check_hashbang): Pass open flags & mode args to
- hurd_file_name_path_lookup.
-
-Mon Feb 26 16:33:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hashexec.c (check_hashbang): Correctly deal with interpreter
- lines having no argument.
-
-Sat Jan 13 12:28:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hashexec.c (check_hashbang): Use hash_file_name_path_lookup()
- instead of doing the path search ourselves, and get rid of
- LOOKUP_CWDIR & associated logic.
- * exec.c (S_exec_exec): Use strdupa(). Also update use of
- hurd_file_name_lookup() [still probably not right though].
-
-Thu Jan 11 15:36:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hashexec.c (check_hashbang): When using executable name found on
- the path, don't return alloca()ed memory from search_path(); use
- malloc() instead.
- Use envz_get() to search the environment.
-
- * exec.c (S_exec_exec): Use envz_get() to search the environment.
-
-Thu Jan 4 11:30:15 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (safe_bzero): Rewritten using hurd_catch_signal.
- * hashexec.c (check_hashbang): Rearrange arg frobbing code
- somewhat to use hurd_catch_signal instead of old preemption interface.
-
-Fri Dec 29 15:54:06 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * exec.c (do_exec): Be careful not to look at BOOT after we
- release our reference on it.
- Correctly initialize BOOT->intarray in the case where NINTS <
- INIT_INT_MAX but we don't alloc a new array.
-
-Fri Dec 15 01:53:07 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (map): Rearrange code to fix some bugs and not remap
- unless necessary.
- (input_room): Simplify.
- (check_elf): Extract all information from file header before
- calling `map' for program headers.
-
-Sat Nov 25 22:10:41 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * crash.c (S_msg_sig_post_untraced): Also let the debugger have
- the process back if it's posting the crashing signal.
-
-Tue Nov 21 15:01:56 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (safe_bzero): New function, broken out of load_section.
- (load_section): Call it.
-
- * main.c (going_down): Variable removed.
- (deadboot): Don't test it. Instead, use ports calls to check if
- there are no other live ports.
- (trivfs_goaway): Don't set it.
-
-Wed Nov 15 19:40:44 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hashexec.c (user_port): Fixed port selection logic.
- (check_hashbang): Fixed PATH searching in script name guessing.
-
-Mon Nov 13 15:11:37 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (S_exec_startup): Compatibility RPC removed.
-
- * exec.c (load_section): Catch faults while zeroing partial bss page.
-
-Sun Nov 5 00:15:07 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Add flags arg to trivfs_startup call.
-
-Wed Oct 25 15:50:38 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (S_exec_startup_get_info): New function, modified from
- S_exec_startup.
- (S_exec_startup): Just call it.
- * main.c (exec_demuxer): Call exec_startup_server.
-
-Tue Oct 24 19:21:20 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Add exec_startupServer.o.
-
- * priv.h (struct bootinfo): Use vm_size_t for phdr_size.
-
-Wed Oct 18 18:36:30 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hashexec.c (check_hashbang: prepare_args): Enable and clean up
- code to guess the name of the script before resorting to /dev/fd.
-
-Wed Oct 18 03:05:05 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hashexec.c: New file.
- * exec.c (struct execdata): Moved to priv.h.
- (std_*, finish): Make global.
- (do_exec): Only reset CWDIR when null, even if secure.
- Actually call check_hashbang and return success if it does.
- Use new hurd_file_name_lookup protocol with private callbacks to open
- interpreter file on behalf of client.
- Remove `bootout' label; use `stdout' or `out' as appropriate instead.
- At `out' label always deref BOOT, which cleans it up iff necessary.
- (S_exec_exec): #if 0 out $EXECSERVERS processing for time being.
- * priv.h: Added some #includes.
- (struct execdata): Moved here from exec.c.
- (std_*): Declare these.
- (finish, check_hashbang): Declare them.
- * Makefile (SRCS, OBJS): Add hashexec.[co].
- (DIST_FILES): Remove it from here.
-
-Wed Oct 11 01:45:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * main.c, priv.h, execmutations.h: New files.
- * exec.c: Server mechanics removed; now uses libtrivfs/libports.
- Main program split out into main.c.
- (std_lock): New variable (rwlock).
- (do_exec): Acquire reader lock to access std_ints and std_ports.
- (S_exec_setexecdata): Acquire writer lock to change them.
- * Makefile (OBJS): Add main.o; remove fsysServer.o, notifyServer.o.
- (LCLHDRS): Add priv.h and execmutations.h.
- (exec-MIGSFLAGS): New variable.
- (exec): Depend on livtrivfs, libthreads, libshouldbeinlibc.
-
-Mon Oct 2 10:33:14 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * exec.c (do_exec): Doc fix.
-
-Wed Sep 27 11:21:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (do_exec): Don't set NEWTASK's bootstrap port until after
- we have finished completely with OLDTASK.
- (do_mach_notify_no_senders): Remove bogus mod_refs call on
- receive_portset.
-
-Wed Sep 20 19:57:55 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (struct bootinfo): New members `phdr_addr', `phdr_size',
- `user_entry'.
- (do_exec): Set them. Code rearranged to construct bootinfo before
- looking up interpreter file, keep proper track of port rights and
- VM copied into bootinfo (there were leaks).
-
-Sat Sep 16 13:15:42 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile: Remove vpath directive.
-
-Fri Sep 8 17:50:03 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OTHERLIBS, CPPFLAGS): Disable bfd by default.
-
-Mon Aug 28 16:57:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (S_fsys_forward): New stub function.
-
-Sun Jul 30 23:49:49 1995 Michael I. Bushnell, p/BSG <mib@geech.gnu.ai.mit.edu>
- * Makefile (SRCS): Added unzip.c, util.c, and inflate.c.
-
-Thu Jul 6 15:32:39 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * hostarch.c (bfd_mach_host_arch_mach): Remove assignment from
- inside if test.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Wed Jul 5 18:00:49 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (OTHERLIBS): Define var.
- (all, exec): Delete targets.
-
-Tue Jun 27 11:48:08 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * exec.c (load_section): Remove assignments from if tests.
- (map): Likewise.
- (prepare): Likewise.
- (load): Likewise.
- (servercopy): Likewise.
- (do_exec): Likewise.
- (S_exec_setexecdata): Likewise.
- (S_exec_exec): Put extra parens around assignment inside while
- test.
-
-Thu Jun 8 02:57:28 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (struct execdata.info.elf): Add members `anywhere' and
- `loadbase'.
- (load_section): Use them; if `anywhere' set, load the section anywhere.
- Record load address in `loadbase'.
- (check_elf): Initialize `anywhere' and `loadbase'.
- (postload): Merged into load.
- (load): Perform postload functionality here, after calling
- finish_mapping.
- (finish): Take new flag arg; deallocate file port only if set.
- (do_exec): Pass flag to finish appropriately.
- Don't call finish_mapping and postload after load. KLUDGE: Load
- the interpreter before the program instead of after.
-
-Mon Jun 5 06:42:33 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c: Majorly revamped: Now supports the ELF format directly.
- Secondarily uses the BFD library #ifdef BFD. Supports gunzipping
- only #ifdef GZIP.
- * hostarch.c: Rewritten to unconditionally return both BFD and ELF
- machine types.
-
-Fri May 12 18:59:21 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * exec.c (S_fsys_set_options, S_fsys_mod_readonly): Change from
- mod_readonly to set_options.
-
-Thu Apr 20 22:14:47 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (check_gzip): Rewind the stream before calling
- `get_method'. Open a new BFD on the uncompressed data stream
- before return.
-
-Sun Apr 9 01:27:10 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (struct execdata) [BFD]: New member `interp_section'.
- (check_section): Notice section named ".interp" and set that pointer.
- (load_section): Do nothing if the section is zero size.
- When reading into our copy of the overlap page, don't read past
- the end of the section.
- (do_exec): Consolidate new subfunction `check_maybe_gzip'.
- If there is an interpreter section, load the interpreter file too,
- and use its entry point instead of the user program's. Cleaned up
- and made more robust deallocation of BOOT info on error.
- (deadboot): New function, split out of do_mach_port_notify_no_senders.
-
- * Makefile (vpath lib%.a): Add search path.
- (exec): Depend on -lbfd and -liberty.
- (CPPFLAGS): Append -DBFD; omit -DA_OUT_H=...
- (bfdexec): Target removed.
- * exec.c (load_section): fseek to desired position before freading.
- (input_room): Always map a page-aligned region.
-
-Thu Feb 9 01:01:57 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (check_section): Don't check SEC_RELOC flag.
-
-Wed Feb 8 19:48:11 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * exec.c (load_section) [BFD]: BFD does not set SEC_HAS_CONTENTS
- on a.out BSS's ever; don't make zeroing of bss conditional on that.
- It's not clear exactly what SEC_HAS_CONTENTS is for anyhow;
- perhaps the Right Thing is to set in on BSS. In any case, don't
- depend on this flag here.
-
-Sat Jan 28 17:08:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (prepare): Give the stream a seek function.
-
-Sun Jan 22 03:16:17 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c: Update BFD code; it works now.
- * hostarch.c [BFD]: Fix prototype.
-
-Thu Jan 19 01:24:18 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hostarch.c: Add case for CPU_TYPE_ALPHA.
-
- * hostarch.c (bfd_mach_host_arch_mach, aout_mach_host_machine):
- Use mach_msg_type_number_t instead of unsigned int. Cast
- &HOSTINFO to (natural_t *).
-
-Sun Jan 15 06:29:56 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c [BFD] (bfd_mach_host_arch_mach): In decl, MACHINE arg is
- `long int *' now.
- [BFD] (host_bfd_arch_info): New variable.
- [BFD] (host_bfd): Initialize `arch_info' member to its address.
- (check) [BFD]: Use bfd_arch_get_compatible properly, rather than the
- nonexistent bfd_arch_compatible.
- (main) [BFD]: Fill in host_bfd.arch_info instead of old
- `obj_machine' and `obj_archiecture' members, which BFD no longer has.
- * hostarch.c [BFD] (bfd_mach_host_arch_mach): MACHINE arg is `long
- int *' now.
-
-Tue Dec 13 23:28:08 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Add unzip.o util.o inflate.o.
- (LCLHDRS): Add gzip.h crypt.h tailor.h.
- (unzip.o util.o inflate.o): Depend on those.
- (CFLAGS): Use +=.
- * inflate.c, unzip.c, util.c, tailor.h, gzip.h, crypt.h: New files.
-
-Sun Dec 11 19:49:01 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (struct execdata): New members `headbuf', `file_data',
- `optimal_block'.
- (load_section): Copy data from U->file_data if that is nonnull.
- Use new subfunction `write_to_task' that handles non-page aligned
- sections.
- (input_room): Fix EOF check.
- Use io_read if no memory object.
- (prepare): New function, broken out of check.
- Initialize E->file_data and E->optimal_block. Set
- E->stream.__seen bit.
- (check): No longer take FILE arg.
- Use E->file_data if nonnull; else read from stream if no memory object.
- (finish_mapping): Reset members after deallocating resources.
- (finish): Likewise. Call fclose. Don't deallocate E->header if
- it points to &E->headbuf or E->file_data.
- (check_gzip): New function, implements executing gzip'd binaries.
- (do_exec): Call prepare before check.
- Call check_gzip if file format unrecognized.
-
-Wed Nov 9 01:40:28 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * exec.c (set_active_trans): Don't deallocate EXECNODE here to
- work around a ufs bug.
-
- * exec.c: Include <hurd/paths.h> and <fcntl.h>.
- (set_active_trans): New function.
- (S_exec_init): Call set_active_trans.
-
-Wed Aug 31 11:16:04 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * exec.c (load_section): Pass address of stream in call to fread.
- (input_room): Cast second arg to vm_deallocate. Dereference F
- in setting __error member.
- (close_exec_stream): Provide all three args to vm_deallocate
- and cast the second one properly.
-
-Wed Aug 31 04:32:26 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c (do_exec): Do check before task_suspend.
- #if 0'd out: If check gets ENOEXEC, call check_hashbang.
- (struct execdata): Move member `stream' outside of [BFD].
- (load_section): Use fread instead of hand mapping and copying
- unconditionally (was [BFD]); old code left #if'd out.
- (close_exec_stream): Renamed from close_stdio_bfd; moved out of [BFD].
- (input_room): Define unconditionally, not [BFD].
- (check): Set up E->stream unconditionally.
-
-Tue Aug 30 11:58:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * exec.c (S_fsys_syncfs, S_fsys_mod_readonly): New stubs.
-
- * exec.c (set_init_port): Use new authentication protocol.
-
- * exec.c (S_exec_exec): Call hurd_file_name_lookup instead
- of hurd_path_lookup.
-
- * exec.c (S_fsys_getroot): Return FS_RETRY_NORMAL instead
- of FS_RETRY_NONE.
-
- * exec.c (procserver): New global variable.
- (S_exec_init): Set procserver.
- (do_exec): Use `procserver' instead of USEPORT macro.
- (S_exec_init): Likewise.
-
-Mon Aug 29 13:08:44 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * exec.c (do_exec): Enable and fix up code for doing proc_reassign
- in the EXEC_NEWTASK case.
- (do_exec): If we don't provide the proc port, and this is a
- newtask exec, then use the proc port to fetch a new one
- corresponding to the new task.
-
-Wed Aug 17 14:59:58 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * exec.c (S_exec_exec): Bother to pass flags to do_exec.
-
- * exec.c (essentialstartupport, essentialhostport): Deleted vars.
- (S_exec_init): Do startup_essential_task here like before, but
- make sure we do it last.
- (S_exec_setexecdata): Don't do startup_essential_task here.
-
-Tue Aug 16 10:02:50 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * exec.c (set_init_port): Don't assume that MACH_PORT_NULL == 0.
- (do_exec): Likewise.
-
-Mon Aug 15 21:23:13 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.c: Include <unistd.h> for getpid decl.
- (set_init_port): Use pid_t for PID.
- (S_exec_init): Pass poly arg to proc_execdata_notify.
-
-Mon Aug 15 15:24:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * exec.c (do_exec): Finish implementing EXEC_SECURE flag;
- implement EXEC_DEFAULTS flag.
- (S_exec_init): Delay startup_essential_task until after
- we've received the first essential ports from the proc server.
- (essentialstartupport essentialhostport): New global vars.
-
-Fri Jul 22 10:21:30 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
- * exec.c: Include "exec_S.h" instead of "exec_server.h".
- Include "notify_S.h".
-
-Tue Jul 19 20:51:58 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile (exec_server.h execServer.c, fsys_S.h fsysServer.c):
- Find .defs file in ../hurd, not $(includedir).
-
-Tue Jul 19 12:42:32 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * exec.c (S_fsys_getroot): New arg `dotdot'; don't do anything
- with it.
- (S_fsys_startup): Removed dotdot args.
- (main): Deleted var `dotdot'; don't expect it from fsys_startup.
-
- * Makefile (exec): Don't use variable $(link) anymore.
-
-Tue Jul 5 14:20:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (SRCS, TAGSHDRS): New variables.
-
-Fri Jun 24 14:42:59 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * exec.c (load_section) [AOUT, mapstart > addr]: Dereference
- U->header in use of N_MAGIC.
-
-Fri Jun 24 02:40:32 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.c (load_section): Store protection of section in new local
- VM_PROT. If vm_write of overlap page gets KERN_PROTECTION_FAILURE,
- change protection of overlap page long enough to write it.
- [AOUT]: Return ENOEXEC if there is overlap in NMAGIC or ZMAGIC.
-
-Thu Jun 16 16:15:17 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * exec.c (S_fsys_getroot): Implement new fsys_getroot interface.
-
-Mon Jun 13 04:06:24 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * exec.c (check): Store FILE in E->file.
-
-Tue May 31 17:20:24 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * a.out.h (struct exec): Type removed.
- (OMAGIC, NMAGIC, ZMAGIC, N_MAGIC, N_MACHTYPE, N_BADMAG): Macros
- removed. Just #include "a.out.gnu.h" to get all these defined.
- (N_TXTLEN, N_TXTOFF): Use N_MAGIC instead of a_magic member.
-
- * Makefile (DIST_FILES): Add a.out.gnu.h.
- (exec.o, hostarch.o): Depend on a.out.gnu.h.
-
-Fri May 27 01:40:04 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.c (servercopy): New function to check the servercopy flag
- and possibly vm_allocate a copy of argument data.
- (do_exec): Take new args DTABLE_COPY, PORTARRAY_COPY,
- INTARRAY_COPY. Use servercopy for ARGV, ENVP, DTABLE, PORTARRAY,
- and INTARRAY.
- (S_exec_exec): Take those new args and pass them to do_exec.
- (S_exec_setexecdata): Take new args PORTS_COPY and INTS_COPY.
- Use servercopy for PORTS and INTS.
- (S_exec_startup): Never copy from info in *BOOT, always just set
- the argument pointers to the pointers in *BOOT. MiG will copy and
- deallocate the space as necessary.
-
- * exec.c (check): Lock and unlock E->cntl->lock properly.
- (finish_mapping): New function, broken out of finish.
- (postload_section): New function, broken out of load_section.
- (postload): New function, like load but calls postload_section.
- (do_exec): Call finish_mapping and postload between load and finish.
-
-Tue May 24 19:49:16 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.c (S_exec_exec): Use strsep instead of strtok.
- (main): Keep looping after error from mach_msg_server.
-
-Tue May 24 14:22:16 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * exec.c (load_section): Cast arg to vm_deallocate properly.
-
-Tue May 24 01:05:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.c (struct bootinfo): Remove members argv_vmalloc, envp_vmalloc.
- (do_exec): Don't set BOOT->argv_vmalloc or BOOT->envp_vmalloc. If
- ARGV_COPY is set, vm_allocate space for ARGV; likewise for
- ENVP_COPY and ENVP.
- (S_exec_startup): Don't test BOOT->argv_vmalloc and
- BOOT->envp_vmalloc; BOOT->argv and BOOT->envp are always vm_allocate'd.
- (do_mach_notify_no_senders): Likewise.
- (load_section): Handle non-bss sections that are not page aligned.
-
-Mon May 23 22:01:11 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.c (S_exec_exec): Reverse args to memmem.
- (do_exec): Don't vm_deallocate DEALLOCNAMES or DESTROYNAMES; mig
- deallocates the space for us.
-
-Tue May 17 13:33:41 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * exec.c (S_exec_init): Don't deallocate host_priv until after
- we've used it in the call to startup_essential_task.
-
-Thu May 12 03:53:57 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.c (S_fsys_init): Add reply port args.
-
-Wed May 11 16:03:07 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * exec.c (S_exec_init): Spelling fix.
-
- * Makefile (exec.o): Add dependencies on fsys_S.h and notify_S.h.
- (fsysServer.c, notifyServer.c): Notice that these rules build
- fsys_S.h and notify_S.h respectively.
-
-Mon May 9 17:06:52 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * exec.c (exec_version, save_argv): New variable.
- (main): Set save_argv.
- (S_exec_init): Give the real argv to proc.
- Call proc_register_version if we can.
- (S_exec_init): Call startup_essential_task if we can.
-
-Thu May 5 06:25:02 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
- * exec.c: Change return type of all RPC server functions to
- kern_return_t. error_t is not compatible with the declarations in
- the mig-generated header files.
-
- * exec.c (do_exec): Set BOOT->stack_base and BOOT->stack_size with
- mach_setup_thread.
- (S_exec_exec): Pass msg type arg for FILE arg to exec_exec.
-
-Thu Dec 23 18:05:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.c (do_exec): For a newtask exec when EXEC_SECURE is not set
- and OLDTASK is not null, send the `task_create' RPC on OLDTASK
- rather than mach_task_self ().
diff --git a/exec/Makefile b/exec/Makefile
index 6a5d9525..e7050c10 100644
--- a/exec/Makefile
+++ b/exec/Makefile
@@ -1,6 +1,6 @@
-# Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1993,94,95,96,98,99,2000,01,02,10 Free Software Foundation, Inc.
# This file is part of the GNU Hurd.
-#
+#
# The GNU Hurd is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
@@ -10,7 +10,7 @@
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with the GNU Hurd; see the file COPYING. If not, write to
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -18,21 +18,27 @@
dir := exec
makemode := server
-SRCS = exec.c main.c hashexec.c hostarch.c unzip.c util.c inflate.c
+SRCS = exec.c main.c hashexec.c hostarch.c \
+ $(gzip-sources) $(bzip2-sources)
OBJS = main.o hostarch.o exec.o hashexec.o \
execServer.o exec_startupServer.o \
- $(gzip-objects)
-gzip-objects = unzip.o util.o inflate.o
+ $(gzip-objects) $(bzip2-objects)
+gzip-sources = unzip.c util.c inflate.c
+gzip-objects = $(gzip-sources:%.c=%.o)
+bzip2-sources = do-bunzip2.c
+bzip2-objects = $(bzip2-sources:%.c=%.o)
+
LCLHDRS = gzip.h crypt.h tailor.h priv.h execmutations.h
target = exec
-DIST_FILES = core.c gcore.c elfcore.c exectrans.c
+#targets = exec exec.static
+DIST_FILES = elfcore.c
#OTHERLIBS = -lbfd -liberty
+HURDLIBS = trivfs fshelp iohelp threads ports ihash shouldbeinlibc
exec-MIGSFLAGS = -imacros $(srcdir)/execmutations.h
include ../Makeconf
-CPPFLAGS += -DGZIP # -DBFD
+CPPFLAGS += -DGZIP -DBZIP2 # -DBFD
-exec: ../libtrivfs/libtrivfs.so ../libthreads/libthreads.so \
- ../libshouldbeinlibc/libshouldbeinlibc.so ../libfshelp/libfshelp.so
+exec.static exec: $(OBJS) $(library_deps)
diff --git a/exec/core.c b/exec/core.c
deleted file mode 100644
index 6d685a23..00000000
--- a/exec/core.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/* GNU Hurd standard core server.
- Copyright (C) 1992 Free Software Foundation, Inc.
- Written by Roland McGrath.
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd.h>
-#include "core_server.h"
-#include <bfd.h>
-#include <string.h>
-
-/* Uses nonexistent bfd function: */
-char *bfd_intuit_section_name (bfd_vma vma, bfd_size_type size,
- flagword *flags);
-
-/* Object file format to write core files in. */
-static char *core_target = NULL;
-
-/* Dump a core from TASK into FILE.
- SIGNO and SIGCODE indicate the signal that killed the process. */
-
-error_t
-core_dump_task (mach_port_t coreserver,
- task_t task,
- file_t file,
- int signo, int sigcode,
- const char *my_target)
-{
- error_t err;
-
- processor_set_name_t pset;
- host_t host;
- processor_set_basic_info_data_t pinfo;
-
- thread_t *threads;
- size_t nthreads;
-
- vm_address_t addr;
- vm_size_t size;
- vm_prot_t prot, maxprot;
- vm_inherit_t inherit;
- boolean_t shared;
- memory_object_name_t objname;
- vm_offset_t offset;
-
- bfd *bfd;
- bfd_architecture arch;
- bfd_machine machine;
- asection *sec;
-
- /* The task is suspended while we examine it.
- In the case of a post-mortem dump, the only thread not suspended will
- be the signal thread, which will be blocked waiting for this RPC to
- return. But for gcore, threads might be running. And Leviticus
- specifies that only suspended threads be thread_info'd, anyway. */
- if (err = task_suspend (task))
- goto lose;
-
- /* Figure out what flavor of machine the task is on. */
- if (err = task_get_assignment (task, &pset))
- goto lose;
- err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host,
- &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT);
- mach_port_deallocate (mach_task_self (), pset);
- if (err)
- goto lose;
- err = bfd_mach_host_arch_mach (host, &arch, &machine);
- mach_port_deallocate (mach_task_self (), host);
- if (err)
- goto lose;
-
- /* Open the BFD. */
- bfd = NULL;
- {
- FILE *f = fopenport (file, "w");
- if (f == NULL)
- {
- err = errno;
- goto lose;
- }
- bfd = bfd_openstream (f, my_target ?: core_target);
- if (bfd == NULL)
- {
- err = errno;
- (void) fclose (f);
- errno = err;
- goto bfdlose;
- }
- }
-
- bfd_set_arch_mach (bfd, arch, machine);
-
- /* XXX How are thread states stored in bfd? */
- if (err = task_threads (task, &threads, &nthreads))
- goto lose;
-
- /* Create a BFD section to describe each contiguous chunk
- of the task's address space with the same stats. */
- sec = NULL;
- addr = 0;
- while (!vm_region (task, &addr, &size, &prot, &maxprot,
- &inherit, &shared, &objname, &offset))
- {
- mach_port_deallocate (mach_task_self (), objname);
-
- if (prot != VM_PROT_NONE)
- {
- flagword flags = SEC_NO_FLAGS;
-
- if (!(prot & VM_PROT_WRITE))
- flags |= SEC_READONLY;
- if (!(prot & VM_PROT_EXECUTE))
- flags |= SEC_DATA;
-
- if (sec != NULL &&
- (vm_address_t) (bfd_section_vma (bfd, sec) +
- bfd_section_size (bfd, sec)) == addr &&
- flags == (bfd_get_section_flags (bfd, sec) &
- (SEC_READONLY|SEC_DATA)))
- /* Coalesce with the previous section. */
- bfd_set_section_size (bfd, sec,
- bfd_section_size (bfd, sec) + size);
- else
- {
- /* Make a new section (which might grow by
- the next region being coalesced onto it). */
- char *name = bfd_intuit_section_name (addr, size, &flags);
- if (name == NULL)
- {
- /* No guess from BFD. */
- if (asprintf (&name, "[%p,%p) %c%c%c",
- (void *) addr, (void *) (addr + size),
- (prot & VM_PROT_READ) ? 'r' : '-',
- (prot & VM_PROT_WRITE) ? 'w' : '-',
- (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1)
- goto lose;
- }
- sec = bfd_make_section (name);
- bfd_set_section_flags (bfd, sec, flags);
- bfd_set_section_vma (bfd, sec, addr);
- bfd_set_section_size (bfd, sec, size);
- }
- }
- }
-
- /* Write all the sections' data. */
- for (sec = bfd->sections; sec != NULL; sec = sec->next)
- {
- void *data;
- err = vm_read (task, bfd_section_vma (bfd, sec),
- bfd_section_size (bfd, sec), &data);
- if (err)
- /* XXX What to do?
- 1. lose
- 2. remove this section
- 3. mark this section as having ungettable contents (how?)
- */
- goto lose;
- err = bfd_set_section_contents (bfd, sec, data, 0,
- bfd_section_size (bfd, sec));
- vm_deallocate (mach_task_self (), data, bfd_section_size (bfd, sec));
- if (err)
- goto bfdlose;
- }
-
- bfdlose:
- switch (bfd_error)
- {
- case system_call_error:
- err = errno;
- break;
-
- case no_memory:
- err = ENOMEM;
- break;
-
- default:
- err = EGRATUITOUS;
- break;
- }
-
- lose:
- if (bfd != NULL)
- bfd_close (bfd);
- else
- mach_port_deallocate (mach_task_self (), file);
- task_resume (task);
- mach_port_deallocate (mach_task_self (), task);
- return err;
-}
-
-error_t
-fsys_getroot (fsys_t fsys, idblock_t id, file_t realnode, file_t dotdot,
- file_t *root)
-{
- *root = core;
- mach_port_deallocate (mach_task_self (), realnode);
- mach_port_deallocate (mach_task_self (), dotdot);
- return POSIX_SUCCESS;
-}
-
-mach_port_t request_portset;
-
-int
-request_server (mach_msg_header_t *inp,
- mach_msg_header_t *outp)
-{
- if (inp->msgh_local_port == fsys)
- return fsys_server (inp, outp);
- else if (inp->msgh_local_port == core)
- return (core_server (inp, outp) ||
- io_server (inp, outp) ||
- fs_server (inp, outp));
-}
-
-int
-main (int argc, char **argv)
-{
- error_t err;
- fsys_t fsys;
- mach_port_t boot, dotdot;
-
- if ((err = mach_port_allocate (mach_task_self (),
- MACH_PORT_RIGHT_RECEIVE, &fsys)) ||
- (err = mach_port_allocate (mach_task_self (),
- MACH_PORT_RIGHT_RECEIVE, &core)))
- hurd_perror ("mach_port_allocate", err);
- else if (err = task_get_bootstrap_port (mach_task_self (), &boot))
- hurd_perror ("task_get_bootstrap_port", err);
- else if (err = fsys_startup (boot, fsys, &realnode, &dotdot))
- hurd_perror ("fsys_startup", err);
- mach_port_deallocate (mach_task_self (), dotdot);
-
- mach_port_allocate (mach_task_self (),
- MACH_PORT_RIGHT_PORT_SET, &request_portset);
-
- mach_port_move_member (mach_task_self (), fsys, request_portset);
- mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &core);
- mach_port_move_member (mach_task_self (), core, request_portset);
-
- mach_port_mod_refs (mach_task_self (), realnode, MACH_PORT_RIGHT_SEND, 1);
-
- core_target = argv[1];
-
- do
- err = mach_msg_server (request_server, vm_page_size, request_portset);
- while (!err);
- hurd_perror ("mach_msg_server", err);
- return 1;
-}
diff --git a/exec/do-bunzip2.c b/exec/do-bunzip2.c
new file mode 100644
index 00000000..716a0cde
--- /dev/null
+++ b/exec/do-bunzip2.c
@@ -0,0 +1,1745 @@
+/* bunzip2 engine, modified by okuji@kuicr.kyoto-u.ac.jp. */
+
+/* Stolen from util.c. */
+#include <stdio.h>
+#include <sys/types.h>
+
+/* I/O interface */
+extern int (*unzip_read) (char *buf, size_t maxread);
+extern void (*unzip_write) (const char *buf, size_t nwrite);
+extern void (*unzip_read_error) (void);
+extern void (*unzip_error) (const char *msg);
+
+/* bzip2 doesn't require window sliding. Just for buffering. */
+#define INBUFSIZ 0x1000
+#define OUTBUFSIZ 0x1000
+
+static unsigned char inbuf[INBUFSIZ];
+static unsigned char outbuf[OUTBUFSIZ];
+static unsigned inptr;
+static unsigned insize;
+static unsigned outcnt;
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ */
+static int
+fill_inbuf (int eof_ok)
+{
+ int len;
+
+ /* Read as much as possible */
+ insize = 0;
+ do
+ {
+ len = (*unzip_read)((char*)inbuf+insize, INBUFSIZ-insize);
+ if (len == 0 || len == EOF)
+ break;
+ insize += len;
+ }
+ while (insize < INBUFSIZ);
+
+ if (insize == 0)
+ {
+ if (eof_ok)
+ return EOF;
+ unzip_read_error();
+ }
+
+ inptr = 1;
+ return inbuf[0];
+}
+
+static void
+flush_outbuf (void)
+{
+ if (outcnt == 0)
+ return;
+
+ (*unzip_write) ((char *) outbuf, outcnt);
+ outcnt = 0;
+}
+
+static inline int
+bz2_getc (void *stream)
+{
+ return inptr < insize ? inbuf[inptr++] : fill_inbuf (1);
+}
+
+static inline int
+bz2_putc (int c, void *stream)
+{
+ if (outcnt == OUTBUFSIZ)
+ flush_outbuf ();
+ outbuf[outcnt++] = c;
+ return c;
+}
+
+static inline int
+bz2_ferror (void *stream)
+{
+ return 0;
+}
+
+static inline int
+bz2_fflush (void *stream)
+{
+ flush_outbuf ();
+ return 0;
+}
+
+static inline int
+bz2_fclose (void *stream)
+{
+ flush_outbuf ();
+ return 0;
+}
+
+#define fprintf(s, f...) /**/
+
+
+/*-----------------------------------------------------------*/
+/*--- A block-sorting, lossless compressor bzip2.c ---*/
+/*-----------------------------------------------------------*/
+
+/*--
+ This program is bzip2, a lossless, block-sorting data compressor,
+ version 0.1pl2, dated 29-Aug-1997.
+
+ Copyright (C) 1996, 1997 by Julian Seward.
+ Guildford, Surrey, UK
+ email: jseward@acm.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The GNU General Public License is contained in the file LICENSE.
+
+ This program is based on (at least) the work of:
+ Mike Burrows
+ David Wheeler
+ Peter Fenwick
+ Alistair Moffat
+ Radford Neal
+ Ian H. Witten
+ Robert Sedgewick
+ Jon L. Bentley
+
+ For more information on these sources, see the file ALGORITHMS.
+--*/
+
+/*----------------------------------------------------*/
+/*--- IMPORTANT ---*/
+/*----------------------------------------------------*/
+
+/*--
+ WARNING:
+ This program (attempts to) compress data by performing several
+ non-trivial transformations on it. Unless you are 100% familiar
+ with *all* the algorithms contained herein, and with the
+ consequences of modifying them, you should NOT meddle with the
+ compression or decompression machinery. Incorrect changes can
+ and very likely *will* lead to disastrous loss of data.
+
+ DISCLAIMER:
+ I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
+ USE OF THIS PROGRAM, HOWSOEVER CAUSED.
+
+ Every compression of a file implies an assumption that the
+ compressed file can be decompressed to reproduce the original.
+ Great efforts in design, coding and testing have been made to
+ ensure that this program works correctly. However, the
+ complexity of the algorithms, and, in particular, the presence
+ of various special cases in the code which occur with very low
+ but non-zero probability make it impossible to rule out the
+ possibility of bugs remaining in the program. DO NOT COMPRESS
+ ANY DATA WITH THIS PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE
+ POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL NOT BE RECOVERABLE.
+
+ That is not to say this program is inherently unreliable.
+ Indeed, I very much hope the opposite is true. bzip2 has been
+ carefully constructed and extensively tested.
+
+ PATENTS:
+ To the best of my knowledge, bzip2 does not use any patented
+ algorithms. However, I do not have the resources available to
+ carry out a full patent search. Therefore I cannot give any
+ guarantee of the above statement.
+--*/
+
+
+
+/*----------------------------------------------------*/
+/*--- and now for something much more pleasant :-) ---*/
+/*----------------------------------------------------*/
+
+/*---------------------------------------------*/
+/*--
+ Place a 1 beside your platform, and 0 elsewhere.
+--*/
+
+/*--
+ Generic 32-bit Unix.
+ Also works on 64-bit Unix boxes.
+--*/
+#define BZ_UNIX 1
+
+/*--
+ Win32, as seen by Jacob Navia's excellent
+ port of (Chris Fraser & David Hanson)'s excellent
+ lcc compiler.
+--*/
+#define BZ_LCCWIN32 0
+
+
+
+/*---------------------------------------------*/
+/*--
+ Some stuff for all platforms.
+--*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#if DEBUG
+ #include <assert.h>
+#endif
+#include <string.h>
+#include <signal.h>
+#include <math.h>
+
+#define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); }
+#define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); }
+#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
+
+
+/*---------------------------------------------*/
+/*--
+ Platform-specific stuff.
+--*/
+
+#if BZ_UNIX
+ #include <sys/types.h>
+ #include <utime.h>
+ #include <unistd.h>
+ #include <malloc.h>
+ #include <sys/stat.h>
+ #include <sys/times.h>
+
+ #define Int32 int
+ #define UInt32 unsigned int
+ #define Char char
+ #define UChar unsigned char
+ #define Int16 short
+ #define UInt16 unsigned short
+
+ #define PATH_SEP '/'
+ #define MY_LSTAT lstat
+ #define MY_S_IFREG S_ISREG
+ #define MY_STAT stat
+
+ #define APPEND_FILESPEC(root, name) \
+ root=snocString((root), (name))
+
+ #define SET_BINARY_MODE(fd) /**/
+
+ /*--
+ You should try very hard to persuade your C compiler
+ to inline the bits marked INLINE. Otherwise bzip2 will
+ run rather slowly. gcc version 2.x is recommended.
+ --*/
+ #ifdef __GNUC__
+ #define INLINE inline
+ #define NORETURN __attribute__ ((noreturn))
+ #else
+ #define INLINE /**/
+ #define NORETURN /**/
+ #endif
+#endif
+
+
+
+#if BZ_LCCWIN32
+ #include <io.h>
+ #include <fcntl.h>
+ #include <sys\stat.h>
+
+ #define Int32 int
+ #define UInt32 unsigned int
+ #define Int16 short
+ #define UInt16 unsigned short
+ #define Char char
+ #define UChar unsigned char
+
+ #define INLINE /**/
+ #define NORETURN /**/
+ #define PATH_SEP '\\'
+ #define MY_LSTAT _stat
+ #define MY_STAT _stat
+ #define MY_S_IFREG(x) ((x) & _S_IFREG)
+
+ #if 0
+ /*-- lcc-win32 seems to expand wildcards itself --*/
+ #define APPEND_FILESPEC(root, spec) \
+ do { \
+ if ((spec)[0] == '-') { \
+ root = snocString((root), (spec)); \
+ } else { \
+ struct _finddata_t c_file; \
+ long hFile; \
+ hFile = _findfirst((spec), &c_file); \
+ if ( hFile == -1L ) { \
+ root = snocString ((root), (spec)); \
+ } else { \
+ int anInt = 0; \
+ while ( anInt == 0 ) { \
+ root = snocString((root), \
+ &c_file.name[0]); \
+ anInt = _findnext(hFile, &c_file); \
+ } \
+ } \
+ } \
+ } while ( 0 )
+ #else
+ #define APPEND_FILESPEC(root, name) \
+ root = snocString ((root), (name))
+ #endif
+
+ #define SET_BINARY_MODE(fd) \
+ do { \
+ int retVal = setmode ( fileno ( fd ), \
+ O_BINARY ); \
+ ERROR_IF_MINUS_ONE ( retVal ); \
+ } while ( 0 )
+
+#endif
+
+
+/*---------------------------------------------*/
+/*--
+ Some more stuff for all platforms :-)
+--*/
+
+#define Bool unsigned char
+#define True 1
+#define False 0
+
+/*--
+ IntNative is your platform's `native' int size.
+ Only here to avoid probs with 64-bit platforms.
+--*/
+#define IntNative int
+
+
+/*--
+ change to 1, or compile with -DDEBUG=1 to debug
+--*/
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- ---*/
+/*---------------------------------------------------*/
+
+/*--
+ Implementation notes, July 1997
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Memory allocation
+ ~~~~~~~~~~~~~~~~~
+ All large data structures are allocated on the C heap,
+ for better or for worse. That includes the various
+ arrays of pointers, striped words, bytes, frequency
+ tables and buffers for compression and decompression.
+
+ bzip2 can operate at various block-sizes, ranging from
+ 100k to 900k in 100k steps, and it allocates only as
+ much as it needs to. When compressing, we know from the
+ command-line options what the block-size is going to be,
+ so all allocation can be done at start-up; if that
+ succeeds, there can be no further allocation problems.
+
+ Decompression is more complicated. Each compressed file
+ contains, in its header, a byte indicating the block
+ size used for compression. This means bzip2 potentially
+ needs to reallocate memory for each file it deals with,
+ which in turn opens the possibility for a memory allocation
+ failure part way through a run of files, by encountering
+ a file requiring a much larger block size than all the
+ ones preceding it.
+
+ The policy is to simply give up if a memory allocation
+ failure occurs. During decompression, it would be
+ possible to move on to subsequent files in the hope that
+ some might ask for a smaller block size, but the
+ complications for doing this seem more trouble than they
+ are worth.
+
+
+ Compressed file formats
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ [This is now entirely different from both 0.21, and from
+ any previous Huffman-coded variant of bzip.
+ See the associated file bzip2.txt for details.]
+
+
+ Error conditions
+ ~~~~~~~~~~~~~~~~
+ Dealing with error conditions is the least satisfactory
+ aspect of bzip2. The policy is to try and leave the
+ filesystem in a consistent state, then quit, even if it
+ means not processing some of the files mentioned in the
+ command line. `A consistent state' means that a file
+ exists either in its compressed or uncompressed form,
+ but not both. This boils down to the rule `delete the
+ output file if an error condition occurs, leaving the
+ input intact'. Input files are only deleted when we can
+ be pretty sure the output file has been written and
+ closed successfully.
+
+ Errors are a dog because there's so many things to
+ deal with. The following can happen mid-file, and
+ require cleaning up.
+
+ internal `panics' -- indicating a bug
+ corrupted or inconsistent compressed file
+ can't allocate enough memory to decompress this file
+ I/O error reading/writing/opening/closing
+ signal catches -- Control-C, SIGTERM, SIGHUP.
+
+ Other conditions, primarily pertaining to file names,
+ can be checked in-between files, which makes dealing
+ with them easier.
+--*/
+
+
+
+/*---------------------------------------------------*/
+/*--- Misc (file handling) data decls ---*/
+/*---------------------------------------------------*/
+
+static UInt32 bytesIn, bytesOut;
+static Int32 verbosity;
+static Bool smallMode;
+static UInt32 globalCrc;
+
+
+
+
+static void panic ( Char* );
+static void ioError ( void );
+static void uncompressOutOfMemory ( Int32, Int32 );
+static void blockOverrun ( void );
+static void badBlockHeader ( void );
+static void crcError ( UInt32, UInt32 );
+static void cleanUpAndFail ( Int32 );
+static void compressedStreamEOF ( void );
+
+
+
+/*---------------------------------------------------*/
+/*--- Data decls for the front end ---*/
+/*---------------------------------------------------*/
+
+/*--
+ The overshoot bytes allow us to avoid most of
+ the cost of pointer renormalisation during
+ comparison of rotations in sorting.
+ The figure of 20 is derived as follows:
+ qSort3 allows an overshoot of up to 10.
+ It then calls simpleSort, which calls
+ fullGtU, also with max overshoot 10.
+ fullGtU does up to 10 comparisons without
+ renormalising, giving 10+10 == 20.
+--*/
+#define NUM_OVERSHOOT_BYTES 20
+
+/*--
+ These are the main data structures for
+ the Burrows-Wheeler transform.
+--*/
+
+/*--
+ Pointers to compression and decompression
+ structures. Set by
+ allocateCompressStructures and
+ setDecompressStructureSizes
+
+ The structures are always set to be suitable
+ for a block of size 100000 * blockSize100k.
+--*/
+static UInt16 *ll16; /*-- small decompress --*/
+static UChar *ll4; /*-- small decompress --*/
+
+static Int32 *tt; /*-- fast decompress --*/
+static UChar *ll8; /*-- fast decompress --*/
+
+
+/*--
+ freq table collected to save a pass over the data
+ during decompression.
+--*/
+static Int32 unzftab[256];
+
+
+/*--
+ index of the last char in the block, so
+ the block size == last + 1.
+--*/
+static Int32 last;
+
+
+/*--
+ index in zptr[] of original string after sorting.
+--*/
+static Int32 origPtr;
+
+
+/*--
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+--*/
+static Int32 blockSize100k;
+
+
+/*--
+ Used when sorting. If too many long comparisons
+ happen, we stop sorting, randomise the block
+ slightly, and try again.
+--*/
+
+static Bool blockRandomised;
+
+
+
+/*---------------------------------------------------*/
+/*--- Data decls for the back end ---*/
+/*---------------------------------------------------*/
+
+#define MAX_ALPHA_SIZE 258
+#define MAX_CODE_LEN 23
+
+#define RUNA 0
+#define RUNB 1
+
+#define N_GROUPS 6
+#define G_SIZE 50
+#define N_ITERS 4
+
+#define MAX_SELECTORS (2 + (900000 / G_SIZE))
+
+static Bool inUse[256];
+static Int32 nInUse;
+
+static UChar seqToUnseq[256];
+static UChar unseqToSeq[256];
+
+static UChar selector [MAX_SELECTORS];
+static UChar selectorMtf[MAX_SELECTORS];
+
+static UChar len [N_GROUPS][MAX_ALPHA_SIZE];
+
+/*-- decompress only --*/
+static Int32 limit [N_GROUPS][MAX_ALPHA_SIZE];
+static Int32 base [N_GROUPS][MAX_ALPHA_SIZE];
+static Int32 perm [N_GROUPS][MAX_ALPHA_SIZE];
+static Int32 minLens[N_GROUPS];
+
+
+/*---------------------------------------------------*/
+/*--- 32-bit CRC grunge ---*/
+/*---------------------------------------------------*/
+
+/*--
+ I think this is an implementation of the AUTODIN-II,
+ Ethernet & FDDI 32-bit CRC standard. Vaguely derived
+ from code by Rob Warnock, in Section 51 of the
+ comp.compression FAQ.
+--*/
+
+static UInt32 crc32Table[256] = {
+
+ /*-- Ugly, innit? --*/
+
+ 0x00000000UL, 0x04c11db7UL, 0x09823b6eUL, 0x0d4326d9UL,
+ 0x130476dcUL, 0x17c56b6bUL, 0x1a864db2UL, 0x1e475005UL,
+ 0x2608edb8UL, 0x22c9f00fUL, 0x2f8ad6d6UL, 0x2b4bcb61UL,
+ 0x350c9b64UL, 0x31cd86d3UL, 0x3c8ea00aUL, 0x384fbdbdUL,
+ 0x4c11db70UL, 0x48d0c6c7UL, 0x4593e01eUL, 0x4152fda9UL,
+ 0x5f15adacUL, 0x5bd4b01bUL, 0x569796c2UL, 0x52568b75UL,
+ 0x6a1936c8UL, 0x6ed82b7fUL, 0x639b0da6UL, 0x675a1011UL,
+ 0x791d4014UL, 0x7ddc5da3UL, 0x709f7b7aUL, 0x745e66cdUL,
+ 0x9823b6e0UL, 0x9ce2ab57UL, 0x91a18d8eUL, 0x95609039UL,
+ 0x8b27c03cUL, 0x8fe6dd8bUL, 0x82a5fb52UL, 0x8664e6e5UL,
+ 0xbe2b5b58UL, 0xbaea46efUL, 0xb7a96036UL, 0xb3687d81UL,
+ 0xad2f2d84UL, 0xa9ee3033UL, 0xa4ad16eaUL, 0xa06c0b5dUL,
+ 0xd4326d90UL, 0xd0f37027UL, 0xddb056feUL, 0xd9714b49UL,
+ 0xc7361b4cUL, 0xc3f706fbUL, 0xceb42022UL, 0xca753d95UL,
+ 0xf23a8028UL, 0xf6fb9d9fUL, 0xfbb8bb46UL, 0xff79a6f1UL,
+ 0xe13ef6f4UL, 0xe5ffeb43UL, 0xe8bccd9aUL, 0xec7dd02dUL,
+ 0x34867077UL, 0x30476dc0UL, 0x3d044b19UL, 0x39c556aeUL,
+ 0x278206abUL, 0x23431b1cUL, 0x2e003dc5UL, 0x2ac12072UL,
+ 0x128e9dcfUL, 0x164f8078UL, 0x1b0ca6a1UL, 0x1fcdbb16UL,
+ 0x018aeb13UL, 0x054bf6a4UL, 0x0808d07dUL, 0x0cc9cdcaUL,
+ 0x7897ab07UL, 0x7c56b6b0UL, 0x71159069UL, 0x75d48ddeUL,
+ 0x6b93dddbUL, 0x6f52c06cUL, 0x6211e6b5UL, 0x66d0fb02UL,
+ 0x5e9f46bfUL, 0x5a5e5b08UL, 0x571d7dd1UL, 0x53dc6066UL,
+ 0x4d9b3063UL, 0x495a2dd4UL, 0x44190b0dUL, 0x40d816baUL,
+ 0xaca5c697UL, 0xa864db20UL, 0xa527fdf9UL, 0xa1e6e04eUL,
+ 0xbfa1b04bUL, 0xbb60adfcUL, 0xb6238b25UL, 0xb2e29692UL,
+ 0x8aad2b2fUL, 0x8e6c3698UL, 0x832f1041UL, 0x87ee0df6UL,
+ 0x99a95df3UL, 0x9d684044UL, 0x902b669dUL, 0x94ea7b2aUL,
+ 0xe0b41de7UL, 0xe4750050UL, 0xe9362689UL, 0xedf73b3eUL,
+ 0xf3b06b3bUL, 0xf771768cUL, 0xfa325055UL, 0xfef34de2UL,
+ 0xc6bcf05fUL, 0xc27dede8UL, 0xcf3ecb31UL, 0xcbffd686UL,
+ 0xd5b88683UL, 0xd1799b34UL, 0xdc3abdedUL, 0xd8fba05aUL,
+ 0x690ce0eeUL, 0x6dcdfd59UL, 0x608edb80UL, 0x644fc637UL,
+ 0x7a089632UL, 0x7ec98b85UL, 0x738aad5cUL, 0x774bb0ebUL,
+ 0x4f040d56UL, 0x4bc510e1UL, 0x46863638UL, 0x42472b8fUL,
+ 0x5c007b8aUL, 0x58c1663dUL, 0x558240e4UL, 0x51435d53UL,
+ 0x251d3b9eUL, 0x21dc2629UL, 0x2c9f00f0UL, 0x285e1d47UL,
+ 0x36194d42UL, 0x32d850f5UL, 0x3f9b762cUL, 0x3b5a6b9bUL,
+ 0x0315d626UL, 0x07d4cb91UL, 0x0a97ed48UL, 0x0e56f0ffUL,
+ 0x1011a0faUL, 0x14d0bd4dUL, 0x19939b94UL, 0x1d528623UL,
+ 0xf12f560eUL, 0xf5ee4bb9UL, 0xf8ad6d60UL, 0xfc6c70d7UL,
+ 0xe22b20d2UL, 0xe6ea3d65UL, 0xeba91bbcUL, 0xef68060bUL,
+ 0xd727bbb6UL, 0xd3e6a601UL, 0xdea580d8UL, 0xda649d6fUL,
+ 0xc423cd6aUL, 0xc0e2d0ddUL, 0xcda1f604UL, 0xc960ebb3UL,
+ 0xbd3e8d7eUL, 0xb9ff90c9UL, 0xb4bcb610UL, 0xb07daba7UL,
+ 0xae3afba2UL, 0xaafbe615UL, 0xa7b8c0ccUL, 0xa379dd7bUL,
+ 0x9b3660c6UL, 0x9ff77d71UL, 0x92b45ba8UL, 0x9675461fUL,
+ 0x8832161aUL, 0x8cf30badUL, 0x81b02d74UL, 0x857130c3UL,
+ 0x5d8a9099UL, 0x594b8d2eUL, 0x5408abf7UL, 0x50c9b640UL,
+ 0x4e8ee645UL, 0x4a4ffbf2UL, 0x470cdd2bUL, 0x43cdc09cUL,
+ 0x7b827d21UL, 0x7f436096UL, 0x7200464fUL, 0x76c15bf8UL,
+ 0x68860bfdUL, 0x6c47164aUL, 0x61043093UL, 0x65c52d24UL,
+ 0x119b4be9UL, 0x155a565eUL, 0x18197087UL, 0x1cd86d30UL,
+ 0x029f3d35UL, 0x065e2082UL, 0x0b1d065bUL, 0x0fdc1becUL,
+ 0x3793a651UL, 0x3352bbe6UL, 0x3e119d3fUL, 0x3ad08088UL,
+ 0x2497d08dUL, 0x2056cd3aUL, 0x2d15ebe3UL, 0x29d4f654UL,
+ 0xc5a92679UL, 0xc1683bceUL, 0xcc2b1d17UL, 0xc8ea00a0UL,
+ 0xd6ad50a5UL, 0xd26c4d12UL, 0xdf2f6bcbUL, 0xdbee767cUL,
+ 0xe3a1cbc1UL, 0xe760d676UL, 0xea23f0afUL, 0xeee2ed18UL,
+ 0xf0a5bd1dUL, 0xf464a0aaUL, 0xf9278673UL, 0xfde69bc4UL,
+ 0x89b8fd09UL, 0x8d79e0beUL, 0x803ac667UL, 0x84fbdbd0UL,
+ 0x9abc8bd5UL, 0x9e7d9662UL, 0x933eb0bbUL, 0x97ffad0cUL,
+ 0xafb010b1UL, 0xab710d06UL, 0xa6322bdfUL, 0xa2f33668UL,
+ 0xbcb4666dUL, 0xb8757bdaUL, 0xb5365d03UL, 0xb1f740b4UL
+};
+
+
+/*---------------------------------------------*/
+
+static void initialiseCRC ( void )
+{
+ globalCrc = 0xffffffffUL;
+}
+
+
+/*---------------------------------------------*/
+
+static UInt32 getFinalCRC ( void )
+{
+ return ~globalCrc;
+}
+
+
+/*---------------------------------------------*/
+
+static UInt32 getGlobalCRC ( void )
+{
+ return globalCrc;
+}
+
+
+/*---------------------------------------------*/
+
+static void setGlobalCRC ( UInt32 newCrc )
+{
+ globalCrc = newCrc;
+}
+
+
+/*---------------------------------------------*/
+
+#define UPDATE_CRC(crcVar,cha) \
+{ \
+ crcVar = (crcVar << 8) ^ \
+ crc32Table[(crcVar >> 24) ^ \
+ ((UChar)cha)]; \
+}
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O ---*/
+/*---------------------------------------------------*/
+
+
+static UInt32 bsBuff;
+static Int32 bsLive;
+static void* bsStream;
+static Bool bsWriting;
+
+
+/*---------------------------------------------*/
+
+static void bsSetStream ( void* f, Bool wr )
+{
+ if (bsStream != NULL) panic ( "bsSetStream" );
+ bsStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ bytesOut = 0;
+ bytesIn = 0;
+ bsWriting = wr;
+}
+
+
+/*---------------------------------------------*/
+
+static void bsFinishedWithStream ( void )
+{
+ if (bsWriting)
+ while (bsLive > 0) {
+ bz2_putc ( (UChar)(bsBuff >> 24), bsStream );
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ bsStream = NULL;
+}
+
+
+/*---------------------------------------------*/
+
+#define bsNEEDR(nz) \
+{ \
+ while (bsLive < nz) { \
+ Int32 zzi = bz2_getc ( bsStream ); \
+ if (zzi == EOF) compressedStreamEOF(); \
+ bsBuff = (bsBuff << 8) | (zzi & 0xffL); \
+ bsLive += 8; \
+ } \
+}
+
+
+/*---------------------------------------------*/
+
+#define bsR1(vz) \
+{ \
+ bsNEEDR(1); \
+ vz = (bsBuff >> (bsLive-1)) & 1; \
+ bsLive--; \
+}
+
+
+/*---------------------------------------------*/
+
+static INLINE UInt32 bsR ( Int32 n )
+{
+ UInt32 v;
+ bsNEEDR ( n );
+ v = (bsBuff >> (bsLive-n)) & ((1 << n)-1);
+ bsLive -= n;
+ return v;
+}
+
+
+/*---------------------------------------------*/
+
+static UChar bsGetUChar ( void )
+{
+ return (UChar)bsR(8);
+}
+
+
+
+/*---------------------------------------------*/
+
+static Int32 bsGetUInt32 ( void )
+{
+ UInt32 u;
+ u = 0;
+ u = (u << 8) | bsR(8);
+ u = (u << 8) | bsR(8);
+ u = (u << 8) | bsR(8);
+ u = (u << 8) | bsR(8);
+ return u;
+}
+
+
+/*---------------------------------------------*/
+
+static UInt32 bsGetIntVS ( UInt32 numBits )
+{
+ return (UInt32)bsR(numBits);
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- Huffman coding low-level stuff ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------*/
+
+static void hbCreateDecodeTables ( Int32 *limit,
+ Int32 *base,
+ Int32 *perm,
+ UChar *length,
+ Int32 minLen,
+ Int32 maxLen,
+ Int32 alphaSize )
+{
+ Int32 pp, i, j, vec;
+
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++)
+ for (j = 0; j < alphaSize; j++)
+ if (length[j] == i) { perm[pp] = j; pp++; };
+
+ for (i = 0; i < MAX_CODE_LEN; i++) base[i] = 0;
+ for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+ for (i = 1; i < MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+ for (i = 0; i < MAX_CODE_LEN; i++) limit[i] = 0;
+ vec = 0;
+
+ for (i = minLen; i <= maxLen; i++) {
+ vec += (base[i+1] - base[i]);
+ limit[i] = vec-1;
+ vec <<= 1;
+ }
+ for (i = minLen + 1; i <= maxLen; i++)
+ base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- Undoing the reversible transformation ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+#define SET_LL4(i,n) \
+ { if (((i) & 0x1) == 0) \
+ ll4[(i) >> 1] = (ll4[(i) >> 1] & 0xf0) | (n); else \
+ ll4[(i) >> 1] = (ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
+ }
+
+
+#define GET_LL4(i) \
+ (((UInt32)(ll4[(i) >> 1])) >> (((i) << 2) & 0x4) & 0xF)
+
+
+#define SET_LL(i,n) \
+ { ll16[i] = (UInt16)(n & 0x0000ffff); \
+ SET_LL4(i, n >> 16); \
+ }
+
+
+#define GET_LL(i) \
+ (((UInt32)ll16[i]) | (GET_LL4(i) << 16))
+
+
+/*---------------------------------------------*/
+/*--
+ Manage memory for compression/decompression.
+ When compressing, a single block size applies to
+ all files processed, and that's set when the
+ program starts. But when decompressing, each file
+ processed could have been compressed with a
+ different block size, so we may have to free
+ and reallocate on a per-file basis.
+
+ A call with argument of zero means
+ `free up everything.' And a value of zero for
+ blockSize100k means no memory is currently allocated.
+--*/
+
+
+/*---------------------------------------------*/
+
+static void setDecompressStructureSizes ( Int32 newSize100k )
+{
+ if (! (0 <= newSize100k && newSize100k <= 9 &&
+ 0 <= blockSize100k && blockSize100k <= 9))
+ panic ( "setDecompressStructureSizes" );
+
+ if (newSize100k == blockSize100k) return;
+
+ blockSize100k = newSize100k;
+
+ if (ll16 != NULL) free ( ll16 );
+ if (ll4 != NULL) free ( ll4 );
+ if (ll8 != NULL) free ( ll8 );
+ if (tt != NULL) free ( tt );
+
+ if (newSize100k == 0) return;
+
+ if (smallMode) {
+
+ Int32 n = 100000 * newSize100k;
+ ll16 = malloc ( n * sizeof(UInt16) );
+ ll4 = malloc ( ((n+1) >> 1) * sizeof(UChar) );
+
+ if (ll4 == NULL || ll16 == NULL) {
+ Int32 totalDraw
+ = n * sizeof(Int16) + ((n+1) >> 1) * sizeof(UChar);
+ uncompressOutOfMemory ( totalDraw, n );
+ }
+
+ } else {
+
+ Int32 n = 100000 * newSize100k;
+ ll8 = malloc ( n * sizeof(UChar) );
+ tt = malloc ( n * sizeof(Int32) );
+
+ if (ll8 == NULL || tt == NULL) {
+ Int32 totalDraw
+ = n * sizeof(UChar) + n * sizeof(UInt32);
+ uncompressOutOfMemory ( totalDraw, n );
+ }
+
+ }
+}
+
+
+
+/*---------------------------------------------------*/
+/*--- The new back end ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+static void makeMaps ( void )
+{
+ Int32 i;
+ nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = i;
+ unseqToSeq[i] = nInUse;
+ nInUse++;
+ }
+}
+
+
+
+/*---------------------------------------------*/
+
+static void recvDecodingTables ( void )
+{
+ Int32 i, j, t, nGroups, nSelectors, alphaSize;
+ Int32 minLen, maxLen;
+ Bool inUse16[16];
+
+ /*--- Receive the mapping table ---*/
+ for (i = 0; i < 16; i++)
+ if (bsR(1) == 1)
+ inUse16[i] = True; else
+ inUse16[i] = False;
+
+ for (i = 0; i < 256; i++) inUse[i] = False;
+
+ for (i = 0; i < 16; i++)
+ if (inUse16[i])
+ for (j = 0; j < 16; j++)
+ if (bsR(1) == 1) inUse[i * 16 + j] = True;
+
+ makeMaps();
+ alphaSize = nInUse+2;
+
+ /*--- Now the selectors ---*/
+ nGroups = bsR ( 3 );
+ nSelectors = bsR ( 15 );
+ for (i = 0; i < nSelectors; i++) {
+ j = 0;
+ while (bsR(1) == 1) j++;
+ selectorMtf[i] = j;
+ }
+
+ /*--- Undo the MTF values for the selectors. ---*/
+ {
+ UChar pos[N_GROUPS], tmp, v;
+ for (v = 0; v < nGroups; v++) pos[v] = v;
+
+ for (i = 0; i < nSelectors; i++) {
+ v = selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) { pos[v] = pos[v-1]; v--; }
+ pos[0] = tmp;
+ selector[i] = tmp;
+ }
+ }
+
+ /*--- Now the coding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ Int32 curr = bsR ( 5 );
+ for (i = 0; i < alphaSize; i++) {
+ while (bsR(1) == 1) {
+ if (bsR(1) == 0) curr++; else curr--;
+ }
+ len[t][i] = curr;
+ }
+ }
+
+ /*--- Create the Huffman decoding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) maxLen = len[t][i];
+ if (len[t][i] < minLen) minLen = len[t][i];
+ }
+ hbCreateDecodeTables (
+ &limit[t][0], &base[t][0], &perm[t][0], &len[t][0],
+ minLen, maxLen, alphaSize
+ );
+ minLens[t] = minLen;
+ }
+}
+
+
+/*---------------------------------------------*/
+
+#define GET_MTF_VAL(lval) \
+{ \
+ Int32 zt, zn, zvec, zj; \
+ if (groupPos == 0) { \
+ groupNo++; \
+ groupPos = G_SIZE; \
+ } \
+ groupPos--; \
+ zt = selector[groupNo]; \
+ zn = minLens[zt]; \
+ zvec = bsR ( zn ); \
+ while (zvec > limit[zt][zn]) { \
+ zn++; bsR1(zj); \
+ zvec = (zvec << 1) | zj; \
+ }; \
+ lval = perm[zt][zvec - base[zt][zn]]; \
+}
+
+
+/*---------------------------------------------*/
+
+static void getAndMoveToFrontDecode ( void )
+{
+ UChar yy[256];
+ Int32 i, j, nextSym, limitLast;
+ Int32 EOB, groupNo, groupPos;
+
+ limitLast = 100000 * blockSize100k;
+ origPtr = bsGetIntVS ( 24 );
+
+ recvDecodingTables();
+ EOB = nInUse+1;
+ groupNo = -1;
+ groupPos = 0;
+
+ /*--
+ Setting up the unzftab entries here is not strictly
+ necessary, but it does save having to do it later
+ in a separate pass, and so saves a block's worth of
+ cache misses.
+ --*/
+ for (i = 0; i <= 255; i++) unzftab[i] = 0;
+
+ for (i = 0; i <= 255; i++) yy[i] = (UChar) i;
+
+ last = -1;
+
+ GET_MTF_VAL(nextSym);
+
+ while (True) {
+
+ if (nextSym == EOB) break;
+
+ if (nextSym == RUNA || nextSym == RUNB) {
+ UChar ch;
+ Int32 s = -1;
+ Int32 N = 1;
+ do {
+ if (nextSym == RUNA) s = s + (0+1) * N; else
+ if (nextSym == RUNB) s = s + (1+1) * N;
+ N = N * 2;
+ GET_MTF_VAL(nextSym);
+ }
+ while (nextSym == RUNA || nextSym == RUNB);
+
+ s++;
+ ch = seqToUnseq[yy[0]];
+ unzftab[ch] += s;
+
+ if (smallMode)
+ while (s > 0) {
+ last++;
+ ll16[last] = ch;
+ s--;
+ }
+ else
+ while (s > 0) {
+ last++;
+ ll8[last] = ch;
+ s--;
+ };
+
+ if (last >= limitLast) blockOverrun();
+ continue;
+
+ } else {
+
+ UChar tmp;
+ last++; if (last >= limitLast) blockOverrun();
+
+ tmp = yy[nextSym-1];
+ unzftab[seqToUnseq[tmp]]++;
+ if (smallMode)
+ ll16[last] = seqToUnseq[tmp]; else
+ ll8[last] = seqToUnseq[tmp];
+
+ /*--
+ This loop is hammered during decompression,
+ hence the unrolling.
+
+ for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1];
+ --*/
+
+ j = nextSym-1;
+ for (; j > 3; j -= 4) {
+ yy[j] = yy[j-1];
+ yy[j-1] = yy[j-2];
+ yy[j-2] = yy[j-3];
+ yy[j-3] = yy[j-4];
+ }
+ for (; j > 0; j--) yy[j] = yy[j-1];
+
+ yy[0] = tmp;
+ GET_MTF_VAL(nextSym);
+ continue;
+ }
+ }
+}
+
+
+/*---------------------------------------------------*/
+/*--- Stuff for randomising repetitive blocks ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+static Int32 rNums[512] = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+};
+
+
+#define RAND_DECLS \
+ Int32 rNToGo = 0; \
+ Int32 rTPos = 0; \
+
+#define RAND_MASK ((rNToGo == 1) ? 1 : 0)
+
+#define RAND_UPD_MASK \
+ if (rNToGo == 0) { \
+ rNToGo = rNums[rTPos]; \
+ rTPos++; if (rTPos == 512) rTPos = 0; \
+ } \
+ rNToGo--;
+
+
+
+/*---------------------------------------------------*/
+/*--- The Reversible Transformation (tm) ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+
+static INLINE Int32 indexIntoF ( Int32 indx, Int32 *cftab )
+{
+ Int32 nb, na, mid;
+ nb = 0;
+ na = 256;
+ do {
+ mid = (nb + na) >> 1;
+ if (indx >= cftab[mid]) nb = mid; else na = mid;
+ }
+ while (na - nb != 1);
+ return nb;
+}
+
+
+
+#define GET_SMALL(cccc) \
+ \
+ cccc = indexIntoF ( tPos, cftab ); \
+ tPos = GET_LL(tPos);
+
+
+
+static void undoReversibleTransformation_small ( void* dst )
+{
+ Int32 cftab[257], cftabAlso[257];
+ Int32 i, j, tmp, tPos;
+ UChar ch;
+
+ /*--
+ We assume here that the global array unzftab will
+ already be holding the frequency counts for
+ ll8[0 .. last].
+ --*/
+
+ /*-- Set up cftab to facilitate generation of indexIntoF --*/
+ cftab[0] = 0;
+ for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1];
+ for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1];
+
+ /*-- Make a copy of it, used in generation of T --*/
+ for (i = 0; i <= 256; i++) cftabAlso[i] = cftab[i];
+
+ /*-- compute the T vector --*/
+ for (i = 0; i <= last; i++) {
+ ch = (UChar)ll16[i];
+ SET_LL(i, cftabAlso[ch]);
+ cftabAlso[ch]++;
+ }
+
+ /*--
+ Compute T^(-1) by pointer reversal on T. This is rather
+ subtle, in that, if the original block was two or more
+ (in general, N) concatenated copies of the same thing,
+ the T vector will consist of N cycles, each of length
+ blocksize / N, and decoding will involve traversing one
+ of these cycles N times. Which particular cycle doesn't
+ matter -- they are all equivalent. The tricky part is to
+ make sure that the pointer reversal creates a correct
+ reversed cycle for us to traverse. So, the code below
+ simply reverses whatever cycle origPtr happens to fall into,
+ without regard to the cycle length. That gives one reversed
+ cycle, which for normal blocks, is the entire block-size long.
+ For repeated blocks, it will be interspersed with the other
+ N-1 non-reversed cycles. Providing that the F-subscripting
+ phase which follows starts at origPtr, all then works ok.
+ --*/
+ i = origPtr;
+ j = GET_LL(i);
+ do {
+ tmp = GET_LL(j);
+ SET_LL(j, i);
+ i = j;
+ j = tmp;
+ }
+ while (i != origPtr);
+
+ /*--
+ We recreate the original by subscripting F through T^(-1).
+ The run-length-decoder below requires characters incrementally,
+ so tPos is set to a starting value, and is updated by
+ the GET_SMALL macro.
+ --*/
+ tPos = origPtr;
+
+ /*-------------------------------------------------*/
+ /*--
+ This is pretty much a verbatim copy of the
+ run-length decoder present in the distribution
+ bzip-0.21; it has to be here to avoid creating
+ block[] as an intermediary structure. As in 0.21,
+ this code derives from some sent to me by
+ Christian von Roques.
+
+ It allows dst==NULL, so as to support the test (-t)
+ option without slowing down the fast decompression
+ code.
+ --*/
+ {
+ IntNative retVal;
+ Int32 i2, count, chPrev, ch2;
+ UInt32 localCrc;
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /*-- not a char and not EOF --*/
+ localCrc = getGlobalCRC();
+
+ {
+ RAND_DECLS;
+ while ( i2 <= last ) {
+ chPrev = ch2;
+ GET_SMALL(ch2);
+ if (blockRandomised) {
+ RAND_UPD_MASK;
+ ch2 ^= (UInt32)RAND_MASK;
+ }
+ i2++;
+
+ if (dst)
+ retVal = bz2_putc ( ch2, dst );
+
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+
+ if (ch2 != chPrev) {
+ count = 1;
+ } else {
+ count++;
+ if (count >= 4) {
+ Int32 j2;
+ UChar z;
+ GET_SMALL(z);
+ if (blockRandomised) {
+ RAND_UPD_MASK;
+ z ^= RAND_MASK;
+ }
+ for (j2 = 0; j2 < (Int32)z; j2++) {
+ if (dst) retVal = bz2_putc (ch2, dst);
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+ }
+ i2++;
+ count = 0;
+ }
+ }
+ }
+ }
+
+ setGlobalCRC ( localCrc );
+ }
+ /*-- end of the in-line run-length-decoder. --*/
+}
+#undef GET_SMALL
+
+
+/*---------------------------------------------*/
+
+#define GET_FAST(cccc) \
+ \
+ cccc = ll8[tPos]; \
+ tPos = tt[tPos];
+
+
+
+static void undoReversibleTransformation_fast ( void* dst )
+{
+ Int32 cftab[257];
+ Int32 i, tPos;
+ UChar ch;
+
+ /*--
+ We assume here that the global array unzftab will
+ already be holding the frequency counts for
+ ll8[0 .. last].
+ --*/
+
+ /*-- Set up cftab to facilitate generation of T^(-1) --*/
+ cftab[0] = 0;
+ for (i = 1; i <= 256; i++) cftab[i] = unzftab[i-1];
+ for (i = 1; i <= 256; i++) cftab[i] += cftab[i-1];
+
+ /*-- compute the T^(-1) vector --*/
+ for (i = 0; i <= last; i++) {
+ ch = (UChar)ll8[i];
+ tt[cftab[ch]] = i;
+ cftab[ch]++;
+ }
+
+ /*--
+ We recreate the original by subscripting L through T^(-1).
+ The run-length-decoder below requires characters incrementally,
+ so tPos is set to a starting value, and is updated by
+ the GET_FAST macro.
+ --*/
+ tPos = tt[origPtr];
+
+ /*-------------------------------------------------*/
+ /*--
+ This is pretty much a verbatim copy of the
+ run-length decoder present in the distribution
+ bzip-0.21; it has to be here to avoid creating
+ block[] as an intermediary structure. As in 0.21,
+ this code derives from some sent to me by
+ Christian von Roques.
+ --*/
+ {
+ IntNative retVal;
+ Int32 i2, count, chPrev, ch2;
+ UInt32 localCrc;
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /*-- not a char and not EOF --*/
+ localCrc = getGlobalCRC();
+
+ if (blockRandomised) {
+ RAND_DECLS;
+ while ( i2 <= last ) {
+ chPrev = ch2;
+ GET_FAST(ch2);
+ RAND_UPD_MASK;
+ ch2 ^= (UInt32)RAND_MASK;
+ i2++;
+
+ retVal = bz2_putc ( ch2, dst );
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+
+ if (ch2 != chPrev) {
+ count = 1;
+ } else {
+ count++;
+ if (count >= 4) {
+ Int32 j2;
+ UChar z;
+ GET_FAST(z);
+ RAND_UPD_MASK;
+ z ^= RAND_MASK;
+ for (j2 = 0; j2 < (Int32)z; j2++) {
+ retVal = bz2_putc (ch2, dst);
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+ }
+ i2++;
+ count = 0;
+ }
+ }
+ }
+
+ } else {
+
+ while ( i2 <= last ) {
+ chPrev = ch2;
+ GET_FAST(ch2);
+ i2++;
+
+ retVal = bz2_putc ( ch2, dst );
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+
+ if (ch2 != chPrev) {
+ count = 1;
+ } else {
+ count++;
+ if (count >= 4) {
+ Int32 j2;
+ UChar z;
+ GET_FAST(z);
+ for (j2 = 0; j2 < (Int32)z; j2++) {
+ retVal = bz2_putc (ch2, dst);
+ UPDATE_CRC ( localCrc, (UChar)ch2 );
+ }
+ i2++;
+ count = 0;
+ }
+ }
+ }
+
+ } /*-- if (blockRandomised) --*/
+
+ setGlobalCRC ( localCrc );
+ }
+ /*-- end of the in-line run-length-decoder. --*/
+}
+#undef GET_FAST
+
+
+
+/*---------------------------------------------------*/
+/*--- Processing of complete files and streams ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------*/
+
+static Bool uncompressStream ( void *zStream, void *stream )
+{
+ UChar magic1, magic2, magic3, magic4;
+ UChar magic5, magic6;
+ UInt32 storedBlockCRC, storedCombinedCRC;
+ UInt32 computedBlockCRC, computedCombinedCRC;
+ Int32 currBlockNo;
+ IntNative retVal;
+
+ SET_BINARY_MODE(stream);
+ SET_BINARY_MODE(zStream);
+
+ ERROR_IF_NOT_ZERO ( bz2_ferror(stream) );
+ ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) );
+
+ bsSetStream ( zStream, False );
+
+ /*--
+ A bad magic number is `recoverable from';
+ return with False so the caller skips the file.
+ --*/
+ magic1 = bsGetUChar ();
+ magic2 = bsGetUChar ();
+ magic3 = bsGetUChar ();
+ magic4 = bsGetUChar ();
+ if (magic1 != 'B' ||
+ magic2 != 'Z' ||
+ magic3 != 'h' ||
+ magic4 < '1' ||
+ magic4 > '9') {
+ bsFinishedWithStream();
+ retVal = bz2_fclose ( stream );
+ ERROR_IF_EOF ( retVal );
+ return False;
+ }
+
+ setDecompressStructureSizes ( magic4 - '0' );
+ computedCombinedCRC = 0;
+
+ if (verbosity >= 2) fprintf ( stderr, "\n " );
+ currBlockNo = 0;
+
+ while (True) {
+ magic1 = bsGetUChar ();
+ magic2 = bsGetUChar ();
+ magic3 = bsGetUChar ();
+ magic4 = bsGetUChar ();
+ magic5 = bsGetUChar ();
+ magic6 = bsGetUChar ();
+ if (magic1 == 0x17 && magic2 == 0x72 &&
+ magic3 == 0x45 && magic4 == 0x38 &&
+ magic5 == 0x50 && magic6 == 0x90) break;
+
+ if (magic1 != 0x31 || magic2 != 0x41 ||
+ magic3 != 0x59 || magic4 != 0x26 ||
+ magic5 != 0x53 || magic6 != 0x59) badBlockHeader();
+
+ storedBlockCRC = bsGetUInt32 ();
+
+ if (bsR(1) == 1)
+ blockRandomised = True; else
+ blockRandomised = False;
+
+ currBlockNo++;
+ if (verbosity >= 2)
+ fprintf ( stderr, "[%d: huff+mtf ", currBlockNo );
+ getAndMoveToFrontDecode ();
+ ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) );
+
+ initialiseCRC();
+ if (verbosity >= 2) fprintf ( stderr, "rt+rld" );
+ if (smallMode)
+ undoReversibleTransformation_small ( stream );
+ else
+ undoReversibleTransformation_fast ( stream );
+
+ ERROR_IF_NOT_ZERO ( bz2_ferror(stream) );
+
+ computedBlockCRC = getFinalCRC();
+ if (verbosity >= 3)
+ fprintf ( stderr, " {0x%x, 0x%x}", storedBlockCRC, computedBlockCRC );
+ if (verbosity >= 2) fprintf ( stderr, "] " );
+
+ /*-- A bad CRC is considered a fatal error. --*/
+ if (storedBlockCRC != computedBlockCRC)
+ crcError ( storedBlockCRC, computedBlockCRC );
+
+ computedCombinedCRC = (computedCombinedCRC << 1) | (computedCombinedCRC >> 31);
+ computedCombinedCRC ^= computedBlockCRC;
+ };
+
+ if (verbosity >= 2) fprintf ( stderr, "\n " );
+
+ storedCombinedCRC = bsGetUInt32 ();
+ if (verbosity >= 2)
+ fprintf ( stderr,
+ "combined CRCs: stored = 0x%x, computed = 0x%x\n ",
+ storedCombinedCRC, computedCombinedCRC );
+ if (storedCombinedCRC != computedCombinedCRC)
+ crcError ( storedCombinedCRC, computedCombinedCRC );
+
+
+ bsFinishedWithStream ();
+ ERROR_IF_NOT_ZERO ( bz2_ferror(zStream) );
+ retVal = bz2_fclose ( zStream );
+ ERROR_IF_EOF ( retVal );
+
+ ERROR_IF_NOT_ZERO ( bz2_ferror(stream) );
+ retVal = bz2_fflush ( stream );
+ ERROR_IF_NOT_ZERO ( retVal );
+ return True;
+}
+
+
+#if 0
+
+#endif
+/*---------------------------------------------------*/
+/*--- Error [non-] handling grunge ---*/
+/*---------------------------------------------------*/
+
+
+
+static void
+myFree (void **p)
+{
+ free (*p);
+ *p = NULL;
+}
+
+/*---------------------------------------------*/
+/* Ugg... Orignal code doesn't free dynamic allocated memories. */
+
+static void cleanUpAndFail ( Int32 ec )
+{
+ myFree ((void **) &ll16);
+ myFree ((void **) &ll4);
+ myFree ((void **) &ll8);
+ myFree ((void **) &tt);
+
+ (*unzip_error) (NULL);
+}
+
+
+/*---------------------------------------------*/
+
+static void panic ( Char* s )
+{
+ cleanUpAndFail( 3 );
+}
+
+
+
+/*---------------------------------------------*/
+
+static void crcError ( UInt32 crcStored, UInt32 crcComputed )
+{
+ cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+
+static void compressedStreamEOF ( void )
+{
+ cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+
+static void ioError ( )
+{
+ cleanUpAndFail( 1 );
+}
+
+
+/*---------------------------------------------*/
+
+static void blockOverrun ()
+{
+ cleanUpAndFail( 2 );
+}
+
+
+/*---------------------------------------------*/
+
+static void badBlockHeader ()
+{
+ cleanUpAndFail( 2 );
+}
+
+
+
+/*---------------------------------------------*/
+static void uncompressOutOfMemory ( Int32 draw, Int32 blockSize )
+{
+ cleanUpAndFail(1);
+}
+
+
+
+/*-----------------------------------------------------------*/
+/*--- end bzip2.c ---*/
+/*-----------------------------------------------------------*/
+
+void
+do_bunzip2 (void)
+{
+ Bool ret;
+
+ /*-- Initialise --*/
+ ll4 = NULL;
+ ll16 = NULL;
+ ll8 = NULL;
+ tt = NULL;
+#ifdef SMALL_BZIP2
+ smallMode = True;
+#else
+ smallMode = False;
+#endif
+ verbosity = 0;
+ blockSize100k = 0;
+ bsStream = NULL;
+
+ outcnt = 0;
+ inptr = 0;
+ insize = 0;
+
+ ret = uncompressStream ((void *)1, (void *)2); /* Arguments ignored. */
+ if (ret != True)
+ cleanUpAndFail(1);
+}
diff --git a/exec/elfcore.c b/exec/elfcore.c
index 4388a135..f953cc76 100644
--- a/exec/elfcore.c
+++ b/exec/elfcore.c
@@ -1,100 +1,566 @@
+/* Write ELF core dump files for GNU Hurd.
+ Copyright (C) 2002, 2004, 2008 Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <elf.h>
+#include <link.h>
+#include <string.h>
+#include <argz.h>
+#include <sys/mman.h>
+#include <sys/utsname.h>
+#include <sys/procfs.h>
+#include <stddef.h>
+
+#define ELF_CLASS PASTE (ELFCLASS, __ELF_NATIVE_CLASS)
+#define PASTE(a, b) PASTE_1 (a, b)
+#define PASTE_1(a, b) a##b
+
+#include <endian.h>
+#if BYTE_ORDER == BIG_ENDIAN
+#define ELF_DATA ELFDATA2MSB
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define ELF_DATA ELFDATA2LSB
+#endif
+
+#include <mach/thread_status.h>
+#include <assert.h>
+
+#ifdef i386_THREAD_STATE
+# define ELF_MACHINE EM_386
+
+/* The gregset_t format (compatible with Linux/x86) almost fits
+ the Mach i386_thread_state. */
+static inline void
+fetch_thread_regset (thread_t thread, prgregset_t *gregs)
+{
+ union
+ {
+ struct i386_thread_state state;
+ prgregset_t gregs;
+ } *u = (void *) gregs;
+ mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+ assert (sizeof (struct i386_thread_state) < sizeof (prgregset_t));
+ assert (offsetof (struct i386_thread_state, gs) == REG_GS * 4);
+ assert (offsetof (struct i386_thread_state, eax) == REG_EAX * 4);
+
+ (void) thread_get_state (thread, i386_THREAD_STATE,
+ (thread_state_t) &u->state, &count);
+
+ u->gregs[REG_EIP] = u->state.eip;
+ u->gregs[REG_CS] = u->state.cs;
+ u->gregs[REG_EFL] = u->state.efl;
+ u->gregs[REG_UESP] = u->state.uesp;
+ u->gregs[REG_SS] = u->state.ss;
+
+ /* These are the extra words that don't exist in prgregset_t. */
+ u->gregs[REG_ERR] = u->gregs[REG_TRAPNO] = 0;
+}
+
+static inline void
+fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs)
+{
+ struct i386_float_state st;
+ mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+ error_t err = thread_get_state (thread, i386_FLOAT_STATE,
+ (thread_state_t) &st, &count);
+ if (err == 0 && st.initialized)
+ {
+ assert (sizeof *fpregs >= sizeof st.hw_state);
+ memcpy (fpregs, st.hw_state, sizeof st.hw_state);
+ }
+}
+
+#elif defined ALPHA_THREAD_STATE
+# define ELF_MACHINE EM_ALPHA
+
+/* The gregset_t format (compatible with Linux/Alpha) almost fits
+ the Mach alpha_thread_state. */
+static inline void
+fetch_thread_regset (thread_t thread, prgregset_t *gregs)
{
- processor_set_name_t pset;
- host_t host;
- processor_set_basic_info_data_t pinfo;
+ mach_msg_type_number_t count = ALPHA_THREAD_STATE_COUNT;
+ assert (sizeof (struct alpha_thread_state) <= sizeof (prgregset_t));
+ (void) thread_get_state (thread, ALPHA_THREAD_STATE,
+ (thread_state_t) gregs, &count);
+ /* XXX
+ gregs[32] is process-status word: Mach doesn't return it!
+ It's already zero'd.
+ */
+}
+/* The FPU state matches exactly. */
+static inline void
+fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs)
+{
+ mach_msg_type_number_t count = ALPHA_FLOAT_STATE_COUNT;
+ assert (sizeof (struct alpha_float_state) == sizeof *fpregs);
+ (void) thread_get_state (thread, ALPHA_FLOAT_STATE,
+ (thread_state_t) fpregs, &count);
+}
+
+#else
+# warning "do not understand this machine flavor, no registers in dumps"
+# define ELF_MACHINE EM_NONE
+#endif
+
+
+#define TIME_VALUE_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->seconds; \
+ (ts)->tv_nsec = (tv)->microseconds * 1000; \
+}
+
+#define PAGES_TO_KB(x) ((x) * (vm_page_size / 1024))
+#define ENCODE_PCT(f) ((uint16_t) ((f) * 32768.0))
+
+extern process_t procserver; /* crash.c */
+
+error_t
+dump_core (task_t task, file_t file, off_t corelimit,
+ int signo, long int sigcode, int sigerror)
+{
+ static float host_memory_size = -1.0;
+ error_t err;
+ ElfW(Phdr) *phdrs, *ph;
+ ElfW(Ehdr) hdr = /* ELF header for the core file. */
+ {
+ e_ident:
+ {
+ [EI_MAG0] = ELFMAG0,
+ [EI_MAG1] = ELFMAG1,
+ [EI_MAG2] = ELFMAG2,
+ [EI_MAG3] = ELFMAG3,
+ [EI_CLASS] = ELF_CLASS,
+ [EI_DATA] = ELF_DATA,
+ [EI_VERSION] = EV_CURRENT,
+ [EI_OSABI] = ELFOSABI_SYSV,
+ [EI_ABIVERSION] = 0
+ },
+ e_type: ET_CORE,
+ e_version: EV_CURRENT,
+ e_machine: ELF_MACHINE,
+ e_ehsize: sizeof hdr,
+ e_phentsize: sizeof phdrs[0],
+ e_phoff: sizeof hdr, /* Fill in e_phnum later. */
+ };
+ off_t offset;
+ size_t wrote;
+
+ pid_t pid;
thread_t *threads;
- size_t nthreads;
-
- vm_address_t addr;
- vm_size_t size;
- vm_prot_t prot, maxprot;
- vm_inherit_t inherit;
- boolean_t shared;
- memory_object_name_t objname;
- vm_offset_t offset;
-
- /* Figure out what flavor of machine the task is on. */
- if (err = task_get_assignment (task, &pset))
- goto lose;
- err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host,
- &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT);
- mach_port_deallocate (mach_task_self (), pset);
- if (err)
- goto lose;
- err = bfd_mach_host_arch_mach (host, &arch, &machine, &e_machine);
- mach_port_deallocate (mach_task_self (), host);
+ size_t nthreads, i;
+ off_t notestart;
+
+ /* Helper macros for writing notes. */
+#define DEFINE_NOTE(typename) struct { struct note_header hdr; typename data; }
+#define WRITE_NOTE(type, var) ({ \
+ (var).hdr = NOTE_HEADER ((type), sizeof (var).data); \
+ write_note (&(var).hdr); \
+})
+ struct note_header
+ {
+ ElfW(Nhdr) note;
+ char name[(sizeof "CORE" + 3) &~ 3];
+ } __attribute__ ((packed));
+#define NOTE_HEADER(type, size) \
+ ((struct note_header) { { sizeof "CORE", (size), (type) }, "CORE" })
+ inline error_t write_note (struct note_header *hdr)
+ {
+ error_t err = 0;
+ char *data = (char *) hdr;
+ size_t size = sizeof *hdr + hdr->note.n_descsz;
+ if (corelimit >= 0 && offset + size > corelimit)
+ size = corelimit - offset;
+ while (size > 0)
+ {
+ err = io_write (file, data, size, offset, &wrote);
+ if (err)
+ return err;
+ if (wrote > size)
+ return EGRATUITOUS;
+ data += wrote;
+ size -= wrote;
+ }
+ offset = (offset + wrote + 3) &~ 3; /* Pad it to word alignment. */
+ return 0;
+ }
+
+ struct vm_region_list
+ {
+ struct vm_region_list *next;
+ vm_prot_t protection;
+ vm_address_t start;
+ vm_size_t length;
+ };
+ struct vm_region_list *regions = NULL, **tailp = &regions, *r;
+ unsigned int nregions = 0;
+
+ if (corelimit >= 0 && corelimit < sizeof hdr)
+ return EFBIG;
+
+ {
+ /* Examine the task and record the locations of contiguous memory
+ segments that we will dump into the core file. */
+
+ vm_address_t region_address, last_region_address, last_region_end;
+ vm_prot_t last_protection;
+#define RECORD_LAST_REGION do { \
+ if (last_region_end > last_region_address \
+ && last_protection != VM_PROT_NONE) \
+ record_last_region (alloca (sizeof (struct vm_region_list))); } while (0)
+ inline void record_last_region (struct vm_region_list *region)
+ {
+ *tailp = region;
+ tailp = &region->next;
+ region->next = NULL;
+ region->start = last_region_address;
+ region->length = last_region_end - last_region_address;
+ region->protection = last_protection;
+ ++nregions;
+ }
+
+ region_address = last_region_address = last_region_end = VM_MIN_ADDRESS;
+ last_protection = VM_PROT_NONE;
+ while (region_address < VM_MAX_ADDRESS)
+ {
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ boolean_t shared;
+ mach_port_t object_name;
+ vm_offset_t offset;
+ vm_size_t region_length = VM_MAX_ADDRESS - region_address;
+
+ err = vm_region (task,
+ &region_address,
+ &region_length,
+ &protection,
+ &max_protection,
+ &inheritance,
+ &shared,
+ &object_name,
+ &offset);
+ if (err == KERN_NO_SPACE)
+ break;
+ if (err != KERN_SUCCESS)
+ return err;
+
+ if (protection == last_protection && region_address == last_region_end)
+ /* This region is contiguous with and indistinguishable from
+ the previous one, so we just extend that one. */
+ last_region_end = region_address += region_length;
+ else
+ {
+ /* This region is distinct from the last one we saw,
+ so record that previous one. */
+ RECORD_LAST_REGION;
+ last_region_address = region_address;
+ last_region_end = region_address += region_length;
+ last_protection = protection;
+ }
+ }
+ /* Record the final region. */
+ RECORD_LAST_REGION;
+ }
+
+ /* Now we start laying out the file. */
+ offset = sizeof hdr + ((nregions + 1) * sizeof *phdrs);
+
+ /* Final check for tiny core limit. From now on, we will simply truncate
+ the file at CORELIMIT but not change the contents of what we write. */
+ if (corelimit >= 0 && corelimit < offset)
+ return EFBIG;
+
+ /* Now we can complete the file header and write it. */
+ hdr.e_phnum = nregions + 1;
+ err = io_write (file, (char *) &hdr, sizeof hdr, 0, &wrote);
if (err)
- goto lose;
+ return err;
+ if (wrote < sizeof hdr)
+ return EGRATUITOUS; /* XXX */
+
+ /* Now we can write the various notes. */
+ notestart = offset;
- if (err = task_threads (task, &threads, &nthreads))
- goto lose;
+ /* First a dull note containing the results of `uname', a la Solaris. */
+ {
+ DEFINE_NOTE (struct utsname) note;
+ if (uname (&note.data) == 0) /* XXX Use proc_uname on task's proc port? */
+ err = WRITE_NOTE (NT_UTSNAME, note);
+ }
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ return err;
- /* Create a BFD section to describe each contiguous chunk
- of the task's address space with the same stats. */
- sec = NULL;
- addr = 0;
- while (!vm_region (task, &addr, &size, &prot, &maxprot,
- &inherit, &shared, &objname, &offset))
+ err = proc_task2pid (procserver, task, &pid);
+ if (err)
+ return err;
+
+ /* Make sure we have the total RAM size of the host.
+ We only do this once, assuming that it won't change.
+ XXX this could use the task's host-self port instead. */
+ if (host_memory_size <= 0.0)
{
- mach_port_deallocate (mach_task_self (), objname);
+ host_basic_info_data_t hostinfo;
+ mach_msg_type_number_t size = sizeof hostinfo;
+ error_t err = host_info (mach_host_self (), HOST_BASIC_INFO,
+ (host_info_t) &hostinfo, &size);
+ if (err == 0)
+ host_memory_size = hostinfo.memory_size;
+ }
+
+ /* The psinfo_t note contains some process-global info we should get from
+ the proc server, but no thread-specific info like register state. */
+ {
+ DEFINE_NOTE (psinfo_t) psinfo;
+ DEFINE_NOTE (pstatus_t) pstatus;
+ int flags = PI_FETCH_TASKINFO | PI_FETCH_THREADS | PI_FETCH_THREAD_BASIC;
+ char *waits = 0;
+ mach_msg_type_number_t num_waits = 0;
+ char pibuf[offsetof (struct procinfo, threadinfos[2])];
+ struct procinfo *pi = (void *) &pibuf;
+ mach_msg_type_number_t pi_size = sizeof pibuf;
+
+ memset (&pstatus.data, 0, sizeof pstatus.data);
+ memset (&psinfo.data, 0, sizeof psinfo.data);
+ pstatus.data.pr_pid = psinfo.data.pr_pid = pid;
+
+ err = proc_getprocinfo (procserver, pid, &flags,
+ (procinfo_t *) &pi, &pi_size,
+ &waits, &num_waits);
+ if (err == 0)
+ {
+ if (num_waits != 0)
+ munmap (waits, num_waits);
+
+ pstatus.data.pr_flags = psinfo.data.pr_flag = pi->state;
+ pstatus.data.pr_nlwp = psinfo.data.pr_nlwp = pi->nthreads;
+ pstatus.data.pr_ppid = psinfo.data.pr_ppid = pi->ppid;
+ pstatus.data.pr_pgid = psinfo.data.pr_pgid = pi->pgrp;
+ pstatus.data.pr_sid = psinfo.data.pr_sid = pi->session;
+
+ psinfo.data.pr_euid = pi->owner;
+ /* XXX struct procinfo should have these */
+ psinfo.data.pr_egid = psinfo.data.pr_gid = psinfo.data.pr_uid = -1;
+
+ psinfo.data.pr_size = PAGES_TO_KB (pi->taskinfo.virtual_size);
+ psinfo.data.pr_rssize = PAGES_TO_KB (pi->taskinfo.resident_size);
+
+ {
+ /* Sum all the threads' cpu_usage fields. */
+ integer_t cpu_usage = 0;
+ for (i = 0; i < pi->nthreads; ++i)
+ cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage;
+ psinfo.data.pr_pctcpu = ENCODE_PCT ((float) cpu_usage
+ / (float) TH_USAGE_SCALE);
+ }
+ if (host_memory_size > 0.0)
+ psinfo.data.pr_pctmem
+ = ENCODE_PCT
+ ((float) pi->taskinfo.resident_size / host_memory_size);
+
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.creation_time,
+ &psinfo.data.pr_start);
- if (prot != VM_PROT_NONE)
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time,
+ &pstatus.data.pr_utime);
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.system_time,
+ &pstatus.data.pr_stime);
+ /* Sum the user and system time for pr_time. */
+ pi->taskinfo.user_time.seconds += pi->taskinfo.system_time.seconds;
+ pi->taskinfo.user_time.microseconds += pi->taskinfo.system_time.microseconds;
+ if (pi->taskinfo.user_time.microseconds >= 1000000)
+ {
+ ++pi->taskinfo.user_time.seconds;
+ pi->taskinfo.user_time.microseconds -= 1000000;
+ }
+ TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time, &psinfo.data.pr_time);
+ /* XXX struct procinfo should have dead child info for pr_c[us]?time */
+
+ psinfo.data.pr_wstat = pi->exitstatus;
+
+ if ((void *) pi != &pibuf)
+ munmap (pi, pi_size);
+ }
+ if (err == 0)
+ {
+ /* We have to nab the process's own proc port to get the
+ proc server to tell us its registered arg locations. */
+ process_t proc;
+ err = proc_task2proc (procserver, task, &proc);
+ if (err == 0)
+ {
+ err = proc_get_arg_locations (proc,
+ &psinfo.data.pr_argv,
+ &psinfo.data.pr_envp);
+ mach_port_deallocate (mach_task_self (), proc);
+ }
{
- flagword flags = SEC_NO_FLAGS;
-
- if (!(prot & VM_PROT_WRITE))
- flags |= SEC_READONLY;
- if (!(prot & VM_PROT_EXECUTE))
- flags |= SEC_DATA;
-
- if (sec != NULL &&
- (vm_address_t) (bfd_section_vma (bfd, sec) +
- bfd_section_size (bfd, sec)) == addr &&
- flags == (bfd_get_section_flags (bfd, sec) &
- (SEC_READONLY|SEC_DATA)))
- /* Coalesce with the previous section. */
- bfd_set_section_size (bfd, sec,
- bfd_section_size (bfd, sec) + size);
- else
+ /* Now fetch the arguments. We could do this directly from the
+ task given the locations we now have. But we are lazy and have
+ the proc server do it for us. */
+ char *data = psinfo.data.pr_psargs;
+ size_t datalen = sizeof psinfo.data.pr_psargs;
+ err = proc_getprocargs (procserver, pid, &data, &datalen);
+ if (err == 0)
{
- /* Make a new section (which might grow by
- the next region being coalesced onto it). */
- char *name = bfd_intuit_section_name (addr, size, &flags);
- if (name == NULL)
+ psinfo.data.pr_argc = argz_count (data, datalen);
+ argz_stringify (data, datalen, ' ');
+ if (data != psinfo.data.pr_psargs)
{
- /* No guess from BFD. */
- if (asprintf (&name, "[%p,%p) %c%c%c",
- (void *) addr, (void *) (addr + size),
- (prot & VM_PROT_READ) ? 'r' : '-',
- (prot & VM_PROT_WRITE) ? 'w' : '-',
- (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1)
- goto lose;
+ memcpy (psinfo.data.pr_psargs, data,
+ sizeof psinfo.data.pr_psargs);
+ munmap (data, datalen);
}
- sec = bfd_make_section (name);
- bfd_set_section_flags (bfd, sec, flags);
- bfd_set_section_vma (bfd, sec, addr);
- bfd_set_section_size (bfd, sec, size);
}
}
+ err = WRITE_NOTE (NT_PSINFO, psinfo);
+ }
+
+ err = WRITE_NOTE (NT_PSTATUS, pstatus) ?: err;
+ }
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ return err;
+
+ /* Now examine all the threads in the task.
+ For each thread we produce one or more notes. */
+ err = task_threads (task, &threads, &nthreads);
+ if (err)
+ return err;
+ for (i = 0; i < nthreads; ++i)
+ {
+ DEFINE_NOTE (lwpstatus_t) note;
+ memset (&note.data, 0, sizeof note.data);
+ note.data.pr_lwpid = i;
+
+ /* We have to write the death signal into every thread's record, even
+ though only one thread really took the signal. This is both because
+ we don't know which thread it was, and because GDB blindly uses the
+ value from each record to clobber the last (even if it's zero). */
+ note.data.pr_cursig = signo;
+ note.data.pr_info.si_signo = signo;
+ note.data.pr_info.si_code = sigcode;
+ note.data.pr_info.si_errno = sigerror;
+
+ fetch_thread_regset (threads[i], &note.data.pr_reg);
+ fetch_thread_fpregset (threads[i], &note.data.pr_fpreg);
+
+ err = WRITE_NOTE (NT_LWPSTATUS, note);
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ break;
+
+ mach_port_deallocate (mach_task_self (), threads[i]);
}
+ /* If we broke out of the loop early, deallocate remaining thread ports. */
+ while (i < nthreads)
+ mach_port_deallocate (mach_task_self (), threads[i++]);
+ munmap (threads, nthreads * sizeof *threads);
+ if (err || (corelimit >= 0 && corelimit <= offset))
+ return err;
- /* Write all the sections' data. */
- for (sec = bfd->sections; sec != NULL; sec = sec->next)
+ /* Make an array of program headers and fill them in.
+ The first one describes the note segment. */
+ ph = phdrs = alloca ((nregions + 1) * sizeof *phdrs);
+
+ memset (ph, 0, sizeof *ph);
+ ph->p_type = PT_NOTE;
+ ph->p_offset = notestart;
+ ph->p_filesz = offset - notestart;
+ ++ph;
+
+ /* Now make ELF program headers for each of the recorded memory regions.
+ Consistent with the Linux kernel, we create PT_LOAD headers with
+ p_filesz = 0 for the read-only segments that we are not dumping
+ into the file. */
+ for (r = regions; r != NULL; r = r->next)
{
- void *data;
- err = vm_read (task, bfd_section_vma (bfd, sec),
- bfd_section_size (bfd, sec), &data);
- if (err)
- /* XXX What to do?
- 1. lose
- 2. remove this section
- 3. mark this section as having ungettable contents (how?)
- */
- goto lose;
- err = bfd_set_section_contents (bfd, sec, data, 0,
- bfd_section_size (bfd, sec));
- vm_deallocate (mach_task_self (), data, bfd_section_size (bfd, sec));
- if (err)
- goto bfdlose;
+ memset (ph, 0, sizeof *ph);
+ ph->p_type = PT_LOAD;
+ ph->p_align = vm_page_size;
+ ph->p_flags = (((r->protection & VM_PROT_READ) ? PF_R : 0)
+ | ((r->protection & VM_PROT_WRITE) ? PF_W : 0)
+ | ((r->protection & VM_PROT_EXECUTE) ? PF_X : 0));
+ ph->p_vaddr = r->start;
+ ph->p_memsz = r->length;
+ ph->p_filesz = (r->protection & VM_PROT_WRITE) ? ph->p_memsz : 0;
+ ph->p_offset = round_page (offset);
+ offset += ph->p_filesz;
+ ++ph;
}
+
+ /* Now write the memory segment data. */
+ for (ph = &phdrs[1]; ph < &phdrs[nregions + 1]; ++ph)
+ if (ph->p_filesz > 0)
+ {
+ vm_address_t va = ph->p_vaddr;
+ vm_size_t sz = ph->p_memsz;
+ off_t ofs = ph->p_offset;
+ int wrote_any = 0;
+ do
+ {
+ pointer_t copied;
+ size_t copy_count;
+ err = vm_read (task, va, sz, &copied, &copy_count);
+ if (err == 0)
+ {
+ char *data = (void *) copied;
+ size_t left = copy_count, wrote;
+
+ va += copy_count;
+ sz -= copy_count;
+
+ do
+ {
+ if (corelimit >= 0 && ofs + left > corelimit)
+ left = corelimit - ofs;
+ err = io_write (file, data, left, ofs, &wrote);
+ if (err)
+ break;
+ ofs += wrote;
+ data += wrote;
+ left -= wrote;
+ if (ofs >= corelimit)
+ break;
+ } while (left > 0);
+
+ munmap ((void *) copied, copy_count);
+
+ if (left < copy_count)
+ wrote_any = 1;
+ }
+ else
+ {
+ /* Leave a hole in the file for pages we can't read. */
+ va += vm_page_size;
+ sz -= vm_page_size;
+ ofs += vm_page_size;
+ }
+ } while (sz > 0 && (corelimit < 0 || ofs < corelimit));
+
+ if (! wrote_any)
+ /* If we failed to write any contents at all,
+ don't claim the big hole as the contents. */
+ ph->p_filesz = 0;
+ }
+
+ /* Finally, we go back and write the program headers. */
+ err = io_write (file, (char *) phdrs, (nregions + 1) * sizeof phdrs[0],
+ sizeof hdr, &wrote);
+
+ return err;
+}
diff --git a/exec/exec.c b/exec/exec.c
index a9de454a..4c2fcec1 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -1,5 +1,6 @@
/* GNU Hurd standard exec server.
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,98,99,2000,01,02,04
+ Free Software Foundation, Inc.
Written by Roland McGrath.
Can exec ELF format directly.
@@ -10,6 +11,9 @@
Can exec any executable format the BFD library understands
to be for this flavor of machine.
#endif
+ #ifdef BZIP2
+ Can bunzip2 executables into core on the fly.
+ #endif
This file is part of the GNU Hurd.
@@ -32,9 +36,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
#include <hurd.h>
#include <hurd/exec.h>
-#include <hurd/shared.h>
#include <sys/stat.h>
+#include <sys/param.h>
#include <unistd.h>
+#include <stdbool.h>
mach_port_t procserver; /* Our proc port. */
@@ -70,6 +75,10 @@ b2he (error_t deflt)
static void check_gzip (struct execdata *);
#endif
+#ifdef BZIP2
+static void check_bzip2 (struct execdata *);
+#endif
+
#ifdef BFD
/* Check a section, updating the `locations' vector [BFD]. */
@@ -132,7 +141,7 @@ load_section (void *section, struct execdata *u)
#ifdef BFD
asection *const sec = section;
#endif
- const Elf32_Phdr *const ph = section;
+ const ElfW(Phdr) *const ph = section;
if (u->error)
return;
@@ -173,6 +182,7 @@ load_section (void *section, struct execdata *u)
if (! anywhere)
addr += u->info.elf.loadbase;
else
+#if 0
switch (elf_machine)
{
case EM_386:
@@ -187,6 +197,9 @@ load_section (void *section, struct execdata *u)
default:
break;
}
+#endif
+ if (anywhere && addr < vm_page_size)
+ addr = vm_page_size;
}
if (memsz == 0)
@@ -214,16 +227,19 @@ load_section (void *section, struct execdata *u)
if (! u->error && off != 0)
{
vm_address_t page = 0;
- u->error = vm_allocate (mach_task_self (),
- &page, vm_page_size, 1);
+ page = (vm_address_t) mmap (0, vm_page_size,
+ PROT_READ|PROT_WRITE, MAP_ANON,
+ 0, 0);
+ u->error = (page == -1) ? errno : 0;
if (! u->error)
{
- memcpy ((void *) page,
+ u->error = hurd_safe_copyin ((void *) page, /* XXX/fault */
(void *) (contents + (size - off)),
off);
- u->error = vm_write (u->task, mapstart + (size - off),
- page, vm_page_size);
- vm_deallocate (mach_task_self (), page, vm_page_size);
+ if (! u->error)
+ u->error = vm_write (u->task, mapstart + (size - off),
+ page, vm_page_size);
+ munmap ((caddr_t) page, vm_page_size);
}
}
/* Reset the current protections to the desired state. */
@@ -256,21 +272,10 @@ load_section (void *section, struct execdata *u)
{
/* Cannot map the data. Read it into a buffer and vm_write
it into the task. */
- void *buf;
const vm_size_t size = filesz - (mapstart - addr);
- u->error = vm_allocate (mach_task_self (),
- (vm_address_t *) &buf, size, 1);
- if (! u->error)
- {
- if (fseek (&u->stream,
- filepos + (mapstart - addr), SEEK_SET) ||
- fread (buf, size, 1, &u->stream) != 1)
- u->error = errno;
- else
- write_to_task (mapstart, size, vm_prot,
- (vm_address_t) buf);
- vm_deallocate (mach_task_self (), (vm_address_t) buf, size);
- }
+ void *buf = map (u, filepos + (mapstart - addr), size);
+ if (buf)
+ write_to_task (mapstart, size, vm_prot, (vm_address_t) buf);
}
if (u->error)
return;
@@ -308,8 +313,12 @@ load_section (void *section, struct execdata *u)
&overlap_page, vm_page_size, 0);
size = vm_page_size;
if (!u->error)
- u->error = vm_allocate (mach_task_self (),
- &ourpage, vm_page_size, 1);
+ {
+ ourpage = (vm_address_t) mmap (0, vm_page_size,
+ PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ u->error = (ourpage == -1) ? errno : 0;
+ }
}
if (u->error)
{
@@ -325,14 +334,17 @@ load_section (void *section, struct execdata *u)
readsize = filesz;
if (SECTION_IN_MEMORY_P)
- bcopy (SECTION_CONTENTS, readaddr, readsize);
+ memcpy (readaddr, SECTION_CONTENTS, readsize);
else
- if (fseek (&u->stream, filepos, SEEK_SET) ||
- fread (readaddr, readsize, 1, &u->stream) != 1)
- {
- u->error = errno;
+ {
+ const void *contents = map (u, filepos, readsize);
+ if (!contents)
goto maplose;
- }
+ u->error = hurd_safe_copyin (readaddr, contents,
+ readsize); /* XXX/fault */
+ if (u->error)
+ goto maplose;
+ }
u->error = vm_write (u->task, overlap_page, ourpage, size);
if (u->error == KERN_PROTECTION_FAILURE)
{
@@ -349,7 +361,7 @@ load_section (void *section, struct execdata *u)
u->error = vm_protect (u->task, overlap_page, size,
0, vm_prot);
}
- vm_deallocate (mach_task_self (), ourpage, size);
+ munmap ((caddr_t) ourpage, size);
if (u->error)
goto maplose;
}
@@ -412,15 +424,122 @@ load_section (void *section, struct execdata *u)
u->error = vm_write (u->task, overlap_page, ourpage, size);
if (! u->error && !(vm_prot & VM_PROT_WRITE))
u->error = vm_protect (u->task, overlap_page, size, 0, vm_prot);
- vm_deallocate (mach_task_self (), ourpage, size);
+ munmap ((caddr_t) ourpage, size);
}
}
}
-/* Make sure our mapping window (or read buffer) covers
- LEN bytes of the file starting at POSN. */
+/* XXX all accesses of the mapped data need to use fault handling
+ to abort the RPC when mapped file data generates bad page faults.
+ I've marked some accesses with XXX/fault comments.
+ --roland */
-static void *
+void *
+map (struct execdata *e, off_t posn, size_t len)
+{
+ const size_t size = e->file_size;
+ size_t offset;
+
+ if ((map_filepos (e) & ~(map_vsize (e) - 1)) == (posn & ~(map_vsize (e) - 1))
+ && posn + len - map_filepos (e) <= map_fsize (e))
+ /* The current mapping window covers it. */
+ offset = posn & (map_vsize (e) - 1);
+ else if (posn + len > size)
+ /* The requested data wouldn't fit in the file. */
+ return NULL;
+ else if (e->file_data != NULL) {
+ return e->file_data + posn;
+ } else if (e->filemap == MACH_PORT_NULL)
+ {
+ /* No mapping for the file. Read the data by RPC. */
+ char *buffer = map_buffer (e);
+ mach_msg_type_number_t nread = map_vsize (e);
+
+ assert (e->file_data == NULL); /* Must be first or second case. */
+
+ /* Read as much as we can get into the buffer right now. */
+ e->error = io_read (e->file, &buffer, &nread, posn, round_page (len));
+ if (e->error)
+ return NULL;
+ if (buffer != map_buffer (e))
+ {
+ /* The data was returned out of line. Discard the old buffer. */
+ if (map_vsize (e) != 0)
+ munmap (map_buffer (e), map_vsize (e));
+ map_buffer (e) = buffer;
+ map_vsize (e) = round_page (nread);
+ }
+
+ map_filepos (e) = posn;
+ map_set_fsize (e, nread);
+ offset = 0;
+ }
+ else
+ {
+ /* Deallocate the old mapping area. */
+ if (map_buffer (e) != NULL)
+ munmap (map_buffer (e), map_vsize (e));
+ map_buffer (e) = NULL;
+
+ /* Make sure our mapping is page-aligned in the file. */
+ offset = posn & (vm_page_size - 1);
+ map_filepos (e) = trunc_page (posn);
+ map_vsize (e) = round_page (posn + len) - map_filepos (e);
+
+ /* Map the data from the file. */
+ if (vm_map (mach_task_self (),
+ (vm_address_t *) &map_buffer (e), map_vsize (e), 0, 1,
+ e->filemap, map_filepos (e), 1, VM_PROT_READ, VM_PROT_READ,
+ VM_INHERIT_NONE))
+ {
+ e->error = EIO;
+ return NULL;
+ }
+
+ if (e->cntl)
+ e->cntl->accessed = 1;
+
+ map_set_fsize (e, MIN (map_vsize (e), size - map_filepos (e)));
+ }
+
+ return map_buffer (e) + offset;
+}
+
+
+/* Initialize E's stdio stream. */
+static void prepare_stream (struct execdata *e);
+
+/* Point the stream at the buffer of file data in E->file_data. */
+static void prepare_in_memory (struct execdata *e);
+
+
+#ifndef EXECDATA_STREAM
+
+/* We don't have a stdio stream, but we have a mapping window
+ we need to initialize. */
+static void
+prepare_stream (struct execdata *e)
+{
+ e->map_buffer = NULL;
+ e->map_vsize = e->map_fsize = 0;
+ e->map_filepos = 0;
+}
+
+static void prepare_in_memory (struct execdata *e)
+{
+ prepare_stream(e);
+}
+
+#else
+
+#ifdef _STDIO_USES_IOSTREAM
+
+# error implement me for libio!
+
+#else /* old GNU stdio */
+
+#if 0
+void *
map (struct execdata *e, off_t posn, size_t len)
{
FILE *f = &e->stream;
@@ -431,6 +550,13 @@ map (struct execdata *e, off_t posn, size_t len)
f->__buffer + (posn + len - f->__offset) < f->__get_limit)
/* The current mapping window covers it. */
offset = posn & (f->__bufsize - 1);
+ else if (e->file_data != NULL)
+ {
+ /* The current "mapping window" is in fact the whole file contents.
+ So if it's not in there, it's not in there. */
+ f->__eof = 1;
+ return NULL;
+ }
else if (e->filemap == MACH_PORT_NULL)
{
/* No mapping for the file. Read the data by RPC. */
@@ -448,8 +574,7 @@ map (struct execdata *e, off_t posn, size_t len)
{
/* The data was returned out of line. Discard the old buffer. */
if (f->__bufsize != 0)
- vm_deallocate (mach_task_self (),
- (vm_address_t) f->__buffer, f->__bufsize);
+ munmap (f->__buffer, f->__bufsize);
f->__buffer = buffer;
f->__bufsize = round_page (nread);
}
@@ -462,8 +587,7 @@ map (struct execdata *e, off_t posn, size_t len)
{
/* Deallocate the old mapping area. */
if (f->__buffer != NULL)
- vm_deallocate (mach_task_self (), (vm_address_t) f->__buffer,
- f->__bufsize);
+ munmap (f->__buffer, f->__bufsize);
f->__buffer = NULL;
/* Make sure our mapping is page-aligned in the file. */
@@ -474,7 +598,7 @@ map (struct execdata *e, off_t posn, size_t len)
/* Map the data from the file. */
if (vm_map (mach_task_self (),
(vm_address_t *) &f->__buffer, f->__bufsize, 0, 1,
- e->filemap, f->__target, 1, VM_PROT_READ, VM_PROT_READ,
+ e->filemap, f->__offset, 1, VM_PROT_READ, VM_PROT_READ,
VM_INHERIT_NONE))
{
errno = e->error = EIO;
@@ -486,7 +610,7 @@ map (struct execdata *e, off_t posn, size_t len)
e->cntl->accessed = 1;
if (f->__offset + f->__bufsize > size)
- f->__get_limit = f->__buffer + (size - f->__target);
+ f->__get_limit = f->__buffer + (size - f->__offset);
else
f->__get_limit = f->__buffer + f->__bufsize;
}
@@ -502,13 +626,26 @@ map (struct execdata *e, off_t posn, size_t len)
return f->__bufp;
}
+#endif
-/* stdio input-room function. */
+/* stdio input-room function.
+ XXX/fault in the stdio case (or libio replacement), i.e. for bfd
+ (if ever revived), need to check all the mapping fault issues */
static int
input_room (FILE *f)
{
- return (map (f->__cookie, f->__target, 1) == NULL ? EOF :
- (unsigned char) *f->__bufp++);
+ struct execdata *e = f->__cookie;
+ char *p = map (e, f->__target, 1);
+ if (p == NULL)
+ {
+ (e->error ? f->__error : f->__eof) = 1;
+ return EOF;
+ }
+
+ f->__target = f->__offset;
+ f->__bufp = p;
+
+ return (unsigned char) *f->__bufp++;
}
static int
@@ -517,12 +654,68 @@ close_exec_stream (void *cookie)
struct execdata *e = cookie;
if (e->stream.__buffer != NULL)
- vm_deallocate (mach_task_self (), (vm_address_t) e->stream.__buffer,
- e->stream.__bufsize);
+ munmap (e->stream.__buffer, e->stream.__bufsize);
+
+ return 0;
+}
+
+/* stdio seek function. */
+static int
+fake_seek (void *cookie, fpos_t *pos, int whence)
+{
+ struct execdata *e = cookie;
+
+ /* Set __target to match the specifed seek location */
+ switch (whence)
+ {
+ case SEEK_END:
+ e->stream.__target = e->file_size + *pos;
+ break;
+ case SEEK_CUR:
+ e->stream.__target += *pos;
+ break;
+
+ case SEEK_SET:
+ e->stream.__target = *pos;
+ break;
+ }
+ *pos = e->stream.__target;
return 0;
}
+/* Initialize E's stdio stream. */
+static void
+prepare_stream (struct execdata *e)
+{
+ memset (&e->stream, 0, sizeof (e->stream));
+ e->stream.__magic = _IOMAGIC;
+ e->stream.__mode.__read = 1;
+ e->stream.__userbuf = 1;
+ e->stream.__room_funcs.__input = input_room;
+ e->stream.__io_funcs.seek = fake_seek;
+ e->stream.__io_funcs.close = close_exec_stream;
+ e->stream.__cookie = e;
+ e->stream.__seen = 1;
+}
+
+/* Point the stream at the buffer of file data. */
+static void
+prepare_in_memory (struct execdata *e)
+{
+ memset (&e->stream, 0, sizeof (e->stream));
+ e->stream.__magic = _IOMAGIC;
+ e->stream.__mode.__read = 1;
+ e->stream.__buffer = e->file_data;
+ e->stream.__bufsize = e->file_size;
+ e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize;
+ e->stream.__bufp = e->stream.__buffer;
+ e->stream.__seen = 1;
+}
+#endif
+
+#endif
+
/* Prepare to check and load FILE. */
static void
@@ -543,16 +736,7 @@ prepare (file_t file, struct execdata *e)
e->interp.section = NULL;
/* Initialize E's stdio stream. */
- memset (&e->stream, 0, sizeof (e->stream));
- e->stream.__magic = _IOMAGIC;
- e->stream.__mode.__read = 1;
- e->stream.__userbuf = 1;
- e->stream.__room_funcs.__input = input_room;
- /* This never gets called, but fseek returns ESPIPE if it's null. */
- e->stream.__io_funcs.seek = __default_io_functions.seek;
- e->stream.__io_funcs.close = close_exec_stream;
- e->stream.__cookie = e;
- e->stream.__seen = 1;
+ prepare_stream (e);
/* Try to mmap FILE. */
e->error = io_map (file, &rd, &wr);
@@ -569,17 +753,7 @@ prepare (file_t file, struct execdata *e)
e->filemap = rd;
e->error = /* io_map_cntl (file, &e->cntlmap) */ EOPNOTSUPP; /* XXX */
- if (e->error)
- {
- /* No shared page. Do a stat to find the file size. */
- struct stat st;
- e->error = io_stat (file, &st);
- if (e->error)
- return;
- e->file_size = st.st_size;
- e->optimal_block = st.st_blksize;
- }
- else
+ if (!e->error)
e->error = vm_map (mach_task_self (), (vm_address_t *) &e->cntl,
vm_page_size, 0, 1, e->cntlmap, 0, 0,
VM_PROT_READ|VM_PROT_WRITE,
@@ -617,9 +791,17 @@ prepare (file_t file, struct execdata *e)
break;
}
}
- else if (e->error == EOPNOTSUPP)
- /* We can't mmap FILE, but perhaps we can do normal I/O to it. */
- e->error = 0;
+
+ if (!e->cntl && (!e->error || e->error == EOPNOTSUPP))
+ {
+ /* No shared page. Do a stat to find the file size. */
+ struct stat st;
+ e->error = io_stat (file, &st);
+ if (e->error)
+ return;
+ e->file_size = st.st_size;
+ e->optimal_block = st.st_blksize;
+ }
}
/* Check the magic number, etc. of the file.
@@ -669,18 +851,18 @@ check_bfd (struct execdata *e)
static void
check_elf (struct execdata *e)
{
- Elf32_Ehdr *ehdr = map (e, 0, sizeof (Elf32_Ehdr));
- Elf32_Phdr *phdr;
+ ElfW(Ehdr) *ehdr = map (e, 0, sizeof (ElfW(Ehdr)));
+ ElfW(Phdr) *phdr;
if (! ehdr)
{
- if (! ferror (&e->stream))
+ if (!e->error)
e->error = ENOEXEC;
return;
}
- if (*(Elf32_Word *) ehdr != ((union { Elf32_Word word;
- unsigned char string[SELFMAG]; })
+ if (*(ElfW(Word) *) ehdr != ((union { ElfW(Word) word;
+ unsigned char string[SELFMAG]; })
{ string: ELFMAG }).word)
{
e->error = ENOEXEC;
@@ -691,13 +873,15 @@ check_elf (struct execdata *e)
ehdr->e_ident[EI_DATA] != host_ELFDATA ||
ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
ehdr->e_version != EV_CURRENT ||
- ehdr->e_machine != elf_machine ||
ehdr->e_ehsize < sizeof *ehdr ||
- ehdr->e_phentsize != sizeof (Elf32_Phdr))
+ ehdr->e_phentsize != sizeof (ElfW(Phdr)))
{
e->error = ENOEXEC;
return;
}
+ e->error = elf_machine_matches_host (ehdr->e_machine);
+ if (e->error)
+ return;
/* Extract all this information now, while EHDR is mapped.
The `map' call below for the phdrs may reuse the mapping window. */
@@ -707,24 +891,33 @@ check_elf (struct execdata *e)
e->info.elf.loadbase = 0;
e->info.elf.phnum = ehdr->e_phnum;
- phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (Elf32_Phdr));
+ phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (ElfW(Phdr)));
if (! phdr)
{
- if (! ferror (&e->stream))
+ if (!e->error)
e->error = ENOEXEC;
return;
}
e->info.elf.phdr = phdr;
+ e->info.elf.phdr_addr = ehdr->e_phoff;
}
+/* Copy MAPPED_PHDR into E->info.elf.phdr, filling in E->interp.phdr
+ in the process. */
static void
-check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr,
- vm_address_t *phdr_addr, vm_size_t *phdr_size)
+check_elf_phdr (struct execdata *e, const ElfW(Phdr) *mapped_phdr)
{
- const Elf32_Phdr *phdr;
+ const ElfW(Phdr) *phdr;
+ bool seen_phdr = false;
memcpy (e->info.elf.phdr, mapped_phdr,
- e->info.elf.phnum * sizeof (Elf32_Phdr));
+ e->info.elf.phnum * sizeof (ElfW(Phdr)));
+
+ /* Default state if we do not see PT_GNU_STACK telling us what to do.
+ Executable stack is the compatible default.
+ (XXX should be machine-dependent??)
+ */
+ e->info.elf.execstack = 1;
for (phdr = e->info.elf.phdr;
phdr < &e->info.elf.phdr[e->info.elf.phnum];
@@ -734,26 +927,37 @@ check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr,
case PT_INTERP:
e->interp.phdr = phdr;
break;
- case PT_PHDR:
- if (phdr_addr)
- *phdr_addr = phdr->p_vaddr & ~(phdr->p_align - 1);
- if (phdr_size)
- *phdr_size = phdr->p_memsz;
- break;
case PT_LOAD:
- /* Sanity check. */
if (e->file_size <= (off_t) (phdr->p_offset +
phdr->p_filesz))
- e->error = ENOEXEC;
+ {
+ e->error = ENOEXEC;
+ return;
+ }
+ /* Check if this is the segment that contains the phdr image. */
+ if (!seen_phdr
+ && (phdr->p_offset & -phdr->p_align) == 0 /* Sanity check. */
+ && phdr->p_offset <= e->info.elf.phdr_addr
+ && e->info.elf.phdr_addr - phdr->p_offset < phdr->p_filesz)
+ {
+ e->info.elf.phdr_addr += phdr->p_vaddr - phdr->p_offset;
+ seen_phdr = true;
+ }
+ break;
+ case PT_GNU_STACK:
+ e->info.elf.execstack = phdr->p_flags & PF_X;
break;
}
+
+ if (!seen_phdr)
+ e->info.elf.phdr_addr = 0;
}
static void
check (struct execdata *e)
{
- check_elf (e);
+ check_elf (e); /* XXX/fault */
#ifdef BFD
if (e->error == ENOEXEC)
{
@@ -781,7 +985,7 @@ finish_mapping (struct execdata *e)
e->cntl->conch_status = USER_HAS_NOT_CONCH;
spin_unlock (&e->cntl->lock);
}
- vm_deallocate (mach_task_self (), (vm_address_t) e->cntl, vm_page_size);
+ munmap (e->cntl, vm_page_size);
e->cntl = NULL;
}
if (e->filemap != MACH_PORT_NULL)
@@ -796,7 +1000,9 @@ finish_mapping (struct execdata *e)
}
}
-/* Clean up after reading the file (need not be completed). */
+/* Clean up after reading the file (need not be completed).
+ Note: this may be called several times for the E, so it must take care
+ of checking what was already freed. */
void
finish (struct execdata *e, int dealloc_file)
{
@@ -809,7 +1015,19 @@ finish (struct execdata *e, int dealloc_file)
}
else
#endif
- fclose (&e->stream);
+ {
+#ifdef EXECDATA_STREAM
+ fclose (&e->stream);
+#else
+ if (e->file_data != NULL) {
+ free (e->file_data);
+ e->file_data = NULL;
+ } else if (map_buffer (e) != NULL) {
+ munmap (map_buffer (e), map_vsize (e));
+ map_buffer (e) = NULL;
+ }
+#endif
+ }
if (dealloc_file && e->file != MACH_PORT_NULL)
{
mach_port_deallocate (mach_task_self (), e->file);
@@ -838,12 +1056,12 @@ load (task_t usertask, struct execdata *e)
else
#endif
{
- Elf32_Word i;
+ ElfW(Word) i;
for (i = 0; i < e->info.elf.phnum; ++i)
if (e->info.elf.phdr[i].p_type == PT_LOAD)
load_section (&e->info.elf.phdr[i], e);
- /* The entry point address is relative to whereever we loaded the
+ /* The entry point address is relative to wherever we loaded the
program text. */
e->entry += e->info.elf.loadbase;
}
@@ -893,7 +1111,7 @@ load (task_t usertask, struct execdata *e)
/* Force it to be paged in. */
(void) *(volatile int *) a;
- vm_deallocate (mach_task_self (), myaddr, mysize);
+ munmap ((caddr_t) myaddr, mysize);
}
}
@@ -927,9 +1145,23 @@ check_gzip (struct execdata *earg)
size_t zipdatasz = 0;
FILE *zipout = NULL;
jmp_buf ziperr;
+ off_t zipread_pos = 0;
int zipread (char *buf, size_t maxread)
{
- return fread (buf, 1, maxread, &e->stream);
+ char *contents = map (e, zipread_pos, 1);
+ size_t n;
+ if (contents == NULL)
+ {
+ errno = e->error;
+ return -1;
+ }
+ n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents);
+ errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */
+ if (errno)
+ longjmp (ziperr, 2);
+
+ zipread_pos += n;
+ return n;
}
void zipwrite (const char *buf, size_t nwrite)
{
@@ -964,7 +1196,6 @@ check_gzip (struct execdata *earg)
return;
}
- rewind (&e->stream);
if (get_method (0) != 0)
{
/* Not a happy gzip file. */
@@ -989,41 +1220,136 @@ check_gzip (struct execdata *earg)
/* The output is complete. Clean up the stream and store its resultant
buffer and size in the execdata as the file contents. */
fclose (zipout);
+
+ /* Clean up the old exec file stream's state.
+ Now that we have the contents all in memory (in E->file_data),
+ nothing will in fact ever try to use E->stream again. */
+ finish (e, 0);
+
+ /* Prepare the stream state to use the file contents already in memory. */
e->file_data = zipdata;
e->file_size = zipdatasz;
+ prepare_in_memory (e);
+}
+#endif
+
+#ifdef BZIP2
+/* Check the file for being a bzip2'd image. Return with ENOEXEC means not
+ a valid bzip2 file; return with another error means lossage in decoding;
+ return with zero means the file was uncompressed into memory which E now
+ points to, and `check' can be run again. */
+
+static void
+check_bzip2 (struct execdata *earg)
+{
+ struct execdata *e = earg;
+ /* Entry points to bunzip2 engine. */
+ void do_bunzip2 (void);
+ /* Callbacks from unzip for I/O and error interface. */
+ extern int (*unzip_read) (char *buf, size_t maxread);
+ extern void (*unzip_write) (const char *buf, size_t nwrite);
+ extern void (*unzip_read_error) (void);
+ extern void (*unzip_error) (const char *msg);
+
+ char *zipdata = NULL;
+ size_t zipdatasz = 0;
+ FILE *zipout = NULL;
+ jmp_buf ziperr;
+ off_t zipread_pos = 0;
+ int zipread (char *buf, size_t maxread)
+ {
+ char *contents = map (e, zipread_pos, 1);
+ size_t n;
+ if (contents == NULL)
+ {
+ errno = e->error;
+ return -1;
+ }
+ n = MIN (maxread, map_buffer (e) + map_fsize (e) - contents);
+ errno = hurd_safe_copyin (buf, contents, n); /* XXX/fault */
+ if (errno)
+ longjmp (ziperr, 2);
+
+ zipread_pos += n;
+ return n;
+ }
+ void zipwrite (const char *buf, size_t nwrite)
+ {
+ if (fwrite (buf, nwrite, 1, zipout) != 1)
+ longjmp (ziperr, 1);
+ }
+ void ziprderr (void)
+ {
+ errno = ENOEXEC;
+ longjmp (ziperr, 2);
+ }
+ void ziperror (const char *msg)
+ {
+ errno = ENOEXEC;
+ longjmp (ziperr, 2);
+ }
+
+ unzip_read = zipread;
+ unzip_write = zipwrite;
+ unzip_read_error = ziprderr;
+ unzip_error = ziperror;
+
+ if (setjmp (ziperr))
+ {
+ /* Error in unzipping jumped out. */
+ if (zipout)
+ {
+ fclose (zipout);
+ free (zipdata);
+ }
+ e->error = errno;
+ return;
+ }
+
+ zipout = open_memstream (&zipdata, &zipdatasz);
+ if (! zipout)
+ {
+ e->error = errno;
+ return;
+ }
- /* Clean up the old exec file stream's state. */
+ /* Call the bunzip2 engine. */
+ do_bunzip2 ();
+
+ /* The output is complete. Clean up the stream and store its resultant
+ buffer and size in the execdata as the file contents. */
+ fclose (zipout);
+
+ /* Clean up the old exec file stream's state.
+ Now that we have the contents all in memory (in E->file_data),
+ nothing will in fact ever try to use E->stream again. */
finish (e, 0);
- /* Point the stream at the buffer of file data. */
- memset (&e->stream, 0, sizeof (e->stream));
- e->stream.__magic = _IOMAGIC;
- e->stream.__mode.__read = 1;
- e->stream.__buffer = e->file_data;
- e->stream.__bufsize = e->file_size;
- e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize;
- e->stream.__bufp = e->stream.__buffer;
- e->stream.__seen = 1;
+ /* Prepare the stream state to use the file contents already in memory. */
+ e->file_data = zipdata;
+ e->file_size = zipdatasz;
+ prepare_in_memory (e);
}
#endif
-static inline error_t
-servercopy (void **arg, mach_msg_type_number_t argsize, boolean_t argcopy)
+static inline void *
+servercopy (void *arg, mach_msg_type_number_t argsize, boolean_t argcopy,
+ error_t *errorp)
{
- if (argcopy)
- {
- /* ARG came in-line, so we must copy it. */
- error_t error;
- void *copy;
- error = vm_allocate (mach_task_self (),
- (vm_address_t *) &copy, argsize, 1);
- if (error)
- return error;
- bcopy (*arg, copy, argsize);
- *arg = copy;
+ if (! argcopy)
+ return arg;
+
+ /* ARG came in-line, so we must copy it. */
+ void *copy;
+ copy = mmap (0, argsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (copy == MAP_FAILED)
+ {
+ *errorp = errno;
+ return NULL;
}
- return 0;
+ memcpy (copy, arg, argsize);
+ return copy;
}
@@ -1047,8 +1373,6 @@ do_exec (file_t file,
struct bootinfo *boot = 0;
int *ports_replaced;
int secure, defaults;
- vm_address_t phdr_addr = 0;
- vm_size_t phdr_size = 0;
mach_msg_type_number_t i;
int intarray_dealloc = 0; /* Dealloc INTARRAY before returning? */
int oldtask_trashed = 0; /* Have we trashed the old task? */
@@ -1074,6 +1398,7 @@ do_exec (file_t file,
/* The gzip code is really cheesy, not even close to thread-safe.
So we serialize all uses of it. */
mutex_lock (&lock);
+ e->error = 0;
check_gzip (e);
mutex_unlock (&lock);
if (e->error == 0)
@@ -1083,11 +1408,30 @@ do_exec (file_t file,
check (e);
}
#endif
+#ifdef BZIP2
+ if (e->error == ENOEXEC)
+ {
+ /* See if it is a compressed image. */
+ static struct mutex lock = MUTEX_INITIALIZER;
+ /* The bzip2 code is really cheesy, not even close to thread-safe.
+ So we serialize all uses of it. */
+ mutex_lock (&lock);
+ e->error = 0;
+ check_bzip2 (e);
+ mutex_unlock (&lock);
+ if (e->error == 0)
+ /* The file was uncompressed into memory, and now E describes the
+ uncompressed image rather than the actual file. Check it again
+ for a valid magic number. */
+ check (e);
+ }
+#endif
}
/* Here is the main body of the function. */
+ interp.file = MACH_PORT_NULL;
/* Catch this error now, rather than later. */
/* XXX For EXEC_DEFAULTS, this is only an error if one of the user's
@@ -1135,13 +1479,11 @@ do_exec (file_t file,
else
#endif
{
- const Elf32_Phdr *phdr = e.info.elf.phdr;
- e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (Elf32_Phdr));
- check_elf_phdr (&e, phdr, &phdr_addr, &phdr_size);
+ const ElfW(Phdr) *phdr = e.info.elf.phdr;
+ e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (ElfW(Phdr)));
+ check_elf_phdr (&e, phdr);
}
- interp.file = MACH_PORT_NULL;
-
if (oldtask == MACH_PORT_NULL)
flags |= EXEC_NEWTASK;
@@ -1152,6 +1494,9 @@ do_exec (file_t file,
e.error = task_create (((flags & EXEC_SECURE) ||
oldtask == MACH_PORT_NULL) ?
mach_task_self () : oldtask,
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
0, &newtask);
if (e.error)
goto out;
@@ -1178,6 +1523,7 @@ do_exec (file_t file,
if (new != MACH_PORT_NULL && reauth)
{
mach_port_t ref = mach_reply_port (), authed;
+ /* MAKE_SEND is safe here because we destroy REF ourselves. */
e.error = io_reauthenticate (new, ref, MACH_MSG_TYPE_MAKE_SEND);
if (! e.error)
e.error = auth_user_authenticate
@@ -1209,11 +1555,6 @@ do_exec (file_t file,
}
bzero (&boot->pi + 1, (char *) &boot[1] - (char *) (&boot->pi + 1));
- /* First record some information about the image itself. */
- boot->phdr_addr = phdr_addr;
- boot->phdr_size = phdr_size;
- boot->user_entry = e.entry;
-
/* These flags say the information we pass through to the new program
may need to be modified. */
secure = (flags & EXEC_SECURE);
@@ -1225,18 +1566,18 @@ do_exec (file_t file,
boot->flags = flags;
- e.error = servercopy ((void **) &argv, argvlen, argv_copy);
+ argv = servercopy (argv, argvlen, argv_copy, &e.error);
if (e.error)
goto stdout;
boot->argv = argv;
boot->argvlen = argvlen;
- e.error = servercopy ((void **) &envp, envplen, envp_copy);
+ envp = servercopy (envp, envplen, envp_copy, &e.error);
if (e.error)
goto stdout;
boot->envp = envp;
boot->envplen = envplen;
- e.error = servercopy ((void **) &dtable, dtablesize * sizeof (mach_port_t),
- dtable_copy);
+ dtable = servercopy (dtable, dtablesize * sizeof (mach_port_t),
+ dtable_copy, &e.error);
if (e.error)
goto stdout;
boot->dtable = dtable;
@@ -1249,10 +1590,8 @@ do_exec (file_t file,
round_page (INIT_INT_MAX * sizeof (int))))
{
/* Allocate a new vector that is big enough. */
- vm_allocate (mach_task_self (),
- (vm_address_t *) &boot->intarray,
- INIT_INT_MAX * sizeof (int),
- 1);
+ boot->intarray = mmap (0, INIT_INT_MAX * sizeof (int),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
memcpy (boot->intarray, intarray, nints * sizeof (int));
intarray_dealloc = !intarray_copy;
}
@@ -1262,8 +1601,8 @@ do_exec (file_t file,
}
else
{
- e.error = servercopy ((void **) &intarray, nints * sizeof (int),
- intarray_copy);
+ intarray = servercopy (intarray, nints * sizeof (int), intarray_copy,
+ &e.error);
if (e.error)
goto stdout;
boot->intarray = intarray;
@@ -1276,9 +1615,8 @@ do_exec (file_t file,
/* Now choose the ports to give the new program. */
boot->nports = nports < INIT_PORT_MAX ? INIT_PORT_MAX : nports;
- vm_allocate (mach_task_self (),
- (vm_address_t *) &boot->portarray,
- boot->nports * sizeof (mach_port_t), 1);
+ boot->portarray = mmap (0, boot->nports * sizeof (mach_port_t),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
/* Start by copying the array as passed. */
for (i = 0; i < nports; ++i)
boot->portarray[i] = portarray[i];
@@ -1374,7 +1712,7 @@ do_exec (file_t file,
name = map (&e, (e.interp.phdr->p_offset
& ~(e.interp.phdr->p_align - 1)),
e.interp.phdr->p_filesz);
- if (! name && ! ferror (&e.stream))
+ if (! name && ! e.error)
e.error = ENOEXEC;
}
@@ -1398,8 +1736,11 @@ do_exec (file_t file,
errno = EBADF;
return MACH_PORT_NULL;
}
+ mach_port_mod_refs (mach_task_self (), boot->dtable[fd],
+ MACH_PORT_RIGHT_SEND, +1);
return boot->dtable[fd];
}
+ /* XXX/fault */
e.error = hurd_file_name_lookup (&user_port, &user_fd, 0,
name, O_READ, 0, &interp.file);
}
@@ -1421,10 +1762,10 @@ do_exec (file_t file,
else
#endif
{
- const Elf32_Phdr *phdr = interp.info.elf.phdr;
+ const ElfW(Phdr) *phdr = interp.info.elf.phdr;
interp.info.elf.phdr = alloca (interp.info.elf.phnum *
- sizeof (Elf32_Phdr));
- check_elf_phdr (&interp, phdr, NULL, NULL);
+ sizeof (ElfW(Phdr)));
+ check_elf_phdr (&interp, phdr);
}
}
e.error = interp.error;
@@ -1439,7 +1780,7 @@ do_exec (file_t file,
if (newtask == oldtask)
{
- thread_array_t threads;
+ thread_t *threads;
mach_msg_type_number_t nthreads, i;
/* Terminate all the threads of the old task. */
@@ -1452,8 +1793,7 @@ do_exec (file_t file,
thread_terminate (threads[i]);
mach_port_deallocate (mach_task_self (), threads[i]);
}
- vm_deallocate (mach_task_self (),
- (vm_address_t) threads, nthreads * sizeof (thread_t));
+ munmap ((caddr_t) threads, nthreads * sizeof (thread_t));
/* Deallocate the entire virtual address space of the task. */
@@ -1500,6 +1840,20 @@ do_exec (file_t file,
/* Clean up. */
finish (&e, 0);
+ /* Now record some essential addresses from the image itself that the
+ program's startup code will need to know. We do this after loading
+ the image so that a load-anywhere image gets the adjusted addresses. */
+ if (e.info.elf.phdr_addr != 0)
+ {
+#ifdef BFD
+ if (!e.bfd)
+#endif
+ e.info.elf.phdr_addr += e.info.elf.loadbase;
+ boot->phdr_addr = e.info.elf.phdr_addr;
+ boot->phdr_size = e.info.elf.phnum * sizeof (ElfW(Phdr));
+ }
+ boot->user_entry = e.entry; /* already adjusted in `load' */
+
/* Create the initial thread. */
e.error = thread_create (newtask, &thread);
if (e.error)
@@ -1513,6 +1867,17 @@ do_exec (file_t file,
&boot->stack_base, &boot->stack_size);
if (e.error)
goto out;
+#ifdef BFD
+ if (!e.bfd)
+#endif
+ {
+ /* It would probably be better to change mach_setup_thread so
+ it does a vm_map with the right permissions to start with. */
+ if (!e.info.elf.execstack)
+ e.error = vm_protect (newtask, boot->stack_base, boot->stack_size,
+ 0, VM_PROT_READ | VM_PROT_WRITE);
+ }
+
if (oldtask != newtask && oldtask != MACH_PORT_NULL)
{
@@ -1538,8 +1903,6 @@ do_exec (file_t file,
proc_reassign (proc, newtask);
mach_port_deallocate (mach_task_self (), proc);
}
-
- mach_port_deallocate (mach_task_self (), oldtask);
}
/* Make sure the proc server has the right idea of our identity. */
@@ -1566,36 +1929,53 @@ do_exec (file_t file,
authenticated anyhow. */
proc_setowner (boot->portarray[INIT_PORT_PROC],
neuids ? euids[0] : 0, !neuids);
-
+
/* Clean up */
if (euids != euidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) euids,
- neuids * sizeof (uid_t));
+ munmap (euids, neuids * sizeof (uid_t));
if (egids != egidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) egids,
- negids * sizeof (uid_t));
+ munmap (egids, negids * sizeof (uid_t));
if (auids != auidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) auids,
- nauids * sizeof (uid_t));
+ munmap (auids, nauids * sizeof (uid_t));
if (agids != agidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) agids,
- nagids * sizeof (uid_t));
+ munmap (agids, nagids * sizeof (uid_t));
}
}
{
- mach_port_t btport = ports_get_right (boot);
- mach_port_insert_right (mach_task_self (), btport, btport,
- MACH_MSG_TYPE_MAKE_SEND);
+ mach_port_t btport = ports_get_send_right (boot);
e.error = task_set_bootstrap_port (newtask, btport);
mach_port_deallocate (mach_task_self (), btport);
}
out:
- if (e.interp.section)
+ if (interp.file != MACH_PORT_NULL)
finish (&interp, 1);
finish (&e, !e.error);
+ if (!e.error && (flags & EXEC_SIGTRAP)) /* XXX && !secure ? */
+ {
+ /* This is a "traced" exec, i.e. the new task is to be debugged. The
+ caller has requested that the new process stop with SIGTRAP before
+ it starts. Since the process has no signal thread yet to do its
+ own POSIX signal mechanics, we simulate it by notifying the proc
+ server of the signal and leaving the initial thread with a suspend
+ count of one, as it would be if the process were stopped by a
+ POSIX signal. */
+ mach_port_t proc;
+ if (boot->nports > INIT_PORT_PROC)
+ proc = boot->portarray[INIT_PORT_PROC];
+ else
+ /* Ask the proc server for the proc port for this task. */
+ e.error = proc_task2proc (procserver, newtask, &proc);
+ if (!e.error)
+ /* Tell the proc server that the process has stopped with the
+ SIGTRAP signal. Don't bother to check for errors from the RPC
+ here; for non-secure execs PROC may be the user's own proc
+ server its confusion shouldn't make the exec fail. */
+ proc_mark_stop (proc, SIGTRAP, 0);
+ }
+
if (boot)
{
/* Release the original reference. Now there is only one
@@ -1619,7 +1999,8 @@ do_exec (file_t file,
if (thread != MACH_PORT_NULL)
{
- thread_resume (thread);
+ if (!e.error && !(flags & EXEC_SIGTRAP))
+ thread_resume (thread);
mach_port_deallocate (mach_task_self (), thread);
}
@@ -1666,13 +2047,9 @@ do_exec (file_t file,
portarray, and we are not saving those pointers in BOOT for later
transfer, deallocate the original space now. */
if (intarray_dealloc)
- vm_deallocate (mach_task_self (),
- (vm_address_t) intarray,
- nints * sizeof intarray[0]);
+ munmap (intarray, nints * sizeof intarray[0]);
if (!portarray_copy)
- vm_deallocate (mach_task_self (),
- (vm_address_t) portarray,
- nports * sizeof portarray[0]);
+ munmap (portarray, nports * sizeof portarray[0]);
}
return e.error;
@@ -1804,13 +2181,16 @@ S_exec_setexecdata (struct trivfs_protid *protid,
if (nports < INIT_PORT_MAX || nints < INIT_INT_MAX)
return EINVAL; /* */
- err = servercopy ((void **) &ports, nports * sizeof (mach_port_t),
- ports_copy);
+ err = 0;
+ ports = servercopy (ports, nports * sizeof (mach_port_t), ports_copy, &err);
if (err)
return err;
- err = servercopy ((void **) &ints, nints * sizeof (int), ints_copy);
+ ints = servercopy (ints, nints * sizeof (int), ints_copy, &err);
if (err)
- return err;
+ {
+ munmap (ports, nports * sizeof (mach_port_t));
+ return err;
+ }
rwlock_writer_lock (&std_lock);
@@ -1819,16 +2199,14 @@ S_exec_setexecdata (struct trivfs_protid *protid,
mach_msg_type_number_t i;
for (i = 0; i < std_nports; ++i)
mach_port_deallocate (mach_task_self (), std_ports[i]);
- vm_deallocate (mach_task_self (), (vm_address_t)std_ports,
- std_nports * sizeof (mach_port_t));
+ munmap (std_ports, std_nports * sizeof (mach_port_t));
}
std_ports = ports;
std_nports = nports;
if (std_ints)
- vm_deallocate (mach_task_self (), (vm_address_t)std_ints,
- std_nints * sizeof (int));
+ munmap (std_ints, std_nints * sizeof (int));
std_ints = ints;
std_nints = nints;
diff --git a/exec/execmutations.h b/exec/execmutations.h
index 62ae5c55..96b47721 100644
--- a/exec/execmutations.h
+++ b/exec/execmutations.h
@@ -4,3 +4,5 @@
#define FILE_DESTRUCTOR trivfs_end_using_protid (trivfs_protid_t)
#define EXEC_IMPORTS import "priv.h";
+
+#define SERVERCOPY 1
diff --git a/exec/exectrans.c b/exec/exectrans.c
deleted file mode 100644
index 59c9cdf2..00000000
--- a/exec/exectrans.c
+++ /dev/null
@@ -1,81 +0,0 @@
-
-#include <stdio.h>
-#include <getopt.h>
-#include <error.h>
-#include <sys/stat.h>
-
-#include <hurd.h>
-#include <hurd/trivfs.h>
-
-
-/* Where to put the service ports. */
-static struct port_bucket *port_bucket;
-
-/* Trivfs hooks. */
-int trivfs_fstype = FSTYPE_MISC;
-int trivfs_fsid = 0;
-int trivfs_support_read = 1;
-int trivfs_support_write = 1;
-int trivfs_support_exec = 1;
-int trivfs_allow_open = O_READ|O_WRITE|O_EXEC;
-
-struct port_class *trivfs_protid_portclasses[1];
-struct port_class *trivfs_cntl_portclasses[1];
-int trivfs_protid_nportclasses = 1;
-int trivfs_cntl_nportclasses = 1;
-
-
-static int
-exec_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
-{
- extern int exec_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
- return exec_server (inp, outp) || trivfs_demuxer (inp, outp);
-}
-
-void
-trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
-{
- st->st_fstype = FSTYPE_MISC;
-}
-
-error_t
-trivfs_goaway (struct trivfs_control *fsys, int flags)
-{
- int count;
-
- /* Stop new requests. */
- ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]);
- ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]);
-
- /* Are there any extant user ports for the /servers/exec file? */
- count = ports_count_class (trivfs_protid_portclasses[0]);
- if (count == 0 || (flags & FSYS_GOAWAY_FORCE))
- {
- /* No users. Disconnect from the filesystem. */
- mach_port_deallocate (mach_task_self (), fsys->underlying);
-
- /* Are there remaining exec_startup RPCs to answer? */
- count = ports_count_class (execboot_portclass);
- if (count == 0)
- /* Nope. We got no reason to live. */
- exit (0);
-
- /* Continue servicing tasks starting up. */
- ports_enable_class (execboot_portclass);
-
- /* No more communication with the parent filesystem. */
- ports_destroy_right (fsys);
- going_down = 1;
-
- return 0;
- }
- else
- {
- /* We won't go away, so start things going again... */
- ports_enable_class (trivfs_protid_portclasses[0]);
- ports_resume_class_rpcs (trivfs_cntl_portclasses[0]);
- ports_resume_class_rpcs (trivfs_protid_portclasses[0]);
-
- return EBUSY;
- }
-}
diff --git a/exec/gcore.c b/exec/gcore.c
deleted file mode 100644
index 7343516c..00000000
--- a/exec/gcore.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/* `gcore' for GNU Hurd.
- Copyright (C) 1992 Free Software Foundation
- Written by Roland McGrath.
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <hurd.h>
-#include <hurd/core.h>
-#include <limits.h>
-
-int
-main (int argc, char **argv)
-{
- file_t coreserv;
- int i;
-
- if (argc < 2)
- {
- usage:
- fprintf (stderr, "Usage: %s PID ...\n", program_invocation_short_name);
- exit (1);
- }
-
- coreserv = path_lookup (_SERVERS_CORE, 0, 0);
- if (coreserv == MACH_PORT_NULL)
- {
- perror (_SERVERS_CORE);
- exit (1);
- }
-
- for (i = 1; i < argc; ++i)
- {
- char *end;
- pid_t pid;
- task_t task;
-
- pid = strtol (&argv[i], &end, 10);
- if (end == &argv[i] || *end != '\0')
- goto usage;
-
- task = pid2task ((pid_t) pid);
- if (task == MACH_PORT_NULL)
- fprintf (stderr, "pid2task: %d: %s\n", pid, strerror (errno));
- else
- {
- char name[PATH_MAX];
- file_t file;
- sprintf (name, "core.%d", pid);
- file = path_lookup (name, FS_LOOKUP_WRITE|FS_LOOKUP_CREATE,
- 0666 &~ getumask ());
- if (file == MACH_PORT_NULL)
- perror (name);
- else
- {
- error_t err = core_dump_task (coreserv, task,
- file,
- 0, 0,
- getenv ("GNUTARGET"));
- mach_port_deallocate (mach_task_self (), file);
- if (err)
- {
- (void) remove (name);
- fprintf (stderr, "core_dump_task: %d: %s\n",
- pid, strerror (err));
- }
- }
- }
- mach_port_deallocate (mach_task_self (), task);
- }
-
- exit (0);
-}
diff --git a/exec/hashexec.c b/exec/hashexec.c
index 748f8e1b..2aa3844b 100644
--- a/exec/hashexec.c
+++ b/exec/hashexec.c
@@ -1,5 +1,5 @@
/* GNU Hurd standard exec server, #! script execution support.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2000,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -18,11 +18,11 @@ You should have received a copy of the GNU General Public License
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
#include "priv.h"
#include <hurd/sigpreempt.h>
#include <unistd.h>
#include <envz.h>
+#include <sys/param.h>
/* This is called to check E for a #! interpreter specification. E has
already been prepared (successfully) and checked (unsuccessfully). If
@@ -43,13 +43,10 @@ check_hashbang (struct execdata *e,
mach_port_t *deallocnames, u_int ndeallocnames,
mach_port_t *destroynames, u_int ndestroynames)
{
- char *ibuf = NULL;
- size_t ibufsiz = 0;
char *p;
char *interp, *arg; /* Interpreter file name, and first argument */
- size_t interp_len, len;
+ size_t interp_len, arg_len;
file_t interp_file; /* Port open on the interpreter file. */
- FILE *f = &e->stream;
char *new_argv;
size_t new_argvlen;
mach_port_t *new_dtable = NULL;
@@ -57,12 +54,18 @@ check_hashbang (struct execdata *e,
file_t user_fd (int fd)
{
- if (fd < 0 || fd >= dtablesize || dtable[fd] == MACH_PORT_NULL)
+ if (fd >= 0 && fd < dtablesize)
{
- errno = EBADF;
- return MACH_PORT_NULL;
+ const file_t dport = dtable[fd];
+ if (dport != MACH_PORT_NULL)
+ {
+ mach_port_mod_refs (mach_task_self (), dport,
+ MACH_PORT_RIGHT_SEND, +1);
+ return dport;
+ }
}
- return dtable[fd];
+ errno = EBADF;
+ return MACH_PORT_NULL;
}
file_t user_crdir, user_cwdir;
error_t user_port (int which, error_t (*operate) (mach_port_t))
@@ -71,6 +74,9 @@ check_hashbang (struct execdata *e,
{
error_t err;
mach_port_t ref;
+
+ /* MAKE_SEND is safe here because we destroy REF ourselves. */
+
error_t uauth (auth_t auth)
{
return auth_user_authenticate (auth,
@@ -121,50 +127,81 @@ check_hashbang (struct execdata *e,
name, flags, 0, result);
}
- rewind (f);
+ const char *page;
+ char interp_buf[vm_page_size - 2 + 1];
- /* Check for our ``magic number''--"#!". */
+ e->error = 0;
+ page = map (e, 0, 2);
- errno = 0;
- if (getc (f) != '#' || getc (f) != '!')
+ if (!page)
{
- /* No `#!' here. If there was a read error (not including EOF),
- return that error indication. Otherwise return ENOEXEC to
- say it's not a file we know how to execute. */
- e->error = ferror (f) ? errno : ENOEXEC;
+ if (!e->error)
+ e->error = ENOEXEC;
return;
}
- /* Read the rest of the first line of the file. */
-
- interp_len = getline (&ibuf, &ibufsiz, f);
- if (ferror (f))
+ /* Check for our ``magic number''--"#!". */
+ if (page[0] != '#' || page[1] != '!')
{
- e->error = errno ?: EIO;
+ /* These are not the droids we're looking for. */
+ e->error = ENOEXEC;
return;
}
- if (ibuf[interp_len - 1] == '\n')
- ibuf[--interp_len] = '\0';
- /* Find the name of the interpreter. */
- p = ibuf + strspn (ibuf, " \t");
- interp = strsep (&p, " \t");
+ /* Read the rest of the first line of the file.
+ We in fact impose an arbitrary limit of about a page on this. */
- if (p)
- /* Skip remaining blanks, and the rest of the line is the argument. */
+ p = memccpy (interp_buf, page + 2, '\n',
+ MIN (map_fsize (e) - 2, sizeof interp_buf));
+ if (p == NULL)
{
- p += strspn (p, " \t");
- arg = p;
- len = interp_len - (arg - ibuf);
+ /* The first line went on for more than sizeof INTERP_BUF! */
+ interp_len = sizeof interp_buf;
+ interp_buf[interp_len - 1] = '\0';
}
else
- /* There is no argument. */
- len = 0;
+ {
+ interp_len = p - interp_buf; /* Includes null terminator. */
+ *--p = '\0'; /* Kill the newline. */
+ }
+
+ /* We are now done reading the script file. */
+ finish (e, 0);
+
+
+ /* Find the name of the interpreter. */
+ interp = interp_buf + strspn (interp_buf, " \t");
+ p = strpbrk (interp, " \t");
+
+ if (p)
+ {
+ /* Terminate the interpreter name. */
+ *p++ = '\0';
- if (len == 0)
- arg = NULL;
+ /* Skip remaining blanks, and the rest of the line is the argument. */
+
+ arg = p + strspn (p, " \t");
+ arg_len = interp_len - 1 - (arg - interp_buf); /* without null here */
+ interp_len = p - interp; /* This one includes the null. */
+
+ if (arg_len == 0)
+ arg = NULL;
+ else
+ {
+ /* Trim trailing blanks after the argument. */
+ size_t i = arg_len - 1;
+ while (arg[i] == ' ' || arg[i] == '\t')
+ arg[i--] = '\0';
+ arg_len = i + 2; /* Include the terminating null. */
+ }
+ }
else
- ++len; /* Include the terminating null. */
+ {
+ /* There is no argument. */
+ arg = NULL;
+ arg_len = 0;
+ interp_len -= interp - interp_buf; /* Account for blanks skipped. */
+ }
user_crdir = user_cwdir = MACH_PORT_NULL;
@@ -179,7 +216,7 @@ check_hashbang (struct execdata *e,
jmp_buf args_faulted;
void fault_handler (int signo)
{ longjmp (args_faulted, 1); }
- error_t setup_args (struct hurd_signal_preempter *preempter)
+ error_t setup_args (struct hurd_signal_preemptor *preemptor)
{
size_t namelen;
char * volatile file_name = NULL;
@@ -197,14 +234,13 @@ check_hashbang (struct execdata *e,
char *name;
int free_name = 0; /* True if we should free NAME. */
file_t name_file;
- mach_port_t fileid;
- dev_t filedev;
+ mach_port_t fileid, filefsid;
ino_t fileno;
/* Search $PATH for NAME, opening a port NAME_FILE on it.
This is encapsulated in a function so we can catch faults
reading the user's environment. */
- error_t search_path (struct hurd_signal_preempter *preempter)
+ error_t search_path (struct hurd_signal_preemptor *preemptor)
{
error_t err;
char *path = envz_get (envp, envplen, "PATH"), *pfxed_name;
@@ -228,9 +264,10 @@ check_hashbang (struct execdata *e,
return err;
}
- error = io_identity (file, &fileid, &filedev, &fileno);
+ error = io_identity (file, &fileid, &filefsid, &fileno);
if (error)
goto out;
+ mach_port_deallocate (mach_task_self (), filefsid);
if (memchr (argv, '\0', argvlen) == NULL)
{
@@ -251,11 +288,15 @@ check_hashbang (struct execdata *e,
if (!error && name_file != MACH_PORT_NULL)
{
- mach_port_t id;
- dev_t dev;
+ mach_port_t id, fsid;
ino_t ino;
- error = io_identity (name_file, &id, &dev, &ino);
- __mach_port_deallocate (__mach_task_self (), id);
+ error = io_identity (name_file, &id, &fsid, &ino);
+ mach_port_deallocate (mach_task_self (), name_file);
+ if (!error)
+ {
+ mach_port_deallocate (mach_task_self (), fsid);
+ mach_port_deallocate (mach_task_self (), id);
+ }
if (!error && id == fileid)
{
file_name = name;
@@ -263,10 +304,9 @@ check_hashbang (struct execdata *e,
}
else if (free_name)
free (name);
- __mach_port_deallocate (__mach_task_self (), name_file);
}
- __mach_port_deallocate (__mach_task_self (), fileid);
+ mach_port_deallocate (mach_task_self (), fileid);
}
if (file_name == NULL)
@@ -298,33 +338,50 @@ check_hashbang (struct execdata *e,
/* Prepare the arguments to pass to the interpreter from the original
arguments and the name of the script file. The args will look
- like `ARGV[0] {ARG} FILE_NAME ARGV[1..n]' (ARG might have been
+ like `INTERP {ARG} FILE_NAME ARGV[1..n]' (ARG might have been
omitted). */
namelen = strlen (file_name) + 1;
- new_argvlen = argvlen + len + namelen;
- e->error = vm_allocate (mach_task_self (),
- (vm_address_t *) &new_argv,
- new_argvlen, 1);
- if (e->error)
- return e->error;
+ new_argvlen
+ = (argvlen - strlen (argv) - 1) /* existing args - old argv[0] */
+ + interp_len + arg_len + namelen; /* New args */
+
+ new_argv = mmap (0, new_argvlen, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (new_argv == (caddr_t) -1)
+ {
+ e->error = errno;
+ return e->error;
+ }
+ else
+ e->error = 0;
if (! setjmp (args_faulted))
{
char *other_args;
- other_args = memccpy (new_argv, argv, '\0', argvlen);
- p = &new_argv[other_args ? other_args - new_argv : argvlen];
+
+ p = new_argv;
+
+ /* INTERP */
+ memcpy (p, interp, interp_len);
+ p += interp_len;
+
+ /* Maybe ARG */
if (arg)
{
- memcpy (p, arg, len);
- p += len;
+ memcpy (p, arg, arg_len);
+ p += arg_len;
}
+
+ /* FILE_NAME */
memcpy (p, file_name, namelen);
p += namelen;
- if (other_args)
- memcpy (p, other_args - new_argv + argv,
- argvlen - (other_args - new_argv));
+
+ /* Maybe remaining args */
+ other_args = argv + strlen (argv) + 1;
+ if (other_args - argv < argvlen)
+ memcpy (p, other_args, argvlen - (other_args - argv));
}
else
{
@@ -332,7 +389,7 @@ check_hashbang (struct execdata *e,
char *n = stpncpy (new_argv,
"**fault in exec server reading argv[0]**",
argvlen);
- memcpy (memcpy (n, arg, len) + len, file_name, namelen);
+ memcpy (memcpy (n, arg, arg_len) + arg_len, file_name, namelen);
}
if (free_file_name)
@@ -347,10 +404,6 @@ check_hashbang (struct execdata *e,
&setup_args, &fault_handler);
}
- /* We are now done reading the script file. */
- finish (e, 0);
- free (ibuf);
-
rwlock_reader_unlock (&std_lock);
if (user_crdir != MACH_PORT_NULL)
@@ -384,21 +437,19 @@ check_hashbang (struct execdata *e,
task_resume (oldtask); /* Our caller suspended it. */
mach_port_deallocate (mach_task_self (), oldtask);
if (! argv_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) argv, argvlen);
+ munmap (argv, argvlen);
if (! envp_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) envp, envplen);
+ munmap (envp, envplen);
for (i = 0; i < dtablesize; ++i)
- mach_port_deallocate (mach_task_self (), dtable[i]);
+ if (MACH_PORT_VALID (dtable[i]))
+ mach_port_deallocate (mach_task_self (), dtable[i]);
if (! dtable_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) dtable,
- dtablesize * sizeof *dtable);
+ munmap (dtable, dtablesize * sizeof *dtable);
for (i = 0; i < nports; ++i)
mach_port_deallocate (mach_task_self (), portarray[i]);
if (! portarray_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) portarray,
- nports * sizeof *portarray);
+ munmap (portarray, nports * sizeof *portarray);
if (! intarray_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) intarray,
- nints * sizeof *intarray);
+ munmap (intarray, nints * sizeof *intarray);
}
}
diff --git a/exec/hostarch.c b/exec/hostarch.c
index 38a38a00..ec59a417 100644
--- a/exec/hostarch.c
+++ b/exec/hostarch.c
@@ -1,6 +1,6 @@
/* Determine the BFD and ELF architecture and machine flavor
from a Mach host port. Used by the exec and core servers.
- Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,95,96,99,2000,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -10,7 +10,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -19,17 +19,82 @@ You should have received a copy of the GNU General Public License
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include "priv.h"
#include <mach.h>
#include <hurd/hurd_types.h>
#include <errno.h>
-#include <bfd.h>
#include <elf.h>
error_t
+elf_machine_matches_host (ElfW(Half) e_machine)
+{
+ static void *host_type; /* Cached entry into the switch below. */
+ struct host_basic_info hostinfo;
+
+ if (host_type)
+ goto *host_type;
+ else
+ {
+ error_t err;
+ mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT;
+
+ err = host_info (mach_host_self (), HOST_BASIC_INFO,
+ (natural_t *) &hostinfo, &hostinfocnt);
+ if (err)
+ return err;
+ assert (hostinfocnt == HOST_BASIC_INFO_COUNT);
+ }
+
+#define CACHE(test) ({ __label__ here; host_type = &&here; \
+ here: return (test) ? 0 : ENOEXEC; })
+ switch (hostinfo.cpu_type)
+ {
+ case CPU_TYPE_MC68020:
+ case CPU_TYPE_MC68030:
+ case CPU_TYPE_MC68040:
+ CACHE (e_machine == EM_68K);
+
+ case CPU_TYPE_I860:
+ CACHE (e_machine == EM_860);
+
+ case CPU_TYPE_MIPS:
+ CACHE (e_machine == EM_MIPS);
+
+ case CPU_TYPE_MC88000:
+ CACHE (e_machine == EM_88K);
+
+ case CPU_TYPE_SPARC:
+ CACHE (e_machine == EM_SPARC);
+
+ case CPU_TYPE_I386:
+ case CPU_TYPE_I486:
+ case CPU_TYPE_PENTIUM:
+ case CPU_TYPE_PENTIUMPRO:
+ CACHE (e_machine == EM_386);
+
+ case CPU_TYPE_POWERPC:
+ CACHE (e_machine == EM_PPC);
+
+ case CPU_TYPE_ALPHA:
+ CACHE (e_machine == EM_ALPHA);
+
+ case CPU_TYPE_HPPA:
+ CACHE (e_machine == EM_PARISC);
+
+ default:
+ return EGRATUITOUS; /* XXX */
+ }
+
+ return 0;
+}
+
+#ifdef BFD
+#include <bfd.h>
+
+error_t
bfd_mach_host_arch_mach (host_t host,
enum bfd_architecture *arch,
- long int *machine,
- Elf32_Half *e_machine)
+ long int *machine)
{
error_t err;
struct host_basic_info hostinfo;
@@ -117,3 +182,5 @@ bfd_mach_host_arch_mach (host_t host,
return 0;
}
+
+#endif /* BFD */
diff --git a/exec/main.c b/exec/main.c
index 809b99a8..efad85aa 100644
--- a/exec/main.c
+++ b/exec/main.c
@@ -1,46 +1,48 @@
/* GNU Hurd standard exec server, main program and server mechanics.
- Copyright (C) 1992, 1993, 19941996 Free Software Foundation, Inc.
- Written by Roland McGrath.
-This file is part of the GNU Hurd.
+ Copyright (C) 1992,93,94,95,96,97,98,99,2000,01,02
+ Free Software Foundation, Inc.
+ Written by Roland McGrath.
+ This file is part of the GNU Hurd.
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
#include <error.h>
#include <hurd/paths.h>
#include <hurd/startup.h>
+#include <argp.h>
+#include <version.h>
+const char *argp_program_version = STANDARD_HURD_VERSION (exec);
+#ifdef BFD
bfd_arch_info_type host_bfd_arch_info;
bfd host_bfd = { arch_info: &host_bfd_arch_info };
-Elf32_Half elf_machine; /* ELF e_machine for the host. */
-
extern error_t bfd_mach_host_arch_mach (host_t host,
enum bfd_architecture *bfd_arch,
long int *bfd_machine,
- Elf32_Half *elf_machine);
-
+ ElfW(Half) *elf_machine);
+#endif
/* Trivfs hooks. */
int trivfs_fstype = FSTYPE_MISC;
int trivfs_fsid = 0;
-int trivfs_support_read = 1;
-int trivfs_support_write = 1;
-int trivfs_support_exec = 1;
-int trivfs_allow_open = O_READ|O_WRITE|O_EXEC;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_allow_open = 0;
struct port_class *trivfs_protid_portclasses[1];
struct port_class *trivfs_cntl_portclasses[1];
@@ -49,7 +51,6 @@ int trivfs_cntl_nportclasses = 1;
struct trivfs_control *fsys;
-char *exec_version = "0.0";
char **save_argv;
@@ -72,21 +73,15 @@ deadboot (void *p)
struct bootinfo *boot = p;
size_t i;
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->argv, boot->argvlen);
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->envp, boot->envplen);
+ munmap (boot->argv, boot->argvlen);
+ munmap (boot->envp, boot->envplen);
for (i = 0; i < boot->dtablesize; ++i)
mach_port_deallocate (mach_task_self (), boot->dtable[i]);
for (i = 0; i < boot->nports; ++i)
mach_port_deallocate (mach_task_self (), boot->portarray[i]);
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->portarray,
- boot->nports * sizeof (mach_port_t));
- vm_deallocate (mach_task_self (),
- (vm_address_t) boot->intarray,
- boot->nints * sizeof (int));
+ munmap (boot->portarray, boot->nports * sizeof (mach_port_t));
+ munmap (boot->intarray, boot->nints * sizeof (int));
/* See if we are going away and this was the last thing keeping us up. */
if (ports_count_class (trivfs_cntl_portclasses[0]) == 0)
@@ -113,17 +108,21 @@ main (int argc, char **argv)
{
error_t err;
mach_port_t bootstrap;
+ struct argp argp = { 0, 0, 0, "Hurd standard exec server." };
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
save_argv = argv;
+#ifdef BFD
/* Put the Mach kernel's idea of what flavor of machine this is into the
fake BFD against which architecture compatibility checks are made. */
err = bfd_mach_host_arch_mach (mach_host_self (),
&host_bfd.arch_info->arch,
- &host_bfd.arch_info->mach,
- &elf_machine);
+ &host_bfd.arch_info->mach);
if (err)
error (1, err, "Getting host architecture from Mach");
+#endif
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
@@ -150,8 +149,7 @@ main (int argc, char **argv)
/* Launch. */
ports_manage_port_operations_multithread (port_bucket, exec_demuxer,
- 2 * 60 * 1000, 0,
- 0, MACH_PORT_NULL);
+ 2 * 60 * 1000, 0, 0);
return 0;
}
@@ -204,24 +202,6 @@ trivfs_goaway (struct trivfs_control *fsys, int flags)
}
}
-/* Attempt to set the active translator for the exec server so that
- filesystems other than the bootstrap can find it. */
-void
-set_active_trans ()
-{
- file_t execnode;
-
- execnode = file_name_lookup (_SERVERS_EXEC, O_NOTRANS | O_CREAT, 0666);
- if (execnode == MACH_PORT_NULL)
- return;
-
- file_set_translator (execnode, 0, FS_TRANS_SET, 0, 0, 0,
- ports_get_right (fsys), MACH_MSG_TYPE_MAKE_SEND);
- /* Don't deallocate EXECNODE here. If we drop the last reference,
- a bug in ufs might throw away the active translator. XXX */
-}
-
-
/* Sent by the bootstrap filesystem after the other essential
servers have been started up. */
@@ -229,7 +209,7 @@ kern_return_t
S_exec_init (struct trivfs_protid *protid,
auth_t auth, process_t proc)
{
- mach_port_t host_priv, dev_master, startup;
+ mach_port_t host_priv, startup;
error_t err;
if (! protid || ! protid->isroot)
@@ -239,50 +219,45 @@ S_exec_init (struct trivfs_protid *protid,
_hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], auth); /* Consume. */
/* Do initial setup with the proc server. */
- _hurd_proc_init (save_argv);
-
- /* Set the active translator on /servers/exec. */
- set_active_trans ();
+ _hurd_proc_init (save_argv, NULL, 0);
procserver = getproc ();
- err = get_privileged_ports (&host_priv, &dev_master);
- if (!err)
- {
- proc_register_version (procserver, host_priv, "exec", HURD_RELEASE,
- exec_version);
- mach_port_deallocate (mach_task_self (), dev_master);
- err = proc_getmsgport (procserver, 1, &startup);
- if (err)
- {
- mach_port_deallocate (mach_task_self (), host_priv);
- host_priv = MACH_PORT_NULL;
- }
- }
- else
- host_priv = MACH_PORT_NULL;
-
+ /* Have the proc server notify us when the canonical ints and ports
+ change. This will generate an immediate callback giving us the
+ initial boot-time canonical sets. */
{
- /* Have the proc server notify us when the canonical ints and ports
- change. */
-
+ struct iouser *user;
struct trivfs_protid *cred;
- err = trivfs_open (fsys, 0, 0, 0, 0, 0, MACH_PORT_NULL, &cred);
+ mach_port_t right;
+
+ err = iohelp_create_empty_iouser (&user);
+ assert_perror (err);
+ err = trivfs_open (fsys, user, 0, MACH_PORT_NULL, &cred);
assert_perror (err);
- proc_execdata_notify (procserver, ports_get_right (cred),
- MACH_MSG_TYPE_MAKE_SEND);
+ right = ports_get_send_right (cred);
+ proc_execdata_notify (procserver, right, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
}
+ err = get_privileged_ports (&host_priv, NULL);
+ assert_perror (err);
+
+ proc_register_version (procserver, host_priv, "exec", "", HURD_VERSION);
+
+ err = proc_getmsgport (procserver, 1, &startup);
+ assert_perror (err);
+ mach_port_deallocate (mach_task_self (), procserver);
+
/* Call startup_essential task last; init assumes we are ready to
run once we call it. */
- if (host_priv != MACH_PORT_NULL)
- {
- startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL,
- "exec", host_priv);
- mach_port_deallocate (mach_task_self (), startup);
- mach_port_deallocate (mach_task_self (), host_priv);
- }
+ err = startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL,
+ "exec", host_priv);
+ assert_perror (err);
+ mach_port_deallocate (mach_task_self (), startup);
+
+ mach_port_deallocate (mach_task_self (), host_priv);
return 0;
}
diff --git a/exec/priv.h b/exec/priv.h
index 0ded21eb..7cee15e4 100644
--- a/exec/priv.h
+++ b/exec/priv.h
@@ -1,5 +1,5 @@
/* GNU Hurd standard exec server, private declarations.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2000,02, 04 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -9,7 +9,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -22,12 +22,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <hurd/trivfs.h>
#include <hurd/ports.h>
#include <hurd/lookup.h>
#include <rwlock.h>
+
+#ifdef BFD
#include <bfd.h>
+#endif
+
#include <elf.h>
+#include <link.h> /* This gives us the ElfW macro. */
#include <fcntl.h>
#include "exec_S.h"
@@ -35,11 +41,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef exec_priv_h
#define exec_priv_h
+#ifdef BFD
/* A BFD whose architecture and machine type are those of the host system. */
extern bfd_arch_info_type host_bfd_arch_info;
extern bfd host_bfd;
-extern Elf32_Half elf_machine; /* ELF e_machine for the host. */
-
+#endif
/* Information kept around to be given to a new task
in response to a message on the task's bootstrap port. */
@@ -62,11 +68,14 @@ struct bootinfo
struct port_bucket *port_bucket;
struct port_class *execboot_portclass;
-
-typedef struct trivfs_protid *trivfs_protid_t; /* For MiG. */
-
extern mach_port_t procserver; /* Our proc port. */
+#ifdef BFD
+#define EXECDATA_STREAM /* BFD uses stdio to access the executable. */
+#else
+typedef void asection;
+#endif
+
/* Data shared between check, check_section,
load, load_section, and finish. */
@@ -77,16 +86,46 @@ struct execdata
/* Set by check. */
vm_address_t entry;
- FILE stream;
file_t file;
+#ifndef EXECDATA_STREAM
+
+ /* Note that if `file_data' (below) is set, then these just point
+ into that and should not be deallocated (file_data is malloc'd). */
+ char *map_buffer; /* Our mapping window or read buffer. */
+ size_t map_vsize; /* Page-aligned size allocated there. */
+ size_t map_fsize; /* Bytes from there to end of mapped data. */
+ off_t map_filepos; /* Position `map_buffer' maps to. */
+#define map_buffer(e) ((e)->map_buffer)
+#define map_fsize(e) ((e)->map_fsize)
+#define map_vsize(e) ((e)->map_vsize)
+#define map_filepos(e) ((e)->map_filepos)
+#define map_set_fsize(e, fsize) ((e)->map_fsize = (fsize))
+
+#else
+
+#ifdef _STDIO_USES_IOSTREAM
+# error implement me for libio!
+#else
+ FILE stream;
+#define map_buffer(e) ((e)->stream.__buffer)
+#define map_fsize(e) ((e)->stream.__get_limit - (e)->stream.__buffer)
+#define map_vsize(e) ((e)->stream.__bufsize)
+#define map_filepos(e) ((e)->stream.__offset)
+#define map_set_fsize(e, fsize) \
+ ((e)->stream.__get_limit = (e)->stream.__buffer + (fsize))
+#endif
+
+#endif
+
#ifdef BFD
bfd *bfd;
#endif
+
union /* Interpreter section giving name of file. */
{
asection *section;
- const Elf32_Phdr *phdr;
+ const ElfW(Phdr) *phdr;
} interp;
memory_object_t filemap, cntlmap;
struct shared_io *cntl;
@@ -108,16 +147,26 @@ struct execdata
/* Program header table read from the executable.
After `check' this is a pointer into the mapping window.
By `load' it is local alloca'd storage. */
- Elf32_Phdr *phdr;
- Elf32_Word phnum; /* Number of program header table elements. */
+ ElfW(Phdr) *phdr;
+ ElfW(Addr) phdr_addr;
+ ElfW(Word) phnum; /* Number of program header table elements. */
int anywhere; /* Nonzero if image can go anywhere. */
vm_address_t loadbase; /* Actual mapping location. */
+ int execstack; /* Zero if stack can be nonexecutable. */
} elf;
} info;
};
+error_t elf_machine_matches_host (ElfW(Half) e_machine);
+
void finish (struct execdata *, int dealloc_file_port);
+/* Make sure our mapping window (or read buffer) covers
+ LEN bytes of the file starting at POSN, and return
+ a pointer into the window corresponding to POSN. */
+void *map (struct execdata *e, off_t posn, size_t len);
+
+
void check_hashbang (struct execdata *e,
file_t file,
task_t oldtask,
diff --git a/ext2fs/ChangeLog b/ext2fs/ChangeLog
deleted file mode 100644
index d8741b9c..00000000
--- a/ext2fs/ChangeLog
+++ /dev/null
@@ -1,588 +0,0 @@
-Fri Aug 2 12:10:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_write_disknode): If WAIT is false, still record
- the write for later, using record_global_poke.
-
-Thu Aug 1 16:18:59 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2_fs.h (ext2_debug_flag): New decl.
- (ext2_debug): Pay attention to EXT2_DEBUG_FLAG.
- * ext2fs.c [EXT2FS_DEBUG] (options, ext2_debug_flag): New variables.
- [EXT2FS_DEBUG] (parse_opt, diskfs_get_options): New functions.
- [EXT2FS_DEBUG] (startup_parents, startup_argp, runtime_parents,
- diskfs_runtime_argp): New variables.
- [!EXT2FS_DEBUG] (startup_argp): New macro.
- (main): Use STARTUP_ARGP instead of DISKFS_STD_DEVICE_STARTUP_ARGP.
- * pager.c (diskfs_grow): Fix ext2_debug format strings.
- * truncate.c (trunc_direct): Fix ext2_debug call.
-
-Sat Jul 20 00:58:44 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.h (struct disknode): Remove debugging info.
- (RECORD_LAST): Function removed.
- (LAST_BUFSZ): Macro removed.
- (enum last_act): Type removed.
- * inode.c (diskfs_cached_lookup): Don't initialize debugging info.
- * pager.c (file_pager_read_page, file_pager_write_page,
- pager_unlock_page, diskfs_grow): Don't record debugging info.
- * truncate.c (diskfs_truncate): Likewise.
-
- * pager.c (file_pager_read_page): Set
- NODE->dn->last_page_partially_writable if we return such a page.
-
-Fri Jul 19 15:02:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pager.c (diskfs_grow): Rename OLD_END_BLOCK to END_BLOCK.
- Correctly determine whether to set DN->last_page_partially_writable
- after allocating new blocks.
-
- * pager.c (file_pager_read_page, file_pager_write_page): Pass
- NODE->dn, not &NODE->dn to RECORD_LAST.
-
-Mon Jul 15 18:00:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.h (struct disknode): Add debugging info.
- (RECORD_LAST): New function.
- (LAST_BUFSZ): New macro.
- (enum last_act): New type.
- * pager.c (pager_unlock_page, diskfs_grow, file_pager_read_page,
- file_pager_write_page): Record debugging info.
- * truncate.c (diskfs_truncate): Likewise.
- * inode.c (diskfs_cached_lookup): Initialize debugging info.
-
- * pager.c (file_pager_read_page): Initialize *WRITELOCK to 0.
-
-Tue Jun 25 12:22:21 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.h (sync_global): Renamed from sync_global_data. Add WAIT
- flag. Don't call diskfs_set_hypermetadata.
- (alloc_sync): Call diskfs_set_hypermetadata instead of sync_global_data.
- (sync_super_block): Function removed.
- * hyper.c (diskfs_readonly_changed): No longer clear the clean bit.
- (diskfs_set_hypermetadata): Work correctly.
- * truncate.c (diskfs_truncate): Add call diskfs_check_readonly to
- clear clean bit.
- * inode.c (diskfs_cached_lookup): Use diskfs_check_readonly
- instead of diskfs_readonly.
- * dir.c (diskfs_lookup_hard, diskfs_dirempty): Likewise.
- * pager.c (diskfs_shutdown_pager): Don't shutdown the disk pager,
- just sync it.
- (diskfs_sync_everything): Call sync_global instead of pokel_sync.
- (final_sblock): Variable removed.
- (diskfs_grow): Add call diskfs_check_readonly to clear clean bit.
-
-Mon Jun 24 17:14:25 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (check_high_bits, diskfs_validate_owner_change,
- diskfs_validate_group_change, diskfs_validate_mode_change,
- diskfs_validate_author_change): New functions.
- (write_node): For non-hurd filesystems, assert that no hurd
- extensions should be used.
-
-Thu Jun 20 22:36:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.c (main): Rename diskfs_device_startup_argp to
- diskfs_std_device_startup_argp.
-
-Sat Jun 15 15:56:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (read_disknode, write_inode): Use hurd-specific fields
- only on a hurd filesystem.
-
-Fri May 10 09:32:43 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_statfs): Fix one reference to old name of ST
- member.
-
-Thu May 9 11:52:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_statfs): Expect and fill in new format
- statfs buffer.
-
- * Makefile (ext2fs ext2fs.static): s/ioserver/iohelp/g.
- * ext2fs.h: ioserver.h -> iohelp.h.
-
-Tue May 7 16:22:56 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (diskfs_S_file_get_storage_info): Rewrite for new
- interface.
-
-Tue Apr 30 12:51:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (targets): Renamed from `target'.
-
-Fri Apr 26 16:10:19 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (makemode): Now `servers'.
- (targets): Renamed from `target'; now include ext2fs.static.
- (ext2fs.static-LDFLAGS): Renamed from `LDFLAGS'.
- (ext2fs.static): Depend on same things as `ext2fs'.
- (include ../Makeconf): Must come before dependency information.
-
-Wed Apr 17 13:30:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_write_disknode): Only sync DI if WAIT.
-
- * dir.c (diskfs_lookup_hard): Set atime appropriately, and sync
- the new atime if we are running synchronously (!).
- (diskfs_dirempty): Likewise.
- (diskfs_direnter_hard): Set mtime appropriately.
- (diskfs_dirremove_hard): Likewise.
- (diskfs_dirrewrite_hard): Likewise.
-
-Thu Apr 4 18:51:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_cached_lookup): Renamed from iget; all uses updated.
- Initialize the CACHE_ID field in the new node.
- * ext2fs.h (struct disknode): Get rid of NUMBER field; all references
- replaced by references to the CACHE_ID field in the corresponding node.
-
-Fri Mar 29 11:03:58 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir.c (diskfs_null_dirstat): New function.
- (diskfs_lookup_hard, diskfs_direnter, diskfs_dirremove_hard,
- diskfs_dirrewrite_hard): Renamed from versions without `_hard' suffix.
- Get rid of stuff now done by diskfs.
-
- * ext2fs.c (main): Pass new argument to argp_parse.
-
-Tue Mar 19 17:52:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pager.c (pager_unlock_page, diskfs_grow): Try to make the logic
- a bit simpler and more robust.
-
-Fri Feb 16 17:05:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.c (main): Check error return from diskfs_init_diskfs.
-
-Tue Feb 6 14:49:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.h (ext2_warning): Make a declaration, not a macro.
- * msg.c (ext2_warning): Rename from _ext2_warning; don't take (or
- print) a function argument any more.
-
- * dir.c (diskfs_get_directs): When BUFSIZ is 0, allocate enough
- extra space over the directory size to account for the worst case
- difference between the ext2 and canonical formats.
-
-Sat Feb 3 11:27:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hyper.c (get_hypermetadata, diskfs_readonly_changed): Use
- ext2_warning to print warnings instead of error().
- * msg.c (_ext2_warning): Include `warning:' in message.
-
-Sat Feb 3 06:10:43 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hyper.c: Fixed handling of the filesystem `clean bit'.
- (ext2fs_clean): New boolean variable.
- (get_hypermetadata): Set it iff the clean bit is set on entry.
- If not clean, complain and force read-only.
- (diskfs_set_hypermetadata): Set clean bit only if ext2fs_clean is set.
- (diskfs_readonly_changed): Complain if going writable and clean
- bit clear.
-
- * ext2fs.c: Include string.h for strerror decl.
-
-Tue Jan 30 22:25:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hyper.c (get_hypermetadata): Don't return any error value, just
- panic if we can't read the superblock.
- * ext2fs.c (main): Move warp_inode() inline. Make sure root inode
- is really there. Don't check return value from get_hypermetadata.
- (warp_inode): Function removed.
- * ext2fs.h (get_hypermetadata): Returns void now.
-
-Tue Jan 30 17:04:41 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * pager.c (file_pager_read_page, file_pager_write_page): Check for
- a page offset beyond the allocsize and return EIO.
-
-Wed Jan 17 15:11:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (diskfs_S_file_get_storage_info): Calculate the
- right value for *RUNS_LEN.
-
-Tue Jan 16 17:37:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pager.c (diskfs_file_update): Ext2fs doesn't require that the
- last block in the file always be allocated, so don't.
- (diskfs_grow, pager_unlock_page): Don't set last_block_allocated.
- * ext2fs.h (struct disknode): Get rid of last_block_allocated field.
- * inode.c (read_disknode): Don't set last_block_allocated.
- * truncate.c (diskfs_truncate): Likewise.
-
- * Makefile (LDFLAGS): Add -static.
-
-Mon Jan 15 10:25:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pager.c (pager_unlock_page, diskfs_grow): Leave things in a
- slightly more consistent state when block allocation errors happen.
-
- * dir.c (diskfs_direnter): Don't include the terminating '\0' in
- on-disk directory entry names.
-
- * inode.c (diskfs_node_norefs): When losing our in-core copy of an
- inode, remember which indirect blocks still have to be written.
- * pokel.c (pokel_inherit, pokel_finalize): New functions.
- * ext2fs.h (pokel_inherit, pokel_finalize): New declarations.
-
- * dir.c (diskfs_lookup): Patch from ufs/dir.c: If we are returning
- an error, then set the dirstat to be ignored by drop_dirstat.
-
-Sun Jan 14 13:17:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ialloc.c (diskfs_alloc_node): Set NP->istranslated to 0.
- * inode.c (write_node): If NP isn't translated, force
- DI->i_translator to 0.
-
- * getblk.c (inode_getblk, block_getblk): Set dn_set_mtime too.
-
-Sat Jan 6 11:57:26 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * pager.c (pager_bucket): Made global.
- (create_disk_pager): Pass MAY_CACHE to disk_pager_setup.
- * ext2fs.c (main): Don't map in disk image here; create_disk_pager
- now does it.
-
-Fri Jan 5 16:57:54 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ext2fs.h: Declare create_disk_pager.
-
-Thu Jan 4 18:46:40 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ext2fs.h (disk_pager, disk_pager_port, disk_image,
- create_disk_pager): Decls removed.
- Include hurd/diskfs-pager.h instead.
-
- * pager.c (create_disk_pager): Use disk_pager_setup.
-
-Tue Nov 14 14:59:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir.c (dirscanblock): Apply mib's changes to ufs/dir.c.
-
-Sat Nov 4 20:01:01 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (diskfs_S_file_get_storage_info): Add FLAGS argument.
-
-Wed Nov 1 20:09:59 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.c (main): Add FLAGS arg to diskfs_startup_diskfs call.
-
-Mon Oct 23 17:49:16 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_get_translator, diskfs_set_translator): Only
- support these if the filesystem's creator-os is `hurd'.
- (read_disknode): Only check the i_translator field if the
- filesystem's creator-os is `hurd'.
-
-Fri Oct 20 19:18:16 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.h (MS_RDONLY, MS_NOSUID, MS_NODEV, MS_NOEXEC,
- MS_SYNCHRONOUS, MS_REMOUNT, S_APPEND, S_IMMUTABLE, IS_APPEND,
- IS_IMMUTABLE): Macros deleted.
-
-Thu Oct 19 19:15:15 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pager.c (create_disk_pager, diskfs_get_filemap,
- pager_clear_user_data): Don't use the p field in a upi.
- (diskfs_get_filemap): Update/initialize the max_prot field.
- Add the prot arg.
-
- * ext2fs.h (struct user_pager_info): Add max_prot field, remove p.
- * pager.c (drop_pager_softrefs): Declare PAGER, not UPI.
- (enable_caching): The disk node is upi->node, not upi->np.
- (diskfs_enable_pagers): Function removed.
- * inode.c (read_disknode): Add DN and OFFSET variables. Use
- log2_block_size to mask instead of doing a modulo with block_size.
- * hyper.c (diskfs_readonly_changed): Typo.
- (allocate_mod_map): Declare ERR; OLD_MOD_MAP_SIZE --> MOD_MAP_SIZE.
- * dir.c (diskfs_lookup, diskfs_dirempty): Give diskfs_get_filemap
- a protection arg.
- * truncate.c (force_delayed_copies): Ditto.
-
-Wed Oct 18 21:00:28 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.h (struct disknode): Replace fileinfo field with pager.
- * inode.c (diskfs_node_norefs, iget): Use pager field, not fileinfo.
- * pager.c (diskfs_get_filemap_pager_struct, flush_node_pager,
- diskfs_file_update, pager_clear_user_data, drop_pager_softrefs): Ditto.
- * truncate.c (enable_delayed_copies, force_delayed_copies): Ditto.
-
- * ext2fs.c (main): Always include VM_PROT_WRITE in max prot.
- * hyper.c (diskfs_readonly_changed): Change the protection of
- DISK_IMAGE to reflect the new state.
- * pager.c (diskfs_enable_pagers): New function.
-
-Tue Oct 17 21:16:04 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pokel.c (_pokel_exec, pokel_flush): New functions.
- (pokel_sync): Use _pokel_exec to do the work.
- * pager.c (flush_node_pager): New function.
- * ext2fs.h (pokel_flush, flush_node_pager): New declarations.
-
- * hyper.c (allocate_mod_map): New function (from get_hypermetadata).
- (zeroblock, modified_global_blocks): Define (were common).
- (get_hypermetadata): Deallocate ZEROBLOCK if necessary. Use
- allocate_mod_map to allocate MODIFIED_GLOBAL_BLOCKS.
- (diskfs_readonly_changed): New function.
- * main.c (main): Move stuff into get_hypermetadata.
- Writable init code moved to diskfs_readonly_changed.
-
- * inode.c (diskfs_node_reload): New function.
- (iget, read_disknode): Code to set allocsize and the last_* fields
- moved from iget to read_disknode.
-
- * ext2fs.h (disk_pager): Type changed to struct pager.
- (sync_global_ptr): Use DISK_PAGER, not DISK_PAGER->p.
- * pager.c (create_disk_pager): Store the actual pager into DISK_PAGER.
- * ext2fs.c (main): Use DISK_PAGER directly, not ->p.
- * inode.c (iget): Ditto.
- * pager.c (diskfs_shutdown_pager, diskfs_sync_everything): Ditto.
-
-Mon Oct 16 15:23:25 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_lost_hardrefs): #ifdef'd out contents removed.
-
-Fri Oct 13 17:50:23 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.c (main): Use argp for parsing.
- (usage, USAGE, SHORT_OPTS, long_opts, console_stdio): Removed
-
-Thu Oct 12 18:16:00 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * hyper.c (get_hypermetadata): Use diskfs device functions &
- variables instead of our own.
- * ext2fs.h (device_arg, device_name, device_port, device_start,
- device_size, device_block_size): Declarations removed.
-
- * ext2fs.c (printf, _ext2_error, _ext2_panic, _ext2_warning):
- Functions moved to msg.c
- * msg.c: New file.
- (printf, _ext2_error, _ext2_panic, _ext2_warning): Funcs from ext2fs.c.
- * Makefile (SRCS): Remove devio.c, add msg.c.
-
-Sat Oct 7 20:47:19 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (diskfs_S_file_get_storage_info): run_elem_t --> off_t.
-
- * ext2fs.c (diskfs_init_completed): Func deleted (now in libdiskfs).
-
-Fri Oct 6 17:24:57 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (diskfs_S_file_get_storage_info): Change type of
- ADDRESSES to off_t **, and add BLOCK_SIZE parameter.
-
-Wed Oct 4 20:02:34 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_statfs): fsys_stb_bsize -> fsys_stb_iosize.
- fsys_stb_fsize -> fsys_stb_bsize.
-
-Wed Sep 27 20:07:53 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ext2fs.c (main): Use diskfs routines to open the device.
- Support both file and mach devices. Move the parse function here.
- (parse_opt): Move into main (as a nested function).
- * ext2fs.h (device_arg, device_start): New declarations.
- * devio.c (dev_read_sync, dev_write_sync): Offset the address to
- which we're doing i/o with DEVICE_START.
-
-Tue Sep 26 18:39:58 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (diskfs_S_file_get_storage_info): New function.
- * Makefile (SRCS): Add storeinfo.c.
-
-Fri Sep 15 14:21:18 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * truncate.c (trunc_indirect): Only record an indirect block as
- being modified when it actually is.
-
- * truncate.c (diskfs_truncate): Use the new truncate functions.
- (poke_pages): Gratuitous cosmetic changes.
- (trunc_direct): Rewritten, new args.
- (trunc_indirect): Rewritten, new args, now more general to support
- all the various indirection levels.
- (trunc_triple_indirect, trunc_double_indirect,
- trunc_single_indirect): New functions.
- (struct free_block_run): New structure.
- (free_block_run_finish, free_block_run_free_ptr,
- free_block_run_add, free_block_run_init, _free_block_run_flush):
- New functions.
- (trunc_dindirect, trunc_tindirect): Functions deleted.
- (DIRECT_BLOCK, INDIRECT_BLOCK, DINDIRECT_BLOCK, TINDIRECT_BLOCK):
- Macros deleted.
-
- * getblk.c (block_getblk, ext2_getblk): u32 --> block_t.
- * balloc.c (ext2_new_block): Ditto.
- * hyper.c (get_hypermetadata): Ditto.
- * pager.c (file_pager_write_page): Ditto.
-
-Wed Sep 13 12:30:23 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.c (diskfs_lookup): Don't attempt to lock NP if NPP is not
- set. Don't even set NP if NPP is not set; use INUM as "lookup
- succeeded flag" instead. Lookups for REMOVE and RENAME now *must*
- set NPP.
-
-Tue Sep 12 11:03:19 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pokel.c (pokel_init): Initialize the free_pokes field.
- (pokel_add): Assert that this malloc should succeed.
- (pokel_sync): Don't hold POKEL's spin lock while syncing.
-
- * ialloc.c (diskfs_alloc_node): Check for a non-zero ALLOCSIZE.
-
-Tue Sep 5 16:59:40 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pager.c (diskfs_pager_users): Ignore the disk pager when seeing
- if there are any active pagers.
- (diskfs_shutdown_pager): shutdown_one gets passed a pager, not a upi.
- (diskfs_sync_everything): sync_one gets passed a pager, not a upi.
-
-Sun Sep 3 17:28:13 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ext2fs.c (thread_cancel): Removed.
-
-Fri Aug 25 14:37:32 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (ext2fs): Put libports in the right place in the
- linking order.
-
-Thu Aug 24 10:34:15 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (ext2fs): Put all dependencies here.
- (HURDLIBS): Removed.
-
-Tue Aug 22 19:39:06 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Add libshouldbeinlibc.
- Remove rules for error.o.
-
-Fri Jul 21 17:51:33 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * pager.c (diskfs_get_filemap): Free initial reference created by
- pager_create.
-
- * pager.c (diskfs_get_filemap): Avoid race with simultaneous
- termination by looping until we win.
- (pager_clear_user_data): Only clear UPI->np->dn->fileinfo if it
- still points to us.
-
-Thu Jul 6 15:33:24 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Thu Jul 6 13:36:25 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * pager.c (diskfs_pager_users): New function.
-
-Tue Jun 27 13:08:33 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * pager.c (pager_unlock_page): Declare BLOCK volatile.
-
-Sat Jun 24 17:59:36 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Add libihash.
-
- * ext2fs.c (thread_cancel): Dummy function.
-
- * dir.c (diskfs_direnter): Move assignment out of test.
- (diskfs_get_directs): Fix print-format types.
- * ialloc.c (diskfs_free_node): Fix print-format types.
-
- * pager.c (thread_function): New function.
- (create_disk_pager): Make a new thread to service paging requests.
- * ext2fs.c (main): Have the initial thread die when it's done, leaving
- other thread to do the work.
-
- * pager.c (pager_bucket): New variable.
- (pager_list_lock, file_pager_list): Variables deleted.
- (create_disk_pager): Create pager_bucket.
- (create_disk_pager, diskfs_get_filemap): Pass pager_bucket to
- pager_create.
- (pager_traverse): Function deleted.
- (diskfs_get_filemap, pager_clear_user_data): Don't add/remove UPI
- to/from the pager list, as there isn't any.
- (diskfs_shutdown_pager, diskfs_sync_everything): Use
- ports_bucket_iterate on pager_bucket to go through all the pagers,
- instead of pager_traverse.
- (diskfs_file_update, pager_traverse, allow_pager_softrefs,
- drop_pager_softrefs): Change pager [un]ref calls to use the new ports
- ref calls directly instead.
- (pager_dropweak): New function (does nothing).
- * ext2fs.h (struct user_pager_info): Remove the next & prevp fields.
-
- * truncate.c (force_delayed_copies, enable_delayed_copies): Change
- pager [un]ref calls to use the new ports ref calls directly instead.
- * inode.c (diskfs_lost_hardrefs): Ditto.
-
- * inode.c (diskfs_node_iterate): New function.
- (write_all_disknodes): Re-implemented using diskfs_node_iterate.
-
-Wed Jun 14 16:19:49 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * inode.c (diskfs_get_translator): Conform to new memory usage
- semantic.
-
-Fri May 19 20:56:51 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ext2fs.c (main): Use options_parse & diskfs_standard_startup_options
- to do command line options parsing.
- (long_opts): Was `options'. Most things removed, as
- they're now handled by libdiskfs.
- (parse_opt): New routine to deal with our few meagre remaining
- options in the approved options_parse manner.
-
-Mon May 15 15:55:49 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ext2fs.c (main, usage, options): Add --writable & --nosync options.
-
-Sat May 13 20:04:55 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_statfs): Set st->fsys_stb_bsize, not _fsize,
- to the block size.
-
-Sat May 13 05:02:59 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Remove exec_server_image.o.
- (exec_server_image.o): Rule removed.
-
-Fri May 12 15:23:02 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ext2fs.c (main): Add an optional argument to the --sync option
- that lets the user specify an initial sync interval.
-
-Thu May 11 13:30:06 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pager.c (pager_unlock_page): Give an explanation of why the file
- system will shortly crash.
-
- * balloc.c (ext2_free_blocks, ext2_new_block): Get rid of the
- CHECK_STRICT variable, and just always do the tests it controlled.
- * ext2fs.h: Get rid of the CHECK_STRICT variable.
-
- * ext2fs.h (ext2_error, ext2_warning, ext2_panic, all callers changed):
- Make these into macros that automagically supply the caller's
- function name, and rename the original functions (which these
- macros call) to have an underline prefix.
- * ext2fs.c (ext2_error, ext2_warning, ext2_panic): Rename to add
- the underline prefix. Also rearrange a bit to hold the lock
- around the use of the global message buffer.
-
- * ext2fs.c (main): Enable the bootstrap code.
-
- * inode.c (read_disknode): Make st_blksize larger: 2 * pagesize.
-
-Wed May 10 14:03:34 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * getblk.c (block_getblk, inode_getblk): Return ENOSPC instead of
- EIO when we can't allocate a new block.
-
- * bitmap.c (find_next_zero_bit): Fix stupid typos (present in the
- original linux source I copied this function from!) which were
- causing occasional garbage results.
-
-Tue May 9 18:08:41 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ext2fs.h (DONT_CACHE_MEMORY_OBJECTS): Don't define this any
- more, as the bugs we were using it to catch are supposedly gone :-|
diff --git a/ext2fs/Makefile b/ext2fs/Makefile
index 0c4d3467..e83aab26 100644
--- a/ext2fs/Makefile
+++ b/ext2fs/Makefile
@@ -1,6 +1,6 @@
# Makefile for ext2fs
#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1994,95,96,99,2000,02 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
@@ -17,17 +17,15 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
dir := ext2fs
-makemode := servers
+makemode := server
-targets = ext2fs ext2fs.static
-SRCS = balloc.c bitmap.c dir.c ext2fs.c getblk.c hyper.c ialloc.c \
- inode.c pager.c pokel.c truncate.c storeinfo.c msg.c
+target = ext2fs
+SRCS = balloc.c dir.c ext2fs.c getblk.c hyper.c ialloc.c \
+ inode.c pager.c pokel.c truncate.c storeinfo.c msg.c xinl.c
OBJS = $(SRCS:.c=.o)
-LCLHDRS = ext2fs.h ext2_fs.h ext2_fs_i.h
-
-ext2fs.static-LDFLAGS += -static
+LCLHDRS = ext2fs.h ext2_fs.h ext2_fs_i.h bitmap.c
+HURDLIBS = diskfs pager iohelp fshelp store threads ports ihash shouldbeinlibc
include ../Makeconf
-ext2fs ext2fs.static: $(OBJS) ../libdiskfs/libdiskfs.a ../libpager/libpager.a ../libiohelp/libiohelp.a ../libfshelp/libfshelp.a ../libports/libports.a ../libthreads/libthreads.a ../libihash/libihash.a ../libshouldbeinlibc/libshouldbeinlibc.a
-
+ext2fs.static: $(boot-store-types:%=../libstore/libstore_%.a)
diff --git a/ext2fs/balloc.c b/ext2fs/balloc.c
index 9c47b742..7333123c 100644
--- a/ext2fs/balloc.c
+++ b/ext2fs/balloc.c
@@ -1,8 +1,8 @@
/* Block allocation routines
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995,99,2000 Free Software Foundation, Inc.
- Converted to work under the hurd by Miles Bader <miles@gnu.ai.mit.edu>
+ Converted to work under the hurd by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -42,10 +42,19 @@
#include <string.h>
#include "ext2fs.h"
+#include "bitmap.c"
+
+/* Returns a pointer to the first occurrence of CH in the buffer BUF of len
+ LEN, or BUF + LEN if CH doesn't occur. */
+static inline void *
+memscan (void *buf, unsigned char ch, size_t len)
+{
+ return memchr (buf, ch, len) ?: buf + len;
+}
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
-void
+void
ext2_free_blocks (block_t block, unsigned long count)
{
char *bh;
@@ -60,44 +69,57 @@ ext2_free_blocks (block_t block, unsigned long count)
(block + count) > sblock->s_blocks_count)
{
ext2_error ("freeing blocks not in datazone - "
- "block = %lu, count = %lu", block, count);
+ "block = %u, count = %lu", block, count);
spin_unlock (&global_lock);
return;
}
- ext2_debug ("freeing block %lu[%lu]", block, count);
+ ext2_debug ("freeing block %u[%lu]", block, count);
- block_group = (block - sblock->s_first_data_block) /
- sblock->s_blocks_per_group;
- bit = (block - sblock->s_first_data_block) % sblock->s_blocks_per_group;
- if (bit + count > sblock->s_blocks_per_group)
- ext2_panic ("freeing blocks across group boundary - "
- "block = %lu, count = %lu",
- block, count);
- gdp = group_desc (block_group);
- bh = bptr (gdp->bg_block_bitmap);
+ do
+ {
+ unsigned long int gcount = count;
+
+ block_group = ((block - sblock->s_first_data_block)
+ / sblock->s_blocks_per_group);
+ bit = (block - sblock->s_first_data_block) % sblock->s_blocks_per_group;
+ if (bit + count > sblock->s_blocks_per_group)
+ {
+ unsigned long overflow = bit + count - sblock->s_blocks_per_group;
+ gcount -= overflow;
+ ext2_debug ("freeing blocks across group boundary - "
+ "block = %u, count = %lu",
+ block, count);
+ }
+ gdp = group_desc (block_group);
+ bh = bptr (gdp->bg_block_bitmap);
- if (in_range (gdp->bg_block_bitmap, block, count) ||
- in_range (gdp->bg_inode_bitmap, block, count) ||
- in_range (block, gdp->bg_inode_table, itb_per_group) ||
- in_range (block + count - 1, gdp->bg_inode_table, itb_per_group))
- ext2_panic ("freeing blocks in system zones - "
- "block = %lu, count = %lu",
- block, count);
+ if (in_range (gdp->bg_block_bitmap, block, gcount) ||
+ in_range (gdp->bg_inode_bitmap, block, gcount) ||
+ in_range (block, gdp->bg_inode_table, itb_per_group) ||
+ in_range (block + gcount - 1, gdp->bg_inode_table, itb_per_group))
+ ext2_panic ("freeing blocks in system zones - "
+ "block = %u, count = %lu",
+ block, count);
- for (i = 0; i < count; i++)
- {
- if (!clear_bit (bit + i, bh))
- ext2_warning ("bit already cleared for block %lu", block + i);
- else
+ for (i = 0; i < gcount; i++)
{
- gdp->bg_free_blocks_count++;
- sblock->s_free_blocks_count++;
+ if (!clear_bit (bit + i, bh))
+ ext2_warning ("bit already cleared for block %lu", block + i);
+ else
+ {
+ gdp->bg_free_blocks_count++;
+ sblock->s_free_blocks_count++;
+ }
}
- }
- record_global_poke (bh);
- record_global_poke (gdp);
+ record_global_poke (bh);
+ record_global_poke (gdp);
+
+ block += gcount;
+ count -= gcount;
+ } while (count > 0);
+
sblock_dirty = 1;
spin_unlock (&global_lock);
@@ -108,12 +130,14 @@ ext2_free_blocks (block_t block, unsigned long count)
/*
* ext2_new_block uses a goal block to assist allocation. If the goal is
* free, or there is a free block within 32 blocks of the goal, that block
- * is allocated. Otherwise a forward search is made for a free block; within
+ * is allocated. Otherwise a forward search is made for a free block; within
* each block group the search first looks for an entire free byte in the block
* bitmap, and then for any free bit if that fails.
*/
block_t
-ext2_new_block (block_t goal, block_t *prealloc_count, block_t *prealloc_block)
+ext2_new_block (block_t goal,
+ block_t prealloc_goal,
+ block_t *prealloc_count, block_t *prealloc_block)
{
char *bh;
char *p, *r;
@@ -138,7 +162,7 @@ ext2_new_block (block_t goal, block_t *prealloc_count, block_t *prealloc_block)
}
#endif
- ext2_debug ("goal=%lu", goal);
+ ext2_debug ("goal=%u", goal);
repeat:
/*
@@ -170,7 +194,7 @@ repeat:
if (j)
{
/*
- * The goal was occupied; search forward for a free
+ * The goal was occupied; search forward for a free
* block within the next 32 blocks
*/
lmap = ((((unsigned long *) bh)[j >> 5]) >>
@@ -198,7 +222,7 @@ repeat:
* of the goal: do a search forward through the block groups,
* searching in each group first for an entire free byte in
* the bitmap and then for any free bit.
- *
+ *
* Search first in the remainder of the current group; then,
* cyclicly search through the rest of the groups.
*/
@@ -223,7 +247,7 @@ repeat:
ext2_debug ("bit not found in block group %d", i);
/*
- * Now search the rest of the groups. We assume that
+ * 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++)
@@ -256,7 +280,7 @@ repeat:
}
search_back:
- /*
+ /*
* 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.
@@ -296,12 +320,12 @@ got_block:
* Do block preallocation now if required.
*/
#ifdef EXT2_PREALLOCATE
- if (prealloc_block)
+ if (prealloc_goal)
{
*prealloc_count = 0;
*prealloc_block = tmp + 1;
for (k = 1;
- k < 8 && (j + k) < sblock->s_blocks_per_group; k++)
+ k < prealloc_goal && (j + k) < sblock->s_blocks_per_group; k++)
{
if (set_bit (j + k, bh))
break;
@@ -317,7 +341,7 @@ got_block:
}
gdp->bg_free_blocks_count -= *prealloc_count;
sblock->s_free_blocks_count -= *prealloc_count;
- ext2_debug ("preallocated a further %lu bits", *prealloc_count);
+ ext2_debug ("preallocated a further %u bits", *prealloc_count);
}
#endif
@@ -348,7 +372,7 @@ got_block:
return j;
}
-unsigned long
+unsigned long
ext2_count_free_blocks ()
{
#ifdef EXT2FS_DEBUG
@@ -370,7 +394,7 @@ ext2_count_free_blocks ()
i, gdp->bg_free_blocks_count, x);
bitmap_count += x;
}
- printf ("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu",
+ printf ("ext2_count_free_blocks: stored = %u, computed = %lu, %lu",
sblock->s_free_blocks_count, desc_count, bitmap_count);
spin_unlock (&global_lock);
return bitmap_count;
@@ -379,14 +403,14 @@ ext2_count_free_blocks ()
#endif
}
-static inline int
+static inline int
block_in_use (block_t block, unsigned char *map)
{
return test_bit ((block - sblock->s_first_data_block) %
sblock->s_blocks_per_group, map);
}
-void
+void
ext2_check_blocks_bitmap ()
{
char *bh;
@@ -405,16 +429,41 @@ ext2_check_blocks_bitmap ()
for (i = 0; i < groups_count; i++)
{
+ inline int test_root (int a, int b)
+ {
+ if (a == 0)
+ return 1;
+ while (1)
+ {
+ if (a == 1)
+ return 1;
+ if (a % b)
+ return 0;
+ a = a / b;
+ }
+ }
+ inline int ext2_group_sparse (int group)
+ {
+ return (test_root (group, 3) || test_root (group, 5)
+ || test_root (group, 7));
+ }
+
gdp = group_desc (i);
desc_count += gdp->bg_free_blocks_count;
bh = bptr (gdp->bg_block_bitmap);
- if (!test_bit (0, bh))
- ext2_error ("superblock in group %d is marked free", i);
+ if (!EXT2_HAS_RO_COMPAT_FEATURE (sblock,
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+ || ext2_group_sparse (i))
+ {
+ if (!test_bit (0, bh))
+ ext2_error ("superblock in group %d is marked free", i);
- for (j = 0; j < desc_blocks; j++)
- if (!test_bit (j + 1, bh))
- ext2_error ("descriptor block #%d in group %d is marked free", j, i);
+ for (j = 0; j < desc_blocks; j++)
+ if (!test_bit (j + 1, bh))
+ ext2_error ("descriptor block #%d in group %d is marked free",
+ j, i);
+ }
if (!block_in_use (gdp->bg_block_bitmap, bh))
ext2_error ("block bitmap for group %d is marked free", i);
diff --git a/ext2fs/bitmap.c b/ext2fs/bitmap.c
index a983cab9..e512d011 100644
--- a/ext2fs/bitmap.c
+++ b/ext2fs/bitmap.c
@@ -18,6 +18,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define ffz(word) (ffs (~(unsigned int) (word)) - 1)
+
/*
* linux/fs/ext2/bitmap.c (&c)
*
@@ -29,12 +31,13 @@
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
+static inline
unsigned long count_free (char * map, unsigned int numchars)
{
unsigned int i;
unsigned long sum = 0;
-
- if (!map)
+
+ if (!map)
return (0);
for (i = 0; i < numchars; i++)
sum += nibblemap[map[i] & 0xf] +
@@ -44,31 +47,6 @@ unsigned long count_free (char * map, unsigned int numchars)
/* ---------------------------------------------------------------- */
-static int ffz_nibble_map[] = {0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4};
-
-inline unsigned long ffz(unsigned long word)
-{
- int offset = 0;
- if ((word & 0xFFFF) == 0xFFFF)
- {
- word >>= 16;
- offset += 16;
- }
- if ((word & 0xFF) == 0xFF)
- {
- word >>= 8;
- offset += 8;
- }
- if ((word & 0xF) == 0xF)
- {
- word >>= 4;
- offset += 4;
- }
- return ffz_nibble_map[word & 0xF] + offset;
-}
-
-/* ---------------------------------------------------------------- */
-
/*
* Copyright 1994, David S. Miller (davem@caip.rutgers.edu).
*/
@@ -78,7 +56,7 @@ inline unsigned long ffz(unsigned long word)
* on Linus's ALPHA routines, which are pretty portable BTW.
*/
-inline unsigned long
+static inline unsigned long
find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
@@ -89,7 +67,7 @@ find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
return size;
size -= result;
offset &= 31UL;
- if (offset)
+ if (offset)
{
tmp = *(p++);
tmp |= ~0UL >> (32-offset);
@@ -100,7 +78,7 @@ find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
size -= 32;
result += 32;
}
- while (size & ~31UL)
+ while (size & ~31UL)
{
if (~(tmp = *(p++)))
goto found_middle;
@@ -121,23 +99,8 @@ found_middle:
* holds on the Sparc as it does for the ALPHA.
*/
-inline int
+static inline int
find_first_zero_bit(void *buf, unsigned len)
{
return find_next_zero_bit(buf, len, 0);
}
-
-/* ---------------------------------------------------------------- */
-
-/* Returns a pointer to the first occurence of CH in the buffer BUF of len
- LEN, or BUF + LEN if CH doesn't occur. */
-void *memscan(void *buf, unsigned char ch, unsigned len)
-{
- unsigned char *p = (unsigned char *)buf;
- while (len-- > 0)
- if (*p == ch)
- break;
- else
- p++;
- return (void *)p;
-}
diff --git a/ext2fs/devio.c b/ext2fs/devio.c
deleted file mode 100644
index 3e97fcb6..00000000
--- a/ext2fs/devio.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Device input and output
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Written by Michael I. Bushnell. */
-
-#include "ext2fs.h"
-#include <device/device.h>
-#include <device/device_request.h>
-
-/* Write disk block ADDR with DATA of LEN bytes, waiting for completion. */
-error_t
-dev_write_sync (block_t addr, vm_address_t data, long len)
-{
- int written;
- assert (!diskfs_readonly);
- if (device_write (device_port, 0, device_start + addr,
- (io_buf_ptr_t) data, len, &written)
- || written != len)
- return EIO;
- return 0;
-}
-
-/* Read disk block ADDR; put the address of the data in DATA; read LEN
- bytes. Always *DATA should be a full page no matter what. */
-error_t
-dev_read_sync (block_t addr, vm_address_t *data, long len)
-{
- u_int read;
- if (device_read (device_port, 0, device_start + addr, len,
- (io_buf_ptr_t *)data, &read)
- || read != len)
- return EIO;
- return 0;
-}
-
diff --git a/ext2fs/dir.c b/ext2fs/dir.c
index 36fcfd58..d70dbf32 100644
--- a/ext2fs/dir.c
+++ b/ext2fs/dir.c
@@ -1,8 +1,9 @@
/* Directory management routines
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2007
+ Free Software Foundation, Inc.
- Converted for ext2fs by Miles Bader <miles@gnu.ai.mit.edu>
+ Converted for ext2fs by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -72,39 +73,66 @@ struct dirstat
/* Index of this directory block. */
int idx;
-
- /* For stat COMPRESS, this is the address (inside mapbuf)
+
+ /* For stat COMPRESS, this is the address (inside mapbuf)
of the first direct in the directory block to be compressed. */
/* For stat HERE_TIS, SHRINK, and TAKE, this is the entry referenced. */
- struct ext2_dir_entry *entry;
+ struct ext2_dir_entry_2 *entry;
/* For stat HERE_TIS, type REMOVE, this is the address of the immediately
previous direct in this directory block, or zero if this is the first. */
- struct ext2_dir_entry *preventry;
+ struct ext2_dir_entry_2 *preventry;
/* For stat COMPRESS, this is the number of bytes needed to be copied
in order to undertake the compression. */
size_t nbytes;
};
-size_t diskfs_dirstat_size = sizeof (struct dirstat);
+const size_t diskfs_dirstat_size = sizeof (struct dirstat);
/* Initialize DS such that diskfs_drop_dirstat will ignore it. */
-void
+void
diskfs_null_dirstat (struct dirstat *ds)
{
ds->type = LOOKUP;
}
-static error_t
-dirscanblock (vm_address_t blockoff, struct node *dp, int idx, char *name,
- int namelen, enum lookup_type type, struct dirstat *ds,
- ino_t *inum);
+static error_t
+dirscanblock (vm_address_t blockoff, struct node *dp, int idx,
+ const char *name, int namelen, enum lookup_type type,
+ struct dirstat *ds, ino_t *inum);
+
+#if 0 /* XXX unused for now */
+static const unsigned char ext2_file_type[EXT2_FT_MAX] =
+{
+ [EXT2_FT_UNKNOWN] = DT_UNKNOWN,
+ [EXT2_FT_REG_FILE] = DT_REG,
+ [EXT2_FT_DIR] = DT_DIR,
+ [EXT2_FT_CHRDEV] = DT_CHR,
+ [EXT2_FT_BLKDEV] = DT_BLK,
+ [EXT2_FT_FIFO] = DT_FIFO,
+ [EXT2_FT_SOCK] = DT_SOCK,
+ [EXT2_FT_SYMLINK] = DT_LNK,
+};
+
+static const unsigned char file_type_ext2[] =
+{
+ [DT_UNKNOWN] = EXT2_FT_UNKNOWN,
+ [DT_REG] = EXT2_FT_REG_FILE,
+ [DT_DIR] = EXT2_FT_DIR,
+ [DT_CHR] = EXT2_FT_CHRDEV,
+ [DT_BLK] = EXT2_FT_BLKDEV,
+ [DT_FIFO] = EXT2_FT_FIFO,
+ [DT_SOCK] = EXT2_FT_SOCK,
+ [DT_LNK] = EXT2_FT_SYMLINK,
+};
+#endif
+
/* Implement the diskfs_lookup from the diskfs library. See
<hurd/diskfs.h> for the interface specification. */
error_t
-diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
+diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type,
struct node **npp, struct dirstat *ds, struct protid *cred)
{
error_t err;
@@ -119,8 +147,9 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
vm_address_t buf = 0;
vm_size_t buflen = 0;
int blockaddr;
- int idx;
-
+ int idx, lastidx;
+ int looped;
+
if ((type == REMOVE) || (type == RENAME))
assert (npp);
@@ -129,12 +158,16 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
spec_dotdot = type & SPEC_DOTDOT;
type &= ~SPEC_DOTDOT;
-
+
namelen = strlen (name);
if (namelen > EXT2_NAME_LEN)
- return ENAMETOOLONG;
-
+ {
+ if (ds)
+ diskfs_null_dirstat (ds);
+ return ENAMETOOLONG;
+ }
+
try_again:
if (ds)
{
@@ -144,7 +177,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
}
if (buf)
{
- vm_deallocate (mach_task_self (), buf, buflen);
+ munmap ((caddr_t) buf, buflen);
buf = 0;
}
if (ds && (type == CREATE || type == RENAME))
@@ -152,6 +185,10 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
/* Map in the directory contents. */
memobj = diskfs_get_filemap (dp, prot);
+
+ if (memobj == MACH_PORT_NULL)
+ return errno;
+
buf = 0;
/* We allow extra space in case we have to do an EXTEND. */
buflen = round_page (dp->dn_stat.st_size + DIRBLKSIZ);
@@ -160,26 +197,45 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
mach_port_deallocate (mach_task_self (), memobj);
inum = 0;
-
- if (!diskfs_check_readonly ())
- dp->dn_set_atime = 1;
-
- for (blockaddr = buf, idx = 0;
- blockaddr - buf < dp->dn_stat.st_size;
- blockaddr += DIRBLKSIZ, idx++)
+
+ diskfs_set_node_atime (dp);
+
+ /* Start the lookup at DP->dn->dir_idx. */
+ idx = dp->dn->dir_idx;
+ if (idx * DIRBLKSIZ > dp->dn_stat.st_size)
+ idx = 0; /* just in case */
+ blockaddr = buf + idx * DIRBLKSIZ;
+ looped = (idx == 0);
+ lastidx = idx;
+ if (lastidx == 0)
+ lastidx = dp->dn_stat.st_size / DIRBLKSIZ;
+
+ while (!looped || idx < lastidx)
{
err = dirscanblock (blockaddr, dp, idx, name, namelen, type, ds, &inum);
if (!err)
- break;
+ {
+ dp->dn->dir_idx = idx;
+ break;
+ }
if (err != ENOENT)
{
- vm_deallocate (mach_task_self (), buf, buflen);
+ munmap ((caddr_t) buf, buflen);
return err;
}
+
+ blockaddr += DIRBLKSIZ;
+ idx++;
+ if (blockaddr - buf >= dp->dn_stat.st_size && !looped)
+ {
+ /* We've gotten to the end; start back at the beginning */
+ looped = 1;
+ blockaddr = buf;
+ idx = 0;
+ }
}
- if (!diskfs_check_readonly ())
- dp->dn_set_atime = 1;
+ diskfs_set_node_atime (dp);
if (diskfs_synchronous)
diskfs_node_update (dp, 1);
@@ -203,7 +259,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
goto out;
}
}
-
+
/* We are looking up .. */
/* Check to see if this is the root of the filesystem. */
else if (dp->cache_id == 2)
@@ -211,7 +267,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
err = EAGAIN;
goto out;
}
-
+
/* We can't just do diskfs_cached_lookup, because we would then deadlock.
So we do this. Ick. */
else if (retry_dotdot)
@@ -245,11 +301,11 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
retry_dotdot = inum;
goto try_again;
}
-
+
/* Here below are the spec dotdot cases. */
else if (type == RENAME || type == REMOVE)
np = ifind (inum);
-
+
else if (type == LOOKUP)
{
diskfs_nput (dp);
@@ -260,13 +316,13 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
else
assert (0);
}
-
+
if ((type == CREATE || type == RENAME) && !inum && ds && ds->stat == LOOKING)
{
/* We didn't find any room, so mark ds to extend the dir */
ds->type = CREATE;
ds->stat = EXTEND;
- ds->idx = idx;
+ ds->idx = dp->dn_stat.st_size / DIRBLKSIZ;
}
/* Return to the user; if we can't, release the reference
@@ -277,7 +333,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
|| !ds
|| ds->type == LOOKUP)
{
- vm_deallocate (mach_task_self (), buf, buflen);
+ munmap ((caddr_t) buf, buflen);
if (ds)
ds->type = LOOKUP; /* set to be ignored by drop_dirstat */
}
@@ -286,7 +342,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
ds->mapbuf = buf;
ds->mapextent = buflen;
}
-
+
if (np)
{
assert (npp);
@@ -320,20 +376,20 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
diskfs_lookup. If found, set *INUM to the inode number, else
return ENOENT. */
static error_t
-dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
- int namelen, enum lookup_type type,
+dirscanblock (vm_address_t blockaddr, struct node *dp, int idx,
+ const char *name, int namelen, enum lookup_type type,
struct dirstat *ds, ino_t *inum)
{
int nfree = 0;
int needed = 0;
vm_address_t currentoff, prevoff;
- struct ext2_dir_entry *entry = 0;
+ struct ext2_dir_entry_2 *entry = 0;
int nentries = 0;
size_t nbytes = 0;
int looking = 0;
int countcopies = 0;
int consider_compress = 0;
-
+
if (ds && (ds->stat == LOOKING
|| ds->stat == COMPRESS))
{
@@ -346,8 +402,8 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
currentoff < blockaddr + DIRBLKSIZ;
prevoff = currentoff, currentoff += entry->rec_len)
{
- entry = (struct ext2_dir_entry *)currentoff;
-
+ entry = (struct ext2_dir_entry_2 *)currentoff;
+
if (!entry->rec_len
|| entry->rec_len % EXT2_DIR_PAD
|| entry->name_len > EXT2_NAME_LEN
@@ -355,16 +411,16 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
|| EXT2_DIR_REC_LEN (entry->name_len) > entry->rec_len
|| memchr (entry->name, '\0', entry->name_len))
{
- ext2_warning ("bad directory entry: inode: %d offset: %ld",
+ ext2_warning ("bad directory entry: inode: %Ld offset: %zd",
dp->cache_id,
currentoff - blockaddr + idx * DIRBLKSIZ);
return ENOENT;
}
-
+
if (looking || countcopies)
{
int thisfree;
-
+
/* Count how much free space this entry has in it. */
if (entry->inode == 0)
thisfree = entry->rec_len;
@@ -376,9 +432,9 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
number of bytes there too. */
if (countcopies && currentoff != blockaddr)
nbytes += EXT2_DIR_REC_LEN (entry->name_len);
-
+
if (ds->stat == COMPRESS && nbytes > ds->nbytes)
- /* The previously found compress is better than
+ /* The previously found compress is better than
this one, so don't bother counting any more. */
countcopies = 0;
@@ -395,9 +451,9 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
nfree += thisfree;
if (nfree >= needed)
consider_compress = 1;
- }
+ }
}
-
+
if (entry->inode)
nentries++;
@@ -408,17 +464,17 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
break;
}
- if (consider_compress
+ if (consider_compress
&& (ds->type == LOOKING
|| (ds->type == COMPRESS && ds->nbytes > nbytes)))
{
ds->type = CREATE;
ds->stat = COMPRESS;
- ds->entry = (struct ext2_dir_entry *) blockaddr;
+ ds->entry = (struct ext2_dir_entry_2 *) blockaddr;
ds->idx = idx;
ds->nbytes = nbytes;
}
-
+
if (currentoff >= blockaddr + DIRBLKSIZ)
{
int i;
@@ -428,9 +484,9 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
down how many entries there were. */
if (!dp->dn->dirents)
{
- dp->dn->dirents = malloc ((dp->dn_stat.st_size / DIRBLKSIZ + 1)
- * sizeof (int));
- for (i = 0; i < dp->dn_stat.st_size/DIRBLKSIZ; i++)
+ dp->dn->dirents = malloc ((dp->dn_stat.st_size / DIRBLKSIZ)
+ * sizeof (int));
+ for (i = 0; i < dp->dn_stat.st_size/DIRBLKSIZ; i++)
dp->dn->dirents[i] = -1;
}
/* Make sure the count is correct if there is one now. */
@@ -440,7 +496,7 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
return ENOENT;
}
-
+
/* We have found the required name. */
if (ds && type == CREATE)
@@ -451,7 +507,7 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
ds->stat = HERE_TIS;
ds->entry = entry;
ds->idx = idx;
- ds->preventry = (struct ext2_dir_entry *) prevoff;
+ ds->preventry = (struct ext2_dir_entry_2 *) prevoff;
}
*inum = entry->inode;
@@ -465,53 +521,49 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
only be made if the directory has been held locked continuously since
the preceding lookup call, and only if that call returned ENOENT. */
error_t
-diskfs_direnter_hard (struct node *dp, char *name, struct node *np,
+diskfs_direnter_hard (struct node *dp, const char *name, struct node *np,
struct dirstat *ds, struct protid *cred)
{
- struct ext2_dir_entry *new;
+ struct ext2_dir_entry_2 *new;
int namelen = strlen (name);
int needed = EXT2_DIR_REC_LEN (namelen);
int oldneeded;
vm_address_t fromoff, tooff;
- int totfreed;
+ int totfreed;
error_t err;
- off_t oldsize;
+ size_t oldsize = 0;
assert (ds->type == CREATE);
-
+
assert (!diskfs_readonly);
dp->dn_set_mtime = 1;
+ /* Select a location for the new directory entry. Each branch of this
+ switch is responsible for setting NEW to point to the on-disk
+ directory entry being written, and setting NEW->rec_len appropriately. */
+
switch (ds->stat)
{
case TAKE:
/* We are supposed to consume this slot. */
assert (ds->entry->inode == 0 && ds->entry->rec_len >= needed);
-
- ds->entry->inode = np->cache_id;
- ds->entry->name_len = namelen;
- bcopy (name, ds->entry->name, namelen);
+ new = ds->entry;
break;
-
+
case SHRINK:
/* We are supposed to take the extra space at the end
of this slot. */
oldneeded = EXT2_DIR_REC_LEN (ds->entry->name_len);
assert (ds->entry->rec_len - oldneeded >= needed);
-
- new = (struct ext2_dir_entry *) ((vm_address_t) ds->entry + oldneeded);
- new->inode = np->cache_id;
+ new = (struct ext2_dir_entry_2 *) ((vm_address_t) ds->entry + oldneeded);
+
new->rec_len = ds->entry->rec_len - oldneeded;
- new->name_len = namelen;
- bcopy (name, new->name, namelen);
-
ds->entry->rec_len = oldneeded;
-
break;
-
+
case COMPRESS:
/* We are supposed to move all the entries to the
front of the block, giving each the minimum
@@ -521,15 +573,15 @@ diskfs_direnter_hard (struct node *dp, char *name, struct node *np,
while (fromoff < (vm_address_t) ds->entry + DIRBLKSIZ)
{
- struct ext2_dir_entry *from = (struct ext2_dir_entry *)fromoff;
- struct ext2_dir_entry *to = (struct ext2_dir_entry *) tooff;
+ struct ext2_dir_entry_2 *from = (struct ext2_dir_entry_2 *)fromoff;
+ struct ext2_dir_entry_2 *to = (struct ext2_dir_entry_2 *) tooff;
int fromreclen = from->rec_len;
if (from->inode != 0)
{
assert (fromoff >= tooff);
- bcopy (from, to, fromreclen);
+ memmove (to, from, fromreclen);
to->rec_len = EXT2_DIR_REC_LEN (to->name_len);
tooff += to->rec_len;
@@ -539,75 +591,105 @@ diskfs_direnter_hard (struct node *dp, char *name, struct node *np,
totfreed = (vm_address_t) ds->entry + DIRBLKSIZ - tooff;
assert (totfreed >= needed);
-
- new = (struct ext2_dir_entry *) tooff;
- new->inode = np->cache_id;
+
+ new = (struct ext2_dir_entry_2 *) tooff;
new->rec_len = totfreed;
- new->name_len = namelen;
- bcopy (name, new->name, namelen);
break;
case EXTEND:
/* Extend the file. */
assert (needed <= DIRBLKSIZ);
-
+
oldsize = dp->dn_stat.st_size;
+ if ((off_t)(oldsize + DIRBLKSIZ) != (dp->dn_stat.st_size + DIRBLKSIZ))
+ {
+ /* We can't possibly map the whole directory in. */
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+ return EOVERFLOW;
+ }
while (oldsize + DIRBLKSIZ > dp->allocsize)
{
err = diskfs_grow (dp, oldsize + DIRBLKSIZ, cred);
if (err)
{
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
return err;
}
}
- new = (struct ext2_dir_entry *) (ds->mapbuf + oldsize);
+ new = (struct ext2_dir_entry_2 *) (ds->mapbuf + oldsize);
dp->dn_stat.st_size = oldsize + DIRBLKSIZ;
dp->dn_set_ctime = 1;
- new->inode = np->cache_id;
new->rec_len = DIRBLKSIZ;
- new->name_len = namelen;
- bcopy (name, new->name, namelen);
break;
-
+
default:
- assert (0);
+ new = 0;
+ assert (! "impossible: bogus status field in dirstat");
}
+ /* NEW points to the directory entry being written, and its
+ rec_len field is already filled in. Now fill in the rest. */
+
+ new->inode = np->cache_id;
+#if 0
+ /* XXX We cannot enable this code because file types can change
+ (and conceivably quite often) with translator settings.
+ There is no way for the translator that determines the type of
+ the virtual node to cause all the directory entries linked to
+ its underlying inode to reflect the proper type. */
+ new->file_type = (EXT2_HAS_INCOMPAT_FEATURE (sblock,
+ EXT2_FEATURE_INCOMPAT_FILETYPE)
+ ? file_type_ext2[IFTODT (np->dn_stat.st_mode & S_IFMT)]
+ : 0);
+#else
+ new->file_type = 0;
+#endif
+ new->name_len = namelen;
+ memcpy (new->name, name, namelen);
+
+ /* Mark the directory inode has having been written. */
+ dp->dn->info.i_flags &= ~EXT2_BTREE_FL;
dp->dn_set_mtime = 1;
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
-
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+
if (ds->stat != EXTEND)
{
- /* If we are keeping count of this block, then keep the count up
+ /* If we are keeping count of this block, then keep the count up
to date. */
if (dp->dn->dirents && dp->dn->dirents[ds->idx] != -1)
dp->dn->dirents[ds->idx]++;
}
else
{
+ int i;
/* It's cheap, so start a count here even if we aren't counting
anything at all. */
if (dp->dn->dirents)
{
- dp->dn->dirents = realloc (dp->dn->dirents,
- (ds->idx + 1) * sizeof (int));
+ dp->dn->dirents = realloc (dp->dn->dirents,
+ (dp->dn_stat.st_size / DIRBLKSIZ
+ * sizeof (int)));
+ for (i = oldsize / DIRBLKSIZ;
+ i < dp->dn_stat.st_size / DIRBLKSIZ;
+ i++)
+ dp->dn->dirents[i] = -1;
+
dp->dn->dirents[ds->idx] = 1;
}
else
{
- int i;
- dp->dn->dirents = malloc ((ds->idx + 1) * sizeof (int));
- for (i = 0; i < ds->idx; i++)
+ dp->dn->dirents = malloc (dp->dn_stat.st_size / DIRBLKSIZ
+ * sizeof (int));
+ for (i = 0; i < dp->dn_stat.st_size / DIRBLKSIZ; i++)
dp->dn->dirents[i] = -1;
dp->dn->dirents[ds->idx] = 1;
}
}
-
+
diskfs_file_update (dp, 1);
return 0;
@@ -616,17 +698,15 @@ diskfs_direnter_hard (struct node *dp, char *name, struct node *np,
/* Following a lookup call for REMOVE, this removes the link from the
directory. DP is the directory being changed and DS is the cached
information returned from lookup. This call is only valid if the
- directory has been locked continously since the call to lookup, and
+ directory has been locked continuously since the call to lookup, and
only if that call succeeded. */
error_t
diskfs_dirremove_hard (struct node *dp, struct dirstat *ds)
{
assert (ds->type == REMOVE);
assert (ds->stat == HERE_TIS);
-
- assert (!diskfs_readonly);
- dp->dn_set_mtime = 1;
+ assert (!diskfs_readonly);
if (ds->preventry == 0)
ds->entry->inode = 0;
@@ -638,23 +718,24 @@ diskfs_dirremove_hard (struct node *dp, struct dirstat *ds)
}
dp->dn_set_mtime = 1;
+ dp->dn->info.i_flags &= ~EXT2_BTREE_FL;
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
/* If we are keeping count of this block, then keep the count up
to date. */
if (dp->dn->dirents && dp->dn->dirents[ds->idx] != -1)
dp->dn->dirents[ds->idx]--;
-
+
diskfs_file_update (dp, 1);
return 0;
}
-
+
/* Following a lookup call for RENAME, this changes the inode number
- on a directory entry. DP is the directory being changed; NP is
- the new node being linked in; DP is the cached information returned
+ on a directory entry. DP is the directory being changed; NP is
+ the new node being linked in; DP is the cached information returned
by lookup. This call is only valid if the directory has been locked
continuously since the call to lookup, and only if that call
succeeded. */
@@ -663,14 +744,15 @@ diskfs_dirrewrite_hard (struct node *dp, struct node *np, struct dirstat *ds)
{
assert (ds->type == RENAME);
assert (ds->stat == HERE_TIS);
-
+
assert (!diskfs_readonly);
ds->entry->inode = np->cache_id;
dp->dn_set_mtime = 1;
+ dp->dn->info.i_flags &= ~EXT2_BTREE_FL;
+
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
-
diskfs_file_update (dp, 1);
return 0;
@@ -683,23 +765,26 @@ diskfs_dirempty (struct node *dp, struct protid *cred)
{
error_t err;
vm_address_t buf = 0, curoff;
- struct ext2_dir_entry *entry;
+ struct ext2_dir_entry_2 *entry;
int hit = 0; /* Found something in the directory. */
memory_object_t memobj = diskfs_get_filemap (dp, VM_PROT_READ);
-
+
+ if (memobj == MACH_PORT_NULL)
+ /* XXX should reflect error properly. */
+ return 0;
+
err = vm_map (mach_task_self (), &buf, dp->dn_stat.st_size, 0,
1, memobj, 0, 0, VM_PROT_READ, VM_PROT_READ, 0);
mach_port_deallocate (mach_task_self (), memobj);
assert (!err);
- if (! diskfs_check_readonly ())
- dp->dn_set_atime = 1;
+ diskfs_set_node_atime (dp);
- for (curoff = buf;
+ for (curoff = buf;
!hit && curoff < buf + dp->dn_stat.st_size;
curoff += entry->rec_len)
{
- entry = (struct ext2_dir_entry *) curoff;
+ entry = (struct ext2_dir_entry_2 *) curoff;
if (entry->inode != 0
&& (entry->name_len > 2
@@ -709,12 +794,11 @@ diskfs_dirempty (struct node *dp, struct protid *cred)
hit = 1;
}
- if (! diskfs_check_readonly ())
- dp->dn_set_atime = 1;
+ diskfs_set_node_atime (dp);
if (diskfs_synchronous)
diskfs_node_update (dp, 1);
- vm_deallocate (mach_task_self (), buf, dp->dn_stat.st_size);
+ munmap ((caddr_t) buf, dp->dn_stat.st_size);
return !hit;
}
@@ -726,7 +810,7 @@ diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
if (ds->type != LOOKUP)
{
assert (ds->mapbuf);
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
ds->type = LOOKUP;
}
return 0;
@@ -739,29 +823,29 @@ diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
static error_t
count_dirents (struct node *dp, int nb, char *buf)
{
- int amt;
+ size_t amt;
char *offinblk;
- struct ext2_dir_entry *entry;
+ struct ext2_dir_entry_2 *entry;
int count = 0;
error_t err;
assert (dp->dn->dirents);
assert ((nb + 1) * DIRBLKSIZ <= dp->dn_stat.st_size);
-
+
err = diskfs_node_rdwr (dp, buf, nb * DIRBLKSIZ, DIRBLKSIZ, 0, 0, &amt);
if (err)
return err;
assert (amt == DIRBLKSIZ);
-
+
for (offinblk = buf;
offinblk < buf + DIRBLKSIZ;
offinblk += entry->rec_len)
{
- entry = (struct ext2_dir_entry *) offinblk;
+ entry = (struct ext2_dir_entry_2 *) offinblk;
if (entry->inode)
count++;
}
-
+
assert (dp->dn->dirents[nb] == -1 || dp->dn->dirents[nb] == count);
dp->dn->dirents[nb] = count;
return 0;
@@ -771,14 +855,14 @@ count_dirents (struct node *dp, int nb, char *buf)
Must be a power of two. */
#define DIRENT_ALIGN 4
-/* Implement the disikfs_get_directs callback as described in
+/* Implement the diskfs_get_directs callback as described in
<hurd/diskfs.h>. */
error_t
-diskfs_get_directs (struct node *dp,
- int entry,
+diskfs_get_directs (struct node *dp,
+ int entry,
int nentries,
char **data,
- u_int *datacnt,
+ size_t *datacnt,
vm_size_t bufsiz,
int *amt)
{
@@ -791,11 +875,11 @@ diskfs_get_directs (struct node *dp,
error_t err;
int i;
char *datap;
- struct ext2_dir_entry *entryp;
+ struct ext2_dir_entry_2 *entryp;
int allocsize;
- int checklen;
+ size_t checklen;
struct dirent *userp;
-
+
nblks = dp->dn_stat.st_size/DIRBLKSIZ;
if (!dp->dn->dirents)
@@ -805,33 +889,6 @@ diskfs_get_directs (struct node *dp,
dp->dn->dirents[i] = -1;
}
- /* Allocate enough space to hold the maximum we might return */
- if (!bufsiz || bufsiz > dp->dn_stat.st_size)
- /* Allocate enough to return the entire directory. Since ext2's
- directory format is different than the format used to return the
- entries, we allocate enough to hold the on disk directory plus
- whatever extra would be necessary in the worst-case. */
- {
- /* The minimum size of an ext2fs directory entry. */
- size_t min_entry_size = EXT2_DIR_REC_LEN (0);
- /* The minimum size of a returned dirent entry. The +1 is for '\0'. */
- size_t min_dirent_size = offsetof (struct dirent, d_name) + 1;
- /* The maximum possible number of ext2fs dir entries in this dir. */
- size_t max_entries = dp->dn_stat.st_size / min_entry_size;
- /* The maximum difference in size per directory entry. */
- size_t entry_extra =
- DIRENT_ALIGN
- + (min_dirent_size > min_entry_size
- ? min_dirent_size - min_entry_size : 0);
-
- allocsize = round_page (dp->dn_stat.st_size + max_entries * entry_extra);
- }
- else
- allocsize = round_page (bufsiz);
-
- if (allocsize > *datacnt)
- vm_allocate (mach_task_self (), (vm_address_t *) data, allocsize, 1);
-
/* Scan through the entries to find ENTRY. If we encounter
a -1 in the process then stop to fill it. When we run
off the end, ENTRY is too big. */
@@ -852,17 +909,47 @@ diskfs_get_directs (struct node *dp,
break;
curentry += dp->dn->dirents[blkno];
-
+
bufvalid = 0;
}
-
+
if (blkno == nblks)
{
+ /* We reached the end of the directory without seeing ENTRY.
+ This is treated as an EOF condition, meaning we return
+ success with empty results. */
*datacnt = 0;
*amt = 0;
return 0;
}
+ /* Allocate enough space to hold the maximum we might return */
+ if (!bufsiz || bufsiz > dp->dn_stat.st_size)
+ /* Allocate enough to return the entire directory. Since ext2's
+ directory format is different than the format used to return the
+ entries, we allocate enough to hold the on disk directory plus
+ whatever extra would be necessary in the worst-case. */
+ {
+ /* The minimum size of an ext2fs directory entry. */
+ size_t min_entry_size = EXT2_DIR_REC_LEN (0);
+ /* The minimum size of a returned dirent entry. The +1 is for '\0'. */
+ size_t min_dirent_size = offsetof (struct dirent, d_name) + 1;
+ /* The maximum possible number of ext2fs dir entries in this dir. */
+ size_t max_entries = dp->dn_stat.st_size / min_entry_size;
+ /* The maximum difference in size per directory entry. */
+ size_t entry_extra =
+ DIRENT_ALIGN
+ + (min_dirent_size > min_entry_size
+ ? min_dirent_size - min_entry_size : 0);
+
+ allocsize = round_page (dp->dn_stat.st_size + max_entries * entry_extra);
+ }
+ else
+ allocsize = round_page (bufsiz);
+
+ if (allocsize > *datacnt)
+ *data = mmap (0, allocsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+
/* Set bufp appropriately */
bufp = buf;
if (curentry != entry)
@@ -878,13 +965,13 @@ diskfs_get_directs (struct node *dp,
assert (checklen == DIRBLKSIZ);
bufvalid = 1;
}
- for (i = 0, bufp = buf;
- i < entry - curentry && bufp - buf < DIRBLKSIZ;
- bufp += ((struct ext2_dir_entry *)bufp)->rec_len, i++)
+ for (i = 0, bufp = buf;
+ i < entry - curentry && bufp - buf < DIRBLKSIZ;
+ bufp += ((struct ext2_dir_entry_2 *)bufp)->rec_len, i++)
;
/* Make sure we didn't run off the end. */
assert (bufp - buf < DIRBLKSIZ);
- }
+ }
i = 0;
datap = *data;
@@ -896,7 +983,7 @@ diskfs_get_directs (struct node *dp,
{
if (!bufvalid)
{
- err = diskfs_node_rdwr (dp, buf, blkno * DIRBLKSIZ, DIRBLKSIZ,
+ err = diskfs_node_rdwr (dp, buf, blkno * DIRBLKSIZ, DIRBLKSIZ,
0, 0, &checklen);
if (err)
return err;
@@ -905,7 +992,7 @@ diskfs_get_directs (struct node *dp,
bufp = buf;
}
- entryp = (struct ext2_dir_entry *)bufp;
+ entryp = (struct ext2_dir_entry_2 *)bufp;
if (entryp->inode)
{
@@ -934,7 +1021,30 @@ diskfs_get_directs (struct node *dp,
userp->d_fileno = entryp->inode;
userp->d_reclen = rec_len;
userp->d_namlen = name_len;
- bcopy (entryp->name, userp->d_name, name_len);
+
+#if 0
+ /* We don't bother to check the EXT2_FEATURE_INCOMPAT_FILETYPE
+ flag in the superblock, because in old filesystems the
+ file_type field is the high byte of the length field and is
+ always zero because names cannot be that long. */
+ if (entryp->file_type < EXT2_FT_MAX)
+ userp->d_type = ext2_file_type[entryp->file_type];
+ else
+ {
+ ext2_warning ("bad type %d in directory entry: "
+ "inode: %d offset: %d",
+ entryp->file_type,
+ dp->cache_id,
+ blkno * DIRBLKSIZ + bufp - buf);
+ userp->d_type = DT_UNKNOWN;
+ }
+#else
+ /* XXX
+ For complex reasons it might not be correct to return
+ the filesystem's d_type value to the user. */
+ userp->d_type = DT_UNKNOWN;
+#endif
+ memcpy (userp->d_name, entryp->name, name_len);
userp->d_name[name_len] = '\0';
datap += rec_len;
@@ -943,7 +1053,7 @@ diskfs_get_directs (struct node *dp,
if (entryp->rec_len == 0)
{
- ext2_warning ("zero length directory entry: inode: %d offset: %d",
+ ext2_warning ("zero length directory entry: inode: %Ld offset: %zd",
dp->cache_id,
blkno * DIRBLKSIZ + bufp - buf);
return EIO;
@@ -957,23 +1067,22 @@ diskfs_get_directs (struct node *dp,
}
else if (bufp - buf > DIRBLKSIZ)
{
- ext2_warning ("directory entry too long: inode: %d offset: %d",
+ ext2_warning ("directory entry too long: inode: %Ld offset: %zd",
dp->cache_id,
blkno * DIRBLKSIZ + bufp - buf - entryp->rec_len);
return EIO;
}
}
-
+
/* We've copied all we can. If we allocated our own array
but didn't fill all of it, then free whatever memory we didn't use. */
if (allocsize > *datacnt)
{
if (round_page (datap - *data) < allocsize)
- vm_deallocate (mach_task_self (),
- (vm_address_t) (*data + round_page (datap - *data)),
- allocsize - round_page (datap - *data));
+ munmap ((caddr_t) (*data + round_page (datap - *data)),
+ allocsize - round_page (datap - *data));
}
-
+
/* Set variables for return */
*datacnt = datap - *data;
*amt = i;
diff --git a/ext2fs/ext2_fs.h b/ext2fs/ext2_fs.h
index 9934ce85..b1caeefa 100644
--- a/ext2fs/ext2_fs.h
+++ b/ext2fs/ext2_fs.h
@@ -16,12 +16,7 @@
#ifndef _LINUX_EXT2_FS_H
#define _LINUX_EXT2_FS_H
-typedef unsigned long u32;
-typedef long s32;
-typedef unsigned short u16;
-typedef short s16;
-typedef unsigned char u8;
-typedef signed char s8;
+/* #include <linux/types.h> */
/*
* The second extended filesystem constants/structures
@@ -33,40 +28,28 @@ typedef signed char s8;
#undef EXT2FS_DEBUG
/*
- * Define EXT2FS_DEBUG_CACHE to produce cache debug messages
- */
-#undef EXT2FS_DEBUG_CACHE
-
-/*
- * Define EXT2FS_CHECK_CACHE to add some checks to the name cache code
- */
-#undef EXT2FS_CHECK_CACHE
-
-/*
- * Define EXT2FS_PRE_02B_COMPAT to convert ext 2 fs prior to 0.2b
- */
-#undef EXT2FS_PRE_02B_COMPAT
-
-/*
* Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
*/
#define EXT2_PREALLOCATE
+#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
/*
* The second extended file system version
*/
-#define EXT2FS_DATE "95/03/19"
-#define EXT2FS_VERSION "0.5a"
+#define EXT2FS_DATE "95/08/09"
+#define EXT2FS_VERSION "0.5b"
/*
* Debug code
*/
#ifdef EXT2FS_DEBUG
-extern int ext2_debug_flag;
-#define ext2_debug(f, a...) \
- do { if (ext2_debug_flag) printf ("ext2fs: (debug) %s: " f "\n", __FUNCTION__ , ## a); } while (0)
+# define ext2_debug(f, a...) { \
+ printk ("EXT2-fs DEBUG (%s, %d): %s:", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ printk (f, ## a); \
+ }
#else
-#define ext2_debug(f, a...) (void)0
+# define ext2_debug(f, a...) /**/
#endif
/*
@@ -78,12 +61,13 @@ extern int ext2_debug_flag;
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
-#define EXT2_FIRST_INO 11 /* First non reserved inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO 11
/*
* The second extended file system magic number
*/
-#define EXT2_PRE_02B_MAGIC 0xEF51
#define EXT2_SUPER_MAGIC 0xEF53
/*
@@ -103,13 +87,24 @@ extern int ext2_debug_flag;
# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
#endif
#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
-#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (u32))
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
#ifdef __KERNEL__
-# define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10)
+# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
#else
# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
#endif
-#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode))
+#ifdef __KERNEL__
+#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits)
+#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size)
+#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino)
+#else
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_INODE_SIZE : \
+ (s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_FIRST_INO : \
+ (s)->s_first_ino)
+#endif
/*
* Macro-instructions used to manage fragments
@@ -130,45 +125,36 @@ extern int ext2_debug_flag;
*/
struct ext2_acl_header /* Header of Access Control Lists */
{
- u32 aclh_size;
- u32 aclh_file_count;
- u32 aclh_acle_count;
- u32 aclh_first_acle;
+ __u32 aclh_size;
+ __u32 aclh_file_count;
+ __u32 aclh_acle_count;
+ __u32 aclh_first_acle;
};
struct ext2_acl_entry /* Access Control List Entry */
{
- u32 acle_size;
- u16 acle_perms; /* Access permissions */
- u16 acle_type; /* Type of entry */
- u16 acle_tag; /* User or group identity */
- u16 acle_pad1;
- u32 acle_next; /* Pointer on next entry for the */
+ __u32 acle_size;
+ __u16 acle_perms; /* Access permissions */
+ __u16 acle_type; /* Type of entry */
+ __u16 acle_tag; /* User or group identity */
+ __u16 acle_pad1;
+ __u32 acle_next; /* Pointer on next entry for the */
/* same inode or on next free entry */
};
/*
* Structure of a blocks group descriptor
*/
-struct ext2_old_group_desc
-{
- u32 bg_block_bitmap; /* Blocks bitmap block */
- u32 bg_inode_bitmap; /* Inodes bitmap block */
- u32 bg_inode_table; /* Inodes table block */
- u16 bg_free_blocks_count; /* Free blocks count */
- u16 bg_free_inodes_count; /* Free inodes count */
-};
-
struct ext2_group_desc
{
- u32 bg_block_bitmap; /* Blocks bitmap block */
- u32 bg_inode_bitmap; /* Inodes bitmap block */
- u32 bg_inode_table; /* Inodes table block */
- u16 bg_free_blocks_count; /* Free blocks count */
- u16 bg_free_inodes_count; /* Free inodes count */
- u16 bg_used_dirs_count; /* Directories count */
- u16 bg_pad;
- u32 bg_reserved[3];
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_pad;
+ __u32 bg_reserved[3];
};
/*
@@ -178,6 +164,7 @@ struct ext2_group_desc
# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group)
# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block)
# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group)
+# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits)
#else
# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
@@ -203,6 +190,41 @@ struct ext2_group_desc
#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL 0x00000100
+#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */
+
+/* Flags that should be inherited by new inodes from their parent. */
+#define EXT2_FL_INHERITED (EXT2_SECRM_FL | EXT2_UNRM_FL | EXT2_COMPR_FL |\
+ EXT2_SYNC_FL | EXT2_NODUMP_FL |\
+ EXT2_NOATIME_FL | EXT2_COMPRBLK_FL |\
+ EXT2_NOCOMP_FL)
+
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define EXT2_REG_FLMASK (~(0))
+
+/* Flags that are appropriate for non-directories/regular files. */
+#define EXT2_OTHER_FLMASK (EXT2_NODUMP_FL | EXT2_NOATIME_FL)
+
+/* Mask out flags that are inappropriate for the given type of inode. */
+static __inline__ __u32 ext2_mask_flags(mode_t mode, __u32 flags)
+{
+ if (S_ISDIR(mode))
+ return flags;
+ else if (S_ISREG(mode))
+ return flags & EXT2_REG_FLMASK;
+ else
+ return flags & EXT2_OTHER_FLMASK;
+}
/*
* ioctl commands
@@ -216,71 +238,78 @@ struct ext2_group_desc
* Structure of an inode on the disk
*/
struct ext2_inode {
- u16 i_mode; /* File mode */
- u16 i_uid; /* Owner Uid */
- u32 i_size; /* Size in bytes */
- u32 i_atime; /* Access time */
- u32 i_ctime; /* Creation time */
- u32 i_mtime; /* Modification time */
- u32 i_dtime; /* Deletion Time */
- u16 i_gid; /* Group Id */
- u16 i_links_count; /* Links count */
- u32 i_blocks; /* Blocks count */
- u32 i_flags; /* File flags */
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Low 16 bits of Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Low 16 bits of Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
union {
struct {
- u32 l_i_reserved1;
+ __u32 l_i_reserved1;
} linux1;
struct {
- u32 h_i_translator;
+ __u32 h_i_translator;
} hurd1;
struct {
- u32 m_i_reserved1;
+ __u32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
- u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
- u32 i_version; /* File version (for NFS) */
- u32 i_file_acl; /* File ACL */
- u32 i_dir_acl; /* Directory ACL */
- u32 i_faddr; /* Fragment address */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_generation; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
union {
struct {
- u8 l_i_frag; /* Fragment number */
- u8 l_i_fsize; /* Fragment size */
- u16 i_pad1;
- u32 l_i_reserved2[2];
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u16 l_i_uid_high; /* these 2 fields */
+ __u16 l_i_gid_high; /* were reserved2[0] */
+ __u32 l_i_reserved2;
} linux2;
struct {
- u8 h_i_frag; /* Fragment number */
- u8 h_i_fsize; /* Fragment size */
- u16 h_i_mode_high;
- u16 h_i_uid_high;
- u16 h_i_gid_high;
- u32 h_i_author;
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
} hurd2;
struct {
- u8 m_i_frag; /* Fragment number */
- u8 m_i_fsize; /* Fragment size */
- u16 m_pad1;
- u32 m_i_reserved2[2];
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
+#define i_size_high i_dir_acl
+
#if defined(__KERNEL__) || defined(__linux__)
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
#define i_fsize osd2.linux2.l_i_fsize
+#define i_uid_low i_uid
+#define i_gid_low i_gid
+#define i_uid_high osd2.linux2.l_i_uid_high
+#define i_gid_high osd2.linux2.l_i_gid_high
#define i_reserved2 osd2.linux2.l_i_reserved2
#endif
#ifdef __hurd__
#define i_translator osd1.hurd1.h_i_translator
-#define i_frag osd2.hurd2.h_i_frag;
-#define i_fsize osd2.hurd2.h_i_fsize;
+#define i_frag osd2.hurd2.h_i_frag
+#define i_fsize osd2.hurd2.h_i_fsize
#define i_uid_high osd2.hurd2.h_i_uid_high
#define i_gid_high osd2.hurd2.h_i_gid_high
-#define i_mode_high osd2.hurd2.h_i_mode_high
#define i_author osd2.hurd2.h_i_author
#endif
@@ -310,6 +339,7 @@ struct ext2_inode {
#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
@@ -333,40 +363,122 @@ struct ext2_inode {
* Structure of the super block
*/
struct ext2_super_block {
- u32 s_inodes_count; /* Inodes count */
- u32 s_blocks_count; /* Blocks count */
- u32 s_r_blocks_count; /* Reserved blocks count */
- u32 s_free_blocks_count; /* Free blocks count */
- u32 s_free_inodes_count; /* Free inodes count */
- u32 s_first_data_block; /* First Data Block */
- u32 s_log_block_size; /* Block size */
- s32 s_log_frag_size; /* Fragment size */
- u32 s_blocks_per_group; /* # Blocks per group */
- u32 s_frags_per_group; /* # Fragments per group */
- u32 s_inodes_per_group; /* # Inodes per group */
- u32 s_mtime; /* Mount time */
- u32 s_wtime; /* Write time */
- u16 s_mnt_count; /* Mount count */
- s16 s_max_mnt_count; /* Maximal mount count */
- u16 s_magic; /* Magic signature */
- u16 s_state; /* File system state */
- u16 s_errors; /* Behaviour when detecting errors */
- u16 s_pad;
- u32 s_lastcheck; /* time of last check */
- u32 s_checkinterval; /* max. time between checks */
- u32 s_creator_os; /* OS */
- u32 s_rev_level; /* Revision level */
- u16 s_def_resuid; /* Default uid for reserved blocks */
- u16 s_def_resgid; /* Default gid for reserved blocks */
- u32 s_reserved[235]; /* Padding to the end of the block */
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level; /* minor revision level */
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_padding1;
+ __u32 s_reserved[204]; /* Padding to the end of the block */
};
+#ifdef __KERNEL__
+#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
+#else
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+#endif
+
+/*
+ * Codes for operating systems
+ */
#define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
-#define EXT2_CURRENT_REV 0
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
#define EXT2_DEF_RESUID 0
#define EXT2_DEF_RESGID 0
@@ -376,13 +488,42 @@ struct ext2_super_block {
#define EXT2_NAME_LEN 255
struct ext2_dir_entry {
- u32 inode; /* Inode number */
- u16 rec_len; /* Directory entry length */
- u16 name_len; /* Name length */
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u16 name_len; /* Name length */
char name[EXT2_NAME_LEN]; /* File name */
};
/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
@@ -392,4 +533,119 @@ struct ext2_dir_entry {
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
+#ifdef __KERNEL__
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext2 source programs needs to include it so they are duplicated here.
+ */
+# define NORET_TYPE /**/
+# define ATTRIB_NORET __attribute__((noreturn))
+# define NORET_AND noreturn,
+
+/* acl.c */
+extern int ext2_permission (struct inode *, int);
+
+/* balloc.c */
+extern int ext2_group_sparse(int group);
+extern int ext2_new_block (const struct inode *, unsigned long,
+ __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (const struct inode *, unsigned long,
+ unsigned long);
+extern unsigned long ext2_count_free_blocks (struct super_block *);
+extern void ext2_check_blocks_bitmap (struct super_block *);
+extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh);
+
+/* bitmap.c */
+extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
+
+/* dir.c */
+extern int ext2_check_dir_entry (const char *, struct inode *,
+ struct ext2_dir_entry_2 *, struct buffer_head *,
+ unsigned long);
+
+/* file.c */
+extern int ext2_read (struct inode *, struct file *, char *, int);
+extern int ext2_write (struct inode *, struct file *, char *, int);
+
+/* fsync.c */
+extern int ext2_sync_file (struct file *, struct dentry *);
+
+/* ialloc.c */
+extern struct inode * ext2_new_inode (const struct inode *, int, int *);
+extern void ext2_free_inode (struct inode *);
+extern unsigned long ext2_count_free_inodes (struct super_block *);
+extern void ext2_check_inodes_bitmap (struct super_block *);
+
+/* inode.c */
+extern long ext2_bmap (struct inode *, long);
+extern int ext2_get_block (struct inode *, long, struct buffer_head *, int);
+
+extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
+extern int ext2_getblk_block (struct inode *, long, int, int *, int *);
+extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
+
+extern int ext2_getcluster (struct inode * inode, long block);
+extern void ext2_read_inode (struct inode *);
+extern void ext2_write_inode (struct inode *);
+extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
+extern int ext2_sync_inode (struct inode *);
+extern void ext2_discard_prealloc (struct inode *);
+
+/* ioctl.c */
+extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+/* namei.c */
+extern void ext2_release (struct inode *, struct file *);
+extern struct dentry *ext2_lookup (struct inode *, struct dentry *);
+extern int ext2_create (struct inode *,struct dentry *,int);
+extern int ext2_mkdir (struct inode *,struct dentry *,int);
+extern int ext2_rmdir (struct inode *,struct dentry *);
+extern int ext2_unlink (struct inode *,struct dentry *);
+extern int ext2_symlink (struct inode *,struct dentry *,const char *);
+extern int ext2_link (struct dentry *, struct inode *, struct dentry *);
+extern int ext2_mknod (struct inode *, struct dentry *, int, int);
+extern int ext2_rename (struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
+
+/* super.c */
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
+ const char *, ...)
+ __attribute__ ((NORET_AND format (printf, 3, 4)));
+extern void ext2_warning (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern void ext2_put_super (struct super_block *);
+extern void ext2_write_super (struct super_block *);
+extern int ext2_remount (struct super_block *, int *, char *);
+extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int ext2_statfs (struct super_block *, struct statfs *, int);
+
+/* truncate.c */
+extern void ext2_truncate (struct inode *);
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern struct inode_operations ext2_dir_inode_operations;
+
+/* file.c */
+extern struct inode_operations ext2_file_inode_operations;
+
+/* symlink.c */
+extern struct inode_operations ext2_symlink_inode_operations;
+extern struct inode_operations ext2_fast_symlink_inode_operations;
+
+#endif /* __KERNEL__ */
+
#endif /* _LINUX_EXT2_FS_H */
diff --git a/ext2fs/ext2_fs_i.h b/ext2fs/ext2_fs_i.h
index 6c7e0e71..72bcd5c0 100644
--- a/ext2fs/ext2_fs_i.h
+++ b/ext2fs/ext2_fs_i.h
@@ -20,21 +20,23 @@
* second extended file system inode data in memory
*/
struct ext2_inode_info {
- u32 i_data[15];
- u32 i_flags;
- u32 i_faddr;
- u8 i_frag_no;
- u8 i_frag_size;
- u16 i_osync;
- u32 i_file_acl;
- u32 i_dir_acl;
- u32 i_dtime;
- u32 i_version;
- u32 i_block_group;
- u32 i_next_alloc_block;
- u32 i_next_alloc_goal;
- u32 i_prealloc_block;
- u32 i_prealloc_count;
+ __u32 i_data[15];
+ __u32 i_flags;
+ __u32 i_faddr;
+ __u8 i_frag_no;
+ __u8 i_frag_size;
+ __u16 i_osync;
+ __u32 i_file_acl;
+ __u32 i_dir_acl;
+ __u32 i_dtime;
+ __u32 not_used_1; /* FIX: not used/ 2.2 placeholder */
+ __u32 i_block_group;
+ __u32 i_next_alloc_block;
+ __u32 i_next_alloc_goal;
+ __u32 i_prealloc_block;
+ __u32 i_prealloc_count;
+ __u32 i_high_size;
+ int i_new_inode:1; /* Is a freshly allocated inode */
};
#endif /* _LINUX_EXT2_FS_I */
diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c
index a1bbc22c..0857a749 100644
--- a/ext2fs/ext2fs.c
+++ b/ext2fs/ext2fs.c
@@ -1,6 +1,6 @@
/* Main entry point for the ext2 file system translator
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,97,98,99,2002 Free Software Foundation, Inc.
Converted for ext2fs by Miles Bader <miles@gnu.ai.mit.edu>
@@ -27,11 +27,15 @@
#include <string.h>
#include <error.h>
#include <argz.h>
+#include <argp.h>
+#include <hurd/store.h>
+#include <version.h>
#include "ext2fs.h"
/* ---------------------------------------------------------------- */
int diskfs_link_max = EXT2_LINK_MAX;
+int diskfs_name_max = EXT2_NAME_LEN;
int diskfs_maxsymlinks = 8;
int diskfs_shortcut_symlink = 1;
int diskfs_shortcut_chrdev = 1;
@@ -40,24 +44,33 @@ int diskfs_shortcut_fifo = 1;
int diskfs_shortcut_ifsock = 1;
char *diskfs_server_name = "ext2fs";
-int diskfs_major_version = 0;
-int diskfs_minor_version = 0;
-int diskfs_edit_version = 0;
+char *diskfs_server_version = HURD_VERSION;
+char *diskfs_extra_version = "GNU Hurd; ext2 " EXT2FS_VERSION;
-int diskfs_synchronous = 0;
-int diskfs_readonly = 0;
+int diskfs_synchronous;
struct node *diskfs_root_node;
+
+struct store *store;
+struct store_parsed *store_parsed;
+
+char *diskfs_disk_name;
#ifdef EXT2FS_DEBUG
-
-int ext2_debug_flag = 0;
+int ext2_debug_flag;
+#endif
/* Ext2fs-specific options. */
static const struct argp_option
options[] =
{
- {"debug", 'D', 0, 0, "Toggle debugging output" },
+ {"debug", 'D', 0, 0, "Toggle debugging output"
+#ifndef EXT2FS_DEBUG
+ " (not compiled in)"
+#endif
+ },
+ {"sblock", 'S', "BLOCKNO", 0,
+ "Use alternate superblock location (1kb blocks)"},
{0}
};
@@ -65,19 +78,50 @@ options[] =
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
+ /* We save our parsed values in this structure, hung off STATE->hook.
+ Only after parsing all options successfully will we use these values. */
+ struct
+ {
+ int debug_flag;
+ unsigned int sb_block;
+ } *values = state->hook;
+
switch (key)
{
case 'D':
- state->hook = (void *)1; /* Do it at the end */
+ values->debug_flag = 1;
+ break;
+ case 'S':
+ values->sb_block = strtoul (arg, &arg, 0);
+ if (!arg || *arg != '\0')
+ {
+ argp_error (state, "invalid number for --sblock");
+ return EINVAL;
+ }
break;
case ARGP_KEY_INIT:
- state->hook = 0;
+ state->child_inputs[0] = state->input;
+ values = malloc (sizeof *values);
+ if (values == 0)
+ return ENOMEM;
+ state->hook = values;
+ bzero (values, sizeof *values);
+ values->sb_block = SBLOCK_BLOCK;
break;
+
case ARGP_KEY_SUCCESS:
/* All options parse successfully, so implement ours if possible. */
- if (state->hook)
- ext2_debug_flag = !ext2_debug_flag;
+ if (values->debug_flag)
+ {
+#ifdef EXT2FS_DEBUG
+ ext2_debug_flag = !ext2_debug_flag;
+#else
+ argp_failure (state, 2, 0, "debugging support not compiled in");
+ return EINVAL;
+#endif
+ }
+
break;
default:
@@ -85,89 +129,59 @@ parse_opt (int key, char *arg, struct argp_state *state)
}
return 0;
}
-
-/* Add our startup arguments to the standard diskfs set. */
-static const struct argp *startup_parents[] = { &diskfs_std_device_startup_argp, 0};
-static struct argp startup_argp = {options, parse_opt, 0, 0, startup_parents};
-
-/* Similarly at runtime. */
-static const struct argp *runtime_parents[] = {&diskfs_std_runtime_argp, 0};
-static struct argp runtime_argp = {options, parse_opt, 0, 0, runtime_parents};
-
-struct argp *diskfs_runtime_argp = (struct argp *)&runtime_argp;
/* Override the standard diskfs routine so we can add our own output. */
error_t
-diskfs_get_options (char **argz, unsigned *argz_len)
+diskfs_append_args (char **argz, size_t *argz_len)
{
error_t err;
- *argz = 0;
- *argz_len = 0;
-
/* Get the standard things. */
err = diskfs_append_std_options (argz, argz_len);
+#ifdef EXT2FS_DEBUG
if (!err && ext2_debug_flag)
- {
- err = argz_add (argz, argz_len, "--debug");
- if (err)
- free (argz); /* Deallocate what diskfs returned. */
- }
+ err = argz_add (argz, argz_len, "--debug");
+#endif
+ if (! err)
+ err = store_parsed_append_args (store_parsed, argz, argz_len);
return err;
}
+
+/* Add our startup arguments to the standard diskfs set. */
+static const struct argp_child startup_children[] =
+ {{&diskfs_store_startup_argp}, {0}};
+static struct argp startup_argp = {options, parse_opt, 0, 0, startup_children};
-#else /* !EXT2FS_DEBUG */
-
-#define startup_argp diskfs_std_device_startup_argp
+/* Similarly at runtime. */
+static const struct argp_child runtime_children[] =
+ {{&diskfs_std_runtime_argp}, {0}};
+static struct argp runtime_argp = {options, parse_opt, 0, 0, runtime_children};
-#endif /* EXT2FS_DEBUG */
+struct argp *diskfs_runtime_argp = (struct argp *)&runtime_argp;
-void
+int
main (int argc, char **argv)
{
error_t err;
- mach_port_t bootstrap = MACH_PORT_NULL;
-
- argp_parse (&startup_argp, argc, argv, 0, 0, 0);
+ mach_port_t bootstrap;
- diskfs_console_stdio ();
+ /* Initialize the diskfs library, parse arguments, and open the store.
+ This starts the first diskfs thread for us. */
+ store = diskfs_init_main (&startup_argp, argc, argv,
+ &store_parsed, &bootstrap);
- if (! diskfs_boot_flags)
- {
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error (2, 0, "Must be started as a translator");
- }
-
- /* Initialize the diskfs library. This must come before
- any other diskfs call. */
- err = diskfs_init_diskfs ();
- if (err)
- error (4, err, "init");
-
- err = diskfs_device_open ();
- if (err)
- error (3, err, "%s", diskfs_device_arg);
-
- if ((diskfs_device_size << diskfs_log2_device_block_size)
- < SBLOCK_OFFS + SBLOCK_SIZE)
- ext2_panic ("superblock won't fit on the device!");
- if (diskfs_log2_device_block_size == 0)
- ext2_panic ("device block size (%u) not a power of two",
- diskfs_device_block_size);
- if (diskfs_log2_device_blocks_per_page < 0)
- ext2_panic ("device block size (%u) greater than page size (%d)",
- diskfs_device_block_size, vm_page_size);
+ if (store->size < SBLOCK_OFFS + SBLOCK_SIZE)
+ ext2_panic ("device too small for superblock (%Ld bytes)", store->size);
+ if (store->log2_blocks_per_page < 0)
+ ext2_panic ("device block size (%zu) greater than page size (%zd)",
+ store->block_size, vm_page_size);
/* Map the entire disk. */
create_disk_pager ();
- /* Start the first request thread, to handle RPCs and page requests. */
- diskfs_spawn_first_thread ();
-
- pokel_init (&global_pokel, disk_pager, disk_image);
+ pokel_init (&global_pokel, diskfs_disk_pager, disk_image);
get_hypermetadata();
@@ -188,49 +202,15 @@ main (int argc, char **argv)
/* and so we die, leaving others to do the real work. */
cthread_exit (0);
+ /* NOTREACHED */
+ return 0;
}
error_t
diskfs_reload_global_state ()
{
pokel_flush (&global_pokel);
- pager_flush (disk_pager, 1);
+ pager_flush (diskfs_disk_pager, 1);
get_hypermetadata ();
return 0;
}
-
-/* ---------------------------------------------------------------- */
-
-static spin_lock_t free_page_bufs_lock = SPIN_LOCK_INITIALIZER;
-static vm_address_t free_page_bufs = 0;
-
-/* Returns a single page page-aligned buffer. */
-vm_address_t get_page_buf ()
-{
- vm_address_t buf;
-
- spin_lock (&free_page_bufs_lock);
-
- buf = free_page_bufs;
- if (buf == 0)
- {
- spin_unlock (&free_page_bufs_lock);
- vm_allocate (mach_task_self (), &buf, vm_page_size, 1);
- }
- else
- {
- free_page_bufs = *(vm_address_t *)buf;
- spin_unlock (&free_page_bufs_lock);
- }
-
- return buf;
-}
-
-/* Frees a block returned by get_page_buf. */
-void free_page_buf (vm_address_t buf)
-{
- spin_lock (&free_page_bufs_lock);
- *(vm_address_t *)buf = free_page_bufs;
- free_page_bufs = buf;
- spin_unlock (&free_page_bufs_lock);
-}
diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h
index 8a4bde9d..2ad4a9df 100644
--- a/ext2fs/ext2fs.h
+++ b/ext2fs/ext2fs.h
@@ -1,8 +1,7 @@
/* Common definitions for the ext2 filesystem translator
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995, 1996, 1999, 2002, 2004 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -27,10 +26,35 @@
#include <hurd/diskfs.h>
#include <assert.h>
#include <rwlock.h>
+#include <sys/mman.h>
#define __hurd__ /* Enable some hurd-specific fields. */
+
+/* Types used by the ext2 header files. */
+typedef u_int32_t __u32;
+typedef int32_t __s32;
+typedef u_int16_t __u16;
+typedef int16_t __s16;
+typedef u_int8_t __u8;
+typedef int8_t __s8;
+
#include "ext2_fs.h"
#include "ext2_fs_i.h"
+
+#define i_mode_high osd2.hurd2.h_i_mode_high /* missing from ext2_fs.h */
+
+
+/* If ext2_fs.h defined a debug routine, undef it and use our own. */
+#undef ext2_debug
+
+#ifdef EXT2FS_DEBUG
+extern int ext2_debug_flag;
+#define ext2_debug(f, a...) \
+ do { if (ext2_debug_flag) printf ("ext2fs: (debug) %s: " f "\n", __FUNCTION__ , ## a); } while (0)
+#else
+#define ext2_debug(f, a...) (void)0
+#endif
+
#undef __hurd__
/* Define this if memory objects should not be cached by the kernel.
@@ -42,7 +66,7 @@
int printf (const char *fmt, ...);
/* A block number. */
-typedef u32 block_t;
+typedef __u32 block_t;
/* ---------------------------------------------------------------- */
@@ -77,64 +101,52 @@ void pokel_flush (struct pokel *pokel);
/* Transfer all regions from FROM to POKEL, which must have the same pager. */
void pokel_inherit (struct pokel *pokel, struct pokel *from);
+#include <features.h>
+#ifdef EXT2FS_DEFINE_EI
+#define EXT2FS_EI
+#else
+#define EXT2FS_EI __extern_inline
+#endif
+
/* ---------------------------------------------------------------- */
/* Bitmap routines. */
+#include <stdint.h>
+
+extern int test_bit (unsigned num, char *bitmap);
+
+extern int set_bit (unsigned num, char *bitmap);
+
+#if defined(__USE_EXTERN_INLINES) || defined(EXT2FS_DEFINE_EI)
/* Returns TRUE if bit NUM is set in BITMAP. */
-extern inline int
+EXT2FS_EI int
test_bit (unsigned num, char *bitmap)
{
- return bitmap[num >> 3] & (1 << (num & 0x7));
+ const uint32_t *const bw = (uint32_t *) bitmap + (num >> 5);
+ const uint_fast32_t mask = 1 << (num & 31);
+ return *bw & mask;
}
/* Sets bit NUM in BITMAP, and returns the previous state of the bit. Unlike
the linux version, this function is NOT atomic! */
-extern inline int
+EXT2FS_EI int
set_bit (unsigned num, char *bitmap)
{
- char *p = bitmap + (num >> 3);
- char byte = *p;
- char mask = (1 << (num & 0x7));
-
- if (byte & mask)
- return 1;
- else
- {
- *p = byte | mask;
- return 0;
- }
+ uint32_t *const bw = (uint32_t *) bitmap + (num >> 5);
+ const uint_fast32_t mask = 1 << (num & 31);
+ return (*bw & mask) ?: (*bw |= mask, 0);
}
/* Clears bit NUM in BITMAP, and returns the previous state of the bit.
Unlike the linux version, this function is NOT atomic! */
-extern inline int
+EXT2FS_EI int
clear_bit (unsigned num, char *bitmap)
{
- char *p = bitmap + (num >> 3);
- char byte = *p;
- char mask = (1 << (num & 0x7));
-
- if (byte & mask)
- {
- *p = byte & ~mask;
- return 1;
- }
- else
- return 0;
+ uint32_t *const bw = (uint32_t *) bitmap + (num >> 5);
+ const uint_fast32_t mask = 1 << (num & 31);
+ return (*bw & mask) ? (*bw &= ~mask, mask) : 0;
}
-
-/* Counts the number of bits unset in MAP, a bitmap NUMCHARS long. */
-unsigned long count_free (char * map, unsigned int numchars);
-
-extern int find_first_zero_bit(void * addr, unsigned size);
-
-extern int find_next_zero_bit (void * addr, int size, int offset);
-
-extern unsigned long ffz(unsigned long word);
-
-/* Returns a pointer to the first occurence of CH in the buffer BUF of len
- LEN, or BUF + LEN if CH doesn't occur. */
-void *memscan(void *buf, unsigned char ch, unsigned len);
+#endif /* Use extern inlines. */
/* ---------------------------------------------------------------- */
@@ -156,6 +168,7 @@ struct disknode
/* Random extra info used by the ext2 routines. */
struct ext2_inode_info info;
+ uint32_t info_i_translator; /* That struct from Linux source lacks this. */
/* This file's pager. */
struct pager *pager;
@@ -163,6 +176,9 @@ struct disknode
/* True if the last page of the file has been made writable, but is only
partially allocated. */
int last_page_partially_writable;
+
+ /* Index to start a directory lookup at. */
+ int dir_idx;
};
struct user_pager_info
@@ -197,23 +213,34 @@ void flush_node_pager (struct node *node);
/* ---------------------------------------------------------------- */
-/* Our in-core copy of the super-block. */
+/* The physical media. */
+extern struct store *store;
+/* What the user specified. */
+extern struct store_parsed *store_parsed;
+
+/* Mapped image of the disk. */
+extern void *disk_image;
+
+/* Our in-core copy of the super-block (pointer into the disk_image). */
struct ext2_super_block *sblock;
/* True if sblock has been modified. */
int sblock_dirty;
/* Where the super-block is located on disk (at min-block 1). */
-#define SBLOCK_BLOCK 1
-#define SBLOCK_OFFS (SBLOCK_BLOCK * EXT2_MIN_BLOCK_SIZE)
-#define SBLOCK_SIZE (sizeof (struct ext2_super_block))
+#define SBLOCK_BLOCK 1 /* Default location, second 1k block. */
+#define SBLOCK_SIZE (sizeof (struct ext2_super_block))
+extern unsigned int sblock_block; /* Specified location (in 1k blocks). */
+#define SBLOCK_OFFS (sblock_block << 10) /* Byte offset of superblock. */
/* The filesystem block-size. */
-unsigned long block_size;
+unsigned int block_size;
/* The log base 2 of BLOCK_SIZE. */
-unsigned log2_block_size;
+unsigned int log2_block_size;
-/* log2 of the number of device blocks (DISKFS_DEVICE_BLOCK_SIZE) in a
- filesystem block (BLOCK_SIZE). */
+/* The number of bits to scale min-blocks to get filesystem blocks. */
+#define BLOCKSIZE_SCALE (sblock->s_log_block_size)
+
+/* log2 of the number of device blocks in a filesystem block. */
unsigned log2_dev_blocks_per_fs_block;
/* log2 of the number of stat blocks (512 bytes) in a filesystem block. */
@@ -226,14 +253,6 @@ vm_address_t zeroblock;
void get_hypermetadata ();
/* ---------------------------------------------------------------- */
-
-/* Returns a single page page-aligned buffer. */
-vm_address_t get_page_buf ();
-
-/* Frees a block returned by get_page_buf. */
-void free_page_buf (vm_address_t buf);
-
-/* ---------------------------------------------------------------- */
/* Random stuff calculated from the super block. */
unsigned long frag_size; /* Size of a fragment in bytes */
@@ -277,32 +296,28 @@ unsigned long next_generation;
#define bptr_block(ptr) boffs_block(bptr_offs(ptr))
/* Get the descriptor for block group NUM. The block group descriptors are
- stored starting in the block following the super block. */
-extern inline struct ext2_group_desc *
-group_desc(unsigned long num)
-{
- int desc_per_block = EXT2_DESC_PER_BLOCK(sblock);
- unsigned long group_desc = num / desc_per_block;
- unsigned long desc = num % desc_per_block;
- return
- ((struct ext2_group_desc *)boffs_ptr(SBLOCK_OFFS + boffs(1 + group_desc)))
- + desc;
-}
+ stored starting in the filesystem block following the super block.
+ We cache a pointer into the disk image for easy lookup. */
+#define group_desc(num) (&group_desc_image[num])
+struct ext2_group_desc *group_desc_image;
#define inode_group_num(inum) (((inum) - 1) / sblock->s_inodes_per_group)
+extern struct ext2_inode *dino (ino_t inum);
+
+#if defined(__USE_EXTERN_INLINES) || defined(EXT2FS_DEFINE_EI)
/* Convert an inode number to the dinode on disk. */
-extern inline struct ext2_inode *
+EXT2FS_EI struct ext2_inode *
dino (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);
- unsigned long inodes_per_block = EXT2_INODES_PER_BLOCK(sblock);
block_t block = bg->bg_inode_table + (group_inum / inodes_per_block);
return ((struct ext2_inode *)bptr(block)) + group_inum % inodes_per_block;
}
+#endif /* Use extern inlines. */
/* ---------------------------------------------------------------- */
/* inode.c */
@@ -331,11 +346,19 @@ struct pokel global_pokel;
char *modified_global_blocks;
spin_lock_t modified_global_blocks_lock;
+extern int global_block_modified (block_t block);
+extern void record_global_poke (void *ptr);
+extern void sync_global_ptr (void *bptr, int wait);
+extern void record_indir_poke (struct node *node, void *ptr);
+extern void sync_global (int wait);
+extern void alloc_sync (struct node *np);
+
+#if defined(__USE_EXTERN_INLINES) || defined(EXT2FS_DEFINE_EI)
/* Marks the global block BLOCK as being modified, and returns true if we
think it may have been clean before (but we may not be sure). Note that
this isn't enough to cause the block to be synced; you must call
record_global_poke to do that. */
-extern inline int
+EXT2FS_EI int
global_block_modified (block_t block)
{
if (modified_global_blocks)
@@ -351,7 +374,7 @@ global_block_modified (block_t block)
}
/* This records a modification to a non-file block. */
-extern inline void
+EXT2FS_EI void
record_global_poke (void *ptr)
{
int boffs = trunc_block (bptr_offs (ptr));
@@ -360,16 +383,16 @@ record_global_poke (void *ptr)
}
/* This syncs a modification to a non-file block. */
-extern inline void
+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 (disk_pager, trunc_page (boffs), vm_page_size, wait);
+ pager_sync_some (diskfs_disk_pager, trunc_page (boffs), vm_page_size, wait);
}
/* This records a modification to one of a file's indirect blocks. */
-extern inline void
+EXT2FS_EI void
record_indir_poke (struct node *node, void *ptr)
{
int boffs = trunc_block (bptr_offs (ptr));
@@ -379,14 +402,14 @@ record_indir_poke (struct node *node, void *ptr)
/* ---------------------------------------------------------------- */
-extern inline void
+EXT2FS_EI void
sync_global (int wait)
{
pokel_sync (&global_pokel, wait);
}
/* Sync all allocation information and node NP if diskfs_synchronous. */
-extern inline void
+EXT2FS_EI void
alloc_sync (struct node *np)
{
if (diskfs_synchronous)
@@ -399,18 +422,21 @@ alloc_sync (struct node *np)
diskfs_set_hypermetadata (1, 0);
}
}
+#endif /* Use extern inlines. */
/* ---------------------------------------------------------------- */
/* getblk.c */
void ext2_discard_prealloc (struct node *node);
-/* Returns in DISK_BLOCK the disk block correspding to BLOCK in NODE. If
- there is no such block yet, but CREATE is true, then it is created,
+/* Returns in DISK_BLOCK the disk block corresponding to BLOCK in NODE.
+ If there is no such block yet, but CREATE is true, then it is created,
otherwise EINVAL is returned. */
error_t ext2_getblk (struct node *node, block_t block, int create, block_t *disk_block);
-block_t ext2_new_block (block_t goal, block_t *prealloc_count, block_t *prealloc_block);
+block_t ext2_new_block (block_t goal,
+ block_t prealloc_goal,
+ block_t *prealloc_count, block_t *prealloc_block);
void ext2_free_blocks (block_t block, unsigned long count);
diff --git a/ext2fs/getblk.c b/ext2fs/getblk.c
index ecc69dcc..23ba6459 100644
--- a/ext2fs/getblk.c
+++ b/ext2fs/getblk.c
@@ -1,8 +1,8 @@
/* File block to disk block mapping routines
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,99,2000,2004 Free Software Foundation, Inc.
- Converted to work under the hurd by Miles Bader <miles@gnu.ai.mit.edu>
+ Converted to work under the hurd by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -38,14 +38,14 @@
#include <string.h>
#include "ext2fs.h"
-/*
+/*
* ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the
* superblock in the same manner as are ext2_free_blocks and
* ext2_new_block. We just wait on the super rather than locking it
* here, since ext2_new_block will do the necessary locking and we
* can't block until then.
*/
-void
+void
ext2_discard_prealloc (struct node *node)
{
#ifdef EXT2_PREALLOCATE
@@ -78,7 +78,7 @@ ext2_alloc_block (struct node *node, block_t goal, int zero)
{
result = node->dn->info.i_prealloc_block++;
node->dn->info.i_prealloc_count--;
- ext2_debug ("preallocation hit (%lu/%lu) => %lu",
+ ext2_debug ("preallocation hit (%lu/%lu) => %u",
++alloc_hits, ++alloc_attempts, result);
}
else
@@ -86,13 +86,17 @@ ext2_alloc_block (struct node *node, block_t goal, int zero)
ext2_debug ("preallocation miss (%lu/%lu)",
alloc_hits, ++alloc_attempts);
ext2_discard_prealloc (node);
- if (S_ISREG (node->dn_stat.st_mode))
- result =
- ext2_new_block (goal,
- &node->dn->info.i_prealloc_count,
- &node->dn->info.i_prealloc_block);
- else
- result = ext2_new_block (goal, 0, 0);
+ result = ext2_new_block
+ (goal,
+ S_ISREG (node->dn_stat.st_mode)
+ ? (sblock->s_prealloc_blocks ?: EXT2_DEFAULT_PREALLOC_BLOCKS)
+ : (S_ISDIR (node->dn_stat.st_mode)
+ && EXT2_HAS_COMPAT_FEATURE(sblock,
+ EXT2_FEATURE_COMPAT_DIR_PREALLOC))
+ ? sblock->s_prealloc_dir_blocks
+ : 0,
+ &node->dn->info.i_prealloc_count,
+ &node->dn->info.i_prealloc_block);
}
#else
result = ext2_new_block (goal, 0, 0);
@@ -150,7 +154,7 @@ inode_getblk (struct node *node, int nr, int create, int zero,
*result = ext2_alloc_block (node, goal, zero);
- ext2_debug ("%screate, hint = %lu, goal = %lu => %lu",
+ ext2_debug ("%screate, hint = %u, goal = %u => %u",
create ? "" : "no", hint, goal, *result);
if (!*result)
@@ -221,8 +225,8 @@ block_getblk (struct node *node, block_t block, int nr, int create, int zero,
return 0;
}
-/* Returns in DISK_BLOCK the disk block correspding to BLOCK in NODE. If
- there is no such block yet, but CREATE is true, then it is created,
+/* Returns in DISK_BLOCK the disk block corresponding to BLOCK in NODE.
+ If there is no such block yet, but CREATE is true, then it is created,
otherwise EINVAL is returned. */
error_t
ext2_getblk (struct node *node, block_t block, int create, block_t *disk_block)
@@ -235,7 +239,7 @@ ext2_getblk (struct node *node, block_t block, int create, block_t *disk_block)
addr_per_block * addr_per_block +
addr_per_block * addr_per_block * addr_per_block)
{
- ext2_warning ("block > big: %lu", block);
+ ext2_warning ("block > big: %u", block);
return EIO;
}
/*
@@ -244,7 +248,7 @@ ext2_getblk (struct node *node, block_t block, int create, block_t *disk_block)
* allocations use the same goal zone
*/
- ext2_debug ("block = %lu, next = %lu, goal = %lu", block,
+ ext2_debug ("block = %u, next = %u, goal = %u", block,
node->dn->info.i_next_alloc_block,
node->dn->info.i_next_alloc_goal);
diff --git a/ext2fs/hyper.c b/ext2fs/hyper.c
index f46d0fcb..bee4175f 100644
--- a/ext2fs/hyper.c
+++ b/ext2fs/hyper.c
@@ -1,8 +1,7 @@
/* Fetching and storing the hypermetadata (superblock and bg summary info)
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1994,95,96,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -21,20 +20,20 @@
#include <string.h>
#include <stdio.h>
#include <error.h>
+#include <hurd/store.h>
#include "ext2fs.h"
-vm_address_t zeroblock = 0;
-char *modified_global_blocks = 0;
+vm_address_t zeroblock;
+char *modified_global_blocks;
static void
allocate_mod_map (void)
{
- static vm_size_t mod_map_size = 0;
+ static vm_size_t mod_map_size;
if (modified_global_blocks && mod_map_size)
/* Get rid of the old one. */
- vm_deallocate (mach_task_self (),
- (vm_address_t)modified_global_blocks, mod_map_size);
+ munmap (modified_global_blocks, mod_map_size);
if (!diskfs_readonly && block_size < vm_page_size)
/* If the block size is too small, we have to take extra care when
@@ -42,18 +41,18 @@ allocate_mod_map (void)
on any file pager blocks. In this case use a bitmap to record which
global blocks are actually modified so the pager can write only them. */
{
- error_t err;
/* One bit per filesystem block. */
mod_map_size = sblock->s_blocks_count >> 3;
- err =
- vm_allocate (mach_task_self (),
- (vm_address_t *)&modified_global_blocks, mod_map_size, 1);
- assert_perror (err);
+ modified_global_blocks = mmap (0, mod_map_size, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ assert (modified_global_blocks != (void *) -1);
}
else
modified_global_blocks = 0;
}
+unsigned int sblock_block = SBLOCK_BLOCK; /* in 1k blocks */
+
static int ext2fs_clean; /* fs clean before we started writing? */
void
@@ -63,10 +62,7 @@ get_hypermetadata (void)
if (err)
ext2_panic ("can't read superblock: %s", strerror (err));
- if (zeroblock)
- vm_deallocate (mach_task_self (), zeroblock, block_size);
-
- sblock = (struct ext2_super_block *)boffs_ptr (SBLOCK_OFFS);
+ sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
if (sblock->s_magic != EXT2_SUPER_MAGIC
#ifdef EXT2FS_PRE_02B_COMPAT
@@ -76,38 +72,39 @@ get_hypermetadata (void)
ext2_panic ("bad magic number %#x (should be %#x)",
sblock->s_magic, EXT2_SUPER_MAGIC);
- block_size = EXT2_MIN_BLOCK_SIZE << sblock->s_log_block_size;
-
- if (block_size > 8192)
- ext2_panic ("block size %ld is too big (max is 8192 bytes)", block_size);
+ log2_block_size = EXT2_MIN_BLOCK_LOG_SIZE + sblock->s_log_block_size;
+ block_size = 1 << log2_block_size;
- log2_block_size = ffs (block_size) - 1;
- if ((1 << log2_block_size) != block_size)
- ext2_panic ("block size %ld isn't a power of two!", block_size);
+ if (block_size > EXT2_MAX_BLOCK_SIZE)
+ ext2_panic ("block size %d is too big (max is %d bytes)",
+ block_size, EXT2_MAX_BLOCK_SIZE);
- log2_dev_blocks_per_fs_block
- = log2_block_size - diskfs_log2_device_block_size;
+ log2_dev_blocks_per_fs_block = log2_block_size - store->log2_block_size;
if (log2_dev_blocks_per_fs_block < 0)
- ext2_panic ("block size %ld isn't a power-of-two multiple of the device"
- " block size (%d)!",
- block_size, diskfs_device_block_size);
+ ext2_panic ("block size %d isn't a power-of-two multiple of the device"
+ " block size (%zd)!",
+ block_size, store->block_size);
log2_stat_blocks_per_fs_block = 0;
while ((512 << log2_stat_blocks_per_fs_block) < block_size)
log2_stat_blocks_per_fs_block++;
if ((512 << log2_stat_blocks_per_fs_block) != block_size)
- ext2_panic ("block size %ld isn't a power-of-two multiple of 512!",
+ ext2_panic ("block size %d isn't a power-of-two multiple of 512!",
block_size);
- if (diskfs_device_size
- < (sblock->s_blocks_count << log2_dev_blocks_per_fs_block))
- ext2_panic ("disk size (%ld blocks) too small "
- "(superblock says we need %ld)",
- diskfs_device_size,
- sblock->s_blocks_count << log2_dev_blocks_per_fs_block);
+ if ((store->size >> log2_block_size) < sblock->s_blocks_count)
+ ext2_panic ("disk size (%qd bytes) too small; superblock says we need %qd",
+ (long long int) store->size,
+ (long long int) sblock->s_blocks_count << log2_block_size);
+ if (log2_dev_blocks_per_fs_block != 0
+ && (store->size & ((1 << log2_dev_blocks_per_fs_block) - 1)) != 0)
+ ext2_warning ("%Ld (%zd byte) device blocks "
+ " unused after last filesystem (%d byte) block",
+ (store->size & ((1 << log2_dev_blocks_per_fs_block) - 1)),
+ store->block_size, block_size);
/* Set these handy variables. */
- inodes_per_block = block_size / sizeof (struct ext2_inode);
+ inodes_per_block = block_size / EXT2_INODE_SIZE (sblock);
frag_size = EXT2_MIN_FRAG_SIZE << sblock->s_log_frag_size;
if (frag_size)
@@ -115,6 +112,23 @@ get_hypermetadata (void)
else
ext2_panic ("frag size is zero!");
+ if (sblock->s_rev_level > EXT2_GOOD_OLD_REV)
+ {
+ if (sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP)
+ ext2_panic ("could not mount because of unsupported optional features"
+ " (0x%x)",
+ sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP);
+ if (sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)
+ {
+ ext2_warning ("mounted readonly because of"
+ " unsupported optional features (0x%x)",
+ sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP);
+ diskfs_readonly = 1;
+ }
+ if (sblock->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
+ ext2_panic ("inode size %d isn't supported", sblock->s_inode_size);
+ }
+
groups_count =
((sblock->s_blocks_count - sblock->s_first_data_block +
sblock->s_blocks_per_group - 1)
@@ -140,11 +154,16 @@ get_hypermetadata (void)
diskfs_end_catch_exception ();
+ /* 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. */
- vm_allocate (mach_task_self (), &zeroblock, block_size, 1);
+ if (zeroblock == 0)
+ zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0);
}
-void
+error_t
diskfs_set_hypermetadata (int wait, int clean)
{
if (clean && ext2fs_clean && !(sblock->s_state & EXT2_VALID_FS))
@@ -168,6 +187,9 @@ diskfs_set_hypermetadata (int wait, int clean)
}
sync_global (wait);
+
+ /* Should check writability here and return EROFS if necessary. XXX */
+ return 0;
}
void
@@ -175,10 +197,9 @@ diskfs_readonly_changed (int readonly)
{
allocate_mod_map ();
- vm_protect (mach_task_self (),
- (vm_address_t)disk_image,
- diskfs_device_size << diskfs_log2_device_block_size,
- 0, VM_PROT_READ | (readonly ? 0 : VM_PROT_WRITE));
+ (*(readonly ? store_set_flags : store_clear_flags)) (store, STORE_READONLY);
+
+ mprotect (disk_image, store->size, PROT_READ | (readonly ? 0 : PROT_WRITE));
if (!readonly && !(sblock->s_state & EXT2_VALID_FS))
ext2_warning ("UNCLEANED FILESYSTEM NOW WRITABLE");
diff --git a/ext2fs/ialloc.c b/ext2fs/ialloc.c
index f2d9348e..15c17a4e 100644
--- a/ext2fs/ialloc.c
+++ b/ext2fs/ialloc.c
@@ -1,8 +1,8 @@
/* Inode allocation routines.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,99,2000,02 Free Software Foundation, Inc.
- Converted to work under the hurd by Miles Bader <miles@gnu.ai.mit.edu>
+ Converted to work under the hurd by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,7 +18,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/*
+/*
* linux/fs/ext2/ialloc.c
*
* Copyright (C) 1992, 1993, 1994, 1995
@@ -26,7 +26,7 @@
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
- * BSD ufs-inspired inode and directory allocation by
+ * BSD ufs-inspired inode and directory allocation by
* Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/
@@ -42,10 +42,11 @@
*/
#include "ext2fs.h"
+#include "bitmap.c"
/* ---------------------------------------------------------------- */
-/* Free node NP; the on disk copy has already been synced with
+/* Free node NP; the on disk copy has already been synced with
diskfs_node_update (where NP->dn_stat.st_mode was 0). It's
mode used to be OLD_MODE. */
void
@@ -63,9 +64,9 @@ diskfs_free_node (struct node *np, mode_t old_mode)
spin_lock (&global_lock);
- if (inum < EXT2_FIRST_INO || inum > sblock->s_inodes_count)
+ if (inum < EXT2_FIRST_INO (sblock) || inum > sblock->s_inodes_count)
{
- ext2_error ("reserved inode or nonexistent inode: %u", inum);
+ ext2_error ("reserved inode or nonexistent inode: %Ld", inum);
spin_unlock (&global_lock);
return;
}
@@ -77,7 +78,7 @@ diskfs_free_node (struct node *np, mode_t old_mode)
bh = bptr (gdp->bg_inode_bitmap);
if (!clear_bit (bit, bh))
- ext2_warning ("bit already cleared for inode %u", inum);
+ ext2_warning ("bit already cleared for inode %Ld", inum);
else
{
record_global_poke (bh);
@@ -236,7 +237,7 @@ repeat:
}
inum += i * sblock->s_inodes_per_group + 1;
- if (inum < EXT2_FIRST_INO || inum > sblock->s_inodes_count)
+ if (inum < EXT2_FIRST_INO (sblock) || inum > sblock->s_inodes_count)
{
ext2_error ("reserved inode or inode > inodes count - "
"block_group = %d,inode=%d", i, inum);
@@ -290,7 +291,6 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node)
if (st->st_blocks)
{
- ext2_warning("Free inode %d had %d blocks", inum, st->st_blocks);
st->st_blocks = 0;
np->dn_set_ctime = 1;
}
@@ -301,15 +301,23 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node)
np->dn->info.i_data[block] = 0;
np->dn_set_ctime = 1;
}
- np->istranslated = 0;
+ if (np->dn->info_i_translator != 0)
+ {
+ np->dn->info_i_translator = 0;
+ np->dn_set_ctime = 1;
+ }
+ st->st_mode &= ~S_IPTRANS;
if (np->allocsize)
{
- ext2_warning ("Free inode %d had a size of %ld", inum, st->st_size);
st->st_size = 0;
np->allocsize = 0;
np->dn_set_ctime = 1;
}
+ /* Propagate initial inode flags from the directory, as Linux does. */
+ np->dn->info.i_flags =
+ ext2_mask_flags(mode, dir->dn->info.i_flags & EXT2_FL_INHERITED);
+
st->st_flags = 0;
/*
@@ -330,7 +338,7 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node)
/* ---------------------------------------------------------------- */
-unsigned long
+unsigned long
ext2_count_free_inodes ()
{
#ifdef EXT2FS_DEBUG
@@ -353,7 +361,7 @@ ext2_count_free_inodes ()
i, gdp->bg_free_inodes_count, x);
bitmap_count += x;
}
- ext2_debug ("stored = %lu, computed = %lu, %lu",
+ ext2_debug ("stored = %u, computed = %lu, %lu",
sblock->s_free_inodes_count, desc_count, bitmap_count);
spin_unlock (&global_lock);
return desc_count;
@@ -364,7 +372,7 @@ ext2_count_free_inodes ()
/* ---------------------------------------------------------------- */
-void
+void
ext2_check_inodes_bitmap ()
{
int i;
diff --git a/ext2fs/inode.c b/ext2fs/inode.c
index 7704edbd..f25cc1fa 100644
--- a/ext2fs/inode.c
+++ b/ext2fs/inode.c
@@ -1,8 +1,9 @@
/* Inode management routines
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2007
+ Free Software Foundation, Inc.
- Converted for ext2fs by Miles Bader <miles@gnu.ai.mit.edu>
+ Converted for ext2fs by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,6 +23,21 @@
#include <string.h>
#include <unistd.h>
#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+
+/* these flags aren't actually defined by a header file yet, so temporarily
+ disable them if necessary. */
+#ifndef UF_APPEND
+#define UF_APPEND 0
+#endif
+#ifndef UF_NODUMP
+#define UF_NODUMP 0
+#endif
+#ifndef UF_IMMUTABLE
+#define UF_IMMUTABLE 0
+#endif
#define INOHSZ 512
#if ((INOHSZ&(INOHSZ-1)) == 0)
@@ -32,7 +48,7 @@
static struct node *nodehash[INOHSZ];
-static error_t read_disknode (struct node *np);
+static error_t read_node (struct node *np);
spin_lock_t generation_lock = SPIN_LOCK_INITIALIZER;
@@ -45,10 +61,10 @@ inode_init ()
nodehash[n] = 0;
}
-/* Fetch inode INUM, set *NPP to the node structure;
+/* Fetch inode INUM, set *NPP to the node structure;
gain one user reference and lock the node. */
-error_t
-diskfs_cached_lookup (int inum, struct node **npp)
+error_t
+diskfs_cached_lookup (ino_t inum, struct node **npp)
{
error_t err;
struct node *np;
@@ -64,7 +80,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
*npp = np;
return 0;
}
-
+
/* Format specific data for the new node. */
dn = malloc (sizeof (struct disknode));
if (! dn)
@@ -73,9 +89,10 @@ diskfs_cached_lookup (int inum, struct node **npp)
return ENOMEM;
}
dn->dirents = 0;
+ dn->dir_idx = 0;
dn->pager = 0;
rwlock_init (&dn->alloc_lock);
- pokel_init (&dn->indir_pokel, disk_pager, disk_image);
+ pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_image);
/* Create the new node. */
np = diskfs_make_node (dn);
@@ -91,10 +108,10 @@ diskfs_cached_lookup (int inum, struct node **npp)
nodehash[INOHASH(inum)] = np;
spin_unlock (&diskfs_node_refcnt_lock);
-
+
/* Get the contents of NP off disk. */
- err = read_disknode (np);
-
+ err = read_node (np);
+
if (!diskfs_check_readonly () && !np->dn_stat.st_gen)
{
spin_lock (&generation_lock);
@@ -104,7 +121,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
spin_unlock (&generation_lock);
np->dn_set_ctime = 1;
}
-
+
if (err)
return err;
else
@@ -120,13 +137,13 @@ struct node *
ifind (ino_t inum)
{
struct node *np;
-
+
spin_lock (&diskfs_node_refcnt_lock);
for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
{
if (np->cache_id != inum)
continue;
-
+
assert (np->references);
spin_unlock (&diskfs_node_refcnt_lock);
return np;
@@ -136,7 +153,7 @@ ifind (ino_t inum)
/* The last reference to a node has gone away; drop
it from the hash table and clean all state in the dn structure. */
-void
+void
diskfs_node_norefs (struct node *np)
{
*np->dn->hprevp = np->dn->hnext;
@@ -179,65 +196,77 @@ diskfs_new_hardrefs (struct node *np)
/* Read stat information out of the ext2_inode. */
static error_t
-read_disknode (struct node *np)
+read_node (struct node *np)
{
error_t err;
- unsigned offset;
- static int fsid, fsidset;
struct stat *st = &np->dn_stat;
struct disknode *dn = np->dn;
struct ext2_inode *di = dino (np->cache_id);
struct ext2_inode_info *info = &dn->info;
-
+
err = diskfs_catch_exception ();
if (err)
return err;
- np->istranslated = sblock->s_creator_os == EXT2_OS_HURD && di->i_translator;
-
- if (!fsidset)
- {
- fsid = getpid ();
- fsidset = 1;
- }
-
st->st_fstype = FSTYPE_EXT2FS;
- st->st_fsid = fsid;
+ st->st_fsid = getpid (); /* This call is very cheap. */
st->st_ino = np->cache_id;
st->st_blksize = vm_page_size * 2;
st->st_nlink = di->i_links_count;
st->st_size = di->i_size;
- st->st_gen = di->i_version;
+ st->st_gen = di->i_generation;
- st->st_atime = di->i_atime;
- st->st_mtime = di->i_mtime;
- st->st_ctime = di->i_ctime;
-
-#ifdef XXX
- st->st_atime_usec = di->i_atime.ts_nsec / 1000;
- st->st_mtime_usec = di->i_mtime.ts_nsec / 1000;
- st->st_ctime_usec = di->i_ctime.ts_nsec / 1000;
+ st->st_atim.tv_sec = di->i_atime;
+#ifdef not_yet
+ /* ``struct ext2_inode'' doesn't do better than sec. precision yet. */
+#else
+ st->st_atim.tv_nsec = 0;
+#endif
+ st->st_mtim.tv_sec = di->i_mtime;
+#ifdef not_yet
+ /* ``struct ext2_inode'' doesn't do better than sec. precision yet. */
+#else
+ st->st_mtim.tv_nsec = 0;
+#endif
+ st->st_ctim.tv_sec = di->i_ctime;
+#ifdef not_yet
+ /* ``struct ext2_inode'' doesn't do better than sec. precision yet. */
+#else
+ st->st_ctim.tv_nsec = 0;
#endif
st->st_blocks = di->i_blocks;
- st->st_flags = di->i_flags;
-
+
+ st->st_flags = 0;
+ if (di->i_flags & EXT2_APPEND_FL)
+ st->st_flags |= UF_APPEND;
+ if (di->i_flags & EXT2_NODUMP_FL)
+ st->st_flags |= UF_NODUMP;
+ if (di->i_flags & EXT2_IMMUTABLE_FL)
+ st->st_flags |= UF_IMMUTABLE;
+
if (sblock->s_creator_os == EXT2_OS_HURD)
{
st->st_mode = di->i_mode | (di->i_mode_high << 16);
+ st->st_mode &= ~S_ITRANS;
+ if (di->i_translator)
+ st->st_mode |= S_IPTRANS;
+
st->st_uid = di->i_uid | (di->i_uid_high << 16);
st->st_gid = di->i_gid | (di->i_gid_high << 16);
+
st->st_author = di->i_author;
if (st->st_author == -1)
st->st_author = st->st_uid;
}
else
{
- st->st_mode = di->i_mode;
+ st->st_mode = di->i_mode & ~S_ITRANS;
st->st_uid = di->i_uid;
st->st_gid = di->i_gid;
st->st_author = st->st_uid;
+ np->author_tracks_uid = 1;
}
/* Setup the ext2fs auxiliary inode info. */
@@ -248,32 +277,57 @@ read_disknode (struct node *np)
info->i_frag_size = di->i_fsize;
info->i_osync = 0;
info->i_file_acl = di->i_file_acl;
- info->i_dir_acl = di->i_dir_acl;
- info->i_version = di->i_version;
+ if (S_ISDIR (st->st_mode))
+ info->i_dir_acl = di->i_dir_acl;
+ else
+ {
+ info->i_dir_acl = 0;
+ info->i_high_size = di->i_size_high;
+ if (info->i_high_size) /* XXX */
+ {
+ ext2_warning ("cannot handle large file inode %Ld", np->cache_id);
+ return EFBIG;
+ }
+ }
info->i_block_group = inode_group_num (np->cache_id);
info->i_next_alloc_block = 0;
info->i_next_alloc_goal = 0;
info->i_prealloc_count = 0;
- if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
+ /* Set to a conservative value. */
+ dn->last_page_partially_writable = 0;
+
+ if (S_ISCHR (st->st_mode) || S_ISBLK (st->st_mode))
st->st_rdev = di->i_block[0];
else
{
- int block;
- for (block = 0; block < EXT2_N_BLOCKS; block++)
- info->i_data[block] = di->i_block[block];
+ memcpy (info->i_data, di->i_block,
+ EXT2_N_BLOCKS * sizeof info->i_data[0]);
st->st_rdev = 0;
}
+ dn->info_i_translator = di->i_translator;
diskfs_end_catch_exception ();
- /* Set these to conservative values. */
- dn->last_page_partially_writable = 0;
-
- np->allocsize = np->dn_stat.st_size;
- offset = np->allocsize & ((1 << log2_block_size) - 1);
- if (offset > 0)
- np->allocsize += block_size - offset;
+ 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;
+ }
+ else
+ /* Allocsize should be zero for anything except directories, files, and
+ long symlinks. These are the only things allowed to have any blocks
+ allocated as well, although st_size may be zero for any type (cases
+ where st_blocks=0 and st_size>0 include fast symlinks, and, under
+ linux, some devices). */
+ np->allocsize = 0;
return 0;
}
@@ -285,8 +339,17 @@ check_high_bits (struct node *np, long l)
{
if (sblock->s_creator_os == EXT2_OS_HURD)
return 0;
- else
- return ((l & ~0xFFFF) == 0) ? 0 : EINVAL;
+
+ /* Linux 2.3.42 has a mount-time option (not a bit stored on disk)
+ NO_UID32 to ignore the high 16 bits of uid and gid, but by default
+ allows them. It also does this check for "interoperability with old
+ kernels". Note that our check refuses to change the values, while
+ Linux 2.3.42 just silently clears the high bits in an inode it updates,
+ even if it was updating it for an unrelated reason. */
+ if (np->dn->info.i_dtime != 0)
+ return 0;
+
+ return ((l & ~0xFFFF) == 0) ? 0 : EINVAL;
}
/* Return 0 if NP's owner can be changed to UID; otherwise return an error
@@ -322,10 +385,22 @@ diskfs_validate_author_change (struct node *np, uid_t author)
if (sblock->s_creator_os == EXT2_OS_HURD)
return 0;
else
- /* For non-hurd filesystems, the auther & owner are the same. */
+ /* For non-hurd filesystems, the author & owner are the same. */
return (author == np->dn_stat.st_uid) ? 0 : EINVAL;
}
+/* The user may define this function. Return 0 if NP's flags can be
+ changed to FLAGS; otherwise return an error code. It must always
+ be possible to clear the flags. */
+error_t
+diskfs_validate_flags_change (struct node *np, int flags)
+{
+ if (flags & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND))
+ return EINVAL;
+ else
+ return 0;
+}
+
/* Writes everything from NP's inode to the disk image, and returns a pointer
to it, or NULL if nothing need be done. */
static struct ext2_inode *
@@ -337,10 +412,11 @@ write_node (struct node *np)
if (np->dn->info.i_prealloc_count)
ext2_discard_prealloc (np);
-
- assert (!np->dn_set_ctime && !np->dn_set_atime && !np->dn_set_mtime);
+
if (np->dn_stat_dirty)
{
+ struct ext2_inode_info *info = &np->dn->info;
+
assert (!diskfs_readonly);
ext2_debug ("writing inode %d to disk", np->cache_id);
@@ -348,8 +424,8 @@ write_node (struct node *np)
err = diskfs_catch_exception ();
if (err)
return NULL;
-
- di->i_version = st->st_gen;
+
+ di->i_generation = st->st_gen;
/* We happen to know that the stat mode bits are the same
as the ext2fs mode bits. */
@@ -357,14 +433,14 @@ write_node (struct node *np)
/* Only the low 16 bits of these fields are standard across all ext2
implementations. */
- di->i_mode = st->st_mode & 0xFFFF;
+ di->i_mode = st->st_mode & 0xFFFF & ~S_ITRANS;
di->i_uid = st->st_uid & 0xFFFF;
di->i_gid = st->st_gid & 0xFFFF;
if (sblock->s_creator_os == EXT2_OS_HURD)
/* If this is a hurd-compatible filesystem, write the high bits too. */
{
- di->i_mode_high = (st->st_mode >> 16) & 0xffff;
+ di->i_mode_high = (st->st_mode >> 16) & 0xffff & ~S_ITRANS;
di->i_uid_high = st->st_uid >> 16;
di->i_gid_high = st->st_gid >> 16;
di->i_author = st->st_author;
@@ -375,39 +451,57 @@ write_node (struct node *np)
assert ((st->st_uid & ~0xFFFF) == 0);
assert ((st->st_gid & ~0xFFFF) == 0);
assert ((st->st_mode & ~0xFFFF) == 0);
- assert (st->st_author == st->st_uid);
+ assert (np->author_tracks_uid && st->st_author == st->st_uid);
}
di->i_links_count = st->st_nlink;
- di->i_size = st->st_size;
-
- di->i_atime = st->st_atime;
- di->i_mtime = st->st_mtime;
- di->i_ctime = st->st_ctime;
-#ifdef XXX
- di->i_atime.ts_nsec = st->st_atime_usec * 1000;
- di->i_mtime.ts_nsec = st->st_mtime_usec * 1000;
- di->i_ctime.ts_nsec = st->st_ctime_usec * 1000;
-#endif
- di->i_blocks = st->st_blocks;
- di->i_flags = st->st_flags;
-
- if (!np->istranslated && sblock->s_creator_os == EXT2_OS_HURD)
- di->i_translator = 0;
+ di->i_atime = st->st_atim.tv_sec;
+#ifdef not_yet
+ /* ``struct ext2_inode'' doesn't do better than sec. precision yet. */
+ di->i_atime.tv_nsec = st->st_atim.tv_nsec;
+#endif
+ di->i_mtime = st->st_mtim.tv_sec;
+#ifdef not_yet
+ di->i_mtime.tv_nsec = st->st_mtim.tv_nsec;
+#endif
+ di->i_ctime = st->st_ctim.tv_sec;
+#ifdef not_yet
+ di->i_ctime.tv_nsec = st->st_ctim.tv_nsec;
+#endif
- /* Set dtime non-zero to indicate a deleted file. */
- di->i_dtime = (st->st_mode ? 0 : di->i_mtime);
+ /* Convert generic flags in ST->st_flags to ext2-specific flags in DI
+ (but don't mess with ext2 flags we don't know about). The original
+ set was copied from DI into INFO by read_node, but might have been
+ modified for ext2fs-specific reasons; so we use INFO->i_flags
+ to start with, and then apply the flags in ST->st_flags. */
+ info->i_flags &= ~(EXT2_APPEND_FL | EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL);
+ if (st->st_flags & UF_APPEND)
+ info->i_flags |= EXT2_APPEND_FL;
+ if (st->st_flags & UF_NODUMP)
+ info->i_flags |= EXT2_NODUMP_FL;
+ if (st->st_flags & UF_IMMUTABLE)
+ info->i_flags |= EXT2_IMMUTABLE_FL;
+ di->i_flags = info->i_flags;
+
+ if (st->st_mode == 0)
+ /* Set dtime non-zero to indicate a deleted file.
+ We don't clear i_size, i_blocks, and i_translator in this case,
+ to give "undeletion" utilities a chance. */
+ di->i_dtime = di->i_mtime;
+ else
+ {
+ di->i_dtime = 0;
+ di->i_size = st->st_size;
+ di->i_blocks = st->st_blocks;
+ }
if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
di->i_block[0] = st->st_rdev;
else
- {
- int block;
- for (block = 0; block < EXT2_N_BLOCKS; block++)
- di->i_block[block] = np->dn->info.i_data[block];
- }
-
+ memcpy (di->i_block, np->dn->info.i_data,
+ EXT2_N_BLOCKS * sizeof di->i_block[0]);
+
diskfs_end_catch_exception ();
np->dn_stat_dirty = 0;
@@ -431,7 +525,7 @@ diskfs_node_reload (struct node *node)
}
pokel_flush (&dn->indir_pokel);
flush_node_pager (node);
- read_disknode (node);
+ read_node (node);
return 0;
}
@@ -445,7 +539,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
error_t err = 0;
int n, num_nodes = 0;
struct node *node, **node_list, **p;
-
+
spin_lock (&diskfs_node_refcnt_lock);
/* We must copy everything from the hash table into another data structure
@@ -493,12 +587,12 @@ write_all_disknodes ()
{
struct ext2_inode *di;
- diskfs_set_node_times (node);
-
/* Sync the indirect blocks here; they'll all be done before any
inodes. Waiting for them shouldn't be too bad. */
pokel_sync (&node->dn->indir_pokel, 1);
+ diskfs_set_node_times (node);
+
/* Update the inode image. */
di = write_node (node);
if (di)
@@ -518,10 +612,12 @@ diskfs_write_disknode (struct node *np, int wait)
{
struct ext2_inode *di = write_node (np);
if (di)
- if (wait)
- sync_global_ptr (di, 1);
- else
- record_global_poke (di);
+ {
+ if (wait)
+ sync_global_ptr (di, 1);
+ else
+ record_global_poke (di);
+ }
}
/* Set *ST with appropriate values to reflect the current state of the
@@ -534,17 +630,21 @@ diskfs_set_statfs (struct statfs *st)
st->f_blocks = sblock->s_blocks_count;
st->f_bfree = sblock->s_free_blocks_count;
st->f_bavail = st->f_bfree - sblock->s_r_blocks_count;
+ if (st->f_bfree < sblock->s_r_blocks_count)
+ st->f_bavail = 0;
st->f_files = sblock->s_inodes_count;
st->f_ffree = sblock->s_free_inodes_count;
st->f_fsid = getpid ();
st->f_namelen = 0;
+ st->f_favail = st->f_ffree;
+ st->f_frsize = frag_size;
return 0;
}
-
+
/* Implement the diskfs_set_translator callback from the diskfs
library; see <hurd/diskfs.h> for the interface description. */
error_t
-diskfs_set_translator (struct node *np, char *name, unsigned namelen,
+diskfs_set_translator (struct node *np, const char *name, unsigned namelen,
struct protid *cred)
{
daddr_t blkno;
@@ -563,10 +663,10 @@ diskfs_set_translator (struct node *np, char *name, unsigned namelen,
err = diskfs_catch_exception ();
if (err)
return err;
-
+
di = dino (np->cache_id);
blkno = di->i_translator;
-
+
if (namelen && !blkno)
{
/* Allocate block for translator */
@@ -574,14 +674,15 @@ diskfs_set_translator (struct node *np, char *name, unsigned namelen,
ext2_new_block ((np->dn->info.i_block_group
* EXT2_BLOCKS_PER_GROUP (sblock))
+ sblock->s_first_data_block,
- 0, 0);
+ 0, 0, 0);
if (blkno == 0)
{
diskfs_end_catch_exception ();
return ENOSPC;
}
-
+
di->i_translator = blkno;
+ np->dn->info_i_translator = blkno;
record_global_poke (di);
np->dn_stat.st_blocks += 1 << log2_stat_blocks_per_fs_block;
@@ -591,14 +692,15 @@ diskfs_set_translator (struct node *np, char *name, unsigned namelen,
{
/* Clear block for translator going away. */
di->i_translator = 0;
+ np->dn->info_i_translator = 0;
record_global_poke (di);
ext2_free_blocks (blkno, 1);
np->dn_stat.st_blocks -= 1 << log2_stat_blocks_per_fs_block;
- np->istranslated = 0;
+ np->dn_stat.st_mode &= ~S_IPTRANS;
np->dn_set_ctime = 1;
}
-
+
if (namelen)
{
buf[0] = namelen & 0xFF;
@@ -608,10 +710,10 @@ diskfs_set_translator (struct node *np, char *name, unsigned namelen,
bcopy (buf, bptr (blkno), block_size);
record_global_poke (bptr (blkno));
- np->istranslated = 1;
+ np->dn_stat.st_mode |= S_IPTRANS;
np->dn_set_ctime = 1;
}
-
+
diskfs_end_catch_exception ();
return err;
}
@@ -621,10 +723,10 @@ diskfs_set_translator (struct node *np, char *name, unsigned namelen,
error_t
diskfs_get_translator (struct node *np, char **namep, unsigned *namelen)
{
- error_t err;
+ error_t err = 0;
daddr_t blkno;
unsigned datalen;
- void *transloc;
+ const void *transloc;
assert (sblock->s_creator_os == EXT2_OS_HURD);
@@ -635,18 +737,76 @@ diskfs_get_translator (struct node *np, char **namep, unsigned *namelen)
blkno = (dino (np->cache_id))->i_translator;
assert (blkno);
transloc = bptr (blkno);
-
+
datalen =
((unsigned char *)transloc)[0] + (((unsigned char *)transloc)[1] << 8);
- *namep = malloc (datalen);
- bcopy (transloc + 2, *namep, datalen);
+ if (datalen > block_size - 2)
+ err = EFTYPE; /* ? */
+ else
+ {
+ *namep = malloc (datalen);
+ if (!*namep)
+ err = ENOMEM;
+ else
+ memcpy (*namep, transloc + 2, datalen);
+ }
diskfs_end_catch_exception ();
*namelen = datalen;
+ return err;
+}
+
+/* The maximum size of a symlink store in the inode (including '\0'). */
+#define MAX_INODE_SYMLINK \
+ (EXT2_N_BLOCKS * sizeof (((struct ext2_inode *)0)->i_block[0]))
+
+/* Write an in-inode symlink, or return EINVAL if we can't. */
+static error_t
+write_symlink (struct node *node, const char *target)
+{
+ size_t len = strlen (target) + 1;
+
+ if (len > MAX_INODE_SYMLINK)
+ return EINVAL;
+
+ assert (node->dn_stat.st_blocks == 0);
+
+ bcopy (target, node->dn->info.i_data, len);
+ node->dn_stat.st_size = len - 1;
+ node->dn_set_ctime = 1;
+ node->dn_set_mtime = 1;
+
return 0;
}
+/* Read an in-inode symlink, or return EINVAL if we can't. */
+static error_t
+read_symlink (struct node *node, char *target)
+{
+ if (node->dn_stat.st_blocks)
+ return EINVAL;
+
+ assert (node->dn_stat.st_size < MAX_INODE_SYMLINK);
+
+ bcopy (node->dn->info.i_data, target, node->dn_stat.st_size);
+ return 0;
+}
+
+/* If this function is nonzero (and diskfs_shortcut_symlink is set) it
+ is called to set a symlink. If it returns EINVAL or isn't set,
+ then the normal method (writing the contents into the file data) is
+ used. If it returns any other error, it is returned to the user. */
+error_t (*diskfs_create_symlink_hook)(struct node *np, const char *target) =
+ write_symlink;
+
+/* If this function is nonzero (and diskfs_shortcut_symlink is set) it
+ is called to read the contents of a symlink. If it returns EINVAL or
+ isn't set, then the normal method (reading from the file data) is
+ used. If it returns any other error, it is returned to the user. */
+error_t (*diskfs_read_symlink_hook)(struct node *np, char *target) =
+ read_symlink;
+
/* Called when all hard ports have gone away. */
void
diskfs_shutdown_soft_ports ()
diff --git a/ext2fs/msg.c b/ext2fs/msg.c
index ba295070..727d926d 100644
--- a/ext2fs/msg.c
+++ b/ext2fs/msg.c
@@ -49,8 +49,7 @@ void _ext2_error (const char * function, const char * fmt, ...)
vsprintf (error_buf, fmt, args);
va_end (args);
- fprintf (stderr, "ext2fs: %s: %s: %s\n",
- diskfs_device_arg, function, error_buf);
+ fprintf (stderr, "ext2fs: %s: %s: %s\n", diskfs_disk_name, function, error_buf);
mutex_unlock(&printf_lock);
}
@@ -66,7 +65,7 @@ void _ext2_panic (const char * function, const char * fmt, ...)
va_end (args);
fprintf(stderr, "ext2fs: %s: panic: %s: %s\n",
- diskfs_device_arg, function, error_buf);
+ diskfs_disk_name, function, error_buf);
mutex_unlock(&printf_lock);
@@ -83,7 +82,7 @@ void ext2_warning (const char * fmt, ...)
vsprintf (error_buf, fmt, args);
va_end (args);
- fprintf (stderr, "ext2fs: %s: warning: %s\n", diskfs_device_arg, error_buf);
+ fprintf (stderr, "ext2fs: %s: warning: %s\n", diskfs_disk_name, error_buf);
mutex_unlock(&printf_lock);
}
diff --git a/ext2fs/pager.c b/ext2fs/pager.c
index dfc43a9f..0136f9b1 100644
--- a/ext2fs/pager.c
+++ b/ext2fs/pager.c
@@ -1,8 +1,8 @@
/* Pager for ext2fs
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,97,98,99,2000,02 Free Software Foundation, Inc.
- Converted for ext2fs by Miles Bader <miles@gnu.ai.mit.edu>
+ Converted for ext2fs by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,12 +18,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <hurd/store.h>
#include "ext2fs.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
@@ -32,13 +37,91 @@ spin_lock_t node_to_page_lock = SPIN_LOCK_INITIALIZER;
#define MAY_CACHE 1
#endif
-/* ---------------------------------------------------------------- */
+#define STATS
+
+#ifdef STATS
+struct ext2fs_pager_stats
+{
+ spin_lock_t lock;
+
+ unsigned long disk_pageins;
+ unsigned long disk_pageouts;
+
+ unsigned long file_pageins;
+ unsigned long file_pagein_reads; /* Device reads done by file pagein */
+ unsigned long file_pagein_freed_bufs; /* Discarded pages */
+ unsigned long file_pagein_alloced_bufs; /* Allocated pages */
+
+ unsigned long file_pageouts;
+
+ unsigned long file_page_unlocks;
+ unsigned long file_grows;
+};
+
+static struct ext2fs_pager_stats ext2s_pager_stats;
+
+#define STAT_INC(field) \
+do { spin_lock (&ext2s_pager_stats.lock); \
+ ext2s_pager_stats.field++; \
+ spin_unlock (&ext2s_pager_stats.lock); } while (0)
+#else /* !STATS */
+#define STAT_INC(field) /* nop */0
+#endif /* STATS */
+
+#define FREE_PAGE_BUFS 24
+
+/* Returns a single page page-aligned buffer. */
+static void *
+get_page_buf ()
+{
+ static struct mutex free_page_bufs_lock = MUTEX_INITIALIZER;
+ static void *free_page_bufs;
+ static int num_free_page_bufs;
+ void *buf;
+
+ mutex_lock (&free_page_bufs_lock);
+ if (num_free_page_bufs > 0)
+ {
+ buf = free_page_bufs;
+ num_free_page_bufs --;
+ if (num_free_page_bufs > 0)
+ free_page_bufs += vm_page_size;
+#ifndef NDEBUG
+ else
+ free_page_bufs = 0;
+#endif /* ! NDEBUG */
+ }
+ else
+ {
+ assert (free_page_bufs == 0);
+ buf = mmap (0, vm_page_size * FREE_PAGE_BUFS,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf == MAP_FAILED)
+ buf = 0;
+ else
+ {
+ free_page_bufs = buf + vm_page_size;
+ num_free_page_bufs = FREE_PAGE_BUFS - 1;
+ }
+ }
+
+ mutex_unlock (&free_page_bufs_lock);
+ return buf;
+}
+
+/* Frees a block returned by get_page_buf. */
+static inline void
+free_page_buf (void *buf)
+{
+ munmap (buf, vm_page_size);
+}
+
/* Find the location on disk of page OFFSET in NODE. Return the disk block
- in BLOCK (if unallocated, then return 0). If *LOCK is 0, then it a reader
- lock is aquired on NODE's ALLOC_LOCK before doing anything, and left
- locked after return -- even if an error is returned. 0 on success or an
- error code otherwise is returned. */
+ in BLOCK (if unallocated, then return 0). If *LOCK is 0, then a reader
+ lock is acquired on NODE's ALLOC_LOCK before doing anything, and left
+ locked after the return -- even if an error is returned. 0 is returned
+ on success otherwise an error code. */
static error_t
find_block (struct node *node, vm_offset_t offset,
block_t *block, struct rwlock **lock)
@@ -65,14 +148,12 @@ find_block (struct node *node, vm_offset_t offset,
return err;
}
-/* ---------------------------------------------------------------- */
-
/* Read one page for the pager backing NODE at offset PAGE, into BUF. This
may need to read several filesystem blocks to satisfy one page, and tries
to consolidate the i/o if possible. */
static error_t
file_pager_read_page (struct node *node, vm_offset_t page,
- vm_address_t *buf, int *writelock)
+ void **buf, int *writelock)
{
error_t err;
int offs = 0;
@@ -91,30 +172,47 @@ file_pager_read_page (struct node *node, vm_offset_t page,
if (num_pending_blocks > 0)
{
block_t dev_block = pending_blocks << log2_dev_blocks_per_fs_block;
- int length = num_pending_blocks << log2_block_size;
- vm_address_t new_buf;
+ 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
+ buffer, otherwise, we try to read directly into the tail of the
+ buffer we've already got. */
+ void *new_buf = *buf + offs;
+ size_t new_len = offs == 0 ? 0 : vm_page_size - offs;
+
+ STAT_INC (file_pagein_reads);
- err = diskfs_device_read_sync (dev_block, &new_buf, length);
+ err = store_read (store, dev_block, amount, &new_buf, &new_len);
if (err)
return err;
+ else if (amount != new_len)
+ return EIO;
- if (offs == 0)
- /* First read, make the returned page be our buffer. */
- *buf = new_buf;
- else
+ if (new_buf != *buf + offs)
{
- /* We've already got some buffer, so copy into it. */
- bcopy ((char *)new_buf, (char *)*buf + offs, length);
- vm_deallocate (mach_task_self (), new_buf, length);
+ /* The read went into a different buffer than the one we
+ passed. */
+ if (offs == 0)
+ /* First read, make the returned page be our buffer. */
+ *buf = new_buf;
+ else
+ /* We've already got some buffer, so copy into it. */
+ {
+ bcopy (new_buf, *buf + offs, new_len);
+ free_page_buf (new_buf); /* Return NEW_BUF to our pool. */
+ STAT_INC (file_pagein_freed_bufs);
+ }
}
- offs += length;
+ offs += new_len;
num_pending_blocks = 0;
}
return 0;
}
+ STAT_INC (file_pageins);
+
*writelock = 0;
if (page >= node->allocsize)
@@ -151,11 +249,12 @@ file_pager_read_page (struct node *node, vm_offset_t page,
if (offs == 0)
/* No page allocated to read into yet. */
{
- err = vm_allocate (mach_task_self (), buf, vm_page_size, 1);
- if (err)
+ *buf = get_page_buf ();
+ if (! *buf)
break;
+ STAT_INC (file_pagein_alloced_bufs);
}
- bzero ((char *)*buf + offs, block_size);
+ bzero (*buf + offs, block_size);
offs += block_size;
}
else
@@ -177,16 +276,14 @@ file_pager_read_page (struct node *node, vm_offset_t page,
return err;
}
-/* ---------------------------------------------------------------- */
-
struct pending_blocks
{
/* The block number of the first of the blocks. */
block_t block;
/* How many blocks we have. */
- int num;
+ off_t num;
/* A (page-aligned) buffer pointing to the data we're dealing with. */
- vm_address_t buf;
+ void *buf;
/* And an offset into BUF. */
int offs;
};
@@ -199,22 +296,24 @@ pending_blocks_write (struct pending_blocks *pb)
{
error_t err;
block_t dev_block = pb->block << log2_dev_blocks_per_fs_block;
- int length = pb->num << log2_block_size;
+ size_t length = pb->num << log2_block_size, amount;
- ext2_debug ("writing block %lu[%d]", 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. */
{
- vm_address_t page_buf = get_page_buf ();
- bcopy ((char *)pb->buf + pb->offs, (void *)page_buf, length);
- err = diskfs_device_write_sync (dev_block, page_buf, length);
+ void *page_buf = get_page_buf ();
+ bcopy (pb->buf + pb->offs, (void *)page_buf, length);
+ err = store_write (store, dev_block, page_buf, length, &amount);
free_page_buf (page_buf);
}
else
- err = diskfs_device_write_sync (dev_block, pb->buf, length);
+ err = store_write (store, dev_block, pb->buf, length, &amount);
if (err)
return err;
+ else if (amount != length)
+ return EIO;
pb->offs += length;
pb->num = 0;
@@ -224,7 +323,7 @@ pending_blocks_write (struct pending_blocks *pb)
}
static void
-pending_blocks_init (struct pending_blocks *pb, vm_address_t buf)
+pending_blocks_init (struct pending_blocks *pb, void *buf)
{
pb->buf = buf;
pb->block = 0;
@@ -258,32 +357,34 @@ pending_blocks_add (struct pending_blocks *pb, block_t block)
return 0;
}
-/* ---------------------------------------------------------------- */
-
/* Write one page for the pager backing NODE, at offset PAGE, 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
-file_pager_write_page (struct node *node, vm_offset_t offset, vm_address_t buf)
+file_pager_write_page (struct node *node, vm_offset_t offset, void *buf)
{
error_t err = 0;
struct pending_blocks pb;
- struct rwlock *lock = 0;
+ struct rwlock *lock = &node->dn->alloc_lock;
block_t block;
int left = vm_page_size;
pending_blocks_init (&pb, buf);
+ /* Holding NODE->dn->alloc_lock effectively locks NODE->allocsize,
+ at least for the cases we care about: pager_unlock_page,
+ diskfs_grow and diskfs_truncate. */
+ rwlock_reader_lock (&node->dn->alloc_lock);
+
if (offset >= node->allocsize)
- {
- err = EIO;
- left = 0;
- }
+ left = 0;
else if (offset + left > node->allocsize)
left = node->allocsize - offset;
ext2_debug ("writing inode %d page %d[%d]", node->cache_id, offset, left);
+ STAT_INC (file_pageouts);
+
while (left > 0)
{
err = find_block (node, offset, &block, &lock);
@@ -298,26 +399,24 @@ file_pager_write_page (struct node *node, vm_offset_t offset, vm_address_t buf)
if (!err)
pending_blocks_write (&pb);
- if (lock)
- rwlock_reader_unlock (lock);
+ rwlock_reader_unlock (&node->dn->alloc_lock);
return err;
}
-/* ---------------------------------------------------------------- */
-
static error_t
-disk_pager_read_page (vm_offset_t page, vm_address_t *buf, int *writelock)
+disk_pager_read_page (vm_offset_t page, void **buf, int *writelock)
{
error_t err;
- int length = vm_page_size;
- vm_size_t dev_end = diskfs_device_size << diskfs_log2_device_block_size;
+ size_t length = vm_page_size, read = 0;
+ vm_size_t dev_end = store->size;
if (page + vm_page_size > dev_end)
length = dev_end - page;
- err = diskfs_device_read_sync (page >> diskfs_log2_device_block_size,
- (void *)buf, length);
+ err = store_read (store, page >> 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);
@@ -327,17 +426,19 @@ disk_pager_read_page (vm_offset_t page, vm_address_t *buf, int *writelock)
}
static error_t
-disk_pager_write_page (vm_offset_t page, vm_address_t buf)
+disk_pager_write_page (vm_offset_t page, void *buf)
{
error_t err = 0;
- int length = vm_page_size;
- vm_size_t dev_end = diskfs_device_size << diskfs_log2_device_block_size;
+ size_t length = vm_page_size, amount;
+ vm_size_t dev_end = store->size;
if (page + vm_page_size > dev_end)
length = dev_end - page;
ext2_debug ("writing disk page %d[%d]", page, length);
+ STAT_INC (disk_pageouts);
+
if (modified_global_blocks)
/* Be picky about which blocks in a page that we write. */
{
@@ -374,26 +475,27 @@ disk_pager_write_page (vm_offset_t page, vm_address_t buf)
err = pending_blocks_write (&pb);
}
else
- err =
- diskfs_device_write_sync (page >> diskfs_log2_device_block_size,
- buf, length);
+ {
+ err = store_write (store, page >> store->log2_block_size,
+ buf, length, &amount);
+ if (!err && length != amount)
+ err = EIO;
+ }
return err;
}
-/* ---------------------------------------------------------------- */
-
/* 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
the pager should make the page writeable. */
error_t
pager_read_page (struct user_pager_info *pager, vm_offset_t page,
- vm_address_t *buf, int *writelock)
+ vm_address_t *buf, int *writelock)
{
if (pager->type == DISK)
- return disk_pager_read_page (page, buf, writelock);
+ return disk_pager_read_page (page, (void **)buf, writelock);
else
- return file_pager_read_page (pager->node, page, 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
@@ -403,13 +505,11 @@ pager_write_page (struct user_pager_info *pager, vm_offset_t page,
vm_address_t buf)
{
if (pager->type == DISK)
- return disk_pager_write_page (page, buf);
+ return disk_pager_write_page (page, (void *)buf);
else
- return file_pager_write_page (pager->node, page, buf);
+ return file_pager_write_page (pager->node, page, (void *)buf);
}
-/* ---------------------------------------------------------------- */
-
/* 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
file. */
@@ -465,20 +565,20 @@ pager_unlock_page (struct user_pager_info *pager, vm_offset_t page)
page, vm_page_size, node->cache_id);
#endif
+ STAT_INC (file_page_unlocks);
+
rwlock_writer_unlock (&dn->alloc_lock);
if (err == ENOSPC)
ext2_warning ("This filesystem is out of space, and will now crash. Bye!");
else if (err)
- ext2_warning ("inode=%d, page=0x%x: %s",
+ ext2_warning ("inode=%Ld, page=0x%zx: %s",
node->cache_id, page, strerror (err));
return err;
}
}
-/* ---------------------------------------------------------------- */
-
/* 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 identifies the user responsible
@@ -530,8 +630,8 @@ diskfs_grow (struct node *node, off_t size, struct protid *cred)
? new_end_block
: old_page_end_block);
- ext2_debug ("extending writable page %u by %ld blocks"
- "; first new block = %lu",
+ ext2_debug ("extending writable page %u by %d blocks"
+ "; first new block = %u",
trunc_page (old_size),
writable_end - end_block,
end_block);
@@ -544,9 +644,9 @@ diskfs_grow (struct node *node, off_t size, struct protid *cred)
}
diskfs_end_catch_exception ();
- if (err)
+ if (! err)
/* Reflect how much we allocated successfully. */
- new_size = (end_block - 1) << log2_block_size;
+ new_size = end_block << log2_block_size;
else
/* See if it's still valid to say this. */
dn->last_page_partially_writable =
@@ -554,11 +654,13 @@ diskfs_grow (struct node *node, off_t size, struct protid *cred)
}
}
+ STAT_INC (file_grows);
+
ext2_debug ("new size: %ld%s.", new_size,
dn->last_page_partially_writable
? " (last page writable)": "");
if (err)
- ext2_warning ("inode=%d, target=%ld: %s",
+ ext2_warning ("inode=%Ld, target=%Ld: %s",
node->cache_id, new_size, strerror (err));
node->allocsize = new_size;
@@ -571,8 +673,6 @@ diskfs_grow (struct node *node, off_t size, struct protid *cred)
return 0;
}
-/* ---------------------------------------------------------------- */
-
/* This syncs a single file (NODE) to disk. Wait for all I/O to complete
if WAIT is set. NODE->lock must be held. */
void
@@ -618,8 +718,6 @@ flush_node_pager (struct node *node)
}
-/* ---------------------------------------------------------------- */
-
/* Return in *OFFSET and *SIZE the minimum valid address the pager will
accept and the size of the object. */
inline error_t
@@ -631,7 +729,7 @@ pager_report_extent (struct user_pager_info *pager,
*offset = 0;
if (pager->type == DISK)
- *size = diskfs_device_size << diskfs_log2_device_block_size;
+ *size = store->size;
else
*size = pager->node->allocsize;
@@ -667,27 +765,17 @@ pager_dropweak (struct user_pager_info *p __attribute__ ((unused)))
{
}
-/* ---------------------------------------------------------------- */
-
-/* A top-level function for the paging thread that just services paging
- requests. */
-static void
-service_paging_requests (any_t foo __attribute__ ((unused)))
-{
- for (;;)
- ports_manage_port_operations_multithread (pager_bucket, pager_demuxer,
- 1000 * 60 * 2, 1000 * 60 * 10,
- 1, MACH_PORT_NULL);
-}
-
/* Create the DISK pager. */
void
create_disk_pager (void)
{
struct user_pager_info *upi = malloc (sizeof (struct user_pager_info));
-
+ if (!upi)
+ ext2_panic ("can't create disk pager: %s", strerror (errno));
upi->type = DISK;
- disk_pager_setup (upi, MAY_CACHE);
+ pager_bucket = ports_create_bucket ();
+ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size,
+ &disk_image);
}
/* Call this to create a FILE_DATA pager and return a send right.
@@ -723,11 +811,19 @@ diskfs_get_filemap (struct node *node, vm_prot_t prot)
malloc (sizeof (struct user_pager_info));
upi->type = FILE_DATA;
upi->node = node;
- upi->max_prot = 0;
+ upi->max_prot = prot;
diskfs_nref_light (node);
node->dn->pager =
pager_create (upi, pager_bucket, MAY_CACHE,
MEMORY_OBJECT_COPY_DELAY);
+ if (node->dn->pager == 0)
+ {
+ diskfs_nrele_light (node);
+ free (upi);
+ spin_unlock (&node_to_page_lock);
+ return MACH_PORT_NULL;
+ }
+
right = pager_get_port (node->dn->pager);
ports_port_deref (node->dn->pager);
}
@@ -755,7 +851,10 @@ drop_pager_softrefs (struct node *node)
spin_unlock (&node_to_page_lock);
if (MAY_CACHE && pager)
- pager_change_attributes (pager, 0, MEMORY_OBJECT_COPY_DELAY, 0);
+ {
+ pager_sync (pager, 0);
+ pager_change_attributes (pager, 0, MEMORY_OBJECT_COPY_DELAY, 0);
+ }
if (pager)
ports_port_deref (pager);
}
@@ -798,7 +897,7 @@ diskfs_shutdown_pager ()
error_t shutdown_one (void *v_p)
{
struct pager *p = v_p;
- if (p != disk_pager)
+ if (p != diskfs_disk_pager)
pager_shutdown (p);
return 0;
}
@@ -821,7 +920,7 @@ diskfs_sync_everything (int wait)
error_t sync_one (void *v_p)
{
struct pager *p = v_p;
- if (p != disk_pager)
+ if (p != diskfs_disk_pager)
pager_sync (p, wait);
return 0;
}
@@ -833,8 +932,6 @@ diskfs_sync_everything (int wait)
sync_global (wait);
}
-/* ---------------------------------------------------------------- */
-
static void
disable_caching ()
{
diff --git a/ext2fs/storeinfo.c b/ext2fs/storeinfo.c
index 419809c9..395ab5ca 100644
--- a/ext2fs/storeinfo.c
+++ b/ext2fs/storeinfo.c
@@ -19,7 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <string.h>
-#include <netinet/in.h> /* htonl */
+#include <hurd/store.h>
#include "ext2fs.h"
@@ -34,142 +34,97 @@ diskfs_S_file_get_storage_info (struct protid *cred,
char **data, mach_msg_type_number_t *data_len)
{
error_t err = 0;
- size_t name_len =
- (diskfs_device_name && *diskfs_device_name)
- ? strlen (diskfs_device_name) + 1 : 0;
- /* True when we've allocated memory for the corresponding vector. */
- int al_ports = 0, al_ints = 0, al_offsets = 0, al_data = 0;
-
- if (! cred)
- return EOPNOTSUPP;
-
-#define ENSURE_MEM(v, vl, alp, num) \
- if (!err && *vl < num) \
- { \
- err = vm_allocate (mach_task_self (), \
- (vm_address_t *)v, num * sizeof (**v), 1); \
- if (! err) \
- { \
- *vl = num; \
- alp = 1; \
- } \
- }
-
- /* Two longs. */
-#define MISC_LEN (sizeof (long) * 2)
-
- ENSURE_MEM (ports, num_ports, al_ports, 1);
- ENSURE_MEM (ints, num_ints, al_ints, 6);
- ENSURE_MEM (data, data_len, al_data, name_len + MISC_LEN);
- /* OFFSETS is more complex, and done below. */
-
- if (! err)
+ unsigned num_fs_blocks;
+ struct store *file_store;
+ struct store_run *runs, *run = 0;
+ block_t index = 0;
+ size_t num_runs = 0, runs_alloced = 10;
+ struct node *node = cred->po->np;
+
+ runs = malloc (runs_alloced * sizeof (struct store_run));
+ if (! runs)
+ return ENOMEM;
+
+ mutex_lock (&node->lock);
+
+ /* NUM_FS_BLOCKS counts down the blocks in the file that we've not
+ enumerated yet; when it hits zero, we can stop. */
+ if (node->dn_stat.st_size < node->dn_stat.st_blocks * 512)
+ /* The value indicated by st_blocks is too big (because it includes
+ indirect blocks), so use the size of the file. */
+ num_fs_blocks =
+ (node->dn_stat.st_size + block_size - 1) >> log2_block_size;
+ else
+ num_fs_blocks = node->dn_stat.st_blocks >> log2_stat_blocks_per_fs_block;
+
+ while (num_fs_blocks-- > 0)
{
- block_t index = 0;
- unsigned num_fs_blocks;
- off_t *run = *num_offsets ? *offsets : 0;
- struct node *node = cred->po->np;
-
- mutex_lock (&node->lock);
-
- num_fs_blocks = node->dn_stat.st_blocks >> log2_stat_blocks_per_fs_block;
- while (num_fs_blocks > 0)
+ block_t block;
+
+ err = ext2_getblk (node, index++, 0, &block);
+ if (err == EINVAL)
+ /* Either a hole, or past the end of the file.
+ A hole can't be mapped in runs since we don't know
+ where the blocks will be allocated, so we can't return the
+ underlying storage. */
+ err = EOPNOTSUPP;
+ if (err)
+ break;
+
+ block <<= log2_dev_blocks_per_fs_block;
+ if (num_runs == 0
+ || block != run->start + run->length) /* BLOCK doesn't follow RUN */
+ /* Add a new run. */
{
- block_t block;
-
- err = ext2_getblk (node, index++, 0, &block);
- if (err == EINVAL)
- /* Either a hole, or past the end of the file. */
- {
- block = 0;
- err = 0;
- }
- else if (err)
- break;
-
- block <<= log2_dev_blocks_per_fs_block;
- if (!run
- || ((block && run[0] >= 0) /* Neither is a hole and... */
- ? (block != run[0] + run[1]) /* BLOCK doesn't follow RUN */
- : (block || run[0] >= 0))) /* or one is, but not both */
- /* Add a new run. */
+ if (num_runs == runs_alloced)
+ /* Make some more space in RUNS. */
{
- run += 2;
- if (!run || run >= *offsets + *num_offsets)
- if (al_offsets)
- /* We've already allocated space for offsets; add a new
- page to the end of it. */
- {
- err =
- vm_allocate (mach_task_self (),
- (vm_address_t *)&run, vm_page_size, 0);
- if (err)
- break;
- *num_offsets += vm_page_size / sizeof (off_t);
- }
- else
- /* We've run out the space passed for inline offsets by
- the caller, so allocate our own memory and copy
- anything we've already stored. */
- {
- off_t *old = *offsets;
- size_t old_len = *num_offsets;
- err =
- vm_allocate (mach_task_self (),
- (vm_address_t *)offsets,
- old_len * sizeof (off_t) + vm_page_size, 1);
- if (err)
- break;
- if (old_len)
- bcopy (old, *offsets, old_len * sizeof (off_t));
- *num_offsets = old_len + vm_page_size / sizeof (off_t);
- run = *offsets;
- al_offsets = 1;
- }
-
- run[0] = block ?: -1; /* -1 means a hole in OFFSETS */
- run[1] = 0; /* will get extended just below */
+ struct store_run *new;
+ runs_alloced *= 2;
+ new = realloc (runs, runs_alloced * sizeof (struct store_run));
+ if (! new)
+ {
+ err = ENOMEM;
+ break;
+ }
+ runs = new;
}
- /* Increase the size of the current run by one filesystem block. */
- run[1] += 1 << log2_dev_blocks_per_fs_block;
-
- num_fs_blocks--;
+ run = runs + num_runs++;
+ run->start = block;
+ /* The length will get extended just below. */
+ run->length = 0;
}
- /* Fill in PORTS. Root gets device port, everyone else, nothing. */
- (*ports)[0] = diskfs_isuid (0, cred) ? diskfs_device : MACH_PORT_NULL;
- *ports_type = MACH_MSG_TYPE_COPY_SEND;
-
- /* Fill in INTS. */
- (*ints)[0] = STORAGE_DEVICE; /* type */
- (*ints)[1] = 0; /* flags */
- (*ints)[2] = diskfs_device_block_size; /* block size */
- (*ints)[3] = (run - *offsets) / 2; /* num runs */
- (*ints)[4] = name_len;
- (*ints)[5] = MISC_LEN;
-
- /* Fill in DATA. */
- if (name_len)
- strcpy (*data, diskfs_device_name);
- /* The following must be kept in sync with MISC_LEN. */
- ((long *)(*data + name_len))[0] = htonl (node->cache_id);
- ((long *)(*data + name_len))[1] =
- htonl (dino (node->cache_id)->i_translator);
-
- mutex_unlock (&node->lock);
+ /* Increase the size of the current run by one filesystem block. */
+ run->length += 1 << log2_dev_blocks_per_fs_block;
}
- if (err)
+ mutex_unlock (&node->lock);
+
+ if (! err)
+ err = store_clone (store, &file_store);
+ if (! err)
{
-#define DISCARD_MEM(v, vl, alp) \
- if (alp) \
- vm_deallocate (mach_task_self (), (vm_address_t)*v, *vl * sizeof **v);
- DISCARD_MEM (ports, num_ports, al_ports);
- DISCARD_MEM (ints, num_ints, al_ints);
- DISCARD_MEM (offsets, num_offsets, al_offsets);
- DISCARD_MEM (data, data_len, al_data);
+ err = store_remap (file_store, runs, num_runs, &file_store);
+ if (!err
+ && !idvec_contains (cred->user->uids, 0)
+ && !store_is_securely_returnable (file_store, cred->po->openstat))
+ {
+ err = store_set_flags (file_store, STORE_INACTIVE);
+ if (err == EINVAL)
+ err = EACCES;
+ }
+ if (! err)
+ {
+ *ports_type = MACH_MSG_TYPE_COPY_SEND;
+ err = store_return (file_store, ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+ }
+ store_free (file_store);
}
+ free (runs);
+
return err;
}
diff --git a/ext2fs/truncate.c b/ext2fs/truncate.c
index ebe8f374..077225b0 100644
--- a/ext2fs/truncate.c
+++ b/ext2fs/truncate.c
@@ -1,8 +1,8 @@
/* File truncation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,99,2000 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -102,7 +102,7 @@ trunc_direct (struct node *node, block_t end, struct free_block_run *fbr)
{
block_t *blocks = node->dn->info.i_data;
- ext2_debug ("truncating direct blocks from %ld", end);
+ ext2_debug ("truncating direct blocks from %d", end);
while (end < EXT2_NDIR_BLOCKS)
free_block_run_free_ptr (fbr, blocks + end++);
@@ -138,7 +138,10 @@ trunc_indirect (struct node *node, block_t end,
}
if (first == 0 && all_freed)
- free_block_run_free_ptr (fbr, p);
+ {
+ pager_flush_some (diskfs_disk_pager, boffs (*p), block_size, 1);
+ free_block_run_free_ptr (fbr, p);
+ }
else if (modified)
record_indir_poke (node, ind_bh);
}
@@ -205,7 +208,7 @@ poke_pages (memory_object_t obj, vm_offset_t start, vm_offset_t end)
vm_address_t poke;
for (poke = addr; poke < addr + len; poke += vm_page_size)
*(volatile int *)poke = *(volatile int *)poke;
- vm_deallocate (mach_task_self (), addr, len);
+ munmap ((caddr_t) addr, len);
}
start += len;
@@ -226,16 +229,22 @@ force_delayed_copies (struct node *node, off_t length)
if (pager)
ports_port_ref (pager);
spin_unlock (&node_to_page_lock);
-
+
if (pager)
{
mach_port_t obj;
-
+
pager_change_attributes (pager, MAY_CACHE, MEMORY_OBJECT_COPY_NONE, 1);
obj = diskfs_get_filemap (node, VM_PROT_READ);
- poke_pages (obj, round_page (length), round_page (node->allocsize));
- mach_port_deallocate (mach_task_self (), obj);
- pager_flush_some (pager, round_page(length), node->allocsize - length, 1);
+ if (obj != MACH_PORT_NULL)
+ {
+ /* XXX should cope with errors from diskfs_get_filemap */
+ poke_pages (obj, round_page (length), round_page (node->allocsize));
+ mach_port_deallocate (mach_task_self (), obj);
+ pager_flush_some (pager, round_page(length),
+ node->allocsize - length, 1);
+ }
+
ports_port_deref (pager);
}
}
@@ -263,7 +272,7 @@ enable_delayed_copies (struct node *node)
/* The user must define this function. Truncate locked node NODE to be SIZE
bytes long. (If NODE is already less than or equal to SIZE bytes
long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
- is set) then this should clear the symlink, even if
+ is set) then this should clear the symlink, even if
diskfs_create_symlink_hook stores the link target elsewhere. */
error_t
diskfs_truncate (struct node *node, off_t length)
@@ -277,13 +286,25 @@ diskfs_truncate (struct node *node, off_t length)
if (length >= node->dn_stat.st_size)
return 0;
+ if (! node->dn_stat.st_blocks)
+ /* There aren't really any blocks allocated, so just frob the size. This
+ is true for fast symlinks, and also apparently for some device nodes
+ in linux. */
+ {
+ node->dn_stat.st_size = length;
+ node->dn_set_mtime = 1;
+ node->dn_set_ctime = 1;
+ diskfs_node_update (node, 1);
+ return 0;
+ }
+
/*
* If the file is not being truncated to a block boundary, the
* contents of the partial block following the end of the file must be
* zeroed in case it ever becomes accessible again because of
* subsequent file growth.
*/
- offset = length % block_size;
+ offset = length & (block_size - 1);
if (offset > 0)
{
diskfs_node_rdwr (node, (void *)zeroblock, length, block_size - offset,
@@ -291,7 +312,7 @@ diskfs_truncate (struct node *node, off_t length)
diskfs_file_update (node, 1);
}
- ext2_discard_prealloc(node);
+ ext2_discard_prealloc (node);
force_delayed_copies (node, length);
@@ -304,7 +325,7 @@ diskfs_truncate (struct node *node, off_t length)
node->dn_set_ctime = 1;
diskfs_node_update (node, 1);
- err = diskfs_catch_exception();
+ err = diskfs_catch_exception ();
if (!err)
{
block_t end = boffs_block (round_block (length)), offs;
@@ -330,6 +351,8 @@ diskfs_truncate (struct node *node, off_t length)
won't hurt if is wrong. */
node->dn->last_page_partially_writable =
trunc_page (node->allocsize) != node->allocsize;
+
+ diskfs_end_catch_exception ();
}
node->dn_set_mtime = 1;
diff --git a/ext2fs/xinl.c b/ext2fs/xinl.c
new file mode 100644
index 00000000..9f37e166
--- /dev/null
+++ b/ext2fs/xinl.c
@@ -0,0 +1,2 @@
+#define EXT2FS_DEFINE_EI
+#include "ext2fs.h"
diff --git a/fatfs/Makefile b/fatfs/Makefile
new file mode 100644
index 00000000..06ed8778
--- /dev/null
+++ b/fatfs/Makefile
@@ -0,0 +1,30 @@
+# Copyright (C) 1997, 2003, 2007 Free Software Foundation
+# Modified by Marcus Brinkmann, 2000-05-05
+#
+# 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 := fatfs
+makemode := server
+
+target = fatfs
+SRCS = inode.c main.c dir.c pager.c fat.c virt-inode.c node-create.c
+LCLHDRS = fat.h fatfs.h virt-inode.h
+
+OBJS = $(SRCS:.c=.o)
+HURDLIBS = diskfs iohelp fshelp store pager threads ports ihash shouldbeinlibc
+
+include ../Makeconf
+
+fatfs.static: $(boot-store-types:%=../libstore/libstore_%.a)
diff --git a/fatfs/dir.c b/fatfs/dir.c
new file mode 100644
index 00000000..762320f8
--- /dev/null
+++ b/fatfs/dir.c
@@ -0,0 +1,999 @@
+/* dir.c - FAT filesystem.
+
+ Copyright (C) 1997, 1998, 1999, 2002, 2003, 2007
+ Free Software Foundation, Inc.
+
+ Written by Thomas Bushnell, n/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <ctype.h>
+#include <string.h>
+#include <dirent.h>
+#include <hurd/fsys.h>
+
+#include "fatfs.h"
+
+/* The size of a directory block is usually just the cluster size.
+ However, the root directory of FAT12/16 file systems is stored in
+ sectors in a special region, so we settle on the greatest common
+ divisor here. */
+#define DIRBLKSIZ bytes_per_sector
+#define LOG2_DIRBLKSIZ log2_bytes_per_sector
+
+enum slot_status
+{
+ /* This means we haven't yet found room for a new entry. */
+ LOOKING,
+
+ /* This means that the specified entry is free and should be used. */
+ TAKE,
+
+ /* This means that the specified entry has enough room at the end
+ to hold the new entry. */
+ SHRINK,
+
+ /* This means that there is enough space in the block, but not in
+ any one single entry, so they all have to be shifted to make
+ room. */
+ COMPRESS,
+
+ /* This means that the directory will have to be grown to hold the
+ entry. */
+ EXTEND,
+
+ /* For removal and rename, this means that this is the location
+ of the entry found. */
+ HERE_TIS,
+};
+
+struct dirstat
+{
+ /* Type of followp operation expected. */
+ enum lookup_type type;
+
+ /* One of the statuses above. */
+ enum slot_status stat;
+
+ /* Mapped address and length of directory. */
+ vm_address_t mapbuf;
+ vm_size_t mapextent;
+
+ /* Index of this directory block. */
+ int idx;
+
+ /* For stat COMPRESS, this is the address (inside mapbuf)
+ of the first direct in the directory block to be compressed. */
+ /* For stat HERE_TIS, SHRINK, and TAKE, this is the entry referenced. */
+ struct dirrect *entry;
+
+ /* For stat HERE_TIS, type REMOVE, this is the address of the immediately
+ previous direct in this directory block, or zero if this is the first. */
+ struct dirrect *preventry;
+
+ /* For stat COMPRESS, this is the number of bytes needed to be copied
+ in order to undertake the compression. */
+ size_t nbytes;
+};
+
+const size_t diskfs_dirstat_size = sizeof (struct dirstat);
+
+/* Initialize DS such that diskfs_drop_dirstat will ignore it. */
+void
+diskfs_null_dirstat (struct dirstat *ds)
+{
+ ds->type = LOOKUP;
+}
+
+/* Forward declaration. */
+static error_t
+dirscanblock (vm_address_t blockoff, struct node *dp, int idx,
+ const char *name, int namelen, enum lookup_type type,
+ struct dirstat *ds, ino_t *inum);
+
+static int
+fatnamematch (const char *dirname, const char *username, size_t unamelen)
+{
+ char *dn = strdup(dirname);
+ int dpos = 0;
+ int upos = 0;
+ int ext = 0;
+
+ /* Deleted files. */
+ if (dn[0] == FAT_DIR_NAME_DELETED || dn[0] == FAT_DIR_NAME_LAST)
+ return 0;
+ if (dn[0] == FAT_DIR_NAME_REPLACE_DELETED)
+ dn[0] = FAT_DIR_NAME_DELETED;
+
+ /* Special representations for `.' and `..'. */
+ if (!memcmp(dn, FAT_DIR_NAME_DOT, 11))
+ return unamelen == 1 && username[0] == '.';
+
+ if (!memcmp (dn, FAT_DIR_NAME_DOTDOT, 11))
+ return unamelen == 2 && username[0] == '.' && username[1] == '.';
+
+ if (unamelen > 12)
+ return 0;
+
+ do
+ {
+ /* First check if we have reached the extension without coming
+ across blanks. */
+ if (dpos == 8 && !ext)
+ {
+ if (username[upos] == '.')
+ {
+ upos++;
+ ext = 1;
+ }
+ else
+ break;
+ }
+ /* Second, skip blanks in base part. */
+ if (dn[dpos] == ' ')
+ {
+ if (ext)
+ break;
+ while (dpos < 8 && dn[++dpos] == ' ');
+ if (username[upos] == '.')
+ upos++;
+ ext = 1;
+ }
+ else
+ {
+ if (tolower(dn[dpos]) == tolower(username[upos]))
+ {
+ dpos++;
+ upos++;
+ }
+ else
+ break;
+ }
+ } while (upos < unamelen && dpos < 11);
+ while (dpos < 11 && dn[dpos] == ' ')
+ dpos++;
+ return (upos == unamelen && dpos == 11);
+}
+
+/* Implement the diskfs_lookup callback from the diskfs library. See
+ <hurd/diskfs.h> for the interface specification. */
+error_t
+diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type,
+ struct node **npp, struct dirstat *ds, struct protid *cred)
+{
+ error_t err;
+ ino_t inum;
+ int namelen;
+ int spec_dotdot;
+ struct node *np = 0;
+ int retry_dotdot = 0;
+ vm_prot_t prot =
+ (type == LOOKUP) ? VM_PROT_READ : (VM_PROT_READ | VM_PROT_WRITE);
+ memory_object_t memobj;
+ vm_address_t buf = 0;
+ vm_size_t buflen = 0;
+ int blockaddr;
+ int idx, lastidx;
+ int looped;
+
+ if ((type == REMOVE) || (type == RENAME))
+ assert (npp);
+
+ if (npp)
+ *npp = 0;
+
+ spec_dotdot = type & SPEC_DOTDOT;
+ type &= ~SPEC_DOTDOT;
+
+ namelen = strlen (name);
+
+ if (namelen > FAT_NAME_MAX)
+ return ENAMETOOLONG;
+
+ try_again:
+ if (ds)
+ {
+ ds->type = LOOKUP;
+ ds->mapbuf = 0;
+ ds->mapextent = 0;
+ }
+ if (buf)
+ {
+ munmap ((caddr_t) buf, buflen);
+ buf = 0;
+ }
+ if (ds && (type == CREATE || type == RENAME))
+ ds->stat = LOOKING;
+
+ /* Map in the directory contents. */
+ memobj = diskfs_get_filemap (dp, prot);
+
+ if (memobj == MACH_PORT_NULL)
+ return errno;
+
+ buf = 0;
+ /* We allow extra space in case we have to do an EXTEND. */
+ buflen = round_page (dp->dn_stat.st_size + DIRBLKSIZ);
+ err = vm_map (mach_task_self (),
+ &buf, buflen, 0, 1, memobj, 0, 0, prot, prot, 0);
+ mach_port_deallocate (mach_task_self (), memobj);
+
+ inum = 0;
+
+ diskfs_set_node_atime (dp);
+
+ /* Start the lookup at DP->dn->dir_idx. */
+ idx = dp->dn->dir_idx;
+ if (idx << LOG2_DIRBLKSIZ > dp->dn_stat.st_size)
+ idx = 0; /* just in case */
+ blockaddr = buf + (idx << LOG2_DIRBLKSIZ);
+ looped = (idx == 0);
+ lastidx = idx;
+ if (lastidx == 0)
+ lastidx = dp->dn_stat.st_size >> LOG2_DIRBLKSIZ;
+
+ while (!looped || idx < lastidx)
+ {
+ err = dirscanblock (blockaddr, dp, idx, name, namelen, type, ds, &inum);
+ if (!err)
+ {
+ dp->dn->dir_idx = idx;
+ break;
+ }
+ if (err != ENOENT)
+ {
+ munmap ((caddr_t) buf, buflen);
+ return err;
+ }
+
+ blockaddr += DIRBLKSIZ;
+ idx++;
+ if (blockaddr - buf >= dp->dn_stat.st_size && !looped)
+ {
+ /* We've gotten to the end; start back at the beginning. */
+ looped = 1;
+ blockaddr = buf;
+ idx = 0;
+ }
+ }
+
+ diskfs_set_node_atime (dp);
+ if (diskfs_synchronous)
+ diskfs_node_update (dp, 1);
+
+ /* If err is set here, it's ENOENT, and we don't want to
+ think about that as an error yet. */
+ err = 0;
+
+ if (inum && npp)
+ {
+ if (namelen != 2 || name[0] != '.' || name[1] != '.')
+ {
+ if (inum == dp->cache_id)
+ {
+ np = dp;
+ diskfs_nref (np);
+ }
+ else
+ {
+ err = diskfs_cached_lookup_in_dirbuf (inum, &np, buf);
+ if (err)
+ goto out;
+ }
+ }
+
+ /* We are looking up "..". */
+ /* Check to see if this is the root of the filesystem. */
+ else if (dp == diskfs_root_node)
+ {
+ err = EAGAIN;
+ goto out;
+ }
+
+ /* We can't just do diskfs_cached_lookup, because we would then
+ deadlock. So we do this. Ick. */
+ else if (retry_dotdot)
+ {
+ /* Check to see that we got the same answer as last time. */
+ if (inum != retry_dotdot)
+ {
+ /* Drop what we *thought* was .. (but isn't any more) and
+ try *again*. */
+ diskfs_nput (np);
+ mutex_unlock (&dp->lock);
+ err = diskfs_cached_lookup_in_dirbuf (inum, &np, buf);
+ mutex_lock (&dp->lock);
+ if (err)
+ goto out;
+ retry_dotdot = inum;
+ goto try_again;
+ }
+ /* Otherwise, we got it fine and np is already set properly. */
+ }
+ else if (!spec_dotdot)
+ {
+ /* Lock them in the proper order, and then
+ repeat the directory scan to see if this is still
+ right. */
+ mutex_unlock (&dp->lock);
+ err = diskfs_cached_lookup_in_dirbuf (inum, &np, buf);
+ mutex_lock (&dp->lock);
+ if (err)
+ goto out;
+ retry_dotdot = inum;
+ goto try_again;
+ }
+
+ /* Here below are the spec dotdot cases. */
+ else if (type == RENAME || type == REMOVE)
+ np = ifind (inum);
+
+ else if (type == LOOKUP)
+ {
+ diskfs_nput (dp);
+ err = diskfs_cached_lookup_in_dirbuf (inum, &np, buf);
+ if (err)
+ goto out;
+ }
+ else
+ assert (0);
+ }
+
+ if ((type == CREATE || type == RENAME) && !inum && ds && ds->stat == LOOKING)
+ {
+ /* We didn't find any room, so mark ds to extend the dir. */
+ ds->type = CREATE;
+ ds->stat = EXTEND;
+ ds->idx = dp->dn_stat.st_size >> LOG2_DIRBLKSIZ;
+ }
+
+ /* Return to the user; if we can't, release the reference
+ (and lock) we acquired above. */
+ out:
+ /* Deallocate or save the mapping. */
+ if ((err && err != ENOENT)
+ || !ds
+ || ds->type == LOOKUP)
+ {
+ munmap ((caddr_t) buf, buflen);
+ if (ds)
+ ds->type = LOOKUP; /* Set to be ignored by drop_dirstat. */
+ }
+ else
+ {
+ ds->mapbuf = buf;
+ ds->mapextent = buflen;
+ }
+
+ if (np)
+ {
+ assert (npp);
+ if (err)
+ {
+ if (!spec_dotdot)
+ {
+ /* Normal case. */
+ if (np == dp)
+ diskfs_nrele (np);
+ else
+ diskfs_nput (np);
+ }
+ else if (type == RENAME || type == REMOVE)
+ /* We just did ifind to get np; that allocates
+ no new references, so we don't have anything to do. */
+ ;
+ else if (type == LOOKUP)
+ /* We did diskfs_cached_lookup. */
+ diskfs_nput (np);
+ }
+ else
+ *npp = np;
+ }
+
+ return err ? : inum ? 0 : ENOENT;
+}
+
+/* Scan block at address BLKADDR (of node DP; block index IDX), for
+ name NAME of length NAMELEN. Args TYPE, DS are as for
+ diskfs_lookup. If found, set *INUM to the inode number, else
+ return ENOENT. */
+static error_t
+dirscanblock (vm_address_t blockaddr, struct node *dp, int idx,
+ const char *name, int namelen, enum lookup_type type,
+ struct dirstat *ds, ino_t *inum)
+{
+ int nfree = 0;
+ int needed = 0;
+ vm_address_t currentoff, prevoff = 0;
+ struct dirrect *entry = 0;
+ size_t nbytes = 0;
+ int looking = 0;
+ int countcopies = 0;
+ int consider_compress = 0;
+ inode_t inode;
+ vi_key_t entry_key = vi_zero_key;
+
+ /* FAT lacks the "." and ".." directory record in the root directory,
+ so we emulate them here. */
+ if (idx == 0 && dp == diskfs_root_node
+ && (fatnamematch (FAT_DIR_NAME_DOT, name, namelen)
+ || fatnamematch (FAT_DIR_NAME_DOTDOT, name, namelen)))
+ {
+ entry_key.dir_inode = diskfs_root_node->cache_id;
+ currentoff = blockaddr;
+ }
+ else
+ {
+ if (ds && (ds->stat == LOOKING
+ || ds->stat == COMPRESS))
+ {
+ looking = 1;
+ countcopies = 1;
+ needed = FAT_DIR_RECORDS (namelen);
+ }
+
+ for (currentoff = blockaddr, prevoff = 0;
+ currentoff < blockaddr + DIRBLKSIZ;
+ prevoff = currentoff, currentoff += FAT_DIR_REC_LEN)
+ {
+ entry = (struct dirrect *)currentoff;
+
+ if (looking || countcopies)
+ {
+ int thisfree;
+
+ /* Count how much free space this entry has in it. */
+ if ((char) entry->name[0] == FAT_DIR_NAME_LAST ||
+ (char) entry->name[0] == FAT_DIR_NAME_DELETED)
+ thisfree = FAT_DIR_REC_LEN;
+ else
+ thisfree = 0;
+
+ /* If this isn't at the front of the block, then it will
+ have to be copied if we do a compression; count the
+ number of bytes there too. */
+ if (countcopies && currentoff != blockaddr)
+ nbytes += FAT_DIR_REC_LEN;
+
+ if (ds->stat == COMPRESS && nbytes > ds->nbytes)
+ /* The previously found compress is better than this
+ one, so don't bother counting any more. */
+ countcopies = 0;
+
+ if (thisfree >= needed)
+ {
+ ds->type = CREATE;
+ ds->stat = TAKE;
+ ds->entry = entry;
+ ds->idx = idx;
+ looking = countcopies = 0;
+ }
+ else
+ {
+ nfree += thisfree;
+ if (nfree >= needed)
+ consider_compress = 1;
+ }
+ }
+
+ if (entry->attribute & FAT_DIR_ATTR_LABEL)
+ /* Either the volume label in root dir or a long filename
+ component. */
+ continue;
+
+ if (fatnamematch (entry->name, name, namelen))
+ break;
+ }
+
+ if (consider_compress
+ && (ds->type == LOOKING
+ || (ds->type == COMPRESS && ds->nbytes > nbytes)))
+ {
+ ds->type = CREATE;
+ ds->stat = COMPRESS;
+ ds->entry = (struct dirrect *) blockaddr;
+ ds->idx = idx;
+ ds->nbytes = nbytes;
+ }
+ }
+
+ if (currentoff >= blockaddr + DIRBLKSIZ)
+ {
+ /* The name is not in this block. */
+
+ return ENOENT;
+ }
+
+ /* We have found the required name. */
+
+ if (ds && type == CREATE)
+ ds->type = LOOKUP; /* It's invalid now. */
+ else if (ds && (type == REMOVE || type == RENAME))
+ {
+ ds->type = type;
+ ds->stat = HERE_TIS;
+ ds->entry = entry;
+ ds->idx = idx;
+ ds->preventry = (struct dirrect *) prevoff;
+ }
+
+ if (entry_key.dir_inode)
+ {
+ /* The required name is "." or ".." in the root dir. */
+ *inum = entry_key.dir_inode;
+ }
+ else if ((entry->attribute & FAT_DIR_ATTR_DIR)
+ && !memcmp (entry->name, FAT_DIR_NAME_DOT, 11))
+ {
+ /* "." and ".." have to be treated special. We don't want their
+ directory records, but the records of the directories they
+ point to. */
+
+ *inum = dp->cache_id;
+ }
+ else if ((entry->attribute & FAT_DIR_ATTR_DIR)
+ && !memcmp (entry->name, FAT_DIR_NAME_DOTDOT, 11))
+ {
+ if (entry->first_cluster_low[0] == 0
+ && entry->first_cluster_low[1] == 0
+ && entry->first_cluster_high[0] == 0
+ && entry->first_cluster_high[1] == 0)
+ {
+ *inum = diskfs_root_node->cache_id;
+ }
+ else
+ {
+ struct vi_key vk = vi_key (dp->dn->inode);
+ *inum = vk.dir_inode;
+ }
+ }
+ else
+ {
+ entry_key.dir_inode = dp->cache_id;
+ entry_key.dir_offset = (currentoff - blockaddr) + (idx << LOG2_DIRBLKSIZ);
+ return vi_rlookup(entry_key, inum, &inode, 1);
+ }
+ return 0;
+}
+
+/* Following a lookup call for CREATE, this adds a node to a
+ directory. DP is the directory to be modified; NAME is the name to
+ be entered; NP is the node being linked in; DS is the cached
+ information returned by lookup; CRED describes the user making the
+ call. This call may only be made if the directory has been held
+ locked continuously since the preceding lookup call, and only if
+ that call returned ENOENT. */
+error_t
+diskfs_direnter_hard (struct node *dp, const char *name, struct node *np,
+ struct dirstat *ds, struct protid *cred)
+{
+ struct dirrect *new;
+ int namelen = strlen (name);
+ int needed = FAT_DIR_RECORDS (namelen);
+ error_t err;
+ loff_t oldsize = 0;
+
+ assert (ds->type == CREATE);
+
+ assert (!diskfs_readonly);
+
+ dp->dn_set_mtime = 1;
+
+ /* Select a location for the new directory entry. Each branch of
+ this switch is responsible for setting NEW to point to the
+ on-disk directory entry being written. */
+
+ switch (ds->stat)
+ {
+ case TAKE:
+ /* We are supposed to consume this slot. */
+ assert ((char)ds->entry->name[0] == FAT_DIR_NAME_LAST
+ || (char)ds->entry->name[0] == FAT_DIR_NAME_DELETED);
+
+ new = ds->entry;
+ break;
+
+ case EXTEND:
+ /* Extend the file. */
+ assert (needed <= bytes_per_cluster);
+
+ oldsize = dp->dn_stat.st_size;
+ while (oldsize + bytes_per_cluster > dp->allocsize)
+ {
+ err = diskfs_grow (dp, oldsize + bytes_per_cluster, cred);
+ if (err)
+ {
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+ return err;
+ }
+ memset ((caddr_t) ds->mapbuf + oldsize, 0, bytes_per_cluster);
+ }
+
+ new = (struct dirrect *) ((char *) ds->mapbuf + oldsize);
+
+ dp->dn_stat.st_size = oldsize + bytes_per_cluster;
+ dp->dn_set_ctime = 1;
+
+ break;
+
+ case SHRINK:
+ case COMPRESS:
+ default:
+ assert(0);
+
+ /* COMPRESS will be used later, with long filenames, but shrink
+ does not make sense on fat, as all entries have fixed
+ size. */
+ }
+
+ /* NEW points to the directory entry being written. Now fill in the
+ data. */
+
+ memcpy (new->name, " ", 11);
+ memcpy (new->name, name, namelen % 11); /* XXX */
+
+ write_word (new->first_cluster_low, np->dn->start_cluster & 0xffff);
+ write_word (new->first_cluster_high, np->dn->start_cluster >> 16);
+ write_dword (new->file_size, np->dn_stat.st_size);
+
+ if (!(name[0] == '.' && (name[1] == '\0'
+ || (name[1] == '.' && name[2] =='\0'))))
+ {
+ vi_key_t entry_key;
+
+ entry_key.dir_inode = dp->cache_id;
+ entry_key.dir_offset = ((int) ds->entry) - ((int) ds->mapbuf);
+
+ /* Set the key for this inode now because it wasn't know when
+ the inode was initialized. */
+ vi_change (vi_lookup (np->cache_id), entry_key);
+
+ if (np->dn_stat.st_mode & S_IFDIR)
+ new->attribute = FAT_DIR_ATTR_DIR;
+ }
+ else
+ new->attribute = FAT_DIR_ATTR_DIR;
+
+ /* Mark the directory inode has having been written. */
+ dp->dn_set_mtime = 1;
+
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+
+ diskfs_file_update (dp, 1);
+
+ return 0;
+}
+
+/* Following a lookup call for REMOVE, this removes the link from the
+ directory. DP is the directory being changed and DS is the cached
+ information returned from lookup. This call is only valid if the
+ directory has been locked continuously since the call to lookup, and
+ only if that call succeeded. */
+error_t
+diskfs_dirremove_hard (struct node *dp, struct dirstat *ds)
+{
+ assert (ds->type == REMOVE);
+ assert (ds->stat == HERE_TIS);
+
+ assert (!diskfs_readonly);
+
+ dp->dn_set_mtime = 1;
+
+ ds->entry->name[0] = FAT_DIR_NAME_DELETED;
+
+ /* XXX Do something with dirrect? inode? */
+
+ dp->dn_set_mtime = 1;
+
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+
+ diskfs_file_update (dp, 1);
+
+ return 0;
+}
+
+/* Following a lookup call for RENAME, this changes the inode number
+ on a directory entry. DP is the directory being changed; NP is the
+ new node being linked in; DP is the cached information returned by
+ lookup. This call is only valid if the directory has been locked
+ continuously since the call to lookup, and only if that call
+ succeeded. */
+error_t
+diskfs_dirrewrite_hard (struct node *dp, struct node *np, struct dirstat *ds)
+{
+ error_t err;
+ vi_key_t entry_key;
+ mach_port_t control = MACH_PORT_NULL;
+ struct node *oldnp;
+ ino_t inode;
+ inode_t vinode;
+
+ /* We need the inode and vinode of the old node. */
+ entry_key.dir_inode = dp->cache_id;
+ entry_key.dir_offset = ((int) ds->entry) - ((int) ds->mapbuf);
+ err = vi_rlookup (entry_key, &inode, &vinode, 0);
+
+ assert (err != EINVAL);
+
+ /* Lookup the node, we already have a reference. */
+ oldnp = ifind (inode);
+
+ assert (ds->type == RENAME);
+ assert (ds->stat == HERE_TIS);
+
+ assert (!diskfs_readonly);
+
+ /* The link count must be 0 so the file will be removed and
+ the node will be dropped. */
+ oldnp->dn_stat.st_nlink--;
+ assert (!oldnp->dn_stat.st_nlink);
+
+ /* Close the file, free the referenced held by clients. */
+ fshelp_fetch_control (&oldnp->transbox, &control);
+
+ if (control)
+ {
+ fsys_goaway (control, FSYS_GOAWAY_UNLINK);
+ mach_port_deallocate (mach_task_self (), control);
+ }
+
+ /* Put the new key in the vinode. */
+ vi_change (vi_lookup (np->cache_id), entry_key);
+
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+
+ dp->dn_set_mtime = 1;
+ diskfs_file_update (dp, 1);
+
+ return 0;
+}
+
+/* Tell if DP is an empty directory (has only "." and ".." entries).
+ This routine must be called from inside a catch_exception (). */
+int
+diskfs_dirempty (struct node *dp, struct protid *cred)
+{
+ error_t err;
+ vm_address_t buf = 0, curoff;
+ struct dirrect *entry;
+ int hit = 0; /* Found something in the directory. */
+ memory_object_t memobj = diskfs_get_filemap (dp, VM_PROT_READ);
+
+ if (memobj == MACH_PORT_NULL)
+ /* XXX should reflect error properly. */
+ return 0;
+
+ err = vm_map (mach_task_self (), &buf, dp->dn_stat.st_size, 0,
+ 1, memobj, 0, 0, VM_PROT_READ, VM_PROT_READ, 0);
+ mach_port_deallocate (mach_task_self (), memobj);
+ assert (!err);
+
+ diskfs_set_node_atime (dp);
+
+ for (curoff = buf;
+ !hit && curoff < buf + dp->dn_stat.st_size;
+ curoff += FAT_DIR_REC_LEN)
+ {
+ entry = (struct dirrect *) curoff;
+
+ if (entry->name[0] == FAT_DIR_NAME_LAST)
+ break;
+ if ((char) entry->name[0] != FAT_DIR_NAME_DELETED
+ && memcmp (entry->name, FAT_DIR_NAME_DOT, 11)
+ && memcmp (entry->name, FAT_DIR_NAME_DOTDOT, 11))
+ hit = 1;
+ }
+
+ diskfs_set_node_atime (dp);
+ if (diskfs_synchronous)
+ diskfs_node_update (dp, 1);
+
+ munmap ((caddr_t) buf, dp->dn_stat.st_size);
+
+ return !hit;
+}
+
+/* Make DS an invalid dirstat. */
+error_t
+diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
+{
+ if (ds->type != LOOKUP)
+ {
+ assert (ds->mapbuf);
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+ ds->type = LOOKUP;
+ }
+ return 0;
+}
+
+
+/* Implement the diskfs_get_directs callback as described in
+ <hurd/diskfs.h>. */
+error_t
+diskfs_get_directs (struct node *dp,
+ int entry,
+ int nentries,
+ char **data,
+ u_int *datacnt,
+ vm_size_t bufsiz,
+ int *amt)
+{
+ volatile vm_size_t allocsize;
+ struct dirrect *ep;
+ struct dirent *userp;
+ int i;
+ char *datap;
+ volatile int ouralloc = 0;
+ error_t err;
+ vm_prot_t prot = VM_PROT_READ;
+ memory_object_t memobj;
+ vm_address_t buf = 0, bufp;
+ vm_size_t buflen = 0;
+
+ /* Allocate some space to hold the returned data. */
+ allocsize = bufsiz ? round_page (bufsiz) : vm_page_size * 4;
+ if (allocsize > *datacnt)
+ {
+ *data = mmap (0, allocsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ ouralloc = 1;
+ }
+
+ /* Map in the directory contents. */
+ memobj = diskfs_get_filemap (dp, prot);
+
+ if (memobj == MACH_PORT_NULL)
+ return errno;
+
+ /* We allow extra space in case we have to do an EXTEND. */
+ buflen = round_page (dp->dn_stat.st_size);
+ err = vm_map (mach_task_self (),
+ &buf, buflen, 0, 1, memobj, 0, 0, prot, prot, 0);
+ mach_port_deallocate (mach_task_self (), memobj);
+
+ bufp = buf;
+ for (i = 0; i < entry; i ++)
+ {
+ /* The root directory in FAT file systems doesn't contain
+ entries for DOT and DOTDOT, they are special cased below. */
+ if (dp == diskfs_root_node && i < 2)
+ continue;
+
+ ep = (struct dirrect *) bufp;
+
+ if (bufp >= buf + buflen || (char)ep->name[0] == FAT_DIR_NAME_LAST)
+ {
+ /* Not that many entries in the directory; return nothing. */
+ if (allocsize > *datacnt)
+ munmap (data, allocsize);
+ munmap ((caddr_t) buf, buflen);
+ *datacnt = 0;
+ *amt = 0;
+ return 0;
+ }
+
+ /* Ignore and skip deleted and label entries (catches also long
+ filenames). */
+ if ((char)ep->name[0] == FAT_DIR_NAME_DELETED
+ || (ep->attribute & FAT_DIR_ATTR_LABEL))
+ i--;
+ bufp = bufp + FAT_DIR_REC_LEN;
+ }
+
+ /* Now copy entries one at a time. */
+ i = 0;
+ datap = *data;
+ while (((nentries == -1) || (i < nentries))
+ && (!bufsiz || datap - *data < bufsiz)
+ && bufp < buf + buflen)
+ {
+ char name[13];
+ size_t namlen, reclen;
+ struct dirrect dot = { FAT_DIR_NAME_DOT, FAT_DIR_ATTR_DIR };
+ struct dirrect dotdot = { FAT_DIR_NAME_DOTDOT, FAT_DIR_ATTR_DIR };
+
+ /* The root directory in FAT file systems doesn't contain
+ entries for DOT and DOTDOT, they are special cased below. */
+ if (dp == diskfs_root_node && (i + entry == 0))
+ ep = &dot;
+ else if (dp == diskfs_root_node && (i + entry == 1))
+ ep = &dotdot;
+ else
+ ep = (struct dirrect *) bufp;
+
+ if ((char)ep->name[0] == FAT_DIR_NAME_LAST)
+ {
+ /* Last entry. */
+ bufp = buf + buflen;
+ continue;
+ }
+
+ if ((char)ep->name[0] == FAT_DIR_NAME_DELETED || (ep->attribute & FAT_DIR_ATTR_LABEL))
+ {
+ bufp = bufp + FAT_DIR_REC_LEN;
+ continue;
+ }
+
+ /* See if there's room to hold this one. */
+
+ fat_to_unix_filename(ep->name, name);
+ namlen = strlen(name);
+
+ /* Perhaps downcase it? */
+
+ reclen = sizeof (struct dirent) + namlen;
+ reclen = (reclen + 3) & ~3;
+
+ /* Expand buffer if necessary. */
+ if (datap - *data + reclen > allocsize)
+ {
+ vm_address_t newdata;
+
+ vm_allocate (mach_task_self (), &newdata,
+ (ouralloc
+ ? (allocsize *= 2)
+ : (allocsize = vm_page_size * 2)), 1);
+ memcpy ((void *) newdata, (void *) *data, datap - *data);
+
+ if (ouralloc)
+ munmap (*data, allocsize / 2);
+
+ datap = (char *) newdata + (datap - *data);
+ *data = (char *) newdata;
+ ouralloc = 1;
+ }
+
+ userp = (struct dirent *) datap;
+
+ /* Fill in entry. */
+ {
+ ino_t inode;
+ inode_t v_inode;
+ vi_key_t entry_key;
+
+ entry_key.dir_inode = dp->cache_id;
+ entry_key.dir_offset = bufp - buf;
+
+ vi_rlookup (entry_key, &inode, &v_inode, 1);
+ userp->d_fileno = inode;
+ }
+ userp->d_type = DT_UNKNOWN;
+ userp->d_reclen = reclen;
+ userp->d_namlen = namlen;
+ memcpy (userp->d_name, name, namlen);
+ userp->d_name[namlen] = '\0';
+
+ /* And move along. */
+ datap = datap + reclen;
+ if (!(dp == diskfs_root_node && i + entry < 2))
+ bufp = bufp + FAT_DIR_REC_LEN;
+ i++;
+ }
+
+ /* If we didn't use all the pages of a buffer we allocated, free
+ the excess. */
+ if (ouralloc
+ && round_page (datap - *data) < round_page (allocsize))
+ munmap ((caddr_t) round_page (datap),
+ round_page (allocsize) - round_page (datap - *data));
+
+ munmap ((caddr_t) buf, buflen);
+
+ /* Return. */
+ *amt = i;
+ *datacnt = datap - *data;
+ return 0;
+}
diff --git a/fatfs/fat.c b/fatfs/fat.c
new file mode 100644
index 00000000..1d110c40
--- /dev/null
+++ b/fatfs/fat.c
@@ -0,0 +1,761 @@
+/* fat.c - Support for FAT filesystems.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <error.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <hurd/store.h>
+#include <hurd/diskfs.h>
+
+#include "fatfs.h"
+
+/* Unprocessed superblock. */
+struct boot_sector *sblock;
+
+/* Processed sblock info. */
+fat_t fat_type;
+size_t bytes_per_sector;
+size_t log2_bytes_per_sector;
+size_t sectors_per_cluster;
+size_t bytes_per_cluster;
+unsigned int log2_bytes_per_cluster;
+size_t sectors_per_fat;
+size_t total_sectors;
+size_t nr_of_root_dir_sectors;
+size_t first_root_dir_byte;
+size_t first_data_sector;
+vm_offset_t first_data_byte;
+size_t first_fat_sector;
+cluster_t nr_of_clusters;
+
+/* Hold this lock while converting times using gmtime. */
+spin_lock_t epoch_to_time_lock = SPIN_LOCK_INITIALIZER;
+
+/* Hold this lock while allocating a new cluster in the FAT. */
+spin_lock_t allocate_free_cluster_lock = SPIN_LOCK_INITIALIZER;
+
+/* Where to look for the next free cluster. This is meant to avoid
+ searching through a nearly full file system from the beginning at
+ every request. It would be better to use the field of the same
+ name in the fs_info block. 2 is the first data cluster in any
+ FAT. */
+cluster_t next_free_cluster = 2;
+
+
+/* Read the superblock. */
+void
+fat_read_sblock (void)
+{
+ error_t err;
+ int read;
+
+ sblock = malloc (sizeof (struct boot_sector));
+ err = store_read (store, 0, sizeof (struct boot_sector),
+ (void **) &sblock, &read);
+ if (err)
+ error (1, err, "Could not read superblock");
+
+ if (read_word(sblock->id) != BOOT_SECTOR_ID)
+ error (1, 0, "Could not find valid superblock");
+
+ /* Parse some important bits of the superblock. */
+
+ bytes_per_sector = read_word (sblock->bytes_per_sector);
+ switch (bytes_per_sector)
+ {
+ case 512:
+ log2_bytes_per_sector = 9;
+ break;
+
+ case 1024:
+ log2_bytes_per_sector = 10;
+ break;
+
+ case 2048:
+ log2_bytes_per_sector = 11;
+ break;
+
+ case 4096:
+ log2_bytes_per_sector = 12;
+ break;
+
+ default:
+ error (1, 0, "Invalid number of bytes per sector");
+ };
+
+ sectors_per_cluster = sblock->sectors_per_cluster;
+ if (sectors_per_cluster != 1 && sectors_per_cluster != 2
+ && sectors_per_cluster != 4 && sectors_per_cluster != 8
+ && sectors_per_cluster != 16 && sectors_per_cluster != 32
+ && sectors_per_cluster != 64 && sectors_per_cluster != 128)
+ error (1, 0, "Invalid number of sectors per cluster");
+
+ bytes_per_cluster = sectors_per_cluster << log2_bytes_per_sector;
+ switch (bytes_per_cluster)
+ {
+ case 512:
+ log2_bytes_per_cluster = 9;
+ break;
+
+ case 1024:
+ log2_bytes_per_cluster = 10;
+ break;
+
+ case 2048:
+ log2_bytes_per_cluster = 11;
+ break;
+
+ case 4096:
+ log2_bytes_per_cluster = 12;
+ break;
+
+ case 8192:
+ log2_bytes_per_cluster = 13;
+ break;
+
+ case 16384:
+ log2_bytes_per_cluster = 14;
+ break;
+
+ case 32768:
+ log2_bytes_per_cluster = 15;
+ break;
+
+ default:
+ error (1, 0, "Invalid number of bytes per cluster");
+ };
+
+ total_sectors = read_word (sblock->total_sectors_16)
+ ?: read_word (sblock->total_sectors_32);
+ if (total_sectors * bytes_per_sector > store->size)
+ error (1, 0, "Store is smaller then implied by metadata");
+ if (total_sectors == 0)
+ error (1, 0, "Number of total sectors is zero");
+
+ if (bytes_per_sector & (store->block_size - 1))
+ error (1, 0, "Block size of filesystem is not"
+ " a multiple of the block size of the store");
+
+ if (read_word (sblock->reserved_sectors) == 0)
+ error (1, 0, "Number of reserved sectors is zero");
+ if (sblock->nr_of_fat_tables == 0)
+ error (1, 0, "Number of FATs is zero");
+
+ sectors_per_fat = read_word (sblock->sectors_per_fat_16)
+ ?: read_word (sblock->compat.fat32.sectors_per_fat_32);
+ if (sectors_per_fat == 0)
+ error (1, 0, "Number of sectors per fat is zero");
+
+ nr_of_root_dir_sectors = ((read_word (sblock->nr_of_root_dirents) *
+ FAT_DIR_REC_LEN) - 1) / bytes_per_sector + 1;
+
+ first_root_dir_byte = (read_word (sblock->reserved_sectors)
+ + (sblock->nr_of_fat_tables * sectors_per_fat)) << log2_bytes_per_sector;
+ first_data_sector = (first_root_dir_byte >> log2_bytes_per_sector)
+ + nr_of_root_dir_sectors;
+ first_data_byte = first_data_sector << log2_bytes_per_sector;
+
+ nr_of_clusters = (total_sectors - first_data_sector) / sectors_per_cluster;
+
+ if (nr_of_clusters < FAT12_MAX_NR_OF_CLUSTERS)
+ fat_type = FAT12;
+ else
+ {
+ if (nr_of_clusters < FAT16_MAX_NR_OF_CLUSTERS)
+ fat_type = FAT16;
+ else
+ fat_type = FAT32;
+ }
+
+ if (fat_type == FAT32 && read_word (sblock->compat.fat32.fs_version) != 0)
+ error (1, 0, "Incompatible file system version");
+
+ first_fat_sector = 0;
+ if (fat_type == FAT32 && read_word (sblock->compat.fat32.extension_flags) & 1<<7)
+ {
+ first_fat_sector = (read_word (sblock->compat.fat32.extension_flags) & 0x0f);
+ if (first_fat_sector > sblock->nr_of_fat_tables)
+ error (1, 0, "Active FAT table does not exist");
+ first_fat_sector *= sectors_per_fat;
+ }
+ first_fat_sector += read_word (sblock->reserved_sectors);
+}
+
+
+/* Write NEXT_CLUSTER in the FAT at position CLUSTER.
+ You must call this from inside diskfs_catch_exception.
+ Returns 0 (always succeeds). */
+error_t
+fat_write_next_cluster(cluster_t cluster, cluster_t next_cluster)
+{
+ loff_t fat_entry_offset;
+ cluster_t data;
+
+ /* First data cluster is cluster 2. */
+ assert (cluster >= 2 && cluster < nr_of_clusters + 2);
+
+ switch (fat_type)
+ {
+ case FAT12:
+ if (next_cluster == FAT_BAD_CLUSTER)
+ next_cluster = FAT12_BAD_CLUSTER;
+ else if (next_cluster == FAT_EOC)
+ next_cluster = FAT12_EOC;
+
+ fat_entry_offset = (cluster * 3) / 2;
+ data = read_word (fat_image + fat_entry_offset);
+ if (cluster & 1)
+ data = (data & 0xf) | ((next_cluster & 0xfff) << 4);
+ else
+ data = (data & 0xf000) | (next_cluster & 0xfff);
+
+ write_word (fat_image + fat_entry_offset, data);
+ break;
+
+ case FAT16:
+ if (next_cluster == FAT_BAD_CLUSTER)
+ next_cluster = FAT16_BAD_CLUSTER;
+ else if (next_cluster == FAT_EOC)
+ next_cluster = FAT16_EOC;
+
+ fat_entry_offset = cluster * 2;
+ write_word (fat_image + fat_entry_offset, next_cluster);
+ break;
+
+ case FAT32:
+ default: /* To silence gcc warning. */
+ if (next_cluster == FAT_BAD_CLUSTER)
+ next_cluster = FAT32_BAD_CLUSTER;
+ else if (next_cluster == FAT_EOC)
+ next_cluster = FAT32_EOC;
+
+ fat_entry_offset = cluster * 4;
+ write_dword (fat_image + fat_entry_offset, next_cluster & 0x0fffffff);
+ }
+
+ return 0;
+}
+
+/* Read the FAT entry at position CLUSTER into NEXT_CLUSTER.
+ You must call this from inside diskfs_catch_exception.
+ Returns 0 (always succeeds). */
+error_t
+fat_get_next_cluster(cluster_t cluster, cluster_t *next_cluster)
+{
+ loff_t fat_entry_offset;
+
+ /* First data cluster is cluster 2. */
+ assert (cluster >= 2 && cluster < nr_of_clusters + 2);
+
+ switch (fat_type)
+ {
+ case FAT12:
+ fat_entry_offset = (cluster * 3) / 2;
+ *next_cluster = read_word (fat_image + fat_entry_offset);
+ if (cluster & 1)
+ *next_cluster = *next_cluster >> 4;
+ else
+ *next_cluster &= 0xfff;
+
+ if (*next_cluster == FAT12_BAD_CLUSTER)
+ *next_cluster = FAT_BAD_CLUSTER;
+ else if (*next_cluster >= FAT12_EOC)
+ *next_cluster = FAT_EOC;
+ break;
+
+ case FAT16:
+ fat_entry_offset = cluster * 2;
+ *next_cluster = read_word (fat_image + fat_entry_offset);
+ if (*next_cluster == FAT16_BAD_CLUSTER)
+ *next_cluster = FAT_BAD_CLUSTER;
+ else if (*next_cluster >= FAT16_EOC)
+ *next_cluster = FAT_EOC;
+ break;
+
+ case FAT32:
+ default: /* To silence gcc warning. */
+ fat_entry_offset = cluster * 4;
+ *next_cluster = read_dword (fat_image + fat_entry_offset);
+ *next_cluster &= 0x0fffffff;
+ if (*next_cluster == FAT32_BAD_CLUSTER)
+ *next_cluster = FAT_BAD_CLUSTER;
+ else if (*next_cluster >= FAT32_EOC)
+ *next_cluster = FAT_EOC;
+ }
+
+ return 0;
+}
+
+/* Allocate a new cluster, write CONTENT into the FAT at this new
+ clusters position. At success, 0 is returned and CLUSTER contains
+ the cluster number allocated. Otherwise, ENOSPC is returned if the
+ filesystem is full.
+ You must call this from inside diskfs_catch_exception. */
+error_t
+fat_allocate_cluster (cluster_t content, cluster_t *cluster)
+{
+ error_t err = 0;
+ cluster_t old_next_free_cluster;
+ int wrapped = 0;
+ cluster_t found_cluster = FAT_FREE_CLUSTER;
+
+ assert (content != FAT_FREE_CLUSTER);
+
+ spin_lock (&allocate_free_cluster_lock);
+ old_next_free_cluster = next_free_cluster;
+
+ /* Loop over all clusters, starting from next_free_cluster and
+ wrapping if reaching the end of the FAT, until we either find an
+ unallocated cluster, or we have to give up because all clusters
+ are allocated. */
+ do
+ {
+ cluster_t next_free_content;
+
+ fat_get_next_cluster (next_free_cluster, &next_free_content);
+
+ if (next_free_content == FAT_FREE_CLUSTER)
+ found_cluster = next_free_cluster;
+
+ if (++next_free_cluster == nr_of_clusters + 2)
+ {
+ next_free_cluster = 2;
+ wrapped = 1;
+ }
+ }
+ while (found_cluster == FAT_FREE_CLUSTER
+ && !(wrapped && next_free_cluster == old_next_free_cluster));
+
+ if (found_cluster != FAT_FREE_CLUSTER)
+ {
+ *cluster = found_cluster;
+ fat_write_next_cluster(found_cluster, content);
+ }
+ else
+ err = ENOSPC;
+
+ spin_unlock(&allocate_free_cluster_lock);
+ return err;
+}
+
+/* Extend the cluster chain to maximum size or new_last_cluster,
+ whatever is less. If we reach the end of the file, and CREATE is
+ true, allocate new blocks until there is either no space on the
+ device or new_last_cluster are allocated. (new_last_cluster: 0 is
+ the first cluster of the file). */
+error_t
+fat_extend_chain (struct node *node, cluster_t new_last_cluster, int create)
+{
+ error_t err = 0;
+ struct disknode *dn = node->dn;
+ struct cluster_chain *table;
+ int offs;
+ cluster_t left, prev_cluster, cluster;
+
+ error_t allocate_new_table(struct cluster_chain **table)
+ {
+ struct cluster_chain *t;
+
+ t = *table;
+ *table = malloc (sizeof (struct cluster_chain));
+ if (!*table)
+ return ENOMEM;
+ (*table)->next = 0;
+ if (t)
+ dn->last = t->next = *table;
+ else
+ dn->last = dn->first = *table;
+ return 0;
+ }
+
+ spin_lock(&dn->chain_extension_lock);
+
+ /* If we already have what we need, or we have all clusters that are
+ available without allocating new ones, go out. */
+ if (new_last_cluster < dn->length_of_chain
+ || (!create && dn->chain_complete))
+ {
+ spin_unlock(&dn->chain_extension_lock);
+ return 0;
+ }
+
+ left = new_last_cluster + 1 - dn->length_of_chain;
+
+ table = dn->last;
+ if (table)
+ {
+ offs = (dn->length_of_chain - 1) & (CLUSTERS_PER_TABLE - 1);
+ prev_cluster = table->cluster[offs];
+ }
+ else
+ {
+ offs = CLUSTERS_PER_TABLE - 1;
+ prev_cluster = FAT_FREE_CLUSTER;
+ }
+
+ while (left)
+ {
+ if (dn->chain_complete)
+ {
+ err = fat_allocate_cluster(FAT_EOC, &cluster);
+ if (err)
+ break;
+ if (prev_cluster)
+ fat_write_next_cluster(prev_cluster, cluster);
+ else
+ /* XXX: Also write this to dirent structure! */
+ dn->start_cluster = cluster;
+ }
+ else
+ {
+ if (prev_cluster != FAT_FREE_CLUSTER)
+ err = fat_get_next_cluster(prev_cluster, &cluster);
+ else
+ cluster = dn->start_cluster;
+ if (cluster == FAT_EOC || cluster == FAT_FREE_CLUSTER)
+ {
+ dn->chain_complete = 1;
+ if (create)
+ continue;
+ else
+ break;
+ }
+ }
+ prev_cluster = cluster;
+ offs++;
+ if (offs == CLUSTERS_PER_TABLE)
+ {
+ offs = 0;
+ err = allocate_new_table(&table);
+ if (err)
+ break;
+ }
+ table->cluster[offs] = cluster;
+ dn->length_of_chain++;
+ left--;
+ }
+
+ if (dn->length_of_chain << log2_bytes_per_cluster > node->allocsize)
+ node->allocsize = dn->length_of_chain << log2_bytes_per_cluster;
+
+ spin_unlock(&dn->chain_extension_lock);
+ return err;
+}
+
+/* Returns in DISK_CLUSTER the disk cluster corresponding to cluster
+ CLUSTER in NODE. If there is no such cluster yet, but CREATE is
+ true, then it is created, otherwise EINVAL is returned. */
+error_t
+fat_getcluster (struct node *node, cluster_t cluster, int create,
+ cluster_t *disk_cluster)
+{
+ error_t err = 0;
+ cluster_t chains_to_go = cluster >> LOG2_CLUSTERS_PER_TABLE;
+ cluster_t offs = cluster & (CLUSTERS_PER_TABLE - 1);
+ struct cluster_chain *chain;
+
+ if (cluster >= node->dn->length_of_chain)
+ {
+ err = fat_extend_chain (node, cluster, create);
+ if (err)
+ return err;
+ if (cluster >= node->dn->length_of_chain)
+ {
+ assert (!create);
+ return EINVAL;
+ }
+ }
+ chain = node->dn->first;
+ while (chains_to_go--)
+ {
+ assert (chain);
+ chain = chain->next;
+ }
+ assert (chain);
+ *disk_cluster = chain->cluster[offs];
+ return 0;
+}
+
+void
+fat_truncate_node (struct node *node, cluster_t clusters_to_keep)
+{
+ struct cluster_chain *next;
+ cluster_t count;
+ cluster_t offs;
+ cluster_t pos;
+
+ /* The root dir of a FAT12/16 fs is of fixed size, while the root
+ dir of a FAT32 fs must never decease to exist. */
+ assert (! (((fat_type == FAT12 || fat_type == FAT16) && node == diskfs_root_node)
+ || (fat_type == FAT32 && node == diskfs_root_node && clusters_to_keep == 0)));
+
+ /* Expand the cluster chain, because we have to know the complete tail. */
+ fat_extend_chain (node, FAT_EOC, 0);
+ if (clusters_to_keep == node->dn->length_of_chain)
+ return;
+ assert (clusters_to_keep < node->dn->length_of_chain);
+
+ /* Truncation happens here. */
+ next = node->dn->first;
+ if (clusters_to_keep == 0)
+ {
+ /* Deallocate the complete file. */
+ node->dn->start_cluster = 0;
+ pos = count = offs = 0;
+ node->dn->last = 0;
+ }
+ else
+ {
+ count = (clusters_to_keep - 1) >> LOG2_CLUSTERS_PER_TABLE;
+ offs = (clusters_to_keep - 1) & (CLUSTERS_PER_TABLE - 1);
+ while (count-- > 0)
+ {
+ assert (next);
+
+ /* This cluster is now the last cluster in the chain. */
+ if (count == 0)
+ node->dn->last = next;
+
+ next = next->next;
+ }
+ assert (next);
+ fat_write_next_cluster (next->cluster[offs++], FAT_EOC);
+ pos = clusters_to_keep;
+ }
+
+ /* Purge dangling clusters. If we die here, scandisk will have to
+ clean up the remains. */
+ while (pos < node->dn->length_of_chain)
+ {
+ if (offs == CLUSTERS_PER_TABLE)
+ {
+ offs = 0;
+ next = next->next;
+ assert(next);
+ }
+ fat_write_next_cluster(next->cluster[offs++], 0);
+ pos++;
+ }
+
+ /* Free now unused tables. (Could be done in one run with the above.) */
+ next = node->dn->first;
+ if (clusters_to_keep != 0)
+ {
+ count = (clusters_to_keep - 1) >> LOG2_CLUSTERS_PER_TABLE;
+ offs = (clusters_to_keep - 1) & (CLUSTERS_PER_TABLE - 1);
+ while (count-- > 0)
+ {
+ assert (next);
+ next = next->next;
+ }
+ assert (next);
+ next = next->next;
+ }
+ while (next)
+ {
+ struct cluster_chain *next_next = next->next;
+ free (next);
+ next = next_next;
+ }
+
+ if (clusters_to_keep == 0)
+ node->dn->first = 0;
+
+ node->dn->length_of_chain = clusters_to_keep;
+}
+
+
+/* Count the number of free clusters in the FAT. */
+int
+fat_get_freespace (void)
+{
+ int free_clusters = 0;
+ cluster_t curr_cluster;
+ cluster_t next_cluster;
+ error_t err;
+
+ err = diskfs_catch_exception ();
+ if (!err)
+ {
+ /* First cluster is the 3rd entry in the FAT table. */
+ for (curr_cluster = 2; curr_cluster < nr_of_clusters + 2;
+ curr_cluster++)
+ {
+ fat_get_next_cluster (curr_cluster, &next_cluster);
+ if (next_cluster == FAT_FREE_CLUSTER)
+ free_clusters++;
+ }
+ }
+ diskfs_end_catch_exception ();
+
+ return free_clusters;
+}
+
+
+/* FILE must be a buffer with 13 characters. */
+void fat_to_unix_filename(const char *name, char *file)
+{
+ int npos;
+ int fpos = 0;
+ int ext = 0;
+
+ for (npos = 0; npos < 11; npos++)
+ {
+ if (name[npos] == ' ')
+ {
+ if (ext)
+ {
+ break;
+ }
+ else
+ {
+ file[fpos] = '.';
+ fpos++;
+ ext = 1;
+ while (npos < 7 && name[npos+1] == ' ') npos++;
+ }
+ }
+ else
+ {
+ file[fpos] = name[npos];
+ fpos++;
+ if (npos == 7)
+ {
+ file[fpos] = '.';
+ fpos++;
+ ext = 1;
+ }
+ }
+ }
+ if (ext && file[fpos-1] == '.')
+ file[fpos-1] = '\0';
+ else
+ file[fpos] = '\0';
+}
+
+void
+fat_from_unix_filename(char *fn, const char *un, int ul)
+{
+ int fp = 0;
+ int up = 0;
+ int ext = 0;
+
+ while (fp < 11)
+ {
+ if (up == ul)
+ {
+ /* We parsed the complete unix filename. */
+ while (fp < 11)
+ fn[fp++] = ' ';
+ }
+ else
+ {
+ if (!ext)
+ {
+ if (un[up] == '.')
+ {
+ while (fp < 8)
+ fn[fp++] = ' ';
+ ext = 1;
+ un++;
+ }
+ else if (fp == 8)
+ {
+ while (un[up++] != '.' && up < ul);
+ ext = 1;
+ }
+ else
+ fn[fp++] = toupper(un[ul++]);
+ }
+ else
+ {
+ if (un[up] == '.')
+ {
+ while (fp < 11)
+ fn[fp++] = ' ';
+ }
+ else
+ fn[fp++] = toupper(un[up++]);
+ }
+ }
+ }
+}
+
+
+/* Return Epoch-based time from a MSDOS time/date pair. */
+void
+fat_to_epoch (char *date, char *time, struct timespec *ts)
+{
+ struct tm tm;
+
+ /* Date format:
+ Bits 0-4: Day of month (1-31).
+ Bits 5-8: Month of year (1-12).
+ Bits 9-15: Count of years from 1980 (0-127).
+
+ Time format:
+ Bits 0-4: 2-second count (0-29).
+ Bits 5-10: Minutes (0-59).
+ Bits 11-15: Hours (0-23).
+ */
+
+ tm.tm_year = (read_word (date) >> 9) + 80;
+ tm.tm_mon = ((read_word (date) & 0x1ff) >> 5) - 1;
+ tm.tm_mday = read_word (date) & 0x1f;
+ tm.tm_hour = (read_word (time) >> 11);
+ tm.tm_min = (read_word (time) & 0x7ff) >> 5;
+ tm.tm_sec = read_word (time) & 0x1f;
+ tm.tm_isdst = 0;
+
+ ts->tv_sec = timegm (&tm);
+ ts->tv_nsec = 0;
+}
+
+/* Return MSDOS time/date pair from Epoch-based time. */
+void
+fat_from_epoch (char *date, char *time, time_t *tp)
+{
+ struct tm *tm;
+
+ spin_lock(&epoch_to_time_lock);
+ tm = gmtime (tp);
+
+ /* Date format:
+ Bits 0-4: Day of month (1-31).
+ Bits 5-8: Month of year (1-12).
+ Bits 9-15: Count of years from 1980 (0-127).
+
+ Time format:
+ Bits 0-4: 2-second count (0-29).
+ Bits 5-10: Minutes (0-59).
+ Bits 11-15: Hours (0-23).
+ */
+
+ write_word(date, tm->tm_mday | ((tm->tm_mon + 1) << 5)
+ | ((tm->tm_year - 80) << 9));
+ write_word(time, (tm->tm_hour << 11) | (tm->tm_min << 5)
+ | (tm->tm_sec >> 1));
+ spin_unlock(&epoch_to_time_lock);
+}
diff --git a/fatfs/fat.h b/fatfs/fat.h
new file mode 100644
index 00000000..58b45c63
--- /dev/null
+++ b/fatfs/fat.h
@@ -0,0 +1,399 @@
+/* fat.h - Support for FAT filesystems interfaces.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef FAT_H
+#define FAT_H
+
+/* Specification of the FAT12/16/32 filesystem format. */
+
+/* Overview
+ --------
+
+ Any FAT fs consists of several regions, which follow immediately
+ after each other.
+
+ Reserved
+
+ The reserved region consists of the boot sector, and with it the
+ BIOS Paramter Block, which contains all necessary data about the
+ filesystem like sector size, number of clusters etc. It also
+ holds the filesystem info block.
+
+ The reserved region of FAT32 filesystems also hold a backup copy
+ of the root sector at sector 6 (usually), followed by a backup
+ copy of the filesystem info sector.
+
+ The number of sectors occupied by the reserved region is stored
+ in the reserved region as well, in the word at offset 14
+ (reserved_sectors).
+
+ FAT
+
+ The FAT region contains the File Allocation Table, which is a
+ linked list of clusters occupied by each file or directory.
+ There might be multiple FAT tables in the FAT region, for
+ redundancy.
+
+ The number of FATs is stored in the reserved region, in the byte
+ at offset 16 (nr_of_fat_tables). The number of sectors per FAT is
+ stored in the word at offset 22 (sectors_per_fat_16) or, if this
+ is zero (as it is for FAT32), in the doubleword at offset 36
+ (sectors_per_fat_32).
+
+ Root Directory
+
+ In FAT12/16, the root directory entries allocate their own region
+ and are not accessed through the FAT.
+
+ The size of this region is determined by the word at offset 17
+ (nr_of_root_dirents). You have to multiply this with the nr of
+ bytes per entry, and divide through the number of bytes per
+ sector, rounding up. On FAT32 filesystems, this region does not
+ exist, and nr_of_root_dirents is zero. The FAT32 root directory
+ is accessed through the FAT as any other directory is.
+
+ Data
+
+ The data region occupies the rest of the filesystem and stores
+ the actual file and directory data. It is separated in clusters,
+ which are indexed in the FAT.
+
+ The size of the data region is stored in the word at offset 19
+ (total_sectors_16) or, if this is zero, in the doubleword at
+ offset 32 (total_sectors_32).
+
+
+ NOTE that all meta data in a FAT filesystem is stored in little endian
+ format.
+
+*/
+
+/* The supported FAT types. */
+
+enum fat { FAT12, FAT16, FAT32 };
+typedef enum fat fat_t;
+
+/* The FAT type is determined by the number of clusters in the data
+ region, and nothing else. The maximal number of clusters for a
+ FAT12 and FAT16 respectively is defined here.
+*/
+
+#define FAT12_MAX_NR_OF_CLUSTERS 4084
+#define FAT16_MAX_NR_OF_CLUSTERS 65524
+#define FAT32_MAX_NR_OF_CLUSTERS (FAT32_BAD_CLUSTER - 1)
+
+struct boot_sector
+{
+ /* Unused. */
+ unsigned char jump_to_boot_code[3]; /* 0, typ. 0xeb 0x?? 0x90 */
+ unsigned char oem_name[8]; /* 3, typ. "MSWIN4.1" */
+
+ /* Sector and Cluster size.
+ bytes_per_sector is usually 512, but 1024, 2048, 4096 are also allowed.
+ sectors_per_cluster is one of 1, 2, 4, 8, 16, 32, 64, 128.
+ Note that bytes per cluster (product of the two) must be <= 32768. */
+ unsigned char bytes_per_sector[2]; /* 11 */
+ unsigned char sectors_per_cluster; /* 13 */
+
+ /* Size of the various regions.
+ reserved_sectors must not be zero and is typically 1 on FAT12/16
+ filesystems and 32 on FAT32 filesystems.
+ nr_of_fat_tables must not be zero and is typically 2.
+ nr_of_root_dirents must be zero on FAT32 filesystems.
+ For FAT12/16, the value multiplied with DIR_ENTRY_SIZE (32)
+ should always be a multiple of bytes_per_sector to retain
+ compatibility. For FAT16, 512 should be used.
+ total_sectors_16 contains the complete number of sectors if not zero.
+ If zero, the number of sectors is stored in total_sectors_32. */
+ unsigned char reserved_sectors[2]; /* 14 */
+ unsigned char nr_of_fat_tables; /* 16 */
+ unsigned char nr_of_root_dirents[2]; /* 17 */
+ unsigned char total_sectors_16[2]; /* 19 */
+
+ /* Media descriptor.
+ Allowed are values between 0xf0 and 0xff.
+ 0xf8 is a fixed hardware (disk), 0xf0 denotes a removable media.
+ Must be the same as the first byte in the FAT (compatibility
+ with DOS 1.x). */
+ unsigned char media_descriptor; /* 21 */
+
+ /* Size of one FAT.
+ On FAT32 systems, this value must be zero and sectors_per_fat_32
+ used instead. */
+ unsigned char sectors_per_fat_16[2]; /* 22 */
+
+ /* Disk geometry. Unused. */
+ unsigned char sectors_per_track[2]; /* 24 */
+ unsigned char nr_of_heads[2]; /* 26 */
+ unsigned char nr_of_hidden_sectors[4]; /* 28 */
+
+ /* See total_sectors_16. */
+ unsigned char total_sectors_32[4]; /* 32 */
+
+ /* FAT specific information.
+ Starting with offset 36, FAT12/16 filesystems differ from FAT32
+ filesystems. */
+ union
+ {
+ struct
+ {
+ unsigned char drive; /* 36 */
+ unsigned char reserved; /* 37 */
+
+ /* Boot signature.
+ Value is 0x29.
+ Indicates that the following three fields
+ are present. */
+ unsigned char boot_signature; /* 38 */
+
+ /* Identifier.
+ serial is an unique identifier for removable media.
+ label is the filesystem label, which must match the label
+ stored in the root directory entry which has DIR_ATTR_LABEL
+ set. If no name is specified, the content is "NO NAME ".
+ fs_type: One of "FAT12 ", "FAT16 ", "FAT ".
+ Don't use. */
+ unsigned char serial[4]; /* 39 */
+ unsigned char label[11]; /* 43 */
+ unsigned char fs_type[8]; /* 54 */
+ } fat;
+ struct
+ {
+ /* See sectors_per_fat_16. */
+ unsigned char sectors_per_fat_32[4]; /* 36 */
+
+ /* Extension flags.
+ Bits 0-3: Zero based nr of active FAT.
+ Bit 7: If 0, all FATs are active and should be kept up to date.
+ If 1, only the active FAT (see bits 0-3) should be used.
+ The rest of the bits are reserved. */
+ unsigned char extension_flags[2]; /* 40 */
+
+ /* Filesystem version.
+ The high byte is the major number, the low byte the minor version.
+ Don't mount if either version number is higher than known versions. */
+ unsigned char fs_version[2]; /* 42 */
+
+ /* Root cluster.
+ The cluster where the root directory starts. */
+ unsigned char root_cluster[4]; /* 44 */
+
+ /* Filesystem Info sector.
+ The setor number of the filesystem info block in the
+ reserved area. */
+ unsigned char fs_info_sector[2]; /* 48 */
+
+ /* Backup boot sector.
+ The sector of the backup copy of the boot sector.
+ Should be 6, so it can be used even if this field is
+ corrupted. */
+ unsigned char backup_boot_sector[2]; /* 50 */
+ unsigned char reserved1[12]; /* 52 */
+
+ /* See fat structure above, with the following exception:
+ fs_type is "FAT32 ". */
+ unsigned char drive_number; /* 64 */
+ unsigned char reserved2; /* 65 */
+ unsigned char boot_signature; /* 66 */
+ unsigned char serial[4]; /* 67 */
+ unsigned char label[11]; /* 71 */
+ unsigned char fs_type[8]; /* 82 */
+ } fat32;
+ } compat;
+ unsigned char unused[420]; /* 90 */
+
+ /* Expected ID at offset 510.
+ */
+#define BOOT_SECTOR_ID 0xaa55
+
+ unsigned char id[2]; /* 510 */
+};
+
+/* File System Info Block. */
+
+#define FAT_FS_INFO_LEAD_SIGNATURE 0x41615252L
+#define FAT_FS_INFO_STRUCT_SIGNATURE 0x61417272L
+#define FAT_FS_INFO_TRAIL_SIGNAURE 0xaa550000L
+#define FAT_FS_NR_OF_FREE_CLUSTERS_UNKNOWN 0xffffffffL
+#define FAT_FS_NEXT_FREE_CLUSTER_UNKNOWN 0xffffffffL
+
+struct fat_fs_info
+{
+ unsigned char lead_signature[4];
+ unsigned char reserved1[480];
+ unsigned char struct_signature[4];
+ unsigned char nr_of_free_clusters[4];
+ unsigned char next_free_cluster[4];
+ unsigned char reserved2[12];
+ unsigned char trail_signature[4];
+};
+
+/* File Allocation Table, special entries. */
+
+#define FAT_FREE_CLUSTER 0
+
+#define FAT12_BAD_CLUSTER 0x0ff7
+#define FAT16_BAD_CLUSTER 0xfff7
+#define FAT32_BAD_CLUSTER 0x0ffffff7L
+#define FAT_BAD_CLUSTER FAT32_BAD_CLUSTER
+
+#define FAT12_EOC 0x0ff8
+#define FAT16_EOC 0xfff8
+#define FAT32_EOC 0x0ffffff8
+#define FAT_EOC FAT32_EOC
+
+/* Directories. */
+
+#define FAT_DIR_REC_LEN 32
+#define FAT_DIR_RECORDS(x) FAT_DIR_REC_LEN /* Something else for vfat. */
+
+#define FAT_DIR_ATTR_RDONLY 0x01
+#define FAT_DIR_ATTR_HIDDEN 0x02
+#define FAT_DIR_ATTR_SYSTEM 0x04
+#define FAT_DIR_ATTR_LABEL 0x08
+#define FAT_DIR_ATTR_DIR 0x10
+#define FAT_DIR_ATTR_ARCHIVE 0x20
+#define FAT_DIR_ATTR_LONGNAME (DIR_ATTR_RDONLY | DIR_ATTR_HIDDEN \
+ | DIR_ATTR_SYSTEM | DIR_ATTR_LABEL)
+
+#define FAT_DIR_NAME_LAST '\x00'
+#define FAT_DIR_NAME_DELETED '\xe5'
+
+/* If the first character is this, replace it with FAT_DIR_NAME_DELETED
+ after checking for it. */
+#define FAT_DIR_NAME_REPLACE_DELETED '\x05'
+
+#define FAT_DIR_NAME_DOT ". "
+#define FAT_DIR_NAME_DOTDOT ".. "
+
+struct dirrect
+{
+ unsigned char name[11];
+ unsigned char attribute;
+ unsigned char reserved;
+ unsigned char creation_time_centiseconds;
+ unsigned char creation_time[2];
+ unsigned char creation_date[2];
+ unsigned char last_access_date[2];
+ unsigned char first_cluster_high[2];
+ unsigned char write_time[2];
+ unsigned char write_date[2];
+ unsigned char first_cluster_low[2];
+ unsigned char file_size[4];
+};
+
+#define FAT_NAME_MAX 12 /* VFAT: 255 */
+
+extern vm_offset_t first_data_byte;
+extern size_t bytes_per_cluster;
+
+/* A cluster number. */
+typedef unsigned long cluster_t;
+
+#define LOG2_CLUSTERS_PER_TABLE 10
+#define CLUSTERS_PER_TABLE (1 << LOG2_CLUSTERS_PER_TABLE)
+
+struct cluster_chain
+{
+ struct cluster_chain *next;
+ cluster_t cluster[CLUSTERS_PER_TABLE];
+};
+
+/* Prototyping. */
+void fat_read_sblock (void);
+void fat_to_epoch (char *, char *, struct timespec *);
+void fat_from_epoch (char *, char *, time_t *);
+error_t fat_getcluster (struct node *, cluster_t, int, cluster_t *);
+void fat_truncate_node (struct node *, cluster_t);
+error_t fat_extend_chain (struct node *, cluster_t, int);
+int fat_get_freespace (void);
+
+/* Unprocessed superblock. */
+extern struct boot_sector *sblock;
+
+/* Processed sblock info. */
+extern fat_t fat_type;
+extern size_t bytes_per_sector;
+extern size_t log2_bytes_per_sector;
+extern size_t sectors_per_cluster;
+extern size_t bytes_per_cluster;
+extern unsigned int log2_bytes_per_cluster;
+extern size_t sectors_per_fat;
+extern size_t total_sectors;
+extern size_t nr_of_root_dir_sectors;
+extern size_t first_root_dir_byte;
+extern size_t first_data_sector;
+extern vm_offset_t first_data_byte;
+extern size_t first_fat_sector;
+extern cluster_t nr_of_clusters;
+
+/* Numeric conversions for these fields. */
+#include <endian.h>
+#include <byteswap.h>
+
+static inline unsigned int
+read_dword (unsigned char *addr)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return *(unsigned int *)addr;
+#elif BYTE_ORDER == BIG_ENDIAN
+ return bswap_32 (*(unsigned int *) addr);
+#else
+#error unknown byte order
+#endif
+}
+
+static inline unsigned int
+read_word (unsigned char *addr)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return *(unsigned short *)addr;
+#elif BYTE_ORDER == BIG_ENDIAN
+ return bswap_16 (*(unsigned int *) addr);
+#else
+#error unknown byte order
+#endif
+}
+
+static inline void
+write_dword (unsigned char *addr, unsigned int value)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ *(unsigned int *)addr = value;
+#elif BYTE_ORDER == BIG_ENDIAN
+ *(unsigned int *)addr = bswap_32 (value);
+#else
+#error unknown byte order
+#endif
+}
+
+static inline void
+write_word (unsigned char *addr, unsigned int value)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ *(unsigned short *)addr = value;
+#elif BYTE_ORDER == BIG_ENDIAN
+ *(unsigned int *)addr = bswap_16 (value);
+#else
+#error unknown byte order
+#endif
+}
+
+#endif /* FAT_H */
diff --git a/fatfs/fatfs.h b/fatfs/fatfs.h
new file mode 100644
index 00000000..16b058a8
--- /dev/null
+++ b/fatfs/fatfs.h
@@ -0,0 +1,128 @@
+/* fatfs.h - Interface for fatfs.
+ Copyright (C) 1997, 1999, 2002, 2003 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <hurd/diskfs.h>
+#include <hurd/diskfs-pager.h>
+#include <hurd/store.h>
+
+#include "fat.h"
+#include "virt-inode.h"
+
+/* There is no such thing as an inode in this format, all such information
+ being recorded in the directory entry. So we report inode numbers as
+ the start cluster number of the file. When messing around with the
+ directory entry, hold the DIRENT_LOCK. */
+
+struct disknode
+{
+ cluster_t start_cluster;
+
+ /* Links on hash list. */
+ struct node *hnext, **hprevp;
+
+ /* The inode as returned by virtual inode management routines. */
+ inode_t inode;
+
+ /* The directory that hold this file, always hold a reference. */
+ struct node *dirnode;
+
+ struct rwlock dirent_lock;
+
+ char *link_target; /* For S_ISLNK. */
+
+ size_t translen;
+ char *translator;
+
+ /* Lock to hold while fiddling with this inode's block allocation
+ info. */
+ struct rwlock alloc_lock;
+ /* Lock to hold while extending this inode's block allocation info.
+ Hold only if you hold readers alloc_lock, then you don't need to
+ hold it if you hold writers alloc_lock already. */
+ spin_lock_t chain_extension_lock;
+ struct cluster_chain *first;
+ struct cluster_chain *last;
+ cluster_t length_of_chain;
+ int chain_complete;
+
+ /* This file's pager. */
+ struct pager *pager;
+
+ /* Index to start a directory lookup at. */
+ int dir_idx;
+};
+
+struct user_pager_info
+{
+ struct node *node;
+ enum pager_type
+ {
+ FAT,
+ FILE_DATA,
+ } type;
+ vm_prot_t max_prot;
+};
+
+/* The physical media. */
+extern struct store *store;
+
+/* The UID and GID for all files in the filesystem. */
+extern uid_t fs_uid;
+extern gid_t fs_gid;
+
+/* Mapped image of the FAT. */
+extern void *fat_image;
+
+/* Handy source of zeroes. */
+extern vm_address_t zerocluster;
+
+extern struct dirrect dr_root_node;
+
+
+#define LOG2_BLOCKS_PER_CLUSTER \
+ (log2_bytes_per_cluster - store->log2_block_size)
+
+#define round_cluster(offs) \
+ ((((offs) + bytes_per_cluster - 1) \
+ >> log2_bytes_per_cluster) << log2_bytes_per_cluster)
+
+#define FAT_FIRST_CLUSTER_BLOCK(cluster) \
+ (((cluster - 2) << LOG2_BLOCKS_PER_CLUSTER) + \
+ (first_data_byte >> store->log2_block_size))
+
+void drop_pager_softrefs (struct node *);
+void allow_pager_softrefs (struct node *);
+void create_fat_pager (void);
+
+void flush_node_pager (struct node *node);
+
+void write_all_disknodes ();
+
+struct node *ifind (ino_t inum);
+
+error_t fat_get_next_cluster (cluster_t cluster, cluster_t *next_cluster);
+void fat_to_unix_filename (const char *, char *);
+
+error_t diskfs_cached_lookup_in_dirbuf (int cache_id, struct node **npp,
+ vm_address_t buf);
+void refresh_node_stats (void);
+
diff --git a/fatfs/inode.c b/fatfs/inode.c
new file mode 100644
index 00000000..2a427933
--- /dev/null
+++ b/fatfs/inode.c
@@ -0,0 +1,784 @@
+/* inode.c - Inode management routines.
+
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2007
+ Free Software Foundation, Inc.
+
+ Modified for fatfs by Marcus Brinkmann <marcus@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include "fatfs.h"
+
+/* These flags aren't actually defined by a header file yet, so
+ temporarily disable them if necessary. */
+#ifndef UF_APPEND
+#define UF_APPEND 0
+#endif
+#ifndef UF_NODUMP
+#define UF_NODUMP 0
+#endif
+#ifndef UF_IMMUTABLE
+#define UF_IMMUTABLE 0
+#endif
+
+#define INOHSZ 512
+#if ((INOHSZ&(INOHSZ-1)) == 0)
+#define INOHASH(ino) ((ino)&(INOHSZ-1))
+#else
+#define INOHASH(ino) (((unsigned)(ino))%INOHSZ)
+#endif
+
+static struct node *nodehash[INOHSZ];
+
+static error_t read_node (struct node *np, vm_address_t buf);
+
+/* Initialize the inode hash table. */
+void
+inode_init ()
+{
+ int n;
+ for (n = 0; n < INOHSZ; n++)
+ nodehash[n] = 0;
+}
+
+/* Fetch inode INUM, set *NPP to the node structure; gain one user
+ reference and lock the node. */
+error_t
+diskfs_cached_lookup (ino64_t inum, struct node **npp)
+{
+ error_t err;
+ struct node *np;
+ struct disknode *dn;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+ for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
+ if (np->cache_id == inum)
+ {
+ np->references++;
+ spin_unlock (&diskfs_node_refcnt_lock);
+ mutex_lock (&np->lock);
+ *npp = np;
+ return 0;
+ }
+
+ /* Format specific data for the new node. */
+ dn = malloc (sizeof (struct disknode));
+ if (! dn)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ return ENOMEM;
+ }
+ dn->pager = 0;
+ dn->first = 0;
+ dn->last = 0;
+ dn->length_of_chain = 0;
+ dn->chain_complete = 0;
+ dn->chain_extension_lock = SPIN_LOCK_INITIALIZER;
+ rwlock_init (&dn->alloc_lock);
+ rwlock_init (&dn->dirent_lock);
+
+ /* Create the new node. */
+ np = diskfs_make_node (dn);
+ np->cache_id = inum;
+ np->dn->inode = vi_lookup(inum);
+
+ mutex_lock (&np->lock);
+
+ /* Put NP in NODEHASH. */
+ dn->hnext = nodehash[INOHASH(inum)];
+ if (dn->hnext)
+ dn->hnext->dn->hprevp = &dn->hnext;
+ dn->hprevp = &nodehash[INOHASH(inum)];
+ nodehash[INOHASH(inum)] = np;
+
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ /* Get the contents of NP off disk. */
+ err = read_node (np, 0);
+
+ if (err)
+ return err;
+ else
+ {
+ *npp = np;
+ return 0;
+ }
+}
+
+/* Fetch inode INUM, set *NPP to the node structure;
+ gain one user reference and lock the node.
+ On the way, use BUF as the directory file map. */
+error_t
+diskfs_cached_lookup_in_dirbuf (int inum, struct node **npp, vm_address_t buf)
+{
+ error_t err;
+ struct node *np;
+ struct disknode *dn;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+ for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
+ if (np->cache_id == inum)
+ {
+ np->references++;
+ spin_unlock (&diskfs_node_refcnt_lock);
+ mutex_lock (&np->lock);
+ *npp = np;
+ return 0;
+ }
+
+ /* Format specific data for the new node. */
+ dn = malloc (sizeof (struct disknode));
+ if (! dn)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ return ENOMEM;
+ }
+ dn->pager = 0;
+ dn->first = 0;
+ dn->last = 0;
+ dn->length_of_chain = 0;
+ dn->chain_complete = 0;
+ dn->chain_extension_lock = SPIN_LOCK_INITIALIZER;
+ rwlock_init (&dn->alloc_lock);
+ rwlock_init (&dn->dirent_lock);
+
+ /* Create the new node. */
+ np = diskfs_make_node (dn);
+ np->cache_id = inum;
+ np->dn->inode = vi_lookup(inum);
+
+ mutex_lock (&np->lock);
+
+ /* Put NP in NODEHASH. */
+ dn->hnext = nodehash[INOHASH(inum)];
+ if (dn->hnext)
+ dn->hnext->dn->hprevp = &dn->hnext;
+ dn->hprevp = &nodehash[INOHASH(inum)];
+ nodehash[INOHASH(inum)] = np;
+
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ /* Get the contents of NP off disk. */
+ err = read_node (np, buf);
+
+ if (err)
+ return err;
+ else
+ {
+ *npp = np;
+ return 0;
+ }
+}
+
+/* Lookup node INUM (which must have a reference already) and return
+ it without allocating any new references. */
+struct node *
+ifind (ino_t inum)
+{
+ struct node *np;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+ for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
+ {
+ if (np->cache_id != inum)
+ continue;
+
+ assert (np->references);
+ spin_unlock (&diskfs_node_refcnt_lock);
+ return np;
+ }
+ assert (0);
+}
+
+/* The last reference to a node has gone away; drop it from the hash
+ table and clean all state in the dn structure. */
+void
+diskfs_node_norefs (struct node *np)
+{
+ struct cluster_chain *last = np->dn->first;
+
+ *np->dn->hprevp = np->dn->hnext;
+ if (np->dn->hnext)
+ np->dn->hnext->dn->hprevp = np->dn->hprevp;
+
+ while (last)
+ {
+ struct cluster_chain *next = last->next;
+ free(last);
+ last = next;
+ }
+
+ if (np->dn->translator)
+ free (np->dn->translator);
+
+ /* It is safe to unlock diskfs_node_refcnt_lock here for a while because
+ all references to the node have been deleted. */
+ if (np->dn->dirnode)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ diskfs_nrele (np->dn->dirnode);
+ spin_lock (&diskfs_node_refcnt_lock);
+ }
+
+ assert (!np->dn->pager);
+
+ free (np->dn);
+ free (np);
+}
+
+/* The last hard reference to a node has gone away; arrange to have
+ all the weak references dropped that can be. */
+void
+diskfs_try_dropping_softrefs (struct node *np)
+{
+ drop_pager_softrefs (np);
+}
+
+/* The last hard reference to a node has gone away. */
+void
+diskfs_lost_hardrefs (struct node *np)
+{
+}
+
+/* A new hard reference to a node has been created; it's now OK to
+ have unused weak references. */
+void
+diskfs_new_hardrefs (struct node *np)
+{
+ allow_pager_softrefs (np);
+}
+
+/* Read stat information out of the directory entry. */
+static error_t
+read_node (struct node *np, vm_address_t buf)
+{
+ /* XXX This needs careful investigation. */
+ error_t err;
+ struct stat *st = &np->dn_stat;
+ struct disknode *dn = np->dn;
+ struct dirrect *dr;
+ struct node *dp = 0;
+ struct vi_key vk = vi_key(np->dn->inode);
+ vm_prot_t prot = VM_PROT_READ;
+ memory_object_t memobj;
+ vm_size_t buflen = 0;
+ int our_buf = 0;
+
+ st->st_fstype = FSTYPE_MSLOSS;
+ st->st_fsid = getpid ();
+ st->st_ino = np->cache_id;
+ st->st_gen = 0;
+ st->st_rdev = 0;
+
+ st->st_nlink = 1;
+ st->st_uid = fs_uid;
+ st->st_gid = fs_gid;
+
+ st->st_rdev = 0;
+
+ np->dn->translator = 0;
+ np->dn->translen = 0;
+
+ st->st_flags = 0;
+
+ /* FIXME: If we are called through diskfs_alloc_node for a newly
+ allocated node that has no directory entry yet, only set a
+ minimal amount of data until the dirent is created (and we get
+ called a second time?). */
+ if (vk.dir_inode == 0 && vk.dir_offset == (void *) 2)
+ return 0;
+
+ if (vk.dir_inode == 0)
+ dr = &dr_root_node;
+ else
+ {
+ if (buf == 0)
+ {
+ /* FIXME: We know intimately that the parent dir is locked
+ by libdiskfs. The only case it is not locked is for NFS
+ (fsys_getfile) and we disabled that. */
+ dp = ifind (vk.dir_inode);
+ assert (dp);
+
+ /* Map in the directory contents. */
+ memobj = diskfs_get_filemap (dp, prot);
+
+ if (memobj == MACH_PORT_NULL)
+ return errno;
+
+ buflen = round_page (dp->dn_stat.st_size);
+ err = vm_map (mach_task_self (),
+ &buf, buflen, 0, 1, memobj, 0, 0, prot, prot, 0);
+ mach_port_deallocate (mach_task_self (), memobj);
+ our_buf = 1;
+ }
+
+ dr = (struct dirrect *) (buf + vk.dir_offset);
+ }
+
+ /* Files in fatfs depend on the directory that hold the file. */
+ np->dn->dirnode = dp;
+ if (dp)
+ dp->references++;
+
+ rwlock_reader_lock(&np->dn->dirent_lock);
+
+ dn->start_cluster = (read_word (dr->first_cluster_high) << 16)
+ + read_word (dr->first_cluster_low);
+
+ if (dr->attribute & FAT_DIR_ATTR_DIR)
+ {
+ st->st_mode = S_IFDIR | 0777;
+ /* When we read in the node the first time, diskfs_root_node is
+ zero. */
+ if ((diskfs_root_node == 0 || np == diskfs_root_node)
+ && (fat_type == FAT12 || fat_type == FAT16))
+ {
+ st->st_size = read_dword (dr->file_size);
+ np->allocsize = nr_of_root_dir_sectors << log2_bytes_per_sector;
+ }
+ else
+ {
+ np->allocsize = 0;
+ rwlock_reader_lock(&dn->alloc_lock);
+ err = fat_extend_chain (np, FAT_EOC, 0);
+ rwlock_reader_unlock(&dn->alloc_lock);
+ if (err)
+ {
+ if (our_buf && buf)
+ munmap ((caddr_t) buf, buflen);
+ return err;
+ }
+ st->st_size = np->allocsize;
+ }
+ }
+ else
+ {
+ unsigned offset;
+ st->st_mode = S_IFREG | 0666;
+ st->st_size = read_dword (dr->file_size);
+ np->allocsize = np->dn_stat.st_size;
+
+ /* Round up to a cluster multiple. */
+ offset = np->allocsize & (bytes_per_cluster - 1);
+ if (offset > 0)
+ np->allocsize += bytes_per_cluster - offset;
+ }
+ if (dr->attribute & FAT_DIR_ATTR_RDONLY)
+ st->st_mode &= ~0222;
+
+ {
+ struct timespec ts;
+ fat_to_epoch (dr->write_date, dr->write_time, &ts);
+ st->st_ctim = st->st_mtim = st->st_atim = ts;
+ }
+
+ st->st_blksize = bytes_per_sector;
+ st->st_blocks = (st->st_size - 1) / bytes_per_sector + 1;
+
+ rwlock_reader_unlock(&np->dn->dirent_lock);
+
+ if (our_buf && buf)
+ munmap ((caddr_t) buf, buflen);
+ return 0;
+}
+
+/* Return 0 if NP's owner can be changed to UID; otherwise return an
+ error code. */
+error_t
+diskfs_validate_owner_change (struct node *np, uid_t uid)
+{
+ /* Allow configurable uid. */
+ if (uid != 0)
+ return EINVAL;
+ return 0;
+}
+
+/* Return 0 if NP's group can be changed to GID; otherwise return an
+ error code. */
+error_t
+diskfs_validate_group_change (struct node *np, gid_t gid)
+{
+ /* Allow configurable gid. */
+ if (gid != 0)
+ return EINVAL;
+ return 0;
+}
+
+/* Return 0 if NP's mode can be changed to MODE; otherwise return an
+ error code. It must always be possible to clear the mode; diskfs
+ will not ask for permission before doing so. */
+error_t
+diskfs_validate_mode_change (struct node *np, mode_t mode)
+{
+ /* XXX */
+ return 0;
+}
+
+/* Return 0 if NP's author can be changed to AUTHOR; otherwise return
+ an error code. */
+error_t
+diskfs_validate_author_change (struct node *np, uid_t author)
+{
+ return (author == np->dn_stat.st_uid) ? 0 : EINVAL;
+}
+
+/* The user may define this function. Return 0 if NP's flags can be
+ changed to FLAGS; otherwise return an error code. It must always
+ be possible to clear the flags. */
+error_t
+diskfs_validate_flags_change (struct node *np, int flags)
+{
+ if (flags & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND))
+ return EINVAL;
+ else
+ return 0;
+}
+
+/* Writes everything from NP's inode to the disk image. */
+void
+write_node (struct node *np)
+{
+ error_t err;
+ struct stat *st = &np->dn_stat;
+ struct dirrect *dr;
+ struct node *dp;
+ struct vi_key vk = vi_key(np->dn->inode);
+ vm_prot_t prot = VM_PROT_READ | VM_PROT_WRITE;
+ memory_object_t memobj;
+ vm_address_t buf = 0;
+ vm_size_t buflen;
+
+ /* XXX: If we are called from node-create before direnter was
+ called, DR is zero and we can't update the node. Just return
+ here, and leave it to direnter to call us again when we are
+ ready.
+ If we are called for the root directory node, we can't do anything,
+ as FAT root dirs don't have a directory entry for themselve.
+ */
+ if (vk.dir_inode == 0 || np == diskfs_root_node)
+ return;
+
+ assert (!np->dn_set_ctime && !np->dn_set_atime && !np->dn_set_mtime);
+ if (np->dn_stat_dirty)
+ {
+ assert (!diskfs_readonly);
+
+ dp = np->dn->dirnode;
+ assert (dp);
+
+ mutex_lock (&dp->lock);
+
+ /* Map in the directory contents. */
+ memobj = diskfs_get_filemap (dp, prot);
+
+ if (memobj == MACH_PORT_NULL)
+ {
+ mutex_unlock (&dp->lock);
+ /* FIXME: We shouldn't ignore this error. */
+ return;
+ }
+
+ buflen = round_page (dp->dn_stat.st_size);
+ err = vm_map (mach_task_self (),
+ &buf, buflen, 0, 1, memobj, 0, 0, prot, prot, 0);
+ mach_port_deallocate (mach_task_self (), memobj);
+
+ dr = (struct dirrect *) (buf + vk.dir_offset);
+
+ rwlock_writer_lock(&np->dn->dirent_lock);
+ write_word (dr->first_cluster_low, np->dn->start_cluster & 0xffff);
+ write_word (dr->first_cluster_high, np->dn->start_cluster >> 16);
+
+ write_dword (dr->file_size, st->st_size);
+
+ /* Write time. */
+ fat_from_epoch ((unsigned char *) &dr->write_date,
+ (unsigned char *) &dr->write_time, &st->st_mtime);
+
+ rwlock_writer_unlock(&np->dn->dirent_lock);
+ np->dn_stat_dirty = 0;
+
+ munmap ((caddr_t) buf, buflen);
+ mutex_unlock (&dp->lock);
+ }
+}
+
+/* Reload all data specific to NODE from disk, without writing anything.
+ Always called with DISKFS_READONLY true. */
+error_t
+diskfs_node_reload (struct node *node)
+{
+ struct cluster_chain *last = node->dn->first;
+
+ while (last)
+ {
+ struct cluster_chain *next = last->next;
+ free(last);
+ last = next;
+ }
+ flush_node_pager (node);
+ read_node (node, 0);
+
+ return 0;
+}
+
+/* For each active node, call FUN. The node is to be locked around the call
+ to FUN. If FUN returns non-zero for any node, then immediately stop, and
+ return that value. */
+error_t
+diskfs_node_iterate (error_t (*fun)(struct node *))
+{
+ error_t err = 0;
+ int n, num_nodes = 0;
+ struct node *node, **node_list, **p;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+
+ /* We must copy everything from the hash table into another data structure
+ to avoid running into any problems with the hash-table being modified
+ during processing (normally we delegate access to hash-table with
+ diskfs_node_refcnt_lock, but we can't hold this while locking the
+ individual node locks). */
+
+ for (n = 0; n < INOHSZ; n++)
+ for (node = nodehash[n]; node; node = node->dn->hnext)
+ num_nodes++;
+
+ node_list = alloca (num_nodes * sizeof (struct node *));
+ p = node_list;
+ for (n = 0; n < INOHSZ; n++)
+ for (node = nodehash[n]; node; node = node->dn->hnext)
+ {
+ *p++ = node;
+ node->references++;
+ }
+
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ p = node_list;
+ while (num_nodes-- > 0)
+ {
+ node = *p++;
+ if (!err)
+ {
+ mutex_lock (&node->lock);
+ err = (*fun)(node);
+ mutex_unlock (&node->lock);
+ }
+ diskfs_nrele (node);
+ }
+
+ return err;
+}
+
+/* Write all active disknodes into the ext2_inode pager. */
+void
+write_all_disknodes ()
+{
+ error_t write_one_disknode (struct node *node)
+ {
+ diskfs_set_node_times (node);
+
+ /* Update the inode image. */
+ write_node (node);
+
+ return 0;
+ }
+
+ diskfs_node_iterate (write_one_disknode);
+}
+
+
+void
+refresh_node_stats ()
+{
+ error_t refresh_one_node_stat (struct node *node)
+ {
+ node->dn_stat.st_uid = fs_uid;
+ node->dn_stat.st_gid = fs_gid;
+ return 0;
+ }
+
+ diskfs_node_iterate (refresh_one_node_stat);
+}
+
+
+/* Sync the info in NP->dn_stat and any associated format-specific
+ information to disk. If WAIT is true, then return only after the
+ physicial media has been completely updated. */
+void
+diskfs_write_disknode (struct node *np, int wait)
+{
+ write_node (np);
+}
+
+/* Set *ST with appropriate values to reflect the current state of the
+ filesystem. */
+error_t
+diskfs_set_statfs (struct statfs *st)
+{
+ st->f_type = FSTYPE_MSLOSS;
+ st->f_bsize = bytes_per_sector;
+ st->f_blocks = total_sectors;
+ st->f_bfree = fat_get_freespace () * sectors_per_cluster;
+ st->f_bavail = st->f_bfree;
+ /* There is no easy way to determine the number of (free) files on a
+ FAT filesystem. */
+ st->f_files = 0;
+ st->f_ffree = 0;
+ st->f_fsid = getpid ();
+ st->f_namelen = 0;
+ st->f_favail = st->f_ffree;
+ st->f_frsize = bytes_per_cluster;
+ return 0;
+}
+
+error_t
+diskfs_set_translator (struct node *node,
+ const char *name, u_int namelen,
+ struct protid *cred)
+{
+ assert (!diskfs_readonly);
+ return EOPNOTSUPP;
+}
+
+error_t
+diskfs_get_translator (struct node *node, char **namep, u_int *namelen)
+{
+ assert(0);
+}
+
+void
+diskfs_shutdown_soft_ports ()
+{
+ /* Should initiate termination of internally held pager ports
+ (the only things that should be soft) XXX */
+}
+
+/* The user must define this function. Truncate locked node NODE to be SIZE
+ bytes long. (If NODE is already less than or equal to SIZE bytes
+ long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
+ is set) then this should clear the symlink, even if
+ diskfs_create_symlink_hook stores the link target elsewhere. */
+error_t
+diskfs_truncate (struct node *node, loff_t length)
+{
+ error_t err;
+ loff_t offset;
+
+ diskfs_check_readonly ();
+ assert (!diskfs_readonly);
+
+ if (length >= node->dn_stat.st_size)
+ return 0;
+
+ /* If the file is not being truncated to a cluster boundary, the
+ contents of the partial cluster following the end of the file
+ must be zeroed in case it ever becomes accessible again because
+ of subsequent file growth. */
+ offset = length & (bytes_per_cluster - 1);
+ if (offset > 0)
+ {
+ diskfs_node_rdwr (node, (void *)zerocluster, length, bytes_per_cluster - offset,
+ 1, 0, 0);
+ diskfs_file_update (node, 1);
+ }
+
+ rwlock_writer_lock (&node->dn->alloc_lock);
+
+ /* Update the size on disk; if we crash, we'll loose. */
+ node->dn_stat.st_size = length;
+ node->dn_set_mtime = 1;
+ node->dn_set_ctime = 1;
+ diskfs_node_update (node, 1);
+
+ err = diskfs_catch_exception ();
+ if (!err)
+ {
+ fat_truncate_node(node, round_cluster(length) >> log2_bytes_per_cluster);
+ node->allocsize = round_cluster(length);
+ }
+ diskfs_end_catch_exception ();
+
+ node->dn_set_mtime = 1;
+ node->dn_set_ctime = 1;
+ node->dn_stat_dirty = 1;
+
+ rwlock_writer_unlock (&node->dn->alloc_lock);
+
+ return err;
+}
+
+error_t
+diskfs_S_file_get_storage_info (struct protid *cred,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ loff_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
+{
+ /* XXX */
+ return EOPNOTSUPP;
+}
+
+/* Free node NP; the on disk copy has already been synced with
+ diskfs_node_update (where NP->dn_stat.st_mode was 0). It's
+ mode used to be OLD_MODE. */
+void
+diskfs_free_node (struct node *np, mode_t old_mode)
+{
+ assert (!diskfs_readonly);
+
+ vi_free(np->dn->inode);
+}
+
+/* The user must define this function. Allocate a new node to be of
+ mode MODE in locked directory DP (don't actually set the mode or
+ modify the dir, that will be done by the caller); the user
+ responsible for the request can be identified with CRED. Set *NP
+ to be the newly allocated node. */
+error_t
+diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node)
+{
+ error_t err;
+ ino_t inum;
+ inode_t inode;
+ struct node *np;
+
+ assert (!diskfs_readonly);
+
+ /* FIXME: We use a magic key here that signals read_node that we are
+ not entered in any directory yet. */
+ err = vi_new((struct vi_key) {0,2}, &inum, &inode);
+ if (err)
+ return err;
+
+ err = diskfs_cached_lookup (inum, &np);
+ if (err)
+ return err;
+
+ /* FIXME: We know that readnode couldn't put this in. */
+ np->dn->dirnode = dir;
+ dir->references++;
+
+ *node = np;
+ return 0;
+}
diff --git a/fatfs/main.c b/fatfs/main.c
new file mode 100644
index 00000000..b85d7fe7
--- /dev/null
+++ b/fatfs/main.c
@@ -0,0 +1,281 @@
+/* main.c - FAT filesystem.
+
+ Copyright (C) 1997, 1998, 1999, 2002, 2003, 2007
+ Free Software Foundation, Inc.
+
+ Written by Thomas Bushnell, n/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <error.h>
+#include <argp.h>
+#include <argz.h>
+#include <limits.h>
+
+#include <version.h>
+#include "fatfs.h"
+
+struct node *diskfs_root_node;
+
+struct store *store = 0;
+struct store_parsed *store_parsed = 0;
+char *diskfs_disk_name = 0;
+
+char *diskfs_server_name = "fatfs";
+char *diskfs_server_version = HURD_VERSION;
+char *diskfs_extra_version = "GNU Hurd";
+int diskfs_synchronous = 0;
+
+int diskfs_link_max = 1;
+int diskfs_name_max = FAT_NAME_MAX;
+int diskfs_maxsymlinks = 8; /* XXX */
+
+/* Handy source of zeroes. */
+vm_address_t zerocluster;
+
+struct dirrect dr_root_node;
+
+/* The UID and GID for all files in the filesystem. */
+uid_t default_fs_uid;
+gid_t default_fs_gid;
+uid_t fs_uid;
+gid_t fs_gid;
+
+/* fatfs specific options. */
+static const struct argp_option options[] =
+ {
+ { "uid", 'U', "uid", 0, "Default uid for files" },
+ { "gid", 'G', "gid", 0, "Default gid for files" },
+ { 0 }
+ };
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'U':
+ if (arg)
+ fs_uid = atoi (arg);
+ refresh_node_stats ();
+ break;
+ case 'G':
+ if (arg)
+ fs_gid = atoi (arg);
+ refresh_node_stats ();
+ break;
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input;
+ break;
+ case ARGP_KEY_SUCCESS:
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/* Add our startup arguments to the standard diskfs set. */
+static const struct argp_child startup_children[] =
+ { { &diskfs_store_startup_argp }, { 0 } };
+static struct argp startup_argp =
+ { options, parse_opt, 0, 0, startup_children };
+
+/* Similarly at runtime. */
+static const struct argp_child runtime_children[] =
+ { { &diskfs_std_runtime_argp }, { 0 } };
+static struct argp runtime_argp =
+ { options, parse_opt, 0, 0, runtime_children };
+
+struct argp *diskfs_runtime_argp = (struct argp *) &runtime_argp;
+
+
+/* Override the standard diskfs routine so we can add our own
+ output. */
+error_t
+diskfs_append_args (char **argz, unsigned *argz_len)
+{
+ error_t err;
+ char buf[100];
+
+ /* Get the standard things. */
+ err = diskfs_append_std_options (argz, argz_len);
+
+ if (!err && fs_uid != default_fs_uid)
+ {
+ snprintf (buf, sizeof buf, "--uid=%d", fs_uid);
+ err = argz_add (argz, argz_len, buf);
+ }
+
+ if (!err && fs_gid != default_fs_gid)
+ {
+ snprintf (buf, sizeof buf, "--gid=%d", fs_gid);
+ err = argz_add (argz, argz_len, buf);
+ }
+
+ if (! err)
+ err = store_parsed_append_args (store_parsed, argz, argz_len);
+
+ return err;
+}
+
+
+/* Fetch the root node. */
+static void
+fetch_root ()
+{
+ error_t err;
+ ino_t inum;
+ inode_t inode;
+
+ memset (&dr_root_node, 0, sizeof(struct dirrect));
+
+ /* Fill root directory entry. XXX Should partially be in fat.c */
+ dr_root_node.attribute = FAT_DIR_ATTR_DIR;
+ if (fat_type == FAT32)
+ {
+ /* FAT12/16: There is no such thing as a start cluster, because
+ the whole root dir is in a special region after the FAT. The
+ start cluster of the root node is undefined. */
+ dr_root_node.first_cluster_high[1]
+ = sblock->compat.fat32.root_cluster[3];
+ dr_root_node.first_cluster_high[0]
+ = sblock->compat.fat32.root_cluster[2];
+ dr_root_node.first_cluster_low[1] = sblock->compat.fat32.root_cluster[1];
+ dr_root_node.first_cluster_low[0] = sblock->compat.fat32.root_cluster[0];
+ }
+
+ /* Determine size of the directory (different for fat12/16 vs 32). */
+ switch (fat_type)
+ {
+ case FAT12:
+ case FAT16:
+ write_dword(dr_root_node.file_size, nr_of_root_dir_sectors
+ << log2_bytes_per_sector);
+ break;
+
+ case FAT32:
+ {
+ /* Extend the cluster chain of the root directory and calculate
+ file_size based on that. */
+ cluster_t rootdir;
+ int cs = 0;
+
+ rootdir = (cluster_t) *sblock->compat.fat32.root_cluster;
+ while (rootdir != FAT_EOC)
+ {
+ fat_get_next_cluster (rootdir, &rootdir);
+ cs++;
+ }
+ write_dword (dr_root_node.file_size, cs << log2_bytes_per_cluster);
+ }
+ break;
+
+ default:
+ assert(!"don't know how to set size of root dir");
+ };
+
+ /* The magic vi_key {0, 1} for the root directory is distinguished
+ from the vi_zero_key (in the dir_offset value) as well as all
+ normal virtual inode keys (in the dir_inode value). Enter the
+ disknode into the inode table. */
+ err = vi_new ((struct vi_key) {0, 1}, &inum, &inode);
+ assert_perror (err);
+
+ /* Allocate a node for the root directory disknode in
+ diskfs_root_node. */
+ if (!err)
+ err = diskfs_cached_lookup (inum, &diskfs_root_node);
+
+ assert_perror (err);
+
+ mutex_unlock (&diskfs_root_node->lock);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ mach_port_t bootstrap;
+
+ default_fs_uid = getuid ();
+ default_fs_gid = getgid ();
+ fs_uid = default_fs_uid;
+ fs_gid = default_fs_gid;
+
+ /* This filesystem is not capable of writing yet. */
+ diskfs_readonly = 1;
+ diskfs_hard_readonly = 1;
+
+ /* Initialize the diskfs library, parse arguments, and open the
+ store. This starts the first diskfs thread for us. */
+ store = diskfs_init_main (&startup_argp, argc, argv, &store_parsed,
+ &bootstrap);
+
+ fat_read_sblock ();
+
+ create_fat_pager ();
+
+ zerocluster = (vm_address_t) mmap (0, bytes_per_cluster, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+
+ fetch_root ();
+
+ diskfs_startup_diskfs (bootstrap, 0);
+
+ cthread_exit (0);
+
+ return 0;
+}
+
+
+/* Nothing to do for read-only medium. */
+error_t
+diskfs_reload_global_state ()
+{
+ return 0;
+}
+
+
+error_t
+diskfs_set_hypermetadata (int wait, int clean)
+{
+ return 0;
+}
+
+
+void
+diskfs_readonly_changed (int readonly)
+{
+ /* We should never get here because we set diskfs_hard_readonly above. */
+ abort ();
+}
+
+/* FIXME: libdiskfs doesn't lock the parent dir when looking up a node
+ for fsys_getfile, so we disable NFS. */
+error_t
+diskfs_S_fsys_getfile (mach_port_t fsys,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ uid_t *uids, mach_msg_type_number_t nuids,
+ gid_t *gids, mach_msg_type_number_t ngids,
+ char *handle, mach_msg_type_number_t handle_len,
+ mach_port_t *file, mach_msg_type_name_t *file_type)
+{
+ return EOPNOTSUPP;
+}
diff --git a/fatfs/node-create.c b/fatfs/node-create.c
new file mode 100644
index 00000000..d85508b3
--- /dev/null
+++ b/fatfs/node-create.c
@@ -0,0 +1,204 @@
+/* node-create.c - Making new files.
+ Copyright (C) 1992,93,94,96,98,2001, 2003 Free Software Foundation
+ Modified for fatfs by Marco Gerards.
+
+ 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. */
+
+
+/* This file was copied from libdiskfs and changed for fatfs. The
+ libdiskfs version created the "." and ".." links. After creating
+ those the directory was created and the "." and ".." were linked
+ in. In normally it is sane to do this, but this is impossible for
+ fatfs because fatfs doesn't support hardlinks. For fatfs the "."
+ and".." directory entries are created after creating the
+ directory. */
+
+
+#include <hurd/diskfs.h>
+
+/* This enables SysV style group behaviour. New nodes inherit the GID
+ of the user creating them unless the SGID bit is set of the parent
+ directory. */
+int _diskfs_no_inherit_dir_group;
+
+/* Create a new node. Give it MODE; if that includes IFDIR, also
+ initialize `.' and `..' in the new directory. Return the node in NPP.
+ CRED identifies the user responsible for the call. If NAME is nonzero,
+ then link the new node into DIR with name NAME; DS is the result of a
+ prior diskfs_lookup for creation (and DIR has been held locked since).
+ DIR must always be provided as at least a hint for disk allocation
+ strategies. */
+error_t
+diskfs_create_node (struct node *dir,
+ const char *name,
+ mode_t mode,
+ struct node **newnode,
+ struct protid *cred,
+ struct dirstat *ds)
+{
+ struct node *np;
+ error_t err;
+ uid_t newuid;
+ gid_t newgid;
+
+ if (diskfs_check_readonly ())
+ {
+ *newnode = NULL;
+ return EROFS;
+ }
+
+ /* Make the node */
+ err = diskfs_alloc_node (dir, mode, newnode);
+ if (err)
+ {
+ if (name)
+ diskfs_drop_dirstat (dir, ds);
+ *newnode = NULL;
+ return err;
+ }
+
+ np = *newnode;
+
+ /* Initialize the on-disk fields. */
+ if (cred->user->uids->num)
+ newuid = cred->user->uids->ids[0];
+ else
+ {
+ newuid = dir->dn_stat.st_uid;
+ mode &= ~S_ISUID;
+ }
+ err = diskfs_validate_owner_change (np, newuid);
+ if (err)
+ goto change_err;
+ np->dn_stat.st_uid = newuid;
+ if (np->author_tracks_uid)
+ np->dn_stat.st_author = newuid;
+
+ if (!_diskfs_no_inherit_dir_group)
+ {
+ newgid = dir->dn_stat.st_gid;
+ if (!idvec_contains (cred->user->gids, newgid))
+ mode &= ~S_ISGID;
+ }
+ else
+ {
+ if (dir->dn_stat.st_mode & S_ISGID)
+ {
+ /* If the parent dir has the sgid bit set, inherit its gid.
+ If the new node is a directory, also inherit the sgid bit
+ set. */
+ newgid = dir->dn_stat.st_gid;
+ if (S_ISDIR (mode))
+ mode |= S_ISGID;
+ else
+ {
+ if (!idvec_contains (cred->user->gids, newgid))
+ mode &= ~S_ISGID;
+ }
+ }
+ else
+ {
+ if (cred->user->gids->num)
+ newgid = cred->user->gids->ids[0];
+ else
+ {
+ newgid = dir->dn_stat.st_gid;
+ mode &= ~S_ISGID;
+ }
+ }
+ }
+
+ err = diskfs_validate_group_change (np, newgid);
+ if (err)
+ goto change_err;
+ np->dn_stat.st_gid = newgid;
+
+ np->dn_stat.st_rdev = 0;
+ np->dn_stat.st_nlink = !!name;
+ err = diskfs_validate_mode_change (np, mode);
+ if (err)
+ goto change_err;
+ np->dn_stat.st_mode = mode;
+
+ np->dn_stat.st_blocks = 0;
+ np->dn_stat.st_size = 0;
+ np->dn_stat.st_flags = 0;
+ np->dn_set_atime = 1;
+ np->dn_set_mtime = 1;
+ np->dn_set_ctime = 1;
+
+ diskfs_node_update (np, 1);
+
+ if (err)
+ {
+ change_err:
+ np->dn_stat.st_mode = 0;
+ np->dn_stat.st_nlink = 0;
+ if (name)
+ diskfs_drop_dirstat (dir, ds);
+ *newnode = NULL;
+ return err;
+ }
+
+ if (name)
+ {
+ err = diskfs_direnter (dir, name, np, ds, cred);
+ if (err)
+ {
+ np->dn_stat.st_nlink = 0;
+ np->dn_set_ctime = 1;
+ diskfs_nput (np);
+ }
+
+ /* For fatfs the "." and ".." directory entries should be
+ created after the directory was created and not before the
+ directory was created. */
+ if (S_ISDIR (mode))
+ err = diskfs_init_dir (np, dir, cred);
+
+ if (err)
+ {
+ struct dirstat *ds = alloca (diskfs_dirstat_size);
+ struct node *foo;
+ /* Keep old error intact. */
+ error_t err;
+
+ np->dn_stat.st_nlink = 0;
+
+ err = diskfs_lookup (dir, name, REMOVE, &foo, ds, cred);
+ if (err)
+ {
+ /* The new node couldn't be removed, we have a big
+ problem now. */
+ *newnode = NULL;
+ return err;
+ }
+
+ err = diskfs_dirremove (dir, foo, name, ds);
+ if (err)
+ {
+ diskfs_nput (np);
+ *newnode = NULL;
+ return err;
+ }
+ }
+
+ diskfs_node_update (np, 1);
+ }
+ if (err)
+ *newnode = NULL;
+
+ return err;
+}
diff --git a/fatfs/pager.c b/fatfs/pager.c
new file mode 100644
index 00000000..e617af03
--- /dev/null
+++ b/fatfs/pager.c
@@ -0,0 +1,1022 @@
+/* pager.c - Pager for fatfs.
+ Copyright (C) 1997, 1999, 2002, 2003 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <hurd/store.h>
+#include "fatfs.h"
+
+/* A ports bucket to hold pager ports. */
+struct port_bucket *pager_bucket;
+
+/* Mapped image of the FAT. */
+void *fat_image;
+
+spin_lock_t node_to_page_lock = SPIN_LOCK_INITIALIZER;
+
+#ifdef DONT_CACHE_MEMORY_OBJECTS
+#define MAY_CACHE 0
+#else
+#define MAY_CACHE 1
+#endif
+
+#define STAT_INC(field) (void) 0
+
+#define MAX_FREE_PAGE_BUFS 32
+
+static spin_lock_t free_page_bufs_lock = SPIN_LOCK_INITIALIZER;
+static void *free_page_bufs = 0;
+static int num_free_page_bufs = 0;
+
+/* Returns a single page page-aligned buffer. */
+static void *
+get_page_buf ()
+{
+ void *buf;
+
+ spin_lock (&free_page_bufs_lock);
+
+ buf = free_page_bufs;
+ if (buf == 0)
+ {
+ spin_unlock (&free_page_bufs_lock);
+ buf = mmap (0, vm_page_size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf == (void *) -1)
+ buf = 0;
+ }
+ else
+ {
+ free_page_bufs = *(void **)buf;
+ num_free_page_bufs--;
+ spin_unlock (&free_page_bufs_lock);
+ }
+
+ return buf;
+}
+
+/* Frees a block returned by get_page_buf. */
+static void
+free_page_buf (void *buf)
+{
+ spin_lock (&free_page_bufs_lock);
+ if (num_free_page_bufs < MAX_FREE_PAGE_BUFS)
+ {
+ *(void **)buf = free_page_bufs;
+ free_page_bufs = buf;
+ num_free_page_bufs++;
+ spin_unlock (&free_page_bufs_lock);
+ }
+ else
+ {
+ spin_unlock (&free_page_bufs_lock);
+ munmap (buf, vm_page_size);
+ }
+}
+
+/* Find the location on disk of page OFFSET in NODE. Return the disk
+ cluster in CLUSTER. If *LOCK is 0, then it a reader
+ lock is acquired on NODE's ALLOC_LOCK before doing anything, and left
+ locked after return -- even if an error is returned. 0 on success or an
+ error code otherwise is returned. */
+static error_t
+find_cluster (struct node *node, vm_offset_t offset,
+ cluster_t *cluster, struct rwlock **lock)
+{
+ error_t err;
+
+ if (!*lock)
+ {
+ *lock = &node->dn->alloc_lock;
+ rwlock_reader_lock (*lock);
+ }
+
+ if (round_cluster (offset) > node->allocsize)
+ return EIO;
+
+ err = fat_getcluster (node, offset >> log2_bytes_per_cluster, 0, cluster);
+
+ return err;
+}
+
+/* Read one page for the root dir pager at offset PAGE, into BUF. This
+ may need to select several filesystem sectors to satisfy one page.
+ Assumes that fat_type is FAT12 or FAT16, and that vm_page_size is a
+ power of two multiple of bytes_per_sector (which happens to be true).
+*/
+static error_t
+root_dir_pager_read_page (vm_offset_t page, void **buf, int *writelock)
+{
+ error_t err;
+ daddr_t addr;
+ int overrun = 0;
+ size_t read = 0;
+
+ *writelock = 0;
+
+ if (page >= diskfs_root_node->allocsize)
+ {
+ return EIO;
+ }
+
+ rwlock_reader_lock(&diskfs_root_node->dn->alloc_lock);
+
+ addr = first_root_dir_byte + page;
+ if (page + vm_page_size > diskfs_root_node->allocsize)
+ overrun = page + vm_page_size - diskfs_root_node->allocsize;
+
+ err = store_read (store, addr >> store->log2_block_size,
+ vm_page_size, (void **) buf, &read);
+ if (!err && read != vm_page_size)
+ err = EIO;
+
+ rwlock_reader_unlock (&diskfs_root_node->dn->alloc_lock);
+
+ if (overrun)
+ bzero ((void *) *buf + vm_page_size - overrun, overrun);
+
+ return err;
+}
+
+/* Read one page for the pager backing NODE at offset PAGE, into BUF. This
+ may need to select only a part of a filesystem block to satisfy one page.
+ Assumes that bytes_per_cluster is a power of two multiple of vm_page_size.
+*/
+static error_t
+file_pager_read_small_page (struct node *node, vm_offset_t page,
+ void **buf, int *writelock)
+{
+ error_t err;
+ struct rwlock *lock = NULL;
+ cluster_t cluster;
+ size_t read = 0;
+
+ *writelock = 0;
+
+ if (page >= node->allocsize)
+ {
+ return EIO;
+ }
+
+ err = find_cluster (node, page, &cluster, &lock);
+
+ if (!err)
+ {
+ err = store_read (store,
+ FAT_FIRST_CLUSTER_BLOCK(cluster)
+ + ((page % bytes_per_cluster)
+ >> store->log2_block_size),
+ vm_page_size, (void **) buf, &read);
+
+ if (read != vm_page_size)
+ err = EIO;
+ }
+
+ if (lock)
+ rwlock_reader_unlock (lock);
+
+ return err;
+}
+
+/* Read one page for the pager backing NODE at offset PAGE, into BUF. This
+ may need to read several filesystem blocks to satisfy one page, and tries
+ to consolidate the i/o if possible.
+ Assumes that vm_page_size is a power of two multiple of bytes_per_cluster.
+*/
+static error_t
+file_pager_read_huge_page (struct node *node, vm_offset_t page,
+ void **buf, int *writelock)
+{
+ error_t err;
+ int offs = 0;
+ struct rwlock *lock = NULL;
+ int left = vm_page_size;
+ cluster_t pending_clusters = 0;
+ int num_pending_clusters = 0;
+
+ /* Read the NUM_PENDING_CLUSTERS cluster in PENDING_CLUSTERS, into the buffer
+ pointed to by BUF (allocating it if necessary) at offset OFFS. OFFS in
+ adjusted by the amount read, and NUM_PENDING_CLUSTERS is zeroed. Any read
+ error is returned. */
+ error_t do_pending_reads ()
+ {
+ if (num_pending_clusters > 0)
+ {
+ size_t dev_block = FAT_FIRST_CLUSTER_BLOCK(pending_clusters);
+ size_t amount = num_pending_clusters << log2_bytes_per_cluster;
+ /* 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
+ buffer, otherwise, we try to read directly into the tail of the
+ buffer we've already got. */
+ void *new_buf = *buf + offs;
+ size_t new_len = offs == 0 ? 0 : vm_page_size - offs;
+
+ STAT_INC (file_pagein_reads);
+
+ err = store_read (store, dev_block, amount, &new_buf, &new_len);
+ if (err)
+ return err;
+ else if (amount != new_len)
+ return EIO;
+
+ if (new_buf != *buf + offs)
+ {
+ /* The read went into a different buffer than the one we
+ passed. */
+ if (offs == 0)
+ /* First read, make the returned page be our buffer. */
+ *buf = new_buf;
+ else
+ /* We've already got some buffer, so copy into it. */
+ {
+ memcpy (*buf + offs, new_buf, new_len);
+ free_page_buf (new_buf); /* Return NEW_BUF to our pool. */
+ STAT_INC (file_pagein_freed_bufs);
+ }
+ }
+
+ offs += new_len;
+ num_pending_clusters = 0;
+ }
+
+ return 0;
+ }
+
+ STAT_INC (file_pageins);
+
+ *writelock = 0;
+
+ if (page >= node->allocsize)
+ {
+ err = EIO;
+ left = 0;
+ }
+ else if (page + left > node->allocsize)
+ left = node->allocsize - page;
+
+ while (left > 0)
+ {
+ cluster_t cluster;
+
+ err = find_cluster (node, page, &cluster, &lock);
+ if (err)
+ break;
+
+ if (cluster != pending_clusters + num_pending_clusters)
+ {
+ err = do_pending_reads ();
+ if (err)
+ break;
+ pending_clusters = cluster;
+ }
+
+ num_pending_clusters++;
+
+ page += bytes_per_cluster;
+ left -= bytes_per_cluster;
+ }
+
+ if (!err && num_pending_clusters > 0)
+ err = do_pending_reads();
+
+ if (lock)
+ rwlock_reader_unlock (lock);
+
+ return err;
+}
+
+struct pending_clusters
+ {
+ /* The cluster number of the first of the clusters. */
+ cluster_t cluster;
+ /* How many clusters we have. */
+ loff_t num;
+ /* A (page-aligned) buffer pointing to the data we're dealing with. */
+ void *buf;
+ /* And an offset into BUF. */
+ int offs;
+};
+
+/* Write the any pending clusters in PC. */
+static error_t
+pending_clusters_write (struct pending_clusters *pc)
+{
+ if (pc->num > 0)
+ {
+ error_t err;
+ size_t dev_block = FAT_FIRST_CLUSTER_BLOCK(pc->cluster);
+
+ size_t length = pc->num << log2_bytes_per_cluster, amount;
+
+ if (pc->offs > 0)
+ /* Put what we're going to write into a page-aligned buffer. */
+ {
+ void *page_buf = get_page_buf ();
+ memcpy ((void *) page_buf, pc->buf + pc->offs, length);
+ err = store_write (store, dev_block, page_buf, length, &amount);
+ free_page_buf (page_buf);
+ }
+ else
+ err = store_write (store, dev_block, pc->buf, length, &amount);
+ if (err)
+ return err;
+ else if (amount != length)
+ return EIO;
+
+ pc->offs += length;
+ pc->num = 0;
+ }
+
+ return 0;
+}
+
+static void
+pending_clusters_init (struct pending_clusters *pc, void *buf)
+{
+ pc->buf = buf;
+ pc->cluster = 0;
+ pc->num = 0;
+ pc->offs = 0;
+}
+
+/* Add the disk cluster CLUSTER to the list of destination disk clusters pending in
+ PC. */
+static error_t
+pending_clusters_add (struct pending_clusters *pc, cluster_t cluster)
+{
+ if (cluster != pc->cluster + pc->num)
+ {
+ error_t err = pending_clusters_write (pc);
+ if (err)
+ return err;
+ pc->cluster = cluster;
+ }
+ pc->num++;
+ return 0;
+}
+
+/* Write one page for the pager backing NODE, at offset PAGE, into BUF. This
+ may need to write several filesystem blocks to satisfy one page, and tries
+ to consolidate the i/o if possible.
+ Assumes that vm_page_size is a power of two multiple of bytes_per_cluster.
+*/
+static error_t
+file_pager_write_huge_page (struct node *node, vm_offset_t offset, void *buf)
+{
+ error_t err = 0;
+ struct pending_clusters pc;
+ struct rwlock *lock = &node->dn->alloc_lock;
+ cluster_t cluster;
+ int left = vm_page_size;
+
+ pending_clusters_init (&pc, buf);
+
+ /* Holding NODE->dn->alloc_lock effectively locks NODE->allocsize,
+ at least for the cases we care about: pager_unlock_page,
+ diskfs_grow and diskfs_truncate. */
+ rwlock_reader_lock (&node->dn->alloc_lock);
+
+ if (offset >= node->allocsize)
+ left = 0;
+ else if (offset + left > node->allocsize)
+ left = node->allocsize - offset;
+
+ STAT_INC (file_pageouts);
+
+ while (left > 0)
+ {
+ err = find_cluster (node, offset, &cluster, &lock);
+ if (err)
+ break;
+ pending_clusters_add (&pc, cluster);
+ offset += bytes_per_cluster;
+ left -= bytes_per_cluster;
+ }
+
+ if (!err)
+ pending_clusters_write (&pc);
+
+ rwlock_reader_unlock (&node->dn->alloc_lock);
+
+ return err;
+}
+
+/* Write one page for the root dir pager, at offset OFFSET, into BUF. This
+ may need to write several filesystem blocks to satisfy one page, and tries
+ to consolidate the i/o if possible.
+ Assumes that fat_type is FAT12 or FAT16 and that vm_page_size is a
+ power of two multiple of bytes_per_sector.
+*/
+static error_t
+root_dir_pager_write_page (vm_offset_t offset, void *buf)
+{
+ error_t err;
+ daddr_t addr;
+ size_t length;
+ size_t write = 0;
+
+ if (offset >= diskfs_root_node->allocsize)
+ return 0;
+
+ /* Holding NODE->dn->alloc_lock effectively locks NODE->allocsize,
+ at least for the cases we care about: pager_unlock_page,
+ diskfs_grow and diskfs_truncate. */
+ rwlock_reader_lock (&diskfs_root_node->dn->alloc_lock);
+
+ addr = first_root_dir_byte + offset;
+
+ if (offset + vm_page_size > diskfs_root_node->allocsize)
+ length = diskfs_root_node->allocsize - offset;
+ else
+ length = vm_page_size;
+
+ err = store_write (store, addr >> store->log2_block_size, (void **) buf,
+ length, &write);
+ if (!err && write != length)
+ err = EIO;
+
+ rwlock_reader_unlock (&diskfs_root_node->dn->alloc_lock);
+
+ return err;
+}
+
+/* Write one page for the pager backing NODE, at offset OFFSET, into BUF. This
+ may need to write several filesystem blocks to satisfy one page, and tries
+ to consolidate the i/o if possible.
+ Assumes that bytes_per_cluster is a power of two multiple of vm_page_size.
+*/
+static error_t
+file_pager_write_small_page (struct node *node, vm_offset_t offset, void *buf)
+{
+ error_t err;
+ struct rwlock *lock = NULL;
+ cluster_t cluster;
+ size_t write = 0;
+
+ if (offset >= node->allocsize)
+ return 0;
+
+ /* Holding NODE->dn->alloc_lock effectively locks NODE->allocsize,
+ at least for the cases we care about: pager_unlock_page,
+ diskfs_grow and diskfs_truncate. */
+ rwlock_reader_lock (&node->dn->alloc_lock);
+
+ err = find_cluster (node, offset, &cluster, &lock);
+
+ if (!err)
+ {
+ err = store_write (store, FAT_FIRST_CLUSTER_BLOCK(cluster)
+ + ((offset % bytes_per_cluster)
+ >> store->log2_block_size),
+ (void **) buf, vm_page_size, &write);
+ if (write != vm_page_size)
+ err = EIO;
+ }
+
+ if (lock)
+ rwlock_reader_unlock (lock);
+
+ return err;
+}
+
+static error_t
+fat_pager_read_page (vm_offset_t page, void **buf, int *writelock)
+{
+ error_t err;
+ size_t length = vm_page_size, read = 0;
+ vm_size_t fat_end = bytes_per_sector * sectors_per_fat;
+
+ if (page + vm_page_size > fat_end)
+ length = fat_end - page;
+
+ page += first_fat_sector * bytes_per_sector;
+ err = store_read (store, page >> store->log2_block_size, length, buf, &read);
+ if (read != length)
+ return EIO;
+ if (!err && length != vm_page_size)
+ memset ((void *)(*buf + length), 0, vm_page_size - length);
+
+ *writelock = 0;
+
+ return err;
+}
+
+static error_t
+fat_pager_write_page (vm_offset_t page, void *buf)
+{
+ error_t err = 0;
+ size_t length = vm_page_size, amount;
+ vm_size_t fat_end = bytes_per_sector * sectors_per_fat;
+
+ if (page + vm_page_size > fat_end)
+ length = fat_end - page;
+
+ page += first_fat_sector * bytes_per_sector;
+ err = store_write (store, page >> store->log2_block_size,
+ buf, length, &amount);
+ if (!err && length != amount)
+ err = EIO;
+
+ return err;
+}
+
+/* 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
+ the pager should make the page writeable. */
+error_t
+pager_read_page (struct user_pager_info *pager, vm_offset_t page,
+ vm_address_t *buf, int *writelock)
+{
+ if (pager->type == FAT)
+ return fat_pager_read_page (page, (void **)buf, writelock);
+ else
+ {
+ if (pager->node == diskfs_root_node
+ && (fat_type == FAT12 || fat_type == FAT16))
+ return root_dir_pager_read_page (page, (void **)buf, writelock);
+ else
+ {
+ if (bytes_per_cluster < vm_page_size)
+ return file_pager_read_huge_page (pager->node, page,
+ (void **)buf, writelock);
+ else
+ return file_pager_read_small_page (pager->node, page,
+ (void **)buf, writelock);
+ }
+ }
+}
+
+/* Satisfy a pager write request for either the disk pager or file pager
+ PAGER, from the page at offset PAGE from BUF. */
+error_t
+pager_write_page (struct user_pager_info *pager, vm_offset_t page,
+ vm_address_t buf)
+{
+ if (pager->type == FAT)
+ return fat_pager_write_page (page, (void *)buf);
+ else
+ {
+ if (pager->node == diskfs_root_node
+ && (fat_type == FAT12 || fat_type == FAT16))
+ return root_dir_pager_write_page (page, (void *)buf);
+ else
+ {
+ if (bytes_per_cluster < vm_page_size)
+ return file_pager_write_huge_page (pager->node, page,
+ (void *)buf);
+ else
+ return file_pager_write_small_page (pager->node, page,
+ (void *)buf);
+ }
+ }
+}
+
+/* Make page PAGE writable, at least up to ALLOCSIZE. */
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t page)
+{
+ /* All pages are writeable. The disk pages anyway, and the file
+ pages because blocks are directly allocated in diskfs_grow. */
+ return 0;
+}
+
+/* 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
+ identifies the user responsible for the call. Note that this will
+ only be called for real files, so there is no need to be careful
+ about the root dir node on FAT12/16. */
+error_t
+diskfs_grow (struct node *node, loff_t size, struct protid *cred)
+{
+ diskfs_check_readonly ();
+ assert (!diskfs_readonly);
+
+ if (size > node->allocsize)
+ {
+ error_t err = 0;
+ loff_t old_size;
+ volatile loff_t new_size;
+ volatile cluster_t end_cluster;
+ cluster_t new_end_cluster;
+ struct disknode *dn = node->dn;
+
+ rwlock_writer_lock (&dn->alloc_lock);
+
+ old_size = node->allocsize;
+ new_size = ((size + bytes_per_cluster - 1) >> log2_bytes_per_cluster)
+ << log2_bytes_per_cluster;
+
+ /* The first unallocated clusters after the old and new ends of
+ the file, respectively. */
+ end_cluster = old_size >> log2_bytes_per_cluster;
+ new_end_cluster = new_size >> log2_bytes_per_cluster;
+
+ if (new_end_cluster > end_cluster)
+ {
+ err = diskfs_catch_exception ();
+ while (!err && end_cluster < new_end_cluster)
+ {
+ cluster_t disk_cluster;
+ err = fat_getcluster (node, end_cluster++, 1, &disk_cluster);
+ }
+ diskfs_end_catch_exception ();
+
+ if (err)
+ /* Reflect how much we allocated successfully. */
+ new_size = (end_cluster - 1) >> log2_bytes_per_cluster;
+ }
+
+ STAT_INC (file_grows);
+
+ node->allocsize = new_size;
+
+ rwlock_writer_unlock (&dn->alloc_lock);
+
+ return err;
+ }
+ else
+ return 0;
+}
+
+/* This syncs a single file (NODE) to disk. Wait for all I/O to
+ complete if WAIT is set. NODE->lock must be held. */
+void
+diskfs_file_update (struct node *node, int wait)
+{
+ struct pager *pager;
+
+ spin_lock (&node_to_page_lock);
+ pager = node->dn->pager;
+ if (pager)
+ ports_port_ref (pager);
+ spin_unlock (&node_to_page_lock);
+
+ if (pager)
+ {
+ pager_sync (pager, wait);
+ ports_port_deref (pager);
+ }
+
+ diskfs_node_update (node, wait);
+}
+
+/* Invalidate any pager data associated with NODE. */
+void
+flush_node_pager (struct node *node)
+{
+ struct pager *pager;
+ struct disknode *dn = node->dn;
+
+ spin_lock (&node_to_page_lock);
+ pager = dn->pager;
+ if (pager)
+ ports_port_ref (pager);
+ spin_unlock (&node_to_page_lock);
+
+ if (pager)
+ {
+ pager_flush (pager, 1);
+ ports_port_deref (pager);
+ }
+}
+
+/* Return in *OFFSET and *SIZE the minimum valid address the pager
+ will accept and the size of the object. */
+inline error_t
+pager_report_extent (struct user_pager_info *pager,
+ vm_address_t *offset, vm_size_t *size)
+{
+ assert (pager->type == FAT || pager->type == FILE_DATA);
+
+ *offset = 0;
+
+ if (pager->type == FAT)
+ *size = bytes_per_sector * sectors_per_fat;
+ else
+ *size = pager->node->allocsize;
+
+ return 0;
+}
+
+/* This is called when a pager is being deallocated after all extant
+ send rights have been destroyed. */
+void
+pager_clear_user_data (struct user_pager_info *upi)
+{
+ if (upi->type == FILE_DATA)
+ {
+ struct pager *pager;
+
+ spin_lock (&node_to_page_lock);
+ pager = upi->node->dn->pager;
+ if (pager && pager_get_upi (pager) == upi)
+ upi->node->dn->pager = 0;
+ spin_unlock (&node_to_page_lock);
+
+ diskfs_nrele_light (upi->node);
+ }
+
+ free (upi);
+}
+
+/* This will be called when the ports library wants to drop weak
+ references. The pager library creates no weak references itself.
+ If the user doesn't either, then it's OK for this function to do
+ nothing. */
+void
+pager_dropweak (struct user_pager_info *p __attribute__ ((unused)))
+{
+}
+
+/* Create the disk pager. */
+void
+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,
+ bytes_per_sector * sectors_per_fat,
+ &fat_image);
+}
+
+/* Call this to create a FILE_DATA pager and return a send right.
+ NODE must be locked. */
+mach_port_t
+diskfs_get_filemap (struct node *node, vm_prot_t prot)
+{
+ mach_port_t right;
+
+ assert (S_ISDIR (node->dn_stat.st_mode)
+ || S_ISREG (node->dn_stat.st_mode)
+ || (S_ISLNK (node->dn_stat.st_mode)));
+
+ spin_lock (&node_to_page_lock);
+ do
+ {
+ struct pager *pager = node->dn->pager;
+ if (pager)
+ {
+ /* Because PAGER is not a real reference, this might be
+ nearly deallocated. If that's so, then the port right
+ will be null. In that case, clear here and loop. The
+ deallocation will complete separately. */
+ right = pager_get_port (pager);
+ if (right == MACH_PORT_NULL)
+ node->dn->pager = 0;
+ else
+ pager_get_upi (pager)->max_prot |= prot;
+ }
+ else
+ {
+ struct user_pager_info *upi =
+ malloc (sizeof (struct user_pager_info));
+ upi->type = FILE_DATA;
+ upi->node = node;
+ upi->max_prot = prot;
+ diskfs_nref_light (node);
+ node->dn->pager =
+ pager_create (upi, pager_bucket, MAY_CACHE,
+ MEMORY_OBJECT_COPY_DELAY);
+ if (node->dn->pager == 0)
+ {
+ diskfs_nrele_light (node);
+ free (upi);
+ spin_unlock (&node_to_page_lock);
+ return MACH_PORT_NULL;
+ }
+
+ right = pager_get_port (node->dn->pager);
+ ports_port_deref (node->dn->pager);
+ }
+ }
+ while (right == MACH_PORT_NULL);
+ spin_unlock (&node_to_page_lock);
+
+ mach_port_insert_right (mach_task_self (), right, right,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+ return right;
+}
+
+/* Call this when we should turn off caching so that unused memory
+ object ports get freed. */
+void
+drop_pager_softrefs (struct node *node)
+{
+ struct pager *pager;
+
+ spin_lock (&node_to_page_lock);
+ pager = node->dn->pager;
+ if (pager)
+ ports_port_ref (pager);
+ spin_unlock (&node_to_page_lock);
+
+ if (MAY_CACHE && pager)
+ pager_change_attributes (pager, 0, MEMORY_OBJECT_COPY_DELAY, 0);
+ if (pager)
+ ports_port_deref (pager);
+}
+
+/* Call this when we should turn on caching because it's no longer
+ important for unused memory object ports to get freed. */
+void
+allow_pager_softrefs (struct node *node)
+{
+ struct pager *pager;
+
+ spin_lock (&node_to_page_lock);
+ pager = node->dn->pager;
+ if (pager)
+ ports_port_ref (pager);
+ spin_unlock (&node_to_page_lock);
+
+ if (MAY_CACHE && pager)
+ pager_change_attributes (pager, 1, MEMORY_OBJECT_COPY_DELAY, 0);
+ if (pager)
+ ports_port_deref (pager);
+}
+
+/* Call this to find out the struct pager * corresponding to the
+ FILE_DATA pager of inode IP. This should be used *only* as a
+ subsequent argument to register_memory_fault_area, and will be
+ deleted when the kernel interface is fixed. NODE must be
+ locked. */
+struct pager *
+diskfs_get_filemap_pager_struct (struct node *node)
+{
+ /* This is safe because pager can't be cleared; there must be an
+ active mapping for this to be called. */
+ return node->dn->pager;
+}
+
+/* Shutdown all the pagers (except the disk pager). */
+void
+diskfs_shutdown_pager ()
+{
+ error_t shutdown_one (void *v_p)
+ {
+ struct pager *p = v_p;
+ if (p != diskfs_disk_pager)
+ pager_shutdown (p);
+ return 0;
+ }
+
+ write_all_disknodes ();
+
+ ports_bucket_iterate (pager_bucket, shutdown_one);
+
+ pager_sync (diskfs_disk_pager, 1);
+
+ /* Despite the name of this function, we never actually shutdown the
+ disk pager, just make sure it's synced. */
+}
+
+/* Sync all the pagers. */
+void
+diskfs_sync_everything (int wait)
+{
+ error_t sync_one (void *v_p)
+ {
+ struct pager *p = v_p;
+ if (p != diskfs_disk_pager)
+ pager_sync (p, wait);
+ return 0;
+ }
+
+ write_all_disknodes ();
+ ports_bucket_iterate (pager_bucket, sync_one);
+ pager_sync (diskfs_disk_pager, wait);
+}
+
+static void
+disable_caching ()
+{
+ error_t block_cache (void *arg)
+ {
+ struct pager *p = arg;
+
+ pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_DELAY, 1);
+ return 0;
+ }
+
+ /* Loop through the pagers and turn off caching one by one,
+ synchronously. That should cause termination of each pager. */
+ ports_bucket_iterate (pager_bucket, block_cache);
+}
+
+static void
+enable_caching ()
+{
+ error_t enable_cache (void *arg)
+ {
+ struct pager *p = arg;
+ struct user_pager_info *upi = pager_get_upi (p);
+
+ pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_DELAY, 0);
+
+ /* It's possible that we didn't have caching on before, because
+ the user here is the only reference to the underlying node
+ (actually, that's quite likely inside this particular
+ routine), and if that node has no links. So dinkle the node
+ ref counting scheme here, which will cause caching to be
+ turned off, if that's really necessary. */
+ if (upi->type == FILE_DATA)
+ {
+ diskfs_nref (upi->node);
+ diskfs_nrele (upi->node);
+ }
+
+ return 0;
+ }
+
+ ports_bucket_iterate (pager_bucket, enable_cache);
+}
+
+/* Tell diskfs if there are pagers exported, and if none, then
+ prevent any new ones from showing up. */
+int
+diskfs_pager_users ()
+{
+ int npagers = ports_count_bucket (pager_bucket);
+
+ if (npagers <= 1)
+ return 0;
+
+ if (MAY_CACHE)
+ {
+ disable_caching ();
+
+ /* Give it a second; the kernel doesn't actually shutdown
+ immediately. XXX */
+ sleep (1);
+
+ npagers = ports_count_bucket (pager_bucket);
+ if (npagers <= 1)
+ return 0;
+
+ /* Darn, there are actual honest users. Turn caching back on,
+ and return failure. */
+ enable_caching ();
+ }
+
+ ports_enable_bucket (pager_bucket);
+
+ return 1;
+}
+
+/* Return the bitwise or of the maximum prot parameter (the second arg
+ to diskfs_get_filemap) for all active user pagers. */
+vm_prot_t
+diskfs_max_user_pager_prot ()
+{
+ vm_prot_t max_prot = 0;
+ int npagers = ports_count_bucket (pager_bucket);
+
+ if (npagers > 1)
+ /* More than just the disk pager. */
+ {
+ error_t add_pager_max_prot (void *v_p)
+ {
+ struct pager *p = v_p;
+ struct user_pager_info *upi = pager_get_upi (p);
+ if (upi->type == FILE_DATA)
+ max_prot |= upi->max_prot;
+ /* Stop iterating if MAX_PROT is as filled as it is going to
+ get. */
+ return (max_prot
+ == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)) ? 1 : 0;
+ }
+
+ disable_caching (); /* Make any silly pagers go away. */
+
+ /* Give it a second; the kernel doesn't actually shutdown
+ immediately. XXX */
+ sleep (1);
+
+ ports_bucket_iterate (pager_bucket, add_pager_max_prot);
+
+ enable_caching ();
+ }
+
+ ports_enable_bucket (pager_bucket);
+
+ return max_prot;
+}
diff --git a/fatfs/virt-inode.c b/fatfs/virt-inode.c
new file mode 100644
index 00000000..d7c990d6
--- /dev/null
+++ b/fatfs/virt-inode.c
@@ -0,0 +1,235 @@
+/* Virtual Inode management routines
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* TODO: Improve NEW by keeping a bitmap of free inodes.
+ TODO: Improve RLOOKUP by keeping an open hash for keys (need to change
+ CHANGE and FREE, too).
+ TODO: Improve FREE by keeping the highest inode in use and keep it
+ up-to-date. When a table page can be freed, do so. */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <spin-lock.h>
+#include "virt-inode.h"
+
+/* Each virtual inode contains the UNIQUE key it belongs to,
+ which must not be zero. */
+
+vi_key_t vi_zero_key = {0, 0};
+
+struct v_inode
+{
+ vi_key_t key;
+};
+
+/* All inodes are stored in a table by their index number - 1.
+ Decrementing by one is necessary because inode numbers start from 1,
+ but our table is zero based. */
+
+#define LOG2_TABLE_PAGE_SIZE 10
+#define TABLE_PAGE_SIZE (1 << LOG2_TABLE_PAGE_SIZE)
+
+struct table_page
+{
+ struct table_page *next;
+
+ struct v_inode vi[TABLE_PAGE_SIZE];
+};
+
+struct table_page *inode_table;
+
+spin_lock_t inode_table_lock = SPIN_LOCK_INITIALIZER;
+
+/* See vi_new and vi_rlookup. */
+error_t
+_vi_new(vi_key_t key, ino_t *inode, inode_t *v_inode)
+{
+ struct table_page *table = inode_table;
+ struct table_page *prev_table = 0;
+ int page = 0;
+ int offset = 0;
+
+ while (table && memcmp(&vi_zero_key, &table->vi[offset].key, sizeof(vi_key_t)))
+ {
+ offset++;
+ if (offset == TABLE_PAGE_SIZE)
+ {
+ offset = 0;
+ page++;
+ prev_table = table;
+ table = table->next;
+ }
+ }
+
+ if (table)
+ {
+ table->vi[offset].key = key;
+ /* See above for rationale of increment. */
+ *inode = (page << LOG2_TABLE_PAGE_SIZE) + offset + 1;
+ *v_inode = &table->vi[offset];
+ }
+ else
+ {
+ struct table_page **pagep;
+
+ if (prev_table)
+ pagep = &prev_table->next;
+ else
+ pagep = &inode_table;
+ *pagep = (struct table_page *) malloc (sizeof (struct table_page));
+ if (!*pagep)
+ {
+ return ENOSPC;
+ }
+ memset (*pagep, 0, sizeof (struct table_page));
+ (*pagep)->vi[0].key = key;
+ /* See above for rationale of increment. */
+ *inode = (page << LOG2_TABLE_PAGE_SIZE) + 1;
+ *v_inode = &(*pagep)->vi[0];
+ }
+
+ return 0;
+}
+
+/* Allocate a new inode number INODE for KEY and return it as well as
+ the virtual inode V_INODE. Return 0 on success, otherwise an error
+ value (ENOSPC). */
+error_t
+vi_new(vi_key_t key, ino_t *inode, inode_t *v_inode)
+{
+ error_t err;
+
+ assert (memcmp(&vi_zero_key, &key, sizeof (vi_key_t)));
+
+ spin_lock (&inode_table_lock);
+ err = _vi_new(key, inode, v_inode);
+ spin_unlock (&inode_table_lock);
+
+ return err;
+}
+
+/* Get the key for virtual inode V_INODE. */
+vi_key_t
+vi_key(inode_t v_inode)
+{
+ return v_inode->key;
+}
+
+/* Get the inode V_INODE belonging to inode number INODE.
+ Returns 0 if this inode number is free. */
+inode_t
+vi_lookup(ino_t inode)
+{
+ struct table_page *table = inode_table;
+ /* See above for rationale of decrement. */
+ int page = (inode - 1) >> LOG2_TABLE_PAGE_SIZE;
+ int offset = (inode - 1) & (TABLE_PAGE_SIZE - 1);
+ inode_t v_inode = 0;
+
+ spin_lock (&inode_table_lock);
+
+ while (table && page > 0)
+ {
+ page--;
+ table = table->next;
+ }
+
+ if (table)
+ v_inode = &table->vi[offset];
+
+ spin_unlock (&inode_table_lock);
+
+ return v_inode;
+}
+
+/* Get the inode number and virtual inode belonging to key KEY.
+ Returns 0 on success and EINVAL if no inode is found for KEY and
+ CREATE is false. Otherwise, if CREATE is true, allocate new inode. */
+error_t
+vi_rlookup(vi_key_t key, ino_t *inode, inode_t *v_inode, int create)
+{
+ error_t err = 0;
+ struct table_page *table = inode_table;
+ int page = 0;
+ int offset = 0;
+
+ assert (memcmp(&vi_zero_key, &key, sizeof (vi_key_t)));
+
+ spin_lock (&inode_table_lock);
+
+ while (table && memcmp(&table->vi[offset].key, &key, sizeof (vi_key_t)))
+ {
+ offset++;
+ if (offset == TABLE_PAGE_SIZE)
+ {
+ offset = 0;
+ page++;
+ table = table->next;
+ }
+ }
+
+ if (table)
+ {
+ /* See above for rationale of increment. */
+ *inode = (page << LOG2_TABLE_PAGE_SIZE) + offset + 1;
+ *v_inode = &table->vi[offset];
+ }
+ else
+ {
+ if (create)
+ err = _vi_new (key, inode, v_inode);
+ else
+ err = EINVAL;
+ }
+
+ spin_unlock (&inode_table_lock);
+
+ return err;
+}
+
+/* Change the key of virtual inode V_INODE to KEY and return the old
+ key. */
+vi_key_t vi_change(inode_t v_inode, vi_key_t key)
+{
+ vi_key_t okey = v_inode->key;
+
+ assert (memcmp(&vi_zero_key, &key, sizeof (vi_key_t)));
+ v_inode->key = key;
+ return okey;
+}
+
+/* Release virtual inode V_INODE, freeing the inode number. Return
+ the key. */
+vi_key_t vi_free(inode_t v_inode)
+{
+ vi_key_t key;
+ spin_lock (&inode_table_lock);
+ key = v_inode->key;
+ v_inode->key = vi_zero_key;
+ spin_unlock (&inode_table_lock);
+ return key;
+}
+
+
+
+
+
+
diff --git a/fatfs/virt-inode.h b/fatfs/virt-inode.h
new file mode 100644
index 00000000..5b889d23
--- /dev/null
+++ b/fatfs/virt-inode.h
@@ -0,0 +1,69 @@
+/* virt-inode.h - Public interface for the virtual inode management routines.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef VIRT_INODE_H
+#define VIRT_INODE_H
+
+#include <errno.h>
+#include <dirent.h>
+
+/* Define struct vi_key to match your needs. It is passed by copy,
+ so don't make it too huge. Equality is tested with memcpy, because
+ C == operator doesn't work on structs. */
+
+struct vi_key
+{
+ ino_t dir_inode;
+ int dir_offset;
+};
+
+typedef struct vi_key vi_key_t;
+
+extern vi_key_t vi_zero_key;
+
+typedef struct v_inode *inode_t;
+
+/* Allocate a new inode number INODE for KEY and return it as well as
+ the virtual inode V_INODE. Return 0 on success, otherwise an error
+ value (ENOSPC). */
+error_t vi_new(vi_key_t key, ino_t *inode, inode_t *v_inode);
+
+/* Get the key for virtual inode V_INODE. */
+vi_key_t vi_key(inode_t v_inode);
+
+/* Get the inode V_INODE belonging to inode number INODE.
+ Returns 0 if this inode number is free. */
+inode_t vi_lookup(ino_t inode);
+
+/* Get the inode number and virtual inode belonging to key KEY.
+ Returns 0 on success and EINVAL if no inode is found for KEY and
+ CREATE is false. Otherwise, if CREATE is true, allocate a new
+ inode. */
+error_t vi_rlookup(vi_key_t key, ino_t *inode, inode_t *v_inode, int create);
+
+/* Change the key of virtual inode V_INODE to KEY and return the old
+ key. */
+vi_key_t vi_change(inode_t v_inode, vi_key_t key);
+
+/* Release virtual inode V_INODE, freeing the inode number. Return
+ the key. */
+vi_key_t vi_free(inode_t v_inode);
+
+#endif
diff --git a/fstests/ChangeLog b/fstests/ChangeLog
deleted file mode 100644
index e7bbb31c..00000000
--- a/fstests/ChangeLog
+++ /dev/null
@@ -1,47 +0,0 @@
-Thu Jun 27 17:59:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (targets): Comment out opendisk for now.
-
-Mon Apr 29 16:43:44 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (OBJS): Delete variable.
-
-Thu Jul 6 21:03:12 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (OBJS): New var.
- (timertest, fstests, opendisk, fdtests): List object files.
-
-Wed Aug 31 12:02:01 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (targets): Added opendisk.
- (SRCS): Added opendisk.c.
- * opendisk.c: New file.
-
-Wed Aug 31 03:26:13 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * fstests.c: Include unistd.h.
- (main): #if 0 out unused variables.
-
-Tue Aug 16 13:55:04 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * timertest.c (main): Don't sigpause; instead getchar, so we are
- blocked in an RPC when the signal arrives--do sigpause on EOF.
-
-Thu Jul 21 19:14:30 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten to use new scheme.
-
-Tue Jul 19 12:43:00 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (OBJS): Deleted variables.
- (fstests, fdtests, timertest): Don't use variable $(link) anymore.
- (install): Install all three programs.
-
-Tue Jul 5 14:20:48 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (SRCS): New variable.
-
-Mon Jun 20 15:05:34 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (install): Use $(INSTALL_BIN) instead of cp.
-
diff --git a/fstests/fstests.c b/fstests/fstests.c
index 600eb3ef..4a0b35d5 100644
--- a/fstests/fstests.c
+++ b/fstests/fstests.c
@@ -1,5 +1,5 @@
/* Test filesystem behavior
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -27,6 +27,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd.h>
#include <fcntl.h>
#include <errno.h>
+#include <error.h>
#include <unistd.h>
int check_refs (mach_port_t port) /* To call from gdb */
@@ -38,56 +39,57 @@ int check_refs (mach_port_t port) /* To call from gdb */
return err ? -err : refs;
}
-void
+int
main ()
{
mach_port_t root;
+#if HURDISH_TESTS
extern file_t *_hurd_init_dtable;
char string[] = "Did this get into the file?\n";
-#if 0
file_t filetowrite;
retry_type retry;
char pathbuf[1024];
int written;
- int err;
+ error_t err;
#endif
root = getcrdir ();
printf ("fstests running...\n");
-#if 0
+#if HURDISH_TESTS
if ((err = dir_unlink (root, "CREATED")) && err != ENOENT)
- printf ("Error on unlink: %d\n", err);
- else if (err = dir_pathtrans (root, "CREATED", O_WRITE | O_CREAT, 0666,
- &retry, pathbuf, &filetowrite))
- printf ("Error on pathtrans: %d\n", err);
+ error (0, err, "Error on unlink");
+ else if (err = dir_lookup (root, "CREATED", O_WRITE | O_CREAT, 0666,
+ &retry, pathbuf, &filetowrite))
+ error (0, err, "Error on lookup");
else if (err = io_write (filetowrite, string, strlen (string), -1, &written))
- printf ("Error on write: %d\n", err);
+ error (0, err, "Error on write");
else if (written != strlen (string))
- printf ("Short write: %d\n", written);
+ error (0, 0, "Short write: %d\n", written);
else if (err = file_syncfs (filetowrite, 1, 0))
- printf ("Error on sync: %d\n", err);
+ error (0, err, "Error on sync");
#else
if (unlink ("/newdir"))
- perror ("unlink");
+ error (0, errno, "unlink");
if (rmdir ("/newdir"))
- perror ("1st rmdir");
+ error (0, errno, "1st rmdir");
if (mkdir ("/newdir", 0777))
- perror ("1st mkdir");
+ error (0, errno, "1st mkdir");
if (rename ("/newdir", "/newdir2"))
- perror ("1st rename");
+ error (0, errno, "1st rename");
if (rmdir ("/foo"))
- perror ("2nd rmdir");
+ error (0, errno, "2nd rmdir");
if (mkdir ("/foo", 0777))
- perror ("2nd mkdir");
+ error (0, errno, "2nd mkdir");
if (rename ("/newdir2", "/foo"))
- perror ("2nd rename");
- if (sync ())
- perror ("sync");
+ error (0, errno, "2nd rename");
+ sync ();
#endif
printf ("All done.\n");
malloc (0);
+
+ return 0;
}
diff --git a/fstests/timertest.c b/fstests/timertest.c
index 3c011fd9..2d602560 100644
--- a/fstests/timertest.c
+++ b/fstests/timertest.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/* A test for the Hurd timer and getchar
+ Copyright (C) 1994,2001,02 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
@@ -18,6 +18,9 @@
#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <error.h>
void
alarm_handler (int signo)
@@ -27,7 +30,7 @@ alarm_handler (int signo)
}
int
-main()
+main(int argc, char *argv[])
{
struct itimerval real_timer;
@@ -35,14 +38,11 @@ main()
real_timer.it_interval.tv_sec = 1;
real_timer.it_value.tv_usec = 0;
real_timer.it_value.tv_sec = 1;
-
+
signal (SIGALRM, alarm_handler);
-
+
if (setitimer (ITIMER_REAL, &real_timer, 0) < 0)
- {
- perror ("Setting timer");
- exit (1);
- }
+ error (1, errno, "Setting timer");
while (1)
{
@@ -51,10 +51,7 @@ main()
fflush (stdout);
c = getchar ();
if (ferror (stdin))
- {
- perror ("getchar");
- exit (1);
- }
+ error (1, errno, "getchar");
if (c == EOF)
{
puts ("Saw EOF. Pausing (no input)...");
@@ -65,4 +62,3 @@ main()
printf ("Saw %.3o\n", c);
}
}
-
diff --git a/devio/Makefile b/ftpfs/Makefile
index a1494a55..0b6c9e2b 100644
--- a/devio/Makefile
+++ b/ftpfs/Makefile
@@ -1,6 +1,6 @@
-# Makefile for devio
+# Makefile for ftpfs
#
-# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1997, 2000 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
@@ -16,21 +16,15 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-dir := devio
+dir := ftpfs
makemode := server
-target = devio
-SRCS = dev.c iostate.c window.c devio.c open.c devpager.c io.c rdwr.c mem.c
-LCLHDRS = dev.h iostate.h window.h open.h ptypes.h mem.h
-DIST_FILES = MAKEDEV
+target = ftpfs
+
+SRCS = ftpfs.c fs.c host.c netfs.c dir.c conn.c ccache.c node.c ncache.c
+LCLHDRS = ftpfs.h ccache.h
OBJS = $(SRCS:.c=.o)
+HURDLIBS = netfs fshelp iohelp threads ports ihash ftpconn shouldbeinlibc
include ../Makeconf
-
-devio: $(OBJS) ../libtrivfs/libtrivfs.a ../libpager/libpager.a ../libports/libports.a ../libfshelp/libfshelp.a ../libthreads/libthreads.a ../libihash/libihash.a ../libshouldbeinlibc/libshouldbeinlibc.a
-
-install: $(prefix)/dev/MAKEDEV
-
-$(prefix)/dev/MAKEDEV: MAKEDEV
- $(INSTALL_PROGRAM) $(srcdir)/MAKEDEV $(prefix)/dev/MAKEDEV
diff --git a/ftpfs/ccache.c b/ftpfs/ccache.c
new file mode 100644
index 00000000..56f3bf1e
--- /dev/null
+++ b/ftpfs/ccache.c
@@ -0,0 +1,293 @@
+/* Remote file contents caching
+
+ Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <hurd/netfs.h>
+
+#include "ccache.h"
+
+#define READ_CHUNK_SIZE (8*1024)
+#define ALLOC_CHUNK_SIZE (64*1024)
+
+/* Read LEN bytes at OFFS in the file referred to by CC into DATA, or return
+ an error. */
+error_t
+ccache_read (struct ccache *cc, off_t offs, size_t len, void *data)
+{
+ error_t err = 0;
+ size_t max = offs + len;
+
+ mutex_lock (&cc->lock);
+
+ if (max > cc->size)
+ max = cc->size;
+
+ while (cc->max < max && !err)
+ {
+ if (cc->fetching_active)
+ /* Some thread is fetching data, so just let it do its thing, but get
+ a wakeup call when it's done. */
+ {
+ if (hurd_condition_wait (&cc->wakeup, &cc->lock))
+ err = EINTR;
+ }
+ else
+ {
+ int re_connected = 0;
+ struct netnode *nn = cc->node->nn;
+
+ cc->fetching_active = 1;
+
+ while (cc->max < max && !err)
+ {
+ mutex_unlock (&cc->lock);
+
+ if (! cc->conn)
+ /* We need to setup a connection to fetch data over. */
+ {
+ err = ftpfs_get_ftp_conn (nn->fs, &cc->conn);
+ if (! err)
+ {
+ err = ftp_conn_start_retrieve (cc->conn, nn->rmt_path,
+ &cc->data_conn);
+ if (err == ENOENT)
+ err = ESTALE;
+ if (err)
+ {
+ ftpfs_release_ftp_conn (nn->fs, cc->conn);
+ cc->conn = 0;
+ }
+ else
+ cc->data_conn_pos = 0;
+ }
+ re_connected = 1;
+ }
+
+ if (! err)
+ /* Try and read some data over the connection. */
+ {
+ size_t new_end = cc->max + READ_CHUNK_SIZE;
+
+ if (new_end > cc->size)
+ new_end = cc->size;
+
+ if (new_end > cc->alloced)
+ /* Make some room in memory for the new part of the
+ image. */
+ {
+ size_t alloc_end = cc->alloced + ALLOC_CHUNK_SIZE;
+
+ if (alloc_end < new_end)
+ alloc_end = new_end;
+ else if (alloc_end > cc->size)
+ alloc_end = cc->size;
+
+ if (cc->alloced == 0)
+ {
+ vm_address_t addr = 0;
+ addr = (vm_address_t) mmap (0, alloc_end,
+ PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ err = (addr == -1) ? errno : 0;
+ if (! err)
+ cc->image = (char *)addr;
+ }
+ else
+ {
+ vm_address_t addr =
+ (vm_address_t)cc->image + cc->alloced;
+ /* XXX. This can't be replaced with mmap until we
+ have MAP_EXCL. -tb */
+ err = vm_allocate (mach_task_self (),
+ &addr, alloc_end - cc->alloced,
+ 0);
+ if (err == EKERN_NO_SPACE)
+ /* Gack. We've goota move the whole splooge. */
+ {
+ addr = 0;
+ addr = (vm_address_t) mmap (0, alloc_end,
+ PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ err = (addr == -1) ? errno : 0;
+ if (! err)
+ /* That worked; copy what's already-fetched. */
+ {
+ bcopy (cc->image, (void *)addr, cc->max);
+ munmap (cc->image, cc->alloced);
+ cc->image = (char *)addr;
+ }
+ }
+ }
+ if (! err)
+ cc->alloced = alloc_end;
+ }
+
+ if (! err)
+ {
+ ssize_t rd =
+ read (cc->data_conn,
+ cc->image + cc->data_conn_pos,
+ new_end - cc->data_conn_pos);
+ if (rd < 0)
+ err = errno;
+ else if (rd == 0)
+ /* EOF. This either means the file changed size, or
+ our data-connection got closed; we just try to
+ open the connection a second time, and then if
+ that fails, assume the size changed. */
+ {
+ if (re_connected)
+ err = EIO; /* Something's fucked */
+ else
+ /* Try opening the connection again. */
+ {
+ close (cc->data_conn);
+ ftp_conn_finish_transfer (cc->conn);
+ ftpfs_release_ftp_conn (nn->fs, cc->conn);
+ cc->conn = 0;
+ }
+ }
+ else
+ {
+ cc->data_conn_pos += rd;
+ if (cc->data_conn_pos > cc->max)
+ cc->max = cc->data_conn_pos;
+ }
+ }
+
+ if (!err && ports_self_interrupted ())
+ err = EINTR;
+ }
+
+ mutex_lock (&cc->lock);
+
+ if (cc->max < max && !err)
+ /* If anyone's waiting for data, let them look (if we're done
+ fetching, this gets delayed until below). */
+ condition_broadcast (&cc->wakeup);
+ }
+
+ if (!err && cc->conn && cc->max == cc->size)
+ /* We're finished reading all data, close the data connection. */
+ {
+ close (cc->data_conn);
+ ftp_conn_finish_transfer (cc->conn);
+ ftpfs_release_ftp_conn (nn->fs, cc->conn);
+ cc->conn = 0;
+ }
+
+ /* We're done, error or no. */
+ cc->fetching_active = 0;
+
+ /* Let others know something's going on. */
+ condition_broadcast (&cc->wakeup);
+ }
+ }
+
+ if (! err)
+ bcopy (cc->image + offs, data, max - offs);
+
+ mutex_unlock (&cc->lock);
+
+ return err;
+}
+
+/* Discard any cached contents in CC. */
+error_t
+ccache_invalidate (struct ccache *cc)
+{
+ error_t err = 0;
+
+ mutex_lock (&cc->lock);
+
+ while (cc->fetching_active && !err)
+ /* Some thread is fetching data, so just let it do its thing, but get
+ a wakeup call when it's done. */
+ {
+ if (hurd_condition_wait (&cc->wakeup, &cc->lock))
+ err = EINTR;
+ }
+
+ if (! err)
+ {
+ if (cc->alloced > 0)
+ {
+ munmap (cc->image, cc->alloced);
+ cc->image = 0;
+ cc->alloced = 0;
+ cc->max = 0;
+ }
+ if (cc->conn)
+ {
+ close (cc->data_conn);
+ ftp_conn_finish_transfer (cc->conn);
+ ftpfs_release_ftp_conn (cc->node->nn->fs, cc->conn);
+ cc->conn = 0;
+ }
+ }
+
+ mutex_unlock (&cc->lock);
+
+ return err;
+}
+
+/* Return a ccache object for NODE in CC. */
+error_t
+ccache_create (struct node *node, struct ccache **cc)
+{
+ struct ccache *new = malloc (sizeof (struct ccache));
+
+ if (! new)
+ return ENOMEM;
+
+ new->node = node;
+ new->image = 0;
+ new->size = node->nn_stat.st_size;
+ new->max = 0;
+ new->alloced = 0;
+ mutex_init (&new->lock);
+ condition_init (&new->wakeup);
+ new->fetching_active = 0;
+ new->conn = 0;
+ new->data_conn = -1;
+
+ *cc = new;
+
+ return 0;
+}
+
+/* Free all resources used by CC. */
+void
+ccache_free (struct ccache *cc)
+{
+ if (cc->alloced > 0)
+ munmap (cc->image, cc->alloced);
+ if (cc->data_conn >= 0)
+ close (cc->data_conn);
+ if (cc->conn)
+ {
+ ftp_conn_finish_transfer (cc->conn);
+ ftpfs_release_ftp_conn (cc->node->nn->fs, cc->conn);
+ }
+ free (cc);
+}
diff --git a/ftpfs/ccache.h b/ftpfs/ccache.h
new file mode 100644
index 00000000..410720c3
--- /dev/null
+++ b/ftpfs/ccache.h
@@ -0,0 +1,73 @@
+/* Remote file contents caching
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef __CCACHE_H__
+#define __CCACHE_H__
+
+#include "ftpfs.h"
+
+struct ccache
+{
+ /* The filesystem node this is a cache of. */
+ struct node *node;
+
+ /* In memory file image, alloced using vm_allocate. */
+ char *image;
+
+ /* Size of data. */
+ off_t size;
+
+ /* Upper bounds of fetched image. */
+ off_t max;
+
+ /* Amount of IMAGE that has been allocated. */
+ size_t alloced;
+
+ struct mutex lock;
+
+ /* People can wait for a reading thread on this condition. */
+ struct condition wakeup;
+
+ /* True if some thread is now fetching data. Only that thread should
+ modify the DATA_CONN, DATA_CONN_POS, and MAX fields. */
+ int fetching_active;
+
+ /* Ftp connection over which data is being fetched, or 0. */
+ struct ftp_conn *conn;
+ /* File descriptor over which data is being fetched. */
+ int data_conn;
+ /* Where DATA_CONN points in the file. */
+ off_t data_conn_pos;
+};
+
+/* Read LEN bytes at OFFS in the file referred to by CC into DATA, or return
+ an error. */
+error_t ccache_read (struct ccache *cc, off_t offs, size_t len, void *data);
+
+/* Discard any cached contents in CC. */
+error_t ccache_invalidate (struct ccache *cc);
+
+/* Return a ccache object for NODE in CC. */
+error_t ccache_create (struct node *node, struct ccache **cc);
+
+/* Free all resources used by CC. */
+void ccache_free (struct ccache *cc);
+
+#endif /* __CCACHE_H__ */
diff --git a/ftpfs/conn.c b/ftpfs/conn.c
new file mode 100644
index 00000000..9be7dd28
--- /dev/null
+++ b/ftpfs/conn.c
@@ -0,0 +1,106 @@
+/* Ftp connection management
+
+ Copyright (C) 1997,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include "ftpfs.h"
+
+/* A particular connection. */
+struct ftpfs_conn
+{
+ struct ftp_conn *conn;
+ struct ftpfs_conn *next;
+};
+
+/* For debugging purposes, give each connection a unique integer id. */
+static unsigned conn_id = 0;
+
+/* Get an ftp connection to use for an operation. */
+error_t
+ftpfs_get_ftp_conn (struct ftpfs *fs, struct ftp_conn **conn)
+{
+ struct ftpfs_conn *fsc;
+
+ spin_lock (&fs->conn_lock);
+ fsc = fs->free_conns;
+ if (fsc)
+ fs->free_conns = fsc->next;
+ spin_unlock (&fs->conn_lock);
+
+ if (! fsc)
+ {
+ error_t err;
+
+ fsc = malloc (sizeof (struct ftpfs_conn));
+ if (! fsc)
+ return ENOMEM;
+
+ err = ftp_conn_create (fs->ftp_params, fs->ftp_hooks, &fsc->conn);
+
+ if (! err)
+ {
+ /* Set connection type to binary. */
+ err = ftp_conn_set_type (fsc->conn, "I");
+ if (err)
+ ftp_conn_free (fsc->conn);
+ }
+
+ if (err)
+ {
+ free (fsc);
+ return err;
+ }
+
+ /* For debugging purposes, give each connection a unique integer id. */
+ fsc->conn->hook = (void *)(uintptr_t)conn_id++;
+ }
+
+ spin_lock (&fs->conn_lock);
+ fsc->next = fs->conns;
+ fs->conns = fsc;
+ spin_unlock (&fs->conn_lock);
+
+ *conn = fsc->conn;
+
+ return 0;
+}
+
+/* Return CONN to the pool of free connections in FS. */
+void
+ftpfs_release_ftp_conn (struct ftpfs *fs, struct ftp_conn *conn)
+{
+ struct ftpfs_conn *fsc, *pfsc;
+
+ spin_lock (&fs->conn_lock);
+ for (pfsc = 0, fsc = fs->conns; fsc; pfsc = fsc, fsc = fsc->next)
+ if (fsc->conn == conn)
+ {
+ if (pfsc)
+ pfsc->next = fsc->next;
+ else
+ fs->conns = fsc->next;
+ fsc->next = fs->free_conns;
+ fs->free_conns = fsc;
+ break;
+ }
+ assert (fsc);
+ spin_unlock (&fs->conn_lock);
+}
diff --git a/ftpfs/dir.c b/ftpfs/dir.c
new file mode 100644
index 00000000..8ef719d8
--- /dev/null
+++ b/ftpfs/dir.c
@@ -0,0 +1,885 @@
+/* Directory operations
+
+ Copyright (C) 1997,98,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <hurd/netfs.h>
+
+#include "ftpfs.h"
+#include "ccache.h"
+
+/* Free the directory entry E and all resources it consumes. */
+void
+free_entry (struct ftpfs_dir_entry *e)
+{
+ assert (! e->self_p); /* We should only free deleted nodes. */
+ free (e->name);
+ if (e->symlink_target)
+ free (e->symlink_target);
+ free (e);
+}
+
+/* Put the directory entry E into the hash table HTABLE, of length HTABLE_LEN. */
+static void
+insert (struct ftpfs_dir_entry *e,
+ struct ftpfs_dir_entry **htable, size_t htable_len)
+{
+ struct ftpfs_dir_entry **t = &htable[e->hv % htable_len];
+ if (*t)
+ (*t)->self_p = &e->next;
+ e->next = *t;
+ e->self_p = t;
+ *t = e;
+}
+
+/* Replace DIR's hashtable with a new one of length NEW_LEN, retaining all
+ existing entries. */
+static error_t
+rehash (struct ftpfs_dir *dir, size_t new_len)
+{
+ int i;
+ size_t old_len = dir->htable_len;
+ struct ftpfs_dir_entry **old_htable = dir->htable;
+ struct ftpfs_dir_entry **new_htable =
+ malloc (new_len * sizeof (struct ftpfs_dir_entry *));
+
+ if (! new_htable)
+ return ENOMEM;
+
+ bzero (new_htable, new_len * sizeof (struct ftpfs_dir_entry *));
+
+ for (i = 0; i < old_len; i++)
+ while (old_htable[i])
+ {
+ struct ftpfs_dir_entry *e = old_htable[i];
+
+ /* Remove E from the old table (don't bother to fixup
+ e->next->self_p). */
+ old_htable[i] = e->next;
+
+ insert (e, new_htable, new_len);
+ }
+
+ free (old_htable);
+
+ dir->htable = new_htable;
+ dir->htable_len = new_len;
+
+ return 0;
+}
+
+/* Calculate NAME's hash value. */
+static size_t
+hash (const char *name)
+{
+ size_t hv = 0;
+ while (*name)
+ hv = ((hv << 5) + *name++) & 0xFFFFFF;
+ return hv;
+}
+
+/* Lookup NAME in DIR and return its entry. If there is no such entry, and
+ ADD is true, then a new entry is allocated and returned, otherwise 0 is
+ returned (if ADD is true then 0 can be returned if a memory allocation
+ error occurs). */
+struct ftpfs_dir_entry *
+lookup (struct ftpfs_dir *dir, const char *name, int add)
+{
+ size_t hv = hash (name);
+ struct ftpfs_dir_entry *h = dir->htable[hv % dir->htable_len], *e = h;
+
+ while (e && strcmp (name, e->name) != 0)
+ e = e->next;
+
+ if (!e && add)
+ {
+ if (dir->num_entries > dir->htable_len)
+ /* Grow the hash table. */
+ if (rehash (dir, (dir->htable_len + 1) * 2 - 1) != 0)
+ return 0;
+
+ e = malloc (sizeof *e);
+ if (e)
+ {
+ e->hv = hv;
+ e->name = strdup (name);
+ e->node = 0;
+ e->dir = dir;
+ e->stat_timestamp = 0;
+ bzero (&e->stat, sizeof e->stat);
+ e->symlink_target = 0;
+ e->noent = 0;
+ e->valid = 0;
+ e->name_timestamp = e->stat_timestamp = 0;
+ e->ordered_next = 0;
+ e->ordered_self_p = 0;
+ e->next = 0;
+ e->self_p = 0;
+ insert (e, dir->htable, dir->htable_len);
+ dir->num_entries++;
+ }
+ }
+
+ return e;
+}
+
+/* Remove E from its position in the ordered_next chain. */
+static void
+ordered_unlink (struct ftpfs_dir_entry *e)
+{
+ if (e->ordered_self_p)
+ *e->ordered_self_p = e->ordered_next;
+ if (e->ordered_next)
+ e->ordered_next->self_p = e->ordered_self_p;
+}
+
+/* Delete E from its directory, freeing any resources it holds. */
+static void
+delete (struct ftpfs_dir_entry *e, struct ftpfs_dir *dir)
+{
+ dir->num_entries--;
+
+ /* Take out of the hash chain. */
+ if (e->self_p)
+ *e->self_p = e->next;
+ if (e->next)
+ e->next->self_p = e->self_p;
+
+ /* This indicates a deleted entry. */
+ e->self_p = 0;
+ e->next = 0;
+
+ /* Take out of the directory ordered list. */
+ ordered_unlink (e);
+
+ /* If there's a node attached, we'll delete the entry whenever it goes
+ away, otherwise, just delete it now. */
+ if (! e->node)
+ free_entry (e);
+}
+
+/* Clear the valid bit in all DIR's htable. */
+static void
+mark (struct ftpfs_dir *dir)
+{
+ size_t len = dir->htable_len, i;
+ struct ftpfs_dir_entry **htable = dir->htable, *e;
+
+ for (i = 0; i < len; i++)
+ for (e = htable[i]; e; e = e->next)
+ e->valid = 0;
+}
+
+/* Delete any entries in DIR which don't have their valid bit set. */
+static void
+sweep (struct ftpfs_dir *dir)
+{
+ size_t len = dir->htable_len, i;
+ struct ftpfs_dir_entry **htable = dir->htable, *e;
+
+ for (i = 0; i < len; i++)
+ for (e = htable[i]; e; e = e->next)
+ if (!e->valid && !e->noent)
+ delete (e, dir);
+}
+
+/* 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 ftpfs_dir_entry *e, const struct stat *st,
+ const char *symlink_target, time_t timestamp)
+{
+ ino_t ino;
+ struct ftpfs *fs = e->dir->fs;
+
+ if (e->stat.st_ino)
+ ino = e->stat.st_ino;
+ else
+ ino = fs->next_inode++;
+
+ e->name_timestamp = timestamp;
+
+ if (st)
+ /* The ST and SYMLINK_TARGET parameters are only valid if ST isn't 0. */
+ {
+ e->stat = *st;
+ e->stat_timestamp = timestamp;
+
+ if (!e->symlink_target || !symlink_target
+ || strcmp (e->symlink_target, symlink_target) != 0)
+ {
+ if (e->symlink_target)
+ free (e->symlink_target);
+ e->symlink_target = symlink_target ? strdup (symlink_target) : 0;
+ }
+ }
+
+ /* The st_ino field is always valid. */
+ e->stat.st_ino = ino;
+ e->stat.st_fsid = fs->fsid;
+ e->stat.st_fstype = FSTYPE_FTP;
+}
+
+/* Add the timestamp TIMESTAMP to the set used to detect bulk stats, and
+ return true if there have been enough individual stats recently to call
+ for just refetching the whole directory. */
+static int
+need_bulk_stat (time_t timestamp, struct ftpfs_dir *dir)
+{
+ time_t period = dir->fs->params.bulk_stat_period;
+ unsigned threshold = dir->fs->params.bulk_stat_threshold;
+
+ if (timestamp > dir->bulk_stat_base_stamp + period * 3)
+ /* No stats done in a while, just start over. */
+ {
+ dir->bulk_stat_count_first_half = 1;
+ dir->bulk_stat_count_second_half = 0;
+ dir->bulk_stat_base_stamp = (timestamp / period) * period;
+ }
+ else if (timestamp > dir->bulk_stat_base_stamp + period * 2)
+ /* Start a new period, but keep the second half of the old one. */
+ {
+ dir->bulk_stat_count_first_half = dir->bulk_stat_count_second_half;
+ dir->bulk_stat_count_second_half = 1;
+ dir->bulk_stat_base_stamp += period;
+ }
+ else if (timestamp > dir->bulk_stat_base_stamp + period)
+ dir->bulk_stat_count_second_half++;
+ else
+ dir->bulk_stat_count_first_half++;
+
+ return
+ (dir->bulk_stat_count_first_half + dir->bulk_stat_count_second_half)
+ > threshold;
+}
+
+static void
+reset_bulk_stat_info (struct ftpfs_dir *dir)
+{
+ dir->bulk_stat_count_first_half = 0;
+ dir->bulk_stat_count_second_half = 0;
+ dir->bulk_stat_base_stamp = 0;
+}
+
+/* State shared between ftpfs_dir_refresh and update_ordered_entry. */
+struct dir_fetch_state
+{
+ struct ftpfs_dir *dir;
+ time_t timestamp;
+
+ /* A pointer to the NEXT-field of the previously seen entry, or a pointer
+ to the ORDERED field in the directory if this is the first. */
+ struct ftpfs_dir_entry **prev_entry_next_p;
+};
+
+/* Update the directory entry for NAME to reflect ST and SYMLINK_TARGET, also
+ rearranging the entries to reflect the order in which they are sent from
+ the server, and setting their valid bits so that obsolete entries can be
+ deleted. HOOK points to the state from ftpfs_dir_fetch. */
+static error_t
+update_ordered_entry (const char *name, const struct stat *st,
+ const char *symlink_target, void *hook)
+{
+ struct dir_fetch_state *dfs = hook;
+ struct ftpfs_dir_entry *e = lookup (dfs->dir, name, 1);
+
+ if (! e)
+ return ENOMEM;
+
+ update_entry (e, st, symlink_target, dfs->timestamp);
+ e->valid = 1;
+
+ if (! e->ordered_self_p)
+ /* Position E 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. */
+ e->ordered_self_p = dfs->prev_entry_next_p;
+
+ if (*e->ordered_self_p)
+ /* Update the self_p pointer of the previous successor. */
+ (*e->ordered_self_p)->ordered_self_p = &e->ordered_next;
+
+ /* E comes before the previous successor. */
+ e->ordered_next = *e->ordered_self_p;
+
+ *e->ordered_self_p = e; /* Put E there. */
+ }
+
+ /* Put the next entry after this one. */
+ dfs->prev_entry_next_p = &e->ordered_next;
+
+ return 0;
+}
+
+/* Update the directory entry for NAME, rearranging the entries to reflect
+ the order in which they are sent from the server, and setting their valid
+ bits so that obsolete entries can be deleted. HOOK points to the state
+ from ftpfs_dir_fetch. */
+static error_t
+update_ordered_name (const char *name, void *hook)
+{
+ /* We just do the same thing as for stats, but without the stat info. */
+ return update_ordered_entry (name, 0, 0, hook);
+}
+
+/* Refresh DIR from the directory DIR_NAME in the filesystem FS. If
+ UPDATE_STATS is true, then directory stat information will also be
+ updated. If PRESERVE_ENTRY is non-0, that entry won't be deleted if it's
+ not in the directory after the refresh, but instead will have its NOENT
+ flag turned on. */
+static error_t
+refresh_dir (struct ftpfs_dir *dir, int update_stats, time_t timestamp,
+ struct ftpfs_dir_entry *preserve_entry)
+{
+ error_t err;
+ struct ftp_conn *conn;
+ struct dir_fetch_state dfs;
+
+ if ((update_stats
+ ? dir->stat_timestamp + dir->fs->params.stat_timeout
+ : dir->name_timestamp + dir->fs->params.name_timeout)
+ >= timestamp)
+ /* We've already refreshed this directory recently. */
+ return 0;
+
+ err = ftpfs_get_ftp_conn (dir->fs, &conn);
+ if (err)
+ return err;
+
+ /* Mark directory entries so we can GC them later using sweep. */
+ mark (dir);
+
+ if (update_stats)
+ /* We're doing a bulk stat now, so don't do another for a while. */
+ reset_bulk_stat_info (dir);
+
+ /* Info passed to update_ordered_entry. */
+ dfs.dir = dir;
+ dfs.timestamp = timestamp;
+ dfs.prev_entry_next_p = &dir->ordered;
+
+ /* Make sure `.' and `..' are always included (if the actual list also
+ includes `.' and `..', the ordered may be rearranged). */
+ err = update_ordered_name (".", &dfs);
+ if (! err)
+ err = update_ordered_name ("..", &dfs);
+
+ /* Refetch the directory from the server. */
+ if (update_stats)
+ /* Fetch both names and stat info. */
+ err = ftp_conn_get_stats (conn, dir->rmt_path, 1,
+ update_ordered_entry, &dfs);
+ else
+ /* Just fetch names. */
+ err = ftp_conn_get_names (conn, dir->rmt_path, update_ordered_name, &dfs);
+
+ if (! err)
+ /* GC any directory entries that weren't seen this time. */
+ {
+ dir->name_timestamp = timestamp;
+ if (update_stats)
+ dir->stat_timestamp = timestamp;
+ if (preserve_entry && !preserve_entry->valid)
+ {
+ preserve_entry->noent = 1;
+ preserve_entry->name_timestamp = timestamp;
+ }
+ sweep (dir);
+ }
+
+ ftpfs_release_ftp_conn (dir->fs, conn);
+
+ return err;
+}
+
+/* Refresh DIR. */
+error_t
+ftpfs_dir_refresh (struct ftpfs_dir *dir)
+{
+ time_t timestamp = NOW;
+ return refresh_dir (dir, 0, timestamp, 0);
+}
+
+/* State shared between ftpfs_dir_entry_refresh and update_old_entry. */
+struct refresh_entry_state
+{
+ struct ftpfs_dir_entry *entry;
+ time_t timestamp;
+};
+
+/* Update the directory entry for NAME to reflect ST and SYMLINK_TARGET.
+ HOOK points to the state from ftpfs_dir_fetch_entry. */
+static error_t
+update_old_entry (const char *name, const struct stat *st,
+ const char *symlink_target, void *hook)
+{
+ struct refresh_entry_state *res = hook;
+
+ if (strcmp (name, res->entry->name) != 0)
+ return EGRATUITOUS;
+
+ update_entry (res->entry, st, symlink_target, res->timestamp);
+
+ return 0;
+}
+
+/* Refresh stat information for NODE. This may actually refresh the whole
+ directory if that is deemed desirable. NODE should be locked. */
+error_t
+ftpfs_refresh_node (struct node *node)
+{
+ struct netnode *nn = node->nn;
+ struct ftpfs_dir_entry *entry = nn->dir_entry;
+
+ if (! entry)
+ /* This is a deleted node, don't attempt to do anything. */
+ return 0;
+ else
+ {
+ error_t err = 0;
+ time_t timestamp = NOW;
+ struct ftpfs_dir *dir = entry->dir;
+
+ mutex_lock (&dir->node->lock);
+
+ if (! entry->self_p)
+ /* This is a deleted entry, just awaiting disposal; do so. */
+ {
+ nn->dir_entry = 0;
+ free_entry (entry);
+ return 0;
+ }
+ else if ((entry->name_timestamp + dir->fs->params.name_timeout
+ >= timestamp)
+ && entry->noent)
+ err = ENOENT;
+ else if (entry->stat_timestamp + dir->fs->params.stat_timeout < timestamp)
+ {
+ /* Stat information needs updating. */
+ if (need_bulk_stat (timestamp, dir))
+ /* Refetch the whole directory from the server. */
+ {
+ err = refresh_dir (entry->dir, 1, timestamp, entry);
+ if (!err && entry->noent)
+ err = ENOENT;
+ }
+ else if (*(entry->name))
+ {
+ /* The root node is treated separately below. */
+ struct ftp_conn *conn;
+
+ err = ftpfs_get_ftp_conn (dir->fs, &conn);
+
+ if (! err)
+ {
+ char *rmt_path;
+
+ err = ftp_conn_append_name (conn, dir->rmt_path, entry->name,
+ &rmt_path);
+ if (! err)
+ {
+ struct refresh_entry_state res;
+
+ res.entry = entry;
+ res.timestamp = timestamp;
+
+ if (! err)
+ err = ftp_conn_get_stats (conn, rmt_path, 0,
+ update_old_entry, &res);
+
+ free (rmt_path);
+ }
+
+ ftpfs_release_ftp_conn (dir->fs, conn);
+ }
+
+ if (err == ENOENT)
+ {
+ entry->noent = 1; /* A negative entry. */
+ entry->name_timestamp = timestamp;
+ }
+ }
+ else
+ {
+ /* Refresh the root node with the old stat
+ information. */
+ struct refresh_entry_state res;
+ res.entry = entry;
+ res.timestamp = timestamp;
+ err = update_old_entry (entry->name,
+ &netfs_root_node->nn_stat,
+ NULL, &res);
+ }
+ }
+
+ if ((entry->stat.st_mtim.tv_sec < node->nn_stat.st_mtim.tv_sec
+ || (entry->stat.st_mtim.tv_sec == node->nn_stat.st_mtim.tv_sec
+ && entry->stat.st_mtim.tv_nsec < node->nn_stat.st_mtim.tv_nsec)
+ || entry->stat.st_size != node->nn_stat.st_size)
+ && nn && nn->contents)
+ /* The file has changed. */
+ ccache_invalidate (nn->contents);
+
+ node->nn_stat = entry->stat;
+ node->nn_translated = S_ISLNK (entry->stat.st_mode) ? S_IFLNK : 0;
+ if (!nn->dir && S_ISDIR (entry->stat.st_mode))
+ ftpfs_dir_create (nn->fs, node, nn->rmt_path, &nn->dir);
+
+ mutex_unlock (&dir->node->lock);
+
+ ftpfs_cache_node (node);
+
+ return err;
+ }
+}
+
+/* Remove NODE from its entry (if the entry is still valid, it will remain
+ without a node). NODE should be locked. */
+error_t
+ftpfs_detach_node (struct node *node)
+{
+ struct netnode *nn = node->nn;
+ struct ftpfs_dir_entry *entry = nn->dir_entry;
+
+ if (entry)
+ /* NODE is still attached to some entry, so detach it. */
+ {
+ struct ftpfs_dir *dir = entry->dir;
+
+ mutex_lock (&dir->node->lock);
+
+ if (entry->self_p)
+ /* Just detach NODE from the still active entry. */
+ entry->node = 0;
+ else
+ /* This is a deleted entry, just awaiting disposal; do so. */
+ {
+ nn->dir_entry = 0;
+ free_entry (entry);
+ }
+
+ if (--dir->num_live_entries == 0)
+ netfs_nput (dir->node);
+ else
+ mutex_unlock (&dir->node->lock);
+ }
+
+ return 0;
+}
+
+/* State shared between ftpfs_dir_lookup and update_new_entry. */
+struct new_entry_state
+{
+ time_t timestamp;
+ struct ftpfs_dir *dir;
+ struct ftpfs_dir_entry *entry;
+};
+
+/* Update the directory entry for NAME to reflect ST and SYMLINK_TARGET.
+ HOOK->entry will be updated to reflect the new entry. */
+static error_t
+update_new_entry (const char *name, const struct stat *st,
+ const char *symlink_target, void *hook)
+{
+ struct ftpfs_dir_entry *e;
+ struct new_entry_state *nes = hook;
+
+ e = lookup (nes->dir, name, 1);
+ if (! e)
+ return ENOMEM;
+
+ update_entry (e, st, symlink_target, nes->timestamp);
+ nes->entry = e;
+
+ return 0;
+}
+
+/* Lookup NAME in DIR, returning its entry, or an error. DIR's node should
+ be locked, and will be unlocked after returning; *NODE will contain the
+ result node, locked, and with an additional reference, or 0 if an error
+ occurs. */
+error_t
+ftpfs_dir_lookup (struct ftpfs_dir *dir, const char *name,
+ struct node **node)
+{
+ struct ftp_conn *conn;
+ struct ftpfs_dir_entry *e;
+ error_t err = 0;
+ char *rmt_path = 0;
+ time_t timestamp = NOW;
+
+ 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;
+ }
+
+ e = lookup (dir, name, 0);
+ if (!e || e->name_timestamp + dir->fs->params.name_timeout < timestamp)
+ /* Try to fetch info about NAME. */
+ {
+ if (need_bulk_stat (timestamp, dir))
+ /* Refetch the whole directory from the server. */
+ {
+ err = refresh_dir (dir, 1, timestamp, e);
+ if (!err && !e)
+ e = lookup (dir, name, 0);
+ }
+ else
+ {
+ err = ftpfs_get_ftp_conn (dir->fs, &conn);
+ if (! err)
+ {
+ err = ftp_conn_append_name (conn, dir->rmt_path, name,
+ &rmt_path);
+ if (! err)
+ {
+ struct new_entry_state nes;
+
+ nes.dir = dir;
+ nes.timestamp = timestamp;
+ nes.entry = NULL;
+
+ err = ftp_conn_get_stats (conn, rmt_path, 0,
+ update_new_entry, &nes);
+ if (! err)
+ e = nes.entry;
+ else if (err == ENOENT)
+ {
+ e = lookup (dir, name, 1);
+ if (! e)
+ err = ENOMEM;
+ else
+ {
+ e->noent = 1; /* A negative entry. */
+ e->name_timestamp = timestamp;
+ }
+ }
+ }
+
+ ftpfs_release_ftp_conn (dir->fs, conn);
+ }
+ }
+ }
+
+ if (! err)
+ {
+ if (e && !e->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 (e->node)
+ e->node->references++;
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ if (! e->node)
+ /* No node; make one and install it into E. */
+ {
+ if (! rmt_path)
+ /* We have to cons up the absolute path. We need the
+ connection just for the pathname frobbing functions. */
+ {
+ err = ftpfs_get_ftp_conn (dir->fs, &conn);
+ if (! err)
+ {
+ err = ftp_conn_append_name (conn, dir->rmt_path, name,
+ &rmt_path);
+ ftpfs_release_ftp_conn (dir->fs, conn);
+ }
+ }
+
+ if (! err)
+ {
+ err = ftpfs_create_node (e, rmt_path, &e->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 = e->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 (&e->node->lock);
+ }
+ }
+ else
+ err = ENOENT;
+ }
+
+ if (err)
+ {
+ *node = 0;
+ mutex_unlock (&dir->node->lock);
+ }
+
+ if (rmt_path)
+ free (rmt_path);
+
+ return err;
+}
+
+/* Lookup the null name in DIR, and return a node for it in NODE. Unlike
+ ftpfs_dir_lookup, this won't attempt to validate the existence 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
+ftpfs_dir_null_lookup (struct ftpfs_dir *dir, struct node **node)
+{
+ struct ftpfs_dir_entry *e;
+ error_t err = 0;
+
+ e = lookup (dir, "", 1);
+ if (! e)
+ return ENOMEM;
+
+ if (! e->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 (e->node)
+ e->node->references++;
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ if (! e->node)
+ /* No node; make one and install it into E. */
+ {
+ err = ftpfs_create_node (e, dir->rmt_path, &e->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 = e->node;
+ }
+ else
+ err = ENOENT;
+
+ return err;
+}
+
+/* Size of initial htable for a new directory. */
+#define INIT_HTABLE_LEN 5
+
+/* Return in DIR a new ftpfs directory, in the filesystem FS, with node NODE
+ and remote path RMT_PATH. RMT_PATH is *not copied*, so it shouldn't ever
+ change while this directory is active. */
+error_t
+ftpfs_dir_create (struct ftpfs *fs, struct node *node, const char *rmt_path,
+ struct ftpfs_dir **dir)
+{
+ struct ftpfs_dir *new = malloc (sizeof (struct ftpfs_dir));
+ struct ftpfs_dir_entry **htable
+ = calloc (INIT_HTABLE_LEN, sizeof (struct ftpfs_dir_entry *));
+
+ if (!new || !htable)
+ {
+ if (new)
+ free (new);
+ if (htable)
+ free (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 = 0;
+ new->rmt_path = rmt_path;
+ new->fs = fs;
+ new->node = node;
+ new->stat_timestamp = 0;
+ new->name_timestamp = 0;
+ new->bulk_stat_base_stamp = 0;
+ new->bulk_stat_count_first_half = 0;
+ new->bulk_stat_count_second_half = 0;
+
+ *dir = new;
+
+ return 0;
+}
+
+void
+ftpfs_dir_free (struct ftpfs_dir *dir)
+{
+ /* Free all entries. */
+ mark (dir);
+ sweep (dir);
+
+ if (dir->htable)
+ free (dir->htable);
+
+ netfs_nrele (dir->node);
+
+ free (dir);
+}
diff --git a/ftpfs/fs.c b/ftpfs/fs.c
new file mode 100644
index 00000000..e4db3031
--- /dev/null
+++ b/ftpfs/fs.c
@@ -0,0 +1,86 @@
+/* Fs operations
+
+ Copyright (C) 1997, 2001, 2003 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stddef.h>
+#include <string.h>
+
+#include <hurd/ihash.h>
+#include <hurd/netfs.h>
+
+#include "ftpfs.h"
+
+/* Create a new ftp filesystem with the given parameters. */
+error_t
+ftpfs_create (char *rmt_path, int fsid,
+ struct ftp_conn_params *ftp_params,
+ struct ftp_conn_hooks *ftp_hooks,
+ struct ftpfs_params *params,
+ struct ftpfs **fs)
+{
+ error_t err;
+ /* Since nodes keep some of their state in the enclosing directory, we need
+ one for the root node. */
+ struct ftpfs_dir *super_root_dir;
+ /* And also a super-root node, just used for locking SUPER_ROOT_DIR. */
+ struct node *super_root;
+ /* The new node. */
+ struct ftpfs *new = malloc (sizeof (struct ftpfs));
+
+ if (! new)
+ return ENOMEM;
+
+ new->free_conns = 0;
+ new->conns = 0;
+ spin_lock_init (&new->conn_lock);
+ new->node_cache_mru = new->node_cache_lru = 0;
+ new->node_cache_len = 0;
+ mutex_init (&new->node_cache_lock);
+
+ new->fsid = fsid;
+ new->next_inode = 2;
+
+ new->params = *params;
+ new->ftp_params = ftp_params;
+ new->ftp_hooks = ftp_hooks;
+
+ hurd_ihash_init (&new->inode_mappings,
+ offsetof (struct ftpfs_dir_entry, inode_locp));
+ spin_lock_init (&new->inode_mappings_lock);
+
+ super_root = netfs_make_node (0);
+ if (! super_root)
+ err = ENOMEM;
+ else
+ {
+ err = ftpfs_dir_create (new, super_root, rmt_path, &super_root_dir);
+ if (! err)
+ err = ftpfs_dir_null_lookup (super_root_dir, &new->root);
+ }
+
+ if (err)
+ {
+ hurd_ihash_destroy (&new->inode_mappings);
+ free (new);
+ }
+ else
+ *fs = new;
+
+ return err;
+}
diff --git a/ftpfs/ftpfs.c b/ftpfs/ftpfs.c
new file mode 100644
index 00000000..393cc5ba
--- /dev/null
+++ b/ftpfs/ftpfs.c
@@ -0,0 +1,430 @@
+/* Ftp filesystem
+
+ Copyright (C) 1997,98,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <unistd.h>
+#include <argp.h>
+#include <error.h>
+#include <argz.h>
+#include <netdb.h>
+#include <sys/stat.h>
+
+#include <version.h>
+
+#include <hurd/netfs.h>
+
+#include "ftpfs.h"
+
+char *netfs_server_name = "ftpfs";
+char *netfs_server_version = HURD_VERSION;
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ftpfs);
+
+static char *args_doc = "REMOTE_FS [SERVER]";
+static char *doc = "Hurd ftp filesystem translator."
+"\vIf SERVER is not specified, an attempt is made to extract"
+" it from REMOTE_FS, using `SERVER:FS' notation."
+" SERVER can be a hostname, in which case anonymous ftp is used,"
+" or may include a user and password like `USER:PASSWORD@HOST' (the"
+" `:PASSWORD' part is optional).";
+
+/* The filesystem. */
+struct ftpfs *ftpfs;
+
+/* Parameters describing the server we're connecting to. */
+struct ftp_conn_params *ftpfs_ftp_params = 0;
+
+/* customization hooks. */
+struct ftp_conn_hooks ftpfs_ftp_hooks = { interrupt_check: ports_self_interrupted };
+
+/* The (user-specified) name of the SERVER:FILESYSTEM we're connected too. */
+char *ftpfs_remote_fs;
+
+/* The FILESYSTEM component of FTPFS_REMOTE_FS. */
+char *ftpfs_remote_root;
+
+/* Random parameters for the filesystem. */
+struct ftpfs_params ftpfs_params;
+
+volatile struct mapped_time_value *ftpfs_maptime;
+
+int netfs_maxsymlinks = 12;
+
+extern error_t lookup_server (const char *server,
+ struct ftp_conn_params **params, int *h_err);
+
+static FILE *debug_stream = 0;
+static char *debug_stream_name = 0;
+static struct mutex debug_lock = MUTEX_INITIALIZER;
+
+/* Prints ftp connection log to DEBUG_STREAM. */
+static void
+cntl_debug (struct ftp_conn *conn, int type, const char *txt)
+{
+ char *type_str;
+
+ switch (type)
+ {
+ case FTP_CONN_CNTL_DEBUG_CMD: type_str = ">"; break;
+ case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
+ default: type_str = "?"; break;
+ }
+
+ mutex_lock (&debug_lock);
+ if (debug_stream)
+ {
+ fprintf (debug_stream, "%u.%s%s\n",
+ (unsigned)(uintptr_t)conn->hook, type_str, txt);
+ fflush (debug_stream);
+ }
+ mutex_unlock (&debug_lock);
+}
+
+/* Various default parameters. */
+#define DEFAULT_NAME_TIMEOUT 300
+#define DEFAULT_STAT_TIMEOUT 120
+
+#define DEFAULT_BULK_STAT_PERIOD 10
+#define DEFAULT_BULK_STAT_THRESHOLD 5
+
+#define DEFAULT_NODE_CACHE_MAX 50
+
+/* Return a string corresponding to the printed rep of DEFAULT_what */
+#define ___D(what) #what
+#define __D(what) ___D(what)
+#define _D(what) __D(DEFAULT_ ## what)
+
+/* Common (runtime & startup) options. */
+
+#define OPT_NO_DEBUG 1
+
+#define OPT_NAME_TIMEOUT 5
+#define OPT_STAT_TIMEOUT 7
+#define OPT_NODE_CACHE_MAX 8
+#define OPT_BULK_STAT_PERIOD 9
+#define OPT_BULK_STAT_THRESHOLD 10
+
+/* Options usable both at startup and at runtime. */
+static const struct argp_option common_options[] =
+{
+ {"debug", 'D', "FILE", OPTION_ARG_OPTIONAL, "Print debug output to FILE"},
+ {"no-debug", OPT_NO_DEBUG, 0, OPTION_HIDDEN },
+
+ {0,0,0,0, "Parameters:"},
+ {"name-timeout", OPT_NAME_TIMEOUT, "SECS", 0,
+ "Time directory names are cached (default " _D(NAME_TIMEOUT) ")"},
+ {"stat-timeout", OPT_STAT_TIMEOUT, "SECS", 0,
+ "Time stat information is cached (default " _D(STAT_TIMEOUT) ")"},
+ {"node-cache-size", OPT_NODE_CACHE_MAX, "ENTRIES", 0,
+ "Number of recently used filesystem nodes that are cached (default "
+ _D(NODE_CACHE_MAX) ")"},
+
+ {"bulk-stat-period", OPT_BULK_STAT_PERIOD, "SECS", 0,
+ "Period for detecting bulk stats (default " _D(BULK_STAT_PERIOD) ")"},
+ {"bulk-stat-threshold", OPT_BULK_STAT_THRESHOLD, "SECS", 0,
+ "Number of stats within the bulk-stat-period that trigger a bulk stat"
+ " (default " _D(BULK_STAT_THRESHOLD) ")"},
+
+ {0, 0}
+};
+
+static error_t
+parse_common_opt (int key, char *arg, struct argp_state *state)
+{
+ error_t err = 0;
+ struct ftpfs_params *params = state->input;
+
+ switch (key)
+ {
+ case 'D':
+ mutex_lock (&debug_lock);
+
+ if (debug_stream && debug_stream != stderr)
+ fclose (debug_stream);
+ if (debug_stream_name)
+ {
+ free (debug_stream_name);
+ debug_stream_name = 0;
+ }
+
+ if (arg)
+ {
+ debug_stream_name = strdup (arg);
+ if (! debug_stream_name)
+ {
+ argp_failure (state, 0, ENOMEM, "%s: Cannot open debugging file", arg);
+ err = ENOMEM;
+ }
+
+ if (! err)
+ {
+ debug_stream = fopen (arg, "w+");
+ if (! debug_stream)
+ {
+ err = errno;
+ argp_failure (state, 0, err, "%s: Cannot open debugging file", arg);
+ }
+ }
+ }
+ else
+ debug_stream = stderr;
+
+ if (! err)
+ ftpfs_ftp_hooks.cntl_debug = cntl_debug;
+
+ mutex_unlock (&debug_lock);
+
+ return err;
+
+ case OPT_NO_DEBUG:
+ mutex_lock (&debug_lock);
+ if (debug_stream && debug_stream != stderr)
+ fclose (debug_stream);
+ ftpfs_ftp_hooks.cntl_debug = 0;
+ mutex_unlock (&debug_lock);
+ break;
+
+ case OPT_NODE_CACHE_MAX:
+ params->node_cache_max = atoi (arg); break;
+ case OPT_NAME_TIMEOUT:
+ params->name_timeout = atoi (arg); break;
+ case OPT_STAT_TIMEOUT:
+ params->stat_timeout = atoi (arg); break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static struct argp common_argp = { common_options, parse_common_opt };
+
+/* Startup options. */
+
+static const struct argp_option startup_options[] =
+{
+ { 0 }
+};
+
+/* Parse a single command line option/argument. */
+static error_t
+parse_startup_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ if (state->arg_num > 1)
+ argp_usage (state);
+ else if (state->arg_num == 0)
+ ftpfs_remote_fs = arg;
+ else
+ /* If the fs & server are two separate args, glom them together into the
+ ":" notation. */
+ {
+ char *rfs = malloc (strlen (ftpfs_remote_fs) + 1 + strlen (arg) + 1);
+ if (! rfs)
+ argp_failure (state, 99, ENOMEM, "%s", arg);
+ stpcpy (stpcpy (stpcpy (rfs, arg), ":"), ftpfs_remote_fs);
+ ftpfs_remote_fs = rfs;
+ }
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ /* Validate the remote fs arg; at this point FTPFS_REMOTE_FS is in
+ SERVER:FS notation. */
+ if (state->arg_num == 0)
+ argp_error (state, "No remote filesystem specified");
+ else
+ {
+ int h_err; /* Host lookup error. */
+ error_t err;
+ char *sep = strrchr (ftpfs_remote_fs, '@');
+
+ if (sep)
+ /* FTPFS_REMOTE_FS includes a '@', which means that it's in
+ USER[:PASS]@HOST:FS notation, so we have to be careful not to
+ choose the wrong `:' as the SERVER-FS separator. */
+ sep = strchr (sep, ':');
+ else
+ sep = strchr (ftpfs_remote_fs, ':');
+
+ if (! sep)
+ /* We have just a host name, so treat it as "HOST:/". */
+ ftpfs_remote_root = "/";
+ else
+ ftpfs_remote_root = sep + 1;
+
+ /* Lookup the ftp server (the part before the `:'). */
+ if (sep)
+ *sep = '\0';
+ err = lookup_server (ftpfs_remote_fs, &ftpfs_ftp_params, &h_err);
+ if (err == EINVAL)
+ argp_failure (state, 10, 0, "%s: %s",
+ ftpfs_remote_fs, hstrerror (h_err));
+ else if (err)
+ argp_failure (state, 11, err, "%s", ftpfs_remote_fs);
+ if (sep)
+ *sep = ':';
+ }
+
+ case ARGP_KEY_INIT:
+ /* Setup up state for our first child parser (common options). */
+ state->child_inputs[0] = &ftpfs_params;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/* Runtime options. */
+
+/* Parse a single command line option/argument. */
+static error_t
+parse_runtime_opt (int key, char *arg, struct argp_state *state)
+{
+ if (key == ARGP_KEY_INIT)
+ /* Setup up state for our first child parser (common options). */
+ {
+ state->child_inputs[0] = &ftpfs->params;
+ return 0;
+ }
+ else
+ return ARGP_ERR_UNKNOWN;
+}
+
+static const struct argp_child runtime_argp_children[] =
+ { {&common_argp}, {&netfs_std_runtime_argp}, {0} };
+static struct argp runtime_argp =
+ { 0, parse_runtime_opt, 0, 0, runtime_argp_children };
+
+/* Use by netfs_set_options to handle runtime option parsing. */
+struct argp *netfs_runtime_argp = &runtime_argp;
+
+/* Return an argz string describing the current options. Fill *ARGZ
+ with a pointer to newly malloced storage holding the list and *LEN
+ to the length of that storage. */
+error_t
+netfs_append_args (char **argz, size_t *argz_len)
+{
+ char buf[80];
+ error_t err = 0;
+
+#define FOPT(fmt, arg) \
+ do { \
+ if (! err) \
+ { \
+ snprintf (buf, sizeof buf, fmt, arg); \
+ err = argz_add (argz, argz_len, buf); \
+ } \
+ } while (0)
+
+ mutex_lock (&debug_lock);
+ if (ftpfs_ftp_hooks.cntl_debug && debug_stream)
+ {
+ if (debug_stream != stderr)
+ {
+ char *rep;
+ asprintf (&rep, "--debug=%s", debug_stream_name);
+ err = argz_add (argz, argz_len, rep);
+ free (rep);
+ }
+ else
+ err = argz_add (argz, argz_len, "--debug");
+ }
+ mutex_unlock (&debug_lock);
+
+ if (ftpfs->params.name_timeout != DEFAULT_NAME_TIMEOUT)
+ FOPT ("--name-timeout=%ld", ftpfs->params.name_timeout);
+ if (ftpfs->params.stat_timeout != DEFAULT_STAT_TIMEOUT)
+ FOPT ("--stat-timeout=%ld", ftpfs->params.stat_timeout);
+ if (ftpfs->params.node_cache_max != DEFAULT_NODE_CACHE_MAX)
+ FOPT ("--node-cache-size=%Zu", ftpfs->params.node_cache_max);
+ if (ftpfs->params.bulk_stat_period != DEFAULT_BULK_STAT_PERIOD)
+ FOPT ("--bulk-stat-period=%ld", ftpfs->params.bulk_stat_period);
+ if (ftpfs->params.bulk_stat_threshold != DEFAULT_BULK_STAT_THRESHOLD)
+ FOPT ("--bulk-stat-threshold=%d", ftpfs->params.bulk_stat_threshold);
+
+ return argz_add (argz, argz_len, ftpfs_remote_fs);
+}
+
+/* Program entry point. */
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap, underlying_node;
+ struct stat underlying_stat;
+ const struct argp_child argp_children[] =
+ { {&common_argp}, {&netfs_std_startup_argp}, {0} };
+ struct argp argp =
+ { startup_options, parse_startup_opt, args_doc, doc, argp_children };
+
+ ftpfs_params.name_timeout = DEFAULT_NAME_TIMEOUT;
+ ftpfs_params.stat_timeout = DEFAULT_STAT_TIMEOUT;
+ ftpfs_params.node_cache_max = DEFAULT_NODE_CACHE_MAX;
+ ftpfs_params.bulk_stat_period = DEFAULT_BULK_STAT_PERIOD;
+ ftpfs_params.bulk_stat_threshold = DEFAULT_BULK_STAT_THRESHOLD;
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+
+ netfs_init ();
+
+ err = maptime_map (0, 0, &ftpfs_maptime);
+ if (err)
+ error (3, err, "mapping time");
+
+ err = ftpfs_create (ftpfs_remote_root, getpid (),
+ ftpfs_ftp_params, &ftpfs_ftp_hooks,
+ &ftpfs_params, &ftpfs);
+ if (err)
+ error (4, err, "%s", ftpfs_remote_fs);
+
+ netfs_root_node = ftpfs->root;
+
+ underlying_node = netfs_startup (bootstrap, 0);
+ err = io_stat (underlying_node, &underlying_stat);
+ if (err)
+ 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);
+
+ /* If the underlying node isn't a directory, propagate read permission to
+ execute permission since we need that for lookups. */
+ if (! S_ISDIR (underlying_stat.st_mode))
+ {
+ if (underlying_stat.st_mode & S_IRUSR)
+ netfs_root_node->nn_stat.st_mode |= S_IXUSR;
+ if (underlying_stat.st_mode & S_IRGRP)
+ netfs_root_node->nn_stat.st_mode |= S_IXGRP;
+ if (underlying_stat.st_mode & S_IROTH)
+ netfs_root_node->nn_stat.st_mode |= S_IXOTH;
+ }
+
+ for (;;)
+ netfs_server_loop ();
+}
diff --git a/ftpfs/ftpfs.h b/ftpfs/ftpfs.h
new file mode 100644
index 00000000..0eef5bde
--- /dev/null
+++ b/ftpfs/ftpfs.h
@@ -0,0 +1,250 @@
+/* Ftp filesystem
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef __FTPFS_H__
+#define __FTPFS_H__
+
+#include <stdlib.h>
+#include <cthreads.h>
+#include <ftpconn.h>
+#include <maptime.h>
+#include <hurd/ihash.h>
+
+/* Anonymous types. */
+struct ccache;
+struct ftpfs_conn;
+
+/* A single entry in a directory. */
+struct ftpfs_dir_entry
+{
+ char *name; /* Name of this entry */
+ size_t hv; /* Hash value of NAME (before mod'ing) */
+
+ /* 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 ftpfs_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 ftpfs_dir_entry *next, **self_p;
+
+ /* Next entry in `directory order', or 0 if none known. */
+ struct ftpfs_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 ftpfs_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 ftpfs_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 ftpfs_dir_entry *ordered;
+
+ /* The filesystem node that this is the directory for. */
+ struct node *node;
+
+ /* The filesystem this directory is in. */
+ struct ftpfs *fs;
+
+ /* The path to this directory on the server. */
+ const char *rmt_path;
+
+ time_t stat_timestamp;
+ time_t name_timestamp;
+
+ /* Stuff for detecting bulk stats. */
+
+ /* The timestamp of the first sample in bulk_stat_count1, rounded to
+ BULK_STAT_PERIOD seconds. */
+ time_t bulk_stat_base_stamp;
+
+ /* The number of stats done in the period [bulk_stat_base_stamp,
+ bulk_stat_base_stamp+BULK_STAT_PERIOD). */
+ unsigned bulk_stat_count_first_half;
+ /* The number of stats done in the period
+ [bulk_stat_base_stamp+BULK_STAT_PERIOD,
+ bulk_stat_base_stamp+BULK_STAT_PERIOD*2). */
+ unsigned bulk_stat_count_second_half;
+};
+
+/* libnetfs node structure. */
+struct netnode
+{
+ /* The remote filesystem. */
+ struct ftpfs *fs;
+
+ /* The directory entry for this node. */
+ struct ftpfs_dir_entry *dir_entry;
+
+ /* The path in FS that this file corresponds to. */
+ const char *rmt_path;
+
+ /* If this is a regular file, an optional cache of the contents. This may
+ be 0, if no cache has yet been created, but once created, it only goes
+ away when the node is destroyed. */
+ struct ccache *contents;
+
+ /* If this is a directory, the contents, or 0 if not fetched. */
+ struct ftpfs_dir *dir;
+
+ /* Position in the node cache. */
+ struct node *ncache_next, *ncache_prev;
+};
+
+/* Various parameters that can be used to change the behavior of an ftpfs. */
+struct ftpfs_params
+{
+ /* Amount of time name existence is cached. */
+ time_t name_timeout;
+
+ /* Amount of time stat information is cached. */
+ time_t stat_timeout;
+
+ /* Parameters for detecting bulk stats; if more than BULK_STAT_THRESHOLD
+ stats are done within BULK_STAT_PERIOD seconds, the whole enclosing
+ directory is fetched. */
+ time_t bulk_stat_period;
+ unsigned bulk_stat_threshold;
+
+ /* The size of the node cache. */
+ size_t node_cache_max;
+};
+
+/* A particular filesystem. */
+struct ftpfs
+{
+ /* Root of filesystem. */
+ struct node *root;
+
+ /* A pool of ftp connections for server threads to use. */
+ struct ftpfs_conn *free_conns;
+ struct ftpfs_conn *conns;
+ spin_lock_t conn_lock;
+
+ /* Parameters for making new ftp connections. */
+ struct ftp_conn_params *ftp_params;
+ struct ftp_conn_hooks *ftp_hooks;
+
+ /* 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;
+
+ struct ftpfs_params params;
+
+ /* A cache that holds a reference to recently used nodes. */
+ struct node *node_cache_mru, *node_cache_lru;
+ size_t node_cache_len; /* Number of entries in it. */
+ struct mutex node_cache_lock;
+};
+
+extern volatile struct mapped_time_value *ftpfs_maptime;
+
+/* The current time. */
+#define NOW \
+ ({ struct timeval tv; maptime_read (ftpfs_maptime, &tv); tv.tv_sec; })
+
+/* Create a new ftp filesystem with the given parameters. */
+error_t ftpfs_create (char *rmt_root, int fsid,
+ struct ftp_conn_params *ftp_params,
+ struct ftp_conn_hooks *ftp_hooks,
+ struct ftpfs_params *params,
+ struct ftpfs **fs);
+
+/* Refresh stat information for NODE. This may actually refresh the whole
+ directory if that is deemed desirable. */
+error_t ftpfs_refresh_node (struct node *node);
+
+/* Remove NODE from its entry (if the entry is still valid, it will remain
+ without a node). NODE should be locked. */
+error_t ftpfs_detach_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. E may be 0, if this is the root node. */
+error_t ftpfs_create_node (struct ftpfs_dir_entry *e, const char *rmt_path,
+ struct node **node);
+
+/* Add NODE to the recently-used-node cache, which adds a reference to
+ prevent it from going away. NODE should be locked. */
+void ftpfs_cache_node (struct node *node);
+
+/* Get an ftp connection to use for an operation. */
+error_t ftpfs_get_ftp_conn (struct ftpfs *fs, struct ftp_conn **conn);
+
+/* Return CONN to the pool of free connections in FS. */
+void ftpfs_release_ftp_conn (struct ftpfs *fs, struct ftp_conn *conn);
+
+/* Return in DIR a new ftpfs directory, in the filesystem FS, with node NODE
+ and remote path RMT_PATH. RMT_PATH is *not copied*, so it shouldn't ever
+ change while this directory is active. */
+error_t ftpfs_dir_create (struct ftpfs *fs, struct node *node,
+ const char *rmt_path, struct ftpfs_dir **dir);
+
+void ftpfs_dir_free (struct ftpfs_dir *dir);
+
+/* Refresh DIR. */
+error_t ftpfs_dir_refresh (struct ftpfs_dir *dir);
+
+/* Lookup NAME in DIR, returning its entry, or an error. DIR's node should
+ be locked, and will be unlocked after returning; *NODE will contain the
+ result node, locked, and with an additional reference, or 0 if an error
+ occurs. */
+error_t ftpfs_dir_lookup (struct ftpfs_dir *dir, const char *name,
+ struct node **node);
+
+/* Lookup the null name in DIR, and return a node for it in NODE. Unlike
+ ftpfs_dir_lookup, this won't attempt to validate the existence 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 ftpfs_dir_null_lookup (struct ftpfs_dir *dir, struct node **node);
+
+#endif /* __FTPFS_H__ */
diff --git a/ftpfs/host.c b/ftpfs/host.c
new file mode 100644
index 00000000..cd6fd4c0
--- /dev/null
+++ b/ftpfs/host.c
@@ -0,0 +1,154 @@
+/* Server lookup
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <ftpconn.h>
+
+/* Split the server-specification string SERVER into its components: a
+ hostname (returned in HOST), username (USER), and password (PASSWD). */
+static error_t
+split_server_name (const char *server, char **host, char **user, char **passwd)
+{
+ size_t plim;
+ const char *p = server, *sep;
+
+ *host = 0;
+ *user = 0;
+ *passwd = 0;
+
+ /* Extract the hostname; syntax is either `HOST:...', `...@HOST', or just
+ HOST if there are no user parameters specified. */
+ sep = strrchr (p, '@');
+ if (sep)
+ /* ...@HOST */
+ {
+ *host = strdup (sep + 1);
+ if (! *host)
+ return ENOMEM;
+ plim = sep - server;
+ }
+ else
+ {
+ sep = strchr (server, ':');
+ if (sep)
+ /* HOST:... */
+ {
+ *host = strndup (server, sep - server);
+ if (! *host)
+ return ENOMEM;
+ p = sep + 1;
+ plim = strlen (p);
+ }
+ else
+ /* Just HOST */
+ {
+ *host = strdup (server);
+ if (! *host)
+ return ENOMEM;
+ return 0;
+ }
+ }
+
+ /* Now P...P+PLIM contains any user parameters for HOST. */
+ sep = memchr (p, ':', plim);
+ if (sep)
+ /* USERNAME:PASSWD */
+ {
+ *user = strndup (p, sep - p);
+ *passwd = strndup (sep + 1, plim - (sep + 1 - p));
+ if (!*user || !*passwd)
+ {
+ if (*user)
+ free (*user);
+ if (*passwd)
+ free (*passwd);
+ free (*host);
+ return ENOMEM;
+ }
+ }
+ else
+ /* Just USERNAME */
+ {
+ *user = strndup (p, plim);
+ if (! *user)
+ free (*user);
+ }
+
+ return 0;
+}
+
+/* */
+error_t
+lookup_server (const char *server, struct ftp_conn_params **params, int *h_err)
+{
+ char hostent_data[2048]; /* XXX what size should this be???? */
+ struct hostent _he, *he;
+ char *host, *user, *passwd;
+ error_t err = split_server_name (server, &host, &user, &passwd);
+
+ if (err)
+ return err;
+
+ /* We didn't find a pre-existing host entry. Make a new one. Note that
+ since we don't lock anything while making up our new structure, another
+ thread could have inserted a duplicate entry for the same host name, but
+ this isn't really a problem, just annoying. */
+
+ if (gethostbyname_r (host, &_he, hostent_data, sizeof hostent_data,
+ &he, h_err) == 0)
+ {
+ *params = malloc (sizeof (struct ftp_conn_params));
+ if (! *params)
+ err = ENOMEM;
+ else
+ {
+ (*params)->addr = malloc (he->h_length);
+ if (! (*params)->addr)
+ {
+ free (*params);
+ err = ENOMEM;
+ }
+ else
+ {
+ bcopy (he->h_addr_list[0], (*params)->addr, he->h_length);
+ (*params)->addr_len = he->h_length;
+ (*params)->addr_type = he->h_addrtype;
+ (*params)->user = user;
+ (*params)->pass = passwd;
+ (*params)->acct = 0;
+ }
+ }
+ }
+ else
+ err = EINVAL;
+
+ free (host);
+
+ if (err)
+ {
+ free (user);
+ free (passwd);
+ }
+
+ return err;
+}
diff --git a/ftpfs/ncache.c b/ftpfs/ncache.c
new file mode 100644
index 00000000..27b868a7
--- /dev/null
+++ b/ftpfs/ncache.c
@@ -0,0 +1,87 @@
+/* Node caching
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <hurd/netfs.h>
+
+#include "ftpfs.h"
+
+/* Remove NN's node from its position in FS's node cache. */
+static void
+node_unlink (struct node *node, struct ftpfs *fs)
+{
+ struct netnode *nn = node->nn;
+ if (nn->ncache_next)
+ nn->ncache_next->nn->ncache_prev = nn->ncache_prev;
+ if (nn->ncache_prev)
+ nn->ncache_prev->nn->ncache_next = nn->ncache_next;
+ if (fs->node_cache_mru == node)
+ fs->node_cache_mru = nn->ncache_next;
+ if (fs->node_cache_lru == node)
+ fs->node_cache_lru = nn->ncache_prev;
+ nn->ncache_next = 0;
+ nn->ncache_prev = 0;
+ fs->node_cache_len--;
+}
+
+/* Add NODE to the recently-used-node cache, which adds a reference to
+ prevent it from going away. NODE should be locked. */
+void
+ftpfs_cache_node (struct node *node)
+{
+ struct netnode *nn = node->nn;
+ struct ftpfs *fs = nn->fs;
+
+ mutex_lock (&fs->node_cache_lock);
+
+ if (fs->params.node_cache_max > 0 || fs->node_cache_len > 0)
+ {
+ if (fs->node_cache_mru != node)
+ {
+ if (nn->ncache_next || nn->ncache_prev)
+ /* Node is already in the cache. */
+ node_unlink (node, fs);
+ else
+ /* Add a reference from the cache. */
+ netfs_nref (node);
+
+ nn->ncache_next = fs->node_cache_mru;
+ nn->ncache_prev = 0;
+ if (fs->node_cache_mru)
+ fs->node_cache_mru->nn->ncache_prev = node;
+ if (! fs->node_cache_lru)
+ fs->node_cache_lru = node;
+ fs->node_cache_mru = node;
+ fs->node_cache_len++;
+ }
+
+ /* Forget the least used nodes. */
+ while (fs->node_cache_len > fs->params.node_cache_max)
+ {
+ struct node *lru = fs->node_cache_lru;
+ node_unlink (lru, fs);
+ netfs_nrele (lru);
+ }
+ }
+
+ mutex_unlock (&fs->node_cache_lock);
+}
diff --git a/ftpfs/netfs.c b/ftpfs/netfs.c
new file mode 100644
index 00000000..8922f3ab
--- /dev/null
+++ b/ftpfs/netfs.c
@@ -0,0 +1,463 @@
+/* ftpfs interface to libnetfs
+
+ Copyright (C) 1997, 1998, 1999, 2001, 2007 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with 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 <dirent.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include <hurd/netfs.h>
+
+#include "ftpfs.h"
+#include "ccache.h"
+
+/* 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 = 0;
+ mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+/* 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 = ftpfs_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 = ftpfs_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, ftpfs_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 = ftpfs_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;
+}
+
+/* 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 ftpfs_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;
+}
+
+/* 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, as for netfs_get_dirents. */
+static error_t
+get_dirents (struct ftpfs_dir *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)
+{
+ struct ftpfs_dir_entry *e;
+ error_t err = 0;
+
+ if (! dir)
+ return ENOTDIR;
+
+ e = dir->ordered;
+
+ /* Find the first entry. */
+ while (first_entry-- > 0)
+ if (! e)
+ {
+ max_entries = 0;
+ break;
+ }
+ else
+ e = e->ordered_next;
+
+ if (max_entries != 0)
+ {
+ size_t size =
+ (max_data_len == 0 || max_data_len > DIRENTS_CHUNK_SIZE
+ ? DIRENTS_CHUNK_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)
+ {
+ char *p = *data;
+ int count = 0;
+
+ /* See how much space we need for the result. */
+ while ((max_entries == -1 || count < max_entries) && e)
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (e->name);
+ size_t sz = DIRENT_LEN (name_len);
+ int entry_type =
+ e->stat_timestamp ? IFTODT (e->stat.st_mode) : DT_UNKNOWN;
+
+ if ((p - *data) + sz > size)
+ {
+ if (max_data_len > 0)
+ break;
+ else
+ /* Try to grow our return buffer. */
+ {
+ 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 = e->stat.st_ino;
+ hdr.d_reclen = sz;
+ hdr.d_type = entry_type;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, e->name);
+ p += sz;
+
+ count++;
+ e = e->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;
+ }
+
+ return err;
+}
+
+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 = ftpfs_refresh_node (dir);
+
+ if (! err)
+ {
+ if (dir->nn->dir)
+ {
+ err = ftpfs_dir_refresh (dir->nn->dir);
+ if (! err)
+ err = get_dirents (dir->nn->dir, first_entry, max_entries,
+ data, data_len, max_entries, data_entries);
+ }
+ else
+ err = ENOTDIR;
+ }
+
+ 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 = ftpfs_refresh_node (dir);
+ if (! err)
+ err = ftpfs_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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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 = FSTYPE_FTP;
+ 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 = 0;
+ 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 = ftpfs_refresh_node (node);
+ if (! err)
+ {
+ struct ftpfs_dir_entry *e = node->nn->dir_entry;
+ if (e)
+ bcopy (e->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 = 0;
+
+ if (! node->nn->contents)
+ err = ccache_create (node, &node->nn->contents);
+ if (! err)
+ {
+ if (*len > node->nn_stat.st_size - offset)
+ *len = node->nn_stat.st_size - offset;
+ if (*len > 0)
+ err = ccache_read (node->nn->contents, offset, *len, data);
+ }
+
+ return err;
+}
+
+/* Write to the file NODE for user CRED starting at OFSET 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;
+}
diff --git a/ftpfs/node.c b/ftpfs/node.c
new file mode 100644
index 00000000..d949016c
--- /dev/null
+++ b/ftpfs/node.c
@@ -0,0 +1,114 @@
+/* General fs node functions
+
+ Copyright (C) 1997, 2006 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <fcntl.h>
+#include <string.h>
+
+#include <hurd/ihash.h>
+#include <hurd/fshelp.h>
+#include <hurd/iohelp.h>
+#include <hurd/netfs.h>
+
+#include "ftpfs.h"
+#include "ccache.h"
+
+/* Node maintenance. */
+
+/* Return a new node in NODE, with a name NAME, and return the new node
+ with a single reference in NODE. E may be 0, if this is the root node. */
+error_t
+ftpfs_create_node (struct ftpfs_dir_entry *e, const char *rmt_path,
+ struct node **node)
+{
+ struct node *new;
+ struct netnode *nn = malloc (sizeof (struct netnode));
+ error_t err;
+
+ if (! nn)
+ return ENOMEM;
+
+ nn->fs = e->dir->fs;
+ nn->dir_entry = e;
+ nn->contents = 0;
+ nn->dir = 0;
+ nn->rmt_path = strdup (rmt_path);
+ nn->ncache_next = nn->ncache_prev = 0;
+
+ new = netfs_make_node (nn);
+ if (! new)
+ {
+ free (nn);
+ return ENOMEM;
+ }
+
+ fshelp_touch (&new->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ ftpfs_maptime);
+
+ spin_lock (&nn->fs->inode_mappings_lock);
+ err = hurd_ihash_add (&nn->fs->inode_mappings, e->stat.st_ino, e);
+ spin_unlock (&nn->fs->inode_mappings_lock);
+
+ if (err)
+ {
+ free (nn);
+ free (new);
+ return err;
+ }
+
+ e->node = new;
+ *node = new;
+
+ return 0;
+}
+
+/* Node NP is all done; free all its associated storage. */
+void
+netfs_node_norefs (struct node *node)
+{
+ struct netnode *nn = node->nn;
+
+ /* Ftpfs_detach_node does ref count frobbing (of other nodes), so we have
+ to unlock NETFS_NODE_REFCNT_LOCK during it. */
+ node->references++;
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ /* Remove NODE from any entry it is attached to. */
+ ftpfs_detach_node (node);
+
+ if (nn->dir)
+ {
+ assert (nn->dir->num_live_entries == 0);
+ ftpfs_dir_free (nn->dir);
+ }
+
+ /* Remove this entry from the set of known inodes. */
+ spin_lock (&nn->fs->inode_mappings_lock);
+ hurd_ihash_locp_remove (&nn->fs->inode_mappings, nn->dir_entry->inode_locp);
+ spin_unlock (&nn->fs->inode_mappings_lock);
+
+ if (nn->contents)
+ ccache_free (nn->contents);
+
+ free (nn);
+ free (node);
+
+ /* Caller expects us to leave this locked... */
+ spin_lock (&netfs_node_refcnt_lock);
+}
diff --git a/hostmux/Makefile b/hostmux/Makefile
new file mode 100644
index 00000000..8e100995
--- /dev/null
+++ b/hostmux/Makefile
@@ -0,0 +1,30 @@
+# Makefile for hostmux
+#
+# Copyright (C) 1997, 1999, 2000 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 := hostmux
+makemode := server
+
+target = hostmux
+
+SRCS = hostmux.c mux.c leaf.c node.c stubs.c
+LCLHDRS = hostmux.h
+
+OBJS = $(SRCS:.c=.o)
+HURDLIBS = netfs fshelp iohelp threads ports ihash shouldbeinlibc
+
+include ../Makeconf
diff --git a/libmom/priv.h b/hostmux/hostmux-xinl.c
index 88d2d9ed..4e11968e 100644
--- a/libmom/priv.h
+++ b/hostmux/hostmux-xinl.c
@@ -1,7 +1,7 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* Real definitions for extern inline functions in hostmux.h
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,10 +18,5 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include "mom.h"
-#include <assert.h>
-#include <cthreads.h>
-
-extern struct mutex _mom_memory_lock;
-
-
+#define HOSTMUX_DEFINE_EI
+#include "hostmux.h"
diff --git a/hostmux/hostmux.c b/hostmux/hostmux.c
new file mode 100644
index 00000000..3778613c
--- /dev/null
+++ b/hostmux/hostmux.c
@@ -0,0 +1,169 @@
+/* Multiplexing filesystems by host
+
+ Copyright (C) 1997, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <sys/time.h>
+
+#include <version.h>
+
+#include "hostmux.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (hostmux);
+
+char *netfs_server_name = "hostmux";
+char *netfs_server_version = HURD_VERSION;
+int netfs_maxsymlinks = 25;
+
+volatile struct mapped_time_value *hostmux_mapped_time;
+
+#define DEFAULT_HOST_PAT "${host}"
+
+/* Startup options. */
+static const struct argp_option options[] =
+{
+ { "host-pattern", 'H', "PAT", 0,
+ "The string to replace in the translator specification with the hostname;"
+ " if empty, or doesn't occur, the hostname is appended as additional"
+ " argument instead (default `" DEFAULT_HOST_PAT "')" },
+ { 0 }
+};
+static const char args_doc[] = "TRANSLATOR [ARG...]";
+static const char doc[] =
+ "A translator for invoking host-specific translators."
+ "\vThis translator appears like a directory in which hostnames can be"
+ " looked up, and will start TRANSLATOR to service each resulting node.";
+
+/* Return an argz string describing the current options. Fill *ARGZ
+ with a pointer to newly malloced storage holding the list and *LEN
+ to the length of that storage. */
+error_t
+netfs_append_args (char **argz, size_t *argz_len)
+{
+ char buf[80];
+ error_t err = 0;
+ struct hostmux *mux = netfs_root_node->nn->mux;
+
+#define FOPT(fmt, arg) \
+ do { \
+ if (! err) \
+ { \
+ snprintf (buf, sizeof buf, fmt, arg); \
+ err = argz_add (argz, argz_len, buf); \
+ } \
+ } while (0)
+
+ if (strcmp (mux->host_pat, DEFAULT_HOST_PAT) != 0)
+ FOPT ("--host-pattern=%s", mux->host_pat);
+
+ if (! err)
+ err = argz_append (argz, argz_len,
+ mux->trans_template, mux->trans_template_len);
+
+ return err;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct stat ul_stat;
+ mach_port_t bootstrap;
+ struct hostmux mux = { host_pat: DEFAULT_HOST_PAT, next_fileno: 10 };
+ struct netnode root_nn = { mux: &mux };
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'H':
+ mux.host_pat = arg; break;
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ case ARGP_KEY_ARGS:
+ /* Steal the entire tail of arg vector for our own use. */
+ return argz_create (state->argv + state->next,
+ &mux.trans_template, &mux.trans_template_len);
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = { options, parse_opt, args_doc, doc };
+
+ /* Parse our command line arguments. */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ netfs_init ();
+
+ /* Create the root node (some attributes initialized below). */
+ netfs_root_node = netfs_make_node (&root_nn);
+ if (! netfs_root_node)
+ error (5, ENOMEM, "Cannot create root node");
+
+ err = maptime_map (0, 0, &hostmux_maptime);
+ if (err)
+ error (6, err, "Cannot map time");
+
+ /* Handshake with the party trying to start the translator. */
+ mux.underlying = netfs_startup (bootstrap, 0);
+
+ /* We inherit various attributes from the node underlying this translator. */
+ err = io_stat (mux.underlying, &ul_stat);
+ if (err)
+ error (7, err, "Cannot stat underlying node");
+
+ /* MUX.stat_template contains some fields that are inherited by all nodes
+ we create. */
+ mux.stat_template.st_uid = ul_stat.st_uid;
+ mux.stat_template.st_gid = ul_stat.st_gid;
+ mux.stat_template.st_author = ul_stat.st_author;
+ mux.stat_template.st_fsid = getpid ();
+ mux.stat_template.st_nlink = 1;
+ mux.stat_template.st_fstype = FSTYPE_MISC;
+
+ /* Initialize the root node's stat information. */
+ netfs_root_node->nn_stat = mux.stat_template;
+ netfs_root_node->nn_stat.st_ino = 2;
+ netfs_root_node->nn_stat.st_mode =
+ S_IFDIR | (ul_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+ netfs_root_node->nn_translated = 0;
+
+ /* If the underlying node isn't a directory, propagate read permission to
+ execute permission since we need that for lookups. */
+ if (! S_ISDIR (ul_stat.st_mode))
+ {
+ if (ul_stat.st_mode & S_IRUSR)
+ netfs_root_node->nn_stat.st_mode |= S_IXUSR;
+ if (ul_stat.st_mode & S_IRGRP)
+ netfs_root_node->nn_stat.st_mode |= S_IXGRP;
+ if (ul_stat.st_mode & S_IROTH)
+ netfs_root_node->nn_stat.st_mode |= S_IXOTH;
+ }
+
+ fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ hostmux_maptime);
+
+ for (;;) /* ?? */
+ netfs_server_loop ();
+}
diff --git a/hostmux/hostmux.h b/hostmux/hostmux.h
new file mode 100644
index 00000000..98ef04ac
--- /dev/null
+++ b/hostmux/hostmux.h
@@ -0,0 +1,95 @@
+/* Multiplexing filesystems by host
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef __HOSTMUX_H__
+#define __HOSTMUX_H__
+
+#include <hurd/netfs.h>
+#include <rwlock.h>
+#include <maptime.h>
+#include <features.h>
+
+#ifdef HOSTMUX_DEFINE_EI
+#define HOSTMUX_EI
+#else
+#define HOSTMUX_EI __extern_inline
+#endif
+
+/* Handy source of time. */
+volatile struct mapped_time_value *hostmux_maptime;
+
+/* The state associated with a host multiplexer translator. */
+struct hostmux
+{
+ /* The host hodes in this mux. */
+ struct hostmux_name *names;
+ struct rwlock names_lock;
+
+ /* The next inode number we'll use; protected by NAMES_LOCK. */
+ ino_t next_fileno;
+
+ /* A template argz, which is used to start each host-specific translator
+ with the host name appropriately added. */
+ char *trans_template;
+ size_t trans_template_len;
+
+ /* What string to replace in TRANS_TEMPLATE with the name of the host; if
+ 0, or it doesn't occur, the host name is appended as an additional
+ argument. */
+ char *host_pat;
+
+ /* Constant fields for host stat entries. */
+ struct stat stat_template;
+
+ /* The file that this translator is sitting on top of; we inherit various
+ characteristics from it. */
+ file_t underlying;
+};
+
+/* The name of a recently looked up host entry. */
+struct hostmux_name
+{
+ const char *name; /* Looked up name (may be a number). */
+ const char *canon; /* The canonical (fq) host name. */
+
+ /* A filesystem node associated with NAME. If NAME = CANON, then this will
+ refer to a node with a translator for that host, otherwise, the node
+ will be a symbolic link to the canonical name. */
+ struct node *node;
+
+ ino_t fileno; /* The inode number for this entry. */
+
+ struct hostmux_name *next;
+};
+
+/* The fs specific storage that libnetfs associates with each filesystem
+ node. */
+struct netnode
+{
+ /* The mux this node belongs to (the node can either be the mux root, or
+ one of the hosts served by it). */
+ struct hostmux *mux;
+
+ /* For mux nodes, 0, and for leaf nodes, the name under which the node was
+ looked up. */
+ struct hostmux_name *name;
+};
+
+#endif /* __HOSTMUX_H__ */
diff --git a/hostmux/leaf.c b/hostmux/leaf.c
new file mode 100644
index 00000000..fb53622f
--- /dev/null
+++ b/hostmux/leaf.c
@@ -0,0 +1,124 @@
+/* Hostmux leaf node functions
+
+ Copyright (C) 1997,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <argz.h>
+
+#include "hostmux.h"
+
+/* Read the contents of NODE (a symlink), for USER, into BUF. */
+error_t
+netfs_attempt_readlink (struct iouser *user, struct node *node, char *buf)
+{
+ assert (node->nn->name);
+ memcpy (buf, node->nn->name->canon, node->nn_stat.st_size);
+ fshelp_touch (&node->nn_stat, TOUCH_ATIME, hostmux_maptime);
+ return 0;
+}
+
+/* For locked node NODE with S_IPTRANS set in its mode, look up the name of
+ its translator. Store the name into newly malloced storage, and return it
+ in *ARGZ; set *ARGZ_LEN to the total length.
+
+ For hostmux, this creates a new translator string by instantiating the
+ global translator template. */
+error_t
+netfs_get_translator (struct node *node, char **argz, size_t *argz_len)
+{
+ if (! node->nn->name)
+ return EINVAL;
+ else
+ {
+ error_t err = 0;
+ unsigned replace_count = 0;
+ struct hostmux *mux = node->nn->mux;
+
+ *argz = 0; /* Initialize return value. */
+ *argz_len = 0;
+
+ /* Return a copy of MUX's translator template, with occurrences of
+ HOST_PAT replaced by the canonical hostname. */
+ err = argz_append (argz, argz_len,
+ mux->trans_template, mux->trans_template_len);
+ if (! err)
+ err = argz_replace (argz, argz_len,
+ mux->host_pat, node->nn->name->canon,
+ &replace_count);
+
+ if (!err && replace_count == 0)
+ /* Default, if no instances of HOST_PAT occur, is to append the
+ hostname. */
+ err = argz_add (argz, argz_len, node->nn->name->canon);
+
+ if (err && *argz_len > 0)
+ free (*argz);
+
+ return err;
+ }
+}
+
+/* Create a new leaf node in MUX, with a name NAME, and return the new node
+ with a single reference in NODE. */
+error_t
+create_host_node (struct hostmux *mux, struct hostmux_name *name,
+ struct node **node)
+{
+ struct node *new;
+ struct netnode *nn = malloc (sizeof (struct netnode));
+
+ if (! nn)
+ return ENOMEM;
+
+ nn->mux = mux;
+ nn->name = name;
+
+ new = netfs_make_node (nn);
+ if (! new)
+ {
+ free (nn);
+ return ENOMEM;
+ }
+
+ new->nn_stat = mux->stat_template;
+ new->nn_stat.st_ino = name->fileno;
+
+ if (strcmp (name->name, name->canon) == 0)
+ /* The real name of the host, make a real node. */
+ {
+ new->nn_stat.st_mode = (S_IFREG | S_IPTRANS | 0666);
+ new->nn_stat.st_size = 0;
+ }
+ else
+ /* An alias for this host, make a symlink instead. */
+ {
+ new->nn_stat.st_mode = (S_IFLNK | 0666);
+ new->nn_stat.st_size = strlen (name->canon);
+ }
+ new->nn_translated = new->nn_stat.st_mode;
+
+ fshelp_touch (&new->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ hostmux_maptime);
+
+ name->node = new;
+
+ *node = new;
+
+ return 0;
+}
diff --git a/hostmux/mux.c b/hostmux/mux.c
new file mode 100644
index 00000000..dd976c57
--- /dev/null
+++ b/hostmux/mux.c
@@ -0,0 +1,457 @@
+/* Root hostmux node
+
+ Copyright (C) 1997,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stddef.h>
+#include <string.h>
+#include <dirent.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+
+#include "hostmux.h"
+
+error_t create_host_node (struct hostmux *mux, struct hostmux_name *name,
+ struct node **node);
+
+/* 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))
+
+static error_t lookup_host (struct hostmux *mux, const char *host,
+ struct node **node); /* fwd decl */
+
+/* [root] Directory operations. */
+
+/* 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;
+
+ if (dir->nn->name)
+ err = ENOTDIR;
+ else
+ err = fshelp_access (&dir->nn_stat, S_IEXEC, user);
+
+ if (! err)
+ {
+ if (strcmp (name, ".") == 0)
+ /* Current directory -- just add an additional reference to DIR and
+ return it. */
+ {
+ netfs_nref (dir);
+ *node = dir;
+ err = 0;
+ }
+ else if (strcmp (name, "..") == 0)
+ err = EAGAIN;
+ else
+ err = lookup_host (dir->nn->mux, name, node);
+
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, hostmux_maptime);
+ }
+
+ mutex_unlock (&dir->lock);
+ if (err)
+ *node = 0;
+ else
+ mutex_lock (&(*node)->lock);
+
+ return err;
+}
+
+/* Implement the netfs_get_directs callback as described in
+ <hurd/netfs.h>. */
+error_t
+netfs_get_dirents (struct iouser *cred, struct node *dir,
+ int first_entry, int num_entries, char **data,
+ mach_msg_type_number_t *data_len,
+ vm_size_t max_data_len, int *data_entries)
+{
+ error_t err;
+ int count;
+ size_t size = 0; /* Total size of our return block. */
+ struct hostmux_name *first_name, *nm;
+
+ /* Add the length of a directory entry for NAME to SIZE and return true,
+ unless it would overflow MAX_DATA_LEN or NUM_ENTRIES, in which case
+ return false. */
+ int bump_size (const char *name)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ size_t new_size = size + DIRENT_LEN (strlen (name));
+ if (max_data_len > 0 && new_size > max_data_len)
+ return 0;
+ size = new_size;
+ count++;
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ if (dir->nn->name)
+ return ENOTDIR;
+
+ rwlock_reader_lock (&dir->nn->mux->names_lock);
+
+ /* Find the first entry. */
+ for (first_name = dir->nn->mux->names, count = 2;
+ first_name && first_entry > count;
+ first_name = first_name->next)
+ if (first_name->node)
+ count++;
+
+ count = 0;
+
+ /* Make space for the `.' and `..' entries. */
+ if (first_entry == 0)
+ bump_size (".");
+ if (first_entry <= 1)
+ bump_size ("..");
+
+ /* See how much space we need for the result. */
+ for (nm = first_name; nm; nm = nm->next)
+ if (nm->node && !bump_size (nm->name))
+ break;
+
+ /* Allocate it. */
+ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = ((void *) *data == (void *) -1) ? errno : 0;
+
+ if (! err)
+ /* Copy out the result. */
+ {
+ char *p = *data;
+
+ int add_dir_entry (const char *name, ino_t fileno, int type)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (name);
+ size_t sz = DIRENT_LEN (name_len);
+
+ if (sz > size)
+ return 0;
+ else
+ size -= sz;
+
+ hdr.d_fileno = fileno;
+ hdr.d_reclen = sz;
+ hdr.d_type = type;
+ hdr.d_namlen = name_len;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, name);
+ p += sz;
+
+ count++;
+
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ *data_len = size;
+ *data_entries = count;
+
+ count = 0;
+
+ /* Add `.' and `..' entries. */
+ if (first_entry == 0)
+ add_dir_entry (".", 2, DT_DIR);
+ if (first_entry <= 1)
+ add_dir_entry ("..", 2, DT_DIR);
+
+ /* Fill in the real directory entries. */
+ for (nm = first_name; nm; nm = nm->next)
+ if (nm->node
+ && !add_dir_entry (nm->name, nm->fileno,
+ strcmp (nm->canon, nm->name) == 0
+ ? DT_REG : DT_LNK))
+ break;
+ }
+
+ rwlock_reader_unlock (&dir->nn->mux->names_lock);
+
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, hostmux_maptime);
+
+ return err;
+}
+
+/* Host lookup. */
+
+/* Free storage allocated consumed by the host mux name NM, but not the node
+ it points to. */
+static void
+free_name (struct hostmux_name *nm)
+{
+ if (nm->name != nm->canon)
+ free ((char *)nm->canon);
+ free ((char *)nm->name);
+ free (nm);
+}
+
+/* See if there's an existing entry for the name HOST, and if so, return its
+ node in NODE with an additional references. True is returned iff the
+ lookup succeeds. If PURGE is true, then any nodes with a null node are
+ removed. */
+static int
+lookup_cached (struct hostmux *mux, const char *host, int purge,
+ struct node **node)
+{
+ struct hostmux_name *nm = mux->names, **prevl = &mux->names;
+
+ while (nm)
+ {
+ struct hostmux_name *next = nm->next;
+
+ if (strcasecmp (host, nm->name) == 0)
+ {
+ spin_lock (&netfs_node_refcnt_lock);
+ if (nm->node)
+ nm->node->references++;
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ if (nm->node)
+ {
+ *node = nm->node;
+ return 1;
+ }
+ }
+
+ if (purge && !nm->node)
+ {
+ *prevl = nm->next;
+ free_name (nm);
+ }
+ else
+ prevl = &nm->next;
+
+ nm = next;
+ }
+
+ return 0;
+}
+
+/* See if there's an existing entry for the name HOST, and if so, return its
+ node in NODE, with an additional reference, otherwise, create a new node
+ for the host HE as referred to by HOST, and return that instead, with a
+ single reference. The type of node created is either a translator node,
+ if HOST refers to the official name of the host, or a symlink node to the
+ official name, if it doesn't. */
+static error_t
+lookup_addrinfo (struct hostmux *mux, const char *host, struct addrinfo *he,
+ struct node **node)
+{
+ error_t err;
+ struct hostmux_name *nm = malloc (sizeof (struct hostmux_name));
+
+ if (! nm)
+ return ENOMEM;
+
+ nm->name = strdup (host);
+ if (strcmp (host, he->ai_canonname) == 0)
+ nm->canon = nm->name;
+ else
+ nm->canon = strdup (he->ai_canonname);
+
+ err = create_host_node (mux, nm, node);
+ if (err)
+ {
+ free_name (nm);
+ return err;
+ }
+
+ rwlock_writer_lock (&mux->names_lock);
+ if (lookup_cached (mux, host, 1, node))
+ /* An entry for HOST has already been created between the time we last
+ looked and now (which is possible because we didn't lock MUX).
+ Just throw away our version and return the one already in the cache. */
+ {
+ rwlock_writer_unlock (&mux->names_lock);
+ nm->node->nn->name = 0; /* Avoid touching the mux name list. */
+ netfs_nrele (nm->node); /* Free the tentative new node. */
+ free_name (nm); /* And the name it was under. */
+ }
+ else
+ /* Enter NM into MUX's list of names, and return the new node. */
+ {
+ nm->fileno = mux->next_fileno++; /* Now that we hold the lock... */
+ nm->next = mux->names;
+ mux->names = nm;
+ rwlock_writer_unlock (&mux->names_lock);
+ }
+
+ return 0;
+}
+
+/* Lookup the host HOST in MUX, and return the resulting node in NODE, with
+ an additional reference, or an error. */
+static error_t
+lookup_host (struct hostmux *mux, const char *host, struct node **node)
+{
+ int was_cached;
+ int h_err;
+ struct addrinfo *ai;
+ struct addrinfo hints;
+
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_IP;
+
+ rwlock_reader_lock (&mux->names_lock);
+ was_cached = lookup_cached (mux, host, 0, node);
+ rwlock_reader_unlock (&mux->names_lock);
+
+ if (was_cached)
+ return 0;
+
+ h_err = getaddrinfo (host, NULL, &hints, &ai);
+ if (! h_err)
+ {
+ h_err = lookup_addrinfo (mux, host, ai, node);
+ freeaddrinfo (ai);
+ }
+
+ return h_err;
+}
+
+/* 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;
+}
+
+/* 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)
+{
+ if (node->nn->name)
+ return EOPNOTSUPP;
+ else
+ {
+ struct hostmux *mux = node->nn->mux;
+ error_t err = file_chown (mux->underlying, uid, gid);
+
+ if (! err)
+ {
+ struct hostmux_name *nm;
+
+ /* Change NODE's owner. */
+ mux->stat_template.st_uid = uid;
+ mux->stat_template.st_gid = gid;
+ node->nn_stat.st_uid = uid;
+ node->nn_stat.st_gid = gid;
+
+ /* Change the owner of each leaf node. */
+ rwlock_reader_lock (&mux->names_lock);
+ for (nm = mux->names; nm; nm = nm->next)
+ if (nm->node)
+ {
+ nm->node->nn_stat.st_uid = uid;
+ nm->node->nn_stat.st_gid = gid;
+ }
+ rwlock_reader_unlock (&mux->names_lock);
+
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, hostmux_maptime);
+ }
+
+ return err;
+ }
+}
+
+/* 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)
+{
+ if (node->nn->name)
+ return EOPNOTSUPP;
+ else
+ {
+ struct hostmux *mux = node->nn->mux;
+ error_t err = file_chauthor (mux->underlying, author);
+
+ if (! err)
+ {
+ struct hostmux_name *nm;
+
+ /* Change NODE's owner. */
+ mux->stat_template.st_author = author;
+ node->nn_stat.st_author = author;
+
+ /* Change the owner of each leaf node. */
+ rwlock_reader_lock (&mux->names_lock);
+ for (nm = mux->names; nm; nm = nm->next)
+ if (nm->node)
+ nm->node->nn_stat.st_author = author;
+ rwlock_reader_unlock (&mux->names_lock);
+
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, hostmux_maptime);
+ }
+
+ return err;
+ }
+}
+
+/* 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)
+{
+ mode &= ~S_ITRANS;
+ if ((mode & S_IFMT) == 0)
+ mode |= (node->nn_stat.st_mode & S_IFMT);
+ if (node->nn->name || ((mode & S_IFMT) != (node->nn_stat.st_mode & S_IFMT)))
+ return EOPNOTSUPP;
+ else
+ {
+ error_t err = file_chmod (node->nn->mux->underlying, mode & ~S_IFMT);
+ if (! err)
+ {
+ node->nn_stat.st_mode = mode;
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, hostmux_maptime);
+ }
+ return err;
+ }
+}
diff --git a/hostmux/node.c b/hostmux/node.c
new file mode 100644
index 00000000..d6edc53e
--- /dev/null
+++ b/hostmux/node.c
@@ -0,0 +1,127 @@
+/* General fs node functions
+
+ Copyright (C) 1997, 1999, 2007 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <fcntl.h>
+
+#include "hostmux.h"
+
+/* Node maintenance. */
+
+/* Node NP is all done; free all its associated storage. */
+void
+netfs_node_norefs (struct node *node)
+{
+ if (node->nn->name)
+ /* Remove our name's pointer to us; the name itself will eventually be
+ freed by another party. */
+ node->nn->name->node = 0;
+ free (node->nn);
+ free (node);
+}
+
+/* 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 = 0;
+ mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+/* 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 = 0;
+ if (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 = fshelp_isowner (&node->nn_stat, cred);
+ int flags = TOUCH_CTIME;
+
+ if (! err)
+ {
+ if (mtime)
+ node->nn_stat.st_mtim = *mtime;
+ else
+ flags |= TOUCH_MTIME;
+
+ if (atime)
+ node->nn_stat.st_atim = *atime;
+ else
+ flags |= TOUCH_ATIME;
+
+ fshelp_touch (&node->nn_stat, flags, hostmux_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)
+{
+ *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 0;
+}
+
+/* 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 0;
+}
+
+/* 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;
+}
diff --git a/hostmux/stubs.c b/hostmux/stubs.c
new file mode 100644
index 00000000..f5dd9b67
--- /dev/null
+++ b/hostmux/stubs.c
@@ -0,0 +1,145 @@
+/* Stub routines for hostmux
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd/netfs.h>
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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)
+{
+ return EOPNOTSUPP;
+}
+
+/* Delete NAME in DIR for USER. */
+error_t
+netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* Attempt to remove directory named NAME in DIR for USER. */
+error_t
+netfs_attempt_rmdir (struct iouser *user,
+ struct node *dir, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 = 0;
+ mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+/* 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)
+{
+ return EOPNOTSUPP;
+}
+
+/* Write to the file NODE for user CRED starting at OFSET 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 EOPNOTSUPP;
+}
diff --git a/hurd.boot b/hurd.boot
index 3ffbf039..844c6345 100644
--- a/hurd.boot
+++ b/hurd.boot
@@ -3,11 +3,11 @@
# First, the bootstrap filesystem. It needs several ports as arguments,
# as well as the user flags from the boot loader.
-/hurd/ufs --bootflags=${boot-args} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} --machdev ${root-device} $(task-create) $(task-resume)
+/hurd/ufs --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} --machdev ${root-device} $(task-create) $(task-resume)
# Now the exec server; to load the dynamically-linked exec server program,
# we have the boot loader in fact load and run ld.so, which in turn
# loads and runs /hurd/exec. This task is created, and its task port saved
-# in ${exec-task} to be passed to the fs above, but it is left suspended;
+# in ${exec-task} to be passed to the fs above, but it is left suspended;
# the fs will resume the exec task once it is ready.
/lib/ld.so /hurd/exec $(exec-task=task-create)
diff --git a/hurd/=pending-changes b/hurd/=pending-changes
index 33660b46..d57270a9 100644
--- a/hurd/=pending-changes
+++ b/hurd/=pending-changes
@@ -1,26 +1,24 @@
User visible:
-Change fsys_set_options interface to allow returning data & err+data.
- fsys: fsys_t; options: data_t; do_children: int; err: error_t; result: data_t
-Add error_t to hurd_types.defs.
-
-Add notification calls to process.defs (and create process_notify.defs).
+Add notification calls to process.defs (and create process_notify.defs).
(not yet)
Add file_exchange_contents (not yet)
Change file_getfh and fsys_getfile to use more convenient interface.
-Remove hostid/hostname calls from process.defs.
-
Add serverport arg to auth_user_authenticate; change auth to use it to
abort auth_user_authenticate when it's dead.
-Add io_revoke.
+Add optional timeout arg to msg.defs.
+
+Add file_fetch_dir.
+Delete release arg from register version crap.
+
+Delete non-string args from io_server_version; separate name and version.
Not user visible:
Format of /var/login should be user:1 not user-1.
[Or as subdirectories, if a server supplies directory ops anyway]
-
diff --git a/hurd/ChangeLog b/hurd/ChangeLog
deleted file mode 100644
index 99a0fe2f..00000000
--- a/hurd/ChangeLog
+++ /dev/null
@@ -1,844 +0,0 @@
-Wed Jul 17 14:30:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile: gs/install-hdrs/install-headers/g.
-
-Tue Jul 16 11:37:35 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (INSTHDRS): Repair syntax.
- (install-hdrs install): Correctly form pathname.
-
-Sat Jul 13 20:55:59 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile: Rewritten to get the right things installed in the
- right places.
-
- * Makefile (install-hdrs): New target; eq to install.
-
-Mon Jul 1 16:28:01 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * crash.defs (crash_dump_task): Use integer_t for sigcode. Add exc,
- code, subcode, cttyid_port args.
-
-Wed Jun 12 15:56:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * startup_notify.defs (subsystem declaration): Use correct value
- 29500 from subsystems file.
-
-Sat May 25 17:09:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * msg_request.defs (msg_sig_post_request,
- msg_sig_post_untraced_request): Add SIGCODE argument.
-
-Wed May 22 18:50:14 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * process_reply.defs (proc_wait_reply): Add SIGCODE argument.
-
-Tue May 14 17:39:24 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * Makefile (install): Depend on $(includedir)/hurd and add rule to
- create it.
-
-Sat May 11 17:32:20 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * Makefile: Quick hack for installing headers prior to building libc.
- (hdrs): New variable, do wildcarding in $(srcdir).
- (DIST_FILES): Use that.
- (install): Install $(hdrs) in $(includedir)/hurd from $(srcdir).
-
-Thu May 9 12:44:43 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Reference *.h, instead of individual
- files.
-
- * Makefile (REMHDRS, dohdrs): Deleted targets.
-
-Tue May 7 12:54:19 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * io.defs (io_identity): Server passes back fs id port and st_ino
- value.
-
-Mon May 6 15:28:50 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * msg.defs (msg_describe_ports): New rpc.
-
- * fs.defs (file_get_storage_info): Change arguments & comment.
-
-Mon May 6 13:31:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * version.h (hurd_versions): Add version 0.0.
- * hurd_types.h (HURD_RELEASE): Update to 0.0.
-
- * hurd_types.h (struct procinfo): Add exitstatus and sigcode
- members.
-
- * hurd_types.h (FSTYPE_SOCKET): Doc fix.
-
- * hurd_types.h (retry_type) [FS_RETRY_REAUTH]: Doc fix.
-
- * hurd_types.h (file_storage_class): Add STORAGE_NULL,
- STORAGE_CONCAT, STORAGE_INTERLEAVE, and STORAGE_LAYER.
-
- * hurd_types.h (struct fsys_statfsbuf): Delete type.
- (fsys_statfsbuf_t): Now based upon struct statfs.
- * hurd_types.defs (fsys_statfsbuf_t): Now 16 long.
- Import <sys/statfs.h>.
-
- * fsys.defs (fsys_get_options): Add RPT.
-
- * startup_notify.defs: New file.
- * startup.defs (startup_request_notification): NOTIFY_PORT now
- mach_port_send_t. New arg NAME.
- * subsystems: Add startup_notify.
-
- * process.defs (proc_getprocinfo): Make FLAGS inout.
-
- * process.defs (proc_get_tty): New RPC.
- * process_request.defs (proc_get_tty_request): Likewise.
-
- * process.defs (proc_mark_stop, proc_mark_exit): Add SIGCODE arg.
- (proc_wait): Return SIGCODE parm too.
- * process_request.defs (proc_mark_stop_request,
- proc_mark_exit_request): Likewise.
-
- * process.defs (proc_setowner): Add CLEAR parm.
- * process_request.defs (proc_setowner_request): Likewise.
-
- * process.defs (proc_setmsgport): Return old message port with
- mach_port_send_t to permit more flexibility in proc server.
-
- * fs.defs (file_sync): New parm `omit_metadata'.
- (dir_link, dir_rename): Add parm `excl'.
-
- * io.defs (io_verify_identity): Delete RPC.
- (io_identity): New RPC.
-
-Fri May 3 16:56:22 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * hurd_types.h (EXEC_INHERITED): Macro removed.
- (EXEC_TRACED): Macro removed.
- (INIT_TRACEMASK): New enum constant.
-
- * msg.defs (msg_*_exec_flags): RPCs removed.
-
- * msg.defs (msg_sig_post, msg_sig_post_untraced): Add SIGCODE arg.
- (msg_startup_dosync): RPC removed.
-
- * io.defs (io_select): Remove ID_TAG arg.
- (io_verify_identity): New RPC.
-
- * auth.defs (auth_user_authenticate, auth_server_authenticate): Remove
- second rendezvous port arg, leaving just one, of type mach_port_send_t.
-
-Tue Apr 30 13:54:34 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * auth.defs: Mark with INTR_INTERFACE.
- (auth_user_authenticate): Remove sreplyport arg.
-
-Sun Apr 28 19:13:42 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * interrupt.defs: Remove 1 second waittime spec.
- (interrupt_operation): Add waittime arg.
- * msg.defs (msg_startup_dosync): Add waittime arg.
-
-Thu Apr 25 16:27:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pfinet.defs: New file.
- * subsystems: Added pfinet.
-
-Fri Feb 9 11:30:08 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * tioctl.defs: Import hurd/ioctl_types.h with <> instead of "".
-
-Thu Feb 8 20:35:34 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ioctl_types.h: Protect from multiple inclusion.
-
-Tue Dec 26 17:47:03 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.defs (io_select): Fix ifdefs around the reply port decls to
- work properly when the server side ports are desired.
-
-Wed Dec 20 15:21:41 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * process.defs (proc_getsidport): Use mach_port_send_t instead of
- mach_port_make_send_t.
-
-Tue Dec 19 18:28:35 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * process.defs (proc_getsidport): Make SESSPORT's type
- mach_port_make_send_t, since proc always just holds a receive right.
-
-Mon Dec 11 15:21:42 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Added netfs.h.
- (REMHDRS): Added ../libnetfs/netfs.h.
-
-Fri Dec 1 15:45:11 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * tioctl.defs (tioctl_tiocsig): Needs one int arg.
-
-Tue Nov 21 09:58:13 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * interrupt.defs (interrupt_operation): Include SEQNO server
- argument.
-
-Mon Nov 20 18:26:52 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * msg_request.defs: Add skip for `Obsolete io_select_done'
- to match msg.defs.
- * msg_reply.defs: Ditto.
-
-Sat Nov 18 23:33:55 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * crash.defs (crash_dump_task): Add sreplyport arg.
- * crash_reply.defs: New file.
-
-Mon Nov 13 15:05:04 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.defs (exec_startup): RPC removed; replaced with skip.
-
-Fri Nov 10 10:02:17 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * process_request.defs: New file.
-
-Sat Nov 4 23:15:01 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsys_reply.defs (fsys_startup_reply, fsys_get_options_reply): Tyop.
-
-Tue Oct 31 15:54:20 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hurd_types.h: Add missing */.
-
-Tue Oct 31 14:14:39 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * process.defs (proc_getprocinfo): New parm THREADWAITS.
-
-Tue Oct 31 02:23:55 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * msg.defs (msg_report_wait): Add string out arg.
-
-Mon Oct 30 10:41:06 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * hurd_types.h (PI_FETCH_TASKINFO, PI_FETCH_THREADS,
- PI_FETCH_THREAD_BASIC, PI_FETCH_THREAD_SCHED,
- PI_FETCH_THREAD_WAITS): New flags.
- (procinfo): New (buried) members `rpc_block' and `died'.
- * msg.defs (msg_report_wait): Change second arg to be a real
- thread_t. Change returned reason from a string to an rpc code.
-
- * process.defs (proc_getprocinfo): New parm FLAGS.
-
- * hurd_types.h (enum file_storage_class): Added new classes
- STORAGE_MEMORY and STORAGE_TASK. Doc fixes. Drop all the MUTATED
- bits.
- (STORAGE_MUTATED) New flag.
- * fs.defs (file_get_storage_info): New parm FLAGS.
-
- * hurd_types.h (PI_LOGINLD, PI_WAITING, PI_TRACED, PI_GETMSG): New
- flags.
-
- * io.defs (io_select): Make sreply port also available if
- IO_SELECT_REPLY_PORT is defined.
-
-Fri Oct 27 14:43:17 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * fsys.defs (fsys_startup): New parm OPENFLAGS.
-
- * hurd_types.defs (SCP): New macro.
- * io.defs (io_write, io_restrict_auth): Add SCP to incoming
- variable sized arrays.
- * socket.defs (socket_create_address, socket_setopt, socket_send):
- Likewise.
- * fs.defs (file_exec, file_set_translator): Likewise.
-
- * socket.defs (socket_create_address): Drop parm `binding'.
-
- * fs.defs: Added reply port option to all RPC's.
-
- * fsys.defs (fsys_get_options): New RPC.
- * fsys_reply.defs (fsys_get_options_reply): New stub.
- * fs.defs (file_get_fs_options): New RPC.
-
- * msg.defs (msg_report_wait): New RPC.
-
- * fs.defs (file_invoke_translator): Function deleted.
-
- * fsys_reply.defs (fsys_startup_reply, fsys_getfile_reply,
- fsys_syncfs_reply, fsys_set_options_reply, fsys_getpriv_reply,
- fsys_forward_reply): New functions, completing interface.
-
- * fsys.defs: Doc fix.
-
-Wed Oct 25 15:59:25 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec_startup.defs: New file.
- * subsystems: Add exec_startup at 30500.
-
-Thu Oct 12 16:56:52 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.defs: Add INTR_INTERFACE marker.
-
- * fs.defs (file_exec): Remove dealloc[] keywords, and revert
- EXEC_TASK arg to task_t from mach_port_send_t. We cannot safely
- use dealloc ool or move rights with the current RPC system.
-
-Tue Oct 10 17:29:31 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * exec.defs [EXEC_IMPORTS]: Use this if defined.
- (exec_exec, exec_init, exec_setexecdata): Use file_t for receiver.
- (exec_exec): Use mach_port_send_t for FILE.
-
-Sat Oct 7 05:26:20 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * fs.defs (file_exec): Add dealloc[] flag to most args.
-
-Fri Oct 6 17:18:36 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsys.defs (fsys_getpriv): Change types of returned ports to
- mach_port_send_t.
-
- * fs.defs (file_get_storage_info): Change type of ADDRESSES to
- off_array_t. Add ADDRESS_UNITS out parameter.
- (dir_link): Swap the DIR and FILE parameters.
-
- * hurd_types.defs (off_array_t, size_t, ssize_t): New types.
- * hurd_types.h (off_array_t): New type.
-
-Tue Oct 3 13:51:00 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * hurd_types.h (struct fsys_statfsbuf): fsys_stb_bsize ->
- fsys_stb_iosize. fsys_stb_fsize -> fsys_stb_bsize.
-
-Tue Sep 26 11:16:56 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * hurd_types.h (file_storage_class): New type.
- * fs.defs (file_get_storage_info): New RPC; use the slot that used
- to hold file_pathconf.
-
-Sun Sep 17 17:57:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * fs.defs (file_truncate): RPC renamed to file_set_size.
-
- * io.defs (io_pathconf): New RPC.
- * fs.defs (file_pathconf): RPC removed (replaced with skip).
-
- * hurd_types.h (EXEC_STACK_ARGS): New macro.
-
-Fri Sep 15 21:32:15 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * subsystems: core renamed to crash.
- * paths.h (_SERVERS_CRASH): New macro.
- (_SERVERS_CORE): Macro removed.
- * core.defs: Renamed to crash.defs.
- * crash.defs (crash_dump_task): Renamed from core_dump_task.
-
-Thu Aug 24 11:55:28 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fsys.defs (fsys_forward): New rpc.
- * subsystems: Remove tserver.
- * tserver.defs: Removed.
-
-Mon Aug 21 14:08:52 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * tserver.defs (tserver_translate): New file.
- * subsystems: Add tserver.
-
-Mon Jul 17 15:05:16 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * socket.defs (socket_create): Change type of SERVER to pf_t.
- (socket_create_address, socket_fabricate_address): Rename first
- arg to `server', of type mach_port_t (so it can be either pf_t or
- socket_t).
- (socket_recv): Change type of ADDR to mach_port_send_t.
- (socket_send, socket_recv): Change type of AMOUNT to
- mach_msg_type_number_t.
- * hurd_types.h (pf_t): New type.
- * hurd_types.defs (pf_t): New type.
-
-Mon Jun 26 19:23:38 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fsys_reply.defs (fsys_goaway_reply): New routine, in its proper
- place.
-
-Fri May 12 18:54:17 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fsys.defs (fsys_set_options, fsys_mod_readonly): Replace
- mod_readonly with the more general set_options interface.
-
-Mon Mar 20 21:44:59 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (REMHDRS): Add ../libps/ps.h.
-
-Mon Mar 6 15:25:27 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * process.defs: Doc fix.
-
-Tue Jan 17 03:14:22 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * msg_request.defs: Fix typo reply->request.
-
- * io.defs (io_select): Add user reply port and reply timeout args.
- Make arg SELECT_TYPE inout, remove SELECT_RESULT out arg.
- * io_reply.defs: Synchronize with new io_select definition.
-
- * hurd_types.h (EXEC_INHERITED): New macro.
-
- * msg_reply.defs: Prepend `msg_' to all RPC names.
- (dir_changed, file_changed): Remove these skips.
- * msg_request.defs: Prepend `msg_' to all RPC names. Add
- msg_sig_post_untraced_reply and intervening skips.
- * msg.defs: Prepend `msg_' to all RPC names.
- (dir_changed, file_changed): RPCs moved to fs_notify.defs.
- (msg_get_exec_flags, msg_set_exec_flags,
- msg_set_some_exec_flags, msg_clear_some_exec_flags): New RPCs.
- * fs_notify.defs: New file, broken out of msg.defs.
- * subsystems: Add fs_notify at 20500.
-
- * msg_reply.defs: Add sig_post_untraced_reply, and intervening skips.
-
-Mon Jan 16 17:34:34 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hurd_types.h (EXEC_TRACED): New macro.
- * msg.defs (sig_post_untraced): New RPC.
-
- * msg.defs (io_select_done): RPC removed, replaced with a skip.
- * io_reply.defs: Add ID_TAG arg.
- * io_request.defs (io_select_request): Remove RETURN_PORT arg.
- * io.defs (io_select): Remove RETURN_PORT arg; make ID_TAG inout.
-
-Fri Dec 9 00:35:47 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io.defs (io_read, io_write, io_readable): Use
- mach_msg_type_number_t in place of int.
-
-Tue Sep 13 11:03:23 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * auth.defs (auth_getids, auth_server_authenticate): Reverse
- these changes; the auth server doesn't want them.
-
- * msg.defs (get_init_ports, get_init_ints, get_dtable,
- get_env_variable): Added `dealloc' to variable sized OUT parameters.
-
-Mon Sep 12 19:28:35 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * auth.defs (auth_getids, auth_server_authenticate): Added
- `dealloc' to variable sized OUT parameters.
- * fs.defs (file_getfh, dir_readdir, file_get_translator): Likewise.
- * io.defs (io_read): Likewise.
- * login.defs (login_get_location, login_get_input_devices): Likewise.
- * process.defs (proc_gethostname, proc_getallpids,
- proc_getexecdata, proc_getprocargs, proc_getprocenv,
- proc_getloginpids, proc_getsessionpgids, proc_getsessionpids,
- proc_getpgrppids): Likewise.
- * socket.defs (socket_whatis_address, socket_getopt, socket_recv):
- Likewise.
-
-Sat Sep 10 06:08:19 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * tioctl.defs (sizes_t): Rename to winsize_t; make struct, not array.
- * ioctl_types.h (sizes_t): Removed.
- (winsize_t): New typedef for struct winsize.
- (modes_t, speeds_t, cc_t): Use proper termios.h types.
-
-Tue Aug 30 04:23:25 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * fs.defs (dir_pathtrans): Renamed to dir_lookup; fixed comment.
-
-Fri Aug 26 12:45:51 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * fs.defs (file_set_translator): Separate FLAGS arg into PASSIVE_FLAGS
- and ACTIVE_FLAGS; rename TRANS and EXISTING args to less confusing
- names.
- * hurd_types.h: New flag FS_TRANS_SET.
-
-Thu Aug 25 11:55:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * auth.defs (auth_user_authenticate, auth_server_authenticate):
- Changed rend_int to be a port; mach_port_send_t on both sides.
- * io.defs (io_reauthenticate): Pass a port instead of an int
- for secondary rendezvous.
- * process.defs (proc_reauthenticate): Pass a port instead of an
- int for secondary rendezvous.
-
- * hurd_types.h (retry_type): Removed FS_RETRY_NONE; added
- explicit initializers to keep the values constant.
-
- * hurd_types.h (FSTYPE_EXT2FS): New macroo.
-
- * hurd_types.h (struct procinfo): New member `logincollection'.
-
- * fsys.defs (fsys_syncfs, fsys_mod_readonly): New RPC's.
- * fsys_reply.defs: Added two skips corresponding to new RPC's.
-
-Wed Aug 17 20:03:29 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io.defs (io_select): Make RETURN_PORT arg mach_port_poly_t.
- * msg.defs (io_select_done): Make NOTIFY_PORT arg mach_port_poly_t.
-
-Wed Aug 17 15:23:03 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * term.defs (termctty_open_terminal): New RPC.
-
-Mon Aug 15 11:49:54 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * startup.defs (startup_essential_task): Add sreplyport arg.
- * startup_reply.defs: Add startup_essential_task_reply.
-
-Tue Aug 9 19:43:50 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * core.defs (core_dump_task): Add SIGERROR arg.
-
- * interrupt.defs (INTERRUPT_TIMEOUT): New macro.
- Specify `waittime' with that value.
-
-Mon Aug 8 15:49:30 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
-
-Thu Jul 21 15:44:43 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES, HDRS): Name header files explicitly.
-
-Fri Jul 15 22:53:29 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * subsystems: Rename utmp to login.
- Mark begin and end of spread of subsystems used by ioctls.
- * login.defs: Renamed from utmp.defs; renamed all calls.
-
-Fri Jul 15 18:20:34 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fsys.defs (fsys_startup): Remove DOTDOT_NODE.
- (fsys_getroot): Add arg DOTDOT_NODE.
-
-Thu Jul 14 11:46:56 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * utmp.defs: New file.
-
-Mon Jul 11 20:07:52 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * hurd_types.defs (INTR_ROUTINE): Macro removed.
- (INTR_INTERFACE): New macro.
- * fs.defs: Invoke INTR_INTERFACE. Remove all INTR_ROUTINE uses.
- * io.defs, process.defs, socket.defs: Likewise.
-
-Fri Jul 8 15:53:02 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * hurd_types.h (retry_type): Added new magical types "machtype"
- and "/".
- * fs.defs (dir_pathtrans): Doc fix.
-
- * msg.defs: Doc fix.
-
- * process.defs (proc_wait): Doc fix.
-
- * socket.defs (socket_fabricate_address): Added sockaddr_type
- arg.
-
-Fri Jul 8 15:26:19 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * fs.defs (file_invoke_translator): New RPC.
-
- * hurd_types.defs (INTR_ROUTINE): New macro.
- * socket.defs: Use INTR_ROUTINE for all interruptible RPCs.
- * process.defs: Likewise.
- * fs.defs: Likewise.
- (dir_readdir): Make this interruptible.
-
-Fri Jul 8 14:22:11 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * tioctl.defs: Remove ifdefs that were omitting most of the
- ioctls. Added RPCs for missing codes 118-123. Added
- block of skips between 99 and 100. Added INTR to appropriate
- calls.
-
-Tue Jul 5 14:46:49 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (DIST_FILES): Added subsystems.
-
- * fsys_reply.defs: Added fsys_getroot_reply in its proper place.
-
-Wed Jun 29 13:06:42 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * ifsock.defs (ifsock_setsockaddr, ifsock_assume_responsibility):
- Deleted RPCs.
-
- * msg.defs (set_init_port, set_fd): Change back to using
- mach_port_send_t instead of mach_port_t for PORT arg.
-
-Tue Jun 28 18:39:02 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * msg.defs (get_dtable, set_dtable): Add REFPORT arg.
- (get_fd, set_fd): Add REFPORT and FD args.
- (set_init_port, set_fd): Use mach_port_t instead of
- mach_port_send_t for PORT arg.
- (get_environment): Add dealloc flag to VALUE arg.
-
- * fsys.defs: Add RPT arg to all routines except fsys_init (which
- has an unconditional sreplyport arg).
-
- * hurd_types.defs (sreply_port_t): New type.
- (RPTDECL, RPT, RPTLAST): New macros (moved from io.defs).
- * io.defs (reply_port_t): Type removed.
- (RPTDECL, RPT, RPTLAST): Macros moved to hurd_types.defs.
- * auth.defs (reply_port_t): Type removed.
- (auth_user_authenticate, auth_server_authenticate): Use
- sreply_port_t in place of reply_port_t.
- * fsys.defs (fsys_init): Likewise.
-
- * msg.defs (sig_post): Likewise.
- * process.defs (proc_getmsgport, proc_setmsgport, proc_wait): Likewise.
- * startup.defs (startup_procinit, startup_authinit): Likewise.
-
-Fri Jun 24 03:54:53 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * term.defs (term_become_ctty): Renamed to term_open_ctty.
-
- * process.defs (proc_setprocargs): Renamed to proc_set_arg_locations.
- (proc_get_arg_locations): New rpc.
- * process_reply.defs: Add skip for proc_get_arg_locations.
-
-Thu Jun 23 11:59:49 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * term.defs (term_become_ctty): Delete SIGPT arg.
-
-Wed Jun 22 16:34:51 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * term.defs: Changed NEWTTY arg to be mach_port_send_t.
-
-Thu Jun 16 00:48:45 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * hurd_types.defs (file_changed_type_t, dir_changed_type_t): New types.
- * hurd_types.h (INIT_PORT_LOGINCOLL): Removed.
- (dir_changed_type_t, file_changed_type_t): New typedefs.
-
- * fs.defs (file_check_access): Renamed from file_access, interface
- changed.
-
-Wed Jun 15 21:24:46 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fsys.defs (fsys_getroot): New interface; similar to
- fs.defs:dir_pathtrans. This eliminates the noxious need for
- dir_pathtrans to work on null pathnames for non directories. This
- is the Right Thing.
-
- * fs.defs (file_get_translator_cntl): Return port as
- `mach_port_send_t' not `fsys_t'.
-
-Wed Jun 15 12:13:35 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * fs.defs (file_access): New RPC.
-
-Tue Jun 14 13:57:18 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * hurd_types.h: Reorganized; many comments fixed or improved.
-
- * hurd_types.h (enum verstype): Removed declaration.
- (enum term_bottom_type): New type.
- (TERM_ON_MACHDEV, TERM_ON_HURDIO, TERM_ON_MASTERPTY): Moved
- into enum above.
- (FSTYPE_SOCKET, FSTYPE_MISC): New macros.
-
- * msg.defs (dir_changed, file_changed): New RPCs.
- * fs.defs (dir_notice_changes, file_notice_changes): New RPCs.
- * hurd_types.h (enum dir_changed_type, enum file_changed_type):
- New declarations.
-
- * fs.defs (dir_readdir): Totally new interface.
-
-Mon Jun 13 07:14:23 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * socket.defs: Corrected subsystem to 26000; was 20000, same as fs.
-
-Mon Jun 6 23:07:08 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * ioctl_types.h (modes_t, speeds_t, ccs_t, sizes_t): Make these
- arrays of the appopriate sizes, not pointers.
-
-Sun Jun 5 22:41:08 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * tioctl.defs: Fix subsystem.
-
-Fri May 27 07:53:15 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * exec.defs (exec_exec): Add `servercopy' flag to DTABLE,
- PORTARRAY, and INTARRAY args.
- (exec_startup): Add `dealloc' flag to ARGV, ENVP, PORTARRAY, and
- INTARRAY args.
- (exec_setexecdata): Add `servercopy' flag to PORTS and INTS args.
-
-Wed May 25 13:32:31 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * io_reply.defs (io_readable_reply, io_get_openmodes_reply): Fix
- typos.
-
-Thu May 12 00:43:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * fsys_reply.defs: New file.
- * fsys.defs (reply_port_t): Define type.
- (fsys_init): Add sreplyport arg.
-
- * process.defs (proc_setmsgport): Add sreplyport arg.
- * process_reply.defs: Add proc_setmsgport_reply.
-
- * version.h: Added multiple inclusion protection.
- (struct hurd_version): Fixed `vers' member.
- (hurd_versions): Add braces.
-
-Wed May 11 16:05:43 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * startup.defs (startup_uname, startup_register_version): For
- some bizzaro reason these didn't get removed. Now they are for real.
-
-Tue May 10 18:17:41 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * tioctl.defs, ioctl_types.h: New files.
-
-Mon May 9 14:28:06 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * version.h: New file.
-
- * startup.defs (startup_uname, startup_register_version): Removed
- * process.defs (proc_uname, proc_register_version): New RPCs.
- * process_reply.defs: Added skips corresponding to proc_name
- and proc_register_version.
-
-Wed May 4 01:01:11 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * msg_request.defs: New file.
-
-Sun May 1 17:40:48 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * hurd_types.h (utsname_t): New typedef.
- * hurd_types.defs (utsname_t): Define type for MiG.
- Import <sys/utsname.h>.
-
-Fri Apr 29 16:19:10 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * io.defs (io_prenotify, io_postnotify): File offsets should be
- vm_offset_t.
-
- * io.defs (io_async): NOTIFY_PORT and ASYNC_ID_PORT
- should be mach_port_send_t.
- (io_get_icky_async_id): ICKY_ASYNC_ID_PORT should be
- mach_port_send_t.
- (io_map_cntl): Returned object should be mach_port_send_t.
-
- * io.defs: Added new type reply_port_t; added sreplyport of
- that type to all the stubs when REPLY_PORTS is defined.
-
- * term.defs (term_getctty): CTTY arg should be mach_port_send_t
- for the convenience of servers.
-
- * io.defs (io_readnotify): New RPC.
- * shared.h (use_readnotify_size, readnotify_size): New members.
-
- * socket.defs: Change ports returned from servers to be
- mach_port_send_t for the convenience of servers.
-
- * ifsock.defs (ifsock_assume_responsibility): Just take over the
- bootstrap port directly; this is more reliable anyway.
-
- * fs.defs (file_set_translator): EXISTING arg should be
- mach_port_send_t.
-
- * shared.h (shared_io): Added optimal_transfer_size.
-
- * hurd_types.h (HURD_RELEASE): New macro.
-
- * startup.defs (startup_uname, startup_register_version): New
- RPCs.
-
- * startup.defs (startup_essential_task): require host priv port
- for security.
-
- * exec.defs (exec_exec) : FILE arg should be mach_port_send_t.
-
-Thu Apr 28 22:58:14 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * msg.defs (reply_port_t): Define type.
- (sig_post): Use reply_port_t for sreplyport arg; remove #ifdef.
- * msg_reply.defs (reply_port_t): Define type.
- (sig_post_reply): Use reply_port_t for first arg.
-
-Wed Apr 27 06:39:46 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * msg.defs (sig_post): Put sreplyport arg inside #ifdef MSG_SREPLYPORT.
-
-Thu Apr 21 21:17:37 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * msg.defs (get_init_port, set_init_port, get_fd, set_fd): Make
- PORT arg mach_port_send_t.
- (get_environment, set_environment,
- get_env_variable, set_env_variable): New routines.
-
-Thu Feb 17 17:59:13 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * hurd_types.defs (io_statbuf_t): Change size to 32 ints.
-
-Tue Feb 8 20:53:25 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * msg_reply.defs: Change subsystem to `msg_reply'. MiG-generated
- header files use `#ifndef _subsystem_user_' to protect against
- multiple inclusion, so two headers with the same subsystem conflict.
-
-Thu Feb 3 03:45:18 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * hurd_types.h: Include <mach/task_info.h> and <mach/thread_info.h>
- before using task_basic_info and thread_basic_info in sturct procinfo.
-
-Mon Jan 24 17:33:00 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * msg_reply.defs: New file.
-
-Tue Dec 21 01:11:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * socket.defs: Fix typos.
-
-Mon Dec 6 22:52:00 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Made snapshot.
-
-Mon Dec 6 22:36:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * hurd_types.defs (flock_t): Defined.
- * hurd_types.h (flock_t): Added typedef.
-
-Mon Dec 6 19:28:27 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * process.defs (proc_get_collports): Designate as INTR, also
- return the pids.
-
-Wed Dec 1 21:41:06 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * hurd_types.h: Remove deprecated information:
- INBAND_MAX_DATA, FS_LOOKUP_* bits.
- Added PI_ZOMBIE.
-
- * process.defs (proc_getmsgport): Now is INTR.
-
- * io.defs (io_get_conch, io_release_conch, io_eofnotify,
- io_prenotify, io_postnotify, io_readsleep, io_sigio):
- Remove cntl argument.
-
-Tue Nov 23 12:18:21 1993 Michael I. Bushnell (mib at ernst.gnu.ai.mit.edu)
-
- * fsys.defs (fsys_startup): control_port is now mach_port_send_t.
-
- * io.defs (io_map): remove `xx' argument.
-
- * process.defs (proc_handle_exceptions): forwardport is now
- mach_port_send_t.
-
- * auth.defs, auth_reply.defs: Removed auth_combine and extended
- auth_makeauth to take multiple auth ports.
-
- * shared.h, io.defs: Changed `it' terminology to `conch'.
-
-Mon Nov 22 22:58:59 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * io.defs: Changed io_map to use mach_port_send_t.
-
- * auth.defs: Changed auth_user_authenticate arg newport to be
- mach_port_send_t.
-
-
diff --git a/hurd/Makefile b/hurd/Makefile
index 37ccddb4..66a6d287 100644
--- a/hurd/Makefile
+++ b/hurd/Makefile
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+# Copyright (C) 1993,94,95,96,99,2002 Free Software Foundation
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -19,9 +18,9 @@ dir := hurd
makemode := misc
hdrs = $(wildcard $(srcdir)/*.defs $(srcdir)/*.h)
-DIST_FILES = subsystems $(notdir $(hdrs))
+DIST_FILES = subsystems $(notdir $(hdrs)) ioctl-tmpl.sym ioctl.awk gensym.awk
-INSTHDRS = hurd_types.h ioctl_types.h paths.h shared.h version.h \
+INSTHDRS = hurd_types.h version.h ioctl_types.h paths.h shared.h console.h \
$(notdir $(wildcard $(srcdir)/*.defs))
include ../Makeconf
@@ -32,3 +31,53 @@ install-headers install: $(includedir)/hurd \
$(includedir)/hurd/%: $(srcdir)/%; $(INSTALL_DATA) $< $@
$(includedir)/hurd:;mkdir -p $@
+
+%.msgids: $(srcdir)/%.defs
+ if grep -q '^subsystem' $<; \
+ then $(CPP) $(CPPFLAGS) $< | $(MIGCOM) -n -list $@; \
+ else > $@; fi
+hurd.msgids: $(patsubst %.defs,%.msgids,$(filter %.defs,$(INSTHDRS)))
+ cat $^ > $@
+
+#
+# The following rules assist in creating an `Xioctl.defs' file
+# to define RPCs that are sent primarily by ioctl commands.
+# To use them, write a file `Xioctl-headers.h', e.g. for `mioctl-headers.h':
+# #include <sys/mtio.h>
+# with an #include for each header that defines ioctl request macros
+# using _IO('X') et al. Then `make Xioctl-proto.defs' will create
+# a prototype file for you to hand-edit into `Xioctl.defs'.
+
+# Building foo.h from foo.sym:
+%.symc: %.sym
+ $(AWK) -f $(srcdir)/gensym.awk $< >$*.symc
+%.symc.o: %.symc
+ $(CC) -S $(CPPFLAGS) $(CFLAGS) $(CPPFLAGS-$@) -x c -o $@ $<
+%.h: %.symc.o
+ sed <$< -e 's/^[^*].*$$//' | \
+ sed -e 's/^[*]/#define/' -e 's/mAgIc[^-0-9]*//' -e '/^ *$$/d' >$@
+
+%-ioctls.sym: tmpl-ioctls.sym
+ sed 's|HEADER|<$(subst +,/,$*)>|' $< > $@
+
+cpp = $(CC) $(CPPFLAGS) $(CFLAGS) $(CPPFLAGS-$@) -E -x c
+
+%ioctl-requests.list: %ioctl-headers.h
+ $(cpp) $< | sed -n 's/^#.*"\([^"]*\)".*$$/\1/p' | sort | uniq | \
+ while read f; do \
+ sed -n 's/^[ ]*#[ ]*define[ ]*\([A-Z0-9_]*\)[^A-Z0-9_][^A-Z0-9_]*_IO.*'\'$*\'.*$$'/\1/p' $$f; \
+ done | sort | uniq > $@
+
+%ioctl.defs: %ioctl.sym
+
+%ioctl-values.sym: %ioctl-headers.h %ioctl-requests.list ioctl-tmpl.sym
+ (sed 's%@HEADER_LIST@%$<%;s/@GROUP@/$*/g' < $(filter %.sym,$^); \
+ while read r; do \
+ for x in CMD SUBID INOUT TYPE \
+ TYPE0 TYPE1 TYPE2 COUNT0 COUNT1 COUNT2; do \
+ echo "expr $${x}($${r}) $${r}_$${x}"; \
+ done; \
+ done < $(filter %.list,$^)) > $@
+
+%ioctl-proto.defs: %ioctl-values.h ioctl.awk
+ sed 's/^#define//;s/_/ /g' $< | $(AWK) -f $(filter %.awk,$^) > $@
diff --git a/hurd/auth.defs b/hurd/auth.defs
index ad80cfb5..ebb682fd 100644
--- a/hurd/auth.defs
+++ b/hurd/auth.defs
@@ -1,5 +1,5 @@
/* Definitions for the authentication server
- Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1991,92,93,94,96,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -59,6 +59,7 @@ routine auth_makeauth (
the server. */
routine auth_user_authenticate (
handle: auth_t;
+ sreplyport reply: mach_port_poly_t;
rendezvous: mach_port_send_t;
out newport: mach_port_send_t);
@@ -76,5 +77,3 @@ routine auth_server_authenticate (
out auids: idarray_t;
out egids: idarray_t;
out agids: idarray_t);
-
-
diff --git a/hurd/auth_reply.defs b/hurd/auth_reply.defs
index 10530fa7..63dc7dca 100644
--- a/hurd/auth_reply.defs
+++ b/hurd/auth_reply.defs
@@ -1,5 +1,5 @@
/* Reply-only side of auth interface
- Copyright (C) 1991, 1993, 1994 Free Software Foundation
+ Copyright (C) 1991,93,94,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -31,14 +31,13 @@ skip; /* auth_makeauth */
simpleroutine auth_user_authenticate_reply (
reply_port: reply_port_t;
- in return_code: kern_return_t;
+ RETURN_CODE_ARG;
in newhandle: mach_port_send_t);
simpleroutine auth_server_authenticate_reply (
reply_port: reply_port_t;
- in return_code: kern_return_t;
+ RETURN_CODE_ARG;
in gen_uids: idarray_t;
in aux_uids: idarray_t;
in gen_gids: idarray_t;
in aux_gids: idarray_t);
-
diff --git a/hurd/auth_request.defs b/hurd/auth_request.defs
new file mode 100644
index 00000000..a1f9e271
--- /dev/null
+++ b/hurd/auth_request.defs
@@ -0,0 +1,36 @@
+/* Request-only side of auth interface
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+subsystem auth_reply 25000; /* must match auth.defs */
+
+#include <hurd/hurd_types.defs>
+
+skip; /* auth_getids */
+skip; /* auth_makeauth */
+
+simpleroutine auth_user_authenticate_request (
+ handle: auth_t;
+ ureplyport reply: mach_port_poly_t;
+ rendezvous: mach_port_send_t);
+
+simpleroutine auth_server_authenticate_request (
+ handle: auth_t;
+ ureplyport reply: mach_port_poly_t;
+ rendezvous: mach_port_send_t;
+ newport: mach_port_poly_t);
diff --git a/hurd/configure b/hurd/configure
new file mode 100755
index 00000000..62baeecd
--- /dev/null
+++ b/hurd/configure
@@ -0,0 +1,2182 @@
+#! /bin/sh
+# From configure.ac Id: configure.ac,v 1.2 2003/02/16 00:08:08 roland Exp .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.57 for GNU Hurd bootstrap installation of header files.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME='GNU Hurd'
+PACKAGE_TARNAME='hurd'
+PACKAGE_VERSION='bootstrap installation of header files'
+PACKAGE_STRING='GNU Hurd bootstrap installation of header files'
+PACKAGE_BUGREPORT=''
+
+ac_unique_file="hurd_types.h"
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures GNU Hurd bootstrap installation of header files to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of GNU Hurd bootstrap installation of header files:";;
+ esac
+ cat <<\_ACEOF
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+GNU Hurd configure bootstrap installation of header files
+generated by GNU Autoconf 2.57
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by GNU Hurd $as_me bootstrap installation of header files, which was
+generated by GNU Autoconf 2.57. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core core.* *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in .. $srcdir/..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in .. $srcdir/.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in .. $srcdir/.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+ ac_config_files="$ac_config_files install-headers"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then we branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\_ACEOF
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
+t quote
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+_ACEOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
+
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by GNU Hurd $as_me bootstrap installation of header files, which was
+generated by GNU Autoconf 2.57. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+GNU Hurd config.status bootstrap installation of header files
+configured by $0, generated by GNU Autoconf 2.57,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "install-headers" ) CONFIG_FILES="$CONFIG_FILES install-headers" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+ # Run the commands associated with the file.
+ case $ac_file in
+ install-headers ) chmod +x install-headers ;;
+ esac
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/hurd/configure.ac b/hurd/configure.ac
new file mode 100644
index 00000000..0e015ba0
--- /dev/null
+++ b/hurd/configure.ac
@@ -0,0 +1,11 @@
+dnl Run through autoconf to create a configure script for install-headers.
+AC_REVISION([$Id: configure.ac,v 1.2 2003/02/16 00:08:08 roland Exp $])
+AC_PREREQ(2.53)dnl dnl Minimum Autoconf version required.
+AC_INIT([GNU Hurd], [bootstrap installation of header files])
+AC_CONFIG_SRCDIR([hurd_types.h])
+AC_CONFIG_AUX_DIR([..])
+
+AC_PROG_INSTALL
+
+AC_CONFIG_FILES([install-headers], [chmod +x install-headers])
+AC_OUTPUT
diff --git a/hurd/console.h b/hurd/console.h
new file mode 100644
index 00000000..baf03942
--- /dev/null
+++ b/hurd/console.h
@@ -0,0 +1,309 @@
+/* console.h -- Public interface to the console server.
+ Copyright (C) 2002,10 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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 */
+
+#ifndef _HURD_CONSOLE_H
+#define _HURD_CONSOLE_H
+
+#include <stdint.h>
+#include <wchar.h>
+
+typedef enum
+ {
+ CONS_COLOR_BLACK = 0, CONS_COLOR_RED, CONS_COLOR_GREEN, CONS_COLOR_YELLOW,
+ CONS_COLOR_BLUE, CONS_COLOR_MAGENTA, CONS_COLOR_CYAN, CONS_COLOR_WHITE
+ } cons_color_t;
+#define CONS_COLOR_MAX (CONS_COLOR_WHITE)
+
+typedef struct
+{
+ /* The intensity is traditionally a color attribute. */
+#define CONS_ATTR_INTENSITY_NORMAL 000000000000
+#define CONS_ATTR_INTENSITY_BOLD 000000000001
+#define CONS_ATTR_INTENSITY_DIM 000000000002
+ uint32_t intensity : 2;
+
+ uint32_t underlined : 1;
+ uint32_t blinking : 1;
+ uint32_t reversed : 1;
+ uint32_t concealed : 1;
+
+ /* Color attributes. */
+ uint32_t bgcol : 3;
+ uint32_t fgcol : 3;
+
+ /* Font attributes. */
+ uint32_t italic : 1;
+ uint32_t bold : 1;
+} conchar_attr_t;
+
+/* We support double-width characters by using an extra bit to identify the
+ continuation in the character matrix. The constants below document our
+ usage of wchar_t. */
+#define CONS_WCHAR_MASK ((wchar_t) 0x401fffff)
+#define CONS_WCHAR_CONTINUED ((wchar_t) 0x40000000)
+
+typedef struct
+{
+ wchar_t chr;
+ conchar_attr_t attr;
+} conchar_t;
+
+typedef union
+{
+ struct
+ {
+ /* Only the first 31 bits are available (see WHAT.not_matrix). */
+ uint32_t start;
+ uint32_t end;
+ } matrix;
+ struct
+ {
+ uint32_t cursor_pos : 1;
+ uint32_t cursor_status : 1;
+ uint32_t screen_cur_line : 1;
+ uint32_t screen_scr_lines : 1;
+ uint32_t bell_audible : 1;
+ uint32_t bell_visible : 1;
+ uint32_t flags : 1;
+ uint32_t _unused : 24;
+ uint32_t not_matrix : 1;
+ /* Here are 32 more unused bits. */
+ } what;
+} cons_change_t;
+
+struct cons_display
+{
+#define CONS_MAGIC 0x48555244 /* Hex for "HURD". */
+ uint32_t magic; /* CONS_MAGIC, use to detect
+ endianess. */
+#define CONS_VERSION_MAJ 0x0
+#define CONS_VERSION_MAJ_SHIFT 16
+#define CONS_VERSION_AGE 0x0
+ uint32_t version; /* Version of interface. Lower 16
+ bits define the age, upper 16 bits
+ the major version. */
+
+
+ /* Various one bit flags that don't deserve their own field. */
+
+ /* The output is stopped. The client can display the status of this
+ flag, but should not otherwise interpret it. */
+#define CONS_FLAGS_SCROLL_LOCK 0x00000001
+
+ /* Tracking mouse events is requested. See CONS_MOUSE_* macros
+ further down. */
+#define CONS_FLAGS_TRACK_MOUSE 0x00000002
+
+ uint32_t flags;
+
+
+ struct
+ {
+ uint32_t width; /* Width of screen matrix. */
+ uint32_t lines; /* Length of whole matrix. */
+ uint32_t cur_line; /* Virtual start of visible area. Needs to be
+ taken module LINES to get the real start of
+ visible area in the matrix. This is only
+ ever increased by the server, so clients
+ can optimize scrolling. */
+ uint32_t scr_lines; /* Number of lines in scrollback buffer
+ preceding CUR_LINE. */
+ uint32_t height; /* Number of lines in visible area following
+ (and including) CUR_LINE. */
+ uint32_t matrix; /* Index (in uint32_t) of the beginning of
+ screen matrix in this structure. */
+ } screen;
+
+ struct
+ {
+ uint32_t col; /* Current column (x-position) of cursor. */
+ uint32_t row; /* Current row (y-position) of cursor. */
+
+#define CONS_CURSOR_INVISIBLE 0
+#define CONS_CURSOR_NORMAL 1
+#define CONS_CURSOR_VERY_VISIBLE 2
+ uint32_t status; /* Visibility status of cursor. */
+ } cursor;
+
+ struct
+ {
+ uint32_t audible; /* Audible bell. */
+ uint32_t visible; /* Visible bell. */
+ } bell;
+
+ struct
+ {
+ uint32_t buffer; /* Index (in uint32_t) of the beginning of the
+ changes buffer in this structure. */
+ uint32_t length; /* Length of buffer. */
+ uint32_t written; /* Number of records written by server. */
+
+#define _CONS_CHANGES_LENGTH 512
+ cons_change_t _buffer[_CONS_CHANGES_LENGTH];
+ } changes;
+
+ /* Don't use this, use ((wchar_t *) cons_display +
+ cons_display.screen.matrix) instead. This will make your client
+ upward compatible with future versions of this interface. */
+ conchar_t _matrix[0];
+};
+
+
+/* The console server will use the following UCS-4 characters for the
+ specified terminal graphic characters. If the display driver is
+ UCS-4 capable, it can print them without interpretation. */
+
+/* ACS_BLOCK maps to FULL BLOCK. */
+#define CONS_CHAR_BLOCK ((wchar_t) 0x2588)
+/* ACS_DIAMOND maps to BLACK DIAMOND. */
+#define CONS_CHAR_DIAMOND ((wchar_t) 0x25c6)
+/* ACS_CKBOARD maps to MEDIUM SHADE. */
+#define CONS_CHAR_CKBOARD ((wchar_t) 0x2592)
+/* ACS_BOARD maps to LIGHT SHADE. */
+#define CONS_CHAR_BOARD ((wchar_t) 0x2591)
+/* ACS_BULLET maps to BULLET (Linux maps it to MIDDLE DOT 0x00b7). */
+#define CONS_CHAR_BULLET ((wchar_t) 0x2022)
+/* ACS_STERLING maps to POUND STERLING. */
+#define CONS_CHAR_STERLING ((wchar_t) 0x00a3)
+/* ACS_DEGREE maps to DEGREE SIGN. */
+#define CONS_CHAR_DEGREE ((wchar_t) 0x00b0)
+/* ACS_PLMINUS maps to PLUS-MINUS SIGN. */
+#define CONS_CHAR_PLMINUS ((wchar_t) 0x00b1)
+/* ACS_PI maps to GREEK SMALL LETTER PI. */
+#define CONS_CHAR_PI ((wchar_t) 0x03c0)
+/* ACS_LANTERN maps to BLACK HOURGLASS. XXX Is this appropriate? */
+#define CONS_CHAR_LANTERN ((wchar_t) 0x29d7)
+
+/* ACS_RARROW maps to RIGHTWARDS ARROW. */
+#define CONS_CHAR_RARROW ((wchar_t) 0x2192)
+/* ACS_LARROW maps to LEFTWARDS ARROW. */
+#define CONS_CHAR_LARROW ((wchar_t) 0x2190)
+/* ACS_UARROW maps to UPWARDS ARROW. */
+#define CONS_CHAR_UARROW ((wchar_t) 0x2191)
+/* ACS_DARROW maps to DOWNWARDS ARROW. */
+#define CONS_CHAR_DARROW ((wchar_t) 0x2193)
+
+/* ACS_LRCORNER maps to BOX DRAWINGS LIGHT UP AND LEFT. */
+#define CONS_CHAR_LRCORNER ((wchar_t) 0x2518)
+/* ACS_URCORNER maps to BOX DRAWINGS LIGHT DOWN AND LEFT. */
+#define CONS_CHAR_URCORNER ((wchar_t) 0x2510)
+/* ACS_ULCORNER maps to BOX DRAWINGS LIGHT DOWN AND RIGHT. */
+#define CONS_CHAR_ULCORNER ((wchar_t) 0x250c)
+/* ACS_LLCORNER maps to BOX DRAWINGS LIGHT UP AND RIGHT. */
+#define CONS_CHAR_LLCORNER ((wchar_t) 0x2514)
+/* ACS_PLUS maps to BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL. */
+#define CONS_CHAR_PLUS ((wchar_t) 0x253c)
+/* ACS_HLINE maps to BOX DRAWINGS LIGHT HORIZONTAL. */
+#define CONS_CHAR_HLINE ((wchar_t) 0x2500)
+/* ACS_LTEE maps to BOX DRAWINGS LIGHT VERTICAL AND RIGHT. */
+#define CONS_CHAR_LTEE ((wchar_t) 0x251c)
+/* ACS_RTEE maps to BOX DRAWINGS LIGHT VERTICAL AND LEFT. */
+#define CONS_CHAR_RTEE ((wchar_t) 0x2524)
+/* ACS_BTEE maps to BOX DRAWINGS LIGHT UP AND HORIZONTAL. */
+#define CONS_CHAR_BTEE ((wchar_t) 0x2534)
+/* ACS_TTEE maps to BOX DRAWINGS LIGHT DOWN AND HORIZONTAL. */
+#define CONS_CHAR_TTEE ((wchar_t) 0x252c)
+/* ACS_VLINE maps to BOX DRAWINGS LIGHT VERTICAL. */
+#define CONS_CHAR_VLINE ((wchar_t) 0x2502)
+
+/* ACS_S1 maps to HORIZONTAL SCAN LINE-1. */
+#define CONS_CHAR_S1 ((wchar_t) 0x23ba)
+/* ACS_S3 maps to HORIZONTAL SCAN LINE-3. */
+#define CONS_CHAR_S3 ((wchar_t) 0x23bb)
+/* ACS_S7 maps to HORIZONTAL SCAN LINE-1. */
+#define CONS_CHAR_S7 ((wchar_t) 0x23bc)
+/* ACS_S9 maps to HORIZONTAL SCAN LINE-1. */
+#define CONS_CHAR_S9 ((wchar_t) 0x23bd)
+
+/* ACS_NEQUAL maps to NOT EQUAL TO. */
+#define CONS_CHAR_NEQUAL ((wchar_t) 0x2260)
+/* ACS_LEQUAL maps to LESS-THAN OR EQUAL TO. */
+#define CONS_CHAR_LEQUAL ((wchar_t) 0x2264)
+/* ACS_GEQUAL maps to GREATER-THAN OR EQUAL TO. */
+#define CONS_CHAR_GEQUAL ((wchar_t) 0x2265)
+
+
+
+/* The input driver should emit these escape sequences for special
+ keys which don't represent characters in UTF-8. */
+#define CONS_KEY_UP "\eOA" /* Cursor up. */
+#define CONS_KEY_DOWN "\eOB" /* Cursor down. */
+#define CONS_KEY_RIGHT "\eOC" /* Cursor right. */
+#define CONS_KEY_LEFT "\eOD" /* Cursor left. */
+#define CONS_KEY_BACKSPACE "\177" /* Backspace key. */
+#define CONS_KEY_F1 "\eOP" /* Function key 1. */
+#define CONS_KEY_F2 "\eOQ" /* Function key 2. */
+#define CONS_KEY_F3 "\eOR" /* Function key 3. */
+#define CONS_KEY_F4 "\eOS" /* Function key 4. */
+#define CONS_KEY_F5 "\e[15~" /* Function key 5. */
+#define CONS_KEY_F6 "\e[17~" /* Function key 6. */
+#define CONS_KEY_F7 "\e[18~" /* Function key 7. */
+#define CONS_KEY_F8 "\e[19~" /* Function key 8. */
+#define CONS_KEY_F9 "\e[20~" /* Function key 9. */
+#define CONS_KEY_F10 "\e[21~" /* Function key 10. */
+#define CONS_KEY_F11 "\e[23~" /* Function key 11. */
+#define CONS_KEY_F12 "\e[24~" /* Function key 12. */
+#define CONS_KEY_F13 "\e[25~" /* Function key 13. */
+#define CONS_KEY_F14 "\e[26~" /* Function key 14. */
+#define CONS_KEY_F15 "\e[28~" /* Function key 15. */
+#define CONS_KEY_F16 "\e[29~" /* Function key 16. */
+#define CONS_KEY_F17 "\e[31~" /* Function key 17. */
+#define CONS_KEY_F18 "\e[32~" /* Function key 18. */
+#define CONS_KEY_F19 "\e[33~" /* Function key 19. */
+#define CONS_KEY_F20 "\e[34~" /* Function key 20. */
+#define CONS_KEY_HOME "\e[1~" /* Home key. */
+#define CONS_KEY_IC "\e[2~" /* Insert char mode. */
+#define CONS_KEY_DC "\e[3~" /* Delete character. */
+#define CONS_KEY_END "\e[4~" /* End key. */
+#define CONS_KEY_PPAGE "\e[5~" /* Previous page. */
+#define CONS_KEY_NPAGE "\e[6~" /* Next page. */
+#define CONS_KEY_BTAB "\e[Z" /* Back tab key. */
+#define CONS_KEY_B2 "\e[G" /* Center of keypad. */
+
+/* Mouse support is compatible to xterm's mouse tracking feature. */
+
+#define CONS_MOUSE_BUTTON_MASK 0x03
+#define CONS_MOUSE_BUTTON1 0x00
+#define CONS_MOUSE_BUTTON2 0x01
+#define CONS_MOUSE_BUTTON3 0x02
+#define CONS_MOUSE_RELEASE 0x03
+#define CONS_MOUSE_MOD_MASK 0x1c
+#define CONS_MOUSE_MOD_SHIFT 0x04
+#define CONS_MOUSE_MOD_META 0x08
+#define CONS_MOUSE_MOD_CTRL 0x10
+
+/* Screen positions are offset by this value. */
+#define CONS_MOUSE_OFFSET_BASE 0x20
+
+#define CONS_MOUSE_EVENT_LENGTH 6
+#define CONS_MOUSE_EVENT_PREFIX "\e[M"
+
+/* This macro populates STR with the mouse event EVENT at position X
+ and Y, and returns 1 if successul and 0 if X or Y is out of
+ range. X and Y start from 0. */
+#define CONS_MOUSE_EVENT(str,event,x,y) \
+ (((int)(x) < 0 || (int)(x) + CONS_MOUSE_OFFSET_BASE > 255 \
+ || (int)(y) < 0 || (int)(y) + CONS_MOUSE_OFFSET_BASE > 255) ? 0 \
+ : ((*(str) = CONS_MOUSE_EVENT_PREFIX[0]), \
+ (*((str) + 1) = CONS_MOUSE_EVENT_PREFIX[1]), \
+ (*((str) + 2) = CONS_MOUSE_EVENT_PREFIX[2]), \
+ (*((str) + 3) = (char)((int)(event) + CONS_MOUSE_OFFSET_BASE)), \
+ (*((str) + 4) = (char)((int)(x) + CONS_MOUSE_OFFSET_BASE)), \
+ (*((str) + 5) = (char)((int)(y) + CONS_MOUSE_OFFSET_BASE), 1)))
+
+#endif /* _HURD_CONSOLE_H */
diff --git a/hurd/crash_reply.defs b/hurd/crash_reply.defs
index 6231650a..ec6ddcd6 100644
--- a/hurd/crash_reply.defs
+++ b/hurd/crash_reply.defs
@@ -1,5 +1,5 @@
/* MiG protocol for handling program crashes, reply half.
- Copyright (C) 1992, 1994, 1995 Free Software Foundation
+ Copyright (C) 1992,94,95,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -27,4 +27,4 @@ subsystem crash_reply 32100; /* must match crash + 100 */
simpleroutine crash_dump_task_reply (
ureply_port: mach_port_poly_t;
- result: int);
+ RETURN_CODE_ARG);
diff --git a/hurd/default_pager.defs b/hurd/default_pager.defs
new file mode 100644
index 00000000..8ad82dcc
--- /dev/null
+++ b/hurd/default_pager.defs
@@ -0,0 +1,95 @@
+/* -*- C -*-
+ Version of <mach/default_pager.defs> modified for Hurd implementation.
+*/
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+subsystem default_pager 2275;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+#include <mach/default_pager_types.defs>
+#include <device/device_types.defs>
+
+import <hurd/default_pager_types.h>; /* XXX */
+
+routine default_pager_object_create(
+ default_pager : mach_port_t;
+ out memory_object : memory_object_t =
+ MACH_MSG_TYPE_MAKE_SEND;
+ object_size : vm_size_t);
+
+routine default_pager_info(
+ default_pager : mach_port_t;
+ out info : default_pager_info_t);
+
+routine default_pager_objects(
+ default_pager : mach_port_t;
+ out objects : default_pager_object_array_t,
+ CountInOut, Dealloc;
+ out ports : mach_port_array_t =
+ array[] of mach_port_move_send_t,
+ CountInOut, Dealloc);
+
+routine default_pager_object_pages(
+ default_pager : mach_port_t;
+ memory_object : memory_object_name_t;
+ out pages : default_pager_page_array_t,
+ CountInOut, Dealloc);
+
+/* This is the original Mach call, now deprecated in favor
+ of default_pager_paging_storage. */
+routine default_pager_paging_file(
+ default_pager : mach_port_t;
+ master_device_port : mach_port_t;
+ filename : default_pager_filename_t;
+ add : boolean_t);
+
+skip; /* default_pager_register_fileserver */
+
+/* Add or remove an area of paging storage, which is a subset of the
+ Mach device for which device_open returned DEVICE_PORT. The area
+ consists of the concatenation of contiguous regions described by
+ RUNS. Each even-numbered element of RUNS gives the starting record
+ number of a region whose length is given by the next odd-numbered
+ element. NAME is used in any diagnostics the default pager prints
+ about device errors when paging. When removing a paging area, NAME
+ and RUNS must match exactly. */
+routine default_pager_paging_storage(
+ default_pager : mach_port_t;
+ device_port : mach_port_t;
+ runs : recnum_array_t =
+ array[] of recnum_t;
+ name : default_pager_filename_t;
+ add : boolean_t);
+
+/* This call is made on a memory object returned by default_pager_object_create
+ to fix the object's maximum size. Any references to pages beyond the limit
+ will fail. */
+routine default_pager_object_set_size(
+ memory_object : mach_port_t;
+ msgseqno seqno : mach_port_seqno_t;
+ object_size_limit : vm_size_t);
diff --git a/hurd/default_pager_reply.defs b/hurd/default_pager_reply.defs
new file mode 100644
index 00000000..0f9ff86b
--- /dev/null
+++ b/hurd/default_pager_reply.defs
@@ -0,0 +1,17 @@
+/* Reply half of default_pager.defs. */
+
+subsystem default_pager_reply 2375; /* 2275 + 100 */
+
+#include <hurd/hurd_types.defs>
+
+skip; /* default_pager_object_create */
+skip; /* default_pager_info */
+skip; /* default_pager_objects */
+skip; /* default_pager_object_pages */
+skip; /* default_pager_paging_file */
+skip; /* default_pager_register_fileserver */
+skip; /* default_pager_paging_storage */
+
+simpleroutine default_pager_object_set_size_reply(
+ reply_port: mach_port_send_once_t;
+ RETURN_CODE_ARG);
diff --git a/libdiskfs/init-loop.c b/hurd/default_pager_types.h
index d0aa0413..7cd14a3d 100644
--- a/libdiskfs/init-loop.c
+++ b/hurd/default_pager_types.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/* C declarations for Hurd default pager interface
+ Copyright (C) 2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -17,12 +17,12 @@ You should have received a copy of the GNU General Public License
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* Written by Michael I. Bushnell. */
+#ifndef _DEFAULT_PAGER_TYPES_H
+#define _DEFAULT_PAGER_TYPES_H
-#include "priv.h"
+#include <mach/std_types.h> /* For mach_port_t et al. */
+#include <device/device_types.h> /* For recnum_t. */
-void
-diskfs_main_request_loop (void)
-{
- ports_manage_port_operations_multithread ();
-}
+typedef recnum_t *recnum_array_t;
+
+#endif
diff --git a/hurd/exec.defs b/hurd/exec.defs
index 8c9b1491..2888fb1e 100644
--- a/hurd/exec.defs
+++ b/hurd/exec.defs
@@ -1,5 +1,5 @@
/* Interface definitions for the exec servers.
- Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991,92,93,94,95,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -34,11 +34,11 @@ routine exec_exec (
file: mach_port_send_t;
oldtask: task_t;
flags: int;
- argv: data_t, servercopy;
- envp: data_t, servercopy;
- dtable: portarray_t, servercopy;
- portarray: portarray_t, servercopy;
- intarray: intarray_t, servercopy;
+ argv: data_t SCP;
+ envp: data_t SCP;
+ dtable: portarray_t SCP;
+ portarray: portarray_t SCP;
+ intarray: intarray_t SCP;
deallocnames: mach_port_name_array_t;
destroynames: mach_port_name_array_t);
@@ -53,5 +53,5 @@ routine exec_init (
simpleroutine exec_setexecdata (
execserver: file_t;
- ports: portarray_t, servercopy;
- ints: intarray_t, servercopy);
+ ports: portarray_t SCP;
+ ints: intarray_t SCP);
diff --git a/hurd/fs.defs b/hurd/fs.defs
index b7dae433..52d83bd5 100644
--- a/hurd/fs.defs
+++ b/hurd/fs.defs
@@ -1,5 +1,5 @@
-/* Definitions for the filesystem interface.
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/* Definitions for the filesystem interface.
+ Copyright (C) 1994,95,96,97,98,99,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -94,6 +94,8 @@ routine file_chflags (
new_flags: int);
/* Change access and modify times */
+/* If the microseconds value is -1 (all bits on) then the time should be
+ set to the current time and the remainder of the time_value_t ignored. */
routine file_utimes (
utimes_file: file_t;
RPT
@@ -106,7 +108,7 @@ routine file_utimes (
routine file_set_size (
trunc_file: file_t;
RPT
- new_size: off_t);
+ new_size: loff_t);
/* Apply/manipulate advisory lock */
routine file_lock (
@@ -136,7 +138,7 @@ routine file_check_access (
out allowed: int);
/* Notice changes to file FILE. Send notification messages (see
- msg.defs) to PORT as they occur. */
+ fs_notify.defs) to PORT as they occur. */
routine file_notice_changes (
file: file_t;
RPT
@@ -175,10 +177,10 @@ routine file_syncfs (
routine file_get_storage_info (
file: file_t;
RPT
- out ports: portarray_t;
- out ints: intarray_t;
- out offsets: off_array_t;
- out data: data_t);
+ out ports: portarray_t, dealloc;
+ out ints: intarray_t, dealloc;
+ out offsets: off_array_t, dealloc;
+ out data: data_t, dealloc);
/* Return the node for hard links to this potentially translated file.
This returns a potentially unauthenticated node. */
@@ -198,13 +200,16 @@ routine file_getfh (
/* Operations supported on directories */
/* Translate a file name, following all symlinks. Upon return, if DO_RETRY
- is FS_RETRY_MAGICAL then RETRY_NAME specifies what to do, the list of
- possibilities is documented in <hurd/hurd_types.h>; if FS_RETRY_REAUTH,
- then RESULT should be reauthenticated before being used. If RETRY_NAME
- is the empty string, no further dir_lookup calls are required; RESULT,
- or the reauthenticated port, is the port to use. Otherwise the
- dir_lookup call should be repeated, sent to RESULT (or the
- reauthenticated port) with RETRY_NAME passed for FILE_NAME. */
+ is FS_RETRY_MAGICAL then RETRY_NAME specifies what to do, the list
+ of possibilities is documented in <hurd/hurd_types.h>; if
+ FS_RETRY_REAUTH, then RESULT should be reauthenticated before being
+ used. If RETRY_NAME is the empty string and the retry type is
+ FS_RETRY_NORMAL, then no further dir_lookup calls are required;
+ RESULT is the port to use. Otherwise the dir_lookup call should be
+ repeated, sent to RESULT (or the reauthenticated port) with
+ RETRY_NAME passed for FILE_NAME. This call is required to be
+ supported by all files (even non-directories) if the filename is
+ null, and should function in that case as a re-open of the file. */
routine dir_lookup (
start_dir: file_t;
RPT
@@ -226,7 +231,7 @@ routine dir_lookup (
routine dir_readdir (
dir: file_t;
RPT
- out data: data_t, dealloc;
+ out data: data_t, dealloc[];
entry: int;
nentries: int;
bufsiz: vm_size_t;
@@ -250,13 +255,13 @@ routine dir_unlink (
directory: file_t;
RPT
name: string_t);
-
+
/* Create a hard link.
If DIR and FILE are not implemented by the same filesystem,
EXDEV should be returned. If the two filesystems, however can
inter-operate and guarantee the appropriate Posix semantics, they can
- communicate by a private protocol and allow hard links between them.
+ communicate by a private protocol and allow hard links between them.
If EXCL is set, then fail if NAME already exists in DIR. */
routine dir_link (
dir: file_t;
@@ -266,7 +271,7 @@ routine dir_link (
excl: int);
/* Rename file -- comments similar to those for dir_link apply here
- about EXDEV. If EXCL is set, then fail if NEWNAME already exists in
+ about EXDEV. If EXCL is set, then fail if NEWNAME already exists in
NEWDIRECTORY. */
routine dir_rename (
olddirectory: file_t;
@@ -279,7 +284,7 @@ routine dir_rename (
/* Create a new file without linking it into the filesystem. You
still must have write permission on the specified directory, even
though it will not actually be written. Return in *newnode a port
- to the file. Flags are the same as for dir_pathtrans, but
+ to the file. Flags are the same as for dir_lookup, but
O_CREAT and O_TRUNC are assumed even if not specified. */
routine dir_mkfile (
directory: file_t;
@@ -289,7 +294,7 @@ routine dir_mkfile (
out newnode: mach_port_send_t);
/* Notice changes to directory DIR. Send directory change notifications
- (see msg.defs) to PORT as they occur. */
+ (see fs_notify.defs) to PORT as they occur. */
routine dir_notice_changes (
directory: file_t;
RPT
@@ -298,12 +303,12 @@ routine dir_notice_changes (
/* To get or set the translator currently running on a file, use
file_set_translator, file_get_translator, or
file_get_translator_cntl on a port gotten with the
- FS_LOOKUP_NOTRANS flag to dir_pathtrans. You can send these RPCs
+ FS_LOOKUP_NOTRANS flag to dir_lookup. You can send these RPCs
to a port to a translated node (looked up without
FS_LOOKUP_NOTRANS) to stack a new translator on top of the existing
one. */
-/* Set a translator for future lookups to a file.
+/* Set a translator for future lookups to a file.
PASSIVE is the passive translator;
ACTIVE is the active translator.
@@ -338,4 +343,12 @@ routine file_get_translator_cntl (
routine file_get_fs_options (
file: file_t;
RPT
- out options: data_t);
+ out options: data_t, dealloc);
+
+/* Return a new file, NEW_FILE, with the same semantics as FILE, but
+ with lookups of `..' (if FILE is a directory) redirected to PARENT. */
+routine file_reparent (
+ file: file_t;
+ RPT
+ parent: mach_port_t;
+ out new_file: mach_port_send_t);
diff --git a/hurd/fs_notify.defs b/hurd/fs_notify.defs
index 47ee2df0..3a30fe6d 100644
--- a/hurd/fs_notify.defs
+++ b/hurd/fs_notify.defs
@@ -1,5 +1,5 @@
/* Miscellaneous callbacks from Hurd fs servers to their clients.
- Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991,92,93,94,95,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -25,22 +25,31 @@ subsystem fs_notify 20500;
FS_NOTIFY_IMPORTS
#endif
+/* For maximum robustness, the server must not wait for the client to
+ receive the notification message. This is achieved by setting a
+ send timeout (XXX which is implicitely 0 with MACH_MSG_TIMEOUT_NONE). */
+MsgOption MACH_SEND_TIMEOUT;
-/* This is sent by a filesystem (after being requested with
+/* This is sent by a filesystem (after being requested with
dir_notice_changes) every time a directory is changed.
CHANGE identifies the sort of change that has occurred (see hurd_types.h);
- NAME is the name that was changed. */
-routine dir_changed (
- notify_port: mach_port_t;
+ NAME is the name that was changed. TICKNO is a sequential number
+ that allows the client to verify that it got all notifications. */
+simpleroutine dir_changed (
+ notify_port: fs_notify_t;
+ tickno: natural_t;
change: dir_changed_type_t;
name: string_t);
/* This is sent by a filesystem (after being requested with
file_notice_changes) every time a file or its stat info is changed.
CHANGE identifies the sort of change that has occurred (see hurd_types.h);
- START and END identify the affected regions of the file's data. */
-routine file_changed (
- notify_port: mach_port_t;
+ START and END identify the affected regions of the file's data.
+ TICKNO is a sequential number that allows the client to verify that
+ it got all notifications. */
+simpleroutine file_changed (
+ notify_port: fs_notify_t;
+ tickno: natural_t;
change: file_changed_type_t;
- start: off_t;
- end: off_t);
+ start: loff_t;
+ end: loff_t);
diff --git a/hurd/fsys.defs b/hurd/fsys.defs
index 144bdb6a..979a6cfc 100644
--- a/hurd/fsys.defs
+++ b/hurd/fsys.defs
@@ -1,5 +1,5 @@
/* Definitions for the filesystem control interface
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97, 2002 Free Software Foundation
This file is part of the GNU Hurd.
@@ -31,6 +31,8 @@ subsystem fsys 22000;
FSYS_IMPORTS
#endif
+INTR_INTERFACE
+
/* Sent by filesystem on its bootstrap port upon startup.
REALNODE is the node this filesystem is the translator for,
opened with flags FLAGS (O_NOTRANS is assumed even if not
@@ -49,9 +51,9 @@ routine fsys_goaway (
flags: int);
/* Return a file to the root of the filesystem.
- FLAGS are as for dir_pathtrans (but O_CREAT and O_EXCL are not
+ FLAGS are as for dir_lookup (but O_CREAT and O_EXCL are not
meaningful). DO_RETRY, RETRY_NAME, and RESULT are as
- for dir_pathtrans. The port should be authenticated with GEN_UIDS
+ for dir_lookup. The port should be authenticated with GEN_UIDS
and GEN_GIDS (except, of course, for FS_RETRY_REAUTH and
FS_RETRY_MAGICAL). DOTDOT_NODE is an unauthenticated port for the
directory in which this root is located. */
@@ -124,4 +126,4 @@ routine fsys_forward (
routine fsys_get_options (
server: fsys_t;
RPT
- out options: data_t);
+ out options: data_t, dealloc);
diff --git a/hurd/fsys_reply.defs b/hurd/fsys_reply.defs
index b3676e64..e2031692 100644
--- a/hurd/fsys_reply.defs
+++ b/hurd/fsys_reply.defs
@@ -1,5 +1,7 @@
/* Reply half of fsys
- Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation
+
+ Copyright (C) 1991, 1993, 1994, 1995, 2001, 2007
+ Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +10,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -27,51 +29,50 @@ type reply_port_t = polymorphic | MACH_MSG_TYPE_PORT_SEND_ONCE
ctype: mach_port_t;
simpleroutine fsys_startup_reply (
- repsy_port: reply_port_t;
- retcode: kern_return_t;
+ reply_port: reply_port_t;
+ RETURN_CODE_ARG;
realnode: mach_port_send_t);
simpleroutine fsys_goaway_reply (
reply_port: reply_port_t;
- retcode: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine fsys_getroot_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
do_retry: retry_type;
retry_name: string_t;
file: mach_port_send_t);
simpleroutine fsys_getfile_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
file: mach_port_send_t);
simpleroutine fsys_syncfs_reply (
reply_port: reply_port_t;
- retocde: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine fsys_set_options_reply (
reply_port: reply_port_t;
- retcode: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine fsys_getpriv_reply (
reply_port_: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
host_priv: mach_port_send_t;
device_master: mach_port_send_t;
fstask: mach_port_send_t);
simpleroutine fsys_init_reply (
reply_port: reply_port_t;
- retcode: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine fsys_forward_reply (
reply_port: reply_port_t;
- retcode: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine fsys_get_options_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
options: data_t);
-
diff --git a/hurd/gensym.awk b/hurd/gensym.awk
new file mode 100644
index 00000000..21283214
--- /dev/null
+++ b/hurd/gensym.awk
@@ -0,0 +1,78 @@
+#
+# Copyright (c) 1994 The University of Utah and
+# the Computer Systems Laboratory (CSL). All rights reserved.
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+# IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+# ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# CSL requests users of this software to return to csl-dist@cs.utah.edu any
+# improvements that they make and grant CSL redistribution rights.
+#
+# Author: Bryan Ford, University of Utah CSL
+#
+
+BEGIN {
+ bogus_printed = "no"
+}
+
+# Start the bogus function just before the first sym directive,
+# so that any #includes higher in the file don't get stuffed inside it.
+/^[a-z]/ {
+ if (bogus_printed == "no")
+ {
+ print "void bogus() {";
+ bogus_printed = "yes";
+ }
+}
+
+# Take an arbitrarily complex C symbol or expression and constantize it.
+/^expr/ {
+ print "__asm (\"";
+ if ($3 == "")
+ printf "* %s mAgIc%%0\" : : \"i\" (%s));\n", $2, $2;
+ else
+ printf "* %s mAgIc%%0\" : : \"i\" (%s));\n", $3, $2;
+}
+
+# Output a symbol defining the size of a C structure.
+/^size/ {
+ print "__asm (\"";
+ if ($4 == "")
+ printf "* %s_SIZE mAgIc%%0\" : : \"i\" (sizeof(struct %s)));\n",
+ toupper($3), $2;
+ else
+ printf "* %s mAgIc%%0\" : : \"i\" (sizeof(struct %s)));\n",
+ $4, $2;
+}
+
+# Output a symbol defining the byte offset of an element of a C structure.
+/^offset/ {
+ print "__asm (\"";
+ if ($5 == "")
+ {
+ printf "* %s_%s mAgIc%%0\" : : \"i\" (&((struct %s*)0)->%s));\n",
+ toupper($3), toupper($4), $2, $4;
+ }
+ else
+ {
+ printf "* %s mAgIc%%0\" : : \"i\" (&((struct %s*)0)->%s));\n",
+ toupper($5), $2, $4;
+ }
+}
+
+# Copy through all preprocessor directives.
+/^#/ {
+ print
+}
+
+END {
+ print "}"
+}
+
diff --git a/hurd/hurd_types.defs b/hurd/hurd_types.defs
index 45767893..5ad5e93f 100644
--- a/hurd/hurd_types.defs
+++ b/hurd/hurd_types.defs
@@ -1,5 +1,5 @@
/* MiG type declarations for Hurd interfaces -*- C -*-
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993,94,95,96,98,2001,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -140,10 +140,23 @@ intran: STARTUP_INTRAN
outtran: STARTUP_OUTTRAN
#endif
#ifdef STARTUP_DESTRUCTOR
-destructor: STARTUP_DESCTRUCTOR
+destructor: STARTUP_DESTRUCTOR
#endif
;
+type fs_notify_t = mach_port_copy_send_t
+#ifdef FS_NOTIFY_INTRAN
+intran: FS_NOTIFY_INTRAN
+#endif
+#ifdef FS_NOTIFY_OUTTRAN
+outtran: FS_NOTIFY_OUTTRAN
+#endif
+#ifdef FS_NOTIFY_DESTRUCTOR
+destructor: FS_NOTIFY_DESTRUCTOR
+#endif
+;
+
+
type proccoll_t = mach_port_copy_send_t;
type sreply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic
@@ -168,6 +181,12 @@ type sreply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic
#define SCP
#endif
+#ifdef HAVE_MIG_RETCODE
+#define RETURN_CODE_ARG in return_code: kern_return_t, retcode
+#else
+#define RETURN_CODE_ARG in return_code: kern_return_t
+#endif
+
#ifdef USERPREFIX
userprefix USERPREFIX;
@@ -186,26 +205,24 @@ serverprefix SERVERPREFIX;
type data_t = array[] of char;
type string_t = c_string[1024]; /* XXX */
type io_statbuf_t = struct[32] of int;
-type uid_t = int;
-type gid_t = int;
-type mode_t = int;
-type dev_t = short;
-type retry_type = int;
-type pid_t = int;
-type wait_status_t = int;
-type off_t = int;
-type size_t = unsigned;
-type ssize_t = int;
-type file_changed_type_t = int;
-type dir_changed_type_t = int;
+type uid_t = unsigned32;
+type gid_t = unsigned32;
+type mode_t = unsigned32;
+type retry_type = unsigned32;
+type pid_t = int32;
+type wait_status_t = int32;
+type loff_t = int64;
+type ino64_t = int64;
+type file_changed_type_t = unsigned32;
+type dir_changed_type_t = unsigned32;
type portarray_t = array[] of mach_port_send_t;
type intarray_t = array[] of int;
-type off_array_t = array[] of off_t;
+type off_array_t = array[] of loff_t;
type pidarray_t = array[] of pid_t;
type procinfo_t = array[] of int;
-type fsys_statfsbuf_t=struct[16] of int;
+type fsys_statfsbuf_t=struct[22] of int;
type idarray_t = array[] of uid_t;
@@ -213,7 +230,8 @@ type rusage_t = struct[18] of int; /* XXX */
type flock_t = struct[5] of int;
-#include <utsnamelen.h>
+#define _SYS_UTSNAME_H /* Inhibit warning from <bits/utsname.h>. */
+#include <bits/utsname.h>
type utsname_t = struct[5 * _UTSNAME_LENGTH] of char;
import <sys/types.h>;
diff --git a/hurd/hurd_types.h b/hurd/hurd_types.h
index 4ecd26e1..e1a644f1 100644
--- a/hurd/hurd_types.h
+++ b/hurd/hurd_types.h
@@ -1,5 +1,5 @@
/* C declarations for Hurd server interfaces
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1993,94,95,96,98,99,2001,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define _HURD_TYPES_H
#include <mach/std_types.h> /* For mach_port_t et al. */
+#include <mach/message.h> /* For mach_msg_id_t et al. */
#include <sys/types.h> /* For pid_t and uid_t. */
/* A string identifying this release of the GNU Hurd. Our
@@ -43,6 +44,7 @@ typedef mach_port_t socket_t;
typedef mach_port_t pf_t; /* Protocol family */
typedef mach_port_t addr_port_t;
typedef mach_port_t startup_t;
+typedef mach_port_t fs_notify_t;
typedef mach_port_t proccoll_t;
#include <errno.h> /* Defines `error_t'. */
@@ -56,12 +58,17 @@ typedef int *fd_mask_t;
typedef mach_port_t *portarray_t;
typedef pid_t *pidarray_t;
typedef uid_t *idarray_t;
-typedef off_t *off_array_t;
+typedef loff_t *off_array_t;
typedef struct rusage rusage_t;
typedef struct flock flock_t;
typedef struct utsname utsname_t;
+#if _FILE_OFFSET_BITS == 64
typedef struct stat io_statbuf_t;
typedef struct statfs fsys_statfsbuf_t;
+#else
+typedef struct stat64 io_statbuf_t;
+typedef struct statfs64 fsys_statfsbuf_t;
+#endif
/* Parameters and flags in RPC calls */
@@ -73,19 +80,21 @@ typedef struct statfs fsys_statfsbuf_t;
#define EXEC_NEWTASK 0x00000001 /* Create new task; kill old one. */
#define EXEC_SECURE 0x00000002 /* Use secure values of portarray, etc. */
#define EXEC_DEFAULTS 0x00000004 /* Use defaults for unspecified ports. */
-/* These two are passed through by the exec server but not examined by it. */
+#define EXEC_SIGTRAP 0x00000008 /* Simulate SIGTRAP on startup. */
+/* This flag is passed through by the exec server but not examined by it. */
#define EXEC_STACK_ARGS 0x00000010 /* Use arguments from stack, not RPC. */
/* Bits for flags in fs.defs:file_set_translator call: */
#define FS_TRANS_FORCE 0x00000001 /* Must use translator(no sht circuit) */
#define FS_TRANS_EXCL 0x00000002 /* Don't do it if already translated. */
#define FS_TRANS_SET 0x00000004 /* Set or clear translator */
+#define FS_TRANS_ORPHAN 0x00000008 /* Orphan the active translator. */
-/* Values for retry field in fs.defs:dir_pathtrans call: */
+/* Values for retry field in fs.defs:dir_lookup call: */
enum retry_type
{
FS_RETRY_NORMAL = 1, /* Retry normally if retry_name is not null. */
- FS_RETRY_REAUTH = 2, /* Retry after reauthenticating retry port.
+ FS_RETRY_REAUTH = 2, /* Retry after reauthenticating retry port.
Even if the retry name is null, a retry
is still necessary with this code after the
reauthentication is complete. */
@@ -104,7 +113,7 @@ enum retry_type
};
typedef enum retry_type retry_type;
-/* Types for msg.defs:dir_changed call: */
+/* Types for fs_notify.defs:dir_changed call: */
enum dir_changed_type
{
DIR_CHANGED_NULL, /* Always sent first for sync. */
@@ -114,7 +123,7 @@ enum dir_changed_type
};
typedef enum dir_changed_type dir_changed_type_t;
-/* Types for msg.defs:file_changed call: */
+/* Types for fs_notify.defs:file_changed call: */
enum file_changed_type
{
FILE_CHANGED_NULL, /* Always sent first for sync. */
@@ -156,13 +165,15 @@ enum term_bottom_type
STORAGE_HURD_FILE is a hurd file_t (as if a file were mapped)
STORAGE_TASK is a task_t (the storage is in the vm of the task)
STORAGE_MEMORY is a memory object port
- STORAGE_NULL is a fixed-size constant source of zeros
+ STORAGE_ZERO is a fixed-size constant source of zeros
STORAGE_INTERLEAVE is a set of other storage types interleaved at a fixed
interval
STORAGE_CONCAT is a set of other storage types concatenated end-to-end
STORAGE_LAYER is a set of storage types, representing the same address
range; all will be written too, and will be read in turn until one
succeeds
+ STORAGE_REMAP is a layer on top of another store that remaps its blocks
+ STORAGE_COPY is a memory snapshot of another store
STORAGE_NETWORK means that the file is stored elsewhere on the
network; all the remaining fields contan type-specific information.
STORAGE_OTHER means none of these apply; and should be used when no
@@ -187,6 +198,11 @@ enum term_bottom_type
(BS is the LCM of its children; SIZE is the sum of theirs)
layer - TY, FL, NC - - NC
(BS is the LCM of its children; SIZE is the minimum of theirs)
+ remap - TY, FL, NR NR * (OFFS, LEN) - 1
+ (BS and SIZE are that of the child)
+ copy - TY, FL, SIZE - DATA -
+ (DATA is preceded by padding to the next page boundary, and is
+ SIZE bytes long itself)
For ileave, concat, and layer, the children are encoded following the parent.
The first int must always be TY.
@@ -220,10 +236,12 @@ enum file_storage_class
STORAGE_NETWORK,
STORAGE_MEMORY,
STORAGE_TASK,
- STORAGE_NULL,
+ STORAGE_ZERO,
STORAGE_CONCAT,
STORAGE_INTERLEAVE,
STORAGE_LAYER,
+ STORAGE_REMAP,
+ STORAGE_COPY,
};
/* Flags for the flags word returned by some types . */
@@ -233,13 +251,17 @@ enum file_storage_class
#include <mach/task_info.h>
#include <mach/thread_info.h>
+#ifndef THREAD_SCHED_INFO
+#include <mach/policy.h>
+#endif
/* Flags sent in proc_getprocinfo request. */
-#define PI_FETCH_TASKINFO 0x00000001
-#define PI_FETCH_THREADS 0x00000002
-#define PI_FETCH_THREAD_BASIC 0x00004
-#define PI_FETCH_THREAD_SCHED 0x00008
-#define PI_FETCH_THREAD_WAITS 0x00010
+#define PI_FETCH_TASKINFO 0x0001
+#define PI_FETCH_TASKEVENTS 0x0020
+#define PI_FETCH_THREADS 0x0002
+#define PI_FETCH_THREAD_BASIC 0x0004
+#define PI_FETCH_THREAD_SCHED 0x0008
+#define PI_FETCH_THREAD_WAITS 0x0010
struct procinfo
{
@@ -255,12 +277,20 @@ struct procinfo
int nthreads; /* size of pi_threadinfos */
struct task_basic_info taskinfo;
+ struct task_events_info taskevents;
+#ifdef TASK_SCHED_TIMESHARE_INFO
+ struct policy_timeshare_base timeshare_base_info;
+#endif
struct
{
int died; /* this thread died in the middle of call */
- int rpc_block; /* thred is blocked on this RPC */
+ mach_msg_id_t rpc_block; /* thread is blocked on this RPC */
struct thread_basic_info pis_bi;
+#ifdef THREAD_SCHED_INFO
struct thread_sched_info pis_si;
+#else
+ struct policy_infos pis_pi;
+#endif
} threadinfos[0];
};
typedef int *procinfo_t;
@@ -308,6 +338,9 @@ typedef int *procinfo_t;
#define FSTYPE_SOCKET 0x00000015 /* io_t that isn't a file but a socket */
#define FSTYPE_MISC 0x00000016 /* generic trivfs server */
#define FSTYPE_EXT2FS 0x00000017 /* Linux filesystem by Remy Card */
+#define FSTYPE_HTTP 0x00000018 /* Transparent HTTP */
+#define FSTYPE_MEMFS 0x00000019 /* In-core filesystem */
+#define FSTYPE_ISO9660 0x0000001a /* ISO9660 */
/* Standard port assignments for file_exec and exec_* */
enum
diff --git a/hurd/iioctl.defs b/hurd/iioctl.defs
new file mode 100644
index 00000000..4efe928f
--- /dev/null
+++ b/hurd/iioctl.defs
@@ -0,0 +1,179 @@
+/* Definitions for interface ioctls
+ Copyright (C) 2000, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <hurd/hurd_types.defs>
+
+INTR_INTERFACE
+
+/* Ioctl class `i'; the subsystem is derived from calculations in
+ <ioctls.h>. */
+subsystem iioctl 112000; /* XXX */
+
+import <hurd/ioctl_types.h>; /* XXX */
+
+/* This is the first arg for a struct ifreq_something as specified by the
+ definition of _IOT_ifreq_something in <net/if.h>. */
+type ifname_t = array[16] of char; /* IFNAMSIZ is 16. */
+
+/* This is the second arg of struct ifreq as specified by the
+ definition of _IOT_ifreq in <net/if.h>. */
+type sockaddr_t = struct[16] of char; /* sizeof(struct sockaddr) is 16. */
+
+skip; skip; skip; skip; /* 0 1 2 3 unused */
+skip; skip; skip; skip; /* 4 5 6 7 unused */
+skip; skip; skip; skip; /* 8 9 10 11 unused */
+
+/* 12 SIOCSIFADDR */
+routine iioctl_siocsifaddr (
+ reqport: io_t;
+ ifnam: ifname_t;
+ addr: sockaddr_t);
+
+skip; /* 13 unused */
+
+/* 14 SIOCSIFDSTADDR */
+routine iioctl_siocsifdstaddr (
+ reqport: io_t;
+ ifnam: ifname_t;
+ dstaddr: sockaddr_t);
+
+skip; /* 15 unused */
+
+/* 16 SIOCSIFFLAGS */
+routine iioctl_siocsifflags (
+ reqport: io_t;
+ ifnam: ifname_t;
+ flags: short);
+
+/* 17 SIOCGIFFLAGS */
+routine iioctl_siocgifflags (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout flags: short);
+
+skip; /* 18 unused */
+
+/* 19 SIOCSIFBRDADDR */
+routine iioctl_siocsifbrdaddr (
+ reqport: io_t;
+ ifnam: ifname_t;
+ brdaddr: sockaddr_t);
+
+skip; skip; /* 20 21 unused */
+
+/* 22 SIOCSIFNETMASK */
+routine iioctl_siocsifnetmask (
+ reqport: io_t;
+ ifnam: ifname_t;
+ netmask: sockaddr_t);
+
+/* 23 SIOCGIFMETRIC */
+routine iioctl_siocgifmetric (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout metric: int);
+
+/* 24 SIOCSIFMETRIC */
+routine iioctl_siocsifmetric (
+ reqport: io_t;
+ ifnam: ifname_t;
+ metric: int);
+
+/* 25 SIOCDIFADDR */
+routine iioctl_siocdifaddr (
+ reqport: io_t;
+ ifnam: ifname_t;
+ addr: sockaddr_t);
+
+skip; skip; skip; skip; /* 26 27 28 29 unused */
+skip; skip; skip; /* 30 31 32 unused */
+
+/* 33 SIOCGIFADDR */
+routine iioctl_siocgifaddr (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout addr: sockaddr_t);
+
+/* 34 SIOCGIFDSTADDR */
+routine iioctl_siocgifdstaddr (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout dstaddr: sockaddr_t);
+
+/* 35 SIOCGIFBRDADDR */
+routine iioctl_siocgifbrdaddr (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout brdaddr: sockaddr_t);
+
+skip; /* 36 SIOCGIFCONF -- implemented in C library */
+
+/* 37 SIOCGIFNETMASK */
+routine iioctl_siocgifnetmask (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout netmask: sockaddr_t);
+
+skip; /* 38 SIOCGARP -- Not implemented yet */
+
+routine iioctl_siocgifhwaddr (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout netmask: sockaddr_t);
+
+skip; skip; /* 40, 41 unused */
+skip; skip; skip; skip; /* 42, 43, 44, 45 unused */
+skip; skip; skip; skip; /* 46, 47, 48, 49 unused */
+skip; /* 50 unused */
+
+/* 51 SIOCGIFMTU */
+routine iioctl_siocgifmtu (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout mtu: int);
+
+/* 52 SIOCSIFMTU */
+routine iioctl_siocsifmtu (
+ reqport: io_t;
+ ifnam: ifname_t;
+ mtu: int);
+
+skip; skip; skip; skip; /* 53, 54, 55, 56 unused */
+skip; skip; skip; skip; /* 57, 58, 59, 60 unused */
+skip; skip; skip; skip; /* 61, 62, 63, 64 unused */
+skip; skip; skip; skip; /* 65, 66, 67, 68 unused */
+skip; skip; skip; skip; /* 69, 70, 71, 72 unused */
+skip; skip; skip; skip; /* 73, 74, 75, 76 unused */
+skip; skip; skip; skip; /* 77, 78, 79, 80 unused */
+skip; skip; skip; skip; /* 81, 82, 83, 84 unused */
+skip; skip; skip; skip; /* 85, 86, 87, 88 unused */
+skip; /* 89 unused */
+
+/* 90 SIOCGIFINDEX */
+routine iioctl_siocgifindex (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout index: int);
+
+/* 91 SIOCGIFNAME */
+routine iioctl_siocgifname (
+ reqport: io_t;
+ inout ifnam: ifname_t;
+ inout index: int);
diff --git a/hurd/install-headers.in b/hurd/install-headers.in
new file mode 100755
index 00000000..99d35833
--- /dev/null
+++ b/hurd/install-headers.in
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+# @configure_input@
+#
+# This is a trivial script for those who aren't comfortable typing:
+# cp hurd/*.h hurd/*.defs /usr/local/i686-gnu/include/hurd/
+# by themselves. That is, it copies the essential Hurd header files
+# into $(includedir) before you attempt to build the Hurd itself.
+# In addition to installing Mach headers, this is sufficient to bootstrap
+# an empty cross-compilation environment such that glibc can be compiled.
+
+srcdir=@srcdir@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+
+INSTALL="@INSTALL@"
+INSTALL_DATA="@INSTALL_DATA@"
+
+${srcdir}/../mkinstalldirs ${includedir}/hurd
+for file in `cd ${srcdir}; echo *.h *.defs`; do
+ ${INSTALL_DATA} ${file} ${includedir}/hurd/${file}
+done
diff --git a/hurd/io.defs b/hurd/io.defs
index 7cb85478..9119b05b 100644
--- a/hurd/io.defs
+++ b/hurd/io.defs
@@ -1,5 +1,5 @@
/* Definitions for generic IO interface
- Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1991,93,94,95,96,99,2001,02,04 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -34,7 +34,7 @@ INTR_INTERFACE
/* Write data to an IO object. If offset is -1, write at the object
maintained file pointer. If the object is not seekable, offset is
- ignored. The amount successfully written is returned in amount. A
+ ignored. The amount successfully written is returned in AMOUNT. A
given user should not have more than one outstanding io_write on an
object at a time; servers implement congestion control by delaying
responses to io_write. Servers may drop data (returning ENOBUFS)
@@ -43,26 +43,26 @@ routine io_write (
io_object: io_t;
RPT
data: data_t SCP;
- offset: off_t;
- out amount: mach_msg_type_number_t);
+ offset: loff_t;
+ out amount: vm_size_t);
/* Read data from an IO object. If offset if -1, read from the object
maintained file pointer. If the object is not seekable, offset is
- ignored. The amount desired to be read is in amount. */
+ ignored. The amount desired to be read is in AMOUNT. */
routine io_read (
io_object: io_t;
RPT
out data: data_t, dealloc;
- offset: off_t;
- amount: mach_msg_type_number_t);
+ offset: loff_t;
+ amount: vm_size_t);
/* Change current read/write offset */
routine io_seek (
io_object: io_t;
RPT
- offset: off_t;
+ offset: loff_t;
whence: int;
- out newp: off_t);
+ out newp: loff_t);
/* Tell how much data can be read from the object without blocking for
a "long time" (this should be the same meaning of "long time" used
@@ -70,7 +70,7 @@ routine io_seek (
routine io_readable (
io_object: io_t;
RPT
- out amount: mach_msg_type_number_t);
+ out amount: vm_size_t);
/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
@@ -101,7 +101,7 @@ routine io_clear_some_openmodes (
when appropriate, to the designated port using sig_post. A
port is also returned which will be used as the reference port in
sending such signals (this is the "async IO ID" port). The async
- call is cancelled by deleting all refernces to the async_id_port.
+ call is cancelled by deleting all references to the async_id_port.
Each call to io_async generates a new ASYNC_ID_PORT.
*/
routine io_async (
@@ -146,9 +146,7 @@ routine io_get_icky_async_id (
/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
Block until one of the indicated types of i/o can be done "quickly", and
- return the types that are then available. ID_TAG is returned as passed; it
- is just for the convenience of the user in matching up reply messages with
- specific requests sent. */
+ return the types that are then available. */
/* INTR */
routine io_select (
io_object: io_t;
@@ -316,5 +314,9 @@ routine io_identity (
RPT
out idport: mach_port_send_t;
out fsidport: mach_port_send_t;
- out fileno: int);
+ out fileno: ino64_t);
+/* Revoke the access of all descriptors except this one currently open
+ on the specified object. */
+routine io_revoke (
+ io_object: io_t RPTLAST);
diff --git a/hurd/io_reply.defs b/hurd/io_reply.defs
index 68bd2f1c..b5daf27e 100644
--- a/hurd/io_reply.defs
+++ b/hurd/io_reply.defs
@@ -1,5 +1,5 @@
/* Definitions for generic IO interface
- Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1991,93,94,95,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -28,128 +28,126 @@ subsystem io_reply 21100; /* much mach io.defs + 100 */
IO_IMPORTS
#endif
-type reply_port_t = polymorphic | MACH_MSG_TYPE_MAKE_SEND_ONCE
+type reply_port_t = polymorphic | MACH_MSG_TYPE_MAKE_SEND_ONCE
ctype: mach_port_t;
simpleroutine io_write_reply (
reply: reply_port_t;
- return_code: kern_return_t;
- amount: int);
+ RETURN_CODE_ARG;
+ amount: vm_size_t);
simpleroutine io_read_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
data: data_t);
simpleroutine io_seek_reply (
reply: reply_port_t;
- return_code: kern_return_t;
- newp: off_t);
+ RETURN_CODE_ARG;
+ newp: loff_t);
simpleroutine io_readable_reply (
reply: reply_port_t;
- return_code: kern_return_t;
- amount: int);
+ RETURN_CODE_ARG;
+ amount: vm_size_t);
simpleroutine io_set_all_openmodes_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_get_openmodes_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
bits: int);
simpleroutine io_set_some_openmodes_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_clear_some_openmodes_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_async_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
async_id_port: mach_port_send_t);
simpleroutine io_mod_owner_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_get_owner_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
owner: pid_t);
simpleroutine io_get_icky_async_id_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
id_port: mach_port_send_t);
simpleroutine io_select_reply (
reply: reply_port_t;
- return_code: kern_return_t;
- select_result: int;
- id_tag: int);
+ RETURN_CODE_ARG;
+ select_result: int);
simpleroutine io_stat_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
stat_info: io_statbuf_t);
skip; /* io_reauthenticate has no reply */
simpleroutine io_restrict_auth_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
new_object: mach_port_send_t);
simpleroutine io_duplicate_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
newport: mach_port_send_t);
simpleroutine io_map_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
rdobject: mach_port_send_t;
wrobject: mach_port_send_t);
simpleroutine io_map_cntl_reply (
reply: reply_port_t;
- return_code: kern_return_t;
+ RETURN_CODE_ARG;
memobj: mach_port_send_t);
simpleroutine io_get_conch_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_release_conch_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_eofnotify_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_prenotify_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_postnotify_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_readnotify_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_readsleep_reply (
reply: reply_port_t;
- return_code: kern_return_t);
+ RETURN_CODE_ARG);
simpleroutine io_sigio_reply (
reply: reply_port_t;
- return_code: kern_return_t);
-
+ RETURN_CODE_ARG);
diff --git a/hurd/io_request.defs b/hurd/io_request.defs
index 366963f2..55a8a31b 100644
--- a/hurd/io_request.defs
+++ b/hurd/io_request.defs
@@ -1,5 +1,5 @@
/* Definitions for generic IO interface
- Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1991,93,94,95,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -35,18 +35,18 @@ simpleroutine io_write_request (
io_object: io_t;
reply: reply_port_t;
data: data_t;
- offset: off_t);
+ offset: loff_t);
simpleroutine io_read_request (
io_object: io_t;
reply: reply_port_t;
- offset: off_t;
- amount: int);
+ offset: loff_t;
+ amount: vm_size_t);
simpleroutine io_seek_request (
io_object: io_t;
reply: reply_port_t;
- offset: off_t;
+ offset: loff_t;
whence: int);
simpleroutine io_readable_request (
@@ -160,7 +160,3 @@ simpleroutine io_readsleep_request (
simpleroutine io_sigio_request (
io_object: io_t;
reply: reply_port_t);
-
-
-
-
diff --git a/hurd/ioctl-decode.h b/hurd/ioctl-decode.h
new file mode 100644
index 00000000..f65880cf
--- /dev/null
+++ b/hurd/ioctl-decode.h
@@ -0,0 +1,15 @@
+/* This file is used by the Makefile rules for generating
+ Xioctl-proto.defs, see Makefile for details. */
+
+#define CMD(request) _IOC_COMMAND (request)
+#define TYPE(request) _IOC_TYPE (request)
+#define INOUT(request) _IOC_INOUT (request)
+
+#define SUBID(request) IOC_COMMAND_SUBID (_IOC_COMMAND (request))
+
+#define TYPE0(request) _IOT_TYPE0 (_IOC_TYPE (request))
+#define TYPE1(request) _IOT_TYPE1 (_IOC_TYPE (request))
+#define TYPE2(request) _IOT_TYPE2 (_IOC_TYPE (request))
+#define COUNT0(request) _IOT_COUNT0 (_IOC_TYPE (request))
+#define COUNT1(request) _IOT_COUNT1 (_IOC_TYPE (request))
+#define COUNT2(request) _IOT_COUNT2 (_IOC_TYPE (request))
diff --git a/hurd/ioctl-tmpl.sym b/hurd/ioctl-tmpl.sym
new file mode 100644
index 00000000..8029ec00
--- /dev/null
+++ b/hurd/ioctl-tmpl.sym
@@ -0,0 +1,13 @@
+/* This file is used by the Makefile rules for generating
+ Xioctl-proto.defs, see Makefile for details. */
+
+#include <sys/ioctl.h>
+#include <hurd/ioctls.defs>
+
+#include "ioctl-decode.h"
+
+#include "@HEADER_LIST@"
+#define GROUPCHAR '@GROUP@'
+
+expr GROUPCHAR GROUP
+expr IOC_GROUP_SUBSYSTEM(GROUPCHAR) SUBSYSTEM
diff --git a/hurd/ioctl.awk b/hurd/ioctl.awk
new file mode 100644
index 00000000..289a9ab9
--- /dev/null
+++ b/hurd/ioctl.awk
@@ -0,0 +1,127 @@
+#
+# This awk script is used by the Makefile rules for generating
+# Xioctl-proto.defs, see Makefile for details.
+#
+
+$1 == "SUBSYSTEM" { subsystem = $2 + 0; next }
+$1 == "GROUP" { groupchar = $2; next }
+
+$2 == "CMD" { cmd[tolower($1)] = $3;
+ c = $3 + 0;
+ if (c > highcmd) highcmd = c;
+ icmd[c] = tolower($1);
+ next }
+$2 == "SUBID" { subid[tolower($1)] = $3;
+ c = $3 + 0;
+ if (c > highid) highid = c;
+ id2cmdname[c] = tolower($1);
+ next }
+$2 == "TYPE" { type[tolower($1)] = $3; next }
+$2 == "INOUT" { inout[tolower($1)] = $3; next }
+$2 == "TYPE0" { type0[tolower($1)] = $3; next }
+$2 == "TYPE1" { type1[tolower($1)] = $3; next }
+$2 == "TYPE2" { type2[tolower($1)] = $3; next }
+$2 == "COUNT0" { count0[tolower($1)] = $3; next }
+$2 == "COUNT1" { count1[tolower($1)] = $3; next }
+$2 == "COUNT2" { count2[tolower($1)] = $3; next }
+
+END {
+ group = sprintf("%cioctl", groupchar);
+
+ printf "subsystem %s %d; /* see ioctls.defs for calculation */\n\n", \
+ group, subsystem;
+
+ typemap[0] = "char";
+ typemap[1] = "char";
+ typemap[2] = "short";
+ typemap[3] = "int";
+ typemap[4] = "???64 bits???";
+ inoutmap[1] = "out";
+ inoutmap[2] = "in";
+ inoutmap[3] = "inout";
+
+ print "";
+ for (cmdname in type0) {
+ if (count0[cmdname] > 1) {
+ typecount = type0[cmdname] "," count0[cmdname];
+ if (!tc[typecount]) {
+ tc[typecount] = typemap[type0[cmdname]] "array_" count0[cmdname] "_t";
+ print "type", tc[typecount], "=", ("array[" count0[cmdname] "]"), \
+ "of", (typemap[type0[cmdname]] ";"), "/* XXX rename this! */";
+ }
+ argtype["0," cmdname] = tc[typecount];
+ }
+ else if (count0[cmdname] == 1) {
+ argtype["0," cmdname] = typemap[type0[cmdname]]
+ }
+ }
+
+ for (cmdname in type1) {
+ if (count1[cmdname] > 1) {
+ typecount = type1[cmdname] "," count1[cmdname];
+ if (!tc[typecount]) {
+ tc[typecount] = typemap[type1[cmdname]] "array_" count1[cmdname] "_t";
+ print "type", tc[typecount], "=", ("array[" count1[cmdname] "]"), \
+ "of", (typemap[type1[cmdname]] ";"), "/* XXX rename this! */";
+ }
+ argtype["1," cmdname] = tc[typecount];
+ }
+ else if (count1[cmdname] == 1) {
+ argtype["1," cmdname] = typemap[type1[cmdname]]
+ }
+ }
+
+ for (cmdname in type2) {
+ if (count2[cmdname] > 1) {
+ typecount = type2[cmdname] "," count2[cmdname];
+ if (!tc[typecount]) {
+ tc[typecount] = typemap[type2[cmdname]] "array_" count2[cmdname] "_t";
+ print "type", tc[typecount], "=", ("array[" count2[cmdname] "]"), \
+ "of", (typemap[type2[cmdname]] ";"), "/* XXX rename this! */";
+ }
+ argtype["2," cmdname] = tc[typecount];
+ }
+ else if (count2[cmdname] == 1) {
+ argtype["2," cmdname] = typemap[type2[cmdname]]
+ }
+ }
+ print "";
+
+ lastid = -1;
+ for (i = 0; i <= highid; ++i)
+ if (id2cmdname[i]) {
+ cmdname = id2cmdname[i];
+
+ if (lastid < 100 && i > 100) {
+ if (lastid == 98)
+ print "\nskip; /* 99 unused */"
+ else
+ printf "\nskip %d; /* %d-99 unused */\n", 100 - lastid, lastid + 1;
+ print "\n\
+/* Because MiG defines reply ports as 100 more than request ports, we\n\
+ have to leave one hundred empty RPC's here. */\n\
+skip 100;";
+ lastid = 199;
+ }
+
+ if (i == lastid + 2)
+ print "\nskip; /*", lastid + 1, "unused */";
+ else if (i != lastid + 1)
+ printf "\nskip %d; /* %d-%d unused */\n", \
+ i - lastid - 1, lastid + 1, i - 1;
+ lastid = i;
+ print "\n/*", i, toupper(cmdname), "*/";
+ printf "routine %s_%s (\n\treqport: io_t", group, cmdname;
+ if (inout[cmdname]) {
+ io = inoutmap[inout[cmdname]];
+ for (argidx = 0; argidx <= 2; ++argidx)
+ if (argtype[argidx "," cmdname])
+ printf ";\n\t%s\targ%d: %s", \
+ io, argidx, argtype[argidx "," cmdname];
+ }
+ else {
+ printf ";\n\tin\trequest: int";
+ }
+ print ");"
+ }
+}
diff --git a/hurd/ioctl_types.h b/hurd/ioctl_types.h
index 01a1e2e6..8baa3604 100644
--- a/hurd/ioctl_types.h
+++ b/hurd/ioctl_types.h
@@ -26,4 +26,8 @@ typedef cc_t ccs_t[NCCS];
#include <sys/ioctl.h>
typedef struct winsize winsize_t;
+#include <net/if.h>
+typedef struct sockaddr sockaddr_t;
+typedef char ifname_t[16];
+
#endif /* hurd/ioctl_types.h */
diff --git a/hurd/ioctls.defs b/hurd/ioctls.defs
new file mode 100644
index 00000000..bcad5489
--- /dev/null
+++ b/hurd/ioctls.defs
@@ -0,0 +1,48 @@
+/* Macro definitions for defining and using ioctl-based RPC interfaces.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _HURD_IOCTLS_DEFS
+#define _HURD_IOCTLS_DEFS 1
+
+#ifndef _SYS_IOCTL_H
+#define _SYS_IOCTL_H /* Suppress #error in <bits/ioctl.h>. */
+#endif
+#include <bits/ioctls.h>
+
+
+/* Calculate the MiG subsystem (i.e. first message ID)
+ for the RPCs produced by ioctl requests in the given group. */
+#define IOC_GROUP_SUBSYSTEM(group) (100000 + ((group) - 'f') * 4000)
+
+/* Because of MiG's poorly chosen algorithm of adding 100 to a request
+ msgid to produce the reply msgid, we cannot just add the command part of
+ the ioctl request to the subsystem base msgid. For ioctl requests past
+ 99, we must skip blocks of 100 msgids to allow for the reply msgids
+ corresponding to the earlier requests. Since our ioctl request format
+ allows only 7 bits for the command portion, we know that it cannot
+ exceed 127 and thus we can handle just 100+ as a special case. */
+#define IOC_COMMAND_SUBID(cmd) ((cmd) + ((cmd) < 100 ? 0 : 100))
+
+#define IOC_CONSTRUCT_MSGID(group, cmd) \
+ (IOC_GROUP_SUBSYSTEM (group) + IOC_COMMAND_SUBID (cmd))
+#define IOC_MSGID(request) \
+ IOC_CONSTRUCT_MSGID (_IOC_GROUP (request), _IOC_COMMAND (request))
+
+
+#endif /* !_HURD_IOCTLS_DEFS */
diff --git a/libtrivfs/interrupt.c b/hurd/kdioctl.defs
index 3b3bd211..64f9b9ea 100644
--- a/libtrivfs/interrupt.c
+++ b/hurd/kdioctl.defs
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1993, 1994 Free Software Foundation
+/* Definitions for kd ioctls
+ Copyright (C) 1991, 1993, 1994, 1995, 1996, 1998, 2005 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -17,18 +17,23 @@ You should have received a copy of the GNU General Public License
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* Written by Michael I. Bushnell. */
-
-#include "priv.h"
-#include "interrupt_S.h"
-
-error_t
-trivfs_S_interrupt_operation (mach_port_t port)
-{
- struct port_info *pi = ports_lookup_port (0, port, 0);
- if (!pi)
- return EOPNOTSUPP;
- ports_interrupt_rpc (pi);
- ports_port_deref (pi);
- return 0;
-}
+#include <hurd/hurd_types.defs>
+
+/* Ioctl class `k'; the subsystem is derived from calculations in
+ <ioctls.h>. */
+subsystem kdioctl 120000;
+
+import <hurd/ioctl_types.h>;
+
+skip; /* 0 unused */
+
+/* 1 KDSKBDMODE */
+routine kdioctl_kdskbdmode (
+ port: io_t;
+ in mode: int);
+/* 2 KDGKBDMODE */
+routine kdioctl_kdgkbdmode (
+ port: io_t;
+ out mode: int);
+
+/* 3 - 256 unused */
diff --git a/hurd/msg.defs b/hurd/msg.defs
index 32c962af..95802472 100644
--- a/hurd/msg.defs
+++ b/hurd/msg.defs
@@ -1,6 +1,5 @@
/* RPCs which a friendly Hurd process will understand on its message port.
- Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 Free Software
- Foundation, Inc.
+ Copyright (C) 1991,92,93,94,95,96,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -191,7 +190,7 @@ routine msg_report_wait (
process: mach_port_t;
thread: thread_t;
out wait_desc: string_t;
- out wait_rpc: int);
+ out wait_rpc: mach_msg_id_t);
/* Given a list of port names in NAMES, return a description of the
corresponding port from libc's point of view, in a '\0'-separated vector.
@@ -201,4 +200,3 @@ routine msg_describe_ports (
refport: mach_port_t;
names: mach_port_name_array_t;
out descriptions: data_t);
-
diff --git a/hurd/msg_reply.defs b/hurd/msg_reply.defs
index 357224f9..c1b95fdc 100644
--- a/hurd/msg_reply.defs
+++ b/hurd/msg_reply.defs
@@ -1,5 +1,5 @@
/* Reply side of miscellaneous callbacks from Hurd servers to their clients
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -26,7 +26,7 @@ type reply_port_t = polymorphic | MACH_MSG_TYPE_PORT_SEND_ONCE
simpleroutine msg_sig_post_reply (
reply_port: reply_port_t;
- in return_code: kern_return_t);
+ RETURN_CODE_ARG);
skip; /* msg_proc_newids */
skip; /* msg_add_auth */
@@ -52,4 +52,4 @@ skip; /* msg_startup_dosync */
simpleroutine msg_sig_post_untraced_reply (
reply_port: reply_port_t;
- in return_code: kern_return_t);
+ RETURN_CODE_ARG);
diff --git a/hurd/newterm.defs b/hurd/newterm.defs
index 9371bdfb..d44d0926 100644
--- a/hurd/newterm.defs
+++ b/hurd/newterm.defs
@@ -1,5 +1,5 @@
/* Creation of terminal processors
- Copyright (C) 1991, 1993 Free Software Foundation
+ Copyright (C) 1991, 1993 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -25,12 +25,12 @@ subsystem newterm 27000;
/* Create a new terminal thingie with no bottom half. (You need to do
one of term_on_* before this can be used for I/O.) */
-newterm_from_device (
+routine newterm_from_device (
newterm: mach_port_t;
out terminal: io_t);
/* Register a terminal as a node in the filesystem. */
-newterm_makenode (
+routine newterm_makenode (
newterm: mach_port_t;
terminal: io_t;
mode: mode_t;
diff --git a/hurd/password.defs b/hurd/password.defs
new file mode 100644
index 00000000..b6d74198
--- /dev/null
+++ b/hurd/password.defs
@@ -0,0 +1,50 @@
+/* Protocol for password checker
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Thomas Bushnell, n/BSG. */
+
+subsystem password 38000;
+
+#ifdef PASSWORD_IMPORTS
+PASSWORD_IMPORTS
+#endif
+
+#include <hurd/hurd_types.defs>
+
+/* Service for this protocol normally lives on /servers/password as
+ specified by _SERVERS_PASSWORD in <hurd/paths.h>. */
+
+/* Check to see if the password for user USER is really PW. Return
+ an error if it fails, and return an auth port for the id in AUTH
+ if it succeeded. */
+routine password_check_user (
+ server: io_t;
+ user: uid_t;
+ pw: string_t;
+ out auth: mach_port_send_t);
+
+
+/* Check to see if the password for GROUP is really PW. Return
+ an error if it fails, and return an auth port for the id in AUTH
+ if it succeeded. */
+routine password_check_group (
+ server: io_t;
+ group: uid_t;
+ pw: string_t;
+ out auth: mach_port_send_t);
diff --git a/hurd/paths.h b/hurd/paths.h
index f8fd6ffb..48771325 100644
--- a/hurd/paths.h
+++ b/hurd/paths.h
@@ -1,5 +1,5 @@
/* Standard Hurd pathnames.
- Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992,94,95,97,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -26,8 +26,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define _SERVERS "/servers/"
#define _SERVERS_CRASH _SERVERS "crash"
#define _SERVERS_EXEC _SERVERS "exec"
-#define _SERVERS_STARTUP _SERVERS "startup"
#define _SERVERS_PROC _SERVERS "proc"
+#define _SERVERS_PASSWORD _SERVERS "password"
+#define _SERVERS_DEFPAGER _SERVERS "default-pager"
/* Directory containing naming points for socket servers.
Entries are named by the string representing the domain number
diff --git a/hurd/pfinet.defs b/hurd/pfinet.defs
index 11a6e64d..ec0b03e3 100644
--- a/hurd/pfinet.defs
+++ b/hurd/pfinet.defs
@@ -1,5 +1,5 @@
/* Definitions for pfinet-specific calls
- Copyright (C) 1996 Free Software Foundation
+ Copyright (C) 1999,2000,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -17,66 +17,23 @@ You should have received a copy of the GNU General Public License
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-subsystem pfinet 21000;
+subsystem pfinet 37000;
#include <hurd/hurd_types.defs>
-INTR_INTERFACE
-
-/* Add a route entry for DESTINATION through GATEWAY. All outgoing IP
- addresses A for which (A & MASK) == DESTINATION will be directed
- through GATEWAY. What BSD calls `host routes' are just where
- MASK is all one bits. */
-routine pfinet_add_route (
- socket_t ignored;
- int gateway;
- int destination;
- int mask);
-
-/* Delete a route entry; the parameters much exactly match a preceding
- pfinet_add_route call. */
-routine pfinet_delete_route (
- socket_t ignored;
- int gateway;
- int destination;
- int mask);
-
-/* Return the current contents of the routing table. GATEWAY,
- DESTINATION, MASK, REDIRECT, and WIRED are parallel arrays with one element
- each for each route. GATEWAY, DESTINATION, and MASK refer to the
- parameters of the pfinet_add_route call. REDIRECT is set for
- internally generated routes. WIRED is set for permanent routes
- associated with live interfaces. */
-routine pfinet_get_routes (
- socket_t ignored;
- intarray_t gateway;
- intarray_t destination;
- intarray_t mask;
- data_t redirect;
- data_t wired);
-
-/* Add a new interface specification. NAME is the kernel device name
- corresponding to the interface. ADDR is our address on that
- interface. DEST is the address of the peers we can talk to on the
- interface, such that if (X & MASK) == DEST for some address X,
- then it should be directly reachable on this interface.
- A wired routing entry will be added for this interface. */
-routine pfinet_add_interface (
- socket_t ignored;
- string_t name;
- int addr;
- int dest;
- int mask;
- int type);
-
-/* Delete an interface specification. The parameters must exactly
- match those of a preceding pfinet_add_interface call. */
-routine pfinet_delete_interface (
- socket_t ignored;
- string_t name;
- int addr;
- int dest;
- int mask;
- int type);
+#ifdef SOCKET_IMPORTS
+SOCKET_IMPORTS
+#endif
+INTR_INTERFACE
+/* Return a list of interfaces as expected by the SIOCGIFCONF ioctl.
+ The maximum number of bytes returned can be given in AMOUNT, but if
+ AMOUNT is -1, all interfaces will be returned. Always
+ succeeds (and interface list will be truncated to fit into AMOUNT
+ space) for BSD compatibility. */
+routine pfinet_siocgifconf (
+ port: io_t;
+ amount: vm_size_t;
+ out buf: data_t, dealloc
+);
diff --git a/hurd/process.defs b/hurd/process.defs
index e21beb1f..43cc9f2a 100644
--- a/hurd/process.defs
+++ b/hurd/process.defs
@@ -1,5 +1,5 @@
/* Definitions for process server interface
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97,2001 Free Software Foundation
This file is part of the GNU Hurd.
@@ -33,28 +33,10 @@ INTR_INTERFACE
/*** Host management ***/
-/* Set the hostid for the machine. This should be unique among all
- machines. By convention, it is the "primary" IP address of the
- machine. */
-routine proc_sethostid (
- process: process_t;
- hostid: int);
-
-/* Get the host id. */
-routine proc_gethostid (
- process: process_t;
- out hostid: int);
-
-/* Set the hostname for the machine. By convention this is the DNS
- FQDN for the machine. */
-routine proc_sethostname (
- process: process_t;
- hostname: data_t);
-
-/* Get the hostname. */
-routine proc_gethostname (
- process: process_t;
- out hostname: data_t, dealloc);
+skip; /* Was proc_sethostid */
+skip; /* Was proc_gethostid */
+skip; /* Was proc_sethostname */
+skip; /* Was proc_gethostname */
/* Get the privileged host port and the device master port. */
routine proc_getprivports (
@@ -279,7 +261,7 @@ routine proc_getprocinfo (
process: process_t;
which: pid_t;
inout flags: int;
- out procinfo: procinfo_t;
+ out procinfo: procinfo_t, dealloc;
out threadwaits: data_t, dealloc);
routine proc_getprocargs (
@@ -312,8 +294,7 @@ routine proc_getloginpids (
id: pid_t;
out pids: pidarray_t, dealloc);
-/* These next two should not actually be used; they are here
- for "historic reasons." You are not expected to understand this. */
+/* You are not expected to understand this. */
routine proc_setlogin (
process: process_t;
logname: string_t);
@@ -375,7 +356,7 @@ routine proc_getpgrppids (
out pidset: pidarray_t, dealloc);
-/*** Another miscelleneous info query ***/
+/*** Other miscelleneous info queries ***/
/* Return the controlling TTY used by PID in TTY; opened without read or
write access. */
@@ -383,3 +364,9 @@ routine proc_get_tty (
calling_process: process_t;
target_process: pid_t;
out tty: mach_port_send_t);
+
+/* Return the number of Mach ports used by PID */
+routine proc_getnports (
+ process: process_t;
+ which: pid_t;
+ out nports: mach_msg_type_number_t);
diff --git a/hurd/process_reply.defs b/hurd/process_reply.defs
index c8a6c3c0..80d39293 100644
--- a/hurd/process_reply.defs
+++ b/hurd/process_reply.defs
@@ -1,5 +1,5 @@
/* Reply half of wait
- Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1991,93,94,96,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -39,9 +39,9 @@ skip; /* child */
simpleroutine proc_setmsgport_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
in oldmsgport: mach_port_t);
-
+
skip; /* reassign */
skip; /* setowner */
skip; /* getpids */
@@ -50,14 +50,13 @@ skip; /* get_arg_locations */
simpleroutine proc_getmsgport_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
in msgports: mach_port_t);
simpleroutine proc_wait_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
in status: int;
in sigcode: int;
in rusage: rusage_t;
in pid_status: pid_t);
-
diff --git a/hurd/process_request.defs b/hurd/process_request.defs
index c351cc6b..80a28282 100644
--- a/hurd/process_request.defs
+++ b/hurd/process_request.defs
@@ -1,6 +1,6 @@
/* Definitions for process server interface (request-only version)
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 98 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -9,7 +9,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -32,30 +32,10 @@ type reply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic
/*** Host management ***/
-/* Set the hostid for the machine. This should be unique among all
- machines. By convention, it is the "primary" IP address of the
- machine. */
-simpleroutine proc_sethostid_request (
- process: process_t;
- ureplyport reply: reply_port_t;
- hostid: int);
-
-/* Get the host id. */
-simpleroutine proc_gethostid_request (
- process: process_t;
- ureplyport reply: reply_port_t);
-
-/* Set the hostname for the machine. By convention this is the DNS
- FQDN for the machine. */
-simpleroutine proc_sethostname_request (
- process: process_t;
- ureplyport reply: reply_port_t;
- hostname: data_t);
-
-/* Get the hostname. */
-simpleroutine proc_gethostname_request (
- process: process_t;
- ureplyport reply: reply_port_t);
+skip; /* Was proc_sethostid */
+skip; /* Was proc_gethostid */
+skip; /* Was proc_sethostname */
+skip; /* Was proc_gethostname */
/* Get the privileged host port and the device master port. */
simpleroutine proc_getprivports_request (
@@ -209,7 +189,7 @@ simpleroutine proc_handle_exceptions_request (
-/*** Mark bits. Some of these (exec, traced, eg) modify small pieces
+/*** Mark bits. Some of these (exec, traced, eg) modify small pieces
of the proc server's behavior; others are purely informational. ***/
/* Mark the process as stopped on a signal. */
@@ -239,13 +219,13 @@ simpleroutine proc_mark_exec_request (
ureplyport reply: reply_port_t);
/* Inform the process server that the process has asked to be traced.
- The only result of this is to change the behavior of wait by the
+ The only result of this is to change the behavior of wait by the
parent slightly. */
simpleroutine proc_mark_traced_request (
process: process_t;
ureplyport reply: reply_port_t);
-/* Inform the process server whether SIGCHLD should be sent for stopped
+/* Inform the process server whether SIGCHLD should be sent for stopped
child processes. */
simpleroutine proc_mod_stopchild_request (
process: process_t;
@@ -317,7 +297,7 @@ simpleroutine proc_getloginpids_request (
ureplyport reply: reply_port_t;
id: pid_t);
-/* These next two should not actually be used; they are here
+/* These next two should not actually be used; they are here
for "historic reasons." You are not expected to understand this. */
simpleroutine proc_setlogin_request (
process: process_t;
@@ -386,3 +366,8 @@ simpleroutine proc_get_tty_request (
ureplyport reply: reply_port_t;
pid: pid_t);
+/* Return the number of Mach ports used by PID */
+simpleroutine proc_getnports_request (
+ process: process_t;
+ ureplyport reply: reply_port_t;
+ which: pid_t);
diff --git a/hurd/socket.defs b/hurd/socket.defs
index f71930ea..53219077 100644
--- a/hurd/socket.defs
+++ b/hurd/socket.defs
@@ -1,5 +1,5 @@
/* Definitions for socket interface
- Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1991,93,94,95,2001,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -122,7 +122,7 @@ routine socket_send (
data: data_t SCP;
ports: portarray_t SCP;
control: data_t SCP;
- out amount: mach_msg_type_number_t);
+ out amount: vm_size_t);
/* Receive data from a socket, possibly including Mach ports. */
routine socket_recv (
@@ -133,4 +133,4 @@ routine socket_recv (
out ports: portarray_t, dealloc;
out control: data_t, dealloc;
out outflags: int;
- amount: mach_msg_type_number_t);
+ amount: vm_size_t);
diff --git a/hurd/startup.defs b/hurd/startup.defs
index 6f48bb2b..bd5cd6e1 100644
--- a/hurd/startup.defs
+++ b/hurd/startup.defs
@@ -1,5 +1,5 @@
/* Definitions for startup server interface
- Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1991, 1992, 1993, 1994, 1996, 1999 Free Software Foundation
This file is part of the GNU Hurd.
@@ -41,7 +41,7 @@ routine startup_essential_task (
credential: host_priv_t);
/* This call registers a task as "notified", which means that if the
- system is going down, we should told about it and get a chance to
+ system is going down, we should be told about it and get a chance to
run. A startup_dosync message (see startup_notify.defs) will be
sent to the notify port. NAME will be used to provide a helpful
message to the user when the system is shutting down. */
@@ -56,7 +56,7 @@ routine startup_reboot (
refport: mach_port_t;
reboot_code: int);
-/* NOTE: All changes two these last two must be reflected in
+/* NOTE: All changes to these last two must be reflected in
startup_reply.defs. */
/* This call is made by the proc server for its initialization, on its
diff --git a/hurd/startup_reply.defs b/hurd/startup_reply.defs
index 1776dc3d..a8462676 100644
--- a/hurd/startup_reply.defs
+++ b/hurd/startup_reply.defs
@@ -1,6 +1,6 @@
/* Server-reply definitions for startup server interface
NOTE: All changes here must be reflected in startup.defs.
- Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation
+ Copyright (C) 1991,92,93,94,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -9,7 +9,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -33,14 +33,14 @@ STARTUP_IMPORTS
simpleroutine startup_essential_task_reply (
reply_port: reply_port_t;
- retcode: kern_return_t);
+ RETURN_CODE_ARG);
skip; /* startup_request_notification */
skip; /* startup_reboot */
simpleroutine startup_procinit_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
startup_task: task_t;
auth: auth_t;
host_priv: mach_port_send_t;
@@ -48,5 +48,5 @@ simpleroutine startup_procinit_reply (
simpleroutine startup_authinit_reply (
reply_port: reply_port_t;
- retcode: kern_return_t;
+ RETURN_CODE_ARG;
proc: mach_port_send_t);
diff --git a/hurd/subsystems b/hurd/subsystems
index b4aac67e..c05895c2 100644
--- a/hurd/subsystems
+++ b/hurd/subsystems
@@ -35,6 +35,7 @@ ifsock 34000 S_IFSOCK node protocol for AF_LOCAL rendezvous
tape 35000 Special control operations for magtapes
login 36000 Database of logged-in users
pfinet 37000 Internet configuration calls
+password 38000 Password checker
<ioctl space> 100000- First subsystem of ioctl class 'f' (lowest class)
tioctl 156000 Ioctl class 't' (terminals)
tioctl 156200 (continued)
diff --git a/hurd/term.defs b/hurd/term.defs
index 8739459b..dbc03b76 100644
--- a/hurd/term.defs
+++ b/hurd/term.defs
@@ -1,5 +1,5 @@
/* Special protocol for terminal driver
- Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1993, 1994, 1999 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -27,6 +27,8 @@ subsystem term 28000;
TERM_IMPORTS
#endif
+INTR_INTERFACE
+
/* Find out what the controlling terminal ID port is. */
routine term_getctty (
terminal: io_t;
@@ -110,3 +112,12 @@ routine termctty_open_terminal (
ctty: mach_port_t;
flags: int;
out terminal: mach_port_send_t);
+
+/* This call is only supported for PTY-based terminals. For a slave,
+ it returns a filename which, when opened, would yield the master for
+ this terminal. For a master, it returns a filename which, when
+ opened, would yield the slave for this terminal. */
+routine term_get_peername (
+ terminal: io_t;
+ out name: string_t);
+
diff --git a/hurd/tioctl.defs b/hurd/tioctl.defs
index 910496b1..58ee698f 100644
--- a/hurd/tioctl.defs
+++ b/hurd/tioctl.defs
@@ -1,5 +1,5 @@
/* Definitions for terminal ioctls
- Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1991,93,94,95,96,99,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -20,6 +20,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/hurd_types.defs>
+#ifdef TIOCTL_IMPORTS
+TIOCTL_IMPORTS
+#endif
+
+INTR_INTERFACE
+
/* Ioctl class `t'; the subsystem is derived from calculations in
<ioctls.h>. */
subsystem tioctl 156000; /* XXX */
@@ -131,7 +137,8 @@ routine tioctl_tiocsig (
/* 96 TIOCEXT */
routine tioctl_tiocext (
- port: io_t);
+ port: io_t;
+ mode: int);
skip; /* 97 TIOCSCTTY -- implemented in C library */
skip; /* 98 TIOCCONS -- implemented in C library */
diff --git a/hurd/version.h b/hurd/version.h
index 6afdf4a6..9b85b5a5 100644
--- a/hurd/version.h
+++ b/hurd/version.h
@@ -1,84 +1,6 @@
-/* Hurd version calculation
- Copyright (C) 1994, 1996 Free Software Foundation
+/* This file just gives a value that can be tested easily with #if as a
+ gross check of the Hurd interface version. It has the format YYYYMMDD
+ and will only ever be increased. This will be bumped whenever either
+ the RPC interfaces or the library APIs change. */
- 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. */
-
-#ifndef _HURD_VERSION_H
-#define _HURD_VERSION_H
-
-/* Each version of the Hurd defines a set of versions for the servers
- that make it up. Each server is identified by one of these
- structures. */
-struct hurd_server_version
-{
- char *name; /* The name of the server. */
- char *version; /* The server's version. */
-};
-
-/* A version of the Hurd is therefore defined by its version number
- (which is incremented for each distribution) and its release number
- (which refers to the interfaces in the hurd directory, and is found
- in <hurd/hurd_types.h> as HURD_RELEASE) and by a list of hurd_vers
- structures defining servers that were distributed with that
- version. */
-struct hurd_version
-{
- char *hurdrelease;
- char *hurdversion;
- int nservers;
- struct hurd_server_version vers[0];
-};
-
-#endif /* hurd/version.h */
-
-
-/* And these are the standard lists referred to above. */
-#ifdef HURD_VERSION_DEFINE
-
-struct hurd_version hurd_versions[] =
-{
- {
- /* Hurd version 0.0 pre-alpha; frozen May 3, 1996. */
- "0.0 pre-alpha",
- "0.0 pre-alpha",
- 5,
- {
- {"auth", "0.0 pre-alpha"},
- {"proc", "0.0 pre-alpha"},
- {"ufs", "0.0 pre-alpha"},
- {"init", "0.0 pre-alpha"},
- {"exec", "0.0 pre-alpha"},
- }
- },
- {
- /* Hurd version 0.0. Not frozen yet. */
- "0.0",
- "0.0",
- 5,
- {
- {"auth", "0.0"},
- {"proc", "0.0"},
- {"ufs", "0.0"},
- {"init", "0.0"},
- {"exec", "0.0"},
- }
- }
-};
-
-int nhurd_versions = sizeof hurd_versions / sizeof *hurd_versions;
-
-#endif
-
-
+#define HURD_INTERFACE_VERSION 20020609
diff --git a/include/ChangeLog b/include/ChangeLog
deleted file mode 100644
index 9110eea4..00000000
--- a/include/ChangeLog
+++ /dev/null
@@ -1,4 +0,0 @@
-Sat Jul 13 21:02:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile: New file.
-
diff --git a/include/Makefile b/include/Makefile
index f4113d99..3dc9ba75 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -1,5 +1,6 @@
-#
-# Copyright (C) 1996 Free Software Foundation, Inc.
+# Makefile for include subdirectory.
+#
+# Copyright (C) 1996, 2002, 2010 Free Software Foundation, Inc.
# Written by Michael I. Bushnell, p/BSG.
#
# This file is part of the GNU Hurd.
@@ -21,7 +22,16 @@
dir := include
makemode := misc
-DIST_FILES = $(notdir $(wildcard $(srcdir)/*.h))
+installhdrs := sys/procfs.h
+
+LCLHDRS := $(patsubst $(srcdir)/%,%,$(wildcard $(srcdir)/*.h $(srcdir)/*/*.h))
include ../Makeconf
+install-headers install: $(installhdrs:%=$(includedir)/%)
+$(includedir)/%: $(srcdir)/%
+ @$(MKINSTALLDIRS) $(@D)
+ $(INSTALL_DATA) $< $@
+
+lndist: $(top_srcdir)/hurd-snap/$(dir)
+ cp -r --parent $(addprefix $(srcdir)/, Makefile $(installhdrs)) $<
diff --git a/include/sys/procfs.h b/include/sys/procfs.h
new file mode 100644
index 00000000..ec82308b
--- /dev/null
+++ b/include/sys/procfs.h
@@ -0,0 +1,120 @@
+/* <sys/procfs.h> -- data structures describing ELF core file formats
+ Copyright (C) 2002 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_PROCFS_H
+#define _SYS_PROCFS_H 1
+
+/* This poorly-named file describes the format of the note segments in ELF
+ core files. It doesn't have anything to do with a `/proc' file system.
+
+ Anyway, the whole purpose of this file is for GDB and GDB only.
+ Don't read too much into it. Don't use it for anything other than
+ GDB unless you know what you are doing. */
+
+#include <features.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <ucontext.h>
+
+__BEGIN_DECLS
+
+/* This structure gives some general information about the process, things
+ that `ps' would tell you (hence the name). We have chosen the names and
+ the layout of the structure to coincide with the Solaris 8 definition.
+ The `file' program happens to know to look at 84 bytes into this
+ structure for the 16-byte `pr_fname' member, so we don't disappoint it. */
+#define ELF_PRARGSZ (80) /* Number of chars of argument list saved. */
+struct elf_psinfo
+{
+ int pr_flag; /* Meaningless flag bits. */
+ int pr_nlwp; /* Number of threads in this process. */
+ pid_t pr_pid; /* Process ID. */
+ pid_t pr_ppid; /* Parent's process ID. */
+ pid_t pr_pgid; /* Process group ID. */
+ pid_t pr_sid; /* Session ID. */
+ uid_t pr_uid, pr_euid; /* Real and effective UID (first one). */
+ gid_t pr_gid, pr_egid; /* Real and effective GID (first one). */
+ size_t pr_size; /* Virtual memory size of process (KB). */
+ size_t pr_rssize; /* Resident set size of process (KB). */
+ uint16_t pr_pctcpu; /* % of CPU used by all threads. */
+ uint16_t pr_pctmem; /* % of virtual memory used by process. */
+ struct timespec pr_start; /* Date & time of task creation. */
+ struct timespec pr_time; /* CPU time used by this process. */
+ struct timespec pr_ctime; /* CPU time used by dead children. */
+ uint32_t pr_reserved1[2]; /* Padding to place pr_psargs at offset 84. */
+ char pr_fname[16]; /* Initial part of executable file name. */
+ char pr_psargs[ELF_PRARGSZ]; /* Initial part of argument list. */
+ int pr_wstat; /* Zombie exit status (not really used). */
+ int pr_argc; /* The argument count at startup. */
+ uintptr_t pr_argv; /* Original argument vector address. */
+ uintptr_t pr_envp; /* Original environment vector address. */
+};
+typedef struct elf_psinfo psinfo_t;
+
+/* This structure also gives general information about the process.
+ The Solaris version gives the status of "the representative thread",
+ but GDB does not actually use this structure for anything but the PID. */
+struct elf_pstatus
+{
+ int pr_flags; /* Meaningless flags bits. */
+ int pr_nlwp; /* Number of threads in this process. */
+ pid_t pr_pid; /* Process ID. */
+ pid_t pr_ppid; /* Parent's process ID. */
+ pid_t pr_pgid; /* Process group ID. */
+ pid_t pr_sid; /* Session ID. */
+ struct timespec pr_utime; /* User CPU time used by this process. */
+ struct timespec pr_stime; /* System CPU time used by this process. */
+ struct timespec pr_cutime; /* User CPU time used by dead children. */
+ struct timespec pr_cstime; /* System CPU time used by dead children. */
+};
+typedef struct elf_pstatus pstatus_t;
+
+/* Information about a signal, the signal that killed the process. */
+struct elf_siginfo
+{
+ int si_signo; /* Signal number. */
+ int si_code; /* Extra code. */
+ int si_errno; /* Errno. */
+};
+
+typedef gregset_t prgregset_t;
+typedef fpregset_t prfpregset_t;
+
+/* This structure describes the state of one thread. GDB examines
+ pr_cursig to see what killed the process, so those are set in the
+ record for every thread. The `pr_lwpid' member contains a value
+ that is unique among the threads in this code file, but otherwise
+ meaningless. GDB examines that and the `pr_reg' and `pr_fpreg'
+ members for the register state of the thread. */
+struct elf_lwpstatus
+{
+ int pr_flags; /* Meaningless flags bits. */
+ int pr_lwpid; /* Identifies this thread from others. */
+ int pr_cursig; /* Signal that killed the thread. */
+ struct elf_siginfo pr_info; /* Details about the signal. */
+ prgregset_t pr_reg; /* State of thread's general registers. */
+ prfpregset_t pr_fpreg; /* State of its floating-point registers. */
+};
+typedef struct elf_lwpstatus lwpstatus_t;
+
+
+__END_DECLS
+
+#endif /* sys/procfs.h */
diff --git a/init/ChangeLog b/init/ChangeLog
deleted file mode 100644
index 5e1d8a2b..00000000
--- a/init/ChangeLog
+++ /dev/null
@@ -1,491 +0,0 @@
-Tue Jul 16 11:55:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (process_signal): Set WUNTRACED in call to waitpid.
-
-Sun Jul 7 21:18:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (init_stdarrays): Don't use unsafe MOVE_SEND in call to
- interruptible proc_setexecdata.
- (open_console): Likewise, for file_set_translator.
-
-Wed Jul 3 14:46:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (init): Add libports (because libfshelp.so requires it,
- lose lose lose).
-
- * init.c (process_signal) [case SIGCHLD]: Correctly place `break'
- *outside* of for loop.
-
-Mon Jul 1 18:07:56 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (process_signal): On SIGCHLD, keep reaping children until
- we get an error; tolerate all errors silently.
-
-Mon Jun 24 16:29:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (kill_multi_user): Kill user tasks before doing
- notify_shutdown.
-
-Fri Jun 21 16:17:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (open_console): Pass correct length of argument vector
- when setting active translators.
- <maptime.h>: New include.
- (open_console): Print error messages for /dev/console failures.
- Reduce the scope of some variables.
-
-Thu Jun 20 14:51:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (mapped_time): New variable.
- (launch_multi_user): Initialize mapped_time.
-
- * init.c (_PATH_RUNCOM): Move to /libexec/rc.
-
-Wed Jun 19 14:49:08 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (run_for_real): Doc fix.
- (startup_terminal): Deal properly if one of the run_for_real's
- fails.
- (launch_single_user): If the shell can't be started, crash the
- system.
- (process_rc_script): Return non-zero if run_for_real fails.
- (process_signal) [SIGCHLD]: If process_rc_script fails, go back to
- single-user.
- (S_startup_essential_task): Likewise.
- (init_ttys): Return non-zero if we fail.
- (startup_terminal): Return non-zero if we don't actually start
- anything.
- (startup_ttys): Return non-zero if we fail.
- (launch_multi_user): If init_ttys fails, go back to single. If we
- go multi, actually set system_state accordingly. If startup_ttys
- fails, go back to single.
- (init_ttys, reread_ttys): Test return value of setttyent
- correctly.
-
-Mon Jun 17 14:05:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (libutil-libsubst): Define (as -lutil); and link
- against -lutil.
- * init.c: Include <ttyent.h>, <argz.h>, and <utmp.h>.
- (add_terminal, init_ttys, free_ttys, startup_terminal,
- startup_ttys, find_line, reread_ttys, restart_terminal): New functions.
- (launch_multi_user): Use new functions to do things right.
- (session_pid): Delete variable.
- (kill_multi_user): Call free_ttys.
- (process_signal) [SIGHUP]: Call reread_ttys.
- [SIGCHLD/MULTI]: Call restart_terminal.
-
- * init.c (run_for_real): New arg `setsid'; only do setsid if it's
- set. All callers changed. Return the pid of the new program,
- not the task port. All callers changed.
-
- * Makefile (dir): Now init.
-
- * init.c: Include "mung_msg_S.h" instead of "msg_S.h".
- (S_msg_sig_post, S_msg_sig_post_untraced): Include SIGCODE parm.
- * Makefile (mung_msg_S.h): New rule.
-
-Mon Jun 17 00:17:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (run_for_real, open_console, process_signal, reboot_mach,
- run_for_real, run, reboot_system): Use error instead of fprintf.
- (notify_shutdown): Always emit terminating newline.
-
-Fri Jun 14 11:07:30 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c: Include <paths.h>, <error.h>, <sys/wait.h>, and
- <hurd/msg_reply.h>.
- (S_startup_essential_task): When all core servers have
- showed up, call launch_single_user only if RB_SINGLE; otherwise
- call process_rc_script. Call init_stdarrays here.
- (open_console): New function; massaged guts taken from
- launch_single_user. Be more verbose if we do something unusual.
- (launch_single_user): Call open_console. Don't call
- init_stdarrays here.
- (system_state, default_ints): New variables.
- (main): Initialize SYSTEM_STATE and DEFAULT_INTS.
- (run_for_real): Pass default_ints.
- (run): Likewise.
- (S_startup_essential_task): Delete var INITDONE; use SYSTEM_STATE
- instead.
- (launch_single_user): Set SYSTEM_STATE to SINGLE.
- (process_rc_script): New function.
- (launch_multi_user): New function.
- (kill_everyone): New function.
- (kill_multi_user): New function.
- (do_fastboot, rc_pid, session_pid): New variables.
- (process_signal): New function; guts from S_msg_sig_post_untraced.
- Handle state transitions here when programs exit. Process
- SIGTERM, and SIGHUP appropriately.
- (_PATH_RUNCOM, _PATH_LOGIN): New macros.
- (S_msg_sig_post_untraced): Only validate signal here; use
- process_signal to do the work, but reply first.
- (S_msg_sig_post): Likewise.
- (notify_shutdown): New function.
- (reboot_system): Use notify_shutdown.
-
-Wed Jun 12 16:01:17 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (S_startup_request_notification): Fill NT->name properly.
-
-Mon May 27 11:33:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Open TERM RDWR.
- Use openport to get FD from TERM.
- Print errno on assertion failure for FD.
-
-Fri May 24 12:29:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (reboot_mach): Insert a brief pause before actually
- rebooting the kernel so that the user has a chance to see any
- messages that may be displayed.
-
-Tue May 14 11:26:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (S_msg_get_exec_flags, S_msg_set_all_exec_flags,
- S_msg_set_some_exec_flags, S_msg_clear_some_exec_flags): Delete
- functions.
- (S_msg_describe_ports): New function.
-
- * init.c (reboot_system): Print prettier messages for shutdown
- notifications.
-
-Fri May 10 09:25:16 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c: <hurd/startup_notify.h> -> "startup_notify_U.h".
- * Makefile (OBJS): Add startup_notifyUser.o.
-
-Thu May 9 19:03:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (struct ntfy_task): New member `name'.
- (S_startup_request_notification): Expect and record name.
- (S_msg_startup_dosync): Delete function.
- Include <hurd/startup_notify.h>.
- (reboot_system): Use new startup_dosync interface.
-
- * init.c (init_stdarrays): Use new authentication interface.
-
-Mon May 6 14:25:02 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (init_version): Upgrade to 0.0.
-
-Mon Apr 29 16:49:18 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (reboot_system): Not quite yet, though.
-
-Sun Apr 28 19:15:30 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * init.c (reboot_system): Use 1 minute timeout on reply to
- msg_startup_dosync.
-
-Wed Apr 17 17:06:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Set an active, not passive,
- translator on /tmp/console, so it works with / read-only.
- * Makefile (init): Depend on libfshelp.
-
-Mon Mar 25 16:55:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (init): Add explicit dependency so that
- libshouldbeinlibc is included.
- * init.c: Include <wire.h>.
- (main): Delete declarations of _etext _edata, and __data_start.
- (main): Use new wire_task_self function instead of doing it ourselves.
-
-Tue Dec 19 18:29:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_core_servers, run_for_real): Call proc_mark_exec
- on child proc ports.
-
-Tue Dec 5 15:22:25 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Change initialization of TERMINAL
- to match new term driver arg syntax. Start terminal as ordinary
- passive translator instead of special weird kludge. Deleted
- variables foobiebletchcount, foobiebletch, and termtask.
-
-Sun Nov 5 02:03:33 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init.c (reboot_system): Add flags, noise, & noise_len params to
- proc_getprocinfo. Deallocate NOISE if necessary.
- (S_msg_report_wait): New function.
-
-Tue Oct 24 16:49:08 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Undo last change of 9Oct95.
-
-Mon Oct 9 04:29:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Pass dealloc args in file_exec calls.
-
-Thu Jul 6 15:34:23 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * init.c (S_msg_sig_post, S_msg_sig_post_untraced): Reverse order
- of these definitions.
-
- * init.c: Include <hurd/msg_server.h>.
- (reboot_mach): Insert extra parens around assignment inside while
- test.
- (launch_core_servers): Remove assignment from inside if test.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Thu Feb 9 17:18:21 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (S_msg_sig_post_untraced): Omit obnoxious "random child
- died" messages.
-
-Sat Jan 28 15:00:37 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Include "msg_S.h". Prepend `msg_' to msg.defs server
- functions. Add stubs for new msg.defs functions.
-
-Thu Jan 19 01:59:30 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c: Prepend `msg_' to names of msg.defs RPCs.
-
-Mon Nov 28 15:00:42 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (run_for_real): Print error msg if file_exec fails.
- (shell_pid): New variable.
- (demuxer): Also try msg_server.
- (launch_single_user): Open terminal O_RDWR and dup to 0, 1, 2.
- Set shell_pid after starting shell.
- (S_sig_post): New function; grok SIGCHLD and restart shell if
- shell_pid dies.
- * Makefile (OBJS): Add msgServer.o.
- (init.o): Depend on msg_S.h.
-
-Fri Nov 11 14:06:43 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * init.c (fakeboot): New variable.
- (STANDALONE): Deleted macro.
- (main): Set FAKEBOOT if -f was passed.
- (reboot_mach): Use FAKEBOOT flag instead of STANDALONE macro.
- (launch_core_servers): Likewise.
- (reboot_system): Likewise. Also don't exit here; let
- reboot_mach exit.
-
-Tue Nov 1 04:13:49 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (main): Use &_start for start of text to wire.
- (main): Use assert_perror in place of `assert (!err)'.
- (launch_single_user): Use _PATH_CONSOLE and _PATH_BSHELL instead
- of hardcoded strings.
- Check for error from io_stat on console, print message.
- Add #if 0'd code to prompt for shell name.
-
-Tue Sep 6 13:09:40 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Don't run device or pipes
- servers by default. Run terminal server inside /tmp if
- /dev/console isn't set up properly.
-
-Wed Aug 31 01:03:51 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Test TERMTASK as port, not boolean;
- if null, properly initialize TERM to MACH_PORT_NULL as well.
-
-Tue Aug 30 17:07:07 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c: Include <hurd/term.h>.
-
- * init.c (run): Use file_name_lookup instead of path_lookup.
- (launch_single_user): Likewise.
- (run_for_real): Likewise.
-
- * init.c (init_stdarrays): Use new authentication protocol.
-
-Mon Aug 22 16:44:11 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (run_for_real): If CTTY is set, then also put the process
- in its own login collection.
-
-Fri Aug 19 12:16:47 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (run_for_real): New arg `ctty'. All callers changed.
- If it's set, then set the new process's INIT_PORT_CTTYID
- accordingly, and change CTTY's owner to be the new process pgrp.
- (launch_single_user): Don't free TERM right away, only do it
- after we've passed it to run_for_real on the shell.
-
-Thu Aug 18 16:48:08 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (main): Print informative bootstrap messages.
- (launch_core_servers): Likewise.
- (launch_single_user): Likewise.
- (run): Don't print meaningless bootstrap clutter.
-
- * init.c (launch_single_user): Use task_info; it's less intrusive
- than task_suspend/task_resume.
-
- * init.c (launch_single_user): Run pipes before shell.
-
- * init.c (launch_single_user): Pause a bit to give term a chance
- to startup.
-
- * init.c (bootstrap_args): New variable.
- (main): Set `bootstrap_args' appropriately from argv[1].
- (prompt_for_servers): Deleted variable.
- (run): Use RB_INITNAME instead of prompt_for_servers.
- Only do `pausing' hack if RB_KDB is set.
- (run_for_real): Likewise.
-
- * init.c (main): Wire text and data segment soon after starting.
-
-Wed Aug 17 19:20:51 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (run_for_real): Call proc_setsid on new proc.
-
-Wed Aug 17 14:04:18 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (init_stdarrays): New function.
- (launch_single_user): Call init_stdarrays.
-
-Tue Aug 16 00:44:20 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Prompt whether to run term or dev.
-
- * init.c (main): Set default_ports[INIT_PORT_BOOTSTRAP] to STARTUP
- while running proc and auth, and then reset it to null.
-
-Mon Aug 15 23:16:24 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * init.c (launch_single_user): Use a volatile var to choose dev or
- term, so you can set it in gdb.
- (main): Set bootstrap port to MACH_PORT_NULL after fetching it.
- Don't set default_ports[INIT_PORT_BOOTSTRAP]; it should be nil.
-
-Mon Aug 15 11:40:34 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (launch_core_servers): Renamed from launch_system.
- Don't start dev, term, pipes, or shell here.
- (S_startup_procinit): Call launch_core_servers instead of
- launch_system.
- (S_startup_authinit): Likewise.
- (launch_single_user): New function.
- (S_startup_essential_task): Call launch_single_user once
- all the core servers have registered themselves here.
-
-Fri Aug 12 14:05:07 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (launch_system): Comment out use of dev for now.
-
-Thu Aug 11 12:25:32 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init.c (launch_system): Run dev instead of term.
-
-Thu Jul 21 17:45:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
- * init.c: Include "startup_reply_U.h instead of "startup_reply.h".
- (demuxer): Remove S_ from references to startup_server.
-
-Tue Jul 19 20:36:30 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * init.c (run_for_real): Moved unused var BUF inside #if 0 where used.
- (launch_system): Call proc_set_arg_locations, not proc_setprocargs.
-
-Tue Jul 19 12:44:56 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (init): Don't use variable $(link) anymore.
-
-Tue Jul 5 14:21:34 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): After terminal driver is running,
- reopen stdin so that we always read through it. Don't do
- output, because that (for reliability) shouldn't depend
- on the terminal driver.
- (main): Open stdin separately from stdout/stderr.
-
- * Makefile (SRCS): New variable.
-
-Fri Jul 1 11:19:46 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (run_for_real): Return the task we created. All callers
- changed.
-
-Tue Jun 21 14:08:37 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Correct first arg to pipes.
-
-Mon Jun 20 15:06:19 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Look for pipes in /hurd/pipes, not
- /bin/pipes.
-
- * init.c (run_for_real): Comment out old code that prompts user;
- abandon attempt if we can't run something.
-
- * Makefile (install): Use $(INSTALL_BIN) instead of cp.
-
-Fri Jun 17 00:13:50 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * init.c (demuxer): Use S_startup_server instead of startup_server.
-
-Wed Jun 15 18:14:59 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (launch_system): Start pipes server after starting shell.
-
- * init.c (run_for_real): New parms ARGS and ARGLEN. All callers
- changed.
-
-Tue May 24 02:20:55 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Start the shell before doing proc_setmsgport.
-
-Tue May 24 00:05:43 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Call proc_setmsgport before fsys_init.
-
-Mon May 16 14:43:47 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (reboot_system): Restore bits commented out on May 12;
- the proc bug responsible has been fixed.
-
-Fri May 13 14:59:12 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Make sure the auth server's proc state
- is correct *before* calling startup_authinit_reply.
-
-Thu May 12 15:13:10 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (reboot_system): Comment out bits checking to see
- if the procserver has died; they aren't quite right.
-
- * init.c (S_startup_essential_task): Don't take over the exception
- port of the task right now; this interferes with things too much.
-
-Thu May 12 02:22:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * init.c (launch_system): Don't call _hurd_proc_init; just call
- proc_setprocargs ourselves.
- (launch_system): Do proc_setmsgport last.
- (run, run_for_real): Pass argv[0] with name of program.
-
-Mon May 9 14:30:11 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (init_version): New variable.
- (launch_system): Call proc_register_version; don't call
- proc_setprocargs (which is done by _hurd_proc_init). Give
- correct argument to _hurd_proc_init.
-
- * init.c (S_startup_register_version, S_startup_uname): Deleted.
-
-Fri May 6 13:01:04 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c (S_startup_register_version, S_startup_uname):
- New functions (temporary only).
-
-Thu May 5 19:15:39 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * init.c: Include <hurd/msg.h> for prototype of startup_dosync.
- Change return types of MiG stubs to be kern_return_t.
- (S_startup_essential_task): Expect new arg CREDENTIAL and
- validate it.
-
-Thu May 5 07:44:21 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
diff --git a/init/Makefile b/init/Makefile
index 91e3e16b..ffb82ffd 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1994,95,96,99,2001 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
@@ -18,16 +18,14 @@
dir := init
makemode := server
-SRCS = init.c
-OBJS = init.o startupServer.o notifyServer.o startup_replyUser.o msgServer.o \
- startup_notifyUser.o
+SRCS = init.c stubs.c
+OBJS = $(SRCS:.c=.o) \
+ startupServer.o notifyServer.o startup_replyUser.o msgServer.o \
+ startup_notifyUser.o
target = init
-libutil-libsubst = -lutil
+HURDLIBS = shouldbeinlibc
-init: $(OBJS) ../libports/libports.a ../libfshelp/libfshelp.a ../libshouldbeinlibc/libshouldbeinlibc.a -lutil
+include ../Makeconf
mung_msg_S.h: msg_S.h
sed 's/msg_server/mung_msg_server/' < $< > $@
-
-include ../Makeconf
-
diff --git a/init/init.c b/init/init.c
index 58a33410..d66bee0b 100644
--- a/init/init.c
+++ b/init/init.c
@@ -1,21 +1,22 @@
-/* Somewhat primitive version of init
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+/* Start and maintain hurd core servers and system run state
-This file is part of the GNU Hurd.
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2005, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU Hurd.
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell and Roland McGrath. */
@@ -38,17 +39,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/term.h>
#include <hurd/fshelp.h>
#include <paths.h>
-#include <sys/wait.h>
+#include <sys/mman.h>
#include <hurd/msg_server.h>
#include <wire.h>
-#include <paths.h>
#include <sys/wait.h>
#include <error.h>
#include <hurd/msg_reply.h>
-#include <ttyent.h>
#include <argz.h>
-#include <utmp.h>
#include <maptime.h>
+#include <version.h>
+#include <argp.h>
#include "startup_notify_U.h"
#include "startup_reply_U.h"
@@ -57,25 +57,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "mung_msg_S.h"
/* host_reboot flags for when we crash. */
-#define CRASH_FLAGS RB_AUTOBOOT
+static int crash_flags = RB_AUTOBOOT;
#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot")
-#define _PATH_RUNCOM "/libexec/rc"
-#define _PATH_LOGIN "/bin/login"
-
-/* How long to wait after starting window specs before starting getty */
-#define WINDOW_DELAY 3 /* seconds */
-
+
+const char *argp_program_version = STANDARD_HURD_VERSION (init);
-/* Current state of the system. */
-enum
+static struct argp_option
+options[] =
{
- INITIAL,
- SINGLE,
- RUNCOM,
- MULTI,
-} system_state;
+ {"single-user", 's', 0, 0, "Startup system in single-user mode"},
+ {"query", 'q', 0, 0, "Ask for the names of servers to start"},
+ {"init-name", 'n', 0, 0 },
+ {"crash-debug", 'H', 0, 0, "On system crash, go to kernel debugger"},
+ {"debug", 'd', 0, 0 },
+ {"fake-boot", 'f', 0, 0, "This hurd hasn't been booted on the raw machine"},
+ {0, 'x', 0, OPTION_HIDDEN},
+ {0}
+};
+
+static char doc[] = "Start and maintain hurd core servers and system run state";
+
+static int booted; /* Set when the core servers are up. */
/* This structure keeps track of each notified task. */
struct ntfy_task
@@ -94,78 +98,46 @@ struct ess_task
};
/* These are linked lists of all of the registered items. */
-struct ess_task *ess_tasks;
-struct ntfy_task *ntfy_tasks;
-
-/* Mapped time */
-volatile struct mapped_time_value *mapped_time;
-
-/* All the ttys in /etc/ttys. */
-struct terminal
-{
- /* argz list for getty */
- char *getty_argz;
- size_t getty_argz_len;
-
- /* argz list for window spec */
- char *window_argz;
- size_t window_argz_len;
-
- int on;
- int pid;
-
- char *name;
-};
-
-struct terminal *ttys;
-/* Number of live elements in ttys */
-int nttys;
-/* Total number of elements in ttys */
-int ttyslen;
+static struct ess_task *ess_tasks;
+static struct ntfy_task *ntfy_tasks;
/* Our receive right */
-mach_port_t startup;
+static mach_port_t startup;
/* Ports to the kernel */
-mach_port_t host_priv, device_master;
+static mach_port_t host_priv, device_master;
/* Args to bootstrap, expressed as flags */
-int bootstrap_args;
-
-/* Set if something determines we should no longer pass the `autoboot'
- flag to _PATH_RUNCOM. */
-int do_fastboot;
+static int bootstrap_args = 0;
/* Stored information for returning proc and auth startup messages. */
-mach_port_t procreply, authreply;
-mach_msg_type_name_t procreplytype, authreplytype;
+static mach_port_t procreply, authreply;
+static mach_msg_type_name_t procreplytype, authreplytype;
/* Our ports to auth and proc. */
-mach_port_t authserver;
-mach_port_t procserver;
+static mach_port_t authserver;
+static mach_port_t procserver;
/* Our bootstrap port, on which we call fsys_getpriv and fsys_init. */
-mach_port_t bootport;
+static mach_port_t bootport;
/* Set iff we are a `fake' bootstrap. */
-int fakeboot;
+static int fakeboot;
/* The tasks of auth and proc and the bootstrap filesystem. */
-task_t authtask, proctask, fstask;
-
-char *init_version = "0.0";
+static task_t authtask, proctask, fstask;
-mach_port_t default_ports[INIT_PORT_MAX];
-mach_port_t default_dtable[3];
-int default_ints[INIT_INT_MAX];
-
-char **global_argv;
-
-pid_t shell_pid; /* PID of single-user shell. */
-pid_t rc_pid; /* PID of rc script */
+static mach_port_t default_ports[INIT_PORT_MAX];
+static mach_port_t default_dtable[3];
+static int default_ints[INIT_INT_MAX];
+static char **global_argv;
+static char *startup_envz;
+static size_t startup_envz_len;
+void launch_system (void);
+void process_signal (int signo);
/** Utility functions **/
@@ -199,12 +171,13 @@ reboot_mach (int flags)
}
else
{
+ error_t err;
printf ("%s: %sing Mach (flags %#x)...\n",
program_invocation_short_name, BOOT (flags), flags);
fflush (stdout);
sleep (5);
- while ((errno = host_reboot (host_priv, flags)))
- error (0, errno, "reboot");
+ while ((err = host_reboot (host_priv, flags)))
+ error (0, err, "reboot");
for (;;);
}
}
@@ -213,19 +186,19 @@ reboot_mach (int flags)
void
crash_mach (void)
{
- reboot_mach (CRASH_FLAGS);
+ reboot_mach (crash_flags);
}
/* Notify all tasks that have requested shutdown notifications */
void
-notify_shutdown (char *msg)
+notify_shutdown (const char *msg)
{
struct ntfy_task *n;
for (n = ntfy_tasks; n != NULL; n = n->next)
{
error_t err;
- printf ("%s: notifying %s of %s...",
+ printf ("%s: notifying %s of %s...",
program_invocation_short_name, n->name, msg);
fflush (stdout);
err = startup_dosync (n->notify_port, 60000); /* 1 minute to reply */
@@ -237,7 +210,7 @@ notify_shutdown (char *msg)
puts ("done");
fflush (stdout);
}
-}
+}
/* Reboot the Hurd. */
void
@@ -248,7 +221,7 @@ reboot_system (int flags)
if (fakeboot)
{
pid_t *pp;
- u_int npids = 0;
+ size_t npids = 0;
error_t err;
int ind;
@@ -278,11 +251,13 @@ reboot_system (int flags)
if (task != mach_task_self () && task != proctask)
{
struct procinfo *pi = 0;
- u_int pisize = 0;
+ size_t pisize = 0;
char *noise;
- unsigned noise_len;
- err = proc_getprocinfo (procserver, pp[ind], 0,
- (int **)&pi, &pisize, &noise,&noise_len);
+ size_t noise_len = 0;
+ int flags;
+ err = proc_getprocinfo (procserver, pp[ind], &flags,
+ (int **)&pi, &pisize,
+ &noise, &noise_len);
if (err == MACH_SEND_INVALID_DEST)
goto procbad;
if (err)
@@ -298,8 +273,7 @@ reboot_system (int flags)
task_terminate (task);
}
if (noise_len > 0)
- vm_deallocate (mach_task_self (),
- (vm_address_t)noise, noise_len);
+ munmap (noise, noise_len);
}
}
printf ("%s: Killing proc server\n", program_invocation_short_name);
@@ -315,21 +289,64 @@ reboot_system (int flags)
void
crash_system (void)
{
- reboot_system (CRASH_FLAGS);
+ reboot_system (crash_flags);
}
+/* Request a dead-name notification sent to our port. */
+static void
+request_dead_name (mach_port_t name)
+{
+ mach_port_t prev;
+ mach_port_request_notification (mach_task_self (), name,
+ MACH_NOTIFY_DEAD_NAME, 1, startup,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
+ if (prev != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), prev);
+}
+
+/* Record an essential task in the list. */
+static error_t
+record_essential_task (const char *name, task_t task)
+{
+ struct ess_task *et;
+ /* Record this task as essential. */
+ et = malloc (sizeof (struct ess_task));
+ if (et == NULL)
+ return ENOMEM;
+ et->task_port = task;
+ et->name = strdup (name);
+ if (et->name == NULL)
+ {
+ free (et);
+ return ENOMEM;
+ }
+ et->next = ess_tasks;
+ ess_tasks = et;
+
+ /* Dead-name notification on the task port will tell us when it dies. */
+ request_dead_name (task);
+
+#if 0
+ /* Taking over the exception port will give us a better chance
+ if the task tries to get wedged on a fault. */
+ task_set_special_port (task, TASK_EXCEPTION_PORT, startup);
+#endif
+
+ return 0;
+}
+
/** Starting programs **/
/* Run SERVER, giving it INIT_PORT_MAX initial ports from PORTS.
Set TASK to be the task port of the new image. */
void
-run (char *server, mach_port_t *ports, task_t *task)
+run (const char *server, mach_port_t *ports, task_t *task)
{
char buf[BUFSIZ];
- char *prog = server;
+ const char *prog = server;
if (bootstrap_args & RB_INITNAME)
{
@@ -341,35 +358,34 @@ run (char *server, mach_port_t *ports, task_t *task)
while (1)
{
file_t file;
+ error_t err;
file = file_name_lookup (prog, O_EXEC, 0);
if (file == MACH_PORT_NULL)
error (0, errno, "%s", prog);
else
{
- char *progname;
- task_create (mach_task_self (), 0, task);
+ task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, task);
if (bootstrap_args & RB_KDB)
{
printf ("Pausing for %s\n", prog);
getchar ();
}
- progname = strrchr (prog, '/');
- if (progname)
- ++progname;
- else
- progname = prog;
- errno = file_exec (file, *task, 0,
- progname, strlen (progname) + 1, /* Args. */
- "", 1, /* No env. */
- default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
- ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
- default_ints, INIT_INT_MAX,
- NULL, 0, NULL, 0);
- if (!errno)
+ err = file_exec (file, *task, 0,
+ (char *)prog, strlen (prog) + 1, /* Args. */
+ startup_envz, startup_envz_len,
+ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
+ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+ default_ints, INIT_INT_MAX,
+ NULL, 0, NULL, 0);
+ if (!err)
break;
- error (0, errno, "%s", prog);
+ error (0, err, "%s", prog);
}
printf ("File name for server %s (or nothing to reboot): ", server);
@@ -383,6 +399,10 @@ run (char *server, mach_port_t *ports, task_t *task)
printf ("started %s\n", prog);
fflush (stdout);
#endif
+
+ /* Dead-name notification on the task port will tell us when it dies,
+ so we can crash if we don't make it to a fully bootstrapped Hurd. */
+ request_dead_name (*task);
}
/* Run FILENAME as root with ARGS as its argv (length ARGLEN). Return
@@ -391,7 +411,7 @@ run (char *server, mach_port_t *ports, task_t *task)
collection. If SETSID is set, put it in a new session. Return
0 if the task was not created successfully. */
pid_t
-run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
+run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
int setsid)
{
file_t file;
@@ -408,20 +428,24 @@ run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
if (getstring (buf, sizeof (buf)) && *buf)
filename = buf;
file = file_name_lookup (filename, O_EXEC, 0);
- if (!file)
+ if (file == MACH_PORT_NULL)
error (0, errno, "%s", filename);
}
- while (!file);
+ while (file == MACH_PORT_NULL);
#else
file = file_name_lookup (filename, O_EXEC, 0);
- if (!file)
+ if (file == MACH_PORT_NULL)
{
error (0, errno, "%s", filename);
return 0;
}
#endif
- task_create (mach_task_self (), 0, &task);
+ task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &task);
proc_child (procserver, task);
proc_task2pid (procserver, task, &pid);
proc_task2proc (procserver, task, &default_ports[INIT_PORT_PROC]);
@@ -446,7 +470,7 @@ run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
progname = filename;
err = file_exec (file, task, 0,
args, arglen,
- NULL, 0, /* No env. */
+ startup_envz, startup_envz_len,
default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
default_ports, MACH_MSG_TYPE_COPY_SEND,
INIT_PORT_MAX,
@@ -469,237 +493,9 @@ run_for_real (char *filename, char *args, int arglen, mach_port_t ctty,
return pid;
}
-
-
-
-/** /etc/ttys support **/
-
-
-/* Add a new terminal spec for TT and return it. */
-struct terminal *
-add_terminal (struct ttyent *tt)
-{
- struct terminal *t;
- char *line;
-
- if (nttys >= ttyslen)
- {
- ttys = realloc (ttys, (ttyslen * 2) * sizeof (struct ttyent));
- bzero (&ttys[nttys], ttyslen);
- ttyslen *= 2;
- }
-
- t = &ttys[nttys];
- nttys++;
-
- t->name = malloc (strlen (tt->ty_name) + 1);
- strcpy (t->name, tt->ty_name);
-
- if (t->getty_argz)
- free (t->getty_argz);
- if (t->window_argz)
- free (t->window_argz);
-
- if ((tt->ty_status & TTY_ON) && tt->ty_getty)
- {
- asprintf (&line, "%s %s", tt->ty_getty, tt->ty_name);
- argz_create_sep (line, ' ', &t->getty_argz, &t->getty_argz_len);
- if (tt->ty_window)
- argz_create_sep (tt->ty_window, ' ',
- &t->window_argz, &t->window_argz_len);
- else
- t->window_argz = 0;
- t->on = 1;
- }
- else
- {
- t->getty_argz = t->window_argz = 0;
- t->on = 0;
- }
- return t;
-}
-
-
-/* Read /etc/ttys and initialize ttys array. Return non-zero if we fail. */
-int
-init_ttys (void)
-{
- struct ttyent *tt;
-
- ttyslen = 10;
- nttys = 0;
-
- ttys = malloc (ttyslen * sizeof (struct ttyent));
- bzero (ttys, ttyslen * sizeof (struct ttyent));
-
- if (!setttyent ())
- {
- error (0, errno, "%s", _PATH_TTYS);
- return 1;
- }
- while ((tt = getttyent ()))
- {
- if (!tt->ty_name)
- continue;
-
- add_terminal (tt);
- }
-
- endttyent ();
- return 0;
-}
-
-/* Free everyting in the terminal array */
-void
-free_ttys (void)
-{
- int i;
-
- for (i = 0; i < nttys; i++)
- {
- if (ttys[i].getty_argz)
- free (ttys[i].getty_argz);
- if (ttys[i].window_argz)
- free (ttys[i].window_argz);
- free (ttys[i].name);
- }
- free (ttys);
-}
-
-/* Start line T. Return non-zero if we didn't actually start anything. */
-int
-startup_terminal (struct terminal *t)
-{
- pid_t pid;
- assert (t->on);
- assert (t->getty_argz);
-
- if (t->window_argz)
- {
- pid = run_for_real (t->window_argz, t->window_argz,
- t->window_argz_len, MACH_PORT_NULL, 1);
- if (!pid)
- goto error;
-
- sleep (WINDOW_DELAY);
- }
-
- pid = run_for_real (t->getty_argz, t->getty_argz,
- t->getty_argz_len, MACH_PORT_NULL, 0);
- if (pid == 0)
- {
- error:
- t->pid = 0;
- t->on = 0;
- return 1;
- }
- else
- {
- t->pid = pid;
- return 0;
- }
-}
-
-/* For each line in /etc/ttys, start up the specified program. Return
- non-zero if we fail. */
-int
-startup_ttys (void)
-{
- int i;
- int didone, fail;
-
- didone = 0;
-
- for (i = 0; i < nttys; i++)
- if (ttys[i].on)
- {
- fail = startup_terminal (&ttys[i]);
- if (!fail)
- didone = 1;
- }
- return !didone;
-}
-
-/* Find the terminal spec corresponding to line LINE. */
-struct terminal *
-find_line (char *line)
-{
- int i;
-
- for (i = 0; i < nttys; i++)
- if (!strcmp (ttys[i].name, line))
- return &ttys[i];
- return 0;
-}
-
-/* PID has just exited; restart the terminal it's on if necessary. */
-void
-restart_terminal (int pid)
-{
- int i;
-
- for (i = 0; i < nttys; i++)
- if (pid == ttys[i].pid)
- {
- if (logout (ttys[i].name))
- logwtmp (ttys[i].name, "", "");
- ttys[i].pid = 0;
- if (ttys[i].on)
- startup_terminal (&ttys[i]);
- }
-}
-
-/* Re-read /etc/ttys. If a line has turned off, kill what's there.
- If a line has turned on, start it. If an on line has changed,
- kill it, and then restart it. */
-void
-reread_ttys (void)
-{
- struct ttyent *tt;
- struct terminal *t;
- int on;
-
- if (!setttyent ())
- {
- error (0, errno, "%s", _PATH_TTYS);
- return;
- }
-
- while ((tt = getttyent ()))
- {
- if (!tt->ty_name)
- continue;
-
- t = find_line (tt->ty_name);
- on = tt->ty_getty && (tt->ty_status & TTY_ON);
-
- if (t)
- {
- if (t->on && !on)
- {
- t->on = 0;
- kill (t->pid, SIGHUP);
- }
- else if (!t->on && on)
- {
- t->on = 1;
- startup_terminal (t);
- }
- }
- else
- {
- t = add_terminal (tt);
- if (on)
- startup_terminal (t);
- }
- }
- endttyent ();
-}
-
/** Main program and setup **/
-
static int
demuxer (mach_msg_header_t *inp,
mach_msg_header_t *outp)
@@ -711,32 +507,46 @@ demuxer (mach_msg_header_t *inp,
startup_server (inp, outp));
}
+static int
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'q': bootstrap_args |= RB_ASKNAME; break;
+ case 's': bootstrap_args |= RB_SINGLE; break;
+ case 'd': bootstrap_args |= RB_KDB; break;
+ case 'n': bootstrap_args |= RB_INITNAME; break;
+ case 'f': fakeboot = 1; break;
+ case 'H': crash_flags = RB_DEBUGGER; break;
+ case 'x': /* NOP */ break;
+ default: return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
int
main (int argc, char **argv, char **envp)
{
volatile int err;
int i;
+ int flags;
mach_port_t consdev;
+ struct argp argp = { options, parse_opt, 0, doc };
- global_argv = argv;
+ /* Parse the arguments. We don't want the vector reordered, we
+ should pass on to our child the exact arguments we got and just
+ ignore any arguments that aren't flags for us. ARGP_NO_ERRS
+ suppresses --help and --version, so we only use that option if we
+ are booting. */
+ flags = ARGP_IN_ORDER;
+ if (getpid () == 0)
+ flags |= ARGP_NO_ERRS;
+ argp_parse (&argp, argc, argv, flags, 0, 0);
- system_state = INITIAL;
+ if (getpid () > 0)
+ error (2, 0, "can only be run by bootstrap filesystem");
- /* Parse the arguments */
- bootstrap_args = 0;
- if (argc >= 2)
- {
- if (index (argv[1], 'q'))
- bootstrap_args |= RB_ASKNAME;
- if (index (argv[1], 's'))
- bootstrap_args |= RB_SINGLE;
- if (index (argv[1], 'd'))
- bootstrap_args |= RB_KDB;
- if (index (argv[1], 'n'))
- bootstrap_args |= RB_INITNAME;
- if (index (argv[1], 'f'))
- fakeboot = 1;
- }
+ global_argv = argv;
/* Fetch a port to the bootstrap filesystem, the host priv and
master device ports, and the console. */
@@ -756,6 +566,9 @@ main (int argc, char **argv, char **envp)
crash_mach ();
setbuf (stdout, NULL);
+ err = argz_create (envp, &startup_envz, &startup_envz_len);
+ assert_perror (err);
+
/* At this point we can use assert to check for errors. */
err = mach_port_allocate (mach_task_self (),
MACH_PORT_RIGHT_RECEIVE, &startup);
@@ -764,6 +577,9 @@ main (int argc, char **argv, char **envp)
MACH_MSG_TYPE_MAKE_SEND);
assert_perror (err);
+ /* Crash if the boot filesystem task dies. */
+ request_dead_name (fstask);
+
/* Set up the set of ports we will pass to the programs we exec. */
for (i = 0; i < INIT_PORT_MAX; i++)
switch (i)
@@ -788,7 +604,7 @@ main (int argc, char **argv, char **envp)
not run under job control shells are protected. */
default_ints[INIT_SIGIGN] = (sigmask (SIGTSTP)
| sigmask (SIGTTIN)
- | sigmask (SIGTTOU));
+ | sigmask (SIGTTOU));
default_ports[INIT_PORT_BOOTSTRAP] = startup;
run ("/hurd/proc", default_ports, &proctask);
@@ -812,7 +628,8 @@ void
launch_core_servers (void)
{
mach_port_t old;
- mach_port_t authproc, fsproc;
+ mach_port_t authproc, fsproc, procproc;
+ error_t err;
/* Reply to the proc and auth servers. */
startup_procinit_reply (procreply, procreplytype, 0,
@@ -834,7 +651,8 @@ launch_core_servers (void)
proc_task2proc (procserver, authtask, &authproc);
proc_mark_exec (authproc);
startup_authinit_reply (authreply, authreplytype, 0, authproc,
- MACH_MSG_TYPE_MOVE_SEND);
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), authproc);
/* Give the library our auth and proc server ports. */
_hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
@@ -848,8 +666,16 @@ launch_core_servers (void)
default_ports[INIT_PORT_AUTH] = authserver;
- proc_register_version (procserver, host_priv, "init", HURD_RELEASE,
- init_version);
+ /* Declare that the proc server is our child. */
+ proc_child (procserver, proctask);
+ err = proc_task2proc (procserver, proctask, &procproc);
+ if (!err)
+ {
+ proc_mark_exec (procproc);
+ mach_port_deallocate (mach_task_self (), procproc);
+ }
+
+ proc_register_version (procserver, host_priv, "init", "", HURD_VERSION);
/* Get the bootstrap filesystem's proc server port.
We must do this before calling proc_setmsgport below. */
@@ -874,9 +700,10 @@ launch_core_servers (void)
mach_port_deallocate (mach_task_self (), old);
/* Give the bootstrap FS its proc and auth ports. */
- errno = fsys_init (bootport, fsproc, MACH_MSG_TYPE_MOVE_SEND, authserver);
- if (errno)
- error (0, errno, "fsys_init"); /* Not necessarily fatal. */
+ err = fsys_init (bootport, fsproc, MACH_MSG_TYPE_COPY_SEND, authserver);
+ mach_port_deallocate (mach_task_self (), fsproc);
+ if (err)
+ error (0, err, "fsys_init"); /* Not necessarily fatal. */
}
/* Set up the initial value of the standard exec data. */
@@ -899,6 +726,8 @@ init_stdarrays ()
__USEPORT (AUTH, auth_makeauth (port, 0, MACH_MSG_TYPE_COPY_SEND, 0,
0, 0, 0, 0, 0, 0, 0, 0, &nullauth));
+ /* MAKE_SEND is safe in these transactions because we destroy REF
+ ourselves each time. */
pt = getcwdir ();
ref = mach_reply_port ();
io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND);
@@ -926,444 +755,359 @@ init_stdarrays ()
mach_port_deallocate (mach_task_self (), std_port_array[i]);
}
-/* Open /dev/console. If it isn't there, or it isn't a terminal, then
- create /tmp/console and put the terminal on it. If we get EROFS,
- in trying to create /tmp/console then as a last resort, put the
- console on /tmp itself.
-
- In any case, after the console has been opened, set it appropriately
- in default_dtable. Also return a port right for the terminal. */
-file_t
-open_console ()
+/* Frobnicate the kernel task and the proc server's idea of it (PID 2),
+ so the kernel command line can be read as for a normal Hurd process. */
+
+void
+frob_kernel_process (void)
{
-#define TERMINAL_FIRST_TRY "/hurd/term\0/tmp/console\0device\0console"
-#define TERMINAL_SECOND_TRY "/hurd/term\0/tmp\0device\0console"
- mach_port_t term;
- static char *termname;
- struct stat st;
- error_t err = 0;
-
- if (system_state != INITIAL)
+ error_t err;
+ int argc, i;
+ char *argz, *entry;
+ size_t argzlen;
+ size_t windowsz;
+ vm_address_t mine, his;
+ task_t task;
+ process_t proc, kbs;
+
+ err = proc_pid2task (procserver, 2, &task);
+ if (err)
{
- term = file_name_lookup (termname, O_RDWR, 0);
- return term;
+ error (0, err, "cannot get kernel task port");
+ return;
}
+ err = proc_task2proc (procserver, task, &proc);
+ if (err)
+ {
+ error (0, err, "cannot get kernel task's proc server port");
+ mach_port_deallocate (mach_task_self (), task);
+ return;
+ }
+
+ /* Mark the kernel task as an essential task so that we never
+ want to task_terminate it. */
+ err = record_essential_task ("kernel", task);
+ assert_perror (err);
- termname = _PATH_CONSOLE;
- term = file_name_lookup (termname, O_RDWR, 0);
- if (term != MACH_PORT_NULL)
- err = io_stat (term, &st);
+ err = task_get_bootstrap_port (task, &kbs);
+ assert_perror (err);
+ if (kbs == MACH_PORT_NULL)
+ {
+ /* The kernel task has no bootstrap port set, so we are presumably
+ the first Hurd to boot. Install the kernel task's proc port from
+ this Hurd's proc server as the task bootstrap port. Additional
+ Hurds will see this. */
+
+ err = task_set_bootstrap_port (task, proc);
+ if (err)
+ error (0, err, "cannot set kernel task's bootstrap port");
+
+ if (fakeboot)
+ error (0, 0, "warning: --fake-boot specified but I see no other Hurd");
+ }
else
- err = errno;
- if (err)
- error (0, err, "%s", termname);
- else if (st.st_fstype != FSTYPE_TERM)
- error (0, 0, "%s: Not a terminal", termname);
-
- if (term == MACH_PORT_NULL || err || st.st_fstype != FSTYPE_TERM)
- /* Start the terminal server ourselves. */
{
- size_t argz_len; /* Length of args passed to translator. */
- char *terminal; /* Name of term translator. */
- mach_port_t control; /* Control port for term translator. */
- int try = 1;
-
- error_t open_node (int flags,
- mach_port_t *underlying,
- mach_msg_type_name_t *underlying_type)
+ /* The kernel task has a bootstrap port set. Perhaps it is its proc
+ server port from another Hurd. If so, propagate the kernel
+ argument locations from that Hurd rather than diddling with the
+ kernel task ourselves. */
+
+ vm_address_t kargv, kenvp;
+ err = proc_get_arg_locations (kbs, &kargv, &kenvp);
+ mach_port_deallocate (mach_task_self (), kbs);
+ if (err)
+ error (0, err, "kernel task bootstrap port (ignoring)");
+ else
{
- term = file_name_lookup (termname, flags | O_CREAT|O_NOTRANS, 0666);
- if (term == MACH_PORT_NULL)
+ err = proc_set_arg_locations (proc, kargv, kenvp);
+ if (err)
+ error (0, err, "cannot propagate original kernel command line");
+ else
{
- error (0, errno, "%s", termname);
- return errno;
+ mach_port_deallocate (mach_task_self (), proc);
+ mach_port_deallocate (mach_task_self (), task);
+ if (! fakeboot)
+ error (0, 0, "warning: "
+ "I see another Hurd, but --fake-boot was not given");
+ return;
}
-
- *underlying = term;
- *underlying_type = MACH_MSG_TYPE_COPY_SEND;
-
- return 0;
}
+ }
- retry:
- bootstrap_args |= RB_SINGLE;
+ /* Our arguments make up the multiboot command line used to boot the
+ kernel. We'll write into the kernel task a page containing a
+ canonical argv array and argz of those words. */
- if (try == 1)
- {
- terminal = TERMINAL_FIRST_TRY;
- argz_len = sizeof TERMINAL_FIRST_TRY;
- try = 2;
- }
- else if (try == 2)
- {
- terminal = TERMINAL_SECOND_TRY;
- argz_len = sizeof TERMINAL_SECOND_TRY;
- try = 3;
- }
- else
- goto fail;
-
- termname = terminal + strlen (terminal) + 1; /* first arg is name */
-
- /* The callback to start_translator opens TERM as a side effect. */
- errno =
- fshelp_start_translator (open_node, terminal, terminal, argz_len, 3000,
- &control);
- if (errno)
- {
- error (0, errno, "%s", terminal);
- goto retry;
- }
-
- errno = file_set_translator (term, 0, FS_TRANS_SET, 0, 0, 0,
- control, MACH_MSG_TYPE_COPY_SEND);
- mach_port_deallocate (mach_task_self (), control);
- if (errno)
- {
- error (0, errno, "%s", termname);
- goto retry;
- }
- mach_port_deallocate (mach_task_self (), term);
-
- /* Now repeat the open. */
- term = file_name_lookup (termname, O_RDWR, 0);
- if (term == MACH_PORT_NULL)
- {
- error (0, errno, "%s", termname);
- goto retry;
- }
- errno = io_stat (term, &st);
- if (errno)
- {
- error (0, errno, "%s", termname);
- term = MACH_PORT_NULL;
- goto retry;
- }
- if (st.st_fstype != FSTYPE_TERM)
- {
- error (0, 0, "%s: Not a terminal", termname);
- term = MACH_PORT_NULL;
- goto retry;
- }
+ err = argz_create (&global_argv[1], &argz, &argzlen);
+ assert_perror (err);
+ argc = argz_count (argz, argzlen);
+
+ windowsz = round_page (((argc + 1) * sizeof (char *)) + argzlen);
- if (term)
- error (0, 0, "Using temporary console %s", termname);
+ mine = (vm_address_t) mmap (0, windowsz, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ assert (mine != -1);
+ err = vm_allocate (task, &his, windowsz, 1);
+ if (err)
+ {
+ error (0, err, "cannot allocate %Zu bytes in kernel task", windowsz);
+ free (argz);
+ mach_port_deallocate (mach_task_self (), proc);
+ mach_port_deallocate (mach_task_self (), task);
+ munmap ((caddr_t) mine, windowsz);
+ return;
}
- fail:
+ for (i = 0, entry = argz; entry != NULL;
+ ++i, entry = argz_next (argz, argzlen, entry))
+ ((char **) mine)[i] = ((char *) &((char **) his)[argc + 1]
+ + (entry - argz));
+ ((char **) mine)[argc] = NULL;
+ memcpy (&((char **) mine)[argc + 1], argz, argzlen);
- /* At this point either TERM is the console or it's null. If it's
- null, then don't do anything, and our fd's will be copied.
- Otherwise, open fd's 0, 1, and 2. */
- if (term != MACH_PORT_NULL)
+ free (argz);
+
+ /* We have the data all set up in our copy, now just write it over. */
+ err = vm_write (task, his, mine, windowsz);
+ mach_port_deallocate (mach_task_self (), task);
+ munmap ((caddr_t) mine, windowsz);
+ if (err)
{
- int fd = openport (term, O_RDWR);
- if (fd < 0)
- assert_perror (errno);
-
- dup2 (fd, 0);
- close (fd);
- dup2 (0, 1);
- dup2 (0, 2);
-
- fclose (stdin);
- stdin = fdopen (0, "r");
-
- /* Don't reopen our output channel for reliability's sake. */
-
- /* Set ports in init_dtable for programs we start. */
- mach_port_deallocate (mach_task_self (), default_dtable[0]);
- mach_port_deallocate (mach_task_self (), default_dtable[1]);
- mach_port_deallocate (mach_task_self (), default_dtable[2]);
- default_dtable[0] = getdport (0);
- default_dtable[1] = getdport (1);
- default_dtable[2] = getdport (2);
+ error (0, err, "cannot write command line into kernel task");
+ return;
}
- else
- error (0, 0, "Cannot open console");
- return term;
+ /* The argument vector is set up in the kernel task at address HIS.
+ Finally, we can inform the proc server where to find it. */
+ err = proc_set_arg_locations (proc, his, his + (argc * sizeof (char *)));
+ mach_port_deallocate (mach_task_self (), proc);
+ if (err)
+ error (0, err, "proc_set_arg_locations for kernel task");
}
-
-/** Single and multi user transitions **/
-
+/** Running userland. **/
-/* Start the single-user environment. This can only be done
- when the core servers have fully started. We know that
- startup_essential_task is the last thing they do before being
- ready to handle requests, so we start this once all the necessary
- servers have identified themselves that way. */
-void
-launch_single_user ()
-{
- char shell[1024];
- mach_port_t term;
+/* In the "split-init" setup, we just run a single program (usually
+ /libexec/runsystem) that is not expected to ever exit (or stop).
+ If it does exit (or can't be started), we go to an emergency single-user
+ shell as a fallback. */
- printf ("Single-user environment:");
- fflush (stdout);
- term = open_console ();
+static pid_t child_pid; /* PID of the child we run */
+static task_t child_task; /* and its (original) task port */
- system_state = SINGLE;
-
-#if 0
- printf ("Shell program [%s]: ", _PATH_BSHELL);
- if (! getstring (shell, sizeof shell))
-#endif
- strcpy (shell, _PATH_BSHELL);
-
- /* The shell needs a real controlling terminal, so set that up here. */
- shell_pid = run_for_real (shell, shell, strlen (shell) + 1, term, 1);
- mach_port_deallocate (mach_task_self (), term);
- if (shell_pid == 0)
- crash_system ();
- printf (" shell.\n");
- fflush (stdout);
-}
+error_t send_signal (mach_port_t msgport, int signal, mach_port_t refport,
+ mach_msg_timeout_t);
-/* Run /etc/rc as a shell script. Return non-zero if we fail. */
-int
-process_rc_script ()
-{
- char *rcargs;
- size_t rcargslen;
- mach_port_t term;
+static void launch_something (const char *why);
- if (do_fastboot)
- {
- rcargs = malloc (rcargslen = sizeof _PATH_RUNCOM);
- strcpy (rcargs, _PATH_RUNCOM);
- }
- else
- {
- rcargslen = asprintf (&rcargs, "%s%c%s", _PATH_RUNCOM, '\0', "autoboot");
- rcargslen++; /* final null */
- }
-
- term = open_console ();
-
- system_state = RUNCOM;
-
- rc_pid = run_for_real (rcargs, rcargs, rcargslen, term, 1);
- mach_port_deallocate (mach_task_self (), term);
- return ! rc_pid;
-}
-/* Start up multi-user state. */
+/* SIGNO has arrived and has been validated. Do whatever work it
+ implies. */
void
-launch_multi_user ()
+process_signal (int signo)
{
- int fail;
-
- if (!mapped_time)
- maptime_map (1, 0, &mapped_time);
-
- fail = init_ttys ();
- if (fail)
- launch_single_user ();
- else
+ if (signo == SIGCHLD)
{
- system_state = MULTI;
- fail = startup_ttys ();
- if (fail)
- launch_single_user ();
- }
-}
+ /* A child died. Find its status. */
+ int status;
+ pid_t pid;
+ while (1)
+ {
+ pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED);
+ if (pid <= 0)
+ break; /* No more children. */
-/* Kill all the outstanding processes with SIGNO. Return 1 if
- there were no tasks left to kill. */
-int
-kill_everyone (int signo)
-{
- pid_t pidbuf[100], *pids = pidbuf;
- mach_msg_type_number_t i, npids = 100;
- task_t tk;
- struct ess_task *es;
- mach_port_t msg;
- int didany;
- int nloops;
- error_t err;
+ /* Since we are init, orphaned processes get reparented to us and
+ alas, all our adopted children eventually die. Woe is us. We
+ just need to reap the zombies to relieve the proc server of
+ its burden, and then we can forget about the little varmints. */
+
+ if (pid == child_pid)
+ {
+ /* The big magilla bit the dust. */
+
+ char *desc = 0;
+
+ mach_port_deallocate (mach_task_self (), child_task);
+ child_task = MACH_PORT_NULL;
+ child_pid = -1;
+
+ if (WIFSIGNALED (status))
+ asprintf (&desc, "terminated abnormally (%s)",
+ strsignal (WTERMSIG (status)));
+ else if (WIFSTOPPED (status))
+ asprintf (&desc, "stopped abnormally (%s)",
+ strsignal (WTERMSIG (status)));
+ else if (WEXITSTATUS (status) == 0)
+ desc = strdup ("finished");
+ else
+ asprintf (&desc, "exited with status %d",
+ WEXITSTATUS (status));
+
+ {
+ char buf[40];
+ snprintf (buf, sizeof buf, "%d", status);
+ setenv ("STATUS", buf, 1);
+ }
- for (nloops = 10; nloops; nloops--)
+ launch_something (desc);
+ }
+ }
+ }
+ else
{
- if (nloops < 9)
- /* Give it a rest for folks to have a chance to die */
- sleep (1);
+ /* Pass the signal on to the child. */
+ task_t task;
+ error_t err;
- didany = 0;
- err = proc_getallpids (procserver, &pids, &npids);
- if (!err)
+ err = proc_pid2task (procserver, child_pid, &task);
+ if (err)
+ {
+ error (0, err, "proc_pid2task on %d", child_pid);
+ task = child_task;
+ }
+ else
{
- for (i = 0; i < npids; i++)
+ mach_port_deallocate (mach_task_self (), child_task);
+ child_task = task;
+ }
+
+ if (signo == SIGKILL)
+ {
+ err = task_terminate (task);
+ if (err != MACH_SEND_INVALID_DEST)
+ error (0, err, "task_terminate");
+ }
+ else
+ {
+ mach_port_t msgport;
+ err = proc_getmsgport (procserver, child_pid, &msgport);
+ if (err)
+ error (0, err, "proc_getmsgport");
+ else
{
- if (pids[i] == 1 /* us */
- || pids[i] == 2 /* kernel */
- || pids[i] == 3 /* default pager for now XXX */)
- continue;
-
- /* See if the task is essential */
- err = proc_pid2task (procserver, pids[i], &tk);
+ err = send_signal (msgport, signo, task,
+ 500); /* Block only half a second. */
+ mach_port_deallocate (mach_task_self (), msgport);
if (err)
- continue;
-
- for (es = ess_tasks; es; es = es->next)
- if (tk == es->task_port)
- {
- /* Skip this one */
- mach_port_deallocate (mach_task_self (), tk);
- continue;
- }
-
- /* Kill it */
- if (signo == SIGKILL)
- {
- task_terminate (tk);
- didany = 1;
- }
- else
{
- err = proc_getmsgport (procserver, pids[i], &msg);
- if (err)
- {
- mach_port_deallocate (mach_task_self (), tk);
- continue;
- }
-
- didany = 1;
- msg_sig_post (msg, signo, 0, tk);
- mach_port_deallocate (mach_task_self (), tk);
+ error (0, err, "cannot send %s to child %d",
+ strsignal (signo), child_pid);
+ err = task_terminate (task);
+ if (err != MACH_SEND_INVALID_DEST)
+ error (0, err, "task_terminate");
}
}
}
- if (pids != pidbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) pids,
- npids * sizeof (pid_t));
- if (!didany)
- return 1;
}
- return 0;
}
-/* Kill outstanding multi-user sessions */
-void
-kill_multi_user ()
+/* Start the child program PROG. It is run via /libexec/console-run
+ with the given additional arguments. */
+static int
+start_child (const char *prog, char **progargs)
{
- int sigs[3] = {SIGHUP, SIGTERM, SIGKILL};
- int stage;
-
- free_ttys ();
-
- for (stage = 0; stage < 3; stage++)
- if (kill_everyone (sigs[stage]))
- break;
-
- /* Notify tasks that they are about to die. */
- notify_shutdown ("transition to single-user");
-
- if (stage == 3)
- error (0, 0, "warning: some processes wouldn't die; `ps -axlM' advised");
-}
+ file_t file;
+ error_t err;
+ char *args;
+ size_t arglen;
-/* SIGNO has arrived and has been validated. Do whatever work it
- implies. */
-void
-process_signal (int signo)
-{
- int fail;
-
- switch (signo)
+ if (progargs == 0)
{
- case SIGTERM:
- if (system_state == MULTI)
- {
- /* Drop back to single user. */
- kill_multi_user ();
- launch_single_user ();
- }
- break;
-
- case SIGHUP:
- if (system_state == MULTI)
- reread_ttys ();
- break;
-
- case SIGCHLD:
+ const char *argv[] = { "/libexec/console-run", prog, 0 };
+ err = argz_create ((char **) argv, &args, &arglen);
+ }
+ else
+ {
+ int argc = 0;
+ while (progargs[argc] != 0)
+ ++argc;
{
- /* A child died. Find its status. */
- int status;
- pid_t pid;
+ const char *argv[2 + argc + 1];
+ argv[0] = "/libexec/console-run";
+ argv[1] = prog;
+ argv[2 + argc] = 0;
+ while (argc-- > 0)
+ argv[2 + argc] = progargs[argc];
+ err = argz_create ((char **) argv, &args, &arglen);
+ }
+ }
+ assert_perror (err);
- for (;;)
- {
- pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED);
- if (pid <= 0)
- return;
+ file = file_name_lookup (args, O_EXEC, 0);
+ if (file == MACH_PORT_NULL)
+ {
+ error (0, errno, "%s", args);
+ free (args);
+ return -1;
+ }
- if (pid == shell_pid && system_state == SINGLE)
- {
- if (WIFSIGNALED (status))
- {
- error (0, 0,
- "Single-user terminated abnormally (%s), restarting",
- strsignal (WTERMSIG (status)));
- launch_single_user ();
- }
- else if (WIFSTOPPED (status))
- {
- error (0, 0,
- "Single-user stopped (%s), killing and restarting",
- strsignal (WSTOPSIG (status)));
- kill (shell_pid, SIGKILL);
- launch_single_user ();
- }
- else
- {
- do_fastboot = 1;
- fail = process_rc_script ();
- if (fail)
- {
- do_fastboot = 0;
- launch_single_user ();
- }
- }
- }
- else if (pid == rc_pid && system_state == RUNCOM)
- {
- if (WIFSIGNALED (status))
- {
- error (0, 0,
- "%s terminated abnormally (%s), \
-going to single user mode",
- _PATH_RUNCOM, strsignal (WTERMSIG (status)));
- launch_single_user ();
- }
- else if (WIFSTOPPED (status))
- {
- error (0, 0,
- "%s stopped (%s), \
-killing it and going to single user mode",
- _PATH_RUNCOM, strsignal (WSTOPSIG (status)));
- kill (rc_pid, SIGKILL);
- launch_single_user ();
- }
- else if (WEXITSTATUS (status))
- launch_single_user ();
- else
- launch_multi_user ();
- }
- else if (system_state == MULTI)
- restart_terminal (pid);
- }
- break;
- }
- default:
- break;
+ task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &child_task);
+ proc_child (procserver, child_task);
+ proc_task2pid (procserver, child_task, &child_pid);
+ proc_task2proc (procserver, child_task, &default_ports[INIT_PORT_PROC]);
+
+ if (bootstrap_args & RB_KDB)
+ {
+ printf ("Pausing for %s\n", args);
+ getchar ();
+ }
+
+ err = file_exec (file, child_task, 0,
+ args, arglen,
+ startup_envz, startup_envz_len,
+ NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */
+ default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+ default_ints, INIT_INT_MAX,
+ NULL, 0, NULL, 0);
+ mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]);
+ mach_port_deallocate (mach_task_self (), file);
+ free (args);
+ if (err)
+ {
+ error (0, err, "Cannot execute %s", args);
+ free (args);
+ return -1;
}
+
+ return 0;
}
+static void
+launch_something (const char *why)
+{
+ static unsigned int try;
+ static const char *const tries[] =
+ {
+ "/libexec/runsystem",
+ _PATH_BSHELL,
+ "/bin/shd", /* XXX */
+ };
+
+ if (why)
+ error (0, 0, "%s %s", tries[try - 1], why);
+
+ if (try == 0 && start_child (tries[try++], &global_argv[1]) == 0)
+ return;
+
+ while (try < sizeof tries / sizeof tries[0])
+ if (start_child (tries[try++], NULL) == 0)
+ return;
+
+ crash_system ();
+}
+void
+launch_system (void)
+{
+ launch_something (0);
+}
/** RPC servers **/
@@ -1421,6 +1165,7 @@ S_startup_authinit (startup_t server,
return MIG_NO_REPLY;
}
+
kern_return_t
S_startup_essential_task (mach_port_t server,
mach_port_t reply,
@@ -1430,43 +1175,19 @@ S_startup_essential_task (mach_port_t server,
char *name,
mach_port_t credential)
{
- struct ess_task *et;
- mach_port_t prev;
static int authinit, procinit, execinit;
int fail;
if (credential != host_priv)
return EPERM;
- /* Record this task as essential. */
- et = malloc (sizeof (struct ess_task));
- if (et == NULL)
- return ENOMEM;
- et->task_port = task;
- et->name = strdup (name);
- if (et->name == NULL)
- {
- free (et);
- return ENOMEM;
- }
- et->next = ess_tasks;
- ess_tasks = et;
-
- /* Dead-name notification on the task port will tell us when it dies. */
- mach_port_request_notification (mach_task_self (), task,
- MACH_NOTIFY_DEAD_NAME, 1, startup,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
- if (prev)
- mach_port_deallocate (mach_task_self (), prev);
-#if 0
- /* Taking over the exception port will give us a better chance
- if the task tries to get wedged on a fault. */
- task_set_special_port (task, TASK_EXCEPTION_PORT, startup);
-#endif
+ fail = record_essential_task (name, task);
+ if (fail)
+ return fail;
mach_port_deallocate (mach_task_self (), credential);
- if (system_state == INITIAL)
+ if (!booted)
{
if (!strcmp (name, "auth"))
authinit = 1;
@@ -1482,15 +1203,12 @@ S_startup_essential_task (mach_port_t server,
startup_essential_task_reply (reply, replytype, 0);
init_stdarrays ();
+ frob_kernel_process ();
+
+ launch_system ();
+
+ booted = 1;
- if (bootstrap_args & RB_SINGLE)
- launch_single_user ();
- else
- {
- fail = process_rc_script ();
- if (fail)
- launch_single_user ();
- }
return MIG_NO_REPLY;
}
}
@@ -1504,15 +1222,10 @@ S_startup_request_notification (mach_port_t server,
char *name)
{
struct ntfy_task *nt;
- mach_port_t prev;
- mach_port_request_notification (mach_task_self (), notify,
- MACH_NOTIFY_DEAD_NAME, 1, startup,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
- if (prev != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), prev);
+ request_dead_name (notify);
- /* Note that the ntfy_tasks list is kept in inverse order of the
+ /* Note that the ntfy_tasks list is kept in inverse order of the
calls; this is important. We need later notification requests
to get executed first. */
nt = malloc (sizeof (struct ntfy_task));
@@ -1531,6 +1244,11 @@ do_mach_notify_dead_name (mach_port_t notify,
struct ntfy_task *nt, *pnt;
struct ess_task *et;
+ assert (notify == startup);
+
+ /* Deallocate the extra reference the notification carries. */
+ mach_port_deallocate (mach_task_self (), name);
+
for (et = ess_tasks; et != NULL; et = et->next)
if (et->task_port == name)
/* An essential task has died. */
@@ -1549,8 +1267,35 @@ do_mach_notify_dead_name (mach_port_t notify,
else
ntfy_tasks = nt->next;
free (nt);
+
return 0;
}
+
+ if (! booted)
+ {
+ /* The system has not come up yet, so essential tasks are not yet
+ registered. But the essential servers involved in the bootstrap
+ handshake might crash before completing it, so we have requested
+ dead-name notification on those tasks. */
+ static const struct { task_t *taskp; const char *name; } boots[] =
+ {
+ {&fstask, "bootstrap filesystem"},
+ {&authtask, "auth"},
+ {&proctask, "proc"},
+ };
+ size_t i;
+ for (i = 0; i < sizeof boots / sizeof boots[0]; ++i)
+ if (name == *boots[i].taskp)
+ {
+ error (0, 0, "Crashing system; %s server died during bootstrap",
+ boots[i].name);
+ crash_mach ();
+ }
+ error (0, 0, "BUG! Unexpected dead-name notification (name %#zx)",
+ name);
+ crash_mach ();
+ }
+
return 0;
}
@@ -1614,7 +1359,7 @@ S_msg_sig_post_untraced (mach_port_t msgport,
/* Reply immediately */
msg_sig_post_untraced_reply (reply, reply_type, 0);
-
+
process_signal (signo);
return MIG_NO_REPLY;
}
@@ -1627,10 +1372,10 @@ S_msg_sig_post (mach_port_t msgport,
if (refport != mach_task_self ())
return EPERM;
mach_port_deallocate (mach_task_self (), refport);
-
+
/* Reply immediately */
msg_sig_post_reply (reply, reply_type, 0);
-
+
process_signal (signo);
return MIG_NO_REPLY;
}
@@ -1803,13 +1548,13 @@ S_msg_describe_ports (mach_port_t process,
data_t *descriptions,
mach_msg_type_number_t *descriptionsCnt)
{
- return _S_msg_describe_ports (process, refport, names, namesCnt,
+ return _S_msg_describe_ports (process, refport, names, namesCnt,
descriptions, descriptionsCnt);
}
error_t
S_msg_report_wait (mach_port_t process, thread_t thread,
- string_t desc, int *rpc)
+ string_t desc, mach_msg_id_t *rpc)
{
*desc = 0;
*rpc = 0;
diff --git a/init/stubs.c b/init/stubs.c
new file mode 100644
index 00000000..5292ab68
--- /dev/null
+++ b/init/stubs.c
@@ -0,0 +1,139 @@
+/* By-hand stubs for some RPC calls
+ Copyright (C) 1994,96,99,2000 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. */
+
+#include <stdlib.h>
+#include <hurd/hurd_types.h>
+#include <mach.h>
+#include <string.h>
+#include <assert.h>
+
+/* From hurd/msg.defs: */
+#define RPCID_SIG_POST 23000
+
+
+/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't
+ block in any fashion. */
+error_t
+send_signal (mach_port_t msgport,
+ int signal,
+ mach_port_t refport,
+ mach_msg_timeout_t timeout)
+{
+ error_t err;
+
+ /* This message buffer might be modified by mach_msg in some error cases,
+ so we cannot safely reuse a static buffer. */
+ struct
+ {
+ mach_msg_header_t head;
+ mach_msg_type_t signaltype;
+ int signal;
+ mach_msg_type_t sigcode_type;
+ natural_t sigcode;
+ mach_msg_type_t refporttype;
+ mach_port_t refport;
+ }
+ message =
+ {
+ {
+ /* Message header: */
+ (MACH_MSGH_BITS_COMPLEX
+ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */
+ sizeof message, /* msgh_size */
+ msgport, /* msgh_remote_port */
+ MACH_PORT_NULL, /* msgh_local_port */
+ 0, /* msgh_seqno */
+ RPCID_SIG_POST, /* msgh_id */
+ },
+ {
+ /* Type descriptor for signo */
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Signal number */
+ signal,
+ /* Type descriptor for sigcode */
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Sigcode */
+ 0,
+ {
+ /* Type descriptor for refport */
+ MACH_MSG_TYPE_COPY_SEND, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Reference port */
+ refport
+ };
+
+ err = mach_msg (&message.head,
+ MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0,
+ MACH_PORT_NULL, timeout, MACH_PORT_NULL);
+
+ switch (err)
+ {
+ case MACH_SEND_TIMED_OUT:
+ /* The send could not complete in time. In this error case, the
+ kernel has modified the message buffer in a pseudo-receive
+ operation. That means our COPY_SEND refs might now be MOVE_SEND
+ refs, in which case each has gained user ref accordingly. To
+ avoid leaking those refs, we must clean up the buffer. We don't
+ use mach_msg_destroy because it assumes the local/remote ports in
+ the header have been reversed as from a real receive, while a
+ pseudo-receive leaves them as they were. */
+ if (MACH_MSGH_BITS_REMOTE (message.head.msgh_bits)
+ == MACH_MSG_TYPE_MOVE_SEND)
+ mach_port_deallocate (mach_task_self (),
+ message.head.msgh_remote_port);
+ if (message.refporttype.msgt_name == MACH_MSG_TYPE_MOVE_SEND)
+ mach_port_deallocate (mach_task_self (), message.refport);
+ break;
+
+ /* These are the other codes that mean a pseudo-receive modified
+ the message buffer and we might need to clean up the send rights.
+ None of them should be possible in our usage. */
+ case MACH_SEND_INTERRUPTED:
+ case MACH_SEND_INVALID_NOTIFY:
+ case MACH_SEND_NO_NOTIFY:
+ case MACH_SEND_NOTIFY_IN_PROGRESS:
+ assert_perror (err);
+ break;
+
+ default: /* Other errors are safe to ignore. */
+ break;
+ }
+
+ return err;
+}
diff --git a/install-sh b/install-sh
new file mode 100644
index 00000000..a5897de6
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,519 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2006-12-25.00
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dst_arg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ -*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/isofs/EXTENSIONS b/isofs/EXTENSIONS
new file mode 100644
index 00000000..625cdac0
--- /dev/null
+++ b/isofs/EXTENSIONS
@@ -0,0 +1,16 @@
+-*- Text -*-
+
+These are the SUSP and RockRidge compliant extensions that GNU uses:
+
+See rr.h for format details.
+
+AU: Author, an additional uid on a file. If this is not present, the
+author is the same as the owner.
+
+TR: Translator, specifying a command line to run as a translator.
+
+MD: A full 32 bit hurd mode; if not present, the mode is the one found
+in the PX record.
+
+FL: 32 bits of flags; if not present, the flags are zero.
+
diff --git a/isofs/Makefile b/isofs/Makefile
new file mode 100644
index 00000000..515611c5
--- /dev/null
+++ b/isofs/Makefile
@@ -0,0 +1,31 @@
+
+# Copyright (C) 1997, 2000, 2005 Free Software Foundation
+#
+# 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 := isofs
+makemode := server
+
+target = iso9660fs
+SRCS = inode.c main.c lookup.c pager.c rr.c
+LCLHDRS = iso9660.h isofs.h rr.h
+DIST_FILES = EXTENSIONS
+
+OBJS = $(SRCS:.c=.o)
+HURDLIBS = diskfs iohelp fshelp store pager threads ports ihash shouldbeinlibc
+
+include ../Makeconf
+
+iso9660fs.static: $(boot-store-types:%=../libstore/libstore_%.a)
diff --git a/isofs/ext.c b/isofs/ext.c
new file mode 100644
index 00000000..80379b7b
--- /dev/null
+++ b/isofs/ext.c
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Extensions to ISO 9660 we support */
+
+#include "isofs.h"
+
+struct susp_field susp_extension[] =
+{
+ { 'C', 'E', 1, process_su_ce },
+ { 'P', 'D', 1, process_su_pd },
+ { 'S', 'P', 1, process_su_sp },
+ { 'E', 'R', 1, process_su_er },
+ { 'S', 'T', 1, process_su_st },
+ { 0, 0, 0, 0 },
+};
+
+struct susp_field rr_extension[] =
+{
+ { 'P', 'X', 1, process_rr_px },
+ { 'P', 'N', 1, process_rr_pn },
+ { 'S', 'L', 1, process_rr_sl },
+ { 'N', 'M', 1, process_rr_nm },
+ { 'C', 'L', 1, process_rr_cl },
+ { 'P', 'L', 1, process_rr_pl },
+ { 'R', 'E', 1, process_rr_re },
+ { 'T', 'F', 1, process_rr_tf },
+ { 'S', 'F', 1, process_rr_sf },
+ { 0, 0, 0, 0 },
+};
+
+struct susp_ext extensions[] =
+{
+ { "RRIP_1991A", 1,
+ "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
+ "ROCK RIDGE SPECIFICATION VERSION 1 REVISION 1.10 JULY 13 1993",
+ rr_extensions
+ },
+ { 0, 0, 0, 0, susp_extensions },
+ { 0, 0, 0, 0, 0 },
+}
+
+
diff --git a/isofs/inode.c b/isofs/inode.c
new file mode 100644
index 00000000..99aca957
--- /dev/null
+++ b/isofs/inode.c
@@ -0,0 +1,634 @@
+/*
+ Copyright (C) 1997, 1998, 2002, 2007 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "isofs.h"
+
+
+/* There is no such thing as an inode in this format, all such
+ information being recorded in the directory entry. So we report
+ inode numbers as absolute offsets from DISK_IMAGE. We use the directory
+ record for symlinks and zero length files, and file_start otherwise.
+ Only for hard links to zero length files we get extra inodes. */
+
+#define INOHSZ 512
+#if ((INOHSZ&(INOHSZ-1)) == 0)
+#define INOHASH(ino) ((ino>>8)&(INOHSZ-1))
+#else
+#define INOHASH(ino) (((unsigned)(ino>>8))%INOHSZ)
+#endif
+
+struct node_cache
+{
+ struct dirrect *dr; /* somewhere in disk_image */
+ off_t file_start; /* start of file */
+
+ off_t id; /* UNIQUE identifier. */
+
+ struct node *np; /* if live */
+};
+
+static int node_cache_size = 0;
+static int node_cache_alloced = 0;
+struct node_cache *node_cache = 0;
+
+/* Forward */
+static error_t read_disknode (struct node *,
+ struct dirrect *, struct rrip_lookup *);
+
+
+/* See if node with identifier ID is in the cache. If so, return it,
+ with one additional reference. diskfs_node_refcnt_lock must be held
+ on entry to the call, and will be released iff the node was found
+ in the cache. */
+void
+inode_cache_find (off_t id, struct node **npp)
+{
+ int i;
+
+ for (i = 0; i < node_cache_size; i++)
+ if (node_cache[i].id == id
+ && node_cache[i].np)
+ {
+ *npp = node_cache[i].np;
+ (*npp)->references++;
+ spin_unlock (&diskfs_node_refcnt_lock);
+ mutex_lock (&(*npp)->lock);
+ return;
+ }
+ *npp = 0;
+}
+
+
+/* Determine if we use file_start or struct dirrect * as node id. */
+int
+use_file_start_id (struct dirrect *record, struct rrip_lookup *rr)
+{
+ /* If it is a symlink or a zero length file, don't use file_start. */
+ if (rr->valid & VALID_SL || isonum_733 (record->size) == 0)
+ return 0;
+
+ return 1;
+}
+
+/* Enter NP into the cache. The directory entry we used is DR, the
+ cached Rock-Ridge info RR. diskfs_node_refcnt_lock must be held. */
+void
+cache_inode (struct node *np, struct dirrect *record,
+ struct rrip_lookup *rr)
+{
+ int i;
+ struct node_cache *c = 0;
+ off_t id;
+
+ if (use_file_start_id (record, rr))
+ id = np->dn->file_start << store->log2_block_size;
+ else
+ id = (off_t) ((void *) record - (void *) disk_image);
+
+ /* First see if there's already an entry. */
+ for (i = 0; i < node_cache_size; i++)
+ if (node_cache[i].id == id)
+ break;
+
+ if (i == node_cache_size)
+ {
+ if (node_cache_size >= node_cache_alloced)
+ {
+ if (!node_cache_alloced)
+ {
+ /* Initialize */
+ node_cache_alloced = 10;
+ node_cache = malloc (sizeof (struct node_cache) * 10);
+ }
+ else
+ {
+ node_cache_alloced *= 2;
+ node_cache = realloc (node_cache,
+ sizeof (struct node_cache)
+ * node_cache_alloced);
+ }
+ assert (node_cache);
+ }
+ node_cache_size++;
+ }
+
+ c = &node_cache[i];
+ c->id = id;
+ c->dr = record;
+ c->file_start = np->dn->file_start;
+ c->np = np;
+
+ /* PLUS 1 so that we don't store zero cache ID's (not allowed by diskfs) */
+ np->cache_id = i + 1;
+}
+
+/* Fetch inode with cache id ID; set *NPP to the node structure;
+ gain one user reference and lock the node. */
+error_t
+diskfs_cached_lookup (ino_t id, struct node **npp)
+{
+ struct node *np;
+ error_t err;
+
+ /* Cache ID's are incremented when presented to diskfs
+ to avoid presenting zero cache ID's. */
+ id--;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+ assert (id < node_cache_size);
+
+ np = node_cache[id].np;
+
+ if (!np)
+ {
+ struct node_cache *c = &node_cache[id];
+ struct rrip_lookup rr;
+ struct disknode *dn;
+
+ rrip_lookup (node_cache[id].dr, &rr, 1);
+
+ /* We should never cache the wrong directory entry */
+ assert (!(rr.valid & VALID_CL));
+
+ dn = malloc (sizeof (struct disknode));
+ if (!dn)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ release_rrip (&rr);
+ return ENOMEM;
+ }
+ dn->fileinfo = 0;
+ dn->dr = c->dr;
+ dn->file_start = c->file_start;
+ np = diskfs_make_node (dn);
+ if (!np)
+ {
+ free (dn);
+ spin_unlock (&diskfs_node_refcnt_lock);
+ release_rrip (&rr);
+ return ENOMEM;
+ }
+ np->cache_id = id + 1; /* see above for rationale for increment */
+ mutex_lock (&np->lock);
+ c->np = np;
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ err = read_disknode (np, node_cache[id].dr, &rr);
+ if (!err)
+ *npp = np;
+
+ release_rrip (&rr);
+
+ return err;
+ }
+
+
+ np->references++;
+ spin_unlock (&diskfs_node_refcnt_lock);
+ mutex_lock (&np->lock);
+ *npp = np;
+ return 0;
+}
+
+
+/* Return Epoch-based time from a seven byte according to 9.1.5 */
+char *
+isodate_915 (char *c, struct timespec *ts)
+{
+ struct tm tm;
+ signed char tz;
+
+ /* Copy into a struct TM. */
+ tm.tm_year = *c++;
+ tm.tm_mon = *c++ - 1;
+ tm.tm_mday = *c++;
+ tm.tm_hour = *c++;
+ tm.tm_min = *c++;
+ tm.tm_sec = *c++;
+ tz = *c++;
+
+ tm.tm_isdst = 0;
+ ts->tv_sec = timegm (&tm);
+ ts->tv_nsec = 0;
+
+ /* Only honor TZ offset if it makes sense */
+ if (-48 <= tz && tz <= 52)
+ ts->tv_sec -= 15 * 60 * tz; /* TZ is in fifteen minute chunks */
+
+ return c;
+}
+
+/* Return Epoch-based time from a seventeen byte according to 8.4.26.1 */
+char *
+isodate_84261 (char *c, struct timespec *ts)
+{
+ struct tm tm;
+ int hsec;
+ signed char tz;
+
+ sscanf (c, "%4d%2d%2d%2d%2d%2d%2d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
+ &hsec);
+
+ /* Convert to appropriate units */
+ ts->tv_nsec = hsec * 10000000;
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+
+ tm.tm_isdst = 0;
+ ts->tv_sec = timegm (&tm);
+
+ tz = c[16];
+
+ /* Only honor TZ offset if it makes sense */
+ if (-48 <= tz && tz <= 52)
+ ts->tv_sec -= 15 * 60 * tz; /* TZ is in fifteen minute chunks */
+
+ return c + 17;
+}
+
+/* Calculate the file start (in store blocks) of the file at RECORD. */
+error_t
+calculate_file_start (struct dirrect *record, off_t *file_start,
+ struct rrip_lookup *rr)
+{
+ error_t err;
+
+ if (rr && (rr->valid & VALID_CL))
+ {
+ *file_start = (void *) rr->realdirent - (void *)disk_image;
+ *file_start >>= store->log2_block_size;
+ }
+ else if (rr && (rr->valid & VALID_PL))
+ *file_start = rr->realfilestart;
+ else
+ {
+ err = diskfs_catch_exception ();
+ if (err)
+ return err;
+
+ *file_start = ((isonum_733 (record->extent) + record->ext_attr_len)
+ * (logical_block_size / store->block_size));
+
+ diskfs_end_catch_exception ();
+ }
+ return 0;
+}
+
+
+/* Load the inode with directory entry RECORD and cached Rock-Ridge
+ info RR into NP. The directory entry is at OFFSET in BLOCK. */
+error_t
+load_inode (struct node **npp, struct dirrect *record,
+ struct rrip_lookup *rr)
+{
+ error_t err;
+ off_t file_start;
+ struct disknode *dn;
+ struct node *np;
+
+ err = calculate_file_start (record, &file_start, rr);
+ if (err)
+ return err;
+ if (rr->valid & VALID_CL)
+ record = rr->realdirent;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+
+ /* First check the cache */
+ if (use_file_start_id (record, rr))
+ inode_cache_find (file_start << store->log2_block_size, npp);
+ else
+ inode_cache_find ((off_t) ((void *) record - (void *) disk_image), npp);
+
+ if (*npp)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ return 0;
+ }
+
+ /* Create a new node */
+ dn = malloc (sizeof (struct disknode));
+ if (!dn)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ return ENOMEM;
+ }
+ dn->fileinfo = 0;
+ dn->dr = record;
+ dn->file_start = file_start;
+
+ np = diskfs_make_node (dn);
+ if (!np)
+ {
+ free (dn);
+ spin_unlock (&diskfs_node_refcnt_lock);
+ return ENOMEM;
+ }
+
+ mutex_lock (&np->lock);
+
+ cache_inode (np, record, rr);
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ err = read_disknode (np, record, rr);
+ *npp = np;
+ return err;
+}
+
+
+/* Read stat information from the directory entry at DR and the
+ contents of RL. */
+static error_t
+read_disknode (struct node *np, struct dirrect *dr,
+ struct rrip_lookup *rl)
+{
+ error_t err;
+ struct stat *st = &np->dn_stat;
+ st->st_fstype = FSTYPE_ISO9660;
+ st->st_fsid = getpid ();
+ if (use_file_start_id (dr, rl))
+ st->st_ino = (ino_t) np->dn->file_start << store->log2_block_size;
+ else
+ st->st_ino = (ino_t) ((void *) dr - (void *) disk_image);
+ st->st_gen = 0;
+ st->st_rdev = 0;
+
+ err = diskfs_catch_exception ();
+ if (err)
+ return err;
+
+ if (rl->valid & VALID_PX)
+ {
+ if ((rl->valid & VALID_MD) == 0)
+ st->st_mode = rl->mode;
+ st->st_nlink = rl->nlink;
+ st->st_uid = rl->uid;
+ st->st_gid = rl->gid;
+ }
+ else
+ {
+ if ((rl->valid & VALID_MD) == 0)
+ {
+ /* If there are no periods, it's a directory. */
+ if (((rl->valid & VALID_NM) && !index (rl->name, '.'))
+ || (!(rl->valid & VALID_NM) && !memchr (dr->name, '.',
+ dr->namelen)))
+ st->st_mode = S_IFDIR | 0777;
+ else
+ st->st_mode = S_IFREG | 0666;
+ }
+ st->st_nlink = 1;
+ st->st_uid = 0;
+ st->st_gid = 0;
+ }
+
+ if (rl->valid & VALID_MD)
+ st->st_mode = rl->allmode;
+
+ if (rl->valid & VALID_AU)
+ st->st_author = rl->author;
+ else
+ st->st_author = st->st_gid;
+
+ st->st_size = isonum_733 (dr->size);
+
+ if ((rl->valid & VALID_PN)
+ && (S_ISCHR (st->st_mode) || S_ISBLK (st->st_mode)))
+ st->st_rdev = rl->rdev;
+ else
+ st->st_rdev = 0;
+
+ if (dr->ileave)
+ /* XXX ??? */
+ st->st_size = 0;
+
+ /* Calculate these if we'll need them */
+ if (!(rl->valid & VALID_TF)
+ || ((rl->tfflags & (TF_CREATION|TF_ACCESS|TF_MODIFY))
+ != (TF_CREATION|TF_ACCESS|TF_MODIFY)))
+ {
+ struct timespec ts;
+ isodate_915 (dr->date, &ts);
+ st->st_ctim = st->st_mtim = st->st_atim = ts;
+ }
+
+ /* Override what we have better info for */
+ if (rl->valid & VALID_TF)
+ {
+ if (rl->tfflags & TF_CREATION)
+ st->st_ctim = rl->ctime;
+
+ if (rl->tfflags & TF_ACCESS)
+ st->st_atim = rl->atime;
+
+ if (rl->tfflags & TF_MODIFY)
+ st->st_mtim = rl->mtime;
+ }
+
+ st->st_blksize = logical_block_size;
+ st->st_blocks = (st->st_size - 1) / 512 + 1;
+
+ if (rl->valid & VALID_FL)
+ st->st_flags = rl->flags;
+ else
+ st->st_flags = 0;
+
+ if (S_ISLNK (st->st_mode))
+ {
+ if (rl->valid & VALID_SL)
+ {
+ np->dn->link_target = rl->target;
+ rl->target = 0;
+ st->st_size = strlen (np->dn->link_target);
+ }
+ else
+ {
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFREG;
+ }
+ }
+
+ if (rl->valid & VALID_TR)
+ {
+ st->st_mode |= S_IPTRANS;
+ np->dn->translen = rl->translen;
+ np->dn->translator = rl->trans;
+ rl->trans = 0;
+ }
+ else
+ {
+ np->dn->translator = 0;
+ np->dn->translen = 0;
+ }
+
+ diskfs_end_catch_exception ();
+
+ return 0;
+}
+
+/* Symlink targets are never stored in files, so always use this. */
+static error_t
+read_symlink_hook (struct node *np, char *buf)
+{
+ bcopy (np->dn->link_target, buf, np->dn_stat.st_size);
+ return 0;
+}
+error_t (*diskfs_read_symlink_hook) (struct node *, char *)
+ = read_symlink_hook;
+
+
+/* The last reference to NP has gone away; drop it from the cache
+ and clean all state in the dn structure. */
+void
+diskfs_node_norefs (struct node *np)
+{
+ assert (node_cache[np->cache_id - 1].np == np);
+ node_cache[np->cache_id - 1].np = 0;
+
+ if (np->dn->translator)
+ free (np->dn->translator);
+
+ assert (!np->dn->fileinfo);
+ free (np->dn);
+ free (np);
+}
+
+/* The last hard reference to a node has gone away; arrange to have
+ all the weak references dropped that can be. */
+void
+diskfs_try_dropping_softrefs (struct node *np)
+{
+ drop_pager_softrefs (np);
+}
+
+void
+diskfs_lost_hardrefs (struct node *np)
+{
+}
+
+void
+diskfs_new_hardrefs (struct node *np)
+{
+ allow_pager_softrefs (np);
+}
+
+error_t
+diskfs_truncate (struct node *np, off_t length)
+{
+ return EROFS;
+}
+
+error_t
+diskfs_grow (struct node *np, off_t end, struct protid *cred)
+{
+ return EROFS;
+}
+
+error_t
+diskfs_set_translator (struct node *np,
+ const char *name, u_int namelen,
+ struct protid *cred)
+{
+ return EROFS;
+}
+
+error_t
+diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
+{
+ return EOPNOTSUPP;
+}
+
+void
+diskfs_shutdown_soft_ports ()
+{
+ /* Should initiate termination of internally held pager ports
+ (the only things that should be soft) XXX */
+}
+
+error_t
+diskfs_node_reload (struct node *node)
+{
+ /* Never necessary on a read-only medium */
+ return 0;
+}
+
+error_t
+diskfs_validate_author_change (struct node *np, uid_t author)
+{
+ return EROFS;
+}
+
+error_t
+diskfs_node_iterate (error_t (*fun)(struct node *))
+{
+ /* We never actually have to do anything, because this function
+ is only used for things that have to do with read-write media. */
+ return 0;
+}
+
+void
+diskfs_write_disknode (struct node *np, int wait)
+{
+}
+
+error_t
+diskfs_set_statfs (struct statfs *st)
+{
+ /* There is no easy way to determine the number of files on an
+ ISO 9660 filesystem. */
+ bzero (st, sizeof *st);
+ st->f_type = FSTYPE_ISO9660;
+ st->f_bsize = logical_block_size;
+ st->f_blocks = isonum_733 (sblock->vol_sp_size);
+ st->f_fsid = getpid ();
+ st->f_frsize = logical_block_size;
+ return 0;
+}
+
+error_t
+diskfs_S_file_get_storage_info (struct protid *cred,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
+{
+ /* XXX */
+ return EOPNOTSUPP;
+}
+
+void
+diskfs_free_node (struct node *no, mode_t mode)
+{
+ abort ();
+}
+
+error_t
+diskfs_alloc_node (struct node *dp, mode_t mode, struct node **np)
+{
+ return EROFS;
+}
diff --git a/isofs/iso9660.h b/isofs/iso9660.h
new file mode 100644
index 00000000..2fd8cc2b
--- /dev/null
+++ b/isofs/iso9660.h
@@ -0,0 +1,125 @@
+/*
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Specification of ISO 9660 format */
+
+/* Volume descriptor */
+
+struct voldesc
+{
+ unsigned char type;
+ unsigned char id[5];
+ unsigned char version;
+ unsigned char data[0];
+};
+
+/* Volume descriptor types */
+#define VOLDESC_PRIMARY 1
+#define VOLDESC_END 255
+
+/* We don't support any other types */
+
+/* Expected ID */
+#define ISO_STANDARD_ID "CD001"
+
+/* Primary descriptor */
+struct sblock
+{
+ unsigned char type;
+ unsigned char id[5];
+ unsigned char version;
+ unsigned char skip1;
+ unsigned char sysid[32];
+ unsigned char volid[32];
+ unsigned char skip2[8];
+ unsigned char vol_sp_size[8]; /* total number of logical blocks */
+ unsigned char skip[32];
+ unsigned char vol_set_size[4];
+ unsigned char vol_seqno[4];
+ unsigned char blksize[4]; /* logical block size */
+ unsigned char ptsize[8];
+ unsigned char type_l_pt[4];
+ unsigned char opt_type_l_pt[4];
+ unsigned char type_m_pt[4];
+ unsigned char opt_type_m_pt[4];
+ unsigned char root[34];
+ unsigned char volset_id[128];
+ unsigned char pub_id[128];
+ unsigned char prep_id[128];
+ unsigned char app_id[128];
+ unsigned char copyr_id[37];
+ unsigned char abstr_id[37];
+ unsigned char biblio_id[37];
+ unsigned char creation_time[17];
+ unsigned char mod_time[17];
+ unsigned char expir_time[17];
+ unsigned char effect_time[17];
+ unsigned char file_structure;
+ unsigned char skip4;
+ unsigned char appl_data[512];
+ unsigned char skip5[652];
+};
+
+/* Directory record */
+struct dirrect
+{
+ unsigned char len;
+ unsigned char ext_attr_len;
+ unsigned char extent[8];
+ unsigned char size[8];
+ unsigned char date[7];
+ unsigned char flags;
+ unsigned char file_unit_size;
+ unsigned char ileave;
+ unsigned char vol_seqno[4];
+ unsigned char namelen;
+ unsigned char name[0];
+};
+
+
+
+/* Numeric conversions for these fields */
+
+#include <endian.h>
+
+static inline unsigned int
+isonum_733 (unsigned char *addr)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return *(unsigned int *)addr;
+#elif BYTE_ORDER == BIG_ENDIAN
+ return *(unsigned int *)(addr + 4);
+#else
+ return
+ addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
+#endif
+}
+
+static inline unsigned int
+isonum_723 (unsigned char *addr)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return *(unsigned short *)addr;
+#elif BYTE_ORDER == BIG_ENDIAN
+ return *(unsigned short *)addr + 2;
+#else
+ return addr[0] | (addr[1] << 8);
+#endif
+}
diff --git a/isofs/isofs.h b/isofs/isofs.h
new file mode 100644
index 00000000..68a94e93
--- /dev/null
+++ b/isofs/isofs.h
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <hurd/diskfs.h>
+#include <hurd/diskfs-pager.h>
+#include <hurd/store.h>
+
+#include "rr.h"
+
+/* There is no such thing as an inode in this format, all such informatio n
+ being recorded in the directory entry. So we report inode numbers as
+ absolute offsets from DISK_IMAGE. */
+
+struct disknode
+{
+ struct dirrect *dr; /* Somewhere in disk_image. */
+
+ off_t file_start; /* In store->block_size units */
+
+ struct user_pager_info *fileinfo;
+
+ char *link_target; /* for S_ISLNK */
+
+ size_t translen;
+ char *translator;
+};
+
+struct user_pager_info
+{
+ struct node *np;
+ enum pager_type
+ {
+ DISK,
+ FILE_DATA,
+ } type;
+ struct pager *p;
+};
+
+/* The physical media */
+extern struct store *store;
+
+char *host_name;
+
+/* Name we are mounted on, with trailing slash */
+char *mounted_on;
+
+/* Mapped image of disk */
+void *disk_image;
+
+/* Processed sblock info */
+
+/* Block size of pointers etc. on disk (6.2.2). */
+size_t logical_block_size;
+
+/* Size of "logical sectors" (6.1.2). These are 2048 or the
+ largest power of two that will fit in a physical sector, whichever is
+ greater. I don't know how to fetch the physical sector size; so
+ we'll just use a constant. */
+#define logical_sector_size 2048
+
+/* Unprocessed superblock */
+struct sblock *sblock;
+
+
+
+void drop_pager_softrefs (struct node *);
+void allow_pager_softrefs (struct node *);
+void create_disk_pager (void);
+
+error_t load_inode (struct node **, struct dirrect *, struct rrip_lookup *);
+error_t calculate_file_start (struct dirrect *, off_t *, struct rrip_lookup *);
+
+char *isodate_915 (char *, struct timespec *);
+char *isodate_84261 (char *, struct timespec *);
diff --git a/isofs/lookup.c b/isofs/lookup.c
new file mode 100644
index 00000000..8daa5464
--- /dev/null
+++ b/isofs/lookup.c
@@ -0,0 +1,457 @@
+/*
+ Copyright (C) 1997,98,99,2001,02 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include "isofs.h"
+
+/* From inode.c */
+int use_file_start_id (struct dirrect *record, struct rrip_lookup *rr);
+
+/* Forward */
+static error_t dirscanblock (void *, const char *, size_t,
+ struct dirrect **, struct rrip_lookup *);
+
+static int
+isonamematch (const char *dirname, size_t dnamelen,
+ const char *username, size_t unamelen)
+{
+ /* Special representations for `.' and `..' */
+ if (dnamelen == 1 && dirname[0] == '\0')
+ return unamelen == 1 && username[0] == '.';
+
+ if (dnamelen == 1 && dirname[0] == '\1')
+ return unamelen == 2 && username[0] == '.' && username[1] == '.';
+
+ if (unamelen > dnamelen)
+ return 0;
+
+ if (!strncasecmp (dirname, username, unamelen))
+ {
+ /* A prefix has matched. Check if it's acceptable. */
+ if (dnamelen == unamelen)
+ return 1;
+
+ /* User has omitted the version number */
+ if (dirname[unamelen] == ';')
+ return 1;
+
+ /* User has omitted an empty extension */
+ if (dirname[unamelen] == '.'
+ && (dirname[unamelen+1] == '\0' || dirname[unamelen+1] == ';'))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Implement the diskfs_lookup callback from the diskfs library. See
+ <hurd/diskfs.h> for the interface specification. */
+error_t
+diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type,
+ struct node **npp, struct dirstat *ds, struct protid *cred)
+{
+ error_t err = 0;
+ struct dirrect *record;
+ int namelen;
+ int spec_dotdot;
+ void *buf;
+ void *blockaddr;
+ struct rrip_lookup rr;
+
+ if ((type == REMOVE) || (type == RENAME))
+ assert (npp);
+
+ if (npp)
+ *npp = 0;
+
+ spec_dotdot = type & SPEC_DOTDOT;
+ type &= ~SPEC_DOTDOT;
+
+ namelen = strlen (name);
+
+ /* This error is constant, but the errors for CREATE and REMOVE depend
+ on whether NAME exists. */
+ if (type == RENAME)
+ return EROFS;
+
+ buf = disk_image + (dp->dn->file_start << store->log2_block_size);
+
+ for (blockaddr = buf;
+ blockaddr < buf + dp->dn_stat.st_size;
+ blockaddr += logical_sector_size)
+ {
+ err = dirscanblock (blockaddr, name, namelen, &record, &rr);
+
+ if (!err)
+ break;
+
+ if (err != ENOENT)
+ return err;
+ }
+
+ if ((!err && type == REMOVE)
+ || (err == ENOENT && type == CREATE))
+ err = EROFS;
+
+ if (err)
+ return err;
+
+ /* Load the inode */
+ if (namelen == 2 && name[0] == '.' && name[1] == '.')
+ {
+ if (dp == diskfs_root_node)
+ err = EAGAIN;
+ else if (spec_dotdot)
+ {
+ /* renames and removes can't get this far. */
+ assert (type == LOOKUP);
+ diskfs_nput (dp);
+ err = load_inode (npp, record, &rr);
+ }
+ else
+ {
+ /* We don't have to do the normal rigamarole, because
+ we are permanently read-only, so things are necessarily
+ quiescent. Just be careful to honor the locking order. */
+ mutex_unlock (&dp->lock);
+ err = load_inode (npp, record, &rr);
+ mutex_lock (&dp->lock);
+ }
+ }
+ else if (namelen == 1 && name[0] == '.')
+ {
+ *npp = dp;
+ diskfs_nref (dp);
+ }
+ else
+ err = load_inode (npp, record, &rr);
+
+ release_rrip (&rr);
+ return err;
+}
+
+
+/* Scan one logical sector of directory contents (at address BLKADDR)
+ for NAME of length NAMELEN. Return its address in *RECORD. */
+static error_t
+dirscanblock (void *blkaddr, const char *name, size_t namelen,
+ struct dirrect **record, struct rrip_lookup *rr)
+{
+ struct dirrect *entry;
+ void *currentoff;
+ size_t reclen;
+ size_t entry_namelen;
+ int matchrr;
+ int matchnormal;
+
+ for (currentoff = blkaddr;
+ currentoff < blkaddr + logical_sector_size;
+ currentoff += reclen)
+ {
+ entry = (struct dirrect *) currentoff;
+
+ reclen = entry->len;
+
+ /* Validate reclen */
+ if (reclen == 0
+ || reclen < sizeof (struct dirrect)
+ || currentoff + reclen > blkaddr + logical_sector_size)
+ break;
+
+ entry_namelen = entry->namelen;
+
+ /* More validation */
+ if (reclen < sizeof (struct dirrect) + entry_namelen)
+ break;
+
+ /* Check to see if the name matches the directory entry. */
+ if (isonamematch (entry->name, entry_namelen, name, namelen))
+ matchnormal = 1;
+ else
+ matchnormal = 0;
+
+ /* Now scan for RRIP fields */
+ matchrr = rrip_match_lookup (entry, name, namelen, rr);
+
+ /* Ignore RE entries */
+ if (rr->valid & VALID_RE)
+ {
+ release_rrip (rr);
+ continue;
+ }
+
+ /* See if the name matches */
+ if (((rr->valid & VALID_NM) && matchrr)
+ || (!(rr->valid & VALID_NM) && matchnormal))
+ {
+ /* We've got it. Return success */
+ *record = entry;
+ return 0;
+ }
+
+ release_rrip (rr);
+ }
+
+ /* Wasn't there. */
+ *record = 0;
+ return ENOENT;
+}
+
+error_t
+diskfs_get_directs (struct node *dp,
+ int entry,
+ int nentries,
+ char **data,
+ size_t *datacnt,
+ vm_size_t bufsiz,
+ int *amt)
+{
+ volatile vm_size_t allocsize;
+ struct dirrect *ep;
+ struct dirent *userp;
+ int i;
+ void *dirbuf, *bufp;
+ char *datap;
+ volatile int ouralloc = 0;
+ error_t err;
+
+ /* Allocate some space to hold the returned data. */
+ allocsize = bufsiz ? round_page (bufsiz) : vm_page_size * 4;
+ if (allocsize > *datacnt)
+ {
+ *data = mmap (0, allocsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ ouralloc = 1;
+ }
+
+ err = diskfs_catch_exception ();
+ if (err)
+ {
+ if (ouralloc)
+ munmap (*data, allocsize);
+ return err;
+ }
+
+ /* Skip to ENTRY */
+ dirbuf = disk_image + (dp->dn->file_start << store->log2_block_size);
+ bufp = dirbuf;
+ for (i = 0; i < entry; i ++)
+ {
+ struct rrip_lookup rr;
+
+ ep = (struct dirrect *) bufp;
+ rrip_lookup (ep, &rr, 0);
+
+ /* Ignore and skip RE entries */
+ if (rr.valid & VALID_RE)
+ i--;
+ else
+ {
+ if (bufp - dirbuf >= dp->dn_stat.st_size)
+ {
+ /* Not that many entries in the directory; return nothing. */
+ release_rrip (&rr);
+ if (allocsize > *datacnt)
+ munmap (data, allocsize);
+ *datacnt = 0;
+ *amt = 0;
+ return 0;
+ }
+ }
+ bufp = bufp + ep->len;
+ release_rrip (&rr);
+
+ /* If BUFP points at a null, then we have hit the last
+ record in this logical sector. In that case, skip up to
+ the next logical sector. */
+ if (*(char *)bufp == '\0')
+ bufp = (void *) (((long) bufp & ~(logical_sector_size - 1))
+ + logical_sector_size);
+ }
+
+ /* Now copy entries one at a time */
+ i = 0;
+ datap = *data;
+ while (((nentries == -1) || (i < nentries))
+ && (!bufsiz || datap - *data < bufsiz)
+ && ((void *) bufp - dirbuf < dp->dn_stat.st_size))
+ {
+ struct rrip_lookup rr;
+ const char *name;
+ size_t namlen, reclen;
+
+ ep = (struct dirrect *) bufp;
+
+ /* Fetch Rock-Ridge information for this file */
+ rrip_lookup (ep, &rr, 0);
+
+ /* Ignore and skip RE entries */
+ if (! (rr.valid & VALID_RE))
+ {
+ /* See if there's room to hold this one */
+ name = rr.valid & VALID_NM ? rr.name : (char *) ep->name;
+ namlen = rr.valid & VALID_NM ? strlen (name) : ep->namelen;
+
+ /* Name frobnication */
+ if (!(rr.valid & VALID_NM))
+ {
+ if (namlen == 1 && name[0] == '\0')
+ {
+ name = ".";
+ namlen = 1;
+ }
+ else if (namlen == 1 && name[0] == '\1')
+ {
+ name = "..";
+ namlen = 2;
+ }
+ /* Perhaps downcase it too? */
+ }
+
+ reclen = sizeof (struct dirent) + namlen;
+ reclen = (reclen + 3) & ~3;
+
+ /* Expand buffer if necessary */
+ if (datap - *data + reclen > allocsize)
+ {
+ vm_address_t newdata;
+
+ vm_allocate (mach_task_self (), &newdata,
+ (ouralloc
+ ? (allocsize *= 2)
+ : (allocsize = vm_page_size * 2)), 1);
+ bcopy ((void *) *data, (void *)newdata, datap - *data);
+
+ if (ouralloc)
+ munmap (*data, allocsize / 2);
+
+ datap = (char *) newdata + (datap - *data);
+ *data = (char *) newdata;
+ ouralloc = 1;
+ }
+
+ userp = (struct dirent *) datap;
+
+ /* Fill in entry */
+
+ if (use_file_start_id (ep, &rr))
+ {
+ off_t file_start;
+
+ err = calculate_file_start (ep, &file_start, &rr);
+ if (err)
+ {
+ release_rrip (&rr);
+ diskfs_end_catch_exception ();
+ if (ouralloc)
+ munmap (*data, allocsize);
+ return err;
+ }
+
+ userp->d_fileno = file_start << store->log2_block_size;
+ }
+ else
+ userp->d_fileno = (ino_t) ((void *) ep - (void *) disk_image);
+
+ userp->d_type = DT_UNKNOWN;
+ userp->d_reclen = reclen;
+ userp->d_namlen = namlen;
+ bcopy (name, userp->d_name, namlen);
+ userp->d_name[namlen] = '\0';
+
+ /* And move along */
+ datap = datap + reclen;
+ i++;
+ }
+
+ release_rrip (&rr);
+ bufp = bufp + ep->len;
+
+ /* If BUFP points at a null, then we have hit the last
+ record in this logical sector. In that case, skip up to
+ the next logical sector. */
+ if (*(char *)bufp == '\0')
+ bufp = (void *) (((long) bufp & ~(logical_sector_size - 1))
+ + logical_sector_size);
+ }
+
+ diskfs_end_catch_exception ();
+
+ /* If we didn't use all the pages of a buffer we allocated, free
+ the excess. */
+ if (ouralloc
+ && round_page (datap - *data) < round_page (allocsize))
+ munmap ((caddr_t) round_page (datap),
+ round_page (allocsize) - round_page (datap - *data));
+
+ /* Return */
+ *amt = i;
+ *datacnt = datap - *data;
+ return 0;
+}
+
+/* We have no dirstats at all. */
+const size_t diskfs_dirstat_size = 0;
+
+void
+diskfs_null_dirstat (struct dirstat *ds)
+{
+}
+
+error_t
+diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
+{
+ return 0;
+}
+
+/* These should never be called. */
+
+error_t
+diskfs_direnter_hard(struct node *dp,
+ const char *name,
+ struct node *np,
+ struct dirstat *ds,
+ struct protid *cred)
+{
+ abort ();
+}
+
+error_t
+diskfs_dirremove_hard(struct node *dp,
+ struct dirstat *ds)
+{
+ abort ();
+}
+
+error_t
+diskfs_dirrewrite_hard(struct node *dp,
+ struct node *np,
+ struct dirstat *ds)
+{
+ abort ();
+}
+
+int
+diskfs_dirempty(struct node *dp,
+ struct protid *cred)
+{
+ abort ();
+}
diff --git a/isofs/main.c b/isofs/main.c
new file mode 100644
index 00000000..4f6ea8fa
--- /dev/null
+++ b/isofs/main.c
@@ -0,0 +1,170 @@
+/*
+ Copyright (C) 1997,98,99,2002 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <error.h>
+#include <argp.h>
+#include <version.h>
+#include <limits.h>
+#include "isofs.h"
+
+struct node *diskfs_root_node;
+struct store *store = 0;
+struct store_parsed *store_parsed = 0;
+char *diskfs_disk_name = 0;
+
+char *diskfs_server_name = "iso9660fs";
+char *diskfs_server_version = HURD_VERSION;
+char *diskfs_extra_version = "GNU Hurd";
+int diskfs_synchronous = 0;
+
+int diskfs_link_max = INT_MAX;
+int diskfs_name_max = 255; /* see iso9660.h: struct dirrect::namelen */
+int diskfs_maxsymlinks = 8;
+
+
+/* Fetch the root node */
+static void
+fetch_root ()
+{
+ struct rrip_lookup rl;
+ struct dirrect *dr;
+ error_t err;
+
+ dr = (struct dirrect *) sblock->root;
+
+ /* First check for SUSP and all relevant extensions */
+ rrip_initialize (dr);
+
+ /* Now rescan the node for real */
+ rrip_lookup (dr, &rl, 1);
+
+ /* And fetch the node. */
+ err = load_inode (&diskfs_root_node, dr, &rl);
+ assert_perror (err);
+
+ mutex_unlock (&diskfs_root_node->lock);
+}
+
+
+/* Find and read the superblock. */
+static void
+read_sblock ()
+{
+ struct voldesc *vd;
+ error_t err;
+ struct sblock * volatile sb = 0;
+
+ err = diskfs_catch_exception ();
+ if (err)
+ error (4, err, "reading superblock");
+
+ /* Start at logical sector 16 and keep going until
+ we find a matching superblock */
+ for (vd = disk_image + (logical_sector_size * 16);
+ (void *) vd < disk_image + (logical_sector_size * 500); /* for sanity */
+ vd = (void *) vd + logical_sector_size)
+ {
+ if (vd->type == VOLDESC_END)
+ break;
+
+ if (vd->type == VOLDESC_PRIMARY
+ && !memcmp (ISO_STANDARD_ID, vd->id, 5)
+ && vd->version == 1)
+ {
+ /* Here's a valid primary descriptor. */
+ sb = (struct sblock *) vd;
+ break;
+ }
+ }
+
+ if (!sb)
+ error (1, 0, "Could not find valid superblock");
+
+ sblock = malloc (sizeof (struct sblock));
+ if (!sblock)
+ error (1, errno, "Could not allocate memory for superblock");
+ bcopy (sb, sblock, sizeof (struct sblock));
+ diskfs_end_catch_exception ();
+
+ /* Parse some important bits of this */
+ logical_block_size = isonum_723 (sblock->blksize);
+}
+
+/* Override the standard diskfs routine so we can add our own output. */
+error_t
+diskfs_append_args (char **argz, size_t *argz_len)
+{
+ error_t err;
+
+ /* Get the standard things. */
+ err = diskfs_append_std_options (argz, argz_len);
+
+ if (! err)
+ err = store_parsed_append_args (store_parsed, argz, argz_len);
+
+ return err;
+}
+
+int
+main (int argc, char **argv)
+{
+ mach_port_t bootstrap;
+
+ /* This filesystem is never capable of writing. */
+ diskfs_readonly = 1;
+ diskfs_hard_readonly = 1;
+
+ /* Initialize the diskfs library, parse arguments, and open the store.
+ This starts the first diskfs thread for us. */
+ store = diskfs_init_main (NULL, argc, argv, &store_parsed, &bootstrap);
+
+ create_disk_pager ();
+
+ read_sblock ();
+
+ fetch_root ();
+
+ diskfs_startup_diskfs (bootstrap, 0);
+
+ cthread_exit (0);
+
+ return 0;
+}
+
+/* Nothing to do for read-only medium */
+error_t
+diskfs_reload_global_state ()
+{
+ return 0;
+}
+
+error_t
+diskfs_set_hypermetadata (int wait, int clean)
+{
+ return 0;
+}
+
+void
+diskfs_readonly_changed (int readonly)
+{
+ /* We should never get here because we set diskfs_hard_readonly above. */
+ abort ();
+}
diff --git a/isofs/pager.c b/isofs/pager.c
new file mode 100644
index 00000000..5142cbc8
--- /dev/null
+++ b/isofs/pager.c
@@ -0,0 +1,352 @@
+/*
+ Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <error.h>
+#include <string.h>
+#include "isofs.h"
+
+spin_lock_t node2pagelock = SPIN_LOCK_INITIALIZER;
+
+struct port_bucket *pager_bucket;
+
+/* Mapped image of the disk */
+void *disk_image;
+
+
+/* Implement the pager_read_page callback from the pager library. See
+ <hurd/pager.h> for the interface definition. */
+error_t
+pager_read_page (struct user_pager_info *upi,
+ vm_offset_t page,
+ vm_address_t *buf,
+ int *writelock)
+{
+ error_t err;
+ daddr_t addr;
+ struct node *np = upi->np;
+ size_t read = 0;
+ size_t overrun = 0;
+
+ /* This is a read-only medium */
+ *writelock = 1;
+
+ if (upi->type == FILE_DATA)
+ {
+ addr = np->dn->file_start + (page >> store->log2_block_size);
+
+ if (page >= np->dn_stat.st_size)
+ {
+ *buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ return 0;
+ }
+
+ if (page + vm_page_size > np->dn_stat.st_size)
+ overrun = page + vm_page_size - np->dn_stat.st_size;
+ }
+ else
+ {
+ assert (upi->type == DISK);
+ addr = page >> store->log2_block_size;
+ }
+
+ err = store_read (store, addr, vm_page_size, (void **) buf, &read);
+ if (read != vm_page_size)
+ return EIO;
+
+ if (overrun)
+ bzero ((void *) *buf + vm_page_size - overrun, overrun);
+
+ return 0;
+}
+
+/* This function should never be called. */
+error_t
+pager_write_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t buf)
+{
+ assert (0);
+}
+
+/* Never permit unlocks to succeed. */
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t address)
+{
+ return EROFS;
+}
+
+/* Tell how big the file is. */
+error_t
+pager_report_extent (struct user_pager_info *pager,
+ vm_address_t *offset,
+ vm_size_t *size)
+{
+ *offset = 0;
+ *size = pager->np->dn_stat.st_size;
+ return 0;
+}
+
+/* Implement the pager_clear_user_data callback from the pager library. */
+void
+pager_clear_user_data (struct user_pager_info *upi)
+{
+ if (upi->type == FILE_DATA)
+ {
+ spin_lock (&node2pagelock);
+ if (upi->np->dn->fileinfo == upi)
+ upi->np->dn->fileinfo = 0;
+ spin_unlock (&node2pagelock);
+ diskfs_nrele_light (upi->np);
+ }
+ free (upi);
+}
+
+void
+pager_dropweak (struct user_pager_info *upi)
+{
+}
+
+
+/* Create the disk pager */
+void
+create_disk_pager (void)
+{
+ struct user_pager_info *upi = malloc (sizeof (struct user_pager_info));
+
+ if (!upi)
+ error (1, errno, "Could not create disk pager");
+ upi->type = DISK;
+ upi->np = 0;
+ pager_bucket = ports_create_bucket ();
+ diskfs_start_disk_pager (upi, pager_bucket, 1, store->size, &disk_image);
+ upi->p = diskfs_disk_pager;
+}
+
+/* This need not do anything */
+void
+diskfs_file_update (struct node *np,
+ int wait)
+{
+}
+
+/* Create a FILE_DATA pager for the specified node */
+mach_port_t
+diskfs_get_filemap (struct node *np, vm_prot_t prot)
+{
+ struct user_pager_info *upi;
+ mach_port_t right;
+
+ assert (S_ISDIR (np->dn_stat.st_mode)
+ || S_ISREG (np->dn_stat.st_mode)
+ || S_ISLNK (np->dn_stat.st_mode));
+
+ spin_lock (&node2pagelock);
+
+ do
+ if (!np->dn->fileinfo)
+ {
+ upi = malloc (sizeof (struct user_pager_info));
+ upi->type = FILE_DATA;
+ upi->np = np;
+ diskfs_nref_light (np);
+ upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_DELAY);
+ if (upi->p == 0)
+ {
+ diskfs_nrele_light (np);
+ free (upi);
+ spin_unlock (&node2pagelock);
+ return MACH_PORT_NULL;
+ }
+ np->dn->fileinfo = upi;
+ right = pager_get_port (np->dn->fileinfo->p);
+ ports_port_deref (np->dn->fileinfo->p);
+ }
+ else
+ {
+ /* Because NP->dn->fileinfo->p is not a real reference,
+ this might be nearly deallocated. If that's so, then
+ the port right will be null. In that case, clear here
+ and loop. The deallocation will complete separately. */
+ right = pager_get_port (np->dn->fileinfo->p);
+ if (right == MACH_PORT_NULL)
+ np->dn->fileinfo = 0;
+ }
+ while (right == MACH_PORT_NULL);
+
+ spin_unlock (&node2pagelock);
+
+ mach_port_insert_right (mach_task_self (), right, right,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+ return right;
+}
+
+/* Call this when we should turn off caching so that unused memory
+ object ports get freed. */
+void
+drop_pager_softrefs (struct node *np)
+{
+ struct user_pager_info *upi;
+
+ spin_lock (&node2pagelock);
+ upi = np->dn->fileinfo;
+ if (upi)
+ ports_port_ref (upi->p);
+ spin_unlock (&node2pagelock);
+
+ if (upi)
+ {
+ pager_change_attributes (upi->p, 0, MEMORY_OBJECT_COPY_DELAY, 0);
+ ports_port_deref (upi->p);
+ }
+}
+
+/* Call this when we should turn on caching because it's no longer
+ important for unused memory object ports to get freed. */
+void
+allow_pager_softrefs (struct node *np)
+{
+ struct user_pager_info *upi;
+
+ spin_lock (&node2pagelock);
+ upi = np->dn->fileinfo;
+ if (upi)
+ ports_port_ref (upi->p);
+ spin_unlock (&node2pagelock);
+
+ if (upi)
+ {
+ pager_change_attributes (upi->p, 1, MEMORY_OBJECT_COPY_DELAY, 0);
+ ports_port_deref (upi->p);
+ }
+}
+
+
+static void
+block_caching ()
+{
+ error_t block_cache (void *arg)
+ {
+ struct pager *p = arg;
+
+ pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_DELAY, 1);
+ return 0;
+ }
+
+ /* Loop through the pagers and turn off caching one by one,
+ synchronously. That should cause termination of each pager. */
+ ports_bucket_iterate (pager_bucket, block_cache);
+}
+
+static void
+enable_caching ()
+{
+ error_t enable_cache (void *arg)
+ {
+ struct pager *p = arg;
+ struct user_pager_info *upi = pager_get_upi (p);
+
+ pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_DELAY, 0);
+
+ /* It's possible that we didn't have caching on before, because
+ the user here is the only reference to the underlying node
+ (actually, that's quite likely inside this particular
+ routine), and if that node has no links. So dinkle the node
+ ref counting scheme here, which will cause caching to be
+ turned off, if that's really necessary. */
+ if (upi->type == FILE_DATA)
+ {
+ diskfs_nref (upi->np);
+ diskfs_nrele (upi->np);
+ }
+
+ return 0;
+ }
+
+ ports_bucket_iterate (pager_bucket, enable_cache);
+}
+
+
+/* Tell diskfs if there are pagers exported, and if none, then
+ prevent any new ones from showing up. */
+int
+diskfs_pager_users ()
+{
+ int npagers = ports_count_bucket (pager_bucket);
+
+ if (npagers <= 1)
+ return 0;
+
+ block_caching ();
+
+ /* Give it a second; the kernel doesn't actually shutdown
+ immediately. XXX */
+ sleep (1);
+
+ npagers = ports_count_bucket (pager_bucket);
+ if (npagers <= 1)
+ return 0;
+
+ /* Darn, there are actual honest users. Turn caching back on,
+ and return failure. */
+ enable_caching ();
+
+ ports_enable_bucket (pager_bucket);
+
+ return 1;
+}
+
+/* Return the bitwise or of the maximum prot parameter (the second arg to
+ diskfs_get_filemap) for all active user pagers. */
+vm_prot_t
+diskfs_max_user_pager_prot ()
+{
+ /* We never allow writing, so there's no need to carefully check it. */
+ return VM_PROT_READ | VM_PROT_EXECUTE;
+}
+
+/* Call this to find out the struct pager * corresponding to the
+ FILE_DATA pager of inode IP. This should be used *only* as a subsequent
+ argument to register_memory_fault_area, and will be deleted when
+ the kernel interface is fixed. NP must be locked. */
+struct pager *
+diskfs_get_filemap_pager_struct (struct node *np)
+{
+ /* This is safe because fileinfo can't be cleared; there must be
+ an active mapping for this to be called. */
+ return np->dn->fileinfo->p;
+}
+
+/* Shutdown all the pagers. */
+void
+diskfs_shutdown_pager ()
+{
+ /* Because there's no need to ever sync, we don't have to do anything
+ here. */
+}
+
+/* Sync all the pagers. */
+void
+diskfs_sync_everything (int wait)
+{
+ /* ditto */
+}
diff --git a/isofs/rr.c b/isofs/rr.c
new file mode 100644
index 00000000..be4395d6
--- /dev/null
+++ b/isofs/rr.c
@@ -0,0 +1,649 @@
+/*
+ Copyright (C) 1997,99,2002 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Parse Rock-Ridge and related SUSP conformant extensions. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "isofs.h"
+
+/* These tell whether the specified extensions are on or not. */
+int susp_live = 0;
+int rock_live = 0;
+int gnuext_live = 0;
+
+/* How far to skip when reading SUSP fields. */
+int susp_skip = 0;
+
+void
+release_rrip (struct rrip_lookup *rr)
+{
+ if ((rr->valid & VALID_NM) && rr->name)
+ free (rr->name);
+ if ((rr->valid & VALID_SL) && rr->target)
+ free (rr->target);
+ if ((rr->valid & VALID_TR) && rr->trans)
+ free (rr->trans);
+}
+
+
+/* Work function combining the three interfaces below. */
+static int
+rrip_work (struct dirrect *dr, struct rrip_lookup *rr,
+ const char *match_name, size_t match_name_len,
+ int initializing, int ignorenm)
+{
+ void *bp, *terminus;
+ void *slbuf, *nmbuf;
+ size_t slbufsize, nmbufsize;
+ int nomorenm, nomoresl;
+
+ /* Initialize RR */
+ rr->valid = 0;
+ rr->target = rr->name = 0;
+
+ if (!susp_live && !initializing)
+ return 0;
+
+ /* The only extensions we currently support are rock-ridge, so
+ this test will cut a lot of useless work. */
+ if (!rock_live && !initializing)
+ return 0;
+
+ /* Initialized the name buffers */
+ nmbuf = slbuf = 0;
+ nmbufsize = slbufsize = 0;
+ nomorenm = nomoresl = 0;
+
+ /* Find the beginning and end of the SUSP area */
+
+ /* If this is the root node, from the root directory, then
+ we look in a special place. This only happens during the two
+ calls in fetch_root, and we know exactly what the value passed
+ is there. */
+
+ if (dr == (struct dirrect *)sblock->root)
+ {
+ struct dirrect *p;
+ off_t filestart;
+ char *c;
+ error_t err;
+
+ /* Look at the first directory entry in root. */
+ err = calculate_file_start (dr, &filestart, 0);
+ if (err)
+ return 0; /* give up */
+ p = disk_image + (filestart << store->log2_block_size);
+
+ /* Set C to the system use area. */
+ c = p->name + p->namelen;
+ if ((uintptr_t)c & 1)
+ c++;
+
+ /* There needs to be an SUSP SP field right here; make sure there is */
+ if (!bcmp (c, "SP\7\1\276\357", 6))
+ bp = c;
+ else if (!bcmp (c + 15, "SP\7\1\276\357", 6))
+ /* Detect CD-ROM XA disk */
+ bp = c + 15;
+ else
+ /* No SUSP, give up. */
+ return 0;
+
+ terminus = (char *) p + p->len;
+ }
+ else
+ {
+ /* It's in the normal place. */
+ bp = dr->name + dr->namelen;
+ if ((uintptr_t) bp & 1)
+ bp++; /* must be even */
+ bp += susp_skip; /* skip to start of susp area */
+ terminus = (char *) dr + dr->len;
+ }
+
+
+ /* Loop across all the fields, processing them one at a time. */
+
+ while (bp < terminus)
+ {
+ struct su_header *susp = bp;
+ void *body;
+
+ /* Make sure the whole thing fits */
+ if (bp + sizeof (struct su_header) > terminus
+ || bp + susp->len > terminus)
+ break;
+
+ body = (char *) susp + sizeof (struct su_header);
+
+ /* CE means that further extension fields are elsewhere on
+ the disk. We just reset the pointers and keep going. */
+ if (susp->sig[0] == 'C'
+ && susp->sig[1] == 'E'
+ && susp->version == 1)
+ {
+ int offset;
+ int location;
+ int size;
+ struct su_ce *ce = body;
+
+ offset = isonum_733 (ce->offset);
+ location = isonum_733 (ce->continuation);
+ size = isonum_733 (ce->size);
+
+ /* Reset pointers */
+ bp = disk_image + (location * logical_block_size) + offset;
+ terminus = bp + size;
+
+ /* NOT goto next_field */
+ continue;
+ }
+
+ /* Only on the root node; SP signals that the sharing protocol
+ is in use. */
+ if (initializing
+ && susp->sig[0] == 'S'
+ && susp->sig[1] == 'P'
+ && susp->version == 1)
+ {
+ /* Sharing Protocol */
+ struct su_sp *sp = body;
+
+ /* Verify magic numbers */
+ if (sp->check[0] == SU_SP_CHECK_0
+ && sp->check[1] == SU_SP_CHECK_1)
+ susp_live = 1;
+
+ susp_skip = sp->skip;
+
+ goto next_field;
+ }
+
+ /* Only on the root node; ER signals that a specified extension
+ is present. We implement and check for only the Rock Ridge
+ extension. */
+ if (initializing
+ && susp->sig[0] == 'E'
+ && susp->sig[1] == 'R'
+ && susp->version == 1)
+ {
+ /* Extension Reference */
+ struct su_er *er = body;
+
+ /* Make sure the ER field is valid */
+ if ((void *) er->more + er->len_id + er->len_des + er->len_src
+ < terminus)
+ goto next_field;
+
+ /* Check for rock-ridge */
+ if (er->ext_ver == ROCK_VERS
+ && !memcmp (ROCK_ID, er->more, er->len_id))
+ rock_live = 1;
+
+ /* Check for Gnuext */
+ else if (er->ext_ver == GNUEXT_VERS
+ && !memcmp (GNUEXT_ID, er->more, er->len_id))
+ gnuext_live = 1;
+ }
+
+ /* PD fields are padding and just get ignored. */
+ if (susp->sig[0] == 'P'
+ && susp->sig[1] == 'D'
+ && susp->version == 1)
+ goto next_field;
+
+ /* ST fields mean that there are no more SUSP fields to be processed. */
+ if (susp->sig[0] == 'S'
+ && susp->sig[1] == 'T'
+ && susp->version == 1)
+ /* All done */
+ break;
+
+ /* The rest are Rock-Ridge, and are not interesting if we are doing
+ setup. */
+
+ if (initializing || !rock_live)
+ goto next_field;
+
+ /* RE is present in a directory entry to mean that the node
+ is specified by a CL field elsewhere. So this entry needs
+ to be ignored by anyone who understands CL fields. */
+ if (susp->sig[0] == 'R'
+ && susp->sig[1] == 'E'
+ && susp->version == 1)
+ {
+ rr->valid |= VALID_RE;
+
+ /* No point in parsing anything else now. */
+ break;
+ }
+
+ /* NM identifies the real name of the file; it overrides
+ the name in the directory. */
+ if (susp->sig[0] == 'N'
+ && susp->sig[1] == 'M'
+ && susp->version == 1
+ && !ignorenm)
+ {
+ struct rr_nm *nm = body;
+ size_t nmlen = susp->len - 5;
+ char *name;
+ size_t namelen;
+
+ if (nomorenm)
+ goto next_field;
+
+ if (nm->flags & NAME_DOT)
+ {
+ name = ".";
+ namelen = 1;
+ goto finalize_nm;
+ }
+ else if (nm->flags & NAME_DOTDOT)
+ {
+ name = "..";
+ namelen = 2;
+ goto finalize_nm;
+ }
+ else if (nm->flags & NAME_HOST)
+ {
+ name = host_name;
+ namelen = strlen (host_name);
+ goto finalize_nm;
+ }
+
+ /* Add this component to the list. */
+
+ /* We don't store a trailing null here, but we always leave
+ room for it. The null gets stored in the finalization
+ code below. */
+ if (!nmbuf)
+ nmbuf = malloc ((nmbufsize = nmlen) + 1);
+ else
+ nmbuf = realloc (nmbuf, (nmbufsize += nmlen) + 1);
+ assert (nmbuf);
+
+ bcopy (nm->name, nmbuf + nmbufsize - nmlen, nmlen);
+
+ if (nm->flags & NAME_CONTINUE)
+ goto next_field;
+
+ name = nmbuf;
+ namelen = nmbufsize;
+
+ finalize_nm:
+ nomorenm = 1;
+
+ /* Is this a failed match? */
+ if (match_name && (match_name_len != namelen
+ || memcmp (match_name, name, match_name_len)))
+ {
+ if (nmbuf)
+ free (nmbuf);
+ return 0;
+ }
+
+ /* Store the name */
+ rr->valid |= VALID_NM;
+ if (name != nmbuf)
+ {
+ rr->name = strdup (name);
+ assert (rr->name);
+ }
+ else
+ {
+ rr->name = name;
+ name[namelen] = '\0';
+ }
+
+ if (rr->valid & VALID_CL)
+ /* Finalize CL processing. */
+ goto clrecurse;
+
+ goto next_field;
+ }
+
+ /* PX gives mode, nlink, uid, and gid posix-style attributes. */
+ if (susp->sig[0] == 'P'
+ && susp->sig[1] == 'X'
+ && susp->version == 1)
+ {
+ struct rr_px *px = body;
+
+ rr->valid |= VALID_PX;
+
+ rr->mode = isonum_733 (px->mode);
+ rr->nlink = isonum_733 (px->nlink);
+ rr->uid = isonum_733 (px->uid);
+ rr->gid = isonum_733 (px->gid);
+
+ goto next_field;
+ }
+
+ /* PN, for S_ISCHR and S_ISDEV devices gives the magic numbers */
+ if (susp->sig[0] == 'P'
+ && susp->sig[1] == 'N'
+ && susp->version == 1)
+ {
+ struct rr_pn *pn = body;
+
+ rr->valid |= VALID_PN;
+ rr->rdev = makedev (isonum_733 (pn->high), isonum_733 (pn->low));
+
+ goto next_field;
+ }
+
+ /* SL tells, for a symlink, what the target of the link is */
+ if (susp->sig[0] == 'S'
+ && susp->sig[1] == 'L'
+ && susp->version == 1)
+ {
+ struct rr_sl *sl = body;
+ size_t crlen = susp->len - 5;
+ struct rr_sl_comp *comp;
+ void *cp;
+ size_t targalloced, targused;
+
+ void add_comp (char *cname, size_t cnamelen)
+ {
+ if (rr->target == 0)
+ {
+ rr->target = malloc (cnamelen * 2);
+ targused = 0;
+ targalloced = cnamelen * 2;
+ }
+ else while (targused + cnamelen > targalloced)
+ rr->target = realloc (rr->target, targalloced *= 2);
+ assert (rr->target);
+
+ bcopy (cname, rr->target + targused, cnamelen);
+ targused += cnamelen;
+ }
+
+ if (nomoresl)
+ goto next_field;
+
+ /* Append the component use fields to the records we are saving
+ up */
+
+ if (!slbuf)
+ slbuf = malloc (slbufsize = crlen);
+ else
+ slbuf = realloc (slbuf, slbufsize += crlen);
+ assert (slbuf);
+
+ bcopy (sl->data, slbuf + slbufsize - crlen, crlen);
+
+ if (sl->flags & 1)
+ /* We'll finish later. */
+ goto next_field;
+
+ /* Do the symlink translation */
+ for (cp = slbuf; cp < slbuf + slbufsize; cp += comp->len + 2)
+ {
+ comp = (struct rr_sl_comp *)cp;
+ nomoresl = 1;
+
+ /* Put in a slash after each component as we go,
+ unless it's a "continuation" component. */
+
+ if (comp->flags & NAME_DOT)
+ add_comp ("./", 2);
+ else if (comp->flags & NAME_DOTDOT)
+ add_comp ("../", 3);
+ else if (comp->flags & NAME_ROOT)
+ {
+ targused = 0;
+ add_comp ("/", 1);
+ }
+ else if (comp->flags & NAME_VOLROOT)
+ {
+ targused = 0;
+ add_comp (mounted_on, strlen (mounted_on));
+ }
+ else if (comp->flags & NAME_HOST)
+ {
+ add_comp (host_name, strlen (host_name));
+ add_comp ("/", 1);
+ }
+ else
+ {
+ add_comp (comp->name, comp->len);
+ if (!(comp->flags & NAME_CONTINUE))
+ add_comp ("/", 1);
+ }
+ }
+
+ /* And turn the final character, if it's a slash, into a null.
+ Otherwise, add a null. */
+ if (rr->target[targused - 1] == '/')
+ rr->target[targused - 1] = '\0';
+ else
+ add_comp ("", 1);
+
+ rr->valid |= VALID_SL;
+
+ free (slbuf);
+ goto next_field;
+ }
+
+ /* TF gives atime, mtime, ctime (and others we don't care about);
+ this overrides the time specified in the directory. */
+ if (susp->sig[0] == 'T'
+ && susp->sig[1] == 'F'
+ && susp->version == 1)
+ {
+ char *(*convert)(char *, struct timespec *);
+ struct rr_tf *tf = body;
+ char *c;
+
+ if (tf->flags & TF_LONG_FORM)
+ convert = isodate_84261;
+ else
+ convert = isodate_915;
+
+ rr->valid |= VALID_TF;
+ rr->tfflags = tf->flags;
+ c = tf->data;
+
+ if (rr->tfflags & TF_CREATION)
+ c = (*convert) (c, &rr->ctime);
+ if (rr->tfflags & TF_MODIFY)
+ c = (*convert) (c, &rr->mtime);
+ if (rr->tfflags & TF_ACCESS)
+ c = (*convert) (c, &rr->atime);
+
+ goto next_field;
+ }
+
+ /* CL means that this entry is a relocated directory. We ignore
+ the attributes in this directory entry (except for NM); they
+ are fetched from the "." entry of the directory itself. The
+ CL field identifies the location of the directory, overriding
+ the location given in the present directory. This directory
+ is listed somewhere else too (to keep the format ISO 9660 compliant),
+ but there's an RE entry on that one so that we ignore it. */
+ if (susp->sig[0] == 'C'
+ && susp->sig[1] == 'L'
+ && susp->version == 1)
+ {
+ struct rr_cl *cl = body;
+
+ rr->realdirent
+ = disk_image + (isonum_733 (cl->loc) * logical_block_size);
+ rr->valid |= VALID_CL;
+
+ if (rr->valid & VALID_NM)
+ {
+ /* We've gotten all we care about from this node.
+ Remember the NM name, and load all the contents
+ from the new location. */
+ char *savename;
+ struct dirrect *realdir;
+
+ clrecurse:
+ /* It might look like VALID_NM is alway set here, but if
+ we got here from the exit point of the function, then
+ VALID_NM is actually clear. */
+
+ /* Save these, because rrip_work will clear them. */
+ savename = (rr->valid & VALID_NM) ? rr->name : 0;
+ realdir = rr->realdirent;
+
+ rrip_work (realdir, rr, 0, 0, 0, 1);
+
+ rr->valid |= VALID_CL;
+ rr->realdirent = realdir;
+ if (savename)
+ {
+ rr->valid |= VALID_NM;
+ rr->name = savename;
+ }
+
+ /* If there's an NM field, then we must have matched
+ if we got here. */
+ return (rr->valid & VALID_NM) ? 1 : 0;
+ }
+
+ /* We must keep looking for an NM record. When we find one,
+ the NM code will goto the above piece of code. */
+ goto next_field;
+ }
+
+ /* PL is found in the ".." entry of a relocated directory.
+ The present directory entry points to the fictitious parent
+ (the one that holds the fictitious RE link here); the PL
+ field identifies the real parent (the one that has the CL
+ entry). */
+ if (susp->sig[0] == 'P'
+ && susp->sig[1] == 'L'
+ && susp->version == 1)
+ {
+ struct rr_pl *pl = body;
+
+ rr->realfilestart = (isonum_733 (pl->loc)
+ * (logical_block_size
+ >> store->log2_block_size));
+ rr->valid |= VALID_PL;
+ goto next_field;
+ }
+
+ /* The rest are GNU ext. */
+ if (!gnuext_live)
+ goto next_field;
+
+ /* Author */
+ if (susp->sig[0] == 'A'
+ && susp->sig[1] == 'U'
+ && susp->version == 1)
+ {
+ struct gn_au *au = body;
+
+ rr->author = isonum_733 (au->author);
+ rr->valid |= VALID_AU;
+
+ goto next_field;
+ }
+
+ if (susp->sig[0] == 'T'
+ && susp->sig[1] == 'R'
+ && susp->version == 1)
+ {
+ struct gn_tr *tr = body;
+
+ rr->translen = tr->len;
+ rr->trans = malloc (rr->translen);
+ assert (rr->trans);
+ memcpy (tr->data, rr->trans, rr->translen);
+ rr->valid |= VALID_TR;
+
+ goto next_field;
+ }
+
+ if (susp->sig[0] == 'M'
+ && susp->sig[1] == 'D'
+ && susp->version == 1)
+ {
+ struct gn_md *md = body;
+
+ rr->allmode = isonum_733 (md->mode);
+ rr->valid |= VALID_MD;
+
+ goto next_field;
+ }
+
+ if (susp->sig[0] == 'F'
+ && susp->sig[1] == 'L'
+ && susp->version == 1)
+ {
+ struct gn_fl *fl = body;
+
+ rr->flags = isonum_733 (fl->flags);
+ rr->valid |= VALID_FL;
+
+ goto next_field;
+ }
+
+ next_field:
+ bp = bp + susp->len;
+ }
+
+ if (rr->valid & VALID_CL)
+ goto clrecurse;
+
+ /* If we saw an NM field, then it matched; otherwise we
+ didn't see one. */
+ return rr->valid & VALID_NM ? 1 : 0;
+}
+
+/* Parse extensions for directory entry DR. If we encounter an NM
+ record, and it does not match NAME (length NAMELEN), then stop
+ immediately (but do note the NM file in RR->valid) and return zero.
+ If we encounter no NM record at all, then process all the fields
+ normally and return zero. If we encounter an NM field which matches
+ the provided name, then process all the fields and return 1. In any
+ case, fill RR with information corresponding to the fields we do
+ encounter. */
+int
+rrip_match_lookup (struct dirrect *dr, const char *name, size_t namelen,
+ struct rrip_lookup *rr)
+{
+ return rrip_work (dr, rr, name, namelen, 0, 0);
+}
+
+/* Parse extensions for dirrect DR and store the results in RR.
+ If IGNORENM, then do not bother with NM records. */
+void
+rrip_lookup (struct dirrect *dr, struct rrip_lookup *rr, int ignorenm)
+{
+ rrip_work (dr, rr, 0, 0, 0, ignorenm);
+}
+
+/* Scan extensions on dirrect DR looking for the tags that are supposed
+ to be on the root directory. */
+void
+rrip_initialize (struct dirrect *dr)
+{
+ struct rrip_lookup rr;
+ rrip_work (dr, &rr, 0, 0, 1, 1);
+ release_rrip (&rr);
+}
diff --git a/isofs/rr.h b/isofs/rr.h
new file mode 100644
index 00000000..ab80e4bd
--- /dev/null
+++ b/isofs/rr.h
@@ -0,0 +1,266 @@
+/*
+ Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "iso9660.h"
+
+/* The results of an rrip_scan_lookup call are one of these */
+struct rrip_lookup
+{
+ /* PX */
+ mode_t mode;
+ nlink_t nlink;
+ uid_t uid;
+ gid_t gid;
+
+ /* PN */
+ dev_t rdev;
+
+ /* SL */
+ char *target;
+
+ /* NM */
+ char *name; /* name of this entry if changed (malloced) */
+
+ /* CL */
+ off_t newloc; /* relocated directory */
+
+ /* PL */
+ off_t parloc; /* parent of relocated directory */
+
+ /* TF */
+ int tfflags;
+ struct timespec atime, mtime, ctime; /* file times */
+
+ /* CL */
+ struct dirrect *realdirent; /* actual directory entry for attributes */
+
+ /* RL */
+ off_t realfilestart; /* override file start in dir entry */
+
+ /* AU */
+ uid_t author;
+
+ /* TR */
+ size_t translen;
+ char *trans;
+
+ /* MD */
+ mode_t allmode;
+
+ /* FL */
+ long flags;
+
+ int valid;
+};
+
+/* VALID in one of these is from the following bits */
+#define VALID_PX 0x0001
+#define VALID_PN 0x0002
+#define VALID_SL 0x0004
+#define VALID_NM 0x0008
+#define VALID_CL 0x0010
+#define VALID_PL 0x0020
+#define VALID_TF 0x0040
+#define VALID_RE 0x0080
+#define VALID_AU 0x0100
+#define VALID_TR 0x0200
+#define VALID_MD 0x0400
+#define VALID_FL 0x0800
+
+
+/* Definitions for System Use Sharing Protocol.
+ Version 1. Revision 1.10. Dated July 16, 1993. */
+
+/* A system use field begins with the following header */
+struct su_header
+{
+ char sig[2];
+ unsigned char len;
+ char version;
+};
+
+/* The body of a CE (Continuation Area) field */
+struct su_ce
+{
+ char continuation[8];
+ char offset[8];
+ char size[8];
+};
+
+/* The body of a SP (Sharing Protocol Indicator) field */
+struct su_sp
+{
+ unsigned char check[2];
+ u_char skip;
+};
+
+#define SU_SP_CHECK_0 0xbe
+#define SU_SP_CHECK_1 0xef
+
+/* The body of a ER (Extension Reference) field */
+struct su_er
+{
+ u_char len_id;
+ u_char len_des;
+ u_char len_src;
+ u_char ext_ver;
+ char more[0];
+};
+
+
+
+
+/* Definitions for Rock Ridge extensions.
+ Version 1. Revision 1.10. Dated July 13, 1993. */
+
+/* These are the ER values to indicate the presence of Rock-Ridge
+ extensions. */
+#define ROCK_VERS 1
+#define ROCK_ID "RRIP_1991A"
+#define ROCK_DES \
+ "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS"
+#define ROCK_SRC \
+ "ROCK RIDGE SPECIFICATION VERSION 1 REVISION 1.10 JULY 13 1993"
+
+/* The body of a PX (Posix Attributes) field. */
+struct rr_px
+{
+ char mode[8];
+ char nlink[8];
+ char uid[8];
+ char gid[8];
+};
+
+/* The body of a PN (Posix Device Node) field. */
+struct rr_pn
+{
+ char high[8];
+ char low[8];
+};
+
+/* The body of a SL (Symbolic Link) field. */
+struct rr_sl
+{
+ u_char flags;
+ char data[0];
+};
+
+/* Each component in the DATA is: */
+struct rr_sl_comp
+{
+ u_char flags;
+ u_char len;
+ char name[0];
+};
+
+/* The body of a NM (Alternate Name) field. */
+struct rr_nm
+{
+ u_char flags;
+ char name[0];
+};
+
+/* Flags for SL and NM components */
+#define NAME_CONTINUE 0x01
+#define NAME_DOT 0x02
+#define NAME_DOTDOT 0x04
+#define NAME_ROOT 0x08
+#define NAME_VOLROOT 0x10
+#define NAME_HOST 0x20
+
+/* The body of a CL (Child Directory Location) field. */
+struct rr_cl
+{
+ char loc[8];
+};
+
+/* The body of a PL (Parent Directory Location) field. */
+struct rr_pl
+{
+ char loc[8];
+};
+
+/* The body of a TF (Time Stamp) field. */
+struct rr_tf
+{
+ u_char flags;
+ char data[0];
+};
+
+/* Flags for a TF */
+#define TF_CREATION 0x01
+#define TF_MODIFY 0x02
+#define TF_ACCESS 0x04
+#define TF_ATTRIBUTES 0x08
+#define TF_BACKUP 0x10
+#define TF_EXPIRATION 0x20
+#define TF_EFFECTIVE 0x40
+#define TF_LONG_FORM 0x80
+
+
+/* The body of a SF (Sparse File) field. */
+struct rr_sf
+{
+ char size[8];
+};
+
+
+/* GNU extensions */
+
+#define GNUEXT_VERS 1
+#define GNUEXT_ID "GNUEXT_1997"
+#define GNUEXT_DES \
+ "The GNU Extensions provide support for special GNU filesystem features"
+#define GNUEXT_SRC \
+ "GNU Hurd source release 0.3 or later"
+
+/* AU -- author (version 1) */
+struct gn_au
+{
+ char author[8];
+};
+
+/* TR -- translator (version 1) */
+struct gn_tr
+{
+ u_char len;
+ char data[0];
+};
+
+/* MD -- full mode (version 1) */
+struct gn_md
+{
+ char mode[8];
+};
+
+/* FL -- flags (version 1) */
+struct gn_fl
+{
+ char flags[8];
+};
+
+
+/* Rock-Ridge related functions. */
+
+int rrip_match_lookup (struct dirrect *, const char *,
+ size_t, struct rrip_lookup *);
+void rrip_lookup (struct dirrect *, struct rrip_lookup *, int);
+void rrip_initialize (struct dirrect *);
+void release_rrip (struct rrip_lookup *);
diff --git a/libcons/Makefile b/libcons/Makefile
new file mode 100644
index 00000000..38ca74a7
--- /dev/null
+++ b/libcons/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 1994,95,96,97,98,99,2000,01,02,2005,2010 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 := libcons
+makemode := library
+
+libname = libcons
+SRCS= demuxer.c init-init.c init-loop.c opts-version.c extra-version.c \
+ dir-changed.c file-changed.c opts-std-startup.c cons-lookup.c \
+ cons-switch.c vcons-remove.c vcons-add.c vcons-open.c \
+ vcons-close.c vcons-destroy.c vcons-refresh.c vcons-scrollback.c \
+ vcons-input.c vcons-move-mouse.c vcons-event.c
+LCLHDRS = priv.h mutations.h $(installhdrs)
+installhdrs = cons.h
+
+fs_notify-MIGSFLAGS = -imacros $(srcdir)/mutations.h
+MIGSTUBS = fs_notifyServer.o
+OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
+
+HURDLIBS = threads ports
+
+MIGCOMSFLAGS = -prefix cons_
+
+include ../Makeconf
diff --git a/libcons/cons-lookup.c b/libcons/cons-lookup.c
new file mode 100644
index 00000000..d91cc3ce
--- /dev/null
+++ b/libcons/cons-lookup.c
@@ -0,0 +1,107 @@
+/* cons-lookup.c - Looking up virtual consoles.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <malloc.h>
+#include <sys/mman.h>
+
+#include "cons.h"
+
+/* Lookup the virtual console entry with number ID in the console
+ CONS, and return it in R_VCONS_ENTRY. If CREATE is true, the
+ virtual console entry will be created if it doesn't exist yet. If
+ CREATE is true, and ID 0, the first free virtual console id is
+ used. CONS must be locked. */
+error_t
+cons_lookup (cons_t cons, int id, int create, vcons_list_t *r_vcons_entry)
+{
+ vcons_list_t previous_vcons_entry = 0;
+ vcons_list_t vcons_entry;
+
+ if (!id && !create)
+ return EINVAL;
+
+ if (id)
+ {
+ if (cons->vcons_list && cons->vcons_list->id <= id)
+ {
+ previous_vcons_entry = cons->vcons_list;
+ while (previous_vcons_entry->next
+ && previous_vcons_entry->next->id <= id)
+ previous_vcons_entry = previous_vcons_entry->next;
+ if (previous_vcons_entry->id == id)
+ {
+ *r_vcons_entry = previous_vcons_entry;
+ return 0;
+ }
+ }
+ else if (!create)
+ return ESRCH;
+ }
+ else
+ {
+ id = 1;
+ if (cons->vcons_list && cons->vcons_list->id == 1)
+ {
+ previous_vcons_entry = cons->vcons_list;
+ while (previous_vcons_entry && previous_vcons_entry->id == id)
+ {
+ id++;
+ previous_vcons_entry = previous_vcons_entry->next;
+ }
+ }
+ }
+
+ vcons_entry = calloc (1, sizeof (struct vcons_list));
+ if (!vcons_entry)
+ return ENOMEM;
+
+ vcons_entry->id = id;
+ vcons_entry->vcons = NULL;
+
+ /* Insert the virtual console into the doubly linked list. */
+ if (previous_vcons_entry)
+ {
+ vcons_entry->prev = previous_vcons_entry;
+ if (previous_vcons_entry->next)
+ {
+ previous_vcons_entry->next->prev = vcons_entry;
+ vcons_entry->next = previous_vcons_entry->next;
+ }
+ else
+ cons->vcons_last = vcons_entry;
+ previous_vcons_entry->next = vcons_entry;
+ }
+ else
+ {
+ if (cons->vcons_list)
+ {
+ cons->vcons_list->prev = vcons_entry;
+ vcons_entry->next = cons->vcons_list;
+ }
+ else
+ cons->vcons_last = vcons_entry;
+ cons->vcons_list = vcons_entry;
+ }
+
+ cons_vcons_add (cons, vcons_entry);
+ *r_vcons_entry = vcons_entry;
+ return 0;
+}
diff --git a/libcons/cons-switch.c b/libcons/cons-switch.c
new file mode 100644
index 00000000..752af97e
--- /dev/null
+++ b/libcons/cons-switch.c
@@ -0,0 +1,88 @@
+/* cons-switch.c - Switch to another virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+
+#include "cons.h"
+
+/* Open the virtual console ID or the virtual console DELTA steps away
+ from VCONS in the linked list and return it in R_VCONS, which will
+ be locked. */
+error_t
+cons_switch (vcons_t vcons, int id, int delta, vcons_t *r_vcons)
+{
+ error_t err = 0;
+ cons_t cons = vcons->cons;
+ vcons_list_t vcons_entry = NULL;
+
+ if (!id && !delta)
+ return 0;
+
+ mutex_lock (&cons->lock);
+ if (id)
+ {
+ vcons_entry = cons->vcons_list;
+ while (vcons_entry && vcons_entry->id != id)
+ vcons_entry = vcons_entry->next;
+ }
+ else if (delta > 0)
+ {
+ vcons_entry = vcons->vcons_entry;
+ while (delta-- > 0)
+ {
+ vcons_entry = vcons_entry->next;
+ if (!vcons_entry)
+ vcons_entry = cons->vcons_list;
+ }
+ }
+ else
+ {
+ assert (delta < 0);
+ vcons_entry = vcons->vcons_entry;
+ while (delta++ < 0)
+ {
+ vcons_entry = vcons_entry->prev;
+ if (!vcons_entry)
+ vcons_entry = cons->vcons_last;
+ }
+ }
+
+ if (!vcons_entry)
+ {
+ mutex_unlock (&cons->lock);
+ return ESRCH;
+ }
+
+ if (vcons_entry->vcons)
+ {
+ *r_vcons = vcons_entry->vcons;
+ mutex_lock (&vcons_entry->vcons->lock);
+ }
+ else
+ {
+ err = cons_vcons_open (cons, vcons_entry, r_vcons);
+ if (!err)
+ vcons_entry->vcons = *r_vcons;
+ }
+
+ mutex_unlock (&cons->lock);
+ return err;
+}
diff --git a/libcons/cons.h b/libcons/cons.h
new file mode 100644
index 00000000..e9d01a8c
--- /dev/null
+++ b/libcons/cons.h
@@ -0,0 +1,331 @@
+/* cons.h - Definitions for cons helper and callback functions.
+ Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _HURD_CONS_H
+#define _HURD_CONS_H
+
+#include <dirent.h>
+
+#include <hurd/ports.h>
+#include <mach.h>
+
+#include <hurd/console.h>
+
+typedef struct cons *cons_t;
+typedef struct vcons_list *vcons_list_t;
+typedef struct vcons *vcons_t;
+typedef struct cons_notify *cons_notify_t;
+
+struct vcons_list
+{
+ cons_t cons;
+ vcons_list_t next;
+ vcons_list_t prev;
+
+ /* The ID of the virtual console entry in the list. */
+ int id;
+
+ /* The opened vcons port on which we receive notifications. */
+ vcons_t vcons;
+};
+
+struct cons_notify
+{
+ struct port_info pi;
+
+ /* This is set for the dir notification port. */
+ cons_t cons;
+};
+
+struct vcons
+{
+ /* This must come first for the port info structure. */
+ struct cons_notify notify;
+
+ /* These elements are static from creation time. */
+ cons_t cons;
+ vcons_list_t vcons_entry;
+ int id;
+
+ /* The lock that protects all other members. */
+ struct mutex lock;
+
+ /* The FD of the input node. */
+ int input;
+
+ /* The shared memory of the display. */
+ struct cons_display *display;
+ size_t display_size;
+
+ struct
+ {
+ uint32_t flags;
+ struct
+ {
+ uint32_t col;
+ uint32_t row;
+ uint32_t status;
+ } cursor;
+ struct
+ {
+ uint32_t width;
+ uint32_t height;
+ uint32_t lines;
+ uint32_t cur_line;
+ uint32_t scr_lines;
+ conchar_t *matrix;
+ } screen;
+ struct
+ {
+ uint32_t audible;
+ uint32_t visible;
+ } bell;
+ struct
+ {
+ uint32_t written;
+ uint32_t length;
+ cons_change_t *buffer;
+ } changes;
+ } state;
+
+ uint32_t scrolling;
+};
+
+struct cons
+{
+ /* Protects the cons structure and the linked list in
+ VCONS_LIST. */
+ struct mutex lock;
+ vcons_list_t vcons_list;
+ vcons_list_t vcons_last;
+
+ struct port_class *port_class;
+ struct port_bucket *port_bucket;
+ DIR *dir;
+ io_t dirport;
+ int slack;
+};
+
+/* Determines if the mouse moves relatively, to an absolute location
+ or to an absolute location expressed by a percentage. */
+enum mouse_movement
+ {
+ CONS_VCONS_MOUSE_MOVE_REL,
+ CONS_VCONS_MOUSE_MOVE_ABS,
+ CONS_VCONS_MOUSE_MOVE_ABS_PERCENT
+ };
+
+/* The status of a mouse button. */
+enum mouse_button
+ {
+ CONS_VCONS_MOUSE_BUTTON_NO_OP,
+ CONS_VCONS_MOUSE_BUTTON_PRESSED,
+ CONS_VCONS_MOUSE_BUTTON_RELEASED
+ };
+
+/* An event produced by mouse movement an button presses. */
+typedef struct mouse_event
+{
+ enum mouse_movement mouse_movement;
+ float x;
+ float y;
+
+ enum mouse_button mouse_button;
+ int button;
+} *mouse_event_t;
+
+
+/* The user must define this variable. Set this to the name of the
+ console client. */
+extern const char *cons_client_name;
+
+/* The user must define this variable. Set this to be the client
+ version number. */
+extern const char *cons_client_version;
+
+/* The user may define this variable. Set this to be any additional
+ version specification that should be printed for --version. */
+extern char *cons_extra_version;
+
+/* The user must define this function. Deallocate the scarce
+ resources (like font glyph slots, colors etc) in the LENGTH entries
+ of the screen matrix starting from position COL and ROW. This call
+ is immediately followed by calls to cons_vcons_write that cover the
+ same area. If there are no scarce resources, the caller might do
+ nothing. */
+void cons_vcons_clear (vcons_t vcons, size_t length,
+ uint32_t col, uint32_t row);
+
+/* The user must define this function. Write LENGTH characters
+ starting from STR on the virtual console VCONS, which is locked,
+ starting from position COL and ROW. */
+void cons_vcons_write (vcons_t vcons, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row);
+
+/* The user must define this function. Set the cursor on virtual
+ console VCONS, which is locked, to position COL and ROW. */
+void cons_vcons_set_cursor_pos (vcons_t vcons, uint32_t col, uint32_t row);
+
+/* The user must define this function. Set the cursor status of
+ virtual console VCONS, which is locked, to STATUS. */
+void cons_vcons_set_cursor_status (vcons_t vcons, uint32_t status);
+
+/* The user must define this function. Scroll the content of virtual
+ console VCONS, which is locked, up by DELTA if DELTA is positive or
+ down by -DELTA if DELTA is negative. DELTA will never be zero, and
+ the absolute value if DELTA will be smaller than or equal to the
+ height of the screen matrix.
+
+ This call will be immediately followed by corresponding
+ cons_vcons_write calls to fill the resulting gap on the screen, and
+ VCONS will be looked throughout the whole time. The purpose of the
+ function is two-fold: It is called with an absolute value of DELTA
+ smaller than the screen height to perform scrolling. It is called
+ with an absolute value of DELTA equal to the screen height to
+ prepare a full refresh of the screen. In the latter case the user
+ should not really perform any scrolling. Instead it might
+ deallocate limited resources (like display glyph slots and palette
+ colors) if that helps to perform the subsequent write, just like
+ cons_vcons_clear. It goes without saying that the same
+ deallocation, if any, should be performed on the area that will be
+ filled with the scrolled in content.
+
+ XXX Possibly need a function to invalidate scrollback buffer, or in
+ general to signal a switch of the console so state can be reset.
+ Only do this if we make guarantees about validity of scrollback
+ buffer, of course.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+void cons_vcons_scroll (vcons_t vcons, int delta);
+
+/* The user may define this function. Make the changes from
+ cons_vcons_write, cons_vcons_set_cursor_pos,
+ cons_vcons_set_cursor_status and cons_vcons_scroll active. VCONS
+ is locked and will have been continuously locked from the first
+ change since the last update on. This is the latest possible point
+ the user must make the changes visible from. The user can always
+ make the changes visible at a more convenient, earlier time. */
+void cons_vcons_update (vcons_t vcons);
+
+/* The user must define this function. Make the virtual console
+ VCONS, which is locked, beep audibly. */
+void cons_vcons_beep (vcons_t vcons);
+
+/* The user must define this function. Make the virtual console
+ VCONS, which is locked, flash visibly. */
+void cons_vcons_flash (vcons_t vcons);
+
+/* The user must define this function. Notice the current status of
+ the scroll lock flag. */
+void cons_vcons_set_scroll_lock (vcons_t vcons, int onoff);
+
+/* The user must define this function. It is called whenever a
+ virtual console is selected to be the active one. It is the user's
+ responsibility to close the console at some later time. */
+error_t cons_vcons_activate (vcons_t vcons);
+
+/* The user may define this function. It is called after a
+ virtual console entry was added. CONS is locked. */
+void cons_vcons_add (cons_t cons, vcons_list_t vcons_entry);
+
+/* The user may define this function. It is called just before a
+ virtual console entry is removed. CONS is locked. */
+void cons_vcons_remove (cons_t cons, vcons_list_t vcons_entry);
+
+/* Open the virtual console ID or the virtual console DELTA steps away
+ from VCONS in the linked list and return it in R_VCONS, which will
+ be locked. */
+error_t cons_switch (vcons_t vcons, int id, int delta, vcons_t *r_vcons);
+
+/* Enter SIZE bytes from the buffer BUF into the virtual console
+ VCONS. */
+error_t cons_vcons_input (vcons_t vcons, char *buf, size_t size);
+
+/* The user must define this function. Clear the existing screen
+ matrix and set the size of the screen matrix to the dimension COL x
+ ROW. This call will be immediately followed by a call to
+ cons_vcons_write that covers the whole new screen matrix. */
+error_t cons_vcons_set_dimension (vcons_t vcons,
+ uint32_t col, uint32_t row);
+
+typedef enum
+ {
+ CONS_SCROLL_DELTA_LINES, CONS_SCROLL_DELTA_SCREENS,
+ CONS_SCROLL_ABSOLUTE_LINE, CONS_SCROLL_ABSOLUTE_PERCENTAGE
+ } cons_scroll_t;
+
+/* Scroll back into the history of VCONS. If TYPE is
+ CONS_SCROLL_DELTA_LINES, scroll up or down by VALUE lines. If TYPE
+ is CONS_SCROLL_DELTA_SCREENS, scroll up or down by VALUE multiples
+ of a screen height. If TYPE is CONS_SCROLL_ABSOLUTE_LINE, scroll to
+ line VALUE (where 0 is the lowest line). If TYPE is
+ CONS_SCROLL_ABSOLUTE_PERCENTAGE, scroll to the position determined
+ by VALUE, where 0 is the bottom and 1 is the top.
+
+ The function returns the number of lines actually scrolled up or
+ down. */
+int cons_vcons_scrollback (vcons_t vcons, cons_scroll_t type, float value);
+
+/* Set the mouse cursor position to X, Y. VCONS is locked. */
+error_t cons_vcons_set_mousecursor_pos (vcons_t vcons, float x, float y);
+
+/* If STATUS is set to 0, hide the mouse cursor, otherwise show
+ it. VCONS is locked. */
+error_t cons_vcons_set_mousecursor_status (vcons_t vcons, int status);
+
+
+
+extern const struct argp cons_startup_argp;
+
+extern struct port_bucket *cons_port_bucket;
+extern struct port_class *cons_port_class;
+
+/* The filename of the console server. */
+extern char *cons_file;
+
+error_t cons_init (void);
+void cons_server_loop (void);
+int cons_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp);
+
+/* Lookup the virtual console with number ID in the console CONS,
+ acquire a reference for it, and return its list entry in R_VCONS.
+ If CREATE is true, the virtual console will be created if it
+ doesn't exist yet. If CREATE is true, and ID 0, the first free
+ virtual console id is used. CONS must be locked. */
+error_t cons_lookup (cons_t cons, int id, int create, vcons_list_t *r_vcons);
+
+/* Open the virtual console for VCONS_ENTRY. CONS is locked. */
+error_t cons_vcons_open (cons_t cons, vcons_list_t vcons_entry,
+ vcons_t *r_vcons);
+
+/* Close the virtual console VCONS. VCONS->cons is locked. */
+void cons_vcons_close (vcons_t vcons);
+
+/* Destroy the virtual console VCONS. */
+void cons_vcons_destroy (void *port);
+
+/* Redraw the virtual console VCONS, which is locked. */
+void cons_vcons_refresh (vcons_t vcons);
+
+/* Handle the event EV on the virtual console VCONS. */
+error_t cons_vcons_move_mouse (vcons_t vcons, mouse_event_t ev);
+
+#endif /* hurd/cons.h */
diff --git a/libmom/refs-identical.c b/libcons/demuxer.c
index 0c4ee885..8982bfa9 100644
--- a/libmom/refs-identical.c
+++ b/libcons/demuxer.c
@@ -1,6 +1,6 @@
-/* Tell if two mom port references refer to the same channel
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* demuxer.c - Message demuxer for console client library.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
This file is part of the GNU Hurd.
@@ -18,11 +18,13 @@
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 "cons.h"
int
-mom_ports_identical (struct mom_port_ref *obj1,
- struct mom_port_ref *obj2)
+cons_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
{
- return obj1->port == obj2->port;
+ int cons_fs_notify_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+
+ return (cons_fs_notify_server (inp, outp));
}
+
diff --git a/libcons/dir-changed.c b/libcons/dir-changed.c
new file mode 100644
index 00000000..e1997d0f
--- /dev/null
+++ b/libcons/dir-changed.c
@@ -0,0 +1,129 @@
+/* dir-changed.c - Handling dir changed notifications.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <dirent.h>
+#include <assert.h>
+#include <mach.h>
+#include <cthreads.h>
+
+#include "cons.h"
+#include "fs_notify_S.h"
+
+
+static error_t
+add_one (cons_t cons, char *name)
+{
+ unsigned long int nr;
+ char *tail;
+
+ errno = 0;
+ nr = strtoul (name, &tail, 10);
+ if (!errno && *tail == '\0' && nr > 0)
+ {
+ vcons_list_t vcons_entry;
+ return cons_lookup (cons, nr, 1, &vcons_entry);
+ }
+ return 0;
+}
+
+static error_t
+lookup_one (cons_t cons, char *name, vcons_list_t *vcons_entry)
+{
+ unsigned long int nr;
+ char *tail;
+
+ errno = 0;
+ nr = strtoul (name, &tail, 10);
+ if (!errno && *tail == '\0' && nr > 0)
+ return cons_lookup (cons, nr, 0, vcons_entry);
+ return 0;
+}
+
+
+kern_return_t
+cons_S_dir_changed (cons_notify_t notify, natural_t tickno,
+ dir_changed_type_t change, string_t name)
+{
+ error_t err;
+ cons_t cons;
+
+ if (!notify || !notify->cons)
+ return EOPNOTSUPP;
+ cons = notify->cons;
+
+ mutex_lock (&cons->lock);
+
+ switch (change)
+ {
+ case DIR_CHANGED_NULL:
+ {
+ DIR *dir = cons->dir;
+ struct dirent *dent;
+ do
+ {
+ errno = 0;
+ dent = readdir (dir);
+ if (!dent && errno)
+ err = errno;
+ else if (dent)
+ err = add_one (cons, dent->d_name);
+ }
+ while (dent && !err);
+ if (err)
+ assert ("Unexpected error"); /* XXX */
+ }
+ break;
+ case DIR_CHANGED_NEW:
+ {
+ err = add_one (cons, name);
+ if (err)
+ assert ("Unexpected error"); /* XXX */
+ }
+ break;
+ case DIR_CHANGED_UNLINK:
+ {
+ vcons_list_t vcons_entry;
+ err = lookup_one (cons, name, &vcons_entry);
+ if (!err)
+ {
+ cons_vcons_remove (cons, vcons_entry);
+ if (vcons_entry->prev)
+ vcons_entry->prev->next = vcons_entry->next;
+ else
+ cons->vcons_list = vcons_entry->next;
+ if (vcons_entry->next)
+ vcons_entry->next->prev = vcons_entry->prev;
+ else
+ cons->vcons_last = vcons_entry->prev;
+
+ free (vcons_entry);
+ }
+ }
+ break;
+ case DIR_CHANGED_RENUMBER:
+ default:
+ assert ("Unexpected dir-changed type.");
+ mutex_unlock (&cons->lock);
+ return EINVAL;
+ }
+ mutex_unlock (&cons->lock);
+ return 0;
+}
diff --git a/libihash/priv.h b/libcons/extra-version.c
index 5d235700..4ff54d85 100644
--- a/libihash/priv.h
+++ b/libcons/extra-version.c
@@ -1,6 +1,6 @@
-/* Private declaration for ihash library
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* Default value for cons_extra_version
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
This file is part of the GNU Hurd.
@@ -18,4 +18,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-int _ihash_nextprime (unsigned);
+
+#include "priv.h"
+
+char *cons_extra_version = "";
diff --git a/libcons/file-changed.c b/libcons/file-changed.c
new file mode 100644
index 00000000..b12a6f10
--- /dev/null
+++ b/libcons/file-changed.c
@@ -0,0 +1,366 @@
+/* file-changed.c - Handling file changed notifications.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+
+#include <mach.h>
+
+#include "cons.h"
+#include "fs_notify_S.h"
+
+kern_return_t
+cons_S_file_changed (cons_notify_t notify, natural_t tickno,
+ file_changed_type_t change,
+ off_t start, off_t end)
+{
+ error_t err = 0;
+ vcons_t vcons = (vcons_t) notify;
+
+ if (!notify || notify->cons)
+ return EOPNOTSUPP;
+
+ mutex_lock (&vcons->lock);
+ switch (change)
+ {
+ case FILE_CHANGED_NULL:
+ /* Always sent first for sync. */
+ cons_vcons_refresh (vcons);
+ break;
+ case FILE_CHANGED_WRITE:
+ /* File data has been written. */
+ while (vcons->state.changes.written < vcons->display->changes.written)
+ {
+ cons_change_t change;
+
+ if (vcons->display->changes.written - vcons->state.changes.written
+ > vcons->cons->slack)
+ {
+ cons_vcons_refresh (vcons);
+ continue;
+ }
+ change = vcons->state.changes.buffer[vcons->state.changes.written
+ % vcons->state.changes.length];
+ if (vcons->display->changes.written - vcons->state.changes.written
+ > vcons->state.changes.length - 1)
+ {
+ /* While we were reading the entry, the server might
+ have overwritten it. */
+ cons_vcons_refresh (vcons);
+ continue;
+ }
+ vcons->state.changes.written++;
+
+ if (change.what.not_matrix)
+ {
+ if (change.what.cursor_pos)
+ {
+ uint32_t old_row = vcons->state.cursor.row;
+ uint32_t height = vcons->state.screen.height;
+ uint32_t row;
+
+ vcons->state.cursor.col = vcons->display->cursor.col;
+ row = vcons->state.cursor.row = vcons->display->cursor.row;
+
+ if (row + vcons->scrolling < height)
+ {
+ cons_vcons_set_cursor_pos (vcons,
+ vcons->state.cursor.col,
+ row + vcons->scrolling);
+ if (old_row + vcons->scrolling >= height)
+ /* The cursor was invisible before. */
+ cons_vcons_set_cursor_status (vcons,
+ vcons->state.cursor.status);
+ }
+ else if (old_row + vcons->scrolling < height)
+ /* The cursor was visible before. */
+ cons_vcons_set_cursor_status (vcons, CONS_CURSOR_INVISIBLE);
+
+ _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
+ cons_vcons_update (vcons);
+ }
+ if (change.what.cursor_status)
+ {
+ vcons->state.cursor.status = vcons->display->cursor.status;
+ cons_vcons_set_cursor_status (vcons,
+ vcons->state.cursor.status);
+ cons_vcons_update (vcons);
+ }
+ if (change.what.screen_cur_line)
+ {
+ uint32_t new_cur_line;
+
+ new_cur_line = vcons->display->screen.cur_line;
+
+ if (new_cur_line != vcons->state.screen.cur_line)
+ {
+ off_t size = vcons->state.screen.width
+ * vcons->state.screen.lines;
+ off_t vis_start;
+ uint32_t scrolling;
+ off_t start;
+ off_t end;
+
+ if (new_cur_line > vcons->state.screen.cur_line)
+ scrolling = new_cur_line
+ - vcons->state.screen.cur_line;
+ else
+ scrolling = UINT32_MAX - vcons->state.screen.cur_line
+ + 1 + new_cur_line;
+
+ /* If we are scrolling back, defer scrolling
+ until absolutely necessary. */
+ if (vcons->scrolling)
+ {
+ if (_cons_jump_down_on_output)
+ _cons_vcons_scrollback
+ (vcons, CONS_SCROLL_ABSOLUTE_LINE, 0);
+ else
+ {
+ if (vcons->scrolling + scrolling
+ <= vcons->state.screen.scr_lines)
+ {
+ vcons->scrolling += scrolling;
+ scrolling = 0;
+ }
+ else
+ {
+ scrolling -= vcons->state.screen.scr_lines
+ - vcons->scrolling;
+ vcons->scrolling
+ = vcons->state.screen.scr_lines;
+ }
+ }
+ }
+
+ if (scrolling)
+ {
+ uint32_t cur_disp_line;
+
+ if (new_cur_line >= vcons->scrolling)
+ cur_disp_line = new_cur_line - vcons->scrolling;
+ else
+ cur_disp_line = (UINT32_MAX - (vcons->scrolling - new_cur_line)) + 1;
+
+ if (scrolling > vcons->state.screen.height)
+ scrolling = vcons->state.screen.height;
+ if (scrolling < vcons->state.screen.height)
+ cons_vcons_scroll (vcons, scrolling);
+ else
+ cons_vcons_clear (vcons, vcons->state.screen.width
+ * vcons->state.screen.height,
+ 0, 0);
+ vis_start = vcons->state.screen.width
+ * (cur_disp_line % vcons->state.screen.lines);
+ start = (((cur_disp_line % vcons->state.screen.lines)
+ + vcons->state.screen.height - scrolling)
+ * vcons->state.screen.width) % size;
+ end = start + scrolling * vcons->state.screen.width - 1;
+ cons_vcons_write (vcons,
+ vcons->state.screen.matrix + start,
+ end < size
+ ? end - start + 1
+ : size - start,
+ 0, vcons->state.screen.height
+ - scrolling);
+ if (end >= size)
+ cons_vcons_write (vcons,
+ vcons->state.screen.matrix,
+ end - size + 1,
+ 0, (size - vis_start)
+ / vcons->state.screen.width);
+ _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
+ cons_vcons_update (vcons);
+ }
+ vcons->state.screen.cur_line = new_cur_line;
+ }
+ }
+ if (change.what.screen_scr_lines)
+ {
+ vcons->state.screen.scr_lines
+ = vcons->display->screen.scr_lines;
+ if (vcons->state.screen.scr_lines < vcons->scrolling)
+ assert (!"Implement shrinking scrollback buffer! XXX");
+ }
+ if (change.what.bell_audible)
+ {
+ while (vcons->state.bell.audible
+ < vcons->display->bell.audible)
+ {
+ if (_cons_audible_bell == BELL_AUDIBLE)
+ cons_vcons_beep (vcons);
+ else if (_cons_audible_bell == BELL_VISUAL)
+ cons_vcons_flash (vcons);
+ vcons->state.bell.audible++;
+ }
+ }
+ if (change.what.bell_visible)
+ {
+ while (vcons->state.bell.visible
+ < vcons->display->bell.visible)
+ {
+ if (_cons_visual_bell == BELL_VISUAL)
+ cons_vcons_flash (vcons);
+ else if (_cons_visual_bell == BELL_AUDIBLE)
+ cons_vcons_beep (vcons);
+ vcons->state.bell.visible++;
+ }
+ }
+ if (change.what.flags)
+ {
+ uint32_t flags = vcons->display->flags;
+
+ if ((flags & CONS_FLAGS_SCROLL_LOCK)
+ != (vcons->state.flags & CONS_FLAGS_SCROLL_LOCK))
+ cons_vcons_set_scroll_lock (vcons, flags
+ & CONS_FLAGS_SCROLL_LOCK);
+ vcons->state.flags = flags;
+ }
+ }
+ else
+ {
+ /* For clipping. */
+ off_t size = vcons->state.screen.width*vcons->state.screen.lines;
+ off_t rotate;
+ off_t vis_end = vcons->state.screen.height
+ * vcons->state.screen.width - 1;
+ off_t end2 = -1;
+ off_t start_rel = 0; /* start relative to visible start. */
+ off_t start = change.matrix.start;
+ off_t end = change.matrix.end;
+
+ if (vcons->scrolling && _cons_jump_down_on_output)
+ _cons_vcons_scrollback (vcons, CONS_SCROLL_ABSOLUTE_LINE, 0);
+
+ if (vcons->state.screen.cur_line >= vcons->scrolling)
+ rotate = vcons->state.screen.cur_line - vcons->scrolling;
+ else
+ rotate = (UINT32_MAX - (vcons->scrolling - vcons->state.screen.cur_line)) + 1;
+ rotate = vcons->state.screen.width * (rotate % vcons->state.screen.lines);
+
+ /* Rotate the buffer. */
+ start -= rotate;
+ if (start < 0)
+ start += size;
+ end -= rotate;
+ if (end < 0)
+ end += size;
+
+ /* Find the intersection. */
+ if (start > vis_end)
+ {
+ if (end < start)
+ {
+ start = 0;
+ if (vis_end < end)
+ end = vis_end;
+ }
+ else
+ start = -1;
+ }
+ else
+ {
+ if (end >= start)
+ {
+ if (end > vis_end)
+ end = vis_end;
+ }
+ else
+ {
+ end2 = end;
+ end = vis_end;
+ }
+ }
+ /* We now have three cases: No intersection if start ==
+ -1, one intersection [start;end] if end2 == -1, and
+ two intersections [start;end] and [0;end2] if end2 !=
+ -1. However, we still have to undo the buffer
+ rotation. */
+ if (start != -1)
+ {
+ start_rel = start;
+ start += rotate;
+ if (start >= size)
+ start -= size;
+ end += rotate;
+ if (end >= size)
+ end -= size;
+ if (start > end)
+ end += size;
+ }
+ if (end2 != -1)
+ /* The interval should be [vis_start:end2]. */
+ end2 += rotate;
+
+ if (start != -1)
+ {
+ cons_vcons_clear (vcons, end - start + 1,
+ start_rel % vcons->state.screen.width,
+ start_rel / vcons->state.screen.width);
+ cons_vcons_write (vcons, vcons->state.screen.matrix + start,
+ end < size
+ ? end - start + 1
+ : size - start,
+ start_rel % vcons->state.screen.width,
+ start_rel / vcons->state.screen.width);
+ if (end >= size)
+ cons_vcons_write (vcons, vcons->state.screen.matrix,
+ end - size + 1,
+ (size - rotate)
+ % vcons->state.screen.width,
+ (size - rotate)
+ / vcons->state.screen.width);
+ if (end2 != -1)
+ {
+ cons_vcons_clear (vcons, end2 - rotate + 1, 0, 0);
+ cons_vcons_write (vcons,
+ vcons->state.screen.matrix + rotate,
+ end2 < size
+ ? end2 - rotate + 1
+ : size - rotate,
+ 0, 0);
+ if (end2 >= size)
+ cons_vcons_write (vcons, vcons->state.screen.matrix,
+ end2 - size + 1,
+ (size - rotate)
+ % vcons->state.screen.width,
+ (size - rotate)
+ / vcons->state.screen.width);
+ }
+ _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
+ cons_vcons_update (vcons);
+ }
+ }
+ }
+ break;
+ case FILE_CHANGED_EXTEND:
+ /* File has grown. */
+ case FILE_CHANGED_TRUNCATE:
+ /* File has been truncated. */
+ case FILE_CHANGED_META:
+ /* Stat information has changed, and none of the previous three
+ apply. Not sent for changes in node times. */
+ default:
+ err = EINVAL;
+ };
+
+ mutex_unlock (&vcons->lock);
+ return err;
+}
diff --git a/libcons/init-init.c b/libcons/init-init.c
new file mode 100644
index 00000000..eda292f5
--- /dev/null
+++ b/libcons/init-init.c
@@ -0,0 +1,97 @@
+/* init-init.c - Initialize the console library.
+ Copyright (C) 1995, 1996, 2002 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <malloc.h>
+
+#include <hurd.h>
+#include <hurd/ports.h>
+
+#include <mach.h>
+
+#include "cons.h"
+#include "priv.h"
+
+struct port_bucket *cons_port_bucket;
+struct port_class *cons_port_class;
+
+
+error_t
+cons_init (void)
+{
+ error_t err;
+ cons_t cons;
+ cons_notify_t dir_notify_port;
+ mach_port_t dir_notify;
+
+ cons_port_bucket = ports_create_bucket ();
+ if (!cons_port_bucket)
+ return errno;
+
+ cons_port_class = ports_create_class (cons_vcons_destroy, NULL);
+ if (!cons_port_class)
+ return errno;
+
+ /* Create the console structure. */
+ cons = malloc (sizeof (*cons));
+ if (!cons)
+ return errno;
+ mutex_init (&cons->lock);
+ cons->vcons_list = NULL;
+ cons->vcons_last = NULL;
+ cons->dir = opendir (cons_file);
+ cons->slack = _cons_slack;
+ if (!cons->dir)
+ {
+ free (cons);
+ return errno;
+ }
+ cons->dirport = getdport (dirfd (cons->dir));
+ if (cons->dirport == MACH_PORT_NULL)
+ {
+ closedir (cons->dir);
+ free (cons);
+ return errno;
+ }
+
+ /* Request directory notifications. */
+ err = ports_create_port (cons_port_class, cons_port_bucket,
+ sizeof (*dir_notify_port), &dir_notify_port);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), cons->dirport);
+ closedir (cons->dir);
+ free (cons);
+ return err;
+ }
+ dir_notify_port->cons = cons;
+
+ dir_notify = ports_get_right (dir_notify_port);
+ err = dir_notice_changes (cons->dirport, dir_notify,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), cons->dirport);
+ closedir (cons->dir);
+ free (cons);
+ return err;
+ }
+ return 0;
+}
diff --git a/libcons/init-loop.c b/libcons/init-loop.c
new file mode 100644
index 00000000..18576cb0
--- /dev/null
+++ b/libcons/init-loop.c
@@ -0,0 +1,32 @@
+/* init-loop.c - Server loop for console client library.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd/ports.h>
+
+#include "cons.h"
+
+void
+cons_server_loop (void)
+{
+ ports_manage_port_operations_one_thread (cons_port_bucket,
+ cons_demuxer, 0);
+ /* Not reached. */
+}
+
diff --git a/libmom/memory-init.c b/libcons/mutations.h
index 38972018..af5ab2d0 100644
--- a/libmom/memory-init.c
+++ b/libcons/mutations.h
@@ -1,6 +1,6 @@
-/* Initialization and static data for mom memory management.
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* mutations.h - MIG mutations for the console client library.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
This file is part of the GNU Hurd.
@@ -18,15 +18,10 @@
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"
+/* Only CPP macro definitions should go in this file. */
-struct mutex _mom_memory_lock = MUTEX_INITIALIZER;
-size_t mom_page_size;
+#define FS_NOTIFY_INTRAN cons_notify_t begin_using_notify_port (fs_notify_t)
+#define FS_NOTIFY_DESTRUCTOR end_using_notify_port (cons_notify_t)
-static void init_memory (void) __attribute__ ((constructor));
+#define FS_NOTIFY_IMPORTS import "priv.h";
-static void
-init_memory (void)
-{
- mom_page_size = vm_page_size;
-}
diff --git a/libcons/opts-std-startup.c b/libcons/opts-std-startup.c
new file mode 100644
index 00000000..23bd9971
--- /dev/null
+++ b/libcons/opts-std-startup.c
@@ -0,0 +1,229 @@
+/* opts-std-startup.c - Standard startup-time command line parser.
+ Copyright (C) 1995,96,97,98,99,2001,02,2003,2004,2005 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org> and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <argp.h>
+#include <string.h>
+
+#include "priv.h"
+
+
+/* Option keys for long-only options in argp_option. */
+#define OPT_SLACK 600 /* --slack */
+#define OPT_JUMP_DOWN_ON_INPUT 601 /* --jump-down-on-input */
+#define OPT_NO_JUMP_DOWN_ON_INPUT 602 /* --no-jump-down-on-input */
+#define OPT_JUMP_DOWN_ON_OUTPUT 603 /* --jump-down-on-output */
+#define OPT_NO_JUMP_DOWN_ON_OUTPUT 604 /* --no-jump-down-on-output */
+#define OPT_VISUAL_BELL 605 /* --visual-bell */
+#define OPT_AUDIBLE_BELL 606 /* --audible-bell */
+#define OPT_MOUSE_SHOW 607 /* --mouse-show-on */
+#define OPT_MOUSE_HIDE 608 /* --mouse-hide-on */
+#define OPT_MOUSE_SENS 609 /* --mouse-sensitivity */
+
+/* The number of records the client is allowed to lag behind the server. */
+#define DEFAULT_SLACK 100
+#define DEFAULT_SLACK_STRING STRINGIFY(DEFAULT_SLACK)
+#define STRINGIFY(x) STRINGIFY_1(x)
+#define STRINGIFY_1(x) #x
+
+/* The mouse sensitivity. */
+#define DEFAULT_MOUSE_SENS 3.0
+#define DEFAULT_MOUSE_SENS_STRING STRINGIFY(DEFAULT_MOUSE_SENS)
+
+/* Number of records the client is allowed to lag behind the
+ server. */
+int _cons_slack = DEFAULT_SLACK;
+
+/* If we jump down on input. */
+int _cons_jump_down_on_input = 1;
+
+/* If we jump down on output. */
+int _cons_jump_down_on_output;
+
+/* The filename of the console server. */
+char *cons_file;
+
+/* The type of bell used for the visual bell. */
+bell_type_t _cons_visual_bell = BELL_VISUAL;
+
+/* The type of bell used for the audible bell. */
+bell_type_t _cons_audible_bell = BELL_AUDIBLE;
+
+/* The type of events that will make the mouse cursor visible. */
+int _cons_show_mouse = CONS_EVT_MOUSE_MOVE;
+
+/* The type of events that will hide the mouse cursor. */
+int _cons_hide_mouse = CONS_EVT_KEYPRESS;
+
+/* The mouse sensitivity. */
+float _cons_mouse_sens = DEFAULT_MOUSE_SENS;
+
+static const struct argp_option
+startup_options[] =
+{
+ { "slack", OPT_SLACK, "RECORDS", 0, "Max number of records the client is"
+ " allowed to lag behind the server (default " DEFAULT_SLACK_STRING ")" },
+ { "jump-down-on-input", OPT_JUMP_DOWN_ON_INPUT, NULL, 0,
+ "End scrollback when something is entered (default)" },
+ { "no-jump-down-on-input", OPT_NO_JUMP_DOWN_ON_INPUT, NULL, 0,
+ "End scrollback when something is entered" },
+ { "jump-down-on-output", OPT_JUMP_DOWN_ON_OUTPUT, NULL, 0,
+ "End scrollback when something is printed" },
+ { "no-jump-down-on-output", OPT_NO_JUMP_DOWN_ON_OUTPUT, NULL, 0,
+ "End scrollback when something is printed (default)" },
+ { "visual-bell", OPT_VISUAL_BELL, "BELL", 0, "Visual bell: on (default), "
+ "off, visual, audible" },
+ { "audible-bell", OPT_AUDIBLE_BELL, "BELL", 0, "Audible bell: on (default), "
+ "off, visual, audible" },
+ { "mouse-show-on", OPT_MOUSE_SHOW, "EVENTS", 0, "One or more of the events"
+ " mousemove, mousebutton, keypress, output (default is mousemove), if one"
+ " of these events occur the mouse cursor will be made visible" },
+ { "mouse-hide-on", OPT_MOUSE_HIDE, "EVENTS", 0, "One or more of the events"
+ " mousemove, mousebutton, keypress, output (default is keypress), if one"
+ " of these events occur the mouse cursor will be hidden " },
+ { "mouse-sensitivity", OPT_MOUSE_SENS, "SENSITIVITY", 0, "The mouse"
+ " sensitivity (default " DEFAULT_MOUSE_SENS_STRING "). A lower value"
+ " means more sensitive" },
+ { 0, 0 }
+};
+
+static const char args_doc[] = "CONSOLE";
+static const char doc[] = "A console client.";
+
+
+static error_t
+parse_startup_opt (int opt, char *arg, struct argp_state *state)
+{
+ int parse_events (char *events)
+ {
+ char *evtstr = strdupa (events);
+ char *tok = strtok (evtstr, ",");
+ int evmask = 0;
+
+ while (tok)
+ {
+ if (!strcasecmp ("mousemove", tok))
+ evmask |= CONS_EVT_MOUSE_MOVE;
+ else if (!strcasecmp ("mousebutton", tok))
+ evmask |= CONS_EVT_MOUSE_BUTTON;
+ else if (!strcasecmp ("keypress", tok))
+ evmask |= CONS_EVT_KEYPRESS;
+ else if (!strcasecmp ("output", tok))
+ evmask |= CONS_EVT_OUTPUT;
+ else
+ argp_error (state, "The event can be one of: MOUSEMOVE,"
+ " MOUSEBUTTON, KEYPRESS or OUTPUT");
+ tok = strtok (NULL, ",");
+ }
+ return evmask;
+ }
+
+ switch (opt)
+ {
+ case OPT_SLACK:
+ _cons_slack = atoi (arg);
+ break;
+
+ case OPT_JUMP_DOWN_ON_INPUT:
+ _cons_jump_down_on_input = 1;
+ break;
+
+ case OPT_NO_JUMP_DOWN_ON_INPUT:
+ _cons_jump_down_on_input = 0;
+ break;
+
+ case OPT_JUMP_DOWN_ON_OUTPUT:
+ _cons_jump_down_on_output = 1;
+ break;
+
+ case OPT_NO_JUMP_DOWN_ON_OUTPUT:
+ _cons_jump_down_on_output = 0;
+ break;
+
+ case OPT_AUDIBLE_BELL:
+ if (!strcasecmp ("on", arg) || !strcasecmp ("audible", arg))
+ _cons_audible_bell = BELL_AUDIBLE;
+ else if (!strcasecmp ("off", arg))
+ _cons_audible_bell = BELL_OFF;
+ else if (!strcasecmp ("visual", arg))
+ _cons_audible_bell = BELL_VISUAL;
+ else
+ argp_error (state, "The audible bell can be one of: on, off, visual, "
+ "audible");
+ break;
+
+ case OPT_VISUAL_BELL:
+ if (!strcasecmp ("on", arg) || !strcasecmp ("visual", arg))
+ _cons_visual_bell = BELL_VISUAL;
+ else if (!strcasecmp ("off", arg))
+ _cons_visual_bell = BELL_OFF;
+ else if (!strcasecmp ("audible", arg))
+ _cons_visual_bell = BELL_AUDIBLE;
+ else
+ argp_error (state, "The visual bell can be one of: on, off, visual, "
+ "audible");
+ break;
+
+ case OPT_MOUSE_SHOW:
+ _cons_show_mouse = parse_events (arg);
+ break;
+
+ case OPT_MOUSE_HIDE:
+ _cons_hide_mouse = parse_events (arg);
+ break;
+
+ case OPT_MOUSE_SENS:
+ {
+ char *tail;
+
+ errno = 0;
+ _cons_mouse_sens = strtod (arg, &tail);
+ if (tail == NULL || tail == arg || *tail != '\0')
+ argp_error (state, "SENSITIVITY is not a number: %s", arg);
+ if (errno)
+ argp_error (state, "Overflow in argument SENSITIVITY %s", arg);
+ break;
+ }
+
+ case ARGP_KEY_ARG:
+ if (state->arg_num > 0)
+ /* Too many arguments. */
+ argp_error (state, "Too many non option arguments");
+ cons_file = arg;
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_error (state, "Filename of console server missing");
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/* An argp structure for the standard console client command line
+ arguments. */
+const struct argp
+cons_startup_argp =
+{
+ startup_options, parse_startup_opt, args_doc, doc
+};
diff --git a/libcons/opts-version.c b/libcons/opts-version.c
new file mode 100644
index 00000000..f8751490
--- /dev/null
+++ b/libcons/opts-version.c
@@ -0,0 +1,44 @@
+/* opts-version.c - Default hook for argp --version handling
+ Copyright (C) 1996, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu> and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <argp.h>
+#include <version.h>
+
+#include "priv.h"
+
+static void
+_print_version (FILE *stream, struct argp_state *state)
+{
+ if (argp_program_version)
+ /* If this is non-zero, then the program's probably defined it, so let
+ that take precedence over the default. */
+ fputs (argp_program_version, stream);
+ else if (cons_extra_version && *cons_extra_version)
+ fprintf (stream, "%s (%s) %s\n",
+ cons_client_name, cons_extra_version, cons_client_version);
+ else
+ fprintf (stream, "%s %s\n", cons_client_name, cons_client_version);
+
+ fputs (STANDARD_HURD_VERSION (libcons) "\n", stream);
+}
+
+void (*argp_program_version_hook) (FILE *stream, struct argp_state *state)
+ = _print_version;
diff --git a/libcons/priv.h b/libcons/priv.h
new file mode 100644
index 00000000..38971ff8
--- /dev/null
+++ b/libcons/priv.h
@@ -0,0 +1,93 @@
+/* Private declarations for cons library
+ Copyright (C) 2002, 2003, 2005 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. */
+
+#ifndef _CONS_PRIV_H
+#define _CONS_PRIV_H
+
+#include "cons.h"
+
+
+/* The kind of bells available. */
+typedef enum
+ {
+ BELL_OFF,
+ BELL_VISUAL,
+ BELL_AUDIBLE
+ } bell_type_t;
+
+#define CONS_EVT_MOUSE_MOVE (1 << 1)
+#define CONS_EVT_MOUSE_BUTTON (1 << 2)
+#define CONS_EVT_KEYPRESS (1 << 4)
+#define CONS_EVT_OUTPUT (1 << 8)
+
+
+/* Number of records the client is allowed to lag behind the
+ server. */
+extern int _cons_slack;
+
+/* If we jump down at input. */
+extern int _cons_jump_down_on_input;
+
+/* If we jump down at output. */
+extern int _cons_jump_down_on_output;
+
+/* The type of bell used for the visual bell. */
+extern bell_type_t _cons_visual_bell;
+
+/* The type of bell used for the audible bell. */
+extern bell_type_t _cons_audible_bell;
+
+/* The type of events that will make the mouse cursor visible. */
+extern int _cons_show_mouse;
+
+/* The type of events that will hide the mouse cursor. */
+extern int _cons_hide_mouse;
+
+/* The mouse sensitivity. */
+extern float _cons_mouse_sens;
+
+
+/* Non-locking version of cons_vcons_scrollback. Does also not update
+ the display. */
+int _cons_vcons_scrollback (vcons_t vcons, cons_scroll_t type, float value);
+
+/* Non-locking version of cons_vcons_input. */
+error_t _cons_vcons_input (vcons_t vcons, char *buf, size_t size);
+
+/* Generate the console event EVENT for console VCONS. */
+void _cons_vcons_console_event (vcons_t vcons, int event);
+
+
+/* Called by MiG to translate ports into cons_notify_t. mutations.h
+ arranges for this to happen for the fs_notify interfaces. */
+static inline cons_notify_t
+begin_using_notify_port (fs_notify_t port)
+{
+ return ports_lookup_port (cons_port_bucket, port, cons_port_class);
+}
+
+/* Called by MiG after server routines have been run; this balances
+ begin_using_notify_port, and is arranged for the fs_notify
+ interfaces by mutations.h. */
+static inline void
+end_using_notify_port (cons_notify_t cred)
+{
+ if (cred)
+ ports_port_deref (cred);
+}
+
+#endif /* _CONS_PRIV_H */
diff --git a/libmom/mach-port-set.c b/libcons/vcons-add.c
index ed6842fd..1a6eb204 100644
--- a/libmom/mach-port-set.c
+++ b/libcons/vcons-add.c
@@ -1,6 +1,6 @@
-/* Initialize a mom port reference from a Mach port
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* vcons-add.c - Add a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
This file is part of the GNU Hurd.
@@ -18,13 +18,13 @@
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 <errno.h>
-error_t
-mom_mach_port_set (struct mom_port_ref *obj,
- mach_port_t port)
+#include "cons.h"
+
+/* The virtual console entry VCONS_ENTRY was just added. CONS is
+ locked. */
+void
+cons_vcons_add (cons_t cons, vcons_list_t vcons_entry)
{
- obj->port = port;
- return 0;
}
-
diff --git a/pfinet/devices.c b/libcons/vcons-close.c
index ac37cc03..33a38982 100644
--- a/pfinet/devices.c
+++ b/libcons/vcons-close.c
@@ -1,6 +1,6 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* vcons-close.c - Close a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
This file is part of the GNU Hurd.
@@ -18,36 +18,28 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <linux/netdevice.h>
-#include <device/device.h>
-#include <hurd.h>
-
-struct device *dev_base;
-struct device loopback_dev;
+#include <assert.h>
-device_t master_device;
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <cthreads.h>
-void
-init_devices (void)
-{
- error_t err;
-
- err = get_privileged_ports (0, &master_device);
- if (err)
- {
- perror ("Cannot fetch master device port");
- exit (1);
- }
-
- dev_base = 0;
-}
+#include "cons.h"
+/* Close the virtual console VCONS. */
void
-add_device (struct device *dev)
+cons_vcons_close (vcons_t vcons)
{
- dev->next = dev_base;
- dev_base = dev;
+ cons_t cons = vcons->cons;
+ vcons_list_t vcons_entry = vcons->vcons_entry;
+
+ mutex_lock (&cons->lock);
+ /* The same virtual console should never be opened twice. */
+ assert (vcons_entry->vcons == vcons);
+ vcons_entry->vcons = NULL;
+ mutex_unlock (&cons->lock);
+
+ /* Destroy the port. */
+ ports_port_deref (vcons);
+ ports_destroy_right (vcons);
}
-
-
-
diff --git a/libcons/vcons-destroy.c b/libcons/vcons-destroy.c
new file mode 100644
index 00000000..ca1c5c37
--- /dev/null
+++ b/libcons/vcons-destroy.c
@@ -0,0 +1,52 @@
+/* vcons-destroy.c - Clean up the resources for a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+
+#include <hurd.h>
+#include <mach.h>
+
+#include "cons.h"
+
+/* Destroy the virtual console VCONS. */
+void
+cons_vcons_destroy (void *port)
+{
+ cons_notify_t notify = (cons_notify_t) port;
+ vcons_t vcons = (vcons_t) port;
+
+ if (notify->cons)
+ return;
+
+ if (vcons->input >= 0)
+ {
+ close (vcons->input);
+ vcons->input = -1;
+ }
+ if (vcons->display != MAP_FAILED)
+ {
+ munmap (vcons->display, vcons->display_size);
+ vcons->display = MAP_FAILED;
+ }
+}
diff --git a/libmom/fetch-mach-port.c b/libcons/vcons-event.c
index 85262600..d8c31dc0 100644
--- a/libmom/fetch-mach-port.c
+++ b/libcons/vcons-event.c
@@ -1,6 +1,6 @@
-/* Return the Mach port corresponding to a mom port reference
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* vcons-event.c - Handle console events.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Written by Marco Gerards.
This file is part of the GNU Hurd.
@@ -18,10 +18,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+#include "cons.h"
#include "priv.h"
-mach_port_t
-mom_fetch_mach_port (struct mom_port_ref *obj)
+void
+_cons_vcons_console_event (vcons_t vcons, int event)
{
- return obj->port;
+ if (_cons_show_mouse & event)
+ cons_vcons_set_mousecursor_status (vcons, 1);
+ else if (_cons_hide_mouse & event)
+ cons_vcons_set_mousecursor_status (vcons, 0);
}
diff --git a/libcons/vcons-input.c b/libcons/vcons-input.c
new file mode 100644
index 00000000..e008b9c9
--- /dev/null
+++ b/libcons/vcons-input.c
@@ -0,0 +1,64 @@
+/* vcons-input.c - Add input to a virtual console.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "cons.h"
+#include "priv.h"
+
+/* Non-locking version of cons_vcons_input. */
+error_t
+_cons_vcons_input (vcons_t vcons, char *buf, size_t size)
+{
+ int ret;
+
+ do
+ {
+ ret = write (vcons->input, buf, size);
+ if (ret > 0)
+ {
+ size -= ret;
+ buf += ret;
+ }
+ }
+ while (size && (ret != -1 || errno == EINTR));
+
+ return 0;
+}
+
+
+/* Enter SIZE bytes from the buffer BUF into the virtual console
+ VCONS. */
+error_t
+cons_vcons_input (vcons_t vcons, char *buf, size_t size)
+{
+ mutex_lock (&vcons->lock);
+
+ _cons_vcons_console_event (vcons, CONS_EVT_KEYPRESS);
+
+ if (vcons->scrolling && _cons_jump_down_on_input)
+ _cons_vcons_scrollback (vcons, CONS_SCROLL_ABSOLUTE_LINE, 0);
+
+ _cons_vcons_input (vcons, buf, size);
+
+ mutex_unlock (&vcons->lock);
+ return 0;
+}
diff --git a/libcons/vcons-move-mouse.c b/libcons/vcons-move-mouse.c
new file mode 100644
index 00000000..1e5f7b9f
--- /dev/null
+++ b/libcons/vcons-move-mouse.c
@@ -0,0 +1,103 @@
+/* vcons-move-mouse.c - Catch mouse events.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Written by Marco Gerards.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "cons.h"
+#include "priv.h"
+
+static float mousepos_x;
+static float mousepos_y;
+
+error_t
+cons_vcons_move_mouse (vcons_t vcons, mouse_event_t ev)
+{
+ char event[CONS_MOUSE_EVENT_LENGTH];
+ uint32_t report_events;
+
+ mutex_lock (&vcons->lock);
+ report_events = vcons->display->flags & CONS_FLAGS_TRACK_MOUSE;
+
+ switch (ev->mouse_movement)
+ {
+ case CONS_VCONS_MOUSE_MOVE_REL:
+ mousepos_x += ((float) ev->x / _cons_mouse_sens);
+ mousepos_y += ((float) ev->y / _cons_mouse_sens);
+ break;
+
+ case CONS_VCONS_MOUSE_MOVE_ABS_PERCENT:
+ mousepos_x = vcons->state.screen.width * ev->x / 100;
+ mousepos_y = vcons->state.screen.height * ev->y / 100;
+
+ case CONS_VCONS_MOUSE_MOVE_ABS:
+ mousepos_x = ev->x;
+ mousepos_y = ev->y;
+ break;
+ }
+
+ /* Keep the mouse cursor in range of the VC. */
+ if (mousepos_x < 0)
+ mousepos_x = 0;
+ if (mousepos_y < 0)
+ mousepos_y = 0;
+ if (mousepos_x >= (float) vcons->state.screen.width)
+ mousepos_x = vcons->state.screen.width - 1;
+ if (mousepos_y >= (float) vcons->state.screen.height)
+ mousepos_y = vcons->state.screen.height - 1;
+
+ cons_vcons_set_mousecursor_pos (vcons, (float) mousepos_x, (float) mousepos_y);
+
+ /* Report a mouse movement event. */
+ if (ev->x || ev->y)
+ _cons_vcons_console_event (vcons, CONS_EVT_MOUSE_MOVE);
+
+ /* Report a mouse button event. */
+ if (ev->mouse_button != CONS_VCONS_MOUSE_BUTTON_NO_OP)
+ _cons_vcons_console_event (vcons, CONS_EVT_MOUSE_BUTTON);
+
+ if (report_events)
+ {
+ switch (ev->mouse_button)
+ {
+ case CONS_VCONS_MOUSE_BUTTON_NO_OP:
+ break;
+
+ case CONS_VCONS_MOUSE_BUTTON_PRESSED:
+ /* Make an xterm like event string. */
+ CONS_MOUSE_EVENT (event, ev->button, (int) mousepos_x + 1, (int) mousepos_y + 1);
+
+ _cons_vcons_input (vcons, event, CONS_MOUSE_EVENT_LENGTH);
+ /* And send it to the server. */
+ break;
+
+ case CONS_VCONS_MOUSE_BUTTON_RELEASED:
+ /* Make an xterm like event string. */
+ CONS_MOUSE_EVENT (event, CONS_MOUSE_RELEASE, (int) mousepos_x + 1, (int) mousepos_y + 1);
+
+ /* And send it to the server. */
+ _cons_vcons_input (vcons, event, CONS_MOUSE_EVENT_LENGTH);
+ break;
+ }
+ }
+
+ mutex_unlock (&vcons->lock);
+ return 0;
+}
diff --git a/libcons/vcons-open.c b/libcons/vcons-open.c
new file mode 100644
index 00000000..8c34fc5e
--- /dev/null
+++ b/libcons/vcons-open.c
@@ -0,0 +1,175 @@
+/* vcons-open.c - Open a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+
+#include <hurd.h>
+#include <mach.h>
+
+#include "cons.h"
+
+/* Open the virtual console for VCONS_ENTRY. CONS is locked.
+ Afterwards, R_VCONS will be locked. */
+error_t
+cons_vcons_open (cons_t cons, vcons_list_t vcons_entry, vcons_t *r_vcons)
+{
+ error_t err = 0;
+ char *name;
+ file_t vconsp = MACH_PORT_NULL;
+ file_t file = MACH_PORT_NULL;
+ int fd = -1;
+ struct stat statbuf;
+ mach_port_t notify = MACH_PORT_NULL;
+ vcons_t vcons;
+
+ if (asprintf (&name, "%u", vcons_entry->id) < 0)
+ return err;
+
+ /* Set up the port we receive notification messages on. */
+ err = ports_create_port (cons_port_class, cons_port_bucket,
+ sizeof (*vcons), &vcons);
+ if (err)
+ goto err;
+ vcons->notify.cons = NULL;
+ vcons->cons = cons;
+ vcons->vcons_entry = vcons_entry;
+ vcons->id = vcons_entry->id;
+ mutex_init (&vcons->lock);
+ vcons->input = -1;
+ vcons->display = MAP_FAILED;
+ vcons->scrolling = 0;
+
+ /* Open the directory port of the virtual console. */
+ vconsp = file_name_lookup_under (cons->dirport, name,
+ O_DIRECTORY | O_RDONLY, 0);
+ if (vconsp == MACH_PORT_NULL)
+ {
+ err = errno;
+ goto err;
+ }
+
+ /* Within that directory, open the input node. */
+ file = file_name_lookup_under (vconsp, "input", O_WRONLY /* | O_NONBLOCK */, 0);
+ if (file == MACH_PORT_NULL)
+ err = errno;
+ else
+ {
+ vcons->input = openport (file, O_WRONLY /* | O_NONBLOCK */);
+ if (vcons->input < 0)
+ err = errno;
+ else
+ /* openport() consumed the reference. */
+ file = MACH_PORT_NULL;
+ }
+ if (err)
+ goto err;
+
+ /* Within that directory, also open the display node. */
+ file = file_name_lookup_under (vconsp, "display", O_RDONLY, 0);
+ if (file == MACH_PORT_NULL)
+ err = errno;
+ else
+ {
+ /* Acquire an additional reference for openport(). */
+ err = mach_port_mod_refs (mach_task_self (), file,
+ MACH_PORT_RIGHT_SEND, +1);
+ if (err)
+ goto err;
+ fd = openport (file, O_RDONLY);
+ if (fd < 0)
+ err = errno;
+ }
+ if (err)
+ goto err;
+
+ /* Map the whole file. */
+ if (fstat (fd, &statbuf) < 0)
+ {
+ err = errno;
+ goto err;
+ }
+ vcons->display_size = statbuf.st_size;
+ vcons->display = mmap (0, vcons->display_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (vcons->display == MAP_FAILED)
+ {
+ err = errno;
+ goto err;
+ }
+
+ if (vcons->display->magic != CONS_MAGIC
+ || vcons->display->version >> CONS_VERSION_MAJ_SHIFT != 0)
+ {
+ err = EINVAL;
+ goto err;
+ }
+ vcons->state.screen.width = vcons->display->screen.width;
+ vcons->state.screen.height = vcons->display->screen.height;
+ vcons->state.screen.lines = vcons->display->screen.lines;
+ vcons->state.screen.matrix = (conchar_t *)
+ (((uint32_t *) vcons->display) + vcons->display->screen.matrix);
+ vcons->state.changes.length = vcons->display->changes.length;
+ vcons->state.changes.buffer = (cons_change_t *)
+ (((uint32_t *) vcons->display) + vcons->display->changes.buffer);
+
+ /* Request notification messages. */
+ notify = ports_get_right (vcons);
+ mach_port_set_qlimit (mach_task_self (), notify, 1);
+
+ /* When this succeeds, we will immediately receive notification
+ messages for this virtual console. */
+ mutex_lock (&vcons->lock);
+ err = file_notice_changes (file, notify, MACH_MSG_TYPE_MAKE_SEND);
+ if (!err)
+ {
+ *r_vcons = vcons;
+ goto out;
+ }
+
+ err:
+ if (vcons->input >= 0)
+ {
+ close (vcons->input);
+ vcons->input = -1;
+ }
+ if (vcons->display != MAP_FAILED)
+ {
+ munmap (vcons->display, vcons->display_size);
+ vcons->display = MAP_FAILED;
+ }
+ if (notify)
+ {
+ mach_port_deallocate (mach_task_self (), notify);
+ ports_port_deref (vcons);
+ }
+ ports_destroy_right (vcons);
+ out:
+ if (fd > 0)
+ close (fd);
+ if (file != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), file);
+ if (vconsp != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), vconsp);
+ free (name);
+ return err;
+}
diff --git a/libcons/vcons-refresh.c b/libcons/vcons-refresh.c
new file mode 100644
index 00000000..ce6807fe
--- /dev/null
+++ b/libcons/vcons-refresh.c
@@ -0,0 +1,76 @@
+/* vcons-refresh.c - Redraw a virtual console.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+
+#include "cons.h"
+#include "priv.h"
+
+/* Redraw the virtual console VCONS, which is locked. */
+void
+cons_vcons_refresh (vcons_t vcons)
+{
+ uint32_t start;
+ vcons->state.screen.cur_line = vcons->display->screen.cur_line;
+ vcons->state.screen.scr_lines = vcons->display->screen.scr_lines;
+ vcons->state.cursor.col = vcons->display->cursor.col;
+ vcons->state.cursor.row = vcons->display->cursor.row;
+ vcons->state.cursor.status = vcons->display->cursor.status;
+ vcons->state.bell.audible = vcons->display->bell.audible;
+ vcons->state.bell.visible = vcons->display->bell.visible;
+ vcons->state.flags = vcons->display->flags;
+ vcons->state.changes.written = vcons->display->changes.written;
+
+ if (vcons->state.screen.scr_lines < vcons->scrolling)
+ vcons->scrolling = vcons->scrolling;
+
+ cons_vcons_set_dimension (vcons, vcons->state.screen.width,
+ vcons->state.screen.height);
+
+ if (vcons->state.screen.cur_line >= vcons->scrolling)
+ start = vcons->state.screen.cur_line - vcons->scrolling;
+ else
+ start = (UINT32_MAX
+ - (vcons->scrolling - vcons->state.screen.cur_line)) + 1;
+ start %= vcons->state.screen.lines;
+
+ cons_vcons_write (vcons, vcons->state.screen.matrix
+ + start * vcons->state.screen.width,
+ ((vcons->state.screen.lines - start
+ < vcons->state.screen.height)
+ ? vcons->state.screen.lines - start
+ : vcons->state.screen.height)
+ * vcons->state.screen.width, 0, 0);
+ if (vcons->state.screen.lines - start < vcons->state.screen.height)
+ cons_vcons_write (vcons, vcons->state.screen.matrix,
+ vcons->state.screen.height * vcons->state.screen.width
+ - (vcons->state.screen.lines - start)
+ * vcons->state.screen.width, 0,
+ vcons->state.screen.lines - start);
+
+ cons_vcons_set_cursor_pos (vcons, vcons->state.cursor.col,
+ vcons->state.cursor.row);
+ cons_vcons_set_cursor_status (vcons, vcons->state.cursor.status);
+ cons_vcons_set_scroll_lock (vcons, vcons->state.flags
+ & CONS_FLAGS_SCROLL_LOCK);
+ _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
+ cons_vcons_update (vcons);
+}
diff --git a/libcons/vcons-remove.c b/libcons/vcons-remove.c
new file mode 100644
index 00000000..34b31d6f
--- /dev/null
+++ b/libcons/vcons-remove.c
@@ -0,0 +1,31 @@
+/* vcons-remove.c - Remove a virtual console.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+
+#include "cons.h"
+
+/* The virtual console VCONS_ENTRY is going to be removed.
+ VCONS_ENTRY->cons is locked. */
+void
+cons_vcons_remove (cons_t cons, vcons_list_t vcons_entry)
+{
+ assert (!vcons_entry->vcons);
+}
diff --git a/libcons/vcons-scrollback.c b/libcons/vcons-scrollback.c
new file mode 100644
index 00000000..77c8c211
--- /dev/null
+++ b/libcons/vcons-scrollback.c
@@ -0,0 +1,164 @@
+/* vcons-scrollback.c - Move forward and backward in the scrollback buffer.
+ Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdint.h>
+
+#include <cthreads.h>
+
+#include "cons.h"
+#include "priv.h"
+
+/* Non-locking version of cons_vcons_scrollback. Does also not update
+ the display. */
+int
+_cons_vcons_scrollback (vcons_t vcons, cons_scroll_t type, float value)
+{
+ int scrolling;
+ uint32_t new_scr;
+
+ switch (type)
+ {
+ case CONS_SCROLL_DELTA_LINES:
+ scrolling = vcons->scrolling + ((uint32_t) value);
+ break;
+ case CONS_SCROLL_DELTA_SCREENS:
+ scrolling = vcons->scrolling
+ + ((uint32_t) (value * vcons->state.screen.height));
+ break;
+ case CONS_SCROLL_ABSOLUTE_LINE:
+ scrolling = (uint32_t) value;
+ break;
+ case CONS_SCROLL_ABSOLUTE_PERCENTAGE:
+ scrolling = (uint32_t) (value * vcons->state.screen.scr_lines);
+ break;
+ default:
+ return 0;
+ }
+
+ if (scrolling < 0)
+ new_scr = 0;
+ else if (scrolling > vcons->state.screen.scr_lines)
+ new_scr = vcons->state.screen.scr_lines;
+ else
+ new_scr = scrolling;
+
+ if (new_scr == vcons->scrolling)
+ return 0;
+
+ scrolling = vcons->scrolling - new_scr;
+ {
+ uint32_t new_cur_line;
+ off_t size = vcons->state.screen.width
+ * vcons->state.screen.lines;
+ off_t vis_start;
+ off_t start;
+ off_t end;
+
+ if (vcons->state.screen.cur_line >= new_scr)
+ new_cur_line = vcons->state.screen.cur_line - new_scr;
+ else
+ new_cur_line = (UINT32_MAX - (new_scr - vcons->state.screen.cur_line)) + 1;
+
+ if (scrolling > 0 && (uint32_t) scrolling > vcons->state.screen.height)
+ scrolling = vcons->state.screen.height;
+ else if (scrolling < 0
+ && (uint32_t) (-scrolling) > vcons->state.screen.height)
+ scrolling = -vcons->state.screen.height;
+ if ((scrolling > 0 && scrolling < vcons->state.screen.height)
+ || (scrolling < 0
+ && (uint32_t) (-scrolling) < vcons->state.screen.height))
+ cons_vcons_scroll (vcons, scrolling);
+ else if ((scrolling > 0 && scrolling == vcons->state.screen.height)
+ || (scrolling < 0
+ && (uint32_t) (-scrolling) == vcons->state.screen.height))
+ cons_vcons_clear (vcons, vcons->state.screen.width
+ * vcons->state.screen.height, 0, 0);
+
+ vis_start = vcons->state.screen.width
+ * (new_cur_line % vcons->state.screen.lines);
+ if (scrolling > 0)
+ start = (((new_cur_line % vcons->state.screen.lines)
+ + vcons->state.screen.height - scrolling)
+ * vcons->state.screen.width) % size;
+ else
+ start = vis_start;
+ end = start + abs (scrolling) * vcons->state.screen.width - 1;
+
+ cons_vcons_write (vcons,
+ vcons->state.screen.matrix + start,
+ end < size
+ ? end - start + 1
+ : size - start,
+ 0, (scrolling > 0)
+ ? vcons->state.screen.height - scrolling : 0);
+ if (end >= size)
+ cons_vcons_write (vcons,
+ vcons->state.screen.matrix,
+ end - size + 1,
+ 0, (size - vis_start)
+ / vcons->state.screen.width);
+ }
+
+ /* Set the new cursor position. */
+ {
+ uint32_t row = vcons->state.cursor.row;
+ uint32_t height = vcons->state.screen.height;
+
+ if (row + new_scr < height)
+ {
+ cons_vcons_set_cursor_pos (vcons, vcons->state.cursor.col,
+ row + new_scr);
+ if (row + vcons->scrolling >= height)
+ /* The cursor was invisible before. */
+ cons_vcons_set_cursor_status (vcons, vcons->state.cursor.status);
+ }
+ else if (row + vcons->scrolling < height)
+ /* The cursor was visible before. */
+ cons_vcons_set_cursor_status (vcons, CONS_CURSOR_INVISIBLE);
+ }
+
+ vcons->scrolling -= scrolling;
+
+ return -scrolling;
+}
+
+/* Scroll back into the history of VCONS. If TYPE is
+ CONS_SCROLL_DELTA_LINES, scroll up or down by VALUE lines. If TYPE
+ is CONS_SCROLL_DELTA_SCREENS, scroll up or down by VALUE multiples
+ of a screen height. If TYPE is CONS_SCROLL_ABSOLUTE_LINE, scroll to
+ line VALUE (where 0 is the lowest line). If TYPE is
+ CONS_SCROLL_ABSOLUTE_PERCENTAGE, scroll to the position determined
+ by VALUE, where 0 is the bottom and 1 is the top.
+
+ The function returns the number of lines actually scrolled up or
+ down. */
+int
+cons_vcons_scrollback (vcons_t vcons, cons_scroll_t type, float value)
+{
+ int ret;
+
+ mutex_lock (&vcons->lock);
+ ret = _cons_vcons_scrollback (vcons, type, value);
+ _cons_vcons_console_event (vcons, CONS_EVT_OUTPUT);
+ cons_vcons_update (vcons);
+ mutex_unlock (&vcons->lock);
+ return ret;
+}
+
diff --git a/libdirmgt/ChangeLog b/libdirmgt/ChangeLog
deleted file mode 100644
index 28d23867..00000000
--- a/libdirmgt/ChangeLog
+++ /dev/null
@@ -1,5 +0,0 @@
-Tue Apr 11 11:14:27 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: New file.
-
-
diff --git a/libdiskfs/=exc.c b/libdiskfs/=exc.c
deleted file mode 100644
index ced9c5b9..00000000
--- a/libdiskfs/=exc.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- Copyright (C) 1994, 1995 Free Software Foundation
-
- 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. */
-
-#include "priv.h"
-
-/* List of preempters that are around. */
-struct preempt_record
-{
- struct preempt_record *next;
- struct hurd_signal_preempt preempter1, preempter2;
- struct pager *p;
- vm_address_t off;
- void *addr;
- long len;
-};
-
-static struct preempt_record *preempt_list;
-static spin_lock_t preempt_list_lock = SPIN_LOCK_INITIALIZER;
-
-/* This special signal handler is run anytime we have taken a fault on
- a page that we map (registered through
- diskfs_register_memory_fault_area). What we do is just longjmp to the
- context saved on the stack by diskfs_catch_exception. */
-static void
-special_segv_handler (int code, int subcode, int error)
-{
- struct preempt_record *rec;
- struct thread_stuff *stack_record;
-
- /* SUBCODE is the address and ERROR is the error returned by the
- pager through the kernel. But because there is an annoying
- kernel bug (or rather unimplemented feature) the errors are not
- actually passed back. So we have to scan the list of preempt
- records and find the one that got us here, and then query the
- pager to find out what error it gave the kernel. */
- spin_lock (&preempt_list_lock);
- for (rec = preempt_list; rec; rec = rec->next)
- if ((void *)subcode >= rec->addr
- && (void *)subcode < rec->addr + rec->len)
- break;
- assert (rec);
- spin_unlock (&preempt_list_lock);
- error = pager_get_error (rec->p, rec->off + (void *)subcode - rec->addr);
-
- /* Now look up the stack record left by diskfs_catch_exception, consuming it
- on the way */
- stack_record = (struct thread_stuff *) cthread_data (cthread_self ());
- assert (stack_record);
- cthread_set_data (cthread_self (), (any_t)stack_record->link);
-
- /* And return to it... */
- longjmp (&stack_record->buf, error);
-
- abort ();
-}
-
-/* Return a signal handler for a thread which has faulted inside a
- region registered as expecting such faults. This routine runs
- inside the library's signal thread, and accordingly must be
- careful. */
-static sighandler_t
-segv_preempter (thread_t thread, int signo,
- long int sigcode, int sigerror)
-{
- /* Just assume that everything is cool (how could it not be?)
- and return our special handler above. */
- return special_segv_handler;
-}
-
-/* Mark the memory at ADDR continuing for LEN bytes as mapped from pager P
- at offset OFF. Call when vm_map-ing part of the disk. */
-void
-diskfs_register_memory_fault_area (struct pager *p,
- vm_address_t off,
- void *addr,
- long len)
-{
- struct preempt_record *rec = malloc (sizeof (struct preempt_record));
-
- hurd_preempt_signals (&rec->preempter1, SIGSEGV, addr, addr + len,
- segv_preempter);
- hurd_preempt_signals (&rec->preempter2, SIGBUS, addr, addr + len,
- segv_preempter);
- rec->p = p;
- rec->off = off;
- rec->addr = addr;
- rec->len = len;
-
- spin_lock (&preempt_list_lock);
- rec->next = preempt_list;
- preempt_list = rec;
- spin_unlock (&preempt_list_lock);
-}
-
-/* Mark the memory at ADDR continuing for LEN bytes as no longer
- mapped from the disk. Call when vm_unmap-ing part of the disk. */
-void
-diskfs_unregister_memory_fault_area (void *addr,
- long len)
-{
- struct preempt_record *rec, **prevp;
-
- spin_lock (&preempt_list_lock);
- for (rec = preempt_list, prevp = &preempt_list;
- rec;
- rec = rec->next, prevp = &rec->next)
- if (rec->addr == addr && rec->len == len)
- {
- /* This is it, make it go away. */
- *prevp = rec->next;
- spin_unlock (&preempt_list_lock);
- hurd_unpreempt_signals (&rec->preempter1, SIGSEGV);
- hurd_unpreempt_signals (&rec->preempter2, SIGBUS);
- free (rec);
- return;
- }
- spin_unlock (&preempt_list_lock);
-
- /* Not found */
- assert (0);
-}
-
-/* Set up the exception handling system. */
-void
-init_exceptions ()
-{
-}
diff --git a/libdiskfs/ChangeLog b/libdiskfs/ChangeLog
deleted file mode 100644
index 6d0fa719..00000000
--- a/libdiskfs/ChangeLog
+++ /dev/null
@@ -1,2492 +0,0 @@
-Thu Aug 1 17:24:08 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * file-get-transcntl.c (diskfs_S_file_get_translator_cntl): Don't
- diskfs_nput NP; we've never created a reference. Just unlock it.
- (And bother to lock it in the first place.)
-
-Sat Jul 27 20:05:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * lookup.c (diskfs_lookup): Don't nput *NP if we didn't find a file.
-
- * init-startup.c (diskfs_S_startup_dosync): Clean up after ourselves.
- Don't sync if DISKFS_READONLY.
- * file-syncfs.c (diskfs_S_file_syncfs): Don't sync if DISKFS_READONLY.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs): Likewise.
- * sync-interval.c (periodic_sync): Likewise.
- * shutdown.c (diskfs_shutdown): Likewise.
-
-Fri Jul 26 14:52:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): Unlock NP before we attempt to
- do setuid/setgid (which otherwise can deadlock during port reauth).
- Pay attention to the error code returned by fshelp_exec_reauth,
- and don't make NEWPI if it's an error.
- Initialize ERR.
-
-Tue Jul 23 16:05:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-version.c (_print_version): Make return type void.
-
-Fri Jul 19 21:19:42 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * filedev.c (diskfs_get_file_device): INTS[3] contains the number
- of runs, not the number of offsets (which is 2*NUM_RUNS).
- Don't deallocate the device port we've fetched.
-
- * opts-std-startup.c (startup_options, parse_startup_opt): Remove
- the --version option, which is handled elsewhere now.
-
-Thu Jul 18 23:05:56 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * protid-make.c (diskfs_start_protid): Use noinstall version of
- ports_create_port.
- (diskfs_finish_protid): Install port right into port set here.
-
-Mon Jul 15 21:37:12 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_checkdirmod): diskfs_isowner returns error or
- zero, so invert sense of tests.
-
- * lookup.c (diskfs_lookup): If we get an error from
- diskfs_checkdirmod, diskfs_nput the node we picked up; the caller
- won't want it.
-
- * dir-renamed.c (diskfs_rename_dir): When unlocking FDP, only do
- it if we FDP != TDP. Also, only do step two (changing .. in the
- directory being moved) if FDP != TDP.
-
-Sat Jul 13 20:05:27 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Repeat
- diskfs_start_protid and auth_server_authenticate for as we get
- EINTR.
-
-Sun Jul 7 21:07:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_S_fsys_init): Don't use unsafe MOVE_SEND in
- call to exec_init.
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Don't use
- unsafe MOVE_SEND in auth_server_authenticate.
-
-Sun Jul 7 10:27:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-version.c (_print_version): Include HURD_RELEASE in default.
-
-Sat Jul 6 16:27:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-version.c: New file.
- * Makefile (OTHERSRCS): Add opts-version.c.
-
-Sat Jul 6 13:32:58 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * node-drop.c (diskfs_drop_node): If this might be a special
- symlink, then truncate it even though NP->allocsize might be
- clear.
-
-Wed Jul 3 11:22:58 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-identity.c (diskfs_S_io_identity): Fetch identity using
- fshelp_get_identity rather than creating it ourselves.
- * diskfs.h (struct node): Remove member `identity'.
- * node-drop.c (diskfs_drop_node): Don't deallocate NP->identity.
- * node-make.c (diskfs_make_node): Don't initialize NP->identity.
-
-Thu Jun 27 10:07:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init-startup.c (diskfs_startup_diskfs): Don't call
- diskfs_readonly_changed here anymore.
-
- * disk-pager.c (disk_pager_setup): Check diskfs_readonly variable
- instead of calling diskfs_check_readonly.
-
- * Makefile (LCLHDRS): Add diskfs-pager.h.
-
-Tue Jun 25 21:55:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-std-runtime.c (parse_opt): Add hair to share arg parsing
- state between two parsers that use the same parse_opt function at
- the same time.
-
-Mon Jun 24 14:55:50 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init-startup.c (diskfs_S_startup_dosync): Don't crash the
- filesystem, just do a clean sync.
- * node-drop.c (diskfs_drop_node): Call diskfs_check_readonly
- before making mods.
- * priv.h (_diskfs_diskdirty): New variable.
- * diskfs.h (diskfs_check_readonly): New function.
- * readonly.c (_diskfs_diskdirty): New var.
- (diskfs_check_readonly): New function.
- (diskfs_set_readonly): After clean sync, clear _diskfs_diskdirty.
- * rdwr-internal.c (_diskfs_rdwr_internal): Use
- diskfs_check_readonly instead of diskfs_readonly.
- * node-create.c (diskfs_create_node): Likewise.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
- * file-set-trans.c (diskfs_S_file_set_translator): Likewise.
- * disk-pager.c (disk_pager_setup): Likewise.
- * dir-unlink.c (diskfs_S_dir_unlink): Likewise.
- * dir-rmdir.c (diskfs_S_dir_rmdir): Likewise.
- * dir-rename.c (diskfs_S_dir_rename): Likewise.
- * dir-mkfile.c (diskfs_S_dir_mkfile): Likewise.
- * dir-mkdir.c (diskfs_S_dir_mkdir): Likewise.
- * dir-lookup.c (diskfs_S_dir_lookup): Likewise.
- * dir-link.c (diskfs_S_dir_link): Likewise.
- * conch-fetch.c (iohelp_fetch_shared_data): Likewise.
- * remount.c (diskfs_remount): Likewise.
-
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): If
- auth_server_authenticate fails, then fill with empty IDs. We
- can't permit interruption, because this is a simpleroutine.
-
- * file-set-trans.c (diskfs_S_file_set_translator): Validate rdev
- change before making it.
- * file-chflags.c (diskfs_S_file_chflags): Validate flags change
- before making it.
- * lithp.h (dithkfth_validate_author_change): New macro.
- * file-chauthor.c (dithkfth_TH_file_chauthor): Validate new author
- before changing it.
- * node-create.c (diskfs_create_node): Validate group change before
- making it.
- * file-chown.c (diskfs_S_file_chown): Likewise.
- * node-create.c (diskfs_create_node): Validate mode change before
- making it.
- * file-set-trans.c (diskfs_S_file_set_translator): Likewise
- * file-chmod.c (diskfs_S_file_chmod): Likewise.
- * node-create.c (diskfs_creade_node): Validate owner change before
- making it.
- * file-chown.c (diskfs_S_file_chown): Likewise.
- * Makefile (OTHERSRCS): Add validate-mode.c, validate-group.c,
- validate-author.c, validate-flags.c, validate-rdev.c, and
- validate-owner.c.
- * validate-mode.c, validate-group.c, validate-author.c,
- validate-flags.c, validate-rdev.c, validate-owner.c: New files.
- * diskfs.h (diskfs_validate_mode_change,
- diskfs_validate_owner_change, diskfs_validate_group_change,
- diskfs_validate_author_change, diskfs_validate_flags_change,
- diskfs_validate_rdev_change): New decls.
-
-Fri Jun 21 00:18:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsys-options.c (diskfs_S_fsys_get_options): Use
- fshelp_return_malloced_buffer to setup the return data.
- * file-get-fs-opts.c (diskfs_S_file_get_fs_options): Likewise.
- * opts-set.c (diskfs_set_options): Supply INPUT arg to
- fshelp_set_options.
-
- * opts-append-std.c (diskfs_append_std_options): Use argz_add
- instead of rolling our own. Deal with errors.
- <argz.h>: New include.
-
-Wed Jun 19 21:57:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init-startup.c (diskfs_S_startup_dosync): Pass HANDLE to
- ports_lookup_port. Declare ERR.
-
- * opts-get.c (diskfs_get_options): Call diskfs_append_std_options to
- do most of the work.
- * opts-append-std.c: New file.
- * opts-set.c: New file (old version renamed).
- * opts-std-runtime.c: Renamed from opts-set.c.
- (diskfs_set_options): Function removed.
- (struct parse_hook): New type.
- (set_opts, parse_opt): New functions.
- (common_argp, parents, diskfs_std_runtime_argp): New variables.
- * diskfs.h (diskfs_parse_runtime_options): Decl removed.
- (diskfs_std_startup_argp): Renamed from diskfs_startup_argp, now a
- structure decl, not a pointer decl.
- (diskfs_std_device_startup_argp): Renamed from
- diskfs_device_startup_argp, now a structure decl, not a pointer
- decl.
- (diskfs_set_options): Update decl (now takes argz & argz_len).
- (diskfs_runtime_arg): New declaration.
- (diskfs_std_runtime_argp, diskfs_append_std_options): New declarations.
- * opts-runtime-parse.c, opts-runtime-unparse.c: Files removed.
- * opts-std-startup.c (parse_dev_startup_opt): Use argp_error.
- (diskfs_startup_arg, diskfs_device_startup_arg): Variables removed.
- (diskfs_std_startup_argp): Renamed from startup_argp, exported.
- (diskfs_std_device_startup_argp): Renamed from dev_startup_argp,
- exported.
- * fsys-options.c (diskfs_S_fsys_set_options): Don't split
- arguments, just call diskfs_set_options with what we got.
- * opts-runtime.c: New file.
- * Makefile (OTHERSRCS): Add opts-std-runtime.c, opts-append-std.c,
- opts-runtime.c. Remove opts-runtime-parse.c, opts-runtime-unparse.c
-
-Thu Jun 13 10:05:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (MIGSTUBS): Add startup_notifyServer.o.
- * init-startup.c (diskfs_S_startup_dosync): Uncomment function.
- * demuxer.c (diskfs_demuxer): Call diskfs_startup_notify_server.
- * init-startup.c (_diskfs_init_completed): NOTIFY doesn't need
- deallocation.
-
- * boot-start.c (diskfs_S_fsys_init): Build version string
- correctly.
-
-Tue May 14 11:14:12 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (OTHERSRCS): Remove init-completed.c.
-
- * node-drop.c (diskfs_drop_node): Fix typo.
-
-Sat May 11 01:11:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-std-startup.c (parse_dev_startup_opt, parse_startup_opt):
- Use ARGP_ERR_UNKNOWN instead of EINVAL.
- * opts-set.c (diskfs_set_options): Likewise.
-
-Fri May 10 17:15:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-identity.c: New file.
- * Makefile (IOSRCS): Add io-identity.c.
- * diskfs.h (diskfs_fsys_identity): New variable.
- (struct node): New member `identity'.
- * init-init.c (diskfs_fsys_identity): New variable.
- (diskfs_init_diskfs): Initialize diskfs_fsys_identity.
- * node-make.c (diskfs_make_node): Initialize NP->identity.
- * node-drop.c (diskfs_drop_node): Free NP->identity if it's been
- allocated.
-
-Thu May 9 11:52:52 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * protid-make.c (diskfs_make_protid): Delete function.
- * diskfs.h (diskfs_make_protid): Delete declaration.
-
- * init-startup.c (_diskfs_init_completed): Don't need to insert
- right any more now that it's a poly arg.
- Provide helpful name to init.
-
- * fsys-options.c (diskfs_S_fsys_get_options): Accept and ignore
- replyport parameters.
-
- * file-sync.c (diskfs_S_file_sync): Accept and ignore new parm
- OMITMETADATA.
-
- * priv.h: ioserver.h -> iohelp.h.
- * diskfs.h: Likewise.
- * file-sync.c (diskfs_S_file_sync): s/ioserver/iohelp/g
- * io-prenotify.c (diskfs_S_io_prenotify): Likewise.
- * io-get-conch.c (diskfs_S_io_get_conch): Likewise.
- * io-modes-off.c (diskfs_S_io_clear_some_openmodes): Likewise.
- * io-modes-on.c (diskfs_S_io_set_some_openmodes): Likewise.
- * io-modes-set.c (diskfs_S_io_set_all_openmodes): Likewise.
- * io-read.c (diskfs_S_io_read): Likewise.
- * io-readable.c (diskfs_S_io_readable): Likewise.
- * io-rel-conch.c (diskfs_S_io_release_conch): Likewise.
- * io-seek.c (diskfs_S_io_seek): Likewise.
- * io-stat.c (diskfs_S_io_stat): Likewise.
- * io-write.c (diskfs_S_io_write): Likewise.
- * conch-fetch.c (iohelp_fetch_shared_data): Likewise.
- * conch-set.c (iohelp_put_shared_data): Likewise.
- * node-make.c (diskfs_make_node): Likewise.
- * node-rdwr.c (diskfs_node_rdwr): Likewise.
- * Makefile (libdiskfs.so): Likewise.
-
- * dir-rename.c (diskfs_S_dir_rename): Understand new parm EXCL and
- do the right thing with it.
- * dir-link.c (diskfs_S_dir_link): Likewise.
-
-Thu May 9 12:12:41 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Don't pass CRED
- port in auth_server_authenticate.
-
- * io-select.c (diskfs_S_io_select): Removed TAG arg.
-
-Thu May 9 11:42:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * filedev.c (diskfs_get_file_device): Deallocate most things we
- got back from file_get_storage_info even if we didn't get an error.
-
- * filedev.c (diskfs_get_file_device): Fix type of DATA & _DATA.
- BLOCKSIZE -> BLOCK_SIZE. Copy name from DATA, not DEV_NAME_BUF.
-
-Mon May 6 20:12:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * filedev.c (diskfs_get_file_device): Enable new version.
-
-Fri May 3 15:55:44 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * filedev.c [0] (diskfs_get_file_device): Rewrite to use new interface.
-
-Tue Apr 30 14:39:06 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init-startup.c: Include <string.h> and <hurd/startup.h>.
- (diskfs_startup_diskfs): If not bootstrap filesystem, call
- _diskfs_init_completed here.
- (diskfs_S_startup_dosync): New function (commented out).
- (_diskfs_init_completed): New function.
- * init-completed.c: Delete file.
- * init-init.c (diskfs_shutdown_notification_class): New variable.
- (diskfs_init_diskfs): Initialize diskfs_shutdown_notification_class.
- * diskfs.h (diskfs_shutdown_notification_class): New variable.
- * boot-start.c (diskfs_S_fsys_init): diskfs_init_completed ->
- _diskfs_init_completed.
- * priv.h (_diskfs_init_completed): New declaration.
- * diskfs.h (diskfs_init_completed): Delete function.
-
-Mon Apr 29 15:42:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * name-cache.c (struct lookup_cache): Add HDR, remove NEXT & PREV.
- (lookup_cache): Change type to struct cacheq.
- (mru_cache, lru_cache): Variables removed.
- (make_mru, make_lru, init_lookup_cache): Functions removed.
- (find_cache, diskfs_purge_lookup_cache,
- diskfs_check_lookup_cache): Use cacheq functions.
-
-Sun Apr 28 15:22:30 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * protid-make.c: Add obsolescence link warning.
-
-Tue Apr 23 11:05:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * node-drop.c (diskfs_drop_node): Don't do anything special for
- socket naming points.
- * Makefile (OTHERSRCS): Add dead-name.c.
- * dead-name.c: New file.
- * ifsock.c (diskfs_S_ifsock_getsockaddr): Request notification for
- new SOCKADDR; count that notification as a reference.
-
-Fri Apr 12 15:56:48 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * name-cache.c (diskfs_enter_lookup_cache): Never cache . or ..
-
-Thu Apr 11 17:59:18 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * console.c: Include <hurd.h>.
-
- * Makefile (fsys-MIGSFLAGS, fs-MIGSFLAGS, io-MIGSFLAGS,
- ifsock-MIGSFLAGS): Reference fsmutations.h in $(srcdir).
-
- * boot-start.c (diskfs_start_bootstrap): Print helpful message
- before doing anything else.
-
-Wed Apr 10 16:47:21 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * name-cache.c (struct lookup_cache): Add NEXT & PREV fields.
- Rename LEN back to NAME_LEN.
- (lru_cache, mru_cache): New variables.
- (first_cache, last_cache): Variables removed.
- (make_mru, make_lru, find_cache, init_lookup_cache): New functions.
- (diskfs_enter_lookup_cache, diskfs_purge_lookup_cache,
- diskfs_check_lookup_cache): Rewrite to use the linked list. Deal
- with negative entries.
-
-Tue Apr 9 12:59:02 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * lookup.c (diskfs_lookup): Deal with DS or NP being 0.
- * name-cache.c (diskfs_check_lookup_cache): Correctly handle the
- case where the lookup returns DIR itself.
-
- * diskfs.h (diskfs_enter_lookup_cache, diskfs_purge_lookup_cache,
- diskfs_check_lookup_cache): Renamed from versions without `lookup_'.
- * name-cache.c (diskfs_enter_lookup_cache, diskfs_purge_lookup_cache,
- diskfs_check_lookup_cache): Likewise.
- * direnter.c (diskfs_direnter): Similarly, rename use.
- * dirrewrite.c (diskfs_dirrewrite): Likewise.
- * dirremove.c (diskfs_dirremove): Likewise.
- * lookup.c (diskfs_lookup): Likewise.
-
-Sun Apr 7 15:29:02 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * name-cache.c (diskfs_check_cache): Declare I.
- (struct lookup_cache, diskfs_enter_cache): Change NAMELEN field to LEN.
-
-Wed Apr 3 16:02:45 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * node-drop.c (diskfs_drop_node): Don't call
- _diskfs_purge_cache_deletion.
- * name-cache.c (_diskfs_purge_cache_deletion): Delete function.
-
- * diskfs.h (diskfs_cached_lookup): New declaration.
- (struct node): New member `cache_id'.
-
-Tue Apr 2 12:50:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * name-cache.c (diskfs_enter_cache): Don't set LC->next->prev if
- LC->next is null.
- (diskfs_purge_cache): If freeing node at LOOKUP_CACHE_TAIL, bump
- LOOKUP_CACHE_TAIL back itself too.
- (_diskfs_purge_cache_deletion): Likewise.
-
- * lookup.c (diskfs_lookup): When doing diskfs_checkdirmod check,
- don't return success when we should return ENOENT, just because
- checkdirmod won. Also enter successful lookups for CREATE or
- LOOKUP in the name cache.
-
-Fri Mar 29 13:57:37 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * io-map-cntl.c: Initialize shared page magic number.
-
-Mon Mar 25 09:30:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * name-cache.c (statistics): New variable.
- (diskfs_check_cache): Keep statistics on cache performance.
-
-Fri Mar 22 17:51:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-runtime-parse.c (diskfs_parse_runtime_options): Supply new
- argument to argp_parse.
-
-Fri Mar 22 15:44:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * lookup.c (diskfs_lookup): Dereference NP in call to
- diskfs_checkdirmod.
- * direnter.c (diskfs_direnter): Don't fall off end.
- * diskfs.h (diskfs_enter_cache, diskfs_purge_cache,
- diskfs_check_cache): Add declarations.
- * dir-rename.c (diskfs_S_dir_rename): Use new args for
- diskfs_dirrewrite and diskfs_dirremove.
- * dir-renamed.c (diskfs_rename_dir): Likewise.
- * dir-clear.c (diskfs_clear_directory): Use new diskfs_dirremove
- args.
- * dir-rmdir.c (diskfs_S_dir_rmdir): Likewise.
- * dir-unlink.c (diskfs_S_dir_unlink): Likewise.
-
- * Makefile (OTHERSRCS): Add direnter.c, dirrewrite.c, dirremove.c,
- and lookup.c.
-
-Wed Mar 20 14:34:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_lookup_hard): Remove mention of ENOTDIR and
- EACCES errors.
- * diskfs.h (diskfs_null_dirstat): New function.
- * dir-lookup.c (diskfs_S_dir_lookup): Don't check cache here.
- * dir-unlink.c (diskfs_S_dir_unlink): Don't frob cache here.
- * dir-rmdir.c (diskfs_S_dir_rmdir): Likewise.
- * dir-clear.c (diskfs_clear_directory): Likewise.
- * node-create.c (diskfs_create_node): Likewise.
- * dir-renamed.c (diskfs_rename_dir): Likewise.
- * dir-rename.c (diskfs_S_dir_rename): Likewise.
- * dir-link.c (diskfs_S_dir_link): Likewise.
- * direnter.c: New file.
- * dirrewrite.c: Likewise.
- * dirremove.c: Likewise.
- * lookup.c: Likewise.
- * diskfs.h (diskfs_lookup): Renamed to be diskfs_lookup_hard.
- (diskfs_direnter): Renamed to be diskfs_direnter_hard.
- (diskfs_dirrewrite): Renamed to be diskfs_dirrewrite_hard.
- (diskfs_dirremove): Renamed to be diskfs_dirremove_hard.
- (diskfs_lookup, diskfs_direnter, diskfs_dirrewrite, diskfs_dirremove):
-
-Tue Mar 19 14:55:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * name-cache.c: New file.
- * Makefile (OTHERSRCS): Add name-cache.c.
- * dir-lookup.c (diskfs_S_dir_lookup): Check cache before normal
- diskfs_lookup call.
- * node-drop.c (diskfs_drop_node): Call
- _diskfs_purge_cache_deletion before releasing node structure with
- diskfs_node_norefs.
- * dir-clear.c (diskfs_clear_directory): Call
- diskfs_purge_cache_node before diskfs_dirremove.
- * dir-rename.c (diskfs_S_dir_rename): Likewise.
- * dir-renamed.c (diskfs_rename_dir): Likewise.
- * dir-rmdir.c (diskfs_S_dir_rmdir): Likewise.
- * dir-unlink.c (diskfs_S_dir_unlink): Likewise.
- * dir-init.c (diskfs_init_dir): Doc fix.
- * dir-rename.c (diskfs_S_dir_rename): Call diskfs_purge_cache
- before diskfs_dirrewrite for old node.
- * dir-renamed.c (diskfs_rename_dir): Likewise.
- * node-create.c (diskfs_create_node): Call diskfs_enter_cache if
- diskfs_direnter is successful.
- * dir-link.c (diskfs_S_dir_link): Likewise.
- * dir-rename.c (diskfs_S_dir_rename): Call diskfs_enter_cache if
- diskfs_direnter/diskfs_dirrewrite is successful.
- * dir-renamed.c (diskfs_rename_dir): Likewise.
-
-Fri Mar 15 23:10:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Don't leak a send right to
- the anonymous handle on DNP when calling fetch_root.
-
-Tue Mar 12 14:36:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * file-set-trans.c (diskfs_S_file_set_translator): Deallocate ref
- on CONTROL when we are done with it.
-
-Thu Mar 7 16:45:02 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * readonly.c (diskfs_set_readonly): Don't sleep(1) after syncing.
-
-Thu Feb 29 14:29:20 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (OTHERSRCS): Change `opts-runtime-def.c' to
- `opts-runtime-parse.c'. Add `opts-runtime-unparse.c'.
-
-Wed Feb 21 06:10:05 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * file-set-trans.c (diskfs_S_file_set_translator): Add EROFS check.
-
-Sun Feb 18 00:08:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init-init.c (diskfs_init_diskfs): Use maptime_map.
- * node-times.c (diskfs_set_node_times): Use maptime_read.
-
-Fri Feb 16 13:48:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-runtime-def.c (diskfs_parse_runtime_options): STANDARD_ARGP
- is const.
-
-Thu Feb 15 16:59:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_nput): It's not valid to touch *NP (by
- `mutex_unlock (&np->lock);') after we have called
- diskfs_drop_node. So don't do it in that case.
-
-Wed Feb 7 22:42:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_nput): Before bumping NP->references (which
- precedes diskfs_try_dropping_softrefs), *lock*
- diskfs_node_refcnt_lock, not mutant unlock.
- (diskfs_nrele): Likewise.
-
-Wed Feb 7 16:22:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_parse_runtime_options): Make STANDARD_ARGP const.
- (diskfs_startup_argp, diskfs_device_startup_argp): Make const.
- * opts-common.c (diskfs_common_options): Make const.
- * opts-std-startup.c (startup_options, dev_startup_options,
- dev_start_argp_parents, dev_startup_argp, startup_common_argp,
- startup_argp_parents, startup_argp, diskfs_startup_argp): Make const.
- * opts-set.c (std_runtime_options): Make const.
- (diskfs_set_options): Make argp structures const.
-
-Wed Feb 7 13:39:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Revert last change.
-
-Tue Feb 6 15:56:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Make the new peropen we'll
- pass as dotdot to the fetch_root with the same flags as DIRCRED->po.
-
-Wed Jan 31 00:27:10 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * node-rdwr.c (diskfs_node_rdwr): Handle null AMTREAD.
-
-Tue Jan 30 21:20:13 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * fsys-options.c (diskfs_S_fsys_set_options): Use
- rwlock_writer_lock instead of rwlock_reader_lock in DO_CHILDREN case.
-
-Tue Jan 30 15:03:35 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * peropen-rele.c (diskfs_release_peropen): Free dotdotport when
- deallocating peropen.
-
-Wed Jan 24 18:14:28 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Use diskfs_create_protid instead
- of diskfs_make_protid, and deal with an error return.
- * dir-mkfile.c (diskfs_S_dir_mkfile): Likewise.
- * file-exec.c (diskfs_S_file_exec): Likewise.
- * file-inv-trans.c (diskfs_S_file_invoke_translator): Likewise.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
- * io-duplicate.c (diskfs_S_io_duplicate): Likewise.
- * io-restrict-auth.c (diskfs_S_io_restrict_auth): Likewise.
- * trans-callback.c (_diskfs_translator_callback2_fn): Likewise.
- * boot-start.c (diskfs_start_bootstrap, diskfs_S_exec_startup_get_info,
- diskfs_execboot_fsys_startup, diskfs_S_fsys_init): Likewise.
- * protid-make.c (diskfs_start_protid): Return an error now, and use
- ports_create_port instead of ports_allocate_port.
- (diskfs_create_protid): New function.
- (diskfs_make_protid): Call diskfs_create_protid.
- * diskfs.h (diskfs_start_protid): Update declaration.
- (diskfs_create_protid): New declaration.
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Use new version of
- diskfs_start_protid.
- * file-getcontrol.c (diskfs_S_file_getcontrol): Use ports_create_port
- instead of ports_allocate_port.
- * boot-start.c (start_execserver, diskfs_start_bootstrap): Likewise.
- * init-startup.c (diskfs_startup_diskfs): Likewise.
- * sync-interval.c (diskfs_set_sync_interval): Likewise.
- (periodic_sync): Pass in the MSG_ID arg to ports_begin_rpc, and
- deal with any error returned.
-
- * readonly.c (diskfs_set_readonly): Deal with ports_inhibit_class_rpcs
- returning an error.
- * remount.c (diskfs_remount): Likewise.
- * shutdown.c (diskfs_shutdown): Likewise.
- * sync-interval.c (diskfs_set_sync_interval): Likewise.
-
- * dir-readdir.c: Include <fcntl.h>.
-
-Tue Jan 23 16:28:47 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts-std-startup.c (startup_options): Put boot options in a
- separate group with a header.
-
-Thu Jan 18 14:05:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir-readdir.c (diskfs_S_dir_readdir): Require read permission
- before succeeding.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Deallocate ref to dotdot
- after diskfs_make_peropen, because the latter does not eat a
- reference.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): In symlink case, use
- MOVE_SEND to return the dotdot port to the user.
-
-Thu Jan 11 22:09:05 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * diskfs-pager.h (struct disk_image_user): New type.
- (diskfs_catch_exception, diskfs_end_catch_exception): Use it to
- maintain a linked list of catchers instead of just one.
-
-Sat Jan 6 11:49:02 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (installhdrs): Add diskfs-pager.h.
- (OTHERSRCS): Add disk-pager.c.
-
-Fri Jan 5 17:06:42 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io-write.c: Return errors regardless of *AMT--writes are all or
- nothing.
- * io-read.c: Return errors regardless of *DATALEN--reads are all or
- nothing.
-
-Thu Jan 4 16:11:35 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * disk-pager.c, diskfs-pager.h: New files.
- * exc.c: File removed.
- * Makefile (OTHERSRCS): Remove exc.c.
- * diskfs.h (diskfs_catch_exception, diskfs_end_catch_exception):
- Macros removed.
- (diskfs_register_memory_fault_area,
- diskfs_unregister_memory_fault_area): Decls removed.
-
- * diskfs.h: Use size_t instead of int for amounts in
- diskfs_node_rdwr prototype.
- * node-rdwr.c (diskfs_node_rdwr): Pass AMTREAD read/write to
- _diskfs_rdwr_internal, instead of assuming it wrote the whole amount.
- Update the node if anything was transferred, regardless of ERR.
- * rdwr-internal.c (_diskfs_rdwr_internal): Rewritten using
- pager_memcpy.
- Fix types of args: OFFSET to off_t, make AMT read/write size_t *.
- * priv.h: Fix args in _diskfs_rdwr_internal prototype.
- * io-write.c: Pass AMT read/write to _diskfs_rdwr_internal, and
- return success if any bytes were written.
- * io-read.c: Likewise.
-
-Mon Jan 1 15:45:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): Use fshelp_exec_reauth().
- (setid, scan_ids): Functions deleted.
-
-Thu Dec 28 14:21:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): Always reauth the proc port,
- as exec does not do it, even in the secure case. Set the proc's
- owner too.
-
- * file-exec.c (setid): Don't touch the return params unless we succeed.
- Add SETID parameter, and just copy old into new unless it's set.
- Handle the NOLDGENIDS == 0 case correctly.
- (diskfs_S_file_exec): Use the new setid() properly. Make sure that
- {GEN,AUX}{UIDS,GIDS} are always in a state where they can be freed.
-
-Thu Dec 28 00:24:29 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * priv.h (end_using_protid_port): Don't calls ports_port_deref if
- CRED is null.
-
-Wed Dec 27 17:32:21 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-exec.c (setid): New function.
- (scan_ids): Moved out of diskfs_S_file_exec.
- (diskfs_S_file_exec): Move duplicated code into setid(). Make the
- bogus auth port case work correctly. Deleted old ifdefed-out code.
- Enable setuid code.
-
- * exc.c (diskfs_register_memory_fault_area): Register both
- preempter1 and preempter2 in REC instead of preempter1 twice.
-
-Sat Dec 23 14:49:22 1995 Michael I. Bushnell p/BSG <mib@gnu.ai.mit.edu>
-
- * exc.c: Entire file rewritten to use libc signal preemption
- facility.
-
-Wed Dec 20 14:49:29 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_S_fsys_init): Call proc_mark_exec on
- EXECPROCESS.
-
-Tue Dec 19 13:19:19 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): Better attempt at
- setuid/setgid execution; still not entirely right, but mostly so.
- Will move this code to libfshelp before turning it on.
-
-Thu Dec 14 15:51:19 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_checkdirmod): Correctly return error code for
- failure, not 1.
-
-Mon Dec 4 17:07:20 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir-unlink.c (diskfs_S_dir_unlink): Don't call fsys_goaway until
- we've released our lock.
-
-Mon Dec 4 16:57:28 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir-unlink.c (diskfs_S_dir_unlink): Delete vestigial fetch_control.
-
-Tue Nov 21 13:54:14 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * rdwr-internal.c (_diskfs_rdwr_internal): Declare PROT volatile.
-
- * init-first.c (master_thread_function): Declare to be `static
- any_t'.
-
- * fsys-options.c: Include <string.h>.
-
- * diskfs.h (diskfs_get_options): Bother providing declaration.
-
- * file-get-fs-opts.c: Include <string.h>.
- (diskfs_S_file_get_fs_options): Dereference DATA_LEN in call to
- vm_allocate.
-
-Sat Nov 18 09:01:28 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_S_exec_startup_get_info): Renamed from
- diskfs_S_exec_startup, slightly different protocol. Unused exec
- server stubs removed.
- * Makefile (MIGSTUBS): Replaced execServer.o with exec_startupServer.o.
-
-Mon Nov 13 17:13:40 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * demuxer.c (diskfs_demuxer):
- diskfs_exec_server --> diskfs_exec_startup_server.
-
-Mon Nov 13 16:28:27 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * file-lock-stat.c (diskfs_S_file_lock_stat): Lock around reads to
- make sure they are mutually consistent.
-
- * io-readable.c (diskfs_S_io_readable): Set *AMOUNT to zero if
- filepointer is past the end of the file.
-
-Thu Nov 9 12:33:53 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir-link.c (diskfs_S_dir_link): Now that args are swapped,
- deallocate port ref on FILECRED instead of DIRCRED.
-
-Sun Nov 5 10:49:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (OTHERSRCS): Add opts-get.c.
- (FSSRCS): Add file-get-fs-opts.c.
- * file-get-fs-opts.c (diskfs_S_file_get_fs_options): New function.
- * fsys-options.c (diskfs_S_fsys_get_options): New function.
- * opts-get.c (diskfs_get_options): New function.
-
- * sync-interval.c (diskfs_sync_interval): New variable.
- (diskfs_set_sync_interval): Set DISKFS_SYNC_INTERVAL.
-
-Sat Nov 4 23:17:50 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-get-trans.c (diskfs_S_file_get_translator): Initialize ERROR.
-
- * trans-callback.c (_diskfs_translator_callback2_fn):
- UNDERLYING_TYPE should be a pointer. As should the UIDS & GIDS
- args to diskfs_make_protid.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Pass both callback args
- to fshelp_fetch_root.
-
- * filedev.c (diskfs_get_file_device): Give FLAGS argument to
- file_get_storage_info.
-
- * dir-lookup.c (diskfs_S_dir_lookup): Fix various typos.
- (short_circuited_callback1): Dereference ARGZ & ARGZ_LEN.
- Include <hurd/paths.h>
-
-Wed Nov 1 15:56:45 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Add new callback arg to
- fshelp_fetch_root call. Change short_circuited_callback1 to
- reflect the split into two callbacks (we use the global diskfs
- callback for the other_).
- * trans-callback.c (_diskfs_translator_callback1_fn,
- _diskfs_translator_callback2_fn): New functions, replacing the
- single original.
- (_diskfs_translator_callback1, _diskfs_translator_callback2):
- New variables, replacing the single original.
- * priv.h (_diskfs_translator_callback1, _diskfs_translator_callback2):
- Declare.
-
- * boot-start.c (diskfs_execboot_fsys_startup): Add FLAGS arg; use.
- * fsys-startup.c (diskfs_S_fsys_startup): Ditto.
- * init-startup.c (diskfs_startup_diskfs): Ditto.
- * diskfs.h (diskfs_startup_diskfs, diskfs_execboot_fsys_startup):
- Add FLAGS arg.
-
-Mon Oct 30 13:20:12 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Move code for starting
- short-circuited translators here, from _diskfs_translator_callback_fn.
- Inline code from node_is_translated.
- (node_is_translated): Function removed.
- (major, minor): New macros -- temporarily here until libc exports them.
-
-Thu Oct 26 18:41:23 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * trans-callback.c (_diskfs_translator_callback_fn): Deal with
- short-circuited translators.
- * dir-lookup.c (node_is_translated): New function.
- (diskfs_S_dir_lookup): Use node_is_translated() instead of
- np->istranslated to see whether NP has a passive translator.
-
- * file-set-trans.c (diskfs_S_file_set_translator): Add missing else.
- Use makedev macro instead of doing it by hand.
- (makedev): New macro -- temporarily here until libc exports one.
-
-Thu Oct 19 12:43:47 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsys-options.c (diskfs_S_fsys_set_options): Only hold
- DISKFS_FSYS_LOCK for writing while setting our own options; we
- hold it for reading while setting our children's.
-
- * rdwr-internal.c (_diskfs_rdwr_internal): Get rid of CRED argument.
- * priv.h (_diskfs_rdwr_internal): Ditto.
- * node-rdwr.c (diskfs_node_rdwr): Ditto.
- * io-write.c (diskfs_S_io_write): Ditto.
- * io-read.c (diskfs_S_io_read): Ditto.
-
-Wed Oct 18 15:52:53 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_get_filemap): Add prot parameter.
- (diskfs_max_user_pager_prot): New declaration.
- * rdwr-internal.c (_diskfs_rdwr_internal): Add argument CRED, and
- use it to decide how to setup the mapped i/o.
- * io-write.c (diskfs_S_io_write): Pass CRED to _diskfs_rdwr_internal.
- * io-read.c (diskfs_S_io_read): Ditto.
- * node-rdwr.c (diskfs_node_rdwr): Ditto.
- * io-map.c (diskfs_S_io_map): Pass the appropiate vm protection to
- diskfs_get_filemap. If this node isn't O_RDWR, only return the
- appropiate memobj.
- Include <fcntl.h>.
- * priv.h (_diskfs_rdwr_internal): Add cred parameter.
-
- * boot-start.c (diskfs_execboot_fsys_startup): Open exec's
- realnode read-only for now, since we know it doesn't matter and
- having gratuitously writable nodes around prevents us from
- starting up or going read-only.
- (diskfs_S_fsys_init): Don't make the cwdir/crdir right with O_WRITE.
- * trans-callback.c (_diskfs_translator_callback_fn): Ditto for
- other translators. The fsys_startup interface should change very
- soon and make this irrelevant.
-
- * readonly.c (diskfs_set_readonly): Return EBUSY if necessary.
- Add hack to try and work around pagers-can't-wait bug.
-
- * opts-common.c (diskfs_common_options): New variable.
- * priv.h (diskfs_common_options): New declaration.
- * opts-std-startup.c (startup_options): Remove options common to
- both runtime and startup.
- (startup_common_argp, startup_argp_parents): New variables.
- (startup_argp): Include parents.
- * opts-set.c (std_runtime_options): Remove options common to
- both runtime and startup.
- (diskfs_set_options): Use the common options.
- * Makefile (OTHERSRCS): Add opts-common.c.
-
- * diskfs.h (diskfs_fsys_lock): Change to a struct rwlock.
- Include <rwlock.h>
- * shutdown.c (diskfs_fsys_lock): Now a rwlock.
- (diskfs_shutdown): Lock DISKFS_FSYS_LOCK for writing.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Hold DISKFS_FSYS_LOCK
- for reading.
- * sync-interval.c (periodic_sync): Hold DISKFS_FSYS_LOCK for
- reading while syncing.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs): Ditto.
- * fsys-options.c (diskfs_S_fsys_set_options): Hold DISKS_FSYS_LOCK
- for writing.
- Dereference PT even when a child filesystem returns an error.
- * opts-set.c (diskfs_set_options): Don't hold DISKS_FSYS_LOCK (our
- caller should).
-
- * machdev.c (diskfs_get_mach_device): SIZE is in blocks.
-
-Wed Oct 18 14:00:58 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): Return EACCES for attempts to
- execute a directory. Dike out totally bogus set[ug]id code.
- Bother to lock NP around critical section.
-
-Tue Oct 17 14:32:41 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init-startup.c (diskfs_startup_diskfs): Call diskfs_readonly_changed
- if we're starting up writable.
- * diskfs.h (diskfs_readonly_changed, diskfs_reload_global_state,
- diskfs_node_reload, diskfs_set_readonly, diskfs_remount): New
- declarations.
- (diskfs_main_request_loop): Declaration removed.
- * Makefile (OTHERSRCS): Add readonly.c, remount.c.
- * readonly.c (diskfs_set_readonly): New function.
- * remount.c (diskfs_remount): New function.
-
- * opts-set.c (diskfs_set_options): Rework readonly transition &
- remounting. Hold diskfs_fsys_lock.
-
- * diskfs.h (diskfs_fsys_lock): Renamed from diskfs_shutdown_lock.
- * shutdown.c (diskfs_shutdown): diskfs_shutdown_lock -->
- diskfs_fsys_lock.
-
-Fri Oct 13 14:51:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_start_bootstrap): Get rid of ARGV argument.
- (diskfs_argv): New declaration.
- * boot-start.c (saved_argv): Variable removed.
- (diskfs_argv): New variable. Should get set by default arg parser.
- (diskfs_start_bootstrap): Get rid of ARGV argument.
- (diskfs_S_fsys_init): Use DISKFS_ARGV instead of SAVED_ARGV.
- * opts-std-startup.c (parse_startup_opt): Set DISKFS_ARGV.
- * init-startup.c (diskfs_startup_diskfs): Call diskfs_start_bootstrap
- if we're the bootstrap file system.
-
- * dev-globals.c (diskfs_device, diskfs_device_name,
- diskfs_device_start, diskfs_device_size, diskfs_device_block_size,
- diskfs_log2_device_block_size, diskfs_log2_device_blocks_per_page):
- New variables.
- * dev-io.c (diskfs_device_write_sync, diskfs_device_write_sync):
- New functions.
- * dev-open.c (diskfs_device_open): New function, new file.
- * diskfs.h (diskfs_device, diskfs_device_name,
- diskfs_device_start, diskfs_device_size, diskfs_device_block_size,
- diskfs_log2_device_block_size, diskfs_log2_device_blocks_per_page,
- diskfs_device_write_sync, diskfs_device_write_sync,
- diskfs_device_open, diskfs_console_stdio): New declarations.
- * console.c (diskfs_console_stdio): New function.
- * Makefile (OTHERSRCS): Add dev-open.c, dev-io.c, dev-globals.c,
- console.c.
- * opts-std-startup.c (diskfs_use_mach_device, diskfs_device_arg,
- dev_startup_options, dev_startup_argp_parents, dev_startup_argp,
- diskfs_device_startup_argp): New variables.
- (parse_dev_startup_opt): New function.
-
-Thu Oct 12 16:11:22 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_execboot_fsys_startup): Fix args to dir_lookup.
- Declare PATHBUF and RETRY.
-
- * boot-start.c (diskfs_S_fsys_init): Put the contents of
- diskfs_init_completed in here, freeing that routine for user-use.
-
- * init-completed.c (diskfs_init_completed): Now empty.
-
- * opts-set.c (std_runtime_options): Renamed from long_options,
- convert to argp format.
- (SHORT_OPTIONS): Removed.
- (diskfs_set_options): Converted to use argp.
- * diskfs.h (diskfs_parse_runtime_options,
- diskfs_standard_startup_argp): Use argp, not options.
- Include <argp.h> instead of <options.h>.
- * opts-runtime-def.c (diskfs_parse_runtime_options): Use argp
- instead of options.
- * opts-std-startup.c (std_startup_options): Renamed from
- std_long_options; converted to argp format.
- (std_startup_argp): Renamed from std_startp_argp, converted argp fmt.
- (diskfs_standard_startup_argp): Renamed from
- diskfs_standard_startup_options.
-
-Thu Oct 12 03:25:09 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_execboot_fsys_startup): Use dir_lookup
- instead of hurd_file_name_lookup to open /servers/exec.
-
-Mon Oct 9 03:42:49 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_execboot_fsys_startup): Pass back a port to
- /servers/exec in *REAL.
-
-Sat Oct 7 20:51:06 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * init-completed.c (diskfs_init_completed): New function.
- * diskfs.h (diskfs_init_completed): must --> may.
- Add necessary includes.
-
- * Makefile (OTHERSRCS): Add init-completed.c.
-
-Sat Oct 7 05:07:42 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (libdiskfs.so): Depend on libpager, libioserver,
- libfshelp, libthreads.
-
-Fri Oct 6 17:26:51 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_get_file_device, diskfs_get_mach_device): New funcs.
- (diskfs_boot_flags): New variable.
- (diskfs_bootflags, diskfs_bootflagarg): Variables deleted.
-
- * boot-start.c (diskfs_S_fsys_getpriv): Add the port type parameters.
-
- * Makefile (MIGSFLAGS): Variable deleted.
- (fs-MIGSFLAGS, io-MIGSFLAGS, ifsock-MIGSFLAGS): New variables.
- (fsys-MIGSFLAGS): Also import fsmutations.h.
-
- * dir-link.c (diskfs_S_dir_link): Swap first two arguments.
-
- * filedev.c (diskfs_get_file_device): Use new block_size return
- value from file_get_storage_info.
-
-Thu Oct 5 15:10:34 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (OTHERSRCS): Remove boot-parse.c; add filedev.c & machdev.c.
- * diskfs.h (diskfs_host_priv, diskfs_master_device): Variables deleted.
- (diskfs_parse_bootargs): Function deleted.
- (diskfs_init_diskfs): Now returns error_t.
- * init-init.c (diskfs_init_diskfs): Always use get_privileged_ports.
- Now return error_t.
- * machdev.c (diskfs_get_mach_device): Use get_privileged_ports
- instead of diskfs_master_device.
- * boot-start.c (diskfs_S_fsys_getpriv): Use get_privileged_ports
- to get the privileged ports.
- (diskfs_start_bootstrap): Use diskfs_boot_flags instead of
- diskfs_bootflagarg.
- (diskfs_start_bootstrap, start_execserver): Look for flags
- directly in diskfs_boot_flags, instead of using the old
- diskfs_bootflags.
- * boot-start.c (diskfs_S_exec_startup): Use get_console to get the
- console device.
- (get_console): New function.
- * opts-std-startup.c (OPT_BOOTFLAGS, OPT_EXEC_SERVER_TASK,
- OPT_HOST_PRIV_PORT, OPT_DEVICE_MASTER_PORT): New defines.
- (std_long_opts, parse_std_startup_opt): Add the
- --device-master-port, --host-priv-port, --exec-server-task, and
- --bootflags options.
-
-Thu Oct 5 00:46:09 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * sync-interval.c (periodic_sync_lock): Variable removed.
- (diskfs_set_sync_interval): Use ports_inhibit_port_rpcs on `pi'
- instead of the spin lock.
- (periodic_sync): Don't use the lock.
- Put ports_begin_rpc before check of periodic_sync_thread.
-
-Wed Sep 27 20:11:09 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * filedev.c (diskfs_get_file_device): New file, new function.
- * machdev.c (diskfs_get_mach_device): New file, new function.
-
-Mon Sep 18 14:21:29 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * io-pathconf.c (diskfs_S_io_pathconf): Renamed from
- file_pathconf.c:diskfs_S_file_pathconf.
- * Makefile (FSSRCS): Deleted file-pathconf.c.
- (IOSRCS): Added io-pathconf.c.
-
-Sun Sep 17 18:04:10 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_S_exec_startup): Don't pass an argument
- string. Set *FLAGS to EXEC_STACK_ARGS.
-
- * file-set-size.c: Renamed from file-trunate.c.
- (diskfs_S_file_set_size): Renamed from diskfs_s_file_truncate.
- If SIZE exceeds the file size, extend the file.
- * Makefile (FSSRCS): Rename file-truncate.c to file-set-size.c.
-
-Sat Sep 16 13:10:21 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ourfs_notify.defs: New file.
- * Makefile (DIST_FILES): Added ourfs_notify.defs.
- (ourfs_notify_U.h ourfs_notifyUser.c, ourfs_notify.defs): Targets
- removed.
-
-Wed Sep 13 12:36:26 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_lookup): Doc fix.
- * dir-clear.c (diskfs_clear_directory): Set the fourth arg in
- REMOVE lookup calls in accord with change in rules for the lookup
- call.
-
-Wed Sep 6 11:30:24 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * demuxer.c (diskfs_demuxer): Use ports_notify_server and
- ports_interrupt_server instead of our own versions.
- * Makefile (SRCS): Removed $(NOTIFYSRCS) and $(INTSRCS).
- (NOTIFYSRCS, INTSRCS, notify-MIGSFLAGS): Removed.
- (MIGSTUBS): Removed notifyServer.o and interruptServer.o.
- * interrupt.c: File deleted.
-
-Tue Aug 29 14:22:58 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * io-select.c (diskfs_S_io_select): Don't check open modes or
- return EBADF.
-
-Fri Aug 25 15:02:19 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (FSYSSRCS): Add fsys-forward.c.
-
-Fri Aug 25 09:44:43 1995 Michael I. Bushnell, p/BSG <mib@mole.gnu.ai.mit.edu>
-
- * file-truncate.c (diskfs_S_file_truncate): Bother to check the
- return value of diskfs_truncate.
-
-Wed Aug 23 14:39:07 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (REMHDRS): Removed.
- Rules dealing with ../lib removed.
-
-Sat Jul 29 10:34:38 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ifsock.c (diskfs_S_ifsock_getsockaddr): Don't loop infinitely if
- we fail to get a reasonable PF_LOCAL server.
-
-Fri Jul 28 14:59:45 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ifsock.c (diskfs_S_ifsock_getsockaddr): Try to restart the
- PF_LOCAL server if it dies.
-
- * node-drop.c (diskfs_drop_node): Don't actually drop the node if
- it is a socket naming point, unless it also has no links.
-
-Sat Jul 22 13:54:48 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-getcontrol.c (diskfs_S_file_getcontrol): Fix typo.
- * boot-start.c (start_execserver): Likewise.
-
-Fri Jul 21 12:37:36 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * trans-callback.c (_diskfs_translator_callback_fn): Use correct
- sense of diskfs_readonly flag.
-
- * boot-start.c (diskfs_start_bootstrap): Free initial reference
- created by diskfs_make_protid.
- (diskfs_S_exec_startup): Likewise.
- (diskfs_S_fsys_init): Likewise.
- * dir-lookup.c (diskfs_S_dir_lookup): Likewise. (Two places.)
- * dir-mkfile.c (diskfs_S_dir_mkfile): Likewise.
- * file-exec.c (diskfs_S_file_exec): Likewise.
- * file-inv-trans.c (diskfs_S_file_invoke_translator): Likewise.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
- * io-duplicate.c (diskfs_S_io_duplicate): Likewise.
- * io-restrict-auth.c (diskfs_S_io_restrict_auth): Likewise.
- * trans-callback.c (_diskfs_translator_callback_fn): Likewise.
-
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Free initial
- reference created by diskfs_start_protid.
-
- * boot-start.c (diskfs_start_bootstrap): Free initial reference
- created by ports_allocate_port.
- (start_execserver): Likewise.
- * file-getcontrol.c (diskfs_S_file_getcontrol): Likewise.
- * init-startup.c (diskfs_startup_diskfs): Likewise.
-
- * dir-lookup.c (diskfs_S_dir_lookup): Examine the active
- translator on NP, not on diskfs_root_node, to see if translator
- usage is necessary.
-
- * file-set-trans.c (diskfs_S_file_set_translator): Only validate
- PASSIVELEN if PASSIVE is set.
-
-Tue Jul 18 16:12:20 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * init-first.c (thread_timeout, server_timeout): New vars.
- (THREAD_TIMEOUT, SERVER_TIMEOUT): Delete macros.
- (master_thread_function): Use vars instead of macros.
-
- * file-get-trans.c (diskfs_S_file_get_translator): Conform to new
- memory semantic of diskfs_get_translator.
-
-Wed Jul 12 16:39:24 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * shutdown.c (diskfs_shutdown): Call ports_resume_class_rpcs for
- diskfs_protid_class before return EBUSY.
-
-Thu Jul 6 15:34:59 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (ourfs_notify_U.h ourfs_notifyUser.c): Use
- ourfs_notify.defs instead of directly out of the include
- directory.
- (ourfs_notify.defs): New target.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Mon Jun 26 15:38:07 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fsys-goaway.c (diskfs_S_fsys_goaway): Include "fsys_S.h" and
- "fsys_reply_U.h". New parms REPLY and REPLY_TYPE. Send
- fsys_goaway reply message before exit.
- * Makefile (fsys-MIGSFLAGS): New variable.
- * fsys-startup.c (diskfs_S_fsys_startup): New parms REPLY and
- REPLYTYPE.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
- * fsys-options.c (diskfs_S_fsys_set_options): Likewise.
- * boot-start.c (diskfs_S_fsys_getpriv): Likewise.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs): Likewise.
- * fsys-getfile.c (diskfs_S_fsys_getfile): Include "fsys_S.h". New
- parms REPLY and REPLYTYPE.
-
- * sync-interval.c (periodic_sync_thread, periodic_sync_lock):
- Declare static.
- (control): Delete var.
- (pi): New var.
- (diskfs_set_sync_interval): Set PI instead of CONTROL.
- (periodic_sync): Do sync by hand; use ports routines around it
- properly.
-
- * shutdown.c (diskfs_shutdown): Fix parentheses on bitwise tests.
-
- * fsys-goaway.c (diskfs_S_fsys_goaway): If diskfs_shutdown returns
- zero, then exit here.
- * shutdown.c (diskfs_shutdown): Don't actually exit; return zero
- instead.
- * init-first.c (master_thread_function): Exit when shutdown
- returns zero.
-
- * file-set-trans.c (diskfs_S_file_set_translator): Ignore harmless
- errors from fsys_goaway.
- * shutdown.c (diskfs_shutdown): Ignore harmless errors from
- fsys_goaway.
- * fsys-options.c (diskfs_S_fsys_set_options/helper): Ignore
- harmless errors from fsys_set_options.
-
- * file-set-trans.c (diskfs_S_file_set_translator): Fix parentheses
- on first active EXCL check.
-
-Fri Jun 23 15:43:55 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fsys-options.c (diskfs_S_fsys_set_options) [helper]: Unlock NP
- around fsys call.
- * file-syncfs.c (diskfs_S_file_syncfs) [helper]: Likewise.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs) [helper]: Likewise.
- * shutdown.c (diskfs_shutdown) [helper]: Likewise.
-
-Thu Jun 22 14:48:46 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * priv.h (_diskfs_translator_callback): Must be extern to force
- inclusion of trans-callback.c.
-
- * dir-lookup.c (diskfs_S_dir_lookup): Correctly parethenize
- O_NOTRANS flags test.
-
-Tue Jun 20 11:52:24 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * node-make.c (diskfs_make_node): Fix function name
- fshelp_init_transbox -> fshelp_transbox_init.
-
- * file-syncfs.c: Include <hurd/fsys.h>.
- * fsys-syncfs.c: Likewise.
-
- * file-syncfs.c (diskfs_S_file_syncfs) [helper]: First arg to
- fshelp_fetch_control should be &NP->transbox, not NP.
- * fsys-options.c (diskfs_S_fsys_set_options) [helper]: Likewise.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs) [helper]: Likewise.
- * shutdown.c (diskfs_shutdown) [helper]: Likewise.
-
- * file-set-trans.c (diskfs_S_file_set_translator): Remove
- assignment from if test.
- * node-rdwr.c (diskfs_node_rdwr): Likewise.
-
-Mon Jun 19 16:32:12 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_node_iterate): New (user-provided) function.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs): Use diskfs_node_iterate
- instead of diskfs_sync_translators.
- * file-syncfs.c (diskfs_S_file_syncfs): Likewise.
- * shutdown.c (diskfs_shutdown): Likewise.
- * fsys-options.c (diskfs_S_fsys_set_options): Likewise.
-
- * dir-rmdir.c (diskfs_S_dir_rmdir): Don't attempt anything for
- translated directories here; just return EBUSY.
- * dir-unlink.c (diskfs_S_dir_unlink): Don't do massively
- complicated fsys_goaway. Instead, call it at the end (but only if
- this was the last link) and ignore errors.
-
- * fsys-startup.c (diskfs_S_fsys_startup): Strip out support for
- translators; fshelp now does that itself.
-
- * file-set-trans.c: Include <hurd/fsys.h>.
-
- * file-set-trans.c (diskfs_S_file_set_translator): Use new
- translator interface throughout.
- * dir-lookup.c (diskfs_S_dir_lookup): Use new translator startup
- interface.
-
-Fri Jun 16 17:42:44 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * file-get-transcntl.c (diskfs_S_file_get_translator_cntl): Use
- fshelp_fetch_control instead of old interface.
-
-Wed Jun 14 15:52:30 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * node-drop.c (diskfs_drop_node): Call fshelp_drop_transbox
- instead of fshelp_kill_translator; do it *after* the truncate.
- * node-make.c (diskfs_make_node): Initialize TRANSBOX member using
- new function. Drop initialization of TRANSLATOR member.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Use new translator
- startup interface.
- * Makefile (OTHERSRCS): Removed trans-start.c, trans-destroy.c,
- and trans-sync.c. Added trans-callback.c.
- * trans-start.c, trans-destroy,c, trans-sync.c: Deleted files.
- * trans-callback.c: New file.
- * priv.h (_diskfs_translator_callback): New declaration.
- * diskfs.h (diskfs_start_translator, diskfs_destroy_translator,
- diskfs_sync_translators):
- Delete declarations.
- (struct node): Replace TRANSLATOR member with new TRANSBOX member.
- (diskfs_get_translator): Specify new calling interface.
-
-Fri Jun 9 15:48:30 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * rdwr-internal.c (_diskfs_rdwr_internal): Cast __VM_PAGE_SIZE in
- comparisen.
- * io-write.c (diskfs_S_io_write): Cast DATALEN to off_t in
- comparisons.
- * io-read.c (diskfs_S_io_read): Cast MAKREAD to off_t in
- comparison.
- * io-prenotify.c (diskfs_S_io_prenotify): Cast END to off_t in
- comparison.
- * file-get-trans.c (diskfs_S_file_get_translator): Declare
- variable `buflen' and various variables `len' to be unsigned.
- * file-exec.c (diskfs_S_file_exec): Declare both variables `i' to
- be unsigned int.
-
- * io-async-icky.c (diskfs_S_io_get_icky_async_id): Validate CRED.
-
- * interrupt.c (diskfs_S_interrupt_operation): Bother to implement.
-
- * init-init.c (diskfs_init_diskfs): Pass null second argument in
- calls to ports_create_class.
-
- * fsys-options.c (diskfs_S_fsys_set_options): Bother validating
- FSYS and implementing DO_CHILDREN.
-
- * dir-lookup.c (diskfs_S_dir_lookup): Initialize GIDS, NUIDS, and
- NGIDS to avoid warning.
-
- * boot-start.c: Provide unused attributes where appropriate.
- * file-chg.c (diskfs_S_file_notice_changes): Mark parameters as
- unused.
- * file-getfh.c (diskfs_S_file_getfh): Likewise.
- * file-inv-trans.c (diskfs_S_file_invoke_translator): Likewise.
- * fsys-getfile.c (diskfs_S_fsys_getfile): Likewise.
- * init-init.c (_diskfs_control_clean): Likewise.
- * io-async.c (diskfs_S_io_async): Likewise.
- * notify-stubs.c: Likewise.
- * file-pathconf.c (diskfs_S_file_pathconf): Declare NAME to be
- unused.
- * io-select.c (diskfs_S_io_select): Declare ATTRIBUTE unused.
- * io-stubs.c (diskfs_S_io_postnotify): Declare parms START and END
- unused.
- * io-prenotify.c (diskfs_S_io_prenotify): Declare parm START
- unused.
-
- * diskfs.h (diskfs_transboot_class): Delete var.
- * init-init.c (diskfs_transboot_class): Delete var.
- (diskfs_init_diskfs): Don't initialize it.
-
- * dir-rename.c (diskfs_S_dir_rename): After renaming directory,
- synchronize relevant state if DISKFS_SYNCHRONOUS.
-
-Thu Jun 8 19:01:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_pager_users): New function.
- * shutdown.c (diskfs_shutdown): Rewrote to use new ports interface
- adequately.
-
-Tue Jun 6 13:50:13 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * init-first.c (diskfs_spawn_first_thread): Call our own
- thread function instead of the ports one directly.
- (master_thread_function): New function.
-
- * notify-nosenders.c (diskfs_do_seqnos_mach_notify_no_senders):
- Don't help support pagers here at all.
- * demuxer.c (diskfs_demuxer): Don't call pager_demuxer.
-
- * boot-start.c (diskfs_start_bootstrap): Use new args for
- ports_allocate_port.
- (start_execserver): Likewise.
- * init-startup.c (diskfs_startup_diskfs): Likewise.
- * protid-make.c (diskfs_start_protid): Likewise.
- * file-getcontrol.c (diskfs_S_file_getcontrol): Likewise.
- * sync-interval.c (diskfs_set_sync_interval): Likewise.
-
- * boot-start.c (diskfs_S_exec_startup): Use ports_lookup_port and
- ports_port_deref instead of ports_check_port_type and
- ports_done_with_port.
- (diskfs_execboot_fsys_startup): Likewise.
- (diskfs_S_fsys_init): Likewise.
- (diskfs_S_fsys_getpriv): Likewise.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
- * fsys-goaway.c (diskfs_S_fsys_goaway): Likewise
- * fsys-startup.c (diskfs_S_fsys_startup): Likewise.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs): Likewise.
- * notify-nosenders.c (diskfs_do_seqnos_mach_notify_no_senders):
- Likewise.
- * priv.h (begin_using_protid_port): Use ports_lookup_port.
- (end_using_protid_port): Use ports_port_deref.
-
- * trans-start.c (fshelp_transboot_port_type): Deleted var.
- * priv.h (enum porttype): Delete.
- * demuxer.c: Renamed from ports-demuxer.c.
- (diskfs_demuxer): Renamed from ports_demuxer.
- * init-init.c (diskfs_protid_class, diskfs_transboot_class,
- diskfs_control_class, diskfs_initboot_class,
- diskfs_execboot_class, diskfs_port_bucket): New vars.
- (diskfs_init_diskfs): Don't call libports_initialize.
- Initialize diskfs_protid_class, diskfs_transboot_class,
- diskfs_control_class, diskfs_initboot_class,
- diskfs_execboot_class, and diskfs_port_bucket.
- * diskfs.h: (diskfs_shutdown_soft_ports): Deleted decl.
- (ports_demuxer): Deleted decl.
- (diskfs_demuxer): New decl.
- (diskfs_protid_class, diskfs_transboot_class, diskfs_control_class,
- diskfs_initboot_class,diskfs_execboot_class, diskfs_port_bucket):
- New decls.
- * ports-noports.c, ports-clean.c, ports-soft.c, ports-idle.c,
- ports-consts.c, pager-consts.c, init-loop.c: Deleted files.
- * Makefile (OTHERSRCS): Deleted ports-noports.c, ports-clean.c,
- ports-soft.c, ports-consts, pager-consts.c, init-loop.c, and
- ports-idle.c.
- Replace ports-demuxer.c with demuxer.c.
-
-Mon May 22 13:52:16 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * opts-set.c (diskfs_set_options): Don't fall through to the error
- case from the 's' one!
- Use ARG instead of the global OPTARG.
-
-Sat May 20 01:11:05 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * file-getcontrol.c (diskfs_S_file_getcontrol): Unlock
- _diskfs_control_lock lock instead of locking it again!
-
-Fri May 19 21:22:14 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * opts-set.c (diskfs_set_options): New function in new file.
- * opts-runtime-def.c (diskfs_parse_runtime_options): Ditto.
- * opts-std-startup.c (diskfs_standard_startup_options): New
- exported variable in new file.
- * fsys-options.c (diskfs_S_fsys_set_options): Extract the argument
- vector and call diskfs_set_options.
- * diskfs.h: (diskfs_standard_startup_options): Declare new variable.
- (diskfs_set_options): Declare new function.
- (diskfs_parse_runtime_options): Ditto.
- Include <options.h> (currently in ../lib).
- * Makefile (OTHERSRCS): Add opts-set.c, opts-std-startup.c, and
- opts-runtime-def.c.
- (OBJS): Add argz.o & options.o.
- (REMHDRS): Add argz.h & options.h.
-
-Tue May 16 17:36:46 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * init-first.c (diskfs_spawn_first_thread): Don't start syncing here.
- * init-startup.c (diskfs_startup_diskfs): Do it here instead.
-
-Mon May 15 15:18:25 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_set_options): Declare.
- * fsys-options.c (diskfs_S_fsys_set_options): Extract argc & argv,
- and call diskfs_set_options.
- * def-set-options.c: New file (contains a default diskfs_set_options).
-
- * Makefile (OBJS): Add argz.o (from ../lib). It shouldn't hurt to
- have this in libdiskfs, since we need it...
- (CPPFLAGS): Add -I../lib, to get argz.h, + $(CPPFLAGS-$(notdir $<))
- Set the vpath for %.c to ../lib, so we get argz.c.
- (OTHERSRCS): Add def-set-options.c.
-
-Sat May 13 03:08:35 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-parse.c (diskfs_execserver_task): New variable.
- (diskfs_parse_bootargs): Take a third integer arg before the
- device name, our name for the task port of the exec server, which
- is loaded and ready to run but suspended.
- * boot-start.c (start_execserver): Don't create and load a task;
- the exec server file is no longer linked into the filesystem.
- Just set the bootstrap port of diskfs_execserver_task and resume
- it.
-
-Fri May 12 16:22:33 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fsys-readonly.c (diskfs_S_fsys_set_options,
- diskfs_S_fsys_mod_readonly): Change from mod_readonly to
- set_options. This file is now actually called fsys-options.c.
- * Makefile (FSYSSRCS): Rename fsys-readonly.c to fsys-options.c.
-
- * sync-interval.c (diskfs_set_sync_interval): New function (in a
- new file) that establishes a thread to periodically sync the
- filesystem.
- * Makefile (OTHERSRCS): Add sync-interval.c and sync-default.c.
- * diskfs.h: Add declarations of diskfs_set_sync_interval and
- diskfs_default_sync_interval.
-
- * init-first.c (diskfs_spawn_first_thread): Start background syncing.
- * sync-default.c (diskfs_default_sync_interval): A new variable
- that defines a default initial sync interval.
-
-Fri May 12 15:45:43 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * io-read.c (diskfs_S_io_read): If the offset is past the end of
- the file, then return EOF.
-
-Thu Apr 27 20:01:16 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * node-drop.c (diskfs_drop_node): Deal cleanly with errors in
- diskfs_truncate.
-
- * diskfs.h (diskfs_nrele, diskfs_nput): We need to hold a real
- reference around the call to diskfs_try_dropping_softrefs, because
- that's a user-supplied routine that might itself rely on the
- reference counting system.
-
-Thu Apr 20 18:54:26 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * node-create.c (diskfs_create_node): Return EROFS if diskfs_readonly.
-
-Tue Apr 4 20:20:40 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * dir-unlink.c (diskfs_S_dir_unlink): Do fsys_goaway for
- translated nodes being unlinked.
- * dir-rmdir.c (diskfs_S_dir_rmdir): Likewise.
-
-Tue Apr 4 18:33:35 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): However, replacing *MAKE_SEND*
- with COPY_SEND just doesn't work...
-
-Tue Apr 4 14:31:51 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): Using MOVE_SEND in call to
- exec_exec loses, because it consumes a reference, which will be
- consumed again by mach_msg_server if we return an error. So use
- COPY_SEND instead, and deallocate the rights ourselves only when
- we are to return success.
-
-Fri Mar 31 12:25:57 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-set-trans.c (diskfs_S_file_set_translator): Only destroy
- existing active translator if ACTIVE_FLAGS will change it. If the
- existing active translator is provided then don't do anything.
-
-Fri Mar 17 11:36:40 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * io-stat.c (diskfs_S_io_stat): Typo.
-
- * diskfs.h: Back out changes to protid and associated permission
- checking functions.
- * file-chmod.c (diskfs_S_file_chmod): Likewise.
- * file-chown.c (diskfs_S_file_chown): Likewise.
- * file-getcontrol.c (diskfs_S_file_getcontrol): Likewise.
-
- * dir-link.c (diskfs_S_dir_link): Fix typo.
-
- * diskfs.h (_diskfs_idcheckdirmod): `diskfs_hasuid' ->
- diskfs_idhasuid.
- * priv.h (CHANGE_NODE_FIELD): Remove trailing space on backslashed
- line.
-
- * diskfs.h (_diskfs_idcheckdirmod): `cred' -> `id'.
- (diskfs_idhasgid): Likewise.
-
- * dir-clear.c (diskfs_clear_directory): Don't do
- diskfs_synchronous here.
- * dir-init.c (diskfs_init_dir): Likewise.
- * dir-rmdir.c (diskfs_S_dir_rmdir): Repair implementation of
- diskfs_syncronous.
- * dir-renamed.c (diskfs_rename_dir): If we are synchronous,
- sync the one node our parent doesn't have access to.
- * dir-mkdir.c (diskfs_S_dir_mkdir): Implement diskfs_synchronous.
- * dir-mkfile.c (diskfs_S_dir_mkfile): Likewise.
- * dir-lookup.c (diskfs_S_dir_lookup): Likewise.
- * io-read.c (diskfs_S_io_read): Likewise.
- * fsys-syncfs.c (diskfs_S_fsys_syncfs): Likewise.
- * node-drop.c (diskfs_drop_node): Likewise.
- * node-rdwr.c (diskfs_node_rdwr): Likewise.
-
-Wed Mar 15 11:54:12 1995 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * conch-fetch.c (ioserver_fetch_shared_data): Implement
- diskfs_synchronous.
- * dir-clear.c (diskfs_clear_directory): Likewise.
- * dir-init.c (diskfs_init_dir): Likewise.
- * dir-renamed.c (diskfs_rename_dir): Likewise.
-
-Wed Mar 8 16:36:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_synchronous): New variable.
- * priv.h (CHANGE_NODE_FIELD): If DISKFS_SYNCHRONOUS, then sync
- node after possibly changing it.
- * io-seek.c: Prevent diskfs_synchronous from having its usual
- effect here.
- * dir-link.c (diskfs_S_dir_link): Implement diskfs_synchronous.
- * dir-rename.c (diskfs_S_dir_rename): Likewise.
- * dir-rmdir.c (diskfs_S_dir_rmdir): Likewise
- * dir-unlink.c (diskfs_S_dir_unlink): Likewise.
- * file-sync.c (diskfs_S_file_sync): Likewise.
- * file-syncfs.c (diskfs_S_file_syncfs): Likewise.
- * io-prenotify.c (diskfs_S_io_prenotify): Likewise.
- * io-stat.c (diskfs_S_io_stat): Likewise.
- * io-write.c (diskfs_S_io_write): Likewise.
- * io-sigio.c (diskfs_S_io_sigio): Likewise.
-
-Tue Mar 7 15:21:09 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * diskfs.h (struct userid): New type.
- (struct protid): Replace UIDS, GIDS, NUIDS, and NGIDS with ID.
- (diskfs_isuid): Replace with new function diskfs_idhasuid.
- (diskfs_groupmember): Replace with new function diskfs_idhasgid.
- (_diskfs_idisowner, _diskfs_idaccess, _diskfs_idcheckdirmod):
- New functions.
- (diskfs_isowner): Check each ID in the chain with
- _diskfs_idisowner.
- (diskfs_access): Check each ID in the chain with _diskfs_idaccess.
- (diskfs_checkdirmod): Check each ID in the chain with
- _diskfs_idcheckdirmod.
- * file-chmod.c (diskfs_S_file_chmod): Perform the permission
- check for each ID in the chain.
- * file-chown.c (diskfs_S_file_chown): Likewise.
- * file-getcontrol.c (diskfs_S_file_getcontrol): Likewise.
-
- * boot-parse.c (diskfs_parse_bootargs): Use assert_perror instead
- of assert where appropriate.
- * boot-start.c (diskfs_start_bootstrap): Likewise.
- (diskfs_S_fsys_init): Likewise.
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Likewise.
- * rdwr-internal.c (_diskfs_rdwr_internal): Likewise.
-
-Thu Jan 19 02:04:34 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (ourfs_notify_U.h ourfs_notifyUser.c): Make this
- instead of ourmsg_U.h. All references changed.
- * dir-chg.c: Undo renaming. Includ ourfs_notify_U.h instead of
- ourmsg_U.h.
-
- * io-select.c: Updated to new io_select protocol.
-
- * dir-chg.c (diskfs_S_dir_notice_changes): Call
- nowait_msg_dir_changed instead of nowait_dir_changed.
-
-Sat Dec 10 20:03:07 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-start.c (start_execserver): When aligning bss size for
- vm_allocate, don't include bss start alignment fixup offset.
-
-Fri Dec 9 02:06:35 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io-read.c (diskfs_S_io_read): Don't check for MAXREAD<0.
-
- * io-write.c: Use mach_msg_type_number_t in place of unsigned int
- and int.
- * io-readable.c: Likewise.
- * io-read.c: Likewise.
-
-Wed Nov 23 00:26:48 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ports-demuxer.c (ports_demuxer): Call
- diskfs_seqnos_notify_server, not seqnos_notify_server.
-
-Fri Nov 11 13:11:35 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * io-read.c (diskfs_S_io_read): If OFF is past the end of the
- file, don't set MAXREAD to a negative number; that will crash
- rdwr_internal.
-
-Wed Nov 9 01:46:18 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-exec.c: Include <hurd/paths.h>.
- (diskfs_S_file_exec): If diskfs_exec isn't already
- set, try to open it here. (Later, we should also deal if
- exec_exec returns that the previous server died.)
-
-Tue Nov 8 00:06:56 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * file-get-trans.c: Include <stdio.h> for asprintf decl.
-
-Wed Nov 2 16:16:57 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * priv.h (CHANGE_NODE_FIELD): Don't call diskfs_node_update here.
-
-Fri Oct 28 18:26:15 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-parse.c (diskfs_parse_bootargs): Make stdout line buffered.
- (diskfs_parse_bootargs): Use getline instead of scanf.
- * boot-start.c (diskfs_start_bootstrap): Likewise.
- (diskfs_S_fsys_init): Create a root port with two send right refs
- and install it as crdir and cwdir.
-
-Tue Oct 25 14:16:50 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_start_bootstrap): Renamed variable ARGV
- to be EXEC_ARGV and ARGVLEN to be EXEC_ARGVLEN.
-
-Fri Oct 7 01:30:12 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-parse.c (diskfs_parse_bootargs): Open console for reading too.
-
- * boot-start.c (saved_argv): New static variable.
- (diskfs_start_bootstrap): Take arg ARGV; store it in saved_argv.
- (diskfs_S_fsys_init): Construct a portarray and call _hurd_init.
- Or, if _hurd_ports is already allocated, call _hurd_proc_init.
- * diskfs.h (diskfs_start_bootstrap): Update prototype.
-
-Thu Oct 6 17:47:42 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * boot-start.c (diskfs_S_fsys_init): Allocate a reference on
- authhandle before allowing the library to consume one.
-
-Wed Oct 5 13:00:46 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * node-drop.c (diskfs_drop_node): Clear passive translator
- if we are releasing the inode.
-
-Thu Sep 29 18:12:31 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-parse.c (diskfs_parse_bootargs): If we have a bootstrap
- port, talk to the CMU default pager on it, then clear it.
-
-Fri Sep 23 00:15:52 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * diskfs.h (diskfs_lost_hardrefs): Doc fix.
- (diskfs_try_dropping_softrefs): New declaration.
- (diskfs_nput): Always call diskfs_lost_hardrefs if the last
- hardref goes away; call diskfs_try_dropping_softrefs if the
- link count has vanished too.
- (diskfs_nrele): Likewise.
- (diskfs_nref): Lock node during call to diskfs_new_hardrefs.
-
-Thu Sep 22 21:20:40 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * diskfs.h (struct node): New member `istranslated'.
- (diskfs_node_translated): Deleted function.
- * dir-lookup.c (diskfs_S_dir_lookup): Use istranslated field
- instead of diskfs_node_translated.
- * file-get-trans.c (diskfs_S_file_get_translator): Likewise.
- * file-inv-trans.c (diskfs_S_file_invoke_translator): Likewise.
- * file-set-trans.c (diskfs_S_file_set_translator): Likewise.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
-
-Fri Sep 16 11:53:04 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * file-set-trans.c (diskfs_S_file_set_translator): Use new
- lock on translator fields; don't hold it and the NP lock
- simultaneously.
- * trans-destroy.c (diskfs_destroy_translator): Doc fix.
-
- * dir-lookup.c (diskfs_S_dir_lookup): Turn off *all* flags
- in call to getroot if we aren't the last component.
-
-Thu Sep 15 13:01:21 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * init-init.c (diskfs_init_diskfs): Restore commented-out
- initialization of diskfs_auth_server_port.
-
-Mon Sep 12 14:38:54 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Clear translator
- port if we get MIG_SERVER_DIED, as with MACH_SEND_INVALID_DEST.
-
-Sun Sep 11 23:30:13 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Copy PATHBUF into RETRYNAME
- properly when symlink target begins with a slash.
-
-Sat Sep 10 08:36:08 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OTHERSRCS): Add init-startup.c.
- * init-init.c (_diskfs_dotdot_file): Variable removed.
- (diskfs_init_diskfs): Take no args; return void.
- Don't do fsys_startup here.
- * init-startup.c (diskfs_startup_diskfs): New file, new function.
- Do fsys_startup here instead.
- * diskfs.h (diskfs_init_diskfs): Update prototype.
- (diskfs_startup_diskfs): Declare it.
-
- * dir-lookup.c (diskfs_S_dir_lookup): Use error_t for ERROR.
- Retry when fsys_getroot returns MIG_SERVER_DIED, as with
- MACH_SEND_INVALID_DEST.
-
-Fri Sep 9 13:04:36 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup) [EAGAIN]: Only copy
- into RETRYNAME if this isn't the last component.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Set *RETRY
- and *RETRYNAME properly on normal return.
-
- * init-init.c (diskfs_init_diskfs): Don't attempt to continue
- if fsys_startup fails. Deallocate BOOTSTRAP after using it.
-
-Wed Sep 7 09:52:52 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * trans-start.c (diskfs_start_translator): Don't give write
- access to underlying node if it's not IFREG.
-
- * dir-lookup.c (diskfs_S_dir_lookup): When returning a port
- passed back from fsys_getroot, use MACH_MSG_TYPE_MOVE_SEND,
- not the local default of MAKE_SEND.
-
- * trans-start.c (diskfs_start_translator): Removed assert.
-
-Tue Sep 6 15:30:59 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * dir-lookup.c (diskfs_S_dir_lookup): Translator startup code
- rewritted to be more robust and use new locking protocol
- on translink structures.
- * trans-start.c (diskfs_start_translator): Don't pass LOCK arg
- to diskfs_start_translator. Unlock NP around call to
- diskfs_start_translator. Don't expect DIR to be deallocated.
-
-Thu Sep 1 12:28:03 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * trans-start.c (diskfs_start_translator): Expect right
- on DIR and NPPORT to be consumed by fshelp_start_translator.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Allocate additional
- send-right for DOTDOT to be consumed by diskfs_start_translator.
- Be careful to deallocate DOTDOT when appropriate.
- * dir-lookup.c (diskfs_S_dir_lookup): Create DIRFILE from
- DNP, not NP. Create local reference for dirfile to use
- in call to fsys_getroot.
-
- * boot-start.c (diskfs_start_bootstrap): Give the
- library values for current working and root directories.
-
- * trans-start.c (diskfs_start_translator): Fix and enable.
- * diskfs.h (diskfs_start_translator): Add new third arg to
- prototype.
- * dir-lookup.c (diskfs_S_dir_lookup): Provide third arg to
- diskfs_start_translator.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
-
-Wed Aug 31 12:04:51 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec) [reauth]: Destroy REF after
- using it.
-
- * file-get-trans.c (diskfs_S_file_get_translator)
- [S_ISCHR || S_ISBLK]: Correct cast of second arg to vm_allocate.
-
- * Makefile (FSYSSRCS): Added fsys-readonly.c and fsys-syncfs.c.
- * fsys-readonly.c, fsys-syncfs.c: New files.
-
-Wed Aug 31 01:50:07 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * boot-parse.c (diskfs_parse_bootargs): Fix scanf format for
- bootstrap filesystem device name.
-
- * file-exec.c (diskfs_S_file_exec): For S_ISUID|S_ISGID, create
- new auth handle and reauthenticate passed ports properly.
-
-Tue Aug 30 13:44:29 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-exec.c (diskfs_S_file_exec): Don't bother setting
- EXEC_NEWTASK for non-readable execs; it doesn't really work
- anyhow.
-
- * init-init.c: Call ports_get_right with the result of
- ports_allocate_port in call to fsys_startup.
-
- * trans-sync.c (diskfs_sync_translators): Use fsys_syncfs
- instead of old ugly method.
-
- * init-init.c: Include <hurd/fsys.h>.
-
- * boot-start.c (diskfs_start_bootstrap): Check to make sure return
- from fsys_getroot and dir_lookup is FS_RETRY_NORMAL with empty
- retry_name instead of old FS_RETRY_NONE.
- * dir-lookup.c (diskfs_S_dir_lookup): Initialize return values with
- FS_RETRY_NORMAL and empty retryname instead of old FS_RETRY_NONE.
-
- * Makefile (FSSRCS): Remove dir-pathtrans.c; add dir-lookup.c.
- * dir-lookup.c: Renamed from dir-pathtrans.c.
- * dir-pathtrans.c (diskfs_S_dir_lookup): Renamed from
- diskfs_S_dir_pathtrans.
- * boot-start.c (diskfs_start_bootstrap): Call dir_lookup instead
- of dir_pathtrans.
- * ifsock.c (diskfs_S_ifsock_getsockaddr): Call file_name_lookup
- instead of path_lookup.
-
-Mon Aug 29 12:51:42 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Use new
- protocol for auth_server_authenticate.
-
-Fri Aug 26 12:49:09 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-set-trans.c (diskfs_S_file_set_translator): Rename args;
- split flags arg into two. Interpret flags according to new
- scheme.
-
-Thu Aug 18 12:58:44 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * boot-parse.c (diskfs_parse_bootargs): Print informative
- bootstrap message.
- * boot-start.c (diskfs_start_bootstrap): Likewise.
- (start_execserver): Likewise.
-
- * boot-start.c (diskfs_start_bootstrap): Only do `pausing'
- hack if RB_KDB was in bootstrap args.
- (start_execserver): Likewise.
-
- * io-select.c (diskfs_S_io_select): Add new `porttype' arg.
-
-Thu Aug 11 13:05:40 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Set retry stuff
- correctly if there are more components after translator
- fsys_getroot.
-
-Sat Jul 23 02:25:54 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (notify-MIGSFLAGS): New variable: -DSEQNOS.
-
- * ports-demuxer.c (ports_demuxer): Prepend diskfs_ to Hurd
- interface server functions.
-
-Fri Jul 22 10:54:23 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Changed to use new scheme.
- * boot-start.c: Include "fsys_reply_U.h" instead of "fsys_reply.h".
- * dir-chg.c: Include "ourmsg_U.h" instead of "msg.h".
- * fsmutations.h SERVERPREFIX): Delete macro.
-
- * diskfs.h (struct thread_stuff, diskfs_catch_exception,
- diskfs_end_catch_exception): Moved here from diskfs_machdep.
- Delete inclusion of diskfs_machdep.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Skip leading
- slashes instead of returning an error.
-
-Tue Jul 19 22:12:29 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Fix fsys_getroot call:
- MACH_MSG_TYPE_MOVE_SEND instead of MACH_PORT_RIGHT_MOVE_SEND.
-
-Tue Jul 19 18:37:52 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * boot-start.c (diskfs_start_bootstrap): Create root port
- before calling fsys_getroot on exec server. Pass root port
- as exec server's dotdot node.
- (diskfs_execboot_fsys_startup): Deleted dotdot args.
- * diskfs.h (diskfs_execboot_fsys_startup): Deleted dotdot args.
- * dir-pathtrans.c (diskfs_S_dir_pathtrans) [translator startup]:
- Set dirfile always, not just when invoking the passive translator.
- Pass dirfile to fsys_getroot. Clean up deallocate of dirfile.
- * file-inv-trans.c (diskfs_S_file_invoke_translator): Comment
- out code; this function should vanish.
- * priv.h (_diskfs_dotdot_file): Deleted variable.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Use new arg `dotdot'
- in place of _diskfs_dotdot_file. Pass dotdot in call to
- fsys_getroot.
- * trans-sync.c (diskfs_sync_translators): Pass grunge as dotdot
- arg in call to fsys_getroot.
- * fsys-startup.c (diskfs_S_fsys_startup): Deleted dotdot args;
- don't pass them in calls to helper functions.
- * init-init.c (diskfs_init_diskfs): Don't expect dotdot arg
- from fsys_getroot; don't set _diskfs_dotdot_file.
-
-Mon Jul 18 15:24:30 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * file-inv-trans.c: New file.
- * Makefile (FSSRCS): Added file-inv-trans.c.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Dereference
- returned_port in check for null.
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Likewise.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): After
- diskfs_start_translator, set var `control'.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): After getting
- MACH_SEND_INVALID_DEST from the translator, set error to zero
- so that the user's open completes normally. Do other fixes
- from Jul 7 that were made in dir-pathtrans.c for translator
- startup.
-
- * ports-idle.c (ports_notice_idle): New file.
- * Makefile (OTHERSRCS): Added ports-idle.c.
-
- * node-times.c (diskfs_set_node_times): Set old stat structure
- times until the header file gets changed.
-
- * ifsock.c (diskfs_S_ifsock_getsockaddr): Provide type argument
- in call to socket_fabricate_address.
-
-Fri Jul 15 12:00:38 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Use
- DIRCRED->po->dotdotport instead of diskfs_dotdot_file.
-
- * diskfs.h (diskfs_read_symlink_hook): New variable.
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Don't permit symlinks
- to be opened for reading or writing (just like other special file
- types). Try using diskfs_read_symlink_hook before reading
- from file data.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Try using
- diskfs_read_symlink_hook before reading from file data.
- * file-get-trans.c (diskfs_S_file_get_translator): Likewise.
-
-Thu Jul 14 14:39:08 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * diskfs.h (diskfs_create_symlink_hook): New variable.
- (diskfs_truncate): Doc fix.
- * file-set-trans.c (diskfs_S_file_set_translator): Try
- diskfs_create_symlink_hook first, before writing ourselves.
- Return errors to user properly.
-
- * node-times.c (diskfs_set_node_times): Use new stat structures
- with struct timespec instead of old definitions.
-
-Wed Jul 13 14:26:37 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * shutdown.c (diskfs_shutdown): Check UNLINK bit first to avoid
- dumping translators if we end up returning an error.
-
- * ports-noports.c: New file.
- * ports-soft.c: New file.
- * diskfs.h (diskfs_shutdown_soft_ports): New declaration.
- * Makefile (OTHERSRCS): Added ports-noports.c and ports-soft.c.
-
- * diskfs.h (diskfs_init_diskfs): New arg `bootstrap'; add return
- value. Call fsys_getroot if bootstrap is set.
-
- * diskfs.h (diskfs_dotdot_file): Deleted variable.
- (struct peropen): New member `dotdotnode'.
- (diskfs_make_peropen): New arg DOTDOTPORT.
- * peropen-make.c (diskfs_make_peropen): Set PO->dotdotport;
- allocate reference if necessary.
- * priv.h (_diskfs_dotdot_file): New variable.
- * init-init.c (_diskfs_dotdot_file): New definition.
- * boot-start.c (diskfs_start_bootstrap): dotdot for created
- peropen to root should be null (we are *the* root directory in this
- case).
- (diskfs_S_exec_startup): Likewise.
- * dir-mkfile.c (diskfs_S_dir_mkfile): Inherit dotdot for
- new peropen from CRED->po.
- * file-exec.c (diskfs_S_file_exec): Likewise.
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Inherit dotdot for
- new peropens from DIRCRED->po.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Set dotdot
- from _diskfs_dotdot_file.
-
- * diskfs.h (diskfs_control_port): Deleted variable.
- * priv.h (_diskfs_control_lock, _diskfs_ncontrol_ports): New vars.
- (_diskfs_control_clean): New declaration.
- * ports-clean.c (ports_cleanroutines[PT_CTL]): Use
- _diskfs_control_clean.
- * init-init.c (diskfs_init_diskfs): Don't create control port here.
- (_diskfs_control_lock, _diskfs_ncontrol_ports): New declarations.
- * file-getcontrol.c (diskfs_S_file_getcontrol): Always create
- a new control port structure.
-
- * io-write.c (diskfs_S_io_write): Honor O_FSYNC bit.
- * conch-set.c (ioserver_put_shared_data): Set do_sigio if
- user set O_FSYNC.
- * io-stubs.c (diskfs_S_io_sigio): Removed function.
- * io-sigio.c: New file.
- * Makefile (IOSRCS): Added io-sigio.c
-
- * io-write.c (diskfs_S_io_write): Eliminate pointless test for
- !err before _diskfs_rdwr_internal; only increment filepointer if
- there was no error.
-
- * priv.h (_diskfs_rdwr_internal): New arg NOTIME.
- * rdwr-internal.c (_diskfs_rdwr_internal): New arg NOTIME.
- * io-read.c (diskfs_S_io_read): Don't set atime if O_NOATIME is on.
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Don't allow non-owner
- to set O_NOATIME.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
-
- * priv.h (HONORED_STATE_MODES): Add O_NOATIME.
- (OPENONLY_STATE_MODES): New macro.
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Use
- OPENONLY_STATE_MODES to turn off appropriate bits.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): At start, turn
- off all the bits not in O_HURD; we ignore all those and don't
- keep track of them in any way.
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
-
- * file-get-trans.c (diskfs_S_file_get_translator): Return
- shortcircuited translators for IFCHR, IFBLK, IFIFO, and IFSOCK.
-
- * file-set-trans.c (diskfs_S_file_set_translator): In computing
- rdev, 377 should be *octal*, not hex.
-
- * dir-rename.c (diskfs_S_dir_rename): Deallocate received
- send-right for TOCRED any time we return success.
-
- * dir-link.c (diskfs_S_dir_link): Don't assume that NP is a
- non-directory before checking it.
-
- * boot-start.c (diskfs_start_bootstrap): New variable
- `initnamebuf' which is allocated and then not changed; free
- it rather than freeing `initname'.
-
-Mon Jul 11 18:16:25 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Symlinks to pathnames
- beginning with `/' sholud return FS_RERTY_MAGICAL (but the
- retry name is stils the same).
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
-
-Fri Jul 8 13:34:25 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): After getting
- MACH_SEND_INVALID_DEST from the translator, set error to zero
- so that the user's open completes normally.
- (diskfs_S_dir_pathtrans): Call mach_port_mod_refs correctly.
- (diskfs_S_dir_pathtrans): In call to fsys_getroot, turn off
- O_NOLINK for !lastcomp, not for lastcomp.
-
-Thu Jul 7 14:46:46 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Deal correctly
- with the sendright on the translator control port avoiding
- races while the node is unlocked.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): At translator
- lookup time, if there is an active translator, release the
- lock on DNP just like we do in the start-passive case. Also
- after fsys_getroot, release reference and clear DNP so that
- code at out: doesn't get it wrong.
- (diskfs_S_dir_pathtrans): Call fshelp_translator_drop instead
- of setting it to null ourselves.
- * trans-destroy.c (diskfs_destroy_translator): Likewise.
-
-Wed Jul 6 14:43:55 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * ports-demuxer.c (ports_demuxer): Only call ifsock_server
- if diskfs_shortcut_ifsock is set.
-
-Tue Jul 5 14:15:32 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (TAGSHDRS): New variable.
-
-Thu Jun 30 11:35:43 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fsmutations.h (IFSOCK_IMPORTS): New macro.
-
- * ports-demuxer.c (ports_demuxer): Call ifsock_server.
-
-Wed Jun 29 17:07:17 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * diskfs.h (struct node): New member `sockaddr'.
- * node-make.c (diskfs_make_node): Initialize NP->sockaddr.
- * node-drop.c (diskfs_drop_node): Deallocate NP->sockaddr
- if it's been set.
- * ifsock.c: New file.
- * Makefile (IFSOCKSRCS): New variable.
- (SRCS): Added $(IFSOCKSRCS).
- (MIGSTUBS): Added ifsockServer.o.
- (ifsock_S.h ifsockServer.c): New rule.
- (ifsock_S.h): Depended on by IFSOCKSRCS generated objects.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Detect the case
- where the server has died by looking for MACH_SEND_INVALID_DEST
- as a return from fsys_getroot. Rearrange lock/unlock and
- reference counting of NP and DNP because we may need them back
- if we have to repeat the call.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Likewise.
-
-Fri Jun 24 15:52:52 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-link.c (diskfs_S_dir_link): The port_info struct member
- is `port_right', not `port'.
-
-Tue Jun 21 13:25:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-link.c (diskfs_S_dir_link): Deallocate received send
- right for DIRCRED anytime we return success.
-
- * dir-chg.c (diskfs_S_dir_notice_changes): New var `np'. Return
- ENOTDIR if call is made on a non-directory.
-
-Mon Jun 20 16:40:37 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * node-drop.c (diskfs_drop_node): Free structures holding
- dirmod requests.
- * node-make.c (diskfs_make_node): Initialize NP->dirmod_reqs
- to zero.
-
-Fri Jun 17 13:16:18 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Initialize ERROR.
-
-Fri Jun 17 11:21:25 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * trans-sync.c: Include <fcntl.h>.
-
- * Makefile (boot-start.o): Depend on fsys_reply.h.
-
-Thu Jun 16 11:31:46 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makefile (msg.h, msgUser.c): New rules.
- (MIGSTUBS): Added msgUser.o.
- (dir-chg.o): Depends on msg.h.
- * dir-chg.c: Include "msg.h".
-
- * diskfs.h (diskfs_start_translator): Second arg DIR is now
- file_t. Changed locking rules.
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Call
- diskfs_start_translator the new way; clean up lock releases.
-
- * fshelp-dropnode.c: Deleted file.
- * fshelp-getnode.c: Deleted file.
- * Makefile (OTHERSRCS): Removed fshelp-dropnode.c and fshelp-getnode.c.
-
- * boot-start.c (diskfs_start_bootstrap): Use new fsys_getroot
- interface.
-
- * fsys-getroot.c: Include <fcntl.h> for O_ bits. Include
- <hurd/fsys.h> for fsys_startup prototype.
-
- * boot-start.c (diskfs_start_bootstrap, diskfs_S_exec_startup):
- Delete obsolete assignments to INIT_PORT_LOGINCOLL.
-
- * diskfs.h (struct node) [dirmod_reqs]: New member.
- (struct dirmod): New type.
- (diskfs_dirrewrite, diskfs_dirremove, diskfs_direnter): Doc fix.
- (diskfs_notice_dirchange): New prototype.
- * dir-chg.c (diskfs_S_dir_notice_changes): Implement call.
- (diskfs_notice_dirchange): New function.
-
- * diskfs.h (diskfs_get_directs): Doc fix.
-
- * file-access.c (diskfs_S_file_check_access): Renamed from
- diskfs_S_file_access. Return allowable operations in *TYPE
- rather than checking those explicitly asked for. Use O_ bits
- instead of _OK bits. Include <fcntl.h>.
-
-Wed Jun 15 21:26:14 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Require lookup of
- empty pathname to fail if not made on a directory.
-
- * fsys-getroot.c (diskfs_S_fsys_getroot): Rewritten to implement
- the new fsys_getroot interface.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Don't implement
- O_TRUNC here anymore.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Use the new
- fsys_getroot interface for translator startup.
-
- * io-modes-set.c (diskfs_S_io_set_all_openmodes): Only let
- the user set the user-setable bits.
-
- * file-get-transcntl.c (diskfs_S_file_get_translator_cntl): New
- arg CTLTYPE; set appropriately.
-
-Wed Jun 15 12:18:16 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * file-chg.c (diskfs_S_file_notice_changes): Declare return type.
-
- * file-access.c: New file.
- * Makefile (FSSRCS): Added file-access.c.
-
-Tue Jun 14 14:06:36 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * diskfs.h (diskfs_get_dirents): New declaration.
- * dir-readdir.c (diskfs_S_dir_readdir): Implement new
- interface using diskfs_get_directs.
-
- * dir-chg.c, file-chg.c: New files.
- * Makefile (FSSRCS): Added dir-chg.c and file-chg.c.
-
-Thu Jun 9 13:39:25 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Release lock on NP
- during call to fsys_getroot; stash control port and uid info in
- new local variables. Reacquire lock before return (because
- common code at label OUT expects NP to be locked).
-
-Mon Jun 6 18:54:50 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): In translator
- startup check, test O_NOTRANS in flags correctly.
-
- * dir-renamed.c (diskfs_rename_dir): Don't call diskfs_nrele on
- TMPNP after SPEC_DOTDOT calls; the spec says that SPEC_DOTDOT
- with RENAME does not allocate a new reference.
-
-Sun Jun 5 05:51:11 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Fix
- initialization of {GEN,AUX}_{UIDS,GIDS}.
-
-Fri Jun 3 18:19:22 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * file-set-trans.c (diskfs_S_file_set_translator): Use
- fshelp_set_control instead of doing it ourselves.
-
-Thu Jun 2 12:00:51 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * diskfs.h (struct node): New member `light_references'.
- (diskfs_nref, diskfs_nput, diskfs_nrele, diskfs_make_node): Doc fix.
- (diskfs_nref_light, diskfs_nput_light, diskfs_nrele_light):
- New functions.
- (diskfs_nrele, diskfs_nput): Only call diskfs_drop_node if both
- NP->references *and* NP->light_references are zero.
- (diskfs_new_hardrefs, diskfs_lost_hardrefs): New declarations.
- (diskfs_nref): Call diskfs_new_hardrefs when appropriate.
- (diskfs_nput, diskfs_nrele): Call diskfs_lost_hardrefs when
- appropriate.
-
- * node-make.c (diskfs_make_node): Initialize NP->light_references.
- Doc fix.
-
-Wed Jun 1 18:24:11 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Skip over multiple
- slashes in pathnames by incrementing NEXTNAME after setting it.
- Also, if after we do this we discover that there is no last
- component, then set LASTCOMP and clear NEXTNAME and CREATE
- entirely, and set (new variable) MUSTBEDIR. Then check for
- MUSTBEDIR after the node has been fetched. Make var TYPE
- function-global and set it always, not just when NEWNODE is unset.
-
-Fri May 27 08:47:46 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * boot-start.c (diskfs_S_exec_exec, diskfs_S_exec_setexecdata):
- Add missing args.
- (diskfs_S_exec_startup): Don't point *ARGVP to EXEC_DATA local
- storage. Instead, copy EXEC_DATA to *ARGVP if *ARGVLEN allows;
- otherwise vm_allocate new space and copy into there.
-
-Thu May 26 15:33:57 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * diskfs.h (diskfs_nrele): Acquire lock if we are releasing
- the last reference.
-
- * node-drop.c (diskfs_drop_node): If we are truncating, then
- go back to normal user state and do the truncate; the next
- time through we will do the dealloc for real.
- Semantics change: now this routine is responsible for
- unlocking diskfs_node_refcnt_lock. All callers changed.
-
-Wed May 25 20:34:17 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * io-write.c (diskfs_S_io_write): Don't check for *AMT < 0; AMT is
- an out-only parameter.
-
-Wed May 25 12:23:25 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * ports-consts.c (ports_use_multiple_threads): Deleted definition.
- * init-first.c (diskfs_spawn_first_thread): Fork
- ports_manage_port_operations_multithread instead of
- ports_maange_port_operations.
- * init-loop.c (diskfs_main_request_loop): Likewise.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Reference node in
- lookup of empty path case so that common code at the out: label
- doesn't free an extra one.
-
-Mon May 23 23:13:51 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * boot-start.c (diskfs_S_fsys_init): Start exec_init after
- proc_child.
-
-Thu May 19 12:48:53 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * io-reauthenticate.c (diskfs_S_io_reauthenticate): Unlock
- node after calling diskfs_finish_protid.
-
-Thu May 12 14:23:29 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makefile (clean): Add fsys_reply.h and *User.c.
-
-Thu May 12 03:45:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile (fsys_reply.h fsys_replyUser.c): New rule.
- (MIGSTUBS): Add fsys_replyUser.o.
- * boot-start.c: Include fsys_reply.h.
- (diskfs_S_fsys_init): Take new reply port args.
- Send reply msg as soon as verified, before doing anything.
-
-Mon May 9 16:58:24 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * diskfs.h (diskfs_init_completed): New function declaration.
- * boot-start.c (diskfs_S_fsys_init): Don't call _hurd_proc_init.
- Do call diskfs_init_completed.
-
-Thu May 5 13:04:43 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Behave properly
- if nextname is null. Copy nextname to the end of the symlink
- target rather than vice versa. Don't punt to the caller before
- doing the append.
- (diskfs_S_dir_pathtrans): O_NOTRANS should prevent symlink
- interpretation.
- (diskfs_S_dir_pathtrans): If a symlink traversal was the last
- component, then clear CREATE (symlinks to nothing don't honor
- O_CREAT) and clear LASTCOMP (because it isn't true any longer).
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Fix mangled check
- for O_NOLINK.
- (diskfs_S_dir_pathtrans): Repair furtherly mangled check for
- O_NOLINK.
-
- * conch-set.c (ioserver_put_shared_data): Set
- optimal_transfer_size from the same thing we return in stat.
-
- * io-async.c (diskfs_S_io_async): Just return EOPNOTSUPP without
- doing anything more at all.
-
-Thu May 5 06:32:10 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * io-prenotify.c (diskfs_S_io_prenotify): Make START and END args
- type vm_offset_t.
-
- * io-map-cntl.c (diskfs_S_io_map_cntl): Take 3rd result arg
- for msg type of *CTLOBJ; set it to copy-send.
-
- * io-async.c (diskfs_S_io_async): Take 3rd result arg for msg type
- of *IDPORT; set it to copy-send. Return 0 instead of EOPNOTSUPP;
- should not be deallocating NOTIFY if returning an error.
-
- * io-async-icky.c (diskfs_S_io_get_icky_async_id): Take 3rd result arg
- for msg type of *IDPORT; set it to copy-send.
-
- * conch-set.c (ioserver_put_shared_data): Temporarily #if 0
- setting of optimal_transfer_size from bogus undeclared variable.
-
- * protid-make.c: Include <string.h> to get bcopy declared.
-
- * {file,dir,io,fsys}-*.c: Changed return type of all RPC server
- functions to kern_return_t. error_t is not compatible with the
- declarations in the mig-generated header files.
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
- * file-exec.c (diskfs_S_file_exec): Fix msg type arg in exec_exec call.
-
- * dir-pathtrans.c (diskfs_S_dir_pathtrans): Add missing close paren.
-
- * boot-start.c (diskfs_start_bootstrap): Pass msg type arg for
- FILE arg to exec_exec.
- (diskfs_S_fsys_getpriv): Change return type to kern_return_t.
- error_t is not compatible with the declarations in the
- mig-generated header files.
- (diskfs_S_fsys_init): Likewise.
- (exec_stack_base, exec_stack_size): New variables.
- (diskfs_S_exec_startup): Use those for stack values in reply.
- (start_execserver): Pass them to mach_setup_thread to be initialized.
-
-Mon May 2 16:32:22 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * dir-pathtrans.c: Test for O_NOLINK flag was mangled.
-
-Fri Apr 29 16:44:08 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * io-stubs.c (diskfs_S_io_readnotify): New function.
-
- * conch-set.c (ioserver_put_shared_data): Set new fields
- optimal_transfer_size (to sblock->fs_bsize) and
- use_readnotify_size (to zero).
-
- * file-exec.c (diskfs_S_file_exec): Change call to exec_exec in
- accord with interface change in exec.defs.
-
-Mon Feb 14 11:26:26 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * boot-start.c: #include <hurd.h>.
- (start_execserver): Call _hurd_setup_thread in place of start_thread.
diff --git a/libdiskfs/Makefile b/libdiskfs/Makefile
index bf355c47..73686889 100644
--- a/libdiskfs/Makefile
+++ b/libdiskfs/Makefile
@@ -1,5 +1,6 @@
#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+# Copyright (C) 1994,95,96,97,98,99,2000,01,2006
+# 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
@@ -19,16 +20,16 @@ dir := libdiskfs
makemode := library
libname = libdiskfs
-FSSRCS= dir-link.c dir-mkdir.c dir-mkfile.c dir-lookup.c dir-rename.c \
- dir-rmdir.c dir-unlink.c file-chauthor.c file-chflags.c file-chown.c \
- file-get-trans.c file-get-transcntl.c file-getfh.c file-getlinknode.c \
- file-get-fs-opts.c \
- file-set-trans.c file-statfs.c file-sync.c file-syncfs.c \
- file-set-size.c file-utimes.c file-getcontrol.c file-lock.c \
- file-chmod.c dir-readdir.c file-lock-stat.c file-exec.c dir-chg.c \
- file-chg.c file-access.c file-inv-trans.c
-IOSRCS= io-async-icky.c io-async.c io-duplicate.c io-get-conch.c \
- io-interrupt.c io-map-cntl.c io-map.c io-modes-get.c io-modes-off.c \
+FSSRCS= dir-chg.c dir-link.c dir-lookup.c dir-mkdir.c dir-mkfile.c \
+ dir-readdir.c dir-rename.c dir-rmdir.c dir-unlink.c \
+ file-access.c file-chauthor.c file-chflags.c file-chg.c \
+ file-chmod.c file-chown.c file-exec.c file-get-fs-opts.c \
+ file-get-trans.c file-get-transcntl.c file-getcontrol.c \
+ file-getfh.c file-getlinknode.c file-lock-stat.c \
+ file-lock.c file-set-size.c file-set-trans.c file-statfs.c \
+ file-sync.c file-syncfs.c file-utimes.c file-reparent.c
+IOSRCS= io-async-icky.c io-async.c io-duplicate.c io-get-conch.c io-revoke.c \
+ io-map-cntl.c io-map.c io-modes-get.c io-modes-off.c \
io-modes-on.c io-modes-set.c io-owner-mod.c io-owner-get.c \
io-pathconf.c io-prenotify.c io-read.c io-readable.c io-identity.c \
io-reauthenticate.c io-rel-conch.c io-restrict-auth.c io-seek.c \
@@ -37,28 +38,32 @@ FSYSSRCS=fsys-getroot.c fsys-goaway.c fsys-startup.c fsys-getfile.c \
fsys-options.c fsys-syncfs.c fsys-forward.c
IFSOCKSRCS=ifsock.c
OTHERSRCS = conch-fetch.c conch-set.c dir-clear.c dir-init.c dir-renamed.c \
+ extern-inline.c \
node-create.c node-drop.c node-make.c node-rdwr.c node-update.c \
+ node-nref.c node-nput.c node-nrele.c node-nrefl.c node-nputl.c \
+ node-nrelel.c \
peropen-make.c peropen-rele.c protid-make.c protid-rele.c \
- init-init.c init-startup.c init-first.c \
+ init-init.c init-startup.c init-first.c init-main.c \
rdwr-internal.c boot-start.c demuxer.c node-times.c shutdown.c \
sync-interval.c sync-default.c \
opts-set.c opts-get.c opts-std-startup.c opts-std-runtime.c \
opts-append-std.c opts-common.c opts-runtime.c opts-version.c \
- trans-callback.c readonly.c remount.c filedev.c machdev.c \
- dev-open.c dev-io.c dev-globals.c console.c disk-pager.c \
+ trans-callback.c readonly.c readonly-changed.c \
+ remount.c console.c disk-pager.c \
name-cache.c direnter.c dirrewrite.c dirremove.c lookup.c dead-name.c \
validate-mode.c validate-group.c validate-author.c validate-flags.c \
- validate-rdev.c validate-owner.c
+ validate-rdev.c validate-owner.c extra-version.c
SRCS = $(OTHERSRCS) $(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(IFSOCKSRCS)
-LCLHDRS = diskfs.h priv.h lithp.h fsmutations.h diskfs-pager.h
+LCLHDRS = diskfs.h priv.h lithp.h fsmutations.h diskfs-pager.h fhandle.h
installhdrs = diskfs.h diskfs-pager.h
-DIST_FILES = ourfs_notify.defs
MIGSTUBS = fsServer.o ioServer.o fsysServer.o exec_startupServer.o \
- fsys_replyUser.o ourfs_notifyUser.o ifsockServer.o \
+ fsys_replyUser.o fs_notifyUser.o ifsockServer.o \
startup_notifyServer.o
OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
+HURDLIBS = fshelp iohelp store threads ports shouldbeinlibc pager
+
fsys-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h -DREPLY_PORTS
fs-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
io-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
@@ -66,6 +71,3 @@ ifsock-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
MIGCOMSFLAGS = -prefix diskfs_
include ../Makeconf
-
-libdiskfs.so: $(foreach lib,threads ports fshelp shouldbeinlibc iohelp,\
- ../lib$(lib)/lib$(lib).so)
diff --git a/libdiskfs/boot-parse.c b/libdiskfs/boot-parse.c
deleted file mode 100644
index cb4ffca2..00000000
--- a/libdiskfs/boot-parse.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- Copyright (C) 1993, 1994, 1995 Free Software Foundation
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Written by Michael I. Bushnell. */
-
-#include "priv.h"
-#include <stdio.h>
-#include <device/device.h>
-#include <string.h>
-#include <sys/reboot.h>
-#include <mach/mig_support.h>
-
-int diskfs_bootflags;
-char *diskfs_bootflagarg;
-task_t diskfs_execserver_task;
-
-/* Call this if the bootstrap port is null and you want to support
- being a bootstrap filesystem. ARGC and ARGV should be as passed
- to main. If the arguments are not in the proper format, an
- error message will be printed on stderr and exit called. Otherwise,
- diskfs_priv_host, diskfs_master_device, and diskfs_bootflags will be
- set and the Mach kernel name of the bootstrap device will be
- returned. */
-char *
-diskfs_parse_bootargs (int argc, char **argv)
-{
- char *devname;
- device_t con;
- mach_port_t bootstrap;
-
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap != MACH_PORT_NULL)
- {
- /* We were started not by the kernel, but by the CMU default_pager.
- It passes us args: -<flags> root_name server_dir_name. We ignore
- the last one. An RPC on our bootstrap port fetches the privileged
- ports. */
-
- struct
- {
- mach_msg_header_t Head;
- mach_msg_type_t priv_hostType;
- mach_port_t priv_host;
- mach_msg_type_t priv_deviceType;
- mach_port_t priv_device;
- } msg;
- mach_msg_return_t msg_result;
-
- static const mach_msg_type_t portCheck = {
- /* msgt_name = */ MACH_MSG_TYPE_MOVE_SEND,
- /* msgt_size = */ 32,
- /* msgt_number = */ 1,
- /* msgt_inline = */ TRUE,
- /* msgt_longform = */ FALSE,
- /* msgt_deallocate = */ FALSE,
- /* msgt_unused = */ 0
- };
-
- msg.Head.msgh_bits =
- MACH_MSGH_BITS (MACH_MSG_TYPE_MOVE_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
- /* msgh_size passed as argument */
- msg.Head.msgh_remote_port = bootstrap;
- msg.Head.msgh_local_port = mig_get_reply_port ();
- msg.Head.msgh_seqno = 0;
- msg.Head.msgh_id = 999999;
-
- msg_result = mach_msg (&msg.Head, MACH_SEND_MSG|MACH_RCV_MSG,
- sizeof msg.Head, sizeof msg,
- msg.Head.msgh_local_port,
- MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
- if (msg_result != MACH_MSG_SUCCESS)
- {
- if ((msg_result == MACH_SEND_INVALID_REPLY) ||
- (msg_result == MACH_SEND_INVALID_MEMORY) ||
- (msg_result == MACH_SEND_INVALID_RIGHT) ||
- (msg_result == MACH_SEND_INVALID_TYPE) ||
- (msg_result == MACH_SEND_MSG_TOO_SMALL) ||
- (msg_result == MACH_RCV_INVALID_NAME))
- mig_dealloc_reply_port (msg.Head.msgh_local_port);
- else
- mig_put_reply_port (msg.Head.msgh_local_port);
- assert_perror (msg_result);
- }
- mig_put_reply_port (msg.Head.msgh_local_port);
-
- assert (msg.Head.msgh_id == 999999 + 100);
- assert (msg.Head.msgh_size == sizeof msg);
- assert (msg.Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);
- assert (*(int *) &msg.priv_hostType == *(int *) &portCheck);
- assert (*(int *) &msg.priv_deviceType == *(int *) &portCheck);
- diskfs_host_priv = msg.priv_host;
- diskfs_master_device = msg.priv_device;
-
- /* bootstrap_privileged_ports (bootstrap,
- &diskfs_host_priv,
- &diskfs_master_device); */
-
- /* Clear our bootstrap port, to appear as if run by the kernel. */
- task_set_bootstrap_port (mach_task_self (), MACH_PORT_NULL);
-
- devname = argv[2];
- }
- else
- {
- /* The arguments, as passed by the kernel, are as follows:
- -<flags> hostport deviceport rootname */
-
- if (argc != 6 || argv[1][0] != '-')
- {
- fprintf (stderr, "\
-Usage: %s: -[qsdnx] hostport deviceport exectaskport rootname\n",
- program_invocation_name);
- exit (1);
- }
- diskfs_host_priv = atoi (argv[2]);
- diskfs_master_device = atoi (argv[3]);
- diskfs_execserver_task = atoi (argv[4]);
- devname = argv[5];
- }
-
- (void) device_open (diskfs_master_device, D_READ|D_WRITE, "console", &con);
- stderr = stdout = mach_open_devstream (con, "w");
- setlinebuf (stdout);
- stdin = mach_open_devstream (con, "r");
-
- /* For now... */
- /* readonly = 1; */
-
- /* The possible flags are
- q -- RB_ASKNAME
- s -- RB_SINGLE
- d -- RB_KDB
- n -- RB_INITNAME */
- /* q tells us to ask about what device to use, n
- about what to run as init. */
-
- diskfs_bootflags = 0;
- if (index (argv[1], 'q'))
- diskfs_bootflags |= RB_ASKNAME;
- if (index (argv[1], 's'))
- diskfs_bootflags |= RB_SINGLE;
- if (index (argv[1], 'd'))
- diskfs_bootflags |= RB_KDB;
- if (index (argv[1], 'n'))
- diskfs_bootflags |= RB_INITNAME;
-
- if (diskfs_bootflags & RB_ASKNAME)
- {
- char *line = NULL;
- size_t linesz = 0;
- ssize_t len;
- printf ("Bootstrap filesystem device name [%s]: ", devname);
- switch (len = getline (&line, &linesz, stdin))
- {
- case -1:
- perror ("getline");
- printf ("Using default of `%s'.\n", devname);
- case 0: /* Hmm. */
- case 1: /* Empty line, just a newline. */
- /* Use default. */
- free (line);
- break;
- default:
- line[len - 1] = '\0'; /* Remove the newline. */
- devname = line;
- break;
- }
- }
-
- printf ("\nInitial bootstrap: %s", argv[0]);
- fflush (stdout);
-
- diskfs_bootflagarg = argv[1];
-
- return devname;
-}
-
diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c
index 9c0e0f79..15563bdb 100644
--- a/libdiskfs/boot-start.c
+++ b/libdiskfs/boot-start.c
@@ -1,5 +1,6 @@
/*
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,10,11
+ Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -30,17 +31,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <device/device.h>
#include <sys/reboot.h>
#include <string.h>
+#include <argz.h>
+#include <error.h>
#include "fsys_S.h"
#include "fsys_reply_U.h"
-mach_port_t diskfs_exec_ctl;
-mach_port_t diskfs_exec;
+static mach_port_t diskfs_exec_ctl;
extern task_t diskfs_exec_server_task;
+static task_t parent_task = MACH_PORT_NULL;
static struct mutex execstartlock;
static struct condition execstarted;
-static char *default_init = "hurd/init";
+const char *diskfs_boot_init_program = _HURD_INIT;
static void start_execserver ();
@@ -62,6 +65,25 @@ get_console ()
return console;
}
+/* Make sure we have the privileged ports. */
+void
+_diskfs_boot_privports (void)
+{
+ assert (diskfs_boot_filesystem ());
+ if (_hurd_host_priv == MACH_PORT_NULL)
+ {
+ /* We are the boot command run by the real bootstrap filesystem.
+ We get the privileged ports from it as init would. */
+ mach_port_t bootstrap;
+ error_t err = task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ assert_perror (err);
+ err = fsys_getpriv (bootstrap, &_hurd_host_priv, &_hurd_device_master,
+ &parent_task);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ assert_perror (err);
+ }
+}
+
/* Once diskfs_root_node is set, call this if we are a bootstrap
filesystem. */
void
@@ -71,95 +93,164 @@ diskfs_start_bootstrap ()
retry_type retry;
char pathbuf[1024];
string_t retry_name;
- uid_t idlist[] = {0, 0, 0};
mach_port_t portarray[INIT_PORT_MAX];
mach_port_t fdarray[3]; /* XXX */
task_t newt;
error_t err;
- char *initname, *initnamebuf;
- char *exec_argv;
- int exec_argvlen;
+ char *exec_argv, *exec_env;
+ const char *initname;
+ size_t exec_argvlen, exec_envlen;
struct port_info *bootinfo;
struct protid *rootpi;
-
- printf ("Hurd server bootstrap: %s", program_invocation_short_name);
- fflush (stdout);
-
- /* Get the execserver going and wait for its fsys_startup */
- mutex_init (&execstartlock);
- condition_init (&execstarted);
- mutex_lock (&execstartlock);
- start_execserver ();
- condition_wait (&execstarted, &execstartlock);
- mutex_unlock (&execstartlock);
- assert (diskfs_exec_ctl);
+ struct peropen *rootpo;
+ mach_port_t diskfs_exec;
+ unsigned int init_lookups = 0;
/* Create the port for current and root directory. */
- err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node,
- O_READ | O_EXEC,
- MACH_PORT_NULL),
- 0,0,0,0, &rootpi);
+ err = diskfs_make_peropen (diskfs_root_node, O_READ | O_EXEC, 0,
+ &rootpo);
assert_perror (err);
- root_pt = ports_get_right (rootpi);
- /* Get us a send right to copy around. */
- mach_port_insert_right (mach_task_self (), root_pt, root_pt,
- MACH_MSG_TYPE_MAKE_SEND);
+ err = diskfs_create_protid (rootpo, 0, &rootpi);
+ assert_perror (err);
+ /* Get us a send right to copy around. */
+ root_pt = ports_get_send_right (rootpi);
ports_port_deref (rootpi);
- /* Contact the exec server. */
- err = fsys_getroot (diskfs_exec_ctl, root_pt, MACH_MSG_TYPE_COPY_SEND,
- idlist, 3, idlist, 3, 0,
- &retry, retry_name, &diskfs_exec);
- assert_perror (err);
- assert (retry == FS_RETRY_NORMAL);
- assert (retry_name[0] == '\0');
- assert (diskfs_exec);
-
+ if (diskfs_exec_server_task == MACH_PORT_NULL)
+ {
+ /* We are the boot command run by the real bootstrap filesystem.
+ Our parent (the real bootstrap filesystem) provides us a root
+ directory where we look up /servers/exec like any non-bootstrap
+ filesystem would. */
+ 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);
+ else
+ {
+#ifndef NDEBUG
+ /* Make sure this is really a port to another server. */
+ struct port_info *pi = ports_lookup_port (diskfs_port_bucket,
+ diskfs_exec, 0);
+ assert (!pi);
+#endif
+ }
- /* Execute the startup server. */
- initnamebuf = NULL;
- initname = default_init;
- if (index (diskfs_boot_flags, 'i'))
+ /* Here we assume the parent has already printed:
+ Hurd server bootstrap: bootfs[bootdev] exec ourfs
+ */
+ printf ("\nContinuing on new root filesystem %s:", diskfs_disk_name);
+ fflush (stdout);
+ }
+ else
{
- size_t bufsz;
- ssize_t len;
- printf ("Init name [%s]: ", default_init);
- bufsz = 0;
- switch (len = getline (&initnamebuf, &bufsz, stdin))
+ uid_t idlist[] = {0, 0, 0};
+ file_t execnode;
+
+ printf ("Hurd server bootstrap: %s[%s]",
+ program_invocation_short_name, diskfs_disk_name);
+ fflush (stdout);
+
+ /* Get the execserver going and wait for its fsys_startup */
+ mutex_init (&execstartlock);
+ condition_init (&execstarted);
+ mutex_lock (&execstartlock);
+ start_execserver ();
+ condition_wait (&execstarted, &execstartlock);
+ mutex_unlock (&execstartlock);
+ assert (diskfs_exec_ctl != MACH_PORT_NULL);
+
+ /* Contact the exec server. */
+ err = fsys_getroot (diskfs_exec_ctl, root_pt, MACH_MSG_TYPE_COPY_SEND,
+ idlist, 3, idlist, 3, 0,
+ &retry, retry_name, &diskfs_exec);
+ assert_perror (err);
+ assert (retry == FS_RETRY_NORMAL);
+ assert (retry_name[0] == '\0');
+ assert (diskfs_exec != MACH_PORT_NULL);
+
+ /* Attempt to set the active translator for the exec server so that
+ filesystems other than the bootstrap can find it. */
+ err = dir_lookup (root_pt, _SERVERS_EXEC, O_NOTRANS, 0,
+ &retry, pathbuf, &execnode);
+ if (err)
{
- case -1:
- perror ("getline");
- printf ("Using default of `%s'.\n", initname);
- case 0: /* Hmm. */
- case 1: /* Empty line, just a newline. */
- /* Use default. */
- break;
- default:
- initnamebuf[len - 1] = '\0'; /* Remove the newline. */
- initname = initnamebuf;
- while (*initname == '/')
- initname++;
- break;
+ error (0, err, "cannot set translator on %s", _SERVERS_EXEC);
+ mach_port_deallocate (mach_task_self (), diskfs_exec_ctl);
}
+ else
+ {
+ assert (retry == FS_RETRY_NORMAL);
+ assert (retry_name[0] == '\0');
+ assert (execnode != MACH_PORT_NULL);
+ err = file_set_translator (execnode, 0, FS_TRANS_SET, 0, 0, 0,
+ diskfs_exec_ctl, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), diskfs_exec_ctl);
+ mach_port_deallocate (mach_task_self (), execnode);
+ assert_perror (err);
+ }
+ diskfs_exec_ctl = MACH_PORT_NULL; /* Not used after this. */
+ }
+
+ /* Cache the exec server port for file_exec to use. */
+ _hurd_port_set (&_diskfs_exec_portcell, diskfs_exec);
+
+ if (_diskfs_boot_command)
+ {
+ /* We have a boot command line to run instead of init. */
+ err = argz_create (_diskfs_boot_command, &exec_argv, &exec_argvlen);
+ assert_perror (err);
+ initname = exec_argv;
+ while (*initname == '/')
+ initname++;
}
else
- initname = default_init;
+ {
+ /* Choose the name of the startup server to execute. */
+ initname = diskfs_boot_init_program;
+ while (*initname == '/')
+ initname++;
+
+ exec_argvlen = asprintf (&exec_argv, "/%s%c", initname, '\0');
+ assert (exec_argvlen != -1);
+ err = argz_add_sep (&exec_argv, &exec_argvlen,
+ diskfs_boot_command_line, ' ');
+ assert_perror (err);
+
+ initname = exec_argv + 1;
+ }
+ lookup_init:
err = dir_lookup (root_pt, initname, O_READ, 0,
&retry, pathbuf, &startup_pt);
+ init_lookups++;
+ if (err)
+ {
+ printf ("\nCannot find startup program `%s': %s\n",
+ initname, strerror (err));
+ fflush (stdout);
+ free (exec_argv);
+ assert_perror (err); /* XXX this won't reboot properly */
+ }
+ else if (retry == FS_RETRY_MAGICAL && pathbuf[0] == '/')
+ {
+ assert (init_lookups < SYMLOOP_MAX);
+
+ /* INITNAME is a symlink with an absolute target, so try again. */
+ initname = strdupa (pathbuf);
+ goto lookup_init;
+ }
- assert_perror (err);
assert (retry == FS_RETRY_NORMAL);
assert (pathbuf[0] == '\0');
err = ports_create_port (diskfs_initboot_class, diskfs_port_bucket,
sizeof (struct port_info), &bootinfo);
assert_perror (err);
- bootpt = ports_get_right (bootinfo);
- mach_port_insert_right (mach_task_self (), bootpt, bootpt,
- MACH_MSG_TYPE_MAKE_SEND);
+ bootpt = ports_get_send_right (bootinfo);
ports_port_deref (bootinfo);
portarray[INIT_PORT_CRDIR] = root_pt;
@@ -171,31 +262,34 @@ diskfs_start_bootstrap ()
fdarray[0] = fdarray[1] = fdarray[2] = get_console (); /* XXX */
- exec_argvlen =
- asprintf (&exec_argv, "%s%c%s%c", initname, '\0', diskfs_boot_flags, '\0');
+ err = argz_create (environ, &exec_env, &exec_envlen);
+ assert_perror (err);
- err = task_create (mach_task_self (), 0, &newt);
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &newt);
assert_perror (err);
- if (index (diskfs_boot_flags, 'd'))
+ if (_diskfs_boot_pause)
{
- printf ("pausing for init...\n");
+ printf ("pausing for %s...\n", exec_argv);
getc (stdin);
}
- printf (" init");
+ printf (" %s", basename (exec_argv));
fflush (stdout);
err = exec_exec (diskfs_exec, startup_pt, MACH_MSG_TYPE_COPY_SEND,
- newt, 0, exec_argv, exec_argvlen, 0, 0,
+ newt, 0, exec_argv, exec_argvlen, exec_env, exec_envlen,
fdarray, MACH_MSG_TYPE_COPY_SEND, 3,
portarray, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
/* Supply no intarray, since we have no info for it.
With none supplied, it will use the defaults. */
NULL, 0, 0, 0, 0, 0);
free (exec_argv);
+ free (exec_env);
mach_port_deallocate (mach_task_self (), root_pt);
mach_port_deallocate (mach_task_self (), startup_pt);
mach_port_deallocate (mach_task_self (), bootpt);
- if (initnamebuf != default_init)
- free (initnamebuf);
assert_perror (err);
}
@@ -228,6 +322,7 @@ diskfs_S_exec_startup_get_info (mach_port_t port,
mach_port_t rootport;
struct ufsport *upt;
struct protid *rootpi;
+ struct peropen *rootpo;
if (!(upt = ports_lookup_port (diskfs_port_bucket, port,
diskfs_execboot_class)))
@@ -243,14 +338,14 @@ diskfs_S_exec_startup_get_info (mach_port_t port,
*flags = EXEC_STACK_ARGS;
if (*portarraylen < INIT_PORT_MAX)
- vm_allocate (mach_task_self (), (vm_address_t *) portarrayP,
- (INIT_PORT_MAX * sizeof (mach_port_t)), 1);
+ *portarrayP = mmap (0, INIT_PORT_MAX * sizeof (mach_port_t),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
portarray = *portarrayP;
*portarraylen = INIT_PORT_MAX;
if (*dtablelen < 3)
- vm_allocate (mach_task_self (), (vm_address_t *) dtableP,
- (3 * sizeof (mach_port_t)), 1);
+ *dtableP = mmap (0, 3 * sizeof (mach_port_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
dtable = *dtableP;
*dtablelen = 3;
dtable[0] = dtable[1] = dtable[2] = get_console (); /* XXX */
@@ -258,11 +353,12 @@ diskfs_S_exec_startup_get_info (mach_port_t port,
*intarrayP = NULL;
*intarraylen = 0;
- err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node,
- O_READ | O_EXEC,
- MACH_PORT_NULL),
- 0,0,0,0, &rootpi);
+ err = diskfs_make_peropen (diskfs_root_node, O_READ | O_EXEC, 0, &rootpo);
+ assert_perror (err);
+
+ err = diskfs_create_protid (rootpo, 0, &rootpi);
assert_perror (err);
+
rootport = ports_get_right (rootpi);
ports_port_deref (rootpi);
portarray[INIT_PORT_CWDIR] = rootport;
@@ -293,19 +389,18 @@ diskfs_execboot_fsys_startup (mach_port_t port, int flags,
enum retry_type retry;
struct port_info *pt;
struct protid *rootpi;
+ struct peropen *rootpo;
mach_port_t rootport;
if (!(pt = ports_lookup_port (diskfs_port_bucket, port,
diskfs_execboot_class)))
return EOPNOTSUPP;
- err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node, flags,
- MACH_PORT_NULL),
- 0,0,0,0, &rootpi);
+ err = diskfs_make_peropen (diskfs_root_node, flags, 0, &rootpo);
assert_perror (err);
- rootport = ports_get_right (rootpi);
- mach_port_insert_right (mach_task_self (), rootport, rootport,
- MACH_MSG_TYPE_MAKE_SEND);
+ err = diskfs_create_protid (rootpo, 0, &rootpi);
+ assert_perror (err);
+ rootport = ports_get_send_right (rootpi);
ports_port_deref (rootpi);
err = dir_lookup (rootport, _SERVERS_EXEC, flags|O_NOTRANS, 0,
@@ -365,12 +460,11 @@ diskfs_S_fsys_init (mach_port_t port,
{
struct port_infe *pt;
static int initdone = 0;
- process_t execprocess;
- string_t version;
mach_port_t host, startup;
error_t err;
mach_port_t root_pt;
struct protid *rootpi;
+ struct peropen *rootpo;
pt = ports_lookup_port (diskfs_port_bucket, port, diskfs_initboot_class);
if (!pt)
@@ -384,9 +478,12 @@ diskfs_S_fsys_init (mach_port_t port,
anything which might attempt to send an RPC to init. */
fsys_init_reply (reply, replytype, 0);
- /* Allocate our reference here; _hurd_init will consume a reference
+ /* Allocate our references here; _hurd_init will consume a reference
for the library itself. */
err = mach_port_mod_refs (mach_task_self (),
+ procserver, MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ err = mach_port_mod_refs (mach_task_self (),
authhandle, MACH_PORT_RIGHT_SEND, +1);
assert_perror (err);
@@ -394,36 +491,78 @@ diskfs_S_fsys_init (mach_port_t port,
mach_port_deallocate (mach_task_self (), diskfs_auth_server_port);
diskfs_auth_server_port = authhandle;
- assert (diskfs_exec_server_task != MACH_PORT_NULL);
- err = proc_task2proc (procserver, diskfs_exec_server_task, &execprocess);
- assert_perror (err);
-
- /* Declare that the exec server is our child. */
- proc_child (procserver, diskfs_exec_server_task);
- proc_mark_exec (execprocess);
-
- /* Don't start this until now so that exec is fully authenticated
- with proc. */
- exec_init (diskfs_exec, authhandle, execprocess, MACH_MSG_TYPE_COPY_SEND);
- mach_port_deallocate (mach_task_self (), execprocess);
-
- /* We don't need this anymore. */
- mach_port_deallocate (mach_task_self (), diskfs_exec_server_task);
- diskfs_exec_server_task = MACH_PORT_NULL;
+ if (diskfs_exec_server_task != MACH_PORT_NULL)
+ {
+ process_t execprocess;
+ err = proc_task2proc (procserver, diskfs_exec_server_task, &execprocess);
+ assert_perror (err);
+
+ /* Declare that the exec server is our child. */
+ proc_child (procserver, diskfs_exec_server_task);
+ proc_mark_exec (execprocess);
+
+ /* Don't start this until now so that exec is fully authenticated
+ with proc. */
+ HURD_PORT_USE (&_diskfs_exec_portcell,
+ exec_init (port, authhandle,
+ execprocess, MACH_MSG_TYPE_COPY_SEND));
+ mach_port_deallocate (mach_task_self (), execprocess);
+
+ /* We don't need this anymore. */
+ mach_port_deallocate (mach_task_self (), diskfs_exec_server_task);
+ diskfs_exec_server_task = MACH_PORT_NULL;
+ }
+ else
+ {
+ mach_port_t bootstrap;
+ process_t parent_proc;
+
+ assert (parent_task != MACH_PORT_NULL);
+
+ /* Tell the proc server that our parent task is our child. This
+ makes the process hierarchy fail to represent the real order of
+ who created whom, but it sets the owner and authentication ids to
+ root. It doesn't really matter that the parent fs task be
+ authenticated, but the exec server needs to be authenticated to
+ complete the boot handshakes with init. The exec server gets its
+ privilege by the parent fs doing proc_child (code above) after
+ we send it fsys_init (below). */
+
+ err = proc_child (procserver, parent_task);
+ assert_perror (err);
+
+ /* Get the parent's proc server port so we can send it in the fsys_init
+ RPC just as init would. */
+ err = proc_task2proc (procserver, parent_task, &parent_proc);
+ assert_perror (err);
+
+ /* We don't need this anymore. */
+ mach_port_deallocate (mach_task_self (), parent_task);
+ parent_task = MACH_PORT_NULL;
+
+ proc_mark_exec (parent_proc);
+
+ /* Give our parent (the real bootstrap filesystem) an fsys_init
+ RPC of its own, as init would have sent it. */
+ err = task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ assert_perror (err);
+ err = fsys_init (bootstrap, parent_proc, MACH_MSG_TYPE_COPY_SEND,
+ authhandle);
+ mach_port_deallocate (mach_task_self (), parent_proc);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ assert_perror (err);
+ }
/* Get a port to the root directory to put in the library's
data structures. */
- err = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node,
- O_READ|O_EXEC,
- MACH_PORT_NULL),
- 0,0,0,0, &rootpi);
+ err = diskfs_make_peropen (diskfs_root_node, O_READ|O_EXEC, 0, &rootpo);
+ assert_perror (err);
+ err = diskfs_create_protid (rootpo, 0, &rootpi);
assert_perror (err);
- root_pt = ports_get_right (rootpi);
+ root_pt = ports_get_send_right (rootpi);
ports_port_deref (rootpi);
/* We need two send rights, for the crdir and cwdir slots. */
- mach_port_insert_right (mach_task_self (), root_pt, root_pt,
- MACH_MSG_TYPE_MAKE_SEND);
mach_port_mod_refs (mach_task_self (), root_pt,
MACH_PORT_RIGHT_SEND, +1);
@@ -437,7 +576,7 @@ diskfs_S_fsys_init (mach_port_t port,
_hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authhandle); /* Consume. */
_hurd_port_set (&_hurd_ports[INIT_PORT_CRDIR], root_pt); /* Consume. */
_hurd_port_set (&_hurd_ports[INIT_PORT_CWDIR], root_pt); /* Consume. */
- _hurd_proc_init (diskfs_argv);
+ _hurd_proc_init (diskfs_argv, NULL, 0);
}
else
{
@@ -447,8 +586,8 @@ diskfs_S_fsys_init (mach_port_t port,
and call _hurd_init. */
mach_port_t *portarray;
unsigned int i;
- __vm_allocate (__mach_task_self (), (vm_address_t *) &portarray,
- INIT_PORT_MAX * sizeof *portarray, 1);
+ portarray = mmap (0, INIT_PORT_MAX * sizeof *portarray,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
if (MACH_PORT_NULL != (mach_port_t) 0)
for (i = 0; i < INIT_PORT_MAX; ++i)
portarray[i] = MACH_PORT_NULL;
@@ -463,9 +602,8 @@ diskfs_S_fsys_init (mach_port_t port,
if (err)
return err;
- sprintf (version, "%d.%d", diskfs_major_version, diskfs_minor_version);
- proc_register_version (procserver, host,
- diskfs_server_name, HURD_RELEASE, version);
+ proc_register_version (procserver, host, diskfs_server_name, "",
+ diskfs_server_version);
err = proc_getmsgport (procserver, 1, &startup);
if (!err)
@@ -476,6 +614,7 @@ diskfs_S_fsys_init (mach_port_t port,
}
mach_port_deallocate (mach_task_self (), host);
+ mach_port_deallocate (mach_task_self (), procserver);
_diskfs_init_completed ();
@@ -496,14 +635,12 @@ start_execserver (void)
err = ports_create_port (diskfs_execboot_class, diskfs_port_bucket,
sizeof (struct port_info), &execboot_info);
assert_perror (err);
- right = ports_get_right (execboot_info);
- mach_port_insert_right (mach_task_self (), right,
- right, MACH_MSG_TYPE_MAKE_SEND);
+ right = ports_get_send_right (execboot_info);
ports_port_deref (execboot_info);
task_set_special_port (diskfs_exec_server_task, TASK_BOOTSTRAP_PORT, right);
mach_port_deallocate (mach_task_self (), right);
- if (index (diskfs_boot_flags, 'd'))
+ if (_diskfs_boot_pause)
{
printf ("pausing for exec\n");
getc (stdin);
@@ -513,4 +650,3 @@ start_execserver (void)
printf (" exec");
fflush (stdout);
}
-
diff --git a/libdiskfs/conch-fetch.c b/libdiskfs/conch-fetch.c
index 9d31265c..2c5d0fd8 100644
--- a/libdiskfs/conch-fetch.c
+++ b/libdiskfs/conch-fetch.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -58,7 +58,7 @@ iohelp_fetch_shared_data (void *arg)
cred->po->np->dn_set_mtime = 1;
mod = 1;
}
- if (cred->mapped->accessed)
+ if (cred->mapped->accessed && ! _diskfs_noatime)
{
cred->po->np->dn_set_atime = 1;
mod = 1;
diff --git a/libdiskfs/console.c b/libdiskfs/console.c
index 885f527e..a4c3a1af 100644
--- a/libdiskfs/console.c
+++ b/libdiskfs/console.c
@@ -1,8 +1,7 @@
/* Redirect stdio to the console if possible
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,98,99,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -31,24 +30,35 @@
#include <device/device.h>
#include <hurd.h>
-/* Make errors go somewhere reasonable. */
+#include "priv.h"
+
+/* Make sure errors go somewhere reasonable. */
void
diskfs_console_stdio ()
{
if (getpid () > 0)
{
- int fd = open ("/dev/console", O_RDWR);
+ if (write (2, "", 0) == 0)
+ /* We have a working stderr from our parent (e.g. settrans -a).
+ Just use it. */
+ dup2 (2, 1);
+ else
+ {
+ int fd = open ("/dev/console", O_RDWR);
- dup2 (fd, 0);
- dup2 (fd, 1);
- dup2 (fd, 2);
- if (fd > 2)
- close (fd);
+ dup2 (fd, 0);
+ dup2 (fd, 1);
+ dup2 (fd, 2);
+ if (fd > 2)
+ close (fd);
+ }
}
else
{
mach_port_t dev, cons;
error_t err;
+ if (diskfs_boot_filesystem ())
+ _diskfs_boot_privports ();
err = get_privileged_ports (NULL, &dev);
assert_perror (err);
err = device_open (dev, D_READ|D_WRITE, "console", &cons);
diff --git a/libdiskfs/dev-globals.c b/libdiskfs/dev-globals.c
deleted file mode 100644
index c32b6a59..00000000
--- a/libdiskfs/dev-globals.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Standard device global variables
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <diskfs.h>
-
-/* A mach device port for the device we're using. */
-mach_port_t diskfs_device = MACH_PORT_NULL;
-
-/* The mach device name of DISKFS_DEVICE. May be 0 if unknown. */
-char *diskfs_device_name = 0;
-
-/* The first valid block of DISKFS_DEVICE, in units of
- DISKFS_DEVICE_BLOCK_SIZE. */
-off_t diskfs_device_start = 0;
-
-/* The usable size of DISKFS_DEVICE, in units of DISKFS_DEVICE_BLOCK_SIZE. */
-off_t diskfs_device_size = 0;
-
-/* The unit of addressing for DISKFS_DEVICE. */
-unsigned diskfs_device_block_size = 0;
-
-/* Some handy calculations based on DISKFS_DEVICE_BLOCK_SIZE. */
-/* Log base 2 of DEVICE_BLOCK_SIZE, or 0 if it's not a power of two. */
-unsigned diskfs_log2_device_block_size = 0;
-/* Log base 2 of the number of device blocks in a vm page, or 0 if it's not a
- power of two. */
-unsigned diskfs_log2_device_blocks_per_page = 0;
diff --git a/libdiskfs/dev-io.c b/libdiskfs/dev-io.c
deleted file mode 100644
index 9d0ed9d0..00000000
--- a/libdiskfs/dev-io.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Device input and output
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <device/device.h>
-#include <device/device_request.h>
-
-#include <diskfs.h>
-
-/* Write disk block ADDR with DATA of LEN bytes to DISKFS_DEVICE, waiting for
- completion. ADDR is offset by DISKFS_DEVICE_START. If an error occurs,
- EIO is returned. */
-error_t
-diskfs_device_write_sync (off_t addr, vm_address_t data, size_t len)
-{
- int written;
- assert (!diskfs_readonly);
- if (device_write (diskfs_device, 0, diskfs_device_start + addr,
- (io_buf_ptr_t) data, len, &written)
- || written != len)
- return EIO;
- return 0;
-}
-
-/* Read disk block ADDR from DISKFS_DEVICE; put the address of the data in
- DATA; read LEN bytes. Always *DATA should be a full page no matter what.
- ADDR is offset by DISKFS_DEVICE_START. If an error occurs, EIO is
- returned. */
-error_t
-diskfs_device_read_sync (off_t addr, vm_address_t *data, size_t len)
-{
- unsigned read;
- if (device_read (diskfs_device, 0, diskfs_device_start + addr, len,
- (io_buf_ptr_t *)data, &read)
- || read != len)
- return EIO;
- return 0;
-}
-
diff --git a/libdiskfs/dev-open.c b/libdiskfs/dev-open.c
deleted file mode 100644
index 5b45c30e..00000000
--- a/libdiskfs/dev-open.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Standard device opening
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <diskfs.h>
-
-/* Uses the values of DISKFS_DEVICE_ARG and DISKFS_USE_MACH_DEVICE, and
- attempts to open the device and set the values of DISKFS_DEVICE,
- DISKFS_DEVICE_NAME, DISKFS_DEVICE_START, DISKFS_DEVICE_SIZE, and
- DISKFS_DEVICE_BLOCK_SIZE. */
-error_t
-diskfs_device_open ()
-{
- error_t err;
- if (diskfs_use_mach_device)
- {
- diskfs_device_name = diskfs_device_arg;
- err =
- diskfs_get_mach_device (diskfs_device_name, &diskfs_device,
- &diskfs_device_start, &diskfs_device_size,
- &diskfs_device_block_size);
- }
- else
- err =
- diskfs_get_file_device (diskfs_device_arg,
- &diskfs_device_name, &diskfs_device,
- &diskfs_device_start, &diskfs_device_size,
- &diskfs_device_block_size);
-
- if (! err)
- {
- diskfs_log2_device_block_size = 0;
- while ((1 << diskfs_log2_device_block_size) < diskfs_device_block_size)
- diskfs_log2_device_block_size++;
- while ((1 << diskfs_log2_device_block_size) != diskfs_device_block_size)
- diskfs_log2_device_block_size = 0;
-
- diskfs_log2_device_blocks_per_page = 0;
- while ((diskfs_device_block_size << diskfs_log2_device_blocks_per_page)
- < vm_page_size)
- diskfs_log2_device_blocks_per_page++;
- if ((diskfs_device_block_size << diskfs_log2_device_blocks_per_page)
- != vm_page_size)
- diskfs_log2_device_blocks_per_page = 0;
- }
-
- return err;
-}
diff --git a/libdiskfs/dir-chg.c b/libdiskfs/dir-chg.c
index 42dfb161..7ca34447 100644
--- a/libdiskfs/dir-chg.c
+++ b/libdiskfs/dir-chg.c
@@ -1,5 +1,5 @@
/* Notifications of directory changes.
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1998, 2001 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
@@ -17,40 +17,66 @@
#include "priv.h"
#include "fs_S.h"
-#include "ourfs_notify_U.h"
+#include "fs_notify_U.h"
kern_return_t
diskfs_S_dir_notice_changes (struct protid *cred,
mach_port_t notify)
{
- struct dirmod *req;
+ error_t err;
+ struct modreq *req;
struct node *np;
-
+
if (!cred)
return EOPNOTSUPP;
np = cred->po->np;
- req = malloc (sizeof (struct dirmod));
mutex_lock (&np->lock);
if (!S_ISDIR (np->dn_stat.st_mode))
{
mutex_unlock (&np->lock);
return ENOTDIR;
}
+ err = dir_changed (notify, np->dirmod_tick, DIR_CHANGED_NULL, "");
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ return err;
+ }
+ req = malloc (sizeof (struct modreq));
+ if (! req)
+ {
+ mutex_unlock (&np->lock);
+ return ENOMEM;
+ }
req->port = notify;
req->next = np->dirmod_reqs;
np->dirmod_reqs = req;
- nowait_dir_changed (notify, DIR_CHANGED_NULL, "");
mutex_unlock (&np->lock);
return 0;
}
void
diskfs_notice_dirchange (struct node *dp, enum dir_changed_type type,
- char *name)
+ const char *name)
{
- struct dirmod *req;
-
- for (req = dp->dirmod_reqs; req; req = req->next)
- nowait_dir_changed (req->port, type, name);
-}
+ error_t err;
+ struct modreq **preq;
+
+ dp->dirmod_tick++;
+ preq = &dp->dirmod_reqs;
+ while (*preq)
+ {
+ struct modreq *req = *preq;
+ err = dir_changed (req->port, dp->dirmod_tick, type, name);
+ if (err && err != MACH_SEND_TIMED_OUT)
+ {
+ /* Remove notify port. */
+ *preq = req->next;
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ else
+ preq = &req->next;
+ }
+}
diff --git a/libdiskfs/dir-clear.c b/libdiskfs/dir-clear.c
index 4cb300e2..7cf32358 100644
--- a/libdiskfs/dir-clear.c
+++ b/libdiskfs/dir-clear.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
diff --git a/libdiskfs/dir-init.c b/libdiskfs/dir-init.c
index 67dc34eb..2cba3a4b 100644
--- a/libdiskfs/dir-init.c
+++ b/libdiskfs/dir-init.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -28,10 +28,12 @@ diskfs_init_dir (struct node *dp, struct node *pdp, struct protid *cred)
struct dirstat *ds = alloca (diskfs_dirstat_size);
struct node *foo;
error_t err;
+
+ /* Fabricate a protid that represents root credentials. */
static uid_t zero = 0;
- static struct protid lookupcred = {{0, 0, 0, 0},
- &zero, &zero, 1, 1,
- 0, 0};
+ static struct idvec vec = {&zero, 1, 1};
+ static struct iouser user = {&vec, &vec, 0};
+ struct protid lookupcred = {{0, 0, 0, 0}, &user, cred->po, 0, 0};
/* New links */
if (pdp->dn_stat.st_nlink == diskfs_link_max - 1)
diff --git a/libdiskfs/dir-link.c b/libdiskfs/dir-link.c
index 27928d05..7cc88633 100644
--- a/libdiskfs/dir-link.c
+++ b/libdiskfs/dir-link.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: dir_link
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97,99 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
@@ -31,16 +31,16 @@ diskfs_S_dir_link (struct protid *dircred,
struct dirstat *ds = alloca (diskfs_dirstat_size);
error_t error;
- if (!filecred)
+ if (!dircred)
return EOPNOTSUPP;
-
- np = filecred->po->np;
+
if (diskfs_check_readonly ())
return EROFS;
-
- if (!dircred)
+
+ if (!filecred)
return EXDEV;
-
+
+ np = filecred->po->np;
mutex_lock (&np->lock);
if (S_ISDIR (np->dn_stat.st_mode))
{
@@ -48,7 +48,7 @@ diskfs_S_dir_link (struct protid *dircred,
return EISDIR;
}
mutex_unlock (&np->lock);
-
+
dnp = dircred->po->np;
mutex_lock (&dnp->lock);
@@ -61,6 +61,8 @@ diskfs_S_dir_link (struct protid *dircred,
}
if (error && error != ENOENT)
{
+ if (error == EAGAIN)
+ error = EINVAL;
diskfs_drop_dirstat (dnp, ds);
mutex_unlock (&dnp->lock);
return error;
@@ -74,7 +76,7 @@ diskfs_S_dir_link (struct protid *dircred,
mach_port_deallocate (mach_task_self (), filecred->pi.port_right);
return 0;
}
-
+
if (tnp && S_ISDIR (tnp->dn_stat.st_mode))
{
diskfs_drop_dirstat (dnp, ds);
@@ -82,13 +84,13 @@ diskfs_S_dir_link (struct protid *dircred,
mutex_unlock (&tnp->lock);
return EISDIR;
}
-
+
/* Create new entry for NP */
/* This is safe because NP is not a directory (thus not DNP) and
not TNP and is a leaf. */
mutex_lock (&np->lock);
-
+
/* Increment link count */
if (np->dn_stat.st_nlink == diskfs_link_max - 1)
{
@@ -100,7 +102,7 @@ diskfs_S_dir_link (struct protid *dircred,
np->dn_stat.st_nlink++;
np->dn_set_ctime = 1;
diskfs_node_update (np, 1);
-
+
/* Attach it */
if (tnp)
{
@@ -118,10 +120,10 @@ diskfs_S_dir_link (struct protid *dircred,
}
else
error = diskfs_direnter (dnp, name, np, ds, dircred);
-
+
if (diskfs_synchronous)
diskfs_node_update (dnp, 1);
-
+
mutex_unlock (&dnp->lock);
mutex_unlock (&np->lock);
if (!error)
diff --git a/libdiskfs/dir-lookup.c b/libdiskfs/dir-lookup.c
index c8138254..7e092908 100644
--- a/libdiskfs/dir-lookup.c
+++ b/libdiskfs/dir-lookup.c
@@ -1,5 +1,6 @@
/* libdiskfs implementation of fs.defs:dir_lookup
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 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
@@ -15,16 +16,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "priv.h"
-#include "fs_S.h"
+#include <stdio.h>
#include <fcntl.h>
#include <string.h>
+#include <sys/file.h>
#include <hurd/fsys.h>
#include <hurd/paths.h>
-/* XXX - Temporary hack; this belongs in a header file, probably types.h. */
-#define major(x) ((int)(((unsigned) (x) >> 8) & 0xff))
-#define minor(x) ((int)((x) & 0xff))
+#include "priv.h"
+#include "fs_S.h"
/* Implement dir_lookup as described in <hurd/fs.defs>. */
kern_return_t
@@ -51,15 +51,16 @@ diskfs_S_dir_lookup (struct protid *dircred,
int newnode = 0;
struct dirstat *ds = 0;
int mustbedir = 0;
- int amt;
+ size_t amt;
int type;
- struct protid *newpi;
+ struct protid *newpi = 0;
+ struct peropen *newpo = 0;
if (!dircred)
return EOPNOTSUPP;
flags &= O_HURD;
-
+
create = (flags & O_CREAT);
excl = (flags & O_EXCL);
@@ -73,8 +74,6 @@ diskfs_S_dir_lookup (struct protid *dircred,
if (path[0] == '\0')
{
- mustbedir = 1;
-
/* Set things up in the state expected by the code from gotit: on. */
dnp = 0;
np = dircred->po->np;
@@ -84,6 +83,7 @@ diskfs_S_dir_lookup (struct protid *dircred,
}
dnp = dircred->po->np;
+
mutex_lock (&dnp->lock);
np = 0;
@@ -92,7 +92,7 @@ diskfs_S_dir_lookup (struct protid *dircred,
do
{
assert (!lastcomp);
-
+
/* Find the name of the next pathname component */
nextname = index (path, '/');
@@ -114,14 +114,14 @@ diskfs_S_dir_lookup (struct protid *dircred,
}
else
lastcomp = 1;
-
+
np = 0;
/* diskfs_lookup the next pathname component */
if (lastcomp && create)
{
- assert (!ds);
- ds = alloca (diskfs_dirstat_size);
+ if (!ds)
+ ds = alloca (diskfs_dirstat_size);
error = diskfs_lookup (dnp, path, CREATE, &np, ds, dircred);
}
else
@@ -133,10 +133,37 @@ diskfs_S_dir_lookup (struct protid *dircred,
/* If we get an error we're done */
if (error == EAGAIN)
{
- if (dircred->po->dotdotport != MACH_PORT_NULL)
+ if (dnp == dircred->po->shadow_root)
+ /* We're at the root of a shadow tree. */
+ {
+ if (dircred->po->shadow_root_parent == MACH_PORT_NULL)
+ {
+ /* This is a shadow root with no parent, meaning
+ we should treat it as a virtual root disconnected
+ from its real .. directory. */
+ error = 0;
+ np = dnp;
+ diskfs_nref (np);
+ }
+ else
+ {
+ /* Punt the client up to the shadow root parent. */
+ *retry = FS_RETRY_REAUTH;
+ *returned_port = dircred->po->shadow_root_parent;
+ *returned_port_poly = MACH_MSG_TYPE_COPY_SEND;
+ if (! lastcomp)
+ strcpy (retryname, nextname);
+ error = 0;
+ goto out;
+ }
+ }
+ else if (dircred->po->root_parent != MACH_PORT_NULL)
+ /* We're at a real translator root; even if DIRCRED->po has a
+ shadow root, we can get here if its in a directory that was
+ renamed out from under it... */
{
*retry = FS_RETRY_REAUTH;
- *returned_port = dircred->po->dotdotport;
+ *returned_port = dircred->po->root_parent;
*returned_port_poly = MACH_MSG_TYPE_COPY_SEND;
if (!lastcomp)
strcpy (retryname, nextname);
@@ -144,6 +171,7 @@ diskfs_S_dir_lookup (struct protid *dircred,
goto out;
}
else
+ /* We're at a REAL root, as in there's no way up from here. */
{
error = 0;
np = dnp;
@@ -156,7 +184,7 @@ diskfs_S_dir_lookup (struct protid *dircred,
{
if (error == ENOENT)
{
- mode &= ~(S_IFMT | S_ISPARE | S_ISVTX);
+ mode &= ~(S_IFMT | S_ISPARE | S_ISVTX | S_ITRANS);
mode |= S_IFREG;
error = diskfs_create_node (dnp, path, mode, &np, dircred, ds);
if (diskfs_synchronous)
@@ -169,26 +197,27 @@ diskfs_S_dir_lookup (struct protid *dircred,
else
diskfs_drop_dirstat (dnp, ds);
}
-
+
if (error)
goto out;
/* If this is translated, start the translator (if necessary)
and return. */
if ((((flags & O_NOTRANS) == 0) || !lastcomp)
- && (np->istranslated
+ && ((np->dn_stat.st_mode & S_IPTRANS)
|| S_ISFIFO (np->dn_stat.st_mode)
|| S_ISCHR (np->dn_stat.st_mode)
|| S_ISBLK (np->dn_stat.st_mode)
|| fshelp_translated (&np->transbox)))
{
mach_port_t dirport;
-
+ struct iouser *user;
+
/* A callback function for short-circuited translators.
Symlink & ifsock are handled elsewhere. */
error_t short_circuited_callback1 (void *cookie1, void *cookie2,
uid_t *uid, gid_t *gid,
- char **argz, int *argz_len)
+ char **argz, size_t *argz_len)
{
struct node *node = cookie1;
@@ -221,25 +250,33 @@ diskfs_S_dir_lookup (struct protid *dircred,
/* Create an unauthenticated port for DNP, and then
unlock it. */
- error =
- diskfs_create_protid (diskfs_make_peropen (dnp, 0,
- dircred->po->dotdotport),
- 0, 0, 0, 0, &newpi);
+ error = iohelp_create_empty_iouser (&user);
+ if (! error)
+ {
+ error = diskfs_make_peropen (dnp, 0, dircred->po, &newpo);
+ if (! error)
+ {
+ error = diskfs_create_protid (newpo, user, &newpi);
+ if (! error)
+ newpo = 0;
+ }
+
+ iohelp_free_iouser (user);
+ }
+
if (error)
goto out;
- dirport = ports_get_right (newpi);
- mach_port_insert_right (mach_task_self (), dirport, dirport,
- MACH_MSG_TYPE_MAKE_SEND);
+ dirport = ports_get_send_right (newpi);
ports_port_deref (newpi);
+ newpi = 0;
if (np != dnp)
mutex_unlock (&dnp->lock);
- error = fshelp_fetch_root (&np->transbox, &dircred->po->dotdotport,
- dirport, dircred->uids, dircred->nuids,
- dircred->gids, dircred->ngids,
+ error = fshelp_fetch_root (&np->transbox, dircred->po,
+ dirport, dircred->user,
lastcomp ? flags : 0,
- (np->istranslated
+ ((np->dn_stat.st_mode & S_IPTRANS)
? _diskfs_translator_callback1
: short_circuited_callback1),
_diskfs_translator_callback2,
@@ -256,8 +293,9 @@ diskfs_S_dir_lookup (struct protid *dircred,
*returned_port_poly = MACH_MSG_TYPE_MOVE_SEND;
if (!lastcomp && !error)
{
- strcat (retryname, "/");
- strcat (retryname, nextname);
+ char *end = strchr (retryname, '\0');
+ *end++ = '/';
+ strcpy (end, nextname);
}
return error;
}
@@ -278,9 +316,11 @@ diskfs_S_dir_lookup (struct protid *dircred,
}
}
}
-
+
if (S_ISLNK (np->dn_stat.st_mode)
- && !(lastcomp && (flags & (O_NOLINK|O_NOTRANS))))
+ && (!lastcomp
+ || mustbedir /* "foo/" must see that foo points to a dir */
+ || !(flags & (O_NOLINK|O_NOTRANS))))
{
/* Handle symlink interpretation */
@@ -289,51 +329,70 @@ diskfs_S_dir_lookup (struct protid *dircred,
error = ELOOP;
goto out;
}
-
+
nextnamelen = nextname ? strlen (nextname) + 1 : 0;
- newnamelen = nextnamelen + np->dn_stat.st_size + 1;
+ newnamelen = nextnamelen + np->dn_stat.st_size + 1 + 1;
if (pathbuflen < newnamelen)
{
pathbuf = alloca (newnamelen);
pathbuflen = newnamelen;
}
-
+
if (diskfs_read_symlink_hook)
error = (*diskfs_read_symlink_hook)(np, pathbuf);
if (!diskfs_read_symlink_hook || error == EINVAL)
- error = diskfs_node_rdwr (np, pathbuf,
- 0, np->dn_stat.st_size, 0,
- dircred, &amt);
- if (error)
- goto out;
-
- if (nextname)
{
- pathbuf[np->dn_stat.st_size] = '/';
- bcopy (nextname, pathbuf + np->dn_stat.st_size + 1,
- nextnamelen - 1);
+ error = diskfs_node_rdwr (np, pathbuf,
+ 0, np->dn_stat.st_size, 0,
+ dircred, &amt);
+ if (!error)
+ assert (amt == np->dn_stat.st_size);
}
- pathbuf[nextnamelen + np->dn_stat.st_size] = '\0';
+ if (error)
+ goto out;
- if (pathbuf[0] == '/')
+ if (np->dn_stat.st_size == 0) /* symlink to "" */
+ path = nextname;
+ else
{
- /* Punt to the caller. */
- *retry = FS_RETRY_MAGICAL;
- *returned_port = MACH_PORT_NULL;
- strcpy (retryname, pathbuf);
- goto out;
+ if (nextname)
+ {
+ pathbuf[np->dn_stat.st_size] = '/';
+ memcpy (pathbuf + np->dn_stat.st_size + 1,
+ nextname, nextnamelen - 1);
+ }
+ pathbuf[nextnamelen + np->dn_stat.st_size] = '\0';
+
+ if (pathbuf[0] == '/')
+ {
+ /* Punt to the caller. */
+ *retry = FS_RETRY_MAGICAL;
+ *returned_port = MACH_PORT_NULL;
+ memcpy (retryname, pathbuf,
+ nextnamelen + np->dn_stat.st_size + 1);
+ if (mustbedir)
+ {
+ retryname[nextnamelen + np->dn_stat.st_size] = '/';
+ retryname[nextnamelen + np->dn_stat.st_size + 1] = '\0';
+ }
+ goto out;
+ }
+
+ path = pathbuf;
}
-
- path = pathbuf;
+
if (lastcomp)
- {
- lastcomp = 0;
- /* Symlinks to nonexistent files aren't allowed to cause
- creation, so clear the flag here. */
- create = 0;
- }
+ lastcomp = 0;
+
diskfs_nput (np);
np = 0;
+
+ if (path == 0) /* symlink to "" was the last component */
+ {
+ np = dnp;
+ dnp = 0;
+ break;
+ }
}
else
{
@@ -352,7 +411,7 @@ diskfs_S_dir_lookup (struct protid *dircred,
dnp = 0;
}
} while (path && *path);
-
+
/* At this point, np is the node to return. If newnode is set, then
we just created this node. */
@@ -364,20 +423,21 @@ diskfs_S_dir_lookup (struct protid *dircred,
error = ENOTDIR;
goto out;
}
-
+
if (!newnode)
/* Check permissions on existing nodes, but not new ones. */
{
- if ((type == S_IFSOCK || type == S_IFBLK || type == S_IFLNK
- || type == S_IFCHR || type == S_IFIFO)
- && (flags & (O_READ|O_WRITE|O_EXEC)))
- error = EOPNOTSUPP;
+ if (((type == S_IFSOCK || type == S_IFBLK || type == S_IFCHR ||
+ type == S_IFIFO)
+ && (flags & (O_READ|O_WRITE|O_EXEC)))
+ || (type == S_IFLNK && (flags & (O_WRITE|O_EXEC))))
+ error = EACCES;
if (!error && (flags & O_READ))
- error = diskfs_access (np, S_IREAD, dircred);
+ error = fshelp_access (&np->dn_stat, S_IREAD, dircred->user);
if (!error && (flags & O_EXEC))
- error = diskfs_access (np, S_IEXEC, dircred);
+ error = fshelp_access (&np->dn_stat, S_IEXEC, dircred->user);
if (!error && (flags & O_WRITE))
{
@@ -386,29 +446,41 @@ diskfs_S_dir_lookup (struct protid *dircred,
else if (diskfs_check_readonly ())
error = EROFS;
else
- error = diskfs_access (np, S_IWRITE, dircred);
+ error = fshelp_access (&np->dn_stat, S_IWRITE, dircred->user);
}
if (error)
goto out;
}
-
- if ((flags & O_NOATIME) && (diskfs_isowner (np, dircred) == EPERM))
+
+ if ((flags & O_NOATIME)
+ && (fshelp_isowner (&np->dn_stat, dircred->user) == EPERM))
flags &= ~O_NOATIME;
- flags &= ~OPENONLY_STATE_MODES;
-
- error = diskfs_create_protid (diskfs_make_peropen (np, flags,
- dircred->po->dotdotport),
- dircred->uids, dircred->nuids,
- dircred->gids, dircred->ngids,
- &newpi);
+ error = diskfs_make_peropen (np, (flags &~OPENONLY_STATE_MODES),
+ dircred->po, &newpo);
+
+ if (! error)
+ error = diskfs_create_protid (newpo, dircred->user, &newpi);
+
+ if (! error)
+ {
+ newpo = 0;
+ if (flags & O_EXLOCK)
+ error = fshelp_acquire_lock (&np->userlock, &newpi->po->lock_status,
+ &np->lock, LOCK_EX);
+ else if (flags & O_SHLOCK)
+ error = fshelp_acquire_lock (&np->userlock, &newpi->po->lock_status,
+ &np->lock, LOCK_SH);
+ }
+
if (! error)
{
*returned_port = ports_get_right (newpi);
ports_port_deref (newpi);
+ newpi = 0;
}
-
+
out:
if (np)
{
@@ -419,5 +491,11 @@ diskfs_S_dir_lookup (struct protid *dircred,
}
if (dnp)
diskfs_nput (dnp);
+
+ if (newpi)
+ ports_port_deref (newpi);
+ if (newpo)
+ diskfs_release_peropen (newpo);
+
return error;
}
diff --git a/libdiskfs/dir-mkdir.c b/libdiskfs/dir-mkdir.c
index 89477755..30d7a3b4 100644
--- a/libdiskfs/dir-mkdir.c
+++ b/libdiskfs/dir-mkdir.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: dir_mkdir
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97,2002 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
@@ -31,7 +31,7 @@ diskfs_S_dir_mkdir (struct protid *dircred,
if (!dircred)
return EOPNOTSUPP;
-
+
dnp = dircred->po->np;
if (diskfs_check_readonly ())
return EROFS;
@@ -39,7 +39,6 @@ diskfs_S_dir_mkdir (struct protid *dircred,
mutex_lock (&dnp->lock);
error = diskfs_lookup (dnp, name, CREATE, 0, ds, dircred);
-
if (error == EAGAIN)
error = EEXIST;
if (!error)
@@ -52,7 +51,7 @@ diskfs_S_dir_mkdir (struct protid *dircred,
return error;
}
- mode &= ~(S_ISPARE | S_IFMT);
+ mode &= ~(S_ISPARE | S_IFMT | S_ITRANS);
mode |= S_IFDIR;
error = diskfs_create_node (dnp, name, mode, &np, dircred, ds);
diff --git a/libdiskfs/dir-mkfile.c b/libdiskfs/dir-mkfile.c
index cdfe6e31..914b18fe 100644
--- a/libdiskfs/dir-mkfile.c
+++ b/libdiskfs/dir-mkfile.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/* libdiskfs implementation of fs.defs: dir_mkfile
+ Copyright (C) 1994,95,96,97,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -34,7 +34,8 @@ diskfs_S_dir_mkfile (struct protid *cred,
struct node *dnp, *np;
error_t err;
struct protid *newpi;
-
+ struct peropen *newpo;
+
if (!cred)
return EOPNOTSUPP;
if (diskfs_check_readonly ())
@@ -46,14 +47,14 @@ diskfs_S_dir_mkfile (struct protid *cred,
mutex_unlock (&dnp->lock);
return ENOTDIR;
}
- err = diskfs_access (dnp, S_IWRITE, cred);
+ err = fshelp_access (&dnp->dn_stat, S_IWRITE, cred->user);
if (err)
{
mutex_unlock (&dnp->lock);
return err;
}
-
- mode &= ~(S_IFMT | S_ISPARE | S_ISVTX);
+
+ mode &= ~(S_IFMT | S_ISPARE | S_ISVTX | S_ITRANS);
mode |= S_IFREG;
err = diskfs_create_node (dnp, 0, mode, &np, cred, 0);
mutex_unlock (&dnp->lock);
@@ -66,13 +67,17 @@ diskfs_S_dir_mkfile (struct protid *cred,
if (err)
return err;
-
- flags &= (O_READ | O_WRITE | O_EXEC);
- err = diskfs_create_protid (diskfs_make_peropen (np, flags,
- cred->po->dotdotport),
- cred->uids, cred->nuids,
- cred->gids, cred->ngids,
- &newpi);
+
+ flags &= ~OPENONLY_STATE_MODES; /* These bits are all meaningless here. */
+
+ err = diskfs_make_peropen (np, flags, cred->po, &newpo);
+ if (! err)
+ {
+ err = diskfs_create_protid (newpo, cred->user, &newpi);
+ if (err)
+ diskfs_release_peropen (newpo);
+ }
+
if (! err)
{
*newnode = ports_get_right (newpi);
@@ -84,5 +89,3 @@ diskfs_S_dir_mkfile (struct protid *cred,
return err;
}
-
-
diff --git a/libdiskfs/dir-readdir.c b/libdiskfs/dir-readdir.c
index c66b2dce..d2f9d750 100644
--- a/libdiskfs/dir-readdir.c
+++ b/libdiskfs/dir-readdir.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1993,94,96,99,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -26,7 +26,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
kern_return_t
diskfs_S_dir_readdir (struct protid *cred,
char **data,
- u_int *datacnt,
+ size_t *datacnt,
+ boolean_t *data_dealloc,
int entry,
int nentries,
vm_size_t bufsiz,
@@ -54,8 +55,7 @@ diskfs_S_dir_readdir (struct protid *cred,
}
err = diskfs_get_directs (np, entry, nentries, data, datacnt, bufsiz, amt);
+ *data_dealloc = 1; /* XXX */
mutex_unlock (&np->lock);
return err;
}
-
-
diff --git a/libdiskfs/dir-rename.c b/libdiskfs/dir-rename.c
index 7e993def..867e395d 100644
--- a/libdiskfs/dir-rename.c
+++ b/libdiskfs/dir-rename.c
@@ -1,5 +1,7 @@
/* libdiskfs implementation of fs.defs: dir_rename
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 2007
+ Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,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
@@ -39,7 +42,15 @@ diskfs_S_dir_rename (struct protid *fromcred,
return EOPNOTSUPP;
/* Verify that tocred really is a port to us. */
- if (!tocred)
+ 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;
if (diskfs_check_readonly ())
@@ -55,6 +66,8 @@ diskfs_S_dir_rename (struct protid *fromcred,
mutex_lock (&fdp->lock);
err = diskfs_lookup (fdp, fromname, LOOKUP, &fnp, 0, fromcred);
mutex_unlock (&fdp->lock);
+ if (err == EAGAIN)
+ err = EINVAL;
if (err)
return err;
@@ -100,7 +113,9 @@ diskfs_S_dir_rename (struct protid *fromcred,
mutex_lock (&tdp->lock);
err = diskfs_lookup (tdp, toname, RENAME, &tnp, ds, tocred);
- if (!err && excl)
+ if (err == EAGAIN)
+ err = EINVAL;
+ else if (!err && excl)
{
err = EEXIST;
diskfs_nput (tnp);
@@ -130,6 +145,7 @@ diskfs_S_dir_rename (struct protid *fromcred,
{
diskfs_drop_dirstat (tdp, ds);
diskfs_nrele (fnp);
+ diskfs_nput (tnp);
mutex_unlock (&tdp->lock);
return EISDIR;
}
@@ -141,6 +157,8 @@ diskfs_S_dir_rename (struct protid *fromcred,
{
diskfs_drop_dirstat (tdp, ds);
diskfs_nput (fnp);
+ if (tnp)
+ diskfs_nput (tnp);
mutex_unlock (&tdp->lock);
return EMLINK;
}
diff --git a/libdiskfs/dir-renamed.c b/libdiskfs/dir-renamed.c
index 6ef96ee3..79381b2c 100644
--- a/libdiskfs/dir-renamed.c
+++ b/libdiskfs/dir-renamed.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,95,96,97,98,99,2001,2003 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
@@ -31,8 +31,7 @@ checkpath(struct node *source,
{
error_t err;
struct node *np;
-
- np = target;
+
for (np = target, err = 0;
/* nothing */;
/* This special lookup does a diskfs_nput on its first argument
@@ -44,20 +43,20 @@ checkpath(struct node *source,
diskfs_nput (np);
return err;
}
-
+
if (np == source)
{
diskfs_nput (np);
return EINVAL;
}
-
+
if (np == diskfs_root_node)
{
diskfs_nput (np);
return 0;
}
}
-}
+}
/* Rename directory node FNP (whose parent is FDP, and which has name
FROMNAME in that directory) to have name TONAME inside directory
@@ -67,9 +66,9 @@ checkpath(struct node *source,
routine. FROMCRED and TOCRED are the users responsible for
FDP/FNP and TDP respectively. */
error_t
-diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
- struct node *tdp, char *toname, struct protid *fromcred,
- struct protid *tocred)
+diskfs_rename_dir (struct node *fdp, struct node *fnp, const char *fromname,
+ struct node *tdp, const char *toname,
+ struct protid *fromcred, struct protid *tocred)
{
error_t err;
struct node *tnp, *tmpnp;
@@ -81,32 +80,40 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
diskfs_nref (tdp); /* reference and lock will get consumed by
checkpath */
err = checkpath (fnp, tdp, tocred);
-
+
if (err)
return err;
-
+
/* Now, lock the parent directories. This is legal because tdp is not
a child of fnp (guaranteed by checkpath above). */
mutex_lock (&fdp->lock);
if (fdp != tdp)
mutex_lock (&tdp->lock);
-
+
/* 1: Lookup target; if it exists, make sure it's an empty directory. */
ds = buf;
err = diskfs_lookup (tdp, toname, RENAME, &tnp, ds, tocred);
-
+ assert (err != EAGAIN); /* <-> assert (TONAME != "..") */
+
if (tnp == fnp)
{
diskfs_drop_dirstat (tdp, ds);
- diskfs_nrele (tnp);
+ diskfs_nput (tnp);
mutex_unlock (&tdp->lock);
if (fdp != tdp)
mutex_unlock (&fdp->lock);
return 0;
}
-
- /* Now we can safely lock fnp */
- mutex_lock (&fnp->lock);
+
+ /* Check permissions to remove FROMNAME and lock FNP. */
+ tmpds = alloca (diskfs_dirstat_size);
+ err = diskfs_lookup (fdp, fromname, REMOVE, &tmpnp, tmpds, fromcred);
+ assert (!tmpnp || tmpnp == fnp);
+ if (tmpnp)
+ diskfs_nrele (tmpnp);
+ diskfs_drop_dirstat (fdp, tmpds);
+ if (err)
+ goto out;
if (tnp)
{
@@ -114,7 +121,7 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
err = ENOTDIR;
else if (!diskfs_dirempty (tnp, tocred))
err = ENOTEMPTY;
- }
+ }
if (err && err != ENOENT)
goto out;
@@ -131,24 +138,24 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
tdp->dn_set_ctime = 1;
if (diskfs_synchronous)
diskfs_node_update (tdp, 1);
-
+
tmpds = alloca (diskfs_dirstat_size);
- err = diskfs_lookup (fnp, "..", RENAME | SPEC_DOTDOT,
+ err = diskfs_lookup (fnp, "..", RENAME | SPEC_DOTDOT,
&tmpnp, tmpds, fromcred);
assert (err != ENOENT);
- assert (tmpnp == fdp);
if (err)
{
diskfs_drop_dirstat (fnp, tmpds);
goto out;
}
+ assert (tmpnp == fdp);
err = diskfs_dirrewrite (fnp, fdp, tdp, "..", tmpds);
if (diskfs_synchronous)
diskfs_file_update (fnp, 1);
if (err)
goto out;
-
+
fdp->dn_stat.st_nlink--;
fdp->dn_set_ctime = 1;
if (diskfs_synchronous)
@@ -170,7 +177,7 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
fnp->dn_stat.st_nlink++;
fnp->dn_set_ctime = 1;
diskfs_node_update (fnp, 1);
-
+
if (tnp)
{
err = diskfs_dirrewrite (tdp, tnp, fnp, toname, ds);
@@ -198,11 +205,12 @@ diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
ds = buf;
mutex_unlock (&fnp->lock);
err = diskfs_lookup (fdp, fromname, REMOVE, &tmpnp, ds, fromcred);
- assert (tmpnp == fnp);
- diskfs_nrele (tmpnp);
+ assert (!tmpnp || tmpnp == fnp);
+ if (tmpnp)
+ diskfs_nrele (tmpnp);
if (err)
goto out;
-
+
diskfs_dirremove (fdp, fnp, fromname, ds);
ds = 0;
fnp->dn_stat.st_nlink--;
diff --git a/libdiskfs/dir-rmdir.c b/libdiskfs/dir-rmdir.c
index 70c87d03..a90ff07b 100644
--- a/libdiskfs/dir-rmdir.c
+++ b/libdiskfs/dir-rmdir.c
@@ -1,5 +1,5 @@
/* libdsikfs implementation of fs.defs: dir_rmdir
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97,99 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
@@ -25,13 +25,27 @@ diskfs_S_dir_rmdir (struct protid *dircred,
char *name)
{
struct node *dnp;
- struct node *np = 0;
+ struct node *np;
struct dirstat *ds = alloca (diskfs_dirstat_size);
error_t error;
+ /* This routine cleans up the state we have after calling diskfs_lookup.
+ After that call, all returns are done with `return done (ERROR, NP);'. */
+ inline error_t done (error_t error, struct node *np)
+ {
+ if (np)
+ diskfs_nput (np);
+
+ if (ds)
+ diskfs_drop_dirstat (dnp, ds);
+ mutex_unlock (&dnp->lock);
+
+ return error;
+ }
+
if (!dircred)
return EOPNOTSUPP;
-
+
dnp = dircred->po->np;
if (diskfs_check_readonly ())
return EROFS;
@@ -39,44 +53,32 @@ diskfs_S_dir_rmdir (struct protid *dircred,
mutex_lock (&dnp->lock);
error = diskfs_lookup (dnp, name, REMOVE, &np, ds, dircred);
- if (error == EAGAIN)
- error = ENOTEMPTY;
if (error)
- {
- mutex_unlock (&dnp->lock);
- diskfs_drop_dirstat (dnp, ds);
- return error;
- }
+ return done (error == EAGAIN ? ENOTEMPTY : error, 0);
- /* Attempt to rmdir(".") */
if (dnp == np)
{
+ /* Attempt to rmdir(".") */
diskfs_nrele (np);
diskfs_drop_dirstat (dnp, ds);
mutex_unlock (&dnp->lock);
return EINVAL;
}
- if (np->istranslated || fshelp_translated (&np->transbox))
- {
- diskfs_drop_dirstat (dnp, ds);
- diskfs_nput (np);
- mutex_unlock (&dnp->lock);
- return EBUSY;
- }
+ if ((np->dn_stat.st_mode & S_IPTRANS) || fshelp_translated (&np->transbox))
+ /* Attempt to rmdir a translated node. */
+ return done (EBUSY, np);
+
+ if (!S_ISDIR (np->dn_stat.st_mode))
+ return done (ENOTDIR, np);
- /* Verify the directory is empty (and valid). (Rmdir ".." won't be
- valid since ".." will contain a reference to the current directory and
- thus be non-empty). */
if (!diskfs_dirempty (np, dircred))
- {
- diskfs_nput (np);
- diskfs_drop_dirstat (dnp, ds);
- mutex_unlock (&dnp->lock);
- return ENOTEMPTY;
- }
+ return done (ENOTEMPTY, np);
+ /* Here we go! */
error = diskfs_dirremove (dnp, np, name, ds);
+ ds = 0;
+
if (!error)
{
np->dn_stat.st_nlink--;
@@ -88,7 +90,5 @@ diskfs_S_dir_rmdir (struct protid *dircred,
if (diskfs_synchronous)
diskfs_file_update (dnp, 1);
- diskfs_nput (np);
- mutex_unlock (&dnp->lock);
- return 0;
+ return done (error, np);
}
diff --git a/libdiskfs/dir-unlink.c b/libdiskfs/dir-unlink.c
index 34fe0b67..e40aead5 100644
--- a/libdiskfs/dir-unlink.c
+++ b/libdiskfs/dir-unlink.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: dir_unlink
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,97,2002 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
@@ -32,7 +32,7 @@ diskfs_S_dir_unlink (struct protid *dircred,
if (!dircred)
return EOPNOTSUPP;
-
+
dnp = dircred->po->np;
if (diskfs_check_readonly ())
return EROFS;
@@ -41,14 +41,14 @@ diskfs_S_dir_unlink (struct protid *dircred,
error = diskfs_lookup (dnp, name, REMOVE, &np, ds, dircred);
if (error == EAGAIN)
- error = EISDIR;
+ error = EPERM; /* 1003.1-1996 5.5.1.4 */
if (error)
{
diskfs_drop_dirstat (dnp, ds);
mutex_unlock (&dnp->lock);
return error;
}
-
+
/* This isn't the BSD behavior, but it is Posix compliant and saves
us on several race conditions.*/
if (S_ISDIR(np->dn_stat.st_mode))
@@ -59,9 +59,9 @@ diskfs_S_dir_unlink (struct protid *dircred,
diskfs_nput (np);
diskfs_drop_dirstat (dnp, ds);
mutex_unlock (&dnp->lock);
- return EISDIR;
+ return EPERM; /* 1003.1-1996 5.5.1.4 */
}
-
+
error = diskfs_dirremove (dnp, np, name, ds);
if (diskfs_synchronous)
diskfs_node_update (dnp, 1);
@@ -71,7 +71,7 @@ diskfs_S_dir_unlink (struct protid *dircred,
mutex_unlock (&dnp->lock);
return error;
}
-
+
np->dn_stat.st_nlink--;
np->dn_set_ctime = 1;
if (diskfs_synchronous)
@@ -80,10 +80,10 @@ diskfs_S_dir_unlink (struct protid *dircred,
if (np->dn_stat.st_nlink == 0)
fshelp_fetch_control (&np->transbox, &control);
- /* This check is necessary because we might get here on an error while
+ /* This check is necessary because we might get here on an error while
checking the mode on something which happens to be `.'. */
if (np == dnp)
- diskfs_nrele (np);
+ diskfs_nrele (np);
else
diskfs_nput (np);
mutex_unlock (&dnp->lock);
diff --git a/libdiskfs/direnter.c b/libdiskfs/direnter.c
index ca0006eb..cb9b76ca 100644
--- a/libdiskfs/direnter.c
+++ b/libdiskfs/direnter.c
@@ -1,5 +1,5 @@
/* Wrapper for diskfs_direnter_hard
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -29,13 +29,13 @@
growth). This function is a wrapper for diskfs_direnter_hard. */
error_t
diskfs_direnter (struct node *dp,
- char *name,
+ const char *name,
struct node *np,
struct dirstat *ds,
struct protid *cred)
{
error_t err;
-
+
err = diskfs_direnter_hard (dp, name, np, ds, cred);
if (err)
return err;
@@ -45,5 +45,4 @@ diskfs_direnter (struct node *dp,
diskfs_enter_lookup_cache (dp, np, name);
return 0;
-}
-
+}
diff --git a/libdiskfs/dirremove.c b/libdiskfs/dirremove.c
index 8970d19a..239daa72 100644
--- a/libdiskfs/dirremove.c
+++ b/libdiskfs/dirremove.c
@@ -1,5 +1,5 @@
/* Wrapper for diskfs_dirremove_hard
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -27,20 +27,19 @@
call diskfs_notice_dirchange if DP->dirmod_reqs is nonzero. This
function is a wrapper for diskfs_dirremove_hard. The entry being
removed has name NAME and refers to NP. */
-error_t
-diskfs_dirremove (struct node *dp,
- struct node *np,
- char *name,
+error_t
+diskfs_dirremove (struct node *dp,
+ struct node *np,
+ const char *name,
struct dirstat *ds)
{
error_t err;
-
+
diskfs_purge_lookup_cache (dp, np);
-
+
err = diskfs_dirremove_hard (dp, ds);
-
+
if (!err && dp->dirmod_reqs)
diskfs_notice_dirchange (dp, DIR_CHANGED_UNLINK, name);
return err;
}
-
diff --git a/libdiskfs/dirrewrite.c b/libdiskfs/dirrewrite.c
index b2e750f5..8f713960 100644
--- a/libdiskfs/dirrewrite.c
+++ b/libdiskfs/dirrewrite.c
@@ -1,5 +1,5 @@
/* Wrapper for diskfs_dirrewrite_hard
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -29,23 +29,22 @@
diskfs_notice_dirchange if DP->dirmod_reqs is nonzero. NAME is the
name of OLDNP inside DP; it is this reference which is being
rewritten. This function is a wrapper for diskfs_dirrewrite_hard. */
-error_t diskfs_dirrewrite (struct node *dp,
+error_t diskfs_dirrewrite (struct node *dp,
struct node *oldnp,
struct node *np,
- char *name,
+ const char *name,
struct dirstat *ds)
{
error_t err;
-
+
diskfs_purge_lookup_cache (dp, oldnp);
-
+
err = diskfs_dirrewrite_hard (dp, np, ds);
if (err)
return err;
-
+
if (dp->dirmod_reqs)
diskfs_notice_dirchange (dp, DIR_CHANGED_RENUMBER, name);
diskfs_enter_lookup_cache (dp, np, name);
return 0;
}
-
diff --git a/libdiskfs/disk-pager.c b/libdiskfs/disk-pager.c
index 9ae2a2a5..fefd2ef4 100644
--- a/libdiskfs/disk-pager.c
+++ b/libdiskfs/disk-pager.c
@@ -1,5 +1,5 @@
/* Map the disk image and handle faults accessing it.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,99,2001,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This program is free software; you can redistribute it and/or
@@ -21,56 +21,53 @@
#include <hurd/sigpreempt.h>
#include <error.h>
-struct pager *disk_pager;
-void *disk_image;
-extern struct port_bucket *pager_bucket;
+struct pager *diskfs_disk_pager;
static void fault_handler (int sig, long int sigcode, struct sigcontext *scp);
-static struct hurd_signal_preempter preempter =
+static struct hurd_signal_preemptor preemptor =
{
signals: sigmask (SIGSEGV) | sigmask (SIGBUS),
- preempter: NULL,
+ preemptor: NULL,
handler: (sighandler_t) &fault_handler,
};
-
/* A top-level function for the paging thread that just services paging
requests. */
static void
-service_paging_requests (any_t foo __attribute__ ((unused)))
+service_paging_requests (any_t arg)
{
+ struct port_bucket *pager_bucket = arg;
for (;;)
- ports_manage_port_operations_multithread (pager_bucket, pager_demuxer,
- 1000 * 60 * 2, 1000 * 60 * 10,
- 1, MACH_PORT_NULL);
+ ports_manage_port_operations_multithread (pager_bucket,
+ pager_demuxer,
+ 1000 * 60 * 2,
+ 1000 * 60 * 10, 0);
}
void
-disk_pager_setup (struct user_pager_info *upi, int may_cache)
+diskfs_start_disk_pager (struct user_pager_info *upi,
+ struct port_bucket *pager_bucket, int may_cache,
+ size_t size, void **image)
{
error_t err;
mach_port_t disk_pager_port;
- if (! pager_bucket)
- pager_bucket = ports_create_bucket ();
-
/* Make a thread to service paging requests. */
cthread_detach (cthread_fork ((cthread_fn_t) service_paging_requests,
- (any_t) 0));
+ (any_t)pager_bucket));
/* Create the pager. */
- disk_pager = pager_create (upi, pager_bucket,
- may_cache, MEMORY_OBJECT_COPY_NONE);
- assert (disk_pager);
+ diskfs_disk_pager = pager_create (upi, pager_bucket,
+ may_cache, MEMORY_OBJECT_COPY_NONE);
+ assert (diskfs_disk_pager);
/* Get a port to the disk pager. */
- disk_pager_port = pager_get_port (disk_pager);
+ disk_pager_port = pager_get_port (diskfs_disk_pager);
mach_port_insert_right (mach_task_self (), disk_pager_port, disk_pager_port,
MACH_MSG_TYPE_MAKE_SEND);
/* Now map the disk image. */
- err = vm_map (mach_task_self (), (vm_address_t *)&disk_image,
- diskfs_device_size << diskfs_log2_device_block_size,
+ err = vm_map (mach_task_self (), (vm_address_t *)image, size,
0, 1, disk_pager_port, 0, 0,
VM_PROT_READ | (diskfs_readonly ? 0 : VM_PROT_WRITE),
VM_PROT_READ | VM_PROT_WRITE,
@@ -78,11 +75,10 @@ disk_pager_setup (struct user_pager_info *upi, int may_cache)
if (err)
error (2, err, "cannot vm_map whole disk");
- /* Set up the signal preempter to catch faults on the disk image. */
- preempter.first = (vm_address_t) disk_image;
- preempter.last = ((vm_address_t) disk_image +
- (diskfs_device_size << diskfs_log2_device_block_size));
- hurd_preempt_signals (&preempter);
+ /* Set up the signal preemptor to catch faults on the disk image. */
+ preemptor.first = (vm_address_t) *image;
+ preemptor.last = ((vm_address_t) *image + size);
+ hurd_preempt_signals (&preemptor);
/* We have the mapping; we no longer need the send right. */
mach_port_deallocate (mach_task_self (), disk_pager_port);
@@ -94,14 +90,28 @@ fault_handler (int sig, long int sigcode, struct sigcontext *scp)
jmp_buf *env = cthread_data (cthread_self ());
error_t err;
- assert (env && "unexpected fault on disk image");
+#ifndef NDEBUG
+ if (!env)
+ {
+ error (0, 0,
+ "BUG: unexpected fault on disk image (%d, %#lx) in [%#lx,%#lx)"
+ " eip %#zx err %#x",
+ sig, sigcode,
+ preemptor.first, preemptor.last,
+ scp->sc_pc, scp->sc_error);
+ assert (scp->sc_error == EKERN_MEMORY_ERROR);
+ err = pager_get_error (diskfs_disk_pager, sigcode);
+ assert (err);
+ assert_perror (err);
+ }
+#endif
/* Clear the record, since the faulting thread will not. */
cthread_set_data (cthread_self (), 0);
/* Fetch the error code from the pager. */
assert (scp->sc_error == EKERN_MEMORY_ERROR);
- err = pager_get_error (disk_pager, sigcode);
+ err = pager_get_error (diskfs_disk_pager, sigcode);
assert (err);
/* Make `diskfault_catch' return the error code. */
diff --git a/libdiskfs/diskfs-pager.h b/libdiskfs/diskfs-pager.h
index a7d20c9d..4ec0b27b 100644
--- a/libdiskfs/diskfs-pager.h
+++ b/libdiskfs/diskfs-pager.h
@@ -1,5 +1,5 @@
/* Map the disk image and handle faults accessing it.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Written by Roland McGrath.
This program is free software; you can redistribute it and/or
@@ -18,6 +18,7 @@
#ifndef _HURD_DISKFS_PAGER_H
#define _HURD_DISKFS_PAGER_H 1
+
#include <hurd/pager.h>
#include <hurd/ports.h>
#include <setjmp.h>
@@ -26,15 +27,16 @@
#include <assert.h>
#include <stdlib.h>
+/* Start a pager for the whole disk, and store it in DISKFS_DISK_PAGER,
+ preparing a signal preemptor so that the `diskfs_catch_exception' macro
+ below works. SIZE should be the size of the image to map, and the address
+ 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,
+ size_t size, void **image);
-/* Set up the three variables below and prepare a signal preempter
- so that the `diskfs_catch_exception' macro below works.
- INFO and MAY_CACHE are passed to `pager_create'. */
-extern void disk_pager_setup (struct user_pager_info *info, int may_cache);
-
-extern struct port_bucket *pager_bucket; /* Ports bucket used by pagers. */
-extern struct pager *disk_pager; /* Pager backing to the disk. */
-extern void *disk_image; /* Region mapping entire disk from it. */
+extern struct pager *diskfs_disk_pager;
struct disk_image_user
{
diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h
index 8cada32f..2051e41d 100644
--- a/libdiskfs/diskfs.h
+++ b/libdiskfs/diskfs.h
@@ -1,5 +1,7 @@
/* Definitions for fileserver helper functions
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2007, 2008,
+ 2009 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
@@ -18,13 +20,20 @@
#ifndef _HURD_DISKFS
#define _HURD_DISKFS
-#include <argp.h>
#include <assert.h>
#include <unistd.h>
#include <rwlock.h>
#include <hurd/ports.h>
#include <hurd/fshelp.h>
#include <hurd/iohelp.h>
+#include <idvec.h>
+#include <features.h>
+
+#ifdef DISKFS_DEFINE_EXTERN_INLINE
+#define DISKFS_EXTERN_INLINE
+#else
+#define DISKFS_EXTERN_INLINE __extern_inline
+#endif
/* Each user port referring to a file points to one of these
(with the aid of the ports library). */
@@ -33,8 +42,7 @@ struct protid
struct port_info pi; /* libports info block */
/* User identification */
- uid_t *uids, *gids;
- int nuids, ngids;
+ struct iouser *user;
/* Object this refers to */
struct peropen *po;
@@ -44,15 +52,23 @@ struct protid
struct shared_io *mapped;
};
-/* One of these is created for each node opened by dir_pathtrans. */
+/* One of these is created for each node opened by dir_lookup. */
struct peropen
{
int filepointer;
int lock_status;
int refcnt;
int openstat;
- mach_port_t dotdotport; /* dotdot from ROOT through this peropen */
+
struct node *np;
+
+ /* The parent of the translator's root node. */
+ mach_port_t root_parent;
+
+ /* If this node is in a shadow tree, the parent of its root. */
+ mach_port_t shadow_root_parent;
+ /* If in a shadow tree, its root node in this translator. */
+ struct node *shadow_root;
};
/* A unique one of these exists for each node currently in use (and
@@ -64,12 +80,11 @@ struct node
struct disknode *dn;
- struct stat dn_stat;
- int istranslated;
+ io_statbuf_t dn_stat;
/* Stat has been modified if one of the following four fields
is nonzero. Also, if one of the dn_set_?time fields is nonzero,
- the appropriate dn_stat.st_?time field needs to be updated. */
+ the appropriate dn_stat.st_?tim field needs to be updated. */
int dn_set_ctime;
int dn_set_atime;
int dn_set_mtime;
@@ -90,11 +105,17 @@ struct node
struct conch conch;
- struct dirmod *dirmod_reqs;
+ struct modreq *dirmod_reqs;
+ unsigned int dirmod_tick;
- off_t allocsize;
+ struct modreq *filemod_reqs;
+ unsigned int filemod_tick;
- int cache_id;
+ loff_t allocsize;
+
+ ino64_t cache_id;
+
+ int author_tracks_uid;
};
/* Possibly lookup types for diskfs_lookup call */
@@ -106,23 +127,25 @@ enum lookup_type
RENAME,
};
-/* Pending directory modification request */
-struct dirmod
+/* Pending directory and file modification request */
+struct modreq
{
mach_port_t port;
- struct dirmod *next;
+ struct modreq *next;
};
/* Special flag for diskfs_lookup. */
#define SPEC_DOTDOT 0x10000000
+struct argp; /* opaque in this file */
+struct argp_child; /* opaque in this file */
+struct store; /* opaque in this file */
+struct store_parsed; /* opaque in this file */
/* Declarations of variables the library sets. */
extern mach_port_t diskfs_default_pager; /* send right */
-extern mach_port_t diskfs_exec_ctl; /* send right */
-extern mach_port_t diskfs_exec; /* send right */
extern auth_t diskfs_auth_server_port; /* send right */
/* The io_identity identity port for the filesystem. */
@@ -133,10 +156,20 @@ extern mach_port_t diskfs_fsys_identity;
file systems, to give the procserver. */
extern char **diskfs_argv;
-/* When this is a bootstrap filesystem, the command line options passed from
- the kernel. If not a bootstrap filesystem, it is 0, so it can be used to
- distinguish between the two cases. */
-extern char *diskfs_boot_flags;
+/* When this is a bootstrap filesystem, the multiboot kernel command
+ line passed from the kernel. If not a bootstrap filesystem, it is
+ 0. As such, it can be used to distinguish between the two cases.
+ Note: this is only valid after the arguments have been parsed by,
+ for example, diskfs_init_main. */
+extern const char *diskfs_boot_command_line;
+#define diskfs_boot_filesystem() (diskfs_boot_command_line != 0)
+
+/* When this is a bootstrap filesystem, nonzero if starting each bootstrap
+ program should pause for a keystroke, for debugging purposes. */
+extern int _diskfs_boot_pause;
+
+/* Name of the init program run when this is a bootstrap filesystem. */
+extern const char *diskfs_boot_init_program;
/* Hold this lock while do fsys level operations. Innocuous users can just
hold a reader lock, and anyone who's going to do nasty things that would
@@ -155,6 +188,9 @@ extern spin_lock_t diskfs_node_refcnt_lock;
extern int pager_port_type;
+/* Whether the filesystem is currently writable or not. */
+extern int diskfs_readonly;
+
struct pager;
@@ -178,7 +214,7 @@ struct dirstat;
/* The user must define this variable; it should be the size in bytes
of a struct dirstat. */
-extern size_t diskfs_dirstat_size;
+extern const size_t diskfs_dirstat_size;
/* The user must define this variable; it is the maximum number of
links to any one file. The implementation of dir_rename does not know
@@ -186,14 +222,20 @@ extern size_t diskfs_dirstat_size;
reimplement dir_rename yourself. */
extern int diskfs_link_max;
+/* The user must define this variable; it is the maximum length of
+ a single pathname component (i.e. file name within directory).
+ The filesystem code does not use this for anything, but it is
+ returned to user queries for _PC_NAME_MAX. */
+extern int diskfs_name_max;
+
/* The user must define this variable; it is the maximum number of
- symlinks to be traversed within a single call to dir_pathtrans.
- If this is exceeded, dir_pathtrans will return ELOOP. */
+ symlinks to be traversed within a single call to dir_lookup.
+ If this is exceeded, dir_lookup will return ELOOP. */
extern int diskfs_maxsymlinks;
-/* The user must define this variable and set it if the filesystem
- should be readonly. */
-extern int diskfs_readonly;
+/* This variable is defined by diskfs; the user should set it if
+ the filesystem media cannot be made writeable. */
+extern int diskfs_hard_readonly;
/* The user must define this variable. Set this to be the node
of root of the filesystem. */
@@ -203,11 +245,13 @@ extern struct node *diskfs_root_node;
filesystem server. */
extern char *diskfs_server_name;
-/* The user must define these variables. Set these to be the major, minor,
- and edit version numbers. */
-extern int diskfs_major_version;
-extern int diskfs_minor_version;
-extern int diskfs_edit_version;
+/* The user must define this variables. Set this to be the server
+ version number. */
+extern char *diskfs_server_version;
+
+/* The user may define this variable. Set this to be any additional
+ version specification that should be printed for --version. */
+extern char *diskfs_extra_version;
/* The user may define this variable. This should be nonzero iff the
filesystem format supports shortcutting symlink translation.
@@ -239,8 +283,17 @@ int diskfs_shortcut_ifsock;
thread is started up (in diskfs_spawn_first_threa). */
extern int diskfs_default_sync_interval;
+/* The user must define this variable, which should be a string that somehow
+ identifies the particular disk this filesystem is interpreting. It is
+ generally only used to print messages or to distinguish instances of the
+ same filesystem type from one another. If this filesystem accesses no
+ external media, then define this to be 0. */
+extern char *diskfs_disk_name;
+
/* The user must define this function. Set *STATFSBUF with
- appropriate values to reflect the current state of the filesystem. */
+ appropriate values to reflect the current state of the filesystem.
+ The buffer will be initialized to all zeros by the caller;
+ the caller will set f_namelen to diskfs_name_max. */
error_t diskfs_set_statfs (fsys_statfsbuf_t *statfsbuf);
/* The user must define this function. Lookup in directory DP (which
@@ -282,7 +335,8 @@ error_t diskfs_set_statfs (fsys_statfsbuf_t *statfsbuf);
Return EAGAIN if NAME refers to the `..' of this filesystem's root.
Return EIO if appropriate.
*/
-error_t diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
+error_t diskfs_lookup_hard (struct node *dp,
+ const char *name, enum lookup_type type,
struct node **np, struct dirstat *ds,
struct protid *cred);
@@ -292,7 +346,7 @@ error_t diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
has been locked continuously since that call and DS is as that call
set it, NP is locked. CRED identifies the user responsible
for the call (to be used only to validate directory growth). */
-error_t diskfs_direnter_hard (struct node *dp, char *name,
+error_t diskfs_direnter_hard (struct node *dp, const char *name,
struct node *np, struct dirstat *ds,
struct protid *cred);
@@ -331,7 +385,7 @@ error_t diskfs_drop_dirstat (struct node *dp, struct dirstat *ds);
then there is no limit on *DATACNT; if N is -1, then there is no limit
on AMT. */
error_t diskfs_get_directs (struct node *dp, int entry, int n,
- char **data, u_int *datacnt,
+ char **data, size_t *datacnt,
vm_size_t bufsiz, int *amt);
/* The user must define this function. For locked node NP (for which
@@ -343,7 +397,8 @@ error_t diskfs_get_translator (struct node *np, char **namep, u_int *namelen);
/* The user must define this function. For locked node NP, set
the name of the translating program to be NAME, length NAMELEN. CRED
identifies the user responsible for the call. */
-error_t diskfs_set_translator (struct node *np, char *name, u_int namelen,
+error_t diskfs_set_translator (struct node *np,
+ const char *name, u_int namelen,
struct protid *cred);
/* The user must define this function. Truncate locked node NP to be SIZE
@@ -351,20 +406,20 @@ error_t diskfs_set_translator (struct node *np, char *name, u_int namelen,
long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
is set) then this should clear the symlink, even if
diskfs_create_symlink_hook stores the link target elsewhere. */
-error_t diskfs_truncate (struct node *np, off_t size);
+error_t diskfs_truncate (struct node *np, loff_t size);
/* The user must define this function. Grow the disk allocated to locked node
NP to be at least SIZE bytes, and set NP->allocsize to the actual
allocated size. (If the allocated size is already SIZE bytes, do
nothing.) CRED identifies the user responsible for the call. */
-error_t diskfs_grow (struct node *np, off_t size, struct protid *cred);
+error_t diskfs_grow (struct node *np, loff_t size, struct protid *cred);
/* The user must define this function. Write to disk (synchronously
iff WAIT is nonzero) from format-specific buffers any non-paged
metadata. If CLEAN is nonzero, then after this is written the
filesystem will be absolutely clean, and the non-paged metadata can
so indicate. */
-void diskfs_set_hypermetadata (int wait, int clean);
+error_t diskfs_set_hypermetadata (int wait, int clean);
/* The user must define this function. Allocate a new node to be of
mode MODE in locked directory DP (don't actually set the mode or
@@ -462,7 +517,7 @@ void diskfs_shutdown_pager ();
/* The user must define this function. Return a memory object port (send
right) for the file contents of NP. PROT is the maximum allowable
- access. */
+ access. On errors, return MACH_PORT_NULL and set errno. */
mach_port_t diskfs_get_filemap (struct node *np, vm_prot_t prot);
/* The user must define this function. Return true if there are pager
@@ -502,7 +557,7 @@ error_t diskfs_node_reload (struct node *node);
is called to set a symlink. If it returns EINVAL or isn't set,
then the normal method (writing the contents into the file data) is
used. If it returns any other error, it is returned to the user. */
-error_t (*diskfs_create_symlink_hook)(struct node *np, char *target);
+error_t (*diskfs_create_symlink_hook)(struct node *np, const char *target);
/* If this function is nonzero (and diskfs_shortcut_symlink is set) it
is called to read the contents of a symlink. If it returns EINVAL or
@@ -512,33 +567,6 @@ error_t (*diskfs_read_symlink_hook)(struct node *np, char *target);
/* The library exports the following functions for general use */
-/* Returns the name and a send right for the mach device on which the file
- NAME is stored, and returns it in DEV_NAME (which is malloced) and PORT.
- Other values returned are START, the first valid offset, SIZE, the the
- number of blocks after START, and BLOCK_SIZE, the units in which the
- device is addressed.
-
- The device is opened for reading, and if the diskfs global variable
- DISKFS_READONLY is false, writing. */
-error_t diskfs_get_file_device (char *name,
- char **dev_name, mach_port_t *port,
- off_t *start, off_t *size, size_t *block_size);
-
-/* Returns a send right to for the mach device called NAME, and returns it in
- PORT. Other values returned are START, the first valid offset, SIZE, the
- the number of blocks after START, and BLOCK_SIZE, the units in which the
- device is addressed.
-
- The device is opened for reading, and if the diskfs global variable
- DISKFS_READ_ONLY is false, writing.
-
- If NAME cannot be opened and this is a bootstrap filesystem, the user will
- be prompted for new names until a valid one is found. */
-error_t diskfs_get_mach_device (char *name,
- mach_port_t *port,
- off_t *start, off_t *size, size_t *block_size);
-
-
/* Call this after arguments have been parsed to initialize the library.
You must call this before calling any other diskfs functions, and after
parsing diskfs options. */
@@ -553,8 +581,9 @@ mach_port_t diskfs_startup_diskfs (mach_port_t bootstrap, int flags);
/* Call this after all format-specific initialization is done (except
for setting diskfs_root_node); at this point the pagers should be
- ready to go. */
-void diskfs_spawn_first_thread (void);
+ ready to go. DEMUXER is the demuxer to user. Normally, this is
+ just diskfs_demuxer. */
+void diskfs_spawn_first_thread (ports_demuxer_type demuxer);
/* Once diskfs_root_node is set, call this if we are a bootstrap
filesystem. If you call this, then the library will call
@@ -574,240 +603,30 @@ void diskfs_node_update (struct node *np, int wait);
/* Add a hard reference to a node. If there were no hard
references previously, then the node cannot be locked
(because you must hold a hard reference to hold the lock). */
-extern inline void
-diskfs_nref (struct node *np)
-{
- int new_hardref;
- spin_lock (&diskfs_node_refcnt_lock);
- np->references++;
- new_hardref = (np->references == 1);
- spin_unlock (&diskfs_node_refcnt_lock);
- if (new_hardref)
- {
- mutex_lock (&np->lock);
- diskfs_new_hardrefs (np);
- mutex_unlock (&np->lock);
- }
-}
+void diskfs_nref (struct node *np);
/* Unlock node NP and release a hard reference; if this is the last
hard reference and there are no links to the file then request
soft references to be dropped. */
-extern inline void
-diskfs_nput (struct node *np)
-{
- int tried_drop_softrefs = 0;
-
- loop:
- spin_lock (&diskfs_node_refcnt_lock);
- assert (np->references);
- np->references--;
- if (np->references + np->light_references == 0)
- diskfs_drop_node (np);
- else if (np->references == 0 && !tried_drop_softrefs)
- {
- spin_unlock (&diskfs_node_refcnt_lock);
- diskfs_lost_hardrefs (np);
- if (!np->dn_stat.st_nlink)
- {
- /* There are no links. If there are soft references that
- can be dropped, we can't let them postpone deallocation.
- So attempt to drop them. But that's a user-supplied
- routine, which might result in further recursive calls to
- the ref-counting system. So we have to reacquire our
- reference around the call to forestall disaster. */
- spin_lock (&diskfs_node_refcnt_lock);
- np->references++;
- spin_unlock (&diskfs_node_refcnt_lock);
-
- diskfs_try_dropping_softrefs (np);
-
- /* But there's no value in looping forever in this
- routine; only try to drop soft refs once. */
- tried_drop_softrefs = 1;
-
- /* Now we can drop the reference back... */
- goto loop;
- }
- mutex_unlock (&np->lock);
- }
- else
- {
- spin_unlock (&diskfs_node_refcnt_lock);
- mutex_unlock (&np->lock);
- }
-}
+void diskfs_nput (struct node *np);
/* Release a hard reference on NP. If NP is locked by anyone, then
this cannot be the last hard reference (because you must hold a
hard reference in order to hold the lock). If this is the last
hard reference and there are no links, then request soft references
to be dropped. */
-extern inline void
-diskfs_nrele (struct node *np)
-{
- int tried_drop_softrefs = 0;
-
- loop:
- spin_lock (&diskfs_node_refcnt_lock);
- assert (np->references);
- np->references--;
- if (np->references + np->light_references == 0)
- {
- mutex_lock (&np->lock);
- diskfs_drop_node (np);
- }
- else if (np->references == 0)
- {
- mutex_lock (&np->lock);
- spin_unlock (&diskfs_node_refcnt_lock);
- diskfs_lost_hardrefs (np);
- if (!np->dn_stat.st_nlink && !tried_drop_softrefs)
- {
- /* Same issue here as in nput; see that for explanation */
- spin_lock (&diskfs_node_refcnt_lock);
- np->references++;
- spin_unlock (&diskfs_node_refcnt_lock);
-
- diskfs_try_dropping_softrefs (np);
- tried_drop_softrefs = 1;
-
- /* Now we can drop the reference back... */
- mutex_unlock (&np->lock);
- goto loop;
- }
- mutex_unlock (&np->lock);
- }
- else
- spin_unlock (&diskfs_node_refcnt_lock);
-}
+void diskfs_nrele (struct node *np);
/* Add a light reference to a node. */
-extern inline void
-diskfs_nref_light (struct node *np)
-{
- spin_lock (&diskfs_node_refcnt_lock);
- np->light_references++;
- spin_unlock (&diskfs_node_refcnt_lock);
-}
+void diskfs_nref_light (struct node *np);
/* Unlock node NP and release a light reference */
-extern inline void
-diskfs_nput_light (struct node *np)
-{
- spin_lock (&diskfs_node_refcnt_lock);
- assert (np->light_references);
- np->light_references--;
- if (np->references + np->light_references == 0)
- diskfs_drop_node (np);
- else
- {
- spin_unlock (&diskfs_node_refcnt_lock);
- mutex_unlock (&np->lock);
- }
-}
+void diskfs_nput_light (struct node *np);
/* Release a light reference on NP. If NP is locked by anyone, then
this cannot be the last reference (because you must hold a
hard reference in order to hold the lock). */
-extern inline void
-diskfs_nrele_light (struct node *np)
-{
- spin_lock (&diskfs_node_refcnt_lock);
- assert (np->light_references);
- np->light_references--;
- if (np->references + np->light_references == 0)
- {
- mutex_lock (&np->lock);
- diskfs_drop_node (np);
- }
- else
- spin_unlock (&diskfs_node_refcnt_lock);
-}
-
-/* Return nonzero iff the user identified by CRED has uid UID. */
-extern inline int
-diskfs_isuid (uid_t uid, struct protid *cred)
-{
- int i;
- for (i = 0; i < cred->nuids; i++)
- if (cred->uids[i] == uid)
- return 1;
- return 0;
-}
-
-/* Return nonzero iff the user identified by CRED has group GRP. */
-extern inline int
-diskfs_groupmember (uid_t grp, struct protid *cred)
-{
- int i;
- for (i = 0; i < cred->ngids; i++)
- if (cred->gids[i] == grp)
- return 1;
- return 0;
-}
-
-/* Check to see if the user identified by CRED is permitted to do
- owner-only operations on node NP; if so, return 0; if not, return
- EPERM. */
-extern inline error_t
-diskfs_isowner (struct node *np, struct protid *cred)
-{
- /* Permitted if the user is the owner, superuser, or if the user
- is in the group of the file and has the group ID as their user
- ID. (This last is colloquially known as `group leader'.) */
- if (diskfs_isuid (np->dn_stat.st_uid, cred) || diskfs_isuid (0, cred)
- || (diskfs_groupmember (np->dn_stat.st_gid, cred)
- && diskfs_isuid (np->dn_stat.st_gid, cred)))
- return 0;
- else
- return EPERM;
-}
-
-/* Check to see is the user identified by CRED is permitted to do
- operation OP on node NP. Op is one of S_IREAD, S_IWRITE, or S_IEXEC.
- Return 0 if the operation is permitted and EACCES if not. */
-extern inline error_t
-diskfs_access (struct node *np, int op, struct protid *cred)
-{
- int gotit;
- if (diskfs_isuid (0, cred))
- gotit = 1;
- else if (cred->nuids == 0 && (np->dn_stat.st_mode & S_IUSEUNK))
- gotit = np->dn_stat.st_mode & (op << S_IUNKSHIFT);
- else if (!diskfs_isowner (np, cred))
- gotit = np->dn_stat.st_mode & op;
- else if (diskfs_groupmember (np->dn_stat.st_gid, cred))
- gotit = np->dn_stat.st_mode & (op >> 3);
- else
- gotit = np->dn_stat.st_mode & (op >> 6);
- return gotit ? 0 : EACCES;
-}
-
-/* Check to see if the user identified by CRED is allowed to modify
- directory DP with respect to existing file NP. This is the same
- as diskfs_access (dp, S_IWRITE, cred), except when the directory
- has the sticky bit set. (If there is no existing file NP, then
- 0 can be passed.) */
-extern inline error_t
-diskfs_checkdirmod (struct node *dp, struct node *np,
- struct protid *cred)
-{
- error_t err;
-
- /* The user must be able to write the directory, but if the directory
- is sticky, then the user must also be either the owner of the directory
- or the file. */
- err = diskfs_access (dp, S_IWRITE, cred);
- if (err)
- return err;
-
- if ((dp->dn_stat.st_mode & S_ISVTX) && np && !diskfs_isuid (0, cred)
- && diskfs_isowner (dp, cred) && diskfs_isowner (np, cred))
- return EACCES;
-
- return 0;
-}
+void diskfs_nrele_light (struct node *np);
/* Reading and writing of files. this is called by other filesystem
routines and handles extension of files automatically. NP is the
@@ -819,7 +638,7 @@ diskfs_checkdirmod (struct node *dp, struct node *np,
extension). For reads, *AMTREAD is filled with the amount actually
read. */
error_t
-diskfs_node_rdwr (struct node *np, char *data, off_t off,
+diskfs_node_rdwr (struct node *np, char *data, loff_t off,
size_t amt, int dir, struct protid *cred,
size_t *amtread);
@@ -832,7 +651,15 @@ diskfs_node_rdwr (struct node *np, char *data, off_t off,
fully completed. */
void
diskfs_notice_dirchange (struct node *dp, enum dir_changed_type type,
- char *name);
+ const char *name);
+
+/* Send notifications to users who have requested them with
+ file_notice_changes for file NP. The type of modification is TYPE.
+ START and END identify the affected region of the file's data.
+ This should be called after the change is fully completed. */
+void
+diskfs_notice_filechange (struct node *np, enum file_changed_type type,
+ loff_t start, loff_t end);
/* Create a new node structure with DS as its physical disknode.
The new node will have one hard reference and no light references. */
@@ -846,6 +673,11 @@ struct node *diskfs_make_node (struct disknode *dn);
either be LOOKUP, CREATE, RENAME, or REMOVE. CRED identifies the
user making the call.
+ NAME will have leading and trailing slashes stripped. It is an
+ error if there are internal slashes. NAME will be modified in
+ place if there are slashes in it; it is therefore an error to
+ specify a constant NAME which contains slashes.
+
If the name is found, return zero, and (if NP is nonzero) set *NP
to point to the node for it, locked. If the name is not found,
return ENOENT, and (if NP is nonzero) set *NP to zero. If NP is
@@ -884,10 +716,11 @@ struct node *diskfs_make_node (struct disknode *dn);
Return ENOENT if NAME isn't in the directory.
Return EAGAIN if NAME refers to the `..' of this filesystem's root.
Return EIO if appropriate.
-
- This function is a wrapper for diskfs_lookup_hard.
+
+ This function is a wrapper for diskfs_lookup_hard.
*/
-error_t diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
+error_t diskfs_lookup (struct node *dp,
+ const char *name, enum lookup_type type,
struct node **np, struct dirstat *ds,
struct protid *cred);
@@ -898,7 +731,7 @@ error_t diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
responsible for the call (to be used only to validate directory
growth). This function is a wrapper for diskfs_direnter_hard. */
error_t
-diskfs_direnter (struct node *dp, char *name, struct node *np,
+diskfs_direnter (struct node *dp, const char *name, struct node *np,
struct dirstat *ds, struct protid *cred);
/* This will only be called after a successful call to diskfs_lookup
@@ -910,7 +743,8 @@ diskfs_direnter (struct node *dp, char *name, struct node *np,
name of OLDNP inside DP; it is this reference which is being
rewritten. This function is a wrapper for diskfs_dirrewrite_hard. */
error_t diskfs_dirrewrite (struct node *dp, struct node *oldnp,
- struct node *np, char *name, struct dirstat *ds);
+ struct node *np, const char *name,
+ struct dirstat *ds);
/* This will only be called after a successful call to diskfs_lookup
of type REMOVE; this call should remove the name found from the
@@ -920,10 +754,10 @@ error_t diskfs_dirrewrite (struct node *dp, struct node *oldnp,
function is a wrapper for diskfs_dirremove_hard. The entry being
removed has name NAME and refers to NP. */
error_t diskfs_dirremove (struct node *dp, struct node *np,
- char *name, struct dirstat *ds);
+ const char *name, struct dirstat *ds);
/* Return the node corresponding to CACHE_ID in *NPP. */
-error_t diskfs_cached_lookup (int cache_id, struct node **npp);
+error_t diskfs_cached_lookup (ino64_t cache_id, struct node **npp);
/* Create a new node. Give it MODE; if that includes IFDIR, also
initialize `.' and `..' in the new directory. Return the node in NPP.
@@ -933,29 +767,49 @@ error_t diskfs_cached_lookup (int cache_id, struct node **npp);
DIR must always be provided as at least a hint for disk allocation
strategies. */
error_t
-diskfs_create_node (struct node *dir, char *name, mode_t mode,
+diskfs_create_node (struct node *dir, const char *name, mode_t mode,
struct node **newnode, struct protid *cred,
struct dirstat *ds);
-/* Create and return a protid for an existing peropen PO in CRED. The uid
- set is UID (length NUIDS); the gid set is GID (length NGIDS). The node
- PO->np must be locked. */
-error_t diskfs_create_protid (struct peropen *po, uid_t *uids, int nuids,
- uid_t *gids, int ngids, struct protid **cred);
+/* Create and return a protid for an existing peropen PO in CRED,
+ referring to user USER. The node PO->np must be locked. */
+error_t diskfs_create_protid (struct peropen *po, struct iouser *user,
+ struct protid **cred);
/* Build and return in CRED a protid which has no user identification, for
peropen PO. The node PO->np must be locked. */
error_t diskfs_start_protid (struct peropen *po, struct protid **cred);
/* Finish building protid CRED started with diskfs_start_protid;
- the uid set is UID (length NUIDS); the gid set is GID (length NGIDS). */
-void diskfs_finish_protid (struct protid *cred, uid_t *uids, int nuids,
- gid_t *gids, int nguds);
+ the user to install is USER. */
+void diskfs_finish_protid (struct protid *cred, struct iouser *user);
-/* Create and return a new peropen structure on node NP with open
- flags FLAGS. */
-struct peropen *diskfs_make_peropen (struct node *np, int flags,
- mach_port_t dotdotnode);
+extern struct protid * diskfs_begin_using_protid_port (file_t port);
+
+extern void diskfs_end_using_protid_port (struct protid *cred);
+
+#if defined(__USE_EXTERN_INLINES) || defined(DISKFS_DEFINE_EXTERN_INLINE)
+
+/* 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 *
+diskfs_begin_using_protid_port (file_t port)
+{
+ return ports_lookup_port (diskfs_port_bucket, port, diskfs_protid_class);
+}
+
+/* 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
+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
@@ -963,14 +817,23 @@ struct peropen *diskfs_make_peropen (struct node *np, int flags,
free the structure for us. */
void diskfs_protid_rele (void *arg);
+/* Create a new peropen structure on node NP with open flags FLAGS in
+ *PPO. The initial values for the root_parent, shadow_root, and
+ shadow_root_parent fields are copied from CONTEXT if it's non-zero,
+ otherwise they are zeroed. */
+error_t
+diskfs_make_peropen (struct node *np, int flags,
+ struct peropen *context, struct peropen **ppo);
+
/* Decrement the reference count on a peropen structure. */
void diskfs_release_peropen (struct peropen *po);
/* Node NP has just been found in DIR with NAME. If NP is null, that
means that this name has been confirmed as absent in the directory. */
-void diskfs_enter_lookup_cache (struct node *dir, struct node *np, char *name);
+void diskfs_enter_lookup_cache (struct node *dir, struct node *np,
+ const char *name);
-/* Purge all references in the cache to NP as a node inside
+/* Purge all references in the cache to NP as a node inside
directory DP. */
void diskfs_purge_lookup_cache (struct node *dp, struct node *np);
@@ -978,7 +841,7 @@ void diskfs_purge_lookup_cache (struct node *dp, struct node *np);
anything entry at all, then return 0. If the entry is confirmed to
not exist, then return -1. Otherwise, return NP for the entry, with
a newly allocated reference. */
-struct node *diskfs_check_lookup_cache (struct node *dir, char *name);
+struct node *diskfs_check_lookup_cache (struct node *dir, const char *name);
/* Rename directory node FNP (whose parent is FDP, and which has name
FROMNAME in that directory) to have name TONAME inside directory
@@ -991,9 +854,9 @@ struct node *diskfs_check_lookup_cache (struct node *dir, char *name);
if that is not true for your format, you have to redefine this
function.*/
error_t
-diskfs_rename_dir (struct node *fdp, struct node *fnp, char *fromname,
- struct node *tdp, char *toname, struct protid *fromcred,
- struct protid *tocred);
+diskfs_rename_dir (struct node *fdp, struct node *fnp, const char *fromname,
+ struct node *tdp, const char *toname,
+ struct protid *fromcred, struct protid *tocred);
/* Clear the `.' and `..' entries from directory DP. Its parent is
PDP, and the user responsible for this is identified by CRED. Both
@@ -1014,11 +877,15 @@ error_t diskfs_clear_directory (struct node *dp, struct node *pdp,
error_t
diskfs_init_dir (struct node *dp, struct node *pdp, struct protid *cred);
-/* If NP->dn_set_ctime is set, then modify NP->dn_stat.st_ctime
+/* If disk is not readonly and the noatime option is not enabled, set
+ NP->dn_set_atime. */
+void diskfs_set_node_atime (struct node *np);
+
+/* If NP->dn_set_ctime is set, then modify NP->dn_stat.st_ctim
appropriately; do the analogous operation for atime and mtime as well. */
void diskfs_set_node_times (struct node *np);
-/* Shutdown the filesystem; flags are as for fsys_shutdown. */
+/* Shutdown the filesystem; flags are as for fsys_goaway. */
error_t diskfs_shutdown (int flags);
/* Change an active filesystem between read-only and writable modes, setting
@@ -1049,14 +916,12 @@ error_t diskfs_set_sync_interval (int interval);
/* Parse and execute the runtime options in ARGZ & ARGZ_LEN. EINVAL is
returned if some option is unrecognized. The default definition of this
routine will parse them using DISKFS_RUNTIME_ARGP, which see. */
-error_t diskfs_set_options (char *argz, size_t argz_len);
+error_t diskfs_set_options (const char *argz, size_t argz_len);
-/* Return an argz string describing the current options. Fill *ARGZ
- with a pointer to newly malloced storage holding the list and *LEN
- to the length of that storage. The default definition of this routine
- simply initializes *ARGZ and *ARGZ_LEN to 0 and calls
- diskfs_append_std_options. */
-error_t diskfs_get_options (char **argz, unsigned *argz_len);
+/* Append to the malloced string *ARGZ of length *ARGZ_LEN a NUL-separated
+ list of the arguments to this translator. The default definition of this
+ routine simply calls diskfs_append_std_options. */
+error_t diskfs_append_args (char **argz, size_t *argz_len);
/* If this is defined or set to an argp structure, it will be used by the
default diskfs_set_options to handle runtime option parsing. The default
@@ -1071,12 +936,19 @@ extern const struct argp diskfs_std_runtime_argp;
/* An argp structure for the standard diskfs command line arguments. The
user may call argp_parse on this to parse the command line, chain it onto
the end of his own argp structure, or ignore it completely. */
-extern const struct argp diskfs_std_startup_argp;
+extern const struct argp diskfs_startup_argp;
+
+/* An argp structure for the standard diskfs command line arguments plus a
+ store specification. The address of a location in which to return the
+ resulting struct store_parsed structure should be passed as the input
+ argument to argp_parse; see the declaration for STORE_ARGP in
+ <hurd/store.h> for more information. */
+extern const struct argp diskfs_store_startup_argp;
/* *Appends* to ARGZ & ARGZ_LEN '\0'-separated options describing the standard
diskfs option state (note that unlike diskfs_get_options, ARGZ & ARGZ_LEN
must already have a sane value). */
-error_t diskfs_append_std_options (char **argz, unsigned *argz_len);
+error_t diskfs_append_std_options (char **argz, size_t *argz_len);
/* Demultiplex incoming messages on ports created by libdiskfs. */
int diskfs_demuxer (mach_msg_header_t *, mach_msg_header_t *);
@@ -1089,67 +961,33 @@ int diskfs_check_readonly (void);
fsys, interrupt, and notify interfaces. All the server routines
have the prefix `diskfs_S_'; `in' arguments of type file_t or io_t
appear as `struct protid *' to the stub. */
+
+
+/* All-in-one initialization function for diskfs filesystems using
+ libstore. This parses arguments using STARTUP_ARGP (defaulting to
+ diskfs_store_startup_argp if it's null; note that the ARGP_IN_ORDER
+ flag is always used); it calls diskfs_init_diskfs; it opens the
+ store with store_parsed_open, and sets diskfs_hard_readonly and
+ diskfs_readonly if the store is unwritable; it calls
+ diskfs_spawn_first_thread; finally, it returns the store and its
+ description in *STORE and *STORE_PARSED, and the bootstrap port in
+ *BOOTSTRAP. The caller should pass *BOOTSTRAP to
+ diskfs_startup_diskfs after setting diskfs_root_node.
+ (See <argp.h> and <hurd/store.h>.)
+
+ This call cannot return failure; if it encounters a fatal problem,
+ it prints a diagnostic on stderr (or the console) and exits the
+ program. */
+struct store *diskfs_init_main (struct argp *startup_argp,
+ int argc, char **argv,
+ struct store_parsed **store_parsed,
+ mach_port_t *bootstrap);
/* The following are optional convenience routines and global variable, which
can be used by any user program that uses a mach device to hold the
underlying filesystem. */
-/* A pointer to an argp structure for the standard diskfs command line
- arguments, that also parses a device argument. The user may call
- argp_parse on this to parse the command line, chain it onto the end of his
- own argp structure, or ignore it completely. */
-extern const struct argp diskfs_std_device_startup_argp;
-
-/* The following two are set by the preceding argument parser: */
-/* The device specifier given on the command line. */
-extern char *diskfs_device_arg;
-/* True if --machdev was specified, meaning that DISKFS_DEVICE_ARG names a
- mach device and not a filesystem device node. */
-extern int diskfs_use_mach_device;
-
-/* Uses the values of DISKFS_DEVICE_ARG and DISKFS_USE_MACH_DEVICE, and
- attempts to open the device and set the values of DISKFS_DEVICE,
- DISKFS_DEVICE_NAME, DISKFS_DEVICE_START, DISKFS_DEVICE_SIZE, and
- DISKFS_DEVICE_BLOCK_SIZE. */
-extern error_t diskfs_device_open ();
-
-/* A mach device port for the device we're using. */
-extern mach_port_t diskfs_device;
-
-/* The mach device name of DISKFS_DEVICE. May be 0 if unknown. */
-extern char *diskfs_device_name;
-
-/* The first valid block of DISKFS_DEVICE, in units of
- DISKFS_DEVICE_BLOCK_SIZE. */
-extern off_t diskfs_device_start;
-
-/* The usable size of DISKFS_DEVICE, in units of DISKFS_DEVICE_BLOCK_SIZE. */
-extern off_t diskfs_device_size;
-
-/* The unit of addressing for DISKFS_DEVICE. */
-extern unsigned diskfs_device_block_size;
-
-/* Some handy calculations based on DISKFS_DEVICE_BLOCK_SIZE. */
-/* Log base 2 of DEVICE_BLOCK_SIZE, or 0 if it's not a power of two. */
-extern unsigned diskfs_log2_device_block_size;
-/* Log base 2 of the number of device blocks in a vm page. This number is
- only valid if DISKFS_LOG2_DEVICE_BLOCK_SIZE is not 0. */
-extern unsigned diskfs_log2_device_blocks_per_page;
-
-/* Write disk block ADDR with DATA of LEN bytes to DISKFS_DEVICE, waiting for
- completion. ADDR is offset by DISKFS_DEVICE_START. If an error occurs,
- EIO is returned. */
-error_t diskfs_device_write_sync (off_t addr, vm_address_t data, size_t len);
-
-/* Read disk block ADDR from DISKFS_DEVICE; put the address of the data in
- DATA; read LEN bytes. Always *DATA should be a full page no matter what.
- ADDR is offset by DISKFS_DEVICE_START. If an error occurs, EIO is
- returned. */
-error_t diskfs_device_read_sync (off_t addr, vm_address_t *data, size_t len);
-
/* Make errors go somewhere reasonable. */
void diskfs_console_stdio ();
-
#endif /* hurd/diskfs.h */
-
diff --git a/libdiskfs/ports-consts.c b/libdiskfs/extern-inline.c
index c2726c4c..43de88d6 100644
--- a/libdiskfs/ports-consts.c
+++ b/libdiskfs/extern-inline.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/* Run time callable functions for extern inlines.
+ Copyright (C) 2001 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
@@ -15,6 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#define DISKFS_DEFINE_EXTERN_INLINE
-/* ports_wire_threads is set in init-init.c. */
-int ports_wire_cthreads = 1;
+#include "diskfs.h"
diff --git a/libmom/wire-memory.c b/libdiskfs/extra-version.c
index b3832154..b1d78084 100644
--- a/libmom/wire-memory.c
+++ b/libdiskfs/extra-version.c
@@ -1,6 +1,6 @@
-/*
+/* Default value for diskfs_extra_version
Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+ Written by Thomas Bushnell, n/BSG.
This file is part of the GNU Hurd.
@@ -18,11 +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 "priv.h"
-error_t
-mom_wire_memory (void *start, size_t len)
-{
- return EOPNOTSUPP;
-}
+char *diskfs_extra_version = "";
diff --git a/libdiskfs/fhandle.h b/libdiskfs/fhandle.h
new file mode 100644
index 00000000..bd827d84
--- /dev/null
+++ b/libdiskfs/fhandle.h
@@ -0,0 +1,36 @@
+/* File handle type (for nfs server support)
+
+ Copyright (C) 1997,99 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __FHANDLE_H__
+#define __FHANDLE_H__
+
+/* Must be exactly 28 bytes long */
+union diskfs_fhandle
+{
+ unsigned char bytes[28];
+ struct
+ {
+ int pad1;
+ int cache_id;
+ unsigned int gen;
+ } data;
+};
+
+#endif /* __FHANDLE_H__ */
diff --git a/libdiskfs/file-access.c b/libdiskfs/file-access.c
index 7553ffda..4a5eb17d 100644
--- a/libdiskfs/file-access.c
+++ b/libdiskfs/file-access.c
@@ -31,11 +31,11 @@ diskfs_S_file_check_access (struct protid *cred,
np = cred->po->np;
mutex_lock (&np->lock);
*type = 0;
- if (diskfs_access (np, S_IREAD, cred) == 0)
+ if (fshelp_access (&np->dn_stat, S_IREAD, cred->user) == 0)
*type |= O_READ;
- if (diskfs_access (np, S_IWRITE, cred) == 0)
+ if (fshelp_access (&np->dn_stat, S_IWRITE, cred->user) == 0)
*type |= O_WRITE;
- if (diskfs_access (np, S_IEXEC, cred) == 0)
+ if (fshelp_access (&np->dn_stat, S_IEXEC, cred->user) == 0)
*type |= O_EXEC;
mutex_unlock (&np->lock);
diff --git a/libdiskfs/file-chauthor.c b/libdiskfs/file-chauthor.c
index 25f4c4ec..6e49c53f 100644
--- a/libdiskfs/file-chauthor.c
+++ b/libdiskfs/file-chauthor.c
@@ -27,13 +27,16 @@ dithkfth_TH_file_chauthor (struct protid *cred,
{
CHANGE_NODE_FIELD (cred,
({
- err = dithkfth_ithowner (np, cred);
+ err = fthhelp_ithowner (&np->dn_thtat, cred->uther);
if (!err)
err = dithkfth_validate_author_change (np, author);
if (!err)
{
np->dn_thtat.tht_author = author;
np->dn_thet_theetime = 1;
+ if (np->filemod_reqs)
+ diskfs_notice_filechange(np, FILE_CHANGED_META,
+ 0, 0);
}
}));
}
diff --git a/libdiskfs/file-chflags.c b/libdiskfs/file-chflags.c
index e1403f25..01dc495c 100644
--- a/libdiskfs/file-chflags.c
+++ b/libdiskfs/file-chflags.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs:file_chflags
- Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1992, 1993, 1994, 1996, 1998 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,10 +25,16 @@ diskfs_S_file_chflags (struct protid *cred,
{
CHANGE_NODE_FIELD (cred,
({
- err = diskfs_isowner (np, cred);
+ err = fshelp_isowner (&np->dn_stat, cred->user);
if (!err)
err = diskfs_validate_flags_change (np, flags);
if (!err)
- np->dn_stat.st_flags = flags;
+ {
+ np->dn_stat.st_flags = flags;
+ np->dn_set_ctime = 1;
+ }
+ if (!err && np->filemod_reqs)
+ diskfs_notice_filechange(np, FILE_CHANGED_META,
+ 0, 0);
}));
}
diff --git a/libdiskfs/file-chg.c b/libdiskfs/file-chg.c
index 27d932e6..22edc69c 100644
--- a/libdiskfs/file-chg.c
+++ b/libdiskfs/file-chg.c
@@ -17,11 +17,55 @@
#include "priv.h"
#include "fs_S.h"
+#include "fs_notify_U.h"
kern_return_t
-diskfs_S_file_notice_changes (struct protid *cred __attribute__ ((unused)),
- mach_port_t notify __attribute__ ((unused)))
+diskfs_S_file_notice_changes (struct protid *cred, mach_port_t notify)
{
- return EOPNOTSUPP;
+ error_t err;
+ struct modreq *req;
+ struct node *np;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+ mutex_lock (&np->lock);
+ err = file_changed (notify, np->filemod_tick, FILE_CHANGED_NULL, 0, 0);
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ return err;
+ }
+ req = malloc (sizeof (struct modreq));
+ req->port = notify;
+ req->next = np->filemod_reqs;
+ np->filemod_reqs = req;
+ mutex_unlock (&np->lock);
+ return 0;
}
+void
+diskfs_notice_filechange (struct node *dp, enum file_changed_type type,
+ off_t start, off_t end)
+{
+ error_t err;
+ struct modreq **preq;
+
+ dp->filemod_tick++;
+ preq = &dp->filemod_reqs;
+ while (*preq)
+ {
+ struct modreq *req = *preq;
+ err = file_changed (req->port, dp->filemod_tick, type, start, end);
+ if (err && err != MACH_SEND_TIMED_OUT)
+ {
+ /* Remove notify port. */
+ *preq = req->next;
+ mach_port_deallocate (mach_task_self (), req->port);
+ free (req);
+ }
+ else
+ preq = &req->next;
+ }
+}
diff --git a/libdiskfs/file-chmod.c b/libdiskfs/file-chmod.c
index 545b810f..5dad2c78 100644
--- a/libdiskfs/file-chmod.c
+++ b/libdiskfs/file-chmod.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: file_chmod
- Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,96,97,2002 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
@@ -22,29 +22,35 @@ error_t
diskfs_S_file_chmod (struct protid *cred,
mode_t mode)
{
- mode &= ~(S_IFMT | S_ISPARE);
-
+ mode &= ~(S_IFMT | S_ISPARE | S_ITRANS);
+
CHANGE_NODE_FIELD (cred,
- ({
- if (!(err = diskfs_isowner (np, cred)))
- {
- if (!diskfs_isuid (0, cred))
- {
- if (!S_ISDIR (np->dn_stat.st_mode))
- mode &= ~S_ISVTX;
- if (!diskfs_groupmember (np->dn_stat.st_gid,
- cred))
- mode &= ~S_ISGID;
- if (!diskfs_isuid (np->dn_stat.st_uid, cred))
- mode &= ~S_ISUID;
- }
- mode |= (np->dn_stat.st_mode & (S_IFMT | S_ISPARE));
- err = diskfs_validate_mode_change (np, mode);
- if (!err)
- {
- np->dn_stat.st_mode = mode;
- np->dn_set_ctime = 1;
- }
- }
- }));
+ ({
+ if (!(err = fshelp_isowner (&np->dn_stat, cred->user)))
+ {
+ if (!idvec_contains (cred->user->uids, 0))
+ {
+ if (!S_ISDIR (np->dn_stat.st_mode))
+ mode &= ~S_ISVTX;
+ if (!idvec_contains (cred->user->gids,
+ np->dn_stat.st_gid))
+ mode &= ~S_ISGID;
+ if (!idvec_contains (cred->user->uids,
+ np->dn_stat.st_uid))
+ mode &= ~S_ISUID;
+ }
+ mode |= (np->dn_stat.st_mode
+ & (S_IFMT | S_ISPARE | S_ITRANS));
+ err = diskfs_validate_mode_change (np, mode);
+ if (!err)
+ {
+ np->dn_stat.st_mode = mode;
+ np->dn_set_ctime = 1;
+ if (np->filemod_reqs)
+ diskfs_notice_filechange (np,
+ FILE_CHANGED_META,
+ 0, 0);
+ }
+ }
+ }));
}
diff --git a/libdiskfs/file-chown.c b/libdiskfs/file-chown.c
index a0c4f225..ecb851f2 100644
--- a/libdiskfs/file-chown.c
+++ b/libdiskfs/file-chown.c
@@ -1,5 +1,5 @@
/* libdiskfs implementetation of fs.defs: file_chown
- Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1992, 1993, 1994, 1996, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -24,24 +24,40 @@ diskfs_S_file_chown (struct protid *cred,
uid_t uid,
gid_t gid)
{
+ if (uid == (uid_t) -1 && gid == (gid_t) -1) /* No change requested. */
+ return 0;
+
CHANGE_NODE_FIELD (cred,
({
- err = diskfs_isowner (np, cred);
+ err = fshelp_isowner (&np->dn_stat, cred->user);
if (err
- || ((!diskfs_isuid (uid, cred)
- || !diskfs_groupmember (gid, cred))
- && !diskfs_isuid (0, cred)))
+ || (((uid != (uid_t) -1
+ && !idvec_contains (cred->user->uids, uid))
+ || (gid != (gid_t) -1
+ && !idvec_contains (cred->user->gids, gid)))
+ && !idvec_contains (cred->user->uids, 0)))
err = EPERM;
- else
+ else
{
- err = diskfs_validate_owner_change (np, uid);
- if (!err)
+ if (uid != (uid_t) -1)
+ err = diskfs_validate_owner_change (np, uid);
+ if (!err && gid != (gid_t) -1)
err = diskfs_validate_group_change (np, gid);
if (!err)
{
- np->dn_stat.st_uid = uid;
- np->dn_stat.st_gid = gid;
+ if (uid != (uid_t) -1)
+ {
+ np->dn_stat.st_uid = uid;
+ if (np->author_tracks_uid)
+ np->dn_stat.st_author = uid;
+ }
+ if (gid != (gid_t) -1)
+ np->dn_stat.st_gid = gid;
np->dn_set_ctime = 1;
+ if (np->filemod_reqs)
+ diskfs_notice_filechange(np,
+ FILE_CHANGED_META,
+ 0, 0);
}
}
}));
diff --git a/libdiskfs/file-exec.c b/libdiskfs/file-exec.c
index c21f12e1..452240c0 100644
--- a/libdiskfs/file-exec.c
+++ b/libdiskfs/file-exec.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+/* File execution (file_exec RPC) for diskfs servers, using exec server.
+ Copyright (C) 1993,94,95,96,97,98,2000,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -22,30 +22,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
#include "fs_S.h"
#include <sys/stat.h>
-#include <fcntlbits.h>
+#include <fcntl.h>
#include <hurd/exec.h>
#include <hurd/paths.h>
#include <string.h>
#include <idvec.h>
-kern_return_t
+kern_return_t
diskfs_S_file_exec (struct protid *cred,
task_t task,
int flags,
char *argv,
- u_int argvlen,
+ size_t argvlen,
char *envp,
- u_int envplen,
+ size_t envplen,
mach_port_t *fds,
- u_int fdslen,
+ size_t fdslen,
mach_port_t *portarray,
- u_int portarraylen,
+ size_t portarraylen,
int *intarray,
- u_int intarraylen,
+ size_t intarraylen,
mach_port_t *deallocnames,
- u_int deallocnameslen,
+ size_t deallocnameslen,
mach_port_t *destroynames,
- u_int destroynameslen)
+ size_t destroynameslen)
{
struct node *np;
uid_t uid;
@@ -53,44 +53,67 @@ diskfs_S_file_exec (struct protid *cred,
mode_t mode;
int suid, sgid;
struct protid *newpi;
+ struct peropen *newpo;
error_t err = 0;
-
+ mach_port_t execserver;
+ int cached_exec;
+ struct hurd_userlink ulink;
+ mach_port_t right;
+
+#define RETURN(code) do { err = (code); goto out; } while (0)
+
if (!cred)
return EOPNOTSUPP;
- if (diskfs_exec == MACH_PORT_NULL)
- diskfs_exec = file_name_lookup (_SERVERS_EXEC, 0, 0);
- if (diskfs_exec == MACH_PORT_NULL)
- return EOPNOTSUPP;
-
+ /* Get a light reference to the cached exec server port. */
+ execserver = _hurd_port_get (&_diskfs_exec_portcell, &ulink);
+ cached_exec = (execserver != MACH_PORT_NULL);
+ if (execserver == MACH_PORT_NULL)
+ {
+ /* No cached port. Look up the canonical naming point. */
+ execserver = file_name_lookup (_SERVERS_EXEC, 0, 0);
+ if (execserver == MACH_PORT_NULL)
+ return EOPNOTSUPP; /* No exec server, no exec. */
+ else
+ {
+ /* Install the newly-gotten exec server port for other
+ threads to use, then get a light reference for this call. */
+ _hurd_port_set (&_diskfs_exec_portcell, execserver);
+ execserver = _hurd_port_get (&_diskfs_exec_portcell, &ulink);
+ }
+ }
+
np = cred->po->np;
mutex_lock (&np->lock);
mode = np->dn_stat.st_mode;
uid = np->dn_stat.st_uid;
- gid = np->dn_stat.st_uid;
+ gid = np->dn_stat.st_gid;
mutex_unlock (&np->lock);
+ if (_diskfs_noexec)
+ RETURN (EACCES);
+
if ((cred->po->openstat & O_EXEC) == 0)
- return EBADF;
-
+ RETURN (EBADF);
+
if (!((mode & (S_IXUSR|S_IXGRP|S_IXOTH))
|| ((mode & S_IUSEUNK) && (mode & (S_IEXEC << S_IUNKSHIFT)))))
- return EACCES;
-
+ RETURN (EACCES);
+
if ((mode & S_IFMT) == S_IFDIR)
- return EACCES;
+ RETURN (EACCES);
suid = mode & S_ISUID;
sgid = mode & S_ISGID;
- if (suid || sgid)
+ if (!_diskfs_nosuid && (suid || sgid))
{
int secure = 0;
error_t get_file_ids (struct idvec *uids, struct idvec *gids)
{
- error_t err = idvec_merge_ids (uids, cred->uids, cred->nuids);
+ error_t err = idvec_merge (uids, cred->user->uids);
if (! err)
- err = idvec_merge_ids (gids, cred->gids, cred->ngids);
+ err = idvec_merge (gids, cred->user->gids);
return err;
}
err =
@@ -107,34 +130,74 @@ diskfs_S_file_exec (struct protid *cred,
to the user. Too many things depend on that that it can't be
changed. So this vague attempt isn't even worth trying. */
#if 0
- if (diskfs_access (np, S_IREAD, cred))
+ if (fshelp_access (&np->dn_stat, S_IREAD, cred->user))
flags |= EXEC_NEWTASK;
#endif
if (! err)
- err = diskfs_create_protid (diskfs_make_peropen (np, O_READ,
- cred->po->dotdotport),
- cred->uids, cred->nuids,
- cred->gids, cred->ngids,
- &newpi);
+ /* Make a new peropen for the exec server to access the file, since any
+ seeking the exec server might want to do should not affect the
+ original peropen on which file_exec was called. (The new protid for
+ this peropen clones the caller's iouser to preserve the caller's
+ authentication credentials.) The new peropen's openmodes must have
+ O_READ even if the caller had only O_EXEC privilege, so the exec
+ server can read the executable file. We also include O_EXEC so that
+ the exec server can turn this peropen into a file descriptor in the
+ target process and permit it to exec its /dev/fd/N pseudo-file. */
+ {
+ err = diskfs_make_peropen (np, O_READ|O_EXEC, cred->po, &newpo);
+ if (! err)
+ {
+ err = diskfs_create_protid (newpo, cred->user, &newpi);
+ if (err)
+ diskfs_release_peropen (newpo);
+ }
+ }
if (! err)
{
- err = exec_exec (diskfs_exec,
- ports_get_right (newpi),
- MACH_MSG_TYPE_MAKE_SEND,
- task, flags, argv, argvlen, envp, envplen,
- fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
- portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
- intarray, intarraylen, deallocnames, deallocnameslen,
- destroynames, destroynameslen);
+ do
+ {
+ right = ports_get_send_right (newpi);
+ err = exec_exec (execserver,
+ right, MACH_MSG_TYPE_COPY_SEND,
+ task, flags, argv, argvlen, envp, envplen,
+ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
+ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
+ intarray, intarraylen,
+ deallocnames, deallocnameslen,
+ destroynames, destroynameslen);
+ mach_port_deallocate (mach_task_self (), right);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+ if (cached_exec)
+ {
+ /* We were using a previously looked-up exec server port.
+ Try looking up a new one before giving an error. */
+ cached_exec = 0;
+ _hurd_port_free (&_diskfs_exec_portcell, &ulink, execserver);
+
+ execserver = file_name_lookup (_SERVERS_EXEC, 0, 0);
+ if (execserver == MACH_PORT_NULL)
+ err = EOPNOTSUPP;
+ else
+ {
+ _hurd_port_set (&_diskfs_exec_portcell, execserver);
+ execserver = _hurd_port_get (&_diskfs_exec_portcell,
+ &ulink);
+ }
+ }
+ else
+ err = EOPNOTSUPP;
+ }
+ } while (err == MACH_SEND_INVALID_DEST);
ports_port_deref (newpi);
}
if (! err)
{
unsigned int i;
-
+
mach_port_deallocate (mach_task_self (), task);
for (i = 0; i < fdslen; i++)
mach_port_deallocate (mach_task_self (), fds[i]);
@@ -142,5 +205,8 @@ diskfs_S_file_exec (struct protid *cred,
mach_port_deallocate (mach_task_self (), portarray[i]);
}
- return err;
+ out:
+ _hurd_port_free (&_diskfs_exec_portcell, &ulink, execserver);
+
+ return err;
}
diff --git a/libdiskfs/file-get-fs-opts.c b/libdiskfs/file-get-fs-opts.c
index 662e7511..b3bca821 100644
--- a/libdiskfs/file-get-fs-opts.c
+++ b/libdiskfs/file-get-fs-opts.c
@@ -1,8 +1,7 @@
/* Get run-time file system options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,98,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -22,26 +21,33 @@
#include <errno.h>
#include <string.h>
+#include <argz.h>
#include "priv.h"
error_t
diskfs_S_file_get_fs_options (struct protid *cred,
- char **data, unsigned *data_len)
+ char **data, size_t *data_len)
{
error_t err;
- char *argz;
- size_t argz_len;
+ char *argz = 0;
+ size_t argz_len = 0;
if (! cred)
return EOPNOTSUPP;
+ err = argz_add (&argz, &argz_len, program_invocation_name);
+ if (err)
+ return err;
+
rwlock_reader_lock (&diskfs_fsys_lock);
- err = diskfs_get_options (&argz, &argz_len);
+ err = diskfs_append_args (&argz, &argz_len);
rwlock_reader_unlock (&diskfs_fsys_lock);
if (! err)
/* Move ARGZ from a malloced buffer into a vm_alloced one. */
- err = fshelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ err = iohelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ else
+ free (argz);
return err;
}
diff --git a/libdiskfs/file-get-trans.c b/libdiskfs/file-get-trans.c
index abb9e9e7..e77dba82 100644
--- a/libdiskfs/file-get-trans.c
+++ b/libdiskfs/file-get-trans.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: file_get_translator
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,98,99,2002 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
@@ -25,14 +25,14 @@
kern_return_t
diskfs_S_file_get_translator (struct protid *cred,
char **trans,
- u_int *translen)
+ size_t *translen)
{
struct node *np;
error_t error = 0;
-
+
if (!cred)
return EOPNOTSUPP;
-
+
np = cred->po->np;
mutex_lock (&np->lock);
@@ -41,14 +41,14 @@ diskfs_S_file_get_translator (struct protid *cred,
if (S_ISLNK (np->dn_stat.st_mode))
{
unsigned int len = sizeof _HURD_SYMLINK + np->dn_stat.st_size + 1;
- int amt;
+ size_t amt;
assert (diskfs_shortcut_symlink);
- if (len > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *)trans, len, 1);
+ if (len > *translen)
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
bcopy (_HURD_SYMLINK, *trans, sizeof _HURD_SYMLINK);
if (diskfs_read_symlink_hook)
- error = (*diskfs_read_symlink_hook) (np,
+ error = (*diskfs_read_symlink_hook) (np,
*trans + sizeof _HURD_SYMLINK);
if (!diskfs_read_symlink_hook || error == EINVAL)
{
@@ -62,6 +62,8 @@ diskfs_S_file_get_translator (struct protid *cred,
(*trans)[sizeof _HURD_SYMLINK + np->dn_stat.st_size] = '\0';
*translen = len;
}
+ else if (len > *translen)
+ munmap (trans, len);
}
else if (S_ISCHR (np->dn_stat.st_mode) || S_ISBLK (np->dn_stat.st_mode))
{
@@ -73,27 +75,28 @@ diskfs_S_file_get_translator (struct protid *cred,
else
assert (diskfs_shortcut_blkdev);
- buflen = asprintf (&buf, "%s%c%d%c%d",
- (S_ISCHR (np->dn_stat.st_mode)
+ buflen = asprintf (&buf, "%s%c%d%c%d",
+ (S_ISCHR (np->dn_stat.st_mode)
? _HURD_CHRDEV
: _HURD_BLKDEV),
'\0', (np->dn_stat.st_rdev >> 8) & 0377,
'\0', (np->dn_stat.st_rdev) & 0377);
buflen++; /* terminating nul */
-
+
if (buflen > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *) trans, buflen, 1);
+ *trans = mmap (0, buflen, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
bcopy (buf, *trans, buflen);
+ free (buf);
*translen = buflen;
error = 0;
}
else if (S_ISFIFO (np->dn_stat.st_mode))
{
unsigned int len;
-
+
len = sizeof _HURD_FIFO;
if (len > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *) trans, len, 1);
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
bcopy (_HURD_FIFO, *trans, sizeof _HURD_FIFO);
*translen = len;
error = 0;
@@ -101,17 +104,17 @@ diskfs_S_file_get_translator (struct protid *cred,
else if (S_ISSOCK (np->dn_stat.st_mode))
{
unsigned int len;
-
+
len = sizeof _HURD_IFSOCK;
if (len > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *) trans, len, 1);
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
bcopy (_HURD_IFSOCK, *trans, sizeof _HURD_IFSOCK);
*translen = len;
error = 0;
}
else
{
- if (!np->istranslated)
+ if (! (np->dn_stat.st_mode & S_IPTRANS))
error = EINVAL;
else
{
@@ -121,15 +124,14 @@ diskfs_S_file_get_translator (struct protid *cred,
if (!error)
{
if (len > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *) trans,
- len, 1);
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
bcopy (string, *trans, len);
*translen = len;
free (string);
}
}
}
-
+
mutex_unlock (&np->lock);
return error;
diff --git a/libdiskfs/file-get-transcntl.c b/libdiskfs/file-get-transcntl.c
index adda4477..528529fb 100644
--- a/libdiskfs/file-get-transcntl.c
+++ b/libdiskfs/file-get-transcntl.c
@@ -33,13 +33,16 @@ diskfs_S_file_get_translator_cntl (struct protid *cred,
np = cred->po->np;
mutex_lock (&np->lock);
- error = diskfs_isowner (np, cred);
+
+ error = fshelp_isowner (&np->dn_stat, cred->user);
if (!error)
error = fshelp_fetch_control (&np->transbox, ctl);
- if (ctl == MACH_PORT_NULL)
+ if (!error && *ctl == MACH_PORT_NULL)
error = ENXIO;
if (!error)
- *ctltype = MACH_MSG_TYPE_COPY_SEND;
+ *ctltype = MACH_MSG_TYPE_MOVE_SEND;
+
mutex_unlock (&np->lock);
+
return error;
}
diff --git a/libdiskfs/file-getcontrol.c b/libdiskfs/file-getcontrol.c
index e510a271..23afb7cb 100644
--- a/libdiskfs/file-getcontrol.c
+++ b/libdiskfs/file-getcontrol.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs:file_getcontrol.c
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,6 +17,7 @@
#include "priv.h"
#include "fs_S.h"
+#include <hurd/fshelp.h>
/* Implement file_getcontrol as described in <hurd/fs.defs>. */
kern_return_t
@@ -24,28 +25,27 @@ diskfs_S_file_getcontrol (struct protid *cred,
mach_port_t *control,
mach_msg_type_name_t *controltype)
{
- int error = 0;
+ int error;
struct port_info *newpi;
if (!cred)
return EOPNOTSUPP;
- if (!diskfs_isuid (0, cred))
- error = EPERM;
- else
- {
- error = ports_create_port (diskfs_control_class, diskfs_port_bucket,
- sizeof (struct port_info), &newpi);
- if (! error)
- {
- spin_lock (&_diskfs_control_lock);
- _diskfs_ncontrol_ports++;
- spin_unlock (&_diskfs_control_lock);
- *control = ports_get_right (newpi);
- *controltype = MACH_MSG_TYPE_MAKE_SEND;
- ports_port_deref (newpi);
- }
- }
-
- return error;
+ error = fshelp_iscontroller (&diskfs_root_node->dn_stat, cred->user);
+ if (error)
+ return error;
+
+ error = ports_create_port (diskfs_control_class, diskfs_port_bucket,
+ sizeof (struct port_info), &newpi);
+ if (error)
+ return error;
+
+ spin_lock (&_diskfs_control_lock);
+ _diskfs_ncontrol_ports++;
+ spin_unlock (&_diskfs_control_lock);
+ *control = ports_get_right (newpi);
+ *controltype = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newpi);
+
+ return 0;
}
diff --git a/libdiskfs/file-getfh.c b/libdiskfs/file-getfh.c
index bc788a20..2dcf68e5 100644
--- a/libdiskfs/file-getfh.c
+++ b/libdiskfs/file-getfh.c
@@ -1,28 +1,60 @@
-/* libdiskfs implementation of fs.defs: file_getfh
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation
+/* Return a file handle (for nfs server support)
- 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.
+ Copyright (C) 1997,99,2002 Free Software Foundation, Inc.
- 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.
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <string.h>
#include "priv.h"
#include "fs_S.h"
+#include "fhandle.h"
-/* Implement file_getfh as described in <hurd/fs.defs>. */
-kern_return_t
-diskfs_S_file_getfh (struct protid *cred __attribute__ ((unused)),
- char **data __attribute__ ((unused)),
- u_int *datalen __attribute__ ((unused)))
+/* Return an NFS file handle for CRED in FH & FN_LEN. */
+error_t
+diskfs_S_file_getfh (struct protid *cred, char **fh, size_t *fh_len)
{
- return EOPNOTSUPP;
+ struct node *node;
+ union diskfs_fhandle *f;
+
+ if (! cred)
+ return EOPNOTSUPP;
+
+ if (! idvec_contains (cred->user->uids, 0))
+ return EPERM;
+
+ assert (sizeof *f == sizeof f->bytes);
+
+ node = cred->po->np;
+
+ mutex_lock (&node->lock);
+
+ if (*fh_len < sizeof (union diskfs_fhandle))
+ *fh = mmap (0, sizeof (union diskfs_fhandle), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ *fh_len = sizeof *f;
+
+ f = (union diskfs_fhandle *) *fh;
+
+ bzero (f, sizeof *f);
+ f->data.cache_id = node->cache_id;
+ f->data.gen = node->dn_stat.st_gen;
+
+ mutex_unlock (&node->lock);
+
+ return 0;
}
diff --git a/libdiskfs/file-inv-trans.c b/libdiskfs/file-inv-trans.c
deleted file mode 100644
index bbdac6ff..00000000
--- a/libdiskfs/file-inv-trans.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
-
- 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. */
-
-#include "priv.h"
-#include "fs_S.h"
-#include <fcntl.h>
-
-/* Implement fs.defs:file_invoke_translator as described in <hurd/fs.defs>. */
-kern_return_t
-diskfs_S_file_invoke_translator (struct protid *cred __attribute__ ((unused)),
- int flags __attribute__ ((unused)),
- retry_type *retry __attribute__ ((unused)),
- char *retry_name __attribute__ ((unused)),
- mach_port_t *retrypt __attribute__ ((unused)),
- mach_msg_type_name_t *retrypttype
- __attribute__ ((unused)))
-{
-#if 0
- /* XXX */
- static mach_port_t _diskfs_dotdot_file = MACH_PORT_NULL;
- error_t error = 0;
- mode_t type;
- struct node *np;
- struct protid *newpi;
-
- /* This code is very similar (but subtly different) from
- dir-pathtrans.c and fsys-getroot.c. A way should be found to
- combine them. */
-
- if (!cred)
- return EOPNOTSUPP;
-
- flags &= O_HURD;
-
- np = cred->po->np;
-
- mutex_lock (&np->lock);
-
- type = np->dn_stat.st_mode & S_IFMT;
-
- repeat_transcheck:
- /* Ignore O_NOTRANS in the following check */
- if (np->istranslated || np->translator.control != MACH_PORT_NULL)
- {
- mach_port_t control = np->translator.control;
-
- if (control == MACH_PORT_NULL)
- {
- /* This use of _diskfs_dotdot_file is completely and utterly
- bogus. XXX */
- if (error = diskfs_start_translator (np, _diskfs_dotdot_file))
- {
- mutex_unlock (&np->lock);
- return error;
- }
- control = np->translator.control;
- }
-
- mach_port_mod_refs (mach_task_self (), control, MACH_PORT_RIGHT_SEND, 1);
- mutex_unlock (&np->lock);
- error = fsys_getroot (control, cred->uids, cred->nuids,
- cred->gids, cred->ngids, flags, retry,
- retry_name, retrypt);
- if (error == MACH_SEND_INVALID_DEST)
- {
- mutex_lock (&np->lock);
- if (np->translator.control == control)
- fshelp_translator_drop (&np->translator);
- mach_port_deallocate (mach_task_self (), control);
- error = 0;
- goto repeat_transcheck;
- }
-
- if (!error && *retrypt != MACH_PORT_NULL)
- *retrypttype = MACH_MSG_TYPE_MOVE_SEND;
- else
- *retrypttype = MACH_MSG_TYPE_COPY_SEND;
-
- return error;
- }
-
- /* Ignore O_NOTRANS here. */
- if (type == S_IFLNK && !(flags & O_NOLINK))
- {
- /* Handle symlink interpretation */
- char pathbuf[np->dn_stat.st_size + 1];
- int amt;
-
- if (diskfs_read_symlink_hook)
- error = (*diskfs_read_symlink_hook) (np, pathbuf);
- if (!diskfs_read_symlink_hook || error == EINVAL)
- error = diskfs_node_rdwr (np, pathbuf, 0, np->dn_stat.st_size, 0,
- 0, &amt);
- pathbuf[amt] = '\0';
-
- mutex_unlock (&np->lock);
- if (error)
- return error;
-
- if (pathbuf[0] == '/')
- {
- *retry = FS_RETRY_MAGICAL;
- *retrypt = MACH_PORT_NULL;
- *retrypttype = MACH_MSG_TYPE_COPY_SEND;
- strcpy (retry_name, pathbuf);
- return 0;
- }
- else
- {
- *retry = FS_RETRY_REAUTH;
- *retrypt = _diskfs_dotdot_file;
- *retrypttype = MACH_MSG_TYPE_COPY_SEND;
- strcpy (retry_name, pathbuf);
- return 0;
- }
- }
-
- if ((type == S_IFSOCK || type == S_IFBLK
- || type == S_IFCHR || type == S_IFIFO)
- && (flags & (O_READ|O_WRITE|O_EXEC)))
- error = EOPNOTSUPP;
-
-
- flags &= ~OPENONLY_STATE_MODES;
-
- error = diskfs_create_protid (diskfs_make_peropen (np, flags,
- _diskfs_dotdot_file),
- cred->uids, cred->nuids,
- cred->gids, cred->ngids,
- &newpi);
- if (! error)
- {
- *retry = FS_RETRY_NONE;
- retry_name[0] = '\0';
- *retrypt = ports_get_right (newpi);
- *retrypttype = MACH_MSG_TYPE_MAKE_SEND;
- ports_port_deref (newpi);
- }
-
- mutex_unlock (&np->lock);
-
- return error;
-#else
- return EOPNOTSUPP;
-#endif
-}
diff --git a/libdiskfs/file-reparent.c b/libdiskfs/file-reparent.c
new file mode 100644
index 00000000..e659bcf0
--- /dev/null
+++ b/libdiskfs/file-reparent.c
@@ -0,0 +1,70 @@
+/* Reparent a file
+
+ Copyright (C) 1997,2002 Free Software Foundation
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "priv.h"
+#include "fs_S.h"
+
+error_t
+diskfs_S_file_reparent (struct protid *cred, mach_port_t parent,
+ mach_port_t *new, mach_msg_type_name_t *new_type)
+{
+ error_t err;
+ struct node *node;
+ struct protid *new_cred;
+ struct peropen *new_po;
+
+ if (! cred)
+ return EOPNOTSUPP;
+
+ node = cred->po->np;
+
+ mutex_lock (&node->lock);
+ err = diskfs_make_peropen (node, cred->po->openstat, cred->po, &new_po);
+ if (! err)
+ {
+ err = diskfs_create_protid (new_po, cred->user, &new_cred);
+ if (err)
+ diskfs_release_peropen (new_po);
+ }
+ mutex_unlock (&node->lock);
+
+ if (! err)
+ {
+ /* Remove old shadow root state. */
+ if (new_cred->po->shadow_root && new_cred->po->shadow_root != node)
+ diskfs_nrele (new_cred->po->shadow_root);
+ if (new_cred->po->shadow_root_parent)
+ mach_port_deallocate (mach_task_self (),
+ new_cred->po->shadow_root_parent);
+
+ /* And install PARENT instead. */
+ new_cred->po->shadow_root = node;
+ new_cred->po->shadow_root_parent = parent;
+
+ *new = ports_get_right (new_cred);
+ *new_type = MACH_MSG_TYPE_MAKE_SEND;
+
+ ports_port_deref (new_cred);
+ }
+
+ return err;
+}
diff --git a/libdiskfs/file-set-size.c b/libdiskfs/file-set-size.c
index f4d3f110..18abb469 100644
--- a/libdiskfs/file-set-size.c
+++ b/libdiskfs/file-set-size.c
@@ -29,7 +29,13 @@ diskfs_S_file_set_size (struct protid *cred,
if (!(cred->po->openstat & O_WRITE))
err = EINVAL;
else if (size < np->dn_stat.st_size)
- err = diskfs_truncate (np, size);
+ {
+ err = diskfs_truncate (np, size);
+ if (!err && np->filemod_reqs)
+ diskfs_notice_filechange (np,
+ FILE_CHANGED_TRUNCATE,
+ 0, size);
+ }
else if (size > np->dn_stat.st_size)
{
err = diskfs_grow (np, size, cred);
@@ -37,6 +43,10 @@ diskfs_S_file_set_size (struct protid *cred,
{
np->dn_stat.st_size = size;
np->dn_set_ctime = np->dn_set_mtime = 1;
+ if (np->filemod_reqs)
+ diskfs_notice_filechange (np,
+ FILE_CHANGED_EXTEND,
+ 0, size);
}
}
else
diff --git a/libdiskfs/file-set-trans.c b/libdiskfs/file-set-trans.c
index 1143ef4a..26a19eb4 100644
--- a/libdiskfs/file-set-trans.c
+++ b/libdiskfs/file-set-trans.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: file_set_translator
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2001,02 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
@@ -20,9 +20,6 @@
#include <hurd/paths.h>
#include <hurd/fsys.h>
-/* XXX - Temporary */
-#define makedev(maj,min) ((((maj)&0xFF)<<8)+((min)&0xFF))
-
/* Implement file_set_translator as described in <hurd/fs.defs>. */
kern_return_t
diskfs_S_file_set_translator (struct protid *cred,
@@ -30,7 +27,7 @@ diskfs_S_file_set_translator (struct protid *cred,
int active_flags,
int killtrans_flags,
char *passive,
- u_int passivelen,
+ size_t passivelen,
fsys_t active)
{
struct node *np;
@@ -53,14 +50,15 @@ diskfs_S_file_set_translator (struct protid *cred,
mutex_lock (&np->lock);
- error = diskfs_isowner (np, cred);
+ error = fshelp_isowner (&np->dn_stat, cred->user);
if (error)
{
mutex_unlock (&np->lock);
return error;
}
- if (active_flags & FS_TRANS_SET)
+ if ((active_flags & FS_TRANS_SET)
+ && ! (active_flags & FS_TRANS_ORPHAN))
{
error = fshelp_fetch_control (&np->transbox, &control);
if (error)
@@ -87,7 +85,7 @@ diskfs_S_file_set_translator (struct protid *cred,
/* Handle exclusive passive bit *first*. */
if ((passive_flags & FS_TRANS_SET)
&& (passive_flags & FS_TRANS_EXCL)
- && np->istranslated)
+ && (np->dn_stat.st_mode & S_IPTRANS))
{
mutex_unlock (&np->lock);
return EBUSY;
@@ -159,7 +157,7 @@ diskfs_S_file_set_translator (struct protid *cred,
}
minor = strtol (arg, 0, 0);
- error = diskfs_validate_rdev_change (np,
+ error = diskfs_validate_rdev_change (np,
makedev (major, minor));
if (error)
{
diff --git a/libdiskfs/file-statfs.c b/libdiskfs/file-statfs.c
index f90b74ef..817b0115 100644
--- a/libdiskfs/file-statfs.c
+++ b/libdiskfs/file-statfs.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: file_statfs
- Copyright (C) 1992, 1993, 1994 Free Software Foundation
+ Copyright (C) 1992,93,94,98,2000 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
@@ -15,6 +15,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <string.h>
+#include <sys/statvfs.h>
+
#include "priv.h"
#include "fs_S.h"
@@ -25,8 +28,23 @@ diskfs_S_file_statfs (struct protid *file,
{
if (!file)
return EOPNOTSUPP;
-
+
+ /* Start will all zeros, so the fs can skip fields for which
+ it has no information to contribute. */
+ bzero (statbuf, sizeof *statbuf);
+
+ if (diskfs_readonly)
+ statbuf->f_flag |= ST_RDONLY;
+ if (_diskfs_nosuid)
+ statbuf->f_flag |= ST_NOSUID;
+ if (_diskfs_noexec)
+ statbuf->f_flag |= ST_NOEXEC;
+ if (diskfs_synchronous)
+ statbuf->f_flag |= ST_SYNCHRONOUS;
+
diskfs_set_statfs (statbuf);
+ statbuf->f_namelen = diskfs_name_max;
+
return 0;
}
diff --git a/libdiskfs/file-utimes.c b/libdiskfs/file-utimes.c
index a79d91bd..39fac504 100644
--- a/libdiskfs/file-utimes.c
+++ b/libdiskfs/file-utimes.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of fs.defs: file_utimes
- Copyright (C) 1992, 1993, 1994 Free Software Foundation
+ Copyright (C) 1992, 1993, 1994, 1998, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -26,12 +26,32 @@ diskfs_S_file_utimes (struct protid *cred,
{
CHANGE_NODE_FIELD (cred,
({
- if (!(err = diskfs_isowner (np, cred)))
+ if (!(err = fshelp_isowner (&np->dn_stat, cred->user)))
{
- np->dn_stat.st_atime = atime.seconds;
- np->dn_stat.st_mtime = mtime.seconds;
- np->dn_set_atime = np->dn_set_mtime = 0;
+ if (atime.microseconds == -1)
+ np->dn_set_atime = 1;
+ else
+ {
+ np->dn_stat.st_atim.tv_sec = atime.seconds;
+ np->dn_stat.st_atim.tv_nsec = atime.microseconds * 1000;
+ np->dn_set_atime = 0;
+ }
+
+ if (mtime.microseconds == -1)
+ np->dn_set_mtime = 1;
+ else
+ {
+ np->dn_stat.st_mtim.tv_sec = mtime.seconds;
+ np->dn_stat.st_mtim.tv_nsec = mtime.microseconds * 1000;
+ np->dn_set_mtime = 0;
+ }
+
np->dn_set_ctime = 1;
+
+ if (np->filemod_reqs)
+ diskfs_notice_filechange (np,
+ FILE_CHANGED_META,
+ 0, 0);
}
}));
}
diff --git a/libdiskfs/filedev.c b/libdiskfs/filedev.c
deleted file mode 100644
index d7ee7030..00000000
--- a/libdiskfs/filedev.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Get the mach device underlying a file
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <errno.h>
-#include <sys/fcntl.h>
-
-#include <device/device.h>
-
-#include "priv.h"
-
-/* Returns the name and a send right for the mach device on which the file
- NAME is stored, and returns it in DEV_NAME (which is malloced) and PORT.
- Other values returned are START, the first valid offset, SIZE, the the
- number of blocks after START, and BLOCK_SIZE, the units in which the
- device is addressed.
-
- The device is opened for reading, and if the diskfs global variable
- DISKFS_READONLY is false, writing. */
-error_t
-diskfs_get_file_device (char *name,
- char **dev_name, mach_port_t *port,
- off_t *start, off_t *size, size_t *block_size)
-{
- int i;
- error_t err;
- mach_msg_type_number_t data_len = 100;
- mach_msg_type_number_t num_ints = 10, num_ports = 10, num_offsets = 10;
- int _ints[num_ints], *ints = _ints;
- mach_port_t _ports[num_ports], *ports = _ports;
- off_t _offsets[num_offsets], *offsets = _offsets;
- char _data[data_len], *data = _data;
- file_t node =
- file_name_lookup (name, diskfs_readonly ? O_RDONLY : O_RDWR, 0);
-
- if (node == MACH_PORT_NULL)
- return errno;
-
- *port = MACH_PORT_NULL;
-
- err = file_get_storage_info (node, &ports, &num_ports, &ints, &num_ints,
- &offsets, &num_offsets, &data, &data_len);
- if (err)
- return err;
-
- /* See <hurd/store.h> for an explanation of what's in the vectors returned
- by file_get_storage_info. */
-
- if (num_ints < 6)
- err = EGRATUITOUS;
- else if (ints[0] != STORAGE_DEVICE)
- err = ENODEV;
-
- if (!err && block_size)
- *block_size = ints[2];
-
- if (!err && (start || size))
- /* Extract the device block addresses. */
- {
- size_t num_runs = ints[3];
- if (num_runs != 1)
- /* We can't handle anything but a contiguous set of blocks. */
- err = ENODEV; /* XXX */
- else
- {
- if (start)
- *start = offsets[0];
- if (size)
- *size = offsets[1];
- }
- }
-
- if (!err && dev_name)
- /* Extract the device name into DEV_NAME. */
- {
- size_t name_len = ints[4];
- if (data && name_len > 0)
- if (data_len < name_len)
- err = EGRATUITOUS;
- else
- {
- *dev_name = malloc (name_len);
- if (*dev_name)
- strcpy (*dev_name, data);
- else
- err = ENOMEM;
- }
- }
-
- if (!err && port)
- /* Extract the device port. */
- if (num_ports != 1)
- err = EGRATUITOUS;
- else
- *port = ports[0];
-
- /* Deallocate things we don't care about or that we've made copies of. */
- for (i = (err || !port) ? 0 : 1; i < num_ports; i++)
- if (MACH_PORT_VALID (ports[i]))
- mach_port_deallocate (mach_task_self (), ports[i]);
-
-#define DISCARD_MEM(v, vl, b) \
- if (v != b) \
- vm_deallocate (mach_task_self (), (vm_address_t)v, vl * sizeof *v);
- DISCARD_MEM (ports, num_ports, _ports);
- DISCARD_MEM (ints, num_ints, _ints);
- DISCARD_MEM (offsets, num_offsets, _offsets);
- DISCARD_MEM (data, data_len, _data);
-
- /* Note that we don't deallocate NODE unless we're returning an error,
- which should prevent the information returned by file_get_storage_info
- from changing. */
-
- if (err)
- /* We got an error, deallocate everything. */
- mach_port_deallocate (mach_task_self (), node);
-
- return err;
-}
diff --git a/libdiskfs/fsmutations.h b/libdiskfs/fsmutations.h
index 9280ee04..5026810c 100644
--- a/libdiskfs/fsmutations.h
+++ b/libdiskfs/fsmutations.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994,2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,11 +17,11 @@
/* Only CPP macro definitions should go in this file. */
-#define FILE_INTRAN protid_t begin_using_protid_port (file_t)
-#define FILE_DESTRUCTOR end_using_protid_port (protid_t)
+#define FILE_INTRAN protid_t diskfs_begin_using_protid_port (file_t)
+#define FILE_DESTRUCTOR diskfs_end_using_protid_port (protid_t)
-#define IO_INTRAN protid_t begin_using_protid_port (io_t)
-#define IO_DESTRUCTOR end_using_protid_port (protid_t)
+#define IO_INTRAN protid_t diskfs_begin_using_protid_port (io_t)
+#define IO_DESTRUCTOR diskfs_end_using_protid_port (protid_t)
#define FILE_IMPORTS import "priv.h";
#define IO_IMPORTS import "priv.h";
diff --git a/libdiskfs/fsys-getfile.c b/libdiskfs/fsys-getfile.c
index 90352ead..2fe9495e 100644
--- a/libdiskfs/fsys-getfile.c
+++ b/libdiskfs/fsys-getfile.c
@@ -1,40 +1,110 @@
-/*
- Copyright (C) 1994, 1995 Free Software Foundation
+/* Return the file for a given handle (for nfs server support)
-This file is part of the GNU Hurd.
+ Copyright (C) 1997,99,2001,02 Free Software Foundation, Inc.
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+ This file is part of the GNU Hurd.
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ The GNU Hurd is 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.
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-/* Written by Michael I. Bushnell. */
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <fcntl.h>
#include "priv.h"
#include "fsys_S.h"
+#include "fhandle.h"
+/* Return in FILE & FILE_TYPE the file in FSYS corresponding to the NFS file
+ handle HANDLE & HANDLE_LEN. */
error_t
-diskfs_S_fsys_getfile (mach_port_t fsys __attribute__ ((unused)),
- mach_port_t reply,
- mach_msg_type_name_t replytype,
- uid_t *gen_uids __attribute__ ((unused)),
- u_int ngen_uids __attribute__ ((unused)),
- uid_t *gen_gids __attribute__ ((unused)),
- u_int ngen_gids __attribute__ ((unused)),
- char *handle __attribute__ ((unused)),
- u_int handlelen __attribute__ ((unused)),
- mach_port_t *file __attribute__ ((unused)),
- mach_msg_type_name_t *filetype __attribute__ ((unused)))
+diskfs_S_fsys_getfile (mach_port_t fsys,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ uid_t *uids, mach_msg_type_number_t nuids,
+ gid_t *gids, mach_msg_type_number_t ngids,
+ char *handle, mach_msg_type_number_t handle_len,
+ mach_port_t *file, mach_msg_type_name_t *file_type)
{
- return EOPNOTSUPP;
-}
+ int flags;
+ error_t err;
+ struct node *node;
+ const union diskfs_fhandle *f;
+ struct protid *new_cred;
+ struct peropen *new_po;
+ struct iouser *user;
+ struct port_info *pt =
+ ports_lookup_port (diskfs_port_bucket, fsys, diskfs_control_class);
+
+ if (!pt)
+ return EOPNOTSUPP;
+
+ if (handle_len != sizeof *f)
+ {
+ ports_port_deref (pt);
+ return EINVAL;
+ }
+
+ f = (const union diskfs_fhandle *) handle;
+
+ err = diskfs_cached_lookup (f->data.cache_id, &node);
+ if (err)
+ {
+ ports_port_deref (pt);
+ return err;
+ }
+
+ if (node->dn_stat.st_gen != f->data.gen)
+ {
+ diskfs_nput (node);
+ ports_port_deref (pt);
+ return ESTALE;
+ }
+ err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids);
+ if (err)
+ {
+ diskfs_nput (node);
+ ports_port_deref (pt);
+ return err;
+ }
+
+ flags = 0;
+ if (! fshelp_access (&node->dn_stat, S_IREAD, user))
+ flags |= O_READ;
+ if (! fshelp_access (&node->dn_stat, S_IEXEC, user))
+ flags |= O_EXEC;
+ if (! fshelp_access (&node->dn_stat, S_IWRITE, user)
+ && ! S_ISDIR (node->dn_stat.st_mode)
+ && ! diskfs_check_readonly ())
+ flags |= O_WRITE;
+
+ err = diskfs_make_peropen (node, flags, 0, &new_po);
+ if (! err)
+ {
+ err = diskfs_create_protid (new_po, user, &new_cred);
+ if (err)
+ diskfs_release_peropen (new_po);
+ }
+
+ iohelp_free_iouser (user);
+
+ diskfs_nput (node);
+ ports_port_deref (pt);
+
+ if (! err)
+ {
+ *file = ports_get_right (new_cred);
+ *file_type = MACH_MSG_TYPE_MAKE_SEND;
+ }
+
+ return err;
+}
diff --git a/libdiskfs/fsys-getroot.c b/libdiskfs/fsys-getroot.c
index 9db349c9..e083032e 100644
--- a/libdiskfs/fsys-getroot.c
+++ b/libdiskfs/fsys-getroot.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993,94,95,96,97,98,2002 Free Software Foundation
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -31,43 +31,55 @@ diskfs_S_fsys_getroot (fsys_t controlport,
mach_msg_type_name_t replytype,
mach_port_t dotdot,
uid_t *uids,
- u_int nuids,
+ size_t nuids,
uid_t *gids,
- u_int ngids,
+ size_t ngids,
int flags,
retry_type *retry,
char *retryname,
file_t *returned_port,
mach_msg_type_name_t *returned_port_poly)
{
- struct port_info *pt = ports_lookup_port (diskfs_port_bucket, controlport,
+ struct port_info *pt = ports_lookup_port (diskfs_port_bucket, controlport,
diskfs_control_class);
error_t error = 0;
mode_t type;
- struct protid pseudocred;
struct protid *newpi;
-
+ struct peropen *newpo;
+ struct iouser user;
+ struct peropen peropen_context =
+ {
+ root_parent: dotdot,
+ shadow_root_parent: MACH_PORT_NULL,
+ shadow_root: _diskfs_chroot_directory ? diskfs_root_node : NULL /* XXX */
+ };
+
if (!pt)
return EOPNOTSUPP;
flags &= O_HURD;
+ user.uids = make_idvec ();
+ user.gids = make_idvec ();
+ idvec_set_ids (user.uids, uids, nuids);
+ idvec_set_ids (user.gids, gids, ngids);
+#define drop_idvec() idvec_free (user.gids); idvec_free (user.uids)
+
rwlock_reader_lock (&diskfs_fsys_lock);
mutex_lock (&diskfs_root_node->lock);
-
+
/* This code is similar (but not the same as) the code in
- dir-pathtrans.c that does the same thing. Perhaps a way should
+ dir-lookup.c that does the same thing. Perhaps a way should
be found to share the logic. */
type = diskfs_root_node->dn_stat.st_mode & S_IFMT;
- if ((diskfs_root_node->istranslated
+ if (((diskfs_root_node->dn_stat.st_mode & S_IPTRANS)
|| fshelp_translated (&diskfs_root_node->transbox))
&& !(flags & O_NOTRANS))
{
error = fshelp_fetch_root (&diskfs_root_node->transbox,
- &dotdot, dotdot, uids, nuids,
- gids, ngids, flags,
+ &peropen_context, dotdot, &user, flags,
_diskfs_translator_callback1,
_diskfs_translator_callback2,
retry, retryname, returned_port);
@@ -75,21 +87,22 @@ diskfs_S_fsys_getroot (fsys_t controlport,
{
mutex_unlock (&diskfs_root_node->lock);
rwlock_reader_unlock (&diskfs_fsys_lock);
+ drop_idvec ();
if (!error)
*returned_port_poly = MACH_MSG_TYPE_MOVE_SEND;
return error;
}
-
+
/* ENOENT means the translator was removed in the interim. */
error = 0;
}
-
+
if (type == S_IFLNK && !(flags & (O_NOLINK | O_NOTRANS)))
{
/* Handle symlink interpretation */
char pathbuf[diskfs_root_node->dn_stat.st_size + 1];
- int amt;
-
+ size_t amt;
+
if (diskfs_read_symlink_hook)
error = (*diskfs_read_symlink_hook) (diskfs_root_node, pathbuf);
if (!diskfs_read_symlink_hook || error == EINVAL)
@@ -101,8 +114,11 @@ diskfs_S_fsys_getroot (fsys_t controlport,
mutex_unlock (&diskfs_root_node->lock);
rwlock_reader_unlock (&diskfs_fsys_lock);
if (error)
- return error;
-
+ {
+ drop_idvec ();
+ return error;
+ }
+
if (pathbuf[0] == '/')
{
*retry = FS_RETRY_MAGICAL;
@@ -110,6 +126,7 @@ diskfs_S_fsys_getroot (fsys_t controlport,
*returned_port_poly = MACH_MSG_TYPE_COPY_SEND;
strcpy (retryname, pathbuf);
mach_port_deallocate (mach_task_self (), dotdot);
+ drop_idvec ();
return 0;
}
else
@@ -118,67 +135,73 @@ diskfs_S_fsys_getroot (fsys_t controlport,
*returned_port = dotdot;
*returned_port_poly = MACH_MSG_TYPE_MOVE_SEND;
strcpy (retryname, pathbuf);
+ drop_idvec ();
return 0;
}
}
- if ((type == S_IFSOCK || type == S_IFBLK
+ if ((type == S_IFSOCK || type == S_IFBLK
|| type == S_IFCHR || type == S_IFIFO)
&& (flags & (O_READ|O_WRITE|O_EXEC)))
error = EOPNOTSUPP;
-
- /* diskfs_access requires a cred; so we give it one. */
- pseudocred.uids = uids;
- pseudocred.gids = gids;
- pseudocred.nuids = nuids;
- pseudocred.ngids = ngids;
-
+
if (!error && (flags & O_READ))
- error = diskfs_access (diskfs_root_node, S_IREAD, &pseudocred);
-
+ error = fshelp_access (&diskfs_root_node->dn_stat, S_IREAD, &user);
+
if (!error && (flags & O_EXEC))
- error = diskfs_access (diskfs_root_node, S_IEXEC, &pseudocred);
-
+ error = fshelp_access (&diskfs_root_node->dn_stat, S_IEXEC, &user);
+
if (!error && (flags & (O_WRITE)))
{
if (type == S_IFDIR)
error = EISDIR;
else if (diskfs_check_readonly ())
error = EROFS;
- else
- error = diskfs_access (diskfs_root_node, S_IWRITE, &pseudocred);
+ else
+ error = fshelp_access (&diskfs_root_node->dn_stat,
+ S_IWRITE, &user);
}
if (error)
{
mutex_unlock (&diskfs_root_node->lock);
rwlock_reader_unlock (&diskfs_fsys_lock);
+ drop_idvec ();
return error;
}
-
+
if ((flags & O_NOATIME)
- && (diskfs_isowner (diskfs_root_node, &pseudocred) == EPERM))
+ && (fshelp_isowner (&diskfs_root_node->dn_stat, &user)
+ == EPERM))
flags &= ~O_NOATIME;
flags &= ~OPENONLY_STATE_MODES;
- error = diskfs_create_protid (diskfs_make_peropen (diskfs_root_node,
- flags, dotdot),
- uids, nuids, gids, ngids, &newpi);
- mach_port_deallocate (mach_task_self (), dotdot);
+ error = diskfs_make_peropen (diskfs_root_node, flags,
+ &peropen_context, &newpo);
if (! error)
{
+ error = diskfs_create_protid (newpo, &user, &newpi);
+ if (error)
+ diskfs_release_peropen (newpo);
+ }
+
+ if (! error)
+ {
+ mach_port_deallocate (mach_task_self (), dotdot);
*retry = FS_RETRY_NORMAL;
*retryname = '\0';
*returned_port = ports_get_right (newpi);
*returned_port_poly = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (newpi);
}
-
+
mutex_unlock (&diskfs_root_node->lock);
rwlock_reader_unlock (&diskfs_fsys_lock);
ports_port_deref (pt);
+ drop_idvec ();
+
return error;
}
diff --git a/libdiskfs/fsys-options.c b/libdiskfs/fsys-options.c
index 5a8b681f..ea5ee8c5 100644
--- a/libdiskfs/fsys-options.c
+++ b/libdiskfs/fsys-options.c
@@ -1,6 +1,6 @@
/* Parse run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -88,8 +88,8 @@ diskfs_S_fsys_get_options (fsys_t fsys,
mach_msg_type_name_t replytype,
char **data, mach_msg_type_number_t *data_len)
{
- char *argz;
- size_t argz_len;
+ char *argz = 0;
+ size_t argz_len = 0;
error_t err;
struct port_info *port =
ports_lookup_port (diskfs_port_bucket, fsys, diskfs_control_class);
@@ -97,13 +97,19 @@ diskfs_S_fsys_get_options (fsys_t fsys,
if (!port)
return EOPNOTSUPP;
+ err = argz_add (&argz, &argz_len, program_invocation_name);
+ if (err)
+ return err;
+
rwlock_reader_lock (&diskfs_fsys_lock);
- err = diskfs_get_options (&argz, &argz_len);
+ err = diskfs_append_args (&argz, &argz_len);
rwlock_reader_unlock (&diskfs_fsys_lock);
if (! err)
/* Move ARGZ from a malloced buffer into a vm_alloced one. */
- err = fshelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ err = iohelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ else
+ free (argz);
ports_port_deref (port);
return err;
diff --git a/libdiskfs/ifsock.c b/libdiskfs/ifsock.c
index bee9cc19..3e9b8325 100644
--- a/libdiskfs/ifsock.c
+++ b/libdiskfs/ifsock.c
@@ -45,7 +45,7 @@ diskfs_S_ifsock_getsockaddr (struct protid *cred,
mutex_unlock (&np->lock);
return EOPNOTSUPP;
}
- err = diskfs_access (np, S_IREAD, cred);
+ err = fshelp_access (&np->dn_stat, S_IWRITE, cred->user);
if (err)
{
mutex_unlock (&np->lock);
diff --git a/libdiskfs/init-first.c b/libdiskfs/init-first.c
index f1df3dd1..d91345be 100644
--- a/libdiskfs/init-first.c
+++ b/libdiskfs/init-first.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994,95,97,2001 Free Software Foundation
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,33 +20,37 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
+#include <stdlib.h>
+#include <hurd/ports.h>
static int thread_timeout = 1000 * 60 * 2; /* two minutes */
static int server_timeout = 1000 * 60 * 10; /* ten minutes */
static any_t
-master_thread_function (any_t foo __attribute__ ((unused)))
+master_thread_function (any_t demuxer)
{
error_t err;
- do
+ do
{
ports_manage_port_operations_multithread (diskfs_port_bucket,
- diskfs_demuxer,
+ (ports_demuxer_type) demuxer,
thread_timeout,
server_timeout,
- 1, MACH_PORT_NULL);
+ 0);
err = diskfs_shutdown (0);
}
while (err);
-
+
exit (0);
+ /* NOTREACHED */
+ return (any_t) 0;
}
void
-diskfs_spawn_first_thread (void)
+diskfs_spawn_first_thread (ports_demuxer_type demuxer)
{
cthread_detach (cthread_fork ((cthread_fn_t) master_thread_function,
- (any_t) 0));
+ (any_t) demuxer));
}
diff --git a/libdiskfs/init-init.c b/libdiskfs/init-init.c
index 14c6f84d..cd0c1b29 100644
--- a/libdiskfs/init-init.c
+++ b/libdiskfs/init-init.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 95, 96, 97, 98, 99, 2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -28,12 +28,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
mach_port_t diskfs_default_pager;
mach_port_t diskfs_auth_server_port;
volatile struct mapped_time_value *diskfs_mtime;
+
+struct rwlock diskfs_fsys_lock = RWLOCK_INITIALIZER;
mach_port_t diskfs_fsys_identity;
+int _diskfs_nosuid, _diskfs_noexec;
+int _diskfs_noatime;
+
+struct hurd_port _diskfs_exec_portcell;
+
spin_lock_t diskfs_node_refcnt_lock = SPIN_LOCK_INITIALIZER;
spin_lock_t _diskfs_control_lock = SPIN_LOCK_INITIALIZER;
-int _diskfs_ncontrol_ports = 0;
+int _diskfs_ncontrol_ports;
struct port_class *diskfs_protid_class;
struct port_class *diskfs_control_class;
@@ -44,13 +51,13 @@ struct port_class *diskfs_shutdown_notification_class;
struct port_bucket *diskfs_port_bucket;
/* Call this after arguments have been parsed to initialize the
- library. */
+ library. */
error_t
diskfs_init_diskfs (void)
{
error_t err;
-
- if (diskfs_boot_flags)
+
+ if (diskfs_boot_filesystem ())
/* This is a boot filesystem, we have to do some things specially. */
{
mach_port_t host;
@@ -86,6 +93,8 @@ diskfs_init_diskfs (void)
diskfs_port_bucket = ports_create_bucket ();
+ _hurd_port_init (&_diskfs_exec_portcell, MACH_PORT_NULL);
+
return 0;
}
diff --git a/libdiskfs/init-main.c b/libdiskfs/init-main.c
new file mode 100644
index 00000000..16fdafa4
--- /dev/null
+++ b/libdiskfs/init-main.c
@@ -0,0 +1,78 @@
+/* diskfs_init_main -- initialize diskfs world, parse arguments, and open store
+ Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "diskfs.h"
+#include <argp.h>
+#include <assert.h>
+#include <error.h>
+#include <hurd/store.h>
+
+struct store *
+diskfs_init_main (struct argp *startup_argp,
+ int argc, char **argv,
+ struct store_parsed **store_parsed,
+ mach_port_t *bootstrap)
+{
+ error_t err;
+ struct store_argp_params store_params = { 0 };
+ struct store *store;
+
+ /* We must use ARGP_IN_ORDER for the parsing of --boot-command to work. */
+ err = argp_parse (startup_argp ?: &diskfs_store_startup_argp,
+ argc, argv, ARGP_IN_ORDER, NULL,
+ &store_params);
+ assert_perror (err);
+ *store_parsed = store_params.result;
+
+ err = store_parsed_name (*store_parsed, &diskfs_disk_name);
+ if (err)
+ error (2, err, "store_parsed_name");
+
+ /* This must come after the args have been parsed, as this is where the
+ host priv ports are set for booting. */
+ diskfs_console_stdio ();
+
+ if (diskfs_boot_filesystem ())
+ /* We are the bootstrap filesystem. */
+ *bootstrap = MACH_PORT_NULL;
+ else
+ {
+ task_get_bootstrap_port (mach_task_self (), bootstrap);
+ if (*bootstrap == MACH_PORT_NULL)
+ error (2, 0, "Must be started as a translator");
+ }
+
+ /* Initialize the diskfs library. Must come before any other diskfs call. */
+ err = diskfs_init_diskfs ();
+ if (err)
+ error (4, err, "init");
+
+ err = store_parsed_open (*store_parsed, diskfs_readonly ? STORE_READONLY : 0,
+ &store);
+ if (err)
+ error (3, err, "%s", diskfs_disk_name);
+
+ if (store->flags & STORE_HARD_READONLY)
+ diskfs_readonly = diskfs_hard_readonly = 1;
+
+ /* Start the first request thread, to handle RPCs and page requests. */
+ diskfs_spawn_first_thread (diskfs_demuxer);
+
+ return store;
+}
diff --git a/libdiskfs/init-startup.c b/libdiskfs/init-startup.c
index 885f7ccc..bf1acf29 100644
--- a/libdiskfs/init-startup.c
+++ b/libdiskfs/init-startup.c
@@ -1,5 +1,5 @@
/* diskfs_startup_diskfs -- advertise our fsys control port to our parent FS.
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,98,99,2000,02 Free Software Foundation
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -22,30 +22,84 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
#include <stdio.h>
#include <string.h>
+#include <fcntl.h>
+#include <error.h>
#include <hurd/fsys.h>
#include <hurd/startup.h>
+char *_diskfs_chroot_directory;
+
mach_port_t
diskfs_startup_diskfs (mach_port_t bootstrap, int flags)
{
- mach_port_t realnode;
+ error_t err;
+ mach_port_t realnode, right;
struct port_info *newpi;
-
- if (bootstrap != MACH_PORT_NULL)
+
+ if (_diskfs_chroot_directory != NULL)
{
- errno = ports_create_port (diskfs_control_class, diskfs_port_bucket,
- sizeof (struct port_info), &newpi);
- if (! errno)
+ /* The boot options requested we change to a subdirectory
+ and treat that as the root of the filesystem. */
+ struct node *np, *old;
+ struct protid *rootpi;
+ struct peropen *rootpo;
+
+ /* Skip leading slashes. */
+ while (*_diskfs_chroot_directory == '/')
+ ++_diskfs_chroot_directory;
+
+ mutex_lock (&diskfs_root_node->lock);
+
+ /* Create a protid we can use in diskfs_lookup. */
+ err = diskfs_make_peropen (diskfs_root_node, O_READ|O_EXEC,
+ 0, &rootpo);
+ assert_perror (err);
+ err = diskfs_create_protid (rootpo, 0, &rootpi);
+ assert_perror (err);
+
+ /* Look up the directory name. */
+ err = diskfs_lookup (diskfs_root_node, _diskfs_chroot_directory,
+ LOOKUP, &np, NULL, rootpi);
+ mutex_unlock (&diskfs_root_node->lock);
+ ports_port_deref (rootpi);
+
+ if (err == EAGAIN)
+ error (1, 0, "`--virtual-root=%s' specifies the real root directory",
+ _diskfs_chroot_directory);
+ else if (err)
+ error (1, err, "`%s' not found", _diskfs_chroot_directory);
+
+ if (!S_ISDIR (np->dn_stat.st_mode))
{
- errno = fsys_startup (bootstrap, flags, ports_get_right (newpi),
- MACH_MSG_TYPE_MAKE_SEND, &realnode);
- ports_port_deref (newpi);
+ mutex_unlock (&np->lock);
+ error (1, ENOTDIR, "%s", _diskfs_chroot_directory);
}
- if (errno)
+
+ /* Install this node as the new root, forgetting about the real root
+ node. The last essential piece that makes the virtual root work
+ is in fsys-getroot.c, which sets the first peropen's shadow_root
+ if _diskfs_chroot_directory is non-null. */
+ old = diskfs_root_node;
+ diskfs_root_node = np;
+ mutex_unlock (&np->lock);
+ diskfs_nput (old);
+ }
+
+ if (bootstrap != MACH_PORT_NULL)
+ {
+ err = ports_create_port (diskfs_control_class, diskfs_port_bucket,
+ sizeof (struct port_info), &newpi);
+ if (! err)
{
- perror ("Translator startup failure: fsys_startup");
- exit (1);
+ right = ports_get_send_right (newpi);
+ err = fsys_startup (bootstrap, flags, right,
+ MACH_MSG_TYPE_COPY_SEND, &realnode);
+ mach_port_deallocate (mach_task_self (), right);
+ ports_port_deref (newpi);
}
+ if (err)
+ error (1, err, "Translator startup failure: fsys_startup");
+
mach_port_deallocate (mach_task_self (), bootstrap);
_diskfs_ncontrol_ports++;
@@ -70,22 +124,22 @@ error_t
diskfs_S_startup_dosync (mach_port_t handle)
{
error_t err = 0;
- struct port_info *pi
+ struct port_info *pi
= ports_lookup_port (diskfs_port_bucket, handle,
diskfs_shutdown_notification_class);
if (!pi)
return EOPNOTSUPP;
-
+
if (! diskfs_readonly)
{
/* First start a sync so that if something goes wrong
we at least get this much done. */
diskfs_sync_everything (0);
diskfs_set_hypermetadata (0, 0);
-
+
rwlock_writer_lock (&diskfs_fsys_lock);
-
+
/* Permit all the current RPC's to finish, and then suspend new ones */
err = ports_inhibit_class_rpcs (diskfs_protid_class);
if (! err)
@@ -107,7 +161,7 @@ diskfs_S_startup_dosync (mach_port_t handle)
/* This is called when we have an ordinary environment, complete
with proc and auth ports. */
-void
+void
_diskfs_init_completed ()
{
startup_t init;
@@ -117,12 +171,12 @@ _diskfs_init_completed ()
mach_port_t notify;
char *name;
- /* Contact the startup server and register our shutdown request.
+ /* Contact the startup server and register our shutdown request.
If we get an error, print an informational message. */
proc = getproc ();
assert (proc);
-
+
err = ports_create_port (diskfs_shutdown_notification_class,
diskfs_port_bucket, sizeof (struct port_info),
&pi);
@@ -133,23 +187,21 @@ _diskfs_init_completed ()
mach_port_deallocate (mach_task_self (), proc);
if (err)
goto errout;
-
- notify = ports_get_right (pi);
+
+ notify = ports_get_send_right (pi);
ports_port_deref (pi);
- asprintf (&name, "%s %s", program_invocation_short_name,
- diskfs_device_arg);
- err = startup_request_notification (init, notify,
- MACH_MSG_TYPE_MAKE_SEND, name);
+ asprintf (&name,
+ "%s %s", program_invocation_short_name, diskfs_disk_name ?: "-");
+ err = startup_request_notification (init, notify,
+ MACH_MSG_TYPE_COPY_SEND, name);
+ mach_port_deallocate (mach_task_self (), notify);
free (name);
if (err)
goto errout;
-
+
mach_port_deallocate (mach_task_self (), init);
return;
errout:
- fprintf (stderr, "Cannot request shutdown notification: %s\n",
- strerror (err));
+ error (0, err, "Cannot request shutdown notification");
}
-
-
diff --git a/libdiskfs/io-duplicate.c b/libdiskfs/io-duplicate.c
index addefc48..3cbf8f7b 100644
--- a/libdiskfs/io-duplicate.c
+++ b/libdiskfs/io-duplicate.c
@@ -32,8 +32,7 @@ diskfs_S_io_duplicate (struct protid *cred,
mutex_lock (&cred->po->np->lock);
- err = diskfs_create_protid (cred->po, cred->uids, cred->nuids,
- cred->gids, cred->ngids, &newpi);
+ err = diskfs_create_protid (cred->po, cred->user, &newpi);
if (! err)
{
*port = ports_get_right (newpi);
diff --git a/libdiskfs/io-identity.c b/libdiskfs/io-identity.c
index 2cd64907..6f4e7546 100644
--- a/libdiskfs/io-identity.c
+++ b/libdiskfs/io-identity.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of io_identity RPC
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,98,2001,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,26 +28,40 @@ diskfs_S_io_identity (struct protid *cred,
mach_msg_type_name_t *idtype,
mach_port_t *fsys,
mach_msg_type_name_t *fsystype,
- int *fileno)
+ ino_t *fileno)
{
struct node *np;
error_t err;
+ ino_t inum;
if (!cred)
return EOPNOTSUPP;
-
+
np = cred->po->np;
mutex_lock (&np->lock);
-
- err = fshelp_get_identity (diskfs_port_bucket, np->dn_stat.st_ino, id);
- if (!err)
+ inum = np->dn_stat.st_ino;
+ mutex_unlock (&np->lock);
+
+ err = fshelp_get_identity (diskfs_port_bucket, inum, id);
+ if (! err)
+ {
+ if (cred->po->shadow_root && cred->po->shadow_root != diskfs_root_node)
+ {
+ err = fshelp_get_identity (diskfs_port_bucket,
+ cred->po->shadow_root->dn_stat.st_ino,
+ fsys);
+ if (err)
+ mach_port_deallocate (mach_task_self (), *id);
+ }
+ else
+ *fsys = diskfs_fsys_identity;
+ }
+ if (! err)
{
*idtype = MACH_MSG_TYPE_MAKE_SEND;
- *fsys = diskfs_fsys_identity;
*fsystype = MACH_MSG_TYPE_MAKE_SEND;
- *fileno = np->dn_stat.st_ino;
+ *fileno = inum;
}
-
- mutex_unlock (&np->lock);
+
return err;
}
diff --git a/libdiskfs/io-map-cntl.c b/libdiskfs/io-map-cntl.c
index b45ccffd..d615b046 100644
--- a/libdiskfs/io-map-cntl.c
+++ b/libdiskfs/io-map-cntl.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,96,2002 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
@@ -34,8 +34,8 @@ diskfs_S_io_map_cntl (struct protid *cred,
{
default_pager_object_create (diskfs_default_pager, &cred->shared_object,
__vm_page_size);
- vm_map (mach_task_self (), (u_int *)&cred->mapped, vm_page_size, 0, 1,
- cred->shared_object, 0, 0,
+ vm_map (mach_task_self (), (vm_address_t *)&cred->mapped, vm_page_size,
+ 0, 1, cred->shared_object, 0, 0,
VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE, 0);
cred->mapped->shared_page_magic = SHARED_PAGE_MAGIC;
cred->mapped->conch_status = USER_HAS_NOT_CONCH;
diff --git a/libdiskfs/io-map.c b/libdiskfs/io-map.c
index c9e897c6..6268f2c5 100644
--- a/libdiskfs/io-map.c
+++ b/libdiskfs/io-map.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -44,13 +44,19 @@ diskfs_S_io_map (struct protid *cred,
{
case O_READ | O_WRITE:
*wrobj = *rdobj = diskfs_get_filemap (node, VM_PROT_READ |VM_PROT_WRITE);
+ if (*wrobj == MACH_PORT_NULL)
+ goto error;
mach_port_mod_refs (mach_task_self (), *rdobj, MACH_PORT_RIGHT_SEND, 1);
break;
case O_READ:
*rdobj = diskfs_get_filemap (node, VM_PROT_READ);
+ if (*rdobj == MACH_PORT_NULL)
+ goto error;
break;
case O_WRITE:
*wrobj = diskfs_get_filemap (node, VM_PROT_WRITE);
+ if (*wrobj == MACH_PORT_NULL)
+ goto error;
break;
}
mutex_unlock (&node->lock);
@@ -59,4 +65,9 @@ diskfs_S_io_map (struct protid *cred,
*wrtype = MACH_MSG_TYPE_MOVE_SEND;
return 0;
+
+error:
+ mutex_unlock (&node->lock);
+ return errno;
}
+
diff --git a/libdiskfs/io-pathconf.c b/libdiskfs/io-pathconf.c
index 0b80b14e..38e277c3 100644
--- a/libdiskfs/io-pathconf.c
+++ b/libdiskfs/io-pathconf.c
@@ -1,5 +1,5 @@
/* libdiskfs implementation of io.defs: io_pathconf
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1992, 1993, 1994, 1995, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,16 +15,66 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <unistd.h>
#include "priv.h"
#include "io_S.h"
+#include <dirent.h>
+#include <limits.h>
/* Implement io_pathconf as described in <hurd/io.defs>. */
kern_return_t
diskfs_S_io_pathconf (struct protid *cred,
- int name __attribute__ ((unused)), int *value)
+ int name,
+ int *value)
{
if (!cred)
return EOPNOTSUPP;
- *value = 0; /* XXX */
+
+ switch (name)
+ {
+ case _PC_LINK_MAX:
+ *value = diskfs_link_max;
+ break;
+
+ case _PC_MAX_CANON:
+ case _PC_MAX_INPUT:
+ case _PC_PIPE_BUF:
+ case _PC_VDISABLE:
+ case _PC_SOCK_MAXBUF:
+ case _PC_PATH_MAX:
+ *value = -1;
+ break;
+
+ case _PC_NAME_MAX:
+ /* <hurd/hurd_types.defs> string_t constrains the upper bound.
+ The `struct dirent' format defined by libc further contrains it. */
+#define D_NAMLEN_MAX (UCHAR_MAX * sizeof (((struct dirent *) 0)->d_namlen))
+ if (diskfs_name_max > D_NAMLEN_MAX || diskfs_name_max < 0)
+ diskfs_name_max = D_NAMLEN_MAX;
+ *value = diskfs_name_max;
+ break;
+
+ case _PC_NO_TRUNC: /* enforced in diskfs_lookup */
+ *value = 1; /* diskfs_name_max >= 0; */ /* see above */
+ break;
+
+ case _PC_CHOWN_RESTRICTED:
+ case _PC_SYNC_IO:
+ case _PC_ASYNC_IO:
+ *value = 1;
+ break;
+
+ case _PC_PRIO_IO:
+ *value = 0;
+ break;
+
+ case _PC_FILESIZEBITS:
+ *value = 32;
+ break;
+
+ default:
+ return EINVAL;
+ }
+
return 0;
}
diff --git a/libdiskfs/io-prenotify.c b/libdiskfs/io-prenotify.c
index 4ae3967b..f193f52b 100644
--- a/libdiskfs/io-prenotify.c
+++ b/libdiskfs/io-prenotify.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,7 +22,7 @@
We set the prenotify size to be the allocated size of the file;
then users are forced to call this routine before writing past
- that, and we can do allocation (orreturn ENOSPC if necessary. */
+ that, and we can do allocation (or return ENOSPC if necessary). */
kern_return_t
diskfs_S_io_prenotify (struct protid *cred,
vm_offset_t start __attribute__ ((unused)),
@@ -64,6 +64,8 @@ diskfs_S_io_prenotify (struct protid *cred,
err = diskfs_grow (np, end, cred);
if (diskfs_synchronous)
diskfs_node_update (np, 1);
+ if (!err && np->filemod_reqs)
+ diskfs_notice_filechange (np, FILE_CHANGED_EXTEND, 0, end);
out:
mutex_unlock (&np->lock);
return err;
diff --git a/libdiskfs/io-read.c b/libdiskfs/io-read.c
index a5dd148a..787c0eae 100644
--- a/libdiskfs/io-read.c
+++ b/libdiskfs/io-read.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,99,2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -29,7 +29,7 @@ diskfs_S_io_read (struct protid *cred,
{
struct node *np;
int err;
- int off = offset;
+ off_t off = offset;
char *buf;
int ourbuf = 0;
@@ -46,6 +46,11 @@ diskfs_S_io_read (struct protid *cred,
if (off == -1)
off = cred->po->filepointer;
+ if (off < 0)
+ {
+ mutex_unlock (&np->lock);
+ return EINVAL;
+ }
if (off > np->dn_stat.st_size)
maxread = 0;
@@ -55,24 +60,49 @@ diskfs_S_io_read (struct protid *cred,
if (maxread > *datalen)
{
ourbuf = 1;
- vm_allocate (mach_task_self (), (u_int *) &buf, maxread, 1);
+ buf = mmap (0, maxread, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
*data = buf;
}
else
buf = *data;
*datalen = maxread;
- if (maxread)
+
+ if (maxread == 0)
+ err = 0;
+ else if (S_ISLNK (np->dn_stat.st_mode))
+ {
+ /* Read from a symlink. */
+ if (! diskfs_read_symlink_hook)
+ err = EINVAL;
+ else
+ {
+ if (off == 0 && maxread == np->dn_stat.st_size)
+ err = (*diskfs_read_symlink_hook)(np, buf);
+ else
+ {
+ char *whole_link = alloca (np->dn_stat.st_size);
+ err = (*diskfs_read_symlink_hook)(np, whole_link);
+ if (! err)
+ memcpy (buf, whole_link + off, maxread);
+ }
+ }
+ }
+ else
+ err = EINVAL; /* Use read below. */
+
+ if (err == EINVAL)
err = _diskfs_rdwr_internal (np, buf, off, datalen, 0,
cred->po->openstat & O_NOATIME);
- else
- err = 0;
+
if (diskfs_synchronous)
diskfs_node_update (np, 1); /* atime! */
+
if (offset == -1 && !err)
cred->po->filepointer += *datalen;
+
if (err && ourbuf)
- vm_deallocate (mach_task_self (), (u_int) buf, maxread);
+ munmap (buf, maxread);
mutex_unlock (&np->lock);
return err;
diff --git a/libdiskfs/io-reauthenticate.c b/libdiskfs/io-reauthenticate.c
index 9b065a3b..3c5da52d 100644
--- a/libdiskfs/io-reauthenticate.c
+++ b/libdiskfs/io-reauthenticate.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,2000,01 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
@@ -24,22 +24,14 @@ diskfs_S_io_reauthenticate (struct protid *cred,
mach_port_t rend_port)
{
struct protid *newcred;
- uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
- uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
- u_int genuidlen, gengidlen, auxuidlen, auxgidlen;
error_t err;
mach_port_t newright;
+ struct iouser *user;
if (cred == 0)
return EOPNOTSUPP;
- genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
- gen_uids = gubuf;
- gen_gids = ggbuf;
- aux_uids = aubuf;
- aux_gids = agbuf;
-
- /* This routine must carefully ignore EINTR because we
+ /* This routine must carefully ignore EINTR because we
are a simpleroutine, so callers won't know to restart. */
mutex_lock (&cred->po->np->lock);
@@ -52,44 +44,23 @@ diskfs_S_io_reauthenticate (struct protid *cred,
return err;
}
- newright = ports_get_right (newcred);
- err = mach_port_insert_right (mach_task_self (), newright, newright,
- MACH_MSG_TYPE_MAKE_SEND);
- assert_perror (err);
- do
- err = auth_server_authenticate (diskfs_auth_server_port,
- rend_port,
- MACH_MSG_TYPE_COPY_SEND,
- newright,
- MACH_MSG_TYPE_COPY_SEND,
- &gen_uids, &genuidlen,
- &aux_uids, &auxuidlen,
- &gen_gids, &gengidlen,
- &aux_gids, &auxgidlen);
- while (err == EINTR);
- mach_port_deallocate (mach_task_self (), rend_port);
+ newright = ports_get_send_right (newcred);
+ assert (newright != MACH_PORT_NULL);
+
+ err = iohelp_reauth (&user, diskfs_auth_server_port, rend_port,
+ newright, 1);
+ if (! err)
+ {
+ diskfs_finish_protid (newcred, user);
+ iohelp_free_iouser (user);
+ mach_port_deallocate (mach_task_self (), rend_port);
+ }
+
mach_port_deallocate (mach_task_self (), newright);
-
- if (err)
- diskfs_finish_protid (newcred, 0, 0, 0, 0);
- else
- diskfs_finish_protid (newcred, gen_uids, genuidlen, gen_gids, gengidlen);
+
mutex_unlock (&cred->po->np->lock);
ports_port_deref (newcred);
- if (gubuf != gen_uids)
- vm_deallocate (mach_task_self (), (u_int) gen_uids,
- genuidlen * sizeof (uid_t));
- if (ggbuf != gen_gids)
- vm_deallocate (mach_task_self (), (u_int) gen_gids,
- gengidlen * sizeof (uid_t));
- if (aubuf != aux_uids)
- vm_deallocate (mach_task_self (), (u_int) aux_uids,
- auxuidlen * sizeof (uid_t));
- if (agbuf != aux_gids)
- vm_deallocate (mach_task_self (), (u_int) aux_gids,
- auxgidlen * sizeof (uid_t));
-
- return 0;
+ return err;
}
diff --git a/libdiskfs/io-restrict-auth.c b/libdiskfs/io-restrict-auth.c
index f2e00293..c1560ac1 100644
--- a/libdiskfs/io-restrict-auth.c
+++ b/libdiskfs/io-restrict-auth.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,95,96,2001, 2002 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,16 +18,6 @@
#include "priv.h"
#include "io_S.h"
-/* Tell if the array LIST (of size N) contains a member equal to QUERY. */
-static inline int
-listmember (int *list, int query, int n)
-{
- int i;
- for (i = 0; i < n; i++)
- if (list[i] == query)
- return 1;
- return 0;
-}
/* Implement io_restrict_auth as described in <hurd/io.defs>. */
kern_return_t
@@ -35,31 +25,23 @@ diskfs_S_io_restrict_auth (struct protid *cred,
mach_port_t *newport,
mach_msg_type_name_t *newportpoly,
uid_t *uids,
- u_int nuids,
+ size_t nuids,
gid_t *gids,
- u_int ngids)
+ size_t ngids)
{
error_t err;
- uid_t *newuids, *newgids;
- int i, newnuids, newngids;
+ struct iouser *user;
struct protid *newpi;
-
+
if (!cred)
return EOPNOTSUPP;
-
- newuids = alloca (sizeof (uid_t) * cred->nuids);
- newgids = alloca (sizeof (uid_t) * cred->ngids);
-
- for (i = newnuids = 0; i < cred->nuids; i++)
- if (listmember (uids, cred->uids[i], nuids))
- newuids[newnuids++] = cred->uids[i];
- for (i = newngids = 0; i < cred->ngids; i++)
- if (listmember (gids, cred->gids[i], ngids))
- newgids[newngids++] = cred->gids[i];
-
+
+ err = iohelp_restrict_iouser (&user, cred->user, uids, nuids, gids, ngids);
+ if (err)
+ return err;
+
mutex_lock (&cred->po->np->lock);
- err = diskfs_create_protid (cred->po, newuids, newnuids, newgids, newngids,
- &newpi);
+ err = diskfs_create_protid (cred->po, user, &newpi);
if (! err)
{
*newport = ports_get_right (newpi);
@@ -68,5 +50,6 @@ diskfs_S_io_restrict_auth (struct protid *cred,
}
mutex_unlock (&cred->po->np->lock);
+ iohelp_free_iouser (user);
return err;
}
diff --git a/libdiskfs/io-revoke.c b/libdiskfs/io-revoke.c
new file mode 100644
index 00000000..d42fb6c1
--- /dev/null
+++ b/libdiskfs/io-revoke.c
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 1999 Free Software Foundation
+ Written by Thomas Bushnell, BSG.
+
+ 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. */
+
+#include "priv.h"
+#include "io_S.h"
+
+/* Implement io_revoke as described in <hurd/io.defs>. */
+kern_return_t
+diskfs_S_io_revoke (struct protid *cred)
+{
+ error_t err;
+ struct node *np;
+
+ error_t
+ iterator_function (void *port)
+ {
+ struct protid *user = port;
+
+ if ((user != cred)
+ && (user->po->np == np))
+ ports_destroy_right (user);
+ return 0;
+ }
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+
+ mutex_lock (&np->lock);
+
+ err = fshelp_isowner (&np->dn_stat, cred->user);
+
+ mutex_unlock (&np->lock);
+
+ if (err)
+ return err;
+
+ ports_inhibit_bucket_rpcs (diskfs_port_bucket);
+ ports_class_iterate (diskfs_protid_class, iterator_function);
+ ports_resume_bucket_rpcs (diskfs_port_bucket);
+
+ return 0;
+}
diff --git a/libdiskfs/io-seek.c b/libdiskfs/io-seek.c
index 33aa77d4..71179816 100644
--- a/libdiskfs/io-seek.c
+++ b/libdiskfs/io-seek.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,1995,1996,2000,2006 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
@@ -19,9 +19,6 @@
#include "io_S.h"
#include <unistd.h>
-#define diskfs_readonly 0
-#define diskfs_synchronous 0
-
/* Implement io_seek as described in <hurd/io.defs>. */
kern_return_t
diskfs_S_io_seek (struct protid *cred,
@@ -29,29 +26,36 @@ diskfs_S_io_seek (struct protid *cred,
int whence,
off_t *newoffset)
{
-
- CHANGE_NODE_FIELD (cred,
- ({
- iohelp_get_conch (&np->conch);
- switch (whence)
- {
- case SEEK_SET:
- err = 0;
- cred->po->filepointer = offset;
- break;
- case SEEK_CUR:
- err = 0;
- cred->po->filepointer += offset;
- break;
- case SEEK_END:
- err = 0;
- cred->po->filepointer = (np->dn_stat.st_size
- + offset);
- break;
- default:
- err = EINVAL;
- break;
- }
- *newoffset = cred->po->filepointer;
- }));
+ error_t err = 0;
+ struct node *np;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+
+ mutex_lock (&np->lock);
+
+ iohelp_get_conch (&np->conch);
+ switch (whence)
+ {
+ case SEEK_CUR:
+ offset += cred->po->filepointer;
+ goto check;
+ case SEEK_END:
+ offset += np->dn_stat.st_size;
+ case SEEK_SET:
+ check:
+ if (offset >= 0)
+ {
+ *newoffset = cred->po->filepointer = offset;
+ break;
+ }
+ default:
+ err = EINVAL;
+ break;
+ }
+
+ mutex_unlock (&np->lock);
+ return err;
}
diff --git a/libdiskfs/io-stat.c b/libdiskfs/io-stat.c
index df8b4291..59f3187e 100644
--- a/libdiskfs/io-stat.c
+++ b/libdiskfs/io-stat.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,95,96,97,2001 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
@@ -28,15 +28,24 @@ diskfs_S_io_stat (struct protid *cred,
if (!cred)
return EOPNOTSUPP;
-
+
np = cred->po->np;
mutex_lock (&np->lock);
+
iohelp_get_conch (&np->conch);
if (diskfs_synchronous)
diskfs_node_update (np, 1);
else
diskfs_set_node_times (np);
- bcopy (&np->dn_stat, statbuf, sizeof (struct stat));
+
+ memcpy (statbuf, &np->dn_stat, sizeof (struct stat));
+ statbuf->st_mode &= ~(S_IATRANS | S_IROOT);
+ if (fshelp_translated (&np->transbox))
+ statbuf->st_mode |= S_IATRANS;
+ if (cred->po->shadow_root == np || np == diskfs_root_node)
+ statbuf->st_mode |= S_IROOT;
+
mutex_unlock (&np->lock);
+
return 0;
}
diff --git a/libdiskfs/io-version.c b/libdiskfs/io-version.c
index a1f12d79..b19dd0d1 100644
--- a/libdiskfs/io-version.c
+++ b/libdiskfs/io-version.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 1996 Free Software Foundation
This file is part of the GNU Hurd.
@@ -19,6 +19,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
+#include <stdio.h>
+
#include "priv.h"
#include "io_S.h"
@@ -31,10 +33,8 @@ diskfs_S_io_server_version (struct protid *cred,
{
if (cred)
{
- strcpy (server_name, diskfs_server_name);
- *major = diskfs_major_version;
- *minor = diskfs_minor_version;
- *edit = diskfs_edit_version;
+ snprintf (server_name, sizeof (string_t), "%s %s",
+ diskfs_server_name, diskfs_server_version);
return 0;
}
else
diff --git a/libdiskfs/io-write.c b/libdiskfs/io-write.c
index 8b68e1a1..a3c4199e 100644
--- a/libdiskfs/io-write.c
+++ b/libdiskfs/io-write.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,97,2001 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
@@ -29,7 +29,7 @@ diskfs_S_io_write (struct protid *cred,
{
struct node *np;
error_t err;
- int off = offset;
+ off_t off = offset;
if (!cred)
return EOPNOTSUPP;
@@ -50,6 +50,11 @@ diskfs_S_io_write (struct protid *cred,
cred->po->filepointer = np->dn_stat.st_size;
off = cred->po->filepointer;
}
+ if (off < 0)
+ {
+ err = EINVAL;
+ goto out;
+ }
err = 0;
while (off + (off_t) datalen > np->allocsize)
@@ -59,6 +64,8 @@ diskfs_S_io_write (struct protid *cred,
diskfs_node_update (np, 1);
if (err)
goto out;
+ if (np->filemod_reqs)
+ diskfs_notice_filechange (np, FILE_CHANGED_EXTEND, 0, off + datalen);
}
if (off + (off_t) datalen > np->dn_stat.st_size)
@@ -79,6 +86,8 @@ diskfs_S_io_write (struct protid *cred,
&& ((cred->po->openstat & O_FSYNC) || diskfs_synchronous))
diskfs_file_update (np, 1);
+ if (!err && np->filemod_reqs)
+ diskfs_notice_filechange (np, FILE_CHANGED_WRITE, off, off + *amt);
out:
mutex_unlock (&np->lock);
return err;
diff --git a/libdiskfs/lithp.h b/libdiskfs/lithp.h
index fa312fd2..be56377d 100644
--- a/libdiskfs/lithp.h
+++ b/libdiskfs/lithp.h
@@ -22,9 +22,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Hmm. */
#define dithkfth_TH_file_chauthor diskfs_S_file_chauthor
-#define dithkfth_ithowner diskfs_isowner
+#define fthhelp_ithowner fshelp_isowner
#define dithkfth_validate_author_change diskfs_validate_author_change
#define dn_thtat dn_stat
#define tht_author st_author
#define dn_thet_theetime dn_set_ctime
#define fth_TH_dot_h "fs_S.h"
+#define uther user
diff --git a/libdiskfs/lookup.c b/libdiskfs/lookup.c
index 40ce8937..1f2a2588 100644
--- a/libdiskfs/lookup.c
+++ b/libdiskfs/lookup.c
@@ -1,5 +1,5 @@
/* Wrapper for diskfs_lookup_hard
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -19,11 +19,28 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "priv.h"
+#include <string.h>
+
+static struct
+{
+ int present;
+ int absent;
+ int errors;
+ int dot;
+ int dotdot;
+} cache_misses;
+static spin_lock_t cm_lock = SPIN_LOCK_INITIALIZER;
+
/* Lookup in directory DP (which is locked) the name NAME. TYPE will
either be LOOKUP, CREATE, RENAME, or REMOVE. CRED identifies the
user making the call.
+ NAME will have leading and trailing slashes stripped. It is an
+ error if there are internal slashes. NAME will be modified in
+ place if there are slashes in it; it is therefore an error to
+ specify a constant NAME which contains slashes.
+
If the name is found, return zero, and (if NP is nonzero) set *NP
to point to the node for it, locked. If the name is not found,
return ENOENT, and (if NP is nonzero) set *NP to zero. If NP is
@@ -62,16 +79,15 @@
Return ENOENT if NAME isn't in the directory.
Return EAGAIN if NAME refers to the `..' of this filesystem's root.
Return EIO if appropriate.
-
- This function is a wrapper for diskfs_lookup_hard.
-*/
-error_t
-diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
- struct node **np, struct dirstat *ds,
- struct protid *cred)
+
+ This function is a wrapper for diskfs_lookup_hard. */
+error_t
+diskfs_lookup (struct node *dp, const char *name, enum lookup_type type,
+ struct node **np, struct dirstat *ds, struct protid *cred)
{
error_t err;
-
+ struct node *cached;
+
if (type == REMOVE || type == RENAME)
assert (np);
@@ -81,7 +97,37 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
diskfs_null_dirstat (ds);
return ENOTDIR;
}
- err = diskfs_access (dp, S_IEXEC, cred);
+
+ /* Strip leading and trailing slashes. */
+ while (*name == '/')
+ name++;
+
+ if (name[0] == '\0')
+ {
+ if (ds)
+ diskfs_null_dirstat (ds);
+ return EINVAL;
+ }
+ else
+ {
+ char *p = strchr (name, '/');
+ if (p != 0)
+ {
+ *p = '\0';
+ do
+ ++p;
+ while (*p == '/');
+ if (*p != '\0')
+ {
+ if (ds)
+ diskfs_null_dirstat (ds);
+ return EINVAL;
+ }
+ }
+ }
+
+
+ err = fshelp_access (&dp->dn_stat, S_IEXEC, cred->user);
if (err)
{
if (ds)
@@ -89,55 +135,100 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
return err;
}
+ if (dp == cred->po->shadow_root
+ && name[0] == '.' && name[1] == '.' && name[2] == '\0')
+ /* Ran into the root. */
+ {
+ if (ds)
+ diskfs_null_dirstat (ds);
+ return EAGAIN;
+ }
+
if (type == LOOKUP)
+ /* Check the cache first */
+ cached = diskfs_check_lookup_cache (dp, name);
+ else
+ cached = 0;
+
+ if (cached == (struct node *)-1)
+ /* Negative lookup cached. */
+ {
+ if (np)
+ *np = 0;
+ return ENOENT;
+ }
+ else if (cached)
{
- /* Check the cache first */
- struct node *cached = diskfs_check_lookup_cache (dp, name);
+ if (np)
+ *np = cached; /* Return what we found. */
+ else
+ /* Ick, the user doesn't want the result, we have to drop our
+ reference. */
+ if (cached == dp)
+ diskfs_nrele (cached);
+ else
+ diskfs_nput (cached);
- if (cached == (struct node *)-1)
- /* Negative lookup cached. */
- {
- if (np)
- *np = 0;
- return ENOENT;
- }
- else if (cached)
+ if (ds)
+ diskfs_null_dirstat (ds);
+ }
+ else
+ {
+ err = diskfs_lookup_hard (dp, name, type, np, ds, cred);
+
+ spin_lock (&cm_lock);
+ if (type == LOOKUP)
{
- if (np)
- *np = cached; /* Return what we found. */
+ if (err == ENOENT)
+ cache_misses.absent++;
+ else if (err)
+ cache_misses.errors++;
else
- /* Ick, the user doesn't want the result, we have to drop our
- reference. */
- if (cached == dp)
- diskfs_nrele (cached);
- else
- diskfs_nput (cached);
- if (ds)
- diskfs_null_dirstat (ds);
- return 0;
+ cache_misses.present++;
+ if (name[0] == '.')
+ {
+ if (name[1] == '\0')
+ cache_misses.dot++;
+ else if (name[1] == '.' && name[2] == '\0')
+ cache_misses.dotdot++;
+ }
}
- }
-
- err = diskfs_lookup_hard (dp, name, type, np, ds, cred);
- if (err && err != ENOENT)
- return err;
-
- if (type == RENAME
- || (type == CREATE && err == ENOENT)
- || (type == REMOVE && err != ENOENT))
- {
- error_t err2 = diskfs_checkdirmod (dp, (err || !np) ? 0 : *np, cred);
- if (err2)
+ spin_unlock (&cm_lock);
+
+ if (err && err != ENOENT)
+ return err;
+
+ if (type == RENAME
+ || (type == CREATE && err == ENOENT)
+ || (type == REMOVE && err != ENOENT))
{
- if (np && !err)
- diskfs_nput (*np);
- return err2;
+ error_t err2;
+
+ if (diskfs_name_max > 0 && strlen (name) > diskfs_name_max)
+ err2 = ENAMETOOLONG;
+ else
+ err2 = fshelp_checkdirmod (&dp->dn_stat,
+ (err || !np) ? 0 : &(*np)->dn_stat,
+ cred->user);
+ if (err2)
+ {
+ if (np && !err)
+ {
+ if (*np == dp)
+ diskfs_nrele (*np);
+ else
+ diskfs_nput (*np);
+ *np = 0;
+ }
+ return err2;
+ }
}
+
+ if ((type == LOOKUP || type == CREATE) && !err && np)
+ diskfs_enter_lookup_cache (dp, *np, name);
+ else if (type == LOOKUP && err == ENOENT)
+ diskfs_enter_lookup_cache (dp, 0, name);
}
- if ((type == LOOKUP || type == CREATE) && !err && np)
- diskfs_enter_lookup_cache (dp, *np, name);
-
return err;
}
-
diff --git a/libdiskfs/machdev.c b/libdiskfs/machdev.c
deleted file mode 100644
index 786bf0ab..00000000
--- a/libdiskfs/machdev.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Get mach device info
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <stdio.h>
-
-#include <device/device.h>
-
-#include "priv.h"
-
-/* Returns a send right to for the mach device called NAME, and returns it in
- PORT. Other values returned are START, the first valid offset, SIZE, the
- the number of blocks after START, and BLOCK_SIZE, the units in which the
- device is addressed.
-
- The device is opened for reading, and if the diskfs global variable
- DISKFS_READ_ONLY is false, writing.
-
- If NAME cannot be opened and this is a bootstrap filename, the user will
- be prompted for new names until a valid one is found. */
-error_t
-diskfs_get_mach_device (char *name,
- mach_port_t *port,
- off_t *start, off_t *size, size_t *block_size)
-{
- error_t err = 0;
-
- do
- {
- mach_port_t dev_master;
-
- err = get_privileged_ports (0, &dev_master);
- if (err)
- return err;
-
- err = device_open (dev_master,
- (diskfs_readonly ? 0 : D_WRITE) | D_READ,
- name, port);
-
- if (err == D_NO_SUCH_DEVICE && diskfs_boot_flags)
- /* If this is a bootstrap filesystem, prompt the user to give us
- another name rather than just crashing. */
- {
- char *line = 0;
- size_t linesz = 0;
- ssize_t len;
-
- printf ("Cannot open device %s\n", name);
- printf ("Open instead: ");
- fflush (stdout);
- len = getline (&line, &linesz, stdin);
- if (len > 2)
- name = line;
- }
-
- mach_port_deallocate (mach_task_self (), dev_master);
- }
- while (err == D_NO_SUCH_DEVICE && diskfs_boot_flags);
-
- if (!err)
- {
- unsigned sizes_len = DEV_GET_SIZE_COUNT;
- size_t sizes[DEV_GET_SIZE_COUNT];
-
- err = device_get_status (*port, DEV_GET_SIZE, sizes, &sizes_len);
- assert (sizes_len == DEV_GET_SIZE_COUNT);
-
- *start = 0;
- *size = sizes[DEV_GET_SIZE_DEVICE_SIZE];
- *block_size = sizes[DEV_GET_SIZE_RECORD_SIZE];
- if (*block_size > 1)
- *size /= *block_size;
- }
-
- return err;
-}
diff --git a/libdiskfs/name-cache.c b/libdiskfs/name-cache.c
index 2cf1ed8b..f31482d4 100644
--- a/libdiskfs/name-cache.c
+++ b/libdiskfs/name-cache.c
@@ -1,6 +1,6 @@
/* Directory name lookup caching
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG, & Miles Bader.
This file is part of the GNU Hurd.
@@ -24,7 +24,7 @@
#include <cacheq.h>
/* Maximum number of names to cache at once */
-#define MAXCACHE 256
+#define MAXCACHE 200
/* Maximum length of file name we bother caching */
#define CACHE_NAME_LEN 100
@@ -44,7 +44,10 @@ struct lookup_cache
char name[CACHE_NAME_LEN];
/* Strlen of NAME. If this is zero, it's an unused entry. */
- size_t name_len;
+ size_t name_len;
+
+ /* XXX */
+ int stati;
};
/* The contents of the cache in no particular order */
@@ -53,28 +56,39 @@ static struct cacheq lookup_cache = { sizeof (struct lookup_cache) };
static spin_lock_t cache_lock = SPIN_LOCK_INITIALIZER;
/* Buffer to hold statistics */
-static struct
+static struct stats
{
long pos_hits;
long neg_hits;
long miss;
long fetch_errors;
} statistics;
+
+#define PARTIAL_THRESH 100
+#define NPARTIALS MAXCACHE / PARTIAL_THRESH
+struct stats partial_stats [NPARTIALS];
+
/* If there's an entry for NAME, of length NAME_LEN, in directory DIR in the
- cache, return it's entry, otherwise 0. CACHE_LOCK must be held. */
+ cache, return its entry, otherwise 0. CACHE_LOCK must be held. */
static struct lookup_cache *
find_cache (struct node *dir, const char *name, size_t name_len)
{
struct lookup_cache *c;
+ int i;
/* Search the list. All unused entries are contiguous at the end of the
list, so we can stop searching when we see the first one. */
- for (c = lookup_cache.mru; c && c->name_len; c = c->hdr.next)
+ for (i = 0, c = lookup_cache.mru;
+ c && c->name_len;
+ c = c->hdr.next, i++)
if (c->name_len == name_len
&& c->dir_cache_id == dir->cache_id
&& c->name[0] == name[0] && strcmp (c->name, name) == 0)
- return c;
+ {
+ c->stati = i / 100;
+ return c;
+ }
return 0;
}
@@ -82,19 +96,12 @@ find_cache (struct node *dir, const char *name, size_t name_len)
/* Node NP has just been found in DIR with NAME. If NP is null, that
means that this name has been confirmed as absent in the directory. */
void
-diskfs_enter_lookup_cache (struct node *dir, struct node *np, char *name)
+diskfs_enter_lookup_cache (struct node *dir, struct node *np, const char *name)
{
struct lookup_cache *c;
size_t name_len = strlen (name);
-
- if (name_len > CACHE_NAME_LEN - 1)
- return;
- /* Never cache . or ..; it's too much trouble to get the locking
- order right. */
- if (name[0] == '.'
- && (name[1] == '\0'
- || (name[1] == '.' && name[2] == '\0')))
+ if (name_len > CACHE_NAME_LEN - 1)
return;
spin_lock (&cache_lock);
@@ -120,13 +127,13 @@ diskfs_enter_lookup_cache (struct node *dir, struct node *np, char *name)
spin_unlock (&cache_lock);
}
-/* Purge all references in the cache to NP as a node inside
+/* Purge all references in the cache to NP as a node inside
directory DP. */
void
diskfs_purge_lookup_cache (struct node *dp, struct node *np)
{
struct lookup_cache *c, *next;
-
+
spin_lock (&cache_lock);
for (c = lookup_cache.mru; c; c = next)
{
@@ -145,15 +152,56 @@ diskfs_purge_lookup_cache (struct node *dp, struct node *np)
spin_unlock (&cache_lock);
}
+/* Register a negative hit for an entry in the Nth stat class */
+void
+register_neg_hit (int n)
+{
+ int i;
+
+ statistics.neg_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].neg_hits++;
+}
+
+/* Register a positive hit for an entry in the Nth stat class */
+void
+register_pos_hit (int n)
+{
+ int i;
+
+ statistics.pos_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].pos_hits++;
+}
+
+/* Register a miss */
+void
+register_miss ()
+{
+ int i;
+
+ statistics.miss++;
+ for (i = 0; i < NPARTIALS; i++)
+ partial_stats[i].miss++;
+}
+
+
+
/* Scan the cache looking for NAME inside DIR. If we don't know
anything entry at all, then return 0. If the entry is confirmed to
not exist, then return -1. Otherwise, return NP for the entry, with
a newly allocated reference. */
struct node *
-diskfs_check_lookup_cache (struct node *dir, char *name)
+diskfs_check_lookup_cache (struct node *dir, const char *name)
{
struct lookup_cache *c;
-
+
spin_lock (&cache_lock);
c = find_cache (dir, name, strlen (name));
@@ -163,15 +211,18 @@ diskfs_check_lookup_cache (struct node *dir, char *name)
cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */
- statistics.pos_hits++;
- spin_unlock (&cache_lock);
-
if (id == 0)
/* A negative cache entry. */
- return (struct node *)-1;
+ {
+ register_neg_hit (c->stati);
+ spin_unlock (&cache_lock);
+ return (struct node *)-1;
+ }
else if (id == dir->cache_id)
/* The cached node is the same as DIR. */
{
+ register_pos_hit (c->stati);
+ spin_unlock (&cache_lock);
diskfs_nref (dir);
return dir;
}
@@ -179,12 +230,35 @@ diskfs_check_lookup_cache (struct node *dir, char *name)
/* Just a normal entry in DIR; get the actual node. */
{
struct node *np;
- error_t err = diskfs_cached_lookup (id, &np);
+ error_t err;
+
+ register_pos_hit (c->stati);
+ spin_unlock (&cache_lock);
+
+ if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
+ {
+ mutex_unlock (&dir->lock);
+ err = diskfs_cached_lookup (id, &np);
+ mutex_lock (&dir->lock);
+
+ /* In the window where DP was unlocked, we might
+ have lost. So check the cache again, and see
+ if it's still there; if so, then we win. */
+ c = find_cache (dir, "..", 2);
+ if (!c || c->node_cache_id != id)
+ {
+ /* Lose */
+ mutex_unlock (&np->lock);
+ return 0;
+ }
+ }
+ else
+ err = diskfs_cached_lookup (id, &np);
return err ? 0 : np;
}
}
-
- statistics.miss++;
+
+ register_miss ();
spin_unlock (&cache_lock);
return 0;
diff --git a/libdiskfs/node-create.c b/libdiskfs/node-create.c
index 3f8dc4c1..4a7d108d 100644
--- a/libdiskfs/node-create.c
+++ b/libdiskfs/node-create.c
@@ -1,5 +1,5 @@
/* Making new files
- Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,96,98,2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,6 +17,11 @@
#include "priv.h"
+/* This enables SysV style group behaviour. New nodes inherit the GID
+ of the user creating them unless the SGID bit is set of the parent
+ directory. */
+int _diskfs_no_inherit_dir_group;
+
/* Create a new node. Give it MODE; if that includes IFDIR, also
initialize `.' and `..' in the new directory. Return the node in NPP.
CRED identifies the user responsible for the call. If NAME is nonzero,
@@ -26,7 +31,7 @@
strategies. */
error_t
diskfs_create_node (struct node *dir,
- char *name,
+ const char *name,
mode_t mode,
struct node **newnode,
struct protid *cred,
@@ -36,9 +41,12 @@ diskfs_create_node (struct node *dir,
error_t err;
uid_t newuid;
gid_t newgid;
-
+
if (diskfs_check_readonly ())
- return EROFS;
+ {
+ *newnode = NULL;
+ return EROFS;
+ }
/* Make the node */
err = diskfs_alloc_node (dir, mode, newnode);
@@ -46,14 +54,15 @@ diskfs_create_node (struct node *dir,
{
if (name)
diskfs_drop_dirstat (dir, ds);
+ *newnode = NULL;
return err;
}
np = *newnode;
/* Initialize the on-disk fields. */
- if (cred->nuids)
- newuid = cred->uids[0];
+ if (cred->user->uids->num)
+ newuid = cred->user->uids->ids[0];
else
{
newuid = dir->dn_stat.st_uid;
@@ -63,16 +72,43 @@ diskfs_create_node (struct node *dir,
if (err)
goto change_err;
np->dn_stat.st_uid = newuid;
+ if (np->author_tracks_uid)
+ np->dn_stat.st_author = newuid;
- if (diskfs_groupmember (dir->dn_stat.st_gid, cred))
- newgid = dir->dn_stat.st_gid;
- else if (cred->ngids)
- newgid = cred->gids[0];
- else
+ if (!_diskfs_no_inherit_dir_group)
{
newgid = dir->dn_stat.st_gid;
- mode &= ~S_ISGID;
+ if (!idvec_contains (cred->user->gids, newgid))
+ mode &= ~S_ISGID;
+ }
+ else
+ {
+ if (dir->dn_stat.st_mode & S_ISGID)
+ {
+ /* If the parent dir has the sgid bit set, inherit its gid.
+ If the new node is a directory, also inherit the sgid bit
+ set. */
+ newgid = dir->dn_stat.st_gid;
+ if (S_ISDIR (mode))
+ mode |= S_ISGID;
+ else
+ {
+ if (!idvec_contains (cred->user->gids, newgid))
+ mode &= ~S_ISGID;
+ }
+ }
+ else
+ {
+ if (cred->user->gids->num)
+ newgid = cred->user->gids->ids[0];
+ else
+ {
+ newgid = dir->dn_stat.st_gid;
+ mode &= ~S_ISGID;
+ }
+ }
}
+
err = diskfs_validate_group_change (np, newgid);
if (err)
goto change_err;
@@ -94,7 +130,7 @@ diskfs_create_node (struct node *dir,
if (S_ISDIR (mode))
err = diskfs_init_dir (np, dir, cred);
-
+
diskfs_node_update (np, 1);
if (err)
@@ -104,9 +140,10 @@ diskfs_create_node (struct node *dir,
np->dn_stat.st_nlink = 0;
if (name)
diskfs_drop_dirstat (dir, ds);
+ *newnode = NULL;
return err;
}
-
+
if (name)
{
err = diskfs_direnter (dir, name, np, ds, cred);
@@ -119,5 +156,8 @@ diskfs_create_node (struct node *dir,
diskfs_nput (np);
}
}
+ if (err)
+ *newnode = NULL;
+
return err;
}
diff --git a/libdiskfs/node-drop.c b/libdiskfs/node-drop.c
index d24bd86d..f44966ba 100644
--- a/libdiskfs/node-drop.c
+++ b/libdiskfs/node-drop.c
@@ -17,6 +17,20 @@
#include "priv.h"
+/* Free the list of modification requests MR */
+static void
+free_modreqs (struct modreq *mr)
+{
+ struct modreq *tmp;
+ for (; mr; mr = tmp)
+ {
+ mach_port_deallocate (mach_task_self (), mr->port);
+ tmp = mr->next;
+ free (mr);
+ }
+}
+
+
/* Node NP now has no more references; clean all state. The
diskfs_node_refcnt_lock must be held, and will be released
upon return. NP must be locked. */
@@ -30,7 +44,7 @@ diskfs_drop_node (struct node *np)
diskfs_check_readonly ();
assert (!diskfs_readonly);
- if (np->istranslated)
+ if (np->dn_stat.st_mode & S_IPTRANS)
diskfs_set_translator (np, 0, 0, 0);
if (np->allocsize != 0
@@ -73,15 +87,9 @@ diskfs_drop_node (struct node *np)
fshelp_drop_transbox (&np->transbox);
if (np->dirmod_reqs)
- {
- struct dirmod *dm, *tmp;
- for (dm = np->dirmod_reqs; dm; dm = tmp)
- {
- mach_port_deallocate (mach_task_self (), dm->port);
- tmp = dm->next;
- free (dm);
- }
- }
+ free_modreqs (np->dirmod_reqs);
+ if (np->filemod_reqs)
+ free_modreqs (np->filemod_reqs);
assert (!np->sockaddr);
diff --git a/libdiskfs/node-make.c b/libdiskfs/node-make.c
index 972167a2..74fdda19 100644
--- a/libdiskfs/node-make.c
+++ b/libdiskfs/node-make.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,95,96,2002 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
@@ -25,13 +25,16 @@ struct node *
diskfs_make_node (struct disknode *dn)
{
struct node *np = malloc (sizeof (struct node));
-
+
+ if (np == 0)
+ return 0;
+
np->dn = dn;
np->dn_set_ctime = 0;
np->dn_set_atime = 0;
np->dn_set_mtime = 0;
np->dn_stat_dirty = 0;
-
+
mutex_init (&np->lock);
np->references = 1;
np->light_references = 0;
@@ -39,11 +42,13 @@ diskfs_make_node (struct disknode *dn)
np->sockaddr = MACH_PORT_NULL;
np->dirmod_reqs = 0;
-
+ np->dirmod_tick = 0;
+ np->filemod_reqs = 0;
+ np->filemod_tick = 0;
+
fshelp_transbox_init (&np->transbox, &np->lock, np);
iohelp_initialize_conch (&np->conch, &np->lock);
fshelp_lock_init (&np->userlock);
-
return np;
}
diff --git a/libdiskfs/node-nput.c b/libdiskfs/node-nput.c
new file mode 100644
index 00000000..2aad1b66
--- /dev/null
+++ b/libdiskfs/node-nput.c
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "priv.h"
+
+/* Unlock node NP and release a hard reference; if this is the last
+ hard reference and there are no links to the file then request
+ weak references to be dropped. */
+void
+diskfs_nput (struct node *np)
+{
+ int tried_drop_softrefs = 0;
+
+ loop:
+ spin_lock (&diskfs_node_refcnt_lock);
+ assert (np->references);
+ np->references--;
+ if (np->references + np->light_references == 0)
+ diskfs_drop_node (np);
+ else if (np->references == 0 && !tried_drop_softrefs)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ /* This is our cue that something akin to "last process closes file"
+ in the POSIX.1 sense happened, so make sure any pending node time
+ updates now happen in a timely fashion. */
+ diskfs_set_node_times (np);
+
+ diskfs_lost_hardrefs (np);
+ if (!np->dn_stat.st_nlink)
+ {
+ /* There are no links. If there are soft references that
+ can be dropped, we can't let them postpone deallocation.
+ So attempt to drop them. But that's a user-supplied
+ routine, which might result in further recursive calls to
+ the ref-counting system. So we have to reacquire our
+ reference around the call to forestall disaster. */
+ spin_lock (&diskfs_node_refcnt_lock);
+ np->references++;
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ diskfs_try_dropping_softrefs (np);
+
+ /* But there's no value in looping forever in this
+ routine; only try to drop soft refs once. */
+ tried_drop_softrefs = 1;
+
+ /* Now we can drop the reference back... */
+ goto loop;
+ }
+ mutex_unlock (&np->lock);
+ }
+ else
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ mutex_unlock (&np->lock);
+ }
+}
diff --git a/libmom/make-memory-readonly.c b/libdiskfs/node-nputl.c
index e7ca4c87..45b109ea 100644
--- a/libmom/make-memory-readonly.c
+++ b/libdiskfs/node-nputl.c
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This file is part of the GNU Hurd.
@@ -18,19 +18,21 @@
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"
-error_t
-mom_make_memory_readonly (void *start, size_t len)
+/* Unlock node NP and release a light reference */
+void
+diskfs_nput_light (struct node *np)
{
- error_t err;
-
- assert ((vm_address_t) start % vm_page_size == 0);
- assert (len % vm_page_size == 0);
-
- mutex_lock (&_mom_memory_lock);
- err = vm_protect (mach_task_self (), (vm_address_t) start, len, 0,
- VM_PROT_READ | VM_PROT_EXECUTE);
- mutex_unlock (&_mom_memory_lock);
- return err;
+ spin_lock (&diskfs_node_refcnt_lock);
+ assert (np->light_references);
+ np->light_references--;
+ if (np->references + np->light_references == 0)
+ diskfs_drop_node (np);
+ else
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ mutex_unlock (&np->lock);
+ }
}
diff --git a/libdiskfs/node-nref.c b/libdiskfs/node-nref.c
new file mode 100644
index 00000000..753de65f
--- /dev/null
+++ b/libdiskfs/node-nref.c
@@ -0,0 +1,40 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "priv.h"
+
+/* Add a hard reference to a node. If there were no hard
+ references previously, then the node cannot be locked
+ (because you must hold a hard reference to hold the lock). */
+void
+diskfs_nref (struct node *np)
+{
+ int new_hardref;
+ spin_lock (&diskfs_node_refcnt_lock);
+ np->references++;
+ new_hardref = (np->references == 1);
+ spin_unlock (&diskfs_node_refcnt_lock);
+ if (new_hardref)
+ {
+ mutex_lock (&np->lock);
+ diskfs_new_hardrefs (np);
+ mutex_unlock (&np->lock);
+ }
+}
diff --git a/libmom/ref-destroy.c b/libdiskfs/node-nrefl.c
index 6966bcdc..ce3b39dd 100644
--- a/libmom/ref-destroy.c
+++ b/libdiskfs/node-nrefl.c
@@ -1,6 +1,6 @@
-/* Completely destroy a MOM port
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This file is part of the GNU Hurd.
@@ -20,10 +20,11 @@
#include "priv.h"
+/* Add a light reference to a node. */
void
-mom_ref_destroy (struct mom_port_ref *obj)
+diskfs_nref_light (struct node *np)
{
- mach_port_deallocate (mach_task_self (), obj->port);
+ spin_lock (&diskfs_node_refcnt_lock);
+ np->light_references++;
+ spin_unlock (&diskfs_node_refcnt_lock);
}
-
-
diff --git a/libdiskfs/node-nrele.c b/libdiskfs/node-nrele.c
new file mode 100644
index 00000000..9dbc5d8c
--- /dev/null
+++ b/libdiskfs/node-nrele.c
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "priv.h"
+
+/* Release a hard reference on NP. If NP is locked by anyone, then
+ this cannot be the last hard reference (because you must hold a
+ hard reference in order to hold the lock). If this is the last
+ hard reference and there are no links, then request soft references
+ to be dropped. */
+void
+diskfs_nrele (struct node *np)
+{
+ int tried_drop_softrefs = 0;
+
+ loop:
+ spin_lock (&diskfs_node_refcnt_lock);
+ assert (np->references);
+ np->references--;
+ if (np->references + np->light_references == 0)
+ {
+ mutex_lock (&np->lock);
+ diskfs_drop_node (np);
+ }
+ else if (np->references == 0)
+ {
+ mutex_lock (&np->lock);
+ spin_unlock (&diskfs_node_refcnt_lock);
+ diskfs_lost_hardrefs (np);
+ if (!np->dn_stat.st_nlink && !tried_drop_softrefs)
+ {
+ /* Same issue here as in nput; see that for explanation */
+ spin_lock (&diskfs_node_refcnt_lock);
+ np->references++;
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ diskfs_try_dropping_softrefs (np);
+ tried_drop_softrefs = 1;
+
+ /* Now we can drop the reference back... */
+ mutex_unlock (&np->lock);
+ goto loop;
+ }
+ mutex_unlock (&np->lock);
+ }
+ else
+ spin_unlock (&diskfs_node_refcnt_lock);
+}
diff --git a/libmom/make-memory-readwrite.c b/libdiskfs/node-nrelel.c
index f35e6bfd..e61f6378 100644
--- a/libmom/make-memory-readwrite.c
+++ b/libdiskfs/node-nrelel.c
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This file is part of the GNU Hurd.
@@ -20,17 +20,20 @@
#include "priv.h"
-error_t
-mom_make_memory_readwrite (void *start, size_t len)
+/* Release a light reference on NP. If NP is locked by anyone, then
+ this cannot be the last reference (because you must hold a
+ hard reference in order to hold the lock). */
+void
+diskfs_nrele_light (struct node *np)
{
- error_t err;
-
- assert ((vm_address_t) start % vm_page_size == 0);
- assert (len % vm_page_size == 0);
-
- mutex_lock (&_mom_memory_lock);
- err = vm_protect (mach_task_self (), (vm_address_t) start, len, 0,
- VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
- mutex_unlock (&_mom_memory_lock);
- return err;
+ spin_lock (&diskfs_node_refcnt_lock);
+ assert (np->light_references);
+ np->light_references--;
+ if (np->references + np->light_references == 0)
+ {
+ mutex_lock (&np->lock);
+ diskfs_drop_node (np);
+ }
+ else
+ spin_unlock (&diskfs_node_refcnt_lock);
}
diff --git a/libdiskfs/node-rdwr.c b/libdiskfs/node-rdwr.c
index 319a985c..ed94df44 100644
--- a/libdiskfs/node-rdwr.c
+++ b/libdiskfs/node-rdwr.c
@@ -45,6 +45,8 @@ diskfs_node_rdwr (struct node *np,
err = diskfs_grow (np, off + amt, cred);
if (err)
return err;
+ if (np->filemod_reqs)
+ diskfs_notice_filechange (np, FILE_CHANGED_EXTEND, 0, off + amt);
}
if (off + amt > np->dn_stat.st_size)
diff --git a/libdiskfs/node-times.c b/libdiskfs/node-times.c
index 720c85e0..67f0142e 100644
--- a/libdiskfs/node-times.c
+++ b/libdiskfs/node-times.c
@@ -1,5 +1,7 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation
+/* Process st_?tim updates marked for a diskfs node.
+
+ Copyright (C) 1994, 1996, 1999, 2000, 2007, 2009 Free Software Foundation,
+ Inc.
This file is part of the GNU Hurd.
@@ -8,7 +10,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -22,47 +24,51 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
#include <maptime.h>
-/* If NP->dn_set_ctime is set, then modify NP->dn_stat.st_ctime
+/* If disk is not readonly and the noatime option is not enabled, set
+ NP->dn_set_atime. */
+void
+diskfs_set_node_atime (struct node *np)
+{
+ if (!_diskfs_noatime && !diskfs_check_readonly ())
+ np->dn_set_atime = 1;
+}
+
+/* If NP->dn_set_ctime is set, then modify NP->dn_stat.st_ctim
appropriately; do the analogous operation for atime and mtime as well. */
void
diskfs_set_node_times (struct node *np)
{
struct timeval t;
+ if (!np->dn_set_mtime && !np->dn_set_atime && !np->dn_set_ctime)
+ return;
+
maptime_read (diskfs_mtime, &t);
+ /* We are careful to test and reset each of these individually, so there
+ is no race condition where a dn_set_?time flag setting gets lost. It
+ is not a problem to have the kind of race where the flag is set after
+ we've tested it and done nothing--as long as the flag remains set so
+ the update will happen at the next call. */
if (np->dn_set_mtime)
{
-#ifdef notyet
- np->dn_stat.st_mtimespec.ts_sec = t.tv_sec;
- np->dn_stat.st_mtimespec.ts_nsec = t.tv_usec * 1000;
-#else
- np->dn_stat.st_mtime = t.tv_sec;
- np->dn_stat.st_mtime_usec = t.tv_usec;
-#endif
+ np->dn_stat.st_mtim.tv_sec = t.tv_sec;
+ np->dn_stat.st_mtim.tv_nsec = t.tv_usec * 1000;
+ np->dn_stat_dirty = 1;
+ np->dn_set_mtime = 0;
}
if (np->dn_set_atime)
{
-#ifdef notyet
- np->dn_stat.st_atimespec.ts_sec = t.tv_sec;
- np->dn_stat.st_atimespec.ts_nsec = t.tv_usec * 1000;
-#else
- np->dn_stat.st_atime = t.tv_sec;
- np->dn_stat.st_atime_usec = t.tv_usec;
-#endif
+ np->dn_stat.st_atim.tv_sec = t.tv_sec;
+ np->dn_stat.st_atim.tv_nsec = t.tv_usec * 1000;
+ np->dn_stat_dirty = 1;
+ np->dn_set_atime = 0;
}
if (np->dn_set_ctime)
{
-#ifdef notyet
- np->dn_stat.st_ctimespec.ts_sec = t.tv_sec;
- np->dn_stat.st_ctimespec.ts_nsec = t.tv_usec * 1000;
-#else
- np->dn_stat.st_ctime = t.tv_sec;
- np->dn_stat.st_ctime_usec = t.tv_usec;
-#endif
+ np->dn_stat.st_ctim.tv_sec = t.tv_sec;
+ np->dn_stat.st_ctim.tv_nsec = t.tv_usec * 1000;
+ np->dn_stat_dirty = 1;
+ np->dn_set_ctime = 0;
}
-
- if (np->dn_set_mtime || np->dn_set_atime || np->dn_set_ctime)
- np->dn_stat_dirty = 1;
- np->dn_set_mtime = np->dn_set_atime = np->dn_set_ctime = 0;
}
diff --git a/libdiskfs/notify-stubs.c b/libdiskfs/notify-stubs.c
deleted file mode 100644
index a9177f81..00000000
--- a/libdiskfs/notify-stubs.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- Copyright (C) 1994, 1995 Free Software Foundation
-
- 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. */
-
-#include "priv.h"
-
-error_t
-diskfs_do_seqnos_mach_notify_port_deleted (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
- mach_port_t name
- __attribute__ ((unused)))
-{
- return 0;
-}
-
-error_t
-diskfs_do_seqnos_mach_notify_msg_accepted (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
- mach_port_t name
- __attribute__ ((unused)))
-{
- return 0;
-}
-
-error_t
-diskfs_do_seqnos_mach_notify_port_destroyed (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
- mach_port_t name
- __attribute__ ((unused)))
-{
- return 0;
-}
-
-error_t
-diskfs_do_seqnos_mach_notify_send_once (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)))
-{
- return 0;
-}
-
-error_t
-diskfs_do_seqnos_mach_notify_dead_name (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
- mach_port_t name
- __attribute__ ((unused)))
-{
- return 0;
-}
diff --git a/libdiskfs/opts-append-std.c b/libdiskfs/opts-append-std.c
index 505752d5..b951bf93 100644
--- a/libdiskfs/opts-append-std.c
+++ b/libdiskfs/opts-append-std.c
@@ -1,8 +1,8 @@
/* Get standard diskfs run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 96,97,98,99,2002 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -20,12 +20,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <stdio.h>
#include <argz.h>
#include "priv.h"
error_t
-diskfs_append_std_options (char **argz, unsigned *argz_len)
+diskfs_append_std_options (char **argz, size_t *argz_len)
{
error_t err;
extern int diskfs_sync_interval;
@@ -34,21 +35,32 @@ diskfs_append_std_options (char **argz, unsigned *argz_len)
err = argz_add (argz, argz_len, "--readonly");
else
err = argz_add (argz, argz_len, "--writable");
- if (err)
- return err;
- if (diskfs_synchronous)
- err = argz_add (argz, argz_len, "--sync");
- else if (diskfs_sync_interval == 0)
- err = argz_add (argz, argz_len, "--nosync");
- else
+ if (!err && _diskfs_nosuid)
+ err = argz_add (argz, argz_len, "--no-suid");
+ if (!err && _diskfs_noexec)
+ err = argz_add (argz, argz_len, "--no-exec");
+ if (!err && _diskfs_noatime)
+ err = argz_add (argz, argz_len, "--no-atime");
+ if (!err && _diskfs_no_inherit_dir_group)
+ err = argz_add (argz, argz_len, "--no-inherit-dir-group");
+
+ if (! err)
{
- char buf[80];
- sprintf (buf, "--sync=%d", diskfs_sync_interval);
- err = argz_add (argz, argz_len, buf);
+ if (diskfs_synchronous)
+ err = argz_add (argz, argz_len, "--sync");
+ else if (DEFAULT_SYNC_INTERVAL != diskfs_sync_interval)
+ {
+ if (diskfs_sync_interval == 0)
+ err = argz_add (argz, argz_len, "--no-sync");
+ else
+ {
+ char buf[80];
+ sprintf (buf, "--sync=%d", diskfs_sync_interval);
+ err = argz_add (argz, argz_len, buf);
+ }
+ }
}
- if (err)
- free (argz); /* Free the first option allocated. */
return err;
}
diff --git a/libdiskfs/opts-common.c b/libdiskfs/opts-common.c
index 5d94f7b4..d37c2868 100644
--- a/libdiskfs/opts-common.c
+++ b/libdiskfs/opts-common.c
@@ -1,6 +1,6 @@
/* Options common to both startup and runtime
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -21,17 +21,39 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <argp.h>
+#include "priv.h"
const struct argp_option diskfs_common_options[] =
{
{"readonly", 'r', 0, 0, "Never write to disk or allow opens for writing"},
{"rdonly", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"ro", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
{"writable", 'w', 0, 0, "Use normal read/write behavior"},
{"rdwr", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"rw", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
{"sync", 's', "INTERVAL", OPTION_ARG_OPTIONAL,
"If INTERVAL is supplied, sync all data not actually written to disk"
" every INTERVAL seconds, otherwise operate in synchronous mode (the"
- " default is to sync every 30 seconds)"},
- {"nosync", 'n', 0, 0, "Don't automatically sync data to disk"},
+ " default is to sync every " DEFAULT_SYNC_INTERVAL_STRING " seconds)"},
+ {"no-sync", 'n', 0, 0, "Don't automatically sync data to disk"},
+ {"nosync", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"no-suid", 'S', 0, 0, "Don't permit set-uid or set-gid execution"},
+ {"nosuid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"suid-ok", OPT_SUID_OK, 0, 0, "Enable set-uid execution"},
+ {"no-exec", 'E', 0, 0, "Don't permit any execution of files on this filesystem"},
+ {"noexec", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"exec-ok", OPT_EXEC_OK, 0, 0, "Enable execution of files"},
+ {"no-atime", 'A', 0, 0,
+ "Do not update file access times on disk for reads"},
+ {"noatime", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"atime", OPT_ATIME, 0, 0, "Do update file access times for reads normally"},
+ {"no-inherit-dir-group", OPT_NO_INHERIT_DIR_GROUP, 0, 0,
+ "Create new nodes with gid of the process"},
+ {"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)"},
+ {"grpid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"bsdgroups", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
{0, 0}
};
diff --git a/libdiskfs/opts-get.c b/libdiskfs/opts-get.c
index 26558212..c23e4bec 100644
--- a/libdiskfs/opts-get.c
+++ b/libdiskfs/opts-get.c
@@ -1,8 +1,7 @@
/* Get run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -23,9 +22,7 @@
#include "priv.h"
error_t
-diskfs_get_options (char **argz, unsigned *argz_len)
+diskfs_append_args (char **argz, size_t *argz_len)
{
- *argz = 0;
- *argz_len = 0;
return diskfs_append_std_options (argz, argz_len);
}
diff --git a/libdiskfs/opts-runtime.c b/libdiskfs/opts-runtime.c
index d7264069..f0d1a382 100644
--- a/libdiskfs/opts-runtime.c
+++ b/libdiskfs/opts-runtime.c
@@ -1,6 +1,6 @@
/* Default definition for diskfs_runtime_argp
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2004 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -19,5 +19,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
+#include <argp.h>
struct argp *diskfs_runtime_argp = (struct argp *)&diskfs_std_runtime_argp;
diff --git a/libdiskfs/opts-set.c b/libdiskfs/opts-set.c
index 72af4ef1..3cfe3f6b 100644
--- a/libdiskfs/opts-set.c
+++ b/libdiskfs/opts-set.c
@@ -1,6 +1,6 @@
/* Set run-time options
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -25,7 +25,7 @@
#include "priv.h"
error_t
-diskfs_set_options (char *argz, size_t argz_len)
+diskfs_set_options (const char *argz, size_t argz_len)
{
if (diskfs_runtime_argp)
return fshelp_set_options (diskfs_runtime_argp, 0, argz, argz_len, 0);
diff --git a/libdiskfs/opts-std-runtime.c b/libdiskfs/opts-std-runtime.c
index 9a3ee80a..177dfaf6 100644
--- a/libdiskfs/opts-std-runtime.c
+++ b/libdiskfs/opts-std-runtime.c
@@ -1,6 +1,6 @@
/* Parse standard run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -18,18 +18,22 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <argp.h>
+
#include "priv.h"
static const struct argp_option
std_runtime_options[] =
{
- {"remount", 'u', 0, 0, "Flush any meta-data cached in core"},
+ {"update", 'u', 0, 0, "Flush any meta-data cached in core"},
+ {"remount", 0, 0, OPTION_HIDDEN | OPTION_ALIAS}, /* deprecated */
{0, 0}
};
struct parse_hook
{
- int readonly, sync, sync_interval, remount;
+ int readonly, sync, sync_interval, remount, nosuid, noexec, noatime,
+ noinheritdirgroup;
};
/* Implement the options in H, and free H. */
@@ -50,10 +54,12 @@ set_opts (struct parse_hook *h)
}
if (h->readonly != diskfs_readonly)
- if (err)
- diskfs_set_readonly (h->readonly); /* keep the old error. */
- else
- err = diskfs_set_readonly (h->readonly);
+ {
+ if (err)
+ diskfs_set_readonly (h->readonly); /* keep the old error. */
+ else
+ err = diskfs_set_readonly (h->readonly);
+ }
/* Change sync mode. */
if (h->sync)
@@ -68,6 +74,15 @@ set_opts (struct parse_hook *h)
diskfs_set_sync_interval (h->sync_interval);
}
+ if (h->nosuid != -1)
+ _diskfs_nosuid = h->nosuid;
+ if (h->noexec != -1)
+ _diskfs_noexec = h->noexec;
+ if (h->noatime != -1)
+ _diskfs_noatime = h->noatime;
+ if (h->noinheritdirgroup != -1)
+ _diskfs_no_inherit_dir_group = h->noinheritdirgroup;
+
free (h);
return err;
@@ -83,10 +98,21 @@ parse_opt (int opt, char *arg, struct argp_state *state)
case 'r': h->readonly = 1; break;
case 'w': h->readonly = 0; break;
case 'u': h->remount = 1; break;
+ case 'S': h->nosuid = 1; break;
+ case 'E': h->noexec = 1; break;
+ case 'A': h->noatime = 1; break;
+ case OPT_SUID_OK: h->nosuid = 0; break;
+ case OPT_EXEC_OK: h->noexec = 0; break;
+ case OPT_ATIME: h->noatime = 0; break;
+ case OPT_NO_INHERIT_DIR_GROUP: h->noinheritdirgroup = 1; break;
+ case OPT_INHERIT_DIR_GROUP: h->noinheritdirgroup = 0; break;
case 'n': h->sync_interval = 0; h->sync = 0; break;
case 's':
if (arg)
- h->sync_interval = atoi (arg);
+ {
+ h->sync = 0;
+ h->sync_interval = atoi (arg);
+ }
else
h->sync = 1;
break;
@@ -103,6 +129,7 @@ parse_opt (int opt, char *arg, struct argp_state *state)
h->sync = diskfs_synchronous;
h->sync_interval = -1;
h->remount = 0;
+ h->nosuid = h->noexec = h->noatime = h->noinheritdirgroup = -1;
/* We know that we have one child, with which we share our hook. */
state->child_inputs[0] = h;
@@ -127,8 +154,8 @@ parse_opt (int opt, char *arg, struct argp_state *state)
static const struct argp common_argp = { diskfs_common_options, parse_opt };
-static const struct argp *parents[] = { &common_argp, 0 };
+static const struct argp_child children[] = { {&common_argp}, {0} };
const struct argp diskfs_std_runtime_argp =
{
- std_runtime_options, parse_opt, 0, 0, parents
+ std_runtime_options, parse_opt, 0, 0, children
};
diff --git a/libdiskfs/opts-std-startup.c b/libdiskfs/opts-std-startup.c
index 8eb51e7c..6fe28758 100644
--- a/libdiskfs/opts-std-startup.c
+++ b/libdiskfs/opts-std-startup.c
@@ -1,8 +1,9 @@
/* Standard startup-time command line parser
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2007
+ Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -22,9 +23,14 @@
#include <stdio.h>
#include <argp.h>
+#include <hurd/store.h>
+#include <hurd/paths.h>
#include "priv.h"
-char *diskfs_boot_flags = 0;
+const char *diskfs_boot_command_line;
+char **_diskfs_boot_command;
+
+int _diskfs_boot_pause;
extern char **diskfs_argv;
@@ -35,16 +41,33 @@ mach_port_t diskfs_exec_server_task = MACH_PORT_NULL;
#define OPT_HOST_PRIV_PORT (-1)
#define OPT_DEVICE_MASTER_PORT (-2)
#define OPT_EXEC_SERVER_TASK (-3)
-#define OPT_BOOTFLAGS (-4)
+#define OPT_BOOT_CMDLINE (-4)
+#define OPT_BOOT_COMMAND (-5)
+#define OPT_BOOT_INIT_PROGRAM (-6)
+#define OPT_BOOT_PAUSE (-7)
static const struct argp_option
startup_options[] =
{
+ {"directory", 'C', "DIRECTORY", 0,
+ "Use DIRECTORY as the root of the filesystem"},
+ {"virtual-root", 0, 0, OPTION_ALIAS},
+ {"chroot", 0, 0, OPTION_ALIAS},
+
{0,0,0,0, "Boot options:", -2},
+ {"multiboot-command-line", OPT_BOOT_CMDLINE, "ARGS", 0,
+ "Required for bootstrap filesystem, the multiboot kernel command line"},
+ {"bootflags", 0, 0, OPTION_ALIAS|OPTION_HIDDEN},
+ {"boot-init-program", OPT_BOOT_INIT_PROGRAM, "FILE", 0,
+ "For bootstrap filesystem, init program to run (default " _HURD_INIT ")"},
+ {"boot-debug-pause", OPT_BOOT_PAUSE, 0, 0,
+ "Pause for keystroke before starting bootstrap programs"},
+ {"boot-command", OPT_BOOT_COMMAND, 0, 0,
+ "Remaining arguments form command line to run"
+ " at bootstrap instead of init"},
{"host-priv-port", OPT_HOST_PRIV_PORT, "PORT"},
{"device-master-port", OPT_DEVICE_MASTER_PORT, "PORT"},
{"exec-server-task", OPT_EXEC_SERVER_TASK, "PORT"},
- {"bootflags", OPT_BOOTFLAGS, "FLAGS"},
{0}
};
@@ -54,10 +77,17 @@ parse_startup_opt (int opt, char *arg, struct argp_state *state)
{
switch (opt)
{
- case 'r':
- diskfs_readonly = 1; break;
- case 'w':
- diskfs_readonly = 0; break;
+#define TOGGLE(var, on, off) \
+ case on: var = 1; break; \
+ case off: var = 0; break;
+ TOGGLE (diskfs_readonly, 'r', 'w');
+ TOGGLE (_diskfs_nosuid, 'S', OPT_SUID_OK);
+ TOGGLE (_diskfs_noexec, 'E', OPT_EXEC_OK);
+ TOGGLE (_diskfs_noatime, 'A', OPT_ATIME);
+ TOGGLE (_diskfs_no_inherit_dir_group, OPT_NO_INHERIT_DIR_GROUP,
+ OPT_INHERIT_DIR_GROUP);
+#undef TOGGLE
+
case 's':
if (arg == NULL)
diskfs_synchronous = 1;
@@ -76,8 +106,22 @@ parse_startup_opt (int opt, char *arg, struct argp_state *state)
_hurd_host_priv = atoi (arg); break;
case OPT_EXEC_SERVER_TASK:
diskfs_exec_server_task = atoi (arg); break;
- case OPT_BOOTFLAGS:
- diskfs_boot_flags = arg; break;
+ case OPT_BOOT_CMDLINE:
+ diskfs_boot_command_line = arg; break;
+ case OPT_BOOT_INIT_PROGRAM:
+ diskfs_boot_init_program = arg; break;
+ case OPT_BOOT_PAUSE:
+ _diskfs_boot_pause = 1; break;
+ case 'C':
+ _diskfs_chroot_directory = arg; break;
+
+ case OPT_BOOT_COMMAND:
+ if (state->next == state->argc)
+ argp_error (state, "Command line must follow --boot-command option");
+ _diskfs_boot_command = state->argv + state->next;
+ state->next = state->argc; /* stop parsing */
+ {char **p; for (p = _diskfs_boot_command; *p; ++p) printf("BC %s\n",*p);}
+ break;
case ARGP_KEY_END:
diskfs_argv = state->argv; break;
@@ -92,50 +136,26 @@ parse_startup_opt (int opt, char *arg, struct argp_state *state)
/* Suck in the common arguments. */
static const struct argp startup_common_argp =
{ diskfs_common_options, parse_startup_opt };
+static const struct argp_child startup_argp_children[] =
+ { {&startup_common_argp}, {0} };
/* This may be used with argp_parse to parse standard diskfs startup
options, possible chained onto the end of a user argp structure. */
-static const struct argp *startup_argp_parents[] = { &startup_common_argp, 0 };
-
const struct argp
-diskfs_std_startup_argp =
+diskfs_startup_argp =
{
- startup_options, parse_startup_opt, 0, 0, startup_argp_parents
+ startup_options, parse_startup_opt, 0, 0, startup_argp_children
};
-/* ---------------------------------------------------------------- */
-
-int diskfs_use_mach_device = 0;
-char *diskfs_device_arg = 0;
-
-static const struct argp_option
-dev_startup_options[] =
-{
- {"machdev", 'm', 0, 0, "DEVICE is a mach device, not a file"},
- {0, 0}
-};
-
static error_t
-parse_dev_startup_opt (int opt, char *arg, struct argp_state *state)
+parse_store_startup_opt (int opt, char *arg, struct argp_state *state)
{
switch (opt)
{
- case 'm':
- diskfs_use_mach_device = 1;
- break;
- case ARGP_KEY_ARG:
- diskfs_device_arg = arg;
- break;
-
- case ARGP_KEY_END:
- if (diskfs_boot_flags)
- diskfs_use_mach_device = 1; /* Can't do much else... */
- break;
-
- case ARGP_KEY_NO_ARGS:
- argp_error (state, "No device specified");
- return EINVAL;
-
+ case ARGP_KEY_INIT:
+ /* Propagate our input to our STORE_ARGP child , which it will use to
+ return what it parses. */
+ state->child_inputs[1] = state->input; break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -143,9 +163,16 @@ parse_dev_startup_opt (int opt, char *arg, struct argp_state *state)
return 0;
}
-static const struct argp *dev_startup_argp_parents[] =
- { &diskfs_std_startup_argp, 0 };
+static const struct argp_child store_argp_children[] =
+ { {&diskfs_startup_argp}, {&store_argp}, {0} };
-const struct argp diskfs_std_device_startup_argp =
- { dev_startup_options, parse_dev_startup_opt, "DEVICE", 0,
- dev_startup_argp_parents };
+/* An argp structure for the standard diskfs command line arguments plus a
+ store specification. The address of a location in which to return the
+ resulting struct store_parsed structure should be passed as the input
+ argument to argp_parse; see the declaration for STORE_ARGP in
+ <hurd/store.h> for more information. */
+const struct argp
+diskfs_store_startup_argp =
+{
+ 0, parse_store_startup_opt, 0, 0, store_argp_children
+};
diff --git a/libdiskfs/opts-version.c b/libdiskfs/opts-version.c
index 0e9d4098..c26334b2 100644
--- a/libdiskfs/opts-version.c
+++ b/libdiskfs/opts-version.c
@@ -20,6 +20,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <stdio.h>
+#include <argp.h>
+#include <version.h>
+
#include "priv.h"
static void
@@ -28,12 +32,15 @@ _print_version (FILE *stream, struct argp_state *state)
if (argp_program_version)
/* If this is non-zero, then the program's probably defined it, so let
that take precedence over the default. */
- fprintf (stream, "%s\n", argp_program_version);
+ fputs (argp_program_version, stream);
+ else if (diskfs_extra_version && *diskfs_extra_version)
+ fprintf (stream, "%s (%s) %s\n",
+ diskfs_server_name, diskfs_extra_version, diskfs_server_version);
else
- /* Construct a version using the standard diskfs variables. */
- fprintf (stream, "%s %d.%d (GNU %s)\n",
- diskfs_server_name, diskfs_major_version, diskfs_minor_version,
- HURD_RELEASE);
+ fprintf (stream, "%s %s\n", diskfs_server_name, diskfs_server_version);
+
+ /* And because diskfs is big and huge, put our information out too. */
+ fputs (STANDARD_HURD_VERSION (libdiskfs) "\n", stream);
}
void (*argp_program_version_hook) (FILE *stream, struct argp_state *state)
diff --git a/libdiskfs/ourfs_notify.defs b/libdiskfs/ourfs_notify.defs
deleted file mode 100644
index 64127fe6..00000000
--- a/libdiskfs/ourfs_notify.defs
+++ /dev/null
@@ -1,5 +0,0 @@
-/* Private specialized presentation of fs_notify.defs for diskfs library. */
-
-#define routine simpleroutine
-#define USERPREFIX nowait_
-#include <hurd/fs_notify.defs>
diff --git a/libdiskfs/peropen-make.c b/libdiskfs/peropen-make.c
index de483f26..d37516c1 100644
--- a/libdiskfs/peropen-make.c
+++ b/libdiskfs/peropen-make.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994,97,99,2001,02 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -20,19 +20,45 @@
/* Create and return a new peropen structure on node NP with open
flags FLAGS. */
-struct peropen *
-diskfs_make_peropen (struct node *np, int flags, mach_port_t dotdotport)
+error_t
+diskfs_make_peropen (struct node *np, int flags, struct peropen *context,
+ struct peropen **ppo)
{
- struct peropen *po = malloc (sizeof (struct peropen));
+ struct peropen *po = *ppo = malloc (sizeof (struct peropen));
+
+ if (! po)
+ return ENOMEM;
+
po->filepointer = 0;
po->lock_status = LOCK_UN;
po->refcnt = 0;
po->openstat = flags;
po->np = np;
- po->dotdotport = dotdotport;
- if (dotdotport != MACH_PORT_NULL)
- mach_port_mod_refs (mach_task_self (), dotdotport,
- MACH_PORT_RIGHT_SEND, 1);
+
+ if (context)
+ {
+ po->root_parent = context->root_parent;
+ if (po->root_parent != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), po->root_parent,
+ MACH_PORT_RIGHT_SEND, 1);
+
+ po->shadow_root = context->shadow_root;
+ if (po->shadow_root)
+ diskfs_nref (po->shadow_root);
+
+ po->shadow_root_parent = context->shadow_root_parent;
+ if (po->shadow_root_parent != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
+ MACH_PORT_RIGHT_SEND, 1);
+ }
+ else
+ {
+ po->root_parent = MACH_PORT_NULL;
+ po->shadow_root_parent = MACH_PORT_NULL;
+ po->shadow_root = _diskfs_chroot_directory ? diskfs_root_node : 0;
+ }
+
diskfs_nref (np);
- return po;
+
+ return 0;
}
diff --git a/libdiskfs/peropen-rele.c b/libdiskfs/peropen-rele.c
index b38b2af6..6974e86a 100644
--- a/libdiskfs/peropen-rele.c
+++ b/libdiskfs/peropen-rele.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1996 Free Software Foundation
+ Copyright (C) 1994, 1996, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,6 +15,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <sys/file.h>
#include "priv.h"
/* Decrement the reference count on a peropen structure. */
@@ -22,14 +23,27 @@ void
diskfs_release_peropen (struct peropen *po)
{
mutex_lock (&po->np->lock);
+
if (--po->refcnt)
{
mutex_unlock (&po->np->lock);
return;
}
- mach_port_deallocate (mach_task_self (), po->dotdotport);
+
+ if (po->root_parent)
+ mach_port_deallocate (mach_task_self (), po->root_parent);
+
+ if (po->shadow_root && po->shadow_root != po->np)
+ diskfs_nrele (po->shadow_root);
+
+ if (po->shadow_root_parent)
+ mach_port_deallocate (mach_task_self (), po->shadow_root_parent);
+
+ if (po->lock_status != LOCK_UN)
+ fshelp_acquire_lock (&po->np->userlock, &po->lock_status,
+ &po->np->lock, LOCK_UN);
+
diskfs_nput (po->np);
+
free (po);
}
-
-
diff --git a/libdiskfs/ports-clean.c b/libdiskfs/ports-clean.c
deleted file mode 100644
index 01a50dc5..00000000
--- a/libdiskfs/ports-clean.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- Copyright (C) 1994 Free Software Foundation
-
- 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. */
-
-#include "priv.h"
-#include <hurd/pager.h>
-
-/* Indexed by port type (PT_*); called when the last reference goes
- away on a port. */
-void (*ports_cleanroutines[])(void *)=
-{
- [PT_PROTID] = diskfs_protid_rele,
- [PT_PAGER] = pager_clean,
- [PT_TRANSBOOT] = fshelp_transboot_clean,
- [PT_CTL] = _diskfs_control_clean,
-};
diff --git a/libdiskfs/priv.h b/libdiskfs/priv.h
index 0f14ca3a..07464d56 100644
--- a/libdiskfs/priv.h
+++ b/libdiskfs/priv.h
@@ -1,5 +1,7 @@
/* Private declarations for fileserver library
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2006, 2009 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
@@ -20,18 +22,51 @@
#include <mach.h>
#include <hurd.h>
+#include <sys/mman.h>
#include <hurd/ports.h>
#include <hurd/fshelp.h>
#include <hurd/iohelp.h>
+#include <hurd/port.h>
#include <assert.h>
+#include <argp.h>
#include "diskfs.h"
-extern mach_port_t fs_control_port; /* receive right */
+/* These inhibit setuid or exec. */
+extern int _diskfs_nosuid, _diskfs_noexec;
+
+/* This relaxes the requirement to set `st_atim'. */
+extern int _diskfs_noatime;
+
+/* This enables SysV style group behaviour. New nodes inherit the GID
+ of the user creating them unless the SGID bit is set of the parent
+ directory. */
+extern int _diskfs_no_inherit_dir_group;
+
+/* This is the -C argument value. */
+extern char *_diskfs_chroot_directory;
+
+/* If --boot-command is given, this points to the program and args. */
+extern char **_diskfs_boot_command;
+
+/* Port cell holding a cached port to the exec server. */
+extern struct hurd_port _diskfs_exec_portcell;
volatile struct mapped_time_value *_diskfs_mtime;
-extern struct argp_option diskfs_common_options[];
+extern const struct argp_option diskfs_common_options[];
+/* Option keys for long-only options in diskfs_common_options. */
+#define OPT_SUID_OK 600 /* --suid-ok */
+#define OPT_EXEC_OK 601 /* --exec-ok */
+#define OPT_ATIME 602 /* --atime */
+#define OPT_NO_INHERIT_DIR_GROUP 603 /* --no-inherit-dir-group */
+#define OPT_INHERIT_DIR_GROUP 604 /* --inherit-dir-group */
+
+/* Common value for diskfs_common_options and diskfs_default_sync_interval. */
+#define DEFAULT_SYNC_INTERVAL 5
+#define DEFAULT_SYNC_INTERVAL_STRING STRINGIFY(DEFAULT_SYNC_INTERVAL)
+#define STRINGIFY(x) STRINGIFY_1(x)
+#define STRINGIFY_1(x) #x
/* Diskfs thinks the disk is dirty if this is set. */
extern int _diskfs_diskdirty;
@@ -39,25 +74,6 @@ extern int _diskfs_diskdirty;
/* Needed for MiG. */
typedef struct protid *protid_t;
-/* Called by MiG to translate ports into struct protid *.
- fsmutations.h arranges for this to happen for the io and
- fs interfaces. */
-extern inline struct protid *
-begin_using_protid_port (file_t port)
-{
- return ports_lookup_port (diskfs_port_bucket, port, diskfs_protid_class);
-}
-
-/* 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. */
-extern inline void
-end_using_protid_port (struct protid *cred)
-{
- if (cred)
- ports_port_deref (cred);
-}
-
/* Actually read or write a file. The file size must already permit
the requested access. NP is the file to read/write. DATA is a buffer
to write from or fill on read. OFFSET is the absolute address (-1
@@ -72,6 +88,9 @@ error_t _diskfs_rdwr_internal (struct node *np, char *data, off_t offset,
and auth ports). */
void _diskfs_init_completed (void);
+/* Called in a bootstrap filesystem only, to get the privileged ports. */
+void _diskfs_boot_privports (void);
+
/* Clean routine for control port. */
void _diskfs_control_clean (void *);
@@ -97,7 +116,7 @@ extern fshelp_fetch_root_callback2_t _diskfs_translator_callback2;
if (!(PROTID)) \
return EOPNOTSUPP; \
\
- if (diskfs_readonly) \
+ if (diskfs_check_readonly ()) \
return EROFS; \
\
np = (PROTID)->po->np; \
@@ -114,6 +133,7 @@ extern fshelp_fetch_root_callback2_t _diskfs_translator_callback2;
#define HONORED_STATE_MODES (O_APPEND|O_ASYNC|O_FSYNC|O_NONBLOCK|O_NOATIME)
/* Bits that are turned off after open */
-#define OPENONLY_STATE_MODES (O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK)
+#define OPENONLY_STATE_MODES \
+ (O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK|O_EXLOCK|O_SHLOCK)
#endif
diff --git a/libdiskfs/protid-make.c b/libdiskfs/protid-make.c
index c67bd41b..9b78a37f 100644
--- a/libdiskfs/protid-make.c
+++ b/libdiskfs/protid-make.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,6 +17,7 @@
#include "priv.h"
#include <string.h>
+#include <assert.h>
/* Build and return in CRED a protid which has no user identification, for
peropen PO. The node PO->np must be locked. */
@@ -37,45 +38,32 @@ diskfs_start_protid (struct peropen *po, struct protid **cred)
}
/* Finish building protid CRED started with diskfs_start_protid;
- the uid set is UID (length NUIDS); the gid set is GID (length NGIDS). */
+ the user to install is USER. */
void
-diskfs_finish_protid (struct protid *cred, uid_t *uids, int nuids,
- gid_t *gids, int ngids)
+diskfs_finish_protid (struct protid *cred, struct iouser *user)
{
- if (!uids)
- nuids = 1;
- if (!gids)
- ngids = 1;
+ error_t err;
- cred->uids = malloc (nuids * sizeof (uid_t));
- cred->gids = malloc (ngids * sizeof (uid_t));
- cred->nuids = nuids;
- cred->ngids = ngids;
-
- if (uids)
- bcopy (uids, cred->uids, nuids * sizeof (uid_t));
- else
- *cred->uids = 0;
-
- if (gids)
- bcopy (gids, cred->gids, ngids * sizeof (uid_t));
+ if (!user)
+ err = iohelp_create_simple_iouser (&cred->user, 0, 0);
else
- *cred->gids = 0;
+ err = iohelp_dup_iouser (&cred->user, user);
+ assert_perror (err);
- mach_port_move_member (mach_task_self (), cred->pi.port_right,
- diskfs_port_bucket->portset);
+ err = mach_port_move_member (mach_task_self (), cred->pi.port_right,
+ diskfs_port_bucket->portset);
+ assert_perror (err);
}
-/* Create and return a protid for an existing peropen PO in CRED. The uid
- set is UID (length NUIDS); the gid set is GID (length NGIDS). The node
- PO->np must be locked. */
+/* Create and return a protid for an existing peropen PO in CRED for USER.
+ The node PO->np must be locked. */
error_t
-diskfs_create_protid (struct peropen *po, uid_t *uids, int nuids,
- uid_t *gids, int ngids, struct protid **cred)
+diskfs_create_protid (struct peropen *po, struct iouser *user,
+ struct protid **cred)
{
error_t err = diskfs_start_protid (po, cred);
if (! err)
- diskfs_finish_protid (*cred, uids, nuids, gids, ngids);
+ diskfs_finish_protid (*cred, user);
return err;
}
diff --git a/libdiskfs/protid-rele.c b/libdiskfs/protid-rele.c
index 0c5d40ed..be74056a 100644
--- a/libdiskfs/protid-rele.c
+++ b/libdiskfs/protid-rele.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,7 +17,7 @@
#include "priv.h"
-/* Called when a protid CRED has no more references. (Because references\
+/* 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
free the structure for us. */
@@ -26,11 +26,11 @@ diskfs_protid_rele (void *arg)
{
struct protid *cred = arg;
+ iohelp_free_iouser (cred->user);
if (cred->shared_object)
mach_port_deallocate (mach_task_self (), cred->shared_object);
if (cred->mapped)
- vm_deallocate (mach_task_self (), (vm_address_t) cred->mapped,
- vm_page_size);
+ munmap (cred->mapped, vm_page_size);
diskfs_release_peropen (cred->po);
}
diff --git a/libdiskfs/rdwr-internal.c b/libdiskfs/rdwr-internal.c
index 9fe42ade..18a4ae1e 100644
--- a/libdiskfs/rdwr-internal.c
+++ b/libdiskfs/rdwr-internal.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,99,2000 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
@@ -41,16 +41,23 @@ _diskfs_rdwr_internal (struct node *np,
if (dir)
assert (!diskfs_readonly);
+ if (*amt == 0)
+ /* Zero-length writes do not update mtime or anything else, by POSIX. */
+ return 0;
+
if (!diskfs_check_readonly () && !notime)
{
if (dir)
np->dn_set_mtime = 1;
- else
+ else if (! _diskfs_noatime)
np->dn_set_atime = 1;
}
memobj = diskfs_get_filemap (np, prot);
+ if (memobj == MACH_PORT_NULL)
+ return errno;
+
err = pager_memcpy (diskfs_get_filemap_pager_struct (np), memobj,
offset, data, amt, prot);
@@ -58,7 +65,7 @@ _diskfs_rdwr_internal (struct node *np,
{
if (dir)
np->dn_set_mtime = 1;
- else
+ else if (!_diskfs_noatime)
np->dn_set_atime = 1;
}
diff --git a/libdiskfs/opts-runtime-parse.c b/libdiskfs/readonly-changed.c
index 00ec2fc0..44ee9225 100644
--- a/libdiskfs/opts-runtime-parse.c
+++ b/libdiskfs/readonly-changed.c
@@ -1,6 +1,6 @@
-/* A default diskfs_parse_runtime_options routine
+/* Default hook for change to/from read-only
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -18,13 +18,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "priv.h"
+#include "diskfs.h"
-error_t
-diskfs_parse_runtime_options (int argc, char **argv,
- const struct argp *standard_argp)
+/* The user may define this function. It is called when the disk has been
+ changed from read-only to read-write mode or vice-versa. READONLY is the
+ new state (which is also reflected in DISKFS_READONLY). This function is
+ also called during initial startup if the filesystem is to be writable. */
+void
+diskfs_readonly_changed (int readonly)
{
- return argp_parse (standard_argp, argc, argv,
- ARGP_NO_ERRS | ARGP_NO_HELP | ARGP_PARSE_ARGV0,
- 0, 0);
+ /* By default do nothing at all. */
}
diff --git a/libdiskfs/readonly.c b/libdiskfs/readonly.c
index 18ade09a..02f583c8 100644
--- a/libdiskfs/readonly.c
+++ b/libdiskfs/readonly.c
@@ -1,6 +1,6 @@
/* Change to/from read-only
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -21,21 +21,34 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <fcntl.h>
+#include <error.h>
#include "priv.h"
int _diskfs_diskdirty;
+int diskfs_readonly = 0;
+int diskfs_hard_readonly = 0;
int
diskfs_check_readonly ()
{
+ error_t err;
+
if (diskfs_readonly)
return 1;
else
{
if (!_diskfs_diskdirty)
{
- diskfs_set_hypermetadata (1, 0);
+ err = diskfs_set_hypermetadata (1, 0);
+ if (err)
+ {
+ error (0, 0,
+ "%s: MEDIA NOT WRITABLE; switching to READ-ONLY",
+ diskfs_disk_name ?: "-");
+ diskfs_hard_readonly = diskfs_readonly = 1;
+ return 1;
+ }
_diskfs_diskdirty = 1;
}
return 0;
@@ -51,6 +64,9 @@ diskfs_set_readonly (int readonly)
{
error_t err = 0;
+ if (diskfs_hard_readonly)
+ return readonly ? 0 : EROFS;
+
if (readonly != diskfs_readonly)
{
err = ports_inhibit_class_rpcs (diskfs_protid_class);
@@ -60,15 +76,13 @@ diskfs_set_readonly (int readonly)
{
error_t peropen_writable (void *pi)
{
- if (((struct port_info *)pi)->class == diskfs_protid_class
- && (((struct protid *)pi)->po->openstat & O_WRITE))
- return EBUSY;
- else
- return 0;
+ struct protid *const cred = pi;
+ return (cred->po->openstat & O_WRITE) ? EBUSY : 0;
}
/* Any writable open files? */
- err = ports_bucket_iterate (diskfs_port_bucket, peropen_writable);
+ err = ports_class_iterate (diskfs_protid_class,
+ peropen_writable);
/* Any writable pagers? */
if (!err && (diskfs_max_user_pager_prot () & VM_PROT_WRITE))
diff --git a/libdiskfs/shutdown.c b/libdiskfs/shutdown.c
index a3f96e22..f9bc4b57 100644
--- a/libdiskfs/shutdown.c
+++ b/libdiskfs/shutdown.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993,94,95,96,98,99,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -22,10 +22,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
#include <hurd/fsys.h>
-struct rwlock diskfs_fsys_lock = RWLOCK_INITIALIZER;
-
/* Shutdown the filesystem; flags are as for fsys_goaway. */
-error_t
+error_t
diskfs_shutdown (int flags)
{
int nports = -1;
@@ -47,13 +45,13 @@ diskfs_shutdown (int flags)
else
error = 0;
mutex_lock (&np->lock);
-
+
if ((error == MIG_SERVER_DIED) || (error == MACH_SEND_INVALID_DEST))
error = 0;
-
+
return error;
}
-
+
if ((flags & FSYS_GOAWAY_UNLINK)
&& S_ISDIR (diskfs_root_node->dn_stat.st_mode))
return EBUSY;
@@ -66,7 +64,7 @@ diskfs_shutdown (int flags)
}
rwlock_writer_lock (&diskfs_fsys_lock);
-
+
/* Permit all the current RPC's to finish, and then
suspend new ones. */
err = ports_inhibit_class_rpcs (diskfs_protid_class);
@@ -76,9 +74,16 @@ diskfs_shutdown (int flags)
return err;
}
+ /* Write everything out and set "clean" state. Even if we don't in fact
+ shut down now, this has the nice effect that a disk that has not been
+ written for a long time will not need checking after a crash. */
+ diskfs_sync_everything (1);
+ diskfs_set_hypermetadata (1, 1);
+ _diskfs_diskdirty = 0;
+
/* First, see if there are outstanding user ports. */
nports = ports_count_class (diskfs_protid_class);
- if (((flags & FSYS_GOAWAY_FORCE) == 0)
+ if (((flags & FSYS_GOAWAY_FORCE) == 0)
&& (nports || diskfs_pager_users ()))
{
ports_enable_class (diskfs_protid_class);
diff --git a/libdiskfs/sync-default.c b/libdiskfs/sync-default.c
index cdcfde98..0d1fd93b 100644
--- a/libdiskfs/sync-default.c
+++ b/libdiskfs/sync-default.c
@@ -1,6 +1,6 @@
/* A variable holding the initial sync interval
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -18,4 +18,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-int diskfs_default_sync_interval = 30;
+#include "priv.h"
+
+int diskfs_default_sync_interval = DEFAULT_SYNC_INTERVAL;
diff --git a/libdiskfs/sync-interval.c b/libdiskfs/sync-interval.c
index acdb0842..20b9fbb4 100644
--- a/libdiskfs/sync-interval.c
+++ b/libdiskfs/sync-interval.c
@@ -1,8 +1,7 @@
/* Support for periodic syncing
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -68,11 +67,11 @@ diskfs_set_sync_interval (int interval)
else
{
periodic_sync_thread =
- cthread_fork ((cthread_fn_t)periodic_sync, (any_t)interval);
+ cthread_fork ((cthread_fn_t)periodic_sync, (any_t)(intptr_t)interval);
if (periodic_sync_thread)
cthread_detach (periodic_sync_thread);
else
- err = EIEIO;
+ err = ENOMEM;
}
if (!err)
@@ -112,8 +111,14 @@ periodic_sync (int interval)
if (! diskfs_readonly)
{
rwlock_reader_lock (&diskfs_fsys_lock);
- diskfs_sync_everything (0);
- diskfs_set_hypermetadata (0, 0);
+ /* Only sync if we need to, to avoid clearing the clean flag
+ when it's just been set. Any other thread doing a sync
+ will have held the lock while it did its work. */
+ if (_diskfs_diskdirty)
+ {
+ diskfs_sync_everything (0);
+ diskfs_set_hypermetadata (0, 0);
+ }
rwlock_reader_unlock (&diskfs_fsys_lock);
}
ports_end_rpc (pi, &link);
diff --git a/libdiskfs/trans-callback.c b/libdiskfs/trans-callback.c
index 7701199b..283b184f 100644
--- a/libdiskfs/trans-callback.c
+++ b/libdiskfs/trans-callback.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -26,17 +26,20 @@
static error_t
_diskfs_translator_callback1_fn (void *cookie1, void *cookie2,
uid_t *uid, gid_t *gid,
- char **argz, int *argz_len)
+ char **argz, size_t *argz_len)
{
error_t err;
struct node *np = cookie1;
- if (!np->istranslated)
+ if (! (np->dn_stat.st_mode & S_IPTRANS))
return ENOENT;
err = diskfs_get_translator (np, argz, (u_int *) argz_len);
if (err)
- return err;
+ {
+ assert (err != EOPNOTSUPP);
+ return err;
+ }
*uid = np->dn_stat.st_uid;
*gid = np->dn_stat.st_gid;
@@ -53,12 +56,26 @@ _diskfs_translator_callback2_fn (void *cookie1, void *cookie2,
mach_msg_type_name_t *underlying_type)
{
struct node *np = cookie1;
- mach_port_t *dotdot = cookie2;
struct protid *cred;
- error_t err =
- diskfs_create_protid (diskfs_make_peropen (np, flags, *dotdot),
- &np->dn_stat.st_uid, 1, &np->dn_stat.st_gid, 1,
- &cred);
+ struct peropen *po;
+ error_t err;
+ struct iouser *user;
+
+ err = iohelp_create_simple_iouser (&user, np->dn_stat.st_uid,
+ np->dn_stat.st_gid);
+ if (err)
+ return err;
+
+ err = diskfs_make_peropen (np, flags, cookie2, &po);
+ if (! err)
+ {
+ err = diskfs_create_protid (po, user, &cred);
+ if (err)
+ diskfs_release_peropen (po);
+ }
+
+ iohelp_free_iouser (user);
+
if (! err)
{
*underlying = ports_get_right (cred);
diff --git a/libfshelp/ChangeLog b/libfshelp/ChangeLog
deleted file mode 100644
index fb6241bb..00000000
--- a/libfshelp/ChangeLog
+++ /dev/null
@@ -1,430 +0,0 @@
-Tue Jul 16 11:30:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * lock-acquire.c (EWOULDBLOCK): Define, to work around new libc
- bug.
-
-Sun Jul 7 21:26:02 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * start-translator.c (fshelp_start_translator): Don't use unsafe
- MOVE_SEND in call to fshelp_start_translator_long.
- * fetch-root.c (fshelp_fetch_root): Don't use unsafe MOVE_SEND in
- call to fshelp_start_translator_long.
-
-Thu Jul 4 15:38:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * get-identity.c (fshelp_get_identity): Bother to initialize
- I->fileno.
-
-Wed Jul 3 11:29:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * get-identity.c: New file.
- * fshelp.h (struct port_bucket): Mention name in global scope.
- (fshelp_get_identity): New declaration.
- * Makefile (SRCS): Add get-identity.c.
-
-Thu Jun 27 17:56:44 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Add trans.h.
-
-Mon Jun 24 16:00:48 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root): Deal properly with errors from
- auth_makeauth.
-
-Fri Jun 21 00:07:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * set-options.c (fshelp_set_options): Add & use INPUT arg.
- * fshelp.h (fshelp_set_options): Add INPUT argument.
- (fshelp_return_malloced_buffer): New declaration.
- * return-buffer.c: New file.
- * Makefile (SRCS): Add return-buffer.c.
-
-Wed Jun 19 18:50:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * set-options.c: New file.
- * fshelp.h: Add fshelp_set_options.
- * Makefile (SRCS): Add set-options.c.
-
-Fri May 10 16:12:50 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * delegate.c (fshelp_delegate_translation): Don't cast ARGV when
- calling arg_create.
-
-Thu May 9 11:17:08 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * exec-reauth.c (fshelp_exec_reauth): Provide new third arg to
- proc_setowner.
-
- * delegate.c (fshelp_delegate_translation): Cast first arg to
- argz_create appropriately.
-
- * fetch-root.c (fshelp_fetch_root) [reauth]: Use new args for
- auth_user_authenticate.
-
-Fri Apr 26 18:51:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * start-translator-long.c (service_fsys_startup): Make mach_msg
- calls interruptible.
-
-Wed Feb 21 17:09:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * set-active.c (fshelp_set_active): When EXCL, make sure the
- active translator is really active.
-
- * fetch-root.c (fshelp_fetch_root): Make sure the returned fsys control
- port is valid.
-
-Wed Feb 14 16:42:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * start-translator-long.c (fshelp_start_translator_long):
- Terminate TASK if the exec fails.
-
-Mon Jan 29 15:32:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root): Use hurd_condition_wait
- instead of condition_wait.
-
- * set-active.c (fshelp_set_active): Deal correctly with the case
- where a passive translator is being started.
-
-Fri Jan 26 17:56:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root): If io_reauthenticate returns
- an error, just return MACH_PORT_NULL instead of aborting (the
- server probably died; not a good sign for the health of the
- translator, but it's better than dying ourselves...).
-
-Tue Jan 2 15:36:28 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * exec-reauth.c (fshelp_exec_reauth): Don't setgid the uids.
-
-Mon Jan 1 17:13:25 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * exec-reauth.c (fshelp_exec_reauth): New function.
- * fshelp.h (fshelp_exec_reauth): New declaration.
- * Makefile (SRCS): Added exec-reauth.c
-
-Mon Nov 6 13:37:52 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * start-translator-long.c (service_fsys_startup): Don't pass the
- address of reply.realnodeType.msgt_name -- it's not really an int,
- although the compiler pretends it is.
-
- * fetch-root.c (fshelp_fetch_root): When PORT_TYPE is
- MACH_MSG_TYPE_MAKE_SEND, make the right *before* using it.
- (fshelp_fetch_root): Don't bother reauthenticating the underlying
- node returned by CALLBACK2 -- it already has the right ids. This
- also gets rid of a problem with giving away our auth port prematurely.
-
-Wed Nov 1 16:14:08 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root): Uses two callbacks now. Pass
- an appropiate function to fshelp_start_translator_long instead of
- the actual underlying node.
- * fshelp.h (fshelp_fetch_root_callback1_t,
- fshelp_fetch_root_callback2_t): New types replacing fshelp_callback_t.
- (fshelp_fetch_root): Takes two callback args now.
-
- * start-translator.c (fshelp_start_translator): Change to use a
- callback function instead of passing the actual node.
- * start-translator-long.c (fshelp_start_translator_long,
- service_fsys_startup): Ditto.
- (service_fsys_startup): Support the open flags coming from the
- translator.
- (struct fsys_startup_request): Add the flags field.
- (flagsCheck): New variable.
- * fshelp.h (fshelp_open_fn_t): New type.
- (fshelp_start_translator, fshelp_start_translator_long): Now take
- a function that opens the underlying node instead of the node itself.
-
-Fri Oct 13 16:52:43 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * start-translator-long.c (fshelp_start_translator_long): Undo
- last change to file_exec args.
-
-Sat Oct 7 20:20:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * start-translator-long.c (fshelp_start_translator_long): Add
- values for the dealloc parameters to file_exec (all false).
- Give away our send right to TASK when we do file_exec.
- Initialize BOOTSTRAP & TASK so the cleanup code doesn't get confused.
-
-Fri Sep 29 17:44:00 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * transbox-init.c (fshelp_transbox_init): Initialize the flags field.
-
-Tue Sep 5 18:25:24 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fshelp.h (fshelp_delegate_translation): New declaration.
- * delegate.c (fshelp_delegate_translation): New file, new function.
-
-Fri Sep 1 12:01:06 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Add delegate.c.
- (REMHDRS): Removed.
-
-Tue Jul 11 14:11:24 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * start-translator-long.c (fshelp_start_translator_long): If
- PORTS_TYPE is MACH_MSG_TYPE_COPY_SEND, then drop our right on
- bootstrap after the call, because we are pretending we haven't
- changed the calling user's state. For the same reason, save the
- old BOOTSTRAP port value, and restore it after the call.
-
-Thu Jul 6 15:35:23 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Mon Jun 26 15:36:21 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root): Wakeup other blocked calls
- *before* returning errors provided by fshelp_start_translator_long
- or CALLBACK.
-
-Fri Jun 23 14:25:52 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root): Parenthesize assert test
- correctly.
- * start-translator-long.c (service_fsys_startup): Parenthesize
- construction of flags arg correctly.
-
-Thu Jun 22 17:06:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root) [reauth]: If PORT is null, then
- just return it.
-
- * fetch-root.c (fshelp_fetch_root): Pass type and length
- parameters in the right order in calls to auth_makeauth and
- fshelp_start_translator_long.
-
-Wed Jun 21 13:19:44 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fetch-root.c (fshelp_fetch_root): Pass new third arg to
- fshelp_set_active.
-
-Mon Jun 19 16:41:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fetch-control.c (fshelp_fetch_control): Only frob refs if
- control is non-null.
-
- * fshelp.h (fshelp_set_active): New parm EXCL.
- * set-active.c (fshelp_set_active): Implement new interface.
-
- * fetch-control.c (fshelp_fetch_control): Don't frob obsolete
- innerlock.
- * transbox-init.c (fshelp_transbox_init): Don't init obsolete
- innerlock. Do init TRANSBOX->wakeup.
- * set-active.c (fshelp_set_active): Don't frob obsolete innerlock.
- * fetch-root.c (fshelp_fetch_root): Reduce levels of loops. Only
- change ACTIVE when we are holding the lock. Use condition
- mechanism to serialize attempts to start the passive translator.
- * fshelp.h (struct transbox): Delete member `innerlock'. Add
- members `flags' and `wakeup'; and define values for flags.
-
-Wed Jun 14 13:06:17 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fshelp.h (fshelp_fetch_root): New arg COOKIE.
- (fshelp_callback_t): COOKIE->COOKIE1. New arg COOKIE2.
- * fetch-root.c (fshelp_fetch_root): Take new arg COOKIE and pass
- it to CALLBACK. Free ARGZ after we're done with them. Never
- consume the right on DOTDOT.
- * Makefile (LCLHDRS): Removed trans.h.
- * handle-startup.c, init-trans.c, start-trans.c,
- transboot-clean.c, kill-trans.c, trans-iter.c, trans-cntl.c,
- trans-drop.c, trans.h: Deleted files.
-
- * Makefile (SRCS): Remove translated.c.
- * fshelp.h (fshelp_fetch_root): Don't actually need ROOT_TYPE.
- UIDS and GIDS should be arrays.
- (fshelp_callback_t): Should be error_t.
-
-Tue Jun 13 15:59:08 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- Brand new translator support routines
- * fshelp.h: Deleted `struct translink', fshelp_transboot_port_type,
- fshelp_init_trans_link, fshelp_set_control,
- fshelp_start_translator, fshelp_handle_fsys_startup,
- fshelp_transboot_clean, fshelp_translator_iterate,
- fshelp_translator_drop, fshelp_kill_translator.
- * fshelp.h: Added fshelp_start_translator_long,
- fshelp_start_translator, `struct transbox', fshelp_fetch_root,
- fshelp_transbox_init, fshelp_callback_t, fshelp_translated,
- fshelp_set_active, fshelp_fetch_control, fshelp_drop_transbox.
- * Makefile (SRCS): Removed handle-startup.c, init-trans.c,
- start-trans.c, transboot-clean.c, kill-trans.c, trans-iter.c,
- trans-cntl.c, trans-drop.c. Added start-translator-long.c,
- start-translator.c, fetch-root.c, transbox-init.c, translated.c,
- set-active.c, fetch-control.c, and drop-transbox.c.
- (OBJS): Replaced with computation from $(SRCS).
- * start-translator.c, fetch-root.c, transbox-init.c, set-active.c,
- fetch-control.c, drop-transbox.c: New files.
- * start-translator-long.c: Adapted from ../lib/start-trans.c.
- Include "fshelp.h" and <assert.h>.
- (service_fsys_startup): Declare static. Only pass
- MACH_RCV_TIMEOUT if TIMEOUT is nonzero. New parm `node_type'.
- (fshelp_start_translator_long): Renamed from start_translator.
- Lookup up executable at NAME instead of ARGZ. Delete vars
- INIT_PORTS, FD_PORTS, INIT_INTS, I, and CHILD_PROC. Don't set any
- of the ports, fds, or ints, with the exception of the bootstrap
- port. Don't bother getting the child's proc server port.
- Don't use __USEPORT. If we fail before calling file_exec,
- then deallocate the ports ourselves, if they were MOVE_SEND.
-
-Fri Oct 28 18:37:56 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * start-trans.c: Change `assert (!err)' to `assert_perror (err)'
- throughout.
- (fshelp_start_translator): Add assert_perror for io_reauthenticate
- return.
-
-Mon Sep 19 20:58:35 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * trans-iter.c (fshelp_translator_iterate): Bother to attach
- ITEM onto LIST as it's constructed.
-
-Sat Sep 10 08:42:00 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * transboot-clean.c (fshelp_transboot_clean): Use EDIED, not EINVAL.
-
-Wed Sep 7 10:34:13 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * start-trans.c (fshelp_start_translator): RETRY label belongs
- *after* initial lock of LINK. Unlock LINK before returning.
-
-Tue Sep 6 14:52:49 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * fshelp.h (struct trans_link): New member `lock'.
- (fshelp_start_translator): Omit `lock' arg.
- * trans.h (struct transboot): Omit member `lock'.
- * init-trans.c (fshelp_init_trans_link): Initialize LINK->lock.
- * start-trans.c (fshelp_start_translator): Don't set TB->lock.
- Omit `lock' arg; use LINK->lock instead.
- (fshelp_start_translator): Don't deallocate DIR.
- * handle-startup.c (fshelp_handle_fsys_startup): Lock
- TB->link->lock instead of TB->lock.
- * transboot-clean.c (fshelp_transboot_clean): Likewise.
-
-Thu Sep 1 16:46:53 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * fshelp.h (fshelp_start_translator): Doc fix.
- * start-trans.c (fshelp_start_translator): Don't reauthenticate
- NODE argument; expect fully authenticated node.
-
-Wed Aug 31 14:28:25 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * start-trans.c (fshelp_start_translator): Before call to
- proc_reauthenticate, CALL mach_reply_port, not just refer to
- confusing CPP macro.
-
- * start-trans.c (fshelp_start_translator): Call proc_setowner
- for new process.
-
-Tue Aug 30 16:19:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * start-trans.c: Include <string.h>.
-
- * start-trans.c (fshelp_start_translator): Use new
- reauthentication protocol throughout.
-
- * start-trans.c (fshelp_start_translator): Use
- hurd_file_name_lookup instead of hurd_path_lookup.
-
-Wed Aug 17 16:03:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * start-trans.c (fshelp_start_translator): Designate the new
- process as our child; then make sure it's under its own
- authentication. As long as we've gotten the proc port for
- this operation, might as well pass it too.
- (fshelp_start_translator): Zero init ints and init ports.
-
- * transboot-clean.c (fshelp_transboot_clean): Only set an error
- if we haven't gotten fsys_startup yet.
-
-Mon Aug 15 12:24:47 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * start-trans.c (fshelp_start_translator): Set LINK->starting
- before blocking.
- * handle-startup.c (fshelp_handle_fsys_startup): Clear
- LINK->starting before waking up blocks.
-
- * fshelp.h (struct trans_link): New member `error'.
- * transboot-clean.c (fshelp_transboot_clean): Wakeup blocked
- users with error.
- * trans-cntl.c (fshelp_set_control): Clear LINK->error.
- * init-trans.c (fshelp_init_trans_link): Likewise.
-
- * start-trans.c (fshelp_start_translator): Fix
- auth_user_authenticate to use the correct rendezvous port in
- producing realnode from node..
-
-Fri Jul 22 12:03:14 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
-
-Wed Jul 20 13:31:39 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * start-trans.c (fshelp_start_translator): Missing first arg
- to mach_port_deallocate of `dir'.
-
-Tue Jul 19 18:44:53 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fshelp.h (fshelp_start_translator): Doc fix.
- (fshelp_handle_fsys_startup): Deleted dotdot args.
- * trans.h (struct transboot): Removed member `dir'.
- * start-trans.c (fshelp_start_translator): Don't initialize
- TB->dir.
- (fshelp_start_translator): Deallocate DIR arg when we're
- done with it.
- * handle-startup.c (fshelp_handle_fsys_startup): Deleted
- dotdot args.
- * transboot-clean.c (fshelp_transboot_clean): Don't free
- no-longer-existent TB->dir.
-
-Fri Jul 8 12:58:54 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * trans-cntl.c: Include <assert.h>.
-
-Thu Jul 7 18:08:49 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * trans-drop.c: New file.
- * fshelp.h (fshelp_translator_drop): New declaration.
- * Makefile (OBJS): Added trans-drop.o.
- (SRCS): ADded trans-drop.c.
-
-Tue Jul 5 14:14:53 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (DIST_FILES): New variable.
-
-Thu Jun 16 16:27:39 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * fshelp.h (fshelp_get_node_port, fshelp_done_with_node): Deleted
- prototypes.
- (fshelp_start_translator): Changed types of DIR and NODE to be
- file_t.
- * trans.h (struct transboot): Deleted members UID and GID.
- Changed types of DIR and NODE to be file_t.
- * transboot-clean.c (fshelp_transboot_clean): Deallocate ports
- TB->node and TB->dir instead of calling fshelp_done_with_node.
- * start-trans.c (fshelp_start_translator): Changed types of
- DIR and MODE to be file_t. Rewritten to behave correctly in
- numerous ways.
- * handle-startup.c (fshelp_handle_fsys_startup): Return REAL
- and DIR from ports in TB instead of calling fshelp_get_node_port.
-
-Fri Jun 3 18:13:04 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fshelp.h (fshelp_set_control): New declaration.
- * trans-cntl.c: New file.
- * Makefile (SRCS): Added trans-cntl.c.
- (OBJS): Added trans-cntl.o.
- trans-cntl.o: Depend on trans.h.
-
-Thu May 5 07:46:00 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
-Mon Feb 14 11:32:59 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile (install): New target.
-
diff --git a/libfshelp/Makefile b/libfshelp/Makefile
index ac2d0c9a..30879dc9 100644
--- a/libfshelp/Makefile
+++ b/libfshelp/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1994, 95, 96, 98, 1999, 2006 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
@@ -22,17 +22,18 @@ libname = libfshelp
SRCS = lock-acquire.c lock-init.c \
start-translator-long.c start-translator.c \
fetch-root.c transbox-init.c set-active.c fetch-control.c \
- drop-transbox.c \
+ drop-transbox.c translated.c \
delegate.c \
exec-reauth.c \
set-options.c \
- return-buffer.c get-identity.c
+ get-identity.c \
+ perms-isowner.c perms-iscontroller.c perms-access.c \
+ perms-checkdirmod.c \
+ touch.c
LCLHDRS = fshelp.h locks.h trans.h
installhdrs = fshelp.h
+HURDLIBS = shouldbeinlibc threads iohelp ports
OBJS = $(subst .c,.o,$(SRCS))
include ../Makeconf
-
-libfshelp.so: $(foreach lib,shouldbeinlibc threads,\
- ../lib$(lib)/lib$(lib).so)
diff --git a/libfshelp/delegate.c b/libfshelp/delegate.c
index cb8b8365..a44310f0 100644
--- a/libfshelp/delegate.c
+++ b/libfshelp/delegate.c
@@ -1,8 +1,7 @@
/* fshelp_delegate_translation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,99,2000,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -30,7 +29,7 @@
ARGV is the command line. If SERVER_NAME is NULL, then a name is
concocted by appending ARGV[0] to _SERVERS. */
error_t
-fshelp_delegate_translation (char *server_name,
+fshelp_delegate_translation (const char *server_name,
mach_port_t requestor, char **argv)
{
error_t err;
@@ -48,12 +47,15 @@ fshelp_delegate_translation (char *server_name,
if (server != MACH_PORT_NULL)
{
char *argz;
- int argz_len;
+ size_t argz_len;
err = argz_create (argv, &argz, &argz_len);
if (!err)
- err = fsys_forward (server,
- requestor, MACH_MSG_TYPE_COPY_SEND,
- argz, argz_len);
+ {
+ err = fsys_forward (server,
+ requestor, MACH_MSG_TYPE_COPY_SEND,
+ argz, argz_len);
+ free (argz);
+ }
}
else
err = errno;
diff --git a/libfshelp/exec-reauth.c b/libfshelp/exec-reauth.c
index e6009827..d9a82974 100644
--- a/libfshelp/exec-reauth.c
+++ b/libfshelp/exec-reauth.c
@@ -1,9 +1,9 @@
/* Setuid reauthentication for exec
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,2002 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>,
- from the original by Michael I. Bushnell p/BSG <mib@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>,
+ from the original by Michael I. Bushnell p/BSG <mib@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -83,7 +83,7 @@ fshelp_exec_reauth (int suid, uid_t uid, int sgid, gid_t gid,
/* STEP 3: Attempt to create this new auth handle. */
err = auth_makeauth (auth, &ports[INIT_PORT_AUTH],
- MACH_MSG_TYPE_COPY_SEND, 1,
+ MACH_MSG_TYPE_COPY_SEND, 1,
eff_uids->ids, eff_uids->num,
avail_uids->ids, avail_uids->num,
eff_gids->ids, eff_gids->num,
@@ -108,12 +108,12 @@ fshelp_exec_reauth (int suid, uid_t uid, int sgid, gid_t gid,
if (suid && !err)
err = idvec_setid (eff_uids, avail_uids, uid, &_secure);
if (sgid && !err)
- err = idvec_setid (eff_uids, avail_uids, gid, &_secure);
+ err = idvec_setid (eff_gids, avail_gids, gid, &_secure);
if (err)
goto abandon_suid;
/* Trrrry again... */
- err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 1,
+ err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 1,
eff_uids->ids, eff_uids->num,
avail_uids->ids, avail_uids->num,
eff_gids->ids, eff_gids->num,
@@ -130,8 +130,9 @@ fshelp_exec_reauth (int suid, uid_t uid, int sgid, gid_t gid,
/* Re-authenticate the exec parameters. */
exec_reauth (newauth, _secure, 0, ports, num_ports, fds, num_fds);
- if (eff_uids->num > 0)
- proc_setowner (ports[INIT_PORT_PROC], eff_uids->ids[0], 0);
+ proc_setowner (ports[INIT_PORT_PROC],
+ eff_uids->num > 0 ? eff_uids->ids[0] : 0,
+ !eff_uids->num);
abandon_suid:
if (eff_uids)
@@ -144,7 +145,7 @@ fshelp_exec_reauth (int suid, uid_t uid, int sgid, gid_t gid,
idvec_free (avail_gids);
}
- if (_secure && secure)
+ if (secure)
*secure = _secure;
return err;
diff --git a/libfshelp/fetch-root.c b/libfshelp/fetch-root.c
index b38b276d..54d3c0ca 100644
--- a/libfshelp/fetch-root.c
+++ b/libfshelp/fetch-root.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,99,2000,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -27,19 +27,18 @@
error_t
fshelp_fetch_root (struct transbox *box, void *cookie,
file_t dotdot,
- uid_t *uids, int uids_len,
- uid_t *gids, int gids_len,
+ struct iouser *user,
int flags,
fshelp_fetch_root_callback1_t callback1,
fshelp_fetch_root_callback2_t callback2,
- retry_type *retry, char *retryname,
+ retry_type *retry, char *retryname,
file_t *root)
{
error_t err;
mach_port_t control;
int cancel;
int i;
-
+
start_over:
if (box->active != MACH_PORT_NULL)
@@ -48,50 +47,51 @@ fshelp_fetch_root (struct transbox *box, void *cookie,
{
uid_t uid, gid;
char *argz;
- int argz_len;
+ size_t argz_len;
error_t err;
mach_port_t ports[INIT_PORT_MAX];
int ints[INIT_INT_MAX];
mach_port_t fds[STDERR_FILENO + 1];
auth_t ourauth, newauth;
- int uidarray[2], gidarray[2];
-
- mach_port_t
- reauth (mach_port_t port, mach_msg_type_name_t port_type)
- {
- mach_port_t rend, ret;
- error_t err;
-
- if (port == MACH_PORT_NULL)
- return port;
-
- if (port_type == MACH_MSG_TYPE_MAKE_SEND)
- mach_port_insert_right (mach_task_self (), port, port,port_type);
-
- rend = mach_reply_port ();
-
- err = io_reauthenticate (port, rend,
- MACH_MSG_TYPE_MAKE_SEND);
- if (! err)
- err = auth_user_authenticate (newauth, rend,
- MACH_MSG_TYPE_MAKE_SEND, &ret);
- if (err)
- ret = MACH_PORT_NULL;
-
- mach_port_destroy (mach_task_self (), rend);
- if (!err && port_type != MACH_MSG_TYPE_COPY_SEND)
- mach_port_deallocate (mach_task_self (), port);
-
- return ret;
- }
+
+ mach_port_t reauth (mach_port_t port) /* Consumes PORT. */
+ {
+ mach_port_t rend, ret;
+ error_t err;
+
+ if (port == MACH_PORT_NULL)
+ return port;
+
+ if (ourauth == MACH_PORT_NULL)
+ /* We have no auth server, so we aren't doing reauthentications.
+ Just pass on our own ports directly. */
+ return port;
+
+ rend = mach_reply_port ();
+
+ /* MAKE_SEND is safe here because we destroy REND ourselves. */
+ err = io_reauthenticate (port, rend,
+ MACH_MSG_TYPE_MAKE_SEND);
+ mach_port_deallocate (mach_task_self (), port);
+ if (! err)
+ err = auth_user_authenticate (newauth, rend,
+ MACH_MSG_TYPE_MAKE_SEND, &ret);
+ if (err)
+ ret = MACH_PORT_NULL;
+
+ mach_port_destroy (mach_task_self (), rend);
+
+ return ret;
+ }
error_t fetch_underlying (int flags, mach_port_t *underlying,
- mach_msg_type_name_t *underlying_type)
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
{
return
(*callback2) (box->cookie, cookie, flags,
underlying, underlying_type);
}
-
+
if (box->flags & TRANSBOX_STARTING)
{
box->flags |= TRANSBOX_WANTED;
@@ -102,50 +102,57 @@ fshelp_fetch_root (struct transbox *box, void *cookie,
}
box->flags |= TRANSBOX_STARTING;
mutex_unlock (box->lock);
-
+
err = (*callback1) (box->cookie, cookie, &uid, &gid, &argz, &argz_len);
if (err)
goto return_error;
-
+
ourauth = getauth ();
- uidarray[0] = uidarray[1] = uid;
- gidarray[0] = gidarray[1] = gid;
- err = auth_makeauth (ourauth, 0, MACH_MSG_TYPE_MAKE_SEND, 0,
- uidarray, 1, uidarray, 2,
- gidarray, 1, gidarray, 2, &newauth);
- if (err)
- goto return_error;
-
+ if (ourauth == MACH_PORT_NULL)
+ newauth = ourauth;
+ else
+ {
+ uid_t uidarray[2] = { uid, uid };
+ gid_t gidarray[2] = { gid, gid };
+ err = auth_makeauth (ourauth, 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ uidarray, 1, uidarray, 2,
+ gidarray, 1, gidarray, 2, &newauth);
+ if (err)
+ goto return_error;
+ }
+
bzero (ports, INIT_PORT_MAX * sizeof (mach_port_t));
bzero (fds, (STDERR_FILENO + 1) * sizeof (mach_port_t));
bzero (ints, INIT_INT_MAX * sizeof (int));
-
- ports[INIT_PORT_CWDIR] = reauth (getcwdir (), MACH_MSG_TYPE_MOVE_SEND);
- ports[INIT_PORT_CRDIR] = reauth (getcrdir (), MACH_MSG_TYPE_MOVE_SEND);
+
+ ports[INIT_PORT_CWDIR] = dotdot;
+ ports[INIT_PORT_CRDIR] = reauth (getcrdir ());
ports[INIT_PORT_AUTH] = newauth;
-
- fds[STDERR_FILENO] =
- reauth (getdport (STDERR_FILENO), MACH_MSG_TYPE_MOVE_SEND);
-
- err = fshelp_start_translator_long (fetch_underlying,
+
+ fds[STDERR_FILENO] = reauth (getdport (STDERR_FILENO));
+
+ err = fshelp_start_translator_long (fetch_underlying, NULL,
argz, argz, argz_len,
fds, MACH_MSG_TYPE_COPY_SEND,
STDERR_FILENO + 1,
ports, MACH_MSG_TYPE_COPY_SEND,
- INIT_PORT_MAX,
+ INIT_PORT_MAX,
ints, INIT_INT_MAX,
+ uid,
0, &control);
for (i = 0; i <= STDERR_FILENO; i++)
mach_port_deallocate (mach_task_self (), fds[i]);
+
for (i = 0; i < INIT_PORT_MAX; i++)
- mach_port_deallocate (mach_task_self (), ports[i]);
-
+ if (i != INIT_PORT_CWDIR)
+ mach_port_deallocate (mach_task_self (), ports[i]);
+
mutex_lock (box->lock);
-
+
free (argz);
return_error:
-
+
box->flags &= ~TRANSBOX_STARTING;
if (box->flags & TRANSBOX_WANTED)
{
@@ -162,19 +169,20 @@ fshelp_fetch_root (struct transbox *box, void *cookie,
box->active = control;
}
-
+
control = box->active;
- mach_port_mod_refs (mach_task_self (), control,
+ mach_port_mod_refs (mach_task_self (), control,
MACH_PORT_RIGHT_SEND, 1);
mutex_unlock (box->lock);
-
+
/* Cancellation point XXX */
err = fsys_getroot (control, dotdot, MACH_MSG_TYPE_COPY_SEND,
- uids, uids_len, gids, gids_len, flags,
- retry, retryname, root);
-
+ user->uids->ids, user->uids->num,
+ user->gids->ids, user->gids->num,
+ flags, retry, retryname, root);
+
mutex_lock (box->lock);
-
+
if ((err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
&& control == box->active)
fshelp_set_active (box, MACH_PORT_NULL, 0);
@@ -182,9 +190,6 @@ fshelp_fetch_root (struct transbox *box, void *cookie,
if (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
goto start_over;
-
+
return err;
}
-
-
-
diff --git a/libfshelp/fshelp.h b/libfshelp/fshelp.h
index 9461ae50..9f4fa677 100644
--- a/libfshelp/fshelp.h
+++ b/libfshelp/fshelp.h
@@ -1,5 +1,5 @@
/* FS helper library definitions
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,98,99,2000,01,02 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
@@ -19,7 +19,7 @@
#define _HURD_FSHELP_
/* This library implements various things that are generic to
- all or most implementors of the filesystem protocol. It
+ all or most implementors of the filesystem protocol. It
presumes that you are using the iohelp library as well. It
is divided into separate facilities which may be used independently. */
@@ -27,6 +27,9 @@
#include <mach.h>
#include <hurd/hurd_types.h>
#include <cthreads.h>
+#include <hurd/iohelp.h>
+#include <sys/stat.h>
+#include <maptime.h>
/* Passive translator linkage */
@@ -35,11 +38,12 @@
or the ports library. */
/* A callback used by the translator starting functions, which should be a
- function that given some open flags, opens the appropiate file, and
+ function that given some open flags, opens the appropriate file, and
returns the node port. */
typedef error_t (*fshelp_open_fn_t) (int flags,
file_t *node,
- mach_msg_type_name_t *node_type);
+ mach_msg_type_name_t *node_type,
+ task_t, void *cookie);
/* Start a passive translator NAME with arguments ARGZ (length
ARGZ_LEN). Initialize the initports to PORTS (length PORTS_LEN),
@@ -47,15 +51,18 @@ typedef error_t (*fshelp_open_fn_t) (int flags,
table to FDS (length FDS_LEN). Return the control port in
*CONTROL. If the translator doesn't respond or die in TIMEOUT
milliseconds (if TIMEOUT > 0), return an appropriate error. If the
- translator dies before responding, return EDIED. */
+ translator dies before responding, return EDIED. Set the new
+ task's owner to OWNER_UID (or, if OWNER_UID is -1, then clear the
+ new task's owner. */
error_t
-fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn,
+fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn, void *cookie,
char *name, char *argz, int argz_len,
- mach_port_t *fds,
+ mach_port_t *fds,
mach_msg_type_name_t fds_type, int fds_len,
- mach_port_t *ports,
+ mach_port_t *ports,
mach_msg_type_name_t ports_type, int ports_len,
int *ints, int ints_len,
+ uid_t owner_uid,
int timeout, fsys_t *control);
@@ -63,7 +70,7 @@ fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn,
are copied from our own state, fd[2] is copied from our own stderr,
and the other fds are cleared. */
error_t
-fshelp_start_translator (fshelp_open_fn_t underlying_open_fn,
+fshelp_start_translator (fshelp_open_fn_t underlying_open_fn, void *cookie,
char *name, char *argz, int argz_len,
int timeout, fsys_t *control);
@@ -75,7 +82,7 @@ fshelp_start_translator (fshelp_open_fn_t underlying_open_fn,
use the passive translator routines above, but they don't require
the ports library at all. */
-struct transbox
+struct transbox
{
fsys_t active;
struct mutex *lock;
@@ -98,8 +105,8 @@ struct transbox
then return ENOENT. COOKIE1 is the cookie passed in fshelp_transbox_init.
COOKIE2 is the cookie passed in the call to fshelp_fetch_root. */
typedef error_t (*fshelp_fetch_root_callback1_t) (void *cookie1, void *cookie2,
- uid_t *uid, gid_t *gid,
- char **argz, int *argz_len);
+ uid_t *uid, gid_t *gid,
+ char **argz, size_t *argz_len);
/* This routine is called by fshelp_fetch_root to fetch more information.
Return an unauthenticated node for the file itself in *UNDERLYING and
@@ -113,18 +120,16 @@ typedef error_t (*fshelp_fetch_root_callback2_t) (void *cookie1, void *cookie2,
*underlying_type);
/* Fetch the root from TRANSBOX. DOTDOT is an unauthenticated port
- for the directory in which we are looking; UIDS (length UIDS_LEN)
- and GIDS (length GIDS_LEN) are the ids of the user responsible for
- the call. FLAGS are as for dir_pathtrans (but O_CREAT and O_EXCL
- are not meaningful and are ignored). The trasnbox lock (as
- set by fshelp_transbox_init) must be held before the call, and will
- be held upon return, but may be released during the operation of
- the call. */
+ for the directory in which we are looking; USER specifies the ids
+ of the user responsible for the call. FLAGS are as for dir_lookup
+ (but O_CREAT and O_EXCL are not meaningful and are ignored). The
+ transbox lock (as set by fshelp_transbox_init) must be held before
+ the call, and will be held upon return, but may be released during
+ the operation of the call. */
error_t
fshelp_fetch_root (struct transbox *transbox, void *cookie,
- file_t dotdot,
- uid_t *uids, int uids_len,
- uid_t *gids, int gids_len,
+ file_t dotdot,
+ struct iouser *user,
int flags,
fshelp_fetch_root_callback1_t callback1,
fshelp_fetch_root_callback2_t callback2,
@@ -136,11 +141,7 @@ fshelp_transbox_init (struct transbox *transbox,
void *cookie);
/* Return true iff there is an active translator on this box */
-extern inline int
-fshelp_translated (struct transbox *box)
-{
- return (box->active != MACH_PORT_NULL);
-}
+int fshelp_translated (struct transbox *box);
/* Atomically replace the existing active translator port for this box
with NEWACTIVE. If EXCL is non-zero then don't frob an existing
@@ -171,11 +172,11 @@ struct lock_box
There should be one lock box per object and one int per open; these
are passed as arguments BOX and USER respectively. FLAGS are as
per file_lock. MUT is a mutex which will be held whenever this
- routine is called, to lock BOX->wait. */
-error_t fshelp_acquire_lock (struct lock_box *box, int *user,
+ routine is called, to lock BOX->wait. */
+error_t fshelp_acquire_lock (struct lock_box *box, int *user,
struct mutex *mut, int flags);
-
+
/* Initialize lock_box BOX. (The user int passed to fshelp_acquire_lock
should be initialized with LOCK_UN.). */
void fshelp_lock_init (struct lock_box *box);
@@ -193,7 +194,7 @@ struct port_bucket; /* shut up C compiler */
notifications) are used.
*/
error_t fshelp_get_identity (struct port_bucket *bucket,
- ino_t fileno, mach_port_t *pt);
+ ino64_t fileno, mach_port_t *pt);
@@ -201,7 +202,7 @@ error_t fshelp_get_identity (struct port_bucket *bucket,
the node SERVER_NAME. REQUESTOR is the translator's bootstrap port, and
ARGV is the command line. If SERVER_NAME is NULL, then a name is
concocted by appending ARGV[0] to _SERVERS. */
-error_t fshelp_delegate_translation (char *server_name,
+error_t fshelp_delegate_translation (const char *server_name,
mach_port_t requestor, char **argv);
struct idvec; /* Include <idvec.h> to get the real thing. */
@@ -227,13 +228,44 @@ struct argp; /* Include <argp.h> to get the real thing. */
/* Invoke ARGP with data from DATA & LEN, in the standard way. */
error_t fshelp_set_options (struct argp *argp, int flags,
- char *argz, size_t argz_len, void *input);
+ const char *argz, size_t argz_len, void *input);
+
-/* Puts data from the malloced buffer BUF, LEN bytes long, into RBUF & RLEN,
- suitable for returning from a mach rpc. If LEN > 0, BUF is freed,
- regardless of whether an error is returned or not. */
-error_t fshelp_return_malloced_buffer (char *buf, size_t len,
- char **rbuf,
- mach_msg_type_number_t *rlen);
+/* Standardized filesystem permission checking */
+/* Check to see whether USER should be considered the owner of the
+ file identified by ST. If so, return zero; otherwise return an
+ appropriate error code. */
+error_t fshelp_isowner (io_statbuf_t *st, struct iouser *user);
+
+/* Check to see whether USER should be considered a controller of the
+ filesystem. Which is to say, check to see if we should give USER the
+ control port. ST is the stat of the root node. USER is the user
+ asking for a send right to the control port. */
+error_t
+fshelp_iscontroller (io_statbuf_t *st, struct iouser *user);
+
+/* Check to see whether the user USER can operate on a file identified
+ by ST. OP is one of S_IREAD, S_IWRITE, and S_IEXEC. If the access
+ is permitted, return zero; otherwise return an appropriate error
+ code. */
+error_t fshelp_access (io_statbuf_t *st, int op, struct iouser *user);
+
+/* Check to see whether USER is allowed to modify DIR with respect to
+ existing file ST. (If there is no existing file, pass 0 for ST.)
+ If the access is permissible return 0; otherwise return an
+ appropriate error code. */
+error_t fshelp_checkdirmod (io_statbuf_t *dir, io_statbuf_t *st,
+ struct iouser *user);
+
+
+/* Timestamps to change. */
+#define TOUCH_ATIME 0x1
+#define TOUCH_MTIME 0x2
+#define TOUCH_CTIME 0x4
+
+/* Change the stat times of NODE as indicated by WHAT (from the set TOUCH_*)
+ to the current time. */
+void fshelp_touch (io_statbuf_t *st, unsigned what,
+ volatile struct mapped_time_value *maptime);
#endif
diff --git a/libfshelp/get-identity.c b/libfshelp/get-identity.c
index 05d76491..51c5fb29 100644
--- a/libfshelp/get-identity.c
+++ b/libfshelp/get-identity.c
@@ -1,5 +1,5 @@
/* Helper function for io_identity
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -26,7 +26,7 @@
static struct port_class *idclass = 0;
static struct mutex idlock = MUTEX_INITIALIZER;
-struct idspec
+struct idspec
{
struct port_info pi;
ino_t fileno;
@@ -50,7 +50,7 @@ fshelp_get_identity (struct port_bucket *bucket,
error_t check_port (void *arg)
{
struct idspec *i = arg;
- if (i->pi.class == idclass && i->fileno == fileno)
+ if (i->fileno == fileno)
{
*pt = ports_get_right (i);
return 1;
@@ -64,15 +64,15 @@ fshelp_get_identity (struct port_bucket *bucket,
id_initialize ();
*pt = MACH_PORT_NULL;
-
- ports_bucket_iterate (bucket, check_port);
+
+ ports_class_iterate (idclass, check_port);
if (*pt != MACH_PORT_NULL)
{
mutex_unlock (&idlock);
return 0;
}
-
+
err = ports_create_port (idclass, bucket, sizeof (struct idspec), &i);
if (err)
{
@@ -80,11 +80,9 @@ fshelp_get_identity (struct port_bucket *bucket,
return err;
}
i->fileno = fileno;
-
+
*pt = ports_get_right (i);
ports_port_deref (i);
mutex_unlock (&idlock);
return 0;
}
-
-
diff --git a/libfshelp/lock-acquire.c b/libfshelp/lock-acquire.c
index 9c81634a..bad1114d 100644
--- a/libfshelp/lock-acquire.c
+++ b/libfshelp/lock-acquire.c
@@ -42,9 +42,11 @@ fshelp_acquire_lock (struct lock_box *box, int *user, struct mutex *mut,
if (flags & LOCK_UN)
{
if (*user & LOCK_UN)
- return EBADF;
+ return 0;
+
assert (*user == box->type);
assert (*user == LOCK_SH || *user == LOCK_EX);
+
if (*user == LOCK_SH)
{
if (!--box->shcount)
@@ -80,7 +82,8 @@ fshelp_acquire_lock (struct lock_box *box, int *user, struct mutex *mut,
if (flags & LOCK_NB)
return EWOULDBLOCK;
box->waiting = 1;
- condition_wait (&box->wait, mut);
+ if (hurd_condition_wait (&box->wait, mut))
+ return EINTR;
}
/* If we have a shared lock, release it. */
@@ -108,15 +111,16 @@ fshelp_acquire_lock (struct lock_box *box, int *user, struct mutex *mut,
}
else if (flags & LOCK_EX)
{
- /* Wait for any shared locks to finish. */
- while (box->type == LOCK_SH)
+ /* Wait for any shared (and exclusive) locks to finish. */
+ while (box->type != LOCK_UN)
{
if (flags & LOCK_NB)
return EWOULDBLOCK;
else
{
box->waiting = 1;
- condition_wait (&box->wait, mut);
+ if (hurd_condition_wait (&box->wait, mut))
+ return EINTR;
}
}
box->type = LOCK_EX;
diff --git a/libfshelp/perms-access.c b/libfshelp/perms-access.c
new file mode 100644
index 00000000..67e52812
--- /dev/null
+++ b/libfshelp/perms-access.c
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include "fshelp.h"
+
+/* Check to see whether the user USER can operate on a file identified
+ by ST. OP is one of S_IREAD, S_IWRITE, and S_IEXEC. If the access
+ is permitted, return zero; otherwise return an appropriate error
+ code. */
+error_t
+fshelp_access (struct stat *st, int op, struct iouser *user)
+{
+ int gotit;
+ if (idvec_contains (user->uids, 0))
+ 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))
+ gotit = st->st_mode & op;
+ else if (idvec_contains (user->gids, st->st_gid))
+ gotit = st->st_mode & (op >> 3);
+ else
+ gotit = st->st_mode & (op >> 6);
+ return gotit ? 0 : EACCES;
+}
diff --git a/libmom/unuse-memory.c b/libfshelp/perms-checkdirmod.c
index 363f2a45..823c9f63 100644
--- a/libmom/unuse-memory.c
+++ b/libfshelp/perms-checkdirmod.c
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This file is part of the GNU Hurd.
@@ -18,26 +18,27 @@
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 "fshelp.h"
+
+/* Check to see whether USER is allowed to modify DIR with respect to
+ existing file ST. (If there is no existing file, pass 0 for ST.)
+ If the access is permissible return 0; otherwise return an
+ appropriate error code. */
error_t
-mom_unuse_memory (void *start, size_t len)
+fshelp_checkdirmod (struct stat *dir, struct stat *st, struct iouser *user)
{
error_t err;
- assert ((vm_address_t) start % vm_page_size == 0);
- assert (len % vm_page_size == 0);
-
- mutex_lock (&_mom_memory_lock);
- /* Deallocate and reallocate so that we drop any mapping around. */
- err = vm_deallocate (mach_task_self (), (vm_address_t) start, len);
- if (!err)
- err = vm_map (mach_task_self (), (vm_address_t *)&start, len, 0, 0,
- MACH_PORT_NULL, 0, 0, 0,
- VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE,
- VM_INHERIT_COPY);
- mutex_unlock (&_mom_memory_lock);
- return err;
-}
+ /* The user must be able to write the directory. */
+ err = fshelp_access (dir, S_IWRITE, user);
+ if (err)
+ return err;
-
+ /* If the directory is sticky, the user must own either it or the file. */
+ if ((dir->st_mode & S_ISVTX) && st
+ && fshelp_isowner (dir, user) && fshelp_isowner (st, user))
+ return EACCES;
+
+ return 0;
+}
diff --git a/libfshelp/perms-iscontroller.c b/libfshelp/perms-iscontroller.c
new file mode 100644
index 00000000..0adfdf22
--- /dev/null
+++ b/libfshelp/perms-iscontroller.c
@@ -0,0 +1,38 @@
+/* see whether a user should be considered a controller of the filesystem
+ Copyright (C) 2001, 2008 Free Software Foundation, Inc.
+ Written by Neal H Walfield <neal@cs.uml.edu>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include "fshelp.h"
+
+/* Check to see whether USER should be considered a controller of the
+ filesystem. Which is to say, check to see if we should give USER the
+ control port. ST is the stat of the root node. USER is the user
+ asking for a send right to the control port. */
+error_t
+fshelp_iscontroller (struct stat *st, struct iouser *user)
+{
+ /* Permitted if USER has the superuser uid, the owner uid or if the
+ USER has authority over the process's effective id. */
+ if (idvec_contains (user->uids, 0)
+ || idvec_contains (user->uids, st->st_uid)
+ || idvec_contains (user->uids, geteuid ()))
+ return 0;
+ return EPERM;
+}
diff --git a/libmom/reserve-memory-anywhere.c b/libfshelp/perms-isowner.c
index 40f9ec00..d1975993 100644
--- a/libmom/reserve-memory-anywhere.c
+++ b/libfshelp/perms-isowner.c
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This file is part of the GNU Hurd.
@@ -18,23 +18,22 @@
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 "fshelp.h"
+/* Check to see whether USER should be considered the owner of the
+ file identified by ST. If so, return zero; otherwise return an
+ appropriate error code. */
error_t
-mom_reserve_memory_anywhere (void **start, size_t len)
+fshelp_isowner (struct stat *st, struct iouser *user)
{
- error_t err;
-
- assert (len % vm_page_size == 0);
-
- *start = 0;
-
- mutex_lock (&_mom_memory_lock);
- err = vm_map (mach_task_self (), (vm_address_t *)&start, len, 0, 1,
- MACH_PORT_NULL, 0, 0, 0,
- VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE,
- VM_INHERIT_COPY);
- mutex_unlock (&_mom_memory_lock);
-
- return err;
+ /* Permitted if the user has the owner UID, the superuser UID, or if
+ the user is in the group of the file and has the group ID as
+ their user ID. */
+ if (idvec_contains (user->uids, st->st_uid)
+ || idvec_contains (user->uids, 0)
+ || (idvec_contains (user->gids, st->st_gid)
+ && idvec_contains (user->uids, st->st_gid)))
+ return 0;
+ else
+ return EPERM;
}
diff --git a/libfshelp/set-options.c b/libfshelp/set-options.c
index ba1e50d5..13e4001f 100644
--- a/libfshelp/set-options.c
+++ b/libfshelp/set-options.c
@@ -1,6 +1,6 @@
/* Standard filesystem runtime option parsing
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -32,12 +32,12 @@
/* Invoke ARGP with data from DATA & LEN, in the standard way. */
error_t
fshelp_set_options (struct argp *argp, int flags,
- char *argz, size_t argz_len, void *input)
+ const char *argz, size_t argz_len, void *input)
{
int argc = argz_count (argz, argz_len);
char **argv = alloca (sizeof (char *) * (argc + 1));
- argz_extract (argz, argz_len, argv);
+ argz_extract ((char *) argz, argz_len, argv);
return
argp_parse (argp, argc, argv,
diff --git a/libfshelp/start-translator-long.c b/libfshelp/start-translator-long.c
index 34202f43..5bf14541 100644
--- a/libfshelp/start-translator-long.c
+++ b/libfshelp/start-translator-long.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,99,2000,02, 04 Free Software Foundation, Inc.
Written by Miles Bader and Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -48,67 +48,79 @@ struct fsys_startup_reply
mach_port_t realnode;
};
-static const mach_msg_type_t flagsCheck = {
- MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
- 32, /* msgt_size = */
- 1, /* msgt_number = */
- TRUE, /* msgt_inline = */
- FALSE, /* msgt_longform = */
- FALSE, /* msgt_deallocate = */
- 0 /* msgt_unused = */
-};
-
-static const mach_msg_type_t control_portCheck =
-{
- 17, /* msgt_name = */
- 32, /* msgt_size = */
- 1, /* msgt_number = */
- TRUE, /* msgt_inline = */
- FALSE, /* msgt_longform = */
- FALSE, /* msgt_deallocate = */
- 0 /* msgt_unused = */
-};
-
-static const mach_msg_type_t RetCodeType = {
- MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
- 32, /* msgt_size = */
- 1, /* msgt_number = */
- TRUE, /* msgt_inline = */
- FALSE, /* msgt_longform = */
- FALSE, /* msgt_deallocate = */
- 0 /* msgt_unused = */
-};
-
-static const mach_msg_type_t realnodeType =
-{
- -1, /* msgt_name = */
- 32, /* msgt_size = */
- 1, /* msgt_number = */
- TRUE, /* msgt_inline = */
- FALSE, /* msgt_longform = */
- FALSE, /* msgt_deallocate = */
- 0 /* msgt_unused = */
-};
-
-
/* Wait around for an fsys_startup message on the port PORT from the
translator on NODE (timing out after TIMEOUT milliseconds), and return a
- send right for the resulting fsys control port in CONTROL. If a dead-name
+ send right for the resulting fsys control port in CONTROL. If a no-senders
notification is received on PORT, then it will be assumed that the
translator died, and EDIED will be returned. If an error occurs, the
error code is returned, otherwise 0. */
static error_t
-service_fsys_startup (fshelp_open_fn_t underlying_open_fn,
- mach_port_t port, long timeout,
- fsys_t *control)
+service_fsys_startup (fshelp_open_fn_t underlying_open_fn, void *cookie,
+ mach_port_t port, long timeout, fsys_t *control,
+ task_t task)
{
- error_t err;
- union
+ /* These should be optimized away to pure integer constants. */
+ const mach_msg_type_t flagsCheck =
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+ const mach_msg_type_t control_portCheck =
{
- mach_msg_header_t head;
- struct fsys_startup_request startup;
- mach_dead_name_notification_t dead;
+ MACH_MSG_TYPE_PORT_SEND, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+ const mach_msg_type_t RetCodeType =
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+ const mach_msg_type_t realnodeType =
+ {
+ -1, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+
+ /* Return true iff TYPE fails to match CHECK. */
+ inline int type_check (const mach_msg_type_t *type,
+ const mach_msg_type_t *check)
+ {
+ union
+ {
+ unsigned32_t word;
+ mach_msg_type_t type;
+ } t, c;
+ t.type = *type;
+ c.type = *check;
+ return t.word != c.word;
}
+
+ error_t err;
+ union
+ {
+ mach_msg_header_t head;
+ struct fsys_startup_request startup;
+ }
request;
struct fsys_startup_reply reply;
@@ -119,7 +131,7 @@ service_fsys_startup (fshelp_open_fn_t underlying_open_fn,
if (err)
return err;
- /* Check whether we actually got a dead-name notification instead. */
+ /* Check whether we actually got a no-senders notification instead. */
if (request.head.msgh_id == MACH_NOTIFY_NO_SENDERS)
return EDIED;
@@ -135,9 +147,8 @@ service_fsys_startup (fshelp_open_fn_t underlying_open_fn,
if (request.head.msgh_id != 22000)
reply.RetCode = MIG_BAD_ID;
- else if ((*(int *)&request.startup.control_portType
- != *(int *)&control_portCheck)
- || (*(int *)&request.startup.flagsType != *(int *)&flagsCheck))
+ else if (type_check (&request.startup.control_portType, &control_portCheck)
+ || type_check (&request.startup.flagsType, &flagsCheck))
reply.RetCode = MIG_BAD_ARGUMENTS;
else
{
@@ -147,7 +158,8 @@ service_fsys_startup (fshelp_open_fn_t underlying_open_fn,
reply.RetCode =
(*underlying_open_fn) (request.startup.flags,
- &reply.realnode, &realnode_type);
+ &reply.realnode, &realnode_type, task,
+ cookie);
reply.realnodeType = realnodeType;
reply.realnodeType.msgt_name = realnode_type;
@@ -161,6 +173,11 @@ service_fsys_startup (fshelp_open_fn_t underlying_open_fn,
sizeof(reply), 0,
request.head.msgh_remote_port,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (err == MACH_SEND_INTERRUPTED
+ && reply.realnodeType.msgt_name == MACH_MSG_TYPE_MOVE_SEND)
+ /* For MACH_SEND_INTERRUPTED, we'll have pseudo-received the message
+ and might have to clean up a generated send right. */
+ mach_port_deallocate (mach_task_self (), reply.realnode);
if (reply.RetCode)
/* Make our error return be the earlier one. */
@@ -172,19 +189,20 @@ service_fsys_startup (fshelp_open_fn_t underlying_open_fn,
error_t
fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn,
- char *name, char *argz, int argz_len,
- mach_port_t *fds,
+ void *cookie, char *name, char *argz,
+ int argz_len, mach_port_t *fds,
mach_msg_type_name_t fds_type, int fds_len,
mach_port_t *ports,
mach_msg_type_name_t ports_type, int ports_len,
int *ints, int ints_len,
+ uid_t owner_uid,
int timeout, fsys_t *control)
{
error_t err;
file_t executable;
mach_port_t bootstrap = MACH_PORT_NULL;
mach_port_t task = MACH_PORT_NULL;
- mach_port_t prev_notify, proc, saveport;
+ mach_port_t prev_notify, proc, saveport, childproc;
int ports_moved = 0;
/* Find the translator itself. Since argz has zero-separated elements, we
@@ -192,7 +210,7 @@ fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn,
executable = file_name_lookup(name, O_EXEC, 0);
if (executable == MACH_PORT_NULL)
return errno;
-
+
/* Create a bootstrap port for the translator. */
err =
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &bootstrap);
@@ -200,15 +218,26 @@ fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn,
goto lose;
/* Create the task for the translator. */
- err = task_create (mach_task_self (), 0, &task);
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &task);
if (err)
goto lose;
- /* Designate TASK as our child. */
+ /* Designate TASK as our child and set it's owner accordingly. */
proc = getproc ();
proc_child (proc, task);
+ err = proc_task2proc (proc, task, &childproc);
mach_port_deallocate (mach_task_self (), proc);
-
+ if (err)
+ goto lose;
+ err = proc_setowner (childproc, owner_uid, owner_uid == (uid_t) -1);
+ mach_port_deallocate (mach_task_self (), childproc);
+ if (err)
+ goto lose;
+
assert (ports_len > INIT_PORT_BOOTSTRAP);
switch (ports_type)
{
@@ -264,13 +293,14 @@ fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn,
/* Ok, cool, we've got a running(?) program, now rendezvous with it if
possible using the startup protocol on the bootstrap port... */
- err = service_fsys_startup(underlying_open_fn, bootstrap, timeout, control);
+ err = service_fsys_startup(underlying_open_fn, cookie, bootstrap,
+ timeout, control, task);
lose:
if (!ports_moved)
{
int i;
-
+
if (fds_type == MACH_MSG_TYPE_MOVE_SEND)
for (i = 0; i < fds_len; i++)
mach_port_deallocate (mach_task_self (), fds[i]);
diff --git a/libfshelp/start-translator.c b/libfshelp/start-translator.c
index f5cc4072..ba5418ec 100644
--- a/libfshelp/start-translator.c
+++ b/libfshelp/start-translator.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -25,33 +25,34 @@
error_t
fshelp_start_translator (fshelp_open_fn_t underlying_open_fn,
- char *name, char *argz, int argz_len,
- int timeout, fsys_t *control)
+ void *cookie, char *name, char *argz,
+ int argz_len, int timeout, fsys_t *control)
{
mach_port_t ports[INIT_PORT_MAX];
mach_port_t fds[STDERR_FILENO + 1];
int ints[INIT_INT_MAX];
int i;
error_t err;
-
+
for (i = 0; i < INIT_PORT_MAX; i++)
ports[i] = MACH_PORT_NULL;
for (i = 0; i < STDERR_FILENO + 1; i++)
fds[i] = MACH_PORT_NULL;
bzero (ints, INIT_INT_MAX * sizeof (int));
-
+
ports[INIT_PORT_CWDIR] = getcwdir ();
ports[INIT_PORT_CRDIR] = getcrdir ();
ports[INIT_PORT_AUTH] = getauth ();
fds[STDERR_FILENO] = getdport (STDERR_FILENO);
-
- err = fshelp_start_translator_long (underlying_open_fn,
+
+ err = fshelp_start_translator_long (underlying_open_fn, cookie,
name, argz, argz_len,
fds, MACH_MSG_TYPE_COPY_SEND,
STDERR_FILENO + 1,
ports, MACH_MSG_TYPE_COPY_SEND,
INIT_PORT_MAX,
ints, INIT_INT_MAX,
+ geteuid (),
timeout, control);
for (i = 0; i < INIT_PORT_MAX; i++)
mach_port_deallocate (mach_task_self (), ports[i]);
diff --git a/libfshelp/touch.c b/libfshelp/touch.c
new file mode 100644
index 00000000..00d90edd
--- /dev/null
+++ b/libfshelp/touch.c
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 1999, 2007 Free Software Foundation, Inc.
+
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "fshelp.h"
+
+/* Change the stat times of NODE as indicated by WHAT (from the set TOUCH_*)
+ to the current time. */
+void
+fshelp_touch (struct stat *st, unsigned what,
+ volatile struct mapped_time_value *maptime)
+{
+ struct timeval tv;
+
+ maptime_read (maptime, &tv);
+
+ if (what & TOUCH_ATIME)
+ {
+ st->st_atim.tv_sec = tv.tv_sec;
+ st->st_atim.tv_nsec = tv.tv_usec * 1000;
+ }
+ if (what & TOUCH_CTIME)
+ {
+ st->st_ctim.tv_sec = tv.tv_sec;
+ st->st_ctim.tv_nsec = tv.tv_usec * 1000;
+ }
+ if (what & TOUCH_MTIME)
+ {
+ st->st_mtim.tv_sec = tv.tv_sec;
+ st->st_mtim.tv_nsec = tv.tv_usec * 1000;
+ }
+}
diff --git a/libfshelp/translated.c b/libfshelp/translated.c
new file mode 100644
index 00000000..2dc724b6
--- /dev/null
+++ b/libfshelp/translated.c
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "fshelp.h"
+
+/* Return true iff there is an active translator on this box */
+int
+fshelp_translated (struct transbox *box)
+{
+ return (box->active != MACH_PORT_NULL);
+}
diff --git a/libftpconn/Makefile b/libftpconn/Makefile
new file mode 100644
index 00000000..05f3ddfb
--- /dev/null
+++ b/libftpconn/Makefile
@@ -0,0 +1,34 @@
+# Makefile for libftpconn
+#
+# Copyright (C) 1997 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 := libftpconn
+makemode := library
+
+libname = libftpconn
+installhdrs = ftpconn.h
+installhdrsubdir = .
+
+SRCS = addr.c cmd.c create.c cwd.c errs.c names.c open.c reply.c \
+ rmt.c set-type.c stats.c unix.c xfer.c xinl.c fname.c
+LCLHDRS = ftpconn.h priv.h
+
+OBJS = $(SRCS:.c=.o)
+
+CPPFLAGS += -DHAVE_HURD_HURD_TYPES_H -DHAVE_STAT_ST_AUTHOR
+
+include ../Makeconf
diff --git a/libftpconn/addr.c b/libftpconn/addr.c
new file mode 100644
index 00000000..3b668f34
--- /dev/null
+++ b/libftpconn/addr.c
@@ -0,0 +1,79 @@
+/* Send/receive data-connection addresses
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+error_t
+ftp_conn_get_pasv_addr (struct ftp_conn *conn, struct sockaddr **addr)
+{
+ int reply;
+ const char *txt;
+ error_t err = ftp_conn_cmd_reopen (conn, "pasv", 0, &reply, &txt);
+
+ if (! err)
+ {
+ if (reply == REPLY_PASV_OK)
+ err = (*(conn->syshooks.pasv_addr ?: ftp_conn_unix_pasv_addr))
+ (conn, txt, addr);
+ else
+ err = unexpected_reply (conn, reply, txt, 0);
+ }
+
+ return err;
+}
+
+error_t
+ftp_conn_send_actv_addr (struct ftp_conn *conn, struct sockaddr *addr)
+{
+ error_t err;
+
+ if (addr == 0)
+ err = EINVAL;
+ else if (addr->sa_family != AF_INET)
+ err = EAFNOSUPPORT;
+ else
+ {
+ char buf[50];
+ int reply;
+ unsigned char *a =
+ (unsigned char *)&((struct sockaddr_in *)addr)->sin_addr.s_addr;
+ unsigned char *p =
+ (unsigned char *)&((struct sockaddr_in *)addr)->sin_port;
+
+ snprintf (buf, sizeof buf, "%d,%d,%d,%d,%d,%d",
+ a[0], a[1], a[2], a[3], p[0], p[1]);
+ err = ftp_conn_cmd_reopen (conn, "port", buf, &reply, 0);
+
+ if (! err)
+ {
+ if (reply == REPLY_OK)
+ err = 0;
+ else
+ err = unexpected_reply (conn, reply, 0, 0);
+ }
+ }
+
+ return err;
+}
diff --git a/libftpconn/cmd.c b/libftpconn/cmd.c
new file mode 100644
index 00000000..803dda7c
--- /dev/null
+++ b/libftpconn/cmd.c
@@ -0,0 +1,169 @@
+/* Send commands to the ftp server
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <arpa/telnet.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+/* Version of write that writes all LEN bytes of BUF if possible to FD. */
+static error_t
+_write (int fd, const void *buf, size_t len)
+{
+ while (len > 0)
+ {
+ ssize_t wr = write (fd, buf, len);
+ if (wr < 0)
+ return errno;
+ else if (wr == 0)
+ return EPIPE;
+ buf += wr;
+ len -= wr;
+ }
+ return 0;
+}
+
+static error_t
+_skip_write (int fd, const void *buf, size_t len, size_t *skip)
+{
+ size_t sk = *skip;
+ error_t err = 0;
+
+ if (len > sk)
+ {
+ err = _write (fd, buf + sk, len - sk);
+ *skip = 0;
+ }
+ else
+ *skip = sk - len;
+
+ return err;
+}
+
+/* Ridiculous function to deal with the never-to-occur case of the ftp
+ command being too long for the buffer in ftp_conn_cmd; just writes the
+ portion of the command that wasn't written there. */
+static error_t
+_long_cmd (int fd, const char *cmd, const char *arg, size_t skip)
+{
+ error_t err = _skip_write (fd, cmd, strlen (cmd), &skip);
+ if (!err && arg)
+ {
+ err = _skip_write (fd, " ", 1, &skip);
+ if (! err)
+ err = _skip_write (fd, arg, strlen (arg), &skip);
+ }
+ if (! err)
+ err = _skip_write (fd, "\r\n", 2, &skip);
+ return err;
+}
+
+/* Send the ftp command CMD, with optional argument ARG (if non-zero) to
+ CONN's ftp server. If either of REPLY or REPLY_TXT is non-zero, then a
+ reply is waited for and returned as with ftp_conn_get_reply, otherwise
+ the next reply from the server is left unconsumed. */
+error_t
+ftp_conn_cmd (struct ftp_conn *conn, const char *cmd, const char *arg,
+ int *reply, const char **reply_txt)
+{
+ error_t err = 0;
+
+ if (conn->control < 0)
+ err = EPIPE;
+ else
+ /* (This used to try to call dprintf to output to conn->control, but that
+ function doesn't appear to work.) */
+ {
+ char buf[200];
+ size_t out =
+ snprintf (buf, sizeof buf, arg ? "%s %s\r\n" : "%s\r\n", cmd, arg);
+ err = _write (conn->control, buf, out);
+
+ if (!err && conn->hooks && conn->hooks->cntl_debug)
+ {
+ buf[out - 2] = '\0'; /* Stomp the CR & NL. */
+ (* conn->hooks->cntl_debug) (conn, FTP_CONN_CNTL_DEBUG_CMD, buf);
+ }
+
+ if (!err && out == sizeof buf)
+ err = _long_cmd (conn->control, cmd, arg, sizeof buf);
+ }
+
+ if (!err && (reply || reply_txt))
+ err = ftp_conn_get_reply (conn, reply, reply_txt);
+
+ return err;
+}
+
+/* Send an ftp command to CONN's server, and optionally await a reply as with
+ ftp_conn_cmd, but also open a new connection if it appears that the old
+ one has died (as when the ftp server times it out). */
+error_t
+ftp_conn_cmd_reopen (struct ftp_conn *conn, const char *cmd, const char *arg,
+ int *reply, const char **reply_txt)
+{
+ int _reply;
+ error_t err;
+
+ err = ftp_conn_cmd (conn, cmd, arg, &_reply, reply_txt);
+ if (err == EPIPE || (!err && _reply == REPLY_CLOSED))
+ /* Retry once after reopening the connection. */
+ {
+ err = ftp_conn_open (conn);
+ if (! err)
+ err = ftp_conn_cmd (conn, cmd, arg, reply, reply_txt);
+ }
+ else if (reply)
+ *reply = _reply;
+
+ return err;
+}
+
+/* Send an ftp ABOR command to CONN's server, aborting any transfer in
+ progress. */
+void
+ftp_conn_abort (struct ftp_conn *conn)
+{
+ if (conn->control >= 0)
+ {
+ static const char ip[] = { IAC, IP, IAC };
+ static const char abor[] = { DM, 'a', 'b', 'o', 'r', '\r', '\n' };
+
+ if (conn->hooks && conn->hooks->cntl_debug)
+ (* conn->hooks->cntl_debug) (conn, FTP_CONN_CNTL_DEBUG_CMD, "abor");
+
+ if (send (conn->control, ip, sizeof ip, MSG_OOB) == sizeof ip
+ && write (conn->control, abor, sizeof abor) == sizeof abor)
+ {
+ int reply;
+ error_t err;
+ do
+ err = ftp_conn_get_raw_reply (conn, &reply, 0);
+ while (reply == REPLY_ABORTED);
+ if (reply != REPLY_TRANS_OK && reply != REPLY_ABORT_OK)
+ ftp_conn_close (conn);
+ }
+ else
+ ftp_conn_close (conn);
+ }
+}
diff --git a/libftpconn/create.c b/libftpconn/create.c
new file mode 100644
index 00000000..20a64561
--- /dev/null
+++ b/libftpconn/create.c
@@ -0,0 +1,87 @@
+/* Create a new ftp connection
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <ftpconn.h>
+
+/* Create a new ftp connection as specified by PARAMS, and return it in CONN;
+ HOOKS contains customization hooks used by the connection. Neither PARAMS
+ nor HOOKS is copied, so a copy of it should be made if necessary before
+ calling this function; if it should be freed later, a FINI hook may be
+ used to do so. */
+error_t
+ftp_conn_create (const struct ftp_conn_params *params,
+ const struct ftp_conn_hooks *hooks,
+ struct ftp_conn **conn)
+{
+ error_t err;
+ struct ftp_conn *new = malloc (sizeof (struct ftp_conn));
+
+ if (! new)
+ return ENOMEM;
+
+ new->control = -1;
+ new->line = 0;
+ new->line_sz = 0;
+ new->line_offs = 0;
+ new->line_len = 0;
+ new->reply_txt = 0;
+ new->reply_txt_sz = 0;
+ new->params = params;
+ new->hooks = hooks;
+ new->syshooks_valid = 0;
+ new->use_passive = 1;
+ new->actv_data_addr = 0;
+ new->cwd = 0;
+ new->type = 0;
+ bzero (&new->syshooks, sizeof new->syshooks);
+
+ if (new->hooks && new->hooks->init)
+ err = (*new->hooks->init) (new);
+ else
+ err = 0;
+
+ if (err)
+ ftp_conn_free (new);
+ else
+ *conn = new;
+
+ return err;
+}
+
+/* Free the ftp connection CONN, closing it first, and freeing all resources
+ it uses. */
+void
+ftp_conn_free (struct ftp_conn *conn)
+{
+ ftp_conn_close (conn);
+ if (conn->hooks && conn->hooks->fini)
+ (* conn->hooks->fini) (conn);
+ if (conn->line)
+ free (conn->line);
+ if (conn->reply_txt)
+ free (conn->reply_txt);
+ if (conn->actv_data_addr)
+ free (conn->actv_data_addr);
+ free (conn);
+}
diff --git a/libftpconn/cwd.c b/libftpconn/cwd.c
new file mode 100644
index 00000000..868150f1
--- /dev/null
+++ b/libftpconn/cwd.c
@@ -0,0 +1,113 @@
+/* Get/set connection current working directory
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+static error_t
+_cache_cwd (struct ftp_conn *conn, int reopen)
+{
+ int reply;
+ const char *txt;
+ error_t err =
+ (reopen ? ftp_conn_cmd_reopen : ftp_conn_cmd) (conn, "pwd", 0, &reply, &txt);
+
+ if (! err)
+ {
+ if (reply == REPLY_DIR_NAME)
+ {
+ char *cwd = malloc (strlen (txt));
+ if (! cwd)
+ err = ENOMEM;
+ else if (sscanf (txt, "\"%[^\"]\"", cwd) != 1)
+ err = EGRATUITOUS;
+ else
+ {
+ if (conn->cwd)
+ free (conn->cwd);
+ conn->cwd = cwd;
+ }
+ }
+ else
+ err = unexpected_reply (conn, reply, txt, 0);
+ }
+
+ return err;
+}
+
+/* Return a malloced string containing CONN's working directory in CWD. */
+error_t
+ftp_conn_get_cwd (struct ftp_conn *conn, char **cwd)
+{
+ error_t err = 0;
+ if (! conn->cwd)
+ err = _cache_cwd (conn, 1);
+ if (! err)
+ {
+ *cwd = strdup (conn->cwd);
+ if (! *cwd)
+ err = ENOMEM;
+ }
+ return err;
+}
+
+/* Return a malloced string containing CONN's working directory in CWD. */
+error_t
+ftp_conn_cwd (struct ftp_conn *conn, const char *cwd)
+{
+ error_t err = 0;
+ if (conn->cwd && strcmp (conn->cwd, cwd) == 0)
+ err = 0;
+ else
+ {
+ int reply;
+ const char *txt;
+ err = ftp_conn_cmd_reopen (conn, "cwd", cwd, &reply, &txt);
+ if (! err)
+ {
+ if (reply == REPLY_FCMD_OK)
+ err = _cache_cwd (conn, 0);
+ else
+ err = unexpected_reply (conn, reply, txt, ftp_conn_poss_file_errs);
+ }
+ }
+ return err;
+}
+
+/* Return a malloced string containing CONN's working directory in CWD. */
+error_t
+ftp_conn_cdup (struct ftp_conn *conn)
+{
+ int reply;
+ const char *txt;
+ error_t err = ftp_conn_cmd_reopen (conn, "cdup", 0, &reply, &txt);
+ if (! err)
+ {
+ if (reply == REPLY_OK)
+ err = _cache_cwd (conn, 0);
+ else
+ err = unexpected_reply (conn, reply, txt, ftp_conn_poss_file_errs);
+ }
+ return err;
+}
diff --git a/libdiskfs/init-completed.c b/libftpconn/errs.c
index cbb94e3b..5a93fb55 100644
--- a/libdiskfs/init-completed.c
+++ b/libftpconn/errs.c
@@ -1,6 +1,6 @@
-/* Function called when we're done initializing at boot time
+/* Error codes we think may result from file operations we do
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -18,15 +18,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <stdio.h>
+#include <errno.h>
+#include <ftpconn.h>
+#include "priv.h"
-#include <hurd/startup.h>
-
-#include "diskfs.h"
-
-/* Called by diskfs_start_bootstrap, after the filesystem has a normal
- environment (complete with auth and proc ports). */
-void
-diskfs_init_completed ()
+/* Error codes we think may result from file operations we do. */
+const error_t
+ftp_conn_poss_file_errs[] =
{
-}
+ EIO, ENOENT, EPERM, EACCES, ENOTDIR, ENAMETOOLONG, ELOOP, EISDIR, EROFS,
+ EMFILE, ENFILE, ENXIO, EOPNOTSUPP, ENOSPC, EDQUOT, ETXTBSY, EEXIST,
+ 0
+};
diff --git a/libftpconn/fname.c b/libftpconn/fname.c
new file mode 100644
index 00000000..3be6eeec
--- /dev/null
+++ b/libftpconn/fname.c
@@ -0,0 +1,78 @@
+/* Filename frobbing
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+
+#include "ftpconn.h"
+
+/* Give a name which refers to a directory file, and a name in that
+ directory, this should return in COMPOSITE the composite name referring to
+ that name in that directory, in malloced storage. */
+error_t
+ftp_conn_append_name (struct ftp_conn *conn,
+ const char *dir, const char *name,
+ char **composite)
+{
+ error_t err = ftp_conn_validate_syshooks (conn);
+ if (err)
+ return err;
+ else if (conn->syshooks.append_name)
+ return (*conn->syshooks.append_name) (conn, dir, name, composite);
+ else
+ return EOPNOTSUPP;
+}
+
+/* If the name of a file COMPOSITE is a composite name (containing both a
+ filename and a directory name), this function will return the name
+ component only in BASE, in malloced storage, otherwise it simply returns a
+ newly malloced copy of COMPOSITE in BASE. */
+error_t
+ftp_conn_basename (struct ftp_conn *conn, const char *composite, char **base)
+{
+ error_t err = ftp_conn_validate_syshooks (conn);
+
+ if (err)
+ return err;
+
+ if (conn->syshooks.basename)
+ {
+ size_t in_size = strlen (composite) + 1;
+ char *in = strdup (composite), *out = in;
+
+ if (! in)
+ return ENOMEM;
+
+ err = (*conn->syshooks.basename) (conn, &out);
+ if (err || out != in)
+ {
+ if (!err && out >= in && out < in + in_size)
+ /* OUT uses storage from IN, but not at the beginning. */
+ out = strdup (out);
+ free (in);
+ }
+
+ if (! err)
+ *base = out;
+
+ return err;
+ }
+ else
+ return EOPNOTSUPP;
+}
diff --git a/libftpconn/ftpconn.h b/libftpconn/ftpconn.h
new file mode 100644
index 00000000..6bff5918
--- /dev/null
+++ b/libftpconn/ftpconn.h
@@ -0,0 +1,394 @@
+/* Manage an ftp connection
+
+ Copyright (C) 1997,2001,02 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __FTPCONN_H__
+#define __FTPCONN_H__
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <features.h>
+
+#define __need_error_t
+#include <errno.h>
+
+#ifndef __error_t_defined
+typedef int error_t;
+#define __error_t_defined
+#endif
+
+#ifdef FTP_CONN_DEFINE_EI
+#define FTP_CONN_EI
+#else
+#define FTP_CONN_EI __extern_inline
+#endif
+
+struct ftp_conn;
+struct ftp_conn_params;
+struct ftp_conn_stat;
+
+/* The type of the function called by ...get_stats to add each new stat.
+ NAME is the file in question, STAT is stat info about it, and if NAME is a
+ symlink, SYMLINK_TARGET is what it is linked to, or 0 if it's not a
+ symlink. NAME and SYMLINK_TARGET should be copied if they are used
+ outside of this function. HOOK is as passed into ...get_stats. */
+typedef error_t (*ftp_conn_add_stat_fun_t) (const char *name,
+# if _FILE_OFFSET_BITS == 64
+ const struct stat *stat,
+# else
+ const struct stat64 *stat,
+# endif
+ const char *symlink_target,
+ void *hook);
+
+/* Hooks that customize behavior for particular types of remote system. */
+struct ftp_conn_syshooks
+{
+ /* Should return in ADDR a malloced struct sockaddr containing the address
+ of the host referenced by the PASV reply contained in TXT. */
+ error_t (*pasv_addr) (struct ftp_conn *conn, const char *txt,
+ struct sockaddr **addr);
+
+ /* Look at the error string in TXT, and try to guess an error code to
+ return. If POSS_ERRS is non-zero, it contains a list of errors
+ that are likely to occur with the previous command, terminated with 0.
+ If no match is found and POSS_ERRS is non-zero, the first error in
+ POSS_ERRS should be returned by default. */
+ error_t (*interp_err) (struct ftp_conn *conn, const char *txt,
+ const error_t *poss_errs);
+
+ /* Start an operation to get a list of file-stat structures for NAME (this
+ is often similar to ftp_conn_start_dir, but with OS-specific flags), and
+ return a file-descriptor for reading on, and a state structure in STATE
+ suitable for passing to cont_get_stats. If CONTENTS is true, NAME must
+ refer to a directory, and the contents will be returned, otherwise, the
+ (single) result will refer to NAME. */
+ error_t (*start_get_stats) (struct ftp_conn *conn, const char *name,
+ int contents, int *fd, void **state);
+
+ /* Read stats information from FD, calling ADD_STAT for each new stat (HOOK
+ is passed to ADD_STAT). FD and STATE should be returned from
+ start_get_stats. If this function returns EAGAIN, then it should be
+ called again to finish the job (possibly after calling select on FD); if
+ it returns 0, then it is finishe,d and FD and STATE are deallocated. */
+ error_t (*cont_get_stats) (struct ftp_conn *conn, int fd, void *state,
+ ftp_conn_add_stat_fun_t add_stat, void *hook);
+
+ /* Give a name which refers to a directory file, and a name in that
+ directory, this should return in COMPOSITE the composite name referring
+ to that name in that directory, in malloced storage. */
+ error_t (*append_name) (struct ftp_conn *conn,
+ const char *dir, const char *name,
+ char **composite);
+
+ /* If the name of a file *NAME is a composite name (containing both a
+ filename and a directory name), this function should change *NAME to be
+ the name component only; if the result is shorter than the original
+ *NAME, the storage pointed to it may be modified, otherwise, *NAME
+ should be changed to point to malloced storage holding the result, which
+ will be freed by the caller. */
+ error_t (*basename) (struct ftp_conn *conn, char **name);
+};
+
+/* Type parameter for the cntl_debug hook. */
+#define FTP_CONN_CNTL_DEBUG_CMD 1
+#define FTP_CONN_CNTL_DEBUG_REPLY 2
+
+/* Type parameter for the get_login_param hook. */
+#define FTP_CONN_GET_LOGIN_PARAM_USER 1
+#define FTP_CONN_GET_LOGIN_PARAM_PASS 2
+#define FTP_CONN_GET_LOGIN_PARAM_ACCT 3
+
+/* General connection customization. */
+struct ftp_conn_hooks
+{
+ /* If non-zero, should look at the SYST reply in SYST, and fill in CONN's
+ syshooks (with ftp_conn_set_hooks) appropriately; SYST may be zero if
+ the remote system doesn't support that command. If zero, then the
+ default ftp_conn_choose_syshooks is used. */
+ void (*choose_syshooks) (struct ftp_conn *conn, const char *syst);
+
+ /* If non-zero, called during io on the ftp control connection -- TYPE is
+ FTP_CONN_CNTL_DEBUG_CMD for commands, and FTP_CONN_CNTL_DEBUG_REPLY for
+ replies; TXT is the actual text. */
+ void (*cntl_debug) (struct ftp_conn *conn, int type, const char *txt);
+
+ /* Called after CONN's connection the server has been opened (or reopened). */
+ void (*opened) (struct ftp_conn *conn);
+
+ /* If the remote system requires some login parameter that isn't available,
+ this hook is called to try and get it, returning a value in TXT. The
+ return value should be in a malloced block of memory. The returned
+ value will only be used once; if it's desired that it should `stick',
+ the user may modify the value stored in CONN's params field, but that is
+ an issue outside of the scope of this interface -- params are only read,
+ never written. */
+ error_t (*get_login_param) (struct ftp_conn *conn, int type, char **txt);
+
+ /* Called after CONN's connection the server has closed for some reason. */
+ void (*closed) (struct ftp_conn *conn);
+
+ /* Called when CONN is initially created before any other hook calls. An
+ error return causes the creation to fail with that error code. */
+ error_t (*init) (struct ftp_conn *conn);
+
+ /* Called when CONN is about to be destroyed. No hook calls are ever made
+ after this one. */
+ void (*fini) (struct ftp_conn *conn);
+
+ /* This hook should return true if the current thread has been interrupted
+ in some way, and EINTR (or a short count in some cases) should be
+ returned from a blocking function. */
+ int (*interrupt_check) (struct ftp_conn *conn);
+};
+
+/* A single ftp connection. */
+struct ftp_conn
+{
+ const struct ftp_conn_params *params; /* machine, user, &c */
+ const struct ftp_conn_hooks *hooks; /* Customization hooks. */
+
+ struct ftp_conn_syshooks syshooks; /* host-dependent hook functions */
+ int syshooks_valid : 1; /* True if the system type has been determined. */
+
+ int control; /* fd for ftp control connection */
+
+ char *line; /* buffer for reading control replies */
+ size_t line_sz; /* allocated size of LINE */
+ size_t line_offs; /* Start of unread input in LINE. */
+ size_t line_len; /* End of the contents in LINE. */
+
+ char *reply_txt; /* A buffer for the text of entire replies */
+ size_t reply_txt_sz; /* size of it */
+
+ char *cwd; /* Last know CWD, or 0 if unknown. */
+ const char *type; /* Connection type, or 0 if default. */
+
+ void *hook; /* Random user data. */
+
+ int use_passive : 1; /* If true, first try passive data conns. */
+
+ struct sockaddr *actv_data_addr;/* Address of port for active data conns. */
+};
+
+/* Parameters for an ftp connection; doesn't include any actual connection
+ state. */
+struct ftp_conn_params
+{
+ void *addr; /* Address. */
+ size_t addr_len; /* Length in bytes of ADDR. */
+ int addr_type; /* Type of ADDR (AF_*). */
+
+ char *user, *pass, *acct; /* Parameters for logging into ftp. */
+};
+
+/* Unix hooks */
+extern error_t ftp_conn_unix_pasv_addr (struct ftp_conn *conn, const char *txt,
+ struct sockaddr **addr);
+extern error_t ftp_conn_unix_interp_err (struct ftp_conn *conn, const char *txt,
+ const error_t *poss_errs);
+extern error_t ftp_conn_unix_start_get_stats (struct ftp_conn *conn,
+ const char *name,
+ int contents, int *fd,
+ void **state);
+extern error_t ftp_conn_unix_cont_get_stats (struct ftp_conn *conn,
+ int fd, void *state,
+ ftp_conn_add_stat_fun_t add_stat,
+ void *hook);
+error_t ftp_conn_unix_append_name (struct ftp_conn *conn,
+ const char *dir, const char *name,
+ char **composite);
+error_t ftp_conn_unix_basename (struct ftp_conn *conn, char **name);
+
+extern struct ftp_conn_syshooks ftp_conn_unix_syshooks;
+
+error_t
+ftp_conn_get_raw_reply (struct ftp_conn *conn,
+ int *reply, const char **reply_txt);
+error_t
+ftp_conn_get_reply (struct ftp_conn *conn, int *reply, const char **reply_txt);
+
+error_t
+ftp_conn_cmd (struct ftp_conn *conn, const char *cmd, const char *arg,
+ int *reply, const char **reply_txt);
+
+error_t
+ftp_conn_cmd_reopen (struct ftp_conn *conn, const char *cmd, const char *arg,
+ int *reply, const char **reply_txt);
+
+void ftp_conn_abort (struct ftp_conn *conn);
+
+/* Sets CONN's syshooks to a copy of SYSHOOKS. */
+void ftp_conn_set_syshooks (struct ftp_conn *conn,
+ struct ftp_conn_syshooks *syshooks);
+
+error_t ftp_conn_open (struct ftp_conn *conn);
+
+void ftp_conn_close (struct ftp_conn *conn);
+
+extern error_t ftp_conn_validate_syshooks (struct ftp_conn *conn);
+
+#if defined(__USE_EXTERN_INLINES) || defined(FTP_CONN_DEFINE_EI)
+/* Makes sure that CONN's syshooks are set according to the remote system
+ type. */
+FTP_CONN_EI error_t
+ftp_conn_validate_syshooks (struct ftp_conn *conn)
+{
+ if (conn->syshooks_valid)
+ return 0;
+ else
+ /* Opening the connection should set the syshooks. */
+ return ftp_conn_open (conn);
+}
+#endif /* Use extern inlines. */
+
+/* Create a new ftp connection as specified by PARAMS, and return it in CONN;
+ HOOKS contains customization hooks used by the connection. Neither PARAMS
+ nor HOOKS is copied, so a copy of it should be made if necessary before
+ calling this function; if it should be freed later, a FINI hook may be
+ used to do so. */
+error_t ftp_conn_create (const struct ftp_conn_params *params,
+ const struct ftp_conn_hooks *hooks,
+ struct ftp_conn **conn);
+
+/* Free the ftp connection CONN, closing it first, and freeing all resources
+ it uses. */
+void ftp_conn_free (struct ftp_conn *conn);
+
+/* Start a transfer command CMD (and optional args ...), returning a file
+ descriptor in DATA. POSS_ERRS is a list of errnos to try matching
+ against any resulting error text. */
+error_t
+ftp_conn_start_transfer (struct ftp_conn *conn,
+ const char *cmd, const char *arg,
+ const error_t *poss_errs,
+ int *data);
+
+/* Wait for the reply signalling the end of a data transfer. */
+error_t ftp_conn_finish_transfer (struct ftp_conn *conn);
+
+/* Start retreiving file NAME over CONN, returning a file descriptor in DATA
+ over which the data can be read. */
+error_t ftp_conn_start_retrieve (struct ftp_conn *conn, const char *name, int *data);
+
+/* Start retreiving a list of files in NAME over CONN, returning a file
+ descriptor in DATA over which the data can be read. */
+error_t ftp_conn_start_list (struct ftp_conn *conn, const char *name, int *data);
+
+/* Start retreiving a directory listing of NAME over CONN, returning a file
+ descriptor in DATA over which the data can be read. */
+error_t ftp_conn_start_dir (struct ftp_conn *conn, const char *name, int *data);
+
+/* Start storing into file NAME over CONN, returning a file descriptor in DATA
+ into which the data can be written. */
+error_t ftp_conn_start_store (struct ftp_conn *conn, const char *name, int *data);
+
+/* Transfer the output of SRC_CMD/SRC_NAME on SRC_CONN to DST_NAME on
+ DST_CONN, moving the data directly between servers. */
+error_t
+ftp_conn_rmt_transfer (struct ftp_conn *src_conn,
+ const char *src_cmd, const char *src_name,
+ const int *src_poss_errs,
+ struct ftp_conn *dst_conn, const char *dst_name);
+
+/* Copy the SRC_NAME on SRC_CONN to DST_NAME on DST_CONN, moving the data
+ directly between servers. */
+error_t
+ftp_conn_rmt_copy (struct ftp_conn *src_conn, const char *src_name,
+ struct ftp_conn *dst_conn, const char *dst_name);
+
+/* Return a malloced string containing CONN's working directory in CWD. */
+error_t ftp_conn_get_cwd (struct ftp_conn *conn, char **cwd);
+
+/* Return a malloced string containing CONN's working directory in CWD. */
+error_t ftp_conn_cwd (struct ftp_conn *conn, const char *cwd);
+
+/* Return a malloced string containing CONN's working directory in CWD. */
+error_t ftp_conn_cdup (struct ftp_conn *conn);
+
+/* Set the ftp connection type of CONN to TYPE, or return an error. */
+error_t ftp_conn_set_type (struct ftp_conn *conn, const char *type);
+
+/* Start an operation to get a list of file-stat structures for NAME (this
+ is often similar to ftp_conn_start_dir, but with OS-specific flags), and
+ return a file-descriptor for reading on, and a state structure in STATE
+ suitable for passing to cont_get_stats. If CONTENTS is true, NAME must
+ refer to a directory, and the contents will be returned, otherwise, the
+ (single) result will refer to NAME. */
+error_t ftp_conn_start_get_stats (struct ftp_conn *conn,
+ const char *name, int contents,
+ int *fd, void **state);
+
+/* Read stats information from FD, calling ADD_STAT for each new stat (HOOK
+ is passed to ADD_STAT). FD and STATE should be returned from
+ start_get_stats. If this function returns EAGAIN, then it should be
+ called again to finish the job (possibly after calling select on FD); if
+ it returns 0, then it is finishe,d and FD and STATE are deallocated. */
+error_t ftp_conn_cont_get_stats (struct ftp_conn *conn, int fd, void *state,
+ ftp_conn_add_stat_fun_t add_stat, void *hook);
+
+/* Get a list of file-stat structures for NAME, calling ADD_STAT for each one
+ (HOOK is passed to ADD_STAT). If CONTENTS is true, NAME must refer to a
+ directory, and the contents will be returned, otherwise, the (single)
+ result will refer to NAME. This function may block. */
+error_t ftp_conn_get_stats (struct ftp_conn *conn,
+ const char *name, int contents,
+ ftp_conn_add_stat_fun_t add_stat, void *hook);
+
+/* The type of the function called by ...get_names to add each new name.
+ NAME is the name in question and HOOK is as passed into ...get_stats. */
+typedef error_t (*ftp_conn_add_name_fun_t) (const char *name, void *hook);
+
+/* Start an operation to get a list of filenames in the directory NAME, and
+ return a file-descriptor for reading on, and a state structure in STATE
+ suitable for passing to cont_get_names. */
+error_t ftp_conn_start_get_names (struct ftp_conn *conn,
+ const char *name, int *fd, void **state);
+
+/* Read filenames from FD, calling ADD_NAME for each new NAME (HOOK is passed
+ to ADD_NAME). FD and STATE should be returned from start_get_stats. If
+ this function returns EAGAIN, then it should be called again to finish the
+ job (possibly after calling select on FD); if it returns 0, then it is
+ finishe,d and FD and STATE are deallocated. */
+error_t ftp_conn_cont_get_names (struct ftp_conn *conn, int fd, void *state,
+ ftp_conn_add_name_fun_t add_name, void *hook);
+
+/* Get a list of names in the directory NAME, calling ADD_NAME for each one
+ (HOOK is passed to ADD_NAME). This function may block. */
+error_t ftp_conn_get_names (struct ftp_conn *conn, const char *name,
+ ftp_conn_add_name_fun_t add_name, void *hook);
+
+/* Give a name which refers to a directory file, and a name in that
+ directory, this should return in COMPOSITE the composite name referring to
+ that name in that directory, in malloced storage. */
+error_t ftp_conn_append_name (struct ftp_conn *conn,
+ const char *dir, const char *name,
+ char **composite);
+
+/* If the name of a file COMPOSITE is a composite name (containing both a
+ filename and a directory name), this function will return the name
+ component only in BASE, in malloced storage, otherwise it simply returns a
+ newly malloced copy of COMPOSITE in BASE. */
+error_t ftp_conn_basename (struct ftp_conn *conn,
+ const char *composite, char **base);
+
+#endif /* __FTPCONN_H__ */
diff --git a/libftpconn/names.c b/libftpconn/names.c
new file mode 100644
index 00000000..4536b723
--- /dev/null
+++ b/libftpconn/names.c
@@ -0,0 +1,238 @@
+/* Fetch directory file names
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ftpconn.h>
+
+struct get_names_state
+{
+ char *name; /* Last read (maybe partial) name. */
+ size_t name_len; /* Valid length of NAME, *not including* '\0'. */
+ size_t name_alloced; /* Allocated size of NAME (>= NAME_LEN). */
+ int name_partial; /* True if NAME isn't complete. */
+
+ size_t buf_len; /* Length of contents in BUF. */
+ char buf[7000];
+};
+
+/* Start an operation to get a list of filenames in the directory NAME, and
+ return a file-descriptor for reading on, and a state structure in STATE
+ suitable for passing to cont_get_names. */
+error_t
+ftp_conn_start_get_names (struct ftp_conn *conn,
+ const char *name, int *fd, void **state)
+{
+ error_t err;
+ struct get_names_state *s = malloc (sizeof (struct get_names_state));
+
+ if (! s)
+ return ENOMEM;
+
+ err = ftp_conn_start_list (conn, name, fd);
+
+ if (err)
+ free (s);
+ else
+ {
+ s->name = 0;
+ s->name_len = s->name_alloced = 0;
+ s->name_partial = 0;
+ s->buf_len = 0;
+ *state = s;
+ }
+
+ return err;
+}
+
+/* Read filenames from FD, calling ADD_NAME for each new NAME (HOOK is passed
+ to ADD_NAME). FD and STATE should be returned from start_get_names. If
+ this function returns EAGAIN, then it should be called again to finish the
+ job (possibly after calling select on FD); if it returns 0, then it is
+ finishe,d and FD and STATE are deallocated. */
+error_t
+ftp_conn_cont_get_names (struct ftp_conn *conn, int fd, void *state,
+ ftp_conn_add_name_fun_t add_name, void *hook)
+{
+ char *p, *nl;
+ ssize_t rd;
+ size_t name_len;
+ error_t err = 0;
+ struct get_names_state *s = state;
+ int (*icheck) (struct ftp_conn *conn) = conn->hooks->interrupt_check;
+
+ /* We always consume full lines, so we know that we have to read more when
+ we first get called. */
+ rd = read (fd, s->buf + s->buf_len, sizeof (s->buf) - s->buf_len);
+ if (rd < 0)
+ {
+ err = errno;
+ goto finished;
+ }
+
+ if (icheck && (*icheck) (conn))
+ {
+ err = EINTR;
+ goto finished;
+ }
+
+ if (rd == 0)
+ /* EOF */
+ if (s->buf_len == 0)
+ /* We're done! Clean up and return the result in NAMES. */
+ goto finished;
+ else
+ /* Partial line at end of file? */
+ nl = s->buf + s->buf_len;
+ else
+ /* Look for a new line in what we read (we know that there weren't any in
+ the buffer before that). */
+ {
+ nl = memchr (s->buf + s->buf_len, '\n', rd);
+ s->buf_len += rd;
+ }
+
+ if (!nl && s->buf_len < sizeof (s->buf))
+ /* We didn't find any newlines (which implies we didn't hit EOF), and we
+ still have room to grow the buffer, so just wait until next time to do
+ anything. */
+ return EAGAIN;
+
+ /* Where we start parsing. */
+ p = s->buf;
+
+ do
+ {
+ /* Fill in S->name, possibly extending it from a previous buffer. */
+ name_len = (nl ? nl - p : s->buf + s->buf_len - p);
+ if (name_len > 0 && p[name_len - 1] == '\r')
+ name_len--;
+ if (name_len > 0)
+ /* Extending s->name. */
+ {
+ size_t old_len = s->name_len;
+ size_t total_len = old_len + name_len + 1;
+
+ if (total_len > s->name_alloced)
+ {
+ char *new_name = realloc (s->name, total_len);
+ if (! new_name)
+ goto enomem;
+ s->name = new_name;
+ s->name_alloced = total_len;
+ }
+
+ strncpy (s->name + old_len, p, name_len);
+ s->name[old_len + name_len] = '\0';
+ s->name_len = total_len - 1;
+ }
+
+ if (nl)
+ {
+ char *name = s->name;
+
+ if (conn->syshooks.basename)
+ /* Fixup any screwy names returned by the server. */
+ {
+ err = (*conn->syshooks.basename) (conn, &name);
+ if (err)
+ goto finished;
+ }
+
+ /* Call the callback function to process the current entry. */
+ err = (*add_name) (name, hook);
+
+ if (name < s->name || name > s->name + s->name_len)
+ /* User-allocated NAME from the fix_nlist_name hook. */
+ free (name);
+
+ if (err)
+ goto finished;
+
+ s->name_len = 0;
+ s->name_partial = 0;
+
+ p = nl + 1;
+ nl = memchr (p, '\n', s->buf + s->buf_len - p);
+ }
+ else
+ /* We found no newline, so the name extends past what we read; we'll
+ try to read more next time. */
+ {
+ s->name_partial = 1;
+ /* Skip over the partial name for the next iteration. */
+ p += name_len;
+ }
+ }
+ while (nl);
+
+ /* Move any remaining characters in the buffer to the beginning for the
+ next call. */
+ s->buf_len -= (p - s->buf);
+ if (s->buf_len > 0)
+ memmove (s->buf, p, s->buf_len);
+
+ /* Try again later. */
+ return EAGAIN;
+
+enomem:
+ /* Some memory allocation failed. */
+ err = ENOMEM;
+
+finished:
+ /* We're finished (with an error if ERR != 0), deallocate everything &
+ return. */
+ if (s->name)
+ free (s->name);
+ free (s);
+ close (fd);
+
+ if (err && rd > 0)
+ ftp_conn_abort (conn);
+ else if (err)
+ ftp_conn_finish_transfer (conn);
+ else
+ err = ftp_conn_finish_transfer (conn);
+
+ return err;
+}
+
+/* Get a list of names in the directory NAME, calling ADD_NAME for each one
+ (HOOK is passed to ADD_NAME). This function may block. */
+error_t
+ftp_conn_get_names (struct ftp_conn *conn, const char *name,
+ ftp_conn_add_name_fun_t add_name, void *hook)
+{
+ int fd;
+ void *state;
+ error_t err = ftp_conn_start_get_names (conn, name, &fd, &state);
+
+ if (err)
+ return err;
+
+ do
+ err = ftp_conn_cont_get_names (conn, fd, state, add_name, hook);
+ while (err == EAGAIN);
+
+ return err;
+}
+
diff --git a/libftpconn/open.c b/libftpconn/open.c
new file mode 100644
index 00000000..f52bf4d0
--- /dev/null
+++ b/libftpconn/open.c
@@ -0,0 +1,252 @@
+/* Connection initiation
+
+ Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+static error_t
+ftp_conn_login (struct ftp_conn *conn)
+{
+ int reply;
+ error_t err = 0;
+ const struct ftp_conn_params *p = conn->params;
+
+ err = ftp_conn_cmd (conn, "user", p->user ?: "anonymous", &reply, 0);
+
+ if (!err && reply == REPLY_NEED_ACCT)
+ {
+ char *acct = p->acct;
+ if (!acct && conn->hooks && conn->hooks->get_login_param)
+ err = (* conn->hooks->get_login_param) (conn,
+ FTP_CONN_GET_LOGIN_PARAM_ACCT,
+ &acct);
+ if (! err)
+ err = acct ? ftp_conn_cmd (conn, "acct", acct, &reply, 0) : EACCES;
+ if (acct && !p->acct)
+ free (acct);
+ }
+
+ if (!err && reply == REPLY_NEED_PASS)
+ {
+ char *pass = p->pass;
+ if (!pass && conn->hooks && conn->hooks->get_login_param)
+ err = (* conn->hooks->get_login_param) (conn,
+ FTP_CONN_GET_LOGIN_PARAM_PASS,
+ &pass);
+ if (! err)
+ {
+ if (pass)
+ err = ftp_conn_cmd (conn, "pass", pass, &reply, 0);
+ else
+ {
+ pass = getenv ("USER");
+ if (! pass)
+ pass = getenv ("LOGNAME");
+ if (! pass)
+ {
+ struct passwd *pe = getpwuid (getuid ());
+ pass = pe ? pe->pw_name : "?";
+ }
+
+ /* Append a '@' */
+ pass = strdup (pass);
+ if (pass)
+ pass = realloc (pass, strlen (pass) + 1);
+ if (pass)
+ {
+ strcat (pass, "@");
+ err = ftp_conn_cmd (conn, "pass", pass, &reply, 0);
+ }
+ else
+ err = ENOMEM;
+ }
+ }
+ if (pass && !p->pass)
+ free (pass);
+ }
+
+ if (!err && reply != REPLY_LOGIN_OK)
+ {
+ if (REPLY_IS_FAILURE (reply))
+ err = EACCES;
+ else
+ err = unexpected_reply (conn, reply, 0, 0);
+ }
+
+ return err;
+}
+
+static error_t
+ftp_conn_hello (struct ftp_conn *conn)
+{
+ int reply;
+ error_t err;
+
+ do
+ err = ftp_conn_get_reply (conn, &reply, 0);
+ while (!err && reply == REPLY_DELAY);
+
+ if (err)
+ return err;
+
+ if (reply == REPLY_CLOSED)
+ return ECONNREFUSED;
+ if (reply != REPLY_HELLO)
+ return EGRATUITOUS;
+
+ return 0;
+}
+
+/* Sets CONN's syshooks to a copy of SYSHOOKS. */
+void
+ftp_conn_set_syshooks (struct ftp_conn *conn, struct ftp_conn_syshooks *syshooks)
+{
+ conn->syshooks = *syshooks;
+}
+
+void
+ftp_conn_choose_syshooks (struct ftp_conn *conn, const char *syst)
+{
+ if (!syst || (strncasecmp (syst, "UNIX", 4) == 0 && !isalnum (syst[4])))
+ ftp_conn_set_syshooks (conn, &ftp_conn_unix_syshooks);
+}
+
+/* Sets CONN's syshooks by querying the remote system to see what type it is. */
+static error_t
+ftp_conn_sysify (struct ftp_conn *conn)
+{
+ int reply;
+ const char *txt;
+ error_t err = ftp_conn_cmd (conn, "syst", 0, &reply, &txt);
+
+ if (! err)
+ {
+ if (reply == REPLY_SYSTYPE ||
+ reply == REPLY_BAD_CMD || reply == REPLY_UNIMP_CMD || REPLY_NO_LOGIN)
+ {
+ if (reply == REPLY_BAD_CMD || reply == REPLY_UNIMP_CMD
+ || reply == REPLY_NO_LOGIN)
+ txt = 0;
+ if (conn->hooks && conn->hooks->choose_syshooks)
+ (*conn->hooks->choose_syshooks) (conn, txt);
+ else
+ ftp_conn_choose_syshooks (conn, txt);
+ conn->syshooks_valid = 1;
+ }
+ else
+ err = unexpected_reply (conn, reply, txt, 0);
+ }
+
+ return err;
+}
+
+error_t
+ftp_conn_open (struct ftp_conn *conn)
+{
+ static int ftp_port = 0;
+ int csock;
+ error_t err;
+ struct sockaddr_in ftp_addr;
+
+ if (conn->params->addr_type != AF_INET)
+ return EAFNOSUPPORT;
+
+ if (! ftp_port)
+ {
+ struct servent *se = getservbyname ("ftp", "tcp");
+ if (! se)
+ return EGRATUITOUS;
+ ftp_port = se->s_port;
+ }
+
+ if (conn->control >= 0)
+ {
+ close (conn->control);
+ conn->control = -1;
+ }
+ bzero (&conn->syshooks, sizeof conn->syshooks);
+
+ csock = socket (PF_INET, SOCK_STREAM, 0);
+ if (csock < 0)
+ return errno;
+
+ ftp_addr.sin_len = sizeof ftp_addr;
+ ftp_addr.sin_family = conn->params->addr_type;
+ ftp_addr.sin_addr = *(struct in_addr *)conn->params->addr;
+ ftp_addr.sin_port = ftp_port;
+
+ if (connect (csock, (struct sockaddr *)&ftp_addr, sizeof ftp_addr) < 0)
+ {
+ err = errno;
+ close (csock);
+ return err;
+ }
+
+ conn->control = csock;
+
+ err = ftp_conn_hello (conn);
+
+ if (!err && conn->hooks && conn->hooks->opened)
+ (* conn->hooks->opened) (conn);
+
+ if (! err)
+ /* Make any machine-dependent customizations. */
+ ftp_conn_sysify (conn);
+
+ if (! err)
+ /* login */
+ err = ftp_conn_login (conn);
+
+ if (!err && !conn->syshooks_valid)
+ /* Try again now. */
+ err = ftp_conn_sysify (conn);
+
+ if (!err && conn->type)
+ /* Set the connection type. */
+ {
+ int reply;
+ err = ftp_conn_cmd (conn, "type", conn->type, &reply, 0);
+ if (!err && reply != REPLY_OK)
+ err = unexpected_reply (conn, reply, 0, 0);
+ }
+
+ if (err)
+ ftp_conn_close (conn);
+
+ return err;
+}
+
+void
+ftp_conn_close (struct ftp_conn *conn)
+{
+ if (conn->control >= 0)
+ close (conn->control);
+ conn->control = -1;
+ if (conn->hooks && conn->hooks->closed)
+ (* conn->hooks->closed) (conn);
+}
diff --git a/libftpconn/priv.h b/libftpconn/priv.h
new file mode 100644
index 00000000..570ea290
--- /dev/null
+++ b/libftpconn/priv.h
@@ -0,0 +1,98 @@
+/* libftpconn private definitions
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#ifndef __FTPCONN_PRIV_H__
+#define __FTPCONN_PRIV_H__
+
+#include <features.h>
+
+#ifdef FTP_CONN_DEFINE_EI
+#define FTP_CONN_EI
+#else
+#define FTP_CONN_EI __extern_inline
+#endif
+
+/* Ftp reply codes. */
+#define REPLY_DELAY 120 /* Service ready in nnn minutes */
+
+#define REPLY_OK 200 /* Command OK */
+#define REPLY_SYSTYPE 215 /* NAME version */
+#define REPLY_HELLO 220 /* Service ready for new user */
+#define REPLY_ABORT_OK 225 /* ABOR command successful */
+#define REPLY_TRANS_OK 226 /* Closing data connection; requested file
+ action successful */
+#define REPLY_PASV_OK 227 /* Entering passive mode */
+#define REPLY_LOGIN_OK 230 /* User logged in, proceed */
+#define REPLY_FCMD_OK 250 /* Requested file action okay, completed */
+#define REPLY_DIR_NAME 257 /* "DIR" msg */
+
+#define REPLY_NEED_PASS 331 /* User name okay, need password */
+#define REPLY_NEED_ACCT 332 /* Need account for login */
+
+#define REPLY_CLOSED 421 /* Service not available, closing control connection */
+#define REPLY_ABORTED 426 /* Connection closed; transfer aborted */
+
+#define REPLY_BAD_CMD 500 /* Syntax error; command unrecognized */
+#define REPLY_BAD_ARG 501 /* Synax error in parameters or arguments */
+#define REPLY_UNIMP_CMD 502 /* Command not implemented */
+#define REPLY_UNIMP_ARG 504 /* Command not implemented for that parameter */
+
+#define REPLY_NO_LOGIN 530 /* Not logged in */
+#define REPLY_NO_ACCT 532 /* Need account for storing files */
+#define REPLY_NO_SPACE 552 /* Requested file action aborted
+ Exceeded storage allocation */
+
+#define REPLY_IS_PRELIM(rep) ((rep) >= 100 && (rep) < 200)
+#define REPLY_IS_SUCCESS(rep) ((rep) >= 200 && (rep) < 300)
+#define REPLY_IS_INCOMPLETE(rep) ((rep) >= 300 && (rep) < 400)
+#define REPLY_IS_TRANSIENT(rep) ((rep) >= 400 && (rep) < 500)
+#define REPLY_IS_FAILURE(rep) ((rep) >= 500 && (rep) < 600)
+
+extern error_t unexpected_reply (struct ftp_conn *conn, int reply, const char *reply_txt,
+ const error_t *poss_errs);
+#if defined(__USE_EXTERN_INLINES) || defined(FTP_CONN_DEFINE_EI)
+FTP_CONN_EI error_t
+unexpected_reply (struct ftp_conn *conn, int reply, const char *reply_txt,
+ const error_t *poss_errs)
+{
+ if (reply == REPLY_CLOSED)
+ return EPIPE;
+ else if (reply == REPLY_UNIMP_CMD || reply == REPLY_UNIMP_ARG)
+ return EOPNOTSUPP;
+ else if (reply == REPLY_BAD_ARG)
+ return EINVAL;
+ else if (REPLY_IS_FAILURE (reply) && reply_txt
+ && conn->syshooks.interp_err && poss_errs)
+ return (*conn->syshooks.interp_err) (conn, reply_txt, poss_errs);
+ else if (REPLY_IS_TRANSIENT (reply))
+ return EAGAIN;
+ else
+ return EGRATUITOUS;
+}
+#endif /* Use extern inlines. */
+
+/* Error codes we think may result from file operations we do. */
+extern const error_t ftp_conn_poss_file_errs[];
+
+error_t ftp_conn_get_pasv_addr (struct ftp_conn *conn, struct sockaddr **addr);
+
+error_t ftp_conn_send_actv_addr (struct ftp_conn *conn, struct sockaddr *addr);
+
+#endif /* __FTPCONN_PRIV_H__ */
diff --git a/libftpconn/reply.c b/libftpconn/reply.c
new file mode 100644
index 00000000..d39cdb02
--- /dev/null
+++ b/libftpconn/reply.c
@@ -0,0 +1,241 @@
+/* Parse ftp server replies
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+/* Add STR (of size LEN) to CONN's reply_txt buffer, at offset *OFFS,
+ updating *OFFS. */
+static inline error_t
+ftp_conn_add_reply_txt (struct ftp_conn *conn, size_t *offs,
+ const char *str, size_t len)
+{
+ if (*offs + len + 1 > conn->reply_txt_sz)
+ {
+ size_t new_sz = *offs + len + 50;
+ char *new = realloc (conn->reply_txt, new_sz);
+ if (! new)
+ return ENOMEM;
+ conn->reply_txt = new;
+ conn->reply_txt_sz = new_sz;
+ }
+
+ bcopy (str, conn->reply_txt + *offs, len);
+ conn->reply_txt[*offs + len] = '\0'; /* Make sure nul terminated. */
+
+ *offs += len;
+
+ return 0;
+}
+
+/* Return a new line read from CONN's control connection in LINE & LINE_LEN;
+ LINE points into storage allocated in CONN, and is only valid until the
+ next call to this function, or return an error code. (we used to just use
+ the stdio getline function, and keep a stdio stream for the control
+ connection, but interleaved I/O didn't work correctly.) */
+static inline error_t
+ftp_conn_getline (struct ftp_conn *conn, const char **line, size_t *line_len)
+{
+ char *l = conn->line;
+ size_t offs = conn->line_offs, len = conn->line_len, sz = conn->line_sz;
+ int (*icheck) (struct ftp_conn *conn) = conn->hooks->interrupt_check;
+
+ for (;;)
+ {
+ int rd;
+
+ if (offs < len)
+ /* See if there's a newline in the active part of the line buffer. */
+ {
+ char *nl = memchr (l + offs, '\n', len - offs);
+ if (nl)
+ /* There is! Consume and return the whole line we found. */
+ {
+ *line = l + offs;
+
+ offs = nl + 1 - l; /* Consume the line */
+
+ /* Null terminate the result by overwriting the newline; if
+ there's a CR preceding it, get rid of that too. */
+ if (nl > *line && nl[-1] == '\r')
+ nl--;
+ *nl = '\0';
+
+ *line_len = nl - *line;
+
+ if (offs == len)
+ conn->line_offs = conn->line_len = 0;
+ else
+ conn->line_offs = offs;
+
+ return 0;
+ }
+ }
+
+ /* No newline yet, so read some more! */
+
+ if (offs > (len << 2) && offs < len)
+ /* Relocate the current contents of the buffer to the beginning. */
+ {
+ len -= offs;
+ bcopy (l + offs, l, len - offs);
+ offs = conn->line_offs = 0;
+ conn->line_len = len;
+ }
+ if (len == sz)
+ /* Grow the line buffer; there's no space left. */
+ {
+ sz = sz + len ?: 50;
+ l = realloc (l, sz);
+ if (! l)
+ return ENOMEM;
+ conn->line = l;
+ conn->line_sz = sz;
+ }
+
+ /* Actually read something. */
+ rd = read (conn->control, l + len, sz - len);
+ if (rd < 0)
+ return errno;
+ else if (rd == 0)
+ {
+ *line = l + offs;
+ *line_len = 0;
+ return 0;
+ }
+
+ len += rd;
+ conn->line_len = len;
+
+ if (icheck && (*icheck) (conn))
+ return EINTR;
+ }
+}
+
+/* Get the next reply from CONN's ftp server, returning the reply code in
+ REPLY, if REPLY is non-zero, and the text of the reply (not including the
+ reply code) in REPLY_TXT (if it isn't zero), or return an error code. If
+ the reply is multiple lines, all of them are included in REPLY_TXT,
+ separated by newlines. */
+inline error_t
+ftp_conn_get_raw_reply (struct ftp_conn *conn, int *reply,
+ const char **reply_txt)
+{
+ size_t reply_txt_offs = 0; /* End of a multi-line reply in accum buf. */
+ int multi = 0; /* If a multi-line reply, the reply code. */
+
+ if (!reply && !reply_txt)
+ return 0; /* nop */
+
+ do
+ {
+ const char *l;
+ size_t len;
+ error_t err = ftp_conn_getline (conn, &l, &len);
+
+ if (err)
+ return err;
+ if (!multi && len == 0)
+ return EPIPE;
+
+#define ACCUM(txt, len) \
+ do { \
+ if (reply_txt) /* Only accumulate if wanted. */ \
+ { \
+ error_t err = \
+ ftp_conn_add_reply_txt (conn, &reply_txt_offs, txt, len); \
+ if (err) \
+ return err; \
+ } \
+ } while (0)
+
+ if (conn->hooks && conn->hooks->cntl_debug)
+ (*conn->hooks->cntl_debug) (conn, FTP_CONN_CNTL_DEBUG_REPLY, l);
+
+ if (isdigit (l[0]) && isdigit (l[1]) && isdigit (l[2]))
+ /* A reply code. */
+ {
+ int code = (l[0] - '0')*100 + (l[1] - '0')*10 + (l[2] - '0');
+
+ if (multi && code != multi)
+ /* Two codes in a multi-line reply don't match. */
+ return EGRATUITOUS;
+
+ if (l[3] == '-')
+ /* The non-terminal line of a multi-line reply. RFC959 actually
+ claims there shouldn't be more than one multi-line code (other
+ lines in between the two shouldn't have a numeric code at
+ all), but real ftp servers don't obey this rule. */
+ multi = code;
+ else if (l[3] != ' ')
+ /* Some syntax error. */
+ return EGRATUITOUS;
+ else
+ /* The end of the reply (and perhaps the only line). */
+ {
+ multi = 0;
+ if (reply)
+ *reply = code;
+ }
+
+ ACCUM (l + 4, len - 4);
+ }
+ else if (multi)
+ /* The lines between the first and last in a multi-line reply may be
+ anything as long as they don't start with a digit. */
+ ACCUM (l, len);
+ else
+ return EGRATUITOUS;
+ }
+ while (multi);
+
+ if (reply_txt)
+ *reply_txt = conn->reply_txt;
+
+ return 0;
+}
+
+/* Get the next reply from CONN's ftp server, returning the reply code in
+ REPLY, if REPLY is non-zero, and the text of the reply (not including the
+ reply code) in REPLY_TXT (if it isn't zero), or return an error code. If
+ the reply is multiple lines, all of them are included in REPLY_TXT,
+ separated by newlines. This differs from ftp_conn_get_raw_reply in that
+ it eats REPLY_ABORT_OK replies on the assumption that they're junk left
+ over from the last abort command. */
+error_t
+ftp_conn_get_reply (struct ftp_conn *conn, int *reply, const char **reply_txt)
+{
+ int code;
+ error_t err;
+
+ do
+ err = ftp_conn_get_raw_reply (conn, &code, reply_txt);
+ while (!err && code == REPLY_ABORT_OK);
+
+ if (!err && reply)
+ *reply = code;
+
+ return err;
+}
diff --git a/libftpconn/rmt.c b/libftpconn/rmt.c
new file mode 100644
index 00000000..7ada5774
--- /dev/null
+++ b/libftpconn/rmt.c
@@ -0,0 +1,94 @@
+/* Remote (server-to-server) transfer
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+/* Transfer the output of SRC_CMD/SRC_NAME on SRC_CONN to DST_NAME on
+ DST_CONN, moving the data directly between servers. */
+error_t
+ftp_conn_rmt_transfer (struct ftp_conn *src_conn,
+ const char *src_cmd, const char *src_name,
+ const int *src_poss_errs,
+ struct ftp_conn *dst_conn, const char *dst_name)
+{
+ struct sockaddr *src_addr;
+ error_t err = ftp_conn_get_pasv_addr (src_conn, &src_addr);
+
+ if (! err)
+ {
+ err = ftp_conn_send_actv_addr (dst_conn, src_addr);
+
+ if (! err)
+ {
+ int reply;
+ const char *txt;
+ err = ftp_conn_cmd (src_conn, src_cmd, src_name, 0, 0);
+
+ if (! err)
+ {
+ err = ftp_conn_cmd (dst_conn, "stor", dst_name, &reply, &txt);
+
+ if (! err)
+ {
+ if (REPLY_IS_PRELIM (reply))
+ {
+ err = ftp_conn_get_reply (src_conn, &reply, &txt);
+ if (!err && !REPLY_IS_PRELIM (reply))
+ err = unexpected_reply (src_conn, reply, txt,
+ src_poss_errs);
+
+ if (err)
+ ftp_conn_abort (dst_conn);
+ else
+ err = ftp_conn_finish_transfer (dst_conn);
+ }
+ else
+ err = unexpected_reply (dst_conn, reply, txt,
+ ftp_conn_poss_file_errs);
+ }
+ if (err)
+ /* Ftp servers seem to hang trying to abort at this point, so
+ just close the connection entirely. */
+ ftp_conn_close (src_conn);
+ else
+ err = ftp_conn_finish_transfer (src_conn);
+ }
+ }
+
+ free (src_addr);
+ }
+
+ return err;
+}
+
+/* Copy the SRC_NAME on SRC_CONN to DST_NAME on DST_CONN, moving the data
+ directly between servers. */
+error_t
+ftp_conn_rmt_copy (struct ftp_conn *src_conn, const char *src_name,
+ struct ftp_conn *dst_conn, const char *dst_name)
+{
+ return
+ ftp_conn_rmt_transfer (src_conn, "retr", src_name, ftp_conn_poss_file_errs,
+ dst_conn, dst_name);
+}
diff --git a/libftpconn/set-type.c b/libftpconn/set-type.c
new file mode 100644
index 00000000..6c500ce6
--- /dev/null
+++ b/libftpconn/set-type.c
@@ -0,0 +1,60 @@
+/* Set connection type
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+/* Set the ftp connection type of CONN to TYPE, or return an error. */
+error_t
+ftp_conn_set_type (struct ftp_conn *conn, const char *type)
+{
+ error_t err = 0;
+
+ if (! type)
+ return EINVAL;
+
+ if (!conn->type || strcmp (type, conn->type) != 0)
+ {
+ type = strdup (type);
+ if (! type)
+ err = ENOMEM;
+ else
+ {
+ int reply;
+ error_t err = ftp_conn_cmd (conn, "type", type, &reply, 0);
+
+ if (!err && reply != REPLY_OK && reply != REPLY_CLOSED)
+ err = unexpected_reply (conn, reply, 0, 0);
+
+ if (!err || err == EPIPE)
+ {
+ if (conn->type)
+ free ((char *)conn->type);
+ conn->type = type;
+ }
+ }
+ }
+
+ return err;
+}
diff --git a/libftpconn/stats.c b/libftpconn/stats.c
new file mode 100644
index 00000000..1b37a7f3
--- /dev/null
+++ b/libftpconn/stats.c
@@ -0,0 +1,80 @@
+/* Fetch file stats
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <ftpconn.h>
+
+/* Start an operation to get a list of file-stat structures for NAME (this
+ is often similar to ftp_conn_start_dir, but with OS-specific flags), and
+ return a file-descriptor for reading on, and a state structure in STATE
+ suitable for passing to cont_get_stats. If CONTENTS is true, NAME must
+ refer to a directory, and the contents will be returned, otherwise, the
+ (single) result will refer to NAME. */
+error_t
+ftp_conn_start_get_stats (struct ftp_conn *conn,
+ const char *name, int contents,
+ int *fd, void **state)
+{
+ if (conn->syshooks.start_get_stats)
+ return
+ (*conn->syshooks.start_get_stats) (conn, name, contents, fd, state);
+ else
+ return EOPNOTSUPP;
+}
+
+/* Read stats information from FD, calling ADD_STAT for each new stat (HOOK
+ is passed to ADD_STAT). FD and STATE should be returned from
+ start_get_stats. If this function returns EAGAIN, then it should be
+ called again to finish the job (possibly after calling select on FD); if
+ it returns 0, then it is finishe,d and FD and STATE are deallocated. */
+error_t
+ftp_conn_cont_get_stats (struct ftp_conn *conn, int fd, void *state,
+ ftp_conn_add_stat_fun_t add_stat, void *hook)
+{
+ if (conn->syshooks.cont_get_stats)
+ return (*conn->syshooks.cont_get_stats) (conn, fd, state, add_stat, hook);
+ else
+ return EOPNOTSUPP;
+}
+
+/* Get a list of file-stat structures for NAME, calling ADD_STAT for each one
+ (HOOK is passed to ADD_STAT). If CONTENTS is true, NAME must refer to a
+ directory, and the contents will be returned, otherwise, the (single)
+ result will refer to NAME. This function may block. */
+error_t
+ftp_conn_get_stats (struct ftp_conn *conn,
+ const char *name, int contents,
+ ftp_conn_add_stat_fun_t add_stat, void *hook)
+{
+ int fd;
+ void *state;
+ error_t err = ftp_conn_start_get_stats (conn, name, contents, &fd, &state);
+
+ if (err)
+ return err;
+
+ do
+ err = ftp_conn_cont_get_stats (conn, fd, state, add_stat, hook);
+ while (err == EAGAIN);
+
+ return err;
+}
diff --git a/libftpconn/unix.c b/libftpconn/unix.c
new file mode 100644
index 00000000..28efefdd
--- /dev/null
+++ b/libftpconn/unix.c
@@ -0,0 +1,772 @@
+/* Unix-specific ftpconn hooks
+
+ Copyright (C) 1997, 1998, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <libgen.h> /* For dirname(). */
+#ifdef HAVE_HURD_HURD_TYPES_H
+#include <hurd/hurd_types.h>
+#endif
+
+#include <ftpconn.h>
+
+/* Uid/gid to use when we don't know about a particular user name. */
+#define DEFAULT_UID 65535
+#define DEFAULT_GID 65535
+
+struct ftp_conn_syshooks ftp_conn_unix_syshooks = {
+ ftp_conn_unix_pasv_addr, ftp_conn_unix_interp_err,
+ ftp_conn_unix_start_get_stats, ftp_conn_unix_cont_get_stats,
+ ftp_conn_unix_append_name, ftp_conn_unix_basename
+};
+
+/* Try to get an internet address out of the reply to a PASV command.
+ Unfortunately, the format of the reply such isn't standardized. */
+error_t
+ftp_conn_unix_pasv_addr (struct ftp_conn *conn, const char *txt,
+ struct sockaddr **addr)
+{
+ unsigned a0, a1, a2, a3; /* Parts of the inet address */
+ unsigned p0, p1; /* Parts of the prot (msb, lsb) */
+
+ if (sscanf (txt, "%*[^0-9]%d,%d,%d,%d,%d,%d", &a0,&a1,&a2,&a3, &p0,&p1) != 6)
+ return EGRATUITOUS;
+ else
+ {
+ unsigned char *a, *p;
+
+ *addr = malloc (sizeof (struct sockaddr_in));
+ if (! *addr)
+ return ENOMEM;
+
+ (*addr)->sa_len = sizeof (struct sockaddr_in);
+ (*addr)->sa_family = AF_INET;
+
+ a = (unsigned char *)&((struct sockaddr_in *)*addr)->sin_addr.s_addr;
+ a[0] = a0 & 0xff;
+ a[1] = a1 & 0xff;
+ a[2] = a2 & 0xff;
+ a[3] = a3 & 0xff;
+
+ p = (unsigned char *)&((struct sockaddr_in *)*addr)->sin_port;
+ p[0] = p0 & 0xff;
+ p[1] = p1 & 0xff;
+
+ return 0;
+ }
+}
+
+/* Compare strings P & Q in a most forgiving manner, ignoring case and
+ everything but alphanumeric characters. */
+static int
+strlaxcmp (const char *p, const char *q)
+{
+ for (;;)
+ {
+ int ch1, ch2;
+
+ while (*p && !isalnum (*p))
+ p++;
+ while (*q && !isalnum (*q))
+ q++;
+
+ if (!*p || !*q)
+ break;
+
+ ch1 = tolower (*p);
+ ch2 = tolower (*q);
+ if (ch1 != ch2)
+ break;
+
+ p++;
+ q++;
+ }
+
+ return *p - *q;
+}
+
+/* Try to convert an error message in TXT into an error code. POSS_ERRS
+ contains a list of likely errors to try; if no other clue is found, the
+ first thing in poss_errs is returned. */
+error_t
+ftp_conn_unix_interp_err (struct ftp_conn *conn, const char *txt,
+ const error_t *poss_errs)
+{
+ const char *p;
+ const error_t *e;
+
+ if (!poss_errs || !poss_errs[0])
+ return EIO;
+
+ /* ignore everything before the last colon. */
+ p = strrchr (txt, ':');
+ if (p)
+ p++;
+ else
+ p = txt;
+
+ /* Now, for each possible error, do a string compare ignoring case and
+ anything non-alphanumberic. */
+ for (e = poss_errs; *e; e++)
+ if (strlaxcmp (p, strerror (*e)) == 0)
+ return *e;
+
+ return poss_errs[0];
+}
+
+struct get_stats_state
+{
+ char *name; /* Last read (maybe partial) name. */
+ size_t name_len; /* Valid length of NAME, *not including* '\0'. */
+ size_t name_alloced; /* Allocated size of NAME (>= NAME_LEN). */
+ int name_partial; /* True if NAME isn't complete. */
+
+ int contents; /* Are we looking for directory contents? */
+ char *searched_name; /* If we are not, then we are only
+ looking for this name. */
+
+ int added_slash; /* Did we prefix the name with `./'? */
+
+ struct stat stat; /* Last read stat info. */
+
+ int start; /* True if at beginning of output. */
+
+ size_t buf_len; /* Length of contents in BUF. */
+ char buf[7000];
+};
+
+/* Start an operation to get a list of file-stat structures for NAME (this is
+ often similar to ftp_conn_start_dir, but with OS-specific flags), and
+ return a file-descriptor for reading on, and a state structure in STATE
+ suitable for passing to cont_get_stats. If CONTENTS is true, NAME must
+ refer to a directory, and the contents will be returned, otherwise, the
+ (single) result will refer to NAME. */
+error_t
+ftp_conn_unix_start_get_stats (struct ftp_conn *conn,
+ const char *name, int contents,
+ int *fd, void **state)
+{
+ error_t err = 0;
+ size_t req_len;
+ char *req = NULL;
+ struct get_stats_state *s = NULL;
+ const char *flags = "-A";
+ const char *slash = strchr (name, '/');
+ char *searched_name = NULL;
+
+ s = (struct get_stats_state *) malloc (sizeof (struct get_stats_state));
+ if (! s)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+ if (! contents)
+ {
+ if (! strcmp (name, "/"))
+ {
+ /* Listing only the directory itself and not the directory
+ content seems to be not supported by all FTP servers. If
+ the directory in question is not the root directory, we
+ can simply lookup `..', but that doesn't work if we are
+ already on the root directory. */
+ err = EINVAL;
+ }
+ else
+ {
+ searched_name = strdup (basename ((char *) name));
+ if (! searched_name)
+ err = ENOMEM;
+ }
+ if (err)
+ goto out;
+ }
+
+ if (strcspn (name, "*? \t\n{}$`\\\"'") < strlen (name))
+ /* NAME contains some metacharacters, which makes the behavior of various
+ ftp servers unpredictable, so punt. */
+ {
+ err = EINVAL;
+ goto out;
+ }
+
+ /* We pack the ls options and the name into the list argument, in REQ,
+ which will do the right thing on most unix ftp servers. */
+
+ req_len = strlen (flags) + 2; /* space character + null character. */
+ if (! contents)
+ {
+ /* If we are looking for a directory rather than its content,
+ lookup the parent directory and search for the entry, rather
+ than looking it up directly, as not all ftp servers support
+ the -d option to ls. To make sure we get a directory, append
+ '/', except for the root directory. */
+ char *dirn = dirname (strdupa (name));
+ int is_root = ! strcmp (dirn, "/");
+ req_len += strlen (dirn) + (is_root ? 0 : 1);
+ req = malloc (req_len);
+ if (! req)
+ err = ENOMEM;
+ else
+ sprintf (req, "%s %s%s", flags, dirn, (is_root ? "" : "/"));
+ }
+ else
+ {
+ /* If NAME doesn't contain a slash, we prepend `./' to it so that we can
+ tell from the results whether it's a directory or not. */
+ req_len += strlen (name) + (slash ? 0 : 2);
+ req = malloc (req_len);
+ if (! req)
+ err = ENOMEM;
+ else
+ sprintf (req, "%s %s%s", flags, slash ? "" : "./", name);
+ }
+
+ if (err)
+ goto out;
+
+ /* Make the actual request. */
+ err = ftp_conn_start_dir (conn, req, fd);
+
+ out:
+
+ if (req)
+ free (req);
+ if (err)
+ {
+ if (s)
+ free (s);
+ if (searched_name)
+ free (searched_name);
+ }
+ else
+ {
+ s->contents = contents;
+ s->searched_name = searched_name;
+ s->added_slash = !slash;
+ s->name = 0;
+ s->name_len = s->name_alloced = 0;
+ s->name_partial = 0;
+ s->buf_len = 0;
+ s->start = 1;
+ *state = s;
+ }
+
+ return err;
+}
+
+static char *months[] =
+{
+ "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct",
+ "nov", "dec", 0
+};
+
+/* Translate the information in the ls output in *LINE as best we can into
+ STAT, and update *LINE to point to the filename at the end of the line.
+ If *LINE should be ignored, EAGAIN is returned. */
+static error_t
+parse_dir_entry (char **line, struct stat *stat)
+{
+ char **m;
+ struct tm tm;
+ char *p = *line, *e;
+
+ /*
+drwxrwxrwt 3 root wheel 1024 May 1 16:58 /tmp
+drwxrwxrwt 5 root daemon 4096 May 1 17:15 /tmp
+drwxrwxrwt 4 root 0 1024 May 1 14:34 /tmp
+drwxrwxrwt 6 root wheel 284 May 1 12:46 /tmp
+drwxrwxrwt 4 sys sys 482 May 1 17:11 /tmp
+drwxrwxrwt 7 34 archive 512 May 1 14:28 /tmp
+ */
+
+ if (strncasecmp (p, "total ", 6) == 0)
+ return EAGAIN;
+
+ bzero (stat, sizeof *stat);
+
+#ifdef FSTYPE_FTP
+ stat->st_fstype = FSTYPE_FTP;
+#endif
+
+ /* File format (S_IFMT) bits. */
+ switch (*p++)
+ {
+ case '-': stat->st_mode |= S_IFREG; break;
+ case 'd': stat->st_mode |= S_IFDIR; break;
+ case 'c': stat->st_mode |= S_IFCHR; break;
+ case 'b': stat->st_mode |= S_IFBLK; break;
+ case 'l': stat->st_mode |= S_IFLNK; break;
+ case 's': stat->st_mode |= S_IFSOCK; break;
+ case 'p': stat->st_mode |= S_IFIFO; break;
+ default: return EGRATUITOUS;
+ }
+
+ /* User perm bits. */
+ switch (*p++)
+ {
+ case '-': break;
+ case 'r': stat->st_mode |= S_IRUSR; break;
+ default: return EGRATUITOUS;
+ }
+ switch (*p++)
+ {
+ case '-': break;
+ case 'w': stat->st_mode |= S_IWUSR; break;
+ default: return EGRATUITOUS;
+ }
+ switch (*p++)
+ {
+ case '-': break;
+ case 'x': stat->st_mode |= S_IXUSR; break;
+ case 's': stat->st_mode |= S_IXUSR | S_ISUID; break;
+ case 'S': stat->st_mode |= S_ISUID; break;
+ default: return EGRATUITOUS;
+ }
+
+ /* Group perm bits. */
+ switch (*p++)
+ {
+ case '-': break;
+ case 'r': stat->st_mode |= S_IRGRP; break;
+ default: return EGRATUITOUS;
+ }
+ switch (*p++)
+ {
+ case '-': break;
+ case 'w': stat->st_mode |= S_IWGRP; break;
+ default: return EGRATUITOUS;
+ }
+ switch (*p++)
+ {
+ case '-': break;
+ case 'x': stat->st_mode |= S_IXGRP; break;
+ case 's': stat->st_mode |= S_IXGRP | S_ISGID; break;
+ case 'S': stat->st_mode |= S_ISGID; break;
+ default: return EGRATUITOUS;
+ }
+
+ /* `Other' perm bits. */
+ switch (*p++)
+ {
+ case '-': break;
+ case 'r': stat->st_mode |= S_IROTH; break;
+ default: return EGRATUITOUS;
+ }
+ switch (*p++)
+ {
+ case '-': break;
+ case 'w': stat->st_mode |= S_IWOTH; break;
+ default: return EGRATUITOUS;
+ }
+ switch (*p++)
+ {
+ case '-': break;
+ case 'x': stat->st_mode |= S_IXOTH; break;
+ case 't': stat->st_mode |= S_IXOTH | S_ISVTX; break;
+ case 'T': stat->st_mode |= S_ISVTX; break;
+ default: return EGRATUITOUS;
+ }
+
+#define SKIP_WS() \
+ while (isspace (*p)) p++;
+#define PARSE_INT() ({ \
+ unsigned u = strtoul (p, &e, 10); \
+ if (e == p || isalnum (*e)) \
+ return EGRATUITOUS; \
+ p = e; \
+ u; \
+ })
+
+ /* Link count. */
+ SKIP_WS ();
+ stat->st_nlink = PARSE_INT ();
+
+ /* File owner. */
+ SKIP_WS ();
+ if (isdigit (*p))
+ stat->st_uid = PARSE_INT ();
+ else
+ {
+ struct passwd *pw;
+
+ e = p + strcspn (p, " \t\n");
+ *e++ = '\0';
+
+ pw = getpwnam (p);
+
+ if (pw)
+ stat->st_uid = pw->pw_uid;
+ else
+ stat->st_uid = DEFAULT_UID;
+
+ p = e;
+ }
+
+#ifdef HAVE_STAT_ST_AUTHOR
+ stat->st_author = stat->st_uid;
+#endif
+
+ /* File group. */
+ SKIP_WS ();
+ if (isdigit (*p))
+ stat->st_gid = PARSE_INT ();
+ else
+ {
+ struct group *gr;
+
+ e = p + strcspn (p, " \t\n");
+ *e++ = '\0';
+
+ gr = getgrnam (p);
+
+ if (gr)
+ stat->st_gid = gr->gr_gid;
+ else
+ stat->st_gid = DEFAULT_GID;
+
+ p = e;
+ }
+
+ /* File size / device numbers. */
+ SKIP_WS ();
+ if (S_ISCHR (stat->st_mode) || S_ISBLK (stat->st_mode))
+ /* Block and character devices show the block params instead of the file
+ size. */
+ {
+ stat->st_dev = PARSE_INT ();
+ if (*p != ',')
+ return EGRATUITOUS;
+ stat->st_dev = (stat->st_dev << 8) | PARSE_INT ();
+ stat->st_size = 0;
+ }
+ else
+ /* File size. */
+ stat->st_size = PARSE_INT ();
+
+ stat->st_blocks = stat->st_size >> 9;
+
+ /* Date. Ick. */
+ /* Formats: MONTH DAY HH:MM and MONTH DAY YEAR */
+
+ bzero (&tm, sizeof tm);
+
+ SKIP_WS ();
+ e = p + strcspn (p, " \t\n");
+ for (m = months; *m; m++)
+ if (strncasecmp (*m, p, e - p) == 0)
+ {
+ tm.tm_mon = m - months;
+ break;
+ }
+ if (! *m)
+ return EGRATUITOUS;
+ p = e;
+
+ SKIP_WS ();
+ tm.tm_mday = PARSE_INT ();
+
+ SKIP_WS ();
+ if (p[1] == ':' || p[2] == ':')
+ {
+ struct tm *now_tm;
+ struct timeval now_tv;
+
+ tm.tm_hour = PARSE_INT ();
+ p++;
+ tm.tm_min = PARSE_INT ();
+
+ if (gettimeofday (&now_tv, 0) != 0)
+ return errno;
+
+ now_tm = localtime (&now_tv.tv_sec);
+ if (now_tm->tm_mon < tm.tm_mon)
+ tm.tm_year = now_tm->tm_year - 1;
+ else
+ tm.tm_year = now_tm->tm_year;
+ }
+ else
+ tm.tm_year = PARSE_INT () - 1900;
+
+ stat->st_mtim.tv_sec = mktime (&tm);
+ if (stat->st_mtim.tv_sec == (time_t)-1)
+ return EGRATUITOUS;
+
+ /* atime and ctime are the same as mtime. */
+ stat->st_atim.tv_sec = stat->st_ctim.tv_sec = stat->st_mtim.tv_sec;
+ stat->st_atim.tv_nsec = stat->st_ctim.tv_nsec = stat->st_mtim.tv_nsec = 0;
+
+ /* Update *LINE to point to the filename. */
+ SKIP_WS ();
+ *line = p;
+
+ return 0;
+}
+
+/* Read stats information from FD, calling ADD_STAT for each new stat (HOOK
+ is passed to ADD_STAT). FD and STATE should be returned from
+ start_get_stats. If this function returns EAGAIN, then it should be
+ called again to finish the job (possibly after calling select on FD); if
+ it returns 0, then it is finishe,d and FD and STATE are deallocated. */
+error_t
+ftp_conn_unix_cont_get_stats (struct ftp_conn *conn, int fd, void *state,
+ ftp_conn_add_stat_fun_t add_stat, void *hook)
+{
+ char *p, *nl;
+ ssize_t rd;
+ size_t name_len;
+ error_t err = 0;
+ struct get_stats_state *s = state;
+ int (*icheck) (struct ftp_conn *conn) = conn->hooks->interrupt_check;
+
+ /* We always consume full lines, so we know that we have to read more when
+ we first get called. */
+ rd = read (fd, s->buf + s->buf_len, sizeof (s->buf) - s->buf_len);
+ if (rd < 0)
+ {
+ err = errno;
+ goto finished;
+ }
+
+ if (icheck && (*icheck) (conn))
+ {
+ err = EINTR;
+ goto finished;
+ }
+
+ if (rd == 0)
+ /* EOF */
+ if (s->buf_len == 0)
+ /* We're done! Clean up and return the result in STATS. */
+ {
+ if (s->start)
+ /* No output at all. From many ftp servers, this means that the
+ specified file wasn't found. */
+ err = ENOENT;
+ goto finished;
+ }
+ else
+ /* Partial line at end of file? */
+ nl = s->buf + s->buf_len;
+ else
+ /* Look for a new line in what we read (we know that there weren't any in
+ the buffer before that). */
+ {
+ nl = memchr (s->buf + s->buf_len, '\n', rd);
+ s->buf_len += rd;
+ }
+
+ s->start = 0; /* We've read past the start. */
+
+ if (!nl && s->buf_len < sizeof (s->buf))
+ /* We didn't find any newlines (which implies we didn't hit EOF), and we
+ still have room to grow the buffer, so just wait until next time to do
+ anything. */
+ return EAGAIN;
+
+ /* Where we start parsing. */
+ p = s->buf;
+
+ do
+ {
+ if (! s->name_partial)
+ /* We aren't continuing to read an overflowed name from the previous
+ call, so we know that we are at the start of a line, and can parse
+ the info here as a directory entry. */
+ {
+ /* Parse the directory entry info, updating P to point to the
+ beginning of the name. */
+ err = parse_dir_entry (&p, &s->stat);
+ if (err == EAGAIN)
+ /* This line isn't a real entry and should be ignored. */
+ goto skip_line;
+ if (err)
+ goto finished;
+ }
+
+ /* Now fill in S->last_stat's name field, possibly extending it from a
+ previous buffer. */
+ name_len = (nl ? nl - p : s->buf + s->buf_len - p);
+ if (name_len > 0 && p[name_len - 1] == '\r')
+ name_len--;
+ if (name_len > 0)
+ /* Extending s->name. */
+ {
+ size_t old_len = s->name_len;
+ size_t total_len = old_len + name_len + 1;
+
+ if (total_len > s->name_alloced)
+ {
+ char *new_name = realloc (s->name, total_len);
+ if (! new_name)
+ goto enomem;
+ s->name = new_name;
+ s->name_alloced = total_len;
+ }
+
+ strncpy (s->name + old_len, p, name_len);
+ s->name[old_len + name_len] = '\0';
+ s->name_len = total_len - 1;
+ }
+
+ if (nl)
+ {
+ char *name = s->name;
+ char *symlink_target = 0;
+
+ if (S_ISLNK (s->stat.st_mode))
+ /* A symlink, see if we can find the link target. */
+ {
+ symlink_target = strstr (name, " -> ");
+ if (symlink_target)
+ {
+ *symlink_target = '\0';
+ symlink_target += 4;
+ }
+ }
+
+ if (strchr (name, '/'))
+ {
+ if (s->contents)
+ /* We know that the name originally request had a slash in
+ it (because we added one if necessary), so if a name in
+ the listing has one too, it can't be the contents of a
+ directory; if this is the case and we wanted the
+ contents, this must not be a directory. */
+ {
+ err = ENOTDIR;
+ goto finished;
+ }
+ else if (s->added_slash)
+ /* S->name must be the same name we passed; if we added a
+ `./' prefix, removed it so the client gets back what it
+ passed. */
+ name += 2;
+ }
+
+ /* Pass only directory-relative names to the callback function. */
+ name = basename (name);
+
+ if (s->contents || ! strcmp (s->name, s->searched_name))
+ {
+ /* We are only interested in searched_name. */
+
+ /* Call the callback function to process the current entry; it is
+ responsible for freeing S->name and SYMLINK_TARGET. */
+ err = (*add_stat) (name, &s->stat, symlink_target, hook);
+ if (err)
+ goto finished;
+ }
+
+ s->name_len = 0;
+ s->name_partial = 0;
+
+ skip_line:
+ p = nl + 1;
+ nl = memchr (p, '\n', s->buf + s->buf_len - p);
+ }
+ else
+ /* We found no newline, so the name extends past what we read; we'll
+ try to read more next time. */
+ {
+ s->name_partial = 1;
+ /* Skip over the partial name for the next iteration. */
+ p += name_len;
+ }
+ }
+ while (nl);
+
+ /* Move any remaining characters in the buffer to the beginning for the
+ next call. */
+ s->buf_len -= (p - s->buf);
+ if (s->buf_len > 0)
+ memmove (s->buf, p, s->buf_len);
+
+ /* Try again later. */
+ return EAGAIN;
+
+enomem:
+ /* Some memory allocation failed. */
+ err = ENOMEM;
+
+finished:
+ /* We're finished (with an error if ERR != 0), deallocate everything &
+ return. */
+ if (s->name)
+ free (s->name);
+ if (s->searched_name)
+ free (s->searched_name);
+ free (s);
+ close (fd);
+
+ if (err && rd > 0)
+ ftp_conn_abort (conn);
+ else if (err)
+ ftp_conn_finish_transfer (conn);
+ else
+ err = ftp_conn_finish_transfer (conn);
+
+ return err;
+}
+
+/* Give a name which refers to a directory file, and a name in that
+ directory, this should return in COMPOSITE the composite name referring to
+ that name in that directory, in malloced storage. */
+error_t
+ftp_conn_unix_append_name (struct ftp_conn *conn,
+ const char *dir, const char *name,
+ char **composite)
+{
+ char *path = malloc (strlen (dir) + 1 + strlen (name) + 1);
+
+ if (! path)
+ return ENOMEM;
+
+ /* Form the path name. */
+ if (name && *name)
+ if (dir[0] == '/' && dir[1] == '\0')
+ stpcpy (stpcpy (path, dir), name);
+ else
+ stpcpy (stpcpy (stpcpy (path, dir), "/"), name);
+ else
+ strcpy (path, dir);
+
+ *composite = path;
+
+ return 0;
+}
+
+/* If the name of a file *NAME is a composite name (containing both a
+ filename and a directory name), this function should change *NAME to be
+ the name component only; if the result is shorter than the original
+ *NAME, the storage pointed to it may be modified, otherwise, *NAME
+ should be changed to point to malloced storage holding the result, which
+ will be freed by the caller. */
+error_t
+ftp_conn_unix_basename (struct ftp_conn *conn, char **name)
+{
+ *name = basename (*name);
+ return 0;
+}
diff --git a/libftpconn/xfer.c b/libftpconn/xfer.c
new file mode 100644
index 00000000..b3d0786d
--- /dev/null
+++ b/libftpconn/xfer.c
@@ -0,0 +1,280 @@
+/* Start/stop data channel transfer
+
+ Copyright (C) 1997,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <ftpconn.h>
+#include "priv.h"
+
+/* Open an active data connection, returning the file descriptor in DATA. */
+static error_t
+ftp_conn_start_open_actv_data (struct ftp_conn *conn, int *data)
+{
+ error_t err = 0;
+ /* DCQ is a socket on which to listen for data connections from the server. */
+ int dcq;
+ struct sockaddr *addr = conn->actv_data_addr;
+ socklen_t addr_len = sizeof *addr;
+
+ if (! addr)
+ /* Generate an address for the data connection (which we must know,
+ so we can tell the server). */
+ {
+ addr = conn->actv_data_addr = malloc (sizeof (struct sockaddr_in));
+ if (! addr)
+ return ENOMEM;
+
+ /* Get the local address chosen by the system. */
+ if (conn->control < 0)
+ err = EBADF;
+ else if (getsockname (conn->control, addr, &addr_len) < 0)
+ err = errno;
+
+ if (err == EBADF || err == EPIPE)
+ /* Control connection has closed; reopen it and try again. */
+ {
+ err = ftp_conn_open (conn);
+ if (!err && getsockname (conn->control, addr, &addr_len) < 0)
+ err = errno;
+ }
+
+ if (err)
+ {
+ free (addr);
+ conn->actv_data_addr = 0;
+ return err;
+ }
+ }
+
+ dcq = socket (AF_INET, SOCK_STREAM, 0);
+ if (dcq < 0)
+ return errno;
+
+ /* Let the system choose a port for us. */
+ ((struct sockaddr_in *)addr)->sin_port = 0;
+
+ /* Use ADDR as the data socket's local address. */
+ if (!err && bind (dcq, addr, addr_len) < 0)
+ err = errno;
+
+ /* See what port was chosen by the system. */
+ if (!err && getsockname (dcq, addr, &addr_len) < 0)
+ err = errno;
+
+ /* Set the incoming connection queue length. */
+ if (!err && listen (dcq, 1) < 0)
+ err = errno;
+
+ if (err)
+ close (dcq);
+ else
+ err = ftp_conn_send_actv_addr (conn, conn->actv_data_addr);
+
+ if (! err)
+ *data = dcq;
+
+ return err;
+}
+
+/* Finish opening the active data connection *DATA opened with
+ ftp_conn_start_open_actv_data, following the sending of the command that
+ uses the connection to the server. This function closes the file
+ descriptor in *DATA, and returns a new file descriptor for the actual data
+ connection. */
+static error_t
+ftp_conn_finish_open_actv_data (struct ftp_conn *conn, int *data)
+{
+ struct sockaddr_in rmt_addr;
+ socklen_t rmt_addr_len = sizeof rmt_addr;
+ int real = accept (*data, &rmt_addr, &rmt_addr_len);
+
+ close (*data);
+
+ if (real < 0)
+ return errno;
+
+ *data = real;
+
+ return 0;
+}
+
+/* Abort an active data connection open sequence; this function should be
+ called if ftp_conn_start_open_actv_data succeeds, but an error happens
+ before ftp_conn_finish_open_actv_data can be called. */
+static void
+ftp_conn_abort_open_actv_data (struct ftp_conn *conn, int data)
+{
+ close (data);
+}
+
+/* Return a data connection, which may not be in a completely open state;
+ this call should be followed by the command that uses the connection, and
+ a call to ftp_conn_finish_open_data, if that succeeds. */
+static error_t
+ftp_conn_start_open_data (struct ftp_conn *conn, int *data)
+{
+ error_t err;
+
+ if (conn->use_passive)
+ /* First try a passive connection. */
+ {
+ struct sockaddr *addr;
+
+ /* Tell the server we wan't to use passive mode, for which it should
+ give us an address to connect to. */
+ err = ftp_conn_get_pasv_addr (conn, &addr);
+
+ if (! err)
+ {
+ int dsock = socket (PF_INET, SOCK_STREAM, 0);
+
+ if (dsock < 0)
+ err = errno;
+ else if (connect (dsock, addr, addr->sa_len) < 0)
+ {
+ err = errno;
+ close (dsock);
+ }
+ else
+ *data = dsock;
+
+ free (addr);
+ }
+ }
+ else
+ err = EAGAIN;
+
+ if (err)
+ /* Using a passive connection didn't work, try an active one. */
+ {
+ conn->use_passive = 0; /* Don't try again. */
+ err = ftp_conn_start_open_actv_data (conn, data);
+ }
+
+ return err;
+}
+
+/* Finish opening the data connection *DATA opened with
+ ftp_conn_start_open_data, following the sending of the command that uses
+ the connection to the server. This function may change *DATA, in which
+ case the old file descriptor is closed. */
+static error_t
+ftp_conn_finish_open_data (struct ftp_conn *conn, int *data)
+{
+ if (conn->use_passive)
+ /* Passive connections should already have been completely opened. */
+ return 0;
+ else
+ return ftp_conn_finish_open_actv_data (conn, data);
+}
+
+/* Abort a data connection open sequence; this function should be called if
+ ftp_conn_start_open_data succeeds, but an error happens before
+ ftp_conn_finish_open_data can be called. */
+static void
+ftp_conn_abort_open_data (struct ftp_conn *conn, int data)
+{
+ if (conn->use_passive)
+ close (data);
+ else
+ return ftp_conn_abort_open_actv_data (conn, data);
+}
+
+/* Start a transfer command CMD/ARG, returning a file descriptor in DATA.
+ POSS_ERRS is a list of errnos to try matching against any resulting error
+ text. */
+error_t
+ftp_conn_start_transfer (struct ftp_conn *conn,
+ const char *cmd, const char *arg,
+ const error_t *poss_errs,
+ int *data)
+{
+ error_t err = ftp_conn_start_open_data (conn, data);
+
+ if (! err)
+ {
+ int reply;
+ const char *txt;
+
+ err = ftp_conn_cmd (conn, cmd, arg, &reply, &txt);
+ if (!err && !REPLY_IS_PRELIM (reply))
+ err = unexpected_reply (conn, reply, txt, poss_errs);
+
+ if (err)
+ ftp_conn_abort_open_data (conn, *data);
+ else
+ err = ftp_conn_finish_open_data (conn, data);
+ }
+
+ return err;
+}
+
+/* Wait for the reply signalling the end of a data transfer. */
+error_t
+ftp_conn_finish_transfer (struct ftp_conn *conn)
+{
+ int reply;
+ error_t err = ftp_conn_get_reply (conn, &reply, 0);
+ if (!err && reply != REPLY_TRANS_OK && reply != REPLY_FCMD_OK)
+ err = unexpected_reply (conn, reply, 0, 0);
+ return err;
+}
+
+/* Start retreiving file NAME over CONN, returning a file descriptor in DATA
+ over which the data can be read. */
+error_t
+ftp_conn_start_retrieve (struct ftp_conn *conn, const char *name, int *data)
+{
+ if (! name)
+ return EINVAL;
+ return
+ ftp_conn_start_transfer (conn, "retr", name, ftp_conn_poss_file_errs, data);
+}
+
+/* Start retreiving a list of files in NAME over CONN, returning a file
+ descriptor in DATA over which the data can be read. */
+error_t
+ftp_conn_start_list (struct ftp_conn *conn, const char *name, int *data)
+{
+ return
+ ftp_conn_start_transfer (conn, "nlst", name, ftp_conn_poss_file_errs, data);
+}
+
+/* Start retreiving a directory listing of NAME over CONN, returning a file
+ descriptor in DATA over which the data can be read. */
+error_t
+ftp_conn_start_dir (struct ftp_conn *conn, const char *name, int *data)
+{
+ return
+ ftp_conn_start_transfer (conn, "list", name, ftp_conn_poss_file_errs, data);
+}
+
+/* Start storing into file NAME over CONN, returning a file descriptor in DATA
+ into which the data can be written. */
+error_t
+ftp_conn_start_store (struct ftp_conn *conn, const char *name, int *data)
+{
+ if (! name)
+ return EINVAL;
+ return
+ ftp_conn_start_transfer (conn, "stor", name, ftp_conn_poss_file_errs, data);
+}
diff --git a/libftpconn/xinl.c b/libftpconn/xinl.c
new file mode 100644
index 00000000..72b7fdcf
--- /dev/null
+++ b/libftpconn/xinl.c
@@ -0,0 +1,24 @@
+/* Real definitions for extern inline functions in priv.h
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>.
+
+ 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. */
+
+#define FTP_CONN_DEFINE_EI
+#include <ftpconn.h>
+#include "priv.h"
diff --git a/libmom/Makefile b/libhurdbugaddr/Makefile
index 04df2c9c..9fad3448 100644
--- a/libmom/Makefile
+++ b/libhurdbugaddr/Makefile
@@ -1,6 +1,6 @@
#
# Copyright (C) 1996 Free Software Foundation, Inc.
-# Written by Michael I. Bushnell, p/BSG.
+# Written by Miles Bader
#
# This file is part of the GNU Hurd.
#
@@ -16,26 +16,13 @@
#
# 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.
-
-dir := libmom
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libhurdbugaddr
makemode := library
+libname := libhurdbugaddr
-libname = libmom
-
-SRCS = allocate-address.c allocate-memory.c copy-ref.c \
- deallocate-memory.c fetch-mach-port.c hash-ref.c \
- mach-port-set.c make-memory-readonly.c make-memory-readwrite.c \
- memory-init.c ref-destroy.c refs-identical.c reserve-memory.c \
- reserve-memory-anywhere.c unreserve-memory.c unuse-memory.c \
- wire-memory.c error-trans.c
-
-LCLHDRS = mom.h mom-kerndep.h priv.h mom-errors.h
-installhdrs = mom.h mom-kerndep.h mom-errors.h
-installhdrsubdir = .
-
-OBJS = $(SRCS:.c=.o)
+SRCS=bugaddr.c
+OBJS=bugaddr.o
include ../Makeconf
-
-
diff --git a/utils/sync.c b/libhurdbugaddr/bugaddr.c
index bce972e8..b04c9352 100644
--- a/utils/sync.c
+++ b/libhurdbugaddr/bugaddr.c
@@ -1,6 +1,8 @@
-/* Call sync synchronously.
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
+/* Hurd default for ARGP_PROGRAM_BUG_ADDRESS
+
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
This file is part of the GNU Hurd.
@@ -18,11 +20,4 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <hurd.h>
-
-int
-main ()
-{
- __USEPORT (CRDIR, __file_syncfs (port, 1, 1));
- return 0;
-}
+const char *argp_program_bug_address = "<bug-hurd@gnu.org>";
diff --git a/libihash/ChangeLog b/libihash/ChangeLog
deleted file mode 100644
index 4fa8198d..00000000
--- a/libihash/ChangeLog
+++ /dev/null
@@ -1,21 +0,0 @@
-Thu Apr 11 15:26:18 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ihash.c: Include "priv.h".
- * primes.c: Likewise.
- * priv.h: New file.
- * Makefile (LCLHDRS): Add priv.h.
- * primes.c (_ihash_nextprime): Renamed from nextprime.c. All
- callers changed.
-
-Thu Mar 7 15:01:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * primes.c: Include <spin_lock.h>.
- (table_lock): New variable.
- (nextprime): Lock table_lock around operation of routine.
-
-Sun Aug 6 15:23:13 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ihash.c (ihash_locp_remove): Get rid of the optimization to use
- HASH_EMPTY instead of HASH_DEL when the next position on the chain
- is empty -- different hash chains may share this cell, and have
- different next positions.
diff --git a/libihash/Makefile b/libihash/Makefile
index 92078c63..e0258241 100644
--- a/libihash/Makefile
+++ b/libihash/Makefile
@@ -1,6 +1,5 @@
-#
-# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-# Written by Michael I. Bushnell.
+#
+# Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc.
#
# This file is part of the GNU Hurd.
#
@@ -17,16 +16,15 @@
# 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 := libihash
makemode := library
-SRCS=ihash.c primes.c
-LCLHDRS=ihash.h priv.h
-OBJS=ihash.o primes.o
libname := libihash
+SRCS = ihash.c
installhdrs = ihash.h
+LCLHDRS = $(installhdrs)
-include ../Makeconf
-
+OBJS = $(SRCS:.c=.o)
+include ../Makeconf
diff --git a/libihash/ihash.c b/libihash/ihash.c
index 8454cdfb..05d53ced 100644
--- a/libihash/ihash.c
+++ b/libihash/ihash.c
@@ -1,278 +1,446 @@
-/* Integer-keyed hash table functions.
-
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+/* ihash.c - Integer-keyed hash table functions.
+ Copyright (C) 1993-1997, 2001, 2003, 2004, 2006
+ Free Software Foundation, Inc.
+ Written by Michael I. Bushnell.
+ Revised by Miles Bader <miles@gnu.org>.
+ Revised by Marcus Brinkmann <marcus@gnu.org>.
This file is part of the GNU Hurd.
- Written by Michael I. Bushnell; revised by Miles Bader <miles@gnu>.
-
The GNU Hurd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful,
+
+ The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include <hurd/ihash.h>
-#include "ihash.h"
-#include "priv.h"
-
-/* ---------------------------------------------------------------- */
-
-/* When an entry in a hashtable's TAB array is HASH_EMPTY, that location is
- available, and none of the other arrays are valid at that index. */
-#define HASH_EMPTY 0
-
-/* When an entry in a hashtable's TAB array is HASH_DEL, that location is
- available, and none of the other arrays are valid at that index. The
- difference from HASH_EMPTY is that searches continue though HASH_DEL and
- stop at HASH_EMPTY. */
-#define HASH_DEL ((void *) -1)
-
-/* Returns an initial index in HT for the key ID, for search for an entry. */
-#define HASH(ht, id) ((id) % (ht)->size)
-/* Returns subsequent indices in HT for the key ID, given the previous one. */
-#define REHASH(ht, id, h) (((id) + (h)) % (ht)->size)
-/* ---------------------------------------------------------------- */
+/* The prime numbers of the form 4 * i + 3 for some i, all greater
+ than twice the previous one and smaller than 2^40 (for now). */
+static const uint64_t ihash_sizes[] =
+{
+ 3,
+ 7,
+ 19,
+ 43,
+ 103,
+ 211,
+ 431,
+ 863,
+ 1747,
+ 3499,
+ 7019,
+ 14051,
+ 28111,
+ 56239,
+ 112507,
+ 225023,
+ 450067,
+ 900139,
+ 1800311,
+ 3600659,
+ 7201351,
+ 14402743,
+ 28805519,
+ 57611039,
+ 115222091,
+ 230444239,
+ 460888499,
+ 921777067,
+ 1843554151,
+ UINT64_C (3687108307),
+ UINT64_C (7374216631),
+ UINT64_C (14748433279),
+ UINT64_C (29496866579),
+ UINT64_C (58993733159),
+ UINT64_C (117987466379),
+ UINT64_C (235974932759),
+ UINT64_C (471949865531),
+ UINT64_C (943899731087)
+};
+
+static const unsigned int ihash_nsizes = (sizeof ihash_sizes
+ / sizeof ihash_sizes[0]);
+
+/* Return 1 if the slot with the index IDX in the hash table HT is
+ empty, and 0 otherwise. */
static inline int
-index_empty(ihash_t ht, int index)
+index_empty (hurd_ihash_t ht, unsigned int idx)
{
- return ht->tab[index] == HASH_EMPTY || ht->tab[index] == HASH_DEL;
+ return ht->items[idx].value == _HURD_IHASH_EMPTY
+ || ht->items[idx].value == _HURD_IHASH_DELETED;
}
+
+/* Return 1 if the index IDX in the hash table HT is occupied by the
+ element with the key KEY. */
static inline int
-index_valid(ihash_t ht, int index, int id)
+index_valid (hurd_ihash_t ht, unsigned int idx, hurd_ihash_key_t key)
{
- return !index_empty(ht, index) && ht->ids[index] == id;
+ return !index_empty (ht, idx) && ht->items[idx].key == key;
}
-/* Given a hash table HT, and a key ID, finds the index in the table of that
- key. You must subsequently check to see whether the given index is valid
- (with index_valid() or index_empty()). */
+
+/* Given a hash table HT, and a key KEY, find the index in the table
+ of that key. You must subsequently check with index_valid() if the
+ returned index is valid. */
static inline int
-find_index(ihash_t ht, int id)
+find_index (hurd_ihash_t ht, hurd_ihash_key_t key)
{
- int h, firsth = -1;
+ unsigned int idx;
+ unsigned int i;
+ unsigned int up_idx;
+ unsigned int down_idx;
+
+ idx = key % ht->size;
+
+ if (ht->items[idx].value == _HURD_IHASH_EMPTY || ht->items[idx].key == key)
+ return idx;
- for (h = HASH(ht, id);
- ht->tab[h] != HASH_EMPTY && ht->ids[h] != id && h != firsth;
- h = REHASH(ht, id, h))
- if (firsth == -1)
- firsth = h;
+ /* Instead of calculating idx + 1, idx + 4, idx + 9, ..., idx + i^2,
+ we add 1, 3, 5, 7, etc to the previous index. We do this in both
+ directions separately. */
+ i = 1;
+ up_idx = idx;
+ down_idx = idx;
- return h;
+ do
+ {
+ up_idx = (up_idx + i) % ht->size;
+ if (ht->items[up_idx].value == _HURD_IHASH_EMPTY
+ || ht->items[up_idx].key == key)
+ return up_idx;
+
+ if (down_idx < i)
+ down_idx += ht->size;
+ down_idx = (down_idx - i) % ht->size;
+ if (ht->items[down_idx].value == _HURD_IHASH_EMPTY
+ || ht->items[down_idx].key == key)
+ return down_idx;
+
+ /* After (ht->size - 1) / 2 iterations, this will be 0. */
+ i = (i + 2) % ht->size;
+ }
+ while (i);
+
+ /* If we end up here, the item could not be found. Return any
+ invalid index. */
+ return idx;
}
-
-/* ---------------------------------------------------------------- */
-/* Create an integer hash table and return it in HT. If a memory allocation
- error occurs, ENOMEM is returned, otherwise 0. */
-error_t
-ihash_create(ihash_t *ht)
+
+/* Remove the entry pointed to by the location pointer LOCP from the
+ hashtable HT. LOCP is the location pointer of which the address
+ was provided to hurd_ihash_add(). */
+static inline void
+locp_remove (hurd_ihash_t ht, hurd_ihash_locp_t locp)
{
- *ht = malloc(sizeof(struct ihash));
- if (*ht == NULL)
- return ENOMEM;
- (*ht)->size = 0;
- return 0;
+ if (ht->cleanup)
+ (*ht->cleanup) (*locp, ht->cleanup_data);
+ *locp = _HURD_IHASH_DELETED;
+ ht->nr_items--;
}
-/* Free HT and all resources it consumes. */
-void
-ihash_free(ihash_t ht)
+
+/* Construction and destruction of hash tables. */
+
+/* Initialize the hash table at address HT. */
+void
+hurd_ihash_init (hurd_ihash_t ht, intptr_t locp_offs)
{
- void (*cleanup)(void *value, void *arg) = ht->cleanup;
+ ht->nr_items = 0;
+ ht->size = 0;
+ ht->locp_offset = locp_offs;
+ ht->max_load = HURD_IHASH_MAX_LOAD_DEFAULT;
+ ht->cleanup = 0;
+}
+
- if (cleanup)
+/* Destroy the hash table at address HT. This first removes all
+ elements which are still in the hash table, and calling the cleanup
+ function for them (if any). */
+void
+hurd_ihash_destroy (hurd_ihash_t ht)
+{
+ if (ht->cleanup)
{
- int i;
- void *arg = ht->cleanup_arg;
- for (i = 0; i < ht->size; i++)
- if (!index_empty(ht, i))
- (*cleanup)(ht->tab[i], arg);
+ hurd_ihash_cleanup_t cleanup = ht->cleanup;
+ void *cleanup_data = ht->cleanup_data;
+
+ HURD_IHASH_ITERATE (ht, value)
+ (*cleanup) (value, cleanup_data);
}
if (ht->size > 0)
- {
- free(ht->tab);
- free(ht->ids);
- free(ht->locps);
- }
+ free (ht->items);
+}
- free(ht);
+
+/* Create a hash table, initialize it and return it in HT. If a
+ memory allocation error occurs, ENOMEM is returned, otherwise 0. */
+error_t
+hurd_ihash_create (hurd_ihash_t *ht, intptr_t locp_offs)
+{
+ *ht = malloc (sizeof (struct hurd_ihash));
+ if (*ht == NULL)
+ return ENOMEM;
+
+ hurd_ihash_init (*ht, locp_offs);
+
+ return 0;
}
-/* Sets HT's element cleanup function to CLEANUP, and its second argument to
- ARG. CLEANUP will be called on the value of any element to be
- subsequently overwritten or deleted, with ARG as the second argument. */
+
+/* Destroy the hash table HT and release the memory allocated for it
+ by hurd_ihash_create(). */
void
-ihash_set_cleanup(ihash_t ht,
- void (*cleanup)(void *value, void *arg),
- void *arg)
+hurd_ihash_free (hurd_ihash_t ht)
{
- ht->cleanup = cleanup;
- ht->cleanup_arg = arg;
+ hurd_ihash_destroy (ht);
+ free (ht);
}
+
-/* ---------------------------------------------------------------- */
-
-/* Add ITEM to the hash table HT under the key ID. LOCP is the address of a
- pointer located in ITEM; If non-NULL, LOCP should point to a variable of
- type void **, and will be filled with a pointer that may be used as an
- argument to ihash_locp_remove(). The variable pointed to by LOCP may be
- written to subsequently between this called and when the element is
- deleted, so you can't stash its value elsewhere and hope to use the
- stashed value with ihash_locp_remove(). If a memory allocation error
- occurs, ENOMEM is returned, otherwise 0. */
-error_t
-ihash_add(ihash_t ht, int id, void *item, void ***locp)
+/* Set the cleanup function for the hash table HT to CLEANUP. The
+ second argument to CLEANUP will be CLEANUP_DATA on every
+ invocation. */
+void
+hurd_ihash_set_cleanup (hurd_ihash_t ht, hurd_ihash_cleanup_t cleanup,
+ void *cleanup_data)
{
- if (ht->size)
- {
- int h, firsth = -1;
+ ht->cleanup = cleanup;
+ ht->cleanup_data = cleanup_data;
+}
- /* Search for for an empty or deleted space. */
- for (h = HASH(ht, id);
- ht->tab[h] != HASH_EMPTY && ht->tab[h] != HASH_DEL && h != firsth;
- h = REHASH(ht, id, h))
- if (firsth == -1)
- firsth = h;
- if (index_empty(ht, h) || ht->ids[h] == id)
- {
- if (!index_empty(ht, h) && ht->cleanup)
- ht->cleanup(ht->tab[h], ht->cleanup_arg);
+/* Set the maximum load factor in percent to MAX_LOAD, which should be
+ between 1 and 100. The default is HURD_IHASH_MAX_LOAD_DEFAULT.
+ New elements are only added to the hash table while the number of
+ hashed elements is that much percent of the total size of the hash
+ table. If more elements are added, the hash table is first
+ expanded and reorganized. A MAX_LOAD of 100 will always fill the
+ whole table before enlarging it, but note that this will increase
+ the cost of operations significantly when the table is almost full.
- ht->tab[h] = item;
- ht->ids[h] = id;
- ht->locps[h] = locp;
+ If the value is set to a smaller value than the current load
+ factor, the next reorganization will happen when a new item is
+ added to the hash table. */
+void
+hurd_ihash_set_max_load (hurd_ihash_t ht, unsigned int max_load)
+{
+ ht->max_load = max_load;
+}
- if (locp)
- *locp = &ht->tab[h];
+
+/* Helper function for hurd_ihash_add. Return 1 if the item was
+ added, and 0 if it could not be added because no empty slot was
+ found. The arguments are identical to hurd_ihash_add.
- return 0;
+ We are using open address hashing. As the hash function we use the
+ division method with quadratic probe. This is guaranteed to try
+ all slots in the hash table if the prime number is 3 mod 4. */
+static inline int
+add_one (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t value)
+{
+ unsigned int idx;
+ unsigned int first_free;
+
+ idx = key % ht->size;
+ first_free = idx;
+
+ if (ht->items[idx].value != _HURD_IHASH_EMPTY && ht->items[idx].key != key)
+ {
+ /* Instead of calculating idx + 1, idx + 4, idx + 9, ..., idx +
+ i^2, we add 1, 3, 5, 7, ... 2 * i - 1 to the previous index.
+ We do this in both directions separately. */
+ unsigned int i = 1;
+ unsigned int up_idx = idx;
+ unsigned int down_idx = idx;
+
+ do
+ {
+ up_idx = (up_idx + i) % ht->size;
+ if (ht->items[up_idx].value == _HURD_IHASH_EMPTY
+ || ht->items[up_idx].key == key)
+ {
+ idx = up_idx;
+ break;
+ }
+ if (first_free == idx
+ && ht->items[up_idx].value == _HURD_IHASH_DELETED)
+ first_free = up_idx;
+
+ if (down_idx < i)
+ down_idx += ht->size;
+ down_idx = (down_idx - i) % ht->size;
+ if (down_idx < 0)
+ down_idx += ht->size;
+ else
+ down_idx %= ht->size;
+ if (ht->items[down_idx].value == _HURD_IHASH_EMPTY
+ || ht->items[down_idx].key == key)
+ {
+ idx = down_idx;
+ break;
+ }
+ if (first_free == idx
+ && ht->items[down_idx].value == _HURD_IHASH_DELETED)
+ first_free = down_idx;
+
+ /* After (ht->size - 1) / 2 iterations, this will be 0. */
+ i = (i + 2) % ht->size;
}
+ while (i);
}
- {
- int i;
- void **entry;
- int old_size = ht->size;
- void **old_tab = ht->tab;
- void ****old_locps = ht->locps;
- int *old_ids = ht->ids;
-
- ht->size = _ihash_nextprime (2 * old_size);
- ht->tab = malloc(ht->size * sizeof (void *));
- ht->locps = malloc (ht->size * sizeof (void ***));
- ht->ids = malloc (ht->size * sizeof (int));
-
- if (ht->tab == NULL || ht->locps == NULL || ht->ids == NULL)
- /* Memory allocation error; back out our changes and fail... */
- {
- if (ht->tab) free(ht->tab);
- if (ht->locps) free(ht->locps);
- if (ht->ids) free(ht->ids);
+ /* Remove the old entry for this key if necessary. */
+ if (index_valid (ht, idx, key))
+ locp_remove (ht, &ht->items[idx].value);
- ht->size = old_size;
- ht->tab = old_tab;
- ht->locps = old_locps;
- ht->ids = old_ids;
+ /* If we have not found an empty slot, maybe the last one we
+ looked at was empty (or just got deleted). */
+ if (!index_empty (ht, first_free))
+ first_free = idx;
+
+ if (index_empty (ht, first_free))
+ {
+ ht->nr_items++;
+ ht->items[first_free].value = value;
+ ht->items[first_free].key = key;
- return ENOMEM;
- }
+ if (ht->locp_offset != HURD_IHASH_NO_LOCP)
+ *((hurd_ihash_locp_t *) (((char *) value) + ht->locp_offset))
+ = &ht->items[first_free].value;
- for (i = ht->size, entry = ht->tab; i > 0; i--, entry++)
- *entry = HASH_EMPTY;
+ return 1;
+ }
- /* We have to rehash this again? */
- if (old_size > 0)
- for (i = 0; i < old_size; i++)
- if (old_tab[i] != HASH_EMPTY && old_tab[i] != HASH_DEL)
- ihash_add(ht, old_ids[i], old_tab[i], old_locps[i]);
+ return 0;
+}
- /* Finally add the new element! */
- ihash_add(ht, id, item, locp);
- if (old_size > 0)
+/* Add ITEM to the hash table HT under the key KEY. If there already
+ is an item under this key, call the cleanup function (if any) for
+ it before overriding the value. If a memory allocation error
+ occurs, ENOMEM is returned, otherwise 0. */
+error_t
+hurd_ihash_add (hurd_ihash_t ht, hurd_ihash_key_t key, hurd_ihash_value_t item)
+{
+ struct hurd_ihash old_ht = *ht;
+ int was_added;
+ int i;
+
+ if (ht->size)
+ {
+ /* Only fill the hash table up to its maximum load factor. */
+ if (ht->nr_items * 100 / ht->size <= ht->max_load)
+ if (add_one (ht, key, item))
+ return 0;
+ }
+
+ /* The hash table is too small, and we have to increase it. */
+ for (i = 0; i < ihash_nsizes; i++)
+ if (ihash_sizes[i] > old_ht.size)
+ break;
+ if (i == ihash_nsizes
+ || ihash_sizes[i] > SIZE_MAX / sizeof (struct _hurd_ihash_item))
+ return ENOMEM; /* Surely will be true momentarily. */
+
+ ht->nr_items = 0;
+ ht->size = ihash_sizes[i];
+ /* calloc() will initialize all values to _HURD_IHASH_EMPTY implicitely. */
+ ht->items = calloc (ht->size, sizeof (struct _hurd_ihash_item));
+
+ if (ht->items == NULL)
+ {
+ if (ht->items)
+ free(ht->items);
+
+ *ht = old_ht;
+ return ENOMEM;
+ }
+
+ /* We have to rehash the old entries. */
+ for (i = 0; i < old_ht.size; i++)
+ if (!index_empty (&old_ht, i))
{
- free(old_tab);
- free(old_locps);
- free(old_ids);
+ was_added = add_one (ht, old_ht.items[i].key, old_ht.items[i].value);
+ assert (was_added);
}
- return 0;
- }
+ /* Finally add the new element! */
+ was_added = add_one (ht, key, item);
+ assert (was_added);
+
+ if (old_ht.size > 0)
+ free (old_ht.items);
+
+ return 0;
}
-/* Find and return the item in hash table HT with key ID, or NULL if it
- doesn't exist. */
-void *
-ihash_find (ihash_t ht, int id)
+
+/* Find and return the item in the hash table HT with key KEY, or NULL
+ if it doesn't exist. */
+hurd_ihash_value_t
+hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key)
{
if (ht->size == 0)
- return 0;
+ return NULL;
else
{
- int index = find_index(ht, id);
- return index_valid(ht, index, id) ? ht->tab[index] : 0;
+ int idx = find_index (ht, key);
+ return index_valid (ht, idx, key) ? ht->items[idx].value : NULL;
}
}
-
-/* ---------------------------------------------------------------- */
-/* Call function FUN of one arg for each element of HT. FUN's only arg is a
- pointer to the value stored in the hash table. If FUN ever returns
- non-zero, then iteration stops and ihash_iterate returns that value,
- otherwise it (eventually) returns 0. */
-error_t
-ihash_iterate(ihash_t ht, error_t (*fun)(void *))
+
+/* Remove the entry with the key KEY from the hash table HT. If such
+ an entry was found and removed, 1 is returned, otherwise 0. */
+int
+hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key_t key)
{
- int i;
- for (i = 0; i < ht->size; i++)
- if (!index_empty(ht, i))
- {
- error_t err = fun(ht->tab[i]);
- if (err)
- return err;
- }
+ if (ht->size != 0)
+ {
+ int idx = find_index (ht, key);
+
+ if (index_valid (ht, idx, key))
+ {
+ locp_remove (ht, &ht->items[idx].value);
+ return 1;
+ }
+ }
+
return 0;
}
-/* Remove the entry at LOCP from the hashtable HT. LOCP is as returned from
- an earlier call to ihash_add(). This call should be faster than
- ihash_remove(). HT can be NULL, in which case the call still succeeds,
- but no cleanup can be done. */
-void
-ihash_locp_remove(ihash_t ht, void **locp)
-{
- if (ht && ht->cleanup)
- ht->cleanup(*locp, ht->cleanup_arg);
- *locp = HASH_DEL;
-}
-/* Remove the entry with a key of ID from HT. If anything was actually
- removed, 1 is returned, otherwise (if there was no such element), 0. */
-int
-ihash_remove(ihash_t ht, int id)
+/* Remove the entry pointed to by the location pointer LOCP from the
+ hashtable HT. LOCP is the location pointer of which the address
+ was provided to hurd_ihash_add(). This call is faster than
+ hurd_ihash_remove(). */
+void
+hurd_ihash_locp_remove (hurd_ihash_t ht, hurd_ihash_locp_t locp)
{
- int index = find_index(ht, id);
- if (index_valid(ht, index, id))
- {
- ihash_locp_remove(ht, &ht->tab[index]);
- return 1;
- }
- else
- return 0;
+ locp_remove (ht, locp);
}
diff --git a/libihash/ihash.h b/libihash/ihash.h
index 5d01ea1c..a4e76dc4 100644
--- a/libihash/ihash.h
+++ b/libihash/ihash.h
@@ -1,97 +1,231 @@
-/* Integer-keyed hash table functions.
+/* ihash.h - Integer keyed hash table interface.
+ Copyright (C) 1995, 2003, 2004 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>.
+ Revised by Marcus Brinkmann <marcus@gnu.org>.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ This file is part of the GNU Hurd.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This program is free software; you can redistribute it and/or
+ The GNU Hurd is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
- This program is distributed in the hope that it will be useful, but
+ The GNU Hurd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ along with the GNU Hurd; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#ifndef __IHASH_H__
-#define __IHASH_H__
+#ifndef _HURD_IHASH_H
+#define _HURD_IHASH_H 1
#include <errno.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
-/* ---------------------------------------------------------------- */
+/* The type of the values corresponding to the keys. Must be a
+ pointer type. The values (hurd_ihash_value_t) 0 and
+ (hurd_ihash_value_t) ~0 are reserved for the implementation. */
+typedef void *hurd_ihash_value_t;
+
+/* When an value entry in the hash table is _HURD_IHASH_EMPTY or
+ _HURD_IHASH_DELETED, then the location is available, and none of
+ the other members of the item are valid at that index. The
+ difference is that searches continue though _HURD_IHASH_DELETED,
+ but stop at _HURD_IHASH_EMPTY. */
+#define _HURD_IHASH_EMPTY ((hurd_ihash_value_t) 0)
+#define _HURD_IHASH_DELETED ((hurd_ihash_value_t) -1)
+
+/* The type of integer we want to use for the keys. */
+typedef uintptr_t hurd_ihash_key_t;
+
+/* The type of a location pointer, which is a pointer to the hash
+ value stored in the hash table. */
+typedef hurd_ihash_value_t *hurd_ihash_locp_t;
-typedef struct ihash *ihash_t;
+
+/* The type of the cleanup function, which is called for every value
+ removed from the hash table. */
+typedef void (*hurd_ihash_cleanup_t) (hurd_ihash_value_t value, void *arg);
-struct ihash
+
+struct _hurd_ihash_item
{
- /* An array storing the elements in the hash table (each a void *). */
- void **tab;
+ /* The value of this hash item. Must be the first element of
+ the struct for the HURD_IHASH_ITERATE macro. */
+ hurd_ihash_value_t value;
- /* An array storing the integer key for each element. */
- int *ids;
+ /* The integer key of this hash item. */
+ hurd_ihash_key_t key;
+};
+typedef struct _hurd_ihash_item *_hurd_ihash_item_t;
- /* An array storing pointers to the `location pointers' for each element.
- These are used as cookies for quick 'n' easy removal. */
- void ****locps; /* four, count them, four stars */
+struct hurd_ihash
+{
+ /* The number of hashed elements. */
+ size_t nr_items;
- /* The length of all these arrays. */
- int size;
+ /* An array of (key, value) pairs. */
+ _hurd_ihash_item_t items;
- /* When freeing or overwriting an element, this function, if non-NULL, is
- called with the value as the first argument, and CLEANUP_ARG as the
- second argument. */
- void (*cleanup)(void *element, void *arg);
- void *cleanup_arg;
-};
+ /* The length of the array ITEMS. */
+ size_t size;
-/* Create an integer hash table and return it in HT. If a memory allocation
- error occurs, ENOMEM is returned, otherwise 0. */
-error_t ihash_create(ihash_t *ht);
-
-/* Free HT and all resources it consumes. */
-void ihash_free(ihash_t ht);
-
-/* Sets HT's element cleanup function to CLEANUP, and its second argument to
- ARG. CLEANUP will be called on the value of any element to be
- subsequently overwritten or deleted, with ARG as the second argument. */
-void ihash_set_cleanup(ihash_t ht,
- void (*cleanup)(void *value, void *arg),
- void *arg);
-
-/* Add ITEM to the hash table HT under the key ID. LOCP is the address of a
- pointer located in ITEM; If non-NULL, LOCP should point to a variable of
- type void **, and will be filled with a pointer that may be used as an
- argument to ihash_locp_remove() [the variable pointed to by LOCP may be
- written to subsequently between this call and when the element is
- deleted, so you can't stash its value elsewhere and hope to use the
- stashed value with ihash_locp_remove()]. If a memory allocation error
- occurs, ENOMEM is returned, otherwise 0. */
-error_t ihash_add(ihash_t ht, int id, void *item, void ***locp);
+ /* The offset of the location pointer from the hash value. */
+ intptr_t locp_offset;
-/* Find and return the item in hash table HT with key ID, or NULL if it
- doesn't exist. */
-void *ihash_find(ihash_t ht, int id);
+ /* The maximum load factor in percent. */
+ int max_load;
-/* Call function FUN of one arg for each element of HT. FUN's only arg is a
- pointer to the value stored in the hash table. If FUN ever returns
- non-zero, then iteration stops and ihash_iterate returns that value,
- otherwise it (eventually) returns 0. */
-error_t ihash_iterate(ihash_t ht, error_t (*fun)(void *));
+ /* When freeing or overwriting an element, this function is called
+ with the value as the first argument, and CLEANUP_DATA as the
+ second argument. This does not happen if CLEANUP is NULL. */
+ hurd_ihash_cleanup_t cleanup;
+ void *cleanup_data;
+};
+typedef struct hurd_ihash *hurd_ihash_t;
-/* Remove the entry with a key of ID from HT. If anything was actually
- removed, 1 is returned, otherwise (if there was no such element), 0. */
-int ihash_remove(ihash_t ht, int id);
+
+/* Construction and destruction of hash tables. */
+
+/* The default value for the maximum load factor in percent. */
+#define HURD_IHASH_MAX_LOAD_DEFAULT 80
+
+/* The LOCP_OFFS to use if no location pointer is available. */
+#define HURD_IHASH_NO_LOCP INTPTR_MIN
+
+/* The static initializer for a struct hurd_ihash. */
+#define HURD_IHASH_INITIALIZER(locp_offs) \
+ { .nr_items = 0, .size = 0, .cleanup = (hurd_ihash_cleanup_t) 0, \
+ .max_load = HURD_IHASH_MAX_LOAD_DEFAULT, \
+ .locp_offset = (locp_offs)}
+
+/* Initialize the hash table at address HT. If LOCP_OFFSET is not
+ HURD_IHASH_NO_LOCP, then this is an offset (in bytes) from the
+ address of a hash value where a location pointer can be found. The
+ location pointer must be of type hurd_ihash_locp_t and can be used
+ for fast removal with hurd_ihash_locp_remove(). */
+void hurd_ihash_init (hurd_ihash_t ht, intptr_t locp_offs);
+
+/* Destroy the hash table at address HT. This first removes all
+ elements which are still in the hash table, and calling the cleanup
+ function for them (if any). */
+void hurd_ihash_destroy (hurd_ihash_t ht);
+
+/* Create a hash table, initialize it and return it in HT. If
+ LOCP_OFFSET is not HURD_IHASH_NO_LOCP, then this is an offset (in
+ bytes) from the address of a hash value where a location pointer
+ can be found. The location pointer must be of type
+ hurd_ihash_locp_t and can be used for fast removal with
+ hurd_ihash_locp_remove(). If a memory allocation error occurs,
+ ENOMEM is returned, otherwise 0. */
+error_t hurd_ihash_create (hurd_ihash_t *ht, intptr_t locp_offs);
+
+/* Destroy the hash table HT and release the memory allocated for it
+ by hurd_ihash_create(). */
+void hurd_ihash_free (hurd_ihash_t ht);
-/* Remove the entry at LOCP from the hashtable HT. LOCP is as returned from
- an earlier call to ihash_add(). This call should be faster than
- ihash_remove(). HT can be NULL, in which case the call still succeeds,
- but no cleanup can be done. */
-void ihash_locp_remove(ihash_t ht, void **ht_locp);
+
+/* Configuration of the hash table. */
+
+/* Set the cleanup function for the hash table HT to CLEANUP. The
+ second argument to CLEANUP will be CLEANUP_DATA on every
+ invocation. */
+void hurd_ihash_set_cleanup (hurd_ihash_t ht, hurd_ihash_cleanup_t cleanup,
+ void *cleanup_data);
+
+/* Set the maximum load factor in percent to MAX_LOAD, which should be
+ between 50 and 100. The default is HURD_IHASH_MAX_LOAD_DEFAULT.
+ New elements are only added to the hash table while the number of
+ hashed elements is that much percent of the total size of the hash
+ table. If more elements are added, the hash table is first
+ expanded and reorganized. A MAX_LOAD of 100 will always fill the
+ whole table before enlarging it, but note that this will increase
+ the cost of operations significantly when the table is almost full.
+
+ If the value is set to a smaller value than the current load
+ factor, the next reorganization will happen when a new item is
+ added to the hash table. */
+void hurd_ihash_set_max_load (hurd_ihash_t ht, unsigned int max_load);
-#endif /* __IHASH_H__ */
+
+/* Add ITEM to the hash table HT under the key KEY. If there already
+ is an item under this key, call the cleanup function (if any) for
+ it before overriding the value. If a memory allocation error
+ occurs, ENOMEM is returned, otherwise 0. */
+error_t hurd_ihash_add (hurd_ihash_t ht, hurd_ihash_key_t key,
+ hurd_ihash_value_t item);
+
+/* Find and return the item in the hash table HT with key KEY, or NULL
+ if it doesn't exist. */
+hurd_ihash_value_t hurd_ihash_find (hurd_ihash_t ht, hurd_ihash_key_t key);
+
+/* Iterate over all elements in the hash table. You use this macro
+ with a block, for example like this:
+
+ error_t err;
+ HURD_IHASH_ITERATE (ht, value)
+ {
+ err = foo (value);
+ if (err)
+ break;
+ }
+ if (err)
+ cleanup_and_return ();
+
+ Or even like this:
+
+ HURD_IHASH_ITERATE (ht, value)
+ foo (value);
+
+ The block will be run for every element in the hash table HT. The
+ value of the current element is available in the variable VALUE
+ (which is declared for you and local to the block). */
+
+/* The implementation of this macro is peculiar. We want the macro to
+ execute a block following its invocation, so we can only prepend
+ code. This excludes creating an outer block. However, we must
+ define two variables: The hash value variable VALUE, and the loop
+ variable.
+
+ We can define variables inside the for-loop initializer (C99), but
+ we can only use one basic type to do that. We can not use two
+ for-loops, because we want a break statement inside the iterator
+ block to terminate the operation. So we must have both variables
+ of the same basic type, but we can make one (or both) of them a
+ pointer type.
+
+ The pointer to the value can be used as the loop variable. This is
+ also the first element of the hash item, so we can cast the pointer
+ freely between these two types. The pointer is only dereferenced
+ after the loop condition is checked (but of course the value the
+ pointer pointed to must not have an influence on the condition
+ result, so the comma operator is used to make sure this
+ subexpression is always true). */
+#define HURD_IHASH_ITERATE(ht, val) \
+ for (hurd_ihash_value_t val, \
+ *_hurd_ihash_valuep = (ht)->size ? &(ht)->items[0].value : 0; \
+ (ht)->size \
+ && ((_hurd_ihash_item_t) _hurd_ihash_valuep) - &(ht)->items[0] \
+ < (ht)->size \
+ && (val = *_hurd_ihash_valuep, 1); \
+ _hurd_ihash_valuep = (hurd_ihash_value_t *) \
+ (((_hurd_ihash_item_t) _hurd_ihash_valuep) + 1)) \
+ if (val != _HURD_IHASH_EMPTY && val != _HURD_IHASH_DELETED)
+
+/* Remove the entry with the key KEY from the hash table HT. If such
+ an entry was found and removed, 1 is returned, otherwise 0. */
+int hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key_t key);
+
+/* Remove the entry pointed to by the location pointer LOCP from the
+ hash table HT. LOCP is the location pointer of which the address
+ was provided to hurd_ihash_add(). This call is faster than
+ hurd_ihash_remove(). */
+void hurd_ihash_locp_remove (hurd_ihash_t ht, hurd_ihash_locp_t locp);
+
+#endif /* _HURD_IHASH_H */
diff --git a/libihash/primes.c b/libihash/primes.c
deleted file mode 100644
index 3abc6f9d..00000000
--- a/libihash/primes.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* Prime number generation
- Copyright (C) 1994, 1996 Free Software Foundation
-
- 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. */
-
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <assert.h>
-#include <spin-lock.h>
-#include "priv.h"
-
-#define BITS_PER_UNSIGNED (8 * sizeof (unsigned))
-#define SQRT_INT_MAX (1 << (BITS_PER_UNSIGNED / 2))
-
-static spin_lock_t table_lock = SPIN_LOCK_INITIALIZER;
-
-/* Return the next prime greater than or equal to N. */
-int
-_ihash_nextprime (unsigned n)
-{
- /* Among other things, We guarantee that, for all i (0 <= i < primes_len),
- primes[i] is a prime,
- next_multiple[i] is a multiple of primes[i],
- next_multiple[i] > primes[primes_len - 1],
- next_multiple[i] is not a multiple of two unless primes[i] == 2, and
- next_multiple[i] is the smallest such value. */
- static unsigned *primes, *next_multiple;
- static int primes_len;
- static int primes_size;
- static unsigned next_sieve; /* always even */
- unsigned max_prime;
-
- spin_lock (&table_lock);
-
- if (! primes)
- {
- primes_size = 128;
- primes = (unsigned *) malloc (primes_size * sizeof (*primes));
- next_multiple = (unsigned *) malloc (primes_size
- * sizeof (*next_multiple));
-
- primes[0] = 2; next_multiple[0] = 6;
- primes[1] = 3; next_multiple[1] = 9;
- primes[2] = 5; next_multiple[2] = 15;
- primes_len = 3;
-
- next_sieve = primes[primes_len - 1] + 1;
- }
-
- if (n <= primes[0])
- {
- spin_unlock (&table_lock);
- return primes[0];
- }
-
- while (n > (max_prime = primes[primes_len - 1]))
- {
- /* primes doesn't contain any prime large enough. Sieve from
- max_prime + 1 to 2 * max_prime, looking for more primes. */
- unsigned start = next_sieve;
- unsigned end = start + max_prime + 1;
- char *sieve = (char *) alloca ((end - start) * sizeof (*sieve));
- int i;
-
- assert (sieve);
-
- bzero (sieve, (end - start) * sizeof (*sieve));
-
- /* Make the sieve indexed by prime number, rather than
- distance-from-start-to-the-prime-number. When we're done,
- sieve[P] will be zero iff P is prime.
-
- ANSI C doesn't define what this means. Fuck them. */
- sieve -= start;
-
- /* Set sieve[i] for all composites i, start <= i < end.
- Ignore multiples of 2. */
- for (i = 1; i < primes_len; i++)
- {
- unsigned twice_prime = 2 * primes[i];
- unsigned multiple;
-
- for (multiple = next_multiple[i];
- multiple < end;
- multiple += twice_prime)
- sieve[multiple] = 1;
- next_multiple[i] = multiple;
- }
-
- for (i = start + 1; i < end; i += 2)
- if (! sieve[i])
- {
- if (primes_len >= primes_size)
- {
- primes_size *= 2;
- primes = (int *) realloc (primes,
- primes_size * sizeof (*primes));
- next_multiple
- = (int *) realloc (next_multiple,
- primes_size * sizeof (*next_multiple));
- }
- primes[primes_len] = i;
- if (i >= SQRT_INT_MAX)
- next_multiple[primes_len] = INT_MAX;
- else
- next_multiple[primes_len] = i * i;
- primes_len++;
- }
-
- next_sieve = end;
- }
-
- /* Now we have at least one prime >= n. Find the smallest such. */
- {
- int bottom = 0;
- int top = primes_len;
-
- while (bottom < top)
- {
- int mid = (bottom + top) / 2;
-
- if (primes[mid] < n)
- bottom = mid + 1;
- else
- top = mid;
- }
-
- spin_unlock (&table_lock);
- return primes[top];
- }
-}
-
diff --git a/libiohelp/ChangeLog b/libiohelp/ChangeLog
deleted file mode 100644
index b890e9a8..00000000
--- a/libiohelp/ChangeLog
+++ /dev/null
@@ -1,37 +0,0 @@
-Thu May 9 12:42:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile: All occurrences of `ioserver' replaced with `iohelp'.
-
-Mon May 6 16:27:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * iohelp.h: Renamed from `ioserver.h'. All local includes
- updated.
- * get_conch.c: All occurrences of `ioserver' replaced with
- `iohelp'.
- * handle_io_get_conch.c: Likewise.
- * handle_io_release_conch.c: Likewise.
- * initialize_conch.c: Likewise.
- * verify_user_conch.c: Likewise.
- * iohelp.h: Likewise.
-
-Mon Oct 9 14:57:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile: Specify shared library dependencies.
-
-Thu Jul 6 15:35:56 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Fri Jul 22 11:43:56 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Converted to new scheme.
-
-Tue Jul 5 14:13:09 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (TAGSHDRS): New variable.
-
-Thu May 5 07:48:45 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
diff --git a/libiohelp/Makefile b/libiohelp/Makefile
index 9dfc8ca4..ba73282b 100644
--- a/libiohelp/Makefile
+++ b/libiohelp/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+# Copyright (C) 1993, 1994, 1995, 1996, 1998, 2002, 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
@@ -19,13 +19,13 @@ dir := libiohelp
makemode := library
SRCS = get_conch.c handle_io_get_conch.c handle_io_release_conch.c \
- initialize_conch.c verify_user_conch.c
-OBJS = get_conch.o handle_io_get_conch.o handle_io_release_conch.o \
- initialize_conch.o verify_user_conch.o
-LCLHDRS = iohelp.h
+ initialize_conch.c verify_user_conch.c iouser-create.c \
+ iouser-dup.c iouser-reauth.c iouser-free.c iouser-restrict.c \
+ shared.c return-buffer.c
+OBJS = $(SRCS:.c=.o)
+LCLHDRS = iohelp.h
+HURDLIBS = threads shouldbeinlibc
libname = libiohelp
installhdrs = iohelp.h
include ../Makeconf
-
-libfshelp.so: ../libthreads/libthreads.so
diff --git a/libiohelp/handle_io_release_conch.c b/libiohelp/handle_io_release_conch.c
index fa95a6e5..8a6bd32d 100644
--- a/libiohelp/handle_io_release_conch.c
+++ b/libiohelp/handle_io_release_conch.c
@@ -23,13 +23,16 @@
void
iohelp_handle_io_release_conch (struct conch *c, void *user)
{
-
+ struct shared_io *user_sh = c->holder_shared_page;
+
+ spin_lock (&user_sh->lock);
if (c->holder_shared_page->conch_status != USER_HAS_NOT_CONCH)
{
c->holder_shared_page->conch_status = USER_HAS_NOT_CONCH;
iohelp_fetch_shared_data (c->holder);
}
-
+ spin_unlock (&user_sh->lock);
+
if (c->holder == user)
{
c->holder = 0;
diff --git a/libiohelp/iohelp.h b/libiohelp/iohelp.h
index 2897653d..a52d5985 100644
--- a/libiohelp/iohelp.h
+++ b/libiohelp/iohelp.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1993, 1994, 1996 Free Software Foundation
+/* Library providing helper functions for io servers.
+ Copyright (C) 1993,94,96,98,2001,02 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
@@ -64,4 +64,70 @@ void iohelp_fetch_shared_data (void *);
void iohelp_put_shared_data (void *);
+
+/* User identification */
+
+#include <idvec.h>
+
+struct iouser
+{
+ struct idvec *uids, *gids;
+ void *hook; /* Never used by iohelp library */
+};
+
+/* Return a copy of IOUSER in CLONE. On error, *CLONE is set to NULL. */
+error_t iohelp_dup_iouser (struct iouser **clone, struct iouser *iouser);
+
+/* Free a reference to IOUSER. */
+void iohelp_free_iouser (struct iouser *iouser);
+
+/* Create a new IOUSER in USER for the specified idvecs. On error, *USER
+ is set to NULL. */
+error_t iohelp_create_iouser (struct iouser **user, struct idvec *uids,
+ struct idvec *gids);
+
+/* Create a new IOUSER in USER for the specified arrays. On error, *USER
+ is set to NULL. */
+error_t iohelp_create_complex_iouser (struct iouser **user,
+ const uid_t *uids, int nuids,
+ const gid_t *gids, int ngids);
+
+/* Create a new IOUSER in USER for the specified uid and gid. On error,
+ *USER is set to NULL. */
+error_t iohelp_create_simple_iouser (struct iouser **user,
+ uid_t uid, gid_t gid);
+
+/* Create a new IOUSER in USER with no identity. On error, *USER is set
+ to NULL. */
+error_t iohelp_create_empty_iouser (struct iouser **user);
+
+/* Create a new IOUSER in NEW_USER that restricts OLD_USER to the subset
+ specified by the two ID lists. This is appropriate for implementing
+ io_restrict_auth. */
+error_t iohelp_restrict_iouser (struct iouser **new_user,
+ const struct iouser *old_user,
+ const uid_t *uids, int nuids,
+ const gid_t *gids, int ngids);
+
+/* Conduct a reauthentication transaction, returning a new iouser in
+ USER. AUTHSERVER is the I/O servers auth port. The rendezvous port
+ provided by the user is REND_PORT. If the transaction cannot be
+ completed, return zero, unless PERMIT_FAILURE is non-zero. If
+ PERMIT_FAILURE is nonzero, then should the transaction fail, return
+ an iouser that has no ids. The new port to be sent to the user is
+ newright. On error, *USER is set to NULL. */
+error_t iohelp_reauth (struct iouser **user, auth_t authserver,
+ mach_port_t rend_port, mach_port_t newright,
+ int permit_failure);
+
+
+/* Puts data from the malloced buffer BUF, LEN bytes long, into RBUF & RLEN,
+ suitable for returning from a mach rpc. If LEN > 0, BUF is freed,
+ regardless of whether an error is returned or not. */
+error_t iohelp_return_malloced_buffer (char *buf, size_t len,
+ char **rbuf,
+ mach_msg_type_number_t *rlen);
+
+
+
#endif
diff --git a/libiohelp/iouser-create.c b/libiohelp/iouser-create.c
new file mode 100644
index 00000000..f1dd2f0e
--- /dev/null
+++ b/libiohelp/iouser-create.c
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 1996,2001,02 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. */
+
+#include "iohelp.h"
+
+error_t
+iohelp_create_iouser (struct iouser **user, struct idvec *uids,
+ struct idvec *gids)
+{
+ struct iouser *new;
+ *user = new = malloc (sizeof (struct iouser));
+ if (!new)
+ return ENOMEM;
+
+ new->uids = uids;
+ new->gids = gids;
+ new->hook = 0;
+
+ return 0;
+}
+
+#define E(err) \
+ do { \
+ if (err) \
+ { \
+ *user = 0; \
+ if (! uids) \
+ return err; \
+ idvec_free (uids); \
+ if (! gids) \
+ return err; \
+ idvec_free (gids); \
+ return err; \
+ } \
+ } while (0)
+
+error_t
+iohelp_create_empty_iouser (struct iouser **user)
+{
+ struct idvec *uids, *gids;
+
+ uids = make_idvec ();
+ if (! uids)
+ E (ENOMEM);
+
+ gids = make_idvec ();
+ if (! gids)
+ E (ENOMEM);
+
+ E (iohelp_create_iouser (user, uids, gids));
+
+ return 0;
+}
+
+error_t
+iohelp_create_simple_iouser (struct iouser **user, uid_t uid, gid_t gid)
+{
+ struct idvec *uids, *gids;
+
+ uids = make_idvec ();
+ if (! uids)
+ E (ENOMEM);
+
+ gids = make_idvec ();
+ if (! gids)
+ E (ENOMEM);
+
+ E (idvec_add (uids, uid));
+ E (idvec_add (gids, gid));
+
+ E (iohelp_create_iouser (user, uids, gids));
+
+ return 0;
+}
+
+error_t
+iohelp_create_complex_iouser (struct iouser **user,
+ const uid_t *uvec, int nuids,
+ const gid_t *gvec, int ngids)
+{
+ struct idvec *uids, *gids;
+
+ uids = make_idvec ();
+ if (! uids)
+ E (ENOMEM);
+
+ gids = make_idvec ();
+ if (! gids)
+ E (ENOMEM);
+
+ E (idvec_set_ids (uids, uvec, nuids));
+ E (idvec_set_ids (gids, gvec, ngids));
+
+ E (iohelp_create_iouser (user, uids, gids));
+
+ return 0;
+}
diff --git a/libdiskfs/notify-nosenders.c b/libiohelp/iouser-dup.c
index 7e6a504f..9158d0c4 100644
--- a/libdiskfs/notify-nosenders.c
+++ b/libiohelp/iouser-dup.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1996,2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,25 +15,42 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "priv.h"
-#include <hurd/pager.h>
+#include "iohelp.h"
-/* Called by the kernel when a port has no more senders. We arrange
- to have this sent to the port which is out of senders (NOTIFY). MSCOUNT
- is the make-send count of the port when the notification was generated;
- SEQNO is the sequence number of the message dequeue. */
error_t
-diskfs_do_seqnos_mach_notify_no_senders (mach_port_t notify,
- mach_port_seqno_t seqno __attribute__ ((unused)),
- mach_port_mscount_t mscount)
+iohelp_dup_iouser (struct iouser **clone, struct iouser *iouser)
{
- struct port_info *pt;
+ struct iouser *new;
+ error_t err = 0;
+
+ *clone = new = malloc (sizeof (struct iouser));
+ if (!new)
+ return ENOMEM;
+
+ new->uids = make_idvec ();
+ new->gids = make_idvec ();
+ new->hook = 0;
+ if (!new->uids || !new->gids)
+ {
+ err = ENOMEM;
+ goto lose;
+ }
+
+ err = idvec_set (new->uids, iouser->uids);
+ if (!err)
+ err = idvec_set (new->gids, iouser->gids);
+
+ if (err)
+ {
+ lose:
+ if (new->uids)
+ idvec_free (new->uids);
+ if (new->gids)
+ idvec_free (new->gids);
+ free (new);
+ *clone = 0;
+ return err;
+ }
- pt = ports_lookup_port (diskfs_port_bucket, notify, 0);
-
- ports_no_senders (pt, mscount);
-
- ports_port_deref (pt);
-
return 0;
}
diff --git a/libdiskfs/ports-soft.c b/libiohelp/iouser-free.c
index 11ff1379..4cfdc954 100644
--- a/libdiskfs/ports-soft.c
+++ b/libiohelp/iouser-free.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1996 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,11 +15,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "priv.h"
+#include "iohelp.h"
-/* Called by ports library when there are only soft ports left. */
void
-ports_no_hard_ports ()
+iohelp_free_iouser (struct iouser *iouser)
{
- diskfs_shutdown_soft_ports ();
+ idvec_free (iouser->uids);
+ idvec_free (iouser->gids);
+ free (iouser);
}
+
+
diff --git a/libiohelp/iouser-reauth.c b/libiohelp/iouser-reauth.c
new file mode 100644
index 00000000..4125cfb8
--- /dev/null
+++ b/libiohelp/iouser-reauth.c
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 1996,99,2001,02 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. */
+
+#include "iohelp.h"
+#include <hurd/auth.h>
+#include <sys/mman.h>
+
+/* Conduct a reauthentication transaction, returning a new iouser.
+ AUTHSERVER is the I/O servers auth port. The rendezvous port
+ provided by the user is REND_PORT. If the transaction cannot be
+ completed, return zero, unless PERMIT_FAILURE is non-zero. If
+ PERMIT_FAILURE is nonzero, then should the transaction fail, return
+ an iouser that has no ids. The new port to be sent to the user is
+ newright. */
+error_t iohelp_reauth (struct iouser **user,
+ auth_t authserver, mach_port_t rend_port,
+ mach_port_t newright, int permit_failure)
+{
+ uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
+ uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
+ size_t genuidlen, gengidlen, auxuidlen, auxgidlen;
+ error_t err;
+ struct iouser *new;
+
+ *user = new = malloc (sizeof (struct iouser));
+ if (!new)
+ return ENOMEM;
+
+ new->uids = make_idvec ();
+ new->gids = make_idvec ();
+ if (!new->uids || !new->gids)
+ {
+ if (new->uids)
+ idvec_free (new->uids);
+ if (new->gids)
+ idvec_free (new->gids);
+ free (new);
+ return ENOMEM;
+ }
+
+ genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
+ gen_uids = gubuf;
+ gen_gids = ggbuf;
+ aux_uids = aubuf;
+ aux_gids = agbuf;
+
+ do
+ err = auth_server_authenticate (authserver,
+ rend_port,
+ MACH_MSG_TYPE_COPY_SEND,
+ newright,
+ MACH_MSG_TYPE_COPY_SEND,
+ &gen_uids, &genuidlen,
+ &aux_uids, &auxuidlen,
+ &gen_gids, &gengidlen,
+ &aux_gids, &auxgidlen);
+ while (err == EINTR);
+
+ if (err)
+ {
+ if (permit_failure)
+ genuidlen = gengidlen = 0;
+ else
+ goto out;
+ }
+
+ err = idvec_set_ids (new->uids, gen_uids, genuidlen);
+ if (!err)
+ err = idvec_set_ids (new->gids, gen_gids, gengidlen);
+
+ if (gubuf != gen_uids)
+ munmap ((caddr_t) gen_uids, genuidlen * sizeof (uid_t));
+ if (ggbuf != gen_gids)
+ munmap ((caddr_t) gen_gids, gengidlen * sizeof (uid_t));
+ if (aubuf != aux_uids)
+ munmap ((caddr_t) aux_uids, auxuidlen * sizeof (uid_t));
+ if (agbuf != aux_gids)
+ munmap ((caddr_t) aux_gids, auxgidlen * sizeof (uid_t));
+
+ if (err)
+ {
+ out:
+ idvec_free (new->uids);
+ idvec_free (new->gids);
+ free (new);
+ *user = 0;
+ return err;
+ }
+
+ *user = new;
+ return 0;
+}
diff --git a/libiohelp/iouser-restrict.c b/libiohelp/iouser-restrict.c
new file mode 100644
index 00000000..853820ea
--- /dev/null
+++ b/libiohelp/iouser-restrict.c
@@ -0,0 +1,83 @@
+/* iohelp_restrict_iouser -- helper for io_restrict_auth implementations
+ Copyright (C) 2002 Free Software Foundation
+
+ 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. */
+
+#include "iohelp.h"
+
+/* Tell if the array LIST (of size N) contains a member equal to QUERY. */
+static inline int
+listmember (const uid_t *list, int query, int n)
+{
+ int i;
+ for (i = 0; i < n; i++)
+ if (list[i] == query)
+ return 1;
+ return 0;
+}
+
+error_t
+iohelp_restrict_iouser (struct iouser **new_user,
+ const struct iouser *old_user,
+ const uid_t *uids, int nuids,
+ const gid_t *gids, int ngids)
+{
+ if (idvec_contains (old_user->uids, 0))
+ /* OLD_USER has root access, and so may use any ids. */
+ return iohelp_create_complex_iouser (new_user, uids, nuids, gids, ngids);
+ else
+ {
+ struct idvec *uvec, *gvec;
+ int i;
+ error_t err;
+
+ uvec = make_idvec ();
+ if (! uvec)
+ return ENOMEM;
+
+ gvec = make_idvec ();
+ if (! gvec)
+ {
+ idvec_free (uvec);
+ return ENOMEM;
+ }
+
+ /* Otherwise, use any of the requested ids that OLD_USER already has. */
+ for (i = 0; i < old_user->uids->num; i++)
+ if (listmember (uids, old_user->uids->ids[i], nuids))
+ {
+ err = idvec_add (uvec, old_user->uids->ids[i]);
+ if (err)
+ goto out;
+ }
+ for (i = 0; i < old_user->gids->num; i++)
+ if (listmember (gids, old_user->gids->ids[i], ngids))
+ {
+ err = idvec_add (gvec, old_user->gids->ids[i]);
+ if (err)
+ goto out;
+ }
+
+ err = iohelp_create_iouser (new_user, uvec, gvec);
+
+ if (err)
+ {
+ out:
+ idvec_free (uvec);
+ idvec_free (gvec);
+ }
+ return err;
+ }
+}
diff --git a/libfshelp/return-buffer.c b/libiohelp/return-buffer.c
index 58c704f3..3095dfb6 100644
--- a/libfshelp/return-buffer.c
+++ b/libiohelp/return-buffer.c
@@ -1,8 +1,8 @@
/* Make a malloced buffer suitable for returning from a mach rpc
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998, 1999 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -22,20 +22,24 @@
#include <string.h>
#include <mach.h>
+#include <sys/mman.h>
-#include "fshelp.h"
+#include "iohelp.h"
/* Puts data from the malloced buffer BUF, LEN bytes long, into RBUF & RLEN,
suitable for returning from a mach rpc. If LEN > 0, BUF is freed,
regardless of whether an error is returned or not. */
error_t
-fshelp_return_malloced_buffer (char *buf, size_t len,
+iohelp_return_malloced_buffer (char *buf, size_t len,
char **rbuf, mach_msg_type_number_t *rlen)
{
error_t err = 0;
if (*rlen < len)
- err = vm_allocate (mach_task_self (), (vm_address_t *)rbuf, len, 1);
+ {
+ *rbuf = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = (*rbuf == (char *) -1) ? errno : 0;
+ }
if (! err)
{
if (len)
diff --git a/libdiskfs/io-interrupt.c b/libiohelp/shared.c
index 2d2e4c61..082b526b 100644
--- a/libdiskfs/io-interrupt.c
+++ b/libiohelp/shared.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/* Default functions
+ Copyright (C) 1996, 2002 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
@@ -15,15 +15,19 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "priv.h"
-#include "io_S.h"
-/* Implement io_interrupt as described in <hurd/io.defs>. */
-error_t
-S_io_interrupt (struct protid *cred)
+#include "iohelp.h"
+
+/* These definitions exist to satisfy the linker. */
+
+void __attribute__ ((weak))
+iohelp_fetch_shared_data (void *foo)
+{
+ abort ();
+}
+
+void __attribute__ ((weak))
+iohelp_put_shared_data (void *foo)
{
- if (!cred)
- return EOPNOTSUPP;
-
- return 0;
+ abort ();
}
diff --git a/libmom/ChangeLog b/libmom/ChangeLog
deleted file mode 100644
index f04006c5..00000000
--- a/libmom/ChangeLog
+++ /dev/null
@@ -1,31 +0,0 @@
-Sat May 25 17:25:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * refs-identical.c (mom_ports_identical): Omit uses of deleted
- members of struct mom_port_ref.c.
-
- * ref-destroy.c (mom_ref_destroy): Omit uses of deleted members of
- struct mom_port_ref.c.
-
- * mach-port-set.c (mom_mach_port_set): Omit uses of deleted
- members of struct mom_port_ref.c.
-
- * fetch-mach-port.c (mom_fetch_mach_port): Omit uses of deleted
- members of struct mom_port_ref.c.
-
- * copy-ref.c (mom_copy_ref): Likewise.
-
- * mom-kerndep.h (struct mom_port_ref): Delete members `lock' and
- `refcnt'.
- * Makefile (SRCS): Delete add-ref.c and drop-ref.c.
- * mom.h (mom_add_ref, mom_drop_ref): Delete functions.
- * add-ref.c, drop-ref.c: Delete files.
-
-Fri May 24 16:14:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mom.h: Include <mom-errors.h>.
- * error-trans.c: New file.
- * mom-kerndep.h (mom_error_translate_mach): New function.
- * Makefile (LCLHDRS, installhdrs): Add mom-errors.h.
- (SRCS): Add error-trans.c.
- * mom-errors.h: New file.
-
diff --git a/libmom/allocate-address.c b/libmom/allocate-address.c
deleted file mode 100644
index fa017bac..00000000
--- a/libmom/allocate-address.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-#include "priv.h"
-
-error_t
-mom_allocate_address (void *start, size_t len, int readonly,
- struct mom_port_ref *obj, size_t offset,
- int copy)
-{
- error_t err;
- mach_port_t port;
-
- assert ((vm_address_t) start % vm_page_size == 0);
- assert (len % vm_page_size == 0);
- if (obj)
- {
- port = mom_fetch_mach_port (obj);
- assert (offset % vm_page_size == 0);
- }
- else
- port = MACH_PORT_NULL;
-
- mutex_lock (&_mom_memory_lock);
- err = vm_map (mach_task_self (), (vm_address_t *)&start, len, 0, 0,
- port, (obj ? offset : 0), (obj ? copy : 0),
- (VM_PROT_READ | VM_PROT_EXECUTE
- | (!readonly ? VM_PROT_WRITE : 0)),
- VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE,
- VM_INHERIT_COPY);
- mutex_unlock (&_mom_memory_lock);
- return err;
-}
diff --git a/libmom/mom-errors.h b/libmom/mom-errors.h
deleted file mode 100644
index 85a35d5e..00000000
--- a/libmom/mom-errors.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Error codes for MOM library
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-
-/* MOM uses Mach error system 0x11 and subsystem 0. */
-#define _MOM_ERRNO(n) ((0x11 << 26 | ((n) & 0x3fff)))
-
-enum __momerrors_error_codes
-{
- /* These are standard errors to be returned by RPC user stubs
- in Mom systems. */
-
- /* All Mom systems must detect and return these errors */
-
- /* The RPC attempted to send to an invalid mom_port_ref. This can
- happen because, for example, the server it spoke to has died. */
- EMOM_INVALID_DEST = _MOM_ERRNO (1),
-
- /* The RPC attempted to send an invalid mom_port_ref in its content.
- This shall not happen if the server the reference is to has
- merely died. */
- EMOM_INVALID_REF = _MOM_ERRNO (2),
-
- /* The server began processing the RPC, but at some point it died. */
- EMOM_SERVER_DIED = _MOM_ERRNO (3)
-};
-
-typedef enum __momerrors_error_codes mom_error_t;
-
-
diff --git a/libmom/mom-kerndep.h b/libmom/mom-kerndep.h
deleted file mode 100644
index cc61db05..00000000
--- a/libmom/mom-kerndep.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Mach-specific type definitions for MOM
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-#include <mach/mach.h>
-#include <spin-lock.h>
-
-struct mom_port_ref
-{
- mach_port_t port;
-};
-
-/* Mach-specific functions */
-
-/* Initialize OBJ with a reference to Mach port PORT. One Mach user
- reference is consumed. */
-error_t mom_mach_port_set (struct mom_port_ref *obj, mach_port_t port);
-
-/* Return the Mach port corresponding to OBJ. No new Mach user
- references are created, so this Mach port should not be used
- after OBJ has been destroyed. */
-mach_port_t mom_fetch_mach_port (struct mom_port_ref *obj);
-
-/* Turn a Mach error number into a Mom error number. */
-mom_error_t mom_error_translate_mach (error_t macherr);
diff --git a/libmom/mom.h b/libmom/mom.h
deleted file mode 100644
index 75d4b08d..00000000
--- a/libmom/mom.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Microkernel object module
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-
-
-#include <stdlib.h>
-#include <errno.h>
-
-#include <mom-errors.h>
-
-/* This header file defines structure layouts for the use of functions
- below; it is specific to the particular microkernel in use. */
-#include <mom-kerndep.h>
-
-
-
-
-
-/* User RPC endpoints */
-
-/* A communications end-point suitable for sending RPC's to servers. */
-struct mom_port_ref; /* layout defined in mom-kerndep.h */
-
-/* Create a new port reference that refers to the same underlying channel
- as OBJ. Fill *NEW with the new reference. NEW should be otherwise
- unused memory. */
-error_t mom_copy_ref (struct mom_port_ref *new, struct mom_port_ref *obj);
-
-/* Tell if two mom ports refer to the same underlying server RPC channel */
-int mom_refs_identical (struct mom_port_ref *obj1, struct mom_port_ref *obj2);
-
-/* Return a hash key for a port. Different ports may have the same
- hash key, but no port's hash key will ever change as long as that
- port is known to this task. Two identical ports (as by
- mom_ports_identical) will always have the same hash key. */
-int mom_hash_ref (struct mom_port_ref *obj);
-
-/* Destroy mom port reference OBJ and deallocate the underlying kernel
- object. After this call, the memory in *OBJ may be used by the
- user for any purpose. It is an error to call this routine if any
- other thread might be calling any other mom port reference function
- on OBJ concurrently. */
-void mom_ref_destroy (struct mom_port_ref *obj);
-
-
-
-/* Memory management */
-
-/* Size of a physical page; mom memory management calls must be in
- aligned multiples of this value. */
-extern size_t mom_page_size;
-
-/* Reserve a region of memory from START and continuing for LEN bytes
- so that it won't be used by anyone, but don't make it directly
- usable. */
-error_t mom_reserve_memory (void *start, size_t len);
-
-/* Reserve a region of memory anywhere of size LEN bytes and return
- its address in ADDR. */
-error_t mom_reserve_memory_anywhere (void **addr, size_t len);
-
-/* Make a reserved region of memory usable, as specified by START and
- LEN. If READONLY is set then only make it available for read
- access; otherwise permit both read and write. If OBJ is null, then
- use zero-filled anonymous storage. If OBJ is non-null, then it
- specifies a mom port reference referring to a memory server, and
- OFFSET is the offset within that server. If COPY is set, then the
- data is copied from the memory object, otherwise it shares with
- other users of the same object. */
-error_t mom_use_memory (void *start, size_t len, int readonly,
- struct mom_port_ref *obj, size_t offset,
- int copy);
-
-/* Ask the kernel to wire the region of memory specified to physical
- memory. The exact semantics of this are kernel dependent; it is
- also usually privileged in some fashion and will fail for
- non-privileged users. */
-error_t mom_wire_memory (void *start, size_t len);
-
-/* Convert a region of usable memory to read-only */
-error_t mom_make_memory_readonly (void *start, size_t len);
-
-/* Convert a region of usable memory to read/write */
-error_t mom_make_memory_readwrite (void *start, size_t len);
-
-/* Convert a region of usable memory to reserved but unusable status. */
-error_t mom_unuse_memory (void *start, size_t len);
-
-/* Convert a region of reserved unusable memory to unreserved status. */
-error_t mom_unreserve_memory (void *start, size_t len);
-
-
-
-/* Optimized combination versions of memory functions; these are very
- likely to be faster than using the two call sequences they are
- equivalent to. */
-
-/* Combined version of mom_unuse_memory followed by mom_unreserve_memory. */
-error_t mom_deallocate_memory (void *start, size_t len);
-
-/* Combined version of mom_reserve_memory and mom_use_memory. */
-error_t mom_allocate_address (void *start, size_t len, int readonly,
- struct mom_port_ref *obj, size_t offset,
- int copy);
-
-/* Combined version of mom_reserve_memory_anywhere and mom_use_memory. */
-error_t mom_allocate_memory (void **start, size_t len, int readonly,
- struct mom_port_ref *obj, size_t offset,
- int copy);
-
-/* Shorthand for the most common sort of allocation--like mom_allocate_memory,
- but READONLY, and OBJ are both null. */
-#define mom_allocate(start,len) \
- (mom_allocate_memory ((start), (len), 0, 0, 0, 0))
-
diff --git a/libnetfs/ChangeLog b/libnetfs/ChangeLog
deleted file mode 100644
index cf6933ca..00000000
--- a/libnetfs/ChangeLog
+++ /dev/null
@@ -1,253 +0,0 @@
-Fri Jul 26 14:34:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-exec.c (netfs_S_file_exec): Unlock NP before we attempt to
- do setuid/setgid (which otherwise can deadlock during port reauth).
- Pay attention to the error code returned by fshelp_exec_reauth,
- and don't make NEWPI if it's an error.
-
-Tue Jul 23 14:28:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-utimes.c (netfs_S_file_utimes): `struct timespec' now uses
- a field prefix of `tv_'.
-
-Thu Jul 18 23:09:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (netfs_S_io_reauthenticate): After attaching
- credential to NEWPI, install it in NETFS_PORT_BUCKET->portset.
- * make-protid.c (netfs_make_protid): If CRED is null, use
- noinstall version of ports_create_port.
-
-Sat Jul 13 20:10:02 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (netfs_S_io_reauthenticate): Repeat
- auth_server_authenticate for as long as we get EINTR. Tolerate
- other errors without crashing as well.
-
-Sun Jul 7 21:28:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (netfs_S_io_reauthenticate): Don't use
- unsafe MOVE_SEND in call to auth_server_authenticate.
-
-Thu Jul 4 16:56:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-write.c (netfs_S_io_write): Bother implementing O_APPEND.
-
- * io-identity.c (netfs_S_io_identity): Don't take address of ID in
- call to fshelp_get_identity.
-
-Wed Jul 3 11:54:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir-mkfile.c (netfs_S_dir_mkfile): Return right with MAKE_SEND,
- not COPY_SEND.
-
- * io-identity.c (netfs_S_io_identity): Use fshelp_get_identity
- instead of creating port ourselves.
- * netfs.h (struct node): Delete member identity.
- * make-node.c (netfs_make_node): Don't initialize NP->identity.
- * drop-node.c (netfs_drop_node): Don't deallocate NP->identity.
-
-Thu Jun 27 17:57:30 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Add execserver.h.
-
-Thu Jun 27 00:24:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * append-std-options.c: New file.
- * Makefile (OTHERSRCS): Add append-std-options.c.
-
-Wed Jun 26 15:57:13 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * netfs.h: Change options parsing interface to match libdiskfs's:
- (netfs_set_options, netfs_get_options): Updated to inew interface.
- (netfs_runtime_argp, netfs_std_runtime_argp, netfs_std_startup_arg):
- New variables.
- (netfs_append_std_options): New declaration.
- (netfs_parse_runtime_options, netfs_unparse_runtime_options):
- Functions removed.
- * set-options.c (std_runtime_options): Variable removed.
- (parse_runtime_opt): Function removed.
- (netfs_set_options): Change to use fshelp_set_options.
- * fsys-set-options.c (netfs_S_fsys_set_options): Don't convert
- options string into argv vector.
- * fsys-get-options.c (netfs_S_fsys_get_options): Use
- fshelp_return_malloced_buffer to prepare return value.
- * file-get-fs-options.c (netfs_S_file_get_fs_options): Likewise.
- * get-options.c (netfs_get_options): Call netfs_append_std_options.
- * std-startup-argp.c, std-runtime-argp.c, runtime-argp.c: New files.
- * parse-runtime-options.c, unparse-runtime-options.c: Files removed.
- * Makefile (OTHERSRCS): Add runtime-argp.c, std-runtime-argp.c,
- & std-startup-argp.c. Remove parse-runtime-options.c &
- unparse-runtime-options.c.
-
-Tue May 14 14:05:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * init-init.c (netfs_fsys_identity): New variable.
- (netfs_init): Initialize netfs_fsys_identity.
- * drop-node.c (netfs_drop_node): Destroy NP->identity if it's set.
- * make-node.c (netfs_make_node): Initialize NP->identity.
- * netfs.h (struct node): New member `identity'.
- (netfs_fsys_identity): New variable.
- * Makefile (IOSRCS): Add io-identity.c.
- * io-identity.c: New file.
-
-Sat May 11 01:24:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * startup-argp.c (parse_startup_opt): Use ARGP_ERR_UNKNOWN instead
- of EINVAL.
-
-Thu May 9 18:54:11 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * file-get-storage-info.c (netfs_S_file_get_storage_info): fixup
-
-Thu May 9 18:15:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-get-storage-info.c (netfs_S_file_get_storage_info): Change
- to new interface.
-
-Thu May 9 11:53:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * make-protid.c (netfs_make_protid): Use new ports interface; if
- it fails return zero.
-
- * io-select.c (netfs_S_io_select): No longer has TAG arg.
-
- * io-reauthenticate.c (netfs_S_io_reauthenticate): Don't pass
- right for USER to auth_server_authenticate.
-
- * file-sync.c (netfs_S_file_sync): Accept and ignore new omitmeta
- arg.
-
- * dir-rename.c (netfs_S_dir_rename): Accept and pass through excl
- flag.
- * dir-link.c (netfs_S_dir_link): Likewise.
- * netfs.h (netfs_attempt_link): Add excl parm.
- (netfs_attempt_rename): Likewise.
-
- * netfs.h (netfs_attempt_statfs): Use struct statfs, not old
- deprecated structure.
- * file-statfs.c (netfs_S_file_statfs): Use new struct statfs.
-
- * netfs.h: ioserver.h -> iohelp.h.
-
-Mon Apr 29 16:27:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * file-getcontrol.c (netfs_S_file_getcontrol): Use correct args to
- ports_create_port.
-
-Sat Apr 27 06:02:03 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * file-getcontrol.c: Use ports_create_port instead of
- ports_allocate_port, and notice the error.
-
-Wed Apr 24 16:02:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-seek.c (netfs_S_io_seek): Bother to set *NEWOFFSET.
-
-Fri Apr 12 16:21:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * file-exec.c (netfs_S_file_exec): Copy credential using
- netfs_copy_credential before handing it off to netfs_make_protid.
-
- * dir-lookup.c (netfs_S_dir_lookup): netfs_make_protid's second
- arg must be a real credential; the unauthenticated port creation
- frob now makes a genuine (but empty) credential.
-
-Thu Apr 11 18:10:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (fsys-MIGSFLAGS, fs-MIGSFLAGS, io-MIGSFLAGS,
- ifsock-MIGSFLAGS): Find mutations.h in $(srcdir).
-
-Wed Apr 3 14:47:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (netfs_S_io_reauthenticate): In check for
- deallocation of aux_gids; check against AGBUF, not AUBUF.
-
-Tue Apr 2 09:14:30 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-write.c: Include <fcntl.h>.
- (netfs_S_io_write): Verify that the user has the file open for
- writing.
- * io-read.c: Include <fcntl.h>.
- (netfs_S_io_read): Verify that the user has the file open for
- reading.
-
-Mon Apr 1 16:02:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * fsstubs.c (netfs_S_file_exec): Remove stub.
- * Makefile (FSSRCS): Add file-exec.c.
- * execserver.h: New file.
- * file-exec.c: New file.
-
-Mon Apr 1 14:21:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * parse-runtime-options.c (netfs_parse_runtime_options): Pass new
- arg to arg_parse.
-
-Tue Mar 19 14:12:32 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Add callbacks.h misc.h modes.h mutations.h
- priv.h.
-
-Mon Mar 18 11:09:05 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * netfs.h (netfs_startup): Add declaration.
-
- * netfs.h (netfs_protid_class, netfs_control_class,
- netfs_port_bucket, netfs_root_node, netfs_auth_server_port): Make
- this extern.
-
- * fsys-getroot.c: Include "callbacks.h".
-
- * file-set-translator.c (makedev): New macro.
-
-Thu Mar 14 16:47:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * netfs.h (netfs_attempt_mkdev): Don't pass dev_t in pieces.
- * file-set-translator.c (netfs_S_file_set_translator): In call to
- netfs_attempt_mkdev don't pass MAJOR and MINOR in pieces.
-
-Tue Mar 12 14:57:26 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * fsys-getroot.c (netfs_S_fsys_getroot): Add translator linkage
- code.
- * dir-lookup.c (netfs_S_dir_lookup): Fix up and enable translator
- linkage code.
-
- * netfs.h (netfs_attempt_chmod): Doc fix.
- (netfs_attempt_mksymlink, netfs_attempt_mkdev,
- netfs_set_translator): New declarations.
- * file-set-translator.c: New file.
- * fsstubs.c (netfs_S_file_set_translator): Delete function.
- * Makefile (FSSRCS): Add file-set-translator.c.
-
-Mon Mar 11 16:44:08 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * fsstubs.c (netfs_S_file_get_translator): Remove function.
- * file-get-translator.c: New file.
- * Makefile (FSSRCS): Add file-get-translator.c.
-
-Mon Mar 4 13:36:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsys-set-options.c, fsys-get-options.c, file-get-fs-options.c:
- New files.
- * netfs.h (netfs_startup_argp, netfs_get_options,
- netfs_set_options, netfs_parse_runtime_options,
- netfs_unparse_runtime_options): New declarations.
- * Makefile (OTHERSRCS): Add startup-argp.c, set-options.c,
- get-options.c, parse-runtime-options.c, & unparse-runtime-options.c.
- (FSYSSRCS): Add fsys-set-options.c & fsys-get-options.c.
- (FSSRCS): Add file-get-fs-options.c.
- * unparse-runtime-options.c (netfs_unparse_runtime_options): Add
- comment, and remove bogus semi.
- * fsysstubs.c (netfs_S_fsys_set_options, netfs_S_fsys_get_options):
- Functions removed.
- * fsstubs.c (netfs_S_file_get_fs_options): Function removed.
- * parse-runtime-options.c: Include "netfs.h", not "priv.h".
- * set-options.c: Likewise.
- (parse_runtime_opt): New function.
- * priv.h: Include <hurd/hurd_types.h>
-
-Tue Apr 11 11:15:30 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: New file.
-
diff --git a/libnetfs/Makefile b/libnetfs/Makefile
index 08ff74fe..d6a991df 100644
--- a/libnetfs/Makefile
+++ b/libnetfs/Makefile
@@ -1,5 +1,7 @@
#
-# Copyright (C) 1995, 1996 Free Software Foundation
+# Copyright (C) 1995, 1996, 1997, 1999, 2001, 2002, 2008 Free Software
+# Foundation
+#
# Written by Michael I. Bushnell.
#
# This file is part of the GNU Hurd.
@@ -22,40 +24,46 @@ dir := libnetfs
makemode := library
libname = libnetfs
-FSSRCS= file-chauthor.c file-check-access.c file-chflags.c file-chmod.c \
- file-chown.c file-get-storage-info.c file-lock-stat.c file-lock.c \
- file-set-size.c file-statfs.c file-sync.c file-syncfs.c file-utimes.c \
- dir-lookup.c dir-unlink.c dir-rename.c dir-rmdir.c dir-mkfile.c \
- dir-notice-changes.c dir-mkdir.c dir-link.c file-getcontrol.c \
- fsstubs.c file-getlinknode.c dir-readdir.c file-get-fs-options.c \
- file-get-translator.c file-set-translator.c file-exec.c
+HURDLIBS = fshelp iohelp threads ports shouldbeinlibc
+
+FSSRCS= dir-link.c dir-lookup.c dir-mkdir.c dir-mkfile.c \
+ dir-notice-changes.c dir-readdir.c dir-rename.c \
+ dir-rmdir.c dir-unlink.c file-chauthor.c \
+ file-check-access.c file-chflags.c file-chmod.c file-chown.c \
+ file-exec.c file-get-fs-options.c file-get-storage-info.c \
+ file-get-translator.c file-getcontrol.c file-getlinknode.c \
+ file-lock-stat.c file-lock.c file-set-size.c \
+ file-set-translator.c file-statfs.c file-sync.c file-syncfs.c \
+ file-utimes.c file-reparent.c fsstubs.c
IOSRCS= io-read.c io-readable.c io-seek.c io-write.c io-stat.c io-async.c \
io-set-all-openmodes.c io-get-openmodes.c io-set-some-openmodes.c \
io-clear-some-openmodes.c io-mod-owner.c io-get-owner.c io-select.c \
io-get-icky-async-id.c io-reauthenticate.c io-restrict-auth.c \
- io-duplicate.c iostubs.c io-identity.c
+ io-duplicate.c iostubs.c io-identity.c io-revoke.c io-pathconf.c \
+ io-version.c
FSYSSRCS= fsys-syncfs.c fsys-getroot.c fsys-get-options.c fsys-set-options.c \
- fsysstubs.c
+ fsys-goaway.c fsysstubs.c
IFSOCKSRCS=
OTHERSRCS= drop-node.c init-init.c make-node.c make-peropen.c make-protid.c \
init-loop.c demuxer.c shutdown.c release-protid.c release-peropen.c \
- init-startup.c startup-argp.c set-options.c get-options.c \
+ init-startup.c startup-argp.c set-options.c append-args.c \
runtime-argp.c std-runtime-argp.c std-startup-argp.c \
- append-std-options.c
+ append-std-options.c trans-callback.c set-get-trans.c \
+ nref.c nrele.c nput.c file-get-storage-info-default.c
SRCS= $(OTHERSRCS) $(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(IFSOCKSRCS)
LCLHDRS = netfs.h callbacks.h misc.h modes.h mutations.h priv.h execserver.h
installhdrs=netfs.h
-MIGSTUBS= ioServer.o fsServer.o fsysServer.o ifsockServer.o
+MIGSTUBS= ioServer.o fsServer.o fsysServer.o fsys_replyUser.o ifsockServer.o
OBJS=$(sort $(SRCS:.c=.o) $(MIGSTUBS))
-fsys-MIGSFLAGS = -imacros $(srcdir)/mutations.h
+fsys-MIGSFLAGS = -imacros $(srcdir)/mutations.h -DREPLY_PORTS
fs-MIGSFLAGS = -imacros $(srcdir)/mutations.h
io-MIGSFLAGS = -imacros $(srcdir)/mutations.h
ifsock-MIGSFLAGS = -imacros $(srcdir)/mutations.h
diff --git a/libnetfs/get-options.c b/libnetfs/append-args.c
index 3eb11900..867c7bbd 100644
--- a/libnetfs/get-options.c
+++ b/libnetfs/append-args.c
@@ -1,4 +1,4 @@
-/* Get run-time options
+/* Append current command-line arguments
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
@@ -22,10 +22,10 @@
#include "netfs.h"
+/* Append to the malloced string *ARGZ of length *ARGZ_LEN a NUL-separated
+ list of the arguments to this translator. */
error_t
-netfs_get_options (char **argz, size_t *argz_len)
+netfs_append_args (char **argz, size_t *argz_len)
{
- *argz = 0;
- *argz_len = 0;
return netfs_append_std_options (argz, argz_len);
}
diff --git a/libnetfs/append-std-options.c b/libnetfs/append-std-options.c
index cb0a36da..e5d79631 100644
--- a/libnetfs/append-std-options.c
+++ b/libnetfs/append-std-options.c
@@ -1,8 +1,7 @@
/* Get standard netfs run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -22,11 +21,10 @@
#include "netfs.h"
-/* *Appends* to ARGZ & ARGZ_LEN '\0'-separated options describing the standard
- netfs option state (note that unlike netfs_get_options, ARGZ & ARGZ_LEN
- must already have a sane value). */
+/* Appends to ARGZ & ARGZ_LEN '\0'-separated options describing the standard
+ netfs option state. */
error_t
-netfs_append_std_options (char **argz, unsigned *argz_len)
+netfs_append_std_options (char **argz, size_t *argz_len)
{
return 0;
}
diff --git a/libnetfs/dir-link.c b/libnetfs/dir-link.c
index 35cc6f7a..1c31b8f9 100644
--- a/libnetfs/dir-link.c
+++ b/libnetfs/dir-link.c
@@ -34,7 +34,7 @@ netfs_S_dir_link (struct protid *diruser, struct protid *fileuser, char *name,
return EXDEV;
/* Note that nothing is locked here */
- err = netfs_attempt_link (diruser->credential, diruser->po->np,
+ err = netfs_attempt_link (diruser->user, diruser->po->np,
fileuser->po->np, name, excl);
if (!err)
mach_port_deallocate (mach_task_self (), fileuser->pi.port_right);
diff --git a/libnetfs/dir-lookup.c b/libnetfs/dir-lookup.c
index 9ca623f3..17d9e23e 100644
--- a/libnetfs/dir-lookup.c
+++ b/libnetfs/dir-lookup.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,10 +28,6 @@
#include "callbacks.h"
#include "misc.h"
-/* XXX - Temporary hack; this belongs in a header file, probably types.h. */
-#define major(x) ((int)(((unsigned) (x) >> 8) & 0xff))
-#define minor(x) ((int)((x) & 0xff))
-
error_t
netfs_S_dir_lookup (struct protid *diruser,
char *filename,
@@ -52,25 +48,24 @@ netfs_S_dir_lookup (struct protid *diruser,
char *nextname;
error_t error;
struct protid *newpi;
+ struct iouser *user;
if (!diruser)
return EOPNOTSUPP;
-
+
create = (flags & O_CREAT);
excl = (flags & O_EXCL);
-
+
/* Skip leading slashes */
while (*filename == '/')
filename++;
-
+
*retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
*do_retry = FS_RETRY_NORMAL;
*retry_name = '\0';
-
+
if (*filename == '\0')
{
- mustbedir = 1;
-
/* Set things up in the state expected by the code from gotit: on. */
dnp = 0;
np = diruser->po->np;
@@ -78,20 +73,19 @@ netfs_S_dir_lookup (struct protid *diruser,
netfs_nref (np);
goto gotit;
}
-
+
dnp = diruser->po->np;
mutex_lock (&dnp->lock);
- np = 0;
-
+
netfs_nref (dnp); /* acquire a reference for later netfs_nput */
-
+
do
{
assert (!lastcomp);
-
+
/* Find the name of the next pathname component */
nextname = index (filename, '/');
-
+
if (nextname)
{
*nextname++ = '\0';
@@ -108,55 +102,66 @@ netfs_S_dir_lookup (struct protid *diruser,
else
lastcomp = 0;
}
- else
+ else
lastcomp = 1;
-
+
np = 0;
-
+
retry_lookup:
-
- if (dnp == netfs_root_node
+
+ if ((dnp == netfs_root_node || dnp == diruser->po->shadow_root)
&& filename[0] == '.' && filename[1] == '.' && filename[2] == '\0')
- {
- /* Lookup of .. from root */
- if (diruser->po->dotdotport != MACH_PORT_NULL)
- {
- *do_retry = FS_RETRY_REAUTH;
- *retry_port = diruser->po->dotdotport;
- *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
- if (!lastcomp)
- strcpy (retry_name, nextname);
- error = 0;
- mutex_unlock (&dnp->lock);
- goto out;
- }
- else
- /* We are global root */
- {
- error = 0;
- np = dnp;
- netfs_nref (np);
- }
- }
+ if (dnp == diruser->po->shadow_root)
+ /* We're at the root of a shadow tree. */
+ {
+ *do_retry = FS_RETRY_REAUTH;
+ *retry_port = diruser->po->shadow_root_parent;
+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
+ if (! lastcomp)
+ strcpy (retry_name, nextname);
+ error = 0;
+ mutex_unlock (&dnp->lock);
+ goto out;
+ }
+ else if (diruser->po->root_parent != MACH_PORT_NULL)
+ /* We're at a real translator root; even if DIRUSER->po has a
+ shadow root, we can get here if its in a directory that was
+ renamed out from under it... */
+ {
+ *do_retry = FS_RETRY_REAUTH;
+ *retry_port = diruser->po->root_parent;
+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
+ if (!lastcomp)
+ strcpy (retry_name, nextname);
+ error = 0;
+ mutex_unlock (&dnp->lock);
+ goto out;
+ }
+ else
+ /* We are global root */
+ {
+ error = 0;
+ np = dnp;
+ netfs_nref (np);
+ }
else
/* Attempt a lookup on the next pathname component. */
- error = netfs_attempt_lookup (diruser->credential, dnp, filename, &np);
-
+ error = netfs_attempt_lookup (diruser->user, dnp, filename, &np);
+
/* At this point, DNP is unlocked */
/* Implement O_EXCL flag here */
if (lastcomp && create && excl && !error)
error = EEXIST;
-
+
/* Create the new node if necessary */
if (lastcomp && create && error == ENOENT)
{
mode &= ~(S_IFMT | S_ISPARE | S_ISVTX);
mode |= S_IFREG;
mutex_lock (&dnp->lock);
- error = netfs_attempt_create_file (diruser->credential, dnp,
+ error = netfs_attempt_create_file (diruser->user, dnp,
filename, mode, &np);
- newnode = 1;
/* If someone has already created the file (between our lookup
and this create) then we just got EEXIST. If we are
@@ -166,55 +171,57 @@ netfs_S_dir_lookup (struct protid *diruser,
mutex_lock (&dnp->lock);
goto retry_lookup;
}
+
+ newnode = 1;
}
/* All remaining errors get returned to the user */
if (error)
goto out;
-
- error = netfs_validate_stat (np, diruser->credential);
+
+ error = netfs_validate_stat (np, diruser->user);
if (error)
goto out;
if ((((flags & O_NOTRANS) == 0) || !lastcomp)
- && (np->istranslated
- || S_ISFIFO (np->nn_stat.st_mode)
- || S_ISCHR (np->nn_stat.st_mode)
- || S_ISBLK (np->nn_stat.st_mode)
+ && ((np->nn_translated & S_IPTRANS)
+ || S_ISFIFO (np->nn_translated)
+ || S_ISCHR (np->nn_translated)
+ || S_ISBLK (np->nn_translated)
|| fshelp_translated (&np->transbox)))
{
mach_port_t dirport;
- uid_t *uids, *gids;
- int nuids, ngids;
-
+
/* A callback function for short-circuited translators.
S_ISLNK and S_IFSOCK are handled elsewhere. */
error_t short_circuited_callback1 (void *cookie1, void *cookie2,
uid_t *uid, gid_t *gid,
- char **argz, int *argz_len)
+ char **argz, size_t *argz_len)
{
struct node *np = cookie1;
error_t err;
- err = netfs_validate_stat (np, diruser->credential);
+ err = netfs_validate_stat (np, diruser->user);
if (err)
return err;
- switch (np->nn_stat.st_mode & S_IFMT)
+ switch (np->nn_translated & S_IFMT)
{
case S_IFCHR:
case S_IFBLK:
- asprintf (argz, "%s%c%d%c%d",
- (S_ISCHR (np->nn_stat.st_mode)
- ? _HURD_CHRDEV : _HURD_BLKDEV),
- 0, major (np->nn_stat.st_rdev),
- 0, minor (np->nn_stat.st_rdev));
+ if (asprintf (argz, "%s%c%d%c%d",
+ (S_ISCHR (np->nn_translated)
+ ? _HURD_CHRDEV : _HURD_BLKDEV),
+ 0, major (np->nn_stat.st_rdev),
+ 0, minor (np->nn_stat.st_rdev)) < 0)
+ return ENOMEM;
*argz_len = strlen (*argz) + 1;
*argz_len += strlen (*argz + *argz_len) + 1;
*argz_len += strlen (*argz + *argz_len) + 1;
break;
case S_IFIFO:
- asprintf (argz, "%s", _HURD_FIFO);
+ if (asprintf (argz, "%s", _HURD_FIFO) < 0)
+ return ENOMEM;
*argz_len = strlen (*argz) + 1;
break;
default:
@@ -223,35 +230,44 @@ netfs_S_dir_lookup (struct protid *diruser,
*uid = np->nn_stat.st_uid;
*gid = np->nn_stat.st_gid;
-
+
return 0;
}
-
+
/* Create an unauthenticated port for DNP, and then
unlock it. */
- newpi =
- netfs_make_protid (netfs_make_peropen (dnp, 0,
- diruser->po->dotdotport),
- netfs_make_credential (0, 0, 0, 0));
- dirport = ports_get_right (newpi);
- mach_port_insert_right (mach_task_self (), dirport, dirport,
- MACH_MSG_TYPE_MAKE_SEND);
- ports_port_deref (newpi);
- if (np != dnp)
- mutex_unlock (&dnp->lock);
-
- netfs_interpret_credential (diruser->credential, &uids, &nuids,
- &gids, &ngids);
- error = fshelp_fetch_root (&np->transbox, &diruser->po->dotdotport,
- dirport, uids, nuids, gids, ngids,
- lastcomp ? flags : 0,
- (np->istranslated
- ? _netfs_translator_callback1
- : short_circuited_callback1),
- _netfs_translator_callback2,
- do_retry, retry_name, retry_port);
- free (uids);
- free (gids);
+ error = iohelp_create_empty_iouser (&user);
+ if (! error)
+ {
+ newpi = netfs_make_protid (netfs_make_peropen (dnp, 0,
+ diruser->po),
+ user);
+ if (! newpi)
+ {
+ error = errno;
+ iohelp_free_iouser (user);
+ }
+ }
+
+ if (! error)
+ {
+ dirport = ports_get_send_right (newpi);
+ ports_port_deref (newpi);
+
+ error = fshelp_fetch_root (&np->transbox, diruser->po,
+ dirport,
+ diruser->user,
+ lastcomp ? flags : 0,
+ ((np->nn_translated & S_IPTRANS)
+ ? _netfs_translator_callback1
+ : short_circuited_callback1),
+ _netfs_translator_callback2,
+ do_retry, retry_name, retry_port);
+ /* fetch_root copies DIRPORT for success, so we always should
+ deallocate our send right. */
+ mach_port_deallocate (mach_task_self (), dirport);
+ }
+
if (error != ENOENT)
{
netfs_nrele (dnp);
@@ -264,30 +280,20 @@ netfs_S_dir_lookup (struct protid *diruser,
}
return error;
}
-
+
/* ENOENT means there was a hiccup, and the translator vanished
- while NP was unlocked inside fshelp_fetch_root.
- Reacquire the locks and continue as normal. */
+ while NP was unlocked inside fshelp_fetch_root; continue as normal. */
error = 0;
- if (np != dnp)
- {
- if (!strcmp (filename, ".."))
- mutex_lock (&dnp->lock);
- else
- {
- mutex_unlock (&np->lock);
- mutex_lock (&dnp->lock);
- mutex_lock (&np->lock);
- }
- }
}
-
- if (S_ISLNK (np->nn_stat.st_mode)
- && !(lastcomp && (flags & (O_NOLINK|O_NOTRANS))))
+
+ if (S_ISLNK (np->nn_translated)
+ && (!lastcomp
+ || mustbedir /* "foo/" must see that foo points to a dir */
+ || !(flags & (O_NOLINK|O_NOTRANS))))
{
size_t nextnamelen, newnamelen, linklen;
char *linkbuf;
-
+
/* Handle symlink interpretation */
if (nsymlinks++ > netfs_maxsymlinks)
{
@@ -296,23 +302,23 @@ netfs_S_dir_lookup (struct protid *diruser,
}
linklen = np->nn_stat.st_size;
-
+
nextnamelen = nextname ? strlen (nextname) + 1 : 0;
newnamelen = nextnamelen + linklen + 1;
linkbuf = alloca (newnamelen);
-
- error = netfs_attempt_readlink (diruser->credential, np, linkbuf);
+
+ error = netfs_attempt_readlink (diruser->user, np, linkbuf);
if (error)
goto out;
-
+
if (nextname)
{
linkbuf[linklen] = '/';
- bcopy (nextname, linkbuf + linklen + 1,
+ memcpy (linkbuf + linklen + 1, nextname,
nextnamelen - 1);
}
linkbuf[nextnamelen + linklen] = '\0';
-
+
if (linkbuf[0] == '/')
{
/* Punt to the caller */
@@ -321,7 +327,7 @@ netfs_S_dir_lookup (struct protid *diruser,
strcpy (retry_name, linkbuf);
goto out;
}
-
+
filename = linkbuf;
if (lastcomp)
{
@@ -340,7 +346,7 @@ netfs_S_dir_lookup (struct protid *diruser,
/* Normal nodes here for next filename component */
filename = nextname;
netfs_nrele (dnp);
-
+
if (lastcomp)
dnp = 0;
else
@@ -357,26 +363,36 @@ netfs_S_dir_lookup (struct protid *diruser,
if (mustbedir)
{
- netfs_validate_stat (np, diruser->credential);
+ netfs_validate_stat (np, diruser->user);
if (!S_ISDIR (np->nn_stat.st_mode))
{
error = ENOTDIR;
goto out;
}
- }
- error = netfs_check_open_permissions (diruser->credential, np,
+ }
+ error = netfs_check_open_permissions (diruser->user, np,
flags, newnode);
if (error)
goto out;
-
+
flags &= ~OPENONLY_STATE_MODES;
-
- newpi = netfs_make_protid (netfs_make_peropen (np, flags,
- diruser->po->dotdotport),
- netfs_copy_credential (diruser->credential));
+
+ error = iohelp_dup_iouser (&user, diruser->user);
+ if (error)
+ goto out;
+
+ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po),
+ user);
+ if (! newpi)
+ {
+ iohelp_free_iouser (user);
+ error = errno;
+ goto out;
+ }
+
*retry_port = ports_get_right (newpi);
ports_port_deref (newpi);
-
+
out:
if (np)
netfs_nput (np);
@@ -384,5 +400,3 @@ netfs_S_dir_lookup (struct protid *diruser,
netfs_nrele (dnp);
return error;
}
-
-
diff --git a/libnetfs/dir-mkdir.c b/libnetfs/dir-mkdir.c
index fdfde30c..33feb25f 100644
--- a/libnetfs/dir-mkdir.c
+++ b/libnetfs/dir-mkdir.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -33,7 +33,7 @@ netfs_S_dir_mkdir (struct protid *user, char *name, mode_t mode)
mode |= S_IFDIR;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_mkdir (user->credential, user->po->np, name, mode);
+ err = netfs_attempt_mkdir (user->user, user->po->np, name, mode);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/dir-mkfile.c b/libnetfs/dir-mkfile.c
index 89212daa..7d388737 100644
--- a/libnetfs/dir-mkfile.c
+++ b/libnetfs/dir-mkfile.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,25 +28,37 @@ netfs_S_dir_mkfile (struct protid *diruser, int flags, mode_t mode,
{
error_t err;
struct node *np;
+ struct iouser *user;
struct protid *newpi;
mutex_lock (&diruser->po->np->lock);
- err = netfs_attempt_mkfile (diruser->credential, diruser->po->np, mode, &np);
+ err = netfs_attempt_mkfile (diruser->user, diruser->po->np, mode, &np);
if (!err)
{
/* the dir is now unlocked and NP is locked */
flags &= OPENONLY_STATE_MODES;
- newpi = netfs_make_protid (netfs_make_peropen (np, flags,
- diruser->po->dotdotport),
- netfs_copy_credential (diruser->credential));
- *newfile = ports_get_right (newpi);
- *newfiletype = MACH_MSG_TYPE_MAKE_SEND;
- ports_port_deref (newpi);
+ err = iohelp_dup_iouser (&user, diruser->user);
+ if (! err)
+ {
+ newpi = netfs_make_protid (netfs_make_peropen (np, flags,
+ diruser->po),
+ user);
+ if (newpi)
+ {
+ *newfile = ports_get_right (newpi);
+ *newfiletype = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newpi);
+ }
+ else
+ {
+ err = errno;
+ iohelp_free_iouser (user);
+ }
+ }
netfs_nput (np);
- return 0;
}
- else
- return err;
+
+ return err;
}
diff --git a/libnetfs/dir-readdir.c b/libnetfs/dir-readdir.c
index 85719302..7f896ac1 100644
--- a/libnetfs/dir-readdir.c
+++ b/libnetfs/dir-readdir.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1996,99,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -27,6 +27,7 @@ error_t
netfs_S_dir_readdir (struct protid *user,
char **data,
mach_msg_type_number_t *datacnt,
+ boolean_t *data_dealloc,
int entry,
int nentries,
vm_size_t bufsiz,
@@ -34,23 +35,24 @@ netfs_S_dir_readdir (struct protid *user,
{
error_t err;
struct node *np;
-
+
if (!user)
return EOPNOTSUPP;
-
+
np = user->po->np;
mutex_lock (&np->lock);
-
+
err = 0;
if ((user->po->openstat & O_READ) == 0)
err = EBADF;
if (!err)
- err = netfs_validate_stat (np, user->credential);
+ err = netfs_validate_stat (np, user->user);
if (!err && (np->nn_stat.st_mode & S_IFMT) != S_IFDIR)
err = ENOTDIR;
if (!err)
- err = netfs_get_dirents (user->credential, np, entry, nentries, data,
+ err = netfs_get_dirents (user->user, np, entry, nentries, data,
datacnt, bufsiz, amt);
+ *data_dealloc = 1; /* XXX */
mutex_unlock (&np->lock);
return err;
}
diff --git a/libnetfs/dir-rename.c b/libnetfs/dir-rename.c
index 6898c5e9..0215376b 100644
--- a/libnetfs/dir-rename.c
+++ b/libnetfs/dir-rename.c
@@ -34,7 +34,7 @@ netfs_S_dir_rename (struct protid *fromdiruser, char *fromname,
return EXDEV;
/* Note that nothing is locked here */
- err = netfs_attempt_rename (fromdiruser->credential, fromdiruser->po->np,
+ err = netfs_attempt_rename (fromdiruser->user, fromdiruser->po->np,
fromname, todiruser->po->np, toname, excl);
if (!err)
mach_port_deallocate (mach_task_self (), todiruser->pi.port_right);
diff --git a/libnetfs/dir-rmdir.c b/libnetfs/dir-rmdir.c
index 4f9e962a..9a5941d3 100644
--- a/libnetfs/dir-rmdir.c
+++ b/libnetfs/dir-rmdir.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -30,7 +30,7 @@ netfs_S_dir_rmdir (struct protid *diruser, char *name)
return EOPNOTSUPP;
mutex_lock (&diruser->po->np->lock);
- err = netfs_attempt_rmdir (diruser->credential, diruser->po->np, name);
+ err = netfs_attempt_rmdir (diruser->user, diruser->po->np, name);
mutex_unlock (&diruser->po->np->lock);
return err;
}
diff --git a/libnetfs/dir-unlink.c b/libnetfs/dir-unlink.c
index 4bf8798e..8077514a 100644
--- a/libnetfs/dir-unlink.c
+++ b/libnetfs/dir-unlink.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -27,7 +27,7 @@ netfs_S_dir_unlink (struct protid *user, char *name)
error_t err;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_unlink (user->credential, user->po->np, name);
+ err = netfs_attempt_unlink (user->user, user->po->np, name);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-chauthor.c b/libnetfs/file-chauthor.c
index 1ed305bb..ec7f6177 100644
--- a/libnetfs/file-chauthor.c
+++ b/libnetfs/file-chauthor.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -31,7 +31,7 @@ netfs_S_file_chauthor (struct protid *user,
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_chauthor (user->credential, user->po->np, author);
+ err = netfs_attempt_chauthor (user->user, user->po->np, author);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-check-access.c b/libnetfs/file-check-access.c
index c3c278d7..8e36ede1 100644
--- a/libnetfs/file-check-access.c
+++ b/libnetfs/file-check-access.c
@@ -25,11 +25,13 @@ error_t
netfs_S_file_check_access (struct protid *user,
int *types)
{
+ error_t err;
+
if (!user)
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- netfs_report_access (user->credential, user->po->np, types);
+ err = netfs_report_access (user->user, user->po->np, types);
mutex_unlock (&user->po->np->lock);
- return 0;
+ return err;
}
diff --git a/libnetfs/file-chflags.c b/libnetfs/file-chflags.c
index 3bb96938..068a1cea 100644
--- a/libnetfs/file-chflags.c
+++ b/libnetfs/file-chflags.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -31,7 +31,7 @@ netfs_S_file_chflags (struct protid *user,
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_chflags (user->credential, user->po->np, flags);
+ err = netfs_attempt_chflags (user->user, user->po->np, flags);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-chmod.c b/libnetfs/file-chmod.c
index ac725c6c..0f082f18 100644
--- a/libnetfs/file-chmod.c
+++ b/libnetfs/file-chmod.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -29,9 +29,11 @@ netfs_S_file_chmod (struct protid *user,
if (!user)
return EOPNOTSUPP;
+
+ mode &= ~(S_IFMT | S_ISPARE | S_ITRANS);
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_chmod (user->credential, user->po->np, mode);
+ err = netfs_attempt_chmod (user->user, user->po->np, mode);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-chown.c b/libnetfs/file-chown.c
index d3484ba0..4b724048 100644
--- a/libnetfs/file-chown.c
+++ b/libnetfs/file-chown.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -32,7 +32,7 @@ netfs_S_file_chown (struct protid *user,
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_chown (user->credential, user->po->np,
+ err = netfs_attempt_chown (user->user, user->po->np,
owner, group);
mutex_unlock (&user->po->np->lock);
return err;
diff --git a/libnetfs/file-exec.c b/libnetfs/file-exec.c
index 7268e7c7..73c125ba 100644
--- a/libnetfs/file-exec.c
+++ b/libnetfs/file-exec.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1996,97,2000,01,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -24,30 +24,30 @@
#include "execserver.h"
#include "fs_S.h"
#include <sys/stat.h>
-#include <fcntlbits.h>
+#include <fcntl.h>
#include <hurd/exec.h>
#include <hurd/paths.h>
#include <string.h>
#include <idvec.h>
-kern_return_t
+kern_return_t
netfs_S_file_exec (struct protid *cred,
task_t task,
int flags,
char *argv,
- u_int argvlen,
+ size_t argvlen,
char *envp,
- u_int envplen,
+ size_t envplen,
mach_port_t *fds,
- u_int fdslen,
+ size_t fdslen,
mach_port_t *portarray,
- u_int portarraylen,
+ size_t portarraylen,
int *intarray,
- u_int intarraylen,
+ size_t intarraylen,
mach_port_t *deallocnames,
- u_int deallocnameslen,
+ size_t deallocnameslen,
mach_port_t *destroynames,
- u_int destroynameslen)
+ size_t destroynameslen)
{
struct node *np;
error_t err;
@@ -55,7 +55,8 @@ netfs_S_file_exec (struct protid *cred,
gid_t gid;
mode_t mode;
int suid, sgid;
-
+ mach_port_t right;
+
if (!cred)
return EOPNOTSUPP;
@@ -66,23 +67,23 @@ netfs_S_file_exec (struct protid *cred,
if ((cred->po->openstat & O_EXEC) == 0)
return EBADF;
-
+
np = cred->po->np;
mutex_lock (&np->lock);
mode = np->nn_stat.st_mode;
uid = np->nn_stat.st_uid;
gid = np->nn_stat.st_gid;
- err = netfs_validate_stat (np, cred->credential);
+ err = netfs_validate_stat (np, cred->user);
mutex_unlock (&np->lock);
if (err)
return err;
-
+
if (!((mode & (S_IXUSR|S_IXGRP|S_IXOTH))
|| ((mode & S_IUSEUNK) && (mode & (S_IEXEC << S_IUNKSHIFT)))))
return EACCES;
-
+
if ((mode & S_IFMT) == S_IFDIR)
return EACCES;
@@ -94,20 +95,14 @@ netfs_S_file_exec (struct protid *cred,
error_t get_file_ids (struct idvec *uidsvec, struct idvec *gidsvec)
{
error_t err;
- uid_t *uids, *gids;
- int nuids, ngids;
- netfs_interpret_credential (cred->credential, &uids, &nuids,
- &gids, &ngids);
-
- err = idvec_merge_ids (uidsvec, uids, nuids);
+ err = idvec_merge (uidsvec, cred->user->uids);
if (! err)
- err = idvec_merge_ids (gidsvec, gids, ngids);
- free (uids);
- free (gids);
+ err = idvec_merge (gidsvec, cred->user->gids);
+
return err;
}
- err =
+ err =
fshelp_exec_reauth (suid, uid, sgid, gid,
netfs_auth_server_port, get_file_ids,
portarray, portarraylen, fds, fdslen, &secure);
@@ -127,25 +122,40 @@ netfs_S_file_exec (struct protid *cred,
if (! err)
{
- struct protid *newpi =
- netfs_make_protid (netfs_make_peropen (np, O_READ,
- cred->po->dotdotport),
- netfs_copy_credential (cred->credential));
- err = exec_exec (_netfs_exec,
- ports_get_right (newpi),
- MACH_MSG_TYPE_MAKE_SEND,
- task, flags, argv, argvlen, envp, envplen,
- fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
- portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
- intarray, intarraylen, deallocnames, deallocnameslen,
- destroynames, destroynameslen);
- ports_port_deref (newpi);
+ struct iouser *user;
+ struct protid *newpi;
+
+ err = iohelp_dup_iouser (&user, cred->user);
+ if (! err)
+ {
+ newpi = netfs_make_protid (netfs_make_peropen (np, O_READ, cred->po),
+ user);
+ if (newpi)
+ {
+ right = ports_get_send_right (newpi);
+ err = exec_exec (_netfs_exec,
+ right, MACH_MSG_TYPE_COPY_SEND,
+ task, flags, argv, argvlen, envp, envplen,
+ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
+ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
+ intarray, intarraylen,
+ deallocnames, deallocnameslen,
+ destroynames, destroynameslen);
+ mach_port_deallocate (mach_task_self (), right);
+ ports_port_deref (newpi);
+ }
+ else
+ {
+ err = errno;
+ iohelp_free_iouser (user);
+ }
+ }
}
if (! err)
{
unsigned int i;
-
+
mach_port_deallocate (mach_task_self (), task);
for (i = 0; i < fdslen; i++)
mach_port_deallocate (mach_task_self (), fds[i]);
@@ -153,5 +163,5 @@ netfs_S_file_exec (struct protid *cred,
mach_port_deallocate (mach_task_self (), portarray[i]);
}
- return err;
+ return err;
}
diff --git a/libnetfs/file-get-fs-options.c b/libnetfs/file-get-fs-options.c
index 8d4af76b..1a18c72d 100644
--- a/libnetfs/file-get-fs-options.c
+++ b/libnetfs/file-get-fs-options.c
@@ -1,6 +1,6 @@
/* Unparse run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -34,23 +34,29 @@ netfs_S_file_get_fs_options (struct protid *user,
char **data, mach_msg_type_number_t *data_len)
{
error_t err;
- char *argz;
- size_t argz_len;
+ char *argz = 0;
+ size_t argz_len = 0;
if (! user)
return EOPNOTSUPP;
+ err = argz_add (&argz, &argz_len, program_invocation_name);
+ if (! err)
+ {
#if NOT_YET
- rwlock_reader_lock (&netfs_fsys_lock);
+ rwlock_reader_lock (&netfs_fsys_lock);
#endif
- err = netfs_get_options (&argz, &argz_len);
+ err = netfs_append_args (&argz, &argz_len);
#if NOT_YET
- rwlock_reader_unlock (&netfs_fsys_lock);
+ rwlock_reader_unlock (&netfs_fsys_lock);
#endif
+ }
if (! err)
/* Move ARGZ from a malloced buffer into a vm_alloced one. */
- err = fshelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ err = iohelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ else
+ free (argz);
return err;
}
diff --git a/libmom/allocate-memory.c b/libnetfs/file-get-storage-info-default.c
index d98632bc..0ca68c96 100644
--- a/libmom/allocate-memory.c
+++ b/libnetfs/file-get-storage-info-default.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,34 +18,38 @@
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 "netfs.h"
+#include "fs_S.h"
+#include <sys/mman.h>
+
error_t
-mom_allocate_memory (void **start, size_t len, int readonly,
- struct mom_port_ref *obj, size_t offset,
- int copy)
+netfs_file_get_storage_info (struct iouser *cred,
+ struct node *np,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints,
+ mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data,
+ mach_msg_type_number_t *data_len)
{
- error_t err;
- mach_port_t port;
+ *data_len = 0;
+ *num_offsets = 0;
+ *num_ports = 0;
- assert (len % vm_page_size == 0);
- if (obj)
+ if (*num_ints == 0)
+ /* Argh */
{
- port = mom_fetch_mach_port (obj);
- assert (offset % vm_page_size == 0);
+ *ints = mmap (0, sizeof (int), PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*ints == (int *) -1)
+ return errno;
}
- else
- port = MACH_PORT_NULL;
-
- *start = 0;
-
- mutex_lock (&_mom_memory_lock);
- err = vm_map (mach_task_self (), (vm_address_t *)start, len, 0, 0,
- port, (obj ? offset : 0), (obj ? copy : 0),
- (VM_PROT_READ | VM_PROT_EXECUTE
- | (!readonly ? VM_PROT_WRITE : 0)),
- VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE,
- VM_INHERIT_COPY);
- mutex_unlock (&_mom_memory_lock);
- return err;
+
+ *num_ints = 1;
+ (*ints)[0] = STORAGE_NETWORK;
+
+ return 0;
}
diff --git a/libnetfs/file-get-storage-info.c b/libnetfs/file-get-storage-info.c
index 05232e85..ac977be3 100644
--- a/libnetfs/file-get-storage-info.c
+++ b/libnetfs/file-get-storage-info.c
@@ -1,6 +1,6 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/*
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Written by Neal H Walfield <neal@cs.uml.edu>
This file is part of the GNU Hurd.
@@ -23,34 +23,25 @@
error_t
netfs_S_file_get_storage_info (struct protid *user,
- mach_port_t **ports,
- mach_msg_type_name_t *ports_type,
- mach_msg_type_number_t *num_ports,
- int **ints, mach_msg_type_number_t *num_ints,
- off_t **offsets,
- mach_msg_type_number_t *num_offsets,
- char **data, mach_msg_type_number_t *data_len)
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
{
+ error_t err;
+
if (!user)
return EOPNOTSUPP;
-
- *data_len = 0;
- *num_offsets = 0;
- *num_ports = 0;
-
- if (*num_ints == 0)
- /* Argh */
- {
- error_t err =
- vm_allocate (mach_task_self (), (vm_address_t *)ints, sizeof (int), 1);
- if (err)
- return err;
- }
-
- *num_ints = 1;
- (*ints)[0] = STORAGE_NETWORK;
-
- return 0;
-}
-
+ mutex_lock (&user->po->np->lock);
+ err = netfs_file_get_storage_info (user->user, user->po->np, ports,
+ ports_type, num_ports, ints,
+ num_ints, offsets, num_offsets,
+ data, data_len);
+ mutex_unlock (&user->po->np->lock);
+
+ return err;
+}
diff --git a/libnetfs/file-get-translator.c b/libnetfs/file-get-translator.c
index ebad95ac..7edc8fd0 100644
--- a/libnetfs/file-get-translator.c
+++ b/libnetfs/file-get-translator.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1999, 2000, 2008 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,10 +18,12 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+#include <string.h>
+#include <stdio.h>
+#include <hurd/paths.h>
#include "netfs.h"
#include "fs_S.h"
-#include <hurd/paths.h>
-#include <string.h>
+#include <sys/mman.h>
error_t
netfs_S_file_get_translator (struct protid *user,
@@ -36,7 +38,7 @@ netfs_S_file_get_translator (struct protid *user,
np = user->po->np;
mutex_lock (&np->lock);
- err = netfs_validate_stat (np, user->credential);
+ err = netfs_validate_stat (np, user->user);
if (err)
{
@@ -49,10 +51,10 @@ netfs_S_file_get_translator (struct protid *user,
unsigned int len = sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1;
if (len > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *)trans, len, 1);
- bcopy (_HURD_SYMLINK, *trans, sizeof _HURD_SYMLINK);
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ memcpy (*trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK);
- err = netfs_attempt_readlink (user->credential, np,
+ err = netfs_attempt_readlink (user->user, np,
*trans + sizeof _HURD_SYMLINK);
if (!err)
{
@@ -69,16 +71,21 @@ netfs_S_file_get_translator (struct protid *user,
(S_ISCHR (np->nn_stat.st_mode)
? _HURD_CHRDEV
: _HURD_BLKDEV),
- '\0', (np->nn_stat.st_rdev >> 8) & 0377,
- '\0', (np->nn_stat.st_rdev) & 0377);
- buflen++; /* terminating nul */
-
- if (buflen > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *) trans, buflen, 1);
- bcopy (buf, *trans, buflen);
- free (buf);
- *translen = buflen;
- err = 0;
+ '\0', major (np->nn_stat.st_rdev),
+ '\0', minor (np->nn_stat.st_rdev));
+ if (buflen < 0)
+ err = ENOMEM;
+ else
+ {
+ buflen++; /* terminating nul */
+
+ if (buflen > *translen)
+ *trans = mmap (0, buflen, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ memcpy (*trans, buf, buflen);
+ free (buf);
+ *translen = buflen;
+ err = 0;
+ }
}
else if (S_ISFIFO (np->nn_stat.st_mode))
{
@@ -86,8 +93,8 @@ netfs_S_file_get_translator (struct protid *user,
len = sizeof _HURD_FIFO;
if (len > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *) trans, len, 1);
- bcopy (_HURD_FIFO, *trans, sizeof _HURD_FIFO);
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ memcpy (*trans, _HURD_FIFO, sizeof _HURD_FIFO);
*translen = len;
err = 0;
}
@@ -97,8 +104,8 @@ netfs_S_file_get_translator (struct protid *user,
len = sizeof _HURD_IFSOCK;
if (len > *translen)
- vm_allocate (mach_task_self (), (vm_address_t *) trans, len, 1);
- bcopy (_HURD_IFSOCK, *trans, sizeof _HURD_IFSOCK);
+ *trans = mmap (0, len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ memcpy (*trans, _HURD_IFSOCK, sizeof _HURD_IFSOCK);
*translen = len;
err = 0;
}
@@ -109,4 +116,3 @@ netfs_S_file_get_translator (struct protid *user,
return err;
}
-
diff --git a/libnetfs/file-getcontrol.c b/libnetfs/file-getcontrol.c
index ccbd7541..50401f86 100644
--- a/libnetfs/file-getcontrol.c
+++ b/libnetfs/file-getcontrol.c
@@ -1,6 +1,6 @@
/* Return the filesystem corresponding to a file
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@
#include "netfs.h"
#include "fsys_S.h"
+#include <hurd/fshelp.h>
error_t
netfs_S_file_getcontrol (struct protid *user,
@@ -29,34 +30,22 @@ netfs_S_file_getcontrol (struct protid *user,
{
error_t err;
struct port_info *pi;
- uid_t *uids, *gids;
- int nuids, ngids;
- int i;
if (!user)
return EOPNOTSUPP;
- mutex_lock (&user->po->np->lock);
- netfs_interpret_credential (user->credential, &uids, &nuids, &gids, &ngids);
- mutex_unlock (&user->po->np->lock);
- free (gids);
-
- for (i = 0; i < nuids; i++)
- if (uids[i] == 0)
- {
- /* They've got root; give it to them. */
- free (uids);
- err = ports_create_port (netfs_control_class, netfs_port_bucket,
- sizeof (struct port_info), &pi);
- if (err)
- return err;
- *control = ports_get_right (pi);
- *controltype = MACH_MSG_TYPE_MAKE_SEND;
- ports_port_deref (pi);
- return 0;
- }
-
- /* Not got root. */
- free (uids);
- return EPERM;
+ err = fshelp_iscontroller (&netfs_root_node->nn_stat, user->user);
+ if (err)
+ return err;
+
+ /* They've have the appropriate credentials; give it to them. */
+ err = ports_create_port (netfs_control_class, netfs_port_bucket,
+ sizeof (struct port_info), &pi);
+ if (err)
+ return err;
+
+ *control = ports_get_right (pi);
+ *controltype = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (pi);
+ return 0;
}
diff --git a/libnetfs/file-reparent.c b/libnetfs/file-reparent.c
new file mode 100644
index 00000000..396a0a6b
--- /dev/null
+++ b/libnetfs/file-reparent.c
@@ -0,0 +1,74 @@
+/* Reparent a file
+
+ Copyright (C) 1997, 2001 Free Software Foundation
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "fs_S.h"
+
+error_t
+netfs_S_file_reparent (struct protid *cred, mach_port_t parent,
+ mach_port_t *new_file, mach_msg_type_name_t *new_file_type)
+{
+ error_t err;
+ struct node *node;
+ struct protid *new_cred;
+ struct iouser *user;
+
+ if (! cred)
+ return EOPNOTSUPP;
+
+ err = iohelp_dup_iouser (&user, cred->user);
+ if (err)
+ return err;
+
+ node = cred->po->np;
+
+ mutex_lock (&node->lock);
+
+ new_cred =
+ netfs_make_protid (netfs_make_peropen (node, cred->po->openstat, cred->po),
+ user);
+ mutex_unlock (&node->lock);
+
+ if (new_cred)
+ {
+ /* Remove old shadow root state. */
+ if (new_cred->po->shadow_root && new_cred->po->shadow_root != node)
+ {
+ mutex_lock (&new_cred->po->shadow_root->lock);
+ netfs_nput (new_cred->po->shadow_root);
+ }
+ if (new_cred->po->shadow_root_parent)
+ mach_port_deallocate (mach_task_self (), new_cred->po->shadow_root_parent);
+
+ /* And install PARENT instead. */
+ new_cred->po->shadow_root = node;
+ new_cred->po->shadow_root_parent = parent;
+
+ *new_file = ports_get_right (new_cred);
+ *new_file_type = MACH_MSG_TYPE_MAKE_SEND;
+
+ ports_port_deref (new_cred);
+
+ return 0;
+ }
+ else
+ return errno;
+}
diff --git a/libnetfs/file-set-size.c b/libnetfs/file-set-size.c
index 7463ccfe..7b253e04 100644
--- a/libnetfs/file-set-size.c
+++ b/libnetfs/file-set-size.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -31,7 +31,7 @@ netfs_S_file_set_size (struct protid *user,
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_set_size (user->credential, user->po->np, size);
+ err = netfs_attempt_set_size (user->user, user->po->np, size);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-set-translator.c b/libnetfs/file-set-translator.c
index 4307924a..a0a70dba 100644
--- a/libnetfs/file-set-translator.c
+++ b/libnetfs/file-set-translator.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1996, 1997, 1999, 2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -22,8 +22,6 @@
#include <hurd/paths.h>
#include <hurd/fsys.h>
-#define makedev(maj,min) ((((maj)&0xFF)<<8)+((min)&0xFF))
-
error_t
netfs_S_file_set_translator (struct protid *user,
int passive_flags, int active_flags,
@@ -33,46 +31,37 @@ netfs_S_file_set_translator (struct protid *user,
{
struct node *np;
error_t err = 0;
- uid_t *uids, *gids;
- int nuids, ngids;
- int i;
mach_port_t control;
if (!user)
return EOPNOTSUPP;
-
+
if (!(passive_flags & FS_TRANS_SET) && !(active_flags & FS_TRANS_SET))
return 0;
-
+
if (passive && passive[passivelen - 1])
return EINVAL;
-
+
np = user->po->np;
mutex_lock (&np->lock);
-
- if (active_flags & FS_TRANS_SET)
+
+ if (active_flags & FS_TRANS_SET
+ && ! (active_flags & FS_TRANS_ORPHAN))
{
/* Validate--user must be owner */
- netfs_interpret_credential (user->credential, &uids, &nuids,
- &gids, &ngids);
- err = netfs_validate_stat (np, user->credential);
+ err = netfs_validate_stat (np, user->user);
if (err)
goto out;
- for (i = 0; i < nuids; i++)
- if (uids[i] == 0 || uids[i] == np->nn_stat.st_uid)
- break;
- if (i == nuids)
- {
- mutex_unlock (&np->lock);
- return EBUSY;
- }
+ err = fshelp_isowner (&np->nn_stat, user->user);
+ if (err)
+ goto out;
err = fshelp_fetch_control (&np->transbox, &control);
if (err)
goto out;
-
- if (control != MACH_PORT_NULL
+
+ if (control != MACH_PORT_NULL
&& (active_flags & FS_TRANS_EXCL) == 0)
{
mutex_unlock (&np->lock);
@@ -87,13 +76,13 @@ netfs_S_file_set_translator (struct protid *user,
if ((passive_flags & FS_TRANS_SET)
&& (passive_flags & FS_TRANS_EXCL))
{
- err = netfs_validate_stat (np, user->credential);
- if (!err && np->istranslated)
+ err = netfs_validate_stat (np, user->user);
+ if (!err && (np->nn_stat.st_mode & S_IPTRANS))
err = EBUSY;
if (err)
goto out;
}
-
+
if (active_flags & FS_TRANS_SET)
{
err = fshelp_set_active (&np->transbox, active,
@@ -101,7 +90,7 @@ netfs_S_file_set_translator (struct protid *user,
if (err)
goto out;
}
-
+
if (passive_flags & FS_TRANS_SET)
{
mode_t newmode = 0;
@@ -120,12 +109,12 @@ netfs_S_file_set_translator (struct protid *user,
else if (!strcmp (passive, _HURD_IFSOCK))
newmode = S_IFSOCK;
}
-
+
switch (newmode)
{
int major, minor;
char *arg;
-
+
case S_IFBLK:
case S_IFCHR:
/* Find the device number from the arguments
@@ -138,7 +127,7 @@ netfs_S_file_set_translator (struct protid *user,
return EINVAL;
}
major = strtol (arg, 0, 0);
-
+
arg = arg + strlen (arg) + 1;
assert (arg < passive + passivelen);
if (arg == passive + passivelen)
@@ -147,13 +136,13 @@ netfs_S_file_set_translator (struct protid *user,
return EINVAL;
}
minor = strtol (arg, 0, 0);
-
- err = netfs_attempt_mkdev (user->credential, np,
+
+ err = netfs_attempt_mkdev (user->user, np,
newmode, makedev (major, minor));
if (err == EOPNOTSUPP)
goto fallback;
break;
-
+
case S_IFLNK:
arg = passive + strlen (passive) + 1;
assert (arg <= passive + passivelen);
@@ -162,30 +151,30 @@ netfs_S_file_set_translator (struct protid *user,
mutex_unlock (&np->lock);
return EINVAL;
}
-
- err = netfs_attempt_mksymlink (user->credential, np, arg);
+
+ err = netfs_attempt_mksymlink (user->user, np, arg);
if (err == EOPNOTSUPP)
goto fallback;
break;
default:
- err = netfs_validate_stat (np, user->credential);
+ err = netfs_validate_stat (np, user->user);
if (!err)
- err = netfs_attempt_chmod (user->credential, np,
+ err = netfs_attempt_chmod (user->user, np,
((np->nn_stat.st_mode & ~S_IFMT)
| newmode));
if (err == EOPNOTSUPP)
goto fallback;
break;
-
+
case 0:
fallback:
- err = netfs_set_translator (user->credential, np,
+ err = netfs_set_translator (user->user, np,
passive, passivelen);
break;
}
}
-
+
out:
mutex_unlock (&np->lock);
return err;
diff --git a/libnetfs/file-statfs.c b/libnetfs/file-statfs.c
index 52e95272..180d29fc 100644
--- a/libnetfs/file-statfs.c
+++ b/libnetfs/file-statfs.c
@@ -31,7 +31,7 @@ netfs_S_file_statfs (struct protid *user,
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_statfs (user->credential, user->po->np, st);
+ err = netfs_attempt_statfs (user->user, user->po->np, st);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-sync.c b/libnetfs/file-sync.c
index 95bc0529..99492ed8 100644
--- a/libnetfs/file-sync.c
+++ b/libnetfs/file-sync.c
@@ -32,7 +32,7 @@ netfs_S_file_sync (struct protid *user,
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_sync (user->credential, user->po->np, wait);
+ err = netfs_attempt_sync (user->user, user->po->np, wait);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-syncfs.c b/libnetfs/file-syncfs.c
index 13af70ff..28e34a3a 100644
--- a/libnetfs/file-syncfs.c
+++ b/libnetfs/file-syncfs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -34,7 +34,7 @@ netfs_S_file_syncfs (struct protid *user,
/* Translators not yet supported by netfs. XXX */
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_syncfs (user->credential, wait);
+ err = netfs_attempt_syncfs (user->user, wait);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/file-utimes.c b/libnetfs/file-utimes.c
index f641c8da..45adf825 100644
--- a/libnetfs/file-utimes.c
+++ b/libnetfs/file-utimes.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,17 +28,26 @@ netfs_S_file_utimes (struct protid *user,
{
struct timespec atime, mtime;
error_t err;
+
+ if (atimein.microseconds != -1)
+ {
+ atime.tv_sec = atimein.seconds;
+ atime.tv_nsec = atimein.microseconds * 1000;
+ }
- atime.tv_sec = atimein.seconds;
- atime.tv_nsec = atimein.microseconds * 1000;
- mtime.tv_sec = mtimein.seconds;
- mtime.tv_nsec = mtimein.microseconds * 1000;
+ if (mtimein.microseconds != -1)
+ {
+ mtime.tv_sec = mtimein.seconds;
+ mtime.tv_nsec = mtimein.microseconds * 1000;
+ }
if (!user)
return EOPNOTSUPP;
mutex_lock (&user->po->np->lock);
- err = netfs_attempt_utimes (user->credential, user->po->np, &atime, &mtime);
+ err = netfs_attempt_utimes (user->user, user->po->np,
+ atimein.microseconds != -1 ? &atime : 0,
+ mtimein.microseconds != -1 ? &mtime : 0);
mutex_unlock (&user->po->np->lock);
return err;
}
diff --git a/libnetfs/fsstubs.c b/libnetfs/fsstubs.c
index d64cbc93..708cbb82 100644
--- a/libnetfs/fsstubs.c
+++ b/libnetfs/fsstubs.c
@@ -1,6 +1,6 @@
/* Unimplemented rpcs from <hurd/fs.defs>
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -50,21 +50,3 @@ netfs_S_ifsock_getsockaddr (struct protid *user,
{
return EOPNOTSUPP;
}
-
-error_t
-netfs_S_io_pathconf (struct protid *user,
- int name,
- int *value)
-{
- return EOPNOTSUPP;
-}
-
-error_t
-netfs_S_io_server_version (struct protid *user,
- char *name,
- int *major,
- int *minor,
- int *edit)
-{
- return EOPNOTSUPP;
-}
diff --git a/libnetfs/fsys-get-options.c b/libnetfs/fsys-get-options.c
index 35c21d3a..fa045eff 100644
--- a/libnetfs/fsys-get-options.c
+++ b/libnetfs/fsys-get-options.c
@@ -1,6 +1,6 @@
/* Unparse run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998, 2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -32,28 +32,36 @@
/* Implement fsys_get_options as described in <hurd/fsys.defs>. */
error_t
netfs_S_fsys_get_options (fsys_t fsys,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
char **data, mach_msg_type_number_t *data_len)
{
error_t err;
- char *argz;
- size_t argz_len;
+ char *argz = 0;
+ size_t argz_len = 0;
struct port_info *port =
ports_lookup_port (netfs_port_bucket, fsys, netfs_control_class);
if (!port)
return EOPNOTSUPP;
+ err = argz_add (&argz, &argz_len, program_invocation_name);
+ if (! err)
+ {
#if NOT_YET
- rwlock_reader_lock (&netfs_fsys_lock);
+ rwlock_reader_lock (&netfs_fsys_lock);
#endif
- err = netfs_get_options (&argz, &argz_len);
+ err = netfs_append_args (&argz, &argz_len);
#if NOT_YET
- rwlock_reader_unlock (&netfs_fsys_lock);
+ rwlock_reader_unlock (&netfs_fsys_lock);
#endif
+ }
if (! err)
/* Move ARGZ from a malloced buffer into a vm_alloced one. */
- err = fshelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ err = iohelp_return_malloced_buffer (argz, argz_len, data, data_len);
+ else
+ free (argz);
ports_port_deref (port);
diff --git a/libnetfs/fsys-getroot.c b/libnetfs/fsys-getroot.c
index f7f40385..d3e78332 100644
--- a/libnetfs/fsys-getroot.c
+++ b/libnetfs/fsys-getroot.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1996,97,2001,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -26,6 +26,8 @@
error_t
netfs_S_fsys_getroot (mach_port_t cntl,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
mach_port_t dotdot,
uid_t *uids, mach_msg_type_number_t nuids,
uid_t *gids, mach_msg_type_number_t ngids,
@@ -33,43 +35,46 @@ netfs_S_fsys_getroot (mach_port_t cntl,
retry_type *do_retry,
char *retry_name,
mach_port_t *retry_port,
- mach_port_t *retry_port_type)
+ mach_msg_type_name_t *retry_port_type)
{
struct port_info *pt = ports_lookup_port (netfs_port_bucket, cntl,
netfs_control_class);
- struct netcred *cred;
+ struct iouser *cred;
error_t err;
struct protid *newpi;
mode_t type;
+ struct peropen peropen_context = { root_parent: dotdot };
if (!pt)
return EOPNOTSUPP;
ports_port_deref (pt);
- cred = netfs_make_credential (uids, nuids, gids, ngids);
-
+ err = iohelp_create_complex_iouser (&cred, uids, nuids, gids, ngids);
+ if (err)
+ return err;
+
flags &= O_HURD;
-
+
mutex_lock (&netfs_root_node->lock);
err = netfs_validate_stat (netfs_root_node, cred);
if (err)
goto out;
-
+
type = netfs_root_node->nn_stat.st_mode & S_IFMT;
- if ((netfs_root_node->istranslated
+ if (((netfs_root_node->nn_stat.st_mode & S_IPTRANS)
|| fshelp_translated (&netfs_root_node->transbox))
&& !(flags & O_NOTRANS))
{
err = fshelp_fetch_root (&netfs_root_node->transbox,
- &dotdot, dotdot, uids, nuids,
- gids, ngids, flags,
+ &peropen_context, dotdot, cred, flags,
_netfs_translator_callback1,
_netfs_translator_callback2,
do_retry, retry_name, retry_port);
if (err != ENOENT)
{
mutex_unlock (&netfs_root_node->lock);
+ iohelp_free_iouser (cred);
if (!err)
*retry_port_type = MACH_MSG_TYPE_MOVE_SEND;
return err;
@@ -77,17 +82,19 @@ netfs_S_fsys_getroot (mach_port_t cntl,
/* ENOENT means translator has vanished inside fshelp_fetch_root. */
err = 0;
}
-
+
if (type == S_IFLNK && !(flags & (O_NOLINK | O_NOTRANS)))
{
char pathbuf[netfs_root_node->nn_stat.st_size + 1];
-
+
err = netfs_attempt_readlink (cred, netfs_root_node, pathbuf);
- mutex_unlock (&netfs_root_node->lock);
if (err)
goto out;
-
+
+ mutex_unlock (&netfs_root_node->lock);
+ iohelp_free_iouser (cred);
+
if (pathbuf[0] == '/')
{
*do_retry = FS_RETRY_MAGICAL;
@@ -106,34 +113,34 @@ netfs_S_fsys_getroot (mach_port_t cntl,
return 0;
}
}
-
- if ((type == S_IFSOCK || type == S_IFBLK || type == S_IFCHR
+
+ if ((type == S_IFSOCK || type == S_IFBLK || type == S_IFCHR
|| type == S_IFIFO) && (flags & (O_READ|O_WRITE|O_EXEC)))
{
- mutex_unlock (&netfs_root_node->lock);
- return EOPNOTSUPP;
+ err = EOPNOTSUPP;
+ goto out;
}
-
+
err = netfs_check_open_permissions (cred, netfs_root_node, flags, 0);
if (err)
goto out;
-
+
flags &= ~OPENONLY_STATE_MODES;
-
+
newpi = netfs_make_protid (netfs_make_peropen (netfs_root_node, flags,
- dotdot),
+ &peropen_context),
cred);
mach_port_deallocate (mach_task_self (), dotdot);
+
*do_retry = FS_RETRY_NORMAL;
*retry_port = ports_get_right (newpi);
*retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
retry_name[0] = '\0';
ports_port_deref (newpi);
-
+
out:
+ if (err)
+ iohelp_free_iouser (cred);
mutex_unlock (&netfs_root_node->lock);
return err;
}
-
-
-
diff --git a/libmom/reserve-memory.c b/libnetfs/fsys-goaway.c
index ada9ef02..0ac36d3c 100644
--- a/libmom/reserve-memory.c
+++ b/libnetfs/fsys-goaway.c
@@ -1,6 +1,5 @@
-/* Reserve memory
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* implement the fsys_goaway RPC for libnetfs
+ Copyright (C) 2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -18,25 +17,36 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+#include "netfs.h"
+#include "fsys_S.h"
+#include "fsys_reply_U.h"
-#include "priv.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <hurd/ports.h>
error_t
-mom_reserve_memory (void *start, size_t len)
+netfs_S_fsys_goaway (fsys_t control,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int flags)
{
error_t err;
-
- assert ((vm_address_t) start % vm_page_size == 0);
- assert (len % vm_page_size == 0);
-
- mutex_lock (&_mom_memory_lock);
- err = vm_map (mach_task_self (), (vm_address_t *)&start, len, 0, 0,
- MACH_PORT_NULL, 0, 0, 0,
- VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE,
- VM_INHERIT_COPY);
- mutex_unlock (&_mom_memory_lock);
-
+ struct port_info *pt;
+
+ pt = ports_lookup_port (netfs_port_bucket, control,
+ netfs_control_class);
+ if (! pt)
+ return EOPNOTSUPP;
+
+ err = netfs_shutdown (flags);
+ if (! err)
+ {
+ fsys_goaway_reply (reply, reply_type, 0);
+ exit (0);
+ }
+
+ ports_port_deref (pt);
+
return err;
}
-
-
diff --git a/libnetfs/fsys-set-options.c b/libnetfs/fsys-set-options.c
index 8abd5a16..38f06c16 100644
--- a/libnetfs/fsys-set-options.c
+++ b/libnetfs/fsys-set-options.c
@@ -1,6 +1,6 @@
/* Parse run-time options
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -32,6 +32,8 @@
/* Implement fsys_set_options as described in <hurd/fsys.defs>. */
error_t
netfs_S_fsys_set_options (fsys_t fsys,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
char *data, mach_msg_type_number_t data_len,
int do_children)
{
diff --git a/libnetfs/fsys-syncfs.c b/libnetfs/fsys-syncfs.c
index b652890e..f57cb144 100644
--- a/libnetfs/fsys-syncfs.c
+++ b/libnetfs/fsys-syncfs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -23,15 +23,18 @@
error_t
netfs_S_fsys_syncfs (mach_port_t cntl,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
int wait,
int children)
{
- struct netcred *cred;
- uid_t root = 0;
+ struct iouser *cred;
error_t err;
- cred = netfs_make_credential (&root, 1, &root, 1);
+ err = iohelp_create_simple_iouser (&cred, 0, 0);
+ if (err)
+ return err;
err = netfs_attempt_syncfs (cred, wait);
- netfs_drop_credential (cred);
+ iohelp_free_iouser (cred);
return err;
}
diff --git a/libnetfs/fsysstubs.c b/libnetfs/fsysstubs.c
index bed52b18..f44155da 100644
--- a/libnetfs/fsysstubs.c
+++ b/libnetfs/fsysstubs.c
@@ -1,6 +1,6 @@
/* Unimplemented rpcs from <hurd/fsys.defs>
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -24,6 +24,8 @@
error_t
netfs_S_fsys_getfile (fsys_t cntl,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
uid_t *uids, mach_msg_type_number_t nuids,
gid_t *gids, mach_msg_type_number_t ngids,
char *handle, mach_msg_type_number_t handlelen,
@@ -34,6 +36,8 @@ netfs_S_fsys_getfile (fsys_t cntl,
error_t
netfs_S_fsys_getpriv (fsys_t cntl,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
mach_port_t *host, mach_msg_type_name_t *hosttp,
mach_port_t *dev, mach_msg_type_name_t *devtp,
mach_port_t *fs, mach_msg_type_name_t *fstp)
@@ -43,7 +47,8 @@ netfs_S_fsys_getpriv (fsys_t cntl,
error_t
netfs_S_fsys_init (fsys_t cntl,
- mach_port_t reply, mach_msg_type_name_t replytp,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
mach_port_t proc, auth_t auth)
{
return EOPNOTSUPP;
@@ -51,6 +56,8 @@ netfs_S_fsys_init (fsys_t cntl,
error_t
netfs_S_fsys_forward (fsys_t cntl,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
mach_port_t request,
char *argv, mach_msg_type_number_t argvlen)
{
@@ -59,6 +66,8 @@ netfs_S_fsys_forward (fsys_t cntl,
error_t
netfs_S_fsys_startup (mach_port_t bootstrap,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
int flags,
mach_port_t contrl,
mach_port_t *realnod,
@@ -66,10 +75,3 @@ netfs_S_fsys_startup (mach_port_t bootstrap,
{
return EOPNOTSUPP;
}
-
-error_t
-netfs_S_fsys_goaway (mach_port_t cntl,
- int flags)
-{
- return EOPNOTSUPP;
-}
diff --git a/libnetfs/init-loop.c b/libnetfs/init-loop.c
index 921b3924..08bdcd18 100644
--- a/libnetfs/init-loop.c
+++ b/libnetfs/init-loop.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -34,7 +34,7 @@ netfs_server_loop ()
netfs_demuxer,
thread_timeout,
server_timeout,
- 1, MACH_PORT_NULL);
+ 0);
err = netfs_shutdown (0);
}
while (err);
diff --git a/libnetfs/init-startup.c b/libnetfs/init-startup.c
index 669aa66e..2e0f43a8 100644
--- a/libnetfs/init-startup.c
+++ b/libnetfs/init-startup.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,2000,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,35 +18,35 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include "netfs.h"
#include <stdio.h>
+#include <error.h>
#include <hurd/fsys.h>
+#include "netfs.h"
mach_port_t
netfs_startup (mach_port_t bootstrap, int flags)
{
- mach_port_t realnode;
+ error_t err;
+ mach_port_t realnode, right;
struct port_info *newpi;
if (bootstrap == MACH_PORT_NULL)
- {
- fprintf (stderr, "Must be started as a translator...\n");
- exit (1);
- }
+ error (10, 0, "Must be started as a translator");
- errno = ports_create_port (netfs_control_class, netfs_port_bucket,
+ err = ports_create_port (netfs_control_class, netfs_port_bucket,
sizeof (struct port_info), &newpi);
- if (!errno)
+ if (!err)
{
- errno = fsys_startup (bootstrap, flags, ports_get_right (newpi),
- MACH_MSG_TYPE_MAKE_SEND, &realnode);
+ right = ports_get_send_right (newpi);
+ err = fsys_startup (bootstrap, flags, right, MACH_MSG_TYPE_COPY_SEND,
+ &realnode);
+ mach_port_deallocate (mach_task_self (), right);
ports_port_deref (newpi);
}
- if (errno)
- {
- perror ("Translator startup failure: fsys_startup");
- exit (1);
- }
+ if (err)
+ error (11, err, "Translator startup failure: fsys_startup");
+
mach_port_deallocate (mach_task_self (), bootstrap);
+
return realnode;
}
diff --git a/libnetfs/io-duplicate.c b/libnetfs/io-duplicate.c
index ba3954af..ad374fc9 100644
--- a/libnetfs/io-duplicate.c
+++ b/libnetfs/io-duplicate.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -26,11 +26,16 @@ netfs_S_io_duplicate (struct protid *user,
mach_port_t *newport,
mach_msg_type_name_t *newporttp)
{
+ error_t err;
struct protid *newpi;
+ struct iouser *clone;
+
+ err = iohelp_dup_iouser (&clone, user->user);
+ if (err)
+ return err;
mutex_lock (&user->po->np->lock);
- newpi = netfs_make_protid (user->po,
- netfs_copy_credential (user->credential));
+ newpi = netfs_make_protid (user->po, clone);
*newport = ports_get_right (newpi);
mutex_unlock (&user->po->np->lock);
*newporttp = MACH_MSG_TYPE_MAKE_SEND;
diff --git a/libnetfs/io-identity.c b/libnetfs/io-identity.c
index 0656b4dc..e62a01e4 100644
--- a/libnetfs/io-identity.c
+++ b/libnetfs/io-identity.c
@@ -1,5 +1,5 @@
/* libnetfs implementation of io_identity RPC
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -27,18 +27,18 @@ netfs_S_io_identity (struct protid *cred,
mach_msg_type_name_t *idtype,
mach_port_t *fsys,
mach_msg_type_name_t *fsystype,
- int *fileno)
+ ino_t *fileno)
{
struct node *np;
error_t err;
-
+
if (!cred)
return EOPNOTSUPP;
-
+
np = cred->po->np;
mutex_lock (&np->lock);
-
- err = netfs_validate_stat (np, cred->credential);
+
+ err = netfs_validate_stat (np, cred->user);
if (err)
{
mutex_unlock (&np->lock);
@@ -55,7 +55,7 @@ netfs_S_io_identity (struct protid *cred,
*fsys = netfs_fsys_identity;
*fsystype = MACH_MSG_TYPE_MAKE_SEND;
*fileno = np->nn_stat.st_ino;
-
+
mutex_unlock (&np->lock);
return 0;
}
diff --git a/libnetfs/io-pathconf.c b/libnetfs/io-pathconf.c
new file mode 100644
index 00000000..2fd3f5bc
--- /dev/null
+++ b/libnetfs/io-pathconf.c
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include "netfs.h"
+#include "io_S.h"
+
+
+error_t
+netfs_S_io_pathconf (struct protid *user,
+ int name,
+ int *value)
+{
+ if (!user)
+ return EOPNOTSUPP;
+
+ switch (name)
+ {
+ case _PC_LINK_MAX:
+ case _PC_MAX_CANON:
+ case _PC_MAX_INPUT:
+ case _PC_PIPE_BUF:
+ case _PC_VDISABLE:
+ case _PC_SOCK_MAXBUF:
+ case _PC_PATH_MAX:
+ *value = -1;
+ break;
+
+ case _PC_NAME_MAX:
+ *value = 1024; /* see <hurd/hurd_types.defs> string_t */
+ break;
+
+ case _PC_CHOWN_RESTRICTED:
+ case _PC_NO_TRUNC: /* look at string_t trunc behavior in MiG */
+ *value = 1;
+ break;
+
+ case _PC_PRIO_IO:
+ case _PC_SYNC_IO:
+ case _PC_ASYNC_IO:
+ *value = 0;
+ break;
+
+ case _PC_FILESIZEBITS:
+ *value = 32;
+ break;
+
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
diff --git a/libnetfs/io-read.c b/libnetfs/io-read.c
index 54914935..ff8fbcff 100644
--- a/libnetfs/io-read.c
+++ b/libnetfs/io-read.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@
#include "netfs.h"
#include "io_S.h"
#include <fcntl.h>
+#include <sys/mman.h>
error_t
netfs_S_io_read (struct protid *user,
@@ -30,41 +31,79 @@ netfs_S_io_read (struct protid *user,
mach_msg_type_number_t amount)
{
error_t err;
+ off_t start;
+ struct node *node;
int alloced = 0;
if (!user)
return EOPNOTSUPP;
+ node = user->po->np;
mutex_lock (&user->po->np->lock);
if ((user->po->openstat & O_READ) == 0)
{
- mutex_unlock (&user->po->np->lock);
+ mutex_unlock (&node->lock);
return EBADF;
}
if (amount > *datalen)
{
alloced = 1;
- vm_allocate (mach_task_self (), (vm_address_t *) data, amount, 1);
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
}
*datalen = amount;
- err = netfs_attempt_read (user->credential, user->po->np,
- offset == -1 ? user->po->filepointer : offset,
- datalen, *data);
+ start = (offset == -1 ? user->po->filepointer : offset);
+
+ if (start < 0)
+ err = EINVAL;
+ else if (S_ISLNK (node->nn_stat.st_mode))
+ /* Read from a symlink. */
+ {
+ off_t size = node->nn_stat.st_size;
+
+ if (start + amount > size)
+ amount = size - start;
+ if (amount > size)
+ amount = size;
+
+ if (start >= size)
+ {
+ *datalen = 0;
+ err = 0;
+ }
+ else if (amount < size || start > 0)
+ {
+ char *whole_link = alloca (size);
+ err = netfs_attempt_readlink (user->user, node, whole_link);
+ if (! err)
+ {
+ memcpy (*data, whole_link + start, amount);
+ *datalen = amount;
+ }
+ }
+ else
+ {
+ err = netfs_attempt_readlink (user->user, node, *data);
+ *datalen = amount;
+ }
+ }
+ else
+ /* Read from a normal file. */
+ err = netfs_attempt_read (user->user, node, start, datalen, *data);
+
if (offset == -1 && !err)
user->po->filepointer += *datalen;
- mutex_unlock (&user->po->np->lock);
+
+ mutex_unlock (&node->lock);
if (err && alloced)
- vm_deallocate (mach_task_self (), (vm_address_t) *data, amount);
+ munmap (*data, amount);
if (!err && alloced && (round_page (*datalen) < round_page (amount)))
- vm_deallocate (mach_task_self (),
- (vm_address_t) *data + round_page (*datalen),
- round_page (amount) - round_page (*datalen));
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
return err;
}
-
diff --git a/libnetfs/io-readable.c b/libnetfs/io-readable.c
index 13b0346d..ad6bf3c1 100644
--- a/libnetfs/io-readable.c
+++ b/libnetfs/io-readable.c
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -36,7 +36,7 @@ netfs_S_io_readable (struct protid *user,
return EINVAL;
mutex_lock (&user->po->np->lock);
- err = netfs_validate_stat (user->po->np, user->credential);
+ err = netfs_validate_stat (user->po->np, user->user);
if (!err)
{
if (user->po->np->nn_stat.st_size > user->po->filepointer)
diff --git a/libnetfs/io-reauthenticate.c b/libnetfs/io-reauthenticate.c
index dff3af8f..3140499c 100644
--- a/libnetfs/io-reauthenticate.c
+++ b/libnetfs/io-reauthenticate.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,2000,01 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -24,66 +24,30 @@
error_t
netfs_S_io_reauthenticate (struct protid *user, mach_port_t rend_port)
{
- struct protid *newpi;
- uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
- uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
- u_int genuidlen, gengidlen, auxuidlen, auxgidlen;
error_t err;
+ struct protid *newpi;
mach_port_t newright;
-
+
if (!user)
return EOPNOTSUPP;
-
- genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
- gen_uids = gubuf;
- gen_gids = ggbuf;
- aux_uids = aubuf;
- aux_gids = agbuf;
-
+
mutex_lock (&user->po->np->lock);
newpi = netfs_make_protid (user->po, 0);
- newright = ports_get_right (newpi);
- err = mach_port_insert_right (mach_task_self (), newright, newright,
- MACH_MSG_TYPE_MAKE_SEND);
- assert_perror (err);
- do
- err = auth_server_authenticate (netfs_auth_server_port,
- rend_port,
- MACH_MSG_TYPE_COPY_SEND,
- newright,
- MACH_MSG_TYPE_COPY_SEND,
- &gen_uids, &genuidlen,
- &aux_uids, &auxuidlen,
- &gen_gids, &gengidlen,
- &aux_uids, &auxuidlen);
- while (err == EINTR);
+ newright = ports_get_send_right (newpi);
+ assert (newright != MACH_PORT_NULL);
+
+ err = iohelp_reauth (&newpi->user, netfs_auth_server_port, rend_port,
+ newright, 1);
+
mach_port_deallocate (mach_task_self (), rend_port);
mach_port_deallocate (mach_task_self (), newright);
- if (err)
- newpi->credential = netfs_make_credential (0, 0, 0, 0);
- else
- newpi->credential = netfs_make_credential (gen_uids, genuidlen,
- gen_gids, gengidlen);
-
mach_port_move_member (mach_task_self (), newpi->pi.port_right,
netfs_port_bucket->portset);
mutex_unlock (&user->po->np->lock);
ports_port_deref (newpi);
- if (gen_uids != gubuf)
- vm_deallocate (mach_task_self (), (vm_address_t) gen_uids,
- genuidlen * sizeof (uid_t));
- if (aux_uids != aubuf)
- vm_deallocate (mach_task_self (), (vm_address_t) aux_uids,
- auxuidlen * sizeof (uid_t));
- if (gen_gids != ggbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) gen_gids,
- gengidlen * sizeof (uid_t));
- if (aux_gids != agbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) aux_gids,
- auxgidlen * sizeof (uid_t));
- return 0;
+ return err;
}
diff --git a/libnetfs/io-restrict-auth.c b/libnetfs/io-restrict-auth.c
index 1a175a35..bddc8fea 100644
--- a/libnetfs/io-restrict-auth.c
+++ b/libnetfs/io-restrict-auth.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,2001,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -21,16 +21,6 @@
#include "netfs.h"
#include "io_S.h"
-static inline int
-listmember (int *list, int query, int n)
-{
- int i;
- for (i = 0; i < n; i++)
- if (list[i] == query)
- return 1;
- return 0;
-}
-
error_t
netfs_S_io_restrict_auth (struct protid *user,
mach_port_t *newport,
@@ -40,33 +30,33 @@ netfs_S_io_restrict_auth (struct protid *user,
gid_t *gids,
mach_msg_type_number_t ngids)
{
- uid_t *newuids, *newgids, *olduids, *oldgids;
- int i, newnuids, newngids, oldnuids, oldngids;
+ error_t err;
struct protid *newpi;
-
+ struct iouser *new_user;
+
if (!user)
return EOPNOTSUPP;
-
+
+ err = iohelp_restrict_iouser (&new_user, user->user,
+ uids, nuids, gids, ngids);
+ if (err)
+ return err;
+
mutex_lock (&user->po->np->lock);
- netfs_interpret_credential (user->credential, &olduids, &oldnuids,
- &oldgids, &oldngids);
- newuids = alloca (sizeof (uid_t) * oldnuids);
- newgids = alloca (sizeof (gid_t) * oldngids);
- for (i = newnuids = 0; i < oldnuids; i++)
- if (listmember (uids, olduids[i], nuids))
- newuids[newnuids++] = olduids[i];
- for (i = newngids = 0; i < oldngids; i++)
- if (listmember (gids, oldgids[i], ngids))
- newgids[newngids++] = oldgids[i];
-
- newpi = netfs_make_protid (user->po,
- netfs_make_credential (newuids, newnuids,
- newgids, newngids));
- *newport = ports_get_right (newpi);
- mutex_unlock (&user->po->np->lock);
-
- *newporttype = MACH_MSG_TYPE_MAKE_SEND;
+ newpi = netfs_make_protid (user->po, new_user);
+ if (newpi)
+ {
+ *newport = ports_get_right (newpi);
+ mutex_unlock (&user->po->np->lock);
+ *newporttype = MACH_MSG_TYPE_MAKE_SEND;
+ }
+ else
+ {
+ mutex_unlock (&user->po->np->lock);
+ iohelp_free_iouser (new_user);
+ err = ENOMEM;
+ }
+
ports_port_deref (newpi);
- return 0;
+ return err;
}
-
diff --git a/libnetfs/io-revoke.c b/libnetfs/io-revoke.c
new file mode 100644
index 00000000..5b32622a
--- /dev/null
+++ b/libnetfs/io-revoke.c
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 1999 Free Software Foundation
+ Written by Thomas Bushnell, BSG.
+
+ 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. */
+
+#include "netfs.h"
+#include "io_S.h"
+
+/* Implement io_revoke as described in <hurd/io.defs>. */
+kern_return_t
+netfs_S_io_revoke (struct protid *cred)
+{
+ error_t err;
+ struct node *np;
+
+ error_t iterator_function (void *port)
+ {
+ struct protid *user = port;
+
+ if ((user != cred)
+ && (user->po->np == np))
+ ports_destroy_right (user);
+ return 0;
+ }
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+
+ mutex_lock (&np->lock);
+
+ err = netfs_validate_stat (np, cred->user);
+ if (!err)
+ err = fshelp_isowner (&np->nn_stat, cred->user);
+
+ mutex_unlock (&np->lock);
+
+ if (err)
+ return err;
+
+ ports_inhibit_bucket_rpcs (netfs_port_bucket);
+ ports_class_iterate (netfs_protid_class, iterator_function);
+ ports_resume_bucket_rpcs (netfs_port_bucket);
+
+ return 0;
+}
diff --git a/libnetfs/io-seek.c b/libnetfs/io-seek.c
index 55d924c8..85408a4d 100644
--- a/libnetfs/io-seek.c
+++ b/libnetfs/io-seek.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000, 2006 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,36 +28,41 @@ netfs_S_io_seek (struct protid *user,
int whence,
off_t *newoffset)
{
- error_t err;
+ error_t err = 0;
if (!user)
return EOPNOTSUPP;
- mutex_lock (&user->po->np->lock);
switch (whence)
{
- case SEEK_SET:
- err = 0;
- user->po->filepointer = offset;
- break;
-
case SEEK_CUR:
- err = 0;
- user->po->filepointer += offset;
- break;
-
+ offset += user->po->filepointer;
+ goto check;
case SEEK_END:
- err = netfs_validate_stat (user->po->np, user->credential);
- if (!err)
- user->po->filepointer = user->po->np->nn_stat.st_size + offset;
- break;
-
+ {
+ struct node *np;
+
+ np = user->po->np;
+ mutex_lock (&np->lock);
+
+ err = netfs_validate_stat (np, user->user);
+ if (!err)
+ offset += np->nn_stat.st_size;
+
+ mutex_unlock (&np->lock);
+ }
+ case SEEK_SET:
+ check:
+ if (offset >= 0)
+ {
+ *newoffset = user->po->filepointer = offset;
+ break;
+ }
default:
err = EINVAL;
break;
}
- *newoffset = user->po->filepointer;
- mutex_unlock (&user->po->np->lock);
+
return err;
}
diff --git a/libnetfs/io-select.c b/libnetfs/io-select.c
index 07ce9e75..c72eba6b 100644
--- a/libnetfs/io-select.c
+++ b/libnetfs/io-select.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2004 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,9 +20,12 @@
#include "netfs.h"
#include "io_S.h"
+#include <hurd/ports.h>
error_t
netfs_S_io_select (struct protid *user,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
int *type)
{
if (!user)
diff --git a/libnetfs/io-stat.c b/libnetfs/io-stat.c
index 0e4f5d6f..3826c9d9 100644
--- a/libnetfs/io-stat.c
+++ b/libnetfs/io-stat.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -23,19 +23,32 @@
#include <string.h>
error_t
-netfs_S_io_stat (struct protid *fileuser,
- io_statbuf_t *statbuf)
+netfs_S_io_stat (struct protid *user, io_statbuf_t *statbuf)
{
error_t err;
+ struct node *node;
- if (!fileuser)
+ if (! user)
return EOPNOTSUPP;
- mutex_lock (&fileuser->po->np->lock);
- err = netfs_validate_stat (fileuser->po->np, fileuser->credential);
- if (!err)
- bcopy (&fileuser->po->np->nn_stat, statbuf, sizeof (struct stat));
- mutex_unlock (&fileuser->po->np->lock);
+ node = user->po->np;
+ mutex_lock (&node->lock);
+
+ err = netfs_validate_stat (node, user->user);
+ if (! err)
+ {
+ memcpy (statbuf, &node->nn_stat, sizeof (struct stat));
+
+ /* Set S_IATRANS and S_IROOT bits as appropriate. */
+ statbuf->st_mode &= ~(S_IATRANS | S_IROOT);
+ if (fshelp_translated (&node->transbox))
+ statbuf->st_mode |= S_IATRANS; /* Has an active translator. */
+ if (user->po->shadow_root == node || node == netfs_root_node)
+ statbuf->st_mode |= S_IROOT; /* Is a root node. */
+ }
+
+ mutex_unlock (&node->lock);
+
return err;
}
diff --git a/libdiskfs/interrupt.c b/libnetfs/io-version.c
index ffd7fb83..d38b194a 100644
--- a/libdiskfs/interrupt.c
+++ b/libnetfs/io-version.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1994, 1996, 2002 Free Software Foundation
This file is part of the GNU Hurd.
@@ -19,21 +19,22 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
-#include "priv.h"
-#include "interrupt_S.h"
+#include <stdio.h>
+
+#include "netfs.h"
+#include "io_S.h"
kern_return_t
-diskfs_S_interrupt_operation (mach_port_t handle)
+netfs_S_io_server_version (struct protid *cred,
+ char *server_name,
+ int *major,
+ int *minor,
+ int *edit)
{
- struct port_info *pi;
-
- pi = ports_lookup_port (diskfs_port_bucket, handle, 0);
- if (!pi)
+ if (!cred)
return EOPNOTSUPP;
-
- ports_interrupt_rpc (pi);
-
- ports_port_deref (pi);
+ snprintf (server_name, sizeof (string_t), "%s %s",
+ netfs_server_name, netfs_server_version);
return 0;
}
diff --git a/libnetfs/io-write.c b/libnetfs/io-write.c
index c299d15c..c4423dab 100644
--- a/libnetfs/io-write.c
+++ b/libnetfs/io-write.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -36,22 +36,19 @@ netfs_S_io_write (struct protid *user,
if (!user)
return EOPNOTSUPP;
- np = user->po->np;
-
- mutex_lock (&np->lock);
if ((user->po->openstat & O_WRITE) == 0)
- {
- mutex_unlock (&np->lock);
- return EBADF;
- }
+ return EBADF;
*amount = datalen;
+ np = user->po->np;
+ mutex_lock (&np->lock);
+
if (off == -1)
{
if (user->po->openstat & O_APPEND)
{
- err = netfs_validate_stat (np, user->credential);
+ err = netfs_validate_stat (np, user->user);
if (err)
{
mutex_unlock (&np->lock);
@@ -62,7 +59,7 @@ netfs_S_io_write (struct protid *user,
off = user->po->filepointer;
}
- err = netfs_attempt_write (user->credential, np, off, amount, data);
+ err = netfs_attempt_write (user->user, np, off, amount, data);
if (offset == -1 && !err)
user->po->filepointer += *amount;
mutex_unlock (&np->lock);
diff --git a/libnetfs/make-node.c b/libnetfs/make-node.c
index 973744e7..c547bfcb 100644
--- a/libnetfs/make-node.c
+++ b/libnetfs/make-node.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -25,6 +25,8 @@ struct node *
netfs_make_node (struct netnode *nn)
{
struct node *np = malloc (sizeof (struct node));
+ if (! np)
+ return NULL;
np->nn = nn;
diff --git a/libnetfs/make-peropen.c b/libnetfs/make-peropen.c
index 961a77d1..92f58da0 100644
--- a/libnetfs/make-peropen.c
+++ b/libnetfs/make-peropen.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -22,7 +22,7 @@
#include <sys/file.h>
struct peropen *
-netfs_make_peropen (struct node *np, int flags, mach_port_t dotdotport)
+netfs_make_peropen (struct node *np, int flags, struct peropen *context)
{
struct peropen *po = malloc (sizeof (struct peropen));
@@ -31,11 +31,26 @@ netfs_make_peropen (struct node *np, int flags, mach_port_t dotdotport)
po->refcnt = 0;
po->openstat = flags;
po->np = np;
- po->dotdotport = dotdotport;
- if (dotdotport != MACH_PORT_NULL)
- mach_port_mod_refs (mach_task_self (), dotdotport,
- MACH_PORT_RIGHT_SEND, 1);
+
+ if (context)
+ {
+ po->root_parent = context->root_parent;
+ if (po->root_parent != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), po->root_parent,
+ MACH_PORT_RIGHT_SEND, 1);
+
+ po->shadow_root = context->shadow_root;
+ if (po->shadow_root)
+ netfs_nref (po->shadow_root);
+
+ po->shadow_root_parent = context->shadow_root_parent;
+ if (po->shadow_root_parent != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), po->shadow_root_parent,
+ MACH_PORT_RIGHT_SEND, 1);
+ }
+
netfs_nref (np);
+
return po;
}
diff --git a/libnetfs/make-protid.c b/libnetfs/make-protid.c
index 7d9240a1..bf18283c 100644
--- a/libnetfs/make-protid.c
+++ b/libnetfs/make-protid.c
@@ -21,7 +21,7 @@
#include "netfs.h"
struct protid *
-netfs_make_protid (struct peropen *po, struct netcred *cred)
+netfs_make_protid (struct peropen *po, struct iouser *cred)
{
struct protid *pi;
@@ -38,7 +38,7 @@ netfs_make_protid (struct peropen *po, struct netcred *cred)
po->refcnt++;
pi->po = po;
- pi->credential = cred;
+ pi->user = cred;
pi->shared_object = MACH_PORT_NULL;
pi->mapped = 0;
return pi;
diff --git a/libnetfs/misc.h b/libnetfs/misc.h
index aa942087..4845d252 100644
--- a/libnetfs/misc.h
+++ b/libnetfs/misc.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 2004 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -21,4 +21,4 @@
#include <fcntl.h>
/* Bits that are turned off after open */
-#define OPENONLY_STATE_MODES (O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK)
+#define OPENONLY_STATE_MODES (O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS)
diff --git a/libnetfs/mutations.h b/libnetfs/mutations.h
index ea0b8476..003bbe21 100644
--- a/libnetfs/mutations.h
+++ b/libnetfs/mutations.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2004 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,6 +20,8 @@
/* Only CPP macro definitions should go in this file. */
+#define IO_SELECT_REPLY_PORT
+
#define FILE_INTRAN protid_t begin_using_protid_port (file_t)
#define FILE_DESTRUCTOR end_using_protid_port (protid_t)
diff --git a/libnetfs/netfs.h b/libnetfs/netfs.h
index 836005ee..1dda718e 100644
--- a/libnetfs/netfs.h
+++ b/libnetfs/netfs.h
@@ -1,6 +1,6 @@
-/*
+/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,99,2000,02 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
@@ -23,22 +23,23 @@
#include <hurd/fshelp.h>
#include <hurd/iohelp.h>
#include <assert.h>
-#include <argp.h>
/* This library supports client-side network file system
- implementations. It is analogous to the diskfs library provided for
+ implementations. It is analogous to the diskfs library provided for
disk-based filesystems. */
+struct argp;
+
struct protid
{
struct port_info pi;
-
+
/* User identification */
- struct netcred *credential;
-
+ struct iouser *user;
+
/* Object this refers to */
struct peropen *po;
-
+
/* Shared memory I/O information. */
memory_object_t shared_object;
struct shared_io *mapped;
@@ -47,34 +48,46 @@ struct protid
/* One of these is created for each open */
struct peropen
{
- off_t filepointer;
+ loff_t filepointer;
int lock_status;
int refcnt;
int openstat;
- mach_port_t dotdotport;
+
struct node *np;
+
+ /* The parent of the translator's root node. */
+ mach_port_t root_parent;
+
+ /* If this node is in a shadow tree, the parent of its root. */
+ mach_port_t shadow_root_parent;
+ /* If in a shadow tree, its root node in this translator. */
+ struct node *shadow_root;
};
/* A unique one of these exists for each node currently in use. */
struct node
{
struct node *next, **prevp;
-
- /* Protocol specific stuff. */
+
+ /* Protocol specific stuff; defined by user. */
struct netnode *nn;
- struct stat nn_stat;
+ /* The stat information for this particular node. */
+ io_statbuf_t nn_stat;
+ /* The S_IPTRANS and S_IFMT bits here are examined instead of nn_stat.st_mode
+ to decide whether to do passive translator processing. Other bits
+ are ignored, so you can set this to nn_stat.st_mode if you want that. */
+ mode_t nn_translated;
- int istranslated;
-
struct mutex lock;
-
+
+ /* The number of references to this node. */
int references;
-
+
mach_port_t sockaddr;
-
+
int owner;
-
+
struct transbox transbox;
struct lock_box userlock;
@@ -84,199 +97,231 @@ struct node
struct dirmod *dirmod_reqs;
};
+/* The user must define this variable. Set this to the name of the
+ filesystem server. */
+extern char *netfs_server_name;
+
+/* The user must define this variables. Set this to be the server
+ version number. */
+extern char *netfs_server_version;
+
/* The user must define this function. 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 *NP, struct netcred *cred);
+ filled with the most current information. CRED identifies the user
+ responsible for the operation. NP is locked. */
+error_t netfs_validate_stat (struct node *np, struct iouser *cred);
/* The user must define this function. 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 netcred *cred, struct node *np,
+ call for the user specified by CRED on locked node NP, to change
+ the owner to UID and the group to GID. */
+error_t netfs_attempt_chown (struct iouser *cred, struct node *np,
uid_t uid, uid_t gid);
/* The user must define this function. 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 netcred *cred, struct node *np,
+ call for the user specified by CRED on locked node NP, thereby
+ changing the author to AUTHOR. */
+error_t netfs_attempt_chauthor (struct iouser *cred, struct node *np,
uid_t author);
/* The user must define this function. 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 netcred *cred, struct node *np,
+ call for the user specified by CRED on locked 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 *np,
mode_t mode);
-/* The user must define this function. Attempt to turn NODE (user CRED)
- into a symlink with target NAME. */
-error_t netfs_attempt_mksymlink (struct netcred *cred, struct node *np,
+/* The user must define this function. Attempt to turn locked node NP
+ (user CRED) into a symlink with target NAME. */
+error_t netfs_attempt_mksymlink (struct iouser *cred, struct node *np,
char *name);
/* The user must define this function. Attempt to turn NODE (user
- CRED) into a device. TYPE is either S_IFBLK or S_IFCHR. */
-error_t netfs_attempt_mkdev (struct netcred *cred, struct node *np,
+ CRED) into a device. TYPE is either S_IFBLK or S_IFCHR. NP is
+ locked. */
+error_t netfs_attempt_mkdev (struct iouser *cred, struct node *np,
mode_t type, dev_t indexes);
-/* The user must define this function. Attempt to set the passive
+/* The user may define this function. Attempt to set the passive
translator record for FILE to ARGZ (of length ARGZLEN) for user
- CRED. */
-error_t netfs_set_translator (struct netcred *cred, struct node *np,
+ CRED. NP is locked. */
+error_t netfs_set_translator (struct iouser *cred, struct node *np,
char *argz, size_t argzlen);
+/* The user may define this function (but should define it together
+ with netfs_set_translator). For locked node NODE with S_IPTRANS
+ set in its mode, look up the name of its translator. Store the
+ name into newly malloced storage, and return it in *ARGZ; set
+ *ARGZ_LEN to the total length. */
+error_t netfs_get_translator (struct node *node, char **argz,
+ size_t *argz_len);
+
/* The user must define this function. 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 netcred *cred, struct node *np,
+ call for the user specified by CRED on locked node NP, to change
+ the flags to FLAGS. */
+error_t netfs_attempt_chflags (struct iouser *cred, struct node *np,
int flags);
/* The user must define this function. 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 netcred *cred, struct node *np,
+ call for the user specified by CRED on locked node NP, to change
+ the atime to ATIME and the mtime to MTIME. If ATIME or MTIME is
+ null, then set to the current time. */
+error_t netfs_attempt_utimes (struct iouser *cred, struct node *np,
struct timespec *atime, struct timespec *mtime);
/* The user must define this function. 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 netcred *cred, struct node *np,
- off_t size);
+ size of the locked file NP (for user CRED) to SIZE bytes long. */
+error_t netfs_attempt_set_size (struct iouser *cred, struct node *np,
+ loff_t size);
/* The user must define this function. This should attempt to fetch
filesystem status information for the remote filesystem, for the
- user CRED. */
-error_t netfs_attempt_statfs (struct netcred *cred, struct node *np,
- struct statfs *st);
-
-/* The user must define this function. This should sync the file NP
- completely to disk, for the user CRED. If WAIT is set, return
- only after sync is completely finished. */
-error_t netfs_attempt_sync (struct netcred *cred, struct node *np,
+ user CRED. NP is locked. */
+error_t netfs_attempt_statfs (struct iouser *cred, struct node *np,
+ fsys_statfsbuf_t *st);
+
+/* The user must define this function. This should sync the locked
+ file NP completely to disk, for the user CRED. If WAIT is set,
+ return only after the sync is completely finished. */
+error_t netfs_attempt_sync (struct iouser *cred, struct node *np,
int wait);
/* The user must define this function. This should sync the entire
- remote filesystem. If WAIT is set, return only after
- sync is completely finished. */
-error_t netfs_attempt_syncfs (struct netcred *cred, int wait);
-
-/* The user must define this function. Lookup NAME in DIR for USER;
- set *NP to the found name upon return. If the name was not found,
- then return ENOENT. On any error, clear *NP. (*NP, if found, should
- be locked, this call should unlock DIR no matter what.) */
-error_t netfs_attempt_lookup (struct netcred *user, struct node *dir,
+ remote filesystem. If WAIT is set, return only after the sync is
+ completely finished. */
+error_t netfs_attempt_syncfs (struct iouser *cred, int wait);
+
+/* The user must define this function. Lookup NAME in DIR (which is
+ locked) for USER; set *NP to the found name upon return. If the
+ name was not found, then return ENOENT. On any error, clear *NP.
+ (*NP, if found, should be locked and a reference to it generated.
+ This call should unlock DIR no matter what.) */
+error_t netfs_attempt_lookup (struct iouser *user, struct node *dir,
char *name, struct node **np);
-/* The user must define this function. Delete NAME in DIR for USER. */
-error_t netfs_attempt_unlink (struct netcred *user, struct node *dir,
+/* The user must define this function. Delete NAME in DIR (which is
+ locked) for USER. */
+error_t netfs_attempt_unlink (struct iouser *user, struct node *dir,
char *name);
-/* Note that in this one call, neither of the specific nodes are locked. */
-error_t netfs_attempt_rename (struct netcred *user, struct node *fromdir,
- char *fromname, struct node *todir,
+/* The user must define this function. Attempt to rename the
+ directory FROMDIR to TODIR. Note that 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);
/* The user must define this function. Attempt to create a new
- directory named NAME in DIR for USER with mode MODE. */
-error_t netfs_attempt_mkdir (struct netcred *user, struct node *dir,
+ directory named NAME in DIR (which is locked) for USER with mode
+ MODE. */
+error_t netfs_attempt_mkdir (struct iouser *user, struct node *dir,
char *name, mode_t mode);
/* The user must define this function. Attempt to remove directory
- named NAME in DIR for USER. */
-error_t netfs_attempt_rmdir (struct netcred *user,
+ named NAME in DIR (which is locked) for USER. */
+error_t netfs_attempt_rmdir (struct iouser *user,
struct node *dir, char *name);
/* The user must define this function. 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 netcred *user, struct node *dir,
+ NAME to FILE for USER. Note that neither DIR nor FILE are
+ locked. If EXCL is set, do not delete the target. 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);
/* The user must define this function. Attempt to create an anonymous
- file related to DIR for USER with MODE. Set *NP to the returned
- file upon success. No matter what, unlock DIR. */
-error_t netfs_attempt_mkfile (struct netcred *user, struct node *dir,
+ file related to DIR (which is locked) for USER with MODE. Set *NP
+ 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 **np);
/* The user must define this function. Attempt to create a file named
- NAME in DIR for USER with MODE. Set *NP to the new node upon
- return. On any error, clear *NP. *NP should be locked on success;
- no matter what, unlock DIR before returning. */
-error_t netfs_attempt_create_file (struct netcred *user, struct node *dir,
+ NAME in DIR (which is locked) for USER with MODE. Set *NP to the
+ new node upon return. On any error, clear *NP. *NP 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 **np);
-/* The user must define this function. Read the contents of NP (a symlink),
- for USER, into BUF. */
-error_t netfs_attempt_readlink (struct netcred *user, struct node *np,
+/* The user must define this function. Read the contents of locked
+ node NP (a symlink), for USER, into BUF. */
+error_t netfs_attempt_readlink (struct iouser *user, struct node *np,
char *buf);
-/* The user must define this function. Node NP 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 netcred *user, struct node *np,
+/* The user must define this function. Locked node NP 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 *np,
int flags, int newnode);
-/* The user must define this function. Read from the file NP 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 netcred *cred, struct node *np,
- off_t offset, size_t *len, void *data);
+/* The user must define this function. Read from the locked file NP
+ 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 *np,
+ loff_t offset, size_t *len, void *data);
-/* The user must define this function. Write to the file NP for user
- CRED starting at OFSET and continuing for up to *LEN bytes from
- DATA. Set *LEN to the amount seccessfully written upon return. */
-error_t netfs_attempt_write (struct netcred *cred, struct node *np,
- off_t offset, size_t *len, void *data);
+/* The user must define this function. Write to the locked file NP
+ for user CRED starting at OFSET and continuing for up to *LEN bytes
+ from DATA. Set *LEN to the amount successfully written upon
+ return. */
+error_t netfs_attempt_write (struct iouser *cred, struct node *np,
+ loff_t offset, size_t *len, void *data);
/* The user must define this function. Return the valid access
types (bitwise OR of O_READ, O_WRITE, and O_EXEC) in *TYPES for
- file NP and user CRED. */
-void netfs_report_access (struct netcred *cred, struct node *np,
- int *types);
-
-/* The user must define this function. Malloc and fill two arrays with
- the uids and gids from the specified credential. */
-void netfs_interpret_credential (struct netcred *cred, uid_t **uids,
- int *nuids, uid_t **gids, int *ngids);
-
-/* The user must define this function. Return a (virtual or physical)
- copy of CRED. */
-struct netcred *netfs_copy_credential (struct netcred *cred);
-
-/* The user must define this function. The specified credential is
- not in use any more. */
-void netfs_drop_credential (struct netcred *cred);
-
-/* The user must define this function. Create a new credential
- from the specified UID and GID arrays. */
-struct netcred *netfs_make_credential (uid_t *uids, int nuids,
+ locked file NP and user CRED. */
+error_t netfs_report_access (struct iouser *cred, struct node *np,
+ int *types);
+
+/* The user must define this function. Create a new user from the
+ specified UID and GID arrays. */
+struct iouser *netfs_make_user (uid_t *uids, int nuids,
uid_t *gids, int ngids);
-/* The user must define this function. Node NP is all done; free
- all its associated storage. */
+/* The user must define this function. Node NP has no more references;
+ free all its associated storage. */
void netfs_node_norefs (struct node *np);
-error_t netfs_get_dirents (struct netcred *, struct node *, int, int, char **,
- mach_msg_type_number_t *, vm_size_t, int *);
+/* The user must define this function. Fill the array *DATA of size
+ BUFSIZE with up to NENTRIES dirents from DIR (which is locked)
+ starting with entry ENTRY for user CRED. The number of entries in
+ the array is stored in *AMT and the number of bytes in *DATACNT.
+ If the supplied buffer is not large enough to hold the data, it
+ should be grown. */
+error_t netfs_get_dirents (struct iouser *cred, struct node *dir,
+ int entry, int nentries, char **data,
+ mach_msg_type_number_t *datacnt,
+ vm_size_t bufsize, int *amt);
+
+/* The user may define this function. For a full description,
+ see hurd/hurd_types.h. The default response indicates a network
+ store. If the supplied buffers are not large enough, they should
+ be grown as necessary. NP is locked. */
+error_t netfs_file_get_storage_info (struct iouser *cred,
+ struct node *np,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints,
+ mach_msg_type_number_t *num_ints,
+ loff_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data,
+ mach_msg_type_number_t *data_len);
/* Option parsing */
/* Parse and execute the runtime options in ARGZ & ARGZ_LEN. EINVAL is
returned if some option is unrecognized. The default definition of this
- routine will parse them using NETFS_RUNTIME_ARGP, which see. */
+ routine will parse them using NETFS_RUNTIME_ARGP. */
error_t netfs_set_options (char *argz, size_t argz_len);
-/* Return an argz string describing the current options. Fill *ARGZ
- with a pointer to newly malloced storage holding the list and *LEN
- to the length of that storage. The default definition of this routine
- simply initializes *ARGZ and *ARGZ_LEN to 0 and calls
- netfs_append_std_options. */
-error_t netfs_get_options (char **argz, size_t *argz_len);
+/* Append to the malloced string *ARGZ of length *ARGZ_LEN a NUL-separated
+ list of the arguments to this translator. The default definition of this
+ routine simply calls netfs_append_std_options. */
+error_t netfs_append_args (char **argz, size_t *argz_len);
/* If this is defined or set to a pointer to an argp structure, it will be
used by the default netfs_set_options to handle runtime option parsing.
@@ -300,24 +345,77 @@ extern const struct argp netfs_std_startup_argp;
must already have a sane value). */
error_t netfs_append_std_options (char **argz, size_t *argz_len);
+/* Definitions provided by user */
+
+/* Maximum number of symlinks to follow before returning ELOOP. */
+extern int netfs_maxsymlinks;
+
/* Definitions provided by netfs. */
-struct node *netfs_make_node (struct netnode *);
-mach_port_t netfs_startup (mach_port_t, int);
+/* Given a netnode created by the user program, wraps it in a node
+ structure. The new node is not locked and has a single reference.
+ If an error occurs, NULL is returned. */
+struct node *netfs_make_node (struct netnode *);
+/* Whenever node->references is to be touched, this lock must be
+ held. Cf. netfs_nrele, netfs_nput, netfs_nref and netfs_drop_node. */
extern spin_lock_t netfs_node_refcnt_lock;
-extern int netfs_maxsymlinks;
-
+/* Normally called in main. This function sets up some of the netfs
+ server's internal state. */
void netfs_init (void);
+
+/* Starts the netfs server. Called after netfs_init. BOOTSTRAP is
+ the bootstrap port. FLAGS indicate how to open the underlying node
+ (Cf. hurd/fsys.defs). */
+mach_port_t netfs_startup (mach_port_t bootstrap, int flags);
+
+/* Normally called as the last function in main. The netfs server now
+ begins answering requests. This function never returns. */
void netfs_server_loop (void);
-struct protid *netfs_make_protid (struct peropen *, struct netcred *);
-struct peropen *netfs_make_peropen (struct node *, int, mach_port_t);
-void netfs_drop_node (struct node *);
+
+/* Creates a new credential from USER which can be NULL on the peropen
+ PO. Returns NULL and sets errno on error. */
+struct protid *netfs_make_protid (struct peropen *po, struct iouser *user);
+
+/* Create and return a new peropen structure on node NP with open
+ flags FLAGS. The initial values for the root_parent, shadow_root,
+ and shadow_root_parent fields are copied from CONTEXT if it's
+ non-zero, otherwise zeroed. */
+struct peropen *netfs_make_peropen (struct node *, int,
+ struct peropen *context);
+
+/* Add a reference to node NP. Unless you already hold a reference,
+ NP must be locked. */
+void netfs_nref (struct node *np);
+
+/* Releases a node. Drops a reference to node NP, which must not be
+ locked by the caller. If this was the last reference, drops the
+ node. The node cannot be used again without first obtaining a
+ reference to it. */
+void netfs_nrele (struct node *np);
+
+/* Puts a node back. Drops a reference to the node NP, which must be
+ locked by the caller (this lock will be released by netfs_nput).
+ If this was the last reference, drops the node. The node cannot be
+ used again without first obtaining a reference to it. */
+void netfs_nput (struct node *np);
+
+/* Called internally when no more references to node NP exist. */
+void netfs_drop_node (struct node *np);
+
+/* Called internally when no more references to a protid exit. */
void netfs_release_protid (void *);
+
+/* Called internally when no more references to a protid exit. */
void netfs_release_peropen (struct peropen *);
+
+/* The netfs message demuxer. */
int netfs_demuxer (mach_msg_header_t *, mach_msg_header_t *);
-error_t netfs_shutdown (int);
+
+/* Called to ask the filesystem to shutdown. If it returns, an error
+ occurred. FLAGS are passed to fsys_goaway. */
+error_t netfs_shutdown (int flags);
extern struct port_class *netfs_protid_class;
extern struct port_class *netfs_control_class;
@@ -326,45 +424,6 @@ extern struct node *netfs_root_node;
extern mach_port_t netfs_fsys_identity;
extern auth_t netfs_auth_server_port;
-extern inline void
-netfs_nref (struct node *np)
-{
- spin_lock (&netfs_node_refcnt_lock);
- np->references++;
- spin_unlock (&netfs_node_refcnt_lock);
-}
-
-extern inline void
-netfs_nrele (struct node *np)
-{
- spin_lock (&netfs_node_refcnt_lock);
- assert (np->references);
- np->references--;
- if (np->references == 0)
- {
- mutex_lock (&np->lock);
- netfs_drop_node (np);
- }
- else
- spin_unlock (&netfs_node_refcnt_lock);
-}
-
-extern inline void
-netfs_nput (struct node *np)
-{
- spin_lock (&netfs_node_refcnt_lock);
- assert (np->references);
- np->references--;
- if (np->references == 0)
- netfs_drop_node (np);
- else
- {
- spin_unlock (&netfs_node_refcnt_lock);
- mutex_unlock (&np->lock);
- }
-}
-
-
/* Mig gook. */
typedef struct protid *protid_t;
diff --git a/libnetfs/nput.c b/libnetfs/nput.c
new file mode 100644
index 00000000..c62b7b9f
--- /dev/null
+++ b/libnetfs/nput.c
@@ -0,0 +1,38 @@
+/*
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "priv.h"
+
+void
+netfs_nput (struct node *np)
+{
+ spin_lock (&netfs_node_refcnt_lock);
+ assert (np->references);
+ np->references--;
+ if (np->references == 0)
+ netfs_drop_node (np);
+ /* netfs_drop_node drops netfs_node_refcnt_lock for us. */
+ else
+ {
+ spin_unlock (&netfs_node_refcnt_lock);
+ mutex_unlock (&np->lock);
+ }
+}
+
diff --git a/libmom/unreserve-memory.c b/libnetfs/nref.c
index 88e8eb94..4e26910f 100644
--- a/libmom/unreserve-memory.c
+++ b/libnetfs/nref.c
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This file is part of the GNU Hurd.
@@ -20,8 +20,10 @@
#include "priv.h"
-error_t
-mom_unreserve_memory (void *start, size_t len)
+void
+netfs_nref (struct node *np)
{
- return mom_deallocate_memory (start, len);
+ spin_lock (&netfs_node_refcnt_lock);
+ np->references++;
+ spin_unlock (&netfs_node_refcnt_lock);
}
diff --git a/libmom/error-trans.c b/libnetfs/nrele.c
index 57ef7e31..dca9599a 100644
--- a/libmom/error-trans.c
+++ b/libnetfs/nrele.c
@@ -1,6 +1,6 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This file is part of the GNU Hurd.
@@ -20,21 +20,18 @@
#include "priv.h"
-mom_error_t
-mom_error_translate_mach (error_t macherr)
+void
+netfs_nrele (struct node *np)
{
- switch (macherr)
+ spin_lock (&netfs_node_refcnt_lock);
+ assert (np->references);
+ np->references--;
+ if (np->references == 0)
{
- case EMACH_SEND_INVALID_DEST:
- return EMOM_INVALID_DEST;
-
- case EMACH_SEND_INVALID_RIGHT:
- return EMOM_INVALID_REF;
-
- case EMIG_SERVER_DIED:
- return EMOM_SERVER_DIED;
-
- default:
- return macherr;
+ mutex_lock (&np->lock);
+ netfs_drop_node (np);
+ /* netfs_drop_node drops netfs_node_refcnt_lock for us. */
}
+ else
+ spin_unlock (&netfs_node_refcnt_lock);
}
diff --git a/libnetfs/priv.h b/libnetfs/priv.h
index eefb8e7f..b0f9f4a0 100644
--- a/libnetfs/priv.h
+++ b/libnetfs/priv.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -22,14 +22,15 @@
#include "netfs.h"
-extern inline struct protid *
+static inline struct protid * __attribute__ ((unused))
begin_using_protid_port (file_t port)
{
return ports_lookup_port (netfs_port_bucket, port, netfs_protid_class);
}
-extern inline void
+static inline void __attribute__ ((unused))
end_using_protid_port (struct protid *cred)
{
- ports_port_deref (cred);
+ if (cred)
+ ports_port_deref (cred);
}
diff --git a/libnetfs/release-peropen.c b/libnetfs/release-peropen.c
index 4fc0b45e..9a52184b 100644
--- a/libnetfs/release-peropen.c
+++ b/libnetfs/release-peropen.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,8 +28,19 @@ netfs_release_peropen (struct peropen *po)
mutex_unlock (&po->np->lock);
else
{
- mach_port_deallocate (mach_task_self (), po->dotdotport);
+ if (po->root_parent)
+ mach_port_deallocate (mach_task_self (), po->root_parent);
+
+ if (po->shadow_root && po->shadow_root != po->np)
+ {
+ mutex_lock (&po->shadow_root->lock);
+ netfs_nput (po->shadow_root);
+ }
+ if (po->shadow_root_parent)
+ mach_port_deallocate (mach_task_self (), po->shadow_root_parent);
+
netfs_nput (po->np);
+
free (po);
}
}
diff --git a/libnetfs/release-protid.c b/libnetfs/release-protid.c
index 3585021f..b1bac0eb 100644
--- a/libnetfs/release-protid.c
+++ b/libnetfs/release-protid.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -19,17 +19,17 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "netfs.h"
+#include <sys/mman.h>
void
netfs_release_protid (void *arg)
{
struct protid *user = arg;
-
- netfs_drop_credential (user->credential);
+
+ iohelp_free_iouser (user->user);
if (user->shared_object)
mach_port_deallocate (mach_task_self (), user->shared_object);
if (user->mapped)
- vm_deallocate (mach_task_self (), (vm_address_t) user->mapped,
- vm_page_size);
+ munmap (user->mapped, vm_page_size);
netfs_release_peropen (user->po);
}
diff --git a/libnetfs/runtime-argp.c b/libnetfs/runtime-argp.c
index ae787fe2..9e5989c7 100644
--- a/libnetfs/runtime-argp.c
+++ b/libnetfs/runtime-argp.c
@@ -1,6 +1,6 @@
/* Default definition for netfs_runtime_argp
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2004 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -19,5 +19,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "netfs.h"
+#include <argp.h>
struct argp *netfs_runtime_argp = (struct argp *)&netfs_std_runtime_argp;
diff --git a/libnetfs/set-get-trans.c b/libnetfs/set-get-trans.c
new file mode 100644
index 00000000..b58668d8
--- /dev/null
+++ b/libnetfs/set-get-trans.c
@@ -0,0 +1,47 @@
+/* Default versions of netfs_set_translator & netfs_get_translator
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "netfs.h"
+
+/* Default implementations of the netfs_set_translator and
+ netfs_set_translator functions. */
+
+/* The user may define this function. 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 *np,
+ char *argz, size_t argzlen)
+{
+ return EOPNOTSUPP;
+}
+
+/* The user may define this function (but should define it together with
+ netfs_set_translator). For locked node NODE with S_IPTRANS set in its
+ mode, look up the name of its translator. Store the name into newly
+ malloced storage, and return it in *ARGZ; set *ARGZ_LEN to the total
+ length. */
+error_t
+netfs_get_translator (struct node *node, char **argz, size_t *argz_len)
+{
+ return EOPNOTSUPP;
+}
diff --git a/libnetfs/shutdown.c b/libnetfs/shutdown.c
index 8e4c7a68..9ba137d0 100644
--- a/libnetfs/shutdown.c
+++ b/libnetfs/shutdown.c
@@ -1,28 +1,106 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/*
+ Copyright (C) 1993,94,95,96,98,99,2001 Free Software Foundation, Inc.
- This file is part of the GNU Hurd.
+This file is part of the GNU Hurd.
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "netfs.h"
+/* Written by Michael I. Bushnell. */
+#include "priv.h"
+#include <errno.h>
+#include <sys/stat.h>
+#include <hurd/fsys.h>
+#include <hurd/fshelp.h>
+#include <cthreads.h>
+
+/* Shutdown the filesystem; flags are as for fsys_goaway. */
error_t
netfs_shutdown (int flags)
{
- return EBUSY;
-}
+ error_t
+ helper (struct node *node)
+ {
+ error_t err;
+ mach_port_t control;
+
+ err = fshelp_fetch_control (&node->transbox, &control);
+ if (!err && (control != MACH_PORT_NULL))
+ {
+ mutex_unlock (&node->lock);
+ err = fsys_goaway (control, flags);
+ mach_port_deallocate (mach_task_self (), control);
+ mutex_lock (&node->lock);
+ }
+ else
+ err = 0;
+
+ if ((err == MIG_SERVER_DIED) || (err == MACH_SEND_INVALID_DEST))
+ err = 0;
+
+ return err;
+ }
+
+ int nports;
+ int err;
+
+ if ((flags & FSYS_GOAWAY_UNLINK)
+ && S_ISDIR (netfs_root_node->nn_stat.st_mode))
+ return EBUSY;
+#ifdef NOTYET
+ if (flags & FSYS_GOAWAY_RECURSE)
+ {
+ err = netfs_node_iterate (helper);
+ if (err)
+ return err;
+ }
+#endif
+
+#ifdef NOTYET
+ rwlock_writer_lock (&netfs_fsys_lock);
+#endif
+
+ /* Permit all current RPC's to finish, and then suspend any new ones. */
+ err = ports_inhibit_class_rpcs (netfs_protid_class);
+ if (err)
+ {
+#ifdef NOTYET
+ rwlock_writer_unlock (&netfs_fsys_lock);
+#endif
+ return err;
+ }
+
+ nports = ports_count_class (netfs_protid_class);
+ if (((flags & FSYS_GOAWAY_FORCE) == 0) && nports)
+ /* There are outstanding user ports; resume operations. */
+ {
+ ports_enable_class (netfs_protid_class);
+ ports_resume_class_rpcs (netfs_protid_class);
+#ifdef NOTYET
+ rwlock_writer_unlock (&netfs_fsys_lock);
+#endif
+ return EBUSY;
+ }
+
+ if (!(flags & FSYS_GOAWAY_NOSYNC))
+ {
+ err = netfs_attempt_syncfs (0, flags);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/libnetfs/std-runtime-argp.c b/libnetfs/std-runtime-argp.c
index d8d4ba0a..9e2ad1d6 100644
--- a/libnetfs/std-runtime-argp.c
+++ b/libnetfs/std-runtime-argp.c
@@ -18,6 +18,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <argp.h>
#include "netfs.h"
const struct argp netfs_std_runtime_argp = { 0 };
diff --git a/libnetfs/std-startup-argp.c b/libnetfs/std-startup-argp.c
index 7fc4b024..3de84a57 100644
--- a/libnetfs/std-startup-argp.c
+++ b/libnetfs/std-startup-argp.c
@@ -20,6 +20,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <argp.h>
#include "netfs.h"
const struct argp
diff --git a/libnetfs/trans-callback.c b/libnetfs/trans-callback.c
new file mode 100644
index 00000000..4dec162e
--- /dev/null
+++ b/libnetfs/trans-callback.c
@@ -0,0 +1,83 @@
+/* Callback functions for starting translators
+
+ Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "priv.h"
+#include <fcntl.h>
+
+/* Callback function needed for calls to fshelp_fetch_root. See
+ <hurd/fshelp.h> for the interface description. */
+static error_t
+_netfs_translator_callback1_fn (void *cookie1, void *cookie2,
+ uid_t *uid, gid_t *gid,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+ struct node *np = cookie1;
+
+ if (! (np->nn_stat.st_mode & S_IPTRANS))
+ return ENOENT;
+
+ err = netfs_get_translator (np, argz, argz_len);
+ if (err)
+ {
+ assert (err != EOPNOTSUPP);
+ return err;
+ }
+
+ *uid = np->nn_stat.st_uid;
+ *gid = np->nn_stat.st_gid;
+
+ return 0;
+}
+
+/* Callback function needed for calls to fshelp_fetch_root. See
+ <hurd/fshelp.h> for the interface description. */
+static error_t
+_netfs_translator_callback2_fn (void *cookie1, void *cookie2, int flags,
+ mach_port_t *underlying,
+ mach_msg_type_name_t *underlying_type)
+{
+ error_t err;
+ struct protid *cred;
+ struct node *node = cookie1;
+ struct iouser *user;
+
+ err = iohelp_create_simple_iouser (&user, node->nn_stat.st_uid,
+ node->nn_stat.st_gid);
+ if (err)
+ return err;
+
+ cred = netfs_make_protid (netfs_make_peropen (node, flags, cookie2),
+ user);
+ if (cred)
+ {
+ *underlying = ports_get_right (cred);
+ *underlying_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (cred);
+ return 0;
+ }
+ else
+ return errno;
+}
+
+fshelp_fetch_root_callback1_t _netfs_translator_callback1 =
+ _netfs_translator_callback1_fn;
+fshelp_fetch_root_callback2_t _netfs_translator_callback2 =
+ _netfs_translator_callback2_fn;
diff --git a/libnetfs/unparse-runtime-options.c b/libnetfs/unparse-runtime-options.c
deleted file mode 100644
index 4596600c..00000000
--- a/libnetfs/unparse-runtime-options.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* A default netfs_unparse_runtime_options routine
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include "netfs.h"
-
-/* The user may define this function, in which case it is called when the the
- filesystem receives a get-options request. ARGZ & ARGZ_LEN will contain
- information on `standard' netfs options; the user may extend them
- (probably by using argz_add), or ignore them, in which case case ARGZ
- should be freed, as it is malloced. The default implementation simply
- leaves ARGZ & ARGZ_LEN unmodified and returns sucess (0). */
-error_t
-netfs_unparse_runtime_options (char **argz, size_t *argz_len)
-{
- return 0;
-}
diff --git a/libpager/ChangeLog b/libpager/ChangeLog
deleted file mode 100644
index ed8e3cca..00000000
--- a/libpager/ChangeLog
+++ /dev/null
@@ -1,374 +0,0 @@
-Thu May 9 11:10:11 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pager-create.c: Get rid of link warning.
-
- * pager-create.c (pager_create): ports_allocate_port ->
- ports_create_port; if we get an error return a null structure.
-
-Thu May 2 11:17:17 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * offer-page.c (pager_offer_page): Make sure we hold lock across
- operation. Also set incore bit when operation is complete.
-
-Tue Apr 30 12:40:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * lock-object.c (_pager_lock_object): Eliminate spurious extra
- lock acquisition around pagemap frobbing.
-
-Sun Apr 28 15:46:12 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * pager-create.c (pager_create): Add link warning.
-
-Thu Apr 18 13:03:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * data-return.c (_pager_do_write_request): If kernel didn't keep a
- copy, turn off INCORE bit. Don't track INIT bit for now.
- * lock-object.c (_pager_lock_object): If SYNC and SHOULD_FLUSH,
- then turn off PM_INCORE bits when flush is complete.
- * data-request.c (_pager_seqnos_memory_object_data_request): Set
- PM_INCORE.
- * priv.h (PM_INIT): Comment out.
- (PM_INCORE): New bit.
- * offer-page.c: New file.
- * Makefile (SRCS): Add offer-page.c.
- * pager.h (pager_offer_page): New function.
-
-Thu Apr 11 17:50:57 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pager-memcpy.c (pager_memcpy [copy]): Return error_t so that
- this function has the proper type as an arg for
- hurd_catch_signal.
- (pager_memcpy): Cast FAULT to proper type in call to
- hurd_catch_signal.
-
-Tue Mar 26 15:38:06 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * lock-completed.c: Include <stdio.h>.
-
- * data-return.c (_pager_do_write_request): Delete unused label
- `out'.
-
- * pager-sync.c (pager_sync, pager_sync_some): Ask for RETURN_ALL
- and not just RETURN_DIRTY, because we treat precious pages as
- dirty in this library.
- * pager-return.c (pager_return, pager_return_some): Likewise.
-
-Mon Mar 18 13:10:32 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pager.h (pager_return, pager_return_some): New declarations.
- * Makefile (SRCS): Add pager-return.c.
- * pager-return.c: New file.
-
- * pager-flush.c (pager_flush): Lock request should be
- VM_PROT_NO_CHANGE, not VM_PROT_NONE.
- (pager_flush_some): Likewise.
-
-Wed Mar 6 17:53:20 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * lock-object.c (_pager_lock_object): Correctly remove LR from
- P's linked list of lock requests.
- * pager-attr.c (pager_change_attributes): Likewise for attributes.
-
- * lock-object.c (_pager_lock_object): Don't barf anymore.
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed): Ditto.
- * Makefile (SRCS): Remove barf.c.
-
-Wed Feb 21 14:15:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed):
- Get rid of bletcherous semi.
- Make barf more voluminous.
-
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed):
- Be picky about always releasing SEQNO.
- * object-init.c (_pager_seqnos_memory_object_init): Likewise.
-
-Tue Feb 20 17:44:59 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * lock-object.c (_pager_lock_object): Use barf instead of printf.
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed): Ditto.
- * Makefile (SRCS): Add barf.c.
-
- * data-return.c (_pager_do_write_request): Always wait for and
- release SEQNO if OBJECT is a valid pager.
- * data-request.c (_pager_seqnos_memory_object_data_request): Likewise.
- * object-terminate.c (_pager_seqnos_memory_object_terminate): Likewise.
-
-Tue Feb 20 16:05:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * lock-object.c (_pager_lock_object): Print debugging message when
- SYNC.
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed):
- Print a notice when an incoming lock completion corresponds to no
- outstanding lock request.
-
-Tue Feb 20 15:10:29 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * lock-object.c (_pager_lock_object): Remove `sync = 0'.
-
-Fri Jan 5 17:09:43 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * pager-memcpy.c: New file.
- * Makefile (SRCS): Add pager-memcpy.c.
-
-Thu Jan 4 15:37:21 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * pager.h: Declare pager_memcpy.
-
-Mon Oct 9 14:57:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * priv.h: Declare _pager_page_errors extern, not common.
-
- * Makefile: Specify shared library dependencies.
-
-Wed Sep 13 14:49:53 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed):
- Don't push the locks_pending field negative in the case where the
- pager was terminated before we get called.
-
-Tue Sep 5 15:50:12 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * chg-compl.c (_pager_seqnos_memory_object_change_completed):
- Don't push the attrs_pending field negative in the case where the
- pager was terminated before we get called.
-
-Wed Aug 23 15:00:46 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Make this the main list of files, from which
- the others are derived.
- (COBJS, REMHDRS): Removed.
- (OBJS): Derived mostly from $(SRCS).
-
-Fri Jul 21 16:43:19 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * object-create.c (_pager_seqnos_memory_object_create): Drop
- initial reference created by ports_intern_external_reference when
- we're done with P.
-
-Thu Jul 6 15:36:36 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Mon Jun 26 20:15:03 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * get-upi.c: New file.
- * pager.h (pager_get_upi): New function.
- * Makefile (COBJS): Add get-upi.o.
-
-Thu Jun 22 11:43:15 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * object-init.c (_pager_seqnos_memory_object_init): Rather than an
- empty `if' body and an unconditional return, how about a real
- test?
-
- * notify-stubs.c: New file.
- * Makefile (COBJS): Add notify-stubs.o.
-
-Tue Jun 20 12:44:22 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * chg-compl.c (_pager_seqnos_memory_object_change_completed): Use
- new ports routines.
- * pager-shutdown.c (pager_shutdown): Likewise.
- * object-terminate.c (_pager_free_structure): Likewise.
- * object-init.c (_pager_seqnos_memory_object_init): Likewise.
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed):
- Likewise.
- * data-unlock.c (_pager_seqnos_memory_object_data_unlock): Likewise.
- * data-return.c (_pager_do_write_request): Likewise.
- * data-request.c (_pager_seqnos_memory_object_data_request):
- Likewise.
- * pager-create.c (pager_create): New parm BUCKET. Allocate port
- using new ports interface. Arrange to have _pager_class
- initialized at startup.
- * clean.c, dropweak.c: New files.
- * no-senders.c: Rename pager_no_senders to
- _pager_do_seqnos_mach_notify_no_senders. Lookup up port right
- ourselves. Remove function pager_clean (now in clean.c).
- * priv.h (_pager_class): New var.
- (_pager_clean, _pager_real_dropweak): New decls.
- * Makefile (COBJS): Delete reference.o. Add clean.o and dropweak.o
- (OBJS): Add notifyServer.o.
- (demuxer.o): Depend on notify_S.h.
- * demuxer.c: Include "notify_S.h".
- (pager_demuxer): Declare and use _pager_seqnos_notify_server.
- * pager.h: Include <hurd/ports.h>.
- (pager_no_senders, pager_reference, pager_unreference,
- pager_port_type, pager_clean): Remove declarations.
- (pager_create): New parm BUCKET.
- (pager_clean): Doc fix.
- (pager_dropweak): New decl.
- * reference.c: Deleted file.
-
-Thu May 11 11:19:44 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * priv.h (PM_NEXTERROR, SET_PM_NEXTERROR): Mask 2-bit error code
- with 0x3, not 0x2!
-
- * mark-error.c (_pager_mark_next_request_error,
- _pager_mark_object_error): Put the error code in the correct place
- in the pagemap rather than always at the beginning.
- (pager_get_error): Get the error code from the pagemap rather than
- just using the pagemap offset!
-
-Wed Nov 23 00:28:19 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * demuxer.c (pager_demuxer): Call
- _pager_seqnos_memory_object_server, not
- seqnos_memory_object_server.
-
-Tue Nov 8 14:15:01 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * lock-object.c (_pager_lock_object): Hammer SYNC to zero for now;
- there's some deadlock bug in noticing when the sync finishes.
-
-Tue Aug 30 17:55:34 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * data-return.c: Include <assert.h>.
- (_pager_seqnos_memory_object_data_return): Use return correctly.
-
-Mon Aug 29 17:30:52 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * priv.h (PM_INIT): New pagemap bit.
- * data-return.c (_pager_do_write-request): Set PM_INIT for
- affected pages. New var `omitdata' hold a bitmap of the
- pages that we are not actually writing. Set accordingly
- while looking through pagemap before starting I/O. Don't
- actually call I/O on these pages or frob the page map with them
- later.
-
- * data-return.c (_pager_seqnos_memory_object_data_return): Split
- into two functions; _pager_do_write_request does the real work
- now.
-
- * object-create.c: New file.
- * data-init.c: New file.
-
-Fri Jul 22 11:54:05 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten to use new scheme.
- * data-request.c: Include "memory_object_S.h" instead of
- "memory_object.h".
- * data-return.c: Likewise.
- * data-unlock.c: Likewise.
- * lock-completed: Likewise.
- * stubs.c: Likewise.
- * object-init.c: Likewise.
- * demuxer.c: Likewise.
- * object-terminate.c: Likewise.
-
-Tue Jul 5 14:14:17 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (TAGSHDRS): New variable.
-
-Wed Jun 1 11:41:24 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * pager-attr.c (pager_change_attributes): Return immediately
- if we are already in the requested state.
-
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed):
- Call ports_done_with_port before returning to free reference
- created by ports_check_port_type.
- * chg-compl.c (_pager_seqnos_memory_object_change_completed):
- Likewise.
-
- * seqnos.c (_pager_release_seqno): New second arg SEQNO.
- Set p->seqno here. All callers changed.
- (_pager_wait_for_seqno): Don't set p->seqno here; then it
- might get released before we actually call _pager_release_seqno.
- * priv.h (_pager_release_seqno): Declare new second arg.
-
- * priv.h (KERNEL_INIT_RACE): New compilation option. All the
- changes in this block are conditionalized by this macro.
- * priv.h (struct pager): New members init_head and init_tail.
- (struct pending_init): New type.
- * object-init.c (_pager_seqnos_memory_object_init): If the object
- is not ready for init, then queue the init for later processing.
- * object-terminate.c (_pager_seqnos_memory_object_terminate): If
- there is a pending init, return it here.
- * no-senders.c (pager_clean): Destroy all pending inits here.
-
- * object-terminate.c (_pager_free_structure): Don't unlock
- interlock or free the seqno here.
- (_pager_seqnos_memory_object_terminate): Unlock interlock and
- free seqno after calling _pager_free_structure.
- * no-senders.c (pager_clean): Unlock interlock after calling
- _pager_free_structure. Don't free seqno here at all.
-
-Tue May 24 15:25:54 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * data-return.c (_pager_seqnos_memory_object_data_return): New
- vars NPAGES, I, and PAGERRS. Rename var PM_ENTRY to be
- PM_ENTRIES. Deal with multiple-page data_return calls by dealing
- with multiple pagemap slots and calling pager_write_page multiple
- times.
-
- * data-return.c (_pager_seqnos_memory_object_data_return): Fix
- printf messages; include length in bogus length messages.
-
- *data-unlock (_pager_seqnos_memory_object_data_unlock): Likewise.
-
-Mon May 23 13:06:31 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * data-request.c (_pager_seqnos_memory_object_data_request):
- Report length in bogus arg messages; terminate messages with
- newlines.
-
- * chg-compl.c: Include <stdio.h>.
-
- * priv.h (struct pager [may_cache, copy_strategy]): New members.
- * pager.h (pager_create_pager): Added new args MAY_CACHE and
- COPY_STRATEGY.
- (pager_report_attributes): Deleted declaration.
- * object-init.c (_pager_seqnos_memory_object_init): Set attributes
- from values in P rather than by calling pager_report_attributes.
- * pager-attr.c (pager_change_attributes): Don't panic if the
- pager isn't yet initialized by the kernel; record the provided
- values in may_cache and copy_strategy.
-
- * pager-attr.c: Spelling fix.
- Include <assert.h>.
- * Makefile (COBJS): Added pager-attr.o.
-
-Fri May 20 15:41:12 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * lock-completed.c (_pager_seqnos_memory_object_lock_completed):
- Delete unneeded variable wakeup. Break out of loop as soon
- as we find the right record. Call condition_broadcast only
- if we need bother.
-
- * pager.h (pager_change_attributes, pager_report_attributes):
- New declarations.
- * priv.h (struct attribute_request): New structure.
- (struct pager [attribute_requests]): New member.
- * pager-create.c (pager_create): Initialize new member.
- * object-init.c (_pager_seqnos_memory_object_init): Call
- pager_report_attributes for correct args to memory_object_ready.
- * pager-attr.c: New file.
- * object-terminate.c (_pager_free_structure): Wakeup pending
- pager_change_attribute requests.
- * stubs.c (_pager_seqnos_memory_object_change_completed): Deleted
- function.
- * chg-compl.c: New file.
- * Makefile (COBJS): Added chg-compl.o.
-
-Thu May 5 07:49:21 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * stubs.c (_pager_seqnos_memory_object_supply_completed): Change
- RESULT arg to type kern_return_t; error_t is not compatible.
-
- * demuxer.c (pager_demuxer): Declare seqnos_memory_object_server.
-
- * stubs.c, lock-completed.c: Changed return type of all RPC server
- functions to kern_return_t. error_t is not compatible with the
- declarations in the mig-generated header files.
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
-Tue Apr 26 15:08:57 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * object-init.c (_pager_seqnos_memory_object_init): Only check
- for inits of active objects AFTER waiting for seqno; otherwise we
- could race against a prior terminate.
-
diff --git a/libpager/Makefile b/libpager/Makefile
index f8c0999a..fc23364a 100644
--- a/libpager/Makefile
+++ b/libpager/Makefile
@@ -29,6 +29,7 @@ SRCS = data-request.c data-return.c data-unlock.c pager-port.c \
LCLHDRS = pager.h priv.h
installhdrs = pager.h
+HURDLIBS= threads ports
OBJS = $(SRCS:.c=.o) memory_objectServer.o notifyServer.o
MIGSFLAGS = -DSEQNOS
@@ -36,5 +37,3 @@ MIGCOMSFLAGS = -prefix _pager_
include ../Makeconf
-libpager.so: $(foreach lib,threads ports,\
- ../lib$(lib)/lib$(lib).so)
diff --git a/libpager/data-init.c b/libpager/data-init.c
deleted file mode 100644
index f411a938..00000000
--- a/libpager/data-init.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Initial contents of memory object (default pager only)
- Copyright (C) 1994 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include "priv.h"
-#include "memory_object_default_S.h"
-
-kern_return_t
-_pager_seqnos_memory_object_data_initialize (mach_port_t object,
- mach_port_seqno_t seqno,
- mach_port_t control,
- vm_offset_t offset,
- pointer_t data,
- vm_size_t datalen)
-{
- _pager_do_write_request (object, seqno, control, offset, data,
- datalen, 1, 0, 1);
-}
diff --git a/libpager/data-request.c b/libpager/data-request.c
index 341fb924..36725b11 100644
--- a/libpager/data-request.c
+++ b/libpager/data-request.c
@@ -1,5 +1,5 @@
/* Implementation of memory_object_data_request for pager library
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,2000,02,10 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,7 +22,7 @@
/* Implement pagein callback as described in <mach/memory_object.defs>. */
kern_return_t
-_pager_seqnos_memory_object_data_request (mach_port_t object,
+_pager_seqnos_memory_object_data_request (mach_port_t object,
mach_port_seqno_t seqno,
mach_port_t control,
vm_offset_t offset,
@@ -30,7 +30,7 @@ _pager_seqnos_memory_object_data_request (mach_port_t object,
vm_prot_t access)
{
struct pager *p;
- char *pm_entry;
+ short *pm_entry;
int doread, doerror;
error_t err;
vm_address_t page;
@@ -43,7 +43,7 @@ _pager_seqnos_memory_object_data_request (mach_port_t object,
/* 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. */
if (control != p->memobjcntl)
{
@@ -52,7 +52,7 @@ _pager_seqnos_memory_object_data_request (mach_port_t object,
}
if (length != __vm_page_size)
{
- printf ("incg data request: bad length size %d\n", length);
+ printf ("incg data request: bad length size %zd\n", length);
goto release_out;
}
if (offset % __vm_page_size)
@@ -61,18 +61,18 @@ _pager_seqnos_memory_object_data_request (mach_port_t object,
goto release_out;
}
- _pager_block_termination (p); /* prevent termination until
+ _pager_block_termination (p); /* prevent termination until
mark_object_error is done */
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;
+ goto allow_release_out;
}
- _pager_pagemap_resize (p, offset + length);
+ err = _pager_pagemap_resize (p, offset + length);
+ if (err)
+ goto allow_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
@@ -97,9 +97,9 @@ _pager_seqnos_memory_object_data_request (mach_port_t object,
if (PM_NEXTERROR (*pm_entry) != PAGE_NOERR && (access & VM_PROT_WRITE))
{
- memory_object_data_error (control, offset, length,
+ memory_object_data_error (control, offset, length,
_pager_page_errors[PM_NEXTERROR (*pm_entry)]);
- _pager_mark_object_error (p, offset, length,
+ _pager_mark_object_error (p, offset, length,
_pager_page_errors[PM_NEXTERROR (*pm_entry)]);
*pm_entry = SET_PM_NEXTERROR (*pm_entry, PAGE_NOERR);
doread = 0;
@@ -117,7 +117,7 @@ _pager_seqnos_memory_object_data_request (mach_port_t object,
err = pager_read_page (p->upi, offset, &page, &write_lock);
if (err)
goto error_read;
-
+
memory_object_data_supply (p->memobjcntl, offset, page, length, 1,
write_lock ? VM_PROT_WRITE : VM_PROT_NONE, 0,
MACH_PORT_NULL);
@@ -128,20 +128,18 @@ _pager_seqnos_memory_object_data_request (mach_port_t object,
ports_port_deref (p);
return 0;
- allow_term_out:
- mutex_lock (&p->interlock);
- _pager_allow_termination (p);
- mutex_unlock (&p->interlock);
- ports_port_deref (p);
- return 0;
-
error_read:
memory_object_data_error (p->memobjcntl, offset, length, EIO);
_pager_mark_object_error (p, offset, length, EIO);
+ allow_term_out:
+ mutex_lock (&p->interlock);
_pager_allow_termination (p);
+ mutex_unlock (&p->interlock);
ports_port_deref (p);
return 0;
+ allow_release_out:
+ _pager_allow_termination (p);
release_out:
_pager_release_seqno (p, seqno);
mutex_unlock (&p->interlock);
diff --git a/libpager/data-return.c b/libpager/data-return.c
index 562af955..a010c6dc 100644
--- a/libpager/data-return.c
+++ b/libpager/data-return.c
@@ -1,5 +1,5 @@
/* Implementation of memory_object_data_return for pager library
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,99,2000,02 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
@@ -37,7 +37,7 @@ _pager_do_write_request (mach_port_t object,
int initializing)
{
struct pager *p;
- char *pm_entries;
+ short *pm_entries;
int npages, i;
error_t *pagerrs;
struct lock_request *lr;
@@ -45,7 +45,7 @@ _pager_do_write_request (mach_port_t object,
struct lock_list *next;} *lock_list, *ll;
int wakeup;
int omitdata = 0;
-
+
p = ports_lookup_port (0, object, _pager_class);
if (!p)
return EOPNOTSUPP;
@@ -53,7 +53,7 @@ _pager_do_write_request (mach_port_t object,
/* 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. */
if (control != p->memobjcntl)
{
@@ -62,7 +62,7 @@ _pager_do_write_request (mach_port_t object,
}
if (length % __vm_page_size)
{
- printf ("incg data return: bad length size %d\n", length);
+ printf ("incg data return: bad length size %zd\n", length);
goto release_out;
}
if (offset % __vm_page_size)
@@ -90,8 +90,21 @@ _pager_do_write_request (mach_port_t object,
pm_entries = &p->pagemap[offset / __vm_page_size];
+ /* 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
+ this object are going to wait for seqno while we wait for the
+ previous write), but the case is relatively infrequent. */
+ retry:
+ for (i = 0; i < npages; i++)
+ if (pm_entries[i] & PM_PAGINGOUT)
+ {
+ pm_entries[i] |= PM_WRITEWAIT;
+ condition_wait (&p->wakeup, &p->interlock);
+ goto retry;
+ }
+
/* Mark these pages as being paged out. */
-#if 0
if (initializing)
{
assert (npages <= 32);
@@ -106,13 +119,10 @@ _pager_do_write_request (mach_port_t object,
else
for (i = 0; i < npages; i++)
pm_entries[i] |= PM_PAGINGOUT | PM_INIT;
-#else
- for (i = 0; i < npages; i++)
- pm_entries[i] |= PM_PAGINGOUT;
+
if (!kcopy)
for (i = 0; i < npages; i++)
pm_entries[i] &= ~PM_INCORE;
-#endif
/* If this write occurs while a lock is pending, record
it. We have to keep this list because a lock request
@@ -140,8 +150,8 @@ _pager_do_write_request (mach_port_t object,
for (i = 0; i < npages; i++)
if (!(omitdata & (1 << i)))
- pagerrs[i] = pager_write_page (p->upi,
- offset + (vm_page_size * i),
+ pagerrs[i] = pager_write_page (p->upi,
+ offset + (vm_page_size * i),
data + (vm_page_size * i));
/* Acquire the right to meddle with the pagemap */
@@ -149,11 +159,15 @@ _pager_do_write_request (mach_port_t object,
_pager_pagemap_resize (p, offset + length);
pm_entries = &p->pagemap[offset / __vm_page_size];
+ wakeup = 0;
for (i = 0; i < npages; i++)
{
if (omitdata & (1 << i))
continue;
-
+
+ if (pm_entries[i] & PM_WRITEWAIT)
+ wakeup = 1;
+
if (pagerrs[i] && ! (pm_entries[i] & PM_PAGEINWAIT))
/* The only thing we can do here is mark the page, and give
errors from now on when it is to be read. This is
@@ -165,23 +179,22 @@ _pager_do_write_request (mach_port_t object,
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),
+ 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);
else
- vm_deallocate (mach_task_self (),
- data + (vm_page_size * i),
- vm_page_size);
+ munmap ((caddr_t) (data + (vm_page_size * i)),
+ vm_page_size);
- pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT);
+ pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT | PM_WRITEWAIT);
}
- wakeup = 0;
for (ll = lock_list; ll; ll = ll->next)
if (!--ll->lr->pending_writes && !ll->lr->locks_pending)
wakeup = 1;
+
if (wakeup)
condition_broadcast (&p->wakeup);
@@ -201,7 +214,7 @@ _pager_do_write_request (mach_port_t object,
/* Implement pageout call back as described by <mach/memory_object.defs>. */
kern_return_t
-_pager_seqnos_memory_object_data_return (mach_port_t object,
+_pager_seqnos_memory_object_data_return (mach_port_t object,
mach_port_seqno_t seqno,
mach_port_t control,
vm_offset_t offset,
diff --git a/libpager/data-unlock.c b/libpager/data-unlock.c
index a4ef0600..9692f589 100644
--- a/libpager/data-unlock.c
+++ b/libpager/data-unlock.c
@@ -1,5 +1,5 @@
/* Implementation of memory_object_data_unlock for pager library
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994,95,2002 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
@@ -19,10 +19,10 @@
#include "memory_object_S.h"
#include <stdio.h>
-/* Implement kernel requests for access as described in
+/* Implement kernel requests for access as described in
<mach/memory_object.defs>. */
kern_return_t
-_pager_seqnos_memory_object_data_unlock (mach_port_t object,
+_pager_seqnos_memory_object_data_unlock (mach_port_t object,
mach_port_seqno_t seqno,
mach_port_t control,
vm_offset_t offset,
@@ -31,7 +31,7 @@ _pager_seqnos_memory_object_data_unlock (mach_port_t object,
{
struct pager *p;
volatile int err;
-
+
p = ports_lookup_port (0, object, _pager_class);
if (!p)
return EOPNOTSUPP;
@@ -65,12 +65,12 @@ _pager_seqnos_memory_object_data_unlock (mach_port_t object,
}
if (length != __vm_page_size)
{
- printf ("incg data unlock: bad length size %d\n", length);
+ printf ("incg data unlock: bad length size %zd\n", length);
goto out;
}
err = pager_unlock_page (p->upi, offset);
-
+
if (!err)
/* We can go ahead and release the lock. */
_pager_lock_object (p, offset, length, MEMORY_OBJECT_RETURN_NONE, 0,
@@ -87,4 +87,3 @@ _pager_seqnos_memory_object_data_unlock (mach_port_t object,
ports_port_deref (p);
return 0;
}
-
diff --git a/libpager/demuxer.c b/libpager/demuxer.c
index f233d1c0..79c0ddc5 100644
--- a/libpager/demuxer.c
+++ b/libpager/demuxer.c
@@ -1,5 +1,5 @@
/* Demuxer for pager library
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994, 1995, 2002, 2011 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -20,7 +20,7 @@
#include "notify_S.h"
/* Demultiplex a single message directed at a pager port; INP is the
- message received; fille OUTP with the reply. */
+ message received; fill OUTP with the reply. */
int
pager_demuxer (mach_msg_header_t *inp,
mach_msg_header_t *outp)
@@ -29,8 +29,12 @@ pager_demuxer (mach_msg_header_t *inp,
mach_msg_header_t *outp);
extern int _pager_seqnos_notify_server (mach_msg_header_t *inp,
mach_msg_header_t *outp);
-
- return (_pager_seqnos_memory_object_server (inp, outp)
- || _pager_seqnos_notify_server (inp, outp));
-}
+ int result = _pager_seqnos_memory_object_server (inp, outp)
+ || _pager_seqnos_notify_server (inp, outp);
+ if (!result)
+ /* Synchronize our bookkeeping of the port's seqno with the one consumed by
+ this bogus message. */
+ _pager_update_seqno (inp->msgh_local_port, inp->msgh_seqno);
+ return result;
+}
diff --git a/libpager/lock-object.c b/libpager/lock-object.c
index d2f6da6d..d108666e 100644
--- a/libpager/lock-object.c
+++ b/libpager/lock-object.c
@@ -1,5 +1,5 @@
/* Synchronous wrapper for memory_object_lock_request
- Copyright (C) 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1993, 1994, 1996, 1997, 2000 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -30,9 +30,8 @@ _pager_lock_object (struct pager *p,
vm_prot_t lock_value,
int sync)
{
- struct lock_request *lr = 0;
- char *pm_entries;
int i;
+ struct lock_request *lr = 0;
mutex_lock (&p->interlock);
if (p->pager_state != NORMAL)
@@ -85,10 +84,20 @@ _pager_lock_object (struct pager *p,
if (should_flush)
{
+ vm_offset_t pm_offs = offset / __vm_page_size;
+
_pager_pagemap_resize (p, offset + size);
- pm_entries = &p->pagemap[offset / __vm_page_size];
- for (i = 0; i < size / vm_page_size; i++)
- pm_entries[i] &= ~PM_INCORE;
+ if (p->pagemapsize > pm_offs)
+ {
+ short *pm_entries = &p->pagemap[pm_offs];
+ vm_offset_t bound = size / vm_page_size;
+
+ if (bound > p->pagemapsize)
+ bound = p->pagemapsize;
+
+ for (i = 0; i < bound; i++)
+ pm_entries[i] &= ~PM_INCORE;
+ }
}
}
diff --git a/libpager/mark-error.c b/libpager/mark-error.c
index 411d3a7d..5c4e029d 100644
--- a/libpager/mark-error.c
+++ b/libpager/mark-error.c
@@ -1,5 +1,5 @@
/* Recording errors for pager library
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -32,7 +32,7 @@ _pager_mark_next_request_error(struct pager *pager,
error_t error)
{
int page_error;
- char *p;
+ short *p;
offset /= __vm_page_size;
length /= __vm_page_size;
@@ -70,7 +70,7 @@ _pager_mark_object_error(struct pager *pager,
error_t error)
{
int page_error = 0;
- char *p;
+ short *p;
offset /= __vm_page_size;
length /= __vm_page_size;
@@ -99,16 +99,24 @@ _pager_mark_object_error(struct pager *pager,
/* Tell us what the error (set with mark_object_error) for
pager P is on page ADDR. */
error_t
-pager_get_error (struct pager *p,
- vm_address_t addr)
+pager_get_error (struct pager *p, vm_address_t addr)
{
error_t err;
mutex_lock (&p->interlock);
- _pager_pagemap_resize (p, addr);
-
- err = _pager_page_errors[PM_ERROR(p->pagemap[addr/__vm_page_size])];
+
+ addr /= vm_page_size;
+
+ /* If there really is no error for ADDR, we should be able to exted the
+ pagemap table; otherwise, if some previous operation failed because it
+ couldn't extend the table, this attempt will *probably* (heh) fail for
+ the same reason. */
+ err = _pager_pagemap_resize (p, addr);
+
+ if (! err)
+ err = _pager_page_errors[PM_ERROR(p->pagemap[addr])];
mutex_unlock (&p->interlock);
+
return err;
}
diff --git a/libpager/notify-stubs.c b/libpager/notify-stubs.c
index 728163e4..2d791aac 100644
--- a/libpager/notify-stubs.c
+++ b/libpager/notify-stubs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2011 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -18,58 +18,59 @@
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>
error_t
-_pager_do_seqnos_mach_notify_port_deleted (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
+_pager_do_seqnos_mach_notify_port_deleted (mach_port_t notify,
+ mach_port_seqno_t seqno,
mach_port_t name
__attribute__ ((unused)))
{
+ _pager_update_seqno (notify, seqno);
+
return 0;
}
error_t
-_pager_do_seqnos_mach_notify_msg_accepted (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
+_pager_do_seqnos_mach_notify_msg_accepted (mach_port_t notify,
+ mach_port_seqno_t seqno,
mach_port_t name
__attribute__ ((unused)))
{
+ _pager_update_seqno (notify, seqno);
+
return 0;
}
error_t
-_pager_do_seqnos_mach_notify_port_destroyed (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
+_pager_do_seqnos_mach_notify_port_destroyed (mach_port_t notify,
+ mach_port_seqno_t seqno,
mach_port_t name
__attribute__ ((unused)))
{
+ _pager_update_seqno (notify, seqno);
+
return 0;
}
error_t
-_pager_do_seqnos_mach_notify_send_once (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)))
+_pager_do_seqnos_mach_notify_send_once (mach_port_t notify,
+ mach_port_seqno_t seqno)
{
+ _pager_update_seqno (notify, seqno);
+
return 0;
}
error_t
-_pager_do_seqnos_mach_notify_dead_name (mach_port_t notify
- __attribute__ ((unused)),
- mach_port_seqno_t seqno
- __attribute__ ((unused)),
+_pager_do_seqnos_mach_notify_dead_name (mach_port_t notify,
+ mach_port_seqno_t seqno,
mach_port_t name
__attribute__ ((unused)))
{
+ _pager_update_seqno (notify, seqno);
+
return 0;
}
diff --git a/libpager/object-create.c b/libpager/object-create.c
deleted file mode 100644
index c8dfe6de..00000000
--- a/libpager/object-create.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Create a new memory object (Default pager only)
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
-#include "priv.h"
-#include "memory_object_create_S.h"
-
-/* Implement the object creation call as described in
- <mach/memory_object_default.defs>. */
-kern_return_t
-_pager_seqnos_memory_object_create (mach_port_t master,
- mach_port_seqno_t seqno,
- mach_port_t newobject,
- vm_size_t objectsize,
- mach_port_t newctl,
- mach_port_t newname,
- vm_size_t objectpagesize)
-{
- struct port_info *masterpi;
- struct pager *p;
-
- if (!pager_support_defpager)
- return EOPNOTSUPP;
-
- if (objectpagesize != vm_page_size)
- return EINVAL;
-
- masterpi = ports_check_port_type (object, pager_master_port_type);
- if (!masterpi)
- return EOPNOTSUPP;
-
- p = ports_intern_external_port (newobject, sizeof (struct pager),
- pager_port_type);
-
- p->pager_state = NORMAL;
- mutex_init (&p->interlock);
- condition_init (&p->wakeup);
- p->lock_requests = 0;
- p->attribute_requests = 0;
- p->may_cache = 0;
- p->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
- p->memobjcntl = newctl;
- p->memobjname = newname;
- p->seqno = -1;
- p->noterm = 0;
- p->waitingforseqno = 0;
- p->pagemap = 0;
- p->pagemapsize = 0;
-
- p->upi = pager_create_upi (p);
-
- ports_port_deref (p);
- return 0;
-}
-
-
diff --git a/libpager/object-terminate.c b/libpager/object-terminate.c
index 8598ab50..dc53541c 100644
--- a/libpager/object-terminate.c
+++ b/libpager/object-terminate.c
@@ -1,5 +1,5 @@
/* Implementation of memory_object_terminate for pager library
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1999, 2000 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -53,6 +53,12 @@ _pager_seqnos_memory_object_terminate (mach_port_t object,
condition_wait (&p->wakeup, &p->interlock);
}
+ /* Destry the ports we received; mark that in P so that it doesn't bother
+ doing it again. */
+ mach_port_destroy (mach_task_self (), control);
+ mach_port_destroy (mach_task_self (), name);
+ p->memobjcntl = p->memobjname = MACH_PORT_NULL;
+
_pager_free_structure (p);
#ifdef KERNEL_INIT_RACE
@@ -104,13 +110,21 @@ _pager_free_structure (struct pager *p)
if (wakeup)
condition_broadcast (&p->wakeup);
- mach_port_deallocate (mach_task_self (), p->memobjcntl);
- mach_port_deallocate (mach_task_self (), p->memobjname);
+ if (p->memobjcntl != MACH_PORT_NULL)
+ {
+ mach_port_deallocate (mach_task_self (), p->memobjcntl);
+ p->memobjcntl = MACH_PORT_NULL;
+ }
+ if (p->memobjname != MACH_PORT_NULL)
+ {
+ mach_port_deallocate (mach_task_self (), p->memobjname);
+ p->memobjname = MACH_PORT_NULL;
+ }
/* Free the pagemap */
if (p->pagemapsize)
{
- vm_deallocate (mach_task_self (), (u_int)p->pagemap, p->pagemapsize);
+ munmap (p->pagemap, p->pagemapsize * sizeof (* p->pagemap));
p->pagemapsize = 0;
p->pagemap = 0;
}
diff --git a/libpager/offer-page.c b/libpager/offer-page.c
index fe08d3b4..aed22197 100644
--- a/libpager/offer-page.c
+++ b/libpager/offer-page.c
@@ -1,5 +1,5 @@
/* Wrapper for unsolicited memory_object_data_supply
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,23 +28,25 @@ pager_offer_page (struct pager *p,
vm_offset_t offset,
vm_address_t buf)
{
- char *pm_entry;
-
- try_again:
mutex_lock (&p->interlock);
- _pager_pagemap_resize (p, offset + vm_page_size);
- pm_entry = &p->pagemap[offset / vm_page_size];
- if (*pm_entry & PM_INCORE)
+
+ if (_pager_pagemap_resize (p, offset + vm_page_size))
{
- mutex_unlock (&p->interlock);
- pager_flush_some (p, offset, vm_page_size, 1);
- goto try_again;
+ short *pm_entry = &p->pagemap[offset / vm_page_size];
+
+ while (*pm_entry & PM_INCORE)
+ {
+ mutex_unlock (&p->interlock);
+ pager_flush_some (p, offset, vm_page_size, 1);
+ mutex_lock (&p->interlock);
+ }
+ *pm_entry |= PM_INCORE;
+
+ memory_object_data_supply (p->memobjcntl, offset, buf, vm_page_size, 0,
+ writelock ? VM_PROT_WRITE : VM_PROT_NONE,
+ precious, MACH_PORT_NULL);
}
- *pm_entry |= PM_INCORE;
- memory_object_data_supply (p->memobjcntl, offset, buf, vm_page_size, 0,
- writelock ? VM_PROT_WRITE : VM_PROT_NONE,
- precious, MACH_PORT_NULL);
mutex_unlock (&p->interlock);
}
diff --git a/libpager/pagemap.c b/libpager/pagemap.c
index 2adbcc0e..b8b3362c 100644
--- a/libpager/pagemap.c
+++ b/libpager/pagemap.c
@@ -1,5 +1,5 @@
/* Pagemap manipulation for pager library
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 1997, 1999, 2000 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,21 +19,29 @@
#include <string.h>
/* Grow the pagemap of pager P as necessary to deal with address OFF */
-void
-_pager_pagemap_resize (struct pager *p,
- vm_address_t off)
+error_t
+_pager_pagemap_resize (struct pager *p, vm_address_t off)
{
- void *newaddr;
- int newsize;
+ error_t err = 0;
off /= __vm_page_size;
- if (p->pagemapsize >= off)
- return;
-
- newsize = round_page (off);
- vm_allocate (mach_task_self (), (u_int *)&newaddr, newsize, 1);
- bcopy (p->pagemap, newaddr, p->pagemapsize);
- vm_deallocate (mach_task_self (), (u_int)p->pagemap, p->pagemapsize);
- p->pagemap = newaddr;
- p->pagemapsize = newsize;
+
+ if (p->pagemapsize < off)
+ {
+ void *newaddr;
+ int newsize = round_page (off);
+
+ newaddr = mmap (0, newsize * sizeof (*p->pagemap),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = (newaddr == (void *) -1) ? errno : 0;
+ if (! err)
+ {
+ bcopy (p->pagemap, newaddr, p->pagemapsize * sizeof (*p->pagemap));
+ munmap (p->pagemap, p->pagemapsize * sizeof (*p->pagemap));
+ p->pagemap = newaddr;
+ p->pagemapsize = newsize;
+ }
+ }
+
+ return err;
}
diff --git a/libpager/pager-memcpy.c b/libpager/pager-memcpy.c
index 0333c805..f2be5585 100644
--- a/libpager/pager-memcpy.c
+++ b/libpager/pager-memcpy.c
@@ -1,5 +1,5 @@
/* Fault-safe copy into or out of pager-backed memory.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,99, 2000,01,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This program is free software; you can redistribute it and/or
@@ -16,9 +16,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include "priv.h"
#include "pager.h"
+#include <sys/mman.h>
#include <hurd/sigpreempt.h>
#include <assert.h>
+#include <string.h>
+
+/* Start using vm_copy over memcpy when we have that many page. This is
+ roughly the L1 cache size. (This value *cannot* be less than
+ vm_page_size.) */
+#define VMCOPY_BETTER_THAN_MEMCPY (8*vm_page_size)
/* Try to copy *SIZE bytes between the region OTHER points to
and the region at OFFSET in the pager indicated by PAGER and MEMOBJ.
@@ -27,55 +35,136 @@
*SIZE is always filled in the actual number of bytes successfully copied.
Returns an error code if the pager-backed memory faults;
if there is no fault, returns 0 and *SIZE will be unchanged. */
-
error_t
pager_memcpy (struct pager *pager, memory_object_t memobj,
vm_offset_t offset, void *other, size_t *size,
vm_prot_t prot)
{
- vm_address_t window = 0;
- vm_size_t windowsize = 8 * vm_page_size;
- size_t to_copy = *size;
error_t err;
+ size_t n = *size;
- error_t copy (struct hurd_signal_preempter *preempter)
+#define VMCOPY_WINDOW_DEFAULT_SIZE (32 * vm_page_size)
+#define MEMCPY_WINDOW_DEFAULT_SIZE (32 * vm_page_size)
+ vm_address_t window;
+ vm_size_t window_size;
+
+ error_t do_vm_copy (void)
{
- while (to_copy > 0)
- {
- size_t pageoff = offset & (vm_page_size - 1);
+ assert ((offset & (vm_page_size - 1)) == 0);
+ assert (((vm_address_t) other & (vm_page_size - 1)) == 0);
+ assert (n >= vm_page_size);
- if (window)
- /* Deallocate the old window. */
- vm_deallocate (mach_task_self (), window, windowsize);
+ do
+ {
+ window_size =
+ VMCOPY_WINDOW_DEFAULT_SIZE > n
+ ? (n - (n & (vm_page_size - 1)))
+ : VMCOPY_WINDOW_DEFAULT_SIZE;
+
+ assert (window_size >= VMCOPY_BETTER_THAN_MEMCPY);
+ assert ((window_size & (vm_page_size - 1)) == 0);
+
+ err = vm_map (mach_task_self (), &window, window_size, 0, 1,
+ memobj, offset, 0, prot, prot, VM_INHERIT_NONE);
+ if (err)
+ return err;
- /* Map in and copy a standard-sized window, unless that is
- more than the total left to be copied. */
+ if (prot == VM_PROT_READ)
+ err = vm_copy (mach_task_self (), window, window_size,
+ (vm_address_t) other);
+ else
+ err = vm_copy (mach_task_self (), (vm_address_t) other,
+ window_size, window);
- if (windowsize > pageoff + to_copy)
- windowsize = pageoff + to_copy;
+ vm_deallocate (mach_task_self (), window, window_size);
- window = 0;
- err = vm_map (mach_task_self (), &window, windowsize, 0, 1,
- memobj, offset - pageoff, 0,
- prot, prot, VM_INHERIT_NONE);
if (err)
- return 0;
+ return err;
- /* Realign the fault preempter for the new mapping window. */
- preempter->first = window;
- preempter->last = window + windowsize;
+ other += window_size;
+ offset += window_size;
+ n -= window_size;
+ }
+ while (n >= VMCOPY_BETTER_THAN_MEMCPY);
- if (prot == VM_PROT_READ)
- memcpy (other, (const void *) window + pageoff,
- windowsize - pageoff);
- else
- memcpy ((void *) window + pageoff, other, windowsize - pageoff);
+ return 0;
+ }
- offset += windowsize - pageoff;
- other += windowsize - pageoff;
- to_copy -= windowsize - pageoff;
+ error_t do_copy (struct hurd_signal_preemptor *preemptor)
+ {
+ error_t do_memcpy (size_t to_copy)
+ {
+ window_size = MEMCPY_WINDOW_DEFAULT_SIZE;
+
+ do
+ {
+ size_t pageoff = offset & (vm_page_size - 1);
+ size_t copy_count = window_size - pageoff;
+
+ /* Map in and copy a standard-sized window, unless that is
+ more than the total left to be copied. */
+
+ if (window_size >= round_page (pageoff + to_copy))
+ {
+ copy_count = to_copy;
+ window_size = round_page (pageoff + to_copy);
+ }
+
+ err = vm_map (mach_task_self (), &window, window_size, 0, 1,
+ memobj, offset - pageoff, 0,
+ prot, prot, VM_INHERIT_NONE);
+ if (err)
+ return err;
+
+ /* Realign the fault preemptor for the new mapping window. */
+ preemptor->first = window;
+ preemptor->last = window + window_size;
+
+ if (prot == VM_PROT_READ)
+ memcpy (other, (const void *) window + pageoff, copy_count);
+ else
+ memcpy ((void *) window + pageoff, other, copy_count);
+
+ vm_deallocate (mach_task_self (), window, window_size);
+
+ offset += copy_count;
+ other += copy_count;
+ to_copy -= copy_count;
+ n -= copy_count;
+
+ assert (n >= 0);
+ assert (to_copy >= 0);
+ }
+ while (to_copy > 0);
+
+ return 0;
}
- return 0;
+
+ /* Can we use vm_copy? */
+ if ((((vm_address_t) other & (vm_page_size - 1))
+ == (offset & (vm_page_size - 1)))
+ && (n >= (VMCOPY_BETTER_THAN_MEMCPY + vm_page_size
+ - ((vm_address_t) other & (vm_page_size - 1)))))
+ /* 1) other and offset are aligned with repect to each other;
+ and 2) we have at least VMCOPY_BETTER_THAN_MEMCPY fully
+ aligned pages. */
+ {
+ err = do_memcpy (vm_page_size
+ - ((vm_address_t) other & (vm_page_size - 1)));
+ if (err)
+ return err;
+
+ assert (n >= VMCOPY_BETTER_THAN_MEMCPY);
+
+ err = do_vm_copy ();
+ if (err || n == 0)
+ /* We failed or we finished. */
+ return err;
+
+ assert (n < VMCOPY_BETTER_THAN_MEMCPY);
+ }
+
+ return do_memcpy (n);
}
jmp_buf buf;
@@ -83,19 +172,47 @@ pager_memcpy (struct pager *pager, memory_object_t memobj,
{
assert (scp->sc_error == EKERN_MEMORY_ERROR);
err = pager_get_error (pager, sigcode - window + offset);
- to_copy -= sigcode - window;
+ n -= sigcode - window;
+ vm_deallocate (mach_task_self (), window, window_size);
longjmp (buf, 1);
}
+ if (n == 0)
+ /* Nothing to do. */
+ return 0;
+
+ if (((vm_address_t) other & (vm_page_size - 1)) == 0
+ && (offset & (vm_page_size - 1)) == 0
+ && n >= VMCOPY_BETTER_THAN_MEMCPY)
+ /* 1) the start address is page aligned; 2) the offset is page
+ aligned; and 3) we have more than VMCOPY_BETTER_THAN_MEMCPY
+ pages. */
+ {
+ err = do_vm_copy ();
+ if (err || n == 0)
+ /* We failed or we finished. */
+ {
+ *size -= n;
+ return err;
+ }
+
+ assert (n < VMCOPY_BETTER_THAN_MEMCPY);
+ }
+
+ /* Need to do it the hard way. */
+
+ window = 0;
+ window_size = 0;
+
if (setjmp (buf) == 0)
hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),
- window, window + windowsize,
- &copy, (sighandler_t) &fault);
+ window, window + window_size,
+ &do_copy, (sighandler_t) &fault);
- if (window)
- vm_deallocate (mach_task_self (), window, windowsize);
+ if (! err)
+ assert (n == 0);
- *size -= to_copy;
+ *size -= n;
return err;
}
diff --git a/libpager/pager.h b/libpager/pager.h
index c6bd4971..99fb3845 100644
--- a/libpager/pager.h
+++ b/libpager/pager.h
@@ -1,5 +1,5 @@
/* Definitions for multi-threaded pager library
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1996, 1997, 1999 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
@@ -38,7 +38,7 @@ int pager_demuxer (mach_msg_header_t *inp,
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. */
+ functions. On errors, return null and set errno. */
struct pager *
pager_create (struct user_pager_info *u_pager,
struct port_bucket *bucket,
@@ -151,7 +151,7 @@ pager_memcpy (struct pager *pager, memory_object_t memobj,
/* The user must define this function. For pager PAGER, read one
page from offset PAGE. Set *BUF to be the address of the page,
and set *WRITE_LOCK if the page must be provided read-only.
- The only permissable error returns are EIO, EDQUOT, and ENOSPC. */
+ The only permissible error returns are EIO, EDQUOT, and ENOSPC. */
error_t
pager_read_page (struct user_pager_info *pager,
vm_offset_t page,
@@ -159,8 +159,8 @@ pager_read_page (struct user_pager_info *pager,
int *write_lock);
/* The user must define this function. For pager PAGER, synchronously
- write one page from BUF to offset PAGE. In addition, vm_deallocate
- (or equivalent) BUF. The only permissable error returns are EIO,
+ write one page from BUF to offset PAGE. In addition, mfree
+ (or equivalent) BUF. The only permissible error returns are EIO,
EDQUOT, and ENOSPC. */
error_t
pager_write_page (struct user_pager_info *pager,
diff --git a/libpager/priv.h b/libpager/priv.h
index 98fca8d4..586bccbf 100644
--- a/libpager/priv.h
+++ b/libpager/priv.h
@@ -1,5 +1,5 @@
/* Private data for pager library.
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994-1997, 1999, 2000, 2011 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
@@ -17,6 +17,7 @@
#include <mach.h>
#include <hurd.h>
+#include <sys/mman.h>
#include "pager.h"
#include <hurd/ports.h>
@@ -35,21 +36,21 @@ struct pager
NORMAL, /* while running */
SHUTDOWN, /* ignore all further requests */
} pager_state;
-
+
struct mutex interlock;
struct condition wakeup;
struct lock_request *lock_requests; /* pending lock requests */
struct attribute_request *attribute_requests; /* pending attr requests */
-
+
boolean_t may_cache;
memory_object_copy_strategy_t copy_strategy;
/* Interface ports */
memory_object_control_t memobjcntl;
memory_object_name_t memobjname;
-
- int seqno;
+
+ mach_port_seqno_t seqno;
int noterm; /* number of threads blocking termination */
@@ -57,15 +58,15 @@ struct pager
int termwaiting:1;
int waitingforseqno:1;
-
+
#ifdef KERNEL_INIT_RACE
/* Out of sequence object_init calls waiting for
terminations. */
struct pending_init *init_head, *init_tail;
#endif
- char *pagemap;
- int pagemapsize;
+ short *pagemap;
+ int pagemapsize; /* number of elements in PAGEMAP */
};
struct lock_request
@@ -107,11 +108,12 @@ extern int _pager_page_errors[];
/* Pagemap format */
/* These are binary state bits */
-/* #define PM_INIT 0x80 data has been written */
-#define PM_INCORE 0x80 /* kernel might have a copy */
-#define PM_PAGINGOUT 0x40 /* being written to disk */
-#define PM_PAGEINWAIT 0x20 /* provide data back when write done */
-#define PM_INVALID 0x10 /* data on disk is irrevocably wrong */
+#define PM_WRITEWAIT 0x0200 /* queue wakeup once write is done */
+#define PM_INIT 0x0100 /* data has been written */
+#define PM_INCORE 0x0080 /* kernel might have a copy */
+#define PM_PAGINGOUT 0x0040 /* being written to disk */
+#define PM_PAGEINWAIT 0x0020 /* provide data back when write done */
+#define PM_INVALID 0x0010 /* data on disk is irrevocably wrong */
/* These take values of enum page_errors */
@@ -129,11 +131,12 @@ extern int _pager_page_errors[];
struct port_class *_pager_class;
-void _pager_wait_for_seqno (struct pager *, int);
-void _pager_release_seqno (struct pager *, int);
+void _pager_wait_for_seqno (struct pager *, mach_port_seqno_t);
+void _pager_release_seqno (struct pager *, mach_port_seqno_t);
+void _pager_update_seqno (mach_port_t, mach_port_seqno_t);
void _pager_block_termination (struct pager *);
void _pager_allow_termination (struct pager *);
-void _pager_pagemap_resize (struct pager *, vm_address_t);
+error_t _pager_pagemap_resize (struct pager *, vm_address_t);
void _pager_mark_next_request_error (struct pager *, vm_address_t,
vm_size_t, error_t);
void _pager_mark_object_error (struct pager *, vm_address_t,
diff --git a/libpager/seqnos.c b/libpager/seqnos.c
index 94cce93b..7d8bcba7 100644
--- a/libpager/seqnos.c
+++ b/libpager/seqnos.c
@@ -1,5 +1,5 @@
/* Sequence number synchronization routines for pager library
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 2011 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,7 +23,7 @@
return. */
void
_pager_wait_for_seqno (struct pager *p,
- int seqno)
+ mach_port_seqno_t seqno)
{
while (seqno != p->seqno + 1)
{
@@ -37,7 +37,7 @@ _pager_wait_for_seqno (struct pager *p,
_pager_wait_for_seqno) to be handled. */
void
_pager_release_seqno (struct pager *p,
- int seqno)
+ mach_port_seqno_t seqno)
{
assert (seqno == p->seqno + 1);
p->seqno = seqno;
@@ -47,3 +47,23 @@ _pager_release_seqno (struct pager *p,
condition_broadcast (&p->wakeup);
}
}
+
+
+/* Just update the seqno. */
+void
+_pager_update_seqno (mach_port_t object,
+ mach_port_seqno_t 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);
+ }
+}
diff --git a/libpager/stubs.c b/libpager/stubs.c
index b455699e..84782120 100644
--- a/libpager/stubs.c
+++ b/libpager/stubs.c
@@ -1,5 +1,5 @@
/* Unused memory object interface stubs
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 2011 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -21,19 +21,22 @@
#include <stdio.h>
kern_return_t
-_pager_seqnos_memory_object_copy (mach_port_t old,
+_pager_seqnos_memory_object_copy (mach_port_t obj,
mach_port_seqno_t seq,
- memory_object_control_t old_ctl,
+ memory_object_control_t obj_ctl,
vm_offset_t off,
vm_size_t len,
mach_port_t new)
{
printf ("m_o_copy called\n");
+
+ _pager_update_seqno (obj, seq);
+
return EOPNOTSUPP;
}
kern_return_t
-_pager_seqnos_memory_object_data_write (mach_port_t old,
+_pager_seqnos_memory_object_data_write (mach_port_t obj,
mach_port_seqno_t seq,
mach_port_t ctl,
vm_offset_t off,
@@ -41,6 +44,9 @@ _pager_seqnos_memory_object_data_write (mach_port_t old,
vm_size_t data_cnt)
{
printf ("m_o_data_write called\n");
+
+ _pager_update_seqno (obj, seq);
+
return EOPNOTSUPP;
}
@@ -54,6 +60,8 @@ _pager_seqnos_memory_object_supply_completed (mach_port_t obj,
vm_offset_t err_off)
{
printf ("m_o_supply_completed called\n");
+
+ _pager_update_seqno (obj, seq);
+
return EOPNOTSUPP;
}
-
diff --git a/libpipe/ChangeLog b/libpipe/ChangeLog
deleted file mode 100644
index cbc850c4..00000000
--- a/libpipe/ChangeLog
+++ /dev/null
@@ -1,137 +0,0 @@
-Tue Jul 16 11:33:34 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pipe.h (EWOULDBLOCK): Define to work around new libc bug.
-
-Mon Jul 1 17:29:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pq.c (pq_queue): Initialize PACKET->buf_vm_alloced.
-
-Tue Jan 23 12:44:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pq.h (packet_ensure, packet_ensure_efficiently): Use packet_fit().
- (packet_fit): New function.
- * pq.c (packet_read): If there's lots of empty space at the
- beginning of a vm_alloced buffer, deallocate it.
-
-Mon Jan 22 17:12:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pq.c (packet_realloc): Reflect in the new values of BUF_START &
- BUF_END that we've removed any empty space at the beginning of BUF.
-
-Sat Jan 13 13:56:13 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pq.h (packet_ensure, packet_ensure_efficiently): Use
- packet_new_size() instead of packet_size_adjust().
- (packet_size_adjust): Declaration removed.
- (packet_new_size): New declaration.
- * pq.c (packet_size_adjust): Function removed.
- (packet_new_size): New function.
-
- * pq.c (packet_read): Re-arrange to be slightly less confusing.
- Reverse start-past-buf-beginning test that may have leaked memory.
-
- * pipe.c (pipe_send): For non-blocking writes, avoid writing more
- than the user requested.
-
-Fri Jan 12 12:15:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pq.c (pq_queue): Initialize the ports_alloced field.
- (packet_read): When a page-aligned read consumes the whole buffer,
- but there's a non-page-multiple amount available, don't let
- buf_len become negative.
-
-Mon Oct 9 14:57:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile: Specify shared library dependencies.
-
-Thu Sep 7 09:08:30 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pq.c (packet_read): Don't leave PACKET in a fucked up state when
- it's vm_allocate'd but doesn't a page-multiple amount of data and
- we're reading everything.
-
- * pipe.c (_pipe_no_readers): REALLY wake up writers when the pipe
- breaks.
-
-Fri Sep 1 10:42:03 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pipe.c (_pipe_no_readers): Wake up write selects too when the
- pipe breaks.
-
-Thu Aug 31 14:39:21 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pipe.c (pipe_send): Make writes blockable.
- (pipe_recv): Wakeup blocked writers.
- (pipe_kick): Function deleted.
- (pipe_create): Make connection-oriented pipes start out broken.
- (_pipe_first_reader): New function.
- (_pipe_first_writer): Don't check whether PIPE is connection-
- oriented before clearing PIPE_BROKEN, as otherwise it will never
- be set.
- (pipe_pair_select): New function.
- (pipe_multiple_lock): New variable.
- * pipe.h (pipe_wait): Renamed to `pipe_wait_readable'.
- (pipe_select): Renamed to `pipe_select_readable'.
- (pipe_writable, pipe_wait_writable, pipe_select_writable): New funcs.
- (pipe_acquire_reader): Call _pipe_first_reader if necessary.
- (_pipe_first_reader): New declaration.
- (struct pipe): New fields: `write_limit', `write_atomic',
- `pending_writes', `pending_write_selects'.
- (struct pipe): `pending_selects' changed to `pending_read_selects'.
- (pipe_pair_select): New declaration.
-
-Tue Aug 29 14:37:49 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * pipe.c (pipe_send): Use condition_broadcast, not condition_signal.
- * pipe.h (pipe_select): New function.
-
- * pipe.h (struct pipe): Remove interrupt_seq_num field.
- (pipe_wait): Use hurd_condition_wait to detect interrupts instead
- of previous ad-hoc mechanism.
-
- * pipe.c (pipe_create): Don't initialize interrupt_seq_num field.
-
- * pipe.h (pipe_acquire_reader, pipe_acquire_writer,
- pipe_add_reader, pipe_add_writer): `aquire' -> `acquire'.
-
-Fri Aug 11 18:35:32 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pipe.c (pipe_create): Initialize READERS & WRITERS, not REFS.
- (_pipe_first_writer): New function.
- (_pipe_no_writers, _pipe_no_writers): New function.
- (pipe_break): Function deleted.
-
-Wed Aug 9 12:53:05 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * pipe.h (struct pipe): Keep separate ref counts for readers and
- writers.
- (pipe_aquire_reader, pipe_aquire_writer): New functions.
- (pipe_release_reader, pipe_release_writer): New functions.
- (pipe_add_reader, pipe_add_writer): New functions.
- (pipe_remove_reader, pipe_remove_writer): New functions.
- (_pipe_first_writer): New function decl.
- (_pipe_no_writers, _pipe_no_writers): New function decl.
- (pipe_aquire, pipe_release): Function deleted.
- (pipe_break): Function decl deleted.
-
-Tue Aug 1 12:37:27 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pipe.c (pipe_recv): Get rid of code to deal with getting the
- source address from the control packet if there is no data packet,
- since pipe_write always writes a data packet.
-
-Mon Jul 31 14:50:00 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pipe.c (pipe_recv): Assert that a control packet should only
- have a source address if there is no corresponding data packet.
- (pipe_send): Change the test to determine whether we should write
- a control packet, so that we only do so if we need to. Also,
- don't record the source address in control packets, as it's
- recorded in the following data packet anyway, and this prevents it
- from being dealloc'd twice.
-
-Fri Jul 28 23:03:27 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pipe.h (stream_pipe_class, dgram_pipe_class, seqpack_pipe_class):
- Make these declarations extern so they don't fuck up initialization.
- (seqpacket_pipe_class): Renamed to `seqpack_pipe_class'.
diff --git a/libpipe/Makefile b/libpipe/Makefile
index 8fed5382..b64166a6 100644
--- a/libpipe/Makefile
+++ b/libpipe/Makefile
@@ -1,6 +1,6 @@
# Makefile for libpipe
#
-# Copyright (C) 1995 Free Software Foundation, Inc.
+# Copyright (C) 1995, 1996 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
@@ -22,12 +22,11 @@ makemode := library
libname = libpipe
installhdrs = pipe.h pq.h
-SRCS = pq.c dgram.c pipe.c stream.c seqpack.c addr.c
+SRCS = pq.c dgram.c pipe.c stream.c seqpack.c addr.c pq-funcs.c pipe-funcs.c
LCLHDRS = pipe.h pq.h
OBJS = $(SRCS:.c=.o)
+HURDLIBS=threads ports
include ../Makeconf
-libpipe.so: $(foreach lib,threads ports,\
- ../lib$(lib)/lib$(lib).so)
diff --git a/libpipe/pipe-funcs.c b/libpipe/pipe-funcs.c
new file mode 100644
index 00000000..79cda2a4
--- /dev/null
+++ b/libpipe/pipe-funcs.c
@@ -0,0 +1,2 @@
+#define PIPE_DEFINE_EI
+#include "pipe.h"
diff --git a/libpipe/pipe.c b/libpipe/pipe.c
index 7f36e5f8..914816bc 100644
--- a/libpipe/pipe.c
+++ b/libpipe/pipe.c
@@ -1,6 +1,6 @@
/* Generic one-way pipes
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -66,7 +66,7 @@ pipe_create (struct pipe_class *class, struct pipe **pipe)
condition_init (&new->pending_write_selects);
mutex_init (&new->lock);
- pq_create (&new->queue);
+ pq_create (&new->queue);
if (! pipe_is_connless (new))
new->flags |= PIPE_BROKEN;
@@ -76,7 +76,7 @@ pipe_create (struct pipe_class *class, struct pipe **pipe)
}
/* Free PIPE and any resources it holds. */
-void
+void
pipe_free (struct pipe *pipe)
{
pq_free (pipe->queue);
@@ -149,7 +149,7 @@ void _pipe_no_writers (struct pipe *pipe)
this function (unlike most pipe functions). */
error_t
pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe,
- int *select_type, int data_only)
+ int *select_type, int data_only)
{
error_t err = 0;
@@ -214,7 +214,7 @@ pipe_pair_select (struct pipe *rpipe, struct pipe *wpipe,
! ((wpipe->flags & PIPE_BROKEN)
|| pipe_readable (wpipe, 1) < wlimit);
}
-
+
if (!err)
{
if (rpipe_blocked)
@@ -260,10 +260,12 @@ pipe_send (struct pipe *pipe, int noblock, void *source,
{
size_t left = pipe->write_limit - pipe_readable (pipe, 1);
if (left < data_len)
- if (data_len <= pipe->write_atomic)
- return EWOULDBLOCK;
- else
- data_len = left;
+ {
+ if (data_len <= pipe->write_atomic)
+ return EWOULDBLOCK;
+ else
+ data_len = left;
+ }
}
if (control_len > 0 || num_ports > 0)
@@ -294,7 +296,7 @@ pipe_send (struct pipe *pipe, int noblock, void *source,
if (!err)
{
timestamp (&pipe->write_time);
-
+
/* And wakeup anyone that might be interested in it. */
condition_broadcast (&pipe->pending_reads);
mutex_unlock (&pipe->lock);
@@ -373,26 +375,29 @@ pipe_recv (struct pipe *pipe, int noblock, unsigned *flags, void **source,
}
if (!err)
- if (packet)
- /* Read some data (PACKET must be a data packet at this point). */
- {
- int dq = 1; /* True if we should dequeue this packet. */
-
- if (source)
- packet_read_source (packet, source);
-
- err = (*pipe->class->read)(packet, &dq, flags, data, data_len, amount);
- if (dq)
- pq_dequeue (pq);
- }
- else
- /* Return EOF. */
- *data_len = 0;
+ {
+ if (packet)
+ /* Read some data (PACKET must be a data packet at this point). */
+ {
+ int dq = 1; /* True if we should dequeue this packet. */
+
+ if (source)
+ packet_read_source (packet, source);
+
+ err = (*pipe->class->read)(packet, &dq, flags,
+ data, data_len, amount);
+ if (dq)
+ pq_dequeue (pq);
+ }
+ else
+ /* Return EOF. */
+ *data_len = 0;
+ }
if (!err && packet)
{
timestamp (&pipe->read_time);
-
+
/* And wakeup anyone that might be interested in it. */
condition_broadcast (&pipe->pending_writes);
mutex_unlock (&pipe->lock);
diff --git a/libpipe/pipe.h b/libpipe/pipe.h
index cc765dc6..96432990 100644
--- a/libpipe/pipe.h
+++ b/libpipe/pipe.h
@@ -24,8 +24,16 @@
#define EWOULDBLOCK EAGAIN /* XXX */
#include <cthreads.h> /* For conditions & mutexes */
+#include <features.h>
+
+#ifdef PIPE_DEFINE_EI
+#define PIPE_EI
+#else
+#define PIPE_EI __extern_inline
+#endif
#include "pq.h"
+
/* A description of a class of pipes and how to operate on them. */
struct pipe_class
@@ -93,7 +101,7 @@ struct pipe
PACKET_TYPE_CONTROL. Each data packet represents one datagram for
protocols that maintain record boundaries. Control packets always
represent the control information to be returned from one read
- operation, and will be returned in conjuction with the following data
+ operation, and will be returned in conjunction with the following data
packet (if any). Reads interested only in data just skip control
packets until they find a data packet. */
struct pq *queue;
@@ -102,9 +110,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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(PIPE_DEFINE_EI)
+
/* Returns the number of characters quickly readable from PIPE. If DATA_ONLY
is true, then `control' packets are ignored. */
-extern inline size_t
+PIPE_EI size_t
pipe_readable (struct pipe *pipe, int data_only)
{
size_t readable = 0;
@@ -123,7 +146,7 @@ pipe_readable (struct pipe *pipe, int data_only)
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. */
-extern inline int
+PIPE_EI int
pipe_is_readable (struct pipe *pipe, int data_only)
{
struct pq *pq = pipe->queue;
@@ -134,11 +157,11 @@ pipe_is_readable (struct pipe *pipe, int data_only)
return (packet != NULL);
}
-/* Waits for PIPE to be readable, or an error to occurr. If NOBLOCK is true,
+/* Waits for PIPE to be readable, or an error to occur. If NOBLOCK is true,
this operation will return EWOULDBLOCK instead of blocking when no data is
immediately available. If DATA_ONLY is true, then `control' packets are
ignored. */
-extern inline error_t
+PIPE_EI error_t
pipe_wait_readable (struct pipe *pipe, int noblock, int data_only)
{
while (! pipe_is_readable (pipe, data_only) && ! (pipe->flags & PIPE_BROKEN))
@@ -151,11 +174,11 @@ pipe_wait_readable (struct pipe *pipe, int noblock, int data_only)
return 0;
}
-/* Waits for PIPE to be readable, or an error to occurr. This call only
+/* Waits for PIPE to be readable, or an error to occur. This call only
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. */
-extern inline error_t
+PIPE_EI error_t
pipe_select_readable (struct pipe *pipe, int data_only)
{
while (! pipe_is_readable (pipe, data_only) && ! (pipe->flags & PIPE_BROKEN))
@@ -167,7 +190,7 @@ pipe_select_readable (struct pipe *pipe, int data_only)
/* 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. */
-extern inline error_t
+PIPE_EI error_t
pipe_wait_writable (struct pipe *pipe, int noblock)
{
size_t limit = pipe->write_limit;
@@ -188,7 +211,7 @@ pipe_wait_writable (struct pipe *pipe, int noblock)
/* 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. */
-extern inline error_t
+PIPE_EI error_t
pipe_select_writable (struct pipe *pipe)
{
size_t limit = pipe->write_limit;
@@ -198,6 +221,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);
@@ -218,8 +243,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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(PIPE_DEFINE_EI)
+
/* Lock PIPE and increment its readers count. */
-extern inline void
+PIPE_EI void
pipe_acquire_reader (struct pipe *pipe)
{
mutex_lock (&pipe->lock);
@@ -228,7 +273,7 @@ pipe_acquire_reader (struct pipe *pipe)
}
/* Lock PIPE and increment its writers count. */
-extern inline void
+PIPE_EI void
pipe_acquire_writer (struct pipe *pipe)
{
mutex_lock (&pipe->lock);
@@ -238,7 +283,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. */
-extern inline void
+PIPE_EI void
pipe_release_reader (struct pipe *pipe)
{
if (--pipe->readers == 0)
@@ -249,7 +294,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. */
-extern inline void
+PIPE_EI void
pipe_release_writer (struct pipe *pipe)
{
if (--pipe->writers == 0)
@@ -259,7 +304,7 @@ pipe_release_writer (struct pipe *pipe)
}
/* Increment PIPE's reader count. PIPE should be unlocked. */
-extern inline void
+PIPE_EI void
pipe_add_reader (struct pipe *pipe)
{
pipe_acquire_reader (pipe);
@@ -267,7 +312,7 @@ pipe_add_reader (struct pipe *pipe)
}
/* Increment PIPE's writer count. PIPE should be unlocked. */
-extern inline void
+PIPE_EI void
pipe_add_writer (struct pipe *pipe)
{
pipe_acquire_writer (pipe);
@@ -276,7 +321,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. */
-extern inline void
+PIPE_EI void
pipe_remove_reader (struct pipe *pipe)
{
mutex_lock (&pipe->lock);
@@ -285,7 +330,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. */
-extern inline void
+PIPE_EI void
pipe_remove_writer (struct pipe *pipe)
{
mutex_lock (&pipe->lock);
@@ -293,12 +338,14 @@ pipe_remove_writer (struct pipe *pipe)
}
/* Empty out PIPE of any data. PIPE should be locked. */
-extern inline void
+PIPE_EI 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
diff --git a/libpipe/pq-funcs.c b/libpipe/pq-funcs.c
new file mode 100644
index 00000000..57061419
--- /dev/null
+++ b/libpipe/pq-funcs.c
@@ -0,0 +1,2 @@
+#define PQ_DEFINE_EI
+#include "pq.h"
diff --git a/libpipe/pq.c b/libpipe/pq.c
index c48f90bd..afdda051 100644
--- a/libpipe/pq.c
+++ b/libpipe/pq.c
@@ -1,6 +1,7 @@
/* Packet queues
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998, 1999, 2002, 2006
+ Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -21,6 +22,7 @@
#include <malloc.h>
#include <string.h>
#include <stddef.h>
+#include <sys/mman.h>
#include "pq.h"
@@ -52,11 +54,12 @@ free_packets (struct packet *head)
if (head->ports)
free (head->ports);
if (head->buf_len > 0)
- if (head->buf_vm_alloced)
- vm_deallocate (mach_task_self (),
- (vm_address_t)head->buf, head->buf_len);
- else
- free (head->buf);
+ {
+ if (head->buf_vm_alloced)
+ munmap (head->buf, head->buf_len);
+ else
+ free (head->buf);
+ }
free (head);
free_packets (next);
}
@@ -125,13 +128,15 @@ pq_queue (struct pq *pq, unsigned type, void *source)
packet->buf = 0;
packet->buf_len = 0;
packet->ports = 0;
- packet->num_ports = packet->ports_alloced = 0;
- packet->buf_start = packet->buf_end = packet->buf;
+ packet->ports_alloced = 0;
packet->buf_vm_alloced = 0;
}
else
pq->free = packet->next;
+ packet->num_ports = 0;
+ packet->buf_start = packet->buf_end = packet->buf;
+
packet->type = type;
packet->source = source;
packet->next = 0;
@@ -203,7 +208,7 @@ packet_extend (struct packet *packet, size_t new_len)
packet->buf_start = new_buf + (packet->buf_start - old_buf);
packet->buf_end = new_buf + (packet->buf_end - old_buf);
}
-
+
packet->buf_len = new_len;
return 1;
@@ -224,8 +229,10 @@ packet_realloc (struct packet *packet, size_t new_len)
/* Make a new buffer. */
if (vm_alloc)
- err =
- vm_allocate (mach_task_self (), (vm_address_t *)&new_buf, new_len, 1);
+ {
+ new_buf = mmap (0, new_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = (new_buf == (char *) -1) ? errno : 0;
+ }
else
{
new_buf = malloc (new_len);
@@ -249,10 +256,12 @@ packet_realloc (struct packet *packet, size_t new_len)
/* And get rid of the old buffer. */
if (old_len > 0)
- if (packet->buf_vm_alloced)
- vm_deallocate (mach_task_self (), (vm_address_t)old_buf, old_len);
- else
- free (old_buf);
+ {
+ if (packet->buf_vm_alloced)
+ vm_deallocate (mach_task_self (), (vm_address_t)old_buf, old_len);
+ else
+ free (old_buf);
+ }
packet->buf = new_buf;
packet->buf_len = new_len;
@@ -267,7 +276,7 @@ packet_realloc (struct packet *packet, size_t new_len)
/* ---------------------------------------------------------------- */
/* If PACKET has any ports, deallocates them. */
-void
+void
packet_dealloc_ports (struct packet *packet)
{
unsigned i;
@@ -289,13 +298,14 @@ packet_set_ports (struct packet *packet,
packet_dealloc_ports (packet);
if (num_ports > packet->ports_alloced)
{
- mach_port_t *new_ports = malloc (sizeof (mach_port_t *) * num_ports);
+ mach_port_t *new_ports = malloc (sizeof (mach_port_t) * num_ports);
if (! new_ports)
return ENOMEM;
free (packet->ports);
+ packet->ports = new_ports;
packet->ports_alloced = num_ports;
}
- bcopy (ports, packet->ports, sizeof (mach_port_t *) * num_ports);
+ bcopy (ports, packet->ports, sizeof (mach_port_t) * num_ports);
packet->num_ports = num_ports;
return 0;
}
@@ -306,13 +316,12 @@ error_t
packet_read_ports (struct packet *packet,
mach_port_t **ports, size_t *num_ports)
{
- int length = packet->num_ports * sizeof (mach_port_t *);
+ int length = packet->num_ports * sizeof (mach_port_t);
if (*num_ports < packet->num_ports)
{
- error_t err =
- vm_allocate (mach_task_self (), (vm_address_t *)ports, length, 1);
- if (err)
- return err;
+ *ports = mmap (0, length, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*ports == (mach_port_t *) -1)
+ return errno;
}
*num_ports = packet->num_ports;
bcopy (packet->ports, *ports, length);
@@ -321,8 +330,8 @@ packet_read_ports (struct packet *packet,
}
/* Append the bytes in DATA, of length DATA_LEN, to what's already in PACKET,
- and return the amount appended in AMOUNT. */
-error_t
+ and return the amount appended in AMOUNT if that's not the null pointer. */
+error_t
packet_write (struct packet *packet,
char *data, size_t data_len, size_t *amount)
{
@@ -334,7 +343,8 @@ packet_write (struct packet *packet,
/* Add the new data. */
bcopy (data, packet->buf_end, data_len);
packet->buf_end += data_len;
- *amount = data_len;
+ if (amount != NULL)
+ *amount = data_len;
return 0;
}
@@ -399,7 +409,7 @@ packet_read (struct packet *packet,
/* Just copy the data the old fashioned way.... */
{
if (*data_len < amount)
- vm_allocate (mach_task_self (), (vm_address_t *)data, amount, 1);
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
bcopy (start, *data, amount);
start += amount;
diff --git a/libpipe/pq.h b/libpipe/pq.h
index abd193f8..0fffe254 100644
--- a/libpipe/pq.h
+++ b/libpipe/pq.h
@@ -1,6 +1,6 @@
/* Packet queues
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2006 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -25,6 +25,14 @@
#include <stddef.h> /* for size_t */
#include <string.h>
#include <mach/mach.h>
+#include <features.h>
+
+#ifdef PQ_DEFINE_EI
+#define PQ_EI
+#else
+#define PQ_EI __extern_inline
+#endif
+
struct packet
{
@@ -65,15 +73,21 @@ error_t packet_set_ports (struct packet *packet,
/* If PACKET has any ports, deallocates them. */
void packet_dealloc_ports (struct packet *packet);
+extern size_t packet_readable (struct packet *packet);
+
+#if defined(__USE_EXTERN_INLINES) || defined(PQ_DEFINE_EI)
+
/* Returns the number of bytes of data in PACKET. */
-extern inline size_t
+PQ_EI 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. */
+ and return the amount appended in AMOUNT if that's not the null pointer. */
error_t packet_write (struct packet *packet,
char *data, size_t data_len, size_t *amount);
@@ -89,14 +103,20 @@ error_t packet_read (struct packet *packet,
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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(PQ_DEFINE_EI)
+
/* Return the source addressd in PACKET in SOURCE, deallocating it from
PACKET. */
-extern inline void
+PQ_EI 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. */
@@ -120,9 +140,17 @@ int packet_extend (struct packet *packet, size_t new_len);
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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(PQ_DEFINE_EI)
+
/* Try to make space in PACKET for AMOUNT more bytes without growing the
buffer, returning true if we could do it. */
-extern inline int
+PQ_EI int
packet_fit (struct packet *packet, size_t amount)
{
char *buf = packet->buf, *end = packet->buf_end;
@@ -154,7 +182,7 @@ packet_fit (struct packet *packet, size_t amount)
/* Make sure that PACKET has room for at least AMOUNT more bytes, or return
the reason why not. */
-extern inline error_t
+PQ_EI error_t
packet_ensure (struct packet *packet, size_t amount)
{
if (! packet_fit (packet, amount))
@@ -171,7 +199,7 @@ packet_ensure (struct packet *packet, size_t amount)
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. */
-extern inline int
+PQ_EI int
packet_ensure_efficiently (struct packet *packet, size_t amount)
{
if (! packet_fit (packet, amount))
@@ -184,6 +212,8 @@ packet_ensure_efficiently (struct packet *packet, size_t amount)
}
return 0;
}
+
+#endif /* Use extern inlines. */
struct pq
{
@@ -196,10 +226,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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(PQ_DEFINE_EI)
+
/* 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. */
-extern inline struct packet *
+PQ_EI struct packet *
pq_tail (struct pq *pq, unsigned type, void *source)
{
struct packet *tail = pq->tail;
@@ -209,16 +243,24 @@ pq_tail (struct pq *pq, unsigned type, void *source)
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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(PQ_DEFINE_EI)
+
/* 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
+ queue, or NULL if there is none, or the next packet isn't appropriate.
+ A packet is inappropriate 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. */
-extern inline struct packet *
+PQ_EI struct packet *
pq_head (struct pq *pq, unsigned type, void *source)
{
struct packet *head = pq->head;
@@ -232,7 +274,7 @@ pq_head (struct pq *pq, unsigned type, void *source)
}
/* The same as pq_head, but first discards the head of the queue. */
-extern inline struct packet *
+PQ_EI struct packet *
pq_next (struct pq *pq, unsigned type, void *source)
{
if (!pq->head)
@@ -241,6 +283,8 @@ pq_next (struct pq *pq, unsigned type, void *source)
return pq_head (pq, type, source);
}
+#endif /* Use extern inlines. */
+
/* Dequeues all packets in PQ. */
void pq_drain (struct pq *pq);
diff --git a/libports/ChangeLog b/libports/ChangeLog
deleted file mode 100644
index 2a50f7ce..00000000
--- a/libports/ChangeLog
+++ /dev/null
@@ -1,438 +0,0 @@
-Thu Jul 18 22:59:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (SRCS): Add create-port-noinstall.c and create-internal.c.
- * create-port-noinstall.c: New file.
- * create-port.c (ports_create_port): Guts deleted; call new work
- function.
- * create-internal.c: New file; all the guts from create-port.c.
-
-Wed Jul 3 14:13:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * get-right.c (ports_get_right): Supply correct sync value in
- notification request.
-
-Mon May 6 16:33:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ports.h (ports_allocate_port, ports_intern_external_port):
- Delete obsolete declarations.
- * allocate-port.c, intern-external-port.c: Delete files.
- * Makefile (SRCS): Delete `intern-external-port.c' and
- `allocate-port.c'.
-
-Sun Apr 28 15:22:58 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * allocate-port.c: Add obsolescence link warning.
- * intern-external-port.c: Add obsolescence link warning.
-
-Fri Mar 29 15:21:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * end-rpc.c (ports_end_rpc): Acquire _PORTS_LOCK before calling
- _ports_remove_notified_rpc.
-
-Fri Mar 29 09:04:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * reallocate-from-external.c (ports_reallocate_from_external):
- Require port to have a current port right.
- * reallocate-port.c (ports_reallocate_port): Likewise.
-
- * complete-deallocate.c (_ports_complete_deallocate): Only drop
- port right if it isn't already null.
-
- * transfer-right.c: New file.
- * Makefile (SRCS): Add transfer-right.c.
- * ports.h (ports_claim_right): Doc fix.
- (ports_transfer_right): New function.
-
-Thu Mar 28 10:47:58 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * claim-right.c (ports_claim_right): Take right out of port
- bucket.
-
- * manage-multithread.c (ports_manage_port_operations_multithread):
- Fill in meaningful statuses and errors rather than just zero.
- * manage-one-thread.c (ports_manage_port_operations_one_thread):
- Likewise.
-
- * begin-rpc.c (ports_begin_rpc): Return EOPNOTSUPP, not EDIED, if
- receive right is gone.
-
- * manage-one-thread.c (ports_manage_port_operations_one_thread):
- Fill in default reply before doing work; we might return 0 and
- mach_msg_server expects us to fill in a reply decently no matter
- what.
- (ports_manage_port_operations_multithread): Likewise.
-
- * claim-right.c (ports_claim_right): Hold lock until sendright
- frobbing is finished.
-
-Wed Mar 20 13:32:13 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * destroy-right.c (ports_destroy_right): Don't do anything if port
- has already been destroyed.
-
- * ports.h (ports_claim_right): New declaration.
- * claim-right.c: New file.
- * Makefile (SRCS): Add `claim-right.c'.
-
-Tue Mar 5 17:28:54 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * get-right.c (ports_get_right): Check mach_port_request_notification
- for error returns, against all odds.
-
-Mon Feb 26 17:10:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * interrupt-on-notify.c (ports_interrupt_rpc_on_notification):
- Only set _PORTS_NOTIFICATIONS->prevp if _PORTS_NOTIFICATIONS != 0.
- Likewise for PN->prev_req_p.
-
-Fri Jan 26 00:45:58 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inhibit-class-rpcs.c (ports_inhibit_class_rpcs): Whoops, we
- still have the lock when hurd_condition_wait gets cancelled.
- * import-port.c (ports_import_port): Likewise.
- * create-port.c (ports_create_port): Likewise.
- * inhibit-bucket-rpcs.c (ports_inhibit_bucket_rpcs): Likewise.
- * inhibit-all-rpcs.c (ports_inhibit_all_rpcs): Likewise.
- * inhibit-port-rpcs.c (ports_inhibit_port_rpcs): Likewise.
-
- * import-port.c (ports_import_port): Don't lose a send right on
- PORT when we return an error.
- * create-port.c (ports_create_port): Delete the receive right, not
- the send right when we return an error.
-
-Thu Jan 25 12:10:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * manage-multithread.c (ports_manage_port_operations_multithread):
- Pass INP->msgh_id, not INP to ports_begin_rpc.
- * manage-one-thread.c (ports_manage_port_operations_one_thread): Ditto.
-
-Wed Jan 24 14:02:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inhibit-all-rpcs.c (ports_inhibit_all_rpcs): Be interruptable;
- return EINTR if interrupted, or EBUSY if already inhibited.
- * inhibit-class-rpcs.c (ports_inhibit_class_rpcs): Likewise.
- * inhibit-port-rpcs.c (ports_inhibit_port_rpcs): Likewise.
- * inhibit-bucket-rpcs.c (ports_inhibit_bucket_rpcs): Likewise.
- * begin-rpc.c (ports_begin_rpc): Be interruptable.
- * create-port.c (ports_create_port): New function.
- * import-port.c (ports_import_port): New function.
- * allocate-port.c (ports_allocate_port): Call ports_create_port.
- * intern-external-port.c (ports_intern_external_port): Call
- ports_import_port.
- * ports.h (ports_create_port, ports_import_ports): New declarations.
- (PORTS_INHIBITED, PORTS_BLOCKED, PORTS_INHIBIT_WAIT, PORTS_NO_ALLOC,
- PORTS_ALLOC_WAIT): New macros (global values for common flags).
- (PORT_BLOCKED, PORT_INHIBITED, PORT_INHIBIT_WAIT,
- PORT_BUCKET_INHIBITED, PORT_BUCKET_BLOCKED, PORT_BUCKET_INHIBIT_WAIT,
- PORT_BUCKET_NO_ALLOC, PORT_BUCKET_ALLOC_WAIT, PORT_CLASS_INHIBITED,
- PORT_CLASS_BLOCKED, PORT_CLASS_INHIBIT_WAIT, PORT_CLASS_NO_ALLOC,
- PORT_CLASS_ALLOC_WAIT, _PORTS_INHIBITED, _PORTS_BLOCKED,
- _PORTS_INHIBIT_WAIT): Redefine using global flag values.
- (ports_inhibit_port_rpcs, ports_inhibit_all_rpcs,
- ports_inhibit_class_rpcs, ports_inhibit_bucket_rpcs): Return error_t.
- (ports_interupt_rpcs): Renamed from port_interrupt_rpc.
-
- * begin-rpc.c (ports_begin_rpc): Take new MSG_ID arg, and use it to
- see if the particular rpc shouldn't be inhibitable.
- * manage-multithread.c (ports_manage_port_operations_multithread):
- Pass INP to ports_begin_rpc, and only call DEMUXER if it returns 0.
- * manage-one-thread.c (ports_manage_port_operations_one_thread): Ditto.
- * ports.h (ports_begin_rpc): Add MSG_ID arg.
- (struct port_class): Add uninhibitable_rpcs field.
- (struct ports_msg_id_range): New structure.
- (ports_default_uninhibitable_rpcs): New declaration.
- * create-class.c (ports_create_class): Initialize the
- uninhibitable_rpcs field.
- * default-uninhibitable-rpcs.c (interrupt_operation_ids,
- ports_default_uninhibitable_rpcs): New variables.
- * Makefile (SRCS): Add default-uninhibitable-rpcs.c.
-
- * interrupt-rpcs.c (ports_interrupt_rpcs): Renamed from
- ports_interrupt_rpc.
- * Makefile (SRCS): Rename interrupt-rpc.c to interrupt-rpcs.c.
- * interrupt-operation.c (ports_S_interrupt_operation): Use
- ports_interrupt_rpcs instead of ports_interrupt_rpc.
- * no-senders.c (ports_no_senders): Likewise.
-
- * manage-multithread.c (ports_manage_port_operations_multithread):
- Fix spelling of cancel_threshold (was cancel_threshhold).
- * interrupt-operation.c (ports_S_interrupt_operation): Likewise.
- * ports.h (struct port_info): Likewise.
- * reallocate-from-external.c (ports_reallocate_from_external): Ditto.
- * reallocate-port.c (ports_reallocate_port): Likewise.
-
-Wed Jan 17 13:08:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * no-senders.c (ports_no_senders): Interrupt RPCs on PI too. Only
- do the ports_interrupt_notified_rpcs() if we're actually losing a ref.
-
-Fri Jan 5 16:40:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * interrupt-on-notify.c (ports_interrupt_rpc_on_notification):
- If PORT is dead or bogus, interrupt RPC immediately, and don't add
- a new request.
-
-Thu Dec 28 14:27:41 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * interrupt-on-notify.c (ports_interrupt_rpc_on_notification): If
- NEW_REQ is not needed, put it on the free list, don't call free on it.
-
-Thu Dec 28 11:04:06 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ports.h (ports_interrupt_self_on_port_death): New macro.
-
- * interrupt-notified-rpcs.c (ports_interrupt_notified_rpcs): Only
- bother to lock _PORTS_LOCK if there are notifications.
-
-Wed Dec 27 16:27:47 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ports.h (struct rpc_info): Get rid of next_notified/prev_notified_p.
- (struct rpc_notify): Get rid of port, what, next fields, and add
- rpc, notify, next, pending, next_req, and prev_req_p fields.
- (struct ports_notify): New structure.
- (_ports_notified_rpcs): Declaration removed.
- (_ports_notifications): New declaration.
- (_ports_free_ports_notifies): New declaration.
- Include <mach/notify.h>.
- * interrupt-on-notify.c (ports_interrupt_rpc_on_notification):
- Mostly rewrite to use new scheme.
- * interrupt-notified-rpcs (_ports_notified_rpcs): Variable removed.
- (_ports_notifications, _ports_free_ports_notifications): New variables.
- (ports_interrupt_notified_rpcs): Rewrite to use new scheme.
- (_ports_remove_notified_rpc): Ditto.
- (cancel_notification): Function removed.
- (remove_req): New function.
-
-Tue Dec 26 14:39:51 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * interrupt-notified-rpcs.c (_ports_notified_rpcs,
- _ports_free_rpc_notifies): New variables.
- (ports_interrupt_notified_rpcs, cancel_notification,
- _ports_remove_notified_rpc): New functions.
- * interrupt-on-notify.c (ports_interrupt_rpc_on_notification,
- ports_interrupt_self_on_notification): New functions, new file.
- * ports.h (struct rpc_notify): New structure.
- (struct rpc_info): Add rpc_notifies, rpc_next_notified, and
- prev_notified_p fields.
- (_ports_notified_rpcs, _ports_free_rpc_notifies,
- _ports_remove_notified_rpc, ports_interrupt_rpc_on_notification,
- ports_interrupt_notified_rpcs, ports_interrupt_self_on_notification):
- New declarations.
- * begin-rpc.c (ports_begin_rpc): Initialize the notifies field.
- * end-rpc.c (ports_end_rpc): Get rid of any rpc notifications.
- * no-senders.c (ports_no_senders): Interrupt any rpcs requesting such.
- * dead-name.c (ports_dead_name): New function.
- * notify-dead-name.c (ports_do_mach_notify_dead_name): Call
- ports_dead_name().
- * Makefile (SRCS): Add interrupt-on-notify.c,
- interrupt-notified-rpcs.c, and dead-name.c.
-
-Tue Nov 21 22:04:28 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * manage-multithread.c: Don't wire timeouts to zero.
-
-Tue Nov 21 09:42:00 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ports.h (ports_do_mach_notify_dead_name): Declare `extern
- kern_return_t'.
- (ports_do_mach_notify_msg_accepted): Likewise.
- (ports_do_mach_notify_no_senders): Likewise.
- (ports_do_mach_notify_port_deleted): Likewise.
- (ports_do_mach_notify_port_destroyed): Likewise.
- (ports_do_mach_notify_send_once): Likewise.
- * notify-send-once.c: Include "notify_S.h".
- * notify-port-deleted.c: Likewise.
- * notify-msg-accepted.c: Likewise.
- * notify-port-destroyed.c: Likewise.
- * notify-no-senders.c: Likewise.
- * notify-dead-name.c: Likewise.
-
- * ports.h (struct port_info): New member `cancel_threshhold'.
- (ports_S_interrupt_operation): Include seqno arg; declare extern
- kern_return_t.
- * interrupt-operation.c: Include "interrupt_S.h".
- (ports_S_interrupt_operation): Set PI->cancel_threshhold if the
- incoming seqno is greater than the current threshhold.
- * manage-multithread.c
- (ports_manage_port_operations_multithread/internal_demuxer): If
- the incoming RPC has already been cancelled, then call
- hurd_thread_cancel before the user's demuxer.
- * manage-one-thread.c (ports_manage_port_operations_one_thread):
- Doc fix.
- * intern-external-port.c (ports_intern_external_port): Initialize
- PI->cancel_threshhold.
- * allocate-port.c (ports_allocate_port): Likewise.
- * reallocate-from-external.c (ports_reallocate_from_external):
- Clear PI->cancel_threshhold.
- * reallocate-port.c (ports_reallocate_port): Likewise.
-
-Sat Nov 18 08:50:13 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * inhibit-all-rpcs.c: If calling thread is serving an RPC, don't
- block waiting for that RPC to finish.
- * inhibit-class-rpcs.c: Likewise.
- * inhibit-bucket-rpcs.c: Likewise.
- * inhibit-port-rpcs.c: Likewise.
-
- * inhibit-all-rpcs.c (ports_inhibit_all_rpcs): Renamed from
- inhibit_all_rpcs.
-
-Tue Oct 24 13:32:39 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * manage-multithread.c
- (ports_manage_port_operations_multithread/internal_demuxer): Don't
- attempt RPC if we can't get a valid port struct.
- * manage-one-thread.c
- (ports_manage_port_operations_one_thread/internal_demuxer): Likewise.
-
-Mon Oct 9 14:57:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile: Specify shared library dependencies.
-
-Fri Sep 22 10:19:17 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ports.h: Include hurd.h.
-
-Fri Sep 8 14:44:03 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * end-rpc.c (ports_end_rpc): Call hurd_check_cancel.
-
-Wed Sep 6 11:20:20 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ports.h (ports_interrupt_server, ports_S_interrupt_operation):
- New declarations.
- * Makefile (OBJS): Add interruptServer.o.
- (SRCS): Add interrupt-operation.c.
- * interrupt-operation.c: New file.
-
- * ports.h (ports_notify_server, ports_do_mach_notify_*): New decls.
- * Makefile (MIGCOMSFLAGS): New variable.
- (OBJS): Added notifyServer.o.
- (SRCS): Added notify-dead-name.c, notify-no-senders.c,
- notify-port-destroyed.c, notify-msg-accepted.c,
- notify-port-deleted.c, and notify-send-once.c.
- * notify-dead-name.c: New file.
- * notify-no-senders.c: New file.
- * notify-port-destroyed.c: New file.
- * notify-msg-accepted.c: New file.
- * notify-port-deleted.c: New file.
- * notify-send-once.c: New file.
-
-Wed Aug 30 16:00:36 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * inhibit-port-rpcs.c (inhibit_port_rpcs): Renamed to
- `ports_inhibit_port_rpcs'.
-
-Tue Aug 29 15:59:49 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * manage-multithread.c (ports_manage_port_operations_multithread):
- Hammer WIRE_CTHREADS on for now.
-
-Thu Aug 24 10:25:52 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * inhibit-port-rpcs.c (inhibit_port_rpcs): thread_cancel ->
- hurd_thread_cancel. Include <hurd.h>.
- * inhibit-class-rpcs.c (ports_inhibit_class_rpcs): Ditto.
- * inhibit-bucket-rpcs.c (ports_inhibit_bucket_rpcs): Ditto.
- * interrupt-rpc.c (ports_interrupt_rpc): Ditto.
- * inhibit-all-rpcs.c (inhibit_all_rpcs): Ditto.
-
- * Makefile (OBJS): Use :.c=.o notation.
-
-Wed Aug 23 15:03:11 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (REMHDRS): Removed.
- Order changed a bit.
-
-Fri Jul 21 11:45:22 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * get-right.c (ports_get_right): If the right is null (because we
- are closing down), then just return null. (This helps in a race
- in ufs/ex2fs).
-
- * complete-deallocate.c (_ports_complete_deallocate): Clear
- PI->port_right; and do it before releasing _ports_lock.
-
- * manage-multithread.c (ports_manage_port_operations_multithread):
- For now, wire GLOBAL_TIMEOUT and THREAD_TIMEOUT to zero.
-
-Tue Jul 18 14:29:49 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * manage-multithread.c (ports_manage_port_operations_multithread)
- [thread_function]: Return int. Don't cthread_exit child threads;
- just let them return normally.
-
-Wed Jul 12 13:32:22 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * resume-class-rpcs.c (ports_resume_class_rpcs): Clear blocked
- flag using correct name.
-
- * manage-multithread.c (ports_manage_port_operations_multithread)
- [internal_demuxer]: Increment NREQTHREADS and TOTALTHREADS
- *before* forking newthread.
- [thread_function]: Don't increment NREQTHREADS and TOTALTHREADS here.
- Initialize NREQTHREADS and TOTALTHREADS in main body of function.
-
-Sat Jul 8 15:10:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * allocate-port.c (ports_allocate_port): Properly add PI to
- CLASS's port list when the list is empty (why did this work before?).
- * intern-external-port.c (ports_intern_external_port): Ditto.
- * begin-rpc.c (ports_begin_rpc): Ditto adding INFO to PI's
- current_rpcs list.
- * create-class.c (ports_create_class): Initialize the PORTS and
- COUNT fields.
-
-Thu Jul 6 15:36:57 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Tue Jun 27 15:28:54 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Add it *back*.
- * stubs.c: New file.
-
-Mon Jun 26 16:51:42 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * ports.h: Fix spelling error.
-
- * manage-multithread.c (ports_manage_port_operations_multithread):
- Declare NREQTHREADS asd TOTALTHREADS volatile.
-
- * manage-multithread.c
- (ports_manage_port_operations_multithread/thread_function): Don't
- hold lock while setting TIMEOUT.
- When master goes back to wait for messages, it should unlock LOCK.
- Declare ERR inside THREAD_FUNCTION so it doesn't get shared by
- multiple threads.
-
-Thu Jun 22 11:28:56 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * get-right.c (ports_get_right): Parenthesize flag test correctly.
- * reallocate-from-external.c (ports_reallocate_from_external):
- Likewise.
-
- * enable-bucket.c (ports_enable_bucket): Clean flag correctly.
-
- * lookup-port.c (ports_lookup_port): UNlock port lock at exit of
- function.
-
- * bucket-iterate.c: Include <hurd/ihash.h> and <cthreads.h>.
- (ports_bucket_iterate): Fix decl of NXT.
-
-Wed Jun 21 14:25:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Added bucket-iterate.c.
- * bucket-iterate.c: New file.
- * ports.h (port_bucket_iterate): New decl.
-
-Tue Jun 20 12:35:44 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * enable-bucket.c: Include <cthreads.h>.
- * enable-class.c: Likewise.
- * count-bucket.c: Likewise.
-
- * libports/lookup-port.c (ports_lookup_port): Remove assignment
- from if test.
-
diff --git a/libports/Makefile b/libports/Makefile
index 50ccd0c9..50b5ed9e 100644
--- a/libports/Makefile
+++ b/libports/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+#
+# Copyright (C) 1995,96,97,99,2000 Free Software Foundation, Inc.
# Written by Michael I. Bushnell.
#
# This file is part of the GNU Hurd.
@@ -29,22 +29,22 @@ SRCS = create-bucket.c create-class.c \
inhibit-port-rpcs.c inhibit-class-rpcs.c inhibit-bucket-rpcs.c \
inhibit-all-rpcs.c resume-port-rpcs.c resume-class-rpcs.c \
resume-bucket-rpcs.c resume-all-rpcs.c interrupt-rpcs.c \
- init.c complete-deallocate.c get-right.c count-class.c count-bucket.c \
- enable-class.c enable-bucket.c bucket-iterate.c stubs.c \
+ init.c complete-deallocate.c get-right.c get-send-right.c \
+ count-class.c count-bucket.c \
+ enable-class.c enable-bucket.c bucket-iterate.c class-iterate.c stubs.c \
notify-dead-name.c notify-no-senders.c notify-port-destroyed.c \
notify-msg-accepted.c notify-port-deleted.c notify-send-once.c \
interrupt-operation.c interrupt-on-notify.c interrupt-notified-rpcs.c \
dead-name.c create-port.c import-port.c default-uninhibitable-rpcs.c \
- claim-right.c transfer-right.c create-port-noinstall.c create-internal.c
+ claim-right.c transfer-right.c create-port-noinstall.c create-internal.c \
+ interrupted.c
LCLHDRS = ports.h
installhdrs = ports.h
+HURDLIBS= ihash
OBJS = $(SRCS:.c=.o) notifyServer.o interruptServer.o
-
+
MIGCOMSFLAGS = -prefix ports_
include ../Makeconf
-
-libports.so: $(foreach lib,ihash,\
- ../lib$(lib)/lib$(lib).so)
diff --git a/libports/bucket-iterate.c b/libports/bucket-iterate.c
index 9b49579f..e439cb19 100644
--- a/libports/bucket-iterate.c
+++ b/libports/bucket-iterate.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+/* Iterate a function over the ports in a bucket.
+ Copyright (C) 1995, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -22,13 +22,17 @@
#include <cthreads.h>
#include <hurd/ihash.h>
-/* This is obsecenely ineffecient. ihash and ports need to cooperate
- more closely to do it effeciently. */
+
+/* Internal entrypoint for both ports_bucket_iterate and ports_class_iterate.
+ If CLASS is non-null, call FUN only for ports in that class. */
error_t
-ports_bucket_iterate (struct port_bucket *bucket,
- error_t (*fun)(void *))
+_ports_bucket_class_iterate (struct port_bucket *bucket,
+ struct port_class *class,
+ error_t (*fun)(void *))
{
- struct item
+ /* This is obscenely ineffecient. ihash and ports need to cooperate
+ more closely to do it efficiently. */
+ struct item
{
struct item *next;
void *p;
@@ -36,22 +40,23 @@ ports_bucket_iterate (struct port_bucket *bucket,
struct item *i, *nxt;
error_t err;
- error_t enqueue (void *pi)
+ mutex_lock (&_ports_lock);
+ HURD_IHASH_ITERATE (&bucket->htable, arg)
{
+ struct port_info *const pi = arg;
struct item *j;
-
- j = malloc (sizeof (struct item));
- j->next = list;
- j->p = pi;
- list = j;
- ((struct port_info *)pi)->refcnt++;
- return 0;
+
+ if (class == 0 || pi->class == class)
+ {
+ j = malloc (sizeof (struct item));
+ j->next = list;
+ j->p = pi;
+ list = j;
+ pi->refcnt++;
+ }
}
-
- mutex_lock (&_ports_lock);
- ihash_iterate (bucket->htable, enqueue);
mutex_unlock (&_ports_lock);
-
+
err = 0;
for (i = list; i; i = nxt)
{
@@ -62,4 +67,11 @@ ports_bucket_iterate (struct port_bucket *bucket,
free (i);
}
return err;
-}
+}
+
+error_t
+ports_bucket_iterate (struct port_bucket *bucket,
+ error_t (*fun)(void *))
+{
+ return _ports_bucket_class_iterate (bucket, 0, fun);
+}
diff --git a/libports/claim-right.c b/libports/claim-right.c
index 2ddb3aaa..aef53bb7 100644
--- a/libports/claim-right.c
+++ b/libports/claim-right.c
@@ -1,5 +1,5 @@
/* Take a receive right away from a port
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,33 +20,34 @@
#include "ports.h"
+#include <assert.h>
+#include <errno.h>
#include <hurd/ihash.h>
mach_port_t
ports_claim_right (void *portstruct)
{
+ error_t err;
struct port_info *pi = portstruct;
- mach_port_t ret;
+ mach_port_t ret = pi->port_right;
- if (pi->port_right != MACH_PORT_NULL)
+ if (ret == MACH_PORT_NULL)
+ return ret;
+
+ mutex_lock (&_ports_lock);
+ hurd_ihash_locp_remove (&pi->bucket->htable, pi->hentry);
+ err = mach_port_move_member (mach_task_self (), ret, MACH_PORT_NULL);
+ assert_perror (err);
+ pi->port_right = MACH_PORT_NULL;
+ if (pi->flags & PORT_HAS_SENDRIGHTS)
{
- ret = pi->port_right;
-
- mutex_lock (&_ports_lock);
- ihash_locp_remove (pi->bucket->htable, pi->hentry);
- mach_port_move_member (mach_task_self (), ret, MACH_PORT_NULL);
- pi->port_right = MACH_PORT_NULL;
- if (pi->flags & PORT_HAS_SENDRIGHTS)
- {
- pi->flags &= ~PORT_HAS_SENDRIGHTS;
- mutex_unlock (&_ports_lock);
- ports_port_deref (pi);
- }
- else
- mutex_unlock (&_ports_lock);
+ pi->flags &= ~PORT_HAS_SENDRIGHTS;
+ mutex_unlock (&_ports_lock);
+ ports_port_deref (pi);
}
else
- ret = MACH_PORT_NULL;
+ mutex_unlock (&_ports_lock);
+
return ret;
}
diff --git a/libmom/copy-ref.c b/libports/class-iterate.c
index 03d4ab45..e2a15173 100644
--- a/libmom/copy-ref.c
+++ b/libports/class-iterate.c
@@ -1,6 +1,5 @@
-/* Copy a mom port reference
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* Iterate a function over the ports in a class.
+ Copyright (C) 1999 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -18,17 +17,20 @@
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 "ports.h"
+#include <cthreads.h>
error_t
-mom_copy_ref (struct mom_port_ref *new,
- struct mom_port_ref *obj)
+ports_class_iterate (struct port_class *class,
+ error_t (*fun)(void *))
{
- error_t err;
-
- err = mach_port_mod_refs (mach_task_self (),
- obj->port, MACH_PORT_RIGHT_SEND, 1);
- if (!err)
- new->port = obj->port;
- return err;
+ mutex_lock (&_ports_lock);
+ if (class->ports != 0)
+ {
+ struct port_bucket *bucket = class->ports->bucket;
+ mutex_unlock (&_ports_lock);
+ return _ports_bucket_class_iterate (bucket, class, fun);
+ }
+ mutex_unlock (&_ports_lock);
+ return 0;
}
diff --git a/libports/complete-deallocate.c b/libports/complete-deallocate.c
index a94ab171..52e8f17b 100644
--- a/libports/complete-deallocate.c
+++ b/libports/complete-deallocate.c
@@ -30,7 +30,7 @@ _ports_complete_deallocate (struct port_info *pi)
if (pi->port_right)
{
- ihash_locp_remove (pi->bucket->htable, pi->hentry);
+ hurd_ihash_locp_remove (&pi->bucket->htable, pi->hentry);
mach_port_mod_refs (mach_task_self (), pi->port_right,
MACH_PORT_RIGHT_RECEIVE, -1);
pi->port_right = MACH_PORT_NULL;
diff --git a/libports/create-bucket.c b/libports/create-bucket.c
index 1c3346e4..6be4bcad 100644
--- a/libports/create-bucket.c
+++ b/libports/create-bucket.c
@@ -1,5 +1,5 @@
/* Create a port bucket
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997, 2001, 2003 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -19,7 +19,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ports.h"
-#include <assert.h>
+#include <stddef.h>
+#include <errno.h>
+#include <stdlib.h>
#include <hurd/ihash.h>
#include <cthreads.h>
@@ -30,18 +32,28 @@ ports_create_bucket ()
error_t err;
ret = malloc (sizeof (struct port_bucket));
- assert (ret);
+ if (! ret)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
&ret->portset);
- assert_perror (err);
- err = ihash_create (&ret->htable);
- assert_perror (err);
+ if (err)
+ {
+ errno = err;
+ free (ret);
+ return NULL;
+ }
+
+ hurd_ihash_init (&ret->htable, offsetof (struct port_info, hentry));
+ ret->rpcs = ret->flags = ret->count = 0;
mutex_lock (&_ports_lock);
ret->next = _ports_all_buckets;
_ports_all_buckets = ret;
mutex_unlock (&_ports_lock);
+
return ret;
}
-
-
diff --git a/libports/create-class.c b/libports/create-class.c
index 7db99ca1..12c8add9 100644
--- a/libports/create-class.c
+++ b/libports/create-class.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995,2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -20,7 +20,7 @@
#include "ports.h"
#include <stdlib.h>
-#include <assert.h>
+#include <errno.h>
struct port_class *
ports_create_class (void (*clean_routine)(void *),
@@ -29,7 +29,12 @@ ports_create_class (void (*clean_routine)(void *),
struct port_class *cl;
cl = malloc (sizeof (struct port_class));
- assert (cl);
+ if (! cl)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
cl->clean_routine = clean_routine;
cl->dropweak_routine = dropweak_routine;
cl->flags = 0;
diff --git a/libports/create-internal.c b/libports/create-internal.c
index bc97ce62..7a9b1cb0 100644
--- a/libports/create-internal.c
+++ b/libports/create-internal.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -48,7 +48,9 @@ _ports_create_port_internal (struct port_class *class,
pi = malloc (size);
if (! pi)
{
- mach_port_deallocate (mach_task_self (), port);
+ err = mach_port_mod_refs (mach_task_self (), port,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ assert_perror (err);
return ENOMEM;
}
@@ -80,7 +82,7 @@ _ports_create_port_internal (struct port_class *class,
goto loop;
}
- err = ihash_add (bucket->htable, port, pi, &pi->hentry);
+ err = hurd_ihash_add (&bucket->htable, port, pi);
if (err)
goto lose;
@@ -94,7 +96,12 @@ _ports_create_port_internal (struct port_class *class,
mutex_unlock (&_ports_lock);
if (install)
- mach_port_move_member (mach_task_self (), pi->port_right, bucket->portset);
+ {
+ err = mach_port_move_member (mach_task_self (), pi->port_right,
+ bucket->portset);
+ if (err)
+ goto lose_unlocked;
+ }
*(void **)result = pi;
return 0;
@@ -103,7 +110,10 @@ _ports_create_port_internal (struct port_class *class,
err = EINTR;
lose:
mutex_unlock (&_ports_lock);
- mach_port_mod_refs (mach_task_self (), port, MACH_PORT_RIGHT_RECEIVE, -1);
+ lose_unlocked:
+ err = mach_port_mod_refs (mach_task_self (), port,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ assert_perror (err);
free (pi);
return err;
diff --git a/libports/dead-name.c b/libports/dead-name.c
index 07705563..de89ba6b 100644
--- a/libports/dead-name.c
+++ b/libports/dead-name.c
@@ -1,6 +1,6 @@
/* Handle various ports internal uses of dead-name notification
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
diff --git a/libports/destroy-right.c b/libports/destroy-right.c
index 704c0f57..327029a8 100644
--- a/libports/destroy-right.c
+++ b/libports/destroy-right.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -23,30 +23,29 @@
#include <hurd/ihash.h>
#include <assert.h>
-void
+error_t
ports_destroy_right (void *portstruct)
{
struct port_info *pi = portstruct;
error_t err;
-
+
if (pi->port_right != MACH_PORT_NULL)
{
mutex_lock (&_ports_lock);
- ihash_locp_remove (pi->bucket->htable, pi->hentry);
+ hurd_ihash_locp_remove (&pi->bucket->htable, pi->hentry);
err = mach_port_mod_refs (mach_task_self (), pi->port_right,
MACH_PORT_RIGHT_RECEIVE, -1);
assert_perror (err);
mutex_unlock (&_ports_lock);
-
+
pi->port_right = MACH_PORT_NULL;
-
+
if (pi->flags & PORT_HAS_SENDRIGHTS)
{
pi->flags &= ~PORT_HAS_SENDRIGHTS;
ports_port_deref (pi);
}
}
-}
-
-
+ return 0;
+}
diff --git a/libports/end-rpc.c b/libports/end-rpc.c
index d4d46e62..47fd1ae7 100644
--- a/libports/end-rpc.c
+++ b/libports/end-rpc.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -38,12 +38,16 @@ ports_end_rpc (void *port, struct rpc_info *info)
_ports_total_rpcs--;
pi->bucket->rpcs--;
- if ((!pi->current_rpcs && (pi->flags & PORT_INHIBIT_WAIT))
- || (!pi->bucket->rpcs && (pi->bucket->flags & PORT_BUCKET_INHIBIT_WAIT))
- || (!pi->class->rpcs && (pi->class->flags & PORT_CLASS_INHIBIT_WAIT))
- || (!_ports_total_rpcs && (_ports_flags & _PORTS_INHIBIT_WAIT)))
+ if ((pi->flags & PORT_INHIBIT_WAIT)
+ || (pi->bucket->flags & PORT_BUCKET_INHIBIT_WAIT)
+ || (pi->class->flags & PORT_CLASS_INHIBIT_WAIT)
+ || (_ports_flags & _PORTS_INHIBIT_WAIT))
condition_broadcast (&_ports_block);
+ /* This removes the current thread's rpc (which should be INFO) from the
+ ports interrupted list. */
+ ports_self_interrupted ();
+
/* Clear the cancellation flag for this thread since the current
RPC is now finished anwhow. */
hurd_check_cancel ();
diff --git a/libports/get-right.c b/libports/get-right.c
index 0c5f13b7..95662f58 100644
--- a/libports/get-right.c
+++ b/libports/get-right.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -23,14 +23,13 @@
#include <mach/notify.h>
#include <assert.h>
-static volatile error_t gdb_loses = 0;
-
mach_port_t
ports_get_right (void *port)
{
struct port_info *pi = port;
mach_port_t foo;
-
+ error_t err;
+
mutex_lock (&_ports_lock);
if (pi->port_right == MACH_PORT_NULL)
@@ -38,23 +37,23 @@ ports_get_right (void *port)
mutex_unlock (&_ports_lock);
return MACH_PORT_NULL;
}
-
+
pi->mscount++;
if ((pi->flags & PORT_HAS_SENDRIGHTS) == 0)
{
pi->flags |= PORT_HAS_SENDRIGHTS;
pi->refcnt++;
- gdb_loses =
- mach_port_request_notification (mach_task_self (), pi->port_right,
- MACH_NOTIFY_NO_SENDERS, pi->mscount,
- pi->port_right,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
- assert_perror (gdb_loses);
+ err = mach_port_request_notification (mach_task_self (),
+ pi->port_right,
+ MACH_NOTIFY_NO_SENDERS,
+ pi->mscount,
+ pi->port_right,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &foo);
+ assert_perror (err);
if (foo != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self (), foo);
}
mutex_unlock (&_ports_lock);
return pi->port_right;
}
-
-
diff --git a/libports/allocate-port.c b/libports/get-send-right.c
index 61e093c8..3e00276c 100644
--- a/libports/allocate-port.c
+++ b/libports/get-send-right.c
@@ -1,6 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
+/* ports_get_send_right -- get a send right to a ports object
+ Copyright (C) 2000 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -19,20 +18,21 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ports.h"
+#include <assert.h>
-/* Backward compatibility. */
-void *ports_allocate_port (struct port_bucket *bucket,
- size_t size,
- struct port_class *class)
+mach_port_t
+ports_get_send_right (void *port)
{
- void *result;
- if (ports_create_port (class, bucket, size, &result))
- result = 0;
- return result;
-}
+ error_t err;
+ mach_port_t right;
+ right = ports_get_right (port);
+ if (right == MACH_PORT_NULL)
+ return MACH_PORT_NULL;
-#include "linkwarn.h"
+ err = mach_port_insert_right (mach_task_self (),
+ right, right, MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
-link_warning (ports_allocate_port,
- "ports_allocate_port is obsolete; use ports_create_port instead")
+ return right;
+}
diff --git a/libports/import-port.c b/libports/import-port.c
index b958245f..d7a62960 100644
--- a/libports/import-port.c
+++ b/libports/import-port.c
@@ -76,7 +76,7 @@ ports_import_port (struct port_class *class, struct port_bucket *bucket,
goto loop;
}
- err = ihash_add (bucket->htable, port, pi, &pi->hentry);
+ err = hurd_ihash_add (&bucket->htable, port, pi);
if (err)
goto lose;
diff --git a/libports/inhibit-all-rpcs.c b/libports/inhibit-all-rpcs.c
index 13aa62c6..9a72f83e 100644
--- a/libports/inhibit-all-rpcs.c
+++ b/libports/inhibit-all-rpcs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -36,19 +36,25 @@ ports_inhibit_all_rpcs ()
{
struct port_bucket *bucket;
int this_one = 0;
- error_t interruptor (void *portstruct)
- {
- struct rpc_info *rpc;
- struct port_info *pi = portstruct;
-
- for (rpc = pi->current_rpcs; rpc; rpc = rpc->next)
- if (hurd_thread_cancel (rpc->thread) == EINTR)
- this_one = 1;
- return 0;
- }
for (bucket = _ports_all_buckets; bucket; bucket = bucket->next)
- ihash_iterate (bucket->htable, interruptor);
+ {
+ HURD_IHASH_ITERATE (&bucket->htable, portstruct)
+ {
+ struct rpc_info *rpc;
+ struct port_info *pi = portstruct;
+
+ for (rpc = pi->current_rpcs; rpc; rpc = rpc->next)
+ {
+ /* Avoid cancelling the calling thread if it's currently
+ handling a RPC. */
+ if (rpc->thread == hurd_thread_self ())
+ this_one = 1;
+ else
+ hurd_thread_cancel (rpc->thread);
+ }
+ }
+ }
while (_ports_total_rpcs > this_one)
{
@@ -70,5 +76,3 @@ ports_inhibit_all_rpcs ()
return err;
}
-
-
diff --git a/libports/inhibit-bucket-rpcs.c b/libports/inhibit-bucket-rpcs.c
index a04906ff..7fc55d31 100644
--- a/libports/inhibit-bucket-rpcs.c
+++ b/libports/inhibit-bucket-rpcs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -35,18 +35,22 @@ ports_inhibit_bucket_rpcs (struct port_bucket *bucket)
else
{
int this_one = 0;
- error_t interruptor (void *portstruct)
+
+ HURD_IHASH_ITERATE (&bucket->htable, portstruct)
{
struct rpc_info *rpc;
struct port_info *pi = portstruct;
for (rpc = pi->current_rpcs; rpc; rpc = rpc->next)
- if (hurd_thread_cancel (rpc->thread) == EINTR)
- this_one = 1;
- return 0;
+ {
+ /* Avoid cancelling the calling thread. */
+ if (rpc->thread == hurd_thread_self ())
+ this_one = 1;
+ else
+ hurd_thread_cancel (rpc->thread);
+ }
}
- ihash_iterate (bucket->htable, interruptor);
while (bucket->rpcs > this_one)
{
diff --git a/libports/inhibit-class-rpcs.c b/libports/inhibit-class-rpcs.c
index 00b9b361..951de4bf 100644
--- a/libports/inhibit-class-rpcs.c
+++ b/libports/inhibit-class-rpcs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -39,8 +39,13 @@ ports_inhibit_class_rpcs (struct port_class *class)
for (pi = class->ports; pi; pi = pi->next)
for (rpc = pi->current_rpcs; rpc; rpc = rpc->next)
- if (hurd_thread_cancel (rpc->thread) == EINTR)
- this_one = 1;
+ {
+ /* Avoid cancelling the calling thread. */
+ if (rpc->thread == hurd_thread_self ())
+ this_one = 1;
+ else
+ hurd_thread_cancel (rpc->thread);
+ }
while (class->rpcs > this_one)
{
diff --git a/libports/inhibit-port-rpcs.c b/libports/inhibit-port-rpcs.c
index 4ec5d853..02a3b462 100644
--- a/libports/inhibit-port-rpcs.c
+++ b/libports/inhibit-port-rpcs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -38,8 +38,13 @@ ports_inhibit_port_rpcs (void *portstruct)
struct rpc_info *this_rpc = 0;
for (rpc = pi->current_rpcs; rpc; rpc = rpc->next)
- if (hurd_thread_cancel (rpc->thread) == EINTR)
- this_rpc = rpc;
+ {
+ /* Avoid cancelling the calling thread. */
+ if (rpc->thread == hurd_thread_self ())
+ this_rpc = rpc;
+ else
+ hurd_thread_cancel (rpc->thread);
+ }
while (pi->current_rpcs
/* If this thread's RPC is the only one left, it doesn't count. */
diff --git a/libports/init.c b/libports/init.c
index 44c8bdd4..7d4d16fd 100644
--- a/libports/init.c
+++ b/libports/init.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -23,6 +23,6 @@
struct mutex _ports_lock = MUTEX_INITIALIZER;
struct condition _ports_block = CONDITION_INITIALIZER;
-struct port_bucket *_ports_all_buckets = 0;
-int _ports_total_rpcs = 0;
-int _ports_flags = 0;
+struct port_bucket *_ports_all_buckets;
+int _ports_total_rpcs;
+int _ports_flags;
diff --git a/libports/intern-external-port.c b/libports/intern-external-port.c
deleted file mode 100644
index 8ece48e4..00000000
--- a/libports/intern-external-port.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include "ports.h"
-
-/* Backward compatibility. */
-void *ports_intern_external_port (struct port_bucket *bucket,
- mach_port_t port,
- size_t size,
- struct port_class *class)
-{
- void *result;
- if (ports_import_port (class, bucket, port, size, &result))
- result = 0;
- return result;
-}
-
-#include "linkwarn.h"
-link_warning (ports_intern_external_port,
- "ports_intern_external_port is obsolete; use ports_import_port")
diff --git a/libports/interrupt-notified-rpcs.c b/libports/interrupt-notified-rpcs.c
index 061d3d87..bdfef977 100644
--- a/libports/interrupt-notified-rpcs.c
+++ b/libports/interrupt-notified-rpcs.c
@@ -1,8 +1,8 @@
/* Handle interruping rpcs because of notification
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2001 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -21,11 +21,11 @@
#include "ports.h"
/* A linked list of ports for which notification has been requested. */
-struct ports_notify *_ports_notifications = 0;
+struct ports_notify *_ports_notifications;
/* Free lists for notify structures. */
-struct ports_notify *_ports_free_ports_notifies = 0;
-struct rpc_notify *_ports_free_rpc_notifies = 0;
+struct ports_notify *_ports_free_ports_notifies;
+struct rpc_notify *_ports_free_rpc_notifies;
/* Interrupt any rpcs on OBJECT that have requested such. */
void
diff --git a/libports/interrupt-on-notify.c b/libports/interrupt-on-notify.c
index 4f8c1344..42ae4884 100644
--- a/libports/interrupt-on-notify.c
+++ b/libports/interrupt-on-notify.c
@@ -1,8 +1,8 @@
/* Mark an rpc to be interrupted when a port dies
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 96, 99 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ports.h"
+#include <assert.h>
/* Arrange for hurd_cancel to be called on RPC's thread if OBJECT gets notified
that any of the things in COND have happened to PORT. RPC should be an
@@ -175,11 +176,9 @@ ports_interrupt_self_on_notification (void *object,
break;
mutex_unlock (&_ports_lock);
- if (rpc)
- /* We don't have to worry about RPC going away after we dropped the lock
- because we're that thread, and we're still here. */
- return ports_interrupt_rpc_on_notification (object, rpc, port, what);
- else
- /* This thread isn't in an rpc! */
- return EIEIO;
+ assert (rpc);
+
+ /* We don't have to worry about RPC going away after we dropped the lock
+ because we're that thread, and we're still here. */
+ return ports_interrupt_rpc_on_notification (object, rpc, port, what);
}
diff --git a/libports/interrupt-rpcs.c b/libports/interrupt-rpcs.c
index 95eeed4b..7c28ff2c 100644
--- a/libports/interrupt-rpcs.c
+++ b/libports/interrupt-rpcs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -31,7 +31,10 @@ ports_interrupt_rpcs (void *portstruct)
mutex_lock (&_ports_lock);
for (rpc = pi->current_rpcs; rpc; rpc = rpc->next)
- hurd_thread_cancel (rpc->thread);
+ {
+ hurd_thread_cancel (rpc->thread);
+ _ports_record_interruption (rpc);
+ }
mutex_unlock (&_ports_lock);
}
diff --git a/libports/interrupted.c b/libports/interrupted.c
new file mode 100644
index 00000000..e4cb2fc2
--- /dev/null
+++ b/libports/interrupted.c
@@ -0,0 +1,75 @@
+/* Keeping track of thread interruption
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "ports.h"
+
+static spin_lock_t interrupted_lock = SPIN_LOCK_INITIALIZER;
+
+/* True if some active rpc has been interrupted. */
+static struct rpc_info *interrupted = 0;
+
+/* If the current thread's rpc has been interrupted with
+ ports_interrupt_rpcs, return true (and clear the interrupted flag). */
+int
+ports_self_interrupted ()
+{
+ struct rpc_info **rpc_p, *rpc;
+ thread_t self = hurd_thread_self ();
+
+ spin_lock (&interrupted_lock);
+ for (rpc_p = &interrupted; *rpc_p; rpc_p = &rpc->interrupted_next)
+ {
+ rpc = *rpc_p;
+ if (rpc->thread == self)
+ {
+ *rpc_p = rpc->interrupted_next;
+ spin_unlock (&interrupted_lock);
+ rpc->interrupted_next = 0;
+ return 1;
+ }
+ }
+ spin_unlock (&interrupted_lock);
+
+ return 0;
+}
+
+/* Add RPC to the list of rpcs that have been interrupted. */
+void
+_ports_record_interruption (struct rpc_info *rpc)
+{
+ struct rpc_info *i;
+
+ spin_lock (&interrupted_lock);
+
+ /* See if RPC is already in the interrupted list. */
+ for (i = interrupted; i; i = i->interrupted_next)
+ if (i == rpc)
+ /* Yup, it is, so just leave it there. */
+ {
+ spin_unlock (&interrupted_lock);
+ return;
+ }
+
+ /* Nope, put it at the beginning. */
+ rpc->interrupted_next = interrupted;
+ interrupted = rpc;
+
+ spin_unlock (&interrupted_lock);
+}
diff --git a/libports/lookup-port.c b/libports/lookup-port.c
index d0ee8d00..8eb98a12 100644
--- a/libports/lookup-port.c
+++ b/libports/lookup-port.c
@@ -32,11 +32,11 @@ ports_lookup_port (struct port_bucket *bucket,
mutex_lock (&_ports_lock);
if (bucket)
- pi = ihash_find (bucket->htable, port);
+ pi = hurd_ihash_find (&bucket->htable, port);
else
for (bucket = _ports_all_buckets; bucket; bucket = bucket->next)
{
- pi = ihash_find (bucket->htable, port);
+ pi = hurd_ihash_find (&bucket->htable, port);
if (pi)
break;
}
diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c
index 2f3f344f..82fa2ac6 100644
--- a/libports/manage-multithread.c
+++ b/libports/manage-multithread.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -29,8 +29,7 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
ports_demuxer_type demuxer,
int thread_timeout,
int global_timeout,
- int wire_cthreads,
- mach_port_t wire_threads)
+ void (*hook)())
{
volatile int nreqthreads;
volatile int totalthreads;
@@ -61,6 +60,7 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
assert (nreqthreads);
nreqthreads--;
if (nreqthreads == 0)
+ /* No thread would be listening for requests, spawn one. */
spawn = 1;
spin_unlock (&lock);
@@ -123,10 +123,8 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
int timeout;
error_t err;
- if (wire_threads)
- thread_wire (wire_threads, hurd_thread_self (), 1);
- if (wire_cthreads)
- cthread_wire ();
+ if (hook)
+ (*hook) ();
if (master)
timeout = global_timeout;
@@ -153,6 +151,12 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
else
{
spin_lock (&lock);
+ if (nreqthreads == 1)
+ {
+ /* No other thread is listening for requests, continue. */
+ spin_unlock (&lock);
+ goto startover;
+ }
nreqthreads--;
totalthreads--;
spin_unlock (&lock);
@@ -160,12 +164,6 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
return 0;
}
- /* Wire this because hurd_thread_cancel will not interoperate
- cleanly with cthreads cleverness yet. */
- wire_cthreads = 1;
-
- thread_timeout = global_timeout = 0; /* XXX */
-
nreqthreads = 1;
totalthreads = 1;
thread_function (1);
diff --git a/libports/manage-one-thread.c b/libports/manage-one-thread.c
index 57b8a9a9..4ea740b2 100644
--- a/libports/manage-one-thread.c
+++ b/libports/manage-one-thread.c
@@ -69,7 +69,7 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket,
}
else
{
- /* No need to check cancel threshhold here, because
+ /* No need to check cancel threshold here, because
in a single threaded server the cancel is always
handled in order. */
status = demuxer (inp, outheadp);
diff --git a/libports/notify-dead-name.c b/libports/notify-dead-name.c
index 24e34674..c67145d1 100644
--- a/libports/notify-dead-name.c
+++ b/libports/notify-dead-name.c
@@ -1,6 +1,6 @@
/* Dead name notification
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -29,5 +29,9 @@ ports_do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_name)
return EOPNOTSUPP;
ports_dead_name (pi, dead_name);
ports_port_deref (pi);
+
+ /* Drop gratuitous extra reference that the notification creates. */
+ mach_port_deallocate (mach_task_self (), dead_name);
+
return 0;
}
diff --git a/libports/port-deref.c b/libports/port-deref.c
index a1238315..1ded45d9 100644
--- a/libports/port-deref.c
+++ b/libports/port-deref.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -32,11 +32,11 @@ ports_port_deref (void *portstruct)
mutex_lock (&_ports_lock);
- if (pi->refcnt == 1 && pi->weakrefcnt && !trieddroppingweakrefs)
+ if (pi->refcnt == 1 && pi->weakrefcnt
+ && pi->class->dropweak_routine && !trieddroppingweakrefs)
{
mutex_unlock (&_ports_lock);
- if (pi->class->dropweak_routine)
- (*pi->class->dropweak_routine) (pi);
+ (*pi->class->dropweak_routine) (pi);
trieddroppingweakrefs = 1;
goto retry;
}
diff --git a/libports/ports.h b/libports/ports.h
index 2d52daa4..9a5ccbc2 100644
--- a/libports/ports.h
+++ b/libports/ports.h
@@ -1,5 +1,5 @@
/* Ports library for server construction
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1993,94,95,96,97,99,2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -24,6 +24,7 @@
#include <mach.h>
#include <stdlib.h>
#include <hurd.h>
+#include <hurd/ihash.h>
#include <mach/notify.h>
/* These are global values for common flags used in the various structures.
@@ -45,7 +46,7 @@ struct port_info
mach_port_t port_right;
struct rpc_info *current_rpcs;
struct port_bucket *bucket;
- void **hentry;
+ hurd_ihash_locp_t hentry;
struct port_info *next, **prevp; /* links on port_class list */
};
/* FLAGS above are the following: */
@@ -57,7 +58,7 @@ struct port_info
struct port_bucket
{
mach_port_t portset;
- struct ihash *htable;
+ struct hurd_ihash htable;
int rpcs;
int flags;
int count;
@@ -92,6 +93,7 @@ struct rpc_info
thread_t thread;
struct rpc_info *next, **prevp;
struct rpc_notify *notifies;
+ struct rpc_info *interrupted_next;
};
/* An rpc has requested interruption on a port notification. */
@@ -162,7 +164,19 @@ error_t ports_create_port (struct port_class *class,
struct port_bucket *bucket,
size_t size,
void *result);
-
+
+/* Just like ports_create_port, except don't actually put the port
+ into the portset underlying BUCKET. This is intended to be used
+ for cases where the port right must be given out before the port is
+ fully initialized; with this call you are guaranteed that no RPC
+ service will occur on the port until you have finished initializing
+ it and installed it into the portset yourself. */
+error_t
+ports_create_port_noinstall (struct port_class *class,
+ struct port_bucket *bucket,
+ size_t size,
+ void *result);
+
/* For an existing RECEIVE right, create and return in RESULT a new port
structure; BUCKET, SIZE, and CLASS args are as for ports_create_port. */
error_t ports_import_port (struct port_class *class,
@@ -180,12 +194,12 @@ void ports_reallocate_from_external (void *port, mach_port_t receive);
/* Destroy the receive right currently associated with PORT. After
this call, ports_reallocate_port and ports_reallocate_from_external
- may not be used. */
-void ports_destroy_right (void *port);
+ may not be used. Always returns 0, for convenient use as an iterator. */
+error_t ports_destroy_right (void *port);
/* Return the receive right currently associated with PORT. The effects
on PORT are the same as in ports_destroy_right, except that the receive
- right itself is not affected. Note that in multi-threaded servers,
+ right itself is not affected. Note that in multi-threaded servers,
messages might already have been dequeued for this port before it gets
removed from the portset; such messages will get EOPNOTSUPP errors. */
mach_port_t ports_claim_right (void *port);
@@ -196,20 +210,25 @@ mach_port_t ports_claim_right (void *port);
were called. */
error_t ports_transfer_right (void *topt, void *frompt);
-/* Return the name of the receive right associated with PORT. The user
- is responsible for creating an ordinary send right from this name. */
+/* Return the name of the receive right associated with PORT. This assumes
+ that send rights will shortly be created, and arranges for notifications
+ accordingly. The user is responsible for creating an ordinary send
+ right from this name. */
mach_port_t ports_get_right (void *port);
+/* This convenience function uses ports_get_right, and
+ deals with the creation of a send right as well. */
+mach_port_t ports_get_send_right (void *port);
/* Reference counting */
-
+
/* Look up PORT and return the associated port structure, allocating a
reference. If the call fails, return 0. If BUCKET is nonzero,
then it specifies a bucket to search; otherwise all buckets will be
searched. If CLASS is nonzero, then the lookup will fail if PORT
is not in CLASS. */
-void *ports_lookup_port (struct port_bucket *bucket,
+void *ports_lookup_port (struct port_bucket *bucket,
mach_port_t port, struct port_class *class);
/* Allocate another reference to PORT. */
@@ -238,7 +257,7 @@ int ports_count_class (struct port_class *class);
of ports currently in BUCKET. */
int ports_count_bucket (struct port_bucket *bucket);
-/* Permit suspended port creation (blocked by ports_count_class)
+/* Permit suspended port creation (blocked by ports_count_class)
to continue. */
void ports_enable_class (struct port_class *class);
@@ -250,16 +269,23 @@ void ports_enable_bucket (struct port_bucket *bucket);
error_t ports_bucket_iterate (struct port_bucket *bucket,
error_t (*fun)(void *port));
+/* Call FUN once for each port in CLASS. */
+error_t ports_class_iterate (struct port_class *class,
+ error_t (*fun)(void *port));
+/* Internal entrypoint for above two. */
+error_t _ports_bucket_class_iterate (struct port_bucket *bucket,
+ struct port_class *class,
+ error_t (*fun)(void *port));
/* RPC management */
-
+
/* Type of MiG demuxer routines. */
-typedef int (*ports_demuxer_type)(mach_msg_header_t *inp,
+typedef int (*ports_demuxer_type)(mach_msg_header_t *inp,
mach_msg_header_t *outp);
-/* Call this when an RPC is beginning on PORT. INFO should be
- allocated by the caller and will be used to hold dynamic state.
+/* Call this when an RPC is beginning on PORT. INFO should be
+ allocated by the caller and will be used to hold dynamic state.
If this RPC should be abandoned, return EDIED; otherwise we
return zero. */
error_t ports_begin_rpc (void *port, mach_msg_id_t msg_id,
@@ -281,21 +307,17 @@ void ports_manage_port_operations_one_thread(struct port_bucket *bucket,
for each incoming message. Return if GLOBAL_TIMEOUT is nonzero and
no messages have been receieved for GLOBAL_TIMEOUT milliseconds.
Create threads as necessary to handle incoming messages so that no
- port is starved because of sluggishness on another port. All
- threads created (and the calling thread) will be wired with
- cthread_wire if WIRE_CTHREADS is non-zero. All threads created
- (and the calling thread) will be wired with thread_wire if
- WIRE_THREADS is non-zero (it must be the priviliged host port in
- order to succeed). If LOCAL_TIMEOUT is non-zero, then individual
- threads will die off if they handle no incoming messages for
- LOCAL_TIMEOUT milliseconds. */
+ port is starved because of sluggishness on another port. If
+ LOCAL_TIMEOUT is non-zero, then individual threads will die off if
+ they handle no incoming messages for LOCAL_TIMEOUT milliseconds.
+ HOOK (if not null) will be called in each new thread immediately
+ after it is created. */
void ports_manage_port_operations_multithread (struct port_bucket *bucket,
ports_demuxer_type demuxer,
int thread_timeout,
int global_timeout,
- int wire_cthreads,
- mach_port_t wire_threads);
-
+ void (*hook)(void));
+
/* Interrupt any pending RPC on PORT. Wait for all pending RPC's to
finish, and then block any new RPC's starting on that port. */
error_t ports_inhibit_port_rpcs (void *port);
@@ -325,6 +347,13 @@ void ports_resume_all_rpcs (void);
/* Cancel (with thread_cancel) any RPC's in progress on PORT. */
void ports_interrupt_rpcs (void *port);
+/* If the current thread's rpc has been interrupted with
+ ports_interrupt_rpcs, return true (and clear the interrupted flag). */
+int ports_self_interrupted ();
+
+/* Add RPC to the list of rpcs that have been interrupted. */
+void _ports_record_interruption (struct rpc_info *rpc);
+
/* Arrange for hurd_cancel to be called on RPC's thread if OBJECT gets notified
that any of the things in COND have happened to PORT. RPC should be an
rpc on OBJECT. */
@@ -363,7 +392,7 @@ extern kern_return_t
/* A default interrupt server */
int ports_interrupt_server (mach_msg_header_t *, mach_msg_header_t *);
-extern kern_return_t ports_S_interrupt_operation (mach_port_t,
+extern kern_return_t ports_S_interrupt_operation (mach_port_t,
mach_port_seqno_t);
/* Private data */
@@ -376,5 +405,7 @@ extern int _ports_flags;
#define _PORTS_BLOCKED PORTS_BLOCKED
#define _PORTS_INHIBIT_WAIT PORTS_INHIBIT_WAIT
void _ports_complete_deallocate (struct port_info *);
+error_t _ports_create_port_internal (struct port_class *, struct port_bucket *,
+ size_t, void *, int);
#endif
diff --git a/libports/reallocate-from-external.c b/libports/reallocate-from-external.c
index 80b2905e..ebddd9f7 100644
--- a/libports/reallocate-from-external.c
+++ b/libports/reallocate-from-external.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2003 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -44,7 +44,7 @@ ports_reallocate_from_external (void *portstruct, mach_port_t receive)
MACH_PORT_RIGHT_RECEIVE, -1);
assert_perror (err);
- ihash_locp_remove (pi->bucket->htable, pi->hentry);
+ hurd_ihash_locp_remove (&pi->bucket->htable, pi->hentry);
if ((pi->flags & PORT_HAS_SENDRIGHTS) && !stat.mps_srights)
{
@@ -61,7 +61,7 @@ ports_reallocate_from_external (void *portstruct, mach_port_t receive)
pi->cancel_threshold = 0;
pi->mscount = stat.mps_mscount;
- ihash_add (pi->bucket->htable, receive, pi, &pi->hentry);
+ hurd_ihash_add (&pi->bucket->htable, receive, pi);
mutex_unlock (&_ports_lock);
mach_port_move_member (mach_task_self (), receive, pi->bucket->portset);
diff --git a/libports/reallocate-port.c b/libports/reallocate-port.c
index 35dd4883..23898e88 100644
--- a/libports/reallocate-port.c
+++ b/libports/reallocate-port.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -37,7 +37,7 @@ ports_reallocate_port (void *portstruct)
MACH_PORT_RIGHT_RECEIVE, -1);
assert_perror (err);
- ihash_locp_remove (pi->bucket->htable, pi->hentry);
+ hurd_ihash_locp_remove (&pi->bucket->htable, pi->hentry);
err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
&pi->port_right);
@@ -49,11 +49,12 @@ ports_reallocate_port (void *portstruct)
}
pi->cancel_threshold = 0;
pi->mscount = 0;
- ihash_add (pi->bucket->htable, pi->port_right, pi, &pi->hentry);
+ hurd_ihash_add (&pi->bucket->htable, pi->port_right, pi);
mutex_unlock (&_ports_lock);
- mach_port_move_member (mach_task_self (), pi->port_right,
- pi->bucket->portset);
+ err = mach_port_move_member (mach_task_self (), pi->port_right,
+ pi->bucket->portset);
+ assert_perror (err);
if (dropref)
ports_port_deref (pi);
diff --git a/libports/resume-all-rpcs.c b/libports/resume-all-rpcs.c
index fa978c1e..452da3b2 100644
--- a/libports/resume-all-rpcs.c
+++ b/libports/resume-all-rpcs.c
@@ -28,7 +28,7 @@ ports_resume_all_rpcs ()
mutex_lock (&_ports_lock);
assert (_ports_flags & _PORTS_INHIBITED);
_ports_flags &= ~_PORTS_INHIBITED;
- if (_ports_flags | _PORTS_BLOCKED)
+ if (_ports_flags & _PORTS_BLOCKED)
{
_ports_flags &= ~_PORTS_BLOCKED;
condition_broadcast (&_ports_block);
diff --git a/libports/resume-bucket-rpcs.c b/libports/resume-bucket-rpcs.c
index 9d968874..59cc75a4 100644
--- a/libports/resume-bucket-rpcs.c
+++ b/libports/resume-bucket-rpcs.c
@@ -28,7 +28,7 @@ ports_resume_bucket_rpcs (struct port_bucket *bucket)
mutex_lock (&_ports_lock);
assert (bucket->flags & PORT_BUCKET_INHIBITED);
bucket->flags &= ~PORT_BUCKET_INHIBITED;
- if (bucket->flags | PORT_BUCKET_BLOCKED)
+ if (bucket->flags & PORT_BUCKET_BLOCKED)
{
bucket->flags &= ~PORT_BUCKET_BLOCKED;
condition_broadcast (&_ports_block);
diff --git a/libports/resume-class-rpcs.c b/libports/resume-class-rpcs.c
index 4b35f26c..a4191747 100644
--- a/libports/resume-class-rpcs.c
+++ b/libports/resume-class-rpcs.c
@@ -28,7 +28,7 @@ ports_resume_class_rpcs (struct port_class *class)
mutex_lock (&_ports_lock);
assert (class->flags & PORT_CLASS_INHIBITED);
class->flags &= ~PORT_CLASS_INHIBITED;
- if (class->flags | PORT_CLASS_BLOCKED)
+ if (class->flags & PORT_CLASS_BLOCKED)
{
class->flags &= ~PORT_CLASS_BLOCKED;
condition_broadcast (&_ports_block);
diff --git a/libports/resume-port-rpcs.c b/libports/resume-port-rpcs.c
index 563c9adc..e9e30fbd 100644
--- a/libports/resume-port-rpcs.c
+++ b/libports/resume-port-rpcs.c
@@ -31,7 +31,7 @@ ports_resume_port_rpcs (void *portstruct)
assert (pi->flags & PORT_INHIBITED);
pi->flags &= ~PORT_INHIBITED;
- if (pi->flags | PORT_BLOCKED)
+ if (pi->flags & PORT_BLOCKED)
{
pi->flags &= ~PORT_BLOCKED;
condition_broadcast (&_ports_block);
diff --git a/libports/transfer-right.c b/libports/transfer-right.c
index d5844ea2..e7b0ff55 100644
--- a/libports/transfer-right.c
+++ b/libports/transfer-right.c
@@ -1,5 +1,5 @@
/* Transfer the receive right from one port structure to another
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2003 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,6 +20,7 @@
#include "ports.h"
+#include <assert.h>
#include <hurd/ihash.h>
error_t
@@ -40,7 +41,7 @@ ports_transfer_right (void *tostruct,
port = frompi->port_right;
if (port != MACH_PORT_NULL)
{
- ihash_locp_remove (frompi->bucket->htable, frompi->hentry);
+ hurd_ihash_locp_remove (&frompi->bucket->htable, frompi->hentry);
frompi->port_right = MACH_PORT_NULL;
if (frompi->flags & PORT_HAS_SENDRIGHTS)
{
@@ -53,9 +54,10 @@ ports_transfer_right (void *tostruct,
/* Destroy the existing right in TOPI. */
if (topi->port_right != MACH_PORT_NULL)
{
- ihash_locp_remove (topi->bucket->htable, topi->hentry);
+ hurd_ihash_locp_remove (&topi->bucket->htable, topi->hentry);
err = mach_port_mod_refs (mach_task_self (), topi->port_right,
MACH_PORT_RIGHT_RECEIVE, -1);
+ assert_perror (err);
if ((topi->flags & PORT_HAS_SENDRIGHTS) && !hassendrights)
{
dereftopi = 1;
@@ -75,9 +77,13 @@ ports_transfer_right (void *tostruct,
if (port)
{
- ihash_add (topi->bucket->htable, port, topi, &topi->hentry);
+ hurd_ihash_add (&topi->bucket->htable, port, topi);
if (topi->bucket != frompi->bucket)
- mach_port_move_member (mach_task_self (), port, topi->bucket->portset);
+ {
+ err = mach_port_move_member (mach_task_self (), port,
+ topi->bucket->portset);
+ assert_perror (err);
+ }
}
mutex_unlock (&_ports_lock);
diff --git a/libps/ChangeLog b/libps/ChangeLog
deleted file mode 100644
index ff633deb..00000000
--- a/libps/ChangeLog
+++ /dev/null
@@ -1,761 +0,0 @@
-Fri Aug 2 15:12:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (set_procinfo_flags): Pass HAVE to count_threads.
- (count_threads): Take new argument HAVE, and use different thread
- counting method depending on whether we have thread detail info.
-
-Thu Jul 18 18:54:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * tty.c (ps_tty_abbrevs): Add an entry for /dev/comX -> cX.
-
-Thu Jul 18 00:45:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Remove ps_msg.h and ps_term.h.
-
-Wed Jul 10 22:49:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (set_procinfo_flags): Don't use fake "*" wait value
- if there's no msgport.
-
-Mon Jul 8 21:39:58 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * write.c (_ps_stream_write_field): If a field is truncatable
- (MAX_WIDTH >= 0), take some of our spacing deficit out of it.
-
-Tue Jul 2 14:43:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (proc_stat_set_flags): Pass PS->task_events_info to
- task_info, not its address.
-
-Thu Jun 27 18:32:27 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Add common.h.
-
-Thu Jun 27 12:33:41 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.h (struct ps_fmt): Add SRC_LEN field.
- (proc_stat_list_clone, ps_fmt_clone): New declarations.
- * fmt.c (_fmt_create): Set NEW_FMT->src_len. Use strdup.
- (ps_fmt_clone): New function.
- * proclist.c (proc_stat_list_clone): New function.
-
-Mon Jun 3 10:17:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (ps_emit_wait): Never truncate what we write.
-
- * user.c (ps_user_passwd): Check return value of install_passwd
- correctly (it's an error_t).
-
- * ps.h (struct proc_stat): Add PROC_INFO_VM_ALLOCED,
- THREAD_WAITS_VM_ALLOCED, and ARGS_VM_ALLOCED fields,
- * procstat.c (merge_procinfo) Take a struct proc_stat as an arg,
- not all the individual fields. Correctly set OLD_PI_HDR.
- Correctly calculate REALLY_NEED.
- (set_procinfo_flags): Use new calling merge_procinfo calling convention.
- (_proc_stat_free): Use explicit VM_ALLOCED flag for MFREEMEM.
- (proc_stat_set_flags): Try mallocing a buffer for PS->args.
- Move second call to set_procinfo_flags after msgport suppress test.
- Add TEST_MSGPORT_FLAGS variable, & use it.
- Be more picky about when we call set_procinfo_flags.
-
-Sat Jun 1 11:18:58 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (set_procinfo_flags): New function.
- (proc_stat_set_flags): Use it, to get msgport validity testing right.
- (merge_procinfo): Take and return HAVE instead of using a
- reference parameter. Clean up malloced storage if we get an error.
-
- * spec.c (struct ps_fmt_spec_block): New type.
- (specs_add_alias): Use a linked list of ps_fmt_spec_blocks instead of
- reallocing a vector of specs.
- (ps_fmt_specs_find): Change searching accordingly.
- * ps.h (struct ps_fmt_specs): The EXPANSIONS field now points to a
- struct ps_fmt_spec_block. Delete EXPANSIONS_ALLOCED field.
-
- * procstat.c (merge_procinfo): Correctly test for malloc failure.
-
-Fri May 31 18:36:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (MFREEMEM): New macro combining MFREEM & MFREEVM.
- (MFREEM, MFREEVM): Macros deleted.
- (merge_procinfo): Do mem allocation more efficiently and correctly.
- (fetch_procinfo): Do conversion for PI_SIZE from/to units of
- sizeof (int), so no one else has to deal with it.
- (PROCINFO_MALLOC_SIZE, WAITS_MALLOC_SIZE): New macros.
-
- * procstat.c (proc_stat_set_flags): After fetching number of
- threads to guess whether we need wait info, put it in PS->num_threads.
- (merge_procinfo): Avoid vm_allocing a procinfo buffer each time if
- we can help it.
- Correctly reflect newly fetched info.
- (PSTAT_PROCINFO_MERGE, PSTAT_PROCINFO_REFETCH): New macros.
-
-Wed May 29 11:31:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (MP_MGET): Only disable msgport on timeout.
- (get_thread_wait): Decrement N in loop.
-
- * ps.h: Renumber PSTAT_ values to remove dup.
-
- * procstat.c (merge_procinfo): Don't die if WAITS == 0.
- (summarize_thread_waits): Correctly advance NEXT_WAIT.
- Skip threads marked `itimer'.
- (proc_stat_set_flags): Consider processes with less than 4 threads
- to be candidates for a meaningful process wait status.
- (get_thread_wait): Use strnlen instead of memchr.
- (PSTAT_PROCINFO): Typo: PSTAT_THREAD_WAIT --> PSTAT_THREAD_WAITS.
- (PSTAT_USES_MSGPORT): Add PSTAT_THREAD_WAIT.
-
-Tue May 28 16:36:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fmt.c (_fmt_create): Make NAME termination work for posix-mode.
-
- * fmt.c (ps_fmt_write_proc_stat): Call the output function correctly.
- (_fmt_create): Get FIELD's precision, not width, from its spec.
-
-Fri May 24 13:33:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * procstat.c (fetch_procinfo): Always turn on PSTAT_PROC_INFO if
- proc_getprocinfo returns successfully.
- (merge_procinfo): Update *HAVE with PSTAT_PROC_INFO from
- REALLY_HAVE here.
-
-Wed May 22 19:55:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fmt.c (_fmt_create): Increment SRC when reading modifiers.
- Recognize '^' modifier.
-
-Sun May 12 13:33:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (PSTAT_PROCINFO, PSTAT_PROCINFO_THREAD): Add
- PSTAT_THREAD_WAITS.
- (proc_stat_set_flags): Be more careful about when we fetch
- thread_wait information, and synthesize a process-summary thread_wait
- value for lots of threads.
- (summarize_thread_waits): Only give a real summary if there's but
- a single user thread.
- (fetch_procinfo): Use PSTAT_THREAD_WAITS instead of PSTAT_THREAD_WAIT.
- * ps.h (PSTAT_THREAD_WAITS): New macro.
-
- * procstat.c (merge_procinfo, fetch_procinfo): Change HAVE to be an
- input/output parameter.
- (proc_stat_set_flags): Change accordingly.
-
- * procstat.c (get_thread_wait): Correctly advance WAIT.
-
- * spec.c (specs): Give runtime specs 2 fraction digits by default.
-
-Thu May 9 17:03:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * procstat.c (fetch_procinfo): Pass a reference to PI_FLAGS in
- call to fetch_procinfo.
-
-Mon May 6 16:28:54 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * proclist.c (proc_stat_list_spec_nominal): Take a spec again.
- * ps.h (proc_stat_list_spec_nominal): Change FIELD arg to SPEC.
-
- * user.c (install_passwd): New function.
- (ps_user_passwd): Use it.
- (ps_user_uname_create, ps_user_passwd_create): New functions.
- * ps.h (ps_user_uname_create, ps_user_passwd_create): New declarations.
- (ps_fmt_set_output_width): New declaration.
-
- * spec.c (ps_emit_user_name): New function.
-
- * ps.h (struct ps_fmt_spec): Remove keep field, add flags field.
- (struct ps_fmt_field): Remove at_mod, colon_mod, & keep fields,
- add flags field.
- (PS_FMT_FIELD_AT_MOD, PS_FMT_FIELD_COLON_MOD, PS_FMT_FIELD_KEEP,
- PS_FMT_FIELD_UPCASE_TITLE): New macros.
- * spec.c (specs): Initialize flags field, not keep field.
- (specs_add_alias): Pass on flags field.
- * fmt.c (_fmt_create): Use flags fields, and implement global
- flags, and add upcase flag (^).
- (ps_fmt_write_titles): Implement PS_FMT_FIELD_UPCASE_TITLE.
- * proclist.c (proc_stat_list_spec_nominal): Use flags field, not
- keep field.
-
- * ps.h (struct proc_stat): Remove exec_flags field.
- (PSTAT_EXEC_FLAGS): Macro removed.
- * procstat.c (add_preconditions, proc_stat_set_flags): Remove
- references to exec_flags.
-
-Sun May 5 00:22:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * proclist.c (proc_stat_list_spec_nominal): Take a field, not a spec.
- If the field has the keep flag set, don't nominalize it.
- * fmt.c (_fmt_create): Change syntax of fields. Add support for
- precision and `@', `:', `?', & `!' modifiers.
- Add POSIX argument, and support for posix-style format strings.
- When using the field name as the title, use the defn, not the user's.
- (ps_fmt_squash): Call FN with the field, not the field's spec.
- (ps_fmt_squash_flags): Appropiately modify the function we use.
- (ps_fmt_create, ps_fmt_creation_error): Add POSIX argument.
- * ps.h (struct ps_fmt_spec): Add precision & keep fields.
- Change args to OUTPUT_FN.
- (struct ps_fmt_field): Add precision, keep, at_mod, & colon_mod fields.
- (proc_stat_list_spec_nominal): Change SPEC arg to FIELD.
- (ps_fmt_squash): Call FN on the field, not the spec.
- (ps_fmt_create, ps_fmt_creation_error): Add POSIX arg.
- * spec.c (specs): Add precision & keep fields.
- (FG): New macro.
- (ps_emit_*): Take FIELD argument instead of WIDTH.
-
-Thu May 2 00:12:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.h (ps_fmt_creation_error): New declaration.
-
-Tue Apr 30 18:54:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fmt.c (_fmt_create): New function (was ps_fmt_create).
- (ps_fmt_create): Call _fmt_create.
- (ps_fmt_creation_error): New function.
-
- * spec.c (ps_emit_past_time): Implement.
-
-Mon Apr 29 12:59:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (ps_emit_seconds): Use new args to fmt_seconds.
- (ps_emit_minutes): Use new args to fmt_minutes.
-
-Tue Apr 23 13:38:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.h (PSTAT_STATE_P_ATTRS): Fix names of individual flags.
-
- * spec.c (state_shadows): If a process has no parent don't show
- various process attributes (that are likely to be noise).
-
-Thu Apr 11 18:05:16 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (MIGCOMUFLAGS): Delete variable.
-
- * spec.c (ps_emit_past_time): Return zero.
-
-Wed Mar 27 15:19:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (msg-MIGUFLAGS, term-MIGUFLAGS): Add a user prefix of `ps_'.
- * procstat.c (proc_stat_set_flags): Use new prefix.
- Include "ps_msg.h".
- * tty.c (ps_tty_name): Use new prefix.
- Include "ps_term.h".
-
-Mon Mar 25 11:35:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ...just about everything...: Get rid of mega typedefs, and just
- use structure pointers like other hurd libraries. Other misc cleanups.
-
- * ps.h (struct ps_fmt_specs): Add EXPANSIONS & EXPANSIONS_ALLOCED.
- * spec.c (ps_fmt_specs_find): Use new alias expansion method.
- (specv_find, specs_add_alias): New functions.
-
-Mon Mar 11 16:27:14 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * write.c (noise_write): Keep track of amount printed correctly.
-
-Sat Mar 9 15:52:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * write.c (iscntl): New macro.
- (noise_write, noise_len): Correctly handle MAX < 0 case.
- (noise_write): Use new arguments for flush.
- (flush): Moved to file scope. Remove END argument and use NEW - 1.
- (noise_write): Make T of type unsigned char * so that chars with
- the high bit set print correctly.
-
-Thu Mar 7 19:08:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * write.c (iscntl): New macro.
- (noise_write, noise_len, flush): New functions.
- (ps_stream_write, _ps_stream_write_field): Use noise functions.
-
-Thu Feb 15 00:02:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (specs): Right-align the TTY column.
-
-Wed Feb 14 17:49:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * write.c (ps_stream_write): Don't screw up on negative spaces.
-
- * proclist.c (proc_stat_list_add_pids): Add and support new return
- parameter PROC_STATS.
- (proc_stat_list_add_pid): Add and support new return parameter PS.
- (proc_stat_list_add_fn_pids, proc_stat_list_add_id_fn_pids,
- proc_stat_list_add_all, proc_stat_list_add_login_coll,
- proc_stat_list_add_session, proc_stat_list_add_pgrp):
- Add and support new return parameters PROC_STATS & NUM_PROCS.
- * ps.h (proc_stat_list_add_pids, proc_stat_list_add_pid,
- proc_stat_list_add_all, proc_stat_list_add_login_coll,
- proc_stat_list_add_session, proc_stat_list_add_pgrp):
- Update declarations.
-
- * filters.c (ps_alive_filter): New variable.
- (ps_alive_p): New function.
- * ps.h (ps_alive_filter): New declaration.
-
-Mon Feb 12 14:34:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (ps_emit_wait): For rpcs, put the port first.
-
-Fri Feb 9 15:55:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.h (struct proc_stat): Add thread_wait, thread_waits, &
- thread_waits_len fields.
- (PSTAT_THREAD_WAIT): Renamed from PSTAT_THREAD_RPC.
- (proc_stat_thread_wait): New macro.
- (ps_stream_write_trunc_field): New declaration.
- * procstat.c (fetch_procinfo, merge_procinfo): Return wait strings.
- (summarize_thread_waits): Return both wait and rpc info.
- (get_thread_wait): New function.
- (proc_stat_set_flags): Support finding wait info.
- Change occurances of PSTAT_THREAD_RPC to PSTAT_THREAD_WAIT.
- * spec.c (specs): Change `Rpc' entry to `Wait'.
- (ps_emit_wait): New function.
- (ps_emit_string, ps_emit_string0): Use ps_stream_write_trunc_field.
- (ps_get_wait): Renamed from ps_get_rpc; calling convention changed.
- (ps_wait_getter): Renamed from ps_rpc_getter & contents changed accord.
- (get_syscall_name, get_rpc_name): New stub functions.
- * write.c (ps_stream_write_field): Call _ps_stream_write_field.
- (ps_stream_write_trunc_field): New function.
- (_ps_stream_write_field): New function, from ps_stream_write_field.
-
-Sat Feb 3 22:22:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (specs, state_shadows, ps_pid_getter,
- ps_thread_index_getter, ps_owner_getter, ps_owner_uid_getter,
- ps_ppid_getter, ps_pgrp_getter, ps_session_getter,
- ps_login_col_getter, ps_num_threads_getter, ps_args_getter,
- ps_state_getter, ps_rpc_getter, ps_vsize_getter, ps_rsize_getter,
- ps_cur_priority_getter, ps_base_priority_getter,
- ps_max_priority_getter, ps_usr_time_getter, ps_sys_time_getter,
- ps_tot_time_getter, ps_rmem_frac_getter, ps_cpu_frac_getter,
- ps_sleep_getter, ps_susp_count_getter, ps_proc_susp_count_getter,
- ps_thread_susp_count_getter, ps_tty_getter, ps_page_faults_getter,
- ps_cow_faults_getter, ps_pageins_getter, ps_msgs_sent_getter,
- ps_msgs_rcvd_getter, ps_zero_fills_getter): Make const.
- * ps.h (ps_getter_t, ps_filter_t, struct ps_filter,
- ps_not_leader_filter, ps_ctty_filter, ps_unorphaned_filter,
- ps_parent_filter, ps_std_fmt_specs): Make const.
-
-Mon Jan 15 16:32:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (summarize_thread_basic_info): If there are any
- running threads, then only average priority from them.
-
-Sun Jan 14 00:24:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (state_shadows): Don't reflect a suspended thread in the
- process state display if any thread isn't suspended.
-
-Sun Dec 24 14:24:52 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (installhdrsubdir): New macro (put ps.h in <>, not <hurd/>).
-
-Sat Dec 23 21:50:58 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fmt.c (ps_fmt_set_output_width): New function.
-
-Fri Dec 22 12:21:04 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.h (struct ps_user_hooks): New structure.
- (PSTAT_HOOK, PSTAT_USER_BASE, PSTAT_USER_MASK): New macros.
- (struct ps_context): Add USER_HOOKS field.
- * procstat.c (_proc_stat_free): Call user cleanup hook.
- (proc_stat_set_flags, add_preconditions): Deal with user bits.
- * context.c (ps_context_create): Initialize USER_HOOKS field.
-
-Thu Dec 21 12:04:24 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (ps_get_usr_time, ps_get_sys_time, ps_get_tot_time):
- Return a struct timeval instead of mach time_value_t.
- (ps_cmp_times): New function.
- (ps_emit_seconds, ps_emit_minutes): Use timefmt functions.
- (append_fraction, sprint_long_time, ps_emit_nice_seconds): Deleted.
- Include <timefmt.h>.
-
- * ps.h (struct ps_fmt_spec): Add TITLE field. Renamed
- DEFAULT_WIDTH field to WIDTH, and move to after TITLE.
- (ps_fmt_spec_width): Renamed from ps_fmt_spec_default_width()..
- (ps_fmt_spec_title): New macro.
- (struct ps_fmt): Add INVAL field.
- (ps_fmt_inval): New macro.
- * spec.c (specs): Rearrange to use new field layout.
-
- * fmt.c (ps_fmt_create): Use the new spec fields.
- (ps_fmt_write_proc_stat): Support new inval field in FMT.
-
- * spec.c (ps_fmt_specs_find): Renamed from find_ps_fmt_spec; now
- uses a struct ps_fmt_specs instead of an array of specs.
- (specs): Renamed from ps_std_fmt_specs;
- (ps_std_fmt_specs): Now of type struct ps_fmt_specs, pointing to specs.
- * ps.h (ps_fmt_specs_t): New typedef.
- (struct ps_fmt_specs): New structure.
- (ps_std_fmt_specs): Now of type struct ps_fmt_specs.
- (ps_fmt_specs_find): Renamed from find_ps_fmt_spec; now uses a
- struct ps_fmt_specs instead of an array of specs.
- (ps_fmt_create): Now takes a ps_fmt_specs_t structure instead of
- an array of specs.
-
- * fmt.c (ps_fmt_create): Now takes a ps_fmt_specs_t instead of an
- array of specs. Also fixup call to ps_fmt_specs_find().
-
- * ps.h (struct proc_stat): Add failed and hook fields.
- * procstat.c (proc_stat_set_flags): Support the failed field.
- (_proc_stat_create): Initialize the failed and hook fields.
-
-Wed Dec 20 12:49:24 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (ps_emit_nz_int): Write `-' when the value is 0, rather
- than mangling the output.
-
-Sun Dec 17 03:09:31 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * procstat.c (proc_stat_set_flags): If there's no owner, set the
- uid to -1 (and the owner to null), instead of failing.
- * spec.c (ps_emit_uid): Use an int uid, and emit "-" for none.
- (ps_emit_uname, ps_cmp_uids, ps_cmp_unames, ps_nominal_user):
- Handle NULL users.
-
- * filters.c (ps_not_leader_p): Renamed from ps_not_sess_leader_p.
- (ps_not_leader_filter): Renamed from ps_not_sess_leader_filter.
- (ps_unorphaned_p): Include login leaders as well as session leaders.
- * ps.h (ps_not_leader_filter): Renamed from ps_not_sess_leader_filter.
-
-Sat Dec 16 23:42:27 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.h (proc_stat_owner_uid): New macro.
- (PSTAT_OWNER_UID): New macro.
- (struct proc_stat): Add owner_uid field.
- * procstat.c (proc_stat_set_flags): Add support for PROC_OWNER_UID.
- (add_preconditions): Add preconditions for owner_uid (& owner).
- * spec.c (ps_owner_uid_getter): New variable.
- (ps_get_owner_uid, ps_nominal_uid): New functions.
- (ps_std_fmt_specs): Make "UID" use owner_uid rather than owner.
- (own_uid): New variable (was function local).
- * filters.c (ps_own_filter): Depend on PSTAT_OWNER_UID.
- (ps_own_p): Account for there being no uid.
-
-Thu Nov 16 12:51:34 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * write.c (ps_stream_write_field): Trim spaces from BUF.
-
-Wed Nov 15 18:55:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.h (ps_fmt_write_titles, ps_fmt_write_proc_stat,
- proc_stat_list_fmt, ps_emit_int, ps_emit_nz_int, ps_emit_priority,
- ps_emit_percent, ps_emit_num_blocks, ps_emit_nice_int,
- ps_emit_nice_seconds, ps_emit_seconds, ps_emit_uid, ps_emit_uname,
- ps_emit_string0, ps_emit_string, ps_emit_tty_name, ps_emit_state,
- ps_stream_write, ps_stream_space, ps_stream_pad,
- ps_stream_newline, ps_stream_write_field, ps_stream_write_int_field):
- Use new STREAM parameter instead of old one and count.
- (ps_stream_write): Renamed from ps_write_string.
- (ps_stream_space): Renamed from ps_write_spaces.
- (ps_stream_pad): Renamed from ps_write_padding.
- (ps_stream_write_field): Renamed from ps_write_field.
- (ps_stream_write_int_field): Renamed from ps_write_int_field.
- (ps_stream_newline): New declaration.
-
- * fmt.c (ps_fmt_write_titles, ps_fmt_write_proc_stat): Use new
- write function names. Use new STREAM parameter instead of old one
- and count.
- * proclist.c (proc_stat_list_fmt): Ditto.
- * spec.c (ps_emit_int, ps_emit_nz_int, ps_emit_priority,
- ps_emit_percent, ps_emit_num_blocks, ps_emit_nice_int,
- ps_emit_nice_seconds, ps_emit_seconds, ps_emit_uid, ps_emit_uname,
- ps_emit_string0, ps_emit_string, ps_emit_tty_name, ps_emit_state):
- Ditto.
- (ps_emit_seconds): Remove leading spaces from what we print.
-
- * write.c (ps_stream_write): Renamed from ps_write_string.
- (ps_stream_space): Renamed from ps_write_spaces.
- (ps_stream_pad): Renamed from ps_write_padding.
- (ps_stream_write_field): Renamed from ps_write_field.
- (ps_stream_write_int_field): Renamed from ps_write_int_field.
- (ps_stream_write, ps_stream_space, ps_stream_pad,
- ps_stream_newline, ps_stream_write_field, ps_stream_write_int_field):
- Use new STREAM parameter instead of old one and count.
- Use new function names.
- (ps_stream_write, ps_stream_space): Support negative spaces.
- (ps_stream_newline): New function.
- (ps_stream_pad, ps_stream_write_field): Use negative spaces.
-
-Tue Nov 7 17:43:48 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (ps_base_priority_getter, ps_cur_priority_getter,
- ps_get_base_priority, ps_get_cur_priority): Get this info using
- PSTAT_THREAD_BASIC instead of PSTAT_THREAD_SCHED.
- * procstat.c (summarize_thread_basic_info): Summarize available
- priority info too.
- (summarize_thread_sched_info): Do max_ & depress_priority too.
-
- * procstat.c (proc_stat_set_flags): Initialize the proc_info and
- proc_info_size fields if they've never been set before.
- Always update proc_getprocinfo fields, even if we already had them.
- (add_preconditions): Correct preconditions for PSTAT_STATE.
- (PSTAT_TEST_MSGPORT): Renamed from SHOULD_SUPPRESS_MSGPORT_FLAGS.
- (PSTAT_USES_MSGPORT): New macro.
- (SUPPRESS_MSGPORT_FLAGS): Use PSTAT_USES_MSGPORT, not PSTAT_MSGPORT.
- (proc_stat_set_flags): Use PSTAT_TEST_MSGPORT.
- (merge_procinfo): Only copy old task info if we actually had it.
- (proc_stat_set_flags): Don't unnecessarily grab procinfo stuff.
-
-Tue Oct 31 14:03:53 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * spec.c (ps_rpc_getter): New variable.
- (ps_get_rpc): New function.
- (ps_std_fmt_specs): Add "RPC" entry.
- (ps_emit_nz_int): New function.
-
- * ps.h (PSTAT_STATE_P_LOGINLDR, PSTAT_STATE_P_WAIT,
- PSTAT_STATE_P_GETMSG): New flags.
- * procstat.c (add_preconditions): Don't require PSTAT_EXEC_FLAGS for
- getting the state anymore (but do require PSTAT_{TASK,THREAD}_BASIC).
- (proc_stat_state_tags): Update to reflect new flags.
- (proc_stat_set_flags): Set new flags.
-
- * procstat.c (PSTAT_PROCINFO, PSTAT_PROCINFO_THREAD): New macros.
- (fetch_procinfo, merge_procinfo): New functions.
- (SHOULD_SUPPRESS_MSGPORT_FLAGS): Change to use more accurate flags.
- (should_suppress_msgport): Use new fields.
- (summarize_thread_basic_info, summarize_thread_sched_info,
- summarize_thread_states, summarize_thread_rpcs, count_threads):
- New functions.
- (proc_stat_set_flags): Support the new division of PSTAT_INFO into
- individual flags, and support getting thread information by
- using the thread's origin proc_stat.
- (_proc_stat_free): Free the thread_basic_info and
- thread_sched_info fields if necessary.
- (proc_stat_thread_create): Don't require that the source process
- have thread information around; it will be fetched later if necessary.
-
- * spec.c (ps_ppid_getter, ps_pgrp_getter, ps_session_getter,
- ps_login_col_getter): Use PSTAT_PROC_INFO, not PSTAT_INFO.
- (ps_get_ppid, ps_get_pgrp, ps_get_session, ps_get_login_col): Use
- proc_stat_proc_info, not proc_stat_info.
- (ps_vsize_getter, ps_rsize_getter, ps_rmem_frac_getter,
- ps_proc_susp_count_getter): Use PSTAT_TASK_BASIC, not PSTAT_INFO.
- (ps_get_vsize, ps_get_rsize, ps_get_rmem_frac, ps_get_proc_susp_count):
- Use proc_stat_task_basic_info, not proc_stat_info.
- (ps_cur_priority_getter, ps_base_priority_getter,
- ps_max_priority_getter): Use PSTAT_THREAD_SCHED, not PSTAT_THREAD_INFO.
- (ps_usr_time_getter, ps_sys_time_getter, ps_tot_time_getter,
- ps_cpu_frac_getter, ps_sleep_getter):
- Use PSTAT_THREAD_BASIC, not PSTAT_THREAD_INFO.
-
- * filters.c (ps_own_filter): Use PSTAT_PROC_INFO, not PSTAT_INFO.
- (ps_own_p): Use proc_stat_proc_info, not proc_stat_info.
-
- * ps.h (proc_stat_num_threads): Use the num_threads field.
- (proc_stat_thread_sched_info, proc_stat_thread_basic_info): Don't
- take the address, now that the fields used are pointers themselves.
- (proc_stat_thread_rpc, proc_stat_task_basic_info): New macros.
- (proc_stat_proc_info): Renamed from proc_stat_info.
- (PSTAT_PROC_INFO): Renamed from PSTAT_INFO.
- (PSTAT_TASK_BASIC, PSTAT_THREAD_BASIC, PSTAT_THREAD_SCHED,
- PSTAT_THREAD_RPC): New macros.
- (struct proc_stat): info & info_len --> proc_info & proc_info_len.
- Add the num_threads, task_basic_info, and thread_rpc fields.
- thread_basic_info & thread_sched_info are now pointers.
-
-Mon Oct 9 14:57:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile: Specify shared library dependencies.
-
-Fri Aug 25 18:55:51 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.h (ps_std_fmt_specs): Declare extern.
-
-Wed Aug 23 15:04:51 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Just put the migs stubs directly in here.
- (REMHDRS, MIGSTUBS): Removed.
-
-Sat Aug 19 11:49:06 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * procstat.c (proc_stat_set_flags): Actually set the P_STOP bit.
-
-Fri Aug 18 16:43:41 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.h (PSTAT_STATE_*): All proc state flags reorganized and
- renamed to PSTAT_STATE_P_* for process-global bits, and
- PSTAT_STATE_T_* for per-thread bits.
- * procstat.c (proc_stat_state_tags): Reordered to reflect the new
- ordering of the state bits.
- (thread_state, proc_stat_set_flags): Use the new state bits.
- * spec.c (ps_emit_state): Rearrange things to reflect the new
- state bits.
- (state_shadows): New variable.
- (ps_emit_state): Use the state_shadows list to turn off some states.
- * filters.c (ps_not_sess_leader_p, ps_unorphaned_p, ps_parent_p):
- Use the new state bits.
-
-Sat Jul 8 13:34:20 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * tty.c (ps_tty_short_name): That assignment around which extra
- parents were put was actually supposed to be a test! Make it so...
-
-Thu Jul 6 22:25:20 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * tty.c (ps_tty_short_name): Put extra parens around assignment
- inside if test.
-
-Thu Jul 6 15:36:04 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * Makefile: Remove include dependencies.
-
-Thu Jun 29 15:29:05 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * Makefile (REMHDRS): New variable.
- ($(OBJS)): depend on ../libihash/ihash.h.
- * ps.h: Include hurd/ihash.h instead of ihash.h.
-
-Wed May 31 13:09:04 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fmt.c (ps_fmt_create): Don't mutate the format spec name in the
- fmt_spec list we're passed just to get correctly capitalized
- titles. Instead, do things correctly by making enough room to
- store our own version of the title string, which we can do with
- what we please.
-
- * ps.h (ps_own_filter, ps_not_sess_leader_filter, ps_ctty_filter,
- ps_unorphaned_filter, ps_parent_filter): Declare these as extern
- so that the linker will bring in the initialized version (it's not
- doing so otherwise may be a bug).
-
-Thu May 4 20:01:32 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * procstat.c (proc_stat_set_flags): If a msg port call times out,
- disable use of that msg port.
- * Makefile (MIGSTUBS, term-MIGUFLAGS, msg-MIGUFLAGS): Compile our
- own msg & term user stubs to add msg timeouts.
-
-Wed May 3 11:32:52 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * proclist.c (proc_stat_list_for_each): New function for iterating
- over proc_stat_lists.
- (proc_stat_list_spec_nominal): New function for deciding if a
- particular spec is always nominal.
- * ps.h: Add entries for proc_stat_list_for_each and
- proc_stat_list_spec_nominal.
-
- * fmt.c (ps_fmt_squash, ps_fmt_squash_flags): Recalculate the set
- of ps flags needed by the fmt in ps_fmt_squash.
-
-Tue May 2 12:25:57 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * ps.h (ps_fmt_squash): Rename to ps_fmt_squash_flags.
- * fmt.c (ps_fmt_squash, ps_fmt_squash_flags): Rename ps_fmt_squash to
- ps_fmt_squash_flags, moving most of the guts into a new more
- general ps_fmt_squash, which is usable for other things than flags.
-
- * ps.h (struct ps_fmt_spec): Add the nominal_fn field, which will
- be used to decide whether values are `unexciting'.
- * spec.c (ps_std_fmt_specs): Add values for the nominal_fn field.
- (ps_nominal_zint, ps_nominal_user, ps_nominal_pri, ps_nominal_nth):
- Possible nominal funs.
-
- * ps.h (struct proc_stat): Add the suspend_count field, along with
- PSTAT_SUSPEND_COUNT, and proc_stat_suspend_count(ps).
- * procstat.c (proc_stat_set_flags, add_preconditions): Add support for
- the suspend_count field.
- * spec.c (ps_std_fmt_specs): Add the Susp (task/thread suspend count),
- PSusp (task suspend count), and TSusp (thread suspend count) output
- specs.
-
- * procstat.c (add_preconditions): A new function that calculates inter-
- flag dependencies; code moved here from from proc_stat_set_flags.
- (should_suppress_msgport): A new function that returns true when
- there's some condition indicating that we shouldn't use a process's msg
- port.
- (proc_stat_set_flags): Avoid using a process's msg port when it may be
- unusable.
-
- * ps.h (PSTAT_STATE_FORKED): A new flag to replace PSTAT_STATE_EXECED;
- we want to the flags to mark exceptional conditions, and this is rarer.
- * procstat.c (proc_stat_set_flags): Set PSTAT_STATE_FORKED instead of
- PSTAT_STATE_EXECED.
- (proc_stat_state_tags): Change the user state letter to "f" from "e".
-
-Sun Apr 23 15:38:39 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * Makefile: Set libname.
-
-Fri Apr 7 11:12:15 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * proclist.c (proc_stat_list_sort1): Always keep threads after their
- process when sorting!
-
- * spec.c (ps_emit_state): If a process is marked as stopped, then
- don't mention sleeping or idle threads' status (as that's presumably
- the signal thread).
-
- * ps.h: Add decls for proc_stat_list_add_pgrp & ps_tty_short_name.
-
- * proclist.c (proc_stat_list_add_all, proc_stat_list_add_login_coll,
- proc_stat_list_add_session): Move most of the functionality into
- proc_stat_list_add_[id_]fn_pids.
- (proc_stat_list_add_pgrp): New function, adds pids for a pgrp.
-
- * tty.c (ps_tty_short_name): New function; functionality used to be in
- spec.c
- (ps_tty_create, ps_tty_free): Add short_name fields.
- * spec.c (ps_emit_tty_name): Move guts into into ps_tty_short_name.
-
- * Just about everything: tighten up types used (i.e., don't use int
- for everything).
-
-Wed Apr 5 22:42:24 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * spec.c (ps_std_fmt_specs): Add the `Arg0' spec, which is the
- same as `Args', but only prints the first one. Change MsgsIn
- and MsgsOut to MsgIn and MsgOut.
-
-Tue Apr 4 20:13:55 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.h: Add the PSTAT_NO_MSGPORT flag, which when set disables any
- use of the process's message port.
- * procstat.c (proc_stat_set_flags): If PSTAT_NO_MSGPORT is set,
- don't use the msg port.
-
-Wed Mar 29 15:36:43 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * procstat.c (proc_stat_set_flags): Don't barf if a process has
- zero threads.
-
-Tue Mar 28 10:33:08 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * ps.h: Add the exec_flags field to the proc_stat structure, and
- add PSTAT_STATE_TRACED.
- * procstat.c (proc_stat_set_flags): Add support for the exec_flags
- field, and make the state bits calculation use that to support the
- PSTAT_STATE_TRACED bit.
-
-Mon Mar 20 20:51:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * user.c (ps_user_passwd) [COUNT, COPY]: Use `if' statement.
- * spec.c (ps_emit_num_blocks): Use int format for int arg.
- (sprint_frac_value): Likewise.
- * write.c (ps_write_int_field): Likewise.
- * host.c (ps_host_basic_info): Cast third arg to host_info.
- (ps_host_sched_info): Likewise.
- (ps_host_load_info): Likewise.
-
- * filters.c: Include <unistd.h>.
- * context.c: Include <hurd/term.h>.
- * tty.c: Likewise.
- * spec.c: Include <string.h>.
- * procstat.c: Likewise.
-
- * host.c: Don't include "pshost.h".
- * spec.c: Likewise.
-
- * ps.h: Include <errno.h>.
- (ps_get_host, ps_host_basic_info, ps_host_sched_info,
- ps_host_load_info): Copied here from pshost.h.
- (ps_write_string, ps_write_spaces, ps_write_padding,
- ps_write_field, ps_write_int_field): Copied here from pswrite.h
- * pshost.h, pswrite.h: Delete files.
-
- * New ChangeLog, moved into canonical directory structure.
- Old ChangeLog is in .../hurd/utils/ps.ChangeLog.
-
diff --git a/libps/Makefile b/libps/Makefile
index 8c8a22fc..ec35c852 100644
--- a/libps/Makefile
+++ b/libps/Makefile
@@ -1,6 +1,6 @@
# Makefile for libps
-#
-# Copyright (C) 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1995,96,99,2002 Free Software Foundation, Inc.
# Written by Michael I. Bushnell.
#
# This file is part of the GNU Hurd.
@@ -26,9 +26,10 @@ libname = libps
SRCS = context.c filters.c fmt.c host.c proclist.c procstat.c spec.c \
tty.c user.c write.c
LCLHDRS=ps.h common.h
-installhdrs=$(LCLHDRS)
+installhdrs = ps.h
installhdrsubdir = .
+HURDLIBS=ihash shouldbeinlibc
OBJS = $(SRCS:.c=.o) msgUser.o termUser.o
msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;' -DUSERPREFIX=ps_
@@ -38,5 +39,3 @@ ps_%.h: %_U.h
sed 's/_$*_user_/_ps_$*_user_/g' $< > $@
include ../Makeconf
-
-libps.so: ../libihash/libihash.so
diff --git a/libps/common.h b/libps/common.h
index 67d89bfd..6c44641e 100644
--- a/libps/common.h
+++ b/libps/common.h
@@ -1,6 +1,6 @@
/* Handy common functions for things in libps.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -18,6 +18,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <sys/mman.h>
+
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define MAX(x, y) ((x) < (y) ? (y) : (x))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -32,7 +34,7 @@
((type *)realloc((void *)(old),(unsigned)(sizeof(type)*(len))))
#define FREE(x) (void)free((void *)x)
-#define VMFREE(x, len) vm_deallocate(mach_task_self(), (vm_address_t)x, len)
+#define VMFREE(x, len) munmap((caddr_t)x, len)
#ifndef FALSE
#define FALSE 0
diff --git a/libps/context.c b/libps/context.c
index 4c5aeaf0..3082d83b 100644
--- a/libps/context.c
+++ b/libps/context.c
@@ -1,8 +1,8 @@
/* The ps_context type, for per-procserver and somewhat global state.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,99,2000,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -34,39 +34,23 @@
error_t
ps_context_create (process_t server, struct ps_context **pc)
{
- error_t err_procs, err_ttys, err_ttys_by_cttyid, err_users;
-
*pc = NEW (struct ps_context);
if (*pc == NULL)
return ENOMEM;
(*pc)->server = server;
(*pc)->user_hooks = 0;
- err_procs = ihash_create (&(*pc)->procs);
- err_ttys = ihash_create (&(*pc)->ttys);
- err_ttys_by_cttyid = ihash_create (&(*pc)->ttys_by_cttyid);
- err_users = ihash_create (&(*pc)->users);
-
- if (err_procs || err_ttys || err_ttys_by_cttyid)
- /* Some allocation error occurred, backout any successful ones and fail. */
- {
- if (!err_procs) ihash_free ((*pc)->procs);
- if (!err_users) ihash_free ((*pc)->users);
- if (!err_ttys) ihash_free ((*pc)->ttys);
- if (!err_ttys_by_cttyid) ihash_free ((*pc)->ttys_by_cttyid);
- free (*pc);
- return ENOMEM;
- }
-
- ihash_set_cleanup ((*pc)->procs,
- (void (*)(void *, void *arg))_proc_stat_free,
- NULL);
- ihash_set_cleanup ((*pc)->ttys,
- (void (*)(void *, void *arg))ps_tty_free,
- NULL);
- ihash_set_cleanup ((*pc)->users,
- (void (*)(void *, void *arg))ps_user_free,
- NULL);
+ hurd_ihash_init (&(*pc)->procs, HURD_IHASH_NO_LOCP);
+ hurd_ihash_init (&(*pc)->ttys, HURD_IHASH_NO_LOCP);
+ hurd_ihash_init (&(*pc)->ttys_by_cttyid, HURD_IHASH_NO_LOCP);
+ hurd_ihash_init (&(*pc)->users, HURD_IHASH_NO_LOCP);
+
+ hurd_ihash_set_cleanup (&(*pc)->procs,
+ (hurd_ihash_cleanup_t) _proc_stat_free, NULL);
+ hurd_ihash_set_cleanup (&(*pc)->ttys,
+ (hurd_ihash_cleanup_t) ps_tty_free, NULL);
+ hurd_ihash_set_cleanup (&(*pc)->users,
+ (hurd_ihash_cleanup_t) ps_user_free, NULL);
return 0;
}
@@ -75,10 +59,13 @@ ps_context_create (process_t server, struct ps_context **pc)
void
ps_context_free (struct ps_context *pc)
{
- ihash_free (pc->procs);
- ihash_free (pc->procs);
+ hurd_ihash_destroy (&pc->procs);
+ hurd_ihash_destroy (&pc->ttys);
+ hurd_ihash_destroy (&pc->ttys_by_cttyid);
+ hurd_ihash_destroy (&pc->users);
free (pc);
}
+
/* ---------------------------------------------------------------- */
@@ -87,15 +74,16 @@ ps_context_free (struct ps_context *pc)
(CREATE should return either an error-code or 0 if no error occurs), and
cache it in HT. */
static error_t
-lookup (int id, ihash_t ht, error_t (*create)(int id, void **), void **value)
+lookup (int id, hurd_ihash_t ht, error_t (*create)(int id, void **),
+ void **value)
{
- *value = ihash_find (ht, id);
+ *value = hurd_ihash_find (ht, id);
if (*value == NULL)
{
error_t err = create (id, value);
if (err)
return err;
- ihash_add (ht, id, *value, NULL);
+ hurd_ihash_add (ht, id, *value);
}
return 0;
}
@@ -109,7 +97,7 @@ ps_context_find_proc_stat (struct ps_context *pc, pid_t pid, struct proc_stat **
{
return _proc_stat_create (pid, pc, (struct proc_stat **)value);
}
- return lookup (pid, pc->procs, create, (void **)ps);
+ return lookup (pid, &pc->procs, create, (void **)ps);
}
/* Find a ps_tty for the terminal referred to by the port TTY_PORT, and
@@ -119,9 +107,9 @@ ps_context_find_tty (struct ps_context *pc, mach_port_t tty_port,
struct ps_tty **tty)
{
return lookup (tty_port,
- pc->ttys,
- (error_t (*)(int id, void **result))ps_tty_create,
- (void **)tty);
+ &pc->ttys,
+ (error_t (*)(int id, void **result))ps_tty_create,
+ (void **)tty);
}
/* Find a ps_tty for the terminal referred to by the ctty id port
@@ -140,7 +128,7 @@ ps_context_find_tty_by_cttyid (struct ps_context *pc, mach_port_t cttyid_port,
}
else
{
- int tty_port;
+ mach_port_t tty_port;
error_t err = termctty_open_terminal (cttyid_port, 0, &tty_port);
if (err)
return err;
@@ -149,7 +137,7 @@ ps_context_find_tty_by_cttyid (struct ps_context *pc, mach_port_t cttyid_port,
}
}
- return lookup (cttyid_port, pc->ttys, create, (void **)tty);
+ return lookup (cttyid_port, &pc->ttys_by_cttyid, create, (void **)tty);
}
/* Find a ps_user for the user referred to by UID, and return it in U. */
@@ -157,7 +145,7 @@ error_t
ps_context_find_user (struct ps_context *pc, uid_t uid, struct ps_user **u)
{
return lookup (uid,
- pc->users,
- (error_t (*)(int id, void **result))ps_user_create,
- (void **)u);
+ &pc->users,
+ (error_t (*)(int id, void **result))ps_user_create,
+ (void **) u);
}
diff --git a/libps/filters.c b/libps/filters.c
index 4fac0390..6663e61e 100644
--- a/libps/filters.c
+++ b/libps/filters.c
@@ -38,7 +38,7 @@ ps_own_p (struct proc_stat *ps)
own_uid = getuid ();
return own_uid >= 0 && own_uid == proc_stat_owner_uid (ps);
}
-struct ps_filter ps_own_filter =
+const struct ps_filter ps_own_filter =
{"own", PSTAT_OWNER_UID, ps_own_p};
static int
@@ -47,7 +47,7 @@ ps_not_leader_p (struct proc_stat *ps)
return
!(proc_stat_state (ps) & (PSTAT_STATE_P_SESSLDR | PSTAT_STATE_P_LOGINLDR));
}
-struct ps_filter ps_not_leader_filter =
+const struct ps_filter ps_not_leader_filter =
{"not-sess-leader", PSTAT_STATE, ps_not_leader_p};
static int
@@ -58,7 +58,7 @@ ps_unorphaned_p (struct proc_stat *ps)
!(state & PSTAT_STATE_P_ORPHAN)
|| (state & (PSTAT_STATE_P_SESSLDR | PSTAT_STATE_P_LOGINLDR));
}
-struct ps_filter ps_unorphaned_filter =
+const struct ps_filter ps_unorphaned_filter =
{"unorphaned", PSTAT_STATE, ps_unorphaned_p};
static int
@@ -66,7 +66,7 @@ ps_ctty_p (struct proc_stat *ps)
{
return proc_stat_cttyid (ps) != MACH_PORT_NULL;
}
-struct ps_filter ps_ctty_filter =
+const struct ps_filter ps_ctty_filter =
{"ctty", PSTAT_CTTYID, ps_ctty_p};
static int
@@ -74,7 +74,7 @@ ps_parent_p (struct proc_stat *ps)
{
return !(proc_stat_state (ps) & PSTAT_STATE_P_NOPARENT);
}
-struct ps_filter ps_parent_filter =
+const struct ps_filter ps_parent_filter =
{"parent", PSTAT_STATE, ps_parent_p};
static int
@@ -87,5 +87,5 @@ ps_alive_p (struct proc_stat *ps)
proc_stat_set_flags (ps, test_flag);
return proc_stat_has (ps, test_flag);
}
-struct ps_filter ps_alive_filter =
+const struct ps_filter ps_alive_filter =
{"alive", 0, ps_alive_p};
diff --git a/libps/fmt.c b/libps/fmt.c
index 8fed27a3..0465555d 100644
--- a/libps/fmt.c
+++ b/libps/fmt.c
@@ -1,7 +1,7 @@
/* Implements the ps_fmt type, which describes how to output a user-readable
version of a proc_stat.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -194,7 +194,9 @@ _fmt_create (char *src, int posix, struct ps_fmt_specs *fmt_specs,
while (*src != '\0' && *src != stop)
src++;
}
- *src++ = '\0'; /* NUL terminhate NAME. */
+
+ if (*src)
+ *src++ = '\0'; /* NUL terminate NAME. */
}
else
/* A gnu-style field spec: `NAME' or `NAME:TITLE'. */
@@ -240,11 +242,13 @@ _fmt_create (char *src, int posix, struct ps_fmt_specs *fmt_specs,
}
if (! field->title)
- /* No explicit title specified in the fmt string. */
- if (field->spec->title)
- field->title = field->spec->title; /* But the spec has one. */
- else
- field->title = field->spec->name; /* Just use the field name. */
+ {
+ /* No explicit title specified in the fmt string. */
+ if (field->spec->title)
+ field->title = field->spec->title; /* But the spec has one. */
+ else
+ field->title = field->spec->name; /* Just use field name. */
+ }
/* Add FIELD's required pstat_flags to FMT's set */
needs |= ps_getter_needs (ps_fmt_spec_getter (field->spec));
@@ -255,7 +259,7 @@ _fmt_create (char *src, int posix, struct ps_fmt_specs *fmt_specs,
field->precision = field->spec->precision;
field->flags = (field->spec->flags & ~clr_flags) ^ inv_flags;
-
+
if (quoted_name && *src == '}')
/* Skip optional trailing `}' after the spec name. */
src++;
@@ -288,7 +292,8 @@ _fmt_create (char *src, int posix, struct ps_fmt_specs *fmt_specs,
new_fmt->fields = fields;
new_fmt->num_fields = field - fields;
new_fmt->needs = needs;
- new_fmt->inval = posix ? "-" : 0;
+ new_fmt->inapp = posix ? "-" : 0;
+ new_fmt->error = "?";
*fmt = new_fmt;
@@ -323,7 +328,7 @@ ps_fmt_creation_error (char *src, int posix, struct ps_fmt_specs *fmt_specs,
}
/* Free FMT, and any resources it consumes. */
-void
+void
ps_fmt_free (struct ps_fmt *fmt)
{
FREE (fmt->src);
@@ -358,14 +363,15 @@ ps_fmt_clone (struct ps_fmt *fmt, struct ps_fmt **copy)
new->num_fields = fmt->num_fields;
new->src = src;
new->src_len = fmt->src_len;
- new->inval = fmt->inval;
+ new->inapp = fmt->inapp;
+ new->error = fmt->error;
*copy = new;
return 0;
}
-/* Write an appropiate header line for FMT, containing the titles of all its
- fields appropiately aligned with where the values would be printed, to
+/* Write an appropriate header line for FMT, containing the titles of all its
+ fields appropriately aligned with where the values would be printed, to
STREAM (without a trailing newline). If count is non-NULL, the total
number number of characters output is added to the integer it points to.
If any fatal error occurs, the error code is returned, otherwise 0. */
@@ -418,7 +424,8 @@ ps_fmt_write_proc_stat (struct ps_fmt *fmt, struct proc_stat *ps, struct ps_stre
error_t err = 0;
struct ps_fmt_field *field = ps_fmt_fields (fmt);
int nfields = ps_fmt_num_fields (fmt);
- int have = proc_stat_flags (ps);
+ ps_flags_t have = ps->flags;
+ ps_flags_t inapp = ps->inapp;
while (nfields-- > 0 && !err)
{
@@ -431,16 +438,20 @@ ps_fmt_write_proc_stat (struct ps_fmt *fmt, struct proc_stat *ps, struct ps_stre
if (spec != NULL && !err)
{
- int need = ps_getter_needs (ps_fmt_spec_getter (spec));
+ ps_flags_t need = ps_getter_needs (ps_fmt_spec_getter (spec));
/* do we have the resources to print this field? */
if ((need & have) == need)
/* Yup */
err = (*spec->output_fn) (ps, field, stream);
+ else if (need & ~have & inapp)
+ /* This field is inappropriate for PS. */
+ err =
+ ps_stream_write_field (stream, fmt->inapp ?: "", field->width);
else
- /* Something to display in invalid fields. */
- err = ps_stream_write_field (stream, fmt->inval ?: "",
- ps_fmt_field_width (field));
+ /* This field is appropriate, but couldn't be fetched. */
+ err =
+ ps_stream_write_field (stream, fmt->error ?: "", field->width);
}
field++;
@@ -450,9 +461,9 @@ ps_fmt_write_proc_stat (struct ps_fmt *fmt, struct proc_stat *ps, struct ps_stre
}
/* Remove those fields from FMT for which the function FN, when called on the
- field, returns true. Appropiate inter-field characters are also removed:
+ field, returns true. Appropriate inter-field characters are also removed:
those *following* deleted fields at the beginning of the fmt, and those
- *preceeding* deleted fields *not* at the beginning. */
+ *preceding* deleted fields *not* at the beginning. */
void
ps_fmt_squash (struct ps_fmt *fmt, int (*fn)(struct ps_fmt_field *field))
{
@@ -468,7 +479,7 @@ ps_fmt_squash (struct ps_fmt *fmt, int (*fn)(struct ps_fmt_field *field))
{
/* Save the old prefix, in case we're deleting the first field,
and need to prepend it to the next field. */
- const char *beg_pfx = field->pfx;
+ const char *beg_pfx = field->pfx;
int beg_pfx_len = field->pfx_len;
nfields--;
@@ -519,7 +530,8 @@ ps_fmt_squash (struct ps_fmt *fmt, int (*fn)(struct ps_fmt_field *field))
else
/* don't squash this field, just move to the next one */
{
- need |= ps_getter_needs (ps_fmt_spec_getter (field->spec));
+ if (field->spec)
+ need |= ps_getter_needs (field->spec->getter);
field++;
}
@@ -528,8 +540,8 @@ ps_fmt_squash (struct ps_fmt *fmt, int (*fn)(struct ps_fmt_field *field))
}
/* Remove those fields from FMT which would need the proc_stat flags FLAGS.
- Appropiate inter-field characters are also removed: those *following*
- deleted fields at the beginning of the fmt, and those *preceeding* deleted
+ Appropriate inter-field characters are also removed: those *following*
+ deleted fields at the beginning of the fmt, and those *preceding* deleted
fields *not* at the beginning. */
void
ps_fmt_squash_flags (struct ps_fmt *fmt, ps_flags_t flags)
diff --git a/libps/host.c b/libps/host.c
index 26be9a31..9a46e008 100644
--- a/libps/host.c
+++ b/libps/host.c
@@ -1,8 +1,8 @@
/* Routines to get global host info.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,2001,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -29,78 +29,80 @@
/* ---------------------------------------------------------------- */
/*
- The Basic & Sched info types are pretty static, so we cache them, but load
- info is dynamic so we don't cache that.
+ The Basic & Sched info types are pretty must static so we cache them.
+ However, as load info is dynamic, we do not cache it.
See <mach/host_info.h> for information on the data types these routines
return.
*/
/* Return the current host port. */
-host_t
+mach_port_t
ps_get_host ()
{
- static host_t host = MACH_PORT_NULL;
+ static mach_port_t host = MACH_PORT_NULL;
if (host == MACH_PORT_NULL)
host = mach_host_self ();
return host;
}
-/* Return a pointer to basic info about the current host in INFO. Since
- this is static global information we just use a static buffer. If a
- system error occurs, the error code is returned, otherwise 0. */
+/* Return a pointer to the basic info about the current host in INFO.
+ Since this is static global information, we just use a static buffer.
+ If a system error occurs, the error code is returned, otherwise 0 is
+ returned. */
error_t
ps_host_basic_info (host_basic_info_t *info)
{
- int initialized = FALSE;
+ static int initialized;
static host_basic_info_data_t buf;
if (!initialized)
{
- int size = sizeof (buf);
- error_t err = host_info (ps_get_host (), HOST_BASIC_INFO,
+ size_t size = sizeof (buf);
+ error_t err = host_info (ps_get_host (), HOST_BASIC_INFO,
(host_info_t) &buf, &size);
if (err)
return err;
- initialized = TRUE;
+ initialized = 1;
}
*info = &buf;
return 0;
}
-/* Return a pointer to scheduling info about the current host in INFO.
- Since this is static global information we just use a static buffer. If a
- system error occurs, the error code is returned, otherwise 0. */
+/* Return a pointer to the scheduling info about the current host in INFO.
+ Since this is static global information, we just use a static buffer.
+ If a system error occurs, the error code is returned, otherwise 0 is
+ returned. */
error_t
ps_host_sched_info (host_sched_info_t *info)
{
- int initialized = FALSE;
+ static int initialized;
static host_sched_info_data_t buf;
if (!initialized)
{
- int size = sizeof (buf);
- error_t err = host_info (ps_get_host (), HOST_SCHED_INFO,
+ size_t size = sizeof (buf);
+ error_t err = host_info (ps_get_host (), HOST_SCHED_INFO,
(host_info_t) &buf, &size);
if (err)
return err;
- initialized = TRUE;
+ initialized = 1;
}
*info = &buf;
return 0;
}
-/* Return a pointer to load info about the current host in INFO. Since
- this is global information we just use a static buffer (if someone desires
- to keep old load info, they should copy the buffer we return a pointer
- to). If a system error occurs, the error code is returned, otherwise 0. */
+/* Return a pointer to the load info about the current host in INFO. Since
+ this is global information, we just use a static buffer (if someone desires
+ to keep old load info, they should copy the returned buffer). If a system
+ error occurs, the error code is returned, otherwise 0 is returned. */
error_t
ps_host_load_info (host_load_info_t *info)
{
static host_load_info_data_t buf;
- int size = sizeof (buf);
+ size_t size = sizeof (buf);
error_t err = host_info (ps_get_host (), HOST_LOAD_INFO,
(host_info_t) &buf, &size);
diff --git a/libps/proclist.c b/libps/proclist.c
index 2dfcfe7d..9a4d6ed5 100644
--- a/libps/proclist.c
+++ b/libps/proclist.c
@@ -1,6 +1,6 @@
/* The type proc_stat_list_t, which holds lists of proc_stats.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,2002 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -46,7 +46,7 @@ proc_stat_list_create (struct ps_context *context, struct proc_stat_list **pp)
}
/* Free PP, and any resources it consumes. */
-void
+void
proc_stat_list_free (struct proc_stat_list *pp)
{
proc_stat_list_remove_threads (pp);
@@ -267,12 +267,12 @@ static error_t
proc_stat_list_add_fn_pids (struct proc_stat_list *pp,
kern_return_t (*fetch_fn)(process_t proc,
pid_t **pids,
- unsigned *num_pids),
- struct proc_stat ***proc_stats, unsigned *num_procs)
+ size_t *num_pids),
+ struct proc_stat ***proc_stats, size_t *num_procs)
{
error_t err;
pid_t pid_array[STATICPIDS], *pids = pid_array;
- unsigned num_pids = STATICPIDS;
+ size_t num_pids = STATICPIDS;
err = (*fetch_fn)(ps_context_server (pp->context), &pids, &num_pids);
if (err)
@@ -298,10 +298,11 @@ proc_stat_list_add_id_fn_pids (struct proc_stat_list *pp, unsigned id,
kern_return_t (*fetch_fn)(process_t proc,
pid_t id,
pid_t **pids,
- unsigned *num_pids),
- struct proc_stat ***proc_stats, unsigned *num_procs)
+ size_t *num_pids),
+ struct proc_stat ***proc_stats,
+ size_t *num_procs)
{
- error_t id_fetch_fn (process_t proc, pid_t **pids, unsigned *num_pids)
+ error_t id_fetch_fn (process_t proc, pid_t **pids, size_t *num_pids)
{
return (*fetch_fn)(proc, id, pids, num_pids);
}
@@ -316,7 +317,7 @@ proc_stat_list_add_id_fn_pids (struct proc_stat_list *pp, unsigned id,
returned in them. */
error_t
proc_stat_list_add_all (struct proc_stat_list *pp,
- struct proc_stat ***proc_stats, unsigned *num_procs)
+ struct proc_stat ***proc_stats, size_t *num_procs)
{
return
proc_stat_list_add_fn_pids (pp, proc_getallpids, proc_stats, num_procs);
@@ -328,7 +329,8 @@ proc_stat_list_add_all (struct proc_stat_list *pp,
of the resulting entries is returned in them. */
error_t
proc_stat_list_add_login_coll (struct proc_stat_list *pp, pid_t login_id,
- struct proc_stat ***proc_stats, unsigned *num_procs)
+ struct proc_stat ***proc_stats,
+ size_t *num_procs)
{
return
proc_stat_list_add_id_fn_pids (pp, login_id, proc_getloginpids,
@@ -341,7 +343,8 @@ proc_stat_list_add_login_coll (struct proc_stat_list *pp, pid_t login_id,
resulting entries is returned in them. */
error_t
proc_stat_list_add_session (struct proc_stat_list *pp, pid_t session_id,
- struct proc_stat ***proc_stats, unsigned *num_procs)
+ struct proc_stat ***proc_stats,
+ size_t *num_procs)
{
return
proc_stat_list_add_id_fn_pids (pp, session_id, proc_getsessionpids,
@@ -354,7 +357,7 @@ proc_stat_list_add_session (struct proc_stat_list *pp, pid_t session_id,
resulting entries is returned in them. */
error_t
proc_stat_list_add_pgrp (struct proc_stat_list *pp, pid_t pgrp,
- struct proc_stat ***proc_stats, unsigned *num_procs)
+ struct proc_stat ***proc_stats, size_t *num_procs)
{
return
proc_stat_list_add_id_fn_pids (pp, pgrp, proc_getpgrppids,
diff --git a/libps/procstat.c b/libps/procstat.c
index 0938073e..ba923780 100644
--- a/libps/procstat.c
+++ b/libps/procstat.c
@@ -1,8 +1,7 @@
/* The proc_stat type, which holds information about a hurd process.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -43,7 +42,7 @@ typedef threadinfo_data_t *threadinfo_t;
/* Return the PSTAT_STATE_ bits describing the state of an individual thread,
from that thread's thread_basic_info_t struct */
-static int
+static int
thread_state (thread_basic_info_t bi)
{
int state = 0;
@@ -79,19 +78,26 @@ thread_state (thread_basic_info_t bi)
/* ---------------------------------------------------------------- */
-/* The set of PSTAT_ flags that we get using proc_getprocinfo. */
-#define PSTAT_PROCINFO \
- (PSTAT_PROC_INFO | PSTAT_TASK_BASIC | PSTAT_NUM_THREADS \
- | PSTAT_THREAD_BASIC | PSTAT_THREAD_SCHED | PSTAT_THREAD_WAIT \
- | PSTAT_THREAD_WAITS)
-/* The set of things we get from procinfo that's thread dependent. */
+/* The set of things we get from procinfo that are per-thread. */
#define PSTAT_PROCINFO_THREAD \
- (PSTAT_NUM_THREADS |PSTAT_THREAD_BASIC |PSTAT_THREAD_SCHED \
- | PSTAT_THREAD_WAIT | PSTAT_THREAD_WAITS)
+ (PSTAT_THREAD_BASIC | PSTAT_THREAD_SCHED | PSTAT_THREAD_WAIT)
+
+/* The set of things we get from procinfo that are per-task, and thread dependent. */
+#define PSTAT_PROCINFO_TASK_THREAD_DEP \
+ (PSTAT_PROCINFO_THREAD | PSTAT_NUM_THREADS | PSTAT_THREAD_WAITS)
+
+/* The set of things we get from procinfo that are per-task (note that this
+ includes thread fields, because tasks use them for thread summaries). */
+#define PSTAT_PROCINFO_TASK \
+ (PSTAT_PROCINFO_TASK_THREAD_DEP | PSTAT_PROC_INFO \
+ | PSTAT_TASK_BASIC | PSTAT_TASK_EVENTS)
+
+/* The set of PSTAT_ flags that we get using proc_getprocinfo. */
+#define PSTAT_PROCINFO PSTAT_PROCINFO_TASK
/* The set of things in PSTAT_PROCINFO that we will not attempt to refetch on
subsequent getprocinfo calls. */
-#define PSTAT_PROCINFO_MERGE PSTAT_TASK_BASIC
+#define PSTAT_PROCINFO_MERGE (PSTAT_TASK_BASIC | PSTAT_TASK_EVENTS)
#define PSTAT_PROCINFO_REFETCH (PSTAT_PROCINFO - PSTAT_PROCINFO_MERGE)
/* Fetches process information from the set in PSTAT_PROCINFO, returning it
@@ -103,18 +109,22 @@ fetch_procinfo (process_t server, pid_t pid,
struct procinfo **pi, size_t *pi_size,
char **waits, size_t *waits_len)
{
+ static const struct { ps_flags_t ps_flag; int pi_flags; } map[] =
+ {
+ { PSTAT_TASK_BASIC, PI_FETCH_TASKINFO },
+ { PSTAT_TASK_EVENTS, PI_FETCH_TASKEVENTS },
+ { PSTAT_NUM_THREADS, PI_FETCH_THREADS },
+ { PSTAT_THREAD_BASIC, PI_FETCH_THREAD_BASIC | PI_FETCH_THREADS },
+ { PSTAT_THREAD_SCHED, PI_FETCH_THREAD_SCHED | PI_FETCH_THREADS },
+ { PSTAT_THREAD_WAITS, PI_FETCH_THREAD_WAITS | PI_FETCH_THREADS },
+ { 0, }
+ };
int pi_flags = 0;
+ int i;
- if ((need & PSTAT_TASK_BASIC) && !(*have & PSTAT_TASK_BASIC))
- pi_flags |= PI_FETCH_TASKINFO;
- if ((need & PSTAT_NUM_THREADS) && !(*have & PSTAT_NUM_THREADS))
- pi_flags |= PI_FETCH_THREADS;
- if ((need & PSTAT_THREAD_BASIC) && !(*have & PSTAT_THREAD_BASIC))
- pi_flags |= PI_FETCH_THREAD_BASIC | PI_FETCH_THREADS;
- if ((need & PSTAT_THREAD_SCHED) && !(*have & PSTAT_THREAD_SCHED))
- pi_flags |= PI_FETCH_THREAD_SCHED | PI_FETCH_THREADS;
- if ((need & PSTAT_THREAD_WAITS) && !(*have & PSTAT_THREAD_WAITS))
- pi_flags |= PI_FETCH_THREAD_WAITS | PI_FETCH_THREADS;
+ for (i = 0; map[i].ps_flag; i++)
+ if ((need & map[i].ps_flag) && !(*have & map[i].ps_flag))
+ pi_flags |= map[i].pi_flags;
if (pi_flags || ((need & PSTAT_PROC_INFO) && !(*have & PSTAT_PROC_INFO)))
{
@@ -129,16 +139,9 @@ fetch_procinfo (process_t server, pid_t pid,
/* Update *HAVE to reflect what we've successfully fetched. */
{
*have |= PSTAT_PROC_INFO;
- if (pi_flags & PI_FETCH_TASKINFO)
- *have |= PSTAT_TASK_BASIC;
- if (pi_flags & PI_FETCH_THREADS)
- *have |= PSTAT_NUM_THREADS;
- if (pi_flags & PI_FETCH_THREAD_BASIC)
- *have |= PSTAT_THREAD_BASIC;
- if (pi_flags & PI_FETCH_THREAD_SCHED)
- *have |= PSTAT_THREAD_SCHED;
- if (pi_flags & PI_FETCH_THREAD_WAITS)
- *have |= PSTAT_THREAD_WAITS;
+ for (i = 0; map[i].ps_flag; i++)
+ if ((pi_flags & map[i].pi_flags) == map[i].pi_flags)
+ *have |= map[i].ps_flag;
}
return err;
}
@@ -150,7 +153,7 @@ fetch_procinfo (process_t server, pid_t pid,
vm_alloced memory for the procinfo structure returned by getprocinfo.
Here we just give enough for four threads. */
#define PROCINFO_MALLOC_SIZE \
- (sizeof (struct procinfo) + 4 * sizeof (threadinfo_data_t))
+ (sizeof (struct procinfo) + 4 * sizeof (threadinfo_data_t))
#define WAITS_MALLOC_SIZE 128
@@ -229,8 +232,7 @@ merge_procinfo (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
/* We got new memory vm_alloced by the getprocinfo, discard the old. */
{
if (ps->proc_info_vm_alloced)
- vm_deallocate (mach_task_self (),
- (vm_address_t)ps->proc_info, ps->proc_info_size);
+ munmap (ps->proc_info, ps->proc_info_size);
else
free (ps->proc_info);
ps->proc_info = new_pi;
@@ -248,8 +250,7 @@ merge_procinfo (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
/* We got new memory vm_alloced by the getprocinfo, discard the old. */
{
if (ps->thread_waits_vm_alloced)
- vm_deallocate (mach_task_self (),
- (vm_address_t)ps->thread_waits, ps->thread_waits_len);
+ munmap (ps->thread_waits, ps->thread_waits_len);
else
free (ps->thread_waits);
ps->thread_waits = new_waits;
@@ -266,7 +267,7 @@ merge_procinfo (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
/* Returns FLAGS augmented with any other flags that are necessary
preconditions to setting them. */
-static ps_flags_t
+static ps_flags_t
add_preconditions (ps_flags_t flags, struct ps_context *context)
{
/* Implement any inter-flag dependencies: if the new flags in FLAGS depend on
@@ -287,7 +288,7 @@ add_preconditions (ps_flags_t flags, struct ps_context *context)
flags |= PSTAT_PROC_INFO;
if (flags & PSTAT_SUSPEND_COUNT)
/* We just request the resources require for both the thread and task
- versions, as the extraneous info won't be possible to aquire anyway. */
+ versions, as the extraneous info won't be possible to acquire anyway. */
flags |= PSTAT_TASK_BASIC | PSTAT_THREAD_BASIC;
if (flags & (PSTAT_CTTYID | PSTAT_CWDIR | PSTAT_AUTH | PSTAT_UMASK)
&& !(flags & PSTAT_NO_MSGPORT))
@@ -295,8 +296,6 @@ add_preconditions (ps_flags_t flags, struct ps_context *context)
flags |= PSTAT_MSGPORT;
flags |= PSTAT_TASK; /* for authentication */
}
- if (flags & PSTAT_TASK_EVENTS)
- flags |= PSTAT_TASK;
return flags;
}
@@ -359,7 +358,8 @@ summarize_thread_basic_info (struct procinfo *pi)
bzero (tbi, sizeof *tbi);
for (i = 0; i < pi->nthreads; i++)
- if (! pi->threadinfos[i].died)
+ if (! pi->threadinfos[i].died
+ && ! (pi->threadinfos[i].pis_bi.flags & TH_FLAGS_IDLE))
{
thread_basic_info_t bi = &pi->threadinfos[i].pis_bi;
int thread_run_state = bi->run_state;
@@ -446,7 +446,8 @@ summarize_thread_sched_info (struct procinfo *pi)
bzero (tsi, sizeof *tsi);
for (i = 0; i < pi->nthreads; i++)
- if (! pi->threadinfos[i].died)
+ if (! pi->threadinfos[i].died
+ && ! (pi->threadinfos[i].pis_bi.flags & TH_FLAGS_IDLE))
{
thread_sched_info_t si = &pi->threadinfos[i].pis_si;
tsi->base_priority += si->base_priority;
@@ -476,7 +477,8 @@ summarize_thread_states (struct procinfo *pi)
/* The union of all thread state bits... */
for (i = 0; i < pi->nthreads; i++)
- if (! pi->threadinfos[i].died)
+ if (! pi->threadinfos[i].died
+ && ! (pi->threadinfos[i].pis_bi.flags & TH_FLAGS_IDLE))
state |= thread_state (&pi->threadinfos[i].pis_bi);
return state;
@@ -485,7 +487,7 @@ summarize_thread_states (struct procinfo *pi)
/* Returns what's blocking the first blocked thread in PI in WAIT and RPC. */
static void
summarize_thread_waits (struct procinfo *pi, char *waits, size_t waits_len,
- char **wait, int *rpc)
+ char **wait, mach_msg_id_t *rpc)
{
int i;
char *next_wait = waits;
@@ -495,38 +497,42 @@ summarize_thread_waits (struct procinfo *pi, char *waits, size_t waits_len,
for (i = 0; i < pi->nthreads; i++)
if (! pi->threadinfos[i].died)
- if (next_wait > waits + waits_len)
- break;
- else
- {
- int left = waits + waits_len - next_wait;
-
- if (strncmp (next_wait, "msgport", left) == 0
- || strncmp (next_wait, "itimer", left) == 0)
- ; /* libc internal threads; ignore. */
- else if (*wait)
- /* There are multiple user threads. Punt. */
- {
- *wait = "*";
- *rpc = 0;
- break;
- }
- else
- {
- *wait = next_wait;
- *rpc = pi->threadinfos[i].rpc_block;
- }
-
- /* Advance NEXT_WAIT to the next wait string. */
- next_wait += strnlen (next_wait, left) + 1;
- }
+ {
+ if (next_wait > waits + waits_len)
+ break;
+ else
+ {
+ int left = waits + waits_len - next_wait;
+
+ if (pi->threadinfos[i].pis_bi.flags & TH_FLAGS_IDLE)
+ ; /* kernel idle thread; ignore */
+ else if (strncmp (next_wait, "msgport", left) == 0
+ || strncmp (next_wait, "itimer", left) == 0)
+ ; /* libc internal threads; ignore. */
+ else if (*wait)
+ /* There are multiple user threads. Punt. */
+ {
+ *wait = "*";
+ *rpc = 0;
+ break;
+ }
+ else
+ {
+ *wait = next_wait;
+ *rpc = pi->threadinfos[i].rpc_block;
+ }
+
+ /* Advance NEXT_WAIT to the next wait string. */
+ next_wait += strnlen (next_wait, left) + 1;
+ }
+ }
}
/* Returns the number of threads in PI that aren't marked dead. */
static unsigned
count_threads (struct procinfo *pi, ps_flags_t have)
{
- if (have & (PSTAT_PROCINFO_THREAD & ~PSTAT_NUM_THREADS))
+ if (have & (PSTAT_PROCINFO_TASK_THREAD_DEP & ~PSTAT_NUM_THREADS))
/* If we have thread info besides the number of threads, then the
threadinfos structures in PI are valid (we use the died bit). */
{
@@ -683,20 +689,19 @@ set_procinfo_flags (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
/* Now copy out the information for this particular thread from the
ORIGIN's list of thread information. */
- if ((need & PSTAT_THREAD_BASIC) && ! (have & PSTAT_THREAD_BASIC)
- && (oflags & PSTAT_THREAD_BASIC)
+ need &= ~have;
+
+ if ((need & PSTAT_THREAD_BASIC) && (oflags & PSTAT_THREAD_BASIC)
&& (ps->thread_basic_info =
clone (&ti->pis_bi, sizeof (struct thread_basic_info))))
have |= PSTAT_THREAD_BASIC;
- if ((need & PSTAT_THREAD_SCHED) && ! (have & PSTAT_THREAD_SCHED)
- && (oflags & PSTAT_THREAD_SCHED)
+ if ((need & PSTAT_THREAD_SCHED) && (oflags & PSTAT_THREAD_SCHED)
&& (ps->thread_sched_info =
clone (&ti->pis_si, sizeof (struct thread_sched_info))))
have |= PSTAT_THREAD_SCHED;
- if ((need & PSTAT_THREAD_WAIT) && ! (have & PSTAT_THREAD_WAIT)
- && (oflags & PSTAT_THREAD_WAITS))
+ if ((need & PSTAT_THREAD_WAIT) && (oflags & PSTAT_THREAD_WAITS))
{
ps->thread_wait =
get_thread_wait (origin->thread_waits,
@@ -709,6 +714,11 @@ set_procinfo_flags (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
}
}
}
+
+ /* Mark things that don't apply to threads (note that we don't do the
+ analogous thing for tasks above, as tasks do have thread fields
+ containing summary information for all their threads). */
+ ps->inapp |= need & ~have & PSTAT_PROCINFO & ~PSTAT_PROCINFO_THREAD;
}
return have;
@@ -762,23 +772,45 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags)
need = flags & ~have & ~ps->failed;
+ /* Returns true if (1) FLAGS is in NEED, and (2) the appropriate
+ preconditions PRECOND are available; if only (1) is true, FLAG is added
+ to the INAPP set if appropriate (to distinguish it from an error), and
+ returns false. */
+#define NEED(flag, precond) \
+ ({ \
+ ps_flags_t __flag = (flag), _precond = (precond); \
+ int val; \
+ if (! (__flag & need)) \
+ val = 0; \
+ else if ((_precond & have) == _precond) \
+ val = 1; \
+ else \
+ { \
+ val = 0; \
+ if (_precond & ps->inapp) \
+ ps->inapp |= __flag; \
+ } \
+ val; \
+ })
+
/* MGET: If we're trying to set FLAG, and the preconditions PRECOND are set
in the flags already, then eval CALL and set ERR to the result.
If the resulting ERR is 0 add FLAG to the set of valid flags. ERR is
returned. */
-#define MGET(_flag, _precond, call) \
- ({ ps_flags_t flag = (_flag), precond = (_precond); \
- error_t err; \
- if (!(need & (flag)) || (have & (precond)) != (precond)) \
- err = 0; \
- else \
- { \
- err = (call); \
- if (!err) \
- have |= flag; \
- } \
- err; \
- })
+#define MGET(flag, precond, call) \
+ ({ \
+ error_t err; \
+ ps_flags_t _flag = (flag); \
+ if (NEED (_flag, precond)) \
+ { \
+ err = (call); \
+ if (!err) \
+ have |= _flag; \
+ } \
+ else \
+ err = 0; \
+ err; \
+ })
/* A version of MGET specifically for the msg port, that turns off the msg
port if a call to it times out. It also implies a precondition of
@@ -795,11 +827,8 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags)
later. */
have = set_procinfo_flags (ps, need & ~have & test_msgport_flags, have);
- if ((need & PSTAT_SUSPEND_COUNT)
- &&
- ((have & PSTAT_PID)
- ? (have & PSTAT_TASK_BASIC)
- : (have & PSTAT_THREAD_BASIC)))
+ if (NEED (PSTAT_SUSPEND_COUNT,
+ ((have & PSTAT_PID) ? PSTAT_TASK_BASIC : PSTAT_THREAD_BASIC)))
{
if (have & PSTAT_PID)
ps->suspend_count = ps->task_basic_info->suspend_count;
@@ -823,31 +852,21 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags)
/* The process's task port. */
MGET(PSTAT_TASK, PSTAT_PID, proc_pid2task (server, ps->pid, &ps->task));
- /* VM statistics for the task. See <mach/task_info.h>. */
- if ((need & PSTAT_TASK_EVENTS) && (have & PSTAT_TASK))
- {
- ps->task_events_info = &ps->task_events_info_buf;
- ps->task_events_info_size = TASK_EVENTS_INFO_COUNT;
- if (task_info (ps->task, TASK_EVENTS_INFO,
- (task_info_t)ps->task_events_info,
- &ps->task_events_info_size)
- == 0)
- have |= PSTAT_TASK_EVENTS;
- }
-
/* PSTAT_STATE_ bits for the process and all its threads. */
if ((need & PSTAT_STATE) && (have & (PSTAT_PROC_INFO | PSTAT_THREAD_BASIC)))
{
ps->state = 0;
if (have & PSTAT_THREAD_BASIC)
- /* Thread states. */
- if (have & PSTAT_THREAD)
- ps->state |= thread_state (ps->thread_basic_info);
- else
- /* For a process, we use the thread list instead of
- PS->thread_basic_info because it contains more information. */
- ps->state |= summarize_thread_states (ps->proc_info);
+ {
+ /* Thread states. */
+ if (have & PSTAT_THREAD)
+ ps->state |= thread_state (ps->thread_basic_info);
+ else
+ /* For a process, we use the thread list instead of
+ PS->thread_basic_info because it contains more information. */
+ ps->state |= summarize_thread_states (ps->proc_info);
+ }
if (have & PSTAT_PROC_INFO)
/* Process state. */
@@ -881,21 +900,43 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags)
}
/* The process's exec arguments */
- if ((need & PSTAT_ARGS) && (have & PSTAT_PID))
+ if (NEED (PSTAT_ARGS, PSTAT_PID))
{
char *buf = malloc (100);
ps->args_len = 100;
ps->args = buf;
if (ps->args)
- if (proc_getprocargs (server, ps->pid, &ps->args, &ps->args_len))
- free (buf);
- else
- {
- have |= PSTAT_ARGS;
- ps->args_vm_alloced = (ps->args != buf);
- if (ps->args_vm_alloced)
- free (buf);
- }
+ {
+ if (proc_getprocargs (server, ps->pid, &ps->args, &ps->args_len))
+ free (buf);
+ else
+ {
+ have |= PSTAT_ARGS;
+ ps->args_vm_alloced = (ps->args != buf);
+ if (ps->args_vm_alloced)
+ free (buf);
+ }
+ }
+ }
+
+ /* The process's exec environment */
+ if (NEED (PSTAT_ENV, PSTAT_PID))
+ {
+ char *buf = malloc (100);
+ ps->env_len = 100;
+ ps->env = buf;
+ if (ps->env)
+ {
+ if (proc_getprocenv (server, ps->pid, &ps->env, &ps->env_len))
+ free (buf);
+ else
+ {
+ have |= PSTAT_ENV;
+ ps->env_vm_alloced = (ps->env != buf);
+ if (ps->env_vm_alloced)
+ free (buf);
+ }
+ }
}
/* The ctty id port; note that this is just a magic cookie;
@@ -920,9 +961,9 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags)
when creating a file. */
MP_MGET (PSTAT_UMASK, PSTAT_TASK,
ps_msg_get_init_int (ps->msgport, ps->task, INIT_UMASK,
- &ps->umask));
+ (int *) &ps->umask));
- if ((need & PSTAT_OWNER_UID) && (have & PSTAT_PROC_INFO))
+ if (NEED (PSTAT_OWNER_UID, PSTAT_PROC_INFO))
{
if (ps->proc_info->state & PI_NOTOWNED)
ps->owner_uid = -1;
@@ -932,34 +973,43 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags)
}
/* A ps_user object for the process's owner. */
- if ((need & PSTAT_OWNER) && (have & PSTAT_OWNER_UID))
- if (ps->owner_uid < 0)
- {
- ps->owner = 0;
+ if (NEED (PSTAT_OWNER, PSTAT_OWNER_UID))
+ {
+ if (ps->owner_uid < 0)
+ {
+ ps->owner = 0;
+ have |= PSTAT_OWNER;
+ }
+ else if (! ps_context_find_user (ps->context, ps->owner_uid, &ps->owner))
have |= PSTAT_OWNER;
- }
- else if (! ps_context_find_user (ps->context, ps->owner_uid, &ps->owner))
- have |= PSTAT_OWNER;
+ }
/* A ps_tty for the process's controlling terminal, or NULL if it
doesn't have one. */
- if ((need & PSTAT_TTY) && (have & PSTAT_CTTYID))
+ if (NEED (PSTAT_TTY, PSTAT_CTTYID))
if (ps_context_find_tty_by_cttyid (ps->context, ps->cttyid, &ps->tty) == 0)
have |= PSTAT_TTY;
+ /* The number of Mach ports in the task. */
+ MGET (PSTAT_NUM_PORTS, PSTAT_PID,
+ proc_getnports (server, ps->pid, &ps->num_ports));
+
/* Update PS's flag state. We haven't tried user flags yet, so don't mark
them as having failed. We do this before checking user bits so that the
user fetch hook sees PS in a consistent state. */
ps->failed |= (need & ~PSTAT_USER_MASK) & ~have;
ps->flags = have;
- need &= PSTAT_USER_MASK; /* Only consider user bits now. */
+ need &= ~have;
if (need && ps->context->user_hooks && ps->context->user_hooks->fetch)
/* There is some user state we need to fetch. */
{
have |= (*ps->context->user_hooks->fetch) (ps, need, have);
- /* Update the flag state again having tried the user bits. */
- ps->failed |= need & ~have;
+ /* Update the flag state again having tried the user bits. We allow
+ the user hook to turn on non-user bits, in which case we remove them
+ from the failed set; the user hook may know some way of getting the
+ info that we don't. */
+ ps->failed = (ps->failed | need) & ~have;
ps->flags = have;
}
@@ -968,7 +1018,7 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags)
/* ---------------------------------------------------------------- */
/* Discard PS and any resources it holds. */
-void
+void
_proc_stat_free (ps)
struct proc_stat *ps;
{
@@ -982,7 +1032,7 @@ _proc_stat_free (ps)
? mach_port_deallocate(mach_task_self (), (ps->port)) : 0)
/* If FLAG is set in PS's flags, then if VM_ALLOCED is zero, free the malloced
- field MEM in PS; othrewise, vm_deallocate MEM, consisting of SIZE
+ field MEM in PS; othrewise, vm_deallocate MEM, consisting of SIZE
elements of type ELTYPE, *unless* MEM == SBUF, which usually means
that MEM points to a static buffer somewhere instead of vm_alloc'd
memory. */
@@ -999,13 +1049,16 @@ _proc_stat_free (ps)
MFREEPORT (PSTAT_AUTH, auth);
/* free any allocated memory pointed to by PS */
- MFREEMEM (PSTAT_PROCINFO, proc_info, ps->proc_info_size,
+ MFREEMEM (PSTAT_PROC_INFO, proc_info, ps->proc_info_size,
ps->proc_info_vm_alloced, 0, char);
MFREEMEM (PSTAT_THREAD_BASIC, thread_basic_info, 0, 0, 0, 0);
MFREEMEM (PSTAT_THREAD_SCHED, thread_sched_info, 0, 0, 0, 0);
MFREEMEM (PSTAT_ARGS, args, ps->args_len, ps->args_vm_alloced, 0, char);
+ MFREEMEM (PSTAT_ENV, env, ps->env_len, ps->env_vm_alloced, 0, char);
MFREEMEM (PSTAT_TASK_EVENTS, task_events_info, ps->task_events_info_size,
0, &ps->task_events_info_buf, char);
+ MFREEMEM (PSTAT_THREAD_WAITS, thread_waits, ps->thread_waits_len,
+ ps->thread_waits_vm_alloced, 0, char);
FREE (ps);
}
@@ -1023,6 +1076,7 @@ _proc_stat_create (pid_t pid, struct ps_context *context, struct proc_stat **ps)
(*ps)->pid = pid;
(*ps)->flags = PSTAT_PID;
(*ps)->failed = 0;
+ (*ps)->inapp = PSTAT_THREAD;
(*ps)->context = context;
(*ps)->hook = 0;
@@ -1036,7 +1090,7 @@ _proc_stat_create (pid_t pid, struct ps_context *context, struct proc_stat **ps)
resulting proc_stat isn't fully functional -- most flags can't be set in
it. It also contains a pointer to PS, so PS shouldn't be freed without
also freeing THREAD_PS. If N was out of range, EINVAL is returned. If a
- memory allocation error occured, ENOMEM is returned. Otherwise, 0 is
+ memory allocation error occurred, ENOMEM is returned. Otherwise, 0 is
returned. */
error_t
proc_stat_thread_create (struct proc_stat *ps, unsigned index, struct proc_stat **thread_ps)
@@ -1057,6 +1111,8 @@ proc_stat_thread_create (struct proc_stat *ps, unsigned index, struct proc_stat
/* A value of -1 for the PID indicates that this is a thread. */
tps->pid = -1;
tps->flags = PSTAT_THREAD;
+ tps->failed = 0;
+ tps->inapp = PSTAT_PID;
tps->thread_origin = ps;
tps->thread_index = index;
diff --git a/libps/ps.h b/libps/ps.h
index 7ae8acb8..91fdc70b 100644
--- a/libps/ps.h
+++ b/libps/ps.h
@@ -1,8 +1,8 @@
/* Routines to gather and print process information.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,99,2001,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -40,8 +40,8 @@ struct ps_user
uid_t uid;
/* The status */
- enum ps_user_passwd_state passwd_state;
-
+ enum ps_user_passwd_state passwd_state;
+
/* The user's password file entry. Only valid if PASSWD_STATE ==
PS_USER_PASSWD_OK. */
struct passwd passwd;
@@ -85,7 +85,7 @@ enum ps_tty_name_state
struct ps_tty {
/* Which tty this refers to. */
file_t port;
-
+
/* The name of the tty, if we could figure it out. */
const char *name;
/* What state the name is in. */
@@ -125,17 +125,17 @@ struct ps_context
process_t server;
/* proc_stats for every process we know about, indexed by process id. */
- ihash_t procs;
+ struct hurd_ihash procs;
/* ps_ttys for every tty we know about, indexed by the terminal port. */
- ihash_t ttys;
+ struct hurd_ihash ttys;
/* ps_ttys for every tty we know about, indexed by their ctty id port
(from libc). */
- ihash_t ttys_by_cttyid;
+ struct hurd_ihash ttys_by_cttyid;
/* A ps_user for every user we know about, indexed by user-id. */
- ihash_t users;
+ struct hurd_ihash users;
/* Functions that can be set to extend the behavior of proc_stats. */
struct ps_user_hooks *user_hooks;
@@ -178,121 +178,134 @@ typedef unsigned ps_flags_t;
typedef unsigned ps_state_t;
struct proc_stat
- {
- /* Which process server this is from. */
- struct ps_context *context;
-
- /* The proc's process id; if <0 then this is a thread, not a process. */
- pid_t pid;
-
- /* Flags describing which fields in this structure are valid. */
- ps_flags_t flags;
- ps_flags_t failed; /* flags that we tried to set and couldn't. */
-
- /* Thread fields -- these are valid if PID < 0. */
- struct proc_stat *thread_origin; /* A proc_stat for the task we're in. */
- unsigned thread_index; /* Which thread in our proc we are. */
-
- /* A process_t port for the process. */
- process_t process;
-
- /* The mach task port for the process. */
- task_t task;
-
- /* A libc msgport for the process. This port is responded to by the
- process itself (usually by the c library); see <hurd/msg.defs> for the
- standard set of rpcs you can send to this port. Accordingly, you
- cannot depend on a timely (or any) reply to messages sent here --
- program carefully! */
- mach_port_t msgport;
-
- /* A pointer to the process's procinfo structure (as returned by
- proc_getinfo; see <hurd/hurd_types.h>). Vm_alloced. */
- struct procinfo *proc_info;
- /* The size of the info structure for deallocation purposes. */
- unsigned proc_info_size;
-
- /* If present, these are just pointers into the proc_info structure. */
- unsigned num_threads;
- task_basic_info_t task_basic_info;
-
- /* For a thread, the obvious structures; for a process, summaries of the
- proc's thread_{basic,sched}_info_t structures: sizes and cumulative
- times are summed, prioritys and delta time are averaged. The
- run_states are added by having running thread take precedence over
- waiting ones, and if there are any other incompatible states, simply
- using a bogus value of -1. Malloced. */
- thread_basic_info_t thread_basic_info;
- thread_sched_info_t thread_sched_info;
-
- /* For a blocked thread, these next fields describe how it's blocked. */
-
- /* A string (pointing into the thread_waits field of the parent
- procstat), describing what's being blocked on. If "KERNEL", a system
- call (not mach_msg), and thread_rpc is the system call number.
- Otherwise if thread_rpc isn't zero, this string describes the port the
- rpc is on; if thread_rpc is 0, this string describes a non-rpc event. */
- char *thread_wait;
- /* The rpc that it's blocked on. For a process the rpc blocking the
- first blocked thread (if any). 0 means no block. */
- mach_msg_id_t thread_rpc;
-
- /* Storage for child-thread waits. */
- char *thread_waits;
- size_t thread_waits_len;
-
- /* The task or thread suspend count (whatever this proc_stat refers to). */
- int suspend_count;
-
- /* A bitmask summarizing the scheduling state of this process and all its
- threads. See the PSTAT_STATE_ defines below for a list of bits. */
- ps_state_t state;
-
- /* A ps_user object for the owner of this process, or NULL if none. */
- struct ps_user *owner;
- int owner_uid; /* The corresponding UID, or -1. */
-
- /* The process's argv, as a string with each element separated by '\0'. */
- char *args;
- /* The length of ARGS. */
- unsigned args_len;
-
- /* Virtual memory statistics for the process, as returned by task_info;
- see <mach/task_info.h> for a description of task_events_info_t. */
- task_events_info_t task_events_info;
- task_events_info_data_t task_events_info_buf;
- unsigned task_events_info_size;
-
- /* Flags showing whether a field is vm_alloced or malloced. */
- unsigned proc_info_vm_alloced : 1;
- unsigned thread_waits_vm_alloced : 1;
- unsigned args_vm_alloced : 1;
-
- /* Various libc ports: */
-
- /* The process's ctty id port, or MACH_PORT_NULL if the process has no
- controlling terminal. Note that this is just a magic cookie; we use
- it to fetch a port to the actual terminal -- it's not useful for much
- else. */
- mach_port_t cttyid;
-
- /* A port to the process's current working directory. */
- mach_port_t cwdir;
-
- /* The process's auth port, which we can use to determine who the process
- is authenticated as. */
- mach_port_t auth;
-
- /* The process's umask, which controls which protection bits won't be set
- when creating a file. */
- unsigned umask;
-
- /* A ps_tty object for the process's controlling terminal. */
- struct ps_tty *tty;
-
- /* A hook for the user to use. */
- void *hook;
- };
+{
+ /* Which process server this is from. */
+ struct ps_context *context;
+
+ /* The proc's process id; if <0 then this is a thread, not a process. */
+ pid_t pid;
+
+ /* Flags describing which fields in this structure are valid. */
+ ps_flags_t flags;
+ ps_flags_t failed; /* flags that we tried to set and couldn't. */
+ ps_flags_t inapp; /* flags that don't apply to this procstat;
+ subset of FAILED. */
+
+ /* Thread fields -- these are valid if PID < 0. */
+ struct proc_stat *thread_origin; /* A proc_stat for the task we're in. */
+ unsigned thread_index; /* Which thread in our proc we are. */
+
+ /* A process_t port for the process. */
+ process_t process;
+
+ /* The mach task port for the process. */
+ task_t task;
+
+ /* A libc msgport for the process. This port is responded to by the
+ process itself (usually by the c library); see <hurd/msg.defs> for the
+ standard set of rpcs you can send to this port. Accordingly, you
+ cannot depend on a timely (or any) reply to messages sent here --
+ program carefully! */
+ mach_port_t msgport;
+
+ /* A pointer to the process's procinfo structure (as returned by
+ proc_getinfo; see <hurd/hurd_types.h>). Vm_alloced. */
+ struct procinfo *proc_info;
+ /* The size of the info structure for deallocation purposes. */
+ unsigned proc_info_size;
+
+ /* If present, these are just pointers into the proc_info structure. */
+ unsigned num_threads;
+ task_basic_info_t task_basic_info;
+
+ /* For a thread, the obvious structures; for a process, summaries of the
+ proc's thread_{basic,sched}_info_t structures: sizes and cumulative
+ times are summed, prioritys and delta time are averaged. The
+ run_states are added by having running thread take precedence over
+ waiting ones, and if there are any other incompatible states, simply
+ using a bogus value of -1. Malloced. */
+ thread_basic_info_t thread_basic_info;
+ thread_sched_info_t thread_sched_info;
+
+ /* For a blocked thread, these next fields describe how it's blocked. */
+
+ /* A string (pointing into the thread_waits field of the parent
+ procstat), describing what's being blocked on. If "KERNEL", a system
+ call (not mach_msg), and thread_rpc is the system call number.
+ Otherwise if thread_rpc isn't zero, this string describes the port the
+ rpc is on; if thread_rpc is 0, this string describes a non-rpc event. */
+ char *thread_wait;
+ /* The rpc that it's blocked on. For a process the rpc blocking the
+ first blocked thread (if any). 0 means no block. */
+ mach_msg_id_t thread_rpc;
+
+ /* Storage for child-thread waits. */
+ char *thread_waits;
+ size_t thread_waits_len;
+
+ /* The task or thread suspend count (whatever this proc_stat refers to). */
+ int suspend_count;
+
+ /* A bitmask summarizing the scheduling state of this process and all its
+ threads. See the PSTAT_STATE_ defines below for a list of bits. */
+ ps_state_t state;
+
+ /* A ps_user object for the owner of this process, or NULL if none. */
+ struct ps_user *owner;
+ int owner_uid; /* The corresponding UID, or -1. */
+
+ /* The process's argv, as a string with each element separated by '\0'. */
+ char *args;
+ /* The length of ARGS. */
+ size_t args_len;
+
+ /* Virtual memory statistics for the process, as returned by task_info;
+ see <mach/task_info.h> for a description of task_events_info_t. */
+ /* FIXME: we are actually currently storing it into proc_info, see
+ fetch_procinfo. */
+ task_events_info_t task_events_info;
+ task_events_info_data_t task_events_info_buf;
+ size_t task_events_info_size;
+
+ /* Flags showing whether a field is vm_alloced or malloced. */
+ unsigned proc_info_vm_alloced : 1;
+ unsigned thread_waits_vm_alloced : 1;
+ unsigned args_vm_alloced : 1;
+ unsigned env_vm_alloced : 1;
+
+ /* Various libc ports: */
+
+ /* The process's ctty id port, or MACH_PORT_NULL if the process has no
+ controlling terminal. Note that this is just a magic cookie; we use
+ it to fetch a port to the actual terminal -- it's not useful for much
+ else. */
+ mach_port_t cttyid;
+
+ /* A port to the process's current working directory. */
+ mach_port_t cwdir;
+
+ /* The process's auth port, which we can use to determine who the process
+ is authenticated as. */
+ mach_port_t auth;
+
+ /* The process's umask, which controls which protection bits won't be set
+ when creating a file. */
+ unsigned umask;
+
+ /* A ps_tty object for the process's controlling terminal. */
+ struct ps_tty *tty;
+
+ /* A hook for the user to use. */
+ void *hook;
+
+ /* XXX these members added at the end for binary compatibility */
+ /* The process's envp, as a string with each element separated by '\0'. */
+ char *env;
+ /* The length of ENV. */
+ size_t env_len;
+
+ unsigned num_ports;
+};
/* Proc_stat flag bits; each bit is set in the FLAGS field if that
information is currently valid. */
@@ -317,6 +330,7 @@ struct proc_stat
#define PSTAT_THREAD_WAIT 0x00800 /* The rpc the thread is waiting on. */
#define PSTAT_THREAD_WAITS 0x01000 /* Thread waits for this PS's threads */
#define PSTAT_ARGS 0x02000 /* The process's args */
+#define PSTAT_ENV 0x2000000 /* The process's environment */
#define PSTAT_STATE 0x04000 /* A bitmask describing the process's
state (see below) */
#define PSTAT_SUSPEND_COUNT 0x08000 /* Task/thread suspend count */
@@ -328,12 +342,13 @@ struct proc_stat
#define PSTAT_OWNER_UID 0x200000 /* The uid of the the proc's owner */
#define PSTAT_UMASK 0x400000 /* The proc's current umask */
#define PSTAT_HOOK 0x800000 /* Has a non-zero hook */
+#define PSTAT_NUM_PORTS 0x4000000 /* Number of Mach ports in the task */
/* Flag bits that don't correspond precisely to any field. */
#define PSTAT_NO_MSGPORT 0x1000000 /* Don't use the msgport at all */
/* Bits from PSTAT_USER_BASE on up are available for user-use. */
-#define PSTAT_USER_BASE 0x2000000
+#define PSTAT_USER_BASE 0x10000000
#define PSTAT_USER_MASK ~(PSTAT_USER_BASE - 1)
/* If the PSTAT_STATE flag is set, then the proc_stats state field holds a
@@ -390,7 +405,7 @@ struct proc_stat
/* This is a constant string holding a single character for each possible bit
in a proc_stats STATE field, in order from bit zero. These are intended
for printing a user-readable summary of a process's state. */
-char *proc_stat_state_tags;
+extern char *proc_stat_state_tags;
/* Process info accessor functions.
@@ -420,6 +435,8 @@ char *proc_stat_state_tags;
#define proc_stat_suspend_count(ps) ((ps)->suspend_count)
#define proc_stat_args(ps) ((ps)->args)
#define proc_stat_args_len(ps) ((ps)->args_len)
+#define proc_stat_env(ps) ((ps)->env)
+#define proc_stat_env_len(ps) ((ps)->env_len)
#define proc_stat_state(ps) ((ps)->state)
#define proc_stat_cttyid(ps) ((ps)->cttyid)
#define proc_stat_cwdir(ps) ((ps)->cwdir)
@@ -429,6 +446,7 @@ char *proc_stat_state_tags;
#define proc_stat_umask(ps) ((ps)->umask)
#define proc_stat_tty(ps) ((ps)->tty)
#define proc_stat_task_events_info(ps) ((ps)->task_events_info)
+#define proc_stat_num_ports(ps) ((ps)->num_ports)
#define proc_stat_has(ps, needs) (((ps)->flags & needs) == needs)
/* True if PS refers to a thread and not a process. */
@@ -442,7 +460,9 @@ error_t _proc_stat_create (pid_t pid, struct ps_context *context,
/* Frees PS and any memory/ports it references. Users shouldn't use this
routine; proc_stats are normally freed only when their ps_context goes
- away. */
+ away. Insubordinate users will make sure they free the thread proc_stats
+ before they free the corresponding process proc_stat since the thread_wait
+ fields of the former may reference the latter. */
void _proc_stat_free (struct proc_stat *ps);
/* Adds FLAGS to PS's flags, fetching information as necessary to validate
@@ -455,7 +475,7 @@ error_t proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags);
PS (N should be between 0 and the number of threads in the process). The
resulting proc_stat isn't fully functional -- most flags can't be set in
it. If N was out of range, EINVAL is returned. If a memory allocation
- error occured, ENOMEM is returned. Otherwise, 0 is returned. */
+ error occurred, ENOMEM is returned. Otherwise, 0 is returned. */
error_t proc_stat_thread_create (struct proc_stat *ps, unsigned n,
struct proc_stat **thread_ps);
@@ -504,7 +524,7 @@ struct ps_getter
ps_flags_t needs;
/* A function that will get the value; the protocol between this function
- and its caller is type-dependent. */
+ and its caller is type-dependent. */
void (*fn) ();
};
@@ -608,7 +628,7 @@ error_t ps_stream_write_int_field (struct ps_stream *stream,
int value, int width);
/* A PS_FMT_SPEC describes how to output something from a PROC_STAT; it
- is a combination of a getter (describing how to get the value), an output
+ is a combination of a getter (describing how to get the value), an output
function (which outputs the result of the getter), and a compare function
(which can be used to sort proc_stats according to how they are
output). It also specifies the default width of the field in which the
@@ -620,7 +640,7 @@ struct ps_fmt_spec
{
/* The name of the spec (and it's title, if TITLE is NULL). */
const char *name;
-
+
/* The title to be printed in the headers. */
const char *title;
@@ -673,7 +693,7 @@ struct ps_fmt_specs
struct ps_fmt_spec_block *expansions; /* Storage for expanded aliases. */
};
-/* An struct ps_fmt_specs, suitable for use with ps_fmt_specs_find,
+/* An struct ps_fmt_specs, suitable for use with ps_fmt_specs_find,
containing specs for most values in a proc_stat. */
extern struct ps_fmt_specs ps_std_fmt_specs;
@@ -730,24 +750,29 @@ struct ps_fmt_field
/* PS_FMT */
struct ps_fmt
- {
- /* A pointer to an array of struct ps_fmt_fields holding the individual
- fields to be formatted. */
- struct ps_fmt_field *fields;
- /* The (valid) length of the fields array. */
- unsigned num_fields;
-
- /* A set of proc_stat flags describing what a proc_stat needs to hold in
- order to print out every field in the fmt. */
- ps_flags_t needs;
-
- /* Storage for various strings pointed to by the fields. */
- char *src;
- size_t src_len; /* Size of SRC. */
-
- /* The string displayed by default for fields that have no valid value. */
- char *inval;
- };
+{
+ /* A pointer to an array of struct ps_fmt_fields holding the individual
+ fields to be formatted. */
+ struct ps_fmt_field *fields;
+ /* The (valid) length of the fields array. */
+ unsigned num_fields;
+
+ /* A set of proc_stat flags describing what a proc_stat needs to hold in
+ order to print out every field in the fmt. */
+ ps_flags_t needs;
+
+ /* Storage for various strings pointed to by the fields. */
+ char *src;
+ size_t src_len; /* Size of SRC. */
+
+ /* The string displayed by default for fields that aren't appropriate for
+ this procstat. */
+ char *inapp;
+
+ /* The string displayed by default for fields which are appropriate, but
+ couldn't be fetched due to some error. */
+ char *error;
+};
/* Accessor macros: */
#define ps_fmt_fields(fmt) ((fmt)->fields)
@@ -797,7 +822,7 @@ void ps_fmt_free (struct ps_fmt *fmt);
instance, you would like squash a format without destroying the original. */
error_t ps_fmt_clone (struct ps_fmt *fmt, struct ps_fmt **copy);
-/* Write an appropiate header line for FMT, containing the titles of all its
+/* Write an appropriate header line for FMT, containing the titles of all its
fields appropiately aligned with where the values would be printed, to
STREAM (without a trailing newline). If count is non-NULL, the total
number number of characters output is added to the integer it points to.
@@ -812,14 +837,14 @@ error_t ps_fmt_write_proc_stat (struct ps_fmt *fmt, struct proc_stat *ps,
struct ps_stream *stream);
/* Remove those fields from FMT for which the function FN, when called on the
- field, returns true. Appropiate inter-field characters are also removed:
+ field, returns true. Appropriate inter-field characters are also removed:
those *following* deleted fields at the beginning of the fmt, and those
- *preceeding* deleted fields *not* at the beginning. */
+ *preceding* deleted fields *not* at the beginning. */
void ps_fmt_squash (struct ps_fmt *fmt, int (*fn)(struct ps_fmt_field *field));
/* Remove those fields from FMT which would need the proc_stat flags FLAGS.
- Appropiate inter-field characters are also removed: those *following*
- deleted fields at the beginning of the fmt, and those *preceeding* deleted
+ Appropriate inter-field characters are also removed: those *following*
+ deleted fields at the beginning of the fmt, and those *preceding* deleted
fields *not* at the beginning. */
void ps_fmt_squash_flags (struct ps_fmt *fmt, ps_flags_t flags);
@@ -898,7 +923,7 @@ error_t proc_stat_list_merge (struct proc_stat_list *pp,
returned in them. */
error_t proc_stat_list_add_all (struct proc_stat_list *pp,
struct proc_stat ***proc_stats,
- unsigned *num_procs);
+ size_t *num_procs);
/* Add to PP entries for all processes in the login collection LOGIN_ID at
its context. If an error occurs, the system error code is returned,
@@ -907,7 +932,7 @@ error_t proc_stat_list_add_all (struct proc_stat_list *pp,
error_t proc_stat_list_add_login_coll (struct proc_stat_list *pp,
pid_t login_id,
struct proc_stat ***proc_stats,
- unsigned *num_procs);
+ size_t *num_procs);
/* Add to PP entries for all processes in the session SESSION_ID at its
context. If an error occurs, the system error code is returned, otherwise
@@ -916,7 +941,7 @@ error_t proc_stat_list_add_login_coll (struct proc_stat_list *pp,
error_t proc_stat_list_add_session (struct proc_stat_list *pp,
pid_t session_id,
struct proc_stat ***proc_stats,
- unsigned *num_procs);
+ size_t *num_procs);
/* Add to PP entries for all processes in the process group PGRP at its
context. If an error occurs, the system error code is returned, otherwise
@@ -924,7 +949,7 @@ error_t proc_stat_list_add_session (struct proc_stat_list *pp,
resulting entries is returned in them. */
error_t proc_stat_list_add_pgrp (struct proc_stat_list *pp, pid_t pgrp,
struct proc_stat ***proc_stats,
- unsigned *num_procs);
+ size_t *num_procs);
/* Try to set FLAGS in each proc_stat in PP (but they may still not be set
-- you have to check). If a fatal error occurs, the error code is
@@ -1009,7 +1034,7 @@ int proc_stat_list_spec_nominal (struct proc_stat_list *pp,
information on the data types these routines return. */
/* Return the current host port. */
-host_t ps_get_host ();
+mach_port_t ps_get_host ();
/* Return a pointer to basic info about the current host in HOST_INFO. Since
this is static global information we just use a static buffer. If a
diff --git a/libps/spec.c b/libps/spec.c
index 62b6dfc2..b34a2343 100644
--- a/libps/spec.c
+++ b/libps/spec.c
@@ -1,8 +1,8 @@
/* Access, formatting, & comparison routines for printing process info.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,99,2001,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -41,7 +41,7 @@ static char *get_rpc_name (mach_msg_id_t it) { return 0; }
typedef void (*vf)();
-static int
+static int
ps_get_pid (struct proc_stat *ps)
{
return proc_stat_pid (ps);
@@ -49,7 +49,7 @@ ps_get_pid (struct proc_stat *ps)
const struct ps_getter ps_pid_getter =
{"pid", PSTAT_PID, (vf) ps_get_pid};
-static int
+static int
ps_get_thread_index (struct proc_stat *ps)
{
return proc_stat_thread_index (ps);
@@ -73,7 +73,7 @@ ps_get_owner_uid (struct proc_stat *ps)
const struct ps_getter ps_owner_uid_getter =
{"uid", PSTAT_OWNER_UID, (vf) ps_get_owner_uid};
-static int
+static int
ps_get_ppid (struct proc_stat *ps)
{
return proc_stat_proc_info (ps)->ppid;
@@ -81,7 +81,7 @@ ps_get_ppid (struct proc_stat *ps)
const struct ps_getter ps_ppid_getter =
{"ppid", PSTAT_PROC_INFO, (vf) ps_get_ppid};
-static int
+static int
ps_get_pgrp (struct proc_stat *ps)
{
return proc_stat_proc_info (ps)->pgrp;
@@ -89,7 +89,7 @@ ps_get_pgrp (struct proc_stat *ps)
const struct ps_getter ps_pgrp_getter =
{"pgrp", PSTAT_PROC_INFO, (vf) ps_get_pgrp};
-static int
+static int
ps_get_session (struct proc_stat *ps)
{
return proc_stat_proc_info (ps)->session;
@@ -97,7 +97,7 @@ ps_get_session (struct proc_stat *ps)
const struct ps_getter ps_session_getter =
{"session", PSTAT_PROC_INFO, (vf) ps_get_session};
-static int
+static int
ps_get_login_col (struct proc_stat *ps)
{
return proc_stat_proc_info (ps)->logincollection;
@@ -105,7 +105,7 @@ ps_get_login_col (struct proc_stat *ps)
const struct ps_getter ps_login_col_getter =
{"login_col", PSTAT_PROC_INFO, (vf) ps_get_login_col};
-static int
+static int
ps_get_num_threads (struct proc_stat *ps)
{
return proc_stat_num_threads (ps);
@@ -113,7 +113,7 @@ ps_get_num_threads (struct proc_stat *ps)
const struct ps_getter ps_num_threads_getter =
{"num_threads", PSTAT_NUM_THREADS, (vf)ps_get_num_threads};
-static void
+static void
ps_get_args (struct proc_stat *ps, char **args_p, int *args_len_p)
{
*args_p = proc_stat_args (ps);
@@ -122,7 +122,16 @@ ps_get_args (struct proc_stat *ps, char **args_p, int *args_len_p)
const struct ps_getter ps_args_getter =
{"args", PSTAT_ARGS, ps_get_args};
-static int
+static void
+ps_get_env (struct proc_stat *ps, char **env_p, int *env_len_p)
+{
+ *env_p = proc_stat_env (ps);
+ *env_len_p = proc_stat_env_len (ps);
+}
+const struct ps_getter ps_env_getter =
+{"env", PSTAT_ENV, ps_get_env};
+
+static int
ps_get_state (struct proc_stat *ps)
{
return proc_stat_state (ps);
@@ -139,7 +148,7 @@ ps_get_wait (struct proc_stat *ps, char **wait, int *rpc)
const struct ps_getter ps_wait_getter =
{"wait", PSTAT_THREAD_WAIT, ps_get_wait};
-static int
+static size_t
ps_get_vsize (struct proc_stat *ps)
{
return proc_stat_task_basic_info (ps)->virtual_size;
@@ -147,7 +156,7 @@ ps_get_vsize (struct proc_stat *ps)
const struct ps_getter ps_vsize_getter =
{"vsize", PSTAT_TASK_BASIC, (vf) ps_get_vsize};
-static int
+static size_t
ps_get_rsize (struct proc_stat *ps)
{
return proc_stat_task_basic_info (ps)->resident_size;
@@ -155,7 +164,7 @@ ps_get_rsize (struct proc_stat *ps)
const struct ps_getter ps_rsize_getter =
{"rsize", PSTAT_TASK_BASIC, (vf) ps_get_rsize};
-static int
+static int
ps_get_cur_priority (struct proc_stat *ps)
{
return proc_stat_thread_basic_info (ps)->cur_priority;
@@ -163,7 +172,7 @@ ps_get_cur_priority (struct proc_stat *ps)
const struct ps_getter ps_cur_priority_getter =
{"cur_priority", PSTAT_THREAD_BASIC, (vf) ps_get_cur_priority};
-static int
+static int
ps_get_base_priority (struct proc_stat *ps)
{
return proc_stat_thread_basic_info (ps)->base_priority;
@@ -171,7 +180,7 @@ ps_get_base_priority (struct proc_stat *ps)
const struct ps_getter ps_base_priority_getter =
{"base_priority", PSTAT_THREAD_BASIC, (vf) ps_get_base_priority};
-static int
+static int
ps_get_max_priority (struct proc_stat *ps)
{
return proc_stat_thread_sched_info (ps)->max_priority;
@@ -179,7 +188,7 @@ ps_get_max_priority (struct proc_stat *ps)
const struct ps_getter ps_max_priority_getter =
{"max_priority", PSTAT_THREAD_SCHED, (vf) ps_get_max_priority};
-static void
+static void
ps_get_usr_time (struct proc_stat *ps, struct timeval *tv)
{
time_value_t tvt = proc_stat_thread_basic_info (ps)->user_time;
@@ -189,7 +198,7 @@ ps_get_usr_time (struct proc_stat *ps, struct timeval *tv)
const struct ps_getter ps_usr_time_getter =
{"usr_time", PSTAT_THREAD_BASIC, ps_get_usr_time};
-static void
+static void
ps_get_sys_time (struct proc_stat *ps, struct timeval *tv)
{
time_value_t tvt = proc_stat_thread_basic_info (ps)->system_time;
@@ -199,7 +208,7 @@ ps_get_sys_time (struct proc_stat *ps, struct timeval *tv)
const struct ps_getter ps_sys_time_getter =
{"sys_time", PSTAT_THREAD_BASIC, ps_get_sys_time};
-static void
+static void
ps_get_tot_time (struct proc_stat *ps, struct timeval *tv)
{
time_value_t tvt = proc_stat_thread_basic_info (ps)->user_time;
@@ -210,10 +219,20 @@ ps_get_tot_time (struct proc_stat *ps, struct timeval *tv)
const struct ps_getter ps_tot_time_getter =
{"tot_time", PSTAT_THREAD_BASIC, ps_get_tot_time};
-static float
+static void
+ps_get_start_time (struct proc_stat *ps, struct timeval *tv)
+{
+ time_value_t *const tvt = &proc_stat_task_basic_info (ps)->creation_time;
+ tv->tv_sec = tvt->seconds;
+ tv->tv_usec = tvt->microseconds;
+}
+const struct ps_getter ps_start_time_getter =
+{"start_time", PSTAT_TASK_BASIC, ps_get_start_time};
+
+static float
ps_get_rmem_frac (struct proc_stat *ps)
{
- static int mem_size = 0;
+ static size_t mem_size = 0;
if (mem_size == 0)
{
@@ -222,7 +241,7 @@ ps_get_rmem_frac (struct proc_stat *ps)
if (err == 0)
mem_size = info->memory_size;
}
-
+
if (mem_size > 0)
return
(float)proc_stat_task_basic_info (ps)->resident_size
@@ -233,7 +252,7 @@ ps_get_rmem_frac (struct proc_stat *ps)
const struct ps_getter ps_rmem_frac_getter =
{"rmem_frac", PSTAT_TASK_BASIC, (vf) ps_get_rmem_frac};
-static float
+static float
ps_get_cpu_frac (struct proc_stat *ps)
{
return (float) proc_stat_thread_basic_info (ps)->cpu_usage
@@ -242,7 +261,7 @@ ps_get_cpu_frac (struct proc_stat *ps)
const struct ps_getter ps_cpu_frac_getter =
{"cpu_frac", PSTAT_THREAD_BASIC, (vf) ps_get_cpu_frac};
-static int
+static int
ps_get_sleep (struct proc_stat *ps)
{
return proc_stat_thread_basic_info (ps)->sleep_time;
@@ -250,7 +269,7 @@ ps_get_sleep (struct proc_stat *ps)
const struct ps_getter ps_sleep_getter =
{"sleep", PSTAT_THREAD_BASIC, (vf) ps_get_sleep};
-static int
+static int
ps_get_susp_count (struct proc_stat *ps)
{
return proc_stat_suspend_count (ps);
@@ -258,7 +277,7 @@ ps_get_susp_count (struct proc_stat *ps)
const struct ps_getter ps_susp_count_getter =
{"susp_count", PSTAT_SUSPEND_COUNT, (vf) ps_get_susp_count};
-static int
+static int
ps_get_proc_susp_count (struct proc_stat *ps)
{
return proc_stat_task_basic_info (ps)->suspend_count;
@@ -266,7 +285,7 @@ ps_get_proc_susp_count (struct proc_stat *ps)
const struct ps_getter ps_proc_susp_count_getter =
{"proc_susp_count", PSTAT_TASK_BASIC, (vf) ps_get_proc_susp_count};
-static int
+static int
ps_get_thread_susp_count (struct proc_stat *ps)
{
return proc_stat_thread_basic_info (ps)->suspend_count;
@@ -282,7 +301,7 @@ ps_get_tty (struct proc_stat *ps)
const struct ps_getter ps_tty_getter =
{"tty", PSTAT_TTY, (vf)ps_get_tty};
-static int
+static int
ps_get_page_faults (struct proc_stat *ps)
{
return proc_stat_task_events_info (ps)->faults;
@@ -290,7 +309,7 @@ ps_get_page_faults (struct proc_stat *ps)
const struct ps_getter ps_page_faults_getter =
{"page_faults", PSTAT_TASK_EVENTS, (vf) ps_get_page_faults};
-static int
+static int
ps_get_cow_faults (struct proc_stat *ps)
{
return proc_stat_task_events_info (ps)->cow_faults;
@@ -298,7 +317,7 @@ ps_get_cow_faults (struct proc_stat *ps)
const struct ps_getter ps_cow_faults_getter =
{"cow_faults", PSTAT_TASK_EVENTS, (vf) ps_get_cow_faults};
-static int
+static int
ps_get_pageins (struct proc_stat *ps)
{
return proc_stat_task_events_info (ps)->pageins;
@@ -306,7 +325,7 @@ ps_get_pageins (struct proc_stat *ps)
const struct ps_getter ps_pageins_getter =
{"pageins", PSTAT_TASK_EVENTS, (vf) ps_get_pageins};
-static int
+static int
ps_get_msgs_sent (struct proc_stat *ps)
{
return proc_stat_task_events_info (ps)->messages_sent;
@@ -314,7 +333,7 @@ ps_get_msgs_sent (struct proc_stat *ps)
const struct ps_getter ps_msgs_sent_getter =
{"msgs_sent", PSTAT_TASK_EVENTS, (vf) ps_get_msgs_sent};
-static int
+static int
ps_get_msgs_rcvd (struct proc_stat *ps)
{
return proc_stat_task_events_info (ps)->messages_received;
@@ -322,7 +341,7 @@ ps_get_msgs_rcvd (struct proc_stat *ps)
const struct ps_getter ps_msgs_rcvd_getter =
{"msgs_rcvd", PSTAT_TASK_EVENTS, (vf) ps_get_msgs_rcvd};
-static int
+static int
ps_get_zero_fills (struct proc_stat *ps)
{
return proc_stat_task_events_info (ps)->zero_fills;
@@ -330,6 +349,14 @@ ps_get_zero_fills (struct proc_stat *ps)
const struct ps_getter ps_zero_fills_getter =
{"zero_fills", PSTAT_TASK_EVENTS, (vf) ps_get_zero_fills};
+static int
+ps_get_num_ports (struct proc_stat *ps)
+{
+ return proc_stat_num_ports (ps);
+}
+const struct ps_getter ps_num_ports_getter =
+{"num_ports", PSTAT_NUM_PORTS, (vf) ps_get_num_ports};
+
/* ---------------------------------------------------------------- */
/* some printing functions */
@@ -378,16 +405,18 @@ ps_emit_num_blocks (struct proc_stat *ps, struct ps_fmt_field *field,
return ps_stream_write_field (stream, buf, field->width);
}
-int
+size_t
sprint_frac_value (char *buf,
- int value, int min_value_len,
- int frac, int frac_scale,
+ size_t value, int min_value_len,
+ size_t frac, int frac_scale,
int width)
{
- int value_len;
- int frac_len;
+ int value_len = 0;
+ int frac_len = 0;
- if (value >= 100) /* the integer part */
+ if (value >= 1000) /* the integer part */
+ value_len = 4; /* values 1000-1023 */
+ if (value >= 100)
value_len = 3;
else if (value >= 10)
value_len = 2;
@@ -403,9 +432,9 @@ sprint_frac_value (char *buf,
frac /= 10;
if (frac_len > 0)
- sprintf (buf, "%d.%0*d", value, frac_len, frac);
+ sprintf (buf, "%zd.%0*zd", value, frac_len, frac);
else
- sprintf (buf, "%d", value);
+ sprintf (buf, "%zd", value);
return strlen (buf);
}
@@ -430,13 +459,13 @@ ps_emit_percent (struct proc_stat *ps, struct ps_fmt_field *field,
/* prints its value nicely */
error_t
-ps_emit_nice_int (struct proc_stat *ps, struct ps_fmt_field *field,
- struct ps_stream *stream)
+ps_emit_nice_size_t (struct proc_stat *ps, struct ps_fmt_field *field,
+ struct ps_stream *stream)
{
char buf[20];
- int value = FG (field, int)(ps);
+ size_t value = FG (field, size_t)(ps);
char *sfx = " KMG";
- int frac = 0;
+ size_t frac = 0;
while (value >= 1024)
{
@@ -462,8 +491,11 @@ ps_emit_seconds (struct proc_stat *ps, struct ps_fmt_field *field,
FG (field, void)(ps, &tv);
- fmt_seconds (&tv, !(field->flags & PS_FMT_FIELD_AT_MOD), prec, ABS (width),
- buf, sizeof (buf));
+ if ((field->flags & PS_FMT_FIELD_COLON_MOD) && tv.tv_sec == 0)
+ strcpy (buf, "-");
+ else
+ fmt_seconds (&tv, !(field->flags & PS_FMT_FIELD_AT_MOD), prec, ABS (width),
+ buf, sizeof (buf));
return ps_stream_write_field (stream, buf, width);
}
@@ -476,10 +508,13 @@ ps_emit_minutes (struct proc_stat *ps, struct ps_fmt_field *field,
struct timeval tv;
int width = field->width;
- FG (field, int)(ps, &tv);
+ FG (field, void)(ps, &tv);
- fmt_minutes (&tv, !(field->flags & PS_FMT_FIELD_AT_MOD), ABS (width),
- buf, sizeof (buf));
+ if ((field->flags & PS_FMT_FIELD_COLON_MOD) && tv.tv_sec < 60)
+ strcpy (buf, "-");
+ else
+ fmt_minutes (&tv, !(field->flags & PS_FMT_FIELD_AT_MOD), ABS (width),
+ buf, sizeof (buf));
return ps_stream_write_field (stream, buf, width);
}
@@ -493,7 +528,7 @@ ps_emit_past_time (struct proc_stat *ps, struct ps_fmt_field *field,
struct timeval tv;
int width = field->width;
- FG (field, int)(ps, &tv);
+ FG (field, void)(ps, &tv);
if (now.tv_sec == 0 && gettimeofday (&now, 0) < 0)
return errno;
@@ -544,7 +579,7 @@ ps_emit_user_name (struct proc_stat *ps, struct ps_fmt_field *field,
if (pw == NULL)
{
char buf[20];
- sprintf (buf, "(UID %d)", pw->pw_uid);
+ sprintf (buf, "(UID %d)", u->uid);
return ps_stream_write_field (stream, buf, width);
}
else
@@ -568,8 +603,8 @@ ps_emit_args (struct proc_stat *ps, struct ps_fmt_field *field,
FG (field, void)(ps, &s0, &s0len);
- if (s0 == NULL)
- *buf = '\0';
+ if (!s0 || s0len == 0 )
+ strcpy (buf, "-");
else
{
if (s0len > sizeof static_buf)
@@ -610,8 +645,8 @@ ps_emit_string (struct proc_stat *ps, struct ps_fmt_field *field,
FG (field, void)(ps, &str, &len);
- if (str == NULL)
- str = "";
+ if (!str || len == 0)
+ str = "-";
return ps_stream_write_trunc_field (stream, str, field->width);
}
@@ -706,7 +741,6 @@ ps_emit_wait (struct proc_stat *ps, struct ps_fmt_field *field,
else if (strcmp (wait, "kernel") == 0)
/* A syscall. RPC is actually the syscall number. */
{
- extern char *get_syscall_name (int num);
char *name = get_syscall_name (rpc);
if (! name)
{
@@ -719,29 +753,35 @@ ps_emit_wait (struct proc_stat *ps, struct ps_fmt_field *field,
/* An rpc (with msg id RPC); WAIT describes the dest port. */
{
char port_name_buf[20];
- extern char *get_rpc_name (mach_msg_id_t num);
char *name = get_rpc_name (rpc);
/* See if we should give a more useful name for the port. */
if (strcmp (wait, "init#0") == 0)
- wait = "cwdir"; /* Current directory */
+ wait = "cwd"; /* Current directory */
else if (strcmp (wait, "init#1") == 0)
- wait = "crdir"; /* Root directory */
+ wait = "root"; /* Root directory */
else if (strcmp (wait, "init#2") == 0)
wait = "auth"; /* Auth port */
else if (strcmp (wait, "init#3") == 0)
wait = "proc"; /* Proc port */
else if (strcmp (wait, "init#4") == 0)
- wait = "bootstrap"; /* Bootstrap port */
+ wait = "cttyid"; /* Ctty id port */
+ else if (strcmp (wait, "init#5") == 0)
+ wait = "boot"; /* Bootstrap port */
else
- /* See if we can shorten the name to fit better. We happen know that
- all currently returned keys are unique in the first character. */
+ /* See if we can shorten the name to fit better. */
{
- char *sep = index (wait, '#');
- if (sep && sep > wait)
+ char *abbrev = 0, *num = 0;
+ if (strncmp (wait, "fd#", 3) == 0)
+ abbrev = "fd", num = wait + 3;
+ else if (strncmp (wait, "bgfd#", 5) == 0)
+ abbrev = "bg", num = wait + 5;
+ else if (strncmp (wait, "port#", 5) == 0)
+ abbrev = "", num = wait + 5;
+ if (abbrev)
{
snprintf (port_name_buf, sizeof port_name_buf,
- "%c%s", wait[0], sep);
+ "%s%s", abbrev, num);
wait = port_name_buf;
}
}
@@ -764,25 +804,34 @@ ps_emit_wait (struct proc_stat *ps, struct ps_fmt_field *field,
#define GUARDED_CMP(s1, s2, call) \
((s1) == NULL ? (((s2) == NULL) ? 0 : -1) : ((s2) == NULL ? 1 : (call)))
-int
+int
ps_cmp_ints (struct proc_stat *ps1, struct proc_stat *ps2,
const struct ps_getter *getter)
{
int (*gf)() = G (getter, int);
int v1 = gf(ps1), v2 = gf (ps2);
return v1 == v2 ? 0 : v1 < v2 ? -1 : 1;
-}
+}
-int
+int
ps_cmp_floats (struct proc_stat *ps1, struct proc_stat *ps2,
const struct ps_getter *getter)
{
float (*gf)() = G (getter, float);
float v1 = gf(ps1), v2 = gf (ps2);
return v1 == v2 ? 0 : v1 < v2 ? -1 : 1;
-}
+}
-int
+int
+ps_cmp_size_ts (struct proc_stat *ps1, struct proc_stat *ps2,
+ const struct ps_getter *getter)
+{
+ size_t (*gf)() = G (getter, size_t);
+ size_t v1 = gf(ps1), v2 = gf (ps2);
+ return v1 == v2 ? 0 : v1 < v2 ? -1 : 1;
+}
+
+int
ps_cmp_uids (struct proc_stat *ps1, struct proc_stat *ps2,
const struct ps_getter *getter)
{
@@ -791,7 +840,7 @@ ps_cmp_uids (struct proc_stat *ps1, struct proc_stat *ps2,
return (u1 ? ps_user_uid (u1) : -1) - (u2 ? ps_user_uid (u2) : -1);
}
-int
+int
ps_cmp_unames (struct proc_stat *ps1, struct proc_stat *ps2,
const struct ps_getter *getter)
{
@@ -802,7 +851,7 @@ ps_cmp_unames (struct proc_stat *ps1, struct proc_stat *ps2,
return GUARDED_CMP (pw1, pw2, strcmp (pw1->pw_name, pw2->pw_name));
}
-int
+int
ps_cmp_strings (struct proc_stat *ps1, struct proc_stat *ps2,
const struct ps_getter *getter)
{
@@ -845,6 +894,16 @@ ps_nominal_zint (struct proc_stat *ps, const struct ps_getter *getter)
return G (getter, int)(ps) == 0;
}
+/* Neither is an empty string. */
+int
+ps_nominal_string (struct proc_stat *ps, const struct ps_getter *getter)
+{
+ char *str;
+ size_t len;
+ G (getter, char *)(ps, &str, &len);
+ return !str || len == 0 || (len == 1 && *str == '-');
+}
+
/* Priorities are similar, but have to be converted to the unix nice scale
first. */
int
@@ -864,7 +923,7 @@ ps_nominal_nth (struct proc_stat *ps, const struct ps_getter *getter)
static int own_uid = -2; /* -1 means no uid at all. */
/* A user is nominal if it's the current user. */
-int
+int
ps_nominal_user (struct proc_stat *ps, const struct ps_getter *getter)
{
struct ps_user *u = G (getter, struct ps_user *)(ps);
@@ -874,7 +933,7 @@ ps_nominal_user (struct proc_stat *ps, const struct ps_getter *getter)
}
/* A uid is nominal if it's that of the current user. */
-int
+int
ps_nominal_uid (struct proc_stat *ps, const struct ps_getter *getter)
{
uid_t uid = G (getter, uid_t)(ps);
@@ -916,7 +975,7 @@ specv_find (const struct ps_fmt_spec *specs, const char *name,
return 0;
}
-/* Number of specs allocated in each block of expansions. */
+/* Number of specs allocated in each block of expansions. */
#define EXP_BLOCK_SIZE 20
/* A node in a linked list of spec vectors. */
@@ -1051,9 +1110,13 @@ static const struct ps_fmt_spec specs[] =
{"LColl", 0, -5, -1, 0,
&ps_login_col_getter, ps_emit_int, ps_cmp_ints, 0},
{"Args", 0, 0, -1, 0,
- &ps_args_getter, ps_emit_args, ps_cmp_strings,0},
+ &ps_args_getter, ps_emit_args, ps_cmp_strings,ps_nominal_string},
{"Arg0", 0, 0, -1, 0,
- &ps_args_getter, ps_emit_string, ps_cmp_strings,0},
+ &ps_args_getter, ps_emit_string, ps_cmp_strings,ps_nominal_string},
+ {"Env", 0, 0, -1, 0,
+ &ps_env_getter, ps_emit_args, ps_cmp_strings,ps_nominal_string},
+ {"Start", 0, -7, 1, 0,
+ &ps_start_time_getter, ps_emit_past_time, ps_cmp_times,0},
{"Time", 0, -8, 2, 0,
&ps_tot_time_getter, ps_emit_seconds, ps_cmp_times, 0},
{"UTime", 0, -8, 2, 0,
@@ -1061,9 +1124,9 @@ static const struct ps_fmt_spec specs[] =
{"STime", 0, -8, 2, 0,
&ps_sys_time_getter, ps_emit_seconds, ps_cmp_times, 0},
{"VSize", 0, -5, -1, 0,
- &ps_vsize_getter, ps_emit_nice_int,ps_cmp_ints, 0},
+ &ps_vsize_getter, ps_emit_nice_size_t,ps_cmp_size_ts, 0},
{"RSize", 0, -5, -1, 0,
- &ps_rsize_getter, ps_emit_nice_int,ps_cmp_ints, 0},
+ &ps_rsize_getter, ps_emit_nice_size_t,ps_cmp_size_ts, 0},
{"Pri", 0, -3, -1, 0,
&ps_cur_priority_getter,ps_emit_priority,ps_cmp_ints, ps_nominal_pri},
{"BPri", 0, -3, -1, 0,
@@ -1100,6 +1163,8 @@ static const struct ps_fmt_spec specs[] =
&ps_msgs_sent_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
{"ZFills", 0, -5, -1, 0,
&ps_zero_fills_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint},
+ {"Ports", 0, -5, -1, 0,
+ &ps_num_ports_getter, ps_emit_int, ps_cmp_ints, 0},
{0}
};
diff --git a/libps/tty.c b/libps/tty.c
index 9d9ee649..3ab72ee8 100644
--- a/libps/tty.c
+++ b/libps/tty.c
@@ -1,8 +1,8 @@
/* The ps_tty type, for per-tty info.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,1996,2000 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -91,11 +91,11 @@ ps_tty_name (struct ps_tty *tty)
struct ps_tty_abbrev
{
- char *pfx;
- char *subst;
+ const char *pfx;
+ const char *subst;
};
-struct ps_tty_abbrev ps_tty_abbrevs[] =
+const struct ps_tty_abbrev ps_tty_abbrevs[] =
{
{ "/tmp/console", "oc" }, /* temp hack */
{ "/dev/console", "co" },
@@ -115,14 +115,14 @@ ps_tty_short_name (struct ps_tty *tty)
return tty->short_name;
else
{
- struct ps_tty_abbrev *abbrev;
+ const struct ps_tty_abbrev *abbrev;
const char *name = ps_tty_name (tty);
if (name)
for (abbrev = ps_tty_abbrevs; abbrev->pfx != NULL; abbrev++)
{
- char *subst = abbrev->subst;
- unsigned pfx_len = strlen (abbrev->pfx);
+ const char *subst = abbrev->subst;
+ size_t pfx_len = strlen (abbrev->pfx);
if (strncmp (name, abbrev->pfx, pfx_len) == 0)
{
@@ -132,11 +132,13 @@ ps_tty_short_name (struct ps_tty *tty)
tty->short_name = name + pfx_len;
else
{
- char *n = malloc (strlen(subst) + strlen (name + pfx_len));
+ size_t slen = strlen (subst);
+ size_t nlen = strlen (name + pfx_len) + 1;
+ char *n = malloc (slen + nlen);
if (n)
{
- strcpy (n, subst);
- strcat (n, name + pfx_len);
+ memcpy (n, subst, slen);
+ memcpy (&n[slen], &name[pfx_len], nlen);
tty->short_name = n;
tty->short_name_alloced = TRUE;
}
diff --git a/libps/user.c b/libps/user.c
index 4af5014f..0b87ace3 100644
--- a/libps/user.c
+++ b/libps/user.c
@@ -1,8 +1,8 @@
/* The ps_user type, for per-user info.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,2001 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -21,6 +21,7 @@
#include <hurd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <assert.h>
#include "ps.h"
diff --git a/libps/write.c b/libps/write.c
index 725ea288..83be42ab 100644
--- a/libps/write.c
+++ b/libps/write.c
@@ -68,7 +68,7 @@ noise_write (const unsigned char *t, ssize_t max, FILE *s)
if (flush (&ok, t, s))
return errno;
- len += (is_cntl ? 2 : 3);
+ len += (is_cntl ? 2 : 4);
if (max >= 0 && len > max)
break;
@@ -96,7 +96,7 @@ noise_len (const char *t, ssize_t max)
len++;
else
{
- size_t rep_len = iscntl (ch) ? 2 : 3;
+ size_t rep_len = iscntl (ch) ? 2 : 4;
if (max >= 0 && rep_len + len > max)
break;
len += rep_len;
diff --git a/libshouldbeinlibc/=argz.c b/libshouldbeinlibc/=argz.c
deleted file mode 100644
index fd90a1e2..00000000
--- a/libshouldbeinlibc/=argz.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/* Routines for dealing with '\0' separated arg vectors.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-/* ---------------------------------------------------------------- */
-
-/* Make a '\0' separated arg vector from a unix argv vector, returning it in
- ARGZ, and the total length in LEN. If a memory allocation error occurs,
- ENOMEM is returned, otherwise 0. */
-error_t
-argz_create(char **argv, char **argz, int *len)
-{
- int tlen = 0;
- char **argp;
-
- for (argp = argv; *argp != NULL; argp++)
- tlen += strlen(*argp) + 1;
-
- *len = tlen;
-
- if (tlen == 0)
- *argz = NULL;
- else
- {
- *argz = malloc(tlen);
- if (*argz == NULL)
- return ENOMEM;
-
- while (tlen > 0)
- {
- tlen -= strlen(*--argp) + 1;
- strcpy(*argz + tlen, *argp);
- }
- }
-
- return 0;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Returns the number of strings in ARGZ. */
-int
-argz_count (char *argz, int len)
-{
- int count = 0;
- while (len > 0)
- {
- int part_len = strlen(argz);
- argz += part_len + 1;
- len -= part_len + 1;
- count++;
- }
- return count;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Puts pointers to each string in ARGZ into ARGV, which must be large enough
- to hold them all. */
-void
-argz_extract (char *argz, int len, char **argv)
-{
- while (len > 0)
- {
- int part_len = strlen(argz);
- *argv++ = argz;
- argz += part_len + 1;
- len -= part_len + 1;
- }
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
- except the last into the character SEP. */
-void
-argz_stringify(char *argz, int len, int sep)
-{
- while (len > 0)
- {
- int part_len = strlen(argz);
- argz += part_len;
- len -= part_len + 1;
- if (len > 0)
- *argz++ = sep;
- }
-}
-
-/* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */
-error_t
-argz_append (char **argz, unsigned *argz_len, char *buf, unsigned buf_len)
-{
- unsigned new_argz_len = *argz_len + buf_len;
- char *new_argz = realloc (*argz, new_argz_len);
- if (new_argz)
- {
- bcopy (buf, new_argz + *argz_len, buf_len);
- *argz = new_argz;
- *argz_len = new_argz_len;
- return 0;
- }
- else
- return ENOMEM;
-}
-
-/* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into
- argz.c in libshouldbelibc. */
-error_t
-argz_add (char **argz, unsigned *argz_len, char *str)
-{
- return argz_append (argz, argz_len, str, strlen (str) + 1);
-}
-
-/* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */
-void
-argz_delete (char **argz, unsigned *argz_len, char *entry)
-{
- if (entry)
- /* Get rid of the old value for NAME. */
- {
- unsigned entry_len = strlen (entry) + 1;
- *argz_len -= entry_len;
- bcopy (entry + entry_len, entry, *argz_len - (entry - *argz));
- if (*argz_len == 0)
- {
- free (*argz);
- *argz = 0;
- }
- }
-}
-
-/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
- existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
- Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
- ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not
- in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
- ARGZ, ENOMEM is returned, else 0. */
-error_t
-argz_insert (char **argz, unsigned *argz_len, char *before, char *entry)
-{
- if (! before)
- return argz_add (argz, argz_len, entry);
-
- if (before < *argz || before >= *argz + *argz_len)
- return EINVAL;
-
- if (before > *argz)
- /* Make sure before is actually the beginning of an entry. */
- while (before[-1])
- before--;
-
- {
- unsigned after_before = *argz_len - (before - *argz);
- unsigned entry_len = strlen (entry) + 1;
- unsigned new_argz_len = *argz_len + entry_len;
- char *new_argz = realloc (*argz, new_argz_len);
-
- if (new_argz)
- {
- before = new_argz + (before - *argz);
- bcopy (before, before + entry_len, after_before);
- bcopy (entry, before, entry_len);
- *argz = new_argz;
- *argz_len = new_argz_len;
- return 0;
- }
- else
- return ENOMEM;
- }
-}
diff --git a/libshouldbeinlibc/=argz.h b/libshouldbeinlibc/=argz.h
deleted file mode 100644
index 1de0cd64..00000000
--- a/libshouldbeinlibc/=argz.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Routines for dealing with '\0' separated arg vectors.
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#ifndef __ARGZ_H__
-#define __ARGZ_H__
-
-/* Make a '\0' separated arg vector from a unix argv vector, returning it in
- ARGZ, and the total length in LEN. If a memory allocation error occurs,
- ENOMEM is returned, otherwise 0. The result can be destroyed using free. */
-error_t argz_create(char **argv, char **argz, int *len);
-
-/* Returns the number of strings in ARGZ. */
-int argz_count (char *argz, int len);
-
-/* Puts pointers to each string in ARGZ into ARGV, which must be large enough
- to hold them all. */
-void argz_extract (char *argz, int len, char **argv);
-
-/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
- except the last into the character SEP. */
-void argz_stringify(char *argz, int len, int sep);
-
-/* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */
-error_t
-argz_append (char **argz, unsigned *argz_len, char *buf, unsigned buf_len);
-
-/* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into
- argz.c in libshouldbelibc. */
-error_t argz_add (char **argz, unsigned *argz_len, char *str);
-
-/* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */
-void argz_delete (char **argz, unsigned *argz_len, char *entry);
-
-/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an
- existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end.
- Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN,
- ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not
- in ARGZ, EINVAL is returned, else if memory can't be allocated for the new
- ARGZ, ENOMEM is returned, else 0. */
-error_t
-argz_insert (char **argz, unsigned *argz_len, char *before, char *entry);
-
-/* Returns the next entry in ARGZ & ARGZ_LEN after ENTRY, or NULL if there
- are no more. If entry is NULL, then the first entry is returned. This
- behavior allows two convenient iteration styles:
-
- char *entry = 0;
- while (entry = argz_next (argz, argz_len, entry))
- ...;
-
- or
-
- char *entry;
- for (entry = argz; entry; entry = argz_next (argz, argz_len, entry))
- ...;
-*/
-extern inline char *
-argz_next (char *argz, unsigned argz_len, char *entry)
-{
- if (entry)
- if (entry >= argz + argz_len)
- return 0;
- else
- return entry + strlen (entry) + 1;
- else
- if (argz_len > 0)
- return argz;
- else
- return 0;
-}
-
-#endif /* __ARGZ_H__ */
diff --git a/libshouldbeinlibc/=envz.c b/libshouldbeinlibc/=envz.c
deleted file mode 100644
index 4d0816e4..00000000
--- a/libshouldbeinlibc/=envz.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/* Routines for dealing with '\0' separated environment vectors
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <malloc.h>
-#include <string.h>
-
-#include "envz.h"
-
-/* The character separating names from values in an envz. */
-#define SEP '='
-
-/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none.
- If NAME contains the separator character, only the portion before it is
- used in the comparison. */
-char *
-envz_entry (char *envz, unsigned envz_len, char *name)
-{
- while (envz_len)
- {
- char *p = name;
- char *entry = envz; /* Start of this entry. */
-
- /* See how far NAME and ENTRY match. */
- while (envz_len && *p == *envz && *p && *p != SEP)
- p++, envz++, envz_len--;
-
- if ((*envz == '\0' || *envz == SEP) && (*p == '\0' || *p == SEP))
- /* Bingo! */
- return entry;
-
- /* No match, skip to the next entry. */
- while (envz_len && *envz)
- envz++, envz_len--;
- if (envz_len)
- envz++, envz_len--; /* skip '\0' */
- }
-
- return 0;
-}
-
-/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0
- if there is none. */
-char *
-envz_get (char *envz, unsigned envz_len, char *name)
-{
- char *entry = envz_entry (envz, envz_len, name);
- if (entry)
- {
- while (*entry && *entry != SEP)
- entry++;
- if (*entry)
- entry++;
- else
- entry = 0; /* A null entry. */
- }
- return entry;
-}
-
-/* Remove the entry for NAME from ENVZ & ENVZ_LEN, if any. */
-void
-envz_remove (char **envz, unsigned *envz_len, char *name)
-{
- char *entry = envz_entry (*envz, *envz_len, name);
- if (entry)
- argz_delete (envz, envz_len, entry);
-}
-
-/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN. If an entry
- with the same name already exists in ENVZ, it is removed. If VALUE is
- NULL, then the new entry will a special null one, for which envz_get will
- return NULL, although envz_entry will still return an entry; this is handy
- because when merging with another envz, the null entry can override an
- entry in the other one. Null entries can be removed with envz_strip (). */
-error_t
-envz_add (char **envz, unsigned *envz_len, char *name, char *value)
-{
- envz_remove (envz, envz_len, name);
-
- if (value)
- /* Add the new value, if there is one. */
- {
- unsigned name_len = strlen (name);
- unsigned value_len = strlen (value);
- unsigned old_envz_len = *envz_len;
- unsigned new_envz_len = old_envz_len + name_len + 1 + value_len + 1;
- char *new_envz = realloc (*envz, new_envz_len);
-
- if (new_envz)
- {
- bcopy (name, new_envz + old_envz_len, name_len);
- new_envz[old_envz_len + name_len] = SEP;
- bcopy (value, new_envz + old_envz_len + name_len + 1, value_len);
- new_envz[new_envz_len - 1] = 0;
-
- *envz = new_envz;
- *envz_len = new_envz_len;
-
- return 0;
- }
- else
- return ENOMEM;
- }
- else
- /* Add a null entry. */
- return argz_add (envz, envz_len, name);
-}
-
-/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add(). If
- OVERRIDE is true, then values in ENVZ2 will supercede those with the same
- name in ENV, otherwise not. */
-error_t
-envz_merge (char **envz, unsigned *envz_len, char *envz2, unsigned envz2_len,
- int override)
-{
- error_t err = 0;
-
- while (envz2_len && ! err)
- {
- char *old = envz_entry (*envz, *envz_len, envz2);
- size_t new_len = strlen (envz2) + 1;
-
- if (! old)
- err = argz_append (envz, envz_len, envz2, new_len);
- else if (override)
- {
- argz_delete (envz, envz_len, old);
- err = argz_append (envz, envz_len, envz2, new_len);
- }
-
- envz2 += new_len;
- envz2_len -= new_len;
- }
-
- return err;
-}
-
-/* Remove null entries. */
-void
-envz_strip (char **envz, unsigned *envz_len)
-{
- char *entry = *envz;
- unsigned left = *envz_len;
- while (left)
- {
- unsigned entry_len = strlen (entry) + 1;
- left -= entry_len;
- if (! index (entry, SEP))
- /* Null entry. */
- bcopy (entry, entry + entry_len, left);
- else
- entry += entry_len;
- }
- *envz_len = entry - *envz;
-}
diff --git a/libshouldbeinlibc/=envz.h b/libshouldbeinlibc/=envz.h
deleted file mode 100644
index 55224c72..00000000
--- a/libshouldbeinlibc/=envz.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Routines for dealing with '\0' separated environment vectors
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#ifndef __ENVZ_H__
-#define __ENVZ_H__
-
-#include <errno.h>
-
-/* Envz's are argz's too, and should be created etc., using the same
- routines. */
-#include <argz.h>
-
-/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none. */
-char *envz_entry (char *envz, unsigned envz_len, char *name);
-
-/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0
- if there is none. */
-char *envz_get (char *envz, unsigned envz_len, char *name);
-
-/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN. If an entry
- with the same name already exists in ENVZ, it is removed. If VALUE is
- NULL, then the new entry will a special null one, for which envz_get will
- return NULL, although envz_entry will still return an entry; this is handy
- because when merging with another envz, the null entry can override an
- entry in the other one. Null entries can be removed with envz_strip (). */
-error_t envz_add (char **envz, unsigned *envz_len, char *name, char *value);
-
-/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add(). If
- OVERRIDE is true, then values in ENVZ2 will supercede those with the same
- name in ENV, otherwise not. */
-error_t
-envz_merge (char **envz, unsigned *envz_len, char *envz2, unsigned envz2_len,
- int override);
-
-/* Remove null entries. */
-void envz_strip (char **envz, unsigned *envz_len);
-
-#endif /* __ENVZ_H__ */
diff --git a/libshouldbeinlibc/=line.c b/libshouldbeinlibc/=line.c
deleted file mode 100644
index 1c8eab8e..00000000
--- a/libshouldbeinlibc/=line.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Simple output formatting functions
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <malloc.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <line.h>
-
-/* Return a new line structure, which will output to STREAM. WIDTH is the
- maximum number of characters per line. If enough memory can't be
- allocated, 0 is returned. */
-struct line *
-make_line (FILE *stream, unsigned width)
-{
- struct line *line = malloc (sizeof (struct line));
- if (line)
- {
- line->buf = malloc (width + 2);
- if (line->buf)
- {
- line->max = line->buf + width;
- line->point = line->buf;
- line->stream = stream;
- }
- else
- {
- free (line);
- line = 0;
- }
- }
- return line;
-}
-
-/* Free LINE and any resources it uses. */
-void
-line_free (struct line *line)
-{
- if (line->point > line->buf)
- line_newline (line, 0);
- free (line->buf);
- free (line);
-}
-
-/* Adds the text in STR to LINE, wrapping words as necessary to fit.
- LMARGIN is the left margin used when wrapping; whitespace is deleted at
- wrap-points. Newlines in STR are honoured by adding a newline and
- indenting to LMARGIN; any following whitespace is kept. */
-void
-line_fill (struct line *line, const char *str, unsigned lmargin)
-{
- while (*str)
- {
- const char *word_end = str;
-
- while (*word_end == ' ')
- word_end++;
-
- if (*word_end == '\n')
- {
- if (line_column (line) > lmargin)
- line_newline (line, lmargin);
- str = word_end + 1;
- }
- else if (*word_end)
- {
- const char *word_start = word_end;
- while (*word_end && !isspace (*word_end))
- word_end++;
- if (line_left (line, word_end - str) >= 0)
- {
- line_write (line, str, word_end - str);
- str = word_end;
- }
- else
- /* Word won't fit on the current line, move to the next one. */
- {
- line_newline (line, lmargin);
- str = word_start; /* Omit spaces when wrapping. */
- }
- }
- }
-}
-
-/* Clean up after a printf to LINE, to take care of any newlines that might
- have been added. ADDED is the amount the printf has added to the line.
- We take care of updating LINE's point. */
-void
-_line_cleanup_printf (struct line *line, unsigned added)
-{
- char *point = line->point, *new_point = point + added, *last_nl = new_point;
-
- while (last_nl > point)
- if (*--last_nl == '\n')
- /* There's a newline; deal. */
- {
- last_nl++;
- fwrite (line->buf, 1, last_nl - line->buf, line->stream);
- if (last_nl < new_point)
- bcopy (last_nl, line->buf, new_point - last_nl);
- new_point -= (last_nl - line->buf);
- break;
- }
-
- line->point = new_point;
-}
-
-/* Add STR, of length LEN, to LINE. */
-void
-line_write (struct line *line, const char *str, unsigned len)
-{
- const char *end = memchr (str, '\n', len) ?: str + len;
- unsigned line_len = end - str;
- char *p = line->point, *max = line->max;
- if (line_len > max - p)
- line_len = max - p;
- bcopy (str, p, line_len);
- p += line_len;
- if (line_len == len)
- line->point = p;
- else
- {
- char *buf = line->buf;
- fwrite (buf, 1, p - buf, line->stream);
- line->point = buf;
- line_write (line, end + 1, len - line_len - 1);
- }
-}
diff --git a/libshouldbeinlibc/=line.h b/libshouldbeinlibc/=line.h
deleted file mode 100644
index 54ab15de..00000000
--- a/libshouldbeinlibc/=line.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Simple output formatting functions
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#ifndef __LINE_H__
-#define __LINE_H__
-
-#include <stdio.h>
-
-struct line
-{
- char *buf;
- char *point, *max;
- FILE *stream;
-};
-
-extern void
-_line_cleanup_printf (struct line *line, unsigned added);
-
-/* Printf FMT & ARGS to LINE. */
-/* XXX This implementation is kind of bogus because it pretends to deal with
- newlines in the output, but it just uses LINE's buffer for the output and
- anything past the end of the buffer will get chopped. A terminating
- newline will work ok though. */
-#define line_printf(line, fmt, args...) \
- ({ struct line *_line = (line); \
- _line_cleanup_printf (_line, \
- snprintf (_line->point, _line->max - _line->point, (fmt) , ##args)); \
- })
-
-/* Returns the amount of free space in line after adding AMOUNT characters to
- it (which will be negative if this would overflow). */
-extern inline int
-line_left (struct line *line, unsigned amount)
-{
- return line->max - line->point - amount;
-}
-
-/* Return the column position of LINE's output point, which starts at 0. */
-extern inline unsigned
-line_column (struct line *line)
-{
- return line->point - line->buf;
-}
-
-/* Add enough spaces to LINE to move the point to column TARGET. */
-
-
-extern inline void
-line_indent_to (struct line *line, int target)
-{
- while (line->point < line->buf + target && line->point < line->max)
- *line->point++ = ' ';
-}
-
-/* Emit the current contents of LINE and a newline to its stream, and fill
- LINE with LMARGIN spaces. */
-extern inline void
-line_newline (struct line *line, int lmargin)
-{
- *line->point++ = '\n';
- *line->point = '\0';
- fputs (line->buf, line->stream);
- line->point = line->buf;
- if (lmargin)
- line_indent_to (line, lmargin);
-}
-
-/* If LINE isn't before or at column position LMARGIN, then add a newline
- and indent to that position. */
-extern inline void
-line_freshline (struct line *line, int lmargin)
-{
- if (line_column (line) > lmargin)
- line_newline (line, lmargin);
-}
-
-/* Add a character to LINE, unless it's full. */
-extern inline int
-line_putc (struct line *line, int ch)
-{
- if (ch == '\n')
- line_newline (line, 0);
- else if (line->point < line->max)
- *line->point++ = ch;
- return ch;
-}
-
-/* Adds the text in STR to LINE, wrapping words as necessary to fit. LMARGIN
- is the left margin used when wrapping. */
-void line_fill (struct line *line, const char *str, unsigned lmargin);
-
-/* Add STR, of length LEN, to LINE. */
-void line_write (struct line *line, const char *str, unsigned len);
-
-/* Add STR to LINE. */
-extern inline void line_puts (struct line *line, const char *str)
-{
- line_write (line, str, strlen (str));
-}
-
-/* Return a new line structure, which will output to STREAM. WIDTH is the
- maximum number of characters per line. If enough memory can't be
- allocated, 0 is returned. */
-struct line *make_line (FILE *stream, unsigned width);
-
-/* Free LINE and any resources it uses. */
-void line_free (struct line *line);
-
-#endif /* __LINE_H__ */
diff --git a/libshouldbeinlibc/=path-lookup.c b/libshouldbeinlibc/=path-lookup.c
deleted file mode 100644
index b89f8d4d..00000000
--- a/libshouldbeinlibc/=path-lookup.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/* Filename lookup using a search path
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <string.h>
-#include <hurd.h>
-#include <hurd/lookup.h>
-
-/* If FILE_NAME contains a '/', or PATH is NULL, call FUN with FILE_NAME, and
- return the result (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to
- NULL). Otherwise, call FUN repeatedly with FILE_NAME prefixed with each
- successive `:' separated element of PATH, returning whenever FUN returns
- 0 (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to the resulting
- prefixed path). If FUN never returns 0, return the first non-ENOENT
- return value, or ENOENT if there is none. */
-error_t
-file_name_path_scan (const char *file_name, const char *path,
- error_t (*fun)(const char *name),
- char **prefixed_name)
-{
- if (path == NULL || index (file_name, '/'))
- {
- if (prefixed_name)
- *prefixed_name = 0;
- return (*fun)(file_name);
- }
- else
- {
- error_t real_err = 0;
- size_t file_name_len = strlen (file_name);
-
- for (;;)
- {
- error_t err;
- const char *next = index (path, ':') ?: path + strlen (path);
- size_t pfx_len = next - path;
- char pfxed_name[pfx_len + 2 + file_name_len + 1];
-
- if (pfx_len == 0)
- pfxed_name[pfx_len++] = '.';
- else
- bcopy (path, pfxed_name, pfx_len);
- if (pfxed_name[pfx_len - 1] != '/')
- pfxed_name[pfx_len++] = '/';
- bcopy (file_name, pfxed_name + pfx_len, file_name_len + 1);
-
- err = (*fun)(pfxed_name);
- if (err == 0)
- {
- if (prefixed_name)
- *prefixed_name = strdup (pfxed_name);
- return 0;
- }
- if (!real_err && err != ENOENT)
- real_err = err;
-
- if (*next == '\0')
- return real_err ?: ENOENT;
- else
- path = next + 1;
- }
- }
-}
-
-/* Lookup FILE_NAME and return the node opened with FLAGS & MODE in result
- (see hurd_file_name_lookup for details), but a simple filename (without
- any directory prefixes) will be consectutively prefixed with the pathnames
- in the `:' separated list PATH until one succeeds in a successful lookup.
- If none succeed, then the first error that wasn't ENOENT is returned, or
- ENOENT if no other errors were returned. If PREFIXED_NAME is non-NULL,
- then if RESULT is looked up directly, *PREFIXED_NAME is set to NULL, and
- if it is looked up using a prefix from PATH, *PREFIXED_NAME is set to
- malloced storage containing the prefixed name. */
-error_t
-hurd_file_name_path_lookup (error_t (*use_init_port)
- (int which,
- error_t (*operate) (mach_port_t)),
- file_t (*get_dtable_port) (int fd),
- const char *file_name, const char *path,
- int flags, mode_t mode,
- file_t *result, char **prefixed_name)
-{
- error_t lookup (const char *name)
- {
- return
- __hurd_file_name_lookup (use_init_port, get_dtable_port,
- name, flags, mode, result);
- }
- return file_name_path_scan (file_name, path, lookup, prefixed_name);
-}
-
-mach_port_t
-file_name_path_lookup (const char *file_name, const char *path,
- int flags, mode_t mode, char **prefixed_name)
-{
- error_t err;
- file_t result;
-
- err = hurd_file_name_path_lookup (&_hurd_ports_use, &__getdport,
- file_name, path, flags, mode,
- &result, prefixed_name);
-
- return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
-}
diff --git a/libshouldbeinlibc/ChangeLog b/libshouldbeinlibc/ChangeLog
deleted file mode 100644
index ab2b938f..00000000
--- a/libshouldbeinlibc/ChangeLog
+++ /dev/null
@@ -1,614 +0,0 @@
-Wed Jul 31 15:24:09 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * wire.c (_start): No longer declared as weak, now that everything
- is getting recompiled anyway.
-
-Fri Jul 26 20:57:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_past_time): Always use WIDTH+1 as strftime's limit.
-
-Thu Jul 25 23:10:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_past_time): Terminate SEPS.
-
- * argp-help.c (hol_entry_help): Never return without restoring margins.
-
-Mon Jul 22 23:41:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_past_time): Try several separators when
- concatenating dates & times.
-
-Fri Jul 19 17:23:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c (hol_usage): Allocate enough space in
- SHORT_NO_ARG_OPTS for the '\0' terminator.
-
-Tue Jul 16 00:24:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c (argp_help): Set the lmargin after printing the
- start of the usage message, so that it won't get indented.
-
-Wed Jul 10 12:16:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_version_options, argp_version_parser): Use an
- uppercase 'V' for short version option.
-
- * argp-help.c (argp_help): "OPTIONS..." -> "OPTION...".
-
-Sat Jul 6 16:17:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_version_parser): Output ARGP_PROGRAM_VERSION
- to STATE->out_stream, not stdout. Supply that stream and STATE to
- ARGP_PROGRAM_VERSION_HOOK.
- * argp.h (argp_program_version_hook): Add argument types.
- * argp-pv.c (argp_program_version): Doc updated.
- * argp-pvh.c (argp_program_version_hook): Type & doc updated.
- "argp.h": New include.
-
-Fri Jul 5 17:13:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_past_time): Get rid of extraneous `f' in fmt string.
-
-Thu Jun 27 17:09:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): Zero the CHILD_INPUTS vector.
-
-Fri Jun 21 17:15:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): Use group_parse instead of calling
- group parser directly for long options.
-
-Wed Jun 19 13:11:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsysops.c: New file.
- * Makefile (SRCS): Add fsysops.c.
-
-Tue Jun 18 21:09:52 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c (argp_failure): If FMT is 0, don't print `: MSG'.
-
-Sun Jun 16 19:25:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (SRCS): Remove line.c.
- (LCLHDRS): Remove line.h.
-
- * argp-help.c (argp_help, argp_state_help, argp_error, argp_failure):
- Handle null streams.
-
- * argp.h (struct argp_state): Add NAME, ERR_STREAM, & OUT_STREAM
- fields.
- (argp_failure): New declaration.
- (ARGP_NO_HELP, ARGP_NO_EXIT): Fix values (were hex, but with
- decimal value!).
- (argp_help): Add NAME argument.
- * argp-parse.c (argp_default_parser): Output to STATE->out_stream.
- (argp_parse): Initialize new fields in STATE.
- Output errors to STATE.err_stream. Handle null streams.
-
- * argp-help.c (argp_help): Add and use NAME argument.
- (argp_error): Use STATE->err_stream instead of STDERR.
- (argp_state_help): Supply NAME argument to argp_help.
- (argp_failure): New function.
-
-Thu May 30 18:10:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c (indent_to): Terminate.
-
-Tue May 28 18:05:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_seconds): Don't print two decimal points.
-
-Wed May 22 00:11:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_default_parser): Break after --HANG.
-
- * argp-help.c (hol_usage): Prefix each option desc with a space.
- Do manual wrapping of descs with an embedded space.
- Don't set wrap margin (done elsewhere now).
- (argp_args_usage): Do manual line wrapping because of embedded spaces.
- (argp_help): Set wrap & left margins when printing usage.
-
- * argp-parse.c (argp_parse): Only print a `Try...' message if the
- error was a parsing error.
-
-Tue May 14 21:59:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (add_field): Correctly decrement *SECS by amount printed.
-
- * timefmt.c (fmt_named_interval): Use fraction digit in more cases.
- Always pick the last suffix if we can't find any that fits.
- Use new tv_ functions.
- (tv_is_zero, tv_is_ge): New functions.
-
-Fri May 10 23:17:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (ARGP_ERR_UNKNOWN): New define.
- * argp-parse.c (EBADKEY): New define.
- (argp_default_parser, argp_version_parser, argp_parse): Use
- EBADKEY instead of EINVAL. Turn any EBADKEY that makes it to the
- end back into EINVAL.
-
-Thu May 9 11:30:47 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * maptime.c (maptime_map): Use new file_get_storage_info interface.
-
- * argp-help.c (argp_help): Just assign STREAM instead of using 2 vars.
-
-Thu May 9 11:00:52 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * exec-reauth.c (exec_reauth): Use new args to
- auth_user_authenticate.
-
- * timefmt.c (fmt_past_time): Cast arg to localtime appropriately.
-
- * argp-help.c (argp_args_usage): add_usage_item -> fprintf.
- (argp_help): Don't shadow arg; change parm STREAM to be STREAMARG
- and adjust initialization of STREAM variable to use the renamed
- parm.
-
-Tue May 7 14:58:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_past_time): Suppress leading noise in some formats.
-
- * argp-help.c (hol_usage): Set the wmargin, not the lmargin.
- (hol_help): Set the wmargin as well as the lmargin.
- * argp-help.c <linewrap.h>: New include.
- (lmargin): Function deleted.
- (hol_entry_help, hol_usage): Use line_wrap_set_lmargin instead.
-
-Mon May 6 12:46:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c <line.h>: Include removed.
- (lmargin, indent_to): New functions.
- (argp_usage_arg): Function removed.
- (hol_entry_help, hol_help, hol_usage, argp_args_usage, argp_doc,
- argp_help): Use stdio streams and line_wrap_ functions instead of
- line_ functions.
-
-Sat May 4 05:32:28 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * rwlock.h: Moved to ../libthreads.
- * Makefile (LCLHDRS): Remove rwlock.h.
-
-Fri May 3 18:10:41 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * path-lookup.c: File removed.
- * Makefile (SRCS): Remove path-lookup.c.
-
- * argz.c, argz.h, envz.c, envz.h: Files removed.
- * Makefile (SRCS): Remove argz.c, envz.c.
- (LCLHDRS): Remove argz.h, envz.h.
-
-Thu May 2 00:31:32 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (_argp_hang): New variable.
- (OPT_HANG): New macro.
- (argp_default_options, argp_default_parser): Add hidden --HANG option.
- (argp_default_parser): New function.
- (argp_version_options, argp_version_argp): New variables.
- (argp_parse): Use ARGP_VERSION_ARGP when appropiate.
- * argp.h (argp_program_version, argp_program_version_hook): New decls.
- * Makefile (SRCS): Add argp-pv.c & argp-pvh.c.
- * argp-pv.c, argp-pvh.c: New files.
-
-Tue Apr 30 20:25:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_past_time): New function.
- (fmt_minutes, fmt_seconds): New args, rewrite.
- (add_field): New function.
- (fmt_frac_value, append_fraction): Functions removed.
- * timefmt.h (fmt_past_time): New declaration.
- (fmt_minutes, fmt_seconds): Update.
-
- * argp-parse.c (argp_parse): Work with ARGP == 0.
-
-Mon Apr 29 15:34:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * cacheq.c, cacheq.h: New files.
- * Makefile (SRCS): Add cacheq.c.
- (LCLHDRS): Add cacheq.h.
-
-Thu Apr 25 00:09:48 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * idvec.c (idvec_free_contents): New function.
- * idvec.h (idvec_free_contents): Declare it.
-
-Thu Apr 11 15:23:15 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wire.c (wire_segment_internal): Cast values nicely in `poke'
- loop.
-
-Wed Apr 3 12:57:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (argp_parse): Change HOOK argument to INPUT.
- (struct argp_state): Rename HOOK & CHILD_HOOKS to INPUT & CHILD_INPUTS;
- add HOOK field again.
- * argp-parse.c (argp_parse): Change HOOK argument to INPUT.
- Don't propagate back return values when we're done.
- (struct group): Rename HOOK & CHILD_HOOKS to INPUT & CHILD_INPUTS;
- add HOOK field again.
- (group_parse): Restore and save value of GROUP's hook field into
- STATE around calling the parser. Don't save changed value of INPUT.
-
-Tue Apr 2 18:25:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * lcm.c: New file.
- * Makefile (SRCS): Add lcm.c.
-
-Thu Mar 28 19:06:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c, xportinfo.c, portinfo.h: New files.
- * portxlate.c, portxlate.h: New files.
- * Makefile (LCLHDRS): Add portinfo.h, portxlate.h.
- (SRCS): Add portinfo.c, xportinfo.c, portxlate.c.
-
-Tue Mar 26 17:43:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * wire.c: Add a weak reference to _start, so we don't have to
- compile all users of this library.
-
-Mon Mar 25 18:38:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * timefmt.c (fmt_named_interval): Rationalize WIDTH.
-
-Mon Mar 25 16:11:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wire.h, wire.c: New files.
- * Makefile (SRCS): Add wire.c.
- (LCLHDRS): Add wire.h.
-
-Mon Mar 25 16:06:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * envz.c (envz_merge): NEW_LEN is a size, not a char.
-
-Mon Mar 18 14:09:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (struct argp_state): Add HOOK and CHILD_HOOKS fields.
- Rename the PARENTS field to be CHILDREN (the most common use is
- initialization, so this change shouldn't have much effect).
- (ARGP_KEY_BEGIN, ARGP_KEY_ERROR): New macros.
- * argp-parse.c (struct group): Add PARENT, PARENT_INDEX, HOOK, and
- CHILD_HOOKS fields.
- (argp_parse): Add HOOK argument.
- Implement passing hook values to parsers, and propagating them
- between parents and children.
- * argp-help.c (argp_doc, argp_args_usage, argp_hol): Rename
- PARENTS field to CHILDREN.
-
- * argp-help.c (argp_error): Take an argp_state instead of an argp,
- and only doing anything if ARGP_NO_ERRS isn't set in it.
- (argp_state_help): New function.
- (argp_help): Don't interpret exiting options anymore.
- * argp-parse.c (argp_default_options): Add --usage option.
- (argp_default_parser): Use argp_state_help, so we don't need to
- screw with exit options anymore.
- Add usage option.
- (argp_parse): When printing `too many arguments', test
- ARGP_NO_ERRS instead of ARGP_NO_HELP.
- * argp.h (argp_state_help): New function.
- (argp_usage, argp_error): Change arguments.
-
-Fri Mar 1 18:59:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c (hol_entry_help): Don't print extraneous blank lines.
-
-Wed Feb 28 18:44:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): Print an error message if appropiate
- when we know there are too many arguments.
-
- * argp-help.c (hol_entry_help): Handle null group headers nicely.
-
-Wed Feb 28 16:09:27 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * maptime.c (maptime_map): mapped_time_value arg is volatile data.
- * maptime.h (maptime_map): Likewise.
-
-Sat Feb 17 21:34:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * shared-dom.c, localhost.c: New file.
- * Makefile (SRCS): Add shared-dom.c and localhost.c.
-
-Fri Feb 16 15:54:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * maptime.c, maptime.h: New files.
- * Makefile (SRCS, LCLHDRS): Add maptime.c and maptime.h respectively.
-
- * timefmt.c (fmt_named_interval): Correct backwards comparison.
-
-Thu Feb 15 15:18:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * canon-host.c: New file.
- * Makefile (SRCS): Add canon-host.c.
-
- * argp-parse.c (argp_parse): Correctly deal with errors from
- getopt, and allow the user to use '?' as a short option.
- (KEY_ERR): New macro.
- (argp_default_options, argp_default_parser): Use -? as the short
- option for --help.
-
-Wed Feb 14 14:33:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): Make things a bit more readable by
- using the TRY_GETOPT variable in place of opt == EOF.
- Use KEY_END, KEY_ARG, and QUOTE.
- Clear STATE.quoted if STATE.next has been moved back before it.
- (KEY_END): New macro, in place of EOF.
- (KEY_ARG, QUOTE): New macros.
-
-Mon Feb 12 15:08:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): Don't parse args in order by
- default. Honor ARGP_NO_ARGS.
- Deal correctly when the user turns a non-option arg into an option
- in re-ordering mode.
- * argp.h (struct argp_state): Add `quoted' field.
-
-Thu Feb 8 19:35:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): When a non-option arg fails to be
- parsed with EINVAL, set ARG_EINVAL true, and leave ERR as is until
- just before we return.
- Put process_arg() in the right scope.
-
-Wed Feb 7 23:08:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): Deal with getopt returning EOF early
- because of `--'.
-
- * argp-parse.c (argp_parse): Make STATE.arg_num per-group.
- (struct group): Renamed process_arg field to args_processed (a count).
-
-Mon Feb 5 13:39:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (struct argp_state): Add ARG_NUM field.
- * argp-parse.c (argp_parse): Implement the ARG_NUM field.
-
- * argp.h (struct argp, struct argp_state, argp_parse, argp_help,
- argp_usage, argp_error, _option_is_short, _option_is_end): Add `const'
- where appropriate.
- * argp-parse.c (argp_default_options, argp_default_argp,
- argp_parse, find_long_option): Likewise.
- * argp-help.c (struct hol_entry, make_hol,
- hol_entry_short_iterate, hol_entry_long_iterate,
- hol_entry_first_short, hol_entry_first_long, hol_find_entry,
- hol_sort, hol_entry_help, argp_hol, argp_args_usage, argp_doc,
- argp_help, argp_error): Likewise.
- * line.h (line_write, line_fill, line_puts): Likewise.
- * line.c (line_write, line_fill): Likewise.
-
-Sat Feb 3 02:00:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * idvec.c (idvec_merge_ids): Correctly add all IDS, even if some
- duplicates are avoided.
-
-Tue Jan 23 15:02:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c (hol_entry_help): Correctly print group headers, and
- precede them with a blank line.
- (hol_set_group): Renamed from hol_set_sort_class.
- (argp_help): Use hol_set_group instead of hol_set_sort_class.
- (struct hol_entry, make_hol, hol_sort, hol_set_group): Rename the
- `set_class' field to be `group'.
- (hol_help, hol_entry_help): After a group header has been printed,
- separate subsequent groups with a blank line.
-
-Mon Jan 15 11:01:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * path-lookup.c (hurd_file_name_path_lookup, file_name_path_lookup):
- Add PREFIXED_NAME (return) argument.
- (file_name_path_scan): New function.
- (hurd_file_name_path_lookup): Use file_name_path_scan().
-
-Tue Jan 2 01:24:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_default_options, argp_default_parser): Add
- --program-name (hidden) option.
- (OPT_PROGNAME): New macro.
-
- * idvec.c (idvec_merge_ids): Preserve duplicates internal to IDS.
- (idvec_ensure): Alloc NUM ids, not NUM chars!
- (idvec_remove): Correctly copy ids when deleting.
- * idvec.h (idvec_merge, idvec_delete): New declarations.
-
- * idvec-auth.c (idvec_merge_auth): Fix various small typos.
-
- * argz.c (argz_delete): If the result is empty, free it.
-
- * exec-reauth.c (exec_reauth): Doc fix.
-
- * argz.h (argz_delete): Renamed from argz_remove.
- * argz.c (argz_delete): Ditto.
- (argz_insert): Deref ARGZ where necessary.
- * envz.c (envz_merge): Rename argz_remove to argz_delete.
-
-Mon Jan 1 17:48:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * idvec.c (idvec_remove, idvec_insert_only): New functions.
- (idvec_setid): Use idvec_insert_only() instead of idvec_insert_new().
- * idvec.h (idvec_remove, idvec_insert_only): New declarations.
-
- * Makefile (SRCS): Add exec-reauth.c.
-
- * idvec.c (idvec_free_wrapper, idvec_free, idvec_ensure,
- idvec_grow, idvec_tail_contains, idvec_add_new, idvec_insert_new,
- idvec_merge_ids, idvec_setid): New functions.
- (idvec_insert): Rewritten to use idvec_grow().
- * idvec-auth.c (idvec_merge_auth): New function.
- * idvec.h (idvec_free_wrapper, idvec_free, idvec_ensure,
- idvec_grow, idvec_tail_contains, idvec_add_new, idvec_insert_new,
- idvec_merge_ids, idvec_setid, idvec_merge_auth): New declarations.
- * Makefile (SRCS): Added idvec-auth.c.
-
-Fri Dec 29 12:15:00 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (_argp_unlock_xxx): New function.
-
-Thu Dec 21 10:18:04 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * idvec.h (struct idvec): Renamed from struct ivec. `ints' field
- renamed to `ids'.
- (make_idvec, idvec_insert, idvec_add, idvec_contains):
- All renamed from the corresponding `ivec' declaration, and types,
- variable names, etc, changed accordingly.
- * idvec.c (make_idvec, idvec_insert, idvec_add, idvec_contains):
- All renamed from the corresponding `ivec' routine, and types,
- variable names, etc, changed accordingly.
- * Makefile (SRCS): Remove options.c. Rename ivec.c to idvec.c.
- (LCLHDRS): Remove options.h. Rename ivec.h to idvec.h.
-
-Wed Dec 20 13:05:00 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argz.c (argz_insert): Instead of an integer position N, take a
- pointer BEFORE into ARGZ to insert before.
- * argz.h (argz_insert): Instead of an integer position N, take a
- pointer BEFORE into ARGZ to insert before.
- (argz_next): New inline function.
-
-Tue Dec 19 13:52:52 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (struct argp_option): Add the GROUP field. Twiddle doc.
- (_option_is_end): Be more pessimistic about what constitutes `the end'.
- * argp-help.c (make_hol): Use the new GROUP field in struct
- argp_option to initialize sort_classes.
- (HEADER_COL): New macro.
- (hol_entry_help): Deal with group headers.
- * argp-parse.c (argp_default_options): Put --help in group -1.
-
-Sun Dec 17 00:18:58 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ivec.c: New file.
- * ivec.h: New file.
- * Makefile (LCLHDRS): Add ivec.h.
- (SRCS): Add ivec.c.
-
-Sat Dec 16 17:42:27 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * termsize.c (deduce_term_size): New function, new file.
- * Makefile (SRCS): Add termsize.c.
-
- * argz.c (argz_insert): New function.
- (argz_remove, argz_append, argz_add): New functions, were in envz.c.
- * argz.h (argz_insert): New declaration.
-
-Thu Dec 14 18:04:48 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argz.h (argz_append, argz_add, argz_remove): New functions.
-
-Wed Dec 13 14:28:12 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * envz.c: New file.
- * envz.h: New file.
- * Makefile (SRCS): Add envz.c.
- (LCLHDRS): Add envz.h
-
-Wed Dec 6 15:05:43 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (struct argp_state): Rename the INDEX field to be NEXT.
- * argp-parse.c (argp_parse): Change uses of that field.
-
- * argz.c (argz_stringify): Add the SEP argument.
- * argz.h (argz_stringify): Ditto.
-
-Tue Dec 5 18:38:40 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (SRCS, LCLHDRS): Removed error.c and error.h.
- (CPPFLAGS-error.c): Variable removed.
- * error.c, error.h: Files removed.
-
-Thu Oct 19 18:39:59 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (argp_usage, argp_error): New declarations.
- (argp_usage): New inline function.
- * argp-help.c (argp_error): New function.
-
-Fri Oct 13 19:28:28 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h (ARGP_HELP_STD_ERR): Doesn't print a usage message.
- (ARGP_HELP_STD_USAGE): ... whereas this does.
-
-Thu Oct 12 15:57:18 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-parse.c (argp_parse): Correctly mark short options as optional.
- (argp_parse): If an option alias doesn't have a key, use the real key.
-
-Wed Oct 11 13:54:18 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp-help.c (hol_find_entry): Don't increment ENTRY prematurely.
-
- * argp-parse.c (argp_parse): Update STATE.argp when adding a
- wrapper to implement the --help option.
- In general, use the version of variables that are in STATE.
- Update STATE.index in the case where getopt returns EOF.
- (argp_parse): Correctly translate options.
-
- * line.c (line_write): New function.
- (line_puts): Function deleted.
- (line_fill): Use line_write instead of line_printf.
- * line.h (line_write): New declaration.
- (line_puts): Rewrite in terms of line_write.
-
- * argp-help.c (hol_entry_help): Print the right documentation
- string for each entry.
-
- * argp-parse.c (argp_default_parser, argp_parse): Rename uses of
- argp_usage* to argp_help*.
-
- * argp-help.c (argp_help): Renamed from argp_usage.
- * argp.h (ARGP_HELP_*, argp_help): Renamed from ARGP_USAGE_* &c.
-
- * argp.h (ARGP_USAGE_STD_HELP): Use ARGP_USAGE_SHORT_USAGE instead
- of ARGP_USAGE_USAGE.
-
- * argp-help.c (make_hol): Deal with a null value of OPT. If there
- are no entries, don't define the ENTRIES or SHORT_OPTIONS fields.
- (hol_free): Don't free ENTRIES or SHORT_OPTIONS unless there are any.
- (hol_sort): Don't sort unless there are some entries.
- (hol_usage): Don't do anything unless there are some entries.
- (hol_sort): Sort int he correct order.
- (argp_usage): Add the ARGP_USAGE_SHORT_USAGE case.
-
- * argp-parse.c (argp_parse): Deal with null parser or option fields.
- If an argp has neither a parser or any options, don't put it in GROUPS.
- Use comparison with EGROUP, rather than testing the parser field,
- the end test for iteration over GROUPS.
-
- * argp-help.c (hol_append): Implement.
-
- * argp-parse.c (argp_parse): Pass in the right value for GROUPS to
- convert_options.
-
- * Makefile (SRCS): Add argp-parse.c, argp-help.c, and line.c
- (LCLHDRS): Add line.h and argp.h.
-
-Tue Oct 10 17:58:14 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.h: Doc fixes.
-
- * argp.h: (ARGP_KEY_NO_ARGS): New macro.
- * argp-parse.c (argp_parse): Add support for ARGP_KEY_NO_ARGS.
- Put all the group attributes into structures which get stored in
- the GROUPS array, rather than having a separate array for each.
-
-Sat Oct 7 03:32:51 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * rwlock.h: Protect against multiple inclusion.
- Include cthreads.h and assert.h.
-
-Wed Sep 27 17:37:08 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * options.c (options_parse): Use 0 as the tag for non-option args.
- * options.h: Ditto.
-
-Sat Sep 23 14:15:01 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * rwlock.h (RWLOCK_INITIALIZER): New macro.
-
-Sat Sep 16 13:40:22 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (lndist, $(srcdir)/hurd-snap/$(dir)/error.[ch]):
- Targets removed.
-
-Thu Aug 24 11:49:13 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * options.c: Include "options.h" instead of <options.h>.
diff --git a/libshouldbeinlibc/Makefile b/libshouldbeinlibc/Makefile
index 1a00dac1..0787d2d6 100644
--- a/libshouldbeinlibc/Makefile
+++ b/libshouldbeinlibc/Makefile
@@ -1,6 +1,6 @@
# Makefile for libshouldbeinlibc
#
-# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1995,96,97,98,99,2002 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
@@ -20,13 +20,17 @@ dir := libshouldbeinlibc
makemode := library
libname = libshouldbeinlibc
-SRCS = argp-parse.c argp-help.c argp-pv.c argp-pvh.c \
- termsize.c idvec.c idvec-auth.c timefmt.c exec-reauth.c \
- canon-host.c maptime.c shared-dom.c localhost.c wire.c portinfo.c \
- xportinfo.c portxlate.c lcm.c cacheq.c fsysops.c
-LCLHDRS = argp.h idvec.h timefmt.h maptime.h \
- wire.h portinfo.h portxlate.h cacheq.h
-installhdrs = $(LCLHDRS)
+SRCS = termsize.c timefmt.c exec-reauth.c maptime-funcs.c \
+ canon-host.c maptime.c shared-dom.c localhost.c wire.c portinfo.c \
+ xportinfo.c portxlate.c lcm.c cacheq.c fsysops.c \
+ idvec.c idvec-auth.c idvec-funcs.c \
+ idvec-impgids.c idvec-verify.c idvec-rep.c \
+ ugids.c ugids-argp.c ugids-rep.c ugids-verify.c ugids-subtract.c \
+ ugids-auth.c ugids-xinl.c ugids-merge.c ugids-imply.c ugids-posix.c \
+ ugids-verify-auth.c
+installhdrs = idvec.h timefmt.h maptime.h \
+ wire.h portinfo.h portxlate.h cacheq.h ugids.h
+LCLHDRS = $(installhdrs)
installhdrsubdir = .
OBJS = $(SRCS:.c=.o)
diff --git a/libshouldbeinlibc/argp-help.c b/libshouldbeinlibc/argp-help.c
deleted file mode 100644
index b8b519e2..00000000
--- a/libshouldbeinlibc/argp-help.c
+++ /dev/null
@@ -1,908 +0,0 @@
-/* Hierarchial argument parsing help output
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <linewrap.h>
-
-#include "argp.h"
-
-#define SHORT_OPT_COL 2 /* column in which short options start */
-#define LONG_OPT_COL 6 /* column in which long options start */
-#define OPT_DOC_COL 29 /* column in which option text starts */
-#define HEADER_COL 1 /* column in which group headers are printed */
-#define USAGE_INDENT 12 /* indentation of wrapped usage lines */
-#define RMARGIN 79 /* right margin used for wrapping */
-
-/* Returns true if OPT hasn't been marked invisible. Visibility only affects
- whether OPT is displayed or used in sorting, not option shadowing. */
-#define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN))
-
-/* Returns true if OPT is an alias for an earlier option. */
-#define oalias(opt) ((opt)->flags & OPTION_ALIAS)
-
-/* Returns true if OPT is the end-of-list marker for a list of options. */
-#define oend(opt) _option_is_end (opt)
-
-/* Returns true if OPT has a short option. */
-#define oshort(opt) _option_is_short (opt)
-
-/*
- The help format for a particular option is like:
-
- -xARG, -yARG, --long1=ARG, --long2=ARG Documentation...
-
- Where ARG will be omitted if there's no argument, for this option, or
- will be surrounded by "[" and "]" appropiately if the argument is
- optional. The documentation string is word-wrapped appropiately, and if
- the list of options is long enough, it will be started on a separate line.
- If there are no short options for a given option, the first long option is
- indented slighly in a way that's supposed to make most long options appear
- to be in a separate column.
-
- For example (from ps):
-
- -p PID, --pid=PID List the process PID
- --pgrp=PGRP List processes in the process group PGRP
- -P, -x, --no-parent Include processes without parents
- -Q, --all-fields Don't elide unusable fields (normally if there's
- some reason ps can't print a field for any
- process, it's removed from the output entirely)
- -r, --reverse, --gratuitously-long-reverse-option
- Reverse the order of any sort
- --session[=SID] Add the processes from the session SID (which
- defaults to the sid of the current process)
-
- The struct argp_option array for the above could look like:
-
- {
- {"pid", 'p', "PID", 0,
- "List the process PID"},
- {"pgrp", OPT_PGRP, "PGRP", 0,
- "List processes in the process group PGRP"},
- {"no-parent", 'P', 0, 0,
- "Include processes without parents"},
- {0, 'x', 0, OPTION_ALIAS},
- {"all-fields",'Q', 0, 0,
- "Don't elide unusable fields (normally if there's some reason ps \
-can't print a field for any process, it's removed from the output entirely)"},
- {"reverse", 'r', 0, 0,
- "Reverse the order of any sort"},
- {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
- {"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL,
- "Add the processes from the session SID (which defaults to the sid of \
-the current process)"},
- }
-
-*/
-
-/* Returns true if CH occurs between BEG and END. */
-static int
-find_char (char ch, char *beg, char *end)
-{
- while (beg < end)
- if (*beg == ch)
- return 1;
- else
- beg++;
- return 0;
-}
-
-struct hol_entry
-{
- /* First option. */
- const struct argp_option *opt;
- /* Number of options (including aliases). */
- unsigned num;
-
- /* A pointers into the HOL's short_options field, to the first short option
- letter for this entry. The order of the characters following this point
- corresponds to the order of options pointed to by OPT, and there are at
- most NUM. A short option recorded in a option following OPT is only
- valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's
- probably been shadowed by some other entry). */
- char *short_options;
-
- /* Entries are sorted by their group first, in the order:
- 1, 2, ..., n, 0, -m, ..., -2, -1
- and then alphabetically within each group. The default is 0. */
- int group;
-};
-
-/* A list of options for help. */
-struct hol
-{
- /* The number of entries in this hol. If this field is zero, the others
- are undefined. */
- unsigned num_entries;
- /* An array of hol_entry's. */
- struct hol_entry *entries;
- /* A string containing all short options in this HOL. Each entry contains
- pointers into this string, so the order can't be messed with blindly. */
- char *short_options;
-};
-
-/* Create a struct hol from an array of struct argp_option. */
-struct hol *make_hol (const struct argp_option *opt)
-{
- char *so;
- const struct argp_option *o;
- struct hol_entry *entry;
- unsigned num_short_options = 0;
- struct hol *hol = malloc (sizeof (struct hol));
-
- assert (hol);
-
- hol->num_entries = 0;
-
- if (opt)
- {
- int cur_group = 0;
-
- /* The first option must not be an alias. */
- assert (! oalias (opt));
-
- /* Calculate the space needed. */
- for (o = opt; ! oend (o); o++)
- {
- if (! oalias (o))
- hol->num_entries++;
- if (oshort (o))
- num_short_options++; /* This is an upper bound. */
- }
-
- hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries);
- hol->short_options = malloc (num_short_options + 1);
-
- assert (hol->entries && hol->short_options);
-
- /* Fill in the entries. */
- so = hol->short_options;
- for (o = opt, entry = hol->entries; ! oend (o); entry++)
- {
- entry->opt = o;
- entry->num = 0;
- entry->short_options = so;
- entry->group = cur_group = o->group ?: cur_group;
-
- do
- {
- entry->num++;
- if (oshort (o) && ! find_char (o->key, hol->short_options, so))
- /* O has a valid short option which hasn't already been used.*/
- *so++ = o->key;
- o++;
- }
- while (! oend (o) && oalias (o));
- }
- *so = '\0'; /* null terminated so we can find the length */
- }
-
- return hol;
-}
-
-/* Free HOL and any resources it uses. */
-static void
-hol_free (struct hol *hol)
-{
- if (hol->num_entries > 0)
- {
- free (hol->entries);
- free (hol->short_options);
- }
- free (hol);
-}
-
-static inline int
-hol_entry_short_iterate (const struct hol_entry *entry,
- int (*func)(const struct argp_option *opt,
- const struct argp_option *real))
-{
- unsigned nopts;
- int val = 0;
- const struct argp_option *opt, *real = entry->opt;
- char *so = entry->short_options;
-
- for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
- if (oshort (opt) && *so == opt->key)
- {
- if (!oalias (opt))
- real = opt;
- if (ovisible (opt))
- val = (*func)(opt, real);
- so++;
- }
-
- return val;
-}
-
-static inline int
-hol_entry_long_iterate (const struct hol_entry *entry,
- int (*func)(const struct argp_option *opt,
- const struct argp_option *real))
-{
- unsigned nopts;
- int val = 0;
- const struct argp_option *opt, *real = entry->opt;
-
- for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--)
- if (opt->name)
- {
- if (!oalias (opt))
- real = opt;
- if (ovisible (opt))
- val = (*func)(opt, real);
- }
-
- return val;
-}
-
-/* Returns the first valid short option in ENTRY, or 0 if there is none. */
-static char
-hol_entry_first_short (const struct hol_entry *entry)
-{
- inline int func1 (const struct argp_option *opt,
- const struct argp_option *real)
- {
- return opt->key;
- }
- return hol_entry_short_iterate (entry, func1);
-}
-
-/* Returns the first valid long option in ENTRY, or 0 if there is none. */
-static const char *
-hol_entry_first_long (const struct hol_entry *entry)
-{
- const struct argp_option *opt;
- unsigned num;
- for (opt = entry->opt, num = entry->num; num > 0; opt++, num--)
- if (opt->name && ovisible (opt))
- return opt->name;
- return 0;
-}
-
-/* Returns the entry in HOL with the long option name NAME, or 0 if there is
- none. */
-static struct hol_entry *hol_find_entry (struct hol *hol, char *name)
-{
- struct hol_entry *entry = hol->entries;
- unsigned num_entries = hol->num_entries;
-
- while (num_entries-- > 0)
- {
- const struct argp_option *opt = entry->opt;
- unsigned num_opts = entry->num;
-
- while (num_opts-- > 0)
- if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0)
- return entry;
- else
- opt++;
-
- entry++;
- }
-
- return 0;
-}
-
-/* If an entry with the long option NAME occurs in HOL, set it's special
- sort position to GROUP. */
-static void
-hol_set_group (struct hol *hol, char *name, int group)
-{
- struct hol_entry *entry = hol_find_entry (hol, name);
- if (entry)
- entry->group = group;
-}
-
-/* Sort HOL by group and alphabetically by option name (with short options
- taking precedence over long). Since the sorting is for display purposes
- only, the shadowing of options isn't effected. */
-static void
-hol_sort (struct hol *hol)
-{
- int entry_cmp (const void *entry1_v, const void *entry2_v)
- {
- const struct hol_entry *entry1 = entry1_v, *entry2 = entry2_v;
- int group1 = entry1->group, group2 = entry2->group;
-
- if (group1 == group2)
- /* Normal comparison. */
- {
- int short1 = hol_entry_first_short (entry1);
- int short2 = hol_entry_first_short (entry2);
- const char *long1 = hol_entry_first_long (entry1);
- const char *long2 = hol_entry_first_long (entry2);
-
- if (!short1 && !short2 && long1 && long2)
- /* Only long options. */
- return strcasecmp (long1, long2);
- else
- /* Compare short/short, long/short, short/long, using the first
- character of long options. Entries without *any* valid
- options (such as options with OPTION_HIDDEN set) will be put
- first, but as they're not displayed, it doesn't matter where
- they are. */
- {
- char first1 = short1 ?: long1 ? *long1 : 0;
- char first2 = short2 ?: long2 ? *long2 : 0;
- /* Compare ignoring case, except when the options are both the
- same letter, in which case lower-case always comes first. */
- return (tolower (first1) - tolower (first2)) ?: first2 - first1;
- }
- }
- else
- /* Order by group: 1, 2, ..., n, 0, -m, ..., -2, -1 */
- if ((group1 < 0 && group2 < 0) || (group1 > 0 && group2 > 0))
- return group1 - group2;
- else
- return group2 - group1;
- }
-
- if (hol->num_entries > 0)
- qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry),
- entry_cmp);
-}
-
-/* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow
- any in MORE with the same name. */
-static void
-hol_append (struct hol *hol, struct hol *more)
-{
- if (more->num_entries == 0)
- hol_free (more);
- else if (hol->num_entries == 0)
- {
- hol->num_entries = more->num_entries;
- hol->entries = more->entries;
- hol->short_options = more->short_options;
- /* We've stolen everything MORE from more. Destroy the empty shell. */
- free (more);
- }
- else
- /* append the entries in MORE to those in HOL, taking care to only add
- non-shadowed SHORT_OPTIONS values. */
- {
- unsigned left;
- char *so, *more_so;
- struct hol_entry *e;
- unsigned num_entries = hol->num_entries + more->num_entries;
- struct hol_entry *entries =
- malloc (num_entries * sizeof (struct hol_entry));
- unsigned hol_so_len = strlen (hol->short_options);
- char *short_options =
- malloc (hol_so_len + strlen (more->short_options) + 1);
-
- bcopy (hol->entries, entries,
- hol->num_entries * sizeof (struct hol_entry));
- bcopy (more->entries, entries + hol->num_entries,
- more->num_entries * sizeof (struct hol_entry));
-
- bcopy (hol->short_options, short_options, hol_so_len);
-
- /* Fix up the short options pointers from HOL. */
- for (e = entries, left = hol->num_entries; left > 0; e++, left--)
- e->short_options += (short_options - hol->short_options);
-
- /* Now add the short options from MORE, fixing up its entries too. */
- so = short_options + hol_so_len;
- more_so = more->short_options;
- for (left = more->num_entries; left > 0; e++, left--)
- {
- int opts_left;
- const struct argp_option *opt;
-
- e->short_options = so;
-
- for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--)
- {
- int ch = *more_so;
- if (oshort (opt) && ch == opt->key)
- /* The next short option in MORE_SO, CH, is from OPT. */
- {
- if (! find_char (ch,
- short_options, short_options + hol_so_len))
- /* The short option CH isn't shadowed by HOL's options,
- so add it to the sum. */
- *so++ = ch;
- more_so++;
- }
- }
- }
-
- *so = '\0';
-
- free (hol->entries);
- free (hol->short_options);
-
- hol->entries = entries;
- hol->num_entries = num_entries;
- hol->short_options = short_options;
-
- hol_free (more);
- }
-}
-
-/* Inserts enough spaces to make sure STREAM is at column COL. */
-static void
-indent_to (FILE *stream, unsigned col)
-{
- int needed = col - line_wrap_point (stream);
- while (needed-- > 0)
- putc (' ', stream);
-}
-
-/* Print help for ENTRY to STREAM. *LAST_ENTRY should contain the last entry
- printed before this, or null if it's the first, and if ENTRY is in a
- different group, and *SEP_GROUPS is true, then a blank line will be
- printed before any output. *SEP_GROUPS is also set to true if a
- user-specified group header is printed. */
-static void
-hol_entry_help (struct hol_entry *entry, FILE *stream,
- struct hol_entry **prev_entry, int *sep_groups)
-{
- unsigned num;
- int first = 1; /* True if nothing's been printed so far. */
- const struct argp_option *real = entry->opt, *opt;
- char *so = entry->short_options;
- int old_lm = line_wrap_set_lmargin (stream, 0);
- int old_wm = line_wrap_set_wmargin (stream, 0);
-
- /* Inserts a comma if this isn't the first item on the line, and then makes
- sure we're at least to column COL. Also clears FIRST. */
- void comma (unsigned col)
- {
- if (first)
- {
- if (sep_groups && *sep_groups
- && prev_entry && *prev_entry
- && entry->group != (*prev_entry)->group)
- putc ('\n', stream);
- first = 0;
- }
- else
- fputs (", ", stream);
- indent_to (stream, col);
- }
-
- /* If the option REAL has an argument, we print it in using the printf
- format REQ_FMT or OPT_FMT depending on whether it's a required or
- optional argument. */
- void arg (char *req_fmt, char *opt_fmt)
- {
- if (real->arg)
- if (real->flags & OPTION_ARG_OPTIONAL)
- fprintf (stream, opt_fmt, real->arg);
- else
- fprintf (stream, req_fmt, real->arg);
- }
-
- /* First emit short options. */
- line_wrap_set_wmargin (stream, SHORT_OPT_COL); /* For truly bizarre cases. */
- for (opt = real, num = entry->num; num > 0; opt++, num--)
- if (oshort (opt) && opt->key == *so)
- /* OPT has a valid (non shadowed) short option. */
- {
- if (ovisible (opt))
- {
- comma (SHORT_OPT_COL);
- putc ('-', stream);
- putc (*so, stream);
- arg (" %s", "[%s]");
- }
- so++;
- }
-
- /* Now, long options. */
- line_wrap_set_wmargin (stream, LONG_OPT_COL);
- for (opt = real, num = entry->num; num > 0; opt++, num--)
- if (opt->name && ovisible (opt))
- {
- comma (LONG_OPT_COL);
- fprintf (stream, "--%s", opt->name);
- arg ("=%s", "[=%s]");
- }
-
- line_wrap_set_lmargin (stream, 0);
- if (first)
- /* Didn't print any switches, what's up? */
- if (!oshort (real) && !real->name && real->doc)
- /* This is a group header, print it nicely. */
- {
- if (*real->doc)
- {
- if (prev_entry && *prev_entry)
- putc ('\n', stream); /* Precede with a blank line. */
- indent_to (stream, HEADER_COL);
- line_wrap_set_lmargin (stream, HEADER_COL);
- line_wrap_set_wmargin (stream, HEADER_COL);
- fputs (real->doc, stream);
- }
- if (sep_groups)
- *sep_groups = 1; /* Separate subsequent groups. */
- }
- else
- /* Just a totally shadowed option or null header; print nothing. */
- goto cleanup; /* Just return, after cleaning up. */
- else if (real->doc)
- /* Now the option documentation. */
- {
- unsigned col = line_wrap_point (stream);
- const char *doc = real->doc;
-
- line_wrap_set_lmargin (stream, OPT_DOC_COL);
- line_wrap_set_wmargin (stream, OPT_DOC_COL);
-
- if (col > OPT_DOC_COL + 3)
- putc ('\n', stream);
- else if (col >= OPT_DOC_COL)
- fprintf (stream, " ");
- else
- indent_to (stream, OPT_DOC_COL);
-
- fputs (doc, stream);
- }
-
- line_wrap_set_lmargin (stream, 0); /* Don't follow the nl with spaces. */
- putc ('\n', stream);
-
- if (prev_entry)
- *prev_entry = entry;
-
-cleanup:
- line_wrap_set_lmargin (stream, old_lm);
- line_wrap_set_wmargin (stream, old_wm);
-}
-
-/* Output a long help message about the options in HOL to STREAM. */
-static void
-hol_help (struct hol *hol, FILE *stream)
-{
- unsigned num;
- struct hol_entry *entry;
- struct hol_entry *last_entry = 0;
- int sep_groups = 0; /* True if we should separate different
- sections with blank lines. */
- for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--)
- hol_entry_help (entry, stream, &last_entry, &sep_groups);
-}
-
-/* Print a short usage description for the arguments in HOL to STREAM. */
-static void
-hol_usage (struct hol *hol, FILE *stream)
-{
- if (hol->num_entries > 0)
- {
- unsigned nentries;
- struct hol_entry *entry;
- char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1);
- char *snao_end = short_no_arg_opts;
-
- /* First we put a list of short options without arguments. */
- for (entry = hol->entries, nentries = hol->num_entries
- ; nentries > 0
- ; entry++, nentries--)
- {
- inline int func2 (const struct argp_option *opt,
- const struct argp_option *real)
- {
- if (! (opt->arg || real->arg))
- *snao_end++ = opt->key;
- return 0;
- }
- hol_entry_short_iterate (entry, func2);
- }
- if (snao_end > short_no_arg_opts)
- {
- *snao_end++ = 0;
- fprintf (stream, " [-%s]", short_no_arg_opts);
- }
-
- /* Now a list of short options *with* arguments. */
- for (entry = hol->entries, nentries = hol->num_entries
- ; nentries > 0
- ; entry++, nentries--)
- {
- inline int func3 (const struct argp_option *opt,
- const struct argp_option *real)
- {
- if (opt->arg || real->arg)
- if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL)
- fprintf (stream, " [-%c[%s]]",
- opt->key, opt->arg ?: real->arg);
- else
- {
- const char *arg = opt->arg ?: real->arg;
- /* Manually do line wrapping so that it (probably) won't
- get wrapped at the embedded space. */
- if (line_wrap_point (stream) + 6 + strlen (arg)
- >= line_wrap_rmargin (stream))
- putc ('\n', stream);
- else
- putc (' ', stream);
- fprintf (stream, "[-%c %s]", opt->key, arg);
- }
- return 0;
- }
- hol_entry_short_iterate (entry, func3);
- }
-
- /* Finally, a list of long options (whew!). */
- for (entry = hol->entries, nentries = hol->num_entries
- ; nentries > 0
- ; entry++, nentries--)
- {
- int func4 (const struct argp_option *opt,
- const struct argp_option *real)
- {
- if (opt->arg || real->arg)
- if ((opt->flags | real->flags) & OPTION_ARG_OPTIONAL)
- fprintf (stream, " [--%s[=%s]]",
- opt->name, opt->arg ?: real->arg);
- else
- fprintf (stream, " [--%s=%s]",
- opt->name, opt->arg ?: real->arg);
- else
- fprintf (stream, " [--%s]", opt->name);
- return 0;
- }
- hol_entry_long_iterate (entry, func4);
- }
- }
-}
-
-/* Make a HOL containing all levels of options in ARGP. */
-static struct hol *
-argp_hol (const struct argp *argp)
-{
- const struct argp **children = argp->children;
- struct hol *hol = make_hol (argp->options);
- if (children)
- while (*children)
- hol_append (hol, argp_hol (*children++));
- return hol;
-}
-
-/* Print all the non-option args documented in ARGP to STREAM. Any output is
- preceded by a space. */
-static void
-argp_args_usage (const struct argp *argp, FILE *stream)
-{
- const struct argp **children = argp->children;
- const char *doc = argp->args_doc;
- if (doc)
- {
- /* Manually do line wrapping so that it (probably) won't get wrapped at
- any embedded spaces. */
- if (line_wrap_point (stream) + 1 + strlen (doc)
- >= line_wrap_rmargin (stream))
- putc ('\n', stream);
- else
- putc (' ', stream);
- fputs (doc, stream);
- }
- if (children)
- while (*children)
- argp_args_usage (*children++, stream);
-}
-
-/* Print the documentation for ARGP to STREAM. Each separate bit of
- documentation is preceded by a blank line. */
-static void
-argp_doc (const struct argp *argp, FILE *stream)
-{
- const struct argp **children = argp->children;
- const char *doc = argp->doc;
- if (doc)
- {
- putc ('\n', stream);
- fputs (doc, stream);
- if (line_wrap_point (stream) > line_wrap_lmargin (stream))
- putc ('\n', stream);
- }
- if (children)
- while (*children)
- argp_doc (*children++, stream);
-}
-
-/* Output a usage message for ARGP to STREAM. FLAGS are from the set
- ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */
-void argp_help (const struct argp *argp, FILE *stream,
- unsigned flags, char *name)
-{
- int first = 1;
- struct hol *hol = 0;
-
- if (! stream)
- return;
-
- stream = line_wrap_stream (stream, 0, RMARGIN, 0);
- assert (stream);
-
- if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG))
- {
- hol = argp_hol (argp);
-
- /* If present, these options always come last. */
- hol_set_group (hol, "help", -1);
- hol_set_group (hol, "version", -1);
-
- hol_sort (hol);
- }
-
- if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE))
- /* Print a short `Usage:' message. */
- {
- int old_lm;
- int old_wm = line_wrap_set_wmargin (stream, USAGE_INDENT);
-
- fprintf (stream, "Usage: %s", name);
-
- /* We set the lmargin as well as the wmargin, because hol_usage
- manually wraps options with newline to avoid annoying breaks. */
- old_lm = line_wrap_set_lmargin (stream, USAGE_INDENT);
-
- if (flags & ARGP_HELP_SHORT_USAGE)
- /* Just show where the options go. */
- {
- if (hol->num_entries > 0)
- fputs (" [OPTION...]", stream);
- }
- else
- /* Actually print the options. */
- hol_usage (hol, stream);
- argp_args_usage (argp, stream);
-
- line_wrap_set_wmargin (stream, old_wm);
- line_wrap_set_lmargin (stream, old_lm);
-
- putc ('\n', stream);
- first = 0;
- }
-
- if (flags & ARGP_HELP_SEE)
- {
- fprintf (stream, "Try `%s --help' for more information.\n", name);
- first = 0;
- }
-
- if (flags & ARGP_HELP_LONG)
- /* Print a long, detailed help message. */
- {
- /* Print info about all the options. */
- if (hol->num_entries > 0)
- {
- if (! first)
- putc ('\n', stream);
- hol_help (hol, stream);
- first = 0;
- }
-
- /* Finally, print any documentation strings at the end. */
- argp_doc (argp, stream);
- }
-
- if (hol)
- hol_free (hol);
-
- line_unwrap_stream (stream);
-}
-
-/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are
- from the set ARGP_HELP_*. */
-void
-argp_state_help (struct argp_state *state, FILE *stream, unsigned flags)
-{
- if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream)
- {
- argp_help (state ? state->argp : 0, stream, flags,
- state ? state->name : program_invocation_name);
-
- if (!state || ! (state->flags & ARGP_NO_EXIT))
- {
- if (flags & ARGP_HELP_EXIT_ERR)
- exit (1);
- if (flags & ARGP_HELP_EXIT_OK)
- exit (0);
- }
- }
-}
-
-/* If appropriate, print the printf string FMT and following args, preceded
- by the program name and `:', to stderr, and followed by a `Try ... --help'
- message, then exit (1). */
-void
-argp_error (struct argp_state *state, const char *fmt, ...)
-{
- if (!state || !(state->flags & ARGP_NO_ERRS))
- {
- FILE *stream = state ? state->err_stream : stderr;
-
- if (stream)
- {
- va_list ap;
-
- fputs (program_invocation_name, stream);
- putc (':', stream);
- putc (' ', stream);
-
- va_start (ap, fmt);
- vfprintf (stream, fmt, ap);
- va_end (ap);
-
- putc ('\n', stream);
-
- argp_state_help (state, stream, ARGP_HELP_STD_ERR);
- }
- }
-}
-
-/* Similar to the standard gnu error-reporting function error(), but will
- respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print
- to STATE->err_stream. This is useful for argument parsing code that is
- shared between program startup (when exiting is desired) and runtime
- option parsing (when typically an error code is returned instead). The
- difference between this function and argp_error is that the latter is for
- *parsing errors*, and the former is for other problems that occur during
- parsing but don't reflect a (syntactic) problem with the input. */
-void
-argp_failure (struct argp_state *state, int status, int errnum,
- const char *fmt, ...)
-{
- if (!state || !(state->flags & ARGP_NO_ERRS))
- {
- FILE *stream = state ? state->err_stream : stderr;
-
- if (stream)
- {
- fputs (state ? state->name : program_invocation_name, stream);
-
- if (fmt)
- {
- va_list ap;
-
- putc (':', stream);
- putc (' ', stream);
-
- va_start (ap, fmt);
- vfprintf (stream, fmt, ap);
- va_end (ap);
- }
-
- if (errnum)
- {
- putc (':', stream);
- putc (' ', stream);
- fputs (strerror (errnum), stream);
- }
-
- putc ('\n', stream);
-
- if (status)
- exit (status);
- }
- }
-}
diff --git a/libshouldbeinlibc/argp-parse.c b/libshouldbeinlibc/argp-parse.c
deleted file mode 100644
index 73b28f06..00000000
--- a/libshouldbeinlibc/argp-parse.c
+++ /dev/null
@@ -1,662 +0,0 @@
-/* Hierarchial argument parsing, layered over getopt
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <limits.h>
-#include <getopt.h>
-#include <cthreads.h>
-
-#include "argp.h"
-
-/* Getopt return values. */
-#define KEY_END (-1) /* The end of the options. */
-#define KEY_ARG 1 /* A non-option argument. */
-#define KEY_ERR '?' /* An error parsing the options. */
-
-/* The meta-argument used to prevent any further arguments being interpreted
- as options. */
-#define QUOTE "--"
-
-/* The number of bits we steal in a long-option value for our own use. */
-#define GROUP_BITS CHAR_BIT
-
-/* The number of bits available for the user value. */
-#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS)
-#define USER_MASK ((1 << USER_BITS) - 1)
-
-/* EZ alias for ARGP_ERR_UNKNOWN. */
-#define EBADKEY ARGP_ERR_UNKNOWN
-
-/* ---------------------------------------------------------------- */
-/* Default options. */
-
-/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep
- for one second intervals, decrementing _ARGP_HANG until it's zero. Thus
- you can force the program to continue by attaching a debugger and setting
- it to 0 yourself. */
-volatile int _argp_hang = 0;
-
-#define OPT_PROGNAME -2
-#define OPT_USAGE -3
-#define OPT_HANG -4
-
-static const struct argp_option argp_default_options[] =
-{
- {"help", '?', 0, 0, "Give this help list", -1},
- {"usage", OPT_USAGE, 0, 0, "Give a short usage message"},
- {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, "Set the program name"},
- {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN,
- "Hang for SECS seconds (default 3600)"},
- {0, 0}
-};
-
-static error_t
-argp_default_parser (int key, char *arg, struct argp_state *state)
-{
- switch (key)
- {
- case '?':
- argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP);
- break;
- case OPT_USAGE:
- argp_state_help (state, state->out_stream,
- ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
- break;
-
- case OPT_PROGNAME: /* Set the program name. */
- program_invocation_name = arg;
- program_invocation_short_name = rindex (arg, '/');
- if (program_invocation_short_name)
- program_invocation_short_name++;
- else
- program_invocation_short_name = program_invocation_name;
-
- if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS))
- == ARGP_PARSE_ARGV0)
- state->argv[0] = arg; /* Update what getopt uses too. */
-
- break;
-
- case OPT_HANG:
- _argp_hang = atoi (arg ?: "3600");
- while (_argp_hang-- > 0)
- sleep (1);
- break;
-
- default:
- return EBADKEY;
- }
- return 0;
-}
-
-static const struct argp argp_default_argp =
- {argp_default_options, &argp_default_parser};
-
-
-static const struct argp_option argp_version_options[] =
-{
- {"version", 'V', 0, 0, "Print program version", -1},
- {0, 0}
-};
-
-static error_t
-argp_version_parser (int key, char *arg, struct argp_state *state)
-{
- switch (key)
- {
- case 'V':
- if (argp_program_version_hook)
- (*argp_program_version_hook) (state->out_stream, state);
- else if (argp_program_version)
- fprintf (state->out_stream, "%s\n", argp_program_version);
- else
- argp_error (state, "No version known!?");
- if (! (state->flags & ARGP_NO_EXIT))
- exit (0);
- break;
- default:
- return EBADKEY;
- }
- return 0;
-}
-
-static const struct argp argp_version_argp =
- {argp_version_options, &argp_version_parser};
-
-/* ---------------------------------------------------------------- */
-
-/* Returns the offset into the getopt long options array LONG_OPTIONS of a
- long option with called NAME, or -1 if none is found. Passing NULL as
- NAME will return the number of options. */
-static int
-find_long_option (struct option *long_options, const char *name)
-{
- struct option *l = long_options;
- while (l->name != NULL)
- if (name != NULL && strcmp (l->name, name) == 0)
- return l - long_options;
- else
- l++;
- if (name == NULL)
- return l - long_options;
- else
- return -1;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Used to regulate access to the getopt routines, which are non-reentrant. */
-static struct mutex getopt_lock = MUTEX_INITIALIZER;
-
-/* This hack to allow programs that know what's going on to call argp
- recursively. If someday argp is changed not to use the non-reentrant
- getopt interface, we can get rid of this shit. XXX */
-void
-_argp_unlock_xxx ()
-{
- mutex_unlock (&getopt_lock);
-}
-
-/* The state of a `group' during parsing. Each group corresponds to a
- particular argp structure from the tree of such descending from the top
- level argp passed to argp_parse. */
-struct group
-{
- /* This group's parsing function. */
- argp_parser_t parser;
-
- /* Points to the point in SHORT_OPTS corresponding to the end of the short
- options for this group. We use it to determine from which group a
- particular short options is from. */
- char *short_end;
-
- /* The number of non-option args sucessfully handled by this parser. */
- unsigned args_processed;
-
- /* This group's parser's parent's group. */
- struct group *parent;
- unsigned parent_index; /* And the our position in the parent. */
-
- /* These fields are swapped into and out of the state structure when
- calling this group's parser. */
- void *input, **child_inputs;
- void *hook;
-};
-
-/* Parse the options strings in ARGC & ARGV according to the argp in
- ARGP. FLAGS is one of the ARGP_ flags above. If OPTIND is
- non-NULL, the index in ARGV of the first unparsed option is returned in
- it. If an unknown option is present, EINVAL is returned; if some parser
- routine returned a non-zero value, it is returned; otherwise 0 is
- returned. */
-error_t
-argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags,
- int *end_index, void *input)
-{
- error_t err = 0;
- /* True if we think using getopt is still useful; if false, then
- remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is
- cleared whenever getopt returns KEY_END, but may be set again if the user
- moves the next argument pointer backwards. */
- int try_getopt = 1;
- /* If true, then err == EBADKEY is a result of a non-option argument failing
- to be parsed (which in some cases isn't actually an error). */
- int arg_ebadkey = 0;
- /* SHORT_OPTS is the getopt short options string for the union of all the
- groups of options. */
- char *short_opts;
- /* LONG_OPTS is the array of getop long option structures for the union of
- all the groups of options. */
- struct option *long_opts;
- /* States of the various parsing groups. */
- struct group *groups;
- /* The end of the GROUPS array. */
- struct group *egroup;
- /* A pointer for people to use for iteration over GROUPS. */
- struct group *group;
- /* An vector containing storage for the CHILD_INPUTS field in all groups. */
- void **child_inputs;
- /* State block supplied to parsing routines. */
- struct argp_state state =
- { argp, argc, argv, 0, flags, err_stream: stderr, out_stream: stdout };
-
- /* Call GROUP's parser with KEY and ARG, swapping any group-specific info
- from STATE before calling, and back into state afterwards. If GROUP has
- no parser, EBADKEY is returned. */
- error_t group_parse (struct group *group, int key, char *arg)
- {
- if (group->parser)
- {
- error_t err;
- state.hook = group->hook;
- state.input = group->input;
- state.child_inputs = group->child_inputs;
- state.arg_num = group->args_processed;
- err = (*group->parser)(key, arg, &state);
- group->hook = state.hook;
- return err;
- }
- else
- return EBADKEY;
- }
-
- /* Parse the non-option argument ARG, at the current position. Returns
- any error, and sets ARG_EBADKEY to true if return EBADKEY. */
- error_t process_arg (char *val, int *arg_ebadkey)
- {
- int index = state.next;
- error_t err = EBADKEY;
-
- for (group = groups; group < egroup && err == EBADKEY; group++)
- err = group_parse (group, ARGP_KEY_ARG, val);
-
- if (!err)
- if (state.next >= index)
- /* Remember that we successfully processed a non-option
- argument -- but only if the user hasn't gotten tricky and set
- the clock back. */
- (--group)->args_processed++;
- else
- /* The user wants to reparse some args, give getopt another try. */
- try_getopt = 1;
-
- if (err == EBADKEY)
- *arg_ebadkey = 1;
-
- return err;
- }
-
- /* Parse the option OPT (with argument ARG), at the current position.
- Returns any error, and sets ARG_EBADKEY to true if it was actually an
- argument and the parser returned EBADKEY. */
- error_t process_opt (int opt, char *val, int *arg_ebadkey)
- {
- /* The group key encoded in the high bits; 0 for short opts or
- group_number + 1 for long opts. */
- int group_key = opt >> USER_BITS;
- error_t err = EBADKEY; /* until otherwise asserted */
-
- if (group_key == 0)
- /* A short option. */
- {
- /* By comparing OPT's position in SHORT_OPTS to the various
- starting positions in each group's SHORT_END field, we can
- determine which group OPT came from. */
- char *short_index = index (short_opts, opt);
- if (short_index)
- for (group = groups; group < egroup; group++)
- if (group->short_end > short_index)
- {
- err = group_parse (group, opt, optarg);
- break;
- }
- }
- else
- /* A long option. We use shifts instead of masking for extracting
- the user value in order to preserve the sign. */
- err =
- group_parse (&groups[group_key - 1],
- (opt << GROUP_BITS) >> GROUP_BITS, optarg);
-
- return err;
- }
-
- if (! (state.flags & ARGP_NO_HELP))
- /* Add our own options. */
- {
- const struct argp **plist = alloca (3 * sizeof (struct argp *));
- struct argp *top_argp = alloca (sizeof (struct argp));
-
- /* TOP_ARGP has no options, it just serves to group the user & default
- argps. */
- bzero (top_argp, sizeof (*top_argp));
- top_argp->children = plist;
-
- if (state.argp)
- *plist++ = state.argp;
- *plist++ = &argp_default_argp;
- if (argp_program_version || argp_program_version_hook)
- *plist++ = &argp_version_argp;
- *plist = 0;
-
- state.argp = top_argp;
- }
-
- /* Find the merged set of getopt options, with keys appropiately prefixed. */
- {
- char *short_end;
- unsigned short_len = (state.flags & ARGP_NO_ARGS) ? 0 : 1;
- struct option *long_end;
- unsigned long_len = 0;
- unsigned num_groups = 0;
- unsigned num_child_inputs = 0;
-
- /* For ARGP, increments NUM_GROUPS by the total number of argp structures
- descended from it, and SHORT_LEN & LONG_LEN by the maximum lengths of
- the resulting merged getopt short options string and long-options
- array, respectively. */
- void calc_lengths (const struct argp *argp)
- {
- const struct argp **children = argp->children;
- const struct argp_option *opt = argp->options;
-
- if (opt || argp->parser)
- {
- num_groups++;
- if (opt)
- {
- int num_opts = 0;
- while (!_option_is_end (opt++))
- num_opts++;
- short_len += num_opts * 3; /* opt + up to 2 `:'s */
- long_len += num_opts;
- }
- }
-
- if (children)
- while (*children)
- {
- calc_lengths (*children++);
- num_child_inputs++;
- }
- }
-
- /* Converts all options in ARGP (which is put in GROUP) and ancestors
- into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and
- LONG_END are the points at which new options are added. Returns the
- next unused group entry. */
- struct group *convert_options (const struct argp *argp,
- struct group *parent, unsigned parent_index,
- struct group *group)
- {
- /* REAL is the most recent non-alias value of OPT. */
- const struct argp_option *real = argp->options;
- const struct argp **children = argp->children;
-
- if (real || argp->parser)
- {
- const struct argp_option *opt;
-
- if (real)
- for (opt = real; !_option_is_end (opt); opt++)
- {
- if (! (opt->flags & OPTION_ALIAS))
- /* OPT isn't an alias, so we can use values from it. */
- real = opt;
-
- if (_option_is_short (opt))
- /* OPT can be used as a short option. */
- {
- *short_end++ = opt->key;
- if (real->arg)
- {
- *short_end++ = ':';
- if (real->flags & OPTION_ARG_OPTIONAL)
- *short_end++ = ':';
- }
- *short_end = '\0'; /* keep 0 terminated */
- }
-
- if (opt->name && find_long_option (long_opts, opt->name) < 0)
- /* OPT can be used as a long option. */
- {
- long_end->name = opt->name;
- long_end->has_arg =
- (real->arg
- ? (real->flags & OPTION_ARG_OPTIONAL
- ? optional_argument
- : required_argument)
- : no_argument);
- long_end->flag = 0;
- /* we add a disambiguating code to all the user's
- values (which is removed before we actually call
- the function to parse the value); this means that
- the user loses use of the high 8 bits in all his
- values (the sign of the lower bits is preserved
- however)... */
- long_end->val =
- ((opt->key | real->key) & USER_MASK)
- + (((group - groups) + 1) << USER_BITS);
-
- /* Keep the LONG_OPTS list terminated. */
- (++long_end)->name = NULL;
- }
- }
-
- group->parser = argp->parser;
- group->short_end = short_end;
- group->args_processed = 0;
- group->parent = parent;
- group->parent_index = parent_index;
- group->input = 0;
- group->hook = 0;
- group->child_inputs = 0;
-
- if (children)
- /* Assign GROUP's CHILD_INPUTS field a slice from CHILD_INPUTS.*/
- {
- unsigned num_children = 0;
- while (children[num_children])
- num_children++;
- group->child_inputs = child_inputs;
- child_inputs += num_children;
- }
-
- parent = group++;
- }
- else
- parent = 0;
-
- if (children)
- {
- unsigned index = 0;
- while (*children)
- group = convert_options (*children++, parent, index++, group);
- }
-
- return group;
- }
-
- if (state.argp)
- calc_lengths (state.argp);
-
- short_opts = short_end = alloca (short_len + 1);
- if (state.flags & ARGP_IN_ORDER)
- *short_end++ = '-';
- else if (state.flags & ARGP_NO_ARGS)
- *short_end++ = '+';
- *short_end = '\0';
-
- long_opts = long_end = alloca ((long_len + 1) * sizeof (struct option));
- long_end->name = NULL;
-
- groups = alloca ((num_groups + 1) * sizeof (struct group));
-
- child_inputs = alloca (num_child_inputs * sizeof (void *));
- bzero (child_inputs, num_child_inputs * sizeof (void *));
-
- if (state.argp)
- egroup = convert_options (state.argp, 0, 0, groups);
- else
- egroup = groups; /* No parsers at all! */
- }
-
- /* Call each parser for the first time, giving it a chance to propagate
- values to child parsers. */
- if (groups < egroup)
- groups->input = input;
- for (group = groups ; group < egroup && (!err || err == EBADKEY); group++)
- {
- if (group->parent)
- /* If a child parser, get the initial input value from the parent. */
- group->input = group->parent->child_inputs[group->parent_index];
- err = group_parse (group, ARGP_KEY_INIT, 0);
- }
- if (err == EBADKEY)
- err = 0; /* Some parser didn't understand. */
-
- /* Getopt is (currently) non-reentrant. */
- mutex_lock (&getopt_lock);
-
- /* Tell getopt to initialize. */
- state.next = 0;
-
- if (state.flags & ARGP_NO_ERRS)
- {
- opterr = 0;
- if (state.flags & ARGP_PARSE_ARGV0)
- /* getopt always skips ARGV[0], so we have to fake it out. As long
- as opterr is 0, then it shouldn't actually try to access it. */
- state.argv--, state.argc++;
- }
- else
- opterr = 1; /* Print error messages. */
-
- if (state.argv == argv && argv[0])
- /* There's an argv[0]; use it for messages. */
- state.name = argv[0];
- else
- state.name = program_invocation_name;
-
- /* Now use getopt on our coalesced options lists. */
- while (! err)
- {
- int opt;
-
- if (state.quoted && state.next < state.quoted)
- /* The next argument pointer has been moved to before the quoted
- region, so pretend we never saw the quoting `--', and give getopt
- another chance. If the user hasn't removed it, getopt will just
- process it again. */
- state.quoted = 0;
-
- if (try_getopt && !state.quoted)
- /* Give getopt a chance to parse this. */
- {
- optind = state.next; /* Put it back in OPTIND for getopt. */
- optopt = KEY_END; /* Distinguish KEY_ERR from a real option. */
- opt = getopt_long (state.argc, state.argv, short_opts, long_opts, 0);
- state.next = optind; /* And see what getopt did. */
-
- if (opt == KEY_END)
- /* Getopt says there are no more options, so stop using
- getopt; we'll continue if necessary on our own. */
- {
- try_getopt = 0;
- if (state.next > 1
- && strcmp (state.argv[state.next - 1], QUOTE) == 0)
- /* Not only is this the end of the options, but it's a
- `quoted' region, which may have args that *look* like
- options, so we definitely shouldn't try to use getopt past
- here, whatever happens. */
- state.quoted = state.next;
- }
- else if (opt == KEY_ERR && optopt != KEY_END)
- /* KEY_ERR can have the same value as a valid user short
- option, but in the case of a real error, getopt sets OPTOPT
- to the offending character, which can never be KEY_END. */
- {
- err = EBADKEY;
- break;
- }
- }
- else
- opt = KEY_END;
-
- if (opt == KEY_END)
- /* We're past what getopt considers the options. */
- if (state.next >= state.argc || (state.flags & ARGP_NO_ARGS))
- break; /* done */
- else
- /* A non-option arg. */
- err = process_arg (state.argv[state.next++], &arg_ebadkey);
- else if (opt == KEY_ARG)
- /* A non-option argument; try each parser in turn. */
- err = process_arg (optarg, &arg_ebadkey);
- else
- err = process_opt (opt, optarg, &arg_ebadkey);
- }
-
- mutex_unlock (&getopt_lock);
-
- if (err == EBADKEY && arg_ebadkey)
- /* Suppress errors generated by unparsed arguments. */
- err = 0;
-
- if (!err)
- if (state.next == state.argc)
- /* We successfully parsed all arguments! Call all the parsers again,
- just a few more times... */
- {
- for (group = groups; group < egroup && (!err || err==EBADKEY); group++)
- if (group->args_processed == 0)
- err = group_parse (group, ARGP_KEY_NO_ARGS, 0);
- for (group = groups; group < egroup && (!err || err==EBADKEY); group++)
- err = group_parse (group, ARGP_KEY_END, 0);
- if (err == EBADKEY)
- err = 0; /* Some parser didn't understand. */
- }
- else if (end_index)
- /* Return any remaining arguments to the user. */
- *end_index = state.next;
- else
- /* No way to return the remaining arguments, they must be bogus. */
- {
- if (!(state.flags & ARGP_NO_ERRS) && state.err_stream)
- fprintf (state.err_stream, "%s: Too many arguments\n", state.name);
- err = EBADKEY;
- }
-
- /* Okay, we're all done, with either an error or success. We only call the
- parsers once more, to indicate which one. */
-
- if (err)
- {
- /* Maybe print an error message. */
- if (err == EBADKEY)
- argp_state_help (&state, state.err_stream, ARGP_HELP_STD_ERR);
-
- /* Since we didn't exit, give each parser an error indication. */
- for (group = groups; group < egroup; group++)
- group_parse (group, ARGP_KEY_ERROR, 0);
- }
- else
- /* Do final cleanup, including propagating back values from parsers. */
- {
- /* We pass over the groups in reverse order so that child groups are
- given a chance to do there processing before passing back a value to
- the parent. */
- for (group = egroup - 1
- ; group >= groups && (!err || err == EBADKEY)
- ; group--)
- err = group_parse (group, ARGP_KEY_SUCCESS, 0);
- if (err == EBADKEY)
- err = 0; /* Some parser didn't understand. */
- }
-
- if (err == EBADKEY)
- err = EINVAL;
-
- return err;
-}
diff --git a/libshouldbeinlibc/argp-pv.c b/libshouldbeinlibc/argp-pv.c
deleted file mode 100644
index e6e87adb..00000000
--- a/libshouldbeinlibc/argp-pv.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Default definition for ARGP_PROGRAM_VERSION
-
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* If set by the user program to a non-zero value, then a default option
- --version is added (unless the ARGP_NO_HELP flag is used), which will
- print this this string followed by a newline and exit (unless the
- ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */
-char *argp_program_version = 0;
diff --git a/libshouldbeinlibc/argp-pvh.c b/libshouldbeinlibc/argp-pvh.c
deleted file mode 100644
index a58c1923..00000000
--- a/libshouldbeinlibc/argp-pvh.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Default definition for ARGP_PROGRAM_VERSION_HOOK
-
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include "argp.h"
-
-/* If set by the user program to a non-zero value, then a default option
- --version is added (unless the ARGP_NO_HELP flag is used), which calls
- this function with a stream to print the version to and a pointer to the
- current parsing state, and then exits (unless the ARGP_NO_EXIT flag is
- used). This variable takes precedent over ARGP_PROGRAM_VERSION. */
-void (*argp_program_version_hook) (FILE *stream, struct argp_state *state) = 0;
diff --git a/libshouldbeinlibc/argp.h b/libshouldbeinlibc/argp.h
deleted file mode 100644
index 9c59c407..00000000
--- a/libshouldbeinlibc/argp.h
+++ /dev/null
@@ -1,356 +0,0 @@
-/* Hierarchial argument parsing, layered over getopt
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#ifndef __ARGP_H__
-#define __ARGP_H__
-
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <getopt.h>
-
-/* A description of a particular option. A pointer to an array of
- these is passed in the OPTIONS field of an argp structure. Each option
- entry can correspond to one long option and/or one short option; more
- names for the same option can be added by following an entry in an option
- array with options having the OPTION_ALIAS flag set. */
-struct argp_option
-{
- /* The long option name. For more than one name for the same option, you
- can use following options with the OPTION_ALIAS flag set. */
- const char *name;
-
- /* What key is returned for this option. If > 0 and printable, then it's
- also accepted as a short option. */
- int key;
-
- /* If non-NULL, this is the name of the argument associated with this
- option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */
- const char *arg;
-
- /* OPTION_ flags. */
- int flags;
-
- /* The doc string for this option. If both NAME and KEY are 0, This string
- will be printed outdented from the normal option column, making it
- useful as a group header (it will be the first thing printed in its
- group); in this usage, it's conventional to end the string with a `:'. */
- const char *doc;
-
- /* The group this option is in. In a long help message, options are sorted
- alphabetically within each group, and the groups presented in the order
- 1, 2, ..., n, 0, -m, ..., -2, -1. Every entry in an options array with
- if this field 0 will inherit the group number of the previous entry, or
- zero if it's the first one. Automagic options such as --help are put
- into group -1. */
- int group;
-};
-
-/* The argument associated with this option is optional. */
-#define OPTION_ARG_OPTIONAL 0x1
-/* This option isn't displayed in any help messages. */
-#define OPTION_HIDDEN 0x2
-/* This option is an alias for the closest previous non-alias option. This
- means that it will be displayed in the same help entry, and will inherit
- fields other than NAME and KEY from the aliased option. */
-#define OPTION_ALIAS 0x4
-
-struct argp; /* fwd declare this type */
-struct argp_state; /* " */
-
-/* The type of a pointer to an argp parsing function. */
-typedef error_t (*argp_parser_t)(int key, char *arg, struct argp_state *state);
-
-/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such
- returns will simply be ignored. For user keys, this error will be turned
- into EINVAL (if the call to argp_parse is such that errors are propagated
- back to the user instead of exiting); returning EINVAL itself would result
- in an immediate stop to parsing in *all* cases. */
-#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX */
-
-/* Special values for the KEY argument to an argument parsing function.
- ARGP_ERR_UNKNOWN should be returned if they aren't understood.
-
- The sequence of keys to parser calls is either (where opt is a user key):
- ARGP_KEY_INIT (opt | ARGP_KEY_ARG)... ARGP_KEY_END
- or ARGP_KEY_INIT opt... ARGP_KEY_NO_ARGS ARGP_KEY_END
-
- If an error occurs, then the parser is called with ARGP_KEY_ERR, and no
- other calls are made. */
-
-/* This is not an option at all, but rather a command line argument. If a
- parser receiving this key returns success, the fact is recorded, and the
- ARGP_KEY_NO_ARGS case won't be used. HOWEVER, if while processing the
- argument, a parser function decrements the NEXT field of the state it's
- passed, the option won't be considered processed; this is to allow you to
- actually modify the argument (perhaps into an option), and have it
- processed again. */
-#define ARGP_KEY_ARG 0
-/* There are no more command line arguments at all. */
-#define ARGP_KEY_END 1
-/* Because it's common to want to do some special processing if there aren't
- any non-option args, user parsers are called with this key if they didn't
- successfully process any non-option arguments. Called just before
- ARGP_KEY_END (where more general validity checks on previously parsed
- arguments can take place). */
-#define ARGP_KEY_NO_ARGS 2
-/* Passed in before any parsing is done. Afterwards, the values of each
- element of the CHILD_INPUT field, if any, in the state structure is
- copied to each child's state to be the initial value of the INPUT field. */
-#define ARGP_KEY_INIT 3
-/* Passed in when parsing has successfully been completed (even if there are
- still arguments remaining). */
-#define ARGP_KEY_SUCCESS 4
-/* Passed in if an error occurs (in which case a call with ARGP_KEY_SUCCESS is
- never made, so any cleanup must be done here). */
-#define ARGP_KEY_ERROR 5
-
-/* An argp structure contains a set of getopt options declarations, a
- function to deal with getting one, and an optional pointer to another
- argp structure. When actually parsing options, getopt is called with
- the union of all the argp structures chained together through their
- CHILD pointers, with conflicts being resolved in favor of the first
- occurance in the chain. */
-struct argp
-{
- /* An array of argp_option structures, terminated by an entry with both
- NAME and KEY having a value of 0. */
- const struct argp_option *options;
-
- /* What to do with an option from this structure. KEY is the key
- associated with the option, and ARG is any associated argument (NULL if
- none was supplied). If KEY isn't understood, ARGP_ERR_UNKNOWN should be
- returned. If a non-zero, non-ARGP_ERR_UNKNOWN value is returned, then
- parsing is stopped immediately, and that value is returned from
- argp_parse(). For special (non-user-supplied) values of KEY, see the
- ARGP_KEY_ definitions below. */
- argp_parser_t parser;
-
- /* A string describing what other arguments are wanted by this program. It
- is only used by argp_usage to print the `Usage:' message. */
- const char *args_doc;
-
- /* A string containing extra text to be printed after the options in a long
- help message, if it is non-NULL. */
- const char *doc;
-
- /* A NULL terminated list of other argp structures that should be parsed
- with this one. Any conflicts are resolved in favor of this argp, or
- early argps in the CHILDREN list. This field is useful if you use
- libraries that supply their own argp structure, which you want to use in
- conjunction with your own. */
- const struct argp **children;
-};
-
-/* Parsing state. This is provided to parsing functions called by argp,
- which may examine and, as noted, modify fields. */
-struct argp_state
-{
- /* The top level ARGP being parsed. */
- const struct argp *argp;
-
- /* The argument vector being parsed. May be modified. */
- int argc;
- char **argv;
-
- /* The index in ARGV of the next arg that to be parsed. May be modified. */
- int next;
-
- /* The flags supplied to argp_parse. May be modified. */
- unsigned flags;
-
- /* While calling a parsing function with a key of ARGP_KEY_ARG, this is the
- number of the current arg, starting at zero, and incremented after each
- such call returns. At all other times, this is the number of such
- arguments that have been processed. */
- unsigned arg_num;
-
- /* If non-zero, the index in ARGV of the first argument following a special
- `--' argument (which prevents anything following being interpreted as an
- option). Only set once argument parsing has proceeded past this point. */
- int quoted;
-
- /* An arbitrary pointer passed in from the user. */
- void *input;
- /* Values to pass to child parsers. This vector will be the same length as
- the number of children for the current parser. */
- void **child_inputs;
-
- /* For the parser's use. Initialized to 0. */
- void *hook;
-
- /* The name used when printing messages. This is initialized to ARGV[0],
- or PROGRAM_INVOCATION_NAME if that is unavailable. */
- char *name;
-
- /* Streams used when argp prints something. */
- FILE *err_stream; /* For errors; initialized to stderr. */
- FILE *out_stream; /* For information; initialized to stdout. */
-};
-
-/* Flags for argp_parse (note that the defaults are those that are
- convenient for program command line parsing): */
-
-/* Don't ignore the first element of ARGV. Normally (and always unless
- ARGP_NO_ERRS is set) the first element of the argument vector is
- skipped for option parsing purposes, as it corresponds to the program name
- in a command line. */
-#define ARGP_PARSE_ARGV0 0x1
-
-/* Don't print error messages for unknown options to stderr; unless this flag
- is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program
- name in the error messages. This flag implies ARGP_NO_EXIT (on the
- assumption that silent exiting upon errors is bad behaviour). */
-#define ARGP_NO_ERRS 0x2
-
-/* Don't parse any non-option args. Normally non-option args are parsed by
- calling the parse functions with a key of ARGP_KEY_ARG, and the actual arg
- as the value. Since it's impossible to know which parse function wants to
- handle it, each one is called in turn, until one returns 0 or an error
- other than ARGP_ERR_UNKNOWN; if an argument is handled by no one, the
- argp_parse returns prematurely (but with a return value of 0). If all
- args have been parsed without error, all parsing functions are called one
- last time with a key of ARGP_KEY_END. This flag needn't normally be set,
- as the normal behavior is to stop parsing as soon as some argument can't
- be handled. */
-#define ARGP_NO_ARGS 0x4
-
-/* Parse options and arguments in the same order they occur on the command
- line -- normally they're rearranged so that all options come first. */
-#define ARGP_IN_ORDER 0x8
-
-/* Don't provide the standard long option --help, which causes usage and
- option help information to be output to stdout, and exit (0) called. */
-#define ARGP_NO_HELP 0x10
-
-/* Don't exit on errors (they may still result in error messages). */
-#define ARGP_NO_EXIT 0x20
-
-/* Turns off any message-printing/exiting options. */
-#define ARGP_SILENT (ARGP_NO_EXIT | ARGP_NO_ERRS | ARGP_NO_HELP)
-
-/* Parse the options strings in ARGC & ARGV according to the options in ARGP.
- FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the
- index in ARGV of the first unparsed option is returned in it. If an
- unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser
- routine returned a non-zero value, it is returned; otherwise 0 is
- returned. This function may also call exit unless the ARGP_NO_HELP flag
- is set. INPUT is a pointer to a value to be passed in to the parser. */
-error_t argp_parse (const struct argp *argp,
- int argc, char **argv, unsigned flags,
- int *arg_index, void *input);
-
-/* If defined or set by the user program to a non-zero value, then a default
- option --version is added (unless the ARGP_NO_HELP flag is used), which
- will print this this string followed by a newline and exit (unless the
- ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */
-extern char *argp_program_version;
-
-/* If defined or set by the user program to a non-zero value, then a default
- option --version is added (unless the ARGP_NO_HELP flag is used), which
- calls this function with a stream to print the version to and a pointer to
- the current parsing state, and then exits (unless the ARGP_NO_EXIT flag is
- used). This variable takes precedent over ARGP_PROGRAM_VERSION. */
-extern void (*argp_program_version_hook) (FILE *stream,
- struct argp_state *state);
-
-/* Flags for argp_help. */
-#define ARGP_HELP_USAGE 0x01 /* Print a Usage: message. */
-#define ARGP_HELP_SHORT_USAGE 0x02 /* " but don't actually print options. */
-#define ARGP_HELP_SEE 0x04 /* Print a `for more help...' message. */
-#define ARGP_HELP_LONG 0x08 /* Print a long help message. */
-
-/* These ARGP_HELP flags are only understood by argp_state_help. */
-#define ARGP_HELP_EXIT_ERR 0x10 /* Call exit(1) instead of returning. */
-#define ARGP_HELP_EXIT_OK 0x20 /* Call exit(0) instead of returning. */
-
-/* The standard thing to do after a program command line parsing error, if an
- error message has already been printed. */
-#define ARGP_HELP_STD_ERR \
- (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
-/* The standard thing to do after a program command line parsing error, if no
- more specific error message has been printed. */
-#define ARGP_HELP_STD_USAGE \
- (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
-/* The standard thing to do in response to a --help option. */
-#define ARGP_HELP_STD_HELP \
- (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK)
-
-/* Output a usage message for ARGP to STREAM. FLAGS are from the set
- ARGP_HELP_*. */
-extern void argp_help (const struct argp *argp, FILE *stream, unsigned flags,
- char *name);
-
-/* The following routines are intended to be called from within an argp
- parsing routine (thus taking an argp_state structure as the first
- argument). They may or may not print an error message and exit, depending
- on the flags in STATE -- in any case, the caller should be prepared for
- them *not* to exit, and should return an appropiate error after calling
- them. [argp_usage & argp_error should probably be called argp_state_...,
- but they're used often enough that they should be short] */
-
-/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are
- from the set ARGP_HELP_*. */
-void argp_state_help (struct argp_state *state, FILE *stream, unsigned flags);
-
-/* Possibly output the standard usage message for ARGP to stderr and exit. */
-extern inline void
-argp_usage (struct argp_state *state)
-{
- argp_state_help (state, stderr, ARGP_HELP_STD_USAGE);
-}
-
-/* If appropriate, print the printf string FMT and following args, preceded
- by the program name and `:', to stderr, and followed by a `Try ... --help'
- message, then exit (1). */
-void argp_error (struct argp_state *state, const char *fmt, ...)
- __attribute__ ((format (printf, 2, 3)));
-
-/* Similar to the standard gnu error-reporting function error(), but will
- respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print
- to STATE->err_stream. This is useful for argument parsing code that is
- shared between program startup (when exiting is desired) and runtime
- option parsing (when typically an error code is returned instead). The
- difference between this function and argp_error is that the latter is for
- *parsing errors*, and the former is for other problems that occur during
- parsing but don't reflect a (syntactic) problem with the input. */
-void argp_failure (struct argp_state *state,
- int status, int errnum, const char *fmt, ...)
- __attribute__ ((format (printf, 4, 5)));
-
-/* Returns true if the option OPT is a valid short option. */
-extern inline int
-_option_is_short (const struct argp_option *opt)
-{
- int key = opt->key;
- return key > 0 && isprint (key);
-}
-
-/* Returns true if the option OPT is in fact the last (unused) entry in an
- options array. */
-extern inline int
-_option_is_end (const struct argp_option *opt)
-{
- return !opt->key && !opt->name && !opt->doc && !opt->group;
-}
-
-#endif /* __ARGP_H__ */
diff --git a/libshouldbeinlibc/cacheq.c b/libshouldbeinlibc/cacheq.c
index c8b0c989..5649903a 100644
--- a/libshouldbeinlibc/cacheq.c
+++ b/libshouldbeinlibc/cacheq.c
@@ -1,6 +1,6 @@
/* Helper functions for maintaining a fixed-size lru-ordered queue
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -82,7 +82,8 @@ cacheq_set_length (struct cacheq *cq, int length)
/* Source entries. */
struct cacheq_hdr *fh = cq->mru;
/* Destination entries (and limit). */
- struct cacheq_hdr *th = new_entries, *end = new_entries + esz * length;
+ struct cacheq_hdr *th = new_entries;
+ struct cacheq_hdr *end = new_entries + esz * (length - 1);
struct cacheq_hdr *prev_th = 0;
if (! new_entries)
@@ -91,7 +92,7 @@ cacheq_set_length (struct cacheq *cq, int length)
while (fh || th)
{
struct cacheq_hdr *next_th =
- (!th || th > end) ? 0 : (void *)th + esz;
+ (!th || th >= end) ? 0 : (void *)th + esz;
if (fh && th)
bcopy (fh, th, esz); /* Copy the bits in a moved entry. */
@@ -105,7 +106,7 @@ cacheq_set_length (struct cacheq *cq, int length)
th->next = next_th;
}
- /* Call user hooks as appropiate. */
+ /* Call user hooks as appropriate. */
if (fh && th)
{
if (cq->move_entry)
diff --git a/libshouldbeinlibc/exec-reauth.c b/libshouldbeinlibc/exec-reauth.c
index 2b068684..dd267ef7 100644
--- a/libshouldbeinlibc/exec-reauth.c
+++ b/libshouldbeinlibc/exec-reauth.c
@@ -1,6 +1,6 @@
/* Re-authentication in preparation for an exec
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 96, 98, 2000 Free Software Foundation, Inc.
Stolen by Miles Bader <miles@gnu.ai.mit.edu>, but really
written by Michael I. Bushnell p/BSG <mib@gnu.ai.mit.edu>
@@ -54,9 +54,12 @@ exec_reauth (auth_t auth, int secure, int must_reauth,
(isproc ? proc_reauthenticate : io_reauthenticate)
(*port, ref, MACH_MSG_TYPE_MAKE_SEND);
+ /* MAKE_SEND is safe here because we destroy REF ourselves. */
+
if (!err)
err = auth_user_authenticate (auth, ref, MACH_MSG_TYPE_MAKE_SEND,
&newport);
+ mach_port_destroy (mach_task_self (), ref);
if (err)
{
if (must_reauth)
@@ -73,22 +76,23 @@ exec_reauth (auth_t auth, int secure, int must_reauth,
*port = newport;
}
}
- mach_port_destroy (mach_task_self (), ref);
}
return 0;
}
-
+
/* Re-authenticate all the ports we are handing to the user
with this new port, and install the new auth port in ports. */
for (i = 0; i < num_fds && !err; ++i)
err = reauth (&fds[i], 0);
if (!err)
- if (secure)
- /* Not worth doing; the exec server will just do it again. */
- ports[INIT_PORT_CRDIR] = MACH_PORT_NULL;
- else
- err = reauth (&ports[INIT_PORT_CRDIR], 0);
+ {
+ if (secure)
+ /* Not worth doing; the exec server will just do it again. */
+ ports[INIT_PORT_CRDIR] = MACH_PORT_NULL;
+ else
+ err = reauth (&ports[INIT_PORT_CRDIR], 0);
+ }
if (!err)
err = reauth (&ports[INIT_PORT_PROC], 1);
if (!err)
diff --git a/libshouldbeinlibc/fsysops.c b/libshouldbeinlibc/fsysops.c
index 4e282f0b..f26069df 100644
--- a/libshouldbeinlibc/fsysops.c
+++ b/libshouldbeinlibc/fsysops.c
@@ -1,6 +1,6 @@
/* Some handy utility routines for fsys control ports
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -23,6 +23,7 @@
#include <errno.h>
#include <argz.h>
#include <mach.h>
+#include <sys/mman.h>
#include <hurd/fsys.h>
/* Make FSYS readonly or writable. */
@@ -57,7 +58,7 @@ fsys_get_readonly (fsys_t fsys, int *readonly)
for (opt = opts
; !ok && opt && opt < opts + opts_len
- ; opt = argz_next (opts, opts_len, opt))
+ ; opt = argz_next (opts, opts_len, opt))
if (strcasecmp (opt, "--readonly") == 0)
{
*readonly = 1;
@@ -74,7 +75,7 @@ fsys_get_readonly (fsys_t fsys, int *readonly)
if (opts != _opts)
/* Free out-of-line memory returned by fsys_get_options. */
- vm_deallocate (mach_task_self (), (vm_address_t)opts, opts_len);
+ munmap (opts, opts_len);
}
return err;
@@ -82,10 +83,10 @@ fsys_get_readonly (fsys_t fsys, int *readonly)
/* Tell FSYS to remount itself. */
error_t
-fsys_remount (fsys_t fsys, int readonly)
+fsys_update (fsys_t fsys, int readonly)
{
error_t err;
- char *opts = "--remount";
+ char *opts = "--update";
size_t opts_len = strlen (opts) + 1;
err = fsys_set_options (fsys, opts, opts_len, 0);
if (err == EINVAL)
diff --git a/libshouldbeinlibc/idvec-auth.c b/libshouldbeinlibc/idvec-auth.c
index 896bfdb7..bb7f4afd 100644
--- a/libshouldbeinlibc/idvec-auth.c
+++ b/libshouldbeinlibc/idvec-auth.c
@@ -1,8 +1,9 @@
/* Idvec functions that interact with an auth server
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1998, 1999, 2001, 2002, 2008
+ Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,12 +20,11 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <mach.h>
+#include <sys/mman.h>
#include <hurd/auth.h>
#include "idvec.h"
-typedef uid_t id_t;
-
/* Add to all of EFF_UIDS, AVAIL_UIDS, EFF_GIDS, AVAIL_GIDS (as if with
idvec_merge_ids()) the ids associated with the auth port AUTH. Any of
these parameters may be NULL if that information isn't desired. */
@@ -34,12 +34,12 @@ idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids,
auth_t auth)
{
error_t err;
- id_t eff_uid_buf[10], avail_uid_buf[20];
- id_t *_eff_uids = eff_uid_buf, *_avail_uids = avail_uid_buf;
- int num_eff_uids = 10, num_avail_uids = 20;
- id_t eff_gid_buf[10], avail_gid_buf[20];
- id_t *_eff_gids = eff_gid_buf, *_avail_gids = avail_gid_buf;
- int num_eff_gids = 10, num_avail_gids = 20;
+ uid_t eff_uid_buf[10], avail_uid_buf[20];
+ uid_t *_eff_uids = eff_uid_buf, *_avail_uids = avail_uid_buf;
+ size_t num_eff_uids = 10, num_avail_uids = 20;
+ uid_t eff_gid_buf[10], avail_gid_buf[20];
+ uid_t *_eff_gids = eff_gid_buf, *_avail_gids = avail_gid_buf;
+ size_t num_eff_gids = 10, num_avail_gids = 20;
err = auth_getids (auth,
&_eff_uids, &num_eff_uids, &_avail_uids, &num_avail_uids,
@@ -60,21 +60,25 @@ idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids,
/* Now that we've ensured there's enough space, none of these should
return an error. */
{
- idvec_merge_ids (eff_uids, _eff_uids, num_eff_uids);
- idvec_merge_ids (avail_uids, _avail_uids, num_avail_uids);
- idvec_merge_ids (eff_gids, _eff_gids, num_eff_gids);
- idvec_merge_ids (avail_gids, _avail_gids, num_avail_gids);
+ if (eff_uids)
+ idvec_merge_ids (eff_uids, _eff_uids, num_eff_uids);
+ if (avail_uids)
+ idvec_merge_ids (avail_uids, _avail_uids, num_avail_uids);
+ if (eff_gids)
+ idvec_merge_ids (eff_gids, _eff_gids, num_eff_gids);
+ if (avail_gids)
+ idvec_merge_ids (avail_gids, _avail_gids, num_avail_gids);
}
/* Deallocate any out-of-line memory we got back. */
if (_eff_uids != eff_uid_buf)
- vm_deallocate (mach_task_self (), (vm_address_t)_eff_uids, num_eff_uids);
+ munmap ((caddr_t) _eff_uids, num_eff_uids * sizeof (uid_t));
if (_avail_uids != avail_uid_buf)
- vm_deallocate (mach_task_self (), (vm_address_t)_avail_uids, num_avail_uids);
+ munmap ((caddr_t) _avail_uids, num_avail_uids * sizeof (uid_t));
if (_eff_gids != eff_gid_buf)
- vm_deallocate (mach_task_self (), (vm_address_t)_eff_gids, num_eff_gids);
+ munmap ((caddr_t) _eff_gids, num_eff_gids * sizeof (gid_t));
if (_avail_gids != avail_gid_buf)
- vm_deallocate (mach_task_self (), (vm_address_t)_avail_gids, num_avail_gids);
+ munmap ((caddr_t) _avail_gids, num_avail_gids * sizeof (gid_t));
return err;
}
diff --git a/libshouldbeinlibc/idvec-funcs.c b/libshouldbeinlibc/idvec-funcs.c
new file mode 100644
index 00000000..3bb0318d
--- /dev/null
+++ b/libshouldbeinlibc/idvec-funcs.c
@@ -0,0 +1,2 @@
+#define IDVEC_DEFINE_EI
+#include "idvec.h"
diff --git a/libshouldbeinlibc/idvec-impgids.c b/libshouldbeinlibc/idvec-impgids.c
new file mode 100644
index 00000000..66f82e21
--- /dev/null
+++ b/libshouldbeinlibc/idvec-impgids.c
@@ -0,0 +1,127 @@
+/* Add gids implied by a user
+
+ Copyright (C) 1997, 2001 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <idvec.h>
+#include <pwd.h>
+#include <grp.h>
+
+#define NUM_STATIC_GIDS 100 /* Initial size of static gid array. */
+
+/* The set of gids implied by a uid. */
+struct uid_implies
+{
+ uid_t uid; /* this uid... */
+ struct idvec *implies; /* implies these gids. */
+ struct uid_implies *next;
+};
+
+/* Cache of previously calculated results for add_implied_gids. */
+static struct uid_implies *uid_implies_cache = 0;
+
+/* Add to IMPLIED_GIDS those group ids implied by the user UID. */
+static error_t
+_merge_implied_gids (struct idvec *implied_gids, uid_t uid)
+{
+ struct uid_implies *ui;
+
+ for (ui = uid_implies_cache; ui; ui = ui->next)
+ if (ui->uid == uid)
+ return idvec_merge (implied_gids, ui->implies);
+
+ {
+ error_t err = 0;
+ struct passwd *pw = getpwuid (uid);
+
+ if (! pw)
+ err = EINVAL;
+ else
+ {
+ struct idvec *cache = make_idvec ();
+#ifdef HAVE_GETGROUPLIST
+ gid_t _gids[NUM_STATIC_GIDS], *gids = _gids;
+ int maxgids = NUM_STATIC_GIDS;
+ int ngids = getgrouplist (pw->pw_name, pw->pw_gid, gids, &maxgids);
+
+ if (ngids == -1)
+ {
+ gids = malloc (maxgids * sizeof (gid_t));
+ if (! gids)
+ err = ENOMEM;
+ else
+ ngids = getgrouplist (pw->pw_name, pw->pw_gid, gids, &maxgids);
+ }
+
+ if (! cache)
+ err = ENOMEM;
+
+ if (! err)
+ {
+ err = idvec_merge_ids (cache, gids, ngids);
+ if (gids != _gids)
+ free (gids);
+ }
+#else
+#warning "getgrouplist() not available; supplementary group IDs unsupported."
+ if (! cache)
+ err = ENOMEM;
+ else
+ {
+ err = idvec_add_new (cache, pw->pw_gid);
+ if (err)
+ idvec_free (cache);
+ }
+#endif
+
+ if (! err)
+ {
+ idvec_merge (implied_gids, cache);
+ ui = malloc (sizeof (struct uid_implies));
+ if (ui)
+ {
+ ui->uid = uid;
+ ui->implies = cache;
+ ui->next = uid_implies_cache;
+ uid_implies_cache = ui;
+ }
+ else
+ idvec_free (cache);
+ }
+ }
+
+ return err;
+ }
+}
+
+/* Add to GIDS those group ids implied by the users in UIDS. */
+error_t
+idvec_merge_implied_gids (struct idvec *gids, const struct idvec *uids)
+{
+ int i;
+ error_t err = 0;
+ for (i = 0; i < uids->num; i++)
+ {
+ error_t this_err = _merge_implied_gids (gids, uids->ids[i]);
+ if (this_err && !err)
+ err = this_err;
+ }
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec-rep.c b/libshouldbeinlibc/idvec-rep.c
new file mode 100644
index 00000000..b20e58ca
--- /dev/null
+++ b/libshouldbeinlibc/idvec-rep.c
@@ -0,0 +1,164 @@
+/* idvec string representation
+
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <idvec.h>
+#include <grp.h>
+#include <pwd.h>
+
+/* Return a string representation of the ids in IDVEC, each id separated by
+ the string SEP (default ","). SHOW_VALUES and SHOW_NAMES reflect how each
+ id is printed (if SHOW_NAMES is true values are used where names aren't
+ available); if both are true, the `VALUE(NAME)' format is used.
+ ID_NAME_FN is used to map each id to a name; it should return a malloced
+ string, which will be freed here. The empty string is returned for an
+ empty list, and 0 for an allocation error. */
+char *
+idvec_rep (const struct idvec *idvec, int show_values, int show_names,
+ char *(*id_name_fn) (uid_t id), const char *sep)
+{
+ size_t sep_len;
+ char *rep = 0;
+ size_t rep_len = 0, rep_sz = 0;
+
+ int ensure_room (size_t amount)
+ {
+ size_t end = rep_len + amount;
+ if (end > rep_sz)
+ {
+ size_t new_sz = rep_sz + end;
+ char *new_rep = realloc (rep, new_sz);
+ if (new_rep)
+ {
+ rep = new_rep;
+ rep_sz = new_sz;
+ }
+ else
+ return 0;
+ }
+ return 1;
+ }
+ int add_id (uid_t val, char *name)
+ {
+ if (!name || show_values)
+ {
+ if (! ensure_room (10))
+ return 0;
+ rep_len += snprintf (rep + rep_len, 10, "%d", val);
+ }
+ if (name)
+ {
+ size_t nlen = strlen (name) + 3;
+ if (! ensure_room (nlen))
+ {
+ free (name);
+ return 0;
+ }
+ rep_len +=
+ snprintf (rep + rep_len, nlen, show_values ? "(%s)" : "%s", name);
+ free (name);
+ }
+ return 1;
+ }
+
+ if (! sep)
+ sep = ",";
+ sep_len = strlen (sep);
+
+ if (idvec->num > 0)
+ {
+ int i;
+
+ for (i = 0; i < idvec->num; i++)
+ {
+ char *name = 0;
+ uid_t val = idvec->ids[i];
+
+ if (i > 0)
+ {
+ if (ensure_room (sep_len))
+ {
+ strcpy (rep + rep_len, sep);
+ rep_len += sep_len;
+ }
+ else
+ break;
+ }
+
+ if (show_names || !show_values)
+ name = (*id_name_fn) (val);
+ if (! add_id (val, name))
+ break;
+ }
+
+ if (i < idvec->num)
+ {
+ free (rep);
+ return 0;
+ }
+
+ return rep;
+ }
+
+ return strdup ("");
+}
+
+/* Return a malloced string with the name of the user UID. */
+static char *
+lookup_uid (uid_t uid)
+{
+ char buf[1024];
+ struct passwd _pw, *pw;
+ if (getpwuid_r (uid, &_pw, buf, sizeof buf, &pw) == 0)
+ return strdup (pw->pw_name);
+ else
+ return 0;
+}
+
+/* Return a malloced string with the name of the group GID. */
+static char *
+lookup_gid (gid_t gid)
+{
+ char buf[1024];
+ struct group _gr, *gr;
+ if (getgrgid_r (gid, &_gr, buf, sizeof buf, &gr) == 0)
+ return strdup (gr->gr_name);
+ else
+ return 0;
+}
+
+/* Like idvec_rep, mapping ids to user names. */
+char *
+idvec_uids_rep (const struct idvec *idvec, int show_values, int show_names,
+ const char *sep)
+{
+ return idvec_rep (idvec, show_values, show_names, lookup_uid, sep);
+}
+
+/* Like idvec_rep, mapping ids to group names. */
+char *
+idvec_gids_rep (const struct idvec *idvec, int show_values, int show_names,
+ const char *sep)
+{
+ return idvec_rep (idvec, show_values, show_names, lookup_gid, sep);
+}
diff --git a/libshouldbeinlibc/idvec-verify.c b/libshouldbeinlibc/idvec-verify.c
new file mode 100644
index 00000000..981f86ac
--- /dev/null
+++ b/libshouldbeinlibc/idvec-verify.c
@@ -0,0 +1,362 @@
+/* Verify user passwords
+
+ Copyright (C) 1996, 1997, 1998, 1999, 2002, 2008
+ Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <idvec.h>
+#include <grp.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <crypt.h>
+
+#define SHADOW_PASSWORD_STRING "x" /* pw_passwd contents for shadow passwd */
+
+#pragma weak crypt
+
+static error_t verify_id (); /* FWD */
+
+/* Get a password from the user, returning it in malloced storage. */
+static char *
+get_passwd (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ char *st = getpass (prompt);
+ if (st)
+ st = strdup (st);
+ return st;
+}
+
+/* Verify PASSWORD using /etc/passwd (and maybe /etc/shadow). */
+static error_t
+verify_passwd (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ const char *encrypted;
+ int wheel_uid = (intptr_t)hook;
+ const char *sys_encrypted;
+
+ if (! pwd_or_grp)
+ /* No password db entry for ID; if ID is root, the system is probably
+ really fucked up, so grant it (heh). */
+ return (id == 0 ? 0 : EACCES);
+
+ /* The encrypted password in the passwd db. */
+ sys_encrypted =
+ (is_group
+ ? ((struct passwd *)pwd_or_grp)->pw_passwd
+ : ((struct group *)pwd_or_grp)->gr_passwd);
+
+ if (sys_encrypted[0] == '\0')
+ return 0; /* No password. */
+
+ if (crypt)
+ /* Encrypt the password entered by the user (SYS_ENCRYPTED is the salt). */
+ encrypted = crypt (password, sys_encrypted);
+ else
+ /* No crypt on this system! Use plain-text passwords. */
+ encrypted = password;
+
+ if (! encrypted)
+ /* Crypt failed. */
+ return errno;
+
+ /* See whether the user's password matches the system one. */
+ if (strcmp (encrypted, sys_encrypted) == 0)
+ /* Password check succeeded. */
+ return 0;
+ else if (id == 0 && !is_group && wheel_uid)
+ /* Special hack: a user attempting to gain root access can use
+ their own password (instead of root's) if they're in group 0. */
+ {
+ struct passwd _pw, *pw;
+ char lookup_buf[1024];
+ char sp_lookup_buf[1024];
+
+ const char *check_shadow (struct passwd *pw)
+ {
+ if (strcmp (pw->pw_passwd, SHADOW_PASSWORD_STRING) == 0)
+ {
+ /* When encrypted password is "x", try shadow passwords. */
+ struct spwd _sp, *sp;
+ if (getspnam_r (pw->pw_name, &_sp, sp_lookup_buf,
+ sizeof sp_lookup_buf, &sp) == 0)
+ return sp->sp_pwdp;
+ }
+ return pw->pw_passwd;
+ }
+
+ if (getpwuid_r (wheel_uid, &_pw, lookup_buf, sizeof lookup_buf, &pw))
+ return errno ?: EINVAL;
+
+ sys_encrypted = check_shadow (pw);
+
+ encrypted = crypt (password, sys_encrypted);
+ if (! encrypted)
+ /* Crypt failed. */
+ return errno;
+
+ if (strcmp (encrypted, sys_encrypted) == 0)
+ /* *this* password is correct! */
+ return 0;
+ }
+
+ return EACCES;
+}
+
+/* Make sure the user has the right to the ids in UIDS and GIDS, given that
+ we know he already has HAVE_UIDS and HAVE_GIDS, asking for passwords (with
+ GETPASS_FN) where necessary; any of the arguments may be 0, which is
+ treated the same as if they were empty. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. Any uid/gid < 0 will be guaranteed to
+ fail regardless of what the user types. GETPASS_FN should ask for a
+ password from the user, and return it in malloced storage; it defaults to
+ using the standard libc function getpass. If VERIFY_FN is 0, then the
+ users password will be encrypted with crypt and compared with the
+ password/group entry's encrypted password, otherwise, VERIFY_FN will be
+ called to check the entered password's validity; it should return 0 if the
+ given password is correct, or an error code. The common arguments to
+ GETPASS_FN and VERIFY_FN are: ID, the user/group id; IS_GROUP, true if its
+ a group, or false if a user; PWD_OR_GRP, a pointer to either the passwd or
+ group entry for ID, and HOOK, containing the appropriate hook passed into
+ idvec_verify. */
+error_t
+idvec_verify (const struct idvec *uids, const struct idvec *gids,
+ const struct idvec *have_uids, const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ if (have_uids && idvec_contains (have_uids, 0))
+ /* Root can do anything. */
+ return 0;
+ else
+ {
+ int i;
+ int multiple = 0; /* Asking for multiple ids? */
+ error_t err = 0; /* Our return status. */
+ struct idvec implied_gids = IDVEC_INIT; /* Gids implied by uids. */
+ /* If we already are in group 0 (`wheel'), this user's password can be
+ used to get root privileges instead of root's. */
+ int wheel_uid =
+ ((have_uids && have_gids
+ && (idvec_contains (have_gids, 0) && have_uids->num > 0))
+ ? have_uids->ids[0]
+ : 0);
+
+ if (! verify_fn)
+ {
+ verify_fn = verify_passwd;
+ verify_hook = (void *)(intptr_t)wheel_uid;
+ }
+
+ /* See if there are multiple ids in contention, in which case we should
+ name each user/group as we ask for its password. */
+ if (uids && gids)
+ {
+ int num_non_implied_gids = 0;
+
+ /* Calculate which groups we need not ask about because they are
+ implied by the uids which we (will) have verified. Note that we
+ ignore any errors; at most, it means we will ask for too many
+ passwords. */
+ idvec_merge_implied_gids (&implied_gids, uids);
+
+ for (i = 0; i < gids->num; i++)
+ if (! idvec_contains (&implied_gids, gids->ids[i]))
+ num_non_implied_gids++;
+
+ multiple = (uids->num + num_non_implied_gids) > 1;
+ }
+ else if (uids)
+ multiple = uids->num > 1;
+ else if (gids)
+ multiple = gids->num > 1;
+
+ if (uids && idvec_contains (uids, 0))
+ /* root is being asked for, which, once granted will provide access for
+ all the others. */
+ err = verify_id (0, 0, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ else
+ {
+ if (uids)
+ /* Check uids */
+ for (i = 0; i < uids->num && !err; i++)
+ {
+ uid_t uid = uids->ids[i];
+ if (!have_uids || !idvec_contains (have_uids, uid))
+ err = verify_id (uid, 0, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ }
+
+ if (gids)
+ /* Check gids */
+ for (i = 0; i < gids->num && !err; i++)
+ {
+ gid_t gid = gids->ids[i];
+ if ((!have_gids || !idvec_contains (have_gids, gid))
+ && !idvec_contains (&implied_gids, gid))
+ err = verify_id (gid, 1, multiple,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+ }
+ }
+
+ idvec_fini (&implied_gids);
+
+ return err;
+ }
+}
+
+/* Verify that the user should be allowed to assume the indentity of the
+ user/group ID (depending on whether IS_GROUP is false/true). If MULTIPLE
+ is true, then this is one of multiple ids being verified, so */
+static error_t
+verify_id (uid_t id, int is_group, int multiple,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ int err;
+ void *pwd_or_grp = 0;
+ char *name = 0;
+ char *prompt = 0, *password;
+ char id_lookup_buf[1024];
+ char sp_lookup_buf[1024];
+
+ /* VERIFY_FN should have been defaulted in idvec_verify if necessary. */
+ assert (verify_fn);
+
+ if (id != (uid_t) -1)
+ do
+ {
+ if (is_group)
+ {
+ struct group _gr, *gr;
+ if (getgrgid_r (id, &_gr, id_lookup_buf, sizeof id_lookup_buf, &gr)
+ == 0)
+ {
+ if (!gr->gr_passwd || !*gr->gr_passwd)
+ return (*verify_fn) ("", id, 1, gr, verify_hook);
+ name = gr->gr_name;
+ pwd_or_grp = gr;
+ }
+ }
+ else
+ {
+ struct passwd _pw, *pw;
+ if (getpwuid_r (id, &_pw, id_lookup_buf, sizeof id_lookup_buf, &pw)
+ == 0)
+ {
+ if (strcmp (pw->pw_passwd, SHADOW_PASSWORD_STRING) == 0)
+ {
+ /* When encrypted password is "x", check shadow
+ passwords to see if there is an empty password. */
+ struct spwd _sp, *sp;
+ if (getspnam_r (pw->pw_name, &_sp, sp_lookup_buf,
+ sizeof sp_lookup_buf, &sp) == 0)
+ /* The storage for the password string is in
+ SP_LOOKUP_BUF, a local variable in this function.
+ We Know that the only use of PW->pw_passwd will be
+ in the VERIFY_FN call in this function, and that
+ the pointer will not be stored past the call. */
+ pw->pw_passwd = sp->sp_pwdp;
+ }
+
+ if (pw->pw_passwd[0] == '\0')
+ return (*verify_fn) ("", id, 0, pw, verify_hook);
+ name = pw->pw_name;
+ pwd_or_grp = pw;
+ }
+ }
+ if (! name)
+ {
+ /* [ug]id lookup failed! */
+ if (id != 0 || is_group)
+ /* If ID != 0, then it's probably just an unknown id, so ask for
+ the root password instead -- root should be able to do
+ anything. */
+ {
+ id = 0; /* Root */
+ is_group = 0; /* uid */
+ multiple = 1; /* Explicitly ask for root's password. */
+ }
+ else
+ /* No password entry for root. */
+ name = "root";
+ }
+ }
+ while (! name);
+
+ if (! getpass_fn)
+ /* Default GETPASS_FN to using getpass. */
+ getpass_fn = get_passwd;
+
+ if (multiple)
+ {
+ if (name)
+ asprintf (&prompt, "Password for %s%s:",
+ is_group ? "group " : "", name);
+ else
+ asprintf (&prompt, "Password for %s %d:",
+ is_group ? "group" : "user", id);
+ }
+
+ /* Prompt the user for the password. */
+ if (prompt)
+ {
+ password =
+ (*getpass_fn) (prompt, id, is_group, pwd_or_grp, getpass_hook);
+ free (prompt);
+ }
+ else
+ password =
+ (*getpass_fn) ("Password:", id, is_group, pwd_or_grp, getpass_hook);
+
+ /* Check the user's answer. */
+ if (password)
+ {
+ err = (*verify_fn) (password, id, is_group, pwd_or_grp, verify_hook);
+
+ /* Paranoia may destroya. */
+ memset (password, 0, strlen (password));
+
+ free (password);
+ }
+ else
+ err = EACCES;
+
+ return err;
+}
diff --git a/libshouldbeinlibc/idvec.c b/libshouldbeinlibc/idvec.c
index 6daa639a..24adeb8f 100644
--- a/libshouldbeinlibc/idvec.c
+++ b/libshouldbeinlibc/idvec.c
@@ -1,6 +1,6 @@
/* Routines for vectors of uids/gids
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -22,8 +22,6 @@
#include <string.h>
#include <idvec.h>
-typedef uid_t id_t;
-
/* Return a new, empty, idvec, or NULL if there wasn't enough memory. */
struct idvec *
make_idvec ()
@@ -67,7 +65,7 @@ idvec_ensure (struct idvec *idvec, unsigned num)
{
if (num > idvec->alloced)
{
- id_t *_ids = realloc (idvec->ids, num * sizeof (id_t));
+ uid_t *_ids = realloc (idvec->ids, num * sizeof (uid_t));
if (! _ids)
return ENOMEM;
idvec->ids = _ids;
@@ -83,47 +81,42 @@ idvec_grow (struct idvec *idvec, unsigned inc)
{
return idvec_ensure (idvec, idvec->num + inc);
}
-
+
/* Returns true if IDVEC contains ID, at or after position POS. */
int
-idvec_tail_contains (struct idvec *idvec, unsigned pos, id_t id)
+idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id)
{
- while (pos < idvec->num)
- if (idvec->ids[pos++] == id)
+ uid_t *ids = idvec->ids, *end = ids + idvec->num, *p = ids + pos;
+ while (p < end)
+ if (*p++ == id)
return 1;
return 0;
}
-
-/* Returns true if IDVEC contains ID. */
-int
-idvec_contains (struct idvec *idvec, id_t id)
-{
- return idvec_tail_contains (idvec, 0, id);
-}
/* 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, id_t id)
+idvec_insert (struct idvec *idvec, unsigned pos, uid_t id)
{
error_t err = 0;
unsigned num = idvec->num;
+ unsigned new_num = (pos < num ? num + 1 : pos + 1);
if (idvec->alloced == num)
/* If we seem to be growing by just one, actually prealloc some more. */
- err = idvec_grow (idvec, num + 1);
+ err = idvec_ensure (idvec, new_num + num);
else
- err = idvec_grow (idvec, 1);
+ err = idvec_ensure (idvec, new_num);
if (! err)
{
- id_t *ids = idvec->ids;
+ uid_t *ids = idvec->ids;
if (pos < num)
- bcopy (ids + pos, ids + pos + 1, (num - pos) * sizeof (id_t));
+ bcopy (ids + pos, ids + pos + 1, (num - pos) * sizeof (uid_t));
else if (pos > num)
- bzero (ids + num, (pos - num) * sizeof (id_t));
+ bzero (ids + num, (pos - num) * sizeof (uid_t));
ids[pos] = id;
- idvec->num = num + 1;
+ idvec->num = new_num;
}
return err;
@@ -132,7 +125,7 @@ idvec_insert (struct idvec *idvec, unsigned pos, id_t id)
/* Add ID onto the end of IDVEC, returning ENOMEM if there's not enough memory,
or 0. */
error_t
-idvec_add (struct idvec *idvec, id_t id)
+idvec_add (struct idvec *idvec, uid_t id)
{
return idvec_insert (idvec, idvec->num, id);
}
@@ -140,7 +133,7 @@ idvec_add (struct idvec *idvec, id_t id)
/* If IDVEC doesn't contain ID, add it onto the end, returning ENOMEM if
there's not enough memory; otherwise, do nothing. */
error_t
-idvec_add_new (struct idvec *idvec, id_t id)
+idvec_add_new (struct idvec *idvec, uid_t id)
{
if (idvec_contains (idvec, id))
return 0;
@@ -151,7 +144,7 @@ idvec_add_new (struct idvec *idvec, id_t id)
/* If IDVEC doesn't contain ID at position POS or after, insert it at POS,
returning ENOMEM if there's not enough memory; otherwise, do nothing. */
error_t
-idvec_insert_new (struct idvec *idvec, unsigned pos, id_t id)
+idvec_insert_new (struct idvec *idvec, unsigned pos, uid_t id)
{
if (idvec_tail_contains (idvec, pos, id))
return 0;
@@ -159,10 +152,33 @@ idvec_insert_new (struct idvec *idvec, unsigned pos, id_t id)
return idvec_insert (idvec, pos, id);
}
+/* Set the ids in IDVEC to IDS (NUM elements long); delete whatever
+ the previous ids were. */
+error_t
+idvec_set_ids (struct idvec *idvec, const uid_t *ids, unsigned num)
+{
+ error_t err;
+
+ err = idvec_ensure (idvec, num);
+ if (!err)
+ {
+ bcopy (ids, idvec->ids, num * sizeof (uid_t));
+ idvec->num = num;
+ }
+ return err;
+}
+
+/* Like idvec_set_ids, but get the new ids from new. */
+error_t
+idvec_set (struct idvec *idvec, const struct idvec *new)
+{
+ return idvec_set_ids (idvec, new->ids, new->num);
+}
+
/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as long as it
wasn't previously in IDVEC. */
error_t
-idvec_merge_ids (struct idvec *idvec, id_t *ids, unsigned num)
+idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num)
{
error_t err = 0;
unsigned num_old = idvec->num;
@@ -181,34 +197,77 @@ idvec_merge_ids (struct idvec *idvec, id_t *ids, unsigned num)
/* Adds each id from NEW to IDVEC, as if with idvec_add_new(). */
error_t
-idvec_merge (struct idvec *idvec, struct idvec *new)
+idvec_merge (struct idvec *idvec, const struct idvec *new)
{
return idvec_merge_ids (idvec, new->ids, new->num);
}
-/* Remove any occurances of ID in IDVEC after position POS> Returns true if
- anything was done. */
+/* Remove any occurrences of ID in IDVEC after position POS.
+ Returns true if anything was done. */
int
-idvec_remove (struct idvec *idvec, unsigned pos, id_t id)
+idvec_remove (struct idvec *idvec, unsigned pos, uid_t id)
{
- int left = idvec->num - pos;
- id_t *ids = idvec->ids + pos, *targ = ids;
- while (left--)
+ if (pos < idvec->num)
{
- if (*ids != id)
+ int left = idvec->num - pos;
+ uid_t *ids = idvec->ids + pos, *targ = ids;
+ while (left--)
{
- if (ids != targ)
- *targ = *ids;
- targ++;
+ if (*ids != id)
+ {
+ if (ids != targ)
+ *targ = *ids;
+ targ++;
+ }
+ ids++;
}
- ids++;
+ if (ids == targ)
+ return 0;
+ idvec->num = targ - idvec->ids;
+ return 1;
}
- if (ids == targ)
+ else
return 0;
- idvec->num = targ - idvec->ids;
- return 1;
}
+/* Remove all ids in SUB from IDVEC, returning true if anything was done. */
+int
+idvec_subtract (struct idvec *idvec, const struct idvec *sub)
+{
+ int i;
+ int done = 0;
+ for (i = 0; i < sub->num; i++)
+ done |= idvec_remove (idvec, 0, sub->ids[i]);
+ return done;
+}
+
+/* Remove all ids from IDVEC that are *not* in KEEP, returning true if
+ anything was changed. */
+int
+idvec_keep (struct idvec *idvec, const struct idvec *keep)
+{
+ uid_t *old = idvec->ids, *new = old, *end = old + idvec->num;
+
+ while (old < end)
+ {
+ uid_t id = *old++;
+ if (idvec_contains (keep, id))
+ {
+ if (old != new)
+ *new = id;
+ new++;
+ }
+ }
+
+ if (old != new)
+ {
+ idvec->num = new - idvec->ids;
+ return 1;
+ }
+ else
+ return 0;
+}
+
/* Deleted the id at position POS in IDVEC. */
void
idvec_delete (struct idvec *idvec, unsigned pos)
@@ -216,20 +275,20 @@ idvec_delete (struct idvec *idvec, unsigned pos)
unsigned num = idvec->num;
if (pos < num)
{
- id_t *ids = idvec->ids;
+ uid_t *ids = idvec->ids;
idvec->num = --num;
if (num > pos)
- bcopy (ids + pos + 1, ids + pos, (num - pos) * sizeof (id_t));
+ bcopy (ids + pos + 1, ids + pos, (num - pos) * sizeof (uid_t));
}
}
-/* Insert ID at position POS in IDVEC, remoint any instances of ID previously
+/* Insert ID at position POS in IDVEC, remove any instances of ID previously
present at POS or after. ENOMEM is returned if there's not enough memory,
otherwise 0. */
error_t
-idvec_insert_only (struct idvec *idvec, unsigned pos, id_t id)
+idvec_insert_only (struct idvec *idvec, unsigned pos, uid_t id)
{
- if (idvec->ids[pos] == id)
+ if (idvec->num > pos && idvec->ids[pos] == id)
return 0;
else
{
@@ -238,39 +297,37 @@ idvec_insert_only (struct idvec *idvec, unsigned pos, id_t id)
}
}
-/* EFF and AVAIL should be idvec's corresponding to a processes effective and
- available ids. ID replaces the first id in EFF, and what it replaces is
- preserved by adding it to AVAIL (if not already present). If SECURE is
- non-NULL, and ID was not previously present in either EFF or AVAIL, then
- *SECURE is set to true. ENOMEM is returned if a malloc fails, otherwise
- 0. The return parameters are only touched if this call succeeds. */
+/* EFF and AVAIL should be idvec's corresponding to a processes
+ effective and available ids. ID replaces the first id in EFF, and,
+ if there are any IDs in AVAIL, replaces the second ID in AVAIL;
+ what it replaces in any case is preserved by adding it to AVAIL if
+ not already present. In addition, the If SECURE is non-NULL, and
+ ID was not previously present in either EFF or AVAIL, then *SECURE
+ is set to true. ENOMEM is returned if a malloc fails, otherwise 0.
+ The return parameters are only touched if this call succeeds. */
error_t
-idvec_setid (struct idvec *eff, struct idvec *avail, id_t id, int *secure)
+idvec_setid (struct idvec *eff, struct idvec *avail, uid_t id, int *secure)
{
error_t err;
/* True if ID was not previously present in either EFF or AVAIL. */
int _secure = !idvec_contains (eff, id) && !idvec_contains (avail, id);
if (eff->num > 0)
- /* If there are any old effective ids, we replace eff[0] with ID, and try
- to preserve the old eff[0] by putting it in AVAIL list if necessary. */
{
- if (avail->num == 0)
- /* The old eff[0] becomes avail[0] (the posix real id). */
- err = idvec_add (avail, eff->ids[0]);
- else
- /* We preserve the old real id, and add eff[0] to the list of saved
- ids (if necessary). Inserting it means that the latest id saved
- will correspond to the (single) posix saved id. */
- err = idvec_insert_only (avail, 1, eff->ids[0]);
-
- /* Replace eff[0] with the new id. */
- eff->ids[0] = id;
+ /* If there are any old effective ids, we replace eff[0] with
+ ID, and try to preserve the old eff[0] by putting it in AVAIL
+ list if necessary. */
+ err = idvec_add_new (avail, eff->ids[0]);
+ if (!err)
+ eff->ids[0] = id;
}
else
/* No previous effective ids, just make ID the first one. */
err = idvec_add (eff, id);
+ if (avail->num > 0 && !err)
+ err = idvec_insert_only (avail, 1, id);
+
if (err)
return err;
diff --git a/libshouldbeinlibc/idvec.h b/libshouldbeinlibc/idvec.h
index 8e99d433..abbc273e 100644
--- a/libshouldbeinlibc/idvec.h
+++ b/libshouldbeinlibc/idvec.h
@@ -1,8 +1,7 @@
/* Routines for vectors of uids/gids
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,99,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,8 +21,16 @@
#define __IDVEC_H__
#include <sys/types.h>
-#include <errno.h>
#include <hurd/hurd_types.h>
+#include <errno.h>
+#include <string.h>
+#include <features.h>
+
+#ifdef IDVEC_DEFINE_EI
+#define IDVEC_EI
+#else
+#define IDVEC_EI __extern_inline
+#endif
struct idvec
{
@@ -31,11 +38,14 @@ struct idvec
unsigned num, alloced;
};
+#define IDVEC_INIT { 0 }
+
/* Return a new, empty, idvec, or NULL if there wasn't enough memory. */
struct idvec *make_idvec (void);
/* Free the storage pointed to by IDVEC->ids. */
void idvec_free_contents (struct idvec *idvec);
+#define idvec_fini idvec_free_contents
/* Free IDVEC, but not the storage pointed to by the IDS field. */
void idvec_free_wrapper (struct idvec *idvec);
@@ -43,13 +53,40 @@ void idvec_free_wrapper (struct idvec *idvec);
/* 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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(IDVEC_DEFINE_EI)
+
/* Mark IDVEC as not containing any ids. */
-extern inline void
+IDVEC_EI void
idvec_clear (struct idvec *idvec)
{
idvec->num = 0;
}
+/* Returns true if IDVEC contains no ids. */
+IDVEC_EI int
+idvec_is_empty (const struct idvec *idvec)
+{
+ return idvec->num == 0;
+}
+
+/* Return true if IDVEC1 has contents identical to IDVEC2. */
+IDVEC_EI int
+idvec_equal (const struct idvec *idvec1, const struct idvec *idvec2)
+{
+ size_t num = idvec1->num;
+ return idvec2->num == num
+ && (num == 0
+ || 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
@@ -61,10 +98,20 @@ error_t idvec_ensure (struct idvec *idvec, unsigned num);
error_t idvec_grow (struct idvec *idvec, unsigned inc);
/* Returns true if IDVEC contains ID, at or after position POS. */
-int idvec_tail_contains (struct idvec *idvec, unsigned pos, uid_t id);
+int idvec_tail_contains (const struct idvec *idvec, unsigned pos, uid_t id);
+
+extern int idvec_contains (const struct idvec *idvec, uid_t id);
+
+#if defined(__USE_EXTERN_INLINES) || defined(IDVEC_DEFINE_EI)
/* Returns true if IDVEC contains ID. */
-int idvec_contains (struct idvec *idvec, uid_t id);
+IDVEC_EI 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. */
@@ -82,31 +129,47 @@ error_t idvec_add_new (struct idvec *idvec, uid_t id);
returning ENOMEM if there's not enough memory; otherwise, do nothing. */
error_t idvec_insert_new (struct idvec *idvec, unsigned pos, uid_t id);
+/* Set the ids in IDVEC to IDS (NUM elements long); delete whatever
+ the previous ids were. */
+error_t idvec_set_ids (struct idvec *idvec, const uid_t *ids, unsigned num);
+
+/* Like idvec_set_ids, but get the new ids from new. */
+error_t idvec_set (struct idvec *idvec, const struct idvec *new);
+
/* Adds each id in the vector IDS (NUM elements long) to IDVEC, as if with
idvec_add_new(). */
-error_t idvec_merge_ids (struct idvec *idvec, uid_t *ids, unsigned num);
+error_t idvec_merge_ids (struct idvec *idvec, const uid_t *ids, unsigned num);
/* Adds each id from NEW to IDVEC, as if with idvec_add_new(). */
-error_t idvec_merge (struct idvec *idvec, struct idvec *new);
+error_t idvec_merge (struct idvec *idvec, const struct idvec *new);
-/* Remove any occurances of ID in IDVEC after position POS> Returns true if
+/* Remove all ids in SUB from IDVEC, returning true if anything was done. */
+int idvec_subtract (struct idvec *idvec, const struct idvec *sub);
+
+/* Remove all ids from IDVEC that are *not* in KEEP, returning true if
+ anything was changed. */
+int idvec_keep (struct idvec *idvec, const struct idvec *keep);
+
+/* Remove any occurrences of ID in IDVEC after position POS> Returns true if
anything was done. */
int idvec_remove (struct idvec *idvec, unsigned pos, uid_t id);
/* Deleted the id at position POS in IDVEC. */
void idvec_delete (struct idvec *idvec, unsigned pos);
-/* Insert ID at position POS in IDVEC, remoint any instances of ID previously
+/* Insert ID at position POS in IDVEC, remove any instances of ID previously
present at POS or after. ENOMEM is returned if there's not enough memory,
otherwise 0. */
error_t idvec_insert_only (struct idvec *idvec, unsigned pos, uid_t id);
-/* EFF and AVAIL should be idvec's corresponding to a processes effective and
- available ids. ID replaces the first id in EFF, and what it replaces is
- preserved by adding it to AVAIL (if not already present). If SECURE is
- non-NULL, and ID was not previously present in either EFF or AVAIL, then
- *SECURE is set to true. ENOMEM is returned if a malloc fails, otherwise
- 0. The return parameters are only touched if this call succeeds. */
+/* EFF and AVAIL should be idvec's corresponding to a process's
+ effective and available ids. ID replaces the first id in EFF, and,
+ if there are any IDs in AVAIL, replaces the second ID in AVAIL;
+ what it replaces in any case is preserved by adding it to AVAIL if
+ not already present. In addition, the If SECURE is non-NULL, and
+ ID was not previously present in either EFF or AVAIL, then *SECURE
+ is set to true. ENOMEM is returned if a malloc fails, otherwise 0.
+ The return parameters are only touched if this call succeeds. */
error_t idvec_setid (struct idvec *eff, struct idvec *avail, uid_t id,
int *secure);
@@ -117,4 +180,58 @@ error_t idvec_merge_auth (struct idvec *eff_uids, struct idvec *avail_uids,
struct idvec *eff_gids, struct idvec *avail_gids,
auth_t auth);
+/* Add to GIDS those group ids implied by the users in UIDS. */
+error_t idvec_merge_implied_gids (struct idvec *gids, const struct idvec *uids);
+
+/* Make sure the user has the right to the ids in UIDS and GIDS, given that
+ we know he already has HAVE_UIDS and HAVE_GIDS, asking for passwords (with
+ GETPASS_FN) where necessary; any of the arguments may be 0, which is
+ treated the same as if they were empty. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. Any uid/gid < 0 will be guaranteed to
+ fail regardless of what the user types. GETPASS_FN should ask for a
+ password from the user, and return it in malloced storage; it defaults to
+ using the standard libc function getpass. If VERIFY_FN is 0, then the
+ users password will be encrypted with crypt and compared with the
+ password/group entry's encrypted password, otherwise, VERIFY_FN will be
+ called to check the entered password's validity; it should return 0 if the
+ given password is correct, or an error code. The common arguments to
+ GETPASS_FN and VERIFY_FN are: ID, the user/group id; IS_GROUP, true if its
+ a group, or false if a user; PWD_OR_GRP, a pointer to either the passwd or
+ group entry for ID, and HOOK, containing the appropriate hook passed into
+ idvec_verify. */
+error_t idvec_verify (const struct idvec *uids, const struct idvec *gids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook);
+
+/* Return a string representation of the ids in IDVEC, each id separated by
+ the string SEP (default ","). SHOW_VALUES and SHOW_NAMES reflect how each
+ id is printed (if SHOW_NAMES is true values are used where names aren't
+ available); if both are true, the `VALUE(NAME)' format is used.
+ ID_NAME_FN is used to map each id to a name; it should return a malloced
+ string, which will be freed here. The empty string is returned for an
+ empty list, and 0 for an allocation error. */
+char *idvec_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ char *(*id_name_fn) (uid_t id),
+ const char *sep);
+
+/* Like idvec_rep, mapping ids to user names. */
+char *idvec_uids_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ const char *sep);
+
+/* Like idvec_rep, mapping ids to group names. */
+char *idvec_gids_rep (const struct idvec *idvec,
+ int show_values, int show_names,
+ const char *sep);
+
#endif /* __IDVEC_H__ */
diff --git a/libshouldbeinlibc/localhost.c b/libshouldbeinlibc/localhost.c
index f0c67541..f0225116 100644
--- a/libshouldbeinlibc/localhost.c
+++ b/libshouldbeinlibc/localhost.c
@@ -39,18 +39,27 @@ localhost ()
errno = 0;
if (buf) {
+ char *new;
buf_len += buf_len;
- buf = realloc (buf, buf_len);
+ new = realloc (buf, buf_len);
+ if (! new)
+ {
+ free (buf);
+ buf = 0;
+ errno = ENOMEM;
+ return 0;
+ }
+ else
+ buf = new;
} else {
buf_len = 128; /* Initial guess */
buf = malloc (buf_len);
+ if (! buf)
+ {
+ errno = ENOMEM;
+ return 0;
+ }
}
-
- if (! buf)
- {
- errno = ENOMEM;
- return 0;
- }
} while ((gethostname(buf, buf_len) == 0 && !memchr (buf, '\0', buf_len))
|| errno == ENAMETOOLONG);
diff --git a/libshouldbeinlibc/maptime-funcs.c b/libshouldbeinlibc/maptime-funcs.c
new file mode 100644
index 00000000..080e3ae6
--- /dev/null
+++ b/libshouldbeinlibc/maptime-funcs.c
@@ -0,0 +1,5 @@
+#define MAPTIME_DEFINE_EI
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "maptime.h"
diff --git a/libshouldbeinlibc/maptime.c b/libshouldbeinlibc/maptime.c
index 95ae64cb..bc750458 100644
--- a/libshouldbeinlibc/maptime.c
+++ b/libshouldbeinlibc/maptime.c
@@ -1,6 +1,6 @@
/* Support for mach's mapped time
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -18,6 +18,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <fcntl.h>
#include <hurd.h>
#include <mach.h>
#include <device/device.h>
@@ -34,11 +35,11 @@ maptime_map (int use_mach_dev, char *dev_name,
volatile struct mapped_time_value **mtime)
{
error_t err;
- device_t device;
- mach_port_t mobj;
+ mach_port_t memobj;
if (use_mach_dev)
{
+ device_t device;
mach_port_t device_master;
err = get_privileged_ports (0, &device_master);
@@ -47,72 +48,32 @@ maptime_map (int use_mach_dev, char *dev_name,
err = device_open (device_master, 0, dev_name ?: "time", &device);
mach_port_deallocate (mach_task_self (), device_master);
}
+
+ err = device_map (device, VM_PROT_READ, 0, sizeof *mtime, &memobj, 0);
}
else
{
- mach_msg_type_number_t data_len = 100;
- mach_msg_type_number_t num_ints = 10, num_ports = 10, num_offsets = 10;
- int _ints[num_ints], *ints = _ints;
- mach_port_t _ports[num_ports], *ports = _ports;
- off_t _offsets[num_offsets], *offsets = _offsets;
- char _data[data_len], *data = _data;
- file_t node = file_name_lookup (dev_name ?: "/dev/time", 0, 0);
+ mach_port_t wr_memobj;
+ file_t node = file_name_lookup (dev_name ?: "/dev/time", O_RDONLY, 0);
if (node == MACH_PORT_NULL)
return errno;
- err = file_get_storage_info (node, &ports, &num_ports, &ints, &num_ints,
- &offsets, &num_offsets, &data, &data_len);
-
- if (! err)
- {
- int i;
-
- if (num_ints >= 6 && ints[0] == STORAGE_DEVICE)
- /* This a device. */
- if (num_ports != 1)
- err = EGRATUITOUS;
- else if (! MACH_PORT_VALID (ports[0]))
- err = EPERM; /* Didn't pass back the device port. XXX */
- else
- {
- device = ports[0];
- ports[0] = MACH_PORT_NULL; /* Don't deallocate here. */
- }
- else
- err = ENODEV; /* Not admitting to being a device. XXX */
-
- /* Deallocate any ports we got back. */
- for (i = 0; i < num_ports; i++)
- if (MACH_PORT_VALID (ports[i]))
- mach_port_deallocate (mach_task_self (), ports[i]);
-
- /* Deallocate any out of line vectors return by gsi. */
-#define DISCARD_MEM(v, vl, b) \
- if (vl && v != b) \
- vm_deallocate (mach_task_self (), (vm_address_t)v, vl * sizeof *v);
- DISCARD_MEM (ints, num_ints, _ints);
- DISCARD_MEM (offsets, num_offsets, _offsets);
- DISCARD_MEM (ports, num_ports, _ports);
- DISCARD_MEM (data, data_len, _data);
- }
+ err = io_map (node, &memobj, &wr_memobj);
+ if (!err && wr_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), wr_memobj);
mach_port_deallocate (mach_task_self (), node);
}
- if (err)
- return err;
-
- err = device_map (device, VM_PROT_READ, 0, sizeof *mtime, &mobj, 0);
if (! err)
{
+ *mtime = 0;
err =
vm_map (mach_task_self (), (vm_address_t *)mtime, sizeof *mtime, 0, 1,
- mobj, 0, 0, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
- mach_port_deallocate (mach_task_self (), mobj);
+ memobj, 0, 0, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+ mach_port_deallocate (mach_task_self (), memobj);
}
- mach_port_deallocate (mach_task_self (), device);
-
return err;
}
diff --git a/libshouldbeinlibc/maptime.h b/libshouldbeinlibc/maptime.h
index 244cbcf1..947ad640 100644
--- a/libshouldbeinlibc/maptime.h
+++ b/libshouldbeinlibc/maptime.h
@@ -1,8 +1,8 @@
/* Support for mach's mapped time
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2000, 2007 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,17 +22,30 @@
#define __MAPTIME_H__
#include <mach/time_value.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <features.h>
+
+#ifdef MAPTIME_DEFINE_EI
+#define MAPTIME_EI
+#else
+#define MAPTIME_EI __extern_inline
+#endif
/* Return the mach mapped time page in MTIME. If USE_MACH_DEV is false, then
- the hurd uptime device DEV_NAME, or "/dev/uptime" if DEV_NAME is 0, is
+ the hurd time device DEV_NAME, or "/dev/time" if DEV_NAME is 0, is
used. If USE_MACH_DEV is true, the mach device DEV_NAME, or "time" if
- DEV_NAME is 0, is used; this is a privileged operation. The mapped uptime
- may be converted to a struct timeval at any time using read_uptime. */
+ DEV_NAME is 0, is used; this is a privileged operation. The mapped time
+ may be converted to a struct timeval at any time using maptime_read. */
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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(MAPTIME_DEFINE_EI)
+
/* Read the current time from MTIME into TV. This should be very fast. */
-static inline void
+MAPTIME_EI void
maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv)
{
do
@@ -43,4 +56,6 @@ maptime_read (volatile struct mapped_time_value *mtime, struct timeval *tv)
while (tv->tv_sec != mtime->check_seconds);
}
+#endif /* Use extern inlines. */
+
#endif /* __MAPTIME_H__ */
diff --git a/libshouldbeinlibc/options.c b/libshouldbeinlibc/options.c
deleted file mode 100644
index 5f719616..00000000
--- a/libshouldbeinlibc/options.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/* Hierarchial options parsing, layered over getopt
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h> /* for CHAR_BIT */
-#include <getopt.h>
-#include <cthreads.h>
-
-#include "options.h"
-
-#define EOF (-1)
-
-/* The number of bits we steal in a long-option value for our own use. */
-#define GROUP_BITS CHAR_BIT
-
-/* The number of bits available for the user value. */
-#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS)
-#define USER_MASK ((1 << USER_BITS) - 1)
-
-/* ---------------------------------------------------------------- */
-
-/* Returns the offset into LONG_OPTIONS of a long option with called NAME, or
- -1 if none is found. Passing NULL as NAME will return the number of
- options. */
-static int
-find_long_option (struct option *long_options, const char *name)
-{
- struct option *l = long_options;
- while (l->name != NULL)
- if (name != NULL && strcmp (l->name, name) == 0)
- return l - long_options;
- else
- l++;
- if (name == NULL)
- return l - long_options;
- else
- return -1;
-}
-
-/* ---------------------------------------------------------------- */
-
-/* Used to regulate access to the getopt routines, which are non-reentrant. */
-static struct mutex getopt_lock = MUTEX_INITIALIZER;
-
-/* Parse the options strings in ARGC & ARGV according to the options in
- OPTIONS. FLAGS is one of the OPTIONS_ flags above. If OPTIND is
- non-NULL, the index in ARGV of the first unparsed option is returned in
- it. If an unknown option is present, EINVAL is returned; if some parser
- routine returned a non-zero value, it is returned; otherwise 0 is
- returned. */
-error_t
-options_parse (struct options *options,
- int argc, char **argv,
- unsigned flags, int *arg_index)
-{
- int opt;
- struct options *o;
- /* SHORT_OPTS is the getopt short options string for the union of all the
- groups of options. */
- char *short_opts;
- /* GROUP_SHORT_STARTS is an array pointing to the part of SHORT_OPTS
- corresponding to each different group of options. We use it to
- determine from which groupa particular short options is from. */
- char **group_short_starts;
- /* LONG_OPTS is the array of getop long option structures for the union of
- all the groups of options. */
- struct option *long_opts;
- error_t err = 0;
-
- /* Find the merged set of short options. */
- {
- char *short_end;
- int short_len = (flags & OPTIONS_PARSE_ARGS) ? 1 : 0;
- int num_groups = 0, group;
-
- /* Find the (maximum) amount of space necessary to store all combined
- short options, plus the number of options groups in the chain. */
- for (o = options; o != NULL; o = o->parent)
- {
- num_groups++;
- short_len += strlen (o->short_options);
- }
-
- short_opts = short_end = alloca (short_len + 1);
- if (flags & OPTIONS_PARSE_ARGS)
- *short_end++ = '-'; /* Tell getopt we want to do this. */
- *short_end = '\0';
-
- group_short_starts = alloca (num_groups * sizeof (char *));
-
- for (o = options, group = 0; o != NULL; o = o->parent, group++)
- {
- char *s;
-
- group_short_starts[group] = short_end;
-
- for (s = o->short_options; *s != '\0'; s++)
- /* We add *S to our set of short options only if it hasn't already
- been added by some previous group. */
- if (*s != ':' && !index (short_opts, *s))
- {
- *short_end++ = *s;
- /* Copy all the colon modifiers following the option. */
- while (s[1] == ':')
- *short_end++ = *++s;
- *short_end = '\0';
- }
- }
- }
-
- /* Find the merged set of long options, with keys appropiately prefixed. */
- {
- struct option *long_end;
- int group;
- int long_len = 0;
-
- for (o = options; o != NULL; o = o->parent)
- long_len += find_long_option (o->long_options, NULL);
-
- long_opts = long_end = alloca ((long_len + 1) * sizeof (struct option));
- long_end->name = NULL;
-
- /* Note that GROUP starts at 1 because 0 is for short options. */
- for (o = options, group = 1; o != NULL; o = o->parent, group++)
- {
- struct option *l;
- for (l = o->long_options; l->name != NULL; l++)
- /* Only add the long option L if it hasn't been already. */
- if (find_long_option (long_opts, l->name) < 0)
- {
- *long_end = *l;
- if (long_end->flag == NULL)
- /* In the case where a long option returns a key from getopt,
- we add a disambiguating code to all the user's values
- (which is removed before we actually call the function to
- parse the value); this means that the user loses use of
- the high 8 bits in all his values (the sign of the lower
- bits is preserved however)... */
- long_end->val = (l->val & USER_MASK) + (group << USER_BITS);
- /* Keep the LONG_OPTS list terminated. */
- (++long_end)->name = NULL;
- }
- }
- }
-
- /* Getopt is (currently) non-reentrant. */
- mutex_lock (&getopt_lock);
-
- /* Tell getopt to initialize. */
- optind = 0;
-
- if (flags & OPTIONS_PRINT_ERRS)
- opterr = 1; /* Print error messages. */
- else
- {
- opterr = 0;
- if (!(flags & OPTIONS_SKIP_ARG0))
- /* getopt always skips ARGV[0], so we have to fake it out. As long
- as opterr is 0, then it shouldn't actually try to access it. */
- argv--, argc++;
- }
-
- /* Now use getopt on our coalesced options lists. */
- while ((opt = getopt_long (argc, argv, short_opts, long_opts, 0)) != EOF)
- {
- int group = opt >> USER_BITS;
-
- err = EINVAL; /* until otherwise asserted */
-
- if (opt == 1)
- /* A non-option argument; try each parser in turn. */
- for (o = options; o != NULL && err == EINVAL; o = o->parent)
- err = (*o->parser)(0, optarg);
- else if (group == 0)
- /* A short option. */
- {
- /* By comparing OPT's position in SHORT_OPTS to the various
- starting positions in GROUP_SHORT_STARTS, we can determine which
- group OPT came from. */
- char *short_index = index (short_opts, opt);
- if (short_index)
- for (o = options, group = 0; o != NULL; o = o->parent, group++)
- if (o->parent == NULL
- || group_short_starts[group + 1] > short_index)
- {
- err = (*o->parser)(opt, optarg);
- break;
- }
- }
- else
- /* A long option. */
- for (o = options; o != NULL; o = o->parent)
- if (--group == 0)
- {
- /* We use shifts instead of masking for extracting the user value
- in order to preserve the sign. */
- err = (*o->parser)(((opt << GROUP_BITS) >> GROUP_BITS), optarg);
- break;
- }
-
- if (err)
- break;
- }
-
- if (arg_index != NULL)
- *arg_index = optind;
-
- mutex_unlock (&getopt_lock);
-
- return err;
-}
diff --git a/libshouldbeinlibc/options.h b/libshouldbeinlibc/options.h
deleted file mode 100644
index 46651add..00000000
--- a/libshouldbeinlibc/options.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* Hierarchial options parsing, layered over getopt
-
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#ifndef __OPTIONS_H__
-#define __OPTIONS_H__
-
-#include <errno.h>
-#include <getopt.h>
-
-/* An options structure contains a set of getopt options declarations, a
- function to deal with getting one, and an optional pointer to another
- options structure. When actually parsing options, getopt is called with
- the union of all the options structures chained together through their
- PARENT pointers, with conflicts being resolved in favor of the first
- occurance in the chain. */
-struct options
-{
- /* The getopt-style short options string for this group of options. */
- char *short_options;
- /* An array of getopt-style long-options structures. */
- struct option *long_options;
-
- /* What to do with an option from this structure. KEY is either the short
- option letter, or the final member of the long-option entry, as returned
- by getopt, and ARG is the value of OPTARG. If a non-zero value is
- returned, then parsing is stopped immediately, and that value is
- returned from options_parse(). */
- error_t (*parser)(int key, char *arg);
-
- /* The next member in this options chain. */
- struct options *parent;
-};
-
-/* Flags for options_parse: */
-
-/* Ignore the first element of ARGV. Useful for program command lines. */
-#define OPTIONS_SKIP_ARG0 0x1
-
-/* Print error messages for unknown options to stderr; if this flag is set,
- OPTIONS_SKIP_ARG0 is ignored, as ARGV[0] is used as the program name in
- the error messages. */
-#define OPTIONS_PRINT_ERRS 0x2
-
-/* Parse non-option args as well, similarly to getopt, by calling the parse
- function with a key of 0, and the actual arg as the value. Since it's
- impossible to know which parse function wants to handle it, each one is
- called in turn, until one returns 0 or an error other than EINVAL. */
-#define OPTIONS_PARSE_ARGS 0x4
-
-
-/* Parse the options strings in ARGC & ARGV according to the options in
- OPTIONS. FLAGS is one of the OPTIONS_ flags above. If ARG_INDEX is
- non-NULL, the index in ARGV of the first unparsed option is returned in
- it. If an unknown option is present, EINVAL is returned; if some parser
- routine returned a non-zero value, it is returned; otherwise 0 is
- returned. */
-error_t options_parse (struct options *options, int argc, char **argv,
- unsigned flags, int *arg_index);
-
-#endif /* __OPTIONS_H__ */
diff --git a/libshouldbeinlibc/portinfo.c b/libshouldbeinlibc/portinfo.c
index cb4e9605..e6305c6e 100644
--- a/libshouldbeinlibc/portinfo.c
+++ b/libshouldbeinlibc/portinfo.c
@@ -1,8 +1,7 @@
/* Print information about a task's ports
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1996,98,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,6 +17,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <sys/types.h>
+#include <sys/mman.h>
+
#include "portinfo.h"
/* Prints info about NAME in TASK to STREAM, in a way described by the flags
@@ -41,7 +43,7 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
mach_port_urefs_t refs;
error_t err = mach_port_get_refs (task, name, right, &refs);
if (! err)
- fprintf (stream, " (refs: %u)", refs);
+ fprintf (stream, " (refs: %zu)", refs);
}
if (type == 0)
@@ -51,7 +53,7 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
return err;
}
- fprintf (stream, hex_names ? "%#6x: " : "%6d: ", name);
+ fprintf (stream, hex_names ? "%#6zx: " : "%6zd: ", name);
if (type & MACH_PORT_TYPE_RECEIVE)
{
@@ -66,15 +68,15 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
fprintf (stream, " (");
if (status.mps_pset != MACH_PORT_NULL)
fprintf (stream,
- hex_names ? "port-set: %#x, " : "port-set: %d, ",
+ hex_names ? "port-set: %#zx, " : "port-set: %zd, ",
status.mps_pset);
- fprintf (stream, "seqno: %u", status.mps_seqno);
+ fprintf (stream, "seqno: %zu", status.mps_seqno);
if (status.mps_mscount)
- fprintf (stream, ", ms-count: %u", status.mps_mscount);
+ fprintf (stream, ", ms-count: %zu", status.mps_mscount);
if (status.mps_qlimit != MACH_PORT_QLIMIT_DEFAULT)
- fprintf (stream, ", qlimit: %u", status.mps_qlimit);
+ fprintf (stream, ", qlimit: %zu", status.mps_qlimit);
if (status.mps_msgcount)
- fprintf (stream, ", msgs: %u", status.mps_msgcount);
+ fprintf (stream, ", msgs: %zu", status.mps_msgcount);
fprintf (stream, "%s%s%s)",
status.mps_srights ? ", send-rights" : "",
status.mps_pdrequest ? ", pd-req" : "",
@@ -112,17 +114,19 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
error_t err =
mach_port_get_set_status (task, name, &members, &members_len);
if (! err)
- if (members_len == 0)
- fprintf (stream, " (empty)");
- else
- {
- fprintf (stream, hex_names ? " (%#x" : " (%u", members[0]);
- for (i = 1; i < members_len; i++)
- fprintf (stream, hex_names ? ", %#x" : ", %u", members[i]);
- fprintf (stream, ")");
- vm_deallocate (mach_task_self (), (vm_address_t)members,
- members_len * sizeof *members);
- }
+ {
+ if (members_len == 0)
+ fprintf (stream, " (empty)");
+ else
+ {
+ fprintf (stream, hex_names ? " (%#zx" : " (%zu", members[0]);
+ for (i = 1; i < members_len; i++)
+ fprintf (stream, hex_names ? ", %#zx" : ", %zu",
+ members[i]);
+ fprintf (stream, ")");
+ munmap ((caddr_t) members, members_len * sizeof *members);
+ }
+ }
}
}
putc ('\n', stream);
@@ -147,10 +151,8 @@ print_task_ports_info (task_t task, mach_port_type_t only,
if (types[i] & only)
print_port_info (names[i], types[i], task, show, stream);
- vm_deallocate (mach_task_self (),
- (vm_address_t)names, names_len * sizeof *names);
- vm_deallocate (mach_task_self (),
- (vm_address_t)types, types_len * sizeof *types);
+ munmap ((caddr_t) names, names_len * sizeof *names);
+ munmap ((caddr_t) types, types_len * sizeof *types);
return 0;
}
diff --git a/libshouldbeinlibc/portinfo.h b/libshouldbeinlibc/portinfo.h
index bef2fa00..143c2898 100644
--- a/libshouldbeinlibc/portinfo.h
+++ b/libshouldbeinlibc/portinfo.h
@@ -1,6 +1,6 @@
/* Print information about a task's ports
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
diff --git a/libshouldbeinlibc/portxlate.c b/libshouldbeinlibc/portxlate.c
index 07b2fc03..291bcf3a 100644
--- a/libshouldbeinlibc/portxlate.c
+++ b/libshouldbeinlibc/portxlate.c
@@ -1,8 +1,7 @@
/* Translate mach port names between two tasks
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1996,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,12 +18,14 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <malloc.h>
+#include <sys/types.h>
+#include <sys/mman.h>
#include "portxlate.h"
/* Return a new port name translator translating names between FROM_TASK and
TO_TASK, in XLATOR, or an error. */
-error_t
+error_t
port_name_xlator_create (mach_port_t from_task, mach_port_t to_task,
struct port_name_xlator **xlator)
{
@@ -59,12 +60,10 @@ port_name_xlator_create (mach_port_t from_task, mach_port_t to_task,
}
else
{
- vm_deallocate (mach_task_self (),
- (vm_address_t)x->to_names,
- x->to_names_len * sizeof (mach_port_t));
- vm_deallocate (mach_task_self (),
- (vm_address_t)x->to_types,
- x->to_types_len * sizeof (mach_port_type_t));
+ munmap ((caddr_t) x->to_names,
+ x->to_names_len * sizeof (mach_port_t));
+ munmap ((caddr_t) x->to_types,
+ x->to_types_len * sizeof (mach_port_type_t));
err = ENOMEM;
}
}
@@ -88,12 +87,8 @@ port_name_xlator_free (struct port_name_xlator *x)
mach_port_deallocate (mach_task_self (), x->ports[i]);
free (x->ports);
- vm_deallocate (mach_task_self (),
- (vm_address_t)x->to_names,
- x->to_names_len * sizeof (mach_port_t));
- vm_deallocate (mach_task_self (),
- (vm_address_t)x->to_types,
- x->to_types_len * sizeof (mach_port_type_t));
+ munmap ((caddr_t) x->to_names, x->to_names_len * sizeof (mach_port_t));
+ munmap ((caddr_t) x->to_types, x->to_types_len * sizeof (mach_port_type_t));
mach_port_deallocate (mach_task_self (), x->to_task);
mach_port_deallocate (mach_task_self (), x->from_task);
@@ -112,8 +107,8 @@ port_name_xlator_xlate (struct port_name_xlator *x,
error_t err;
mach_port_t port;
mach_msg_type_number_t i;
- mach_port_type_t aquired_type;
- mach_port_type_t valid_to_types;
+ mach_msg_type_name_t aquired_type;
+ mach_msg_type_name_t valid_to_types;
if (from_type == 0)
{
@@ -130,7 +125,7 @@ port_name_xlator_xlate (struct port_name_xlator *x,
return EKERN_INVALID_RIGHT;
/* Translate the name FROM, in FROM_TASK's namespace into our namespace. */
- err =
+ err =
mach_port_extract_right (x->from_task, from,
((from_type & MACH_PORT_TYPE_RECEIVE)
? MACH_MSG_TYPE_MAKE_SEND
diff --git a/libshouldbeinlibc/timefmt.c b/libshouldbeinlibc/timefmt.c
index da4ccde0..aa8965b7 100644
--- a/libshouldbeinlibc/timefmt.c
+++ b/libshouldbeinlibc/timefmt.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
+#include <time.h>
#include "timefmt.h"
diff --git a/libshouldbeinlibc/ugids-argp.c b/libshouldbeinlibc/ugids-argp.c
new file mode 100644
index 00000000..dc076d27
--- /dev/null
+++ b/libshouldbeinlibc/ugids-argp.c
@@ -0,0 +1,175 @@
+/* Parse user and group ids
+
+ Copyright (C) 1997, 1999, 2008 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "ugids.h"
+
+#define OA OPTION_ARG_OPTIONAL
+
+static const struct argp_option options[] =
+{
+ {"user", 'u', "USER", 0, "Add USER to the effective uids"},
+ {"avail-user",'U', "USER", 0, "Add USER to the available uids"},
+ {"group", 'g', "GROUP", 0, "Add GROUP to the effective groups"},
+ {"avail-group",'G',"GROUP", 0, "Add GROUP to the available groups"},
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ char id_lookup_buf[1024];
+ struct ugids_argp_params *params = state->input;
+ struct ugids *ugids = params->ugids;
+
+ switch (key)
+ {
+ uid_t uid;
+
+ case 'u':
+ case 'U':
+ case ARGP_KEY_ARG:
+ case ARGP_KEY_END:
+ if (key == ARGP_KEY_ARG && !params->parse_user_args)
+ /* Let someone else parse this argument. */
+ return ARGP_ERR_UNKNOWN;
+
+ if (key == ARGP_KEY_END)
+ {
+ if (ugids_is_empty (ugids))
+ {
+ if (params->default_user >= 0)
+ uid = params->default_user;
+ else if (params->require_ids)
+ {
+ argp_error (state, "No ids specified");
+ return EINVAL;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else if (isdigit (*arg))
+ uid = atoi (arg);
+ else if (strcmp (arg, "-") == 0)
+ break;
+ else
+ {
+ struct passwd _pw, *pw;
+ int err;
+ err = getpwnam_r (arg, &_pw, id_lookup_buf,
+ sizeof id_lookup_buf, &pw);
+ if (err == 0)
+ {
+ if (pw == NULL)
+ {
+ argp_failure (state, 10, 0, "%s: Unknown user", arg);
+ return EINVAL;
+ }
+
+ uid = pw->pw_uid;
+ }
+ else
+ {
+ argp_failure (state, 12, err,
+ "Could not get uid for user: %s", arg);
+ return err;
+ }
+ }
+
+ if (key == ARGP_KEY_ARG || key == ARGP_KEY_END)
+ {
+ /* A user arg, which means add the user, and any appropriate
+ groups. */
+ if (!params->user_args_are_effective
+ && !params->user_args_are_available)
+ return ugids_set_posix_user (ugids, uid);
+ else
+ {
+ error_t err = 0;
+ if (params->user_args_are_effective)
+ err = ugids_add_user (ugids, uid, 0);
+ if (!err && params->user_args_are_available)
+ err = ugids_add_user (ugids, uid, 1);
+ return err;
+ }
+ }
+ else
+ /* Add an individual specific effective/auxiliary uid. */
+ return ugids_add_uid (ugids, uid, key == 'U');
+
+ case 'g':
+ case 'G':
+ if (isdigit (*arg))
+ return ugids_add_gid (ugids, atoi (arg), key == 'G');
+ else
+ {
+ struct group _gr, *gr;
+ int err = getgrnam_r (arg, &_gr, id_lookup_buf,
+ sizeof id_lookup_buf, &gr);
+ if (err == 0)
+ {
+ if (gr == NULL)
+ {
+ argp_failure (state, 11, 0, "%s: Unknown group", arg);
+ return EINVAL;
+ }
+
+ return ugids_add_gid (ugids, gr->gr_gid, key == 'G');
+ }
+ else
+ {
+ argp_failure (state, 13, err,
+ "Could not get gid for group: %s", arg);
+ return err;
+ }
+ }
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Filtering of help output strings for UGIDS_ARGP. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ struct ugids_argp_params *params = input;
+
+ /* Describe the optional behavior of parsing normal args as ugids. */
+ if (key == ARGP_KEY_HELP_ARGS_DOC && params->parse_user_args)
+ return strdup ("[USER...]");
+
+ return (char *)text;
+}
+
+/* A parser for selecting a set of ugids. */
+struct argp ugids_argp = { options, parse_opt, 0, 0, 0, help_filter };
diff --git a/libshouldbeinlibc/ugids-auth.c b/libshouldbeinlibc/ugids-auth.c
new file mode 100644
index 00000000..d7ec9daa
--- /dev/null
+++ b/libshouldbeinlibc/ugids-auth.c
@@ -0,0 +1,53 @@
+/* Translate user and group ids to/from auth ports
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <hurd.h>
+
+#include "ugids.h"
+
+/* Make an auth port from UGIDS and return it in AUTH, using authority in
+ both the auth port FROM and the current auth port. */
+error_t
+ugids_make_auth (const struct ugids *ugids,
+ const auth_t *from, size_t num_from,
+ auth_t *auth)
+{
+ auth_t cur_auth = getauth ();
+ error_t err =
+ auth_makeauth (cur_auth, (auth_t *)from, MACH_MSG_TYPE_COPY_SEND, num_from,
+ ugids->eff_uids.ids, ugids->eff_uids.num,
+ ugids->avail_uids.ids, ugids->avail_uids.num,
+ ugids->eff_gids.ids, ugids->eff_gids.num,
+ ugids->avail_gids.ids, ugids->avail_gids.num,
+ auth);
+ mach_port_deallocate (mach_task_self (), cur_auth);
+ return err;
+}
+
+/* Merge the ids from the auth port AUTH into UGIDS. */
+error_t
+ugids_merge_auth (struct ugids *ugids, auth_t auth)
+{
+ return
+ idvec_merge_auth (&ugids->eff_uids, &ugids->avail_uids,
+ &ugids->eff_gids, &ugids->avail_gids,
+ auth);
+}
diff --git a/libdiskfs/ports-idle.c b/libshouldbeinlibc/ugids-imply.c
index 9da021d5..9c2a8a2c 100644
--- a/libdiskfs/ports-idle.c
+++ b/libshouldbeinlibc/ugids-imply.c
@@ -1,5 +1,8 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/* Calculate implied group ids from user ids
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,22 +18,18 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "priv.h"
+#include <stdlib.h>
+
+#include "ugids.h"
-/* Called by the ports library when we have been idle for
- ten minutes. */
-void
-ports_notice_idle (int nhard, int nsoft)
+/* Mark as implied all gids in UGIDS that can be implied from its uids. */
+error_t
+ugids_imply_all (struct ugids *ugids)
{
- spin_lock (&_diskfs_control_lock);
- if (nhard > _diskfs_ncontrol_ports)
- {
- spin_unlock (&_diskfs_control_lock);
- return;
- }
- spin_unlock (&_diskfs_control_lock);
-
- /* XXX
- Here should actually drop control ports and exit. */
- return;
+ error_t err;
+ err = idvec_merge_implied_gids (&ugids->imp_eff_gids, &ugids->eff_uids);
+ if (! err)
+ err =
+ idvec_merge_implied_gids (&ugids->imp_avail_gids, &ugids->avail_uids);
+ return err;
}
diff --git a/libshouldbeinlibc/ugids-merge.c b/libshouldbeinlibc/ugids-merge.c
new file mode 100644
index 00000000..924e1ed9
--- /dev/null
+++ b/libshouldbeinlibc/ugids-merge.c
@@ -0,0 +1,109 @@
+/* Merging of ugids
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+
+#include "ugids.h"
+
+static error_t
+_merge_gids (struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *new, const struct idvec *new_imp)
+{
+ error_t err;
+ /* Gids that exist in both GIDS and NEW can only be implied in the result
+ if they are implied in both; here GIDS_STRONG and NEW_STRONG contain
+ those gids which shouldn't be implied in the result because they are not
+ in either of the sources. */
+ struct idvec gids_strong = IDVEC_INIT;
+ struct idvec new_strong = IDVEC_INIT;
+
+ err = idvec_set (&gids_strong, gids);
+ if (! err)
+ err = idvec_set (&new_strong, new);
+ if (! err)
+ {
+ idvec_subtract (&gids_strong, gids_imp);
+ idvec_subtract (&new_strong, new_imp);
+
+ err = idvec_merge (gids, new);
+ if (! err)
+ {
+ err = idvec_merge (gids_imp, new_imp);
+ if (! err)
+ {
+ idvec_subtract (gids_imp, &gids_strong);
+ idvec_subtract (gids_imp, &new_strong);
+ }
+ }
+ }
+
+ idvec_fini (&gids_strong);
+ idvec_fini (&new_strong);
+
+ return err;
+}
+
+/* Add all ids in NEW to UGIDS. */
+error_t
+ugids_merge (struct ugids *ugids, const struct ugids *new)
+{
+ error_t err;
+ err = idvec_merge (&ugids->eff_uids, &new->eff_uids);
+ if (! err)
+ err = idvec_merge (&ugids->avail_uids, &new->avail_uids);
+ if (! err)
+ err = _merge_gids (&ugids->eff_gids, &ugids->imp_eff_gids,
+ &new->eff_gids, &new->imp_eff_gids);
+ if (! err)
+ err = _merge_gids (&ugids->avail_gids, &ugids->imp_avail_gids,
+ &new->avail_gids, &new->imp_avail_gids);
+ return err;
+}
+
+/* Set the ids in UGIDS to those in NEW. */
+error_t
+ugids_set (struct ugids *ugids, const struct ugids *new)
+{
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->avail_uids);
+ idvec_clear (&ugids->avail_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+ idvec_clear (&ugids->imp_avail_gids);
+ return ugids_merge (ugids, new);
+}
+
+/* Save any effective ids in UGIDS by merging them into the available ids,
+ and removing them from the effective ones. */
+error_t
+ugids_save (struct ugids *ugids)
+{
+ error_t err = idvec_merge (&ugids->avail_uids, &ugids->eff_uids);
+ if (! err)
+ err = _merge_gids (&ugids->avail_gids, &ugids->imp_avail_gids,
+ &ugids->eff_gids, &ugids->imp_eff_gids);
+ if (! err)
+ {
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+ }
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-posix.c b/libshouldbeinlibc/ugids-posix.c
new file mode 100644
index 00000000..35d73e32
--- /dev/null
+++ b/libshouldbeinlibc/ugids-posix.c
@@ -0,0 +1,95 @@
+/* Set posix-compatible ugids
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+
+#include "ugids.h"
+
+/* Install UID into UGIDS as the main user, making sure that the posix
+ `real' and `saved' uid slots are filled in, and similarly add all
+ groups to which UID belongs. */
+error_t
+ugids_set_posix_user (struct ugids *ugids, uid_t uid)
+{
+ error_t err;
+ struct idvec imp_gids = IDVEC_INIT;
+ uid_t uids_ids[] = { uid };
+ struct idvec uids = { uids_ids, 1 };
+
+ error_t update_real (struct idvec *avail_ids, uid_t id)
+ {
+ if (avail_ids->num == 0
+ || !idvec_tail_contains (avail_ids, 1, avail_ids->ids[0]))
+ return idvec_insert (avail_ids, 0, id);
+ else
+ avail_ids->ids[0] = id;
+ return 0;
+ }
+
+ idvec_merge_implied_gids (&imp_gids, &uids);
+
+ /* Try to add UID. */
+ err = idvec_insert_only (&ugids->eff_uids, 0, uid); /* Effective */
+ if (! err)
+ err = update_real (&ugids->avail_uids, uid); /* Real */
+ if (! err)
+ err = idvec_insert_only (&ugids->avail_uids, 1, uid); /* Saved */
+
+ if (!err && imp_gids.num > 0)
+ /* Now do the gids. */
+ {
+ /* The main gid associated with UID (usually from /etc/passwd). */
+ gid_t gid = imp_gids.ids[0];
+ /* True if GID was already an available gid. */
+ int gid_was_avail = idvec_contains (&ugids->avail_gids, gid);
+
+ /* Update the implied sets for the gids: they're implied unless
+ they were present as non-implied gids before. Here we
+ remove existing effective gids from the IMP_GIDS before we
+ added it to the implied sets -- if some of those gids were
+ actually implied, they'll already be present in the implied
+ set. */
+ idvec_subtract (&imp_gids, &ugids->eff_gids);
+
+ /* Now add GID, as effective, real, and saved gids. */
+ if (! err) /* Effective */
+ err = idvec_insert_only (&ugids->eff_gids, 0, gid);
+ if (! err) /* Real */
+ err = update_real (&ugids->avail_gids, gid);
+ if (! err) /* Saved */
+ err = idvec_insert_only (&ugids->avail_gids, 1, gid);
+
+ /* Mark GID as implied in the available gids unless it was already
+ present (in which case its implied status is already settled). */
+ if (!err && !gid_was_avail)
+ err = idvec_add (&ugids->imp_avail_gids, gid);
+
+ /* Add the other implied gids to the end of the effective gids. */
+ if (! err)
+ err = idvec_merge (&ugids->eff_gids, &imp_gids);
+ /* And make them implied. */
+ if (! err)
+ err = idvec_merge (&ugids->imp_eff_gids, &imp_gids);
+ }
+
+ idvec_fini (&imp_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-rep.c b/libshouldbeinlibc/ugids-rep.c
new file mode 100644
index 00000000..3e6e59d5
--- /dev/null
+++ b/libshouldbeinlibc/ugids-rep.c
@@ -0,0 +1,118 @@
+/* String representation of ugids
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ugids.h"
+
+/* Return a string representation of the ids in UGIDS. SHOW_VALUES and
+ SHOW_NAMES reflect how each id is printed (if SHOW_NAMES is true values
+ are used where names aren't available); if both are true, the
+ `VALUE(NAME)' format is used. ID_SEP, TYPE_SEP, and HDR_SEP contain the
+ strings that separate, respectively, multiple ids of a particular type
+ (default ","), the various types of ids (default ", "), and the name of
+ each type from its ids (default ": "). The empty string is returned for
+ an empty list, and 0 for an allocation error. */
+char *
+ugids_rep (const struct ugids *ugids, int show_values, int show_names,
+ const char *id_sep, const char *type_sep, const char *hdr_sep)
+{
+ size_t type_sep_len, hdr_sep_len;
+ int first = 1;
+ char *rep = 0; /* Result */
+ size_t len = 0; /* Total length of result. */
+ char *euid_rep = 0, *egid_rep = 0, *auid_rep = 0, *agid_rep = 0;
+
+ /* Calculate the rep for NAME, with ids IDS, returning the rep for the ids
+ in REP, and updates LEN to include everything needed by this type (the
+ length of *REP *plus* the length of NAME and any separators). True is
+ returned unless an allocation error occurs. */
+ int type_rep (const char *name, const struct idvec *ids, int is_group,
+ char **rep)
+ {
+ if (ids->num > 0)
+ {
+ if (first)
+ first = 0;
+ else
+ len += type_sep_len;
+ len += strlen (name);
+ len += hdr_sep_len;
+ *rep =
+ (is_group ? idvec_gids_rep : idvec_uids_rep)
+ (ids, show_values, show_names, id_sep);
+ if (*rep)
+ len += strlen (*rep);
+ else
+ return 0;
+ }
+ return 1;
+ }
+ void add_type_rep (char **to, const char *name, const char *rep)
+ {
+ if (rep)
+ {
+ if (first)
+ first = 0;
+ else
+ *to = stpcpy (*to, type_sep);
+ *to = stpcpy (*to, name);
+ *to = stpcpy (*to, hdr_sep);
+ *to = stpcpy (*to, rep);
+ }
+ }
+
+ if (! type_sep)
+ type_sep = ", ";
+ if (! hdr_sep)
+ hdr_sep = ": ";
+
+ type_sep_len = strlen (type_sep);
+ hdr_sep_len = strlen (hdr_sep);
+
+ if (type_rep ("euids", &ugids->eff_uids, 0, &euid_rep)
+ && type_rep ("egids", &ugids->eff_gids, 1, &egid_rep)
+ && type_rep ("auids", &ugids->avail_uids, 0, &auid_rep)
+ && type_rep ("agids", &ugids->avail_gids, 1, &agid_rep))
+ {
+ char *p = malloc (len + 1);
+ if (p)
+ {
+ rep = p;
+ first = 1;
+ add_type_rep (&p, "euids", euid_rep);
+ add_type_rep (&p, "egids", egid_rep);
+ add_type_rep (&p, "auids", auid_rep);
+ add_type_rep (&p, "agids", agid_rep);
+ }
+ }
+
+ if (euid_rep)
+ free (euid_rep);
+ if (egid_rep)
+ free (egid_rep);
+ if (auid_rep)
+ free (auid_rep);
+ if (agid_rep)
+ free (agid_rep);
+
+ return rep;
+}
diff --git a/libshouldbeinlibc/ugids-subtract.c b/libshouldbeinlibc/ugids-subtract.c
new file mode 100644
index 00000000..eecba20e
--- /dev/null
+++ b/libshouldbeinlibc/ugids-subtract.c
@@ -0,0 +1,130 @@
+/* Subtract one set of user and group ids from another
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ugids.h"
+
+/* Remove the gids in SUB from those in GIDS, except where they are implied
+ in SUB (as represented by SUB_IMP), but not in GIDS (as represented by
+ GIDS_IMP). */
+static
+error_t _sub_gids (struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *sub, const struct idvec *sub_imp)
+{
+ error_t err;
+ /* What we'll remove from GIDS. */
+ struct idvec delta = IDVEC_INIT;
+ /* Those implied ids in SUB that we *won't* remove, because they're not
+ also implied in GIDS. */
+ struct idvec delta_suppress = IDVEC_INIT;
+
+ err = idvec_set (&delta, sub);
+ if (! err)
+ err = idvec_set (&delta_suppress, sub_imp);
+ if (! err)
+ {
+ /* Don't suppress those implied ids that are implied in both. */
+ idvec_subtract (&delta_suppress, gids_imp);
+ idvec_subtract (&delta, &delta_suppress);
+
+ /* Actually remove the gids. */
+ idvec_subtract (gids, &delta);
+ }
+
+ idvec_fini (&delta);
+ idvec_fini (&delta_suppress);
+
+ return err;
+}
+
+/* Remove the in SUB from those in GIDS, except where they are implied
+ in SUB (as represented by SUB_IMP), but not in GIDS (as represented by
+ GIDS_IMP). */
+static
+error_t _sub (struct idvec *uids, struct idvec *gids, struct idvec *gids_imp,
+ const struct idvec *sub_uids,
+ const struct idvec *sub_gids, const struct idvec *sub_gids_imp)
+{
+ error_t err;
+ struct idvec new_uids = IDVEC_INIT; /* The set of uids after subtraction. */
+ struct idvec no_sub_gids = IDVEC_INIT; /* Gids we *don't* want to remove
+ from GIDS, despite what's in
+ SUB_GIDS. */
+ struct idvec new_sub_gids = IDVEC_INIT;
+ struct idvec new_sub_gids_imp = IDVEC_INIT;
+
+ err = idvec_set (&new_uids, uids);
+ if (! err)
+ err = idvec_set (&new_sub_gids, sub_gids);
+ if (! err)
+ err = idvec_set (&new_sub_gids_imp, sub_gids_imp);
+ if (! err)
+ {
+ idvec_subtract (&new_uids, sub_uids);
+
+ err = idvec_merge_implied_gids (&no_sub_gids, &new_uids);
+ if (! err)
+ {
+ /* NO_SUB_GIDS is the intersection of implied gids in GIDS,
+ implied gids in SUB_GIDS, and implied gids after the subtraction
+ of uids -- we don't want to remove those implied gids because we
+ can't be sure which uids implied them (as there will be
+ appropriately implicative uids left after the subtraction). */
+ idvec_keep (&no_sub_gids, gids_imp);
+ idvec_keep (&no_sub_gids, sub_gids_imp);
+
+ /* Remove those gids we don't want to subtract. */
+ idvec_subtract (&new_sub_gids, &no_sub_gids);
+ idvec_subtract (&new_sub_gids_imp, &no_sub_gids);
+
+ /* Do the group subtraction. */
+ err = _sub_gids (gids, gids_imp, &new_sub_gids, &new_sub_gids_imp);
+ if (! err)
+ /* Finally, if no problems, do the uid subtraction. */
+ err = idvec_set (uids, &new_uids);
+ }
+ }
+
+ idvec_fini (&new_uids);
+ idvec_fini (&no_sub_gids);
+ idvec_fini (&new_sub_gids);
+ idvec_fini (&new_sub_gids_imp);
+
+ return err;
+}
+
+/* Remove the ids in SUB from those in UGIDS. */
+error_t
+ugids_subtract (struct ugids *ugids, const struct ugids *sub)
+{
+ error_t err =
+ _sub (&ugids->eff_uids, &ugids->eff_gids, &ugids->imp_eff_gids,
+ &sub->eff_uids, &sub->eff_gids, &sub->imp_eff_gids);
+
+ if (! err)
+ /* If this second call to _sub fails, ugids will be in an inconsistent
+ state, but oh well. */
+ err = _sub (&ugids->avail_uids, &ugids->avail_gids, &ugids->imp_avail_gids,
+ &sub->avail_uids, &sub->avail_gids, &sub->imp_avail_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-verify-auth.c b/libshouldbeinlibc/ugids-verify-auth.c
new file mode 100644
index 00000000..91fa06e9
--- /dev/null
+++ b/libshouldbeinlibc/ugids-verify-auth.c
@@ -0,0 +1,190 @@
+/* Verify user/group passwords and authenticate accordingly
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <hurd/paths.h>
+#include <hurd/password.h>
+
+#include "ugids.h"
+
+/* Accumulated information from authentication various passwords. */
+struct svma_state
+{
+ /* The password server. */
+ file_t server;
+
+ /* An auth port for each password that was verify by the server. */
+ auth_t *auths;
+ size_t num_auths;
+};
+
+/* Append the auth ports in AUTHS, of length NUM_AUTHS, to the auth port
+ vector in SS, returning 0 if successful, or an error. */
+static error_t
+svma_state_add_auths (struct svma_state *ss,
+ const auth_t *auths, size_t num_auths)
+{
+ auth_t *new = realloc (ss->auths,
+ (ss->num_auths + num_auths) * sizeof (auth_t));
+ if (new)
+ {
+ ss->auths = new;
+ while (num_auths--)
+ ss->auths[ss->num_auths++] = *auths++;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+/* Get authentication from PASSWORD using the hurd password server. */
+static error_t
+server_verify_make_auth (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+{
+ auth_t auth;
+ struct svma_state *svma_state = hook;
+ error_t (*check) (io_t server, uid_t id, const char *passwd, auth_t *auth) =
+ is_group ? password_check_group : password_check_user;
+ error_t err = (*check) (svma_state->server, id, password, &auth);
+
+ if (! err)
+ /* PASSWORD checked out ok; the corresponding authentication is in AUTH. */
+ {
+ err = svma_state_add_auths (svma_state, &auth, 1);
+ if (err)
+ mach_port_deallocate (mach_task_self (), auth);
+ }
+
+ return err;
+}
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS (asking for passwords where
+ necessary), and return corresponding authentication in AUTH; the auth
+ ports in FROM, of length NUM_FROM, are used to supplement the auth port of
+ the current process if necessary. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. GETPASS_FN and GETPASS_HOOK are as
+ for the idvec_verify function in <idvec.h>. */
+error_t
+ugids_verify_make_auth (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ const auth_t *from, size_t num_from,
+ auth_t *auth)
+{
+ error_t err;
+ /* By default, get authentication from the password server. */
+ struct svma_state svma_state;
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook)
+ = server_verify_make_auth;
+ void *verify_hook = &svma_state;
+
+ /* Try to open the hurd password server. */
+ svma_state.server = file_name_lookup (_SERVERS_PASSWORD, 0, 0);
+
+ if (svma_state.server == MACH_PORT_NULL)
+ /* Can't open the password server, try to use our own authority in
+ the traditional unix manner. */
+ {
+ verify_fn = 0;
+ verify_hook = 0;
+ }
+ else
+ {
+ /* Must initialize list to empty so svma_state_add_auths works. */
+ svma_state.auths = NULL;
+ svma_state.num_auths = 0;
+ }
+
+ /* Check passwords. */
+ err = ugids_verify (ugids, have_uids, have_gids,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+
+ if (! err)
+ {
+ /* The user apparently has access to all the ids, try to grant the
+ corresponding authentication. */
+ if (verify_fn)
+ /* Merge the authentication we got from the password server into our
+ result. */
+ {
+ if (num_from > 0)
+ /* Use FROM as well as the passwords to get authentication. */
+ err = svma_state_add_auths (&svma_state, from, num_from);
+
+ if (! err)
+ {
+ auth_t cur_auth = getauth ();
+
+ err =
+ auth_makeauth (cur_auth,
+ svma_state.auths, MACH_MSG_TYPE_COPY_SEND,
+ svma_state.num_auths,
+ ugids->eff_uids.ids, ugids->eff_uids.num,
+ ugids->avail_uids.ids, ugids->avail_uids.num,
+ ugids->eff_gids.ids, ugids->eff_gids.num,
+ ugids->avail_gids.ids, ugids->avail_gids.num,
+ auth);
+ mach_port_deallocate (mach_task_self (), cur_auth);
+
+ /* Avoid deallocating FROM when we clean up SVMA_STATE. */
+ svma_state.num_auths -= num_from;
+ }
+ }
+ else
+ /* Try to authenticate the old fashioned way... */
+ err = ugids_make_auth (ugids, from, num_from, auth);
+ }
+
+ if (verify_fn)
+ /* Clean up any left over state. */
+ {
+ int i;
+
+ /* Get rid of auth ports. */
+ for (i = 0; i < svma_state.num_auths; i++)
+ mach_port_deallocate (mach_task_self (), svma_state.auths[i]);
+
+ /* Close password server. */
+ mach_port_deallocate (mach_task_self (), svma_state.server);
+
+ if (svma_state.num_auths > 0)
+ free (svma_state.auths);
+ }
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-verify.c b/libshouldbeinlibc/ugids-verify.c
new file mode 100644
index 00000000..f9d45c63
--- /dev/null
+++ b/libshouldbeinlibc/ugids-verify.c
@@ -0,0 +1,70 @@
+/* Verify user/group passwords
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <hurd.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <argp.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "ugids.h"
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS, asking for passwords where
+ necessary. 0 is returned if access should be allowed, otherwise
+ EINVAL if an incorrect password was entered, or an error relating to
+ resource failure. The GETPASS_FN, GETPASS_HOOK, VERIFY_FN, and
+ VERIFY_HOOK arguments are as for the idvec_verify function (in <idvec.h>). */
+error_t
+ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids, const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook)
+{
+ error_t err;
+ struct idvec check_uids = IDVEC_INIT; /* User-ids to verify. */
+ struct idvec check_gids = IDVEC_INIT; /* group-ids to verify. */
+
+ err = idvec_merge (&check_uids, &ugids->eff_uids);
+ if (! err)
+ err = idvec_merge (&check_uids, &ugids->avail_uids);
+ if (! err)
+ err = idvec_merge (&check_gids, &ugids->eff_gids);
+ if (! err)
+ err = idvec_merge (&check_gids, &ugids->avail_gids);
+
+ if (! err)
+ err = idvec_verify (&check_uids, &check_gids, have_uids, have_gids,
+ getpass_fn, getpass_hook, verify_fn, verify_hook);
+
+ idvec_fini (&check_uids);
+ idvec_fini (&check_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids-xinl.c b/libshouldbeinlibc/ugids-xinl.c
new file mode 100644
index 00000000..107de8b9
--- /dev/null
+++ b/libshouldbeinlibc/ugids-xinl.c
@@ -0,0 +1,23 @@
+/* Real definitions for extern inline functions in ugids.h
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>.
+
+ 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. */
+
+#define UGIDS_DEFINE_EI
+#include "ugids.h"
diff --git a/libshouldbeinlibc/ugids.c b/libshouldbeinlibc/ugids.c
new file mode 100644
index 00000000..2b9b6b71
--- /dev/null
+++ b/libshouldbeinlibc/ugids.c
@@ -0,0 +1,97 @@
+/* Frob user and group ids
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ugids.h"
+
+/* Return a new ugids structure, or 0 if an allocation error occurs. */
+struct ugids *
+make_ugids ()
+{
+ struct ugids *u = malloc (sizeof (struct ugids));
+ if (u)
+ bzero (u, sizeof *u);
+ return u;
+}
+
+/* Add a new uid to UGIDS. If AVAIL is true, it's added to the avail uids
+ instead of the effective ones. */
+error_t
+ugids_add_uid (struct ugids *ugids, uid_t uid, int avail)
+{
+ return idvec_add_new (avail ? &ugids->avail_uids : &ugids->eff_uids, uid);
+}
+
+/* Add a new gid to UGIDS. If AVAIL is true, it's added to the avail gids
+ instead of the effective ones. */
+error_t
+ugids_add_gid (struct ugids *ugids, gid_t gid, int avail)
+{
+ error_t err =
+ idvec_add_new (avail ? &ugids->avail_gids : &ugids->eff_gids, gid);
+ if (! err)
+ /* Since this gid is now explicit, remove it from the appropriate implied
+ set. */
+ idvec_remove (avail ? &ugids->imp_avail_gids : &ugids->imp_eff_gids,
+ 0, gid);
+ return err;
+}
+
+/* Add UID to UGIDS, plus any gids to which that user belongs. If AVAIL is
+ true, the are added to the avail gids instead of the effective ones. */
+error_t
+ugids_add_user (struct ugids *ugids, uid_t uid, int avail)
+{
+ error_t err;
+ struct idvec imp_gids = IDVEC_INIT;
+ uid_t uids_ids[] = { uid };
+ struct idvec uids = { uids_ids, 1 };
+ struct idvec *gids = avail ? &ugids->avail_gids : &ugids->eff_gids;
+
+ idvec_merge_implied_gids (&imp_gids, &uids);
+
+ /* Now remove any gids we already know about from IMP_GIDS. For gids
+ that weren't in the appropriate implied set before, this will
+ ensure that they remain out after we merge IMP_GIDS into it, and
+ ones that *were*, they will remain so. */
+ idvec_subtract (&imp_gids, gids);
+
+ /* Try to add UID. */
+ err = idvec_add_new (avail ? &ugids->avail_uids : &ugids->eff_uids, uid);
+
+ if (! err)
+ /* Now that we've added UID, we can add appropriate implied gids.
+ [If this fails, UGIDS will be an inconsistent state, but things
+ are probably fucked anyhow] */
+ err =
+ idvec_merge (avail ? &ugids->avail_gids : &ugids->eff_gids,
+ &imp_gids);
+ if (! err)
+ err = idvec_merge ((avail
+ ? &ugids->imp_avail_gids
+ : &ugids->imp_eff_gids),
+ &imp_gids);
+
+ idvec_fini (&imp_gids);
+
+ return err;
+}
diff --git a/libshouldbeinlibc/ugids.h b/libshouldbeinlibc/ugids.h
new file mode 100644
index 00000000..10e7a242
--- /dev/null
+++ b/libshouldbeinlibc/ugids.h
@@ -0,0 +1,229 @@
+/* Uid/gid parsing/frobbing
+
+ Copyright (C) 1997,2001 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __UGIDS_H__
+#define __UGIDS_H__
+
+#include <stdlib.h> /* For inline function stuff. */
+#include <idvec.h>
+#include <features.h>
+
+#ifdef UGIDS_DEFINE_EI
+#define UGIDS_EI
+#else
+#define UGIDS_EI __extern_inline
+#endif
+
+/* A structure holding a set of the common various types of ids. */
+struct ugids
+{
+ struct idvec eff_uids; /* Effective UIDs */
+ struct idvec eff_gids; /* Effective GIDs */
+ struct idvec avail_uids; /* Available UIDs */
+ struct idvec avail_gids; /* Available GIDs */
+
+ /* These should be a subset of EFF/AVAIL_GIDS, containing those gids which
+ are present only by implication from uids in EFF/AVAIL_UIDS. */
+ struct idvec imp_eff_gids;
+ struct idvec imp_avail_gids;
+};
+
+#define UGIDS_INIT { IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT, IDVEC_INIT }
+
+/* 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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(UGIDS_DEFINE_EI)
+
+/* Free all resources used by UGIDS except UGIDS itself. */
+UGIDS_EI void
+ugids_fini (struct ugids *ugids)
+{
+ idvec_fini (&ugids->eff_uids);
+ idvec_fini (&ugids->eff_gids);
+ idvec_fini (&ugids->avail_uids);
+ idvec_fini (&ugids->avail_gids);
+ idvec_fini (&ugids->imp_eff_gids);
+ idvec_fini (&ugids->imp_avail_gids);
+}
+
+/* Free all resources used by UGIDS. */
+UGIDS_EI void
+ugids_free (struct ugids *ugids)
+{
+ ugids_fini (ugids);
+ free (ugids);
+}
+
+/* Return true if UGIDS contains no ids. */
+UGIDS_EI int
+ugids_is_empty (const struct ugids *ugids)
+{
+ /* We needn't test the imp_*_gids vectors because they are subsets of the
+ corresponding *_gids vectors. */
+ return
+ idvec_is_empty (&ugids->eff_uids)
+ && idvec_is_empty (&ugids->eff_gids)
+ && idvec_is_empty (&ugids->avail_uids)
+ && idvec_is_empty (&ugids->avail_gids);
+}
+
+/* Free all resources used by UGIDS except UGIDS itself. */
+UGIDS_EI int
+ugids_equal (const struct ugids *ugids1, const struct ugids *ugids2)
+{
+ return
+ idvec_equal (&ugids1->eff_uids, &ugids2->eff_uids)
+ && idvec_equal (&ugids1->eff_gids, &ugids2->eff_gids)
+ && idvec_equal (&ugids1->avail_uids, &ugids2->avail_uids)
+ && idvec_equal (&ugids1->avail_gids, &ugids2->avail_gids)
+ && idvec_equal (&ugids1->imp_eff_gids, &ugids2->imp_eff_gids)
+ && 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);
+
+/* Set the ids in UGIDS to those in NEW. */
+error_t ugids_set (struct ugids *ugids, const struct ugids *new);
+
+/* Remove the ids in SUB from those in UGIDS. */
+error_t ugids_subtract (struct ugids *ugids, const struct ugids *sub);
+
+/* Mark as implied all gids in UGIDS that can be implied from its uids. */
+error_t ugids_imply_all (struct ugids *ugids);
+
+/* Save any effective ids in UGIDS by merging them into the available ids,
+ and removing them from the effective ones. */
+error_t ugids_save (struct ugids *ugids);
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS, asking for passwords where
+ necessary. 0 is returned if access should be allowed, otherwise
+ EINVAL if an incorrect password was entered, or an error relating to
+ resource failure. The GETPASS_FN, GETPASS_HOOK, VERIFY_FN, and
+ VERIFY_HOOK arguments are as for the idvec_verify function (in <idvec.h>). */
+error_t ugids_verify (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *getpass_hook,
+ error_t (*verify_fn) (const char *password,
+ uid_t id, int is_group,
+ void *pwd_or_grp, void *hook),
+ void *verify_hook);
+
+/* Make an auth port from UGIDS and return it in AUTH, using authority in
+ both the auth port FROM and the current auth port. */
+error_t ugids_make_auth (const struct ugids *ugids,
+ const auth_t *from, size_t num_from,
+ auth_t *auth);
+
+/* Verify that we have the right to the ids in UGIDS, given that we already
+ possess those in HAVE_UIDS and HAVE_GIDS (asking for passwords where
+ necessary), and return corresponding authentication in AUTH; the auth
+ ports in FROM, of length NUM_FROM, are used to supplement the auth port of
+ the current process if necessary. 0 is returned if access should be
+ allowed, otherwise EINVAL if an incorrect password was entered, or an
+ error relating to resource failure. GETPASS_FN and GETPASS_HOOK are as
+ for the idvec_verify function in <idvec.h>. */
+error_t ugids_verify_make_auth (const struct ugids *ugids,
+ const struct idvec *have_uids,
+ const struct idvec *have_gids,
+ char *(*getpass_fn) (const char *prompt,
+ uid_t id, int is_group,
+ void *pwd_or_grp,
+ void *hook),
+ void *getpass_hook,
+ const auth_t *from, size_t num_from,
+ auth_t *auth);
+
+/* Merge the ids from the auth port AUTH into UGIDS. */
+error_t ugids_merge_auth (struct ugids *ugids, auth_t auth);
+
+/* Return a string representation of the ids in UGIDS. SHOW_VALUES and
+ SHOW_NAMES reflect how each id is printed (if SHOW_NAMES is true values
+ are used where names aren't available); if both are true, the
+ `VALUE(NAME)' format is used. ID_SEP, TYPE_SEP, and HDR_SEP contain the
+ strings that separate, respectively, multiple ids of a particular type
+ (default ","), the various types of ids (default ", "), and the name of
+ each type from its ids (default ": "). The empty string is returned for
+ an empty list, and 0 for an allocation error. */
+char *ugids_rep (const struct ugids *ugids, int show_values, int show_names,
+ const char *id_sep, const char *type_sep,
+ const char *hdr_sep);
+
+/* Add a new uid to UGIDS. If AVAIL is true, it's added to the avail uids
+ instead of the effective ones. */
+error_t ugids_add_uid (struct ugids *ugids, uid_t uid, int avail);
+
+/* Add a new gid to UGIDS. If AVAIL is true, it's added to the avail gids
+ instead of the effective ones. */
+error_t ugids_add_gid (struct ugids *ugids, gid_t gid, int avail);
+
+/* Add UID to UGIDS, plus any gids to which that user belongs. If AVAIL is
+ true, the are added to the avail gids instead of the effective ones. */
+error_t ugids_add_user (struct ugids *ugids, uid_t uid, int avail);
+
+/* Install UID into UGIDS as the main user, making sure that the posix
+ `real' and `saved' uid slots are filled in, and similarly add all
+ groups to which UID belongs. */
+error_t ugids_set_posix_user (struct ugids *ugids, uid_t uid);
+
+/* Params to be passed as the input when parsing UGIDS_ARGP. */
+struct ugids_argp_params
+{
+ /* Parsed ids should be added here. */
+ struct ugids *ugids;
+
+ /* If true, parse multiple args as user otherwise, parse none. */
+ int parse_user_args;
+
+ /* If true, and PARSE_USER_ARGS is true, add user args to the available
+ ids, not the effective ones. If both are true, add them to both.
+ If both are false, use the special ugids_set_posix_user instead (which
+ sets both, in a particular way). */
+ int user_args_are_effective;
+ int user_args_are_available;
+
+ /* If >= 0, a user that should be added if none are specified on the
+ command line (following the same rules). */
+ int default_user;
+
+ /* If true, at least one id has to be specified. */
+ int require_ids;
+};
+
+/* A parser for selecting a set of ugids. */
+extern struct argp ugids_argp;
+
+#endif /* __UGIDS_H__ */
diff --git a/libshouldbeinlibc/wire.c b/libshouldbeinlibc/wire.c
index 7be04dee..bafc9599 100644
--- a/libshouldbeinlibc/wire.c
+++ b/libshouldbeinlibc/wire.c
@@ -1,5 +1,5 @@
/* Function to wire down text and data (including from shared libraries)
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,99,2000,01,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,14 +20,28 @@
#include <link.h>
+#include <dlfcn.h>
#include <mach.h>
#include <hurd.h>
+#include <error.h>
+
+#pragma weak _DYNAMIC
+#pragma weak dlopen
+#pragma weak dlclose
+#pragma weak dlerror
+#pragma weak dlsym
+#ifndef RTLD_NOLOAD
+#define RTLD_NOLOAD 0
+#endif
/* Find the list of shared objects */
static struct link_map *
loaded (void)
{
- Elf32_Dyn *d;
+ ElfW(Dyn) *d;
+
+ if (&_DYNAMIC == 0) /* statically linked */
+ return 0;
for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
if (d->d_tag == DT_DEBUG)
@@ -40,13 +54,27 @@ loaded (void)
}
/* Compute the extent of a particular shared object. */
-static Elf32_Addr
+static ElfW(Addr)
map_extent (struct link_map *map)
{
- /* Find the last load cmd; they are in ascending p_vaddr order. */
- Elf32_Word n = map->l_phnum;
- while (n-- > 0 && map->l_phdr[n].p_type != PT_LOAD);
- return map->l_phdr[n].p_vaddr + map->l_phdr[n].p_filesz;
+ /* In fact, LIB == MAP, but doing it this way makes it entirely kosher. */
+ void *lib = dlopen (map->l_name, RTLD_NOLOAD);
+ if (lib == 0)
+ {
+ error (2, 0, "cannot dlopen %s: %s", map->l_name, dlerror ());
+ /* NOTREACHED */
+ return 0;
+ }
+ else
+ {
+ /* Find the _end symbol's runtime address and subtract the load base. */
+ void *end = dlsym (lib, "_end");
+ if (end == 0)
+ error (2, 0, "cannot wire library %s with no _end symbol: %s",
+ map->l_name, dlerror ());
+ dlclose (lib);
+ return (ElfW(Addr)) end - map->l_addr;
+ }
}
/* Wire down all memory currently allocated at START for LEN bytes;
@@ -70,7 +98,7 @@ wire_segment_internal (vm_address_t start,
do
{
addr = start;
- err = vm_region (mach_task_self (), &addr, &size, &protection,
+ err = vm_region (mach_task_self (), &addr, &size, &protection,
&max_protection, &inheritance, &shared, &object_name,
&offset);
if (err)
@@ -80,25 +108,25 @@ wire_segment_internal (vm_address_t start,
extends beyond the LEN, prune it. */
if (addr + size > start + len)
size = len - (addr - start);
-
+
/* Set protection to allow all access possible */
vm_protect (mach_task_self (), addr, size, 0, max_protection);
-
+
/* Generate write faults */
- for (poke = (char *) addr;
- (vm_address_t) poke < addr + size;
+ for (poke = (char *) addr;
+ (vm_address_t) poke < addr + size;
poke += vm_page_size)
*poke = *poke;
/* Wire pages */
vm_wire (host_priv, mach_task_self (), addr, size, max_protection);
-
+
/* Set protection back to what it was */
vm_protect (mach_task_self (), addr, size, 0, protection);
mach_port_deallocate (mach_task_self (), object_name);
-
+
len -= (addr - start) + size;
start = addr + size;
}
@@ -112,7 +140,7 @@ wire_segment (vm_address_t start,
{
mach_port_t host, device;
error_t error;
-
+
error = get_privileged_ports (&host, &device);
if (!error)
{
@@ -132,17 +160,17 @@ wire_task_self ()
mach_port_t host, device;
error_t error;
extern char _edata, _etext, __data_start;
-
+
error = get_privileged_ports (&host, &device);
if (error)
return;
-
+
map = loaded ();
if (!map)
{
extern void _start ();
vm_address_t text_start = (vm_address_t) &_start;
- wire_segment_internal (text_start,
+ wire_segment_internal (text_start,
(vm_size_t) (&_etext - text_start),
host);
wire_segment_internal ((vm_address_t) &__data_start,
@@ -156,4 +184,3 @@ wire_task_self ()
mach_port_deallocate (mach_task_self (), host);
mach_port_deallocate (mach_task_self (), device);
}
-
diff --git a/libshouldbeinlibc/xportinfo.c b/libshouldbeinlibc/xportinfo.c
index cdd1da38..cce6fb6c 100644
--- a/libshouldbeinlibc/xportinfo.c
+++ b/libshouldbeinlibc/xportinfo.c
@@ -1,6 +1,6 @@
/* Print information about a port, with the name translated between tasks
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -18,6 +18,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <sys/types.h>
+#include <sys/mman.h>
+
#include "portinfo.h"
/* Prints info about NAME translated through X to STREAM, in a way described
@@ -32,7 +35,7 @@ print_xlated_port_info (mach_port_t name, mach_port_type_t type,
error_t err = port_name_xlator_xlate (x, name, type, &name, &type);
if (! err)
{
- fprintf (stream, (show & PORTINFO_HEX_NAMES) ? "%#6x => " : "%6d => ",
+ fprintf (stream, (show & PORTINFO_HEX_NAMES) ? "%#6zx => " : "%6zd => ",
old_name);
err = print_port_info (name, type, x->to_task, show, stream);
}
@@ -59,10 +62,8 @@ print_xlated_task_ports_info (struct port_name_xlator *x,
if (types[i] & only)
print_xlated_port_info (names[i], types[i], x, show, stream);
- vm_deallocate (mach_task_self (),
- (vm_address_t)names, names_len * sizeof *names);
- vm_deallocate (mach_task_self (),
- (vm_address_t)types, types_len * sizeof *types);
+ munmap ((caddr_t) names, names_len * sizeof *names);
+ munmap ((caddr_t) types, types_len * sizeof *types);
return 0;
}
diff --git a/libstore/ChangeLog b/libstore/ChangeLog
deleted file mode 100644
index 07d6041b..00000000
--- a/libstore/ChangeLog
+++ /dev/null
@@ -1,152 +0,0 @@
-Fri Jul 19 16:16:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * decode.c (store_std_leaf_decode): Decode name too.
- Deal with NAME_LENGTH being 0.
-
-Sun Jun 16 22:49:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (parse_opt): Use argp_failure.
-
-Thu May 23 10:54:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (parse_opt): Honor ARGP_NO_ERRS.
- <error.h>: New include.
-
-Wed May 22 00:14:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (parse_opt): Use error instead of ERR for non-parsing errors.
- Rename ERR to PERR.
-
-Tue May 21 00:01:02 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storecat.c (main): Delete most everything and use store arg parsing.
- (options, doc, args_doc): Variables removed.
-
- * create.c (store_create): Add FLAGS & CLASSES params.
- * rdwr.c (store_write): Return an error if STORE is readonly.
- * decode.c (store_decode): Add CLASSES param, use it instead of big
- hardwired switch statement.
- (store_default_leaf_decode): Use typedef for CREATE param. Pass in
- FLAGS arg when calling it.
- * encode.c (store_std_leaf_allocate_encoding): Renamed from
- store_default_leaf_allocate_encoding. Make STORE const.
- (store_std_leaf_encode): Renamed from store_default_leaf_encode.
- Make STORE const. Get class id from store->class->id.
- (store_encode): Use CLASS field instead of METHS field.
- * clone.c (store_clone): Copy the flags by passing them to _make_store.
- Use CLASS field instead of METHS field.
- * file.c (store_file_open, file_decode): New functions.
- (store_file_create): Always set STORE_ENFORCED.
- (file_class): Renamed from file_meths. Add more fields. Make std
- with _STORE_STD_CLASS.
- (file_byte_class): Renamed from file_byte_meths.
- <fcntl.h>, <hurd.h>: New includes.
- * device.c (store_device_open, dev_decode): New functions.
- (store_device_create): Always set STORE_ENFORCED.
- (device_class): Renamed from device_meths. Add more fields. Make std
- with _STORE_STD_CLASS.
- <hurd.h>: New include.
- * stripe.c (ileave_allocate_encoding, ileave_encode, ileave_decode,
- concat_allocate_encoding, concat_encode, concat_decode): New functions.
- (concat_class): New variable.
- (ileave_class): Renamed from stripe_class. More fields added.
- * store.h (struct store): Remove CLASS field. METHS field renamed
- CLASS.
- (STORE_IMMUTABLE_FLAGS, STORE_GENERIC_FLAGS, STORE_BACKEND_SPEC_BASE,
- STORE_BACKEND_FLAGS, STORE_READONLY, STORE_HARD_READONLY,
- STORE_ENFORCED): New macros.
- (struct store_class): Renamed from store_meths; all uses changed.
- Add ID, NAME, DECODE, SET_FLAGS, CLEAR_FLAGS, and NEXT fields.
- (store_std_leaf_decode): Renamed from store_default_leaf_decode.
- (store_std_leaf_create_t): New type.
- (_STORE_STD_CLASS): New macro.
- (struct store_argp_params): READONLY field deleted, FLAGS field added.
- (store_allocate_child_encodings, store_encode_children,
- store_decode_children, store_set_flags, store_clear_flags,
- store_file_open, store_device_open, store_null_create,
- store_std_classes, _store_add_std_class,
- store_allocate_child_encodings, store_encode_children,
- store_decode_children): New declarations
- (store_decode, store_create, store_device_create, _store_device_create,
- store_file_create, _store_file_create, store_ileave_create,
- store_concat_create, _make_store): Declarations updated.
- * make.c (_make_store): CLASS param removed, METHS param renamed
- CLASS; all callers changed. FLAGS param added.
- * stripe.c (store_ileave_create, store_concat_create): Likewise.
- * file.c (store_file_create, _store_file_create): Likewise.
- * device.c (store_device_create, _store_device_create): Likewise.
- * argp.c (open_machdev): Function removed.
- (parse_opt): Use store_device_open instead of open_machdev.
- (open_file, parse_opt): Add FLAGS arg to various function calls.
- * set.c (store_set_children): Function moved to kids.c.
- * null.c, flags.c, std.c, kids.c: New files.
- * Makefile (SRCS): Add null.c, flags.c, std.c, & kids.c.
-
-Sun May 12 10:12:24 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c (store_parse_opt): Put result in the passed-in params struct.
- Pass hook to open_{file,machdev}.
- (open_machdev): Use params to determine readonly-ness.
- (open_file): New function.
- * store.h (store_argp): New declaration.
- (struct store_argp_params): New type.
- * Makefile (SRCS): Add argp.c.
-
- * create.c (store_create): Steal SOURCE instead of cloning it.
-
-Sat May 11 01:17:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * argp.c: New file.
-
- * storeread.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
- * storecat.c (parse_opt): Likewise.
-
-Fri May 10 13:23:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * store.h (struct store_run): New type.
- (struct store): RUNS is a vector of runs, not offsets.
- (_store_device_create, _store_file_create, _make_store,
- store_set_runs, store_default_leaf_decode): Update declaration.
- * rdwr.c (store_find_first_run, store_next_run, store_write,
- store_read): Use store_run, not off_t, vectors; tweak accordingly.
- Rename variables called `RUNS' to `RUN', because although they're
- always vectors, they're used more often for their first element.
- * derive.c (_store_derive): Use store_run, not off_t, vectors; tweak
- accordingly.
- * device.c (store_device_create, _store_device_create): Likewise.
- * set.c (store_set_runs): Likewise.
- * storecat.c (main): Likewise.
- * storeread.c (main): Likewise.
- * make.c (_make_store): Likewise.
- * stripe.c (store_ileave_create, store_concat_create): Likewise.
- * file.c (store_file_create, _store_file_create): Likewise.
- * decode.c (store_default_leaf_decode): Convert the slice of the
- offset vector we're using into a vector of store_runs to pass to
- CREATE. Change type of CREATE accordingly.
- * encode.c (store_default_leaf_encode): Convert from the store_run
- vector to a off_t vector for encoding.
-
- * create.c (store_create): Use the real file_get_storage_info.
- (fgsi): Function removed.
-
- * store.h (struct store): Add CHILDREN & NUM_CHILDREN fields.
- Rename RUNS_LEN to NUM_RUNS (all uses changed).
- (store_set_children): New declaration.
- * make.c (_make_store): Initialize CHILDREN & NUM_CHILDREN.
- (store_free): Free all children too.
- * clone.c (store_clone): Clone children too.
- * set.c (store_set_children): New function.
- * stripe.c (store_ileave_create, store_concat_create): Use
- store_set_children.
- (stripe_clone): Function removed.
- (stripe_read, stripe_write): Get stripes from CHILDREN, not HOOK.
-
- * Makefile (storeread, storecat): Remove explicit dependency on
- program object file.
- Put include of ../Makeconf before dependencies.
-
-Mon May 6 15:20:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * store.h: Move big comment describing file_get_storage_info
- encoding to <hurd/hurd_types.h>.
-
diff --git a/libstore/Makefile b/libstore/Makefile
index b33fc913..56c1fdfd 100644
--- a/libstore/Makefile
+++ b/libstore/Makefile
@@ -1,7 +1,7 @@
# Makefile for libstore
-#
-# Copyright (C) 1995, 1996 Free Software Foundation
-# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc.
+# Written by Miles Bader <miles@gnu.org>
#
# This file is part of the GNU Hurd.
#
@@ -17,22 +17,75 @@
#
# 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.
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
dir := libstore
makemode := library
libname = libstore
-SRCS = create.c derive.c make.c rdwr.c set.c device.c file.c stripe.c \
- storeread.c storecat.c enc.c encode.c decode.c clone.c argp.c \
- std.c kids.c null.c flags.c
+SRCS = create.c derive.c make.c rdwr.c set.c \
+ enc.c encode.c decode.c clone.c argp.c kids.c flags.c \
+ open.c xinl.c typed.c map.c url.c unknown.c \
+ stripe.c $(filter-out ileave.c concat.c,$(store-types:=.c))
+
+# This has to be evaluated after config.make has been included;
+# as a consequence, using 'ifneq' or similar is not an option.
+maybe_part = $(and $(PARTED_LIBS),part)
+
+store-types = \
+ bunzip2 \
+ concat \
+ copy \
+ device \
+ file \
+ gunzip \
+ ileave \
+ memobj \
+ module \
+ mvol \
+ nbd \
+ $(maybe_part) \
+ remap \
+ task \
+ zero
+
+libstore.so-LDLIBS += $(PARTED_LIBS) -ldl
LCLHDRS=store.h
installhdrs=store.h
-UTIL_OBJS = storeread.o storecat.o
-OBJS = $(filter-out $(UTIL_OBJS), $(SRCS:.c=.o))
+HURDLIBS = shouldbeinlibc
+GUNZIP_OBJS = unzip.o inflate.o util.o
+BUNZIP2_OBJS = do-bunzip2.o
+OBJS = $(SRCS:.c=.o) $(GUNZIP_OBJS) $(BUNZIP2_OBJS)
+DIST_FILES = unzipstore.c
include ../Makeconf
-storeread: libstore.so ../libshouldbeinlibc/libshouldbeinlibc.so
-storecat: libstore.so ../libshouldbeinlibc/libshouldbeinlibc.so
+# Look for zip stuff
+vpath %.c $(srcdir)/../exec
+CPPFLAGS += -I$(srcdir)/../exec
+
+module-CPPFLAGS = -D'STORE_SONAME_SUFFIX=".so.$(hurd-version)"'
+
+libstore_gunzip.so.$(hurd-version): $(GUNZIP_OBJS:.o=_pic.o)
+libstore_bunzip2.so.$(hurd-version): $(BUNZIP2_OBJS:.o=_pic.o)
+
+# You can use this rule to make a dynamically-loadable version of any
+# of the modules. We don't make any of these by default, since we
+# just include all the standard store types in libstore.so itself.
+libstore_%.so.$(hurd-version): %_pic.o libstore.so
+ $(CC) -shared -Wl,-soname=$@ -o $@ \
+ $(rpath) $(CFLAGS) $(LDFLAGS) $(libstore_$*.so-LDFLAGS) $^
+
+# Each libstore_TYPE.a is in fact an object file script so that `-lstore_TYPE'
+# just has the same effect as `-u store_TYPE_class'.
+$(store-types:%=libstore_%.a): libstore_%.a: $(srcdir)/Makefile
+ $(CC) -r -nostdlib -nostartfiles -x c /dev/null \
+ -o $@ -u store_$*_class
+cleantarg += $(store-types:%=libstore_%.a)
+
+all: $(store-types:%=libstore_%.a)
+
+install: $(store-types:%=$(libdir)/libstore_%.a)
+$(store-types:%=$(libdir)/libstore_%.a): $(libdir)/%: %
+ $(INSTALL_DATA) $< $@
diff --git a/libstore/argp.c b/libstore/argp.c
index 86b7eae2..6ed79964 100644
--- a/libstore/argp.c
+++ b/libstore/argp.c
@@ -1,9 +1,7 @@
/* Store argument parsing
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,98,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,190 +16,371 @@
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. */
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <stdlib.h>
#include <string.h>
-#include <fcntl.h>
+#include <assert.h>
#include <hurd.h>
#include <argp.h>
-#include <error.h>
+#include <argz.h>
#include "store.h"
+/* We use this class variable instead of just the name so that we ensure
+ linking in store_open to define it. */
+#define DEFAULT_STORE_CLASS store_query_class
+
static const struct argp_option options[] = {
- {"machdev", 'm', 0, 0, "DEVICE is a mach device, not a file"},
- {"interleave", 'i', "BLOCKS", 0, "Interleave in runs of length BLOCKS"},
- {"layer", 'l', 0, 0, "Layer multiple devices for redundancy"},
+ {"store-type",'T', "TYPE", 0, "Each DEVICE names a store of type TYPE"},
+ {"machdev", 'm', 0, OPTION_HIDDEN}, /* deprecated */
+ {"interleave",'I', "BLOCKS", 0, "Interleave in runs of length BLOCKS"},
+ {"layer", 'L', 0, 0, "Layer multiple devices for redundancy"},
{0}
};
static const char args_doc[] = "DEVICE...";
-static const char doc[] = "If multiple DEVICEs are specified, they are"
-" concatenated unless either --interleave or --layer is specified (mutually"
-" exlusive).";
+static const char doc[] = "\vIf neither --interleave or --layer is specified,"
+" multiple DEVICEs are concatenated.";
-/* Used to hold data during argument parsing. */
-struct store_parse_hook
+struct store_parsed
{
- /* A malloced vector of stores specified on the command line, NUM_STORES
- long. */
- struct store **stores;
- size_t num_stores;
+ /* Names of devices parsed. */
+ char *names;
+ size_t names_len;
+
+ /* Prefix that should be applied to each member of NAMES. */
+ char *name_prefix;
- /* Pointer to params struct passed in by user. */
- struct store_argp_params *params;
+ /* --store-type specified. This defaults to the `query' type. */
+ const struct store_class *type;
- off_t interleave; /* --interleave value */
- int machdev : 1; /* --machdev specified */
+ /* A vector of class pointers used to lookup class names. Defaults to
+ STORE_STD_CLASSES. */
+ const struct store_class *const *classes;
+
+ /* DEFAULT_TYPE field passed to parser. */
+ const struct store_class *default_type;
+
+ store_offset_t interleave; /* --interleave value */
int layer : 1; /* --layer specified */
};
-/* Free the parse hook H. If FREE_STORES is true, also free the stores in
- H's store vector, otherwise just free the vector itself. */
-static void
-free_hook (struct store_parse_hook *h, int free_stores)
+void
+store_parsed_free (struct store_parsed *parsed)
{
- int i;
- if (free_stores)
- for (i = 0; i < h->num_stores; i++)
- store_free (h->stores[i]);
- if (h->stores)
- free (h->stores);
- free (h);
+ if (parsed->names_len > 0)
+ free (parsed->names);
+ if (parsed->name_prefix)
+ free (parsed->name_prefix);
+ free (parsed);
}
-
-static error_t
-open_file (char *name, struct store_parse_hook *h, struct store **s)
+
+/* Add the arguments PARSED, and return the corresponding store in STORE. */
+error_t
+store_parsed_append_args (const struct store_parsed *parsed,
+ char **args, size_t *args_len)
{
- error_t err;
- int flags = h->params->flags;
- int open_flags = (flags & STORE_HARD_READONLY) ? O_RDONLY : O_RDWR;
- file_t node = file_name_lookup (name, open_flags, 0);
+ char buf[40];
+ error_t err = 0;
+ size_t num_names = argz_count (parsed->names, parsed->names_len);
- if (node == MACH_PORT_NULL)
- return errno;
+ if (!err && num_names > 1 && (parsed->interleave || parsed->layer))
+ {
+ if (parsed->interleave)
+ snprintf (buf, sizeof buf, "--interleave=%Ld", parsed->interleave);
+ else
+ snprintf (buf, sizeof buf, "--layer=%d", parsed->layer);
+ err = argz_add (args, args_len, buf);
+ }
- err = store_create (node, flags, 0, s);
- if (err)
+ if (!err && parsed->type != parsed->default_type)
{
- if (! h->params->no_file_io)
- /* Try making a store that does file io to NODE. */
- err = store_file_create (node, flags, s);
- if (err)
- mach_port_deallocate (mach_task_self (), node);
+ if (parsed->name_prefix)
+ /* A name prefix of "PFX" is equivalent to appending ":PFX" to the
+ type name. */
+ {
+ size_t npfx_len = strlen (parsed->name_prefix);
+ char tname[strlen ("--store-type=")
+ + strlen (parsed->type->name) + 1 + npfx_len + 1];
+ snprintf (tname, sizeof tname, "--store-type=%s:%.*s",
+ parsed->type->name, (int) npfx_len, parsed->name_prefix);
+ err = argz_add (args, args_len, tname);
+ }
+ else
+ /* A simple type name. */
+ {
+ snprintf (buf, sizeof buf, "--store-type=%s", parsed->type->name);
+ err = argz_add (args, args_len, buf);
+ }
}
+ if (! err)
+ err = argz_append (args, args_len, parsed->names, parsed->names_len);
+
return err;
}
-static error_t
-parse_opt (int opt, char *arg, struct argp_state *state)
+error_t
+store_parsed_name (const struct store_parsed *parsed, char **name)
{
- error_t err = 0;
- struct store_parse_hook *h = state->hook;
+ char buf[40];
+ char *pfx = 0;
+
+ if (argz_count (parsed->names, parsed->names_len) > 1)
+ {
+ if (parsed->interleave)
+ {
+ snprintf (buf, sizeof buf, "interleave(%Ld,", parsed->interleave);
+ pfx = buf;
+ }
+ else if (parsed->layer)
+ pfx = "layer(";
+ }
+
+ if (pfx)
+ *name = malloc (strlen (pfx) + parsed->names_len + 1);
+ else
+ *name = malloc (parsed->names_len);
+
+ if (! *name)
+ return ENOMEM;
+
+ if (pfx)
+ {
+ char *end = stpcpy (*name, pfx);
+ bcopy (parsed->names, end, parsed->names_len);
+ argz_stringify (end, parsed->names_len, ',');
+ strcpy (end + parsed->names_len, ")");
+ }
+ else
+ {
+ bcopy (parsed->names, *name, parsed->names_len);
+ argz_stringify (*name, parsed->names_len, ',');
+ }
+
+ return 0;
+}
+
+/* Open PARSED, and return the corresponding store in STORE. */
+error_t
+store_parsed_open (const struct store_parsed *parsed, int flags,
+ struct store **store)
+{
+ size_t pfx_len = parsed->name_prefix ? strlen (parsed->name_prefix) : 0;
+ size_t num = argz_count (parsed->names, parsed->names_len);
+
+ error_t open (char *name, struct store **store)
+ {
+ const struct store_class *type = parsed->type;
+ if (type->open)
+ {
+ if (parsed->name_prefix)
+ /* If there's a name prefix, we prefix any names we open with that
+ and a colon. */
+ {
+ char pfxed_name[pfx_len + 1 + strlen (name) + 1];
+ stpcpy (stpcpy (stpcpy (pfxed_name, parsed->name_prefix),
+ ":"),
+ name);
+ return (*type->open) (pfxed_name, flags, parsed->classes, store);
+ }
+ else
+ return (*type->open) (name, flags, parsed->classes, store);
+ }
+ else
+ return EOPNOTSUPP;
+ }
+
+ if (num == 1)
+ return open (parsed->names, store);
+ else if (num == 0)
+ return open (0, store);
+ else
+ {
+ int i;
+ char *name;
+ error_t err = 0;
+ struct store **stores = malloc (sizeof (struct store *) * num);
+
+ if (! stores)
+ return ENOMEM;
- /* Print a parsing error message and (if exiting is turned off) return the
- error code ERR. */
+ for (i = 0, name = parsed->names;
+ !err && i < num;
+ i++, name = argz_next (parsed->names, parsed->names_len, name))
+ err = open (name, &stores[i]);
+
+ if (! err)
+ {
+ if (parsed->interleave)
+ err =
+ store_ileave_create (stores, num, parsed->interleave,
+ flags, store);
+ else if (parsed->layer)
+ assert (! parsed->layer);
+ else
+ err = store_concat_create (stores, num, flags, store);
+ }
+
+ if (err)
+ {
+ while (i > 0)
+ store_free (stores[i--]);
+ free (stores);
+ }
+
+ return err;
+ }
+}
+
+static const struct store_class *
+find_class (const char *name, const struct store_class *const *const classes)
+{
+ const struct store_class *const *cl;
+ for (cl = classes ?: __start_store_std_classes;
+ classes ? *cl != 0 : cl < __stop_store_std_classes;
+ ++cl)
+ if ((*cl)->name && strcmp (name, (*cl)->name) == 0)
+ return *cl;
+
+# pragma weak store_module_find_class
+ if (! classes && store_module_find_class)
+ {
+ const struct store_class *cl;
+ if (store_module_find_class (name, strchr (name, '\0'), &cl) == 0)
+ return cl;
+ }
+
+ return 0;
+}
+
+/* Print a parsing error message and (if exiting is turned off) return the
+ error code ERR. Requires a variable called STATE to be in scope. */
#define PERR(err, fmt, args...) \
do { argp_error (state, fmt , ##args); return err; } while (0)
- switch (opt)
+/* Parse a --store-type/-T option. */
+static error_t
+parse_type (char *arg, struct argp_state *state, struct store_parsed *parsed)
+{
+ char *name_prefix = 0;
+ char *type_name = arg;
+ const struct store_class *type;
+ char *class_sep = strchr (arg, ':');
+
+ if (class_sep)
+ /* A `:'-separated class name "T1:T2" is equivalent to prepending "T2:"
+ to the device name passed to T1, and is useful for the case where T1
+ takes typed names of the form "T:NAME". A trailing `:', like "T1:" is
+ equivalent to prefixing `:' to the device name, which causes NAME to
+ be opened with store_open, as a file. */
{
- struct store *s;
+ type_name = strndupa (arg, class_sep - arg);
+ name_prefix = class_sep + 1;
+ }
+
+ type = find_class (type_name, parsed->classes);
+ if (!type || !type->open)
+ PERR (EINVAL, "%s: Invalid argument to --store-type", arg);
+ else if (type != parsed->type && parsed->type != parsed->default_type)
+ PERR (EINVAL, "--store-type specified multiple times");
+
+ parsed->type = type;
+ parsed->name_prefix = name_prefix;
+
+ return 0;
+}
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ error_t err;
+ struct store_parsed *parsed = state->hook;
+ switch (opt)
+ {
case 'm':
- h->machdev = 1; break;
+ arg = "device";
+ /* fall through */
+ case 'T':
+ return parse_type (arg, state, parsed);
- case 'i':
- if (h->layer)
+ case 'I':
+ if (parsed->layer)
PERR (EINVAL, "--layer and --interleave are exclusive");
- if (h->interleave)
+ if (parsed->interleave)
/* Actually no reason why we couldn't support this.... */
PERR (EINVAL, "--interleave specified multiple times");
- h->interleave = atoi (arg);
- if (! h->interleave)
+ parsed->interleave = atoi (arg);
+ if (! parsed->interleave)
PERR (EINVAL, "%s: Bad value for --interleave", arg);
break;
- case 'l':
- if (h->interleave)
+ case 'L':
+#if 1
+ argp_failure (state, 5, 0, "--layer not implemented");
+ return EINVAL;
+#else
+ if (parsed->interleave)
PERR (EINVAL, "--layer and --interleave are exclusive");
- h->layer = 1;
+ parsed->layer = 1;
+#endif
break;
case ARGP_KEY_ARG:
/* A store device to use! */
- if (h->machdev)
- err = store_device_open (arg, h->params->flags, &s);
+ if (parsed->type->validate_name)
+ err = (*parsed->type->validate_name) (arg, parsed->classes);
else
- err = open_file (arg, h, &s);
+ err = 0;
+ if (! err)
+ err = argz_add (&parsed->names, &parsed->names_len, arg);
if (err)
- {
- argp_failure (state, 1, err, "%s", arg);
- return err;
- }
- else
- {
- struct store **stores = realloc (h->stores, h->num_stores + 1);
- if (stores)
- {
- stores[h->num_stores++] = s;
- h->stores = stores;
- }
- else
- return ENOMEM; /* Just fucking lovely */
- }
+ argp_failure (state, 1, err, "%s", arg);
+ return err;
break;
case ARGP_KEY_INIT:
/* Initialize our parsing state. */
- if (! state->input)
- return EINVAL; /* Need at least a way to return a result. */
- h = malloc (sizeof (struct store_parse_hook));
- if (! h)
- return ENOMEM;
- bzero (h, sizeof (struct store_parse_hook));
- h->params = state->input;
- state->hook = h;
+ {
+ struct store_argp_params *params = state->input;
+ if (! params)
+ return EINVAL; /* Need at least a way to return a result. */
+ parsed = state->hook = malloc (sizeof (struct store_parsed));
+ if (! parsed)
+ return ENOMEM;
+ bzero (parsed, sizeof (struct store_parsed));
+ parsed->classes = params->classes;
+ parsed->default_type =
+ find_class (params->default_type ?: DEFAULT_STORE_CLASS.name,
+ parsed->classes);
+ if (! parsed->default_type)
+ {
+ free (parsed);
+ return EINVAL;
+ }
+ parsed->type = parsed->default_type;
+ }
break;
case ARGP_KEY_ERROR:
- /* Parsing error occured, free everything. */
- free_hook (h, 1); break;
+ /* Parsing error occurred, free everything. */
+ store_parsed_free (parsed); break;
case ARGP_KEY_SUCCESS:
/* Successfully finished parsing, return a result. */
-
- if (h->num_stores == 0)
+ if (parsed->names == 0
+ && (!parsed->type->validate_name
+ || (*parsed->type->validate_name) (0, parsed->classes) != 0))
{
- free_hook (h, 1);
- PERR (EINVAL, "No store specified");
+ struct store_argp_params *params = state->input;
+ store_parsed_free (parsed);
+ if (!params->store_optional)
+ PERR (EINVAL, "No store specified");
+ parsed = 0;
}
-
- if (state->input == 0)
- /* No way to return a value! */
- err = EINVAL;
- else if (h->num_stores == 1)
- s = h->stores[0]; /* Just a single store. */
- else if (h->interleave)
- err =
- store_ileave_create (h->stores, h->num_stores, h->interleave,
- h->params->flags, &s);
- else if (h->layer)
- {
- free_hook (h, 1);
- PERR (EINVAL, "--layer not implemented");
- }
- else
- err =
- store_concat_create (h->stores, h->num_stores, h->params->flags, &s);
-
- free_hook (h, err);
- if (! err)
- h->params->result = s;
-
+ ((struct store_argp_params *)state->input)->result = parsed;
break;
default:
diff --git a/libstore/bunzip2.c b/libstore/bunzip2.c
new file mode 100644
index 00000000..ec0630ec
--- /dev/null
+++ b/libstore/bunzip2.c
@@ -0,0 +1,13 @@
+#include <errno.h>
+
+extern void do_bunzip2 (void); /* Entry point to bunzip2 engine. */
+
+static error_t
+DO_UNZIP (void)
+{
+ do_bunzip2 ();
+ return 0;
+}
+
+#define UNZIP bunzip2
+#include "unzipstore.c"
diff --git a/libstore/clone.c b/libstore/clone.c
index bec2e88d..cdbd5747 100644
--- a/libstore/clone.c
+++ b/libstore/clone.c
@@ -1,9 +1,7 @@
/* Store cloning
- Copyright (C) 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
#include <stdlib.h>
@@ -29,13 +27,20 @@
error_t
store_clone (struct store *from, struct store **to)
{
- error_t err = 0;
- struct store *c =
- _make_store (from->class, from->port, from->flags, from->block_size,
- from->runs, from->num_runs, from->end);
+ struct store *c;
+ error_t err =
+ _store_create (from->class, from->port, from->flags, from->block_size,
+ from->runs, from->num_runs, from->end, &c);
+
+ if (err)
+ return err;
- if (! c)
- return ENOMEM;
+ if (from->name)
+ {
+ c->name = strdup (from->name);
+ if (! c->name)
+ err = ENOMEM;
+ }
if (from->misc_len)
{
diff --git a/libstore/copy.c b/libstore/copy.c
new file mode 100644
index 00000000..c670ebf3
--- /dev/null
+++ b/libstore/copy.c
@@ -0,0 +1,267 @@
+/* Copy store backend
+
+ Copyright (C) 1995,96,97,99,2000,01,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <sys/mman.h>
+#include <mach.h>
+
+#define page_aligned(addr) (((size_t) addr & (vm_page_size - 1)) == 0)
+
+#include "store.h"
+
+static error_t
+copy_read (struct store *store, store_offset_t addr, size_t index,
+ size_t amount, void **buf, size_t *len)
+{
+ char *data = store->hook + (addr * store->block_size);
+
+ if (page_aligned (data) && page_aligned (amount))
+ /* When reading whole pages, we can avoid any real copying. */
+ return vm_read (mach_task_self (),
+ (vm_address_t) data, amount,
+ (pointer_t *) buf, len);
+
+ if (*len < amount)
+ /* Have to allocate memory for the return value. */
+ {
+ *buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == MAP_FAILED)
+ return errno;
+ }
+
+ memcpy (*buf, data, amount);
+ *len = amount;
+ return 0;
+}
+
+static error_t
+copy_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ char *data = store->hook + (addr * store->block_size);
+
+ if (page_aligned (data) && page_aligned (len) && page_aligned (buf))
+ {
+ /* When writing whole pages, we can avoid any real copying. */
+ error_t err = vm_write (mach_task_self (),
+ (vm_address_t) data, (vm_address_t) buf, len);
+ *amount = len;
+ return err;
+ }
+
+ memcpy (data, buf, len);
+ *amount = len;
+ return 0;
+}
+
+static error_t
+copy_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+copy_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+copy_encode (const struct store *store, struct store_enc *enc)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+copy_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+copy_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_copy_open (name, flags, classes, store);
+}
+
+static error_t
+copy_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ /* ... */
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+copy_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ /* ... */
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+/* Called just before deallocating STORE. */
+void
+copy_cleanup (struct store *store)
+{
+ if (store->size > 0)
+ munmap (store->hook, store->size);
+}
+
+/* Copy any format-dependent fields in FROM to TO; if there's some reason
+ why the copy can't be made, an error should be returned. This call is
+ made after all format-indendependent fields have been cloned. */
+error_t
+copy_clone (const struct store *from, struct store *to)
+{
+ void *buf;
+ buf = mmap (0, to->size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ {
+ to->hook = buf;
+ memcpy (to->hook, from->hook, from->size);
+ return 0;
+ }
+ return errno;
+}
+
+const struct store_class
+store_copy_class =
+{
+ STORAGE_COPY, "copy", copy_read, copy_write, copy_set_size,
+ copy_allocate_encoding, copy_encode, copy_decode,
+ copy_set_flags, copy_clear_flags, copy_cleanup, copy_clone, 0, copy_open
+};
+STORE_STD_CLASS (copy);
+
+/* Return a new store in STORE which contains a snapshot of the contents of
+ the store FROM; FROM is consumed. */
+error_t
+store_copy_create (struct store *from, int flags, struct store **store)
+{
+ error_t err;
+ struct store_run run;
+
+ run.start = 0;
+ run.length = from->size;
+
+ flags |= STORE_ENFORCED; /* Only uses local resources. */
+
+ err =
+ _store_create (&store_copy_class,
+ MACH_PORT_NULL, flags, from->block_size, &run, 1, 0,
+ store);
+ if (! err)
+ {
+ size_t buf_len = 0;
+
+ /* Copy the input store. */
+ err = store_read (from, 0, from->size, &(*store)->hook, &buf_len);
+
+ if (! err)
+ /* Set the store name. */
+ {
+ if (from->name)
+ {
+ size_t len =
+ strlen (from->class->name) + 1 + strlen (from->name) + 1;
+ (*store)->name = malloc (len);
+ if ((*store)->name)
+ snprintf ((*store)->name, len,
+ "%s:%s", from->class->name, from->name);
+ }
+ else
+ (*store)->name = strdup (from->class->name);
+
+ if (! (*store)->name)
+ err = ENOMEM;
+ }
+
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* Return a new store in STORE which contains the memory buffer BUF, of
+ length BUF_LEN, and uses the block size BLOCK_SIZE. BUF must be
+ vm_allocated, and will be consumed, and BUF_LEN must be a multiple of
+ BLOCK_SIZE. */
+error_t
+store_buffer_create (void *buf, size_t buf_len, int flags,
+ struct store **store)
+{
+ error_t err;
+ struct store_run run;
+
+ run.start = 0;
+ run.length = buf_len;
+
+ flags |= STORE_ENFORCED; /* Only uses local resources. */
+
+ err =
+ _store_create (&store_copy_class,
+ MACH_PORT_NULL, flags, 1, &run, 1, 0, store);
+ if (! err)
+ (*store)->hook = buf;
+
+ return err;
+}
+
+/* Open the copy store NAME -- which consists of another store-class name, a
+ ':', and a name for that store class to open -- and return the
+ corresponding store in STORE. CLASSES is used to select classes specified
+ by the type name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+store_copy_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store *from;
+ error_t err =
+ store_typed_open (name, flags | STORE_HARD_READONLY, classes, &from);
+
+ if (! err)
+ {
+ err = store_copy_create (from, flags, store);
+ if (err)
+ store_free (from);
+ }
+
+ return err;
+}
diff --git a/libstore/create.c b/libstore/create.c
index e332e85c..010a053e 100644
--- a/libstore/create.c
+++ b/libstore/create.c
@@ -1,9 +1,7 @@
/* Store creation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,19 +16,23 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <hurd/fs.h>
#include "store.h"
-/* Return a new store in STORE, which refers to the storage underlying
- SOURCE. CLASSES is used to select classes specified by the provider; if
- it is 0, STORE_STD_CLASSES is used. FLAGS is set with store_set_flags. A
- reference to SOURCE is created (but may be destroyed with
- store_close_source). */
+/* Return a new store in STORE, which refers to the storage underlying SOURCE.
+ CLASSES is used to select classes specified by the provider; if it is 0,
+ STORE_STD_CLASSES is used. FLAGS is set with store_set_flags, with the
+ exception of STORE_INACTIVE, which merely indicates that no attempt should
+ be made to activate an inactive store; if STORE_INACTIVE is not specified,
+ and the store returned for SOURCE is inactive, an attempt is made to
+ activate it (failure of which causes an error to be returned). A reference
+ to SOURCE is created (but may be destroyed with store_close_source). */
error_t
-store_create (file_t source, int flags, struct store_class *classes,
+store_create (file_t source, int flags,
+ const struct store_class *const *classes,
struct store **store)
{
error_t err;
@@ -52,9 +54,20 @@ store_create (file_t source, int flags, struct store_class *classes,
return err;
err = store_decode (&enc, classes, store);
-
- if (!err && flags)
- store_set_flags (*store, flags);
+ if (! err)
+ {
+ if (flags & STORE_INACTIVE)
+ flags &= ~STORE_INACTIVE; /* Don't actually make store inactive. */
+ else if ((*store)->flags & STORE_INACTIVE)
+ err = store_clear_flags (*store, STORE_INACTIVE);
+ if (!err && flags)
+ err = store_set_flags (*store, flags);
+ if (err)
+ store_free (*store);
+ }
+ else if (err == EINVAL && (flags &~ STORE_INACTIVE) == STORE_NO_FILEIO)
+ /* Open a generic "unknown" store that can regurgitate this encoding. */
+ err = store_unknown_decode (&enc, classes, store);
store_enc_dealloc (&enc);
diff --git a/libstore/decode.c b/libstore/decode.c
index 5231b33d..64405ecd 100644
--- a/libstore/decode.c
+++ b/libstore/decode.c
@@ -1,9 +1,7 @@
/* Store wire decoding
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,98,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
#include <malloc.h>
@@ -37,10 +35,15 @@ store_std_leaf_decode (struct store_enc *enc,
{
char *misc, *name;
error_t err;
- int type, flags, i;
+ int type, flags;
mach_port_t port;
size_t block_size, num_runs, name_len, misc_len;
-
+ /* Call CREATE appriately from within store_with_decoded_runs. */
+ error_t call_create (const struct store_run *runs, size_t num_runs)
+ {
+ return (*create)(port, flags, block_size, runs, num_runs, store);
+ }
+
/* Make sure there are enough encoded ints and ports. */
if (enc->cur_int + 6 > enc->num_ints || enc->cur_port + 1 > enc->num_ports)
return EINVAL;
@@ -61,25 +64,63 @@ store_std_leaf_decode (struct store_enc *enc,
if (name_len > 0 && enc->data[enc->cur_data + name_len - 1] != '\0')
return EINVAL; /* Name not terminated. */
- misc = malloc (misc_len);
- if (! misc)
- return ENOMEM;
-
if (name_len > 0)
{
name = strdup (enc->data + enc->cur_data);
if (! name)
+ return ENOMEM;
+ enc->cur_data += name_len;
+ }
+ else
+ name = 0;
+
+ if (misc_len > 0)
+ {
+ misc = malloc (misc_len);
+ if (! misc)
{
- free (misc);
+ if (name)
+ free (name);
return ENOMEM;
}
+ memcpy (misc, enc->data + enc->cur_data + name_len, misc_len);
+ enc->cur_data += misc_len;
}
else
- name = 0;
+ misc = 0;
/* Read encoded ports (be careful to deallocate this if we barf). */
port = enc->ports[enc->cur_port++];
+ err = store_with_decoded_runs (enc, num_runs, call_create);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), port);
+ if (misc)
+ free (misc);
+ if (name)
+ free (name);
+ }
+ else
+ {
+ (*store)->flags = flags;
+ (*store)->name = name;
+ (*store)->misc = misc;
+ (*store)->misc_len = misc_len;
+ }
+
+ return err;
+}
+
+/* Call FUN with the vector RUNS of length RUNS_LEN extracted from ENC. */
+error_t
+store_with_decoded_runs (struct store_enc *enc, size_t num_runs,
+ error_t (*fun) (const struct store_run *runs,
+ size_t num_runs))
+{
+ int i;
+ error_t err;
+
/* Since the runs are passed in an array of off_t pairs, and we use struct
store_run, we have to make a temporary array to hold the (probably
bitwise identical) converted representation to pass to CREATE. */
@@ -92,7 +133,8 @@ store_std_leaf_decode (struct store_enc *enc,
runs[i].start = *e++;
runs[i].length = *e++;
}
- err = (*create)(port, flags, block_size, runs, num_runs, store);
+ enc->cur_offset = e - enc->offsets;
+ err = (*fun)(runs, num_runs);
}
else
/* Ack. Too many runs to allocate the temporary RUNS array on the stack.
@@ -107,28 +149,14 @@ store_std_leaf_decode (struct store_enc *enc,
runs[i].start = *e++;
runs[i].length = *e++;
}
- err = (*create)(port, flags, block_size, runs, num_runs, store);
+ enc->cur_offset = e - enc->offsets;
+ err = (*fun) (runs, num_runs);
free (runs);
}
else
err = ENOMEM;
}
- if (err)
- {
- mach_port_deallocate (mach_task_self (), port);
- free (misc);
- if (name)
- free (name);
- }
- else
- {
- (*store)->flags = flags;
- (*store)->name = name;
- (*store)->misc = misc;
- (*store)->misc_len = misc_len;
- }
-
return err;
}
@@ -137,22 +165,39 @@ store_std_leaf_decode (struct store_enc *enc,
0, STORE_STD_CLASSES is used. If nothing else is to be done with ENC, its
contents may then be freed using store_enc_dealloc. */
error_t
-store_decode (struct store_enc *enc, struct store_class *classes,
+store_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
+ const struct store_class *const *cl;
+
if (enc->cur_int >= enc->num_ints)
/* The first int should always be the type. */
return EINVAL;
- if (! classes)
- classes = store_std_classes;
-
- while (classes)
- if (classes->id == enc->ints[enc->cur_int])
- if (classes->decode)
- return (*classes->decode) (enc, classes, store);
- else
- return EOPNOTSUPP;
+ if (enc->ints[enc->cur_int] == STORAGE_NETWORK)
+ /* This is a special case because store classes supporting
+ individual URL types will also use STORAGE_NETWORK,
+ and we want the generic dispatcher to come first. */
+ return store_url_decode (enc, classes, store);
+
+ for (cl = classes ?: __start_store_std_classes;
+ classes ? *cl != 0 : cl < __stop_store_std_classes;
+ ++cl)
+ if ((*cl)->id == enc->ints[enc->cur_int])
+ {
+ if ((*cl)->decode)
+ return (*(*cl)->decode) (enc, classes, store);
+ else
+ return EOPNOTSUPP;
+ }
+
+# pragma weak store_module_decode
+ if (! classes && store_module_decode)
+ {
+ error_t err = store_module_decode (enc, classes, store);
+ if (err != ENOENT)
+ return err;
+ }
return EINVAL;
}
diff --git a/libstore/derive.c b/libstore/derive.c
index 63cf3430..a76fbe1c 100644
--- a/libstore/derive.c
+++ b/libstore/derive.c
@@ -1,9 +1,7 @@
/* Calculation of various derived store fields
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995-97,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,11 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <sys/types.h>
+#include <mach.h>
#include "store.h"
@@ -34,6 +36,7 @@ _store_derive (struct store *store)
/* BLOCK & SIZE */
store->blocks = 0;
+ store->wrap_src = 0;
for (i = 0; i < num_runs; i++)
{
@@ -50,7 +53,7 @@ _store_derive (struct store *store)
to include all iterations. */
{
size_t num_iters = store->end / store->wrap_src;
- off_t last_part_base = num_iters * store->wrap_src;
+ store_offset_t last_part_base = num_iters * store->wrap_src;
store->blocks *= num_iters;
@@ -68,17 +71,17 @@ _store_derive (struct store *store)
store->size = store->end * bsize;
- /* LOG2_BLOCK_SIZE */
store->log2_block_size = 0;
- while ((1 << store->log2_block_size) < bsize)
- store->log2_block_size++;
- if ((1 << store->log2_block_size) != bsize)
- store->log2_block_size = 0;
-
- /* LOG2_BLOCKS_PER_PAGE */
store->log2_blocks_per_page = 0;
- while ((bsize << store->log2_blocks_per_page) < vm_page_size)
- store->log2_blocks_per_page++;
- if ((bsize << store->log2_blocks_per_page) != vm_page_size)
- store->log2_blocks_per_page = 0;
+
+ if (bsize != 0)
+ {
+ while ((1 << store->log2_block_size) < bsize)
+ store->log2_block_size++;
+ assert ((1 << store->log2_block_size) == bsize);
+
+ while ((bsize << store->log2_blocks_per_page) < vm_page_size)
+ store->log2_blocks_per_page++;
+ assert ((bsize << store->log2_blocks_per_page) == vm_page_size);
+ }
}
diff --git a/libstore/device.c b/libstore/device.c
index 9036699f..3a72df48 100644
--- a/libstore/device.c
+++ b/libstore/device.c
@@ -1,9 +1,7 @@
/* Mach device store backend
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <assert.h>
#include <stdio.h>
@@ -28,47 +26,229 @@
#include "store.h"
+static inline error_t
+dev_error (error_t err)
+{
+ /* Give the canonical POSIX error codes,
+ rather than letting the Mach code propagate up. */
+ switch (err)
+ {
+ case D_IO_ERROR: return EIO;
+ case D_WOULD_BLOCK: return EAGAIN;
+ case D_NO_SUCH_DEVICE: return ENXIO;
+ case D_ALREADY_OPEN: return EBUSY;
+ case D_DEVICE_DOWN: return ENXIO; /* ? */
+ case D_INVALID_OPERATION: return EBADF; /* ? */
+ case D_NO_MEMORY: return ENOMEM;
+ default:
+ break;
+ }
+ /* Anything unexpected propagates up where weirdness will get noticed. */
+ return err;
+}
+
static error_t
dev_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
-{
- error_t err = device_read (store->port, 0, addr, amount, (io_buf_ptr_t *)buf, len);
- char rep_buf[20];
- if (err)
- strcpy (rep_buf, "-");
- else if (*len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf);
- fprintf (stderr, "; dev_read (%ld, %d, %d) [%d] => %s, %s, %d\n",
- addr, index, amount, store->block_size, err ? strerror (err) : "-",
- rep_buf, err ? 0 : *len);
- return err;
+ store_offset_t addr, size_t index, mach_msg_type_number_t amount,
+ void **buf, mach_msg_type_number_t *len)
+{
+ return dev_error (device_read (store->port, 0, addr, amount,
+ (io_buf_ptr_t *)buf, len));
}
static error_t
dev_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
+ store_offset_t addr, size_t index,
+ const void *buf, mach_msg_type_number_t len,
mach_msg_type_number_t *amount)
{
- return device_write (store->port, 0, addr, (io_buf_ptr_t)buf, len, amount);
+ error_t err = dev_error (device_write (store->port, 0, addr,
+ (io_buf_ptr_t)buf, len,
+ (int *) amount));
+ *amount = *(int *) amount; /* stupid device.defs uses int */
+ return err;
+}
+
+static error_t
+dev_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
}
static error_t
-dev_decode (struct store_enc *enc, struct store_class *classes,
+dev_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
return store_std_leaf_decode (enc, _store_device_create, store);
}
-static struct store_class
-dev_class =
+static error_t
+dev_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
{
- STORAGE_DEVICE, "device", dev_read, dev_write,
- store_std_leaf_allocate_encoding, store_std_leaf_encode, dev_decode
+ return dev_error (store_device_open (name, flags, store));
+}
+
+static error_t
+dopen (const char *name, device_t *device, int *mod_flags)
+{
+ device_t dev_master;
+ error_t err = get_privileged_ports (0, &dev_master);
+ if (! err)
+ {
+ if (*mod_flags & STORE_HARD_READONLY)
+ err = device_open (dev_master, D_READ, (char *)name, device);
+ else
+ {
+ err = device_open (dev_master, D_WRITE | D_READ, (char *)name, device);
+ if (err == ED_READ_ONLY)
+ {
+ err = device_open (dev_master, D_READ, (char *)name, device);
+ if (! err)
+ *mod_flags |= STORE_HARD_READONLY;
+ }
+ else if (! err)
+ *mod_flags &= ~STORE_HARD_READONLY;
+ }
+ mach_port_deallocate (mach_task_self (), dev_master);
+ }
+ return err;
+}
+
+static void
+dclose (struct store *store)
+{
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+}
+
+/* Return 0 if STORE's range is enforce by the kernel, otherwise an error. */
+static error_t
+enforced (struct store *store)
+{
+ error_t err;
+ dev_status_data_t sizes;
+ size_t sizes_len = DEV_STATUS_MAX;
+
+ if (store->num_runs != 1 || store->runs[0].start != 0)
+ /* Can't enforce non-contiguous ranges, or one not starting at 0. */
+ return EINVAL;
+ else
+ /* See if the the current (one) range is that the kernel is enforcing. */
+ {
+#ifdef DEV_GET_RECORDS
+ err =
+ device_get_status (store->port, DEV_GET_RECORDS, sizes, &sizes_len);
+
+ if (err && err != D_INVALID_OPERATION)
+ return EINVAL;
+
+ if (!err)
+ {
+ assert (sizes_len == DEV_GET_RECORDS_COUNT);
+
+ if (sizes[DEV_GET_RECORDS_RECORD_SIZE] != store->block_size
+ || (store->runs[0].length !=
+ sizes[DEV_GET_RECORDS_DEVICE_RECORDS]))
+ return EINVAL;
+
+ return 0;
+ }
+ else
+#endif
+ {
+ sizes_len = DEV_STATUS_MAX;
+ err =
+ device_get_status (store->port, DEV_GET_SIZE, sizes, &sizes_len);
+
+ if (err)
+ return EINVAL;
+
+ assert (sizes_len == DEV_GET_SIZE_COUNT);
+
+ if (sizes[DEV_GET_SIZE_RECORD_SIZE] != store->block_size
+ || (store->runs[0].length !=
+ sizes[DEV_GET_SIZE_DEVICE_SIZE] >> store->log2_block_size))
+ return EINVAL;
+
+ return 0;
+ }
+ }
+}
+
+static error_t
+dev_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ if (! ((store->flags | flags) & STORE_INACTIVE))
+ /* Currently active and staying that way, so we must be trying to set the
+ STORE_ENFORCED flag. */
+ {
+ error_t err = enforced (store);
+ if (err)
+ return err;
+ }
+
+ if (flags & STORE_INACTIVE)
+ dclose (store);
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+dev_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ if (!err && (flags & STORE_INACTIVE))
+ err = store->name ? dopen (store->name, &store->port, &store->flags) : ENODEV;
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+static error_t
+dev_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ size_t nruns = store->num_runs;
+
+ if (nruns > 1 || (nruns == 1 && store->runs[0].start != 0))
+ return EOPNOTSUPP;
+ else
+ {
+ /* Note that older Mach drivers (through GNU Mach 1.x) ignore
+ the OFFSET and SIZE parameters. The OSKit-Mach drivers obey
+ them, and so the size we pass must be large enough (or zero
+ only if the size is indeterminable). If using only the newer
+ drivers, we could remove the `start != 0' condition above and
+ support kernel mapping of partial devices. However, since
+ the older drivers silently ignore the OFFSET argument, that
+ would produce scrambled results on old kernels. */
+ error_t err = device_map (store->port, prot,
+ store->runs[0].start,
+ store->runs[0].length,
+ memobj, 0);
+ if (err == ED_INVALID_OPERATION)
+ err = EOPNOTSUPP; /* This device doesn't support paging. */
+ return err;
+ }
+}
+
+const struct store_class
+store_device_class =
+{
+ STORAGE_DEVICE, "device", dev_read, dev_write, dev_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, dev_decode,
+ dev_set_flags, dev_clear_flags, 0, 0, 0, dev_open, 0, dev_map
};
-_STORE_STD_CLASS (dev_class);
+STORE_STD_CLASS (device);
/* Return a new store in STORE referring to the mach device DEVICE. Consumes
the send right DEVICE. */
@@ -76,22 +256,57 @@ error_t
store_device_create (device_t device, int flags, struct store **store)
{
struct store_run run;
- size_t sizes[DEV_GET_SIZE_COUNT], block_size;
- size_t sizes_len = DEV_GET_SIZE_COUNT;
- error_t err = device_get_status (device, DEV_GET_SIZE, sizes, &sizes_len);
+ size_t block_size = 0;
+ dev_status_data_t sizes;
+ size_t sizes_len = DEV_STATUS_MAX;
+ error_t err;
- if (err)
- return err;
+#ifdef DEV_GET_RECORDS
+ err = device_get_status (device, DEV_GET_RECORDS, sizes, &sizes_len);
+ if (! err && sizes_len == DEV_GET_RECORDS_COUNT)
+ {
+ block_size = sizes[DEV_GET_RECORDS_RECORD_SIZE];
- assert (sizes_len == DEV_GET_SIZE_COUNT);
+ if (block_size)
+ {
+ run.start = 0;
+ run.length = sizes[DEV_GET_RECORDS_DEVICE_RECORDS];
+ }
+ }
+ else
+#endif
+ {
+ /* Some Mach devices do not implement device_get_status, but do not
+ return an error. To detect these devices we set the size of the
+ input buffer to something larger than DEV_GET_SIZE_COUNT. If the
+ size of the returned device status is not equal to
+ DEV_GET_SIZE_COUNT, we know that something is wrong. */
+ sizes_len = DEV_STATUS_MAX;
+ err = device_get_status (device, DEV_GET_SIZE, sizes, &sizes_len);
+ if (! err && sizes_len == DEV_GET_SIZE_COUNT)
+ {
+ block_size = sizes[DEV_GET_SIZE_RECORD_SIZE];
- block_size = sizes[DEV_GET_SIZE_RECORD_SIZE];
- run.start = 0;
- run.length = sizes[DEV_GET_SIZE_DEVICE_SIZE] / block_size;
+ if (block_size)
+ {
+ run.start = 0;
+ run.length = sizes[DEV_GET_SIZE_DEVICE_SIZE] / block_size;
+
+ if (run.length * block_size != sizes[DEV_GET_SIZE_DEVICE_SIZE])
+ /* Bogus results (which some mach devices return). */
+ block_size = 0;
+ }
+ }
+ }
flags |= STORE_ENFORCED; /* 'cause it's the whole device. */
- return _store_device_create (device, flags, block_size, &run, 1, store);
+ if (block_size == 0)
+ /* Treat devices that can't do device_get_status as zero-length. */
+ return _store_device_create (device, flags, 0, &run, 0, store);
+ else
+ /* Make a store with one run covering the whole device. */
+ return _store_device_create (device, flags, block_size, &run, 1, store);
}
/* Like store_device_create, but doesn't query the device for information. */
@@ -100,29 +315,28 @@ _store_device_create (device_t device, int flags, size_t block_size,
const struct store_run *runs, size_t num_runs,
struct store **store)
{
- *store =
- _make_store (&dev_class, device, flags, block_size, runs, num_runs, 0);
- return *store ? 0 : ENOMEM;
+ return
+ _store_create (&store_device_class, device, flags, block_size,
+ runs, num_runs, 0, store);
}
/* Open the device NAME, and return the corresponding store in STORE. */
error_t
store_device_open (const char *name, int flags, struct store **store)
{
- device_t dev_master, device;
- int open_flags = ((flags & STORE_HARD_READONLY) ? 0 : D_WRITE) | D_READ;
- error_t err = get_privileged_ports (0, &dev_master);
-
- if (err)
- return err;
-
- err = device_open (dev_master, open_flags, (char *)name, &device);
-
- mach_port_deallocate (mach_task_self (), dev_master);
-
- err = store_device_create (device, flags, store);
- if (err)
- mach_port_deallocate (mach_task_self (), device);
-
+ device_t device;
+ error_t err = dopen (name, &device, &flags);
+ if (! err)
+ {
+ err = store_device_create (device, flags, store);
+ if (! err)
+ {
+ err = store_set_name (*store, name);
+ if (err)
+ store_free (*store);
+ }
+ if (err)
+ mach_port_deallocate (mach_task_self (), device);
+ }
return err;
}
diff --git a/libstore/enc.c b/libstore/enc.c
index 9706dfc9..d5002a0e 100644
--- a/libstore/enc.c
+++ b/libstore/enc.c
@@ -1,9 +1,7 @@
/* Store wire encoding/decoding
- Copyright (C) 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,9 +16,10 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
+#include <sys/mman.h>
#include "store.h"
@@ -62,26 +61,38 @@ store_enc_dealloc (struct store_enc *enc)
}
if (enc->ports != enc->init_ports)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->ports,
- enc->num_ports * sizeof (*enc->ports));
+ munmap ((caddr_t) enc->ports, enc->num_ports * sizeof (*enc->ports));
}
if (enc->ints && enc->num_ints > 0 && enc->ints != enc->init_ints)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->ints,
- enc->num_ints * sizeof (*enc->ints));
+ munmap ((caddr_t) enc->ints, enc->num_ints * sizeof (*enc->ints));
if (enc->offsets && enc->num_offsets > 0
&& enc->offsets != enc->init_offsets)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->offsets,
- enc->num_offsets * sizeof (*enc->offsets));
+ munmap ((caddr_t) enc->offsets, enc->num_offsets * sizeof (*enc->offsets));
if (enc->data && enc->data_len > 0 && enc->data != enc->init_data)
- vm_deallocate (mach_task_self (),
- (vm_address_t)enc->data, enc->data_len);
+ munmap (enc->data, enc->data_len);
/* For good measure... */
bzero (enc, sizeof (*enc));
}
+
+/* Copy out the parameters from ENC into the given variables suitably for
+ returning from a file_get_storage_info rpc, and deallocate ENC. */
+void
+store_enc_return (struct store_enc *enc,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
+{
+ *ports = enc->ports;
+ *num_ports = enc->num_ports;
+ *ints = enc->ints;
+ *num_ints = enc->num_ints;
+ *offsets = enc->offsets;
+ *num_offsets = enc->num_offsets;
+ *data = enc->data;
+ *data_len = enc->data_len;
+}
diff --git a/libstore/encode.c b/libstore/encode.c
index 38490cc0..df27250d 100644
--- a/libstore/encode.c
+++ b/libstore/encode.c
@@ -1,9 +1,7 @@
/* Store wire encoding
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,9 +16,10 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
+#include <sys/mman.h>
#include "store.h"
@@ -32,13 +31,20 @@ store_std_leaf_allocate_encoding (const struct store *store,
{
enc->num_ports++;
enc->num_ints += 6;
- enc->num_offsets += store->num_runs;
+ enc->num_offsets += store->num_runs * 2;
if (store->name)
enc->data_len += strlen (store->name) + 1;
enc->data_len += store->misc_len;
return 0;
}
+/* The RPC protocol uses 32-bit off_t's, but store_offset_t is now 64 bits. */
+static inline int too_big (store_offset_t ofs)
+{
+ off_t o = (off_t) ofs;
+ return o < 0 || ((store_offset_t) o != ofs);
+}
+
error_t
store_std_leaf_encode (const struct store *store, struct store_enc *enc)
{
@@ -56,6 +62,10 @@ store_std_leaf_encode (const struct store *store, struct store_enc *enc)
for (i = 0; i < store->num_runs; i++)
{
+ if (sizeof (*enc->offsets) != sizeof (store->runs[i].start)
+ && (too_big (store->runs[i].start)
+ || too_big (store->runs[i].start + store->runs[i].length)))
+ return EOVERFLOW;
enc->offsets[enc->cur_offset++] = store->runs[i].start;
enc->offsets[enc->cur_offset++] = store->runs[i].length;
}
@@ -82,8 +92,9 @@ store_std_leaf_encode (const struct store *store, struct store_enc *enc)
error_t
store_encode (const struct store *store, struct store_enc *enc)
{
+ void *buf;
error_t err;
- struct store_class *class = store->class;
+ const struct store_class *class = store->class;
/* We zero each vector length for the allocate_encoding method to work, so
save the old values. */
mach_msg_type_number_t init_num_ports = enc->num_ports;
@@ -102,19 +113,36 @@ store_encode (const struct store *store, struct store_enc *enc)
if (err)
return err;
+ errno = 0;
if (enc->num_ports > init_num_ports)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->ports, enc->num_ports, 1);
- if (!err && enc->num_ints > init_num_ints)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->ints, enc->num_ints, 1);
- if (!err && enc->num_offsets > init_num_offsets)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->offsets, enc->num_offsets, 1);
- if (!err && enc->data_len > init_data_len)
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&enc->data, enc->data_len, 1);
+ {
+ buf = mmap (0, enc->num_ports * sizeof *enc->ports,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->ports = buf;
+ }
+ if (!errno && enc->num_ints > init_num_ints)
+ {
+ buf = mmap (0, enc->num_ints * sizeof *enc->ints,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->ints = buf;
+ }
+ if (!errno && enc->num_offsets > init_num_offsets)
+ {
+ buf = mmap (0, enc->num_offsets * sizeof *enc->offsets,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->offsets = buf;
+ }
+ if (!errno && enc->data_len > init_data_len)
+ {
+ buf = mmap (0, enc->data_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (buf != (void *) -1)
+ enc->data = buf;
+ }
+ err = errno;
if (! err)
err = (*class->encode) (store, enc);
@@ -125,3 +153,26 @@ store_encode (const struct store *store, struct store_enc *enc)
return err;
}
+
+/* Encode STORE into the given return variables, suitably for returning from a
+ file_get_storage_info rpc. */
+error_t
+store_return (const struct store *store,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
+{
+ error_t err;
+ struct store_enc enc;
+
+ store_enc_init (&enc, *ports, *num_ports, *ints, *num_ints,
+ *offsets, *num_offsets, *data, *data_len);
+ err = store_encode (store, &enc);
+ if (err)
+ store_enc_dealloc (&enc);
+ else
+ store_enc_return (&enc, ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+ return err;
+}
diff --git a/libstore/file.c b/libstore/file.c
index 44cb7b9d..49f1c3fb 100644
--- a/libstore/file.c
+++ b/libstore/file.c
@@ -1,9 +1,7 @@
-/* Mach file store backend
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+/* File store backend
+ Copyright (C) 1995,96,97,98,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <stdio.h>
#include <string.h>
@@ -29,94 +27,225 @@
#include "store.h"
+/* Return 0 if STORE's range is enforced by the filesystem, otherwise an
+ error. */
+static error_t
+enforced (struct store *store)
+{
+ if (store->num_runs != 1 || store->runs[0].start != 0)
+ /* Can't enforce non-contiguous ranges, or one not starting at 0. */
+ return EINVAL;
+ else
+ {
+ /* See if the the current (one) range is that the kernel is enforcing. */
+ struct stat st;
+ error_t err = io_stat (store->port, &st);
+
+ if (!err
+ && store->runs[0].length != (st.st_size >> store->log2_block_size))
+ /* The single run is not the whole file. */
+ err = EINVAL;
+
+ return err;
+ }
+}
+
static error_t
file_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
+ store_offset_t addr, size_t index, size_t amount, void **buf,
+ size_t *len)
{
size_t bsize = store->block_size;
- error_t err = io_read (store->port, buf, len, addr * bsize, amount);
- char rep_buf[20];
- if (err)
- strcpy (rep_buf, "-");
- else if (*len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf);
- fprintf (stderr, "; file_read (%ld, %d, %d) [%d] => %s, %s, %d\n",
- addr, index, amount, store->block_size, err ? strerror (err) : "-",
- rep_buf, err ? 0 : *len);
- return err;
+ return io_read (store->port, (char **)buf, len, addr * bsize, amount);
}
static error_t
file_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
{
size_t bsize = store->block_size;
- char rep_buf[20];
- if (len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), buf);
- fprintf (stderr, "; file_write (%ld, %d, %s, %d)\n",
- addr, index, rep_buf, len);
return io_write (store->port, buf, len, addr * bsize, amount);
}
static error_t
-file_decode (struct store_enc *enc, struct store_class *classes,
+file_store_set_size (struct store *store, size_t newsize)
+{
+ error_t err;
+
+ if (enforced (store) != 0)
+ /* Bail out if there is more than a single run. */
+ return EOPNOTSUPP;
+
+ err = file_set_size (store->port, newsize);
+
+ if (!err)
+ {
+ /* Update STORE's size and run. */
+ store->size = newsize;
+ store->runs[0].length = newsize >> store->log2_block_size;
+ }
+
+ return err;
+}
+
+static error_t
+file_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
return store_std_leaf_decode (enc, _store_file_create, store);
}
-static struct store_class
-file_class =
+static error_t
+file_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
{
- STORAGE_HURD_FILE, "file", file_read, file_write,
- store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode
-};
-_STORE_STD_CLASS (file_class);
+ return store_file_open (name, flags, store);
+}
static error_t
-file_byte_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
+fiopen (const char *name, file_t *file, int *mod_flags)
+{
+ if (*mod_flags & STORE_HARD_READONLY)
+ *file = file_name_lookup (name, O_RDONLY, 0);
+ else
+ {
+ *file = file_name_lookup (name, O_RDWR, 0);
+ if (*file == MACH_PORT_NULL
+ && (errno == EACCES || errno == EROFS))
+ {
+ *file = file_name_lookup (name, O_RDONLY, 0);
+ if (*file != MACH_PORT_NULL)
+ *mod_flags |= STORE_HARD_READONLY;
+ }
+ else if (*file != MACH_PORT_NULL)
+ *mod_flags &= ~STORE_HARD_READONLY;
+ }
+ return *file == MACH_PORT_NULL ? errno : 0;
+}
+
+static void
+ficlose (struct store *store)
+{
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+}
+
+
+
+static error_t
+file_set_flags (struct store *store, int flags)
{
- error_t err = io_read (store->port, buf, len, addr, amount);
- char rep_buf[20];
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ if (! ((store->flags | flags) & STORE_INACTIVE))
+ /* Currently active and staying that way, so we must be trying to set the
+ STORE_ENFORCED flag. */
+ {
+ error_t err = enforced (store);
+ if (err)
+ return err;
+ }
+
+ if (flags & STORE_INACTIVE)
+ ficlose (store);
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+file_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ if (!err && (flags & STORE_INACTIVE))
+ err = store->name
+ ? fiopen (store->name, &store->port, &store->flags)
+ : ENOENT;
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+static error_t
+file_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ error_t err;
+ mach_port_t rd_memobj, wr_memobj;
+ int ro = (store->flags & STORE_HARD_READONLY);
+
+ if (store->num_runs != 1 || store->runs[0].start != 0)
+ return EOPNOTSUPP;
+
+ if ((prot & VM_PROT_WRITE) && ro)
+ return EACCES;
+
+ err = io_map (store->port, &rd_memobj, &wr_memobj);
if (err)
- strcpy (rep_buf, "-");
- else if (*len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), *buf);
+ return err;
+
+ *memobj = rd_memobj;
+
+ if (ro && wr_memobj == MACH_PORT_NULL)
+ return 0;
+ else if (rd_memobj == wr_memobj)
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), rd_memobj,
+ MACH_PORT_RIGHT_SEND, -1);
+ }
else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), *buf);
- fprintf (stderr, "; file_byte_read (%ld, %d, %d) => %s, %s, %d\n",
- addr, index, amount, err ? strerror (err) : "-",
- rep_buf, err ? 0 : *len);
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), rd_memobj);
+ if (wr_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), wr_memobj);
+ err = EOPNOTSUPP;
+ }
+
return err;
}
+const struct store_class
+store_file_class =
+{
+ STORAGE_HURD_FILE, "file", file_read, file_write, file_store_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode,
+ file_set_flags, file_clear_flags, 0, 0, 0, file_open, 0, file_map
+};
+STORE_STD_CLASS (file);
+
+static error_t
+file_byte_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ return io_read (store->port, (char **)buf, len, addr, amount);
+}
+
static error_t
file_byte_write (struct store *store,
- off_t addr, size_t index,
- char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len,
+ size_t *amount)
{
- char rep_buf[20];
- if (len > sizeof rep_buf - 3)
- sprintf (rep_buf, "\"%.*s\"...", (int)(sizeof rep_buf - 6), buf);
- else
- sprintf (rep_buf, "\"%.*s\"", (int)(sizeof rep_buf - 3), buf);
- fprintf (stderr, "; file_byte_write (%ld, %d, %s, %d)\n",
- addr, index, rep_buf, len);
return io_write (store->port, buf, len, addr, amount);
}
-static struct store_class
-file_byte_class = {STORAGE_HURD_FILE, "file", file_byte_read, file_byte_write};
+struct store_class
+store_file_byte_class =
+{
+ STORAGE_HURD_FILE, "file", file_byte_read, file_byte_write,
+ file_store_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, file_decode,
+ file_set_flags, file_clear_flags, 0, 0, 0, file_open, 0, file_map
+};
/* Return a new store in STORE referring to the mach file FILE. Consumes
the send right FILE. */
@@ -145,29 +274,30 @@ _store_file_create (file_t file, int flags, size_t block_size,
struct store **store)
{
if (block_size == 1)
- *store = _make_store (&file_byte_class, file, flags, 1, runs, num_runs, 0);
- else if ((block_size & (block_size - 1)) == 0)
- *store =
- _make_store (&file_class, file, flags, block_size, runs, num_runs, 0);
+ return _store_create (&store_file_byte_class,
+ file, flags, 1, runs, num_runs, 0, store);
else
- return EINVAL; /* block size not a power of two */
- return *store ? 0 : ENOMEM;
+ return _store_create (&store_file_class,
+ file, flags, block_size, runs, num_runs, 0, store);
}
/* Open the file NAME, and return the corresponding store in STORE. */
error_t
store_file_open (const char *name, int flags, struct store **store)
{
- error_t err;
- int open_flags = (flags & STORE_HARD_READONLY) ? O_RDONLY : O_RDWR;
- file_t node = file_name_lookup (name, open_flags, 0);
-
- if (node == MACH_PORT_NULL)
- return errno;
-
- err = store_file_create (node, flags, store);
- if (err)
- mach_port_deallocate (mach_task_self (), node);
-
+ file_t file;
+ error_t err = fiopen (name, &file, &flags);
+ if (! err)
+ {
+ err = store_file_create (file, flags, store);
+ if (! err)
+ {
+ err = store_set_name (*store, name);
+ if (err)
+ store_free (*store);
+ }
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ }
return err;
}
diff --git a/libstore/flags.c b/libstore/flags.c
index 5d2ce74b..d80181ac 100644
--- a/libstore/flags.c
+++ b/libstore/flags.c
@@ -1,9 +1,7 @@
/* Setting various store flags
- Copyright (C) 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <malloc.h>
#include <string.h>
@@ -33,10 +31,12 @@ store_set_flags (struct store *store, int flags)
int orig = store->flags, new = flags & ~orig;
if (new & STORE_BACKEND_FLAGS)
- if (store->class->set_flags)
- err = (*store->class->set_flags) (store, new);
- else
- err = EINVAL;
+ {
+ if (store->class->set_flags)
+ err = (*store->class->set_flags) (store, new);
+ else
+ err = EINVAL;
+ }
if (! err)
store->flags |= (new & ~STORE_BACKEND_FLAGS);
@@ -52,10 +52,12 @@ store_clear_flags (struct store *store, int flags)
int orig = store->flags, kill = flags & orig;
if (kill & STORE_BACKEND_FLAGS)
- if (store->class->clear_flags)
- err = (*store->class->clear_flags) (store, kill);
- else
- err = EINVAL;
+ {
+ if (store->class->clear_flags)
+ err = (*store->class->clear_flags) (store, kill);
+ else
+ err = EINVAL;
+ }
if (! err)
store->flags &= ~(kill & ~STORE_BACKEND_FLAGS);
diff --git a/libstore/gunzip.c b/libstore/gunzip.c
new file mode 100644
index 00000000..3bff6ead
--- /dev/null
+++ b/libstore/gunzip.c
@@ -0,0 +1,55 @@
+/* Decompressing store backend
+
+ Copyright (C) 1997, 1999, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cthreads.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+/* gzip.h makes several annoying defines & decls, which we have to work
+ around. */
+#define file_t gzip_file_t
+#include "gzip.h"
+#undef file_t
+#undef head
+
+static error_t
+DO_UNZIP (void)
+{
+ /* Entry points to unzip engine. */
+ int get_method (int);
+ extern long int bytes_out;
+
+ if (get_method (0) != 0)
+ /* Not a happy gzip file. */
+ return EINVAL;
+
+ /* Matched gzip magic number. Ready to unzip.
+ Set up the output stream and let 'er rip. */
+ bytes_out = 0;
+ unzip (17, 23); /* Arguments ignored. */
+ return 0;
+}
+
+#define UNZIP gunzip
+#include "unzipstore.c"
diff --git a/libstore/kids.c b/libstore/kids.c
index 7c6cf51d..901a7f85 100644
--- a/libstore/kids.c
+++ b/libstore/kids.c
@@ -1,8 +1,7 @@
/* Managing sub-stores
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -18,19 +17,21 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
#include "store.h"
/* Set STORE's current children list to (a copy of) CHILDREN and NUM_CHILDREN. */
error_t
store_set_children (struct store *store,
- struct store *const *children, unsigned num_children)
+ struct store *const *children, size_t num_children)
{
- unsigned size = num_children * sizeof (struct store_run);
+ unsigned size = num_children * sizeof (struct store *);
struct store **copy = malloc (size);
if (!copy)
@@ -39,13 +40,13 @@ store_set_children (struct store *store,
if (store->children)
free (store->children);
- bcopy (children, copy, size);
+ memcpy (copy, children, size);
store->children = copy;
store->num_children = num_children;
return 0;
}
-
+
/* Calls the allocate_encoding method in each child store of STORE,
propagating any errors. If any child does not hae such a method,
EOPNOTSUPP is returned. */
@@ -59,7 +60,7 @@ store_allocate_child_encodings (const struct store *store,
{
struct store *k = store->children[i];
if (k->class->allocate_encoding)
- (*k->class->allocate_encoding) (store, enc);
+ (*k->class->allocate_encoding) (k, enc);
else
err = EOPNOTSUPP;
}
@@ -77,7 +78,7 @@ store_encode_children (const struct store *store, struct store_enc *enc)
{
struct store *k = store->children[i];
if (k->class->encode)
- (*k->class->encode) (store, enc);
+ (*k->class->encode) (k, enc);
else
err = EOPNOTSUPP;
}
@@ -88,7 +89,8 @@ store_encode_children (const struct store *store, struct store_enc *enc)
positions in CHILDREN. */
error_t
store_decode_children (struct store_enc *enc, int num_children,
- struct store_class *classes, struct store **children)
+ const struct store_class *const *classes,
+ struct store **children)
{
int i;
error_t err = 0;
@@ -100,3 +102,211 @@ store_decode_children (struct store_enc *enc, int num_children,
store_free (children[i]);
return err;
}
+
+/* Set FLAGS in all children of STORE, and if successful, add FLAGS to
+ STORE's flags. */
+error_t
+store_set_child_flags (struct store *store, int flags)
+{
+ int i;
+ error_t err = 0;
+ int old_child_flags[store->num_children];
+
+ for (i = 0; i < store->num_children && !err; i++)
+ {
+ old_child_flags[i] = store->children[i]->flags;
+ err = store_set_flags (store->children[i], flags);
+ }
+
+ if (err)
+ while (i-- > 0)
+ store_clear_flags (store->children[i], flags & ~old_child_flags[i]);
+ else
+ store->flags |= flags;
+
+ return err;
+}
+
+/* Clear FLAGS in all children of STORE, and if successful, remove FLAGS from
+ STORE's flags. */
+error_t
+store_clear_child_flags (struct store *store, int flags)
+{
+ int i;
+ error_t err = 0;
+ int old_child_flags[store->num_children];
+
+ for (i = 0; i < store->num_children && !err; i++)
+ {
+ old_child_flags[i] = store->children[i]->flags;
+ err = store_clear_flags (store->children[i], flags);
+ }
+
+ if (err)
+ while (i-- > 0)
+ store_set_flags (store->children[i], flags & ~old_child_flags[i]);
+ else
+ store->flags &= ~flags;
+
+ return err;
+}
+
+/* Parse multiple store names in NAME, and open each individually, returning
+ all in the vector STORES, and the number in NUM_STORES. The syntax of
+ NAME is a single non-alpha-numeric separator character, followed by each
+ child store name separated by the same separator; each child name is
+ TYPE:NAME notation as parsed by store_typed_open. If every child uses the
+ same TYPE: prefix, then it may be factored out and put before the child
+ list instead (the two types of notation are differentiated by whether the
+ first character of name is alpha-numeric or not). */
+error_t
+store_open_children (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store ***stores, size_t *num_stores)
+{
+ char *pfx = 0; /* Prefix applied to each part name. */
+ size_t pfx_len = 0; /* Space PFX + separator takes up. */
+ char sep = *name; /* Character separating individual names. */
+
+ if (sep && isalnum (sep))
+ /* If the first character is a `name' character, it's likely to be either
+ a type prefix (e.g, TYPE:@NAME1@NAME2@), so we distribute the type
+ prefix among the elements (@TYPE:NAME1@TYPE:NAME2@). */
+ {
+ const char *pfx_end = name;
+
+ while (isalnum (*pfx_end))
+ pfx_end++;
+
+ if (*pfx_end++ != ':')
+ return EINVAL;
+
+ /* Make a copy of the prefix. */
+ pfx = strndupa (name, pfx_end - name);
+ pfx_len = pfx_end - name;
+
+ sep = *pfx_end;
+ }
+
+ if (sep)
+ /* Parse a list of store specs separated by SEP. */
+ {
+ int k;
+ const char *p, *end;
+ error_t err = 0;
+ size_t count = 0;
+
+ /* First, see how many there are. */
+ for (p = name; p && p[1]; p = strchr (p + 1, sep))
+ count++;
+
+ /* Make a vector to hold them. */
+ *stores = malloc (count * sizeof (struct store *));
+ *num_stores = count;
+ if (! *stores)
+ return ENOMEM;
+
+ bzero (*stores, count * sizeof (struct store *));
+
+ /* Open each child store. */
+ for (p = name, k = 0; !err && p && p[1]; p = end, k++)
+ {
+ size_t kname_len;
+
+ end = strchr (p + 1, sep);
+ kname_len = (end ? end - p - 1 : strlen (p + 1));
+
+ {
+ /* Allocate temporary child name on the stack. */
+ char kname[pfx_len + kname_len + 1];
+
+ if (pfx)
+ /* Add type prefix to child name. */
+ memcpy (kname, pfx, pfx_len);
+
+ memcpy (kname + pfx_len, p + 1, kname_len);
+ kname[pfx_len + kname_len] = '\0';
+
+ err = store_typed_open (kname, flags, classes, &(*stores)[k]);
+ }
+ }
+
+ if (err)
+ /* Failure opening some child, deallocate what we've done so far. */
+ {
+ while (--k >= 0)
+ store_free ((*stores)[k]);
+ free (*stores);
+ }
+
+ return err;
+ }
+ else
+ /* Empty list. */
+ {
+ *stores = 0;
+ *num_stores = 0;
+ return 0;
+ }
+}
+
+/* Try to come up with a name for the children in STORE, combining the names
+ of each child in a way that could be used to parse them with
+ store_open_children. This is done heuristically, and so may not succeed.
+ If a child doesn't have a name, EINVAL is returned. */
+error_t
+store_children_name (const struct store *store, char **name)
+{
+ static char try_seps[] = "@+=,._%|;^!~'&";
+ struct store **kids = store->children;
+ size_t num_kids = store->num_children;
+
+ if (num_kids == 0)
+ {
+ *name = strdup ("");
+ return *name ? 0 : ENOMEM;
+ }
+ else
+ {
+ int k;
+ char *s; /* Current separator in search for one. */
+ int fail; /* If we couldn't use *S as as sep. */
+ size_t total_len = 0; /* Length of name we will return. */
+
+ /* Detect children without names, and calculate the total length of the
+ name we will return (which is the sum of the lengths of the child
+ names plus room for the types and separator characters. */
+ for (k = 0; k < num_kids; k++)
+ if (!kids[k] || !kids[k]->name)
+ return EINVAL;
+ else
+ total_len +=
+ /* separator + type name + type separator + child name */
+ 1 + strlen (kids[k]->class->name) + 1 + strlen (kids[k]->name);
+
+ /* Look for a separator character from those in TRY_SEPS that doesn't
+ occur in any of the the child names. */
+ for (s = try_seps, fail = 1; *s && fail; s++)
+ for (k = 0, fail = 0; k < num_kids && !fail; k++)
+ if (strchr (kids[k]->name, *s))
+ fail = 1;
+
+ if (*s)
+ /* We found a usable separator! */
+ {
+ char *p = malloc (total_len + 1);
+
+ if (! p)
+ return ENOMEM;
+ *name = p;
+
+ for (k = 0; k < num_kids; k++)
+ p +=
+ sprintf (p, "%c%s:%s", *s, kids[k]->class->name, kids[k]->name);
+
+ return 0;
+ }
+ else
+ return EGRATUITOUS;
+ }
+}
diff --git a/libstore/make.c b/libstore/make.c
index 6f5e557a..8f289533 100644
--- a/libstore/make.c
+++ b/libstore/make.c
@@ -1,9 +1,7 @@
/* Store allocation/deallocation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
-
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <malloc.h>
@@ -26,42 +24,54 @@
/* Allocate a new store structure with meths METHS, and the various other
fields initialized to the given parameters. */
-struct store *
-_make_store (struct store_class *class,
- mach_port_t port, int flags, size_t block_size,
- const struct store_run *runs, size_t num_runs, off_t end)
+error_t
+_store_create (const struct store_class *class,
+ mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ store_offset_t end, struct store **store)
{
- if (block_size & (block_size - 1))
- return 0; /* block size not a power of two. */
+ if ((block_size & (block_size - 1)) || (block_size == 0 && num_runs > 0))
+ return EINVAL; /* block size not a power of two. */
else
{
- struct store *store = malloc (sizeof (struct store));
- if (store)
+ struct store *new = malloc (sizeof (struct store));
+ if (new)
{
- store->name = 0;
- store->port = port;
- store->runs = 0;
- store->num_runs = 0;
- store->wrap_src = 0;
- store->wrap_dst = 0;
- store->flags = flags;
- store->end = end;
- store->block_size = block_size;
- store->source = MACH_PORT_NULL;
- store->blocks = 0;
- store->size = 0;
- store->log2_block_size = 0;
- store->log2_blocks_per_page = 0;
- store->misc = 0;
- store->hook = 0;
- store->children = 0;
- store->num_children = 0;
-
- store->class = class;
-
- store_set_runs (store, runs, num_runs); /* Calls _store_derive() */
+ error_t err;
+
+ new->name = 0;
+ new->port = port;
+ new->runs = 0;
+ new->num_runs = 0;
+ new->wrap_src = 0;
+ new->wrap_dst = 0;
+ new->flags = flags;
+ new->end = end;
+ new->block_size = block_size;
+ new->source = MACH_PORT_NULL;
+ new->blocks = 0;
+ new->size = 0;
+ new->log2_block_size = 0;
+ new->log2_blocks_per_page = 0;
+ new->misc = 0;
+ new->misc_len = 0;
+ new->hook = 0;
+ new->children = 0;
+ new->num_children = 0;
+
+ new->class = class;
+
+ /* store_set_runs calls _store_derive to derive other fields. */
+ err = store_set_runs (new, runs, num_runs);
+ if (err)
+ free (new);
+ else
+ *store = new;
+
+ return err;
}
- return store;
+ else
+ return ENOMEM;
}
}
diff --git a/libstore/map.c b/libstore/map.c
new file mode 100644
index 00000000..b7533cbb
--- /dev/null
+++ b/libstore/map.c
@@ -0,0 +1,79 @@
+/* Direct store mapping
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd.h>
+#include <hurd/io.h>
+
+#include "store.h"
+
+/* Return a memory object paging on STORE. [among other reasons,] this may
+ fail because store contains non-contiguous regions on the underlying
+ object. In such a case you can try calling some of the routines below to
+ get a pager. */
+error_t
+store_map (const struct store *store, vm_prot_t prot,
+ mach_port_t *memobj)
+{
+ error_t (*map) (const struct store *store, vm_prot_t prot,
+ mach_port_t *memobj) =
+ store->class->map;
+ error_t err = map ? (*map) (store, prot, memobj) : EOPNOTSUPP;
+
+ if (err == EOPNOTSUPP && store->source != MACH_PORT_NULL)
+ /* Can't map the store directly, but we know it represents the file
+ STORE->source, so we can try mapping that instead. */
+ {
+ mach_port_t rd_memobj, wr_memobj;
+ int ro = (store->flags & STORE_HARD_READONLY);
+
+ if ((prot & VM_PROT_WRITE) && ro)
+ return EACCES;
+
+ err = io_map (store->port, &rd_memobj, &wr_memobj);
+ if (! err)
+ {
+ *memobj = rd_memobj;
+
+ if (!ro || wr_memobj != MACH_PORT_NULL)
+ /* If either we or the server think this object is writable, then
+ the write-memory-object must be the same as the read one (if
+ we only care about reading, then it can be null too). */
+ {
+ if (rd_memobj == wr_memobj)
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), rd_memobj,
+ MACH_PORT_RIGHT_SEND, -1);
+ }
+ else
+ {
+ if (rd_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), rd_memobj);
+ if (wr_memobj != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), wr_memobj);
+ err = EOPNOTSUPP;
+ }
+ }
+ }
+ }
+
+ return err;
+}
diff --git a/libstore/memobj.c b/libstore/memobj.c
new file mode 100644
index 00000000..0d5c816e
--- /dev/null
+++ b/libstore/memobj.c
@@ -0,0 +1,197 @@
+/* Store backend using a Mach memory object
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "store.h"
+#include <hurd.h>
+#include <hurd/sigpreempt.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <assert.h>
+
+
+/* Return a new store in STORE referring to the memory object MEMOBJ.
+ Consumes the send right MEMOBJ. */
+error_t
+store_memobj_create (memory_object_t memobj, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return _store_create (&store_memobj_class,
+ memobj, flags, block_size, runs, num_runs, 0, store);
+}
+
+
+/* This one is pretty easy. */
+static error_t
+memobj_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ *memobj = store->port;
+ return mach_port_mod_refs (mach_task_self (), *memobj,
+ MACH_PORT_RIGHT_SEND, +1);
+}
+
+
+static error_t /* swiped from libpager's pager_memcpy */
+memobj_memcpy (memory_object_t memobj,
+ vm_offset_t offset, void *other, size_t *size,
+ vm_prot_t prot)
+{
+ vm_address_t window = 0;
+ vm_size_t windowsize = 8 * vm_page_size;
+ size_t to_copy = *size;
+ error_t err;
+
+ error_t copy (struct hurd_signal_preemptor *preemptor)
+ {
+ while (to_copy > 0)
+ {
+ size_t pageoff = offset & (vm_page_size - 1);
+
+ if (window)
+ /* Deallocate the old window. */
+ munmap ((caddr_t) window, windowsize);
+
+ /* Map in and copy a standard-sized window, unless that is
+ more than the total left to be copied. */
+
+ if (windowsize > pageoff + to_copy)
+ windowsize = pageoff + to_copy;
+
+ window = 0;
+ err = vm_map (mach_task_self (), &window, windowsize, 0, 1,
+ memobj, offset - pageoff, 0,
+ prot, prot, VM_INHERIT_NONE);
+ if (err)
+ return 0;
+
+ /* Realign the fault preemptor for the new mapping window. */
+ preemptor->first = window;
+ preemptor->last = window + windowsize;
+
+ if (prot == VM_PROT_READ)
+ memcpy (other, (const void *) window + pageoff,
+ windowsize - pageoff);
+ else
+ memcpy ((void *) window + pageoff, other, windowsize - pageoff);
+
+ offset += windowsize - pageoff;
+ other += windowsize - pageoff;
+ to_copy -= windowsize - pageoff;
+ }
+ return 0;
+ }
+
+ jmp_buf buf;
+ void fault (int signo, long int sigcode, struct sigcontext *scp)
+ {
+ assert (scp->sc_error == EKERN_MEMORY_ERROR);
+ err = EIO;
+ to_copy -= sigcode - window;
+ longjmp (buf, 1);
+ }
+
+ if (to_copy == 0)
+ /* Short-circuit return if nothing to do.
+ ERR would not be initialized by the copy loop in this case. */
+ return 0;
+
+ if (setjmp (buf) == 0)
+ hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),
+ window, window + windowsize,
+ &copy, (sighandler_t) &fault);
+
+ if (window)
+ munmap ((caddr_t) window, windowsize);
+
+ *size -= to_copy;
+
+ return err;
+}
+
+static error_t
+memobj_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ addr <<= store->log2_block_size;
+ if (((size_t) addr & (vm_page_size - 1)) == 0)
+ {
+ *len = amount;
+ return vm_map (mach_task_self (), (vm_address_t *) buf, amount,
+ 0, 1, store->port, addr << store->log2_block_size, 0,
+ VM_PROT_READ, VM_PROT_ALL, VM_INHERIT_NONE);
+ }
+ else
+ {
+ error_t err;
+ int alloced = 0;
+ if (*len < amount)
+ {
+ *buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == MAP_FAILED)
+ return errno;
+ alloced = 1;
+ }
+ *len = amount;
+ err = memobj_memcpy (store->port, addr, *buf, len, VM_PROT_READ);
+ if (err && alloced)
+ munmap (*buf, amount);
+ else if (alloced && round_page (*len) < round_page (amount))
+ munmap (*buf + round_page (*len),
+ round_page (amount) - round_page (*len));
+ return err;
+ }
+}
+
+static error_t
+memobj_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ *amount = len;
+ return memobj_memcpy (store->port, addr << store->log2_block_size,
+ (void *) buf, amount, VM_PROT_WRITE);
+}
+
+static error_t
+memobj_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+memobj_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_std_leaf_decode (enc, store_memobj_create, store);
+}
+
+const struct store_class
+store_memobj_class =
+{
+ STORAGE_MEMORY, "memobj",
+ map: memobj_map,
+ read: memobj_read,
+ set_size: memobj_set_size,
+ write: memobj_write,
+ allocate_encoding: store_std_leaf_allocate_encoding,
+ encode: store_std_leaf_encode,
+ decode: memobj_decode,
+};
+STORE_STD_CLASS (memobj);
diff --git a/libstore/module.c b/libstore/module.c
new file mode 100644
index 00000000..6e75099a
--- /dev/null
+++ b/libstore/module.c
@@ -0,0 +1,178 @@
+/* Dynamic loading of store class modules
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "store.h"
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h> /* XXX */
+
+static error_t
+open_class (int need_open,
+ const char *name, const char *clname_end,
+ const struct store_class **classp)
+{
+ char *modname, *clsym;
+ void *mod;
+
+ /* Construct the name of the shared object for this module. */
+ if (asprintf (&modname,
+ "libstore_%.*s%s", (int) (clname_end - name), name,
+ STORE_SONAME_SUFFIX) < 0)
+ return ENOMEM;
+
+ /* Now try to load the module.
+
+ Note we never dlclose the module, and add a ref every time we open it
+ anew. We can't dlclose it until no stores of this class exist, so
+ we'd need a creation/deletion hook for that. */
+
+ errno = 0;
+ mod = dlopen (modname, RTLD_LAZY);
+ if (mod == NULL)
+ {
+ const char *errstring = dlerror (); /* Must always call or it leaks! */
+ if (errno != ENOENT)
+ /* XXX not good, but how else to report the error? */
+ error (0, 0, "cannot load %s: %s", modname, errstring);
+ }
+ free (modname);
+ if (mod == NULL)
+ return errno ?: ENOENT;
+
+ if (asprintf (&clsym, "store_%.*s_class",
+ (int) (clname_end - name), name) < 0)
+ {
+ dlclose (mod);
+ return ENOMEM;
+ }
+
+ *classp = dlsym (mod, clsym);
+ free (clsym);
+ if (*classp == NULL)
+ {
+ error (0, 0, "invalid store module %.*s: %s",
+ (int) (clname_end - name), name, dlerror ());
+ dlclose (mod);
+ return EGRATUITOUS;
+ }
+
+ if (need_open && ! (*classp)->open)
+ {
+ /* This class cannot be opened as needed. */
+ dlclose (mod);
+ return EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+error_t
+store_module_find_class (const char *name, const char *clname_end,
+ const struct store_class **classp)
+{
+ return open_class (0, name, clname_end, classp);
+}
+
+error_t
+store_module_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ const struct store_class *cl;
+ const char *clname_end = strchrnul (name, ':');
+ error_t err;
+
+ err = open_class (1, name, clname_end, &cl);
+ if (err)
+ return err;
+
+ if (*clname_end)
+ /* Skip the ':' separating the class-name from the device name. */
+ clname_end++;
+
+ if (! *clname_end)
+ /* The class-specific portion of the name is empty, so make it *really*
+ empty. */
+ clname_end = 0;
+
+ return (*cl->open) (clname_end, flags, classes, store);
+}
+
+const struct store_class store_module_open_class =
+{ -1, "module", open: store_module_open };
+STORE_STD_CLASS (module_open);
+
+error_t
+store_module_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ char *modname;
+ void *mod;
+ const struct store_class *const *cl, *const *clend;
+ enum file_storage_class id;
+
+ if (enc->cur_int >= enc->num_ints)
+ /* The first int should always be the type. */
+ return EINVAL;
+
+ id = enc->ints[enc->cur_int];
+
+ /* Construct the name of the shared object for this module. */
+ if (asprintf (&modname, "libstore_type-%d%s", id, STORE_SONAME_SUFFIX) < 0)
+ return ENOMEM;
+
+ /* Try to open the module. */
+ mod = dlopen (modname, RTLD_LAZY);
+ free (modname);
+ if (mod == NULL)
+ {
+ (void) dlerror (); /* otherwise it leaks */
+ return ENOENT;
+ }
+
+ /* Now find its "store_std_classes" section, which points to each
+ `struct store_class' defined in this module. */
+ cl = dlsym (mod, "__start_store_std_classes");
+ if (cl == NULL)
+ {
+ error (0, 0, "invalid store module type-%d: %s", id, dlerror ());
+ dlclose (mod);
+ return EGRATUITOUS;
+ }
+ clend = dlsym (mod, "__stop_store_std_classes");
+ if (clend == NULL)
+ {
+ error (0, 0, "invalid store module type-%d: %s", id, dlerror ());
+ dlclose (mod);
+ return EGRATUITOUS;
+ }
+
+ while (cl < clend)
+ if ((*cl)->decode && (*cl)->id == id)
+ return (*(*cl)->decode) (enc, classes, store);
+ else
+ ++cl;
+
+ /* This class cannot be opened via store_decode. */
+ dlclose (mod);
+ return EOPNOTSUPP;
+}
diff --git a/libstore/mvol.c b/libstore/mvol.c
new file mode 100644
index 00000000..d243cc8a
--- /dev/null
+++ b/libstore/mvol.c
@@ -0,0 +1,158 @@
+/* Multiple-volume store backend
+
+ Copyright (C) 1996,97,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "store.h"
+
+struct mvol_state
+{
+ /* The current `volume'. */
+ ssize_t cur_vol;
+
+ /* A function to change volumes, making NEW_VOL readable on the store
+ instead of OLD_VOL. OLD_VOL is initially -1, */
+ error_t (*swap_vols) (struct store *store, size_t new_vol, ssize_t old_vol);
+};
+
+static error_t
+ensure_vol (struct store *store, size_t vol)
+{
+ error_t err = 0;
+ struct mvol_state *mv = store->hook;
+ if (vol != mv->cur_vol)
+ {
+ err = (*mv->swap_vols) (store, vol, mv->cur_vol);
+ if (! err)
+ mv->cur_vol = vol;
+ }
+ return err;
+}
+
+static error_t
+mvol_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ error_t err = ensure_vol (store, index);
+ if (! err)
+ err = store_read (store->children[0], addr, amount, buf, len);
+ return err;
+}
+
+static error_t
+mvol_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ error_t err = ensure_vol (store, index);
+ if (! err)
+ err = store_write (store->children[0], addr, buf, len, amount);
+ return err;
+}
+
+static error_t
+mvol_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+mvol_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return store_remap_create (source, runs, num_runs, 0, store);
+}
+
+const struct store_class
+store_mvol_class =
+{
+ -1, "mvol", mvol_read, mvol_write, mvol_set_size,
+ 0, 0, 0,
+ store_set_child_flags, store_clear_child_flags, 0, 0, mvol_remap
+};
+STORE_STD_CLASS (mvol);
+
+/* Return a new store in STORE that multiplexes multiple physical volumes
+ from PHYS as one larger virtual volume. SWAP_VOLS is a function that will
+ be called whenever the volume currently active isn't correct. PHYS is
+ consumed. */
+error_t
+store_mvol_create (struct store *phys,
+ error_t (*swap_vols) (struct store *store, size_t new_vol,
+ ssize_t old_vol),
+ int flags,
+ struct store **store)
+{
+ error_t err;
+ struct store_run run;
+
+ run.start = 0;
+ run.length = phys->end;
+
+ err = _store_create (&store_mvol_class, MACH_PORT_NULL,
+ flags | phys->flags, phys->block_size,
+ &run, 1, 0, store);
+ if (! err)
+ {
+ struct mvol_state *mv = malloc (sizeof (struct mvol_state));
+ if (mv)
+ {
+ mv->swap_vols = swap_vols;
+ mv->cur_vol = -1;
+ (*store)->hook = mv;
+ }
+ else
+ err = ENOMEM;
+
+ if (! err)
+ err = store_set_children (*store, &phys, 1);
+
+ if (! err)
+ {
+ if (phys->name)
+ {
+ size_t nlen =
+ strlen (phys->class->name) + 1 + strlen (phys->name) + 1;
+ char *name = malloc (nlen);
+
+ if (name)
+ {
+ snprintf (name, nlen, "%s:%s", phys->class->name, phys->name);
+ (*store)->name = name;
+ }
+ else
+ err = ENOMEM;
+ }
+ }
+
+ if (err)
+ {
+ if (mv)
+ free (mv);
+ store_free (*store);
+ }
+ }
+
+ return err;
+}
diff --git a/libstore/nbd.c b/libstore/nbd.c
new file mode 100644
index 00000000..3138af01
--- /dev/null
+++ b/libstore/nbd.c
@@ -0,0 +1,529 @@
+/* "Network Block Device" store backend compatible with Linux `nbd' driver
+ Copyright (C) 2001, 2002, 2008 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "store.h"
+#include <hurd.h>
+#include <hurd/io.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+// Avoid dragging in the resolver when linking statically.
+#pragma weak gethostbyname
+
+
+/* The nbd protocol, such as it is, is not really specified anywhere.
+ These message layouts and constants were culled from the nbd-server and
+ Linux kernel nbd module sources. */
+
+#define NBD_INIT_MAGIC "NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53"
+
+#define NBD_REQUEST_MAGIC (htonl (0x25609513))
+#define NBD_REPLY_MAGIC (htonl (0x67446698))
+
+#define NBD_IO_MAX 10240
+
+struct nbd_startup
+{
+ char magic[16]; /* NBD_INIT_MAGIC */
+ uint64_t size; /* size in bytes, 64 bits in net order */
+ char reserved[128]; /* zeros, we don't check it */
+};
+
+struct nbd_request
+{
+ uint32_t magic; /* NBD_REQUEST_MAGIC */
+ uint32_t type; /* 0 read, 1 write, 2 disconnect */
+ uint64_t handle; /* returned in reply */
+ uint64_t from;
+ uint32_t len;
+} __attribute__ ((packed));
+
+struct nbd_reply
+{
+ uint32_t magic; /* NBD_REPLY_MAGIC */
+ uint32_t error;
+ uint64_t handle; /* value from request */
+} __attribute__ ((packed));
+
+
+/* i/o functions. */
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define htonll(x) (x)
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# include <byteswap.h>
+# define htonll(x) (bswap_64 (x))
+#else
+# error what endian?
+#endif
+#define ntohll htonll
+
+
+static inline error_t
+read_reply (struct store *store, uint64_t handle)
+{
+ struct nbd_reply reply;
+ char *buf = (void *) &reply;
+ mach_msg_type_number_t cc = sizeof reply;
+ error_t err = io_read (store->port, &buf, &cc, -1, cc);
+ if (err)
+ return err;
+ if (buf != (void *) &reply)
+ {
+ memcpy (&reply, buf, sizeof reply);
+ munmap (buf, cc);
+ }
+ if (cc != sizeof reply)
+ return EIO;
+ if (reply.magic != NBD_REPLY_MAGIC)
+ return EIO;
+ if (reply.handle != handle)
+ return EIO;
+ if (reply.error != 0)
+ return EIO;
+ return 0;
+}
+
+static error_t
+nbd_write (struct store *store,
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
+{
+ struct nbd_request req =
+ {
+ magic: NBD_REQUEST_MAGIC,
+ type: htonl (1), /* WRITE */
+ };
+ error_t err;
+ mach_msg_type_number_t cc;
+
+ addr <<= store->log2_block_size;
+ *amount = 0;
+
+ do
+ {
+ size_t chunk = len < NBD_IO_MAX ? len : NBD_IO_MAX, nwrote;
+ req.from = htonll (addr);
+ req.len = htonl (chunk);
+
+ err = io_write (store->port, (char *) &req, sizeof req, -1, &cc);
+ if (err)
+ return err;
+ if (cc != sizeof req)
+ return EIO;
+
+ nwrote = 0;
+ do
+ {
+ err = io_write (store->port, (char *) buf, chunk - nwrote, -1, &cc);
+ if (err)
+ return err;
+ buf += cc;
+ nwrote += cc;
+ } while (nwrote < chunk);
+
+ err = read_reply (store, req.handle);
+ if (err)
+ return err;
+
+ addr += chunk;
+ *amount += chunk;
+ len -= chunk;
+ } while (len > 0);
+
+ return 0;
+}
+
+static error_t
+nbd_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ struct nbd_request req =
+ {
+ magic: NBD_REQUEST_MAGIC,
+ type: htonl (0), /* READ */
+ };
+ error_t err;
+ size_t ofs, chunk;
+ char *databuf, *piecebuf;
+ size_t databuflen, piecelen;
+
+ /* Send a request for the largest possible piece of remaining data and
+ read the first piece of its reply into PIECEBUF, PIECELEN. The amount
+ requested can be found in CHUNK. */
+ inline error_t request_chunk (char **buf, size_t *len)
+ {
+ mach_msg_type_number_t cc;
+
+ chunk = (amount - ofs) < NBD_IO_MAX ? (amount - ofs) : NBD_IO_MAX;
+
+ req.from = htonll (addr);
+ req.len = htonl (chunk);
+
+ /* Advance ADDR immediately, so it always points past what we've
+ already requested. */
+ addr += chunk;
+
+ return (io_write (store->port, (char *) &req, sizeof req, -1, &cc) ?
+ : cc != sizeof req ? EIO
+ : read_reply (store, req.handle) ?
+ : io_read (store->port, buf, len, (off_t) -1, chunk));
+ }
+
+ addr <<= store->log2_block_size;
+
+ /* Read the first piece, which can go directly into the caller's buffer. */
+ databuf = *buf;
+ piecelen = databuflen = *len;
+ err = request_chunk (&databuf, &piecelen);
+ if (err)
+ return err;
+ if (databuflen >= amount)
+ {
+ /* That got it all. We're done. */
+ *buf = databuf;
+ *len = piecelen;
+ return 0;
+ }
+
+ /* We haven't read the entire amount yet. */
+ ofs = 0;
+ do
+ {
+ /* Account for what we just read. */
+ ofs += piecelen;
+ chunk -= piecelen;
+ if (ofs == amount)
+ {
+ /* That got it all. We're done. */
+ *buf = databuf;
+ *len = ofs;
+ return 0;
+ }
+
+ /* Now we'll read another piece of the data, hopefully
+ into the latter part of the existing buffer. */
+ piecebuf = databuf + ofs;
+ piecelen = databuflen - ofs;
+
+ if (chunk > 0)
+ /* We haven't finishing reading the last chunk we requested. */
+ err = io_read (store->port, &piecebuf, &piecelen,
+ (off_t) -1, chunk);
+ else
+ /* Request the next chunk from the server. */
+ err = request_chunk (&piecebuf, &piecelen);
+
+ if (!err && piecebuf != databuf + ofs)
+ {
+ /* Now we have two discontiguous pieces of the buffer. */
+ size_t newbuflen = round_page (databuflen + piecelen);
+ char *newbuf = mmap (0, newbuflen,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (newbuf == MAP_FAILED)
+ {
+ err = errno;
+ break;
+ }
+ memcpy (newbuf, databuf, ofs);
+ memcpy (newbuf + ofs, piecebuf, piecelen);
+ if (databuf != *buf)
+ munmap (databuf, databuflen);
+ databuf = newbuf;
+ databuflen = newbuflen;
+ }
+ } while (! err);
+
+ if (databuf != *buf)
+ munmap (databuf, databuflen);
+ return err;
+}
+
+static error_t
+nbd_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+
+
+/* Setup hooks. */
+
+static error_t
+nbd_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_std_leaf_decode (enc, _store_nbd_create, store);
+}
+
+static error_t
+nbd_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_nbd_open (name, flags, store);
+}
+
+static const char url_prefix[] = "nbd://";
+
+/* Valid name syntax is [nbd://]HOSTNAME:PORT[/BLOCKSIZE].
+ If "/BLOCKSIZE" is omitted, the block size is 1. */
+static error_t
+nbd_validate_name (const char *name,
+ const struct store_class *const *classes)
+{
+ char *p, *endp;
+
+ if (!strncmp (name, url_prefix, sizeof url_prefix - 1))
+ name += sizeof url_prefix - 1;
+
+ p = strchr (name, ':');
+ if (p == 0)
+ return EINVAL;
+ endp = 0;
+ strtoul (++p, &endp, 0);
+ if (endp == 0 || endp == p)
+ return EINVAL;
+ switch (*endp)
+ {
+ default:
+ return EINVAL;
+ case '\0':
+ break;
+ case '/':
+ p = endp + 1;
+ strtoul (p, &endp, 0);
+ if (endp == 0 || endp == p)
+ return EINVAL;
+ if (*endp != '\0')
+ return EINVAL;
+ }
+ return 0;
+}
+
+static error_t
+nbdopen (const char *name, int *mod_flags,
+ socket_t *sockport, size_t *blocksize, store_offset_t *size)
+{
+ int sock;
+ struct sockaddr_in sin;
+ const struct hostent *he;
+ char **ap;
+ struct nbd_startup ns;
+ ssize_t cc;
+ size_t ofs;
+ unsigned long int port;
+ char *hostname, *p, *endp;
+
+ if (!strncmp (name, url_prefix, sizeof url_prefix - 1))
+ name += sizeof url_prefix - 1;
+
+ /* First we have to parse the store name to get the host name and TCP
+ port number to connect to and the block size to use. */
+
+ hostname = strdupa (name);
+ p = strchr (hostname, ':');
+
+ if (p == 0)
+ return EINVAL;
+ *p++ = '\0';
+ port = strtoul (p, &endp, 0);
+ if (endp == 0 || endp == p || port > 0xffffUL)
+ return EINVAL;
+ switch (*endp)
+ {
+ default:
+ return EINVAL;
+ case '\0':
+ *blocksize = 1;
+ break;
+ case '/':
+ p = endp + 1;
+ *blocksize = strtoul (p, &endp, 0);
+ if (endp == 0 || endp == p)
+ return EINVAL;
+ if (*endp != '\0')
+ return EINVAL;
+ }
+
+ /* Now look up the host name and get a TCP connection. */
+
+ he = gethostbyname (hostname);
+ if (he == 0) /* XXX emit an error message? */
+ return errno; /* XXX what value will this have? */
+
+ sock = socket (PF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ return errno;
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons (port);
+ for (ap = he->h_addr_list; *ap != 0; ++ap)
+ {
+ sin.sin_addr = *(const struct in_addr *) *ap;
+ errno = 0;
+ if (connect (sock, &sin, sizeof sin) == 0 || errno == ECONNREFUSED)
+ break;
+ }
+ if (errno != 0) /* last connect failed */
+ {
+ error_t err = errno;
+ close (sock);
+ return err;
+ }
+
+ /* Read the startup packet, which tells us the size of the store. */
+ ofs = 0;
+ do {
+ cc = read (sock, (char *) &ns + ofs, sizeof ns - ofs);
+ if (cc < 0)
+ {
+ error_t err = errno;
+ close (sock);
+ return err;
+ }
+ ofs += cc;
+ } while (cc > 0 && ofs < sizeof ns);
+
+ if (ofs != sizeof ns
+ || memcmp (ns.magic, NBD_INIT_MAGIC, sizeof ns.magic) != 0)
+ {
+ close (sock);
+ return EGRATUITOUS; /* ? */
+ }
+
+ *size = ntohll (ns.size);
+ *sockport = getdport (sock);
+ close (sock);
+
+ return 0;
+}
+
+static void
+nbdclose (struct store *store)
+{
+ if (store->port != MACH_PORT_NULL)
+ {
+ /* Send a disconnect message, but don't wait for a reply. */
+ struct nbd_request req =
+ {
+ magic: NBD_REQUEST_MAGIC,
+ type: htonl (2), /* disconnect */
+ };
+ mach_msg_type_number_t cc;
+ (void) io_write (store->port, (char *) &req, sizeof req, -1, &cc);
+
+ /* Close the socket. */
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+ }
+}
+
+static error_t
+nbd_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~STORE_INACTIVE) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ nbdclose (store);
+ store->flags |= STORE_INACTIVE;
+
+ return 0;
+}
+
+static error_t
+nbd_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~STORE_INACTIVE) != 0)
+ err = EINVAL;
+ err = store->name
+ ? nbdopen (store->name, &store->flags,
+ &store->port, &store->block_size, &store->size)
+ : ENOENT;
+ if (! err)
+ store->flags &= ~STORE_INACTIVE;
+ return err;
+}
+
+const struct store_class store_nbd_class =
+{
+ STORAGE_NETWORK, "nbd",
+ open: nbd_open,
+ validate_name: nbd_validate_name,
+ read: nbd_read,
+ write: nbd_write,
+ set_size: nbd_set_size,
+ allocate_encoding: store_std_leaf_allocate_encoding,
+ encode: store_std_leaf_encode,
+ decode: nbd_decode,
+ set_flags: nbd_set_flags, clear_flags: nbd_clear_flags,
+};
+STORE_STD_CLASS (nbd);
+
+/* Create a store from an existing socket to an nbd server.
+ The initial handshake has already been done. */
+error_t
+_store_nbd_create (mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return _store_create (&store_nbd_class,
+ port, flags, block_size, runs, num_runs, 0, store);
+}
+
+/* Open a new store backed by the named nbd server. */
+error_t
+store_nbd_open (const char *name, int flags, struct store **store)
+{
+ error_t err;
+ socket_t sock;
+ struct store_run run;
+ size_t blocksize;
+
+ run.start = 0;
+ err = nbdopen (name, &flags, &sock, &blocksize, &run.length);
+ if (!err)
+ {
+ run.length /= blocksize;
+ err = _store_nbd_create (sock, flags, blocksize, &run, 1, store);
+ if (! err)
+ {
+ if (!strncmp (name, url_prefix, sizeof url_prefix - 1))
+ err = store_set_name (*store, name);
+ else
+ asprintf (&(*store)->name, "%s%s", url_prefix, name);
+ if (err)
+ store_free (*store);
+ }
+ if (err)
+ mach_port_deallocate (mach_task_self (), sock);
+ }
+ return err;
+}
diff --git a/libstore/null.c b/libstore/null.c
deleted file mode 100644
index dd30ded1..00000000
--- a/libstore/null.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Null store backend
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "store.h"
-
-static error_t
-null_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
-{
- if (*len < amount)
- {
- error_t err =
- vm_allocate (mach_task_self (), (vm_address_t *)buf, amount, 1);
- if (! err)
- *len = amount;
- return err;
- }
- else
- {
- bzero (*buf, amount);
- *len = amount;
- return 0;
- }
-}
-
-static error_t
-null_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
-{
- return 0;
-}
-
-error_t
-null_allocate_encoding (const struct store *store, struct store_enc *enc)
-{
- enc->num_ints += 2;
- enc->num_offsets += 1;
- return 0;
-}
-
-error_t
-null_encode (const struct store *store, struct store_enc *enc)
-{
- enc->ints[enc->cur_int++] = store->class->id;
- enc->ints[enc->cur_int++] = store->flags;
- enc->offsets[enc->cur_offset++] = store->size;
- return 0;
-}
-
-error_t
-null_decode (struct store_enc *enc, struct store_class *classes,
- struct store **store)
-{
- off_t size;
- int type, flags;
-
- if (enc->cur_int + 2 > enc->num_ints
- || enc->cur_offset + 1 > enc->num_offsets)
- return EINVAL;
-
- type = enc->ints[enc->cur_int++];
- flags = enc->ints[enc->cur_int++];
- size = enc->offsets[enc->cur_offset++];
-
- return store_null_create (size, flags, store);
-}
-
-static struct store_class
-null_class =
-{
- STORAGE_NULL, "null", null_read, null_write,
- null_allocate_encoding, null_encode, null_decode
-};
-_STORE_STD_CLASS (null_class);
-
-/* Return a new null store SIZE bytes long in STORE. */
-error_t
-store_null_create (size_t size, int flags, struct store **store)
-{
- struct store_run run = { 0, size };
- *store = _make_store (&null_class, MACH_PORT_NULL, flags, 1, &run, 1, 0);
- return *store ? 0 : ENOMEM;
-}
diff --git a/libstore/open.c b/libstore/open.c
new file mode 100644
index 00000000..5c00e107
--- /dev/null
+++ b/libstore/open.c
@@ -0,0 +1,65 @@
+/* Store creation from a file name
+
+ Copyright (C) 1996,97,98,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <fcntl.h>
+#include <hurd.h>
+
+#include "store.h"
+
+/* Open the file NAME, and return a new store in STORE, which refers to the
+ storage underlying it. CLASSES is used to select classes specified by the
+ provider; if it is 0, STORE_STD_CLASSES is used. FLAGS is set with
+ store_set_flags. A reference to the open file is created (but may be
+ destroyed with store_close_source). */
+error_t
+store_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ error_t err;
+ int open_flags = (flags & STORE_HARD_READONLY) ? O_RDONLY : O_RDWR;
+ file_t node = file_name_lookup (name, open_flags, 0);
+
+ if (node == MACH_PORT_NULL && !(flags & STORE_HARD_READONLY)
+ && (errno == EACCES || errno == EROFS))
+ {
+ flags |= STORE_HARD_READONLY;
+ node = file_name_lookup (name, O_RDONLY, 0);
+ }
+
+ if (node == MACH_PORT_NULL)
+ return errno;
+
+ err = store_create (node, flags, classes, store);
+ if (err)
+ {
+ if (! (flags & STORE_NO_FILEIO))
+ /* Try making a store that does file io to NODE. */
+ err = store_file_create (node, flags, store);
+ if (err)
+ mach_port_deallocate (mach_task_self (), node);
+ }
+
+ return err;
+}
+
+const struct store_class
+store_query_class = { -1, "query", open: store_open };
+STORE_STD_CLASS (query);
diff --git a/libstore/part.c b/libstore/part.c
new file mode 100644
index 00000000..439340be
--- /dev/null
+++ b/libstore/part.c
@@ -0,0 +1,197 @@
+/* Partition store backend
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ Written by Neal H Walfield <neal@cs.uml.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "store.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <cthreads.h>
+
+#include <parted/parted.h>
+/*#include <parted/device_gnu.h>*/
+#include <string.h>
+#include <error.h>
+
+#define NEED_PARTED_VERSION "1.5.4"
+#ifndef PED_SECTOR_SIZE
+#define PED_SECTOR_SIZE PED_SECTOR_SIZE_DEFAULT
+#endif
+
+/* Return a new store in STORE which contains a remap store of partition
+ PART from the contents of SOURCE; SOURCE is consumed. */
+error_t
+store_part_create (struct store *source, int index, int flags,
+ struct store **store)
+{
+ static struct mutex parted_lock = MUTEX_INITIALIZER;
+ static int version_check;
+ error_t err = 0;
+ PedDevice *dev;
+ PedDisk *disk;
+ PedPartition *part;
+ struct store_run run;
+
+ if ((source->block_size < PED_SECTOR_SIZE
+ && PED_SECTOR_SIZE % source->block_size != 0)
+ || (source->block_size > PED_SECTOR_SIZE
+ && source->block_size % PED_SECTOR_SIZE != 0))
+ return EINVAL;
+
+ mutex_lock (&parted_lock);
+
+ /* Since Parted provides no source-level information about
+ version compatibility, we have to check at run time. */
+ if (version_check == 0)
+ {
+ const char *version = ped_get_version ();
+ version_check = -1;
+ if (version == 0)
+ error (0, 0, "cannot get version of Parted library!");
+ else if (strverscmp (version, NEED_PARTED_VERSION) < 0)
+ error (0, 0, "Parted library version %s older than needed %s",
+ version, NEED_PARTED_VERSION);
+ else
+ version_check = 1;
+ }
+ if (version_check <= 0)
+ {
+ error (0, 0, "the `part' store type is not available");
+ mutex_unlock (&parted_lock);
+ return ENOTSUP;
+ }
+
+ ped_exception_fetch_all ();
+
+ dev = ped_device_new_from_store (source);
+ if (! dev)
+ {
+ ped_exception_catch ();
+ err = EIO;
+ goto out;
+ }
+
+ assert (ped_device_open (dev) != 0);
+
+ disk = ped_disk_new (dev);
+ if (! disk)
+ {
+ ped_exception_catch ();
+ err = EIO;
+ goto out_with_dev;
+ }
+
+ for (part = ped_disk_next_partition (disk, NULL); part;
+ part = ped_disk_next_partition (disk, part))
+ {
+ if (part->type != PED_PARTITION_LOGICAL
+ && part->type != 0 /* PED_PARTITION_PRIMARY */)
+ continue;
+
+ assert (part->num);
+ if (part->num == index)
+ break;
+ }
+
+ if (! part)
+ {
+ err = EIO;
+ goto out_with_disk;
+ }
+
+ if (source->block_size == PED_SECTOR_SIZE)
+ {
+ run.start = part->geom.start;
+ run.length = part->geom.length;
+ }
+ else if (source->block_size < PED_SECTOR_SIZE)
+ {
+ run.start = part->geom.start * (PED_SECTOR_SIZE / source->block_size);
+ run.length = part->geom.length * (PED_SECTOR_SIZE / source->block_size);
+ }
+ else
+ /* source->block_size > PED_SECTOR_SIZE */
+ {
+ run.start = part->geom.start * PED_SECTOR_SIZE;
+ if (run.start % source->block_size != 0)
+ err = EIO;
+ else
+ {
+ run.start /= source->block_size;
+ run.length = part->geom.length * PED_SECTOR_SIZE;
+ if (run.length % source->block_size != 0)
+ err = EIO;
+ else
+ run.length /= source->block_size;
+ }
+ }
+
+out_with_disk:
+ assert (ped_device_close (dev) != 0);
+ ped_disk_destroy (disk);
+out_with_dev:
+ ped_device_destroy (dev);
+out:
+ ped_exception_leave_all ();
+ mutex_unlock (&parted_lock);
+
+ if (! err)
+ err = store_remap (source, &run, 1, store);
+
+ return err;
+}
+
+/* Open the part NAME. NAME consists of a partition number, a ':', a another
+ store class name, a ':' and a name for to by passed to the store class.
+ E.g. "2:device:hd0" would open the second partition on a DEVICE store
+ named "hd0". FLAGS indicate how to open the store. CLASSES is used to
+ select classes specified by the type NAME; if it is 0, STORE_STD_CLASSES
+ is used. The new store is returned in *STORE. */
+error_t
+store_part_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ int part;
+ char *endp;
+ struct store *source;
+ error_t err;
+
+ part = strtol (name, &endp, 0);
+ if (endp == name || *endp != ':')
+ return EINVAL;
+
+ name = endp + 1;
+ if (*name == '\0')
+ return EINVAL;
+
+ err = store_typed_open (name, flags, classes, &source);
+ if (! err)
+ {
+ err = store_part_create (source, part, flags, store);
+ if (err)
+ store_free (source);
+ }
+
+ return err;
+}
+
+const struct store_class
+store_part_class = { -1, "part", open: store_part_open };
+STORE_STD_CLASS (part);
diff --git a/libstore/rdwr.c b/libstore/rdwr.c
index 9e9d3f84..9737c515 100644
--- a/libstore/rdwr.c
+++ b/libstore/rdwr.c
@@ -1,9 +1,7 @@
/* Store I/O
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995-1999,2001,2002,2003 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,9 +16,10 @@
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. */
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <string.h>
+#include <sys/mman.h>
#include "store.h"
@@ -28,13 +27,13 @@
ADDR, and is not a hole, and in RUNS_END a pointer pointing at the end of
the run list. Returns the offset within it at which ADDR occurs. Also
returns BASE, which should be added to offsets from RUNS. */
-static inline off_t
-store_find_first_run (struct store *store, off_t addr,
+static inline store_offset_t
+store_find_first_run (struct store *store, store_offset_t addr,
struct store_run **run, struct store_run **runs_end,
- off_t *base, size_t *index)
+ store_offset_t *base, size_t *index)
{
struct store_run *tail = store->runs, *tail_end = tail + store->num_runs;
- off_t wrap_src = store->wrap_src;
+ store_offset_t wrap_src = store->wrap_src;
if (addr >= wrap_src && addr < store->end)
/* Locate the correct position within a repeating pattern of runs. */
@@ -50,7 +49,7 @@ store_find_first_run (struct store *store, off_t addr,
binary search or something. */
while (tail < tail_end)
{
- off_t run_blocks = tail->length;
+ store_offset_t run_blocks = tail->length;
if (run_blocks > addr)
{
@@ -73,7 +72,7 @@ store_find_first_run (struct store *store, off_t addr,
things are still kosher. */
static inline int
store_next_run (struct store *store, struct store_run *runs_end,
- struct store_run **run, off_t *base, size_t *index)
+ struct store_run **run, store_offset_t *base, size_t *index)
{
(*run)++;
(*index)++;
@@ -94,11 +93,11 @@ store_next_run (struct store *store, struct store_run *runs_end,
in AMOUNT. ADDR is in BLOCKS (as defined by STORE->block_size). */
error_t
store_write (struct store *store,
- off_t addr, char *buf, size_t len, size_t *amount)
+ store_offset_t addr, const void *buf, size_t len, size_t *amount)
{
error_t err;
size_t index;
- off_t base;
+ store_offset_t base;
struct store_run *run, *runs_end;
int block_shift = store->log2_block_size;
store_write_meth_t write = store->class->write;
@@ -106,19 +105,27 @@ store_write (struct store *store,
if (store->flags & STORE_READONLY)
return EROFS; /* XXX */
+ if ((addr << block_shift) + len > store->size)
+ return EIO;
+
+ if (store->block_size != 0 && (len & (store->block_size - 1)) != 0)
+ return EINVAL;
+
addr = store_find_first_run (store, addr, &run, &runs_end, &base, &index);
if (addr < 0)
err = EIO;
- else if ((run->length << block_shift) >= len)
+ else if ((len >> block_shift) <= run->length - addr)
/* The first run has it all... */
err = (*write)(store, base + run->start + addr, index, buf, len, amount);
else
/* ARGH, we've got to split up the write ... */
{
- mach_msg_type_number_t try = run->length << block_shift, written;
+ mach_msg_type_number_t try, written;
/* Write the initial bit in the first run. Errors here are returned. */
- err = (*write)(store, base + run->start + addr, index, buf, try, &written);
+ try = (run->length - addr) << block_shift;
+ err = (*write) (store, base + run->start + addr, index, buf, try,
+ &written);
if (!err && written == try)
/* Wrote the first bit successfully, now do the rest. Any errors
@@ -132,22 +139,25 @@ store_write (struct store *store,
/* Ok, we can write in this run, at least a bit. */
{
mach_msg_type_number_t seg_written;
- off_t run_len = (run->length << block_shift);
- try = run_len > len ? len : run_len;
+ if ((len >> block_shift) <= run->length)
+ try = len;
+ else
+ try = run->length << block_shift;
+
err = (*write)(store, base + run->start, index, buf, try,
&seg_written);
if (err)
break; /* Ack */
-
written += seg_written;
+
+ if (seg_written < try)
+ break; /* Didn't use up the run, we're done. */
+
len -= seg_written;
if (len == 0)
break; /* Nothing left to write! */
- if (seg_written < run_len)
- break; /* Didn't use up the run, we're done. */
-
buf += seg_written;
}
}
@@ -158,54 +168,64 @@ store_write (struct store *store,
return err;
}
-/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which following the
+/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which follows the
usual mach buffer-return semantics) to STORE at ADDR. ADDR is in BLOCKS
(as defined by STORE->block_size). */
error_t
store_read (struct store *store,
- off_t addr, size_t amount, char **buf, size_t *len)
+ store_offset_t addr, size_t amount, void **buf, size_t *len)
{
- error_t err;
size_t index;
- off_t base;
+ store_offset_t base;
struct store_run *run, *runs_end;
int block_shift = store->log2_block_size;
store_read_meth_t read = store->class->read;
addr = store_find_first_run (store, addr, &run, &runs_end, &base, &index);
- if (addr < 0)
- err = EIO;
- else if ((run->length << block_shift) >= amount)
+ if (addr < 0 || run->start < 0)
+ return EIO; /* Reading from a hole. */
+
+ if ((addr << block_shift) + amount > store->size)
+ amount = store->size - (addr << block_shift);
+
+ if (store->block_size != 0 && (amount & (store->block_size - 1)) != 0)
+ return EINVAL;
+
+ if ((amount >> block_shift) <= run->length - addr)
/* The first run has it all... */
- err = (*read)(store, base + run->start + addr, index, amount, buf, len);
+ return (*read) (store, base + run->start + addr, index, amount, buf, len);
else
/* ARGH, we've got to split up the read ... This isn't fun. */
{
+ error_t err;
int all;
/* WHOLE_BUF and WHOLE_BUF_LEN will point to a buff that's large enough
to hold the entire request. This is initially whatever the user
passed in, but we'll change it as necessary. */
- char *whole_buf = *buf, *buf_end;
+ void *whole_buf = *buf, *buf_end;
size_t whole_buf_len = *len;
/* Read LEN bytes from the store address ADDR into BUF_END. BUF_END
and AMOUNT are adjusted by the amount actually read. Whether or not
the amount read is the same as what was request is returned in ALL. */
- inline error_t seg_read (off_t addr, off_t len, int *all)
+ inline error_t seg_read (store_offset_t addr, size_t len, int *all)
{
/* SEG_BUF and SEG_LEN are the buffer for a particular bit of the
whole (within one run). */
- char *seg_buf = buf_end;
+ void *seg_buf = buf_end;
size_t seg_buf_len = len;
error_t err =
(*read)(store, addr, index, len, &seg_buf, &seg_buf_len);
if (!err)
{
/* If for some bizarre reason, the underlying storage chose not
- to use the buffer space we so kindly gave it, bcopy it to
+ to use the buffer space we so kindly gave it, copy it to
that space. */
if (seg_buf != buf_end)
- bcopy (seg_buf, buf_end, seg_buf_len);
+ {
+ memcpy (buf_end, seg_buf, seg_buf_len);
+ munmap (seg_buf, seg_buf_len);
+ }
buf_end += seg_buf_len;
amount -= seg_buf_len;
*all = (seg_buf_len == len);
@@ -218,30 +238,27 @@ store_read (struct store *store,
make room. */
{
whole_buf_len = amount;
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&whole_buf, amount, 1);
- if (err)
- return err; /* Punt early, there's nothing to clean up. */
+ whole_buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (whole_buf == (void *) -1)
+ return errno; /* Punt early, there's nothing to clean up. */
}
buf_end = whole_buf;
- err = seg_read (base + run->start + addr, run->length << block_shift, &all);
+ err = seg_read (base + run->start + addr,
+ (run->length - addr) << block_shift, &all);
while (!err && all && amount > 0
&& store_next_run (store, runs_end, &run, &base, &index))
{
- off_t run_addr = run->start;
- off_t run_blocks = run->length;
-
- if (run_addr < 0)
+ if (run->start < 0)
/* A hole! Can't read here. Must stop. */
break;
else
- {
- off_t run_len = (run_blocks << block_shift);
- off_t seg_len = run_len > amount ? amount : run_len;
- err = seg_read (base + run_addr, seg_len, &all);
- }
+ err = seg_read (base + run->start,
+ (amount >> block_shift) <= run->length
+ ? amount /* This run has the rest. */
+ : (run->length << block_shift), /* Whole run. */
+ &all);
}
/* The actual amount read. */
@@ -251,20 +268,31 @@ store_read (struct store *store,
/* Deallocate any amount of WHOLE_BUF we didn't use. */
if (whole_buf != *buf)
- if (err)
- vm_deallocate (mach_task_self (),
- (vm_address_t)whole_buf, whole_buf_len);
- else
- {
- vm_size_t unused = whole_buf_len - round_page (*len);
- if (unused)
- vm_deallocate (mach_task_self (),
- (vm_address_t)whole_buf + whole_buf_len - unused,
- unused);
- *buf = whole_buf;
- }
+ {
+ if (err)
+ munmap (whole_buf, whole_buf_len);
+ else
+ {
+ vm_size_t unused = whole_buf_len - round_page (*len);
+ if (unused)
+ munmap (whole_buf + whole_buf_len - unused, unused);
+ *buf = whole_buf;
+ }
+ }
+
+ return err;
}
+}
+
+/* Set STORE's size to NEWSIZE (in bytes). */
+error_t
+store_set_size (struct store *store, size_t newsize)
+{
+ error_t err;
+ store_set_size_meth_t set_size = store->class->set_size;
+
+ /* Updating the runs list is up to the class set_size method. */
+ err = (* set_size) (store, newsize);
return err;
}
-
diff --git a/libstore/remap.c b/libstore/remap.c
new file mode 100644
index 00000000..55ab51ac
--- /dev/null
+++ b/libstore/remap.c
@@ -0,0 +1,345 @@
+/* Block address translation
+
+ Copyright (C) 1996,97,99,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <hurd/fs.h>
+
+#include "store.h"
+
+static error_t
+remap_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ return store_read (store->children[0], addr, amount, buf, len);
+}
+
+static error_t
+remap_write (struct store *store,
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
+{
+ return store_write (store->children[0], addr, buf, len, amount);
+}
+
+static error_t
+remap_set_size (struct store *store, size_t newsize)
+{
+ return store_set_size (store->children[0], newsize);
+}
+
+error_t
+remap_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ enc->num_ints += 3;
+ enc->num_offsets += store->num_runs * 2;
+ return store_allocate_child_encodings (store, enc);
+}
+
+error_t
+remap_encode (const struct store *store, struct store_enc *enc)
+{
+ int i;
+ enc->ints[enc->cur_int++] = store->class->id;
+ enc->ints[enc->cur_int++] = store->flags;
+ enc->ints[enc->cur_int++] = store->num_runs;
+ for (i = 0; i < store->num_runs; i++)
+ {
+ enc->offsets[enc->cur_offset++] = store->runs[i].start;
+ enc->offsets[enc->cur_offset++] = store->runs[i].length;
+ }
+ return store_encode_children (store, enc);
+}
+
+error_t
+remap_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ if (enc->cur_int + 3 > enc->num_ints)
+ return EINVAL;
+ else
+ {
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
+ int flags = enc->ints[enc->cur_int++];
+ int num_runs = enc->ints[enc->cur_int++];
+ error_t create_remap (const struct store_run *runs, size_t num_runs)
+ {
+ struct store *source;
+ error_t err = store_decode_children (enc, 1, classes, &source);
+ if (! err)
+ err = store_remap_create (source, runs, num_runs, flags, store);
+ return err;
+ }
+ return store_with_decoded_runs (enc, num_runs, create_remap);
+ }
+}
+
+error_t
+remap_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ error_t err;
+ struct store *from;
+ const char *end, *p;
+ struct store_run *runs;
+ size_t nruns;
+
+ end = strchr (name, ':');
+ if (!end)
+ return EINVAL;
+
+ runs = alloca ((end - name) * sizeof runs[0]);
+
+ nruns = 0;
+ p = name;
+ do
+ {
+ char *endp;
+ runs[nruns].start = strtoul (p, &endp, 0);
+ if (*endp == '+')
+ {
+ if (endp == p) /* Syntax "+5,+7" means "0+5,0+7". */
+ runs[nruns].start = 0;
+ p = endp + 1;
+ if (p == end || *p == ',')
+ {
+ /* Syntax "100+" means block 100 to the end of the store.
+ Since we don't know the size yet, we use -1 as a marker
+ for the code below. */
+ runs[nruns++].length = (store_offset_t) -1;
+ break;
+ }
+ runs[nruns].length = strtoul (p, &endp, 0);
+ if (endp == p)
+ return EINVAL;
+ }
+ else if (endp == p) /* Must have a number unless starts with +. */
+ return EINVAL;
+ else
+ runs[nruns].length = 1;
+ ++nruns;
+ p = endp;
+ if (*p == ',')
+ ++p;
+ } while (p < end);
+
+ err = store_typed_open (end + 1, flags, classes, &from);
+ if (!err)
+ {
+ /* Check for any runs marked as "through the end of the store"
+ and update them to use the actual size of the store. */
+ size_t i;
+ for (i = 0; i < nruns; ++i)
+ if (runs[i].length == (store_offset_t) -1)
+ runs[i].length = from->blocks - runs[i].start;
+
+ /* Now do the remapping according to RUNS. */
+ err = store_remap (from, runs, nruns, store);
+ if (err)
+ store_free (from);
+ }
+ return err;
+}
+
+error_t
+remap_validate_name (const char *name,
+ const struct store_class *const *classes)
+{
+ const char *end = strchr (name, ':');
+ const char *p;
+
+ if (!end)
+ return EINVAL;
+
+ p = name;
+ do
+ {
+ if (*p != '+')
+ {
+ if (!isdigit (*p))
+ return EINVAL;
+ do
+ ++p;
+ while (isdigit (*p));
+ }
+
+ if (*p == '+')
+ {
+ ++p;
+ if (!isdigit (*p))
+ return EINVAL;
+ do
+ ++p;
+ while (isdigit (*p));
+ }
+
+ if (*p == ',')
+ ++p;
+ else if (*p == ':')
+ return 0;
+ } while (*p != '\0');
+
+ return EINVAL;
+}
+
+
+const struct store_class
+store_remap_class =
+{
+ STORAGE_REMAP, "remap", remap_read, remap_write, remap_set_size,
+ remap_allocate_encoding, remap_encode, remap_decode,
+ store_set_child_flags, store_clear_child_flags,
+ NULL, NULL, NULL, /* cleanup, clone, remap */
+ remap_open, remap_validate_name
+};
+STORE_STD_CLASS (remap);
+
+/* Return a new store in STORE that reflects the blocks in RUNS & RUNS_LEN
+ from SOURCE; SOURCE is consumed, but RUNS is not. Unlike the
+ store_remap function, this function always operates by creating a new
+ store of type `remap' which has SOURCE as a child, and so may be less
+ efficient than store_remap for some types of stores. */
+error_t
+store_remap_create (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ int flags, struct store **store)
+{
+ error_t err =
+ _store_create (&store_remap_class, MACH_PORT_NULL, flags | source->flags,
+ source->block_size, runs, num_runs, 0, store);
+
+ if (! err)
+ {
+ err = store_set_children (*store, &source, 1);
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* For each run in RUNS, of length NUM_RUNS, translate the */
+error_t
+store_remap_runs (const struct store_run *runs, size_t num_runs,
+ const struct store_run *base_runs, size_t num_base_runs,
+ struct store_run **xruns, size_t *num_xruns)
+{
+ int i, j;
+ size_t xruns_alloced = num_runs + num_base_runs;
+
+ /* Add the single run [ADDR, LEN) to *XRUNS, returning true if successful. */
+ int add_run (store_offset_t addr, store_offset_t len)
+ {
+ if (*num_xruns == xruns_alloced)
+ /* Make some more space in *XRUNS. */
+ {
+ struct store_run *new;
+ xruns_alloced *= 2;
+ new = realloc (*xruns, xruns_alloced * sizeof (struct store_run));
+ if (! new)
+ return 0;
+ *xruns = new;
+ }
+ (*xruns)[(*num_xruns)++] = (struct store_run){ addr, len };
+ return 1;
+ }
+
+ *xruns = malloc (xruns_alloced * sizeof (struct store_run));
+ if (! *xruns)
+ return ENOMEM;
+
+ /* Clean up and return error code CODE. */
+#define ERR(code) do { free (*xruns); return (code); } while (0)
+
+ for (i = 0; i < num_runs; i++)
+ {
+ store_offset_t addr = runs[i].start, left = runs[i].length;
+
+ if (addr >= 0)
+ for (j = 0; j < num_base_runs && left > 0; j++)
+ {
+ store_offset_t baddr = base_runs[j].start;
+ store_offset_t blen = base_runs[j].length;
+
+ if (addr >= blen)
+ addr -= blen;
+ else if (baddr < 0)
+ /* A hole, which is invalid. */
+ ERR (EINVAL);
+ else
+ /* Add another output run. */
+ {
+ store_offset_t len = blen - addr; /* Size of next output run. */
+ if (! add_run (baddr + addr, len > left ? left : len))
+ ERR (ENOMEM);
+ addr = 0;
+ left -= len;
+ }
+ }
+ else
+ /* a hole */
+ if (! add_run (-1, left))
+ ERR (ENOMEM);
+ }
+
+ if (xruns_alloced > *num_xruns)
+ *xruns = realloc (*xruns, *num_xruns * sizeof (struct store_run));
+
+ return 0;
+}
+
+/* Return a store in STORE that reflects the blocks in RUNS & RUNS_LEN from
+ SOURCE; SOURCE is consumed, but not RUNS. Unlike the store_remap_create
+ function, this may simply modify SOURCE and return it. */
+error_t
+store_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ if (source->class->remap)
+ /* Use the class-specific remaping function. */
+ return (* source->class->remap) (source, runs, num_runs, store);
+ else
+ /* Just replace SOURCE's runs-list by an appropiately translated RUNS. */
+ {
+ struct store_run *xruns = 0;
+ size_t num_xruns = 0;
+ error_t err =
+ store_remap_runs (runs, num_runs, source->runs, source->num_runs,
+ &xruns, &num_xruns);
+ if (! err)
+ {
+ /* Don't use store_set_runs -- we've already allocated the
+ storage. */
+ free (source->runs);
+ source->runs = xruns;
+ source->num_runs = num_xruns;
+ source->flags &= ~STORE_ENFORCED;
+ source->end = 0; /* Needed to make _store_derive work. */
+ store_close_source (source);
+ _store_derive (source);
+ *store = source;
+ }
+ return err;
+ }
+}
diff --git a/libstore/set.c b/libstore/set.c
index 479184d4..b9ff4f41 100644
--- a/libstore/set.c
+++ b/libstore/set.c
@@ -1,9 +1,7 @@
/* Setting various store fields
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,16 +16,19 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
+#include <errno.h>
+#include <mach.h>
#include "store.h"
/* Set STORE's current runs list to (a copy of) RUNS and NUM_RUNS. */
error_t
-store_set_runs (struct store *store, const struct store_run *runs, unsigned num_runs)
+store_set_runs (struct store *store,
+ const struct store_run *runs, size_t num_runs)
{
unsigned size = num_runs * sizeof (struct store_run);
struct store_run *copy = malloc (size);
@@ -38,7 +39,7 @@ store_set_runs (struct store *store, const struct store_run *runs, unsigned num_
if (store->runs)
free (store->runs);
- bcopy (runs, copy, size);
+ memcpy (copy, runs, size);
store->runs = copy;
store->num_runs = num_runs;
@@ -52,7 +53,7 @@ store_set_runs (struct store *store, const struct store_run *runs, unsigned num_
error_t
store_set_name (struct store *store, const char *name)
{
- char *copy = malloc (strlen (name) + 1);
+ char *copy = strdup (name);
if (!copy)
return ENOMEM;
@@ -60,7 +61,6 @@ store_set_name (struct store *store, const char *name)
if (store->name)
free (store->name);
- strcpy (copy, name);
store->name = copy;
return 0;
@@ -70,7 +70,7 @@ store_set_name (struct store *store, const char *name)
source from which it was created. */
void store_close_source (struct store *store)
{
- if (store->source)
+ if (store->source != MACH_PORT_NULL)
{
mach_port_deallocate (mach_task_self (), store->source);
store->source = MACH_PORT_NULL;
diff --git a/libstore/std.c b/libstore/std.c
index 37edc73b..4784a8a5 100644
--- a/libstore/std.c
+++ b/libstore/std.c
@@ -1,9 +1,7 @@
/* List of standard store classes
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,16 +16,29 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "store.h"
-struct store_class *
-store_std_classes = 0;
-
-void
-_store_add_std_class (struct store_class *class)
+const struct store_class *const __attribute__ ((section ("store_std_classes")))
+store_std_classes[] =
{
- class->next = store_std_classes;
- store_std_classes = class;
-}
+ &store_device_class,
+#if HAVE_PARTED_PARTED_H
+ &store_part_class,
+#endif
+ &store_file_class,
+ &store_zero_class,
+ &store_task_class,
+ &store_ileave_class, &store_concat_class, &store_remap_class,
+ &store_query_class,
+ &store_copy_class, &store_gunzip_class, &store_bunzip2_class,
+
+ /* This pseudo-class must appear before any real STORAGE_NETWORK class,
+ to parse STORAGE_NETWORK file_get_storage_info results properly. */
+ &store_url_open_class,
+ &store_nbd_class,
+
+ &store_typed_open_class,
+ 0
+};
diff --git a/libstore/store.h b/libstore/store.h
index 84e8aae3..ae334a1d 100644
--- a/libstore/store.h
+++ b/libstore/store.h
@@ -1,9 +1,7 @@
/* Store I/O
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1995,96,97,98,99,2001,02,04,05 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,21 +16,38 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* A `store' is a fixed-size block of storage, which can be read and perhaps
+ written to. This library implements many different backends which allow
+ the abstract store interface to be used with common types of storage --
+ devices, files, memory, tasks, etc. It also allows stores to be combined
+ and filtered in various ways. */
#ifndef __STORE_H__
#define __STORE_H__
#include <sys/types.h>
+#include <fcntl.h>
#include <mach.h>
#include <device/device.h>
#include <hurd/hurd_types.h>
+#include <features.h>
+
+#ifdef STORE_DEFINE_EI
+#define STORE_EI
+#else
+#define STORE_EI __extern_inline
+#endif
+/* Type for addresses inside the store. */
+typedef off64_t store_offset_t;
+
/* A portion of a store. If START == -1, it's a hole. */
struct store_run
{
- off_t start, length;
+ store_offset_t start, length;
};
struct store
@@ -47,13 +62,13 @@ struct store
size_t num_runs; /* Length of RUNS. */
/* Maximum valid offset. This is the same as SIZE, but in blocks. */
- off_t end;
+ store_offset_t end;
/* WRAP_SRC is the sum of the run lengths in RUNS. If this is less than
END, then RUNS describes a repeating pattern, of length WRAP_SRC -- each
successive iteration having an additional offset of WRAP_DST. */
- off_t wrap_src;
- off_t wrap_dst; /* Only meaningful if WRAP_SRC < END */
+ store_offset_t wrap_src;
+ store_offset_t wrap_dst; /* Only meaningful if WRAP_SRC < END */
/* Handles for the underlying storage. */
char *name; /* Malloced */
@@ -63,14 +78,14 @@ struct store
size_t block_size;
/* The number of blocks (of size BLOCK_SIZE) in this storage. */
- size_t blocks;
+ store_offset_t blocks;
/* The number of bytes in this storage, including holes. */
- size_t size;
+ store_offset_t size;
/* Log_2 (BLOCK_SIZE) or 0 if not a power of 2. */
- int log2_block_size;
+ unsigned log2_block_size;
/* Log_2 (VM_PAGE_SIZE / BLOCK_SIZE); only valid if LOG2_BLOCK_SIZE is. */
- int log2_blocks_per_page;
+ unsigned log2_blocks_per_page;
/* Random flags. */
int flags;
@@ -78,7 +93,7 @@ struct store
void *misc; /* malloced */
size_t misc_len;
- struct store_class *class;
+ const struct store_class *class;
/* A list of sub-stores. The interpretation of this is type-specific. */
struct store **children;
@@ -91,27 +106,36 @@ struct store
<hurd/hurd_types.h>. XXX synchronize these values. */
/* Flags that reflect something immutable about the object. */
-#define STORE_IMMUTABLE_FLAGS 0xFF
+#define STORE_IMMUTABLE_FLAGS 0x00FF
/* Flags implemented by generic store code. */
-#define STORE_READONLY 0x100 /* No writing allowed. */
-#define STORE_GENERIC_FLAGS STORE_READONLY
+#define STORE_READONLY 0x0100 /* No writing allowed. */
+#define STORE_NO_FILEIO 0x0200 /* If store_create can't fetch store
+ information, don't create a store
+ using file io instead. */
+#define STORE_GENERIC_FLAGS (STORE_READONLY | STORE_NO_FILEIO)
/* Flags implemented by each backend. */
-#define STORE_HARD_READONLY 0x200 /* Can't be made writable. */
-#define STORE_ENFORCED 0x400 /* Range is enforced by device. */
-#define STORE_BACKEND_SPEC_BASE 0x1000 /* Here up are backend-specific */
+#define STORE_HARD_READONLY 0x1000 /* Can't be made writable. */
+#define STORE_ENFORCED 0x2000 /* Range is enforced by device. */
+#define STORE_INACTIVE 0x4000 /* Not in a usable state. */
+#define STORE_INNOCUOUS 0x8000 /* Cannot modify anything dangerous. */
+#define STORE_BACKEND_SPEC_BASE 0x10000 /* Here up are backend-specific */
#define STORE_BACKEND_FLAGS (STORE_HARD_READONLY | STORE_ENFORCED \
+ | STORE_INACTIVE \
| ~(STORE_BACKEND_SPEC_BASE - 1))
typedef error_t (*store_write_meth_t)(struct store *store,
- off_t addr, size_t index,
- char *buf, mach_msg_type_number_t len,
+ store_offset_t addr, size_t index,
+ const void *buf,
+ mach_msg_type_number_t len,
mach_msg_type_number_t *amount);
typedef error_t (*store_read_meth_t)(struct store *store,
- off_t addr, size_t index,
+ store_offset_t addr, size_t index,
mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len);
+ void **buf, mach_msg_type_number_t *len);
+typedef error_t (*store_set_size_meth_t)(struct store *store,
+ size_t newsize);
struct store_enc; /* fwd decl */
@@ -121,14 +145,16 @@ struct store_class
enum file_storage_class id;
/* Name of the class. */
- char *name;
+ const char *name;
/* Read up to AMOUNT bytes at the underlying address ADDR from the storage
- into BUF and LEN. INDEX varies from 0 to the number of runs in STORE. */
+ into BUF and LEN. INDEX varies from 0 to the number of runs in STORE. */
store_read_meth_t read;
/* Write up to LEN bytes from BUF to the storage at the underlying address
- ADDR. INDEX varies from 0 to the number of runs in STORE. */
+ ADDR. INDEX varies from 0 to the number of runs in STORE. */
store_write_meth_t write;
+ /* Set store's size to NEWSIZE (in bytes). */
+ store_set_size_meth_t set_size;
/* To the lengths of each for the four arrays in ENC, add how much STORE
would need to be encoded. */
@@ -139,7 +165,8 @@ struct store_class
/* Decode from ENC a new store, which return in STORE. CLASSES is used to
lookup child classes. */
- error_t (*decode) (struct store_enc *enc, struct store_class *classes,
+ error_t (*decode) (struct store_enc *enc,
+ const struct store_class *const *classes,
struct store **store);
/* Modify flags that reflect backend state, such as STORE_HARD_READONLY and
@@ -155,26 +182,63 @@ struct store_class
made after all format-indendependent fields have been cloned. */
error_t (*clone) (const struct store *from, struct store *to);
- /* For making a list of classes to pass to e.g. store_create. */
- struct store_class *next;
+ /* Return in STORE a store that only contains the parts of SOURCE as
+ enumerated in RUNS & RUNS_LEN, consuming SOURCE in the process. The
+ default behavior, if REMAP is 0, is to replace SOURCE's run list with
+ the subset selected by RUNS, and return SOURCE. */
+ error_t (*remap) (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+ /* Open a new store called NAME in this class. CLASSES is supplied in case
+ it's desirable to open a sub-store in some manner. */
+ error_t (*open) (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+ /* Given a user argument ARG, this function should check it for syntactic
+ validity, or print a syntax error, using ARGP_STATE in the normal
+ manner; if zero is returned, then this argument is assumed valid, and
+ can be passed to the open function. If ARG is 0, then there were *no*
+ arguments specified; in this case, returning EINVAL means that this is
+ not kosher. If PARSE is 0, then it is assumed that if this class has an
+ OPEN function, then validity can't be syntactically determined. */
+ error_t (*validate_name) (const char *name,
+ const struct store_class *const *classes);
+
+ /* Return a memory object paging on STORE. */
+ error_t (*map) (const struct store *store, vm_prot_t prot, mach_port_t *memobj);
};
/* Return a new store in STORE, which refers to the storage underlying
- SOURCE. CLASSES is used to select classes specified by the provider; if
- it is 0, STORE_STD_CLASSES is used. FLAGS is set with store_set_flags. A
- reference to SOURCE is created (but may be destroyed with
- store_close_source). */
-error_t store_create (file_t source, int flags, struct store_class *classes,
+ SOURCE. CLASSES is as if passed to store_find_class, which see. FLAGS
+ is set with store_set_flags, with the exception of STORE_INACTIVE, which
+ merely indicates that no attempt should be made to activate an inactive
+ store; if STORE_INACTIVE is not specified, and the store returned for
+ SOURCE is inactive, an attempt is made to activate it (failure of which
+ causes an error to be returned). A reference to SOURCE is created (but
+ may be destroyed with store_close_source). */
+error_t store_create (file_t source, int flags,
+ const struct store_class *const *classes,
struct store **store);
void store_free (struct store *store);
-/* Allocate a new store structure with class CLASS, and the various other
- fields initialized to the given parameters. */
-struct store *
-_make_store (struct store_class *class, mach_port_t port, int flags,
- size_t block_size, const struct store_run *runs, size_t num_runs,
- off_t end);
+/* Open the file NAME, and return a new store in STORE, which refers to the
+ storage underlying it. CLASSES is as if passed to store_find_class,
+ which see. FLAGS is set with store_set_flags. A reference to the open
+ file is created (but may be destroyed with store_close_source). */
+error_t store_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Allocate a new store structure, returned in STORE, with class CLASS and
+ the various other fields initialized to the given parameters. */
+error_t
+_store_create (const struct store_class *class, mach_port_t port,
+ int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ store_offset_t end, struct store **store);
/* Set STORE's current runs list to (a copy of) RUNS and NUM_RUNS. */
error_t store_set_runs (struct store *store,
@@ -185,6 +249,12 @@ error_t store_set_runs (struct store *store,
error_t store_set_children (struct store *store,
struct store *const *children, size_t num_children);
+/* Try to come up with a name for the children in STORE, combining the names
+ of each child in a way that could be used to parse them with
+ store_open_children. This is done heuristically, and so may not succeed.
+ If a child doesn't have a name, EINVAL is returned. */
+error_t store_children_name (const struct store *store, char **name);
+
/* Sets the name associated with STORE to a copy of NAME. */
error_t store_set_name (struct store *store, const char *name);
@@ -194,52 +264,85 @@ error_t store_set_flags (struct store *store, int flags);
/* Remove FLAGS from STORE's currently set flags. */
error_t store_clear_flags (struct store *store, int flags);
+/* Set FLAGS in all children of STORE, and if successful, add FLAGS to
+ STORE's flags. */
+error_t store_set_child_flags (struct store *store, int flags);
+
+/* Clear FLAGS in all children of STORE, and if successful, remove FLAGS from
+ 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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(STORE_DEFINE_EI)
+
+/* 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
+store_is_securely_returnable (struct store *store, int open_flags)
+{
+ int flags = store->flags;
+ return
+ (flags & (STORE_INNOCUOUS | STORE_INACTIVE))
+ || ((flags & STORE_ENFORCED)
+ && (((open_flags & O_ACCMODE) == O_RDWR)
+ || (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);
/* Return in TO a copy of FROM. */
error_t store_clone (struct store *from, struct store **to);
+
+/* Return a store in STORE that reflects the blocks in RUNS & RUNS_LEN from
+ source; SOURCE is consumed, but not RUNS. Unlike the store_remap_create
+ function, this may simply modify SOURCE and return it. */
+error_t store_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
/* Write LEN bytes from BUF to STORE at ADDR. Returns the amount written in
AMOUNT (in bytes). ADDR is in BLOCKS (as defined by STORE->block_size). */
error_t store_write (struct store *store,
- off_t addr, char *buf, size_t len, size_t *amount);
+ store_offset_t addr, const void *buf, size_t len,
+ size_t *amount);
/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which following the
usual mach buffer-return semantics) to STORE at ADDR. ADDR is in BLOCKS
(as defined by STORE->block_size). Note that LEN is in bytes. */
error_t store_read (struct store *store,
- off_t addr, size_t amount, char **buf, size_t *len);
+ store_offset_t addr, size_t amount, void **buf, size_t *len);
+
+/* Set STORE's size to NEWSIZE (in bytes). */
+error_t store_set_size (struct store *store, size_t newsize);
/* If STORE was created using store_create, remove the reference to the
source from which it was created. */
void store_close_source (struct store *store);
-#if 0
-
-/* Return a memory object paging on STORE. [among other reasons,] this may
- fail because store contains non-contiguous regions on the underlying
- object. In such a case you can try calling some of the routines below to
- get a pager. */
-error_t store_map (struct store *store, vm_prot_t prot, ...,
- mach_port_t *pager);
+/* Return a memory object paging on STORE. If this call fails with
+ EOPNOTSUPP, you can try calling some of the routines below to get a pager. */
+error_t store_map (const struct store *store, vm_prot_t prot,
+ mach_port_t *memobj);
-/* Returns a memory object paging on the file from which STORE was created.
- If STORE wasn't created using store_create, or the source was destroyed
- using store_close_source, this will fail. */
-error_t store_map_source (struct store *store, vm_prot_t prot, ...,
- mach_port_t *pager)
+#if 0
/* Create a new pager and paging threads paging on STORE, and return the
resulting memory object in PAGER. */
error_t store_create_pager (struct store *store, vm_prot_t prot, ...,
- mach_port_t *pager)
+ mach_port_t *memobj)
#endif
/* Creating specific types of stores. */
+/* Return a new zero store SIZE bytes long in STORE. */
+error_t store_zero_create (store_offset_t size, int flags, struct store **store);
+
/* Return a new store in STORE referring to the mach device DEVICE. Consumes
the send right DEVICE. */
error_t store_device_create (device_t device, int flags, struct store **store);
@@ -252,6 +355,21 @@ error_t _store_device_create (device_t device, int flags, size_t block_size,
/* Open the device NAME, and return the corresponding store in STORE. */
error_t store_device_open (const char *name, int flags, struct store **store);
+/* Return a new store in STORE which contains a remap store of partition
+ PART from the contents of SOURCE; SOURCE is consumed. */
+error_t store_part_create (struct store *source, int index, int flags,
+ struct store **store);
+
+/* Open the part NAME. NAME consists of a partition number, a ':', a
+ another store class name, a ':' and a name for to by passed to the
+ store class. E.g. "2:device:hd0" would open the second partition
+ on a DEVICE store named "hd0". FLAGS indicate how to open the
+ store. CLASSES is as if passed to store_find_class, which see.
+ The new store is returned in *STORE. */
+error_t store_part_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
/* Return a new store in STORE referring to the file FILE. Unlike
store_create, this will always use file i/o, even it would be possible to
be more direct. This may work in more cases, for instance if the file has
@@ -266,13 +384,53 @@ error_t _store_file_create (file_t file, int flags, size_t block_size,
/* Open the file NAME, and return the corresponding store in STORE. */
error_t store_file_open (const char *name, int flags, struct store **store);
+/* Return a new store in STORE referring to the task TASK, consuming TASK. */
+error_t store_task_create (task_t task, int flags, struct store **store);
+
+/* Like store_task_create, but doesn't query the task for information. */
+error_t _store_task_create (task_t task, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+/* Open the task NAME (NAME should be the task's pid), and return the
+ corresponding store in STORE. */
+error_t store_task_open (const char *name, int flags, struct store **store);
+
+/* Return a new store in STORE referring to the memory object MEMOBJ.
+ Consumes the send right MEMOBJ. */
+error_t store_memobj_create (memory_object_t memobj, int flags,
+ size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+/* Open the network block device NAME (parsed as "HOSTNAME:PORT[/BLOCKSIZE]"),
+ and return the corresponding store in STORE. This opens a socket and
+ initial connection handshake, which determine the size of the device,
+ and then uses _store_nbd_create with the open socket port. */
+error_t store_nbd_open (const char *name, int flags, struct store **store);
+
+/* Create a store that works by talking to an nbd server on an existing
+ socket port. */
+error_t _store_nbd_create (mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
+/* Return a new store of type "unknown" that holds a copy of the
+ given encoding. The name of the store is taken from ENC->data.
+ Future calls to store_encode/store_return will produce exactly
+ the encoding supplied here. All i/o operations fail with EFTYPE. */
+error_t store_unknown_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store);
+
/* Return a new store in STORE that interleaves all the stores in STRIPES
(NUM_STRIPES of them) every INTERLEAVE bytes; INTERLEAVE must be an
integer multiple of each stripe's block size. The stores in STRIPES are
consumed -- that is, will be freed when this store is (however, the
*array* STRIPES is copied, and so should be freed by the caller). */
error_t store_ileave_create (struct store * const *stripes, size_t num_stripes,
- off_t interleave, int flags, struct store **store);
+ store_offset_t interleave, int flags,
+ struct store **store);
/* Return a new store in STORE that concatenates all the stores in STORES
(NUM_STORES of them). The stores in STRIPES are consumed -- that is, will
@@ -281,24 +439,208 @@ error_t store_ileave_create (struct store * const *stripes, size_t num_stripes,
error_t store_concat_create (struct store * const *stores, size_t num_stores,
int flags, struct store **store);
-/* Return a new null store SIZE bytes long in STORE. */
-error_t store_null_create (size_t size, int flags, struct store **store);
+/* Return a new store that concatenates the stores created by opening all the
+ individual stores described in NAME; for the syntax of NAME, see
+ store_open_children. */
+error_t store_concat_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE that reflects the blocks in RUNS & RUNS_LEN
+ from SOURCE; SOURCE is consumed, but RUNS is not. Unlike the store_remap
+ function, this function always operates by creating a new store of type
+ `remap' which has SOURCE as a child, and so may be less efficient than
+ store_remap for some types of stores. */
+error_t store_remap_create (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ int flags, struct store **store);
+
+/* Return a new store in STORE which contains a snapshot of the contents of
+ the store FROM; FROM is consumed. */
+error_t store_copy_create (struct store *from, int flags, struct store **store);
+
+/* Open the copy store NAME -- which consists of another store-class
+ name, a ':', and a name for that store class to open -- and return
+ the corresponding store in STORE. CLASSES is as if passed to
+ store_find_class, which see. */
+error_t store_copy_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE which contains the memory buffer BUF, of
+ length BUF_LEN. BUF must be vm_allocated, and will be consumed. */
+error_t store_buffer_create (void *buf, size_t buf_len, int flags,
+ struct store **store);
+
+/* Return a new store in STORE which contains a snapshot of the uncompressed
+ contents of the store FROM; FROM is consumed. BLOCK_SIZE is the desired
+ block size of the result. */
+error_t store_gunzip_create (struct store *from, int flags,
+ struct store **store);
+
+/* Open the gunzip NAME -- which consists of another store-class name, a
+ ':', and a name for that store class to open -- and return the
+ corresponding store in STORE. CLASSES is as if passed to
+ store_find_class, which see. */
+error_t store_gunzip_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE which contains a snapshot of the uncompressed
+ contents of the store FROM; FROM is consumed. BLOCK_SIZE is the desired
+ block size of the result. */
+error_t store_bunzip2_create (struct store *from, int flags,
+ struct store **store);
+
+/* Open the bunzip2 NAME -- which consists of another store-class name, a ':',
+ and a name for that store class to open -- and return the corresponding
+ store in STORE. CLASSES is as if passed to store_find_class, which see. */
+error_t store_bunzip2_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Return a new store in STORE that multiplexes multiple physical volumes
+ from PHYS as one larger virtual volume. SWAP_VOLS is a function that will
+ be called whenever the volume currently active isn't correct. PHYS is
+ consumed. */
+error_t store_mvol_create (struct store *phys,
+ error_t (*swap_vols) (struct store *store, size_t new_vol,
+ ssize_t old_vol),
+ int flags,
+ struct store **store);
+
+/* Opening stores from a standard set of store classes.
+
+ These first two functions underlie the following functions, and
+ other functions such as store_open taking a CLASSES argument that
+ can be null. The standard set of classes to be searched when that
+ argument is null includes all the `const struct store_class *'
+ pointers found in the `store_std_classes' section of the executable
+ and all loaded shared objects; store_find_class searches that set
+ for the named class. The store_typed_open and store_url_open
+ functions also try store_module_find_class, but only if the
+ function has already been linked in; it's always available in the
+ shared library, and available for static linking with
+ -lstore_module -ldl.
+
+ The macro STORE_STD_CLASS produces a reference in the `store_std_classes'
+ section, so that linking in a module containing that definition will add
+ the referenced class to the standard search list. In the shared library,
+ the various standard classes are included this way. In the static
+ library, only the pseudo classes like `query' and `typed' will normally
+ be linked in (via referenced to store_open and so forth); to force
+ specific store type modules to be linked in, you must specify an
+ `-lstore_CLASS' option for each individual class to be statically linked.
+*/
+
+/* Find a store class by name. CLNAME_END points to the character
+ after the class name NAME points to; if null, then NAME is just the
+ null-terminated class name. */
+const struct store_class *
+store_find_class (const char *name,
+ const char *clname_end,
+ const struct store_class *const *classes);
+
+/* This is the underlying function that tries to load a module to
+ define the store type called NAME. On success, returns zero
+ and sets *CLASSP to the descriptor found. Returns ENOENT if
+ there is no such module, or other error codes if there is a
+ module but it does not load correctly. */
+error_t store_module_find_class (const char *name,
+ const char *clname_end,
+ const struct store_class **classp);
+
+
+/* Open the store indicated by NAME, which should consist of a store
+ type name followed by a ':' and any type-specific name, returning the
+ new store in STORE. CLASSES is as if passed to store_find_class,
+ which see. */
+error_t store_typed_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Similar to store_typed_open, but NAME must be in URL format, i.e. a
+ class name followed by a ':' and any type-specific name. A leading ':'
+ or no ':' at all is invalid syntax. (See store_module_open, below.) */
+error_t store_url_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* This attempts to decode a standard-form STORAGE_NETWORK encoding whose
+ encoded name is in URL format, by finding the store type indicated in
+ the URL (as for store_url_open) and that type's decode function. */
+error_t store_url_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store);
+
+
+/* Similar to store_typed_open, but the store type's code is found
+ dynamically rather than statically in CLASSES. A shared object name
+ for `dlopen' and symbol names for `dlsym' are derived from the type
+ name and used to find the `struct store_class' for the named type.
+ (CLASSES is used only by the type's own open function, e.g. if that
+ type accepts a child-store syntax in its name.)
+
+ In fact, when this code is linked in (always in the shared library,
+ only with `-lstore_module -ldl -lstore' for static linking), all
+ the functions documented as using STORE_STD_CLASSES will also
+ check for loadable modules if the type name is not found statically. */
+error_t store_module_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store);
+
+
+/* This attempts to find a module that can decode ENC. If no such
+ module can be found it returns ENOENT. Otherwise it returns
+ the result of the loaded store type's `decode' function. */
+error_t store_module_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store);
+
+/* Parse multiple store names in NAME, and open each individually, returning
+ all in the vector STORES, and the number in NUM_STORES. The syntax of
+ NAME is a single non-alpha-numeric separator character, followed by each
+ child store name separated by the same separator; each child name is
+ TYPE:NAME notation as parsed by store_typed_open. If every child uses the
+ same TYPE: prefix, then it may be factored out and put before the child
+ list instead (the two types of notation are differentiated by whether the
+ first character of name is alpha-numeric or not). */
+error_t store_open_children (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store ***stores, size_t *num_stores);
+
/* Standard store classes implemented by libstore. */
-extern struct store_class *store_std_classes;
-
-/* Add CLASS to the list of standard classes. It must not already be in the
- list, or in any other, as its next field is simply written over. */
-void _store_add_std_class (struct store_class *class);
-
-/* Use this macro to automagically add a class to STORE_STD_CLASSES at
- startup. */
-#define _STORE_STD_CLASS(class_struct) \
-static void _store_init_std_##class_struct () __attribute__ ((constructor));\
-static void _store_init_std_##class_struct () \
-{ \
- _store_add_std_class (&class_struct); \
-}
+extern const struct store_class store_device_class;
+extern const struct store_class store_part_class;
+extern const struct store_class store_file_class;
+extern const struct store_class store_task_class;
+extern const struct store_class store_nbd_class;
+extern const struct store_class store_memobj_class;
+extern const struct store_class store_zero_class;
+extern const struct store_class store_ileave_class;
+extern const struct store_class store_concat_class;
+extern const struct store_class store_remap_class;
+extern const struct store_class store_query_class;
+extern const struct store_class store_copy_class;
+extern const struct store_class store_gunzip_class;
+extern const struct store_class store_bunzip2_class;
+extern const struct store_class store_typed_open_class;
+extern const struct store_class store_url_open_class;
+extern const struct store_class store_module_open_class;
+extern const struct store_class store_unknown_class;
+
+/* The following are not included in STORE_STD_CLASSES. */
+extern const struct store_class store_mvol_class;
+
+#define STORE_STD_CLASS(name) \
+ static const struct store_class *const store_std_classes_##name[] \
+ __attribute_used__ __attribute__ ((section ("store_std_classes"))) \
+ = { &store_##name##_class }
+
+
+extern const struct store_class *const __start_store_std_classes[] __attribute__ ((weak));
+extern const struct store_class *const __stop_store_std_classes[] __attribute__ ((weak));
/* Used to hold the various bits that make up the representation of a store
for transmission via rpc. See <hurd/hurd_types.h> for an explanation of
@@ -308,7 +650,7 @@ struct store_enc
/* Each of the four vectors used. All are vm_allocated. */
mach_port_t *ports;
int *ints;
- off_t *offsets;
+ loff_t *offsets;
char *data;
/* The sizes of the vectors. */
@@ -322,7 +664,7 @@ struct store_enc
version won't be deallocated. */
mach_port_t *init_ports;
int *init_ints;
- off_t *init_offsets;
+ loff_t *init_offsets;
char *init_data;
};
@@ -332,13 +674,29 @@ struct store_enc
void store_enc_init (struct store_enc *enc,
mach_port_t *ports, mach_msg_type_number_t num_ports,
int *ints, mach_msg_type_number_t num_ints,
- off_t *offsets, mach_msg_type_number_t num_offsets,
+ loff_t *offsets, mach_msg_type_number_t num_offsets,
char *data, mach_msg_type_number_t data_len);
/* Deallocate storage used by the fields in ENC (but nothing is done with ENC
itself). */
void store_enc_dealloc (struct store_enc *enc);
+
+/* Copy out the parameters from ENC into the given variables suitably for
+ returning from a file_get_storage_info rpc, and deallocate ENC. */
+void store_enc_return (struct store_enc *enc,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ loff_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len);
+/* Encode STORE into the given return variables, suitably for returning from a
+ file_get_storage_info rpc. */
+error_t store_return (const struct store *store,
+ mach_port_t **ports, mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ loff_t **offsets, mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len);
+
/* Encode STORE into ENC, which should have been prepared with
store_enc_init, or return an error. The contents of ENC may then be
return as the value of file_get_storage_info; if for some reason this
@@ -346,11 +704,12 @@ void store_enc_dealloc (struct store_enc *enc);
used by the unsent vectors. */
error_t store_encode (const struct store *store, struct store_enc *enc);
-/* Decode ENC, either returning a new store in STORE, or an error. CLASSES
- defines the mapping from hurd storage class ids to store classes; if it is
- 0, STORE_STD_CLASSES is used. If nothing else is to be done with ENC, its
- contents may then be freed using store_enc_dealloc. */
-error_t store_decode (struct store_enc *enc, struct store_class *classes,
+/* Decode ENC, either returning a new store in STORE, or an error.
+ CLASSES is as if passed to store_find_class, which see. If nothing
+ else is to be done with ENC, its contents may then be freed using
+ store_enc_dealloc. */
+error_t store_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
struct store **store);
/* Calls the allocate_encoding method in each child store of STORE,
@@ -367,9 +726,14 @@ error_t store_encode_children (const struct store *store,
/* Decodes NUM_CHILDREN from ENC, storing the results into successive
positions in CHILDREN. */
error_t store_decode_children (struct store_enc *enc, int num_children,
- struct store_class *classes,
+ const struct store_class *const *classes,
struct store **children);
+/* Call FUN with the vector RUNS of length NUM_RUNS extracted from ENC. */
+error_t store_with_decoded_runs (struct store_enc *enc, size_t num_runs,
+ error_t (*fun) (const struct store_run *runs,
+ size_t num_runs));
+
/* Standard encoding used for most leaf store types. */
error_t store_std_leaf_allocate_encoding (const struct store *store,
struct store_enc *enc);
@@ -392,22 +756,45 @@ error_t store_std_leaf_decode (struct store_enc *enc,
/* An argument parser that may be used for parsing a simple command line
specification for stores. The accompanying input parameter must be a
- pointer to a structure of type struct store_argp_param. */
+ pointer to a struct store_argp_params. */
extern struct argp store_argp;
-/* Structure used to pass in arguments and return the result from
- STORE_ARGP. */
+/* The structure used to pass args back and forth from STORE_ARGP. */
struct store_argp_params
{
- /* An initial set of flags desired to be set. */
- int flags;
+ /* The resulting parsed result. */
+ struct store_parsed *result;
+
+ /* If --store-type isn't specified use this; 0 is equivalent to "query". */
+ const char *default_type;
- /* If true, don't attempt use store_file_create to create a store on files
- upon which store_create has failed. */
- int no_file_io : 1;
+ /* The set of classes used to validate store-types and argument syntax. */
+ const struct store_class *const *classes;
- /* Parsed store returned here. */
- struct store *result;
+ /* This controls the behavior when no store arguments are specified.
+ If zero, the parser fails with the error message "No store specified".
+ If nonzero, the parser succeeds and sets `result' to null. */
+ int store_optional;
};
+/* The result of parsing a store, which should be enough information to open
+ it, or return the arguments. */
+struct store_parsed;
+
+/* Free all resources used by PARSED. */
+void store_parsed_free (struct store_parsed *parsed);
+
+/* Open PARSED, and return the corresponding store in STORE. */
+error_t store_parsed_open (const struct store_parsed *parsed, int flags,
+ struct store **store);
+
+/* Add the arguments used to create PARSED to ARGZ & ARGZ_LEN. */
+error_t store_parsed_append_args (const struct store_parsed *parsed,
+ char **argz, size_t *argz_len);
+
+/* Make a string describing PARSED, and return it in malloced storage in
+ NAME. */
+error_t store_parsed_name (const struct store_parsed *parsed, char **name);
+
+
#endif /* __STORE_H__ */
diff --git a/libstore/storecat.c b/libstore/storecat.c
deleted file mode 100644
index f1374390..00000000
--- a/libstore/storecat.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Test program for libstore -- outputs the concatenation of stores */
-
-#include <argp.h>
-#include <error.h>
-#include <unistd.h>
-
-#include "store.h"
-
-int
-main (int argc, char **argv)
-{
- error_t err;
- struct store *s;
- char buf[4096], *data = buf;
- size_t data_len = sizeof (buf);
- struct store_argp_params params = { 0, 0, 0 };
-
- argp_parse (&store_argp, argc, argv, 0, 0, &params);
- s = params.result;
-
- err = store_read (s, 0, s->size, &data, &data_len);
- if (err)
- error (5, err, s->name ? "%s" : "<store>", s->name);
-
- if (write (1, data, data_len) < 0)
- error (6, errno, "stdout");
-
- exit (0);
-}
diff --git a/libstore/stripe.c b/libstore/stripe.c
index 055c548f..e9c58466 100644
--- a/libstore/stripe.c
+++ b/libstore/stripe.c
@@ -1,9 +1,7 @@
/* Striped store backend
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
+ Copyright (C) 1996,97,99,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,7 +16,7 @@
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. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <stdlib.h>
#include <string.h>
@@ -29,8 +27,8 @@ extern long lcm (long p, long q);
/* Return ADDR adjust for any block size difference between STORE and
STRIPE. We assume that STORE's block size is no less than STRIPE's. */
-static inline off_t
-addr_adj (off_t addr, struct store *store, struct store *stripe)
+static inline store_offset_t
+addr_adj (store_offset_t addr, struct store *store, struct store *stripe)
{
unsigned common_bs = store->log2_block_size;
unsigned stripe_bs = stripe->log2_block_size;
@@ -42,8 +40,8 @@ addr_adj (off_t addr, struct store *store, struct store *stripe)
static error_t
stripe_read (struct store *store,
- off_t addr, size_t index, mach_msg_type_number_t amount,
- char **buf, mach_msg_type_number_t *len)
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
{
struct store *stripe = store->children[index];
return store_read (stripe, addr_adj (addr, store, stripe), amount, buf, len);
@@ -51,13 +49,27 @@ stripe_read (struct store *store,
static error_t
stripe_write (struct store *store,
- off_t addr, size_t index, char *buf, mach_msg_type_number_t len,
- mach_msg_type_number_t *amount)
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
{
struct store *stripe = store->children[index];
return
store_write (stripe, addr_adj (addr, store, stripe), buf, len, amount);
}
+
+error_t
+stripe_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+stripe_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return store_remap_create (source, runs, num_runs, 0, store);
+}
error_t
ileave_allocate_encoding (const struct store *store, struct store_enc *enc)
@@ -77,14 +89,14 @@ ileave_encode (const struct store *store, struct store_enc *enc)
}
error_t
-ileave_decode (struct store_enc *enc, struct store_class *classes,
+ileave_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
if (enc->cur_int + 4 > enc->num_ints)
return EINVAL;
else
{
- int type = enc->ints[enc->cur_int++];
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
int flags = enc->ints[enc->cur_int++];
int interleave = enc->ints[enc->cur_int++];
int nkids = enc->ints[enc->cur_int++];
@@ -96,13 +108,14 @@ ileave_decode (struct store_enc *enc, struct store_class *classes,
}
}
-static struct store_class
-ileave_class =
+const struct store_class
+store_ileave_class =
{
- STORAGE_INTERLEAVE, "interleave", stripe_read, stripe_write,
+ STORAGE_INTERLEAVE, "interleave", stripe_read, stripe_write, stripe_set_size,
ileave_allocate_encoding, ileave_encode, ileave_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap
};
-_STORE_STD_CLASS (ileave_class);
+STORE_STD_CLASS (ileave);
error_t
concat_allocate_encoding (const struct store *store, struct store_enc *enc)
@@ -121,14 +134,14 @@ concat_encode (const struct store *store, struct store_enc *enc)
}
error_t
-concat_decode (struct store_enc *enc, struct store_class *classes,
+concat_decode (struct store_enc *enc, const struct store_class *const *classes,
struct store **store)
{
if (enc->cur_int + 3 > enc->num_ints)
return EINVAL;
else
{
- int type = enc->ints[enc->cur_int++];
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
int flags = enc->ints[enc->cur_int++];
int nkids = enc->ints[enc->cur_int++];
struct store *kids[nkids];
@@ -139,13 +152,15 @@ concat_decode (struct store_enc *enc, struct store_class *classes,
}
}
-static struct store_class
-concat_class =
+const struct store_class
+store_concat_class =
{
- STORAGE_CONCAT, "concat", stripe_read, stripe_write,
- concat_allocate_encoding, concat_encode, concat_decode
+ STORAGE_CONCAT, "concat", stripe_read, stripe_write, stripe_set_size,
+ concat_allocate_encoding, concat_encode, concat_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap,
+ store_concat_open
};
-_STORE_STD_CLASS (concat_class);
+STORE_STD_CLASS (concat);
/* Return a new store in STORE that interleaves all the stores in STRIPES
(NUM_STRIPES of them) every INTERLEAVE bytes; INTERLEAVE must be an
@@ -154,12 +169,15 @@ _STORE_STD_CLASS (concat_class);
*array* STRIPES is copied, and so should be freed by the caller). */
error_t
store_ileave_create (struct store *const *stripes, size_t num_stripes,
- off_t interleave, int flags, struct store **store)
+ store_offset_t interleave, int flags,
+ struct store **store)
{
size_t i;
error_t err;
- off_t block_size = 1, min_end = 0;
+ size_t block_size = 1;
+ store_offset_t min_end = 0;
struct store_run runs[num_stripes];
+ int common_flags = STORE_BACKEND_FLAGS;
/* Find a common block size. */
for (i = 0; i < num_stripes; i++)
@@ -173,31 +191,34 @@ store_ileave_create (struct store *const *stripes, size_t num_stripes,
for (i = 0; i < num_stripes; i++)
{
/* The stripe's end adjusted to the common block size. */
- off_t end = stripes[i]->end;
+ store_offset_t end = stripes[i]->end;
runs[i].start = 0;
runs[i].length = interleave;
if (stripes[i]->block_size != block_size)
end /= (block_size / stripes[i]->block_size);
-
+
if (min_end < 0)
min_end = end;
else if (min_end > end)
/* Only use as much space as the smallest stripe has. */
min_end = end;
- }
- *store = _make_store (&ileave_class, MACH_PORT_NULL, flags, block_size,
- runs, num_stripes, min_end);
- if (! *store)
- return ENOMEM;
+ common_flags &= stripes[i]->flags;
+ }
- (*store)->wrap_dst = interleave;
+ err = _store_create (&store_ileave_class, MACH_PORT_NULL,
+ common_flags | flags, block_size,
+ runs, num_stripes, min_end, store);
+ if (! err)
+ {
+ (*store)->wrap_dst = interleave;
- err = store_set_children (*store, stripes, num_stripes);
- if (err)
- store_free (*store);
+ err = store_set_children (*store, stripes, num_stripes);
+ if (err)
+ store_free (*store);
+ }
return err;
}
@@ -212,7 +233,8 @@ store_concat_create (struct store * const *stores, size_t num_stores,
{
size_t i;
error_t err;
- off_t block_size = 1;
+ size_t block_size = 1;
+ int common_flags = STORE_BACKEND_FLAGS;
struct store_run runs[num_stores];
/* Find a common block size. */
@@ -223,16 +245,49 @@ store_concat_create (struct store * const *stores, size_t num_stores,
{
runs[i].start = 0;
runs[i].length = stores[i]->end;
+ common_flags &= stores[i]->flags;
}
- *store = _make_store (&concat_class, MACH_PORT_NULL, flags, block_size,
- runs, num_stores * 2, 0);
- if (! *store)
- return ENOMEM;
+ err = _store_create (&store_concat_class, MACH_PORT_NULL,
+ flags | common_flags, block_size,
+ runs, num_stores, 0, store);
+ if (! err)
+ {
+ err = store_set_children (*store, stores, num_stores);
+ if (! err)
+ {
+ err = store_children_name (*store, &(*store)->name);
+ if (err == EINVAL)
+ err = 0; /* Can't find a name; deal. */
+ }
+ if (err)
+ store_free (*store);
+ }
- err = store_set_children (*store, stores, num_stores);
- if (err)
- store_free (*store);
+ return err;
+}
+/* Return a new store that concatenates the stores created by opening all the
+ individual stores described in NAME; for the syntax of NAME, see
+ store_open_children. */
+error_t
+store_concat_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store **stores;
+ size_t num_stores;
+ error_t err =
+ store_open_children (name, flags, classes, &stores, &num_stores);
+ if (! err)
+ {
+ err = store_concat_create (stores, num_stores, flags, store);
+ if (err)
+ {
+ size_t k;
+ for (k = 0; k < (*store)->num_children; k++)
+ store_free ((*store)->children[k]);
+ }
+ }
return err;
}
diff --git a/libstore/task.c b/libstore/task.c
new file mode 100644
index 00000000..ea1475c8
--- /dev/null
+++ b/libstore/task.c
@@ -0,0 +1,205 @@
+/* Mach task store backend
+
+ Copyright (C) 1995,96,97,2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <hurd.h>
+
+#include <mach/machine/vm_param.h>
+
+#include "store.h"
+
+static process_t
+proc_server ()
+{
+ static process_t proc = MACH_PORT_NULL;
+ if (proc == MACH_PORT_NULL)
+ proc = getproc ();
+ return proc;
+}
+
+static error_t
+topen (const char *name, task_t *task)
+{
+ char *name_end;
+ pid_t pid = strtoul (name, &name_end, 0);
+
+ if (*name == '\0' || *name_end != '\0')
+ return EINVAL;
+
+ return proc_pid2task (proc_server (), pid, task);
+}
+
+static void
+tclose (struct store *store)
+{
+ mach_port_deallocate (mach_task_self (), store->port);
+ store->port = MACH_PORT_NULL;
+}
+
+static error_t
+task_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount, void **buf, size_t *len)
+{
+ size_t bsize = store->block_size;
+ return vm_read (store->port, addr * bsize, amount, (vm_address_t *)buf, len);
+}
+
+static error_t
+task_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ size_t bsize = store->block_size;
+ error_t err = vm_write (store->port, addr * bsize, (vm_address_t)buf, len);
+ if (! err)
+ *amount = len;
+ return err;
+}
+
+static error_t
+task_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+static error_t
+task_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_std_leaf_decode (enc, _store_task_create, store);
+}
+
+static error_t
+task_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_task_open (name, flags, store);
+}
+
+static error_t
+task_set_flags (struct store *store, int flags)
+{
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ /* Trying to set flags we don't support. */
+ return EINVAL;
+
+ if ((flags & STORE_ENFORCED)
+ && (store->num_runs > 0
+ || store->runs[0].start != 0
+ || store->runs[0].length != (VM_MAX_ADDRESS >> store->log2_block_size)))
+ /* Kernel only enforces the whole thing... */
+ return EINVAL;
+
+ if (flags & STORE_INACTIVE)
+ tclose (store);
+
+ store->flags |= flags; /* When inactive, anything goes. */
+
+ return 0;
+}
+
+static error_t
+task_clear_flags (struct store *store, int flags)
+{
+ error_t err = 0;
+ if ((flags & ~(STORE_INACTIVE | STORE_ENFORCED)) != 0)
+ err = EINVAL;
+ if (!err && (flags & STORE_INACTIVE))
+ err = store->name ? topen (store->name, &store->port) : ESRCH;
+ if (! err)
+ store->flags &= ~flags;
+ return err;
+}
+
+const struct store_class
+store_task_class =
+{
+ STORAGE_TASK, "task", task_read, task_write, task_set_size,
+ store_std_leaf_allocate_encoding, store_std_leaf_encode, task_decode,
+ task_set_flags, task_clear_flags, 0, 0, 0, task_open
+};
+STORE_STD_CLASS (task);
+
+/* Return a new store in STORE referring to the mach task TASK. Consumes
+ the send right TASK. */
+error_t
+store_task_create (task_t task, int flags, struct store **store)
+{
+ struct store_run run;
+
+ run.start = 0;
+ run.length = VM_MAX_ADDRESS / vm_page_size;
+
+ flags |= STORE_ENFORCED; /* 'cause it's the whole task. */
+
+ return _store_task_create (task, flags, vm_page_size, &run, 1, store);
+}
+
+/* Like store_task_create, but doesn't query the task for information. */
+error_t
+_store_task_create (task_t task, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ error_t err = 0;
+
+ if (block_size >= vm_page_size)
+ err = _store_create (&store_task_class,
+ task, flags, block_size, runs, num_runs, 0, store);
+ else
+ err = EINVAL; /* block size less than page size. */
+
+ if (! err)
+ {
+ pid_t pid;
+
+ err = proc_task2pid (proc_server (), task, &pid);
+ if (! err)
+ {
+ char buf[20];
+ snprintf (buf, sizeof buf, "%u", pid);
+ err = store_set_name (*store, buf);
+ }
+
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* Open the task NAME, and return the corresponding store in STORE. */
+error_t
+store_task_open (const char *name, int flags, struct store **store)
+{
+ task_t task;
+ error_t err = topen (name, &task);
+
+ if (! err)
+ {
+ err = store_task_create (task, flags, store);
+ if (err)
+ mach_port_deallocate (mach_task_self (), task);
+ }
+
+ return err;
+}
diff --git a/libstore/typed.c b/libstore/typed.c
new file mode 100644
index 00000000..b1be747d
--- /dev/null
+++ b/libstore/typed.c
@@ -0,0 +1,177 @@
+/* Support for opening `typed' stores
+
+ Copyright (C) 1997,1998,2001,2002,2003,2004 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "store.h"
+#include <string.h>
+#include <dlfcn.h>
+#include <link.h>
+
+
+const struct store_class *
+store_find_class (const char *name, const char *clname_end,
+ const struct store_class *const *classes)
+{
+ const struct store_class *const *cl;
+
+ if (! clname_end)
+ clname_end = strchr (name, '\0');
+
+ if (classes != 0)
+ {
+ /* The caller gave a class list, so that's is all we'll use. */
+ for (cl = classes; *cl != 0; ++cl)
+ if (strlen ((*cl)->name) == (clname_end - name)
+ && !memcmp (name, (*cl)->name, (clname_end - name)))
+ break;
+ return *cl;
+ }
+
+ /* Check the statically-linked set of classes found in the
+ "store_std_classes" section. For static linking, this is the section
+ in the program executable itself and it has been populated by the set
+ of -lstore_TYPE pseudo-libraries included in the link. For dynamic
+ linking with just -lstore, these symbols will be found in libstore.so
+ and have the set statically included when the shared object was built.
+ If a dynamically-linked program has its own "store_std_classes"
+ section, e.g. by -lstore_TYPE objects included in the link, this will
+ be just that section and libstore.so itself is covered below. */
+ for (cl = __start_store_std_classes; cl < __stop_store_std_classes; ++cl)
+ if (strlen ((*cl)->name) == (clname_end - name)
+ && strncmp (name, (*cl)->name, (clname_end - name)) == 0)
+ return *cl;
+
+ /* Now we will iterate through all of the dynamic objects loaded
+ and examine each one's "store_std_classes" section. */
+# pragma weak _r_debug
+# pragma weak dlsym
+# pragma weak dlopen
+# pragma weak dlclose
+# pragma weak dlerror
+ if (dlsym)
+ {
+ struct link_map *map;
+ for (map = _r_debug.r_map; map != 0; map = map->l_next)
+ {
+ const struct store_class *const *start, *const *stop;
+
+ /* We cannot just use MAP directly because it may not have been
+ opened by dlopen such that its data structures are fully set
+ up for dlsym. */
+ void *module = dlopen (map->l_name, RTLD_NOLOAD);
+ if (module == 0)
+ {
+ (void) dlerror (); /* Required to avoid a leak! */
+ continue;
+ }
+
+ start = dlsym (map, "__start_store_std_classes");
+ if (start == 0)
+ (void) dlerror (); /* Required to avoid a leak! */
+ else if (start != __start_store_std_classes) /* */
+ {
+ stop = dlsym (map, "__stop_store_std_classes");
+ if (stop == 0)
+ (void) dlerror (); /* Required to avoid a leak! */
+ else
+ for (cl = start; cl < stop; ++cl)
+ if (strlen ((*cl)->name) == (clname_end - name)
+ && strncmp (name, (*cl)->name, (clname_end - name)) == 0)
+ {
+ dlclose (module);
+ return *cl;
+ }
+ }
+ dlclose (module);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Open the store indicated by NAME, which should consist of a store type
+ name followed by a ':' and any type-specific name, returning the new store
+ in STORE. If NAME doesn't contain a `:', then it will be interpreted as
+ either a class name, if such a class occurs in CLASSES, or a filename,
+ which is opened by calling store_open on NAME; a `:' at the end or the
+ beginning of NAME unambiguously causes the remainder to be treated as a
+ class-name or a filename, respectively. CLASSES is used to select classes
+ specified by the type name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+store_typed_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ const struct store_class *cl;
+ const char *clname_end = strchrnul (name, ':');
+
+ if (clname_end == name && *clname_end)
+ /* Open NAME with store_open. */
+ return store_open (name + 1, flags, classes, store);
+
+ /* Try to find an existing class by the given name. */
+ cl = store_find_class (name, clname_end, classes);
+ if (cl != 0)
+ {
+ if (! cl->open)
+ /* CL cannot be opened. */
+ return EOPNOTSUPP;
+
+ if (*clname_end)
+ /* Skip the ':' separating the class-name from the device name. */
+ clname_end++;
+
+ if (! *clname_end)
+ /* The class-specific portion of the name is empty, so make it *really*
+ empty. */
+ clname_end = 0;
+
+ return (*cl->open) (clname_end, flags, classes, store);
+ }
+
+ /* Try to open a store by loading a module to define the class, if we
+ have the module-loading support linked in. We don't just use
+ store_module_find_class, because store_module_open will unload the new
+ module if the open doesn't succeed and we have no other way to unload
+ it. We always leave modules loaded once a store from the module has
+ been successfully opened and so can leave unbounded numbers of old
+ modules loaded after closing all the stores using them. But at least
+ we can avoid having modules loaded for stores we never even opened. */
+# pragma weak store_module_open
+ if (store_module_open)
+ {
+ error_t err = store_module_open (name, flags, classes, store);
+ if (err != ENOENT)
+ return err;
+ }
+
+ /* No class with the given name found. */
+ if (*clname_end)
+ /* NAME really should be a class name, which doesn't exist. */
+ return EINVAL;
+ else
+ /* Try opening NAME by querying it as a file instead. */
+ return store_open (name, flags, classes, store);
+}
+
+const struct store_class
+store_typed_open_class = { -1, "typed", open: store_typed_open };
+STORE_STD_CLASS (typed_open);
diff --git a/libstore/unknown.c b/libstore/unknown.c
new file mode 100644
index 00000000..8b7f4268
--- /dev/null
+++ b/libstore/unknown.c
@@ -0,0 +1,231 @@
+/* Store backend for unknown encodings
+
+ Copyright (C) 2001,02 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "store.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+/* You can't do anything with an unknown store but encode it. */
+
+static error_t
+noread (struct store *store, store_offset_t addr, size_t index,
+ size_t amount, void **buf, size_t *len)
+{
+ return EFTYPE;
+}
+
+static error_t
+nowrite (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ return EFTYPE;
+}
+
+static error_t
+noset_size (struct store *store, size_t newsize)
+{
+ return EFTYPE;
+}
+
+static error_t
+noflags (struct store *store, int flags)
+{
+ return EINVAL;
+}
+
+/* This is the only way that stores of the "unknown" class get created.
+ We save the store encoding verbatim and regurgitate it as our own. */
+
+static struct store_enc *
+duplicate_encoding (struct store_enc *enc)
+{
+ struct store_enc *us;
+ size_t i;
+
+ us = calloc (1, sizeof *us);
+ if (us == NULL)
+ return NULL;
+
+ us->ports = mmap (0, enc->num_ports * sizeof *enc->ports,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->ports == MAP_FAILED)
+ {
+ no_memory:
+ store_enc_dealloc (us);
+ free (us);
+ return NULL;
+ }
+ us->ints = mmap (0, enc->num_ints * sizeof *enc->ints,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->ints == MAP_FAILED)
+ goto no_memory;
+ us->offsets = mmap (0, enc->num_offsets * sizeof *enc->offsets,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->offsets == MAP_FAILED)
+ goto no_memory;
+ us->data = mmap (0, enc->data_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (us->data == MAP_FAILED)
+ goto no_memory;
+
+ memcpy (us->ports, enc->ports, enc->num_ports * sizeof *enc->ports);
+ memcpy (us->ints, enc->ints, enc->num_ints * sizeof *enc->ints);
+ memcpy (us->offsets, enc->offsets, enc->num_offsets * sizeof *enc->offsets);
+ memcpy (us->data, enc->data, enc->data_len);
+
+ us->num_ports = enc->num_ports;
+ us->num_ints = enc->num_ints;
+ us->num_offsets = enc->num_offsets;
+ us->data_len = enc->data_len;
+
+ for (i = 0; i < us->num_ports; ++i)
+ mach_port_mod_refs (mach_task_self (), us->ports[i],
+ MACH_PORT_RIGHT_SEND, +1);
+
+ return us;
+}
+
+error_t
+store_unknown_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store_enc *us;
+ error_t err = _store_create (&store_unknown_class,
+ MACH_PORT_NULL, STORE_ENFORCED, 0, NULL, 0, 0,
+ store);
+ if (err)
+ return err;
+
+ us = duplicate_encoding (enc);
+ if (us == NULL)
+ {
+ store_free (*store);
+ return ENOMEM;
+ }
+ (*store)->hook = us;
+
+ /* Derive a name for this unknown store from its encoded type field
+ (or lack thereof) and the leading string of its encoded data bytes. */
+ if (enc->cur_int == enc->num_ints)
+ asprintf (&(*store)->name, "notype:%.*s",
+ (int) (us->data_len - us->cur_data), us->data + us->cur_data);
+ else
+ asprintf (&(*store)->name, "type-%d:%.*s", enc->ints[enc->cur_int],
+ (int) ( us->data_len - us->cur_data), us->data + us->cur_data);
+
+ return 0;
+}
+
+/* Re-encode just the way we got it. */
+error_t
+unknown_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ const struct store_enc *us = store->hook;
+ if (us == NULL)
+ return EOPNOTSUPP;
+ enc->num_ports += us->num_ports;
+ enc->num_ints += us->num_ints;
+ enc->num_offsets += us->num_offsets;
+ enc->data_len += us->data_len;
+ return 0;
+}
+
+error_t
+unknown_encode (const struct store *store, struct store_enc *enc)
+{
+ const struct store_enc *us = store->hook;
+ if (us == NULL)
+ return EOPNOTSUPP;
+
+ memcpy (enc->ports, us->ports, us->num_ports * sizeof enc->ports[0]);
+ enc->ports += us->num_ports;
+ memcpy (enc->ints, us->ints, us->num_ints * sizeof enc->ints[0]);
+ enc->ints += us->num_ints;
+ memcpy (enc->offsets, us->offsets, us->num_offsets * sizeof enc->offsets[0]);
+ enc->offsets += us->num_offsets;
+ memcpy (enc->data + enc->cur_data, us->data, us->data_len);
+ enc->cur_data += us->data_len;
+
+ return 0;
+}
+
+
+/* Called just before deallocating STORE. */
+static void
+unknown_cleanup (struct store *store)
+{
+ if (store->hook != NULL)
+ {
+ store_enc_dealloc (store->hook);
+ free (store->hook);
+ }
+}
+
+/* Copy any format-dependent fields in FROM to TO; if there's some reason
+ why the copy can't be made, an error should be returned. This call is
+ made after all format-independent fields have been cloned. */
+static error_t
+unknown_clone (const struct store *from, struct store *to)
+{
+ if (from->hook == NULL)
+ return 0;
+ to->hook = duplicate_encoding (from->hook);
+ return to->hook ? 0 : ENOMEM;
+}
+
+/* Unknown stores cannot be opened with a name. */
+static error_t
+unknown_validate_name (const char *name,
+ const struct store_class *const *classes)
+{
+ return name == NULL ? 0 : EINVAL;
+}
+
+static error_t
+unknown_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ return (name == NULL
+ ? _store_create (&store_unknown_class, MACH_PORT_NULL,
+ STORE_ENFORCED, 0, NULL, 0, 0, store)
+ : EINVAL);
+}
+
+const struct store_class store_unknown_class =
+{
+ -1, "unknown",
+ read: noread,
+ write: nowrite,
+ set_size: noset_size,
+ allocate_encoding: unknown_allocate_encoding,
+ encode: unknown_encode,
+ decode: store_unknown_decode,
+ set_flags: noflags,
+ clear_flags: noflags,
+ cleanup: unknown_cleanup,
+ clone: unknown_clone,
+ open: unknown_open,
+ validate_name: unknown_validate_name,
+};
+STORE_STD_CLASS (unknown);
diff --git a/libstore/unzipstore.c b/libstore/unzipstore.c
new file mode 100644
index 00000000..35e9e7af
--- /dev/null
+++ b/libstore/unzipstore.c
@@ -0,0 +1,267 @@
+/* Decompressing store backend (common code for gunzip and bunzip2)
+
+ Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
+ Written by okuji@kuicr.kyoto-u.ac.jp <okuji@kuicr.kyoto-u.ac.jp>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <cthreads.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+#define IN_BUFFERING (256*1024)
+#define OUT_BUFFERING (512*1024)
+
+static struct mutex unzip_lock = MUTEX_INITIALIZER;
+
+#define STORE_UNZIP(name) STORE_UNZIP_1 (UNZIP, name)
+#define STORE_UNZIP_1(unzip,name) STORE_UNZIP_2 (unzip, name)
+#define STORE_UNZIP_2(unzip,name) store_##unzip##_##name
+#define STORE_STD_CLASS_1(name) STORE_STD_CLASS(name)
+#define STRINGIFY(name) STRINGIFY_1(name)
+#define STRINGIFY_1(name) #name
+
+
+/* Uncompress the contents of FROM, which should contain a valid bzip2 file,
+ into memory, returning the result buffer in BUF & BUF_LEN. */
+static error_t
+unzip_store (struct store *from, void **buf, size_t *buf_len)
+{
+ /* Callbacks from decompression engine for I/O and error interface. */
+ extern int (*unzip_read) (char *buf, size_t maxread);
+ extern void (*unzip_write) (const char *buf, size_t nwrite);
+ extern void (*unzip_read_error) (void);
+ extern void (*unzip_error) (const char *msg);
+
+ /* How we return errors from our hook functions. */
+ jmp_buf zerr_jmp_buf;
+ error_t zerr;
+
+ /* vm_alloced buffer for the input store. */
+ void *in_buf = 0;
+ size_t in_buf_len = 0; /* Amount of valid data in IN_BUF. */
+ size_t in_buf_size = 0; /* Allocated space for IN_BUF. */
+ size_t in_buf_offs = 0; /* Offset of read point in IN_BUF. */
+ off_t in_buf_addr = 0; /* Address in FROM of *next* IN_BUF. */
+
+ /* Buffer input in units that are least IN_BUFFERING bytes, but are also a
+ multiple of FROM's block size. */
+ size_t in_addr_mask = ((1 << from->log2_block_size) - 1);
+ size_t in_buffering = ((IN_BUFFERING + in_addr_mask) & ~in_addr_mask);
+
+ /* Read at most MAXREAD (or 0 if eof) bytes into BUF from our current
+ position in FROM. */
+ int zread (char *buf, size_t maxread)
+ {
+ size_t did_read = 0;
+
+ while (maxread > 0)
+ {
+ size_t left = in_buf_len - in_buf_offs;
+
+ if (left > 0)
+ /* Fill BUF with what we can from IN_BUF. */
+ {
+ if (left > maxread)
+ left = maxread;
+ bcopy (in_buf + in_buf_offs, buf, left);
+ in_buf_offs += left;
+ buf += left;
+ maxread -= left;
+ did_read += left;
+ }
+
+ /* Limit MAXREAD to the number of bytes left in the input. */
+ if (maxread > (from->size - (in_buf_addr << from->log2_block_size)))
+ maxread = from->size - (in_buf_addr << from->log2_block_size);
+
+ if (maxread > 0)
+ /* Have to fill IN_BUF again. */
+ {
+ void *new_in_buf = in_buf;
+ size_t new_in_buf_len = in_buf_len;
+
+ zerr = store_read (from, in_buf_addr, in_buffering,
+ &new_in_buf, &new_in_buf_len);
+ if (zerr)
+ longjmp (zerr_jmp_buf, 1);
+
+ in_buf_addr += (new_in_buf_len >> from->log2_block_size);
+
+ if (new_in_buf != in_buf)
+ {
+ if (in_buf_size > 0)
+ munmap (in_buf, in_buf_size);
+ in_buf = new_in_buf;
+ in_buf_size = new_in_buf_len;
+ }
+
+ in_buf_len = new_in_buf_len;
+ in_buf_offs = 0;
+ }
+ }
+ return did_read;
+ }
+
+ size_t out_buf_offs = 0; /* Position in the output buffer. */
+
+ /* Write compress data to our output buffer. */
+ void zwrite (const char *wbuf, size_t nwrite)
+ {
+ size_t old_buf_len = *buf_len;
+
+ if (out_buf_offs + nwrite > old_buf_len)
+ /* Have to grow the output buffer. */
+ {
+ void *old_buf = *buf;
+ void *new_buf = old_buf + old_buf_len; /* First try. */
+ size_t new_buf_len = round_page (old_buf_len + old_buf_len + nwrite);
+
+ /* Try to grow the buffer. */
+ zerr =
+ vm_allocate (mach_task_self (),
+ (vm_address_t *)&new_buf, new_buf_len - old_buf_len,
+ 0);
+ if (zerr)
+ /* Can't do that, try to make a bigger buffer elsewhere. */
+ {
+ new_buf = mmap (0, new_buf_len, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ zerr = (new_buf == (void *) -1) ? errno : 0;
+ if (zerr)
+ longjmp (zerr_jmp_buf, 1);
+
+ if (out_buf_offs > 0)
+ /* Copy the old buffer into the start of the new & free it. */
+ bcopy (old_buf, new_buf, out_buf_offs);
+
+ munmap (old_buf, old_buf_len);
+
+ *buf = new_buf;
+ }
+
+ *buf_len = new_buf_len;
+ }
+
+ bcopy (wbuf, *buf + out_buf_offs, nwrite);
+ out_buf_offs += nwrite;
+ }
+
+ void zreaderr (void)
+ {
+ zerr = EIO;
+ longjmp (zerr_jmp_buf, 1);
+ }
+ void zerror (const char *msg)
+ {
+ zerr = EINVAL;
+ longjmp (zerr_jmp_buf, 2);
+ }
+
+ /* Try to guess a reasonable output buffer size. */
+ *buf_len = round_page (from->size * 2);
+ *buf = mmap (0, *buf_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ zerr = (*buf == (void *) -1) ? errno : 0;
+ if (zerr)
+ return zerr;
+
+ mutex_lock (&unzip_lock);
+
+ unzip_read = zread;
+ unzip_write = zwrite;
+ unzip_read_error = zreaderr;
+ unzip_error = zerror;
+
+ if (! setjmp (zerr_jmp_buf))
+ {
+ /* Call the decompression engine. */
+ zerr = DO_UNZIP ();
+ }
+
+ mutex_unlock (&unzip_lock);
+
+ if (in_buf_size > 0)
+ munmap (in_buf, in_buf_size);
+
+ if (zerr)
+ {
+ if (*buf_len > 0)
+ munmap (*buf, *buf_len);
+ }
+ else if (out_buf_offs < *buf_len)
+ /* Trim the output buffer to be the right length. */
+ {
+ size_t end = round_page (out_buf_offs);
+ if (end < *buf_len)
+ munmap (*buf + end, *buf_len - end);
+ *buf_len = out_buf_offs;
+ }
+
+ return zerr;
+}
+
+
+/* Return a new store in STORE which contains a snapshot of the uncompressed
+ contents of the store FROM; FROM is consumed. */
+error_t
+STORE_UNZIP(create) (struct store *from, int flags, struct store **store)
+{
+ void *buf;
+ size_t buf_len;
+ error_t err = unzip_store (from, &buf, &buf_len);
+
+ if (! err)
+ {
+ err = store_buffer_create (buf, buf_len, flags, store);
+ if (err)
+ munmap (buf, buf_len);
+ else
+ store_free (from);
+ }
+
+ return err;
+}
+
+/* Open the compressed store NAME -- which consists of another store-class
+ name, a ':', and a name for that store class to open -- and return the
+ corresponding store in STORE. CLASSES is used to select classes
+ specified by the type name; if it is 0, STORE_STD_CLASSES is used. */
+error_t
+STORE_UNZIP(open) (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store *from;
+ error_t err =
+ store_typed_open (name, flags | STORE_HARD_READONLY, classes, &from);
+
+ if (! err)
+ {
+ err = STORE_UNZIP(create) (from, flags, store);
+ if (err)
+ store_free (from);
+ }
+
+ return err;
+}
+
+const struct store_class STORE_UNZIP(class) =
+{ -1, STRINGIFY(UNZIP), open: STORE_UNZIP(open) };
+STORE_STD_CLASS_1 (UNZIP);
diff --git a/libstore/url.c b/libstore/url.c
new file mode 100644
index 00000000..9b5f524e
--- /dev/null
+++ b/libstore/url.c
@@ -0,0 +1,92 @@
+/* Support for opening stores named in URL syntax.
+
+ Copyright (C) 2001,02 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "store.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+/* Similar to store_typed_open, but NAME must be in URL format,
+ i.e. a class name followed by a ':' and any type-specific name.
+ Store classes opened this way must strip off the "class:" prefix.
+ A leading ':' or no ':' at all is invalid syntax. */
+
+error_t
+store_url_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ if (name == 0 || name[0] == ':' || strchr (name, ':') == 0)
+ return EINVAL;
+
+ return store_typed_open (name, flags, classes, store);
+}
+
+error_t
+store_url_decode (struct store_enc *enc,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ const struct store_class *cl;
+
+ /* This is pretty bogus. We use decode.c's code just to validate
+ the generic format and extract the name from the data. */
+ struct store dummy, *dummyptr;
+ error_t dummy_create (mach_port_t port, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+ {
+ *store = &dummy;
+ return 0;
+ }
+ struct store_enc dummy_enc = *enc;
+ error_t err = store_std_leaf_decode (&dummy_enc, &dummy_create, &dummyptr);
+ if (err)
+ return err;
+
+ /* Find the class matching this name. */
+ cl = store_find_class (dummy.name, strchr (dummy.name, ':'), classes);
+# pragma weak store_module_find_class
+ if (cl == 0 && store_module_find_class)
+ err = store_module_find_class (dummy.name, strchr (dummy.name, ':'),
+ &cl);
+ free (dummy.name);
+ free (dummy.misc);
+
+ if (cl == 0)
+ return EINVAL;
+
+ /* Now that we have the class, we just punt to its own decode hook. */
+
+ return (!cl->decode ? EOPNOTSUPP : (*cl->decode) (enc, classes, store));
+}
+
+/* This class is only trivially different from the "typed" class when used
+ by name. Its real purpose is to decode file_get_storage_info results
+ that use the STORAGE_NETWORK type, for which the convention is that the
+ name be in URL format (i.e. "type:something"). */
+
+const struct store_class store_url_open_class =
+{
+ STORAGE_NETWORK, "url",
+ open: store_url_open,
+ decode: store_url_decode
+};
+STORE_STD_CLASS (url_open);
diff --git a/libstore/xinl.c b/libstore/xinl.c
new file mode 100644
index 00000000..90242212
--- /dev/null
+++ b/libstore/xinl.c
@@ -0,0 +1,2 @@
+#define STORE_DEFINE_EI
+#include "store.h"
diff --git a/libstore/zero.c b/libstore/zero.c
new file mode 100644
index 00000000..2fba72cc
--- /dev/null
+++ b/libstore/zero.c
@@ -0,0 +1,196 @@
+/* Zero store backend
+
+ Copyright (C) 1995,96,97,99,2000,01, 02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with 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 <string.h>
+#include <limits.h>
+#include <sys/mman.h>
+
+#include "store.h"
+
+static error_t
+zero_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount, void **buf,
+ size_t *len)
+{
+ if (*len < amount)
+ {
+ *buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == MAP_FAILED)
+ return errno;
+ *len = amount;
+ return 0;
+ }
+ else
+ memset (*buf, 0, amount);
+
+ *len = amount;
+ return 0;
+}
+
+static error_t
+zero_write (struct store *store,
+ store_offset_t addr, size_t index, const void *buf, size_t len,
+ size_t *amount)
+{
+ return 0;
+}
+
+static error_t
+zero_set_size (struct store *store, size_t newsize)
+{
+ return EOPNOTSUPP;
+}
+
+/* Modify SOURCE to reflect those runs in RUNS, and return it in STORE. */
+error_t
+zero_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ /* Because all blocks are the same, a zero store always contains just one
+ run; here we simply count up the number of blocks specified by RUNS, and
+ modify SOURCE's one run to reflect that. */
+ int i;
+ store_offset_t length = 0, old_length = source->runs[0].length;
+ for (i = 0; i < num_runs; i++)
+ if (runs[i].start < 0 || runs[i].start + runs[i].length >= old_length)
+ return EINVAL;
+ else
+ length += runs[i].length;
+ source->runs[0].length = length;
+ *store = source;
+ return 0;
+}
+
+error_t
+zero_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ enc->num_ints += 2;
+ enc->num_offsets += 1;
+ return 0;
+}
+
+error_t
+zero_encode (const struct store *store, struct store_enc *enc)
+{
+ enc->ints[enc->cur_int++] = store->class->id;
+ enc->ints[enc->cur_int++] = store->flags;
+ enc->offsets[enc->cur_offset++] = store->size;
+ return 0;
+}
+
+error_t
+zero_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ store_offset_t size;
+ int type, flags;
+
+ if (enc->cur_int + 2 > enc->num_ints
+ || enc->cur_offset + 1 > enc->num_offsets)
+ return EINVAL;
+
+ type = enc->ints[enc->cur_int++];
+ flags = enc->ints[enc->cur_int++];
+ size = enc->offsets[enc->cur_offset++];
+
+ return store_zero_create (size, flags, store);
+}
+
+static error_t
+zero_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ if (name)
+ {
+ char *end;
+ store_offset_t size = strtoull (name, &end, 0);
+ if (end == name || end == NULL)
+ return EINVAL;
+ switch (*end)
+ {
+ case 'b':
+ size *= 512;
+ break;
+ case 'k':
+ case 'K':
+ size *= 1024;
+ break;
+ case 'm':
+ case 'M':
+ size *= 1024 * 1024;
+ break;
+ case 'g':
+ case 'G':
+ size *= 1024 * 1024 * 1024;
+ break;
+ }
+ return store_zero_create (size, flags, store);
+ }
+ else
+ {
+ store_offset_t max_offs = ~((store_offset_t)1
+ << (CHAR_BIT * sizeof (store_offset_t) - 1));
+ return store_zero_create (max_offs, flags, store);
+ }
+}
+
+static error_t
+zero_validate_name (const char *name, const struct store_class *const *classes)
+{
+ if (name)
+ {
+ char *end;
+ strtoul (name, &end, 0);
+ return end == name ? EINVAL : 0;
+ }
+ else
+ return 0; /* `maximum size' */
+}
+
+static error_t
+zero_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ *memobj = MACH_PORT_NULL;
+ return 0;
+}
+
+const struct store_class
+store_zero_class =
+{
+ STORAGE_ZERO, "zero", zero_read, zero_write, zero_set_size,
+ zero_allocate_encoding, zero_encode, zero_decode,
+ 0, 0, 0, 0, zero_remap, zero_open, zero_validate_name,
+ zero_map
+};
+STORE_STD_CLASS (zero);
+
+/* Return a new zero store SIZE bytes long in STORE. */
+error_t
+store_zero_create (store_offset_t size, int flags, struct store **store)
+{
+ struct store_run run = { 0, size };
+ return
+ _store_create (&store_zero_class, MACH_PORT_NULL,
+ flags | STORE_INNOCUOUS, 1, &run, 1, 0, store);
+}
diff --git a/libthreads/ChangeLog b/libthreads/ChangeLog
deleted file mode 100644
index ebb6a424..00000000
--- a/libthreads/ChangeLog
+++ /dev/null
@@ -1,269 +0,0 @@
-Sat Jul 20 15:47:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (lndist-i386-files): Look for I386SRCS and I386HDRS in
- $(srcdir).
-
-Thu Jun 6 07:29:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * malloc.c (more_memory): Use assert_perror instead of MACH_CALL.
- "cthread_internals.h": Include removed.
-
-Thu May 9 11:13:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (installhdrs, installhdrsubdir): Install headers using
- the generic technique, now that installhdrsubdir is available.
-
- * rwlock.h: If _RWLOCK_DEFINE_FUNCTIONS is defined, then clear
- _EXTERN_INLINE, but *after* header files have been included.
- * rwlock.c (_RWLOCK_DEFINE_FUNCTIONS): New macro; use in place of
- clearing _EXTERN_INLINE, which conflicts with machine-sp.h.
-
-Sat May 4 05:33:57 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * cthreads.h [lint] (NEVER): Spurious global variable removed.
- [!lint] (NEVER): Useless macro removed.
-
- * Makefile (SRCS): Add rwlock.c.
- (LCLHDRS): Add rwlock.h.
- (install): Depend on $(includedir)/rwlock.h.
- ($(includedir)/%.h: %.h): New rule.
- ($(includedir)/cthreads.h): Target removed, obviated by that rule.
- * rwlock.h: Moved to libthreads from libshouldbeinlibc.
- (_EXTERN_INLINE): New macro.
- Use it for all the inline defns.
- * rwlock.c: New file.
-
-Thu Apr 11 17:55:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (CFLAGS): Turn off -Wall.
-
- * Makefile (VPATH): Fix up for new configure reality.
-
-Thu Mar 7 15:52:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * malloc.c (realloc): Use LOG2_MIN_SIZE.
- (LOG2_MIN_SIZE): New macro.
-
- * malloc.c (realloc): Don't bother allocating a new block if the
- new size request fits in the old one and doesn't waste any space.
- Only free the old block if we successfully got a new one.
-
-Wed Mar 6 18:05:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * malloc.c [MCHECK] (struct header): New type.
- (union header): Only define if !MCHECK.
- (HEADER_SIZE, HEADER_NEXT, HEADER_FREE, HEADER_CHECK): New macros.
- [MCHECK] (MIN_SIZE): Add correct definition for this case.
- (more_memory, malloc, free, realloc): Use above macros, and add
- appropiate checks & frobs in MCHECK case.
-
-Wed Jan 31 20:05:57 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * cancel-cond.c: Add assert to check for signal bug.
-
-Wed Jan 24 13:38:11 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * cthreads.h: Use prototypes for functions of zero args.
-
-Sun Dec 10 08:41:36 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * stack.c (addr_range_check, probe_stack): Functions #if 0'd out.
- (stack_init): Don't call probe_stack or frob old stack at all.
- Default cthread_stack_size to 16 pages if it is zero.
-
-Wed Dec 6 14:48:37 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * cprocs.c (condition_unimplies): Take address of (*impp)->next in
- assignment to IMPP on loop step instruction.
-
-Wed Oct 4 16:22:27 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * i386/csw.S (JUMPTARGET): New macro, versions for [PIC] and not.
- Use it in place of EXT.
- * Makefile (csw_pic.o): Bogus braindead target from hell removed.
- Bushnell will be shot.
-
-Fri Sep 22 13:51:22 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * cprocs.c: Include hurd/threadvar.h.
-
-Sat Sep 16 13:42:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (CPPFLAGS): Variable removed.
- (lndist-i386-files): Use $(top_srcdir) in place of $(srcdir).
-
-Wed Sep 13 15:49:17 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * cthreads.h (CONDITION_INITIALIZER): Provide initial zero for
- IMPLICATIONS member.
- (condition_init): Bother initializing NAME and IMPLICATIONS members.
-
-Wed Aug 30 11:10:27 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * cthreads.h (condition_implies, condition_unimplies): New
- functions.
- (struct condition): New member `implications'.
- (cond_imp): New structure.
- (cond_signal): Return int now.
- (condition_broadcast): Always call cond_broadcast if this
- condition has implications.
- (condition_signal): Always call cond_signal if this condition has
- implications.
- * cprocs.c (cond_signal): If this condition has implications,
- see if one of them needs to be signalled when we have no waiters.
- (cond_broadcast): Signal the implications list too.
- (condition_implies, condition_unimplies): New functions.
-
- * cthreads.h (hurd_condition_wait): Provide declaration.
-
-Tue Aug 29 10:48:59 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * cthread_internals.h (cproc_block): Provide decl.
-
-Sat Aug 26 14:08:15 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * cancel-cond.c (hurd_condition_wait_cancel): Name changed to
- `hurd_condition_wait'.
-
-Tue Aug 22 19:26:38 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Add a backslash.
-
-Mon Aug 21 12:52:38 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Add cancel-cond.c.
- * cancel-cond.c: New file.
-
-Thu Jul 6 13:39:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (install): Don't *always* install cthreads.h; do it
- only if it's new.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
- * Makefile (csw_pic.o): Provide slightly cheating rule.
-
-Fri May 12 14:25:35 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * i386/csw.S: Use EXT macro instead of explicit underscores.
- * i386/asm.h: File removed; it is installed by libc.
- * Makefile (I386HDRS): Variable removed.
- ($(OBJS)): Don't depend on i386/asm.h.
-
- * Makefile (CPPFLAGS): Use $(srcdir) instead of $(hurdsource).
-
-Wed Apr 12 14:33:06 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (lndist, lndist-i386-files): Change $(hurdsource) to
- $(srcdir).
- ($(hurdsource)/hurd-snap/$(dir)/i386): Likewise.
-
-Tue Apr 4 17:04:45 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (CPPFLAGS): Define.
- ($(OBJS) rule): Fix typo in target.
- (install-cthreads.h): Use $(INSTALL_DATA).
-
- * cthreads.h (mutex_lock, mutex_unlock): Use __ names for *_solid.
- * cprocs.c (mutex_lock_solid, mutex_unlock_solid): Renamed to __*.
- (_cthread_mutex_lock_routine, _cthread_mutex_unlock_routine): Variables
- removed.
-
-Fri Jul 22 10:47:51 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
-
-Tue Jul 19 12:22:01 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (generic-sources): Restored malloc.c.
- (malloc-sources, malloc-objects): Deleted variables.
- (DIST_FILES): Deleted $(malloc-sources)
- (all): Deleted libmalloc.a.
- (libmalloc.a): Delted target.
- ($(hurdinst)/lib/libmalloc.a): Deleted target.
- (install): Deleted $(hurdinst)/lib/libmalloc.a.
- (clean): Deleted libmalloc.a.
-
-Tue Jul 5 14:17:28 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (SRCS, TAGSHDRS): New variables.
- (TAGS): Deleted local definition; now it's in Makeconf.
-
-Thu May 19 00:54:54 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * cprocs.c (_cthread_mutex_lock_routine,
- _cthread_mutex_unlock_routine): New variables.
-
-Thu May 5 19:33:49 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makefile: (generic-sources): Removed malloc.c.
- (malloc-sources, malloc-objects): new variables.
- (DIST_FILES): added $(malloc-sources).
- (libmalloc.a, $(hurdinst)/lib/libmalloc.a): New targets.
- ($(hurdinst)/lib/malloc.o): Deleted target.
- (all): added libmalloc.a.
- (install): Changed $(hurdinst)/lib/malloc.o to
- $(hurdinst)/lib/libmalloc.a
- (clean): Added libmaloc.a.
-
-Thu May 5 04:30:34 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * cthreads.c (cthread_init): Pass STACK instead of P to mig_init.
-
- * cprocs.c (cproc_create): Pass normal offset value to
- cproc_stack_base. Explicitly store CHILD ptr at base of its stack.
-
- * stack.c (stack_init): Set __hurd_threadvar_stack_mask to find
- the lowest address of the stack segment.
- [STACK_GROWTH_UP]: Set __hurd_threadvar_stack_offset to
- sizeof(ur_cthread_t*).
- [! STACK_GROWTH_UP]: Set __hurd_threadvar_stack_offset to the size
- of the stack minus space for the cproc_self ptr and thread variables.
-
- * malloc.c (malloc, free, realloc): Change declarations to
- standard types, so as not to conflict with the declarations in
- <stdlib.h>.
-
- * cthread_internals.h: #if 0 out declaration of malloc.
- (struct cproc): #if 0 out `reply_port' member; libc implements that.
- * cprocs.c (cproc_alloc): #if 0 out initialization of P->reply_port.
-
- * Makefile (generic-sources): Omit sync.c. libc implements that.
-
- * cprocs.c (cproc_block): Add __hurd_threadvar_max * sizeof (long
- int) to 2nd arg to cproc_stack_base.
-
- * stack.c: Include <hurd/threadvar.h>.
- (__hurd_threadvar_stack_mask, __hurd_threadvar_stack_offset,
- __hurd_threadvar_max): Define variables (uninitialized).
- (stack_init): Set __hurd_threadvar_stack_mask to cthread_stack_mask.
- Set __hurd_threadvar_stack_offset to point past the cproc_self ptr.
- Add __hurd_threadvar_max * sizeof (long int) to 2nd arg to
- cproc_stack_base.
-
- * cthreads.h: #if 0 include of <machine/cthreads.h>.
- Instead, include <machine-sp.h>.
- (cthread_sp): Define using __thread_stack_pointer.
- #if 0 out spin_lock definitions. Just include <spin-lock.h> instead.
- (struct mutex): Move `held' member to be first in the structure.
-
-Wed May 4 14:55:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * i386/thread.c: Changed inclusions because we aren't using
- -I flags the way CMU's makefiles do.
-
- * i386/csw.S: Convert comment character to /* */ pairs.
-
- * Renamed csw.s to csw.S so that GCC knows to run cpp on it.
- * Makefile (machine-sources): Change csw.s to csw.S.
-
-Wed May 4 07:11:46 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile (GEN_SRCS): Renamed generic-sources.
- (I386_SRCS): Replaced with machine-sources, omitting directory.
- (SRCS): Renamed sources. Include $(machine-sources) and prepend
- $(machine)/ directory name.
- (headers): Define variable.
- (OBJS): Renamed objects.
- (VPATH): Define to $(machine).
diff --git a/libthreads/Makefile b/libthreads/Makefile
index d915751a..e9fa571b 100644
--- a/libthreads/Makefile
+++ b/libthreads/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1994,95,96,97,2000,2010 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
@@ -15,15 +15,13 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# This is currently i386 specific. XXX
-
dir := libthreads
makemode := library
# In GNU mig_support.c, sync.c and machine/lock.s are omitted; that work is
# all done in libc.
-SRCS := call.c cprocs.c cthread_data.c cthreads.c stack.c malloc.c \
- cancel-cond.c rwlock.c
+SRCS := call.c cprocs.c cthread_data.c cthreads.c stack.c \
+ cancel-cond.c rwlock.c lockfile.c
I386SRCS := i386/csw.S i386/thread.c
# In GNU machine/cthreads.h is omitted; that work is done in libc headers.
@@ -37,7 +35,7 @@ libname = libthreads
installhdrs = cthreads.h rwlock.h
installhdrsubdir = .
-VPATH += $(srcdir)/$(machine)
+VPATH += $(srcdir)/$(asm_syntax)
include ../Makeconf
@@ -52,3 +50,16 @@ lndist-i386-files: $(top_srcdir)/hurd-snap/$(dir)/i386
$(top_srcdir)/hurd-snap/$(dir)/i386:
mkdir $@
+
+ifeq ($(VERSIONING),yes)
+
+# Adding this dependency gets it included in the command line,
+# where ld will read it as a linker script.
+$(libname).so.$(hurd-version): $(srcdir)/$(libname).map
+
+lndist: lndist-map-file
+
+lndist-map-file: $(top_srcdir)/hurd-snap/$(dir)
+ ln $(addprefix $(srcdir)/,$(libname).map) $<
+
+endif
diff --git a/libthreads/alpha/csw.S b/libthreads/alpha/csw.S
new file mode 100644
index 00000000..8c6ae309
--- /dev/null
+++ b/libthreads/alpha/csw.S
@@ -0,0 +1,200 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: csw.s,v $
+ * Revision 2.3 93/01/19 08:55:56 danner
+ * Locks are longs now. Put MBs before and after releasing
+ * locks.
+ * [93/01/15 af]
+ *
+ * Revision 2.2 93/01/14 18:04:23 danner
+ * Fixed bug in cproc_prepare, it was not setting up
+ * the PV register properly. Safer GP usage too.
+ * ANSIfied comments.
+ * [92/12/22 03:00:50 af]
+ *
+ * Created.
+ * [92/05/31 af]
+ *
+ */
+/*
+ * alpha/csw.s
+ *
+ * Context switch and cproc startup for ALPHA COROUTINE implementation.
+ */
+#include <mach/alpha/asm.h>
+
+ .text
+ .align 4
+
+#define CSW_IMASK \
+ IM_S0|IM_S1|IM_S2|IM_S3|IM_S4|IM_S5|IM_S6|IM_RA|IM_GP
+
+#define ARG_SAVE (6*8)
+#define SAVED_S0 (6*8)
+#define SAVED_S1 (7*8)
+#define SAVED_S2 (8*8)
+#define SAVED_S3 (9*8)
+#define SAVED_S4 (10*8)
+#define SAVED_S5 (11*8)
+#define SAVED_S6 (12*8)
+#define SAVED_GP (13*8)
+#define SAVED_PC (14*8)
+#define SAVED_BYTES (15*8)
+
+/*
+ * Suspend the current thread and resume the next one.
+ *
+ * void
+ * cproc_switch(cur, next, lock)
+ * long *cur;
+ * long *next;
+ * simple_lock *lock;
+ */
+LEAF(cproc_switch,3)
+ subq sp,SAVED_BYTES,sp /* allocate space for registers */
+ /* Save them registers */
+ stq ra,SAVED_PC(sp)
+ stq gp,SAVED_GP(sp)
+ stq s0,SAVED_S0(sp)
+ stq s1,SAVED_S1(sp)
+ stq s2,SAVED_S2(sp)
+ stq s3,SAVED_S3(sp)
+ stq s4,SAVED_S4(sp)
+ stq s5,SAVED_S5(sp)
+ stq s6,SAVED_S6(sp)
+
+ stq sp,0(a0) /* save current sp */
+ ldq sp,0(a1) /* restore next sp */
+ /* Reload them registers */
+ ldq ra,SAVED_PC(sp)
+ ldq gp,SAVED_GP(sp)
+ ldq s0,SAVED_S0(sp)
+ ldq s1,SAVED_S1(sp)
+ ldq s2,SAVED_S2(sp)
+ ldq s3,SAVED_S3(sp)
+ ldq s4,SAVED_S4(sp)
+ ldq s5,SAVED_S5(sp)
+ ldq s6,SAVED_S6(sp)
+ /* return to next thread */
+ .set noreorder
+ mb
+ stq zero,0(a2) /* clear lock */
+ mb
+ .set reorder
+ addq sp,SAVED_BYTES,sp
+ RET
+ END(cproc_switch)
+
+/*
+ * void
+ * cproc_start_wait(parent_context, child, stackp, lock)
+ * long *parent_context;
+ * cproc_t child;
+ * long stackp;
+ * simple_lock *lock;
+ */
+NESTED(cproc_start_wait, 4, SAVED_BYTES, zero, CSW_IMASK, 0)
+ ldgp gp,0(pv)
+ subq sp,SAVED_BYTES,sp /* allocate space for registers */
+ /* Save parent registers */
+ stq ra,SAVED_PC(sp)
+ stq gp,SAVED_GP(sp)
+ stq s0,SAVED_S0(sp)
+ stq s1,SAVED_S1(sp)
+ stq s2,SAVED_S2(sp)
+ stq s3,SAVED_S3(sp)
+ stq s4,SAVED_S4(sp)
+ stq s5,SAVED_S5(sp)
+ stq s6,SAVED_S6(sp)
+
+ stq sp,0(a0) /* save parent sp */
+
+ .set noreorder
+ mb
+ stq zero,0(a3) /* release lock */
+ mb
+ .set reorder
+
+ mov a2,sp /* get child sp */
+ subq sp,ARG_SAVE,sp /* regsave (sanity) */
+ mov a1,a0
+ CALL(cproc_waiting) /* cproc_waiting(child) */
+ /*
+ * Control never returns here.
+ */
+ END(cproc_start_wait)
+
+/*
+ * void
+ * cproc_prepare(child, child_context, stack)
+ * long *child_context;
+ * long *stack;
+ */
+LEAF(cproc_prepare,3)
+ ldgp gp,0(pv)
+ subq a2,ARG_SAVE,a2 /* cthread_body's fake frame */
+ stq a0,0(a2) /* cthread_body(child) */
+ subq a2,SAVED_BYTES,a2 /* cproc_switch's ``frame'' */
+ stq s0,SAVED_S0(a2)
+ stq s1,SAVED_S1(a2)
+ stq s2,SAVED_S2(a2)
+ stq s3,SAVED_S3(a2)
+ stq s4,SAVED_S4(a2)
+ stq s5,SAVED_S5(a2)
+ stq s6,SAVED_S6(a2)
+ stq gp,SAVED_GP(a2)
+ stq a2,0(a1) /* child context */
+ lda v0,1f
+ stq v0,SAVED_PC(a2)
+ RET
+
+ /*
+ * The reason we are getting here is to load
+ * arguments in registers where they are supposed
+ * to be. The code above only put the argument(s)
+ * on the stack, now we'll load them.
+ */
+1: ldgp gp,0(ra) /* we get here from a cswitch */
+ lda v0,cthread_body
+ ldq a0,0(sp)
+ mov v0,ra
+ mov ra,pv /* funcall or return, either way */
+ RET
+ END(cproc_prepare)
+
+/*
+ * unsigned long
+ * cthread_sp()
+ *
+ * Returns the current stack pointer.
+ */
+
+LEAF(cthread_sp,0)
+ mov sp, v0
+ RET
+ END(cthread_sp);
diff --git a/libthreads/alpha/cthreads.h b/libthreads/alpha/cthreads.h
new file mode 100644
index 00000000..f2218f40
--- /dev/null
+++ b/libthreads/alpha/cthreads.h
@@ -0,0 +1,61 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: cthreads.h,v $
+ * Revision 2.4 93/11/17 19:00:42 dbg
+ * When compiling with GCC, inline cthread_sp().
+ * [93/09/21 af]
+ *
+ * Revision 2.3 93/01/19 08:56:02 danner
+ * Locks are now 64bits.
+ * [92/12/30 af]
+ *
+ * Revision 2.2 93/01/14 18:04:28 danner
+ * Created.
+ * [92/05/31 af]
+ *
+ */
+
+#ifndef _MACHINE_CTHREADS_H_
+#define _MACHINE_CTHREADS_H_
+
+typedef long spin_lock_t;
+#define SPIN_LOCK_INITIALIZER 0
+#define spin_lock_init(s) *(s)=0
+#define spin_lock_locked(s) (*(s) != 0)
+
+#if defined(__GNUC__)
+
+#define cthread_sp() \
+ ({ register vm_offset_t _sp__; \
+ __asm__("or $31,$30,%0" \
+ : "=r" (_sp__) ); \
+ _sp__; })
+
+#endif /* __GNUC__ */
+
+#endif _MACHINE_CTHREADS_H_
diff --git a/libthreads/alpha/lock.S b/libthreads/alpha/lock.S
new file mode 100644
index 00000000..657ac1f8
--- /dev/null
+++ b/libthreads/alpha/lock.S
@@ -0,0 +1,84 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: lock.s,v $
+ * Revision 2.3 93/03/09 10:59:04 danner
+ * Lost in previous merge:
+ * Added memory barriers where needed.
+ * Locks are longs now.
+ * [93/01/15 af]
+ *
+ * Revision 2.2 93/01/14 18:04:31 danner
+ * Mumble, "try_lock" really means "try_hard_once".
+ * That is, try hard until you either get it or lose it.
+ * [92/12/24 af]
+ * Created a while back.
+ * [92/12/10 af]
+ *
+ */
+
+#include <mach/alpha/asm.h>
+
+/*
+ The C interface for this function is
+
+ boolean_t
+ spin_try_lock_sw(m)
+ long * m;
+
+ The function has a slightly different semantics than TAS: it will
+ return a boolean value that indicates whether the lock was acquired
+ or not. If not, we'll presume that the user will retry after some
+ appropriate delay.
+ */
+ .text
+ .align 4
+ .set noreorder
+
+LEAF(spin_try_lock,1)
+ mb
+ ldq_l t0,0(a0)
+ or zero,2,v0 /* build lock value */
+ bne t0,nope /* already set, forget it */
+ stq_c v0,0(a0) /* see if we still had the lock */
+ beq v0,yipe /* if we just took an interrupt.. */
+ RET /* if v0 != 0 then we got it */
+nope:
+ mov zero,v0 /* failed to acquire lock */
+ RET
+yipe: br zero,spin_try_lock /* I love branch predictions.. */
+
+ END(spin_try_lock)
+
+LEAF(spin_unlock,1)
+ mb /* but this might be needed.. */
+ stq zero,0(a0) /* no need for interlocks (sec 10.5.2) */
+ mb /* but this might be needed.. */
+ RET
+
+ END(spin_unlock)
+
diff --git a/libthreads/alpha/thread.c b/libthreads/alpha/thread.c
new file mode 100644
index 00000000..db2cb0c8
--- /dev/null
+++ b/libthreads/alpha/thread.c
@@ -0,0 +1,100 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: thread.c,v $
+ * Revision 1.1 2002/05/27 02:13:47 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * * alpha/cthreads.h, alpha/thread.c, alpha/csw.S, alpha/lock.S:
+ * New files, verbatim from CMU release MK83a user/threads/alpha.
+ *
+ * Revision 2.3 93/02/01 09:56:49 danner
+ * mach/mach.h -> mach.h
+ * [93/01/28 danner]
+ *
+ * Revision 2.2 93/01/14 18:04:35 danner
+ * Created.
+ * [92/05/31 af]
+ *
+ */
+/*
+ * alpha/thread.c
+ *
+ * Cproc startup for ALPHA Cthreads implementation.
+ */
+
+
+#include <cthreads.h>
+#include "cthread_internals.h"
+
+#include <mach.h>
+
+#if 0
+/*
+ * C library imports:
+ */
+extern bzero();
+#endif
+
+/*
+ * Set up the initial state of a MACH thread
+ * so that it will invoke routine(child)
+ * when it is resumed.
+ */
+#warning TLS support not implemented
+void
+cproc_setup(
+ register cproc_t child,
+ thread_t thread,
+ tcbhead_t *tcb,
+ void (*routine)(cproc_t))
+{
+ register integer_t *top;
+ struct alpha_thread_state state;
+ register struct alpha_thread_state *ts;
+ kern_return_t r;
+
+ /*
+ * Set up ALPHA call frame and registers.
+ */
+ ts = &state;
+ bzero((char *) ts, sizeof(struct alpha_thread_state));
+
+ top = (integer_t *) (child->stack_base + child->stack_size);
+
+ /*
+ * Set pc & pv to procedure entry, pass one arg in register,
+ * allocate room for 6 regsave on the stack frame (sanity).
+ */
+ ts->pc = (natural_t) routine;
+ ts->r27 = (natural_t) routine;
+ ts->r16 = (integer_t) child;
+ ts->r30 = (integer_t) (top - 6); /* see ARG_SAVE in csw.s */
+
+
+ MACH_CALL(thread_set_state(thread,ALPHA_THREAD_STATE,(thread_state_t) &state,ALPHA_THREAD_STATE_COUNT),r);
+}
diff --git a/libthreads/call.c b/libthreads/call.c
index 26efc8fc..85bd4f38 100644
--- a/libthreads/call.c
+++ b/libthreads/call.c
@@ -1,6 +1,6 @@
/*
* Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
@@ -26,6 +26,10 @@
/*
* HISTORY
* $Log: call.c,v $
+ * Revision 2.5 93/01/14 18:04:38 danner
+ * Converted file to ANSI C.
+ * [92/12/18 pds]
+ *
* Revision 2.4 91/05/14 17:56:00 mrt
* Correcting copyright
*
@@ -42,40 +46,34 @@
#include <cthreads.h>
#include "cthread_internals.h"
-#ifdef THREAD_CALLS
-kern_return_t cthread_get_state(thread)
-cthread_t thread;
+#if defined(THREAD_CALLS)
+kern_return_t cthread_get_state(cthread_t thread)
{
cproc_t p = thread->ur;
}
-kern_return_t cthread_set_state(thread)
-cthread_t thread;
+kern_return_t cthread_set_state(cthread_t thread)
{
cproc_t p = thread->ur;
}
-kern_return_t cthread_abort(thread)
-cthread_t thread;
+kern_return_t cthread_abort(cthread_t thread)
{
cproc_t p = thread->ur;
}
-kern_return_t cthread_resume(thread)
-cthread_t thread;
+kern_return_t cthread_resume(cthread_t thread)
{
cproc_t p = thread->ur;
}
-kern_return_t cthread_suspend(thread)
-cthread_t thread;
+kern_return_t cthread_suspend(cthread_t thread)
{
cproc_t p = thread->ur;
}
-kern_return_t cthread_call_on(thread)
-cthread_t thread;
+kern_return_t cthread_call_on(cthread_t thread)
{
cproc_t p = thread->ur;
}
-#endif THREAD_CALLS
+#endif /* defined(THREAD_CALLS) */
diff --git a/libthreads/cancel-cond.c b/libthreads/cancel-cond.c
index b7780d03..b7793f85 100644
--- a/libthreads/cancel-cond.c
+++ b/libthreads/cancel-cond.c
@@ -77,7 +77,7 @@ hurd_condition_wait (condition_t c, mutex_t m)
#ifdef WAIT_DEBUG
p->waiting_for = (char *)c;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
mutex_unlock (m);
@@ -94,7 +94,7 @@ hurd_condition_wait (condition_t c, mutex_t m)
#ifdef WAIT_DEBUG
p->waiting_for = (char *)0;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
}
spin_lock (&ss->lock);
diff --git a/libthreads/cprocs.c b/libthreads/cprocs.c
index 71a6a3ad..7f63fc0d 100644
--- a/libthreads/cprocs.c
+++ b/libthreads/cprocs.c
@@ -1,120 +1,132 @@
-/*
+/*
* Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1993-1989 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* HISTORY
+ * 26-Oct-94 Johannes Helander (jvh) Helsinki University of Technology
+ * Set the wait_type field.
+ *
* $Log: cprocs.c,v $
- * Revision 1.7 1995/09/22 17:51:10 roland
- * Include hurd/threadvar.h.
+ * Revision 1.16 2002/05/27 02:50:10 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * Changes merged from CMU MK83a version:
+ * * cthreads.h, options.h: Various cleanups.
+ * * call.c, cthread_data.c, sync.c, mig_support.c: Likewise.
+ * * i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
+ * * cthread_internals.h: Add decls for internal functions.
+ * (struct cproc): Use vm_offset_t for stack_base and stack_size members.
+ * Use natural_t for context member.
+ * * cprocs.c: Use prototypes for all defns.
+ * * cthreads.c: Likewise.
+ * (cthread_exit): Cast any_t to integer_t before int.
*
- * Revision 1.6 1995/08/30 15:57:47 mib
- * Repair typos.
+ * Revision 2.18 93/03/09 10:59:10 danner
+ * Lint.
+ * [93/03/06 af]
*
- * Revision 1.5 1995/08/30 15:50:53 mib
- * (cond_signal): If this condition has implications, see if one of them
- * needs to be signalled when we have no waiters.
- * (cond_broadcast): Signal the implications list too.
- * (condition_implies, condition_unimplies): New functions.
+ * Revision 2.17 93/01/19 08:55:44 danner
+ * Added missing spin_lock_t type from cproc_list_lock decl.
+ * [92/12/30 af]
*
- * Revision 1.4 1995/04/04 21:04:29 roland
- * (mutex_lock_solid, mutex_unlock_solid): Renamed to __*.
- * (_cthread_mutex_lock_routine, _cthread_mutex_unlock_routine): Variables
- * removed.
*
- * Revision 1.3 1994/05/19 04:55:30 roland
- * entered into RCS
+ * Revision 2.16 93/01/14 18:04:46 danner
+ * Convert file to ANSI C.
+ * [92/12/18 pds]
+ * 64bit cleanup.
+ * [92/12/10 21:08:32 af]
*
* Revision 2.15 92/03/06 14:09:31 rpd
* Replaced swtch_pri with yield.
* [92/03/06 rpd]
- *
+ *
* Revision 2.14 91/08/28 11:19:16 jsb
* Fixed the loop in cproc_fork_child that frees cprocs.
* [91/08/23 rpd]
- *
+ *
* Revision 2.13 91/07/31 18:33:04 dbg
* Fix some more bad types. Ints are NOT pointers.
- *
+ *
* Fix argument type mismatch in cproc_create.
* [91/07/30 17:32:59 dbg]
- *
+ *
* Revision 2.12 91/05/14 17:56:11 mrt
* Correcting copyright
- *
+ *
* Revision 2.11 91/02/14 14:19:26 mrt
* Added new Mach copyright
* [91/02/13 12:40:50 mrt]
- *
+ *
* Revision 2.10 90/11/05 14:36:41 rpd
* Added cproc_fork_{prepare,parent,child}.
* [90/11/02 rwd]
- *
+ *
* Fix for positive stack growth.
* [90/11/01 rwd]
- *
+ *
* Add spin_lock_t.
* [90/10/31 rwd]
- *
+ *
* Revision 2.9 90/10/12 13:07:12 rpd
* Fix type
* [90/10/10 15:09:59 rwd]
- *
+ *
* Comment code.
* [90/10/02 rwd]
- *
+ *
* Revision 2.8 90/09/09 14:34:44 rpd
* Remove special mutex. Remove thread_calls and debug_mutex
* [90/08/24 rwd]
* Fix up old call to cthread_msg_busy to new format.
* [90/08/22 rwd]
- *
+ *
* Revision 2.7 90/08/06 15:09:17 rwd
* Fixed arguments to cthread_mach_msg.
* [90/06/26 rwd]
* Add additional STATISTICS.
* [90/06/07 rwd]
- *
+ *
* Attempt to reduce number of times a cthread is released to to a
* msg_receive by adding min/max instead of single number to
* cthread_msg calls.
* [90/06/06 rwd]
- *
+ *
* Revision 2.6 90/06/02 15:13:36 rpd
* Converted to new IPC.
* [90/03/20 20:46:16 rpd]
- *
+ *
* Revision 2.5 90/05/29 18:40:11 rwd
* Don't incr special field until the mutex grab is successful.
* [90/05/09 rwd]
- *
+ *
* Revision 2.4 90/03/14 21:12:02 rwd
* Added WAIT_DEBUG code for deadlock debugging.
* [90/03/01 rwd]
* Insert cprocs in cproc_list as allocated.
* [90/03/01 10:20:16 rwd]
- *
+ *
* Revision 2.3 90/01/19 14:36:57 rwd
* Make cthread_msg_busy only release new thread if this is still
* busy. Ie don't release two on back to back calls.
@@ -126,7 +138,7 @@
* Change cproc_self pointer to top of stack. Now need to change
* the stack of the first thread.
* [89/12/12 rwd]
- *
+ *
* Revision 2.2 89/12/08 19:53:13 rwd
* Added CPROC_CONDWAIT state to deal with lock held
* across mutex_unlock problem.
@@ -134,7 +146,7 @@
* Changed mutexes to not hand off. MUTEX_EXTRA conditional is
* now obsolete.
* [89/11/27 rwd]
- *
+ *
* Add MUTEX_EXTRA code for extra kernel threads to serve special
* mutexes in time of need.
* [89/11/25 rwd]
@@ -144,15 +156,15 @@
* macro which tries the spin_lock before making a subroutine call.
* Mutex_unlock is now a macro with mutex_unlock_solid for worst case.
* [89/11/13 rwd]
- *
+ *
* Rewrite most to merge coroutine and thread implementation.
* New routines are cthread_set_kernel_limit, cthread_kernel_limit,
* cthread_wire, cthread_unwire, and cthread_receive.
* [89/10/23 rwd]
- *
+ *
* Revision 2.1 89/08/03 17:07:10 rwd
* Created.
- *
+ *
* 11-Apr-89 David Golub (dbg) at Carnegie-Mellon University
* Made condition_yield loop break if swtch_pri returns TRUE (in
* case we fix it).
@@ -208,7 +220,7 @@
* to eliminate dependency on cproc layout.
*/
/*
- * File: cprocs.c
+ * File: cprocs.c
* Author: Eric Cooper, Carnegie Mellon University
* Date: Aug, 1987
*
@@ -221,15 +233,7 @@
#include "cthread_internals.h"
#include <mach/message.h>
#include <hurd/threadvar.h> /* GNU */
-
-/*
- * C Threads imports:
- */
-extern void alloc_stack();
-extern void cproc_switch(); /* cproc context switch */
-extern void cproc_start_wait(); /* cproc idle thread */
-extern vm_offset_t cproc_stack_base(); /* return start of stack */
-extern vm_offset_t stack_init();
+#include <assert.h>
/*
* Port_entry's are used by cthread_mach_msg to store information
@@ -280,10 +284,10 @@ int cthread_no_mutex = 0; /* total number times woken to get
mutex and couldn't */
private spin_lock_t mutex_count_lock = SPIN_LOCK_INITIALIZER;
/* lock for above */
-#endif STATISTICS
+#endif /* STATISTICS */
cproc_t cproc_list = NO_CPROC; /* list of all cprocs */
-private cproc_list_lock = SPIN_LOCK_INITIALIZER;
+private spin_lock_t cproc_list_lock = SPIN_LOCK_INITIALIZER;
/* lock for above */
private int cprocs_started = FALSE; /* initialized? */
private struct cthread_queue ready = QUEUE_INITIALIZER;
@@ -311,8 +315,8 @@ private mach_msg_header_t wakeup_msg; /* prebuilt message used by idle
* Return current value for max kernel threads
* Note: 0 means no limit
*/
-
-cthread_kernel_limit()
+int
+cthread_kernel_limit(void)
{
return cthread_max_kernel_threads;
}
@@ -323,8 +327,8 @@ cthread_kernel_limit()
* over maximum.
*/
-cthread_set_kernel_limit(n)
- int n;
+void
+cthread_set_kernel_limit(int n)
{
cthread_max_kernel_threads = n;
}
@@ -333,47 +337,28 @@ cthread_set_kernel_limit(n)
* Wire a cthread to its current kernel thread
*/
-void cthread_wire()
+void
+cthread_wire(void)
{
register cproc_t p = cproc_self();
kern_return_t r;
- /*
- * A wired thread has a port associated with it for all
- * of its wait/block cases. We also prebuild a wakeup
- * message.
- */
-
- if (p->wired == MACH_PORT_NULL) {
- MACH_CALL(mach_port_allocate(mach_task_self(),
- MACH_PORT_RIGHT_RECEIVE,
- &p->wired), r);
- MACH_CALL(mach_port_insert_right(mach_task_self(),
- p->wired, p->wired,
- MACH_MSG_TYPE_MAKE_SEND), r);
- p->msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
- p->msg.msgh_size = 0; /* initialized in call */
- p->msg.msgh_remote_port = p->wired;
- p->msg.msgh_local_port = MACH_PORT_NULL;
- p->msg.msgh_kind = MACH_MSGH_KIND_NORMAL;
- p->msg.msgh_id = 0;
-#ifdef STATISTICS
- spin_lock(&wired_lock);
- cthread_wired++;
- spin_unlock(&wired_lock);
-#endif STATISTICS
- }
+ /* In GNU, we wire all threads on creation (in cproc_alloc). */
+ assert (p->wired != MACH_PORT_NULL);
}
/*
* Unwire a cthread. Deallocate its wait port.
*/
-void cthread_unwire()
+void
+cthread_unwire(void)
{
register cproc_t p = cproc_self();
- kern_return_t r;
+ /* This is bad juju in GNU, where all cthreads must be wired. */
+ abort();
+#if 0
if (p->wired != MACH_PORT_NULL) {
MACH_CALL(mach_port_mod_refs(mach_task_self(), p->wired,
MACH_PORT_RIGHT_SEND, -1), r);
@@ -384,14 +369,16 @@ void cthread_unwire()
spin_lock(&wired_lock);
cthread_wired--;
spin_unlock(&wired_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
}
+#endif
}
private cproc_t
-cproc_alloc()
+cproc_alloc(void)
{
register cproc_t p = (cproc_t) malloc(sizeof(struct cproc));
+ kern_return_t r;
p->incarnation = NO_CTHREAD;
#if 0
@@ -400,9 +387,31 @@ cproc_alloc()
#endif
spin_lock_init(&p->lock);
- p->wired = MACH_PORT_NULL;
p->state = CPROC_RUNNING;
p->busy = 0;
+
+ /*
+ * In GNU, every cthread must be wired. So we just
+ * initialize P->wired on creation.
+ *
+ * A wired thread has a port associated with it for all
+ * of its wait/block cases. We also prebuild a wakeup
+ * message.
+ */
+
+ MACH_CALL(mach_port_allocate(mach_task_self(),
+ MACH_PORT_RIGHT_RECEIVE,
+ &p->wired), r);
+ MACH_CALL(mach_port_insert_right(mach_task_self(),
+ p->wired, p->wired,
+ MACH_MSG_TYPE_MAKE_SEND), r);
+ p->msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+ p->msg.msgh_size = 0; /* initialized in call */
+ p->msg.msgh_remote_port = p->wired;
+ p->msg.msgh_local_port = MACH_PORT_NULL;
+ p->msg.msgh_kind = MACH_MSGH_KIND_NORMAL;
+ p->msg.msgh_id = 0;
+
spin_lock(&cproc_list_lock);
p->list = cproc_list;
cproc_list = p;
@@ -416,7 +425,7 @@ cproc_alloc()
*/
vm_offset_t
-cproc_init()
+cproc_init(void)
{
kern_return_t r;
@@ -453,9 +462,7 @@ cproc_init()
* synching on its lock. Just send message to wired cproc.
*/
-private int cproc_ready(p, preq)
- register cproc_t p;
- register int preq;
+private boolean_t cproc_ready(register cproc_t p, register int preq)
{
register cproc_t s=cproc_self();
kern_return_t r;
@@ -469,7 +476,7 @@ private int cproc_ready(p, preq)
mach_error("mach_msg", r);
exit(1);
}
-#endif CHECK_STATUS
+#endif /* CHECK_STATUS */
return TRUE;
}
spin_lock(&p->lock); /* is it ready to be queued? It
@@ -497,7 +504,7 @@ private int cproc_ready(p, preq)
}
#ifdef STATISTICS
cthread_ready++;
-#endif STATISTICS
+#endif /* STATISTICS */
ready_count++;
if ((s->state & CPROC_CONDWAIT) && !(s->wired)) {
@@ -523,7 +530,7 @@ private int cproc_ready(p, preq)
mach_error("mach_msg", r);
exit(1);
}
-#endif CHECK_STATUS
+#endif /* CHECK_STATUS */
return TRUE;
}
spin_unlock(&ready_lock);
@@ -536,8 +543,7 @@ private int cproc_ready(p, preq)
*/
void
-cproc_waiting(p)
- register cproc_t p;
+cproc_waiting(cproc_t p)
{
mach_msg_header_t msg;
register cproc_t new;
@@ -548,7 +554,7 @@ cproc_waiting(p)
cthread_waiting++;
cthread_waiters++;
spin_unlock(&ready_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
for (;;) {
MACH_CALL(mach_msg(&msg, MACH_RCV_MSG,
0, sizeof msg, wait_port,
@@ -560,14 +566,14 @@ cproc_waiting(p)
ready_count++;
#ifdef STATISTICS
cthread_none++;
-#endif STATISTICS
+#endif /* STATISTICS */
spin_unlock(&ready_lock);
- }
+ }
#ifdef STATISTICS
cthread_ready--;
cthread_running++;
cthread_waiting--;
-#endif STATISTICS
+#endif /* STATISTICS */
spin_unlock(&ready_lock);
spin_lock(&new->lock);
new->state = CPROC_RUNNING;
@@ -584,8 +590,8 @@ cproc_waiting(p)
*
*/
-cproc_t
-cproc_waiter()
+private cproc_t
+cproc_waiter(void)
{
register cproc_t waiter;
@@ -599,7 +605,7 @@ cproc_waiter()
spin_lock(&waiters_lock);
cthread_wait_stacks++;
spin_unlock(&waiters_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
waiter = cproc_alloc();
MACH_CALL(vm_allocate(mach_task_self(), &base,
cthread_wait_stack_size, TRUE), r);
@@ -617,7 +623,8 @@ cproc_waiter()
* You must hold cproc_self()->lock when called.
*/
-cproc_block()
+void
+cproc_block(void)
{
extern unsigned int __hurd_threadvar_max; /* GNU */
register cproc_t waiter, new, p = cproc_self();
@@ -638,13 +645,13 @@ cproc_block()
spin_lock(&ready_lock);
#ifdef STATISTICS
cthread_blocked++;
-#endif STATISTICS
+#endif /* STATISTICS */
cthread_queue_deq(&ready, cproc_t, new);
if (new) {
#ifdef STATISTICS
cthread_ready--;
cthread_switches++;
-#endif STATISTICS
+#endif /* STATISTICS */
ready_count--;
spin_unlock(&ready_lock);
spin_lock(&p->lock);
@@ -655,7 +662,7 @@ cproc_block()
cthread_wakeup++;
cthread_switches--;
spin_unlock(&ready_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
cproc_ready(new, 1); /* requeue at head were it was */
} else {
p->state = CPROC_BLOCKED;
@@ -668,7 +675,7 @@ cproc_block()
wait_count++;
#ifdef STATISTICS
cthread_running--;
-#endif STATISTICS
+#endif /* STATISTICS */
spin_unlock(&ready_lock);
waiter = cproc_waiter();
spin_lock(&p->lock);
@@ -679,7 +686,7 @@ cproc_block()
#ifdef STATISTICS
cthread_running++;
cthread_wakeup++;
-#endif STATISTICS
+#endif /* STATISTICS */
spin_unlock(&ready_lock);
spin_lock(&waiters_lock);
cthread_queue_preq(&waiters, waiter);
@@ -689,7 +696,7 @@ cproc_block()
spin_lock(&waiter->lock); /* in case still switching */
spin_unlock(&waiter->lock);
cproc_start_wait
- (&p->context, waiter,
+ (&p->context, waiter,
cproc_stack_base(waiter,
sizeof(ur_cthread_t *) +
/* Account for GNU per-thread
@@ -705,7 +712,7 @@ cproc_block()
* Implement C threads using MACH threads.
*/
cproc_t
-cproc_create()
+cproc_create(void)
{
register cproc_t child = cproc_alloc();
register kern_return_t r;
@@ -718,16 +725,17 @@ cproc_create()
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);
cthread_running++;
spin_unlock(&ready_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
} else {
vm_offset_t stack;
spin_unlock(&n_kern_lock);
@@ -746,18 +754,16 @@ cproc_create()
variables. */
__hurd_threadvar_max *
sizeof (long int));
- cproc_prepare(child, &child->context, stack);
+ cproc_prepare(child, &child->context, stack, &cthread_body);
/* Set up the cproc_self ptr at the base of CHILD's stack. */
- ur_cthread_ptr(stack) = child;
+ ur_cthread_ptr(stack) = (ur_cthread_t) child;
cproc_ready(child,0);
}
return child;
}
void
-condition_wait(c, m)
- register condition_t c;
- mutex_t m;
+condition_wait(condition_t c, mutex_t m)
{
register cproc_t p = cproc_self();
@@ -768,7 +774,7 @@ condition_wait(c, m)
spin_unlock(&c->lock);
#ifdef WAIT_DEBUG
p->waiting_for = (char *)c;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
mutex_unlock(m);
@@ -783,7 +789,7 @@ condition_wait(c, m)
#ifdef WAIT_DEBUG
p->waiting_for = (char *)0;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
/*
* Re-acquire the mutex and return.
@@ -798,7 +804,7 @@ void
condition_implies (condition_t implicator, condition_t implicatand)
{
struct cond_imp *imp;
-
+
imp = malloc (sizeof (struct cond_imp));
imp->implicatand = implicatand;
imp->next = implicator->implications;
@@ -811,7 +817,7 @@ void
condition_unimplies (condition_t implicator, condition_t implicatand)
{
struct cond_imp **impp;
-
+
for (impp = &implicator->implications; *impp; impp = &(*impp)->next)
{
if ((*impp)->implicatand == implicatand)
@@ -827,8 +833,7 @@ condition_unimplies (condition_t implicator, condition_t implicatand)
/* Signal one waiter on C. If there were no waiters at all, return
0, else return 1. */
int
-cond_signal(c)
- register condition_t c;
+cond_signal(condition_t c)
{
register cproc_t p;
struct cond_imp *imp;
@@ -849,8 +854,7 @@ cond_signal(c)
}
void
-cond_broadcast(c)
- register condition_t c;
+cond_broadcast(condition_t c)
{
register cproc_t p;
struct cthread_queue blocked_queue;
@@ -881,7 +885,7 @@ cond_broadcast(c)
}
void
-cthread_yield()
+cthread_yield(void)
{
register cproc_t new, p = cproc_self();
@@ -892,7 +896,7 @@ cthread_yield()
spin_lock(&ready_lock);
#ifdef STATISTICS
cthread_yields++;
-#endif STATISTICS
+#endif /* STATISTICS */
cthread_queue_deq(&ready, cproc_t, new);
if (new) {
cthread_queue_enq(&ready, p);
@@ -923,7 +927,7 @@ __mutex_lock_solid(void *ptr)
#ifdef WAIT_DEBUG
p->waiting_for = (char *)m;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
while (1) {
spin_lock(&m->lock);
if (cthread_queue_head(&m->queue, cproc_t) == NO_CPROC) {
@@ -937,7 +941,7 @@ __mutex_lock_solid(void *ptr)
spin_unlock(&m->lock);
#ifdef WAIT_DEBUG
p->waiting_for = (char *)0;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
return;
} else {
if (!queued) cthread_queue_enq(&m->queue, p);
@@ -947,14 +951,14 @@ __mutex_lock_solid(void *ptr)
if (spin_try_lock(&m->held)) {
#ifdef WAIT_DEBUG
p->waiting_for = (char *)0;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
return;
}
#ifdef STATISTICS
spin_lock(&mutex_count_lock);
cthread_no_mutex++;
spin_unlock(&mutex_count_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
}
}
}
@@ -990,8 +994,8 @@ __mutex_unlock_solid(void *ptr)
* call to occur as often as is possible.
*/
-private port_entry_t get_port_entry(port, min, max)
- mach_port_t port;
+private port_entry_t
+get_port_entry(mach_port_t port, int min, int max)
{
register port_entry_t i;
@@ -1014,8 +1018,8 @@ private port_entry_t get_port_entry(port, min, max)
return i;
}
-cthread_msg_busy(port, min, max)
- mach_port_t port;
+void
+cthread_msg_busy(mach_port_t port, int min, int max)
{
register port_entry_t port_entry;
register cproc_t new, p = cproc_self();
@@ -1036,7 +1040,7 @@ cthread_msg_busy(port, min, max)
spin_lock(&port_lock);
cthread_rnone++;
spin_unlock(&port_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
}
} else {
port_entry->held--;
@@ -1046,8 +1050,8 @@ cthread_msg_busy(port, min, max)
}
-cthread_msg_active(port, min, max)
-mach_port_t port;
+void
+cthread_msg_active(mach_port_t port, int min, int max)
{
register cproc_t p = cproc_self();
register port_entry_t port_entry;
@@ -1058,24 +1062,18 @@ mach_port_t port;
spin_lock(&port_entry->lock);
if (port_entry->held < port_entry->max) {
port_entry->held++;
- p->busy = (int)port_entry;
+ p->busy = port_entry;
}
spin_unlock(&port_entry->lock);
}
}
mach_msg_return_t
-cthread_mach_msg(header, option,
- send_size, rcv_size, rcv_name,
- timeout, notify, min, max)
- register mach_msg_header_t *header;
- register mach_msg_option_t option;
- mach_msg_size_t send_size;
- mach_msg_size_t rcv_size;
- register mach_port_t rcv_name;
- mach_msg_timeout_t timeout;
- mach_port_t notify;
- int min, max;
+cthread_mach_msg(register mach_msg_header_t *header,
+ register mach_msg_option_t option, mach_msg_size_t send_size,
+ mach_msg_size_t rcv_size, register mach_port_t rcv_name,
+ mach_msg_timeout_t timeout, mach_port_t notify, int min,
+ int max)
{
register port_entry_t port_entry;
register cproc_t p = cproc_self();
@@ -1105,7 +1103,7 @@ cthread_mach_msg(header, option,
spin_unlock(&port_entry->lock);
#ifdef WAIT_DEBUG
p->waiting_for = (char *)port_entry;
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
cproc_block();
} else {
port_entry->held++;
@@ -1120,8 +1118,8 @@ cthread_mach_msg(header, option,
}
#ifdef WAIT_DEBUG
p->waiting_for = (char *)0;
-#endif WAIT_DEBUG
- p->busy = (int)port_entry;
+#endif /* WAIT_DEBUG */
+ p->busy = port_entry;
if ((option & MACH_SEND_MSG) && !sent) {
r = mach_msg(header, option,
send_size, rcv_size, rcv_name,
@@ -1134,7 +1132,8 @@ cthread_mach_msg(header, option,
return r;
}
-cproc_fork_prepare()
+void
+cproc_fork_prepare(void)
{
register cproc_t p = cproc_self();
@@ -1143,7 +1142,8 @@ cproc_fork_prepare()
spin_lock(&cproc_list_lock);
}
-cproc_fork_parent()
+void
+cproc_fork_parent(void)
{
register cproc_t p = cproc_self();
@@ -1152,7 +1152,8 @@ cproc_fork_parent()
vm_inherit(mach_task_self(),p->stack_base, p->stack_size, VM_INHERIT_NONE);
}
-cproc_fork_child()
+void
+cproc_fork_child(void)
{
register cproc_t l,p = cproc_self();
cproc_t m;
@@ -1180,7 +1181,7 @@ cproc_fork_child()
cthread_switches = 0;
cthread_no_mutex = 0;
spin_lock_init(&mutex_count_lock);
-#endif STATISTICS
+#endif /* STATISTICS */
for(l=cproc_list;l!=NO_CPROC;l=m) {
m=l->next;
diff --git a/libthreads/cthread_data.c b/libthreads/cthread_data.c
index 0814130d..02e6fa82 100644
--- a/libthreads/cthread_data.c
+++ b/libthreads/cthread_data.c
@@ -1,12 +1,21 @@
/*
* Mach Operating System
- * Copyright (c) 1991 Carnegie-Mellon University
+ * Copyright (c) 1992,1991 Carnegie-Mellon University
* All rights reserved. The CMU software License Agreement specifies
* the terms and conditions for use and redistribution.
*/
/*
* HISTORY
* $Log: cthread_data.c,v $
+ * Revision 2.4 93/05/10 17:51:20 rvb
+ * Make cthread_set_data and cthread_data macros.
+ * [93/05/06 rvb]
+ *
+ * Revision 2.3 93/01/14 18:04:52 danner
+ * Converted file to ANSI C.
+ * Removed usage of obsolete type any_t.
+ * [92/12/18 pds]
+ *
* Revision 2.2 92/05/23 11:35:17 jfriedl
* Snarfed from multi-server sources at CMU.
* No stdio (for use with single-server).
@@ -26,23 +35,23 @@
* [91/03/07 jjc]
*
*/
-#include <cthreads.h>
+#include <stdio.h>
+#include <cthreads.h>
-#ifdef CTHREAD_DATA
-#define CTHREAD_KEY_FIRST (cthread_key_t)1 /* first free key */
-#else CTHREAD_DATA
-#define CTHREAD_KEY_FIRST CTHREAD_KEY_NULL /* first free key */
-#endif CTHREAD_DATA
#define CTHREAD_KEY_MAX (cthread_key_t)8 /* max. no. of keys */
#define CTHREAD_KEY_NULL (cthread_key_t)0
-#ifdef CTHREAD_DATA
+#if defined(CTHREAD_DATA)
/*
* Key reserved for cthread_data
*/
#define CTHREAD_KEY_RESERVED CTHREAD_KEY_NULL
-#endif CTHREAD_DATA
+
+#define CTHREAD_KEY_FIRST (cthread_key_t)1 /* first free key */
+#else /* not defined(CTHREAD_DATA) */
+#define CTHREAD_KEY_FIRST CTHREAD_KEY_NULL /* first free key */
+#endif /* defined(CTHREAD_DATA) */
/* lock protecting key creation */
@@ -58,8 +67,8 @@ cthread_key_t cthread_key = CTHREAD_KEY_FIRST;
* maintained on a thread specific basis.
* Returns 0 if successful and returns -1 otherwise.
*/
-cthread_keycreate(key)
-cthread_key_t *key;
+int
+cthread_keycreate(cthread_key_t *key)
{
if (cthread_key >= CTHREAD_KEY_FIRST && cthread_key < CTHREAD_KEY_MAX) {
mutex_lock((mutex_t)&cthread_data_lock);
@@ -80,20 +89,19 @@ cthread_key_t *key;
* If the calling thread doesn't have a value for the given key,
* the value returned is CTHREAD_DATA_VALUE_NULL.
*/
-cthread_getspecific(key, value)
-cthread_key_t key;
-any_t *value;
+int
+cthread_getspecific(cthread_key_t key, void **value)
{
register cthread_t self;
- register any_t *thread_data;
+ register void **thread_data;
*value = CTHREAD_DATA_VALUE_NULL;
if (key < CTHREAD_KEY_NULL || key >= cthread_key)
return(-1);
self = cthread_self();
- thread_data = (any_t *)(self->private_data);
- if (thread_data != (any_t *)0)
+ thread_data = (void **)(self->private_data);
+ if (thread_data != NULL)
*value = thread_data[key];
return(0);
@@ -104,20 +112,19 @@ any_t *value;
* Set private data associated with given key
* Returns 0 if successful and returns -1 otherwise.
*/
-cthread_setspecific(key, value)
-cthread_key_t key;
-any_t value;
+int
+cthread_setspecific(cthread_key_t key, void *value)
{
register int i;
register cthread_t self;
- register any_t *thread_data;
+ register void **thread_data;
if (key < CTHREAD_KEY_NULL || key >= cthread_key)
return(-1);
self = cthread_self();
- thread_data = (any_t *)(self->private_data);
- if (thread_data != (any_t *)0)
+ thread_data = (void **)(self->private_data);
+ if (thread_data != NULL)
thread_data[key] = value;
else {
/*
@@ -125,12 +132,12 @@ any_t value;
* point cthread_data at it, and then set the
* data for the given key with the given value.
*/
- thread_data = (any_t *)malloc(CTHREAD_KEY_MAX * sizeof(any_t));
- if (thread_data == (any_t *)0) {
+ thread_data = malloc(CTHREAD_KEY_MAX * sizeof(void *));
+ if (thread_data == NULL) {
printf("cthread_setspecific: malloc failed\n");
return(-1);
}
- self->private_data = (any_t)thread_data;
+ self->private_data = thread_data;
for (i = 0; i < CTHREAD_KEY_MAX; i++)
thread_data[i] = CTHREAD_DATA_VALUE_NULL;
@@ -141,16 +148,15 @@ any_t value;
}
-#ifdef CTHREAD_DATA
+#if defined(CTHREAD_DATA_XX)
/*
* Set thread specific "global" variable,
* using new POSIX routines.
* Crash and burn if the thread given isn't the calling thread.
* XXX For compatibility with old cthread_set_data() XXX
*/
-cthread_set_data(t, x)
-cthread_t t;
-any_t x;
+int
+cthread_set_data(cthread_t t, void *x)
{
register cthread_t self;
@@ -159,6 +165,7 @@ any_t x;
return(cthread_setspecific(CTHREAD_KEY_RESERVED, x));
else {
ASSERT(t == self);
+ return(-1);
}
}
@@ -169,12 +176,11 @@ any_t x;
* Crash and burn if the thread given isn't the calling thread.
* XXX For compatibility with old cthread_data() XXX
*/
-any_t
-cthread_data(t)
-cthread_t t;
+void *
+cthread_data(cthread_t t)
{
register cthread_t self;
- any_t value;
+ void *value;
self = cthread_self();
if (t == self) {
@@ -183,6 +189,7 @@ cthread_t t;
}
else {
ASSERT(t == self);
+ return(NULL);
}
}
-#endif CTHREAD_DATA
+#endif /* defined(CTHREAD_DATA_XX) */
diff --git a/libthreads/cthread_internals.h b/libthreads/cthread_internals.h
index c3aa8050..81e3b91c 100644
--- a/libthreads/cthread_internals.h
+++ b/libthreads/cthread_internals.h
@@ -1,79 +1,112 @@
-/*
+/*
* Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* HISTORY
+ * 26-Oct-94 Johannes Helander (jvh) Helsinki University of Technology
+ * Defined WAIT_DEBUG and initialized wait_enum
+ *
* $Log: cthread_internals.h,v $
- * Revision 1.2 1994/05/05 10:58:01 roland
- * entered into RCS
+ * Revision 1.6 2002/05/27 02:50:10 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * Changes merged from CMU MK83a version:
+ * * cthreads.h, options.h: Various cleanups.
+ * * call.c, cthread_data.c, sync.c, mig_support.c: Likewise.
+ * * i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
+ * * cthread_internals.h: Add decls for internal functions.
+ * (struct cproc): Use vm_offset_t for stack_base and stack_size members.
+ * Use natural_t for context member.
+ * * cprocs.c: Use prototypes for all defns.
+ * * cthreads.c: Likewise.
+ * (cthread_exit): Cast any_t to integer_t before int.
+ *
+ * Revision 2.17 93/05/10 21:33:36 rvb
+ * Context is a natural_t. Assumming, that is, that on
+ * some future architecture one word might be enough.
+ * [93/05/06 09:19:35 af]
+ *
+ * Revision 2.16 93/05/10 17:51:23 rvb
+ * Flush stdlib
+ * [93/05/05 09:12:29 rvb]
+ *
+ * Revision 2.15 93/01/14 18:04:56 danner
+ * Added declarations for library-internal routines.
+ * [92/12/18 pds]
+ *
+ * Replaced malloc and mach_error declarations with includes of
+ * mach_error.h and stdlib.h.
+ * [92/06/13 pds]
+ * 64bit cleanup.
+ * [92/12/01 af]
*
* Revision 2.14 92/08/03 18:03:56 jfriedl
* Made state element of struct cproc volatile.
* [92/08/02 jfriedl]
- *
+ *
* Revision 2.13 92/03/06 14:09:24 rpd
* Added yield, defined using thread_switch.
* [92/03/06 rpd]
- *
+ *
* Revision 2.12 92/03/01 00:40:23 rpd
* Removed exit declaration. It conflicted with the real thing.
* [92/02/29 rpd]
- *
+ *
* Revision 2.11 91/08/28 11:19:23 jsb
* Fixed MACH_CALL to allow multi-line expressions.
* [91/08/23 rpd]
- *
+ *
* Revision 2.10 91/07/31 18:33:33 dbg
* Protect against redefinition of ASSERT.
* [91/07/30 17:33:21 dbg]
- *
+ *
* Revision 2.9 91/05/14 17:56:24 mrt
* Correcting copyright
- *
+ *
* Revision 2.8 91/02/14 14:19:42 mrt
* Added new Mach copyright
* [91/02/13 12:41:02 mrt]
- *
+ *
* Revision 2.7 90/11/05 14:36:55 rpd
* Added spin_lock_t.
* [90/10/31 rwd]
- *
+ *
* Revision 2.6 90/09/09 14:34:51 rpd
* Remove special field.
* [90/08/24 rwd]
- *
+ *
* Revision 2.5 90/06/02 15:13:44 rpd
* Converted to new IPC.
* [90/03/20 20:52:47 rpd]
- *
+ *
* Revision 2.4 90/03/14 21:12:11 rwd
* Added waiting_for field for debugging deadlocks.
* [90/03/01 rwd]
* Added list field to keep a master list of all cprocs.
* [90/03/01 rwd]
- *
+ *
* Revision 2.3 90/01/19 14:37:08 rwd
* Keep track of real thread for use in thread_* substitutes.
* Add CPROC_ARUN for about to run and CPROC_HOLD to avoid holding
@@ -82,7 +115,7 @@
* Add busy field to be used by cthread_msg calls to make sure we
* have the right number of blocked kernel threads.
* [89/12/21 rwd]
- *
+ *
* Revision 2.2 89/12/08 19:53:28 rwd
* Added CPROC_CONDWAIT state
* [89/11/28 rwd]
@@ -101,7 +134,7 @@
* basically a merge of coroutine and thread. Added
* cthread_receivce call for use by servers.
* [89/10/23 rwd]
- *
+ *
*/
/*
* cthread_internals.h
@@ -128,6 +161,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
@@ -139,14 +180,14 @@ typedef struct cproc {
struct cproc *list; /* for master cproc list */
#ifdef WAIT_DEBUG
volatile char *waiting_for; /* address of mutex/cond waiting for */
-#endif WAIT_DEBUG
+#endif /* WAIT_DEBUG */
#if 0
/* This is not needed in GNU; libc handles it. */
mach_port_t reply_port; /* for mig_get_reply_port() */
#endif
- int context;
+ natural_t context;
spin_lock_t lock;
volatile int state; /* current state */
#define CPROC_RUNNING 0
@@ -155,19 +196,17 @@ typedef struct cproc {
#define CPROC_CONDWAIT 4
mach_port_t wired; /* is cthread wired to kernel thread */
- int busy; /* used with cthread_msg calls */
+ void *busy; /* used with cthread_msg calls */
mach_msg_header_t msg;
- unsigned int stack_base;
- unsigned int stack_size;
+ vm_offset_t stack_base;
+ vm_offset_t stack_size;
} *cproc_t;
#define NO_CPROC ((cproc_t) 0)
#define cproc_self() ((cproc_t) ur_cthread_self())
-int cproc_block ();
-
#if 0
/* This declaration conflicts with <stdlib.h> in GNU. */
/*
@@ -190,9 +229,9 @@ extern void mach_error();
quit(1, "error in %s at %d: %s\n", __FILE__, __LINE__, \
mach_error_string(ret)); \
} else
-#else CHECK_STATUS
+#else /* CHECK_STATUS */
#define MACH_CALL(expr, ret) (ret) = (expr)
-#endif CHECK_STATUS
+#endif /* CHECK_STATUS */
#define private static
#ifndef ASSERT
@@ -207,3 +246,79 @@ extern void mach_error();
#define yield() \
(void) thread_switch(MACH_PORT_NULL, SWITCH_OPTION_DEPRESS, 10)
+
+/*
+ * Functions implemented in malloc.c.
+ */
+
+#if defined(DEBUG)
+extern void print_malloc_free_list(void);
+#endif /* defined(DEBUG) */
+
+extern void malloc_fork_prepare(void);
+
+extern void malloc_fork_parent(void);
+
+extern void malloc_fork_child(void);
+
+
+/*
+ * Functions implemented in stack.c.
+ */
+
+extern vm_offset_t stack_init(cproc_t _cproc);
+
+extern void alloc_stack(cproc_t _cproc);
+
+extern vm_offset_t cproc_stack_base(cproc_t _cproc, int _offset);
+
+extern void stack_fork_child(void);
+
+/*
+ * Functions implemented in cprocs.c.
+ */
+
+extern vm_offset_t cproc_init(void);
+
+extern void cproc_waiting(cproc_t _waiter);
+
+extern void cproc_block(void);
+
+extern cproc_t cproc_create(void);
+
+extern void cproc_fork_prepare(void);
+
+extern void cproc_fork_parent(void);
+
+extern void cproc_fork_child(void);
+
+/*
+ * Function implemented in cthreads.c.
+ */
+
+extern void cthread_body(cproc_t _self);
+
+/*
+ * Functions from machine dependent files.
+ */
+
+extern void cproc_switch(natural_t *_cur, const natural_t *_new,
+ spin_lock_t *_lock);
+
+extern void cproc_start_wait(natural_t *_parent, cproc_t _child,
+ vm_offset_t _stackp,
+ spin_lock_t *_lock);
+
+extern void cproc_prepare(cproc_t _child,
+ natural_t *_child_context,
+ vm_offset_t _stackp,
+ void (*cthread_body_pc)());
+
+extern void cproc_setup(cproc_t _child, thread_t _mach_thread,
+ tcbhead_t *tcb, void (*_routine)(cproc_t));
+
+
+/* From glibc. */
+
+/* Dynamic linker TLS allocation. */
+extern void *_dl_allocate_tls(void *);
diff --git a/libthreads/cthreads.c b/libthreads/cthreads.c
index d45a02b4..aef20bed 100644
--- a/libthreads/cthreads.c
+++ b/libthreads/cthreads.c
@@ -1,78 +1,125 @@
-/*
+/*
* Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* HISTORY
- * $Log: cthreads.c,v $
+ * 20-Oct-93 Tero Kivinen (kivinen) at Helsinki University of Technology
+ * Renamed cthread_t->catch to to cthread_t->catch_exit, because
+ * catch is reserved word in c++.
+ *
+ * $Log: cthreads.c,v $
+ * Revision 1.15 2002/07/31 02:35:14 marcus
+ * Add comment to last change, for the benefit of the next merge :)
+ *
+ * Revision 1.14 2002/07/31 02:20:44 marcus
+ * 2002-07-29 Marcus Brinkmann <marcus@gnu.org>
+ *
+ * * cthreads.c (cthread_init): Move cthread_alloc call before
+ * cproc_init call (lost in merge).
+ *
+ * Revision 1.13 2002/05/28 23:55:55 roland
+ * 2002-05-28 Roland McGrath <roland@frob.com>
+ *
+ * * cthreads.c (cthread_fork_prepare, cthread_fork_parent,
+ * cthread_fork_child): Don't call malloc_fork_* (lost in merge).
+ *
+ * Revision 1.12 2002/05/27 02:50:10 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * Changes merged from CMU MK83a version:
+ * * cthreads.h, options.h: Various cleanups.
+ * * call.c, cthread_data.c, sync.c, mig_support.c: Likewise.
+ * * i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
+ * * cthread_internals.h: Add decls for internal functions.
+ * (struct cproc): Use vm_offset_t for stack_base and stack_size members.
+ * Use natural_t for context member.
+ * * cprocs.c: Use prototypes for all defns.
+ * * cthreads.c: Likewise.
+ * (cthread_exit): Cast any_t to integer_t before int.
+ *
+ * Revision 2.13 93/01/21 12:27:55 danner
+ * Remove deadlock in cproc_fork_child; must release malloc lock first.
+ * [93/01/19 16:37:43 bershad]
+ *
+ * Revision 2.12 93/01/14 18:05:00 danner
+ * Converted file to ANSI C.
+ * Removed use of obsolete type any_t.
+ * [92/12/18 pds]
+ * 64bit cleanup.
+ * [92/12/01 af]
+ *
+ * Free private_data in cthread_exit, from Mike Kupfer.
+ * [92/11/30 af]
+ *
* Revision 2.11 92/07/20 13:33:37 cmaeda
* In cthread_init, do machine dependent initialization if it's defined.
* [92/05/11 14:41:08 cmaeda]
- *
+ *
* Revision 2.10 91/08/28 11:19:26 jsb
* Fixed mig_init initialization in cthread_fork_child.
* [91/08/23 rpd]
- *
+ *
* Revision 2.9 91/07/31 18:34:23 dbg
* Fix bad self-pointer reference.
- *
+ *
* Don't declare _setjmp and _longjmp; they are included by
* cthreads.h.
* [91/07/30 17:33:50 dbg]
- *
+ *
* Revision 2.8 91/05/14 17:56:31 mrt
* Correcting copyright
- *
+ *
* Revision 2.7 91/02/14 14:19:47 mrt
* Added new Mach copyright
* [91/02/13 12:41:07 mrt]
- *
+ *
* Revision 2.6 90/11/05 14:37:03 rpd
* Added cthread_fork_{prepare,parent,child}.
* [90/11/02 rwd]
- *
+ *
* Add spin_lock_t.
* [90/10/31 rwd]
- *
+ *
* Revision 2.5 90/08/07 14:30:58 rpd
* Removed RCS keyword nonsense.
- *
+ *
* Revision 2.4 90/06/02 15:13:49 rpd
* Converted to new IPC.
* [90/03/20 20:56:44 rpd]
- *
+ *
* Revision 2.3 90/01/19 14:37:12 rwd
* Make cthread_init return pointer to new stack.
* [89/12/18 19:17:45 rwd]
- *
+ *
* Revision 2.2 89/12/08 19:53:37 rwd
* Change cproc and cthread counters to globals with better names.
* [89/11/02 rwd]
- *
+ *
* Revision 2.1 89/08/03 17:09:34 rwd
* Created.
- *
+ *
*
* 31-Dec-87 Eric Cooper (ecc) at Carnegie Mellon University
* Changed cthread_exit() logic for the case of the main thread,
@@ -101,22 +148,12 @@
*/
#include <cthreads.h>
+#include <mach/mig_support.h>
#include "cthread_internals.h"
-/*
- * C Threads imports:
- */
-extern void cproc_create();
-extern vm_offset_t cproc_init();
-extern void mig_init();
-
-/*
- * Mach imports:
- */
-
-/*
- * C library imports:
- */
+#ifdef HAVE_USELOCALE
+# include <locale.h>
+#endif
/*
* Thread status bits.
@@ -125,9 +162,9 @@ extern void mig_init();
#define T_RETURNED 0x2
#define T_DETACHED 0x4
-#ifdef DEBUG
+#if defined(DEBUG)
int cthread_debug = FALSE;
-#endif DEBUG
+#endif /* defined(DEBUG) */
private struct cthread_queue cthreads = QUEUE_INITIALIZER;
private struct mutex cthread_lock = MUTEX_INITIALIZER;
@@ -143,9 +180,7 @@ private spin_lock_t free_lock = SPIN_LOCK_INITIALIZER; /* unlocked */
private struct cthread initial_cthread = { 0 };
private cthread_t
-cthread_alloc(func, arg)
- cthread_fn_t func;
- any_t arg;
+cthread_alloc(cthread_fn_t func, void *arg)
{
register cthread_t t = NO_CTHREAD;
@@ -177,8 +212,7 @@ cthread_alloc(func, arg)
}
private void
-cthread_free(t)
- register cthread_t t;
+cthread_free(cthread_t t)
{
spin_lock(&free_lock);
t->next = free_cthreads;
@@ -186,8 +220,8 @@ cthread_free(t)
spin_unlock(&free_lock);
}
-int
-cthread_init()
+vm_offset_t
+cthread_init(void)
{
static int cthreads_started = FALSE;
register cproc_t p;
@@ -196,9 +230,13 @@ cthread_init()
if (cthreads_started)
return 0;
+
+ /* cthread_alloc must be called before cproc_init, because
+ malloc is not usable between initializing the new stack and
+ switching to it. */
+ t = cthread_alloc((cthread_fn_t) 0, (any_t) 0);
stack = cproc_init();
cthread_cprocs = 1;
- t = cthread_alloc((cthread_fn_t) 0, (any_t) 0);
#ifdef cthread_md_init
cthread_md_init();
@@ -224,16 +262,15 @@ cthread_init()
/*
* Used for automatic initialization by crt0.
- * Cast needed since too many C compilers choke on the type void (*)().
*/
-int (*_cthread_init_routine)() = (int (*)()) cthread_init;
+vm_offset_t (*_cthread_init_routine)(void) = cthread_init;
+
/*
* Procedure invoked at the base of each cthread.
*/
void
-cthread_body(self)
- cproc_t self;
+cthread_body(cproc_t self)
{
register cthread_t t;
@@ -251,10 +288,15 @@ cthread_body(self)
*/
mutex_unlock(&cthread_lock);
cthread_assoc(self, t); /* assume thread's identity */
- if (_setjmp(t->catch) == 0) { /* catch for cthread_exit() */
+ if (_setjmp(t->catch_exit) == 0) { /* catch for cthread_exit() */
/*
* Execute the fork request.
*/
+#ifdef HAVE_USELOCALE
+ /* A fresh thread needs to be bound to the
+ global locale. */
+ uselocale (LC_GLOBAL_LOCALE);
+#endif
t->result = (*(t->func))(t->arg);
}
/*
@@ -286,9 +328,7 @@ cthread_body(self)
}
cthread_t
-cthread_fork(func, arg)
- cthread_fn_t func;
- any_t arg;
+cthread_fork(cthread_fn_t func, void *arg)
{
register cthread_t t;
@@ -320,11 +360,10 @@ cthread_detach(t)
}
}
-any_t
-cthread_join(t)
- cthread_t t;
+void *
+cthread_join(cthread_t t)
{
- any_t result;
+ void *result;
TRACE(printf("[%s] join(%s)\n", cthread_name(cthread_self()), cthread_name(t)));
mutex_lock(&t->lock);
@@ -338,21 +377,24 @@ cthread_join(t)
}
void
-cthread_exit(result)
- any_t result;
+cthread_exit(void *result)
{
register cthread_t t = cthread_self();
TRACE(printf("[%s] exit()\n", cthread_name(t)));
t->result = result;
+ if (t->private_data != 0) {
+ free((char *)t->private_data);
+ t->private_data = 0;
+ }
if (t->state & T_MAIN) {
mutex_lock(&cthread_lock);
while (cthread_cthreads > 1)
condition_wait(&cthread_idle, &cthread_lock);
mutex_unlock(&cthread_lock);
- exit((int) result);
+ exit((int) (integer_t) result);
} else {
- _longjmp(t->catch, TRUE);
+ _longjmp(t->catch_exit, TRUE);
}
}
@@ -363,64 +405,58 @@ cthread_exit(result)
int (*_cthread_exit_routine)() = (int (*)()) cthread_exit;
void
-cthread_set_name(t, name)
- cthread_t t;
- char *name;
+cthread_set_name(cthread_t t, const char *name)
{
t->name = name;
}
-char *
-cthread_name(t)
- cthread_t t;
+const char *
+cthread_name(cthread_t t)
{
- return (t == NO_CTHREAD
- ? "idle"
- : (t->name == 0 ? "?" : t->name));
+ return (t == NO_CTHREAD ? "idle" : (t->name == 0 ? "?" : t->name));
}
int
-cthread_limit()
+cthread_limit(void)
{
return cthread_max_cprocs;
}
void
-cthread_set_limit(n)
- int n;
+cthread_set_limit(int n)
{
cthread_max_cprocs = n;
}
int
-cthread_count()
+cthread_count(void)
{
return cthread_cthreads;
}
-cthread_fork_prepare()
+void
+cthread_fork_prepare(void)
{
spin_lock(&free_lock);
mutex_lock(&cthread_lock);
- malloc_fork_prepare();
cproc_fork_prepare();
}
-cthread_fork_parent()
+void
+cthread_fork_parent(void)
{
cproc_fork_parent();
- malloc_fork_parent();
mutex_unlock(&cthread_lock);
spin_unlock(&free_lock);
}
-cthread_fork_child()
+void
+cthread_fork_child(void)
{
cthread_t t;
cproc_t p;
cproc_fork_child();
- malloc_fork_child();
mutex_unlock(&cthread_lock);
spin_unlock(&free_lock);
condition_init(&cthread_needed);
diff --git a/libthreads/cthreads.h b/libthreads/cthreads.h
index 601d3984..d937dcca 100644
--- a/libthreads/cthreads.h
+++ b/libthreads/cthreads.h
@@ -1,6 +1,6 @@
/*
* Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
@@ -25,35 +25,79 @@
*/
/*
* HISTORY
- * $Log: cthreads.h,v $
- * Revision 1.11 1996/01/24 18:37:59 roland
- * Use prototypes for functions of zero args.
- *
- * Revision 1.10 1995/09/13 19:50:07 mib
- * (CONDITION_INITIALIZER): Provide initial zero for IMPLICATIONS member.
- * (condition_init): Bother initializing NAME and IMPLICATIONS members.
- *
- * Revision 1.9 1995/08/30 15:51:41 mib
- * (condition_implies, condition_unimplies): New functions.
- * (struct condition): New member `implications'.
- * (cond_imp): New structure.
- * (cond_signal): Return int now.
- * (condition_broadcast): Always call cond_broadcast if this condition
- * has implications.
- * (condition_signal): Always call cond_signal if this condition has
- * implications.
- *
- * Revision 1.8 1995/08/30 15:10:23 mib
- * (hurd_condition_wait): Provide declaration.
+ * 20-Oct-93 Tero Kivinen (kivinen) at Helsinki University of Technology
+ * Renamed cthread_t->catch to to cthread_t->catch_exit, because
+ * catch is reserved word in c++.
*
- * Revision 1.7 1995/07/18 17:15:51 mib
- * Reverse previous change.
+ * 12-Oct-93 Johannes Helander (jvh) at Helsinki University of Technology
+ * Added CONDITION_NAMED_INITIALIZER and MUTEX_NAMED_INITIALIZER1
+ * macros. They take one argument: a name string.
*
- * Revision 1.5 1995/04/04 21:06:16 roland
- * (mutex_lock, mutex_unlock): Use __ names for *_solid.
- *
- * Revision 1.4 1994/05/05 10:52:06 roland
- * entered into RCS
+ * $Log: cthreads.h,v $
+ * Revision 1.19 2002/05/28 23:55:58 roland
+ * 2002-05-28 Roland McGrath <roland@frob.com>
+ *
+ * * cthreads.h (hurd_condition_wait, condition_implies,
+ * condition_unimplies): Restore decls lost in merge.
+ * (mutex_clear): Define as mutex_init instead of bogon (lost in merge).
+ *
+ * Revision 1.18 2002/05/27 02:50:10 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * Changes merged from CMU MK83a version:
+ * * cthreads.h, options.h: Various cleanups.
+ * * call.c, cthread_data.c, sync.c, mig_support.c: Likewise.
+ * * i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
+ * * cthread_internals.h: Add decls for internal functions.
+ * (struct cproc): Use vm_offset_t for stack_base and stack_size members.
+ * Use natural_t for context member.
+ * * cprocs.c: Use prototypes for all defns.
+ * * cthreads.c: Likewise.
+ * (cthread_exit): Cast any_t to integer_t before int.
+ *
+ * Revision 2.17 93/05/10 19:43:11 rvb
+ * Removed include of stdlib.h and just define malloc
+ * [93/04/27 mrt]
+ *
+ * Revision 2.16 93/05/10 17:51:26 rvb
+ * Just imagine how much more useful TWO special/fast lookup
+ * variables could be. (Actually, I am planning on using this
+ * for bsdss -- for multiple threads per task. If I don't, I'll
+ * remove the feature.)
+ * [93/05/10 rvb]
+ * Big mistake here! CTHREAD_DATA must always be set TRUE.
+ * cthreads.h is included by import_mach.h by lots of files
+ * that are not compiled with -DCTHREAD_DATA. This means
+ * they see a different structure for cthread_t than the
+ * cthread library -- which is compiled with CTHREAD_DATA.
+ * Also, make cthread_set_data and cthread_data macros.
+ * [93/05/06 rvb]
+ * Flush stdlib
+ * [93/05/05 rvb]
+ *
+ * Revision 2.15 93/01/27 09:03:32 danner
+ * Updated include of mach/mach.h to mach.h
+ *
+ *
+ * Revision 2.14 93/01/24 13:24:50 danner
+ * Get MACRO_BEGIN, MACRO_END, NEVER, ... from sys/macro_help.h
+ * why define it here.
+ * [92/10/20 rvb]
+ *
+ * Revision 2.13 93/01/14 18:05:04 danner
+ * Added MACRO_BEGIN and MACRO_END to definition of spin_lock.
+ * Fixed return value of cthread_set_data.
+ * Added prototypes for other miscellaneous functions.
+ * [92/12/18 pds]
+ * Converted file to ANSI C.
+ * Added declarations of cthread_fork_{prepare,parent,child}.
+ * Added include of <sys/macro_help.h>.
+ * [92/12/13 pds]
+ *
+ * Replaced calloc declaration with an include of stdlib.h.
+ * [92/06/15 pds]
+ * 64bit cleanup.
+ * [92/12/02 af]
*
* Revision 2.12 92/05/22 18:38:36 jfriedl
* From Mike Kupfer <kupfer@sprite.Berkeley.EDU>:
@@ -193,62 +237,49 @@
#ifndef _CTHREADS_
#define _CTHREADS_ 1
-/* MIB XXX */
-#define CTHREAD_DATA
-
#if 0
/* This is CMU's machine-dependent file. In GNU all of the machine
dependencies are dealt with in libc. */
#include <machine/cthreads.h>
+#include <mach.h>
+#include <sys/macro_help.h>
+#include <mach/machine/vm_param.h>
+
+#ifdef __STDC__
+extern void *malloc();
#else
-#include <machine-sp.h>
-#define cthread_sp() ((int) __thread_stack_pointer ())
+extern char *malloc();
#endif
-#if c_plusplus || __STDC__
-
-#ifndef C_ARG_DECLS
-#define C_ARG_DECLS(arglist) arglist
-#endif /* not C_ARG_DECLS */
-
-typedef void *any_t;
-
-#else /* not (c_plusplus || __STDC__) */
-
-#ifndef C_ARG_DECLS
-#define C_ARG_DECLS(arglist) ()
-#endif /* not C_ARG_DECLS */
-
-typedef char *any_t;
-
-#endif /* not (c_plusplus || __STDC__) */
+#else /* GNU */
+# include <stdlib.h>
+# include <mach.h>
+# include <mach/machine/vm_param.h>
+# include <machine-sp.h>
+# define cthread_sp() ((vm_address_t) __thread_stack_pointer ())
+# define MACRO_BEGIN __extension__ ({
+# define MACRO_END 0; })
+#endif
-#include <mach/mach.h>
-#include <mach/machine/vm_param.h>
+typedef void *any_t; /* XXX - obsolete, should be deleted. */
-#ifndef TRUE
+#if defined(TRUE)
+#else /* not defined(TRUE) */
#define TRUE 1
#define FALSE 0
-#endif /* TRUE */
-
-#ifndef MACRO_BEGIN
-
-#define MACRO_BEGIN do {
-#define MACRO_END } while (0)
+#endif
-#endif MACRO_BEGIN
+/* Enable mutex holder debugging */
+/* #define WAIT_DEBUG */
+/* Record function name instead of thread pointer */
+/* #define WAIT_FUNC_DEBUG */
/*
* C Threads package initialization.
*/
-extern int cthread_init C_ARG_DECLS((void));
-#if 0
-/* This prototype is broken for GNU. */
-extern any_t calloc C_ARG_DECLS((unsigned n, unsigned size));
-#else
-#include <stdlib.h>
-#endif
+extern vm_offset_t cthread_init(void);
+
/*
* Queues.
@@ -268,7 +299,7 @@ typedef struct cthread_queue_item {
#define cthread_queue_alloc() ((cthread_queue_t) calloc(1, sizeof(struct cthread_queue)))
#define cthread_queue_init(q) ((q)->head = (q)->tail = 0)
-#define cthread_queue_free(q) free((any_t) (q))
+#define cthread_queue_free(q) free((q))
#define cthread_queue_enq(q, x) \
MACRO_BEGIN \
@@ -300,7 +331,7 @@ typedef struct cthread_queue_item {
#define cthread_queue_map(q, t, f) \
MACRO_BEGIN \
register cthread_queue_item_t x, next; \
- for (x = (cthread_queue_item_t) ((q)->head); x != 0; x = next) { \
+ for (x = (cthread_queue_item_t) ((q)->head); x != 0; x = next){\
next = x->next; \
(*(f))((t) x); \
} \
@@ -317,20 +348,24 @@ typedef struct cthread_queue_item {
/*
* Spin locks.
*/
-extern void
-spin_lock_solid C_ARG_DECLS((spin_lock_t *p));
+extern void spin_lock_solid(spin_lock_t *_lock);
-#ifndef spin_unlock
-extern void
-spin_unlock C_ARG_DECLS((spin_lock_t *p));
+#if defined(spin_unlock)
+#else /* not defined(spin_unlock) */
+extern void spin_unlock(spin_lock_t *_lock);
#endif
-#ifndef spin_try_lock
-extern int
-spin_try_lock C_ARG_DECLS((spin_lock_t *p));
+#if defined(spin_try_lock)
+#else /* not defined(spin_try_lock) */
+extern boolean_t spin_try_lock(spin_lock_t *_lock);
#endif
-#define spin_lock(p) ({if (!spin_try_lock(p)) spin_lock_solid(p);})
+#define spin_lock(p) \
+ MACRO_BEGIN \
+ if (!spin_try_lock(p)) { \
+ spin_lock_solid(p); \
+ } \
+ MACRO_END
#endif /* End unused CMU code. */
@@ -344,12 +379,32 @@ typedef struct mutex {
see if it gets the mutex. */
spin_lock_t held;
spin_lock_t lock;
- char *name;
+ const char *name;
struct cthread_queue queue;
+ /* holder is for WAIT_DEBUG. Not ifdeffed to keep size constant. */
+#ifdef WAIT_FUNC_DEBUG
+ const char *fname;
+#else /* WAIT_FUNC_DEBUG */
+ struct cthread *holder;
+#endif /* WAIT_FUNC_DEBUG */
} *mutex_t;
+#ifdef WAIT_DEBUG
+#ifdef WAIT_FUNC_DEBUG
+#define WAIT_CLEAR_DEBUG(m) (m)->fname = 0
+#define WAIT_SET_DEBUG(m) (m)->fname = __FUNCTION__
+#else /* WAIT_FUNC_DEBUG */
+#define WAIT_CLEAR_DEBUG(m) (m)->holder = 0
+#define WAIT_SET_DEBUG(m) (m)->holder = cthread_self()
+#endif /* WAIT_FUNC_DEBUG */
+#else /* WAIT_DEBUG */
+#define WAIT_CLEAR_DEBUG(m) (void) 0
+#define WAIT_SET_DEBUG(m) (void) 0
+#endif /* WAIT_DEBUG */
+
/* Rearranged accordingly for GNU: */
-#define MUTEX_INITIALIZER { SPIN_LOCK_INITIALIZER, SPIN_LOCK_INITIALIZER, 0, QUEUE_INITIALIZER }
+#define MUTEX_INITIALIZER { SPIN_LOCK_INITIALIZER, SPIN_LOCK_INITIALIZER, 0, QUEUE_INITIALIZER, }
+#define MUTEX_NAMED_INITIALIZER(Name) { SPIN_LOCK_INITIALIZER, SPIN_LOCK_INITIALIZER, Name, QUEUE_INITIALIZER, }
#define mutex_alloc() ((mutex_t) calloc(1, sizeof(struct mutex)))
#define mutex_init(m) \
@@ -357,37 +412,36 @@ typedef struct mutex {
spin_lock_init(&(m)->lock); \
cthread_queue_init(&(m)->queue); \
spin_lock_init(&(m)->held); \
+ WAIT_CLEAR_DEBUG(m); \
MACRO_END
#define mutex_set_name(m, x) ((m)->name = (x))
#define mutex_name(m) ((m)->name != 0 ? (m)->name : "?")
-#define mutex_clear(m) /* nop */???
-#define mutex_free(m) free((any_t) (m))
-
-extern void __mutex_lock_solid (void *mutex); /* blocking -- roland@gnu */
-extern void __mutex_unlock_solid (void *mutex); /* roland@gnu */
+#define mutex_clear(m) mutex_init(m)
+#define mutex_free(m) free((m))
-#define mutex_try_lock(m) spin_try_lock(&(m)->held)
+#define mutex_try_lock(m) (spin_try_lock(&(m)->held) ? WAIT_SET_DEBUG(m), 1 : 0)
#define mutex_lock(m) \
MACRO_BEGIN \
if (!spin_try_lock(&(m)->held)) { \
__mutex_lock_solid(m); \
} \
+ WAIT_SET_DEBUG(m); \
MACRO_END
#define mutex_unlock(m) \
MACRO_BEGIN \
if (spin_unlock(&(m)->held), \
- cthread_queue_head(&(m)->queue, int) != 0) { \
+ cthread_queue_head(&(m)->queue, vm_offset_t) != 0) { \
__mutex_unlock_solid(m); \
} \
+ WAIT_CLEAR_DEBUG(m); \
MACRO_END
-
/*
* Condition variables.
*/
typedef struct condition {
spin_lock_t lock;
struct cthread_queue queue;
- char *name;
+ const char *name;
struct cond_imp *implications;
} *condition_t;
@@ -398,8 +452,10 @@ struct cond_imp
};
#define CONDITION_INITIALIZER { SPIN_LOCK_INITIALIZER, QUEUE_INITIALIZER, 0, 0 }
+#define CONDITION_NAMED_INITIALIZER(Name) { SPIN_LOCK_INITIALIZER, QUEUE_INITIALIZER, Name, 0 }
-#define condition_alloc() ((condition_t) calloc(1, sizeof(struct condition)))
+#define condition_alloc() \
+ ((condition_t) calloc(1, sizeof(struct condition)))
#define condition_init(c) \
MACRO_BEGIN \
spin_lock_init(&(c)->lock); \
@@ -417,7 +473,7 @@ struct cond_imp
#define condition_free(c) \
MACRO_BEGIN \
condition_clear(c); \
- free((any_t) (c)); \
+ free((c)); \
MACRO_END
#define condition_signal(c) \
@@ -434,29 +490,23 @@ struct cond_imp
} \
MACRO_END
-extern int
-cond_signal C_ARG_DECLS((condition_t c));
-
-extern void
-cond_broadcast C_ARG_DECLS((condition_t c));
+extern int cond_signal(condition_t _cond);
-extern void
-condition_wait C_ARG_DECLS((condition_t c, mutex_t m));
+extern void cond_broadcast(condition_t _cond);
-extern int
-hurd_condition_wait C_ARG_DECLS((condition_t c, mutex_t m));
+extern void condition_wait(condition_t _cond, mutex_t _mutex);
+extern int hurd_condition_wait(condition_t _cond, mutex_t _mutex);
-extern void
-condition_implies C_ARG_DECLS((condition_t implicator, condition_t implicatand));
-
-extern void
-condition_unimplies C_ARG_DECLS((condition_t implicator, condition_t implicatand));
+extern void condition_implies(condition_t _implicator,
+ condition_t _implicatand);
+extern void condition_unimplies(condition_t _implicator,
+ condition_t _implicatand);
/*
* Threads.
*/
-typedef any_t (*cthread_fn_t) C_ARG_DECLS((any_t arg));
+typedef void * (*cthread_fn_t)(void *arg);
#include <setjmp.h>
@@ -465,34 +515,28 @@ typedef struct cthread {
struct mutex lock;
struct condition done;
int state;
- jmp_buf catch;
+ jmp_buf catch_exit;
cthread_fn_t func;
- any_t arg;
- any_t result;
- char *name;
-#ifdef CTHREAD_DATA
- any_t data;
-#endif CTHREAD_DATA
- any_t private_data;
+ void *arg;
+ void *result;
+ const char *name;
+ void *data;
+ void *ldata;
+ void *private_data;
struct ur_cthread *ur;
} *cthread_t;
#define NO_CTHREAD ((cthread_t) 0)
-extern cthread_t
-cthread_fork C_ARG_DECLS((cthread_fn_t func, any_t arg));
+extern cthread_t cthread_fork(cthread_fn_t _func, void *_arg);
-extern void
-cthread_detach C_ARG_DECLS((cthread_t t));
+extern void cthread_detach(cthread_t _thread);
-extern any_t
-cthread_join C_ARG_DECLS((cthread_t t));
+extern any_t cthread_join(cthread_t _thread);
-extern void
-cthread_yield C_ARG_DECLS((void));
+extern void cthread_yield(void);
-extern void
-cthread_exit C_ARG_DECLS((any_t result));
+extern void cthread_exit(void *_result);
/*
* This structure must agree with struct cproc in cthread_internals.h
@@ -503,20 +547,20 @@ typedef struct ur_cthread {
} *ur_cthread_t;
#ifndef cthread_sp
-extern int
-cthread_sp C_ARG_DECLS((void));
+extern vm_offset_t
+cthread_sp(void);
#endif
-extern int cthread_stack_mask;
+extern vm_offset_t cthread_stack_mask;
-#ifdef STACK_GROWTH_UP
+#if defined(STACK_GROWTH_UP)
#define ur_cthread_ptr(sp) \
(* (ur_cthread_t *) ((sp) & cthread_stack_mask))
-#else STACK_GROWTH_UP
+#else /* not defined(STACK_GROWTH_UP) */
#define ur_cthread_ptr(sp) \
(* (ur_cthread_t *) ( ((sp) | cthread_stack_mask) + 1 \
- sizeof(ur_cthread_t *)) )
-#endif STACK_GROWTH_UP
+#endif /* defined(STACK_GROWTH_UP) */
#define ur_cthread_self() (ur_cthread_ptr(cthread_sp()))
@@ -524,37 +568,80 @@ extern int cthread_stack_mask;
((t) ? ((t)->ur = (ur_cthread_t)(id)) : 0))
#define cthread_self() (ur_cthread_self()->incarnation)
-extern void
-cthread_set_name C_ARG_DECLS((cthread_t t, char *name));
+extern void cthread_set_name(cthread_t _thread, const char *_name);
+
+extern const char * cthread_name(cthread_t _thread);
+
+extern int cthread_count(void);
+
+extern void cthread_set_limit(int _limit);
+
+extern int cthread_limit(void);
+
+extern void cthread_set_kernel_limit(int _n);
+
+extern int cthread_kernel_limit(void);
+
+extern void cthread_wire(void);
+
+extern void cthread_unwire(void);
-extern char *
-cthread_name C_ARG_DECLS((cthread_t t));
+extern void cthread_msg_busy(mach_port_t _port, int _min, int _max);
-extern int
-cthread_count C_ARG_DECLS((void));
+extern void cthread_msg_active(mach_port_t _prt, int _min, int _max);
-extern void
-cthread_set_limit C_ARG_DECLS((int n));
+extern mach_msg_return_t cthread_mach_msg(mach_msg_header_t *_header,
+ mach_msg_option_t _option,
+ mach_msg_size_t _send_size,
+ mach_msg_size_t _rcv_size,
+ mach_port_t _rcv_name,
+ mach_msg_timeout_t _timeout,
+ mach_port_t _notify,
+ int _min, int _max);
-extern int
-cthread_limit C_ARG_DECLS((void));
+extern void cthread_fork_prepare(void);
-extern void
-cthread_wire C_ARG_DECLS((void));
+extern void cthread_fork_parent(void);
-#ifdef CTHREAD_DATA
+extern void cthread_fork_child(void);
+
+#if defined(THREAD_CALLS)
+/*
+ * Routines to replace thread_*.
+ */
+extern kern_return_t cthread_get_state(cthread_t _thread);
+
+extern kern_return_t cthread_set_state(cthread_t _thread);
+
+extern kern_return_t cthread_abort(cthread_t _thread);
+
+extern kern_return_t cthread_resume(cthread_t _thread);
+
+extern kern_return_t cthread_suspend(cthread_t _thread);
+
+extern kern_return_t cthread_call_on(cthread_t _thread);
+#endif /* defined(THREAD_CALLS) */
+
+#if defined(CTHREAD_DATA_XX)
/*
* Set or get thread specific "global" variable
*
* The thread given must be the calling thread (ie. thread_self).
* XXX This is for compatibility with the old cthread_data. XXX
*/
-extern int
-cthread_set_data C_ARG_DECLS((cthread_t t, any_t x));
+extern int cthread_set_data(cthread_t _thread, void *_val);
+
+extern void * cthread_data(cthread_t _thread);
+#else /* defined(CTHREAD_DATA_XX) */
+
+#define cthread_set_data(_thread, _val) ((_thread)->data) = (void *)(_val);
+#define cthread_data(_thread) ((_thread)->data)
+
+#define cthread_set_ldata(_thread, _val) ((_thread)->ldata) = (void *)(_val);
+#define cthread_ldata(_thread) ((_thread)->ldata)
+
+#endif /* defined(CTHREAD_DATA_XX) */
-extern any_t
-cthread_data C_ARG_DECLS((cthread_t t));
-#endif CTHREAD_DATA
/*
* Support for POSIX thread specific data
@@ -562,7 +649,7 @@ cthread_data C_ARG_DECLS((cthread_t t));
* Multiplexes a thread specific "global" variable
* into many thread specific "global" variables.
*/
-#define CTHREAD_DATA_VALUE_NULL (any_t)0
+#define CTHREAD_DATA_VALUE_NULL (void *)0
#define CTHREAD_KEY_INVALID (cthread_key_t)-1
typedef int cthread_key_t;
@@ -572,27 +659,25 @@ typedef int cthread_key_t;
* Different threads may use same key, but the values bound to the key are
* maintained on a thread specific basis.
*/
-extern int
-cthread_keycreate C_ARG_DECLS((cthread_key_t *key));
+extern int cthread_keycreate(cthread_key_t *_key);
/*
* Get value currently bound to key for calling thread
*/
-extern int
-cthread_getspecific C_ARG_DECLS((cthread_key_t key, any_t *value));
+extern int cthread_getspecific(cthread_key_t _key, void **_value);
/*
* Bind value to given key for calling thread
*/
-extern int
-cthread_setspecific C_ARG_DECLS((cthread_key_t key, any_t value));
+extern int cthread_setspecific(cthread_key_t _key, void *_value);
/*
* Debugging support.
*/
-#ifdef DEBUG
+#if defined(DEBUG)
-#ifndef ASSERT
+#if defined(ASSERT)
+#else /* not defined(ASSERT) */
/*
* Assertion macro, similar to <assert.h>
*/
@@ -607,18 +692,19 @@ cthread_setspecific C_ARG_DECLS((cthread_key_t key, any_t value));
} \
MACRO_END
-#endif ASSERT
+#endif /* defined(ASSERT) */
#define SHOULDNT_HAPPEN 0
extern int cthread_debug;
-#else DEBUG
+#else /* not defined(DEBUG) */
-#ifndef ASSERT
+#if defined(ASSERT)
+#else /* not defined(ASSERT) */
#define ASSERT(p)
-#endif ASSERT
+#endif /* defined(ASSERT) */
-#endif DEBUG
+#endif /* defined(DEBUG) */
-#endif _CTHREADS_
+#endif /* not defined(_CTHREADS_) */
diff --git a/libthreads/i386/csw.S b/libthreads/i386/csw.S
index 0951c5cc..69c93652 100644
--- a/libthreads/i386/csw.S
+++ b/libthreads/i386/csw.S
@@ -1,31 +1,57 @@
-/*
+/*
* Mach Operating System
* Copyright (c) 1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* HISTORY
* $Log: csw.S,v $
+ * Revision 1.9 1998/07/20 06:58:28 roland
+ * 1998-07-20 Roland McGrath <roland@baalperazim.frob.com>
+ *
+ * * i386/csw.S (cproc_prepare): Take address of cthread_body as third
+ * arg, so we don't have to deal with PIC magic to find its address
+ * without producing a text reloc.
+ * * cprocs.c (cproc_create): Pass &cthread_body to cproc_prepare.
+ *
+ * Revision 1.8 1997/04/04 01:31:16 thomas
+ * Thu Apr 3 20:29:27 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+ *
+ * * i386/csw.S: Define __ELF__ too.
+ *
+ * Revision 1.7 1996/10/24 19:30:10 thomas
+ * Mon Oct 21 22:05:48 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+ *
+ * * i386/csw.S (CALL_MCOUNT): New macro.
+ * (cproc_swtich, cproc_start_wait, cproc_prepare): Use CALL_MCOUNT.
+ *
+ * Revision 1.6 1996/08/29 17:44:42 thomas
+ * *** empty log message ***
+ *
+ * Revision 1.5 1995/10/04 20:55:28 roland
+ * (JUMPTARGET): New macro, versions for [PIC] and not.
+ * Use it in place of EXT.
+ *
* Revision 1.4 1995/10/04 20:22:17 roland
* [PIC] (EXT): Redefine to use PLT.
*
@@ -38,28 +64,31 @@
* Revision 2.7 91/07/31 18:36:32 dbg
* Fix for ANSI C preprocessor.
* [91/07/30 17:35:16 dbg]
- *
+ *
* Revision 2.6 91/05/14 17:56:56 mrt
* Correcting copyright
- *
+ *
* Revision 2.5 91/05/08 13:35:49 dbg
* Unlock lock with a locked instruction (xchg).
* [91/03/20 dbg]
- *
+ *
* Revision 2.4 91/02/14 14:20:02 mrt
* Changed to new Mach copyright
* [91/02/13 12:15:27 mrt]
- *
+ *
* Revision 2.3 91/01/08 16:46:20 rpd
* Don't use Times - horta doesn't like it for some reason.
* [91/01/06 rpd]
- *
+ *
* Revision 2.2 90/05/03 15:54:37 dbg
* Created.
* [90/02/05 dbg]
- *
+ *
*/
-#include <i386/asm.h>
+#define ELF
+#undef __ELF__
+#define __ELF__ 1
+#include <mach/i386/asm.h>
#ifdef PIC
#define JUMPTARGET(name) EXT(name##@PLT)
@@ -67,12 +96,21 @@
#define JUMPTARGET(name) EXT(name)
#endif
+#ifdef PROF
+#define CALL_MCOUNT \
+ pushl %ebp; movl %esp, %ebp; call JUMPTARGET(mcount); popl %ebp;
+#else
+#define CALL_MCOUNT
+#endif
+
+
/*
* Suspend the current thread and resume the next one.
*
* void cproc_switch(int *cur, int *next, int *lock)
*/
ENTRY(cproc_switch)
+ CALL_MCOUNT
pushl %ebp /* save ebp */
movl %esp,%ebp /* set frame pointer to get arguments */
pushl %ebx /* save ebx */
@@ -86,7 +124,7 @@ ENTRY(cproc_switch)
movl (%eax),%esp /* get new stack pointer */
xorl %eax,%eax /* unlock */
xchgl %eax,(%edx) /* the lock - now old thread can run */
-
+
popl %edi /* restore di */
popl %esi /* si */
popl %ebx /* bx */
@@ -104,6 +142,7 @@ ENTRY(cproc_switch)
* int *lock)
*/
ENTRY(cproc_start_wait)
+ CALL_MCOUNT
pushl %ebp /* save ebp */
movl %esp,%ebp /* set frame pointer */
pushl %ebx /* save ebx */
@@ -126,9 +165,11 @@ ENTRY(cproc_start_wait)
* it, it will start up as if it called
* cproc_body(child)
*
- * void cproc_prepare(cproc_t child, int *context, int stack)
+ * void cproc_prepare(cproc_t child, int *context, int stack,
+ * void (*cthread_body)(cproc_t));
*/
ENTRY(cproc_prepare)
+ CALL_MCOUNT
pushl %ebp /* save ebp */
movl %esp,%ebp /* set frame pointer */
movl B_ARG2,%edx /* get child`s stack */
@@ -142,8 +183,8 @@ ENTRY(cproc_prepare)
/* 20 return PC from cthread_body */
/* 24 argument to cthread_body */
movl $0,12(%edx) /* clear frame pointer */
- movl $JUMPTARGET(cthread_body),16(%edx)
- /* resume at cthread_body */
+ movl B_ARG3,%ecx /* get address of cthread_body passed in */
+ movl %ecx,16(%edx) /* set child to resume at cthread_body */
movl $0,20(%edx) /* fake return address from cthread_body */
movl B_ARG0,%ecx /* get child thread pointer */
movl %ecx,24(%edx) /* set as argument to cthread_body */
@@ -151,4 +192,3 @@ ENTRY(cproc_prepare)
movl %edx,(%ecx) /* save context */
leave
ret
-
diff --git a/libthreads/i386/cthreads.h b/libthreads/i386/cthreads.h
index 8ffe4b72..694387b6 100644
--- a/libthreads/i386/cthreads.h
+++ b/libthreads/i386/cthreads.h
@@ -1,6 +1,6 @@
/*
* Mach Operating System
- * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1993,1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
@@ -25,7 +25,37 @@
*/
/*
* HISTORY
- * $Log: cthreads.h,v $
+ * $Log: cthreads.h,v $
+ * Revision 1.3 2007/03/03 23:57:37 sthibaul
+ * 2006-03-04 Samuel Thibault <samuel.thibault@ens-lyon.org>
+ *
+ * * libpthread/sysdeps/i386/machine-sp.h (thread_stack_pointer):
+ * Optimize esp read.
+ * * libpthread/i386/cthreads.h (cthread_sp): Likewise.
+ *
+ * Revision 1.2 2002/05/27 02:50:10 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * Changes merged from CMU MK83a version:
+ * * cthreads.h, options.h: Various cleanups.
+ * * call.c, cthread_data.c, sync.c, mig_support.c: Likewise.
+ * * i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
+ * * cthread_internals.h: Add decls for internal functions.
+ * (struct cproc): Use vm_offset_t for stack_base and stack_size members.
+ * Use natural_t for context member.
+ * * cprocs.c: Use prototypes for all defns.
+ * * cthreads.c: Likewise.
+ * (cthread_exit): Cast any_t to integer_t before int.
+ *
+ * Revision 2.9 93/01/24 13:24:58 danner
+ * Move ! in spin_try_lock to give the compiler
+ * a fighting chance.
+ * [92/11/19 rvb]
+ *
+ * Revision 2.8 93/01/14 18:05:09 danner
+ * asm -> __asm__
+ * [93/01/10 danner]
+ *
* Revision 2.7 92/01/03 20:36:59 dbg
* Add volatile to spin_lock_t. Change spin_unlock and
* spin_try_lock definitions back to memory operands, but rely on
@@ -66,22 +96,20 @@ typedef volatile int spin_lock_t;
#define spin_unlock(p) \
({ register int _u__ ; \
- asm volatile("xorl %0, %0; \n\
+ __asm__ volatile("xorl %0, %0; \n\
xchgl %0, %1" \
- : "=&r" (_u__), "=m" (*(p)) ); \
+ : "=&r" (_u__), "=m" (*(p)) :: "memory" ); \
0; })
#define spin_try_lock(p)\
- ({ boolean_t _r__; \
- asm volatile("movl $1, %0; \n\
+ (!({ boolean_t _r__; \
+ __asm__ volatile("movl $1, %0; \n\
xchgl %0, %1" \
- : "=&r" (_r__), "=m" (*(p)) ); \
- !_r__; })
+ : "=&r" (_r__), "=m" (*(p)) :: "memory" ); \
+ _r__; }))
#define cthread_sp() \
- ({ int _sp__; \
- asm("movl %%esp, %0" \
- : "=g" (_sp__) ); \
+ ({ register int _sp__ asm("esp"); \
_sp__; })
#endif /* __GNUC__ */
diff --git a/libthreads/i386/lock.s b/libthreads/i386/lock.s
index e27fa7ff..f064e5bb 100644
--- a/libthreads/i386/lock.s
+++ b/libthreads/i386/lock.s
@@ -26,6 +26,10 @@
/*
* HISTORY
* $Log: lock.s,v $
+ * Revision 2.6 93/05/10 17:51:38 rvb
+ * Use C Comment
+ * [93/05/04 18:14:05 rvb]
+ *
* Revision 2.5 91/05/14 17:57:20 mrt
* Correcting copyright
*
@@ -49,22 +53,22 @@
* boolean_t spin_try_lock(int *m)
*/
ENTRY(spin_try_lock)
- movl 4(%esp),%ecx / point at mutex
- movl $1,%eax / set locked value in acc
- xchg %eax,(%ecx) / swap with mutex
- / xchg with memory is automatically
- / locked
- xorl $1,%eax / 1 (locked) => FALSE
- / 0 (locked) => TRUE
+ movl 4(%esp),%ecx /* point at mutex */
+ movl $1,%eax /* set locked value in acc */
+ xchg %eax,(%ecx) /* swap with mutex */
+ /* xchg with memory is automatically */
+ /* locked */
+ xorl $1,%eax /* 1 (locked) => FALSE */
+ /* 0 (locked) => TRUE */
ret
/*
* void spin_unlock(int *m)
*/
ENTRY(spin_unlock)
- movl 4(%esp),%ecx / point at mutex
- xorl %eax,%eax / set unlocked value in acc
- xchg %eax,(%ecx) / swap with mutex
- / xchg with memory is automatically
- / locked
+ movl 4(%esp),%ecx /* point at mutex */
+ xorl %eax,%eax /* set unlocked value in acc */
+ xchg %eax,(%ecx) /* swap with mutex */
+ /* xchg with memory is automatically */
+ /* locked */
ret
diff --git a/libthreads/i386/thread.c b/libthreads/i386/thread.c
index 8ba81826..00537be5 100644
--- a/libthreads/i386/thread.c
+++ b/libthreads/i386/thread.c
@@ -1,50 +1,52 @@
-/*
+/*
* Mach Operating System
- * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1992,1991,1990 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* HISTORY
* $Log: thread.c,v $
+ * Revision 2.8 93/02/02 21:54:58 mrt
+ * Changed include of mach/mach.h to mach.h.
+ * [93/02/02 mrt]
+ *
+ * Revision 2.7 93/01/14 18:05:15 danner
+ * Converted file to ANSI C.
+ * Fixed argument types.
+ * [92/12/18 pds]
+ *
* Revision 2.6 91/07/31 18:37:07 dbg
* Undefine cthread_sp macro around function definition.
* [91/07/30 17:36:23 dbg]
- *
- * Revision 2.5 91/05/14 17:57:27 mrt
- * Correcting copyright
- *
- * Revision 2.4 91/02/14 14:20:21 mrt
- * Changed to new Mach copyright
- * [91/02/13 12:20:10 mrt]
- *
+ *
* Revision 2.3 90/06/02 15:13:53 rpd
* Added definition of cthread_sp.
* [90/06/02 rpd]
- *
+ *
* Revision 2.2 90/05/03 15:55:03 dbg
* Created (from 68020 version).
* [90/02/05 dbg]
- *
+ *
*/
/*
* i386/thread.c
@@ -52,20 +54,28 @@
*/
#ifndef lint
-static char rcs_id[] = "$Header: cvs-sans-libpthread/hurd/libthreads/i386/thread.c,v 1.2 1994/05/04 19:05:26 mib Exp $";
-#endif not lint
+char rcs_id[] = "$Header: cvs-sans-libpthread/hurd/libthreads/i386/thread.c,v 1.7 2002/05/27 02:50:10 roland Exp $";
+#endif /* not lint */
-#include "../cthreads.h"
-#include "../cthread_internals.h"
-
+#include <cthreads.h>
+#include "cthread_internals.h"
+#include <mach.h>
+#include <mach/i386/mach_i386.h>
+#include <mach/mig_errors.h>
-#include <mach/mach.h>
-
-/*
- * C library imports:
- */
-extern bzero();
+#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
@@ -73,42 +83,53 @@ extern bzero();
* when it is resumed.
*/
void
-cproc_setup(child, thread, routine)
- register cproc_t child;
- int thread;
- int routine;
+cproc_setup(register cproc_t child, thread_t thread, tcbhead_t *tcb, void (*routine)(cproc_t))
{
- register int *top = (int *) (child->stack_base + child->stack_size);
+ extern unsigned int __hurd_threadvar_max; /* GNU */
+ register int *top = (int *)
+ cproc_stack_base (child,
+ sizeof(ur_cthread_t *) +
+ /* Account for GNU per-thread variables. */
+ __hurd_threadvar_max *
+ sizeof (long int));
struct i386_thread_state state;
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 = routine;
+ ts->eip = (int) routine;
*--top = (int) child; /* argument to function */
*--top = 0; /* fake return address */
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);
}
-#ifdef cthread_sp
+#if defined(cthread_sp)
#undef cthread_sp
#endif
int
-cthread_sp()
+cthread_sp(void)
{
- int x;
-
- return (int) &x;
+ return (int) __thread_stack_pointer ();
}
-
diff --git a/libthreads/libthreads.map b/libthreads/libthreads.map
new file mode 100644
index 00000000..1a041f71
--- /dev/null
+++ b/libthreads/libthreads.map
@@ -0,0 +1,27 @@
+/* This is the version script file used for building libthreads.so. -*- C -*-
+ It is in the form of a linker script, to be including as an input
+ file in the link command, rather than with --version-script. */
+
+/* We only use this file when we build against a libio-using libc,
+ which we presume will be 2.2 that is expecting our lockfile.c
+ hooks. Therefore the flockfile functions are added to the
+ GLIBC_2.2.6 version node. The rest of the library's symbols will use
+ HURD_CTHREADS_0.3. */
+
+VERSION
+{
+ GLIBC_2.2.6
+ {
+ global:
+ _IO_flockfile; _IO_funlockfile; _IO_ftrylockfile;
+ flockfile; funlockfile; ftrylockfile;
+ local:
+ _cthreads_flockfile; _cthreads_funlockfile; _cthreads_ftrylockfile;
+ };
+
+ HURD_CTHREADS_0.3
+ {
+ global:
+ *;
+ };
+};
diff --git a/libthreads/lockfile.c b/libthreads/lockfile.c
new file mode 100644
index 00000000..eeb1a2f3
--- /dev/null
+++ b/libthreads/lockfile.c
@@ -0,0 +1,65 @@
+/* lockfile - Handle locking and unlocking of streams. Hurd cthreads version.
+ Copyright (C) 2000,01,02 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 <cthreads.h> /* Must come before <stdio.h>! */
+#include <stdio.h>
+
+
+#ifdef _STDIO_USES_IOSTREAM
+
+void
+_cthreads_flockfile (_IO_FILE *fp)
+{
+ _IO_lock_lock (*fp->_lock);
+}
+
+void
+_cthreads_funlockfile (_IO_FILE *fp)
+{
+ _IO_lock_unlock (*fp->_lock);
+}
+
+int
+_cthreads_ftrylockfile (_IO_FILE *fp)
+{
+ return __libc_lock_trylock_recursive (*fp->_lock);
+}
+
+# undef _IO_flockfile
+# undef _IO_funlockfile
+# undef _IO_ftrylockfile
+# undef flockfile
+# undef funlockfile
+# undef ftrylockfile
+
+void _IO_flockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_flockfile")));
+void _IO_funlockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_funlockfile")));
+int _IO_ftrylockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_ftrylockfile")));
+
+void flockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_flockfile")));
+void funlockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_funlockfile")));
+int ftrylockfile (_IO_FILE *)
+ __attribute__ ((alias ("_cthreads_ftrylockfile")));
+
+#endif /* _STDIO_USES_IOSTREAM */
diff --git a/libthreads/malloc.c b/libthreads/malloc.c
deleted file mode 100644
index abf971f7..00000000
--- a/libthreads/malloc.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
-/*
- * HISTORY
- * $Log: malloc.c,v $
- * Revision 1.6 1996/03/07 21:13:08 miles
- * (realloc):
- * Use LOG2_MIN_SIZE.
- * Don't bother allocating a new block if the new size request fits in the old
- * one and doesn't waste any space.
- * Only free the old block if we successfully got a new one.
- * (LOG2_MIN_SIZE): New macro.
- *
- * Revision 1.5 1996/03/06 23:51:04 miles
- * [MCHECK] (struct header): New type.
- * (union header): Only define if !MCHECK.
- * (HEADER_SIZE, HEADER_NEXT, HEADER_FREE, HEADER_CHECK): New macros.
- * [MCHECK] (MIN_SIZE): Add correct definition for this case.
- * (more_memory, malloc, free, realloc):
- * Use above macros, and add appropiate checks & frobs in MCHECK case.
- *
- * Revision 1.4 1994/05/05 11:21:42 roland
- * entered into RCS
- *
- * Revision 2.7 91/05/14 17:57:34 mrt
- * Correcting copyright
- *
- * Revision 2.6 91/02/14 14:20:26 mrt
- * Added new Mach copyright
- * [91/02/13 12:41:21 mrt]
- *
- * Revision 2.5 90/11/05 14:37:33 rpd
- * Added malloc_fork* code.
- * [90/11/02 rwd]
- *
- * Add spin_lock_t.
- * [90/10/31 rwd]
- *
- * Revision 2.4 90/08/07 14:31:28 rpd
- * Removed RCS keyword nonsense.
- *
- * Revision 2.3 90/06/02 15:14:00 rpd
- * Converted to new IPC.
- * [90/03/20 20:56:57 rpd]
- *
- * Revision 2.2 89/12/08 19:53:59 rwd
- * Removed conditionals.
- * [89/10/23 rwd]
- *
- * Revision 2.1 89/08/03 17:09:46 rwd
- * Created.
- *
- *
- * 13-Sep-88 Eric Cooper (ecc) at Carnegie Mellon University
- * Changed realloc() to copy min(old size, new size) bytes.
- * Bug found by Mike Kupfer at Olivetti.
- */
-/*
- * File: malloc.c
- * Author: Eric Cooper, Carnegie Mellon University
- * Date: July, 1988
- *
- * Memory allocator for use with multiple threads.
- */
-
-
-#include <assert.h>
-#include <cthreads.h>
-
-#define MCHECK
-
-/*
- * C library imports:
- */
-extern bcopy();
-
-/*
- * Structure of memory block header.
- * When free, next points to next block on free list.
- * When allocated, fl points to free list.
- * Size of header is 4 bytes, so minimum usable block size is 8 bytes.
- */
-
-#define CHECK_BUSY 0x8a3c743e
-#define CHECK_FREE 0x66688b92
-
-#ifdef MCHECK
-
-typedef struct header {
- long check;
- union {
- struct header *next;
- struct free_list *fl;
- } u;
-} *header_t;
-
-#define HEADER_SIZE sizeof (struct header)
-#define HEADER_NEXT(h) ((h)->u.next)
-#define HEADER_FREE(h) ((h)->u.fl)
-#define HEADER_CHECK(h) ((h)->check)
-#define MIN_SIZE 16
-#define LOG2_MIN_SIZE 4
-
-#else /* ! MCHECK */
-
-typedef union header {
- union header *next;
- struct free_list *fl;
-} *header_t;
-
-#define HEADER_SIZE sizeof (union header)
-#define HEADER_NEXT(h) ((h)->next)
-#define HEADER_FREE(h) ((h)->fl)
-#define MIN_SIZE 8 /* minimum block size */
-#define LOG2_MIN_SIZE 3
-
-#endif /* MCHECK */
-
-typedef struct free_list {
- spin_lock_t lock; /* spin lock for mutual exclusion */
- header_t head; /* head of free list for this size */
-#ifdef DEBUG
- int in_use; /* # mallocs - # frees */
-#endif DEBUG
-} *free_list_t;
-
-/*
- * Free list with index i contains blocks of size 2 ^ (i + LOG2_MIN_SIZE)
- * including header. Smallest block size is MIN_SIZE, with MIN_SIZE -
- * HEADER_SIZE bytes available to user. Size argument to malloc is a signed
- * integer for sanity checking, so largest block size is 2^31.
- */
-#define NBUCKETS 29
-
-static struct free_list malloc_free_list[NBUCKETS];
-
-static void
-more_memory(size, fl)
- int size;
- register free_list_t fl;
-{
- register int amount;
- register int n;
- vm_address_t where;
- register header_t h;
- kern_return_t r;
-
- if (size <= vm_page_size) {
- amount = vm_page_size;
- n = vm_page_size / size;
- /* We lose vm_page_size - n*size bytes here. */
- } else {
- amount = size;
- n = 1;
- }
-
- r = vm_allocate(mach_task_self(), &where, (vm_size_t) amount, TRUE);
- assert_perror (r);
-
- h = (header_t) where;
- do {
- HEADER_NEXT (h) = fl->head;
-#ifdef MCHECK
- HEADER_CHECK (h) = CHECK_FREE;
-#endif
- fl->head = h;
- h = (header_t) ((char *) h + size);
- } while (--n != 0);
-}
-
-/* Declaration changed to standard one for GNU. */
-void *
-malloc(size)
- register size_t size;
-{
- register int i, n;
- register free_list_t fl;
- register header_t h;
-
- if ((int) size < 0) /* sanity check */
- return 0;
- size += HEADER_SIZE;
- /*
- * Find smallest power-of-two block size
- * big enough to hold requested size plus header.
- */
- i = 0;
- n = MIN_SIZE;
- while (n < size) {
- i += 1;
- n <<= 1;
- }
- ASSERT(i < NBUCKETS);
- fl = &malloc_free_list[i];
- spin_lock(&fl->lock);
- h = fl->head;
- if (h == 0) {
- /*
- * Free list is empty;
- * allocate more blocks.
- */
- more_memory(n, fl);
- h = fl->head;
- if (h == 0) {
- /*
- * Allocation failed.
- */
- spin_unlock(&fl->lock);
- return 0;
- }
- }
- /*
- * Pop block from free list.
- */
- fl->head = HEADER_NEXT (h);
-
-#ifdef MCHECK
- assert (HEADER_CHECK (h) == CHECK_FREE);
- HEADER_CHECK (h) = CHECK_BUSY;
-#endif
-
-#ifdef DEBUG
- fl->in_use += 1;
-#endif DEBUG
- spin_unlock(&fl->lock);
- /*
- * Store free list pointer in block header
- * so we can figure out where it goes
- * at free() time.
- */
- HEADER_FREE (h) = fl;
- /*
- * Return pointer past the block header.
- */
- return ((char *) h) + HEADER_SIZE;
-}
-
-/* Declaration changed to standard one for GNU. */
-void
-free(base)
- void *base;
-{
- register header_t h;
- register free_list_t fl;
- register int i;
-
- if (base == 0)
- return;
- /*
- * Find free list for block.
- */
- h = (header_t) (base - HEADER_SIZE);
-
-#ifdef MCHECK
- assert (HEADER_CHECK (h) == CHECK_BUSY);
-#endif
-
- fl = HEADER_FREE (h);
- i = fl - malloc_free_list;
- /*
- * Sanity checks.
- */
- if (i < 0 || i >= NBUCKETS) {
- ASSERT(0 <= i && i < NBUCKETS);
- return;
- }
- if (fl != &malloc_free_list[i]) {
- ASSERT(fl == &malloc_free_list[i]);
- return;
- }
- /*
- * Push block on free list.
- */
- spin_lock(&fl->lock);
- HEADER_NEXT (h) = fl->head;
-#ifdef MCHECK
- HEADER_CHECK (h) = CHECK_FREE;
-#endif
- fl->head = h;
-#ifdef DEBUG
- fl->in_use -= 1;
-#endif DEBUG
- spin_unlock(&fl->lock);
- return;
-}
-
-/* Declaration changed to standard one for GNU. */
-void *
-realloc(old_base, new_size)
- void *old_base;
- size_t new_size;
-{
- register header_t h;
- register free_list_t fl;
- register int i;
- unsigned int old_size;
- char *new_base;
-
- if (old_base == 0)
- return malloc (new_size);
-
- /*
- * Find size of old block.
- */
- h = (header_t) (old_base - HEADER_SIZE);
-#ifdef MCHECK
- assert (HEADER_CHECK (h) == CHECK_BUSY);
-#endif
- fl = HEADER_FREE (h);
- i = fl - malloc_free_list;
- /*
- * Sanity checks.
- */
- if (i < 0 || i >= NBUCKETS) {
- ASSERT(0 <= i && i < NBUCKETS);
- return 0;
- }
- if (fl != &malloc_free_list[i]) {
- ASSERT(fl == &malloc_free_list[i]);
- return 0;
- }
- /*
- * Free list with index i contains blocks of size
- * 2 ^ (i + * LOG2_MIN_SIZE) including header.
- */
- old_size = (1 << (i + LOG2_MIN_SIZE)) - HEADER_SIZE;
-
- if (new_size <= old_size
- && new_size > (((old_size + HEADER_SIZE) >> 1) - HEADER_SIZE))
- /* The new size still fits in the same block, and wouldn't fit in
- the next smaller block! */
- return old_base;
-
- /*
- * Allocate new block, copy old bytes, and free old block.
- */
- new_base = malloc(new_size);
- if (new_base)
- bcopy(old_base, new_base,
- (int) (old_size < new_size ? old_size : new_size));
-
- if (new_base || new_size == 0)
- /* Free OLD_BASE, but only if the malloc didn't fail. */
- free (old_base);
-
- return new_base;
-}
-
-#ifdef DEBUG
-void
-print_malloc_free_list()
-{
- register int i, size;
- register free_list_t fl;
- register int n;
- register header_t h;
- int total_used = 0;
- int total_free = 0;
-
- fprintf(stderr, " Size In Use Free Total\n");
- for (i = 0, size = MIN_SIZE, fl = malloc_free_list;
- i < NBUCKETS;
- i += 1, size <<= 1, fl += 1) {
- spin_lock(&fl->lock);
- if (fl->in_use != 0 || fl->head != 0) {
- total_used += fl->in_use * size;
- for (n = 0, h = fl->head; h != 0; h = HEADER_NEXT (h), n += 1)
- ;
- total_free += n * size;
- fprintf(stderr, "%10d %10d %10d %10d\n",
- size, fl->in_use, n, fl->in_use + n);
- }
- spin_unlock(&fl->lock);
- }
- fprintf(stderr, " all sizes %10d %10d %10d\n",
- total_used, total_free, total_used + total_free);
-}
-#endif DEBUG
-
-void malloc_fork_prepare()
-/*
- * Prepare the malloc module for a fork by insuring that no thread is in a
- * malloc critical section.
- */
-{
- register int i;
-
- for (i = 0; i < NBUCKETS; i++) {
- spin_lock(&malloc_free_list[i].lock);
- }
-}
-
-void malloc_fork_parent()
-/*
- * Called in the parent process after a fork() to resume normal operation.
- */
-{
- register int i;
-
- for (i = NBUCKETS-1; i >= 0; i--) {
- spin_unlock(&malloc_free_list[i].lock);
- }
-}
-
-void malloc_fork_child()
-/*
- * Called in the child process after a fork() to resume normal operation.
- */
-{
- register int i;
-
- for (i = NBUCKETS-1; i >= 0; i--) {
- spin_unlock(&malloc_free_list[i].lock);
- }
-}
diff --git a/libthreads/mig_support.c b/libthreads/mig_support.c
index bb9e6a5e..cd0d4124 100644
--- a/libthreads/mig_support.c
+++ b/libthreads/mig_support.c
@@ -1,54 +1,68 @@
-/*
+/*
* Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1993-1989 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* HISTORY
+ * 26-Feb-94 Johannes Helander (jvh) at Helsinki University of Technology
+ * Added mach_put_reply_port. mig_dealloc_reply_port now takes the
+ * port as an argument.
+ *
* $Log: mig_support.c,v $
+ * Revision 2.8 93/01/24 13:27:14 danner
+ * Corrrected include of mach/mach.h to mach.h
+ * [93/01/16 mrt]
+ *
+ * Revision 2.7 93/01/14 18:05:37 danner
+ * Converted file to ANSI C.
+ * Made argument to mig_init a void * for compatibility with
+ * mig_init in libmach.
+ * [92/12/18 pds]
+ *
* Revision 2.6 91/05/14 17:57:41 mrt
* Correcting copyright
- *
+ *
* Revision 2.5 91/02/14 14:20:30 mrt
* Added new Mach copyright
* [91/02/13 12:41:26 mrt]
- *
+ *
* Revision 2.4 90/08/07 14:31:41 rpd
* Removed RCS keyword nonsense.
- *
+ *
* Revision 2.3 90/08/07 14:27:48 rpd
* When we recycle the global reply port by giving it to the first
* cthread, clear the global reply port. This will take care of
- * someone accidently calling this twice.
+ * someone accidentally calling this twice.
* [90/08/07 rwd]
- *
+ *
* Revision 2.2 90/06/02 15:14:04 rpd
* Converted to new IPC.
* [90/03/20 20:56:50 rpd]
- *
+ *
* Revision 2.1 89/08/03 17:09:50 rwd
* Created.
- *
+ *
* 18-Jan-89 David Golub (dbg) at Carnegie-Mellon University
* Replaced task_data() by thread_reply().
*
@@ -75,7 +89,9 @@
*/
-#include <mach/mach.h>
+#include <mach.h>
+#include <mach/mig_support.h>
+#include <mach/mach_traps.h>
#include <cthreads.h>
#include "cthread_internals.h"
@@ -88,8 +104,7 @@ private mach_port_t mig_reply_port = MACH_PORT_NULL;
* called and again with initial cproc at end of cthread_init.
*/
void
-mig_init(initial)
- register cproc_t initial;
+mig_init(register void *initial)
{
if (initial == NO_CPROC) {
/* called from mach_init before cthread_init,
@@ -101,23 +116,16 @@ mig_init(initial)
/* recycle global reply port as this cthread's reply port */
multithreaded = TRUE;
- initial->reply_port = mig_reply_port;
+ ((cproc_t) initial)->reply_port = mig_reply_port;
mig_reply_port = MACH_PORT_NULL;
}
}
-void
-__mig_init (initial)
- register cproc_t initial;
-{
- mig_init (initial);
-}
-
/*
* Called by mig interface code whenever a reply port is needed.
*/
mach_port_t
-mig_get_reply_port()
+mig_get_reply_port(void)
{
register mach_port_t reply_port;
@@ -137,18 +145,13 @@ mig_get_reply_port()
return reply_port;
}
-mach_port_t
-__mig_get_reply_port()
-{
- return mig_get_reply_port();
-}
-
/*
* Called by mig interface code after a timeout on the reply port.
* May also be called by user.
*/
+/*ARGSUSED*/
void
-mig_dealloc_reply_port()
+mig_dealloc_reply_port(mach_port_t p)
{
register mach_port_t reply_port;
@@ -169,8 +172,45 @@ mig_dealloc_reply_port()
MACH_PORT_RIGHT_RECEIVE, -1);
}
+/*
+ * Called by mig interfaces when done with a port.
+ * Used to provide the same interface as needed when a custom
+ * allocator is used.
+ */
+
+/*ARGSUSED*/
+void
+mig_put_reply_port(mach_port_t port)
+{
+ /* Do nothing */
+}
+
+void
+__mig_init(register void *initial)
+{
+ mig_init (initial);
+}
+
+mach_port_t
+__mig_get_reply_port(void)
+{
+ return mig_get_reply_port();
+}
+
+void
+__mig_dealloc_reply_port(mach_port_t p)
+{
+ mig_dealloc_reply_port(p);
+}
+
+void
+__mig_put_reply_port(mach_port_t port)
+{
+ mig_put_reply_port(port);
+}
+
void
-__mig_dealloc_reply_port ()
+__mig_dealloc_reply_port (void)
{
mig_dealloc_reply_port ();
}
diff --git a/libthreads/options.h b/libthreads/options.h
index 952720de..b8074693 100644
--- a/libthreads/options.h
+++ b/libthreads/options.h
@@ -1,57 +1,71 @@
-/*
+/*
* Mach Operating System
* Copyright (c) 1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
- *
+ *
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
- *
+ *
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
+ *
* Carnegie Mellon requests users of this software to return to
- *
+ *
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
- *
+ *
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* HISTORY
- * $Log: options.h,v $
+ * $Log: options.h,v $
+ * Revision 1.2 2002/05/27 02:50:10 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * Changes merged from CMU MK83a version:
+ * * cthreads.h, options.h: Various cleanups.
+ * * call.c, cthread_data.c, sync.c, mig_support.c: Likewise.
+ * * i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
+ * * cthread_internals.h: Add decls for internal functions.
+ * (struct cproc): Use vm_offset_t for stack_base and stack_size members.
+ * Use natural_t for context member.
+ * * cprocs.c: Use prototypes for all defns.
+ * * cthreads.c: Likewise.
+ * (cthread_exit): Cast any_t to integer_t before int.
+ *
* Revision 2.8 91/05/14 17:58:35 mrt
* Correcting copyright
- *
+ *
* Revision 2.7 91/02/14 14:21:03 mrt
* Added new Mach copyright
* [91/02/13 12:41:31 mrt]
- *
+ *
* Revision 2.6 90/09/09 14:35:04 rpd
* Remove special option , debug_mutex and thread_calls.
* [90/08/24 rwd]
- *
+ *
* Revision 2.5 90/06/02 15:14:14 rpd
* Removed RCS Source, Header lines.
* [90/05/03 00:07:27 rpd]
- *
+ *
* Revision 2.4 90/03/14 21:12:15 rwd
* Added new option:
* WAIT_DEBUG: keep track of who a blocked thread is
* waiting for.
* [90/03/01 rwd]
- *
+ *
* Revision 2.3 90/01/19 14:37:25 rwd
* New option:
* THREAD_CALLS: cthread_* version of thread_* calls.
* [90/01/03 rwd]
- *
+ *
* Revision 2.2 89/12/08 19:54:09 rwd
* Added code:
* MUTEX_SPECIAL: Have extra kernel threads available for
@@ -77,7 +91,7 @@
* [89/11/13 rwd]
* Added copyright. Removed all options.
* [89/10/23 rwd]
- *
+ *
*/
/*
* options.h
@@ -87,4 +101,4 @@
#define SPIN_RESCHED
/*#define CHECK_STATUS*/
/*#define RED_ZONE*/
-#define WAIT_DEBUG
+/*#define WAIT_DEBUG*/
diff --git a/libthreads/rwlock.c b/libthreads/rwlock.c
index 6fcb08c4..ae6a7c48 100644
--- a/libthreads/rwlock.c
+++ b/libthreads/rwlock.c
@@ -1,6 +1,2 @@
-/* This file defines the real functions for the inlines in rwlock.h. */
-
-#include <cthreads.h>
-
-#define _RWLOCK_DEFINE_FUNCTIONS /* Define the real functions. */
-#include <rwlock.h>
+#define RWLOCK_DEFINE_EI
+#include "rwlock.h"
diff --git a/libthreads/rwlock.h b/libthreads/rwlock.h
index 7abbfff1..44d9a35d 100644
--- a/libthreads/rwlock.h
+++ b/libthreads/rwlock.h
@@ -21,6 +21,13 @@
#include <cthreads.h>
#include <assert.h>
+#include <features.h>
+
+#ifdef RWLOCK_DEFINE_EI
+#define RWLOCK_EI
+#else
+#define RWLOCK_EI __extern_inline
+#endif
struct rwlock
{
@@ -31,17 +38,20 @@ struct rwlock
int readers_waiting;
};
-#ifdef _RWLOCK_DEFINE_FUNCTIONS
-#undef _EXTERN_INLINE
-#define _EXTERN_INLINE
-#else /* ! _RWLOCK_DEFINE_FUNCTIONS */
-#ifndef _EXTERN_INLINE
-#define _EXTERN_INLINE extern __inline
-#endif
-#endif /* _RWLOCK_DEFINE_FUNCTIONS */
+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);
+
+#if defined(__USE_EXTERN_INLINES) || defined(RWLOCK_DEFINE_EI)
/* Get a reader lock on reader-writer lock LOCK for disknode DN */
-_EXTERN_INLINE void
+RWLOCK_EI void
rwlock_reader_lock (struct rwlock *lock)
{
mutex_lock (&lock->master);
@@ -58,7 +68,7 @@ rwlock_reader_lock (struct rwlock *lock)
}
/* Get a writer lock on reader-writer lock LOCK for disknode DN */
-_EXTERN_INLINE void
+RWLOCK_EI void
rwlock_writer_lock (struct rwlock *lock)
{
mutex_lock (&lock->master);
@@ -75,7 +85,7 @@ rwlock_writer_lock (struct rwlock *lock)
}
/* Release a reader lock on reader-writer lock LOCK for disknode DN */
-_EXTERN_INLINE void
+RWLOCK_EI void
rwlock_reader_unlock (struct rwlock *lock)
{
mutex_lock (&lock->master);
@@ -87,7 +97,7 @@ rwlock_reader_unlock (struct rwlock *lock)
}
/* Release a writer lock on reader-writer lock LOCK for disknode DN */
-_EXTERN_INLINE void
+RWLOCK_EI void
rwlock_writer_unlock (struct rwlock *lock)
{
mutex_lock (&lock->master);
@@ -99,7 +109,7 @@ rwlock_writer_unlock (struct rwlock *lock)
}
/* Initialize reader-writer lock LOCK */
-_EXTERN_INLINE void
+RWLOCK_EI void
rwlock_init (struct rwlock *lock)
{
mutex_init (&lock->master);
@@ -109,6 +119,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/libthreads/stack.c b/libthreads/stack.c
index bc4ef8cd..d6dd9fff 100644
--- a/libthreads/stack.c
+++ b/libthreads/stack.c
@@ -1,6 +1,6 @@
/*
* Mach Operating System
- * Copyright (c) 1991,1990 Carnegie Mellon University
+ * Copyright (c) 1992,1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
@@ -26,8 +26,25 @@
/*
* HISTORY
* $Log: stack.c,v $
- * Revision 1.4 1994/05/05 16:00:09 roland
- * entered into RCS
+ * Revision 1.8 2002/05/27 02:50:41 roland
+ * 2002-05-26 Roland McGrath <roland@frob.com>
+ *
+ * Changes merged from CMU MK83a version:
+ * * cthreads.h, options.h: Various cleanups.
+ * * call.c, cthread_data.c, sync.c, mig_support.c, stack.c: Likewise.
+ * * i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
+ * * cthread_internals.h: Add decls for internal functions.
+ * (struct cproc): Use vm_offset_t for stack_base and stack_size members.
+ * Use natural_t for context member.
+ * * cprocs.c: Use prototypes for all defns.
+ * * cthreads.c: Likewise.
+ * (cthread_exit): Cast any_t to integer_t before int.
+ *
+ * Revision 2.14 93/01/14 18:05:58 danner
+ * Converted file to ANSI C.
+ * [92/12/18 pds]
+ * 64bit cleanup.
+ * [92/12/02 af]
*
* Revision 2.13 92/01/14 16:48:54 rpd
* Fixed addr_range_check to deallocate the object port from vm_region.
@@ -126,12 +143,10 @@
#define BYTES_TO_PAGES(b) (((b) + vm_page_size - 1) / vm_page_size)
-int cthread_stack_mask;
+vm_offset_t cthread_stack_mask;
vm_size_t cthread_stack_size;
private vm_address_t next_stack_base;
-vm_offset_t cproc_stack_base(); /* forward */
-
/*
* Set up a stack segment for a thread.
* Segment has a red zone (invalid page)
@@ -161,7 +176,9 @@ setup_stack(p, base)
register cproc_t p;
register vm_address_t base;
{
+#if defined(RED_ZONE)
register kern_return_t r;
+#endif /* defined(RED_ZONE) */
p->stack_base = base;
/*
@@ -171,20 +188,19 @@ setup_stack(p, base)
/*
* Protect red zone.
*/
-#ifdef RED_ZONE
+#if defined(RED_ZONE)
MACH_CALL(vm_protect(mach_task_self(), base + vm_page_size, vm_page_size, FALSE, VM_PROT_NONE), r);
-#endif RED_ZONE
+#endif /* defined(RED_ZONE) */
/*
* Store self pointer.
*/
*(cproc_t *)&ur_cthread_ptr(base) = p;
}
-#if 0 /* roland@gnu */
-vm_offset_t
-addr_range_check(start_addr, end_addr, desired_protection)
- vm_offset_t start_addr, end_addr;
- vm_prot_t desired_protection;
+#if 0 /* GNU */
+private vm_offset_t
+addr_range_check(vm_offset_t start_addr, vm_offset_t end_addr,
+ vm_prot_t desired_protection)
{
register vm_offset_t addr;
@@ -222,10 +238,8 @@ addr_range_check(start_addr, end_addr, desired_protection)
* 1. stack grows DOWN
* 2. There is an unallocated region below the stack.
*/
-void
-probe_stack(stack_bottom, stack_top)
- vm_offset_t *stack_bottom;
- vm_offset_t *stack_top;
+private void
+probe_stack(vm_offset_t *stack_bottom, vm_offset_t *stack_top)
{
/*
* Since vm_region returns the region starting at
@@ -270,9 +284,8 @@ probe_stack(stack_bottom, stack_top)
/*
* Check that the entire range exists and is writable
*/
- } while (end_addr = (addr_range_check(start_addr,
- end_addr,
- VM_PROT_READ|VM_PROT_WRITE)));
+ } while ((end_addr = addr_range_check(start_addr, end_addr,
+ VM_PROT_READ|VM_PROT_WRITE)));
/*
* Back off to previous power of 2.
*/
@@ -282,13 +295,12 @@ probe_stack(stack_bottom, stack_top)
#endif
/* For GNU: */
-unsigned long int __hurd_threadvar_stack_mask;
-unsigned long int __hurd_threadvar_stack_offset;
-unsigned int __hurd_threadvar_max;
+extern unsigned long int __hurd_threadvar_stack_mask;
+extern unsigned long int __hurd_threadvar_stack_offset;
+extern unsigned int __hurd_threadvar_max;
vm_offset_t
-stack_init(p)
- cproc_t p;
+stack_init(cproc_t p)
{
#if 0
vm_offset_t stack_bottom,
@@ -296,11 +308,7 @@ stack_init(p)
start;
vm_size_t size;
kern_return_t r;
-#endif
-
- void alloc_stack();
-#if 0
/*
* Probe for bottom and top of stack, as a power-of-2 size.
*/
@@ -312,27 +320,27 @@ stack_init(p)
*/
if (cthread_stack_size == 0)
cthread_stack_size = stack_top - stack_bottom;
-#else /* roland@gnu */
+#else /* GNU */
if (cthread_stack_size == 0)
cthread_stack_size = vm_page_size * 16; /* Reasonable default. */
-#endif
+#endif /* GNU */
-#ifdef STACK_GROWTH_UP
+#if defined(STACK_GROWTH_UP)
cthread_stack_mask = ~(cthread_stack_size - 1);
-#else STACK_GROWTH_UP
+#else /* not defined(STACK_GROWTH_UP) */
cthread_stack_mask = cthread_stack_size - 1;
-#endif STACK_GROWTH_UP
-
- /* Set up the variables so GNU can find its per-thread variables. */
- __hurd_threadvar_stack_mask = ~(cthread_stack_size - 1);
- /* The GNU per-thread variables will be stored just after the
- cthread-self pointer at the base of the stack. */
-#ifdef STACK_GROWTH_UP
- __hurd_threadvar_stack_offset = sizeof (ur_cthread_t *);
+#endif /* defined(STACK_GROWTH_UP) */
+
+ /* Set up the variables so GNU can find its per-thread variables. */
+ __hurd_threadvar_stack_mask = ~(cthread_stack_size - 1);
+ /* The GNU per-thread variables will be stored just after the
+ cthread-self pointer at the base of the stack. */
+#ifdef STACK_GROWTH_UP
+ __hurd_threadvar_stack_offset = sizeof (ur_cthread_t *);
#else
- __hurd_threadvar_stack_offset = (cthread_stack_size -
- sizeof (ur_cthread_t *) -
- __hurd_threadvar_max * sizeof (long));
+ __hurd_threadvar_stack_offset = (cthread_stack_size -
+ sizeof (ur_cthread_t *) -
+ __hurd_threadvar_max * sizeof (long));
#endif
/*
@@ -345,28 +353,27 @@ stack_init(p)
*/
alloc_stack(p);
-#if 0
+#if 0 /* GNU */
/*
* Delete rest of old stack.
*/
-#ifdef STACK_GROWTH_UP
+#if defined(STACK_GROWTH_UP)
start = (cthread_sp() | (vm_page_size - 1)) + 1 + vm_page_size;
size = stack_top - start;
-#else STACK_GROWTH_UP
+#else /* not defined(STACK_GROWTH_UP) */
start = stack_bottom;
size = (cthread_sp() & ~(vm_page_size - 1)) - stack_bottom -
vm_page_size;
-#endif STACK_GROWTH_UP
+#endif /* defined(STACK_GROWTH_UP) */
MACH_CALL(vm_deallocate(mach_task_self(),start,size),r);
-#endif
+#endif /* GNU */
/*
* Return new stack; it gets passed back to the caller
* of cthread_init who must switch to it.
*/
- return cproc_stack_base(p,
- sizeof(ur_cthread_t *) +
+ return cproc_stack_base(p, sizeof(ur_cthread_t *) +
/* Account for GNU per-thread variables. */
__hurd_threadvar_max * sizeof (long int));
}
@@ -382,8 +389,7 @@ stack_init(p)
*/
void
-alloc_stack(p)
- cproc_t p;
+alloc_stack(cproc_t p)
{
vm_address_t base = next_stack_base;
@@ -400,11 +406,11 @@ cproc_stack_base(cproc, offset)
register cproc_t cproc;
register int offset;
{
-#ifdef STACK_GROWTH_UP
+#if defined(STACK_GROWTH_UP)
return (cproc->stack_base + offset);
-#else STACK_GROWTH_UP
+#else /* not defined(STACK_GROWTH_UP) */
return (cproc->stack_base + cproc->stack_size - offset);
-#endif STACK_GROWTH_UP
+#endif /* defined(STACK_GROWTH_UP) */
}
diff --git a/libthreads/sync.c b/libthreads/sync.c
index e17280aa..d65eb654 100644
--- a/libthreads/sync.c
+++ b/libthreads/sync.c
@@ -1,6 +1,6 @@
/*
* Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
@@ -26,6 +26,10 @@
/*
* HISTORY
* $Log: sync.c,v $
+ * Revision 2.8 93/01/14 18:06:23 danner
+ * Converted file to ANSI C.
+ * [92/12/18 pds]
+ *
* Revision 2.7 92/03/06 14:09:59 rpd
* Replaced swtch_pri with yield.
* [92/03/06 rpd]
@@ -69,8 +73,7 @@
int cthread_spin_count=0;
void
-spin_lock_solid(p)
- register spin_lock_t *p;
+spin_lock_solid(register spin_lock_t *p)
{
while (spin_lock_locked(p) || !spin_try_lock(p)) {
#ifdef STATISTICS
diff --git a/libtreefs/Makefile b/libtreefs/Makefile
index 89d95e9b..3cdc30c9 100644
--- a/libtreefs/Makefile
+++ b/libtreefs/Makefile
@@ -25,12 +25,12 @@ installhdrs = treefs.h
S_SRCS = s-file.c s-dir.c s-io.c s-fsys.c
OTHERSRCS = defhooks.c dir-hooks.c dir-lookup.c fsys-getroot.c fsys-hooks.c \
fsys-startup.c hooks.c mdir.c nlist.c node-hooks.c rights.c \
- trans-help.c trans-start.c
+ trans-help.c trans-start.c xinl.c
SRCS = $(OTHERSRCS) $(S_SRCS)
LCLHDRS = treefs.h fs-mutate.h
MIGSTUBS = fsServer.o ioServer.o fsysServer.o
-OBJS = $(sort $(subst .c,.o,$(SRCS)) $(MIGSTUBS)
+OBJS = $(sort $(SRCS:.c=.o)) $(MIGSTUBS)
MIGSFLAGS = -imacros fs-mutate.h
MIGCOMSFLAGS = -prefix treefs_
diff --git a/libtreefs/dir-lookup.c b/libtreefs/dir-lookup.c
index 51c2cbd2..336ce8fd 100644
--- a/libtreefs/dir-lookup.c
+++ b/libtreefs/dir-lookup.c
@@ -1,6 +1,6 @@
/* Default treefs_s_dir_lookup hook
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1998 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -55,8 +55,6 @@ _treefs_s_dir_lookup (struct treefs_handle *h,
if (path[0] == '\0')
{
- mustbedir = 1;
-
/* Set things up in the state expected by the code from gotit: on. */
dir = 0;
node = h->po->node;
diff --git a/libtreefs/mig-decls.h b/libtreefs/mig-decls.h
index 0d051e9c..e17f6196 100644
--- a/libtreefs/mig-decls.h
+++ b/libtreefs/mig-decls.h
@@ -25,7 +25,11 @@
/* For mig */
typedef struct treefs_handle *treefs_handle_t;
-extern inline
+extern treefs_handle_t treefs_begin_using_handle_port(mach_port_t port);
+extern void treefs_end_using_handle_port (treefs_handle_t handle);
+
+#if defined(__USE_EXTERN_INLINES) || defined(TREEFS_DEFINE_EI)
+TREEFS_EI
treefs_handle_t treefs_begin_using_handle_port(mach_port_t port)
{
return
@@ -33,9 +37,10 @@ treefs_handle_t treefs_begin_using_handle_port(mach_port_t port)
ports_lookup_port (0, port, treefs_fsys_port_class);
}
-extern inline void
+TREEFS_EI void
treefs_end_using_handle_port (treefs_handle_t handle)
{
if (handle != NULL)
ports_port_deref (&handle->pi);
}
+#endif /* Use extern inlines. */
diff --git a/libtreefs/s-file.c b/libtreefs/s-file.c
index cd9144da..73c32d7f 100644
--- a/libtreefs/s-file.c
+++ b/libtreefs/s-file.c
@@ -1,6 +1,6 @@
/* File_t rpc stubs; see <hurd/fs.defs> for more info
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -62,7 +62,7 @@ treefs_S_file_chmod (struct treefs_protid *cred, mode_t mode)
{
if (!cred)
return EOPNOTSUPP;
- mode &= ~(S_IFMT | S_ISPARE);
+ mode &= ~(S_IFMT | S_ISPARE | S_ITRANS);
return treefs_s_file_chmod (cred, mode);
}
diff --git a/libtreefs/trans-start.c b/libtreefs/trans-start.c
index 1b0156bf..2196a8dc 100644
--- a/libtreefs/trans-start.c
+++ b/libtreefs/trans-start.c
@@ -1,6 +1,6 @@
/* Starting a passive translator
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1999 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
@@ -55,8 +55,9 @@ _treefs_node_start_translator (struct treefs_node *node,
uid = auth->nuids > 0 ? auth->uids[0] : -1;
gid = auth->ngids > 0 ? auth->gids[0] : -1;
+ /* XXX this should use fshelp_start_translator_long. */
err =
- fshelp_start_translator (&node->active_trans, trans, trans_len,
+ fshelp_start_translator (&node->active_trans, NULL, trans, trans_len,
parent_port, node_port, uid, gid);
treefs_node_auth_unref (node, auth);
diff --git a/libtreefs/treefs.h b/libtreefs/treefs.h
index b0c26849..d8f30e4e 100644
--- a/libtreefs/treefs.h
+++ b/libtreefs/treefs.h
@@ -1,8 +1,8 @@
/* Hierarchial filesystem support
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2002 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -26,6 +26,7 @@
#include <errno.h>
#include <cthreads.h>
#include <assert.h>
+#include <features.h>
#include <sys/stat.h>
@@ -36,6 +37,12 @@
/* Include the hook calling macros and non-rpc hook definitions (to get
those, include "trees-s-hooks.h"). */
#include "treefs-hooks.h"
+
+#ifdef TREEFS_DEFINE_EI
+#define TREEFS_EI
+#else
+#define TREEFS_EI __extern_inline
+#endif
/* ---------------------------------------------------------------- */
@@ -84,9 +91,9 @@ struct treefs_peropen
};
/* A filesystem node in the tree. */
-struct treefs_node
+struct treefs_node
{
- struct stat stat;
+ io_statbuf_t stat;
struct treefs_fsys *fsys;
struct trans_link active_trans;
@@ -124,7 +131,7 @@ struct treefs_fsys
/* The port for the node which this filesystem is translating. */
mach_port_t underlying_port;
/* And stat info for it. */
- struct stat underlying_stat;
+ io_statbuf_t underlying_stat;
/* Flags from the TREEFS_FSYS_ set. */
int flags;
@@ -237,10 +244,18 @@ void treefs_hooks_set (treefs_hook_vector_t hooks,
extern spin_lock_t treefs_node_refcnt_lock;
-/* Add a hard reference to a node. If there were no hard
- references previously, then the node cannot be locked
+extern void treefs_node_ref (struct treefs_node *node);
+extern void treefs_node_release (struct treefs_node *node);
+extern void treefs_node_unref (struct treefs_node *node);
+extern void treefs_node_ref_weak (struct treefs_node *node);
+extern void treefs_node_release_weak (struct treefs_node *node);
+extern void treefs_node_unref_weak (struct treefs_node *node);
+
+#if defined(__USE_EXTERN_INLINES) || defined(TREEFS_DEFINE_EI)
+/* Add a hard reference to a node. If there were no hard
+ references previously, then the node cannot be locked
(because you must hold a hard reference to hold the lock). */
-extern inline void
+TREEFS_EI void
treefs_node_ref (struct treefs_node *node)
{
int new_ref;
@@ -259,11 +274,11 @@ treefs_node_ref (struct treefs_node *node)
/* Unlock node NODE and release a hard reference; if this is the last
hard reference and there are no links to the file then request
weak references to be dropped. */
-extern inline void
+TREEFS_EI void
treefs_node_release (struct treefs_node *node)
{
int tried_drop_weak_refs = 0;
-
+
loop:
spin_lock (&treefs_node_refcnt_lock);
assert (node->refs);
@@ -306,11 +321,11 @@ treefs_node_release (struct treefs_node *node)
hard reference in order to hold the lock). If this is the last
hard reference and there are no links, then request weak references
to be dropped. */
-extern inline void
+TREEFS_EI void
treefs_node_unref (struct treefs_node *node)
{
int tried_drop_weak_refs = 0;
-
+
loop:
spin_lock (&treefs_node_refcnt_lock);
assert (node->refs);
@@ -331,7 +346,7 @@ treefs_node_unref (struct treefs_node *node)
spin_unlock (&treefs_node_refcnt_lock);
node->refs++;
spin_unlock (&treefs_node_refcnt_lock);
-
+
treefs_node_try_dropping_weak_refs (node);
tried_drop_weak_refs = 1;
@@ -346,7 +361,7 @@ treefs_node_unref (struct treefs_node *node)
}
/* Add a weak reference to a node. */
-extern inline void
+TREEFS_EI void
treefs_node_ref_weak (struct treefs_node *node)
{
spin_lock (&treefs_node_refcnt_lock);
@@ -355,7 +370,7 @@ treefs_node_ref_weak (struct treefs_node *node)
}
/* Unlock node NODE and release a weak reference */
-extern inline void
+TREEFS_EI void
treefs_node_release_weak (struct treefs_node *node)
{
spin_lock (&treefs_node_refcnt_lock);
@@ -372,8 +387,8 @@ treefs_node_release_weak (struct treefs_node *node)
/* Release a weak reference on NODE. If NODE is locked by anyone, then
this cannot be the last reference (because you must hold a
- hard reference in order to hold the lock). */
-extern inline void
+ hard reference in order to hold the lock). */
+TREEFS_EI void
treefs_node_unref_weak (struct treefs_node *node)
{
spin_lock (&treefs_node_refcnt_lock);
@@ -387,6 +402,7 @@ treefs_node_unref_weak (struct treefs_node *node)
else
spin_unlock (&treefs_node_refcnt_lock);
}
+#endif /* Use extern inlines. */
/* ---------------------------------------------------------------- */
@@ -408,8 +424,12 @@ treefs_node_create_right (struct treefs_node *node, int flags,
/* ---------------------------------------------------------------- */
/* Auth functions; copied from diskfs. */
+extern int treefs_auth_has_uid (struct treefs_auth *auth, uid_t uid);
+extern int treefs_auth_in_group (struct treefs_auth *auth, gid_t gid);
+
+#if defined(__USE_EXTERN_INLINES) || defined(TREEFS_DEFINE_EI)
/* Return nonzero iff the user identified by AUTH has uid UID. */
-extern inline int
+TREEFS_EI int
treefs_auth_has_uid (struct treefs_auth *auth, uid_t uid)
{
int i;
@@ -420,7 +440,7 @@ treefs_auth_has_uid (struct treefs_auth *auth, uid_t uid)
}
/* Return nonzero iff the user identified by AUTH has group GID. */
-extern inline int
+TREEFS_EI int
treefs_auth_in_group (struct treefs_auth *auth, gid_t gid)
{
int i;
@@ -429,6 +449,7 @@ treefs_auth_in_group (struct treefs_auth *auth, gid_t gid)
return 1;
return 0;
}
+#endif /* Use extern inlines. */
/* ---------------------------------------------------------------- */
/* Helper routines for dealing with translators. */
diff --git a/libtreefs/xinl.c b/libtreefs/xinl.c
new file mode 100644
index 00000000..fe83e5a3
--- /dev/null
+++ b/libtreefs/xinl.c
@@ -0,0 +1,3 @@
+#define TREEFS_DEFINE_EI
+#include "treefs.h"
+#include "mig-decls.h"
diff --git a/libtrivfs/ChangeLog b/libtrivfs/ChangeLog
deleted file mode 100644
index 51e946e4..00000000
--- a/libtrivfs/ChangeLog
+++ /dev/null
@@ -1,665 +0,0 @@
-Thu Jul 18 23:14:44 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Use noinstall
- version of ports_create_port. Put it in the port set after the
- node has been fully initialized.
-
-Sat Jul 13 20:15:56 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Repeat
- ports_create_port, auth_server_authenticate, io_restrict_auth, and
- *trivfs_protid_create_hook for as long as we get EINTR. Deal with
- other errors without crashing.
-
-Sun Jul 7 16:06:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Don't use
- MACH_MSG_TYPE_MOVE_SEND; it's unreliable.
-
-Thu Jun 20 22:54:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-get-fs-options.c (trivfs_S_file_get_fs_options):
- Call trivfs_get_options, and package up the results.
- * fsys-get-options.c (trivfs_S_fsys_get_options): Likewise.
- * fsys-set-options.c (trivfs_S_fsys_set_options): Call
- trivfs_set_options.
- * set-options.c, get-options.c: New files.
- * trivfs.h: Add trivfs_set_options & trivfs_get_options.
- * Makefile (OTHERSRCS): Add set-options.c & get-options.c.
-
-Wed Jun 19 21:29:45 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * trivfs.h (trivfs_runtime_argp): New declaration.
- * fsys-set-options.c (trivfs_S_fsys_set_options): Use
- trivfs_runtime_argp to parse options.
- * runtime-argp.c: New file.
- * Makefile (OTHERSRCS): Add runtime-argp.c.
-
-Sat Jun 15 19:50:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsys-stubs.c (trivfs_S_fsys_set_options, trivfs_S_fsys_get_options,
- trivfs_S_file_get_fs_options): Functions removed.
- * fsys-set-options.c, fsys-get-options.c, file-get-fs-options.c:
- New files.
- * Makefile (FSSRCS): Add file-get-fs-options.c
- (FSYSSRCS): Add fsys-set-options.c & fsys-get-options.c.
-
-Thu May 9 20:03:28 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-identity.c: New file.
- * Makefile (IOSRCS): Add io-identity.c.
- * cntl-clean.c (trivfs_clean_cntl): Destroy filesys_id and file_id
- members.
- * cntl-create.c (trivfs_create_control): Initialize filesys_id and
- file_id members of new control.
- * trivfs.h (trivfs_control): New members `filesys_id' and
- `file_id'.
-
-Thu May 9 16:58:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-get-storage-info.c (trivfs_S_file_get_storage_info): Change
- to new interface.
-
-Thu May 9 15:32:38 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Don't send
- right for CRED to auth_server_authenticate.
-
- * fsys-stubs.c (trivfs_S_fsys_get_options): Expect (and ignore)
- reply port args.
-
- * file-syncfs.c (trivfs_S_file_syncfs): Provide new third arg to
- file_sync.
- * fsys-syncfs.c (trivfs_S_fsys_syncfs): Likewise.
- * file-sync.c (trivfs_S_file_sync): Accept and pass through new
- omitmeta parm.
-
- * file-statfs.c (trivfs_S_file_statfs): Use new struct statfs
- format.
-
- * dir-rename.c (trivfs_S_dir_rename): Accept new excl parm.
- * dir-link.c (trivfs_S_dir_link): Likewise.
-
- * Makefile (OTHERSRCS): Delete handle-port.c.
- * trivfs.h (trivfs_handle_port): Delete declaration.
- * handle-port.c: Delete file.
-
-Thu May 9 12:16:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io-select.c (trivfs_S_io_select): Remove TAG arg.
-
-Tue May 7 16:14:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-get-storage-info.c (trivfs_S_file_get_storage_info): Swap
- PORTS_TYPE and NUM_PORTS args.
-
-Mon May 6 20:16:20 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * file-get-storage-info.c (trivfs_S_file_get_storage_info):
- Rewrite for new interface.
-
-Mon Apr 29 15:19:26 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * handle-port.c: Comment out warning addition.
-
-Sun Apr 28 15:22:16 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * handle-port.c: Add obsolescence link warning.
-
-Thu Apr 11 18:03:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (MIGSFLAGS): Reference fsmutations.h in $(srcdir).
-
-Thu Jan 25 16:19:29 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * cntl-create.c (trivfs_create_control): New function.
- * trivfs.h (trivfs_create_control): New declaration.
- * startup.c (trivfs_startup): Use trivfs_create_control.
- * handle-port.c (trivfs_handle_port): Likewise.
- * Makefile (OTHERSRCS): Add cntl-create.c.
-
- * open.c (trivfs_open): Use ports_create_port instead of
- ports_allocate_port, and return any error.
- * protid-dup.c (trivfs_protid_dup): Likewise.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
-
-Mon Jan 15 12:02:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * protid-clean.c (trivfs_clean_protid): Don't hold
- CRED->po->cntl->lock while calling TRIVFS_PEROPEN_DESTROY_HOOK.
-
-SUN Nov 5 00:01:53 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsys-stubs.c (trivfs_S_fsys_get_options,
- trivfs_S_file_get_fs_options): New functions.
-
- * file-get-storage-info.c (trivfs_S_file_get_storage_info): Add
- FLAGS arg.
-
- * dir-chg.c (trivfs_S_dir_notice_changes): Waste some time adding
- reply port args that no one will use.
- * dir-link.c (trivfs_S_dir_link): Ditto.
- * dir-lookup.c (trivfs_S_dir_lookup): Ditto.
- * file-utimes.c (trivfs_S_file_utimes): Ditto.
- * file-statfs.c (trivfs_S_file_statfs)Ditto.
- * file-set-trans.c (trivfs_S_file_set_translator): Ditto.
- * file-lock.c (trivfs_S_file_lock, trivfs_S_file_lock_stat): Ditto.
- * file-getlinknode.c (trivfs_S_file_getlinknode): Ditto.
- * file-getfh.c (trivfs_S_file_getfh): Ditto.
- * file-get-transcntl.c (trivfs_S_file_get_translator_cntl): Ditto.
- * file-get-trans.c (trivfs_S_file_get_translator): Ditto.
- * file-get-storage-info.c (trivfs_S_file_get_storage_info): Ditto.
- * file-chown.c (trivfs_S_file_chown): Ditto.
- * file-chflags.c (trivfs_S_file_chflags): Ditto.
- * file-chg.c (trivfs_S_file_notice_changes): Ditto.
- * dir-unlink.c (trivfs_S_dir_unlink): Ditto.
- * dir-rmdir.c (trivfs_S_dir_rmdir): Ditto.
- * dir-rename.c (trivfs_S_dir_rename): Ditto.
- * dir-readdir.c (trivfs_S_dir_readdir): Ditto.
- * dir-mkfile.c (trivfs_S_dir_mkfile): Ditto.
- * dir-mkdir.c (trivfs_S_dir_mkdir): Ditto.
- * file-chmod.c (trivfs_S_file_chmod): Ditto.
- * file-chauthor.c (trivfs_S_file_chauthor): Ditto.
-
-Wed Nov 1 15:53:38 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * startup.c (trivfs_startup): Add FLAGS arg, passed to fsys_startup.
- * trivfs.h (trivfs_startup): Add FLAGS arg.
- * fsys-stubs.c (trivfs_S_fsys_startup): Ditto.
-
-Sat Oct 7 05:04:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * fsys-stubs.c (trivfs_S_fsys_getpriv): Add poly args.
-
- * Makefile (libtrivfs.so): Depend on ../libports/libports.so.
-
-Fri Oct 6 17:44:08 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * migsupport.c: Remove leading _ from function names.
- * fsmutations.h: Likewise.
- * trivfs.h (trivfs_{begin,end}_using_{protid,control}): Declare them.
-
-Fri Oct 6 17:28:07 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dir-link.c (trivfs_S_dir_link): Swap first two arguments.
-
- * file-get-storage-info.c (trivfs_S_file_get_storage_info): Change
- type of RUNS to off_t **, and add the BLOCK_SIZE parameter.
-
-Thu Oct 5 00:41:33 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (FSSRCS): Add file-get-storage-info.c.
- * file-get-storage-info.c: New file.
-
-Mon Sep 18 14:29:37 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * file-set-size.c (trivfs_S_file_set_size): Renamed from
- file-truncate.c:trivfs_s_file_truncate.
- * io-pathconf.c (trivfs_S_io_pathconf): Renamed from
- file-pathconf.c:trivfs_S_file_pathconf.
- (trivfs_S_io_pathconf): Add reply port to args.
- * Makefile (FSSRCS): Remove file-pathconf.c.
- (IOSRCS): Add io-pathconf.c.
- (FSSRCS): Rename file-truncate.c to file-set-size.c.
-
-Wed Sep 6 10:33:03 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * demuxer.c (trivfs_demuxer): Use ports_notify_server and
- ports_interrupt_server instead of our own versions.
- * Makefile (SRCS): Removed $(NOTIFYSRCS) and $(INTSRCS).
- (NOTIFYSRCS, INTSRCS): Removed.
- (MIGSTUBS): Removed notifyServer.o and interruptServer.o.
- * interrupt.c: File deleted.
-
-Fri Aug 25 12:11:26 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * interrupt.c (trivfs_S_interrupt_operation): Use ports_interrupt_rpc.
-
-Thu Aug 24 11:46:19 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fsys-forward.c (trivfs_S_fsys_forward): New file.
-
-Wed Aug 23 15:09:31 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (REMHDRS): Removed.
- (FSYSSRCS): Added fsys-forward.c.
-
-Mon Aug 21 15:25:36 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * handle-port.c (trivfs_handle_port): Initialize the hook field.
- * io-stat.c (trivfs_S_io_stat): Pass CRED to trivfs_modify_stat.
- * fsys-goaway.c (trivfs_S_fsys_goaway): Use new args for trivfs_goaway.
- * trivfs.h (struct trivfs_control): Add the hook field.
- (trivfs_goaway): Pass the control structure directly instead of
- random fields from it.
- (trivfs_modify_stat): Pass in the node as well.
-
-Mon Aug 21 10:51:24 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * protid-dup.c: Doc fix.
-
-Fri Aug 11 14:01:41 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * open.c (trivfs_open): Actually set the PO field to what we create.
- * Makefile (OTHERSRCS): Add protid-dup.c and open.c.
-
-Tue Aug 8 14:07:04 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * open.c: New file, containing trivfs_open.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Guts (except for
- protection check) moved into trivfs_open.
- * protid-dup.c: New file, containing trivfs_protid_dup.
- * io-duplicate.c (trivfs_S_io_duplicate): Guts moved into
- trivfs_protid_dup.
-
- * trivfs.h (trivfs_protid_create_hook, trivfs_peropen_create_hook):
- Change the declarations now that these return an error code.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Allow
- trivfs_protid_create_hook and trivfs_peropen_create_hook to return
- an error code, and abort if either does.
- * protid-clean.c (trivfs_clean_protid): Only call
- trivfs_protid_destroy_hook hook on CRED if it was fully initialized.
- * io-duplicate.c (trivfs_S_io_duplicate): Allow
- trivfs_protid_create_hook to return an error code.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Ditto.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Ditto.
-
-Fri Jul 21 17:01:12 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Free initial reference
- created by ports_allocate_port.
- * handle-port.c (trivfs_handle_port): Likewise.
- * io-duplicate.c (trivfs_S_io_duplicate): Likewise.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
-
-Sun Jul 16 13:00:44 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * trivfs.h: Protect against including twice, and add includes that
- we depend on.
-
-Thu Jul 6 15:38:48 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Tue Jun 27 10:55:16 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fsys-goaway.c (trivfs_S_fsys_goaway): Call trivfs_goaway the new
- way.
- * startup.c (trivfs_startup): New parms CONTROL_BUCKET and
- PROTID_BUCKET; pass them to trivfs_handle_port. Use new ports
- interface.
- * protid-clean.c (trivfs_clean_protid): Use new ports interface.
- Use PREdecrement in reference counting check.
- * nosenders.c (trivfs_do_mach_notify_no_senders): Use new ports
- interface.
- * migsupport.c (_trivfs_begin_using_protid,
- _trivfs_end_using_protid, _trivfs_begin_using_oontrol,
- _trivfs_end_using_control): Use new ports interface.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Use new ports
- interface.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Use new ports
- interface.
- * io-duplicate.c (trivfs_S_io_duplicate): Use new ports interface.
- * handle-port.c (trivfs_handle_port): Take new parms; use new
- ports interface; initialize CNTL->protid_bucket.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Use new form of
- ports_allocate_port call.
- * trivfs.h (trivfs_protid_portclasses): Renamed from
- trivfs_protid_porttypes. Change type to `struct port_class *'.
- (trivfs_protid_nportclasses): Renamed from trivfs_protid_nporttypes.
- (trivfs_cntl_portclasses): Renamed from trivfs_cntl_porttypes. Change
- type to `struct port_class *'.
- (trivfs_cntl_nportclasses): Renamed from trivfs_cntl_nporttypes.
- (trivfs_startup): Pass port classes instead of integer types. New
- parms CONTROL_BUCKET and PROTID_BUCKET.
- (trivfs_handle_port): Pass port classes instead of integer types.
- New parms CONTROL_BUCKET and PROTID_BUCKET.
- (trivfs_goaway): Pass port classes instead of integer types.
- (struct trivfs_control): Renamed member `protid_types' to be
- `protid_class' and changed type to be `stroct port_class *'.
- New member `protid_bucket'.
-
-Fri May 12 19:05:46 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fsys-stubs.c (trivfs_S_fsys_set_options,
- trivfs_S_fsys_mod_readonly): Change from mod_readonly to set_options.
-
-Sun Apr 9 00:36:36 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * io-stat.c (trivfs_S_io_stat): Before calling trivfs_modify_stat,
- set the st_fstype & st_fsid fields to trivfs_fstype & trivfs_fsid.
- But first, if trivfs_fsid is zero, set it to our process id, which
- should be a nice unique value.
- * file-statfs.c (trivfs_S_file_statfs): Ditto about the PID.
-
- * startup.c (trivfs_startup): New function, which implements a
- common sequence of steps when starting up a new trivfs.
- * trivfs.h: Declare trivfs_startup.
- * Makefile (OTHERSRCS): Add startup.c.
-
-Thu Mar 30 12:27:59 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * trivfs.h (trivfs_check_open_hook): Doc fix.
- (trivfs_complete_open): Delete declaration.
- (struct trivfs_control): Delete members `openshead' and
- `openstail'.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Strip out old
- hack for blocking.
- (struct pending_open): Delete type.
- (trivfs_complete_open): Delete function.
-
- * trivfs.h (struct trivfs_control): New member `lock'.
- * handle-port.c (trivfs_handle_port): Initialize CNTL->lock.
- * io-duplicate.c (trivfs_S_io_duplicate): Lock
- CRED->po->cntl->lock around relevant code.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
- * protid-clean.c (trivfs_clean_protid): Likewise.
-
-Tue Jan 17 19:00:28 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io-select.c: Updated for new io_select interface.
-
-Fri Dec 9 01:35:54 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io-write.c: Use mach_msg_type_number_t in place of unsigned int
- and int.
- * io-read.c: Likewise.
- * io-readable.c: Likewise.
-
-Tue Oct 25 10:54:06 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Don't clear O_NONBLOCK.
-
-Tue Aug 30 13:23:55 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * fsys-syncfs.c: New file.
- * Makefile (FSYSSRCS): Added fsys-syncfs.c.
- * fsys-stubs.c (trivfs_S_fsys_mod_readonly): New function.
-
- * Makefile (FSSRCS): Remove dir-pathtrans.c; add dir-lookup.c.
- * dir-lookup.c: Renamed from dir-pathtrans.c
- * dir-pathtrans.c (trivfs_S_dir_lookup): Renamed from
- trivfs_S_dir_pathtrans.
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Use FS_RETRY_NORMAL
- instead of FS_RETRY_NONE.
- (trivfs_complete_open): Likewise.
-
- * file-set-trans.c (trivfs_S_file_set_translator): Change to args
- as for new file_set_translator procotol.
-
-Mon Aug 29 12:52:43 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Use new
- authentication protocol.
-
-Wed Aug 17 20:11:29 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io-select.c (trivfs_S_io_select): Take poly arg for notify port.
-
-Thu Aug 11 11:58:48 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * io-version.c (trivfs_S_io_server_version): Fix typo in name.
-
-Fri Jul 22 12:41:55 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * fsys-goaway.c: Include fsys_S.h with " not with <>.
- * handle-port.c: Include priv.h with " not with <>.
-
- * Makefile: Converted to use new scheme.
- * fsmutations.h (SERVERPREFIX): Deleted macro.
- * fsys-getroot.c: Include "fsys_reply_U.h" instead of "fsys_reply.h".
-
-Wed Jul 20 15:59:36 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * file-inv.c: New file.
- * Makefile (FSSRCS): Added file-inv.c.
-
-Tue Jul 19 19:23:33 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fsys-stubs.c (trivfs_S_fsys_startup): Deleted dotdot args.
- * fsys-getroot.c (trivfs_S_fsys_getroot): New arg `dotdot';
- don't do anything with it.
-
-Mon Jul 11 14:49:03 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * trivfs.h (trivfs_set_atime, trivfs_set_mtime): New functions.
- * times.c: New file.
- * Makefile (OTHERSRCS): Added `times.c'.
-
-Thu Jul 7 10:39:04 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (DIST_FILES): Add priv.h.
-
-Tue Jul 5 13:24:59 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (DIST_FILES): Added fsmutations.h.
- (TAGSHDRS): New variable.
-
- * fsys-getroot.c: Include "fsys_reply.h".
- (trivfs_S_fsys_getroot, trivfs_complete_open):
- Uncomment code now that we have reply ports.
- (struct pending_open): Delete USERS_PORT, add CRED.
- (trivfs_S_fsys_getroot): When creating PENDO, don't call
- ports_get_right, call ports_port_ref; store CRED in PENDO.
- (trivfs_complete_open): Deal with errors properly. When sending
- port to user, call ports_get_right. Always call
- ports_done_with_port when freeing pending open struct.
- * Makefile (MIGSTUBS): Added fsys_replyUser.o.
- (fsys_reply.h fsys_replyUser.c): New rule.
- (fsys-getroot.c): Add dependency on fsys_reply.h.
-
- * fsmutations.h (REPLY_PORTS): New macro, affecting io and fsys
- interfaces.
- * io-async-icky.c (trivfs_S_io_get_icky_async_id): Added new
- REPLY and REPLYTYPE args.
- * io-async.c (trivfs_S_io_async): Likewise.
- * io-duplicate.c (trivfs_S_io_duplicate): Likewise.
- * io-map.c (trivfs_S_io_map): Likewise.
- * io-modes-get.c (trivfs_S_io_get_openmodes): Likewise.
- * io-modes-off.c (trivfs_S_io_clear_some_openmodes): Likewise.
- * io-modes-on.c (trivfs_S_io_set_some_openmodes): Likewise.
- * io-modes-set.c (trivfs_S_io_set_all_openmodes): Likewise.
- * io-owner-get.c (trivfs_S_io_get_owner): Likewise.
- * io-owner-mod.c (trivfs_S_io_mod_owner): Likewise.
- * io-read.c (trivfs_S_io_read): Likewise.
- * io-readable.c (trivfs_S_io_readable): Likewise.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
- * io-seek.c (trivfs_S_io_seek): Likewise.
- * io-select.c (trivfs_S_io_select): Likewise.
- * io-stat.c (trivfs_S_io_stat): Likewise.
- * io-stubs.c (trivfs_S_io_map_cntl): Likewise.
- (trivfs_S_io_get_conch): Likewise.
- (trivfs_S_io_release_conch): Likewise.
- (trivfs_S_io_eofnotify): Likewise.
- (trivfs_S_io_prenotify): Likewise.
- (trivfs_S_io_postnotify): Likewise.
- (trivfs_S_io_readsleep): Likewise.
- (trivfs_S_io_sigio): Likewise.
- (trivfs_S_io_readnotify): Likewise.
- * io-write.c (trivfs_S_io_write): Likewise.
- * io-version.c (trivfs_S_trivfs_io_server_version): Likewise.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Likewise.
- * fsys-goaway.c (trivfs_S_fsys_goaway): Likewise.
- * fsys-stubs.c (trivfs_S_fsys_startup): Likewise.
- (trivfs_S_fsys_getpriv): Likewise.
- (trivfs_S_fsys_init): Likewise.
- (trivfs_S_fsys_getfile): Likewise.
-
-Wed Jun 29 13:02:17 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * io-read.c (trivfs_S_io_read): Always return EOPNOTSUPP.
- * io-write.c (trivfs_S_io_write): Likewise.
- * file-truncate.c (trivfs_S_file_truncate): Likewise.
- * io-readable.c (trivfs_S_io_readable): Likewise.
- * io-select.c (trivfs_S_io_select): Likewise.
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Use trivfs_allow_open
- instead of trivfs_support_* vars.
-
- * trivfs.h (trivfs_allow_open): New variable.
-
- * dir-pathtrans.c (trivfs_S_dir_pathtrans): Delete unused var
- `newcred'.
-
-Mon Jun 27 15:05:06 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fsys-getroot.c: Comment out code for blocking opens; don't
- permit trivfs_check_open_hook to return EWOULDBLOCK.
-
-Thu Jun 23 12:28:49 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Don't call
- ports_done_with_port for CNTL; the MiG destructor function does
- that for us.
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Call trivfs_check_open_hook
- to allow trivfs users to block or restrict opens.
- * trivfs.h (trivfs_check_open_hook, trivfs_complete_open): New
- declarations.
- (struct trivfs_control): New members `openshead' and `openstail'.
-
-Wed Jun 22 14:49:00 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Initialize both hook
- members to 0.
- * io-duplicate.c (trivfs_S_io_duplicate): Copy NEWCRED->hook
- from CRED->hook.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
-
- * fsys-getroot.c (trivfs_S_fsys_getroot): Don't force read/write
- systems to redefine this function. If O_foo is set, but
- trivfs_support_foo isn't, then return EACCES. Call
- io_restrict_auth at the front so we can check open permission
- using the result. Initialise CRED->po->openmodes.
-
- * trivfs.h (trivfs_peropen): New member `openmodes'.
- * io-modes-get.c (trivfs_S_io_get_openmodes): Set bits from
- CRED->po->openmodes, but only if we are not a read/write
- server; otherwise the server might be hiding bits elsewhere.
-
- * dir-pathtrans.c (trivfs_S_dir_pathtrans): Strip out code; always
- return ENOTDIR.
-
-Tue Jun 21 13:21:07 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * file-access.c: New file.
- * dir-chg.c: New file.
- * file-chg.c: New file.
- * Makefile (FSSRCS): Added file-access.c, dir-chg.c, and file-chg.c.
-
-Mon Jun 20 14:42:12 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-readdir.c (trivfs_S_dir_readdir): Declare args in accord
- with fs.defs interface change.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Likewise. Set
- DO_RETRY and RETRY_NAME appropriately.
- * file-get-transcntl.c (trivfs_S_file_get_translator_cntl):
- CNTL_TYPE is a pointer.
-
-Fri Jun 17 11:23:47 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * file-get-transcntl.c (trivfs_S_file_get_translator_cntl): Add
- missing poly arg.
-
-Wed Jun 15 21:27:20 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir-pathtrans.c: Include <string.h> for bcopy.
- * fsys-getroot.c: Likewise.
- * io-duplicate.c: Likewise.
- * io-reauthenticate.c: Likewise.
- * io-restrict-auth.c: Likewise.
-
-Wed Jun 15 16:58:02 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * trivfs.h (trivfs_goaway): New args REALNODE, CNTLTYPE,
- PROTIDTYPE. All callers changed.
-
- * fsmutations.h (FSYS_DESTRUCTOR, FSYS_INTRAN): New macros.
- * priv.h (trivfs_control_t): New type.
- (_trivfs_begin_using_control, _trivfs_end_using_control): New
- declarations.
- * migsupport.c (_trivfs_begin_using_control,
- _trivfs_end_using_control): New functions.
- * fsys-getroot.c (trivfs_S_fsys_getroot): First arg is now
- `struct trivfs_control *'; don't call ports_check_port_type
- ourselves or ports_done_with_port.
- * fsys-goaway.c (trivfs_S_fsys_goaway): Likewise.
- * fsys-stubs.c (trivfs_S_fsys_startup, trivfs_S_fsys_getpriv,
- trivfs_S_fsys_init, trivfs_S_fsys_getfile): Declare first
- arg as `struct trivfs_control *'.
-
- * trivfs.h (trivfs_protid_porttype, trivfs_cntl_porttype):
- Deleted vars.
- (trivfs_protid_porttypes, trivfs_cntl_porttypes,
- trivfs_protid_nporttypes, trivfs_cntl_nporttypes): New vars.
- (trivfs_control): New member protidtypes.
- (trivfs_handle_port): New args PROTIDTYPE and CNTLTYPE.
- * migsupport.h (_trivfs_begin_using_protid): Check
- against all the members of trivfs_protid_porttypes.
- * dir-pathtrans.c (trivfs_S_dir_pathtrans): Copy type of new port
- from existing port.
- * io-duplicate.c (trivfs_S_io_duplicate): Likewise.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * handle-port.c (trivfs_handle_port): Allocate port of type
- from new arg CNTLTYPE. Initialize CNTL->protidtypes from new arg
- PROTIDTYPE.
- * fsys-getroot (trivfs_S_fsys_getroot): Allocate port of type
- from CNTL->protidtypes.
-
- * trivfs.h (struct trivfs_protid) [hook]: New member.
- (trivfs_protid_create_hook, trivfs_peropen_create_hook,
- trivfs_protid_destroy_hook, trivfs_peropen_destroy_hook): New
- hook functions.
- * dir-pathtrans.c (trivfs_S_dir_pathtrans): Call
- trivfs_peropen_create_hook.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Likewise.
- * dir-pathtrans.c (trivfs_S_dir_pathtrans): Call
- trivfs_protid_create_hook.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Likewise.
- * io-duplicate.c (trivfs_S_io_duplicate): Likewise.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
- * protid-clean.c (trivfs_clean_protid): Call
- trivfs_protid_destroy_hook and trivfs_peropen_destroy_hook.
-
- * trivfs.h (struct trivfs_protid) [po]: New member.
- (struct trivfs_protid) [cntl]: Deleted member.
- (struct trivfs_peropen): New type.
- * file-getcontrol.c (trivfs_S_file_getcontrol): Fetch control
- port through peropen structure.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Likewise.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Likewise.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Reference
- peropen, not cntl.
- * io-restrict-auth.c (trivfs_S_io_restrict_auth): Likewise.
- * io-duplicate.c (trivfs_S_io_duplicate): Likewise.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Create new peropen
- and reference it.
- * dir-pathtrans (trivfs_S_dir_pathtrans): Actually create new
- peropen and cred.
- * protid-clean.c (trivfs_clean_protid): Drop reference on peropen,
- deallocating it if necessary.
-
- * trivfs.h (struct trivfs_protid) [uids, gids, nuids, ngids]: New
- members.
- * io-reauthenticate.c (trivfs_S_io_reauthenticate): Save received
- ids in newly created protid.
- * io-restrict-auth.c (listmember): New function.
- (trivfs_S_io_restrict_auth): Save uids and gids in newly created
- protid.
- * io-duplicate.c (trivfs_S_io_duplicate): Copy uids and gids.
- * protid-clean.c (trivfs_clean_protid): Free CRED->uids and
- CRED->gids.
- * fsys-getroot.c (trivfs_S_fsys_getroot): Initialize uids
- and gids.
-
-
-
diff --git a/libtrivfs/Makefile b/libtrivfs/Makefile
index 66333f32..ddce1e61 100644
--- a/libtrivfs/Makefile
+++ b/libtrivfs/Makefile
@@ -1,5 +1,6 @@
-#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2001, 2002, 2003, 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
@@ -24,12 +25,12 @@ FSSRCS= dir-link.c dir-mkdir.c dir-mkfile.c dir-lookup.c dir-readdir.c \
file-get-transcntl.c file-getcontrol.c file-getfh.c \
file-getlinknode.c file-lock.c file-set-trans.c file-statfs.c \
file-sync.c file-syncfs.c file-set-size.c file-utimes.c file-exec.c \
- file-access.c dir-chg.c file-chg.c file-inv.c file-get-storage-info.c \
- file-get-fs-options.c
+ file-access.c dir-chg.c file-chg.c file-get-storage-info.c \
+ file-get-fs-options.c file-reparent.c
IOSRCS=io-async-icky.c io-async.c io-duplicate.c io-map.c io-modes-get.c \
io-modes-off.c io-modes-on.c io-modes-set.c io-owner-get.c \
- io-owner-mod.c io-pathconf.c io-read.c io-readable.c \
+ io-owner-mod.c io-pathconf.c io-read.c io-readable.c io-revoke.c \
io-reauthenticate.c io-restrict-auth.c io-seek.c io-select.c \
io-stat.c io-stubs.c io-write.c io-version.c io-identity.c
@@ -38,19 +39,25 @@ FSYSSRCS=fsys-getroot.c fsys-goaway.c fsys-stubs.c fsys-syncfs.c \
OTHERSRCS=demuxer.c protid-clean.c protid-dup.c cntl-create.c \
cntl-clean.c migsupport.c times.c startup.c open.c \
- runtime-argp.c set-options.c get-options.c
+ runtime-argp.c set-options.c append-args.c dyn-classes.c \
+ protid-classes.c cntl-classes.c
SRCS=$(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(OTHERSRCS)
MIGSTUBS=fsServer.o ioServer.o fsysServer.o fsys_replyUser.o
+libname = libtrivfs
+HURDLIBS = fshelp iohelp ports shouldbeinlibc
OBJS= $(sort $(subst .c,.o,$(SRCS)) $(MIGSTUBS))
LCLHDRS = trivfs.h fsmutations.h priv.h
MIGSFLAGS=-imacros $(srcdir)/fsmutations.h
MIGCOMSFLAGS = -prefix trivfs_
-libname = libtrivfs
-installhdrs = trivfs.h
+installhdrs := trivfs.h
+mig-sheader-prefix = trivfs_
+ifndef no_deps
+installhdrs += $(patsubst %,trivfs_%_S.h,fs io fsys)
+endif
include ../Makeconf
-libtrivfs.so: ../libports/libports.so
+$(MIGSTUBS:%Server.o=%.sdefsi): $(srcdir)/fsmutations.h
diff --git a/libtrivfs/get-options.c b/libtrivfs/append-args.c
index 370550da..d5c3d4a3 100644
--- a/libtrivfs/get-options.c
+++ b/libtrivfs/append-args.c
@@ -1,4 +1,4 @@
-/* Get runtime options
+/* Append current command line arguments
Copyright (C) 1996 Free Software Foundation
@@ -20,10 +20,11 @@
#include "priv.h"
-/* Return runtime options for FSYS in ARGZ & ARGZ_LEN. ARGZ should be
- allocated with malloc. */
+/* Append to the malloced string *ARGZ of length *ARGZ_LEN a NUL-separated
+ list of the arguments to this translator. */
error_t
-trivfs_get_options (struct trivfs_control *fsys, char **argz, size_t *argz_len)
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
{
return EOPNOTSUPP;
}
diff --git a/devio/ptypes.h b/libtrivfs/cntl-classes.c
index 64aa3b0d..356c9e92 100644
--- a/devio/ptypes.h
+++ b/libtrivfs/cntl-classes.c
@@ -1,8 +1,6 @@
-/* Libports port types for devio.
+/* Defaults for TRIVFS_CNTL_[N]PORTCLASSES
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1997 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
@@ -18,6 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#define PT_FSYS 0
-#define PT_NODE 1
-#define PT_MEMOBJ 2
+#include "trivfs.h"
+
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_cntl_nportclasses;
diff --git a/libtrivfs/cntl-clean.c b/libtrivfs/cntl-clean.c
index 4b7a29cd..a010828f 100644
--- a/libtrivfs/cntl-clean.c
+++ b/libtrivfs/cntl-clean.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1996 Free Software Foundation
+ Copyright (C) 1994, 1996, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -27,4 +27,9 @@ trivfs_clean_cntl (void *arg)
mach_port_destroy (mach_task_self (), cntl->filesys_id);
mach_port_destroy (mach_task_self (), cntl->file_id);
mach_port_deallocate (mach_task_self (), cntl->underlying);
+
+ trivfs_remove_control_port_class (cntl->pi.class);
+ trivfs_remove_port_bucket (cntl->pi.bucket);
+ trivfs_remove_protid_port_class (cntl->protid_class);
+ trivfs_remove_port_bucket (cntl->protid_bucket);
}
diff --git a/libtrivfs/cntl-create.c b/libtrivfs/cntl-create.c
index dbe261b2..f103ed48 100644
--- a/libtrivfs/cntl-create.c
+++ b/libtrivfs/cntl-create.c
@@ -1,6 +1,6 @@
/* Create a new trivfs control port
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -33,9 +33,34 @@ trivfs_create_control (mach_port_t underlying,
struct port_bucket *protid_bucket,
struct trivfs_control **control)
{
- error_t err =
- ports_create_port (control_class, control_bucket,
- sizeof (struct trivfs_control), control);
+ error_t err;
+
+ /* Perhaps allocate, and perhaps add the specified port classes the ones
+ recognized by trivfs. */
+ err = trivfs_add_control_port_class (&control_class);
+ if (! err)
+ err = trivfs_add_protid_port_class (&protid_class);
+ else
+ protid_class = 0;
+
+ /* Perhaps allocate new port buckets. */
+ if (! err)
+ err = trivfs_add_port_bucket (&control_bucket);
+ else
+ control_bucket = 0;
+ if (! err)
+ {
+ if (! protid_bucket)
+ /* By default, use the same port bucket for both. */
+ protid_bucket = control_bucket;
+ err = trivfs_add_port_bucket (&protid_bucket);
+ }
+ else
+ protid_bucket = 0;
+
+ if (! err)
+ err = ports_create_port (control_class, control_bucket,
+ sizeof (struct trivfs_control), control);
if (! err)
{
@@ -47,7 +72,7 @@ trivfs_create_control (mach_port_t underlying,
if (err)
{
ports_port_deref (*control);
- return err;
+ goto out;
}
err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
@@ -56,12 +81,21 @@ trivfs_create_control (mach_port_t underlying,
{
mach_port_destroy (mach_task_self (), (*control)->filesys_id);
ports_port_deref (*control);
- return err;
+ goto out;
}
(*control)->hook = 0;
mutex_init (&(*control)->lock);
}
+out:
+ if (err)
+ {
+ trivfs_remove_control_port_class (control_class);
+ trivfs_remove_protid_port_class (protid_class);
+ trivfs_remove_port_bucket (control_bucket);
+ trivfs_remove_port_bucket (protid_bucket);
+ }
+
return err;
}
diff --git a/libtrivfs/dir-chg.c b/libtrivfs/dir-chg.c
index 6c9a9faf..d01abbbf 100644
--- a/libtrivfs/dir-chg.c
+++ b/libtrivfs/dir-chg.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_dir_notice_changes (struct trivfs_protid *cred,
diff --git a/libtrivfs/dir-link.c b/libtrivfs/dir-link.c
index 0f4833d0..f5a8c735 100644
--- a/libtrivfs/dir-link.c
+++ b/libtrivfs/dir-link.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,96,2002 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
@@ -16,10 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
-trivfs_S_dir_link (struct trivfs_protid *dir,
+trivfs_S_dir_link (struct trivfs_protid *dir,
mach_port_t reply, mach_msg_type_name_t reply_type,
struct trivfs_protid *file, char *name, int excl)
{
@@ -29,5 +28,3 @@ trivfs_S_dir_link (struct trivfs_protid *dir,
return EXDEV;
return ENOTDIR;
}
-
-
diff --git a/libtrivfs/dir-lookup.c b/libtrivfs/dir-lookup.c
index cdcfd4be..66afac1d 100644
--- a/libtrivfs/dir-lookup.c
+++ b/libtrivfs/dir-lookup.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,98,99,2001,02 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
#include <assert.h>
#include <fcntl.h>
#include <string.h>
@@ -32,8 +31,59 @@ trivfs_S_dir_lookup (struct trivfs_protid *cred,
mach_port_t *retrypt,
mach_msg_type_name_t *retrypt_type)
{
+ int perms;
+ error_t err;
+ struct trivfs_protid *newcred;
+
if (!cred)
return EOPNOTSUPP;
- return ENOTDIR;
+ if (filename[0])
+ return ENOTDIR;
+
+ /* This is a null-pathname "reopen" call; do the right thing. */
+
+ /* Burn off flags we don't actually implement */
+ flags &= O_HURD;
+ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS);
+
+ /* Validate permissions */
+ if (! trivfs_check_access_hook)
+ file_check_access (cred->realnode, &perms);
+ else
+ (*trivfs_check_access_hook) (cred->po->cntl, cred->user,
+ cred->realnode, &perms);
+ if ((flags & (O_READ|O_WRITE|O_EXEC) & perms)
+ != (flags & (O_READ|O_WRITE|O_EXEC)))
+ return EACCES;
+
+ /* Execute the open */
+ err = 0;
+ if (trivfs_check_open_hook)
+ err = (*trivfs_check_open_hook) (cred->po->cntl, cred->user, flags);
+ if (!err)
+ {
+ struct iouser *user;
+
+ err = iohelp_dup_iouser (&user, cred->user);
+ if (err)
+ return err;
+
+ err = trivfs_open (cred->po->cntl, user, flags,
+ cred->realnode, &newcred);
+ if (err)
+ iohelp_free_iouser (user);
+ else
+ mach_port_mod_refs (mach_task_self (), cred->realnode,
+ MACH_PORT_RIGHT_SEND, +1);
+ }
+ if (err)
+ return err;
+
+ *retry_type = FS_RETRY_NORMAL;
+ *retry_name = '\0';
+ *retrypt = ports_get_right (newcred);
+ *retrypt_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newcred);
+ return 0;
}
diff --git a/libtrivfs/dir-mkdir.c b/libtrivfs/dir-mkdir.c
index f41dfdbe..d39bd3f8 100644
--- a/libtrivfs/dir-mkdir.c
+++ b/libtrivfs/dir-mkdir.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,02 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
@@ -16,10 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
-trivfs_S_dir_mkdir (struct trivfs_protid *cred,
+trivfs_S_dir_mkdir (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
char *name, mode_t mode)
{
diff --git a/libtrivfs/dir-mkfile.c b/libtrivfs/dir-mkfile.c
index aaaa7ad9..048db244 100644
--- a/libtrivfs/dir-mkfile.c
+++ b/libtrivfs/dir-mkfile.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_dir_mkfile (struct trivfs_protid *file,
diff --git a/libtrivfs/dir-readdir.c b/libtrivfs/dir-readdir.c
index dbd0a054..f1176f07 100644
--- a/libtrivfs/dir-readdir.c
+++ b/libtrivfs/dir-readdir.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,99,2002 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
@@ -16,13 +16,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_dir_readdir (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
char **data,
- u_int *datalen,
+ size_t *datalen,
+ boolean_t *data_dealloc,
int entry,
int nentries,
vm_size_t bufsiz,
diff --git a/libtrivfs/dir-rename.c b/libtrivfs/dir-rename.c
index 48fff625..d68233ec 100644
--- a/libtrivfs/dir-rename.c
+++ b/libtrivfs/dir-rename.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,96,2002 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
@@ -16,10 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
-trivfs_S_dir_rename (struct trivfs_protid *cred,
+trivfs_S_dir_rename (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
char *name,
struct trivfs_protid *cred2, char *name2, int excl)
diff --git a/libtrivfs/dir-rmdir.c b/libtrivfs/dir-rmdir.c
index ab9d8f41..a4d320c4 100644
--- a/libtrivfs/dir-rmdir.c
+++ b/libtrivfs/dir-rmdir.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,14 +16,11 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
-trivfs_S_dir_rmdir (struct trivfs_protid *cred,
+trivfs_S_dir_rmdir (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
char *name)
{
return cred ? ENOTDIR : EOPNOTSUPP;
}
-
-
diff --git a/libtrivfs/dir-unlink.c b/libtrivfs/dir-unlink.c
index d86ad324..a6ef9b0c 100644
--- a/libtrivfs/dir-unlink.c
+++ b/libtrivfs/dir-unlink.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,10 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
-trivfs_S_dir_unlink (struct trivfs_protid *cred,
+trivfs_S_dir_unlink (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
char *name)
{
diff --git a/libtrivfs/dyn-classes.c b/libtrivfs/dyn-classes.c
new file mode 100644
index 00000000..5f73f8f3
--- /dev/null
+++ b/libtrivfs/dyn-classes.c
@@ -0,0 +1,269 @@
+/* Dynamically allocated port classes/buckets recognized by trivfs
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include "priv.h"
+
+/* Auxiliary info for each vector element. */
+struct aux
+{
+ void (*free_el)();
+ unsigned refs;
+};
+
+/* Vectors of dynamically allocated port classes/buckets. */
+
+/* Protid port classes. */
+struct port_class **trivfs_dynamic_protid_port_classes = 0;
+size_t trivfs_num_dynamic_protid_port_classes = 0;
+static struct aux *dynamic_protid_port_classes_aux = 0;
+static size_t dynamic_protid_port_classes_sz = 0;
+
+/* Control port classes. */
+struct port_class **trivfs_dynamic_control_port_classes = 0;
+size_t trivfs_num_dynamic_control_port_classes = 0;
+static struct aux *dynamic_control_port_classes_aux = 0;
+static size_t dynamic_control_port_classes_sz = 0;
+
+/* Port buckets. */
+struct port_bucket **trivfs_dynamic_port_buckets = 0;
+size_t trivfs_num_dynamic_port_buckets = 0;
+static struct aux *dynamic_port_buckets_aux = 0;
+static size_t dynamic_port_buckets_sz = 0;
+
+/* Lock used to control access to all the above vectors. */
+static struct mutex dyn_lock = MUTEX_INITIALIZER;
+
+/* Add EL to the vector pointed to by VEC_V, which should point to a vector
+ of pointers of some type, and has a length stored in *SZ; If there's
+ already a pointer to EL in VEC_V, nothing will actually be added, but the
+ reference count for that element will be increased. *NUM is the actual
+ number of non-null elements in the vector, and will be incremented if
+ something is actually added. AUX_VEC is a pointer to a vector of struct
+ aux elements, that contains information parralleling VEC_V. FREE_EL, if
+ non-zero, should be a function that takes a single argument of the same
+ type as EL, and deallocates it; this function is called in the following
+ cases: (1) An error is encountered trying to grow one of the vectors, (2)
+ when the element is eventually freed by drop_el. */
+static error_t
+add_el (void *el, void (*free_el)(),
+ void *vec_v, struct aux **aux_vec,
+ size_t *sz, size_t *num)
+{
+ int i;
+ size_t new_sz;
+ void ***vec, **new_vec;
+ struct aux *new_aux_vec;
+
+ if (! el)
+ return ENOMEM;
+
+ mutex_lock (&dyn_lock);
+
+ vec = vec_v;
+
+ for (i = 0; i < *sz; i++)
+ if (! (*vec)[i])
+ {
+ (*vec)[i] = el;
+ (*aux_vec)[i].free_el = free_el;
+ (*aux_vec)[i].refs = 1;
+ (*num)++;
+ mutex_unlock (&dyn_lock);
+ return 0;
+ }
+ else if ((*vec)[i] == el)
+ {
+ (*aux_vec)[i].refs++;
+ mutex_unlock (&dyn_lock);
+ return 0;
+ }
+
+ new_sz = *sz + 4;
+ new_vec = realloc (*vec, new_sz * sizeof (void *));
+ new_aux_vec = realloc (*aux_vec, new_sz * sizeof (struct aux));
+
+ if (!new_vec || !new_aux_vec)
+ {
+ if (free_el)
+ (*free_el) (el);
+ /* One of the vectors might be the wrong size, but who cares. */
+ return ENOMEM;
+ }
+
+ for (i = *sz; i < new_sz; i++)
+ new_vec[i] = 0;
+
+ new_vec[*sz] = el;
+ new_aux_vec[*sz].free_el = free_el;
+ new_aux_vec[*sz].refs = 1;
+ (*num)++;
+
+ *vec = new_vec;
+ *aux_vec = new_aux_vec;
+ *sz = new_sz;
+
+ mutex_unlock (&dyn_lock);
+
+ return 0;
+}
+
+/* Scan VEC_V, which should be a vector of SZ pointers of the same type as
+ EL, for EL; if it is found, then decrement its reference count, and if
+ that goes to zero, decrement *NUM and free EL if it had an associated free
+ routine passed to add_el. */
+static void
+drop_el (void *el, void *vec_v, struct aux *aux_vec,
+ size_t sz, size_t *num)
+{
+ int i;
+ void **vec;
+
+ if (! el)
+ return;
+
+ mutex_lock (&dyn_lock);
+
+ vec = vec_v;
+
+ for (i = 0; i < sz; i++)
+ if (vec[i] == el)
+ {
+ if (aux_vec[i].refs == 1)
+ {
+ if (aux_vec[i].free_el)
+ (*aux_vec[i].free_el) (el);
+ vec[i] = 0;
+ (*num)--;
+ }
+ else
+ aux_vec[i].refs--;
+ break;
+ }
+
+ mutex_unlock (&dyn_lock);
+}
+
+/* Add the port class *CLASS to the list of control port classes recognized
+ by trivfs; if *CLASS is 0, an attempt is made to allocate a new port
+ class, which is stored in *CLASS. */
+error_t
+trivfs_add_control_port_class (struct port_class **class)
+{
+ /* XXX Gee, there *is no* way of freeing port classes or buckets! So we
+ actually never free anything! */
+
+ if (! *class)
+ {
+ *class = ports_create_class (trivfs_clean_cntl, 0);
+ if (! *class)
+ return ENOMEM;
+ }
+
+ return
+ add_el (*class, 0,
+ &trivfs_dynamic_control_port_classes,
+ &dynamic_control_port_classes_aux,
+ &dynamic_control_port_classes_sz,
+ &trivfs_num_dynamic_control_port_classes);
+}
+
+/* Remove the previously added dynamic control port class CLASS, freeing it
+ if it was allocated by trivfs_add_control_port_class. */
+void
+trivfs_remove_control_port_class (struct port_class *class)
+{
+ drop_el (class,
+ trivfs_dynamic_control_port_classes,
+ dynamic_control_port_classes_aux,
+ dynamic_control_port_classes_sz,
+ &trivfs_num_dynamic_control_port_classes);
+}
+
+/* Add the port class *CLASS to the list of protid port classes recognized by
+ trivfs; if *CLASS is 0, an attempt is made to allocate a new port class,
+ which is stored in *CLASS. */
+error_t
+trivfs_add_protid_port_class (struct port_class **class)
+{
+ /* XXX Gee, there *is no* way of freeing port classes or buckets! So we
+ actually never free anything! */
+
+ if (! *class)
+ {
+ *class = ports_create_class (trivfs_clean_protid, 0);
+ if (! *class)
+ return ENOMEM;
+ }
+
+ return
+ add_el (*class, 0,
+ &trivfs_dynamic_protid_port_classes,
+ &dynamic_protid_port_classes_aux,
+ &dynamic_protid_port_classes_sz,
+ &trivfs_num_dynamic_protid_port_classes);
+}
+
+/* Remove the previously added dynamic protid port class CLASS, freeing it
+ if it was allocated by trivfs_add_protid_port_class. */
+void
+trivfs_remove_protid_port_class (struct port_class *class)
+{
+ drop_el (class,
+ trivfs_dynamic_protid_port_classes,
+ dynamic_protid_port_classes_aux,
+ dynamic_protid_port_classes_sz,
+ &trivfs_num_dynamic_protid_port_classes);
+}
+
+/* Add the port bucket *BUCKET to the list of dynamically allocated port
+ buckets; if *bucket is 0, an attempt is made to allocate a new port
+ bucket, which is then stored in *bucket. */
+error_t
+trivfs_add_port_bucket (struct port_bucket **bucket)
+{
+ /* XXX Gee, there *is no* way of freeing port bucketes or buckets! So we
+ actually never free anything! */
+
+ if (! *bucket)
+ {
+ *bucket = ports_create_bucket ();
+ if (! *bucket)
+ return ENOMEM;
+ }
+
+ return
+ add_el (*bucket, 0,
+ &trivfs_dynamic_port_buckets,
+ &dynamic_port_buckets_aux,
+ &dynamic_port_buckets_sz,
+ &trivfs_num_dynamic_port_buckets);
+}
+
+/* Remove the previously added dynamic port bucket BUCKET, freeing it
+ if it was allocated by trivfs_add_port_bucket. */
+void
+trivfs_remove_port_bucket (struct port_bucket *bucket)
+{
+ drop_el (bucket,
+ trivfs_dynamic_port_buckets,
+ dynamic_port_buckets_aux,
+ dynamic_port_buckets_sz,
+ &trivfs_num_dynamic_port_buckets);
+}
diff --git a/libtrivfs/file-access.c b/libtrivfs/file-access.c
index d017b8e1..87029540 100644
--- a/libtrivfs/file-access.c
+++ b/libtrivfs/file-access.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,96,2002 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
@@ -16,15 +16,20 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
-kern_return_t
+error_t
trivfs_S_file_check_access (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
int *allowed)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
- *allowed = 0;
+
+ if (! trivfs_check_access_hook)
+ file_check_access (cred->realnode, allowed);
+ else
+ (*trivfs_check_access_hook) (cred->po->cntl, cred->user,
+ cred->realnode, allowed);
+
return 0;
}
diff --git a/libtrivfs/file-chauthor.c b/libtrivfs/file-chauthor.c
index 5f61743a..0460bfe1 100644
--- a/libtrivfs/file-chauthor.c
+++ b/libtrivfs/file-chauthor.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_chauthor (struct trivfs_protid *cred,
@@ -25,4 +24,3 @@ trivfs_S_file_chauthor (struct trivfs_protid *cred,
{
return cred ? file_chauthor (cred->realnode, auth) : EOPNOTSUPP;
}
-
diff --git a/libtrivfs/file-chflags.c b/libtrivfs/file-chflags.c
index 8d3d4577..c28f12f3 100644
--- a/libtrivfs/file-chflags.c
+++ b/libtrivfs/file-chflags.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,10 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
-trivfs_S_file_chflags (struct trivfs_protid *cred,
+trivfs_S_file_chflags (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
int flags)
{
diff --git a/libtrivfs/file-chg.c b/libtrivfs/file-chg.c
index a7df7e1d..3af71b33 100644
--- a/libtrivfs/file-chg.c
+++ b/libtrivfs/file-chg.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_notice_changes (struct trivfs_protid *cred,
diff --git a/libtrivfs/file-chmod.c b/libtrivfs/file-chmod.c
index f4a8cdb3..f42a43c7 100644
--- a/libtrivfs/file-chmod.c
+++ b/libtrivfs/file-chmod.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_chmod (struct trivfs_protid *cred,
diff --git a/libtrivfs/file-chown.c b/libtrivfs/file-chown.c
index 4eb664c5..44f79203 100644
--- a/libtrivfs/file-chown.c
+++ b/libtrivfs/file-chown.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_chown (struct trivfs_protid *cred,
@@ -25,6 +24,3 @@ trivfs_S_file_chown (struct trivfs_protid *cred,
{
return cred ? file_chown (cred->realnode, uid, gid) : EOPNOTSUPP;
}
-
-
-
diff --git a/libtrivfs/file-exec.c b/libtrivfs/file-exec.c
index d39af5fd..a3ab048d 100644
--- a/libtrivfs/file-exec.c
+++ b/libtrivfs/file-exec.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -19,6 +19,8 @@
kern_return_t
trivfs_S_file_exec (trivfs_protid_t exec_file,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
mach_port_t exec_task,
int flags,
data_t argv,
@@ -38,6 +40,3 @@ trivfs_S_file_exec (trivfs_protid_t exec_file,
{
return EOPNOTSUPP;
}
-
-
-
diff --git a/libtrivfs/file-get-fs-options.c b/libtrivfs/file-get-fs-options.c
index de887ca5..2e06c2d9 100644
--- a/libtrivfs/file-get-fs-options.c
+++ b/libtrivfs/file-get-fs-options.c
@@ -1,6 +1,6 @@
/* Get runtime options given a file handle
- Copyright (C) 1996 Free Software Foundation
+ Copyright (C) 1996,98,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -9,7 +9,7 @@
the Free Software Foundation; either version 2, or (at your option)
any later version.
- The GNU Hurd is distributed in the hope that it will be useful,
+ The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -18,10 +18,10 @@
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <argz.h>
#include <hurd/fshelp.h>
#include "priv.h"
-#include "fsys_S.h"
error_t
trivfs_S_file_get_fs_options (struct trivfs_protid *cred,
@@ -30,16 +30,22 @@ trivfs_S_file_get_fs_options (struct trivfs_protid *cred,
char **data, mach_msg_type_number_t *len)
{
error_t err;
- char *argz;
- size_t argz_len;
+ char *argz = 0;
+ size_t argz_len = 0;
if (! cred)
return EOPNOTSUPP;
- err = trivfs_get_options (cred->po->cntl, &argz, &argz_len);
+ err = argz_add (&argz, &argz_len, program_invocation_name);
+ if (err)
+ return err;
+
+ err = trivfs_append_args (cred->po->cntl, &argz, &argz_len);
if (! err)
/* Put ARGZ into vm_alloced memory for the return trip. */
- err = fshelp_return_malloced_buffer (argz, argz_len, data, len);
+ err = iohelp_return_malloced_buffer (argz, argz_len, data, len);
+ else
+ free (argz);
return err;
}
diff --git a/libtrivfs/file-get-storage-info.c b/libtrivfs/file-get-storage-info.c
index 7e4073ad..58bdbc5c 100644
--- a/libtrivfs/file-get-storage-info.c
+++ b/libtrivfs/file-get-storage-info.c
@@ -1,5 +1,5 @@
/* Stub for the file_get_storage_info RPC as described in <hurd/fs.defs>.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
error_t
trivfs_S_file_get_storage_info (struct trivfs_protid *cred,
diff --git a/libtrivfs/file-get-trans.c b/libtrivfs/file-get-trans.c
index 15f5a003..687dc8cc 100644
--- a/libtrivfs/file-get-trans.c
+++ b/libtrivfs/file-get-trans.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,12 +16,12 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_get_translator (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- char **trans, u_int *translen)
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ char **trans, size_t *translen)
{
return EOPNOTSUPP;
}
diff --git a/libtrivfs/file-get-transcntl.c b/libtrivfs/file-get-transcntl.c
index 0367fff2..8af08fc8 100644
--- a/libtrivfs/file-get-transcntl.c
+++ b/libtrivfs/file-get-transcntl.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_get_translator_cntl (struct trivfs_protid *cred,
diff --git a/libtrivfs/file-getcontrol.c b/libtrivfs/file-getcontrol.c
index c75472ab..2a58016e 100644
--- a/libtrivfs/file-getcontrol.c
+++ b/libtrivfs/file-getcontrol.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_getcontrol (struct trivfs_protid *cred,
@@ -27,7 +26,7 @@ trivfs_S_file_getcontrol (struct trivfs_protid *cred,
return EOPNOTSUPP;
if (!cred->isroot)
return EPERM;
-
+
*cntl = ports_get_right (cred->po->cntl);
*cntltype = MACH_MSG_TYPE_MAKE_SEND;
return 0;
diff --git a/libtrivfs/file-getfh.c b/libtrivfs/file-getfh.c
index eeb9e3d1..35deb7d5 100644
--- a/libtrivfs/file-getfh.c
+++ b/libtrivfs/file-getfh.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,12 +16,11 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
-trivfs_S_file_getfh (struct trivfs_protid *cred,
+trivfs_S_file_getfh (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
- char **data, u_int *datalen)
+ char **data, size_t *datalen)
{
return EOPNOTSUPP;
}
diff --git a/libtrivfs/file-getlinknode.c b/libtrivfs/file-getlinknode.c
index 56ac3dff..078e5deb 100644
--- a/libtrivfs/file-getlinknode.c
+++ b/libtrivfs/file-getlinknode.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_getlinknode (struct trivfs_protid *cred,
diff --git a/libtrivfs/file-lock.c b/libtrivfs/file-lock.c
index 10d39736..993baff6 100644
--- a/libtrivfs/file-lock.c
+++ b/libtrivfs/file-lock.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_lock (struct trivfs_protid *cred,
@@ -33,4 +32,3 @@ trivfs_S_file_lock_stat (struct trivfs_protid *cred,
{
return EOPNOTSUPP;
}
-
diff --git a/libtrivfs/file-reparent.c b/libtrivfs/file-reparent.c
new file mode 100644
index 00000000..0682a912
--- /dev/null
+++ b/libtrivfs/file-reparent.c
@@ -0,0 +1,34 @@
+/* Reparent a directory
+
+ Copyright (C) 1997,2002,2010 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "priv.h"
+
+error_t
+trivfs_S_file_reparent (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_port_t parent,
+ mach_port_t *new, mach_msg_type_name_t *new_type)
+{
+ /* This is not a directory, so we just duplicate it */
+ error_t ret = trivfs_S_io_duplicate (cred, reply, reply_type, new, new_type);
+ if (!ret)
+ mach_port_deallocate (mach_task_self (), parent);
+ return ret;
+}
diff --git a/libtrivfs/file-set-size.c b/libtrivfs/file-set-size.c
index eb174e46..287ed996 100644
--- a/libtrivfs/file-set-size.c
+++ b/libtrivfs/file-set-size.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
#include <assert.h>
kern_return_t
diff --git a/libtrivfs/file-set-trans.c b/libtrivfs/file-set-trans.c
index 36e9bd21..339bdb22 100644
--- a/libtrivfs/file-set-trans.c
+++ b/libtrivfs/file-set-trans.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,16 +16,16 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_set_translator (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
int actflags,
int passflags,
int oldtransflags,
char *trans,
- u_int translen,
+ size_t translen,
mach_port_t existing)
{
return EOPNOTSUPP;
diff --git a/libtrivfs/file-statfs.c b/libtrivfs/file-statfs.c
index 8b306623..648eef64 100644
--- a/libtrivfs/file-statfs.c
+++ b/libtrivfs/file-statfs.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,96,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
#include <string.h>
#include <unistd.h>
@@ -33,4 +32,4 @@ trivfs_S_file_statfs (struct trivfs_protid *cred,
stb->f_fsid = trivfs_fsid;
return 0;
-}
+}
diff --git a/libtrivfs/file-sync.c b/libtrivfs/file-sync.c
index 54076f67..cb0add3d 100644
--- a/libtrivfs/file-sync.c
+++ b/libtrivfs/file-sync.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,96,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_sync (struct trivfs_protid *cred,
diff --git a/libtrivfs/file-syncfs.c b/libtrivfs/file-syncfs.c
index 1f74e395..d356296e 100644
--- a/libtrivfs/file-syncfs.c
+++ b/libtrivfs/file-syncfs.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,96,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_syncfs (struct trivfs_protid *cred,
diff --git a/libtrivfs/file-utimes.c b/libtrivfs/file-utimes.c
index 916a8d8a..f9bedd7b 100644
--- a/libtrivfs/file-utimes.c
+++ b/libtrivfs/file-utimes.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fs_S.h"
kern_return_t
trivfs_S_file_utimes (struct trivfs_protid *cred,
diff --git a/libtrivfs/fsmutations.h b/libtrivfs/fsmutations.h
index cb716c8d..d81e5a87 100644
--- a/libtrivfs/fsmutations.h
+++ b/libtrivfs/fsmutations.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995 Free Software Foundation
+/*
+ Copyright (C) 1994,95,2002 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
@@ -28,6 +28,6 @@
#define FSYS_INTRAN trivfs_control_t trivfs_begin_using_control (fsys_t)
#define FSYS_DESTRUCTOR trivfs_end_using_control (trivfs_control_t)
-#define FILE_IMPORTS import "priv.h";
-#define IO_IMPORTS import "priv.h";
-#define FSYS_IMPORTS import "priv.h";
+#define FILE_IMPORTS import <hurd/trivfs.h>;
+#define IO_IMPORTS import <hurd/trivfs.h>;
+#define FSYS_IMPORTS import <hurd/trivfs.h>;
diff --git a/libtrivfs/fsys-forward.c b/libtrivfs/fsys-forward.c
index b7127a24..106360ea 100644
--- a/libtrivfs/fsys-forward.c
+++ b/libtrivfs/fsys-forward.c
@@ -1,8 +1,8 @@
/* fsys_forward
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995,2002 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -11,7 +11,7 @@
the Free Software Foundation; either version 2, or (at your option)
any later version.
- The GNU Hurd is distributed in the hope that it will be useful,
+ The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -21,7 +21,6 @@
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fsys_S.h"
/* Ask SERVER to provide fsys translation service for us. REQUESTOR is
the bootstrap port supplied to the original translator, and ARGV are
diff --git a/libtrivfs/fsys-get-options.c b/libtrivfs/fsys-get-options.c
index aa3b3374..4f2d602b 100644
--- a/libtrivfs/fsys-get-options.c
+++ b/libtrivfs/fsys-get-options.c
@@ -1,6 +1,6 @@
/* Get runtime options
- Copyright (C) 1996 Free Software Foundation
+ Copyright (C) 1996,98,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -9,7 +9,7 @@
the Free Software Foundation; either version 2, or (at your option)
any later version.
- The GNU Hurd is distributed in the hope that it will be useful,
+ The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -18,10 +18,10 @@
along with the GNU Hurd; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <argz.h>
#include <hurd/fshelp.h>
#include "priv.h"
-#include "fsys_S.h"
error_t
trivfs_S_fsys_get_options (struct trivfs_control *fsys,
@@ -29,16 +29,22 @@ trivfs_S_fsys_get_options (struct trivfs_control *fsys,
char **data, mach_msg_type_number_t *len)
{
error_t err;
- char *argz;
- size_t argz_len;
+ char *argz = 0;
+ size_t argz_len = 0;
if (! fsys)
return EOPNOTSUPP;
- err = trivfs_get_options (fsys, &argz, &argz_len);
+ err = argz_add (&argz, &argz_len, program_invocation_name);
+ if (err)
+ return err;
+
+ err = trivfs_append_args (fsys, &argz, &argz_len);
if (! err)
/* Put ARGZ into vm_alloced memory for the return trip. */
- err = fshelp_return_malloced_buffer (argz, argz_len, data, len);
+ err = iohelp_return_malloced_buffer (argz, argz_len, data, len);
+ else
+ free (argz);
return err;
}
diff --git a/libtrivfs/fsys-getroot.c b/libtrivfs/fsys-getroot.c
index 9eca01f5..60528d72 100644
--- a/libtrivfs/fsys-getroot.c
+++ b/libtrivfs/fsys-getroot.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1993,94,95,97,99,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "fsys_S.h"
#include "fsys_reply_U.h"
#include <assert.h>
#include <fcntl.h>
@@ -31,8 +30,8 @@ trivfs_S_fsys_getroot (struct trivfs_control *cntl,
mach_port_t reply_port,
mach_msg_type_name_t reply_port_type,
mach_port_t dotdot,
- uid_t *uids, u_int nuids,
- uid_t *gids, u_int ngids,
+ uid_t *uids, size_t nuids,
+ uid_t *gids, size_t ngids,
int flags,
retry_type *do_retry,
char *retry_name,
@@ -43,16 +42,28 @@ trivfs_S_fsys_getroot (struct trivfs_control *cntl,
error_t err = 0;
mach_port_t new_realnode;
struct trivfs_protid *cred;
+ struct iouser *user;
if (!cntl)
return EOPNOTSUPP;
+ if (trivfs_getroot_hook)
+ {
+ err = (*trivfs_getroot_hook) (cntl, reply_port, reply_port_type, dotdot,
+ uids, nuids, gids, ngids, flags,
+ do_retry, retry_name, newpt, newpttype);
+ if (err != EAGAIN)
+ return err;
+ }
+
+ if ((flags & O_WRITE & trivfs_allow_open) != (flags & O_WRITE))
+ return EROFS;
if ((flags & (O_READ|O_WRITE|O_EXEC) & trivfs_allow_open)
!= (flags & (O_READ|O_WRITE|O_EXEC)))
- return EOPNOTSUPP;
+ return EACCES;
/* O_CREAT and O_EXCL are not meaningful here; O_NOLINK and O_NOTRANS
- will only be useful when trivfs supports translators (which it doesn't
+ will only be useful when trivfs supports translators (which it doesn't
now). */
flags &= O_HURD;
flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS);
@@ -62,27 +73,46 @@ trivfs_S_fsys_getroot (struct trivfs_control *cntl,
if (err)
return err;
- file_check_access (new_realnode, &perms);
+ err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids);
+ if (err)
+ return err;
+
+ /* Validate permissions. */
+ if (! trivfs_check_access_hook)
+ file_check_access (new_realnode, &perms);
+ else
+ (*trivfs_check_access_hook) (cntl, user, new_realnode, &perms);
if ((flags & (O_READ|O_WRITE|O_EXEC) & perms)
!= (flags & (O_READ|O_WRITE|O_EXEC)))
err = EACCES;
if (!err && trivfs_check_open_hook)
- err = (*trivfs_check_open_hook) (cntl, uids, nuids, gids, ngids, flags);
+ err = (*trivfs_check_open_hook) (cntl, user, flags);
if (!err)
- err = trivfs_open (cntl, uids, nuids, gids, ngids, flags, new_realnode,
- &cred);
- if (err)
- mach_port_deallocate (mach_task_self (), new_realnode);
+ {
+ if (! trivfs_open_hook)
+ {
+ err = trivfs_open (cntl, user, flags, new_realnode, &cred);
+ if (!err)
+ mach_port_deallocate (mach_task_self (), dotdot);
+ }
+ else
+ err = (*trivfs_open_hook) (cntl, user, dotdot, flags, new_realnode,
+ &cred);
+ }
- if (!err)
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), new_realnode);
+ iohelp_free_iouser (user);
+ }
+ else
{
*do_retry = FS_RETRY_NORMAL;
*retry_name = '\0';
*newpt = ports_get_right (cred);
*newpttype = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (cred);
- mach_port_deallocate (mach_task_self (), dotdot);
}
return err;
diff --git a/libtrivfs/fsys-goaway.c b/libtrivfs/fsys-goaway.c
index 747e9f0e..1ad119b7 100644
--- a/libtrivfs/fsys-goaway.c
+++ b/libtrivfs/fsys-goaway.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994,95,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "fsys_S.h"
kern_return_t
trivfs_S_fsys_goaway (struct trivfs_control *cred,
diff --git a/libtrivfs/fsys-set-options.c b/libtrivfs/fsys-set-options.c
index 507bd442..43890df7 100644
--- a/libtrivfs/fsys-set-options.c
+++ b/libtrivfs/fsys-set-options.c
@@ -1,6 +1,6 @@
/* Set runtime options
- Copyright (C) 1996 Free Software Foundation
+ Copyright (C) 1996,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -9,7 +9,7 @@
the Free Software Foundation; either version 2, or (at your option)
any later version.
- The GNU Hurd is distributed in the hope that it will be useful,
+ The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -21,7 +21,6 @@
#include <hurd/fshelp.h>
#include "priv.h"
-#include "fsys_S.h"
error_t
trivfs_S_fsys_set_options (struct trivfs_control *cntl,
diff --git a/libtrivfs/fsys-stubs.c b/libtrivfs/fsys-stubs.c
index 4457b231..28990759 100644
--- a/libtrivfs/fsys-stubs.c
+++ b/libtrivfs/fsys-stubs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "fsys_S.h"
kern_return_t
trivfs_S_fsys_startup (mach_port_t bootport,
@@ -29,7 +28,7 @@ trivfs_S_fsys_startup (mach_port_t bootport,
int flags,
mach_port_t cntl,
mach_port_t *realnode,
- mach_port_t *realnodetype)
+ mach_msg_type_name_t *realnodetype)
{
return EOPNOTSUPP;
}
@@ -60,11 +59,11 @@ trivfs_S_fsys_getfile (struct trivfs_control *cntl,
mach_port_t reply,
mach_msg_type_name_t replytype,
uid_t *genuids,
- u_int ngenuids,
+ size_t ngenuids,
uid_t *gengids,
- u_int ngengids,
+ size_t ngengids,
char *handle,
- u_int handlesize,
+ size_t handlesize,
mach_port_t *file,
mach_msg_type_name_t *filetype)
{
diff --git a/libtrivfs/fsys-syncfs.c b/libtrivfs/fsys-syncfs.c
index 6059adfd..e94fda38 100644
--- a/libtrivfs/fsys-syncfs.c
+++ b/libtrivfs/fsys-syncfs.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1994,96,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -19,7 +19,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "fsys_S.h"
kern_return_t
trivfs_S_fsys_syncfs (struct trivfs_control *cntl,
diff --git a/libtrivfs/handle-port.c b/libtrivfs/handle-port.c
deleted file mode 100644
index 9568b88a..00000000
--- a/libtrivfs/handle-port.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
-
- 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. */
-
-#include "priv.h"
-
-/* Backwards compatibility. Use trivfs_create_control. */
-mach_port_t
-trivfs_handle_port (mach_port_t realnode,
- struct port_class *control_class,
- struct port_bucket *control_bucket,
- struct port_class *protid_class,
- struct port_bucket *protid_bucket)
-{
- mach_port_t right;
- struct trivfs_control *control;
- error_t err =
- trivfs_create_control (realnode,
- control_class, control_bucket,
- protid_class, protid_bucket,
- &control);
-
- if (err)
- return MACH_PORT_NULL;
-
- right = ports_get_right (control);
- ports_port_deref (control);
-
- return right;
-}
-
-#if 0
-#include "linkwarn.h"
-obslete (trivfs_handle_port, trivfs_create_control)
-#endif
diff --git a/libtrivfs/io-async-icky.c b/libtrivfs/io-async-icky.c
index 0f0b99ea..bd9c5490 100644
--- a/libtrivfs/io-async-icky.c
+++ b/libtrivfs/io-async-icky.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,99,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
@@ -30,6 +29,5 @@ trivfs_S_io_get_icky_async_id (struct trivfs_protid *cred,
mach_port_t *id,
mach_msg_type_name_t *idtype)
{
- assert (!trivfs_support_read && !trivfs_support_write);
return EOPNOTSUPP;
}
diff --git a/libtrivfs/io-async.c b/libtrivfs/io-async.c
index 0a2646a3..b02f57f6 100644
--- a/libtrivfs/io-async.c
+++ b/libtrivfs/io-async.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,99,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
@@ -31,6 +30,5 @@ trivfs_S_io_async (struct trivfs_protid *cred,
mach_port_t *id,
mach_msg_type_name_t *idtype)
{
- assert (!trivfs_support_read && !trivfs_support_write);
return EOPNOTSUPP;
}
diff --git a/libtrivfs/io-duplicate.c b/libtrivfs/io-duplicate.c
index 4b20bb99..c1b7798d 100644
--- a/libtrivfs/io-duplicate.c
+++ b/libtrivfs/io-duplicate.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1993,94,95,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <string.h>
kern_return_t
@@ -32,10 +31,10 @@ trivfs_S_io_duplicate (struct trivfs_protid *cred,
{
error_t err;
struct trivfs_protid *newcred;
-
+
if (!cred)
return EOPNOTSUPP;
-
+
err = trivfs_protid_dup (cred, &newcred);
if (!err)
{
@@ -46,4 +45,3 @@ trivfs_S_io_duplicate (struct trivfs_protid *cred,
return err;
}
-
diff --git a/libtrivfs/io-identity.c b/libtrivfs/io-identity.c
index 1232dcb4..44f60d38 100644
--- a/libtrivfs/io-identity.c
+++ b/libtrivfs/io-identity.c
@@ -1,5 +1,5 @@
-/* Fetching identity port
- Copyright (C) 1996 Free Software Foundation, Inc.
+/* Fetching identity port
+ Copyright (C) 1996,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -19,7 +19,6 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "priv.h"
-#include "io_S.h"
error_t
trivfs_S_io_identity (struct trivfs_protid *cred,
@@ -29,14 +28,14 @@ trivfs_S_io_identity (struct trivfs_protid *cred,
mach_msg_type_name_t *idport_type,
mach_port_t *fsidport,
mach_msg_type_name_t *fsidport_type,
- int *fileno)
+ ino_t *fileno)
{
error_t err;
struct stat st;
-
+
if (!cred)
return EOPNOTSUPP;
-
+
err = io_stat (cred->realnode, &st);
if (err)
return err;
diff --git a/libtrivfs/io-map.c b/libtrivfs/io-map.c
index f94bf8a5..2959efba 100644
--- a/libtrivfs/io-map.c
+++ b/libtrivfs/io-map.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,2002 Free Software Foundation
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
@@ -32,6 +31,5 @@ trivfs_S_io_map (struct trivfs_protid *cred,
mach_port_t *wrobj,
mach_msg_type_name_t *wrtype)
{
- assert (!trivfs_support_read && !trivfs_support_write);
return EOPNOTSUPP;
}
diff --git a/libtrivfs/io-modes-get.c b/libtrivfs/io-modes-get.c
index 025ed782..4d38d3a6 100644
--- a/libtrivfs/io-modes-get.c
+++ b/libtrivfs/io-modes-get.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,99,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
@@ -29,7 +28,6 @@ trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
mach_msg_type_name_t replytype,
int *bits)
{
- assert (!trivfs_support_read && !trivfs_support_write);
if (!cred)
return EOPNOTSUPP;
else
@@ -38,5 +36,3 @@ trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
return 0;
}
}
-
-
diff --git a/libtrivfs/io-modes-off.c b/libtrivfs/io-modes-off.c
index c78791e9..33b0a573 100644
--- a/libtrivfs/io-modes-off.c
+++ b/libtrivfs/io-modes-off.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
diff --git a/libtrivfs/io-modes-on.c b/libtrivfs/io-modes-on.c
index 8ca82bcf..7886dc50 100644
--- a/libtrivfs/io-modes-on.c
+++ b/libtrivfs/io-modes-on.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
diff --git a/libtrivfs/io-owner-get.c b/libtrivfs/io-owner-get.c
index d91cd4cc..f6c261c7 100644
--- a/libtrivfs/io-owner-get.c
+++ b/libtrivfs/io-owner-get.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
@@ -29,6 +28,5 @@ trivfs_S_io_get_owner (struct trivfs_protid *cred,
mach_msg_type_name_t replytype,
pid_t *owner)
{
- assert (!trivfs_support_read && !trivfs_support_write);
return EOPNOTSUPP;
}
diff --git a/libtrivfs/io-owner-mod.c b/libtrivfs/io-owner-mod.c
index e499776e..4e96a245 100644
--- a/libtrivfs/io-owner-mod.c
+++ b/libtrivfs/io-owner-mod.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
@@ -29,6 +28,5 @@ trivfs_S_io_mod_owner (struct trivfs_protid *cred,
mach_msg_type_name_t replytype,
pid_t owner)
{
- assert (!trivfs_support_read && !trivfs_support_write);
return EOPNOTSUPP;
}
diff --git a/libtrivfs/io-pathconf.c b/libtrivfs/io-pathconf.c
index 658e249c..51d4e094 100644
--- a/libtrivfs/io-pathconf.c
+++ b/libtrivfs/io-pathconf.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,96,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "io_S.h"
kern_return_t
trivfs_S_io_pathconf (struct trivfs_protid *cred,
@@ -24,10 +23,7 @@ trivfs_S_io_pathconf (struct trivfs_protid *cred,
int name, int *val)
{
if (cred)
- {
- *val = 0;
- return 0;
- }
+ return io_pathconf (cred->realnode, name, val);
else
return EOPNOTSUPP;
}
diff --git a/libtrivfs/io-read.c b/libtrivfs/io-read.c
index 24f3642a..dcba818b 100644
--- a/libtrivfs/io-read.c
+++ b/libtrivfs/io-read.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
@@ -30,4 +29,4 @@ trivfs_S_io_read (struct trivfs_protid *cred,
{
assert (!trivfs_support_read);
return EOPNOTSUPP;
-}
+}
diff --git a/libtrivfs/io-readable.c b/libtrivfs/io-readable.c
index 975ab44b..792bd1a7 100644
--- a/libtrivfs/io-readable.c
+++ b/libtrivfs/io-readable.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
diff --git a/libtrivfs/io-reauthenticate.c b/libtrivfs/io-reauthenticate.c
index e199642b..80ef31c1 100644
--- a/libtrivfs/io-reauthenticate.c
+++ b/libtrivfs/io-reauthenticate.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993,94,95,96,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
#include <string.h>
@@ -31,85 +30,49 @@ trivfs_S_io_reauthenticate (struct trivfs_protid *cred,
mach_port_t rendport)
{
struct trivfs_protid *newcred;
- uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
- uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
- u_int genuidlen, gengidlen, auxuidlen, auxgidlen;
error_t err;
- int i;
auth_t auth;
mach_port_t newright;
if (cred == 0)
return EOPNOTSUPP;
- genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
- gen_uids = gubuf;
- gen_gids = ggbuf;
- aux_uids = aubuf;
- aux_gids = agbuf;
-
do
err = ports_create_port_noinstall (cred->po->cntl->protid_class,
cred->po->cntl->protid_bucket,
- sizeof (struct trivfs_protid),
+ sizeof (struct trivfs_protid),
&newcred);
while (err == EINTR);
if (err)
return err;
auth = getauth ();
- newright = ports_get_right (newcred);
- err = mach_port_insert_right (mach_task_self (), newright, newright,
- MACH_MSG_TYPE_MAKE_SEND);
- assert_perror (err);
- do
- err = auth_server_authenticate (auth,
- rendport,
- MACH_MSG_TYPE_COPY_SEND,
- newright,
- MACH_MSG_TYPE_COPY_SEND,
- &gen_uids, &genuidlen,
- &aux_uids, &auxuidlen,
- &gen_gids, &gengidlen,
- &aux_gids, &auxgidlen);
- while (err == EINTR);
+ newright = ports_get_send_right (newcred);
+ assert (newright != MACH_PORT_NULL);
+
+ err = iohelp_reauth (&newcred->user, auth, rendport, newright, 1);
mach_port_deallocate (mach_task_self (), rendport);
- mach_port_deallocate (mach_task_self (), newright);
mach_port_deallocate (mach_task_self (), auth);
-
if (err)
- {
- newcred->isroot = 0;
- newcred->uids = malloc (1);
- newcred->gids = malloc (1);
- newcred->nuids = 0;
- newcred->ngids = 0;
- }
- else
- {
- newcred->isroot = 0;
- for (i = 0; i < genuidlen; i++)
- if (gen_uids[i] == 0)
- newcred->isroot = 1;
-
- newcred->uids = malloc (genuidlen * sizeof (uid_t));
- newcred->gids = malloc (gengidlen * sizeof (uid_t));
- bcopy (gen_uids, newcred->uids, genuidlen * sizeof (uid_t));
- bcopy (gen_gids, newcred->gids, gengidlen * sizeof (uid_t));
- newcred->nuids = genuidlen;
- newcred->ngids = gengidlen;
- }
-
+ return err;
+
+ mach_port_deallocate (mach_task_self (), newright);
+ if (idvec_contains (newcred->user->uids, 0))
+ newcred->isroot = 1;
+
newcred->hook = cred->hook;
-
+
mutex_lock (&cred->po->cntl->lock);
newcred->po = cred->po;
newcred->po->refcnt++;
mutex_unlock (&cred->po->cntl->lock);
-
+
do
err = io_restrict_auth (newcred->po->cntl->underlying, &newcred->realnode,
- gen_uids, genuidlen, gen_gids, gengidlen);
+ newcred->user->uids->ids,
+ newcred->user->uids->num,
+ newcred->user->gids->ids,
+ newcred->user->gids->num);
while (err == EINTR);
if (!err && trivfs_protid_create_hook)
{
@@ -127,19 +90,6 @@ trivfs_S_io_reauthenticate (struct trivfs_protid *cred,
mach_port_move_member (mach_task_self (), newcred->pi.port_right,
cred->po->cntl->protid_bucket->portset);
- if (gubuf != gen_uids)
- vm_deallocate (mach_task_self (), (u_int) gen_uids,
- genuidlen * sizeof (uid_t));
- if (ggbuf != gen_gids)
- vm_deallocate (mach_task_self (), (u_int) gen_gids,
- gengidlen * sizeof (uid_t));
- if (aubuf != aux_uids)
- vm_deallocate (mach_task_self (), (u_int) aux_uids,
- auxuidlen * sizeof (uid_t));
- if (agbuf != aux_gids)
- vm_deallocate (mach_task_self (), (u_int) aux_gids,
- auxgidlen * sizeof (uid_t));
-
ports_port_deref (newcred);
return err;
diff --git a/libtrivfs/io-restrict-auth.c b/libtrivfs/io-restrict-auth.c
index ac915896..98a80a13 100644
--- a/libtrivfs/io-restrict-auth.c
+++ b/libtrivfs/io-restrict-auth.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1993,94,95,96,2001,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <string.h>
/* Tell if the array LIST (of size N) contains a member equal to QUERY. */
@@ -40,55 +39,88 @@ trivfs_S_io_restrict_auth (struct trivfs_protid *cred,
mach_msg_type_name_t replytype,
mach_port_t *newport,
mach_msg_type_name_t *newporttype,
- uid_t *uids, u_int nuids,
- uid_t *gids, u_int ngids)
+ uid_t *uids, size_t nuids,
+ uid_t *gids, size_t ngids)
{
int i;
- error_t err = 0;
+ error_t err;
struct trivfs_protid *newcred;
- uid_t *newuids, *newgids;
- int newnuids, newngids;
-
+ struct idvec *uvec, *gvec;
+ struct iouser *user;
+
if (!cred)
return EOPNOTSUPP;
-
- newuids = alloca (sizeof (uid_t) * cred->nuids);
- newgids = alloca (sizeof (uid_t) * cred->ngids);
- for (i = newnuids = 0; i < cred->nuids; i++)
- if (listmember (uids, cred->uids[i], nuids))
- newuids[newnuids++] = cred->uids[i];
- for (i = newngids = 0; i < cred->gids[i]; i++)
- if (listmember (gids, cred->gids[i], ngids))
- newgids[newngids++] = cred->gids[i];
+
+ if (cred->isroot)
+ /* CRED has root access, and so may use any ids. */
+ {
+ err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids);
+ if (err)
+ return err;
+ }
+ else
+ {
+ uvec = make_idvec ();
+ if (! uvec)
+ return ENOMEM;
+
+ gvec = make_idvec ();
+ if (! gvec)
+ {
+ idvec_free (uvec);
+ return ENOMEM;
+ }
+
+ /* Otherwise, use any of the requested ids that CRED already has. */
+ for (i = 0; i < cred->user->uids->num; i++)
+ if (listmember (uids, cred->user->uids->ids[i], nuids))
+ {
+ err = idvec_add (uvec, cred->user->uids->ids[i]);
+ if (err)
+ goto out;
+ }
+
+ for (i = 0; i < cred->user->gids->num; i++)
+ if (listmember (gids, cred->user->gids->ids[i], ngids))
+ {
+ err = idvec_add (gvec, cred->user->gids->ids[i]);
+ if (err)
+ goto out;
+ }
+
+ err = iohelp_create_iouser (&user, uvec, gvec);
+ if (err)
+ {
+ out:
+ idvec_free (uvec);
+ idvec_free (gvec);
+ return err;
+ }
+ }
err = ports_create_port (cred->po->cntl->protid_class,
cred->po->cntl->protid_bucket,
- sizeof (struct trivfs_protid),
+ sizeof (struct trivfs_protid),
&newcred);
if (err)
- return err;
+ {
+ iohelp_free_iouser (user);
+ return err;
+ }
newcred->isroot = 0;
mutex_lock (&cred->po->cntl->lock);
newcred->po = cred->po;
newcred->po->refcnt++;
mutex_unlock (&cred->po->cntl->lock);
- if (cred->isroot)
- {
- for (i = 0; i < nuids; i++)
- if (uids[i] == 0)
- newcred->isroot = 1;
- }
- newcred->gids = malloc (newngids * sizeof (uid_t));
- newcred->uids = malloc (newnuids * sizeof (uid_t));
- bcopy (newuids, newcred->uids, newnuids * sizeof (uid_t));
- bcopy (newgids, newcred->gids, newngids * sizeof (uid_t));
- newcred->ngids = newngids;
- newcred->nuids = newnuids;
+ if (cred->isroot && idvec_contains (user->uids, 0))
+ newcred->isroot = 1;
+ newcred->user = user;
newcred->hook = cred->hook;
- err = io_restrict_auth (cred->realnode, &newcred->realnode,
- newuids, newnuids, newgids, newngids);
+ err = io_restrict_auth (cred->realnode, &newcred->realnode,
+ user->uids->ids, user->uids->num,
+ user->gids->ids, user->gids->num);
if (!err && trivfs_protid_create_hook)
{
err = (*trivfs_protid_create_hook) (newcred);
diff --git a/libtrivfs/file-inv.c b/libtrivfs/io-revoke.c
index 37f85660..901de4c6 100644
--- a/libtrivfs/file-inv.c
+++ b/libtrivfs/io-revoke.c
@@ -1,5 +1,6 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1999,2002 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, BSG.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -15,18 +16,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* Unused stub */
-
#include "priv.h"
-#include "fs_S.h"
+/* Implement io_revoke as described in <hurd/io.defs>. */
kern_return_t
-trivfs_S_file_invoke_translator (struct trivfs_protid *cred,
- int flags,
- retry_type *retry,
- char *retry_name,
- mach_port_t *retrypt,
- mach_msg_type_name_t *type)
+trivfs_S_io_revoke (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type)
{
- return EOPNOTSUPP;
+ /* Revoke of the underlying node is actually generally right,
+ because that will cause actual calls to fail. In any case,
+ we don't have the ability to check permissions ourselves
+ correctly. */
+
+ return cred ? io_revoke (cred->realnode) : EOPNOTSUPP;
}
diff --git a/libtrivfs/io-seek.c b/libtrivfs/io-seek.c
index 8d810786..8e794cf1 100644
--- a/libtrivfs/io-seek.c
+++ b/libtrivfs/io-seek.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -16,7 +16,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
diff --git a/libtrivfs/io-select.c b/libtrivfs/io-select.c
index 7788da6e..9df24d61 100644
--- a/libtrivfs/io-select.c
+++ b/libtrivfs/io-select.c
@@ -1,5 +1,5 @@
/* Stub io_select RPC for trivfs library.
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1993,94,95,96,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
kern_return_t
diff --git a/libtrivfs/io-stat.c b/libtrivfs/io-stat.c
index aba8540a..6e430a22 100644
--- a/libtrivfs/io-stat.c
+++ b/libtrivfs/io-stat.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,96,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
#include <unistd.h>
kern_return_t
@@ -37,15 +36,15 @@ trivfs_S_io_stat (struct trivfs_protid *cred,
if (!err)
{
- if (!trivfs_fsid)
+ if (! trivfs_fsid)
trivfs_fsid = getpid();
st->st_fstype = trivfs_fstype;
st->st_fsid = trivfs_fsid;
+ st->st_mode = (st->st_mode & ~S_IFMT & ~S_ITRANS) | S_IFCHR | S_IROOT;
trivfs_modify_stat (cred, st);
}
return err;
}
-
diff --git a/libtrivfs/io-stubs.c b/libtrivfs/io-stubs.c
index 2c4f7330..a8cf3f57 100644
--- a/libtrivfs/io-stubs.c
+++ b/libtrivfs/io-stubs.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1993, 1994 Free Software Foundation
+ Copyright (C) 1993,94,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -20,7 +20,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include "priv.h"
-#include "io_S.h"
kern_return_t
trivfs_S_io_map_cntl (struct trivfs_protid *cred,
@@ -48,7 +47,7 @@ trivfs_S_io_release_conch (struct trivfs_protid *cred,
return EOPNOTSUPP;
}
-kern_return_t
+kern_return_t
trivfs_S_io_eofnotify (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype)
@@ -57,20 +56,20 @@ trivfs_S_io_eofnotify (struct trivfs_protid *cred,
}
kern_return_t
-trivfs_S_io_prenotify (struct trivfs_protid *cred,
+trivfs_S_io_prenotify (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
- vm_offset_t start,
+ vm_offset_t start,
vm_offset_t end)
{
return EOPNOTSUPP;
}
kern_return_t
-trivfs_S_io_postnotify (struct trivfs_protid *cred,
+trivfs_S_io_postnotify (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
- vm_offset_t start,
+ vm_offset_t start,
vm_offset_t end)
{
return EOPNOTSUPP;
diff --git a/libtrivfs/io-version.c b/libtrivfs/io-version.c
index 3df9a0d3..ff820db9 100644
--- a/libtrivfs/io-version.c
+++ b/libtrivfs/io-version.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,2002 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
@@ -17,8 +17,8 @@
#include "priv.h"
-kern_return_t
-trivfs_S_io_server_version (mach_port_t obj,
+kern_return_t
+trivfs_S_io_server_version (trivfs_protid_t obj,
mach_port_t reply,
mach_msg_type_name_t replytype,
char *name,
diff --git a/libtrivfs/io-write.c b/libtrivfs/io-write.c
index 05b57fde..106031dd 100644
--- a/libtrivfs/io-write.c
+++ b/libtrivfs/io-write.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994,99,2002 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
@@ -16,8 +16,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "priv.h"
-#include "io_S.h"
#include <assert.h>
+#include <fcntl.h>
kern_return_t
trivfs_S_io_write (struct trivfs_protid *cred,
@@ -28,6 +28,9 @@ trivfs_S_io_write (struct trivfs_protid *cred,
off_t off,
mach_msg_type_number_t *amt)
{
+ if (!(trivfs_allow_open & O_WRITE))
+ return EBADF;
+
assert (!trivfs_support_write);
return EOPNOTSUPP;
}
diff --git a/libtrivfs/migsupport.c b/libtrivfs/migsupport.c
index 14e28231..b2d98e16 100644
--- a/libtrivfs/migsupport.c
+++ b/libtrivfs/migsupport.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -20,45 +20,67 @@
struct trivfs_protid *
trivfs_begin_using_protid (mach_port_t port)
{
- if (trivfs_protid_nportclasses > 1)
+ if (trivfs_protid_nportclasses + trivfs_num_dynamic_protid_port_classes > 1)
{
struct port_info *pi = ports_lookup_port (0, port, 0);
int i;
- for (i = 0; i < trivfs_protid_nportclasses; i++)
- if (pi->class == trivfs_protid_portclasses[i])
- return (struct trivfs_protid *) pi;
- ports_port_deref ((void *)port);
+
+ if (pi)
+ {
+ for (i = 0; i < trivfs_protid_nportclasses; i++)
+ if (pi->class == trivfs_protid_portclasses[i])
+ return (struct trivfs_protid *) pi;
+ for (i = 0; i < trivfs_num_dynamic_protid_port_classes; i++)
+ if (pi->class == trivfs_dynamic_protid_port_classes[i])
+ return (struct trivfs_protid *) pi;
+ ports_port_deref (pi);
+ }
+
return 0;
}
- else
+ else if (trivfs_protid_nportclasses == 1)
return ports_lookup_port (0, port, trivfs_protid_portclasses[0]);
+ else
+ return ports_lookup_port (0, port, trivfs_dynamic_protid_port_classes[0]);
}
void
trivfs_end_using_protid (struct trivfs_protid *cred)
{
- ports_port_deref (cred);
+ if (cred)
+ ports_port_deref (cred);
}
struct trivfs_control *
trivfs_begin_using_control (mach_port_t port)
{
- if (trivfs_cntl_nportclasses > 1)
+ if (trivfs_cntl_nportclasses + trivfs_num_dynamic_control_port_classes > 1)
{
struct port_info *pi = ports_lookup_port (0, port, 0);
int i;
- for (i = 0; i < trivfs_cntl_nportclasses; i++)
- if (pi->class == trivfs_cntl_portclasses[i])
- return (struct trivfs_control *) pi;
- ports_port_deref ((void *)port);
+
+ if (pi)
+ {
+ for (i = 0; i < trivfs_cntl_nportclasses; i++)
+ if (pi->class == trivfs_cntl_portclasses[i])
+ return (struct trivfs_control *) pi;
+ for (i = 0; i < trivfs_num_dynamic_control_port_classes; i++)
+ if (pi->class == trivfs_dynamic_control_port_classes[i])
+ return (struct trivfs_control *) pi;
+ ports_port_deref (pi);
+ }
+
return 0;
}
- else
+ else if (trivfs_cntl_nportclasses == 1)
return ports_lookup_port (0, port, trivfs_cntl_portclasses[0]);
+ else
+ return ports_lookup_port (0, port, trivfs_dynamic_control_port_classes[0]);
}
void
trivfs_end_using_control (struct trivfs_control *cred)
{
- ports_port_deref (cred);
+ if (cred)
+ ports_port_deref (cred);
}
diff --git a/libtrivfs/nosenders.c b/libtrivfs/nosenders.c
deleted file mode 100644
index 2b4abef6..00000000
--- a/libtrivfs/nosenders.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright (C) 1993, 1994, 1995 Free Software Foundation
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Written by Michael I. Bushnell. */
-
-#include "priv.h"
-#include "notify_S.h"
-
-/* Called by the kernel when a port has no more senders. We arrange
- to have this sent to the port which is out of senders (NOTIFY). MSCOUNT
- is the make-send count of the port when the notification was generated. */
-kern_return_t
-trivfs_do_mach_notify_no_senders (mach_port_t notify,
- mach_port_mscount_t mscount)
-{
- struct port_info *pt;
-
- pt = ports_lookup_port (0, notify, 0);
- if (!pt)
- return EOPNOTSUPP;
-
- ports_no_senders (pt, mscount);
-
- ports_port_deref (pt);
-
- return 0;
-}
diff --git a/libtrivfs/notify-stubs.c b/libtrivfs/notify-stubs.c
deleted file mode 100644
index 448984a4..00000000
--- a/libtrivfs/notify-stubs.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- Copyright (C) 1994 Free Software Foundation
-
- 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. */
-
-#include "priv.h"
-#include "notify_S.h"
-
-kern_return_t
-trivfs_do_mach_notify_port_deleted (mach_port_t notify,
- mach_port_t name)
-{
- return 0;
-}
-
-kern_return_t
-trivfs_do_mach_notify_msg_accepted (mach_port_t notify,
- mach_port_t name)
-{
- return 0;
-}
-
-kern_return_t
-trivfs_do_mach_notify_port_destroyed (mach_port_t notify,
- mach_port_t name)
-{
- return 0;
-}
-
-kern_return_t
-trivfs_do_mach_notify_send_once (mach_port_t notify)
-{
- return 0;
-}
-
-kern_return_t
-trivfs_do_mach_notify_dead_name (mach_port_t notify,
- mach_port_t name)
-{
- return 0;
-}
diff --git a/libtrivfs/open.c b/libtrivfs/open.c
index 4303ca74..f64d2ffd 100644
--- a/libtrivfs/open.c
+++ b/libtrivfs/open.c
@@ -1,6 +1,6 @@
/* Make a new trivfs peropen/protid
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1994, 1995, 1996, 1999 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -27,7 +27,7 @@
FLAGS. CNTL is the trivfs control object. */
error_t
trivfs_open (struct trivfs_control *cntl,
- uid_t *uids, unsigned num_uids, gid_t *gids, unsigned num_gids,
+ struct iouser *user,
unsigned flags,
mach_port_t realnode,
struct trivfs_protid **cred)
@@ -55,20 +55,8 @@ trivfs_open (struct trivfs_control *cntl,
sizeof (struct trivfs_protid), &new);
if (! err)
{
- int i;
-
- new->isroot = 0;
- for (i = 0; i < num_uids; i++)
- if (uids[i] == 0)
- new->isroot = 1;
-
- new->uids = malloc (num_uids * sizeof (uid_t));
- bcopy (uids, new->uids, num_uids * sizeof (uid_t));
- new->nuids = num_uids;
-
- new->gids = malloc (num_gids * sizeof (uid_t));
- bcopy (gids, new->gids, num_gids * sizeof (uid_t));
- new->ngids = num_gids;
+ new->user = user;
+ new->isroot = idvec_contains (user->uids, 0);
new->po = po;
new->hook = 0;
diff --git a/libtrivfs/priv.h b/libtrivfs/priv.h
index e75e3644..d92fe336 100644
--- a/libtrivfs/priv.h
+++ b/libtrivfs/priv.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/*
+ Copyright (C) 1994, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -16,21 +16,11 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef TRIVFS_PRIV_H_INCLUDED
+#define TRIVFS_PRIV_H_INCLUDED
#include <mach.h>
#include <hurd.h>
#include <hurd/ports.h>
#include "trivfs.h"
-/* For the sake of MiG. */
-typedef struct trivfs_protid *trivfs_protid_t;
-typedef struct trivfs_control *trivfs_control_t;
-
-struct trivfs_protid *_trivfs_begin_using_protid (mach_port_t);
-void _trivfs_end_using_protid (struct trivfs_protid *);
-struct trivfs_control *_trivfs_begin_using_control (mach_port_t);
-void _trivfs_end_using_control (struct trivfs_control *);
-
-#define TRIVFS_PRIV_H_INCLUDED
#endif
-
diff --git a/libdiskfs/ports-noports.c b/libtrivfs/protid-classes.c
index cddd8f00..204548d8 100644
--- a/libdiskfs/ports-noports.c
+++ b/libtrivfs/protid-classes.c
@@ -1,5 +1,6 @@
-/*
- Copyright (C) 1994 Free Software Foundation
+/* Defaults for TRIVFS_PROTID_[N]PORTCLASSES
+
+ Copyright (C) 1997 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
@@ -15,13 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include "trivfs.h"
-#include "priv.h"
-
-/* Called by ports library when there are no ports outstanding. */
-void
-ports_no_live_ports ()
-{
- diskfs_sync_everything (1);
- exit (0);
-}
+struct port_class *trivfs_protid_portclasses[1];
+int trivfs_protid_nportclasses;
diff --git a/libtrivfs/protid-clean.c b/libtrivfs/protid-clean.c
index b986fca0..b76b202e 100644
--- a/libtrivfs/protid-clean.c
+++ b/libtrivfs/protid-clean.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -44,8 +44,7 @@ trivfs_clean_protid (void *arg)
}
mutex_unlock (&cred->po->cntl->lock);
- free (cred->uids);
- free (cred->gids);
+ iohelp_free_iouser (cred->user);
if (cred->realnode != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self (), cred->realnode);
diff --git a/libtrivfs/protid-dup.c b/libtrivfs/protid-dup.c
index 0aa62dbf..855cd062 100644
--- a/libtrivfs/protid-dup.c
+++ b/libtrivfs/protid-dup.c
@@ -1,6 +1,6 @@
/* Duplicate a protid
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993,94,95,96,2001 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -42,13 +42,12 @@ trivfs_protid_dup (struct trivfs_protid *cred, struct trivfs_protid **dup)
new->isroot = cred->isroot;
- new->uids = malloc (cred->nuids * sizeof (uid_t));
- bcopy (cred->uids, new->uids, cred->nuids * sizeof (uid_t));
- new->nuids = cred->nuids;
-
- new->gids = malloc (cred->ngids * sizeof (gid_t));
- bcopy (cred->gids, new->gids, cred->ngids * sizeof (uid_t));
- new->ngids = cred->ngids;
+ err = iohelp_dup_iouser (&new->user, cred->user);
+ if (err)
+ {
+ ports_port_deref (new);
+ return err;
+ }
new->realnode = cred->realnode;
mach_port_mod_refs (mach_task_self (), new->realnode,
diff --git a/libtrivfs/startup.c b/libtrivfs/startup.c
index 3783efc2..86b0f827 100644
--- a/libtrivfs/startup.c
+++ b/libtrivfs/startup.c
@@ -1,6 +1,6 @@
/* Contact parent filesystem and establish ourselves as the translator.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2000 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -49,11 +49,12 @@ trivfs_startup(mach_port_t bootstrap, int flags,
if (err)
return err;
- right = ports_get_right (fsys);
+ right = ports_get_send_right (fsys);
/* Contact whoever started us. */
- err = fsys_startup (bootstrap, flags, right, MACH_MSG_TYPE_MAKE_SEND,
+ err = fsys_startup (bootstrap, flags, right, MACH_MSG_TYPE_COPY_SEND,
&underlying);
+ mach_port_deallocate (mach_task_self (), right);
if (! err)
fsys->underlying = underlying;
diff --git a/libtrivfs/times.c b/libtrivfs/times.c
index 2c527612..d2fcc589 100644
--- a/libtrivfs/times.c
+++ b/libtrivfs/times.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 1999, 2007 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,9 +25,9 @@ trivfs_set_atime (struct trivfs_control *cntl)
time_value_t mtime;
io_stat (cntl->underlying, &st);
- mtime.seconds = st.st_mtime;
- mtime.microseconds = st.st_mtime_usec;
- host_get_time (mach_host_self (), &atime);
+ mtime.seconds = st.st_mtim.tv_sec;
+ mtime.microseconds = st.st_mtim.tv_nsec / 1000;
+ atime.microseconds = -1;
file_utimes (cntl->underlying, atime, mtime);
return 0;
}
@@ -40,9 +40,9 @@ trivfs_set_mtime (struct trivfs_control *cntl)
time_value_t mtime;
io_stat (cntl->underlying, &st);
- atime.seconds = st.st_atime;
- atime.microseconds = st.st_atime_usec;
- host_get_time (mach_host_self (), &mtime);
+ atime.seconds = st.st_atim.tv_sec;
+ atime.microseconds = st.st_atim.tv_nsec / 1000;
+ mtime.microseconds = -1;
file_utimes (cntl->underlying, atime, mtime);
return 0;
}
diff --git a/libtrivfs/trivfs.h b/libtrivfs/trivfs.h
index 4274226f..798e0b38 100644
--- a/libtrivfs/trivfs.h
+++ b/libtrivfs/trivfs.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/*
+ Copyright (C) 1994,95,96,97,99,2002 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
@@ -23,12 +23,12 @@
#include <sys/types.h> /* for uid_t &c */
#include <mach/mach.h>
#include <hurd/ports.h>
+#include <hurd/iohelp.h>
struct trivfs_protid
{
struct port_info pi;
- uid_t *uids, *gids;
- int nuids, ngids;
+ struct iouser *user;
int isroot;
/* REALNODE will be null if this protid wasn't fully created (currently
only in the case where trivfs_protid_create_hook returns an error). */
@@ -72,7 +72,7 @@ void trivfs_end_using_control (struct trivfs_control *);
extern int trivfs_fstype;
extern int trivfs_fsid;
-/* Set these if trivfs should allow read, write,
+/* Set these if trivfs should allow read, write,
or execute of file. */
extern int trivfs_support_read;
extern int trivfs_support_write;
@@ -84,27 +84,47 @@ extern int trivfs_support_exec;
operations.) */
extern int trivfs_allow_open;
+/* If the user defines these, they should be vectors (and the associated
+ sizes) of port classes that will be translated into control & protid
+ pointers for passing to rpcs, in addition to those passed to or created by
+ trivfs_create_control (or trivfs_startup) will automatically be
+ recognized. */
extern struct port_class *trivfs_protid_portclasses[];
extern int trivfs_protid_nportclasses;
extern struct port_class *trivfs_cntl_portclasses[];
extern int trivfs_cntl_nportclasses;
-/* The user must define this function. This should modify a struct
+/* The user must define this function. This should modify a struct
stat (as returned from the underlying node) for presentation to
- callers of io_stat. It is permissable for this function to do
+ callers of io_stat. It is permissible for this function to do
nothing. */
-void trivfs_modify_stat (struct trivfs_protid *cred, struct stat *);
+void trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t *);
+
+/* If this variable is set, it is called to find out what access this
+ file permits to USER instead of checking the underlying node.
+ REALNODE is the underlying node, and CNTL is the trivfs control
+ object. The access permissions are returned in ALLOWED. */
+error_t (*trivfs_check_access_hook) (struct trivfs_control *cntl,
+ struct iouser *user,
+ mach_port_t realnode,
+ int *allowed);
/* If this variable is set, it is called every time an open happens.
- UIDS, GIDS, and FLAGS are from the open; CNTL identifies the
+ USER and FLAGS are from the open; CNTL identifies the
node being opened. This call need not check permissions on the underlying
node. This call can block as necessary, unless O_NONBLOCK is set
in FLAGS. Any desired error can be returned, which will be reflected
to the user and prevent the open from succeeding. */
error_t (*trivfs_check_open_hook) (struct trivfs_control *cntl,
- uid_t *uids, u_int nuids,
- gid_t *gids, u_int ngids,
- int flags);
+ struct iouser *user, int flags);
+
+/* If this variable is set, it is called in place of `trivfs_open' (below). */
+error_t (*trivfs_open_hook) (struct trivfs_control *fsys,
+ struct iouser *user,
+ mach_port_t dotdot,
+ int flags,
+ mach_port_t realnode,
+ struct trivfs_protid **cred);
/* If this variable is set, it is called every time a new protid
structure is created and initialized. */
@@ -122,13 +142,27 @@ void (*trivfs_protid_destroy_hook) (struct trivfs_protid *);
is about to be destroyed. */
void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *);
+/* If this variable is set, it is called by trivfs_S_fsys_getroot before any
+ other processing takes place; if the return value is EAGAIN, normal trivfs
+ getroot processing continues, otherwise the rpc returns with that return
+ value. */
+error_t (*trivfs_getroot_hook) (struct trivfs_control *cntl,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type);
+
/* Creates a control port for this filesystem and sends it to BOOTSTRAP with
fsys_startup. CONTROL_CLASS & CONTROL_BUCKET are passed to the ports
library to create the control port, and PROTID_CLASS & PROTID_BUCKET are
- used when creating ports representing opens of this node. If CONTROL
- isn't NULL, the trivfs control port is return in it. If any error occurs
- sending fsys_startup, it is returned, otherwise 0. FLAGS specifies how to
- open the underlying node (O_*). */
+ used when creating ports representing opens of this node; any of these may
+ be zero, in which case an appropriate port class/bucket is created. If
+ CONTROL isn't NULL, the trivfs control port is return in it. If any error
+ occurs sending fsys_startup, it is returned, otherwise 0. FLAGS specifies
+ how to open the underlying node (O_*). */
error_t trivfs_startup (mach_port_t bootstrap, int flags,
struct port_class *control_class,
struct port_bucket *control_bucket,
@@ -140,7 +174,8 @@ error_t trivfs_startup (mach_port_t bootstrap, int flags,
return it in CONTROL. CONTROL_CLASS & CONTROL_BUCKET are passed to
the ports library to create the control port, and PROTID_CLASS &
PROTID_BUCKET are used when creating ports representing opens of this
- node. */
+ node; any of these may be zero, in which case an appropriate port
+ class/bucket is created. */
error_t
trivfs_create_control (mach_port_t underlying,
struct port_class *control_class,
@@ -161,8 +196,7 @@ int trivfs_demuxer (mach_msg_header_t *, mach_msg_header_t *);
the underlying node reference, with the given identity, and open flags in
FLAGS. CNTL is the trivfs control object. */
error_t trivfs_open (struct trivfs_control *fsys,
- uid_t *uids, unsigned num_uids,
- gid_t *gids, unsigned num_gids,
+ struct iouser *user,
unsigned flags,
mach_port_t realnode,
struct trivfs_protid **cred);
@@ -194,10 +228,73 @@ extern struct argp *trivfs_runtime_argp;
error_t trivfs_set_options (struct trivfs_control *fsys,
char *argz, size_t argz_len);
-/* Return runtime options for FSYS in ARGZ & ARGZ_LEN. ARGZ should be
- allocated with malloc. The default definition for this routine returns
- EOPNOTSUPP. */
-error_t trivfs_get_options (struct trivfs_control *fsys,
+/* Append to the malloced string *ARGZ of length *ARGZ_LEN a NUL-separated
+ list of the arguments to this translator. The default definition of this
+ routine simply calls diskfs_append_std_options. */
+error_t trivfs_append_args (struct trivfs_control *fsys,
char **argz, size_t *argz_len);
+
+/* Add the port class *CLASS to the list of control port classes recognized
+ by trivfs; if *CLASS is 0, an attempt is made to allocate a new port
+ class, which is stored in *CLASS. */
+error_t trivfs_add_control_port_class (struct port_class **class);
+
+/* Remove the previously added dynamic control port class CLASS, freeing it
+ if it was allocated by trivfs_add_control_port_class. */
+void trivfs_remove_control_port_class (struct port_class *class);
+
+/* Add the port class *CLASS to the list of protid port classes recognized by
+ trivfs; if *CLASS is 0, an attempt is made to allocate a new port class,
+ which is stored in *CLASS. */
+error_t trivfs_add_protid_port_class (struct port_class **class);
+
+/* Remove the previously added dynamic protid port class CLASS, freeing it
+ if it was allocated by trivfs_add_protid_port_class. */
+void trivfs_remove_protid_port_class (struct port_class *class);
+
+/* Add the port bucket *BUCKET to the list of dynamically allocated port
+ buckets; if *bucket is 0, an attempt is made to allocate a new port
+ bucket, which is then stored in *bucket. */
+error_t trivfs_add_port_bucket (struct port_bucket **bucket);
+
+/* Remove the previously added dynamic port bucket BUCKET, freeing it
+ if it was allocated by trivfs_add_port_bucket. */
+void trivfs_remove_port_bucket (struct port_bucket *bucket);
+
+
+/* This stuff is for the sake of MiG stubs and could be in a private
+ header. But it might be handy for users that override parts of the
+ library. Moreover, since the stub headers will use all the imports we
+ need for the stubs, we couldn't make the stub headers public without
+ making this public too. */
+
+typedef struct trivfs_protid *trivfs_protid_t;
+typedef struct trivfs_control *trivfs_control_t;
+
+struct trivfs_protid *_trivfs_begin_using_protid (mach_port_t);
+void _trivfs_end_using_protid (struct trivfs_protid *);
+struct trivfs_control *_trivfs_begin_using_control (mach_port_t);
+void _trivfs_end_using_control (struct trivfs_control *);
+
+/* Vectors of dynamically allocated port classes/buckets. */
+
+/* Protid port classes. */
+extern struct port_class **trivfs_dynamic_protid_port_classes;
+extern size_t trivfs_num_dynamic_protid_port_classes;
+
+/* Control port classes. */
+extern struct port_class **trivfs_dynamic_control_port_classes;
+extern size_t trivfs_num_dynamic_control_port_classes;
+
+/* Port buckets. */
+extern struct port_bucket **trivfs_dynamic_port_buckets;
+extern size_t trivfs_num_dynamic_port_buckets;
+
+/* These are the MiG-generated headers that declare prototypes
+ for the server functions. */
+#include <hurd/trivfs_fs_S.h>
+#include <hurd/trivfs_io_S.h>
+#include <hurd/trivfs_fsys_S.h>
+
#endif /* __TRIVFS_H__ */
diff --git a/login/ChangeLog b/login/ChangeLog
deleted file mode 100644
index 8bfdb3c1..00000000
--- a/login/ChangeLog
+++ /dev/null
@@ -1,15 +0,0 @@
-Mon Aug 21 16:35:34 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * utmp.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
-
-Sun Apr 23 16:03:48 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * utmp.c (_find_device, add_device, remove_device): Remove the LEN
- parameter and the incorrectly computed value which was shadowing
- it, both of which are the wrong thing anyway.
-
-Tue Apr 11 11:20:21 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: New file.
-
-
diff --git a/login/utmp.c b/login/utmp.c
index 4333fa92..c7c1ac04 100644
--- a/login/utmp.c
+++ b/login/utmp.c
@@ -1,6 +1,6 @@
/* Login record (utmp) server.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -134,7 +134,7 @@ next_device(char *dev)
/* ---------------------------------------------------------------- */
-/* Try and start the translator for CTL_PORT on NODE. If succesful, this
+/* Try and start the translator for CTL_PORT on NODE. If successful, this
call will not return until the translator is stopped; otherwise it returns
an error code describing the reason why it couldn't start. */
static error_t
@@ -163,7 +163,7 @@ start_translator(file_t node, fsys_t ctl_port)
}
/* Find an unoccupied (one with no active translator) filename starting with
- NAME_PFX, and start the translator for CTL_PORT on it. If succesful, this
+ NAME_PFX, and start the translator for CTL_PORT on it. If successful, this
call will not return until the translator is stopped; otherwise it returns
an error code describing the reason why it couldn't start. When
successful, this function sets UTMP_NODE_NAME to the name of the file we
@@ -271,9 +271,9 @@ return_data(char *data, int data_len, char **buf, int *buf_len)
{
if (data_len > *buf_len)
{
- error_t err = vm_allocate(mach_task_self(), buf, data_len, 1);
- if (err)
- return err;
+ *buf = mmap (0, data_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == (char *) -1)
+ return errno;
}
*buf_len = data_len;
@@ -326,12 +326,12 @@ S_login_get_idle_time(file_t utmp, time_value_t *tv)
{
struct stat stat;
if (stat(dev, &state) == 0
- && (stat.st_atime < tv->seconds
- || (stat.st_atime == tv->seconds
- && stat.st_atime_usec < tv->microseconds)))
+ && (stat.st_atim.tv_sec < tv->seconds
+ || (stat.st_atim.tv_sec == tv->seconds
+ && stat.st_atim.tv_nsec / 1000 < tv->microseconds)))
{
- tv->seconds = stat.st_atime;
- tv->microseconds = stat.st_atime_usec;
+ tv->seconds = stat.st_atim.tv_sc;
+ tv->microseconds = stat.st_atim.tv_nsec / 1000;
}
}
}
diff --git a/mach-defpager/Makefile b/mach-defpager/Makefile
new file mode 100644
index 00000000..9a4b7edf
--- /dev/null
+++ b/mach-defpager/Makefile
@@ -0,0 +1,40 @@
+# Makefile for mach-defpager subdirectory of hurd sources
+#
+# Copyright (C) 1999, 2000, 2002, 2007, 2010 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := mach-defpager
+makemode:= server
+target := mach-defpager
+
+SRCS := default_pager.c kalloc.c wiring.c main.c setup.c
+OBJS := $(SRCS:.c=.o) \
+ $(addsuffix Server.o,\
+ memory_object default_pager memory_object_default exc) \
+ default_pager_replyUser.o
+LCLHDRS := file_io.h queue.h wiring.h kalloc.h default_pager.h
+
+HURDLIBS:= threads
+LDFLAGS += -static
+
+include ../Makeconf
+
+MIGSFLAGS = -DSEQNOS
+
+# Don't even bother.
+CFLAGS := $(filter-out -Wall,$(CFLAGS))
diff --git a/mach-defpager/default_pager.c b/mach-defpager/default_pager.c
new file mode 100644
index 00000000..1165feea
--- /dev/null
+++ b/mach-defpager/default_pager.c
@@ -0,0 +1,3918 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Default pager. Pages to paging partition.
+ *
+ * MUST BE ABLE TO ALLOCATE WIRED-DOWN MEMORY!!!
+ */
+
+#include <mach.h>
+#include <mach/message.h>
+#include <mach/notify.h>
+#include <mach/mig_errors.h>
+#include <mach/thread_switch.h>
+#include <mach/task_info.h>
+#include <mach/default_pager_types.h>
+
+#include <cthreads.h>
+
+#include <device/device_types.h>
+#include <device/device.h>
+
+#include <queue.h>
+#include <wiring.h>
+#include <kalloc.h>
+#include <default_pager.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <file_io.h>
+
+#include "default_pager_S.h"
+
+#define debug 0
+
+static char my_name[] = "(default pager):";
+
+static struct mutex printf_lock = MUTEX_INITIALIZER;
+
+#define dprintf(f, x...) \
+ ({ mutex_lock (&printf_lock); printf (f , ##x); fflush (stdout); mutex_unlock (&printf_lock); })
+#define ddprintf(f, x...) ((void)0)
+
+/*
+ * parallel vs serial switch
+ */
+#define PARALLEL 1
+
+#if 0
+#define CHECKSUM 1
+#endif
+
+#define USE_PRECIOUS 1
+
+#define ptoa(p) ((p)*vm_page_size)
+#define atop(a) ((a)/vm_page_size)
+
+/*
+
+ */
+/*
+ * Bitmap allocation.
+ */
+typedef unsigned int bm_entry_t;
+#define NB_BM 32
+#define BM_MASK 0xffffffff
+
+#define howmany(a,b) (((a) + (b) - 1)/(b))
+
+/*
+ * Value to indicate no block assigned
+ */
+#define NO_BLOCK ((vm_offset_t)-1)
+
+/*
+ * 'Partition' structure for each paging area.
+ * Controls allocation of blocks within paging area.
+ */
+struct part {
+ struct mutex p_lock; /* for bitmap/free */
+ vm_size_t total_size; /* total number of blocks */
+ vm_size_t free; /* number of blocks free */
+ unsigned int id; /* named lookup */
+ bm_entry_t *bitmap; /* allocation map */
+ boolean_t going_away; /* destroy attempt in progress */
+ struct file_direct *file; /* file paged to */
+};
+typedef struct part *partition_t;
+
+struct {
+ struct mutex lock;
+ int n_partitions;
+ partition_t *partition_list;/* array, for quick mapping */
+} all_partitions; /* list of all such */
+
+typedef unsigned char p_index_t;
+
+#define P_INDEX_INVALID ((p_index_t)-1)
+
+#define no_partition(x) ((x) == P_INDEX_INVALID)
+
+partition_t partition_of(x)
+ int x;
+{
+ if (x >= all_partitions.n_partitions || x < 0)
+ panic("partition_of x%x", x);
+ return all_partitions.partition_list[x];
+}
+
+void set_partition_of(x, p)
+ int x;
+ partition_t p;
+{
+ if (x >= all_partitions.n_partitions || x < 0)
+ panic("set_partition_of x%x", x);
+ all_partitions.partition_list[x] = p;
+}
+
+/*
+ * Simple mapping from (file)NAME to id
+ * Saves space, filenames can be long.
+ */
+unsigned int
+part_id(const char *name)
+{
+ register unsigned int id, xorid;
+ size_t len;
+
+ len = strlen(name);
+ id = xorid = 0;
+ while (len--) {
+ xorid ^= *name;
+ id += *name++;
+ }
+ return (id << 8) | xorid;
+}
+
+void
+partition_init()
+{
+ mutex_init(&all_partitions.lock);
+ all_partitions.n_partitions = 0;
+}
+
+static partition_t
+new_partition (const char *name, struct file_direct *fdp,
+ int check_linux_signature)
+{
+ register partition_t part;
+ register vm_size_t size, bmsize;
+ vm_offset_t raddr;
+ mach_msg_type_number_t rsize;
+ int rc;
+ unsigned int id = part_id(name);
+
+ mutex_lock(&all_partitions.lock);
+ {
+ unsigned int i;
+ for (i = 0; i < all_partitions.n_partitions; i++)
+ {
+ part = partition_of(i);
+ if (part && part->id == id)
+ {
+ printf ("(default pager): Already paging to partition %s!\n",
+ name);
+ mutex_unlock(&all_partitions.lock);
+ return 0;
+ }
+ }
+ }
+ mutex_unlock(&all_partitions.lock);
+
+ size = atop(fdp->fd_size * fdp->fd_bsize);
+ bmsize = howmany(size, NB_BM) * sizeof(bm_entry_t);
+
+ part = (partition_t) kalloc(sizeof(struct part));
+ mutex_init(&part->p_lock);
+ part->total_size = size;
+ part->free = size;
+ part->id = id;
+ part->bitmap = (bm_entry_t *)kalloc(bmsize);
+ part->going_away= FALSE;
+ part->file = fdp;
+
+ bzero((char *)part->bitmap, bmsize);
+
+ if (check_linux_signature < 0)
+ {
+ if (check_linux_signature != -3)
+ printf("(default pager): "
+ "Paging to raw partition %s (%uk paging space)\n",
+ name, part->total_size * (vm_page_size / 1024));
+ return part;
+ }
+
+#define LINUX_PAGE_SIZE 4096 /* size of pages in Linux swap partitions */
+ rc = page_read_file_direct(part->file,
+ 0, LINUX_PAGE_SIZE,
+ &raddr,
+ &rsize);
+ if (rc)
+ panic("(default pager): cannot read first page of %s! rc=%#x\n",
+ name, rc);
+ while (rsize < LINUX_PAGE_SIZE)
+ {
+ /* Filesystem block size is smaller than page size,
+ so we must do several reads to get the whole page. */
+ vm_address_t baddr, bsize;
+ rc = page_read_file_direct(part->file,
+ rsize, LINUX_PAGE_SIZE-rsize,
+ &baddr,
+ &bsize);
+ if (rc)
+ panic("(default pager): "
+ "cannot read first page of %s! rc=%#x at %#x\n",
+ name, rc, rsize);
+
+ memcpy ((char *) raddr + rsize, (void *) baddr, bsize);
+ rsize += bsize;
+ vm_deallocate (mach_task_self (), baddr, bsize);
+ }
+
+ if (!memcmp("SWAP-SPACE", (char *) raddr + LINUX_PAGE_SIZE-10, 10))
+ {
+ /* The partition's first page has a Linux swap signature.
+ This means the beginning of the page contains a bitmap
+ of good pages, and all others are bad. */
+ unsigned int i, j, bad, max;
+ int waste;
+
+ printf("(default pager): Found Linux 2.0 swap signature in %s\n",
+ name);
+
+ /* The first page, and the pages corresponding to the bits
+ occupied by the signature in the final 10 bytes of the page,
+ are always unavailable ("bad"). */
+ *(u_int32_t *)raddr &= ~(u_int32_t) 1;
+ memset((char *) raddr + LINUX_PAGE_SIZE-10, 0, 10);
+
+ max = LINUX_PAGE_SIZE / sizeof(u_int32_t);
+ if (max > (part->total_size + 31) / 32)
+ max = (part->total_size + 31) / 32;
+
+ bad = 0;
+ for (i = 0; i < max; ++i)
+ {
+ u_int32_t bm = ((u_int32_t *) raddr)[i];
+ if (bm == ~(u_int32_t) 0)
+ continue;
+ /* There are some zero bits in this word. */
+ for (j = 0; j < 32; ++j)
+ if ((bm & (1 << j)) == 0)
+ {
+ unsigned int p = i*32 + j;
+ if (p >= part->total_size)
+ break;
+ ++bad;
+ part->bitmap[p / NB_BM] |= 1 << (p % NB_BM);
+ }
+ }
+ part->free -= bad;
+
+ --bad; /* Don't complain about first page. */
+ waste = part->total_size - (8 * (LINUX_PAGE_SIZE-10));
+ if (waste > 0)
+ {
+ /* The wasted pages were already marked "bad". */
+ bad -= waste;
+ if (bad > 0)
+ printf("\
+(default pager): Paging to %s, %dk swap-space (%dk bad, %dk wasted at end)\n",
+ name,
+ part->free * (LINUX_PAGE_SIZE / 1024),
+ bad * (LINUX_PAGE_SIZE / 1024),
+ waste * (LINUX_PAGE_SIZE / 1024));
+ else
+ printf("\
+(default pager): Paging to %s, %dk swap-space (%dk wasted at end)\n",
+ name,
+ part->free * (LINUX_PAGE_SIZE / 1024),
+ waste * (LINUX_PAGE_SIZE / 1024));
+ }
+ else if (bad > 0)
+ printf("\
+(default pager): Paging to %s, %dk swap-space (excludes %dk marked bad)\n",
+ name,
+ part->free * (LINUX_PAGE_SIZE / 1024),
+ bad * (LINUX_PAGE_SIZE / 1024));
+ else
+ printf("\
+(default pager): Paging to %s, %dk swap-space\n",
+ name,
+ part->free * (LINUX_PAGE_SIZE / 1024));
+ }
+ else if (!memcmp("SWAPSPACE2",
+ (char *) raddr + LINUX_PAGE_SIZE-10, 10))
+ {
+ struct
+ {
+ u_int8_t bootbits[1024];
+ u_int32_t version;
+ u_int32_t last_page;
+ u_int32_t nr_badpages;
+ u_int32_t padding[125];
+ u_int32_t badpages[1];
+ } *hdr = (void *) raddr;
+
+ printf("\
+(default pager): Found Linux 2.2 swap signature (v%u) in %s...",
+ hdr->version, name);
+
+ part->bitmap[0] |= 1; /* first page unusable */
+ part->free--;
+
+ switch (hdr->version)
+ {
+ default:
+ if (check_linux_signature)
+ {
+ printf ("version %u unknown! SKIPPING %s!\n",
+ hdr->version,
+ name);
+ vm_deallocate(mach_task_self(), raddr, rsize);
+ kfree(part->bitmap, bmsize);
+ kfree(part, sizeof *part);
+ return 0;
+ }
+ else
+ printf ("version %u unknown! IGNORING SIGNATURE PAGE!"
+ " %dk swap-space\n",
+ hdr->version,
+ part->free * (LINUX_PAGE_SIZE / 1024));
+ break;
+
+ case 1:
+ {
+ unsigned int waste, i;
+ if (hdr->last_page > part->total_size)
+ {
+ printf ("signature says %uk, partition has only %uk! ",
+ hdr->last_page * (LINUX_PAGE_SIZE / 1024),
+ part->total_size * (LINUX_PAGE_SIZE / 1024));
+ waste = 0;
+ }
+ else
+ {
+ waste = part->total_size - hdr->last_page;
+ part->total_size = hdr->last_page;
+ part->free = part->total_size - 1;
+ }
+ for (i = 0; i < hdr->nr_badpages; ++i)
+ {
+ const u_int32_t bad = hdr->badpages[i];
+ part->bitmap[bad / NB_BM] |= 1 << (bad % NB_BM);
+ part->free--;
+ }
+ printf ("%uk swap-space",
+ part->free * (LINUX_PAGE_SIZE / 1024));
+ if (hdr->nr_badpages != 0)
+ printf (" (excludes %uk marked bad)",
+ hdr->nr_badpages * (LINUX_PAGE_SIZE / 1024));
+ if (waste != 0)
+ printf (" (excludes %uk at end of partition)",
+ waste * (LINUX_PAGE_SIZE / 1024));
+ printf ("\n");
+ }
+ }
+ }
+ else if (check_linux_signature)
+ {
+ printf ("(default pager): "
+ "Cannot find Linux swap signature page! "
+ "SKIPPING %s (%uk partition)!",
+ name, part->total_size * (vm_page_size / 1024));
+ kfree(part->bitmap, bmsize);
+ kfree(part, sizeof *part);
+ part = 0;
+ }
+ else
+ printf("(default pager): "
+ "Paging to raw partition %s (%uk paging space)\n",
+ name, part->total_size * (vm_page_size / 1024));
+
+ vm_deallocate(mach_task_self(), raddr, rsize);
+
+ return part;
+}
+
+/*
+ * Create a partition descriptor,
+ * add it to the list of all such.
+ * size is in BYTES.
+ */
+void
+create_paging_partition(const char *name,
+ struct file_direct *fdp, int isa_file,
+ int linux_signature)
+{
+ register partition_t part;
+
+ part = new_partition (name, fdp, linux_signature);
+ if (!part)
+ return;
+
+ mutex_lock(&all_partitions.lock);
+ {
+ register int i;
+
+ for (i = 0; i < all_partitions.n_partitions; i++)
+ if (partition_of(i) == 0) break;
+
+ if (i == all_partitions.n_partitions) {
+ register partition_t *new_list, *old_list;
+ register int n;
+
+ n = i ? (i<<1) : 2;
+ new_list = (partition_t *)
+ kalloc( n * sizeof(partition_t) );
+ if (new_list == 0) no_paging_space(TRUE);
+ bzero(new_list, n*sizeof(partition_t));
+ if (i) {
+ old_list = all_partitions.partition_list;
+ bcopy(old_list, new_list, i*sizeof(partition_t));
+ }
+ all_partitions.partition_list = new_list;
+ all_partitions.n_partitions = n;
+ if (i) kfree(old_list, i*sizeof(partition_t));
+ }
+ set_partition_of(i, part);
+ }
+ mutex_unlock(&all_partitions.lock);
+
+#if 0
+ dprintf("%s Added paging %s %s\n", my_name,
+ (isa_file) ? "file" : "device", name);
+#endif
+ overcommitted(TRUE, part->free);
+}
+
+/*
+ * Choose the most appropriate default partition
+ * for an object of SIZE bytes.
+ * Return the partition locked, unless
+ * the object has no CUR_PARTition.
+ */
+p_index_t
+choose_partition(size, cur_part)
+ unsigned int size;
+ register p_index_t cur_part;
+{
+ register partition_t part;
+ register boolean_t found = FALSE;
+ register int i;
+
+ mutex_lock(&all_partitions.lock);
+ for (i = 0; i < all_partitions.n_partitions; i++) {
+
+ /* the undesirable one ? */
+ if (i == cur_part)
+ continue;
+
+ddprintf ("choose_partition(%x,%d,%d)\n",size,cur_part,i);
+ /* one that was removed ? */
+ if ((part = partition_of(i)) == 0)
+ continue;
+
+ /* one that is being removed ? */
+ if (part->going_away)
+ continue;
+
+ /* is it big enough ? */
+ mutex_lock(&part->p_lock);
+ if (ptoa(part->free) >= size) {
+ if (cur_part != P_INDEX_INVALID) {
+ mutex_unlock(&all_partitions.lock);
+ return (p_index_t)i;
+ } else
+ found = TRUE;
+ }
+ mutex_unlock(&part->p_lock);
+
+ if (found) break;
+ }
+ mutex_unlock(&all_partitions.lock);
+ return (found) ? (p_index_t)i : P_INDEX_INVALID;
+}
+
+/*
+ * Allocate a page in a paging partition
+ * The partition is returned unlocked.
+ */
+vm_offset_t
+pager_alloc_page(pindex, lock_it)
+ p_index_t pindex;
+ boolean_t lock_it;
+{
+ register int bm_e;
+ register int bit;
+ register int limit;
+ register bm_entry_t *bm;
+ partition_t part;
+ static char here[] = "%spager_alloc_page";
+
+ if (no_partition(pindex))
+ return (NO_BLOCK);
+ddprintf ("pager_alloc_page(%d,%d)\n",pindex,lock_it);
+ part = partition_of(pindex);
+
+ /* unlikely, but possible deadlock against destroy_partition */
+ if (!part || part->going_away)
+ return (NO_BLOCK);
+
+ if (lock_it)
+ mutex_lock(&part->p_lock);
+
+ if (part->free == 0) {
+ /* out of paging space */
+ mutex_unlock(&part->p_lock);
+ return (NO_BLOCK);
+ }
+
+ limit = howmany(part->total_size, NB_BM);
+ bm = part->bitmap;
+ for (bm_e = 0; bm_e < limit; bm_e++, bm++)
+ if (*bm != BM_MASK)
+ break;
+
+ if (bm_e == limit)
+ panic(here,my_name);
+
+ /*
+ * Find and set the proper bit
+ */
+ {
+ register bm_entry_t b = *bm;
+
+ for (bit = 0; bit < NB_BM; bit++)
+ if ((b & (1<<bit)) == 0)
+ break;
+ if (bit == NB_BM)
+ panic(here,my_name);
+
+ *bm = b | (1<<bit);
+ part->free--;
+
+ }
+
+ mutex_unlock(&part->p_lock);
+
+ return (bm_e*NB_BM+bit);
+}
+
+/*
+ * Deallocate a page in a paging partition
+ */
+void
+pager_dealloc_page(pindex, page, lock_it)
+ p_index_t pindex;
+ register vm_offset_t page;
+ boolean_t lock_it;
+{
+ register partition_t part;
+ register int bit, bm_e;
+
+ /* be paranoid */
+ if (no_partition(pindex))
+ panic("%sdealloc_page",my_name);
+ddprintf ("pager_dealloc_page(%d,%x,%d)\n",pindex,page,lock_it);
+ part = partition_of(pindex);
+
+ if (page >= part->total_size)
+ panic("%sdealloc_page",my_name);
+
+ bm_e = page / NB_BM;
+ bit = page % NB_BM;
+
+ if (lock_it)
+ mutex_lock(&part->p_lock);
+
+ part->bitmap[bm_e] &= ~(1<<bit);
+ part->free++;
+
+ if (lock_it)
+ mutex_unlock(&part->p_lock);
+}
+
+/*
+
+ */
+/*
+ * Allocation info for each paging object.
+ *
+ * Most operations, even pager_write_offset and pager_put_checksum,
+ * just need a read lock. Higher-level considerations prevent
+ * conflicting operations on a single page. The lock really protects
+ * the underlying size and block map memory, so pager_extend needs a
+ * write lock.
+ *
+ * An object can now span multiple paging partitions. The allocation
+ * info we keep is a pair (offset,p_index) where the index is in the
+ * array of all partition ptrs, and the offset is partition-relative.
+ * Size wise we are doing ok fitting the pair into a single integer:
+ * the offset really is in pages so we have vm_page_size bits available
+ * for the partition index.
+ */
+#define DEBUG_READER_CONFLICTS 0
+
+#if DEBUG_READER_CONFLICTS
+int default_pager_read_conflicts = 0;
+#endif
+
+union dp_map {
+
+ struct {
+ unsigned int p_offset : 24,
+ p_index : 8;
+ } block;
+
+ union dp_map *indirect;
+};
+typedef union dp_map *dp_map_t;
+
+/* quick check for part==block==invalid */
+#define no_block(e) ((e).indirect == (dp_map_t)NO_BLOCK)
+#define invalidate_block(e) ((e).indirect = (dp_map_t)NO_BLOCK)
+
+struct dpager {
+ struct mutex lock; /* lock for extending block map */
+ /* XXX should be read-write lock */
+#if DEBUG_READER_CONFLICTS
+ int readers;
+ boolean_t writer;
+#endif
+ dp_map_t map; /* block map */
+ vm_size_t size; /* size of paging object, in pages */
+ vm_size_t limit; /* limit (bytes) allowed to grow to */
+ p_index_t cur_partition;
+#ifdef CHECKSUM
+ vm_offset_t *checksum; /* checksum - parallel to block map */
+#define NO_CHECKSUM ((vm_offset_t)-1)
+#endif /* CHECKSUM */
+};
+typedef struct dpager *dpager_t;
+
+/*
+ * A paging object uses either a one- or a two-level map of offsets
+ * into a paging partition.
+ */
+#define PAGEMAP_ENTRIES 64
+ /* number of pages in a second-level map */
+#define PAGEMAP_SIZE(npgs) ((npgs)*sizeof(vm_offset_t))
+
+#define INDIRECT_PAGEMAP_ENTRIES(npgs) \
+ ((((npgs)-1)/PAGEMAP_ENTRIES) + 1)
+#define INDIRECT_PAGEMAP_SIZE(npgs) \
+ (INDIRECT_PAGEMAP_ENTRIES(npgs) * sizeof(vm_offset_t *))
+#define INDIRECT_PAGEMAP(size) \
+ (size > PAGEMAP_ENTRIES)
+
+#define ROUNDUP_TO_PAGEMAP(npgs) \
+ (((npgs) + PAGEMAP_ENTRIES - 1) & ~(PAGEMAP_ENTRIES - 1))
+
+/*
+ * Object sizes are rounded up to the next power of 2,
+ * unless they are bigger than a given maximum size.
+ */
+vm_size_t max_doubled_size = 4 * 1024 * 1024; /* 4 meg */
+
+/*
+ * Attach a new paging object to a paging partition
+ */
+void
+pager_alloc(pager, part, size)
+ register dpager_t pager;
+ p_index_t part;
+ register vm_size_t size; /* in BYTES */
+{
+ register int i;
+ register dp_map_t mapptr, emapptr;
+
+ mutex_init(&pager->lock);
+#if DEBUG_READER_CONFLICTS
+ pager->readers = 0;
+ pager->writer = FALSE;
+#endif
+ pager->cur_partition = part;
+
+ /*
+ * Convert byte size to number of pages, then increase to the nearest
+ * power of 2.
+ */
+ size = atop(size);
+ if (size <= atop(max_doubled_size)) {
+ i = 1;
+ while (i < size)
+ i <<= 1;
+ size = i;
+ } else
+ size = ROUNDUP_TO_PAGEMAP(size);
+
+ /*
+ * Allocate and initialize the block map
+ */
+ {
+ register vm_size_t alloc_size;
+ dp_map_t init_value;
+
+ if (INDIRECT_PAGEMAP(size)) {
+ alloc_size = INDIRECT_PAGEMAP_SIZE(size);
+ init_value = (dp_map_t)0;
+ } else {
+ alloc_size = PAGEMAP_SIZE(size);
+ init_value = (dp_map_t)NO_BLOCK;
+ }
+
+ mapptr = (dp_map_t) kalloc(alloc_size);
+ for (emapptr = &mapptr[(alloc_size-1) / sizeof(vm_offset_t)];
+ emapptr >= mapptr;
+ emapptr--)
+ emapptr->indirect = init_value;
+
+ }
+ pager->map = mapptr;
+ pager->size = size;
+ pager->limit = (vm_size_t)-1;
+
+#ifdef CHECKSUM
+ if (INDIRECT_PAGEMAP(size)) {
+ mapptr = (vm_offset_t *)
+ kalloc(INDIRECT_PAGEMAP_SIZE(size));
+ for (i = INDIRECT_PAGEMAP_ENTRIES(size); --i >= 0;)
+ mapptr[i] = 0;
+ } else {
+ mapptr = (vm_offset_t *) kalloc(PAGEMAP_SIZE(size));
+ for (i = 0; i < size; i++)
+ mapptr[i] = NO_CHECKSUM;
+ }
+ pager->checksum = mapptr;
+#endif /* CHECKSUM */
+}
+
+/*
+ * Return size (in bytes) of space actually allocated to this pager.
+ * The pager is read-locked.
+ */
+
+vm_size_t
+pager_allocated(pager)
+ register dpager_t pager;
+{
+ vm_size_t size;
+ register dp_map_t map, emap;
+ vm_size_t asize;
+
+ size = pager->size; /* in pages */
+ asize = 0; /* allocated, in pages */
+ map = pager->map;
+
+ if (INDIRECT_PAGEMAP(size)) {
+ for (emap = &map[INDIRECT_PAGEMAP_ENTRIES(size)];
+ map < emap; map++) {
+
+ register dp_map_t map2, emap2;
+
+ if ((map2 = map->indirect) == 0)
+ continue;
+
+ for (emap2 = &map2[PAGEMAP_ENTRIES];
+ map2 < emap2; map2++)
+ if ( ! no_block(*map2) )
+ asize++;
+
+ }
+ } else {
+ for (emap = &map[size]; map < emap; map++)
+ if ( ! no_block(*map) )
+ asize++;
+ }
+
+ return ptoa(asize);
+}
+
+/*
+ * Find offsets (in the object) of pages actually allocated to this pager.
+ * Returns the number of allocated pages, whether or not they all fit.
+ * The pager is read-locked.
+ */
+
+unsigned int
+pager_pages(pager, pages, numpages)
+ dpager_t pager;
+ register default_pager_page_t *pages;
+ unsigned int numpages;
+{
+ vm_size_t size;
+ dp_map_t map, emap;
+ unsigned int actual;
+ vm_offset_t offset;
+
+ size = pager->size; /* in pages */
+ map = pager->map;
+ actual = 0;
+ offset = 0;
+
+ if (INDIRECT_PAGEMAP(size)) {
+ for (emap = &map[INDIRECT_PAGEMAP_ENTRIES(size)];
+ map < emap; map++) {
+
+ register dp_map_t map2, emap2;
+
+ if ((map2 = map->indirect) == 0) {
+ offset += vm_page_size * PAGEMAP_ENTRIES;
+ continue;
+ }
+ for (emap2 = &map2[PAGEMAP_ENTRIES];
+ map2 < emap2; map2++)
+ if ( ! no_block(*map2) ) {
+ if (actual++ < numpages)
+ pages++->dpp_offset = offset;
+ }
+ offset += vm_page_size;
+ }
+ } else {
+ for (emap = &map[size]; map < emap; map++)
+ if ( ! no_block(*map) ) {
+ if (actual++ < numpages)
+ pages++->dpp_offset = offset;
+ }
+ offset += vm_page_size;
+ }
+ return actual;
+}
+
+/*
+ * Extend the map for a paging object.
+ *
+ * XXX This implementation can allocate an arbitrary large amount
+ * of wired memory when extending a big block map. Because vm-privileged
+ * threads call pager_extend, this can crash the system by exhausting
+ * system memory.
+ */
+void
+pager_extend(pager, new_size)
+ register dpager_t pager;
+ register vm_size_t new_size; /* in pages */
+{
+ register dp_map_t new_mapptr;
+ register dp_map_t old_mapptr;
+ register int i;
+ register vm_size_t old_size;
+
+ mutex_lock(&pager->lock); /* XXX lock_write */
+#if DEBUG_READER_CONFLICTS
+ pager->writer = TRUE;
+#endif
+ /*
+ * Double current size until we cover new size.
+ * If object is 'too big' just use new size.
+ */
+ old_size = pager->size;
+
+ if (new_size <= atop(max_doubled_size)) {
+ i = old_size;
+ while (i < new_size)
+ i <<= 1;
+ new_size = i;
+ } else
+ new_size = ROUNDUP_TO_PAGEMAP(new_size);
+
+ if (INDIRECT_PAGEMAP(old_size)) {
+ /*
+ * Pager already uses two levels. Allocate
+ * a larger indirect block.
+ */
+ new_mapptr = (dp_map_t)
+ kalloc(INDIRECT_PAGEMAP_SIZE(new_size));
+ old_mapptr = pager->map;
+ for (i = 0; i < INDIRECT_PAGEMAP_ENTRIES(old_size); i++)
+ new_mapptr[i] = old_mapptr[i];
+ for (; i < INDIRECT_PAGEMAP_ENTRIES(new_size); i++)
+ new_mapptr[i].indirect = (dp_map_t)0;
+ kfree((char *)old_mapptr, INDIRECT_PAGEMAP_SIZE(old_size));
+ pager->map = new_mapptr;
+ pager->size = new_size;
+#ifdef CHECKSUM
+ new_mapptr = (vm_offset_t *)
+ kalloc(INDIRECT_PAGEMAP_SIZE(new_size));
+ old_mapptr = pager->checksum;
+ for (i = 0; i < INDIRECT_PAGEMAP_ENTRIES(old_size); i++)
+ new_mapptr[i] = old_mapptr[i];
+ for (; i < INDIRECT_PAGEMAP_ENTRIES(new_size); i++)
+ new_mapptr[i] = 0;
+ kfree((char *)old_mapptr, INDIRECT_PAGEMAP_SIZE(old_size));
+ pager->checksum = new_mapptr;
+#endif /* CHECKSUM */
+#if DEBUG_READER_CONFLICTS
+ pager->writer = FALSE;
+#endif
+ mutex_unlock(&pager->lock);
+#if 0
+ ddprintf ("pager_extend 1 mapptr %x [3b] = %x\n", new_mapptr,
+ new_mapptr[0x3b]);
+ if (new_mapptr[0x3b].indirect > 0x10000
+ && new_mapptr[0x3b].indirect != NO_BLOCK)
+ panic ("debug panic");
+#endif
+ return;
+ }
+
+ if (INDIRECT_PAGEMAP(new_size)) {
+ /*
+ * Changing from direct map to indirect map.
+ * Allocate both indirect and direct map blocks,
+ * since second-level (direct) block must be
+ * full size (PAGEMAP_SIZE(PAGEMAP_ENTRIES)).
+ */
+
+ /*
+ * Allocate new second-level map first.
+ */
+ new_mapptr = (dp_map_t) kalloc(PAGEMAP_SIZE(PAGEMAP_ENTRIES));
+ old_mapptr = pager->map;
+ for (i = 0; i < old_size; i++)
+ new_mapptr[i] = old_mapptr[i];
+ for (; i < PAGEMAP_ENTRIES; i++)
+ invalidate_block(new_mapptr[i]);
+ kfree((char *)old_mapptr, PAGEMAP_SIZE(old_size));
+ old_mapptr = new_mapptr;
+
+#if 0
+ ddprintf ("pager_extend 2 mapptr %x [3b] = %x\n", new_mapptr,
+ new_mapptr[0x3b]);
+ if (new_mapptr[0x3b].indirect > 0x10000
+ && new_mapptr[0x3b].indirect != NO_BLOCK)
+ panic ("debug panic");
+#endif
+
+ /*
+ * Now allocate indirect map.
+ */
+ new_mapptr = (dp_map_t)
+ kalloc(INDIRECT_PAGEMAP_SIZE(new_size));
+ new_mapptr[0].indirect = old_mapptr;
+ for (i = 1; i < INDIRECT_PAGEMAP_ENTRIES(new_size); i++)
+ new_mapptr[i].indirect = 0;
+ pager->map = new_mapptr;
+ pager->size = new_size;
+#ifdef CHECKSUM
+ /*
+ * Allocate new second-level map first.
+ */
+ new_mapptr = (vm_offset_t *)kalloc(PAGEMAP_SIZE(PAGEMAP_ENTRIES));
+ old_mapptr = pager->checksum;
+ for (i = 0; i < old_size; i++)
+ new_mapptr[i] = old_mapptr[i];
+ for (; i < PAGEMAP_ENTRIES; i++)
+ new_mapptr[i] = NO_CHECKSUM;
+ kfree((char *)old_mapptr, PAGEMAP_SIZE(old_size));
+ old_mapptr = new_mapptr;
+
+ /*
+ * Now allocate indirect map.
+ */
+ new_mapptr = (vm_offset_t *)
+ kalloc(INDIRECT_PAGEMAP_SIZE(new_size));
+ new_mapptr[0] = (vm_offset_t) old_mapptr;
+ for (i = 1; i < INDIRECT_PAGEMAP_ENTRIES(new_size); i++)
+ new_mapptr[i] = 0;
+ pager->checksum = new_mapptr;
+#endif /* CHECKSUM */
+#if DEBUG_READER_CONFLICTS
+ pager->writer = FALSE;
+#endif
+ mutex_unlock(&pager->lock);
+ return;
+ }
+ /*
+ * Enlarging a direct block.
+ */
+ new_mapptr = (dp_map_t) kalloc(PAGEMAP_SIZE(new_size));
+ old_mapptr = pager->map;
+ for (i = 0; i < old_size; i++)
+ new_mapptr[i] = old_mapptr[i];
+ for (; i < new_size; i++)
+ invalidate_block(new_mapptr[i]);
+ kfree((char *)old_mapptr, PAGEMAP_SIZE(old_size));
+ pager->map = new_mapptr;
+ pager->size = new_size;
+#ifdef CHECKSUM
+ new_mapptr = (vm_offset_t *)
+ kalloc(PAGEMAP_SIZE(new_size));
+ old_mapptr = pager->checksum;
+ for (i = 0; i < old_size; i++)
+ new_mapptr[i] = old_mapptr[i];
+ for (; i < new_size; i++)
+ new_mapptr[i] = NO_CHECKSUM;
+ kfree((char *)old_mapptr, PAGEMAP_SIZE(old_size));
+ pager->checksum = new_mapptr;
+#endif /* CHECKSUM */
+#if DEBUG_READER_CONFLICTS
+ pager->writer = FALSE;
+#endif
+ mutex_unlock(&pager->lock);
+}
+
+/* Truncate a memory object. First, any pages between the new size
+ and the (larger) old size are deallocated. Then, the size of
+ the pagemap may be reduced, an indirect map may be turned into
+ a direct map.
+
+ The pager must be locked by the caller. */
+static void
+pager_truncate(dpager_t pager, vm_size_t new_size) /* in pages */
+{
+ dp_map_t new_mapptr;
+ dp_map_t old_mapptr;
+ int i;
+ vm_size_t old_size;
+
+ /* This deallocates the pages necessary to truncate a direct map
+ previously of size NEW_SIZE to the smaller size OLD_SIZE. */
+ inline void dealloc_direct (dp_map_t mapptr,
+ vm_size_t old_size, vm_size_t new_size)
+ {
+ vm_size_t i;
+ for (i = new_size; i < old_size; ++i)
+ {
+ const union dp_map entry = mapptr[i];
+ pager_dealloc_page(entry.block.p_index, entry.block.p_offset,
+ TRUE);
+ invalidate_block(mapptr[i]);
+ }
+ }
+
+ mutex_lock(&pager->lock); /* XXX lock_write */
+ old_size = pager->size;
+
+ if (INDIRECT_PAGEMAP(old_size))
+ {
+ /* First handle the entire second-levels blocks that are being freed. */
+ for (i = INDIRECT_PAGEMAP_ENTRIES(new_size);
+ i < INDIRECT_PAGEMAP_ENTRIES(old_size);
+ ++i)
+ {
+ const dp_map_t mapptr = pager->map[i].indirect;
+ pager->map[i].indirect = (dp_map_t)0;
+ dealloc_direct (mapptr, PAGEMAP_ENTRIES, 0);
+ kfree ((char *)mapptr, PAGEMAP_SIZE(PAGEMAP_ENTRIES));
+ }
+
+ /* Now truncate what's now the final nonempty direct block. */
+ dealloc_direct (pager->map[(new_size - 1) / PAGEMAP_ENTRIES].indirect,
+ old_size & (PAGEMAP_ENTRIES - 1),
+ new_size & (PAGEMAP_ENTRIES - 1));
+
+ if (INDIRECT_PAGEMAP (new_size))
+ {
+ if (INDIRECT_PAGEMAP_SIZE (new_size) >= vm_page_size)
+ /* XXX we know how kalloc.c works; avoid copying. */
+ kfree ((char *) round_page ((vm_address_t) pager->map
+ + INDIRECT_PAGEMAP_SIZE (new_size)),
+ round_page (INDIRECT_PAGEMAP_SIZE (old_size))
+ - round_page (INDIRECT_PAGEMAP_SIZE (new_size)));
+ else
+ {
+ const dp_map_t old_mapptr = pager->map;
+ pager->map = (dp_map_t) kalloc (INDIRECT_PAGEMAP_SIZE(new_size));
+ memcpy (pager->map, old_mapptr, INDIRECT_PAGEMAP_SIZE(old_size));
+ kfree ((char *) old_mapptr, INDIRECT_PAGEMAP_SIZE (old_size));
+ }
+ }
+ else
+ {
+ /* We are truncating to a size small enough that it goes to using
+ a one-level map. We already have that map, as the first and only
+ nonempty element in our indirect map. */
+ const dp_map_t mapptr = pager->map[0].indirect;
+ kfree((char *)pager->map, INDIRECT_PAGEMAP_SIZE(old_size));
+ pager->map = mapptr;
+ old_size = PAGEMAP_ENTRIES;
+ }
+ }
+
+ if (new_size == 0)
+ new_size = 1;
+
+ if (! INDIRECT_PAGEMAP(old_size))
+ {
+ /* First deallocate pages in the truncated region. */
+ dealloc_direct (pager->map, old_size, new_size);
+ /* Now reduce the size of the direct map itself. We don't bother
+ with kalloc/kfree if it's not shrinking enough that kalloc.c
+ would actually use less. */
+ if (PAGEMAP_SIZE (new_size) <= PAGEMAP_SIZE (old_size) / 2)
+ {
+ const dp_map_t old_mapptr = pager->map;
+ pager->map = (dp_map_t) kalloc (PAGEMAP_SIZE (new_size));
+ memcpy (pager->map, old_mapptr, PAGEMAP_SIZE (old_size));
+ kfree ((char *) old_mapptr, PAGEMAP_SIZE (old_size));
+ }
+ }
+
+ pager->size = new_size;
+ mutex_unlock(&pager->lock);
+
+#ifdef CHECKSUM
+#error write me
+#endif /* CHECKSUM */
+}
+
+
+/*
+ * Given an offset within a paging object, find the
+ * corresponding block within the paging partition.
+ * Return NO_BLOCK if none allocated.
+ */
+union dp_map
+pager_read_offset(pager, offset)
+ register dpager_t pager;
+ vm_offset_t offset;
+{
+ register vm_offset_t f_page;
+ union dp_map pager_offset;
+
+ f_page = atop(offset);
+
+#if DEBUG_READER_CONFLICTS
+ if (pager->readers > 0)
+ default_pager_read_conflicts++; /* would have proceeded with
+ read/write lock */
+#endif
+ mutex_lock(&pager->lock); /* XXX lock_read */
+#if DEBUG_READER_CONFLICTS
+ pager->readers++;
+#endif
+ if (f_page >= pager->size)
+ {
+ ddprintf ("%spager_read_offset pager %x: bad page %d >= size %d",
+ my_name, pager, f_page, pager->size);
+ mutex_unlock(&pager->lock);
+ return (union dp_map) (union dp_map *) NO_BLOCK;
+#if 0
+ panic("%spager_read_offset",my_name);
+#endif
+ }
+
+ if (INDIRECT_PAGEMAP(pager->size)) {
+ register dp_map_t mapptr;
+
+ mapptr = pager->map[f_page/PAGEMAP_ENTRIES].indirect;
+ if (mapptr == 0)
+ invalidate_block(pager_offset);
+ else
+ pager_offset = mapptr[f_page%PAGEMAP_ENTRIES];
+ }
+ else {
+ pager_offset = pager->map[f_page];
+ }
+
+#if DEBUG_READER_CONFLICTS
+ pager->readers--;
+#endif
+ mutex_unlock(&pager->lock);
+ return (pager_offset);
+}
+
+#if USE_PRECIOUS
+/*
+ * Release a single disk block.
+ */
+void pager_release_offset(pager, offset)
+ register dpager_t pager;
+ vm_offset_t offset;
+{
+ register union dp_map entry;
+
+ offset = atop(offset);
+
+ mutex_lock(&pager->lock); /* XXX lock_read */
+
+ if (INDIRECT_PAGEMAP(pager->size)) {
+ register dp_map_t mapptr;
+
+ mapptr = pager->map[offset / PAGEMAP_ENTRIES].indirect;
+ entry = mapptr[offset % PAGEMAP_ENTRIES];
+ invalidate_block(mapptr[offset % PAGEMAP_ENTRIES]);
+ } else {
+ entry = pager->map[offset];
+ invalidate_block(pager->map[offset]);
+ }
+
+ mutex_unlock(&pager->lock);
+
+ pager_dealloc_page(entry.block.p_index, entry.block.p_offset, TRUE);
+}
+#endif /*USE_PRECIOUS*/
+
+
+/*
+ * Move a page from one partition to another
+ * New partition is locked, old partition is
+ * locked unless LOCK_OLD sez otherwise.
+ */
+union dp_map
+pager_move_page(block)
+ union dp_map block;
+{
+ partition_t old_part, new_part;
+ p_index_t old_pindex, new_pindex;
+ union dp_map ret;
+ vm_size_t size;
+ vm_offset_t raddr, offset, new_offset;
+ kern_return_t rc;
+ static char here[] = "%spager_move_page";
+
+ old_pindex = block.block.p_index;
+ invalidate_block(ret);
+
+ /* See if we have room to put it anywhere else */
+ new_pindex = choose_partition( ptoa(1), old_pindex);
+ if (no_partition(new_pindex))
+ return ret;
+
+ /* this unlocks the new partition */
+ new_offset = pager_alloc_page(new_pindex, FALSE);
+ if (new_offset == NO_BLOCK)
+ panic(here,my_name);
+
+ /*
+ * Got the resources, now move the data
+ */
+ddprintf ("pager_move_page(%x,%d,%d)\n",block.block.p_offset,old_pindex,new_pindex);
+ old_part = partition_of(old_pindex);
+ offset = ptoa(block.block.p_offset);
+ rc = page_read_file_direct (old_part->file,
+ offset,
+ vm_page_size,
+ &raddr,
+ &size);
+ if (rc != 0)
+ panic(here,my_name);
+
+ /* release old */
+ pager_dealloc_page(old_pindex, block.block.p_offset, FALSE);
+
+ new_part = partition_of(new_pindex);
+ offset = ptoa(new_offset);
+ rc = page_write_file_direct (new_part->file,
+ offset,
+ raddr,
+ size,
+ &size);
+ if (rc != 0)
+ panic(here,my_name);
+
+ (void) vm_deallocate( mach_task_self(), raddr, size);
+
+ ret.block.p_offset = new_offset;
+ ret.block.p_index = new_pindex;
+
+ return ret;
+}
+
+#ifdef CHECKSUM
+/*
+ * Return the checksum for a block.
+ */
+int
+pager_get_checksum(pager, offset)
+ register dpager_t pager;
+ vm_offset_t offset;
+{
+ register vm_offset_t f_page;
+ int checksum;
+
+ f_page = atop(offset);
+
+ mutex_lock(&pager->lock); /* XXX lock_read */
+ if (f_page >= pager->size)
+ panic("%spager_get_checksum",my_name);
+
+ if (INDIRECT_PAGEMAP(pager->size)) {
+ register vm_offset_t *mapptr;
+
+ mapptr = (vm_offset_t *)pager->checksum[f_page/PAGEMAP_ENTRIES];
+ if (mapptr == 0)
+ checksum = NO_CHECKSUM;
+ else
+ checksum = mapptr[f_page%PAGEMAP_ENTRIES];
+ }
+ else {
+ checksum = pager->checksum[f_page];
+ }
+
+ mutex_unlock(&pager->lock);
+ return (checksum);
+}
+
+/*
+ * Remember the checksum for a block.
+ */
+int
+pager_put_checksum(pager, offset, checksum)
+ register dpager_t pager;
+ vm_offset_t offset;
+ int checksum;
+{
+ register vm_offset_t f_page;
+ static char here[] = "%spager_put_checksum";
+
+ f_page = atop(offset);
+
+ mutex_lock(&pager->lock); /* XXX lock_read */
+ if (f_page >= pager->size)
+ panic(here,my_name);
+
+ if (INDIRECT_PAGEMAP(pager->size)) {
+ register vm_offset_t *mapptr;
+
+ mapptr = (vm_offset_t *)pager->checksum[f_page/PAGEMAP_ENTRIES];
+ if (mapptr == 0)
+ panic(here,my_name);
+
+ mapptr[f_page%PAGEMAP_ENTRIES] = checksum;
+ }
+ else {
+ pager->checksum[f_page] = checksum;
+ }
+ mutex_unlock(&pager->lock);
+}
+
+/*
+ * Compute a checksum - XOR each 32-bit word.
+ */
+int
+compute_checksum(addr, size)
+ vm_offset_t addr;
+ vm_size_t size;
+{
+ register int checksum = NO_CHECKSUM;
+ register int *ptr;
+ register int count;
+
+ ptr = (int *)addr;
+ count = size / sizeof(int);
+
+ while (--count >= 0)
+ checksum ^= *ptr++;
+
+ return (checksum);
+}
+#endif /* CHECKSUM */
+
+/*
+ * Given an offset within a paging object, find the
+ * corresponding block within the paging partition.
+ * Allocate a new block if necessary.
+ *
+ * WARNING: paging objects apparently may be extended
+ * without notice!
+ */
+union dp_map
+pager_write_offset(pager, offset)
+ register dpager_t pager;
+ vm_offset_t offset;
+{
+ register vm_offset_t f_page;
+ register dp_map_t mapptr;
+ register union dp_map block;
+
+ invalidate_block(block);
+
+ f_page = atop(offset);
+
+#if DEBUG_READER_CONFLICTS
+ if (pager->readers > 0)
+ default_pager_read_conflicts++; /* would have proceeded with
+ read/write lock */
+#endif
+ mutex_lock(&pager->lock); /* XXX lock_read */
+#if DEBUG_READER_CONFLICTS
+ pager->readers++;
+#endif
+
+ /* Catch the case where we had no initial fit partition
+ for this object, but one was added later on */
+ if (no_partition(pager->cur_partition)) {
+ p_index_t new_part;
+ vm_size_t size;
+
+ size = (f_page > pager->size) ? f_page : pager->size;
+ new_part = choose_partition(ptoa(size), P_INDEX_INVALID);
+ if (no_partition(new_part))
+ new_part = choose_partition(ptoa(1), P_INDEX_INVALID);
+ if (no_partition(new_part))
+ /* give up right now to avoid confusion */
+ goto out;
+ else
+ pager->cur_partition = new_part;
+ }
+
+ while (f_page >= pager->size) {
+ ddprintf ("pager_write_offset: extending: %x %x\n", f_page, pager->size);
+
+ /*
+ * Paging object must be extended.
+ * Remember that offset is 0-based, but size is 1-based.
+ */
+#if DEBUG_READER_CONFLICTS
+ pager->readers--;
+#endif
+ mutex_unlock(&pager->lock);
+ pager_extend(pager, f_page + 1);
+#if DEBUG_READER_CONFLICTS
+ if (pager->readers > 0)
+ default_pager_read_conflicts++; /* would have proceeded with
+ read/write lock */
+#endif
+ mutex_lock(&pager->lock); /* XXX lock_read */
+#if DEBUG_READER_CONFLICTS
+ pager->readers++;
+#endif
+ ddprintf ("pager_write_offset: done extending: %x %x\n", f_page, pager->size);
+ }
+
+ if (INDIRECT_PAGEMAP(pager->size)) {
+ ddprintf ("pager_write_offset: indirect\n");
+ mapptr = pager->map[f_page/PAGEMAP_ENTRIES].indirect;
+ if (mapptr == 0) {
+ /*
+ * Allocate the indirect block
+ */
+ register int i;
+ ddprintf ("pager_write_offset: allocating indirect\n");
+
+ mapptr = (dp_map_t) kalloc(PAGEMAP_SIZE(PAGEMAP_ENTRIES));
+ if (mapptr == 0) {
+ /* out of space! */
+ no_paging_space(TRUE);
+ goto out;
+ }
+ pager->map[f_page/PAGEMAP_ENTRIES].indirect = mapptr;
+ for (i = 0; i < PAGEMAP_ENTRIES; i++)
+ invalidate_block(mapptr[i]);
+#ifdef CHECKSUM
+ {
+ register vm_offset_t *cksumptr;
+ register int j;
+
+ cksumptr = (vm_offset_t *)
+ kalloc(PAGEMAP_SIZE(PAGEMAP_ENTRIES));
+ if (cksumptr == 0) {
+ /* out of space! */
+ no_paging_space(TRUE);
+ goto out;
+ }
+ pager->checksum[f_page/PAGEMAP_ENTRIES]
+ = (vm_offset_t)cksumptr;
+ for (j = 0; j < PAGEMAP_ENTRIES; j++)
+ cksumptr[j] = NO_CHECKSUM;
+ }
+#endif /* CHECKSUM */
+ }
+ f_page %= PAGEMAP_ENTRIES;
+ }
+ else {
+ mapptr = pager->map;
+ }
+
+ block = mapptr[f_page];
+ ddprintf ("pager_write_offset: block starts as %x[%x] %x\n", mapptr, f_page, block);
+ if (no_block(block)) {
+ vm_offset_t off;
+
+ /* get room now */
+ off = pager_alloc_page(pager->cur_partition, TRUE);
+ if (off == NO_BLOCK) {
+ /*
+ * Before giving up, try all other partitions.
+ */
+ p_index_t new_part;
+
+ ddprintf ("pager_write_offset: could not allocate block\n");
+ /* returns it locked (if any one is non-full) */
+ new_part = choose_partition( ptoa(1), pager->cur_partition);
+ if ( ! no_partition(new_part) ) {
+
+#if debug
+dprintf("%s partition %x filled,", my_name, pager->cur_partition);
+dprintf("extending object %x (size %x) to %x.\n",
+ pager, pager->size, new_part);
+#endif
+
+ /* this one tastes better */
+ pager->cur_partition = new_part;
+
+ /* this unlocks the partition too */
+ off = pager_alloc_page(pager->cur_partition, FALSE);
+
+ }
+
+ if (off == NO_BLOCK) {
+ /*
+ * Oh well.
+ */
+ overcommitted(FALSE, 1);
+ goto out;
+ }
+ ddprintf ("pager_write_offset: decided to allocate block\n");
+ }
+ block.block.p_offset = off;
+ block.block.p_index = pager->cur_partition;
+ mapptr[f_page] = block;
+ ddprintf ("pager_write_offset: mapptr %x [3b] = %x\n", mapptr,
+ mapptr[0x3b]);
+ ddprintf ("pager_write_offset: block is finally %x\n", block);
+ }
+
+out:
+
+#if DEBUG_READER_CONFLICTS
+ pager->readers--;
+#endif
+ mutex_unlock(&pager->lock);
+ return (block);
+}
+
+/*
+ * Deallocate all of the blocks belonging to a paging object.
+ * No locking needed because no other operations can be in progress.
+ */
+void
+pager_dealloc(pager)
+ register dpager_t pager;
+{
+ register int i, j;
+ register dp_map_t mapptr;
+ register union dp_map block;
+
+ if (INDIRECT_PAGEMAP(pager->size)) {
+ for (i = INDIRECT_PAGEMAP_ENTRIES(pager->size); --i >= 0; ) {
+ mapptr = pager->map[i].indirect;
+ if (mapptr != 0) {
+ for (j = 0; j < PAGEMAP_ENTRIES; j++) {
+ block = mapptr[j];
+ if ( ! no_block(block) )
+ pager_dealloc_page(block.block.p_index,
+ block.block.p_offset, TRUE);
+ }
+ kfree((char *)mapptr, PAGEMAP_SIZE(PAGEMAP_ENTRIES));
+ }
+ }
+ kfree((char *)pager->map, INDIRECT_PAGEMAP_SIZE(pager->size));
+#ifdef CHECKSUM
+ for (i = INDIRECT_PAGEMAP_ENTRIES(pager->size); --i >= 0; ) {
+ mapptr = (vm_offset_t *)pager->checksum[i];
+ if (mapptr) {
+ kfree((char *)mapptr, PAGEMAP_SIZE(PAGEMAP_ENTRIES));
+ }
+ }
+ kfree((char *)pager->checksum,
+ INDIRECT_PAGEMAP_SIZE(pager->size));
+#endif /* CHECKSUM */
+ }
+ else {
+ mapptr = pager->map;
+ for (i = 0; i < pager->size; i++ ) {
+ block = mapptr[i];
+ if ( ! no_block(block) )
+ pager_dealloc_page(block.block.p_index,
+ block.block.p_offset, TRUE);
+ }
+ kfree((char *)pager->map, PAGEMAP_SIZE(pager->size));
+#ifdef CHECKSUM
+ kfree((char *)pager->checksum, PAGEMAP_SIZE(pager->size));
+#endif /* CHECKSUM */
+ }
+}
+
+/*
+ * Move all the pages of a PAGER that live in a
+ * partition PINDEX somewhere else.
+ * Pager should be write-locked, partition too.
+ * Returns FALSE if it could not do it, but
+ * some pages might have been moved nonetheless.
+ */
+boolean_t
+pager_realloc(pager, pindex)
+ register dpager_t pager;
+ p_index_t pindex;
+{
+ register dp_map_t map, emap;
+ vm_size_t size;
+ union dp_map block;
+
+ size = pager->size; /* in pages */
+ map = pager->map;
+
+ if (INDIRECT_PAGEMAP(size)) {
+ for (emap = &map[INDIRECT_PAGEMAP_ENTRIES(size)];
+ map < emap; map++) {
+
+ register dp_map_t map2, emap2;
+
+ if ((map2 = map->indirect) == 0)
+ continue;
+
+ for (emap2 = &map2[PAGEMAP_ENTRIES];
+ map2 < emap2; map2++)
+ if ( map2->block.p_index == pindex) {
+
+ block = pager_move_page(*map2);
+ if (!no_block(block))
+ *map2 = block;
+ else
+ return FALSE;
+ }
+
+ }
+ goto ok;
+ }
+
+ /* A small one */
+ for (emap = &map[size]; map < emap; map++)
+ if (map->block.p_index == pindex) {
+ block = pager_move_page(*map);
+ if (!no_block(block))
+ *map = block;
+ else
+ return FALSE;
+ }
+ok:
+ pager->cur_partition = choose_partition(0, P_INDEX_INVALID);
+ return TRUE;
+}
+
+/*
+
+ */
+
+/*
+ * Read/write routines.
+ */
+#define PAGER_SUCCESS 0
+#define PAGER_ABSENT 1
+#define PAGER_ERROR 2
+
+/*
+ * Read data from a default pager. Addr is the address of a buffer
+ * to fill. Out_addr returns the buffer that contains the data;
+ * if it is different from <addr>, it must be deallocated after use.
+ */
+int
+default_read(ds, addr, size, offset, out_addr, deallocate, external)
+ register dpager_t ds;
+ vm_offset_t addr; /* pointer to block to fill */
+ register vm_size_t size;
+ register vm_offset_t offset;
+ vm_offset_t *out_addr;
+ /* returns pointer to data */
+ boolean_t deallocate;
+ boolean_t external;
+{
+ register union dp_map block;
+ vm_offset_t raddr;
+ vm_size_t rsize;
+ register int rc;
+ boolean_t first_time;
+ register partition_t part;
+#ifdef CHECKSUM
+ vm_size_t original_size = size;
+#endif /* CHECKSUM */
+ vm_offset_t original_offset = offset;
+
+ /*
+ * Find the block in the paging partition
+ */
+ block = pager_read_offset(ds, offset);
+ if ( no_block(block) ) {
+ if (external) {
+ /*
+ * An external object is requesting unswapped data,
+ * zero fill the page and return.
+ */
+ bzero((char *) addr, vm_page_size);
+ *out_addr = addr;
+ return (PAGER_SUCCESS);
+ }
+ return (PAGER_ABSENT);
+ }
+
+ /*
+ * Read it, trying for the entire page.
+ */
+ offset = ptoa(block.block.p_offset);
+ddprintf ("default_read(%x,%x,%x,%d)\n",addr,size,offset,block.block.p_index);
+ part = partition_of(block.block.p_index);
+ first_time = TRUE;
+ *out_addr = addr;
+
+ do {
+ rc = page_read_file_direct(part->file,
+ offset,
+ size,
+ &raddr,
+ &rsize);
+ if (rc != 0)
+ return (PAGER_ERROR);
+
+ /*
+ * If we got the entire page on the first read, return it.
+ */
+ if (first_time && rsize == size) {
+ *out_addr = raddr;
+ break;
+ }
+ /*
+ * Otherwise, copy the data into the
+ * buffer we were passed, and try for
+ * the next piece.
+ */
+ first_time = FALSE;
+ bcopy((char *)raddr, (char *)addr, rsize);
+ addr += rsize;
+ offset += rsize;
+ size -= rsize;
+ } while (size != 0);
+
+#if USE_PRECIOUS
+ if (deallocate)
+ pager_release_offset(ds, original_offset);
+#endif /*USE_PRECIOUS*/
+
+#ifdef CHECKSUM
+ {
+ int write_checksum,
+ read_checksum;
+
+ write_checksum = pager_get_checksum(ds, original_offset);
+ read_checksum = compute_checksum(*out_addr, original_size);
+ if (write_checksum != read_checksum) {
+ panic(
+ "PAGER CHECKSUM ERROR: offset 0x%x, written 0x%x, read 0x%x",
+ original_offset, write_checksum, read_checksum);
+ }
+ }
+#endif /* CHECKSUM */
+ return (PAGER_SUCCESS);
+}
+
+int
+default_write(ds, addr, size, offset)
+ register dpager_t ds;
+ register vm_offset_t addr;
+ register vm_size_t size;
+ register vm_offset_t offset;
+{
+ register union dp_map block;
+ partition_t part;
+ vm_size_t wsize;
+ register int rc;
+
+ ddprintf ("default_write: pager offset %x\n", offset);
+
+ /*
+ * Find block in paging partition
+ */
+ block = pager_write_offset(ds, offset);
+ if ( no_block(block) )
+ return (PAGER_ERROR);
+
+#ifdef CHECKSUM
+ /*
+ * Save checksum
+ */
+ {
+ int checksum;
+
+ checksum = compute_checksum(addr, size);
+ pager_put_checksum(ds, offset, checksum);
+ }
+#endif /* CHECKSUM */
+ offset = ptoa(block.block.p_offset);
+ddprintf ("default_write(%x,%x,%x,%d)\n",addr,size,offset,block.block.p_index);
+ part = partition_of(block.block.p_index);
+
+ /*
+ * There are various assumptions made here,we
+ * will not get into the next disk 'block' by
+ * accident. It might well be non-contiguous.
+ */
+ do {
+ rc = page_write_file_direct(part->file,
+ offset,
+ addr,
+ size,
+ &wsize);
+ if (rc != 0) {
+ dprintf("*** PAGER ERROR: default_write: ");
+ dprintf("ds=0x%x addr=0x%x size=0x%x offset=0x%x resid=0x%x\n",
+ ds, addr, size, offset, wsize);
+ return (PAGER_ERROR);
+ }
+ addr += wsize;
+ offset += wsize;
+ size -= wsize;
+ } while (size != 0);
+ return (PAGER_SUCCESS);
+}
+
+boolean_t
+default_has_page(ds, offset)
+ dpager_t ds;
+ vm_offset_t offset;
+{
+ return ( ! no_block(pager_read_offset(ds, offset)) );
+}
+/*
+
+ */
+
+/*
+ * Mapping between pager port and paging object.
+ */
+struct dstruct {
+ queue_chain_t links; /* Link in pager-port list */
+
+ struct mutex lock; /* Lock for the structure */
+ struct condition
+ waiting_seqno, /* someone waiting on seqno */
+ waiting_read, /* someone waiting on readers */
+ waiting_write, /* someone waiting on writers */
+ waiting_refs; /* someone waiting on refs */
+
+ memory_object_t pager; /* Pager port */
+ mach_port_seqno_t seqno; /* Pager port sequence number */
+ mach_port_t pager_request; /* Request port */
+ mach_port_urefs_t request_refs; /* Request port user-refs */
+ mach_port_t pager_name; /* Name port */
+ mach_port_urefs_t name_refs; /* Name port user-refs */
+ boolean_t external; /* Is an external object? */
+
+ unsigned int readers; /* Reads in progress */
+ unsigned int writers; /* Writes in progress */
+
+ /* This is the reply port of an outstanding
+ default_pager_object_set_size call. */
+ mach_port_t lock_request;
+
+ unsigned int errors; /* Pageout error count */
+ struct dpager dpager; /* Actual pager */
+};
+typedef struct dstruct * default_pager_t;
+#define DEFAULT_PAGER_NULL ((default_pager_t)0)
+
+#if PARALLEL
+#define dstruct_lock_init(ds) mutex_init(&ds->lock)
+#define dstruct_lock(ds) mutex_lock(&ds->lock)
+#define dstruct_unlock(ds) mutex_unlock(&ds->lock)
+#else /* PARALLEL */
+#define dstruct_lock_init(ds)
+#define dstruct_lock(ds)
+#define dstruct_unlock(ds)
+#endif /* PARALLEL */
+
+/*
+ * List of all pagers. A specific pager is
+ * found directly via its port, this list is
+ * only used for monitoring purposes by the
+ * default_pager_object* calls
+ */
+struct pager_port {
+ queue_head_t queue;
+ struct mutex lock;
+ int count; /* saves code */
+ queue_head_t leak_queue;
+} all_pagers;
+
+#define pager_port_list_init() \
+{ \
+ mutex_init(&all_pagers.lock); \
+ queue_init(&all_pagers.queue); \
+ queue_init(&all_pagers.leak_queue); \
+ all_pagers.count = 0; \
+}
+
+void pager_port_list_insert(port, ds)
+ mach_port_t port;
+ default_pager_t ds;
+{
+ mutex_lock(&all_pagers.lock);
+ queue_enter(&all_pagers.queue, ds, default_pager_t, links);
+ all_pagers.count++;
+ mutex_unlock(&all_pagers.lock);
+}
+
+/* given a data structure return a good port-name to associate it to */
+#define pnameof(_x_) (((vm_offset_t)(_x_))+1)
+/* reverse, assumes no-odd-pointers */
+#define dnameof(_x_) (((vm_offset_t)(_x_))&~1)
+
+/* The magic typecast */
+#define pager_port_lookup(_port_) \
+ ((! MACH_PORT_VALID(_port_) || \
+ ((default_pager_t)dnameof(_port_))->pager != (_port_)) ? \
+ DEFAULT_PAGER_NULL : (default_pager_t)dnameof(_port_))
+
+void pager_port_list_delete(ds)
+ default_pager_t ds;
+{
+ mutex_lock(&all_pagers.lock);
+ queue_remove(&all_pagers.queue, ds, default_pager_t, links);
+ all_pagers.count--;
+ mutex_unlock(&all_pagers.lock);
+}
+
+/*
+ * Destroy a paging partition.
+ * XXX this is not re-entrant XXX
+ */
+kern_return_t
+destroy_paging_partition(name, pp_private)
+ char *name;
+ void **pp_private;
+{
+ register unsigned int id = part_id(name);
+ register partition_t part;
+ boolean_t all_ok = TRUE;
+ default_pager_t entry;
+ int pindex;
+
+ /*
+ * Find and take partition out of list
+ * This prevents choose_partition from
+ * getting in the way.
+ */
+ mutex_lock(&all_partitions.lock);
+ for (pindex = 0; pindex < all_partitions.n_partitions; pindex++) {
+ part = partition_of(pindex);
+ if (part && (part->id == id)) break;
+ }
+ if (pindex == all_partitions.n_partitions) {
+ mutex_unlock(&all_partitions.lock);
+ return KERN_INVALID_ARGUMENT;
+ }
+ part->going_away = TRUE;
+ mutex_unlock(&all_partitions.lock);
+
+ /*
+ * This might take a while..
+ */
+all_over_again:
+#if debug
+dprintf("Partition x%x (id x%x) for %s, all_ok %d\n", part, id, name, all_ok);
+#endif
+ all_ok = TRUE;
+ mutex_lock(&part->p_lock);
+
+ mutex_lock(&all_pagers.lock);
+ queue_iterate(&all_pagers.queue, entry, default_pager_t, links) {
+
+ dstruct_lock(entry);
+
+ if (!mutex_try_lock(&entry->dpager.lock)) {
+
+ dstruct_unlock(entry);
+ mutex_unlock(&all_pagers.lock);
+ mutex_unlock(&part->p_lock);
+
+ /* yield the processor */
+ (void) thread_switch(MACH_PORT_NULL,
+ SWITCH_OPTION_NONE, 0);
+
+ goto all_over_again;
+
+ }
+
+ /*
+ * See if we can relocate all the pages of this object
+ * currently on this partition on some other partition
+ */
+ all_ok = pager_realloc(&entry->dpager, pindex);
+
+ mutex_unlock(&entry->dpager.lock);
+ dstruct_unlock(entry);
+
+ if (!all_ok) break;
+
+ }
+ mutex_unlock(&all_pagers.lock);
+
+ if (all_ok) {
+ /* No need to unlock partition, there are no refs left */
+
+ set_partition_of(pindex, 0);
+ *pp_private = part->file;
+ kfree(part->bitmap, howmany(part->total_size, NB_BM) * sizeof(bm_entry_t));
+ kfree(part, sizeof(struct part));
+ dprintf("%s Removed paging partition %s\n", my_name, name);
+ return KERN_SUCCESS;
+ }
+
+ /*
+ * Put partition back in.
+ */
+ part->going_away = FALSE;
+
+ return KERN_FAILURE;
+}
+
+
+/*
+ * We use the sequence numbers on requests to regulate
+ * our parallelism. In general, we allow multiple reads and writes
+ * to proceed in parallel, with the exception that reads must
+ * wait for previous writes to finish. (Because the kernel might
+ * generate a data-request for a page on the heels of a data-write
+ * for the same page, and we must avoid returning stale data.)
+ * terminate requests wait for proceeding reads and writes to finish.
+ */
+
+unsigned int default_pager_total = 0; /* debugging */
+unsigned int default_pager_wait_seqno = 0; /* debugging */
+unsigned int default_pager_wait_read = 0; /* debugging */
+unsigned int default_pager_wait_write = 0; /* debugging */
+unsigned int default_pager_wait_refs = 0; /* debugging */
+
+#if PARALLEL
+/*
+ * Waits for correct sequence number. Leaves pager locked.
+ */
+void pager_port_lock(ds, seqno)
+ default_pager_t ds;
+ mach_port_seqno_t seqno;
+{
+ default_pager_total++;
+ddprintf ("pager_port_lock <%p>: <%p>: %d: 1\n", &ds, ds, seqno);
+ dstruct_lock(ds);
+ddprintf ("pager_port_lock <%p>: <%p>: %d: 2\n", &ds, ds, seqno);
+ while (ds->seqno != seqno) {
+ddprintf ("pager_port_lock <%p>: <%p>: %d: 3\n", &ds, ds, seqno);
+ default_pager_wait_seqno++;
+ condition_wait(&ds->waiting_seqno, &ds->lock);
+ddprintf ("pager_port_lock <%p>: <%p>: %d: 4\n", &ds, ds, seqno);
+ }
+}
+
+/*
+ * Increments sequence number and unlocks pager.
+ */
+void pager_port_unlock(ds)
+ default_pager_t ds;
+{
+ ds->seqno++;
+ddprintf ("pager_port_unlock <%p>: <%p>: seqno => %d\n", &ds, ds, ds->seqno);
+ dstruct_unlock(ds);
+ddprintf ("pager_port_unlock <%p>: <%p>: 2\n", &ds, ds);
+ condition_broadcast(&ds->waiting_seqno);
+ddprintf ("pager_port_unlock <%p>: <%p>: 3\n", &ds, ds);
+}
+
+/*
+ * Start a read - one more reader. Pager must be locked.
+ */
+void pager_port_start_read(ds)
+ default_pager_t ds;
+{
+ ds->readers++;
+}
+
+/*
+ * Wait for readers. Unlocks and relocks pager if wait needed.
+ */
+void pager_port_wait_for_readers(ds)
+ default_pager_t ds;
+{
+ while (ds->readers != 0) {
+ default_pager_wait_read++;
+ condition_wait(&ds->waiting_read, &ds->lock);
+ }
+}
+
+/*
+ * Finish a read. Pager is unlocked and returns unlocked.
+ */
+void pager_port_finish_read(ds)
+ default_pager_t ds;
+{
+ dstruct_lock(ds);
+ if (--ds->readers == 0) {
+ dstruct_unlock(ds);
+ condition_broadcast(&ds->waiting_read);
+ }
+ else {
+ dstruct_unlock(ds);
+ }
+}
+
+/*
+ * Start a write - one more writer. Pager must be locked.
+ */
+void pager_port_start_write(ds)
+ default_pager_t ds;
+{
+ ds->writers++;
+}
+
+/*
+ * Wait for writers. Unlocks and relocks pager if wait needed.
+ */
+void pager_port_wait_for_writers(ds)
+ default_pager_t ds;
+{
+ while (ds->writers != 0) {
+ default_pager_wait_write++;
+ condition_wait(&ds->waiting_write, &ds->lock);
+ }
+}
+
+/*
+ * Finish a write. Pager is unlocked and returns unlocked.
+ */
+void pager_port_finish_write(ds)
+ default_pager_t ds;
+{
+ dstruct_lock(ds);
+ if (--ds->writers == 0) {
+ dstruct_unlock(ds);
+ condition_broadcast(&ds->waiting_write);
+ }
+ else {
+ dstruct_unlock(ds);
+ }
+}
+
+/*
+ * Wait for concurrent default_pager_objects.
+ * Unlocks and relocks pager if wait needed.
+ */
+void pager_port_wait_for_refs(ds)
+ default_pager_t ds;
+{
+ while (ds->name_refs == 0) {
+ default_pager_wait_refs++;
+ condition_wait(&ds->waiting_refs, &ds->lock);
+ }
+}
+
+/*
+ * Finished creating name refs - wake up waiters.
+ */
+void pager_port_finish_refs(ds)
+ default_pager_t ds;
+{
+ condition_broadcast(&ds->waiting_refs);
+}
+
+#else /* PARALLEL */
+
+#define pager_port_lock(ds,seqno)
+#define pager_port_unlock(ds)
+#define pager_port_start_read(ds)
+#define pager_port_wait_for_readers(ds)
+#define pager_port_finish_read(ds)
+#define pager_port_start_write(ds)
+#define pager_port_wait_for_writers(ds)
+#define pager_port_finish_write(ds)
+#define pager_port_wait_for_refs(ds)
+#define pager_port_finish_refs(ds)
+
+#endif /* PARALLEL */
+
+/*
+ * Default pager.
+ */
+task_t default_pager_self; /* Our task port. */
+
+mach_port_t default_pager_default_port; /* Port for memory_object_create. */
+
+/* We catch exceptions on ourself & startup using this port. */
+mach_port_t default_pager_exception_port;
+
+mach_port_t default_pager_internal_set; /* Port set for internal objects. */
+mach_port_t default_pager_external_set; /* Port set for external objects. */
+mach_port_t default_pager_default_set; /* Port set for "default" thread. */
+
+typedef struct default_pager_thread {
+ cthread_t dpt_thread; /* Server thread. */
+ vm_offset_t dpt_buffer; /* Read buffer. */
+ boolean_t dpt_internal; /* Do we handle internal objects? */
+} default_pager_thread_t;
+
+#if PARALLEL
+ /* determine number of threads at run time */
+#define DEFAULT_PAGER_INTERNAL_COUNT (0)
+
+#else /* PARALLEL */
+#define DEFAULT_PAGER_INTERNAL_COUNT (1)
+#endif /* PARALLEL */
+
+/* Memory created by default_pager_object_create should mostly be resident. */
+#define DEFAULT_PAGER_EXTERNAL_COUNT (1)
+
+unsigned int default_pager_internal_count = DEFAULT_PAGER_INTERNAL_COUNT;
+ /* Number of "internal" threads. */
+unsigned int default_pager_external_count = DEFAULT_PAGER_EXTERNAL_COUNT;
+ /* Number of "external" threads. */
+
+default_pager_t pager_port_alloc(size)
+ vm_size_t size;
+{
+ default_pager_t ds;
+ p_index_t part;
+
+ ds = (default_pager_t) kalloc(sizeof *ds);
+ if (ds == DEFAULT_PAGER_NULL)
+ panic("%spager_port_alloc",my_name);
+ bzero((char *) ds, sizeof *ds);
+
+ dstruct_lock_init(ds);
+
+ /*
+ * Get a suitable partition. If none big enough
+ * just pick one and overcommit. If no partitions
+ * at all.. well just fake one so that we will
+ * kill specific objects on pageouts rather than
+ * panicing the system now.
+ */
+ part = choose_partition(size, P_INDEX_INVALID);
+ if (no_partition(part)) {
+ overcommitted(FALSE, atop(size));
+ part = choose_partition(0,P_INDEX_INVALID);
+#if debug
+ if (no_partition(part))
+ dprintf("%s No paging space at all !!\n", my_name);
+#endif
+ }
+ pager_alloc(&ds->dpager, part, size);
+
+ return ds;
+}
+
+mach_port_urefs_t default_pager_max_urefs = 10000;
+
+/*
+ * Check user reference count on pager_request port.
+ * Pager must be locked.
+ * Unlocks and re-locks pager if needs to call kernel.
+ */
+void pager_port_check_request(ds, pager_request)
+ default_pager_t ds;
+ mach_port_t pager_request;
+{
+ mach_port_delta_t delta;
+ kern_return_t kr;
+
+ assert(ds->pager_request == pager_request);
+
+ if (++ds->request_refs > default_pager_max_urefs) {
+ delta = 1 - ds->request_refs;
+ ds->request_refs = 1;
+
+ dstruct_unlock(ds);
+
+ /*
+ * Deallocate excess user references.
+ */
+
+ kr = mach_port_mod_refs(default_pager_self, pager_request,
+ MACH_PORT_RIGHT_SEND, delta);
+ if (kr != KERN_SUCCESS)
+ panic("%spager_port_check_request",my_name);
+
+ dstruct_lock(ds);
+ }
+}
+
+void default_pager_add(ds, internal)
+ default_pager_t ds;
+ boolean_t internal;
+{
+ mach_port_t pager = ds->pager;
+ mach_port_t pset;
+ mach_port_mscount_t sync;
+ mach_port_t previous;
+ kern_return_t kr;
+ static char here[] = "%sdefault_pager_add";
+
+ /*
+ * The port currently has a make-send count of zero,
+ * because either we just created the port or we just
+ * received the port in a memory_object_create request.
+ */
+
+ if (internal) {
+ /* possibly generate an immediate no-senders notification */
+ sync = 0;
+ pset = default_pager_internal_set;
+ ds->external = FALSE;
+ } else {
+ /* delay notification till send right is created */
+ sync = 1;
+ pset = default_pager_external_set;
+ ds->external = TRUE;
+ }
+
+ kr = mach_port_request_notification(default_pager_self, pager,
+ MACH_NOTIFY_NO_SENDERS, sync,
+ pager, MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &previous);
+ if ((kr != KERN_SUCCESS) || (previous != MACH_PORT_NULL))
+ panic(here,my_name);
+
+ kr = mach_port_move_member(default_pager_self, pager, pset);
+ if (kr != KERN_SUCCESS)
+ panic(here,my_name);
+}
+
+/*
+ * Routine: memory_object_create
+ * Purpose:
+ * Handle requests for memory objects from the
+ * kernel.
+ * Notes:
+ * Because we only give out the default memory
+ * manager port to the kernel, we don't have to
+ * be so paranoid about the contents.
+ */
+kern_return_t
+seqnos_memory_object_create(old_pager, seqno, new_pager, new_size,
+ new_pager_request, new_pager_name, new_page_size)
+ mach_port_t old_pager;
+ mach_port_seqno_t seqno;
+ mach_port_t new_pager;
+ vm_size_t new_size;
+ mach_port_t new_pager_request;
+ mach_port_t new_pager_name;
+ vm_size_t new_page_size;
+{
+ register default_pager_t ds;
+ kern_return_t kr;
+
+ assert(old_pager == default_pager_default_port);
+ assert(MACH_PORT_VALID(new_pager_request));
+ assert(MACH_PORT_VALID(new_pager_name));
+ assert(new_page_size == vm_page_size);
+
+ ds = pager_port_alloc(new_size);
+rename_it:
+ kr = mach_port_rename( default_pager_self,
+ new_pager, (mach_port_t)pnameof(ds));
+ if (kr != KERN_SUCCESS) {
+ default_pager_t ds1;
+
+ if (kr != KERN_NAME_EXISTS)
+ panic("%s m_o_create", my_name);
+ ds1 = (default_pager_t) kalloc(sizeof *ds1);
+ *ds1 = *ds;
+ mutex_lock(&all_pagers.lock);
+ queue_enter(&all_pagers.leak_queue, ds, default_pager_t, links);
+ mutex_unlock(&all_pagers.lock);
+ ds = ds1;
+ goto rename_it;
+ }
+
+ new_pager = (mach_port_t) pnameof(ds);
+
+ /*
+ * Set up associations between these ports
+ * and this default_pager structure
+ */
+
+ ds->pager = new_pager;
+ ds->pager_request = new_pager_request;
+ ds->request_refs = 1;
+ ds->pager_name = new_pager_name;
+ ds->name_refs = 1;
+
+ /*
+ * After this, other threads might receive requests
+ * for this memory object or find it in the port list.
+ */
+
+ pager_port_list_insert(new_pager, ds);
+ default_pager_add(ds, TRUE);
+
+ return(KERN_SUCCESS);
+}
+
+memory_object_copy_strategy_t default_pager_copy_strategy =
+ MEMORY_OBJECT_COPY_DELAY;
+
+kern_return_t
+seqnos_memory_object_init(pager, seqno, pager_request, pager_name,
+ pager_page_size)
+ mach_port_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t pager_request;
+ mach_port_t pager_name;
+ vm_size_t pager_page_size;
+{
+ register default_pager_t ds;
+ kern_return_t kr;
+ static char here[] = "%sinit";
+
+ assert(MACH_PORT_VALID(pager_request));
+ assert(MACH_PORT_VALID(pager_name));
+ assert(pager_page_size == vm_page_size);
+
+ ds = pager_port_lookup(pager);
+ if (ds == DEFAULT_PAGER_NULL)
+ panic(here, my_name);
+ pager_port_lock(ds, seqno);
+
+ if (ds->pager_request != MACH_PORT_NULL)
+ panic(here, my_name);
+
+ ds->pager_request = pager_request;
+ ds->request_refs = 1;
+ ds->pager_name = pager_name;
+ ds->name_refs = 1;
+
+ /*
+ * Even if the kernel immediately terminates the object,
+ * the pager_request port won't be destroyed until
+ * we process the terminate request, which won't happen
+ * until we unlock the object.
+ */
+
+ kr = memory_object_set_attributes(pager_request,
+ TRUE,
+ FALSE, /* do not cache */
+ default_pager_copy_strategy);
+ if (kr != KERN_SUCCESS)
+ panic(here, my_name);
+
+ pager_port_unlock(ds);
+
+ return(KERN_SUCCESS);
+}
+
+kern_return_t
+seqnos_memory_object_terminate(pager, seqno, pager_request, pager_name)
+ mach_port_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t pager_request;
+ mach_port_t pager_name;
+{
+ register default_pager_t ds;
+ mach_port_urefs_t request_refs, name_refs;
+ kern_return_t kr;
+ static char here[] = "%sterminate";
+
+ /*
+ * pager_request and pager_name are receive rights,
+ * not send rights.
+ */
+
+ ds = pager_port_lookup(pager);
+ if (ds == DEFAULT_PAGER_NULL)
+ panic(here, my_name);
+ddprintf ("seqnos_memory_object_terminate <%p>: pager_port_lock: <%p>[s:%d,r:%d,w:%d,l:%d], %d\n",
+ &kr, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held, seqno);
+ pager_port_lock(ds, seqno);
+
+ /*
+ * Wait for read and write requests to terminate.
+ */
+
+ pager_port_wait_for_readers(ds);
+ pager_port_wait_for_writers(ds);
+
+ /*
+ * After memory_object_terminate both memory_object_init
+ * and a no-senders notification are possible, so we need
+ * to clean up the request and name ports but leave
+ * the pager port.
+ *
+ * A concurrent default_pager_objects might be allocating
+ * more references for the name port. In this case,
+ * we must first wait for it to finish.
+ */
+
+ pager_port_wait_for_refs(ds);
+
+ if (ds->external)
+ pager_request = ds->pager_request;
+ ds->pager_request = MACH_PORT_NULL;
+ request_refs = ds->request_refs;
+ ds->request_refs = 0;
+ assert(ds->pager_name == pager_name);
+ ds->pager_name = MACH_PORT_NULL;
+ name_refs = ds->name_refs;
+ ds->name_refs = 0;
+ddprintf ("seqnos_memory_object_terminate <%p>: pager_port_unlock: <%p>[s:%d,r:%d,w:%d,l:%d]\n",
+ &kr, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held);
+ pager_port_unlock(ds);
+
+ /*
+ * Now we destroy our port rights.
+ */
+
+ mach_port_destroy(mach_task_self(), pager_request);
+ mach_port_destroy(mach_task_self(), pager_name);
+
+ return (KERN_SUCCESS);
+}
+
+void default_pager_no_senders(pager, seqno, mscount)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_mscount_t mscount;
+{
+ register default_pager_t ds;
+ kern_return_t kr;
+ static char here[] = "%sno_senders";
+
+ /*
+ * Because we don't give out multiple send rights
+ * for a memory object, there can't be a race
+ * between getting a no-senders notification
+ * and creating a new send right for the object.
+ * Hence we don't keep track of mscount.
+ */
+
+
+ ds = pager_port_lookup(pager);
+ if (ds == DEFAULT_PAGER_NULL)
+ panic(here,my_name);
+ pager_port_lock(ds, seqno);
+
+ /*
+ * We shouldn't get a no-senders notification
+ * when the kernel has the object cached.
+ */
+
+ if (ds->pager_request != MACH_PORT_NULL)
+ panic(here,my_name);
+
+ /*
+ * Unlock the pager (though there should be no one
+ * waiting for it).
+ */
+ dstruct_unlock(ds);
+
+ /*
+ * Remove the memory object port association, and then
+ * the destroy the port itself. We must remove the object
+ * from the port list before deallocating the pager,
+ * because of default_pager_objects.
+ */
+
+ pager_port_list_delete(ds);
+ pager_dealloc(&ds->dpager);
+
+ kr = mach_port_mod_refs(default_pager_self, pager,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ if (kr != KERN_SUCCESS)
+ panic(here,my_name);
+
+ /*
+ * Do this *after* deallocating the port name
+ */
+ kfree((char *) ds, sizeof(*ds));
+
+ /*
+ * Recover memory that we might have wasted because
+ * of name conflicts
+ */
+ mutex_lock(&all_pagers.lock);
+
+ while (!queue_empty(&all_pagers.leak_queue)) {
+
+ ds = (default_pager_t) queue_first(&all_pagers.leak_queue);
+ queue_remove_first(&all_pagers.leak_queue, ds, default_pager_t, links);
+ kfree((char *) ds, sizeof(*ds));
+ }
+
+ mutex_unlock(&all_pagers.lock);
+}
+
+int default_pager_pagein_count = 0;
+int default_pager_pageout_count = 0;
+
+kern_return_t
+seqnos_memory_object_data_request(pager, seqno, reply_to, offset,
+ length, protection_required)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t reply_to;
+ vm_offset_t offset;
+ vm_size_t length;
+ vm_prot_t protection_required;
+{
+ default_pager_thread_t *dpt;
+ default_pager_t ds;
+ vm_offset_t addr;
+ unsigned int errors;
+ kern_return_t rc;
+ static char here[] = "%sdata_request";
+
+ dpt = (default_pager_thread_t *) cthread_data(cthread_self());
+
+ if (length != vm_page_size)
+ panic(here,my_name);
+
+ ds = pager_port_lookup(pager);
+ if (ds == DEFAULT_PAGER_NULL)
+ panic(here,my_name);
+ddprintf ("seqnos_memory_object_data_request <%p>: pager_port_lock: <%p>[s:%d,r:%d,w:%d,l:%d], %d\n",
+ &ds, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held, seqno);
+ pager_port_lock(ds, seqno);
+ pager_port_check_request(ds, reply_to);
+ pager_port_wait_for_writers(ds);
+ pager_port_start_read(ds);
+
+ /*
+ * Get error count while pager locked.
+ */
+ errors = ds->errors;
+
+ddprintf ("seqnos_memory_object_data_request <%p>: pager_port_unlock: <%p>[s:%d,r:%d,w:%d,l:%d]\n",
+ &ds, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held);
+ pager_port_unlock(ds);
+
+ if (errors) {
+ dprintf("%s %s\n", my_name,
+ "dropping data_request because of previous paging errors");
+ (void) memory_object_data_error(reply_to,
+ offset, vm_page_size,
+ KERN_FAILURE);
+ goto done;
+ }
+
+ if (offset >= ds->dpager.limit)
+ rc = PAGER_ERROR;
+ else
+ rc = default_read(&ds->dpager, dpt->dpt_buffer,
+ vm_page_size, offset,
+ &addr, protection_required & VM_PROT_WRITE,
+ ds->external);
+
+ switch (rc) {
+ case PAGER_SUCCESS:
+ if (addr != dpt->dpt_buffer) {
+ /*
+ * Deallocates data buffer
+ */
+ (void) memory_object_data_supply(
+ reply_to, offset,
+ addr, vm_page_size, TRUE,
+ VM_PROT_NONE,
+ FALSE, MACH_PORT_NULL);
+ } else {
+ (void) memory_object_data_provided(
+ reply_to, offset,
+ addr, vm_page_size,
+ VM_PROT_NONE);
+ }
+ break;
+
+ case PAGER_ABSENT:
+ (void) memory_object_data_unavailable(
+ reply_to,
+ offset,
+ vm_page_size);
+ break;
+
+ case PAGER_ERROR:
+ (void) memory_object_data_error(
+ reply_to,
+ offset,
+ vm_page_size,
+ KERN_FAILURE);
+ break;
+ }
+
+ default_pager_pagein_count++;
+
+ done:
+ pager_port_finish_read(ds);
+ return(KERN_SUCCESS);
+}
+
+/*
+ * memory_object_data_initialize: check whether we already have each page, and
+ * write it if we do not. The implementation is far from optimized, and
+ * also assumes that the default_pager is single-threaded.
+ */
+kern_return_t
+seqnos_memory_object_data_initialize(pager, seqno, pager_request,
+ offset, addr, data_cnt)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t pager_request;
+ register
+ vm_offset_t offset;
+ register
+ pointer_t addr;
+ vm_size_t data_cnt;
+{
+ vm_offset_t amount_sent;
+ default_pager_t ds;
+ static char here[] = "%sdata_initialize";
+
+#ifdef lint
+ pager_request++;
+#endif /* lint */
+
+ ds = pager_port_lookup(pager);
+ if (ds == DEFAULT_PAGER_NULL)
+ panic(here,my_name);
+ddprintf ("seqnos_memory_object_data_initialize <%p>: pager_port_lock: <%p>[s:%d,r:%d,w:%d,l:%d], %d\n",
+ &ds, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held, seqno);
+ pager_port_lock(ds, seqno);
+ pager_port_check_request(ds, pager_request);
+ pager_port_start_write(ds);
+ddprintf ("seqnos_memory_object_data_initialize <%p>: pager_port_unlock: <%p>[s:%d,r:%d,w:%d,l:%d]\n",
+ &ds, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held);
+ pager_port_unlock(ds);
+
+ for (amount_sent = 0;
+ amount_sent < data_cnt;
+ amount_sent += vm_page_size) {
+
+ if (!default_has_page(&ds->dpager, offset + amount_sent)) {
+ if (default_write(&ds->dpager,
+ addr + amount_sent,
+ vm_page_size,
+ offset + amount_sent)
+ != PAGER_SUCCESS) {
+ dprintf("%s%s write error\n", my_name, here);
+ dstruct_lock(ds);
+ ds->errors++;
+ dstruct_unlock(ds);
+ }
+ }
+ }
+
+ pager_port_finish_write(ds);
+ if (vm_deallocate(default_pager_self, addr, data_cnt) != KERN_SUCCESS)
+ panic(here,my_name);
+
+ return(KERN_SUCCESS);
+}
+
+/*
+ * memory_object_data_write: split up the stuff coming in from
+ * a memory_object_data_write call
+ * into individual pages and pass them off to default_write.
+ */
+kern_return_t
+seqnos_memory_object_data_write(pager, seqno, pager_request,
+ offset, addr, data_cnt)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t pager_request;
+ register
+ vm_offset_t offset;
+ register
+ pointer_t addr;
+ vm_size_t data_cnt;
+{
+ register
+ vm_size_t amount_sent;
+ default_pager_t ds;
+ static char here[] = "%sdata_write";
+ int err;
+
+#ifdef lint
+ pager_request++;
+#endif /* lint */
+
+ddprintf ("seqnos_memory_object_data_write <%p>: 1\n", &err);
+ if ((data_cnt % vm_page_size) != 0)
+ {
+ ddprintf ("fail 1: %d %d\n", data_cnt, vm_page_size);
+ panic(here,my_name);
+ }
+
+
+ddprintf ("seqnos_memory_object_data_write <%p>: 2\n", &err);
+ ds = pager_port_lookup(pager);
+ddprintf ("seqnos_memory_object_data_write <%p>: 3\n", &err);
+ if (ds == DEFAULT_PAGER_NULL)
+ {
+ ddprintf ("fail 2: %d %d\n", pager, ds);
+ panic(here,my_name);
+ }
+
+ddprintf ("seqnos_memory_object_data_write <%p>: 4\n", &err);
+ddprintf ("seqnos_memory_object_data_write <%p>: pager_port_lock: <%p>[s:%d,r:%d,w:%d,l:%d], %d\n",
+ &err, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held, seqno);
+ pager_port_lock(ds, seqno);
+ddprintf ("seqnos_memory_object_data_write <%p>: 5\n", &err);
+ pager_port_check_request(ds, pager_request);
+ddprintf ("seqnos_memory_object_data_write <%p>: 6\n", &err);
+ pager_port_start_write(ds);
+ddprintf ("seqnos_memory_object_data_write <%p>: 7\n", &err);
+ddprintf ("seqnos_memory_object_data_write <%p>: pager_port_unlock: <%p>[s:%d,r:%d,w:%d,l:%d]\n",
+ &err, ds, ds->seqno, ds->readers, ds->writers, ds->lock.held);
+ pager_port_unlock(ds);
+
+ddprintf ("seqnos_memory_object_data_write <%p>: 8\n", &err);
+ for (amount_sent = 0;
+ amount_sent < data_cnt;
+ amount_sent += vm_page_size) {
+
+ register int result;
+
+ddprintf ("seqnos_memory_object_data_write <%p>: 9\n", &err);
+ result = default_write(&ds->dpager,
+ addr + amount_sent,
+ vm_page_size,
+ offset + amount_sent);
+ddprintf ("seqnos_memory_object_data_write <%p>: 10\n", &err);
+ if (result != KERN_SUCCESS) {
+ddprintf ("seqnos_memory_object_data_write <%p>: 11\n", &err);
+#if debug
+ dprintf("%s WRITE ERROR on default_pageout:", my_name);
+ dprintf(" pager=%x, offset=0x%x, length=0x%x, result=%d\n",
+ pager, offset+amount_sent, vm_page_size, result);
+#endif
+ dstruct_lock(ds);
+ ds->errors++;
+ dstruct_unlock(ds);
+ }
+ default_pager_pageout_count++;
+ }
+
+ddprintf ("seqnos_memory_object_data_write <%p>: 12\n", &err);
+ pager_port_finish_write(ds);
+ddprintf ("seqnos_memory_object_data_write <%p>: 13\n", &err);
+ err = vm_deallocate(default_pager_self, addr, data_cnt);
+ddprintf ("seqnos_memory_object_data_write <%p>: 14\n", &err);
+ if (err != KERN_SUCCESS)
+ {
+ ddprintf ("fail 3: %s %s %s %s\n", default_pager_self, addr, data_cnt, &err);
+
+ panic(here,my_name);
+ }
+
+
+ddprintf ("seqnos_memory_object_data_write <%p>: 15\n", &err);
+ return(KERN_SUCCESS);
+}
+
+/*ARGSUSED*/
+kern_return_t
+seqnos_memory_object_copy(old_memory_object, seqno, old_memory_control,
+ offset, length, new_memory_object)
+ memory_object_t old_memory_object;
+ mach_port_seqno_t seqno;
+ memory_object_control_t
+ old_memory_control;
+ vm_offset_t offset;
+ vm_size_t length;
+ memory_object_t new_memory_object;
+{
+ panic("%scopy", my_name);
+ return KERN_FAILURE;
+}
+
+/* We get this when our memory_object_lock_request has completed
+ after we truncated an object. */
+kern_return_t
+seqnos_memory_object_lock_completed (memory_object_t pager,
+ mach_port_seqno_t seqno,
+ mach_port_t pager_request,
+ vm_offset_t offset,
+ vm_size_t length)
+{
+ default_pager_t ds;
+
+ ds = pager_port_lookup(pager);
+ assert(ds != DEFAULT_PAGER_NULL);
+
+ pager_port_lock(ds, seqno);
+ pager_port_wait_for_readers(ds);
+ pager_port_wait_for_writers(ds);
+
+ /* Now that any in-core pages have been flushed, we can apply
+ the limit to prevent any new page-ins. */
+ assert (page_aligned (offset));
+ ds->dpager.limit = offset;
+
+ default_pager_object_set_size_reply (ds->lock_request, KERN_SUCCESS);
+ ds->lock_request = MACH_PORT_NULL;
+
+ if (ds->dpager.size > ds->dpager.limit / vm_page_size)
+ /* Deallocate the old backing store pages and shrink the page map. */
+ pager_truncate (&ds->dpager, ds->dpager.limit / vm_page_size);
+
+ pager_port_unlock(ds);
+
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+seqnos_memory_object_data_unlock(pager, seqno, pager_request,
+ offset, addr, data_cnt)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t pager_request;
+ vm_offset_t offset;
+ pointer_t addr;
+ vm_size_t data_cnt;
+{
+ panic("%sdata_unlock",my_name);
+ return(KERN_FAILURE);
+}
+
+kern_return_t
+seqnos_memory_object_supply_completed(pager, seqno, pager_request,
+ offset, length,
+ result, error_offset)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t pager_request;
+ vm_offset_t offset;
+ vm_size_t length;
+ kern_return_t result;
+ vm_offset_t error_offset;
+{
+ panic("%ssupply_completed",my_name);
+ return(KERN_FAILURE);
+}
+
+/*
+ * memory_object_data_return: split up the stuff coming in from
+ * a memory_object_data_write call
+ * into individual pages and pass them off to default_write.
+ */
+kern_return_t
+seqnos_memory_object_data_return(pager, seqno, pager_request,
+ offset, addr, data_cnt,
+ dirty, kernel_copy)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ mach_port_t pager_request;
+ vm_offset_t offset;
+ pointer_t addr;
+ vm_size_t data_cnt;
+ boolean_t dirty;
+ boolean_t kernel_copy;
+{
+ panic("%sdata_return",my_name);
+ return(KERN_FAILURE);
+}
+
+kern_return_t
+seqnos_memory_object_change_completed(pager, seqno, may_cache, copy_strategy)
+ memory_object_t pager;
+ mach_port_seqno_t seqno;
+ boolean_t may_cache;
+ memory_object_copy_strategy_t copy_strategy;
+{
+ panic("%schange_completed",my_name);
+ return(KERN_FAILURE);
+}
+
+
+boolean_t default_pager_notify_server(in, out)
+ mach_msg_header_t *in, *out;
+{
+ register mach_no_senders_notification_t *n =
+ (mach_no_senders_notification_t *) in;
+
+ /*
+ * The only send-once rights we create are for
+ * receiving no-more-senders notifications.
+ * Hence, if we receive a message directed to
+ * a send-once right, we can assume it is
+ * a genuine no-senders notification from the kernel.
+ */
+
+ if ((n->not_header.msgh_bits !=
+ MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE)) ||
+ (n->not_header.msgh_id != MACH_NOTIFY_NO_SENDERS))
+ return FALSE;
+
+ assert(n->not_header.msgh_size == sizeof *n);
+ assert(n->not_header.msgh_remote_port == MACH_PORT_NULL);
+
+ assert(n->not_type.msgt_name == MACH_MSG_TYPE_INTEGER_32);
+ assert(n->not_type.msgt_size == 32);
+ assert(n->not_type.msgt_number == 1);
+ assert(n->not_type.msgt_inline);
+ assert(! n->not_type.msgt_longform);
+
+ default_pager_no_senders(n->not_header.msgh_local_port,
+ n->not_header.msgh_seqno, n->not_count);
+
+ out->msgh_remote_port = MACH_PORT_NULL;
+ return TRUE;
+}
+
+extern boolean_t seqnos_memory_object_server();
+extern boolean_t seqnos_memory_object_default_server();
+extern boolean_t default_pager_server();
+extern boolean_t exc_server();
+extern boolean_t bootstrap_server();
+extern void bootstrap_compat();
+
+mach_msg_size_t default_pager_msg_size_object = 128;
+
+boolean_t
+default_pager_demux_object(in, out)
+ mach_msg_header_t *in;
+ mach_msg_header_t *out;
+{
+ /*
+ * We receive memory_object_data_initialize messages in
+ * the memory_object_default interface.
+ */
+
+int rval;
+ddprintf ("DPAGER DEMUX OBJECT <%p>: %d\n", in, in->msgh_id);
+rval =
+ (seqnos_memory_object_server(in, out) ||
+ seqnos_memory_object_default_server(in, out) ||
+ default_pager_notify_server(in, out) ||
+ default_pager_server(in, out));
+ddprintf ("DPAGER DEMUX OBJECT DONE <%p>: %d\n", in, in->msgh_id);
+return rval;
+}
+
+mach_msg_size_t default_pager_msg_size_default = 8 * 1024;
+
+boolean_t
+default_pager_demux_default(in, out)
+ mach_msg_header_t *in;
+ mach_msg_header_t *out;
+{
+ if (in->msgh_local_port == default_pager_default_port) {
+ /*
+ * We receive memory_object_create messages in
+ * the memory_object_default interface.
+ */
+
+int rval;
+ddprintf ("DPAGER DEMUX DEFAULT <%p>: %d\n", in, in->msgh_id);
+rval =
+ (seqnos_memory_object_default_server(in, out) ||
+ default_pager_server(in, out));
+ddprintf ("DPAGER DEMUX DEFAULT DONE <%p>: %d\n", in, in->msgh_id);
+return rval;
+ } else if (in->msgh_local_port == default_pager_exception_port) {
+ /*
+ * We receive exception messages for
+ * ourself and the startup task.
+ */
+
+ return exc_server(in, out);
+ } else {
+ panic(my_name);
+ return FALSE;
+ }
+}
+
+/*
+ * We use multiple threads, for two reasons.
+ *
+ * First, memory objects created by default_pager_object_create
+ * are "external", instead of "internal". This means the kernel
+ * sends data (memory_object_data_write) to the object pageable.
+ * To prevent deadlocks, the external and internal objects must
+ * be managed by different threads.
+ *
+ * Second, the default pager uses synchronous IO operations.
+ * Spreading requests across multiple threads should
+ * recover some of the performance loss from synchronous IO.
+ *
+ * We have 3+ threads.
+ * One receives memory_object_create and
+ * default_pager_object_create requests.
+ * One or more manage internal objects.
+ * One or more manage external objects.
+ */
+
+void
+default_pager_thread_privileges()
+{
+ /*
+ * Set thread privileges.
+ */
+ cthread_wire(); /* attach kernel thread to cthread */
+ wire_thread(); /* grab a kernel stack and memory allocation
+ privileges */
+}
+
+any_t
+default_pager_default_thread (arg)
+ any_t arg;
+{
+ kern_return_t kr;
+ default_pager_thread_privileges ();
+ for (;;) {
+ kr = mach_msg_server(default_pager_demux_default,
+ default_pager_msg_size_default,
+ default_pager_default_set);
+ panic(my_name, kr);
+ }
+}
+
+
+
+any_t
+default_pager_thread(arg)
+ any_t arg;
+{
+ default_pager_thread_t *dpt = (default_pager_thread_t *) arg;
+ mach_port_t pset;
+ kern_return_t kr;
+
+ cthread_set_data(cthread_self(), (any_t) dpt);
+
+
+ /*
+ * Threads handling external objects cannot have
+ * privileges. Otherwise a burst of data-requests for an
+ * external object could empty the free-page queue,
+ * because the fault code only reserves real pages for
+ * requests sent to internal objects.
+ */
+
+ if (dpt->dpt_internal) {
+ default_pager_thread_privileges();
+ pset = default_pager_internal_set;
+ } else {
+ pset = default_pager_external_set;
+ }
+
+ for (;;) {
+ kr = mach_msg_server(default_pager_demux_object,
+ default_pager_msg_size_object,
+ pset);
+ panic(my_name, kr);
+ }
+}
+
+void
+start_default_pager_thread(internal)
+ boolean_t internal;
+{
+ default_pager_thread_t *dpt;
+ kern_return_t kr;
+
+ dpt = (default_pager_thread_t *) kalloc(sizeof *dpt);
+ if (dpt == 0)
+ panic(my_name);
+
+ dpt->dpt_internal = internal;
+
+ kr = vm_allocate(default_pager_self, &dpt->dpt_buffer,
+ vm_page_size, TRUE);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+ wire_memory(dpt->dpt_buffer, vm_page_size,
+ VM_PROT_READ|VM_PROT_WRITE);
+
+ dpt->dpt_thread = cthread_fork(default_pager_thread, (any_t) dpt);
+}
+
+void
+default_pager_initialize(host_port)
+ mach_port_t host_port;
+{
+ memory_object_t DMM;
+ kern_return_t kr;
+
+ /*
+ * This task will become the default pager.
+ */
+ default_pager_self = mach_task_self();
+
+ /*
+ * Initialize the "default pager" port.
+ */
+ kr = mach_port_allocate(default_pager_self, MACH_PORT_RIGHT_RECEIVE,
+ &default_pager_default_port);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+
+ DMM = default_pager_default_port;
+ kr = vm_set_default_memory_manager(host_port, &DMM);
+ if ((kr != KERN_SUCCESS) || MACH_PORT_VALID(DMM))
+ panic(my_name);
+
+ /*
+ * Initialize the exception port.
+ */
+ kr = mach_port_allocate(default_pager_self, MACH_PORT_RIGHT_RECEIVE,
+ &default_pager_exception_port);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+
+ /*
+ * Arrange for wiring privileges.
+ */
+ wire_setup(host_port);
+
+ /*
+ * Find out how many CPUs we have, to determine the number
+ * of threads to create.
+ */
+ if (default_pager_internal_count == 0) {
+ host_basic_info_data_t h_info;
+ natural_t h_info_count;
+
+ h_info_count = HOST_BASIC_INFO_COUNT;
+ (void) host_info(host_port, HOST_BASIC_INFO,
+ (host_info_t)&h_info, &h_info_count);
+
+ /*
+ * Random computation to get more parallelism on
+ * multiprocessors.
+ */
+ default_pager_internal_count =
+ (h_info.avail_cpus > 32 ? 32 : h_info.avail_cpus) / 4 + 3;
+ }
+}
+
+/*
+ * Initialize and Run the default pager
+ */
+void
+default_pager()
+{
+ kern_return_t kr;
+ int i;
+
+ default_pager_thread_privileges();
+
+ /*
+ * Wire down code, data, stack
+ */
+ wire_all_memory();
+
+
+ /*
+ * Initialize the list of all pagers.
+ */
+ pager_port_list_init();
+
+ kr = mach_port_allocate(default_pager_self, MACH_PORT_RIGHT_PORT_SET,
+ &default_pager_internal_set);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+
+ kr = mach_port_allocate(default_pager_self, MACH_PORT_RIGHT_PORT_SET,
+ &default_pager_external_set);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+
+ kr = mach_port_allocate(default_pager_self, MACH_PORT_RIGHT_PORT_SET,
+ &default_pager_default_set);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+
+ kr = mach_port_move_member(default_pager_self,
+ default_pager_default_port,
+ default_pager_default_set);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+
+ kr = mach_port_move_member(default_pager_self,
+ default_pager_exception_port,
+ default_pager_default_set);
+ if (kr != KERN_SUCCESS)
+ panic(my_name);
+
+ /*
+ * Now we create the threads that will actually
+ * manage objects.
+ */
+
+ for (i = 0; i < default_pager_internal_count; i++)
+ start_default_pager_thread(TRUE);
+
+ for (i = 0; i < default_pager_external_count; i++)
+ start_default_pager_thread(FALSE);
+
+ default_pager_default_thread(0); /* Become the default_pager server */
+#if 0
+ cthread_fork (default_pager_default_thread, 0);
+ /* cthread_exit (cthread_self ()); */
+ thread_suspend (mach_thread_self ());
+#endif
+}
+
+/*
+ * Create an external object.
+ */
+kern_return_t
+S_default_pager_object_create (mach_port_t pager,
+ mach_port_t *mem_obj,
+ vm_size_t size)
+{
+ default_pager_t ds;
+ mach_port_t port;
+ kern_return_t result;
+
+ if (pager != default_pager_default_port)
+ return KERN_INVALID_ARGUMENT;
+
+ ds = pager_port_alloc(size);
+rename_it:
+ port = (mach_port_t) pnameof(ds);
+ result = mach_port_allocate_name(default_pager_self,
+ MACH_PORT_RIGHT_RECEIVE, port);
+ if (result != KERN_SUCCESS) {
+ default_pager_t ds1;
+
+ if (result != KERN_NAME_EXISTS) return (result);
+
+ ds1 = (default_pager_t) kalloc(sizeof *ds1);
+ *ds1 = *ds;
+ mutex_lock(&all_pagers.lock);
+ queue_enter(&all_pagers.leak_queue, ds, default_pager_t, links);
+ mutex_unlock(&all_pagers.lock);
+ ds = ds1;
+ goto rename_it;
+ }
+
+ /*
+ * Set up associations between these ports
+ * and this default_pager structure
+ */
+
+ ds->pager = port;
+ pager_port_list_insert(port, ds);
+ default_pager_add(ds, FALSE);
+
+ *mem_obj = port;
+ return (KERN_SUCCESS);
+}
+
+kern_return_t
+S_default_pager_info (mach_port_t pager,
+ default_pager_info_t *infop)
+{
+ vm_size_t total, free;
+
+ if (pager != default_pager_default_port)
+ return KERN_INVALID_ARGUMENT;
+
+ mutex_lock(&all_partitions.lock);
+ paging_space_info(&total, &free);
+ mutex_unlock(&all_partitions.lock);
+
+ infop->dpi_total_space = ptoa(total);
+ infop->dpi_free_space = ptoa(free);
+ infop->dpi_page_size = vm_page_size;
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+S_default_pager_objects (mach_port_t pager,
+ default_pager_object_array_t *objectsp,
+ natural_t *ocountp,
+ mach_port_array_t *portsp,
+ natural_t *pcountp)
+{
+ vm_offset_t oaddr; /* memory for objects */
+ vm_size_t osize; /* current size */
+ default_pager_object_t *objects;
+ natural_t opotential;
+
+ vm_offset_t paddr; /* memory for ports */
+ vm_size_t psize; /* current size */
+ mach_port_t *ports;
+ natural_t ppotential;
+
+ unsigned int actual;
+ unsigned int num_pagers;
+ kern_return_t kr;
+ default_pager_t entry;
+
+ if (pager != default_pager_default_port)
+ return KERN_INVALID_ARGUMENT;
+
+ /* start with the inline memory */
+
+ num_pagers = 0;
+
+ objects = *objectsp;
+ opotential = *ocountp;
+
+ ports = *portsp;
+ ppotential = *pcountp;
+
+ mutex_lock(&all_pagers.lock);
+ /*
+ * We will send no more than this many
+ */
+ actual = all_pagers.count;
+ mutex_unlock(&all_pagers.lock);
+
+ if (opotential < actual) {
+ vm_offset_t newaddr;
+ vm_size_t newsize;
+
+ newsize = 2 * round_page(actual * sizeof *objects);
+
+ kr = vm_allocate(default_pager_self, &newaddr, newsize, TRUE);
+ if (kr != KERN_SUCCESS)
+ goto nomemory;
+
+ oaddr = newaddr;
+ osize = newsize;
+ opotential = osize/sizeof *objects;
+ objects = (default_pager_object_t *) oaddr;
+ }
+
+ if (ppotential < actual) {
+ vm_offset_t newaddr;
+ vm_size_t newsize;
+
+ newsize = 2 * round_page(actual * sizeof *ports);
+
+ kr = vm_allocate(default_pager_self, &newaddr, newsize, TRUE);
+ if (kr != KERN_SUCCESS)
+ goto nomemory;
+
+ paddr = newaddr;
+ psize = newsize;
+ ppotential = psize/sizeof *ports;
+ ports = (mach_port_t *) paddr;
+ }
+
+ /*
+ * Now scan the list.
+ */
+
+ mutex_lock(&all_pagers.lock);
+
+ num_pagers = 0;
+ queue_iterate(&all_pagers.queue, entry, default_pager_t, links) {
+
+ mach_port_t port;
+ vm_size_t size;
+
+ if ((num_pagers >= opotential) ||
+ (num_pagers >= ppotential)) {
+ /*
+ * This should be rare. In any case,
+ * we will only miss recent objects,
+ * because they are added at the end.
+ */
+ break;
+ }
+
+ /*
+ * Avoid interfering with normal operations
+ */
+ if (!mutex_try_lock(&entry->dpager.lock))
+ goto not_this_one;
+ size = pager_allocated(&entry->dpager);
+ mutex_unlock(&entry->dpager.lock);
+
+ dstruct_lock(entry);
+
+ port = entry->pager_name;
+ if (port == MACH_PORT_NULL) {
+ /*
+ * The object is waiting for no-senders
+ * or memory_object_init.
+ */
+ dstruct_unlock(entry);
+ goto not_this_one;
+ }
+
+ /*
+ * We need a reference for the reply message.
+ * While we are unlocked, the bucket queue
+ * can change and the object might be terminated.
+ * memory_object_terminate will wait for us,
+ * preventing deallocation of the entry.
+ */
+
+ if (--entry->name_refs == 0) {
+ dstruct_unlock(entry);
+
+ /* keep the list locked, wont take long */
+
+ kr = mach_port_mod_refs(default_pager_self,
+ port, MACH_PORT_RIGHT_SEND,
+ default_pager_max_urefs);
+ if (kr != KERN_SUCCESS)
+ panic("%sdefault_pager_objects",my_name);
+
+ dstruct_lock(entry);
+
+ entry->name_refs += default_pager_max_urefs;
+ pager_port_finish_refs(entry);
+ }
+ dstruct_unlock(entry);
+
+ /* the arrays are wired, so no deadlock worries */
+
+ objects[num_pagers].dpo_object = (vm_offset_t) entry;
+ objects[num_pagers].dpo_size = size;
+ ports [num_pagers++] = port;
+ continue;
+not_this_one:
+ /*
+ * Do not return garbage
+ */
+ objects[num_pagers].dpo_object = (vm_offset_t) 0;
+ objects[num_pagers].dpo_size = 0;
+ ports [num_pagers++] = MACH_PORT_NULL;
+
+ }
+
+ mutex_unlock(&all_pagers.lock);
+
+ /*
+ * Deallocate and clear unused memory.
+ * (Returned memory will automagically become pageable.)
+ */
+
+ if (objects == *objectsp) {
+ /*
+ * Our returned information fit inline.
+ * Nothing to deallocate.
+ */
+
+ *ocountp = num_pagers;
+ } else if (actual == 0) {
+ (void) vm_deallocate(default_pager_self, oaddr, osize);
+
+ /* return zero items inline */
+ *ocountp = 0;
+ } else {
+ vm_offset_t used;
+
+ used = round_page(actual * sizeof *objects);
+
+ if (used != osize)
+ (void) vm_deallocate(default_pager_self,
+ oaddr + used, osize - used);
+
+ *objectsp = objects;
+ *ocountp = num_pagers;
+ }
+
+ if (ports == *portsp) {
+ /*
+ * Our returned information fit inline.
+ * Nothing to deallocate.
+ */
+
+ *pcountp = num_pagers;
+ } else if (actual == 0) {
+ (void) vm_deallocate(default_pager_self, paddr, psize);
+
+ /* return zero items inline */
+ *pcountp = 0;
+ } else {
+ vm_offset_t used;
+
+ used = round_page(actual * sizeof *ports);
+
+ if (used != psize)
+ (void) vm_deallocate(default_pager_self,
+ paddr + used, psize - used);
+
+ *portsp = ports;
+ *pcountp = num_pagers;
+ }
+
+ return KERN_SUCCESS;
+
+ nomemory:
+
+ {
+ register int i;
+ for (i = 0; i < num_pagers; i++)
+ (void) mach_port_deallocate(default_pager_self, ports[i]);
+ }
+
+ if (objects != *objectsp)
+ (void) vm_deallocate(default_pager_self, oaddr, osize);
+
+ if (ports != *portsp)
+ (void) vm_deallocate(default_pager_self, paddr, psize);
+
+ return KERN_RESOURCE_SHORTAGE;
+}
+
+
+kern_return_t
+S_default_pager_object_pages (mach_port_t pager,
+ mach_port_t object,
+ default_pager_page_array_t *pagesp,
+ natural_t *countp)
+{
+ vm_offset_t addr; /* memory for page offsets */
+ vm_size_t size; /* current memory size */
+ default_pager_page_t *pages;
+ natural_t potential, actual;
+ kern_return_t kr;
+
+ if (pager != default_pager_default_port)
+ return KERN_INVALID_ARGUMENT;
+
+ /* we start with the inline space */
+
+ pages = *pagesp;
+ potential = *countp;
+
+ for (;;) {
+ default_pager_t entry;
+
+ mutex_lock(&all_pagers.lock);
+ queue_iterate(&all_pagers.queue, entry, default_pager_t, links) {
+ dstruct_lock(entry);
+ if (entry->pager_name == object) {
+ mutex_unlock(&all_pagers.lock);
+ goto found_object;
+ }
+ dstruct_unlock(entry);
+ }
+ mutex_unlock(&all_pagers.lock);
+
+ /* did not find the object */
+
+ if (pages != *pagesp)
+ (void) vm_deallocate(default_pager_self, addr, size);
+ return KERN_INVALID_ARGUMENT;
+
+ found_object:
+
+ if (!mutex_try_lock(&entry->dpager.lock)) {
+ /* oh well bad luck */
+
+ dstruct_unlock(entry);
+
+ /* yield the processor */
+ (void) thread_switch(MACH_PORT_NULL,
+ SWITCH_OPTION_NONE, 0);
+ continue;
+ }
+
+ actual = pager_pages(&entry->dpager, pages, potential);
+ mutex_unlock(&entry->dpager.lock);
+ dstruct_unlock(entry);
+
+ if (actual <= potential)
+ break;
+
+ /* allocate more memory */
+
+ if (pages != *pagesp)
+ (void) vm_deallocate(default_pager_self, addr, size);
+ size = round_page(actual * sizeof *pages);
+ kr = vm_allocate(default_pager_self, &addr, size, TRUE);
+ if (kr != KERN_SUCCESS)
+ return kr;
+ pages = (default_pager_page_t *) addr;
+ potential = size/sizeof *pages;
+ }
+
+ /*
+ * Deallocate and clear unused memory.
+ * (Returned memory will automagically become pageable.)
+ */
+
+ if (pages == *pagesp) {
+ /*
+ * Our returned information fit inline.
+ * Nothing to deallocate.
+ */
+
+ *countp = actual;
+ } else if (actual == 0) {
+ (void) vm_deallocate(default_pager_self, addr, size);
+
+ /* return zero items inline */
+ *countp = 0;
+ } else {
+ vm_offset_t used;
+
+ used = round_page(actual * sizeof *pages);
+
+ if (used != size)
+ (void) vm_deallocate(default_pager_self,
+ addr + used, size - used);
+
+ *pagesp = pages;
+ *countp = actual;
+ }
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t
+S_default_pager_object_set_size (mach_port_t pager,
+ mach_port_seqno_t seqno,
+ vm_size_t limit)
+{
+ kern_return_t kr;
+ default_pager_t ds;
+
+ ds = pager_port_lookup(pager);
+ if (ds == DEFAULT_PAGER_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ pager_port_lock(ds, seqno);
+ pager_port_check_request(ds, ds->pager_request);
+ pager_port_wait_for_readers(ds);
+ pager_port_wait_for_writers(ds);
+
+ limit = round_page (limit);
+ if (ds->dpager.size <= limit / vm_page_size)
+ {
+ /* The limit has not been exceeded heretofore. Just change it. */
+ ds->dpager.limit = limit;
+ kr = KERN_SUCCESS;
+ }
+ else if (ds->lock_request == MACH_PORT_NULL)
+ {
+ /* Tell the kernel to flush from core all the pages being removed.
+ We will get the memory_object_lock_completed callback when they
+ have been flushed. We handle that by completing the limit update
+ and posting the reply to the pending truncation. */
+ kr = memory_object_lock_request (ds->pager_request,
+ limit,
+ ds->dpager.size * vm_page_size - limit,
+ MEMORY_OBJECT_RETURN_NONE, TRUE,
+ VM_PROT_ALL, ds->pager);
+ if (kr != KERN_SUCCESS)
+ panic ("memory_object_lock_request: %d", kr);
+ ds->lock_request = ds->pager_request;
+ kr = MIG_NO_REPLY;
+ }
+ else
+ /* There is already another call in progress. Tough titties. */
+ kr = KERN_FAILURE;
+
+ pager_port_unlock(ds);
+
+ return kr;
+}
+
+/*
+ * Add/remove extra paging space
+ */
+
+extern mach_port_t bootstrap_master_device_port;
+extern mach_port_t bootstrap_master_host_port;
+
+kern_return_t
+S_default_pager_paging_file (pager, mdport, file_name, add)
+ mach_port_t pager;
+ mach_port_t mdport;
+ default_pager_filename_t file_name;
+ boolean_t add;
+{
+ kern_return_t kr;
+
+ if (pager != default_pager_default_port)
+ return KERN_INVALID_ARGUMENT;
+
+#if 0
+dprintf("bmd %x md %x\n", bootstrap_master_device_port, mdport);
+#endif
+ if (add) {
+ kr = add_paging_file(bootstrap_master_device_port,
+ file_name, 0);
+ } else {
+ kr = remove_paging_file(file_name);
+ }
+
+ /* XXXX more code needed */
+ if (mdport != bootstrap_master_device_port)
+ mach_port_deallocate( mach_task_self(), mdport);
+
+ return kr;
+}
+
+kern_return_t
+default_pager_register_fileserver(pager, fileserver)
+ mach_port_t pager;
+ mach_port_t fileserver;
+{
+ if (pager != default_pager_default_port)
+ return KERN_INVALID_ARGUMENT;
+#if notyet
+ mach_port_deallocate(mach_task_self(), fileserver);
+ if (0) dp_helper_paging_space(0,0,0);/*just linkit*/
+#endif
+ return KERN_SUCCESS;
+}
+
+/*
+ * When things do not quite workout...
+ */
+void no_paging_space(out_of_memory)
+ boolean_t out_of_memory;
+{
+ static char here[] = "%s *** NOT ENOUGH PAGING SPACE ***";
+
+ if (out_of_memory)
+ dprintf("*** OUT OF MEMORY *** ");
+ panic(here, my_name);
+}
+
+void overcommitted(got_more_space, space)
+ boolean_t got_more_space;
+ vm_size_t space; /* in pages */
+{
+ vm_size_t pages_free, pages_total;
+
+ static boolean_t user_warned = FALSE;
+ static vm_size_t pages_shortage = 0;
+
+ paging_space_info(&pages_total, &pages_free);
+
+ /*
+ * If user added more space, see if it is enough
+ */
+ if (got_more_space) {
+ pages_free -= pages_shortage;
+ if (pages_free > 0) {
+ pages_shortage = 0;
+ if (user_warned)
+ dprintf("%s paging space ok now.\n", my_name);
+ } else
+ pages_shortage = pages_free;
+ user_warned = FALSE;
+ return;
+ }
+ /*
+ * We ran out of gas, let user know.
+ */
+ pages_free -= space;
+ pages_shortage = (pages_free > 0) ? 0 : -pages_free;
+ if (!user_warned && pages_shortage) {
+ user_warned = TRUE;
+ dprintf("%s paging space over-committed.\n", my_name);
+ }
+#if debug
+ user_warned = FALSE;
+ dprintf("%s paging space over-committed [+%d (%d) pages].\n",
+ my_name, space, pages_shortage);
+#endif
+}
+
+void paging_space_info(totp, freep)
+ vm_size_t *totp, *freep;
+{
+ register vm_size_t total, free;
+ register partition_t part;
+ register int i;
+
+ total = free = 0;
+ for (i = 0; i < all_partitions.n_partitions; i++) {
+
+ if ((part = partition_of(i)) == 0) continue;
+
+ /* no need to lock: by the time this data
+ gets back to any remote requestor it
+ will be obsolete anyways */
+ total += part->total_size;
+ free += part->free;
+#if debug
+ dprintf("Partition %d: x%x total, x%x free\n",
+ i, part->total_size, part->free);
+#endif
+ }
+ *totp = total;
+ *freep = free;
+}
+
+/*
+ * Catch exceptions.
+ */
+
+kern_return_t
+catch_exception_raise(exception_port, thread, task, exception, code, subcode)
+ mach_port_t exception_port;
+ mach_port_t thread, task;
+ int exception, code, subcode;
+{
+ ddprintf ("(default_pager)catch_exception_raise(%d,%d,%d)\n",
+ exception, code, subcode);
+ panic(my_name);
+
+ /* mach_msg_server will deallocate thread/task for us */
+
+ return KERN_FAILURE;
+}
diff --git a/mach-defpager/default_pager.h b/mach-defpager/default_pager.h
new file mode 100644
index 00000000..f4cdda64
--- /dev/null
+++ b/mach-defpager/default_pager.h
@@ -0,0 +1,43 @@
+/* Backing store access callbacks for Hurd version of Mach default pager.
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Prototypes for working with paging partitions and files */
+
+#ifndef _DEFAULT_PAGER_H_
+#define _DEFAULT_PAGER_H_
+
+#include <file_io.h>
+
+void partition_init();
+
+void create_paging_partition(const char *name, struct file_direct *fdp,
+ int isa_file, int linux_signature);
+kern_return_t destroy_paging_partition(char *name, void **pp_private);
+
+kern_return_t add_paging_file(mach_port_t master_device_port,
+ char *file_name, int linux_signature);
+kern_return_t remove_paging_file (char *file_name);
+
+void paging_space_info(vm_size_t *totp, vm_size_t *freep);
+void no_paging_space(boolean_t out_of_memory);
+void overcommitted(boolean_t got_more_space, vm_size_t space);
+
+void panic (const char *fmt, ...);
+
+#endif /* _DEFAULT_PAGER_H_ */
diff --git a/mach-defpager/file_io.h b/mach-defpager/file_io.h
new file mode 100644
index 00000000..d0b03f33
--- /dev/null
+++ b/mach-defpager/file_io.h
@@ -0,0 +1,69 @@
+/* Backing store access callbacks for Hurd version of Mach default pager.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _file_io_h
+#define _file_io_h 1
+
+/* The original Mach default pager code used in serverboot can read
+ filesystem meta-data to find the blocks used by paging files.
+ We replace those interfaces with simpler code that only supports
+ subsets of devices represented by a list of runs a la libstore. */
+
+#include <sys/types.h>
+
+#include <device/device_types.h>
+#include <device/device.h>
+
+/* A run of device records, expressed in the device's record size. */
+struct storage_run
+{
+ recnum_t start, length;
+};
+
+struct file_direct
+{
+ mach_port_t device;
+
+ int bshift; /* size of device records (disk blocks) */
+ size_t fd_bsize; /* log2 of that */
+ recnum_t fd_size; /* number of blocks total */
+
+ /* The paging area consists of the concatentation of NRUNS contiguous
+ regions of the device, as described by RUNS. */
+ size_t nruns;
+ struct storage_run runs[0];
+};
+
+/* These are in fact only called to read or write a single page, from
+ default_pager.c::default_read/default_write. The SIZE argument is
+ always vm_page_size and OFFSET is always page-aligned. */
+
+int page_read_file_direct (struct file_direct *fdp,
+ vm_offset_t offset,
+ vm_size_t size,
+ vm_offset_t *addr, /* out */
+ mach_msg_type_number_t *size_read); /* out */
+int page_write_file_direct(struct file_direct *fdp,
+ vm_offset_t offset,
+ vm_offset_t addr,
+ vm_size_t size,
+ vm_offset_t *size_written); /* out */
+
+
+#endif /* file_io.h */
diff --git a/mach-defpager/kalloc.c b/mach-defpager/kalloc.c
new file mode 100644
index 00000000..d9b18c02
--- /dev/null
+++ b/mach-defpager/kalloc.c
@@ -0,0 +1,299 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * File: kern/kalloc.c
+ * Author: Avadis Tevanian, Jr.
+ * Date: 1985
+ *
+ * General kernel memory allocator. This allocator is designed
+ * to be used by the kernel to manage dynamic memory fast.
+ */
+
+#include <mach.h>
+#include <cthreads.h> /* for spin locks */
+#include <malloc.h> /* for malloc_hook/free_hook */
+
+#include "wiring.h"
+
+static void init_hook (void);
+static void *malloc_hook (size_t size, const void *caller);
+static void free_hook (void *ptr, const void *caller);
+
+/* GNU libc 2.14 defines this macro to declare hook variables as volatile.
+ Define it as empty for older libc versions. */
+#ifndef __MALLOC_HOOK_VOLATILE
+# define __MALLOC_HOOK_VOLATILE
+#endif
+
+void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) (void) = init_hook;
+
+
+#define DEBUG
+
+/*
+ * All allocations of size less than kalloc_max are rounded to the
+ * next highest power of 2.
+ */
+vm_size_t kalloc_max; /* max before we use vm_allocate */
+#define MINSIZE 4 /* minimum allocation size */
+
+struct free_list {
+ spin_lock_t lock;
+ vm_offset_t head; /* head of free list */
+#ifdef DEBUG
+ int count;
+#endif /*DEBUG*/
+};
+
+#define KLIST_MAX 13
+ /* sizes: 4, 8, 16, 32, 64,
+ 128, 256, 512, 1024,
+ 2048, 4096, 8192, 16384 */
+struct free_list kfree_list[KLIST_MAX];
+
+spin_lock_t kget_space_lock;
+vm_offset_t kalloc_next_space = 0;
+vm_offset_t kalloc_end_of_space = 0;
+
+vm_size_t kalloc_wasted_space = 0;
+
+boolean_t kalloc_initialized = FALSE;
+
+/*
+ * Initialize the memory allocator. This should be called only
+ * once on a system wide basis (i.e. first processor to get here
+ * does the initialization).
+ *
+ * This initializes all of the zones.
+ */
+
+void kalloc_init(void)
+{
+ vm_offset_t min, max;
+ vm_size_t size;
+ register int i;
+
+ /*
+ * Support free lists for items up to vm_page_size or
+ * 16Kbytes, whichever is less.
+ */
+
+ if (vm_page_size > 16*1024)
+ kalloc_max = 16*1024;
+ else
+ kalloc_max = vm_page_size;
+
+ for (i = 0; i < KLIST_MAX; i++) {
+ spin_lock_init(&kfree_list[i].lock);
+ kfree_list[i].head = 0;
+ }
+ spin_lock_init(&kget_space_lock);
+
+ /*
+ * Do not allocate memory at address 0.
+ */
+ kalloc_next_space = vm_page_size;
+ kalloc_end_of_space = vm_page_size;
+}
+
+/*
+ * Contiguous space allocator for items of less than a page size.
+ */
+vm_offset_t kget_space(vm_offset_t size)
+{
+ vm_size_t space_to_add;
+ vm_offset_t new_space = 0;
+ vm_offset_t addr;
+
+ spin_lock(&kget_space_lock);
+ while (kalloc_next_space + size > kalloc_end_of_space) {
+ /*
+ * Add at least one page to allocation area.
+ */
+ space_to_add = round_page(size);
+
+ if (new_space == 0) {
+ /*
+ * Unlock and allocate memory.
+ * Try to make it contiguous with the last
+ * allocation area.
+ */
+ spin_unlock(&kget_space_lock);
+
+ new_space = kalloc_end_of_space;
+ if (vm_map(mach_task_self(),
+ &new_space, space_to_add, (vm_offset_t) 0, TRUE,
+ MEMORY_OBJECT_NULL, (vm_offset_t) 0, FALSE,
+ VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT)
+ != KERN_SUCCESS)
+ return 0;
+ wire_memory(new_space, space_to_add,
+ VM_PROT_READ|VM_PROT_WRITE);
+ spin_lock(&kget_space_lock);
+ continue;
+ }
+
+ /*
+ * Memory was allocated in a previous iteration.
+ * Check whether the new region is contiguous with the
+ * old one.
+ */
+ if (new_space != kalloc_end_of_space) {
+ /*
+ * Throw away the remainder of the old space,
+ * and start a new one.
+ */
+ kalloc_wasted_space +=
+ kalloc_end_of_space - kalloc_next_space;
+ kalloc_next_space = new_space;
+ }
+ kalloc_end_of_space = new_space + space_to_add;
+
+ new_space = 0;
+ }
+
+ addr = kalloc_next_space;
+ kalloc_next_space += size;
+ spin_unlock(&kget_space_lock);
+
+ if (new_space != 0)
+ (void) vm_deallocate(mach_task_self(), new_space, space_to_add);
+
+ return addr;
+}
+
+void *kalloc(vm_size_t size)
+{
+ register vm_size_t allocsize;
+ vm_offset_t addr;
+ register struct free_list *fl;
+
+ if (!kalloc_initialized) {
+ kalloc_init();
+ kalloc_initialized = TRUE;
+ }
+
+ /* compute the size of the block that we will actually allocate */
+
+ allocsize = size;
+ if (size < kalloc_max) {
+ allocsize = MINSIZE;
+ fl = kfree_list;
+ while (allocsize < size) {
+ allocsize <<= 1;
+ fl++;
+ }
+ }
+
+ /*
+ * If our size is still small enough, check the queue for that size
+ * and allocate.
+ */
+
+ if (allocsize < kalloc_max) {
+ spin_lock(&fl->lock);
+ if ((addr = fl->head) != 0) {
+ fl->head = *(vm_offset_t *)addr;
+#ifdef DEBUG
+ fl->count--;
+#endif
+ spin_unlock(&fl->lock);
+ }
+ else {
+ spin_unlock(&fl->lock);
+ addr = kget_space(allocsize);
+ }
+ }
+ else {
+ if (vm_allocate(mach_task_self(), &addr, allocsize, TRUE)
+ != KERN_SUCCESS)
+ addr = 0;
+ }
+ return (void *) addr;
+}
+
+void
+kfree( void *data,
+ vm_size_t size)
+{
+ register vm_size_t freesize;
+ register struct free_list *fl;
+
+ freesize = size;
+ if (size < kalloc_max) {
+ freesize = MINSIZE;
+ fl = kfree_list;
+ while (freesize < size) {
+ freesize <<= 1;
+ fl++;
+ }
+ }
+
+ if (freesize < kalloc_max) {
+ spin_lock(&fl->lock);
+ *(vm_offset_t *)data = fl->head;
+ fl->head = (vm_offset_t) data;
+#ifdef DEBUG
+ fl->count++;
+#endif
+ spin_unlock(&fl->lock);
+ }
+ else {
+ (void) vm_deallocate(mach_task_self(), (vm_offset_t)data, freesize);
+ }
+}
+
+static void
+init_hook (void)
+{
+ __malloc_hook = malloc_hook;
+ __free_hook = free_hook;
+}
+
+static void *
+malloc_hook (size_t size, const void *caller)
+{
+ return (void *) kalloc ((vm_size_t) size);
+}
+
+static void
+free_hook (void *ptr, const void *caller)
+{
+ /* Just ignore harmless attempts at cleanliness. */
+ /* panic("free not implemented"); */
+}
+
+void malloc_fork_prepare()
+{
+}
+
+void malloc_fork_parent()
+{
+}
+
+void malloc_fork_child()
+{
+}
diff --git a/libnetfs/parse-runtime-options.c b/mach-defpager/kalloc.h
index 1a179736..8f52f1a5 100644
--- a/libnetfs/parse-runtime-options.c
+++ b/mach-defpager/kalloc.h
@@ -1,6 +1,5 @@
-/* A default netfs_parse_runtime_options routine
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/* Backing store access callbacks for Hurd version of Mach default pager.
+ Copyright (C) 2012 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -18,13 +17,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include "netfs.h"
+/*
+ * General kernel memory allocator.
+ */
+
+#ifndef _KALLOC_H_
+#define _KALLOC_H_
+
+void *kalloc (vm_size_t size);
+void kfree (void *data, vm_size_t size);
-error_t
-netfs_parse_runtime_options (int argc, char **argv,
- const struct argp *standard_argp)
-{
- return argp_parse (standard_argp, argc, argv,
- ARGP_NO_ERRS | ARGP_NO_HELP | ARGP_PARSE_ARGV0,
- 0, 0);
-}
+#endif /* _KALLOC_H_ */
diff --git a/mach-defpager/main.c b/mach-defpager/main.c
new file mode 100644
index 00000000..c44c86cb
--- /dev/null
+++ b/mach-defpager/main.c
@@ -0,0 +1,180 @@
+/* Main program for standalone Hurd version of Mach default pager.
+ Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+#include <mach.h>
+#include <hurd.h>
+#include <cthreads.h>
+#include <device/device.h>
+#include <device/device_types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <error.h>
+#include <signal.h>
+#include <string.h>
+
+/* XXX */
+#include <fcntl.h>
+#include <paths.h>
+#include <errno.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <hurd/port.h>
+#include <hurd/fd.h>
+/* XXX */
+
+#include <default_pager.h>
+
+extern
+vm_size_t cthread_wait_stack_size;
+
+mach_port_t bootstrap_master_device_port; /* local name */
+mach_port_t bootstrap_master_host_port; /* local name */
+
+extern void default_pager();
+extern void default_pager_initialize();
+extern void default_pager_setup();
+
+/* initialized in default_pager_initialize */
+extern mach_port_t default_pager_exception_port;
+
+
+static void
+printf_init (device_t master)
+{
+ mach_port_t cons;
+ kern_return_t rc;
+ rc = device_open (master, D_READ|D_WRITE, "console", &cons);
+ if (rc)
+ error (2, rc, "cannot open kernel console device");
+ stdin = mach_open_devstream (cons, "r");
+ stdout = stderr = mach_open_devstream (cons, "w");
+ mach_port_deallocate (mach_task_self (), cons);
+ setbuf (stdout, 0);
+}
+
+
+int debug;
+
+static void
+nohandler (int sig)
+{ }
+
+int
+main (int argc, char **argv)
+{
+ const task_t my_task = mach_task_self();
+ error_t err;
+ memory_object_t defpager;
+
+ /*
+ * Use 4Kbyte cthread wait stacks.
+ */
+ cthread_wait_stack_size = 4 * 1024;
+
+ err = get_privileged_ports (&bootstrap_master_host_port,
+ &bootstrap_master_device_port);
+ if (err)
+ error (1, err, "cannot get privileged ports");
+
+ defpager = MACH_PORT_NULL;
+ err = vm_set_default_memory_manager (bootstrap_master_host_port, &defpager);
+ if (err)
+ error (1, err, "cannot check current default memory manager");
+ if (MACH_PORT_VALID (defpager))
+ error (2, 0, "Another default memory manager is already running");
+
+ if (!(argc == 2 && !strcmp (argv[1], "-d")))
+ {
+ /* We don't use the `daemon' function because we might exit back to the
+ parent before the daemon has completed vm_set_default_memory_manager.
+ Instead, the parent waits for a SIGUSR1 from the child before
+ exitting, and the child sends that signal after it is set up. */
+ sigset_t set;
+ signal (SIGUSR1, nohandler);
+ sigemptyset (&set);
+ sigaddset (&set, SIGUSR1);
+ sigprocmask (SIG_BLOCK, &set, 0);
+ switch (fork ())
+ {
+ case -1:
+ error (1, errno, "cannot become daemon");
+ case 0:
+ setsid ();
+ chdir ("/");
+ close (0);
+ close (1);
+ close (2);
+ break;
+ default:
+ sigemptyset (&set);
+ sigsuspend (&set);
+ _exit (0);
+ }
+ }
+
+ printf_init(bootstrap_master_device_port);
+
+ /*
+ * Set up the default pager.
+ */
+ partition_init();
+
+ /*
+ * task_set_exception_port and task_set_bootstrap_port
+ * both require a send right.
+ */
+ (void) mach_port_insert_right(my_task, default_pager_exception_port,
+ default_pager_exception_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+ /*
+ * Change our exception port.
+ */
+ if (!debug)
+ (void) task_set_exception_port(my_task, default_pager_exception_port);
+
+ default_pager_initialize (bootstrap_master_host_port);
+
+ if (!(argc == 2 && !strcmp (argv[1], "-d")))
+ kill (getppid (), SIGUSR1);
+
+ /*
+ * Become the default pager
+ */
+ default_pager();
+ /*NOTREACHED*/
+ return -1;
+}
+
+
+void
+panic (const char *fmt, ...)
+{
+ va_list ap;
+ fprintf (stderr, "%s: panic: ", program_invocation_name);
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ exit (3);
+}
diff --git a/mach-defpager/queue.h b/mach-defpager/queue.h
new file mode 100644
index 00000000..00619174
--- /dev/null
+++ b/mach-defpager/queue.h
@@ -0,0 +1,316 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon rights
+ * to redistribute these changes.
+ */
+/*
+ * File: queue.h
+ * Author: Avadis Tevanian, Jr.
+ * Date: 1985
+ *
+ * Type definitions for generic queues.
+ *
+ */
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+
+/*
+ * Queue of abstract objects. Queue is maintained
+ * within that object.
+ *
+ * Supports fast removal from within the queue.
+ *
+ * How to declare a queue of elements of type "foo_t":
+ * In the "*foo_t" type, you must have a field of
+ * type "queue_chain_t" to hold together this queue.
+ * There may be more than one chain through a
+ * "foo_t", for use by different queues.
+ *
+ * Declare the queue as a "queue_t" type.
+ *
+ * Elements of the queue (of type "foo_t", that is)
+ * are referred to by reference, and cast to type
+ * "queue_entry_t" within this module.
+ */
+
+/*
+ * A generic doubly-linked list (queue).
+ */
+
+struct queue_entry {
+ struct queue_entry *next; /* next element */
+ struct queue_entry *prev; /* previous element */
+};
+
+typedef struct queue_entry *queue_t;
+typedef struct queue_entry queue_head_t;
+typedef struct queue_entry queue_chain_t;
+typedef struct queue_entry *queue_entry_t;
+
+/*
+ * Macro: queue_init
+ * Function:
+ * Initialize the given queue.
+ * Header:
+ * void queue_init(q)
+ * queue_t q; / * MODIFIED * /
+ */
+#define queue_init(q) ((q)->next = (q)->prev = q)
+
+/*
+ * Macro: queue_first
+ * Function:
+ * Returns the first entry in the queue,
+ * Header:
+ * queue_entry_t queue_first(q)
+ * queue_t q; / * IN * /
+ */
+#define queue_first(q) ((q)->next)
+
+/*
+ * Macro: queue_next
+ * Function:
+ * Returns the entry after an item in the queue.
+ * Header:
+ * queue_entry_t queue_next(qc)
+ * queue_t qc;
+ */
+#define queue_next(qc) ((qc)->next)
+
+/*
+ * Macro: queue_last
+ * Function:
+ * Returns the last entry in the queue.
+ * Header:
+ * queue_entry_t queue_last(q)
+ * queue_t q; / * IN * /
+ */
+#define queue_last(q) ((q)->prev)
+
+/*
+ * Macro: queue_prev
+ * Function:
+ * Returns the entry before an item in the queue.
+ * Header:
+ * queue_entry_t queue_prev(qc)
+ * queue_t qc;
+ */
+#define queue_prev(qc) ((qc)->prev)
+
+/*
+ * Macro: queue_end
+ * Function:
+ * Tests whether a new entry is really the end of
+ * the queue.
+ * Header:
+ * boolean_t queue_end(q, qe)
+ * queue_t q;
+ * queue_entry_t qe;
+ */
+#define queue_end(q, qe) ((q) == (qe))
+
+/*
+ * Macro: queue_empty
+ * Function:
+ * Tests whether a queue is empty.
+ * Header:
+ * boolean_t queue_empty(q)
+ * queue_t q;
+ */
+#define queue_empty(q) queue_end((q), queue_first(q))
+
+
+/*----------------------------------------------------------------*/
+/*
+ * Macros that operate on generic structures. The queue
+ * chain may be at any location within the structure, and there
+ * may be more than one chain.
+ */
+
+/*
+ * Macro: queue_enter
+ * Function:
+ * Insert a new element at the tail of the queue.
+ * Header:
+ * void queue_enter(q, elt, type, field)
+ * queue_t q;
+ * <type> elt;
+ * <type> is what's in our queue
+ * <field> is the chain field in (*<type>)
+ */
+#define queue_enter(head, elt, type, field) \
+{ \
+ register queue_entry_t prev; \
+ \
+ prev = (head)->prev; \
+ if ((head) == prev) { \
+ (head)->next = (queue_entry_t) (elt); \
+ } \
+ else { \
+ ((type)prev)->field.next = (queue_entry_t)(elt);\
+ } \
+ (elt)->field.prev = prev; \
+ (elt)->field.next = head; \
+ (head)->prev = (queue_entry_t) elt; \
+}
+
+/*
+ * Macro: queue_enter_first
+ * Function:
+ * Insert a new element at the head of the queue.
+ * Header:
+ * void queue_enter_first(q, elt, type, field)
+ * queue_t q;
+ * <type> elt;
+ * <type> is what's in our queue
+ * <field> is the chain field in (*<type>)
+ */
+#define queue_enter_first(head, elt, type, field) \
+{ \
+ register queue_entry_t next; \
+ \
+ next = (head)->next; \
+ if ((head) == next) { \
+ (head)->prev = (queue_entry_t) (elt); \
+ } \
+ else { \
+ ((type)next)->field.prev = (queue_entry_t)(elt);\
+ } \
+ (elt)->field.next = next; \
+ (elt)->field.prev = head; \
+ (head)->next = (queue_entry_t) elt; \
+}
+
+/*
+ * Macro: queue_field [internal use only]
+ * Function:
+ * Find the queue_chain_t (or queue_t) for the
+ * given element (thing) in the given queue (head)
+ */
+#define queue_field(head, thing, type, field) \
+ (((head) == (thing)) ? (head) : &((type)(thing))->field)
+
+/*
+ * Macro: queue_remove
+ * Function:
+ * Remove an arbitrary item from the queue.
+ * Header:
+ * void queue_remove(q, qe, type, field)
+ * arguments as in queue_enter
+ */
+#define queue_remove(head, elt, type, field) \
+{ \
+ register queue_entry_t next, prev; \
+ \
+ next = (elt)->field.next; \
+ prev = (elt)->field.prev; \
+ \
+ if ((head) == next) \
+ (head)->prev = prev; \
+ else \
+ ((type)next)->field.prev = prev; \
+ \
+ if ((head) == prev) \
+ (head)->next = next; \
+ else \
+ ((type)prev)->field.next = next; \
+}
+
+/*
+ * Macro: queue_remove_first
+ * Function:
+ * Remove and return the entry at the head of
+ * the queue.
+ * Header:
+ * queue_remove_first(head, entry, type, field)
+ * entry is returned by reference
+ */
+#define queue_remove_first(head, entry, type, field) \
+{ \
+ register queue_entry_t next; \
+ \
+ (entry) = (type) ((head)->next); \
+ next = (entry)->field.next; \
+ \
+ if ((head) == next) \
+ (head)->prev = (head); \
+ else \
+ ((type)(next))->field.prev = (head); \
+ (head)->next = next; \
+}
+
+/*
+ * Macro: queue_remove_last
+ * Function:
+ * Remove and return the entry at the tail of
+ * the queue.
+ * Header:
+ * queue_remove_last(head, entry, type, field)
+ * entry is returned by reference
+ */
+#define queue_remove_last(head, entry, type, field) \
+{ \
+ register queue_entry_t prev; \
+ \
+ (entry) = (type) ((head)->prev); \
+ prev = (entry)->field.prev; \
+ \
+ if ((head) == prev) \
+ (head)->next = (head); \
+ else \
+ ((type)(prev))->field.next = (head); \
+ (head)->prev = prev; \
+}
+
+/*
+ * Macro: queue_assign
+ */
+#define queue_assign(to, from, type, field) \
+{ \
+ ((type)((from)->prev))->field.next = (to); \
+ ((type)((from)->next))->field.prev = (to); \
+ *to = *from; \
+}
+
+/*
+ * Macro: queue_iterate
+ * Function:
+ * iterate over each item in the queue.
+ * Generates a 'for' loop, setting elt to
+ * each item in turn (by reference).
+ * Header:
+ * queue_iterate(q, elt, type, field)
+ * queue_t q;
+ * <type> elt;
+ * <type> is what's in our queue
+ * <field> is the chain field in (*<type>)
+ */
+#define queue_iterate(head, elt, type, field) \
+ for ((elt) = (type) queue_first(head); \
+ !queue_end((head), (queue_entry_t)(elt)); \
+ (elt) = (type) queue_next(&(elt)->field))
+
+
+
+#endif /* _QUEUE_H_ */
diff --git a/mach-defpager/setup.c b/mach-defpager/setup.c
new file mode 100644
index 00000000..080b0fa6
--- /dev/null
+++ b/mach-defpager/setup.c
@@ -0,0 +1,307 @@
+/* Backing store access callbacks for Hurd version of Mach default pager.
+
+ Copyright (C) 2001, 2002, 2007, 2010 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <assert.h>
+#include <mach.h>
+#include <string.h>
+#include <strings.h>
+
+#include <default_pager.h>
+#include <kalloc.h>
+
+#include "file_io.h"
+#include "default_pager_S.h"
+
+/* This should be in some system header... XXX */
+int page_aligned (vm_offset_t num)
+{
+ return trunc_page (num) == num;
+}
+
+extern mach_port_t default_pager_default_port; /* default_pager.c */
+
+kern_return_t
+S_default_pager_paging_storage (mach_port_t pager,
+ mach_port_t device,
+ recnum_t *runs, mach_msg_type_number_t nrun,
+ default_pager_filename_t name,
+ boolean_t add)
+{
+ struct file_direct *fdp;
+ int sizes[DEV_GET_RECORDS_COUNT];
+ natural_t count;
+ mach_msg_type_number_t i;
+ error_t err;
+ recnum_t devsize;
+
+ if (pager != default_pager_default_port)
+ return KERN_INVALID_ARGUMENT;
+
+ if (! add)
+ return remove_paging_file (name); /* XXX ? */
+
+ if (nrun < 2 || nrun % 2 != 0)
+ return EINVAL;
+
+ count = DEV_GET_RECORDS_COUNT;
+ err = device_get_status (device, DEV_GET_RECORDS, sizes, &count);
+ if (err)
+ return err;
+ if (count < DEV_GET_RECORDS_COUNT || sizes[DEV_GET_RECORDS_RECORD_SIZE] <= 0)
+ return EINVAL;
+ devsize = sizes[DEV_GET_RECORDS_DEVICE_RECORDS];
+
+ if (vm_page_size % sizes[DEV_GET_RECORDS_RECORD_SIZE] != 0)
+ /* We can't write disk blocks larger than pages. */
+ return EINVAL;
+
+ fdp = kalloc (offsetof (struct file_direct, runs[nrun]));
+ if (fdp == 0)
+ return ENOMEM;
+
+ fdp->device = device;
+ fdp->bshift = ffs (sizes[DEV_GET_RECORDS_RECORD_SIZE]) - 1;
+ fdp->fd_bsize = sizes[DEV_GET_RECORDS_RECORD_SIZE];
+ fdp->nruns = nrun / 2;
+ fdp->fd_size = 0;
+ for (i = 0; i < nrun; i += 2)
+ {
+ fdp->runs[i].start = runs[i];
+ fdp->runs[i].length = runs[i + 1];
+ if (fdp->runs[i].start + fdp->runs[i].length > devsize)
+ {
+ kfree (fdp, offsetof (struct file_direct, runs[nrun]));
+ return EINVAL;
+ }
+ fdp->fd_size += fdp->runs[i].length;
+ }
+
+ /* Now really do it. */
+ create_paging_partition (name, fdp, 0, -3);
+ return 0;
+}
+
+
+/* Called to read a page from backing store. */
+int
+page_read_file_direct (struct file_direct *fdp,
+ vm_offset_t offset,
+ vm_size_t size,
+ vm_offset_t *addr, /* out */
+ mach_msg_type_number_t *size_read) /* out */
+{
+ struct storage_run *r;
+ error_t err;
+ char *readloc;
+ char *page;
+ mach_msg_type_number_t nread;
+
+ assert (page_aligned (offset));
+ assert (size == vm_page_size);
+
+ offset >>= fdp->bshift;
+
+ assert (offset + (size >> fdp->bshift) <= fdp->fd_size);
+
+ /* Find the run containing the beginning of the page. */
+ for (r = fdp->runs; offset > r->length; ++r)
+ offset -= r->length;
+
+ if (offset + (size >> fdp->bshift) <= r->length)
+ /* The first run contains the whole page. */
+ return device_read (fdp->device, 0, r->start + offset,
+ size, (char **) addr, size_read);
+
+ /* Read the first part of the run. */
+ err = device_read (fdp->device, 0, r->start + offset,
+ (r->length - offset) << fdp->bshift,
+ (char **) addr, &nread);
+ if (err)
+ return err;
+
+ size -= nread;
+ readloc = (char *) *addr;
+ do
+ {
+ readloc += nread;
+ offset += nread >> fdp->bshift;
+ if (offset > r->length)
+ offset -= r++->length;
+
+ /* We always get another out-of-line page, so we have to copy
+ out of that page and deallocate it. */
+ err = device_read (fdp->device, 0, r->start + offset,
+ (r->length - offset) << fdp->bshift,
+ &page, &nread);
+ if (err)
+ {
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) *addr, vm_page_size);
+ return err;
+ }
+ memcpy (readloc, page, nread);
+ vm_deallocate (mach_task_self (), (vm_address_t) page, vm_page_size);
+ size -= nread;
+ } while (size > 0);
+
+ *size_read = vm_page_size;
+ return 0;
+}
+
+/* Called to write a page to backing store. */
+int
+page_write_file_direct(struct file_direct *fdp,
+ vm_offset_t offset,
+ vm_offset_t addr,
+ vm_size_t size,
+ vm_offset_t *size_written) /* out */
+{
+ struct storage_run *r;
+ error_t err;
+ int wrote;
+
+ assert (page_aligned (offset));
+ assert (size == vm_page_size);
+
+ offset >>= fdp->bshift;
+
+ assert (offset + (size >> fdp->bshift) <= fdp->fd_size);
+
+ /* Find the run containing the beginning of the page. */
+ for (r = fdp->runs; offset > r->length; ++r)
+ offset -= r->length;
+
+ if (offset + (size >> fdp->bshift) <= r->length)
+ {
+ /* The first run contains the whole page. */
+ err = device_write (fdp->device, 0, r->start + offset,
+ (char *) addr, size, &wrote);
+ *size_written = wrote;
+ return err;
+ }
+
+ /* Write the first part of the run. */
+ err = device_write (fdp->device, 0,
+ r->start + offset, (char *) addr,
+ (r->length - offset) << fdp->bshift,
+ &wrote);
+ if (err)
+ return err;
+
+ size -= wrote;
+ do
+ {
+ mach_msg_type_number_t segsize;
+
+ addr += wrote;
+ offset += wrote >> fdp->bshift;
+ if (offset > r->length)
+ offset -= r++->length;
+
+ segsize = (r->length - offset) << fdp->bshift;
+ if (segsize > size)
+ segsize = size;
+ err = device_write (fdp->device, 0, r->start + offset,
+ (char *) addr, segsize, &wrote);
+ if (err)
+ {
+ vm_deallocate (mach_task_self (),
+ (vm_address_t) addr, vm_page_size);
+ return err;
+ }
+
+ size -= wrote;
+ } while (size > 0);
+
+ *size_written = vm_page_size;
+ return 0;
+}
+
+
+/* Compatibility entry points used by default_pager_paging_file RPC. */
+
+kern_return_t
+add_paging_file(master_device_port, file_name, linux_signature)
+ mach_port_t master_device_port;
+ char *file_name;
+ int linux_signature;
+{
+ error_t err;
+ mach_port_t dev;
+ int sizes[DEV_GET_SIZE_COUNT];
+ natural_t count;
+ char *devname = file_name;
+
+ assert (linux_signature == 0);
+
+ if (!strncmp (file_name, "/dev/", 5))
+ devname += 5;
+
+ err = device_open (master_device_port, D_READ|D_WRITE, devname, &dev);
+ if (err)
+ return err;
+
+ count = DEV_GET_SIZE_COUNT;
+ err = device_get_status (dev, DEV_GET_SIZE, sizes, &count);
+ if (!err && count < DEV_GET_SIZE_COUNT)
+ err = EGRATUITOUS;
+ if (err)
+ mach_port_deallocate (mach_task_self (), dev);
+ else
+ {
+ struct file_direct *fdp;
+ fdp = kalloc (offsetof (struct file_direct, runs[1]));
+ if (fdp == 0)
+ return ENOMEM;
+
+ fdp->device = dev;
+ fdp->fd_bsize = sizes[DEV_GET_SIZE_RECORD_SIZE];
+ fdp->bshift = ffs (sizes[DEV_GET_SIZE_RECORD_SIZE]) - 1;
+ fdp->fd_size = sizes[DEV_GET_SIZE_DEVICE_SIZE] >> fdp->bshift;
+ fdp->nruns = 1;
+ fdp->runs[0].start = 0;
+ fdp->runs[0].length = fdp->fd_size;
+
+ /* Now really do it. */
+ create_paging_partition (file_name, fdp, 0, 0);
+ }
+
+ return err;
+}
+
+/*
+ * Destroy a paging_partition given a file name
+ */
+kern_return_t
+remove_paging_file (char *file_name)
+{
+ struct file_direct *fdp = 0;
+ kern_return_t kr;
+
+ kr = destroy_paging_partition(file_name, (void **)&fdp);
+ if (kr == KERN_SUCCESS && fdp != 0)
+ {
+ mach_port_deallocate (mach_task_self (), fdp->device);
+ kfree (fdp, (char *) &fdp->runs[fdp->nruns] - (char *) fdp);
+ }
+ return kr;
+}
diff --git a/mach-defpager/wiring.c b/mach-defpager/wiring.c
new file mode 100644
index 00000000..8bf49934
--- /dev/null
+++ b/mach-defpager/wiring.c
@@ -0,0 +1,176 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Package to wire current task's memory.
+ */
+#include <mach.h>
+#include <mach_init.h>
+#include <mach/machine/vm_param.h>
+#include "default_pager.h"
+
+mach_port_t this_task; /* our task */
+mach_port_t priv_host_port = MACH_PORT_NULL;
+ /* the privileged host port */
+
+void
+wire_setup(host_priv)
+ mach_port_t host_priv;
+{
+ priv_host_port = host_priv;
+ this_task = mach_task_self();
+}
+
+void
+wire_memory(start, size, prot)
+ vm_address_t start;
+ vm_size_t size;
+ vm_prot_t prot;
+{
+ kern_return_t kr;
+
+ if (priv_host_port == MACH_PORT_NULL)
+ return;
+
+ kr = vm_wire(priv_host_port,
+ this_task,
+ start, size, prot);
+ if (kr != KERN_SUCCESS)
+ panic("mem_wire: %d", kr);
+}
+
+void
+wire_thread()
+{
+ kern_return_t kr;
+
+ if (priv_host_port == MACH_PORT_NULL)
+ return;
+
+ kr = thread_wire(priv_host_port,
+ mach_thread_self(),
+ TRUE);
+ if (kr != KERN_SUCCESS)
+ panic("wire_thread: %d", kr);
+}
+
+void
+wire_all_memory()
+{
+ register kern_return_t kr;
+ vm_offset_t address;
+ vm_size_t size;
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ boolean_t is_shared;
+ memory_object_name_t object;
+ vm_offset_t offset;
+
+ if (priv_host_port == MACH_PORT_NULL)
+ return;
+
+ /* iterate thru all regions, wiring */
+ address = 0;
+ while (
+ (kr = vm_region(this_task, &address,
+ &size,
+ &protection,
+ &max_protection,
+ &inheritance,
+ &is_shared,
+ &object,
+ &offset))
+ == KERN_SUCCESS)
+ {
+ if (MACH_PORT_VALID(object))
+ (void) mach_port_deallocate(this_task, object);
+ if (protection != VM_PROT_NONE)
+ {
+ /* The VM system cannot cope with a COW fault on another
+ unrelated virtual copy happening later when we have
+ wired down the original page. So we must touch all our
+ pages before wiring to make sure that only we will ever
+ use them. */
+ void *page;
+ if (!(protection & VM_PROT_WRITE))
+ {
+ kr = vm_protect(this_task, address, size,
+ 0, max_protection);
+ }
+ for (page = (void *) address;
+ page < (void *) (address + size);
+ page += vm_page_size)
+ *(volatile int *) page = *(int *) page;
+
+ wire_memory(address, size, protection);
+
+ if (!(protection & VM_PROT_WRITE))
+ {
+ kr = vm_protect(this_task, address, size,
+ 0, protection);
+ }
+ }
+ address += size;
+ }
+}
+
+/*
+ * Alias for vm_allocate to return wired memory.
+ */
+kern_return_t
+vm_allocate(task, address, size, anywhere)
+ task_t task;
+ vm_address_t *address;
+ vm_size_t size;
+ boolean_t anywhere;
+{
+ kern_return_t kr;
+
+ if (anywhere)
+ *address = VM_MIN_ADDRESS;
+ kr = vm_map(task,
+ address, size, (vm_offset_t) 0, anywhere,
+ MEMORY_OBJECT_NULL, (vm_offset_t)0, FALSE,
+ VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ if (task == this_task)
+ (void) vm_wire(priv_host_port, task, *address, size,
+ VM_PROT_DEFAULT);
+ return KERN_SUCCESS;
+}
+
+/* Other versions of this function in libc... */
+kern_return_t
+__vm_allocate (task, address, size, anywhere)
+ task_t task;
+ vm_address_t *address;
+ vm_size_t size;
+ boolean_t anywhere;
+{
+ return vm_allocate (task, address, size, anywhere);
+}
diff --git a/mach-defpager/wiring.h b/mach-defpager/wiring.h
new file mode 100644
index 00000000..b5f8e53f
--- /dev/null
+++ b/mach-defpager/wiring.h
@@ -0,0 +1,35 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon the
+ * rights to redistribute these changes.
+ */
+/*
+ * Package to wire current task's memory.
+ */
+#include <mach.h>
+#include <mach_init.h>
+
+extern void wire_setup(/* mach_port_t host_priv */);
+extern void wire_memory(/* vm_address_t, vm_size_t, vm_prot_t */);
+extern void wire_thread();
+extern void wire_all_memory();
diff --git a/mkbootfs/ChangeLog b/mkbootfs/ChangeLog
deleted file mode 100644
index 787943a2..00000000
--- a/mkbootfs/ChangeLog
+++ /dev/null
@@ -1,22 +0,0 @@
-Fri Jul 22 10:38:17 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
-
-Wed Jul 20 16:24:08 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (mkbootfs): Put -n after hostname for compat with
- old broken rsh.
- Use gcc literally instead of MIGHOSTCC.
-
-Tue Jul 5 14:22:00 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (SRCS): New variable.
-
-Fri May 6 13:25:47 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makefile (mkbootfs): Use MIGHOSTCC instead of CC.
-
-Thu May 5 19:06:21 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makefile (mkbootfs): Call rsh with -n flag.
-
diff --git a/mkbootfs/mkbootfs.c b/mkbootfs/mkbootfs.c
deleted file mode 100644
index e3ad7137..00000000
--- a/mkbootfs/mkbootfs.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Make a bootstrap filesystem from a filesystem and an exec server
- Copyright (C) 1993, 1994 Free Software Foundation
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Written by Michael I. Bushnell. */
-
-/* The job is to write a .o corresponding to the exec server. This
- .o contains the following symbols:
-
- _execserver_text_size
- _execserver_data_size
- _execserver_bss_size
- _execserver_text
- _execserver_data
- _execserver_start
-
- The .o will then be linked along with the rest of the filesystem, which
- will spawn an execserver with the right bits when it starts.
-
- The text should be loaded at 0x10000 and the data at
- 0x10000 + _execserver_text_size and the bss cleared at
- 0x10000 + _execserver_text_size + _execserver_data_size.
- */
-
-/* This is non-general, and only intended for the i386 Mach 3.0 with
- its own weird format. It expects the header files to be from such a
- Mach system as CMU sets them up. */
-
-#include <a.out.h>
-#include <stdio.h>
-#include <sys/file.h>
-
-/* Usage: mkbootfs execserver newdoto */
-
-main (int argc, char **argv)
-{
- int execserver, newdoto;
- struct exec a, newa;
- unsigned long foo;
- void *buf;
- struct nlist n;
-
- signal (0, 0);
-
- if (argc != 3)
- {
- fprintf (stderr, "Usage: %s execserver newdoto\n", argv[0]);
- exit (1);
- }
-
- execserver = open (argv[1], O_RDONLY);
- if (execserver == -1)
- {
- perror (argv[1]);
- exit (1);
- }
-
- newdoto = open (argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (newdoto == -1)
- {
- perror (argv[2]);
- exit (1);
- }
-
- read (execserver, &a, sizeof (struct exec));
-
- /* Write the new data segment to the new file. */
- lseek (newdoto, sizeof (struct exec), L_SET);
-
- /* First, _execserver_text_size */
- foo = a.a_text + sizeof (struct exec);
- write (newdoto, &foo, sizeof foo);
-
- /* Next, _execserver_data_size */
- write (newdoto, &a.a_data, sizeof a.a_data);
-
- /* Next, _execserver_bss_size */
- write (newdoto, &a.a_bss, sizeof a.a_bss);
-
- /* Next, _execserver_text */
- buf = malloc (a.a_text + sizeof (struct exec));
- lseek (execserver, 0, L_SET);
- read (execserver, buf, a.a_text + sizeof (struct exec));
- write (newdoto, buf, a.a_text + sizeof (struct exec));
- free (buf);
-
- /* Next, _execserver_data */
- buf = malloc (a.a_data);
- read (execserver, buf, a.a_data);
- write (newdoto, buf, a.a_data);
- free (buf);
-
- /* Finally, _execserver_start */
- write (newdoto, &a.a_entry, sizeof a.a_entry);
-
- /* We have no relocation information */
-
- /* Now, write the symbol table */
- n.n_un.n_strx = 50;
- n.n_type = N_DATA | N_EXT;
- n.n_value = 0;
-
- /* First, _execserver_text_size */
- write (newdoto, &n, sizeof (n));
- n.n_value += sizeof (foo);
-
- /* Now, _execserver_data_size */
- n.n_un.n_strx += 50;
- write (newdoto, &n, sizeof (n));
- n.n_value += sizeof (foo);
-
- /* Now, _execserver_bss_size */
- n.n_un.n_strx += 50;
- write (newdoto, &n, sizeof (n));
- n.n_value += sizeof (foo);
-
- /* Now, _execserver_text */
- n.n_un.n_strx += 50;
- write (newdoto, &n, sizeof (n));
- n.n_value += a.a_text + sizeof (struct exec);
-
- /* Now, _execserver_data */
- n.n_un.n_strx += 50;
- write (newdoto, &n, sizeof (n));
- n.n_value += a.a_data;
-
- /* Now, _execserver_start */
- n.n_un.n_strx += 50;
- write (newdoto, &n, sizeof (n));
- n.n_value += sizeof (foo);
-
- /* Now, we have to write out the string table */
-#define DOSTRING(x) \
- write (newdoto, x, strlen (x) + 1); \
- lseek (newdoto, 50 - strlen (x) - 1, L_INCR);
-
- foo = 350; /* six strings and the beginning */
- write (newdoto, &foo, sizeof foo);
- lseek (newdoto, 50 - sizeof foo, L_INCR);
-
- DOSTRING ("_execserver_text_size");
- DOSTRING ("_execserver_data_size");
- DOSTRING ("_execserver_bss_size");
- DOSTRING ("_execserver_text");
- DOSTRING ("_execserver_data");
- DOSTRING ("_execserver_start");
-
- lseek (newdoto, -1, L_INCR);
- foo = 0;
- write (newdoto, &foo, 1);
-
- /* Now write out the header */
- a.a_magic = OMAGIC;
- a.a_data =
- (4 * sizeof (int) + a.a_text + a.a_data + sizeof (struct exec));
- a.a_text = 0;
- a.a_bss = 0;
- a.a_syms = 6 * sizeof n;
- a.a_entry = 0;
- a.a_trsize = 0;
- a.a_drsize = 0;
- lseek (newdoto, 0, L_SET);
- write (newdoto, &a, sizeof a);
-
- exit (0);
-}
-
-
-
diff --git a/move-if-change b/move-if-change
new file mode 100755
index 00000000..66d8b8ad
--- /dev/null
+++ b/move-if-change
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Like mv $1 $2, but if the files are the same, just delete $1.
+# Status is 0 if $2 is changed, 1 otherwise.
+if
+test -r $2
+then
+if
+cmp -s $1 $2
+then
+echo $2 is unchanged
+rm -f $1
+else
+mv -f $1 $2
+fi
+else
+mv -f $1 $2
+fi
diff --git a/nfs/ChangeLog b/nfs/ChangeLog
deleted file mode 100644
index e213507e..00000000
--- a/nfs/ChangeLog
+++ /dev/null
@@ -1,170 +0,0 @@
-Wed Jul 31 13:25:00 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * ops.c (netfs_attempt_statfs): Use NFSPROC_STATFS, not SETATTR to
- do a statfs.
-
-Tue Jul 23 19:41:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * nfs.c (xdr_encode_sattr_times): `struct timespec' now uses a
- field prefix of `tv_'.
-
-Wed Jul 17 13:12:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c (mounted_soft): Initialize to zero.
-
-Thu Jul 4 17:14:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (netfs_attempt_link) [case SYMLINK]: Include directory
- handle as an RPC arg.
-
-Wed Jun 26 16:41:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (netfs_get_options): New function.
- (netfs_parse_runtime_options, netfs_unparse_runtime_options):
- Functions removed.
- (runtime_argp_parents, runtime_argp, netfs_runtime_argp): New variables.
- (main): Use &NETFS_STD_STARTUP_ARGP insteda of NETFS_STARTUP_ARGP.
-
-Thu Jun 13 09:24:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (SRCS): Remove pager.c.
- * nfs.h (struct netnode): Add member `fileinfo'.
- * nfs.h (register_fresh_stat): Add decl.
-
-Wed Jun 12 22:37:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (SRCS): Add pager.c.
-
-Wed May 22 18:49:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (parse_startup_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
-
-Tue May 14 14:00:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (netfs_attempt_unlink): Add new arg in call to
- netfs_attempt_link.
-
-Sat May 11 01:10:05 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (parse_common_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
-
-Fri May 10 18:15:11 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (netfs_attempt_rename, netfs_attempt_link): New parm EXCL,
- but don't implement the hard case yet.
-
-Thu May 9 20:24:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (netfs_attempt_statfs): Expect and fill in new statfs
- buffer.
-
-Fri Apr 19 13:50:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c (main): Failure to bind privileged ports is indicated by
- EACCES, not EPERM.
-
-Thu Apr 11 13:51:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (guess_mode_use): New function.
- (netfs_check_open_permissions, netfs_report_access): Replace old
- clever versions with less obtrusive one.
-
-Tue Apr 2 09:12:28 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (netfs_report_access): Bother to initialize LEN.
-
-Fri Mar 29 17:26:14 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * rpc.c: Define malloc to something random around include of rpc/*
- header files to avoid bogus definition there.
-
-Fri Mar 29 17:10:58 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (netfs_report_access): Make sure netfs_attempt_read return
- a reasonable LEN.
- (netfs_attempt_write): Truncate to THISAMT instead of AMT.
-
-Tue Mar 19 11:00:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Drop rpc.h.
-
- * consts.c: Doc fixes.
- * cache.c: Likewise.
- * cred.c: Likewise.
- * main.c: Likewise.
- * mount.c: Likewise.
- * mount.h: Likewise.
- * nfs.c: Likewise.
- * ops.c: Likewise.
- * rpc.c: Likewise.
-
- * rpc.c (rpc_receive_thread): Allocate receive buffer big enough
- for largest read we expect.
-
- * cache.c (lookup_fhandle): Correctly install new node in hash
- table slot.
-
- * main.c (parse_startup_opt): Pass STATE, not STATE->argp in call
- to argp_error.
-
- * cache.c (lookup_fhandle): Initialize NN->dead_dir and
- NN->dead_name.
-
- * ops.c: Include <unistd.h>.
- (register_fresh_stat): Repair syntax.
-
-Mon Mar 18 19:49:28 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main, netfs_parse_runtime_options): Pass new arg to
- argp_parse.
-
-Mon Mar 18 11:19:27 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (register_fresh_stat): Set fs_fsid, st_fstype, st_gen,
- st_author, and st_flags here.
- * nfs.c (xdr_decode_fattr): Don't set st_fstype, st_gen,
- st_author, or st_flags here.
-
- * ops.c (netfs_attempt_write): Increment OFFSET each time around
- the loop.
-
- * nfs.c (xdr_encode_create_state): Call hurd_mode_to_nfs_mode and
- htonl on MODE.
-
- * nfs.c (xdr_encode_sattr_stat): New function.
-
-Thu Mar 14 15:11:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * nfs.h (struct netnode): New members `dtrans' and `transarg'.
- * cache.c (lookup_fhandle): Initialize NN->dtrans.
- (netfs_node_norefs): Free transarg if necessary.
- (recache_handle): New function.
- * ops.c (netfs_attempt_mkfile): Make dtrans possible if it
- isn't already.
- (netfs_attempt_unlink): Likewise, when doing the rename hack.
- (netfs_attempt_mksymlink): Implement using dtrans and transarg.
- (netfs_attempt_mkdev): Likewise.
- (register_fresh_stat): If NP->nn->dtrans is set, then mutate the
- mode here.
- (netfs_attempt_readlink): If NP->nn->dtrans is SYMLINK, then DTRT.
- (netfs_attempt_link): Only issue NFSPROC_LINK if dtrans is not
- operative. Otherwise, DTRT.
- (netfs_attempt_chmod): Implement type-changing using dtrans.
-
-Tue Mar 12 15:23:32 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ops.c (netfs_set_translator, netfs_attempt_mksymlink,
- netfs_attempt_mkdev): New functions.
- (netfs_attempt_chmod): Detect attempt to change node type.
- (netfs_validate_stat): Clear NP->istranslated.
-
-Mon Mar 4 16:16:13 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Use NETFS_STARTUP_ARGP.
- (netfs_parse_runtime_options, netfs_unparse_runtime_options): New funs.
-
-Wed Feb 28 19:24:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (options): New variable.
- (main): Parse our arguments.
-
diff --git a/nfs/Makefile b/nfs/Makefile
index 66ecaeac..10ca2587 100644
--- a/nfs/Makefile
+++ b/nfs/Makefile
@@ -1,5 +1,7 @@
-#
-# Copyright (C) 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1995, 1996, 1997, 2000, 2001, 2008, 2011 Free Software
+# Foundation, Inc.
+#
# Written by Michael I. Bushnell.
#
# This file is part of the GNU Hurd.
@@ -22,10 +24,10 @@ dir := nfs
makemode := server
target = nfs
-LCLHDRS = nfs.h
-SRCS = ops.c rpc.c mount.c cred.c nfs.c cache.c consts.c main.c
-OBJS = $(subst .c,.o,$(SRCS))
-
-nfs: $(OBJS) ../libports/libports.a ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a ../libthreads/libthreads.a
+LCLHDRS = nfs.h mount.h nfs-spec.h
+SRCS = ops.c rpc.c mount.c nfs.c cache.c consts.c main.c name-cache.c \
+ storage-info.c
+OBJS = $(SRCS:.c=.o)
+HURDLIBS = netfs fshelp iohelp threads ports ihash shouldbeinlibc
include ../Makeconf
diff --git a/nfs/cache.c b/nfs/cache.c
index 65b46575..8f87f5d0 100644
--- a/nfs/cache.c
+++ b/nfs/cache.c
@@ -1,5 +1,5 @@
-/* Node cache management for NFS client implementation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/* cache.c - Node cache management for NFS client implementation.
+ Copyright (C) 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -21,49 +21,64 @@
#include "nfs.h"
#include <string.h>
+#include <netinet/in.h>
-/* Hash table containing all the nodes currently active. */
-#define CACHESIZE 512
+/* Hash table containing all the nodes currently active. XXX Was 512,
+ however, a prime is much nicer for the hash function. 509 is nice
+ as not only is it prime, it also keeps the array within a page or
+ two. */
+#define CACHESIZE 509
static struct node *nodehash [CACHESIZE];
-/* Compute and return a hash key for NFS file handle FHANDLE. */
+/* Compute and return a hash key for NFS file handle DATA of LEN
+ bytes. */
static inline int
-hash (void *fhandle)
+hash (int *data, size_t len)
{
unsigned int h = 0;
+ char *cp = (char *)data;
int i;
- for (i = 0; i < NFS_FHSIZE; i++)
- h += ((char *)fhandle)[i];
+ for (i = 0; i < len; i++)
+ h += cp[i];
return h % CACHESIZE;
}
-/* Lookup the specified file handle FHANDLE in the hash table. If it
- is not present, initialize a new node structure and insert it into
- the hash table. Whichever course, a new reference is generated and
- the node is returned. */
-struct node *
-lookup_fhandle (void *fhandle)
+/* Lookup the file handle P (length LEN) in the hash table. If it is
+ not present, initialize a new node structure and insert it into the
+ hash table. Whichever course, a new reference is generated and the
+ node is returned in *NPP; the lock on the node, (*NPP)->LOCK, is
+ held. */
+void
+lookup_fhandle (void *p, size_t len, struct node **npp)
{
struct node *np;
struct netnode *nn;
- int h = hash (fhandle);
+ int h;
+
+ h = hash (p, len);
spin_lock (&netfs_node_refcnt_lock);
for (np = nodehash[h]; np; np = np->nn->hnext)
{
- if (bcmp (np->nn->handle, fhandle, NFS_FHSIZE) != 0)
+ if (np->nn->handle.size != len
+ || memcmp (np->nn->handle.data, p, len) != 0)
continue;
np->references++;
spin_unlock (&netfs_node_refcnt_lock);
mutex_lock (&np->lock);
- return np;
+ *npp = np;
+ return;
}
+ /* Could not find it */
nn = malloc (sizeof (struct netnode));
- bcopy (fhandle, nn->handle, NFS_FHSIZE);
+ assert (nn);
+
+ nn->handle.size = len;
+ memcpy (nn->handle.data, p, len);
nn->stat_updated = 0;
nn->dtrans = NOT_POSSIBLE;
nn->dead_dir = 0;
@@ -79,34 +94,58 @@ lookup_fhandle (void *fhandle)
spin_unlock (&netfs_node_refcnt_lock);
- return np;
+ *npp = np;
}
+/* Package holding args to forked_node_delete. */
+struct fnd
+{
+ struct node *dir;
+ char *name;
+};
+
+/* Worker function to delete nodes that don't have any more local
+ references or links. */
+any_t
+forked_node_delete (any_t arg)
+{
+ struct fnd *args = arg;
+
+ mutex_lock (&args->dir->lock);
+ netfs_attempt_unlink ((struct iouser *)-1, args->dir, args->name);
+ netfs_nput (args->dir);
+ free (args->name);
+ free (args);
+ return 0;
+};
+
/* Called by libnetfs when node NP has no more references. (See
- <hurd/libnetfs.h> for details. Just clear local state and remove
- from the hash table. */
+ <hurd/libnetfs.h> for details. Just clear its local state and
+ remove it from the hash table. Called and expected to leave with
+ NETFS_NODE_REFCNT_LOCK held. */
void
netfs_node_norefs (struct node *np)
{
if (np->nn->dead_dir)
{
- struct node *dir;
- char *name;
+ struct fnd *args;
+
+ args = malloc (sizeof (struct fnd));
+ assert (args);
np->references++;
spin_unlock (&netfs_node_refcnt_lock);
- dir = np->nn->dead_dir;
- name = np->nn->dead_name;
+ args->dir = np->nn->dead_dir;
+ args->name = np->nn->dead_name;
np->nn->dead_dir = 0;
np->nn->dead_name = 0;
netfs_nput (np);
- mutex_lock (&dir->lock);
- netfs_attempt_unlink ((struct netcred *)-1, dir, name);
-
- netfs_nput (dir);
- free (name);
+ /* Do this in a separate thread so that we don't wait for it; it
+ acquires a lock on the dir, which we are not allowed to
+ do. */
+ cthread_detach (cthread_fork (forked_node_delete, (any_t) args));
/* Caller expects us to leave this locked... */
spin_lock (&netfs_node_refcnt_lock);
@@ -123,27 +162,41 @@ netfs_node_norefs (struct node *np)
}
}
-/* Change the file handle used for node NP to be HANDLE. Make sure the
- hash table stays up to date. */
-void
-recache_handle (struct node *np, void *handle)
+/* Change the file handle used for node NP to be the handle at P.
+ Make sure the hash table stays up to date. Return the address
+ after the handle. The lock on the node should be held. */
+int *
+recache_handle (int *p, struct node *np)
{
int h;
+ size_t len;
+
+ if (protocol_version == 2)
+ len = NFS2_FHSIZE;
+ else
+ {
+ len = ntohl (*p);
+ p++;
+ }
+ /* Unlink it */
spin_lock (&netfs_node_refcnt_lock);
*np->nn->hprevp = np->nn->hnext;
if (np->nn->hnext)
np->nn->hnext->nn->hprevp = np->nn->hprevp;
+
+ /* Change the name */
+ np->nn->handle.size = len;
+ memcpy (np->nn->handle.data, p, len);
- bcopy (handle, np->nn->handle, NFS_FHSIZE);
-
- h = hash (handle);
+ /* Reinsert it */
+ h = hash (p, len);
np->nn->hnext = nodehash[h];
if (np->nn->hnext)
np->nn->hnext->nn->hprevp = &np->nn->hnext;
np->nn->hprevp = &nodehash[h];
spin_unlock (&netfs_node_refcnt_lock);
+ return p + len / sizeof (int);
}
-
diff --git a/nfs/cred.c b/nfs/cred.c
deleted file mode 100644
index b83ebaaf..00000000
--- a/nfs/cred.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Credential manipulation for NFS client
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-#include <hurd/netfs.h>
-#include <string.h>
-
-#include "nfs.h"
-
-/* This lock must always be held when manipulating the reference count
- on credential structures. */
-static spin_lock_t cred_refcnt_lock = SPIN_LOCK_INITIALIZER;
-
-/* Interpret CRED, returning newly malloced storage describing the
- user identification references in UIDS, NUIDS, GIDS, and NGIDS.
- See <hurd/libnetfs.h> for details. */
-void
-netfs_interpret_credential (struct netcred *cred, uid_t **uids,
- int *nuids, uid_t **gids, int *ngids)
-{
- /* Who says C isn't APL? */
- bcopy (cred->uids, *uids = malloc ((*nuids = cred->nuids) * sizeof (uid_t)),
- cred->nuids * sizeof (uid_t));
- bcopy (cred->gids, *gids = malloc ((*ngids = cred->ngids) * sizeof (uid_t)),
- cred->ngids * sizeof (uid_t));
-}
-
-/* Return a new reference to CRED. See <hurd/libnetfs.h> for details. */
-struct netcred *
-netfs_copy_credential (struct netcred *cred)
-{
- spin_lock (&cred_refcnt_lock);
- cred->refcnt++;
- spin_unlock (&cred_refcnt_lock);
- return cred;
-}
-
-/* Drop a reference to CRED. See <hurd/libnetfs.h> for details. */
-void
-netfs_drop_credential (struct netcred *cred)
-{
- spin_lock (&cred_refcnt_lock);
- cred->refcnt--;
-
- if (!cred->refcnt)
- {
- spin_unlock (&cred_refcnt_lock);
- free (cred);
- }
- else
- spin_unlock (&cred_refcnt_lock);
-}
-
-/* Make and return a new credential referring to the user identified
- by UIDS, NUIDS, GIDS, and NGIDS. See <hurd/libnetfs.h> for
- details. */
-struct netcred *
-netfs_make_credential (uid_t *uids,
- int nuids,
- uid_t *gids,
- int ngids)
-{
- struct netcred *cred;
-
- cred = malloc (sizeof (struct netcred)
- + nuids * sizeof (uid_t)
- + ngids * sizeof (uid_t));
- cred->uids = (void *) cred + sizeof (struct netcred);
- cred->gids = (void *) cred->uids + nuids * sizeof (uid_t);
- cred->nuids = nuids;
- cred->ngids = ngids;
- cred->refcnt = 1;
-
- bcopy (uids, cred->uids, nuids + sizeof (uid_t));
- bcopy (gids, cred->gids, ngids + sizeof (uid_t));
-
- return cred;
-}
-
-/* Return nonzero iff CRED contains user id UID. */
-int
-cred_has_uid (struct netcred *cred, uid_t uid)
-{
- int i;
- for (i = 0; i < cred->nuids; i++)
- if (cred->uids[i] == uid)
- return 1;
- return 0;
-}
-
-/* Return nonzero iff CRED contains group id GID. */
-int
-cred_has_gid (struct netcred *cred, gid_t gid)
-{
- int i;
- for (i = 0; i < cred->ngids; i++)
- if (cred->gids[i] == gid)
- return 1;
- return 0;
-}
diff --git a/nfs/main.c b/nfs/main.c
index e709fc72..48852062 100644
--- a/nfs/main.c
+++ b/nfs/main.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -29,23 +29,34 @@
#include <maptime.h>
#include <argp.h>
#include <argz.h>
+#include <error.h>
+#include <version.h>
+
+char *netfs_server_name = "nfs";
+char *netfs_server_version = HURD_VERSION;
extern char *localhost ();
/* Default number of times to retry RPCs when mounted soft. */
-#define DEFAULT_SOFT_RETRIES 3
+#define DEFAULT_SOFT_RETRIES 3
/* Default number of seconds to timeout cached stat information. */
#define DEFAULT_STAT_TIMEOUT 3
/* Default number of seconds to timeout cached file contents. */
-#define DEFAULT_CACHE_TIMEOUT 3
+#define DEFAULT_CACHE_TIMEOUT 3
+
+/* Default number of seconds to timeout cache positive dir hits. */
+#define DEFAULT_NAME_CACHE_TIMEOUT 3
+
+/* Default number of seconds to timeout cache negative dir hits. */
+#define DEFAULT_NAME_CACHE_NEG_TIMEOUT 3
/* Default maximum number of bytes to read at once. */
-#define DEFAULT_READ_SIZE 8192
+#define DEFAULT_READ_SIZE 8192
/* Default maximum number of bytes to write at once. */
-#define DEFAULT_WRITE_SIZE 8192
+#define DEFAULT_WRITE_SIZE 8192
/* Number of seconds to timeout cached stat information. */
@@ -54,6 +65,12 @@ int stat_timeout = DEFAULT_STAT_TIMEOUT;
/* Number of seconds to timeout cached file contents. */
int cache_timeout = DEFAULT_CACHE_TIMEOUT;
+/* Number of seconds to timeout cached positive dir hits. */
+int name_cache_timeout = DEFAULT_NAME_CACHE_TIMEOUT;
+
+/* Number of seconds to timeout cached negative dir hits. */
+int name_cache_neg_timeout = DEFAULT_NAME_CACHE_NEG_TIMEOUT;
+
/* Number of seconds to wait for first retransmission of an RPC. */
int initial_transmit_timeout = 1;
@@ -74,8 +91,8 @@ int write_size = DEFAULT_WRITE_SIZE;
#define OPT_SOFT 's'
#define OPT_HARD 'h'
-#define OPT_RSIZE 'r'
-#define OPT_WSIZE 'w'
+#define OPT_RSIZE 'R'
+#define OPT_WSIZE 'W'
#define OPT_STAT_TO -2
#define OPT_CACHE_TO -3
#define OPT_INIT_TR_TO -4
@@ -88,19 +105,23 @@ int write_size = DEFAULT_WRITE_SIZE;
#define OPT_MNT_PROG -11
#define OPT_NFS_PROG -12
#define OPT_PMAP_PORT -13
+#define OPT_NCACHE_TO -14
+#define OPT_NCACHE_NEG_TO -15
/* Return a string corresponding to the printed rep of DEFAULT_what */
#define ___D(what) #what
#define __D(what) ___D(what)
#define _D(what) __D(DEFAULT_ ## what)
+const char *argp_program_version = STANDARD_HURD_VERSION (nfs);
+
/* Options usable both at startup and at runtime. */
static const struct argp_option common_options[] =
{
{0,0,0,0,0,1},
{"soft", OPT_SOFT, "RETRIES", OPTION_ARG_OPTIONAL,
- "File system requests will eventually fail, after RETRIES tries if"
- " specified, otherwise " _D(SOFT_RETRIES)},
+ "File system requests will eventually fail, after RETRIES tries"
+ " (default " _D(SOFT_RETRIES) ")" },
{"hard", OPT_HARD, 0, 0,
"Retry file systems requests until they succeed"},
@@ -117,6 +138,12 @@ static const struct argp_option common_options[] =
"Timeout for cached stat information (default " _D(STAT_TIMEOUT) ")"},
{"cache-timeout", OPT_CACHE_TO, "SEC", 0,
"Timeout for cached file data (default " _D(CACHE_TIMEOUT) ")"},
+ {"name-cache-timeout", OPT_NCACHE_TO, "SEC", 0,
+ "Timeout for positive directory cache entries (default "
+ _D(NAME_CACHE_TIMEOUT) ")"},
+ {"name-cache-neg-timeout", OPT_NCACHE_NEG_TO, "SEC", 0,
+ "Timeout for negative directory cache entires (default "
+ _D(NAME_CACHE_NEG_TIMEOUT) ")"},
{"init-transmit-timeout", OPT_INIT_TR_TO,"SEC", 0},
{"max-transmit-timeout", OPT_MAX_TR_TO, "SEC", 0},
@@ -144,6 +171,8 @@ parse_common_opt (int key, char *arg, struct argp_state *state)
case OPT_CACHE_TO: cache_timeout = atoi (arg); break;
case OPT_INIT_TR_TO: initial_transmit_timeout = atoi (arg); break;
case OPT_MAX_TR_TO: max_transmit_timeout = atoi (arg); break;
+ case OPT_NCACHE_TO: name_cache_timeout = atoi (arg); break;
+ case OPT_NCACHE_NEG_TO: name_cache_neg_timeout = atoi (arg); break;
default:
return ARGP_ERR_UNKNOWN;
@@ -172,29 +201,32 @@ static const struct argp_option startup_options[] = {
{ 0 }
};
static char *args_doc = "REMOTE_FS [HOST]";
-static char *doc = "If HOST is not specified, an attempt is made to extract"
-" it from REMOTE_FS, using either the `HOST:FS' or `FS@HOST' notations.";
+static char *doc = "Hurd nfs translator"
+"\vIf HOST is not specified, an attempt is made to extract"
+" it from REMOTE_FS using either the `HOST:FS' or `FS@HOST' notations.";
-static const struct argp *
-runtime_argp_parents[] = { &netfs_std_runtime_argp, 0 };
+static const struct argp_child
+runtime_argp_children[] = { {&netfs_std_runtime_argp}, {0} };
static struct argp
-runtime_argp = { common_options, parse_common_opt, 0, 0, runtime_argp_parents };
+runtime_argp = { common_options, parse_common_opt, 0, 0,
+ runtime_argp_children };
-/* Use by netfs_set_options to handle runtime option parsing. */
+/* Used by netfs_set_options to handle runtime option parsing. */
struct argp *netfs_runtime_argp = &runtime_argp;
+/* Where to find the remote filesystem. */
+static char *remote_fs; /* = 0; */
+static char *host; /* = 0; */
+
/* Return an argz string describing the current options. Fill *ARGZ
with a pointer to newly malloced storage holding the list and *LEN
to the length of that storage. */
error_t
-netfs_get_options (char **argz, size_t *argz_len)
+netfs_append_args (char **argz, size_t *argz_len)
{
char buf[80];
error_t err = 0;
- *argz = 0;
- *argz_len = 0;
-
#define FOPT(fmt, arg) \
do { \
if (! err) \
@@ -216,12 +248,23 @@ netfs_get_options (char **argz, size_t *argz_len)
FOPT ("--cache-timeout=%d", cache_timeout);
FOPT ("--init-transmit-timeout=%d", initial_transmit_timeout);
FOPT ("--max-transmit-timeout=%d", max_transmit_timeout);
+ FOPT ("--name-cache-timeout=%d", name_cache_timeout);
+ FOPT ("--name-cache-neg-timeout=%d", name_cache_neg_timeout);
if (! err)
err = netfs_append_std_options (argz, argz_len);
- if (err)
- free (argz);
+ if (! err)
+ {
+ char *fs;
+ if (asprintf (&fs, "%s:%s", host, remote_fs))
+ {
+ err = argz_add (argz, argz_len, fs);
+ free (fs);
+ }
+ else
+ err = ENOMEM;
+ }
return err;
}
@@ -235,6 +278,8 @@ extract_nfs_args (char *spec, char **remote_fs, char **host)
char *sep;
spec = strdup (spec); /* So we can trash it. */
+ if (! spec)
+ return NULL;
sep = index (spec, ':');
if (sep)
@@ -259,13 +304,6 @@ extract_nfs_args (char *spec, char **remote_fs, char **host)
return 0;
}
-/* Where to find the remote filesystem. */
-static char *remote_fs = 0;
-static char *host = 0;
-
-/* For debugging. */
-static volatile int hold = 0;
-
static error_t
parse_startup_opt (int key, char *arg, struct argp_state *state)
{
@@ -285,8 +323,6 @@ parse_startup_opt (int key, char *arg, struct argp_state *state)
nfs_port = atoi (arg);
break;
- case OPT_HOLD: hold = 1; break;
-
case ARGP_KEY_ARG:
if (state->arg_num == 0)
remote_fs = arg;
@@ -315,18 +351,17 @@ parse_startup_opt (int key, char *arg, struct argp_state *state)
int
main (int argc, char **argv)
{
+ error_t err;
struct argp common_argp = { common_options, parse_common_opt };
- const struct argp *argp_parents[] =
- { &common_argp, &netfs_std_startup_argp, 0 };
+ const struct argp_child argp_children[] =
+ { {&common_argp}, {&netfs_std_startup_argp}, {0} };
struct argp argp =
- { startup_options, parse_startup_opt, args_doc, doc, argp_parents };
+ { startup_options, parse_startup_opt, args_doc, doc, argp_children };
mach_port_t bootstrap;
struct sockaddr_in addr;
int ret;
argp_parse (&argp, argc, argv, 0, 0, 0);
-
- while (hold);
task_get_bootstrap_port (mach_task_self (), &bootstrap);
netfs_init ();
@@ -350,14 +385,11 @@ main (int argc, char **argv)
}
while ((ret == -1) && (errno == EADDRINUSE));
if (ret == -1)
- {
- perror ("binding main udp socket");
- exit (1);
- }
+ error (1, errno, "binding main udp socket");
- errno = maptime_map (0, 0, &mapped_time);
- if (errno)
- perror ("mapping time");
+ err = maptime_map (0, 0, &mapped_time);
+ if (err)
+ error (2, err, "mapping time");
cthread_detach (cthread_fork ((cthread_fn_t) timeout_service_thread, 0));
cthread_detach (cthread_fork ((cthread_fn_t) rpc_receive_thread, 0));
diff --git a/nfs/mount.c b/nfs/mount.c
index 59363073..6120f87a 100644
--- a/nfs/mount.c
+++ b/nfs/mount.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,22 +18,28 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include "nfs.h"
-
-#include <rpcsvc/mount.h>
+#define malloc a_byte_for_every_bozotic_sun_lossage_and_youd_need_a_lotta_ram
+#include <rpc/types.h>
+#undef TRUE /* Get rid of sun defs. */
+#undef FALSE
+#undef malloc
#include <rpc/pmap_prot.h>
#include <errno.h>
+#include <error.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
+#include "nfs.h"
+#include "mount.h"
+
/* Service name for portmapper */
char *pmap_service_name = "sunrpc";
/* Fallback port number for portmapper */
-short pmap_service_number = PMAPPORT;
+short pmap_service_number = PMAPPORT;
/* RPC program for mount server. */
int mount_program = MOUNTPROG;
@@ -59,11 +65,17 @@ short nfs_port = NFS_PORT;
/* True iff NFS_PORT should be used even if portmapper present. */
int nfs_port_override = 0;
+/* Host name and port number we actually decided to use. */
+const char *mounted_hostname;
+uint16_t mounted_nfs_port; /* host order */
+
+int protocol_version = 2;
+
/* Set up an RPC for procedure PROCNUM for talking to the portmapper.
Allocate storage with malloc and point *BUF at it; caller must free
this when done. Return the address where the args for the
procedure should be placed. */
-int *
+static int *
pmap_initialize_rpc (int procnum, void **buf)
{
return initialize_rpc (PMAPPROG, PMAPVERS, procnum, 0, buf, 0, 0, -1);
@@ -73,29 +85,38 @@ pmap_initialize_rpc (int procnum, void **buf)
server. Allocate storage with malloc and point *BUF at it; caller
must free this when done. Return the address where the args for
the procedure should be placed. */
-int *
+static int *
mount_initialize_rpc (int procnum, void **buf)
{
return initialize_rpc (MOUNTPROG, MOUNTVERS, procnum, 0, buf, 0, 0, -1);
}
/* Using the mount protocol, lookup NAME at host HOST.
- Return a node for it or null for an error. */
+ Return a node for it or null for an error. If an
+ error occurs, a message is automatically sent to stderr. */
struct node *
mount_root (char *name, char *host)
{
struct sockaddr_in addr;
struct hostent *h;
- struct servent *s;
int *p;
void *rpcbuf;
int port;
+ error_t err;
struct node *np;
short pmapport;
/* Lookup the portmapper port number */
if (pmap_service_name)
{
+ struct servent *s;
+
+ /* XXX This will always fail! pmap_service_name will always be "sunrpc"
+ What should pmap_service_name really be? By definition the second
+ argument is either "tcp" or "udp" Thus, is this backwards
+ (as service_name suggests)? If so, should it read:
+ s = getservbyname (pmap_service_name, "udp");
+ or is there something I am missing here? */
s = getservbyname ("sunrpc", pmap_service_name);
if (s)
pmapport = s->s_port;
@@ -112,103 +133,145 @@ mount_root (char *name, char *host)
herror (host);
return 0;
}
-
+
addr.sin_family = h->h_addrtype;
- bcopy (h->h_addr_list[0], &addr.sin_addr, h->h_length);
+ memcpy (&addr.sin_addr, h->h_addr_list[0], h->h_length);
addr.sin_port = pmapport;
-
- connect (main_udp_socket,
- (struct sockaddr *)&addr, sizeof (struct sockaddr_in));
- if (!mount_port_override)
+ if (mount_port_override)
+ addr.sin_port = htons (mount_port);
+ else
{
/* Formulate and send a PMAPPROC_GETPORT request
to lookup the mount program on the server. */
+ if (connect (main_udp_socket, (struct sockaddr *)&addr,
+ sizeof (struct sockaddr_in)) == -1)
+ {
+ error (0, errno, "server mount program");
+ return 0;
+ }
+
p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf);
- *p++ = htonl (MOUNTPROG);
- *p++ = htonl (MOUNTVERS);
- *p++ = htonl (IPPROTO_UDP);
- *p++ = htonl (0);
- errno = conduct_rpc (&rpcbuf, &p);
- if (!errno)
+ if (! p)
{
- port = ntohl (*p++);
+ error (0, errno, "creating rpc packet");
+ return 0;
+ }
+
+ *(p++) = htonl (MOUNTPROG);
+ *(p++) = htonl (MOUNTVERS);
+ *(p++) = htonl (IPPROTO_UDP);
+ *(p++) = htonl (0);
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ port = ntohl (*p);
+ p++;
addr.sin_port = htons (port);
}
else if (mount_port)
addr.sin_port = htons (mount_port);
else
{
- free (rpcbuf);
- perror ("portmap of mount");
- return 0;
+ error (0, err, "portmap of mount");
+ goto error_with_rpcbuf;
}
free (rpcbuf);
}
- else
- addr.sin_port = htons (mount_port);
-
- /* Now talking to the mount program, fetch the file handle
+ /* Now, talking to the mount program, fetch a file handle
for the root. */
- connect (main_udp_socket,
- (struct sockaddr *) &addr, sizeof (struct sockaddr_in));
+ if (connect (main_udp_socket, (struct sockaddr *) &addr,
+ sizeof (struct sockaddr_in)) == -1)
+ {
+ error (0, errno, "connect");
+ goto error_with_rpcbuf;
+ }
+
p = mount_initialize_rpc (MOUNTPROC_MNT, &rpcbuf);
+ if (! p)
+ {
+ error (0, errno, "rpc");
+ goto error_with_rpcbuf;
+ }
+
p = xdr_encode_string (p, name);
- errno = conduct_rpc (&rpcbuf, &p);
- if (errno)
+ err = conduct_rpc (&rpcbuf, &p);
+ if (err)
{
- free (rpcbuf);
- perror (name);
- return 0;
+ error (0, err, "%s", name);
+ goto error_with_rpcbuf;
}
/* XXX Protocol spec says this should be a "unix error code"; we'll
- pretend that an NFS error code is what's meant, the numbers match
+ pretend that an NFS error code is what's meant; the numbers match
anyhow. */
- errno = nfs_error_trans (htonl (*p++));
- if (errno)
+ err = nfs_error_trans (htonl (*p));
+ p++;
+ if (err)
{
- free (rpcbuf);
- perror (name);
- return 0;
+ error (0, err, "%s", name);
+ goto error_with_rpcbuf;
}
-
+
/* Create the node for root */
- np = lookup_fhandle (p);
- p += NFS_FHSIZE / sizeof (int);
+ xdr_decode_fhandle (p, &np);
free (rpcbuf);
mutex_unlock (&np->lock);
- if (!nfs_port_override)
+ if (nfs_port_override)
+ port = nfs_port;
+ else
{
- /* Now send another PMAPPROC_GETPORT request to lookup the nfs server. */
+ /* Send another PMAPPROC_GETPORT request to lookup the nfs server. */
addr.sin_port = pmapport;
- connect (main_udp_socket,
- (struct sockaddr *) &addr, sizeof (struct sockaddr_in));
+ if (connect (main_udp_socket, (struct sockaddr *) &addr,
+ sizeof (struct sockaddr_in)) == -1)
+ {
+ error (0, errno, "connect");
+ return 0;
+ }
+
p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf);
- *p++ = htonl (NFS_PROGRAM);
- *p++ = htonl (NFS_VERSION);
- *p++ = htonl (IPPROTO_UDP);
- *p++ = htonl (0);
- errno = conduct_rpc (&rpcbuf, &p);
- if (!errno)
- port = ntohl (*p++);
+ if (! p)
+ {
+ error (0, errno, "rpc");
+ goto error_with_rpcbuf;
+ }
+ *(p++) = htonl (NFS_PROGRAM);
+ *(p++) = htonl (NFS_VERSION);
+ *(p++) = htonl (IPPROTO_UDP);
+ *(p++) = htonl (0);
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ port = ntohl (*p);
+ p++;
+ }
else if (nfs_port)
port = nfs_port;
else
{
- free (rpcbuf);
- perror ("pmap of nfs server");
- return 0;
+ error (0, err, "portmap of nfs server");
+ goto error_with_rpcbuf;
}
free (rpcbuf);
}
- else
- port = nfs_port;
-
+
addr.sin_port = htons (port);
- connect (main_udp_socket,
- (struct sockaddr *) &addr, sizeof (struct sockaddr_in));
-
+ if (connect (main_udp_socket, (struct sockaddr *) &addr,
+ sizeof (struct sockaddr_in)) == -1)
+ {
+ error (0, errno, "connect");
+ return 0;
+ }
+
+ mounted_hostname = host;
+ mounted_nfs_port = port;
+
return np;
+
+error_with_rpcbuf:
+ free (rpcbuf);
+
+ return 0;
}
diff --git a/nfs/mount.h b/nfs/mount.h
index b1862442..4cb62a83 100644
--- a/nfs/mount.h
+++ b/nfs/mount.h
@@ -20,8 +20,11 @@
/* These constants define the RPC mount protocol; see RFC 1094. */
-#define MOUNT_RPC_PROGRAM 100005
-#define MOUNT_RPC_VERSION 1
+#ifndef NFS_MOUNT_H
+#define NFS_MOUNT_H
+
+#define MOUNTPROG 100005
+#define MOUNTVERS 1
/* Obnoxious arbitrary limits */
#define MOUNT_MNTPATHLEN 1024
@@ -33,3 +36,5 @@
#define MOUNTPROC_UMNT 3
#define MOUNTPROC_UMNTALL 4
#define MOUNTPROC_EXPORT 5
+
+#endif /* NFS_MOUNT_H */
diff --git a/nfs/name-cache.c b/nfs/name-cache.c
new file mode 100644
index 00000000..845cda30
--- /dev/null
+++ b/nfs/name-cache.c
@@ -0,0 +1,305 @@
+/* Directory name lookup caching
+
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG, & Miles Bader.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "nfs.h"
+#include <string.h>
+#include <cacheq.h>
+
+
+/* Maximum number of names to cache at any given time */
+#define MAXCACHE 200
+
+/* Maximum length of file name we bother caching */
+#define CACHE_NAME_LEN 100
+
+/* Cache entry */
+struct lookup_cache
+{
+ struct cacheq_hdr hdr;
+
+ /* File handles and lengths for cache entries. 0 for NODE_CACHE_LEN
+ means a */
+ char dir_cache_fh[NFS3_FHSIZE];
+ size_t dir_cache_len;
+
+ /* Zero means a `negative' entry -- recording that there's
+ definitely no node with this name. */
+ struct node *np;
+
+ /* Name of the node NODE_CACHE_ID in the directory DIR_CACHE_ID. Entries
+ with names too long to fit in this buffer aren't cached at all. */
+ char name[CACHE_NAME_LEN];
+
+ /* Strlen of NAME. If this is zero, it's an unused entry. */
+ size_t name_len;
+
+ /* Time that this cache entry was created. */
+ time_t cache_stamp;
+
+ /* XXX */
+ int stati;
+};
+
+/* The contents of the cache in no particular order */
+static struct cacheq lookup_cache = { sizeof (struct lookup_cache) };
+
+static spin_lock_t cache_lock = SPIN_LOCK_INITIALIZER;
+
+/* Buffer to hold statistics */
+static struct stats
+{
+ long pos_hits;
+ long neg_hits;
+ long miss;
+ long fetch_errors;
+} statistics;
+
+#define PARTIAL_THRESH 100
+#define NPARTIALS (MAXCACHE / PARTIAL_THRESH)
+struct stats partial_stats [NPARTIALS];
+
+
+/* If there's an entry for NAME, of length NAME_LEN, in directory DIR in the
+ cache, return its entry, otherwise 0. CACHE_LOCK must be held. */
+static struct lookup_cache *
+find_cache (char *dir, size_t len, const char *name, size_t name_len)
+{
+ struct lookup_cache *c;
+ int i;
+
+ /* Search the list. All unused entries are contiguous at the end of the
+ list, so we can stop searching when we see the first one. */
+ for (i = 0, c = lookup_cache.mru;
+ c && c->name_len;
+ c = c->hdr.next, i++)
+ if (c->name_len == name_len
+ && c->dir_cache_len == len
+ && c->name[0] == name[0]
+ && memcmp (c->dir_cache_fh, dir, len) == 0
+ && strcmp (c->name, name) == 0)
+ {
+ c->stati = i / PARTIAL_THRESH;
+ return c;
+ }
+
+ return 0;
+}
+
+/* Node NP has just been found in DIR with NAME. If NP is null, this
+ name has been confirmed as absent in the directory. DIR is the
+ fhandle of the directory and LEN is its length. */
+void
+enter_lookup_cache (char *dir, size_t len, struct node *np, char *name)
+{
+ struct lookup_cache *c;
+ size_t name_len = strlen (name);
+
+ if (name_len > CACHE_NAME_LEN - 1)
+ return;
+
+ spin_lock (&cache_lock);
+
+ if (lookup_cache.length == 0)
+ /* There should always be an lru_cache; this being zero means that the
+ cache hasn't been initialized yet. Do so. */
+ cacheq_set_length (&lookup_cache, MAXCACHE);
+
+ /* See if there's an old entry for NAME in DIR. If not, replace the least
+ recently used entry. */
+ c = find_cache (dir, len, name, name_len) ?: lookup_cache.lru;
+
+ /* Fill C with the new entry. */
+ memcpy (c->dir_cache_fh, dir, len);
+ c->dir_cache_len = len;
+ if (c->np)
+ netfs_nrele (c->np);
+ c->np = np;
+ if (c->np)
+ netfs_nref (c->np);
+ strcpy (c->name, name);
+ c->name_len = name_len;
+ c->cache_stamp = mapped_time->seconds;
+
+ /* Now C becomes the MRU entry! */
+ cacheq_make_mru (&lookup_cache, c);
+
+ spin_unlock (&cache_lock);
+}
+
+/* Purge all references in the cache to NAME within directory DIR. */
+void
+purge_lookup_cache (struct node *dp, char *name, size_t namelen)
+{
+ struct lookup_cache *c, *next;
+
+ spin_lock (&cache_lock);
+ for (c = lookup_cache.mru; c; c = next)
+ {
+ /* Save C->hdr.next, since we may move C from this position. */
+ next = c->hdr.next;
+
+ if (c->name_len == namelen
+ && c->dir_cache_len == dp->nn->handle.size
+ && memcmp (c->dir_cache_fh, dp->nn->handle.data,
+ c->dir_cache_len) == 0
+ && strcmp (c->name, name) == 0)
+ {
+ if (c->np)
+ netfs_nrele (c->np);
+ c->name_len = 0;
+ c->np = 0;
+ cacheq_make_lru (&lookup_cache, c); /* Use C as the next free
+ entry. */
+ }
+ }
+ spin_unlock (&cache_lock);
+}
+
+/* Purge all references in the cache to node NP. */
+void
+purge_lookup_cache_node (struct node *np)
+{
+ struct lookup_cache *c, *next;
+
+ spin_lock (&cache_lock);
+ for (c = lookup_cache.mru; c; c = next)
+ {
+ next = c->hdr.next;
+
+ if (c->np == np)
+ {
+ netfs_nrele (c->np);
+ c->name_len = 0;
+ c->np = 0;
+ cacheq_make_lru (&lookup_cache, c);
+ }
+ }
+ spin_unlock (&cache_lock);
+}
+
+
+
+/* Register a negative hit for an entry in the Nth stat class */
+void
+register_neg_hit (int n)
+{
+ int i;
+
+ statistics.neg_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].neg_hits++;
+}
+
+/* Register a positive hit for an entry in the Nth stat class */
+void
+register_pos_hit (int n)
+{
+ int i;
+
+ statistics.pos_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].pos_hits++;
+}
+
+/* Register a miss */
+void
+register_miss ()
+{
+ int i;
+
+ statistics.miss++;
+ for (i = 0; i < NPARTIALS; i++)
+ partial_stats[i].miss++;
+}
+
+
+
+/* Scan the cache looking for NAME inside DIR. If we know nothing
+ about the entry, then return 0. If the entry is confirmed to not
+ exist, then return -1. Otherwise, return NP for the entry, with
+ a newly allocated reference. For all return values other than 0,
+ unlock DIR->LOCK before returning. For positive hits, lock the
+ returned node. */
+struct node *
+check_lookup_cache (struct node *dir, char *name)
+{
+ struct lookup_cache *c;
+
+ spin_lock (&cache_lock);
+
+ c = find_cache (dir->nn->handle.data, dir->nn->handle.size,
+ name, strlen (name));
+ if (c)
+ {
+ int timeout = c->np
+ ? name_cache_timeout
+ : name_cache_neg_timeout;
+
+ /* Make sure the entry is still usable; if not, zap it now. */
+ if (mapped_time->seconds - c->cache_stamp >= timeout)
+ {
+ register_neg_hit (c->stati);
+ if (c->np)
+ netfs_nrele (c->np);
+ c->name_len = 0;
+ c->np = 0;
+ cacheq_make_lru (&lookup_cache, c);
+ spin_unlock (&cache_lock);
+ return 0;
+ }
+
+ cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */
+
+ if (c->np == 0)
+ /* A negative cache entry. */
+ {
+ register_neg_hit (c->stati);
+ spin_unlock (&cache_lock);
+ mutex_unlock (&dir->lock);
+ return (struct node *)-1;
+ }
+ else
+ {
+ struct node *np;
+
+ np = c->np;
+ netfs_nref (np);
+ register_pos_hit (c->stati);
+ spin_unlock (&cache_lock);
+
+ mutex_unlock (&dir->lock);
+ mutex_lock (&np->lock);
+
+ return np;
+ }
+ }
+
+ register_miss ();
+ spin_unlock (&cache_lock);
+
+ return 0;
+}
diff --git a/nfs/nfs-spec.h b/nfs/nfs-spec.h
new file mode 100644
index 00000000..bed03874
--- /dev/null
+++ b/nfs/nfs-spec.h
@@ -0,0 +1,168 @@
+#ifndef NFS_NFS_SPEC_H
+#define NFS_NFS_SPEC_H
+
+#define NFS_PORT 2049
+#define NFS_MAXDATA 8192
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS2_FHSIZE 32
+#define NFS3_FHSIZE 64
+#define NFS_COOKIESIZE 4
+#define NFS_FIFO_DEV -1
+#define NFS3_COOKIEVERFSIZE 8
+#define NFS3_CREATEVERFSIZE 8
+#define NFS3_WRITEVERFSIZE 8
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+enum nfsstat {
+ NFS_OK = 0,
+ NFSERR_PERM = 1,
+ NFSERR_NOENT = 2,
+ NFSERR_IO = 5,
+ NFSERR_NXIO = 6,
+ NFSERR_ACCES = 13,
+ NFSERR_EXIST = 17,
+ NFSERR_XDEV = 18, /* v3 only */
+ NFSERR_NODEV = 19,
+ NFSERR_NOTDIR = 20,
+ NFSERR_ISDIR = 21,
+ NFSERR_INVAL = 22, /* v3 only */
+ NFSERR_FBIG = 27,
+ NFSERR_NOSPC = 28,
+ NFSERR_ROFS = 30,
+ NFSERR_MLINK = 31, /* v3 only */
+ NFSERR_NAMETOOLONG = 63,
+ NFSERR_NOTEMPTY = 66,
+ NFSERR_DQUOT = 69,
+ NFSERR_STALE = 70,
+ NFSERR_REMOTE = 71, /* v3 only */
+ NFSERR_WFLUSH = 99, /* v2 only */
+ NFSERR_BADHANDLE = 10001, /* v3 only */
+ NFSERR_NOT_SYNC = 10002, /* v3 only */
+ NFSERR_BAD_COOKIE = 10003, /* v3 only */
+ NFSERR_NOTSUPP = 10004, /* v3 only */
+ NFSERR_TOOSMALL = 10005, /* v3 only */
+ NFSERR_SERVERFAULT = 10006, /* v3 only */
+ NFSERR_BADTYPE = 10007, /* v3 only */
+ NFSERR_JUKEBOX = 10008, /* v3 only */
+#define NFSERR_TRYLATER NFSERR_JUKEBOX
+};
+
+
+enum ftype {
+ NF2NON = 0, /* v2 only */
+ NFREG = 1,
+ NFDIR = 2,
+ NFBLK = 3,
+ NFCHR = 4,
+ NFLNK = 5,
+ NFSOCK = 6,
+ NF3FIFO = 7, /* v3 only */
+#define NF2BAD NF3FIFO /* v2 only */
+ NF2FIFO = 8, /* v2 only */
+};
+
+/* Ways to set the time in setattr structures */
+enum sattr_time_how
+{
+ DONT_CHANGE = 0,
+ SET_TO_SERVER_TIME = 1,
+ SET_TO_CLIENT_TIME = 2,
+};
+
+/* Construction of ACCESS arg to NFS3PROC_ACCESS. */
+#define ACCESS3_READ 0x01
+#define ACCESS3_LOOKUP 0x02
+#define ACCESS3_MODIFY 0x04
+#define ACCESS3_EXTEND 0x08
+#define ACCESS3_DELETE 0x10
+#define ACCESS3_EXECUTE 0x20
+
+/* STABLE arg to NFS3PROC_READ */
+enum stable_how {
+ UNSTABLE = 0,
+ DATA_SYNC = 1,
+ FILE_SYNC = 2,
+};
+
+/* MODE arg to NFS3PROC_CREATE */
+enum createmode
+{
+ UNCHECKED = 0,
+ GUARDED = 1,
+ EXCLUSIVE = 2,
+};
+
+#define NFS_PROGRAM ((u_long)100003)
+#define NFS_VERSION ((u_long)2)
+
+#define NFS_PROTOCOL_FUNC(proc,vers) \
+ (vers == 2 ? NFS2PROC_ ## proc : NFS3PROC_ ## proc)
+
+#define NFSPROC_NULL(v) NFS_PROTOCOL_FUNC (NULL,v)
+#define NFSPROC_GETATTR(v) NFS_PROTOCOL_FUNC (GETATTR, v)
+#define NFSPROC_SETATTR(v) NFS_PROTOCOL_FUNC (SETATTR, v)
+#define NFSPROC_LOOKUP(v) NFS_PROTOCOL_FUNC (LOOKUP, v)
+#define NFSPROC_READLINK(v) NFS_PROTOCOL_FUNC (READLINK, v)
+#define NFSPROC_READ(v) NFS_PROTOCOL_FUNC (READ, v)
+#define NFSPROC_WRITE(v) NFS_PROTOCOL_FUNC (WRITE, v)
+#define NFSPROC_CREATE(v) NFS_PROTOCOL_FUNC (CREATE, v)
+#define NFSPROC_REMOVE(v) NFS_PROTOCOL_FUNC (REMOVE, v)
+#define NFSPROC_RENAME(v) NFS_PROTOCOL_FUNC (RENAME, v)
+#define NFSPROC_LINK(v) NFS_PROTOCOL_FUNC (LINK, v)
+#define NFSPROC_SYMLINK(v) NFS_PROTOCOL_FUNC (SYMLINK, v)
+#define NFSPROC_MKDIR(v) NFS_PROTOCOL_FUNC (MKDIR, v)
+#define NFSPROC_RMDIR(v) NFS_PROTOCOL_FUNC (RMDIR, v)
+#define NFSPROC_READDIR(v) NFS_PROTOCOL_FUNC (READDIR, v)
+
+/* Values for each protocol */
+#define NFS2PROC_NULL 0
+#define NFS2PROC_GETATTR 1
+#define NFS2PROC_SETATTR 2
+#define NFS2PROC_ROOT 3
+#define NFS2PROC_LOOKUP 4
+#define NFS2PROC_READLINK 5
+#define NFS2PROC_READ 6
+#define NFS2PROC_WRITECACHE 7
+#define NFS2PROC_WRITE 8
+#define NFS2PROC_CREATE 9
+#define NFS2PROC_REMOVE 10
+#define NFS2PROC_RENAME 11
+#define NFS2PROC_LINK 12
+#define NFS2PROC_SYMLINK 13
+#define NFS2PROC_MKDIR 14
+#define NFS2PROC_RMDIR 15
+#define NFS2PROC_READDIR 16
+#define NFS2PROC_STATFS 17
+
+#define NFS3PROC_NULL 0
+#define NFS3PROC_GETATTR 1
+#define NFS3PROC_SETATTR 2
+#define NFS3PROC_LOOKUP 3
+#define NFS3PROC_ACCESS 4
+#define NFS3PROC_READLINK 5
+#define NFS3PROC_READ 6
+#define NFS3PROC_WRITE 7
+#define NFS3PROC_CREATE 8
+#define NFS3PROC_MKDIR 9
+#define NFS3PROC_SYMLINK 10
+#define NFS3PROC_MKNOD 11
+#define NFS3PROC_REMOVE 12
+#define NFS3PROC_RMDIR 13
+#define NFS3PROC_RENAME 14
+#define NFS3PROC_LINK 15
+#define NFS3PROC_READDIR 16
+#define NFS3PROC_READDIRPLUS 17
+#define NFS3PROC_FSSTAT 18
+#define NFS3PROC_FSINFO 19
+#define NFS3PROC_PATHCONF 20
+#define NFS3PROC_COMMIT 21
+
+#endif /* NFS_NFS_SPEC_H */
diff --git a/nfs/nfs.c b/nfs/nfs.c
index 617ca334..4916df65 100644
--- a/nfs/nfs.c
+++ b/nfs/nfs.c
@@ -1,5 +1,8 @@
-/* XDR frobbing and lower level routines for NFS client
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/* nfs.c - XDR frobbing and lower level routines for NFS client.
+
+ Copyright (C) 1995, 1996, 1997, 1999, 2002, 2007
+ Free Software Foundation, Inc.
+
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -24,12 +27,13 @@
#include <netinet/in.h>
#include <stdio.h>
-/* Convert an NFS mode (TYPE and MODE) to a Hurd mode and return it. */
+/* Convert an NFS mode (TYPE and MODE) to a Hurd mode and return
+ it. */
mode_t
nfs_mode_to_hurd_mode (int type, int mode)
{
int hurdmode;
-
+
switch (type)
{
case NFDIR:
@@ -45,12 +49,9 @@ nfs_mode_to_hurd_mode (int type, int mode)
break;
case NFREG:
- case NFNON:
- case NFBAD:
- default:
hurdmode = S_IFREG;
break;
-
+
case NFLNK:
hurdmode = S_IFLNK;
break;
@@ -59,16 +60,39 @@ nfs_mode_to_hurd_mode (int type, int mode)
hurdmode = S_IFSOCK;
break;
- case NFFIFO:
- hurdmode = S_IFIFO;
+ default:
+ if (protocol_version == 2)
+ switch (type)
+ {
+ case NF2NON:
+ case NF2BAD:
+ default:
+ hurdmode = S_IFREG;
+ break;
+
+ case NF2FIFO:
+ hurdmode = S_IFIFO;
+ break;
+ }
+ else
+ switch (type)
+ {
+ case NF3FIFO:
+ hurdmode = S_IFIFO;
+ break;
+
+ default:
+ hurdmode = S_IFREG;
+ break;
+ }
break;
}
-
+
hurdmode |= mode & ~NFSMODE_FMT;
return hurdmode;
}
-/* Convert a Hurd mode to an NFS mode */
+/* Convert a Hurd mode to an NFS mode. */
int
hurd_mode_to_nfs_mode (mode_t mode)
{
@@ -77,170 +101,384 @@ hurd_mode_to_nfs_mode (mode_t mode)
return mode & 07777;
}
+/* Convert a Hurd mode to an NFS type. */
+int
+hurd_mode_to_nfs_type (mode_t mode)
+{
+ switch (mode & S_IFMT)
+ {
+ case S_IFDIR:
+ return NFDIR;
+
+ case S_IFCHR:
+ default:
+ return NFCHR;
+
+ case S_IFBLK:
+ return NFBLK;
+
+ case S_IFREG:
+ return NFREG;
+
+ case S_IFLNK:
+ return NFLNK;
+
+ case S_IFSOCK:
+ return NFSOCK;
+
+ case S_IFIFO:
+ return protocol_version == 2 ? NF2FIFO : NF3FIFO;
+ }
+}
+
+
/* Each of the functions on this page copies its second arg to *P,
converting it to XDR representation along the way. They then
- return the address after the copied value. */
+ return the address after the copied value. */
-/* Encode an NFS file handle. */
+/* Encode an NFS file handle. */
int *
-xdr_encode_fhandle (int *p, void *fhandle)
+xdr_encode_fhandle (int *p, struct fhandle *fhandle)
{
- bcopy (fhandle, p, NFS_FHSIZE);
- return p + INTSIZE (NFS_FHSIZE);
+ if (protocol_version == 2)
+ {
+ memcpy (p, fhandle->data, NFS2_FHSIZE);
+ return p + INTSIZE (NFS2_FHSIZE);
+ }
+ else
+ return xdr_encode_data (p, fhandle->data, fhandle->size);
}
-/* Encode uninterpreted bytes. */
+/* Encode uninterpreted bytes. */
int *
xdr_encode_data (int *p, char *data, size_t len)
{
int nints = INTSIZE (len);
-
+
p[nints] = 0;
- *p++ = htonl (len);
- bcopy (data, p, len);
+ *(p++) = htonl (len);
+ memcpy (p, data, len);
return p + nints;
}
-/* Encode a C string. */
+/* Encode a 64 bit integer. */
+int *
+xdr_encode_64bit (int *p, long long n)
+{
+ *(p++) = htonl (n & 0xffffffff00000000LL >> 32);
+ *(p++) = htonl (n & 0xffffffff);
+ return p;
+}
+
+/* Encode a C string. */
int *
xdr_encode_string (int *p, char *string)
{
return xdr_encode_data (p, string, strlen (string));
}
-
-/* Encode a MODE into an otherwise empty sattr. */
+
+/* Encode a MODE into an otherwise empty sattr. */
int *
xdr_encode_sattr_mode (int *p, mode_t mode)
{
- *p++ = htonl (hurd_mode_to_nfs_mode (mode));
- *p++ = -1; /* uid */
- *p++ = -1; /* gid */
- *p++ = -1; /* size */
- *p++ = -1; /* atime secs */
- *p++ = -1; /* atime usecs */
- *p++ = -1; /* mtime secs */
- *p++ = -1; /* mtime usecs */
+ if (protocol_version == 2)
+ {
+ *(p++) = htonl (hurd_mode_to_nfs_mode (mode));
+ *(p++) = -1; /* uid */
+ *(p++) = -1; /* gid */
+ *(p++) = -1; /* size */
+ *(p++) = -1; /* atime secs */
+ *(p++) = -1; /* atime usecs */
+ *(p++) = -1; /* mtime secs */
+ *(p++) = -1; /* mtime usecs */
+ }
+ else
+ {
+ *(p++) = htonl (1); /* set mode */
+ *(p++) = htonl (hurd_mode_to_nfs_mode (mode));
+ *(p++) = 0; /* no uid */
+ *(p++) = 0; /* no gid */
+ *(p++) = 0; /* no size */
+ *(p++) = DONT_CHANGE; /* no atime */
+ *(p++) = DONT_CHANGE; /* no mtime */
+ }
return p;
}
-/* Encode UID and GID into an otherwise empty sattr. */
+/* Encode UID and GID into an otherwise empty sattr. */
int *
xdr_encode_sattr_ids (int *p, u_int uid, u_int gid)
{
- *p++ = -1; /* mode */
- *p++ = htonl (uid);
- *p++ = htonl (gid);
- *p++ = -1; /* size */
- *p++ = -1; /* atime secs */
- *p++ = -1; /* atime usecs */
- *p++ = -1; /* mtime secs */
- *p++ = -1; /* mtime usecs */
+ if (protocol_version == 2)
+ {
+ *(p++) = -1; /* mode */
+ *(p++) = htonl (uid);
+ *(p++) = htonl (gid);
+ *(p++) = -1; /* size */
+ *(p++) = -1; /* atime secs */
+ *(p++) = -1; /* atime usecs */
+ *(p++) = -1; /* mtime secs */
+ *(p++) = -1; /* mtime usecs */
+ }
+ else
+ {
+ *(p++) = 0; /* no mode */
+ *(p++) = htonl (1); /* set uid */
+ *(p++) = htonl (uid);
+ *(p++) = htonl (1); /* set gid */
+ *(p++) = htonl (gid);
+ *(p++) = 0; /* no size */
+ *(p++) = DONT_CHANGE; /* no atime */
+ *(p++) = DONT_CHANGE; /* no mtime */
+ }
return p;
}
-/* Encode a file size into an otherwise empty sattr. */
+/* Encode a file size into an otherwise empty sattr. */
int *
xdr_encode_sattr_size (int *p, off_t size)
{
- *p++ = -1; /* mode */
- *p++ = -1; /* uid */
- *p++ = -1; /* gid */
- *p++ = htonl (size);
- *p++ = -1; /* atime secs */
- *p++ = -1; /* atime usecs */
- *p++ = -1; /* mtime secs */
- *p++ = -1; /* mtime secs */
+ if (protocol_version == 2)
+ {
+ *(p++) = -1; /* mode */
+ *(p++) = -1; /* uid */
+ *(p++) = -1; /* gid */
+ *(p++) = htonl (size);
+ *(p++) = -1; /* atime secs */
+ *(p++) = -1; /* atime usecs */
+ *(p++) = -1; /* mtime secs */
+ *(p++) = -1; /* mtime secs */
+ }
+ else
+ {
+ *(p++) = 0; /* no mode */
+ *(p++) = 0; /* no uid */
+ *(p++) = 0; /* no gid */
+ *(p++) = htonl (1); /* size */
+ p = xdr_encode_64bit (p, size);
+ *(p++) = DONT_CHANGE; /* no atime */
+ *(p++) = DONT_CHANGE; /* no mtime */
+ }
return p;
}
-/* Encode ATIME and MTIME into an otherwise empty sattr. */
+/* Encode ATIME and MTIME into an otherwise empty sattr. */
int *
xdr_encode_sattr_times (int *p, struct timespec *atime, struct timespec *mtime)
{
- *p++ = -1; /* mode */
- *p++ = -1; /* uid */
- *p++ = -1; /* gid */
- *p++ = -1; /* size */
- *p++ = htonl (atime->tv_sec);
- *p++ = htonl (atime->tv_nsec * 1000);
- *p++ = htonl (mtime->tv_sec);
- *p++ = htonl (mtime->tv_nsec * 1000);
+ if (protocol_version == 2)
+ {
+ *(p++) = -1; /* mode */
+ *(p++) = -1; /* uid */
+ *(p++) = -1; /* gid */
+ *(p++) = -1; /* size */
+ *(p++) = htonl (atime->tv_sec);
+ *(p++) = htonl (atime->tv_nsec / 1000);
+ *(p++) = htonl (mtime->tv_sec);
+ *(p++) = htonl (mtime->tv_nsec / 1000);
+ }
+ else
+ {
+ *(p++) = 0; /* no mode */
+ *(p++) = 0; /* no uid */
+ *(p++) = 0; /* no gid */
+ *(p++) = 0; /* no size */
+ *(p++) = htonl (SET_TO_CLIENT_TIME); /* atime */
+ *(p++) = htonl (atime->tv_sec);
+ *(p++) = htonl (atime->tv_nsec);
+ *(p++) = htonl (SET_TO_CLIENT_TIME); /* mtime */
+ *(p++) = htonl (mtime->tv_sec);
+ *(p++) = htonl (mtime->tv_nsec);
+ }
return p;
}
-/* Encode MODE and a size of 0 into an otherwise empty sattr. */
+/* Encode MODE, a size of zero, and the specified owner into an
+ otherwise empty sattr. */
int *
-xdr_encode_create_state (int *p,
- mode_t mode)
+xdr_encode_create_state (int *p,
+ mode_t mode,
+ uid_t owner)
{
- *p++ = htonl (hurd_mode_to_nfs_mode (mode));
- *p++ = -1; /* uid */
- *p++ = -1; /* gid */
- *p++ = 0; /* size */
- *p++ = -1; /* atime sec */
- *p++ = -1; /* atime usec */
- *p++ = -1; /* mtime sec */
- *p++ = -1; /* mtime usec */
+ if (protocol_version == 2)
+ {
+ *(p++) = htonl (hurd_mode_to_nfs_mode (mode));
+ *(p++) = htonl (owner); /* uid */
+ *(p++) = -1; /* gid */
+ *(p++) = 0; /* size */
+ *(p++) = -1; /* atime sec */
+ *(p++) = -1; /* atime usec */
+ *(p++) = -1; /* mtime sec */
+ *(p++) = -1; /* mtime usec */
+ }
+ else
+ {
+ *(p++) = htonl (1); /* mode */
+ *(p++) = htonl (hurd_mode_to_nfs_mode (mode));
+ *(p++) = htonl (1); /* set uid */
+ *(p++) = htonl (owner);
+ *(p++) = 0; /* no gid */
+ *(p++) = htonl (1); /* set size */
+ p = xdr_encode_64bit (p, 0);
+ *(p++) = htonl (SET_TO_SERVER_TIME); /* atime */
+ *(p++) = htonl (SET_TO_SERVER_TIME); /* mtime */
+ }
return p;
}
-/* Encode ST into an sattr. */
+/* Encode ST into an sattr. */
int *
xdr_encode_sattr_stat (int *p,
struct stat *st)
{
- *p++ = htonl (st->st_mode);
- *p++ = htonl (st->st_uid);
- *p++ = htonl (st->st_gid);
- *p++ = htonl (st->st_size);
- *p++ = htonl (st->st_atime);
- *p++ = htonl (st->st_atime_usec);
- *p++ = htonl (st->st_mtime);
- *p++ = htonl (st->st_mtime_usec);
+ if (protocol_version == 2)
+ {
+ *(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode));
+ *(p++) = htonl (st->st_uid);
+ *(p++) = htonl (st->st_gid);
+ *(p++) = htonl (st->st_size);
+ *(p++) = htonl (st->st_atim.tv_sec);
+ *(p++) = htonl (st->st_atim.tv_nsec / 1000);
+ *(p++) = htonl (st->st_mtim.tv_sec);
+ *(p++) = htonl (st->st_mtim.tv_nsec / 1000);
+ }
+ else
+ {
+ *(p++) = htonl (1); /* set mode */
+ *(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode));
+ *(p++) = htonl (1); /* set uid */
+ *(p++) = htonl (st->st_uid);
+ *(p++) = htonl (1); /* set gid */
+ *(p++) = htonl (st->st_gid);
+ *(p++) = htonl (1); /* set size */
+ p = xdr_encode_64bit (p, st->st_size);
+ *(p++) = htonl (SET_TO_CLIENT_TIME); /* set atime */
+ *(p++) = htonl (st->st_atim.tv_sec);
+ *(p++) = htonl (st->st_atim.tv_nsec);
+ *(p++) = htonl (SET_TO_CLIENT_TIME); /* set mtime */
+ *(p++) = htonl (st->st_mtim.tv_sec);
+ *(p++) = htonl (st->st_mtim.tv_nsec);
+ }
return p;
}
+/* Decode *P into a long long; return the address of the following
+ data. */
+int *
+xdr_decode_64bit (int *p, long long *n)
+{
+ long long high, low;
+ high = ntohl (*p);
+ p++;
+ low = ntohl (*p);
+ p++;
+ *n = ((high & 0xffffffff) << 32) | (low & 0xffffffff);
+ return p;
+}
+
+/* Decode *P into an fhandle and look up the associated node. Return
+ the address of the following data. */
+int *
+xdr_decode_fhandle (int *p, struct node **npp)
+{
+ size_t len;
+
+ if (protocol_version == 2)
+ len = NFS2_FHSIZE;
+ else
+ {
+ len = ntohl (*p);
+ p++;
+ }
+ /* Enter into cache. */
+ lookup_fhandle (p, len, npp);
+ return p + len / sizeof (int);
+}
+
/* Decode *P into a stat structure; return the address of the
- following data. */
+ following data. */
int *
xdr_decode_fattr (int *p, struct stat *st)
{
int type, mode;
-
- type = ntohl (*p++);
- mode = ntohl (*p++);
+
+ type = ntohl (*p);
+ p++;
+ mode = ntohl (*p);
+ p++;
st->st_mode = nfs_mode_to_hurd_mode (type, mode);
- st->st_nlink = ntohl (*p++);
- st->st_uid = ntohl (*p++);
- st->st_gid = ntohl (*p++);
- st->st_size = ntohl (*p++);
- st->st_blksize = ntohl (*p++);
- st->st_rdev = ntohl (*p++);
- st->st_blocks = ntohl (*p++);
- st->st_fsid = ntohl (*p++);
- st->st_ino = ntohl (*p++);
- st->st_atime = ntohl (*p++);
- st->st_atime_usec = ntohl (*p++);
- st->st_mtime = ntohl (*p++);
- st->st_mtime_usec = ntohl (*p++);
- st->st_ctime = ntohl (*p++);
- st->st_ctime_usec = ntohl (*p++);
+ st->st_nlink = ntohl (*p);
+ p++;
+ st->st_uid = ntohl (*p);
+ p++;
+ st->st_gid = ntohl (*p);
+ p++;
+ if (protocol_version == 2)
+ {
+ st->st_size = ntohl (*p);
+ p++;
+ st->st_blksize = ntohl (*p);
+ p++;
+ st->st_rdev = ntohl (*p);
+ p++;
+ st->st_blocks = ntohl (*p);
+ p++;
+ }
+ else
+ {
+ long long size;
+ int major, minor;
+ p = xdr_decode_64bit (p, &size);
+ st->st_size = size;
+ p = xdr_decode_64bit (p, &size);
+ st->st_blocks = size / 512;
+ st->st_blksize = read_size < write_size ? read_size : write_size;
+ major = ntohl (*p);
+ p++;
+ minor = ntohl (*p);
+ p++;
+ st->st_rdev = makedev (major, minor);
+ }
+ st->st_fsid = ntohl (*p);
+ p++;
+ st->st_ino = ntohl (*p);
+ p++;
+ st->st_atim.tv_sec = ntohl (*p);
+ p++;
+ st->st_atim.tv_nsec = ntohl (*p);
+ p++;
+ st->st_mtim.tv_sec = ntohl (*p);
+ p++;
+ st->st_mtim.tv_nsec = ntohl (*p);
+ p++;
+ st->st_ctim.tv_sec = ntohl (*p);
+ p++;
+ st->st_ctim.tv_nsec = ntohl (*p);
+ p++;
+
+ if (protocol_version < 3)
+ {
+ st->st_atim.tv_nsec *= 1000;
+ st->st_mtim.tv_nsec *= 1000;
+ st->st_ctim.tv_nsec *= 1000;
+ }
return p;
}
/* Decode *P into a string, stored at BUF; return the address
- of the following data. */
+ of the following data. */
int *
xdr_decode_string (int *p, char *buf)
{
int len;
-
- len = ntohl (*p++);
- bcopy (p, buf, len);
+
+ len = ntohl (*p);
+ p++;
+ memcpy (buf, p, len);
buf[len] = '\0';
return p + INTSIZE (len);
}
@@ -253,28 +491,29 @@ xdr_decode_string (int *p, char *buf)
means superuser), NP (identifying the node we are operating on), and
SECOND_GID (specifying another GID the server might be interested
in). Allocate at least LEN bytes of space for bulk data in
- addition to the normal amount for an RPC. */
+ addition to the normal amount for an RPC. */
int *
-nfs_initialize_rpc (int rpc_proc, struct netcred *cred,
+nfs_initialize_rpc (int rpc_proc, struct iouser *cred,
size_t len, void **bufp, struct node *np,
uid_t second_gid)
{
uid_t uid;
uid_t gid;
error_t err;
-
+
/* Use heuristics to figure out what ids to present to the server.
- Don't lie, but adjust ids as necessary to secure the desired result. */
+ Don't lie, but adjust ids as necessary to secure the desired
+ result. */
- if (cred == (struct netcred *) -1)
+ if (cred == (struct iouser *) -1)
{
uid = gid = 0;
second_gid = -1;
}
else if (cred
- && (cred->nuids || cred->ngids))
+ && (cred->uids->num || cred->gids->num))
{
- if (cred_has_uid (cred, 0))
+ if (idvec_contains (cred->uids, 0))
{
err = netfs_validate_stat (np, 0);
uid = 0;
@@ -284,35 +523,35 @@ nfs_initialize_rpc (int rpc_proc, struct netcred *cred,
}
else
{
- if (cred->nuids == 0)
+ if (cred->uids->num == 0)
uid = -2;
- else if (cred->nuids == 1)
- uid = cred->uids[0];
+ else if (cred->uids->num == 1)
+ uid = cred->uids->ids[0];
else
{
err = netfs_validate_stat (np, 0);
if (err)
{
- uid = cred->uids[0];
+ uid = cred->uids->ids[0];
printf ("NFS warning, internal stat failure\n");
}
else
{
- if (cred_has_uid (cred, np->nn_stat.st_uid))
+ if (idvec_contains (cred->uids, np->nn_stat.st_uid))
uid = np->nn_stat.st_uid;
else
- uid = cred->uids[0];
+ uid = cred->uids->ids[0];
}
}
- if (cred->ngids == 0)
+ if (cred->gids->num == 0)
{
gid = -2;
second_gid = -1;
}
- else if (cred->ngids == 1)
+ else if (cred->gids->num == 1)
{
- gid = cred->gids[0];
+ gid = cred->gids->ids[0];
second_gid = -1;
}
else
@@ -320,18 +559,18 @@ nfs_initialize_rpc (int rpc_proc, struct netcred *cred,
err = netfs_validate_stat (np, 0);
if (err)
{
- gid = cred->gids[0];
+ gid = cred->gids->ids[0];
printf ("NFS warning, internal stat failure\n");
}
else
{
- if (cred_has_gid (cred, np->nn_stat.st_gid))
+ if (idvec_contains (cred->gids, np->nn_stat.st_gid))
gid = np->nn_stat.st_gid;
else
- gid = cred->gids[0];
- }
+ gid = cred->gids->ids[0];
+ }
if (second_gid != -1
- && !cred_has_gid (cred, second_gid))
+ && !idvec_contains (cred->gids, second_gid))
second_gid = -1;
}
}
@@ -343,7 +582,8 @@ nfs_initialize_rpc (int rpc_proc, struct netcred *cred,
uid, gid, second_gid);
}
-/* ERROR is an NFS error code; return the correspending Hurd error. */
+/* ERROR is an NFS error code; return the correspending Hurd
+ error. */
error_t
nfs_error_trans (int error)
{
@@ -351,58 +591,91 @@ nfs_error_trans (int error)
{
case NFS_OK:
return 0;
-
+
case NFSERR_PERM:
return EPERM;
case NFSERR_NOENT:
return ENOENT;
-
+
case NFSERR_IO:
return EIO;
-
+
case NFSERR_NXIO:
return ENXIO;
-
+
case NFSERR_ACCES:
return EACCES;
-
+
case NFSERR_EXIST:
return EEXIST;
-
+
case NFSERR_NODEV:
return ENODEV;
-
+
case NFSERR_NOTDIR:
return ENOTDIR;
-
+
case NFSERR_ISDIR:
return EISDIR;
-
+
case NFSERR_FBIG:
return E2BIG;
-
+
case NFSERR_NOSPC:
return ENOSPC;
case NFSERR_ROFS:
return EROFS;
-
+
case NFSERR_NAMETOOLONG:
return ENAMETOOLONG;
-
+
case NFSERR_NOTEMPTY:
return ENOTEMPTY;
-
+
case NFSERR_DQUOT:
return EDQUOT;
-
+
case NFSERR_STALE:
return ESTALE;
-
+
case NFSERR_WFLUSH:
- default:
+ /* Not known in v3, but we just give EINVAL for unknown errors
+ so it's the same. */
return EINVAL;
+
+ default:
+ if (protocol_version == 2)
+ return EINVAL;
+ else
+ switch (error)
+ {
+ case NFSERR_XDEV:
+ return EXDEV;
+
+ case NFSERR_INVAL:
+ case NFSERR_REMOTE: /* not sure about this one */
+ default:
+ return EINVAL;
+
+ case NFSERR_MLINK:
+ return EMLINK;
+
+ case NFSERR_NOTSUPP:
+ case NFSERR_BADTYPE:
+ return EOPNOTSUPP;
+
+ case NFSERR_SERVERFAULT:
+ return EIO;
+
+ case NFSERR_BADHANDLE:
+ case NFSERR_NOT_SYNC:
+ case NFSERR_BAD_COOKIE:
+ case NFSERR_TOOSMALL:
+ case NFSERR_JUKEBOX: /* ??? */
+ /* These indicate bugs in the client, so EGRATUITOUS is right. */
+ return EGRATUITOUS;
+ }
}
}
-
diff --git a/nfs/nfs.h b/nfs/nfs.h
index d9d01121..147dc900 100644
--- a/nfs/nfs.h
+++ b/nfs/nfs.h
@@ -1,5 +1,5 @@
/* Data structures and global variables for NFS client
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,99,2001 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
@@ -15,20 +15,30 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Needed for the rpcsvc include files to work. */
-typedef int bool_t; /* Ick. */
+#ifndef NFS_NFS_H
+#define NFS_NFS_H
#include <sys/stat.h>
#include <sys/types.h>
-#include <rpcsvc/nfs_prot.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include "nfs-spec.h"
#include <hurd/netfs.h>
-/* One of these exists for private data needed by the client for each
+/* A file handle */
+struct fhandle
+{
+ size_t size;
+
+ /* Leave enough room for the largest possible fhandle. */
+ char data[NFS3_FHSIZE];
+};
+
+/* There exists one of there for the private data needed by each client
node. */
-struct netnode
+struct netnode
{
- char handle[NFS_FHSIZE];
+ struct fhandle handle;
time_t stat_updated;
struct node *hnext, **hprevp;
@@ -49,9 +59,9 @@ struct netnode
char *name;
dev_t indexes;
} transarg;
-
+
#ifdef notyet
- /* This indicates that the length of the file must be at
+ /* This indicates that the length of the file must be at
least this big because we've written this much locally,
even if the server thinks we haven't gone this far. */
off_t extend_len;
@@ -60,27 +70,19 @@ struct netnode
struct user_pager_info *fileinfo;
/* If this node has been renamed by "deletion" then
- this is the directory and name in that directory which
- is holding the node */
+ this is the directory and the name in that directory
+ which is holding the node */
struct node *dead_dir;
char *dead_name;
};
-/* Credential structure to identify a particular user. */
-struct netcred
-{
- uid_t *uids, *gids;
- int nuids, ngids;
- int refcnt;
-};
-
/* Socket file descriptor for talking to RPC servers. */
int main_udp_socket;
/* Our hostname */
char *hostname;
-/* The current time */
+/* The current time */
volatile struct mapped_time_value *mapped_time;
/* Some tunable parameters */
@@ -91,6 +93,12 @@ extern int stat_timeout;
/* How long to keep around file contents caches */
extern int cache_timeout;
+/* How long to keep around positive dir cache entries */
+extern int name_cache_timeout;
+
+/* How long to keep around negative dir cache entries */
+extern int name_cache_neg_timeout;
+
/* How long to wait for replies before re-sending RPC's. */
extern int initial_transmit_timeout;
extern int max_transmit_timeout;
@@ -120,7 +128,7 @@ extern int mount_program;
/* RPC program version for the mount agent */
extern int mount_version;
-/* If this is nonzero, it's the port to use for the mount agent if
+/* If this is nonzero, it's the port to use for the mount agent if
the portmapper fails or can't be found. */
extern short mount_port;
@@ -134,7 +142,7 @@ extern int nfs_program;
/* RPC program version for the NFS server */
extern int nfs_version;
-/* If this is nonzero, it's the port to be used to find the nfs agent
+/* If this is nonzero, it's the port to be used to find the nfs agent
if the portmapper fails or can't be found */
extern short nfs_port;
@@ -142,17 +150,17 @@ extern short nfs_port;
portmapper. */
extern int nfs_port_override;
+/* Which NFS protocol version we are using */
+extern int protocol_version;
+
-/* Count how many four-byte chunks it takss to hold LEN bytes. */
+/* Count how many four-byte chunks it takes to hold LEN bytes. */
#define INTSIZE(len) (((len)+3)>>2)
-/* cred.c */
-int cred_has_uid (struct netcred *, uid_t);
-int cred_has_gid (struct netcred *, gid_t);
-
/* nfs.c */
-int *xdr_encode_fhandle (int *, void *);
+int hurd_mode_to_nfs_type (mode_t);
+int *xdr_encode_fhandle (int *, struct fhandle *);
int *xdr_encode_data (int *, char *, size_t);
int *xdr_encode_string (int *, char *);
int *xdr_encode_sattr_mode (int *, mode_t);
@@ -160,15 +168,18 @@ int *xdr_encode_sattr_ids (int *, u_int, u_int);
int *xdr_encode_sattr_size (int *, off_t);
int *xdr_encode_sattr_times (int *, struct timespec *, struct timespec *);
int *xdr_encode_sattr_stat (int *, struct stat *);
-int *xdr_encode_create_state (int *, mode_t);
+int *xdr_encode_create_state (int *, mode_t, uid_t);
int *xdr_decode_fattr (int *, struct stat *);
int *xdr_decode_string (int *, char *);
-int *nfs_initialize_rpc (int, struct netcred *, size_t, void **,
+int *xdr_decode_fhandle (int *, struct node **);
+int *nfs_initialize_rpc (int, struct iouser *, size_t, void **,
struct node *, uid_t);
error_t nfs_error_trans (int);
/* mount.c */
struct node *mount_root (char *, char *);
+extern const char *mounted_hostname;
+extern uint16_t mounted_nfs_port; /* host order */
/* ops.c */
int *register_fresh_stat (struct node *, int *);
@@ -180,5 +191,13 @@ void timeout_service_thread (void);
void rpc_receive_thread (void);
/* cache.c */
-struct node *lookup_fhandle (void *);
-void recache_handle (struct node *, void *);
+void lookup_fhandle (void *, size_t, struct node **);
+int *recache_handle (int *, struct node *);
+
+/* name-cache.c */
+void enter_lookup_cache (char *, size_t, struct node *, char *);
+void purge_lookup_cache (struct node *, char *, size_t);
+struct node *check_lookup_cache (struct node *, char *);
+void purge_lookup_cache_node (struct node *);
+
+#endif /* NFS_NFS_H */
diff --git a/nfs/ops.c b/nfs/ops.c
index efeded10..05cfbe9a 100644
--- a/nfs/ops.c
+++ b/nfs/ops.c
@@ -1,5 +1,5 @@
-/* Libnetfs callbacks for node operations in NFS client
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/* ops.c - Libnetfs callbacks for node operations in NFS client.
+ Copyright (C) 1994,95,96,97,99,2002,2011 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
@@ -21,17 +21,19 @@
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
+#include <stddef.h>
#include <dirent.h>
#include <unistd.h>
+#include <maptime.h>
-/* We have fresh stat information for NP; the fattr structure is at
- P. Update our entry. Return the address of the next int after
- the fattr structure. */
+/* We have fresh stat information for NP; the file attribute (fattr)
+ structure is at P. Update our entry. Return the address of the next
+ int after the fattr structure. */
int *
register_fresh_stat (struct node *np, int *p)
{
int *ret;
-
+
ret = xdr_decode_fattr (p, &np->nn_stat);
np->nn->stat_updated = mapped_time->seconds;
@@ -40,12 +42,12 @@ register_fresh_stat (struct node *np, int *p)
case NOT_POSSIBLE:
case POSSIBLE:
break;
-
+
case SYMLINK:
np->nn_stat.st_size = strlen (np->nn->transarg.name);
np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT) | S_IFLNK);
break;
-
+
case CHRDEV:
np->nn_stat.st_rdev = np->nn->transarg.indexes;
np->nn_stat.st_mode = ((np->nn_stat.st_mode & ~S_IFMT) | S_IFCHR);
@@ -70,75 +72,147 @@ register_fresh_stat (struct node *np, int *p)
np->nn_stat.st_gen = 0;
np->nn_stat.st_author = np->nn_stat.st_uid;
np->nn_stat.st_flags = 0;
-
+ np->nn_translated = np->nn_stat.st_mode & S_IFMT;
+
return ret;
}
+/* Handle returned wcc information for various calls. In protocol
+ version 2, this is just register_fresh_stat. In version 3, it
+ checks to see if stat information is present too. If this follows
+ an operation that we expect has modified the attributes, MOD should
+ be set. (This unpacks the post_op_attr XDR type.) */
+int *
+process_returned_stat (struct node *np, int *p, int mod)
+{
+ if (protocol_version == 2)
+ return register_fresh_stat (np, p);
+ else
+ {
+ int attrs_exist;
+
+ attrs_exist = ntohl (*p);
+ p++;
+ if (attrs_exist)
+ p = register_fresh_stat (np, p);
+ else if (mod)
+ /* We know that our values are now wrong */
+ np->nn->stat_updated = 0;
+ return p;
+ }
+}
+
+
+/* Handle returned wcc information for various calls. In protocol
+ version 2, this is just register_fresh_stat. In version 3, it does
+ the wcc_data interpretation too. If this follows an operation that
+ we expect has modified the attributes, MOD should be set.
+ (This unpacks the wcc_data XDR type.) */
+int *
+process_wcc_stat (struct node *np, int *p, int mod)
+{
+ if (protocol_version == 2)
+ return register_fresh_stat (np, p);
+ else
+ {
+ int attrs_exist;
+
+ /* First the pre_op_attr */
+ attrs_exist = ntohl (*p);
+ p++;
+ if (attrs_exist)
+ {
+ /* Just skip them for now */
+ p += 2 * sizeof (int); /* size */
+ p += 2 * sizeof (int); /* mtime */
+ p += 2 * sizeof (int); /* atime */
+ }
+
+ /* Now the post_op_attr */
+ return process_returned_stat (np, p, mod);
+ }
+}
+
+
/* Implement the netfs_validate_stat callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_validate_stat (struct node *np, struct netcred *cred)
+netfs_validate_stat (struct node *np, struct iouser *cred)
{
int *p;
void *rpcbuf;
error_t err;
-
+
if (mapped_time->seconds - np->nn->stat_updated < stat_timeout)
return 0;
- p = nfs_initialize_rpc (NFSPROC_GETATTR, (struct netcred *) -1,
- 0, &rpcbuf, np, -1);
+ p = nfs_initialize_rpc (NFSPROC_GETATTR (protocol_version),
+ (struct iouser *) -1, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
if (!err)
register_fresh_stat (np, p);
- np->istranslated = 0;
-
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_chown callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_chown (struct netcred *cred, struct node *np,
+netfs_attempt_chown (struct iouser *cred, struct node *np,
uid_t uid, gid_t gid)
{
int *p;
void *rpcbuf;
error_t err;
-
- p = nfs_initialize_rpc (NFSPROC_SETATTR, cred, 0, &rpcbuf, np, gid);
+
+ p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
+ cred, 0, &rpcbuf, np, gid);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_sattr_ids (p, uid, gid);
-
- err = conduct_rpc (&rpcbuf, &p);
+ if (protocol_version == 3)
+ *(p++) = 0; /* guard_check == 0 */
+ err = conduct_rpc (&rpcbuf, &p);
if (!err)
- register_fresh_stat (np, p);
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
free (rpcbuf);
-
+
return err;
}
/* Implement the netfs_attempt_chauthor callback as described in
<hurd/netfs.h>. */
error_t
-netfs_attempt_chauthor (struct netcred *cred, struct node *rp,
+netfs_attempt_chauthor (struct iouser *cred, struct node *rp,
uid_t author)
{
return EOPNOTSUPP;
}
/* Implement the netfs_attempt_chmod callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_chmod (struct netcred *cred, struct node *np,
+netfs_attempt_chmod (struct iouser *cred, struct node *np,
mode_t mode)
{
int *p;
@@ -150,26 +224,29 @@ netfs_attempt_chmod (struct netcred *cred, struct node *np,
err = netfs_validate_stat (np, cred);
if (err)
return err;
+
+ /* Has the file type changed? (e.g. from symlink to
+ directory). */
if ((mode & S_IFMT) != (np->nn_stat.st_mode & S_IFMT))
{
char *f = 0;
-
+
if (np->nn->dtrans == NOT_POSSIBLE)
return EOPNOTSUPP;
-
+
if (np->nn->dtrans == SYMLINK)
f = np->nn->transarg.name;
-
+
switch (mode & S_IFMT)
{
default:
return EOPNOTSUPP;
-
+
case S_IFIFO:
np->nn->dtrans = FIFO;
np->nn->stat_updated = 0;
break;
-
+
case S_IFSOCK:
np->nn->dtrans = SOCK;
np->nn->stat_updated = 0;
@@ -180,25 +257,33 @@ netfs_attempt_chmod (struct netcred *cred, struct node *np,
}
}
- p = nfs_initialize_rpc (NFSPROC_SETATTR, cred, 0, &rpcbuf, np, -1);
+ p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_sattr_mode (p, mode);
-
+ if (protocol_version == 3)
+ *(p++) = 0; /* guard check == 0 */
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
- register_fresh_stat (np, p);
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_chflags callback as described in
- <hurd/netfs.h>. */
-error_t
-netfs_attempt_chflags (struct netcred *cred, struct node *np,
+ <hurd/netfs.h>. */
+error_t
+netfs_attempt_chflags (struct iouser *cred, struct node *np,
int flags)
{
return EOPNOTSUPP;
@@ -207,48 +292,91 @@ netfs_attempt_chflags (struct netcred *cred, struct node *np,
/* Implement the netfs_attempt_utimes callback as described in
<hurd/netfs.h>. */
error_t
-netfs_attempt_utimes (struct netcred *cred, struct node *np,
+netfs_attempt_utimes (struct iouser *cred, struct node *np,
struct timespec *atime, struct timespec *mtime)
{
int *p;
void *rpcbuf;
error_t err;
-
- p = nfs_initialize_rpc (NFSPROC_SETATTR, cred, 0, &rpcbuf, np, -1);
+ struct timeval tv;
+ struct timespec current;
+
+ /* XXX For version 3 we can actually do this right, but we don't
+ just yet. */
+ if (!atime || !mtime)
+ {
+ maptime_read (mapped_time, &tv);
+ current.tv_sec = tv.tv_sec;
+ current.tv_nsec = tv.tv_usec * 1000;
+ }
+
+ p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
- p = xdr_encode_sattr_times (p, atime, mtime);
-
+ p = xdr_encode_sattr_times (p,
+ atime ?: &current,
+ mtime ?: &current);
+ if (protocol_version == 3)
+ *(p++) = 0; /* guard check == 0 */
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
- register_fresh_stat (np, p);
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_set_size callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_set_size (struct netcred *cred, struct node *np,
+netfs_attempt_set_size (struct iouser *cred, struct node *np,
off_t size)
{
int *p;
void *rpcbuf;
error_t err;
-
- p = nfs_initialize_rpc (NFSPROC_SETATTR, cred, 0, &rpcbuf, np, -1);
+
+ p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_sattr_size (p, size);
-
+ if (protocol_version == 3)
+ *(p++) = 0; /* guard_check == 0 */
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
- register_fresh_stat (np, p);
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
+
+ /* If we got EACCES, but the user has the file open for writing,
+ then the NFS protocol has screwed us. There's nothing we can do,
+ except in the important case of opens with
+ O_TRUNC|O_CREAT|O_WRONLY|O_EXCL where the new mode does not allow
+ writing. RCS, for example, uses this to create lock files. So permit
+ cases where the O_TRUNC isn't doing anything to succeed if the user
+ does have the file open for writing. */
+ if (err == EACCES)
+ {
+ int error = netfs_validate_stat (np, cred);
+ if (!error && np->nn_stat.st_size == size)
+ err = 0;
+ }
free (rpcbuf);
return err;
@@ -257,45 +385,52 @@ netfs_attempt_set_size (struct netcred *cred, struct node *np,
/* Implement the netfs_attempt_statfs callback as described in
<hurd/netfs.h>. */
error_t
-netfs_attempt_statfs (struct netcred *cred, struct node *np,
+netfs_attempt_statfs (struct iouser *cred, struct node *np,
struct statfs *st)
{
int *p;
void *rpcbuf;
error_t err;
-
- p = nfs_initialize_rpc (NFSPROC_STATFS, cred, 0, &rpcbuf, np, -1);
+
+ p = nfs_initialize_rpc (NFS2PROC_STATFS, cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
+
if (!err)
{
- long iosize, bsize;
- iosize = *p++;
- bsize = *p++;
- st->f_bsize = iosize;
- st->f_blocks = ((*p++) * bsize) / iosize;
- st->f_bfree = ((*p++) * bsize) / iosize;
- st->f_bavail = ((*p++) * bsize) / iosize;
-
+ p++; /* skip IOSIZE field */
+ st->f_bsize = ntohl (*p);
+ p++;
+ st->f_blocks = ntohl (*p);
+ p++;
+ st->f_bfree = ntohl (*p);
+ p++;
+ st->f_bavail = ntohl (*p);
+ p++;
st->f_type = FSTYPE_NFS;
st->f_files = 0;
st->f_ffree = 0;
- st->f_fsid = 0; /* XXX wrong */
+ st->f_fsid = getpid ();
st->f_namelen = 0;
}
-
+
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_sync callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_sync (struct netcred *cred, struct node *np, int wait)
+netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
{
/* We are already completely synchronous. */
return 0;
@@ -304,15 +439,15 @@ netfs_attempt_sync (struct netcred *cred, struct node *np, int wait)
/* Implement the netfs_attempt_syncfs callback as described in
<hurd/netfs.h>. */
error_t
-netfs_attempt_syncfs (struct netcred *cred, int wait)
+netfs_attempt_syncfs (struct iouser *cred, int wait)
{
return 0;
}
/* Implement the netfs_attempt_read callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_read (struct netcred *cred, struct node *np,
+netfs_attempt_read (struct iouser *cred, struct node *np,
off_t offset, size_t *len, void *data)
{
int *p;
@@ -320,191 +455,370 @@ netfs_attempt_read (struct netcred *cred, struct node *np,
size_t trans_len;
error_t err;
size_t amt, thisamt;
-
+ int eof;
+
for (amt = *len; amt;)
{
thisamt = amt;
if (thisamt > read_size)
thisamt = read_size;
- p = nfs_initialize_rpc (NFSPROC_READ, cred, 0, &rpcbuf, np, -1);
+ p = nfs_initialize_rpc (NFSPROC_READ (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
- *p++ = htonl (offset);
- *p++ = htonl (thisamt);
- *p++ = 0;
-
+ *(p++) = htonl (offset);
+ *(p++) = htonl (thisamt);
+ if (protocol_version == 2)
+ *(p++) = 0;
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (err)
{
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+
+ if (!err || protocol_version == 3)
+ p = process_returned_stat (np, p, !err);
+
+ if (err)
+ {
+ free (rpcbuf);
+ return err;
+ }
+
+ trans_len = ntohl (*p);
+ p++;
+ if (trans_len > thisamt)
+ trans_len = thisamt; /* ??? */
+
+ if (protocol_version == 3)
+ {
+ eof = ntohl (*p);
+ p++;
+ }
+ else
+ eof = (trans_len < thisamt);
+
+ memcpy (data, p, trans_len);
free (rpcbuf);
- return err;
- }
-
- p = register_fresh_stat (np, p);
-
- trans_len = ntohl (*p++);
- if (trans_len > thisamt)
- trans_len = thisamt; /* ??? */
-
- bcopy (p, data, trans_len);
- free (rpcbuf);
- data += trans_len;
- offset += trans_len;
- amt -= trans_len;
-
- /* If we got a short count, that means we're all done */
- if (trans_len < thisamt)
- {
- *len -= amt;
- return 0;
+ data += trans_len;
+ offset += trans_len;
+ amt -= trans_len;
+
+ if (eof)
+ {
+ *len -= amt;
+ return 0;
+ }
}
}
return 0;
}
-
+
/* Implement the netfs_attempt_write callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_write (struct netcred *cred, struct node *np,
+netfs_attempt_write (struct iouser *cred, struct node *np,
off_t offset, size_t *len, void *data)
{
int *p;
void *rpcbuf;
error_t err;
size_t amt, thisamt;
-
+ size_t count;
+
for (amt = *len; amt;)
{
thisamt = amt;
if (thisamt > write_size)
thisamt = write_size;
-
- p = nfs_initialize_rpc (NFSPROC_WRITE, cred, thisamt, &rpcbuf, np, -1);
+
+ p = nfs_initialize_rpc (NFSPROC_WRITE (protocol_version),
+ cred, thisamt, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
- *p++ = 0;
- *p++ = htonl (offset);
- *p++ = 0;
+ if (protocol_version == 2)
+ *(p++) = 0;
+ *(p++) = htonl (offset);
+ if (protocol_version == 2)
+ *(p++) = 0;
+ if (protocol_version == 3)
+ *(p++) = htonl (FILE_SYNC);
p = xdr_encode_data (p, data, thisamt);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ if (!err)
+ {
+ if (protocol_version == 3)
+ {
+ count = ntohl (*p);
+ p++;
+ p++; /* ignore COMMITTED */
+ /* ignore verf for now */
+ p += NFS3_WRITEVERFSIZE / sizeof (int);
+ }
+ else
+ /* assume it wrote the whole thing */
+ count = thisamt;
+
+ amt -= count;
+ data += count;
+ offset += count;
+ }
+ }
+
+ free (rpcbuf);
+
+ if (err == EINTR && amt != *len)
+ {
+ *len -= amt;
+ return 0;
+ }
+
if (err)
{
*len = 0;
- free (rpcbuf);
return err;
}
- register_fresh_stat (np, p);
- free (rpcbuf);
- amt -= thisamt;
- data += thisamt;
- offset += thisamt;
}
return 0;
}
+/* See if NAME exists in DIR for CRED. If so, return EEXIST. */
+error_t
+verify_nonexistent (struct iouser *cred, struct node *dir,
+ char *name)
+{
+ int *p;
+ void *rpcbuf;
+ error_t err;
+
+ /* Don't use the lookup cache for this; we want a full sync to
+ get as close to real exclusive create behavior as possible. */
+
+ assert (protocol_version == 2);
+
+ p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ return errno;
+
+ p = xdr_encode_fhandle (p, &dir->nn->handle);
+ p = xdr_encode_string (p, name);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
+
+ free (rpcbuf);
+
+ if (!err)
+ return EEXIST;
+ else
+ return 0;
+}
+
/* Implement the netfs_attempt_lookup callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_lookup (struct netcred *cred, struct node *np,
+netfs_attempt_lookup (struct iouser *cred, struct node *np,
char *name, struct node **newnp)
{
int *p;
void *rpcbuf;
error_t err;
-
- p = nfs_initialize_rpc (NFSPROC_LOOKUP, cred, 0, &rpcbuf, np, -1);
+ char dirhandle[NFS3_FHSIZE];
+ size_t dirlen;
+
+ /* Check the cache first. */
+ *newnp = check_lookup_cache (np, name);
+ if (*newnp)
+ {
+ if (*newnp == (struct node *) -1)
+ {
+ *newnp = 0;
+ return ENOENT;
+ }
+ else
+ return 0;
+ }
+
+ p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
-
+
+ /* Remember the directory handle for later cache use. */
+
+ dirlen = np->nn->handle.size;
+ memcpy (dirhandle, np->nn->handle.data, dirlen);
+
mutex_unlock (&np->lock);
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
{
- *newnp = lookup_fhandle (p);
- p += NFS_FHSIZE / sizeof (int);
- register_fresh_stat (*newnp, p);
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err)
+ {
+ p = xdr_decode_fhandle (p, newnp);
+ p = process_returned_stat (*newnp, p, 1);
+ }
+ if (err)
+ *newnp = 0;
+ if (protocol_version == 3)
+ {
+ if (*newnp)
+ mutex_unlock (&(*newnp)->lock);
+ mutex_lock (&np->lock);
+ p = process_returned_stat (np, p, 0); /* XXX Do we have to lock np? */
+ mutex_unlock (&np->lock);
+ if (*newnp)
+ mutex_lock (&(*newnp)->lock);
+ }
}
else
*newnp = 0;
-
+
+ /* Notify the cache of the hit or miss. */
+ enter_lookup_cache (dirhandle, dirlen, *newnp, name);
+
free (rpcbuf);
-
+
return err;
}
/* Implement the netfs_attempt_mkdir callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_mkdir (struct netcred *cred, struct node *np,
+netfs_attempt_mkdir (struct iouser *cred, struct node *np,
char *name, mode_t mode)
{
int *p;
void *rpcbuf;
error_t err;
-
- p = nfs_initialize_rpc (NFSPROC_MKDIR, cred, 0, &rpcbuf, np, -1);
+ uid_t owner;
+ struct node *newnp;
+
+ if (cred->uids->num)
+ owner = cred->uids->ids[0];
+ else
+ {
+ err = netfs_validate_stat (np, cred);
+ owner = err ? 0 : np->nn_stat.st_uid;
+ mode &= ~S_ISUID;
+ }
+
+ purge_lookup_cache (np, name, strlen (name));
+
+ p = nfs_initialize_rpc (NFSPROC_MKDIR (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
- p = xdr_encode_create_state (p, mode);
-
+ p = xdr_encode_create_state (p, mode, owner);
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- /* Ignore returned information */
- /* XXX should probably cache it */
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
+
+ if (!err)
+ {
+ p = xdr_decode_fhandle (p, &newnp);
+ p = process_returned_stat (newnp, p, 1);
+
+ /* Did we set the owner correctly? If not, try, but ignore failures. */
+ if (!netfs_validate_stat (newnp, (struct iouser *) -1)
+ && newnp->nn_stat.st_uid != owner)
+ netfs_attempt_chown ((struct iouser *) -1, newnp, owner,
+ newnp->nn_stat.st_gid);
+
+ /* We don't actually return this. */
+ netfs_nput (newnp);
+ }
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_rmdir callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_rmdir (struct netcred *cred, struct node *np,
+netfs_attempt_rmdir (struct iouser *cred, struct node *np,
char *name)
{
int *p;
void *rpcbuf;
error_t err;
-
+
/* Should we do the same sort of thing here as with attempt_unlink? */
- p = nfs_initialize_rpc (NFSPROC_RMDIR, cred, 0, &rpcbuf, np, -1);
+ purge_lookup_cache (np, name, strlen (name));
+
+ p = nfs_initialize_rpc (NFSPROC_RMDIR (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
+
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_link callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_link (struct netcred *cred, struct node *dir,
+netfs_attempt_link (struct iouser *cred, struct node *dir,
struct node *np, char *name, int excl)
{
int *p;
void *rpcbuf;
error_t err = 0;
-
+
if (!excl)
- return EOPNOTSUPP; /* XXX */
+ {
+ /* We have no RPC available that will do an atomic replacement,
+ so we settle for second best; just doing an unlink and ignoring
+ any errors. */
+ mutex_lock (&dir->lock);
+ netfs_attempt_unlink (cred, dir, name);
+ mutex_unlock (&dir->lock);
+ }
/* If we have postponed a translator setting on an unlinked node,
then here's where we set it, by creating the new node instead of
@@ -515,32 +829,51 @@ netfs_attempt_link (struct netcred *cred, struct node *dir,
case POSSIBLE:
case NOT_POSSIBLE:
mutex_lock (&dir->lock);
- p = nfs_initialize_rpc (NFSPROC_LINK, cred, 0, &rpcbuf, dir, -1);
+ p = nfs_initialize_rpc (NFSPROC_LINK (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ {
+ mutex_unlock (&dir->lock);
+ return errno;
+ }
+
mutex_unlock (&dir->lock);
-
+
mutex_lock (&np->lock);
p = xdr_encode_fhandle (p, &np->nn->handle);
mutex_unlock (&np->lock);
-
+
mutex_lock (&dir->lock);
+ purge_lookup_cache (dir, name, strlen (name));
+
p = xdr_encode_fhandle (p, &dir->nn->handle);
p = xdr_encode_string (p, name);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
mutex_unlock (&dir->lock);
-
+
free (rpcbuf);
break;
case SYMLINK:
mutex_lock (&dir->lock);
- p = nfs_initialize_rpc (NFSPROC_SYMLINK, cred, 0, &rpcbuf, dir, -1);
+ p = nfs_initialize_rpc (NFSPROC_SYMLINK (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ {
+ mutex_unlock (&dir->lock);
+ return errno;
+ }
+
p = xdr_encode_fhandle (p, &dir->nn->handle);
mutex_unlock (&dir->lock);
-
+
p = xdr_encode_string (p, name);
mutex_lock (&np->lock);
@@ -551,85 +884,198 @@ netfs_attempt_link (struct netcred *cred, struct node *dir,
free (rpcbuf);
return err;
}
-
- p = xdr_encode_string (p, np->nn->transarg.name);
- p = xdr_encode_sattr_stat (p, &np->nn_stat);
+
+ if (protocol_version == 2)
+ {
+ p = xdr_encode_string (p, np->nn->transarg.name);
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ }
+ else
+ {
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ p = xdr_encode_string (p, np->nn->transarg.name);
+ }
mutex_unlock (&np->lock);
mutex_lock (&dir->lock);
+
+ purge_lookup_cache (dir, name, strlen (name));
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
{
- /* NFSPROC_SYMLINK stupidly does not pass back an
- fhandle, so we have to fetch one now. */
- p = nfs_initialize_rpc (NFSPROC_LOOKUP, cred, 0, &rpcbuf, dir, -1);
- p = xdr_encode_fhandle (p, &dir->nn->handle);
- p = xdr_encode_string (p, name);
-
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- mutex_unlock (&dir->lock);
+ err = nfs_error_trans (ntohl (*p));
+ p++;
- if (err)
- err = EGRATUITOUS; /* damn */
- else
+ if (protocol_version == 2 && !err)
{
- mutex_lock (&np->lock);
- recache_handle (np, p);
- p += NFS_FHSIZE / sizeof (int);
- register_fresh_stat (np, p);
- mutex_unlock (&np->lock);
+ free (rpcbuf);
+
+ /* NFSPROC_SYMLINK stupidly does not pass back an
+ fhandle, so we have to fetch one now. */
+ p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ {
+ mutex_unlock (&dir->lock);
+ return errno;
+ }
+ p = xdr_encode_fhandle (p, &dir->nn->handle);
+ p = xdr_encode_string (p, name);
+
+ mutex_unlock (&dir->lock);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
+ if (!err)
+ {
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ p = process_returned_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ }
+ if (err)
+ err = EGRATUITOUS; /* damn */
+ }
+ else if (protocol_version == 3)
+ {
+ if (!err)
+ {
+ mutex_unlock (&dir->lock);
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ p = process_returned_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ mutex_lock (&dir->lock);
+ }
+ p = process_wcc_stat (dir, p, !err);
+ mutex_unlock (&dir->lock);
}
+ else
+ mutex_unlock (&dir->lock);
}
else
mutex_unlock (&dir->lock);
+
+ free (rpcbuf);
break;
-
+
case CHRDEV:
case BLKDEV:
case FIFO:
case SOCK:
- mutex_lock (&dir->lock);
- p = nfs_initialize_rpc (NFSPROC_CREATE, cred, 0, &rpcbuf, dir, -1);
- p = xdr_encode_fhandle (p, &dir->nn->handle);
- p = xdr_encode_string (p, name);
- mutex_unlock (&dir->lock);
- mutex_lock (&np->lock);
- err = netfs_validate_stat (np, cred);
- if (err)
+ if (protocol_version == 2)
{
+ mutex_lock (&dir->lock);
+ err = verify_nonexistent (cred, dir, name);
+ if (err)
+ return err;
+
+ p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ {
+ mutex_unlock (&dir->lock);
+ return errno;
+ }
+
+ p = xdr_encode_fhandle (p, &dir->nn->handle);
+ p = xdr_encode_string (p, name);
+ mutex_unlock (&dir->lock);
+
+ mutex_lock (&np->lock);
+ err = netfs_validate_stat (np, cred);
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ free (rpcbuf);
+ return err;
+ }
+
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
mutex_unlock (&np->lock);
+
+ mutex_lock (&dir->lock);
+ purge_lookup_cache (dir, name, strlen (name));
+ mutex_unlock (&dir->lock); /* XXX Should this really be after the
+ _lengthy_ (blocking) conduct_rpc? */
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
+
+ if (!err)
+ {
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ register_fresh_stat (np, p);
+ mutex_unlock (&np->lock);
+ }
+
free (rpcbuf);
- return err;
}
-
- p = xdr_encode_sattr_stat (p, &np->nn_stat);
- mutex_unlock (&np->lock);
+ else /* protocol_version != 2 */
+ {
+ mutex_lock (&dir->lock);
+ p = nfs_initialize_rpc (NFS3PROC_MKNOD, cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ {
+ mutex_unlock (&dir->lock);
+ return errno;
+ }
+ p = xdr_encode_fhandle (p, &dir->nn->handle);
+ p = xdr_encode_string (p, name);
+ mutex_unlock (&dir->lock);
- mutex_lock (&dir->lock);
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
- mutex_unlock (&dir->lock);
-
- mutex_lock (&np->lock);
- recache_handle (np, p);
- p += NFS_FHSIZE / sizeof (int);
- register_fresh_stat (np, p);
- mutex_unlock (&np->lock);
+ mutex_lock (&np->lock);
+ err = netfs_validate_stat (np, cred);
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ free (rpcbuf);
+ return err;
+ }
+ *(p++) = htonl (hurd_mode_to_nfs_type (np->nn_stat.st_mode));
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ if (np->nn->dtrans == BLKDEV || np->nn->dtrans == CHRDEV)
+ {
+ *(p++) = htonl (major (np->nn_stat.st_rdev));
+ *(p++) = htonl (minor (np->nn_stat.st_rdev));
+ }
+ mutex_unlock (&np->lock);
+ purge_lookup_cache (dir, name, strlen (name));
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+
+ if (!err)
+ {
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ p = process_returned_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ }
+ mutex_lock (&dir->lock);
+ p = process_wcc_stat (dir, p, !err);
+ mutex_unlock (&dir->lock);
+ }
+ free (rpcbuf);
+ }
break;
}
if (err)
return err;
-
+
mutex_lock (&np->lock);
if (np->nn->dtrans == SYMLINK)
@@ -644,21 +1090,21 @@ netfs_attempt_link (struct netcred *cred, struct node *dir,
np->nn->dead_dir = 0;
np->nn->dead_name = 0;
mutex_unlock (&np->lock);
-
+
mutex_lock (&dir->lock);
- netfs_attempt_unlink ((struct netcred *)-1, dir, name);
+ netfs_attempt_unlink ((struct iouser *)-1, dir, name);
mutex_unlock (&dir->lock);
}
else
mutex_unlock (&np->lock);
-
+
return 0;
}
/* Implement the netfs_attempt_mkfile callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_mkfile (struct netcred *cred, struct node *dir,
+netfs_attempt_mkfile (struct iouser *cred, struct node *dir,
mode_t mode, struct node **newnp)
{
error_t err;
@@ -668,16 +1114,20 @@ netfs_attempt_mkfile (struct netcred *cred, struct node *dir,
/* This is the best we can do. */
name = malloc (50);
+ if (! name)
+ return ENOMEM;
do
{
sprintf (name, ".nfstmpgnu.%d", n++);
err = netfs_attempt_create_file (cred, dir, name, mode, newnp);
if (err == EEXIST)
- mutex_lock (&dir->lock);
+ mutex_lock (&dir->lock); /* XXX is this right? does create need this
+ and drop this on error? Doesn't look
+ like it. */
}
while (err == EEXIST);
-
+
if (err)
{
free (name);
@@ -695,43 +1145,101 @@ netfs_attempt_mkfile (struct netcred *cred, struct node *dir,
}
/* Implement the netfs_attempt_create_file callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_create_file (struct netcred *cred, struct node *np,
+netfs_attempt_create_file (struct iouser *cred, struct node *np,
char *name, mode_t mode, struct node **newnp)
{
int *p;
void *rpcbuf;
error_t err;
+ uid_t owner;
+
+ if (cred->uids->num)
+ owner = cred->uids->ids[0];
+ else
+ {
+ err = netfs_validate_stat (np, cred);
+ owner = err ? 0 : np->nn_stat.st_uid;
+ mode &= ~S_ISUID;
+ }
+
+ /* RFC 1094 says that create is always exclusive. But Sun doesn't
+ actually *implement* the spec. No, of course not. So we have to do
+ it for them. */
+ if (protocol_version == 2)
+ {
+ err = verify_nonexistent (cred, np, name);
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ return err;
+ }
+ }
+
+ purge_lookup_cache (np, name, strlen (name));
+
+ p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
- p = nfs_initialize_rpc (NFSPROC_CREATE, cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
- p = xdr_encode_create_state (p, mode);
-
+ if (protocol_version == 3)
+ {
+ /* We happen to know this is where the XID is. */
+ int verf = *(int *)rpcbuf;
+
+ *(p++) = ntohl (EXCLUSIVE);
+ /* 8 byte verf */
+ *(p++) = ntohl (verf);
+ p++;
+ }
+ else
+ p = xdr_encode_create_state (p, mode, owner);
+
err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
mutex_unlock (&np->lock);
if (!err)
{
- *newnp = lookup_fhandle (p);
- p += NFS_FHSIZE / sizeof (int);
- register_fresh_stat (*newnp, p);
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (!err)
+ {
+ p = xdr_decode_fhandle (p, newnp);
+ p = process_returned_stat (*newnp, p, 1);
+ }
+ if (err)
+ *newnp = 0;
+ if (protocol_version == 3)
+ {
+ if (*newnp)
+ mutex_unlock (&(*newnp)->lock);
+ mutex_lock (&np->lock);
+ p = process_wcc_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ if (*newnp)
+ mutex_lock (&(*newnp)->lock);
+ }
+
+ if (*newnp && !netfs_validate_stat (*newnp, (struct iouser *) -1)
+ && (*newnp)->nn_stat.st_uid != owner)
+ netfs_attempt_chown ((struct iouser *) -1, *newnp, owner, (*newnp)->nn_stat.st_gid);
}
else
*newnp = 0;
-
+
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_unlink callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_unlink (struct netcred *cred, struct node *dir,
+netfs_attempt_unlink (struct iouser *cred, struct node *dir,
char *name)
{
int *p;
@@ -747,20 +1255,36 @@ netfs_attempt_unlink (struct netcred *cred, struct node *dir,
return err;
}
- /* See if there are any other users of this node than the
+ /* Restore the locks to sanity. */
+ mutex_unlock (&np->lock);
+ mutex_lock (&dir->lock);
+
+ /* Purge the cache of entries for this node, so that we don't
+ regard cache-held references as live. */
+ purge_lookup_cache_node (np);
+
+ /* See if there are any other users of this node than the
one we just got; if so, we must give this file another link
so that when we delete the one we are asked for it doesn't go
away entirely. */
if (np->references > 1)
{
- char *newname;
+ char *newname = 0;
int n = 0;
+ mutex_unlock (&dir->lock);
+
newname = malloc (50);
- mutex_unlock (&np->lock);
+ if (! newname)
+ {
+ mutex_lock (&dir->lock);
+ netfs_nrele (np); /* XXX Is this the correct thing to do? */
+ return ENOMEM;
+ }
+
do
{
- sprintf (newname, ".nfs%xgnu.%d", (int) np, n++);
+ sprintf (newname, ".nfs%txgnu.%d", (ptrdiff_t) np, n++);
err = netfs_attempt_link (cred, dir, np, newname, 1);
}
while (err == EEXIST);
@@ -776,6 +1300,7 @@ netfs_attempt_unlink (struct netcred *cred, struct node *dir,
/* Write down what name we gave it; we'll delete this when all
our uses vanish. */
mutex_lock (&np->lock);
+
if (np->nn->dead_dir)
netfs_nrele (np->nn->dead_dir);
netfs_nref (dir);
@@ -785,60 +1310,120 @@ netfs_attempt_unlink (struct netcred *cred, struct node *dir,
np->nn->dead_name = newname;
if (np->nn->dtrans == NOT_POSSIBLE)
np->nn->dtrans = POSSIBLE;
+
+ netfs_nput (np);
+ mutex_lock (&dir->lock);
}
- netfs_nput (np);
+ else
+ netfs_nrele (np);
+
+ p = nfs_initialize_rpc (NFSPROC_REMOVE (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ return errno;
- mutex_lock (&dir->lock);
- p = nfs_initialize_rpc (NFSPROC_REMOVE, cred, 0, &rpcbuf, dir, -1);
p = xdr_encode_fhandle (p, &dir->nn->handle);
p = xdr_encode_string (p, name);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (protocol_version == 3)
+ p = process_wcc_stat (dir, p, !err);
+ }
+
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_rename callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_rename (struct netcred *cred, struct node *fromdir,
- char *fromname, struct node *todir, char *toname,
+netfs_attempt_rename (struct iouser *cred, struct node *fromdir,
+ char *fromname, struct node *todir, char *toname,
int excl)
{
int *p;
void *rpcbuf;
error_t err;
-
+
if (excl)
- return EOPNOTSUPP; /* XXX */
+ {
+ struct node *np;
+
+ /* Just do a lookup/link/unlink sequence. */
+
+ mutex_lock (&fromdir->lock);
+ err = netfs_attempt_lookup (cred, fromdir, fromname, &np);
+ mutex_unlock (&fromdir->lock);
+ if (err)
+ return err;
+
+ err = netfs_attempt_link (cred, todir, np, toname, 1);
+ netfs_nput (np);
+ if (err)
+ return err;
+
+ mutex_lock (&fromdir->lock);
+ err = netfs_attempt_unlink (cred, fromdir, fromname);
+ mutex_unlock (&fromdir->lock);
+
+ /* If the unlink failed, then back out the link */
+ if (err)
+ {
+ mutex_lock (&todir->lock);
+ netfs_attempt_unlink (cred, todir, toname);
+ mutex_unlock (&todir->lock);
+ return err;
+ }
+
+ return 0;
+ }
mutex_lock (&fromdir->lock);
- p = nfs_initialize_rpc (NFSPROC_RENAME, cred, 0, &rpcbuf, fromdir, -1);
+ purge_lookup_cache (fromdir, fromname, strlen (fromname));
+ p = nfs_initialize_rpc (NFSPROC_RENAME (protocol_version),
+ cred, 0, &rpcbuf, fromdir, -1);
+ if (! p)
+ {
+ mutex_unlock (&fromdir->lock);
+ return errno;
+ }
+
p = xdr_encode_fhandle (p, &fromdir->nn->handle);
p = xdr_encode_string (p, fromname);
mutex_unlock (&fromdir->lock);
-
+
mutex_lock (&todir->lock);
+ purge_lookup_cache (todir, toname, strlen (toname));
p = xdr_encode_fhandle (p, &todir->nn->handle);
p = xdr_encode_string (p, toname);
mutex_unlock (&todir->lock);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (protocol_version == 3) /* XXX Should we add `&& !err' ? */
+ {
+ mutex_lock (&fromdir->lock);
+ p = process_wcc_stat (fromdir, p, !err);
+ p = process_wcc_stat (todir, p, !err);
+ }
+ }
+
free (rpcbuf);
return err;
}
/* Implement the netfs_attempt_readlink callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_readlink (struct netcred *cred, struct node *np,
+netfs_attempt_readlink (struct iouser *cred, struct node *np,
char *buf)
{
int *p;
@@ -850,105 +1435,132 @@ netfs_attempt_readlink (struct netcred *cred, struct node *np,
strcpy (buf, np->nn->transarg.name);
return 0;
}
-
- p = nfs_initialize_rpc (NFSPROC_READLINK, cred, 0, &rpcbuf, np, -1);
+
+ p = nfs_initialize_rpc (NFSPROC_READLINK (protocol_version),
+ cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
p = xdr_encode_fhandle (p, &np->nn->handle);
-
+
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
- p = xdr_decode_string (p, buf);
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ if (protocol_version == 3)
+ p = process_returned_stat (np, p, 0);
+ if (!err)
+ p = xdr_decode_string (p, buf);
+ }
free (rpcbuf);
return err;
}
-/* For an NFS node NODE, guess whether CRED is able to read or write
- it by hoping the server uses permissions bits in the "expected
- way". Return the or of O_READ, O_WRITE, and O_EXEC accordingly as
- each is possible. */
-static int
-guess_mode_use (struct node *np,
- struct netcred *cred)
-{
- error_t err;
-
- err = netfs_validate_stat (np, cred);
- if (err)
- return err;
-
- if (cred_has_uid (cred, 0))
- return O_READ|O_WRITE|O_EXEC;
- else if (cred->nuids == 0
- && (np->nn_stat.st_mode & S_IUSEUNK))
- return
- (((np->nn_stat.st_mode & 04000000) ? O_READ : 0)
- | ((np->nn_stat.st_mode & 02000000) ? O_WRITE : 0)
- | ((np->nn_stat.st_mode & 01000000) ? O_EXEC : 0));
- else if (cred_has_uid (cred, np->nn_stat.st_uid)
- || (cred_has_gid (cred, np->nn_stat.st_gid)
- && cred_has_uid (cred, np->nn_stat.st_gid)))
- /* Owner */
- return
- (((np->nn_stat.st_mode & 0400) ? O_READ : 0)
- | ((np->nn_stat.st_mode & 0200) ? O_WRITE : 0)
- | ((np->nn_stat.st_mode & 0100) ? O_EXEC : 0));
- else if (cred_has_gid (cred, np->nn_stat.st_gid))
- /* Group */
- return
- (((np->nn_stat.st_mode & 040) ? O_READ : 0)
- | ((np->nn_stat.st_mode & 020) ? O_WRITE : 0)
- | ((np->nn_stat.st_mode & 010) ? O_EXEC : 0));
- else
- /* Other */
- return
- (((np->nn_stat.st_mode & 4) ? O_READ : 0)
- | ((np->nn_stat.st_mode & 2) ? O_WRITE : 0)
- | ((np->nn_stat.st_mode & 1) ? O_EXEC : 0));
-}
-
/* Implement the netfs_check_open_permissions callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_check_open_permissions (struct netcred *cred, struct node *np,
+netfs_check_open_permissions (struct iouser *cred, struct node *np,
int flags, int newnode)
{
- if ((flags & (O_READ|O_WRITE|O_EXEC)) == 0)
+ int modes;
+
+ if (newnode || (flags & (O_READ|O_WRITE|O_EXEC)) == 0)
return 0;
-
- if ((flags & (O_READ|O_WRITE|O_EXEC))
- == (flags & guess_mode_use (np, cred)))
+
+ netfs_report_access (cred, np, &modes);
+ if ((flags & (O_READ|O_WRITE|O_EXEC)) == (flags & modes))
return 0;
else
return EACCES;
}
/* Implement the netfs_report_access callback as described in
- <hurd/netfs.h>. */
-void
-netfs_report_access (struct netcred *cred,
+ <hurd/netfs.h>. */
+error_t
+netfs_report_access (struct iouser *cred,
struct node *np,
int *types)
{
- *types = guess_mode_use (np, cred);
-}
+ error_t err;
+ err = netfs_validate_stat (np, cred);
+ if (err)
+ return err;
+
+ if (protocol_version == 2)
+ {
+ /* Hope the server means the same thing for the bits as we do. */
+ *types = 0;
+ if (fshelp_access (&np->nn_stat, S_IREAD, cred) == 0)
+ *types |= O_READ;
+ if (fshelp_access (&np->nn_stat, S_IWRITE, cred) == 0)
+ *types |= O_WRITE;
+ if (fshelp_access (&np->nn_stat, S_IEXEC, cred) == 0)
+ *types |= O_EXEC;
+ return 0;
+ }
+ else
+ {
+ int *p;
+ void *rpcbuf;
+ error_t err;
+ int ret;
+ int write_check, execute_check;
+
+ if (S_ISDIR (np->nn_stat.st_mode))
+ {
+ write_check = ACCESS3_MODIFY | ACCESS3_DELETE | ACCESS3_EXTEND;
+ execute_check = ACCESS3_LOOKUP;
+ }
+ else
+ {
+ write_check = ACCESS3_MODIFY;
+ execute_check = ACCESS3_EXECUTE;
+ }
+
+ p = nfs_initialize_rpc (NFS3PROC_ACCESS, cred, 0, &rpcbuf, np, -1);
+ if (! p)
+ return errno;
+
+ p = xdr_encode_fhandle (p, &np->nn->handle);
+ *(p++) = htonl (ACCESS3_READ | write_check | execute_check);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ p = process_returned_stat (np, p, 0); /* XXX Should this be
+ protected by the
+ if (!err) ? */
+ if (!err)
+ {
+ ret = ntohl (*p);
+ p++;
+ *types = ((ret & ACCESS3_READ ? O_READ : 0)
+ | (ret & write_check ? O_WRITE : 0)
+ | (ret & execute_check ? O_EXEC : 0));
+ }
+ }
+ return err;
+ }
+}
/* These definitions have unfortunate side effects, don't use them,
- clever though they are. */
+ clever though they are. */
#if 0
/* Implement the netfs_check_open_permissions callback as described in
<hurd/netfs.h>. */
error_t
-netfs_check_open_permissions (struct netcred *cred, struct node *np,
+netfs_check_open_permissions (struct iouser *cred, struct node *np,
int flags, int newnode)
{
char byte;
error_t err;
size_t len;
-
+
/* Sun derived nfs client implementations attempt to reproduce the
server's permission restrictions by hoping they look like Unix,
and using that to give errors at open time. Sadly, that loses
@@ -966,17 +1578,17 @@ netfs_check_open_permissions (struct netcred *cred, struct node *np,
&& (flags & O_WRITE) == 0
&& (flags & O_EXEC) == 0)
return 0;
-
+
err = netfs_validate_stat (np, cred);
if (err)
return err;
-
+
switch (np->nn_stat.st_mode & S_IFMT)
{
/* Don't know how to check, so return provisional success. */
default:
return 0;
-
+
case S_IFREG:
len = 1;
err = netfs_attempt_read (cred, np, 0, &len, &byte);
@@ -985,16 +1597,16 @@ netfs_check_open_permissions (struct netcred *cred, struct node *np,
if ((flags & O_READ) || (flags & O_EXEC))
return err;
else
- /* If we couldn't read a byte, but the user wasn't actually asking
+ /* If we couldn't read a byte, but the user wasn't actually asking
for read, then we shouldn't inhibit the open now. */
return 0;
}
-
+
if (len != 1)
/* The file is empty; reads are known to be OK, but writes can't be
tested, so no matter what, return success. */
return 0;
-
+
if (flags & O_WRITE)
{
err = netfs_attempt_write (cred, np, 0, &len, &byte);
@@ -1015,35 +1627,38 @@ netfs_check_open_permissions (struct netcred *cred, struct node *np,
return failure. Otherwise, succeed. */
p = nfs_initialize_rpc (NFSPROC_READDIR, cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
- *p++ = 0;
- *p++ = htonl (50);
+ *(p++) = 0;
+ *(p++) = htonl (50);
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
free (rpcbuf);
-
+
if (err)
return err;
}
return 0;
}
}
-
+
/* Implement the netfs_report_access callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
void
-netfs_report_access (struct netcred *cred,
+netfs_report_access (struct iouser *cred,
struct node *np,
int *types)
{
char byte;
error_t err;
size_t len;
-
+
/* Much the same logic as netfs_check_open_permissions, except that
here we err on the side of denying access, and that we always
have to check everything. */
-
+
*types = 0;
len = 1;
@@ -1080,9 +1695,9 @@ netfs_report_access (struct netcred *cred,
*BUFP to that buffer. *BUFP must be freed by the caller when no
longer needed. If an error occurs, don't touch *BUFP and return
the error code. Set BUFSIZEP to the amount of data used inside
- *BUFP and TOTALENTRIES to the total number of entries copied. */
+ *BUFP and TOTALENTRIES to the total number of entries copied. */
static error_t
-fetch_directory (struct netcred *cred, struct node *dir,
+fetch_directory (struct iouser *cred, struct node *dir,
void **bufp, size_t *bufsizep, int *totalentries)
{
void *buf;
@@ -1097,7 +1712,11 @@ fetch_directory (struct netcred *cred, struct node *dir,
int isnext;
bufmalloced = read_size;
+
buf = malloc (bufmalloced);
+ if (! buf)
+ return ENOMEM;
+
bp = buf;
cookie = 0;
eof = 0;
@@ -1106,66 +1725,82 @@ fetch_directory (struct netcred *cred, struct node *dir,
while (!eof)
{
/* Fetch new directory entries */
- p = nfs_initialize_rpc (NFSPROC_READDIR, cred, 0, &rpcbuf, dir, -1);
+ p = nfs_initialize_rpc (NFSPROC_READDIR (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ if (! p)
+ {
+ free (buf);
+ return errno;
+ }
+
p = xdr_encode_fhandle (p, &dir->nn->handle);
- *p++ = cookie;
- *p++ = ntohl (read_size);
+ *(p++) = cookie;
+ *(p++) = ntohl (read_size);
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p));
+ p++;
+ }
if (err)
{
free (buf);
return err;
}
- isnext = ntohl (*p++);
-
+ isnext = ntohl (*p);
+ p++;
+
/* Now copy them one at a time. */
while (isnext)
{
ino_t fileno;
int namlen;
int reclen;
-
- fileno = ntohl (*p++);
- namlen = ntohl (*p++);
+
+ fileno = ntohl (*p);
+ p++;
+ namlen = ntohl (*p);
+ p++;
/* There's a hidden +1 here for the null byte and -1 because d_name
has a size of one already in the sizeof. */
reclen = sizeof (struct dirent) + namlen;
reclen = (reclen + 3) & ~3; /* make it a multiple of four */
-
+
/* Expand buffer if necessary */
if (bp + reclen > buf + bufmalloced)
{
char *newbuf;
-
+
newbuf = realloc (buf, bufmalloced *= 2);
+ assert (newbuf);
if (newbuf != buf)
bp = newbuf + (bp - buf);
buf = newbuf;
}
-
+
/* Fill in new entry */
entry = (struct dirent *) bp;
entry->d_fileno = fileno;
entry->d_reclen = reclen;
entry->d_type = DT_UNKNOWN;
entry->d_namlen = namlen;
- bcopy (p, entry->d_name, namlen);
+ memcpy (entry->d_name, p, namlen);
entry->d_name[namlen] = '\0';
p += INTSIZE (namlen);
bp = bp + entry->d_reclen;
++*totalentries;
-
- cookie = *p++;
- isnext = ntohl (*p++);
+
+ cookie = *(p++);
+ isnext = ntohl (*p);
+ p++;
}
- eof = ntohl (*p++);
+ eof = ntohl (*p);
+ p++;
free (rpcbuf);
}
@@ -1175,11 +1810,11 @@ fetch_directory (struct netcred *cred, struct node *dir,
return 0;
}
-
+
/* Implement the netfs_get_directs callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_get_dirents (struct netcred *cred, struct node *np,
+netfs_get_dirents (struct iouser *cred, struct node *np,
int entry, int nentries, char **data,
mach_msg_type_number_t *datacnt,
vm_size_t bufsiz, int *amt)
@@ -1195,15 +1830,15 @@ netfs_get_dirents (struct netcred *cred, struct node *np,
err = fetch_directory (cred, np, &buf, &our_bufsiz, &totalentries);
if (err)
return err;
-
+
/* Allocate enough space to hold the maximum we might return. */
if (!bufsiz || bufsiz > our_bufsiz)
allocsize = round_page (our_bufsiz);
else
allocsize = round_page (bufsiz);
if (allocsize > *datacnt)
- vm_allocate (mach_task_self (), (vm_address_t *)data, allocsize, 1);
-
+ *data = mmap (0, allocsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+
/* Skip ahead to the correct entry. */
bp = buf;
for (thisentry = 0; thisentry < entry;)
@@ -1212,18 +1847,18 @@ netfs_get_dirents (struct netcred *cred, struct node *np,
bp += entry->d_reclen;
thisentry++;
}
-
+
/* Now copy them one at a time */
{
int entries_copied;
-
- for (entries_copied = 0, userdp = *data;
+
+ for (entries_copied = 0, userdp = *data;
(nentries == -1 || entries_copied < nentries)
&& (!bufsiz || userdp - *data < bufsiz)
&& thisentry < totalentries;)
{
struct dirent *entry = (struct dirent *) bp;
- bcopy (bp, userdp, entry->d_reclen);
+ memcpy (userdp, bp, entry->d_reclen);
bp += entry->d_reclen;
userdp += entry->d_reclen;
entries_copied++;
@@ -1231,45 +1866,34 @@ netfs_get_dirents (struct netcred *cred, struct node *np,
}
*amt = entries_copied;
}
-
+
free (buf);
- /* If we allocated the buffer ourselves, but didn't use
+ /* If we allocated the buffer ourselves, but didn't use
all the pages, free the extra. */
if (allocsize > *datacnt
&& round_page (userdp - *data) < round_page (allocsize))
- vm_deallocate (mach_task_self (), round_page (userdp),
- round_page (allocsize) - round_page (userdp - *data));
+ munmap ((caddr_t) round_page (userdp),
+ round_page (allocsize) - round_page (userdp - *data));
*datacnt = userdp - *data;
return 0;
}
-
-/* Implement the netfs_set_translator callback as described in
- <hurd/netfs.h>. */
-error_t
-netfs_set_translator (struct netcred *cred,
- struct node *np,
- char *argz,
- size_t argzlen)
-{
- return EOPNOTSUPP;
-}
/* Implement the netfs_attempt_mksymlink callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_mksymlink (struct netcred *cred,
+netfs_attempt_mksymlink (struct iouser *cred,
struct node *np,
char *arg)
{
if (np->nn->dtrans == NOT_POSSIBLE)
return EOPNOTSUPP;
-
+
if (np->nn->dtrans == SYMLINK)
free (np->nn->transarg.name);
-
+
np->nn->transarg.name = malloc (strlen (arg) + 1);
strcpy (np->nn->transarg.name, arg);
np->nn->dtrans = SYMLINK;
@@ -1278,19 +1902,19 @@ netfs_attempt_mksymlink (struct netcred *cred,
}
/* Implement the netfs_attempt_mkdev callback as described in
- <hurd/netfs.h>. */
+ <hurd/netfs.h>. */
error_t
-netfs_attempt_mkdev (struct netcred *cred,
+netfs_attempt_mkdev (struct iouser *cred,
struct node *np,
mode_t type,
dev_t indexes)
{
if (np->nn->dtrans == NOT_POSSIBLE)
return EOPNOTSUPP;
-
+
if (np->nn->dtrans == SYMLINK)
free (np->nn->transarg.name);
-
+
np->nn->transarg.indexes = indexes;
if (type == S_IFBLK)
np->nn->dtrans = BLKDEV;
@@ -1299,5 +1923,3 @@ netfs_attempt_mkdev (struct netcred *cred,
np->nn->stat_updated = 0;
return 0;
}
-
-
diff --git a/nfs/pager.c b/nfs/pager.c
deleted file mode 100644
index 687a0e2f..00000000
--- a/nfs/pager.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-
-#include "nfs.h"
-#include <unistd.h>
-#include <hurd/pager.h>
-#include <netinet/in.h>
-#include <string.h>
-
-struct user_pager_info
-{
- struct node *np;
- struct pager *p;
- int max_prot;
-};
-
-struct pager_cache_rec
-{
- struct pager_cache_rec *next;
- vm_offset_t offset;
- struct pager *p;
- time_t fetched;
-};
-
-static struct pager_cache_rec *pager_cache_recs;
-static spin_lock_t pager_cache_rec_lock = SPIN_LOCK_INITIALIZER;
-static spin_lock_t node2pagelock = SPIN_LOCK_INITIALIZER;
-static struct port_bucket *pager_bucket;
-
-void
-register_new_page (struct pager *p, vm_offset_t offset)
-{
- struct pager_cache_rec *pc;
-
- pc = malloc (sizeof (struct pager_cache_rec));
- pc->offset = offset;
- pc->p = p;
- ports_port_ref (p);
- pc->fetched = mapped_time->seconds;
-
- spin_lock (&pager_cache_rec_lock);
- pc->next = pager_cache_recs;
- pager_cache_recs = pc;
- spin_unlock (&pager_cache_rec_lock);
-}
-
-any_t
-flush_pager_cache_thread (any_t foo2)
-{
- struct pager_cache_rec *pc, *next, **ppc, *list;
-
- for (;;)
- {
- sleep (1);
-
- /* Dequeue from the main list and queue locally the recs
- for expired pages. */
- list = 0;
- spin_lock (&pager_cache_rec_lock);
- for (pc = pager_cache_recs, ppc = &pager_cache_recs;
- pc;
- ppc = &pc->next, pc = next)
- {
- next = pc->next;
- if (mapped_time->seconds - pc->fetched > cache_timeout)
- {
- *ppc = pc->next;
- pc->next = list;
- list = pc;
- }
- }
- spin_unlock (&pager_cache_rec_lock);
-
- /* And now, one at a time, expire them */
- for (pc = list; pc; pc = next)
- {
- pager_return_some (pc->p, pc->offset, vm_page_size, 0);
- next = pc->next;
- ports_port_deref (pc->p);
- free (pc);
- }
- }
-}
-
-error_t
-pager_read_page (struct user_pager_info *pager,
- vm_offset_t page,
- vm_address_t *buf,
- int *writelock)
-{
- error_t err;
- int *p;
- void *rpcbuf;
- struct node *np;
- size_t amt, thisamt, trans_len;
- void *data;
- off_t offset;
-
- np = pager->np;
-
- mutex_lock (&np->lock);
-
- vm_allocate (mach_task_self (), buf, vm_page_size, 1);
- data = (char *) *buf;
- amt = vm_page_size;
- offset = page;
-
- while (amt)
- {
- thisamt = amt;
- if (thisamt > read_size)
- thisamt = read_size;
-
- p = nfs_initialize_rpc (NFSPROC_READ, (struct netcred *)-1, 0,
- &rpcbuf, np, -1);
- p = xdr_encode_fhandle (p, &np->nn->handle);
- *p++ = htonl (offset);
- *p++ = htonl (vm_page_size);
- *p++ = 0;
-
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
- if (err)
- {
- mutex_unlock (&np->lock);
- free (rpcbuf);
- vm_deallocate (mach_task_self (), *buf, vm_page_size);
- return err;
- }
-
- p = register_fresh_stat (np, p);
- trans_len = ntohl (*p++);
- if (trans_len > thisamt)
- trans_len = thisamt; /* ??? */
-
- bcopy (p, data, trans_len);
-
- free (rpcbuf);
-
- data += trans_len;
- offset += trans_len;
- amt -= trans_len;
-
- /* If we got a short count, we're all done. */
- if (trans_len < thisamt)
- break;
- }
-
- register_new_page (pager->p, page);
- mutex_unlock (&np->lock);
- return 0;
-}
-
-
-error_t
-pager_write_page (struct user_pager_info *pager,
- vm_offset_t page,
- vm_address_t buf)
-{
- int *p;
- void *rpcbuf;
- error_t err;
- size_t amt, thisamt;
- off_t offset;
- struct node *np;
- void *data;
-
- np = pager->np;
- mutex_lock (&np->lock);
-
- amt = vm_page_size;
- offset = page;
- data = (void *) buf;
-
- while (amt)
- {
- thisamt = amt;
- if (amt > write_size)
- amt = write_size;
-
- p = nfs_initialize_rpc (NFSPROC_WRITE, (struct netcred *) -1,
- amt, &rpcbuf, np, -1);
- p = xdr_encode_fhandle (p, &np->nn->handle);
- *p++ = 0;
- *p++ = htonl (offset);
- *p++ = 0;
- p = xdr_encode_data (p, data, thisamt);
-
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
- if (err)
- {
- free (rpcbuf);
- vm_deallocate (mach_task_self (), buf, vm_page_size);
- return err;
- }
- register_fresh_stat (np, p);
- free (rpcbuf);
- amt -= thisamt;
- data += thisamt;
- offset += thisamt;
- }
-
- vm_deallocate (mach_task_self (), buf, vm_page_size);
- mutex_unlock (&np->lock);
- return 0;
-}
-
-error_t
-pager_unlock_page (struct user_pager_info *pager,
- vm_offset_t address)
-{
- abort ();
-}
-
-error_t
-pager_report_extent (struct user_pager_info *pager,
- vm_address_t *offset,
- vm_size_t *size)
-{
- struct node *np;
- error_t err;
-
- np = pager->np;
- mutex_lock (&np->lock);
-
- err = netfs_validate_stat (np, 0);
- if (!err)
- *size = round_page (np->nn_stat.st_size);
- mutex_unlock (&np->lock);
- return err;
-}
-
-void
-pager_clear_user_data (struct user_pager_info *upi)
-{
- spin_lock (&node2pagelock);
- if (upi->np->nn->fileinfo == upi)
- upi->np->nn->fileinfo = 0;
- spin_unlock (&node2pagelock);
- netfs_nrele (upi->np);
- free (upi);
-}
-
-void
-pager_dropweak (struct user_pager_info *upi)
-{
- abort ();
-}
-
-mach_port_t
-netfs_get_filemap (struct node *np, vm_prot_t prot)
-{
- struct user_pager_info *upi;
- mach_port_t right;
-
- spin_lock (&node2pagelock);
- do
- if (!np->nn->fileinfo)
- {
- upi = malloc (sizeof (struct user_pager_info));
- upi->np = np;
- netfs_nref (np);
- upi->max_prot = prot;
- upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_NONE);
- np->nn->fileinfo = upi;
- right = pager_get_port (np->nn->fileinfo->p);
- ports_port_deref (np->nn->fileinfo->p);
- }
- else
- {
- np->nn->fileinfo->max_prot |= prot;
- /* Because NP->dn->fileinfo->p is not a real reference,
- this might be nearly deallocated. If that's so, then
- the port right will be null. In that case, clear here
- and loop. The deallocation will complete separately. */
- right = pager_get_port (np->nn->fileinfo->p);
- if (right == MACH_PORT_NULL)
- np->nn->fileinfo = 0;
- }
- while (right == MACH_PORT_NULL);
-
- spin_unlock (&node2pagelock);
-
- mach_port_insert_right (mach_task_self (), right, right,
- MACH_MSG_TYPE_MAKE_SEND);
- return right;
-}
-
-void
-drop_pager_softrefs (struct node *np)
-{
- struct user_pager_info *upi;
-
- spin_lock (&node2pagelock);
- upi = np->nn->fileinfo;
- if (upi)
- ports_port_ref (upi->p);
- spin_unlock (&node2pagelock);
-
- if (upi)
- {
- pager_change_attributes (upi->p, 0, MEMORY_OBJECT_COPY_NONE, 0);
- ports_port_deref (upi->p);
- }
-}
-
-void
-allow_pager_softrefs (struct node *np)
-{
- struct user_pager_info *upi;
-
- spin_lock (&node2pagelock);
- upi = np->nn->fileinfo;
- if (upi)
- ports_port_ref (upi->p);
- spin_unlock (&node2pagelock);
-
- if (upi)
- {
- pager_change_attributes (upi->p, 1, MEMORY_OBJECT_COPY_NONE, 0);
- ports_port_deref (upi->p);
- }
-}
-
-void
-block_caching ()
-{
- error_t block_cache (void *arg)
- {
- struct pager *p = arg;
- pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_NONE, 1);
- return 0;
- }
- ports_bucket_iterate (pager_bucket, block_cache);
-}
-
-void
-enable_caching ()
-{
- error_t enable_cache (void *arg)
- {
- struct pager *p = arg;
- struct user_pager_info *upi = pager_get_upi (p);
-
- pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_NONE, 0);
- return 0;
- }
-
- ports_bucket_iterate (pager_bucket, enable_cache);
-}
-
-int
-netfs_pager_users ()
-{
- int npagers = ports_count_bucket (pager_bucket);
-
- if (!npagers)
- return 0;
-
- block_caching ();
- /* Give it a sec; the kernel doesn't issue the shutdown right away */
- sleep (1);
- npagers = ports_count_bucket (pager_bucket);
- if (!npagers)
- return 0;
-
- enable_caching ();
-
- ports_enable_bucket (pager_bucket);
-}
-
-vm_prot_t
-netfs_max_user_pager_prot ()
-{
- vm_prot_t max_prot;
- int npagers = ports_count_bucket (pager_bucket);
-
- if (npagers)
- {
- error_t add_pager_max_prot (void *v_p)
- {
- struct pager *p = v_p;
- struct user_pager_info *upi = pager_get_upi (p);
- max_prot |= upi->max_prot;
- return max_prot == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
- }
-
- block_caching ();
- sleep (1);
-
- ports_bucket_iterate (pager_bucket, add_pager_max_prot);
- enable_caching ();
- }
-
- ports_enable_bucket (pager_bucket);
- return max_prot;
-}
-
-void
-netfs_shutdown_pager ()
-{
- error_t shutdown_one (void *arg)
- {
- pager_shutdown ((struct pager *) arg);
- return 0;
- }
-
- ports_bucket_iterate (pager_bucket, shutdown_one);
-}
-
-void
-netfs_sync_everything (int wait)
-{
- error_t sync_one (void *arg)
- {
- pager_sync ((struct pager *) arg, wait);
- return 0;
- }
- ports_bucket_iterate (pager_bucket, sync_one);
-}
-
-void
-pager_initialize (void)
-{
- pager_bucket = ports_create_bucket ();
- cthread_detach (cthread_fork (flush_pager_cache_thread, 0));
-
diff --git a/nfs/rpc.c b/nfs/rpc.c
index 7df05c36..0b0444d0 100644
--- a/nfs/rpc.c
+++ b/nfs/rpc.c
@@ -1,5 +1,5 @@
-/* SunRPC management for NFS client
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+/* rpc.c - SunRPC management for NFS client.
+ Copyright (C) 1994, 1995, 1996, 1997, 2002 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,10 +17,10 @@
#include "nfs.h"
-/* Needed in order to get the RPC header files to include correctly */
+/* Needed in order to get the RPC header files to include correctly. */
#undef TRUE
#undef FALSE
-#define malloc spoiufasdf /* Avoid bogus definition in rpc/types.h */
+#define malloc spoiufasdf /* Avoid bogus definition in rpc/types.h. */
#include <rpc/types.h>
#include <rpc/xdr.h>
@@ -28,40 +28,36 @@
#include <rpc/rpc_msg.h>
#include <rpc/auth_unix.h>
-#undef malloc /* Get rid protection. */
+#undef malloc /* Get rid of the sun block. */
#include <netinet/in.h>
#include <assert.h>
#include <errno.h>
+#include <error.h>
#include <unistd.h>
#include <stdio.h>
-/* One of these exists for each pending RPC. */
+/* One of these exists for each pending RPC. */
struct rpc_list
{
struct rpc_list *next, **prevp;
void *reply;
};
-/* A list of all the pending RPCs. */
+/* A list of all pending RPCs. */
static struct rpc_list *outstanding_rpcs;
-/* This lock must be held around any modifications to the list
- structure of outstanding_rpcs. */
-static spin_lock_t rpc_list_lock = SPIN_LOCK_INITIALIZER;
-
/* Wake up this condition when an outstanding RPC has received a reply
- or we should check for timeouts. */
+ or we should check for timeouts. */
static struct condition rpc_wakeup = CONDITION_INITIALIZER;
-/* This lock must be held around modifications of the REPLY members of
- records on outstanding_rpcs and around uses of rpc_wakeup. */
+/* Lock the global data and the REPLY fields of outstanding RPC's. */
static struct mutex outstanding_lock = MUTEX_INITIALIZER;
-/* Generate and return a new transaction ID. */
-static int
+/* Generate and return a new transaction ID. */
+static inline int
generate_xid ()
{
static int nextxid;
@@ -72,22 +68,31 @@ generate_xid ()
return nextxid++;
}
-/* Set up an RPC for procdeure RPC_PROC, for talking to the server
+/* Set up an RPC for procdeure RPC_PROC for talking to the server
PROGRAM of version VERSION. Allocate storage with malloc and point
*BUF at it; caller must free this when done. Allocate at least LEN
- bytes more than the usual amount for an RPC. Initialize the RPC
- credential structure with UID, GID, and SECOND_GID. (Any of those
- may be -1 to indicate that it does not apply; exactly or two of UID
- and GID must be -1, however.) */
+ bytes more than the usual amount for the RPC. Initialize the RPC
+ credential structure with UID, GID, and SECOND_GID; any of these
+ may be -1 to indicate that it does not apply, however, exactly zero
+ or two of UID and GID must be -1. The returned address is a pointer
+ to the start of the payload. If NULL is returned, an error occurred
+ and the code is set in errno. */
int *
initialize_rpc (int program, int version, int rpc_proc,
size_t len, void **bufp,
uid_t uid, gid_t gid, gid_t second_gid)
{
- void *buf = malloc (len + 1024);
+ void *buf;
int *p, *lenaddr;
struct rpc_list *hdr;
+ buf = malloc (len + 1024);
+ if (! buf)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
/* First the struct rpc_list bit. */
hdr = buf;
hdr->reply = 0;
@@ -95,63 +100,78 @@ initialize_rpc (int program, int version, int rpc_proc,
p = buf + sizeof (struct rpc_list);
/* RPC header */
- *p++ = htonl (generate_xid ());
- *p++ = htonl (CALL);
- *p++ = htonl (RPC_MSG_VERSION);
- *p++ = htonl (program);
- *p++ = htonl (version);
- *p++ = htonl (rpc_proc);
+ *(p++) = htonl (generate_xid ());
+ *(p++) = htonl (CALL);
+ *(p++) = htonl (RPC_MSG_VERSION);
+ *(p++) = htonl (program);
+ *(p++) = htonl (version);
+ *(p++) = htonl (rpc_proc);
assert ((uid == -1) == (gid == -1));
- if (uid != -1)
+ if (uid == -1)
{
- *p++ = htonl (AUTH_UNIX);
+ /* No authentication */
+ *(p++) = htonl (AUTH_NONE);
+ *(p++) = 0;
+ }
+ else
+ {
+ /* Unixy authentication */
+ *(p++) = htonl (AUTH_UNIX);
+ /* The length of the message. We do not yet know what this
+ is, so, just remember where we should put it when we know */
lenaddr = p++;
- *p++ = htonl (mapped_time->seconds);
+ *(p++) = htonl (mapped_time->seconds);
p = xdr_encode_string (p, hostname);
- *p++ = htonl (uid);
- *p++ = htonl (gid);
- if (second_gid != -1)
+ *(p++) = htonl (uid);
+ *(p++) = htonl (gid);
+ if (second_gid == -1)
+ *(p++) = 0;
+ else
{
- *p++ = htonl (1);
- *p++ = htonl (second_gid);
+ *(p++) = htonl (1);
+ *(p++) = htonl (second_gid);
}
- else
- *p++ = 0;
*lenaddr = htonl ((p - (lenaddr + 1)) * sizeof (int));
}
- else
- {
- *p++ = htonl (AUTH_NULL);
- *p++ = 0;
- }
/* VERF field */
- *p++ = htonl (AUTH_NULL);
- *p++ = 0;
+ *(p++) = htonl (AUTH_NONE);
+ *(p++) = 0;
*bufp = buf;
return p;
}
-/* Remove HDR from the list of pending RPC's. */
-static void
+/* Remove HDR from the list of pending RPC's. The rpc_list's lock
+ (OUTSTANDING_LOCK) must be held. */
+static inline void
unlink_rpc (struct rpc_list *hdr)
{
- spin_lock (&rpc_list_lock);
*hdr->prevp = hdr->next;
if (hdr->next)
hdr->next->prevp = hdr->prevp;
- spin_unlock (&rpc_list_lock);
+}
+
+/* Insert HDR at the head of the LIST. The rpc_list's lock
+ (OUTSTANDING_LOCK) must be held. */
+static inline void
+link_rpc (struct rpc_list **list, struct rpc_list *hdr)
+{
+ hdr->next = *list;
+ if (hdr->next)
+ hdr->next->prevp = &hdr->next;
+ hdr->prevp = list;
+ *list = hdr;
}
/* Send the specified RPC message. *RPCBUF is the initialized buffer
- from a previous initialize_rpc call; *PP points past the filled
- in args. Set *PP to the address of the reply contents themselves.
- The user will be expected to free *RPCBUF (which will have changed)
- when done with the reply contents. The old value of *RPCBUF will
- be freed by this routine. */
+ from a previous initialize_rpc call; *PP, the payload, points past
+ the filledin args. Set *PP to the address of the reply contents
+ themselves. The user will be expected to free *RPCBUF (which will
+ have changed) when done with the reply contents. The old value of
+ *RPCBUF will be freed by this routine. */
error_t
conduct_rpc (void **rpcbuf, int **pp)
{
@@ -166,86 +186,94 @@ conduct_rpc (void **rpcbuf, int **pp)
int n;
int cancel;
- /* Link it in */
- spin_lock (&rpc_list_lock);
- hdr->next = outstanding_rpcs;
- if (hdr->next)
- hdr->next->prevp = &hdr->next;
- hdr->prevp = &outstanding_rpcs;
- outstanding_rpcs = hdr;
- spin_unlock (&rpc_list_lock);
+ mutex_lock (&outstanding_lock);
+
+ link_rpc (&outstanding_rpcs, hdr);
xid = * (int *) (*rpcbuf + sizeof (struct rpc_list));
do
{
- /* If we've sent enough, give up */
+ /* If we've sent enough, give up. */
if (mounted_soft && ntransmit == soft_retries)
{
unlink_rpc (hdr);
+ mutex_unlock (&outstanding_lock);
return ETIMEDOUT;
}
- /* Issue the RPC */
- mutex_lock (&outstanding_lock);
+ /* Issue the RPC. */
lasttrans = mapped_time->seconds;
ntransmit++;
nc = (void *) *pp - *rpcbuf - sizeof (struct rpc_list);
cc = write (main_udp_socket, *rpcbuf + sizeof (struct rpc_list), nc);
if (cc == -1)
- assert_perror (errno);
+ {
+ unlink_rpc (hdr);
+ mutex_unlock (&outstanding_lock);
+ return errno;
+ }
else
assert (cc == nc);
- /* Wait for reply */
+ /* Wait for reply. */
cancel = 0;
while (!hdr->reply
&& (mapped_time->seconds - lasttrans < timeout)
&& !cancel)
cancel = hurd_condition_wait (&rpc_wakeup, &outstanding_lock);
- mutex_unlock (&outstanding_lock);
if (cancel)
{
unlink_rpc (hdr);
+ mutex_unlock (&outstanding_lock);
return EINTR;
}
+ /* hdr->reply will have been filled in by rpc_receive_thread,
+ if it has been filled in, then the rpc has been fulfilled,
+ otherwise, retransmit and continue to wait. */
if (!hdr->reply)
{
- timeout *=2;
+ timeout *= 2;
if (timeout > max_transmit_timeout)
timeout = max_transmit_timeout;
}
}
while (!hdr->reply);
- /* Switch to the reply buffer. */
+ mutex_unlock (&outstanding_lock);
+
+ /* Switch to the reply buffer. */
*rpcbuf = hdr->reply;
free (hdr);
- /* Process the reply, dissecting errors. When we're done, set *PP to
- the rpc return contents, if there is no error. */
+ /* Process the reply, dissecting errors. When we're done and if
+ there is no error, set *PP to the rpc return contents. */
p = (int *) *rpcbuf;
+ /* If the transmition id does not match that in the message,
+ something strange happened in rpc_receive_thread. */
assert (*p == xid);
p++;
- switch (ntohl (*p++))
+ switch (ntohl (*p))
{
default:
err = EBADRPC;
break;
case REPLY:
- switch (ntohl (*p++))
+ p++;
+ switch (ntohl (*p))
{
default:
err = EBADRPC;
break;
case MSG_DENIED:
- switch (ntohl (*p++))
+ p++;
+ switch (ntohl (*p))
{
default:
err = EBADRPC;
@@ -256,7 +284,8 @@ conduct_rpc (void **rpcbuf, int **pp)
break;
case AUTH_ERROR:
- switch (ntohl (*p++))
+ p++;
+ switch (ntohl (*p))
{
case AUTH_BADCRED:
case AUTH_REJECTEDCRED:
@@ -278,13 +307,15 @@ conduct_rpc (void **rpcbuf, int **pp)
break;
case MSG_ACCEPTED:
+ p++;
- /* Process VERF field. */
- p++; /* skip verf type */
- n = ntohl (*p++); /* size of verf */
- p += INTSIZE (n); /* skip verf itself */
+ /* Process VERF field. */
+ p++; /* Skip verf type. */
+ n = ntohl (*p); /* Size of verf. */
+ p++;
+ p += INTSIZE (n); /* Skip verf itself. */
- switch (ntohl (*p++))
+ switch (ntohl (*p))
{
default:
case GARBAGE_ARGS:
@@ -304,6 +335,7 @@ conduct_rpc (void **rpcbuf, int **pp)
break;
case SUCCESS:
+ p++;
*pp = p;
err = 0;
break;
@@ -315,7 +347,8 @@ conduct_rpc (void **rpcbuf, int **pp)
return err;
}
-/* Dedicated thread to wakeup rpc_wakeup once a second. */
+/* Dedicated thread to signal those waiting on rpc_wakeup
+ once a second. */
void
timeout_service_thread ()
{
@@ -329,59 +362,56 @@ timeout_service_thread ()
}
/* Dedicate thread to receive RPC replies, register them on the queue
- of pending wakeups, and deal appropriately. */
+ of pending wakeups, and deal appropriately. */
void
rpc_receive_thread ()
{
- int cc;
void *buf;
- struct rpc_list *r;
- int xid;
+
+ /* Allocate a receive buffer. */
+ buf = malloc (1024 + read_size);
+ assert (buf);
while (1)
{
- buf = malloc (1024 + read_size);
-
- do
- {
- cc = read (main_udp_socket, buf, 1024 + read_size);
- if (cc == -1)
- {
- perror ("nfs read");
- r = 0;
+ int cc = read (main_udp_socket, buf, 1024 + read_size);
+ if (cc == -1)
+ {
+ error (0, errno, "nfs read");
+ continue;
+ }
+ else
+ {
+ struct rpc_list *r;
+ int xid = *(int *)buf;
+
+ mutex_lock (&outstanding_lock);
+
+ /* Find the rpc that we just fulfilled. */
+ for (r = outstanding_rpcs; r; r = r->next)
+ {
+ if (* (int *) &r[1] == xid)
+ {
+ unlink_rpc (r);
+ r->reply = buf;
+ condition_broadcast (&rpc_wakeup);
+ break;
+ }
}
- else
+#if 0
+ if (! r)
+ fprintf (stderr, "NFS dropping reply xid %d\n", xid);
+#endif
+ mutex_unlock (&outstanding_lock);
+
+ /* If r is not null then we had a message from a pending
+ (i.e. known) rpc. Thus, it was fulfilled and if we want
+ to get another request, a new buffer is needed. */
+ if (r)
{
- xid = *(int *)buf;
- spin_lock (&rpc_list_lock);
- for (r = outstanding_rpcs; r; r = r->next)
- {
- if (* (int *) &r[1] == xid)
- {
- /* Remove it from the list */
- *r->prevp = r->next;
- if (r->next)
- r->next->prevp = r->prevp;
- spin_unlock (&rpc_list_lock);
-
- mutex_lock (&outstanding_lock);
- r->reply = buf;
- condition_broadcast (&rpc_wakeup);
- mutex_unlock (&outstanding_lock);
- break;
- }
- }
- if (!r)
- {
- spin_unlock (&rpc_list_lock);
- fprintf (stderr, "NFS dropping reply xid %d\n", xid);
- }
+ buf = malloc (1024 + read_size);
+ assert (buf);
}
- }
- while (!r);
+ }
}
}
-
-
-
-
diff --git a/nfs/rpcsvc/mount.h b/nfs/rpcsvc/mount.h
deleted file mode 100644
index 2dc3dc88..00000000
--- a/nfs/rpcsvc/mount.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#define MNTPATHLEN 1024
-#define MNTNAMLEN 255
-#define FHSIZE 32
-
-typedef char fhandle[FHSIZE];
-bool_t xdr_fhandle();
-
-
-struct fhstatus {
- u_int fhs_status;
- union {
- fhandle fhs_fhandle;
- } fhstatus_u;
-};
-typedef struct fhstatus fhstatus;
-bool_t xdr_fhstatus();
-
-
-typedef char *dirpath;
-bool_t xdr_dirpath();
-
-
-typedef char *name;
-bool_t xdr_name();
-
-
-typedef struct mountbody *mountlist;
-bool_t xdr_mountlist();
-
-
-struct mountbody {
- name ml_hostname;
- dirpath ml_directory;
- mountlist ml_next;
-};
-typedef struct mountbody mountbody;
-bool_t xdr_mountbody();
-
-
-typedef struct groupnode *groups;
-bool_t xdr_groups();
-
-
-struct groupnode {
- name gr_name;
- groups gr_next;
-};
-typedef struct groupnode groupnode;
-bool_t xdr_groupnode();
-
-
-typedef struct exportnode *exports;
-bool_t xdr_exports();
-
-
-struct exportnode {
- dirpath ex_dir;
- groups ex_groups;
- exports ex_next;
-};
-typedef struct exportnode exportnode;
-bool_t xdr_exportnode();
-
-
-#define MOUNTPROG ((u_long)100005)
-#define MOUNTVERS ((u_long)1)
-#define MOUNTPROC_NULL ((u_long)0)
-extern void *mountproc_null_1();
-#define MOUNTPROC_MNT ((u_long)1)
-extern fhstatus *mountproc_mnt_1();
-#define MOUNTPROC_DUMP ((u_long)2)
-extern mountlist *mountproc_dump_1();
-#define MOUNTPROC_UMNT ((u_long)3)
-extern void *mountproc_umnt_1();
-#define MOUNTPROC_UMNTALL ((u_long)4)
-extern void *mountproc_umntall_1();
-#define MOUNTPROC_EXPORT ((u_long)5)
-extern exports *mountproc_export_1();
-#define MOUNTPROC_EXPORTALL ((u_long)6)
-extern exports *mountproc_exportall_1();
-
diff --git a/nfs/rpcsvc/nfs_prot.h b/nfs/rpcsvc/nfs_prot.h
deleted file mode 100644
index 7f974930..00000000
--- a/nfs/rpcsvc/nfs_prot.h
+++ /dev/null
@@ -1,343 +0,0 @@
-#define NFS_PORT 2049
-#define NFS_MAXDATA 8192
-#define NFS_MAXPATHLEN 1024
-#define NFS_MAXNAMLEN 255
-#define NFS_FHSIZE 32
-#define NFS_COOKIESIZE 4
-#define NFS_FIFO_DEV -1
-#define NFSMODE_FMT 0170000
-#define NFSMODE_DIR 0040000
-#define NFSMODE_CHR 0020000
-#define NFSMODE_BLK 0060000
-#define NFSMODE_REG 0100000
-#define NFSMODE_LNK 0120000
-#define NFSMODE_SOCK 0140000
-#define NFSMODE_FIFO 0010000
-
-enum nfsstat {
- NFS_OK = 0,
- NFSERR_PERM = 1,
- NFSERR_NOENT = 2,
- NFSERR_IO = 5,
- NFSERR_NXIO = 6,
- NFSERR_ACCES = 13,
- NFSERR_EXIST = 17,
- NFSERR_NODEV = 19,
- NFSERR_NOTDIR = 20,
- NFSERR_ISDIR = 21,
- NFSERR_FBIG = 27,
- NFSERR_NOSPC = 28,
- NFSERR_ROFS = 30,
- NFSERR_NAMETOOLONG = 63,
- NFSERR_NOTEMPTY = 66,
- NFSERR_DQUOT = 69,
- NFSERR_STALE = 70,
- NFSERR_WFLUSH = 99,
-};
-typedef enum nfsstat nfsstat;
-bool_t xdr_nfsstat();
-
-
-enum ftype {
- NFNON = 0,
- NFREG = 1,
- NFDIR = 2,
- NFBLK = 3,
- NFCHR = 4,
- NFLNK = 5,
- NFSOCK = 6,
- NFBAD = 7,
- NFFIFO = 8,
-};
-typedef enum ftype ftype;
-bool_t xdr_ftype();
-
-
-struct nfs_fh {
- char data[NFS_FHSIZE];
-};
-typedef struct nfs_fh nfs_fh;
-bool_t xdr_nfs_fh();
-
-
-struct nfstime {
- u_int seconds;
- u_int useconds;
-};
-typedef struct nfstime nfstime;
-bool_t xdr_nfstime();
-
-
-struct fattr {
- ftype type;
- u_int mode;
- u_int nlink;
- u_int uid;
- u_int gid;
- u_int size;
- u_int blocksize;
- u_int rdev;
- u_int blocks;
- u_int fsid;
- u_int fileid;
- nfstime atime;
- nfstime mtime;
- nfstime ctime;
-};
-typedef struct fattr fattr;
-bool_t xdr_fattr();
-
-
-struct sattr {
- u_int mode;
- u_int uid;
- u_int gid;
- u_int size;
- nfstime atime;
- nfstime mtime;
-};
-typedef struct sattr sattr;
-bool_t xdr_sattr();
-
-
-typedef char *filename;
-bool_t xdr_filename();
-
-
-typedef char *nfspath;
-bool_t xdr_nfspath();
-
-
-struct attrstat {
- nfsstat status;
- union {
- fattr attributes;
- } attrstat_u;
-};
-typedef struct attrstat attrstat;
-bool_t xdr_attrstat();
-
-
-struct sattrargs {
- nfs_fh file;
- sattr attributes;
-};
-typedef struct sattrargs sattrargs;
-bool_t xdr_sattrargs();
-
-
-struct diropargs {
- nfs_fh dir;
- filename name;
-};
-typedef struct diropargs diropargs;
-bool_t xdr_diropargs();
-
-
-struct diropokres {
- nfs_fh file;
- fattr attributes;
-};
-typedef struct diropokres diropokres;
-bool_t xdr_diropokres();
-
-
-struct diropres {
- nfsstat status;
- union {
- diropokres diropres;
- } diropres_u;
-};
-typedef struct diropres diropres;
-bool_t xdr_diropres();
-
-
-struct readlinkres {
- nfsstat status;
- union {
- nfspath data;
- } readlinkres_u;
-};
-typedef struct readlinkres readlinkres;
-bool_t xdr_readlinkres();
-
-
-struct readargs {
- nfs_fh file;
- u_int offset;
- u_int count;
- u_int totalcount;
-};
-typedef struct readargs readargs;
-bool_t xdr_readargs();
-
-
-struct readokres {
- fattr attributes;
- struct {
- u_int data_len;
- char *data_val;
- } data;
-};
-typedef struct readokres readokres;
-bool_t xdr_readokres();
-
-
-struct readres {
- nfsstat status;
- union {
- readokres reply;
- } readres_u;
-};
-typedef struct readres readres;
-bool_t xdr_readres();
-
-
-struct writeargs {
- nfs_fh file;
- u_int beginoffset;
- u_int offset;
- u_int totalcount;
- struct {
- u_int data_len;
- char *data_val;
- } data;
-};
-typedef struct writeargs writeargs;
-bool_t xdr_writeargs();
-
-
-struct createargs {
- diropargs where;
- sattr attributes;
-};
-typedef struct createargs createargs;
-bool_t xdr_createargs();
-
-
-struct renameargs {
- diropargs from;
- diropargs to;
-};
-typedef struct renameargs renameargs;
-bool_t xdr_renameargs();
-
-
-struct linkargs {
- nfs_fh from;
- diropargs to;
-};
-typedef struct linkargs linkargs;
-bool_t xdr_linkargs();
-
-
-struct symlinkargs {
- diropargs from;
- nfspath to;
- sattr attributes;
-};
-typedef struct symlinkargs symlinkargs;
-bool_t xdr_symlinkargs();
-
-
-typedef char nfscookie[NFS_COOKIESIZE];
-bool_t xdr_nfscookie();
-
-
-struct readdirargs {
- nfs_fh dir;
- nfscookie cookie;
- u_int count;
-};
-typedef struct readdirargs readdirargs;
-bool_t xdr_readdirargs();
-
-
-struct entry {
- u_int fileid;
- filename name;
- nfscookie cookie;
- struct entry *nextentry;
-};
-typedef struct entry entry;
-bool_t xdr_entry();
-
-
-struct dirlist {
- entry *entries;
- bool_t eof;
-};
-typedef struct dirlist dirlist;
-bool_t xdr_dirlist();
-
-
-struct readdirres {
- nfsstat status;
- union {
- dirlist reply;
- } readdirres_u;
-};
-typedef struct readdirres readdirres;
-bool_t xdr_readdirres();
-
-
-struct statfsokres {
- u_int tsize;
- u_int bsize;
- u_int blocks;
- u_int bfree;
- u_int bavail;
-};
-typedef struct statfsokres statfsokres;
-bool_t xdr_statfsokres();
-
-
-struct statfsres {
- nfsstat status;
- union {
- statfsokres reply;
- } statfsres_u;
-};
-typedef struct statfsres statfsres;
-bool_t xdr_statfsres();
-
-
-#define NFS_PROGRAM ((u_long)100003)
-#define NFS_VERSION ((u_long)2)
-#define NFSPROC_NULL ((u_long)0)
-extern void *nfsproc_null_2();
-#define NFSPROC_GETATTR ((u_long)1)
-extern attrstat *nfsproc_getattr_2();
-#define NFSPROC_SETATTR ((u_long)2)
-extern attrstat *nfsproc_setattr_2();
-#define NFSPROC_ROOT ((u_long)3)
-extern void *nfsproc_root_2();
-#define NFSPROC_LOOKUP ((u_long)4)
-extern diropres *nfsproc_lookup_2();
-#define NFSPROC_READLINK ((u_long)5)
-extern readlinkres *nfsproc_readlink_2();
-#define NFSPROC_READ ((u_long)6)
-extern readres *nfsproc_read_2();
-#define NFSPROC_WRITECACHE ((u_long)7)
-extern void *nfsproc_writecache_2();
-#define NFSPROC_WRITE ((u_long)8)
-extern attrstat *nfsproc_write_2();
-#define NFSPROC_CREATE ((u_long)9)
-extern diropres *nfsproc_create_2();
-#define NFSPROC_REMOVE ((u_long)10)
-extern nfsstat *nfsproc_remove_2();
-#define NFSPROC_RENAME ((u_long)11)
-extern nfsstat *nfsproc_rename_2();
-#define NFSPROC_LINK ((u_long)12)
-extern nfsstat *nfsproc_link_2();
-#define NFSPROC_SYMLINK ((u_long)13)
-extern nfsstat *nfsproc_symlink_2();
-#define NFSPROC_MKDIR ((u_long)14)
-extern diropres *nfsproc_mkdir_2();
-#define NFSPROC_RMDIR ((u_long)15)
-extern nfsstat *nfsproc_rmdir_2();
-#define NFSPROC_READDIR ((u_long)16)
-extern readdirres *nfsproc_readdir_2();
-#define NFSPROC_STATFS ((u_long)17)
-extern statfsres *nfsproc_statfs_2();
-
diff --git a/nfs/storage-info.c b/nfs/storage-info.c
new file mode 100644
index 00000000..7427b3d8
--- /dev/null
+++ b/nfs/storage-info.c
@@ -0,0 +1,104 @@
+/* file_get_storage_info RPC for NFS client filesystem
+ Copyright (C) 2001,02 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "nfs.h"
+#include <hurd/netfs.h>
+#include <stdio.h>
+
+error_t
+netfs_file_get_storage_info (struct iouser *cred,
+ struct node *np,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints,
+ mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data,
+ mach_msg_type_number_t *data_len)
+{
+ int name_len, fhpos;
+ error_t err;
+
+ inline int fmt (size_t buflen)
+ {
+ return snprintf (*data, buflen,
+ "nfsv%u://%s:%u/%n%*c?rsize=%u&wsize=%u",
+ protocol_version, mounted_hostname, mounted_nfs_port,
+ &fhpos, (int) (np->nn->handle.size * 2),
+ 'X', /* filled below */
+ read_size, write_size);
+ }
+
+ /* We return the file size, so make sure we have it up to date now. */
+ err = netfs_validate_stat (np, cred);
+ if (err)
+ return err;
+
+ /* Format the name, and then do it again if the buffer was too short. */
+ name_len = fmt (*data_len);
+ if (name_len < 0)
+ return errno;
+ ++name_len; /* Include the terminating null. */
+ if (name_len <= *data_len)
+ *data_len = name_len;
+ else
+ {
+ *data = mmap (0, name_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ return errno;
+ *data_len = fmt (name_len) + 1;
+ assert (*data_len == name_len);
+ }
+
+ /* Now fill in the file handle data in hexadecimal. */
+ {
+ static const char hexdigits[] = "0123456789abcdef";
+ size_t i;
+ for (i = 0; i < np->nn->handle.size; ++i)
+ {
+ (*data)[fhpos++] = hexdigits[(uint8_t)np->nn->handle.data[i] >> 4];
+ (*data)[fhpos++] = hexdigits[(uint8_t)np->nn->handle.data[i] & 0xf];
+ }
+ }
+
+ /* Now fill in the rest of the canonical-form storage-info data, which
+ just describes a single run of the file's size, a block-size of one
+ byte, and our URL as the name for the network store type. */
+
+ *num_ports = 0;
+ *ports_type = MACH_MSG_TYPE_COPY_SEND;
+
+ assert (*num_offsets >= 2); /* mig always gives us some */
+ *num_offsets = 2;
+ (*offsets)[0] = 0;
+ (*offsets)[1] = np->nn_stat.st_size;
+
+ assert (*num_ints >= 6); /* mig always gives us some */
+ *num_ints = 1;
+ (*ints)[0] = STORAGE_NETWORK;
+ (*ints)[1] = 0; /* XXX readonly if we supported it */
+ (*ints)[2] = 1; /* block size */
+ (*ints)[3] = 1; /* 1 run in offsets list */
+ (*ints)[4] = name_len;
+ (*ints)[5] = 0; /* misc len */
+
+ return 0;
+}
diff --git a/nfsd/Makefile b/nfsd/Makefile
index 4460b4ba..2c05b7ed 100644
--- a/nfsd/Makefile
+++ b/nfsd/Makefile
@@ -26,9 +26,9 @@ OBJS = $(subst .c,.o,$(SRCS))
LCLHDRS = nfsd.h
target = nfsd
installationdir = $(sbindir)
+HURDLIBS=threads shouldbeinlibc
include ../Makeconf
-CPPFLAGS += -DLOCALSTATEDIR=$(localstatedir)
+CPPFLAGS += -DLOCALSTATEDIR=\"$(localstatedir)\"
-nfsd: ../libthreads/libthreads.a ../libshouldbeinlibc/libshouldbeinlibc.a \ No newline at end of file
diff --git a/nfsd/cache.c b/nfsd/cache.c
index 745a7c8e..7b96dbc2 100644
--- a/nfsd/cache.c
+++ b/nfsd/cache.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/* cache.c - Cache operations for the nfs daemon.
+ Copyright (C) 1996,98,99,2000,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,9 +20,12 @@
#include <string.h>
+#include <sys/mman.h>
#include <hurd/fsys.h>
#include <assert.h>
#include <string.h>
+#include <hurd/io.h>
+#include <hurd/auth.h>
#include "nfsd.h"
@@ -31,7 +34,6 @@
#define malloc spoogie_woogie /* ugh^2. */
#include <rpc/types.h>
#include <rpc/auth.h>
-#include <rpc/auth_unix.h>
#undef malloc
#define IDHASH_TABLE_SIZE 1024
@@ -44,9 +46,9 @@ spin_lock_t idhashlock = SPIN_LOCK_INITIALIZER;
static int nfreeids;
static int leastidlastuse;
-/* Compare I against the specified set of users/groups. */
+/* Compare I against the specified set of users/groups. */
/* Use of int in decl of UIDS and GIDS is correct here; that's
- the NFS type because they come in in known 32 bit slots. */
+ the NFS type because they come in in known 32 bit slots. */
static int
idspec_compare (struct idspec *i, int nuids, int ngids,
int *uids, int *gids)
@@ -56,20 +58,20 @@ idspec_compare (struct idspec *i, int nuids, int ngids,
return 0;
assert (sizeof (int) == sizeof (uid_t));
-
+
if (bcmp (i->uids, uids, nuids * sizeof (uid_t))
|| bcmp (i->gids, gids, ngids * sizeof (gid_t)))
return 0;
-
+
return 1;
}
-/* Compute a hash value for a given user spec */
+/* Compute a hash value for a given user spec. */
static int
idspec_hash (int nuids, int ngids, int *uids, int *gids)
{
int hash, n;
-
+
hash = nuids + ngids;
for (n = 0; n < ngids; n++)
hash += gids[n];
@@ -79,7 +81,7 @@ idspec_hash (int nuids, int ngids, int *uids, int *gids)
return hash;
}
-/* Lookup a user spec in the hash table and allocate a reference */
+/* Lookup a user spec in the hash table and allocate a reference. */
static struct idspec *
idspec_lookup (int nuids, int ngids, int *uids, int *gids)
{
@@ -98,15 +100,15 @@ idspec_lookup (int nuids, int ngids, int *uids, int *gids)
spin_unlock (&idhashlock);
return i;
}
-
+
assert (sizeof (uid_t) == sizeof (int));
i = malloc (sizeof (struct idspec));
i->nuids = nuids;
i->ngids = ngids;
i->uids = malloc (nuids * sizeof (uid_t));
i->gids = malloc (ngids * sizeof (gid_t));
- bcopy (uids, i->uids, nuids * sizeof (uid_t));
- bcopy (gids, i->gids, ngids * sizeof (gid_t));
+ memcpy (i->uids, uids, nuids * sizeof (uid_t));
+ memcpy (i->gids, gids, ngids * sizeof (gid_t));
i->references = 1;
i->next = idhashtable[hash];
@@ -129,42 +131,53 @@ process_cred (int *p, struct idspec **credp)
int ngids;
int firstgid;
int i;
-
- type = ntohl (*p++);
+
+ type = ntohl (*p);
+ p++;
if (type != AUTH_UNIX)
{
- int size = ntohl (*p++);
+ int size = ntohl (*p);
+ p++;
*credp = idspec_lookup (0, 0, 0, 0);
- return p + INTSIZE (size);
+ p += INTSIZE (size);
+ }
+ else
+ {
+ p++; /* Skip size. */
+ p++; /* Skip seconds. */
+ len = ntohl (*p);
+ p++;
+ p += INTSIZE (len); /* Skip hostname. */
+
+ uid = p++; /* Remember location of uid. */
+ *uid = ntohl (*uid);
+
+ firstgid = *(p++); /* Remember first gid. */
+ gids = p; /* Here is where the array will start. */
+ ngids = ntohl (*p);
+ p++;
+
+ /* Now swap the first gid to be the first element of the
+ array. */
+ *gids = firstgid;
+ ngids++; /* And count it. */
+
+ /* And byteswap the gids. */
+ for (i = 0; i < ngids; i++)
+ gids[i] = ntohl (gids[i]);
+
+ p += ngids - 1;
+
+ *credp = idspec_lookup (1, ngids, uid, gids);
}
-
- p++; /* skip size */
- p++; /* skip seconds */
- len = ntohl (*p++);
- p += INTSIZE (len); /* skip hostname */
-
- uid = p++; /* remember loc of uid */
- *uid = ntohl (*uid);
-
- firstgid = *p++; /* remember first gid */
- gids = p; /* here's where the array will start */
- ngids = ntohl (*p++);
-
- /* Now swap the first gid to be the first element of the array */
- *gids = firstgid;
- ngids++; /* and count it */
-
- /* And byteswap the gids */
- for (i = 1; i < ngids; i++)
- gids[i] = ntohl (gids[i]);
-
- /* Next is the verf field; skip it entirely */
- p++; /* skip id */
- len = htonl (*p++);
+
+ /* Next is the verf field; skip it entirely. */
+ p++; /* Skip ID. */
+ len = htonl (*p);
+ p++;
p += INTSIZE (len);
-
- *credp = idspec_lookup (1, ngids, uid, gids);
+
return p;
}
@@ -195,32 +208,43 @@ cred_ref (struct idspec *i)
void
scan_creds ()
{
- struct idspec *i;
int n;
int newleast = mapped_time->seconds;
spin_lock (&idhashlock);
+
if (mapped_time->seconds - leastidlastuse > ID_KEEP_TIMEOUT)
- for (n = 0; n < IDHASH_TABLE_SIZE && nfreeids; n++)
- for (i = idhashtable[n]; i && nfreeids; i = i->next)
- if (!i->references
- && mapped_time->seconds - i->lastuse > ID_KEEP_TIMEOUT)
- {
- nfreeids--;
- *i->prevp = i->next;
- if (i->next)
- i->next->prevp = i->prevp;
- free (i->uids);
- free (i->gids);
- free (i);
- }
- else
- if (!i->references && newleast > i->lastuse)
- newleast = i->lastuse;
-
- /* If we didn't bail early, then this is valid */
- if (nfreeids)
- leastidlastuse = newleast;
+ {
+ for (n = 0; n < IDHASH_TABLE_SIZE && nfreeids; n++)
+ {
+ struct idspec *i = idhashtable[n];
+
+ while (i && nfreeids)
+ {
+ struct idspec *next_i = i->next;
+
+ if (!i->references
+ && mapped_time->seconds - i->lastuse > ID_KEEP_TIMEOUT)
+ {
+ nfreeids--;
+ *i->prevp = i->next;
+ if (i->next)
+ i->next->prevp = i->prevp;
+ free (i->uids);
+ free (i->gids);
+ free (i);
+ }
+ else if (!i->references && newleast > i->lastuse)
+ newleast = i->lastuse;
+
+ i = next_i;
+ }
+ }
+
+ /* If we didn't bail early, then this is valid. */
+ if (nfreeids)
+ leastidlastuse = newleast;
+ }
spin_unlock (&idhashlock);
}
@@ -235,11 +259,11 @@ static int
fh_hash (char *fhandle, struct idspec *i)
{
int hash = 0, n;
-
- for (n = 0; n < NFS_FHSIZE; n++)
+
+ for (n = 0; n < NFS2_FHSIZE; n++)
hash += fhandle[n];
- hash += (int) i >> 6;
- return hash;
+ hash += (intptr_t) i >> 6;
+ return hash % FHHASH_TABLE_SIZE;
}
int *
@@ -249,35 +273,35 @@ lookup_cache_handle (int *p, struct cache_handle **cp, struct idspec *i)
struct cache_handle *c;
fsys_t fsys;
file_t port;
-
+
hash = fh_hash ((char *)p, i);
mutex_lock (&fhhashlock);
for (c = fhhashtable[hash]; c; c = c->next)
- if (c->ids == i && ! bcmp (c->handle, p, NFS_FHSIZE))
+ if (c->ids == i && ! bcmp (c->handle, p, NFS2_FHSIZE))
{
if (c->references == 0)
nfreefh--;
c->references++;
mutex_unlock (&fhhashlock);
*cp = c;
- return p + NFS_FHSIZE / sizeof (int);
+ return p + NFS2_FHSIZE / sizeof (int);
}
-
- /* Not found */
-
- /* First four bytes are our internal table of filesystems */
+
+ /* Not found. */
+
+ /* First four bytes are our internal table of filesystems. */
fsys = lookup_filesystem (*p);
if (fsys == MACH_PORT_NULL
|| fsys_getfile (fsys, i->uids, i->nuids, i->gids, i->ngids,
- (char *)(p + 1), NFS_FHSIZE - sizeof (int), &port))
+ (char *)(p + 1), NFS2_FHSIZE - sizeof (int), &port))
{
mutex_unlock (&fhhashlock);
*cp = 0;
- return p + NFS_FHSIZE / sizeof (int);
+ return p + NFS2_FHSIZE / sizeof (int);
}
-
+
c = malloc (sizeof (struct cache_handle));
- bcopy (p, c->handle, NFS_FHSIZE);
+ memcpy (c->handle, p, NFS2_FHSIZE);
cred_ref (i);
c->ids = i;
c->port = port;
@@ -288,10 +312,10 @@ lookup_cache_handle (int *p, struct cache_handle **cp, struct idspec *i)
c->next->prevp = &c->next;
c->prevp = &fhhashtable[hash];
fhhashtable[hash] = c;
-
+
mutex_unlock (&fhhashlock);
*cp = c;
- return p + NFS_FHSIZE / sizeof (int);
+ return p + NFS2_FHSIZE / sizeof (int);
}
void
@@ -309,91 +333,131 @@ cache_handle_rele (struct cache_handle *c)
mutex_unlock (&fhhashlock);
}
-void
+void
scan_fhs ()
{
- struct cache_handle *c;
int n;
int newleast = mapped_time->seconds;
-
+
mutex_lock (&fhhashlock);
+
if (mapped_time->seconds - leastfhlastuse > FH_KEEP_TIMEOUT)
- for (n = 0; n < FHHASH_TABLE_SIZE && nfreefh; n++)
- for (c = fhhashtable[n]; c && nfreefh; c = c->next)
- if (!c->references
- && mapped_time->seconds - c->lastuse > FH_KEEP_TIMEOUT)
- {
- nfreefh--;
- *c->prevp = c->next;
- if (c->next)
- c->next->prevp = c->prevp;
- cred_rele (c->ids);
- mach_port_deallocate (mach_task_self (), c->port);
- free (c);
- }
- else
- if (!c->references && newleast > c->lastuse)
- newleast = c->lastuse;
-
- /* If we didn't bail early, then this is valid. */
- if (nfreefh)
- leastfhlastuse = newleast;
+ {
+ for (n = 0; n < FHHASH_TABLE_SIZE && nfreefh; n++)
+ {
+ struct cache_handle *c = fhhashtable[n];
+
+ while (c && nfreefh)
+ {
+ struct cache_handle *next_c = c->next;
+
+ if (!c->references
+ && mapped_time->seconds - c->lastuse > FH_KEEP_TIMEOUT)
+ {
+ nfreefh--;
+ *c->prevp = c->next;
+ if (c->next)
+ c->next->prevp = c->prevp;
+ cred_rele (c->ids);
+ mach_port_deallocate (mach_task_self (), c->port);
+ free (c);
+ }
+ else if (!c->references && newleast > c->lastuse)
+ newleast = c->lastuse;
+
+ c = next_c;
+ }
+ }
+
+ /* If we didn't bail early, then this is valid. */
+ if (nfreefh)
+ leastfhlastuse = newleast;
+ }
mutex_unlock (&fhhashlock);
}
struct cache_handle *
-create_cached_handle (int fs, struct cache_handle *credc, file_t newport)
+create_cached_handle (int fs, struct cache_handle *credc, file_t userport)
{
- char fhandle[NFS_FHSIZE];
+ char fhandle[NFS2_FHSIZE];
error_t err;
struct cache_handle *c;
int hash;
char *bp = fhandle + sizeof (int);
- size_t handlelen = NFS_FHSIZE - sizeof (int);
+ size_t handlelen = NFS2_FHSIZE - sizeof (int);
+ mach_port_t newport, ref;
+
+ /* Authenticate USERPORT so that we can call file_getfh on it. */
+ ref = mach_reply_port ();
+ /* MAKE_SEND is safe becaue we destroy REF ourselves. */
+ if (io_reauthenticate (userport, ref, MACH_MSG_TYPE_MAKE_SEND)
+ || auth_user_authenticate (authserver, ref, MACH_MSG_TYPE_MAKE_SEND,
+ &newport))
+ {
+ /* Reauthentication has failed, but maybe the filesystem will let
+ us call file_getfh anyway. */
+ newport = userport;
+ }
+ else
+ mach_port_deallocate (mach_task_self (), userport);
+ mach_port_destroy (mach_task_self (), ref);
+ /* Fetch the file handle. */
*(int *)fhandle = fs;
err = file_getfh (newport, &bp, &handlelen);
- if (err || handlelen != NFS_FHSIZE - sizeof (int))
- {
- mach_port_deallocate (mach_task_self (), newport);
- return 0;
- }
+ mach_port_deallocate (mach_task_self (), newport);
+ if (err || handlelen != NFS2_FHSIZE - sizeof (int))
+ return 0;
if (bp != fhandle + sizeof (int))
{
- bcopy (bp, fhandle + sizeof (int), NFS_FHSIZE - sizeof (int));
- vm_deallocate (mach_task_self (), (vm_address_t) bp, handlelen);
+ memcpy (fhandle + sizeof (int), bp, NFS2_FHSIZE - sizeof (int));
+ munmap (bp, handlelen);
}
-
+
+ /* Cache it. */
hash = fh_hash (fhandle, credc->ids);
mutex_lock (&fhhashlock);
for (c = fhhashtable[hash]; c; c = c->next)
- if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS_FHSIZE))
+ if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS2_FHSIZE))
{
- /* Return this one */
+ /* Return this one. */
if (c->references == 0)
nfreefh--;
c->references++;
mutex_unlock (&fhhashlock);
- mach_port_deallocate (mach_task_self (), newport);
return c;
}
-
- /* Create it anew */
+
+ /* Always call fsys_getfile so that we don't depend on the
+ particular open modes of the port passed in. */
+
+ err = fsys_getfile (lookup_filesystem (fs),
+ credc->ids->uids, credc->ids->nuids,
+ credc->ids->gids, credc->ids->ngids,
+ fhandle + sizeof (int), NFS2_FHSIZE - sizeof (int),
+ &newport);
+ if (err)
+ {
+ mutex_unlock (&fhhashlock);
+ return 0;
+ }
+
+ /* Create it anew. */
c = malloc (sizeof (struct cache_handle));
- bcopy (fhandle, c->handle, NFS_FHSIZE);
+ memcpy (c->handle, fhandle, NFS2_FHSIZE);
cred_ref (credc->ids);
c->ids = credc->ids;
c->port = newport;
c->references = 1;
-
- /* And add it to the hash table */
+
+ /* And add it to the hash table. */
c->next = fhhashtable[hash];
if (c->next)
c->next->prevp = &c->next;
c->prevp = &fhhashtable[hash];
fhhashtable[hash] = c;
mutex_unlock (&fhhashlock);
-
+
return c;
}
@@ -406,19 +470,19 @@ static int leastreplylastuse;
/* Check the list of cached replies to see if this is a replay of a
previous transaction; if so, return the cache record. Otherwise,
- create a new cache record. */
+ create a new cache record. */
struct cached_reply *
-check_cached_replies (int xid,
+check_cached_replies (int xid,
struct sockaddr_in *sender)
{
struct cached_reply *cr;
int hash;
- hash = xid % REPLYHASH_TABLE_SIZE;
-
+ hash = abs(xid % REPLYHASH_TABLE_SIZE);
+
spin_lock (&replycachelock);
for (cr = replyhashtable[hash]; cr; cr = cr->next)
- if (cr->xid == xid
+ if (cr->xid == xid
&& !bcmp (sender, &cr->source, sizeof (struct sockaddr_in)))
{
cr->references++;
@@ -432,9 +496,10 @@ check_cached_replies (int xid,
cr = malloc (sizeof (struct cached_reply));
mutex_init (&cr->lock);
mutex_lock (&cr->lock);
- bcopy (sender, &cr->source, sizeof (struct sockaddr_in));
+ memcpy (&cr->source, sender, sizeof (struct sockaddr_in));
cr->xid = xid;
cr->data = 0;
+ cr->references = 1;
cr->next = replyhashtable[hash];
if (replyhashtable[hash])
@@ -447,7 +512,7 @@ check_cached_replies (int xid,
}
/* A cached reply returned by check_cached_replies is now no longer
- needed by its caller. */
+ needed by its caller. */
void
release_cached_reply (struct cached_reply *cr)
{
@@ -467,30 +532,42 @@ release_cached_reply (struct cached_reply *cr)
void
scan_replies ()
{
- struct cached_reply *cr;
int n;
int newleast = mapped_time->seconds;
-
+
spin_lock (&replycachelock);
+
if (mapped_time->seconds - leastreplylastuse > REPLY_KEEP_TIMEOUT)
- for (n = 0; n < REPLYHASH_TABLE_SIZE && nfreereplies; n++)
- for (cr = replyhashtable[n]; cr && nfreereplies; cr = cr->next)
- if (!cr->references
- && mapped_time->seconds - cr->lastuse > REPLY_KEEP_TIMEOUT)
- {
- nfreereplies--;
- *cr->prevp = cr->next;
- if (cr->next)
- cr->next->prevp = cr->prevp;
- if (cr->data)
- free (cr->data);
- }
- else
- if (!cr->references && newleast > cr->lastuse)
- newleast = cr->lastuse;
-
- /* If we didn't bail early, then this is valid */
- if (nfreereplies)
- leastreplylastuse = newleast;
+ {
+ for (n = 0; n < REPLYHASH_TABLE_SIZE && nfreereplies; n++)
+ {
+ struct cached_reply *cr = replyhashtable[n];
+
+ while (cr && nfreereplies)
+ {
+ struct cached_reply *next_cr = cr->next;
+
+ if (!cr->references
+ && mapped_time->seconds - cr->lastuse > REPLY_KEEP_TIMEOUT)
+ {
+ nfreereplies--;
+ *cr->prevp = cr->next;
+ if (cr->next)
+ cr->next->prevp = cr->prevp;
+ if (cr->data)
+ free (cr->data);
+ free (cr);
+ }
+ else if (!cr->references && newleast > cr->lastuse)
+ newleast = cr->lastuse;
+
+ cr = next_cr;
+ }
+ }
+
+ /* If we didn't bail early, then this is valid. */
+ if (nfreereplies)
+ leastreplylastuse = newleast;
+ }
spin_unlock (&replycachelock);
}
diff --git a/nfsd/fsys.c b/nfsd/fsys.c
index d3c50220..7b15d150 100644
--- a/nfsd/fsys.c
+++ b/nfsd/fsys.c
@@ -1,5 +1,5 @@
/* Filesystem management for NFS server
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,13 +20,14 @@
#include <stdio.h>
#include <errno.h>
+#include <error.h>
#include <hurd.h>
#include <fcntl.h>
#include <string.h>
#include "nfsd.h"
-struct fsys_spec
+struct fsys_spec
{
fsys_t fsys;
char *name;
@@ -49,18 +50,23 @@ init_filesystems (void)
int line;
file_t root;
static FILE *index_file;
+ int i;
fsystable = (struct fsys_spec *) malloc ((fsystablesize = 10)
* sizeof (struct fsys_spec));
+ for (i = 0; i < fsystablesize; i++)
+ {
+ fsystable[i].fsys = MACH_PORT_NULL;
+ fsystable[i].name = 0;
+ }
if (!index_file_name)
return;
-
+
index_file = fopen (index_file_name, "r");
if (!index_file)
{
- fprintf (stderr, "%s: Cannot open `%s': %s\n",
- program_invocation_name, index_file_name, strerror (errno));
+ error (0, errno, "Cannot open `%s'", index_file_name);
return;
}
@@ -72,33 +78,39 @@ init_filesystems (void)
fclose (index_file);
return;
}
-
+
if (nitems != 2)
{
- fprintf (stderr, "%s:%s:%d Bad syntax\n",
- program_invocation_name, index_file_name, line);
+ error (0, 0, "%s:%d Bad syntax", index_file_name, line);
continue;
}
root = file_name_lookup (name, 0, 0);
- if (!root)
+ if (root == MACH_PORT_NULL)
{
- fprintf (stderr, "%s:%s:%d Filesystem `%s': %s\n",
- program_invocation_name, index_file_name, line,
- name, strerror (errno));
+ error (0, errno, "%s:%d Filesystem `%s'",
+ index_file_name, line, name);
free (name);
continue;
}
if (index >= fsystablesize)
- fsystable = (struct fsys_spec *) realloc (fsystable,
- (fsystablesize = index * 2)
- * sizeof (struct fsys_spec));
- if (index > nfsys)
- nfsys = index;
-
+ {
+ fsystable = (struct fsys_spec *)
+ realloc (fsystable, index * 2 * sizeof (struct fsys_spec));
+ for (i = fsystablesize; i < index * 2; i++)
+ {
+ fsystable[i].fsys = MACH_PORT_NULL;
+ fsystable[i].name = 0;
+ }
+ fsystablesize = index * 2;
+ }
+
+ if (index + 1 > nfsys)
+ nfsys = index + 1;
+
fsystable[index].name = name;
- file_getcontrol (root, &fsystable[nfsys].fsys);
+ file_getcontrol (root, &fsystable[index].fsys);
mach_port_deallocate (mach_task_self (), root);
}
}
@@ -109,46 +121,44 @@ write_filesystems (void)
{
file_t newindex;
FILE *f;
+ error_t err;
int i;
if (!index_file_name)
return;
-
+
if (index_file_dir == MACH_PORT_NULL)
{
index_file_dir = file_name_split (index_file_name, &index_file_compname);
if (index_file_dir == MACH_PORT_NULL)
{
- fprintf (stderr, "%s: `%s': %s\n",
- program_invocation_name, index_file_name, strerror (errno));
+ error (0, errno, "`%s'", index_file_name);
index_file_name = 0;
return;
}
}
/* Create an anonymous file in the same directory */
- errno = dir_mkfile (index_file_dir, O_WRONLY, 0666, &newindex);
- if (errno)
+ err = dir_mkfile (index_file_dir, O_WRONLY, 0666, &newindex);
+ if (err)
{
- fprintf (stderr, "%s: `%s': %s\n",
- program_invocation_name, index_file_name, strerror (errno));
+ error (0, err, "`%s'", index_file_name);
index_file_name = 0;
mach_port_deallocate (mach_task_self (), index_file_dir);
index_file_dir = MACH_PORT_NULL;
return;
}
-
+
f = fopenport (newindex, "w");
-
+
for (i = 0; i < nfsys; i++)
if (fsystable[i].name)
fprintf (f, "%d %s\n", i, fsystable[i].name);
/* Link it in */
- errno = dir_link (index_file_dir, newindex, index_file_compname, 0);
- if (errno)
- fprintf (stderr, "%s: `%s': %s\n",
- program_invocation_name, index_file_name, strerror (errno));
+ err = dir_link (index_file_dir, newindex, index_file_compname, 0);
+ if (err)
+ error (0, err, "`%s'", index_file_name);
fflush (f);
file_sync (newindex, 1, 0);
fclose (f);
@@ -174,11 +184,19 @@ enter_filesystem (char *name, file_t root)
for (i = 0; i < nfsys; i++)
if (fsystable[i].name && !strcmp (fsystable[i].name, name))
return i;
-
+
if (nfsys == fsystablesize)
- fsystable = (struct fsys_spec *) realloc (fsystable,
- (fsystablesize *= 2)
- * sizeof (struct fsys_spec));
+ {
+ fsystable = (struct fsys_spec *) realloc (fsystable,
+ (fsystablesize * 2)
+ * sizeof (struct fsys_spec));
+ for (i = fsystablesize; i < fsystablesize * 2; i++)
+ {
+ fsystable[i].fsys = MACH_PORT_NULL;
+ fsystable[i].name = 0;
+ }
+ fsystablesize *= 2;
+ }
fsystable[nfsys].name = malloc (strlen (name) + 1);
strcpy (fsystable[nfsys].name, name);
@@ -189,4 +207,3 @@ enter_filesystem (char *name, file_t root)
return nfsys - 1;
}
-
diff --git a/nfsd/loop.c b/nfsd/loop.c
index 3520e1da..bfec5e5a 100644
--- a/nfsd/loop.c
+++ b/nfsd/loop.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/* loop.c - Main server loop for nfs server.
+ Copyright (C) 1996,98,2002,2006 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -24,7 +24,7 @@
#include "nfsd.h"
#include <rpc/pmap_prot.h>
-#include "../nfs/rpcsvc/mount.h"
+#include "../nfs/mount.h"
#undef TRUE
#undef FALSE
@@ -36,7 +36,7 @@
#undef malloc
void
-server_loop ()
+server_loop (int fd)
{
char buf[MAXIOSIZE];
int xid;
@@ -52,182 +52,172 @@ server_loop ()
struct idspec *cred;
struct cache_handle *c, fakec;
error_t err;
- size_t addrlen;
- fd_set readfds;
- int maxfd;
- int i;
- int *errloc;
-
- bzero (&fakec, sizeof (struct cache_handle));
-
- if (main_udp_socket > pmap_udp_socket)
- maxfd = main_udp_socket;
- else
- maxfd = pmap_udp_socket;
-
+ socklen_t addrlen;
+ int cc;
+
+ memset (&fakec, 0, sizeof (struct cache_handle));
+
for (;;)
{
- FD_ZERO (&readfds);
- FD_SET (main_udp_socket, &readfds);
- FD_SET (pmap_udp_socket, &readfds);
- select (maxfd, &readfds, 0, 0, 0);
-
- for (i = main_udp_socket;
- i != -1;
- i = (i == main_udp_socket ? pmap_udp_socket : -1))
+ p = (int *) buf;
+ proc = 0;
+ addrlen = sizeof (struct sockaddr_in);
+ cc = recvfrom (fd, buf, MAXIOSIZE, 0, &sender, &addrlen);
+ if (cc == -1)
+ continue; /* Ignore errors. */
+ xid = *(p++);
+
+ /* Ignore things that aren't proper RPCs. */
+ if (ntohl (*p) != CALL)
+ continue;
+ p++;
+
+ cr = check_cached_replies (xid, &sender);
+ if (cr->data)
+ /* This transacation has already completed. */
+ goto repost_reply;
+
+ r = (int *) (rbuf = malloc (MAXIOSIZE));
+
+ if (ntohl (*p) != RPC_MSG_VERSION)
{
- if (!FD_ISSET (i, &readfds))
- continue;
-
- p = (int *) buf;
- proc = 0;
- addrlen = sizeof (struct sockaddr_in);
- recvfrom (i, buf, MAXIOSIZE, 0, &sender, &addrlen);
- xid = *p++;
-
- /* Ignore things that aren't proper RPCs. */
- if (ntohl (*p++) != CALL)
- continue;
-
- cr = check_cached_replies (xid, &sender);
- if (cr->data)
- /* This transacation has already completed */
- goto repost_reply;
-
- r = (int *) rbuf = malloc (MAXIOSIZE);
-
- if (ntohl (*p++) != RPC_MSG_VERSION)
- {
- /* Reject RPC */
- *r++ = xid;
- *r++ = htonl (REPLY);
- *r++ = htonl (MSG_DENIED);
- *r++ = htonl (RPC_MISMATCH);
- *r++ = htonl (RPC_MSG_VERSION);
- *r++ = htonl (RPC_MSG_VERSION);
- goto send_reply;
- }
-
- program = ntohl (*p++);
- switch (program)
- {
- case MOUNTPROG:
- version = MOUNTVERS;
- table = &mounttable;
- break;
-
- case NFS_PROGRAM:
- version = NFS_VERSION;
- table = &nfstable;
- break;
-
- case PMAPPROG:
- version = PMAPVERS;
- table = &pmaptable;
- break;
-
- default:
- /* Program unavailable */
- *r++ = xid;
- *r++ = htonl (REPLY);
- *r++ = htonl (MSG_ACCEPTED);
- *r++ = htonl (AUTH_NULL);
- *r++ = htonl (0);
- *r++ = htonl (PROG_UNAVAIL);
- goto send_reply;
- }
-
- if (ntohl (*p++) != version)
- {
- /* Program mismatch */
- *r++ = xid;
- *r++ = htonl (REPLY);
- *r++ = htonl (MSG_ACCEPTED);
- *r++ = htonl (AUTH_NULL);
- *r++ = htonl (0);
- *r++ = htonl (PROG_MISMATCH);
- *r++ = htonl (version);
- *r++ = htonl (version);
- goto send_reply;
- }
-
- procedure = htonl (*p++);
- if (procedure < table->min
- || procedure > table->max
- || table->procs[procedure - table->min].func == 0)
- {
- /* Procedure unavailable */
- *r++ = xid;
- *r++ = htonl (REPLY);
- *r++ = htonl (MSG_ACCEPTED);
- *r++ = htonl (AUTH_NULL);
- *r++ = htonl (0);
- *r++ = htonl (PROC_UNAVAIL);
- *r++ = htonl (table->min);
- *r++ = htonl (table->max);
- goto send_reply;
- }
- proc = &table->procs[procedure - table->min];
-
- p = process_cred (p, &cred); /* auth */
- p = skip_cred (p); /* verf */
-
- if (proc->need_handle)
- p = lookup_cache_handle (p, &c, cred);
- else
- {
- fakec.ids = cred;
- c = &fakec;
- }
-
- if (proc->alloc_reply)
- {
- size_t amt;
- amt = (*proc->alloc_reply) (p) + 256;
- if (amt > MAXIOSIZE)
- {
- free (rbuf);
- r = (int *) rbuf = malloc (amt);
- }
- }
+ /* Reject RPC. */
+ *(r++) = xid;
+ *(r++) = htonl (REPLY);
+ *(r++) = htonl (MSG_DENIED);
+ *(r++) = htonl (RPC_MISMATCH);
+ *(r++) = htonl (RPC_MSG_VERSION);
+ *(r++) = htonl (RPC_MSG_VERSION);
+ goto send_reply;
+ }
+ p++;
+
+ program = ntohl (*p);
+ p++;
+ switch (program)
+ {
+ case MOUNTPROG:
+ version = MOUNTVERS;
+ table = &mounttable;
+ break;
+
+ case NFS_PROGRAM:
+ version = NFS_VERSION;
+ table = &nfs2table;
+ break;
+
+ case PMAPPROG:
+ version = PMAPVERS;
+ table = &pmaptable;
+ break;
+
+ default:
+ /* Program unavailable. */
+ *(r++) = xid;
+ *(r++) = htonl (REPLY);
+ *(r++) = htonl (MSG_ACCEPTED);
+ *(r++) = htonl (AUTH_NULL);
+ *(r++) = htonl (0);
+ *(r++) = htonl (PROG_UNAVAIL);
+ goto send_reply;
+ }
- /* Fill in beginning of reply */
- *r++ = xid;
- *r++ = htonl (REPLY);
- *r++ = htonl (MSG_ACCEPTED);
- *r++ = htonl (AUTH_NULL);
- *r++ = htonl (0);
- *r++ = htonl (SUCCESS);
- if (proc->process_error)
+ if (ntohl (*p) != version)
+ {
+ /* Program mismatch. */
+ *(r++) = xid;
+ *(r++) = htonl (REPLY);
+ *(r++) = htonl (MSG_ACCEPTED);
+ *(r++) = htonl (AUTH_NULL);
+ *(r++) = htonl (0);
+ *(r++) = htonl (PROG_MISMATCH);
+ *(r++) = htonl (version);
+ *(r++) = htonl (version);
+ goto send_reply;
+ }
+ p++;
+
+ procedure = htonl (*p);
+ p++;
+ if (procedure < table->min
+ || procedure > table->max
+ || table->procs[procedure - table->min].func == 0)
+ {
+ /* Procedure unavailable. */
+ *(r++) = xid;
+ *(r++) = htonl (REPLY);
+ *(r++) = htonl (MSG_ACCEPTED);
+ *(r++) = htonl (AUTH_NULL);
+ *(r++) = htonl (0);
+ *(r++) = htonl (PROC_UNAVAIL);
+ *(r++) = htonl (table->min);
+ *(r++) = htonl (table->max);
+ goto send_reply;
+ }
+ proc = &table->procs[procedure - table->min];
+
+ p = process_cred (p, &cred);
+
+ if (proc->need_handle)
+ p = lookup_cache_handle (p, &c, cred);
+ else
+ {
+ fakec.ids = cred;
+ c = &fakec;
+ }
+
+ if (proc->alloc_reply)
+ {
+ size_t amt;
+ amt = (*proc->alloc_reply) (p, version) + 256;
+ if (amt > MAXIOSIZE)
{
- /* Assume success for now and patch it later if necessary */
- errloc = r;
- *r++ = htonl (0);
+ free (rbuf);
+ r = (int *) (rbuf = malloc (amt));
}
+ }
+ /* Fill in beginning of reply. */
+ *(r++) = xid;
+ *(r++) = htonl (REPLY);
+ *(r++) = htonl (MSG_ACCEPTED);
+ *(r++) = htonl (AUTH_NULL);
+ *(r++) = htonl (0);
+ *(r++) = htonl (SUCCESS);
+ if (!proc->process_error)
+ /* The function does its own error processing, and we ignore
+ its return value. */
+ (void) (*proc->func) (c, p, &r, version);
+ else
+ {
if (c)
- err = (*proc->func) (c, p, &r);
- else
- err = ESTALE;
-
- if (proc->process_error && err)
{
- r = errloc;
- *r++ = htonl (nfs_error_trans (err));
+ /* Assume success for now and patch it later if necessary. */
+ int *errloc = r;
+ *(r++) = htonl (0);
+ /* Call processing function, its output after error code. */
+ err = (*proc->func) (c, p, &r, version);
+ if (err)
+ {
+ r = errloc; /* Back up, patch error code, discard rest. */
+ *(r++) = htonl (nfs_error_trans (err, version));
+ }
}
+ else
+ *(r++) = htonl (nfs_error_trans (ESTALE, version));
+ }
- cred_rele (cred);
- if (c != &fakec)
- cache_handle_rele (c);
+ cred_rele (cred);
+ if (c && c != &fakec)
+ cache_handle_rele (c);
- send_reply:
- cr->data = rbuf;
- cr->len = (char *)r - rbuf;
+ send_reply:
+ cr->data = rbuf;
+ cr->len = (char *)r - rbuf;
- repost_reply:
- sendto (i, cr->data, cr->len, 0,
- (struct sockaddr *)&sender, addrlen);
- release_cached_reply (cr);
- }
+ repost_reply:
+ sendto (fd, cr->data, cr->len, 0,
+ (struct sockaddr *) &sender, addrlen);
+ release_cached_reply (cr);
}
}
diff --git a/nfsd/main.c b/nfsd/main.c
index 69099361..ee071090 100644
--- a/nfsd/main.c
+++ b/nfsd/main.c
@@ -1,5 +1,5 @@
/* Main NFS server program
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -23,16 +23,20 @@
#include <unistd.h>
#include <rpc/pmap_prot.h>
#include <maptime.h>
+#include <hurd.h>
+#include <error.h>
int main_udp_socket, pmap_udp_socket;
struct sockaddr_in main_address, pmap_address;
-char *index_file_name;
+static char index_file[] = LOCALSTATEDIR "/state/misc/nfsd.index";
+char *index_file_name = index_file;
int
main (int argc, char **argv)
{
int nthreads;
-
+ int fail;
+
if (argc > 2)
{
fprintf (stderr, "%s [num-threads]\n", argv[0]);
@@ -44,9 +48,8 @@ main (int argc, char **argv)
nthreads = atoi (argv[1]);
if (!nthreads)
nthreads = 4;
-
- index_file_name = asprintf ("%s/state/misc/nfsd.index", LOCALSTATEDIR);
+ authserver = getauth ();
maptime_map (0, 0, &mapped_time);
main_address.sin_family = AF_INET;
@@ -58,16 +61,25 @@ main (int argc, char **argv)
main_udp_socket = socket (PF_INET, SOCK_DGRAM, 0);
pmap_udp_socket = socket (PF_INET, SOCK_DGRAM, 0);
- bind (main_udp_socket, (struct sockaddr *)&main_address,
- sizeof (struct sockaddr_in));
- bind (pmap_udp_socket, (struct sockaddr *)&pmap_address,
- sizeof (struct sockaddr_in));
+ fail = bind (main_udp_socket, (struct sockaddr *)&main_address,
+ sizeof (struct sockaddr_in));
+ if (fail)
+ error (1, errno, "Binding NFS socket");
+
+ fail = bind (pmap_udp_socket, (struct sockaddr *)&pmap_address,
+ sizeof (struct sockaddr_in));
+ if (fail)
+ error (1, errno, "Binding PMAP socket");
init_filesystems ();
+ cthread_detach (cthread_fork ((cthread_fn_t) server_loop,
+ (any_t)(intptr_t) pmap_udp_socket));
+
while (nthreads--)
- cthread_detach (cthread_fork ((cthread_fn_t) server_loop, 0));
-
+ cthread_detach (cthread_fork ((cthread_fn_t) server_loop,
+ (any_t)(intptr_t) main_udp_socket));
+
for (;;)
{
sleep (1);
diff --git a/nfsd/nfsd.h b/nfsd/nfsd.h
index 7b6f530d..e89a411b 100644
--- a/nfsd/nfsd.h
+++ b/nfsd/nfsd.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1996,98,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,14 +18,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-typedef int bool_t;
-
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <cthreads.h>
-#include "../nfs/rpcsvc/nfs_prot.h" /* XXX */
+#include <rpc/types.h>
+#include "../nfs/nfs-spec.h" /* XXX */
#include <hurd/fs.h>
/* These should be configuration options */
@@ -34,7 +33,7 @@ typedef int bool_t;
#define REPLY_KEEP_TIMEOUT 120 /* two minutes */
#define MAXIOSIZE 10240
-struct idspec
+struct idspec
{
struct idspec *next, **prevp;
int nuids, ngids;
@@ -46,7 +45,7 @@ struct idspec
struct cache_handle
{
struct cache_handle *next, **prevp;
- char handle[NFS_FHSIZE];
+ char handle[NFS2_FHSIZE];
struct idspec *ids;
file_t port;
time_t lastuse;
@@ -67,17 +66,17 @@ struct cached_reply
struct procedure
{
- error_t (*func) (struct cache_handle *, int *, int **);
- size_t (*alloc_reply) (int *);
+ error_t (*func) (struct cache_handle *, int *, int **, int);
+ size_t (*alloc_reply) (int *, int);
int need_handle;
int process_error;
};
-struct proctable
+struct proctable
{
int min;
int max;
- struct procedure procs[0];
+ struct procedure procs[];
};
volatile struct mapped_time_value *mapped_time;
@@ -92,6 +91,9 @@ extern struct sockaddr_in main_address, pmap_address;
/* Name of the file on disk containing the filesystem index table */
extern char *index_file_name;
+/* Our auth server */
+auth_t authserver;
+
/* cache.c */
int *process_cred (int *, struct idspec **);
@@ -107,15 +109,14 @@ void release_cached_reply (struct cached_reply *cr);
void scan_replies (void);
/* loop.c */
-void server_loop (void);
+void server_loop (int);
/* ops.c */
-extern struct proctable nfstable, mounttable, pmaptable;
+extern struct proctable nfs2table, mounttable, pmaptable;
/* xdr.c */
-int *skip_cred (int *);
-int nfs_error_trans (error_t);
-int *encode_fattr (int *, struct stat *);
+int nfs_error_trans (error_t, int);
+int *encode_fattr (int *, struct stat *, int version);
int *decode_name (int *, char **);
int *encode_fhandle (int *, char *);
int *encode_string (int *, char *);
diff --git a/nfsd/ops.c b/nfsd/ops.c
index 93c8373c..d503290e 100644
--- a/nfsd/ops.c
+++ b/nfsd/ops.c
@@ -1,5 +1,7 @@
-/* NFS daemon protocol operations
- Copyright (C) 1996 Free Software Foundation, Inc.
+/* ops.c NFS daemon protocol operations.
+
+ Copyright (C) 1996, 2001, 2002, 2007 Free Software Foundation, Inc.
+
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -24,15 +26,18 @@
#include <hurd/paths.h>
#include <hurd.h>
#include <dirent.h>
+#include <string.h>
+#include <sys/mman.h>
#include "nfsd.h"
-#include "../nfs/rpcsvc/mount.h" /* XXX */
+#include "../nfs/mount.h" /* XXX */
#include <rpc/pmap_prot.h>
static error_t
op_null (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
return 0;
}
@@ -40,14 +45,15 @@ op_null (struct cache_handle *c,
static error_t
op_getattr (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
struct stat st;
error_t err;
-
+
err = io_stat (c->port, &st);
if (!err)
- *reply = encode_fattr (*reply, &st);
+ *reply = encode_fattr (*reply, &st, version);
return err;
}
@@ -65,74 +71,89 @@ complete_setattr (mach_port_t port,
if (err)
return err;
- uid = ntohl (*p++);
- gid = ntohl (*p++);
- if ((uid != -1 && uid != st.st_uid)
- || (gid != -1 && gid != st.st_gid))
- {
- if (uid == -1)
- uid = st.st_uid;
- if (gid == -1)
- gid = st.st_gid;
- err = file_chown (port, uid, gid);
- if (err)
- return err;
- }
-
- size = ntohl (*p++);
+ uid = ntohl (*p);
+ p++;
+ gid = ntohl (*p);
+ p++;
+ if (uid == -1)
+ uid = st.st_uid;
+ if (gid == -1)
+ gid = st.st_gid;
+ if (uid != st.st_uid || gid != st.st_gid)
+ err = file_chown (port, uid, gid);
+ if (err)
+ return err;
+
+ size = ntohl (*p);
+ p++;
if (size != -1 && size != st.st_size)
err = file_set_size (port, size);
if (err)
return err;
-
- atime.seconds = ntohl (*p++);
- atime.microseconds = ntohl (*p++);
- mtime.seconds = ntohl (*p++);
- mtime.microseconds = ntohl (*p++);
+
+ atime.seconds = ntohl (*p);
+ p++;
+ atime.microseconds = ntohl (*p);
+ p++;
+ mtime.seconds = ntohl (*p);
+ p++;
+ mtime.microseconds = ntohl (*p);
+ p++;
+
if (atime.seconds != -1 && atime.microseconds == -1)
atime.microseconds = 0;
if (mtime.seconds != -1 && mtime.microseconds == -1)
mtime.microseconds = 0;
- if (atime.seconds != -1 || mtime.seconds != -1
- || atime.microseconds != -1 || mtime.microseconds != -1)
- {
- if (atime.seconds == -1)
- atime.seconds = st.st_atime;
- if (atime.microseconds == -1)
- atime.microseconds = st.st_atime_usec;
- if (mtime.seconds == -1)
- mtime.seconds = st.st_mtime;
- if (mtime.microseconds == -1)
- mtime.microseconds = st.st_mtime_usec;
- err = file_utimes (port, atime, mtime);
- if (err)
- return err;
- }
-
- return 0;
+
+ if (atime.seconds == -1)
+ atime.seconds = st.st_atim.tv_sec;
+ if (atime.microseconds == -1)
+ atime.microseconds = st.st_atim.tv_nsec / 1000;
+ if (mtime.seconds == -1)
+ mtime.seconds = st.st_mtim.tv_sec;
+ if (mtime.microseconds == -1)
+ mtime.microseconds = st.st_mtim.tv_nsec / 1000;
+
+ if (atime.seconds != st.st_atim.tv_sec
+ || atime.microseconds != st.st_atim.tv_nsec / 1000
+ || mtime.seconds != st.st_mtim.tv_sec
+ || mtime.microseconds != st.st_mtim.tv_nsec / 1000)
+ err = file_utimes (port, atime, mtime);
+
+ return err;
}
static error_t
op_setattr (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
error_t err = 0;
mode_t mode;
+ struct stat st;
- mode = ntohl (*p++);
+ mode = ntohl (*p);
+ p++;
if (mode != -1)
err = file_chmod (c->port, mode);
+
+ if (!err)
+ err = complete_setattr (c->port, p);
+ if (!err)
+ err = io_stat (c->port, &st);
if (err)
return err;
-
- return complete_setattr (c->port, p);
+
+ *reply = encode_fattr (*reply, &st, version);
+ return 0;
}
static error_t
op_lookup (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
error_t err;
char *name;
@@ -143,65 +164,76 @@ op_lookup (struct cache_handle *c,
struct stat st;
decode_name (p, &name);
-
+
err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry, retry_name,
&newport);
free (name);
- /* Block attempts to bounce out of this filesystem by any technique */
+ /* Block attempts to bounce out of this filesystem by any technique. */
if (!err
&& (do_retry != FS_RETRY_NORMAL
|| retry_name[0] != '\0'))
err = EACCES;
-
+
if (!err)
err = io_stat (newport, &st);
-
+
if (err)
return err;
-
+
newc = create_cached_handle (*(int *)c->handle, c, newport);
if (!newc)
return ESTALE;
*reply = encode_fhandle (*reply, newc->handle);
- *reply = encode_fattr (*reply, &st);
+ *reply = encode_fattr (*reply, &st, version);
return 0;
}
static error_t
op_readlink (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
char buf[2048], *transp = buf;
mach_msg_type_number_t len = sizeof (buf);
error_t err;
-
- /* Shamelessly copied from the libc readlink */
+
+ /* Shamelessly copied from the libc readlink. */
err = file_get_translator (c->port, &transp, &len);
if (err)
- return err;
-
+ {
+ if (transp != buf)
+ munmap (transp, len);
+ return err;
+ }
+
if (len < sizeof (_HURD_SYMLINK)
|| memcmp (transp, _HURD_SYMLINK, sizeof (_HURD_SYMLINK)))
return EINVAL;
-
+
transp += sizeof (_HURD_SYMLINK);
-
+
*reply = encode_string (*reply, transp);
+
+ if (transp != buf)
+ munmap (transp, len);
+
return 0;
}
static size_t
-count_read_buffersize (int *p)
+count_read_buffersize (int *p, int version)
{
- return ntohl (*++p); /* skip OFFSET, return COUNT */
+ p++; /* Skip OFFSET. */
+ return ntohl (*p); /* Return COUNT. */
}
static error_t
op_read (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
off_t offset;
size_t count;
@@ -210,26 +242,37 @@ op_read (struct cache_handle *c,
struct stat st;
error_t err;
- offset = ntohl (*p++);
- count = ntohl (*p++);
-
+ offset = ntohl (*p);
+ p++;
+ count = ntohl (*p);
+ p++;
+
err = io_read (c->port, &bp, &buflen, offset, count);
if (err)
- return err;
-
+ {
+ if (bp != buf)
+ munmap (bp, buflen);
+ return err;
+ }
+
err = io_stat (c->port, &st);
if (err)
return err;
-
- *reply = encode_fattr (*reply, &st);
+
+ *reply = encode_fattr (*reply, &st, version);
*reply = encode_data (*reply, bp, buflen);
+
+ if (bp != buf)
+ munmap (bp, buflen);
+
return 0;
}
static error_t
op_write (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
off_t offset;
size_t count;
@@ -239,11 +282,13 @@ op_write (struct cache_handle *c,
struct stat st;
p++;
- offset = ntohl (*p++);
+ offset = ntohl (*p);
+ p++;
+ p++;
+ count = ntohl (*p);
p++;
- count = ntohl (*p++);
bp = (char *) *reply;
-
+
while (count)
{
err = io_write (c->port, bp, count, offset, &amt);
@@ -255,20 +300,21 @@ op_write (struct cache_handle *c,
bp += amt;
offset += amt;
}
-
+
file_sync (c->port, 1, 0);
err = io_stat (c->port, &st);
if (err)
return err;
- *reply = encode_fattr (*reply, &st);
+ *reply = encode_fattr (*reply, &st, version);
return 0;
}
static error_t
op_create (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
error_t err;
char *name;
@@ -278,26 +324,51 @@ op_create (struct cache_handle *c,
struct cache_handle *newc;
struct stat st;
mode_t mode;
+ int statchanged = 0;
+ off_t size;
p = decode_name (p, &name);
- mode = ntohl (*p++);
-
- err = dir_lookup (c->port, name, O_NOTRANS | O_CREAT | O_EXCL, mode,
+ mode = ntohl (*p);
+ p++;
+
+ err = dir_lookup (c->port, name, O_NOTRANS | O_CREAT | O_TRUNC, mode,
&do_retry, retry_name, &newport);
if (!err
&& (do_retry != FS_RETRY_NORMAL
|| retry_name[0] != '\0'))
err = EACCES;
-
+
if (err)
return err;
- err = complete_setattr (newport, p);
if (!err)
err = io_stat (newport, &st);
+ if (err)
+ goto errout;
+
+ /* NetBSD ignores most of the setattr fields given; that's good enough
+ for me too. */
+
+ p++, p++; /* Skip uid and gid. */
+
+ size = ntohl (*p);
+ p++;
+ if (size != -1 && size != st.st_size)
+ {
+ err = file_set_size (newport, size);
+ statchanged = 1;
+ }
+ if (err)
+ goto errout;
+
+ /* Ignore times. */
+
+ if (statchanged)
+ err = io_stat (newport, &st);
if (err)
{
+ errout:
dir_unlink (c->port, name);
free (name);
return err;
@@ -307,41 +378,43 @@ op_create (struct cache_handle *c,
newc = create_cached_handle (*(int *)c->handle, c, newport);
if (!newc)
return ESTALE;
-
+
*reply = encode_fhandle (*reply, newc->handle);
- *reply = encode_fattr (*reply, &st);
+ *reply = encode_fattr (*reply, &st, version);
return 0;
}
static error_t
op_remove (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
error_t err;
char *name;
-
+
decode_name (p, &name);
-
+
err = dir_unlink (c->port, name);
free (name);
-
+
return 0;
}
static error_t
op_rename (struct cache_handle *fromc,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
struct cache_handle *toc;
char *fromname, *toname;
error_t err = 0;
-
+
p = decode_name (p, &fromname);
p = lookup_cache_handle (p, &toc, fromc->ids);
decode_name (p, &toname);
-
+
if (!toc)
err = ESTALE;
if (!err)
@@ -354,20 +427,21 @@ op_rename (struct cache_handle *fromc,
static error_t
op_link (struct cache_handle *filec,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
struct cache_handle *dirc;
char *name;
error_t err = 0;
-
+
p = lookup_cache_handle (p, &dirc, filec->ids);
decode_name (p, &name);
-
+
if (!dirc)
err = ESTALE;
if (!err)
err = dir_link (dirc->port, filec->port, name, 1);
-
+
free (name);
return err;
}
@@ -375,7 +449,8 @@ op_link (struct cache_handle *filec,
static error_t
op_symlink (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
char *name, *target;
error_t err;
@@ -386,7 +461,8 @@ op_symlink (struct cache_handle *c,
p = decode_name (p, &name);
p = decode_name (p, &target);
- mode = ntohl (*p++);
+ mode = ntohl (*p);
+ p++;
if (mode == -1)
mode = 0777;
@@ -416,7 +492,8 @@ op_symlink (struct cache_handle *c,
static error_t
op_mkdir (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
char *name;
mode_t mode;
@@ -428,8 +505,9 @@ op_mkdir (struct cache_handle *c,
error_t err;
p = decode_name (p, &name);
- mode = ntohl (*p++);
-
+ mode = ntohl (*p);
+ p++;
+
err = dir_mkdir (c->port, name, mode);
if (err)
@@ -437,7 +515,7 @@ op_mkdir (struct cache_handle *c,
free (name);
return err;
}
-
+
err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry,
retry_name, &newport);
free (name);
@@ -447,29 +525,31 @@ op_mkdir (struct cache_handle *c,
err = EACCES;
if (err)
return err;
-
- err = complete_setattr (newport, p);
+
+ /* Ignore the rest of the sattr structure. */
+
if (!err)
err = io_stat (newport, &st);
if (err)
return err;
-
+
newc = create_cached_handle (*(int *)c->handle, c, newport);
if (!newc)
return ESTALE;
*reply = encode_fhandle (*reply, newc->handle);
- *reply = encode_fattr (*reply, &st);
+ *reply = encode_fattr (*reply, &st, version);
return 0;
}
static error_t
op_rmdir (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
char *name;
error_t err;
-
+
decode_name (p, &name);
err = dir_rmdir (c->port, name);
@@ -480,7 +560,8 @@ op_rmdir (struct cache_handle *c,
static error_t
op_readdir (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
int cookie;
unsigned count;
@@ -491,20 +572,29 @@ op_readdir (struct cache_handle *c,
int nentries;
int i;
int *replystart;
+ int *r;
- cookie = ntohl (*p++);
- count = ntohl (*p++);
+ cookie = ntohl (*p);
+ p++;
+ count = ntohl (*p);
+ p++;
- buf = alloca (count);
- bufsize = count;
+ buf = (char *) 0;
+ bufsize = 0;
err = dir_readdir (c->port, &buf, &bufsize, cookie, -1, count, &nentries);
if (err)
- return err;
+ {
+ if (buf)
+ munmap (buf, bufsize);
+ return err;
+ }
+
+ r = *reply;
if (nentries == 0)
{
- *(*reply)++ = htonl (0); /* no entry */
- *(*reply)++ = htonl (1); /* EOF */
+ *(r++) = htonl (0); /* No entry. */
+ *(r++) = htonl (1); /* EOF. */
}
else
{
@@ -514,31 +604,39 @@ op_readdir (struct cache_handle *c,
&& (char *)reply < (char *)replystart + count);
i++, dp = (struct dirent *) ((char *)dp + dp->d_reclen))
{
- *(*reply)++ = htonl (1); /* entry present */
- *(*reply)++ = htonl (dp->d_ino);
- *reply = encode_string (*reply, dp->d_name);
- *(*reply)++ = htonl (i + cookie + 1); /* next entry */
+ *(r++) = htonl (1); /* Entry present. */
+ *(r++) = htonl (dp->d_ino);
+ r = encode_string (r, dp->d_name);
+ *(r++) = htonl (i + cookie + 1); /* Next entry. */
}
- *(*reply)++ = htonl (0); /* not EOF */
+ *(r++) = htonl (0); /* No more entries. */
+ *(r++) = htonl (0); /* Not EOF. */
}
-
+
+ *reply = r;
+
+ if (buf)
+ munmap (buf, bufsize);
+
return 0;
}
-static size_t
-count_readdir_buffersize (int *p)
+static size_t
+count_readdir_buffersize (int *p, int version)
{
- return ntohl (*++p); /* skip COOKIE; return COUNT */
+ p++; /* Skip COOKIE. */
+ return ntohl (*p); /* Return COUNT. */
}
static error_t
op_statfs (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
struct statfs st;
error_t err;
-
+
err = file_statfs (c->port, &st);
if (!err)
*reply = encode_statfs (*reply, &st);
@@ -548,14 +646,15 @@ op_statfs (struct cache_handle *c,
static error_t
op_mnt (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
file_t root;
struct cache_handle *newc;
char *name;
-
+
decode_name (p, &name);
-
+
root = file_name_lookup (name, 0, 0);
if (!root)
{
@@ -574,14 +673,18 @@ op_mnt (struct cache_handle *c,
static error_t
op_getport (struct cache_handle *c,
int *p,
- int **reply)
+ int **reply,
+ int version)
{
int prog, vers, prot;
-
- prog = ntohl (*p++);
- vers = ntohl (*p++);
- prot = ntohl (*p++);
-
+
+ prog = ntohl (*p);
+ p++;
+ vers = ntohl (*p);
+ p++;
+ prot = ntohl (*p);
+ p++;
+
if (prot != IPPROTO_UDP)
*(*reply)++ = htonl (0);
else if ((prog == MOUNTPROG && vers == MOUNTVERS)
@@ -591,24 +694,24 @@ op_getport (struct cache_handle *c,
*(*reply)++ = htonl (PMAPPORT);
else
*(*reply)++ = 0;
-
+
return 0;
}
-struct proctable nfstable =
+struct proctable nfs2table =
{
- NFSPROC_NULL, /* first proc */
- NFSPROC_STATFS, /* last proc */
+ NFS2PROC_NULL, /* First proc. */
+ NFS2PROC_STATFS, /* Last proc. */
{
{ op_null, 0, 0, 0},
{ op_getattr, 0, 1, 1},
{ op_setattr, 0, 1, 1},
- { 0, 0, 0, 0 }, /* deprecated NFSPROC_ROOT */
+ { 0, 0, 0, 0 }, /* Deprecated NFSPROC_ROOT. */
{ op_lookup, 0, 1, 1},
{ op_readlink, 0, 1, 1},
{ op_read, count_read_buffersize, 1, 1},
- { 0, 0, 0, 0 }, /* nonexistent NFSPROC_WRITECACHE */
+ { 0, 0, 0, 0 }, /* Nonexistent NFSPROC_WRITECACHE. */
{ op_write, 0, 1, 1},
{ op_create, 0, 1, 1},
{ op_remove, 0, 1, 1},
@@ -622,25 +725,25 @@ struct proctable nfstable =
}
};
-
+
struct proctable mounttable =
{
- MOUNTPROC_NULL, /* first proc */
- MOUNTPROC_EXPORT, /* last proc */
+ MOUNTPROC_NULL, /* First proc. */
+ MOUNTPROC_EXPORT, /* Last proc. */
{
{ op_null, 0, 0, 0},
{ op_mnt, 0, 0, 1},
{ 0, 0, 0, 0}, /* MOUNTPROC_DUMP */
- { 0, 0, 0, 0}, /* MOUNTPROC_UMNT */
- { 0, 0, 0, 0}, /* MOUNTPROC_UMNTALL */
+ { op_null, 0, 0, 0}, /* MOUNTPROC_UMNT */
+ { op_null, 0, 0, 0}, /* MOUNTPROC_UMNTALL */
{ 0, 0, 0, 0}, /* MOUNTPROC_EXPORT */
}
};
-struct proctable pmaptable =
+struct proctable pmaptable =
{
- PMAPPROC_NULL, /* first proc */
- PMAPPROC_CALLIT, /* last proc */
+ PMAPPROC_NULL, /* First proc. */
+ PMAPPROC_CALLIT, /* Last proc. */
{
{ op_null, 0, 0, 0},
{ 0, 0, 0, 0}, /* PMAPPROC_SET */
diff --git a/nfsd/proctables.c b/nfsd/proctables.c
deleted file mode 100644
index 1bc76a38..00000000
--- a/nfsd/proctables.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-
-
-struct proctable nfstable =
-{
- NFSPROC_NULL, /* first proc */
- NFSPROC_STATFS, /* last proc */
- { op_null, 0, 0},
- { op_getattr, 0, 1},
- { op_setattr, 0, 1},
- { 0, 0, 0 }, /* deprecated NFSPROC_ROOT */
- { op_lookup, 0, 1},
- { op_readlink, 0, 1},
- { op_read, count_read_buffersize, 1},
- { 0, 0, 0 }, /* nonexistent NFSPROC_WRITECACHE */
- { op_write, 0, 1},
- { op_create, 0, 1},
- { op_remove, 0, 1},
- { op_rename, 0, 1},
- { op_link, 0, 1},
- { op_symlink, 0, 1},
- { op_mkdir, 0, 1},
- { op_rmdir, 0, 1},
- { op_readdir, count_readdir_buffersize, 1},
- { op_statfs, 0, 1},
-};
-
-
-struct proctable mounttable =
-{
- MOUNTPROC_NULL, /* first proc */
- MOUNTPROC_EXPORT, /* last proc */
- { op_null, 0, 0},
- { op_mnt, 0, 0},
- { 0, 0, 0}, /* MOUNTPROC_DUMP */
- { 0, 0, 0}, /* MOUNTPROC_UMNT */
- { 0, 0, 0}, /* MOUNTPROC_UMNTALL */
- { 0, 0, 0}, /* MOUNTPROC_EXPORT */
-};
diff --git a/nfsd/xdr.c b/nfsd/xdr.c
index d5bea0bd..1ff77851 100644
--- a/nfsd/xdr.c
+++ b/nfsd/xdr.c
@@ -1,5 +1,7 @@
-/* XDR packing and unpacking in nfsd
- Copyright (C) 1996 Free Software Foundation, Inc.
+/* xdr.c - XDR packing and unpacking in nfsd.
+
+ Copyright (C) 1996, 2002, 2007 Free Software Foundation, Inc.
+
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -23,26 +25,15 @@
#include <string.h>
#include "nfsd.h"
-/* Return the address of the next thing after the credential at P. */
-int *
-skip_cred (int *p)
-{
- int size;
-
- p++; /* TYPE */
- size = ntohl (*p++);
- return p + INTSIZE (size);
-}
-
-/* Any better ideas? */
+/* Any better ideas? */
static int
hurd_mode_to_nfs_mode (mode_t m)
{
- return m & 0x177777;
+ return m & 0177777;
}
static int
-hurd_mode_to_nfs_type (mode_t m)
+hurd_mode_to_nfs_type (mode_t m, int version)
{
switch (m & S_IFMT)
{
@@ -65,84 +56,93 @@ hurd_mode_to_nfs_type (mode_t m)
return NFSOCK;
case S_IFIFO:
- return NFFIFO;
+ return (version == 2 ? NF2FIFO : NF3FIFO);
default:
- return NFNON;
+ return (version == 2 ? NF2NON : NFREG);
}
}
-/* Encode ST into P and return the next thing to come after it. */
+/* Encode ST into P and return the next thing to come after it. */
int *
-encode_fattr (int *p, struct stat *st)
+encode_fattr (int *p, struct stat *st, int version)
{
- *p++ = htonl (hurd_mode_to_nfs_type (st->st_mode));
- *p++ = htonl (hurd_mode_to_nfs_mode (st->st_mode));
- *p++ = htonl (st->st_nlink);
- *p++ = htonl (st->st_uid);
- *p++ = htonl (st->st_gid);
- *p++ = htonl (st->st_size);
- *p++ = htonl (st->st_blksize);
- *p++ = htonl (st->st_rdev);
- *p++ = htonl (st->st_blocks);
+ *(p++) = htonl (hurd_mode_to_nfs_type (st->st_mode, version));
+ *(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode));
+ *(p++) = htonl (st->st_nlink);
+ *(p++) = htonl (st->st_uid);
+ *(p++) = htonl (st->st_gid);
+ *(p++) = htonl (st->st_size);
+ *(p++) = htonl (st->st_blksize);
+ *(p++) = htonl (st->st_rdev);
+ *(p++) = htonl (st->st_blocks);
+ *(p++) = htonl (st->st_fsid);
+ *(p++) = htonl (st->st_ino);
+ *(p++) = htonl (st->st_atim.tv_sec);
+ *(p++) = htonl (st->st_atim.tv_nsec / 1000);
+ *(p++) = htonl (st->st_mtim.tv_sec);
+ *(p++) = htonl (st->st_mtim.tv_nsec / 1000);
+ *(p++) = htonl (st->st_ctim.tv_sec);
+ *(p++) = htonl (st->st_ctim.tv_nsec / 1000);
return p;
}
-/* Decode P into NAME and return the next thing to come after it. */
+/* Decode P into NAME and return the next thing to come after it. */
int *
decode_name (int *p, char **name)
{
int len;
- len = ntohl (*p++);
+ len = ntohl (*p);
+ p++;
*name = malloc (len + 1);
- bcopy (p, *name, len);
+ memcpy (*name, p, len);
(*name)[len] = '\0';
return p + INTSIZE (len);
}
-/* Encode HANDLE into P and return the next thing to come after it. */
+/* Encode HANDLE into P and return the next thing to come after it. */
int *
encode_fhandle (int *p, char *handle)
{
- bcopy (handle, p, NFS_FHSIZE);
- return p + INTSIZE (NFS_FHSIZE);
+ memcpy (p, handle, NFS2_FHSIZE);
+ return p + INTSIZE (NFS2_FHSIZE);
}
-/* Encode STRING into P and return the next thing to come after it. */
+/* Encode STRING into P and return the next thing to come after it. */
int *
encode_string (int *p, char *string)
{
return encode_data (p, string, strlen (string));
}
-/* Encode DATA into P and return the next thing to come after it. */
+/* Encode DATA into P and return the next thing to come after it. */
int *
encode_data (int *p, char *data, size_t len)
{
int nints = INTSIZE (len);
p[nints] = 0;
- *p++ = htonl (len);
- bcopy (data, p, len);
+ *(p++) = htonl (len);
+ memcpy (p, data, len);
return p + nints;
}
-/* Encode ST into P and return the next thing to come after it. */
+/* Encode ST into P and return the next thing to come after it. */
int *
encode_statfs (int *p, struct statfs *st)
{
- *p++ = st->f_bsize;
- *p++ = st->f_bsize;
- *p++ = st->f_blocks;
- *p++ = st->f_bfree;
- *p++ = st->f_bavail;
+ *(p++) = st->f_bsize;
+ *(p++) = st->f_bsize;
+ *(p++) = st->f_blocks;
+ *(p++) = st->f_bfree;
+ *(p++) = st->f_bavail;
return p;
}
-/* Return an NFS error corresponding to Hurd error ERR. */
+/* Return an NFS error corresponding to Hurd error ERR. */
int
-nfs_error_trans (error_t err)
+nfs_error_trans (error_t err, int version)
{
switch (err)
{
@@ -156,7 +156,6 @@ nfs_error_trans (error_t err)
return NFSERR_NOENT;
case EIO:
- default:
return NFSERR_IO;
case ENXIO:
@@ -197,8 +196,23 @@ nfs_error_trans (error_t err)
case ESTALE:
return NFSERR_STALE;
+
+ default:
+ if (version == 2)
+ return NFSERR_IO;
+ else switch (err)
+ {
+ case EXDEV:
+ return NFSERR_XDEV;
+
+ case EINVAL:
+ return NFSERR_INVAL;
+
+ case EOPNOTSUPP:
+ return NFSERR_NOTSUPP; /* Are we sure here? */
+
+ default:
+ return NFSERR_IO;
+ }
}
}
-
-
-
diff --git a/pfinet/ChangeLog b/pfinet/ChangeLog
deleted file mode 100644
index a7f861ed..00000000
--- a/pfinet/ChangeLog
+++ /dev/null
@@ -1,250 +0,0 @@
-Sat Jul 20 15:48:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (lndist-asm-files): Look for files in $(srcdir).
- (lndist-linux-files): Likewise.
- (lndist-linux-inet-files): Likewise.
-
-Fri Jul 19 09:39:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pfinet.h (make_sock_user): Declaration updated.
-
-Thu Jul 18 23:19:07 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * misc.c (make_sock_user): New parm `noinstall'; if it's set use
- non-installing version of ports_create_port. All callers
- changed.
- * io-ops.c (S_io_reauthenticate): Install NEWUSER port right into
- portset after it's fully initialized.
-
-Sat Jul 13 20:18:18 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-ops.c (S_io_reauthenticate): Repeat auth_server_authenticate
- for as long as we get EINTR. Deal with other errors without
- crashing.
-
-Sun Jul 7 21:29:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-ops.c (S_io_reauthenticate): Don't use unsafe MOVE_SEND in
- call to auth_server_authenticate.
-
-Fri Jul 5 19:42:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ethernet.c (setup_ethernet_device): Linux's device `mtu' member
- does not include the hardware header size; subtract that off the
- value the kernel specifies as maximum packet size in setting
- ETHER_DEV.mtu.
-
-Thu Jun 27 10:14:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (lndist): Add lndist-asm-files.
- (lndist-asm-files): New rule.
- (ASMHEADERS): New variable.
- ($(top_srcdir)/hurd-snap/$(dir)/asm): New rule.
-
-Tue Jun 25 14:00:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * linux-inet/route.c (ip_rt_del): New function.
- * linux-inet/route.h (ip_rt_del): New declaration.
-
- * options.c (trivfs_get_options): Initialize *ARGZ & *ARGZ_LEN.
- (parse_opt): Fix test for address-less netmask.
- Fix byte order when using IN_* macros.
- Base default netmask on dev->pa_addr, not in->address.
- Don't clear dev->pa_addr.
- Delete old routing entries before adding new ones.
- (trivfs_get_options): Add & use ADD_ADDR_OPT macro.
- (parse_hook_add_interface): Initialize H->curint->device.
-
-Mon Jun 24 16:48:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (sigterm_handler): Renamed from sighup_handle. Make void.
- Deal with SIGTERM instead of SIGHUP.
- (main): Use SIGTERM & sigterm_handler instead of SIGHUP &c.
-
- * options.c (parse_hook_add_interface): Realloc the correct number
- of bytes.
-
-Mon Jun 24 16:33:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c (sighup_handle): New function.
- (arrange_shutdown_notification): Register SIGHUP handler.
-
-Mon Jun 24 12:44:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * options.c (parse_opt): Don't fail if there were no options.
- (RETURN): New macro.
- (PERR, FAIL): Use RETURN instead of return to free memory if nec.
-
-Fri Jun 21 16:42:29 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Pass ARGC & ARGV to argp_parse in the correct order.
-
-Thu Jun 20 22:39:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * options.c: Renamed from opts.c.
- (parse_opt): Fix lots of typos.
- (trivfs_get_options): New function.
- (get_opts, trivfs_S_fsys_get_options, trivfs_S_file_get_fs_options):
- Functions removed.
- <netinet/in.h>, <arpa/inet.h>: New includes.
- * Makefile (pfinet): Depend on ../libfshelp/libfshelp.a &
- ../libshouldbeinlibc/libshouldbeinlibc.a.
- (SRCS): Add options.c.
-
-Thu Jun 20 19:47:40 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c: Include <hurd/startup.h> and <string.h>.
- (shutdown_notify_class): Declare variable.
- (S_startup_dosync): Give enough args to ports_lookup_port.
- (S_startup_dosync/do1): Return a value.
- (arrange_shutdown_notification): Correct spelling of
- ports_create_port. Initialize shutdown_notify_class.
- (find_device): Construct arg to strcmp correctly. Correct
- spelling of ENXIO.
-
-Wed Jun 19 18:46:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts.c (trivfs_S_fsys_set_options): Function removed.
- (trivfs_runtime_argp): New variable.
-
-Sun Jun 16 22:45:54 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * opts.c (parse_opt): Rename ERR macro to FAIL. Use argp_failure.
-
-Sat Jun 15 19:47:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Rearrange for arg parsing some more.
- (enumerate_devices): New function.
- (pfinet_argp): New declaration.
- (already_open): Make global.
- <error.h>, <argp.h>: New includes.
-
-Fri Jun 14 15:41:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (find_device): New function.
- (main): Rearrange to use new argument parsing.
-
-Thu Jun 13 16:55:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (MIGSRCS): Add startup_notifyServer.c.
- * main.c (S_startup_dosync, arrange_shutdown_notification): New
- functions.
- (pfinet_demuxer): Call startup_notify_server.
- (main): Call arrange_shutdown_notification).
-
-Tue May 14 14:12:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c (main): Initialize fsys_identity.
- * misc.c (sock_alloc): Initialize SOCK->identity.
- (sock_release): Destroy SOCK->identity if it's been set.
- * io-ops.c (S_io_identity): New function.
- * pfinet.h (fsys_identity): New variable.
- * linux/net.h (struct socket) [_HURD_]: New member `identity'.
-
- * ethernet.c (ethernet_open): Delete superfluous arg to
- assert_perror.
-
-Fri May 10 16:56:52 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * misc.c (make_sock_user): Pass correct args to ports_create_port.
-
- * ethernet.c (ethernet_open): Pass in ERRNO to assert_perror.
-
-Thu May 9 20:27:28 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io-ops.c (S_io_reauthenticate): Use new auth_server_authenticate
- interface.
-
- * io-ops.c (S_io_select): Drop ID_TAG arg.
-
- * ethernet.c (ethernet_thread): Return any_t.
- (input_work_thread): Likewise.
-
- * ethernet.c (ethernet_open): Use new ports_create_port call.
- * socket-ops.c (S_socket_create_address): Likewise.
- * misc.c (make_sock_user): Likewise.
- (make_sockaddr_port): Likewise.
-
-Wed Apr 24 18:35:50 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * main.c (main): Take third cmdline arg and add gateway route.
-
-Mon Apr 15 12:53:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (CPPFLAGS): Look for config.h in $(srcdir).
- (io-MIGSFLAGS, socket-MIGSFLAGS): Look for mutations.h in
- $(srcdir).
- (vpath %.c): Find linux-inet dir under #(srcdir)>
- (SRCS): Add time.c.
- (LCLHDRS, LINUXHDRS, FROBBEDLINUXHEADERS): New variables.
- (lndist, lndist-linux-inet-files, lndist-linux-files,
- $(top-srcdir)/hurd-snap/$(dir)/linux-inet,
- $(top-srcdir)/hurd-snap/$(dir)/linux): New targets.
-
-Mon Feb 26 13:36:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * misc.c (end_using_sockaddr_port): Only call ports_port_deref if
- arg is valid.
- (end_using_socket_port): Likewise.
-
- * linux/interrupt.h (mark_bh): Remove stubby inline, replace
- with real declaration.
- * pfinet.h (packet_queue_lock): New variable.
- * sched.c (packet_queue_lock): Provide initialization.
- * ethernet.c (ethernet_open): Put READPT in etherport_bucket
- instead of pfinet_bucket. Fork ethernet_thread and
- input_work_thread before returning.
- (more_packets, etherport_bucket): New variables.
- (input_work_thread, ethernet_thread, mark_bh): New functions.
-
- * main.c (pfinet_demuxer): Don't use call ethernet_demuxer.
-
-Thu Feb 22 17:54:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ethernet.c (ethernet_open): Request maximum queue limit
- on our read port.
-
-Thu Feb 8 18:32:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * socket-ops.c (S_socket_connect): Don't return EINVAL for
- SS_CONNECTED state.
-
-Mon Jan 22 13:47:47 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * timer-emul.c (init_time): There are *still* a million microseconds to
- the second.
-
-Thu Jan 18 12:37:57 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mapped-time.h (fetch_jiffies): Uh, duh, there are a million
- microseconds in a second, not just a thousand.
-
-Tue Dec 26 19:29:16 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io-ops.c (S_io_select): Add REPLY parameter, and request
- notification if it dies.
- * mutations.h (IO_SELECT_REPLY_PORT): New def.
-
-Thu Dec 14 18:50:07 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ethernet.c (ethernet_open): Don't set filter priority high.
-
-Mon Dec 11 13:23:49 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * socket-ops.c (S_socket_recv): Whoops, incorrectly negated this
- particular return value. Rename the variable `recvd' to make
- things more clear.
- (S_socket_send): Ditto (`sent'), plus correctly check the return
- value when deciding whether to deallocate ADDR's send right.
-
-Thu Dec 7 18:24:37 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * socket-ops.c (S_socket_recv, S_socket_bind, S_socket_send):
- Negate error return values from linux code.
- (S_socket_setopt): Implement.
-
-Wed Aug 23 14:20:48 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (pfinet): Put all dependencies here.
- (HURDLIBS): Removed.
-
diff --git a/pfinet/Makefile b/pfinet/Makefile
index f36e8693..0874eee3 100644
--- a/pfinet/Makefile
+++ b/pfinet/Makefile
@@ -1,6 +1,5 @@
-#
-# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-# Written by Michael I. Bushnell.
+#
+# Copyright (C) 1995, 1996, 1997, 2000, 2007, 2011 Free Software Foundation, Inc.
#
# This file is part of the GNU Hurd.
#
@@ -18,39 +17,127 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
-dir := pfinet
-makemode := server
-LINUXSRCS= af_inet.c arp.c datagram.c dev.c dev_mcast.c devinet.c eth.c \
- icmp.c igmp.c ip.c \
- proc.c protocol.c raw.c route.c skbuff.c sock.c \
- tcp.c timer.c udp.c utils.c
-UNUSEDSRC = packet.c ipx.c ip_fw.c p8022.c p8023.c pe2.c psnap.c rarp.c
-SRCS = sched.c timer-emul.c devices.c socket.c main.c ethernet.c \
- io-ops.c socket-ops.c misc.c time.c options.c
-MIGSRCS = ioServer.c socketServer.c startup_notifyServer.c
-OBJS= $(subst .c,.o,$(LINUXSRCS) $(SRCS) $(MIGSRCS))
-LCLHDRS= config.h mapped-time.h mutations.h pfinet.h
-LINUXHDRS = arp.h datalink.h eth.h icmp.h ip.h ipx.h ipxcall.h p8022.h \
- p8022call.h protocol.h psnap.h psnapcall.h rarp.h raw.h route.h \
- snmp.h sock.h tcp.h udp.h
-FROBBEDLINUXHEADERS = autoconf.h config.h errno.h etherdevice.h fcntl.h \
- icmp.h if.h if_arp.h if_ether.h igmp.h in.h inet.h interrupt.h \
- ip.h ip_fw.h ipx.h kernel.h major.h malloc.h mm.h net.h netdevice.h \
- notifier.h param.h route.h sched.h skbuff.h socket.h sockios.h stat.h \
- string.h tcp.h termios.h time.h timer.h types.h udp.h un.h wait.h
-ASMHEADERS=bitops.h segment.h system.h
-
-pfinet: $(OBJS) ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a \
- ../libthreads/libthreads.a ../libports/libports.a \
- ../libihash/libihash.a ../libshouldbeinlibc/libshouldbeinlibc.a
-
-vpath %.c $(srcdir)/linux-inet
+dir := pfinet
+makemode := server
+
+core-srcs := datagram.c \
+ dev.c \
+ dev_mcast.c \
+ dst.c \
+ iovec.c \
+ neighbour.c \
+ skbuff.c \
+ sock.c \
+ utils.c
+arch-lib-srcs := checksum.c old-checksum.c csum_partial_copy.c
+ethernet-srcs := eth.c
+ipv4-srcs := af_inet.c \
+ arp.c \
+ devinet.c \
+ fib_frontend.c \
+ fib_hash.c \
+ fib_semantics.c \
+ icmp.c \
+ igmp.c \
+ ip_forward.c \
+ ip_fragment.c \
+ ip_input.c \
+ ip_options.c \
+ ip_output.c \
+ ip_sockglue.c \
+ protocol.c \
+ raw.c \
+ route.c \
+ syncookies.c \
+ sysctl_net_ipv4.c \
+ tcp.c \
+ tcp_input.c \
+ tcp_ipv4.c \
+ tcp_output.c \
+ tcp_timer.c \
+ timer.c \
+ udp.c \
+ utils.c
+ipv6-srcs := addrconf.c \
+ af_inet6.c \
+ datagram_ipv6.c \
+ exthdrs.c \
+ icmpv6.c \
+ ip6_fib.c \
+ ip6_flowlabel.c \
+ ip6_input.c \
+ ip6_output.c \
+ ipv6_sockglue.c \
+ mcast.c \
+ ndisc.c \
+ protocol_ipv6.c \
+ raw_ipv6.c \
+ reassembly.c \
+ route_ipv6.c \
+ tcp_ipv6.c \
+ udp_ipv6.c
+ARCHS = alpha arm i386 m68k ppc s390 sparc sparc64
+
+LINUXSRCS = $(core-srcs) $(ethernet-srcs) $(ipv4-srcs) $(ipv6-srcs)
+ARCHSRCS = $(notdir $(wildcard $(addprefix \
+ $(srcdir)/linux-src/arch/$(asm_syntax)/lib/,\
+ $(arch-lib-srcs) $(arch-lib-srcs:.c=.S))))
+SRCS = sched.c timer-emul.c socket.c main.c ethernet.c \
+ io-ops.c socket-ops.c misc.c time.c options.c loopback.c \
+ kmem_cache.c stubs.c dummy.c tunnel.c pfinet-ops.c \
+ iioctl-ops.c
+MIGSRCS = ioServer.c socketServer.c startup_notifyServer.c \
+ pfinetServer.c iioctlServer.c
+OBJS = $(patsubst %.S,%.o,$(patsubst %.c,%.o,\
+ $(LINUXSRCS) $(ARCHSRCS) $(SRCS) $(MIGSRCS)))
+LCLHDRS = config.h mapped-time.h mutations.h pfinet.h
+LINUXHDRS = bitops.h capability.h delay.h errqueue.h etherdevice.h \
+ fddidevice.h firewall.h icmp.h icmpv6.h if_arp.h if_ether.h \
+ if_fddi.h if_packet.h if_ppp.h if_tunnel.h if_tr.h \
+ igmp.h in.h in_route.h inet.h inetdevice.h init.h ip.h \
+ ip_fw.h ipsec.h ipv6_route.h ipx.h kmod.h linkage.h lists.h \
+ module.h mroute.h net.h netdevice.h netlink.h notifier.h \
+ pkt_cls.h pkt_sched.h ppp_defs.h random.h route.h \
+ rtnetlink.h skbuff.h stddef.h sysctl.h tasks.h tcp.h times.h \
+ trdevice.h udp.h
+LINUXNETHDRS = addrconf.h arp.h br.h checksum.h datalink.h dst.h flow.h \
+ icmp.h if_inet6.h inet_common.h ip.h ip_fib.h ip6_fib.h \
+ ip6_route.h ipip.h ipv6.h ipx.h ipxcall.h ndisc.h \
+ neighbour.h p8022.h p8022call.h pkt_cls.h pkt_sched.h \
+ profile.h protocol.h psnap.h psnapcall.h rarp.h raw.h \
+ rawv6.h route.h slhc.h snmp.h sock.h tcp.h transp_v6.h udp.h
+ARCHHDRS = checksum.h
+FROBBEDLINUXHEADERS = autoconf.h binfmts.h config.h errno.h fcntl.h fs.h \
+ if.h in.h in6.h interrupt.h ioctl.h ipv6.h \
+ kernel.h limits.h major.h malloc.h mm.h param.h personality.h \
+ poll.h proc_fs.h sched.h slab.h socket.h sockios.h stat.h \
+ string.h termios.h time.h timer.h timex.h types.h un.h version.h wait.h
+ASMHEADERS = atomic.h bitops.h byteorder.h delay.h errno.h hardirq.h init.h \
+ segment.h spinlock.h system.h types.h uaccess.h
+
+HURDLIBS=trivfs fshelp threads ports ihash shouldbeinlibc iohelp
target = pfinet
include ../Makeconf
-CPPFLAGS += -imacros $(srcdir)/config.h
+vpath %.c $(addprefix $(srcdir)/linux-src/net/,core ethernet ipv4 ipv6)
+vpath %.c $(srcdir)/linux-src/arch/$(asm_syntax)/lib
+vpath %.S $(srcdir)/linux-src/arch/$(asm_syntax)/lib
+
+CPPFLAGS += -imacros $(srcdir)/config.h \
+ -I$(srcdir)/glue-include \
+ -I$(srcdir)/linux-src/include
+
+# Don't ask... We use Linux code. The problem was first noticed when
+# compiling `pfinet' with GCC 4.2.
+CFLAGS += -fno-strict-aliasing
+
+asm/checksum.h: ../config.status
+ mkdir -p $(@D)
+ echo > $@.new \
+ '#include "../linux-src/include/asm-$(asm_syntax)/checksum.h"'
+ mv -f $@.new $@
io-MIGSFLAGS = -imacros $(srcdir)/mutations.h
socket-MIGSFLAGS = -imacros $(srcdir)/mutations.h
@@ -59,20 +146,62 @@ socket-MIGSFLAGS = -imacros $(srcdir)/mutations.h
io_S.h ioServer.c socket_S.h socketServer.c: mutations.h
$(OBJS): config.h
-lndist: lndist-linux-inet-files lndist-linux-files lndist-asm-files
+lndist: lndist-linux-src-net-core-files lndist-linux-src-net-ethernet-files lndist-linux-src-net-ipv4-files lndist-linux-src-net-ipv6-files lndist-linux-src-asm-files lndist-linux-src-include-asm-files lndist-linux-src-include-linux-files lndist-linux-src-include-net-files lndist-glue-include-linux-files lndist-glue-include-asm-files
+
+lndist-linux-src-net-core-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net/core
+ ln $(addprefix $(srcdir)/linux-src/net/core/,$(core-srcs)) $<
+
+lndist-linux-src-net-ethernet-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net/ethernet
+ ln $(addprefix $(srcdir)/linux-src/net/ethernet/,$(ethernet-srcs)) $<
+
+lndist-linux-src-net-ipv4-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net/ipv4
+ ln $(addprefix $(srcdir)/linux-src/net/ipv4/,$(ipv4-srcs)) $<
+
+lndist-linux-src-net-ipv6-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net/ipv6
+ ln $(addprefix $(srcdir)/linux-src/net/ipv6/,$(ipv6-srcs)) $<
+
+# FIXME !i386
+lndist-linux-src-asm-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/arch/i386/lib
+ ln $(addprefix $(srcdir)/linux-src/arch/i386/lib/,$(ARCHSRCS)) $<
-lndist-linux-inet-files: $(top_srcdir)/hurd-snap/$(dir)/linux-inet
- ln $(addprefix $(srcdir)/linux-inet/,$(LINUXSRCS) $(UNUSEDSRC) $(LINUXHDRS)) $<
+lndist-linux-src-include-linux-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/include/linux
+ ln $(addprefix $(srcdir)/linux-src/include/linux/,$(LINUXHDRS)) $<
-lndist-linux-files: $(top_srcdir)/hurd-snap/$(dir)/linux
- ln $(addprefix $(srcdir)/linux/,$(FROBBEDLINUXHEADERS)) $<
+lndist-linux-src-include-net-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/include/net
+ ln $(addprefix $(srcdir)/linux-src/include/net/,$(LINUXNETHDRS)) $<
-lndist-asm-files: $(top_srcdir)/hurd-snap/$(dir)/asm
- ln $(addprefix $(srcdir)/asm/,$(ASMHEADERS)) $<
+lndist-linux-src-include-asm-files: $(top_srcdir)/hurd-snap/$(dir)/linux-src/include/asm-i386
+ ln $(addprefix $(srcdir)/linux-src/include/asm-$(asm_syntax)/,$(ARCHHDRS)) $<
-$(top_srcdir)/hurd-snap/$(dir)/linux-inet:
+lndist-glue-include-linux-files: $(top_srcdir)/hurd-snap/$(dir)/glue-include/linux
+ ln $(addprefix $(srcdir)/glue-include/linux/,$(FROBBEDLINUXHEADERS)) $<
+
+lndist-glue-include-asm-files: $(top_srcdir)/hurd-snap/$(dir)/glue-include/asm
+ ln $(addprefix $(srcdir)/glue-include/asm/,$(ASMHEADERS)) $<
+
+$(top_srcdir)/hurd-snap/$(dir)/linux-src:
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/arch: $(top_srcdir)/hurd-snap/$(dir)/linux-src
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/arch/%/lib: $(top_srcdir)/hurd-snap/$(dir)/linux-src/arch
+ mkdir -p $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/include: $(top_srcdir)/hurd-snap/$(dir)/linux-src
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/include/%: $(top_srcdir)/hurd-snap/$(dir)/linux-src/include
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/net: $(top_srcdir)/hurd-snap/$(dir)/linux-src
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/net/core: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/net/ethernet: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/net/ipv4: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/linux-src/net/ipv6: $(top_srcdir)/hurd-snap/$(dir)/linux-src/net
+ mkdir $@
+$(top_srcdir)/hurd-snap/$(dir)/glue-include:
mkdir $@
-$(top_srcdir)/hurd-snap/$(dir)/linux:
+$(top_srcdir)/hurd-snap/$(dir)/glue-include/asm: $(top_srcdir)/hurd-snap/$(dir)/glue-include
mkdir $@
-$(top_srcdir)/hurd-snap/$(dir)/asm:
+$(top_srcdir)/hurd-snap/$(dir)/glue-include/linux: $(top_srcdir)/hurd-snap/$(dir)/glue-include
mkdir $@
diff --git a/pfinet/README b/pfinet/README
new file mode 100644
index 00000000..e96601f0
--- /dev/null
+++ b/pfinet/README
@@ -0,0 +1,55 @@
+The Hurd's pfinet server is based on networking code taken from
+the Linux kernel sources, initially version 2.2.12 of Linux.
+The subset of the Linux kernel sources used for pfinet is kept
+in the linux-src subdirectory.
+
+This file describes the procedures for tracking new Linux kernel versions
+and updating the Linux networking code in the Hurd CVS repository.
+
+The verbatim Linux kernel sources are kept on a vendor branch in CVS. To
+simplify the process of importing and merging new versions, I have mostly
+imported whole subdirectories of the linux source tree rather than just the
+precise subset of files we are actually using. However, for the arch/*/lib
+and include/asm-* subdirectories I have taken just the checksum files (the
+only thing we use from the machine-dependent Linux code); and I have
+removed the extraneous whole subdirectories within the include/linux and
+include/net directories. It is my intention to leave the remaining
+extraneous files in the CVS repository, but to include in the distributions
+only the files we are actually using (they will be listed in the Makefile).
+They could also be left on the vendor branch and removed from the trunk, but
+I think that would have more disadvantages than advantages.
+
+The initial import was done with the following commands. It is crucial to
+use `-I !' in the `cvs import' command because of the directory
+linux-src/net/core/ ("core" is in CVS's default list of names to ignore).
+
+mkdir import-tmp
+cd import-tmp
+bunzip2 < linux-2.2.12.tar.bz2 | tar xf - linux/{'arch/*/lib/*checksum*','include/asm-*/checksum.h',include/{linux,net},net/{core,ipv4,ethernet}}
+cd linux
+rm -rf include/{net,linux}/*/
+cvs -d `cat ../../CVS/Root` import -I ! -ko -m "Import of Linux 2.2.12 subset (ipv4 stack and related)" hurd/pfinet/linux-src Linux Linux_2_2_12
+
+It should work to repeat the same procedure with later versions to upgrade
+the `Linux' vendor branch. Please import only verbatim official Linux
+kernel sources, and stick to the tag name schema. If you don't already
+know how to merge the new vendor release into the trunk and finish the
+upgrade, then you probably should not be doing this anyway.
+
+On the main branch, only a few files within the linux-src tree are
+modified, and those only lightly (the changes are described in ChangeLog).
+Linux header files that are heavily modified or wholly replaced for use in
+pfinet go into the glue-include/ subdirectory instead of modifying
+linux-src files in place. Whole C source files can just be replaced with
+new files in the top-level pfinet source directory. When modifications to
+a file in linux-src are justified, the modifications should always be
+conditionalized by #ifdef _HURD_.
+
+
+ -- Roland McGrath <roland@gnu.org> 2000-02-03
+
+---
+
+See <http://www.bddebian.com/~wiki/hurd/translator/pfinet/ipv6/> about IPv6
+support and <http://lists.gnu.org/archive/html/bug-hurd/2007-10/msg00014.html>
+for some further details.
diff --git a/pfinet/asm/bitops.h b/pfinet/asm/bitops.h
deleted file mode 100644
index ee339bd6..00000000
--- a/pfinet/asm/bitops.h
+++ /dev/null
@@ -1,135 +0,0 @@
-#ifndef _I386_BITOPS_H
-#define _I386_BITOPS_H
-
-/*
- * Copyright 1992, Linus Torvalds.
- */
-
-/*
- * These have to be done with inline assembly: that way the bit-setting
- * is guaranteed to be atomic. All bit operations return 0 if the bit
- * was cleared before the operation and != 0 if it was not.
- *
- * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
- */
-
-/*
- * Some hacks to defeat gcc over-optimizations..
- */
-struct __dummy { unsigned long a[100]; };
-#define ADDR (*(struct __dummy *) addr)
-
-extern __inline__ int set_bit(int nr, void * addr)
-{
- int oldbit;
-
- __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"=m" (ADDR)
- :"r" (nr));
- return oldbit;
-}
-
-extern __inline__ int clear_bit(int nr, void * addr)
-{
- int oldbit;
-
- __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"=m" (ADDR)
- :"r" (nr));
- return oldbit;
-}
-
-extern __inline__ int change_bit(int nr, void * addr)
-{
- int oldbit;
-
- __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit),"=m" (ADDR)
- :"r" (nr));
- return oldbit;
-}
-
-/*
- * This routine doesn't need to be atomic, but it's faster to code it
- * this way.
- */
-extern __inline__ int test_bit(int nr, void * addr)
-{
- int oldbit;
-
- __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit)
- :"m" (ADDR),"r" (nr));
- return oldbit;
-}
-
-/*
- * Find-bit routines..
- */
-extern inline int find_first_zero_bit(void * addr, unsigned size)
-{
- int res;
-
- if (!size)
- return 0;
- __asm__("
- cld
- movl $-1,%%eax
- repe; scasl
- je 1f
- subl $4,%%edi
- movl (%%edi),%%eax
- notl %%eax
- bsfl %%eax,%%edx
- jmp 2f
-1: xorl %%edx,%%edx
-2: subl %%ebx,%%edi
- shll $3,%%edi
- addl %%edi,%%edx"
- :"=d" (res)
- :"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
- :"ax", "bx", "cx", "di");
- return res;
-}
-
-extern inline int find_next_zero_bit (void * addr, int size, int offset)
-{
- unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
- int set = 0, bit = offset & 31, res;
-
- if (bit) {
- /*
- * Look for zero in first byte
- */
- __asm__("
- bsfl %1,%0
- jne 1f
- movl $32, %0
-1: "
- : "=r" (set)
- : "r" (~(*p >> bit)));
- if (set < (32 - bit))
- return set + offset;
- set = 32 - bit;
- p++;
- }
- /*
- * No zero yet, search remaining full bytes for a zero
- */
- res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
- return (offset + set + res);
-}
-
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- */
-extern inline unsigned long ffz(unsigned long word)
-{
- __asm__("bsfl %1,%0"
- :"=r" (word)
- :"r" (~word));
- return word;
-}
-
-#endif /* _I386_BITOPS_H */
diff --git a/pfinet/asm/segment.h b/pfinet/asm/segment.h
deleted file mode 100644
index 34c35b96..00000000
--- a/pfinet/asm/segment.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef _HACK_ASM_SEGMENT_H_
-#define _HACK_ASM_SEGMENT_H_
-
-#include <sys/types.h>
-
-#define get_fs_long(addr) (*(long *)(addr))
-#define get_user_long(addr) (*(long *)(addr))
-
-#define get_fs_byte(addr) (*(char *)(addr))
-#define get_user_byte(addr) (*(char *)(addr))
-
-#define put_fs_long(x,addr) (*(long *)(addr) = (x))
-#define put_user_long(x,addr) (*(long *)(addr) = (x)
-
-#define put_fs_byte(x,addr) (*(char *)(addr) = (x))
-#define put_user_byte(x,addr) (*(char *)(addr) = (x))
-
-#define memcpy_fromfs(a,b,s) (memcpy (a, b, s))
-#define memcpy_tofs(a,b,s) (memcpy (a, b, s))
-
-#endif
diff --git a/pfinet/asm/system.h b/pfinet/asm/system.h
deleted file mode 100644
index f828c3bb..00000000
--- a/pfinet/asm/system.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _HACK_ASM_SYSTEM_H_
-#define _HACK_ASM_SYSTEM_H_
-
-#define intr_count 0
-#define save_flags(x) ((x) = 0)
-#define restore_flags(x)
-#define cli()
-#define sti()
-
-#endif
diff --git a/pfinet/config.h b/pfinet/config.h
index eb8314ef..95ac0f43 100644
--- a/pfinet/config.h
+++ b/pfinet/config.h
@@ -1,28 +1,40 @@
-#define __KERNEL__
-#define _HURD_
+#define __KERNEL__ 1
+#undef __SMP__
+
+#define _HURD_ 1
#define ENONET ENETUNREACH
-#define CONFIG_INET
-#define CONFIG_NET
-/* #undef CONFIG_INET_RARP */
-/* #undef CONFIG_IP_MULTICAST */
-/* #undef CONFIG_IP_FORWARD */
-/* #undef CONFIG_IP_FIREWALL */
-/* #undef CONFIG_IP_FIREWALL_DEBUG */
-/* #undef CONFIG_IP_FIREWALL_VERBOSE */
-/* #undef DEBUG_CONFIG_IP_FIREWALL */
-/* #undef CONFIG_IP_ACCT */
+#define CONFIG_NET 1
+#define CONFIG_INET 1
+#define CONFIG_IPV6 1
+
+#undef CONFIG_IPX
+#undef CONFIG_ATALK
+#undef CONFIG_PACKET
+#undef CONFIG_UNIX
+#undef CONFIG_NETLINK
+#undef CONFIG_RTNETLINK
+
+#undef CONFIG_FIREWALL
+#undef CONFIG_FILTER
+
+#undef CONFIG_IP_MULTICAST
+#undef CONFIG_IP_ROUTER
+#undef CONFIG_IP_ADVANCED_ROUTER
+#undef CONFIG_IP_PNP
+#undef CONFIG_IP_ALIAS
+
+#undef CONFIG_NET_IPIP
+#undef CONFIG_NET_IPGRE
+
+#undef CONFIG_SYN_COOKIES
-/* #undef CONFIG_SKB_CHECK */
+#undef CONFIG_INET_RARP
-/* #undef CONFIG_TCP_NAGLE_OFF */
-/* #undef CONFIG_AX25 */
-/* #undef CONFIG_IPX */
-/* #undef CONFIG_ATALK */
-/* #undef CONFIG_SLAVE_BALANCING */
+#define CONFIG_SKB_LARGE 1
-/* #undef CONFIG_INET_PCTCP */
-/* #undef CONFIG_INET_SNARL */
+#define CONFIG_IP_NOSIOCRT 1 /* How convenient. */
-/* #undef CONFIG_I_AM_A_BROKEN_BSD_WEENIE */
+#define CONFIG_IPV6_EUI64 1
+#undef CONFIG_IPV6_NO_PB
diff --git a/pfinet/dummy.c b/pfinet/dummy.c
new file mode 100644
index 00000000..523b218f
--- /dev/null
+++ b/pfinet/dummy.c
@@ -0,0 +1,138 @@
+/*
+ Copyright (C) 1995,96,98,99,2000 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "pfinet.h"
+
+#include <device/device.h>
+#include <device/net_status.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <error.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+struct dummy_device
+{
+ struct dummy_device *next;
+ struct device dev;
+ struct net_device_stats stats;
+};
+
+/* Linked list of all dummy devices. */
+struct dummy_device *dummy_dev;
+
+struct net_device_stats *
+dummy_get_stats (struct device *dev)
+{
+ struct dummy_device *ddev = (struct dummy_device *) dev->priv;
+ return &ddev->stats;
+}
+
+int
+dummy_stop (struct device *dev)
+{
+ return 0;
+}
+
+void
+dummy_set_multi (struct device *dev)
+{
+}
+
+int
+dummy_open (struct device *dev)
+{
+ return 0;
+}
+
+int
+dummy_xmit (struct sk_buff *skb, struct device *dev)
+{
+ struct dummy_device *ddev = (struct dummy_device *) dev->priv;
+
+ ddev->stats.tx_packets++;
+ ddev->stats.tx_bytes += skb->len;
+
+ dev_kfree_skb (skb);
+ return 0;
+}
+
+void
+setup_dummy_device (char *name, struct device **device)
+{
+ error_t err;
+ struct dummy_device *ddev;
+ struct device *dev;
+
+ ddev = calloc (1, sizeof (struct dummy_device));
+ if (!ddev)
+ error (2, ENOMEM, "%s", name);
+ ddev->next = dummy_dev;
+ dummy_dev = ddev;
+
+ *device = dev = &ddev->dev;
+
+ dev->name = strdup (name);
+
+ dev->priv = ddev;
+ dev->get_stats = dummy_get_stats;
+
+ dev->open = dummy_open;
+ dev->stop = dummy_stop;
+ dev->hard_start_xmit = dummy_xmit;
+ dev->set_multicast_list = dummy_set_multi;
+
+ /* These are the ones set by drivers/net/net_init.c::ether_setup. */
+ dev->hard_header = eth_header;
+ dev->rebuild_header = eth_rebuild_header;
+ dev->hard_header_cache = eth_header_cache;
+ dev->header_cache_update = eth_header_cache_update;
+ dev->hard_header_parse = eth_header_parse;
+ /* We can't do these two (and we never try anyway). */
+ /* dev->change_mtu = eth_change_mtu; */
+ /* dev->set_mac_address = eth_mac_addr; */
+
+ /* Some more fields */
+ dev->type = ARPHRD_ETHER;
+ dev->hard_header_len = ETH_HLEN;
+ dev->addr_len = ETH_ALEN;
+ memset (dev->broadcast, 0xff, ETH_ALEN);
+ dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+ dev_init_buffers (dev);
+
+ dev->mtu = 1500;
+ dev->tx_queue_len = 0;
+ dev->flags |= IFF_NOARP;
+ dev->flags &= ~IFF_MULTICAST;
+
+ /* That should be enough. */
+
+ /* This call adds the device to the `dev_base' chain,
+ initializes its `ifindex' member (which matters!),
+ and tells the protocol stacks about the device. */
+ err = - register_netdevice (dev);
+ assert_perror (err);
+}
+
+
+
+
diff --git a/pfinet/ethernet.c b/pfinet/ethernet.c
index bb5632de..0fd76706 100644
--- a/pfinet/ethernet.c
+++ b/pfinet/ethernet.c
@@ -1,5 +1,7 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1998, 1999, 2000, 2002, 2007
+ Free Software Foundation, Inc.
+
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,28 +20,38 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+/* Do not include glue-include/linux/errno.h */
+#define _HACK_ERRNO_H
+#include "pfinet.h"
+
#include <device/device.h>
#include <device/net_status.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
#include <netinet/in.h>
#include <string.h>
+#include <error.h>
+#include <fcntl.h>
-#include "pfinet.h"
-
-static char *ethername;
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
-device_t ether_port;
struct port_class *etherreadclass;
-struct port_info *readpt;
-mach_port_t readptname;
-struct device ether_dev;
+struct ether_device
+{
+ struct ether_device *next;
+ device_t ether_port;
+ struct port_info *readpt;
+ mach_port_t readptname;
+ struct device dev;
+};
+
+/* Linked list of all ethernet devices. */
+struct ether_device *ether_dev;
struct enet_statistics retbuf;
-static struct condition more_packets = CONDITION_INITIALIZER;
/* Mach doesn't provide this. DAMN. */
struct enet_statistics *
@@ -48,35 +60,45 @@ ethernet_get_stats (struct device *dev)
return &retbuf;
}
-int
+int
ethernet_stop (struct device *dev)
{
return 0;
}
void
-ethernet_set_multi (struct device *dev, int numaddrs, void *addrs)
+ethernet_set_multi (struct device *dev)
{
- assert (numaddrs == 0);
}
-static short ether_filter[] =
+static short ether_filter[] =
{
+#ifdef NETF_IN
+ /* We have to tell the packet filtering code that we're interested in
+ incoming packets. */
+ NETF_IN, /* Header. */
+#endif
NETF_PUSHLIT | NETF_NOP,
- 1,
- NETF_PUSHZERO | NETF_OR,
+ 1
};
+static int ether_filter_len = sizeof (ether_filter) / sizeof (short);
+
+/* The BPF instruction allows IP and ARP packets */
+static struct bpf_insn bpf_ether_filter[] =
+{
+ {NETF_IN|NETF_BPF, /* Header. */ 0, 0, 0},
+ {40, 0, 0, 12},
+ {21, 1, 0, 2054},
+ {21, 0, 1, 2048},
+ {6, 0, 0, 1500},
+ {6, 0, 0, 0},
+};
+static int bpf_ether_filter_len = sizeof (bpf_ether_filter) / sizeof (short);
-static int ether_filter_len = 3;
static struct port_bucket *etherport_bucket;
-void
-mark_bh (int arg)
-{
- condition_broadcast (&more_packets);
-}
-any_t
+static any_t
ethernet_thread (any_t arg)
{
ports_manage_port_operations_one_thread (etherport_bucket,
@@ -92,72 +114,113 @@ ethernet_demuxer (mach_msg_header_t *inp,
struct net_rcv_msg *msg = (struct net_rcv_msg *) inp;
struct sk_buff *skb;
int datalen;
+ struct ether_device *edev;
+ struct device *dev = 0;
if (inp->msgh_id != NET_RCV_MSG_ID)
return 0;
-
- if (inp->msgh_local_port != readptname)
+
+ for (edev = ether_dev; edev; edev = edev->next)
+ if (inp->msgh_local_port == edev->readptname)
+ dev = &edev->dev;
+
+ if (! dev)
{
if (inp->msgh_remote_port != MACH_PORT_NULL)
mach_port_deallocate (mach_task_self (), inp->msgh_remote_port);
return 1;
}
-
- datalen = ETH_HLEN
+
+ datalen = ETH_HLEN
+ msg->packet_type.msgt_number - sizeof (struct packet_header);
- mutex_lock (&global_lock);
+ __mutex_lock (&net_bh_lock);
skb = alloc_skb (datalen, GFP_ATOMIC);
- skb->len = datalen;
- skb->dev = &ether_dev;
+ skb_put (skb, datalen);
+ skb->dev = dev;
/* Copy the two parts of the frame into the buffer. */
bcopy (msg->header, skb->data, ETH_HLEN);
- bcopy (msg->packet + sizeof (struct packet_header),
+ bcopy (msg->packet + sizeof (struct packet_header),
skb->data + ETH_HLEN,
datalen - ETH_HLEN);
/* Drop it on the queue. */
+ skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
- mutex_unlock (&global_lock);
+ __mutex_unlock (&net_bh_lock);
return 1;
}
-any_t
-input_work_thread (any_t arg)
+
+void
+ethernet_initialize (void)
{
- mutex_lock (&global_lock);
- for (;;)
- {
- condition_wait (&more_packets, &global_lock);
- net_bh (0);
- }
+ etherport_bucket = ports_create_bucket ();
+ etherreadclass = ports_create_class (0, 0);
+
+ cthread_detach (cthread_fork (ethernet_thread, 0));
}
int
ethernet_open (struct device *dev)
{
- if (ether_port != MACH_PORT_NULL)
- return 0;
-
- etherreadclass = ports_create_class (0, 0);
- errno = ports_create_port (etherreadclass, etherport_bucket,
- sizeof (struct port_info), &readpt);
- assert_perror (errno);
- readptname = ports_get_right (readpt);
- mach_port_insert_right (mach_task_self (), readptname, readptname,
+ error_t err;
+ device_t master_device;
+ struct ether_device *edev = (struct ether_device *) dev->priv;
+
+ assert (edev->ether_port == MACH_PORT_NULL);
+
+ err = ports_create_port (etherreadclass, etherport_bucket,
+ sizeof (struct port_info), &edev->readpt);
+ assert_perror (err);
+ edev->readptname = ports_get_right (edev->readpt);
+ mach_port_insert_right (mach_task_self (), edev->readptname, edev->readptname,
MACH_MSG_TYPE_MAKE_SEND);
- mach_port_set_qlimit (mach_task_self (), readptname, MACH_PORT_QLIMIT_MAX);
+ mach_port_set_qlimit (mach_task_self (), edev->readptname, MACH_PORT_QLIMIT_MAX);
- device_open (master_device, D_WRITE | D_READ, ethername, &ether_port);
+ master_device = file_name_lookup (dev->name, O_READ | O_WRITE, 0);
+ if (master_device != MACH_PORT_NULL)
+ {
+ /* The device name here is the path of a device file. */
+ err = device_open (master_device, D_WRITE | D_READ, "eth", &edev->ether_port);
+ mach_port_deallocate (mach_task_self (), master_device);
+ if (err)
+ error (2, err, "device_open on %s", dev->name);
+
+ err = device_set_filter (edev->ether_port, ports_get_right (edev->readpt),
+ MACH_MSG_TYPE_MAKE_SEND, 0,
+ bpf_ether_filter, bpf_ether_filter_len);
+ if (err)
+ error (2, err, "device_set_filter on %s", dev->name);
+ }
+ else
+ {
+ /* No, perhaps a Mach device? */
+ int file_errno = errno;
+ err = get_privileged_ports (0, &master_device);
+ if (err)
+ {
+ error (0, file_errno, "file_name_lookup %s", dev->name);
+ error (2, err, "and cannot get device master port");
+ }
+ err = device_open (master_device, D_WRITE | D_READ, dev->name, &edev->ether_port);
+ mach_port_deallocate (mach_task_self (), master_device);
+ if (err)
+ {
+ error (0, file_errno, "file_name_lookup %s", dev->name);
+ error (2, err, "device_open(%s)", dev->name);
+ }
+
+ err = device_set_filter (edev->ether_port, ports_get_right (edev->readpt),
+ MACH_MSG_TYPE_MAKE_SEND, 0,
+ ether_filter, ether_filter_len);
+ if (err)
+ error (2, err, "device_set_filter on %s", dev->name);
+ }
- device_set_filter (ether_port, ports_get_right (readpt),
- MACH_MSG_TYPE_MAKE_SEND, 0,
- ether_filter, ether_filter_len);
- cthread_detach (cthread_fork (ethernet_thread, 0));
- cthread_detach (cthread_fork (input_work_thread, 0));
return 0;
}
@@ -166,76 +229,105 @@ ethernet_open (struct device *dev)
int
ethernet_xmit (struct sk_buff *skb, struct device *dev)
{
+ error_t err;
+ struct ether_device *edev = (struct ether_device *) dev->priv;
u_int count;
- int err;
-
- err = device_write (ether_port, D_NOWAIT, 0, skb->data, skb->len, &count);
- assert (err == 0);
+
+ err = device_write (edev->ether_port, D_NOWAIT, 0, skb->data, skb->len, &count);
+ assert_perror (err);
assert (count == skb->len);
- dev_kfree_skb (skb, FREE_WRITE);
+ dev_kfree_skb (skb);
return 0;
}
+/* Set device flags (e.g. promiscuous) */
+int
+ethernet_change_flags (struct device *dev, short flags)
+{
+ error_t err = 0;
+#ifdef NET_FLAGS
+ int status = flags;
+ struct ether_device *edev = (struct ether_device *) dev->priv;
+ err = device_set_status (edev->ether_port, NET_FLAGS, &status, 1);
+ if (err == D_INVALID_OPERATION)
+ /* Not supported, ignore. */
+ err = 0;
+#endif
+ return err;
+}
+
void
-setup_ethernet_device (char *name)
+setup_ethernet_device (char *name, struct device **device)
{
struct net_status netstat;
- u_int count;
+ size_t count;
int net_address[2];
- int i;
-
- etherport_bucket = ports_create_bucket ();
+ error_t err;
+ struct ether_device *edev;
+ struct device *dev;
+
+ edev = calloc (1, sizeof (struct ether_device));
+ if (!edev)
+ error (2, ENOMEM, "%s", name);
+ edev->next = ether_dev;
+ ether_dev = edev;
+
+ *device = dev = &edev->dev;
+
+ dev->name = strdup (name);
+ /* Functions. These ones are the true "hardware layer" in Linux. */
+ dev->open = 0; /* We set up before calling dev_open. */
+ dev->stop = ethernet_stop;
+ dev->hard_start_xmit = ethernet_xmit;
+ dev->get_stats = ethernet_get_stats;
+ dev->set_multicast_list = ethernet_set_multi;
+
+ /* These are the ones set by drivers/net/net_init.c::ether_setup. */
+ dev->hard_header = eth_header;
+ dev->rebuild_header = eth_rebuild_header;
+ dev->hard_header_cache = eth_header_cache;
+ dev->header_cache_update = eth_header_cache_update;
+ dev->hard_header_parse = eth_header_parse;
+ /* We can't do these two (and we never try anyway). */
+ /* dev->change_mtu = eth_change_mtu; */
+ /* dev->set_mac_address = eth_mac_addr; */
- ethername = name;
-
- /* Interface buffers. */
- ether_dev.name = ethername;
- for (i = 0; i < DEV_NUMBUFFS; i++)
- skb_queue_head_init (&ether_dev.buffs[i]);
-
- /* Functions */
- ether_dev.open = ethernet_open;
- ether_dev.stop = ethernet_stop;
- ether_dev.hard_start_xmit = ethernet_xmit;
- ether_dev.hard_header = eth_header;
- ether_dev.rebuild_header = eth_rebuild_header;
- ether_dev.type_trans = eth_type_trans;
- ether_dev.get_stats = ethernet_get_stats;
- ether_dev.set_multicast_list = ethernet_set_multi;
-
/* Some more fields */
- ether_dev.type = ARPHRD_ETHER;
- ether_dev.hard_header_len = sizeof (struct ethhdr);
- ether_dev.addr_len = ETH_ALEN;
- for (i = 0; i < 6; i++)
- ether_dev.broadcast[i] = 0xff;
- ether_dev.flags = IFF_BROADCAST | IFF_MULTICAST;
- ether_dev.family = AF_INET; /* hmm. */
- ether_dev.pa_addr = ether_dev.pa_brdaddr = ether_dev.pa_mask = 0;
- ether_dev.pa_alen = sizeof (unsigned long);
-
- ethernet_open (&ether_dev);
+ dev->priv = edev; /* For reverse lookup. */
+ dev->type = ARPHRD_ETHER;
+ dev->hard_header_len = ETH_HLEN;
+ dev->addr_len = ETH_ALEN;
+ memset (dev->broadcast, 0xff, ETH_ALEN);
+ dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+ dev_init_buffers (dev);
+
+ ethernet_open (dev);
/* Fetch hardware information */
count = NET_STATUS_COUNT;
- device_get_status (ether_port, NET_STATUS, (dev_status_t) &netstat, &count);
- ether_dev.mtu = netstat.max_packet_size - ether_dev.hard_header_len;
+ err = device_get_status (edev->ether_port, NET_STATUS,
+ (dev_status_t) &netstat, &count);
+ if (err)
+ error (2, err, "%s: Cannot get device status", name);
+ dev->mtu = netstat.max_packet_size - dev->hard_header_len;
assert (netstat.header_format == HDR_ETHERNET);
assert (netstat.header_size == ETH_HLEN);
assert (netstat.address_size == ETH_ALEN);
count = 2;
assert (count * sizeof (int) >= ETH_ALEN);
- device_get_status (ether_port, NET_ADDRESS, net_address, &count);
+ err = device_get_status (edev->ether_port, NET_ADDRESS, net_address, &count);
+ if (err)
+ error (2, err, "%s: Cannot get hardware Ethernet address", name);
net_address[0] = ntohl (net_address[0]);
net_address[1] = ntohl (net_address[1]);
- bcopy (net_address, ether_dev.dev_addr, ETH_ALEN);
+ bcopy (net_address, dev->dev_addr, ETH_ALEN);
- /* That should be enough. */
+ /* That should be enough. */
- ether_dev.next = dev_base;
- dev_base = &ether_dev;
+ /* This call adds the device to the `dev_base' chain,
+ initializes its `ifindex' member (which matters!),
+ and tells the protocol stacks about the device. */
+ err = - register_netdevice (dev);
+ assert_perror (err);
}
-
-
-
diff --git a/pfinet/glue-include/asm/atomic.h b/pfinet/glue-include/asm/atomic.h
new file mode 100644
index 00000000..d053854e
--- /dev/null
+++ b/pfinet/glue-include/asm/atomic.h
@@ -0,0 +1,27 @@
+#ifndef _HACK_ASM_ATOMIC_H
+#define _HACK_ASM_ATOMIC_H
+
+/* We don't need atomicity in the Linux code because we serialize all
+ entries to it. */
+
+typedef struct { int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+static __inline__ void atomic_add(int i, atomic_t *v) { v->counter += i; }
+static __inline__ void atomic_sub(int i, atomic_t *v) { v->counter -= i; }
+static __inline__ void atomic_inc(atomic_t *v) { ++v->counter; }
+static __inline__ void atomic_dec(atomic_t *v) { --v->counter; }
+static __inline__ int atomic_dec_and_test(atomic_t *v)
+{ return --v->counter == 0; }
+static __inline__ int atomic_inc_and_test_greater_zero(atomic_t *v)
+{ return ++v->counter > 0; }
+
+#define atomic_clear_mask(mask, addr) (*(addr) &= ~(mask))
+#define atomic_set_mask(mask, addr) (*(addr) |= (mask))
+
+
+#endif
diff --git a/pfinet/glue-include/asm/bitops.h b/pfinet/glue-include/asm/bitops.h
new file mode 100644
index 00000000..8c5a835d
--- /dev/null
+++ b/pfinet/glue-include/asm/bitops.h
@@ -0,0 +1,37 @@
+#ifndef _HACK_ASM_BITOPS_H
+#define _HACK_ASM_BITOPS_H
+
+/* We don't need atomicity in the Linux code because we serialize all
+ entries to it. */
+
+#include <stdint.h>
+
+#define BITOPS_WORD(nr, addr) (((uint32_t *) (addr))[(nr) / 32])
+#define BITOPS_MASK(nr) (1 << ((nr) & 31))
+
+static __inline__ void set_bit (int nr, void *addr)
+{ BITOPS_WORD (nr, addr) |= BITOPS_MASK (nr); }
+
+static __inline__ void clear_bit (int nr, void *addr)
+{ BITOPS_WORD (nr, addr) &= ~BITOPS_MASK (nr); }
+
+static __inline__ void change_bit (int nr, void *addr)
+{ BITOPS_WORD (nr, addr) ^= BITOPS_MASK (nr); }
+
+static __inline__ int test_bit (int nr, void *addr)
+{ return BITOPS_WORD (nr, addr) & BITOPS_MASK (nr); }
+
+static __inline__ int test_and_set_bit (int nr, void *addr)
+{
+ int res = BITOPS_WORD (nr, addr) & BITOPS_MASK (nr);
+ BITOPS_WORD (nr, addr) |= BITOPS_MASK (nr);
+ return res;
+}
+
+#define find_first_zero_bit #error loser
+#define find_next_zero_bit #error loser
+
+#define ffz(word) (ffs (~(unsigned int) (word)) - 1)
+
+
+#endif
diff --git a/pfinet/glue-include/asm/byteorder.h b/pfinet/glue-include/asm/byteorder.h
new file mode 100644
index 00000000..a9fe66d0
--- /dev/null
+++ b/pfinet/glue-include/asm/byteorder.h
@@ -0,0 +1,155 @@
+/* Provide the specified-byte-order access functions used in the Linux
+ kernel, implemented as macros in terms of the GNU libc facilities. */
+
+#ifndef _HACK_ASM_BYTEORDER_H
+#define _HACK_ASM_BYTEORDER_H 1
+
+#include <endian.h>
+#include <byteswap.h>
+#include <hurd.h> /* gets other includes that need BYTE_ORDER */
+
+#define BO_cvt(bits, from, to, x) \
+ ((from) == (to) ? (u_int##bits##_t) (x) : bswap_##bits (x))
+#define BO_cvtp(bits, from, to, p) \
+ BO_cvt (bits, from, to, *(const u_int##bits##_t *) (p))
+#define BO_cvts(bits, from, to, p) \
+ ({ const u_int##bits##_t *_p = (p); *_p = BO_cvt (bits, from, to, *_p); })
+
+#define __cpu_to_le64(x) BO_cvt (64, BYTE_ORDER, LITTLE_ENDIAN, (x))
+#define __le64_to_cpu(x) BO_cvt (64, LITTLE_ENDIAN, BYTE_ORDER, (x))
+#define __cpu_to_le32(x) BO_cvt (32, BYTE_ORDER, LITTLE_ENDIAN, (x))
+#define __le32_to_cpu(x) BO_cvt (32, LITTLE_ENDIAN, BYTE_ORDER, (x))
+#define __cpu_to_le16(x) BO_cvt (16, BYTE_ORDER, LITTLE_ENDIAN, (x))
+#define __le16_to_cpu(x) BO_cvt (16, LITTLE_ENDIAN, BYTE_ORDER, (x))
+#define __cpu_to_be64(x) BO_cvt (64, BYTE_ORDER, BIG_ENDIAN, (x))
+#define __be64_to_cpu(x) BO_cvt (64, BIG_ENDIAN, BYTE_ORDER, (x))
+#define __cpu_to_be32(x) BO_cvt (32, BYTE_ORDER, BIG_ENDIAN, (x))
+#define __be32_to_cpu(x) BO_cvt (32, BIG_ENDIAN, BYTE_ORDER, (x))
+#define __cpu_to_be16(x) BO_cvt (16, BYTE_ORDER, BIG_ENDIAN, (x))
+#define __be16_to_cpu(x) BO_cvt (16, BIG_ENDIAN, BYTE_ORDER, (x))
+#define __cpu_to_le64p(p) BO_cvtp (64, BYTE_ORDER, LITTLE_ENDIAN, (p))
+#define __le64_to_cpup(p) BO_cvtp (64, LITTLE_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_le32p(p) BO_cvtp (32, BYTE_ORDER, LITTLE_ENDIAN, (p))
+#define __le32_to_cpup(p) BO_cvtp (32, LITTLE_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_le16p(p) BO_cvtp (16, BYTE_ORDER, LITTLE_ENDIAN, (p))
+#define __le16_to_cpup(p) BO_cvtp (16, LITTLE_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_be64p(p) BO_cvtp (64, BYTE_ORDER, BIG_ENDIAN, (p))
+#define __be64_to_cpup(p) BO_cvtp (64, BIG_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_be32p(p) BO_cvtp (32, BYTE_ORDER, BIG_ENDIAN, (p))
+#define __be32_to_cpup(p) BO_cvtp (32, BIG_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_be16p(p) BO_cvtp (16, BYTE_ORDER, BIG_ENDIAN, (p))
+#define __be16_to_cpup(p) BO_cvtp (16, BIG_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_le64s(p) BO_cvts (64, BYTE_ORDER, LITTLE_ENDIAN, (p))
+#define __le64_to_cpus(p) BO_cvts (64, LITTLE_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_le32s(p) BO_cvts (32, BYTE_ORDER, LITTLE_ENDIAN, (p))
+#define __le32_to_cpus(p) BO_cvts (32, LITTLE_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_le16s(p) BO_cvts (16, BYTE_ORDER, LITTLE_ENDIAN, (p))
+#define __le16_to_cpus(p) BO_cvts (16, LITTLE_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_be64s(p) BO_cvts (64, BYTE_ORDER, BIG_ENDIAN, (p))
+#define __be64_to_cpus(p) BO_cvts (64, BIG_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_be32s(p) BO_cvts (32, BYTE_ORDER, BIG_ENDIAN, (p))
+#define __be32_to_cpus(p) BO_cvts (32, BIG_ENDIAN, BYTE_ORDER, (p))
+#define __cpu_to_be16s(p) BO_cvts (16, BYTE_ORDER, BIG_ENDIAN, (p))
+#define __be16_to_cpus(p) BO_cvts (16, BIG_ENDIAN, BYTE_ORDER, (p))
+
+#define cpu_to_le64 __cpu_to_le64
+#define le64_to_cpu __le64_to_cpu
+#define cpu_to_le32 __cpu_to_le32
+#define le32_to_cpu __le32_to_cpu
+#define cpu_to_le16 __cpu_to_le16
+#define le16_to_cpu __le16_to_cpu
+#define cpu_to_be64 __cpu_to_be64
+#define be64_to_cpu __be64_to_cpu
+#define cpu_to_be32 __cpu_to_be32
+#define be32_to_cpu __be32_to_cpu
+#define cpu_to_be16 __cpu_to_be16
+#define be16_to_cpu __be16_to_cpu
+#define cpu_to_le64p __cpu_to_le64p
+#define le64_to_cpup __le64_to_cpup
+#define cpu_to_le32p __cpu_to_le32p
+#define le32_to_cpup __le32_to_cpup
+#define cpu_to_le16p __cpu_to_le16p
+#define le16_to_cpup __le16_to_cpup
+#define cpu_to_be64p __cpu_to_be64p
+#define be64_to_cpup __be64_to_cpup
+#define cpu_to_be32p __cpu_to_be32p
+#define be32_to_cpup __be32_to_cpup
+#define cpu_to_be16p __cpu_to_be16p
+#define be16_to_cpup __be16_to_cpup
+#define cpu_to_le64s __cpu_to_le64s
+#define le64_to_cpus __le64_to_cpus
+#define cpu_to_le32s __cpu_to_le32s
+#define le32_to_cpus __le32_to_cpus
+#define cpu_to_le16s __cpu_to_le16s
+#define le16_to_cpus __le16_to_cpus
+#define cpu_to_be64s __cpu_to_be64s
+#define be64_to_cpus __be64_to_cpus
+#define cpu_to_be32s __cpu_to_be32s
+#define be32_to_cpus __be32_to_cpus
+#define cpu_to_be16s __cpu_to_be16s
+#define be16_to_cpus __be16_to_cpus
+
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define __BIG_ENDIAN_BITFIELD
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# define __LITTLE_ENDIAN_BITFIELD
+#else
+# error __FOO_ENDIAN_BITFIELD
+#endif
+
+
+#include <netinet/in.h> /* for htonl et al */
+
+/* Though the optimized macros defined by glibc do the constant magic,
+ there are places in the Linux code that use these in constant-only
+ places like initializers, and the ({...}) expressions the macros use are
+ not valid in those contexts. */
+#if BYTE_ORDER == BIG_ENDIAN
+# if !defined(__constant_htonl)
+# define __constant_htonl(x) (x)
+# endif
+# if !defined(__constant_htons)
+# define __constant_htons(x) (x)
+# endif
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# if !defined(__constant_htonl)
+# define __constant_htonl(x) \
+ ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
+ (((unsigned long int)(x) & 0x0000ff00U) << 8) | \
+ (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
+ (((unsigned long int)(x) & 0xff000000U) >> 24)))
+# endif
+# if !defined(__constant_htons)
+# define __constant_htons(x) \
+ ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
+ (((unsigned short int)(x) & 0xff00) >> 8)))
+# endif
+#else
+# error "Don't know if bytes are big- or little-endian!"
+#endif
+
+/* The transformation is the same in both directions. */
+#define __constant_ntohl __constant_htonl
+#define __constant_ntohs __constant_htons
+
+
+/* Some Linux code (e.g. <net/tcp.h>) uses #ifdef __BIG_ENDIAN et al.
+ This is not real wonderful with the glibc definitions, where
+ __BIG_ENDIAN et al are always defined (as values for __BYTE_ORDER). */
+#if BYTE_ORDER == BIG_ENDIAN
+#undef __LITTLE_ENDIAN
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#undef __BIG_ENDIAN
+#endif
+#undef __PDP_ENDIAN
+
+/* Since we've now broken anything that does glibc-style tests,
+ make sure they break loudly rather than silently. Any headers
+ that need __BYTE_ORDER will just have to be included before
+ we diddle with __BIG_ENDIAN or __LITTLE_ENDIAN above. */
+#undef __BYTE_ORDER
+#define __BYTE_ORDER ?????crash?????
+
+
+#endif /* asm/byteorder.h */
diff --git a/pfinet/glue-include/asm/delay.h b/pfinet/glue-include/asm/delay.h
new file mode 100644
index 00000000..7d651a40
--- /dev/null
+++ b/pfinet/glue-include/asm/delay.h
@@ -0,0 +1 @@
+/* stub file. */
diff --git a/pfinet/glue-include/asm/errno.h b/pfinet/glue-include/asm/errno.h
new file mode 100644
index 00000000..7afb6fdc
--- /dev/null
+++ b/pfinet/glue-include/asm/errno.h
@@ -0,0 +1,3 @@
+/* This is used only by checksum.S; the C code uses <linux/errno.h>. */
+
+#define EFAULT 42 /* only used in unreached code */
diff --git a/pfinet/glue-include/asm/hardirq.h b/pfinet/glue-include/asm/hardirq.h
new file mode 100644
index 00000000..c73d7dcb
--- /dev/null
+++ b/pfinet/glue-include/asm/hardirq.h
@@ -0,0 +1 @@
+#include <linux/interrupt.h>
diff --git a/pfinet/glue-include/asm/init.h b/pfinet/glue-include/asm/init.h
new file mode 100644
index 00000000..2331be7c
--- /dev/null
+++ b/pfinet/glue-include/asm/init.h
@@ -0,0 +1,3 @@
+#define __init
+#define __initdata
+#define __initfunc(x) x
diff --git a/config/hostname b/pfinet/glue-include/asm/segment.h
index e69de29b..e69de29b 100644
--- a/config/hostname
+++ b/pfinet/glue-include/asm/segment.h
diff --git a/pfinet/glue-include/asm/spinlock.h b/pfinet/glue-include/asm/spinlock.h
new file mode 100644
index 00000000..1666b0e2
--- /dev/null
+++ b/pfinet/glue-include/asm/spinlock.h
@@ -0,0 +1,75 @@
+#ifndef _HACK_ASM_SPINLOCK_H_
+#define _HACK_ASM_SPINLOCK_H_
+
+#include <cthreads.h>
+
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { }
+
+#undef spin_lock_init
+#undef spin_lock
+#undef spin_unlock
+
+#define spin_lock_init(lock) ((void) (lock))
+#define spin_lock(lock) ((void) (lock))
+#define spin_trylock(lock) ((void) (lock), 1)
+#define spin_unlock_wait(lock) ((void) (lock))
+#define spin_unlock(lock) ((void) (lock))
+#define spin_lock_irq(lock) ((void) (lock))
+#define spin_unlock_irq(lock) ((void) (lock))
+#define spin_lock_irqsave(lock, flags) ((void) (lock), (void) (flags))
+#define spin_unlock_irqrestore(lock, flags) ((void) (lock), (void) (flags))
+
+typedef struct { } rwlock_t;
+#define read_lock(rw) do { } while(0)
+#define write_lock(rw) do { } while(0)
+#define write_unlock(rw) do { } while(0)
+#define read_unlock(rw) do { } while(0)
+
+#if 0
+#include <rwlock.h>
+
+typedef struct mutex spinlock_t;
+
+#undef spin_lock_init
+#undef spin_lock
+#undef spin_unlock
+
+#define SPIN_LOCK_UNLOCKED MUTEX_INITIALIZER
+#define spin_lock_init(lock) ({ __mutex_init (lock); })
+#define spin_lock(lock) ({ __mutex_lock (lock); })
+#define spin_trylock(lock) ({ __mutex_trylock (lock); })
+#define spin_unlock_wait(lock) ({ __mutex_unlock (lock); })
+#define spin_unlock(lock) ({ __mutex_unlock (lock); })
+#define spin_lock_irq(lock) ({ __mutex_lock (lock); })
+#define spin_unlock_irq(lock) ({ __mutex_unlock (lock); })
+
+#define spin_lock_irqsave(lock, flags) \
+ do { flags = 0; __mutex_lock (lock); } while (0)
+#define spin_unlock_irqrestore(lock, flags) ({ __mutex_unlock (lock); })
+
+
+typedef struct rwlock rwlock_t;
+
+#define read_lock(rw) rwlock_reader_lock(rw)
+#define write_lock(rw) rwlock_writer_lock(rw)
+#define write_unlock(rw) rwlock_writer_unlock(rw)
+#define read_unlock(rw) rwlock_reader_unlock(rw)
+
+#endif
+
+
+#define read_lock_irq(lock) read_lock(lock)
+#define read_unlock_irq(lock) read_unlock(lock)
+#define write_lock_irq(lock) write_lock(lock)
+#define write_unlock_irq(lock) write_unlock(lock)
+
+#define read_lock_irqsave(lock, flags) \
+ do { (flags) = 0; read_lock(lock); } while (0)
+#define read_unlock_irqrestore(lock, flags) read_unlock(lock)
+#define write_lock_irqsave(lock, flags) \
+ do { (flags) = 0; write_lock(lock); } while (0)
+#define write_unlock_irqrestore(lock, flags) write_unlock(lock)
+
+
+#endif
diff --git a/pfinet/glue-include/asm/system.h b/pfinet/glue-include/asm/system.h
new file mode 100644
index 00000000..30339b62
--- /dev/null
+++ b/pfinet/glue-include/asm/system.h
@@ -0,0 +1,20 @@
+#ifndef _HACK_ASM_SYSTEM_H
+#define _HACK_ASM_SYSTEM_H
+
+/* We don't need atomicity in the Linux code because we serialize all
+ entries to it. */
+
+#include <stdint.h>
+
+#define xchg(ptr, x) \
+ ({ \
+ __typeof__ (*(ptr)) *_ptr = (ptr), _x = *_ptr; \
+ *_ptr = (x); _x; \
+ })
+
+#define mb() ((void) 0) /* memory barrier */
+#define rmb() mb()
+#define wmb() mb()
+
+
+#endif
diff --git a/pfinet/glue-include/asm/types.h b/pfinet/glue-include/asm/types.h
new file mode 100644
index 00000000..ee9b980a
--- /dev/null
+++ b/pfinet/glue-include/asm/types.h
@@ -0,0 +1 @@
+#include <linux/types.h>
diff --git a/pfinet/glue-include/asm/uaccess.h b/pfinet/glue-include/asm/uaccess.h
new file mode 100644
index 00000000..6f6dc413
--- /dev/null
+++ b/pfinet/glue-include/asm/uaccess.h
@@ -0,0 +1,53 @@
+#ifndef _HACK_ASM_UACCESS_H_
+#define _HACK_ASM_UACCESS_H_
+
+#include <linux/mm.h>
+
+
+#define MAKE_MM_SEG(s) XXX
+#define KERNEL_DS XXX
+#define USER_DS XXX
+
+#define get_ds() XXX
+#define get_fs() XXX
+#define set_fs(x) XXX
+
+#define segment_eq(a,b) XXX
+
+extern int __verify_write(const void *, unsigned long);
+#define __verify_write XXX
+
+#define __addr_ok(addr) (1)
+#define __range_ok(addr,size) (1)
+#define access_ok(type,addr,size) (1)
+
+#define put_user(x,ptr) (*(ptr) = (x), 0)
+#define get_user(x,ptr) ((x) = *(ptr), 0)
+#define __get_user(x,ptr) get_user((x), (ptr))
+
+/* This is used to constitute an arbitrarily-sized memory clobber in an asm. */
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct *)(x))
+
+
+/*
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
+ */
+
+#define put_user_ret(x,ptr,ret) ({ if (put_user(x,ptr)) return ret; })
+
+#define get_user_ret(x,ptr,ret) ({ if (get_user(x,ptr)) return ret; })
+
+
+#define copy_to_user(to,from,n) (memcpy ((to), (from), (n)), 0)
+#define copy_from_user(to,from,n) (memcpy ((to), (from), (n)), 0)
+#define clear_user(mem, len) (bzero ((mem), (len)), 0)
+
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
+
+
+#endif
diff --git a/pfinet/linux/autoconf.h b/pfinet/glue-include/linux/autoconf.h
index e69de29b..e69de29b 100644
--- a/pfinet/linux/autoconf.h
+++ b/pfinet/glue-include/linux/autoconf.h
diff --git a/pfinet/glue-include/linux/binfmts.h b/pfinet/glue-include/linux/binfmts.h
new file mode 100644
index 00000000..c8229dad
--- /dev/null
+++ b/pfinet/glue-include/linux/binfmts.h
@@ -0,0 +1 @@
+#include <linux/capability.h>
diff --git a/pfinet/glue-include/linux/config.h b/pfinet/glue-include/linux/config.h
new file mode 100644
index 00000000..be1e4d3f
--- /dev/null
+++ b/pfinet/glue-include/linux/config.h
@@ -0,0 +1 @@
+#include <linux/errno.h>
diff --git a/pfinet/glue-include/linux/errno.h b/pfinet/glue-include/linux/errno.h
new file mode 100644
index 00000000..7afcd9fd
--- /dev/null
+++ b/pfinet/glue-include/linux/errno.h
@@ -0,0 +1,13 @@
+#ifndef _HACK_ERRNO_H
+#define _HACK_ERRNO_H
+
+#include <errno.h>
+#include <hurd.h>
+
+#define ERESTARTSYS EINTR
+#define ENOPKG ENOSYS
+#define ENOIOCTLCMD ENOTTY
+
+#undef errno
+
+#endif
diff --git a/pfinet/linux/fcntl.h b/pfinet/glue-include/linux/fcntl.h
index cd304557..cd304557 100644
--- a/pfinet/linux/fcntl.h
+++ b/pfinet/glue-include/linux/fcntl.h
diff --git a/pfinet/glue-include/linux/fs.h b/pfinet/glue-include/linux/fs.h
new file mode 100644
index 00000000..45dbb19f
--- /dev/null
+++ b/pfinet/glue-include/linux/fs.h
@@ -0,0 +1,21 @@
+#ifndef _HACK_FS_H
+#define _HACK_FS_H
+
+#include <linux/net.h>
+
+/* Hackery */
+struct inode
+{
+ union
+ {
+ int i_garbage;
+ struct socket socket_i; /* icmp.c actually needs this!! */
+ } u;
+};
+#define i_uid u.i_garbage
+#define i_gid u.i_garbage
+#define i_sock u.i_garbage
+#define i_ino u.i_garbage
+#define i_mode u.i_garbage
+
+#endif
diff --git a/pfinet/glue-include/linux/if.h b/pfinet/glue-include/linux/if.h
new file mode 100644
index 00000000..7d4563c3
--- /dev/null
+++ b/pfinet/glue-include/linux/if.h
@@ -0,0 +1,3 @@
+#include <net/if.h>
+
+#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ALLMULTI)
diff --git a/pfinet/glue-include/linux/in.h b/pfinet/glue-include/linux/in.h
new file mode 100644
index 00000000..074c70e3
--- /dev/null
+++ b/pfinet/glue-include/linux/in.h
@@ -0,0 +1,44 @@
+#ifndef _HACK_IN_H_
+#define _HACK_IN_H_
+
+#include <netinet/in.h>
+
+/* IP_MTU_DISCOVER values */
+#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
+#define IP_PMTUDISC_WANT 1 /* Use per route hints */
+#define IP_PMTUDISC_DO 2 /* Always DF */
+
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+
+struct ip_mreqn
+{
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_address; /* local IP address of interface */
+ int imr_ifindex; /* Interface index */
+};
+
+struct in_pktinfo
+{
+ int ipi_ifindex;
+ struct in_addr ipi_spec_dst;
+ struct in_addr ipi_addr;
+};
+
+
+/* <asm/byteorder.h> contains the htonl type stuff.. */
+#include <asm/byteorder.h>
+
+#ifdef __KERNEL__
+/* Some random defines to make it easier in the kernel.. */
+#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000))
+#define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000))
+#define BADCLASS(x) (((x) & htonl(0xf0000000)) == htonl(0xf0000000))
+#define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000))
+#define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000))
+
+#endif
+
+
+#endif
diff --git a/pfinet/glue-include/linux/in6.h b/pfinet/glue-include/linux/in6.h
new file mode 100644
index 00000000..c3e5dfc4
--- /dev/null
+++ b/pfinet/glue-include/linux/in6.h
@@ -0,0 +1,110 @@
+#ifndef GLUE_LINUX_IN6_H
+#define GLUE_LINUX_IN6_H 1
+
+#include <netinet/in.h>
+
+#if 0
+struct ipv6_mreq {
+ /* IPv6 multicast address of group */
+ struct in6_addr ipv6mr_multiaddr;
+
+ /* local IPv6 address of interface */
+ int ipv6mr_ifindex;
+};
+#endif
+
+/* In Linux's struct ipv6_mreq the second member is called ipv6mr_ifindex,
+ * however it's called ipv6mr_interface in ours.
+ */
+#define ipv6mr_ifindex ipv6mr_interface
+
+struct in6_flowlabel_req
+{
+ struct in6_addr flr_dst;
+ __u32 flr_label;
+ __u8 flr_action;
+ __u8 flr_share;
+ __u16 flr_flags;
+ __u16 flr_expires;
+ __u16 flr_linger;
+ __u32 __flr_pad;
+ /* Options in format of IPV6_PKTOPTIONS */
+};
+
+#define IPV6_FL_A_GET 0
+#define IPV6_FL_A_PUT 1
+#define IPV6_FL_A_RENEW 2
+
+#define IPV6_FL_F_CREATE 1
+#define IPV6_FL_F_EXCL 2
+
+#define IPV6_FL_S_NONE 0
+#define IPV6_FL_S_EXCL 1
+#define IPV6_FL_S_PROCESS 2
+#define IPV6_FL_S_USER 3
+#define IPV6_FL_S_ANY 255
+
+
+/*
+ * Bitmask constant declarations to help applications select out the
+ * flow label and priority fields.
+ *
+ * Note that this are in host byte order while the flowinfo field of
+ * sockaddr_in6 is in network byte order.
+ */
+
+#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff
+#define IPV6_FLOWINFO_PRIORITY 0x0ff00000
+
+/* These defintions are obsolete */
+#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000
+#define IPV6_PRIORITY_FILLER 0x0100
+#define IPV6_PRIORITY_UNATTENDED 0x0200
+#define IPV6_PRIORITY_RESERVED1 0x0300
+#define IPV6_PRIORITY_BULK 0x0400
+#define IPV6_PRIORITY_RESERVED2 0x0500
+#define IPV6_PRIORITY_INTERACTIVE 0x0600
+#define IPV6_PRIORITY_CONTROL 0x0700
+#define IPV6_PRIORITY_8 0x0800
+#define IPV6_PRIORITY_9 0x0900
+#define IPV6_PRIORITY_10 0x0a00
+#define IPV6_PRIORITY_11 0x0b00
+#define IPV6_PRIORITY_12 0x0c00
+#define IPV6_PRIORITY_13 0x0d00
+#define IPV6_PRIORITY_14 0x0e00
+#define IPV6_PRIORITY_15 0x0f00
+
+/*
+ * IPv6 TLV options.
+ */
+#define IPV6_TLV_PAD0 0
+#define IPV6_TLV_PADN 1
+#define IPV6_TLV_ROUTERALERT 20
+#define IPV6_TLV_JUMBO 194
+
+/*
+ * IPV6 socket options
+ */
+
+#define IPV6_ADDRFORM 1
+#define IPV6_PKTINFO 2
+#define IPV6_HOPOPTS 3
+#define IPV6_DSTOPTS 4
+#define IPV6_RTHDR 5
+#define IPV6_PKTOPTIONS 6
+#define IPV6_CHECKSUM 7
+#define IPV6_HOPLIMIT 8
+#define IPV6_NEXTHOP 9
+#define IPV6_AUTHHDR 10
+#define IPV6_FLOWINFO 11
+
+/* IPV6_MTU_DISCOVER values */
+#define IPV6_PMTUDISC_DONT 0
+#define IPV6_PMTUDISC_WANT 1
+#define IPV6_PMTUDISC_DO 2
+
+/* Flowlabel */
+#define IPV6_FLOWLABEL_MGR 32
+#define IPV6_FLOWINFO_SEND 33
+
+#endif /* not GLUE_LINUX_IN6_H */
diff --git a/pfinet/glue-include/linux/interrupt.h b/pfinet/glue-include/linux/interrupt.h
new file mode 100644
index 00000000..5f485e32
--- /dev/null
+++ b/pfinet/glue-include/linux/interrupt.h
@@ -0,0 +1,44 @@
+#ifndef _HACK_INTERRUPT_H_
+#define _HACK_INTERRUPT_H_
+
+#include <linux/netdevice.h>
+#include "pfinet.h"
+
+#define in_interrupt() (0)
+#define synchronize_irq() ((void) 0)
+
+#define synchronize_bh() ((void) 0) /* XXX ? */
+
+/* The code that can call these are already entered holding
+ global_lock, which locks out the net_bh worker thread. */
+#define start_bh_atomic() ((void) 0)
+#define end_bh_atomic() ((void) 0)
+/*
+extern struct mutex net_bh_lock;
+#define start_bh_atomic() __mutex_lock (&net_bh_lock)
+#define end_bh_atomic() __mutex_unlock (&net_bh_lock)
+*/
+
+/* See sched.c::net_bh_worker comments. */
+extern struct condition net_bh_wakeup;
+
+#define NET_BH 0xb00bee51
+
+/* The only call to this ever reached is in net/core/dev.c::netif_rx,
+ to announce having enqueued a packet on `backlog'. */
+static inline void
+mark_bh (int bh)
+{
+ assert (bh == NET_BH);
+ condition_broadcast (&net_bh_wakeup);
+}
+
+void net_bh (void);
+static inline void
+init_bh (int bh, void (*fn) (void))
+{
+ assert (bh == NET_BH);
+ assert (fn == &net_bh);
+}
+
+#endif
diff --git a/pfinet/glue-include/linux/ioctl.h b/pfinet/glue-include/linux/ioctl.h
new file mode 100644
index 00000000..6ec92cf7
--- /dev/null
+++ b/pfinet/glue-include/linux/ioctl.h
@@ -0,0 +1 @@
+#include <sys/ioctl.h>
diff --git a/pfinet/glue-include/linux/ipv6.h b/pfinet/glue-include/linux/ipv6.h
new file mode 100644
index 00000000..5a1604a3
--- /dev/null
+++ b/pfinet/glue-include/linux/ipv6.h
@@ -0,0 +1,117 @@
+#ifndef _IPV6_H
+#define _IPV6_H
+
+#include <linux/in6.h>
+#include <asm/byteorder.h>
+
+/* The latest drafts declared increase in minimal mtu up to 1280. */
+
+#define IPV6_MIN_MTU 1280
+
+/*
+ * Advanced API
+ * source interface/address selection, source routing, etc...
+ * *under construction*
+ */
+
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ __u32 ifr6_prefixlen;
+ int ifr6_ifindex;
+};
+
+#define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */
+#define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */
+
+/*
+ * routing header
+ */
+struct ipv6_rt_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ __u8 type;
+ __u8 segments_left;
+
+ /*
+ * type specific data
+ * variable length field
+ */
+};
+
+
+struct ipv6_opt_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ /*
+ * TLV encoded option data follows.
+ */
+};
+
+#define ipv6_destopt_hdr ipv6_opt_hdr
+#define ipv6_hopopt_hdr ipv6_opt_hdr
+
+#ifdef __KERNEL__
+#define ipv6_optlen(p) (((p)->hdrlen+1) << 3)
+#endif
+
+/*
+ * routing header type 0 (used in cmsghdr struct)
+ */
+
+struct rt0_hdr {
+ struct ipv6_rt_hdr rt_hdr;
+ __u32 bitmap; /* strict/loose bit map */
+ struct in6_addr addr[0];
+
+#define rt0_type rt_hdr.type;
+};
+
+/*
+ * IPv6 fixed header
+ *
+ * BEWARE, it is incorrect. The first 4 bits of flow_lbl
+ * are glued to priority now, forming "class".
+ */
+
+struct ipv6hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 priority:4,
+ version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 version:4,
+ priority:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 flow_lbl[3];
+
+ __u16 payload_len;
+ __u8 nexthdr;
+ __u8 hop_limit;
+
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+};
+
+#ifdef __KERNEL__
+
+/*
+ This structure contains results of exthdrs parsing
+ as offsets from skb->nh.
+ */
+
+struct inet6_skb_parm
+{
+ int iif;
+ __u16 ra;
+ __u16 hop;
+ __u16 auth;
+ __u16 dst0;
+ __u16 srcrt;
+ __u16 dst1;
+};
+
+#endif
+
+#endif
diff --git a/pfinet/glue-include/linux/kernel.h b/pfinet/glue-include/linux/kernel.h
new file mode 100644
index 00000000..a0e101b9
--- /dev/null
+++ b/pfinet/glue-include/linux/kernel.h
@@ -0,0 +1,78 @@
+#ifndef _HACK_KERNEL_H
+#define _HACK_KERNEL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+
+/* These don't actually matter since our locking protocols are different. */
+#define barrier() ((void)0) /*__asm__ __volatile__("": : :"memory") */
+
+#define NORET_TYPE /**/
+#define ATTRIB_NORET __attribute__((noreturn))
+#define NORET_AND noreturn,
+#define FASTCALL(x) x
+
+/* XXX do something syslogy */
+#define KERN_EMERG
+#define KERN_ALERT
+#define KERN_CRIT
+#define KERN_ERR
+#define KERN_WARNING
+#define KERN_NOTICE
+#define KERN_INFO
+#define KERN_DEBUG
+
+#define panic(str...) (printk (str), assert (!"panic"))
+
+/*
+ * Display an IP address in readable format.
+ */
+
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+
+
+#include <linux/sched.h>
+#include <linux/bitops.h>
+
+#define printk printf
+
+extern inline int
+getname (const char *name, char **newp)
+{
+ *newp = malloc (strlen (name) + 1);
+ strcpy (*newp, name);
+ return 0;
+}
+
+extern inline void
+putname (char *p)
+{
+ free (p);
+}
+
+/* These two functions are used only to send SIGURG. But I can't
+ find any SIGIO code at all. So we'll just punt on that; clearly
+ Linux is missing the point. SIGURG should only be sent for
+ sockets that have explicitly requested it. */
+extern inline int
+kill_proc (int pid, int signo, int priv)
+{
+ assert (signo == SIGURG);
+ return 0;
+}
+
+extern inline int
+kill_pg (int pgrp, int signo, int priv)
+{
+ assert (signo == SIGURG);
+ return 0;
+}
+
+
+#endif
diff --git a/pfinet/glue-include/linux/limits.h b/pfinet/glue-include/linux/limits.h
new file mode 100644
index 00000000..856c3bde
--- /dev/null
+++ b/pfinet/glue-include/linux/limits.h
@@ -0,0 +1,8 @@
+#ifndef _HACK_LIMITS_H
+#define _HACK_LIMITS_H
+
+#include <limits.h>
+
+#define UIO_MAXIOV 1024 /* probably 1 would do */
+
+#endif
diff --git a/pfinet/linux/major.h b/pfinet/glue-include/linux/major.h
index e69de29b..e69de29b 100644
--- a/pfinet/linux/major.h
+++ b/pfinet/glue-include/linux/major.h
diff --git a/pfinet/glue-include/linux/malloc.h b/pfinet/glue-include/linux/malloc.h
new file mode 100644
index 00000000..46ae1051
--- /dev/null
+++ b/pfinet/glue-include/linux/malloc.h
@@ -0,0 +1,27 @@
+#ifndef _HACK_MALLOC_H_
+#define _HACK_MALLOC_H_
+
+#include <linux/mm.h>
+
+#include <stdlib.h>
+
+static inline void *kmalloc (size_t sz, int ignored) { return malloc (sz); }
+static inline void kfree (void *ptr) { free (ptr); }
+static inline void kfree_s (void *ptr, size_t sz) { free (ptr); }
+#define free(x) kfree(x) /* just don't ask */
+
+
+typedef struct kmem_cache_s kmem_cache_t;
+
+#define SLAB_HWCACHE_ALIGN 0 /* flag everybody uses */
+#define SLAB_ATOMIC 0
+
+
+extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
+ void (*)(void *, kmem_cache_t *, unsigned long),
+ void (*)(void *, kmem_cache_t *, unsigned long));
+extern void *kmem_cache_alloc(kmem_cache_t *, int);
+extern void kmem_cache_free(kmem_cache_t *, void *);
+
+
+#endif
diff --git a/pfinet/glue-include/linux/mm.h b/pfinet/glue-include/linux/mm.h
new file mode 100644
index 00000000..546776e8
--- /dev/null
+++ b/pfinet/glue-include/linux/mm.h
@@ -0,0 +1,38 @@
+#ifndef _HACK_MM_H_
+#define _HACK_MM_H_
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+/* All memory addresses are presumptively valid, because they are
+ all internal. */
+#define verify_area(a,b,c) 0
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 0
+#define GFP_ATOMIC 0
+#define GFP_KERNEL 0
+#define GFP_BUFFER 0
+#define __GFP_WAIT 0
+
+#include <mach.h>
+#include <sys/mman.h>
+#include <stdint.h>
+
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+
+/* The one use of this is by net/ipv4/tcp.c::tcp_init, which
+ uses the power of two above `num_physpages >> (20 - PAGE_SHIFT)'
+ as a starting point and halves from there the number of pages
+ it tries to allocate for the hash table of TCP connections. */
+#define num_physpages (64 << 20 >> PAGE_SHIFT) /* XXX calculate for 32MB */
+
+static inline uintptr_t
+__get_free_pages (int gfp_mask, unsigned long int order)
+{
+ void *ptr = mmap (0, PAGE_SIZE << order,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ return ptr == MAP_FAILED ? 0 : (uintptr_t) ptr;
+}
+
+#endif
diff --git a/pfinet/linux/param.h b/pfinet/glue-include/linux/param.h
index 39efaf0d..39efaf0d 100644
--- a/pfinet/linux/param.h
+++ b/pfinet/glue-include/linux/param.h
diff --git a/pfinet/glue-include/linux/personality.h b/pfinet/glue-include/linux/personality.h
new file mode 100644
index 00000000..9e218435
--- /dev/null
+++ b/pfinet/glue-include/linux/personality.h
@@ -0,0 +1 @@
+#include <linux/linkage.h>
diff --git a/pfinet/glue-include/linux/poll.h b/pfinet/glue-include/linux/poll.h
new file mode 100644
index 00000000..b21c3c71
--- /dev/null
+++ b/pfinet/glue-include/linux/poll.h
@@ -0,0 +1,24 @@
+#ifndef _HACK_POLL_H_
+#define _HACK_POLL_H_
+
+#include <hurd/hurd_types.h>
+
+#define POLLIN SELECT_READ
+#define POLLRDNORM SELECT_READ
+#define POLLOUT SELECT_WRITE
+#define POLLWRNORM SELECT_WRITE
+#define POLLWRBAND SELECT_WRITE
+#define POLLPRI SELECT_URG
+#define POLLERR SELECT_READ | SELECT_WRITE
+#define POLLHUP SELECT_READ
+
+typedef struct poll_table_struct { } poll_table;
+
+#include <linux/sched.h>
+
+static inline void
+poll_wait(struct file * filp, struct wait_queue ** wait_address, poll_table *p)
+{
+}
+
+#endif
diff --git a/pfinet/linux/config.h b/pfinet/glue-include/linux/proc_fs.h
index e69de29b..e69de29b 100644
--- a/pfinet/linux/config.h
+++ b/pfinet/glue-include/linux/proc_fs.h
diff --git a/pfinet/glue-include/linux/sched.h b/pfinet/glue-include/linux/sched.h
new file mode 100644
index 00000000..d4cae42a
--- /dev/null
+++ b/pfinet/glue-include/linux/sched.h
@@ -0,0 +1,204 @@
+#ifndef _HACK_SCHED_H
+#define _HACK_SCHED_H
+
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <mach.h>
+#include <hurd/hurd_types.h>
+#include <limits.h>
+#include <assert.h>
+#include <cthreads.h>
+
+#include "mapped-time.h"
+
+#include <linux/binfmts.h>
+#include <linux/personality.h>
+#include <linux/tasks.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/times.h>
+#include <linux/timex.h>
+
+#include <asm/system.h>
+#if 0
+#include <asm/semaphore.h>
+#include <asm/page.h>
+
+#include <linux/smp.h>
+#include <linux/tty.h>
+#include <linux/sem.h>
+#include <linux/signal.h>
+#include <linux/securebits.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+
+
+#define jiffies (fetch_jiffies ())
+
+#define current (&current_contents)
+extern struct task_struct current_contents;
+struct task_struct
+{
+ uid_t pgrp, pid;
+ int flags;
+ int timeout;
+ int signal;
+ int blocked;
+ int state, policy;
+ int isroot;
+ char *comm;
+ struct wait_queue **next_wait;
+};
+
+static inline void
+prepare_current (int isroot)
+{
+ current->signal = 0;
+ current->isroot = isroot;
+ /* All other members are constant zero and ignored. */
+}
+#define become_task(user) prepare_current ((user)->isroot)
+#define become_task_protid(protid) prepare_current ((protid)->isroot)
+
+#define signal_pending(current) ((current)->signal)
+
+/* FLAGS in task_struct's. */
+#define PF_EXITING 1
+/* STATE in task_struct's. */
+#define TASK_INTERRUPTIBLE 0
+#define TASK_RUNNING 0
+/* policy in task_struct's. */
+#define SCHED_YIELD 0
+
+struct semaphore { };
+
+
+extern inline int
+suser ()
+{
+ return current->isroot;
+};
+
+extern inline int
+capable(int cap)
+{
+ return current->isroot;
+}
+
+
+extern struct mutex global_lock;
+
+static inline void
+interruptible_sleep_on (struct wait_queue **p)
+{
+ struct condition **condp = (void *) p, *c;
+ int isroot;
+ struct wait_queue **next_wait;
+
+ c = *condp;
+ if (c == 0)
+ {
+ c = malloc (sizeof **condp);
+ assert (c);
+ condition_init (c);
+ *condp = c;
+ }
+
+ isroot = current->isroot; /* This is our context that needs switched. */
+ next_wait = current->next_wait; /* This too, for multiple schedule calls. */
+ current->next_wait = 0;
+ if (hurd_condition_wait (c, &global_lock))
+ current->signal = 1; /* We got cancelled, mark it for later. */
+ current->isroot = isroot; /* Switch back to our context. */
+ current->next_wait = next_wait;
+}
+#define sleep_on interruptible_sleep_on
+
+static inline void
+wake_up_interruptible (struct wait_queue **p)
+{
+ struct condition **condp = (void *) p, *c = *condp;
+ if (c)
+ condition_broadcast (c);
+}
+#define wake_up wake_up_interruptible
+
+
+static inline void
+add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ assert (current->next_wait == 0);
+ current->next_wait = p;
+}
+
+static inline void
+remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ assert (current->next_wait == p);
+ current->next_wait = 0;
+}
+
+static inline void
+schedule (void)
+{
+ assert (current->next_wait);
+ interruptible_sleep_on (current->next_wait);
+}
+
+static inline void
+process_schedule_timeout (unsigned long data)
+{
+ struct wait_queue **sleep = (struct wait_queue **) data;
+
+ wake_up_interruptible (sleep);
+}
+
+static inline long
+schedule_timeout (long timeout)
+{
+ long expire = timeout + jiffies;
+ struct timer_list timer;
+ static struct wait_queue *sleep = 0; /* See comment in wait.h why this suffices. */
+ /* TODO: but free it !! */
+
+ init_timer (&timer);
+ timer.expires = expire;
+ timer.data = (unsigned long) &sleep;
+ timer.function = process_schedule_timeout;
+ add_timer (&timer);
+
+ interruptible_sleep_on (&sleep);
+ if (signal_pending (current))
+ {
+ /* We were canceled. */
+ del_timer (&timer);
+ expire -= jiffies;
+ if (expire >= 0)
+ return expire;
+ else
+ return 0;
+ }
+ return 0;
+}
+
+#define MAX_SCHEDULE_TIMEOUT LONG_MAX
+
+/* This function is used only to send SIGPIPE to the current
+ task. In all such cases, EPIPE is returned anyhow. In the
+ Hurd, servers are not responsible for SIGPIPE; the library
+ does that itself upon receiving EPIPE. So we can just
+ NOP such calls. */
+extern inline int
+send_sig (u_long signo, struct task_struct *task, int priv)
+{
+ assert (signo == SIGPIPE);
+ assert (task == current);
+ return 0;
+}
+
+
+#endif
diff --git a/pfinet/linux/sockios.h b/pfinet/glue-include/linux/slab.h
index e69de29b..e69de29b 100644
--- a/pfinet/linux/sockios.h
+++ b/pfinet/glue-include/linux/slab.h
diff --git a/pfinet/glue-include/linux/socket.h b/pfinet/glue-include/linux/socket.h
new file mode 100644
index 00000000..820ed00f
--- /dev/null
+++ b/pfinet/glue-include/linux/socket.h
@@ -0,0 +1,152 @@
+#ifndef _HACK_SOCKET_H_
+#define _HACK_SOCKET_H_
+
+#include <linux/types.h>
+#include <asm/system.h>
+
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+
+
+/* #define IP_MAX_MEMBERSHIPS 10 */
+
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+
+#define SOPRI_INTERACTIVE 0
+#define SOPRI_NORMAL 1
+#define SOPRI_BACKGROUND 2
+
+#define SOL_IP IPPROTO_IP
+#define SOL_TCP IPPROTO_TCP
+#define SOL_IPV6 IPPROTO_IPV6
+#define SOL_ICMPV6 IPPROTO_ICMPV6
+#define SOL_RAW IPPROTO_RAW
+
+/* IP options */
+#define IP_PKTINFO 190
+#define IP_PKTOPTIONS 191
+#define IP_MTU_DISCOVER 192
+#define IP_RECVERR 193
+#define IP_RECVTTL 194
+#define IP_RECVTOS 195
+#define IP_MTU 196
+#define IP_ROUTER_ALERT 197
+
+
+/* TCP options */
+#define TCP_NODELAY 1
+#define TCP_MAXSEG 2
+#define TCP_CORK 3
+
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+
+#define SO_PASSCRED 190
+#define SO_PEERCRED 191
+#define SO_BSDCOMPAT 192
+
+/* Maximum queue length specifiable by listen. */
+#ifndef SOMAXCONN
+#define SOMAXCONN 128
+#endif
+
+#ifndef CMSG_DATA
+#define msg_control msg_accrights
+#define msg_controllen msg_accrightslen
+struct cmsghdr { int cmsg_garbage; };
+#define cmsg_len cmsg_garbage
+#define cmsg_type cmsg_garbage
+#define cmsg_level cmsg_garbage
+static inline int
+put_cmsg(struct msghdr *msg, int level, int type, int len, void *data)
+{ return 0; }
+#define CMSG_FIRSTHDR(msg) (0)
+#define CMSG_NXTHDR(msg, cmsg) (0)
+#define CMSG_DATA(cmsg) (0)
+#define CMSG_ALIGN(size) (0)
+#define CMSG_LEN(size) (0)
+#else
+static inline int
+put_cmsg(struct msghdr *msg, int level, int type, int len, void *data)
+{ return 0; }
+#endif
+
+#ifndef MSG_NOSIGNAL
+# warning "http://lists.gnu.org/archive/html/bug-hurd/2008-10/msg00007.html"
+# define MSG_NOSIGNAL 0
+#endif
+#define MSG_ERRQUEUE 0
+
+/* There is no SOCK_PACKET, it is a bad bad thing. This chicanery is
+ because the one use of it is a comparison against a `short int' value;
+ using a value outside the range of that type ensures that the comparison
+ will always fail, and in fact it and the dead code will get optimized
+ out entirely at compile time. */
+#define SOCK_PACKET ((int)((uint32_t)USHRT_MAX) * 2)
+#define PF_PACKET 0
+
+#ifndef UIO_MAXIOV
+#define UIO_MAXIOV 4 /* 1 would do */
+#endif
+
+
+struct ucred {
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+};
+
+
+extern inline int /* Does not modify IOV. */
+memcpy_fromiovecend (unsigned char *kdata, struct iovec *iov,
+ int offset, int len)
+{
+ assert (offset + len <= iov->iov_len);
+ memcpy (kdata, iov->iov_base + offset, len);
+ return 0;
+}
+extern inline int /* Modifies IOV to consume LEN bytes. */
+memcpy_fromiovec (unsigned char *kdata, struct iovec *iov, int len)
+{
+ assert (len <= iov->iov_len);
+ memcpy (kdata, iov->iov_base, len);
+ iov->iov_base += len;
+ iov->iov_len -= len;
+ return 0;
+}
+extern inline void /* Modifies IOV to consume LEN bytes. */
+memcpy_tokerneliovec (struct iovec *iov, unsigned char *kdata, int len)
+{
+ assert (len <= iov->iov_len);
+ memcpy (iov->iov_base, kdata, len);
+ iov->iov_base += len;
+ iov->iov_len -= len;
+}
+extern inline int /* Modifies IOV to consume LEN bytes. */
+memcpy_toiovec (struct iovec *iov, unsigned char *kdata, int len)
+{
+ memcpy_tokerneliovec (iov, kdata, len);
+ return 0;
+}
+
+extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
+ struct iovec *iov,
+ int offset,
+ unsigned int len, int *csump);
+
+static inline int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
+{
+ abort ();
+ return 0;
+}
+#if 0
+extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
+extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
+#endif
+
+
+#endif
diff --git a/pfinet/linux/un.h b/pfinet/glue-include/linux/sockios.h
index e69de29b..e69de29b 100644
--- a/pfinet/linux/un.h
+++ b/pfinet/glue-include/linux/sockios.h
diff --git a/pfinet/linux/stat.h b/pfinet/glue-include/linux/stat.h
index 5165069b..5165069b 100644
--- a/pfinet/linux/stat.h
+++ b/pfinet/glue-include/linux/stat.h
diff --git a/pfinet/linux/string.h b/pfinet/glue-include/linux/string.h
index 3b2f5900..3b2f5900 100644
--- a/pfinet/linux/string.h
+++ b/pfinet/glue-include/linux/string.h
diff --git a/pfinet/linux/termios.h b/pfinet/glue-include/linux/termios.h
index 9e269565..9e269565 100644
--- a/pfinet/linux/termios.h
+++ b/pfinet/glue-include/linux/termios.h
diff --git a/pfinet/glue-include/linux/time.h b/pfinet/glue-include/linux/time.h
new file mode 100644
index 00000000..4973c4ab
--- /dev/null
+++ b/pfinet/glue-include/linux/time.h
@@ -0,0 +1,10 @@
+#ifndef _HACK_TIME_H_
+#define _HACK_TIME_H_
+
+#include <sys/time.h>
+#include "mapped-time.h"
+
+#define do_gettimeofday(tp) maptime_read (mapped_time, (tp))
+#define get_fast_time(tp) maptime_read (mapped_time, (tp))
+
+#endif
diff --git a/pfinet/linux/timer.h b/pfinet/glue-include/linux/timer.h
index 2458746e..cc8dec80 100644
--- a/pfinet/linux/timer.h
+++ b/pfinet/glue-include/linux/timer.h
@@ -11,10 +11,10 @@ enum tstate
TIMER_EXPIRED,
TIMER_FUNCTION_RUNNING,
};
-
+
struct timer_list
{
- struct timer_list *next, **prevp;
+ struct timer_list *next, **prev; /* things like to test "T->prev != NULL" */
unsigned long expires;
unsigned long data;
void (*function)(unsigned long);
@@ -22,6 +22,15 @@ struct timer_list
void add_timer (struct timer_list *);
int del_timer (struct timer_list *);
+void mod_timer (struct timer_list *, unsigned long);
void init_timer (struct timer_list *);
+
+#define time_after(a,b) ((long)(b) - (long)(a) < 0)
+#define time_before(a,b) time_after(b,a)
+
+#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0)
+#define time_before_eq(a,b) time_after_eq(b,a)
+
+
#endif
diff --git a/pfinet/glue-include/linux/timex.h b/pfinet/glue-include/linux/timex.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/pfinet/glue-include/linux/timex.h
diff --git a/pfinet/glue-include/linux/types.h b/pfinet/glue-include/linux/types.h
new file mode 100644
index 00000000..604b8b14
--- /dev/null
+++ b/pfinet/glue-include/linux/types.h
@@ -0,0 +1,31 @@
+#ifndef _HACK_TYPES_H
+#define _HACK_TYPES_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+
+#define __u8 uint8_t
+#define __u16 uint16_t
+#define __u32 uint32_t
+#define __u64 uint64_t
+#define __s8 int8_t
+#define __s16 int16_t
+#define __s32 int32_t
+#define __s64 int64_t
+#define u8 uint8_t
+#define u16 uint16_t
+#define u32 uint32_t
+#define u64 uint64_t
+#define s8 int8_t
+#define s16 int16_t
+#define s32 int32_t
+#define s64 int64_t
+
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+
+#endif
diff --git a/pfinet/glue-include/linux/un.h b/pfinet/glue-include/linux/un.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/pfinet/glue-include/linux/un.h
diff --git a/pfinet/glue-include/linux/version.h b/pfinet/glue-include/linux/version.h
new file mode 100644
index 00000000..3a49a481
--- /dev/null
+++ b/pfinet/glue-include/linux/version.h
@@ -0,0 +1,3 @@
+#define UTS_RELEASE "2.1.12"
+#define LINUX_VERSION_CODE KERNEL_VERSION(2,1,12)
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
diff --git a/pfinet/glue-include/linux/wait.h b/pfinet/glue-include/linux/wait.h
new file mode 100644
index 00000000..7ee962dc
--- /dev/null
+++ b/pfinet/glue-include/linux/wait.h
@@ -0,0 +1,32 @@
+#ifndef _HACK_WAIT_H_
+#define _HACK_WAIT_H_
+
+#include <cthreads.h>
+
+/* This data structure actually represents one waiter on a wait queue,
+ and waiters always expect to initialize it with { current, NULL }.
+ The actual wait queue is a `struct wait_queue *' stored somewhere.
+ We ignore these structures provided by the waiters entirely.
+ In the `struct wait_queue *' that is the "head of the wait queue" slot,
+ we actually store a `struct condition *' pointing to malloc'd storage. */
+
+struct wait_queue
+{
+ struct task_struct *task; /* current */
+ struct wait_queue *next; /* NULL */
+};
+
+
+struct select_table_elt
+{
+ struct condition *dependent_condition;
+ struct select_table_elt *next;
+};
+
+typedef struct select_table_struct
+{
+ struct condition master_condition;
+ struct select_table_elt *head;
+} select_table;
+
+#endif
diff --git a/pfinet/iioctl-ops.c b/pfinet/iioctl-ops.c
new file mode 100644
index 00000000..c0dd6d5f
--- /dev/null
+++ b/pfinet/iioctl-ops.c
@@ -0,0 +1,400 @@
+/*
+ Copyright (C) 2000, 2007 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "pfinet.h"
+
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+
+#include "iioctl_S.h"
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <mach/notify.h>
+#include <sys/mman.h>
+#include <hurd/fshelp.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/sock.h>
+
+extern struct notifier_block *netdev_chain;
+
+/* devinet.c */
+extern error_t configure_device (struct device *dev, uint32_t addr,
+ uint32_t netmask, uint32_t peer,
+ uint32_t broadcast);
+extern void inquire_device (struct device *dev, uint32_t *addr,
+ uint32_t *netmask, uint32_t *peer,
+ uint32_t *broadcast);
+
+/* Truncate name, take the global lock and find device with this name. */
+struct device *get_dev (char *name)
+{
+ char ifname[16];
+ struct device *dev;
+
+ memcpy (ifname, name, IFNAMSIZ-1);
+ ifname[IFNAMSIZ-1] = 0;
+
+ __mutex_lock (&global_lock);
+
+ for (dev = dev_base; dev; dev = dev->next)
+ if (strcmp (dev->name, ifname) == 0)
+ break;
+
+ return dev;
+}
+
+enum siocgif_type
+{
+ ADDR,
+ NETMASK,
+ DSTADDR,
+ BRDADDR
+};
+
+#define SIOCGIF(name, type) \
+ kern_return_t \
+ S_iioctl_siocgif##name (io_t port, \
+ ifname_t ifnam, \
+ sockaddr_t *addr) \
+ { \
+ return siocgifXaddr (port, ifnam, addr, type); \
+ }
+
+/* Get some sockaddr type of info. */
+static kern_return_t
+siocgifXaddr (io_t port,
+ ifname_t ifnam,
+ sockaddr_t *addr,
+ enum siocgif_type type)
+{
+ struct sock_user *user = begin_using_socket_port (port);
+ error_t err = 0;
+ struct device *dev;
+ struct sockaddr_in *sin = (struct sockaddr_in *) addr;
+ uint32_t addrs[4];
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ dev = get_dev (ifnam);
+ if (!dev)
+ err = ENODEV;
+ else if (user->sock->sk->family != AF_INET)
+ err = EINVAL;
+ else
+ {
+ sin->sin_family = AF_INET;
+
+ inquire_device (dev, &addrs[0], &addrs[1], &addrs[2], &addrs[3]);
+ sin->sin_addr.s_addr = addrs[type];
+ }
+
+ __mutex_unlock (&global_lock);
+ end_using_socket_port (user);
+ return err;
+}
+
+#define SIOCSIF(name, type) \
+ kern_return_t \
+ S_iioctl_siocsif##name (io_t port, \
+ ifname_t ifnam, \
+ sockaddr_t addr) \
+ { \
+ return siocsifXaddr (port, ifnam, &addr, type); \
+ }
+
+/* Set some sockaddr type of info. */
+static kern_return_t
+siocsifXaddr (io_t port,
+ ifname_t ifnam,
+ sockaddr_t *addr,
+ enum siocgif_type type)
+{
+ struct sock_user *user = begin_using_socket_port(port);
+ error_t err = 0;
+ struct device *dev;
+ struct sockaddr_in *sin = (struct sockaddr_in *) addr;
+ uint32_t addrs[4];
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ dev = get_dev (ifnam);
+
+ if (!user->isroot)
+ err = EPERM;
+ else if (!dev)
+ err = ENODEV;
+ else if (sin->sin_family != AF_INET)
+ err = EINVAL;
+ else if (user->sock->sk->family != AF_INET)
+ err = EINVAL;
+ else
+ {
+ inquire_device (dev, &addrs[0], &addrs[1], &addrs[2], &addrs[3]);
+ addrs[type] = sin->sin_addr.s_addr;
+ err = configure_device (dev, addrs[0], addrs[1], addrs[2], addrs[3]);
+ }
+
+ __mutex_unlock (&global_lock);
+ end_using_socket_port (user);
+ return err;
+}
+
+/* 12 SIOCSIFADDR -- Set address of a network interface. */
+SIOCSIF (addr, ADDR);
+
+/* 14 SIOCSIFDSTADDR -- Set point-to-point (peer) address of a network interface. */
+SIOCSIF (dstaddr, DSTADDR);
+
+/* 16 SIOCSIFFLAGS -- Set flags of a network interface. */
+kern_return_t
+S_iioctl_siocsifflags (io_t port,
+ ifname_t ifnam,
+ short flags)
+{
+ struct sock_user *user = begin_using_socket_port (port);
+ error_t err = 0;
+ struct device *dev;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ dev = get_dev (ifnam);
+
+ if (!user->isroot)
+ err = EPERM;
+ else if (!dev)
+ err = ENODEV;
+ else
+ {
+ err = dev_change_flags (dev, flags);
+ if (!err)
+ err = ethernet_change_flags (dev, flags);
+ }
+
+ __mutex_unlock (&global_lock);
+ end_using_socket_port (user);
+ return err;
+}
+
+/* 17 SIOCGIFFLAGS -- Get flags of a network interface. */
+kern_return_t
+S_iioctl_siocgifflags (io_t port,
+ char *name,
+ short *flags)
+{
+ error_t err = 0;
+ struct device *dev;
+
+ dev = get_dev (name);
+ if (!dev)
+ err = ENODEV;
+ else
+ {
+ *flags = dev->flags;
+ }
+ __mutex_unlock (&global_lock);
+ return err;
+}
+
+/* 19 SIOCSIFBRDADDR -- Set broadcast address of a network interface. */
+SIOCSIF (brdaddr, BRDADDR);
+
+/* 22 SIOCSIFNETMASK -- Set netmask of a network interface. */
+SIOCSIF (netmask, NETMASK);
+
+/* 23 SIOCGIFMETRIC -- Get metric of a network interface. */
+kern_return_t
+S_iioctl_siocgifmetric (io_t port,
+ ifname_t ifnam,
+ int *metric)
+{
+ error_t err = 0;
+ struct device *dev;
+
+ dev = get_dev (ifnam);
+ if (!dev)
+ err = ENODEV;
+ else
+ {
+ *metric = 0; /* Not supported. */
+ }
+ __mutex_unlock (&global_lock);
+ return err;
+}
+
+/* 24 SIOCSIFMETRIC -- Set metric of a network interface. */
+kern_return_t
+S_iioctl_siocsifmetric (io_t port,
+ ifname_t ifnam,
+ int metric)
+{
+ return EOPNOTSUPP;
+}
+
+/* 25 SIOCDIFADDR -- Delete interface address. */
+kern_return_t
+S_iioctl_siocdifaddr (io_t port,
+ ifname_t ifnam,
+ sockaddr_t addr)
+{
+ return EOPNOTSUPP;
+}
+
+/* 33 SIOCGIFADDR -- Get address of a network interface. */
+SIOCGIF (addr, ADDR);
+
+/* 34 SIOCGIFDSTADDR -- Get point-to-point address of a network interface. */
+SIOCGIF (dstaddr, DSTADDR);
+
+/* 35 SIOCGIFBRDADDR -- Get broadcast address of a network interface. */
+SIOCGIF (brdaddr, BRDADDR);
+
+/* 37 SIOCGIFNETMASK -- Get netmask of a network interface. */
+SIOCGIF (netmask, NETMASK);
+
+/* 39 SIOCGIFHWADDR -- Get the hardware address of a network interface. */
+error_t
+S_iioctl_siocgifhwaddr (io_t port,
+ ifname_t ifname,
+ sockaddr_t *addr)
+{
+ error_t err = 0;
+ struct device *dev;
+
+ if (!port)
+ return EOPNOTSUPP;
+
+ dev = get_dev (ifname);
+ if (!dev)
+ err = ENODEV;
+ else
+ {
+ memcpy (addr->sa_data, dev->dev_addr, dev->addr_len);
+ addr->sa_family = dev->type;
+ }
+
+ __mutex_unlock (&global_lock);
+ return err;
+}
+
+/* 51 SIOCGIFMTU -- Get mtu of a network interface. */
+error_t
+S_iioctl_siocgifmtu (io_t port,
+ ifname_t ifnam,
+ int *mtu)
+{
+ error_t err = 0;
+ struct device *dev;
+
+ dev = get_dev (ifnam);
+ if (!dev)
+ err = ENODEV;
+ else
+ {
+ *mtu = dev->mtu;
+ }
+ __mutex_unlock (&global_lock);
+ return err;
+}
+
+/* 51 SIOCSIFMTU -- Set mtu of a network interface. */
+error_t
+S_iioctl_siocsifmtu (io_t port,
+ ifname_t ifnam,
+ int mtu)
+{
+ struct sock_user *user = begin_using_socket_port (port);
+ error_t err = 0;
+ struct device *dev;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ dev = get_dev (ifnam);
+
+ if (!user->isroot)
+ err = EPERM;
+ if (!dev)
+ err = ENODEV;
+ else if (mtu <= 0)
+ err = EINVAL;
+ else
+ {
+ if (dev->change_mtu)
+ dev->change_mtu (dev, mtu);
+ else
+ dev->mtu = mtu;
+
+ notifier_call_chain (&netdev_chain, NETDEV_CHANGEMTU, dev);
+ }
+
+ __mutex_unlock (&global_lock);
+ end_using_socket_port (user);
+ return err;
+}
+
+/* 100 SIOCGIFINDEX -- Get index number of a network interface. */
+error_t
+S_iioctl_siocgifindex (io_t port,
+ ifname_t ifnam,
+ int *index)
+{
+ error_t err = 0;
+ struct device *dev;
+
+ dev = get_dev (ifnam);
+ if (!dev)
+ err = ENODEV;
+ else
+ {
+ *index = dev->ifindex;
+ }
+ __mutex_unlock (&global_lock);
+ return err;
+}
+
+/* 101 SIOCGIFNAME -- Get name of a network interface from index number. */
+error_t
+S_iioctl_siocgifname (io_t port,
+ ifname_t ifnam,
+ int *index)
+{
+ error_t err = 0;
+ struct device *dev;
+
+ __mutex_lock (&global_lock);
+ dev = dev_get_by_index (*index);
+ if (!dev)
+ err = ENODEV;
+ else
+ {
+ strncpy (ifnam, dev->name, IFNAMSIZ);
+ ifnam[IFNAMSIZ-1] = '\0';
+ }
+ __mutex_unlock (&global_lock);
+
+ return err;
+}
diff --git a/pfinet/io-ops.c b/pfinet/io-ops.c
index 72895065..ef8d8513 100644
--- a/pfinet/io-ops.c
+++ b/pfinet/io-ops.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,97,98,99,2000,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -19,78 +19,105 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include "pfinet.h"
+
+#include <linux/wait.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
#include "io_S.h"
#include <netinet/in.h>
-#include <linux/wait.h>
-#include <linux-inet/sock.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <mach/notify.h>
+#include <sys/mman.h>
error_t
S_io_write (struct sock_user *user,
char *data,
- u_int datalen,
+ size_t datalen,
off_t offset,
mach_msg_type_number_t *amount)
{
error_t err;
-
+ struct iovec iov = { data, datalen };
+ struct msghdr m = { msg_name: 0, msg_namelen: 0, msg_flags: 0,
+ msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 };
+
if (!user)
return EOPNOTSUPP;
- mutex_lock (&global_lock);
+ __mutex_lock (&global_lock);
become_task (user);
- err = (*user->sock->ops->write) (user->sock, data, datalen,
- user->sock->userflags);
- mutex_unlock (&global_lock);
+ if (user->sock->flags & O_NONBLOCK)
+ m.msg_flags |= MSG_DONTWAIT;
+ err = (*user->sock->ops->sendmsg) (user->sock, &m, datalen, 0);
+ __mutex_unlock (&global_lock);
- if (err >= 0)
+ if (err < 0)
+ err = -err;
+ else
{
*amount = err;
err = 0;
}
-
+
return err;
}
error_t
S_io_read (struct sock_user *user,
char **data,
- u_int *datalen,
+ size_t *datalen,
off_t offset,
mach_msg_type_number_t amount)
{
error_t err;
int alloced = 0;
+ struct iovec iov;
+ struct msghdr m = { msg_name: 0, msg_namelen: 0, msg_flags: 0,
+ msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 };
if (!user)
return EOPNOTSUPP;
-
+
/* Instead of this, we should peek and the socket and only
allocate as much as necessary. */
if (amount > *datalen)
{
- vm_allocate (mach_task_self (), (vm_address_t *)data, amount, 1);
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ /* Should check whether errno is indeed ENOMEM --
+ but this can't be done in a straightforward way,
+ because the glue headers #undef errno. */
+ return ENOMEM;
alloced = 1;
}
-
- mutex_lock (&global_lock);
+
+ iov.iov_base = *data;
+ iov.iov_len = amount;
+
+ __mutex_lock (&global_lock);
become_task (user);
- err = (*user->sock->ops->read) (user->sock, *data, amount,
- user->sock->userflags);
- mutex_unlock (&global_lock);
-
+ err = (*user->sock->ops->recvmsg) (user->sock, &m, amount,
+ ((user->sock->flags & O_NONBLOCK)
+ ? MSG_DONTWAIT : 0),
+ 0);
+ __mutex_unlock (&global_lock);
+
if (err < 0)
- err = -err;
+ {
+ err = -err;
+ if (alloced)
+ munmap (*data, amount);
+ }
else
{
*datalen = err;
if (alloced && round_page (*datalen) < round_page (amount))
- vm_deallocate (mach_task_self (),
- (vm_address_t) *data + round_page (*datalen),
- round_page (amount) - round_page (*datalen));
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
err = 0;
}
return err;
@@ -111,19 +138,19 @@ S_io_readable (struct sock_user *user,
{
struct sock *sk;
error_t err;
-
+
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
become_task (user);
-
+
/* We need to avoid calling the Linux ioctl routines,
so here is a rather ugly break of modularity. */
- sk = (struct sock *) user->sock->data;
+ sk = user->sock->sk;
err = 0;
-
+
/* Linux's af_inet.c ioctl routine just calls the protocol-specific
ioctl routine; it's those routines that we need to simulate. So
this switch corresponds to the initialization of SK->prot in
@@ -132,17 +159,9 @@ S_io_readable (struct sock_user *user,
{
case SOCK_STREAM:
case SOCK_SEQPACKET:
- /* These guts are copied from tcp.c:tcp_ioctl. */
- if (sk->state == TCP_LISTEN)
- err = EINVAL;
- else
- {
- sk->inuse = 1;
- *amount = tcp_readable (sk);
- release_sock (sk);
- }
+ err = tcp_tiocinq (sk, amount);
break;
-
+
case SOCK_DGRAM:
/* These guts are copied from udp.c:udp_ioctl (TIOCINQ). */
if (sk->state == TCP_LISTEN)
@@ -152,14 +171,14 @@ S_io_readable (struct sock_user *user,
*amount = (skb_peek (&sk->receive_queue)
? : &((struct sk_buff){}))->len;
break;
-
+
case SOCK_RAW:
default:
err = EOPNOTSUPP;
break;
}
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
return err;
}
@@ -169,13 +188,13 @@ S_io_set_all_openmodes (struct sock_user *user,
{
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
if (bits & O_NONBLOCK)
- user->sock->userflags |= O_NONBLOCK;
+ user->sock->flags |= O_NONBLOCK;
else
- user->sock->userflags &= ~O_NONBLOCK;
- mutex_unlock (&global_lock);
+ user->sock->flags &= ~O_NONBLOCK;
+ __mutex_unlock (&global_lock);
return 0;
}
@@ -184,22 +203,22 @@ S_io_get_openmodes (struct sock_user *user,
int *bits)
{
struct sock *sk;
-
+
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
- sk = user->sock->data;
-
+
+ __mutex_lock (&global_lock);
+ sk = user->sock->sk;
+
*bits = 0;
if (!(sk->shutdown & SEND_SHUTDOWN))
*bits |= O_WRITE;
if (!(sk->shutdown & RCV_SHUTDOWN))
*bits |= O_READ;
- if (user->sock->userflags & O_NONBLOCK)
+ if (user->sock->flags & O_NONBLOCK)
*bits |= O_NONBLOCK;
-
- mutex_unlock (&global_lock);
+
+ __mutex_unlock (&global_lock);
return 0;
}
@@ -209,11 +228,11 @@ S_io_set_some_openmodes (struct sock_user *user,
{
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
if (bits & O_NONBLOCK)
- user->sock->userflags |= O_NONBLOCK;
- mutex_unlock (&global_lock);
+ user->sock->flags |= O_NONBLOCK;
+ __mutex_unlock (&global_lock);
return 0;
}
@@ -223,114 +242,63 @@ S_io_clear_some_openmodes (struct sock_user *user,
{
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
if (bits & O_NONBLOCK)
- user->sock->userflags &= ~O_NONBLOCK;
- mutex_unlock (&global_lock);
+ user->sock->flags &= ~O_NONBLOCK;
+ __mutex_unlock (&global_lock);
return 0;
}
error_t
S_io_select (struct sock_user *user,
- mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
int *select_type)
{
- int avail = 0;
- int cancel = 0;
- int requested_notify = 0;
- select_table table;
- struct select_table_elt *elt, *nxt;
+ const int want = *select_type;
+ int avail;
if (!user)
return EOPNOTSUPP;
- mutex_lock (&global_lock);
+ __mutex_lock (&global_lock);
become_task (user);
- /* In Linux, this means (supposedly) that I/O will never be possible.
+ /* In Linux, this means (supposedly) that I/O will never be possible.
That's a lose, so prevent it from happening. */
- assert (user->sock->ops->select);
+ assert (user->sock->ops->poll);
- /* The select function returns one if the specified I/O type is
- immediately possible. If it returns zero, then it is not
- immediately possible, and it has called select_wait. Eventually
- it will wakeup the wait queue specified in the select_wait call;
- at that point we should retry the call. */
-
- for (;;)
+ avail = (*user->sock->ops->poll) ((void *) 0xdeadbeef,
+ user->sock,
+ (void *) 0xdeadbead);
+ if ((avail & want) == 0)
{
- condition_init (&table.master_condition);
- table.head = 0;
-
- if (*select_type & SELECT_READ)
- avail |= ((*user->sock->ops->select) (user->sock, SEL_IN, &table)
- ? SELECT_READ : 0);
- if (*select_type & SELECT_WRITE)
- avail |= ((*user->sock->ops->select) (user->sock, SEL_OUT, &table)
- ? SELECT_WRITE : 0);
- if (*select_type & SELECT_URG)
- avail |= ((*user->sock->ops->select) (user->sock, SEL_EX, &table)
- ? SELECT_URG : 0);
-
- if (!avail)
+ ports_interrupt_self_on_notification (user, reply,
+ MACH_NOTIFY_DEAD_NAME);
+
+ do
{
- if (! requested_notify)
+ /* Block until we are woken or cancelled. */
+ interruptible_sleep_on (user->sock->sk->sleep);
+ if (signal_pending (current)) /* This means we were cancelled. */
{
- ports_interrupt_self_on_notification (user, reply,
- MACH_NOTIFY_DEAD_NAME);
- requested_notify = 1;
+ __mutex_unlock (&global_lock);
+ return EINTR;
}
- cancel = hurd_condition_wait (&table.master_condition, &global_lock);
- }
-
- /* Drop the conditions implications and structures allocated in the
- select table. */
- for (elt = table.head; elt; elt = nxt)
- {
- condition_unimplies (elt->dependent_condition,
- &table.master_condition);
- nxt = elt->next;
- free (elt);
- }
-
- if (avail)
- {
- mutex_unlock (&global_lock);
- *select_type = avail;
- return 0;
- }
-
- if (cancel)
- {
- mutex_unlock (&global_lock);
- return EINTR;
+ avail = (*user->sock->ops->poll) ((void *) 0xdeadbeef,
+ user->sock,
+ (void *) 0xdeadbead);
}
+ while ((avail & want) == 0);
}
-}
-/* Establish that the condition in WAIT_ADDRESS should imply
- the condition in P. Also, add us to the queue in P so
- that the relation can be undone at the proper time. */
-void
-select_wait (struct wait_queue **wait_address, select_table *p)
-{
- struct select_table_elt *elt;
-
- /* tcp.c happens to use an uninitalized wait queue;
- so this special hack is for that. */
- if (*wait_address == 0)
- {
- *wait_address = malloc (sizeof (struct wait_queue));
- condition_init (&(*wait_address)->c);
- }
+ /* We got something. */
+ *select_type = avail;
- elt = malloc (sizeof (struct select_table_elt));
- elt->dependent_condition = &(*wait_address)->c;
- elt->next = p->head;
- p->head = elt;
+ __mutex_unlock (&global_lock);
- condition_implies (elt->dependent_condition, &p->master_condition);
+ return 0;
}
error_t
@@ -339,14 +307,16 @@ S_io_stat (struct sock_user *user,
{
if (!user)
return EOPNOTSUPP;
-
+
bzero (st, sizeof (struct stat));
-
+
st->st_fstype = FSTYPE_SOCKET;
st->st_fsid = getpid ();
- st->st_ino = (ino_t) user->sock; /* why not? */
-
+ st->st_ino = user->sock->st_ino;
+
+ st->st_mode = S_IFSOCK | ACCESSPERMS;
st->st_blksize = 512; /* ???? */
+
return 0;
}
@@ -357,36 +327,34 @@ S_io_reauthenticate (struct sock_user *user,
struct sock_user *newuser;
uid_t gubuf[20], ggbuf[20], aubuf[20], agbuf[20];
uid_t *gen_uids, *gen_gids, *aux_uids, *aux_gids;
- u_int genuidlen, gengidlen, auxuidlen, auxgidlen;
+ size_t genuidlen, gengidlen, auxuidlen, auxgidlen;
error_t err;
- int i;
+ size_t i, j;
auth_t auth;
mach_port_t newright;
if (!user)
return EOPNOTSUPP;
-
+
genuidlen = gengidlen = auxuidlen = auxgidlen = 20;
gen_uids = gubuf;
gen_gids = ggbuf;
aux_uids = aubuf;
aux_gids = agbuf;
- mutex_lock (&global_lock);
- newuser = make_sock_user (user->sock, 0, 1);
-
+ __mutex_lock (&global_lock);
+ newuser = make_sock_user (user->sock, 0, 1, 0);
+
auth = getauth ();
- newright = ports_get_right (newuser);
- err = mach_port_insert_right (mach_task_self (), newright, newright,
- MACH_MSG_TYPE_MAKE_SEND);
- assert_perror (err);
+ newright = ports_get_send_right (newuser);
+ assert (newright != MACH_PORT_NULL);
do
- err = auth_server_authenticate (auth,
+ err = auth_server_authenticate (auth,
rend,
MACH_MSG_TYPE_COPY_SEND,
newright,
MACH_MSG_TYPE_COPY_SEND,
- &gen_uids, &genuidlen,
+ &gen_uids, &genuidlen,
&aux_uids, &auxuidlen,
&gen_gids, &gengidlen,
&aux_gids, &auxgidlen);
@@ -398,29 +366,32 @@ S_io_reauthenticate (struct sock_user *user,
if (err)
newuser->isroot = 0;
else
+ /* Check permission as fshelp_isowner would do. */
for (i = 0; i < genuidlen; i++)
- if (gen_uids[i] == 0)
- newuser->isroot = 1;
+ {
+ if (gen_uids[i] == 0 || gen_uids[i] == pfinet_owner)
+ newuser->isroot = 1;
+ if (gen_uids[i] == pfinet_group)
+ for (j = 0; j < gengidlen; j++)
+ if (gen_gids[j] == pfinet_group)
+ newuser->isroot = 1;
+ }
mach_port_move_member (mach_task_self (), newuser->pi.port_right,
pfinet_bucket->portset);
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
ports_port_deref (newuser);
if (gubuf != gen_uids)
- vm_deallocate (mach_task_self (), (u_int) gen_uids,
- genuidlen * sizeof (uid_t));
+ munmap (gen_uids, genuidlen * sizeof (uid_t));
if (ggbuf != gen_gids)
- vm_deallocate (mach_task_self (), (u_int) gen_gids,
- gengidlen * sizeof (uid_t));
+ munmap (gen_gids, gengidlen * sizeof (uid_t));
if (aubuf != aux_uids)
- vm_deallocate (mach_task_self (), (u_int) aux_uids,
- auxuidlen * sizeof (uid_t));
+ munmap (aux_uids, auxuidlen * sizeof (uid_t));
if (agbuf != aux_gids)
- vm_deallocate (mach_task_self (), (u_int) aux_gids,
- auxgidlen * sizeof (uid_t));
+ munmap (aux_gids, auxgidlen * sizeof (uid_t));
return 0;
}
@@ -429,31 +400,36 @@ error_t
S_io_restrict_auth (struct sock_user *user,
mach_port_t *newobject,
mach_msg_type_name_t *newobject_type,
- uid_t *uids,
- u_int uidslen,
- uid_t *gids,
- u_int gidslen)
+ uid_t *uids, size_t uidslen,
+ uid_t *gids, size_t gidslen)
{
struct sock_user *newuser;
- int i = 0;
+ int i, j;
int isroot;
if (!user)
return EOPNOTSUPP;
- mutex_lock (&global_lock);
+ __mutex_lock (&global_lock);
isroot = 0;
if (user->isroot)
- for (i = 0; i < uidslen && !isroot; i++)
- if (uids[i] == 0)
- isroot = 1;
-
- newuser = make_sock_user (user->sock, isroot, 0);
+ /* Check permission as fshelp_isowner would do. */
+ for (i = 0; i < uidslen; i++)
+ {
+ if (uids[i] == 0 || uids[i] == pfinet_owner)
+ isroot = 1;
+ if (uids[i] == pfinet_group)
+ for (j = 0; j < gidslen; j++)
+ if (gids[j] == pfinet_group)
+ isroot = 1;
+ }
+
+ newuser = make_sock_user (user->sock, isroot, 0, 0);
*newobject = ports_get_right (newuser);
*newobject_type = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (newuser);
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
return 0;
}
@@ -465,13 +441,13 @@ S_io_duplicate (struct sock_user *user,
struct sock_user *newuser;
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
- newuser = make_sock_user (user->sock, user->isroot, 0);
+
+ __mutex_lock (&global_lock);
+ newuser = make_sock_user (user->sock, user->isroot, 0, 0);
*newobject = ports_get_right (newuser);
*newobject_type = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (newuser);
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
return 0;
}
@@ -481,21 +457,21 @@ S_io_identity (struct sock_user *user,
mach_msg_type_name_t *idtype,
mach_port_t *fsys,
mach_msg_type_name_t *fsystype,
- int *fileno)
+ ino_t *fileno)
{
error_t err;
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
if (user->sock->identity == MACH_PORT_NULL)
{
err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
&user->sock->identity);
if (err)
{
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
return err;
}
}
@@ -504,12 +480,19 @@ S_io_identity (struct sock_user *user,
*idtype = MACH_MSG_TYPE_MAKE_SEND;
*fsys = fsys_identity;
*fsystype = MACH_MSG_TYPE_MAKE_SEND;
- *fileno = (ino_t) user->sock; /* matches S_io_stat above */
-
- mutex_unlock (&global_lock);
+ *fileno = user->sock->st_ino;
+
+ __mutex_unlock (&global_lock);
return 0;
}
+error_t
+S_io_revoke (struct sock_user *user)
+{
+ /* XXX maybe we should try */
+ return EOPNOTSUPP;
+}
+
error_t
@@ -534,8 +517,8 @@ S_io_get_owner (struct sock_user *user,
{
return EOPNOTSUPP;
}
-
-error_t
+
+error_t
S_io_get_icky_async_id (struct sock_user *user,
mach_port_t *id,
mach_msg_type_name_t *idtype)
@@ -632,4 +615,3 @@ S_io_sigio (struct sock_user *user)
{
return EOPNOTSUPP;
}
-
diff --git a/pfinet/kmem_cache.c b/pfinet/kmem_cache.c
new file mode 100644
index 00000000..8c73c9bf
--- /dev/null
+++ b/pfinet/kmem_cache.c
@@ -0,0 +1,88 @@
+/* Hack replacement for Linux's kmem_cache_t allocator
+ Copyright (C) 2000 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Hack replacement for Linux's kmem_cache_t allocator, using plain malloc
+ and cthreads locking. The locking here is probably unnecessary. */
+
+#include <cthreads.h>
+#include <linux/malloc.h>
+
+struct kmem_cache_s
+{
+ struct mutex lock;
+
+ void *freelist;
+ size_t item_size;
+
+ void (*ctor) (void *, kmem_cache_t *, unsigned long);
+ void (*dtor) (void *, kmem_cache_t *, unsigned long);
+};
+
+kmem_cache_t *
+kmem_cache_create (const char *name, size_t item_size,
+ size_t something, unsigned long flags,
+ void (*ctor) (void *, kmem_cache_t *, unsigned long),
+ void (*dtor) (void *, kmem_cache_t *, unsigned long))
+{
+ kmem_cache_t *new = malloc (sizeof *new);
+ if (!new)
+ return 0;
+ mutex_init (&new->lock);
+ new->freelist = 0;
+ new->item_size = item_size;
+ new->ctor = ctor;
+ new->dtor = dtor;
+
+ return new;
+}
+
+
+void *
+kmem_cache_alloc (kmem_cache_t *cache, int flags)
+{
+ void *p;
+
+ __mutex_lock (&cache->lock);
+ p = cache->freelist;
+ if (p != 0) {
+ cache->freelist = *(void **)(p + cache->item_size);
+ __mutex_unlock (&cache->lock);
+ return p;
+ }
+ __mutex_unlock (&cache->lock);
+
+ p = malloc (cache->item_size + sizeof (void *));
+ if (p && cache->ctor)
+ (*cache->ctor) (p, cache, flags);
+ return p;
+}
+
+
+void
+kmem_cache_free (kmem_cache_t *cache, void *p)
+{
+ void **const nextp = (void **) (p + cache->item_size);
+
+ __mutex_lock (&cache->lock);
+ *nextp = cache->freelist;
+ cache->freelist = p;
+ __mutex_unlock (&cache->lock);
+
+ /* XXX eventually destroy some... */
+}
diff --git a/pfinet/linux-inet/af_inet.c b/pfinet/linux-inet/af_inet.c
deleted file mode 100644
index d20c8bfb..00000000
--- a/pfinet/linux-inet/af_inet.c
+++ /dev/null
@@ -1,1578 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * AF_INET protocol family socket handler.
- *
- * Version: @(#)af_inet.c (from sock.c) 1.0.17 06/02/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Florian La Roche, <flla@stud.uni-sb.de>
- * Alan Cox, <A.Cox@swansea.ac.uk>
- *
- * Changes (see also sock.c)
- *
- * A.N.Kuznetsov : Socket death error in accept().
- * John Richardson : Fix non blocking error in connect()
- * so sockets that fail to connect
- * don't return -EINPROGRESS.
- * Alan Cox : Asynchronous I/O support
- * Alan Cox : Keep correct socket pointer on sock structures
- * when accept() ed
- * Alan Cox : Semantics of SO_LINGER aren't state moved
- * to close when you look carefully. With
- * this fixed and the accept bug fixed
- * some RPC stuff seems happier.
- * Niibe Yutaka : 4.4BSD style write async I/O
- * Alan Cox,
- * Tony Gale : Fixed reuse semantics.
- * Alan Cox : bind() shouldn't abort existing but dead
- * sockets. Stops FTP netin:.. I hope.
- * Alan Cox : bind() works correctly for RAW sockets. Note
- * that FreeBSD at least is broken in this respect
- * so be careful with compatibility tests...
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "rarp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "raw.h"
-#include "icmp.h"
-
-#define min(a,b) ((a)<(b)?(a):(b))
-
-extern struct proto packet_prot;
-
-
-/*
- * See if a socket number is in use.
- */
-
-static int sk_inuse(struct proto *prot, int num)
-{
- struct sock *sk;
-
- for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )];
- sk != NULL; sk=sk->next)
- {
- if (sk->num == num)
- return(1);
- }
- return(0);
-}
-
-
-/*
- * Pick a new socket number
- */
-
-unsigned short get_new_socknum(struct proto *prot, unsigned short base)
-{
- static int start=0;
-
- /*
- * Used to cycle through the port numbers so the
- * chances of a confused connection drop.
- */
-
- int i, j;
- int best = 0;
- int size = 32767; /* a big num. */
- struct sock *sk;
-
- if (base == 0)
- base = PROT_SOCK+1+(start % 1024);
- if (base <= PROT_SOCK)
- {
- base += PROT_SOCK+(start % 1024);
- }
-
- /* Now look through the entire array and try to find an empty ptr. */
- for(i=0; i < SOCK_ARRAY_SIZE; i++)
- {
- j = 0;
- sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)];
- while(sk != NULL)
- {
- sk = sk->next;
- j++;
- }
- if (j == 0)
- {
- start =(i+1+start )%1024;
- return(i+base+1);
- }
- if (j < size)
- {
- best = i;
- size = j;
- }
- }
-
- /* Now make sure the one we want is not in use. */
-
- while(sk_inuse(prot, base +best+1))
- {
- best += SOCK_ARRAY_SIZE;
- }
- return(best+base+1);
-}
-
-/*
- * Add a socket into the socket tables by number.
- */
-
-void put_sock(unsigned short num, struct sock *sk)
-{
- struct sock *sk1;
- struct sock *sk2;
- int mask;
- unsigned long flags;
-
- sk->num = num;
- sk->next = NULL;
- num = num &(SOCK_ARRAY_SIZE -1);
-
- /* We can't have an interrupt re-enter here. */
- save_flags(flags);
- cli();
-
- sk->prot->inuse += 1;
- if (sk->prot->highestinuse < sk->prot->inuse)
- sk->prot->highestinuse = sk->prot->inuse;
-
- if (sk->prot->sock_array[num] == NULL)
- {
- sk->prot->sock_array[num] = sk;
- restore_flags(flags);
- return;
- }
- restore_flags(flags);
- for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask)
- {
- if ((mask & sk->saddr) &&
- (mask & sk->saddr) != (mask & 0xffffffff))
- {
- mask = mask << 8;
- break;
- }
- }
- cli();
- sk1 = sk->prot->sock_array[num];
- for(sk2 = sk1; sk2 != NULL; sk2=sk2->next)
- {
- if (!(sk2->saddr & mask))
- {
- if (sk2 == sk1)
- {
- sk->next = sk->prot->sock_array[num];
- sk->prot->sock_array[num] = sk;
- sti();
- return;
- }
- sk->next = sk2;
- sk1->next= sk;
- sti();
- return;
- }
- sk1 = sk2;
- }
-
- /* Goes at the end. */
- sk->next = NULL;
- sk1->next = sk;
- sti();
-}
-
-/*
- * Remove a socket from the socket tables.
- */
-
-static void remove_sock(struct sock *sk1)
-{
- struct sock *sk2;
- unsigned long flags;
-
- if (!sk1->prot)
- {
- printk("sock.c: remove_sock: sk1->prot == NULL\n");
- return;
- }
-
- /* We can't have this changing out from under us. */
- save_flags(flags);
- cli();
- sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];
- if (sk2 == sk1)
- {
- sk1->prot->inuse -= 1;
- sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;
- restore_flags(flags);
- return;
- }
-
- while(sk2 && sk2->next != sk1)
- {
- sk2 = sk2->next;
- }
-
- if (sk2)
- {
- sk1->prot->inuse -= 1;
- sk2->next = sk1->next;
- restore_flags(flags);
- return;
- }
- restore_flags(flags);
-}
-
-/*
- * Destroy an AF_INET socket
- */
-
-void destroy_sock(struct sock *sk)
-{
- struct sk_buff *skb;
-
- sk->inuse = 1; /* just to be safe. */
-
- /* In case it's sleeping somewhere. */
- if (!sk->dead)
- sk->write_space(sk);
-
- remove_sock(sk);
-
- /* Now we can no longer get new packets. */
- delete_timer(sk);
- /* Nor send them */
- del_timer(&sk->retransmit_timer);
-
- while ((skb = tcp_dequeue_partial(sk)) != NULL) {
- IS_SKB(skb);
- kfree_skb(skb, FREE_WRITE);
- }
-
- /* Cleanup up the write buffer. */
- while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
- IS_SKB(skb);
- kfree_skb(skb, FREE_WRITE);
- }
-
- /*
- * Don't discard received data until the user side kills its
- * half of the socket.
- */
-
- if (sk->dead)
- {
- while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
- {
- /*
- * This will take care of closing sockets that were
- * listening and didn't accept everything.
- */
- if (skb->sk != NULL && skb->sk != sk)
- {
- IS_SKB(skb);
- skb->sk->dead = 1;
- skb->sk->prot->close(skb->sk, 0);
- }
- IS_SKB(skb);
- kfree_skb(skb, FREE_READ);
- }
- }
-
- /* Now we need to clean up the send head. */
- cli();
- for(skb = sk->send_head; skb != NULL; )
- {
- struct sk_buff *skb2;
-
- /*
- * We need to remove skb from the transmit queue,
- * or maybe the arp queue.
- */
- if (skb->next && skb->prev) {
-/* printk("destroy_sock: unlinked skb\n");*/
- IS_SKB(skb);
- skb_unlink(skb);
- }
- skb->dev = NULL;
- skb2 = skb->link3;
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- }
- sk->send_head = NULL;
- sti();
-
- /* And now the backlog. */
- while((skb=skb_dequeue(&sk->back_log))!=NULL)
- {
- /* this should never happen. */
-/* printk("cleaning back_log\n");*/
- kfree_skb(skb, FREE_READ);
- }
-
- /* Now if it has a half accepted/ closed socket. */
- if (sk->pair)
- {
- sk->pair->dead = 1;
- sk->pair->prot->close(sk->pair, 0);
- sk->pair = NULL;
- }
-
- /*
- * Now if everything is gone we can free the socket
- * structure, otherwise we need to keep it around until
- * everything is gone.
- */
-
- if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
- {
- kfree_s((void *)sk,sizeof(*sk));
- }
- else
- {
- /* this should never happen. */
- /* actually it can if an ack has just been sent. */
- sk->destroy = 1;
- sk->ack_backlog = 0;
- sk->inuse = 0;
- reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
- }
-}
-
-/*
- * The routines beyond this point handle the behaviour of an AF_INET
- * socket object. Mostly it punts to the subprotocols of IP to do
- * the work.
- */
-
-static int inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
-
- switch(cmd)
- {
- case F_SETOWN:
- /*
- * This is a little restrictive, but it's the only
- * way to make sure that you can't send a sigurg to
- * another process.
- */
- if (!suser() && current->pgrp != -arg &&
- current->pid != arg) return(-EPERM);
- sk->proc = arg;
- return(0);
- case F_GETOWN:
- return(sk->proc);
- default:
- return(-EINVAL);
- }
-}
-
-/*
- * Set socket options on an inet socket.
- */
-
-static int inet_setsockopt(struct socket *sock, int level, int optname,
- char *optval, int optlen)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (level == SOL_SOCKET)
- return sock_setsockopt(sk,level,optname,optval,optlen);
- if (sk->prot->setsockopt==NULL)
- return(-EOPNOTSUPP);
- else
- return sk->prot->setsockopt(sk,level,optname,optval,optlen);
-}
-
-/*
- * Get a socket option on an AF_INET socket.
- */
-
-static int inet_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (level == SOL_SOCKET)
- return sock_getsockopt(sk,level,optname,optval,optlen);
- if(sk->prot->getsockopt==NULL)
- return(-EOPNOTSUPP);
- else
- return sk->prot->getsockopt(sk,level,optname,optval,optlen);
-}
-
-/*
- * Automatically bind an unbound socket.
- */
-
-static int inet_autobind(struct sock *sk)
-{
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
- return 0;
-}
-
-/*
- * Move a socket into listening state.
- */
-
-static int inet_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = (struct sock *) sock->data;
-
- if(inet_autobind(sk)!=0)
- return -EAGAIN;
-
- /* We might as well re use these. */
- /*
- * note that the backlog is "unsigned char", so truncate it
- * somewhere. We might as well truncate it to what everybody
- * else does..
- */
- if (backlog > 5)
- backlog = 5;
- sk->max_ack_backlog = backlog;
- if (sk->state != TCP_LISTEN)
- {
- sk->ack_backlog = 0;
- sk->state = TCP_LISTEN;
- }
- return(0);
-}
-
-/*
- * Default callbacks for user INET sockets. These just wake up
- * the user owning the socket.
- */
-
-static void def_callback1(struct sock *sk)
-{
- if(!sk->dead)
- wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk,int len)
-{
- if(!sk->dead)
- {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 1);
- }
-}
-
-static void def_callback3(struct sock *sk)
-{
- if(!sk->dead)
- {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 2);
- }
-}
-
-/*
- * Create an inet socket.
- *
- * FIXME: Gcc would generate much better code if we set the parameters
- * up in in-memory structure order. Gcc68K even more so
- */
-
-static int inet_create(struct socket *sock, int protocol)
-{
- struct sock *sk;
- struct proto *prot;
- int err;
-
- sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
- if (sk == NULL)
- return(-ENOBUFS);
- sk->num = 0;
- sk->reuse = 0;
- switch(sock->type)
- {
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- if (protocol && protocol != IPPROTO_TCP)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- protocol = IPPROTO_TCP;
- sk->no_check = TCP_NO_CHECK;
- prot = &tcp_prot;
- break;
-
- case SOCK_DGRAM:
- if (protocol && protocol != IPPROTO_UDP)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- protocol = IPPROTO_UDP;
- sk->no_check = UDP_NO_CHECK;
- prot=&udp_prot;
- break;
-
- case SOCK_RAW:
- if (!suser())
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPERM);
- }
- if (!protocol)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- prot = &raw_prot;
- sk->reuse = 1;
- sk->no_check = 0; /*
- * Doesn't matter no checksum is
- * performed anyway.
- */
- sk->num = protocol;
- break;
-
-#ifndef _HURD_
- case SOCK_PACKET:
- if (!suser())
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPERM);
- }
- if (!protocol)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- prot = &packet_prot;
- sk->reuse = 1;
- sk->no_check = 0; /* Doesn't matter no checksum is
- * performed anyway.
- */
- sk->num = protocol;
- break;
-#endif
-
- default:
- kfree_s((void *)sk, sizeof(*sk));
- return(-ESOCKTNOSUPPORT);
- }
- sk->socket = sock;
-#ifdef CONFIG_TCP_NAGLE_OFF
- sk->nonagle = 1;
-#else
- sk->nonagle = 0;
-#endif
- sk->type = sock->type;
- sk->stamp.tv_sec=0;
- sk->protocol = protocol;
- sk->wmem_alloc = 0;
- sk->rmem_alloc = 0;
- sk->sndbuf = SK_WMEM_MAX;
- sk->rcvbuf = SK_RMEM_MAX;
- sk->pair = NULL;
- sk->opt = NULL;
- sk->write_seq = 0;
- sk->acked_seq = 0;
- sk->copied_seq = 0;
- sk->fin_seq = 0;
- sk->urg_seq = 0;
- sk->urg_data = 0;
- sk->proc = 0;
- sk->rtt = 0; /*TCP_WRITE_TIME << 3;*/
- sk->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/
- sk->mdev = 0;
- sk->backoff = 0;
- sk->packets_out = 0;
- sk->cong_window = 1; /* start with only sending one packet at a time. */
- sk->cong_count = 0;
- sk->ssthresh = 0;
- sk->max_window = 0;
- sk->urginline = 0;
- sk->intr = 0;
- sk->linger = 0;
- sk->destroy = 0;
- sk->priority = 1;
- sk->shutdown = 0;
- sk->keepopen = 0;
- sk->zapped = 0;
- sk->done = 0;
- sk->ack_backlog = 0;
- sk->window = 0;
- sk->bytes_rcv = 0;
- sk->state = TCP_CLOSE;
- sk->dead = 0;
- sk->ack_timed = 0;
- sk->partial = NULL;
- sk->user_mss = 0;
- sk->debug = 0;
-
- /* this is how many unacked bytes we will accept for this socket. */
- sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
-
- /* how many packets we should send before forcing an ack.
- if this is set to zero it is the same as sk->delay_acks = 0 */
- sk->max_ack_backlog = 0;
- sk->inuse = 0;
- sk->delay_acks = 0;
- skb_queue_head_init(&sk->write_queue);
- skb_queue_head_init(&sk->receive_queue);
- sk->mtu = 576;
- sk->prot = prot;
- sk->sleep = sock->wait;
- sk->daddr = 0;
- sk->saddr = 0 /* ip_my_addr() */;
- sk->err = 0;
- sk->next = NULL;
- sk->pair = NULL;
- sk->send_tail = NULL;
- sk->send_head = NULL;
- sk->timeout = 0;
- sk->broadcast = 0;
- sk->localroute = 0;
- init_timer(&sk->timer);
- init_timer(&sk->retransmit_timer);
- sk->timer.data = (unsigned long)sk;
- sk->timer.function = &net_timer;
- skb_queue_head_init(&sk->back_log);
- sk->blog = 0;
- sock->data =(void *) sk;
- sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
- sk->dummy_th.res1=0;
- sk->dummy_th.res2=0;
- sk->dummy_th.urg_ptr = 0;
- sk->dummy_th.fin = 0;
- sk->dummy_th.syn = 0;
- sk->dummy_th.rst = 0;
- sk->dummy_th.psh = 0;
- sk->dummy_th.ack = 0;
- sk->dummy_th.urg = 0;
- sk->dummy_th.dest = 0;
- sk->ip_tos=0;
- sk->ip_ttl=64;
-#ifdef CONFIG_IP_MULTICAST
- sk->ip_mc_loop=1;
- sk->ip_mc_ttl=1;
- *sk->ip_mc_name=0;
- sk->ip_mc_list=NULL;
-#endif
-
- sk->state_change = def_callback1;
- sk->data_ready = def_callback2;
- sk->write_space = def_callback3;
- sk->error_report = def_callback1;
-
- if (sk->num)
- {
- /*
- * It assumes that any protocol which allows
- * the user to assign a number at socket
- * creation time automatically
- * shares.
- */
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- if (sk->prot->init)
- {
- err = sk->prot->init(sk);
- if (err != 0)
- {
- destroy_sock(sk);
- return(err);
- }
- }
- return(0);
-}
-
-
-/*
- * Duplicate a socket.
- */
-
-static int inet_dup(struct socket *newsock, struct socket *oldsock)
-{
- return(inet_create(newsock,((struct sock *)(oldsock->data))->protocol));
-}
-
-/*
- * Return 1 if we still have things to send in our buffers.
- */
-static inline int closing(struct sock * sk)
-{
- switch (sk->state) {
- case TCP_FIN_WAIT1:
- case TCP_CLOSING:
- case TCP_LAST_ACK:
- return 1;
- }
- return 0;
-}
-
-
-/*
- * The peer socket should always be NULL (or else). When we call this
- * function we are destroying the object and from then on nobody
- * should refer to it.
- */
-
-static int inet_release(struct socket *sock, struct socket *peer)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (sk == NULL)
- return(0);
-
- sk->state_change(sk);
-
- /* Start closing the connection. This may take a while. */
-
-#ifdef CONFIG_IP_MULTICAST
- /* Applications forget to leave groups before exiting */
- ip_mc_drop_socket(sk);
-#endif
- /*
- * If linger is set, we don't return until the close
- * is complete. Other wise we return immediately. The
- * actually closing is done the same either way.
- *
- * If the close is due to the process exiting, we never
- * linger..
- */
-
- if (sk->linger == 0 || (current->flags & PF_EXITING))
- {
- sk->prot->close(sk,0);
- sk->dead = 1;
- }
- else
- {
- sk->prot->close(sk, 0);
- cli();
- if (sk->lingertime)
- current->timeout = jiffies + HZ*sk->lingertime;
- while(closing(sk) && current->timeout>0)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- break;
-#if 0
- /* not working now - closes can't be restarted */
- sti();
- current->timeout=0;
- return(-ERESTARTSYS);
-#endif
- }
- }
- current->timeout=0;
- sti();
- sk->dead = 1;
- }
- sk->inuse = 1;
-
- /* This will destroy it. */
- release_sock(sk);
- sock->data = NULL;
- sk->socket = NULL;
- return(0);
-}
-
-
-/* this needs to be changed to disallow
- the rebinding of sockets. What error
- should it return? */
-
-static int inet_bind(struct socket *sock, struct sockaddr *uaddr,
- int addr_len)
-{
- struct sockaddr_in *addr=(struct sockaddr_in *)uaddr;
- struct sock *sk=(struct sock *)sock->data, *sk2;
- unsigned short snum = 0 /* Stoopid compiler.. this IS ok */;
- int chk_addr_ret;
-
- /* check this error. */
- if (sk->state != TCP_CLOSE)
- return(-EIO);
- if(addr_len<sizeof(struct sockaddr_in))
- return -EINVAL;
-
- if(sock->type != SOCK_RAW)
- {
- if (sk->num != 0)
- return(-EINVAL);
-
- snum = ntohs(addr->sin_port);
-
- /*
- * We can't just leave the socket bound wherever it is, it might
- * be bound to a privileged port. However, since there seems to
- * be a bug here, we will leave it if the port is not privileged.
- */
- if (snum == 0)
- {
- snum = get_new_socknum(sk->prot, 0);
- }
- if (snum < PROT_SOCK && !suser())
- return(-EACCES);
- }
-
- chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr);
- if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST)
- return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
-
- if (chk_addr_ret || addr->sin_addr.s_addr == 0)
- sk->saddr = addr->sin_addr.s_addr;
-
- if(sock->type != SOCK_RAW)
- {
- /* Make sure we are allowed to bind here. */
- cli();
- for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];
- sk2 != NULL; sk2 = sk2->next)
- {
- /* should be below! */
- if (sk2->num != snum)
- continue;
- if (!sk->reuse)
- {
- sti();
- return(-EADDRINUSE);
- }
-
- if (sk2->num != snum)
- continue; /* more than one */
- if (sk2->saddr != sk->saddr)
- continue; /* socket per slot ! -FB */
- if (!sk2->reuse || sk2->state==TCP_LISTEN)
- {
- sti();
- return(-EADDRINUSE);
- }
- }
- sti();
-
- remove_sock(sk);
- put_sock(snum, sk);
- sk->dummy_th.source = ntohs(sk->num);
- sk->daddr = 0;
- sk->dummy_th.dest = 0;
- }
- return(0);
-}
-
-/*
- * Handle sk->err properly. The cli/sti matter.
- */
-
-static int inet_error(struct sock *sk)
-{
- unsigned long flags;
- int err;
- save_flags(flags);
- cli();
- err=sk->err;
- sk->err=0;
- restore_flags(flags);
- return -err;
-}
-
-/*
- * Connect to a remote host. There is regrettably still a little
- * TCP 'magic' in here.
- */
-
-static int inet_connect(struct socket *sock, struct sockaddr * uaddr,
- int addr_len, int flags)
-{
- struct sock *sk=(struct sock *)sock->data;
- int err;
- sock->conn = NULL;
-
- if (sock->state == SS_CONNECTING && tcp_connected(sk->state))
- {
- sock->state = SS_CONNECTED;
- /* Connection completing after a connect/EINPROGRESS/select/connect */
- return 0; /* Rock and roll */
- }
-
- if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK))
- return -EALREADY; /* Connecting is currently in progress */
-
- if (sock->state != SS_CONNECTING)
- {
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return(-EAGAIN);
- if (sk->prot->connect == NULL)
- return(-EOPNOTSUPP);
- err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len);
- if (err < 0)
- return(err);
- sock->state = SS_CONNECTING;
- }
-
- if (sk->state > TCP_FIN_WAIT2 && sock->state==SS_CONNECTING)
- {
- sock->state=SS_UNCONNECTED;
- cli();
- err=sk->err;
- sk->err=0;
- sti();
- return -err;
- }
-
- if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK))
- return(-EINPROGRESS);
-
- cli(); /* avoid the race condition */
- while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- return(-ERESTARTSYS);
- }
- /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with
- icmp error packets wanting to close a tcp or udp socket. */
- if(sk->err && sk->protocol == IPPROTO_TCP)
- {
- sti();
- sock->state = SS_UNCONNECTED;
- err = -sk->err;
- sk->err=0;
- return err; /* set by tcp_err() */
- }
- }
- sti();
- sock->state = SS_CONNECTED;
-
- if (sk->state != TCP_ESTABLISHED && sk->err)
- {
- sock->state = SS_UNCONNECTED;
- err=sk->err;
- sk->err=0;
- return(-err);
- }
- return(0);
-}
-
-
-static int inet_socketpair(struct socket *sock1, struct socket *sock2)
-{
- return(-EOPNOTSUPP);
-}
-
-
-/*
- * Accept a pending connection. The TCP layer now gives BSD semantics.
- */
-
-static int inet_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- struct sock *sk1, *sk2;
- int err;
-
- sk1 = (struct sock *) sock->data;
-
- /*
- * We've been passed an extra socket.
- * We need to free it up because the tcp module creates
- * its own when it accepts one.
- */
- if (newsock->data)
- {
- struct sock *sk=(struct sock *)newsock->data;
- newsock->data=NULL;
- sk->dead = 1;
- destroy_sock(sk);
- }
-
- if (sk1->prot->accept == NULL)
- return(-EOPNOTSUPP);
-
- /* Restore the state if we have been interrupted, and then returned. */
- if (sk1->pair != NULL )
- {
- sk2 = sk1->pair;
- sk1->pair = NULL;
- }
- else
- {
- sk2 = sk1->prot->accept(sk1,flags);
- if (sk2 == NULL)
- {
- if (sk1->err <= 0)
- printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n");
- err=sk1->err;
- sk1->err=0;
- return(-err);
- }
- }
- newsock->data = (void *)sk2;
- sk2->sleep = newsock->wait;
- sk2->socket = newsock;
- newsock->conn = NULL;
- if (flags & O_NONBLOCK)
- return(0);
-
- cli(); /* avoid the race. */
- while(sk2->state == TCP_SYN_RECV)
- {
- interruptible_sleep_on(sk2->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- sk1->pair = sk2;
- sk2->sleep = NULL;
- sk2->socket=NULL;
- newsock->data = NULL;
- return(-ERESTARTSYS);
- }
- }
- sti();
-
- if (sk2->state != TCP_ESTABLISHED && sk2->err > 0)
- {
- err = -sk2->err;
- sk2->err=0;
- sk2->dead=1; /* ANK */
- destroy_sock(sk2);
- newsock->data = NULL;
- return(err);
- }
- newsock->state = SS_CONNECTED;
- return(0);
-}
-
-
-/*
- * This does both peername and sockname.
- */
-
-static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
-{
- struct sockaddr_in *sin=(struct sockaddr_in *)uaddr;
- struct sock *sk;
-
- sin->sin_family = AF_INET;
- sk = (struct sock *) sock->data;
- if (peer)
- {
- if (!tcp_connected(sk->state))
- return(-ENOTCONN);
- sin->sin_port = sk->dummy_th.dest;
- sin->sin_addr.s_addr = sk->daddr;
- }
- else
- {
- sin->sin_port = sk->dummy_th.source;
- if (sk->saddr == 0)
- sin->sin_addr.s_addr = ip_my_addr();
- else
- sin->sin_addr.s_addr = sk->saddr;
- }
- *uaddr_len = sizeof(*sin);
- return(0);
-}
-
-
-/*
- * The assorted BSD I/O operations
- */
-
-static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sin, int *addr_len )
-{
- struct sock *sk = (struct sock *) sock->data;
-
- if (sk->prot->recvfrom == NULL)
- return(-EOPNOTSUPP);
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return(-EAGAIN);
- return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags,
- (struct sockaddr_in*)sin, addr_len));
-}
-
-
-static int inet_recv(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags)
-{
- /* BSD explicitly states these are the same - so we do it this way to be sure */
- return inet_recvfrom(sock,ubuf,size,noblock,flags,NULL,NULL);
-}
-
-static int inet_read(struct socket *sock, char *ubuf, int size, int noblock)
-{
- struct sock *sk = (struct sock *) sock->data;
-
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk))
- return(-EAGAIN);
- return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, 0));
-}
-
-static int inet_send(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return(-EAGAIN);
- return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));
-}
-
-static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)
-{
- return inet_send(sock,ubuf,size,noblock,0);
-}
-
-static int inet_sendto(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sin, int addr_len)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- if (sk->prot->sendto == NULL)
- return(-EOPNOTSUPP);
- if(sk->err)
- return inet_error(sk);
- /* We may need to bind the socket. */
- if(inet_autobind(sk)!=0)
- return -EAGAIN;
- return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags,
- (struct sockaddr_in *)sin, addr_len));
-}
-
-
-static int inet_shutdown(struct socket *sock, int how)
-{
- struct sock *sk=(struct sock*)sock->data;
-
- /*
- * This should really check to make sure
- * the socket is a TCP socket. (WHY AC...)
- */
- how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
- 1->2 bit 2 snds.
- 2->3 */
- if ((how & ~SHUTDOWN_MASK) || how==0) /* MAXINT->0 */
- return(-EINVAL);
- if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
- sock->state = SS_CONNECTED;
- if (!tcp_connected(sk->state))
- return(-ENOTCONN);
- sk->shutdown |= how;
- if (sk->prot->shutdown)
- sk->prot->shutdown(sk, how);
- return(0);
-}
-
-
-static int inet_select(struct socket *sock, int sel_type, select_table *wait )
-{
- struct sock *sk=(struct sock *) sock->data;
- if (sk->prot->select == NULL)
- {
- return(0);
- }
- return(sk->prot->select(sk, sel_type, wait));
-}
-
-#ifndef _HURD_
-
-/*
- * ioctl() calls you can issue on an INET socket. Most of these are
- * device configuration and stuff and very rarely used. Some ioctls
- * pass on to the socket itself.
- *
- * NOTE: I like the idea of a module for the config stuff. ie ifconfig
- * loads the devconfigure module does its configuring and unloads it.
- * There's a good 20K of config code hanging around the kernel.
- */
-
-static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk=(struct sock *)sock->data;
- int err;
-
- switch(cmd)
- {
- case FIOSETOWN:
- case SIOCSPGRP:
- err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
- if(err)
- return err;
- sk->proc = get_fs_long((int *) arg);
- return(0);
- case FIOGETOWN:
- case SIOCGPGRP:
- err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
- if(err)
- return err;
- put_fs_long(sk->proc,(int *)arg);
- return(0);
- case SIOCGSTAMP:
- if(sk->stamp.tv_sec==0)
- return -ENOENT;
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval));
- if(err)
- return err;
- memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval));
- return 0;
- case SIOCADDRT: case SIOCADDRTOLD:
- case SIOCDELRT: case SIOCDELRTOLD:
- return(ip_rt_ioctl(cmd,(void *) arg));
- case SIOCDARP:
- case SIOCGARP:
- case SIOCSARP:
- return(arp_ioctl(cmd,(void *) arg));
-#ifdef CONFIG_INET_RARP
- case SIOCDRARP:
- case SIOCGRARP:
- case SIOCSRARP:
- return(rarp_ioctl(cmd,(void *) arg));
-#endif
- case SIOCGIFCONF:
- case SIOCGIFFLAGS:
- case SIOCSIFFLAGS:
- case SIOCGIFADDR:
- case SIOCSIFADDR:
-
-/* begin multicast support change */
- case SIOCADDMULTI:
- case SIOCDELMULTI:
-/* end multicast support change */
-
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- case SIOCGIFMEM:
- case SIOCSIFMEM:
- case SIOCGIFMTU:
- case SIOCSIFMTU:
- case SIOCSIFLINK:
- case SIOCGIFHWADDR:
- case SIOCSIFHWADDR:
- case OLD_SIOCGIFHWADDR:
- case SIOCSIFMAP:
- case SIOCGIFMAP:
- case SIOCSIFSLAVE:
- case SIOCGIFSLAVE:
- return(dev_ioctl(cmd,(void *) arg));
-
- default:
- if ((cmd >= SIOCDEVPRIVATE) &&
- (cmd <= (SIOCDEVPRIVATE + 15)))
- return(dev_ioctl(cmd,(void *) arg));
-
- if (sk->prot->ioctl==NULL)
- return(-EINVAL);
- return(sk->prot->ioctl(sk, cmd, arg));
- }
- /*NOTREACHED*/
- return(0);
-
-}
-#else /* _HURD_ */
-static int inet_ioctl (struct socket *sock,
- unsigned int cm,
- unsigned long arg)
-{
- return EOPNOTSUPP;
-}
-#endif
-
-
-/*
- * This routine must find a socket given a TCP or UDP header.
- * Everything is assumed to be in net order.
- *
- * We give priority to more closely bound ports: if some socket
- * is bound to a particular foreign address, it will get the packet
- * rather than somebody listening to any address..
- */
-
-struct sock *get_sock(struct proto *prot, unsigned short num,
- unsigned long raddr,
- unsigned short rnum, unsigned long laddr)
-{
- struct sock *s;
- struct sock *result = NULL;
- int badness = -1;
- unsigned short hnum;
-
- hnum = ntohs(num);
-
- /*
- * SOCK_ARRAY_SIZE must be a power of two. This will work better
- * than a prime unless 3 or more sockets end up using the same
- * array entry. This should not be a problem because most
- * well known sockets don't overlap that much, and for
- * the other ones, we can just be careful about picking our
- * socket number when we choose an arbitrary one.
- */
-
- for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
- s != NULL; s = s->next)
- {
- int score = 0;
-
- if (s->num != hnum)
- continue;
-
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- /* local address matches? */
- if (s->saddr) {
- if (s->saddr != laddr)
- continue;
- score++;
- }
- /* remote address matches? */
- if (s->daddr) {
- if (s->daddr != raddr)
- continue;
- score++;
- }
- /* remote port matches? */
- if (s->dummy_th.dest) {
- if (s->dummy_th.dest != rnum)
- continue;
- score++;
- }
- /* perfect match? */
- if (score == 3)
- return s;
- /* no, check if this is the best so far.. */
- if (score <= badness)
- continue;
- result = s;
- badness = score;
- }
- return result;
-}
-
-/*
- * Deliver a datagram to raw sockets.
- */
-
-struct sock *get_sock_raw(struct sock *sk,
- unsigned short num,
- unsigned long raddr,
- unsigned long laddr)
-{
- struct sock *s;
-
- s=sk;
-
- for(; s != NULL; s = s->next)
- {
- if (s->num != num)
- continue;
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- if(s->daddr && s->daddr!=raddr)
- continue;
- if(s->saddr && s->saddr!=laddr)
- continue;
- return(s);
- }
- return(NULL);
-}
-
-#ifdef CONFIG_IP_MULTICAST
-/*
- * Deliver a datagram to broadcast/multicast sockets.
- */
-
-struct sock *get_sock_mcast(struct sock *sk,
- unsigned short num,
- unsigned long raddr,
- unsigned short rnum, unsigned long laddr)
-{
- struct sock *s;
- unsigned short hnum;
-
- hnum = ntohs(num);
-
- /*
- * SOCK_ARRAY_SIZE must be a power of two. This will work better
- * than a prime unless 3 or more sockets end up using the same
- * array entry. This should not be a problem because most
- * well known sockets don't overlap that much, and for
- * the other ones, we can just be careful about picking our
- * socket number when we choose an arbitrary one.
- */
-
- s=sk;
-
- for(; s != NULL; s = s->next)
- {
- if (s->num != hnum)
- continue;
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- if(s->daddr && s->daddr!=raddr)
- continue;
- if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
- continue;
- if(s->saddr && s->saddr!=laddr)
- continue;
- return(s);
- }
- return(NULL);
-}
-
-#endif
-
-static struct proto_ops inet_proto_ops = {
- AF_INET,
-
- inet_create,
- inet_dup,
- inet_release,
- inet_bind,
- inet_connect,
- inet_socketpair,
- inet_accept,
- inet_getname,
- inet_read,
- inet_write,
- inet_select,
- inet_ioctl,
- inet_listen,
- inet_send,
- inet_recv,
- inet_sendto,
- inet_recvfrom,
- inet_shutdown,
- inet_setsockopt,
- inet_getsockopt,
- inet_fcntl,
-};
-
-extern unsigned long seq_offset;
-
-/*
- * Called by socket.c on kernel startup.
- */
-
-void inet_proto_init(struct net_proto *pro)
-{
- struct inet_protocol *p;
- int i;
-
-
- printk("Swansea University Computer Society TCP/IP for NET3.019\n");
-
- /*
- * Tell SOCKET that we are alive...
- */
-
- (void) sock_register(inet_proto_ops.family, &inet_proto_ops);
-
- seq_offset = CURRENT_TIME*250;
-
- /*
- * Add all the protocols.
- */
-
- for(i = 0; i < SOCK_ARRAY_SIZE; i++)
- {
- tcp_prot.sock_array[i] = NULL;
- udp_prot.sock_array[i] = NULL;
- raw_prot.sock_array[i] = NULL;
- }
- tcp_prot.inuse = 0;
- tcp_prot.highestinuse = 0;
- udp_prot.inuse = 0;
- udp_prot.highestinuse = 0;
- raw_prot.inuse = 0;
- raw_prot.highestinuse = 0;
-
- printk("IP Protocols: ");
- for(p = inet_protocol_base; p != NULL;)
- {
- struct inet_protocol *tmp = (struct inet_protocol *) p->next;
- inet_add_protocol(p);
- printk("%s%s",p->name,tmp?", ":"\n");
- p = tmp;
- }
- /*
- * Set the ARP module up
- */
- arp_init();
- /*
- * Set the IP module up
- */
- ip_init();
-}
-
diff --git a/pfinet/linux-inet/arp.c b/pfinet/linux-inet/arp.c
deleted file mode 100644
index 5e00caf7..00000000
--- a/pfinet/linux-inet/arp.c
+++ /dev/null
@@ -1,1295 +0,0 @@
-/* linux/net/inet/arp.c
- *
- * Copyright (C) 1994 by Florian La Roche
- *
- * This module implements the Address Resolution Protocol ARP (RFC 826),
- * which is used to convert IP addresses (or in the future maybe other
- * high-level addresses into a low-level hardware address (like an Ethernet
- * address).
- *
- * FIXME:
- * Experiment with better retransmit timers
- * Clean up the timer deletions
- * If you create a proxy entry set your interface address to the address
- * and then delete it, proxies may get out of sync with reality - check this
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- *
- * Fixes:
- * Alan Cox : Removed the ethernet assumptions in Florian's code
- * Alan Cox : Fixed some small errors in the ARP logic
- * Alan Cox : Allow >4K in /proc
- * Alan Cox : Make ARP add its own protocol entry
- *
- * Ross Martin : Rewrote arp_rcv() and arp_get_info()
- * Stephen Henson : Add AX25 support to arp_get_info()
- * Alan Cox : Drop data when a device is downed.
- * Alan Cox : Use init_timer().
- * Alan Cox : Double lock fixes.
- * Martin Seine : Move the arphdr structure
- * to if_arp.h for compatibility.
- * with BSD based programs.
- * Andrew Tridgell : Added ARP netmask code and
- * re-arranged proxy handling.
- * Alan Cox : Changed to use notifiers.
- * Niibe Yutaka : Reply for this device or proxies only.
- * Alan Cox : Don't proxy across hardware types!
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/config.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in.h>
-#include <linux/mm.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "tcp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "arp.h"
-#ifdef CONFIG_AX25
-#include "ax25.h"
-#endif
-
-
-/*
- * This structure defines the ARP mapping cache. As long as we make changes
- * in this structure, we keep interrupts of. But normally we can copy the
- * hardware address and the device pointer in a local variable and then make
- * any "long calls" to send a packet out.
- */
-
-struct arp_table
-{
- struct arp_table *next; /* Linked entry list */
- unsigned long last_used; /* For expiry */
- unsigned int flags; /* Control status */
- unsigned long ip; /* ip address of entry */
- unsigned long mask; /* netmask - used for generalised proxy arps (tridge) */
- unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */
- unsigned char hlen; /* Length of hardware address */
- unsigned short htype; /* Type of hardware in use */
- struct device *dev; /* Device the entry is tied to */
-
- /*
- * The following entries are only used for unresolved hw addresses.
- */
-
- struct timer_list timer; /* expire timer */
- int retries; /* remaining retries */
- struct sk_buff_head skb; /* list of queued packets */
-};
-
-
-/*
- * Configurable Parameters (don't touch unless you know what you are doing
- */
-
-/*
- * If an arp request is send, ARP_RES_TIME is the timeout value until the
- * next request is send.
- */
-
-#define ARP_RES_TIME (250*(HZ/10))
-
-/*
- * The number of times an arp request is send, until the host is
- * considered unreachable.
- */
-
-#define ARP_MAX_TRIES 3
-
-/*
- * After that time, an unused entry is deleted from the arp table.
- */
-
-#define ARP_TIMEOUT (600*HZ)
-
-/*
- * How often is the function 'arp_check_retries' called.
- * An entry is invalidated in the time between ARP_TIMEOUT and
- * (ARP_TIMEOUT+ARP_CHECK_INTERVAL).
- */
-
-#define ARP_CHECK_INTERVAL (60 * HZ)
-
-enum proxy {
- PROXY_EXACT=0,
- PROXY_ANY,
- PROXY_NONE,
-};
-
-/* Forward declarations. */
-static void arp_check_expire (unsigned long);
-static struct arp_table *arp_lookup(unsigned long paddr, enum proxy proxy);
-
-
-static struct timer_list arp_timer =
- { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire };
-
-/*
- * The default arp netmask is just 255.255.255.255 which means it's
- * a single machine entry. Only proxy entries can have other netmasks
- *
-*/
-
-#define DEF_ARP_NETMASK (~0)
-
-
-/*
- * The size of the hash table. Must be a power of two.
- * Maybe we should remove hashing in the future for arp and concentrate
- * on Patrick Schaaf's Host-Cache-Lookup...
- */
-
-
-#define ARP_TABLE_SIZE 16
-
-/* The ugly +1 here is to cater for proxy entries. They are put in their
- own list for efficiency of lookup. If you don't want to find a proxy
- entry then don't look in the last entry, otherwise do
-*/
-
-#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1)
-
-struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] =
-{
- NULL,
-};
-
-
-/*
- * The last bits in the IP address are used for the cache lookup.
- * A special entry is used for proxy arp entries
- */
-
-#define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1))
-#define PROXY_HASH ARP_TABLE_SIZE
-
-/*
- * Check if there are too old entries and remove them. If the ATF_PERM
- * flag is set, they are always left in the arp cache (permanent entry).
- * Note: Only fully resolved entries, which don't have any packets in
- * the queue, can be deleted, since ARP_TIMEOUT is much greater than
- * ARP_MAX_TRIES*ARP_RES_TIME.
- */
-
-static void arp_check_expire(unsigned long dummy)
-{
- int i;
- unsigned long now = jiffies;
- unsigned long flags;
- save_flags(flags);
- cli();
-
- for (i = 0; i < FULL_ARP_TABLE_SIZE; i++)
- {
- struct arp_table *entry;
- struct arp_table **pentry = &arp_tables[i];
-
- while ((entry = *pentry) != NULL)
- {
- if ((now - entry->last_used) > ARP_TIMEOUT
- && !(entry->flags & ATF_PERM))
- {
- *pentry = entry->next; /* remove from list */
- del_timer(&entry->timer); /* Paranoia */
- kfree_s(entry, sizeof(struct arp_table));
- }
- else
- pentry = &entry->next; /* go to next entry */
- }
- }
- restore_flags(flags);
-
- /*
- * Set the timer again.
- */
-
- del_timer(&arp_timer);
- arp_timer.expires = ARP_CHECK_INTERVAL;
- add_timer(&arp_timer);
-}
-
-
-/*
- * Release all linked skb's and the memory for this entry.
- */
-
-static void arp_release_entry(struct arp_table *entry)
-{
- struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- /* Release the list of `skb' pointers. */
- while ((skb = skb_dequeue(&entry->skb)) != NULL)
- {
- skb_device_lock(skb);
- restore_flags(flags);
- dev_kfree_skb(skb, FREE_WRITE);
- }
- restore_flags(flags);
- del_timer(&entry->timer);
- kfree_s(entry, sizeof(struct arp_table));
- return;
-}
-
-/*
- * Purge a device from the ARP queue
- */
-
-int arp_device_event(unsigned long event, void *ptr)
-{
- struct device *dev=ptr;
- int i;
- unsigned long flags;
-
- if(event!=NETDEV_DOWN)
- return NOTIFY_DONE;
- /*
- * This is a bit OTT - maybe we need some arp semaphores instead.
- */
-
- save_flags(flags);
- cli();
- for (i = 0; i < FULL_ARP_TABLE_SIZE; i++)
- {
- struct arp_table *entry;
- struct arp_table **pentry = &arp_tables[i];
-
- while ((entry = *pentry) != NULL)
- {
- if(entry->dev==dev)
- {
- *pentry = entry->next; /* remove from list */
- del_timer(&entry->timer); /* Paranoia */
- kfree_s(entry, sizeof(struct arp_table));
- }
- else
- pentry = &entry->next; /* go to next entry */
- }
- }
- restore_flags(flags);
- return NOTIFY_DONE;
-}
-
-
-/*
- * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast
- * message.
- */
-
-void arp_send(int type, int ptype, unsigned long dest_ip,
- struct device *dev, unsigned long src_ip,
- unsigned char *dest_hw, unsigned char *src_hw)
-{
- struct sk_buff *skb;
- struct arphdr *arp;
- unsigned char *arp_ptr;
-
- /*
- * No arp on this interface.
- */
-
- if(dev->flags&IFF_NOARP)
- return;
-
- /*
- * Allocate a buffer
- */
-
- skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
- + dev->hard_header_len, GFP_ATOMIC);
- if (skb == NULL)
- {
- printk("ARP: no memory to send an arp packet\n");
- return;
- }
- skb->len = sizeof(struct arphdr) + dev->hard_header_len + 2*(dev->addr_len+4);
- skb->arp = 1;
- skb->dev = dev;
- skb->free = 1;
-
- /*
- * Fill the device header for the ARP frame
- */
-
- dev->hard_header(skb->data,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len,skb);
-
- /* Fill out the arp protocol part. */
- arp = (struct arphdr *) (skb->data + dev->hard_header_len);
- arp->ar_hrd = htons(dev->type);
-#ifdef CONFIG_AX25
- arp->ar_pro = (dev->type != ARPHRD_AX25)? htons(ETH_P_IP) : htons(AX25_P_IP);
-#else
- arp->ar_pro = htons(ETH_P_IP);
-#endif
- arp->ar_hln = dev->addr_len;
- arp->ar_pln = 4;
- arp->ar_op = htons(type);
-
- arp_ptr=(unsigned char *)(arp+1);
-
- memcpy(arp_ptr, src_hw, dev->addr_len);
- arp_ptr+=dev->addr_len;
- memcpy(arp_ptr, &src_ip,4);
- arp_ptr+=4;
- if (dest_hw != NULL)
- memcpy(arp_ptr, dest_hw, dev->addr_len);
- else
- memset(arp_ptr, 0, dev->addr_len);
- arp_ptr+=dev->addr_len;
- memcpy(arp_ptr, &dest_ip, 4);
-
- dev_queue_xmit(skb, dev, 0);
-}
-
-
-/*
- * This function is called, if an entry is not resolved in ARP_RES_TIME.
- * Either resend a request, or give it up and free the entry.
- */
-
-static void arp_expire_request (unsigned long arg)
-{
- struct arp_table *entry = (struct arp_table *) arg;
- struct arp_table **pentry;
- unsigned long hash;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- /*
- * Since all timeouts are handled with interrupts enabled, there is a
- * small chance, that this entry has just been resolved by an incoming
- * packet. This is the only race condition, but it is handled...
- */
-
- if (entry->flags & ATF_COM)
- {
- restore_flags(flags);
- return;
- }
-
- if (--entry->retries > 0)
- {
- unsigned long ip = entry->ip;
- struct device *dev = entry->dev;
-
- /* Set new timer. */
- del_timer(&entry->timer);
- entry->timer.expires = ARP_RES_TIME;
- add_timer(&entry->timer);
- restore_flags(flags);
- arp_send(ARPOP_REQUEST, ETH_P_ARP, ip, dev, dev->pa_addr,
- NULL, dev->dev_addr);
- return;
- }
-
- /*
- * Arp request timed out. Delete entry and all waiting packets.
- * If we give each entry a pointer to itself, we don't have to
- * loop through everything again. Maybe hash is good enough, but
- * I will look at it later.
- */
-
- hash = HASH(entry->ip);
-
- /* proxy entries shouldn't really time out so this is really
- only here for completeness
- */
- if (entry->flags & ATF_PUBL)
- pentry = &arp_tables[PROXY_HASH];
- else
- pentry = &arp_tables[hash];
- while (*pentry != NULL)
- {
- if (*pentry == entry)
- {
- *pentry = entry->next; /* delete from linked list */
- del_timer(&entry->timer);
- restore_flags(flags);
- arp_release_entry(entry);
- return;
- }
- pentry = &(*pentry)->next;
- }
- restore_flags(flags);
- printk("Possible ARP queue corruption.\n");
- /*
- * We should never arrive here.
- */
-}
-
-
-/*
- * This will try to retransmit everything on the queue.
- */
-
-static void arp_send_q(struct arp_table *entry, unsigned char *hw_dest)
-{
- struct sk_buff *skb;
-
- unsigned long flags;
-
- /*
- * Empty the entire queue, building its data up ready to send
- */
-
- if(!(entry->flags&ATF_COM))
- {
- printk("arp_send_q: incomplete entry for %s\n",
- in_ntoa(entry->ip));
- return;
- }
-
- save_flags(flags);
-
- cli();
- while((skb = skb_dequeue(&entry->skb)) != NULL)
- {
- IS_SKB(skb);
- skb_device_lock(skb);
- restore_flags(flags);
- if(!skb->dev->rebuild_header(skb->data,skb->dev,skb->raddr,skb))
- {
- skb->arp = 1;
- if(skb->sk==NULL)
- dev_queue_xmit(skb, skb->dev, 0);
- else
- dev_queue_xmit(skb,skb->dev,skb->sk->priority);
- }
- else
- {
- /* This routine is only ever called when 'entry' is
- complete. Thus this can't fail. */
- printk("arp_send_q: The impossible occurred. Please notify Alan.\n");
- printk("arp_send_q: active entity %s\n",in_ntoa(entry->ip));
- printk("arp_send_q: failed to find %s\n",in_ntoa(skb->raddr));
- }
- }
- restore_flags(flags);
-}
-
-
-/*
- * Delete an ARP mapping entry in the cache.
- */
-
-void arp_destroy(unsigned long ip_addr, int force)
-{
- int checked_proxies = 0;
- struct arp_table *entry;
- struct arp_table **pentry;
- unsigned long hash = HASH(ip_addr);
-
-ugly:
- cli();
- pentry = &arp_tables[hash];
- if (! *pentry) /* also check proxy entries */
- pentry = &arp_tables[PROXY_HASH];
-
- while ((entry = *pentry) != NULL)
- {
- if (entry->ip == ip_addr)
- {
- if ((entry->flags & ATF_PERM) && !force)
- return;
- *pentry = entry->next;
- del_timer(&entry->timer);
- sti();
- arp_release_entry(entry);
- /* this would have to be cleaned up */
- goto ugly;
- /* perhaps like this ?
- cli();
- entry = *pentry;
- */
- }
- pentry = &entry->next;
- if (!checked_proxies && ! *pentry)
- { /* ugly. we have to make sure we check proxy
- entries as well */
- checked_proxies = 1;
- pentry = &arp_tables[PROXY_HASH];
- }
- }
- sti();
-}
-
-
-/*
- * Receive an arp request by the device layer. Maybe I rewrite it, to
- * use the incoming packet for the reply. The time for the current
- * "overhead" isn't that high...
- */
-
-int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
-/*
- * We shouldn't use this type conversion. Check later.
- */
-
- struct arphdr *arp = (struct arphdr *)skb->h.raw;
- unsigned char *arp_ptr= (unsigned char *)(arp+1);
- struct arp_table *entry;
- struct arp_table *proxy_entry;
- int addr_hint,hlen,htype;
- unsigned long hash;
- unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */
- long sip,tip;
- unsigned char *sha,*tha;
-
-/*
- * The hardware length of the packet should match the hardware length
- * of the device. Similarly, the hardware types should match. The
- * device should be ARP-able. Also, if pln is not 4, then the lookup
- * is not from an IP number. We can't currently handle this, so toss
- * it.
- */
- if (arp->ar_hln != dev->addr_len ||
- dev->type != ntohs(arp->ar_hrd) ||
- dev->flags & IFF_NOARP ||
- arp->ar_pln != 4)
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
-/*
- * Another test.
- * The logic here is that the protocol being looked up by arp should
- * match the protocol the device speaks. If it doesn't, there is a
- * problem, so toss the packet.
- */
- switch(dev->type)
- {
-#ifdef CONFIG_AX25
- case ARPHRD_AX25:
- if(arp->ar_pro != htons(AX25_P_IP))
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- break;
-#endif
- case ARPHRD_ETHER:
- case ARPHRD_ARCNET:
- if(arp->ar_pro != htons(ETH_P_IP))
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- break;
-
- default:
- printk("ARP: dev->type mangled!\n");
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
-/*
- * Extract fields
- */
-
- hlen = dev->addr_len;
- htype = dev->type;
-
- sha=arp_ptr;
- arp_ptr+=hlen;
- memcpy(&sip,arp_ptr,4);
- arp_ptr+=4;
- tha=arp_ptr;
- arp_ptr+=hlen;
- memcpy(&tip,arp_ptr,4);
-
-/*
- * Check for bad requests for 127.0.0.1. If this is one such, delete it.
- */
- if(tip == INADDR_LOOPBACK)
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
-/*
- * Process entry. The idea here is we want to send a reply if it is a
- * request for us or if it is a request for someone else that we hold
- * a proxy for. We want to add an entry to our cache if it is a reply
- * to us or if it is a request for our address.
- * (The assumption for this last is that if someone is requesting our
- * address, they are probably intending to talk to us, so it saves time
- * if we cache their address. Their address is also probably not in
- * our cache, since ours is not in their cache.)
- *
- * Putting this another way, we only care about replies if they are to
- * us, in which case we add them to the cache. For requests, we care
- * about those for us and those for our proxies. We reply to both,
- * and in the case of requests for us we add the requester to the arp
- * cache.
- */
-
- addr_hint = ip_chk_addr(tip);
-
- if(arp->ar_op == htons(ARPOP_REPLY))
- {
- if(addr_hint!=IS_MYADDR)
- {
-/*
- * Replies to other machines get tossed.
- */
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-/*
- * Fall through to code below that adds sender to cache.
- */
- }
- else
- {
-/*
- * It is now an arp request
- */
-/*
- * Only reply for the real device address or when it's in our proxy tables
- */
- if(tip!=dev->pa_addr)
- {
-/*
- * To get in here, it is a request for someone else. We need to
- * check if that someone else is one of our proxies. If it isn't,
- * we can toss it.
- */
- cli();
- for(proxy_entry=arp_tables[PROXY_HASH];
- proxy_entry;
- proxy_entry = proxy_entry->next)
- {
- /* we will respond to a proxy arp request
- if the masked arp table ip matches the masked
- tip. This allows a single proxy arp table
- entry to be used on a gateway machine to handle
- all requests for a whole network, rather than
- having to use a huge number of proxy arp entries
- and having to keep them uptodate.
- */
- if (proxy_entry->dev != dev && proxy_entry->htype == htype &&
- !((proxy_entry->ip^tip)&proxy_entry->mask))
- break;
-
- }
- if (proxy_entry)
- {
- memcpy(ha, proxy_entry->ha, hlen);
- sti();
- arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha);
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- else
- {
- sti();
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- }
- else
- {
-/*
- * To get here, it must be an arp request for us. We need to reply.
- */
- arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr);
- }
- }
-
-
-/*
- * Now all replies are handled. Next, anything that falls through to here
- * needs to be added to the arp cache, or have its entry updated if it is
- * there.
- */
-
- hash = HASH(sip);
- cli();
- for(entry=arp_tables[hash];entry;entry=entry->next)
- if(entry->ip==sip && entry->htype==htype)
- break;
-
- if(entry)
- {
-/*
- * Entry found; update it.
- */
- memcpy(entry->ha, sha, hlen);
- entry->hlen = hlen;
- entry->last_used = jiffies;
- if (!(entry->flags & ATF_COM))
- {
-/*
- * This entry was incomplete. Delete the retransmit timer
- * and switch to complete status.
- */
- del_timer(&entry->timer);
- entry->flags |= ATF_COM;
- sti();
-/*
- * Send out waiting packets. We might have problems, if someone is
- * manually removing entries right now -- entry might become invalid
- * underneath us.
- */
- arp_send_q(entry, sha);
- }
- else
- {
- sti();
- }
- }
- else
- {
-/*
- * No entry found. Need to add a new entry to the arp table.
- */
- entry = (struct arp_table *)kmalloc(sizeof(struct arp_table),GFP_ATOMIC);
- if(entry == NULL)
- {
- sti();
- printk("ARP: no memory for new arp entry\n");
-
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- entry->mask = DEF_ARP_NETMASK;
- entry->ip = sip;
- entry->hlen = hlen;
- entry->htype = htype;
- entry->flags = ATF_COM;
- init_timer(&entry->timer);
- memcpy(entry->ha, sha, hlen);
- entry->last_used = jiffies;
- entry->dev = skb->dev;
- skb_queue_head_init(&entry->skb);
- entry->next = arp_tables[hash];
- arp_tables[hash] = entry;
- sti();
- }
-
-/*
- * Replies have been sent, and entries have been added. All done.
- */
- kfree_skb(skb, FREE_READ);
- return 0;
-}
-
-
-/*
- * Find an arp mapping in the cache. If not found, post a request.
- */
-
-int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
- unsigned long saddr, struct sk_buff *skb)
-{
- struct arp_table *entry;
- unsigned long hash;
-#ifdef CONFIG_IP_MULTICAST
- unsigned long taddr;
-#endif
-
- switch (ip_chk_addr(paddr))
- {
- case IS_MYADDR:
- printk("ARP: arp called for own IP address\n");
- memcpy(haddr, dev->dev_addr, dev->addr_len);
- skb->arp = 1;
- return 0;
-#ifdef CONFIG_IP_MULTICAST
- case IS_MULTICAST:
- if(dev->type==ARPHRD_ETHER || dev->type==ARPHRD_IEEE802)
- {
- haddr[0]=0x01;
- haddr[1]=0x00;
- haddr[2]=0x5e;
- taddr=ntohl(paddr);
- haddr[5]=taddr&0xff;
- taddr=taddr>>8;
- haddr[4]=taddr&0xff;
- taddr=taddr>>8;
- haddr[3]=taddr&0x7f;
- return 0;
- }
- /*
- * If a device does not support multicast broadcast the stuff (eg AX.25 for now)
- */
-#endif
-
- case IS_BROADCAST:
- memcpy(haddr, dev->broadcast, dev->addr_len);
- skb->arp = 1;
- return 0;
- }
-
- hash = HASH(paddr);
- cli();
-
- /*
- * Find an entry
- */
- entry = arp_lookup(paddr, PROXY_NONE);
-
- if (entry != NULL) /* It exists */
- {
- if (!(entry->flags & ATF_COM))
- {
- /*
- * A request was already send, but no reply yet. Thus
- * queue the packet with the previous attempt
- */
-
- if (skb != NULL)
- {
- skb_queue_tail(&entry->skb, skb);
- skb_device_unlock(skb);
- }
- sti();
- return 1;
- }
-
- /*
- * Update the record
- */
-
- entry->last_used = jiffies;
- memcpy(haddr, entry->ha, dev->addr_len);
- if (skb)
- skb->arp = 1;
- sti();
- return 0;
- }
-
- /*
- * Create a new unresolved entry.
- */
-
- entry = (struct arp_table *) kmalloc(sizeof(struct arp_table),
- GFP_ATOMIC);
- if (entry != NULL)
- {
- entry->mask = DEF_ARP_NETMASK;
- entry->ip = paddr;
- entry->hlen = dev->addr_len;
- entry->htype = dev->type;
- entry->flags = 0;
- memset(entry->ha, 0, dev->addr_len);
- entry->dev = dev;
- entry->last_used = jiffies;
- init_timer(&entry->timer);
- entry->timer.function = arp_expire_request;
- entry->timer.data = (unsigned long)entry;
- entry->timer.expires = ARP_RES_TIME;
- entry->next = arp_tables[hash];
- arp_tables[hash] = entry;
- add_timer(&entry->timer);
- entry->retries = ARP_MAX_TRIES;
- skb_queue_head_init(&entry->skb);
- if (skb != NULL)
- {
- skb_queue_tail(&entry->skb, skb);
- skb_device_unlock(skb);
- }
- }
- else
- {
- if (skb != NULL && skb->free)
- kfree_skb(skb, FREE_WRITE);
- }
- sti();
-
- /*
- * If we didn't find an entry, we will try to send an ARP packet.
- */
-
- arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, saddr, NULL,
- dev->dev_addr);
-
- return 1;
-}
-
-
-/*
- * Write the contents of the ARP cache to a PROCfs file.
- */
-
-#define HBUFFERLEN 30
-
-int arp_get_info(char *buffer, char **start, off_t offset, int length)
-{
- int len=0;
- off_t begin=0;
- off_t pos=0;
- int size;
- struct arp_table *entry;
- char hbuffer[HBUFFERLEN];
- int i,j,k;
- const char hexbuf[] = "0123456789ABCDEF";
-
- size = sprintf(buffer,"IP address HW type Flags HW address Mask\n");
-
- pos+=size;
- len+=size;
-
- cli();
- for(i=0; i<FULL_ARP_TABLE_SIZE; i++)
- {
- for(entry=arp_tables[i]; entry!=NULL; entry=entry->next)
- {
-/*
- * Convert hardware address to XX:XX:XX:XX ... form.
- */
-#ifdef CONFIG_AX25
-
- if(entry->htype==ARPHRD_AX25)
- strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
- else {
-#endif
-
- for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->hlen;j++)
- {
- hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
- hbuffer[k++]=hexbuf[ entry->ha[j]&15 ];
- hbuffer[k++]=':';
- }
- hbuffer[--k]=0;
-
-#ifdef CONFIG_AX25
- }
-#endif
- size = sprintf(buffer+len,
- "%-17s0x%-10x0x%-10x%s",
- in_ntoa(entry->ip),
- (unsigned int)entry->htype,
- entry->flags,
- hbuffer);
- size += sprintf(buffer+len+size,
- " %-17s\n",
- entry->mask==DEF_ARP_NETMASK?
- "*":in_ntoa(entry->mask));
-
- len+=size;
- pos=begin+len;
-
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
- }
- }
- sti();
-
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len=length; /* Ending slop */
- return len;
-}
-
-
-/*
- * This will find an entry in the ARP table by looking at the IP address.
- * If proxy is PROXY_EXACT then only exact IP matches will be allowed
- * for proxy entries, otherwise the netmask will be used
- */
-
-static struct arp_table *arp_lookup(unsigned long paddr, enum proxy proxy)
-{
- struct arp_table *entry;
- unsigned long hash = HASH(paddr);
-
- for (entry = arp_tables[hash]; entry != NULL; entry = entry->next)
- if (entry->ip == paddr) break;
-
- /* it's possibly a proxy entry (with a netmask) */
- if (!entry && proxy != PROXY_NONE)
- for (entry=arp_tables[PROXY_HASH]; entry != NULL; entry = entry->next)
- if ((proxy==PROXY_EXACT) ? (entry->ip==paddr)
- : !((entry->ip^paddr)&entry->mask))
- break;
-
- return entry;
-}
-
-
-/*
- * Set (create) an ARP cache entry.
- */
-
-static int arp_req_set(struct arpreq *req)
-{
- struct arpreq r;
- struct arp_table *entry;
- struct sockaddr_in *si;
- int htype, hlen;
- unsigned long ip;
- struct rtable *rt;
-
- memcpy_fromfs(&r, req, sizeof(r));
-
- /* We only understand about IP addresses... */
- if (r.arp_pa.sa_family != AF_INET)
- return -EPFNOSUPPORT;
-
- /*
- * Find out about the hardware type.
- * We have to be compatible with BSD UNIX, so we have to
- * assume that a "not set" value (i.e. 0) means Ethernet.
- */
-
- switch (r.arp_ha.sa_family) {
- case ARPHRD_ETHER:
- htype = ARPHRD_ETHER;
- hlen = ETH_ALEN;
- break;
-
- case ARPHRD_ARCNET:
- htype = ARPHRD_ARCNET;
- hlen = 1; /* length of arcnet addresses */
- break;
-
-#ifdef CONFIG_AX25
- case ARPHRD_AX25:
- htype = ARPHRD_AX25;
- hlen = 7;
- break;
-#endif
- default:
- return -EPFNOSUPPORT;
- }
-
- si = (struct sockaddr_in *) &r.arp_pa;
- ip = si->sin_addr.s_addr;
- if (ip == 0)
- {
- printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
- return -EINVAL;
- }
-
- /*
- * Is it reachable directly ?
- */
-
- rt = ip_rt_route(ip, NULL, NULL);
- if (rt == NULL)
- return -ENETUNREACH;
-
- /*
- * Is there an existing entry for this address?
- */
-
- cli();
-
- /*
- * Find the entry
- */
- entry = arp_lookup(ip, PROXY_EXACT);
- if (entry && (entry->flags & ATF_PUBL) != (r.arp_flags & ATF_PUBL))
- {
- sti();
- arp_destroy(ip,1);
- cli();
- entry = NULL;
- }
-
- /*
- * Do we need to create a new entry
- */
-
- if (entry == NULL)
- {
- unsigned long hash = HASH(ip);
- if (r.arp_flags & ATF_PUBL)
- hash = PROXY_HASH;
-
- entry = (struct arp_table *) kmalloc(sizeof(struct arp_table),
- GFP_ATOMIC);
- if (entry == NULL)
- {
- sti();
- return -ENOMEM;
- }
- entry->ip = ip;
- entry->hlen = hlen;
- entry->htype = htype;
- init_timer(&entry->timer);
- entry->next = arp_tables[hash];
- arp_tables[hash] = entry;
- skb_queue_head_init(&entry->skb);
- }
- /*
- * We now have a pointer to an ARP entry. Update it!
- */
-
- memcpy(&entry->ha, &r.arp_ha.sa_data, hlen);
- entry->last_used = jiffies;
- entry->flags = r.arp_flags | ATF_COM;
- if ((entry->flags & ATF_PUBL) && (entry->flags & ATF_NETMASK))
- {
- si = (struct sockaddr_in *) &r.arp_netmask;
- entry->mask = si->sin_addr.s_addr;
- }
- else
- entry->mask = DEF_ARP_NETMASK;
- entry->dev = rt->rt_dev;
- sti();
-
- return 0;
-}
-
-
-/*
- * Get an ARP cache entry.
- */
-
-static int arp_req_get(struct arpreq *req)
-{
- struct arpreq r;
- struct arp_table *entry;
- struct sockaddr_in *si;
-
- /*
- * We only understand about IP addresses...
- */
-
- memcpy_fromfs(&r, req, sizeof(r));
-
- if (r.arp_pa.sa_family != AF_INET)
- return -EPFNOSUPPORT;
-
- /*
- * Is there an existing entry for this address?
- */
-
- si = (struct sockaddr_in *) &r.arp_pa;
- cli();
- entry = arp_lookup(si->sin_addr.s_addr,PROXY_ANY);
-
- if (entry == NULL)
- {
- sti();
- return -ENXIO;
- }
-
- /*
- * We found it; copy into structure.
- */
-
- memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen);
- r.arp_ha.sa_family = entry->htype;
- r.arp_flags = entry->flags;
- sti();
-
- /*
- * Copy the information back
- */
-
- memcpy_tofs(req, &r, sizeof(r));
- return 0;
-}
-
-
-#ifndef _HURD_
-/*
- * Handle an ARP layer I/O control request.
- */
-
-int arp_ioctl(unsigned int cmd, void *arg)
-{
- struct arpreq r;
- struct sockaddr_in *si;
- int err;
-
- switch(cmd)
- {
- case SIOCDARP:
- if (!suser())
- return -EPERM;
- err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
- if(err)
- return err;
- memcpy_fromfs(&r, arg, sizeof(r));
- if (r.arp_pa.sa_family != AF_INET)
- return -EPFNOSUPPORT;
- si = (struct sockaddr_in *) &r.arp_pa;
- arp_destroy(si->sin_addr.s_addr, 1);
- return 0;
- case SIOCGARP:
- err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq));
- if(err)
- return err;
- return arp_req_get((struct arpreq *)arg);
- case SIOCSARP:
- if (!suser())
- return -EPERM;
- err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
- if(err)
- return err;
- return arp_req_set((struct arpreq *)arg);
- default:
- return -EINVAL;
- }
- /*NOTREACHED*/
- return 0;
-}
-#endif
-
-/*
- * Called once on startup.
- */
-
-static struct packet_type arp_packet_type =
-{
- 0, /* Should be: __constant_htons(ETH_P_ARP) - but this _doesn't_ come out constant! */
- NULL, /* All devices */
- arp_rcv,
- NULL,
- NULL
-};
-
-static struct notifier_block arp_dev_notifier={
- arp_device_event,
- NULL,
- 0
-};
-
-void arp_init (void)
-{
- /* Register the packet type */
- arp_packet_type.type=htons(ETH_P_ARP);
- dev_add_pack(&arp_packet_type);
- /* Start with the regular checks for expired arp entries. */
- add_timer(&arp_timer);
- /* Register for device down reports */
- register_netdevice_notifier(&arp_dev_notifier);
-}
-
diff --git a/pfinet/linux-inet/arp.h b/pfinet/linux-inet/arp.h
deleted file mode 100644
index a68adc30..00000000
--- a/pfinet/linux-inet/arp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* linux/net/inet/arp.h */
-#ifndef _ARP_H
-#define _ARP_H
-
-extern void arp_init(void);
-extern void arp_destroy(unsigned long paddr, int force);
-extern void arp_device_down(struct device *dev);
-extern int arp_rcv(struct sk_buff *skb, struct device *dev,
- struct packet_type *pt);
-extern int arp_find(unsigned char *haddr, unsigned long paddr,
- struct device *dev, unsigned long saddr, struct sk_buff *skb);
-extern int arp_get_info(char *buffer, char **start, off_t origin, int length);
-extern int arp_ioctl(unsigned int cmd, void *arg);
-extern void arp_send(int type, int ptype, unsigned long dest_ip,
- struct device *dev, unsigned long src_ip,
- unsigned char *dest_hw, unsigned char *src_hw);
-
-#endif /* _ARP_H */
diff --git a/pfinet/linux-inet/datagram.c b/pfinet/linux-inet/datagram.c
deleted file mode 100644
index cd248cfb..00000000
--- a/pfinet/linux-inet/datagram.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * SUCS NET3:
- *
- * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
- * of these would make sense. Not tonight however 8-).
- * This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
- * identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code)
- *
- * Fixes:
- * Alan Cox : NULL return from skb_peek_copy() understood
- * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
- * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
- * AX.25 now works right, and SPX is feasible.
- * Alan Cox : Fixed write select of non IP protocol crash.
- * Florian La Roche: Changed for my new skbuff handling.
- *
- * Note:
- * A lot of this will change when the protocol/socket separation
- * occurs. Using this will make things reasonably clean.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-
-
-/*
- * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
- * races. This replaces identical code in packet,raw and udp, as well as the yet to
- * be released IPX support. It also finally fixes the long standing peek and read
- * race for datagram sockets. If you alter this routine remember it must be
- * re-entrant.
- */
-
-struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
-{
- struct sk_buff *skb;
- unsigned long intflags;
-
- /* Socket is inuse - so the timer doesn't attack it */
- save_flags(intflags);
-restart:
- sk->inuse = 1;
- while(skb_peek(&sk->receive_queue) == NULL) /* No data */
- {
- /* If we are shutdown then no more data is going to appear. We are done */
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- release_sock(sk);
- *err=0;
- return NULL;
- }
-
- if(sk->err)
- {
- release_sock(sk);
- *err=-sk->err;
- sk->err=0;
- return NULL;
- }
-
- /* Sequenced packets can come disconnected. If so we report the problem */
- if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
- {
- release_sock(sk);
- *err=-ENOTCONN;
- return NULL;
- }
-
- /* User doesn't want to wait */
- if (noblock)
- {
- release_sock(sk);
- *err=-EAGAIN;
- return NULL;
- }
- release_sock(sk);
-
- /* Interrupts off so that no packet arrives before we begin sleeping.
- Otherwise we might miss our wake up */
- cli();
- if (skb_peek(&sk->receive_queue) == NULL)
- {
- interruptible_sleep_on(sk->sleep);
- /* Signals may need a restart of the syscall */
- if (current->signal & ~current->blocked)
- {
- restore_flags(intflags);;
- *err=-ERESTARTSYS;
- return(NULL);
- }
- if(sk->err != 0) /* Error while waiting for packet
- eg an icmp sent earlier by the
- peer has finally turned up now */
- {
- *err = -sk->err;
- sk->err=0;
- restore_flags(intflags);
- return NULL;
- }
- }
- sk->inuse = 1;
- restore_flags(intflags);
- }
- /* Again only user level code calls this function, so nothing interrupt level
- will suddenly eat the receive_queue */
- if (!(flags & MSG_PEEK))
- {
- skb=skb_dequeue(&sk->receive_queue);
- if(skb!=NULL)
- skb->users++;
- else
- goto restart; /* Avoid race if someone beats us to the data */
- }
- else
- {
- cli();
- skb=skb_peek(&sk->receive_queue);
- if(skb!=NULL)
- skb->users++;
- restore_flags(intflags);
- if(skb==NULL) /* shouldn't happen but .. */
- *err=-EAGAIN;
- }
- return skb;
-}
-
-void skb_free_datagram(struct sk_buff *skb)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- skb->users--;
- if(skb->users>0)
- {
- restore_flags(flags);
- return;
- }
- /* See if it needs destroying */
- if(!skb->next && !skb->prev) /* Been dequeued by someone - ie it's read */
- kfree_skb(skb,FREE_READ);
- restore_flags(flags);
-}
-
-void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
-{
- /* We will know all about the fraglist options to allow >4K receives
- but not this release */
- memcpy_tofs(to,skb->h.raw+offset,size);
-}
-
-/*
- * Datagram select: Again totally generic. Moved from udp.c
- * Now does seqpacket.
- */
-
-int datagram_select(struct sock *sk, int sel_type, select_table *wait)
-{
- select_wait(sk->sleep, wait);
- switch(sel_type)
- {
- case SEL_IN:
- if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
- {
- /* Connection closed: Wake up */
- return(1);
- }
- if (skb_peek(&sk->receive_queue) != NULL || sk->err != 0)
- { /* This appears to be consistent
- with other stacks */
- return(1);
- }
- return(0);
-
- case SEL_OUT:
- if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
- {
- return(1);
- }
- if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
- {
- return(1);
- }
- return(0);
-
- case SEL_EX:
- if (sk->err)
- return(1); /* Socket has gone into error state (eg icmp error) */
- return(0);
- }
- return(0);
-}
diff --git a/pfinet/linux-inet/dev.c b/pfinet/linux-inet/dev.c
deleted file mode 100644
index d393af11..00000000
--- a/pfinet/linux-inet/dev.c
+++ /dev/null
@@ -1,1449 +0,0 @@
-/*
- * NET3 Protocol independent device support routines.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Derived from the non IP parts of dev.c 1.0.19
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Mark Evans, <evansmp@uhura.aston.ac.uk>
- *
- * Additional Authors:
- * Florian la Roche <rzsfl@rz.uni-sb.de>
- * Alan Cox <gw4pts@gw4pts.ampr.org>
- * David Hinds <dhinds@allegro.stanford.edu>
- *
- * Changes:
- * Alan Cox : device private ioctl copies fields back.
- * Alan Cox : Transmit queue code does relevant stunts to
- * keep the queue safe.
- * Alan Cox : Fixed double lock.
- * Alan Cox : Fixed promisc NULL pointer trap
- * ???????? : Support the full private ioctl range
- * Alan Cox : Moved ioctl permission check into drivers
- * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI
- * Alan Cox : 100 backlog just doesn't cut it when
- * you start doing multicast video 8)
- * Alan Cox : Rewrote net_bh and list manager.
- * Alan Cox : Fix ETH_P_ALL echoback lengths.
- *
- * Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have
- * the rest as well commented in the end.
- */
-
-/*
- * A lot of these includes will be going walkies very soon
- */
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include "ip.h"
-#include "route.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "arp.h"
-
-
-/*
- * The list of packet types we will receive (as opposed to discard)
- * and the routines to invoke.
- */
-
-struct packet_type *ptype_base = NULL;
-
-/*
- * Our notifier list
- */
-
-struct notifier_block *netdev_chain=NULL;
-
-/*
- * Device drivers call our routines to queue packets here. We empty the
- * queue in the bottom half handler.
- */
-
-static struct sk_buff_head backlog =
-{
- (struct sk_buff *)&backlog, (struct sk_buff *)&backlog
-#ifdef CONFIG_SKB_CHECK
- ,SK_HEAD_SKB
-#endif
-};
-
-/*
- * We don't overdo the queue or we will thrash memory badly.
- */
-
-static int backlog_size = 0;
-
-/*
- * Return the lesser of the two values.
- */
-
-static __inline__ unsigned long min(unsigned long a, unsigned long b)
-{
- return (a < b)? a : b;
-}
-
-
-/******************************************************************************************
-
- Protocol management and registration routines
-
-*******************************************************************************************/
-
-/*
- * For efficiency
- */
-
-static int dev_nit=0;
-
-/*
- * Add a protocol ID to the list. Now that the input handler is
- * smarter we can dispense with all the messy stuff that used to be
- * here.
- */
-
-void dev_add_pack(struct packet_type *pt)
-{
- if(pt->type==htons(ETH_P_ALL))
- dev_nit++;
- pt->next = ptype_base;
- ptype_base = pt;
-}
-
-
-/*
- * Remove a protocol ID from the list.
- */
-
-void dev_remove_pack(struct packet_type *pt)
-{
- struct packet_type **pt1;
- if(pt->type==htons(ETH_P_ALL))
- dev_nit--;
- for(pt1=&ptype_base; (*pt1)!=NULL; pt1=&((*pt1)->next))
- {
- if(pt==(*pt1))
- {
- *pt1=pt->next;
- return;
- }
- }
-}
-
-/*****************************************************************************************
-
- Device Interface Subroutines
-
-******************************************************************************************/
-
-/*
- * Find an interface by name.
- */
-
-struct device *dev_get(char *name)
-{
- struct device *dev;
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (strcmp(dev->name, name) == 0)
- return(dev);
- }
- return(NULL);
-}
-
-
-/*
- * Prepare an interface for use.
- */
-
-int dev_open(struct device *dev)
-{
- int ret = 0;
-
- /*
- * Call device private open method
- */
- if (dev->open)
- ret = dev->open(dev);
-
- /*
- * If it went open OK then set the flags
- */
-
- if (ret == 0)
- {
- dev->flags |= (IFF_UP | IFF_RUNNING);
- /*
- * Initialise multicasting status
- */
-#ifdef CONFIG_IP_MULTICAST
- /*
- * Join the all host group
- */
- ip_mc_allhost(dev);
-#endif
- dev_mc_upload(dev);
- notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
- }
- return(ret);
-}
-
-
-/*
- * Completely shutdown an interface.
- */
-
-int dev_close(struct device *dev)
-{
- /*
- * Only close a device if it is up.
- */
-
- if (dev->flags != 0)
- {
- int ct=0;
- dev->flags = 0;
- /*
- * Call the device specific close. This cannot fail.
- */
- if (dev->stop)
- dev->stop(dev);
-
- notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
-#if 0
- /*
- * Delete the route to the device.
- */
-#ifdef CONFIG_INET
- ip_rt_flush(dev);
- arp_device_down(dev);
-#endif
-#ifdef CONFIG_IPX
- ipxrtr_device_down(dev);
-#endif
-#endif
- /*
- * Flush the multicast chain
- */
- dev_mc_discard(dev);
- /*
- * Blank the IP addresses
- */
- dev->pa_addr = 0;
- dev->pa_dstaddr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- /*
- * Purge any queued packets when we down the link
- */
- while(ct<DEV_NUMBUFFS)
- {
- struct sk_buff *skb;
- while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL)
- if(skb->free)
- kfree_skb(skb,FREE_WRITE);
- ct++;
- }
- }
- return(0);
-}
-
-
-/*
- * Device change register/unregister. These are not inline or static
- * as we export them to the world.
- */
-
-int register_netdevice_notifier(struct notifier_block *nb)
-{
- return notifier_chain_register(&netdev_chain, nb);
-}
-
-int unregister_netdevice_notifier(struct notifier_block *nb)
-{
- return notifier_chain_unregister(&netdev_chain,nb);
-}
-
-
-
-/*
- * Send (or queue for sending) a packet.
- *
- * IMPORTANT: When this is called to resend frames. The caller MUST
- * already have locked the sk_buff. Apart from that we do the
- * rest of the magic.
- */
-
-void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
-{
- unsigned long flags;
- int nitcount;
- struct packet_type *ptype;
- int where = 0; /* used to say if the packet should go */
- /* at the front or the back of the */
- /* queue - front is a retransmit try */
-
- if (dev == NULL)
- {
- printk("dev.c: dev_queue_xmit: dev = NULL\n");
- return;
- }
-
- if(pri>=0 && !skb_device_locked(skb))
- skb_device_lock(skb); /* Shove a lock on the frame */
-#ifdef CONFIG_SLAVE_BALANCING
- save_flags(flags);
- cli();
- if(dev->slave!=NULL && dev->slave->pkt_queue < dev->pkt_queue &&
- (dev->slave->flags & IFF_UP))
- dev=dev->slave;
- restore_flags(flags);
-#endif
-#ifdef CONFIG_SKB_CHECK
- IS_SKB(skb);
-#endif
- skb->dev = dev;
-
- /*
- * This just eliminates some race conditions, but not all...
- */
-
- if (skb->next != NULL)
- {
- /*
- * Make sure we haven't missed an interrupt.
- */
- printk("dev_queue_xmit: worked around a missed interrupt\n");
- dev->hard_start_xmit(NULL, dev);
- return;
- }
-
- /*
- * Negative priority is used to flag a frame that is being pulled from the
- * queue front as a retransmit attempt. It therefore goes back on the queue
- * start on a failure.
- */
-
- if (pri < 0)
- {
- pri = -pri-1;
- where = 1;
- }
-
- if (pri >= DEV_NUMBUFFS)
- {
- printk("bad priority in dev_queue_xmit.\n");
- pri = 1;
- }
-
- /*
- * If the address has not been resolved. Call the device header rebuilder.
- * This can cover all protocols and technically not just ARP either.
- */
-
- if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) {
- return;
- }
-
- save_flags(flags);
- cli();
- if (!where) {
-#ifdef CONFIG_SLAVE_BALANCING
- skb->in_dev_queue=1;
-#endif
- skb_queue_tail(dev->buffs + pri,skb);
- skb_device_unlock(skb); /* Buffer is on the device queue and can be freed safely */
- skb = skb_dequeue(dev->buffs + pri);
- skb_device_lock(skb); /* New buffer needs locking down */
-#ifdef CONFIG_SLAVE_BALANCING
- skb->in_dev_queue=0;
-#endif
- }
- restore_flags(flags);
-
- /* copy outgoing packets to any sniffer packet handlers */
- if(!where)
- {
- for (nitcount= dev_nit, ptype = ptype_base; nitcount > 0 && ptype != NULL; ptype = ptype->next)
- {
- /* Never send packets back to the socket
- * they originated from - MvS (miquels@drinkel.ow.org)
- */
- if (ptype->type == htons(ETH_P_ALL) &&
- (ptype->dev == dev || !ptype->dev) &&
- ((struct sock *)ptype->data != skb->sk))
- {
- struct sk_buff *skb2;
- if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
- break;
- /*
- * The protocol knows this has (for other paths) been taken off
- * and adds it back.
- */
- skb2->len-=skb->dev->hard_header_len;
- ptype->func(skb2, skb->dev, ptype);
- nitcount--;
- }
- }
- }
- if (dev->hard_start_xmit(skb, dev) == 0) {
- /*
- * Packet is now solely the responsibility of the driver
- */
- return;
- }
-
- /*
- * Transmission failed, put skb back into a list. Once on the list it's safe and
- * no longer device locked (it can be freed safely from the device queue)
- */
- cli();
-#ifdef CONFIG_SLAVE_BALANCING
- skb->in_dev_queue=1;
- dev->pkt_queue++;
-#endif
- skb_device_unlock(skb);
- skb_queue_head(dev->buffs + pri,skb);
- restore_flags(flags);
-}
-
-/*
- * Receive a packet from a device driver and queue it for the upper
- * (protocol) levels. It always succeeds. This is the recommended
- * interface to use.
- */
-
-void netif_rx(struct sk_buff *skb)
-{
- static int dropping = 0;
-
- /*
- * Any received buffers are un-owned and should be discarded
- * when freed. These will be updated later as the frames get
- * owners.
- */
- skb->sk = NULL;
- skb->free = 1;
- if(skb->stamp.tv_sec==0)
- skb->stamp = xtime;
-
- /*
- * Check that we aren't overdoing things.
- */
-
- if (!backlog_size)
- dropping = 0;
- else if (backlog_size > 300)
- dropping = 1;
-
- if (dropping)
- {
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Add it to the "backlog" queue.
- */
-#ifdef CONFIG_SKB_CHECK
- IS_SKB(skb);
-#endif
- skb_queue_tail(&backlog,skb);
- backlog_size++;
-
- /*
- * If any packet arrived, mark it for processing after the
- * hardware interrupt returns.
- */
-
- mark_bh(NET_BH);
- return;
-}
-
-
-/*
- * The old interface to fetch a packet from a device driver.
- * This function is the base level entry point for all drivers that
- * want to send a packet to the upper (protocol) levels. It takes
- * care of de-multiplexing the packet to the various modules based
- * on their protocol ID.
- *
- * Return values: 1 <- exit I can't do any more
- * 0 <- feed me more (i.e. "done", "OK").
- *
- * This function is OBSOLETE and should not be used by any new
- * device.
- */
-
-int dev_rint(unsigned char *buff, long len, int flags, struct device *dev)
-{
- static int dropping = 0;
- struct sk_buff *skb = NULL;
- unsigned char *to;
- int amount, left;
- int len2;
-
- if (dev == NULL || buff == NULL || len <= 0)
- return(1);
-
- if (flags & IN_SKBUFF)
- {
- skb = (struct sk_buff *) buff;
- }
- else
- {
- if (dropping)
- {
- if (skb_peek(&backlog) != NULL)
- return(1);
- printk("INET: dev_rint: no longer dropping packets.\n");
- dropping = 0;
- }
-
- skb = alloc_skb(len, GFP_ATOMIC);
- if (skb == NULL)
- {
- printk("dev_rint: packet dropped on %s (no memory) !\n",
- dev->name);
- dropping = 1;
- return(1);
- }
-
- /*
- * First we copy the packet into a buffer, and save it for later. We
- * in effect handle the incoming data as if it were from a circular buffer
- */
-
- to = skb->data;
- left = len;
-
- len2 = len;
- while (len2 > 0)
- {
- amount = min(len2, (unsigned long) dev->rmem_end -
- (unsigned long) buff);
- memcpy(to, buff, amount);
- len2 -= amount;
- left -= amount;
- buff += amount;
- to += amount;
- if ((unsigned long) buff == dev->rmem_end)
- buff = (unsigned char *) dev->rmem_start;
- }
- }
-
- /*
- * Tag the frame and kick it to the proper receive routine
- */
-
- skb->len = len;
- skb->dev = dev;
- skb->free = 1;
-
- netif_rx(skb);
- /*
- * OK, all done.
- */
- return(0);
-}
-
-
-/*
- * This routine causes all interfaces to try to send some data.
- */
-
-void dev_transmit(void)
-{
- struct device *dev;
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (dev->flags != 0 && !dev->tbusy) {
- /*
- * Kick the device
- */
- dev_tint(dev);
- }
- }
-}
-
-
-/**********************************************************************************
-
- Receive Queue Processor
-
-***********************************************************************************/
-
-/*
- * This is a single non-reentrant routine which takes the received packet
- * queue and throws it at the networking layers in the hope that something
- * useful will emerge.
- */
-
-volatile char in_bh = 0; /* Non-reentrant remember */
-
-int in_net_bh() /* Used by timer.c */
-{
- return(in_bh==0?0:1);
-}
-
-/*
- * When we are called the queue is ready to grab, the interrupts are
- * on and hardware can interrupt and queue to the receive queue a we
- * run with no problems.
- * This is run as a bottom half after an interrupt handler that does
- * mark_bh(NET_BH);
- */
-
-void net_bh(void *tmp)
-{
- struct sk_buff *skb;
- struct packet_type *ptype;
- struct packet_type *pt_prev;
- unsigned short type;
-
- /*
- * Atomically check and mark our BUSY state.
- */
-
- if (set_bit(1, (void*)&in_bh))
- return;
-
- /*
- * Can we send anything now? We want to clear the
- * decks for any more sends that get done as we
- * process the input.
- */
-
- dev_transmit();
-
- /*
- * Any data left to process. This may occur because a
- * mark_bh() is done after we empty the queue including
- * that from the device which does a mark_bh() just after
- */
-
- cli();
-
- /*
- * While the queue is not empty
- */
-
- while((skb=skb_dequeue(&backlog))!=NULL)
- {
- /*
- * We have a packet. Therefore the queue has shrunk
- */
- backlog_size--;
-
- sti();
-
- /*
- * Bump the pointer to the next structure.
- * This assumes that the basic 'skb' pointer points to
- * the MAC header, if any (as indicated by its "length"
- * field). Take care now!
- */
-
- skb->h.raw = skb->data + skb->dev->hard_header_len;
- skb->len -= skb->dev->hard_header_len;
-
- /*
- * Fetch the packet protocol ID. This is also quite ugly, as
- * it depends on the protocol driver (the interface itself) to
- * know what the type is, or where to get it from. The Ethernet
- * interfaces fetch the ID from the two bytes in the Ethernet MAC
- * header (the h_proto field in struct ethhdr), but other drivers
- * may either use the ethernet ID's or extra ones that do not
- * clash (eg ETH_P_AX25). We could set this before we queue the
- * frame. In fact I may change this when I have time.
- */
-
- type = skb->dev->type_trans(skb, skb->dev);
-
- /*
- * We got a packet ID. Now loop over the "known protocols"
- * table (which is actually a linked list, but this will
- * change soon if I get my way- FvK), and forward the packet
- * to anyone who wants it.
- *
- * [FvK didn't get his way but he is right this ought to be
- * hashed so we typically get a single hit. The speed cost
- * here is minimal but no doubt adds up at the 4,000+ pkts/second
- * rate we can hit flat out]
- */
- pt_prev = NULL;
- for (ptype = ptype_base; ptype != NULL; ptype = ptype->next)
- {
- if ((ptype->type == type || ptype->type == htons(ETH_P_ALL)) && (!ptype->dev || ptype->dev==skb->dev))
- {
- /*
- * We already have a match queued. Deliver
- * to it and then remember the new match
- */
- if(pt_prev)
- {
- struct sk_buff *skb2;
-
- skb2=skb_clone(skb, GFP_ATOMIC);
-
- /*
- * Kick the protocol handler. This should be fast
- * and efficient code.
- */
-
- if(skb2)
- pt_prev->func(skb2, skb->dev, pt_prev);
- }
- /* Remember the current last to do */
- pt_prev=ptype;
- }
- } /* End of protocol list loop */
-
- /*
- * Is there a last item to send to ?
- */
-
- if(pt_prev)
- pt_prev->func(skb, skb->dev, pt_prev);
- /*
- * Has an unknown packet has been received ?
- */
-
- else
- kfree_skb(skb, FREE_WRITE);
-
- /*
- * Again, see if we can transmit anything now.
- * [Ought to take this out judging by tests it slows
- * us down not speeds us up]
- */
-
- dev_transmit();
- cli();
- } /* End of queue loop */
-
- /*
- * We have emptied the queue
- */
-
- in_bh = 0;
- sti();
-
- /*
- * One last output flush.
- */
-
- dev_transmit();
-}
-
-
-/*
- * This routine is called when an device driver (i.e. an
- * interface) is ready to transmit a packet.
- */
-
-void dev_tint(struct device *dev)
-{
- int i;
- struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- /*
- * Work the queues in priority order
- */
-
- for(i = 0;i < DEV_NUMBUFFS; i++)
- {
- /*
- * Pull packets from the queue
- */
-
-
- cli();
- while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)
- {
- /*
- * Stop anyone freeing the buffer while we retransmit it
- */
- skb_device_lock(skb);
- restore_flags(flags);
- /*
- * Feed them to the output stage and if it fails
- * indicate they re-queue at the front.
- */
- dev_queue_xmit(skb,dev,-i - 1);
- /*
- * If we can take no more then stop here.
- */
- if (dev->tbusy)
- return;
- cli();
- }
- }
- restore_flags(flags);
-}
-
-
-/*
- * Perform a SIOCGIFCONF call. This structure will change
- * size shortly, and there is nothing I can do about it.
- * Thus we will need a 'compatibility mode'.
- */
-
-static int dev_ifconf(char *arg)
-{
- struct ifconf ifc;
- struct ifreq ifr;
- struct device *dev;
- char *pos;
- int len;
- int err;
-
- /*
- * Fetch the caller's info block.
- */
-
- err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
- if(err)
- return err;
- memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));
- len = ifc.ifc_len;
- pos = ifc.ifc_buf;
-
- /*
- * We now walk the device list filling each active device
- * into the array.
- */
-
- err=verify_area(VERIFY_WRITE,pos,len);
- if(err)
- return err;
-
- /*
- * Loop over the interfaces, and write an info block for each.
- */
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if(!(dev->flags & IFF_UP)) /* Downed devices don't count */
- continue;
- memset(&ifr, 0, sizeof(struct ifreq));
- strcpy(ifr.ifr_name, dev->name);
- (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family;
- (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;
-
- /*
- * Write this block to the caller's space.
- */
-
- memcpy_tofs(pos, &ifr, sizeof(struct ifreq));
- pos += sizeof(struct ifreq);
- len -= sizeof(struct ifreq);
-
- /*
- * Have we run out of space here ?
- */
-
- if (len < sizeof(struct ifreq))
- break;
- }
-
- /*
- * All done. Write the updated control block back to the caller.
- */
-
- ifc.ifc_len = (pos - ifc.ifc_buf);
- ifc.ifc_req = (struct ifreq *) ifc.ifc_buf;
- memcpy_tofs(arg, &ifc, sizeof(struct ifconf));
-
- /*
- * Report how much was filled in
- */
-
- return(pos - arg);
-}
-
-
-/*
- * This is invoked by the /proc filesystem handler to display a device
- * in detail.
- */
-
-static int sprintf_stats(char *buffer, struct device *dev)
-{
- struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
- int size;
-
- if (stats)
- size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n",
- dev->name,
- stats->rx_packets, stats->rx_errors,
- stats->rx_dropped + stats->rx_missed_errors,
- stats->rx_fifo_errors,
- stats->rx_length_errors + stats->rx_over_errors
- + stats->rx_crc_errors + stats->rx_frame_errors,
- stats->tx_packets, stats->tx_errors, stats->tx_dropped,
- stats->tx_fifo_errors, stats->collisions,
- stats->tx_carrier_errors + stats->tx_aborted_errors
- + stats->tx_window_errors + stats->tx_heartbeat_errors);
- else
- size = sprintf(buffer, "%6s: No statistics available.\n", dev->name);
-
- return size;
-}
-
-/*
- * Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface
- * to create /proc/net/dev
- */
-
-int dev_get_info(char *buffer, char **start, off_t offset, int length)
-{
- int len=0;
- off_t begin=0;
- off_t pos=0;
- int size;
-
- struct device *dev;
-
-
- size = sprintf(buffer, "Inter-| Receive | Transmit\n"
- " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");
-
- pos+=size;
- len+=size;
-
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- size = sprintf_stats(buffer+len, dev);
- len+=size;
- pos=begin+len;
-
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
- }
-
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len=length; /* Ending slop */
- return len;
-}
-
-
-/*
- * This checks bitmasks for the ioctl calls for devices.
- */
-
-static inline int bad_mask(unsigned long mask, unsigned long addr)
-{
- if (addr & (mask = ~mask))
- return 1;
- mask = ntohl(mask);
- if (mask & (mask+1))
- return 1;
- return 0;
-}
-
-#ifndef _HURD_
-/*
- * Perform the SIOCxIFxxx calls.
- *
- * The socket layer has seen an ioctl the address family thinks is
- * for the device. At this point we get invoked to make a decision
- */
-
-static int dev_ifsioc(void *arg, unsigned int getset)
-{
- struct ifreq ifr;
- struct device *dev;
- int ret;
-
- /*
- * Fetch the caller's info block into kernel space
- */
-
- int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
- if(err)
- return err;
-
- memcpy_fromfs(&ifr, arg, sizeof(struct ifreq));
-
- /*
- * See which interface the caller is talking about.
- */
-
- if ((dev = dev_get(ifr.ifr_name)) == NULL)
- return(-ENODEV);
-
- switch(getset)
- {
- case SIOCGIFFLAGS: /* Get interface flags */
- ifr.ifr_flags = dev->flags;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFFLAGS: /* Set interface flags */
- {
- int old_flags = dev->flags;
-#ifdef CONFIG_SLAVE_BALANCING
- if(dev->flags&IFF_SLAVE)
- return -EBUSY;
-#endif
- dev->flags = ifr.ifr_flags & (
- IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
- IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
- IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER
- | IFF_MULTICAST);
-#ifdef CONFIG_SLAVE_BALANCING
- if(!(dev->flags&IFF_MASTER) && dev->slave)
- {
- dev->slave->flags&=~IFF_SLAVE;
- dev->slave=NULL;
- }
-#endif
- /*
- * Load in the correct multicast list now the flags have changed.
- */
-
- dev_mc_upload(dev);
-#if 0
- if( dev->set_multicast_list!=NULL)
- {
-
- /*
- * Has promiscuous mode been turned off
- */
-
- if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0))
- dev->set_multicast_list(dev,0,NULL);
-
- /*
- * Has it been turned on
- */
-
- if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
- dev->set_multicast_list(dev,-1,NULL);
- }
-#endif
- /*
- * Have we downed the interface
- */
-
- if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0))
- {
- ret = dev_close(dev);
- }
- else
- {
- /*
- * Have we upped the interface
- */
-
- ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
- ? dev_open(dev) : 0;
- /*
- * Check the flags.
- */
- if(ret<0)
- dev->flags&=~IFF_UP; /* Didn't open so down the if */
- }
- }
- break;
-
- case SIOCGIFADDR: /* Get interface address (and family) */
- (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;
- (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
-
- case SIOCSIFADDR: /* Set interface address (and family) */
- dev->pa_addr = (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_addr.s_addr;
- dev->family = ifr.ifr_addr.sa_family;
-
-#ifdef CONFIG_INET
- /* This is naughty. When net-032e comes out It wants moving into the net032
- code not the kernel. Till then it can sit here (SIGH) */
- dev->pa_mask = ip_get_mask(dev->pa_addr);
-#endif
- dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
- ret = 0;
- break;
-
- case SIOCGIFBRDADDR: /* Get the broadcast address */
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
-
- case SIOCSIFBRDADDR: /* Set the broadcast address */
- dev->pa_brdaddr = (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_addr.s_addr;
- ret = 0;
- break;
-
- case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */
- (*(struct sockaddr_in *)
- &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
-
- case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */
- dev->pa_dstaddr = (*(struct sockaddr_in *)
- &ifr.ifr_dstaddr).sin_addr.s_addr;
- ret = 0;
- break;
-
- case SIOCGIFNETMASK: /* Get the netmask for the interface */
- (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask;
- (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
-
- case SIOCSIFNETMASK: /* Set the netmask for the interface */
- {
- unsigned long mask = (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_addr.s_addr;
- ret = -EINVAL;
- /*
- * The mask we set must be legal.
- */
- if (bad_mask(mask,0))
- break;
- dev->pa_mask = mask;
- ret = 0;
- }
- break;
-
- case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */
-
- ifr.ifr_metric = dev->metric;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
-
- case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */
- dev->metric = ifr.ifr_metric;
- ret = 0;
- break;
-
- case SIOCGIFMTU: /* Get the MTU of a device */
- ifr.ifr_mtu = dev->mtu;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
-
- case SIOCSIFMTU: /* Set the MTU of a device */
-
- /*
- * MTU must be positive and under the page size problem
- */
-
- if(ifr.ifr_mtu<1 || ifr.ifr_mtu>3800)
- return -EINVAL;
- dev->mtu = ifr.ifr_mtu;
- ret = 0;
- break;
-
- case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently
- do not support it */
- printk("NET: ioctl(SIOCGIFMEM, %p)\n", arg);
- ret = -EINVAL;
- break;
-
- case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */
- printk("NET: ioctl(SIOCSIFMEM, %p)\n", arg);
- ret = -EINVAL;
- break;
-
- case OLD_SIOCGIFHWADDR: /* Get the hardware address. This will change and SIFHWADDR will be added */
- memcpy(ifr.old_ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN);
- memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
- ret=0;
- break;
-
- case SIOCGIFHWADDR:
- memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN);
- ifr.ifr_hwaddr.sa_family=dev->type;
- memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
- ret=0;
- break;
-
- case SIOCSIFHWADDR:
- if(dev->set_mac_address==NULL)
- return -EOPNOTSUPP;
- if(ifr.ifr_hwaddr.sa_family!=dev->type)
- return -EINVAL;
- ret=dev->set_mac_address(dev,ifr.ifr_hwaddr.sa_data);
- break;
-
- case SIOCGIFMAP:
- ifr.ifr_map.mem_start=dev->mem_start;
- ifr.ifr_map.mem_end=dev->mem_end;
- ifr.ifr_map.base_addr=dev->base_addr;
- ifr.ifr_map.irq=dev->irq;
- ifr.ifr_map.dma=dev->dma;
- ifr.ifr_map.port=dev->if_port;
- memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
- ret=0;
- break;
-
- case SIOCSIFMAP:
- if(dev->set_config==NULL)
- return -EOPNOTSUPP;
- return dev->set_config(dev,&ifr.ifr_map);
-
- case SIOCGIFSLAVE:
-#ifdef CONFIG_SLAVE_BALANCING
- if(dev->slave==NULL)
- return -ENOENT;
- strncpy(ifr.ifr_name,dev->name,sizeof(ifr.ifr_name));
- memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
- ret=0;
-#else
- return -ENOENT;
-#endif
- break;
-#ifdef CONFIG_SLAVE_BALANCING
- case SIOCSIFSLAVE:
- {
-
- /*
- * Fun game. Get the device up and the flags right without
- * letting some scummy user confuse us.
- */
- unsigned long flags;
- struct device *slave=dev_get(ifr.ifr_slave);
- save_flags(flags);
- if(slave==NULL)
- {
- return -ENODEV;
- }
- cli();
- if((slave->flags&(IFF_UP|IFF_RUNNING))!=(IFF_UP|IFF_RUNNING))
- {
- restore_flags(flags);
- return -EINVAL;
- }
- if(dev->flags&IFF_SLAVE)
- {
- restore_flags(flags);
- return -EBUSY;
- }
- if(dev->slave!=NULL)
- {
- restore_flags(flags);
- return -EBUSY;
- }
- if(slave->flags&IFF_SLAVE)
- {
- restore_flags(flags);
- return -EBUSY;
- }
- dev->slave=slave;
- slave->flags|=IFF_SLAVE;
- dev->flags|=IFF_MASTER;
- restore_flags(flags);
- ret=0;
- }
- break;
-#endif
-
- case SIOCADDMULTI:
- if(dev->set_multicast_list==NULL)
- return -EINVAL;
- if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC)
- return -EINVAL;
- dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1);
- return 0;
-
- case SIOCDELMULTI:
- if(dev->set_multicast_list==NULL)
- return -EINVAL;
- if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC)
- return -EINVAL;
- dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1);
- return 0;
- /*
- * Unknown or private ioctl
- */
-
- default:
- if((getset >= SIOCDEVPRIVATE) &&
- (getset <= (SIOCDEVPRIVATE + 15))) {
- if(dev->do_ioctl==NULL)
- return -EOPNOTSUPP;
- ret=dev->do_ioctl(dev, &ifr, getset);
- memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
- break;
- }
-
- ret = -EINVAL;
- }
- return(ret);
-}
-
-
-/*
- * This function handles all "interface"-type I/O control requests. The actual
- * 'doing' part of this is dev_ifsioc above.
- */
-
-int dev_ioctl(unsigned int cmd, void *arg)
-{
- switch(cmd)
- {
- case SIOCGIFCONF:
- (void) dev_ifconf((char *) arg);
- return 0;
-
- /*
- * Ioctl calls that can be done by all.
- */
-
- case SIOCGIFFLAGS:
- case SIOCGIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCGIFMTU:
- case SIOCGIFMEM:
- case SIOCGIFHWADDR:
- case SIOCSIFHWADDR:
- case OLD_SIOCGIFHWADDR:
- case SIOCGIFSLAVE:
- case SIOCGIFMAP:
- return dev_ifsioc(arg, cmd);
-
- /*
- * Ioctl calls requiring the power of a superuser
- */
-
- case SIOCSIFFLAGS:
- case SIOCSIFADDR:
- case SIOCSIFDSTADDR:
- case SIOCSIFBRDADDR:
- case SIOCSIFNETMASK:
- case SIOCSIFMETRIC:
- case SIOCSIFMTU:
- case SIOCSIFMEM:
- case SIOCSIFMAP:
- case SIOCSIFSLAVE:
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- if (!suser())
- return -EPERM;
- return dev_ifsioc(arg, cmd);
-
- case SIOCSIFLINK:
- return -EINVAL;
-
- /*
- * Unknown or private ioctl.
- */
-
- default:
- if((cmd >= SIOCDEVPRIVATE) &&
- (cmd <= (SIOCDEVPRIVATE + 15))) {
- return dev_ifsioc(arg, cmd);
- }
- return -EINVAL;
- }
-}
-#endif
-
-
-/*
- * Initialize the DEV module. At boot time this walks the device list and
- * unhooks any devices that fail to initialise (normally hardware not
- * present) and leaves us with a valid list of present and active devices.
- *
- * The PCMCIA code may need to change this a little, and add a pair
- * of register_inet_device() unregister_inet_device() calls. This will be
- * needed for ethernet as modules support.
- */
-
-void dev_init(void)
-{
- struct device *dev, *dev2;
-
- /*
- * Add the devices.
- * If the call to dev->init fails, the dev is removed
- * from the chain disconnecting the device until the
- * next reboot.
- */
-
- dev2 = NULL;
- for (dev = dev_base; dev != NULL; dev=dev->next)
- {
- if (dev->init && dev->init(dev))
- {
- /*
- * It failed to come up. Unhook it.
- */
-
- if (dev2 == NULL)
- dev_base = dev->next;
- else
- dev2->next = dev->next;
- }
- else
- {
- dev2 = dev;
- }
- }
-}
diff --git a/pfinet/linux-inet/dev_mcast.c b/pfinet/linux-inet/dev_mcast.c
deleted file mode 100644
index cd5e356e..00000000
--- a/pfinet/linux-inet/dev_mcast.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Linux NET3: Multicast List maintenance.
- *
- * Authors:
- * Tim Kordas <tjk@nostromo.eeap.cwru.edu>
- * Richard Underwood <richard@wuzz.demon.co.uk>
- *
- * Stir fried together from the IP multicast and CAP patches above
- * Alan Cox <Alan.Cox@linux.org>
- *
- * Fixes:
- * Alan Cox : Update the device on a real delete
- * rather than any time but...
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "ip.h"
-#include "route.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "arp.h"
-
-
-/*
- * Device multicast list maintenance. This knows about such little matters as promiscuous mode and
- * converting from the list to the array the drivers use. At least until I fix the drivers up.
- *
- * This is used both by IP and by the user level maintenance functions. Unlike BSD we maintain a usage count
- * on a given multicast address so that a casual user application can add/delete multicasts used by protocols
- * without doing damage to the protocols when it deletes the entries. It also helps IP as it tracks overlapping
- * maps.
- */
-
-
-/*
- * Update the multicast list into the physical NIC controller.
- */
-
-void dev_mc_upload(struct device *dev)
-{
- struct dev_mc_list *dmi;
- char *data, *tmp;
-
- /* Don't do anything till we up the interface
- [dev_open will call this function so the list will
- stay sane] */
-
- if(!(dev->flags&IFF_UP))
- return;
-
-
- /* Devices with no set multicast don't get set */
- if(dev->set_multicast_list==NULL)
- return;
- /* Promiscuous is promiscuous - so no filter needed */
- if(dev->flags&IFF_PROMISC)
- {
- dev->set_multicast_list(dev, -1, NULL);
- return;
- }
-
- if(dev->mc_count==0)
- {
- dev->set_multicast_list(dev,0,NULL);
- return;
- }
-
- data=kmalloc(dev->mc_count*dev->addr_len, GFP_KERNEL);
- if(data==NULL)
- {
- printk("Unable to get memory to set multicast list on %s\n",dev->name);
- return;
- }
- for(tmp = data, dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
- {
- memcpy(tmp,dmi->dmi_addr, dmi->dmi_addrlen);
- tmp+=dev->addr_len;
- }
- dev->set_multicast_list(dev,dev->mc_count,data);
- kfree(data);
-}
-
-/*
- * Delete a device level multicast
- */
-
-void dev_mc_delete(struct device *dev, void *addr, int alen, int all)
-{
- struct dev_mc_list **dmi;
- for(dmi=&dev->mc_list;*dmi!=NULL;dmi=&(*dmi)->next)
- {
- if(memcmp((*dmi)->dmi_addr,addr,(*dmi)->dmi_addrlen)==0 && alen==(*dmi)->dmi_addrlen)
- {
- struct dev_mc_list *tmp= *dmi;
- if(--(*dmi)->dmi_users && !all)
- return;
- *dmi=(*dmi)->next;
- dev->mc_count--;
- kfree_s(tmp,sizeof(*tmp));
- dev_mc_upload(dev);
- return;
- }
- }
-}
-
-/*
- * Add a device level multicast
- */
-
-void dev_mc_add(struct device *dev, void *addr, int alen, int newonly)
-{
- struct dev_mc_list *dmi;
- for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
- {
- if(memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen)
- {
- if(!newonly)
- dmi->dmi_users++;
- return;
- }
- }
- dmi=(struct dev_mc_list *)kmalloc(sizeof(*dmi),GFP_KERNEL);
- if(dmi==NULL)
- return; /* GFP_KERNEL so can't happen anyway */
- memcpy(dmi->dmi_addr, addr, alen);
- dmi->dmi_addrlen=alen;
- dmi->next=dev->mc_list;
- dmi->dmi_users=1;
- dev->mc_list=dmi;
- dev->mc_count++;
- dev_mc_upload(dev);
-}
-
-/*
- * Discard multicast list when a device is downed
- */
-
-void dev_mc_discard(struct device *dev)
-{
- while(dev->mc_list!=NULL)
- {
- struct dev_mc_list *tmp=dev->mc_list;
- dev->mc_list=dev->mc_list->next;
- kfree_s(tmp,sizeof(*tmp));
- }
- dev->mc_count=0;
-}
-
diff --git a/pfinet/linux-inet/devinet.c b/pfinet/linux-inet/devinet.c
deleted file mode 100644
index 946536be..00000000
--- a/pfinet/linux-inet/devinet.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * NET3 IP device support routines.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Derived from the IP parts of dev.c 1.0.19
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Mark Evans, <evansmp@uhura.aston.ac.uk>
- *
- * Additional Authors:
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- */
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "tcp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "arp.h"
-
-/*
- * Determine a default network mask, based on the IP address.
- */
-
-unsigned long ip_get_mask(unsigned long addr)
-{
- unsigned long dst;
-
- if (addr == 0L)
- return(0L); /* special case */
-
- dst = ntohl(addr);
- if (IN_CLASSA(dst))
- return(htonl(IN_CLASSA_NET));
- if (IN_CLASSB(dst))
- return(htonl(IN_CLASSB_NET));
- if (IN_CLASSC(dst))
- return(htonl(IN_CLASSC_NET));
-
- /*
- * Something else, probably a multicast.
- */
-
- return(0);
-}
-
-/*
- * Check the address for our address, broadcasts, etc.
- *
- * I intend to fix this to at the very least cache the last
- * resolved entry.
- */
-
-int ip_chk_addr(unsigned long addr)
-{
- struct device *dev;
- unsigned long mask;
-
- /*
- * Accept both `all ones' and `all zeros' as BROADCAST.
- * (Support old BSD in other words). This old BSD
- * support will go very soon as it messes other things
- * up.
- * Also accept `loopback broadcast' as BROADCAST.
- */
-
- if (addr == INADDR_ANY || addr == INADDR_BROADCAST ||
- addr == htonl(0x7FFFFFFFL))
- return IS_BROADCAST;
-
- mask = ip_get_mask(addr);
-
- /*
- * Accept all of the `loopback' class A net.
- */
-
- if ((addr & mask) == htonl(0x7F000000L))
- return IS_MYADDR;
-
- /*
- * OK, now check the interface addresses.
- */
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (!(dev->flags & IFF_UP))
- continue;
- /*
- * If the protocol address of the device is 0 this is special
- * and means we are address hunting (eg bootp).
- */
-
- if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
- return IS_MYADDR;
- /*
- * Is it the exact IP address?
- */
-
- if (addr == dev->pa_addr)
- return IS_MYADDR;
- /*
- * Is it our broadcast address?
- */
-
- if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr)
- return IS_BROADCAST;
- /*
- * Nope. Check for a subnetwork broadcast.
- */
-
- if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0)
- {
- if ((addr & ~dev->pa_mask) == 0)
- return IS_BROADCAST;
- if ((addr & ~dev->pa_mask) == ~dev->pa_mask)
- return IS_BROADCAST;
- }
-
- /*
- * Nope. Check for Network broadcast.
- */
-
- if (((addr ^ dev->pa_addr) & mask) == 0)
- {
- if ((addr & ~mask) == 0)
- return IS_BROADCAST;
- if ((addr & ~mask) == ~mask)
- return IS_BROADCAST;
- }
- }
- if(IN_MULTICAST(ntohl(addr)))
- return IS_MULTICAST;
- return 0; /* no match at all */
-}
-
-
-/*
- * Retrieve our own address.
- *
- * Because the loopback address (127.0.0.1) is already recognized
- * automatically, we can use the loopback interface's address as
- * our "primary" interface. This is the address used by IP et
- * al when it doesn't know which address to use (i.e. it does not
- * yet know from or to which interface to go...).
- */
-
-unsigned long ip_my_addr(void)
-{
- struct device *dev;
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (dev->flags & IFF_LOOPBACK)
- return(dev->pa_addr);
- }
- return(0);
-}
-
-/*
- * Find an interface that can handle addresses for a certain address.
- *
- * This needs optimising, since it's relatively trivial to collapse
- * the two loops into one.
- */
-
-struct device * ip_dev_check(unsigned long addr)
-{
- struct device *dev;
-
- for (dev = dev_base; dev; dev = dev->next)
- {
- if (!(dev->flags & IFF_UP))
- continue;
- if (!(dev->flags & IFF_POINTOPOINT))
- continue;
- if (addr != dev->pa_dstaddr)
- continue;
- return dev;
- }
- for (dev = dev_base; dev; dev = dev->next)
- {
- if (!(dev->flags & IFF_UP))
- continue;
- if (dev->flags & IFF_POINTOPOINT)
- continue;
- if (dev->pa_mask & (addr ^ dev->pa_addr))
- continue;
- return dev;
- }
- return NULL;
-}
diff --git a/pfinet/linux-inet/eth.h b/pfinet/linux-inet/eth.h
deleted file mode 100644
index f8fed44e..00000000
--- a/pfinet/linux-inet/eth.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. NET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the Ethernet handlers.
- *
- * Version: @(#)eth.h 1.0.4 05/13/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _ETH_H
-#define _ETH_H
-
-
-#include <linux/if_ether.h>
-
-
-extern char *eth_print(unsigned char *ptr);
-extern void eth_dump(struct ethhdr *eth);
-extern int eth_header(unsigned char *buff, struct device *dev,
- unsigned short type, unsigned long daddr,
- unsigned long saddr, unsigned len);
-extern int eth_rebuild_header(void *buff, struct device *dev);
-extern void eth_add_arp(unsigned long addr, struct sk_buff *skb,
- struct device *dev);
-extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev);
-
-#endif /* _ETH_H */
diff --git a/pfinet/linux-inet/icmp.c b/pfinet/linux-inet/icmp.c
deleted file mode 100644
index c023eab2..00000000
--- a/pfinet/linux-inet/icmp.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Internet Control Message Protocol (ICMP)
- *
- * Version: @(#)icmp.c 1.0.11 06/02/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Mark Evans, <evansmp@uhura.aston.ac.uk>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Stefan Becker, <stefanb@yello.ping.de>
- *
- * Fixes:
- * Alan Cox : Generic queue usage.
- * Gerhard Koerting: ICMP addressing corrected
- * Alan Cox : Use tos/ttl settings
- * Alan Cox : Protocol violations
- * Alan Cox : SNMP Statistics
- * Alan Cox : Routing errors
- * Alan Cox : Changes for newer routing code
- * Alan Cox : Removed old debugging junk
- * Alan Cox : Fixed the ICMP error status of net/host unreachable
- * Gerhard Koerting : Fixed broadcast ping properly
- * Ulrich Kunitz : Fixed ICMP timestamp reply
- * A.N.Kuznetsov : Multihoming fixes.
- * Laco Rusnak : Multihoming fixes.
- * Alan Cox : Tightened up icmp_send().
- * Alan Cox : Multicasts.
- * Stefan Becker : ICMP redirects in icmp_send().
- *
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/string.h>
-#include "snmp.h"
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "icmp.h"
-#include "tcp.h"
-#include "snmp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-
-
-#define min(a,b) ((a)<(b)?(a):(b))
-
-
-/*
- * Statistics
- */
-
-struct icmp_mib icmp_statistics={0,};
-
-
-/* An array of errno for error messages from dest unreach. */
-struct icmp_err icmp_err_convert[] = {
- { ENETUNREACH, 0 }, /* ICMP_NET_UNREACH */
- { EHOSTUNREACH, 0 }, /* ICMP_HOST_UNREACH */
- { ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */
- { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */
- { EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */
- { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */
- { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */
- { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */
- { ENONET, 1 }, /* ICMP_HOST_ISOLATED */
- { ENETUNREACH, 1 }, /* ICMP_NET_ANO */
- { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */
- { EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS */
- { EOPNOTSUPP, 0 } /* ICMP_HOST_UNR_TOS */
-};
-
-
-/*
- * Send an ICMP message in response to a situation
- *
- * Fixme: Fragment handling is wrong really.
- */
-
-void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev)
-{
- struct sk_buff *skb;
- struct iphdr *iph;
- int offset;
- struct icmphdr *icmph;
- int len;
- struct device *ndev=NULL; /* Make this =dev to force replies on the same interface */
- unsigned long our_addr;
- int atype;
-
- /*
- * Find the original IP header.
- */
-
- iph = (struct iphdr *) (skb_in->data + dev->hard_header_len);
-
- /*
- * No replies to MAC multicast
- */
-
- if(skb_in->pkt_type!=PACKET_HOST)
- return;
-
- /*
- * No replies to IP multicasting
- */
-
- atype=ip_chk_addr(iph->daddr);
- if(atype==IS_BROADCAST || IN_MULTICAST(iph->daddr))
- return;
-
- /*
- * Only reply to first fragment.
- */
-
- if(ntohs(iph->frag_off)&IP_OFFSET)
- return;
-
- /*
- * We must NEVER NEVER send an ICMP error to an ICMP error message
- */
-
- if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED)
- {
-
- /*
- * Is the original packet an ICMP packet?
- */
-
- if(iph->protocol==IPPROTO_ICMP)
- {
- icmph = (struct icmphdr *) ((char *) iph +
- 4 * iph->ihl);
- /*
- * Check for ICMP error packets (Must never reply to
- * an ICMP error).
- */
-
- if (icmph->type == ICMP_DEST_UNREACH ||
- icmph->type == ICMP_SOURCE_QUENCH ||
- icmph->type == ICMP_REDIRECT ||
- icmph->type == ICMP_TIME_EXCEEDED ||
- icmph->type == ICMP_PARAMETERPROB)
- return;
- }
- }
- icmp_statistics.IcmpOutMsgs++;
-
- /*
- * This needs a tidy.
- */
-
- switch(type)
- {
- case ICMP_DEST_UNREACH:
- icmp_statistics.IcmpOutDestUnreachs++;
- break;
- case ICMP_SOURCE_QUENCH:
- icmp_statistics.IcmpOutSrcQuenchs++;
- break;
- case ICMP_REDIRECT:
- icmp_statistics.IcmpOutRedirects++;
- break;
- case ICMP_ECHO:
- icmp_statistics.IcmpOutEchos++;
- break;
- case ICMP_ECHOREPLY:
- icmp_statistics.IcmpOutEchoReps++;
- break;
- case ICMP_TIME_EXCEEDED:
- icmp_statistics.IcmpOutTimeExcds++;
- break;
- case ICMP_PARAMETERPROB:
- icmp_statistics.IcmpOutParmProbs++;
- break;
- case ICMP_TIMESTAMP:
- icmp_statistics.IcmpOutTimestamps++;
- break;
- case ICMP_TIMESTAMPREPLY:
- icmp_statistics.IcmpOutTimestampReps++;
- break;
- case ICMP_ADDRESS:
- icmp_statistics.IcmpOutAddrMasks++;
- break;
- case ICMP_ADDRESSREPLY:
- icmp_statistics.IcmpOutAddrMaskReps++;
- break;
- }
- /*
- * Get some memory for the reply.
- */
-
- len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) +
- sizeof(struct iphdr) + 32; /* amount of header to return */
-
- skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
- if (skb == NULL)
- {
- icmp_statistics.IcmpOutErrors++;
- return;
- }
- skb->free = 1;
-
- /*
- * Build Layer 2-3 headers for message back to source.
- */
-
- our_addr = dev->pa_addr;
- if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
- our_addr = iph->daddr;
- offset = ip_build_header(skb, our_addr, iph->saddr,
- &ndev, IPPROTO_ICMP, NULL, len,
- skb_in->ip_hdr->tos,255);
- if (offset < 0)
- {
- icmp_statistics.IcmpOutErrors++;
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
-
- skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
-
- /*
- * Fill in the frame
- */
-
- icmph = (struct icmphdr *) (skb->data + offset);
- icmph->type = type;
- icmph->code = code;
- icmph->checksum = 0;
- icmph->un.gateway = info; /* This might not be meant for
- this form of the union but it will
- be right anyway */
- memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
-
- icmph->checksum = ip_compute_csum((unsigned char *)icmph,
- sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
-
- /*
- * Send it and free it once sent.
- */
- ip_queue_xmit(NULL, ndev, skb, 1);
-}
-
-
-/*
- * Handle ICMP_UNREACH and ICMP_QUENCH.
- */
-
-static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
-{
- struct inet_protocol *ipprot;
- struct iphdr *iph;
- unsigned char hash;
- int err;
-
- err = (icmph->type << 8) | icmph->code;
- iph = (struct iphdr *) (icmph + 1);
-
- switch(icmph->code & 7)
- {
- case ICMP_NET_UNREACH:
- break;
- case ICMP_HOST_UNREACH:
- break;
- case ICMP_PROT_UNREACH:
- printk("ICMP: %s:%d: protocol unreachable.\n",
- in_ntoa(iph->daddr), ntohs(iph->protocol));
- break;
- case ICMP_PORT_UNREACH:
- break;
- case ICMP_FRAG_NEEDED:
- printk("ICMP: %s: fragmentation needed and DF set.\n",
- in_ntoa(iph->daddr));
- break;
- case ICMP_SR_FAILED:
- printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
- break;
- default:
- break;
- }
-
- /*
- * Get the protocol(s).
- */
-
- hash = iph->protocol & (MAX_INET_PROTOS -1);
-
- /*
- * This can't change while we are doing it.
- */
-
- ipprot = (struct inet_protocol *) inet_protos[hash];
- while(ipprot != NULL)
- {
- struct inet_protocol *nextip;
-
- nextip = (struct inet_protocol *) ipprot->next;
-
- /*
- * Pass it off to everyone who wants it.
- */
- if (iph->protocol == ipprot->protocol && ipprot->err_handler)
- {
- ipprot->err_handler(err, (unsigned char *)(icmph + 1),
- iph->daddr, iph->saddr, ipprot);
- }
-
- ipprot = nextip;
- }
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Handle ICMP_REDIRECT.
- */
-
-static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
- struct device *dev, unsigned long source)
-{
- struct rtable *rt;
- struct iphdr *iph;
- unsigned long ip;
-
- /*
- * Get the copied header of the packet that caused the redirect
- */
-
- iph = (struct iphdr *) (icmph + 1);
- ip = iph->daddr;
-
- switch(icmph->code & 7)
- {
- case ICMP_REDIR_NET:
- /*
- * This causes a problem with subnetted networks. What we should do
- * is use ICMP_ADDRESS to get the subnet mask of the problem route
- * and set both. But we don't..
- */
-#ifdef not_a_good_idea
- ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev,0, 0);
- break;
-#endif
- case ICMP_REDIR_HOST:
- /*
- * Add better route to host.
- * But first check that the redirect
- * comes from the old gateway..
- * And make sure it's an ok host address
- * (not some confused thing sending our
- * address)
- */
- rt = ip_rt_route(ip, NULL, NULL);
- if (!rt)
- break;
- if (rt->rt_gateway != source || ip_chk_addr(icmph->un.gateway))
- break;
- printk("redirect from %s\n", in_ntoa(source));
- ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev,0, 0);
- break;
- case ICMP_REDIR_NETTOS:
- case ICMP_REDIR_HOSTTOS:
- printk("ICMP: cannot handle TOS redirects yet!\n");
- break;
- default:
- break;
- }
-
- /*
- * Discard the original packet
- */
-
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Handle ICMP_ECHO ("ping") requests.
- */
-
-static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- struct device *ndev=NULL;
- int size, offset;
-
- icmp_statistics.IcmpOutEchoReps++;
- icmp_statistics.IcmpOutMsgs++;
-
- size = dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
-
- if (skb2 == NULL)
- {
- icmp_statistics.IcmpOutErrors++;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->free = 1;
-
- /* Build Layer 2-3 headers for message back to source */
- offset = ip_build_header(skb2, daddr, saddr, &ndev,
- IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
- if (offset < 0)
- {
- icmp_statistics.IcmpOutErrors++;
- printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
- kfree_skb(skb2,FREE_WRITE);
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
-
- skb2->len = offset + len;
-
- /*
- * Build ICMP_ECHO Response message.
- */
- icmphr = (struct icmphdr *) (skb2->data + offset);
- memcpy((char *) icmphr, (char *) icmph, len);
- icmphr->type = ICMP_ECHOREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /*
- * Ship it out - free it when done
- */
- ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
-
- /*
- * Free the received frame
- */
-
- kfree_skb(skb, FREE_READ);
-}
-
-/*
- * Handle ICMP Timestamp requests.
- */
-
-static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
- unsigned long *timeptr, midtime;
- struct device *ndev=NULL;
-
- if (len != 20)
- {
- printk(
- "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
- len);
- icmp_statistics.IcmpInErrors++;
-#if 1
- /* correct answers are possible for everything >= 12 */
- if (len < 12)
-#endif
- return;
- }
-
- size = dev->hard_header_len + 84;
-
- if (! (skb2 = alloc_skb(size, GFP_ATOMIC)))
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- icmp_statistics.IcmpOutErrors++;
- return;
- }
- skb2->free = 1;
-
-/*
- * Build Layer 2-3 headers for message back to source
- */
-
- offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len,
- skb->ip_hdr->tos, 255);
- if (offset < 0)
- {
- printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
- kfree_skb(skb2, FREE_WRITE);
- kfree_skb(skb, FREE_READ);
- icmp_statistics.IcmpOutErrors++;
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
- skb2->len = offset + 20;
-
- /*
- * Build ICMP_TIMESTAMP Response message.
- */
-
- icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
- memcpy((char *) icmphr, (char *) icmph, 12);
- icmphr->type = ICMP_TIMESTAMPREPLY;
- icmphr->code = icmphr->checksum = 0;
-
- /* fill in the current time as ms since midnight UT: */
- midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
- timeptr = (unsigned long *) (icmphr + 1);
- /*
- * the originate timestamp (timeptr [0]) is still in the copy:
- */
- timeptr [1] = timeptr [2] = htonl(midtime);
-
- icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
-
- /*
- * Ship it out - free it when done
- */
-
- ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
- icmp_statistics.IcmpOutTimestampReps++;
- kfree_skb(skb, FREE_READ);
-}
-
-
-
-
-/*
- * Handle the ICMP INFORMATION REQUEST.
- */
-
-static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- /* Obsolete */
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Handle ICMP_ADDRESS_MASK requests.
- */
-
-static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
- unsigned long saddr, unsigned long daddr, int len,
- struct options *opt)
-{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
- struct device *ndev=NULL;
-
- icmp_statistics.IcmpOutMsgs++;
- icmp_statistics.IcmpOutAddrMaskReps++;
-
- size = dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
- if (skb2 == NULL)
- {
- icmp_statistics.IcmpOutErrors++;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->free = 1;
-
- /*
- * Build Layer 2-3 headers for message back to source
- */
-
- offset = ip_build_header(skb2, daddr, saddr, &ndev,
- IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
- if (offset < 0)
- {
- icmp_statistics.IcmpOutErrors++;
- printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
- kfree_skb(skb2,FREE_WRITE);
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Re-adjust length according to actual IP header size.
- */
-
- skb2->len = offset + len;
-
- /*
- * Build ICMP ADDRESS MASK Response message.
- */
-
- icmphr = (struct icmphdr *) (skb2->data + offset);
- icmphr->type = ICMP_ADDRESSREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->un.echo.id = icmph->un.echo.id;
- icmphr->un.echo.sequence = icmph->un.echo.sequence;
- memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
-
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /* Ship it out - free it when done */
- ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
-
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
-}
-
-
-/*
- * Deal with incoming ICMP packets.
- */
-
-int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
- unsigned long daddr, unsigned short len,
- unsigned long saddr, int redo, struct inet_protocol *protocol)
-{
- struct icmphdr *icmph;
- unsigned char *buff;
-
- /*
- * Drop broadcast packets. IP has done a broadcast check and ought one day
- * to pass on that information.
- */
-
- icmp_statistics.IcmpInMsgs++;
-
-
- /*
- * Grab the packet as an icmp object
- */
-
- buff = skb1->h.raw;
- icmph = (struct icmphdr *) buff;
-
- /*
- * Validate the packet first
- */
-
- if (ip_compute_csum((unsigned char *) icmph, len))
- {
- /* Failed checksum! */
- icmp_statistics.IcmpInErrors++;
- printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
-
- /*
- * Parse the ICMP message
- */
-
- if (ip_chk_addr(daddr) != IS_MYADDR)
- {
- if (icmph->type != ICMP_ECHO)
- {
- icmp_statistics.IcmpInErrors++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
- daddr=dev->pa_addr;
- }
-
- switch(icmph->type)
- {
- case ICMP_TIME_EXCEEDED:
- icmp_statistics.IcmpInTimeExcds++;
- icmp_unreach(icmph, skb1);
- return 0;
- case ICMP_DEST_UNREACH:
- icmp_statistics.IcmpInDestUnreachs++;
- icmp_unreach(icmph, skb1);
- return 0;
- case ICMP_SOURCE_QUENCH:
- icmp_statistics.IcmpInSrcQuenchs++;
- icmp_unreach(icmph, skb1);
- return(0);
- case ICMP_REDIRECT:
- icmp_statistics.IcmpInRedirects++;
- icmp_redirect(icmph, skb1, dev, saddr);
- return(0);
- case ICMP_ECHO:
- icmp_statistics.IcmpInEchos++;
- icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ECHOREPLY:
- icmp_statistics.IcmpInEchoReps++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_TIMESTAMP:
- icmp_statistics.IcmpInTimestamps++;
- icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_TIMESTAMPREPLY:
- icmp_statistics.IcmpInTimestampReps++;
- kfree_skb(skb1,FREE_READ);
- return 0;
- /* INFO is obsolete and doesn't even feature in the SNMP stats */
- case ICMP_INFO_REQUEST:
- icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_INFO_REPLY:
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_ADDRESS:
- icmp_statistics.IcmpInAddrMasks++;
- icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ADDRESSREPLY:
- /*
- * We ought to set our netmask on receiving this, but
- * experience shows it's a waste of effort.
- */
- icmp_statistics.IcmpInAddrMaskReps++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- default:
- icmp_statistics.IcmpInErrors++;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
- /*NOTREACHED*/
- kfree_skb(skb1, FREE_READ);
- return(-1);
-}
-
-
-/*
- * Perform any ICMP-related I/O control requests.
- * [to vanish soon]
- */
-
-int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
-{
- switch(cmd)
- {
- default:
- return(-EINVAL);
- }
- return(0);
-}
diff --git a/pfinet/linux-inet/igmp.c b/pfinet/linux-inet/igmp.c
deleted file mode 100644
index 32e42213..00000000
--- a/pfinet/linux-inet/igmp.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Linux NET3: Internet Gateway Management Protocol [IGMP]
- *
- * Authors:
- * Alan Cox <Alan.Cox@linux.org>
- *
- * WARNING:
- * This is a 'preliminary' implementation... on your own head
- * be it.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "route.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include <linux/igmp.h>
-
-#ifdef CONFIG_IP_MULTICAST
-
-
-/*
- * Timer management
- */
-
-
-static void igmp_stop_timer(struct ip_mc_list *im)
-{
- del_timer(&im->timer);
- im->tm_running=0;
-}
-
-static int igmp_random(void)
-{
- static unsigned long seed=152L;
- seed=seed*69069L+1;
- return seed^jiffies;
-}
-
-
-static void igmp_start_timer(struct ip_mc_list *im)
-{
- int tv;
- if(im->tm_running)
- return;
- tv=igmp_random()%(10*HZ); /* Pick a number any number 8) */
- im->timer.expires=tv;
- im->tm_running=1;
- add_timer(&im->timer);
-}
-
-/*
- * Send an IGMP report.
- */
-
-#define MAX_IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+64)
-
-static void igmp_send_report(struct device *dev, unsigned long address, int type)
-{
- struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC);
- int tmp;
- struct igmphdr *igh;
-
- if(skb==NULL)
- return;
- tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL,
- skb->mem_len, 0, 1);
- if(tmp<0)
- {
- kfree_skb(skb, FREE_WRITE);
- return;
- }
- igh=(struct igmphdr *)(skb->data+tmp);
- skb->len=tmp+sizeof(*igh);
- igh->csum=0;
- igh->unused=0;
- igh->type=type;
- igh->group=address;
- igh->csum=ip_compute_csum((void *)igh,sizeof(*igh));
- ip_queue_xmit(NULL,dev,skb,1);
-}
-
-
-static void igmp_timer_expire(unsigned long data)
-{
- struct ip_mc_list *im=(struct ip_mc_list *)data;
- igmp_stop_timer(im);
- igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
-}
-
-static void igmp_init_timer(struct ip_mc_list *im)
-{
- im->tm_running=0;
- init_timer(&im->timer);
- im->timer.data=(unsigned long)im;
- im->timer.function=&igmp_timer_expire;
-}
-
-
-static void igmp_heard_report(struct device *dev, unsigned long address)
-{
- struct ip_mc_list *im;
- for(im=dev->ip_mc_list;im!=NULL;im=im->next)
- if(im->multiaddr==address)
- igmp_stop_timer(im);
-}
-
-static void igmp_heard_query(struct device *dev)
-{
- struct ip_mc_list *im;
- for(im=dev->ip_mc_list;im!=NULL;im=im->next)
- if(!im->tm_running && im->multiaddr!=IGMP_ALL_HOSTS)
- igmp_start_timer(im);
-}
-
-/*
- * Map a multicast IP onto multicast MAC for type ethernet.
- */
-
-static void ip_mc_map(unsigned long addr, char *buf)
-{
- addr=ntohl(addr);
- buf[0]=0x01;
- buf[1]=0x00;
- buf[2]=0x5e;
- buf[5]=addr&0xFF;
- addr>>=8;
- buf[4]=addr&0xFF;
- addr>>=8;
- buf[3]=addr&0x7F;
-}
-
-/*
- * Add a filter to a device
- */
-
-void ip_mc_filter_add(struct device *dev, unsigned long addr)
-{
- char buf[6];
- if(dev->type!=ARPHRD_ETHER)
- return; /* Only do ethernet now */
- ip_mc_map(addr,buf);
- dev_mc_add(dev,buf,ETH_ALEN,0);
-}
-
-/*
- * Remove a filter from a device
- */
-
-void ip_mc_filter_del(struct device *dev, unsigned long addr)
-{
- char buf[6];
- if(dev->type!=ARPHRD_ETHER)
- return; /* Only do ethernet now */
- ip_mc_map(addr,buf);
- dev_mc_delete(dev,buf,ETH_ALEN,0);
-}
-
-static void igmp_group_dropped(struct ip_mc_list *im)
-{
- del_timer(&im->timer);
- igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
- ip_mc_filter_del(im->interface, im->multiaddr);
-/* printk("Left group %lX\n",im->multiaddr);*/
-}
-
-static void igmp_group_added(struct ip_mc_list *im)
-{
- igmp_init_timer(im);
- igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
- ip_mc_filter_add(im->interface, im->multiaddr);
-/* printk("Joined group %lX\n",im->multiaddr);*/
-}
-
-int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
- unsigned long daddr, unsigned short len, unsigned long saddr, int redo,
- struct inet_protocol *protocol)
-{
- /* This basically follows the spec line by line -- see RFC1112 */
- struct igmphdr *igh=(struct igmphdr *)skb->h.raw;
-
- if(skb->ip_hdr->ttl!=1 || ip_compute_csum((void *)igh,sizeof(*igh)))
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- if(igh->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
- igmp_heard_query(dev);
- if(igh->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==igh->group)
- igmp_heard_report(dev,igh->group);
- kfree_skb(skb, FREE_READ);
- return 0;
-}
-
-/*
- * Multicast list managers
- */
-
-
-/*
- * A socket has joined a multicast group on device dev.
- */
-
-static void ip_mc_inc_group(struct device *dev, unsigned long addr)
-{
- struct ip_mc_list *i;
- for(i=dev->ip_mc_list;i!=NULL;i=i->next)
- {
- if(i->multiaddr==addr)
- {
- i->users++;
- return;
- }
- }
- i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
- if(!i)
- return;
- i->users=1;
- i->interface=dev;
- i->multiaddr=addr;
- i->next=dev->ip_mc_list;
- igmp_group_added(i);
- dev->ip_mc_list=i;
-}
-
-/*
- * A socket has left a multicast group on device dev
- */
-
-static void ip_mc_dec_group(struct device *dev, unsigned long addr)
-{
- struct ip_mc_list **i;
- for(i=&(dev->ip_mc_list);(*i)!=NULL;i=&(*i)->next)
- {
- if((*i)->multiaddr==addr)
- {
- if(--((*i)->users))
- return;
- else
- {
- struct ip_mc_list *tmp= *i;
- igmp_group_dropped(tmp);
- *i=(*i)->next;
- kfree_s(tmp,sizeof(*tmp));
- }
- }
- }
-}
-
-/*
- * Device going down: Clean up.
- */
-
-void ip_mc_drop_device(struct device *dev)
-{
- struct ip_mc_list *i;
- struct ip_mc_list *j;
- for(i=dev->ip_mc_list;i!=NULL;i=j)
- {
- j=i->next;
- kfree_s(i,sizeof(*i));
- }
- dev->ip_mc_list=NULL;
-}
-
-/*
- * Device going up. Make sure it is in all hosts
- */
-
-void ip_mc_allhost(struct device *dev)
-{
- struct ip_mc_list *i;
- for(i=dev->ip_mc_list;i!=NULL;i=i->next)
- if(i->multiaddr==IGMP_ALL_HOSTS)
- return;
- i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
- if(!i)
- return;
- i->users=1;
- i->interface=dev;
- i->multiaddr=IGMP_ALL_HOSTS;
- i->next=dev->ip_mc_list;
- dev->ip_mc_list=i;
- ip_mc_filter_add(i->interface, i->multiaddr);
-
-}
-
-/*
- * Join a socket to a group
- */
-
-int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr)
-{
- int unused= -1;
- int i;
- if(!MULTICAST(addr))
- return -EINVAL;
- if(!(dev->flags&IFF_MULTICAST))
- return -EADDRNOTAVAIL;
- if(sk->ip_mc_list==NULL)
- {
- if((sk->ip_mc_list=(struct ip_mc_socklist *)kmalloc(sizeof(*sk->ip_mc_list), GFP_KERNEL))==NULL)
- return -ENOMEM;
- memset(sk->ip_mc_list,'\0',sizeof(*sk->ip_mc_list));
- }
- for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
- {
- if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
- return -EADDRINUSE;
- if(sk->ip_mc_list->multidev[i]==NULL)
- unused=i;
- }
-
- if(unused==-1)
- return -ENOBUFS;
- sk->ip_mc_list->multiaddr[unused]=addr;
- sk->ip_mc_list->multidev[unused]=dev;
- ip_mc_inc_group(dev,addr);
- return 0;
-}
-
-/*
- * Ask a socket to leave a group.
- */
-
-int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr)
-{
- int i;
- if(!MULTICAST(addr))
- return -EINVAL;
- if(!(dev->flags&IFF_MULTICAST))
- return -EADDRNOTAVAIL;
- if(sk->ip_mc_list==NULL)
- return -EADDRNOTAVAIL;
-
- for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
- {
- if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
- {
- sk->ip_mc_list->multidev[i]=NULL;
- ip_mc_dec_group(dev,addr);
- return 0;
- }
- }
- return -EADDRNOTAVAIL;
-}
-
-/*
- * A socket is closing.
- */
-
-void ip_mc_drop_socket(struct sock *sk)
-{
- int i;
-
- if(sk->ip_mc_list==NULL)
- return;
-
- for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
- {
- if(sk->ip_mc_list->multidev[i])
- {
- ip_mc_dec_group(sk->ip_mc_list->multidev[i], sk->ip_mc_list->multiaddr[i]);
- sk->ip_mc_list->multidev[i]=NULL;
- }
- }
- kfree_s(sk->ip_mc_list,sizeof(*sk->ip_mc_list));
- sk->ip_mc_list=NULL;
-}
-
-#endif
diff --git a/pfinet/linux-inet/ip.c b/pfinet/linux-inet/ip.c
deleted file mode 100644
index dd188f54..00000000
--- a/pfinet/linux-inet/ip.c
+++ /dev/null
@@ -1,2427 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * The Internet Protocol (IP) module.
- *
- * Version: @(#)ip.c 1.0.16b 9/1/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Donald Becker, <becker@super.org>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Richard Underwood
- * Stefan Becker, <stefanb@yello.ping.de>
- *
- *
- * Fixes:
- * Alan Cox : Commented a couple of minor bits of surplus code
- * Alan Cox : Undefining IP_FORWARD doesn't include the code
- * (just stops a compiler warning).
- * Alan Cox : Frames with >=MAX_ROUTE record routes, strict routes or loose routes
- * are junked rather than corrupting things.
- * Alan Cox : Frames to bad broadcast subnets are dumped
- * We used to process them non broadcast and
- * boy could that cause havoc.
- * Alan Cox : ip_forward sets the free flag on the
- * new frame it queues. Still crap because
- * it copies the frame but at least it
- * doesn't eat memory too.
- * Alan Cox : Generic queue code and memory fixes.
- * Fred Van Kempen : IP fragment support (borrowed from NET2E)
- * Gerhard Koerting: Forward fragmented frames correctly.
- * Gerhard Koerting: Fixes to my fix of the above 8-).
- * Gerhard Koerting: IP interface addressing fix.
- * Linus Torvalds : More robustness checks
- * Alan Cox : Even more checks: Still not as robust as it ought to be
- * Alan Cox : Save IP header pointer for later
- * Alan Cox : ip option setting
- * Alan Cox : Use ip_tos/ip_ttl settings
- * Alan Cox : Fragmentation bogosity removed
- * (Thanks to Mark.Bush@prg.ox.ac.uk)
- * Dmitry Gorodchanin : Send of a raw packet crash fix.
- * Alan Cox : Silly ip bug when an overlength
- * fragment turns up. Now frees the
- * queue.
- * Linus Torvalds/ : Memory leakage on fragmentation
- * Alan Cox : handling.
- * Gerhard Koerting: Forwarding uses IP priority hints
- * Teemu Rantanen : Fragment problems.
- * Alan Cox : General cleanup, comments and reformat
- * Alan Cox : SNMP statistics
- * Alan Cox : BSD address rule semantics. Also see
- * UDP as there is a nasty checksum issue
- * if you do things the wrong way.
- * Alan Cox : Always defrag, moved IP_FORWARD to the config.in file
- * Alan Cox : IP options adjust sk->priority.
- * Pedro Roque : Fix mtu/length error in ip_forward.
- * Alan Cox : Avoid ip_chk_addr when possible.
- * Richard Underwood : IP multicasting.
- * Alan Cox : Cleaned up multicast handlers.
- * Alan Cox : RAW sockets demultiplex in the BSD style.
- * Gunther Mayer : Fix the SNMP reporting typo
- * Alan Cox : Always in group 224.0.0.1
- * Alan Cox : Multicast loopback error for 224.0.0.1
- * Alan Cox : IP_MULTICAST_LOOP option.
- * Alan Cox : Use notifiers.
- * Bjorn Ekwall : Removed ip_csum (from slhc.c too)
- * Bjorn Ekwall : Moved ip_fast_csum to ip.h (inline!)
- * Stefan Becker : Send out ICMP HOST REDIRECT
- * Alan Cox : Only send ICMP_REDIRECT if src/dest are the same net.
- *
- *
- * To Fix:
- * IP option processing is mostly not needed. ip_forward needs to know about routing rules
- * and time stamp but that's about all. Use the route mtu field here too
- * IP fragmentation wants rewriting cleanly. The RFC815 algorithm is much more efficient
- * and could be made very efficient with the addition of some virtual memory hacks to permit
- * the allocation of a buffer that can then be 'grown' by twiddling page tables.
- * Output fragmentation wants updating along with the buffer management to use a single
- * interleaved copy algorithm so that fragmenting has a one copy overhead. Actual packet
- * output should probably do its own fragmentation at the UDP/RAW layer. TCP shouldn't cause
- * fragmentation anyway.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/config.h>
-
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include "snmp.h"
-#include "ip.h"
-#include "protocol.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "arp.h"
-#include "icmp.h"
-#include "raw.h"
-#include <linux/igmp.h>
-#include <linux/ip_fw.h>
-
-#define CONFIG_IP_DEFRAG
-
-extern int last_retran;
-extern void sort_send(struct sock *sk);
-
-#define min(a,b) ((a)<(b)?(a):(b))
-#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000))
-
-/*
- * SNMP management statistics
- */
-
-#ifdef CONFIG_IP_FORWARD
-struct ip_mib ip_statistics={1,64,}; /* Forwarding=Yes, Default TTL=64 */
-#else
-struct ip_mib ip_statistics={0,64,}; /* Forwarding=No, Default TTL=64 */
-#endif
-
-/*
- * Handle the issuing of an ioctl() request
- * for the ip device. This is scheduled to
- * disappear
- */
-
-int ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
-{
- switch(cmd)
- {
- default:
- return(-EINVAL);
- }
-}
-
-
-/* these two routines will do routing. */
-
-static void
-strict_route(struct iphdr *iph, struct options *opt)
-{
-}
-
-
-static void
-loose_route(struct iphdr *iph, struct options *opt)
-{
-}
-
-
-
-
-/* This routine will check to see if we have lost a gateway. */
-void
-ip_route_check(unsigned long daddr)
-{
-}
-
-
-#if 0
-/* this routine puts the options at the end of an ip header. */
-static int
-build_options(struct iphdr *iph, struct options *opt)
-{
- unsigned char *ptr;
- /* currently we don't support any options. */
- ptr = (unsigned char *)(iph+1);
- *ptr = 0;
- return (4);
-}
-#endif
-
-
-/*
- * Take an skb, and fill in the MAC header.
- */
-
-static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr)
-{
- int mac = 0;
-
- skb->dev = dev;
- skb->arp = 1;
- if (dev->hard_header)
- {
- /*
- * Build a hardware header. Source address is our mac, destination unknown
- * (rebuild header will sort this out)
- */
- mac = dev->hard_header(skb->data, dev, ETH_P_IP, NULL, NULL, len, skb);
- if (mac < 0)
- {
- mac = -mac;
- skb->arp = 0;
- skb->raddr = daddr; /* next routing address */
- }
- }
- return mac;
-}
-
-int ip_id_count = 0;
-
-/*
- * This routine builds the appropriate hardware/IP headers for
- * the routine. It assumes that if *dev != NULL then the
- * protocol knows what it's doing, otherwise it uses the
- * routing/ARP tables to select a device struct.
- */
-int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
- struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
-{
- static struct options optmem;
- struct iphdr *iph;
- struct rtable *rt;
- unsigned char *buff;
- unsigned long raddr;
- int tmp;
- unsigned long src;
-
- buff = skb->data;
-
- /*
- * See if we need to look up the device.
- */
-
-#ifdef CONFIG_INET_MULTICAST
- if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name)
- *dev=dev_get(skb->sk->ip_mc_name);
-#endif
- if (*dev == NULL)
- {
- if(skb->localroute)
- rt = ip_rt_local(daddr, &optmem, &src);
- else
- rt = ip_rt_route(daddr, &optmem, &src);
- if (rt == NULL)
- {
- ip_statistics.IpOutNoRoutes++;
- return(-ENETUNREACH);
- }
-
- *dev = rt->rt_dev;
- /*
- * If the frame is from us and going off machine it MUST MUST MUST
- * have the output device ip address and never the loopback
- */
- if (LOOPBACK(saddr) && !LOOPBACK(daddr))
- saddr = src;/*rt->rt_dev->pa_addr;*/
- raddr = rt->rt_gateway;
-
- opt = &optmem;
- }
- else
- {
- /*
- * We still need the address of the first hop.
- */
- if(skb->localroute)
- rt = ip_rt_local(daddr, &optmem, &src);
- else
- rt = ip_rt_route(daddr, &optmem, &src);
- /*
- * If the frame is from us and going off machine it MUST MUST MUST
- * have the output device ip address and never the loopback
- */
- if (LOOPBACK(saddr) && !LOOPBACK(daddr))
- saddr = src;/*rt->rt_dev->pa_addr;*/
-
- raddr = (rt == NULL) ? 0 : rt->rt_gateway;
- }
-
- /*
- * No source addr so make it our addr
- */
- if (saddr == 0)
- saddr = src;
-
- /*
- * No gateway so aim at the real destination
- */
- if (raddr == 0)
- raddr = daddr;
-
- /*
- * Now build the MAC header.
- */
-
- tmp = ip_send(skb, raddr, len, *dev, saddr);
- buff += tmp;
- len -= tmp;
-
- /*
- * Book keeping
- */
-
- skb->dev = *dev;
- skb->saddr = saddr;
- if (skb->sk)
- skb->sk->saddr = saddr;
-
- /*
- * Now build the IP header.
- */
-
- /*
- * If we are using IPPROTO_RAW, then we don't need an IP header, since
- * one is being supplied to us by the user
- */
-
- if(type == IPPROTO_RAW)
- return (tmp);
-
- iph = (struct iphdr *)buff;
- iph->version = 4;
- iph->tos = tos;
- iph->frag_off = 0;
- iph->ttl = ttl;
- iph->daddr = daddr;
- iph->saddr = saddr;
- iph->protocol = type;
- iph->ihl = 5;
- skb->ip_hdr = iph;
-
- /* Setup the IP options. */
-#ifdef Not_Yet_Avail
- build_options(iph, opt);
-#endif
-
- return(20 + tmp); /* IP header plus MAC header size */
-}
-
-
-static int
-do_options(struct iphdr *iph, struct options *opt)
-{
- unsigned char *buff;
- int done = 0;
- int i, len = sizeof(struct iphdr);
-
- /* Zero out the options. */
- opt->record_route.route_size = 0;
- opt->loose_route.route_size = 0;
- opt->strict_route.route_size = 0;
- opt->tstamp.ptr = 0;
- opt->security = 0;
- opt->compartment = 0;
- opt->handling = 0;
- opt->stream = 0;
- opt->tcc = 0;
- return(0);
-
- /* Advance the pointer to start at the options. */
- buff = (unsigned char *)(iph + 1);
-
- /* Now start the processing. */
- while (!done && len < iph->ihl*4) switch(*buff) {
- case IPOPT_END:
- done = 1;
- break;
- case IPOPT_NOOP:
- buff++;
- len++;
- break;
- case IPOPT_SEC:
- buff++;
- if (*buff != 11) return(1);
- buff++;
- opt->security = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->compartment = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->handling = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1));
- buff += 3;
- len += 11;
- break;
- case IPOPT_LSRR:
- buff++;
- if ((*buff - 3)% 4 != 0) return(1);
- len += *buff;
- opt->loose_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0) return(1);
- opt->loose_route.pointer = *buff/4 - 1;
- buff++;
- buff++;
- for (i = 0; i < opt->loose_route.route_size; i++) {
- if(i>=MAX_ROUTE)
- return(1);
- opt->loose_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_SSRR:
- buff++;
- if ((*buff - 3)% 4 != 0) return(1);
- len += *buff;
- opt->strict_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0) return(1);
- opt->strict_route.pointer = *buff/4 - 1;
- buff++;
- buff++;
- for (i = 0; i < opt->strict_route.route_size; i++) {
- if(i>=MAX_ROUTE)
- return(1);
- opt->strict_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_RR:
- buff++;
- if ((*buff - 3)% 4 != 0) return(1);
- len += *buff;
- opt->record_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0) return(1);
- opt->record_route.pointer = *buff/4 - 1;
- buff++;
- buff++;
- for (i = 0; i < opt->record_route.route_size; i++) {
- if(i>=MAX_ROUTE)
- return 1;
- opt->record_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_SID:
- len += 4;
- buff +=2;
- opt->stream = *(unsigned short *)buff;
- buff += 2;
- break;
- case IPOPT_TIMESTAMP:
- buff++;
- len += *buff;
- if (*buff % 4 != 0) return(1);
- opt->tstamp.len = *buff / 4 - 1;
- buff++;
- if ((*buff - 1) % 4 != 0) return(1);
- opt->tstamp.ptr = (*buff-1)/4;
- buff++;
- opt->tstamp.x.full_char = *buff;
- buff++;
- for (i = 0; i < opt->tstamp.len; i++) {
- opt->tstamp.data[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- default:
- return(1);
- }
-
- if (opt->record_route.route_size == 0) {
- if (opt->strict_route.route_size != 0) {
- memcpy(&(opt->record_route), &(opt->strict_route),
- sizeof(opt->record_route));
- } else if (opt->loose_route.route_size != 0) {
- memcpy(&(opt->record_route), &(opt->loose_route),
- sizeof(opt->record_route));
- }
- }
-
- if (opt->strict_route.route_size != 0 &&
- opt->strict_route.route_size != opt->strict_route.pointer) {
- strict_route(iph, opt);
- return(0);
- }
-
- if (opt->loose_route.route_size != 0 &&
- opt->loose_route.route_size != opt->loose_route.pointer) {
- loose_route(iph, opt);
- return(0);
- }
-
- return(0);
-}
-
-/*
- * This routine does all the checksum computations that don't
- * require anything special (like copying or special headers).
- */
-
-unsigned short ip_compute_csum(unsigned char * buff, int len)
-{
- unsigned long sum = 0;
-
- /* Do the first multiple of 4 bytes and convert to 16 bits. */
- if (len > 3)
- {
- __asm__("clc\n"
- "1:\t"
- "lodsl\n\t"
- "adcl %%eax, %%ebx\n\t"
- "loop 1b\n\t"
- "adcl $0, %%ebx\n\t"
- "movl %%ebx, %%eax\n\t"
- "shrl $16, %%eax\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum) , "=S" (buff)
- : "0" (sum), "c" (len >> 2) ,"1" (buff)
- : "ax", "cx", "si", "bx" );
- }
- if (len & 2)
- {
- __asm__("lodsw\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum), "=S" (buff)
- : "0" (sum), "1" (buff)
- : "bx", "ax", "si");
- }
- if (len & 1)
- {
- __asm__("lodsb\n\t"
- "movb $0, %%ah\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum), "=S" (buff)
- : "0" (sum), "1" (buff)
- : "bx", "ax", "si");
- }
- sum =~sum;
- return(sum & 0xffff);
-}
-
-/*
- * Generate a checksum for an outgoing IP datagram.
- */
-
-void ip_send_check(struct iphdr *iph)
-{
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-}
-
-/************************ Fragment Handlers From NET2E **********************************/
-
-
-/*
- * This fragment handler is a bit of a heap. On the other hand it works quite
- * happily and handles things quite well.
- */
-
-static struct ipq *ipqueue = NULL; /* IP fragment queue */
-
-/*
- * Create a new fragment entry.
- */
-
-static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
-{
- struct ipfrag *fp;
-
- fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
- if (fp == NULL)
- {
- printk("IP: frag_create: no memory left !\n");
- return(NULL);
- }
- memset(fp, 0, sizeof(struct ipfrag));
-
- /* Fill in the structure. */
- fp->offset = offset;
- fp->end = end;
- fp->len = end - offset;
- fp->skb = skb;
- fp->ptr = ptr;
-
- return(fp);
-}
-
-
-/*
- * Find the correct entry in the "incomplete datagrams" queue for
- * this IP datagram, and return the queue entry address if found.
- */
-
-static struct ipq *ip_find(struct iphdr *iph)
-{
- struct ipq *qp;
- struct ipq *qplast;
-
- cli();
- qplast = NULL;
- for(qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next)
- {
- if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr &&
- iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol)
- {
- del_timer(&qp->timer); /* So it doesn't vanish on us. The timer will be reset anyway */
- sti();
- return(qp);
- }
- }
- sti();
- return(NULL);
-}
-
-
-/*
- * Remove an entry from the "incomplete datagrams" queue, either
- * because we completed, reassembled and processed it, or because
- * it timed out.
- */
-
-static void ip_free(struct ipq *qp)
-{
- struct ipfrag *fp;
- struct ipfrag *xp;
-
- /*
- * Stop the timer for this entry.
- */
-
- del_timer(&qp->timer);
-
- /* Remove this entry from the "incomplete datagrams" queue. */
- cli();
- if (qp->prev == NULL)
- {
- ipqueue = qp->next;
- if (ipqueue != NULL)
- ipqueue->prev = NULL;
- }
- else
- {
- qp->prev->next = qp->next;
- if (qp->next != NULL)
- qp->next->prev = qp->prev;
- }
-
- /* Release all fragment data. */
-
- fp = qp->fragments;
- while (fp != NULL)
- {
- xp = fp->next;
- IS_SKB(fp->skb);
- kfree_skb(fp->skb,FREE_READ);
- kfree_s(fp, sizeof(struct ipfrag));
- fp = xp;
- }
-
- /* Release the MAC header. */
- kfree_s(qp->mac, qp->maclen);
-
- /* Release the IP header. */
- kfree_s(qp->iph, qp->ihlen + 8);
-
- /* Finally, release the queue descriptor itself. */
- kfree_s(qp, sizeof(struct ipq));
- sti();
-}
-
-
-/*
- * Oops- a fragment queue timed out. Kill it and send an ICMP reply.
- */
-
-static void ip_expire(unsigned long arg)
-{
- struct ipq *qp;
-
- qp = (struct ipq *)arg;
-
- /*
- * Send an ICMP "Fragment Reassembly Timeout" message.
- */
-
- ip_statistics.IpReasmTimeout++;
- ip_statistics.IpReasmFails++;
- /* This if is always true... shrug */
- if(qp->fragments!=NULL)
- icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED,
- ICMP_EXC_FRAGTIME, 0, qp->dev);
-
- /*
- * Nuke the fragment queue.
- */
- ip_free(qp);
-}
-
-
-/*
- * Add an entry to the 'ipq' queue for a newly received IP datagram.
- * We will (hopefully :-) receive all other fragments of this datagram
- * in time, so we just create a queue for this datagram, in which we
- * will insert the received fragments at their respective positions.
- */
-
-static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev)
-{
- struct ipq *qp;
- int maclen;
- int ihlen;
-
- qp = (struct ipq *) kmalloc(sizeof(struct ipq), GFP_ATOMIC);
- if (qp == NULL)
- {
- printk("IP: create: no memory left !\n");
- return(NULL);
- skb->dev = qp->dev;
- }
- memset(qp, 0, sizeof(struct ipq));
-
- /*
- * Allocate memory for the MAC header.
- *
- * FIXME: We have a maximum MAC address size limit and define
- * elsewhere. We should use it here and avoid the 3 kmalloc() calls
- */
-
- maclen = ((unsigned long) iph) - ((unsigned long) skb->data);
- qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC);
- if (qp->mac == NULL)
- {
- printk("IP: create: no memory left !\n");
- kfree_s(qp, sizeof(struct ipq));
- return(NULL);
- }
-
- /*
- * Allocate memory for the IP header (plus 8 octets for ICMP).
- */
-
- ihlen = (iph->ihl * sizeof(unsigned long));
- qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC);
- if (qp->iph == NULL)
- {
- printk("IP: create: no memory left !\n");
- kfree_s(qp->mac, maclen);
- kfree_s(qp, sizeof(struct ipq));
- return(NULL);
- }
-
- /* Fill in the structure. */
- memcpy(qp->mac, skb->data, maclen);
- memcpy(qp->iph, iph, ihlen + 8);
- qp->len = 0;
- qp->ihlen = ihlen;
- qp->maclen = maclen;
- qp->fragments = NULL;
- qp->dev = dev;
-
- /* Start a timer for this entry. */
- qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- add_timer(&qp->timer);
-
- /* Add this entry to the queue. */
- qp->prev = NULL;
- cli();
- qp->next = ipqueue;
- if (qp->next != NULL)
- qp->next->prev = qp;
- ipqueue = qp;
- sti();
- return(qp);
-}
-
-
-/*
- * See if a fragment queue is complete.
- */
-
-static int ip_done(struct ipq *qp)
-{
- struct ipfrag *fp;
- int offset;
-
- /* Only possible if we received the final fragment. */
- if (qp->len == 0)
- return(0);
-
- /* Check all fragment offsets to see if they connect. */
- fp = qp->fragments;
- offset = 0;
- while (fp != NULL)
- {
- if (fp->offset > offset)
- return(0); /* fragment(s) missing */
- offset = fp->end;
- fp = fp->next;
- }
-
- /* All fragments are present. */
- return(1);
-}
-
-
-/*
- * Build a new IP datagram from all its fragments.
- *
- * FIXME: We copy here because we lack an effective way of handling lists
- * of bits on input. Until the new skb data handling is in I'm not going
- * to touch this with a bargepole. This also causes a 4Kish limit on
- * packet sizes.
- */
-
-static struct sk_buff *ip_glue(struct ipq *qp)
-{
- struct sk_buff *skb;
- struct iphdr *iph;
- struct ipfrag *fp;
- unsigned char *ptr;
- int count, len;
-
- /*
- * Allocate a new buffer for the datagram.
- */
-
- len = qp->maclen + qp->ihlen + qp->len;
-
- if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL)
- {
- ip_statistics.IpReasmFails++;
- printk("IP: queue_glue: no memory for gluing queue 0x%X\n", (int) qp);
- ip_free(qp);
- return(NULL);
- }
-
- /* Fill in the basic details. */
- skb->len = (len - qp->maclen);
- skb->h.raw = skb->data;
- skb->free = 1;
-
- /* Copy the original MAC and IP headers into the new buffer. */
- ptr = (unsigned char *) skb->h.raw;
- memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen);
- ptr += qp->maclen;
- memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen);
- ptr += qp->ihlen;
- skb->h.raw += qp->maclen;
-
- count = 0;
-
- /* Copy the data portions of all fragments into the new buffer. */
- fp = qp->fragments;
- while(fp != NULL)
- {
- if(count+fp->len > skb->len)
- {
- printk("Invalid fragment list: Fragment over size.\n");
- ip_free(qp);
- kfree_skb(skb,FREE_WRITE);
- ip_statistics.IpReasmFails++;
- return NULL;
- }
- memcpy((ptr + fp->offset), fp->ptr, fp->len);
- count += fp->len;
- fp = fp->next;
- }
-
- /* We glued together all fragments, so remove the queue entry. */
- ip_free(qp);
-
- /* Done with all fragments. Fixup the new IP header. */
- iph = skb->h.iph;
- iph->frag_off = 0;
- iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count);
- skb->ip_hdr = iph;
-
- ip_statistics.IpReasmOKs++;
- return(skb);
-}
-
-
-/*
- * Process an incoming IP datagram fragment.
- */
-
-static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev)
-{
- struct ipfrag *prev, *next;
- struct ipfrag *tfp;
- struct ipq *qp;
- struct sk_buff *skb2;
- unsigned char *ptr;
- int flags, offset;
- int i, ihl, end;
-
- ip_statistics.IpReasmReqds++;
-
- /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
- qp = ip_find(iph);
-
- /* Is this a non-fragmented datagram? */
- offset = ntohs(iph->frag_off);
- flags = offset & ~IP_OFFSET;
- offset &= IP_OFFSET;
- if (((flags & IP_MF) == 0) && (offset == 0))
- {
- if (qp != NULL)
- ip_free(qp); /* Huh? How could this exist?? */
- return(skb);
- }
-
- offset <<= 3; /* offset is in 8-byte chunks */
-
- /*
- * If the queue already existed, keep restarting its timer as long
- * as we still are receiving fragments. Otherwise, create a fresh
- * queue entry.
- */
-
- if (qp != NULL)
- {
- del_timer(&qp->timer);
- qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- add_timer(&qp->timer);
- }
- else
- {
- /*
- * If we failed to create it, then discard the frame
- */
- if ((qp = ip_create(skb, iph, dev)) == NULL)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- ip_statistics.IpReasmFails++;
- return NULL;
- }
- }
-
- /*
- * Determine the position of this fragment.
- */
-
- ihl = (iph->ihl * sizeof(unsigned long));
- end = offset + ntohs(iph->tot_len) - ihl;
-
- /*
- * Point into the IP datagram 'data' part.
- */
-
- ptr = skb->data + dev->hard_header_len + ihl;
-
- /*
- * Is this the final fragment?
- */
-
- if ((flags & IP_MF) == 0)
- qp->len = end;
-
- /*
- * Find out which fragments are in front and at the back of us
- * in the chain of fragments so far. We must know where to put
- * this fragment, right?
- */
-
- prev = NULL;
- for(next = qp->fragments; next != NULL; next = next->next)
- {
- if (next->offset > offset)
- break; /* bingo! */
- prev = next;
- }
-
- /*
- * We found where to put this one.
- * Check for overlap with preceding fragment, and, if needed,
- * align things so that any overlaps are eliminated.
- */
- if (prev != NULL && offset < prev->end)
- {
- i = prev->end - offset;
- offset += i; /* ptr into datagram */
- ptr += i; /* ptr into fragment data */
- }
-
- /*
- * Look for overlap with succeeding segments.
- * If we can merge fragments, do it.
- */
-
- for(; next != NULL; next = tfp)
- {
- tfp = next->next;
- if (next->offset >= end)
- break; /* no overlaps at all */
-
- i = end - next->offset; /* overlap is 'i' bytes */
- next->len -= i; /* so reduce size of */
- next->offset += i; /* next fragment */
- next->ptr += i;
-
- /*
- * If we get a frag size of <= 0, remove it and the packet
- * that it goes with.
- */
- if (next->len <= 0)
- {
- if (next->prev != NULL)
- next->prev->next = next->next;
- else
- qp->fragments = next->next;
-
- if (tfp->next != NULL)
- next->next->prev = next->prev;
-
- kfree_skb(next->skb,FREE_READ);
- kfree_s(next, sizeof(struct ipfrag));
- }
- }
-
- /*
- * Insert this fragment in the chain of fragments.
- */
-
- tfp = NULL;
- tfp = ip_frag_create(offset, end, skb, ptr);
-
- /*
- * No memory to save the fragment - so throw the lot
- */
-
- if (!tfp)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return NULL;
- }
- tfp->prev = prev;
- tfp->next = next;
- if (prev != NULL)
- prev->next = tfp;
- else
- qp->fragments = tfp;
-
- if (next != NULL)
- next->prev = tfp;
-
- /*
- * OK, so we inserted this new fragment into the chain.
- * Check if we now have a full IP datagram which we can
- * bump up to the IP layer...
- */
-
- if (ip_done(qp))
- {
- skb2 = ip_glue(qp); /* glue together the fragments */
- return(skb2);
- }
- return(NULL);
-}
-
-
-/*
- * This IP datagram is too large to be sent in one piece. Break it up into
- * smaller pieces (each of size equal to the MAC header plus IP header plus
- * a block of the data of the original IP data part) that will yet fit in a
- * single device frame, and queue such a frame for sending by calling the
- * ip_queue_xmit(). Note that this is recursion, and bad things will happen
- * if this function causes a loop...
- *
- * Yes this is inefficient, feel free to submit a quicker one.
- *
- * **Protocol Violation**
- * We copy all the options to each fragment. !FIXME!
- */
-void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag)
-{
- struct iphdr *iph;
- unsigned char *raw;
- unsigned char *ptr;
- struct sk_buff *skb2;
- int left, mtu, hlen, len;
- int offset;
- unsigned long flags;
-
- /*
- * Point into the IP datagram header.
- */
-
- raw = skb->data;
- iph = (struct iphdr *) (raw + dev->hard_header_len);
-
- skb->ip_hdr = iph;
-
- /*
- * Setup starting values.
- */
-
- hlen = (iph->ihl * sizeof(unsigned long));
- left = ntohs(iph->tot_len) - hlen; /* Space per frame */
- hlen += dev->hard_header_len; /* Total header size */
- mtu = (dev->mtu - hlen); /* Size of data space */
- ptr = (raw + hlen); /* Where to start from */
-
- /*
- * Check for any "DF" flag. [DF means do not fragment]
- */
-
- if (ntohs(iph->frag_off) & IP_DF)
- {
- /*
- * Reply giving the MTU of the failed hop.
- */
- ip_statistics.IpFragFails++;
- icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev->mtu, dev);
- return;
- }
-
- /*
- * The protocol doesn't seem to say what to do in the case that the
- * frame + options doesn't fit the mtu. As it used to fall down dead
- * in this case we were fortunate it didn't happen
- */
-
- if(mtu<8)
- {
- /* It's wrong but it's better than nothing */
- icmp_send(skb,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,dev->mtu, dev);
- ip_statistics.IpFragFails++;
- return;
- }
-
- /*
- * Fragment the datagram.
- */
-
- /*
- * The initial offset is 0 for a complete frame. When
- * fragmenting fragments it's wherever this one starts.
- */
-
- if (is_frag & 2)
- offset = (ntohs(iph->frag_off) & 0x1fff) << 3;
- else
- offset = 0;
-
-
- /*
- * Keep copying data until we run out.
- */
-
- while(left > 0)
- {
- len = left;
- /* IF: it doesn't fit, use 'mtu' - the data space left */
- if (len > mtu)
- len = mtu;
- /* IF: we are not sending upto and including the packet end
- then align the next start on an eight byte boundary */
- if (len < left)
- {
- len/=8;
- len*=8;
- }
- /*
- * Allocate buffer.
- */
-
- if ((skb2 = alloc_skb(len + hlen,GFP_ATOMIC)) == NULL)
- {
- printk("IP: frag: no memory for new fragment!\n");
- ip_statistics.IpFragFails++;
- return;
- }
-
- /*
- * Set up data on packet
- */
-
- skb2->arp = skb->arp;
- if(skb->free==0)
- printk("IP fragmenter: BUG free!=1 in fragmenter\n");
- skb2->free = 1;
- skb2->len = len + hlen;
- skb2->h.raw=(char *) skb2->data;
- /*
- * Charge the memory for the fragment to any owner
- * it might possess
- */
-
- save_flags(flags);
- if (sk)
- {
- cli();
- sk->wmem_alloc += skb2->mem_len;
- skb2->sk=sk;
- }
- restore_flags(flags);
- skb2->raddr = skb->raddr; /* For rebuild_header - must be here */
-
- /*
- * Copy the packet header into the new buffer.
- */
-
- memcpy(skb2->h.raw, raw, hlen);
-
- /*
- * Copy a block of the IP datagram.
- */
- memcpy(skb2->h.raw + hlen, ptr, len);
- left -= len;
-
- skb2->h.raw+=dev->hard_header_len;
-
- /*
- * Fill in the new header fields.
- */
- iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/);
- iph->frag_off = htons((offset >> 3));
- /*
- * Added AC : If we are fragmenting a fragment thats not the
- * last fragment then keep MF on each bit
- */
- if (left > 0 || (is_frag & 1))
- iph->frag_off |= htons(IP_MF);
- ptr += len;
- offset += len;
-
- /*
- * Put this fragment into the sending queue.
- */
-
- ip_statistics.IpFragCreates++;
-
- ip_queue_xmit(sk, dev, skb2, 2);
- }
- ip_statistics.IpFragOKs++;
-}
-
-
-
-#ifdef CONFIG_IP_FORWARD
-
-/*
- * Forward an IP datagram to its next destination.
- */
-
-static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
-{
- struct device *dev2; /* Output device */
- struct iphdr *iph; /* Our header */
- struct sk_buff *skb2; /* Output packet */
- struct rtable *rt; /* Route we use */
- unsigned char *ptr; /* Data pointer */
- unsigned long raddr; /* Router IP address */
-
- /*
- * See if we are allowed to forward this.
- */
-
-#ifdef CONFIG_IP_FIREWALL
- int err;
-
- if((err=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0))!=1)
- {
- if(err==-1)
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
- return;
- }
-#endif
- /*
- * According to the RFC, we must first decrease the TTL field. If
- * that reaches zero, we must reply an ICMP control message telling
- * that the packet's lifetime expired.
- *
- * Exception:
- * We may not generate an ICMP for an ICMP. icmp_send does the
- * enforcement of this so we can forget it here. It is however
- * sometimes VERY important.
- */
-
- iph = skb->h.iph;
- iph->ttl--;
- if (iph->ttl <= 0)
- {
- /* Tell the sender its packet died... */
- icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev);
- return;
- }
-
- /*
- * Re-compute the IP header checksum.
- * This is inefficient. We know what has happened to the header
- * and could thus adjust the checksum as Phil Karn does in KA9Q
- */
-
- ip_send_check(iph);
-
- /*
- * OK, the packet is still valid. Fetch its destination address,
- * and give it to the IP sender for further processing.
- */
-
- rt = ip_rt_route(iph->daddr, NULL, NULL);
- if (rt == NULL)
- {
- /*
- * Tell the sender its packet cannot be delivered. Again
- * ICMP is screened later.
- */
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev);
- return;
- }
-
-
- /*
- * Gosh. Not only is the packet valid; we even know how to
- * forward it onto its final destination. Can we say this
- * is being plain lucky?
- * If the router told us that there is no GW, use the dest.
- * IP address itself- we seem to be connected directly...
- */
-
- raddr = rt->rt_gateway;
-
- if (raddr != 0)
- {
- /*
- * There is a gateway so find the correct route for it.
- * Gateways cannot in turn be gatewayed.
- */
- rt = ip_rt_route(raddr, NULL, NULL);
- if (rt == NULL)
- {
- /*
- * Tell the sender its packet cannot be delivered...
- */
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
- return;
- }
- if (rt->rt_gateway != 0)
- raddr = rt->rt_gateway;
- }
- else
- raddr = iph->daddr;
-
- /*
- * Having picked a route we can now send the frame out.
- */
-
- dev2 = rt->rt_dev;
-
- /*
- * In IP you never have to forward a frame on the interface that it
- * arrived upon. We now generate an ICMP HOST REDIRECT giving the route
- * we calculated.
- */
-#ifdef CONFIG_IP_NO_ICMP_REDIRECT
- if (dev == dev2)
- return;
-#else
- if (dev == dev2 && (iph->saddr&dev->pa_mask) == (iph->daddr & dev->pa_mask))
- icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev);
-#endif
-
- /*
- * We now allocate a new buffer, and copy the datagram into it.
- * If the indicated interface is up and running, kick it.
- */
-
- if (dev2->flags & IFF_UP)
- {
-
- /*
- * Current design decrees we copy the packet. For identical header
- * lengths we could avoid it. The new skb code will let us push
- * data so the problem goes away then.
- */
-
- skb2 = alloc_skb(dev2->hard_header_len + skb->len, GFP_ATOMIC);
- /*
- * This is rare and since IP is tolerant of network failures
- * quite harmless.
- */
- if (skb2 == NULL)
- {
- printk("\nIP: No memory available for IP forward\n");
- return;
- }
- ptr = skb2->data;
- skb2->free = 1;
- skb2->len = skb->len + dev2->hard_header_len;
- skb2->h.raw = ptr;
-
- /*
- * Copy the packet data into the new buffer.
- */
- memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len);
-
- /* Now build the MAC header. */
- (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr);
-
- ip_statistics.IpForwDatagrams++;
-
- /*
- * See if it needs fragmenting. Note in ip_rcv we tagged
- * the fragment type. This must be right so that
- * the fragmenter does the right thing.
- */
-
- if(skb2->len > dev2->mtu + dev2->hard_header_len)
- {
- ip_fragment(NULL,skb2,dev2, is_frag);
- kfree_skb(skb2,FREE_WRITE);
- }
- else
- {
-#ifdef CONFIG_IP_ACCT
- /*
- * Count mapping we shortcut
- */
-
- ip_acct_cnt(iph,dev,ip_acct_chain);
-#endif
-
- /*
- * Map service types to priority. We lie about
- * throughput being low priority, but it's a good
- * choice to help improve general usage.
- */
- if(iph->tos & IPTOS_LOWDELAY)
- dev_queue_xmit(skb2, dev2, SOPRI_INTERACTIVE);
- else if(iph->tos & IPTOS_THROUGHPUT)
- dev_queue_xmit(skb2, dev2, SOPRI_BACKGROUND);
- else
- dev_queue_xmit(skb2, dev2, SOPRI_NORMAL);
- }
- }
-}
-
-
-#endif
-
-/*
- * This function receives all incoming IP datagrams.
- */
-
-int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
- struct iphdr *iph = skb->h.iph;
- struct sock *raw_sk=NULL;
- unsigned char hash;
- unsigned char flag = 0;
- unsigned char opts_p = 0; /* Set iff the packet has options. */
- struct inet_protocol *ipprot;
- static struct options opt; /* since we don't use these yet, and they
- take up stack space. */
- int brd=IS_MYADDR;
- int is_frag=0;
-#ifdef CONFIG_IP_FIREWALL
- int err;
-#endif
-
- ip_statistics.IpInReceives++;
-
- /*
- * Tag the ip header of this packet so we can find it
- */
-
- skb->ip_hdr = iph;
-
- /*
- * Is the datagram acceptable?
- *
- * 1. Length at least the size of an ip header
- * 2. Version of 4
- * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
- * (4. We ought to check for IP multicast addresses and undefined types.. does this matter ?)
- */
-
- if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0)
- {
- ip_statistics.IpInHdrErrors++;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- /*
- * See if the firewall wants to dispose of the packet.
- */
-
-#ifdef CONFIG_IP_FIREWALL
-
- if ((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy, 0))!=1)
- {
- if(err==-1)
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev);
- kfree_skb(skb, FREE_WRITE);
- return 0;
- }
-
-#endif
-
- /*
- * Our transport medium may have padded the buffer out. Now we know it
- * is IP we can trim to the true length of the frame.
- */
-
- skb->len=ntohs(iph->tot_len);
-
- /*
- * Next analyse the packet for options. Studies show under one packet in
- * a thousand have options....
- */
-
- if (iph->ihl != 5)
- { /* Fast path for the typical optionless IP packet. */
- memset((char *) &opt, 0, sizeof(opt));
- if (do_options(iph, &opt) != 0)
- return 0;
- opts_p = 1;
- }
-
- /*
- * Remember if the frame is fragmented.
- */
-
- if(iph->frag_off)
- {
- if (iph->frag_off & 0x0020)
- is_frag|=1;
- /*
- * Last fragment ?
- */
-
- if (ntohs(iph->frag_off) & 0x1fff)
- is_frag|=2;
- }
-
- /*
- * Do any IP forwarding required. chk_addr() is expensive -- avoid it someday.
- *
- * This is inefficient. While finding out if it is for us we could also compute
- * the routing table entry. This is where the great unified cache theory comes
- * in as and when someone implements it
- *
- * For most hosts over 99% of packets match the first conditional
- * and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at
- * function entry.
- */
-
- if ( iph->daddr != skb->dev->pa_addr && (brd = ip_chk_addr(iph->daddr)) == 0)
- {
- /*
- * Don't forward multicast or broadcast frames.
- */
-
- if(skb->pkt_type!=PACKET_HOST || brd==IS_BROADCAST)
- {
- kfree_skb(skb,FREE_WRITE);
- return 0;
- }
-
- /*
- * The packet is for another target. Forward the frame
- */
-
-#ifdef CONFIG_IP_FORWARD
- ip_forward(skb, dev, is_frag);
-#else
-/* printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n",
- iph->saddr,iph->daddr);*/
- ip_statistics.IpInAddrErrors++;
-#endif
- /*
- * The forwarder is inefficient and copies the packet. We
- * free the original now.
- */
-
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
-#ifdef CONFIG_IP_MULTICAST
-
- if(brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK))
- {
- /*
- * Check it is for one of our groups
- */
- struct ip_mc_list *ip_mc=dev->ip_mc_list;
- do
- {
- if(ip_mc==NULL)
- {
- kfree_skb(skb, FREE_WRITE);
- return 0;
- }
- if(ip_mc->multiaddr==iph->daddr)
- break;
- ip_mc=ip_mc->next;
- }
- while(1);
- }
-#endif
- /*
- * Account for the packet
- */
-
-#ifdef CONFIG_IP_ACCT
- ip_acct_cnt(iph,dev, ip_acct_chain);
-#endif
-
- /*
- * Reassemble IP fragments.
- */
-
- if(is_frag)
- {
- /* Defragment. Obtain the complete packet if there is one */
- skb=ip_defrag(iph,skb,dev);
- if(skb==NULL)
- return 0;
- skb->dev = dev;
- iph=skb->h.iph;
- }
-
-
-
- /*
- * Point into the IP datagram, just past the header.
- */
-
- skb->ip_hdr = iph;
- skb->h.raw += iph->ihl*4;
-
- /*
- * Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies.
- */
-
- hash = iph->protocol & (SOCK_ARRAY_SIZE-1);
-
- /* If there maybe a raw socket we must check - if not we don't care less */
- if((raw_sk=raw_prot.sock_array[hash])!=NULL)
- {
- struct sock *sknext=NULL;
- struct sk_buff *skb1;
- raw_sk=get_sock_raw(raw_sk, hash, iph->saddr, iph->daddr);
- if(raw_sk) /* Any raw sockets */
- {
- do
- {
- /* Find the next */
- sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr);
- if(sknext)
- skb1=skb_clone(skb, GFP_ATOMIC);
- else
- break; /* One pending raw socket left */
- if(skb1)
- raw_rcv(raw_sk, skb1, dev, iph->saddr,iph->daddr);
- raw_sk=sknext;
- }
- while(raw_sk!=NULL);
- /* Here either raw_sk is the last raw socket, or NULL if none */
- /* We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy */
- }
- }
-
- /*
- * skb->h.raw now points at the protocol beyond the IP header.
- */
-
- hash = iph->protocol & (MAX_INET_PROTOS -1);
- for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next)
- {
- struct sk_buff *skb2;
-
- if (ipprot->protocol != iph->protocol)
- continue;
- /*
- * See if we need to make a copy of it. This will
- * only be set if more than one protocol wants it.
- * and then not for the last one. If there is a pending
- * raw delivery wait for that
- */
- if (ipprot->copy || raw_sk)
- {
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if(skb2==NULL)
- continue;
- }
- else
- {
- skb2 = skb;
- }
- flag = 1;
-
- /*
- * Pass on the datagram to each protocol that wants it,
- * based on the datagram protocol. We should really
- * check the protocol handler's return values here...
- */
- ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr,
- (ntohs(iph->tot_len) - (iph->ihl * 4)),
- iph->saddr, 0, ipprot);
-
- }
-
- /*
- * All protocols checked.
- * If this packet was a broadcast, we may *not* reply to it, since that
- * causes (proven, grin) ARP storms and a leakage of memory (i.e. all
- * ICMP reply messages get queued up for transmission...)
- */
-
- if(raw_sk!=NULL) /* Shift to last raw user */
- raw_rcv(raw_sk, skb, dev, iph->saddr, iph->daddr);
- else if (!flag) /* Free and report errors */
- {
- if (brd != IS_BROADCAST && brd!=IS_MULTICAST)
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0, dev);
- kfree_skb(skb, FREE_WRITE);
- }
-
- return(0);
-}
-
-/*
- * Loop a packet back to the sender.
- */
-
-static void ip_loopback(struct device *old_dev, struct sk_buff *skb)
-{
- extern struct device loopback_dev;
- struct device *dev=&loopback_dev;
- int len=skb->len-old_dev->hard_header_len;
- struct sk_buff *newskb=alloc_skb(len+dev->hard_header_len, GFP_ATOMIC);
-
- if(newskb==NULL)
- return;
-
- newskb->link3=NULL;
- newskb->sk=NULL;
- newskb->dev=dev;
- newskb->saddr=skb->saddr;
- newskb->daddr=skb->daddr;
- newskb->raddr=skb->raddr;
- newskb->free=1;
- newskb->lock=0;
- newskb->users=0;
- newskb->pkt_type=skb->pkt_type;
- newskb->len=len+dev->hard_header_len;
-
-
- newskb->ip_hdr=(struct iphdr *)(newskb->data+ip_send(newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr));
- memcpy(newskb->ip_hdr,skb->ip_hdr,len);
-
- /* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */
-
- /*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/
- ip_queue_xmit(NULL, dev, newskb, 1);
-}
-
-
-/*
- * Queues a packet to be sent, and starts the transmitter
- * if necessary. if free = 1 then we free the block after
- * transmit, otherwise we don't. If free==2 we not only
- * free the block but also don't assign a new ip seq number.
- * This routine also needs to put in the total length,
- * and compute the checksum
- */
-
-void ip_queue_xmit(struct sock *sk, struct device *dev,
- struct sk_buff *skb, int free)
-{
- struct iphdr *iph;
- unsigned char *ptr;
-
- /* Sanity check */
- if (dev == NULL)
- {
- printk("IP: ip_queue_xmit dev = NULL\n");
- return;
- }
-
- IS_SKB(skb);
-
- /*
- * Do some book-keeping in the packet for later
- */
-
-
- skb->dev = dev;
- skb->when = jiffies;
-
- /*
- * Find the IP header and set the length. This is bad
- * but once we get the skb data handling code in the
- * hardware will push its header sensibly and we will
- * set skb->ip_hdr to avoid this mess and the fixed
- * header length problem
- */
-
- ptr = skb->data;
- ptr += dev->hard_header_len;
- iph = (struct iphdr *)ptr;
- skb->ip_hdr = iph;
- iph->tot_len = ntohs(skb->len-dev->hard_header_len);
-
-#ifdef CONFIG_IP_FIREWALL
- if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) != 1)
- /* just don't send this packet */
- return;
-#endif
-
- /*
- * No reassigning numbers to fragments...
- */
-
- if(free!=2)
- iph->id = htons(ip_id_count++);
- else
- free=1;
-
- /* All buffers without an owner socket get freed */
- if (sk == NULL)
- free = 1;
-
- skb->free = free;
-
- /*
- * Do we need to fragment. Again this is inefficient.
- * We need to somehow lock the original buffer and use
- * bits of it.
- */
-
- if(skb->len > dev->mtu + dev->hard_header_len)
- {
- ip_fragment(sk,skb,dev,0);
- IS_SKB(skb);
- kfree_skb(skb,FREE_WRITE);
- return;
- }
-
- /*
- * Add an IP checksum
- */
-
- ip_send_check(iph);
-
- /*
- * Print the frame when debugging
- */
-
- /*
- * More debugging. You cannot queue a packet already on a list
- * Spot this and moan loudly.
- */
- if (skb->next != NULL)
- {
- printk("ip_queue_xmit: next != NULL\n");
- skb_unlink(skb);
- }
-
- /*
- * If a sender wishes the packet to remain unfreed
- * we add it to his send queue. This arguably belongs
- * in the TCP level since nobody else uses it. BUT
- * remember IPng might change all the rules.
- */
-
- if (!free)
- {
- unsigned long flags;
- /* The socket now has more outstanding blocks */
-
- sk->packets_out++;
-
- /* Protect the list for a moment */
- save_flags(flags);
- cli();
-
- if (skb->link3 != NULL)
- {
- printk("ip.c: link3 != NULL\n");
- skb->link3 = NULL;
- }
- if (sk->send_head == NULL)
- {
- sk->send_tail = skb;
- sk->send_head = skb;
- }
- else
- {
- sk->send_tail->link3 = skb;
- sk->send_tail = skb;
- }
- /* skb->link3 is NULL */
-
- /* Interrupt restore */
- restore_flags(flags);
- }
- else
- /* Remember who owns the buffer */
- skb->sk = sk;
-
- /*
- * If the indicated interface is up and running, send the packet.
- */
-
- ip_statistics.IpOutRequests++;
-#ifdef CONFIG_IP_ACCT
- ip_acct_cnt(iph,dev, ip_acct_chain);
-#endif
-
-#ifdef CONFIG_IP_MULTICAST
-
- /*
- * Multicasts are looped back for other local users
- */
-
- if (MULTICAST(iph->daddr) && !(dev->flags&IFF_LOOPBACK))
- {
- if(sk==NULL || sk->ip_mc_loop)
- {
- if(iph->daddr==IGMP_ALL_HOSTS)
- ip_loopback(dev,skb);
- else
- {
- struct ip_mc_list *imc=dev->ip_mc_list;
- while(imc!=NULL)
- {
- if(imc->multiaddr==iph->daddr)
- {
- ip_loopback(dev,skb);
- break;
- }
- imc=imc->next;
- }
- }
- }
- /* Multicasts with ttl 0 must not go beyond the host */
-
- if(skb->ip_hdr->ttl==0)
- {
- kfree_skb(skb, FREE_READ);
- return;
- }
- }
-#endif
- if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK))
- ip_loopback(dev,skb);
-
- if (dev->flags & IFF_UP)
- {
- /*
- * If we have an owner use its priority setting,
- * otherwise use NORMAL
- */
-
- if (sk != NULL)
- {
- dev_queue_xmit(skb, dev, sk->priority);
- }
- else
- {
- dev_queue_xmit(skb, dev, SOPRI_NORMAL);
- }
- }
- else
- {
- ip_statistics.IpOutDiscards++;
- if (free)
- kfree_skb(skb, FREE_WRITE);
- }
-}
-
-
-
-#ifdef CONFIG_IP_MULTICAST
-
-/*
- * Write an multicast group list table for the IGMP daemon to
- * read.
- */
-
-int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
-{
- off_t pos=0, begin=0;
- struct ip_mc_list *im;
- unsigned long flags;
- int len=0;
- struct device *dev;
-
- len=sprintf(buffer,"Device : Count\tGroup Users Timer\n");
- save_flags(flags);
- cli();
-
- for(dev = dev_base; dev; dev = dev->next)
- {
- if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST))
- {
- len+=sprintf(buffer+len,"%-10s: %5d\n",
- dev->name, dev->mc_count);
- for(im = dev->ip_mc_list; im; im = im->next)
- {
- len+=sprintf(buffer+len,
- "\t\t\t%08lX %5d %d:%08lX\n",
- im->multiaddr, im->users,
- im->tm_running, im->timer.expires);
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
- }
- }
- }
- restore_flags(flags);
- *start=buffer+(offset-begin);
- len-=(offset-begin);
- if(len>length)
- len=length;
- return len;
-}
-
-
-#endif
-/*
- * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
- * an IP socket.
- *
- * We implement IP_TOS (type of service), IP_TTL (time to live).
- *
- * Next release we will sort out IP_OPTIONS since for some people are kind of important.
- */
-
-int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
-{
- int val,err;
-#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
- struct ip_fw tmp_fw;
-#endif
- if (optval == NULL)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ, optval, sizeof(int));
- if(err)
- return err;
-
- val = get_fs_long((unsigned long *)optval);
-
- if(level!=SOL_IP)
- return -EOPNOTSUPP;
-
- switch(optname)
- {
- case IP_TOS:
- if(val<0||val>255)
- return -EINVAL;
- sk->ip_tos=val;
- if(val==IPTOS_LOWDELAY)
- sk->priority=SOPRI_INTERACTIVE;
- if(val==IPTOS_THROUGHPUT)
- sk->priority=SOPRI_BACKGROUND;
- return 0;
- case IP_TTL:
- if(val<1||val>255)
- return -EINVAL;
- sk->ip_ttl=val;
- return 0;
-#ifdef CONFIG_IP_MULTICAST
- case IP_MULTICAST_TTL:
- {
- unsigned char ucval;
-
- ucval=get_fs_byte((unsigned char *)optval);
- if(ucval<1||ucval>255)
- return -EINVAL;
- sk->ip_mc_ttl=(int)ucval;
- return 0;
- }
- case IP_MULTICAST_LOOP:
- {
- unsigned char ucval;
-
- ucval=get_fs_byte((unsigned char *)optval);
- if(ucval!=0 && ucval!=1)
- return -EINVAL;
- sk->ip_mc_loop=(int)ucval;
- return 0;
- }
- case IP_MULTICAST_IF:
- {
- /* Not fully tested */
- struct in_addr addr;
- struct device *dev=NULL;
-
- /*
- * Check the arguments are allowable
- */
-
- err=verify_area(VERIFY_READ, optval, sizeof(addr));
- if(err)
- return err;
-
- memcpy_fromfs(&addr,optval,sizeof(addr));
-
- printk("MC bind %s\n", in_ntoa(addr.s_addr));
-
- /*
- * What address has been requested
- */
-
- if(addr.s_addr==INADDR_ANY) /* Default */
- {
- sk->ip_mc_name[0]=0;
- return 0;
- }
-
- /*
- * Find the device
- */
-
- for(dev = dev_base; dev; dev = dev->next)
- {
- if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&&
- (dev->pa_addr==addr.s_addr))
- break;
- }
-
- /*
- * Did we find one
- */
-
- if(dev)
- {
- strcpy(sk->ip_mc_name,dev->name);
- return 0;
- }
- return -EADDRNOTAVAIL;
- }
-
- case IP_ADD_MEMBERSHIP:
- {
-
-/*
- * FIXME: Add/Del membership should have a semaphore protecting them from re-entry
- */
- struct ip_mreq mreq;
- static struct options optmem;
- unsigned long route_src;
- struct rtable *rt;
- struct device *dev=NULL;
-
- /*
- * Check the arguments.
- */
-
- err=verify_area(VERIFY_READ, optval, sizeof(mreq));
- if(err)
- return err;
-
- memcpy_fromfs(&mreq,optval,sizeof(mreq));
-
- /*
- * Get device for use later
- */
-
- if(mreq.imr_interface.s_addr==INADDR_ANY)
- {
- /*
- * Not set so scan.
- */
- if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL)
- {
- dev=rt->rt_dev;
- rt->rt_use--;
- }
- }
- else
- {
- /*
- * Find a suitable device.
- */
- for(dev = dev_base; dev; dev = dev->next)
- {
- if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&&
- (dev->pa_addr==mreq.imr_interface.s_addr))
- break;
- }
- }
-
- /*
- * No device, no cookies.
- */
-
- if(!dev)
- return -ENODEV;
-
- /*
- * Join group.
- */
-
- return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr);
- }
-
- case IP_DROP_MEMBERSHIP:
- {
- struct ip_mreq mreq;
- struct rtable *rt;
- static struct options optmem;
- unsigned long route_src;
- struct device *dev=NULL;
-
- /*
- * Check the arguments
- */
-
- err=verify_area(VERIFY_READ, optval, sizeof(mreq));
- if(err)
- return err;
-
- memcpy_fromfs(&mreq,optval,sizeof(mreq));
-
- /*
- * Get device for use later
- */
-
- if(mreq.imr_interface.s_addr==INADDR_ANY)
- {
- if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL)
- {
- dev=rt->rt_dev;
- rt->rt_use--;
- }
- }
- else
- {
- for(dev = dev_base; dev; dev = dev->next)
- {
- if((dev->flags&IFF_UP)&& (dev->flags&IFF_MULTICAST)&&
- (dev->pa_addr==mreq.imr_interface.s_addr))
- break;
- }
- }
-
- /*
- * Did we find a suitable device.
- */
-
- if(!dev)
- return -ENODEV;
-
- /*
- * Leave group
- */
-
- return ip_mc_leave_group(sk,dev,mreq.imr_multiaddr.s_addr);
- }
-#endif
-#ifdef CONFIG_IP_FIREWALL
- case IP_FW_ADD_BLK:
- case IP_FW_DEL_BLK:
- case IP_FW_ADD_FWD:
- case IP_FW_DEL_FWD:
- case IP_FW_CHK_BLK:
- case IP_FW_CHK_FWD:
- case IP_FW_FLUSH_BLK:
- case IP_FW_FLUSH_FWD:
- case IP_FW_ZERO_BLK:
- case IP_FW_ZERO_FWD:
- case IP_FW_POLICY_BLK:
- case IP_FW_POLICY_FWD:
- if(!suser())
- return -EPERM;
- if(optlen>sizeof(tmp_fw) || optlen<1)
- return -EINVAL;
- err=verify_area(VERIFY_READ,optval,optlen);
- if(err)
- return err;
- memcpy_fromfs(&tmp_fw,optval,optlen);
- err=ip_fw_ctl(optname, &tmp_fw,optlen);
- return -err; /* -0 is 0 after all */
-
-#endif
-#ifdef CONFIG_IP_ACCT
- case IP_ACCT_DEL:
- case IP_ACCT_ADD:
- case IP_ACCT_FLUSH:
- case IP_ACCT_ZERO:
- if(!suser())
- return -EPERM;
- if(optlen>sizeof(tmp_fw) || optlen<1)
- return -EINVAL;
- err=verify_area(VERIFY_READ,optval,optlen);
- if(err)
- return err;
- memcpy_fromfs(&tmp_fw, optval,optlen);
- err=ip_acct_ctl(optname, &tmp_fw,optlen);
- return -err; /* -0 is 0 after all */
-#endif
- /* IP_OPTIONS and friends go here eventually */
- default:
- return(-ENOPROTOOPT);
- }
-}
-
-/*
- * Get the options. Note for future reference. The GET of IP options gets the
- * _received_ ones. The set sets the _sent_ ones.
- */
-
-int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
-{
- int val,err;
-#ifdef CONFIG_IP_MULTICAST
- int len;
-#endif
-
- if(level!=SOL_IP)
- return -EOPNOTSUPP;
-
- switch(optname)
- {
- case IP_TOS:
- val=sk->ip_tos;
- break;
- case IP_TTL:
- val=sk->ip_ttl;
- break;
-#ifdef CONFIG_IP_MULTICAST
- case IP_MULTICAST_TTL:
- val=sk->ip_mc_ttl;
- break;
- case IP_MULTICAST_LOOP:
- val=sk->ip_mc_loop;
- break;
- case IP_MULTICAST_IF:
- err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
- if(err)
- return err;
- len=strlen(sk->ip_mc_name);
- err=verify_area(VERIFY_WRITE, optval, len);
- if(err)
- return err;
- put_fs_long(len,(unsigned long *) optlen);
- memcpy_tofs((void *)optval,sk->ip_mc_name, len);
- return 0;
-#endif
- default:
- return(-ENOPROTOOPT);
- }
- err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(int),(unsigned long *) optlen);
-
- err=verify_area(VERIFY_WRITE, optval, sizeof(int));
- if(err)
- return err;
- put_fs_long(val,(unsigned long *)optval);
-
- return(0);
-}
-
-/*
- * IP protocol layer initialiser
- */
-
-static struct packet_type ip_packet_type =
-{
- 0, /* MUTTER ntohs(ETH_P_IP),*/
- NULL, /* All devices */
- ip_rcv,
- NULL,
- NULL,
-};
-
-/*
- * Device notifier
- */
-
-static int ip_rt_event(unsigned long event, void *ptr)
-{
- if(event==NETDEV_DOWN)
- ip_rt_flush(ptr);
- return NOTIFY_DONE;
-}
-
-struct notifier_block ip_rt_notifier={
- ip_rt_event,
- NULL,
- 0
-};
-
-/*
- * IP registers the packet type and then calls the subprotocol initialisers
- */
-
-void ip_init(void)
-{
- ip_packet_type.type=htons(ETH_P_IP);
- dev_add_pack(&ip_packet_type);
-
- /* So we flush routes when a device is downed */
- register_netdevice_notifier(&ip_rt_notifier);
-/* ip_raw_init();
- ip_packet_init();
- ip_tcp_init();
- ip_udp_init();*/
-}
diff --git a/pfinet/linux-inet/ip.h b/pfinet/linux-inet/ip.h
deleted file mode 100644
index 95954a8c..00000000
--- a/pfinet/linux-inet/ip.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the IP module.
- *
- * Version: @(#)ip.h 1.0.2 05/07/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _IP_H
-#define _IP_H
-
-
-#include <linux/ip.h>
-#include <linux/config.h>
-
-#ifndef _SNMP_H
-#include "snmp.h"
-#endif
-
-#include "sock.h" /* struct sock */
-
-/* IP flags. */
-#define IP_CE 0x8000 /* Flag: "Congestion" */
-#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
-#define IP_MF 0x2000 /* Flag: "More Fragments" */
-#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */
-
-#define IP_FRAG_TIME (30 * HZ) /* fragment lifetime */
-
-#ifdef CONFIG_IP_MULTICAST
-extern void ip_mc_dropsocket(struct sock *);
-extern void ip_mc_dropdevice(struct device *dev);
-extern int ip_mc_procinfo(char *, char **, off_t, int);
-#define MULTICAST(x) (IN_MULTICAST(htonl(x)))
-#endif
-
-
-/* Describe an IP fragment. */
-struct ipfrag {
- int offset; /* offset of fragment in IP datagram */
- int end; /* last byte of data in datagram */
- int len; /* length of this fragment */
- struct sk_buff *skb; /* complete received fragment */
- unsigned char *ptr; /* pointer into real fragment data */
- struct ipfrag *next; /* linked list pointers */
- struct ipfrag *prev;
-};
-
-/* Describe an entry in the "incomplete datagrams" queue. */
-struct ipq {
- unsigned char *mac; /* pointer to MAC header */
- struct iphdr *iph; /* pointer to IP header */
- int len; /* total length of original datagram */
- short ihlen; /* length of the IP header */
- short maclen; /* length of the MAC header */
- struct timer_list timer; /* when will this queue expire? */
- struct ipfrag *fragments; /* linked list of received fragments */
- struct ipq *next; /* linked list pointers */
- struct ipq *prev;
- struct device *dev; /* Device - for icmp replies */
-};
-
-
-extern int backoff(int n);
-
-extern void ip_print(const struct iphdr *ip);
-extern int ip_ioctl(struct sock *sk, int cmd,
- unsigned long arg);
-extern void ip_route_check(unsigned long daddr);
-extern int ip_build_header(struct sk_buff *skb,
- unsigned long saddr,
- unsigned long daddr,
- struct device **dev, int type,
- struct options *opt, int len,
- int tos,int ttl);
-extern unsigned short ip_compute_csum(unsigned char * buff, int len);
-extern int ip_rcv(struct sk_buff *skb, struct device *dev,
- struct packet_type *pt);
-extern void ip_send_check(struct iphdr *ip);
-extern int ip_id_count;
-extern void ip_queue_xmit(struct sock *sk,
- struct device *dev, struct sk_buff *skb,
- int free);
-extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
-extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
-extern void ip_init(void);
-
-extern struct ip_mib ip_statistics;
-
-/*
- * This is a version of ip_compute_csum() optimized for IP headers, which
- * always checksum on 4 octet boundaries.
- * Used by ip.c and slhc.c (the net driver module)
- * (Moved to here by bj0rn@blox.se)
- */
-
-static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
-{
- unsigned long sum = 0;
-
- if (wlen)
- {
- unsigned long bogus;
- __asm__("clc\n"
- "1:\t"
- "lodsl\n\t"
- "adcl %3, %0\n\t"
- "decl %2\n\t"
- "jne 1b\n\t"
- "adcl $0, %0\n\t"
- "movl %0, %3\n\t"
- "shrl $16, %3\n\t"
- "addw %w3, %w0\n\t"
- "adcw $0, %w0"
- : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
- : "0" (sum), "1" (buff), "2" (wlen));
- }
- return (~sum) & 0xffff;
-}
-#endif /* _IP_H */
diff --git a/pfinet/linux-inet/ip_fw.c b/pfinet/linux-inet/ip_fw.c
deleted file mode 100644
index 0572c8f1..00000000
--- a/pfinet/linux-inet/ip_fw.c
+++ /dev/null
@@ -1,1016 +0,0 @@
-/*
- * IP firewalling code. This is taken from 4.4BSD. Please note the
- * copyright message below. As per the GPL it must be maintained
- * and the licenses thus do not conflict. While this port is subject
- * to the GPL I also place my modifications under the original
- * license in recognition of the original copyright.
- * -- Alan Cox.
- *
- * Ported from BSD to Linux,
- * Alan Cox 22/Nov/1994.
- * Zeroing /proc and other additions
- * Jos Vos 4/Feb/1995.
- * Merged and included the FreeBSD-Current changes at Ugen's request
- * (but hey it's a lot cleaner now). Ugen would prefer in some ways
- * we waited for his final product but since Linux 1.2.0 is about to
- * appear it's not practical - Read: It works, it's not clean but please
- * don't consider it to be his standard of finished work.
- * Alan Cox 12/Feb/1995
- * Porting bidirectional entries from BSD, fixing accounting issues,
- * adding struct ip_fwpkt for checking packets with interface address
- * Jos Vos 5/Mar/1995.
- *
- * All the real work was done by .....
- */
-
-/*
- * Copyright (c) 1993 Daniel Boulet
- * Copyright (c) 1994 Ugen J.S.Antsilevich
- *
- * Redistribution and use in source forms, with and without modification,
- * are permitted provided that this entire comment appears intact.
- *
- * Redistribution in binary form may occur without any restrictions.
- * Obviously, it would be nice if you gave credit where credit is due
- * but requiring it would be too onerous.
- *
- * This software is provided ``AS IS'' without any warranties of any kind.
- */
-
-#include <linux/config.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/config.h>
-
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/icmp.h>
-#include <linux/udp.h>
-#include "ip.h"
-#include "protocol.h"
-#include "route.h"
-#include "tcp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "icmp.h"
-#include <linux/ip_fw.h>
-
-/*
- * Implement IP packet firewall
- */
-
-#ifdef CONFIG_IPFIREWALL_DEBUG
-#define dprintf1(a) printk(a)
-#define dprintf2(a1,a2) printk(a1,a2)
-#define dprintf3(a1,a2,a3) printk(a1,a2,a3)
-#define dprintf4(a1,a2,a3,a4) printk(a1,a2,a3,a4)
-#else
-#define dprintf1(a)
-#define dprintf2(a1,a2)
-#define dprintf3(a1,a2,a3)
-#define dprintf4(a1,a2,a3,a4)
-#endif
-
-#define print_ip(a) printf("%d.%d.%d.%d",(ntohl(a.s_addr)>>24)&0xFF,\
- (ntohl(a.s_addr)>>16)&0xFF,\
- (ntohl(a.s_addr)>>8)&0xFF,\
- (ntohl(a.s_addr))&0xFF);
-
-#ifdef IPFIREWALL_DEBUG
-#define dprint_ip(a) print_ip(a)
-#else
-#define dprint_ip(a)
-#endif
-
-#ifdef CONFIG_IP_FIREWALL
-struct ip_fw *ip_fw_fwd_chain;
-struct ip_fw *ip_fw_blk_chain;
-int ip_fw_blk_policy=IP_FW_F_ACCEPT;
-int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
-#endif
-#ifdef CONFIG_IP_ACCT
-struct ip_fw *ip_acct_chain;
-#endif
-
-#define IP_INFO_BLK 0
-#define IP_INFO_FWD 1
-#define IP_INFO_ACCT 2
-
-
-/*
- * Returns 1 if the port is matched by the vector, 0 otherwise
- */
-
-extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag)
-{
- if (!nports)
- return 1;
- if ( range_flag )
- {
- if ( portptr[0] <= port && port <= portptr[1] )
- {
- return( 1 );
- }
- nports -= 2;
- portptr += 2;
- }
- while ( nports-- > 0 )
- {
- if ( *portptr++ == port )
- {
- return( 1 );
- }
- }
- return(0);
-}
-
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
-
-
-/*
- * Returns 0 if packet should be dropped, 1 if it should be accepted,
- * and -1 if an ICMP host unreachable packet should be sent.
- * Also does accounting so you can feed it the accounting chain.
- * If opt is set to 1, it means that we do this for accounting
- * purposes (searches all entries and handles fragments different).
- * If opt is set to 2, it doesn't count a matching packet, which
- * is used when calling this for checking purposes (IP_FW_CHK_*).
- */
-
-
-int ip_fw_chk(struct iphdr *ip, struct device *rif, struct ip_fw *chain, int policy, int opt)
-{
- struct ip_fw *f;
- struct tcphdr *tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl);
- struct udphdr *udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
- __u32 src, dst;
- __u16 src_port=0, dst_port=0;
- unsigned short f_prt=0, prt;
- char notcpsyn=1, frag1, match;
- unsigned short f_flag;
-
- /*
- * If the chain is empty follow policy. The BSD one
- * accepts anything giving you a time window while
- * flushing and rebuilding the tables.
- */
-
- src = ip->saddr;
- dst = ip->daddr;
-
- /*
- * This way we handle fragmented packets.
- * we ignore all fragments but the first one
- * so the whole packet can't be reassembled.
- * This way we relay on the full info which
- * stored only in first packet.
- *
- * Note that this theoretically allows partial packet
- * spoofing. Not very dangerous but paranoid people may
- * wish to play with this. It also allows the so called
- * "fragment bomb" denial of service attack on some types
- * of system.
- */
-
- frag1 = ((ntohs(ip->frag_off) & IP_OFFSET) == 0);
- if (!frag1 && (opt != 1) && (ip->protocol == IPPROTO_TCP ||
- ip->protocol == IPPROTO_UDP))
- return(1);
-
- src = ip->saddr;
- dst = ip->daddr;
-
- /*
- * If we got interface from which packet came
- * we can use the address directly. This is unlike
- * 4.4BSD derived systems that have an address chain
- * per device. We have a device per address with dummy
- * devices instead.
- */
-
- dprintf1("Packet ");
- switch(ip->protocol)
- {
- case IPPROTO_TCP:
- dprintf1("TCP ");
- /* ports stay 0 if it is not the first fragment */
- if (frag1) {
- src_port=ntohs(tcp->source);
- dst_port=ntohs(tcp->dest);
- if(tcp->syn && !tcp->ack)
- /* We *DO* have SYN, value FALSE */
- notcpsyn=0;
- }
- prt=IP_FW_F_TCP;
- break;
- case IPPROTO_UDP:
- dprintf1("UDP ");
- /* ports stay 0 if it is not the first fragment */
- if (frag1) {
- src_port=ntohs(udp->source);
- dst_port=ntohs(udp->dest);
- }
- prt=IP_FW_F_UDP;
- break;
- case IPPROTO_ICMP:
- dprintf2("ICMP:%d ",((char *)portptr)[0]&0xff);
- prt=IP_FW_F_ICMP;
- break;
- default:
- dprintf2("p=%d ",ip->protocol);
- prt=IP_FW_F_ALL;
- break;
- }
- dprint_ip(ip->saddr);
-
- if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
- /* This will print 0 when it is not the first fragment! */
- dprintf2(":%d ", src_port);
- dprint_ip(ip->daddr);
- if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
- /* This will print 0 when it is not the first fragment! */
- dprintf2(":%d ",dst_port);
- dprintf1("\n");
-
- for (f=chain;f;f=f->fw_next)
- {
- /*
- * This is a bit simpler as we don't have to walk
- * an interface chain as you do in BSD - same logic
- * however.
- */
-
- /*
- * Match can become 0x01 (a "normal" match was found),
- * 0x02 (a reverse match was found), and 0x03 (the
- * IP addresses match in both directions).
- * Now we know in which direction(s) we should look
- * for a match for the TCP/UDP ports. Both directions
- * might match (e.g., when both addresses are on the
- * same network for which an address/mask is given), but
- * the ports might only match in one direction.
- * This was obviously wrong in the original BSD code.
- */
- match = 0x00;
-
- if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
- && (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
- /* normal direction */
- match |= 0x01;
-
- if ((f->fw_flg & IP_FW_F_BIDIR) &&
- (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
- && (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
- /* reverse direction */
- match |= 0x02;
-
- if (match)
- {
- /*
- * Look for a VIA match
- */
- if(f->fw_via.s_addr && rif)
- {
- if(rif->pa_addr!=f->fw_via.s_addr)
- continue; /* Mismatch */
- }
- /*
- * Drop through - this is a match
- */
- }
- else
- continue;
-
- /*
- * Ok the chain addresses match.
- */
-
- f_prt=f->fw_flg&IP_FW_F_KIND;
- if (f_prt!=IP_FW_F_ALL)
- {
- /*
- * This is actually buggy as if you set SYN flag
- * on UDP or ICMP firewall it will never work,but
- * actually it is a concern of software which sets
- * firewall entries.
- */
-
- if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
- continue;
- /*
- * Specific firewall - packet's protocol
- * must match firewall's.
- */
-
- if(prt!=f_prt)
- continue;
-
- if(!(prt==IP_FW_F_ICMP || ((match & 0x01) &&
- port_match(&f->fw_pts[0], f->fw_nsp, src_port,
- f->fw_flg&IP_FW_F_SRNG) &&
- port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
- f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) &&
- port_match(&f->fw_pts[0], f->fw_nsp, dst_port,
- f->fw_flg&IP_FW_F_SRNG) &&
- port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port,
- f->fw_flg&IP_FW_F_DRNG))))
- {
- continue;
- }
- }
-#ifdef CONFIG_IP_FIREWALL_VERBOSE
- /*
- * VERY ugly piece of code which actually
- * makes kernel printf for denied packets...
- */
-
- if (f->fw_flg & IP_FW_F_PRN)
- {
- if(opt != 1) {
- if(f->fw_flg&IP_FW_F_ACCEPT)
- printk("Accept ");
- else if(f->fw_flg&IP_FW_F_ICMPRPL)
- printk("Reject ");
- else
- printk("Deny ");
- }
- switch(ip->protocol)
- {
- case IPPROTO_TCP:
- printk("TCP ");
- break;
- case IPPROTO_UDP:
- printk("UDP ");
- case IPPROTO_ICMP:
- printk("ICMP ");
- break;
- default:
- printk("p=%d ",ip->protocol);
- break;
- }
- print_ip(ip->saddr);
- if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
- printk(":%d", src_port);
- printk(" ");
- print_ip(ip->daddr);
- if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
- printk(":%d",dst_port);
- printk("\n");
- }
-#endif
- if (opt != 2) {
- f->fw_bcnt+=ntohs(ip->tot_len);
- f->fw_pcnt++;
- }
- if (opt != 1)
- break;
- } /* Loop */
-
- if(opt == 1)
- return 0;
-
- /*
- * We rely on policy defined in the rejecting entry or, if no match
- * was found, we rely on the general policy variable for this type
- * of firewall.
- */
-
- if(f!=NULL) /* A match was found */
- f_flag=f->fw_flg;
- else
- f_flag=policy;
- if(f_flag&IP_FW_F_ACCEPT)
- return 1;
- if(f_flag&IP_FW_F_ICMPRPL)
- return -1;
- return 0;
-}
-
-
-static void zero_fw_chain(struct ip_fw *chainptr)
-{
- struct ip_fw *ctmp=chainptr;
- while(ctmp)
- {
- ctmp->fw_pcnt=0L;
- ctmp->fw_bcnt=0L;
- ctmp=ctmp->fw_next;
- }
-}
-
-static void free_fw_chain(struct ip_fw *volatile* chainptr)
-{
- unsigned long flags;
- save_flags(flags);
- cli();
- while ( *chainptr != NULL )
- {
- struct ip_fw *ftmp;
- ftmp = *chainptr;
- *chainptr = ftmp->fw_next;
- kfree_s(ftmp,sizeof(*ftmp));
- }
- restore_flags(flags);
-}
-
-/* Volatiles to keep some of the compiler versions amused */
-
-static int add_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl)
-{
- struct ip_fw *ftmp;
- struct ip_fw *chtmp=NULL;
- struct ip_fw *volatile chtmp_prev=NULL;
- unsigned long flags;
- unsigned long m_src_mask,m_dst_mask;
- unsigned long n_sa,n_da,o_sa,o_da,o_sm,o_dm,n_sm,n_dm;
- unsigned short n_sr,n_dr,o_sr,o_dr;
- unsigned short oldkind,newkind;
- int addb4=0;
- int n_o,n_n;
-
- save_flags(flags);
-
- ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
- if ( ftmp == NULL )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printf("ip_fw_ctl: malloc said no\n");
-#endif
- return( ENOMEM );
- }
-
- memcpy(ftmp, frwl, sizeof( struct ip_fw ) );
-
- ftmp->fw_pcnt=0L;
- ftmp->fw_bcnt=0L;
-
- ftmp->fw_next = NULL;
-
- cli();
-
- if (*chainptr==NULL)
- {
- *chainptr=ftmp;
- }
- else
- {
- chtmp_prev=NULL;
- for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next)
- {
- addb4=0;
- newkind=ftmp->fw_flg & IP_FW_F_KIND;
- oldkind=chtmp->fw_flg & IP_FW_F_KIND;
-
- if (newkind!=IP_FW_F_ALL
- && oldkind!=IP_FW_F_ALL
- && oldkind!=newkind)
- {
- chtmp_prev=chtmp;
- continue;
- }
-
- /*
- * Very very *UGLY* code...
- * Sorry,but i had to do this....
- */
-
- n_sa=ntohl(ftmp->fw_src.s_addr);
- n_da=ntohl(ftmp->fw_dst.s_addr);
- n_sm=ntohl(ftmp->fw_smsk.s_addr);
- n_dm=ntohl(ftmp->fw_dmsk.s_addr);
-
- o_sa=ntohl(chtmp->fw_src.s_addr);
- o_da=ntohl(chtmp->fw_dst.s_addr);
- o_sm=ntohl(chtmp->fw_smsk.s_addr);
- o_dm=ntohl(chtmp->fw_dmsk.s_addr);
-
- m_src_mask = o_sm & n_sm;
- m_dst_mask = o_dm & n_dm;
-
- if ((o_sa & m_src_mask) == (n_sa & m_src_mask))
- {
- if (n_sm > o_sm)
- addb4++;
- if (n_sm < o_sm)
- addb4--;
- }
-
- if ((o_da & m_dst_mask) == (n_da & m_dst_mask))
- {
- if (n_dm > o_dm)
- addb4++;
- if (n_dm < o_dm)
- addb4--;
- }
-
- if (((o_da & o_dm) == (n_da & n_dm))
- &&((o_sa & o_sm) == (n_sa & n_sm)))
- {
- if (newkind!=IP_FW_F_ALL &&
- oldkind==IP_FW_F_ALL)
- addb4++;
- if (newkind==oldkind && (oldkind==IP_FW_F_TCP
- || oldkind==IP_FW_F_UDP))
- {
-
- /*
- * Here the main idea is to check the size
- * of port range which the frwl covers
- * We actually don't check their values but
- * just the wideness of range they have
- * so that less wide ranges or single ports
- * go first and wide ranges go later. No ports
- * at all treated as a range of maximum number
- * of ports.
- */
-
- if (ftmp->fw_flg & IP_FW_F_SRNG)
- n_sr=ftmp->fw_pts[1]-ftmp->fw_pts[0];
- else
- n_sr=(ftmp->fw_nsp)?
- ftmp->fw_nsp : 0xFFFF;
-
- if (chtmp->fw_flg & IP_FW_F_SRNG)
- o_sr=chtmp->fw_pts[1]-chtmp->fw_pts[0];
- else
- o_sr=(chtmp->fw_nsp)?chtmp->fw_nsp : 0xFFFF;
-
- if (n_sr<o_sr)
- addb4++;
- if (n_sr>o_sr)
- addb4--;
-
- n_n=ftmp->fw_nsp;
- n_o=chtmp->fw_nsp;
-
- /*
- * Actually this cannot happen as the frwl control
- * procedure checks for number of ports in source and
- * destination range but we will try to be more safe.
- */
-
- if ((n_n>(IP_FW_MAX_PORTS-2)) ||
- (n_o>(IP_FW_MAX_PORTS-2)))
- goto skip_check;
-
- if (ftmp->fw_flg & IP_FW_F_DRNG)
- n_dr=ftmp->fw_pts[n_n+1]-ftmp->fw_pts[n_n];
- else
- n_dr=(ftmp->fw_ndp)? ftmp->fw_ndp : 0xFFFF;
-
- if (chtmp->fw_flg & IP_FW_F_DRNG)
- o_dr=chtmp->fw_pts[n_o+1]-chtmp->fw_pts[n_o];
- else
- o_dr=(chtmp->fw_ndp)? chtmp->fw_ndp : 0xFFFF;
- if (n_dr<o_dr)
- addb4++;
- if (n_dr>o_dr)
- addb4--;
-skip_check:
- }
- /* finally look at the interface address */
- if ((addb4 == 0) && ftmp->fw_via.s_addr &&
- !(chtmp->fw_via.s_addr))
- addb4++;
- }
- if (addb4>0)
- {
- if (chtmp_prev)
- {
- chtmp_prev->fw_next=ftmp;
- ftmp->fw_next=chtmp;
- }
- else
- {
- *chainptr=ftmp;
- ftmp->fw_next=chtmp;
- }
- restore_flags(flags);
- return 0;
- }
- chtmp_prev=chtmp;
- }
- }
-
- if (chtmp_prev)
- chtmp_prev->fw_next=ftmp;
- else
- *chainptr=ftmp;
- restore_flags(flags);
- return(0);
-}
-
-static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
-{
- struct ip_fw *ftmp,*ltmp;
- unsigned short tport1,tport2,tmpnum;
- char matches,was_found;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- ftmp=*chainptr;
-
- if ( ftmp == NULL )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printk("ip_fw_ctl: chain is empty\n");
-#endif
- restore_flags(flags);
- return( EINVAL );
- }
-
- ltmp=NULL;
- was_found=0;
-
- while( ftmp != NULL )
- {
- matches=1;
- if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr
- || ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr
- || ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr
- || ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr
- || ftmp->fw_via.s_addr!=frwl->fw_via.s_addr
- || ftmp->fw_flg!=frwl->fw_flg)
- matches=0;
-
- tport1=ftmp->fw_nsp+ftmp->fw_ndp;
- tport2=frwl->fw_nsp+frwl->fw_ndp;
- if (tport1!=tport2)
- matches=0;
- else if (tport1!=0)
- {
- for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
- if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum])
- matches=0;
- }
- if(matches)
- {
- was_found=1;
- if (ltmp)
- {
- ltmp->fw_next=ftmp->fw_next;
- kfree_s(ftmp,sizeof(*ftmp));
- ftmp=ltmp->fw_next;
- }
- else
- {
- *chainptr=ftmp->fw_next;
- kfree_s(ftmp,sizeof(*ftmp));
- ftmp=*chainptr;
- }
- }
- else
- {
- ltmp = ftmp;
- ftmp = ftmp->fw_next;
- }
- }
- restore_flags(flags);
- if (was_found)
- return 0;
- else
- return(EINVAL);
-}
-
-#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
-
-struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
-{
-
- if ( len != sizeof(struct ip_fw) )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printk("ip_fw_ctl: len=%d, want %d\n",m->m_len,
- sizeof(struct ip_fw));
-#endif
- return(NULL);
- }
-
- if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
- frwl->fw_flg);
-#endif
- return(NULL);
- }
-
- if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printk("ip_fw_ctl: src range set but n_src_p=%d\n",
- frwl->fw_nsp);
-#endif
- return(NULL);
- }
-
- if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printk("ip_fw_ctl: dst range set but n_dst_p=%d\n",
- frwl->fw_ndp);
-#endif
- return(NULL);
- }
-
- if ( frwl->fw_nsp + frwl->fw_ndp > IP_FW_MAX_PORTS )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printk("ip_fw_ctl: too many ports (%d+%d)\n",
- frwl->fw_nsp,frwl->fw_ndp);
-#endif
- return(NULL);
- }
-
- return frwl;
-}
-
-
-
-
-#ifdef CONFIG_IP_ACCT
-
-void ip_acct_cnt(struct iphdr *iph, struct device *dev, struct ip_fw *f)
-{
- (void) ip_fw_chk(iph, dev, f, 0, 1);
- return;
-}
-
-int ip_acct_ctl(int stage, void *m, int len)
-{
- if ( stage == IP_ACCT_FLUSH )
- {
- free_fw_chain(&ip_acct_chain);
- return(0);
- }
- if ( stage == IP_ACCT_ZERO )
- {
- zero_fw_chain(ip_acct_chain);
- return(0);
- }
- if ( stage == IP_ACCT_ADD
- || stage == IP_ACCT_DEL
- )
- {
- struct ip_fw *frwl;
-
- if (!(frwl=check_ipfw_struct(m,len)))
- return (EINVAL);
-
- switch (stage)
- {
- case IP_ACCT_ADD:
- return( add_to_chain(&ip_acct_chain,frwl));
- case IP_ACCT_DEL:
- return( del_from_chain(&ip_acct_chain,frwl));
- default:
- /*
- * Should be panic but... (Why ??? - AC)
- */
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printf("ip_acct_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
- }
- }
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printf("ip_acct_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
-}
-#endif
-
-#ifdef CONFIG_IP_FIREWALL
-int ip_fw_ctl(int stage, void *m, int len)
-{
- int ret;
-
- if ( stage == IP_FW_FLUSH_BLK )
- {
- free_fw_chain(&ip_fw_blk_chain);
- return(0);
- }
-
- if ( stage == IP_FW_FLUSH_FWD )
- {
- free_fw_chain(&ip_fw_fwd_chain);
- return(0);
- }
-
- if ( stage == IP_FW_ZERO_BLK )
- {
- zero_fw_chain(ip_fw_blk_chain);
- return(0);
- }
-
- if ( stage == IP_FW_ZERO_FWD )
- {
- zero_fw_chain(ip_fw_fwd_chain);
- return(0);
- }
-
- if ( stage == IP_FW_POLICY_BLK || stage == IP_FW_POLICY_FWD )
- {
- int *tmp_policy_ptr;
- tmp_policy_ptr=(int *)m;
- if ( stage == IP_FW_POLICY_BLK )
- ip_fw_blk_policy=*tmp_policy_ptr;
- else
- ip_fw_fwd_policy=*tmp_policy_ptr;
- return 0;
- }
-
- if ( stage == IP_FW_CHK_BLK || stage == IP_FW_CHK_FWD )
- {
- struct device viadev;
- struct ip_fwpkt *ipfwp;
- struct iphdr *ip;
-
- if ( len < sizeof(struct ip_fwpkt) )
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printf("ip_fw_ctl: length=%d, expected %d\n",
- len, sizeof(struct ip_fwpkt));
-#endif
- return( EINVAL );
- }
-
- ipfwp = (struct ip_fwpkt *)m;
- ip = &(ipfwp->fwp_iph);
-
- if ( ip->ihl != sizeof(struct iphdr) / sizeof(int))
- {
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printf("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
- sizeof(struct ip)/sizeof(int));
-#endif
- return(EINVAL);
- }
-
- viadev.pa_addr = ipfwp->fwp_via.s_addr;
-
- if ((ret = ip_fw_chk(ip, &viadev,
- stage == IP_FW_CHK_BLK ?
- ip_fw_blk_chain : ip_fw_fwd_chain,
- stage == IP_FW_CHK_BLK ?
- ip_fw_blk_policy : ip_fw_fwd_policy, 2 )) > 0
- )
- return(0);
- else if (ret == -1)
- return(ECONNREFUSED);
- else
- return(ETIMEDOUT);
- }
-
-/*
- * Here we really working hard-adding new elements
- * to blocking/forwarding chains or deleting 'em
- */
-
- if ( stage == IP_FW_ADD_BLK || stage == IP_FW_ADD_FWD
- || stage == IP_FW_DEL_BLK || stage == IP_FW_DEL_FWD
- )
- {
- struct ip_fw *frwl;
- frwl=check_ipfw_struct(m,len);
- if (frwl==NULL)
- return (EINVAL);
-
- switch (stage)
- {
- case IP_FW_ADD_BLK:
- return(add_to_chain(&ip_fw_blk_chain,frwl));
- case IP_FW_ADD_FWD:
- return(add_to_chain(&ip_fw_fwd_chain,frwl));
- case IP_FW_DEL_BLK:
- return(del_from_chain(&ip_fw_blk_chain,frwl));
- case IP_FW_DEL_FWD:
- return(del_from_chain(&ip_fw_fwd_chain,frwl));
- default:
- /*
- * Should be panic but... (Why are BSD people panic obsessed ??)
- */
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printk("ip_fw_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
- }
- }
-
-#ifdef DEBUG_CONFIG_IP_FIREWALL
- printf("ip_fw_ctl: unknown request %d\n",stage);
-#endif
- return(EINVAL);
-}
-#endif /* CONFIG_IP_FIREWALL */
-
-#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
-
-static int ip_chain_procinfo(int stage, char *buffer, char **start,
- off_t offset, int length, int reset)
-{
- off_t pos=0, begin=0;
- struct ip_fw *i;
- unsigned long flags;
- int len, p;
-
-
- switch(stage)
- {
-#ifdef CONFIG_IP_FIREWALL
- case IP_INFO_BLK:
- i = ip_fw_blk_chain;
- len=sprintf(buffer, "IP firewall block rules, default %d\n",
- ip_fw_blk_policy);
- break;
- case IP_INFO_FWD:
- i = ip_fw_fwd_chain;
- len=sprintf(buffer, "IP firewall forward rules, default %d\n",
- ip_fw_fwd_policy);
- break;
-#endif
-#ifdef CONFIG_IP_ACCT
- case IP_INFO_ACCT:
- i = ip_acct_chain;
- len=sprintf(buffer,"IP accounting rules\n");
- break;
-#endif
- default:
- /* this should never be reached, but safety first... */
- i = NULL;
- len=0;
- break;
- }
-
- save_flags(flags);
- cli();
-
- while(i!=NULL)
- {
- len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %08lX %X ",
- ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr),
- ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr),
- ntohl(i->fw_via.s_addr),i->fw_flg);
- len+=sprintf(buffer+len,"%u %u %lu %lu",
- i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt);
- for (p = 0; p < IP_FW_MAX_PORTS; p++)
- len+=sprintf(buffer+len, " %u", i->fw_pts[p]);
- buffer[len++]='\n';
- buffer[len]='\0';
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- else if(reset)
- {
- /* This needs to be done at this specific place! */
- i->fw_pcnt=0L;
- i->fw_bcnt=0L;
- }
- if(pos>offset+length)
- break;
- i=i->fw_next;
- }
- restore_flags(flags);
- *start=buffer+(offset-begin);
- len-=(offset-begin);
- if(len>length)
- len=length;
- return len;
-}
-#endif
-
-#ifdef CONFIG_IP_ACCT
-
-int ip_acct_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
-{
- return ip_chain_procinfo(IP_INFO_ACCT, buffer,start,offset,length,reset);
-}
-
-#endif
-
-#ifdef CONFIG_IP_FIREWALL
-
-int ip_fw_blk_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
-{
- return ip_chain_procinfo(IP_INFO_BLK, buffer,start,offset,length,reset);
-}
-
-int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, int length, int reset)
-{
- return ip_chain_procinfo(IP_INFO_FWD, buffer,start,offset,length,reset);
-}
-
-#endif
diff --git a/pfinet/linux-inet/ipx.c b/pfinet/linux-inet/ipx.c
deleted file mode 100644
index 88b53c30..00000000
--- a/pfinet/linux-inet/ipx.c
+++ /dev/null
@@ -1,1947 +0,0 @@
-/*
- * Implements an IPX socket layer (badly - but I'm working on it).
- *
- * This code is derived from work by
- * Ross Biro : Writing the original IP stack
- * Fred Van Kempen : Tidying up the TCP/IP
- *
- * Many thanks go to Keith Baker, Institute For Industrial Information
- * Technology Ltd, Swansea University for allowing me to work on this
- * in my own time even though it was in some ways related to commercial
- * work I am currently employed to do there.
- *
- * All the material in this file is subject to the Gnu license version 2.
- * Neither Alan Cox nor the Swansea University Computer Society admit liability
- * nor provide warranty for any of this software. This material is provided
- * as is and at no charge.
- *
- * Revision 0.21: Uses the new generic socket option code.
- * Revision 0.22: Gcc clean ups and drop out device registration. Use the
- * new multi-protocol edition of hard_header
- * Revision 0.23: IPX /proc by Mark Evans.
- * Adding a route will overwrite any existing route to the same
- * network.
- * Revision 0.24: Supports new /proc with no 4K limit
- * Revision 0.25: Add ephemeral sockets, passive local network
- * identification, support for local net 0 and
- * multiple datalinks <Greg Page>
- * Revision 0.26: Device drop kills IPX routes via it. (needed for modules)
- * Revision 0.27: Autobind <Mark Evans>
- * Revision 0.28: Small fix for multiple local networks <Thomas Winder>
- * Revision 0.29: Assorted major errors removed <Mark Evans>
- * Small correction to promisc mode error fix <Alan Cox>
- * Asynchronous I/O support.
- * Changed to use notifiers and the newer packet_type stuff.
- * Assorted major fixes <Alejandro Liu>
- *
- * Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com>
- * Neither Greg Page nor Caldera, Inc. admit liability nor provide
- * warranty for any of this software. This material is provided
- * "AS-IS" and at no charge.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/ipx.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include "sock.h"
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/termios.h> /* For TIOCOUTQ/INQ */
-#include <linux/interrupt.h>
-#include "p8022.h"
-#include "psnap.h"
-
-#ifdef CONFIG_IPX
-/* Configuration Variables */
-static unsigned char ipxcfg_max_hops = 16;
-static char ipxcfg_auto_select_primary = 0;
-static char ipxcfg_auto_create_interfaces = 0;
-
-/* Global Variables */
-static struct datalink_proto *p8022_datalink = NULL;
-static struct datalink_proto *pEII_datalink = NULL;
-static struct datalink_proto *p8023_datalink = NULL;
-static struct datalink_proto *pSNAP_datalink = NULL;
-
-static ipx_interface *ipx_interfaces = NULL;
-static ipx_route *ipx_routes = NULL;
-static ipx_interface *ipx_internal_net = NULL;
-static ipx_interface *ipx_primary_net = NULL;
-
-static int
-ipxcfg_set_auto_create(char val)
-{
- ipxcfg_auto_create_interfaces = val;
- return 0;
-}
-
-static int
-ipxcfg_set_auto_select(char val)
-{
- ipxcfg_auto_select_primary = val;
- if (val && (ipx_primary_net == NULL))
- ipx_primary_net = ipx_interfaces;
- return 0;
-}
-
-static int
-ipxcfg_get_config_data(ipx_config_data *arg)
-{
- ipx_config_data vals;
-
- vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces;
- vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary;
- memcpy_tofs(arg, &vals, sizeof(vals));
- return 0;
-}
-
-
-/***********************************************************************************************************************\
-* *
-* Handlers for the socket list. *
-* *
-\***********************************************************************************************************************/
-
-/*
- * Note: Sockets may not be removed _during_ an interrupt or inet_bh
- * handler using this technique. They can be added although we do not
- * use this facility.
- */
-
-static void
-ipx_remove_socket(ipx_socket *sk)
-{
- ipx_socket *s;
- ipx_interface *intrfc;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- /* Determine interface with which socket is associated */
- intrfc = sk->ipx_intrfc;
- if (intrfc == NULL) {
- restore_flags(flags);
- return;
- }
-
- s=intrfc->if_sklist;
- if(s==sk) {
- intrfc->if_sklist=s->next;
- restore_flags(flags);
- return;
- }
-
- while(s && s->next) {
- if(s->next==sk) {
- s->next=sk->next;
- restore_flags(flags);
- return;
- }
- s=s->next;
- }
- restore_flags(flags);
-}
-
-/*
- * This is only called from user mode. Thus it protects itself against
- * interrupt users but doesn't worry about being called during work.
- * Once it is removed from the queue no interrupt or bottom half will
- * touch it and we are (fairly 8-) ) safe.
- */
-
-static void
-ipx_destroy_socket(ipx_socket *sk)
-{
- struct sk_buff *skb;
-
- ipx_remove_socket(sk);
- while((skb=skb_dequeue(&sk->receive_queue))!=NULL) {
- kfree_skb(skb,FREE_READ);
- }
-
- kfree_s(sk,sizeof(*sk));
-}
-
-/* The following code is used to support IPX Interfaces (IPXITF). An
- * IPX interface is defined by a physical device and a frame type.
- */
-
-static ipx_route * ipxrtr_lookup(unsigned long);
-
-static void
-ipxitf_clear_primary_net(void)
-{
- if (ipxcfg_auto_select_primary && (ipx_interfaces != NULL))
- ipx_primary_net = ipx_interfaces;
- else
- ipx_primary_net = NULL;
-}
-
-static ipx_interface *
-ipxitf_find_using_phys(struct device *dev, unsigned short datalink)
-{
- ipx_interface *i;
-
- for (i=ipx_interfaces;
- i && ((i->if_dev!=dev) || (i->if_dlink_type!=datalink));
- i=i->if_next)
- ;
- return i;
-}
-
-static ipx_interface *
-ipxitf_find_using_net(unsigned long net)
-{
- ipx_interface *i;
-
- if (net == 0L)
- return ipx_primary_net;
-
- for (i=ipx_interfaces; i && (i->if_netnum!=net); i=i->if_next)
- ;
-
- return i;
-}
-
-/* Sockets are bound to a particular IPX interface. */
-static void
-ipxitf_insert_socket(ipx_interface *intrfc, ipx_socket *sk)
-{
- ipx_socket *s;
-
- sk->ipx_intrfc = intrfc;
- sk->next = NULL;
- if (intrfc->if_sklist == NULL) {
- intrfc->if_sklist = sk;
- } else {
- for (s = intrfc->if_sklist; s->next != NULL; s = s->next)
- ;
- s->next = sk;
- }
-}
-
-static ipx_socket *
-ipxitf_find_socket(ipx_interface *intrfc, unsigned short port)
-{
- ipx_socket *s;
-
- for (s=intrfc->if_sklist;
- (s != NULL) && (s->ipx_port != port);
- s=s->next)
- ;
-
- return s;
-}
-
-static void ipxrtr_del_routes(ipx_interface *);
-
-static void
-ipxitf_down(ipx_interface *intrfc)
-{
- ipx_interface *i;
- ipx_socket *s, *t;
-
- /* Delete all routes associated with this interface */
- ipxrtr_del_routes(intrfc);
-
- /* error sockets */
- for (s = intrfc->if_sklist; s != NULL; ) {
- s->err = ENOLINK;
- s->error_report(s);
- s->ipx_intrfc = NULL;
- s->ipx_port = 0;
- s->zapped=1; /* Indicates it is no longer bound */
- t = s;
- s = s->next;
- t->next = NULL;
- }
- intrfc->if_sklist = NULL;
-
- /* remove this interface from list */
- if (intrfc == ipx_interfaces) {
- ipx_interfaces = intrfc->if_next;
- } else {
- for (i = ipx_interfaces;
- (i != NULL) && (i->if_next != intrfc);
- i = i->if_next)
- ;
- if ((i != NULL) && (i->if_next == intrfc))
- i->if_next = intrfc->if_next;
- }
-
- /* remove this interface from *special* networks */
- if (intrfc == ipx_primary_net)
- ipxitf_clear_primary_net();
- if (intrfc == ipx_internal_net)
- ipx_internal_net = NULL;
-
- kfree_s(intrfc, sizeof(*intrfc));
-}
-
-static int
-ipxitf_device_event(unsigned long event, void *ptr)
-{
- struct device *dev = ptr;
- ipx_interface *i, *tmp;
-
- if(event!=NETDEV_DOWN)
- return NOTIFY_DONE;
-
- for (i = ipx_interfaces; i != NULL; ) {
-
- tmp = i->if_next;
- if (i->if_dev == dev)
- ipxitf_down(i);
- i = tmp;
-
- }
-
- return NOTIFY_DONE;
-}
-
-static int
-ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb)
-{
- int retval;
-
- if((retval = sock_queue_rcv_skb(sock, skb))<0) {
- /*
- * We do a FREE_WRITE here because this indicates how
- * to treat the socket with which the packet is
- * associated. If this packet is associated with a
- * socket at all, it must be the originator of the
- * packet. Incoming packets will have no socket
- * associated with them at this point.
- */
- kfree_skb(skb,FREE_WRITE);
- }
- return retval;
-}
-
-static int
-ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy)
-{
- ipx_packet *ipx = (ipx_packet *)(skb->h.raw);
- ipx_socket *sock1 = NULL, *sock2 = NULL;
- struct sk_buff *skb1 = NULL, *skb2 = NULL;
- int ipx_offset;
-
- sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock);
-
- /*
- * We need to check if there is a primary net and if
- * this is addressed to one of the *SPECIAL* sockets because
- * these need to be propagated to the primary net.
- * The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and
- * 0x456(Diagnostic).
- */
- if (ipx_primary_net && (intrfc != ipx_primary_net)) {
- switch (ntohs(ipx->ipx_dest.sock)) {
- case 0x452:
- case 0x453:
- case 0x456:
- /*
- * The appropriate thing to do here is to
- * dup the packet and route to the primary net
- * interface via ipxitf_send; however, we'll cheat
- * and just demux it here.
- */
- sock2 = ipxitf_find_socket(ipx_primary_net,
- ipx->ipx_dest.sock);
- break;
- default:
- break;
- }
- }
-
- /* if there is nothing to do, return */
- if ((sock1 == NULL) && (sock2 == NULL)) {
- if (!copy)
- kfree_skb(skb,FREE_WRITE);
- return 0;
- }
-
- ipx_offset = (char *)(skb->h.raw) - (char *)(skb->data);
-
- /* This next segment of code is a little awkward, but it sets it up
- * so that the appropriate number of copies of the SKB are made and
- * that skb1 and skb2 point to it (them) so that it (they) can be
- * demuxed to sock1 and/or sock2. If we are unable to make enough
- * copies, we do as much as is possible.
- */
- if (copy) {
- skb1 = skb_clone(skb, GFP_ATOMIC);
- if (skb1 != NULL) {
- skb1->h.raw = (unsigned char *)&(skb1->data[ipx_offset]);
- skb1->arp = skb1->free = 1;
- }
- } else {
- skb1 = skb;
- }
-
- if (skb1 == NULL) return -ENOMEM;
-
- /* Do we need 2 SKBs? */
- if (sock1 && sock2) {
- skb2 = skb_clone(skb1, GFP_ATOMIC);
- if (skb2 != NULL) {
- skb2->h.raw = (unsigned char *)&(skb2->data[ipx_offset]);
- skb2->arp = skb2->free = 1;
- }
- } else {
- skb2 = skb1;
- }
-
- if (sock1) {
- (void) ipxitf_def_skb_handler(sock1, skb1);
- }
-
- if (skb2 == NULL) return -ENOMEM;
-
- if (sock2) {
- (void) ipxitf_def_skb_handler(sock2, skb2);
- }
-
- return 0;
-}
-
-static struct sk_buff *
-ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buff *skb)
-{
- struct sk_buff *skb2;
- int in_offset = skb->h.raw - skb->data;
- int out_offset = intrfc->if_ipx_offset;
- char *oldraw;
- int len;
-
- /* Hopefully, most cases */
- if (in_offset == out_offset) {
- skb->len += out_offset;
- skb->arp = skb->free = 1;
- return skb;
- }
-
- /* Existing SKB will work, just need to move things around a little */
- if (in_offset > out_offset) {
- oldraw = skb->h.raw;
- skb->h.raw = &(skb->data[out_offset]);
- memmove(skb->h.raw, oldraw, skb->len);
- skb->len += out_offset;
- skb->arp = skb->free = 1;
- return skb;
- }
-
- /* Need new SKB */
- len = skb->len + out_offset;
- skb2 = alloc_skb(len, GFP_ATOMIC);
- if (skb2 != NULL) {
- skb2->h.raw = &(skb2->data[out_offset]);
- skb2->len = len;
- skb2->free=1;
- skb2->arp=1;
- memcpy(skb2->h.raw, skb->h.raw, skb->len);
- }
- kfree_skb(skb, FREE_WRITE);
- return skb2;
-}
-
-static int
-ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
-{
- ipx_packet *ipx = (ipx_packet *)(skb->h.raw);
- struct device *dev = intrfc->if_dev;
- struct datalink_proto *dl = intrfc->if_dlink;
- char dest_node[IPX_NODE_LEN];
- int send_to_wire = 1;
- int addr_len;
-
- /* We need to know how many skbuffs it will take to send out this
- * packet to avoid unnecessary copies.
- */
- if ((dl == NULL) || (dev == NULL) || (dev->flags & IFF_LOOPBACK))
- send_to_wire = 0;
-
- /* See if this should be demuxed to sockets on this interface */
- if (ipx->ipx_dest.net == intrfc->if_netnum) {
- if (memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0)
- return ipxitf_demux_socket(intrfc, skb, 0);
- if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) {
- ipxitf_demux_socket(intrfc, skb, send_to_wire);
- if (!send_to_wire) return 0;
- }
- }
-
- /* if the originating net is not equal to our net; this is routed */
- if (ipx->ipx_source.net != intrfc->if_netnum) {
- if (++(ipx->ipx_tctrl) > ipxcfg_max_hops)
- send_to_wire = 0;
- }
-
- if (!send_to_wire) {
- /*
- * We do a FREE_WRITE here because this indicates how
- * to treat the socket with which the packet is
- * associated. If this packet is associated with a
- * socket at all, it must be the originator of the
- * packet. Routed packets will have no socket associated
- * with them.
- */
- kfree_skb(skb,FREE_WRITE);
- return 0;
- }
-
- /* determine the appropriate hardware address */
- addr_len = dev->addr_len;
- if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) {
- memcpy(dest_node, dev->broadcast, addr_len);
- } else {
- memcpy(dest_node, &(node[IPX_NODE_LEN-addr_len]), addr_len);
- }
-
- /* make any compensation for differing physical/data link size */
- skb = ipxitf_adjust_skbuff(intrfc, skb);
- if (skb == NULL) return 0;
-
- /* set up data link and physical headers */
- skb->dev = dev;
- dl->datalink_header(dl, skb, dest_node);
-
- if (skb->sk != NULL) {
- /* This is an outbound packet from this host. We need to
- * increment the write count.
- */
- skb->sk->wmem_alloc += skb->mem_len;
- }
-
- /* Send it out */
- dev_queue_xmit(skb, dev, SOPRI_NORMAL);
- return 0;
-}
-
-static int
-ipxrtr_add_route(unsigned long, ipx_interface *, unsigned char *);
-
-static int
-ipxitf_add_local_route(ipx_interface *intrfc)
-{
- return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL);
-}
-
-static char * ipx_frame_name(unsigned short);
-static char * ipx_device_name(ipx_interface *);
-static int ipxrtr_route_skb(struct sk_buff *);
-
-static int
-ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
-{
- ipx_packet *ipx = (ipx_packet *) (skb->h.raw);
- ipx_interface *i;
-
- /* See if we should update our network number */
- if ((intrfc->if_netnum == 0L) &&
- (ipx->ipx_source.net == ipx->ipx_dest.net) &&
- (ipx->ipx_source.net != 0L)) {
- /* NB: NetWare servers lie about their hop count so we
- * dropped the test based on it. This is the best way
- * to determine this is a 0 hop count packet.
- */
- if ((i=ipxitf_find_using_net(ipx->ipx_source.net))==NULL) {
- intrfc->if_netnum = ipx->ipx_source.net;
- (void) ipxitf_add_local_route(intrfc);
- } else {
- printk("IPX: Network number collision %lx\n\t%s %s and %s %s\n",
- htonl(ipx->ipx_source.net),
- ipx_device_name(i),
- ipx_frame_name(i->if_dlink_type),
- ipx_device_name(intrfc),
- ipx_frame_name(intrfc->if_dlink_type));
- }
- }
-
- if (ipx->ipx_dest.net == 0L)
- ipx->ipx_dest.net = intrfc->if_netnum;
- if (ipx->ipx_source.net == 0L)
- ipx->ipx_source.net = intrfc->if_netnum;
-
- if (intrfc->if_netnum != ipx->ipx_dest.net) {
- /* We only route point-to-point packets. */
- if ((skb->pkt_type != PACKET_BROADCAST) &&
- (skb->pkt_type != PACKET_MULTICAST))
- return ipxrtr_route_skb(skb);
-
- kfree_skb(skb,FREE_READ);
- return 0;
- }
-
- /* see if we should keep it */
- if ((memcmp(ipx_broadcast_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0)
- || (memcmp(intrfc->if_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0)) {
- return ipxitf_demux_socket(intrfc, skb, 0);
- }
-
- /* we couldn't pawn it off so unload it */
- kfree_skb(skb,FREE_READ);
- return 0;
-}
-
-static void
-ipxitf_insert(ipx_interface *intrfc)
-{
- ipx_interface *i;
-
- intrfc->if_next = NULL;
- if (ipx_interfaces == NULL) {
- ipx_interfaces = intrfc;
- } else {
- for (i = ipx_interfaces; i->if_next != NULL; i = i->if_next)
- ;
- i->if_next = intrfc;
- }
-
- if (ipxcfg_auto_select_primary && (ipx_primary_net == NULL))
- ipx_primary_net = intrfc;
-}
-
-static int
-ipxitf_create_internal(ipx_interface_definition *idef)
-{
- ipx_interface *intrfc;
-
- /* Only one primary network allowed */
- if (ipx_primary_net != NULL) return -EEXIST;
-
- /* Must have a valid network number */
- if (idef->ipx_network == 0L) return -EADDRNOTAVAIL;
- if (ipxitf_find_using_net(idef->ipx_network) != NULL)
- return -EADDRINUSE;
-
- intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
- if (intrfc==NULL)
- return -EAGAIN;
- intrfc->if_dev=NULL;
- intrfc->if_netnum=idef->ipx_network;
- intrfc->if_dlink_type = 0;
- intrfc->if_dlink = NULL;
- intrfc->if_sklist = NULL;
- intrfc->if_internal = 1;
- intrfc->if_ipx_offset = 0;
- intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
- memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN);
- ipx_internal_net = intrfc;
- ipx_primary_net = intrfc;
- ipxitf_insert(intrfc);
- return ipxitf_add_local_route(intrfc);
-}
-
-static int
-ipx_map_frame_type(unsigned char type)
-{
- switch (type) {
- case IPX_FRAME_ETHERII: return htons(ETH_P_IPX);
- case IPX_FRAME_8022: return htons(ETH_P_802_2);
- case IPX_FRAME_SNAP: return htons(ETH_P_SNAP);
- case IPX_FRAME_8023: return htons(ETH_P_802_3);
- }
- return 0;
-}
-
-static int
-ipxitf_create(ipx_interface_definition *idef)
-{
- struct device *dev;
- unsigned short dlink_type = 0;
- struct datalink_proto *datalink = NULL;
- ipx_interface *intrfc;
-
- if (idef->ipx_special == IPX_INTERNAL)
- return ipxitf_create_internal(idef);
-
- if ((idef->ipx_special == IPX_PRIMARY) && (ipx_primary_net != NULL))
- return -EEXIST;
-
- if ((idef->ipx_network != 0L) &&
- (ipxitf_find_using_net(idef->ipx_network) != NULL))
- return -EADDRINUSE;
-
- switch (idef->ipx_dlink_type) {
- case IPX_FRAME_ETHERII:
- dlink_type = htons(ETH_P_IPX);
- datalink = pEII_datalink;
- break;
- case IPX_FRAME_8022:
- dlink_type = htons(ETH_P_802_2);
- datalink = p8022_datalink;
- break;
- case IPX_FRAME_SNAP:
- dlink_type = htons(ETH_P_SNAP);
- datalink = pSNAP_datalink;
- break;
- case IPX_FRAME_8023:
- dlink_type = htons(ETH_P_802_3);
- datalink = p8023_datalink;
- break;
- case IPX_FRAME_NONE:
- default:
- break;
- }
-
- if (datalink == NULL)
- return -EPROTONOSUPPORT;
-
- dev=dev_get(idef->ipx_device);
- if (dev==NULL)
- return -ENODEV;
-
- if (!(dev->flags & IFF_UP))
- return -ENETDOWN;
-
- /* Check addresses are suitable */
- if(dev->addr_len>IPX_NODE_LEN)
- return -EINVAL;
-
- if ((intrfc = ipxitf_find_using_phys(dev, dlink_type)) == NULL) {
-
- /* Ok now create */
- intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
- if (intrfc==NULL)
- return -EAGAIN;
- intrfc->if_dev=dev;
- intrfc->if_netnum=idef->ipx_network;
- intrfc->if_dlink_type = dlink_type;
- intrfc->if_dlink = datalink;
- intrfc->if_sklist = NULL;
- intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
- /* Setup primary if necessary */
- if ((idef->ipx_special == IPX_PRIMARY))
- ipx_primary_net = intrfc;
- intrfc->if_internal = 0;
- intrfc->if_ipx_offset = dev->hard_header_len + datalink->header_length;
- memset(intrfc->if_node, 0, IPX_NODE_LEN);
- memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]), dev->dev_addr, dev->addr_len);
-
- ipxitf_insert(intrfc);
- }
-
- /* If the network number is known, add a route */
- if (intrfc->if_netnum == 0L)
- return 0;
-
- return ipxitf_add_local_route(intrfc);
-}
-
-static int
-ipxitf_delete(ipx_interface_definition *idef)
-{
- struct device *dev = NULL;
- unsigned short dlink_type = 0;
- ipx_interface *intrfc;
-
- if (idef->ipx_special == IPX_INTERNAL) {
- if (ipx_internal_net != NULL) {
- ipxitf_down(ipx_internal_net);
- return 0;
- }
- return -ENOENT;
- }
-
- dlink_type = ipx_map_frame_type(idef->ipx_dlink_type);
- if (dlink_type == 0)
- return -EPROTONOSUPPORT;
-
- dev=dev_get(idef->ipx_device);
- if(dev==NULL) return -ENODEV;
-
- intrfc = ipxitf_find_using_phys(dev, dlink_type);
- if (intrfc != NULL) {
- ipxitf_down(intrfc);
- return 0;
- }
- return -EINVAL;
-}
-
-static ipx_interface *
-ipxitf_auto_create(struct device *dev, unsigned short dlink_type)
-{
- struct datalink_proto *datalink = NULL;
- ipx_interface *intrfc;
-
- switch (htons(dlink_type)) {
- case ETH_P_IPX: datalink = pEII_datalink; break;
- case ETH_P_802_2: datalink = p8022_datalink; break;
- case ETH_P_SNAP: datalink = pSNAP_datalink; break;
- case ETH_P_802_3: datalink = p8023_datalink; break;
- default: return NULL;
- }
-
- if (dev == NULL)
- return NULL;
-
- /* Check addresses are suitable */
- if(dev->addr_len>IPX_NODE_LEN) return NULL;
-
- intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
- if (intrfc!=NULL) {
- intrfc->if_dev=dev;
- intrfc->if_netnum=0L;
- intrfc->if_dlink_type = dlink_type;
- intrfc->if_dlink = datalink;
- intrfc->if_sklist = NULL;
- intrfc->if_internal = 0;
- intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
- intrfc->if_ipx_offset = dev->hard_header_len +
- datalink->header_length;
- memset(intrfc->if_node, 0, IPX_NODE_LEN);
- memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]),
- dev->dev_addr, dev->addr_len);
- ipxitf_insert(intrfc);
- }
-
- return intrfc;
-}
-
-static int
-ipxitf_ioctl(unsigned int cmd, void *arg)
-{
- int err;
- switch(cmd)
- {
- case SIOCSIFADDR:
- {
- struct ifreq ifr;
- struct sockaddr_ipx *sipx;
- ipx_interface_definition f;
- err=verify_area(VERIFY_READ,arg,sizeof(ifr));
- if(err)
- return err;
- memcpy_fromfs(&ifr,arg,sizeof(ifr));
- sipx=(struct sockaddr_ipx *)&ifr.ifr_addr;
- if(sipx->sipx_family!=AF_IPX)
- return -EINVAL;
- f.ipx_network=sipx->sipx_network;
- memcpy(f.ipx_device, ifr.ifr_name, sizeof(f.ipx_device));
- memcpy(f.ipx_node, sipx->sipx_node, IPX_NODE_LEN);
- f.ipx_dlink_type=sipx->sipx_type;
- f.ipx_special=sipx->sipx_special;
- if(sipx->sipx_action==IPX_DLTITF)
- return ipxitf_delete(&f);
- else
- return ipxitf_create(&f);
- }
- case SIOCGIFADDR:
- {
- struct ifreq ifr;
- struct sockaddr_ipx *sipx;
- ipx_interface *ipxif;
- struct device *dev;
- err=verify_area(VERIFY_WRITE,arg,sizeof(ifr));
- if(err)
- return err;
- memcpy_fromfs(&ifr,arg,sizeof(ifr));
- sipx=(struct sockaddr_ipx *)&ifr.ifr_addr;
- dev=dev_get(ifr.ifr_name);
- if(!dev)
- return -ENODEV;
- ipxif=ipxitf_find_using_phys(dev, ipx_map_frame_type(sipx->sipx_type));
- if(ipxif==NULL)
- return -EADDRNOTAVAIL;
- sipx->sipx_network=ipxif->if_netnum;
- memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node));
- memcpy_tofs(arg,&ifr,sizeof(ifr));
- return 0;
- }
- case SIOCAIPXITFCRT:
- err=verify_area(VERIFY_READ,arg,sizeof(char));
- if(err)
- return err;
- return ipxcfg_set_auto_create(get_fs_byte(arg));
- case SIOCAIPXPRISLT:
- err=verify_area(VERIFY_READ,arg,sizeof(char));
- if(err)
- return err;
- return ipxcfg_set_auto_select(get_fs_byte(arg));
- default:
- return -EINVAL;
- }
-}
-
-/*******************************************************************************************************************\
-* *
-* Routing tables for the IPX socket layer *
-* *
-\*******************************************************************************************************************/
-
-static ipx_route *
-ipxrtr_lookup(unsigned long net)
-{
- ipx_route *r;
-
- for (r=ipx_routes; (r!=NULL) && (r->ir_net!=net); r=r->ir_next)
- ;
-
- return r;
-}
-
-static int
-ipxrtr_add_route(unsigned long network, ipx_interface *intrfc, unsigned char *node)
-{
- ipx_route *rt;
-
- /* Get a route structure; either existing or create */
- rt = ipxrtr_lookup(network);
- if (rt==NULL) {
- rt=(ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC);
- if(rt==NULL)
- return -EAGAIN;
- rt->ir_next=ipx_routes;
- ipx_routes=rt;
- }
-
- rt->ir_net = network;
- rt->ir_intrfc = intrfc;
- if (node == NULL) {
- memset(rt->ir_router_node, '\0', IPX_NODE_LEN);
- rt->ir_routed = 0;
- } else {
- memcpy(rt->ir_router_node, node, IPX_NODE_LEN);
- rt->ir_routed=1;
- }
- return 0;
-}
-
-static void
-ipxrtr_del_routes(ipx_interface *intrfc)
-{
- ipx_route **r, *tmp;
-
- for (r = &ipx_routes; (tmp = *r) != NULL; ) {
- if (tmp->ir_intrfc == intrfc) {
- *r = tmp->ir_next;
- kfree_s(tmp, sizeof(ipx_route));
- } else {
- r = &(tmp->ir_next);
- }
- }
-}
-
-static int
-ipxrtr_create(ipx_route_definition *rd)
-{
- ipx_interface *intrfc;
-
- /* Find the appropriate interface */
- intrfc = ipxitf_find_using_net(rd->ipx_router_network);
- if (intrfc == NULL)
- return -ENETUNREACH;
-
- return ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node);
-}
-
-
-static int
-ipxrtr_delete(long net)
-{
- ipx_route **r;
- ipx_route *tmp;
-
- for (r = &ipx_routes; (tmp = *r) != NULL; ) {
- if (tmp->ir_net == net) {
- if (!(tmp->ir_routed)) {
- /* Directly connected; can't lose route */
- return -EPERM;
- }
- *r = tmp->ir_next;
- kfree_s(tmp, sizeof(ipx_route));
- return 0;
- }
- r = &(tmp->ir_next);
- }
-
- return -ENOENT;
-}
-
-static int
-ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, void *ubuf, int len)
-{
- struct sk_buff *skb;
- ipx_interface *intrfc;
- ipx_packet *ipx;
- int size;
- int ipx_offset;
- ipx_route *rt = NULL;
-
- /* Find the appropriate interface on which to send packet */
- if ((usipx->sipx_network == 0L) && (ipx_primary_net != NULL)) {
- usipx->sipx_network = ipx_primary_net->if_netnum;
- intrfc = ipx_primary_net;
- } else {
- rt = ipxrtr_lookup(usipx->sipx_network);
- if (rt==NULL) {
- return -ENETUNREACH;
- }
- intrfc = rt->ir_intrfc;
- }
-
- ipx_offset = intrfc->if_ipx_offset;
- size=sizeof(ipx_packet)+len;
- size += ipx_offset;
-
- if(size+sk->wmem_alloc>sk->sndbuf) return -EAGAIN;
-
- skb=alloc_skb(size,GFP_KERNEL);
- if(skb==NULL) return -ENOMEM;
-
- skb->sk=sk;
- skb->len=size;
- skb->free=1;
- skb->arp=1;
-
- /* Fill in IPX header */
- ipx=(ipx_packet *)&(skb->data[ipx_offset]);
- ipx->ipx_checksum=0xFFFF;
- ipx->ipx_pktsize=htons(len+sizeof(ipx_packet));
- ipx->ipx_tctrl=0;
- ipx->ipx_type=usipx->sipx_type;
- skb->h.raw = (unsigned char *)ipx;
-
- ipx->ipx_source.net = sk->ipx_intrfc->if_netnum;
- memcpy(ipx->ipx_source.node, sk->ipx_intrfc->if_node, IPX_NODE_LEN);
- ipx->ipx_source.sock = sk->ipx_port;
- ipx->ipx_dest.net=usipx->sipx_network;
- memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN);
- ipx->ipx_dest.sock=usipx->sipx_port;
-
- memcpy_fromfs((char *)(ipx+1),ubuf,len);
- return ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ?
- rt->ir_router_node : ipx->ipx_dest.node);
-}
-
-static int
-ipxrtr_route_skb(struct sk_buff *skb)
-{
- ipx_packet *ipx = (ipx_packet *) (skb->h.raw);
- ipx_route *r;
- ipx_interface *i;
-
- r = ipxrtr_lookup(ipx->ipx_dest.net);
- if (r == NULL) {
- /* no known route */
- kfree_skb(skb,FREE_READ);
- return 0;
- }
- i = r->ir_intrfc;
- (void)ipxitf_send(i, skb, (r->ir_routed) ?
- r->ir_router_node : ipx->ipx_dest.node);
- return 0;
-}
-
-/*
- * We use a normal struct rtentry for route handling
- */
-
-static int ipxrtr_ioctl(unsigned int cmd, void *arg)
-{
- int err;
- struct rtentry rt; /* Use these to behave like 'other' stacks */
- struct sockaddr_ipx *sg,*st;
-
- err=verify_area(VERIFY_READ,arg,sizeof(rt));
- if(err)
- return err;
-
- memcpy_fromfs(&rt,arg,sizeof(rt));
-
- sg=(struct sockaddr_ipx *)&rt.rt_gateway;
- st=(struct sockaddr_ipx *)&rt.rt_dst;
-
- if(!(rt.rt_flags&RTF_GATEWAY))
- return -EINVAL; /* Direct routes are fixed */
- if(sg->sipx_family!=AF_IPX)
- return -EINVAL;
- if(st->sipx_family!=AF_IPX)
- return -EINVAL;
-
- switch(cmd)
- {
- case SIOCDELRT:
- return ipxrtr_delete(st->sipx_network);
- case SIOCADDRT:
- {
- struct ipx_route_definition f;
- f.ipx_network=st->sipx_network;
- f.ipx_router_network=sg->sipx_network;
- memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN);
- return ipxrtr_create(&f);
- }
- default:
- return -EINVAL;
- }
-}
-
-static char *
-ipx_frame_name(unsigned short frame)
-{
- switch (ntohs(frame)) {
- case ETH_P_IPX: return "EtherII";
- case ETH_P_802_2: return "802.2";
- case ETH_P_SNAP: return "SNAP";
- case ETH_P_802_3: return "802.3";
- default: return "None";
- }
-}
-
-static char *
-ipx_device_name(ipx_interface *intrfc)
-{
- return (intrfc->if_internal ? "Internal" :
- (intrfc->if_dev ? intrfc->if_dev->name : "Unknown"));
-}
-
-/* Called from proc fs */
-int
-ipx_get_interface_info(char *buffer, char **start, off_t offset, int length)
-{
- ipx_interface *i;
- int len=0;
- off_t pos=0;
- off_t begin=0;
-
- /* Theory.. Keep printing in the same place until we pass offset */
-
- len += sprintf (buffer,"%-11s%-15s%-9s%-11s%s\n", "Network",
- "Node_Address", "Primary", "Device", "Frame_Type");
- for (i = ipx_interfaces; i != NULL; i = i->if_next) {
- len += sprintf(buffer+len, "%08lX ", ntohl(i->if_netnum));
- len += sprintf (buffer+len,"%02X%02X%02X%02X%02X%02X ",
- i->if_node[0], i->if_node[1], i->if_node[2],
- i->if_node[3], i->if_node[4], i->if_node[5]);
- len += sprintf(buffer+len, "%-9s", (i == ipx_primary_net) ?
- "Yes" : "No");
- len += sprintf (buffer+len, "%-11s", ipx_device_name(i));
- len += sprintf (buffer+len, "%s\n",
- ipx_frame_name(i->if_dlink_type));
-
- /* Are we still dumping unwanted data then discard the record */
- pos=begin+len;
-
- if(pos<offset) {
- len=0; /* Keep dumping into the buffer start */
- begin=pos;
- }
- if(pos>offset+length) /* We have dumped enough */
- break;
- }
-
- /* The data in question runs from begin to begin+len */
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Remove unwanted header data from length */
- if(len>length)
- len=length; /* Remove unwanted tail data from length */
-
- return len;
-}
-
-int
-ipx_get_info(char *buffer, char **start, off_t offset, int length)
-{
- ipx_socket *s;
- ipx_interface *i;
- int len=0;
- off_t pos=0;
- off_t begin=0;
-
- /* Theory.. Keep printing in the same place until we pass offset */
-
- len += sprintf (buffer,"%-15s%-28s%-10s%-10s%-7s%s\n", "Local_Address",
- "Remote_Address", "Tx_Queue", "Rx_Queue",
- "State", "Uid");
- for (i = ipx_interfaces; i != NULL; i = i->if_next) {
- for (s = i->if_sklist; s != NULL; s = s->next) {
- len += sprintf (buffer+len,"%08lX:%04X ",
- htonl(i->if_netnum),
- htons(s->ipx_port));
- if (s->state!=TCP_ESTABLISHED) {
- len += sprintf(buffer+len, "%-28s", "Not_Connected");
- } else {
- len += sprintf (buffer+len,
- "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
- htonl(s->ipx_dest_addr.net),
- s->ipx_dest_addr.node[0], s->ipx_dest_addr.node[1],
- s->ipx_dest_addr.node[2], s->ipx_dest_addr.node[3],
- s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5],
- htons(s->ipx_dest_addr.sock));
- }
- len += sprintf (buffer+len,"%08lX %08lX ",
- s->wmem_alloc, s->rmem_alloc);
- len += sprintf (buffer+len,"%02X %03d\n",
- s->state, SOCK_INODE(s->socket)->i_uid);
-
- /* Are we still dumping unwanted data then discard the record */
- pos=begin+len;
-
- if(pos<offset)
- {
- len=0; /* Keep dumping into the buffer start */
- begin=pos;
- }
- if(pos>offset+length) /* We have dumped enough */
- break;
- }
- }
-
- /* The data in question runs from begin to begin+len */
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Remove unwanted header data from length */
- if(len>length)
- len=length; /* Remove unwanted tail data from length */
-
- return len;
-}
-
-int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length)
-{
- ipx_route *rt;
- int len=0;
- off_t pos=0;
- off_t begin=0;
-
- len += sprintf (buffer,"%-11s%-13s%s\n",
- "Network", "Router_Net", "Router_Node");
- for (rt = ipx_routes; rt != NULL; rt = rt->ir_next)
- {
- len += sprintf (buffer+len,"%08lX ", ntohl(rt->ir_net));
- if (rt->ir_routed) {
- len += sprintf (buffer+len,"%08lX %02X%02X%02X%02X%02X%02X\n",
- ntohl(rt->ir_intrfc->if_netnum),
- rt->ir_router_node[0], rt->ir_router_node[1],
- rt->ir_router_node[2], rt->ir_router_node[3],
- rt->ir_router_node[4], rt->ir_router_node[5]);
- } else {
- len += sprintf (buffer+len, "%-13s%s\n",
- "Directly", "Connected");
- }
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
- }
- *start=buffer+(offset-begin);
- len-=(offset-begin);
- if(len>length)
- len=length;
- return len;
-}
-
-/*******************************************************************************************************************\
-* *
-* Handling for system calls applied via the various interfaces to an IPX socket object *
-* *
-\*******************************************************************************************************************/
-
-static int ipx_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- switch(cmd)
- {
- default:
- return(-EINVAL);
- }
-}
-
-static int ipx_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-{
- ipx_socket *sk;
- int err,opt;
-
- sk=(ipx_socket *)sock->data;
-
- if(optval==NULL)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ,optval,sizeof(int));
- if(err)
- return err;
- opt=get_fs_long((unsigned long *)optval);
-
- switch(level)
- {
- case SOL_IPX:
- switch(optname)
- {
- case IPX_TYPE:
- sk->ipx_type=opt;
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- break;
-
- case SOL_SOCKET:
- return sock_setsockopt(sk,level,optname,optval,optlen);
-
- default:
- return -EOPNOTSUPP;
- }
-}
-
-static int ipx_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- ipx_socket *sk;
- int val=0;
- int err;
-
- sk=(ipx_socket *)sock->data;
-
- switch(level)
- {
-
- case SOL_IPX:
- switch(optname)
- {
- case IPX_TYPE:
- val=sk->ipx_type;
- break;
- default:
- return -ENOPROTOOPT;
- }
- break;
-
- case SOL_SOCKET:
- return sock_getsockopt(sk,level,optname,optval,optlen);
-
- default:
- return -EOPNOTSUPP;
- }
- err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(int),(unsigned long *)optlen);
- err=verify_area(VERIFY_WRITE,optval,sizeof(int));
- put_fs_long(val,(unsigned long *)optval);
- return(0);
-}
-
-static int ipx_listen(struct socket *sock, int backlog)
-{
- return -EOPNOTSUPP;
-}
-
-static void def_callback1(struct sock *sk)
-{
- if(!sk->dead)
- wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
- if(!sk->dead)
- {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 1);
- }
-}
-
-static int
-ipx_create(struct socket *sock, int protocol)
-{
- ipx_socket *sk;
- sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
- if(sk==NULL)
- return(-ENOMEM);
- switch(sock->type)
- {
- case SOCK_DGRAM:
- break;
- default:
- kfree_s((void *)sk,sizeof(*sk));
- return(-ESOCKTNOSUPPORT);
- }
- sk->dead=0;
- sk->next=NULL;
- sk->broadcast=0;
- sk->rcvbuf=SK_RMEM_MAX;
- sk->sndbuf=SK_WMEM_MAX;
- sk->wmem_alloc=0;
- sk->rmem_alloc=0;
- sk->inuse=0;
- sk->shutdown=0;
- sk->prot=NULL; /* So we use default free mechanisms */
- sk->broadcast=0;
- sk->err=0;
- skb_queue_head_init(&sk->receive_queue);
- skb_queue_head_init(&sk->write_queue);
- sk->send_head=NULL;
- skb_queue_head_init(&sk->back_log);
- sk->state=TCP_CLOSE;
- sk->socket=sock;
- sk->type=sock->type;
- sk->ipx_type=0; /* General user level IPX */
- sk->debug=0;
- sk->ipx_intrfc = NULL;
- memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr));
- sk->ipx_port = 0;
- sk->mtu=IPX_MTU;
-
- if(sock!=NULL)
- {
- sock->data=(void *)sk;
- sk->sleep=sock->wait;
- }
-
- sk->state_change=def_callback1;
- sk->data_ready=def_callback2;
- sk->write_space=def_callback1;
- sk->error_report=def_callback1;
-
- sk->zapped=1;
- return 0;
-}
-
-static int ipx_release(struct socket *sock, struct socket *peer)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- if(sk==NULL)
- return(0);
- if(!sk->dead)
- sk->state_change(sk);
- sk->dead=1;
- sock->data=NULL;
- ipx_destroy_socket(sk);
- return(0);
-}
-
-static int ipx_dup(struct socket *newsock,struct socket *oldsock)
-{
- return(ipx_create(newsock,SOCK_DGRAM));
-}
-
-static unsigned short
-ipx_first_free_socketnum(ipx_interface *intrfc)
-{
- unsigned short socketNum = intrfc->if_sknum;
-
- if (socketNum < IPX_MIN_EPHEMERAL_SOCKET)
- socketNum = IPX_MIN_EPHEMERAL_SOCKET;
-
- while (ipxitf_find_socket(intrfc, ntohs(socketNum)) != NULL)
- if (socketNum > IPX_MAX_EPHEMERAL_SOCKET)
- socketNum = IPX_MIN_EPHEMERAL_SOCKET;
- else
- socketNum++;
-
- intrfc->if_sknum = socketNum;
- return ntohs(socketNum);
-}
-
-static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
-{
- ipx_socket *sk;
- ipx_interface *intrfc;
- struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
-
- sk=(ipx_socket *)sock->data;
-
- if(sk->zapped==0)
- return -EIO;
-
- if(addr_len!=sizeof(struct sockaddr_ipx))
- return -EINVAL;
-
- intrfc = ipxitf_find_using_net(addr->sipx_network);
- if (intrfc == NULL)
- return -EADDRNOTAVAIL;
-
- if (addr->sipx_port == 0) {
- addr->sipx_port = ipx_first_free_socketnum(intrfc);
- if (addr->sipx_port == 0)
- return -EINVAL;
- }
-
- if(ntohs(addr->sipx_port)<IPX_MIN_EPHEMERAL_SOCKET && !suser())
- return -EPERM; /* protect IPX system stuff like routing/sap */
-
- /* Source addresses are easy. It must be our network:node pair for
- an interface routed to IPX with the ipx routing ioctl() */
-
- if(ipxitf_find_socket(intrfc, addr->sipx_port)!=NULL) {
- if(sk->debug)
- printk("IPX: bind failed because port %X in use.\n",
- (int)addr->sipx_port);
- return -EADDRINUSE;
- }
-
- sk->ipx_port=addr->sipx_port;
- ipxitf_insert_socket(intrfc, sk);
- sk->zapped=0;
- if(sk->debug)
- printk("IPX: socket is bound.\n");
- return 0;
-}
-
-static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
- int addr_len, int flags)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- struct sockaddr_ipx *addr;
-
- sk->state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
-
- if(addr_len!=sizeof(*addr))
- return(-EINVAL);
- addr=(struct sockaddr_ipx *)uaddr;
-
- if(sk->ipx_port==0)
- /* put the autobinding in */
- {
- struct sockaddr_ipx uaddr;
- int ret;
-
- uaddr.sipx_port = 0;
- uaddr.sipx_network = 0L;
- ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
- if (ret != 0) return (ret);
- }
-
- if(ipxrtr_lookup(addr->sipx_network)==NULL)
- return -ENETUNREACH;
- sk->ipx_dest_addr.net=addr->sipx_network;
- sk->ipx_dest_addr.sock=addr->sipx_port;
- memcpy(sk->ipx_dest_addr.node,addr->sipx_node,IPX_NODE_LEN);
- sk->ipx_type=addr->sipx_type;
- sock->state = SS_CONNECTED;
- sk->state=TCP_ESTABLISHED;
- return 0;
-}
-
-static int ipx_socketpair(struct socket *sock1, struct socket *sock2)
-{
- return(-EOPNOTSUPP);
-}
-
-static int ipx_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- if(newsock->data)
- kfree_s(newsock->data,sizeof(ipx_socket));
- return -EOPNOTSUPP;
-}
-
-static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
-{
- ipx_address *addr;
- struct sockaddr_ipx sipx;
- ipx_socket *sk;
-
- sk=(ipx_socket *)sock->data;
-
- *uaddr_len = sizeof(struct sockaddr_ipx);
-
- if(peer) {
- if(sk->state!=TCP_ESTABLISHED)
- return -ENOTCONN;
- addr=&sk->ipx_dest_addr;
- sipx.sipx_network = addr->net;
- memcpy(sipx.sipx_node,addr->node,IPX_NODE_LEN);
- sipx.sipx_port = addr->sock;
- } else {
- if (sk->ipx_intrfc != NULL) {
- sipx.sipx_network = sk->ipx_intrfc->if_netnum;
- memcpy(sipx.sipx_node, sk->ipx_intrfc->if_node,
- IPX_NODE_LEN);
- } else {
- sipx.sipx_network = 0L;
- memset(sipx.sipx_node, '\0', IPX_NODE_LEN);
- }
- sipx.sipx_port = sk->ipx_port;
- }
-
- sipx.sipx_family = AF_IPX;
- sipx.sipx_type = sk->ipx_type;
- memcpy(uaddr,&sipx,sizeof(sipx));
- return 0;
-}
-
-#if 0
-/*
- * User to dump IPX packets (debugging)
- */
-void dump_data(char *str,unsigned char *d) {
- static char h2c[] = "0123456789ABCDEF";
- int l,i;
- char *p, b[64];
- for (l=0;l<16;l++) {
- p = b;
- for (i=0; i < 8 ; i++) {
- *(p++) = h2c[d[i] & 0x0f];
- *(p++) = h2c[(d[i] >> 4) & 0x0f];
- *(p++) = ' ';
- }
- *(p++) = '-';
- *(p++) = ' ';
- for (i=0; i < 8 ; i++) *(p++) = ' '<= d[i] && d[i]<'\177' ? d[i] : '.';
- *p = '\000';
- d += i;
- printk("%s-%04X: %s\n",str,l*8,b);
- }
-}
-
-void dump_addr(char *str,ipx_address *p) {
- printk("%s: %08X:%02X%02X%02X%02X%02X%02X:%04X\n",
- str,ntohl(p->net),p->node[0],p->node[1],p->node[2],
- p->node[3],p->node[4],p->node[5],ntohs(p->sock));
-}
-
-void dump_hdr(char *str,ipx_packet *p) {
- printk("%s: CHKSUM=%04X SIZE=%d (%04X) HOPS=%d (%02X) TYPE=%02X\n",
- str,p->ipx_checksum,ntohs(p->ipx_pktsize),ntohs(p->ipx_pktsize),
- p->ipx_tctrl,p->ipx_tctrl,p->ipx_type);
- dump_addr(" IPX-DST",&p->ipx_dest);
- dump_addr(" IPX-SRC",&p->ipx_source);
-}
-
-void dump_pkt(char *str,ipx_packet *p) {
- dump_hdr(str,p);
- dump_data(str,(unsigned char *)p);
-}
-#endif
-
-int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
- /* NULL here for pt means the packet was looped back */
- ipx_interface *intrfc;
- ipx_packet *ipx;
-
- ipx=(ipx_packet *)skb->h.raw;
-
- if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) {
- /* We don't do checksum options. We can't really. Novell don't seem to have documented them.
- If you need them try the XNS checksum since IPX is basically XNS in disguise. It might be
- the same... */
- kfree_skb(skb,FREE_READ);
- return 0;
- }
-
- /* Too small */
- if(htons(ipx->ipx_pktsize)<sizeof(ipx_packet)) {
- kfree_skb(skb,FREE_READ);
- return 0;
- }
-
- /* Determine what local ipx endpoint this is */
- intrfc = ipxitf_find_using_phys(dev, pt->type);
- if (intrfc == NULL) {
- if (ipxcfg_auto_create_interfaces) {
- intrfc = ipxitf_auto_create(dev, pt->type);
- }
-
- if (intrfc == NULL) {
- /* Not one of ours */
- kfree_skb(skb,FREE_READ);
- return 0;
- }
- }
-
- return ipxitf_rcv(intrfc, skb);
-}
-
-static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
- unsigned flags, struct sockaddr *usip, int addr_len)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
- struct sockaddr_ipx local_sipx;
- int retval;
-
- if (sk->zapped) return -EIO; /* Socket not bound */
- if(flags) return -EINVAL;
-
- if(usipx) {
- if(sk->ipx_port == 0) {
- struct sockaddr_ipx uaddr;
- int ret;
-
- uaddr.sipx_port = 0;
- uaddr.sipx_network = 0L;
- ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
- if (ret != 0) return ret;
- }
-
- if(addr_len <sizeof(*usipx))
- return -EINVAL;
- if(usipx->sipx_family != AF_IPX)
- return -EINVAL;
- } else {
- if(sk->state!=TCP_ESTABLISHED)
- return -ENOTCONN;
- usipx=&local_sipx;
- usipx->sipx_family=AF_IPX;
- usipx->sipx_type=sk->ipx_type;
- usipx->sipx_port=sk->ipx_dest_addr.sock;
- usipx->sipx_network=sk->ipx_dest_addr.net;
- memcpy(usipx->sipx_node,sk->ipx_dest_addr.node,IPX_NODE_LEN);
- }
-
- retval = ipxrtr_route_packet(sk, usipx, ubuf, len);
- if (retval < 0) return retval;
-
- return len;
-}
-
-static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
-{
- return ipx_sendto(sock,ubuf,size,noblock,flags,NULL,0);
-}
-
-static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sip, int *addr_len)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- struct sockaddr_ipx *sipx=(struct sockaddr_ipx *)sip;
- struct ipx_packet *ipx = NULL;
- int copied = 0;
- int truesize;
- struct sk_buff *skb;
- int er;
-
- if(sk->err)
- {
- er= -sk->err;
- sk->err=0;
- return er;
- }
-
- if (sk->zapped)
- return -EIO;
-
- if(addr_len)
- *addr_len=sizeof(*sipx);
-
- skb=skb_recv_datagram(sk,flags,noblock,&er);
- if(skb==NULL)
- return er;
-
- ipx = (ipx_packet *)(skb->h.raw);
- truesize=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet);
- copied = (truesize > size) ? size : truesize;
- skb_copy_datagram(skb,sizeof(struct ipx_packet),ubuf,copied);
-
- if(sipx)
- {
- sipx->sipx_family=AF_IPX;
- sipx->sipx_port=ipx->ipx_source.sock;
- memcpy(sipx->sipx_node,ipx->ipx_source.node,IPX_NODE_LEN);
- sipx->sipx_network=ipx->ipx_source.net;
- sipx->sipx_type = ipx->ipx_type;
- }
- skb_free_datagram(skb);
- return(truesize);
-}
-
-static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock)
-{
- return ipx_send(sock,ubuf,size,noblock,0);
-}
-
-
-static int ipx_recv(struct socket *sock, void *ubuf, int size , int noblock,
- unsigned flags)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- if(sk->zapped)
- return -ENOTCONN;
- return ipx_recvfrom(sock,ubuf,size,noblock,flags,NULL, NULL);
-}
-
-static int ipx_read(struct socket *sock, char *ubuf, int size, int noblock)
-{
- return ipx_recv(sock,ubuf,size,noblock,0);
-}
-
-
-static int ipx_shutdown(struct socket *sk,int how)
-{
- return -EOPNOTSUPP;
-}
-
-static int ipx_select(struct socket *sock , int sel_type, select_table *wait)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
-
- return datagram_select(sk,sel_type,wait);
-}
-
-static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
-{
- int err;
- long amount=0;
- ipx_socket *sk=(ipx_socket *)sock->data;
-
- switch(cmd)
- {
- case TIOCOUTQ:
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
- if(err)
- return err;
- amount=sk->sndbuf-sk->wmem_alloc;
- if(amount<0)
- amount=0;
- put_fs_long(amount,(unsigned long *)arg);
- return 0;
- case TIOCINQ:
- {
- struct sk_buff *skb;
- /* These two are safe on a single CPU system as only user tasks fiddle here */
- if((skb=skb_peek(&sk->receive_queue))!=NULL)
- amount=skb->len;
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
- put_fs_long(amount,(unsigned long *)arg);
- return 0;
- }
- case SIOCADDRT:
- case SIOCDELRT:
- if(!suser())
- return -EPERM;
- return(ipxrtr_ioctl(cmd,(void *)arg));
- case SIOCSIFADDR:
- case SIOCGIFADDR:
- case SIOCAIPXITFCRT:
- case SIOCAIPXPRISLT:
- if(!suser())
- return -EPERM;
- return(ipxitf_ioctl(cmd,(void *)arg));
- case SIOCIPXCFGDATA:
- {
- err=verify_area(VERIFY_WRITE,(void *)arg,
- sizeof(ipx_config_data));
- if(err) return err;
- return(ipxcfg_get_config_data((void *)arg));
- }
- case SIOCGSTAMP:
- if (sk)
- {
- if(sk->stamp.tv_sec==0)
- return -ENOENT;
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval));
- if(err)
- return err;
- memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval));
- return 0;
- }
- return -EINVAL;
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- return -EINVAL;
- default:
- return(dev_ioctl(cmd,(void *) arg));
- }
- /*NOTREACHED*/
- return(0);
-}
-
-static struct proto_ops ipx_proto_ops = {
- AF_IPX,
-
- ipx_create,
- ipx_dup,
- ipx_release,
- ipx_bind,
- ipx_connect,
- ipx_socketpair,
- ipx_accept,
- ipx_getname,
- ipx_read,
- ipx_write,
- ipx_select,
- ipx_ioctl,
- ipx_listen,
- ipx_send,
- ipx_recv,
- ipx_sendto,
- ipx_recvfrom,
- ipx_shutdown,
- ipx_setsockopt,
- ipx_getsockopt,
- ipx_fcntl,
-};
-
-/* Called by ddi.c on kernel start up */
-
-static struct packet_type ipx_8023_packet_type =
-
-{
- 0, /* MUTTER ntohs(ETH_P_8023),*/
- NULL, /* All devices */
- ipx_rcv,
- NULL,
- NULL,
-};
-
-static struct packet_type ipx_dix_packet_type =
-{
- 0, /* MUTTER ntohs(ETH_P_IPX),*/
- NULL, /* All devices */
- ipx_rcv,
- NULL,
- NULL,
-};
-
-static struct notifier_block ipx_dev_notifier={
- ipxitf_device_event,
- NULL,
- 0
-};
-
-
-extern struct datalink_proto *make_EII_client(void);
-extern struct datalink_proto *make_8023_client(void);
-
-void ipx_proto_init(struct net_proto *pro)
-{
- unsigned char val = 0xE0;
- unsigned char snapval[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
-
- (void) sock_register(ipx_proto_ops.family, &ipx_proto_ops);
-
- pEII_datalink = make_EII_client();
- ipx_dix_packet_type.type=htons(ETH_P_IPX);
- dev_add_pack(&ipx_dix_packet_type);
-
- p8023_datalink = make_8023_client();
- ipx_8023_packet_type.type=htons(ETH_P_802_3);
- dev_add_pack(&ipx_8023_packet_type);
-
- if ((p8022_datalink = register_8022_client(val, ipx_rcv)) == NULL)
- printk("IPX: Unable to register with 802.2\n");
-
- if ((pSNAP_datalink = register_snap_client(snapval, ipx_rcv)) == NULL)
- printk("IPX: Unable to register with SNAP\n");
-
- register_netdevice_notifier(&ipx_dev_notifier);
-
- printk("Swansea University Computer Society IPX 0.29 BETA for NET3.019\n");
- printk("IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
-}
-#endif
diff --git a/pfinet/linux-inet/p8022.c b/pfinet/linux-inet/p8022.c
deleted file mode 100644
index 8ff3ec60..00000000
--- a/pfinet/linux-inet/p8022.c
+++ /dev/null
@@ -1,98 +0,0 @@
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include "datalink.h"
-#include <linux/mm.h>
-#include <linux/in.h>
-
-static struct datalink_proto *p8022_list = NULL;
-
-static struct datalink_proto *
-find_8022_client(unsigned char type)
-{
- struct datalink_proto *proto;
-
- for (proto = p8022_list;
- ((proto != NULL) && (*(proto->type) != type));
- proto = proto->next)
- ;
-
- return proto;
-}
-
-int
-p8022_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
- struct datalink_proto *proto;
-
- proto = find_8022_client(*(skb->h.raw));
- if (proto != NULL) {
- skb->h.raw += 3;
- skb->len -= 3;
- return proto->rcvfunc(skb, dev, pt);
- }
-
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return 0;
-}
-
-static void
-p8022_datalink_header(struct datalink_proto *dl,
- struct sk_buff *skb, unsigned char *dest_node)
-{
- struct device *dev = skb->dev;
- unsigned long len = skb->len;
- unsigned long hard_len = dev->hard_header_len;
- unsigned char *rawp;
-
- dev->hard_header(skb->data, dev, len - hard_len,
- dest_node, NULL, len - hard_len, skb);
- rawp = skb->data + hard_len;
- *rawp = dl->type[0];
- rawp++;
- *rawp = dl->type[0];
- rawp++;
- *rawp = 0x03; /* UI */
- rawp++;
- skb->h.raw = rawp;
-}
-
-static struct packet_type p8022_packet_type =
-{
- 0, /* MUTTER ntohs(ETH_P_IPX),*/
- NULL, /* All devices */
- p8022_rcv,
- NULL,
- NULL,
-};
-
-
-void p8022_proto_init(struct net_proto *pro)
-{
- p8022_packet_type.type=htons(ETH_P_802_2);
- dev_add_pack(&p8022_packet_type);
-}
-
-struct datalink_proto *
-register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *))
-{
- struct datalink_proto *proto;
-
- if (find_8022_client(type) != NULL)
- return NULL;
-
- proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
- if (proto != NULL) {
- proto->type[0] = type;
- proto->type_len = 1;
- proto->rcvfunc = rcvfunc;
- proto->header_length = 3;
- proto->datalink_header = p8022_datalink_header;
- proto->string_name = "802.2";
- proto->next = p8022_list;
- p8022_list = proto;
- }
-
- return proto;
-}
-
diff --git a/pfinet/linux-inet/p8022.h b/pfinet/linux-inet/p8022.h
deleted file mode 100644
index 52c676be..00000000
--- a/pfinet/linux-inet/p8022.h
+++ /dev/null
@@ -1,2 +0,0 @@
-struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *));
-
diff --git a/pfinet/linux-inet/p8023.c b/pfinet/linux-inet/p8023.c
deleted file mode 100644
index 7c76223d..00000000
--- a/pfinet/linux-inet/p8023.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include "datalink.h"
-#include <linux/mm.h>
-#include <linux/in.h>
-
-static void
-p8023_datalink_header(struct datalink_proto *dl,
- struct sk_buff *skb, unsigned char *dest_node)
-{
- struct device *dev = skb->dev;
- unsigned long len = skb->len;
- unsigned long hard_len = dev->hard_header_len;
-
- dev->hard_header(skb->data, dev, len - hard_len,
- dest_node, NULL, len - hard_len, skb);
- skb->h.raw = skb->data + hard_len;
-}
-
-struct datalink_proto *
-make_8023_client(void)
-{
- struct datalink_proto *proto;
-
- proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
- if (proto != NULL) {
- proto->type_len = 0;
- proto->header_length = 0;
- proto->datalink_header = p8023_datalink_header;
- proto->string_name = "802.3";
- }
-
- return proto;
-}
-
diff --git a/pfinet/linux-inet/packet.c b/pfinet/linux-inet/packet.c
deleted file mode 100644
index ab031c81..00000000
--- a/pfinet/linux-inet/packet.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * PACKET - implements raw packet sockets.
- *
- * Version: @(#)packet.c 1.0.6 05/25/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- *
- * Fixes:
- * Alan Cox : verify_area() now used correctly
- * Alan Cox : new skbuff lists, look ma no backlogs!
- * Alan Cox : tidied skbuff lists.
- * Alan Cox : Now uses generic datagram routines I
- * added. Also fixed the peek/read crash
- * from all old Linux datagram code.
- * Alan Cox : Uses the improved datagram code.
- * Alan Cox : Added NULL's for socket options.
- * Alan Cox : Re-commented the code.
- * Alan Cox : Use new kernel side addressing
- * Rob Janssen : Correct MTU usage.
- * Dave Platt : Counter leaks caused by incorrect
- * interrupt locking and some slightly
- * dubious gcc output. Can you read
- * compiler: it said _VOLATILE_
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fcntl.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-
-/*
- * We really ought to have a single public _inline_ min function!
- */
-
-static unsigned long min(unsigned long a, unsigned long b)
-{
- if (a < b)
- return(a);
- return(b);
-}
-
-
-/*
- * This should be the easiest of all, all we do is copy it into a buffer.
- */
-
-int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
- struct sock *sk;
- unsigned long flags;
-
- /*
- * When we registered the protocol we saved the socket in the data
- * field for just this event.
- */
-
- sk = (struct sock *) pt->data;
-
- /*
- * The SOCK_PACKET socket receives _all_ frames, and as such
- * therefore needs to put the header back onto the buffer.
- * (it was removed by inet_bh()).
- */
-
- skb->dev = dev;
- skb->len += dev->hard_header_len;
-
- /*
- * Charge the memory to the socket. This is done specifically
- * to prevent sockets using all the memory up.
- */
-
- if (sk->rmem_alloc & 0xFF000000) {
- printk("packet_rcv: sk->rmem_alloc = %ld\n", sk->rmem_alloc);
- sk->rmem_alloc = 0;
- }
-
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- {
-/* printk("packet_rcv: drop, %d+%d>%d\n", sk->rmem_alloc, skb->mem_len, sk->rcvbuf); */
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- save_flags(flags);
- cli();
-
- skb->sk = sk;
- sk->rmem_alloc += skb->mem_len;
-
- /*
- * Queue the packet up, and wake anyone waiting for it.
- */
-
- skb_queue_tail(&sk->receive_queue,skb);
- if(!sk->dead)
- sk->data_ready(sk,skb->len);
-
- restore_flags(flags);
-
- /*
- * Processing complete.
- */
-
- release_sock(sk); /* This is now effectively surplus in this layer */
- return(0);
-}
-
-
-/*
- * Output a raw packet to a device layer. This bypasses all the other
- * protocol layers and you must therefore supply it with a complete frame
- */
-
-static int packet_sendto(struct sock *sk, unsigned char *from, int len,
- int noblock, unsigned flags, struct sockaddr_in *usin,
- int addr_len)
-{
- struct sk_buff *skb;
- struct device *dev;
- struct sockaddr *saddr=(struct sockaddr *)usin;
-
- /*
- * Check the flags.
- */
-
- if (flags)
- return(-EINVAL);
-
- /*
- * Get and verify the address.
- */
-
- if (usin)
- {
- if (addr_len < sizeof(*saddr))
- return(-EINVAL);
- }
- else
- return(-EINVAL); /* SOCK_PACKET must be sent giving an address */
-
- /*
- * Find the device first to size check it
- */
-
- saddr->sa_data[13] = 0;
- dev = dev_get(saddr->sa_data);
- if (dev == NULL)
- {
- return(-ENXIO);
- }
-
- /*
- * You may not queue a frame bigger than the mtu. This is the lowest level
- * raw protocol and you must do your own fragmentation at this level.
- */
-
- if(len>dev->mtu+dev->hard_header_len)
- return -EMSGSIZE;
-
- skb = sk->prot->wmalloc(sk, len, 0, GFP_KERNEL);
-
- /*
- * If the write buffer is full, then tough. At this level the user gets to
- * deal with the problem - do your own algorithmic backoffs.
- */
-
- if (skb == NULL)
- {
- return(-ENOBUFS);
- }
-
- /*
- * Fill it in
- */
-
- skb->sk = sk;
- skb->free = 1;
- memcpy_fromfs(skb->data, from, len);
- skb->len = len;
- skb->arp = 1; /* No ARP needs doing on this (complete) frame */
-
- /*
- * Now send it
- */
-
- if (dev->flags & IFF_UP)
- dev_queue_xmit(skb, dev, sk->priority);
- else
- kfree_skb(skb, FREE_WRITE);
- return(len);
-}
-
-/*
- * A write to a SOCK_PACKET can't actually do anything useful and will
- * always fail but we include it for completeness and future expansion.
- */
-
-static int packet_write(struct sock *sk, unsigned char *buff,
- int len, int noblock, unsigned flags)
-{
- return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0));
-}
-
-/*
- * Close a SOCK_PACKET socket. This is fairly simple. We immediately go
- * to 'closed' state and remove our protocol entry in the device list.
- * The release_sock() will destroy the socket if a user has closed the
- * file side of the object.
- */
-
-static void packet_close(struct sock *sk, int timeout)
-{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
- dev_remove_pack((struct packet_type *)sk->pair);
- kfree_s((void *)sk->pair, sizeof(struct packet_type));
- sk->pair = NULL;
- release_sock(sk);
-}
-
-/*
- * Create a packet of type SOCK_PACKET. We do one slightly irregular
- * thing here that wants tidying up. We borrow the 'pair' pointer in
- * the socket object so we can find the packet_type entry in the
- * device list. The reverse is easy as we use the data field of the
- * packet type to point to our socket.
- */
-
-static int packet_init(struct sock *sk)
-{
- struct packet_type *p;
-
- p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL)
- return(-ENOMEM);
-
- p->func = packet_rcv;
- p->type = sk->num;
- p->data = (void *)sk;
- p->dev = NULL;
- dev_add_pack(p);
-
- /*
- * We need to remember this somewhere.
- */
-
- sk->pair = (struct sock *)p;
-
- return(0);
-}
-
-
-/*
- * Pull a packet from our receive queue and hand it to the user.
- * If necessary we block.
- */
-
-int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
- int noblock, unsigned flags, struct sockaddr_in *sin,
- int *addr_len)
-{
- int copied=0;
- struct sk_buff *skb;
- struct sockaddr *saddr;
- int err;
- int truesize;
-
- saddr = (struct sockaddr *)sin;
-
- if (sk->shutdown & RCV_SHUTDOWN)
- return(0);
-
- /*
- * If the address length field is there to be filled in, we fill
- * it in now.
- */
-
- if (addr_len)
- *addr_len=sizeof(*saddr);
-
- /*
- * Call the generic datagram receiver. This handles all sorts
- * of horrible races and re-entrancy so we can forget about it
- * in the protocol layers.
- */
-
- skb=skb_recv_datagram(sk,flags,noblock,&err);
-
- /*
- * An error occurred so return it. Because skb_recv_datagram()
- * handles the blocking we don't see and worry about blocking
- * retries.
- */
-
- if(skb==NULL)
- return err;
-
- /*
- * You lose any data beyond the buffer you gave. If it worries a
- * user program they can ask the device for its MTU anyway.
- */
-
- truesize = skb->len;
- copied = min(len, truesize);
-
- memcpy_tofs(to, skb->data, copied); /* We can't use skb_copy_datagram here */
-
- /*
- * Copy the address.
- */
-
- if (saddr)
- {
- saddr->sa_family = skb->dev->type;
- memcpy(saddr->sa_data,skb->dev->name, 14);
- }
-
- /*
- * Free or return the buffer as appropriate. Again this hides all the
- * races and re-entrancy issues from us.
- */
-
- skb_free_datagram(skb);
-
- /*
- * We are done.
- */
-
- release_sock(sk);
- return(truesize);
-}
-
-
-/*
- * A packet read can succeed and is just the same as a recvfrom but without the
- * addresses being recorded.
- */
-
-int packet_read(struct sock *sk, unsigned char *buff,
- int len, int noblock, unsigned flags)
-{
- return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
-}
-
-
-/*
- * This structure declares to the lower layer socket subsystem currently
- * incorrectly embedded in the IP code how to behave. This interface needs
- * a lot of work and will change.
- */
-
-struct proto packet_prot =
-{
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- packet_close,
- packet_read,
- packet_write,
- packet_sendto,
- packet_recvfrom,
- ip_build_header, /* Not actually used */
- NULL,
- NULL,
- ip_queue_xmit, /* These two are not actually used */
- NULL,
- NULL,
- NULL,
- NULL,
- datagram_select,
- NULL,
- packet_init,
- NULL,
- NULL, /* No set/get socket options */
- NULL,
- 128,
- 0,
- {NULL,},
- "PACKET",
- 0, 0
-};
diff --git a/pfinet/linux-inet/protocol.c b/pfinet/linux-inet/protocol.c
deleted file mode 100644
index a47d27cd..00000000
--- a/pfinet/linux-inet/protocol.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * INET protocol dispatch tables.
- *
- * Version: @(#)protocol.c 1.0.5 05/25/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * Fixes:
- * Alan Cox : Ahah! udp icmp errors don't work because
- * udp_err is never called!
- * Alan Cox : Added new fields for init and ready for
- * proper fragmentation (_NO_ 4K limits!)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/timer.h>
-#include "ip.h"
-#include "protocol.h"
-#include "tcp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "icmp.h"
-#include "udp.h"
-#include <linux/igmp.h>
-
-
-static struct inet_protocol tcp_protocol = {
- tcp_rcv, /* TCP handler */
- NULL, /* No fragment handler (and won't be for a long time) */
- tcp_err, /* TCP error control */
- NULL, /* next */
- IPPROTO_TCP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "TCP" /* name */
-};
-
-
-static struct inet_protocol udp_protocol = {
- udp_rcv, /* UDP handler */
- NULL, /* Will be UDP fraglist handler */
- udp_err, /* UDP error control */
- &tcp_protocol, /* next */
- IPPROTO_UDP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "UDP" /* name */
-};
-
-
-static struct inet_protocol icmp_protocol = {
- icmp_rcv, /* ICMP handler */
- NULL, /* ICMP never fragments anyway */
- NULL, /* ICMP error control */
- &udp_protocol, /* next */
- IPPROTO_ICMP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "ICMP" /* name */
-};
-
-#ifndef CONFIG_IP_MULTICAST
-struct inet_protocol *inet_protocol_base = &icmp_protocol;
-#else
-static struct inet_protocol igmp_protocol = {
- igmp_rcv, /* IGMP handler */
- NULL, /* IGMP never fragments anyway */
- NULL, /* IGMP error control */
- &icmp_protocol, /* next */
- IPPROTO_IGMP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "IGMP" /* name */
-};
-
-struct inet_protocol *inet_protocol_base = &igmp_protocol;
-#endif
-
-struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
- NULL
-};
-
-
-struct inet_protocol *
-inet_get_protocol(unsigned char prot)
-{
- unsigned char hash;
- struct inet_protocol *p;
-
- hash = prot & (MAX_INET_PROTOS - 1);
- for (p = inet_protos[hash] ; p != NULL; p=p->next) {
- if (p->protocol == prot) return((struct inet_protocol *) p);
- }
- return(NULL);
-}
-
-
-void
-inet_add_protocol(struct inet_protocol *prot)
-{
- unsigned char hash;
- struct inet_protocol *p2;
-
- hash = prot->protocol & (MAX_INET_PROTOS - 1);
- prot ->next = inet_protos[hash];
- inet_protos[hash] = prot;
- prot->copy = 0;
-
- /* Set the copy bit if we need to. */
- p2 = (struct inet_protocol *) prot->next;
- while(p2 != NULL) {
- if (p2->protocol == prot->protocol) {
- prot->copy = 1;
- break;
- }
- p2 = (struct inet_protocol *) prot->next;
- }
-}
-
-
-int
-inet_del_protocol(struct inet_protocol *prot)
-{
- struct inet_protocol *p;
- struct inet_protocol *lp = NULL;
- unsigned char hash;
-
- hash = prot->protocol & (MAX_INET_PROTOS - 1);
- if (prot == inet_protos[hash]) {
- inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
- return(0);
- }
-
- p = (struct inet_protocol *) inet_protos[hash];
- while(p != NULL) {
- /*
- * We have to worry if the protocol being deleted is
- * the last one on the list, then we may need to reset
- * someone's copied bit.
- */
- if (p->next != NULL && p->next == prot) {
- /*
- * if we are the last one with this protocol and
- * there is a previous one, reset its copy bit.
- */
- if (p->copy == 0 && lp != NULL) lp->copy = 0;
- p->next = prot->next;
- return(0);
- }
-
- if (p->next != NULL && p->next->protocol == prot->protocol) {
- lp = p;
- }
-
- p = (struct inet_protocol *) p->next;
- }
- return(-1);
-}
diff --git a/pfinet/linux-inet/protocol.h b/pfinet/linux-inet/protocol.h
deleted file mode 100644
index 3e0b6fb3..00000000
--- a/pfinet/linux-inet/protocol.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the protocol dispatcher.
- *
- * Version: @(#)protocol.h 1.0.2 05/07/93
- *
- * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Changes:
- * Alan Cox : Added a name field and a frag handler
- * field for later.
- */
-
-#ifndef _PROTOCOL_H
-#define _PROTOCOL_H
-
-
-#define MAX_INET_PROTOS 32 /* Must be a power of 2 */
-
-
-/* This is used to register protocols. */
-struct inet_protocol {
- int (*handler)(struct sk_buff *skb, struct device *dev,
- struct options *opt, unsigned long daddr,
- unsigned short len, unsigned long saddr,
- int redo, struct inet_protocol *protocol);
- int (*frag_handler)(struct sk_buff *skb, struct device *dev,
- struct options *opt, unsigned long daddr,
- unsigned short len, unsigned long saddr,
- int redo, struct inet_protocol *protocol);
- void (*err_handler)(int err, unsigned char *buff,
- unsigned long daddr,
- unsigned long saddr,
- struct inet_protocol *protocol);
- struct inet_protocol *next;
- unsigned char protocol;
- unsigned char copy:1;
- void *data;
- char *name;
-};
-
-
-extern struct inet_protocol *inet_protocol_base;
-extern struct inet_protocol *inet_protos[MAX_INET_PROTOS];
-
-
-extern void inet_add_protocol(struct inet_protocol *prot);
-extern int inet_del_protocol(struct inet_protocol *prot);
-
-
-#endif /* _PROTOCOL_H */
diff --git a/pfinet/linux-inet/psnap.c b/pfinet/linux-inet/psnap.c
deleted file mode 100644
index 287b3353..00000000
--- a/pfinet/linux-inet/psnap.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * SNAP data link layer. Derived from 802.2
- *
- * Alan Cox <Alan.Cox@linux.org>, from the 802.2 layer by Greg Page.
- * Merged in additions from Greg Page's psnap.c.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include "datalink.h"
-#include "p8022.h"
-#include "psnap.h"
-#include <linux/mm.h>
-#include <linux/in.h>
-
-static struct datalink_proto *snap_list = NULL;
-static struct datalink_proto *snap_dl = NULL; /* 802.2 DL for SNAP */
-
-/*
- * Find a snap client by matching the 5 bytes.
- */
-
-static struct datalink_proto *find_snap_client(unsigned char *desc)
-{
- struct datalink_proto *proto;
-
- for (proto = snap_list; proto != NULL && memcmp(proto->type, desc, 5) ; proto = proto->next);
- return proto;
-}
-
-/*
- * A SNAP packet has arrived
- */
-
-int snap_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
- static struct packet_type psnap_packet_type =
- {
- 0,
- NULL, /* All Devices */
- snap_rcv,
- NULL,
- NULL,
- };
-
- struct datalink_proto *proto;
-
- proto = find_snap_client(skb->h.raw);
- if (proto != NULL)
- {
- /*
- * Pass the frame on.
- */
-
- skb->h.raw += 5;
- skb->len -= 5;
- if (psnap_packet_type.type == 0)
- psnap_packet_type.type=htons(ETH_P_SNAP);
- return proto->rcvfunc(skb, dev, &psnap_packet_type);
- }
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return 0;
-}
-
-/*
- * Put a SNAP header on a frame and pass to 802.2
- */
-
-static void snap_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node)
-{
- struct device *dev = skb->dev;
- unsigned char *rawp;
-
- rawp = skb->data + snap_dl->header_length+dev->hard_header_len;
- memcpy(rawp,dl->type,5);
- skb->h.raw = rawp+5;
- snap_dl->datalink_header(snap_dl, skb, dest_node);
-}
-
-/*
- * Set up the SNAP layer
- */
-
-void snap_proto_init(struct net_proto *pro)
-{
- snap_dl=register_8022_client(0xAA, snap_rcv);
- if(snap_dl==NULL)
- printk("SNAP - unable to register with 802.2\n");
-}
-
-/*
- * Register SNAP clients. We don't yet use this for IP or IPX.
- */
-
-struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *))
-{
- struct datalink_proto *proto;
-
- if (find_snap_client(desc) != NULL)
- return NULL;
-
- proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
- if (proto != NULL)
- {
- memcpy(proto->type, desc,5);
- proto->type_len = 5;
- proto->rcvfunc = rcvfunc;
- proto->header_length = 5+snap_dl->header_length;
- proto->datalink_header = snap_datalink_header;
- proto->string_name = "SNAP";
- proto->next = snap_list;
- snap_list = proto;
- }
-
- return proto;
-}
-
diff --git a/pfinet/linux-inet/psnap.h b/pfinet/linux-inet/psnap.h
deleted file mode 100644
index b69859db..00000000
--- a/pfinet/linux-inet/psnap.h
+++ /dev/null
@@ -1,2 +0,0 @@
-struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *));
-
diff --git a/pfinet/linux-inet/raw.c b/pfinet/linux-inet/raw.c
deleted file mode 100644
index b7d34a37..00000000
--- a/pfinet/linux-inet/raw.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * RAW - implementation of IP "raw" sockets.
- *
- * Version: @(#)raw.c 1.0.4 05/25/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * Fixes:
- * Alan Cox : verify_area() fixed up
- * Alan Cox : ICMP error handling
- * Alan Cox : EMSGSIZE if you send too big a packet
- * Alan Cox : Now uses generic datagrams and shared skbuff
- * library. No more peek crashes, no more backlogs
- * Alan Cox : Checks sk->broadcast.
- * Alan Cox : Uses skb_free_datagram/skb_copy_datagram
- * Alan Cox : Raw passes ip options too
- * Alan Cox : Setsocketopt added
- * Alan Cox : Fixed error return for broadcasts
- * Alan Cox : Removed wake_up calls
- * Alan Cox : Use ttl/tos
- * Alan Cox : Cleaned up old debugging
- * Alan Cox : Use new kernel side addresses
- * Arnt Gulbrandsen : Fixed MSG_DONTROUTE in raw sockets.
- * Alan Cox : BSD style RAW socket demultiplexing.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "icmp.h"
-#include "udp.h"
-
-
-static inline unsigned long min(unsigned long a, unsigned long b)
-{
- if (a < b)
- return(a);
- return(b);
-}
-
-
-/* raw_err gets called by the icmp module. */
-void raw_err (int err, unsigned char *header, unsigned long daddr,
- unsigned long saddr, struct inet_protocol *protocol)
-{
- struct sock *sk;
-
- if (protocol == NULL)
- return;
- sk = (struct sock *) protocol->data;
- if (sk == NULL)
- return;
-
- /* This is meaningless in raw sockets. */
- if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8))
- {
- if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
- return;
- }
-
- sk->err = icmp_err_convert[err & 0xff].error;
- sk->error_report(sk);
-
- return;
-}
-
-
-/*
- * This should be the easiest of all, all we do is
- * copy it into a buffer. All demultiplexing is done
- * in ip.c
- */
-
-int raw_rcv(struct sock *sk, struct sk_buff *skb, struct device *dev, long saddr, long daddr)
-{
- /* Now we need to copy this into memory. */
- skb->sk = sk;
- skb->len = ntohs(skb->ip_hdr->tot_len);
- skb->h.raw = (unsigned char *) skb->ip_hdr;
- skb->dev = dev;
- skb->saddr = daddr;
- skb->daddr = saddr;
-
- /* Charge it to the socket. */
-
- if(sock_queue_rcv_skb(sk,skb)<0)
- {
- ip_statistics.IpInDiscards++;
- skb->sk=NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- ip_statistics.IpInDelivers++;
- release_sock(sk);
- return(0);
-}
-
-/*
- * Send a RAW IP packet.
- */
-
-static int raw_sendto(struct sock *sk, unsigned char *from,
- int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len)
-{
- struct sk_buff *skb;
- struct device *dev=NULL;
- struct sockaddr_in sin;
- int tmp;
- int err;
-
- /*
- * Check the flags. Only MSG_DONTROUTE is permitted.
- */
-
- if (flags & MSG_OOB) /* Mirror BSD error message compatibility */
- return -EOPNOTSUPP;
-
- if (flags & ~MSG_DONTROUTE)
- return(-EINVAL);
- /*
- * Get and verify the address.
- */
-
- if (usin)
- {
- if (addr_len < sizeof(sin))
- return(-EINVAL);
- memcpy(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EINVAL);
- }
- else
- {
- if (sk->state != TCP_ESTABLISHED)
- return(-EINVAL);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->protocol;
- sin.sin_addr.s_addr = sk->daddr;
- }
- if (sin.sin_port == 0)
- sin.sin_port = sk->protocol;
-
- if (sin.sin_addr.s_addr == INADDR_ANY)
- sin.sin_addr.s_addr = ip_my_addr();
-
- if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -EACCES;
-
- skb=sock_alloc_send_skb(sk, len+sk->prot->max_header, noblock, &err);
- if(skb==NULL)
- return err;
-
- skb->sk = sk;
- skb->free = 1;
- skb->localroute = sk->localroute | (flags&MSG_DONTROUTE);
-
- tmp = sk->prot->build_header(skb, sk->saddr,
- sin.sin_addr.s_addr, &dev,
- sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
- if (tmp < 0)
- {
- kfree_skb(skb,FREE_WRITE);
- release_sock(sk);
- return(tmp);
- }
-
- memcpy_fromfs(skb->data + tmp, from, len);
-
- /*
- * If we are using IPPROTO_RAW, we need to fill in the source address in
- * the IP header
- */
-
- if(sk->protocol==IPPROTO_RAW)
- {
- unsigned char *buff;
- struct iphdr *iph;
-
- buff = skb->data;
- buff += tmp;
-
- iph = (struct iphdr *)buff;
- iph->saddr = sk->saddr;
- }
-
- skb->len = tmp + len;
-
- sk->prot->queue_xmit(sk, dev, skb, 1);
- release_sock(sk);
- return(len);
-}
-
-
-static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
- unsigned flags)
-{
- return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
-}
-
-
-static void raw_close(struct sock *sk, int timeout)
-{
- sk->state = TCP_CLOSE;
-}
-
-
-static int raw_init(struct sock *sk)
-{
- return(0);
-}
-
-
-/*
- * This should be easy, if there is something there
- * we return it, otherwise we block.
- */
-
-int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
- int noblock, unsigned flags, struct sockaddr_in *sin,
- int *addr_len)
-{
- int copied=0;
- struct sk_buff *skb;
- int err;
- int truesize;
-
- if (flags & MSG_OOB)
- return -EOPNOTSUPP;
-
- if (sk->shutdown & RCV_SHUTDOWN)
- return(0);
-
- if (addr_len)
- *addr_len=sizeof(*sin);
-
- skb=skb_recv_datagram(sk,flags,noblock,&err);
- if(skb==NULL)
- return err;
-
- truesize=skb->len;
- copied = min(len, truesize);
-
- skb_copy_datagram(skb, 0, to, copied);
- sk->stamp=skb->stamp;
-
- /* Copy the address. */
- if (sin)
- {
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = skb->daddr;
- }
- skb_free_datagram(skb);
- release_sock(sk);
- return (truesize); /* len not copied. BSD returns the true size of the message so you know a bit fell off! */
-}
-
-
-int raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,unsigned flags)
-{
- return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
-}
-
-
-struct proto raw_prot = {
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- raw_close,
- raw_read,
- raw_write,
- raw_sendto,
- raw_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- NULL,
- NULL,
- NULL,
- NULL,
- datagram_select,
- NULL,
- raw_init,
- NULL,
- ip_setsockopt,
- ip_getsockopt,
- 128,
- 0,
- {NULL,},
- "RAW",
- 0, 0
-};
diff --git a/pfinet/linux-inet/route.c b/pfinet/linux-inet/route.c
deleted file mode 100644
index ce06dcfe..00000000
--- a/pfinet/linux-inet/route.c
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * ROUTE - implementation of the IP router.
- *
- * Version: @(#)route.c 1.0.14 05/31/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Linus Torvalds, <Linus.Torvalds@helsinki.fi>
- *
- * Fixes:
- * Alan Cox : Verify area fixes.
- * Alan Cox : cli() protects routing changes
- * Rui Oliveira : ICMP routing table updates
- * (rco@di.uminho.pt) Routing table insertion and update
- * Linus Torvalds : Rewrote bits to be sensible
- * Alan Cox : Added BSD route gw semantics
- * Alan Cox : Super /proc >4K
- * Alan Cox : MTU in route table
- * Alan Cox : MSS actually. Also added the window
- * clamper.
- * Sam Lantinga : Fixed route matching in rt_del()
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "route.h"
-#include "tcp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "icmp.h"
-
-/*
- * The routing table list
- */
-
-static struct rtable *rt_base = NULL;
-
-/*
- * Pointer to the loopback route
- */
-
-static struct rtable *rt_loopback = NULL;
-
-/*
- * Remove a routing table entry.
- */
-
-static void rt_del(unsigned long dst, char *devname)
-{
- struct rtable *r, **rp;
- unsigned long flags;
-
- rp = &rt_base;
-
- /*
- * This must be done with interrupts off because we could take
- * an ICMP_REDIRECT.
- */
-
- save_flags(flags);
- cli();
- while((r = *rp) != NULL)
- {
- /* Make sure both the destination and the device match */
- if ( r->rt_dst != dst ||
- (devname != NULL && strcmp((r->rt_dev)->name,devname) != 0) )
- {
- rp = &r->rt_next;
- continue;
- }
- *rp = r->rt_next;
-
- /*
- * If we delete the loopback route update its pointer.
- */
-
- if (rt_loopback == r)
- rt_loopback = NULL;
- kfree_s(r, sizeof(struct rtable));
- }
- restore_flags(flags);
-}
-
-
-/*
- * Remove all routing table entries for a device. This is called when
- * a device is downed.
- */
-
-void ip_rt_flush(struct device *dev)
-{
- struct rtable *r;
- struct rtable **rp;
- unsigned long flags;
-
- rp = &rt_base;
- save_flags(flags);
- cli();
- while ((r = *rp) != NULL) {
- if (r->rt_dev != dev) {
- rp = &r->rt_next;
- continue;
- }
- *rp = r->rt_next;
- if (rt_loopback == r)
- rt_loopback = NULL;
- kfree_s(r, sizeof(struct rtable));
- }
- restore_flags(flags);
-}
-
-/*
- * Used by 'rt_add()' when we can't get the netmask any other way..
- *
- * If the lower byte or two are zero, we guess the mask based on the
- * number of zero 8-bit net numbers, otherwise we use the "default"
- * masks judging by the destination address and our device netmask.
- */
-
-static inline unsigned long default_mask(unsigned long dst)
-{
- dst = ntohl(dst);
- if (IN_CLASSA(dst))
- return htonl(IN_CLASSA_NET);
- if (IN_CLASSB(dst))
- return htonl(IN_CLASSB_NET);
- return htonl(IN_CLASSC_NET);
-}
-
-
-/*
- * If no mask is specified then generate a default entry.
- */
-
-static unsigned long guess_mask(unsigned long dst, struct device * dev)
-{
- unsigned long mask;
-
- if (!dst)
- return 0;
- mask = default_mask(dst);
- if ((dst ^ dev->pa_addr) & mask)
- return mask;
- return dev->pa_mask;
-}
-
-
-/*
- * Find the route entry through which our gateway will be reached
- */
-
-static inline struct device * get_gw_dev(unsigned long gw)
-{
- struct rtable * rt;
-
- for (rt = rt_base ; ; rt = rt->rt_next)
- {
- if (!rt)
- return NULL;
- if ((gw ^ rt->rt_dst) & rt->rt_mask)
- continue;
- /*
- * Gateways behind gateways are a no-no
- */
-
- if (rt->rt_flags & RTF_GATEWAY)
- return NULL;
- return rt->rt_dev;
- }
-}
-
-/*
- * Rewrote rt_add(), as the old one was weird - Linus
- *
- * This routine is used to update the IP routing table, either
- * from the kernel (ICMP_REDIRECT) or via an ioctl call issued
- * by the superuser.
- */
-
-void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
- unsigned long gw, struct device *dev, unsigned short mtu, unsigned long window)
-{
- struct rtable *r, *rt;
- struct rtable **rp;
- unsigned long cpuflags;
-
- /*
- * A host is a unique machine and has no network bits.
- */
-
- if (flags & RTF_HOST)
- {
- mask = 0xffffffff;
- }
-
- /*
- * Calculate the network mask
- */
-
- else if (!mask)
- {
- if (!((dst ^ dev->pa_addr) & dev->pa_mask))
- {
- mask = dev->pa_mask;
- flags &= ~RTF_GATEWAY;
- if (flags & RTF_DYNAMIC)
- {
- /*printk("Dynamic route to my own net rejected\n");*/
- return;
- }
- }
- else
- mask = guess_mask(dst, dev);
- dst &= mask;
- }
-
- /*
- * A gateway must be reachable and not a local address
- */
-
- if (gw == dev->pa_addr)
- flags &= ~RTF_GATEWAY;
-
- if (flags & RTF_GATEWAY)
- {
- /*
- * Don't try to add a gateway we can't reach..
- */
-
- if (dev != get_gw_dev(gw))
- return;
-
- flags |= RTF_GATEWAY;
- }
- else
- gw = 0;
-
- /*
- * Allocate an entry and fill it in.
- */
-
- rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
- if (rt == NULL)
- {
- return;
- }
- memset(rt, 0, sizeof(struct rtable));
- rt->rt_flags = flags | RTF_UP;
- rt->rt_dst = dst;
- rt->rt_dev = dev;
- rt->rt_gateway = gw;
- rt->rt_mask = mask;
- rt->rt_mss = dev->mtu - HEADER_SIZE;
- rt->rt_window = 0; /* Default is no clamping */
-
- /* Are the MSS/Window valid ? */
-
- if(rt->rt_flags & RTF_MSS)
- rt->rt_mss = mtu;
-
- if(rt->rt_flags & RTF_WINDOW)
- rt->rt_window = window;
-
- /*
- * What we have to do is loop though this until we have
- * found the first address which has a higher generality than
- * the one in rt. Then we can put rt in right before it.
- * The interrupts must be off for this process.
- */
-
- save_flags(cpuflags);
- cli();
-
- /*
- * Remove old route if we are getting a duplicate.
- */
-
- rp = &rt_base;
- while ((r = *rp) != NULL)
- {
- if (r->rt_dst != dst ||
- r->rt_mask != mask)
- {
- rp = &r->rt_next;
- continue;
- }
- *rp = r->rt_next;
- if (rt_loopback == r)
- rt_loopback = NULL;
- kfree_s(r, sizeof(struct rtable));
- }
-
- /*
- * Add the new route
- */
-
- rp = &rt_base;
- while ((r = *rp) != NULL) {
- if ((r->rt_mask & mask) != mask)
- break;
- rp = &r->rt_next;
- }
- rt->rt_next = r;
- *rp = rt;
-
- /*
- * Update the loopback route
- */
-
- if ((rt->rt_dev->flags & IFF_LOOPBACK) && !rt_loopback)
- rt_loopback = rt;
-
- /*
- * Restore the interrupts and return
- */
-
- restore_flags(cpuflags);
- return;
-}
-
-/*
- * Remove a routing table entry (exported version).
- */
-void ip_rt_del (unsigned long dst, struct device *dev)
-{
- /* Should probably just copy contents of rt_del and replace name
- comparison with device comparsion. */
- rt_del (dst, dev->name);
-}
-
-
-/*
- * Check if a mask is acceptable.
- */
-
-static inline int bad_mask(unsigned long mask, unsigned long addr)
-{
- if (addr & (mask = ~mask))
- return 1;
- mask = ntohl(mask);
- if (mask & (mask+1))
- return 1;
- return 0;
-}
-
-/*
- * Process a route add request from the user
- */
-
-static int rt_new(struct rtentry *r)
-{
- int err;
- char * devname;
- struct device * dev = NULL;
- unsigned long flags, daddr, mask, gw;
-
- /*
- * If a device is specified find it.
- */
-
- if ((devname = r->rt_dev) != NULL)
- {
- err = getname(devname, &devname);
- if (err)
- return err;
- dev = dev_get(devname);
- putname(devname);
- if (!dev)
- return -EINVAL;
- }
-
- /*
- * If the device isn't INET, don't allow it
- */
-
- if (r->rt_dst.sa_family != AF_INET)
- return -EAFNOSUPPORT;
-
- /*
- * Make local copies of the important bits
- */
-
- flags = r->rt_flags;
- daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
- mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
- gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
-
-
- /*
- * BSD emulation: Permits route add someroute gw one-of-my-addresses
- * to indicate which iface. Not as clean as the nice Linux dev technique
- * but people keep using it...
- */
-
- if (!dev && (flags & RTF_GATEWAY))
- {
- struct device *dev2;
- for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next)
- {
- if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw)
- {
- flags &= ~RTF_GATEWAY;
- dev = dev2;
- break;
- }
- }
- }
-
- /*
- * Ignore faulty masks
- */
-
- if (bad_mask(mask, daddr))
- mask = 0;
-
- /*
- * Set the mask to nothing for host routes.
- */
-
- if (flags & RTF_HOST)
- mask = 0xffffffff;
- else if (mask && r->rt_genmask.sa_family != AF_INET)
- return -EAFNOSUPPORT;
-
- /*
- * You can only gateway IP via IP..
- */
-
- if (flags & RTF_GATEWAY)
- {
- if (r->rt_gateway.sa_family != AF_INET)
- return -EAFNOSUPPORT;
- if (!dev)
- dev = get_gw_dev(gw);
- }
- else if (!dev)
- dev = ip_dev_check(daddr);
-
- /*
- * Unknown device.
- */
-
- if (dev == NULL)
- return -ENETUNREACH;
-
- /*
- * Add the route
- */
-
- ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mss, r->rt_window);
- return 0;
-}
-
-
-/*
- * Remove a route, as requested by the user.
- */
-
-static int rt_kill(struct rtentry *r)
-{
- struct sockaddr_in *trg;
- char *devname;
- int err;
-
- trg = (struct sockaddr_in *) &r->rt_dst;
- if ((devname = r->rt_dev) != NULL)
- {
- err = getname(devname, &devname);
- if (err)
- return err;
- }
- rt_del(trg->sin_addr.s_addr, devname);
- if ( devname != NULL )
- putname(devname);
- return 0;
-}
-
-
-/*
- * Called from the PROCfs module. This outputs /proc/net/route.
- */
-
-int rt_get_info(char *buffer, char **start, off_t offset, int length)
-{
- struct rtable *r;
- int len=0;
- off_t pos=0;
- off_t begin=0;
- int size;
-
- len += sprintf(buffer,
- "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\n");
- pos=len;
-
- /*
- * This isn't quite right -- r->rt_dst is a struct!
- */
-
- for (r = rt_base; r != NULL; r = r->rt_next)
- {
- size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\n",
- r->rt_dev->name, r->rt_dst, r->rt_gateway,
- r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
- r->rt_mask, (int)r->rt_mss, r->rt_window);
- len+=size;
- pos+=size;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
- }
-
- *start=buffer+(offset-begin);
- len-=(offset-begin);
- if(len>length)
- len=length;
- return len;
-}
-
-/*
- * This is hackish, but results in better code. Use "-S" to see why.
- */
-
-#define early_out ({ goto no_route; 1; })
-
-/*
- * Route a packet. This needs to be fairly quick. Florian & Co.
- * suggested a unified ARP and IP routing cache. Done right its
- * probably a brilliant idea. I'd actually suggest a unified
- * ARP/IP routing/Socket pointer cache. Volunteers welcome
- */
-
-struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr)
-{
- struct rtable *rt;
-
- for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next)
- {
- if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
- break;
- /*
- * broadcast addresses can be special cases..
- */
- if (rt->rt_flags & RTF_GATEWAY)
- continue;
- if ((rt->rt_dev->flags & IFF_BROADCAST) &&
- (rt->rt_dev->pa_brdaddr == daddr))
- break;
- }
-
- if(src_addr!=NULL)
- *src_addr= rt->rt_dev->pa_addr;
-
- if (daddr == rt->rt_dev->pa_addr) {
- if ((rt = rt_loopback) == NULL)
- goto no_route;
- }
- rt->rt_use++;
- return rt;
-no_route:
- return NULL;
-}
-
-struct rtable * ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr)
-{
- struct rtable *rt;
-
- for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next)
- {
- /*
- * No routed addressing.
- */
- if (rt->rt_flags&RTF_GATEWAY)
- continue;
-
- if (!((rt->rt_dst ^ daddr) & rt->rt_mask))
- break;
- /*
- * broadcast addresses can be special cases..
- */
-
- if ((rt->rt_dev->flags & IFF_BROADCAST) &&
- rt->rt_dev->pa_brdaddr == daddr)
- break;
- }
-
- if(src_addr!=NULL)
- *src_addr= rt->rt_dev->pa_addr;
-
- if (daddr == rt->rt_dev->pa_addr) {
- if ((rt = rt_loopback) == NULL)
- goto no_route;
- }
- rt->rt_use++;
- return rt;
-no_route:
- return NULL;
-}
-
-/*
- * Backwards compatibility
- */
-
-static int ip_get_old_rtent(struct old_rtentry * src, struct rtentry * rt)
-{
- int err;
- struct old_rtentry tmp;
-
- err=verify_area(VERIFY_READ, src, sizeof(*src));
- if (err)
- return err;
- memcpy_fromfs(&tmp, src, sizeof(*src));
- memset(rt, 0, sizeof(*rt));
- rt->rt_dst = tmp.rt_dst;
- rt->rt_gateway = tmp.rt_gateway;
- rt->rt_genmask.sa_family = AF_INET;
- ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask;
- rt->rt_flags = tmp.rt_flags;
- rt->rt_dev = tmp.rt_dev;
- printk("Warning: obsolete routing request made.\n");
- return 0;
-}
-
-#ifndef _HURD_
-/*
- * Handle IP routing ioctl calls. These are used to manipulate the routing tables
- */
-
-int ip_rt_ioctl(unsigned int cmd, void *arg)
-{
- int err;
- struct rtentry rt;
-
- switch(cmd)
- {
- case SIOCADDRTOLD: /* Old style add route */
- case SIOCDELRTOLD: /* Old style delete route */
- if (!suser())
- return -EPERM;
- err = ip_get_old_rtent((struct old_rtentry *) arg, &rt);
- if (err)
- return err;
- return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt);
-
- case SIOCADDRT: /* Add a route */
- case SIOCDELRT: /* Delete a route */
- if (!suser())
- return -EPERM;
- err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
- if (err)
- return err;
- memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
- return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
- }
-
- return -EINVAL;
-}
-#endif
diff --git a/pfinet/linux-inet/route.h b/pfinet/linux-inet/route.h
deleted file mode 100644
index e43efa4e..00000000
--- a/pfinet/linux-inet/route.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the IP router.
- *
- * Version: @(#)route.h 1.0.4 05/27/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Fixes:
- * Alan Cox : Reformatted. Added ip_rt_local()
- * Alan Cox : Support for TCP parameters.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _ROUTE_H
-#define _ROUTE_H
-
-
-#include <linux/route.h>
-
-
-/* This is an entry in the IP routing table. */
-struct rtable
-{
- struct rtable *rt_next;
- unsigned long rt_dst;
- unsigned long rt_mask;
- unsigned long rt_gateway;
- unsigned char rt_flags;
- unsigned char rt_metric;
- short rt_refcnt;
- unsigned long rt_use;
- unsigned short rt_mss;
- unsigned long rt_window;
- struct device *rt_dev;
-};
-
-
-extern void ip_rt_flush(struct device *dev);
-extern void ip_rt_add(short flags, unsigned long addr, unsigned long mask,
- unsigned long gw, struct device *dev, unsigned short mss, unsigned long window);
-extern void ip_rt_del(unsigned long dst, struct device *dev);
-extern struct rtable *ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr);
-extern struct rtable *ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr);
-extern int rt_get_info(char * buffer, char **start, off_t offset, int length);
-extern int ip_rt_ioctl(unsigned int cmd, void *arg);
-
-#endif /* _ROUTE_H */
diff --git a/pfinet/linux-inet/skbuff.c b/pfinet/linux-inet/skbuff.c
deleted file mode 100644
index e4e1d247..00000000
--- a/pfinet/linux-inet/skbuff.c
+++ /dev/null
@@ -1,573 +0,0 @@
-/*
- * Routines having to do with the 'struct sk_buff' memory handlers.
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
- * Florian La Roche <rzsfl@rz.uni-sb.de>
- *
- * Fixes:
- * Alan Cox : Fixed the worst of the load balancer bugs.
- * Dave Platt : Interrupt stacking fix
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-/*
- * Note: There are a load of cli()/sti() pairs protecting the net_memory type
- * variables. Without them for some reason the ++/-- operators do not come out
- * atomic. Also with gcc 2.4.5 these counts can come out wrong anyway - use 2.5.8!!
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include <linux/string.h>
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-
-
-/*
- * Resource tracking variables
- */
-
-volatile unsigned long net_memory = 0;
-volatile unsigned long net_skbcount = 0;
-volatile unsigned long net_locked = 0;
-volatile unsigned long net_allocs = 0;
-volatile unsigned long net_fails = 0;
-volatile unsigned long net_free_locked = 0;
-
-void show_net_buffers(void)
-{
- printk("Networking buffers in use : %lu\n",net_skbcount);
- printk("Memory committed to network buffers: %lu\n",net_memory);
- printk("Network buffers locked by drivers : %lu\n",net_locked);
- printk("Total network buffer allocations : %lu\n",net_allocs);
- printk("Total failed network buffer allocs : %lu\n",net_fails);
- printk("Total free while locked events : %lu\n",net_free_locked);
-}
-
-#if CONFIG_SKB_CHECK
-
-/*
- * Debugging paranoia. Can go later when this crud stack works
- */
-
-int skb_check(struct sk_buff *skb, int head, int line, char *file)
-{
- if (head) {
- if (skb->magic_debug_cookie != SK_HEAD_SKB) {
- printk("File: %s Line %d, found a bad skb-head\n",
- file,line);
- return -1;
- }
- if (!skb->next || !skb->prev) {
- printk("skb_check: head without next or prev\n");
- return -1;
- }
- if (skb->next->magic_debug_cookie != SK_HEAD_SKB
- && skb->next->magic_debug_cookie != SK_GOOD_SKB) {
- printk("File: %s Line %d, bad next head-skb member\n",
- file,line);
- return -1;
- }
- if (skb->prev->magic_debug_cookie != SK_HEAD_SKB
- && skb->prev->magic_debug_cookie != SK_GOOD_SKB) {
- printk("File: %s Line %d, bad prev head-skb member\n",
- file,line);
- return -1;
- }
-#if 0
- {
- struct sk_buff *skb2 = skb->next;
- int i = 0;
- while (skb2 != skb && i < 5) {
- if (skb_check(skb2, 0, line, file) < 0) {
- printk("bad queue element in whole queue\n");
- return -1;
- }
- i++;
- skb2 = skb2->next;
- }
- }
-#endif
- return 0;
- }
- if (skb->next != NULL && skb->next->magic_debug_cookie != SK_HEAD_SKB
- && skb->next->magic_debug_cookie != SK_GOOD_SKB) {
- printk("File: %s Line %d, bad next skb member\n",
- file,line);
- return -1;
- }
- if (skb->prev != NULL && skb->prev->magic_debug_cookie != SK_HEAD_SKB
- && skb->prev->magic_debug_cookie != SK_GOOD_SKB) {
- printk("File: %s Line %d, bad prev skb member\n",
- file,line);
- return -1;
- }
-
-
- if(skb->magic_debug_cookie==SK_FREED_SKB)
- {
- printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
- file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, free=%d\n",
- skb,skb->truesize,skb->mem_len,skb->free);
- return -1;
- }
- if(skb->magic_debug_cookie!=SK_GOOD_SKB)
- {
- printk("File: %s Line %d, passed a non skb!\n", file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, free=%d\n",
- skb,skb->truesize,skb->mem_len,skb->free);
- return -1;
- }
- if(skb->mem_len!=skb->truesize)
- {
- printk("File: %s Line %d, Dubious size setting!\n",file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld\n",
- skb,skb->truesize,skb->mem_len);
- return -1;
- }
- /* Guess it might be acceptable then */
- return 0;
-}
-#endif
-
-
-#ifdef CONFIG_SKB_CHECK
-void skb_queue_head_init(struct sk_buff_head *list)
-{
- list->prev = (struct sk_buff *)list;
- list->next = (struct sk_buff *)list;
- list->magic_debug_cookie = SK_HEAD_SKB;
-}
-
-
-/*
- * Insert an sk_buff at the start of a list.
- */
-void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk)
-{
- unsigned long flags;
- struct sk_buff *list = (struct sk_buff *)list_;
-
- save_flags(flags);
- cli();
-
- IS_SKB(newsk);
- IS_SKB_HEAD(list);
- if (newsk->next || newsk->prev)
- printk("Suspicious queue head: sk_buff on list!\n");
-
- newsk->next = list->next;
- newsk->prev = list;
-
- newsk->next->prev = newsk;
- newsk->prev->next = newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Insert an sk_buff at the end of a list.
- */
-void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
-{
- unsigned long flags;
- struct sk_buff *list = (struct sk_buff *)list_;
-
- save_flags(flags);
- cli();
-
- if (newsk->next || newsk->prev)
- printk("Suspicious queue tail: sk_buff on list!\n");
- IS_SKB(newsk);
- IS_SKB_HEAD(list);
-
- newsk->next = list;
- newsk->prev = list->prev;
-
- newsk->next->prev = newsk;
- newsk->prev->next = newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Remove an sk_buff from a list. This routine is also interrupt safe
- * so you can grab read and free buffers as another process adds them.
- */
-
-struct sk_buff *skb_dequeue(struct sk_buff_head *list_)
-{
- long flags;
- struct sk_buff *result;
- struct sk_buff *list = (struct sk_buff *)list_;
-
- save_flags(flags);
- cli();
-
- IS_SKB_HEAD(list);
-
- result = list->next;
- if (result == list) {
- restore_flags(flags);
- return NULL;
- }
-
- result->next->prev = list;
- list->next = result->next;
-
- result->next = NULL;
- result->prev = NULL;
-
- restore_flags(flags);
-
- IS_SKB(result);
- return result;
-}
-
-/*
- * Insert a packet before another one in a list.
- */
-void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- IS_SKB(old);
- IS_SKB(newsk);
-
- if(!old->next || !old->prev)
- printk("insert before unlisted item!\n");
- if(newsk->next || newsk->prev)
- printk("inserted item is already on a list.\n");
-
- save_flags(flags);
- cli();
- newsk->next = old;
- newsk->prev = old->prev;
- old->prev = newsk;
- newsk->prev->next = newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Place a packet after a given packet in a list.
- */
-void skb_append(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- IS_SKB(old);
- IS_SKB(newsk);
-
- if(!old->next || !old->prev)
- printk("append before unlisted item!\n");
- if(newsk->next || newsk->prev)
- printk("append item is already on a list.\n");
-
- save_flags(flags);
- cli();
-
- newsk->prev = old;
- newsk->next = old->next;
- newsk->next->prev = newsk;
- old->next = newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Remove an sk_buff from its list. Works even without knowing the list it
- * is sitting on, which can be handy at times. It also means that THE LIST
- * MUST EXIST when you unlink. Thus a list must have its contents unlinked
- * _FIRST_.
- */
-void skb_unlink(struct sk_buff *skb)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- IS_SKB(skb);
-
- if(skb->prev && skb->next)
- {
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
- skb->next = NULL;
- skb->prev = NULL;
- }
-#ifdef PARANOID_BUGHUNT_MODE /* This is legal but we sometimes want to watch it */
- else
- printk("skb_unlink: not a linked element\n");
-#endif
- restore_flags(flags);
-}
-
-#endif
-
-/*
- * Free an sk_buff. This still knows about things it should
- * not need to like protocols and sockets.
- */
-
-void kfree_skb(struct sk_buff *skb, int rw)
-{
- if (skb == NULL)
- {
- printk("kfree_skb: skb = NULL (from %p)\n",
- __builtin_return_address(0));
- return;
- }
-#ifdef CONFIG_SKB_CHECK
- IS_SKB(skb);
-#endif
- if (skb->lock)
- {
- skb->free = 3; /* Free when unlocked */
- net_free_locked++;
- return;
- }
- if (skb->free == 2)
- printk("Warning: kfree_skb passed an skb that nobody set the free flag on! (from %p)\n",
- __builtin_return_address(0));
- if (skb->next)
- printk("Warning: kfree_skb passed an skb still on a list (from %p).\n",
- __builtin_return_address(0));
- if (skb->sk)
- {
- if(skb->sk->prot!=NULL)
- {
- if (rw)
- skb->sk->prot->rfree(skb->sk, skb, skb->mem_len);
- else
- skb->sk->prot->wfree(skb->sk, skb, skb->mem_len);
-
- }
- else
- {
- unsigned long flags;
- /* Non INET - default wmalloc/rmalloc handler */
- save_flags(flags);
- cli();
- if (rw)
- skb->sk->rmem_alloc-=skb->mem_len;
- else
- skb->sk->wmem_alloc-=skb->mem_len;
- restore_flags(flags);
- if(!skb->sk->dead)
- skb->sk->write_space(skb->sk);
- kfree_skbmem(skb,skb->mem_len);
- }
- }
- else
- kfree_skbmem(skb, skb->mem_len);
-}
-
-/*
- * Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
- * fields and also do memory statistics to find all the [BEEP] leaks.
- */
-struct sk_buff *alloc_skb(unsigned int size,int priority)
-{
- struct sk_buff *skb;
- unsigned long flags;
-
- if (intr_count && priority!=GFP_ATOMIC) {
- static int count = 0;
- if (++count < 5) {
- printk("alloc_skb called nonatomically from interrupt %p\n",
- __builtin_return_address(0));
- priority = GFP_ATOMIC;
- }
- }
-
- size+=sizeof(struct sk_buff);
- skb=(struct sk_buff *)kmalloc(size,priority);
- if (skb == NULL)
- {
- net_fails++;
- return NULL;
- }
-#ifdef PARANOID_BUGHUNT_MODE
- if(skb->magic_debug_cookie == SK_GOOD_SKB)
- printk("Kernel kmalloc handed us an existing skb (%p)\n",skb);
-#endif
-
- net_allocs++;
-
- skb->free = 2; /* Invalid so we pick up forgetful users */
- skb->lock = 0;
- skb->pkt_type = PACKET_HOST; /* Default type */
- skb->truesize = size;
- skb->mem_len = size;
- skb->mem_addr = skb;
-#ifdef CONFIG_SLAVE_BALANCING
- skb->in_dev_queue = 0;
-#endif
- skb->fraglist = NULL;
- skb->prev = skb->next = NULL;
- skb->link3 = NULL;
- skb->sk = NULL;
- skb->localroute=0;
- skb->stamp.tv_sec=0; /* No idea about time */
- skb->localroute = 0;
- save_flags(flags);
- cli();
- net_memory += size;
- net_skbcount++;
- restore_flags(flags);
-#if CONFIG_SKB_CHECK
- skb->magic_debug_cookie = SK_GOOD_SKB;
-#endif
- skb->users = 0;
- return skb;
-}
-
-/*
- * Free an skbuff by memory
- */
-
-void kfree_skbmem(struct sk_buff *skb,unsigned size)
-{
- unsigned long flags;
-#ifdef CONFIG_SLAVE_BALANCING
- save_flags(flags);
- cli();
- if(skb->in_dev_queue && skb->dev!=NULL)
- skb->dev->pkt_queue--;
- restore_flags(flags);
-#endif
-#ifdef CONFIG_SKB_CHECK
- IS_SKB(skb);
- if(size!=skb->truesize)
- printk("kfree_skbmem: size mismatch.\n");
-
- if(skb->magic_debug_cookie == SK_GOOD_SKB)
- {
- save_flags(flags);
- cli();
- IS_SKB(skb);
- skb->magic_debug_cookie = SK_FREED_SKB;
- kfree_s((void *)skb,size);
- net_skbcount--;
- net_memory -= size;
- restore_flags(flags);
- }
- else
- printk("kfree_skbmem: bad magic cookie\n");
-#else
- save_flags(flags);
- cli();
- kfree_s((void *)skb,size);
- net_skbcount--;
- net_memory -= size;
- restore_flags(flags);
-#endif
-}
-
-/*
- * Duplicate an sk_buff. The new one is not owned by a socket or locked
- * and will be freed on deletion.
- */
-
-struct sk_buff *skb_clone(struct sk_buff *skb, int priority)
-{
- struct sk_buff *n;
- unsigned long offset;
-
- n=alloc_skb(skb->mem_len-sizeof(struct sk_buff),priority);
- if(n==NULL)
- return NULL;
-
- offset=((char *)n)-((char *)skb);
-
- memcpy(n->data,skb->data,skb->mem_len-sizeof(struct sk_buff));
- n->len=skb->len;
- n->link3=NULL;
- n->sk=NULL;
- n->when=skb->when;
- n->dev=skb->dev;
- n->h.raw=skb->h.raw+offset;
- n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
- n->fraglen=skb->fraglen;
- n->fraglist=skb->fraglist;
- n->saddr=skb->saddr;
- n->daddr=skb->daddr;
- n->raddr=skb->raddr;
- n->acked=skb->acked;
- n->used=skb->used;
- n->free=1;
- n->arp=skb->arp;
- n->tries=0;
- n->lock=0;
- n->users=0;
- n->pkt_type=skb->pkt_type;
- return n;
-}
-
-
-/*
- * Skbuff device locking
- */
-
-void skb_device_lock(struct sk_buff *skb)
-{
- if(skb->lock)
- printk("double lock on device queue!\n");
- else
- net_locked++;
- skb->lock++;
-}
-
-void skb_device_unlock(struct sk_buff *skb)
-{
- if(skb->lock==0)
- printk("double unlock on device queue!\n");
- skb->lock--;
- if(skb->lock==0)
- net_locked--;
-}
-
-void dev_kfree_skb(struct sk_buff *skb, int mode)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if(skb->lock==1)
- net_locked--;
-
- if (!--skb->lock && (skb->free == 1 || skb->free == 3))
- {
- restore_flags(flags);
- kfree_skb(skb,mode);
- }
- else
- restore_flags(flags);
-}
-
-int skb_device_locked(struct sk_buff *skb)
-{
- return skb->lock? 1 : 0;
-}
-
diff --git a/pfinet/linux-inet/sock.c b/pfinet/linux-inet/sock.c
deleted file mode 100644
index 40d4a8f4..00000000
--- a/pfinet/linux-inet/sock.c
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Generic socket support routines. Memory allocators, sk->inuse/release
- * handler for protocols to use and generic option handler.
- *
- *
- * Version: @(#)sock.c 1.0.17 06/02/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Florian La Roche, <flla@stud.uni-sb.de>
- * Alan Cox, <A.Cox@swansea.ac.uk>
- *
- * Fixes:
- * Alan Cox : Numerous verify_area() problems
- * Alan Cox : Connecting on a connecting socket
- * now returns an error for tcp.
- * Alan Cox : sock->protocol is set correctly.
- * and is not sometimes left as 0.
- * Alan Cox : connect handles icmp errors on a
- * connect properly. Unfortunately there
- * is a restart syscall nasty there. I
- * can't match BSD without hacking the C
- * library. Ideas urgently sought!
- * Alan Cox : Disallow bind() to addresses that are
- * not ours - especially broadcast ones!!
- * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost)
- * Alan Cox : sock_wfree/sock_rfree don't destroy sockets,
- * instead they leave that for the DESTROY timer.
- * Alan Cox : Clean up error flag in accept
- * Alan Cox : TCP ack handling is buggy, the DESTROY timer
- * was buggy. Put a remove_sock() in the handler
- * for memory when we hit 0. Also altered the timer
- * code. The ACK stuff can wait and needs major
- * TCP layer surgery.
- * Alan Cox : Fixed TCP ack bug, removed remove sock
- * and fixed timer/inet_bh race.
- * Alan Cox : Added zapped flag for TCP
- * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code
- * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
- * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources
- * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing.
- * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so...
- * Rick Sladkey : Relaxed UDP rules for matching packets.
- * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support
- * Pauline Middelink : identd support
- * Alan Cox : Fixed connect() taking signals I think.
- * Alan Cox : SO_LINGER supported
- * Alan Cox : Error reporting fixes
- * Anonymous : inet_create tidied up (sk->reuse setting)
- * Alan Cox : inet sockets don't set sk->type!
- * Alan Cox : Split socket option code
- * Alan Cox : Callbacks
- * Alan Cox : Nagle flag for Charles & Johannes stuff
- * Alex : Removed restriction on inet fioctl
- * Alan Cox : Splitting INET from NET core
- * Alan Cox : Fixed bogus SO_TYPE handling in getsockopt()
- * Adam Caldwell : Missing return in SO_DONTROUTE/SO_DEBUG code
- * Alan Cox : Split IP from generic code
- * Alan Cox : New kfree_skbmem()
- * Alan Cox : Make SO_DEBUG superuser only.
- * Alan Cox : Allow anyone to clear SO_DEBUG
- * (compatibility fix)
- *
- * To Fix:
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "rarp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "raw.h"
-#include "icmp.h"
-
-#define min(a,b) ((a)<(b)?(a):(b))
-
-/*
- * This is meant for all protocols to use and covers goings on
- * at the socket level. Everything here is generic.
- */
-
-int sock_setsockopt(struct sock *sk, int level, int optname,
- char *optval, int optlen)
-{
- int val;
- int err;
- struct linger ling;
-
- if (optval == NULL)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ, optval, sizeof(int));
- if(err)
- return err;
-
- val = get_fs_long((unsigned long *)optval);
- switch(optname)
- {
- case SO_TYPE:
- case SO_ERROR:
- return(-ENOPROTOOPT);
-
- case SO_DEBUG:
- if(val && !suser())
- return(-EPERM);
- sk->debug=val?1:0;
- return 0;
- case SO_DONTROUTE:
- sk->localroute=val?1:0;
- return 0;
- case SO_BROADCAST:
- sk->broadcast=val?1:0;
- return 0;
- case SO_SNDBUF:
- if(val>32767)
- val=32767;
- if(val<256)
- val=256;
- sk->sndbuf=val;
- return 0;
- case SO_LINGER:
- err=verify_area(VERIFY_READ,optval,sizeof(ling));
- if(err)
- return err;
- memcpy_fromfs(&ling,optval,sizeof(ling));
- if(ling.l_onoff==0)
- sk->linger=0;
- else
- {
- sk->lingertime=ling.l_linger;
- sk->linger=1;
- }
- return 0;
- case SO_RCVBUF:
- if(val>32767)
- val=32767;
- if(val<256)
- val=256;
- sk->rcvbuf=val;
- return(0);
-
- case SO_REUSEADDR:
- if (val)
- sk->reuse = 1;
- else
- sk->reuse = 0;
- return(0);
-
- case SO_KEEPALIVE:
- if (val)
- sk->keepopen = 1;
- else
- sk->keepopen = 0;
- return(0);
-
- case SO_OOBINLINE:
- if (val)
- sk->urginline = 1;
- else
- sk->urginline = 0;
- return(0);
-
- case SO_NO_CHECK:
- if (val)
- sk->no_check = 1;
- else
- sk->no_check = 0;
- return(0);
-
- case SO_PRIORITY:
- if (val >= 0 && val < DEV_NUMBUFFS)
- {
- sk->priority = val;
- }
- else
- {
- return(-EINVAL);
- }
- return(0);
-
- default:
- return(-ENOPROTOOPT);
- }
-}
-
-
-int sock_getsockopt(struct sock *sk, int level, int optname,
- char *optval, int *optlen)
-{
- int val;
- int err;
- struct linger ling;
-
- switch(optname)
- {
- case SO_DEBUG:
- val = sk->debug;
- break;
-
- case SO_DONTROUTE:
- val = sk->localroute;
- break;
-
- case SO_BROADCAST:
- val= sk->broadcast;
- break;
-
- case SO_LINGER:
- err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
- if(err)
- return err;
- err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(ling),(unsigned long *)optlen);
- ling.l_onoff=sk->linger;
- ling.l_linger=sk->lingertime;
- memcpy_tofs(optval,&ling,sizeof(ling));
- return 0;
-
- case SO_SNDBUF:
- val=sk->sndbuf;
- break;
-
- case SO_RCVBUF:
- val =sk->rcvbuf;
- break;
-
- case SO_REUSEADDR:
- val = sk->reuse;
- break;
-
- case SO_KEEPALIVE:
- val = sk->keepopen;
- break;
-
- case SO_TYPE:
-#if 0
- if (sk->prot == &tcp_prot)
- val = SOCK_STREAM;
- else
- val = SOCK_DGRAM;
-#endif
- val = sk->type;
- break;
-
- case SO_ERROR:
- val = sk->err;
- sk->err = 0;
- break;
-
- case SO_OOBINLINE:
- val = sk->urginline;
- break;
-
- case SO_NO_CHECK:
- val = sk->no_check;
- break;
-
- case SO_PRIORITY:
- val = sk->priority;
- break;
-
- default:
- return(-ENOPROTOOPT);
- }
- err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(int),(unsigned long *) optlen);
-
- err=verify_area(VERIFY_WRITE, optval, sizeof(int));
- if(err)
- return err;
- put_fs_long(val,(unsigned long *)optval);
-
- return(0);
-}
-
-
-struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
-{
- if (sk)
- {
- if (sk->wmem_alloc + size < sk->sndbuf || force)
- {
- struct sk_buff * c = alloc_skb(size, priority);
- if (c)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- sk->wmem_alloc+= c->mem_len;
- restore_flags(flags); /* was sti(); */
- }
- return c;
- }
- return(NULL);
- }
- return(alloc_skb(size, priority));
-}
-
-
-struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
-{
- if (sk)
- {
- if (sk->rmem_alloc + size < sk->rcvbuf || force)
- {
- struct sk_buff *c = alloc_skb(size, priority);
- if (c)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- sk->rmem_alloc += c->mem_len;
- restore_flags(flags); /* was sti(); */
- }
- return(c);
- }
- return(NULL);
- }
- return(alloc_skb(size, priority));
-}
-
-
-unsigned long sock_rspace(struct sock *sk)
-{
- int amt;
-
- if (sk != NULL)
- {
- if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW)
- return(0);
- amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
- if (amt < 0)
- return(0);
- return(amt);
- }
- return(0);
-}
-
-
-unsigned long sock_wspace(struct sock *sk)
-{
- if (sk != NULL)
- {
- if (sk->shutdown & SEND_SHUTDOWN)
- return(0);
- if (sk->wmem_alloc >= sk->sndbuf)
- return(0);
- return(sk->sndbuf-sk->wmem_alloc );
- }
- return(0);
-}
-
-
-void sock_wfree(struct sock *sk, struct sk_buff *skb, unsigned long size)
-{
-#ifdef CONFIG_SKB_CHECK
- IS_SKB(skb);
-#endif
- kfree_skbmem(skb, size);
- if (sk)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- sk->wmem_alloc -= size;
- restore_flags(flags);
- /* In case it might be waiting for more memory. */
- if (!sk->dead)
- sk->write_space(sk);
- return;
- }
-}
-
-
-void sock_rfree(struct sock *sk, struct sk_buff *skb, unsigned long size)
-{
-#ifdef CONFIG_SKB_CHECK
- IS_SKB(skb);
-#endif
- kfree_skbmem(skb, size);
- if (sk)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- sk->rmem_alloc -= size;
- restore_flags(flags);
- }
-}
-
-/*
- * Generic send/receive buffer handlers
- */
-
-struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, int noblock, int *errcode)
-{
- struct sk_buff *skb;
- int err;
-
- sk->inuse=1;
-
- do
- {
- if(sk->err!=0)
- {
- cli();
- err= -sk->err;
- sk->err=0;
- sti();
- *errcode=err;
- return NULL;
- }
-
- if(sk->shutdown&SEND_SHUTDOWN)
- {
- *errcode=-EPIPE;
- return NULL;
- }
-
- skb = sock_wmalloc(sk, size, 0, GFP_KERNEL);
-
- if(skb==NULL)
- {
- unsigned long tmp;
-
- sk->socket->flags |= SO_NOSPACE;
- if(noblock)
- {
- *errcode=-EAGAIN;
- return NULL;
- }
- if(sk->shutdown&SEND_SHUTDOWN)
- {
- *errcode=-EPIPE;
- return NULL;
- }
- tmp = sk->wmem_alloc;
- cli();
- if(sk->shutdown&SEND_SHUTDOWN)
- {
- sti();
- *errcode=-EPIPE;
- return NULL;
- }
-
- if( tmp <= sk->wmem_alloc)
- {
- sk->socket->flags &= ~SO_NOSPACE;
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- *errcode = -ERESTARTSYS;
- return NULL;
- }
- }
- sti();
- }
- }
- while(skb==NULL);
-
- return skb;
-}
-
-/*
- * Queue a received datagram if it will fit. Stream and sequenced protocols
- * can't normally use this as they need to fit buffers in and play with them.
- */
-
-int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
-{
- unsigned long flags;
- if(sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- return -ENOMEM;
- save_flags(flags);
- cli();
- sk->rmem_alloc+=skb->mem_len;
- skb->sk=sk;
- restore_flags(flags);
- skb_queue_tail(&sk->receive_queue,skb);
- if(!sk->dead)
- sk->data_ready(sk,skb->len);
- return 0;
-}
-
-void release_sock(struct sock *sk)
-{
- unsigned long flags;
-#ifdef CONFIG_INET
- struct sk_buff *skb;
-#endif
-
- if (!sk->prot)
- return;
- /*
- * Make the backlog atomic. If we don't do this there is a tiny
- * window where a packet may arrive between the sk->blog being
- * tested and then set with sk->inuse still 0 causing an extra
- * unwanted re-entry into release_sock().
- */
-
- save_flags(flags);
- cli();
- if (sk->blog)
- {
- restore_flags(flags);
- return;
- }
- sk->blog=1;
- sk->inuse = 1;
- restore_flags(flags);
-#ifdef CONFIG_INET
- /* See if we have any packets built up. */
- while((skb = skb_dequeue(&sk->back_log)) != NULL)
- {
- sk->blog = 1;
- if (sk->prot->rcv)
- sk->prot->rcv(skb, skb->dev, sk->opt,
- skb->saddr, skb->len, skb->daddr, 1,
- /* Only used for/by raw sockets. */
- (struct inet_protocol *)sk->pair);
- }
-#endif
- sk->blog = 0;
- sk->inuse = 0;
-#ifdef CONFIG_INET
- if (sk->dead && sk->state == TCP_CLOSE)
- {
- /* Should be about 2 rtt's */
- reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
- }
-#endif
-}
-
-
diff --git a/pfinet/linux-inet/sock.h b/pfinet/linux-inet/sock.h
deleted file mode 100644
index 2005745e..00000000
--- a/pfinet/linux-inet/sock.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the AF_INET socket handler.
- *
- * Version: @(#)sock.h 1.0.4 05/13/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- * Florian La Roche <flla@stud.uni-sb.de>
- *
- * Fixes:
- * Alan Cox : Volatiles in skbuff pointers. See
- * skbuff comments. May be overdone,
- * better to prove they can be removed
- * than the reverse.
- * Alan Cox : Added a zapped field for tcp to note
- * a socket is reset and must stay shut up
- * Alan Cox : New fields for options
- * Pauline Middelink : identd support
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _SOCK_H
-#define _SOCK_H
-
-#include <linux/timer.h>
-#include <linux/ip.h> /* struct options */
-#include <linux/tcp.h> /* struct tcphdr */
-#include <linux/config.h>
-
-#include <linux/skbuff.h> /* struct sk_buff */
-#include "protocol.h" /* struct inet_protocol */
-#ifdef CONFIG_AX25
-#include "ax25.h"
-#endif
-#ifdef CONFIG_IPX
-#include "ipx.h"
-#endif
-#ifdef CONFIG_ATALK
-#include <linux/atalk.h>
-#endif
-
-#include <linux/igmp.h>
-
-#define SOCK_ARRAY_SIZE 256 /* Think big (also on some systems a byte is faster */
-
-
-/*
- * This structure really needs to be cleaned up.
- * Most of it is for TCP, and not used by any of
- * the other protocols.
- */
-struct sock {
- struct options *opt;
- volatile unsigned long wmem_alloc;
- volatile unsigned long rmem_alloc;
- unsigned long write_seq;
- unsigned long sent_seq;
- unsigned long acked_seq;
- unsigned long copied_seq;
- unsigned long rcv_ack_seq;
- unsigned long window_seq;
- unsigned long fin_seq;
- unsigned long urg_seq;
- unsigned long urg_data;
-
- /*
- * Not all are volatile, but some are, so we
- * might as well say they all are.
- */
- volatile char inuse,
- dead,
- urginline,
- intr,
- blog,
- done,
- reuse,
- keepopen,
- linger,
- delay_acks,
- destroy,
- ack_timed,
- no_check,
- zapped, /* In ax25 & ipx means not linked */
- broadcast,
- nonagle;
- unsigned long lingertime;
- int proc;
- struct sock *next;
- struct sock *prev; /* Doubly linked chain.. */
- struct sock *pair;
- struct sk_buff * volatile send_head;
- struct sk_buff * volatile send_tail;
- struct sk_buff_head back_log;
- struct sk_buff *partial;
- struct timer_list partial_timer;
- long retransmits;
- struct sk_buff_head write_queue,
- receive_queue;
- struct proto *prot;
- struct wait_queue **sleep;
- unsigned long daddr;
- unsigned long saddr;
- unsigned short max_unacked;
- unsigned short window;
- unsigned short bytes_rcv;
-/* mss is min(mtu, max_window) */
- unsigned short mtu; /* mss negotiated in the syn's */
- volatile unsigned short mss; /* current eff. mss - can change */
- volatile unsigned short user_mss; /* mss requested by user in ioctl */
- volatile unsigned short max_window;
- unsigned long window_clamp;
- unsigned short num;
- volatile unsigned short cong_window;
- volatile unsigned short cong_count;
- volatile unsigned short ssthresh;
- volatile unsigned short packets_out;
- volatile unsigned short shutdown;
- volatile unsigned long rtt;
- volatile unsigned long mdev;
- volatile unsigned long rto;
-/* currently backoff isn't used, but I'm maintaining it in case
- * we want to go back to a backoff formula that needs it
- */
- volatile unsigned short backoff;
- volatile error_t err; /* Note change XXX HURD */
- unsigned char protocol;
- volatile unsigned char state;
- volatile unsigned char ack_backlog;
- unsigned char max_ack_backlog;
- unsigned char priority;
- unsigned char debug;
- unsigned short rcvbuf;
- unsigned short sndbuf;
- unsigned short type;
- unsigned char localroute; /* Route locally only */
-#ifdef CONFIG_IPX
- ipx_address ipx_dest_addr;
- ipx_interface *ipx_intrfc;
- unsigned short ipx_port;
- unsigned short ipx_type;
-#endif
-#ifdef CONFIG_AX25
-/* Really we want to add a per protocol private area */
- ax25_address ax25_source_addr,ax25_dest_addr;
- struct sk_buff *volatile ax25_retxq[8];
- char ax25_state,ax25_vs,ax25_vr,ax25_lastrxnr,ax25_lasttxnr;
- char ax25_condition;
- char ax25_retxcnt;
- char ax25_xx;
- char ax25_retxqi;
- char ax25_rrtimer;
- char ax25_timer;
- unsigned char ax25_n2;
- unsigned short ax25_t1,ax25_t2,ax25_t3;
- ax25_digi *ax25_digipeat;
-#endif
-#ifdef CONFIG_ATALK
- struct atalk_sock at;
-#endif
-
-/* IP 'private area' or will be eventually */
- int ip_ttl; /* TTL setting */
- int ip_tos; /* TOS */
- struct tcphdr dummy_th;
- struct timer_list keepalive_timer; /* TCP keepalive hack */
- struct timer_list retransmit_timer; /* TCP retransmit timer */
- struct timer_list ack_timer; /* TCP delayed ack timer */
- int ip_xmit_timeout; /* Why the timeout is running */
-#ifdef CONFIG_IP_MULTICAST
- int ip_mc_ttl; /* Multicasting TTL */
- int ip_mc_loop; /* Loopback (not implemented yet) */
- char ip_mc_name[MAX_ADDR_LEN]; /* Multicast device name */
- struct ip_mc_socklist *ip_mc_list; /* Group array */
-#endif
-
- /* This part is used for the timeout functions (timer.c). */
- int timeout; /* What are we waiting for? */
- struct timer_list timer; /* This is the TIME_WAIT/receive timer when we are doing IP */
- struct timeval stamp;
-
- /* identd */
- struct socket *socket;
-
- /* Callbacks */
- void (*state_change)(struct sock *sk);
- void (*data_ready)(struct sock *sk,int bytes);
- void (*write_space)(struct sock *sk);
- void (*error_report)(struct sock *sk);
-
-};
-
-struct proto {
- struct sk_buff * (*wmalloc)(struct sock *sk,
- unsigned long size, int force,
- int priority);
- struct sk_buff * (*rmalloc)(struct sock *sk,
- unsigned long size, int force,
- int priority);
- void (*wfree)(struct sock *sk, struct sk_buff *skb,
- unsigned long size);
- void (*rfree)(struct sock *sk, struct sk_buff *skb,
- unsigned long size);
- unsigned long (*rspace)(struct sock *sk);
- unsigned long (*wspace)(struct sock *sk);
- void (*close)(struct sock *sk, int timeout);
- int (*read)(struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags);
- int (*write)(struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags);
- int (*sendto)(struct sock *sk,
- unsigned char *from, int len, int noblock,
- unsigned flags, struct sockaddr_in *usin,
- int addr_len);
- int (*recvfrom)(struct sock *sk,
- unsigned char *from, int len, int noblock,
- unsigned flags, struct sockaddr_in *usin,
- int *addr_len);
- int (*build_header)(struct sk_buff *skb,
- unsigned long saddr,
- unsigned long daddr,
- struct device **dev, int type,
- struct options *opt, int len, int tos, int ttl);
- int (*connect)(struct sock *sk,
- struct sockaddr_in *usin, int addr_len);
- struct sock * (*accept) (struct sock *sk, int flags);
- void (*queue_xmit)(struct sock *sk,
- struct device *dev, struct sk_buff *skb,
- int free);
- void (*retransmit)(struct sock *sk, int all);
- void (*write_wakeup)(struct sock *sk);
- void (*read_wakeup)(struct sock *sk);
- int (*rcv)(struct sk_buff *buff, struct device *dev,
- struct options *opt, unsigned long daddr,
- unsigned short len, unsigned long saddr,
- int redo, struct inet_protocol *protocol);
- int (*select)(struct sock *sk, int which,
- select_table *wait);
- int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
- int (*init)(struct sock *sk);
- void (*shutdown)(struct sock *sk, int how);
- int (*setsockopt)(struct sock *sk, int level, int optname,
- char *optval, int optlen);
- int (*getsockopt)(struct sock *sk, int level, int optname,
- char *optval, int *option);
- unsigned short max_header;
- unsigned long retransmits;
- struct sock * sock_array[SOCK_ARRAY_SIZE];
- char name[80];
- int inuse, highestinuse;
-};
-
-#define TIME_WRITE 1
-#define TIME_CLOSE 2
-#define TIME_KEEPOPEN 3
-#define TIME_DESTROY 4
-#define TIME_DONE 5 /* used to absorb those last few packets */
-#define TIME_PROBE0 6
-#define SOCK_DESTROY_TIME 1000 /* about 10 seconds */
-
-#define PROT_SOCK 1024 /* Sockets 0-1023 can't be bound too unless you are superuser */
-
-#define SHUTDOWN_MASK 3
-#define RCV_SHUTDOWN 1
-#define SEND_SHUTDOWN 2
-
-
-extern void destroy_sock(struct sock *sk);
-extern unsigned short get_new_socknum(struct proto *, unsigned short);
-extern void put_sock(unsigned short, struct sock *);
-extern void release_sock(struct sock *sk);
-extern struct sock *get_sock(struct proto *, unsigned short,
- unsigned long, unsigned short,
- unsigned long);
-extern struct sock *get_sock_mcast(struct sock *, unsigned short,
- unsigned long, unsigned short,
- unsigned long);
-extern struct sock *get_sock_raw(struct sock *, unsigned short,
- unsigned long, unsigned long);
-
-extern struct sk_buff *sock_wmalloc(struct sock *sk,
- unsigned long size, int force,
- int priority);
-extern struct sk_buff *sock_rmalloc(struct sock *sk,
- unsigned long size, int force,
- int priority);
-extern void sock_wfree(struct sock *sk, struct sk_buff *skb,
- unsigned long size);
-extern void sock_rfree(struct sock *sk, struct sk_buff *skb,
- unsigned long size);
-extern unsigned long sock_rspace(struct sock *sk);
-extern unsigned long sock_wspace(struct sock *sk);
-
-extern int sock_setsockopt(struct sock *sk,int level,int op,char *optval,int optlen);
-
-extern int sock_getsockopt(struct sock *sk,int level,int op,char *optval,int *optlen);
-extern struct sk_buff *sock_alloc_send_skb(struct sock *skb, unsigned long size, int noblock, int *errcode);
-extern int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
-
-/* declarations from timer.c */
-extern struct sock *timer_base;
-
-void delete_timer (struct sock *);
-void reset_timer (struct sock *, int, unsigned long);
-void net_timer (unsigned long);
-
-
-#endif /* _SOCK_H */
diff --git a/pfinet/linux-inet/tcp.c b/pfinet/linux-inet/tcp.c
deleted file mode 100644
index 61ebba6c..00000000
--- a/pfinet/linux-inet/tcp.c
+++ /dev/null
@@ -1,5120 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Implementation of the Transmission Control Protocol(TCP).
- *
- * Version: @(#)tcp.c 1.0.16 05/25/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Mark Evans, <evansmp@uhura.aston.ac.uk>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- * Florian La Roche, <flla@stud.uni-sb.de>
- * Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
- * Linus Torvalds, <torvalds@cs.helsinki.fi>
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Matthew Dillon, <dillon@apollo.west.oic.com>
- * Arnt Gulbrandsen, <agulbra@no.unit.nvg>
- *
- * Fixes:
- * Alan Cox : Numerous verify_area() calls
- * Alan Cox : Set the ACK bit on a reset
- * Alan Cox : Stopped it crashing if it closed while sk->inuse=1
- * and was trying to connect (tcp_err()).
- * Alan Cox : All icmp error handling was broken
- * pointers passed where wrong and the
- * socket was looked up backwards. Nobody
- * tested any icmp error code obviously.
- * Alan Cox : tcp_err() now handled properly. It wakes people
- * on errors. select behaves and the icmp error race
- * has gone by moving it into sock.c
- * Alan Cox : tcp_reset() fixed to work for everything not just
- * packets for unknown sockets.
- * Alan Cox : tcp option processing.
- * Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong]
- * Herp Rosmanith : More reset fixes
- * Alan Cox : No longer acks invalid rst frames. Acking
- * any kind of RST is right out.
- * Alan Cox : Sets an ignore me flag on an rst receive
- * otherwise odd bits of prattle escape still
- * Alan Cox : Fixed another acking RST frame bug. Should stop
- * LAN workplace lockups.
- * Alan Cox : Some tidyups using the new skb list facilities
- * Alan Cox : sk->keepopen now seems to work
- * Alan Cox : Pulls options out correctly on accepts
- * Alan Cox : Fixed assorted sk->rqueue->next errors
- * Alan Cox : PSH doesn't end a TCP read. Switched a bit to skb ops.
- * Alan Cox : Tidied tcp_data to avoid a potential nasty.
- * Alan Cox : Added some better commenting, as the tcp is hard to follow
- * Alan Cox : Removed incorrect check for 20 * psh
- * Michael O'Reilly : ack < copied bug fix.
- * Johannes Stille : Misc tcp fixes (not all in yet).
- * Alan Cox : FIN with no memory -> CRASH
- * Alan Cox : Added socket option proto entries. Also added awareness of them to accept.
- * Alan Cox : Added TCP options (SOL_TCP)
- * Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets.
- * Alan Cox : Use ip_tos/ip_ttl settings.
- * Alan Cox : Handle FIN (more) properly (we hope).
- * Alan Cox : RST frames sent on unsynchronised state ack error/
- * Alan Cox : Put in missing check for SYN bit.
- * Alan Cox : Added tcp_select_window() aka NET2E
- * window non shrink trick.
- * Alan Cox : Added a couple of small NET2E timer fixes
- * Charles Hedrick : TCP fixes
- * Toomas Tamm : TCP window fixes
- * Alan Cox : Small URG fix to rlogin ^C ack fight
- * Charles Hedrick : Rewrote most of it to actually work
- * Linus : Rewrote tcp_read() and URG handling
- * completely
- * Gerhard Koerting: Fixed some missing timer handling
- * Matthew Dillon : Reworked TCP machine states as per RFC
- * Gerhard Koerting: PC/TCP workarounds
- * Adam Caldwell : Assorted timer/timing errors
- * Matthew Dillon : Fixed another RST bug
- * Alan Cox : Move to kernel side addressing changes.
- * Alan Cox : Beginning work on TCP fastpathing (not yet usable)
- * Arnt Gulbrandsen: Turbocharged tcp_check() routine.
- * Alan Cox : TCP fast path debugging
- * Alan Cox : Window clamping
- * Michael Riepe : Bug in tcp_check()
- * Matt Dillon : More TCP improvements and RST bug fixes
- * Matt Dillon : Yet more small nasties remove from the TCP code
- * (Be very nice to this man if tcp finally works 100%) 8)
- * Alan Cox : BSD accept semantics.
- * Alan Cox : Reset on closedown bug.
- * Peter De Schrijver : ENOTCONN check missing in tcp_sendto().
- * Michael Pall : Handle select() after URG properly in all cases.
- * Michael Pall : Undo the last fix in tcp_read_urg() (multi URG PUSH broke rlogin).
- * Michael Pall : Fix the multi URG PUSH problem in tcp_readable(), select() after URG works now.
- * Michael Pall : recv(...,MSG_OOB) never blocks in the BSD api.
- * Alan Cox : Changed the semantics of sk->socket to
- * fix a race and a signal problem with
- * accept() and async I/O.
- * Alan Cox : Relaxed the rules on tcp_sendto().
- * Yury Shevchuk : Really fixed accept() blocking problem.
- * Craig I. Hagan : Allow for BSD compatible TIME_WAIT for
- * clients/servers which listen in on
- * fixed ports.
- * Alan Cox : Cleaned the above up and shrank it to
- * a sensible code size.
- * Alan Cox : Self connect lockup fix.
- * Alan Cox : No connect to multicast.
- * Ross Biro : Close unaccepted children on master
- * socket close.
- * Alan Cox : Reset tracing code.
- * Alan Cox : Spurious resets on shutdown.
- * Alan Cox : Giant 15 minute/60 second timer error
- * Alan Cox : Small whoops in selecting before an accept.
- * Alan Cox : Kept the state trace facility since it's
- * handy for debugging.
- * Alan Cox : More reset handler fixes.
- * Alan Cox : Started rewriting the code based on the RFC's
- * for other useful protocol references see:
- * Comer, KA9Q NOS, and for a reference on the
- * difference between specifications and how BSD
- * works see the 4.4lite source.
- * A.N.Kuznetsov : Don't time wait on completion of tidy
- * close.
- * Linus Torvalds : Fin/Shutdown & copied_seq changes.
- * Linus Torvalds : Fixed BSD port reuse to work first syn
- * Alan Cox : Reimplemented timers as per the RFC and using multiple
- * timers for sanity.
- * Alan Cox : Small bug fixes, and a lot of new
- * comments.
- * Alan Cox : Fixed dual reader crash by locking
- * the buffers (much like datagram.c)
- * Alan Cox : Fixed stuck sockets in probe. A probe
- * now gets fed up of retrying without
- * (even a no space) answer.
- * Alan Cox : Extracted closing code better
- * Alan Cox : Fixed the closing state machine to
- * resemble the RFC.
- * Alan Cox : More 'per spec' fixes.
- * Alan Cox : tcp_data() doesn't ack illegal PSH
- * only frames. At least one pc tcp stack
- * generates them.
- *
- *
- * To Fix:
- * Fast path the code. Two things here - fix the window calculation
- * so it doesn't iterate over the queue, also spot packets with no funny
- * options arriving in order and process directly.
- *
- * Implement RFC 1191 [Path MTU discovery]
- * Look at the effect of implementing RFC 1337 suggestions and their impact.
- * Rewrite output state machine to use a single queue and do low window
- * situations as per the spec (RFC 1122)
- * Speed up input assembly algorithm.
- * RFC1323 - PAWS and window scaling. PAWS is required for IPv6 so we
- * could do with it working on IPv4
- * User settable/learned rtt/max window/mtu
- * Cope with MTU/device switches when retransmitting in tcp.
- * Fix the window handling to use PR's new code.
- *
- * Change the fundamental structure to a single send queue maintained
- * by TCP (removing the bogus ip stuff [thus fixing mtu drops on
- * active routes too]). Cut the queue off in tcp_retransmit/
- * tcp_transmit.
- * Change the receive queue to assemble as it goes. This lets us
- * dispose of most of tcp_sequence, half of tcp_ack and chunks of
- * tcp_data/tcp_read as well as the window shrink crud.
- * Separate out duplicated code - tcp_alloc_skb, tcp_build_ack
- * tcp_queue_skb seem obvious routines to extract.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or(at your option) any later version.
- *
- * Description of States:
- *
- * TCP_SYN_SENT sent a connection request, waiting for ack
- *
- * TCP_SYN_RECV received a connection request, sent ack,
- * waiting for final ack in three-way handshake.
- *
- * TCP_ESTABLISHED connection established
- *
- * TCP_FIN_WAIT1 our side has shutdown, waiting to complete
- * transmission of remaining buffered data
- *
- * TCP_FIN_WAIT2 all buffered data sent, waiting for remote
- * to shutdown
- *
- * TCP_CLOSING both sides have shutdown but we still have
- * data we have to finish sending
- *
- * TCP_TIME_WAIT timeout to catch resent junk before entering
- * closed, can only be entered from FIN_WAIT2
- * or CLOSING. Required because the other end
- * may not have gotten our last ACK causing it
- * to retransmit the data packet (which we ignore)
- *
- * TCP_CLOSE_WAIT remote side has shutdown and is waiting for
- * us to finish writing our data and to shutdown
- * (we have to close() to move on to LAST_ACK)
- *
- * TCP_LAST_ACK out side has shutdown after remote has
- * shutdown. There may still be data in our
- * buffer that we have to finish sending
- *
- * TCP_CLOSE socket is finished
- */
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/time.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/termios.h>
-#include <linux/in.h>
-#include <linux/fcntl.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "snmp.h"
-#include "ip.h"
-#include "protocol.h"
-#include "icmp.h"
-#include "tcp.h"
-#include "arp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "route.h"
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/mm.h>
-
-/*
- * The MSL timer is the 'normal' timer.
- */
-
-#define reset_msl_timer(x,y,z) reset_timer(x,y,z)
-
-#define SEQ_TICK 3
-unsigned long seq_offset;
-struct tcp_mib tcp_statistics;
-
-static void tcp_close(struct sock *sk, int timeout);
-
-
-/*
- * The less said about this the better, but it works and will do for 1.2
- */
-
-static struct wait_queue *master_select_wakeup;
-
-static __inline__ int min(unsigned int a, unsigned int b)
-{
- if (a < b)
- return(a);
- return(b);
-}
-
-#undef STATE_TRACE
-
-#ifdef STATE_TRACE
-static char *statename[]={
- "Unused","Established","Syn Sent","Syn Recv",
- "Fin Wait 1","Fin Wait 2","Time Wait", "Close",
- "Close Wait","Last ACK","Listen","Closing"
-};
-#endif
-
-static __inline__ void tcp_set_state(struct sock *sk, int state)
-{
- if(sk->state==TCP_ESTABLISHED)
- tcp_statistics.TcpCurrEstab--;
-#ifdef STATE_TRACE
- if(sk->debug)
- printk("TCP sk=%p, State %s -> %s\n",sk, statename[sk->state],statename[state]);
-#endif
- /* This is a hack but it doesn't occur often and it's going to
- be a real to fix nicely */
-
- if(state==TCP_ESTABLISHED && sk->state==TCP_SYN_RECV)
- {
- wake_up_interruptible(&master_select_wakeup);
- }
- sk->state=state;
- if(state==TCP_ESTABLISHED)
- tcp_statistics.TcpCurrEstab++;
-}
-
-/*
- * This routine picks a TCP windows for a socket based on
- * the following constraints
- *
- * 1. The window can never be shrunk once it is offered (RFC 793)
- * 2. We limit memory per socket
- *
- * For now we use NET2E3's heuristic of offering half the memory
- * we have handy. All is not as bad as this seems however because
- * of two things. Firstly we will bin packets even within the window
- * in order to get the data we are waiting for into the memory limit.
- * Secondly we bin common duplicate forms at receive time
- * Better heuristics welcome
- */
-
-int tcp_select_window(struct sock *sk)
-{
- int new_window = sk->prot->rspace(sk);
-
- if(sk->window_clamp)
- new_window=min(sk->window_clamp,new_window);
- /*
- * Two things are going on here. First, we don't ever offer a
- * window less than min(sk->mss, MAX_WINDOW/2). This is the
- * receiver side of SWS as specified in RFC1122.
- * Second, we always give them at least the window they
- * had before, in order to avoid retracting window. This
- * is technically allowed, but RFC1122 advises against it and
- * in practice it causes trouble.
- *
- * Fixme: This doesn't correctly handle the case where
- * new_window > sk->window but not by enough to allow for the
- * shift in sequence space.
- */
- if (new_window < min(sk->mss, MAX_WINDOW/2) || new_window < sk->window)
- return(sk->window);
- return(new_window);
-}
-
-/*
- * Find someone to 'accept'. Must be called with
- * sk->inuse=1 or cli()
- */
-
-static struct sk_buff *tcp_find_established(struct sock *s)
-{
- struct sk_buff *p=skb_peek(&s->receive_queue);
- if(p==NULL)
- return NULL;
- do
- {
- if(p->sk->state == TCP_ESTABLISHED || p->sk->state >= TCP_FIN_WAIT1)
- return p;
- p=p->next;
- }
- while(p!=(struct sk_buff *)&s->receive_queue);
- return NULL;
-}
-
-/*
- * Remove a completed connection and return it. This is used by
- * tcp_accept() to get connections from the queue.
- */
-
-static struct sk_buff *tcp_dequeue_established(struct sock *s)
-{
- struct sk_buff *skb;
- unsigned long flags;
- save_flags(flags);
- cli();
- skb=tcp_find_established(s);
- if(skb!=NULL)
- skb_unlink(skb); /* Take it off the queue */
- restore_flags(flags);
- return skb;
-}
-
-/*
- * This routine closes sockets which have been at least partially
- * opened, but not yet accepted. Currently it is only called by
- * tcp_close, and timeout mirrors the value there.
- */
-
-static void tcp_close_pending (struct sock *sk)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&sk->receive_queue)) != NULL)
- {
- skb->sk->dead=1;
- tcp_close(skb->sk, 0);
- kfree_skb(skb, FREE_READ);
- }
- return;
-}
-
-/*
- * Enter the time wait state.
- */
-
-static void tcp_time_wait(struct sock *sk)
-{
- tcp_set_state(sk,TCP_TIME_WAIT);
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- sk->state_change(sk);
- reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-}
-
-/*
- * A socket has timed out on its send queue and wants to do a
- * little retransmitting. Currently this means TCP.
- */
-
-void tcp_do_retransmit(struct sock *sk, int all)
-{
- struct sk_buff * skb;
- struct proto *prot;
- struct device *dev;
- int ct=0;
-
- prot = sk->prot;
- skb = sk->send_head;
-
- while (skb != NULL)
- {
- struct tcphdr *th;
- struct iphdr *iph;
- int size;
-
- dev = skb->dev;
- IS_SKB(skb);
- skb->when = jiffies;
-
- /*
- * In general it's OK just to use the old packet. However we
- * need to use the current ack and window fields. Urg and
- * urg_ptr could possibly stand to be updated as well, but we
- * don't keep the necessary data. That shouldn't be a problem,
- * if the other end is doing the right thing. Since we're
- * changing the packet, we have to issue a new IP identifier.
- */
-
- iph = (struct iphdr *)(skb->data + dev->hard_header_len);
- th = (struct tcphdr *)(((char *)iph) + (iph->ihl << 2));
- size = skb->len - (((unsigned char *) th) - skb->data);
-
- /*
- * Note: We ought to check for window limits here but
- * currently this is done (less efficiently) elsewhere.
- * We do need to check for a route change but can't handle
- * that until we have the new 1.3.x buffers in.
- *
- */
-
- iph->id = htons(ip_id_count++);
- ip_send_check(iph);
-
- /*
- * This is not the right way to handle this. We have to
- * issue an up to date window and ack report with this
- * retransmit to keep the odd buggy tcp that relies on
- * the fact BSD does this happy.
- * We don't however need to recalculate the entire
- * checksum, so someone wanting a small problem to play
- * with might like to implement RFC1141/RFC1624 and speed
- * this up by avoiding a full checksum.
- */
-
- th->ack_seq = ntohl(sk->acked_seq);
- th->window = ntohs(tcp_select_window(sk));
- tcp_send_check(th, sk->saddr, sk->daddr, size, sk);
-
- /*
- * If the interface is (still) up and running, kick it.
- */
-
- if (dev->flags & IFF_UP)
- {
- /*
- * If the packet is still being sent by the device/protocol
- * below then don't retransmit. This is both needed, and good -
- * especially with connected mode AX.25 where it stops resends
- * occurring of an as yet unsent anyway frame!
- * We still add up the counts as the round trip time wants
- * adjusting.
- */
- if (sk && !skb_device_locked(skb))
- {
- /* Remove it from any existing driver queue first! */
- skb_unlink(skb);
- /* Now queue it */
- ip_statistics.IpOutRequests++;
- dev_queue_xmit(skb, dev, sk->priority);
- }
- }
-
- /*
- * Count retransmissions
- */
-
- ct++;
- sk->prot->retransmits ++;
-
- /*
- * Only one retransmit requested.
- */
-
- if (!all)
- break;
-
- /*
- * This should cut it off before we send too many packets.
- */
-
- if (ct >= sk->cong_window)
- break;
- skb = skb->link3;
- }
-}
-
-/*
- * Reset the retransmission timer
- */
-
-static void reset_xmit_timer(struct sock *sk, int why, unsigned long when)
-{
- del_timer(&sk->retransmit_timer);
- sk->ip_xmit_timeout = why;
- if((int)when < 0)
- {
- when=3;
- printk("Error: Negative timer in xmit_timer\n");
- }
- sk->retransmit_timer.expires=when;
- add_timer(&sk->retransmit_timer);
-}
-
-/*
- * This is the normal code called for timeouts. It does the retransmission
- * and then does backoff. tcp_do_retransmit is separated out because
- * tcp_ack needs to send stuff from the retransmit queue without
- * initiating a backoff.
- */
-
-
-void tcp_retransmit_time(struct sock *sk, int all)
-{
- tcp_do_retransmit(sk, all);
-
- /*
- * Increase the timeout each time we retransmit. Note that
- * we do not increase the rtt estimate. rto is initialized
- * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests
- * that doubling rto each time is the least we can get away with.
- * In KA9Q, Karn uses this for the first few times, and then
- * goes to quadratic. netBSD doubles, but only goes up to *64,
- * and clamps at 1 to 64 sec afterwards. Note that 120 sec is
- * defined in the protocol as the maximum possible RTT. I guess
- * we'll have to use something other than TCP to talk to the
- * University of Mars.
- *
- * PAWS allows us longer timeouts and large windows, so once
- * implemented ftp to mars will work nicely. We will have to fix
- * the 120 second clamps though!
- */
-
- sk->retransmits++;
- sk->backoff++;
- sk->rto = min(sk->rto << 1, 120*HZ);
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
-}
-
-
-/*
- * A timer event has trigger a tcp retransmit timeout. The
- * socket xmit queue is ready and set up to send. Because
- * the ack receive code keeps the queue straight we do
- * nothing clever here.
- */
-
-static void tcp_retransmit(struct sock *sk, int all)
-{
- if (all)
- {
- tcp_retransmit_time(sk, all);
- return;
- }
-
- sk->ssthresh = sk->cong_window >> 1; /* remember window where we lost */
- /* sk->ssthresh in theory can be zero. I guess that's OK */
- sk->cong_count = 0;
-
- sk->cong_window = 1;
-
- /* Do the actual retransmit. */
- tcp_retransmit_time(sk, all);
-}
-
-/*
- * A write timeout has occurred. Process the after effects.
- */
-
-static int tcp_write_timeout(struct sock *sk)
-{
- /*
- * Look for a 'soft' timeout.
- */
- if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
- || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1))
- {
- /*
- * Attempt to recover if arp has changed (unlikely!) or
- * a route has shifted (not supported prior to 1.3).
- */
- arp_destroy (sk->daddr, 0);
- ip_route_check (sk->daddr);
- }
- /*
- * Has it gone just too far ?
- */
- if (sk->retransmits > TCP_RETR2)
- {
- sk->err = ETIMEDOUT;
- sk->error_report(sk);
- del_timer(&sk->retransmit_timer);
- /*
- * Time wait the socket
- */
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING )
- {
- tcp_set_state(sk,TCP_TIME_WAIT);
- reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- }
- else
- {
- /*
- * Clean up time.
- */
- tcp_set_state(sk, TCP_CLOSE);
- return 0;
- }
- }
- return 1;
-}
-
-/*
- * The TCP retransmit timer. This lacks a few small details.
- *
- * 1. An initial rtt timeout on the probe0 should cause what we can
- * of the first write queue buffer to be split and sent.
- * 2. On a 'major timeout' as defined by RFC1122 we shouldn't report
- * ETIMEDOUT if we know an additional 'soft' error caused this.
- * tcp_err should save a 'soft error' for us.
- */
-
-static void retransmit_timer(unsigned long data)
-{
- struct sock *sk = (struct sock*)data;
- int why = sk->ip_xmit_timeout;
-
- /*
- * only process if socket is not in use
- */
-
- cli();
- if (sk->inuse || in_bh)
- {
- /* Try again in 1 second */
- sk->retransmit_timer.expires = HZ;
- add_timer(&sk->retransmit_timer);
- sti();
- return;
- }
-
- sk->inuse = 1;
- sti();
-
- /* Always see if we need to send an ack. */
-
- if (sk->ack_backlog && !sk->zapped)
- {
- sk->prot->read_wakeup (sk);
- if (! sk->dead)
- sk->data_ready(sk,0);
- }
-
- /* Now we need to figure out why the socket was on the timer. */
-
- switch (why)
- {
- /* Window probing */
- case TIME_PROBE0:
- tcp_send_probe0(sk);
- tcp_write_timeout(sk);
- break;
- /* Retransmitting */
- case TIME_WRITE:
- /* It could be we got here because we needed to send an ack.
- * So we need to check for that.
- */
- {
- struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- skb = sk->send_head;
- if (!skb)
- {
- restore_flags(flags);
- }
- else
- {
- /*
- * Kicked by a delayed ack. Reset timer
- * correctly now
- */
- if (jiffies < skb->when + sk->rto)
- {
- reset_xmit_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies);
- restore_flags(flags);
- break;
- }
- restore_flags(flags);
- /*
- * Retransmission
- */
- sk->prot->retransmit (sk, 0);
- tcp_write_timeout(sk);
- }
- break;
- }
- /* Sending Keepalives */
- case TIME_KEEPOPEN:
- /*
- * this reset_timer() call is a hack, this is not
- * how KEEPOPEN is supposed to work.
- */
- reset_xmit_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
-
- /* Send something to keep the connection open. */
- if (sk->prot->write_wakeup)
- sk->prot->write_wakeup (sk);
- sk->retransmits++;
- tcp_write_timeout(sk);
- break;
- default:
- printk ("rexmit_timer: timer expired - reason unknown\n");
- break;
- }
- release_sock(sk);
-}
-
-/*
- * This routine is called by the ICMP module when it gets some
- * sort of error condition. If err < 0 then the socket should
- * be closed and the error returned to the user. If err > 0
- * it's just the icmp type << 8 | icmp code. After adjustment
- * header points to the first 8 bytes of the tcp header. We need
- * to find the appropriate port.
- */
-
-void tcp_err(int err, unsigned char *header, unsigned long daddr,
- unsigned long saddr, struct inet_protocol *protocol)
-{
- struct tcphdr *th;
- struct sock *sk;
- struct iphdr *iph=(struct iphdr *)header;
-
- header+=4*iph->ihl;
-
-
- th =(struct tcphdr *)header;
- sk = get_sock(&tcp_prot, th->source, daddr, th->dest, saddr);
-
- if (sk == NULL)
- return;
-
- if(err<0)
- {
- sk->err = -err;
- sk->error_report(sk);
- return;
- }
-
- if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8))
- {
- /*
- * FIXME:
- * For now we will just trigger a linear backoff.
- * The slow start code should cause a real backoff here.
- */
- if (sk->cong_window > 4)
- sk->cong_window--;
- return;
- }
-
-/* sk->err = icmp_err_convert[err & 0xff].errno; -- moved as TCP should hide non fatals internally (and does) */
-
- /*
- * If we've already connected we will keep trying
- * until we time out, or the user gives up.
- */
-
- if (icmp_err_convert[err & 0xff].fatal || sk->state == TCP_SYN_SENT)
- {
- if (sk->state == TCP_SYN_SENT)
- {
- tcp_statistics.TcpAttemptFails++;
- tcp_set_state(sk,TCP_CLOSE);
- sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
- }
- sk->err = icmp_err_convert[err & 0xff].error;
- }
- return;
-}
-
-
-/*
- * Walk down the receive queue counting readable data until we hit the end or we find a gap
- * in the received data queue (ie a frame missing that needs sending to us). Not
- * sorting using two queues as data arrives makes life so much harder.
- */
-
-#ifndef _HURD_
-static
-#endif
-int tcp_readable(struct sock *sk)
-{
- unsigned long counted;
- unsigned long amount;
- struct sk_buff *skb;
- int sum;
- unsigned long flags;
-
- if(sk && sk->debug)
- printk("tcp_readable: %p - ",sk);
-
- save_flags(flags);
- cli();
- if (sk == NULL || (skb = skb_peek(&sk->receive_queue)) == NULL)
- {
- restore_flags(flags);
- if(sk && sk->debug)
- printk("empty\n");
- return(0);
- }
-
- counted = sk->copied_seq; /* Where we are at the moment */
- amount = 0;
-
- /*
- * Do until a push or until we are out of data.
- */
-
- do
- {
- if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */
- break;
- sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */
- if (skb->h.th->syn)
- sum++;
- if (sum > 0)
- { /* Add it up, move on */
- amount += sum;
- if (skb->h.th->syn)
- amount--;
- counted += sum;
- }
- /*
- * Don't count urg data ... but do it in the right place!
- * Consider: "old_data (ptr is here) URG PUSH data"
- * The old code would stop at the first push because
- * it counted the urg (amount==1) and then does amount--
- * *after* the loop. This means tcp_readable() always
- * returned zero if any URG PUSH was in the queue, even
- * though there was normal data available. If we subtract
- * the urg data right here, we even get it to work for more
- * than one URG PUSH skb without normal data.
- * This means that select() finally works now with urg data
- * in the queue. Note that rlogin was never affected
- * because it doesn't use select(); it uses two processes
- * and a blocking read(). And the queue scan in tcp_read()
- * was correct. Mike <pall@rz.uni-karlsruhe.de>
- */
- if (skb->h.th->urg)
- amount--; /* don't count urg data */
- if (amount && skb->h.th->psh) break;
- skb = skb->next;
- }
- while(skb != (struct sk_buff *)&sk->receive_queue);
-
- restore_flags(flags);
- if(sk->debug)
- printk("got %lu bytes.\n",amount);
- return(amount);
-}
-
-/*
- * LISTEN is a special case for select..
- */
-static int tcp_listen_select(struct sock *sk, int sel_type, select_table *wait)
-{
- if (sel_type == SEL_IN) {
- int retval;
-
- sk->inuse = 1;
- retval = (tcp_find_established(sk) != NULL);
- release_sock(sk);
- if (!retval)
- select_wait(&master_select_wakeup,wait);
- return retval;
- }
- return 0;
-}
-
-
-/*
- * Wait for a TCP event.
- *
- * Note that we don't need to set "sk->inuse", as the upper select layers
- * take care of normal races (between the test and the event) and we don't
- * go look at any of the socket buffers directly.
- */
-static int tcp_select(struct sock *sk, int sel_type, select_table *wait)
-{
- if (sk->state == TCP_LISTEN)
- return tcp_listen_select(sk, sel_type, wait);
-
- switch(sel_type) {
- case SEL_IN:
- if (sk->err)
- return 1;
- if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
- break;
-
- if (sk->shutdown & RCV_SHUTDOWN)
- return 1;
-
- if (sk->acked_seq == sk->copied_seq)
- break;
-
- if (sk->urg_seq != sk->copied_seq ||
- sk->acked_seq != sk->copied_seq+1 ||
- sk->urginline || !sk->urg_data)
- return 1;
- break;
-
- case SEL_OUT:
- if (sk->shutdown & SEND_SHUTDOWN)
- return 0;
- if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
- break;
- /*
- * This is now right thanks to a small fix
- * by Matt Dillon.
- */
-
- if (sk->prot->wspace(sk) < sk->mtu+128+sk->prot->max_header)
- break;
- return 1;
-
- case SEL_EX:
- if (sk->err || sk->urg_data)
- return 1;
- break;
- }
- select_wait(sk->sleep, wait);
- return 0;
-}
-
-#ifndef _HURD_
-int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
-{
- int err;
- switch(cmd)
- {
-
- case TIOCINQ:
-#ifdef FIXME /* FIXME: */
- case FIONREAD:
-#endif
- {
- unsigned long amount;
-
- if (sk->state == TCP_LISTEN)
- return(-EINVAL);
-
- sk->inuse = 1;
- amount = tcp_readable(sk);
- release_sock(sk);
- err=verify_area(VERIFY_WRITE,(void *)arg,
- sizeof(unsigned long));
- if(err)
- return err;
- put_fs_long(amount,(unsigned long *)arg);
- return(0);
- }
- case SIOCATMARK:
- {
- int answ = sk->urg_data && sk->urg_seq == sk->copied_seq;
-
- err = verify_area(VERIFY_WRITE,(void *) arg,
- sizeof(unsigned long));
- if (err)
- return err;
- put_fs_long(answ,(int *) arg);
- return(0);
- }
- case TIOCOUTQ:
- {
- unsigned long amount;
-
- if (sk->state == TCP_LISTEN) return(-EINVAL);
- amount = sk->prot->wspace(sk);
- err=verify_area(VERIFY_WRITE,(void *)arg,
- sizeof(unsigned long));
- if(err)
- return err;
- put_fs_long(amount,(unsigned long *)arg);
- return(0);
- }
- default:
- return(-EINVAL);
- }
-}
-#endif
-
-/*
- * This routine computes a TCP checksum.
- */
-
-unsigned short tcp_check(struct tcphdr *th, int len,
- unsigned long saddr, unsigned long daddr)
-{
- unsigned long sum;
-
- if (saddr == 0) saddr = ip_my_addr();
-
-/*
- * stupid, gcc complains when I use just one __asm__ block,
- * something about too many reloads, but this is just two
- * instructions longer than what I want
- */
- __asm__("
- addl %%ecx, %%ebx
- adcl %%edx, %%ebx
- adcl $0, %%ebx
- "
- : "=b"(sum)
- : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
- : "bx", "cx", "dx" );
- __asm__("
- movl %%ecx, %%edx
- cld
- cmpl $32, %%ecx
- jb 2f
- shrl $5, %%ecx
- clc
-1: lodsl
- adcl %%eax, %%ebx
- lodsl
- adcl %%eax, %%ebx
- lodsl
- adcl %%eax, %%ebx
- lodsl
- adcl %%eax, %%ebx
- lodsl
- adcl %%eax, %%ebx
- lodsl
- adcl %%eax, %%ebx
- lodsl
- adcl %%eax, %%ebx
- lodsl
- adcl %%eax, %%ebx
- loop 1b
- adcl $0, %%ebx
- movl %%edx, %%ecx
-2: andl $28, %%ecx
- je 4f
- shrl $2, %%ecx
- clc
-3: lodsl
- adcl %%eax, %%ebx
- loop 3b
- adcl $0, %%ebx
-4: movl $0, %%eax
- testw $2, %%dx
- je 5f
- lodsw
- addl %%eax, %%ebx
- adcl $0, %%ebx
- movw $0, %%ax
-5: test $1, %%edx
- je 6f
- lodsb
- addl %%eax, %%ebx
- adcl $0, %%ebx
-6: movl %%ebx, %%eax
- shrl $16, %%eax
- addw %%ax, %%bx
- adcw $0, %%bx
- "
- : "=b"(sum)
- : "0"(sum), "c"(len), "S"(th)
- : "ax", "bx", "cx", "dx", "si" );
-
- /* We only want the bottom 16 bits, but we never cleared the top 16. */
-
- return((~sum) & 0xffff);
-}
-
-
-
-void tcp_send_check(struct tcphdr *th, unsigned long saddr,
- unsigned long daddr, int len, struct sock *sk)
-{
- th->check = 0;
- th->check = tcp_check(th, len, saddr, daddr);
- return;
-}
-
-/*
- * This is the main buffer sending routine. We queue the buffer
- * having checked it is sane seeming.
- */
-
-static void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
-{
- int size;
- struct tcphdr * th = skb->h.th;
-
- /*
- * length of packet (not counting length of pre-tcp headers)
- */
-
- size = skb->len - ((unsigned char *) th - skb->data);
-
- /*
- * Sanity check it..
- */
-
- if (size < sizeof(struct tcphdr) || size > skb->len)
- {
- printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
- skb, skb->data, th, skb->len);
- kfree_skb(skb, FREE_WRITE);
- return;
- }
-
- /*
- * If we have queued a header size packet.. (these crash a few
- * tcp stacks if ack is not set)
- */
-
- if (size == sizeof(struct tcphdr))
- {
- /* If it's got a syn or fin it's notionally included in the size..*/
- if(!th->syn && !th->fin)
- {
- printk("tcp_send_skb: attempt to queue a bogon.\n");
- kfree_skb(skb,FREE_WRITE);
- return;
- }
- }
-
- /*
- * Actual processing.
- */
-
- tcp_statistics.TcpOutSegs++;
- skb->h.seq = ntohl(th->seq) + size - 4*th->doff;
-
- /*
- * We must queue if
- *
- * a) The right edge of this frame exceeds the window
- * b) We are retransmitting (Nagle's rule)
- * c) We have too many packets 'in flight'
- */
-
- if (after(skb->h.seq, sk->window_seq) ||
- (sk->retransmits && sk->ip_xmit_timeout == TIME_WRITE) ||
- sk->packets_out >= sk->cong_window)
- {
- /* checksum will be supplied by tcp_write_xmit. So
- * we shouldn't need to set it at all. I'm being paranoid */
- th->check = 0;
- if (skb->next != NULL)
- {
- printk("tcp_send_partial: next != NULL\n");
- skb_unlink(skb);
- }
- skb_queue_tail(&sk->write_queue, skb);
-
- /*
- * If we don't fit we have to start the zero window
- * probes. This is broken - we really need to do a partial
- * send _first_ (This is what causes the Cisco and PC/TCP
- * grief).
- */
-
- if (before(sk->window_seq, sk->write_queue.next->h.seq) &&
- sk->send_head == NULL && sk->ack_backlog == 0)
- reset_xmit_timer(sk, TIME_PROBE0, sk->rto);
- }
- else
- {
- /*
- * This is going straight out
- */
-
- th->ack_seq = ntohl(sk->acked_seq);
- th->window = ntohs(tcp_select_window(sk));
-
- tcp_send_check(th, sk->saddr, sk->daddr, size, sk);
-
- sk->sent_seq = sk->write_seq;
-
- /*
- * This is mad. The tcp retransmit queue is put together
- * by the ip layer. This causes half the problems with
- * unroutable FIN's and other things.
- */
-
- sk->prot->queue_xmit(sk, skb->dev, skb, 0);
-
- /*
- * Set for next retransmit based on expected ACK time.
- * FIXME: We set this every time which means our
- * retransmits are really about a window behind.
- */
-
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- }
-}
-
-/*
- * Locking problems lead us to a messy situation where we can have
- * multiple partially complete buffers queued up. This is really bad
- * as we don't want to be sending partial buffers. Fix this with
- * a semaphore or similar to lock tcp_write per socket.
- *
- * These routines are pretty self descriptive.
- */
-
-struct sk_buff * tcp_dequeue_partial(struct sock * sk)
-{
- struct sk_buff * skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- skb = sk->partial;
- if (skb) {
- sk->partial = NULL;
- del_timer(&sk->partial_timer);
- }
- restore_flags(flags);
- return skb;
-}
-
-/*
- * Empty the partial queue
- */
-
-static void tcp_send_partial(struct sock *sk)
-{
- struct sk_buff *skb;
-
- if (sk == NULL)
- return;
- while ((skb = tcp_dequeue_partial(sk)) != NULL)
- tcp_send_skb(sk, skb);
-}
-
-/*
- * Queue a partial frame
- */
-
-void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk)
-{
- struct sk_buff * tmp;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- tmp = sk->partial;
- if (tmp)
- del_timer(&sk->partial_timer);
- sk->partial = skb;
- init_timer(&sk->partial_timer);
- /*
- * Wait up to 1 second for the buffer to fill.
- */
- sk->partial_timer.expires = HZ;
- sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial;
- sk->partial_timer.data = (unsigned long) sk;
- add_timer(&sk->partial_timer);
- restore_flags(flags);
- if (tmp)
- tcp_send_skb(sk, tmp);
-}
-
-
-/*
- * This routine sends an ack and also updates the window.
- */
-
-static void tcp_send_ack(unsigned long sequence, unsigned long ack,
- struct sock *sk,
- struct tcphdr *th, unsigned long daddr)
-{
- struct sk_buff *buff;
- struct tcphdr *t1;
- struct device *dev = NULL;
- int tmp;
-
- if(sk->zapped)
- return; /* We have been reset, we may not send again */
-
- /*
- * We need to grab some memory, and put together an ack,
- * and then put it into the queue to be sent.
- */
-
- buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- {
- /*
- * Force it to send an ack. We don't have to do this
- * (ACK is unreliable) but it's much better use of
- * bandwidth on slow links to send a spare ack than
- * resend packets.
- */
-
- sk->ack_backlog++;
- if (sk->ip_xmit_timeout != TIME_WRITE && tcp_connected(sk->state))
- {
- reset_xmit_timer(sk, TIME_WRITE, HZ);
- }
- return;
- }
-
- /*
- * Assemble a suitable TCP frame
- */
-
- buff->len = sizeof(struct tcphdr);
- buff->sk = sk;
- buff->localroute = sk->localroute;
- t1 =(struct tcphdr *) buff->data;
-
- /*
- * Put in the IP header and routing stuff.
- */
-
- tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
- if (tmp < 0)
- {
- buff->free = 1;
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- return;
- }
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)t1 +tmp);
-
- memcpy(t1, th, sizeof(*t1));
-
- /*
- * Swap the send and the receive.
- */
-
- t1->dest = th->source;
- t1->source = th->dest;
- t1->seq = ntohl(sequence);
- t1->ack = 1;
- sk->window = tcp_select_window(sk);
- t1->window = ntohs(sk->window);
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->syn = 0;
- t1->psh = 0;
- t1->fin = 0;
-
- /*
- * If we have nothing queued for transmit and the transmit timer
- * is on we are just doing an ACK timeout and need to switch
- * to a keepalive.
- */
-
- if (ack == sk->acked_seq)
- {
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->ack_timed = 0;
- if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL
- && sk->ip_xmit_timeout == TIME_WRITE)
- {
- if(sk->keepopen) {
- reset_xmit_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);
- } else {
- delete_timer(sk);
- }
- }
- }
-
- /*
- * Fill in the packet and send it
- */
-
- t1->ack_seq = ntohl(ack);
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
- if (sk->debug)
- printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
- tcp_statistics.TcpOutSegs++;
- sk->prot->queue_xmit(sk, dev, buff, 1);
-}
-
-
-/*
- * This routine builds a generic TCP header.
- */
-
-extern __inline int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
-{
-
- memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
- th->seq = htonl(sk->write_seq);
- th->psh =(push == 0) ? 1 : 0;
- th->doff = sizeof(*th)/4;
- th->ack = 1;
- th->fin = 0;
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->ack_timed = 0;
- th->ack_seq = htonl(sk->acked_seq);
- sk->window = tcp_select_window(sk);
- th->window = htons(sk->window);
-
- return(sizeof(*th));
-}
-
-/*
- * This routine copies from a user buffer into a socket,
- * and starts the transmit system.
- */
-
-static int tcp_write(struct sock *sk, unsigned char *from,
- int len, int nonblock, unsigned flags)
-{
- int copied = 0;
- int copy;
- int tmp;
- struct sk_buff *skb;
- struct sk_buff *send_tmp;
- unsigned char *buff;
- struct proto *prot;
- struct device *dev = NULL;
-
- sk->inuse=1;
- prot = sk->prot;
- while(len > 0)
- {
- if (sk->err)
- { /* Stop on an error */
- release_sock(sk);
- if (copied)
- return(copied);
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
-
- /*
- * First thing we do is make sure that we are established.
- */
-
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- release_sock(sk);
- sk->err = EPIPE;
- if (copied)
- return(copied);
- sk->err = 0;
- return(-EPIPE);
- }
-
- /*
- * Wait for a connection to finish.
- */
-
- while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
- {
- if (sk->err)
- {
- release_sock(sk);
- if (copied)
- return(copied);
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
-
- if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
- {
- release_sock(sk);
- if (copied)
- return(copied);
-
- if (sk->err)
- {
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
-
- if (sk->keepopen)
- {
- send_sig(SIGPIPE, current, 0);
- }
- return(-EPIPE);
- }
-
- if (nonblock || copied)
- {
- release_sock(sk);
- if (copied)
- return(copied);
- return(-EAGAIN);
- }
-
- release_sock(sk);
- cli();
-
- if (sk->state != TCP_ESTABLISHED &&
- sk->state != TCP_CLOSE_WAIT && sk->err == 0)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- if (copied)
- return(copied);
- return(-ERESTARTSYS);
- }
- }
- sk->inuse = 1;
- sti();
- }
-
- /*
- * The following code can result in copy <= if sk->mss is ever
- * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window).
- * sk->mtu is constant once SYN processing is finished. I.e. we
- * had better not get here until we've seen his SYN and at least one
- * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.)
- * But ESTABLISHED should guarantee that. sk->max_window is by definition
- * non-decreasing. Note that any ioctl to set user_mss must be done
- * before the exchange of SYN's. If the initial ack from the other
- * end has a window of 0, max_window and thus mss will both be 0.
- */
-
- /*
- * Now we need to check if we have a half built packet.
- */
-
- if ((skb = tcp_dequeue_partial(sk)) != NULL)
- {
- int hdrlen;
-
- /* IP header + TCP header */
- hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
- + sizeof(struct tcphdr);
-
- /* Add more stuff to the end of skb->len */
- if (!(flags & MSG_OOB))
- {
- copy = min(sk->mss - (skb->len - hdrlen), len);
- /* FIXME: this is really a bug. */
- if (copy <= 0)
- {
- printk("TCP: **bug**: \"copy\" <= 0!!\n");
- copy = 0;
- }
-
- memcpy_fromfs(skb->data + skb->len, from, copy);
- skb->len += copy;
- from += copy;
- copied += copy;
- len -= copy;
- sk->write_seq += copy;
- }
- if ((skb->len - hdrlen) >= sk->mss ||
- (flags & MSG_OOB) || !sk->packets_out)
- tcp_send_skb(sk, skb);
- else
- tcp_enqueue_partial(skb, sk);
- continue;
- }
-
- /*
- * We also need to worry about the window.
- * If window < 1/2 the maximum window we've seen from this
- * host, don't use it. This is sender side
- * silly window prevention, as specified in RFC1122.
- * (Note that this is different than earlier versions of
- * SWS prevention, e.g. RFC813.). What we actually do is
- * use the whole MSS. Since the results in the right
- * edge of the packet being outside the window, it will
- * be queued for later rather than sent.
- */
-
- copy = sk->window_seq - sk->write_seq;
- if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss)
- copy = sk->mss;
- if (copy > len)
- copy = len;
-
- /*
- * We should really check the window here also.
- */
-
- send_tmp = NULL;
- if (copy < sk->mss && !(flags & MSG_OOB))
- {
- /*
- * We will release the socket in case we sleep here.
- */
- release_sock(sk);
- /*
- * NB: following must be mtu, because mss can be increased.
- * mss is always <= mtu
- */
- skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header, 0, GFP_KERNEL);
- sk->inuse = 1;
- send_tmp = skb;
- }
- else
- {
- /*
- * We will release the socket in case we sleep here.
- */
- release_sock(sk);
- skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL);
- sk->inuse = 1;
- }
-
- /*
- * If we didn't get any memory, we need to sleep.
- */
-
- if (skb == NULL)
- {
- sk->socket->flags |= SO_NOSPACE;
- if (nonblock)
- {
- release_sock(sk);
- if (copied)
- return(copied);
- return(-EAGAIN);
- }
-
- /*
- * FIXME: here is another race condition.
- */
-
- tmp = sk->wmem_alloc;
- release_sock(sk);
- cli();
- /*
- * Again we will try to avoid it.
- */
- if (tmp <= sk->wmem_alloc &&
- (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
- && sk->err == 0)
- {
- sk->socket->flags &= ~SO_NOSPACE;
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- if (copied)
- return(copied);
- return(-ERESTARTSYS);
- }
- }
- sk->inuse = 1;
- sti();
- continue;
- }
-
- skb->len = 0;
- skb->sk = sk;
- skb->free = 0;
- skb->localroute = sk->localroute|(flags&MSG_DONTROUTE);
-
- buff = skb->data;
-
- /*
- * FIXME: we need to optimize this.
- * Perhaps some hints here would be good.
- */
-
- tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
- if (tmp < 0 )
- {
- prot->wfree(sk, skb->mem_addr, skb->mem_len);
- release_sock(sk);
- if (copied)
- return(copied);
- return(tmp);
- }
- skb->len += tmp;
- skb->dev = dev;
- buff += tmp;
- skb->h.th =(struct tcphdr *) buff;
- tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
- if (tmp < 0)
- {
- prot->wfree(sk, skb->mem_addr, skb->mem_len);
- release_sock(sk);
- if (copied)
- return(copied);
- return(tmp);
- }
-
- if (flags & MSG_OOB)
- {
- ((struct tcphdr *)buff)->urg = 1;
- ((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
- }
- skb->len += tmp;
- memcpy_fromfs(buff+tmp, from, copy);
-
- from += copy;
- copied += copy;
- len -= copy;
- skb->len += copy;
- skb->free = 0;
- sk->write_seq += copy;
-
- if (send_tmp != NULL && sk->packets_out)
- {
- tcp_enqueue_partial(send_tmp, sk);
- continue;
- }
- tcp_send_skb(sk, skb);
- }
- sk->err = 0;
-
-/*
- * Nagle's rule. Turn Nagle off with TCP_NODELAY for highly
- * interactive fast network servers. It's meant to be on and
- * it really improves the throughput though not the echo time
- * on my slow slip link - Alan
- */
-
-/*
- * Avoid possible race on send_tmp - c/o Johannes Stille
- */
-
- if(sk->partial && ((!sk->packets_out)
- /* If not nagling we can send on the before case too.. */
- || (sk->nonagle && before(sk->write_seq , sk->window_seq))
- ))
- tcp_send_partial(sk);
-
- release_sock(sk);
- return(copied);
-}
-
-/*
- * This is just a wrapper.
- */
-
-static int tcp_sendto(struct sock *sk, unsigned char *from,
- int len, int nonblock, unsigned flags,
- struct sockaddr_in *addr, int addr_len)
-{
- if (flags & ~(MSG_OOB|MSG_DONTROUTE))
- return -EINVAL;
- if (sk->state == TCP_CLOSE)
- return -ENOTCONN;
- if (addr_len < sizeof(*addr))
- return -EINVAL;
- if (addr->sin_family && addr->sin_family != AF_INET)
- return -EINVAL;
- if (addr->sin_port != sk->dummy_th.dest)
- return -EISCONN;
- if (addr->sin_addr.s_addr != sk->daddr)
- return -EISCONN;
- return tcp_write(sk, from, len, nonblock, flags);
-}
-
-
-/*
- * Send an ack if one is backlogged at this point. Ought to merge
- * this with tcp_send_ack().
- */
-
-static void tcp_read_wakeup(struct sock *sk)
-{
- int tmp;
- struct device *dev = NULL;
- struct tcphdr *t1;
- struct sk_buff *buff;
-
- if (!sk->ack_backlog)
- return;
-
- /*
- * FIXME: we need to put code here to prevent this routine from
- * being called. Being called once in a while is ok, so only check
- * if this is the second time in a row.
- */
-
- /*
- * We need to grab some memory, and put together an ack,
- * and then put it into the queue to be sent.
- */
-
- buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
- if (buff == NULL)
- {
- /* Try again real soon. */
- reset_xmit_timer(sk, TIME_WRITE, HZ);
- return;
- }
-
- buff->len = sizeof(struct tcphdr);
- buff->sk = sk;
- buff->localroute = sk->localroute;
-
- /*
- * Put in the IP header and routing stuff.
- */
-
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
- if (tmp < 0)
- {
- buff->free = 1;
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- return;
- }
-
- buff->len += tmp;
- t1 =(struct tcphdr *)(buff->data +tmp);
-
- memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
- t1->seq = htonl(sk->sent_seq);
- t1->ack = 1;
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->syn = 0;
- t1->psh = 0;
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->window = tcp_select_window(sk);
- t1->window = ntohs(sk->window);
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
- sk->prot->queue_xmit(sk, dev, buff, 1);
- tcp_statistics.TcpOutSegs++;
-}
-
-
-/*
- * FIXME:
- * This routine frees used buffers.
- * It should consider sending an ACK to let the
- * other end know we now have a bigger window.
- */
-
-static void cleanup_rbuf(struct sock *sk)
-{
- unsigned long flags;
- unsigned long left;
- struct sk_buff *skb;
- unsigned long rspace;
-
- if(sk->debug)
- printk("cleaning rbuf for sk=%p\n", sk);
-
- save_flags(flags);
- cli();
-
- left = sk->prot->rspace(sk);
-
- /*
- * We have to loop through all the buffer headers,
- * and try to free up all the space we can.
- */
-
- while((skb=skb_peek(&sk->receive_queue)) != NULL)
- {
- if (!skb->used || skb->users)
- break;
- skb_unlink(skb);
- skb->sk = sk;
- kfree_skb(skb, FREE_READ);
- }
-
- restore_flags(flags);
-
- /*
- * FIXME:
- * At this point we should send an ack if the difference
- * in the window, and the amount of space is bigger than
- * TCP_WINDOW_DIFF.
- */
-
- if(sk->debug)
- printk("sk->rspace = %lu, was %lu\n", sk->prot->rspace(sk),
- left);
- if ((rspace=sk->prot->rspace(sk)) != left)
- {
- /*
- * This area has caused the most trouble. The current strategy
- * is to simply do nothing if the other end has room to send at
- * least 3 full packets, because the ack from those will auto-
- * matically update the window. If the other end doesn't think
- * we have much space left, but we have room for at least 1 more
- * complete packet than it thinks we do, we will send an ack
- * immediately. Otherwise we will wait up to .5 seconds in case
- * the user reads some more.
- */
- sk->ack_backlog++;
- /*
- * It's unclear whether to use sk->mtu or sk->mss here. They differ only
- * if the other end is offering a window smaller than the agreed on MSS
- * (called sk->mtu here). In theory there's no connection between send
- * and receive, and so no reason to think that they're going to send
- * small packets. For the moment I'm using the hack of reducing the mss
- * only on the send side, so I'm putting mtu here.
- */
-
- if (rspace > (sk->window - sk->bytes_rcv + sk->mtu))
- {
- /* Send an ack right now. */
- tcp_read_wakeup(sk);
- }
- else
- {
- /* Force it to send an ack soon. */
- int was_active = del_timer(&sk->retransmit_timer);
- if (!was_active || TCP_ACK_TIME < sk->timer.expires)
- {
- reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- }
- else
- add_timer(&sk->retransmit_timer);
- }
- }
-}
-
-
-/*
- * Handle reading urgent data. BSD has very simple semantics for
- * this, no blocking and very strange errors 8)
- */
-
-static int tcp_read_urg(struct sock * sk, int nonblock,
- unsigned char *to, int len, unsigned flags)
-{
- /*
- * No URG data to read
- */
- if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
- return -EINVAL; /* Yes this is right ! */
-
- if (sk->err)
- {
- int tmp = -sk->err;
- sk->err = 0;
- return tmp;
- }
-
- if (sk->state == TCP_CLOSE || sk->done)
- {
- if (!sk->done) {
- sk->done = 1;
- return 0;
- }
- return -ENOTCONN;
- }
-
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- sk->done = 1;
- return 0;
- }
- sk->inuse = 1;
- if (sk->urg_data & URG_VALID)
- {
- char c = sk->urg_data;
- if (!(flags & MSG_PEEK))
- sk->urg_data = URG_READ;
- put_fs_byte(c, to);
- release_sock(sk);
- return 1;
- }
- release_sock(sk);
-
- /*
- * Fixed the recv(..., MSG_OOB) behaviour. BSD docs and
- * the available implementations agree in this case:
- * this call should never block, independent of the
- * blocking state of the socket.
- * Mike <pall@rz.uni-karlsruhe.de>
- */
- return -EAGAIN;
-}
-
-
-/*
- * This routine copies from a sock struct into the user buffer.
- */
-
-static int tcp_read(struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags)
-{
-#ifndef _HURD_
- struct wait_queue wait = { current, NULL };
-#endif
- int copied = 0;
- unsigned long peek_seq;
- volatile unsigned long *seq; /* So gcc doesn't overoptimise */
- unsigned long used;
-
- /*
- * This error should be checked.
- */
-
- if (sk->state == TCP_LISTEN)
- return -ENOTCONN;
-
- /*
- * Urgent data needs to be handled specially.
- */
-
- if (flags & MSG_OOB)
- return tcp_read_urg(sk, nonblock, to, len, flags);
-
- /*
- * Copying sequence to update. This is volatile to handle
- * the multi-reader case neatly (memcpy_to/fromfs might be
- * inline and thus not flush cached variables otherwise).
- */
-
- peek_seq = sk->copied_seq;
- seq = &sk->copied_seq;
- if (flags & MSG_PEEK)
- seq = &peek_seq;
-
-#ifndef _HURD_
- add_wait_queue(sk->sleep, &wait);
-#endif
- sk->inuse = 1;
- while (len > 0)
- {
- struct sk_buff * skb;
- unsigned long offset;
-
- /*
- * Are we at urgent data? Stop if we have read anything.
- */
-
- if (copied && sk->urg_data && sk->urg_seq == *seq)
- break;
-
- /*
- * Next get a buffer.
- */
-
-#ifndef _HURD_
- current->state = TASK_INTERRUPTIBLE;
-#endif
-
- skb = skb_peek(&sk->receive_queue);
- do
- {
- if (!skb)
- break;
- if (before(*seq, skb->h.th->seq))
- break;
- offset = *seq - skb->h.th->seq;
- if (skb->h.th->syn)
- offset--;
- if (offset < skb->len)
- goto found_ok_skb;
- if (skb->h.th->fin)
- goto found_fin_ok;
- if (!(flags & MSG_PEEK))
- skb->used = 1;
- skb = skb->next;
- }
- while (skb != (struct sk_buff *)&sk->receive_queue);
-
- if (copied)
- break;
-
- if (sk->err)
- {
- copied = -sk->err;
- sk->err = 0;
- break;
- }
-
- if (sk->state == TCP_CLOSE)
- {
- if (!sk->done)
- {
- sk->done = 1;
- break;
- }
- copied = -ENOTCONN;
- break;
- }
-
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- sk->done = 1;
- break;
- }
-
- if (nonblock)
- {
- copied = -EAGAIN;
- break;
- }
-
- cleanup_rbuf(sk);
- release_sock(sk);
- sk->socket->flags |= SO_WAITDATA;
-#ifdef _HURD_
- interruptible_sleep_on (sk->sleep);
-#else
- schedule();
-#endif
- sk->socket->flags &= ~SO_WAITDATA;
- sk->inuse = 1;
-
- if (current->signal & ~current->blocked)
- {
- copied = -ERESTARTSYS;
- break;
- }
- continue;
-
- found_ok_skb:
- /*
- * Lock the buffer. We can be fairly relaxed as
- * an interrupt will never steal a buffer we are
- * using unless I've missed something serious in
- * tcp_data.
- */
-
- skb->users++;
-
- /*
- * Ok so how much can we use ?
- */
-
- used = skb->len - offset;
- if (len < used)
- used = len;
- /*
- * Do we have urgent data here?
- */
-
- if (sk->urg_data)
- {
- unsigned long urg_offset = sk->urg_seq - *seq;
- if (urg_offset < used)
- {
- if (!urg_offset)
- {
- if (!sk->urginline)
- {
- ++*seq;
- offset++;
- used--;
- }
- }
- else
- used = urg_offset;
- }
- }
-
- /*
- * Copy it - We _MUST_ update *seq first so that we
- * don't ever double read when we have dual readers
- */
-
- *seq += used;
-
- /*
- * This memcpy_tofs can sleep. If it sleeps and we
- * do a second read it relies on the skb->users to avoid
- * a crash when cleanup_rbuf() gets called.
- */
-
- memcpy_tofs(to,((unsigned char *)skb->h.th) +
- skb->h.th->doff*4 + offset, used);
- copied += used;
- len -= used;
- to += used;
-
- /*
- * We now will not sleep again until we are finished
- * with skb. Sorry if you are doing the SMP port
- * but you'll just have to fix it neatly ;)
- */
-
- skb->users --;
-
- if (after(sk->copied_seq,sk->urg_seq))
- sk->urg_data = 0;
- if (used + offset < skb->len)
- continue;
-
- /*
- * Process the FIN.
- */
-
- if (skb->h.th->fin)
- goto found_fin_ok;
- if (flags & MSG_PEEK)
- continue;
- skb->used = 1;
- continue;
-
- found_fin_ok:
- ++*seq;
- if (flags & MSG_PEEK)
- break;
-
- /*
- * All is done
- */
-
- skb->used = 1;
- sk->shutdown |= RCV_SHUTDOWN;
- break;
-
- }
-#ifndef _HURD_
- remove_wait_queue(sk->sleep, &wait);
- current->state = TASK_RUNNING;
-#endif
-
- /* Clean up data we have read: This will do ACK frames */
- cleanup_rbuf(sk);
- release_sock(sk);
- return copied;
-}
-
-/*
- * State processing on a close. This implements the state shift for
- * sending our FIN frame. Note that we only send a FIN for some
- * states. A shutdown() may have already sent the FIN, or we may be
- * closed.
- */
-
-static int tcp_close_state(struct sock *sk, int dead)
-{
- int ns=TCP_CLOSE;
- int send_fin=0;
- switch(sk->state)
- {
- case TCP_SYN_SENT: /* No SYN back, no FIN needed */
- break;
- case TCP_SYN_RECV:
- case TCP_ESTABLISHED: /* Closedown begin */
- ns=TCP_FIN_WAIT1;
- send_fin=1;
- break;
- case TCP_FIN_WAIT1: /* Already closing, or FIN sent: no change */
- case TCP_FIN_WAIT2:
- case TCP_CLOSING:
- ns=sk->state;
- break;
- case TCP_CLOSE:
- case TCP_LISTEN:
- break;
- case TCP_CLOSE_WAIT: /* They have FIN'd us. We send our FIN and
- wait only for the ACK */
- ns=TCP_LAST_ACK;
- send_fin=1;
- }
-
- tcp_set_state(sk,ns);
-
- /*
- * This is a (useful) BSD violating of the RFC. There is a
- * problem with TCP as specified in that the other end could
- * keep a socket open forever with no application left this end.
- * We use a 3 minute timeout (about the same as BSD) then kill
- * our end. If they send after that then tough - BUT: long enough
- * that we won't make the old 4*rto = almost no time - whoops
- * reset mistake.
- */
- if(dead && ns==TCP_FIN_WAIT2)
- {
- int timer_active=del_timer(&sk->timer);
- if(timer_active)
- add_timer(&sk->timer);
- else
- reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
- }
-
- return send_fin;
-}
-
-/*
- * Send a fin.
- */
-
-static void tcp_send_fin(struct sock *sk)
-{
- struct proto *prot =(struct proto *)sk->prot;
- struct tcphdr *th =(struct tcphdr *)&sk->dummy_th;
- struct tcphdr *t1;
- struct sk_buff *buff;
- struct device *dev=NULL;
- int tmp;
-
- release_sock(sk); /* in case the malloc sleeps. */
-
- buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
- sk->inuse = 1;
-
- if (buff == NULL)
- {
- /* This is a disaster if it occurs */
- printk("tcp_send_fin: Impossible malloc failure");
- return;
- }
-
- /*
- * Administrivia
- */
-
- buff->sk = sk;
- buff->len = sizeof(*t1);
- buff->localroute = sk->localroute;
- t1 =(struct tcphdr *) buff->data;
-
- /*
- * Put in the IP header and routing stuff.
- */
-
- tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt,
- sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
- if (tmp < 0)
- {
- int t;
- /*
- * Finish anyway, treat this as a send that got lost.
- * (Not good).
- */
-
- buff->free = 1;
- prot->wfree(sk,buff->mem_addr, buff->mem_len);
- sk->write_seq++;
- t=del_timer(&sk->timer);
- if(t)
- add_timer(&sk->timer);
- else
- reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- return;
- }
-
- /*
- * We ought to check if the end of the queue is a buffer and
- * if so simply add the fin to that buffer, not send it ahead.
- */
-
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff->len += tmp;
- buff->dev = dev;
- memcpy(t1, th, sizeof(*t1));
- t1->seq = ntohl(sk->write_seq);
- sk->write_seq++;
- buff->h.seq = sk->write_seq;
- t1->ack = 1;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(sk->window=tcp_select_window(sk));
- t1->fin = 1;
- t1->rst = 0;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
- /*
- * If there is data in the write queue, the fin must be appended to
- * the write queue.
- */
-
- if (skb_peek(&sk->write_queue) != NULL)
- {
- buff->free = 0;
- if (buff->next != NULL)
- {
- printk("tcp_send_fin: next != NULL\n");
- skb_unlink(buff);
- }
- skb_queue_tail(&sk->write_queue, buff);
- }
- else
- {
- sk->sent_seq = sk->write_seq;
- sk->prot->queue_xmit(sk, dev, buff, 0);
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- }
-}
-
-/*
- * Shutdown the sending side of a connection. Much like close except
- * that we don't receive shut down or set sk->dead=1.
- */
-
-void tcp_shutdown(struct sock *sk, int how)
-{
- /*
- * We need to grab some memory, and put together a FIN,
- * and then put it into the queue to be sent.
- * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92.
- */
-
- if (!(how & SEND_SHUTDOWN))
- return;
-
- /*
- * If we've already sent a FIN, or it's a closed state
- */
-
- if (sk->state == TCP_FIN_WAIT1 ||
- sk->state == TCP_FIN_WAIT2 ||
- sk->state == TCP_CLOSING ||
- sk->state == TCP_LAST_ACK ||
- sk->state == TCP_TIME_WAIT ||
- sk->state == TCP_CLOSE ||
- sk->state == TCP_LISTEN
- )
- {
- return;
- }
- sk->inuse = 1;
-
- /*
- * flag that the sender has shutdown
- */
-
- sk->shutdown |= SEND_SHUTDOWN;
-
- /*
- * Clear out any half completed packets.
- */
-
- if (sk->partial)
- tcp_send_partial(sk);
-
- /*
- * FIN if needed
- */
-
- if(tcp_close_state(sk,0))
- tcp_send_fin(sk);
-
- release_sock(sk);
-}
-
-
-static int
-tcp_recvfrom(struct sock *sk, unsigned char *to,
- int to_len, int nonblock, unsigned flags,
- struct sockaddr_in *addr, int *addr_len)
-{
- int result;
-
- /*
- * Have to check these first unlike the old code. If
- * we check them after we lose data on an error
- * which is wrong
- */
-
- if(addr_len)
- *addr_len = sizeof(*addr);
- result=tcp_read(sk, to, to_len, nonblock, flags);
-
- if (result < 0)
- return(result);
-
- if(addr)
- {
- addr->sin_family = AF_INET;
- addr->sin_port = sk->dummy_th.dest;
- addr->sin_addr.s_addr = sk->daddr;
- }
- return(result);
-}
-
-
-/*
- * This routine will send an RST to the other tcp.
- */
-
-static void tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
- struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl)
-{
- struct sk_buff *buff;
- struct tcphdr *t1;
- int tmp;
- struct device *ndev=NULL;
-
- /*
- * Cannot reset a reset (Think about it).
- */
-
- if(th->rst)
- return;
-
- /*
- * We need to grab some memory, and put together an RST,
- * and then put it into the queue to be sent.
- */
-
- buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- return;
-
- buff->len = sizeof(*t1);
- buff->sk = NULL;
- buff->dev = dev;
- buff->localroute = 0;
-
- t1 =(struct tcphdr *) buff->data;
-
- /*
- * Put in the IP header and routing stuff.
- */
-
- tmp = prot->build_header(buff, saddr, daddr, &ndev, IPPROTO_TCP, opt,
- sizeof(struct tcphdr),tos,ttl);
- if (tmp < 0)
- {
- buff->free = 1;
- prot->wfree(NULL, buff->mem_addr, buff->mem_len);
- return;
- }
-
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff->len += tmp;
- memcpy(t1, th, sizeof(*t1));
-
- /*
- * Swap the send and the receive.
- */
-
- t1->dest = th->source;
- t1->source = th->dest;
- t1->rst = 1;
- t1->window = 0;
-
- if(th->ack)
- {
- t1->ack = 0;
- t1->seq = th->ack_seq;
- t1->ack_seq = 0;
- }
- else
- {
- t1->ack = 1;
- if(!th->syn)
- t1->ack_seq=htonl(th->seq);
- else
- t1->ack_seq=htonl(th->seq+1);
- t1->seq=0;
- }
-
- t1->syn = 0;
- t1->urg = 0;
- t1->fin = 0;
- t1->psh = 0;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
- prot->queue_xmit(NULL, ndev, buff, 1);
- tcp_statistics.TcpOutSegs++;
-}
-
-
-/*
- * Look for tcp options. Parses everything but only knows about MSS.
- * This routine is always called with the packet containing the SYN.
- * However it may also be called with the ack to the SYN. So you
- * can't assume this is always the SYN. It's always called after
- * we have set up sk->mtu to our own MTU.
- *
- * We need at minimum to add PAWS support here. Possibly large windows
- * as Linux gets deployed on 100Mb/sec networks.
- */
-
-static void tcp_options(struct sock *sk, struct tcphdr *th)
-{
- unsigned char *ptr;
- int length=(th->doff*4)-sizeof(struct tcphdr);
- int mss_seen = 0;
-
- ptr = (unsigned char *)(th + 1);
-
- while(length>0)
- {
- int opcode=*ptr++;
- int opsize=*ptr++;
- switch(opcode)
- {
- case TCPOPT_EOL:
- return;
- case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
- length--;
- ptr--; /* the opsize=*ptr++ above was a mistake */
- continue;
-
- default:
- if(opsize<=2) /* Avoid silly options looping forever */
- return;
- switch(opcode)
- {
- case TCPOPT_MSS:
- if(opsize==4 && th->syn)
- {
- sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
- mss_seen = 1;
- }
- break;
- /* Add other options here as people feel the urge to implement stuff like large windows */
- }
- ptr+=opsize-2;
- length-=opsize;
- }
- }
- if (th->syn)
- {
- if (! mss_seen)
- sk->mtu=min(sk->mtu, 536); /* default MSS if none sent */
- }
-#ifdef CONFIG_INET_PCTCP
- sk->mss = min(sk->max_window >> 1, sk->mtu);
-#else
- sk->mss = min(sk->max_window, sk->mtu);
-#endif
-}
-
-static inline unsigned long default_mask(unsigned long dst)
-{
- dst = ntohl(dst);
- if (IN_CLASSA(dst))
- return htonl(IN_CLASSA_NET);
- if (IN_CLASSB(dst))
- return htonl(IN_CLASSB_NET);
- return htonl(IN_CLASSC_NET);
-}
-
-/*
- * Default sequence number picking algorithm.
- * As close as possible to RFC 793, which
- * suggests using a 250kHz clock.
- * Further reading shows this assumes 2MB/s networks.
- * For 10MB/s ethernet, a 1MHz clock is appropriate.
- * That's funny, Linux has one built in! Use it!
- */
-
-extern inline unsigned long tcp_init_seq(void)
-{
- struct timeval tv;
- do_gettimeofday(&tv);
- return tv.tv_usec+tv.tv_sec*1000000;
-}
-
-/*
- * This routine handles a connection request.
- * It should make sure we haven't already responded.
- * Because of the way BSD works, we have to send a syn/ack now.
- * This also means it will be harder to close a socket which is
- * listening.
- */
-
-static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
- unsigned long daddr, unsigned long saddr,
- struct options *opt, struct device *dev, unsigned long seq)
-{
- struct sk_buff *buff;
- struct tcphdr *t1;
- unsigned char *ptr;
- struct sock *newsk;
- struct tcphdr *th;
- struct device *ndev=NULL;
- int tmp;
- struct rtable *rt;
-
- th = skb->h.th;
-
- /* If the socket is dead, don't accept the connection. */
- if (!sk->dead)
- {
- sk->data_ready(sk,0);
- }
- else
- {
- if(sk->debug)
- printk("Reset on %p: Connect on dead socket.\n",sk);
- tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl);
- tcp_statistics.TcpAttemptFails++;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Make sure we can accept more. This will prevent a
- * flurry of syns from eating up all our memory.
- */
-
- if (sk->ack_backlog >= sk->max_ack_backlog)
- {
- tcp_statistics.TcpAttemptFails++;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * We need to build a new sock struct.
- * It is sort of bad to have a socket without an inode attached
- * to it, but the wake_up's will just wake up the listening socket,
- * and if the listening socket is destroyed before this is taken
- * off of the queue, this will take care of it.
- */
-
- newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
- if (newsk == NULL)
- {
- /* just ignore the syn. It will get retransmitted. */
- tcp_statistics.TcpAttemptFails++;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- memcpy(newsk, sk, sizeof(*newsk));
- skb_queue_head_init(&newsk->write_queue);
- skb_queue_head_init(&newsk->receive_queue);
- newsk->send_head = NULL;
- newsk->send_tail = NULL;
- skb_queue_head_init(&newsk->back_log);
- newsk->rtt = 0; /*TCP_CONNECT_TIME<<3*/
- newsk->rto = TCP_TIMEOUT_INIT;
- newsk->mdev = 0;
- newsk->max_window = 0;
- newsk->cong_window = 1;
- newsk->cong_count = 0;
- newsk->ssthresh = 0;
- newsk->backoff = 0;
- newsk->blog = 0;
- newsk->intr = 0;
- newsk->proc = 0;
- newsk->done = 0;
- newsk->partial = NULL;
- newsk->pair = NULL;
- newsk->wmem_alloc = 0;
- newsk->rmem_alloc = 0;
- newsk->localroute = sk->localroute;
-
- newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
-
- newsk->err = 0;
- newsk->shutdown = 0;
- newsk->ack_backlog = 0;
- newsk->acked_seq = skb->h.th->seq+1;
- newsk->copied_seq = skb->h.th->seq+1;
- newsk->fin_seq = skb->h.th->seq;
- newsk->state = TCP_SYN_RECV;
- newsk->timeout = 0;
- newsk->ip_xmit_timeout = 0;
- newsk->write_seq = seq;
- newsk->window_seq = newsk->write_seq;
- newsk->rcv_ack_seq = newsk->write_seq;
- newsk->urg_data = 0;
- newsk->retransmits = 0;
- newsk->linger=0;
- newsk->destroy = 0;
- init_timer(&newsk->timer);
- newsk->timer.data = (unsigned long)newsk;
- newsk->timer.function = &net_timer;
- init_timer(&newsk->retransmit_timer);
- newsk->retransmit_timer.data = (unsigned long)newsk;
- newsk->retransmit_timer.function=&retransmit_timer;
- newsk->dummy_th.source = skb->h.th->dest;
- newsk->dummy_th.dest = skb->h.th->source;
-
- /*
- * Swap these two, they are from our point of view.
- */
-
- newsk->daddr = saddr;
- newsk->saddr = daddr;
-
- put_sock(newsk->num,newsk);
- newsk->dummy_th.res1 = 0;
- newsk->dummy_th.doff = 6;
- newsk->dummy_th.fin = 0;
- newsk->dummy_th.syn = 0;
- newsk->dummy_th.rst = 0;
- newsk->dummy_th.psh = 0;
- newsk->dummy_th.ack = 0;
- newsk->dummy_th.urg = 0;
- newsk->dummy_th.res2 = 0;
- newsk->acked_seq = skb->h.th->seq + 1;
- newsk->copied_seq = skb->h.th->seq + 1;
- newsk->socket = NULL;
-
- /*
- * Grab the ttl and tos values and use them
- */
-
- newsk->ip_ttl=sk->ip_ttl;
- newsk->ip_tos=skb->ip_hdr->tos;
-
- /*
- * Use 512 or whatever user asked for
- */
-
- /*
- * Note use of sk->user_mss, since user has no direct access to newsk
- */
-
- rt=ip_rt_route(saddr, NULL,NULL);
-
- if(rt!=NULL && (rt->rt_flags&RTF_WINDOW))
- newsk->window_clamp = rt->rt_window;
- else
- newsk->window_clamp = 0;
-
- if (sk->user_mss)
- newsk->mtu = sk->user_mss;
- else if(rt!=NULL && (rt->rt_flags&RTF_MSS))
- newsk->mtu = rt->rt_mss - HEADER_SIZE;
- else
- {
-#ifdef CONFIG_INET_SNARL /* Sub Nets Are Local */
- if ((saddr ^ daddr) & default_mask(saddr))
-#else
- if ((saddr ^ daddr) & dev->pa_mask)
-#endif
- newsk->mtu = 576 - HEADER_SIZE;
- else
- newsk->mtu = MAX_WINDOW;
- }
-
- /*
- * But not bigger than device MTU
- */
-
- newsk->mtu = min(newsk->mtu, dev->mtu - HEADER_SIZE);
-
- /*
- * This will min with what arrived in the packet
- */
-
- tcp_options(newsk,skb->h.th);
-
- buff = newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- {
- sk->err = -ENOMEM;
- newsk->dead = 1;
- newsk->state = TCP_CLOSE;
- /* And this will destroy it */
- release_sock(newsk);
- kfree_skb(skb, FREE_READ);
- tcp_statistics.TcpAttemptFails++;
- return;
- }
-
- buff->len = sizeof(struct tcphdr)+4;
- buff->sk = newsk;
- buff->localroute = newsk->localroute;
-
- t1 =(struct tcphdr *) buff->data;
-
- /*
- * Put in the IP header and routing stuff.
- */
-
- tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &ndev,
- IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
-
- /*
- * Something went wrong.
- */
-
- if (tmp < 0)
- {
- sk->err = tmp;
- buff->free = 1;
- kfree_skb(buff,FREE_WRITE);
- newsk->dead = 1;
- newsk->state = TCP_CLOSE;
- release_sock(newsk);
- skb->sk = sk;
- kfree_skb(skb, FREE_READ);
- tcp_statistics.TcpAttemptFails++;
- return;
- }
-
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)t1 +tmp);
-
- memcpy(t1, skb->h.th, sizeof(*t1));
- buff->h.seq = newsk->write_seq;
- /*
- * Swap the send and the receive.
- */
- t1->dest = skb->h.th->source;
- t1->source = newsk->dummy_th.source;
- t1->seq = ntohl(newsk->write_seq++);
- t1->ack = 1;
- newsk->window = tcp_select_window(newsk);
- newsk->sent_seq = newsk->write_seq;
- t1->window = ntohs(newsk->window);
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->syn = 1;
- t1->ack_seq = ntohl(skb->h.th->seq+1);
- t1->doff = sizeof(*t1)/4+1;
- ptr =(unsigned char *)(t1+1);
- ptr[0] = 2;
- ptr[1] = 4;
- ptr[2] = ((newsk->mtu) >> 8) & 0xff;
- ptr[3] =(newsk->mtu) & 0xff;
-
- tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
- newsk->prot->queue_xmit(newsk, ndev, buff, 0);
- reset_xmit_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT);
- skb->sk = newsk;
-
- /*
- * Charge the sock_buff to newsk.
- */
-
- sk->rmem_alloc -= skb->mem_len;
- newsk->rmem_alloc += skb->mem_len;
-
- skb_queue_tail(&sk->receive_queue,skb);
- sk->ack_backlog++;
- release_sock(newsk);
- tcp_statistics.TcpOutSegs++;
-}
-
-
-static void tcp_close(struct sock *sk, int timeout)
-{
- /*
- * We need to grab some memory, and put together a FIN,
- * and then put it into the queue to be sent.
- */
-
- sk->inuse = 1;
-
- if(sk->state == TCP_LISTEN)
- {
- /* Special case */
- tcp_set_state(sk, TCP_CLOSE);
- tcp_close_pending(sk);
- release_sock(sk);
- return;
- }
-
- sk->keepopen = 1;
- sk->shutdown = SHUTDOWN_MASK;
-
- if (!sk->dead)
- sk->state_change(sk);
-
- if (timeout == 0)
- {
- struct sk_buff *skb;
-
- /*
- * We need to flush the recv. buffs. We do this only on the
- * descriptor close, not protocol-sourced closes, because the
- * reader process may not have drained the data yet!
- */
-
- while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
- kfree_skb(skb, FREE_READ);
- /*
- * Get rid off any half-completed packets.
- */
-
- if (sk->partial)
- tcp_send_partial(sk);
- }
-
-
- /*
- * Timeout is not the same thing - however the code likes
- * to send both the same way (sigh).
- */
-
- if(timeout)
- {
- tcp_set_state(sk, TCP_CLOSE); /* Dead */
- }
- else
- {
- if(tcp_close_state(sk,1)==1)
- {
- tcp_send_fin(sk);
- }
- }
- release_sock(sk);
-}
-
-
-/*
- * This routine takes stuff off of the write queue,
- * and puts it in the xmit queue. This happens as incoming acks
- * open up the remote window for us.
- */
-
-static void tcp_write_xmit(struct sock *sk)
-{
- struct sk_buff *skb;
-
- /*
- * The bytes will have to remain here. In time closedown will
- * empty the write queue and all will be happy
- */
-
- if(sk->zapped)
- return;
-
- /*
- * Anything on the transmit queue that fits the window can
- * be added providing we are not
- *
- * a) retransmitting (Nagle's rule)
- * b) exceeding our congestion window.
- */
-
- while((skb = skb_peek(&sk->write_queue)) != NULL &&
- before(skb->h.seq, sk->window_seq + 1) &&
- (sk->retransmits == 0 ||
- sk->ip_xmit_timeout != TIME_WRITE ||
- before(skb->h.seq, sk->rcv_ack_seq + 1))
- && sk->packets_out < sk->cong_window)
- {
- IS_SKB(skb);
- skb_unlink(skb);
-
- /*
- * See if we really need to send the packet.
- */
-
- if (before(skb->h.seq, sk->rcv_ack_seq +1))
- {
- /*
- * This is acked data. We can discard it. This
- * cannot currently occur.
- */
-
- sk->retransmits = 0;
- kfree_skb(skb, FREE_WRITE);
- if (!sk->dead)
- sk->write_space(sk);
- }
- else
- {
- struct tcphdr *th;
- struct iphdr *iph;
- int size;
-/*
- * put in the ack seq and window at this point rather than earlier,
- * in order to keep them monotonic. We really want to avoid taking
- * back window allocations. That's legal, but RFC1122 says it's frowned on.
- * Ack and window will in general have changed since this packet was put
- * on the write queue.
- */
- iph = (struct iphdr *)(skb->data +
- skb->dev->hard_header_len);
- th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2));
- size = skb->len - (((unsigned char *) th) - skb->data);
-
- th->ack_seq = ntohl(sk->acked_seq);
- th->window = ntohs(tcp_select_window(sk));
-
- tcp_send_check(th, sk->saddr, sk->daddr, size, sk);
-
- sk->sent_seq = skb->h.seq;
-
- /*
- * IP manages our queue for some crazy reason
- */
-
- sk->prot->queue_xmit(sk, skb->dev, skb, skb->free);
-
- /*
- * Again we slide the timer wrongly
- */
-
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- }
- }
-}
-
-
-/*
- * This routine deals with incoming acks, but not outgoing ones.
- */
-
-extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
-{
- unsigned long ack;
- int flag = 0;
-
- /*
- * 1 - there was data in packet as well as ack or new data is sent or
- * in shutdown state
- * 2 - data from retransmit queue was acked and removed
- * 4 - window shrunk or data from retransmit queue was acked and removed
- */
-
- if(sk->zapped)
- return(1); /* Dead, cant ack any more so why bother */
-
- /*
- * Have we discovered a larger window
- */
-
- ack = ntohl(th->ack_seq);
-
- if (ntohs(th->window) > sk->max_window)
- {
- sk->max_window = ntohs(th->window);
-#ifdef CONFIG_INET_PCTCP
- /* Hack because we don't send partial packets to non SWS
- handling hosts */
- sk->mss = min(sk->max_window>>1, sk->mtu);
-#else
- sk->mss = min(sk->max_window, sk->mtu);
-#endif
- }
-
- /*
- * We have dropped back to keepalive timeouts. Thus we have
- * no retransmits pending.
- */
-
- if (sk->retransmits && sk->ip_xmit_timeout == TIME_KEEPOPEN)
- sk->retransmits = 0;
-
- /*
- * If the ack is newer than sent or older than previous acks
- * then we can probably ignore it.
- */
-
- if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq))
- {
- if(sk->debug)
- printk("Ack ignored %lu %lu\n",ack,sk->sent_seq);
-
- /*
- * Keepalive processing.
- */
-
- if (after(ack, sk->sent_seq))
- {
- return(0);
- }
-
- /*
- * Restart the keepalive timer.
- */
-
- if (sk->keepopen)
- {
- if(sk->ip_xmit_timeout==TIME_KEEPOPEN)
- reset_xmit_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
- }
- return(1);
- }
-
- /*
- * If there is data set flag 1
- */
-
- if (len != th->doff*4)
- flag |= 1;
-
- /*
- * See if our window has been shrunk.
- */
-
- if (after(sk->window_seq, ack+ntohs(th->window)))
- {
- /*
- * We may need to move packets from the send queue
- * to the write queue, if the window has been shrunk on us.
- * The RFC says you are not allowed to shrink your window
- * like this, but if the other end does, you must be able
- * to deal with it.
- */
- struct sk_buff *skb;
- struct sk_buff *skb2;
- struct sk_buff *wskb = NULL;
-
- skb2 = sk->send_head;
- sk->send_head = NULL;
- sk->send_tail = NULL;
-
- /*
- * This is an artifact of a flawed concept. We want one
- * queue and a smarter send routine when we send all.
- */
-
- flag |= 4; /* Window changed */
-
- sk->window_seq = ack + ntohs(th->window);
- cli();
- while (skb2 != NULL)
- {
- skb = skb2;
- skb2 = skb->link3;
- skb->link3 = NULL;
- if (after(skb->h.seq, sk->window_seq))
- {
- if (sk->packets_out > 0)
- sk->packets_out--;
- /* We may need to remove this from the dev send list. */
- if (skb->next != NULL)
- {
- skb_unlink(skb);
- }
- /* Now add it to the write_queue. */
- if (wskb == NULL)
- skb_queue_head(&sk->write_queue,skb);
- else
- skb_append(wskb,skb);
- wskb = skb;
- }
- else
- {
- if (sk->send_head == NULL)
- {
- sk->send_head = skb;
- sk->send_tail = skb;
- }
- else
- {
- sk->send_tail->link3 = skb;
- sk->send_tail = skb;
- }
- skb->link3 = NULL;
- }
- }
- sti();
- }
-
- /*
- * Pipe has emptied
- */
-
- if (sk->send_tail == NULL || sk->send_head == NULL)
- {
- sk->send_head = NULL;
- sk->send_tail = NULL;
- sk->packets_out= 0;
- }
-
- /*
- * Update the right hand window edge of the host
- */
-
- sk->window_seq = ack + ntohs(th->window);
-
- /*
- * We don't want too many packets out there.
- */
-
- if (sk->ip_xmit_timeout == TIME_WRITE &&
- sk->cong_window < 2048 && after(ack, sk->rcv_ack_seq))
- {
- /*
- * This is Jacobson's slow start and congestion avoidance.
- * SIGCOMM '88, p. 328. Because we keep cong_window in integral
- * mss's, we can't do cwnd += 1 / cwnd. Instead, maintain a
- * counter and increment it once every cwnd times. It's possible
- * that this should be done only if sk->retransmits == 0. I'm
- * interpreting "new data is acked" as including data that has
- * been retransmitted but is just now being acked.
- */
- if (sk->cong_window < sk->ssthresh)
- /*
- * In "safe" area, increase
- */
- sk->cong_window++;
- else
- {
- /*
- * In dangerous area, increase slowly. In theory this is
- * sk->cong_window += 1 / sk->cong_window
- */
- if (sk->cong_count >= sk->cong_window)
- {
- sk->cong_window++;
- sk->cong_count = 0;
- }
- else
- sk->cong_count++;
- }
- }
-
- /*
- * Remember the highest ack received.
- */
-
- sk->rcv_ack_seq = ack;
-
- /*
- * If this ack opens up a zero window, clear backoff. It was
- * being used to time the probes, and is probably far higher than
- * it needs to be for normal retransmission.
- */
-
- if (sk->ip_xmit_timeout == TIME_PROBE0)
- {
- sk->retransmits = 0; /* Our probe was answered */
-
- /*
- * Was it a usable window open ?
- */
-
- if (skb_peek(&sk->write_queue) != NULL && /* should always be non-null */
- ! before (sk->window_seq, sk->write_queue.next->h.seq))
- {
- sk->backoff = 0;
-
- /*
- * Recompute rto from rtt. this eliminates any backoff.
- */
-
- sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
- if (sk->rto > 120*HZ)
- sk->rto = 120*HZ;
- if (sk->rto < 20) /* Was 1*HZ, then 1 - turns out we must allow about
- .2 of a second because of BSD delayed acks - on a 100Mb/sec link
- .2 of a second is going to need huge windows (SIGH) */
- sk->rto = 20;
- }
- }
-
- /*
- * See if we can take anything off of the retransmit queue.
- */
-
- while(sk->send_head != NULL)
- {
- /* Check for a bug. */
- if (sk->send_head->link3 &&
- after(sk->send_head->h.seq, sk->send_head->link3->h.seq))
- printk("INET: tcp.c: *** bug send_list out of order.\n");
-
- /*
- * If our packet is before the ack sequence we can
- * discard it as it's confirmed to have arrived the other end.
- */
-
- if (before(sk->send_head->h.seq, ack+1))
- {
- struct sk_buff *oskb;
- if (sk->retransmits)
- {
- /*
- * We were retransmitting. don't count this in RTT est
- */
- flag |= 2;
-
- /*
- * even though we've gotten an ack, we're still
- * retransmitting as long as we're sending from
- * the retransmit queue. Keeping retransmits non-zero
- * prevents us from getting new data interspersed with
- * retransmissions.
- */
-
- if (sk->send_head->link3) /* Any more queued retransmits? */
- sk->retransmits = 1;
- else
- sk->retransmits = 0;
- }
- /*
- * Note that we only reset backoff and rto in the
- * rtt recomputation code. And that doesn't happen
- * if there were retransmissions in effect. So the
- * first new packet after the retransmissions is
- * sent with the backoff still in effect. Not until
- * we get an ack from a non-retransmitted packet do
- * we reset the backoff and rto. This allows us to deal
- * with a situation where the network delay has increased
- * suddenly. I.e. Karn's algorithm. (SIGCOMM '87, p5.)
- */
-
- /*
- * We have one less packet out there.
- */
-
- if (sk->packets_out > 0)
- sk->packets_out --;
- /*
- * Wake up the process, it can probably write more.
- */
- if (!sk->dead)
- sk->write_space(sk);
- oskb = sk->send_head;
-
- if (!(flag&2)) /* Not retransmitting */
- {
- long m;
-
- /*
- * The following amusing code comes from Jacobson's
- * article in SIGCOMM '88. Note that rtt and mdev
- * are scaled versions of rtt and mean deviation.
- * This is designed to be as fast as possible
- * m stands for "measurement".
- */
-
- m = jiffies - oskb->when; /* RTT */
- if(m<=0)
- m=1; /* IS THIS RIGHT FOR <0 ??? */
- m -= (sk->rtt >> 3); /* m is now error in rtt est */
- sk->rtt += m; /* rtt = 7/8 rtt + 1/8 new */
- if (m < 0)
- m = -m; /* m is now abs(error) */
- m -= (sk->mdev >> 2); /* similar update on mdev */
- sk->mdev += m; /* mdev = 3/4 mdev + 1/4 new */
-
- /*
- * Now update timeout. Note that this removes any backoff.
- */
-
- sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
- if (sk->rto > 120*HZ)
- sk->rto = 120*HZ;
- if (sk->rto < 20) /* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */
- sk->rto = 20;
- sk->backoff = 0;
- }
- flag |= (2|4); /* 2 is really more like 'don't adjust the rtt
- In this case as we just set it up */
- cli();
- oskb = sk->send_head;
- IS_SKB(oskb);
- sk->send_head = oskb->link3;
- if (sk->send_head == NULL)
- {
- sk->send_tail = NULL;
- }
-
- /*
- * We may need to remove this from the dev send list.
- */
-
- if (oskb->next)
- skb_unlink(oskb);
- sti();
- kfree_skb(oskb, FREE_WRITE); /* write. */
- if (!sk->dead)
- sk->write_space(sk);
- }
- else
- {
- break;
- }
- }
-
- /*
- * XXX someone ought to look at this too.. at the moment, if skb_peek()
- * returns non-NULL, we complete ignore the timer stuff in the else
- * clause. We ought to organize the code so that else clause can
- * (should) be executed regardless, possibly moving the PROBE timer
- * reset over. The skb_peek() thing should only move stuff to the
- * write queue, NOT also manage the timer functions.
- */
-
- /*
- * Maybe we can take some stuff off of the write queue,
- * and put it onto the xmit queue.
- */
- if (skb_peek(&sk->write_queue) != NULL)
- {
- if (after (sk->window_seq+1, sk->write_queue.next->h.seq) &&
- (sk->retransmits == 0 ||
- sk->ip_xmit_timeout != TIME_WRITE ||
- before(sk->write_queue.next->h.seq, sk->rcv_ack_seq + 1))
- && sk->packets_out < sk->cong_window)
- {
- /*
- * Add more data to the send queue.
- */
- flag |= 1;
- tcp_write_xmit(sk);
- }
- else if (before(sk->window_seq, sk->write_queue.next->h.seq) &&
- sk->send_head == NULL &&
- sk->ack_backlog == 0 &&
- sk->state != TCP_TIME_WAIT)
- {
- /*
- * Data to queue but no room.
- */
- reset_xmit_timer(sk, TIME_PROBE0, sk->rto);
- }
- }
- else
- {
- /*
- * from TIME_WAIT we stay in TIME_WAIT as long as we rx packets
- * from TCP_CLOSE we don't do anything
- *
- * from anything else, if there is write data (or fin) pending,
- * we use a TIME_WRITE timeout, else if keepalive we reset to
- * a KEEPALIVE timeout, else we delete the timer.
- *
- * We do not set flag for nominal write data, otherwise we may
- * force a state where we start to write itsy bitsy tidbits
- * of data.
- */
-
- switch(sk->state) {
- case TCP_TIME_WAIT:
- /*
- * keep us in TIME_WAIT until we stop getting packets,
- * reset the timeout.
- */
- reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- break;
- case TCP_CLOSE:
- /*
- * don't touch the timer.
- */
- break;
- default:
- /*
- * Must check send_head, write_queue, and ack_backlog
- * to determine which timeout to use.
- */
- if (sk->send_head || skb_peek(&sk->write_queue) != NULL || sk->ack_backlog) {
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- } else if (sk->keepopen) {
- reset_xmit_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
- } else {
- del_timer(&sk->retransmit_timer);
- sk->ip_xmit_timeout = 0;
- }
- break;
- }
- }
-
- /*
- * We have nothing queued but space to send. Send any partial
- * packets immediately (end of Nagle rule application).
- */
-
- if (sk->packets_out == 0 && sk->partial != NULL &&
- skb_peek(&sk->write_queue) == NULL && sk->send_head == NULL)
- {
- flag |= 1;
- tcp_send_partial(sk);
- }
-
- /*
- * In the LAST_ACK case, the other end FIN'd us. We then FIN'd them, and
- * we are now waiting for an acknowledge to our FIN. The other end is
- * already in TIME_WAIT.
- *
- * Move to TCP_CLOSE on success.
- */
-
- if (sk->state == TCP_LAST_ACK)
- {
- if (!sk->dead)
- sk->state_change(sk);
- if(sk->debug)
- printk("rcv_ack_seq: %lX==%lX, acked_seq: %lX==%lX\n",
- sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq);
- if (sk->rcv_ack_seq == sk->write_seq /*&& sk->acked_seq == sk->fin_seq*/)
- {
- flag |= 1;
- tcp_set_state(sk,TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
- }
- }
-
- /*
- * Incoming ACK to a FIN we sent in the case of our initiating the close.
- *
- * Move to FIN_WAIT2 to await a FIN from the other end. Set
- * SEND_SHUTDOWN but not RCV_SHUTDOWN as data can still be coming in.
- */
-
- if (sk->state == TCP_FIN_WAIT1)
- {
-
- if (!sk->dead)
- sk->state_change(sk);
- if (sk->rcv_ack_seq == sk->write_seq)
- {
- flag |= 1;
- sk->shutdown |= SEND_SHUTDOWN;
- tcp_set_state(sk, TCP_FIN_WAIT2);
- }
- }
-
- /*
- * Incoming ACK to a FIN we sent in the case of a simultaneous close.
- *
- * Move to TIME_WAIT
- */
-
- if (sk->state == TCP_CLOSING)
- {
-
- if (!sk->dead)
- sk->state_change(sk);
- if (sk->rcv_ack_seq == sk->write_seq)
- {
- flag |= 1;
- tcp_time_wait(sk);
- }
- }
-
- /*
- * Final ack of a three way shake
- */
-
- if(sk->state==TCP_SYN_RECV)
- {
- tcp_set_state(sk, TCP_ESTABLISHED);
- tcp_options(sk,th);
- sk->dummy_th.dest=th->source;
- sk->copied_seq = sk->acked_seq;
- if(!sk->dead)
- sk->state_change(sk);
- if(sk->max_window==0)
- {
- sk->max_window=32; /* Sanity check */
- sk->mss=min(sk->max_window,sk->mtu);
- }
- }
-
- /*
- * I make no guarantees about the first clause in the following
- * test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under
- * what conditions "!flag" would be true. However I think the rest
- * of the conditions would prevent that from causing any
- * unnecessary retransmission.
- * Clearly if the first packet has expired it should be
- * retransmitted. The other alternative, "flag&2 && retransmits", is
- * harder to explain: You have to look carefully at how and when the
- * timer is set and with what timeout. The most recent transmission always
- * sets the timer. So in general if the most recent thing has timed
- * out, everything before it has as well. So we want to go ahead and
- * retransmit some more. If we didn't explicitly test for this
- * condition with "flag&2 && retransmits", chances are "when + rto < jiffies"
- * would not be true. If you look at the pattern of timing, you can
- * show that rto is increased fast enough that the next packet would
- * almost never be retransmitted immediately. Then you'd end up
- * waiting for a timeout to send each packet on the retransmission
- * queue. With my implementation of the Karn sampling algorithm,
- * the timeout would double each time. The net result is that it would
- * take a hideous amount of time to recover from a single dropped packet.
- * It's possible that there should also be a test for TIME_WRITE, but
- * I think as long as "send_head != NULL" and "retransmit" is on, we've
- * got to be in real retransmission mode.
- * Note that tcp_do_retransmit is called with all==1. Setting cong_window
- * back to 1 at the timeout will cause us to send 1, then 2, etc. packets.
- * As long as no further losses occur, this seems reasonable.
- */
-
- if (((!flag) || (flag&4)) && sk->send_head != NULL &&
- (((flag&2) && sk->retransmits) ||
- (sk->send_head->when + sk->rto < jiffies)))
- {
- if(sk->send_head->when + sk->rto < jiffies)
- tcp_retransmit(sk,0);
- else
- {
- tcp_do_retransmit(sk, 1);
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- }
- }
-
- return(1);
-}
-
-
-/*
- * Process the FIN bit. This now behaves as it is supposed to work
- * and the FIN takes effect when it is validly part of sequence
- * space. Not before when we get holes.
- *
- * If we are ESTABLISHED, a received fin moves us to CLOSE-WAIT
- * (and thence onto LAST-ACK and finally, CLOSE, we never enter
- * TIME-WAIT)
- *
- * If we are in FINWAIT-1, a received FIN indicates simultaneous
- * close and we go into CLOSING (and later onto TIME-WAIT)
- *
- * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
- *
- */
-
-static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
-{
- sk->fin_seq = th->seq + skb->len + th->syn + th->fin;
-
- if (!sk->dead)
- {
- sk->state_change(sk);
- sock_wake_async(sk->socket, 1);
- }
-
- switch(sk->state)
- {
- case TCP_SYN_RECV:
- case TCP_SYN_SENT:
- case TCP_ESTABLISHED:
- /*
- * move to CLOSE_WAIT, tcp_data() already handled
- * sending the ack.
- */
- tcp_set_state(sk,TCP_CLOSE_WAIT);
- if (th->rst)
- sk->shutdown = SHUTDOWN_MASK;
- break;
-
- case TCP_CLOSE_WAIT:
- case TCP_CLOSING:
- /*
- * received a retransmission of the FIN, do
- * nothing.
- */
- break;
- case TCP_TIME_WAIT:
- /*
- * received a retransmission of the FIN,
- * restart the TIME_WAIT timer.
- */
- reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- return(0);
- case TCP_FIN_WAIT1:
- /*
- * This case occurs when a simultaneous close
- * happens, we must ack the received FIN and
- * enter the CLOSING state.
- *
- * This causes a WRITE timeout, which will either
- * move on to TIME_WAIT when we timeout, or resend
- * the FIN properly (maybe we get rid of that annoying
- * FIN lost hang). The TIME_WRITE code is already correct
- * for handling this timeout.
- */
-
- if(sk->ip_xmit_timeout != TIME_WRITE)
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- tcp_set_state(sk,TCP_CLOSING);
- break;
- case TCP_FIN_WAIT2:
- /*
- * received a FIN -- send ACK and enter TIME_WAIT
- */
- reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- sk->shutdown|=SHUTDOWN_MASK;
- tcp_set_state(sk,TCP_TIME_WAIT);
- break;
- case TCP_CLOSE:
- /*
- * already in CLOSE
- */
- break;
- default:
- tcp_set_state(sk,TCP_LAST_ACK);
-
- /* Start the timers. */
- reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- return(0);
- }
-
- return(0);
-}
-
-
-
-/*
- * This routine handles the data. If there is room in the buffer,
- * it will be have already been moved into it. If there is no
- * room, then we will just have to discard the packet.
- */
-
-extern __inline__ int tcp_data(struct sk_buff *skb, struct sock *sk,
- unsigned long saddr, unsigned short len)
-{
- struct sk_buff *skb1, *skb2;
- struct tcphdr *th;
- int dup_dumped=0;
- unsigned long new_seq;
- unsigned long shut_seq;
-
- th = skb->h.th;
- skb->len = len -(th->doff*4);
-
- /*
- * The bytes in the receive read/assembly queue has increased. Needed for the
- * low memory discard algorithm
- */
-
- sk->bytes_rcv += skb->len;
-
- if (skb->len == 0 && !th->fin)
- {
- /*
- * Don't want to keep passing ack's back and forth.
- * (someone sent us dataless, boring frame)
- */
- if (!th->ack)
- tcp_send_ack(sk->sent_seq, sk->acked_seq,sk, th, saddr);
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- /*
- * We no longer have anyone receiving data on this connection.
- */
-
-#ifndef TCP_DONT_RST_SHUTDOWN
-
- if(sk->shutdown & RCV_SHUTDOWN)
- {
- /*
- * FIXME: BSD has some magic to avoid sending resets to
- * broken 4.2 BSD keepalives. Much to my surprise a few non
- * BSD stacks still have broken keepalives so we want to
- * cope with it.
- */
-
- if(skb->len) /* We don't care if it's just an ack or
- a keepalive/window probe */
- {
- new_seq= th->seq + skb->len + th->syn; /* Right edge of _data_ part of frame */
-
- /* Do this the way 4.4BSD treats it. Not what I'd
- regard as the meaning of the spec but it's what BSD
- does and clearly they know everything 8) */
-
- /*
- * This is valid because of two things
- *
- * a) The way tcp_data behaves at the bottom.
- * b) A fin takes effect when read not when received.
- */
-
- shut_seq=sk->acked_seq+1; /* Last byte */
-
- if(after(new_seq,shut_seq))
- {
- if(sk->debug)
- printk("Data arrived on %p after close [Data right edge %lX, Socket shut on %lX] %d\n",
- sk, new_seq, shut_seq, sk->blog);
- if(sk->dead)
- {
- sk->acked_seq = new_seq + th->fin;
- tcp_reset(sk->saddr, sk->daddr, skb->h.th,
- sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl);
- tcp_statistics.TcpEstabResets++;
- tcp_set_state(sk,TCP_CLOSE);
- sk->err = EPIPE;
- sk->shutdown = SHUTDOWN_MASK;
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- }
- }
- }
-
-#endif
-
- /*
- * Now we have to walk the chain, and figure out where this one
- * goes into it. This is set up so that the last packet we received
- * will be the first one we look at, that way if everything comes
- * in order, there will be no performance loss, and if they come
- * out of order we will be able to fit things in nicely.
- *
- * [AC: This is wrong. We should assume in order first and then walk
- * forwards from the first hole based upon real traffic patterns.]
- *
- */
-
- if (skb_peek(&sk->receive_queue) == NULL) /* Empty queue is easy case */
- {
- skb_queue_head(&sk->receive_queue,skb);
- skb1= NULL;
- }
- else
- {
- for(skb1=sk->receive_queue.prev; ; skb1 = skb1->prev)
- {
- if(sk->debug)
- {
- printk("skb1=%p :", skb1);
- printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq);
- printk("skb->h.th->seq = %ld\n",skb->h.th->seq);
- printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq,
- sk->acked_seq);
- }
-
- /*
- * Optimisation: Duplicate frame or extension of previous frame from
- * same sequence point (lost ack case).
- * The frame contains duplicate data or replaces a previous frame
- * discard the previous frame (safe as sk->inuse is set) and put
- * the new one in its place.
- */
-
- if (th->seq==skb1->h.th->seq && skb->len>= skb1->len)
- {
- skb_append(skb1,skb);
- skb_unlink(skb1);
- kfree_skb(skb1,FREE_READ);
- dup_dumped=1;
- skb1=NULL;
- break;
- }
-
- /*
- * Found where it fits
- */
-
- if (after(th->seq+1, skb1->h.th->seq))
- {
- skb_append(skb1,skb);
- break;
- }
-
- /*
- * See if we've hit the start. If so insert.
- */
- if (skb1 == skb_peek(&sk->receive_queue))
- {
- skb_queue_head(&sk->receive_queue, skb);
- break;
- }
- }
- }
-
- /*
- * Figure out what the ack value for this frame is
- */
-
- th->ack_seq = th->seq + skb->len;
- if (th->syn)
- th->ack_seq++;
- if (th->fin)
- th->ack_seq++;
-
- if (before(sk->acked_seq, sk->copied_seq))
- {
- printk("*** tcp.c:tcp_data bug acked < copied\n");
- sk->acked_seq = sk->copied_seq;
- }
-
- /*
- * Now figure out if we can ack anything. This is very messy because we really want two
- * receive queues, a completed and an assembly queue. We also want only one transmit
- * queue.
- */
-
- if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1))
- {
- if (before(th->seq, sk->acked_seq+1))
- {
- int newwindow;
-
- if (after(th->ack_seq, sk->acked_seq))
- {
- newwindow = sk->window-(th->ack_seq - sk->acked_seq);
- if (newwindow < 0)
- newwindow = 0;
- sk->window = newwindow;
- sk->acked_seq = th->ack_seq;
- }
- skb->acked = 1;
-
- /*
- * When we ack the fin, we do the FIN
- * processing.
- */
-
- if (skb->h.th->fin)
- {
- tcp_fin(skb,sk,skb->h.th);
- }
-
- for(skb2 = skb->next;
- skb2 != (struct sk_buff *)&sk->receive_queue;
- skb2 = skb2->next)
- {
- if (before(skb2->h.th->seq, sk->acked_seq+1))
- {
- if (after(skb2->h.th->ack_seq, sk->acked_seq))
- {
- newwindow = sk->window -
- (skb2->h.th->ack_seq - sk->acked_seq);
- if (newwindow < 0)
- newwindow = 0;
- sk->window = newwindow;
- sk->acked_seq = skb2->h.th->ack_seq;
- }
- skb2->acked = 1;
- /*
- * When we ack the fin, we do
- * the fin handling.
- */
- if (skb2->h.th->fin)
- {
- tcp_fin(skb,sk,skb->h.th);
- }
-
- /*
- * Force an immediate ack.
- */
-
- sk->ack_backlog = sk->max_ack_backlog;
- }
- else
- {
- break;
- }
- }
-
- /*
- * This also takes care of updating the window.
- * This if statement needs to be simplified.
- */
- if (!sk->delay_acks ||
- sk->ack_backlog >= sk->max_ack_backlog ||
- sk->bytes_rcv > sk->max_unacked || th->fin) {
- /* tcp_send_ack(sk->sent_seq, sk->acked_seq,sk,th, saddr); */
- }
- else
- {
- sk->ack_backlog++;
- if(sk->debug)
- printk("Ack queued.\n");
- reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- }
- }
- }
-
- /*
- * If we've missed a packet, send an ack.
- * Also start a timer to send another.
- */
-
- if (!skb->acked)
- {
-
- /*
- * This is important. If we don't have much room left,
- * we need to throw out a few packets so we have a good
- * window. Note that mtu is used, not mss, because mss is really
- * for the send side. He could be sending us stuff as large as mtu.
- */
-
- while (sk->prot->rspace(sk) < sk->mtu)
- {
- skb1 = skb_peek(&sk->receive_queue);
- if (skb1 == NULL)
- {
- printk("INET: tcp.c:tcp_data memory leak detected.\n");
- break;
- }
-
- /*
- * Don't throw out something that has been acked.
- */
-
- if (skb1->acked)
- {
- break;
- }
-
- skb_unlink(skb1);
- kfree_skb(skb1, FREE_READ);
- }
- tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
- sk->ack_backlog++;
- reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- }
- else
- {
- tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
- }
-
- /*
- * Now tell the user we may have some data.
- */
-
- if (!sk->dead)
- {
- if(sk->debug)
- printk("Data wakeup.\n");
- sk->data_ready(sk,0);
- }
- return(0);
-}
-
-
-/*
- * This routine is only called when we have urgent data
- * signalled. Its the 'slow' part of tcp_urg. It could be
- * moved inline now as tcp_urg is only called from one
- * place. We handle URGent data wrong. We have to - as
- * BSD still doesn't use the correction from RFC961.
- */
-
-static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
-{
- unsigned long ptr = ntohs(th->urg_ptr);
-
- if (ptr)
- ptr--;
- ptr += th->seq;
-
- /* ignore urgent data that we've already seen and read */
- if (after(sk->copied_seq, ptr))
- return;
-
- /* do we already have a newer (or duplicate) urgent pointer? */
- if (sk->urg_data && !after(ptr, sk->urg_seq))
- return;
-
- /* tell the world about our new urgent pointer */
- if (sk->proc != 0) {
- if (sk->proc > 0) {
- kill_proc(sk->proc, SIGURG, 1);
- } else {
- kill_pg(-sk->proc, SIGURG, 1);
- }
- }
- sk->urg_data = URG_NOTYET;
- sk->urg_seq = ptr;
-}
-
-/*
- * This is the 'fast' part of urgent handling.
- */
-
-extern __inline__ int tcp_urg(struct sock *sk, struct tcphdr *th,
- unsigned long saddr, unsigned long len)
-{
- unsigned long ptr;
-
- /*
- * Check if we get a new urgent pointer - normally not
- */
-
- if (th->urg)
- tcp_check_urg(sk,th);
-
- /*
- * Do we wait for any urgent data? - normally not
- */
-
- if (sk->urg_data != URG_NOTYET)
- return 0;
-
- /*
- * Is the urgent pointer pointing into this packet?
- */
-
- ptr = sk->urg_seq - th->seq + th->doff*4;
- if (ptr >= len)
- return 0;
-
- /*
- * Ok, got the correct packet, update info
- */
-
- sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th);
- if (!sk->dead)
- sk->data_ready(sk,0);
- return 0;
-}
-
-/*
- * This will accept the next outstanding connection.
- */
-
-static struct sock *tcp_accept(struct sock *sk, int flags)
-{
- struct sock *newsk;
- struct sk_buff *skb;
-
- /*
- * We need to make sure that this socket is listening,
- * and that it has something pending.
- */
-
- if (sk->state != TCP_LISTEN)
- {
- sk->err = EINVAL;
- return(NULL);
- }
-
- /* Avoid the race. */
- cli();
- sk->inuse = 1;
-
- while((skb = tcp_dequeue_established(sk)) == NULL)
- {
- if (flags & O_NONBLOCK)
- {
- sti();
- release_sock(sk);
- sk->err = EAGAIN;
- return(NULL);
- }
-
- release_sock(sk);
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- sk->err = ERESTARTSYS;
- return(NULL);
- }
- sk->inuse = 1;
- }
- sti();
-
- /*
- * Now all we need to do is return skb->sk.
- */
-
- newsk = skb->sk;
-
- kfree_skb(skb, FREE_READ);
- sk->ack_backlog--;
- release_sock(sk);
- return(newsk);
-}
-
-
-/*
- * This will initiate an outgoing connection.
- */
-
-static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
-{
- struct sk_buff *buff;
- struct device *dev=NULL;
- unsigned char *ptr;
- int tmp;
- int atype;
- struct tcphdr *t1;
- struct rtable *rt;
-
- if (sk->state != TCP_CLOSE)
- {
- return(-EISCONN);
- }
-
- if (addr_len < 8)
- return(-EINVAL);
-
- if (usin->sin_family && usin->sin_family != AF_INET)
- return(-EAFNOSUPPORT);
-
- /*
- * connect() to INADDR_ANY means loopback (BSD'ism).
- */
-
- if(usin->sin_addr.s_addr==INADDR_ANY)
- usin->sin_addr.s_addr=ip_my_addr();
-
- /*
- * Don't want a TCP connection going to a broadcast address
- */
-
- if ((atype=ip_chk_addr(usin->sin_addr.s_addr)) == IS_BROADCAST || atype==IS_MULTICAST)
- return -ENETUNREACH;
-
- sk->inuse = 1;
- sk->daddr = usin->sin_addr.s_addr;
- sk->write_seq = tcp_init_seq();
- sk->window_seq = sk->write_seq;
- sk->rcv_ack_seq = sk->write_seq -1;
- sk->err = 0;
- sk->dummy_th.dest = usin->sin_port;
- release_sock(sk);
-
- buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
- if (buff == NULL)
- {
- return(-ENOMEM);
- }
- sk->inuse = 1;
- buff->len = 24;
- buff->sk = sk;
- buff->free = 0;
- buff->localroute = sk->localroute;
-
- t1 = (struct tcphdr *) buff->data;
-
- /*
- * Put in the IP header and routing stuff.
- */
-
- rt=ip_rt_route(sk->daddr, NULL, NULL);
-
-
- /*
- * We need to build the routing stuff from the things saved in skb.
- */
-
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
- if (tmp < 0)
- {
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- release_sock(sk);
- return(-ENETUNREACH);
- }
-
- buff->len += tmp;
- t1 = (struct tcphdr *)((char *)t1 +tmp);
-
- memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
- t1->seq = ntohl(sk->write_seq++);
- sk->sent_seq = sk->write_seq;
- buff->h.seq = sk->write_seq;
- t1->ack = 0;
- t1->window = 2;
- t1->res1=0;
- t1->res2=0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->syn = 1;
- t1->urg_ptr = 0;
- t1->doff = 6;
- /* use 512 or whatever user asked for */
-
- if(rt!=NULL && (rt->rt_flags&RTF_WINDOW))
- sk->window_clamp=rt->rt_window;
- else
- sk->window_clamp=0;
-
- if (sk->user_mss)
- sk->mtu = sk->user_mss;
- else if(rt!=NULL && (rt->rt_flags&RTF_MTU))
- sk->mtu = rt->rt_mss;
- else
- {
-#ifdef CONFIG_INET_SNARL
- if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr))
-#else
- if ((sk->saddr ^ sk->daddr) & dev->pa_mask)
-#endif
- sk->mtu = 576 - HEADER_SIZE;
- else
- sk->mtu = MAX_WINDOW;
- }
- /*
- * but not bigger than device MTU
- */
-
- if(sk->mtu <32)
- sk->mtu = 32; /* Sanity limit */
-
- sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE);
-
- /*
- * Put in the TCP options to say MTU.
- */
-
- ptr = (unsigned char *)(t1+1);
- ptr[0] = 2;
- ptr[1] = 4;
- ptr[2] = (sk->mtu) >> 8;
- ptr[3] = (sk->mtu) & 0xff;
- tcp_send_check(t1, sk->saddr, sk->daddr,
- sizeof(struct tcphdr) + 4, sk);
-
- /*
- * This must go first otherwise a really quick response will get reset.
- */
-
- tcp_set_state(sk,TCP_SYN_SENT);
- sk->rto = TCP_TIMEOUT_INIT;
-#if 0 /* we already did this */
- init_timer(&sk->retransmit_timer);
-#endif
- sk->retransmit_timer.function=&retransmit_timer;
- sk->retransmit_timer.data = (unsigned long)sk;
- reset_xmit_timer(sk, TIME_WRITE, sk->rto); /* Timer for repeating the SYN until an answer */
- sk->retransmits = TCP_SYN_RETRIES;
-
- sk->prot->queue_xmit(sk, dev, buff, 0);
- reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- tcp_statistics.TcpActiveOpens++;
- tcp_statistics.TcpOutSegs++;
-
- release_sock(sk);
- return(0);
-}
-
-
-/* This functions checks to see if the tcp header is actually acceptable. */
-extern __inline__ int tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
- struct options *opt, unsigned long saddr, struct device *dev)
-{
- unsigned long next_seq;
-
- next_seq = len - 4*th->doff;
- if (th->fin)
- next_seq++;
- /* if we have a zero window, we can't have any data in the packet.. */
- if (next_seq && !sk->window)
- goto ignore_it;
- next_seq += th->seq;
-
- /*
- * This isn't quite right. sk->acked_seq could be more recent
- * than sk->window. This is however close enough. We will accept
- * slightly more packets than we should, but it should not cause
- * problems unless someone is trying to forge packets.
- */
-
- /* have we already seen all of this packet? */
- if (!after(next_seq+1, sk->acked_seq))
- goto ignore_it;
- /* or does it start beyond the window? */
- if (!before(th->seq, sk->acked_seq + sk->window + 1))
- goto ignore_it;
-
- /* ok, at least part of this packet would seem interesting.. */
- return 1;
-
-ignore_it:
- if (th->rst)
- return 0;
-
- /*
- * Send a reset if we get something not ours and we are
- * unsynchronized. Note: We don't do anything to our end. We
- * are just killing the bogus remote connection then we will
- * connect again and it will work (with luck).
- */
-
- if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV)
- {
- tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl);
- return 1;
- }
-
- /* Try to resync things. */
- tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
- return 0;
-}
-
-/*
- * When we get a reset we do this.
- */
-
-static int tcp_std_reset(struct sock *sk, struct sk_buff *skb)
-{
- sk->zapped = 1;
- sk->err = ECONNRESET;
- if (sk->state == TCP_SYN_SENT)
- sk->err = ECONNREFUSED;
- if (sk->state == TCP_CLOSE_WAIT)
- sk->err = EPIPE;
-#ifdef TCP_DO_RFC1337
- /*
- * Time wait assassination protection [RFC1337]
- */
- if(sk->state!=TCP_TIME_WAIT)
- {
- tcp_set_state(sk,TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
- }
-#else
- tcp_set_state(sk,TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
-#endif
- if (!sk->dead)
- sk->state_change(sk);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
-}
-
-/*
- * A TCP packet has arrived.
- */
-
-int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
- unsigned long daddr, unsigned short len,
- unsigned long saddr, int redo, struct inet_protocol * protocol)
-{
- struct tcphdr *th;
- struct sock *sk;
- int syn_ok=0;
-
- if (!skb)
- {
- printk("IMPOSSIBLE 1\n");
- return(0);
- }
-
- if (!dev)
- {
- printk("IMPOSSIBLE 2\n");
- return(0);
- }
-
- tcp_statistics.TcpInSegs++;
-
- if(skb->pkt_type!=PACKET_HOST)
- {
- kfree_skb(skb,FREE_READ);
- return(0);
- }
-
- th = skb->h.th;
-
- /*
- * Find the socket.
- */
-
- sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
-
- /*
- * If this socket has got a reset it's to all intents and purposes
- * really dead. Count closed sockets as dead.
- *
- * Note: BSD appears to have a bug here. A 'closed' TCP in BSD
- * simply drops data. This seems incorrect as a 'closed' TCP doesn't
- * exist so should cause resets as if the port was unreachable.
- */
-
- if (sk!=NULL && (sk->zapped || sk->state==TCP_CLOSE))
- sk=NULL;
-
- if (!redo)
- {
- if (tcp_check(th, len, saddr, daddr ))
- {
- skb->sk = NULL;
- kfree_skb(skb,FREE_READ);
- /*
- * We don't release the socket because it was
- * never marked in use.
- */
- return(0);
- }
- th->seq = ntohl(th->seq);
-
- /* See if we know about the socket. */
- if (sk == NULL)
- {
- /*
- * No such TCB. If th->rst is 0 send a reset (checked in tcp_reset)
- */
- tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
- skb->sk = NULL;
- /*
- * Discard frame
- */
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- skb->len = len;
- skb->acked = 0;
- skb->used = 0;
- skb->free = 0;
- skb->saddr = daddr;
- skb->daddr = saddr;
-
- /* We may need to add it to the backlog here. */
- cli();
- if (sk->inuse)
- {
- skb_queue_tail(&sk->back_log, skb);
- sti();
- return(0);
- }
- sk->inuse = 1;
- sti();
- }
- else
- {
- if (sk==NULL)
- {
- tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- }
-
-
- if (!sk->prot)
- {
- printk("IMPOSSIBLE 3\n");
- return(0);
- }
-
-
- /*
- * Charge the memory to the socket.
- */
-
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- skb->sk=sk;
- sk->rmem_alloc += skb->mem_len;
-
- /*
- * This basically follows the flow suggested by RFC793, with the corrections in RFC1122. We
- * don't implement precedence and we process URG incorrectly (deliberately so) for BSD bug
- * compatibility. We also set up variables more thoroughly [Karn notes in the
- * KA9Q code the RFC793 incoming segment rules don't initialise the variables for all paths].
- */
-
- if(sk->state!=TCP_ESTABLISHED) /* Skip this lot for normal flow */
- {
-
- /*
- * Now deal with unusual cases.
- */
-
- if(sk->state==TCP_LISTEN)
- {
- if(th->ack) /* These use the socket TOS.. might want to be the received TOS */
- tcp_reset(daddr,saddr,th,sk->prot,opt,dev,sk->ip_tos, sk->ip_ttl);
-
- /*
- * We don't care for RST, and non SYN are absorbed (old segments)
- * Broadcast/multicast SYN isn't allowed. Note - bug if you change the
- * netmask on a running connection it can go broadcast. Even Sun's have
- * this problem so I'm ignoring it
- */
-
- if(th->rst || !th->syn || th->ack || ip_chk_addr(daddr)!=IS_MYADDR)
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
-
- /*
- * Guess we need to make a new socket up
- */
-
- tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq());
-
- /*
- * Now we have several options: In theory there is nothing else
- * in the frame. KA9Q has an option to send data with the syn,
- * BSD accepts data with the syn up to the [to be] advertised window
- * and Solaris 2.1 gives you a protocol error. For now we just ignore
- * it, that fits the spec precisely and avoids incompatibilities. It
- * would be nice in future to drop through and process the data.
- */
-
- release_sock(sk);
- return 0;
- }
-
- /* retransmitted SYN? */
- if (sk->state == TCP_SYN_RECV && th->syn && th->seq+1 == sk->acked_seq)
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
-
- /*
- * SYN sent means we have to look for a suitable ack and either reset
- * for bad matches or go to connected
- */
-
- if(sk->state==TCP_SYN_SENT)
- {
- /* Crossed SYN or previous junk segment */
- if(th->ack)
- {
- /* We got an ack, but it's not a good ack */
- if(!tcp_ack(sk,th,saddr,len))
- {
- /* Reset the ack - its an ack from a
- different connection [ th->rst is checked in tcp_reset()] */
- tcp_statistics.TcpAttemptFails++;
- tcp_reset(daddr, saddr, th,
- sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- if(th->rst)
- return tcp_std_reset(sk,skb);
- if(!th->syn)
- {
- /* A valid ack from a different connection
- start. Shouldn't happen but cover it */
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
- /*
- * Ok.. it's good. Set up sequence numbers and
- * move to established.
- */
- syn_ok=1; /* Don't reset this connection for the syn */
- sk->acked_seq=th->seq+1;
- sk->fin_seq=th->seq;
- tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr);
- tcp_set_state(sk, TCP_ESTABLISHED);
- tcp_options(sk,th);
- sk->dummy_th.dest=th->source;
- sk->copied_seq = sk->acked_seq;
- if(!sk->dead)
- {
- sk->state_change(sk);
- sock_wake_async(sk->socket, 0);
- }
- if(sk->max_window==0)
- {
- sk->max_window = 32;
- sk->mss = min(sk->max_window, sk->mtu);
- }
- }
- else
- {
- /* See if SYN's cross. Drop if boring */
- if(th->syn && !th->rst)
- {
- /* Crossed SYN's are fine - but talking to
- yourself is right out... */
- if(sk->saddr==saddr && sk->daddr==daddr &&
- sk->dummy_th.source==th->source &&
- sk->dummy_th.dest==th->dest)
- {
- tcp_statistics.TcpAttemptFails++;
- return tcp_std_reset(sk,skb);
- }
- tcp_set_state(sk,TCP_SYN_RECV);
-
- /*
- * FIXME:
- * Must send SYN|ACK here
- */
- }
- /* Discard junk segment */
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
- /*
- * SYN_RECV with data maybe.. drop through
- */
- goto rfc_step6;
- }
-
- /*
- * BSD has a funny hack with TIME_WAIT and fast reuse of a port. There is
- * a more complex suggestion for fixing these reuse issues in RFC1644
- * but not yet ready for general use. Also see RFC1379.
- */
-
-#define BSD_TIME_WAIT
-#ifdef BSD_TIME_WAIT
- if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead &&
- after(th->seq, sk->acked_seq) && !th->rst)
- {
- long seq=sk->write_seq;
- if(sk->debug)
- printk("Doing a BSD time wait\n");
- tcp_statistics.TcpEstabResets++;
- sk->rmem_alloc -= skb->mem_len;
- skb->sk = NULL;
- sk->err=ECONNRESET;
- tcp_set_state(sk, TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
- release_sock(sk);
- sk=get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
- if (sk && sk->state==TCP_LISTEN)
- {
- sk->inuse=1;
- skb->sk = sk;
- sk->rmem_alloc += skb->mem_len;
- tcp_conn_request(sk, skb, daddr, saddr,opt, dev,seq+128000);
- release_sock(sk);
- return 0;
- }
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-#endif
- }
-
- /*
- * We are now in normal data flow (see the step list in the RFC)
- * Note most of these are inline now. I'll inline the lot when
- * I have time to test it hard and look at what gcc outputs
- */
-
- if(!tcp_sequence(sk,th,len,opt,saddr,dev))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
-
- if(th->rst)
- return tcp_std_reset(sk,skb);
-
- /*
- * !syn_ok is effectively the state test in RFC793.
- */
-
- if(th->syn && !syn_ok)
- {
- tcp_reset(daddr,saddr,th, &tcp_prot, opt, dev, skb->ip_hdr->tos, 255);
- return tcp_std_reset(sk,skb);
- }
-
- /*
- * Process the ACK
- */
-
-
- if(th->ack && !tcp_ack(sk,th,saddr,len))
- {
- /*
- * Our three way handshake failed.
- */
-
- if(sk->state==TCP_SYN_RECV)
- {
- tcp_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);
- }
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
-
-rfc_step6: /* I'll clean this up later */
-
- /*
- * Process urgent data
- */
-
- if(tcp_urg(sk, th, saddr, len))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
-
-
- /*
- * Process the encapsulated data
- */
-
- if(tcp_data(skb,sk, saddr, len))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return 0;
- }
-
- /*
- * And done
- */
-
- release_sock(sk);
- return 0;
-}
-
-/*
- * This routine sends a packet with an out of date sequence
- * number. It assumes the other end will try to ack it.
- */
-
-static void tcp_write_wakeup(struct sock *sk)
-{
- struct sk_buff *buff;
- struct tcphdr *t1;
- struct device *dev=NULL;
- int tmp;
-
- if (sk->zapped)
- return; /* After a valid reset we can send no more */
-
- /*
- * Write data can still be transmitted/retransmitted in the
- * following states. If any other state is encountered, return.
- * [listen/close will never occur here anyway]
- */
-
- if (sk->state != TCP_ESTABLISHED &&
- sk->state != TCP_CLOSE_WAIT &&
- sk->state != TCP_FIN_WAIT1 &&
- sk->state != TCP_LAST_ACK &&
- sk->state != TCP_CLOSING
- )
- {
- return;
- }
-
- buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
- if (buff == NULL)
- return;
-
- buff->len = sizeof(struct tcphdr);
- buff->free = 1;
- buff->sk = sk;
- buff->localroute = sk->localroute;
-
- t1 = (struct tcphdr *) buff->data;
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
- if (tmp < 0)
- {
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- return;
- }
-
- buff->len += tmp;
- t1 = (struct tcphdr *)((char *)t1 +tmp);
-
- memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
-
- /*
- * Use a previous sequence.
- * This should cause the other end to send an ack.
- */
-
- t1->seq = htonl(sk->sent_seq-1);
- t1->ack = 1;
- t1->res1= 0;
- t1->res2= 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->fin = 0; /* We are sending a 'previous' sequence, and 0 bytes of data - thus no FIN bit */
- t1->syn = 0;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(tcp_select_window(sk));
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
- /*
- * Send it and free it.
- * This will prevent the timer from automatically being restarted.
- */
- sk->prot->queue_xmit(sk, dev, buff, 1);
- tcp_statistics.TcpOutSegs++;
-}
-
-/*
- * A window probe timeout has occurred.
- */
-
-void tcp_send_probe0(struct sock *sk)
-{
- if (sk->zapped)
- return; /* After a valid reset we can send no more */
-
- tcp_write_wakeup(sk);
-
- sk->backoff++;
- sk->rto = min(sk->rto << 1, 120*HZ);
- reset_xmit_timer (sk, TIME_PROBE0, sk->rto);
- sk->retransmits++;
- sk->prot->retransmits ++;
-}
-
-/*
- * Socket option code for TCP.
- */
-
-int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
-{
- int val,err;
-
- if(level!=SOL_TCP)
- return ip_setsockopt(sk,level,optname,optval,optlen);
-
- if (optval == NULL)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ, optval, sizeof(int));
- if(err)
- return err;
-
- val = get_fs_long((unsigned long *)optval);
-
- switch(optname)
- {
- case TCP_MAXSEG:
-/*
- * values greater than interface MTU won't take effect. however at
- * the point when this call is done we typically don't yet know
- * which interface is going to be used
- */
- if(val<1||val>MAX_WINDOW)
- return -EINVAL;
- sk->user_mss=val;
- return 0;
- case TCP_NODELAY:
- sk->nonagle=(val==0)?0:1;
- return 0;
- default:
- return(-ENOPROTOOPT);
- }
-}
-
-int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
-{
- int val,err;
-
- if(level!=SOL_TCP)
- return ip_getsockopt(sk,level,optname,optval,optlen);
-
- switch(optname)
- {
- case TCP_MAXSEG:
- val=sk->user_mss;
- break;
- case TCP_NODELAY:
- val=sk->nonagle;
- break;
- default:
- return(-ENOPROTOOPT);
- }
- err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(int),(unsigned long *) optlen);
-
- err=verify_area(VERIFY_WRITE, optval, sizeof(int));
- if(err)
- return err;
- put_fs_long(val,(unsigned long *)optval);
-
- return(0);
-}
-
-
-struct proto tcp_prot = {
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- tcp_close,
- tcp_read,
- tcp_write,
- tcp_sendto,
- tcp_recvfrom,
- ip_build_header,
- tcp_connect,
- tcp_accept,
- ip_queue_xmit,
- tcp_retransmit,
- tcp_write_wakeup,
- tcp_read_wakeup,
- tcp_rcv,
- tcp_select,
-#ifdef _HURD_
- NULL,
-#else
- tcp_ioctl,
-#endif
- NULL,
- tcp_shutdown,
- tcp_setsockopt,
- tcp_getsockopt,
- 128,
- 0,
- {NULL,},
- "TCP",
- 0, 0
-};
diff --git a/pfinet/linux-inet/tcp.h b/pfinet/linux-inet/tcp.h
deleted file mode 100644
index 016fa6dd..00000000
--- a/pfinet/linux-inet/tcp.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the TCP module.
- *
- * Version: @(#)tcp.h 1.0.5 05/23/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _TCP_H
-#define _TCP_H
-
-#include <linux/tcp.h>
-
-#define MAX_SYN_SIZE 44 + MAX_HEADER
-#define MAX_FIN_SIZE 40 + MAX_HEADER
-#define MAX_ACK_SIZE 40 + MAX_HEADER
-#define MAX_RESET_SIZE 40 + MAX_HEADER
-#define MAX_WINDOW 16384
-#define MIN_WINDOW 2048
-#define MAX_ACK_BACKLOG 2
-#define MIN_WRITE_SPACE 2048
-#define TCP_WINDOW_DIFF 2048
-
-/* urg_data states */
-#define URG_VALID 0x0100
-#define URG_NOTYET 0x0200
-#define URG_READ 0x0400
-
-#define TCP_RETR1 7 /*
- * This is how many retries it does before it
- * tries to figure out if the gateway is
- * down.
- */
-
-#define TCP_RETR2 15 /*
- * This should take at least
- * 90 minutes to time out.
- */
-
-#define TCP_TIMEOUT_LEN (15*60*HZ) /* should be about 15 mins */
-#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to successfully
- * close the socket, about 60 seconds */
-#define TCP_FIN_TIMEOUT (3*60*HZ) /* BSD style FIN_WAIT2 deadlock breaker */
-#define TCP_ACK_TIME (3*HZ) /* time to delay before sending an ACK */
-#define TCP_DONE_TIME 250 /* maximum time to wait before actually
- * destroying a socket */
-#define TCP_WRITE_TIME 3000 /* initial time to wait for an ACK,
- * after last transmit */
-#define TCP_TIMEOUT_INIT (3*HZ) /* RFC 1122 initial timeout value */
-#define TCP_SYN_RETRIES 5 /* number of times to retry opening a
- * connection */
-#define TCP_PROBEWAIT_LEN 100 /* time to wait between probes when
- * I've got something to write and
- * there is no window */
-
-#define TCP_NO_CHECK 0 /* turn to one if you want the default
- * to be no checksum */
-
-
-/*
- * TCP option
- */
-
-#define TCPOPT_NOP 1 /* Padding */
-#define TCPOPT_EOL 0 /* End of options */
-#define TCPOPT_MSS 2 /* Segment size negotiating */
-/*
- * We don't use these yet, but they are for PAWS and big windows
- */
-#define TCPOPT_WINDOW 3 /* Window scaling */
-#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
-
-
-/*
- * The next routines deal with comparing 32 bit unsigned ints
- * and worry about wraparound (automatic with unsigned arithmetic).
- */
-
-extern __inline int before(unsigned long seq1, unsigned long seq2)
-{
- return (long)(seq1-seq2) < 0;
-}
-
-extern __inline int after(unsigned long seq1, unsigned long seq2)
-{
- return (long)(seq1-seq2) > 0;
-}
-
-
-/* is s2<=s1<=s3 ? */
-extern __inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
-{
- return (after(seq1+1, seq2) && before(seq1, seq3+1));
-}
-
-
-/*
- * List all states of a TCP socket that can be viewed as a "connected"
- * state. This now includes TCP_SYN_RECV, although I am not yet fully
- * convinced that this is the solution for the 'getpeername(2)'
- * problem. Thanks to Stephen A. Wood <saw@cebaf.gov> -FvK
- */
-extern __inline const int
-tcp_connected(const int state)
-{
- return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
- state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 ||
- state == TCP_SYN_RECV);
-}
-
-
-extern struct proto tcp_prot;
-
-
-extern void tcp_err(int err, unsigned char *header, unsigned long daddr,
- unsigned long saddr, struct inet_protocol *protocol);
-extern void tcp_shutdown (struct sock *sk, int how);
-extern int tcp_rcv(struct sk_buff *skb, struct device *dev,
- struct options *opt, unsigned long daddr,
- unsigned short len, unsigned long saddr, int redo,
- struct inet_protocol *protocol);
-
-extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
-
-extern int tcp_select_window(struct sock *sk);
-extern void tcp_send_check(struct tcphdr *th, unsigned long saddr,
- unsigned long daddr, int len, struct sock *sk);
-extern void tcp_send_probe0(struct sock *sk);
-extern void tcp_enqueue_partial(struct sk_buff *, struct sock *);
-extern struct sk_buff * tcp_dequeue_partial(struct sock *);
-
-
-#endif /* _TCP_H */
diff --git a/pfinet/linux-inet/timer.c b/pfinet/linux-inet/timer.c
deleted file mode 100644
index 4fbbc74b..00000000
--- a/pfinet/linux-inet/timer.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * TIMER - implementation of software timers for IP.
- *
- * Version: @(#)timer.c 1.0.7 05/25/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- * Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
- * Florian La Roche, <flla@stud.uni-sb.de>
- *
- * Fixes:
- * Alan Cox : To avoid destroying a wait queue as we use it
- * we defer destruction until the destroy timer goes
- * off.
- * Alan Cox : Destroy socket doesn't write a status value to the
- * socket buffer _AFTER_ freeing it! Also sock ensures
- * the socket will get removed BEFORE this is called
- * otherwise if the timer TIME_DESTROY occurs inside
- * of inet_bh() with this socket being handled it goes
- * BOOM! Have to stop timer going off if net_bh is
- * active or the destroy causes crashes.
- * Alan Cox : Cleaned up unused code.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <asm/system.h>
-#include <linux/interrupt.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "tcp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "arp.h"
-
-void delete_timer (struct sock *t)
-{
- unsigned long flags;
-
- save_flags (flags);
- cli();
-
- t->timeout = 0;
- del_timer (&t->timer);
-
- restore_flags (flags);
-}
-
-void reset_timer (struct sock *t, int timeout, unsigned long len)
-{
- delete_timer (t);
- t->timeout = timeout;
-#if 1
- /* FIXME: ??? */
- if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */
- len = 3; /* happen (negative values ?) - don't ask me why ! -FB */
-#endif
- t->timer.expires = len;
- add_timer (&t->timer);
-}
-
-
-/*
- * Now we will only be called whenever we need to do
- * something, but we must be sure to process all of the
- * sockets that need it.
- */
-
-void net_timer (unsigned long data)
-{
- struct sock *sk = (struct sock*)data;
- int why = sk->timeout;
-
- /*
- * only process if socket is not in use
- */
-
- cli();
- if (sk->inuse || in_bh)
- {
- sk->timer.expires = 10;
- add_timer(&sk->timer);
- sti();
- return;
- }
-
- sk->inuse = 1;
- sti();
-
- /* Always see if we need to send an ack. */
-
- if (sk->ack_backlog && !sk->zapped)
- {
- sk->prot->read_wakeup (sk);
- if (! sk->dead)
- sk->data_ready(sk,0);
- }
-
- /* Now we need to figure out why the socket was on the timer. */
-
- switch (why)
- {
- case TIME_DONE:
- if (! sk->dead || sk->state != TCP_CLOSE)
- {
- printk ("non dead socket in time_done\n");
- release_sock (sk);
- break;
- }
- destroy_sock (sk);
- break;
-
- case TIME_DESTROY:
- /*
- * We've waited for a while for all the memory associated with
- * the socket to be freed.
- */
- if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0)
- {
- sk->wmem_alloc++; /* So it DOESN'T go away */
- destroy_sock (sk);
- sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */
- sk->inuse = 0; /* This will be ok, the destroy won't totally work */
- }
- if(sk->wmem_alloc==0 && sk->rmem_alloc==0)
- destroy_sock(sk); /* Socket gone, DON'T update sk->inuse! */
- break;
- case TIME_CLOSE:
- /* We've waited long enough, close the socket. */
- sk->state = TCP_CLOSE;
- delete_timer (sk);
- /* Kill the ARP entry in case the hardware has changed. */
- arp_destroy (sk->daddr, 0);
- if (!sk->dead)
- sk->state_change(sk);
- sk->shutdown = SHUTDOWN_MASK;
- reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME);
- release_sock (sk);
- break;
-#if 0
- case TIME_PROBE0:
- tcp_send_probe0(sk);
- release_sock (sk);
- break;
- case TIME_WRITE: /* try to retransmit. */
- /* It could be we got here because we needed to send an ack.
- * So we need to check for that.
- */
- {
- struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- skb = sk->send_head;
- if (!skb)
- {
- restore_flags(flags);
- }
- else
- {
- if (jiffies < skb->when + sk->rto)
- {
- reset_timer (sk, TIME_WRITE, skb->when + sk->rto - jiffies);
- restore_flags(flags);
- release_sock (sk);
- break;
- }
- restore_flags(flags);
- /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq,
- sk->retransmits, sk->packets_out, sk->cong_window); */
- sk->prot->retransmit (sk, 0);
- if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
- || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1))
- {
- arp_destroy (sk->daddr, 0);
- ip_route_check (sk->daddr);
- }
- if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2)
- {
- sk->err = ETIMEDOUT;
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING)
- {
- sk->state = TCP_TIME_WAIT;
- reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- }
- else
- {
- sk->prot->close (sk, 1);
- break;
- }
- }
- }
- release_sock (sk);
- break;
- }
- case TIME_KEEPOPEN:
- /*
- * this reset_timer() call is a hack, this is not
- * how KEEPOPEN is supposed to work.
- */
- reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
-
- /* Send something to keep the connection open. */
- if (sk->prot->write_wakeup)
- sk->prot->write_wakeup (sk);
- sk->retransmits++;
- if (sk->shutdown == SHUTDOWN_MASK)
- {
- sk->prot->close (sk, 1);
- sk->state = TCP_CLOSE;
- }
- if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
- || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1))
- {
- arp_destroy (sk->daddr, 0);
- ip_route_check (sk->daddr);
- release_sock (sk);
- break;
- }
- if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2)
- {
- arp_destroy (sk->daddr, 0);
- sk->err = ETIMEDOUT;
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2)
- {
- sk->state = TCP_TIME_WAIT;
- if (!sk->dead)
- sk->state_change(sk);
- release_sock (sk);
- }
- else
- {
- sk->prot->close (sk, 1);
- }
- break;
- }
- release_sock (sk);
- break;
-#endif
- default:
- printk ("net_timer: timer expired - reason %d is unknown\n", why);
- release_sock (sk);
- break;
- }
-}
-
diff --git a/pfinet/linux-inet/udp.c b/pfinet/linux-inet/udp.c
deleted file mode 100644
index be4cf928..00000000
--- a/pfinet/linux-inet/udp.c
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * The User Datagram Protocol (UDP).
- *
- * Version: @(#)udp.c 1.0.13 06/02/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * Fixes:
- * Alan Cox : verify_area() calls
- * Alan Cox : stopped close while in use off icmp
- * messages. Not a fix but a botch that
- * for udp at least is 'valid'.
- * Alan Cox : Fixed icmp handling properly
- * Alan Cox : Correct error for oversized datagrams
- * Alan Cox : Tidied select() semantics.
- * Alan Cox : udp_err() fixed properly, also now
- * select and read wake correctly on errors
- * Alan Cox : udp_send verify_area moved to avoid mem leak
- * Alan Cox : UDP can count its memory
- * Alan Cox : send to an unknown connection causes
- * an ECONNREFUSED off the icmp, but
- * does NOT close.
- * Alan Cox : Switched to new sk_buff handlers. No more backlog!
- * Alan Cox : Using generic datagram code. Even smaller and the PEEK
- * bug no longer crashes it.
- * Fred Van Kempen : Net2e support for sk->broadcast.
- * Alan Cox : Uses skb_free_datagram
- * Alan Cox : Added get/set sockopt support.
- * Alan Cox : Broadcasting without option set returns EACCES.
- * Alan Cox : No wakeup calls. Instead we now use the callbacks.
- * Alan Cox : Use ip_tos and ip_ttl
- * Alan Cox : SNMP Mibs
- * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support.
- * Matt Dillon : UDP length checks.
- * Alan Cox : Smarter af_inet used properly.
- * Alan Cox : Use new kernel side addressing.
- * Alan Cox : Incorrect return on truncated datagram receive.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/fcntl.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/termios.h>
-#include <linux/mm.h>
-#include <linux/config.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include "snmp.h"
-#include "ip.h"
-#include "protocol.h"
-#include "tcp.h"
-#include <linux/skbuff.h>
-#include "sock.h"
-#include "udp.h"
-#include "icmp.h"
-#include "route.h"
-
-/*
- * SNMP MIB for the UDP layer
- */
-
-struct udp_mib udp_statistics;
-
-
-static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len);
-
-#define min(a,b) ((a)<(b)?(a):(b))
-
-
-/*
- * This routine is called by the ICMP module when it gets some
- * sort of error condition. If err < 0 then the socket should
- * be closed and the error returned to the user. If err > 0
- * it's just the icmp type << 8 | icmp code.
- * Header points to the ip header of the error packet. We move
- * on past this. Then (as it used to claim before adjustment)
- * header points to the first 8 bytes of the udp header. We need
- * to find the appropriate port.
- */
-
-void udp_err(int err, unsigned char *header, unsigned long daddr,
- unsigned long saddr, struct inet_protocol *protocol)
-{
- struct udphdr *th;
- struct sock *sk;
- struct iphdr *ip=(struct iphdr *)header;
-
- header += 4*ip->ihl;
-
- /*
- * Find the 8 bytes of post IP header ICMP included for us
- */
-
- th = (struct udphdr *)header;
-
- sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
-
- if (sk == NULL)
- return; /* No socket for error */
-
- if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8))
- { /* Slow down! */
- if (sk->cong_window > 1)
- sk->cong_window = sk->cong_window/2;
- return;
- }
-
- /*
- * Various people wanted BSD UDP semantics. Well they've come
- * back out because they slow down response to stuff like dead
- * or unreachable name servers and they screw term users something
- * chronic. Oh and it violates RFC1122. So basically fix your
- * client code people.
- */
-
-#ifdef CONFIG_I_AM_A_BROKEN_BSD_WEENIE
- /*
- * It's only fatal if we have connected to them. I'm not happy
- * with this code. Some BSD comparisons need doing.
- */
-
- if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED)
- {
- sk->err = icmp_err_convert[err & 0xff].errno;
- sk->error_report(sk);
- }
-#else
- if (icmp_err_convert[err & 0xff].fatal)
- {
- sk->err = icmp_err_convert[err & 0xff].error;
- sk->error_report(sk);
- }
-#endif
-}
-
-
-static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr)
-{
- unsigned long sum;
-
- __asm__( "\t addl %%ecx,%%ebx\n"
- "\t adcl %%edx,%%ebx\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum)
- : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
- : "cx","bx","dx" );
-
- if (len > 3)
- {
- __asm__("\tclc\n"
- "1:\n"
- "\t lodsl\n"
- "\t adcl %%eax, %%ebx\n"
- "\t loop 1b\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum) , "=S"(uh)
- : "0"(sum), "c"(len/4) ,"1"(uh)
- : "ax", "cx", "bx", "si" );
- }
-
- /*
- * Convert from 32 bits to 16 bits.
- */
-
- __asm__("\t movl %%ebx, %%ecx\n"
- "\t shrl $16,%%ecx\n"
- "\t addw %%cx, %%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum)
- : "bx", "cx");
-
- /*
- * Check for an extra word.
- */
-
- if ((len & 2) != 0)
- {
- __asm__("\t lodsw\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum), "=S"(uh)
- : "0"(sum) ,"1"(uh)
- : "si", "ax", "bx");
- }
-
- /*
- * Now check for the extra byte.
- */
-
- if ((len & 1) != 0)
- {
- __asm__("\t lodsb\n"
- "\t movb $0,%%ah\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum) ,"S"(uh)
- : "si", "ax", "bx");
- }
-
- /*
- * We only want the bottom 16 bits, but we never cleared the top 16.
- */
-
- return((~sum) & 0xffff);
-}
-
-/*
- * Generate UDP checksums. These may be disabled, eg for fast NFS over ethernet
- * We default them enabled.. if you turn them off you either know what you are
- * doing or get burned...
- */
-
-static void udp_send_check(struct udphdr *uh, unsigned long saddr,
- unsigned long daddr, int len, struct sock *sk)
-{
- uh->check = 0;
- if (sk && sk->no_check)
- return;
- uh->check = udp_check(uh, len, saddr, daddr);
-
- /*
- * FFFF and 0 are the same, pick the right one as 0 in the
- * actual field means no checksum.
- */
-
- if (uh->check == 0)
- uh->check = 0xffff;
-}
-
-
-static int udp_send(struct sock *sk, struct sockaddr_in *sin,
- unsigned char *from, int len, int rt)
-{
- struct sk_buff *skb;
- struct device *dev;
- struct udphdr *uh;
- unsigned char *buff;
- unsigned long saddr;
- int size, tmp;
- int ttl;
-
- /*
- * Allocate an sk_buff copy of the packet.
- */
-
- size = sk->prot->max_header + len;
- skb = sock_alloc_send_skb(sk, size, 0, &tmp);
-
-
- if (skb == NULL)
- return tmp;
-
- skb->sk = NULL; /* to avoid changing sk->saddr */
- skb->free = 1;
- skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);
-
- /*
- * Now build the IP and MAC header.
- */
-
- buff = skb->data;
- saddr = sk->saddr;
- dev = NULL;
- ttl = sk->ip_ttl;
-#ifdef CONFIG_IP_MULTICAST
- if (MULTICAST(sin->sin_addr.s_addr))
- ttl = sk->ip_mc_ttl;
-#endif
- tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
- &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl);
-
- skb->sk=sk; /* So memory is freed correctly */
-
- /*
- * Unable to put a header on the packet.
- */
-
- if (tmp < 0 )
- {
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(tmp);
- }
-
- buff += tmp;
- saddr = skb->saddr; /*dev->pa_addr;*/
- skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
- skb->dev = dev;
-
- /*
- * Fill in the UDP header.
- */
-
- uh = (struct udphdr *) buff;
- uh->len = htons(len + sizeof(struct udphdr));
- uh->source = sk->dummy_th.source;
- uh->dest = sin->sin_port;
- buff = (unsigned char *) (uh + 1);
-
- /*
- * Copy the user data.
- */
-
- memcpy_fromfs(buff, from, len);
-
- /*
- * Set up the UDP checksum.
- */
-
- udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
-
- /*
- * Send the datagram to the interface.
- */
-
- udp_statistics.UdpOutDatagrams++;
-
- sk->prot->queue_xmit(sk, dev, skb, 1);
- return(len);
-}
-
-
-static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
- unsigned flags, struct sockaddr_in *usin, int addr_len)
-{
- struct sockaddr_in sin;
- int tmp;
-
- /*
- * Check the flags. We support no flags for UDP sending
- */
- if (flags&~MSG_DONTROUTE)
- return(-EINVAL);
- /*
- * Get and verify the address.
- */
-
- if (usin)
- {
- if (addr_len < sizeof(sin))
- return(-EINVAL);
- memcpy(&sin,usin,sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EINVAL);
- if (sin.sin_port == 0)
- return(-EINVAL);
- }
- else
- {
- if (sk->state != TCP_ESTABLISHED)
- return(-EINVAL);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->dummy_th.dest;
- sin.sin_addr.s_addr = sk->daddr;
- }
-
- /*
- * BSD socket semantics. You must set SO_BROADCAST to permit
- * broadcasting of data.
- */
-
- if(sin.sin_addr.s_addr==INADDR_ANY)
- sin.sin_addr.s_addr=ip_my_addr();
-
- if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -EACCES; /* Must turn broadcast on first */
-
- sk->inuse = 1;
-
- /* Send the packet. */
- tmp = udp_send(sk, &sin, from, len, flags);
-
- /* The datagram has been sent off. Release the socket. */
- release_sock(sk);
- return(tmp);
-}
-
-/*
- * In BSD SOCK_DGRAM a write is just like a send.
- */
-
-static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
- unsigned flags)
-{
- return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
-}
-
-
-#ifndef _HURD_
-/*
- * IOCTL requests applicable to the UDP protocol
- */
-
-int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
-{
- int err;
- switch(cmd)
- {
- case TIOCOUTQ:
- {
- unsigned long amount;
-
- if (sk->state == TCP_LISTEN) return(-EINVAL);
- amount = sk->prot->wspace(sk)/*/2*/;
- err=verify_area(VERIFY_WRITE,(void *)arg,
- sizeof(unsigned long));
- if(err)
- return(err);
- put_fs_long(amount,(unsigned long *)arg);
- return(0);
- }
-
- case TIOCINQ:
- {
- struct sk_buff *skb;
- unsigned long amount;
-
- if (sk->state == TCP_LISTEN) return(-EINVAL);
- amount = 0;
- skb = skb_peek(&sk->receive_queue);
- if (skb != NULL) {
- /*
- * We will only return the amount
- * of this packet since that is all
- * that will be read.
- */
- amount = skb->len;
- }
- err=verify_area(VERIFY_WRITE,(void *)arg,
- sizeof(unsigned long));
- if(err)
- return(err);
- put_fs_long(amount,(unsigned long *)arg);
- return(0);
- }
-
- default:
- return(-EINVAL);
- }
- return(0);
-}
-#endif
-
-/*
- * This should be easy, if there is something there we\
- * return it, otherwise we block.
- */
-
-int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
- int noblock, unsigned flags, struct sockaddr_in *sin,
- int *addr_len)
-{
- int copied = 0;
- int truesize;
- struct sk_buff *skb;
- int er;
-
- /*
- * Check any passed addresses
- */
-
- if (addr_len)
- *addr_len=sizeof(*sin);
-
- /*
- * From here the generic datagram does a lot of the work. Come
- * the finished NET3, it will do _ALL_ the work!
- */
-
- skb=skb_recv_datagram(sk,flags,noblock,&er);
- if(skb==NULL)
- return er;
-
- truesize = skb->len;
- copied = min(len, truesize);
-
- /*
- * FIXME : should use udp header size info value
- */
-
- skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
- sk->stamp=skb->stamp;
-
- /* Copy the address. */
- if (sin)
- {
- sin->sin_family = AF_INET;
- sin->sin_port = skb->h.uh->source;
- sin->sin_addr.s_addr = skb->daddr;
- }
-
- skb_free_datagram(skb);
- release_sock(sk);
- return(truesize);
-}
-
-/*
- * Read has the same semantics as recv in SOCK_DGRAM
- */
-
-int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
- unsigned flags)
-{
- return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
-}
-
-
-int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
-{
- struct rtable *rt;
- unsigned long sa;
- if (addr_len < sizeof(*usin))
- return(-EINVAL);
-
- if (usin->sin_family && usin->sin_family != AF_INET)
- return(-EAFNOSUPPORT);
- if (usin->sin_addr.s_addr==INADDR_ANY)
- usin->sin_addr.s_addr=ip_my_addr();
-
- if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST)
- return -EACCES; /* Must turn broadcast on first */
-
- rt=ip_rt_route(usin->sin_addr.s_addr, NULL, &sa);
- if(rt==NULL)
- return -ENETUNREACH;
- sk->saddr = sa; /* Update source address */
- sk->daddr = usin->sin_addr.s_addr;
- sk->dummy_th.dest = usin->sin_port;
- sk->state = TCP_ESTABLISHED;
- return(0);
-}
-
-
-static void udp_close(struct sock *sk, int timeout)
-{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
- if (sk->dead)
- destroy_sock(sk);
- else
- release_sock(sk);
-}
-
-
-/*
- * All we need to do is get the socket, and then do a checksum.
- */
-
-int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
- unsigned long daddr, unsigned short len,
- unsigned long saddr, int redo, struct inet_protocol *protocol)
-{
- struct sock *sk;
- struct udphdr *uh;
- unsigned short ulen;
- int addr_type = IS_MYADDR;
-
- if(!dev || dev->pa_addr!=daddr)
- addr_type=ip_chk_addr(daddr);
-
- /*
- * Get the header.
- */
- uh = (struct udphdr *) skb->h.uh;
-
- ip_statistics.IpInDelivers++;
-
- /*
- * Validate the packet and the UDP length.
- */
-
- ulen = ntohs(uh->len);
-
- if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh))
- {
- printk("UDP: short packet: %d/%d\n", ulen, len);
- udp_statistics.UdpInErrors++;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- if (uh->check && udp_check(uh, len, saddr, daddr))
- {
- /* <mea@utu.fi> wants to know, who sent it, to
- go and stomp on the garbage sender... */
- printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
- ntohl(saddr),ntohs(uh->source),
- ntohl(daddr),ntohs(uh->dest),
- ulen);
- udp_statistics.UdpInErrors++;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
-
- len=ulen;
-
-#ifdef CONFIG_IP_MULTICAST
- if (addr_type!=IS_MYADDR)
- {
- /*
- * Multicasts and broadcasts go to each listener.
- */
- struct sock *sknext=NULL;
- sk=get_sock_mcast(udp_prot.sock_array[ntohs(uh->dest)&(SOCK_ARRAY_SIZE-1)], uh->dest,
- saddr, uh->source, daddr);
- if(sk)
- {
- do
- {
- struct sk_buff *skb1;
-
- sknext=get_sock_mcast(sk->next, uh->dest, saddr, uh->source, daddr);
- if(sknext)
- skb1=skb_clone(skb,GFP_ATOMIC);
- else
- skb1=skb;
- if(skb1)
- udp_deliver(sk, uh, skb1, dev,saddr,daddr,len);
- sk=sknext;
- }
- while(sknext!=NULL);
- }
- else
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-#endif
- sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
- if (sk == NULL)
- {
- udp_statistics.UdpNoPorts++;
- if (addr_type == IS_MYADDR)
- {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev);
- }
- /*
- * Hmm. We got an UDP broadcast to a port to which we
- * don't wanna listen. Ignore it.
- */
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- return udp_deliver(sk,uh,skb,dev, saddr, daddr, len);
-}
-
-static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len)
-{
- skb->sk = sk;
- skb->dev = dev;
- skb->len = len;
-
- /*
- * These are supposed to be switched.
- */
-
- skb->daddr = saddr;
- skb->saddr = daddr;
-
-
- /*
- * Charge it to the socket, dropping if the queue is full.
- */
-
- skb->len = len - sizeof(*uh);
-
- if (sock_queue_rcv_skb(sk,skb)<0)
- {
- udp_statistics.UdpInErrors++;
- ip_statistics.IpInDiscards++;
- ip_statistics.IpInDelivers--;
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- release_sock(sk);
- return(0);
- }
- udp_statistics.UdpInDatagrams++;
- release_sock(sk);
- return(0);
-}
-
-
-struct proto udp_prot = {
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- udp_close,
- udp_read,
- udp_write,
- udp_sendto,
- udp_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- NULL,
- NULL,
- NULL,
- udp_rcv,
- datagram_select,
-#ifdef _HURD_
- NULL,
-#else
- udp_ioctl,
-#endif
- NULL,
- NULL,
- ip_setsockopt,
- ip_getsockopt,
- 128,
- 0,
- {NULL,},
- "UDP",
- 0, 0
-};
-
diff --git a/pfinet/linux-src/arch/alpha/lib/checksum.c b/pfinet/linux-src/arch/alpha/lib/checksum.c
new file mode 100644
index 00000000..5165279f
--- /dev/null
+++ b/pfinet/linux-src/arch/alpha/lib/checksum.c
@@ -0,0 +1,169 @@
+/*
+ * arch/alpha/lib/checksum.c
+ *
+ * This file contains network checksum routines that are better done
+ * in an architecture-specific manner due to speed..
+ */
+
+#include <linux/string.h>
+
+#include <asm/byteorder.h>
+
+static inline unsigned short from64to16(unsigned long x)
+{
+ /* add up 32-bit words for 33 bits */
+ x = (x & 0xffffffff) + (x >> 32);
+ /* add up 16-bit and 17-bit words for 17+c bits */
+ x = (x & 0xffff) + (x >> 16);
+ /* add up 16-bit and 2-bit for 16+c bit */
+ x = (x & 0xffff) + (x >> 16);
+ /* add up carry.. */
+ x = (x & 0xffff) + (x >> 16);
+ return x;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented.
+ */
+unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return ~from64to16(saddr + daddr + sum +
+ ((unsigned long) ntohs(len) << 16) +
+ ((unsigned long) proto << 8));
+}
+
+unsigned int csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ unsigned long result;
+
+ result = (saddr + daddr + sum +
+ ((unsigned long) ntohs(len) << 16) +
+ ((unsigned long) proto << 8));
+
+ /* Fold down to 32-bits so we don't loose in the typedef-less
+ network stack. */
+ /* 64 to 33 */
+ result = (result & 0xffffffff) + (result >> 32);
+ /* 33 to 32 */
+ result = (result & 0xffffffff) + (result >> 32);
+ return result;
+}
+
+/*
+ * Do a 64-bit checksum on an arbitrary memory area..
+ *
+ * This isn't a great routine, but it's not _horrible_ either. The
+ * inner loop could be unrolled a bit further, and there are better
+ * ways to do the carry, but this is reasonable.
+ */
+static inline unsigned long do_csum(const unsigned char * buff, int len)
+{
+ int odd, count;
+ unsigned long result = 0;
+
+ if (len <= 0)
+ goto out;
+ odd = 1 & (unsigned long) buff;
+ if (odd) {
+ result = *buff << 8;
+ len--;
+ buff++;
+ }
+ count = len >> 1; /* nr of 16-bit words.. */
+ if (count) {
+ if (2 & (unsigned long) buff) {
+ result += *(unsigned short *) buff;
+ count--;
+ len -= 2;
+ buff += 2;
+ }
+ count >>= 1; /* nr of 32-bit words.. */
+ if (count) {
+ if (4 & (unsigned long) buff) {
+ result += *(unsigned int *) buff;
+ count--;
+ len -= 4;
+ buff += 4;
+ }
+ count >>= 1; /* nr of 64-bit words.. */
+ if (count) {
+ unsigned long carry = 0;
+ do {
+ unsigned long w = *(unsigned long *) buff;
+ count--;
+ buff += 8;
+ result += carry;
+ result += w;
+ carry = (w > result);
+ } while (count);
+ result += carry;
+ result = (result & 0xffffffff) + (result >> 32);
+ }
+ if (len & 4) {
+ result += *(unsigned int *) buff;
+ buff += 4;
+ }
+ }
+ if (len & 2) {
+ result += *(unsigned short *) buff;
+ buff += 2;
+ }
+ }
+ if (len & 1)
+ result += *buff;
+ result = from64to16(result);
+ if (odd)
+ result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+ return result;
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
+{
+ return ~do_csum(iph,ihl*4);
+}
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+{
+ unsigned long result = do_csum(buff, len);
+
+ /* add in old sum, and carry.. */
+ result += sum;
+ /* 32+c bits -> 32 bits */
+ result = (result & 0xffffffff) + (result >> 32);
+ return result;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return ~from64to16(do_csum(buff,len));
+}
diff --git a/pfinet/linux-src/arch/alpha/lib/csum_partial_copy.c b/pfinet/linux-src/arch/alpha/lib/csum_partial_copy.c
new file mode 100644
index 00000000..71308133
--- /dev/null
+++ b/pfinet/linux-src/arch/alpha/lib/csum_partial_copy.c
@@ -0,0 +1,384 @@
+/*
+ * csum_partial_copy - do IP checksumming and copy
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * Don't look at this too closely - you'll go mad. The things
+ * we do for performance..
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+
+#define ldq_u(x,y) \
+__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(const unsigned long *)(y)))
+
+#define stq_u(x,y) \
+__asm__ __volatile__("stq_u %1,%0":"=m" (*(unsigned long *)(y)):"r" (x))
+
+#define extql(x,y,z) \
+__asm__ __volatile__("extql %1,%2,%0":"=r" (z):"r" (x),"r" (y))
+
+#define extqh(x,y,z) \
+__asm__ __volatile__("extqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
+
+#define mskql(x,y,z) \
+__asm__ __volatile__("mskql %1,%2,%0":"=r" (z):"r" (x),"r" (y))
+
+#define mskqh(x,y,z) \
+__asm__ __volatile__("mskqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
+
+#define insql(x,y,z) \
+__asm__ __volatile__("insql %1,%2,%0":"=r" (z):"r" (x),"r" (y))
+
+#define insqh(x,y,z) \
+__asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
+
+
+#define __get_user_u(x,ptr) \
+({ \
+ long __guu_err; \
+ __asm__ __volatile__( \
+ "1: ldq_u %0,%2\n" \
+ "2:\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .gprel32 1b\n" \
+ " lda %0,2b-1b(%1)\n" \
+ ".previous" \
+ : "=r"(x), "=r"(__guu_err) \
+ : "m"(__m(ptr)), "1"(0)); \
+ __guu_err; \
+})
+
+#define __put_user_u(x,ptr) \
+({ \
+ long __puu_err; \
+ __asm__ __volatile__( \
+ "1: stq_u %2,%1\n" \
+ "2:\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .gprel32 1b" \
+ " lda $31,2b-1b(%0)\n" \
+ ".previous" \
+ : "=r"(__puu_err) \
+ : "m"(__m(addr)), "rJ"(x), "0"(0)); \
+ __puu_err; \
+})
+
+
+/*
+ * Ok. This isn't fun, but this is the EASY case.
+ */
+static inline unsigned long
+csum_partial_cfu_aligned(const unsigned long *src, unsigned long *dst,
+ long len, unsigned long checksum,
+ int *errp)
+{
+ unsigned long carry = 0;
+ int err = 0;
+
+ while (len >= 0) {
+ unsigned long word;
+ err |= __get_user(word, src);
+ checksum += carry;
+ src++;
+ checksum += word;
+ len -= 8;
+ carry = checksum < word;
+ *dst = word;
+ dst++;
+ }
+ len += 8;
+ checksum += carry;
+ if (len) {
+ unsigned long word, tmp;
+ err |= __get_user(word, src);
+ tmp = *dst;
+ mskql(word, len, word);
+ checksum += word;
+ mskqh(tmp, len, tmp);
+ carry = checksum < word;
+ *dst = word | tmp;
+ checksum += carry;
+ }
+ if (err) *errp = err;
+ return checksum;
+}
+
+/*
+ * This is even less fun, but this is still reasonably
+ * easy.
+ */
+static inline unsigned long
+csum_partial_cfu_dest_aligned(const unsigned long *src, unsigned long *dst,
+ unsigned long soff,
+ long len, unsigned long checksum,
+ int *errp)
+{
+ unsigned long first;
+ unsigned long word, carry;
+ unsigned long lastsrc = 7+len+(unsigned long)src;
+ int err = 0;
+
+ err |= __get_user_u(first,src);
+ carry = 0;
+ while (len >= 0) {
+ unsigned long second;
+
+ err |= __get_user_u(second, src+1);
+ extql(first, soff, word);
+ len -= 8;
+ src++;
+ extqh(second, soff, first);
+ checksum += carry;
+ word |= first;
+ first = second;
+ checksum += word;
+ *dst = word;
+ dst++;
+ carry = checksum < word;
+ }
+ len += 8;
+ checksum += carry;
+ if (len) {
+ unsigned long tmp;
+ unsigned long second;
+ err |= __get_user_u(second, lastsrc);
+ tmp = *dst;
+ extql(first, soff, word);
+ extqh(second, soff, first);
+ word |= first;
+ mskql(word, len, word);
+ checksum += word;
+ mskqh(tmp, len, tmp);
+ carry = checksum < word;
+ *dst = word | tmp;
+ checksum += carry;
+ }
+ if (err) *errp = err;
+ return checksum;
+}
+
+/*
+ * This is slightly less fun than the above..
+ */
+static inline unsigned long
+csum_partial_cfu_src_aligned(const unsigned long *src, unsigned long *dst,
+ unsigned long doff,
+ long len, unsigned long checksum,
+ unsigned long partial_dest,
+ int *errp)
+{
+ unsigned long carry = 0;
+ unsigned long word;
+ int err = 0;
+
+ mskql(partial_dest, doff, partial_dest);
+ while (len >= 0) {
+ unsigned long second_dest;
+ err |= __get_user(word, src);
+ len -= 8;
+ insql(word, doff, second_dest);
+ checksum += carry;
+ stq_u(partial_dest | second_dest, dst);
+ src++;
+ checksum += word;
+ insqh(word, doff, partial_dest);
+ carry = checksum < word;
+ dst++;
+ }
+ len += doff;
+ checksum += carry;
+ if (len >= 0) {
+ unsigned long second_dest;
+ err |= __get_user(word, src);
+ mskql(word, len-doff, word);
+ checksum += word;
+ insql(word, doff, second_dest);
+ stq_u(partial_dest | second_dest, dst);
+ carry = checksum < word;
+ if (len) {
+ ldq_u(second_dest, dst+1);
+ insqh(word, doff, partial_dest);
+ mskqh(second_dest, len, second_dest);
+ stq_u(partial_dest | second_dest, dst+1);
+ }
+ checksum += carry;
+ } else if (len & 7) {
+ unsigned long second_dest;
+ err |= __get_user(word, src);
+ ldq_u(second_dest, dst);
+ mskql(word, len-doff, word);
+ checksum += word;
+ mskqh(second_dest, len, second_dest);
+ carry = checksum < word;
+ insql(word, doff, word);
+ stq_u(partial_dest | word | second_dest, dst);
+ checksum += carry;
+ }
+ if (err) *errp = err;
+ return checksum;
+}
+
+/*
+ * This is so totally un-fun that it's frightening. Don't
+ * look at this too closely, you'll go blind.
+ */
+static inline unsigned long
+csum_partial_cfu_unaligned(const unsigned long * src, unsigned long * dst,
+ unsigned long soff, unsigned long doff,
+ long len, unsigned long checksum,
+ unsigned long partial_dest,
+ int *errp)
+{
+ unsigned long carry = 0;
+ unsigned long first;
+ unsigned long lastsrc;
+ int err = 0;
+
+ err |= __get_user_u(first, src);
+ lastsrc = 7+len+(unsigned long)src;
+ mskql(partial_dest, doff, partial_dest);
+ while (len >= 0) {
+ unsigned long second, word;
+ unsigned long second_dest;
+
+ err |= __get_user_u(second, src+1);
+ extql(first, soff, word);
+ checksum += carry;
+ len -= 8;
+ extqh(second, soff, first);
+ src++;
+ word |= first;
+ first = second;
+ insql(word, doff, second_dest);
+ checksum += word;
+ stq_u(partial_dest | second_dest, dst);
+ carry = checksum < word;
+ insqh(word, doff, partial_dest);
+ dst++;
+ }
+ len += doff;
+ checksum += carry;
+ if (len >= 0) {
+ unsigned long second, word;
+ unsigned long second_dest;
+
+ err |= __get_user_u(second, lastsrc);
+ extql(first, soff, word);
+ extqh(second, soff, first);
+ word |= first;
+ first = second;
+ mskql(word, len-doff, word);
+ checksum += word;
+ insql(word, doff, second_dest);
+ carry = checksum < word;
+ stq_u(partial_dest | second_dest, dst);
+ if (len) {
+ ldq_u(second_dest, dst+1);
+ insqh(word, doff, partial_dest);
+ mskqh(second_dest, len, second_dest);
+ stq_u(partial_dest | second_dest, dst+1);
+ }
+ checksum += carry;
+ } else if (len & 7) {
+ unsigned long second, word;
+ unsigned long second_dest;
+
+ err |= __get_user_u(second, lastsrc);
+ extql(first, soff, word);
+ extqh(second, soff, first);
+ word |= first;
+ ldq_u(second_dest, dst);
+ mskql(word, len-doff, word);
+ checksum += word;
+ mskqh(second_dest, len, second_dest);
+ carry = checksum < word;
+ insql(word, doff, word);
+ stq_u(partial_dest | word | second_dest, dst);
+ checksum += carry;
+ }
+ if (err) *errp = err;
+ return checksum;
+}
+
+static unsigned int
+do_csum_partial_copy_from_user(const char *src, char *dst, int len,
+ unsigned int sum, int *errp)
+{
+ unsigned long checksum = (unsigned) sum;
+ unsigned long soff = 7 & (unsigned long) src;
+ unsigned long doff = 7 & (unsigned long) dst;
+
+ if (len) {
+ if (!doff) {
+ if (!soff)
+ checksum = csum_partial_cfu_aligned(
+ (const unsigned long *) src,
+ (unsigned long *) dst,
+ len-8, checksum, errp);
+ else
+ checksum = csum_partial_cfu_dest_aligned(
+ (const unsigned long *) src,
+ (unsigned long *) dst,
+ soff, len-8, checksum, errp);
+ } else {
+ unsigned long partial_dest;
+ ldq_u(partial_dest, dst);
+ if (!soff)
+ checksum = csum_partial_cfu_src_aligned(
+ (const unsigned long *) src,
+ (unsigned long *) dst,
+ doff, len-8, checksum,
+ partial_dest, errp);
+ else
+ checksum = csum_partial_cfu_unaligned(
+ (const unsigned long *) src,
+ (unsigned long *) dst,
+ soff, doff, len-8, checksum,
+ partial_dest, errp);
+ }
+ /* 64 -> 33 bits */
+ checksum = (checksum & 0xffffffff) + (checksum >> 32);
+ /* 33 -> < 32 bits */
+ checksum = (checksum & 0xffff) + (checksum >> 16);
+ /* 32 -> 16 bits */
+ checksum = (checksum & 0xffff) + (checksum >> 16);
+ checksum = (checksum & 0xffff) + (checksum >> 16);
+ }
+ return checksum;
+}
+
+unsigned int
+csum_partial_copy_from_user(const char *src, char *dst, int len,
+ unsigned int sum, int *errp)
+{
+ if (!access_ok(src, len, VERIFY_READ)) {
+ *errp = -EFAULT;
+ memset(dst, 0, len);
+ return sum;
+ }
+
+ return do_csum_partial_copy_from_user(src, dst, len, sum, errp);
+}
+
+unsigned int
+csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
+{
+ return do_csum_partial_copy_from_user(src, dst, len, sum, NULL);
+}
+
+unsigned int
+csum_partial_copy (const char *src, char *dst, int len, unsigned int sum)
+{
+ unsigned int ret;
+ int error = 0;
+
+ ret = do_csum_partial_copy_from_user(src, dst, len, sum, &error);
+ if (error)
+ printk("csum_partial_copy_old(): tell mingo to convert me!\n");
+
+ return ret;
+}
diff --git a/pfinet/linux-src/arch/arm/lib/checksum.S b/pfinet/linux-src/arch/arm/lib/checksum.S
new file mode 100644
index 00000000..bd5c78d3
--- /dev/null
+++ b/pfinet/linux-src/arch/arm/lib/checksum.S
@@ -0,0 +1,730 @@
+/*
+ * linux/arch/arm/lib/checksum.S
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998 Russell King
+ */
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+#include "constants.h"
+
+ .text
+
+/* Function: __u32 csum_partial(const char *src, int len, __u32)
+ * Params : r0 = buffer, r1 = len, r2 = checksum
+ * Returns : r0 = new checksum
+ */
+
+ENTRY(csum_partial)
+ tst r0, #2
+ beq 1f
+ subs r1, r1, #2
+ addmi r1, r1, #2
+ bmi 3f
+ bic r0, r0, #3
+ ldr r3, [r0], #4
+ adds r2, r2, r3, lsr #16
+ adcs r2, r2, #0
+1: adds r2, r2, #0
+ bics ip, r1, #31
+ beq 3f
+ stmfd sp!, {r4 - r6}
+2: ldmia r0!, {r3 - r6}
+ adcs r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ adcs r2, r2, r6
+ ldmia r0!, {r3 - r6}
+ adcs r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ adcs r2, r2, r6
+ sub ip, ip, #32
+ teq ip, #0
+ bne 2b
+ adcs r2, r2, #0
+ ldmfd sp!, {r4 - r6}
+3: ands ip, r1, #0x1c
+ beq 5f
+4: ldr r3, [r0], #4
+ adcs r2, r2, r3
+ sub ip, ip, #4
+ teq ip, #0
+ bne 4b
+ adcs r2, r2, #0
+5: ands ip, r1, #3
+ moveq r0, r2
+ RETINSTR(moveq,pc,lr)
+ mov ip, ip, lsl #3
+ rsb ip, ip, #32
+ ldr r3, [r0]
+ mov r3, r3, lsl ip
+ adds r2, r2, r3, lsr ip
+ adc r0, r2, #0
+ RETINSTR(mov,pc,lr)
+
+/* Function: __u32 csum_partial_copy_from_user (const char *src, char *dst, int len, __u32 sum, int *err_ptr)
+ * Params : r0 = src, r1 = dst, r2 = len, r3 = sum, [sp, #0] = &err
+ * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT
+ */
+#if defined(CONFIG_CPU_32)
+
+ .macro save_regs
+ stmfd sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc}
+ .endm
+
+#define LOAD_REGS(cond) \
+ LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r8, fp, sp, pc})
+
+ .macro load1b, reg1
+9999: ldrbt \reg1, [r0], $1
+ .section __ex_table, "a"
+ .align 3
+ .long 9999b, 6001f
+ .previous
+ .endm
+
+ .macro load2b, reg1, reg2
+9999: ldrbt \reg1, [r0], $1
+9998: ldrbt \reg2, [r0], $1
+ .section __ex_table, "a"
+ .long 9999b, 6001f
+ .long 9998b, 6001f
+ .previous
+ .endm
+
+ .macro load1l, reg1
+9999: ldrt \reg1, [r0], $4
+ .section __ex_table, "a"
+ .align 3
+ .long 9999b, 6001f
+ .previous
+ .endm
+
+ .macro load2l, reg1, reg2
+9999: ldrt \reg1, [r0], $4
+9998: ldrt \reg2, [r0], $4
+ .section __ex_table, "a"
+ .long 9999b, 6001f
+ .long 9998b, 6001f
+ .previous
+ .endm
+
+ .macro load4l, reg1, reg2, reg3, reg4
+9999: ldrt \reg1, [r0], $4
+9998: ldrt \reg2, [r0], $4
+9997: ldrt \reg3, [r0], $4
+9996: ldrt \reg4, [r0], $4
+ .section __ex_table, "a"
+ .long 9999b, 6001f
+ .long 9998b, 6001f
+ .long 9997b, 6001f
+ .long 9996b, 6001f
+ .previous
+ .endm
+
+#elif defined(CONFIG_CPU_26)
+
+ .macro save_regs
+ stmfd sp!, {r1 - r2, r4 - r9, fp, ip, lr, pc}
+ mov r9, sp, lsr #13
+ mov r9, r9, lsl #13
+ ldr r9, [r9, #TSK_ADDR_LIMIT]
+ mov r9, r9, lsr #24
+ .endm
+
+#define LOAD_REGS(cond) \
+ LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r9, fp, sp, pc})
+
+ .macro load1b, reg1
+ tst r9, #0x01
+9999: ldreqbt \reg1, [r0], #1
+ ldrneb \reg1, [r0], #1
+ .section __ex_table, "a"
+ .align 3
+ .long 9999b, 6001f
+ .previous
+ .endm
+
+ .macro load2b, reg1, reg2
+ tst r9, #0x01
+9999: ldreqbt \reg1, [r0], #1
+ ldrneb \reg1, [r0], #1
+9998: ldreqbt \reg2, [r0], #1
+ ldrneb \reg2, [r0], #1
+ .section __ex_table, "a"
+ .long 9999b, 6001f
+ .long 9998b, 6001f
+ .previous
+ .endm
+
+ .macro load1l, reg1
+ tst r9, #0x01
+9999: ldreqt \reg1, [r0], #4
+ ldrne \reg1, [r0], #4
+ .section __ex_table, "a"
+ .align 3
+ .long 9999b, 6001f
+ .previous
+ .endm
+
+ .macro load2l, reg1, reg2
+ tst r9, #0x01
+ ldmneia r0!, {\reg1, \reg2}
+9999: ldreqt \reg1, [r0], #4
+9998: ldreqt \reg2, [r0], #4
+ .section __ex_table, "a"
+ .long 9999b, 6001f
+ .long 9998b, 6001f
+ .previous
+ .endm
+
+ .macro load4l, reg1, reg2, reg3, reg4
+ tst r9, #0x01
+ ldmneia r0!, {\reg1, \reg2, \reg3, \reg4}
+9999: ldreqt \reg1, [r0], #4
+9998: ldreqt \reg2, [r0], #4
+9997: ldreqt \reg3, [r0], #4
+9996: ldreqt \reg4, [r0], #4
+ .section __ex_table, "a"
+ .long 9999b, 6001f
+ .long 9998b, 6001f
+ .long 9997b, 6001f
+ .long 9996b, 6001f
+ .previous
+ .endm
+
+#else
+#error Unknown CPU architecture
+#endif
+
+ENTRY(csum_partial_copy_from_user)
+ mov ip, sp
+ save_regs
+ sub fp, ip, #4
+ cmp r2, #4
+ blt .too_small_user
+ tst r1, #2 @ Test destination alignment
+ beq .dst_aligned_user
+ subs r2, r2, #2 @ We do not know if SRC is aligned...
+ load2b ip, r8
+ orr ip, ip, r8, lsl #8
+ adds r3, r3, ip
+ adcs r3, r3, #0
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1 @ Destination now aligned
+.dst_aligned_user:
+ tst r0, #3
+ bne .src_not_aligned_user
+ adds r3, r3, #0
+ bics ip, r2, #15 @ Routine for src & dst aligned
+ beq 2f
+1: load4l r4, r5, r6, r7
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+2: ands ip, r2, #12
+ beq 4f
+ tst ip, #8
+ beq 3f
+ load2l r4, r5
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ tst ip, #4
+ beq 4f
+3: load1l r4
+ str r4, [r1], #4
+ adcs r3, r3, r4
+4: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOAD_REGS(eq)
+ load1l r4
+ tst r2, #2
+ beq .exit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+.exit: tst r2, #1
+ strneb r4, [r1], #1
+ andne r4, r4, #255
+ adcnes r3, r3, r4
+ adcs r0, r3, #0
+ LOAD_REGS(al)
+
+.too_small_user:
+ teq r2, #0
+ LOAD_REGS(eq)
+ cmp r2, #2
+ blt .too_small_user1
+ load2b ip, r8
+ orr ip, ip, r8, lsl #8
+ adds r3, r3, ip
+ strb ip, [r1], #1
+ strb r8, [r1], #1
+ tst r2, #1
+.too_small_user1: @ C = 0
+ beq .csum_exit
+ load1b ip
+ strb ip, [r1], #1
+ adcs r3, r3, ip
+.csum_exit: adc r0, r3, #0
+ LOAD_REGS(al)
+
+.src_not_aligned_user:
+ cmp r2, #4
+ blt .too_small_user
+ and ip, r0, #3
+ bic r0, r0, #3
+ load1l r4
+ cmp ip, #2
+ beq .src2_aligned_user
+ bhi .src3_aligned_user
+ mov r4, r4, lsr #8
+ adds r3, r3, #0
+ bics ip, r2, #15
+ beq 2f
+1: load4l r5, r6, r7, r8
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r6, lsl #24
+ mov r6, r6, lsr #8
+ orr r6, r6, r7, lsl #24
+ mov r7, r7, lsr #8
+ orr r7, r7, r8, lsl #24
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ mov r4, r8, lsr #8
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+2: ands ip, r2, #12
+ beq 4f
+ tst ip, #8
+ beq 3f
+ load2l r5, r6
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r6, lsl #24
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ mov r4, r6, lsr #8
+ tst ip, #4
+ beq 4f
+3: load1l r5
+ orr r4, r4, r5, lsl #24
+ str r4, [r1], #4
+ adcs r3, r3, r4
+ mov r4, r5, lsr #8
+4: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOAD_REGS(eq)
+ tst r2, #2
+ beq .exit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ b .exit
+
+.src2_aligned_user:
+ mov r4, r4, lsr #16
+ adds r3, r3, #0
+ bics ip, r2, #15
+ beq 2f
+1: load4l r5, r6, r7, r8
+ orr r4, r4, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r6, lsl #16
+ mov r6, r6, lsr #16
+ orr r6, r6, r7, lsl #16
+ mov r7, r7, lsr #16
+ orr r7, r7, r8, lsl #16
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ mov r4, r8, lsr #16
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+2: ands ip, r2, #12
+ beq 4f
+ tst ip, #8
+ beq 3f
+ load2l r5, r6
+ orr r4, r4, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r6, lsl #16
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ mov r4, r6, lsr #16
+ tst ip, #4
+ beq 4f
+3: load1l r5
+ orr r4, r4, r5, lsl #16
+ str r4, [r1], #4
+ adcs r3, r3, r4
+ mov r4, r5, lsr #16
+4: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOAD_REGS(eq)
+ tst r2, #2
+ beq .exit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ strb r4, [r1], #1
+ load1b r4
+ b .exit
+
+.src3_aligned_user:
+ mov r4, r4, lsr #24
+ adds r3, r3, #0
+ bics ip, r2, #15
+ beq 2f
+1: load4l r5, r6, r7, r8
+ orr r4, r4, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r6, lsl #8
+ mov r6, r6, lsr #24
+ orr r6, r6, r7, lsl #8
+ mov r7, r7, lsr #24
+ orr r7, r7, r8, lsl #8
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ mov r4, r8, lsr #24
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+2: ands ip, r2, #12
+ beq 4f
+ tst ip, #8
+ beq 3f
+ load2l r5, r6
+ orr r4, r4, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r6, lsl #8
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ mov r4, r6, lsr #24
+ tst ip, #4
+ beq 4f
+3: load1l r5
+ orr r4, r4, r5, lsl #8
+ str r4, [r1], #4
+ adcs r3, r3, r4
+ mov r4, r5, lsr #24
+4: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOAD_REGS(eq)
+ tst r2, #2
+ beq .exit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ load1l r4
+ strb r4, [r1], #1
+ adcs r3, r3, r4, lsl #24
+ mov r4, r4, lsr #8
+ b .exit
+
+#if defined(CONFIG_CPU_32)
+ .section .fixup,"ax"
+#endif
+ .align 4
+6001: mov r4, #-EFAULT
+ ldr r5, [fp, #4]
+ str r4, [r5]
+ ldmia sp, {r1, r2} @ retrieve original arguments
+ add r2, r2, r1
+ mov r3, #0 @ zero the buffer
+6002: teq r2, r1
+ strneb r3, [r1], #1
+ bne 6002b
+ LOAD_REGS(al)
+#if defined(CONFIG_CPU_32)
+ .previous
+#endif
+
+/* Function: __u32 csum_partial_copy (const char *src, char *dst, int len, __u32 sum)
+ * Params : r0 = src, r1 = dst, r2 = len, r3 = checksum
+ * Returns : r0 = new checksum
+ */
+ENTRY(csum_partial_copy_nocheck)
+ENTRY(csum_partial_copy)
+ mov ip, sp
+ stmfd sp!, {r4 - r8, fp, ip, lr, pc}
+ sub fp, ip, #4
+ cmp r2, #4
+ blt Ltoo_small
+ tst r1, #2 @ Test destination alignment
+ beq Ldst_aligned
+ subs r2, r2, #2 @ We do not know if SRC is aligned...
+ ldrb ip, [r0], #1
+ ldrb r8, [r0], #1
+ orr ip, ip, r8, lsl #8
+ adds r3, r3, ip
+ adcs r3, r3, #0
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1 @ Destination now aligned
+Ldst_aligned: tst r0, #3
+ bne Lsrc_not_aligned
+ adds r3, r3, #0
+ bics ip, r2, #15 @ Routine for src & dst aligned
+ beq 3f
+1: ldmia r0!, {r4, r5, r6, r7}
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+3: ands ip, r2, #12
+ beq 5f
+ tst ip, #8
+ beq 4f
+ ldmia r0!, {r4, r5}
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ tst ip, #4
+ beq 5f
+4: ldr r4, [r0], #4
+ str r4, [r1], #4
+ adcs r3, r3, r4
+5: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ ldr r4, [r0], #4
+ tst r2, #2
+ beq Lexit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ b Lexit
+
+Ltoo_small: teq r2, #0
+ LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ cmp r2, #2
+ blt Ltoo_small1
+ ldrb ip, [r0], #1
+ ldrb r8, [r0], #1
+ orr ip, ip, r8, lsl #8
+ adds r3, r3, ip
+ strb ip, [r1], #1
+ strb r8, [r1], #1
+Lexit: tst r2, #1
+Ltoo_small1: ldrneb ip, [r0], #1
+ strneb ip, [r1], #1
+ adcnes r3, r3, ip
+ adcs r0, r3, #0
+ LOADREGS(ea,fp,{r4 - r8, fp, sp, pc})
+
+Lsrc_not_aligned:
+ cmp r2, #4
+ blt Ltoo_small
+ and ip, r0, #3
+ bic r0, r0, #3
+ ldr r4, [r0], #4
+ cmp ip, #2
+ beq Lsrc2_aligned
+ bhi Lsrc3_aligned
+ mov r4, r4, lsr #8
+ adds r3, r3, #0
+ bics ip, r2, #15
+ beq 2f
+1: ldmia r0!, {r5, r6, r7, r8}
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r6, lsl #24
+ mov r6, r6, lsr #8
+ orr r6, r6, r7, lsl #24
+ mov r7, r7, lsr #8
+ orr r7, r7, r8, lsl #24
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ mov r4, r8, lsr #8
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+2: ands ip, r2, #12
+ beq 4f
+ tst ip, #8
+ beq 3f
+ ldmia r0!, {r5, r6}
+ orr r4, r4, r5, lsl #24
+ mov r5, r5, lsr #8
+ orr r5, r5, r6, lsl #24
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ mov r4, r6, lsr #8
+ tst ip, #4
+ beq 4f
+3: ldr r5, [r0], #4
+ orr r4, r4, r5, lsl #24
+ str r4, [r1], #4
+ adcs r3, r3, r4
+ mov r4, r5, lsr #8
+4: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ tst r2, #2
+ beq Lexit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ b Lexit
+
+Lsrc2_aligned: mov r4, r4, lsr #16
+ adds r3, r3, #0
+ bics ip, r2, #15
+ beq 2f
+1: ldmia r0!, {r5, r6, r7, r8}
+ orr r4, r4, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r6, lsl #16
+ mov r6, r6, lsr #16
+ orr r6, r6, r7, lsl #16
+ mov r7, r7, lsr #16
+ orr r7, r7, r8, lsl #16
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ mov r4, r8, lsr #16
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+2: ands ip, r2, #12
+ beq 4f
+ tst ip, #8
+ beq 3f
+ ldmia r0!, {r5, r6}
+ orr r4, r4, r5, lsl #16
+ mov r5, r5, lsr #16
+ orr r5, r5, r6, lsl #16
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ mov r4, r6, lsr #16
+ tst ip, #4
+ beq 4f
+3: ldr r5, [r0], #4
+ orr r4, r4, r5, lsl #16
+ str r4, [r1], #4
+ adcs r3, r3, r4
+ mov r4, r5, lsr #16
+4: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ tst r2, #2
+ beq Lexit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ mov r4, r4, lsr #8
+ strb r4, [r1], #1
+ ldrb r4, [r0], #1
+ b Lexit
+
+Lsrc3_aligned: mov r4, r4, lsr #24
+ adds r3, r3, #0
+ bics ip, r2, #15
+ beq 2f
+1: ldmia r0!, {r5, r6, r7, r8}
+ orr r4, r4, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r6, lsl #8
+ mov r6, r6, lsr #24
+ orr r6, r6, r7, lsl #8
+ mov r7, r7, lsr #24
+ orr r7, r7, r8, lsl #8
+ stmia r1!, {r4, r5, r6, r7}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ adcs r3, r3, r6
+ adcs r3, r3, r7
+ mov r4, r8, lsr #24
+ sub ip, ip, #16
+ teq ip, #0
+ bne 1b
+2: ands ip, r2, #12
+ beq 4f
+ tst ip, #8
+ beq 3f
+ ldmia r0!, {r5, r6}
+ orr r4, r4, r5, lsl #8
+ mov r5, r5, lsr #24
+ orr r5, r5, r6, lsl #8
+ stmia r1!, {r4, r5}
+ adcs r3, r3, r4
+ adcs r3, r3, r5
+ mov r4, r6, lsr #24
+ tst ip, #4
+ beq 4f
+3: ldr r5, [r0], #4
+ orr r4, r4, r5, lsl #8
+ str r4, [r1], #4
+ adcs r3, r3, r4
+ mov r4, r5, lsr #24
+4: ands r2, r2, #3
+ adceq r0, r3, #0
+ LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc})
+ tst r2, #2
+ beq Lexit
+ adcs r3, r3, r4, lsl #16
+ strb r4, [r1], #1
+ ldr r4, [r0], #4
+ strb r4, [r1], #1
+ adcs r3, r3, r4, lsl #24
+ mov r4, r4, lsr #8
+ b Lexit
+
+ENTRY(__csum_ipv6_magic)
+ stmfd sp!, {lr}
+ adds ip, r2, r3
+ ldmia r1, {r1 - r3, lr}
+ adcs ip, ip, r1
+ adcs ip, ip, r2
+ adcs ip, ip, r3
+ adcs ip, ip, lr
+ ldmia r0, {r0 - r3}
+ adcs r0, ip, r0
+ adcs r0, r0, r1
+ adcs r0, r0, r2
+ adcs r0, r0, r3
+ ldr r3, [sp, #4]
+ adcs r0, r0, r3
+ adcs r0, r0, #0
+ LOADREGS(fd, sp!, {pc})
diff --git a/pfinet/linux-src/arch/i386/lib/checksum.S b/pfinet/linux-src/arch/i386/lib/checksum.S
new file mode 100644
index 00000000..b48265da
--- /dev/null
+++ b/pfinet/linux-src/arch/i386/lib/checksum.S
@@ -0,0 +1,447 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Pentium Pro/II routines:
+ * Alexander Kjeldaas <astor@guardian.no>
+ * Finn Arne Gangstad <finnag@guardian.no>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ * handling.
+ * Andi Kleen, add zeroing on error
+ * converted to pure assembler
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/errno.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+.text
+.align 4
+.globl csum_partial
+
+#if CPU!=686
+
+ /*
+ * Experiments with Ethernet and SLIP connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary. We get at
+ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+ * alignment for the unrolled loop.
+ */
+csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: unsigned char *buff
+ testl $2, %esi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+1: movw (%esi), %bx
+ addl $2, %esi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, %edx
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+1: movl (%esi), %ebx
+ adcl %ebx, %eax
+ movl 4(%esi), %ebx
+ adcl %ebx, %eax
+ movl 8(%esi), %ebx
+ adcl %ebx, %eax
+ movl 12(%esi), %ebx
+ adcl %ebx, %eax
+ movl 16(%esi), %ebx
+ adcl %ebx, %eax
+ movl 20(%esi), %ebx
+ adcl %ebx, %eax
+ movl 24(%esi), %ebx
+ adcl %ebx, %eax
+ movl 28(%esi), %ebx
+ adcl %ebx, %eax
+ lea 32(%esi), %esi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+3: adcl (%esi), %eax
+ lea 4(%esi), %esi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+ movw (%esi),%cx
+ leal 2(%esi),%esi
+ je 6f
+ shll $16,%ecx
+5: movb (%esi),%cl
+6: addl %ecx,%eax
+ adcl $0, %eax
+7:
+ popl %ebx
+ popl %esi
+ ret
+
+#else /* CPU==686 */
+
+csum_partial:
+ movl 12(%esp),%eax # Function arg: unsigned int sum
+ movl 8(%esp),%ecx # Function arg: int len
+ movl 4(%esp),%esi # Function arg: const unsigned char *buf
+
+ testl $2, %esi
+ jnz 30f
+10:
+ movl %ecx, %edx
+ movl %ecx, %ebx
+ andl $0x7c, %ebx
+ shrl $7, %ecx
+ addl %ebx,%esi
+ shrl $2, %ebx
+ negl %ebx
+ lea 45f(%ebx,%ebx,2), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+
+ # Handle 2-byte-aligned regions
+20: addw (%esi), %ax
+ lea 2(%esi), %esi
+ adcl $0, %eax
+ jmp 10b
+
+30: subl $2, %ecx
+ ja 20b
+ je 32f
+ movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
+ addl %ebx, %eax
+ adcl $0, %eax
+ jmp 80f
+32:
+ addw (%esi), %ax # csumming 2 bytes, 2-aligned
+ adcl $0, %eax
+ jmp 80f
+
+40:
+ addl -128(%esi), %eax
+ adcl -124(%esi), %eax
+ adcl -120(%esi), %eax
+ adcl -116(%esi), %eax
+ adcl -112(%esi), %eax
+ adcl -108(%esi), %eax
+ adcl -104(%esi), %eax
+ adcl -100(%esi), %eax
+ adcl -96(%esi), %eax
+ adcl -92(%esi), %eax
+ adcl -88(%esi), %eax
+ adcl -84(%esi), %eax
+ adcl -80(%esi), %eax
+ adcl -76(%esi), %eax
+ adcl -72(%esi), %eax
+ adcl -68(%esi), %eax
+ adcl -64(%esi), %eax
+ adcl -60(%esi), %eax
+ adcl -56(%esi), %eax
+ adcl -52(%esi), %eax
+ adcl -48(%esi), %eax
+ adcl -44(%esi), %eax
+ adcl -40(%esi), %eax
+ adcl -36(%esi), %eax
+ adcl -32(%esi), %eax
+ adcl -28(%esi), %eax
+ adcl -24(%esi), %eax
+ adcl -20(%esi), %eax
+ adcl -16(%esi), %eax
+ adcl -12(%esi), %eax
+ adcl -8(%esi), %eax
+ adcl -4(%esi), %eax
+45:
+ lea 128(%esi), %esi
+ adcl $0, %eax
+ dec %ecx
+ jge 40b
+ movl %edx, %ecx
+50: andl $3, %ecx
+ jz 80f
+
+ # Handle the last 1-3 bytes without jumping
+ notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
+ movl $0xffffff,%ebx # by the shll and shrl instructions
+ shll $3,%ecx
+ shrl %cl,%ebx
+ andl -128(%esi),%ebx # esi is 4-aligned so should be ok
+ addl %ebx,%eax
+ adcl $0,%eax
+80:
+ ret
+
+#endif /* CPU==686 */
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+ int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+ */
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ * DST definitions? It's damn hard to trigger all cases. I hope I got
+ * them all but there's no guarantee.
+ */
+
+#define SRC(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6001f ; \
+ .previous
+
+#define DST(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6002f ; \
+ .previous
+
+.align 4
+.globl csum_partial_copy_generic
+
+#if CPU!=686
+
+#define ARGBASE 16
+#define FP 12
+
+csum_partial_copy_generic:
+ subl $4,%esp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ movl ARGBASE+16(%esp),%eax # sum
+ movl ARGBASE+12(%esp),%ecx # len
+ movl ARGBASE+4(%esp),%esi # src
+ movl ARGBASE+8(%esp),%edi # dst
+
+ testl $2, %edi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+SRC(1: movw (%esi), %bx )
+ addl $2, %esi
+DST( movw %bx, (%edi) )
+ addl $2, %edi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, FP(%esp)
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+SRC(1: movl (%esi), %ebx )
+SRC( movl 4(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 4(%edi) )
+
+SRC( movl 8(%esi), %ebx )
+SRC( movl 12(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 8(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 12(%edi) )
+
+SRC( movl 16(%esi), %ebx )
+SRC( movl 20(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 16(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 20(%edi) )
+
+SRC( movl 24(%esi), %ebx )
+SRC( movl 28(%esi), %edx )
+ adcl %ebx, %eax
+DST( movl %ebx, 24(%edi) )
+ adcl %edx, %eax
+DST( movl %edx, 28(%edi) )
+
+ lea 32(%esi), %esi
+ lea 32(%edi), %edi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl FP(%esp), %edx
+ movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+SRC(3: movl (%esi), %ebx )
+ adcl %ebx, %eax
+DST( movl %ebx, (%edi) )
+ lea 4(%esi), %esi
+ lea 4(%edi), %edi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+SRC( movw (%esi), %cx )
+ leal 2(%esi), %esi
+DST( movw %cx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%ecx
+SRC(5: movb (%esi), %cl )
+DST( movb %cl, (%edi) )
+6: addl %ecx, %eax
+ adcl $0, %eax
+7:
+5000:
+
+/* Exception handler: */
+.section .fixup, "ax"
+
+6001:
+ movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+
+ /* zero the complete destination - computing the rest
+ is too much work */
+ movl ARGBASE+8(%esp), %edi # dst
+ movl ARGBASE+12(%esp), %ecx # len
+ xorl %eax,%eax
+ rep ; stosb
+
+ jmp 5000b
+
+6002:
+ movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT,(%ebx)
+ jmp 5000b
+
+.previous
+
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ecx # equivalent to addl $4,%esp
+ ret
+
+#else
+
+/* Version for PentiumII/PPro */
+
+#define ROUND1(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ addl %ebx, %eax ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ROUND(x) \
+ SRC(movl x(%esi), %ebx ) ; \
+ adcl %ebx, %eax ; \
+ DST(movl %ebx, x(%edi) ) ;
+
+#define ARGBASE 12
+
+csum_partial_copy_generic:
+ pushl %ebx
+ pushl %edi
+ pushl %esi
+ movl ARGBASE+4(%esp),%esi #src
+ movl ARGBASE+8(%esp),%edi #dst
+ movl ARGBASE+12(%esp),%ecx #len
+ movl ARGBASE+16(%esp),%eax #sum
+ movl %ecx, %edx
+ movl %ecx, %ebx
+ shrl $6, %ecx
+ andl $0x3c, %ebx
+ negl %ebx
+ subl %ebx, %esi
+ subl %ebx, %edi
+ lea 3f(%ebx,%ebx), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+1: addl $64,%esi
+ addl $64,%edi
+ ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
+ ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
+ ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
+ ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4)
+3: adcl $0,%eax
+ dec %ecx
+ jge 1b
+4: andl $3, %edx
+ jz 7f
+ cmpl $2, %edx
+ jb 5f
+SRC( movw (%esi), %dx )
+ leal 2(%esi), %esi
+DST( movw %dx, (%edi) )
+ leal 2(%edi), %edi
+ je 6f
+ shll $16,%edx
+5:
+SRC( movb (%esi), %dl )
+DST( movb %dl, (%edi) )
+6: addl %edx, %eax
+ adcl $0, %eax
+7:
+.section .fixup, "ax"
+6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr
+ movl $-EFAULT, (%ebx)
+ # zero the complete destination (computing the rest is too much work)
+ movl ARGBASE+8(%esp),%edi # dst
+ movl ARGBASE+12(%esp),%ecx # len
+ xorl %eax,%eax
+ rep; stosb
+ jmp 7b
+6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr
+ movl $-EFAULT, (%ebx)
+ jmp 7b
+.previous
+
+ popl %esi
+ popl %edi
+ popl %ebx
+ ret
+
+#undef ROUND
+#undef ROUND1
+
+#endif /* CPU==i686 */
diff --git a/pfinet/linux-src/arch/i386/lib/old-checksum.c b/pfinet/linux-src/arch/i386/lib/old-checksum.c
new file mode 100644
index 00000000..ae3a3804
--- /dev/null
+++ b/pfinet/linux-src/arch/i386/lib/old-checksum.c
@@ -0,0 +1,19 @@
+/*
+ * FIXME: old compatibility stuff, will be removed soon.
+ */
+
+#include <net/checksum.h>
+
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
+{
+ int src_err=0, dst_err=0;
+
+ sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err);
+
+ if (src_err || dst_err)
+ printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n");
+
+ return sum;
+}
+
+
diff --git a/pfinet/linux-src/arch/m68k/lib/checksum.c b/pfinet/linux-src/arch/m68k/lib/checksum.c
new file mode 100644
index 00000000..5110cac4
--- /dev/null
+++ b/pfinet/linux-src/arch/m68k/lib/checksum.c
@@ -0,0 +1,420 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek:
+ * Fixed some nasty bugs, causing some horrible crashes.
+ * A: At some points, the sum (%0) was used as
+ * length-counter instead of the length counter
+ * (%1). Thanks to Roman Hodek for pointing this out.
+ * B: GCC seems to mess up if one uses too many
+ * data-registers to hold input values and one tries to
+ * specify d0 and d1 as scratch registers. Letting gcc
+ * choose these registers itself solves the problem.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 1998/8/31 Andreas Schwab:
+ * Zero out rest of buffer on exception in
+ * csum_partial_copy_from_user.
+ */
+
+#include <net/checksum.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+unsigned int
+csum_partial (const unsigned char *buff, int len, unsigned int sum)
+{
+ unsigned long tmp1, tmp2;
+ /*
+ * Experiments with ethernet and slip connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary.
+ */
+ __asm__("movel %2,%3\n\t"
+ "btst #1,%3\n\t" /* Check alignment */
+ "jeq 2f\n\t"
+ "subql #2,%1\n\t" /* buff%4==2: treat first word */
+ "jgt 1f\n\t"
+ "addql #2,%1\n\t" /* len was == 2, treat only rest */
+ "jra 4f\n"
+ "1:\t"
+ "addw %2@+,%0\n\t" /* add first word to sum */
+ "clrl %3\n\t"
+ "addxl %3,%0\n" /* add X bit */
+ "2:\t"
+ /* unrolled loop for the main part: do 8 longs at once */
+ "movel %1,%3\n\t" /* save len in tmp1 */
+ "lsrl #5,%1\n\t" /* len/32 */
+ "jeq 2f\n\t" /* not enough... */
+ "subql #1,%1\n"
+ "1:\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "dbra %1,1b\n\t"
+ "clrl %4\n\t"
+ "addxl %4,%0\n\t" /* add X bit */
+ "clrw %1\n\t"
+ "subql #1,%1\n\t"
+ "jcc 1b\n"
+ "2:\t"
+ "movel %3,%1\n\t" /* restore len from tmp1 */
+ "andw #0x1c,%3\n\t" /* number of rest longs */
+ "jeq 4f\n\t"
+ "lsrw #2,%3\n\t"
+ "subqw #1,%3\n"
+ "3:\t"
+ /* loop for rest longs */
+ "movel %2@+,%4\n\t"
+ "addxl %4,%0\n\t"
+ "dbra %3,3b\n\t"
+ "clrl %4\n\t"
+ "addxl %4,%0\n" /* add X bit */
+ "4:\t"
+ /* now check for rest bytes that do not fit into longs */
+ "andw #3,%1\n\t"
+ "jeq 7f\n\t"
+ "clrl %4\n\t" /* clear tmp2 for rest bytes */
+ "subqw #2,%1\n\t"
+ "jlt 5f\n\t"
+ "movew %2@+,%4\n\t" /* have rest >= 2: get word */
+ "swap %4\n\t" /* into bits 16..31 */
+ "tstw %1\n\t" /* another byte? */
+ "jeq 6f\n"
+ "5:\t"
+ "moveb %2@,%4\n\t" /* have odd rest: get byte */
+ "lslw #8,%4\n\t" /* into bits 8..15; 16..31 untouched */
+ "6:\t"
+ "addl %4,%0\n\t" /* now add rest long to sum */
+ "clrl %4\n\t"
+ "addxl %4,%0\n" /* add X bit */
+ "7:\t"
+ : "=d" (sum), "=d" (len), "=a" (buff),
+ "=&d" (tmp1), "=&d" (tmp2)
+ : "0" (sum), "1" (len), "2" (buff)
+ );
+ return(sum);
+}
+
+
+
+/*
+ * copy from user space while checksumming, with exception handling.
+ */
+
+unsigned int
+csum_partial_copy_from_user(const char *src, char *dst, int len,
+ int sum, int *csum_err)
+{
+ /*
+ * GCC doesn't like more than 10 operands for the asm
+ * statements so we have to use tmp2 for the error
+ * code.
+ */
+ unsigned long tmp1, tmp2;
+
+ __asm__("movel %2,%4\n\t"
+ "btst #1,%4\n\t" /* Check alignment */
+ "jeq 2f\n\t"
+ "subql #2,%1\n\t" /* buff%4==2: treat first word */
+ "jgt 1f\n\t"
+ "addql #2,%1\n\t" /* len was == 2, treat only rest */
+ "jra 4f\n"
+ "1:\n"
+ "10:\t"
+ "movesw %2@+,%4\n\t" /* add first word to sum */
+ "addw %4,%0\n\t"
+ "movew %4,%3@+\n\t"
+ "clrl %4\n\t"
+ "addxl %4,%0\n" /* add X bit */
+ "2:\t"
+ /* unrolled loop for the main part: do 8 longs at once */
+ "movel %1,%4\n\t" /* save len in tmp1 */
+ "lsrl #5,%1\n\t" /* len/32 */
+ "jeq 2f\n\t" /* not enough... */
+ "subql #1,%1\n"
+ "1:\n"
+ "11:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "12:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "13:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "14:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "15:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "16:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "17:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "18:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "dbra %1,1b\n\t"
+ "clrl %5\n\t"
+ "addxl %5,%0\n\t" /* add X bit */
+ "clrw %1\n\t"
+ "subql #1,%1\n\t"
+ "jcc 1b\n"
+ "2:\t"
+ "movel %4,%1\n\t" /* restore len from tmp1 */
+ "andw #0x1c,%4\n\t" /* number of rest longs */
+ "jeq 4f\n\t"
+ "lsrw #2,%4\n\t"
+ "subqw #1,%4\n"
+ "3:\n"
+ /* loop for rest longs */
+ "19:\t"
+ "movesl %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "dbra %4,3b\n\t"
+ "clrl %5\n\t"
+ "addxl %5,%0\n" /* add X bit */
+ "4:\t"
+ /* now check for rest bytes that do not fit into longs */
+ "andw #3,%1\n\t"
+ "jeq 7f\n\t"
+ "clrl %5\n\t" /* clear tmp2 for rest bytes */
+ "subqw #2,%1\n\t"
+ "jlt 5f\n\t"
+ "20:\t"
+ "movesw %2@+,%5\n\t" /* have rest >= 2: get word */
+ "movew %5,%3@+\n\t"
+ "swap %5\n\t" /* into bits 16..31 */
+ "tstw %1\n\t" /* another byte? */
+ "jeq 6f\n"
+ "5:\n"
+ "21:\t"
+ "movesb %2@,%5\n\t" /* have odd rest: get byte */
+ "moveb %5,%3@+\n\t"
+ "lslw #8,%5\n\t" /* into bits 8..15; 16..31 untouched */
+ "6:\t"
+ "addl %5,%0\n\t" /* now add rest long to sum */
+ "clrl %5\n\t"
+ "addxl %5,%0\n\t" /* add X bit */
+ "7:\t"
+ "clrl %5\n" /* no error - clear return value */
+ "8:\n"
+ ".section .fixup,\"ax\"\n"
+ ".even\n"
+ /* If any execption occurs zero out the rest.
+ Similarities with the code above are intentional :-) */
+ "90:\t"
+ "clrw %3@+\n\t"
+ "movel %1,%4\n\t"
+ "lsrl #5,%1\n\t"
+ "jeq 1f\n\t"
+ "subql #1,%1\n"
+ "91:\t"
+ "clrl %3@+\n"
+ "92:\t"
+ "clrl %3@+\n"
+ "93:\t"
+ "clrl %3@+\n"
+ "94:\t"
+ "clrl %3@+\n"
+ "95:\t"
+ "clrl %3@+\n"
+ "96:\t"
+ "clrl %3@+\n"
+ "97:\t"
+ "clrl %3@+\n"
+ "98:\t"
+ "clrl %3@+\n\t"
+ "dbra %1,91b\n\t"
+ "clrw %1\n\t"
+ "subql #1,%1\n\t"
+ "jcc 91b\n"
+ "1:\t"
+ "movel %4,%1\n\t"
+ "andw #0x1c,%4\n\t"
+ "jeq 1f\n\t"
+ "lsrw #2,%4\n\t"
+ "subqw #1,%4\n"
+ "99:\t"
+ "clrl %3@+\n\t"
+ "dbra %4,99b\n\t"
+ "1:\t"
+ "andw #3,%1\n\t"
+ "jeq 9f\n"
+ "100:\t"
+ "clrw %3@+\n\t"
+ "tstw %1\n\t"
+ "jeq 9f\n"
+ "101:\t"
+ "clrb %3@+\n"
+ "9:\t"
+#define STR(X) STR1(X)
+#define STR1(X) #X
+ "moveq #-" STR(EFAULT) ",%5\n\t"
+ "jra 8b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ ".long 10b,90b\n"
+ ".long 11b,91b\n"
+ ".long 12b,92b\n"
+ ".long 13b,93b\n"
+ ".long 14b,94b\n"
+ ".long 15b,95b\n"
+ ".long 16b,96b\n"
+ ".long 17b,97b\n"
+ ".long 18b,98b\n"
+ ".long 19b,99b\n"
+ ".long 20b,100b\n"
+ ".long 21b,101b\n"
+ ".previous"
+ : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
+ "=&d" (tmp1), "=d" (tmp2)
+ : "0" (sum), "1" (len), "2" (src), "3" (dst)
+ );
+
+ *csum_err = tmp2;
+
+ return(sum);
+}
+
+/*
+ * copy from kernel space while checksumming, otherwise like csum_partial
+ */
+
+unsigned int
+csum_partial_copy(const char *src, char *dst, int len, int sum)
+{
+ unsigned long tmp1, tmp2;
+ __asm__("movel %2,%4\n\t"
+ "btst #1,%4\n\t" /* Check alignment */
+ "jeq 2f\n\t"
+ "subql #2,%1\n\t" /* buff%4==2: treat first word */
+ "jgt 1f\n\t"
+ "addql #2,%1\n\t" /* len was == 2, treat only rest */
+ "jra 4f\n"
+ "1:\t"
+ "movew %2@+,%4\n\t" /* add first word to sum */
+ "addw %4,%0\n\t"
+ "movew %4,%3@+\n\t"
+ "clrl %4\n\t"
+ "addxl %4,%0\n" /* add X bit */
+ "2:\t"
+ /* unrolled loop for the main part: do 8 longs at once */
+ "movel %1,%4\n\t" /* save len in tmp1 */
+ "lsrl #5,%1\n\t" /* len/32 */
+ "jeq 2f\n\t" /* not enough... */
+ "subql #1,%1\n"
+ "1:\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "dbra %1,1b\n\t"
+ "clrl %5\n\t"
+ "addxl %5,%0\n\t" /* add X bit */
+ "clrw %1\n\t"
+ "subql #1,%1\n\t"
+ "jcc 1b\n"
+ "2:\t"
+ "movel %4,%1\n\t" /* restore len from tmp1 */
+ "andw #0x1c,%4\n\t" /* number of rest longs */
+ "jeq 4f\n\t"
+ "lsrw #2,%4\n\t"
+ "subqw #1,%4\n"
+ "3:\t"
+ /* loop for rest longs */
+ "movel %2@+,%5\n\t"
+ "addxl %5,%0\n\t"
+ "movel %5,%3@+\n\t"
+ "dbra %4,3b\n\t"
+ "clrl %5\n\t"
+ "addxl %5,%0\n" /* add X bit */
+ "4:\t"
+ /* now check for rest bytes that do not fit into longs */
+ "andw #3,%1\n\t"
+ "jeq 7f\n\t"
+ "clrl %5\n\t" /* clear tmp2 for rest bytes */
+ "subqw #2,%1\n\t"
+ "jlt 5f\n\t"
+ "movew %2@+,%5\n\t" /* have rest >= 2: get word */
+ "movew %5,%3@+\n\t"
+ "swap %5\n\t" /* into bits 16..31 */
+ "tstw %1\n\t" /* another byte? */
+ "jeq 6f\n"
+ "5:\t"
+ "moveb %2@,%5\n\t" /* have odd rest: get byte */
+ "moveb %5,%3@+\n\t"
+ "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */
+ "6:\t"
+ "addl %5,%0\n\t" /* now add rest long to sum */
+ "clrl %5\n\t"
+ "addxl %5,%0\n" /* add X bit */
+ "7:\t"
+ : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst),
+ "=&d" (tmp1), "=&d" (tmp2)
+ : "0" (sum), "1" (len), "2" (src), "3" (dst)
+ );
+ return(sum);
+}
diff --git a/pfinet/linux-src/arch/ppc/lib/checksum.S b/pfinet/linux-src/arch/ppc/lib/checksum.S
new file mode 100644
index 00000000..66a2e3aa
--- /dev/null
+++ b/pfinet/linux-src/arch/ppc/lib/checksum.S
@@ -0,0 +1,194 @@
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include "../kernel/ppc_asm.tmpl"
+
+ .text
+
+/*
+ * ip_fast_csum(buf, len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ */
+_GLOBAL(ip_fast_csum)
+ lwz r0,0(r3)
+ lwzu r5,4(r3)
+ addi r4,r4,-2
+ addc r0,r0,r5
+ mtctr r4
+1: lwzu r4,4(r3)
+ adde r0,r0,r4
+ bdnz 1b
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ * csum_tcpudp_magic(saddr, daddr, len, proto, sum)
+ */
+_GLOBAL(csum_tcpudp_magic)
+ rlwimi r5,r6,16,0,15 /* put proto in upper half of len */
+ addc r0,r3,r4 /* add 4 32-bit words together */
+ adde r0,r0,r5
+ adde r0,r0,r7
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * csum_partial(buff, len, sum)
+ */
+_GLOBAL(csum_partial)
+ addic r0,r5,0
+ subi r3,r3,4
+ srwi. r6,r4,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r5,r3,2 /* Align buffer to longword boundary */
+ beq+ 1f
+ lhz r5,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r4,r4,2
+ addc r0,r0,r5
+ srwi. r6,r4,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+2: lwzu r5,4(r3) /* the bdnz has zero overhead, so it should */
+ adde r0,r0,r5 /* be unnecessary to unroll this loop */
+ bdnz 2b
+ andi. r4,r4,3
+3: cmpi 0,r4,2
+ blt+ 4f
+ lhz r5,4(r3)
+ addi r3,r3,2
+ subi r4,r4,2
+ adde r0,r0,r5
+4: cmpi 0,r4,1
+ bne+ 5f
+ lbz r5,4(r3)
+ slwi r5,r5,8 /* Upper byte of word */
+ adde r0,r0,r5
+5: addze r3,r0 /* add in final carry */
+ blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+ addic r0,r6,0
+ subi r3,r3,4
+ subi r4,r4,4
+ srwi. r6,r5,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r9,r4,2 /* Align dst to longword boundary */
+ beq+ 1f
+81: lhz r6,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r5,r5,2
+91: sth r6,4(r4)
+ addi r4,r4,2
+ addc r0,r0,r6
+ srwi. r6,r5,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+82: lwzu r6,4(r3) /* the bdnz has zero overhead, so it should */
+92: stwu r6,4(r4) /* be unnecessary to unroll this loop */
+ adde r0,r0,r6
+ bdnz 82b
+ andi. r5,r5,3
+3: cmpi 0,r5,2
+ blt+ 4f
+83: lhz r6,4(r3)
+ addi r3,r3,2
+ subi r5,r5,2
+93: sth r6,4(r4)
+ addi r4,r4,2
+ adde r0,r0,r6
+4: cmpi 0,r5,1
+ bne+ 5f
+84: lbz r6,4(r3)
+94: stb r6,4(r4)
+ slwi r6,r6,8 /* Upper byte of word */
+ adde r0,r0,r6
+5: addze r3,r0 /* add in final carry */
+ blr
+
+/* These shouldn't go in the fixup section, since that would
+ cause the ex_table addresses to get out of order. */
+
+src_error_1:
+ li r6,0
+ subi r5,r5,2
+95: sth r6,4(r4)
+ addi r4,r4,2
+ srwi. r6,r5,2
+ beq 3f
+ mtctr r6
+src_error_2:
+ li r6,0
+96: stwu r6,4(r4)
+ bdnz 96b
+3: andi. r5,r5,3
+ beq src_error
+src_error_3:
+ li r6,0
+ mtctr r5
+ addi r4,r4,3
+97: stbu r6,1(r4)
+ bdnz 97b
+src_error:
+ cmpi 0,r7,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r7)
+1: addze r3,r0
+ blr
+
+dst_error:
+ cmpi 0,r8,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r8)
+1: addze r3,r0
+ blr
+
+.section __ex_table,"a"
+ .long 81b,src_error_1
+ .long 91b,dst_error
+ .long 82b,src_error_2
+ .long 92b,dst_error
+ .long 83b,src_error_3
+ .long 93b,dst_error
+ .long 84b,src_error_3
+ .long 94b,dst_error
+ .long 95b,dst_error
+ .long 96b,dst_error
+ .long 97b,dst_error
diff --git a/pfinet/linux-src/arch/s390/lib/checksum.c b/pfinet/linux-src/arch/s390/lib/checksum.c
new file mode 100644
index 00000000..9411e1c5
--- /dev/null
+++ b/pfinet/linux-src/arch/s390/lib/checksum.c
@@ -0,0 +1,56 @@
+/*
+ * arch/s390/lib/checksum.c
+ * S390 fast network checksum routines
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Ulrich Hild (first version),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * This file contains network checksum routines
+ */
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/checksum.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+unsigned int
+csum_partial (const unsigned char *buff, int len, unsigned int sum)
+{
+ /*
+ * Experiments with ethernet and slip connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary.
+ */
+ __asm__ __volatile__ (
+ " lr 2,%1\n" /* address in gpr 2 */
+ " lr 3,%2\n" /* length in gpr 3 */
+ "0: cksm %0,2\n" /* do checksum on longs */
+ " jo 0b\n"
+ : "+&d" (sum)
+ : "d" (buff), "d" (len)
+ : "cc", "2", "3" );
+ return sum;
+}
+
+/*
+ * Fold a partial checksum without adding pseudo headers
+ */
+unsigned short csum_fold(unsigned int sum)
+{
+ __asm__ __volatile__ (
+ " sr 3,3\n" /* %0 = H*65536 + L */
+ " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */
+ " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */
+ " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */
+ " alr %0,2\n" /* %0 = H+L+C L+H */
+ " srl %0,16\n" /* %0 = H+L+C */
+ : "+d" (sum) : : "cc", "2", "3");
+ return ((unsigned short) ~sum);
+}
+
diff --git a/pfinet/linux-src/arch/sparc/lib/checksum.S b/pfinet/linux-src/arch/sparc/lib/checksum.S
new file mode 100644
index 00000000..3dc58259
--- /dev/null
+++ b/pfinet/linux-src/arch/sparc/lib/checksum.S
@@ -0,0 +1,581 @@
+/* checksum.S: Sparc optimized checksum code.
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996 David S. Miller
+ * Copyright(C) 1997 Jakub Jelinek
+ *
+ * derived from:
+ * Linux/Alpha checksum c-code
+ * Linux/ix86 inline checksum assembly
+ * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ * David Mosberger-Tang for optimized reference c-code
+ * BSD4.4 portable checksum routine
+ */
+
+#include <asm/cprefix.h>
+#include <asm/errno.h>
+
+#define CSUM_BIGCHUNK(buf, offset, sum, t0, t1, t2, t3, t4, t5) \
+ ldd [buf + offset + 0x00], t0; \
+ ldd [buf + offset + 0x08], t2; \
+ addxcc t0, sum, sum; \
+ addxcc t1, sum, sum; \
+ ldd [buf + offset + 0x10], t4; \
+ addxcc t2, sum, sum; \
+ addxcc t3, sum, sum; \
+ ldd [buf + offset + 0x18], t0; \
+ addxcc t4, sum, sum; \
+ addxcc t5, sum, sum; \
+ addxcc t0, sum, sum; \
+ addxcc t1, sum, sum;
+
+#define CSUM_LASTCHUNK(buf, offset, sum, t0, t1, t2, t3) \
+ ldd [buf - offset - 0x08], t0; \
+ ldd [buf - offset - 0x00], t2; \
+ addxcc t0, sum, sum; \
+ addxcc t1, sum, sum; \
+ addxcc t2, sum, sum; \
+ addxcc t3, sum, sum;
+
+ /* Do end cruft out of band to get better cache patterns. */
+csum_partial_end_cruft:
+ be 1f ! caller asks %o1 & 0x8
+ andcc %o1, 4, %g0 ! nope, check for word remaining
+ ldd [%o0], %g2 ! load two
+ addcc %g2, %o2, %o2 ! add first word to sum
+ addxcc %g3, %o2, %o2 ! add second word as well
+ add %o0, 8, %o0 ! advance buf ptr
+ addx %g0, %o2, %o2 ! add in final carry
+ andcc %o1, 4, %g0 ! check again for word remaining
+1: be 1f ! nope, skip this code
+ andcc %o1, 3, %o1 ! check for trailing bytes
+ ld [%o0], %g2 ! load it
+ addcc %g2, %o2, %o2 ! add to sum
+ add %o0, 4, %o0 ! advance buf ptr
+ addx %g0, %o2, %o2 ! add in final carry
+ andcc %o1, 3, %g0 ! check again for trailing bytes
+1: be 1f ! no trailing bytes, return
+ addcc %o1, -1, %g0 ! only one byte remains?
+ bne 2f ! at least two bytes more
+ subcc %o1, 2, %o1 ! only two bytes more?
+ b 4f ! only one byte remains
+ or %g0, %g0, %o4 ! clear fake hword value
+2: lduh [%o0], %o4 ! get hword
+ be 6f ! jmp if only hword remains
+ add %o0, 2, %o0 ! advance buf ptr either way
+ sll %o4, 16, %o4 ! create upper hword
+4: ldub [%o0], %o5 ! get final byte
+ sll %o5, 8, %o5 ! put into place
+ or %o5, %o4, %o4 ! coalese with hword (if any)
+6: addcc %o4, %o2, %o2 ! add to sum
+1: retl ! get outta here
+ addx %g0, %o2, %o0 ! add final carry into retval
+
+ /* Also do alignment out of band to get better cache patterns. */
+csum_partial_fix_alignment:
+ cmp %o1, 6
+ bl cpte - 0x4
+ andcc %o0, 0x2, %g0
+ be 1f
+ andcc %o0, 0x4, %g0
+ lduh [%o0 + 0x00], %g2
+ sub %o1, 2, %o1
+ add %o0, 2, %o0
+ sll %g2, 16, %g2
+ addcc %g2, %o2, %o2
+ srl %o2, 16, %g3
+ addx %g0, %g3, %g2
+ sll %o2, 16, %o2
+ sll %g2, 16, %g3
+ srl %o2, 16, %o2
+ andcc %o0, 0x4, %g0
+ or %g3, %o2, %o2
+1: be cpa
+ andcc %o1, 0xffffff80, %o3
+ ld [%o0 + 0x00], %g2
+ sub %o1, 4, %o1
+ addcc %g2, %o2, %o2
+ add %o0, 4, %o0
+ addx %g0, %o2, %o2
+ b cpa
+ andcc %o1, 0xffffff80, %o3
+
+ /* The common case is to get called with a nicely aligned
+ * buffer of size 0x20. Follow the code path for that case.
+ */
+ .globl C_LABEL(csum_partial)
+C_LABEL(csum_partial): /* %o0=buf, %o1=len, %o2=sum */
+ andcc %o0, 0x7, %g0 ! alignment problems?
+ bne csum_partial_fix_alignment ! yep, handle it
+ sethi %hi(cpte - 8), %g7 ! prepare table jmp ptr
+ andcc %o1, 0xffffff80, %o3 ! num loop iterations
+cpa: be 3f ! none to do
+ andcc %o1, 0x70, %g1 ! clears carry flag too
+5: CSUM_BIGCHUNK(%o0, 0x00, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+ CSUM_BIGCHUNK(%o0, 0x20, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+ CSUM_BIGCHUNK(%o0, 0x40, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+ CSUM_BIGCHUNK(%o0, 0x60, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+ addx %g0, %o2, %o2 ! sink in final carry
+ subcc %o3, 128, %o3 ! detract from loop iters
+ bne 5b ! more to do
+ add %o0, 128, %o0 ! advance buf ptr
+ andcc %o1, 0x70, %g1 ! clears carry flag too
+3: be cpte ! nope
+ andcc %o1, 0xf, %g0 ! anything left at all?
+ srl %g1, 1, %o4 ! compute offset
+ sub %g7, %g1, %g7 ! adjust jmp ptr
+ sub %g7, %o4, %g7 ! final jmp ptr adjust
+ jmp %g7 + %lo(cpte - 8) ! enter the table
+ add %o0, %g1, %o0 ! advance buf ptr
+cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
+ CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3, %g4, %g5)
+ CSUM_LASTCHUNK(%o0, 0x48, %o2, %g2, %g3, %g4, %g5)
+ CSUM_LASTCHUNK(%o0, 0x38, %o2, %g2, %g3, %g4, %g5)
+ CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3, %g4, %g5)
+ CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3, %g4, %g5)
+ CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3, %g4, %g5)
+ addx %g0, %o2, %o2 ! fetch final carry
+ andcc %o1, 0xf, %g0 ! anything left at all?
+cpte: bne csum_partial_end_cruft ! yep, handle it
+ andcc %o1, 8, %g0 ! check how much
+cpout: retl ! get outta here
+ mov %o2, %o0 ! return computed csum
+
+ .globl C_LABEL(__csum_partial_copy_start), C_LABEL(__csum_partial_copy_end)
+C_LABEL(__csum_partial_copy_start):
+
+#define EX(x,y,a,b,z) \
+98: x,y; \
+ .section .fixup,z##alloc,z##execinstr; \
+ .align 4; \
+99: ba 30f; \
+ a, b, %o3; \
+ .section __ex_table,z##alloc; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4
+
+#define EX2(x,y,z) \
+98: x,y; \
+ .section __ex_table,z##alloc; \
+ .align 4; \
+ .word 98b, 30f; \
+ .text; \
+ .align 4
+
+#define EX3(x,y,z) \
+98: x,y; \
+ .section __ex_table,z##alloc; \
+ .align 4; \
+ .word 98b, 96f; \
+ .text; \
+ .align 4
+
+#define EXT(start,end,handler,z) \
+ .section __ex_table,z##alloc; \
+ .align 4; \
+ .word start, 0, end, handler; \
+ .text; \
+ .align 4
+
+ /* This aligned version executes typically in 8.5 superscalar cycles, this
+ * is the best I can do. I say 8.5 because the final add will pair with
+ * the next ldd in the main unrolled loop. Thus the pipe is always full.
+ * If you change these macros (including order of instructions),
+ * please check the fixup code below as well.
+ */
+#define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ ldd [src + off + 0x00], t0; \
+ ldd [src + off + 0x08], t2; \
+ addxcc t0, sum, sum; \
+ ldd [src + off + 0x10], t4; \
+ addxcc t1, sum, sum; \
+ ldd [src + off + 0x18], t6; \
+ addxcc t2, sum, sum; \
+ std t0, [dst + off + 0x00]; \
+ addxcc t3, sum, sum; \
+ std t2, [dst + off + 0x08]; \
+ addxcc t4, sum, sum; \
+ std t4, [dst + off + 0x10]; \
+ addxcc t5, sum, sum; \
+ std t6, [dst + off + 0x18]; \
+ addxcc t6, sum, sum; \
+ addxcc t7, sum, sum;
+
+ /* 12 superscalar cycles seems to be the limit for this case,
+ * because of this we thus do all the ldd's together to get
+ * Viking MXCC into streaming mode. Ho hum...
+ */
+#define CSUMCOPY_BIGCHUNK(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7) \
+ ldd [src + off + 0x00], t0; \
+ ldd [src + off + 0x08], t2; \
+ ldd [src + off + 0x10], t4; \
+ ldd [src + off + 0x18], t6; \
+ st t0, [dst + off + 0x00]; \
+ addxcc t0, sum, sum; \
+ st t1, [dst + off + 0x04]; \
+ addxcc t1, sum, sum; \
+ st t2, [dst + off + 0x08]; \
+ addxcc t2, sum, sum; \
+ st t3, [dst + off + 0x0c]; \
+ addxcc t3, sum, sum; \
+ st t4, [dst + off + 0x10]; \
+ addxcc t4, sum, sum; \
+ st t5, [dst + off + 0x14]; \
+ addxcc t5, sum, sum; \
+ st t6, [dst + off + 0x18]; \
+ addxcc t6, sum, sum; \
+ st t7, [dst + off + 0x1c]; \
+ addxcc t7, sum, sum;
+
+ /* Yuck, 6 superscalar cycles... */
+#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1, t2, t3) \
+ ldd [src - off - 0x08], t0; \
+ ldd [src - off - 0x00], t2; \
+ addxcc t0, sum, sum; \
+ st t0, [dst - off - 0x08]; \
+ addxcc t1, sum, sum; \
+ st t1, [dst - off - 0x04]; \
+ addxcc t2, sum, sum; \
+ st t2, [dst - off - 0x00]; \
+ addxcc t3, sum, sum; \
+ st t3, [dst - off + 0x04];
+
+ /* Handle the end cruft code out of band for better cache patterns. */
+cc_end_cruft:
+ be 1f
+ andcc %o3, 4, %g0
+ EX(ldd [%o0 + 0x00], %g2, and %o3, 0xf,#)
+ add %o1, 8, %o1
+ addcc %g2, %g7, %g7
+ add %o0, 8, %o0
+ addxcc %g3, %g7, %g7
+ EX2(st %g2, [%o1 - 0x08],#)
+ addx %g0, %g7, %g7
+ andcc %o3, 4, %g0
+ EX2(st %g3, [%o1 - 0x04],#)
+1: be 1f
+ andcc %o3, 3, %o3
+ EX(ld [%o0 + 0x00], %g2, add %o3, 4,#)
+ add %o1, 4, %o1
+ addcc %g2, %g7, %g7
+ EX2(st %g2, [%o1 - 0x04],#)
+ addx %g0, %g7, %g7
+ andcc %o3, 3, %g0
+ add %o0, 4, %o0
+1: be 1f
+ addcc %o3, -1, %g0
+ bne 2f
+ subcc %o3, 2, %o3
+ b 4f
+ or %g0, %g0, %o4
+2: EX(lduh [%o0 + 0x00], %o4, add %o3, 2,#)
+ add %o0, 2, %o0
+ EX2(sth %o4, [%o1 + 0x00],#)
+ be 6f
+ add %o1, 2, %o1
+ sll %o4, 16, %o4
+4: EX(ldub [%o0 + 0x00], %o5, add %g0, 1,#)
+ EX2(stb %o5, [%o1 + 0x00],#)
+ sll %o5, 8, %o5
+ or %o5, %o4, %o4
+6: addcc %o4, %g7, %g7
+1: retl
+ addx %g0, %g7, %o0
+
+ /* Also, handle the alignment code out of band. */
+cc_dword_align:
+ cmp %g1, 6
+ bl,a ccte
+ andcc %g1, 0xf, %o3
+ andcc %o0, 0x1, %g0
+ bne ccslow
+ andcc %o0, 0x2, %g0
+ be 1f
+ andcc %o0, 0x4, %g0
+ EX(lduh [%o0 + 0x00], %g4, add %g1, 0,#)
+ sub %g1, 2, %g1
+ EX2(sth %g4, [%o1 + 0x00],#)
+ add %o0, 2, %o0
+ sll %g4, 16, %g4
+ addcc %g4, %g7, %g7
+ add %o1, 2, %o1
+ srl %g7, 16, %g3
+ addx %g0, %g3, %g4
+ sll %g7, 16, %g7
+ sll %g4, 16, %g3
+ srl %g7, 16, %g7
+ andcc %o0, 0x4, %g0
+ or %g3, %g7, %g7
+1: be 3f
+ andcc %g1, 0xffffff80, %g0
+ EX(ld [%o0 + 0x00], %g4, add %g1, 0,#)
+ sub %g1, 4, %g1
+ EX2(st %g4, [%o1 + 0x00],#)
+ add %o0, 4, %o0
+ addcc %g4, %g7, %g7
+ add %o1, 4, %o1
+ addx %g0, %g7, %g7
+ b 3f
+ andcc %g1, 0xffffff80, %g0
+
+ /* Sun, you just can't beat me, you just can't. Stop trying,
+ * give up. I'm serious, I am going to kick the living shit
+ * out of you, game over, lights out.
+ */
+ .align 8
+ .globl C_LABEL(__csum_partial_copy_sparc_generic)
+C_LABEL(__csum_partial_copy_sparc_generic):
+ /* %o0=src, %o1=dest, %g1=len, %g7=sum */
+ xor %o0, %o1, %o4 ! get changing bits
+ andcc %o4, 3, %g0 ! check for mismatched alignment
+ bne ccslow ! better this than unaligned/fixups
+ andcc %o0, 7, %g0 ! need to align things?
+ bne cc_dword_align ! yes, we check for short lengths there
+ andcc %g1, 0xffffff80, %g0 ! can we use unrolled loop?
+3: be 3f ! nope, less than one loop remains
+ andcc %o1, 4, %g0 ! dest aligned on 4 or 8 byte boundary?
+ be ccdbl + 4 ! 8 byte aligned, kick ass
+5: CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+10: EXT(5b, 10b, 20f,#) ! note for exception handling
+ sub %g1, 128, %g1 ! detract from length
+ addx %g0, %g7, %g7 ! add in last carry bit
+ andcc %g1, 0xffffff80, %g0 ! more to csum?
+ add %o0, 128, %o0 ! advance src ptr
+ bne 5b ! we did not go negative, continue looping
+ add %o1, 128, %o1 ! advance dest ptr
+3: andcc %g1, 0x70, %o2 ! can use table?
+ccmerge:be ccte ! nope, go and check for end cruft
+ andcc %g1, 0xf, %o3 ! get low bits of length (clears carry btw)
+ srl %o2, 1, %o4 ! begin negative offset computation
+ sethi %hi(12f), %o5 ! set up table ptr end
+ add %o0, %o2, %o0 ! advance src ptr
+ sub %o5, %o4, %o5 ! continue table calculation
+ sll %o2, 1, %g2 ! constant multiplies are fun...
+ sub %o5, %g2, %o5 ! some more adjustments
+ jmp %o5 + %lo(12f) ! jump into it, duff style, wheee...
+ add %o1, %o2, %o1 ! advance dest ptr (carry is clear btw)
+cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
+ CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3,%g4,%g5)
+ CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3,%g4,%g5)
+ CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3,%g4,%g5)
+ CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3,%g4,%g5)
+ CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3,%g4,%g5)
+ CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
+12: EXT(cctbl, 12b, 22f,#) ! note for exception table handling
+ addx %g0, %g7, %g7
+ andcc %o3, 0xf, %g0 ! check for low bits set
+ccte: bne cc_end_cruft ! something left, handle it out of band
+ andcc %o3, 8, %g0 ! begin checks for that code
+ retl ! return
+ mov %g7, %o0 ! give em the computed checksum
+ccdbl: CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+11: EXT(ccdbl, 11b, 21f,#) ! note for exception table handling
+ sub %g1, 128, %g1 ! detract from length
+ addx %g0, %g7, %g7 ! add in last carry bit
+ andcc %g1, 0xffffff80, %g0 ! more to csum?
+ add %o0, 128, %o0 ! advance src ptr
+ bne ccdbl ! we did not go negative, continue looping
+ add %o1, 128, %o1 ! advance dest ptr
+ b ccmerge ! finish it off, above
+ andcc %g1, 0x70, %o2 ! can use table? (clears carry btw)
+
+ccslow: cmp %g1, 0
+ mov 0, %g5
+ bleu 4f
+ andcc %o0, 1, %o5
+ be,a 1f
+ srl %g1, 1, %g4
+ sub %g1, 1, %g1
+ EX(ldub [%o0], %g5, add %g1, 1,#)
+ add %o0, 1, %o0
+ EX2(stb %g5, [%o1],#)
+ srl %g1, 1, %g4
+ add %o1, 1, %o1
+1: cmp %g4, 0
+ be,a 3f
+ andcc %g1, 1, %g0
+ andcc %o0, 2, %g0
+ be,a 1f
+ srl %g4, 1, %g4
+ EX(lduh [%o0], %o4, add %g1, 0,#)
+ sub %g1, 2, %g1
+ srl %o4, 8, %g2
+ sub %g4, 1, %g4
+ EX2(stb %g2, [%o1],#)
+ add %o4, %g5, %g5
+ EX2(stb %o4, [%o1 + 1],#)
+ add %o0, 2, %o0
+ srl %g4, 1, %g4
+ add %o1, 2, %o1
+1: cmp %g4, 0
+ be,a 2f
+ andcc %g1, 2, %g0
+ EX3(ld [%o0], %o4,#)
+5: srl %o4, 24, %g2
+ srl %o4, 16, %g3
+ EX2(stb %g2, [%o1],#)
+ srl %o4, 8, %g2
+ EX2(stb %g3, [%o1 + 1],#)
+ add %o0, 4, %o0
+ EX2(stb %g2, [%o1 + 2],#)
+ addcc %o4, %g5, %g5
+ EX2(stb %o4, [%o1 + 3],#)
+ addx %g5, %g0, %g5 ! I am now to lazy to optimize this (question it
+ add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl
+ subcc %g4, 1, %g4 ! tricks
+ bne,a 5b
+ EX3(ld [%o0], %o4,#)
+ sll %g5, 16, %g2
+ srl %g5, 16, %g5
+ srl %g2, 16, %g2
+ andcc %g1, 2, %g0
+ add %g2, %g5, %g5
+2: be,a 3f
+ andcc %g1, 1, %g0
+ EX(lduh [%o0], %o4, and %g1, 3,#)
+ andcc %g1, 1, %g0
+ srl %o4, 8, %g2
+ add %o0, 2, %o0
+ EX2(stb %g2, [%o1],#)
+ add %g5, %o4, %g5
+ EX2(stb %o4, [%o1 + 1],#)
+ add %o1, 2, %o1
+3: be,a 1f
+ sll %g5, 16, %o4
+ EX(ldub [%o0], %g2, add %g0, 1,#)
+ sll %g2, 8, %o4
+ EX2(stb %g2, [%o1],#)
+ add %g5, %o4, %g5
+ sll %g5, 16, %o4
+1: addcc %o4, %g5, %g5
+ srl %g5, 16, %o4
+ addx %g0, %o4, %g5
+ orcc %o5, %g0, %g0
+ be 4f
+ srl %g5, 8, %o4
+ and %g5, 0xff, %g2
+ and %o4, 0xff, %o4
+ sll %g2, 8, %g2
+ or %g2, %o4, %g5
+4: addcc %g7, %g5, %g7
+ retl
+ addx %g0, %g7, %o0
+C_LABEL(__csum_partial_copy_end):
+
+/* We do these strange calculations for the csum_*_from_user case only, ie.
+ * we only bother with faults on loads... */
+
+/* o2 = ((g2%20)&3)*8
+ * o3 = g1 - (g2/20)*32 - o2 */
+20:
+ cmp %g2, 20
+ blu,a 1f
+ and %g2, 3, %o2
+ sub %g1, 32, %g1
+ b 20b
+ sub %g2, 20, %g2
+1:
+ sll %o2, 3, %o2
+ b 31f
+ sub %g1, %o2, %o3
+
+/* o2 = (!(g2 & 15) ? 0 : (((g2 & 15) + 1) & ~1)*8)
+ * o3 = g1 - (g2/16)*32 - o2 */
+21:
+ andcc %g2, 15, %o3
+ srl %g2, 4, %g2
+ be,a 1f
+ clr %o2
+ add %o3, 1, %o3
+ and %o3, 14, %o3
+ sll %o3, 3, %o2
+1:
+ sll %g2, 5, %g2
+ sub %g1, %g2, %o3
+ b 31f
+ sub %o3, %o2, %o3
+
+/* o0 += (g2/10)*16 - 0x70
+ * 01 += (g2/10)*16 - 0x70
+ * o2 = (g2 % 10) ? 8 : 0
+ * o3 += 0x70 - (g2/10)*16 - o2 */
+22:
+ cmp %g2, 10
+ blu,a 1f
+ sub %o0, 0x70, %o0
+ add %o0, 16, %o0
+ add %o1, 16, %o1
+ sub %o3, 16, %o3
+ b 22b
+ sub %g2, 10, %g2
+1:
+ sub %o1, 0x70, %o1
+ add %o3, 0x70, %o3
+ clr %o2
+ tst %g2
+ bne,a 1f
+ mov 8, %o2
+1:
+ b 31f
+ sub %o3, %o2, %o3
+96:
+ and %g1, 3, %g1
+ sll %g4, 2, %g4
+ add %g1, %g4, %o3
+30:
+/* %o1 is dst
+ * %o3 is # bytes to zero out
+ * %o4 is faulting address
+ * %o5 is %pc where fault occurred */
+ clr %o2
+31:
+/* %o0 is src
+ * %o1 is dst
+ * %o2 is # of bytes to copy from src to dst
+ * %o3 is # bytes to zero out
+ * %o4 is faulting address
+ * %o5 is %pc where fault occurred */
+ save %sp, -104, %sp
+ mov %i5, %o0
+ mov %i7, %o1
+ mov %i4, %o2
+ call C_LABEL(lookup_fault)
+ mov %g7, %i4
+ cmp %o0, 2
+ bne 1f
+ add %g0, -EFAULT, %i5
+ tst %i2
+ be 2f
+ mov %i0, %o1
+ mov %i1, %o0
+5:
+ call C_LABEL(__memcpy)
+ mov %i2, %o2
+ tst %o0
+ bne,a 2f
+ add %i3, %i2, %i3
+ add %i1, %i2, %i1
+2:
+ mov %i1, %o0
+6:
+ call C_LABEL(__bzero)
+ mov %i3, %o1
+1:
+ ld [%sp + 168], %o2 ! struct_ptr of parent
+ st %i5, [%o2]
+ ret
+ restore
+
+ .section __ex_table,#alloc
+ .align 4
+ .word 5b,2
+ .word 6b,2
diff --git a/pfinet/linux-src/arch/sparc64/lib/checksum.S b/pfinet/linux-src/arch/sparc64/lib/checksum.S
new file mode 100644
index 00000000..ea732b36
--- /dev/null
+++ b/pfinet/linux-src/arch/sparc64/lib/checksum.S
@@ -0,0 +1,278 @@
+/* checksum.S: Sparc V9 optimized checksum code.
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996 David S. Miller
+ * Copyright(C) 1997 Jakub Jelinek
+ *
+ * derived from:
+ * Linux/Alpha checksum c-code
+ * Linux/ix86 inline checksum assembly
+ * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ * David Mosberger-Tang for optimized reference c-code
+ * BSD4.4 portable checksum routine
+ */
+
+#include <asm/errno.h>
+#include <asm/head.h>
+#include <asm/ptrace.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+
+ /* The problem with the "add with carry" instructions on Ultra
+ * are two fold. Firstly, they cannot pair with jack shit,
+ * and also they only add in the 32-bit carry condition bit
+ * into the accumulated sum. The following is much better.
+ * For larger chunks we use VIS code, which is faster ;)
+ */
+
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
+
+ .text
+ /* I think I have an erection... Once _AGAIN_ the SunSoft
+ * engineers are caught asleep at the keyboard, tsk tsk...
+ */
+
+#define CSUMCOPY_LASTCHUNK(off, t0, t1) \
+ ldxa [%src - off - 0x08] %asi, t0; \
+ ldxa [%src - off - 0x00] %asi, t1; \
+ nop; nop; \
+ addcc t0, %sum, %sum; \
+ stw t0, [%dst - off - 0x04]; \
+ srlx t0, 32, t0; \
+ bcc,pt %xcc, 51f; \
+ stw t0, [%dst - off - 0x08]; \
+ add %sum, 1, %sum; \
+51: addcc t1, %sum, %sum; \
+ stw t1, [%dst - off + 0x04]; \
+ srlx t1, 32, t1; \
+ bcc,pt %xcc, 52f; \
+ stw t1, [%dst - off - 0x00]; \
+ add %sum, 1, %sum; \
+52:
+
+cpc_start:
+cc_end_cruft:
+ andcc %g7, 8, %g0 ! IEU1 Group
+ be,pn %icc, 1f ! CTI
+ and %g7, 4, %g5 ! IEU0
+ ldxa [%src + 0x00] %asi, %g2 ! Load Group
+ add %dst, 8, %dst ! IEU0
+ add %src, 8, %src ! IEU1
+ addcc %g2, %sum, %sum ! IEU1 Group + 2 bubbles
+ stw %g2, [%dst - 0x04] ! Store
+ srlx %g2, 32, %g2 ! IEU0
+ bcc,pt %xcc, 1f ! CTI Group
+ stw %g2, [%dst - 0x08] ! Store
+ add %sum, 1, %sum ! IEU0
+1: brz,pt %g5, 1f ! CTI Group
+ clr %g2 ! IEU0
+ lduwa [%src + 0x00] %asi, %g2 ! Load
+ add %dst, 4, %dst ! IEU0 Group
+ add %src, 4, %src ! IEU1
+ stw %g2, [%dst - 0x04] ! Store Group + 2 bubbles
+ sllx %g2, 32, %g2 ! IEU0
+1: andcc %g7, 2, %g0 ! IEU1
+ be,pn %icc, 1f ! CTI Group
+ clr %o4 ! IEU1
+ lduha [%src + 0x00] %asi, %o4 ! Load
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
+ sth %o4, [%dst - 0x2] ! Store Group + 2 bubbles
+ sll %o4, 16, %o4 ! IEU0
+1: andcc %g7, 1, %g0 ! IEU1
+ be,pn %icc, 1f ! CTI Group
+ clr %o5 ! IEU0
+ lduba [%src + 0x00] %asi, %o5 ! Load
+ stb %o5, [%dst + 0x00] ! Store Group + 2 bubbles
+ sll %o5, 8, %o5 ! IEU0
+1: or %g2, %o4, %o4 ! IEU1
+ or %o5, %o4, %o4 ! IEU0 Group
+ addcc %o4, %sum, %sum ! IEU1
+ bcc,pt %xcc, ccfold ! CTI
+ sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 Group
+ b,pt %xcc, ccfold ! CTI
+ add %sum, 1, %sum ! IEU1
+
+cc_fixit:
+ cmp %len, 6 ! IEU1 Group
+ bl,a,pn %icc, ccte ! CTI
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ andcc %src, 2, %g0 ! IEU1 Group
+ be,pn %icc, 1f ! CTI
+ andcc %src, 0x4, %g0 ! IEU1 Group
+ lduha [%src + 0x00] %asi, %g4 ! Load
+ sub %len, 2, %len ! IEU0
+ add %src, 2, %src ! IEU0 Group
+ add %dst, 2, %dst ! IEU1
+ sll %g4, 16, %g3 ! IEU0 Group + 1 bubble
+ addcc %g3, %sum, %sum ! IEU1
+ bcc,pt %xcc, 0f ! CTI
+ srl %sum, 16, %g3 ! IEU0 Group
+ add %g3, 1, %g3 ! IEU0 4 clocks (mispredict)
+0: andcc %src, 0x4, %g0 ! IEU1 Group
+ sth %g4, [%dst - 0x2] ! Store
+ sll %sum, 16, %sum ! IEU0
+ sll %g3, 16, %g3 ! IEU0 Group
+ srl %sum, 16, %sum ! IEU0 Group
+ or %g3, %sum, %sum ! IEU0 Group (regdep)
+1: be,pt %icc, ccmerge ! CTI
+ andcc %len, 0xf0, %g1 ! IEU1
+ lduwa [%src + 0x00] %asi, %g4 ! Load Group
+ sub %len, 4, %len ! IEU0
+ add %src, 4, %src ! IEU1
+ add %dst, 4, %dst ! IEU0 Group
+ addcc %g4, %sum, %sum ! IEU1 Group + 1 bubble
+ stw %g4, [%dst - 0x4] ! Store
+ bcc,pt %xcc, ccmerge ! CTI
+ andcc %len, 0xf0, %g1 ! IEU1 Group
+ b,pt %xcc, ccmerge ! CTI 4 clocks (mispredict)
+ add %sum, 1, %sum ! IEU0
+
+ .align 32
+ .globl csum_partial_copy_sparc64
+csum_partial_copy_sparc64: /* %o0=src, %o1=dest, %o2=len, %o3=sum */
+ xorcc %src, %dst, %o4 ! IEU1 Group
+ srl %sum, 0, %sum ! IEU0
+ andcc %o4, 3, %g0 ! IEU1 Group
+ srl %len, 0, %len ! IEU0
+ bne,pn %icc, ccslow ! CTI
+ andcc %src, 1, %g0 ! IEU1 Group
+ bne,pn %icc, ccslow ! CTI
+ cmp %len, 256 ! IEU1 Group
+ bgeu,pt %icc, csum_partial_copy_vis ! CTI
+ andcc %src, 7, %g0 ! IEU1 Group
+ bne,pn %icc, cc_fixit ! CTI
+ andcc %len, 0xf0, %g1 ! IEU1 Group
+ccmerge:be,pn %icc, ccte ! CTI
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ sll %g1, 2, %o4 ! IEU0
+13: sethi %hi(12f), %o5 ! IEU0 Group
+ add %src, %g1, %src ! IEU1
+ sub %o5, %o4, %o5 ! IEU0 Group
+ jmpl %o5 + %lo(12f), %g0 ! CTI Group brk forced
+ add %dst, %g1, %dst ! IEU0 Group
+cctbl: CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x98,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x88,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x78,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x68,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x58,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x48,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x38,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x28,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x18,%g2,%g3)
+ CSUMCOPY_LASTCHUNK(0x08,%g2,%g3)
+12:
+ andcc %len, 0xf, %g7 ! IEU1 Group
+ccte: bne,pn %icc, cc_end_cruft ! CTI
+ sethi %uhi(PAGE_OFFSET), %g4 ! IEU0
+ccfold: sllx %sum, 32, %o0 ! IEU0 Group
+ addcc %sum, %o0, %o0 ! IEU1 Group (regdep)
+ srlx %o0, 32, %o0 ! IEU0 Group (regdep)
+ bcs,a,pn %xcc, 1f ! CTI
+ add %o0, 1, %o0 ! IEU1 4 clocks (mispredict)
+1: retl ! CTI Group brk forced
+ sllx %g4, 32, %g4 ! IEU0 Group
+
+ccslow: mov 0, %g5
+ brlez,pn %len, 4f
+ andcc %src, 1, %o5
+ be,a,pt %icc, 1f
+ srl %len, 1, %g7
+ sub %len, 1, %len
+ lduba [%src] %asi, %g5
+ add %src, 1, %src
+ stb %g5, [%dst]
+ srl %len, 1, %g7
+ add %dst, 1, %dst
+1: brz,a,pn %g7, 3f
+ andcc %len, 1, %g0
+ andcc %src, 2, %g0
+ be,a,pt %icc, 1f
+ srl %g7, 1, %g7
+ lduha [%src] %asi, %o4
+ sub %len, 2, %len
+ srl %o4, 8, %g2
+ sub %g7, 1, %g7
+ stb %g2, [%dst]
+ add %o4, %g5, %g5
+ stb %o4, [%dst + 1]
+ add %src, 2, %src
+ srl %g7, 1, %g7
+ add %dst, 2, %dst
+1: brz,a,pn %g7, 2f
+ andcc %len, 2, %g0
+ lduwa [%src] %asi, %o4
+5: srl %o4, 24, %g2
+ srl %o4, 16, %g3
+ stb %g2, [%dst]
+ srl %o4, 8, %g2
+ stb %g3, [%dst + 1]
+ add %src, 4, %src
+ stb %g2, [%dst + 2]
+ addcc %o4, %g5, %g5
+ stb %o4, [%dst + 3]
+ addc %g5, %g0, %g5
+ add %dst, 4, %dst
+ subcc %g7, 1, %g7
+ bne,a,pt %icc, 5b
+ lduwa [%src] %asi, %o4
+ sll %g5, 16, %g2
+ srl %g5, 16, %g5
+ srl %g2, 16, %g2
+ andcc %len, 2, %g0
+ add %g2, %g5, %g5
+2: be,a,pt %icc, 3f
+ andcc %len, 1, %g0
+ lduha [%src] %asi, %o4
+ andcc %len, 1, %g0
+ srl %o4, 8, %g2
+ add %src, 2, %src
+ stb %g2, [%dst]
+ add %g5, %o4, %g5
+ stb %o4, [%dst + 1]
+ add %dst, 2, %dst
+3: be,a,pt %icc, 1f
+ sll %g5, 16, %o4
+ lduba [%src] %asi, %g2
+ sll %g2, 8, %o4
+ stb %g2, [%dst]
+ add %g5, %o4, %g5
+ sll %g5, 16, %o4
+1: addcc %o4, %g5, %g5
+ srl %g5, 16, %o4
+ addc %g0, %o4, %g5
+ brz,pt %o5, 4f
+ srl %g5, 8, %o4
+ and %g5, 0xff, %g2
+ and %o4, 0xff, %o4
+ sll %g2, 8, %g2
+ or %g2, %o4, %g5
+4: addcc %sum, %g5, %sum
+ addc %g0, %sum, %o0
+ retl
+ srl %o0, 0, %o0
+cpc_end:
+
+ .globl cpc_handler
+cpc_handler:
+ ldx [%sp + 0x7ff + 128], %g1
+ sub %g0, EFAULT, %g2
+ brnz,a,pt %g1, 1f
+ st %g2, [%g1]
+1: sethi %uhi(PAGE_OFFSET), %g4
+ retl
+ sllx %g4, 32, %g4
+
+ .section __ex_table
+ .align 4
+ .word cpc_start, 0, cpc_end, cpc_handler
+
diff --git a/pfinet/linux-src/include/asm-alpha/checksum.h b/pfinet/linux-src/include/asm-alpha/checksum.h
new file mode 100644
index 00000000..2f6b82e6
--- /dev/null
+++ b/pfinet/linux-src/include/asm-alpha/checksum.h
@@ -0,0 +1,90 @@
+#ifndef _ALPHA_CHECKSUM_H
+#define _ALPHA_CHECKSUM_H
+
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum);
+
+unsigned int csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
+ unsigned short len, unsigned short proto,
+ unsigned int sum);
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from user space (but on the alpha
+ * we have just one address space, so this is identical to the above)
+ *
+ * this is obsolete and will go away.
+ */
+#define csum_partial_copy_fromuser csum_partial_copy
+
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp);
+
+unsigned int csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum);
+
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+extern unsigned short ip_compute_csum(unsigned char * buff, int len);
+
+/*
+ * Fold a partial checksum without adding pseudo headers
+ */
+
+static inline unsigned short csum_fold(unsigned int sum)
+{
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum = (sum & 0xffff) + (sum >> 16);
+ return ~sum;
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+extern unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u16 len,
+ unsigned short proto,
+ unsigned int sum);
+
+#endif
diff --git a/pfinet/linux-src/include/asm-arm/checksum.h b/pfinet/linux-src/include/asm-arm/checksum.h
new file mode 100644
index 00000000..2323bb5d
--- /dev/null
+++ b/pfinet/linux-src/include/asm-arm/checksum.h
@@ -0,0 +1,162 @@
+/*
+ * linux/include/asm-arm/checksum.h
+ *
+ * IP checksum routines
+ *
+ * Copyright (C) Original authors of ../asm-i386/checksum.h
+ * Copyright (C) 1996,1997,1998 Russell King
+ */
+#ifndef __ASM_ARM_CHECKSUM_H
+#define __ASM_ARM_CHECKSUM_H
+
+#ifndef __ASM_ARM_SEGMENT_H
+#include <asm/segment.h>
+#endif
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+unsigned int
+csum_partial_copy_nocheck(const char *src, char *dst, int len, int sum);
+
+unsigned int
+csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr);
+
+#if 0
+/*
+ * This combination is currently not used, but possible:
+ */
+unsigned int
+csum_partial_copy_to_user(const char *src, char *dst, int len, int sum, int *err_ptr);
+#endif
+
+/*
+ * These are the old (and unsafe) way of doing checksums, a warning message will be
+ * printed if they are used and an exception occurs.
+ *
+ * these functions should go away after some time.
+ */
+#define csum_partial_copy_fromuser csum_partial_copy
+unsigned int
+csum_partial_copy(const char *src, char *dst, int len, int sum);
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ * Converted and optimised for ARM by R. M. King.
+ *
+ * Note: the order that the LDM registers are loaded with respect to
+ * the adc's doesn't matter.
+ */
+static inline unsigned short
+ip_fast_csum(unsigned char * iph, unsigned int ihl)
+{
+ unsigned int sum, tmp1;
+
+ __asm__ __volatile__("
+ sub %2, %2, #5
+ ldr %0, [%1], #4
+ ldr %3, [%1], #4
+ adds %0, %0, %3
+ ldr %3, [%1], #4
+ adcs %0, %0, %3
+ ldr %3, [%1], #4
+ adcs %0, %0, %3
+1: ldr %3, [%1], #4
+ adcs %0, %0, %3
+ tst %2, #15
+ subne %2, %2, #1
+ bne 1b
+ adc %0, %0, #0
+ adds %0, %0, %0, lsl #16
+ addcs %0, %0, #0x10000
+ mvn %0, %0
+ mov %0, %0, lsr #16
+ "
+ : "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (tmp1)
+ : "1" (iph), "2" (ihl));
+ return(sum);
+}
+
+/*
+ * Fold a partial checksum without adding pseudo headers
+ */
+static inline unsigned int
+csum_fold(unsigned int sum)
+{
+ __asm__("
+ adds %0, %0, %0, lsl #16
+ addcs %0, %0, #0x10000"
+ : "=r" (sum)
+ : "0" (sum));
+ return (~sum) >> 16;
+}
+
+static inline unsigned long
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
+ unsigned short proto, unsigned int sum)
+{
+ __asm__("
+ adds %0, %0, %1
+ adcs %0, %0, %2
+ adcs %0, %0, %3
+ adc %0, %0, #0"
+ : "=&r"(sum)
+ : "r" (daddr), "r" (saddr), "r" ((ntohs(len)<<16)+proto*256), "0" (sum));
+ return sum;
+}
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
+ unsigned short proto, unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
+}
+
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline unsigned short
+ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold(csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+extern unsigned long
+__csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u32 len,
+ __u32 proto, unsigned int sum);
+
+extern __inline__ unsigned short int
+csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u16 len,
+ unsigned short proto, unsigned int sum)
+{
+ return csum_fold(__csum_ipv6_magic(saddr, daddr, htonl((__u32)len),
+ htonl(proto), sum));
+}
+#endif
diff --git a/pfinet/linux-src/include/asm-i386/checksum.h b/pfinet/linux-src/include/asm-i386/checksum.h
new file mode 100644
index 00000000..add89590
--- /dev/null
+++ b/pfinet/linux-src/include/asm-i386/checksum.h
@@ -0,0 +1,211 @@
+#ifndef _I386_CHECKSUM_H
+#define _I386_CHECKSUM_H
+
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+ int *src_err_ptr, int *dst_err_ptr);
+
+/*
+ * Note: when you get a NULL pointer exception here this means someone
+ * passed in an incorrect kernel address to one of these functions.
+ *
+ * If you use these functions directly please don't forget the
+ * verify_area().
+ */
+extern __inline__
+unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+ int len, int sum)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+}
+
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
+}
+
+#if 0
+
+/* Not used at the moment. It is difficult to imagine for what purpose
+ it can be used :-) Please, do not forget to verify_area before it --ANK
+ */
+
+/*
+ * This combination is currently not used, but possible:
+ */
+
+extern __inline__
+unsigned int csum_partial_copy_to_user ( const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, NULL, err_ptr);
+}
+#endif
+
+/*
+ * These are the old (and unsafe) way of doing checksums, a warning message will be
+ * printed if they are used and an exeption occurs.
+ *
+ * these functions should go away after some time.
+ */
+
+#define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
+ * Arnt Gulbrandsen.
+ */
+static inline unsigned short ip_fast_csum(unsigned char * iph,
+ unsigned int ihl) {
+ unsigned int sum;
+
+ __asm__ __volatile__(
+" movl (%1), %0\n"
+" subl $4, %2\n"
+" jbe 2f\n"
+" addl 4(%1), %0\n"
+" adcl 8(%1), %0\n"
+" adcl 12(%1), %0\n"
+"1: adcl 16(%1), %0\n"
+" lea 4(%1), %1\n"
+" decl %2\n"
+" jne 1b\n"
+" adcl $0, %0\n"
+" movl %0, %2\n"
+" shrl $16, %0\n"
+" addw %w2, %w0\n"
+" adcl $0, %0\n"
+" notl %0\n"
+"2:"
+ /* Since the input registers which are loaded with iph and ipl
+ 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)
+ : "memory");
+ return(sum);
+}
+
+/*
+ * Fold a partial checksum
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+ __asm__("addl %1, %0\n"
+ "adcl $0xffff, %0\n"
+ : "=r" (sum)
+ : "r" (sum << 16), "0" (sum & 0xffff0000)
+ );
+ return (~sum) >> 16;
+}
+
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__(
+ "addl %1, %0\n"
+ "adcl %2, %0\n"
+ "adcl %3, %0\n"
+ "adcl $0, %0\n"
+ : "=r" (sum)
+ : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
+ return csum_fold (csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u16 len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__("addl 0(%1), %0\n"
+ "adcl 4(%1), %0\n"
+ "adcl 8(%1), %0\n"
+ "adcl 12(%1), %0\n"
+ "adcl 0(%2), %0\n"
+ "adcl 4(%2), %0\n"
+ "adcl 8(%2), %0\n"
+ "adcl 12(%2), %0\n"
+ "adcl %3, %0\n"
+ "adcl %4, %0\n"
+ "adcl $0, %0\n"
+ : "=&r" (sum)
+ : "r" (saddr), "r" (daddr),
+ "r"(htonl((__u32) (len))), "r"(htonl(proto)), "0"(sum)
+ : "memory");
+
+ return csum_fold(sum);
+}
+
+/*
+ * Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ if (access_ok(VERIFY_WRITE, dst, len))
+ return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+
+ if (len)
+ *err_ptr = -EFAULT;
+
+ return -1; /* invalid checksum */
+}
+
+#endif
diff --git a/pfinet/linux-src/include/asm-m68k/checksum.h b/pfinet/linux-src/include/asm-m68k/checksum.h
new file mode 100644
index 00000000..f5236490
--- /dev/null
+++ b/pfinet/linux-src/include/asm-m68k/checksum.h
@@ -0,0 +1,154 @@
+#ifndef _M68K_CHECKSUM_H
+#define _M68K_CHECKSUM_H
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
+
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern unsigned int csum_partial_copy_from_user(const char *src, char *dst,
+ int len, int sum, int *csum_err);
+
+#define csum_partial_copy_nocheck(src, dst, len, sum) \
+ csum_partial_copy((src), (dst), (len), (sum))
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ */
+static inline unsigned short
+ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+ unsigned int sum = 0;
+
+ __asm__ ("subqw #1,%2\n"
+ "1:\t"
+ "movel %1@+,%/d0\n\t"
+ "addxl %/d0,%0\n\t"
+ "dbra %2,1b\n\t"
+ "movel %0,%/d0\n\t"
+ "swap %/d0\n\t"
+ "addxw %/d0,%0\n\t"
+ "clrw %/d0\n\t"
+ "addxw %/d0,%0\n\t"
+ : "=d" (sum), "=a" (iph), "=d" (ihl)
+ : "0" (sum), "1" (iph), "2" (ihl)
+ : "d0");
+ return ~sum;
+}
+
+/*
+ * Fold a partial checksum
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+ unsigned int tmp = sum;
+ __asm__("swap %1\n\t"
+ "addw %1, %0\n\t"
+ "clrw %1\n\t"
+ "addxw %1, %0"
+ : "=&d" (sum), "=&d" (tmp)
+ : "0" (sum), "1" (sum));
+ return ~sum;
+}
+
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+static inline unsigned int
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
+ unsigned short proto, unsigned int sum)
+{
+ __asm__ ("addl %1,%0\n\t"
+ "addxl %4,%0\n\t"
+ "addxl %5,%0\n\t"
+ "clrl %1\n\t"
+ "addxl %1,%0"
+ : "=&d" (sum), "=&d" (saddr)
+ : "0" (daddr), "1" (saddr), "d" (len + proto),
+ "d"(sum));
+ return sum;
+}
+
+static inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
+ unsigned short proto, unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static inline unsigned short
+ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold (csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ unsigned short int
+csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
+ __u16 len, unsigned short proto, unsigned int sum)
+{
+ register unsigned long tmp;
+ __asm__("addl %2@,%0\n\t"
+ "movel %2@(4),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %2@(8),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %2@(12),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@,%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@(4),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@(8),%1\n\t"
+ "addxl %1,%0\n\t"
+ "movel %3@(12),%1\n\t"
+ "addxl %1,%0\n\t"
+ "addxl %4,%0\n\t"
+ "clrl %1\n\t"
+ "addxl %1,%0"
+ : "=&d" (sum), "=&d" (tmp)
+ : "a" (saddr), "a" (daddr), "d" ((__u32) len + proto),
+ "0" (sum));
+
+ return csum_fold(sum);
+}
+
+#endif /* _M68K_CHECKSUM_H */
diff --git a/pfinet/linux-src/include/asm-mips/checksum.h b/pfinet/linux-src/include/asm-mips/checksum.h
new file mode 100644
index 00000000..6d3700f0
--- /dev/null
+++ b/pfinet/linux-src/include/asm-mips/checksum.h
@@ -0,0 +1,255 @@
+/* $Id: checksum.h,v 1.6 1998/09/19 19:19:36 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_CHECKSUM_H
+#define __ASM_MIPS_CHECKSUM_H
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ */
+#define csum_partial_copy_nocheck csum_partial_copy
+
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len,
+ unsigned int sum, int *errp);
+
+#define HAVE_CSUM_COPY_USER
+unsigned int csum_and_copy_to_user (const char *src, char *dst,
+ int len, int sum, int *err_ptr);
+
+/*
+ * the same as csum_partial, but copies from user space (but on MIPS
+ * we have just one address space, so this is identical to the above)
+ *
+ * this is obsolete and will go away.
+ */
+#define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum);
+
+/*
+ * Fold a partial checksum without adding pseudo headers
+ */
+static inline unsigned short int csum_fold(unsigned int sum)
+{
+ __asm__("
+ .set noat
+ sll $1,%0,16
+ addu %0,$1
+ sltu $1,%0,$1
+ srl %0,%0,16
+ addu %0,$1
+ xori %0,0xffff
+ .set at"
+ : "=r" (sum)
+ : "0" (sum)
+ : "$1");
+
+ return sum;
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
+ * Arnt Gulbrandsen.
+ */
+static inline unsigned short ip_fast_csum(unsigned char * iph,
+ unsigned int ihl)
+{
+ unsigned int sum;
+ unsigned long dummy;
+
+ /*
+ * This is for 32-bit MIPS processors.
+ */
+ __asm__ __volatile__("
+ .set noreorder
+ .set noat
+ lw %0,(%1)
+ subu %2,4
+ #blez %2,2f
+ sll %2,2 # delay slot
+
+ lw %3,4(%1)
+ addu %2,%1 # delay slot
+ addu %0,%3
+ sltu $1,%0,%3
+ lw %3,8(%1)
+ addu %0,$1
+ addu %0,%3
+ sltu $1,%0,%3
+ lw %3,12(%1)
+ addu %0,$1
+ addu %0,%3
+ sltu $1,%0,%3
+ addu %0,$1
+
+1: lw %3,16(%1)
+ addiu %1,4
+ addu %0,%3
+ sltu $1,%0,%3
+ bne %2,%1,1b
+ addu %0,$1 # delay slot
+
+2: .set at
+ .set reorder"
+ : "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (dummy)
+ : "1" (iph), "2" (ihl)
+ : "$1");
+
+ return csum_fold(sum);
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__("
+ .set noat
+ addu %0,%2
+ sltu $1,%0,%2
+ addu %0,$1
+
+ addu %0,%3
+ sltu $1,%0,%3
+ addu %0,$1
+
+ addu %0,%4
+ sltu $1,%0,%4
+ addu %0,$1
+ .set at"
+ : "=r" (sum)
+ : "0" (daddr), "r"(saddr),
+#ifdef __MIPSEL__
+ "r" ((ntohs(len)<<16)+proto*256),
+#else
+ "r" (((proto)<<16)+len),
+#endif
+ "r"(sum)
+ : "$1");
+
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold(csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u16 len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__("
+ .set noreorder
+ .set noat
+ addu %0,%5 # proto (long in network byte order)
+ sltu $1,%0,%5
+ addu %0,$1
+
+ addu %0,%6 # csum
+ sltu $1,%0,%6
+ lw %1,0(%2) # four words source address
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+
+ lw %1,4(%2)
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+
+ lw %1,8(%2)
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+
+ lw %1,12(%2)
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+
+ lw %1,0(%3)
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+
+ lw %1,4(%3)
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+
+ lw %1,8(%3)
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+
+ lw %1,12(%3)
+ addu %0,$1
+ addu %0,%1
+ sltu $1,%0,$1
+ .set noat
+ .set noreorder"
+ : "=r" (sum),
+ "=r" (proto)
+ : "r" (saddr),
+ "r" (daddr),
+ "0" (htonl((__u32) (len))),
+ "1" (htonl(proto)),
+ "r"(sum)
+ : "$1");
+
+ return csum_fold(sum);
+}
+
+#endif /* __ASM_MIPS_CHECKSUM_H */
diff --git a/pfinet/linux-src/include/asm-ppc/checksum.h b/pfinet/linux-src/include/asm-ppc/checksum.h
new file mode 100644
index 00000000..e635ff59
--- /dev/null
+++ b/pfinet/linux-src/include/asm-ppc/checksum.h
@@ -0,0 +1,113 @@
+#ifndef _PPC_CHECKSUM_H
+#define _PPC_CHECKSUM_H
+
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern unsigned int csum_partial(const unsigned char * buff, int len,
+ unsigned int sum);
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively (if that pointer is not
+ * NULL), and, for an error on src, zeroes the rest of dst.
+ *
+ * Like csum_partial, this must be called with even lengths,
+ * except for the last fragment.
+ */
+extern unsigned int csum_partial_copy_generic(const char *src, char *dst,
+ int len, unsigned int sum,
+ int *src_err, int *dst_err);
+
+#define csum_partial_copy_from_user(src, dst, len, sum, errp) \
+ csum_partial_copy_generic((src), (dst), (len), (sum), (errp), 0)
+
+/* FIXME: this needs to be written to really do no check -- Cort */
+#define csum_partial_copy_nocheck(src, dst, len, sum) \
+ csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+/*
+ * Old versions which ignore errors.
+ */
+#define csum_partial_copy(src, dst, len, sum) \
+ csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+#define csum_partial_copy_fromuser(src, dst, len, sum) \
+ csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+
+
+/*
+ * turns a 32-bit partial checksum (e.g. from csum_partial) into a
+ * 1's complement 16-bit checksum.
+ */
+static inline unsigned int csum_fold(unsigned int sum)
+{
+ unsigned int tmp;
+
+ /* swap the two 16-bit halves of sum */
+ __asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum));
+ /* if there is a carry from adding the two 16-bit halves,
+ it will carry from the lower half into the upper half,
+ giving us the correct sum in the upper half. */
+ sum = ~(sum + tmp) >> 16;
+ return sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold(csum_partial(buff, len, 0));
+}
+
+/*
+ * FIXME: I swiped this one from the sparc and made minor modifications.
+ * It may not be correct. -- Cort
+ */
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__("
+ addc %0,%0,%1
+ adde %0,%0,%2
+ adde %0,%0,%3
+ addze %0,%0
+ "
+ : "=r" (sum)
+ : "r" (daddr), "r"(saddr), "r"((proto<<16)+len), "0"(sum));
+ return sum;
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries. ihl is the number
+ * of 32-bit words and is always >= 5.
+ */
+extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern unsigned short csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum);
+
+#endif
diff --git a/pfinet/linux-src/include/asm-s390/checksum.h b/pfinet/linux-src/include/asm-s390/checksum.h
new file mode 100644
index 00000000..487ccc99
--- /dev/null
+++ b/pfinet/linux-src/include/asm-s390/checksum.h
@@ -0,0 +1,188 @@
+#ifndef _S390_CHECKSUM_H
+#define _S390_CHECKSUM_H
+
+/*
+ * include/asm-s390/checksum.h
+ * S390 fast network checksum routines
+ * see also arch/S390/lib/checksum.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Ulrich Hild (first version)
+ * Martin Schwidefsky (heavily optimized CKSM version)
+ * D.J. Barrow (third attempt)
+ */
+
+#include <asm/uaccess.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int
+csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * csum_partial as an inline function
+ */
+extern inline unsigned int
+csum_partial_inline(const unsigned char * buff, int len, unsigned int sum)
+{
+ __asm__ __volatile__ (
+ " lr 2,%1\n" /* address in gpr 2 */
+ " lr 3,%2\n" /* length in gpr 3 */
+ "0: cksm %0,2\n" /* do checksum on longs */
+ " jo 0b\n"
+ : "+&d" (sum)
+ : "d" (buff), "d" (len)
+ : "cc", "2", "3" );
+ return sum;
+}
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern inline unsigned int
+csum_partial_copy(const char *src, char *dst, int len,unsigned int sum)
+{
+ memcpy(dst,src,len);
+ return csum_partial_inline(dst, len, sum);
+}
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern inline unsigned int
+csum_partial_copy_from_user(const char *src, char *dst,
+ int len, unsigned int sum, int *errp)
+{
+ if (copy_from_user(dst, src, len)) {
+ *errp = -EFAULT;
+ memset(dst, 0, len);
+ return sum;
+ }
+ return csum_partial(dst, len, sum);
+}
+
+extern inline unsigned int
+csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
+{
+ memcpy(dst,src,len);
+ return csum_partial_inline(dst, len, sum);
+}
+
+/*
+ * Fold a partial checksum without adding pseudo headers
+ */
+#if 1
+unsigned short csum_fold(unsigned int sum);
+#else
+extern inline unsigned short
+csum_fold(unsigned int sum)
+{
+ __asm__ __volatile__ (
+ " sr 3,3\n" /* %0 = H*65536 + L */
+ " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */
+ " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */
+ " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */
+ " alr %0,2\n" /* %0 = H+L+C L+H */
+ " srl %0,16\n" /* %0 = H+L+C */
+ : "+&d" (sum) : : "cc", "2", "3");
+ return ((unsigned short) ~sum);
+}
+#endif
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ */
+extern inline unsigned short
+ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+ unsigned long sum;
+
+ __asm__ __volatile__ (
+ " sr %0,%0\n" /* set sum to zero */
+ " lr 2,%1\n" /* address in gpr 2 */
+ " lr 3,%2\n" /* length in gpr 3 */
+ "0: cksm %0,2\n" /* do checksum on longs */
+ " jo 0b\n"
+ : "=&d" (sum)
+ : "d" (iph), "d" (ihl*4)
+ : "cc", "2", "3" );
+ return csum_fold(sum);
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 32-bit checksum
+ */
+extern inline unsigned int
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
+ unsigned short len, unsigned short proto,
+ unsigned int sum)
+{
+ __asm__ __volatile__ (
+ " sll %3,16\n"
+ " or %3,%4\n" /* newproto=proto<<16 in hiword, len in lowword */
+ " alr %1,%2\n" /* saddr+=daddr */
+ " brc 12,0f\n"
+ " ahi %1,1\n" /* add carry */
+ "0: alr %1,%3\n" /* add saddr+=newproto */
+ " brc 12,1f\n"
+ " ahi %1,1\n" /* add carry again */
+ "1: alr %0,%1\n" /* sum+=saddr */
+ " brc 12,2f\n"
+ " ahi %0,1\n" /* add carry again */
+ "2:"
+ : "+&d" (sum)
+ : "d" (saddr), "d" (daddr), "d" (proto), "d" (len)
+ : "cc" );
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+extern inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
+ unsigned short len, unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+extern inline unsigned short
+ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold(csum_partial(buff, len, 0));
+}
+
+#endif /* _S390_CHECKSUM_H */
+
+
diff --git a/pfinet/linux-src/include/asm-sparc/checksum.h b/pfinet/linux-src/include/asm-sparc/checksum.h
new file mode 100644
index 00000000..e552cfc6
--- /dev/null
+++ b/pfinet/linux-src/include/asm-sparc/checksum.h
@@ -0,0 +1,252 @@
+/* $Id: checksum.h,v 1.29 1999/03/21 05:22:07 davem Exp $ */
+#ifndef __SPARC_CHECKSUM_H
+#define __SPARC_CHECKSUM_H
+
+/* checksum.h: IP/UDP/TCP checksum routines on the Sparc.
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996 David S. Miller
+ * Copyright(C) 1996 Eddie C. Dost
+ * Copyright(C) 1997 Jakub Jelinek
+ *
+ * derived from:
+ * Alpha checksum c-code
+ * ix86 inline assembly
+ * RFC1071 Computing the Internet Checksum
+ */
+
+#include <asm/uaccess.h>
+#include <asm/cprefix.h>
+
+/* computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum);
+
+/* the same as csum_partial, but copies from fs:src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+/* FIXME: Remove these two macros ASAP */
+#define csum_partial_copy(src, dst, len, sum) \
+ csum_partial_copy_nocheck(src,dst,len,sum)
+#define csum_partial_copy_fromuser(s, d, l, w) \
+ csum_partial_copy((char *) (s), (d), (l), (w))
+
+extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
+
+extern __inline__ unsigned int
+csum_partial_copy_nocheck (const char *src, char *dst, int len,
+ unsigned int sum)
+{
+ register unsigned int ret asm("o0") = (unsigned int)src;
+ register char *d asm("o1") = dst;
+ register int l asm("g1") = len;
+
+ __asm__ __volatile__ ("
+ call " C_LABEL_STR(__csum_partial_copy_sparc_generic) "
+ mov %4, %%g7
+ " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) :
+ "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+ return ret;
+}
+
+extern __inline__ unsigned int
+csum_partial_copy_from_user(const char *src, char *dst, int len,
+ unsigned int sum, int *err)
+ {
+ if (!access_ok (VERIFY_READ, src, len)) {
+ *err = -EFAULT;
+ memset (dst, 0, len);
+ return sum;
+ } else {
+ register unsigned int ret asm("o0") = (unsigned int)src;
+ register char *d asm("o1") = dst;
+ register int l asm("g1") = len;
+ register unsigned int s asm("g7") = sum;
+
+ __asm__ __volatile__ ("
+ .section __ex_table,#alloc
+ .align 4
+ .word 1f,2
+ .previous
+1:
+ call " C_LABEL_STR(__csum_partial_copy_sparc_generic) "
+ st %5, [%%sp + 64]
+ " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
+ "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+ return ret;
+ }
+ }
+
+extern __inline__ unsigned int
+csum_partial_copy_to_user(const char *src, char *dst, int len,
+ unsigned int sum, int *err)
+{
+ if (!access_ok (VERIFY_WRITE, dst, len)) {
+ *err = -EFAULT;
+ return sum;
+ } else {
+ register unsigned int ret asm("o0") = (unsigned int)src;
+ register char *d asm("o1") = dst;
+ register int l asm("g1") = len;
+ register unsigned int s asm("g7") = sum;
+
+ __asm__ __volatile__ ("
+ .section __ex_table,#alloc
+ .align 4
+ .word 1f,1
+ .previous
+1:
+ call " C_LABEL_STR(__csum_partial_copy_sparc_generic) "
+ st %5, [%%sp + 64]
+ " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
+ "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+ return ret;
+ }
+}
+
+#define HAVE_CSUM_COPY_USER
+#define csum_and_copy_to_user csum_partial_copy_to_user
+
+/* ihl is always 5 or greater, almost always is 5, and iph is word aligned
+ * the majority of the time.
+ */
+extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
+ unsigned int ihl)
+{
+ unsigned short sum;
+
+ /* Note: We must read %2 before we touch %0 for the first time,
+ * because GCC can legitimately use the same register for
+ * both operands.
+ */
+ __asm__ __volatile__("sub\t%2, 4, %%g4\n\t"
+ "ld\t[%1 + 0x00], %0\n\t"
+ "ld\t[%1 + 0x04], %%g2\n\t"
+ "ld\t[%1 + 0x08], %%g3\n\t"
+ "addcc\t%%g2, %0, %0\n\t"
+ "addxcc\t%%g3, %0, %0\n\t"
+ "ld\t[%1 + 0x0c], %%g2\n\t"
+ "ld\t[%1 + 0x10], %%g3\n\t"
+ "addxcc\t%%g2, %0, %0\n\t"
+ "addx\t%0, %%g0, %0\n"
+ "1:\taddcc\t%%g3, %0, %0\n\t"
+ "add\t%1, 4, %1\n\t"
+ "addxcc\t%0, %%g0, %0\n\t"
+ "subcc\t%%g4, 1, %%g4\n\t"
+ "be,a\t2f\n\t"
+ "sll\t%0, 16, %%g2\n\t"
+ "b\t1b\n\t"
+ "ld\t[%1 + 0x10], %%g3\n"
+ "2:\taddcc\t%0, %%g2, %%g2\n\t"
+ "srl\t%%g2, 16, %0\n\t"
+ "addx\t%0, %%g0, %0\n\t"
+ "xnor\t%%g0, %0, %0"
+ : "=r" (sum), "=&r" (iph)
+ : "r" (ihl), "1" (iph)
+ : "g2", "g3", "g4", "cc");
+ return sum;
+}
+
+/* Fold a partial checksum without adding pseudo headers. */
+extern __inline__ unsigned int csum_fold(unsigned int sum)
+{
+ unsigned int tmp;
+
+ __asm__ __volatile__("addcc\t%0, %1, %1\n\t"
+ "srl\t%1, 16, %1\n\t"
+ "addx\t%1, %%g0, %1\n\t"
+ "xnor\t%%g0, %1, %0"
+ : "=&r" (sum), "=r" (tmp)
+ : "0" (sum), "1" (sum<<16)
+ : "cc");
+ return sum;
+}
+
+extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned int len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__ __volatile__("addcc\t%1, %0, %0\n\t"
+ "addxcc\t%2, %0, %0\n\t"
+ "addxcc\t%3, %0, %0\n\t"
+ "addx\t%0, %%g0, %0\n\t"
+ : "=r" (sum), "=r" (saddr)
+ : "r" (daddr), "r" ((proto<<16)+len), "0" (sum),
+ "1" (saddr)
+ : "cc");
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u16 len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__ __volatile__ ("
+ addcc %3, %4, %%g4
+ addxcc %5, %%g4, %%g4
+ ld [%2 + 0x0c], %%g2
+ ld [%2 + 0x08], %%g3
+ addxcc %%g2, %%g4, %%g4
+ ld [%2 + 0x04], %%g2
+ addxcc %%g3, %%g4, %%g4
+ ld [%2 + 0x00], %%g3
+ addxcc %%g2, %%g4, %%g4
+ ld [%1 + 0x0c], %%g2
+ addxcc %%g3, %%g4, %%g4
+ ld [%1 + 0x08], %%g3
+ addxcc %%g2, %%g4, %%g4
+ ld [%1 + 0x04], %%g2
+ addxcc %%g3, %%g4, %%g4
+ ld [%1 + 0x00], %%g3
+ addxcc %%g2, %%g4, %%g4
+ addxcc %%g3, %%g4, %0
+ addx 0, %0, %0
+ "
+ : "=&r" (sum)
+ : "r" (saddr), "r" (daddr),
+ "r"(htonl((__u32) (len))), "r"(htonl(proto)), "r"(sum)
+ : "g2", "g3", "g4", "cc");
+
+ return csum_fold(sum);
+}
+
+/* this routine is used for miscellaneous IP-like checksums, mainly in icmp.c */
+extern __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold(csum_partial(buff, len, 0));
+}
+
+#endif /* !(__SPARC_CHECKSUM_H) */
diff --git a/pfinet/linux-src/include/asm-sparc64/checksum.h b/pfinet/linux-src/include/asm-sparc64/checksum.h
new file mode 100644
index 00000000..e3da2651
--- /dev/null
+++ b/pfinet/linux-src/include/asm-sparc64/checksum.h
@@ -0,0 +1,207 @@
+/* $Id: checksum.h,v 1.11 1998/04/17 02:37:22 davem Exp $ */
+#ifndef __SPARC64_CHECKSUM_H
+#define __SPARC64_CHECKSUM_H
+
+/* checksum.h: IP/UDP/TCP checksum routines on the V9.
+ *
+ * Copyright(C) 1995 Linus Torvalds
+ * Copyright(C) 1995 Miguel de Icaza
+ * Copyright(C) 1996 David S. Miller
+ * Copyright(C) 1996 Eddie C. Dost
+ * Copyright(C) 1997 Jakub Jelinek
+ *
+ * derived from:
+ * Alpha checksum c-code
+ * ix86 inline assembly
+ * RFC1071 Computing the Internet Checksum
+ */
+
+#include <asm/uaccess.h>
+
+/* computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum);
+
+/* the same as csum_partial, but copies from user space while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+/* FIXME: Remove these macros ASAP */
+#define csum_partial_copy(src, dst, len, sum) \
+ csum_partial_copy_nocheck(src,dst,len,sum)
+#define csum_partial_copy_fromuser(s, d, l, w) \
+ csum_partial_copy_from_user((char *) (s), (d), (l), (w), NULL)
+
+extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst, int len, unsigned int sum);
+
+extern __inline__ unsigned int
+csum_partial_copy_nocheck (const char *src, char *dst, int len,
+ unsigned int sum)
+{
+ __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_P));
+ return csum_partial_copy_sparc64(src, dst, len, sum);
+}
+
+extern __inline__ unsigned int
+csum_partial_copy_from_user(const char *src, char *dst, int len,
+ unsigned int sum, int *err)
+{
+ __asm__ __volatile__ ("wr %%g0, %0, %%asi
+ stx %1, [%%sp + 0x7ff + 128]
+ " : : "i" (ASI_S), "r" (err));
+ return csum_partial_copy_sparc64(src, dst, len, sum);
+}
+
+#if 0
+/* Not implemented, but nobody uses it yet... */
+extern __inline__ unsigned int
+csum_partial_copy_to_user(const char *src, char *dst, int len,
+ unsigned int sum, int *err)
+{
+ return 0;
+}
+#endif
+
+/* ihl is always 5 or greater, almost always is 5, and iph is word aligned
+ * the majority of the time.
+ */
+extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
+ unsigned int ihl)
+{
+ unsigned short sum;
+
+ /* Note: We must read %2 before we touch %0 for the first time,
+ * because GCC can legitimately use the same register for
+ * both operands.
+ */
+ __asm__ __volatile__("
+ sub %2, 4, %%g7 ! IEU0
+ lduw [%1 + 0x00], %0 ! Load Group
+ lduw [%1 + 0x04], %%g2 ! Load Group
+ lduw [%1 + 0x08], %%g3 ! Load Group
+ addcc %%g2, %0, %0 ! IEU1 1 Load Bubble + Group
+ lduw [%1 + 0x0c], %%g2 ! Load
+ addccc %%g3, %0, %0 ! Sngle Group no Bubble
+ lduw [%1 + 0x10], %%g3 ! Load Group
+ addccc %%g2, %0, %0 ! Sngle Group no Bubble
+ addc %0, %%g0, %0 ! Sngle Group
+1: addcc %%g3, %0, %0 ! IEU1 Group no Bubble
+ add %1, 4, %1 ! IEU0
+ addccc %0, %%g0, %0 ! Sngle Group no Bubble
+ subcc %%g7, 1, %%g7 ! IEU1 Group
+ be,a,pt %%icc, 2f ! CTI
+ sll %0, 16, %%g2 ! IEU0
+ lduw [%1 + 0x10], %%g3 ! Load Group
+ ba,pt %%xcc, 1b ! CTI
+ nop ! IEU0
+2: addcc %0, %%g2, %%g2 ! IEU1 Group
+ srl %%g2, 16, %0 ! IEU0 Group regdep XXX Scheisse!
+ addc %0, %%g0, %0 ! Sngle Group
+ xnor %%g0, %0, %0 ! IEU0 Group
+ srl %0, 0, %0 ! IEU0 Group XXX Scheisse!
+" : "=r" (sum), "=&r" (iph)
+ : "r" (ihl), "1" (iph)
+ : "g2", "g3", "g7", "cc");
+ return sum;
+}
+
+/* Fold a partial checksum without adding pseudo headers. */
+extern __inline__ unsigned short csum_fold(unsigned int sum)
+{
+ unsigned int tmp;
+
+ __asm__ __volatile__("
+ addcc %0, %1, %1
+ srl %1, 16, %1
+ addc %1, %%g0, %1
+ xnor %%g0, %1, %0
+" : "=&r" (sum), "=r" (tmp)
+ : "0" (sum), "1" (sum<<16)
+ : "cc");
+ return (sum & 0xffff);
+}
+
+extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned int len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__ __volatile__("
+ addcc %1, %0, %0
+ addccc %2, %0, %0
+ addccc %3, %0, %0
+ addc %0, %%g0, %0
+" : "=r" (sum), "=r" (saddr)
+ : "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr)
+ : "cc");
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u16 len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__ __volatile__ ("
+ addcc %3, %4, %%g7
+ addccc %5, %%g7, %%g7
+ lduw [%2 + 0x0c], %%g2
+ lduw [%2 + 0x08], %%g3
+ addccc %%g2, %%g7, %%g7
+ lduw [%2 + 0x04], %%g2
+ addccc %%g3, %%g7, %%g7
+ lduw [%2 + 0x00], %%g3
+ addccc %%g2, %%g7, %%g7
+ lduw [%1 + 0x0c], %%g2
+ addccc %%g3, %%g7, %%g7
+ lduw [%1 + 0x08], %%g3
+ addccc %%g2, %%g7, %%g7
+ lduw [%1 + 0x04], %%g2
+ addccc %%g3, %%g7, %%g7
+ lduw [%1 + 0x00], %%g3
+ addccc %%g2, %%g7, %%g7
+ addccc %%g3, %%g7, %0
+ addc 0, %0, %0
+" : "=&r" (sum)
+ : "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))),
+ "r"(htonl(proto)), "r"(sum)
+ : "g2", "g3", "g7", "cc");
+
+ return csum_fold(sum);
+}
+
+/* this routine is used for miscellaneous IP-like checksums, mainly in icmp.c */
+extern __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold(csum_partial(buff, len, 0));
+}
+
+#endif /* !(__SPARC64_CHECKSUM_H) */
diff --git a/pfinet/linux-src/include/linux/a.out.h b/pfinet/linux-src/include/linux/a.out.h
new file mode 100644
index 00000000..af8a1dfa
--- /dev/null
+++ b/pfinet/linux-src/include/linux/a.out.h
@@ -0,0 +1,268 @@
+#ifndef __A_OUT_GNU_H__
+#define __A_OUT_GNU_H__
+
+#define __GNU_EXEC_MACROS__
+
+#ifndef __STRUCT_EXEC_OVERRIDE__
+
+#include <asm/a.out.h>
+
+#endif /* __STRUCT_EXEC_OVERRIDE__ */
+
+/* these go in the N_MACHTYPE field */
+enum machine_type {
+#if defined (M_OLDSUN2)
+ M__OLDSUN2 = M_OLDSUN2,
+#else
+ M_OLDSUN2 = 0,
+#endif
+#if defined (M_68010)
+ M__68010 = M_68010,
+#else
+ M_68010 = 1,
+#endif
+#if defined (M_68020)
+ M__68020 = M_68020,
+#else
+ M_68020 = 2,
+#endif
+#if defined (M_SPARC)
+ M__SPARC = M_SPARC,
+#else
+ M_SPARC = 3,
+#endif
+ /* skip a bunch so we don't run into any of sun's numbers */
+ M_386 = 100,
+ M_MIPS1 = 151, /* MIPS R3000/R3000 binary */
+ M_MIPS2 = 152 /* MIPS R6000/R4000 binary */
+};
+
+#if !defined (N_MAGIC)
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#define N_SET_INFO(exec, magic, type, flags) \
+ ((exec).a_info = ((magic) & 0xffff) \
+ | (((int)(type) & 0xff) << 16) \
+ | (((flags) & 0xff) << 24))
+#define N_SET_MAGIC(exec, magic) \
+ ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+
+#define N_SET_MACHTYPE(exec, machtype) \
+ ((exec).a_info = \
+ ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+
+#define N_SET_FLAGS(exec, flags) \
+ ((exec).a_info = \
+ ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+
+/* Code indicating object file or impure executable. */
+#define OMAGIC 0407
+/* Code indicating pure executable. */
+#define NMAGIC 0410
+/* Code indicating demand-paged executable. */
+#define ZMAGIC 0413
+/* This indicates a demand-paged executable with the header in the text.
+ The first page is unmapped to help trap NULL pointer references */
+#define QMAGIC 0314
+
+/* Code indicating core file. */
+#define CMAGIC 0421
+
+#if !defined (N_BADMAG)
+#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
+ && N_MAGIC(x) != NMAGIC \
+ && N_MAGIC(x) != ZMAGIC \
+ && N_MAGIC(x) != QMAGIC)
+#endif
+
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+
+#if !defined (N_TXTOFF)
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
+ (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#endif
+
+#if !defined (N_DATOFF)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#endif
+
+#if !defined (N_TRELOFF)
+#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
+#endif
+
+#if !defined (N_DRELOFF)
+#define N_DRELOFF(x) (N_TRELOFF(x) + N_TRSIZE(x))
+#endif
+
+#if !defined (N_SYMOFF)
+#define N_SYMOFF(x) (N_DRELOFF(x) + N_DRSIZE(x))
+#endif
+
+#if !defined (N_STROFF)
+#define N_STROFF(x) (N_SYMOFF(x) + N_SYMSIZE(x))
+#endif
+
+/* Address of text segment in memory after it is loaded. */
+#if !defined (N_TXTADDR)
+#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? PAGE_SIZE : 0)
+#endif
+
+/* Address of data segment in memory after it is loaded.
+ Note that it is up to you to define SEGMENT_SIZE
+ on machines not listed here. */
+#if defined(vax) || defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE page_size
+#endif
+#ifdef sony
+#define SEGMENT_SIZE 0x2000
+#endif /* Sony. */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+
+#ifdef linux
+#include <asm/page.h>
+#if defined(__i386__) || defined(__mc68000__)
+#define SEGMENT_SIZE 1024
+#else
+#ifndef SEGMENT_SIZE
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+#endif
+#endif
+
+#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+#endif
+
+/* Address of bss segment in memory after it is loaded. */
+#if !defined (N_BSSADDR)
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+#endif
+
+#if !defined (N_NLIST_DECLARED)
+struct nlist {
+ union {
+ char *n_name;
+ struct nlist *n_next;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ char n_other;
+ short n_desc;
+ unsigned long n_value;
+};
+#endif /* no N_NLIST_DECLARED. */
+
+#if !defined (N_UNDF)
+#define N_UNDF 0
+#endif
+#if !defined (N_ABS)
+#define N_ABS 2
+#endif
+#if !defined (N_TEXT)
+#define N_TEXT 4
+#endif
+#if !defined (N_DATA)
+#define N_DATA 6
+#endif
+#if !defined (N_BSS)
+#define N_BSS 8
+#endif
+#if !defined (N_FN)
+#define N_FN 15
+#endif
+
+#if !defined (N_EXT)
+#define N_EXT 1
+#endif
+#if !defined (N_TYPE)
+#define N_TYPE 036
+#endif
+#if !defined (N_STAB)
+#define N_STAB 0340
+#endif
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+#define N_INDR 0xa
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+/* These appear as input to LD, in a .o file. */
+#define N_SETA 0x14 /* Absolute set element symbol */
+#define N_SETT 0x16 /* Text set element symbol */
+#define N_SETD 0x18 /* Data set element symbol */
+#define N_SETB 0x1A /* Bss set element symbol */
+
+/* This is output from LD. */
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+
+#if !defined (N_RELOCATION_INFO_DECLARED)
+/* This structure describes a single relocation to be performed.
+ The text-relocation section of the file is a vector of these structures,
+ all of which apply to the text section.
+ Likewise, the data-relocation section applies to the data section. */
+
+struct relocation_info
+{
+ /* Address (within segment) to be relocated. */
+ int r_address;
+ /* The meaning of r_symbolnum depends on r_extern. */
+ unsigned int r_symbolnum:24;
+ /* Nonzero means value is a pc-relative offset
+ and it should be relocated for changes in its own address
+ as well as for changes in the symbol or section specified. */
+ unsigned int r_pcrel:1;
+ /* Length (as exponent of 2) of the field to be relocated.
+ Thus, a value of 2 indicates 1<<2 bytes. */
+ unsigned int r_length:2;
+ /* 1 => relocate with value of symbol.
+ r_symbolnum is the index of the symbol
+ in file's the symbol table.
+ 0 => relocate with the address of a segment.
+ r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+ (the N_EXT bit may be set also, but signifies nothing). */
+ unsigned int r_extern:1;
+ /* Four bits that aren't used, but when writing an object file
+ it is desirable to clear them. */
+#ifdef NS32K
+ unsigned r_bsr:1;
+ unsigned r_disp:1;
+ unsigned r_pad:2;
+#else
+ unsigned int r_pad:4;
+#endif
+};
+#endif /* no N_RELOCATION_INFO_DECLARED. */
+
+
+#endif /* __A_OUT_GNU_H__ */
diff --git a/pfinet/linux-src/include/linux/acct.h b/pfinet/linux-src/include/linux/acct.h
new file mode 100644
index 00000000..e20b1839
--- /dev/null
+++ b/pfinet/linux-src/include/linux/acct.h
@@ -0,0 +1,88 @@
+/*
+ * BSD Process Accounting for Linux - Definitions
+ *
+ * Author: Marco van Wieringen (mvw@planets.elm.net)
+ *
+ * This header file contains the definitions needed to implement
+ * BSD-style process accounting. The kernel accounting code and all
+ * user-level programs that try to do something useful with the
+ * process accounting log must include this file.
+ *
+ * Copyright (C) 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V.
+ *
+ */
+
+#ifndef _LINUX_ACCT_H
+#define _LINUX_ACCT_H
+
+#include <linux/types.h>
+
+/*
+ * comp_t is a 16-bit "floating" point number with a 3-bit base 8
+ * exponent and a 13-bit fraction. See linux/kernel/acct.c for the
+ * specific encoding system used.
+ */
+
+typedef __u16 comp_t;
+
+/*
+ * accounting file record
+ *
+ * This structure contains all of the information written out to the
+ * process accounting file whenever a process exits.
+ */
+
+#define ACCT_COMM 16
+
+struct acct
+{
+ char ac_flag; /* Accounting Flags */
+/*
+ * No binary format break with 2.0 - but when we hit 32bit uid we'll
+ * have to bite one
+ */
+ __u16 ac_uid; /* Accounting Real User ID */
+ __u16 ac_gid; /* Accounting Real Group ID */
+ __u16 ac_tty; /* Accounting Control Terminal */
+ __u32 ac_btime; /* Accounting Process Creation Time */
+ comp_t ac_utime; /* Accounting User Time */
+ comp_t ac_stime; /* Accounting System Time */
+ comp_t ac_etime; /* Accounting Elapsed Time */
+ comp_t ac_mem; /* Accounting Average Memory Usage */
+ comp_t ac_io; /* Accounting Chars Transferred */
+ comp_t ac_rw; /* Accounting Blocks Read or Written */
+ comp_t ac_minflt; /* Accounting Minor Pagefaults */
+ comp_t ac_majflt; /* Accounting Major Pagefaults */
+ comp_t ac_swaps; /* Accounting Number of Swaps */
+ __u32 ac_exitcode; /* Accounting Exitcode */
+ char ac_comm[ACCT_COMM + 1]; /* Accounting Command Name */
+ char ac_pad[10]; /* Accounting Padding Bytes */
+};
+
+/*
+ * accounting flags
+ */
+ /* bit set when the process ... */
+#define AFORK 0x01 /* ... executed fork, but did not exec */
+#define ASU 0x02 /* ... used super-user privileges */
+#define ACOMPAT 0x04 /* ... used compatibility mode (VAX only not used) */
+#define ACORE 0x08 /* ... dumped core */
+#define AXSIG 0x10 /* ... was killed by a signal */
+
+#define AHZ 100
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifdef CONFIG_BSD_PROCESS_ACCT
+extern void acct_auto_close(kdev_t dev);
+extern int acct_process(long exitcode);
+#else
+#define acct_auto_close(x) do { } while (0)
+#define acct_process(x) do { } while (0)
+#endif
+
+#endif /* __KERNEL */
+
+#endif /* _LINUX_ACCT_H */
diff --git a/pfinet/linux-src/include/linux/adfs_fs.h b/pfinet/linux-src/include/linux/adfs_fs.h
new file mode 100644
index 00000000..f6ed2d3b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/adfs_fs.h
@@ -0,0 +1,175 @@
+#ifndef _ADFS_FS_H
+#define _ADFS_FS_H
+
+#include <linux/types.h>
+/*
+ * Structures of data on the disk
+ */
+
+/*
+ * Disc Record at disc address 0xc00
+ */
+struct adfs_discrecord {
+ unsigned char log2secsize;
+ unsigned char secspertrack;
+ unsigned char heads;
+ unsigned char density;
+ unsigned char idlen;
+ unsigned char log2bpmb;
+ unsigned char skew;
+ unsigned char bootoption;
+ unsigned char lowsector;
+ unsigned char nzones;
+ unsigned short zone_spare;
+ unsigned long root;
+ unsigned long disc_size;
+ unsigned short disc_id;
+ unsigned char disc_name[10];
+ unsigned long disc_type;
+ unsigned long disc_size_high;
+ unsigned char log2sharesize:4;
+ unsigned char unused:4;
+ unsigned char big_flag:1;
+};
+
+#define ADFS_DISCRECORD (0xc00)
+#define ADFS_DR_OFFSET (0x1c0)
+#define ADFS_DR_SIZE 60
+#define ADFS_SUPER_MAGIC 0xadf5
+#define ADFS_FREE_FRAG 0
+#define ADFS_BAD_FRAG 1
+#define ADFS_ROOT_FRAG 2
+
+/*
+ * Directory header
+ */
+struct adfs_dirheader {
+ unsigned char startmasseq;
+ unsigned char startname[4];
+};
+
+#define ADFS_NEWDIR_SIZE 2048
+#define ADFS_OLDDIR_SIZE 1024
+#define ADFS_NUM_DIR_ENTRIES 77
+
+/*
+ * Directory entries
+ */
+struct adfs_direntry {
+ char dirobname[10];
+#define ADFS_NAME_LEN 10
+ __u8 dirload[4];
+ __u8 direxec[4];
+ __u8 dirlen[4];
+ __u8 dirinddiscadd[3];
+ __u8 newdiratts;
+#define ADFS_NDA_OWNER_READ (1 << 0)
+#define ADFS_NDA_OWNER_WRITE (1 << 1)
+#define ADFS_NDA_LOCKED (1 << 2)
+#define ADFS_NDA_DIRECTORY (1 << 3)
+#define ADFS_NDA_EXECUTE (1 << 4)
+#define ADFS_NDA_PUBLIC_READ (1 << 5)
+#define ADFS_NDA_PUBLIC_WRITE (1 << 6)
+};
+
+#define ADFS_MAX_NAME_LEN 255
+struct adfs_idir_entry {
+ __u32 inode_no; /* Address */
+ __u32 file_id; /* file id */
+ __u32 name_len; /* name length */
+ __u32 size; /* size */
+ __u32 mtime; /* modification time */
+ __u32 filetype; /* RiscOS file type */
+ __u8 mode; /* internal mode */
+ char name[ADFS_MAX_NAME_LEN]; /* file name */
+};
+
+/*
+ * Directory tail
+ */
+union adfs_dirtail {
+ struct {
+ unsigned char dirlastmask;
+ char dirname[10];
+ unsigned char dirparent[3];
+ char dirtitle[19];
+ unsigned char reserved[14];
+ unsigned char endmasseq;
+ unsigned char endname[4];
+ unsigned char dircheckbyte;
+ } old;
+ struct {
+ unsigned char dirlastmask;
+ unsigned char reserved[2];
+ unsigned char dirparent[3];
+ char dirtitle[19];
+ char dirname[10];
+ unsigned char endmasseq;
+ unsigned char endname[4];
+ unsigned char dircheckbyte;
+ } new;
+};
+
+#ifdef __KERNEL__
+/*
+ * Calculate the boot block checksum on an ADFS drive. Note that this will
+ * appear to be correct if the sector contains all zeros, so also check that
+ * the disk size is non-zero!!!
+ */
+extern inline int adfs_checkbblk(unsigned char *ptr)
+{
+ unsigned int result = 0;
+ unsigned char *p = ptr + 511;
+
+ do {
+ result = (result & 0xff) + (result >> 8);
+ result = result + *--p;
+ } while (p != ptr);
+
+ return (result & 0xff) != ptr[511];
+}
+
+/* dir.c */
+extern unsigned int adfs_val (unsigned char *p, int len);
+extern int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp);
+extern int adfs_dir_read (struct inode *inode, struct buffer_head **bhp);
+extern int adfs_dir_check (struct inode *inode, struct buffer_head **bhp,
+ int buffers, union adfs_dirtail *dtp);
+extern void adfs_dir_free (struct buffer_head **bhp, int buffers);
+extern int adfs_dir_get (struct super_block *sb, struct buffer_head **bhp,
+ int buffers, int pos, unsigned long parent_object_id,
+ struct adfs_idir_entry *ide);
+extern int adfs_dir_find_entry (struct super_block *sb, struct buffer_head **bhp,
+ int buffers, unsigned int index,
+ struct adfs_idir_entry *ide);
+
+/* inode.c */
+extern int adfs_inode_validate (struct inode *inode);
+extern unsigned long adfs_inode_generate (unsigned long parent_id, int diridx);
+extern unsigned long adfs_inode_objid (struct inode *inode);
+extern unsigned int adfs_parent_bmap (struct inode *inode, int block);
+extern int adfs_bmap (struct inode *inode, int block);
+extern void adfs_read_inode (struct inode *inode);
+
+/* map.c */
+extern int adfs_map_lookup (struct super_block *sb, int frag_id, int offset);
+
+/* namei.c */
+extern struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry);
+
+/* super.c */
+extern int init_adfs_fs (void);
+extern void adfs_error (struct super_block *, const char *, const char *, ...);
+
+/*
+ * Inodes and file operations
+ */
+
+/* dir.c */
+extern struct inode_operations adfs_dir_inode_operations;
+
+/* file.c */
+extern struct inode_operations adfs_file_inode_operations;
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/adfs_fs_i.h b/pfinet/linux-src/include/linux/adfs_fs_i.h
new file mode 100644
index 00000000..83157516
--- /dev/null
+++ b/pfinet/linux-src/include/linux/adfs_fs_i.h
@@ -0,0 +1,17 @@
+/*
+ * linux/include/linux/adfs_fs_i.h
+ *
+ * Copyright (C) 1997 Russell King
+ */
+
+#ifndef _ADFS_FS_I
+#define _ADFS_FS_I
+
+/*
+ * adfs file system inode data in memory
+ */
+struct adfs_inode_info {
+ unsigned long file_id; /* id of fragments containing actual data */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/adfs_fs_sb.h b/pfinet/linux-src/include/linux/adfs_fs_sb.h
new file mode 100644
index 00000000..649b61e4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/adfs_fs_sb.h
@@ -0,0 +1,33 @@
+/*
+ * linux/include/linux/adfs_fs_sb.h
+ *
+ * Copyright (C) 1997 Russell King
+ */
+
+#ifndef _ADFS_FS_SB
+#define _ADFS_FS_SB
+
+#include <linux/adfs_fs.h>
+
+/*
+ * adfs file system superblock data in memory
+ */
+struct adfs_sb_info {
+ struct buffer_head *s_sbh; /* buffer head containing disc record */
+ struct adfs_discrecord *s_dr; /* pointer to disc record in s_sbh */
+ uid_t s_uid; /* owner uid */
+ gid_t s_gid; /* owner gid */
+ int s_owner_mask; /* ADFS Owner perm -> unix perm */
+ int s_other_mask; /* ADFS Other perm -> unix perm */
+ __u16 s_zone_size; /* size of a map zone in bits */
+ __u16 s_ids_per_zone; /* max. no ids in one zone */
+ __u32 s_idlen; /* length of ID in map */
+ __u32 s_map_size; /* size of a map */
+ __u32 s_zonesize; /* zone size (in map bits) */
+ __u32 s_map_block; /* block address of map */
+ struct buffer_head **s_map; /* bh list containing map */
+ __u32 s_root; /* root disc address */
+ __s8 s_map2blk; /* shift left by this for map->sector */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/affs_fs.h b/pfinet/linux-src/include/linux/affs_fs.h
new file mode 100644
index 00000000..342ac264
--- /dev/null
+++ b/pfinet/linux-src/include/linux/affs_fs.h
@@ -0,0 +1,115 @@
+#ifndef _AFFS_FS_H
+#define _AFFS_FS_H
+/*
+ * The affs filesystem constants/structures
+ */
+
+#include <linux/types.h>
+
+#define AFFS_SUPER_MAGIC 0xadff
+
+/* Get the filesystem block size given an inode. */
+#define AFFS_I2BSIZE(inode) ((inode)->i_sb->s_blocksize)
+
+/* Get the filesystem hash table size given an inode. */
+#define AFFS_I2HSIZE(inode) ((inode)->i_sb->u.affs_sb.s_hashsize)
+
+/* Get the block number bits given an inode */
+#define AFFS_I2BITS(inode) ((inode)->i_sb->s_blocksize_bits)
+
+/* Get the fs type given an inode */
+#define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL)
+
+struct DateStamp
+{
+ u32 ds_Days;
+ u32 ds_Minute;
+ u32 ds_Tick;
+};
+
+/* --- Prototypes ----------------------------------------------------------------------------- */
+
+/* amigaffs.c */
+
+extern int affs_get_key_entry(int bsize, void *data, int entry_pos);
+extern int affs_get_file_name(int bsize, void *fh_data, unsigned char **name);
+extern u32 affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype);
+extern void affs_fix_checksum(int bsize, void *data, int cspos);
+extern void secs_to_datestamp(time_t secs, struct DateStamp *ds);
+extern int prot_to_mode(unsigned int prot);
+extern u32 mode_to_prot(int mode);
+extern int affs_insert_hash(unsigned long dir_ino, struct buffer_head *header,
+ struct inode *inode);
+extern int affs_remove_hash(struct buffer_head *bh, struct inode *inode);
+extern int affs_remove_link(struct buffer_head *bh, struct inode *inode);
+extern int affs_remove_header(struct buffer_head *bh, struct inode *inode);
+extern void affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
+extern void affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
+extern int affs_check_name(const unsigned char *name, int len);
+extern int affs_copy_name(unsigned char *bstr, const unsigned char *name);
+
+/* bitmap. c */
+
+extern int affs_count_free_blocks(struct super_block *s);
+extern int affs_count_free_bits(int blocksize, const char *data);
+extern void affs_free_block(struct super_block *sb, s32 block);
+extern s32 affs_new_header(struct inode *inode);
+extern s32 affs_new_data(struct inode *inode);
+extern void affs_make_zones(struct super_block *sb);
+
+/* namei.c */
+
+extern int affs_hash_name(const unsigned char *name, int len, int intl, int hashsize);
+extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry);
+extern int affs_unlink(struct inode *dir, struct dentry *dentry);
+extern int affs_create(struct inode *dir, struct dentry *dentry, int mode);
+extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+extern int affs_rmdir(struct inode *dir, struct dentry *dentry);
+extern int affs_link(struct dentry *olddentry, struct inode *dir,
+ struct dentry *dentry);
+extern int affs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname);
+extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry);
+
+/* inode.c */
+
+extern struct buffer_head *affs_bread(kdev_t dev, int block, int size);
+extern void affs_brelse(struct buffer_head *buf);
+extern unsigned long affs_parent_ino(struct inode *dir);
+extern struct inode *affs_new_inode(const struct inode *dir);
+extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
+extern int affs_add_entry(struct inode *dir, struct inode *link,
+ struct inode *inode, struct dentry *dentry, s32 type);
+extern void affs_put_inode(struct inode *inode);
+extern void affs_delete_inode(struct inode *inode);
+extern void affs_read_inode(struct inode *inode);
+extern void affs_write_inode(struct inode *inode);
+
+/* super.c */
+
+extern int affs_fs(void);
+extern int init_affs_fs(void);
+
+/* file.c */
+
+void affs_free_prealloc(struct inode *inode);
+extern void affs_truncate(struct inode *);
+
+/* dir.c */
+
+extern void affs_dir_truncate(struct inode *);
+
+/* jump tables */
+
+extern struct inode_operations affs_file_inode_operations;
+extern struct inode_operations affs_file_inode_operations_ofs;
+extern struct inode_operations affs_dir_inode_operations;
+extern struct inode_operations affs_symlink_inode_operations;
+extern struct inode_operations affs_chrdev_inode_operations;
+extern struct inode_operations affs_blkdev_inode_operations;
+
+extern struct dentry_operations affs_dentry_operations;
+extern struct dentry_operations affs_dentry_operations_intl;
+
+#endif
diff --git a/pfinet/linux-src/include/linux/affs_fs_i.h b/pfinet/linux-src/include/linux/affs_fs_i.h
new file mode 100644
index 00000000..beeabb0d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/affs_fs_i.h
@@ -0,0 +1,47 @@
+#ifndef _AFFS_FS_I
+#define _AFFS_FS_I
+
+#include <linux/a.out.h>
+#include <linux/time.h>
+
+#define AFFS_MAX_PREALLOC 16 /* MUST be a power of 2 */
+#define AFFS_KCSIZE 73 /* Allows for 1 extension block at 512 byte-blocks */
+
+struct key_cache {
+ struct timeval kc_lru_time; /* Last time this cache was used */
+ s32 kc_first; /* First cached key */
+ s32 kc_last; /* Last cached key */
+ s32 kc_this_key; /* Key of extension block this data block keys are from */
+ int kc_this_seq; /* Sequence number of this extension block */
+ s32 kc_next_key; /* Key of next extension block */
+ s32 kc_keys[AFFS_KCSIZE]; /* Key cache */
+};
+
+#define EC_SIZE (PAGE_SIZE - 4 * sizeof(struct key_cache) - 4) / 4
+
+struct ext_cache {
+ struct key_cache kc[4]; /* The 4 key caches */
+ s32 ec[EC_SIZE]; /* Keys of assorted extension blocks */
+ int max_ext; /* Index of last known extension block */
+};
+
+/*
+ * affs fs inode data in memory
+ */
+struct affs_inode_info {
+ u32 i_protect; /* unused attribute bits */
+ s32 i_parent; /* parent ino */
+ s32 i_original; /* if != 0, this is the key of the original */
+ s32 i_data[AFFS_MAX_PREALLOC]; /* preallocated blocks */
+ struct ext_cache *i_ec; /* Cache gets allocated dynamically */
+ int i_cache_users; /* Cache cannot be freed while > 0 */
+ int i_lastblock; /* last allocated block */
+ short i_pa_cnt; /* number of preallocated blocks */
+ short i_pa_next; /* Index of next block in i_data[] */
+ short i_pa_last; /* Index of next free slot in i_data[] */
+ short i_zone; /* write zone */
+ unsigned char i_hlink; /* This is a fake */
+ unsigned char i_pad;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/affs_fs_sb.h b/pfinet/linux-src/include/linux/affs_fs_sb.h
new file mode 100644
index 00000000..a066aee7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/affs_fs_sb.h
@@ -0,0 +1,74 @@
+#ifndef _AFFS_FS_SB
+#define _AFFS_FS_SB
+
+/*
+ * super-block data in memory
+ *
+ * Block numbers are adjusted for their actual size
+ *
+ */
+
+#define MAX_ZONES 8
+#define AFFS_DATA_MIN_FREE 512 /* Number of free blocks in zone for data blocks */
+#define AFFS_HDR_MIN_FREE 128 /* Same for header blocks */
+#define AFFS_ZONE_SIZE 1024 /* Blocks per alloc zone, must be multiple of 32 */
+
+struct affs_bm_info {
+ struct buffer_head *bm_bh; /* Buffer head if loaded (bm_count > 0) */
+ s32 bm_firstblk; /* Block number of first bit in this map */
+ s32 bm_key; /* Disk block number */
+ int bm_count; /* Usage counter */
+};
+
+struct affs_alloc_zone {
+ short az_size; /* Size of this allocation zone in double words */
+ short az_count; /* Number of users */
+ int az_free; /* Free blocks in here (no. of bits) */
+};
+
+struct affs_zone {
+ unsigned long z_ino; /* Associated inode number */
+ struct affs_bm_info *z_bm; /* Zone lies in this bitmap */
+ int z_start; /* Index of first word in bitmap */
+ int z_end; /* Index of last word in zone + 1 */
+ int z_az_no; /* Zone number */
+ unsigned long z_lru_time; /* Time of last usage */
+};
+
+struct affs_sb_info {
+ int s_partition_size; /* Partition size in blocks. */
+ int s_blksize; /* Initial device blksize */
+ s32 s_root_block; /* FFS root block number. */
+ int s_hashsize; /* Size of hash table. */
+ unsigned long s_flags; /* See below. */
+ s16 s_uid; /* uid to override */
+ s16 s_gid; /* gid to override */
+ umode_t s_mode; /* mode to override */
+ int s_reserved; /* Number of reserved blocks. */
+ struct buffer_head *s_root_bh; /* Cached root block. */
+ struct affs_bm_info *s_bitmap; /* Bitmap infos. */
+ int s_bm_count; /* Number of bitmap blocks. */
+ int s_nextzone; /* Next zone to look for free blocks. */
+ int s_num_az; /* Total number of alloc zones. */
+ struct affs_zone *s_zones; /* The zones themselves. */
+ struct affs_alloc_zone *s_alloc;/* The allocation zones. */
+ char *s_zonemap; /* Bitmap for allocation zones. */
+ char *s_prefix; /* Prefix for volumes and assigns. */
+ int s_prefix_len; /* Length of prefix. */
+ char s_volume[32]; /* Volume prefix for absolute symlinks. */
+};
+
+#define SF_INTL 0x0001 /* International filesystem. */
+#define SF_BM_VALID 0x0002 /* Bitmap is valid. */
+#define SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */
+#define SF_QUIET 0x0008 /* chmod errors will be not reported */
+#define SF_SETUID 0x0010 /* Ignore Amiga uid */
+#define SF_SETGID 0x0020 /* Ignore Amiga gid */
+#define SF_SETMODE 0x0040 /* Ignore Amiga protection bits */
+#define SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */
+#define SF_OFS 0x0200 /* Old filesystem */
+#define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */
+#define SF_VERBOSE 0x0800 /* Talk about fs when mounting */
+#define SF_READONLY 0x1000 /* Don't allow to remount rw */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/affs_hardblocks.h b/pfinet/linux-src/include/linux/affs_hardblocks.h
new file mode 100644
index 00000000..ae893e02
--- /dev/null
+++ b/pfinet/linux-src/include/linux/affs_hardblocks.h
@@ -0,0 +1,66 @@
+#ifndef AFFS_HARDBLOCKS_H
+#define AFFS_HARDBLOCKS_H
+
+/* Just the needed definitions for the RDB of an Amiga HD. */
+
+struct RigidDiskBlock {
+ u32 rdb_ID;
+ u32 rdb_SummedLongs;
+ s32 rdb_ChkSum;
+ u32 rdb_HostID;
+ u32 rdb_BlockBytes;
+ u32 rdb_Flags;
+ u32 rdb_BadBlockList;
+ u32 rdb_PartitionList;
+ u32 rdb_FileSysHeaderList;
+ u32 rdb_DriveInit;
+ u32 rdb_Reserved1[6];
+ u32 rdb_Cylinders;
+ u32 rdb_Sectors;
+ u32 rdb_Heads;
+ u32 rdb_Interleave;
+ u32 rdb_Park;
+ u32 rdb_Reserved2[3];
+ u32 rdb_WritePreComp;
+ u32 rdb_ReducedWrite;
+ u32 rdb_StepRate;
+ u32 rdb_Reserved3[5];
+ u32 rdb_RDBBlocksLo;
+ u32 rdb_RDBBlocksHi;
+ u32 rdb_LoCylinder;
+ u32 rdb_HiCylinder;
+ u32 rdb_CylBlocks;
+ u32 rdb_AutoParkSeconds;
+ u32 rdb_HighRDSKBlock;
+ u32 rdb_Reserved4;
+ char rdb_DiskVendor[8];
+ char rdb_DiskProduct[16];
+ char rdb_DiskRevision[4];
+ char rdb_ControllerVendor[8];
+ char rdb_ControllerProduct[16];
+ char rdb_ControllerRevision[4];
+ u32 rdb_Reserved5[10];
+};
+
+#define IDNAME_RIGIDDISK 0x5244534B /* "RDSK" */
+
+struct PartitionBlock {
+ u32 pb_ID;
+ u32 pb_SummedLongs;
+ s32 pb_ChkSum;
+ u32 pb_HostID;
+ u32 pb_Next;
+ u32 pb_Flags;
+ u32 pb_Reserved1[2];
+ u32 pb_DevFlags;
+ u8 pb_DriveName[32];
+ u32 pb_Reserved2[15];
+ u32 pb_Environment[17];
+ u32 pb_EReserved[15];
+};
+
+#define IDNAME_PARTITION 0x50415254 /* "PART" */
+
+#define RDB_ALLOCATION_LIMIT 16
+
+#endif /* AFFS_HARDBLOCKS_H */
diff --git a/pfinet/linux-src/include/linux/amifd.h b/pfinet/linux-src/include/linux/amifd.h
new file mode 100644
index 00000000..491bdd86
--- /dev/null
+++ b/pfinet/linux-src/include/linux/amifd.h
@@ -0,0 +1,61 @@
+#ifndef _AMIFD_H
+#define _AMIFD_H
+
+/* Definitions for the Amiga floppy driver */
+
+#include <linux/fd.h>
+
+#define FD_MAX_UNITS 4 /* Max. Number of drives */
+#define FLOPPY_MAX_SECTORS 22 /* Max. Number of sectors per track */
+
+#ifndef ASSEMBLER
+
+struct fd_data_type {
+ char *name; /* description of data type */
+ int sects; /* sectors per track */
+#ifdef __STDC__
+ int (*read_fkt)(int);
+ void (*write_fkt)(int);
+#else
+ int (*read_fkt)(); /* read whole track */
+ void (*write_fkt)(); /* write whole track */
+#endif
+};
+
+/*
+** Floppy type descriptions
+*/
+
+struct fd_drive_type {
+ unsigned long code; /* code returned from drive */
+ char *name; /* description of drive */
+ unsigned int tracks; /* number of tracks */
+ unsigned int heads; /* number of heads */
+ unsigned int read_size; /* raw read size for one track */
+ unsigned int write_size; /* raw write size for one track */
+ unsigned int sect_mult; /* sectors and gap multiplier (HD = 2) */
+ unsigned int precomp1; /* start track for precomp 1 */
+ unsigned int precomp2; /* start track for precomp 2 */
+ unsigned int step_delay; /* time (in ms) for delay after step */
+ unsigned int settle_time; /* time to settle after dir change */
+ unsigned int side_time; /* time needed to change sides */
+};
+
+struct amiga_floppy_struct {
+ struct fd_drive_type *type; /* type of floppy for this unit */
+ struct fd_data_type *dtype; /* type of floppy for this unit */
+ int track; /* current track (-1 == unknown) */
+ unsigned char *trackbuf; /* current track (kmaloc()'d */
+
+ int blocks; /* total # blocks on disk */
+
+ int changed; /* true when not known */
+ int disk; /* disk in drive (-1 == unknown) */
+ int motor; /* true when motor is at speed */
+ int busy; /* true when drive is active */
+ int dirty; /* true when trackbuf is not on disk */
+ int status; /* current error code for unit */
+};
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/amifdreg.h b/pfinet/linux-src/include/linux/amifdreg.h
new file mode 100644
index 00000000..76188bf4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/amifdreg.h
@@ -0,0 +1,81 @@
+#ifndef _LINUX_AMIFDREG_H
+#define _LINUX_AMIFDREG_H
+
+/*
+** CIAAPRA bits (read only)
+*/
+
+#define DSKRDY (0x1<<5) /* disk ready when low */
+#define DSKTRACK0 (0x1<<4) /* head at track zero when low */
+#define DSKPROT (0x1<<3) /* disk protected when low */
+#define DSKCHANGE (0x1<<2) /* low when disk removed */
+
+/*
+** CIAAPRB bits (read/write)
+*/
+
+#define DSKMOTOR (0x1<<7) /* motor on when low */
+#define DSKSEL3 (0x1<<6) /* select drive 3 when low */
+#define DSKSEL2 (0x1<<5) /* select drive 2 when low */
+#define DSKSEL1 (0x1<<4) /* select drive 1 when low */
+#define DSKSEL0 (0x1<<3) /* select drive 0 when low */
+#define DSKSIDE (0x1<<2) /* side selection: 0 = upper, 1 = lower */
+#define DSKDIREC (0x1<<1) /* step direction: 0=in, 1=out (to trk 0) */
+#define DSKSTEP (0x1) /* pulse low to step head 1 track */
+
+/*
+** DSKBYTR bits (read only)
+*/
+
+#define DSKBYT (1<<15) /* register contains valid byte when set */
+#define DMAON (1<<14) /* disk DMA enabled */
+#define DISKWRITE (1<<13) /* disk write bit in DSKLEN enabled */
+#define WORDEQUAL (1<<12) /* DSKSYNC register match when true */
+/* bits 7-0 are data */
+
+/*
+** ADKCON/ADKCONR bits
+*/
+
+#ifndef SETCLR
+#define ADK_SETCLR (1<<15) /* control bit */
+#endif
+#define ADK_PRECOMP1 (1<<14) /* precompensation selection */
+#define ADK_PRECOMP0 (1<<13) /* 00=none, 01=140ns, 10=280ns, 11=500ns */
+#define ADK_MFMPREC (1<<12) /* 0=GCR precomp., 1=MFM precomp. */
+#define ADK_WORDSYNC (1<<10) /* enable DSKSYNC auto DMA */
+#define ADK_MSBSYNC (1<<9) /* when 1, enable sync on MSbit (for GCR) */
+#define ADK_FAST (1<<8) /* bit cell: 0=2us (GCR), 1=1us (MFM) */
+
+/*
+** DSKLEN bits
+*/
+
+#define DSKLEN_DMAEN (1<<15)
+#define DSKLEN_WRITE (1<<14)
+
+/*
+** INTENA/INTREQ bits
+*/
+
+#define DSKINDEX (0x1<<4) /* DSKINDEX bit */
+
+/*
+** Misc
+*/
+
+#define MFM_SYNC 0x4489 /* standard MFM sync value */
+
+/* Values for FD_COMMAND */
+#define FD_RECALIBRATE 0x07 /* move to track 0 */
+#define FD_SEEK 0x0F /* seek track */
+#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */
+#define FD_WRITE 0xC5 /* write with MT, MFM */
+#define FD_SENSEI 0x08 /* Sense Interrupt Status */
+#define FD_SPECIFY 0x03 /* specify HUT etc */
+#define FD_FORMAT 0x4D /* format one track */
+#define FD_VERSION 0x10 /* get version code */
+#define FD_CONFIGURE 0x13 /* configure FIFO operation */
+#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */
+
+#endif /* _LINUX_AMIFDREG_H */
diff --git a/pfinet/linux-src/include/linux/amigaffs.h b/pfinet/linux-src/include/linux/amigaffs.h
new file mode 100644
index 00000000..a6b16e06
--- /dev/null
+++ b/pfinet/linux-src/include/linux/amigaffs.h
@@ -0,0 +1,228 @@
+#ifndef AMIGAFFS_H
+#define AMIGAFFS_H
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+
+/* AmigaOS allows file names with up to 30 characters length.
+ * Names longer than that will be silently truncated. If you
+ * want to disallow this, comment out the following #define.
+ * Creating filesystem objects with longer names will then
+ * result in an error (ENAMETOOLONG).
+ */
+/*#define AFFS_NO_TRUNCATE */
+
+/* Ugly macros make the code more pretty. */
+
+#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st))))
+#define AFFS_GET_HASHENTRY(data,hashkey) be32_to_cpu(((struct dir_front *)data)->hashtable[hashkey])
+#define AFFS_BLOCK(data,ino,blk) ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-(blk)]
+
+#define FILE_END(p,i) GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i))
+#define ROOT_END(p,i) GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i))
+#define DIR_END(p,i) GET_END_PTR(struct dir_end,p,AFFS_I2BSIZE(i))
+#define LINK_END(p,i) GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i))
+#define ROOT_END_S(p,s) GET_END_PTR(struct root_end,p,(s)->s_blocksize)
+#define DATA_FRONT(bh) ((struct data_front *)(bh)->b_data)
+#define DIR_FRONT(bh) ((struct dir_front *)(bh)->b_data)
+
+/* Only for easier debugging if need be */
+#define affs_bread bread
+#define affs_brelse brelse
+
+#ifdef __LITTLE_ENDIAN
+#define BO_EXBITS 0x18UL
+#elif defined(__BIG_ENDIAN)
+#define BO_EXBITS 0x00UL
+#else
+#error Endianness must be known for affs to work.
+#endif
+
+#define FS_OFS 0x444F5300
+#define FS_FFS 0x444F5301
+#define FS_INTLOFS 0x444F5302
+#define FS_INTLFFS 0x444F5303
+#define FS_DCOFS 0x444F5304
+#define FS_DCFFS 0x444F5305
+#define MUFS_FS 0x6d754653 /* 'muFS' */
+#define MUFS_OFS 0x6d754600 /* 'muF\0' */
+#define MUFS_FFS 0x6d754601 /* 'muF\1' */
+#define MUFS_INTLOFS 0x6d754602 /* 'muF\2' */
+#define MUFS_INTLFFS 0x6d754603 /* 'muF\3' */
+#define MUFS_DCOFS 0x6d754604 /* 'muF\4' */
+#define MUFS_DCFFS 0x6d754605 /* 'muF\5' */
+
+#define T_SHORT 2
+#define T_LIST 16
+#define T_DATA 8
+
+#define ST_LINKFILE -4
+#define ST_FILE -3
+#define ST_ROOT 1
+#define ST_USERDIR 2
+#define ST_SOFTLINK 3
+#define ST_LINKDIR 4
+
+struct root_front
+{
+ s32 primary_type;
+ s32 spare1[2];
+ s32 hash_size;
+ s32 spare2;
+ u32 checksum;
+ s32 hashtable[0];
+};
+
+struct root_end
+{
+ s32 bm_flag;
+ s32 bm_keys[25];
+ s32 bm_extend;
+ struct DateStamp dir_altered;
+ u8 disk_name[40];
+ struct DateStamp disk_altered;
+ struct DateStamp disk_made;
+ s32 spare1[3];
+ s32 secondary_type;
+};
+
+struct dir_front
+{
+ s32 primary_type;
+ s32 own_key;
+ s32 spare1[3];
+ u32 checksum;
+ s32 hashtable[0];
+};
+
+struct dir_end
+{
+ s32 spare1;
+ s16 owner_uid;
+ s16 owner_gid;
+ u32 protect;
+ s32 spare2;
+ u8 comment[92];
+ struct DateStamp created;
+ u8 dir_name[32];
+ s32 spare3[2];
+ s32 link_chain;
+ s32 spare4[5];
+ s32 hash_chain;
+ s32 parent;
+ s32 spare5;
+ s32 secondary_type;
+};
+
+struct file_front
+{
+ s32 primary_type;
+ s32 own_key;
+ s32 block_count;
+ s32 unknown1;
+ s32 first_data;
+ u32 checksum;
+ s32 blocks[0];
+};
+
+struct file_end
+{
+ s32 spare1;
+ s16 owner_uid;
+ s16 owner_gid;
+ u32 protect;
+ s32 byte_size;
+ u8 comment[92];
+ struct DateStamp created;
+ u8 file_name[32];
+ s32 spare2;
+ s32 original; /* not really in file_end */
+ s32 link_chain;
+ s32 spare3[5];
+ s32 hash_chain;
+ s32 parent;
+ s32 extension;
+ s32 secondary_type;
+};
+
+struct hlink_front
+{
+ s32 primary_type;
+ s32 own_key;
+ s32 spare1[3];
+ u32 checksum;
+};
+
+struct hlink_end
+{
+ s32 spare1;
+ s16 owner_uid;
+ s16 owner_gid;
+ u32 protect;
+ u8 comment[92];
+ struct DateStamp created;
+ u8 link_name[32];
+ s32 spare2;
+ s32 original;
+ s32 link_chain;
+ s32 spare3[5];
+ s32 hash_chain;
+ s32 parent;
+ s32 spare4;
+ s32 secondary_type;
+};
+
+struct slink_front
+{
+ s32 primary_type;
+ s32 own_key;
+ s32 spare1[3];
+ s32 checksum;
+ u8 symname[288]; /* depends on block size */
+};
+
+struct data_front
+{
+ s32 primary_type;
+ s32 header_key;
+ s32 sequence_number;
+ s32 data_size;
+ s32 next_data;
+ s32 checksum;
+ u8 data[488]; /* depends on block size */
+};
+
+/* Permission bits */
+
+#define FIBF_OTR_READ 0x8000
+#define FIBF_OTR_WRITE 0x4000
+#define FIBF_OTR_EXECUTE 0x2000
+#define FIBF_OTR_DELETE 0x1000
+#define FIBF_GRP_READ 0x0800
+#define FIBF_GRP_WRITE 0x0400
+#define FIBF_GRP_EXECUTE 0x0200
+#define FIBF_GRP_DELETE 0x0100
+
+#define FIBF_SCRIPT 0x0040
+#define FIBF_PURE 0x0020 /* no use under linux */
+#define FIBF_ARCHIVE 0x0010 /* never set, always cleared on write */
+#define FIBF_READ 0x0008 /* 0 means allowed */
+#define FIBF_WRITE 0x0004 /* 0 means allowed */
+#define FIBF_EXECUTE 0x0002 /* 0 means allowed, ignored under linux */
+#define FIBF_DELETE 0x0001 /* 0 means allowed */
+
+#define FIBF_OWNER 0x000F /* Bits pertaining to owner */
+
+#define AFFS_UMAYWRITE(prot) (((prot) & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE))
+#define AFFS_UMAYREAD(prot) ((prot) & FIBF_READ)
+#define AFFS_UMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE)
+#define AFFS_GMAYWRITE(prot) (((prot)&(FIBF_GRP_WRITE|FIBF_GRP_DELETE))==\
+ (FIBF_GRP_WRITE|FIBF_GRP_DELETE))
+#define AFFS_GMAYREAD(prot) ((prot) & FIBF_GRP_READ)
+#define AFFS_GMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE)
+#define AFFS_OMAYWRITE(prot) (((prot)&(FIBF_OTR_WRITE|FIBF_OTR_DELETE))==\
+ (FIBF_OTR_WRITE|FIBF_OTR_DELETE))
+#define AFFS_OMAYREAD(prot) ((prot) & FIBF_OTR_READ)
+#define AFFS_OMAYEXECUTE(prot) ((prot) & FIBF_EXECUTE)
+
+#endif
diff --git a/pfinet/linux-src/include/linux/apm_bios.h b/pfinet/linux-src/include/linux/apm_bios.h
new file mode 100644
index 00000000..caf0b4b7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/apm_bios.h
@@ -0,0 +1,144 @@
+#ifndef _LINUX_APM_H
+#define _LINUX_APM_H
+
+/*
+ * Include file for the interface to an APM BIOS
+ * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com)
+ *
+ * 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.
+ */
+
+typedef unsigned short apm_event_t;
+typedef unsigned short apm_eventinfo_t;
+
+#ifdef __KERNEL__
+
+#define APM_40 0x40
+#define APM_CS (APM_40 + 8)
+#define APM_CS_16 (APM_CS + 8)
+#define APM_DS (APM_CS_16 + 8)
+
+struct apm_bios_info {
+ unsigned short version;
+ unsigned short cseg;
+ unsigned long offset;
+ unsigned short cseg_16;
+ unsigned short dseg;
+ unsigned short flags;
+ unsigned short cseg_len;
+ unsigned short cseg_16_len;
+ unsigned short dseg_len;
+};
+
+ /* Results of APM Installation Check */
+#define APM_16_BIT_SUPPORT 0x0001
+#define APM_32_BIT_SUPPORT 0x0002
+#define APM_IDLE_SLOWS_CLOCK 0x0004
+#define APM_BIOS_DISABLED 0x0008
+#define APM_BIOS_DISENGAGED 0x0010
+
+/*
+ * Maximum number of events stored
+ */
+#define APM_MAX_EVENTS 20
+
+/*
+ * The per-file APM data
+ */
+struct apm_bios_struct {
+ int magic;
+ struct apm_bios_struct * next;
+ int suser;
+ int suspends_pending;
+ int standbys_pending;
+ int suspends_read;
+ int standbys_read;
+ int event_head;
+ int event_tail;
+ apm_event_t events[APM_MAX_EVENTS];
+};
+
+/*
+ * The magic number in apm_bios_struct
+ */
+#define APM_BIOS_MAGIC 0x4101
+
+/*
+ * in init/main.c
+ */
+extern struct apm_bios_info apm_bios_info;
+
+extern void apm_bios_init(void);
+extern void apm_setup(char *, int *);
+
+extern int apm_register_callback(int (*callback)(apm_event_t));
+extern void apm_unregister_callback(int (*callback)(apm_event_t));
+
+extern void apm_power_off(void);
+extern int apm_display_blank(void);
+extern int apm_display_unblank(void);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Power states
+ */
+#define APM_STATE_READY 0x0000
+#define APM_STATE_STANDBY 0x0001
+#define APM_STATE_SUSPEND 0x0002
+#define APM_STATE_OFF 0x0003
+#define APM_STATE_BUSY 0x0004
+#define APM_STATE_REJECT 0x0005
+
+/*
+ * Events (results of Get PM Event)
+ */
+#define APM_SYS_STANDBY 0x0001
+#define APM_SYS_SUSPEND 0x0002
+#define APM_NORMAL_RESUME 0x0003
+#define APM_CRITICAL_RESUME 0x0004
+#define APM_LOW_BATTERY 0x0005
+#define APM_POWER_STATUS_CHANGE 0x0006
+#define APM_UPDATE_TIME 0x0007
+#define APM_CRITICAL_SUSPEND 0x0008
+#define APM_USER_STANDBY 0x0009
+#define APM_USER_SUSPEND 0x000a
+#define APM_STANDBY_RESUME 0x000b
+#define APM_CAPABILITY_CHANGE 0x000c
+
+/*
+ * Error codes
+ */
+#define APM_SUCCESS 0x00
+#define APM_DISABLED 0x01
+#define APM_CONNECTED 0x02
+#define APM_NOT_CONNECTED 0x03
+#define APM_16_CONNECTED 0x05
+#define APM_16_UNSUPPORTED 0x06
+#define APM_32_CONNECTED 0x07
+#define APM_32_UNSUPPORTED 0x08
+#define APM_BAD_DEVICE 0x09
+#define APM_BAD_PARAM 0x0a
+#define APM_NOT_ENGAGED 0x0b
+#define APM_BAD_FUNCTION 0x0c
+#define APM_RESUME_DISABLED 0x0d
+#define APM_NO_ERROR 0x53
+#define APM_BAD_STATE 0x60
+#define APM_NO_EVENTS 0x80
+#define APM_NOT_PRESENT 0x86
+
+/* ioctl operations */
+#include <linux/ioctl.h>
+
+#define APM_IOC_STANDBY _IO('A', 1)
+#define APM_IOC_SUSPEND _IO('A', 2)
+
+#endif /* LINUX_APM_H */
diff --git a/pfinet/linux-src/include/linux/arcdevice.h b/pfinet/linux-src/include/linux/arcdevice.h
new file mode 100644
index 00000000..b4df083e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/arcdevice.h
@@ -0,0 +1,354 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. NET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the ARCnet handlers.
+ *
+ * Version: $Id: arcdevice.h,v 1.3 1997/11/09 11:05:05 mj Exp $
+ *
+ * Authors: Avery Pennarun <apenwarr@bond.net>
+ * David Woodhouse <dwmw2@cam.ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#ifndef _LINUX_ARCDEVICE_H
+#define _LINUX_ARCDEVICE_H
+
+#include <linux/config.h>
+#include <linux/if_arcnet.h>
+
+#ifdef __KERNEL__
+
+#define ARC_20020 1
+#define ARC_RIM_I 2
+#define ARC_90xx 3
+#define ARC_90xx_IO 4
+
+#define MAX_ARCNET_DEVS 8
+
+
+/* The card sends the reconfiguration signal when it loses the connection to
+ * the rest of its network. It is a 'Hello, is anybody there?' cry. This
+ * usually happens when a new computer on the network is powered on or when
+ * the cable is broken.
+ *
+ * Define DETECT_RECONFIGS if you want to detect network reconfigurations.
+ * Recons may be a real nuisance on a larger ARCnet network; if you are a
+ * network administrator you probably would like to count them.
+ * Reconfigurations will be recorded in stats.tx_carrier_errors (the last
+ * field of the /proc/net/dev file).
+ *
+ * Define SHOW_RECONFIGS if you really want to see a log message whenever
+ * a RECON occurs.
+ */
+#define DETECT_RECONFIGS
+#undef SHOW_RECONFIGS
+
+
+/* RECON_THRESHOLD is the maximum number of RECON messages to receive within
+ * one minute before printing a "cabling problem" warning. You must have
+ * DETECT_RECONFIGS enabled if you want to use this. The default value
+ * should be fine.
+ *
+ * After that, a "cabling restored" message will be printed on the next IRQ
+ * if no RECON messages have been received for 10 seconds.
+ *
+ * Do not define RECON_THRESHOLD at all if you want to disable this feature.
+ */
+#define RECON_THRESHOLD 30
+
+
+/* Define this to the minimum "timeout" value. If a transmit takes longer
+ * than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large
+ * network, or one with heavy network traffic, this timeout may need to be
+ * increased. The larger it is, though, the longer it will be between
+ * necessary transmits - don't set this too large.
+ */
+#define TX_TIMEOUT (20*HZ/100)
+
+
+/* Display warnings about the driver being an ALPHA version.
+ */
+#undef ALPHA_WARNING
+
+
+/* New debugging bitflags: each option can be enabled individually.
+ *
+ * These can be set while the driver is running by typing:
+ * ifconfig arc0 down metric 1xxx HOSTNAME
+ * where 1xxx is 1000 + the debug level you want
+ * and HOSTNAME is your hostname/ip address
+ * and then resetting your routes.
+ *
+ * An ioctl() should be used for this instead, someday.
+ *
+ * Note: only debug flags included in the ARCNET_DEBUG_MAX define will
+ * actually be available. GCC will (at least, GCC 2.7.0 will) notice
+ * lines using a BUGLVL not in ARCNET_DEBUG_MAX and automatically optimize
+ * them out.
+ */
+#define D_NORMAL 1 /* important operational info */
+#define D_EXTRA 2 /* useful, but non-vital information */
+#define D_INIT 4 /* show init/probe messages */
+#define D_INIT_REASONS 8 /* show reasons for discarding probes */
+/* debug levels below give LOTS of output during normal operation! */
+#define D_DURING 16 /* trace operations (including irq's) */
+#define D_TX 32 /* show tx packets */
+#define D_RX 64 /* show rx packets */
+#define D_SKB 128 /* show skb's */
+
+#ifndef ARCNET_DEBUG_MAX
+#define ARCNET_DEBUG_MAX (~0) /* enable ALL debug messages */
+#endif
+
+#ifndef ARCNET_DEBUG
+#define ARCNET_DEBUG (D_NORMAL|D_EXTRA)
+#endif
+extern int arcnet_debug;
+
+/* macros to simplify debug checking */
+#define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
+#define BUGMSG2(x,msg,args...) do { BUGLVL(x) printk(msg, ## args); } while (0)
+#define BUGMSG(x,msg,args...) \
+ BUGMSG2(x,"%s%6s: " msg, \
+ x==D_NORMAL ? KERN_WARNING : \
+ x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \
+ dev->name , ## args)
+
+
+#define SETMASK AINTMASK(lp->intmask)
+
+ /* Time needed to resetthe card - in jiffies. This works on my SMC
+ * PC100. I can't find a reference that tells me just how long I
+ * should wait.
+ */
+#define RESETtime (HZ * 3 / 10) /* reset */
+
+ /* these are the max/min lengths of packet data. (including
+ * ClientData header)
+ * note: packet sizes 250, 251, 252 are impossible (God knows why)
+ * so exception packets become necessary.
+ *
+ * These numbers are compared with the length of the full packet,
+ * including ClientData header.
+ */
+#define MTU 253 /* normal packet max size */
+#define MinTU 257 /* extended packet min size */
+#define XMTU 508 /* extended packet max size */
+
+ /* status/interrupt mask bit fields */
+#define TXFREEflag 0x01 /* transmitter available */
+#define TXACKflag 0x02 /* transmitted msg. ackd */
+#define RECONflag 0x04 /* system reconfigured */
+#define TESTflag 0x08 /* test flag */
+#define RESETflag 0x10 /* power-on-reset */
+#define RES1flag 0x20 /* reserved - usually set by jumper */
+#define RES2flag 0x40 /* reserved - usually set by jumper */
+#define NORXflag 0x80 /* receiver inhibited */
+
+ /* Flags used for IO-mapped memory operations */
+#define AUTOINCflag 0x40 /* Increase location with each access */
+#define IOMAPflag 0x02 /* (for 90xx) Use IO mapped memory, not mmap */
+#define ENABLE16flag 0x80 /* (for 90xx) Enable 16-bit mode */
+
+ /* in the command register, the following bits have these meanings:
+ * 0-2 command
+ * 3-4 page number (for enable rcv/xmt command)
+ * 7 receive broadcasts
+ */
+#define NOTXcmd 0x01 /* disable transmitter */
+#define NORXcmd 0x02 /* disable receiver */
+#define TXcmd 0x03 /* enable transmitter */
+#define RXcmd 0x04 /* enable receiver */
+#define CONFIGcmd 0x05 /* define configuration */
+#define CFLAGScmd 0x06 /* clear flags */
+#define TESTcmd 0x07 /* load test flags */
+
+ /* flags for "clear flags" command */
+#define RESETclear 0x08 /* power-on-reset */
+#define CONFIGclear 0x10 /* system reconfigured */
+
+ /* flags for "load test flags" command */
+#define TESTload 0x08 /* test flag (diagnostic) */
+
+ /* byte deposited into first address of buffers on reset */
+#define TESTvalue 0321 /* that's octal for 0xD1 :) */
+
+ /* for "enable receiver" command */
+#define RXbcasts 0x80 /* receive broadcasts */
+
+ /* flags for "define configuration" command */
+#define NORMALconf 0x00 /* 1-249 byte packets */
+#define EXTconf 0x08 /* 250-504 byte packets */
+
+ /* Starts receiving packets into recbuf.
+ */
+#define EnableReceiver() ACOMMAND(RXcmd|(recbuf<<3)|RXbcasts)
+
+
+
+#define JIFFER(time) for (delayval=jiffies+time; time_before(jiffies,delayval);) ;
+
+ /* a complete ARCnet packet */
+union ArcPacket
+{
+ struct archdr hardheader; /* the hardware header */
+ u_char raw[512]; /* raw packet info, incl ClientData */
+};
+
+
+ /* the "client data" header - RFC1201 information
+ * notice that this screws up if it's not an even number of bytes
+ * <sigh>
+ */
+struct ClientData
+{
+ /* data that's NOT part of real packet - we MUST get rid of it before
+ * actually sending!!
+ */
+ u_char saddr, /* Source address - needed for IPX */
+ daddr; /* Destination address */
+
+ /* data that IS part of real packet */
+ u_char protocol_id, /* ARC_P_IP, ARC_P_ARP, etc */
+ split_flag; /* for use with split packets */
+ u_short sequence; /* sequence number */
+};
+#define EXTRA_CLIENTDATA (sizeof(struct ClientData)-4)
+
+
+ /* the "client data" header - RFC1051 information
+ * this also screws up if it's not an even number of bytes
+ * <sigh again>
+ */
+struct S_ClientData
+{
+ /* data that's NOT part of real packet - we MUST get rid of it before
+ * actually sending!!
+ */
+ u_char saddr, /* Source address - needed for IPX */
+ daddr, /* Destination address */
+ junk; /* padding to make an even length */
+
+ /* data that IS part of real packet */
+ u_char protocol_id; /* ARC_P_IP, ARC_P_ARP, etc */
+};
+#define S_EXTRA_CLIENTDATA (sizeof(struct S_ClientData)-1)
+
+
+/* "Incoming" is information needed for each address that could be sending
+ * to us. Mostly for partially-received split packets.
+ */
+struct Incoming
+{
+ struct sk_buff *skb; /* packet data buffer */
+ unsigned char lastpacket, /* number of last packet (from 1) */
+ numpackets; /* number of packets in split */
+ u_short sequence; /* sequence number of assembly */
+};
+
+struct Outgoing
+{
+ struct sk_buff *skb; /* buffer from upper levels */
+ struct ClientData *hdr; /* clientdata of last packet */
+ u_char *data; /* pointer to data in packet */
+ short length, /* bytes total */
+ dataleft, /* bytes left */
+ segnum, /* segment being sent */
+ numsegs, /* number of segments */
+ seglen; /* length of segment */
+};
+
+
+struct arcnet_local {
+ struct net_device_stats stats;
+ u_short sequence; /* sequence number (incs with each packet) */
+ u_short aborted_seq;
+ u_char stationid, /* our 8-bit station address */
+ recbuf, /* receive buffer # (0 or 1) */
+ txbuf, /* transmit buffer # (2 or 3) */
+ txready, /* buffer where a packet is ready to send */
+ config, /* current value of CONFIG register */
+ timeout, /* Extended timeout for COM20020 */
+ backplane, /* Backplane flag for COM20020 */
+ setup, /* Contents of setup register */
+ intmask; /* current value of INTMASK register */
+ short intx, /* in TX routine? */
+ in_txhandler, /* in TX_IRQ handler? */
+ sending, /* transmit in progress? */
+ lastload_dest, /* can last loaded packet be acked? */
+ lasttrans_dest; /* can last TX'd packet be acked? */
+
+#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
+ time_t first_recon, /* time of "first" RECON message to count */
+ last_recon; /* time of most recent RECON */
+ int num_recons, /* number of RECONs between first and last. */
+ network_down; /* do we think the network is down? */
+#endif
+
+ struct timer_list timer; /* the timer interrupt struct */
+ struct Incoming incoming[256]; /* one from each address */
+ struct Outgoing outgoing; /* packet currently being sent */
+
+ int card_type;
+ char *card_type_str;
+
+ void (*inthandler) (struct device *dev);
+ int (*arcnet_reset) (struct device *dev, int reset_delay);
+ void (*asetmask) (struct device *dev, u_char mask);
+ void (*acommand) (struct device *dev, u_char command);
+ u_char (*astatus) (struct device *dev);
+ void (*en_dis_able_TX) (struct device *dev, int enable);
+ void (*prepare_tx)(struct device *dev,u_char *hdr,int hdrlen,
+ char *data,int length,int daddr,int exceptA, int offset);
+ void (*openclose_device)(int open);
+
+ struct device *adev; /* RFC1201 protocol device */
+
+ /* These are last to ensure that the chipset drivers don't depend on the
+ * CONFIG_ARCNET_ETH and CONFIG_ARCNET_1051 options.
+ */
+
+#ifdef CONFIG_ARCNET_ETH
+ struct device *edev; /* Ethernet-Encap device */
+#endif
+
+#ifdef CONFIG_ARCNET_1051
+ struct device *sdev; /* RFC1051 protocol device */
+#endif
+};
+
+/* Functions exported by arcnet.c
+ */
+
+#if ARCNET_DEBUG_MAX & D_SKB
+extern void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
+ char *desc);
+#else
+#define arcnet_dump_skb(dev,skb,desc) ;
+#endif
+
+#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
+extern void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
+ char *desc);
+#else
+#define arcnet_dump_packet(dev,buffer,ext,desc) ;
+#endif
+
+extern void arcnet_tx_done(struct device *dev, struct arcnet_local *lp);
+extern void arcnet_makename(char *device);
+extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+extern void arcnet_setup(struct device *dev);
+extern int arcnet_go_tx(struct device *dev,int enable_irq);
+extern void arcnetA_continue_tx(struct device *dev);
+extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
+extern void arcnet_use_count(int open);
+
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_ARCDEVICE_H */
diff --git a/pfinet/linux-src/include/linux/atalk.h b/pfinet/linux-src/include/linux/atalk.h
new file mode 100644
index 00000000..e9d20979
--- /dev/null
+++ b/pfinet/linux-src/include/linux/atalk.h
@@ -0,0 +1,180 @@
+/*
+ * AppleTalk networking structures
+ *
+ * The following are directly referenced from the University Of Michigan
+ * netatalk for compatibility reasons.
+ */
+
+#ifndef __LINUX_ATALK_H__
+#define __LINUX_ATALK_H__
+
+#define ATPORT_FIRST 1
+#define ATPORT_RESERVED 128
+#define ATPORT_LAST 254 /* 254 is only legal on localtalk */
+#define ATADDR_ANYNET (__u16)0
+#define ATADDR_ANYNODE (__u8)0
+#define ATADDR_ANYPORT (__u8)0
+#define ATADDR_BCAST (__u8)255
+#define DDP_MAXSZ 587
+#define DDP_MAXHOPS 15 /* 4 bits of hop counter */
+
+#define SIOCATALKDIFADDR (SIOCPROTOPRIVATE + 0)
+
+struct at_addr
+{
+ __u16 s_net;
+ __u8 s_node;
+};
+
+struct sockaddr_at
+{
+ sa_family_t sat_family;
+ __u8 sat_port;
+ struct at_addr sat_addr;
+ char sat_zero[ 8 ];
+};
+
+struct netrange
+{
+ __u8 nr_phase;
+ __u16 nr_firstnet;
+ __u16 nr_lastnet;
+};
+
+struct atalk_route
+{
+ struct device *dev;
+ struct at_addr target;
+ struct at_addr gateway;
+ int flags;
+ struct atalk_route *next;
+};
+
+struct atalk_iface
+{
+ struct device *dev;
+ struct at_addr address; /* Our address */
+ int status; /* What are we doing? */
+#define ATIF_PROBE 1 /* Probing for an address */
+#define ATIF_PROBE_FAIL 2 /* Probe collided */
+ struct netrange nets; /* Associated direct netrange */
+ struct atalk_iface *next;
+};
+
+struct atalk_sock
+{
+ unsigned short dest_net;
+ unsigned short src_net;
+ unsigned char dest_node;
+ unsigned char src_node;
+ unsigned char dest_port;
+ unsigned char src_port;
+};
+
+#ifdef __KERNEL__
+
+#include <asm/byteorder.h>
+
+struct ddpehdr
+{
+#ifdef __LITTLE_ENDIAN_BITFIELD
+ __u16 deh_len:10, deh_hops:4, deh_pad:2;
+#else
+ __u16 deh_pad:2, deh_hops:4, deh_len:10;
+#endif
+ __u16 deh_sum;
+ __u16 deh_dnet;
+ __u16 deh_snet;
+ __u8 deh_dnode;
+ __u8 deh_snode;
+ __u8 deh_dport;
+ __u8 deh_sport;
+ /* And netatalk apps expect to stick the type in themselves */
+};
+
+/*
+ * Don't drop the struct into the struct above. You'll get some
+ * surprise padding.
+ */
+
+struct ddpebits
+{
+#ifdef __LITTLE_ENDIAN_BITFIELD
+ __u16 deh_len:10, deh_hops:4, deh_pad:2;
+#else
+ __u16 deh_pad:2, deh_hops:4, deh_len:10;
+#endif
+};
+
+/*
+ * Short form header
+ */
+
+struct ddpshdr
+{
+#ifdef __LITTLE_ENDIAN_BITFIELD
+ __u16 dsh_len:10, dsh_pad:6;
+#else
+ __u16 dsh_pad:6, dsh_len:10;
+#endif
+ __u8 dsh_dport;
+ __u8 dsh_sport;
+ /* And netatalk apps expect to stick the type in themselves */
+};
+
+/* AppleTalk AARP headers */
+
+struct elapaarp
+{
+ __u16 hw_type;
+#define AARP_HW_TYPE_ETHERNET 1
+#define AARP_HW_TYPE_TOKENRING 2
+ __u16 pa_type;
+ __u8 hw_len;
+ __u8 pa_len;
+#define AARP_PA_ALEN 4
+ __u16 function;
+#define AARP_REQUEST 1
+#define AARP_REPLY 2
+#define AARP_PROBE 3
+ __u8 hw_src[ETH_ALEN] __attribute__ ((packed));
+ __u8 pa_src_zero __attribute__ ((packed));
+ __u16 pa_src_net __attribute__ ((packed));
+ __u8 pa_src_node __attribute__ ((packed));
+ __u8 hw_dst[ETH_ALEN] __attribute__ ((packed));
+ __u8 pa_dst_zero __attribute__ ((packed));
+ __u16 pa_dst_net __attribute__ ((packed));
+ __u8 pa_dst_node __attribute__ ((packed));
+};
+
+#define AARP_EXPIRY_TIME (5*60*HZ) /* Not specified - how long till we drop a resolved entry */
+#define AARP_HASH_SIZE 16 /* Size of hash table */
+#define AARP_TICK_TIME (HZ/5) /* Fast retransmission timer when resolving */
+#define AARP_RETRANSMIT_LIMIT 10 /* Send 10 requests then give up (2 seconds) */
+#define AARP_RESOLVE_TIME (10*HZ) /* Some value bigger than total retransmit time + a bit for last reply to appear and to stop continual requests */
+
+extern struct datalink_proto *ddp_dl, *aarp_dl;
+extern void aarp_proto_init(void);
+/* Inter module exports */
+
+/*
+ * Give a device find its atif control structure
+ */
+
+extern __inline__ struct atalk_iface *atalk_find_dev(struct device *dev)
+{
+ return dev->atalk_ptr;
+}
+
+extern struct at_addr *atalk_find_dev_addr(struct device *dev);
+extern struct device *atrtr_get_dev(struct at_addr *sa);
+extern int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr);
+extern void aarp_send_probe(struct device *dev, struct at_addr *addr);
+extern void aarp_device_down(struct device *dev);
+
+#ifdef MODULE
+extern void aarp_cleanup_module(void);
+#endif /* MODULE */
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_ATALK_H__ */
diff --git a/pfinet/linux-src/include/linux/atari_rootsec.h b/pfinet/linux-src/include/linux/atari_rootsec.h
new file mode 100644
index 00000000..09745f7a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/atari_rootsec.h
@@ -0,0 +1,34 @@
+#ifndef _LINUX_ATARI_ROOTSEC_H
+#define _LINUX_ATARI_ROOTSEC_H
+
+/*
+ * linux/include/linux/atari_rootsec.h
+ * definitions for Atari Rootsector layout
+ * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
+ *
+ * modified for ICD/Supra partitioning scheme restricted to at most 12
+ * partitions
+ * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
+ */
+
+struct partition_info
+{
+ u_char flg; /* bit 0: active; bit 7: bootable */
+ char id[3]; /* "GEM", "BGM", "XGM", or other */
+ u32 st; /* start of partition */
+ u32 siz; /* length of partition */
+};
+
+struct rootsector
+{
+ char unused[0x156]; /* room for boot code */
+ struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */
+ char unused2[0xc];
+ u32 hd_siz; /* size of disk in blocks */
+ struct partition_info part[4];
+ u32 bsl_st; /* start of bad sector list */
+ u32 bsl_cnt; /* length of bad sector list */
+ u16 checksum; /* checksum for bootable disks */
+} __attribute__ ((__packed__));
+
+#endif /* _LINUX_ATARI_ROOTSEC_H */
diff --git a/pfinet/linux-src/include/linux/auto_fs.h b/pfinet/linux-src/include/linux/auto_fs.h
new file mode 100644
index 00000000..9a0ddd6c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/auto_fs.h
@@ -0,0 +1,83 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * linux/include/linux/auto_fs.h
+ *
+ * Copyright 1997 Transmeta Corporation - All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+
+#ifndef _LINUX_AUTO_FS_H
+#define _LINUX_AUTO_FS_H
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/limits.h>
+#include <linux/ioctl.h>
+#include <asm/types.h>
+
+#define AUTOFS_PROTO_VERSION 3
+
+/*
+ * Architectures where both 32- and 64-bit binaries can be executed
+ * on 64-bit kernels need this. This keeps the structure format
+ * uniform, and makes sure the wait_queue_token isn't too big to be
+ * passed back down to the kernel.
+ *
+ * This assumes that on these architectures:
+ * mode 32 bit 64 bit
+ * -------------------------
+ * int 32 bit 32 bit
+ * long 32 bit 64 bit
+ *
+ * If so, 32-bit user-space code should be backwards compatible.
+ */
+
+#if defined(__sparc__) || defined(__mips__)
+typedef unsigned int autofs_wqt_t;
+#else
+typedef unsigned long autofs_wqt_t;
+#endif
+
+enum autofs_packet_type {
+ autofs_ptype_missing, /* Missing entry (mount request) */
+ autofs_ptype_expire, /* Expire entry (umount request) */
+};
+
+struct autofs_packet_hdr {
+ int proto_version; /* Protocol version */
+ enum autofs_packet_type type; /* Type of packet */
+};
+
+struct autofs_packet_missing {
+ struct autofs_packet_hdr hdr;
+ autofs_wqt_t wait_queue_token;
+ int len;
+ char name[NAME_MAX+1];
+};
+
+struct autofs_packet_expire {
+ struct autofs_packet_hdr hdr;
+ int len;
+ char name[NAME_MAX+1];
+};
+
+#define AUTOFS_IOC_READY _IO(0x93,0x60)
+#define AUTOFS_IOC_FAIL _IO(0x93,0x61)
+#define AUTOFS_IOC_CATATONIC _IO(0x93,0x62)
+#define AUTOFS_IOC_PROTOVER _IOR(0x93,0x63,int)
+#define AUTOFS_IOC_SETTIMEOUT _IOWR(0x93,0x64,unsigned long)
+#define AUTOFS_IOC_EXPIRE _IOR(0x93,0x65,struct autofs_packet_expire)
+
+#ifdef __KERNEL__
+
+/* Init function */
+int init_autofs_fs(void);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_AUTO_FS_H */
diff --git a/pfinet/linux-src/include/linux/awe_voice.h b/pfinet/linux-src/include/linux/awe_voice.h
new file mode 100644
index 00000000..aed60f5c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/awe_voice.h
@@ -0,0 +1,524 @@
+/*
+ * sound/awe_voice.h
+ *
+ * Voice information definitions for the low level driver for the
+ * AWE32/SB32/AWE64 wave table synth.
+ * version 0.4.3; Feb. 1, 1999
+ *
+ * Copyright (C) 1996-1999 Takashi Iwai
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef AWE_VOICE_H
+#define AWE_VOICE_H
+
+#ifndef SAMPLE_TYPE_AWE32
+#define SAMPLE_TYPE_AWE32 0x20
+#endif
+
+#ifndef _PATCHKEY
+#define _PATCHKEY(id) ((id<<8)|0xfd)
+#endif
+
+/*----------------------------------------------------------------
+ * patch information record
+ *----------------------------------------------------------------*/
+
+/* patch interface header: 16 bytes */
+typedef struct awe_patch_info {
+ short key; /* use AWE_PATCH here */
+#define AWE_PATCH _PATCHKEY(0x07)
+
+ short device_no; /* synthesizer number */
+ unsigned short sf_id; /* file id (should be zero) */
+ short optarg; /* optional argument */
+ int len; /* data length (without this header) */
+
+ short type; /* patch operation type */
+#define AWE_LOAD_INFO 0 /* awe_voice_rec */
+#define AWE_LOAD_DATA 1 /* awe_sample_info */
+#define AWE_OPEN_PATCH 2 /* awe_open_parm */
+#define AWE_CLOSE_PATCH 3 /* none */
+#define AWE_UNLOAD_PATCH 4 /* none */
+#define AWE_REPLACE_DATA 5 /* awe_sample_info (optarg=#channels)*/
+#define AWE_MAP_PRESET 6 /* awe_voice_map */
+/*#define AWE_PROBE_INFO 7*/ /* awe_voice_map (pat only) */
+#define AWE_PROBE_DATA 8 /* optarg=sample */
+#define AWE_LOAD_CHORUS_FX 0x10 /* awe_chorus_fx_rec (optarg=mode) */
+#define AWE_LOAD_REVERB_FX 0x11 /* awe_reverb_fx_rec (optarg=mode) */
+
+ short reserved; /* word alignment data */
+
+ /* the actual patch data begins after this */
+#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
+ char data[0];
+#endif
+} awe_patch_info;
+
+/*#define AWE_PATCH_INFO_SIZE 16*/
+#define AWE_PATCH_INFO_SIZE sizeof(awe_patch_info)
+
+
+/*----------------------------------------------------------------
+ * open patch
+ *----------------------------------------------------------------*/
+
+#define AWE_PATCH_NAME_LEN 32
+
+typedef struct _awe_open_parm {
+ unsigned short type; /* sample type */
+#define AWE_PAT_TYPE_MISC 0
+#define AWE_PAT_TYPE_GM 1
+#define AWE_PAT_TYPE_GS 2
+#define AWE_PAT_TYPE_MT32 3
+#define AWE_PAT_TYPE_XG 4
+#define AWE_PAT_TYPE_SFX 5
+#define AWE_PAT_TYPE_GUS 6
+#define AWE_PAT_TYPE_MAP 7
+
+#define AWE_PAT_LOCKED 0x100 /* lock the samples */
+#define AWE_PAT_SHARED 0x200 /* sample is shared */
+
+ short reserved;
+ char name[AWE_PATCH_NAME_LEN];
+} awe_open_parm;
+
+/*#define AWE_OPEN_PARM_SIZE 28*/
+#define AWE_OPEN_PARM_SIZE sizeof(awe_open_parm)
+
+
+/*----------------------------------------------------------------
+ * raw voice information record
+ *----------------------------------------------------------------*/
+
+/* wave table envelope & effect parameters to control EMU8000 */
+typedef struct _awe_voice_parm {
+ unsigned short moddelay; /* modulation delay (0x8000) */
+ unsigned short modatkhld; /* modulation attack & hold time (0x7f7f) */
+ unsigned short moddcysus; /* modulation decay & sustain (0x7f7f) */
+ unsigned short modrelease; /* modulation release time (0x807f) */
+ short modkeyhold, modkeydecay; /* envelope change per key (not used) */
+ unsigned short voldelay; /* volume delay (0x8000) */
+ unsigned short volatkhld; /* volume attack & hold time (0x7f7f) */
+ unsigned short voldcysus; /* volume decay & sustain (0x7f7f) */
+ unsigned short volrelease; /* volume release time (0x807f) */
+ short volkeyhold, volkeydecay; /* envelope change per key (not used) */
+ unsigned short lfo1delay; /* LFO1 delay (0x8000) */
+ unsigned short lfo2delay; /* LFO2 delay (0x8000) */
+ unsigned short pefe; /* modulation pitch & cutoff (0x0000) */
+ unsigned short fmmod; /* LFO1 pitch & cutoff (0x0000) */
+ unsigned short tremfrq; /* LFO1 volume & freq (0x0000) */
+ unsigned short fm2frq2; /* LFO2 pitch & freq (0x0000) */
+ unsigned char cutoff; /* initial cutoff (0xff) */
+ unsigned char filterQ; /* initial filter Q [0-15] (0x0) */
+ unsigned char chorus; /* chorus send (0x00) */
+ unsigned char reverb; /* reverb send (0x00) */
+ unsigned short reserved[4]; /* not used */
+} awe_voice_parm;
+
+typedef struct _awe_voice_parm_block {
+ unsigned short moddelay; /* modulation delay (0x8000) */
+ unsigned char modatk, modhld;
+ unsigned char moddcy, modsus;
+ unsigned char modrel, moddummy;
+ short modkeyhold, modkeydecay; /* envelope change per key (not used) */
+ unsigned short voldelay; /* volume delay (0x8000) */
+ unsigned char volatk, volhld;
+ unsigned char voldcy, volsus;
+ unsigned char volrel, voldummy;
+ short volkeyhold, volkeydecay; /* envelope change per key (not used) */
+ unsigned short lfo1delay; /* LFO1 delay (0x8000) */
+ unsigned short lfo2delay; /* LFO2 delay (0x8000) */
+ unsigned char env1fc, env1pit;
+ unsigned char lfo1fc, lfo1pit;
+ unsigned char lfo1freq, lfo1vol;
+ unsigned char lfo2freq, lfo2pit;
+ unsigned char cutoff; /* initial cutoff (0xff) */
+ unsigned char filterQ; /* initial filter Q [0-15] (0x0) */
+ unsigned char chorus; /* chorus send (0x00) */
+ unsigned char reverb; /* reverb send (0x00) */
+ unsigned short reserved[4]; /* not used */
+} awe_voice_parm_block;
+
+#define AWE_VOICE_PARM_SIZE 48
+
+
+/* wave table parameters: 92 bytes */
+typedef struct _awe_voice_info {
+ unsigned short sf_id; /* file id (should be zero) */
+ unsigned short sample; /* sample id */
+ int start, end; /* sample offset correction */
+ int loopstart, loopend; /* loop offset correction */
+ short rate_offset; /* sample rate pitch offset */
+ unsigned short mode; /* sample mode */
+#define AWE_MODE_ROMSOUND 0x8000
+#define AWE_MODE_STEREO 1
+#define AWE_MODE_LOOPING 2
+#define AWE_MODE_NORELEASE 4 /* obsolete */
+#define AWE_MODE_INIT_PARM 8
+
+ short root; /* midi root key */
+ short tune; /* pitch tuning (in cents) */
+ char low, high; /* key note range */
+ char vellow, velhigh; /* velocity range */
+ char fixkey, fixvel; /* fixed key, velocity */
+ char pan, fixpan; /* panning, fixed panning */
+ short exclusiveClass; /* exclusive class (0 = none) */
+ unsigned char amplitude; /* sample volume (127 max) */
+ unsigned char attenuation; /* attenuation (0.375dB) */
+ short scaleTuning; /* pitch scale tuning(%), normally 100 */
+ awe_voice_parm parm; /* voice envelope parameters */
+ short index; /* internal index (set by driver) */
+} awe_voice_info;
+
+/*#define AWE_VOICE_INFO_SIZE 92*/
+#define AWE_VOICE_INFO_SIZE sizeof(awe_voice_info)
+
+/*----------------------------------------------------------------*/
+
+/* The info entry of awe_voice_rec is changed from 0 to 1
+ * for some compilers refusing zero size array.
+ * Due to this change, sizeof(awe_voice_rec) becomes different
+ * from older versions.
+ * Use AWE_VOICE_REC_SIZE instead.
+ */
+
+/* instrument info header: 4 bytes */
+typedef struct _awe_voice_rec_hdr {
+ unsigned char bank; /* midi bank number */
+ unsigned char instr; /* midi preset number */
+ char nvoices; /* number of voices */
+ char write_mode; /* write mode; normally 0 */
+#define AWE_WR_APPEND 0 /* append anyway */
+#define AWE_WR_EXCLUSIVE 1 /* skip if already exists */
+#define AWE_WR_REPLACE 2 /* replace if already exists */
+} awe_voice_rec_hdr;
+
+/*#define AWE_VOICE_REC_SIZE 4*/
+#define AWE_VOICE_REC_SIZE sizeof(awe_voice_rec_hdr)
+
+/* the standard patch structure for one sample */
+typedef struct _awe_voice_rec_patch {
+ awe_patch_info patch;
+ awe_voice_rec_hdr hdr;
+ awe_voice_info info;
+} awe_voice_rec_patch;
+
+
+/* obsolete data type */
+#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
+#define AWE_INFOARRAY_SIZE 0
+#else
+#define AWE_INFOARRAY_SIZE 1
+#endif
+
+typedef struct _awe_voice_rec {
+ unsigned char bank; /* midi bank number */
+ unsigned char instr; /* midi preset number */
+ short nvoices; /* number of voices */
+ /* voice information follows here */
+ awe_voice_info info[AWE_INFOARRAY_SIZE];
+} awe_voice_rec;
+
+
+/*----------------------------------------------------------------
+ * sample wave information
+ *----------------------------------------------------------------*/
+
+/* wave table sample header: 32 bytes */
+typedef struct awe_sample_info {
+ unsigned short sf_id; /* file id (should be zero) */
+ unsigned short sample; /* sample id */
+ int start, end; /* start & end offset */
+ int loopstart, loopend; /* loop start & end offset */
+ int size; /* size (0 = ROM) */
+ short checksum_flag; /* use check sum = 1 */
+ unsigned short mode_flags; /* mode flags */
+#define AWE_SAMPLE_8BITS 1 /* wave data is 8bits */
+#define AWE_SAMPLE_UNSIGNED 2 /* wave data is unsigned */
+#define AWE_SAMPLE_NO_BLANK 4 /* no blank loop is attached */
+#define AWE_SAMPLE_SINGLESHOT 8 /* single-shot w/o loop */
+#define AWE_SAMPLE_BIDIR_LOOP 16 /* bidirectional looping */
+#define AWE_SAMPLE_STEREO_LEFT 32 /* stereo left sound */
+#define AWE_SAMPLE_STEREO_RIGHT 64 /* stereo right sound */
+#define AWE_SAMPLE_REVERSE_LOOP 128 /* reverse looping */
+ unsigned int checksum; /* check sum */
+#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
+ unsigned short data[0]; /* sample data follows here */
+#endif
+} awe_sample_info;
+
+/*#define AWE_SAMPLE_INFO_SIZE 32*/
+#define AWE_SAMPLE_INFO_SIZE sizeof(awe_sample_info)
+
+
+/*----------------------------------------------------------------
+ * voice preset mapping
+ *----------------------------------------------------------------*/
+
+typedef struct awe_voice_map {
+ int map_bank, map_instr, map_key; /* key = -1 means all keys */
+ int src_bank, src_instr, src_key;
+} awe_voice_map;
+
+#define AWE_VOICE_MAP_SIZE sizeof(awe_voice_map)
+
+
+/*----------------------------------------------------------------
+ * awe hardware controls
+ *----------------------------------------------------------------*/
+
+#define _AWE_DEBUG_MODE 0x00
+#define _AWE_REVERB_MODE 0x01
+#define _AWE_CHORUS_MODE 0x02
+#define _AWE_REMOVE_LAST_SAMPLES 0x03
+#define _AWE_INITIALIZE_CHIP 0x04
+#define _AWE_SEND_EFFECT 0x05
+#define _AWE_TERMINATE_CHANNEL 0x06
+#define _AWE_TERMINATE_ALL 0x07
+#define _AWE_INITIAL_VOLUME 0x08
+#define _AWE_INITIAL_ATTEN _AWE_INITIAL_VOLUME
+#define _AWE_RESET_CHANNEL 0x09
+#define _AWE_CHANNEL_MODE 0x0a
+#define _AWE_DRUM_CHANNELS 0x0b
+#define _AWE_MISC_MODE 0x0c
+#define _AWE_RELEASE_ALL 0x0d
+#define _AWE_NOTEOFF_ALL 0x0e
+#define _AWE_CHN_PRESSURE 0x0f
+/*#define _AWE_GET_CURRENT_MODE 0x10*/
+#define _AWE_EQUALIZER 0x11
+/*#define _AWE_GET_MISC_MODE 0x12*/
+/*#define _AWE_GET_FONTINFO 0x13*/
+
+#define _AWE_MODE_FLAG 0x80
+#define _AWE_COOKED_FLAG 0x40 /* not supported */
+#define _AWE_MODE_VALUE_MASK 0x3F
+
+/*----------------------------------------------------------------*/
+
+#define _AWE_SET_CMD(p,dev,voice,cmd,p1,p2) \
+{((char*)(p))[0] = SEQ_PRIVATE;\
+ ((char*)(p))[1] = dev;\
+ ((char*)(p))[2] = _AWE_MODE_FLAG|(cmd);\
+ ((char*)(p))[3] = voice;\
+ ((unsigned short*)(p))[2] = p1;\
+ ((unsigned short*)(p))[3] = p2;}
+
+/* buffered access */
+#define _AWE_CMD(dev, voice, cmd, p1, p2) \
+{_SEQ_NEEDBUF(8);\
+ _AWE_SET_CMD(_seqbuf + _seqbufptr, dev, voice, cmd, p1, p2);\
+ _SEQ_ADVBUF(8);}
+
+/* direct access */
+#define _AWE_CMD_NOW(seqfd,dev,voice,cmd,p1,p2) \
+{struct seq_event_rec tmp;\
+ _AWE_SET_CMD(&tmp, dev, voice, cmd, p1, p2);\
+ ioctl(seqfd, SNDCTL_SEQ_OUTOFBAND, &tmp);}
+
+/*----------------------------------------------------------------*/
+
+/* set debugging mode */
+#define AWE_DEBUG_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_DEBUG_MODE, p1, 0)
+/* set reverb mode; from 0 to 7 */
+#define AWE_REVERB_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_REVERB_MODE, p1, 0)
+/* set chorus mode; from 0 to 7 */
+#define AWE_CHORUS_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_CHORUS_MODE, p1, 0)
+
+/* reset channel */
+#define AWE_RESET_CHANNEL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 0, 0)
+#define AWE_RESET_CONTROL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 1, 0)
+
+/* send an effect to all layers */
+#define AWE_SEND_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,type,value)
+#define AWE_ADD_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x80),value)
+#define AWE_UNSET_EFFECT(dev,voice,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x40),0)
+/* send an effect to a layer */
+#define AWE_SEND_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)),value)
+#define AWE_ADD_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x80),value)
+#define AWE_UNSET_LAYER_EFFECT(dev,voice,layer,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x40),0)
+
+/* terminate sound on the channel/voice */
+#define AWE_TERMINATE_CHANNEL(dev,voice) _AWE_CMD(dev,voice,_AWE_TERMINATE_CHANNEL,0,0)
+/* terminate all sounds */
+#define AWE_TERMINATE_ALL(dev) _AWE_CMD(dev, 0, _AWE_TERMINATE_ALL, 0, 0)
+/* release all sounds (w/o sustain effect) */
+#define AWE_RELEASE_ALL(dev) _AWE_CMD(dev, 0, _AWE_RELEASE_ALL, 0, 0)
+/* note off all sounds (w sustain effect) */
+#define AWE_NOTEOFF_ALL(dev) _AWE_CMD(dev, 0, _AWE_NOTEOFF_ALL, 0, 0)
+
+/* set initial attenuation */
+#define AWE_INITIAL_VOLUME(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 0)
+#define AWE_INITIAL_ATTEN AWE_INITIAL_VOLUME
+/* relative attenuation */
+#define AWE_SET_ATTEN(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 1)
+
+/* set channel playing mode; mode=0/1/2 */
+#define AWE_SET_CHANNEL_MODE(dev,mode) _AWE_CMD(dev, 0, _AWE_CHANNEL_MODE, mode, 0)
+#define AWE_PLAY_INDIRECT 0 /* indirect voice mode (default) */
+#define AWE_PLAY_MULTI 1 /* multi note voice mode */
+#define AWE_PLAY_DIRECT 2 /* direct single voice mode */
+#define AWE_PLAY_MULTI2 3 /* sequencer2 mode; used internally */
+
+/* set drum channel mask; channels is 32bit long value */
+#define AWE_DRUM_CHANNELS(dev,channels) _AWE_CMD(dev, 0, _AWE_DRUM_CHANNELS, ((channels) & 0xffff), ((channels) >> 16))
+
+/* set bass and treble control; values are from 0 to 11 */
+#define AWE_EQUALIZER(dev,bass,treble) _AWE_CMD(dev, 0, _AWE_EQUALIZER, bass, treble)
+
+/* remove last loaded samples */
+#define AWE_REMOVE_LAST_SAMPLES(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_REMOVE_LAST_SAMPLES, 0, 0)
+/* initialize emu8000 chip */
+#define AWE_INITIALIZE_CHIP(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_INITIALIZE_CHIP, 0, 0)
+
+/* set miscellaneous modes; meta command */
+#define AWE_MISC_MODE(dev,mode,value) _AWE_CMD(dev, 0, _AWE_MISC_MODE, mode, value)
+/* exclusive sound off; 1=off */
+#define AWE_EXCLUSIVE_SOUND(dev,mode) AWE_MISC_MODE(dev,AWE_MD_EXCLUSIVE_SOUND,mode)
+/* default GUS bank number */
+#define AWE_SET_GUS_BANK(dev,bank) AWE_MISC_MODE(dev,AWE_MD_GUS_BANK,bank)
+/* change panning position in realtime; 0=don't 1=do */
+#define AWE_REALTIME_PAN(dev,mode) AWE_MISC_MODE(dev,AWE_MD_REALTIME_PAN,mode)
+
+/* extended pressure controls; not portable with other sound drivers */
+#define AWE_KEY_PRESSURE(dev,ch,note,vel) SEQ_START_NOTE(dev,ch,(note)+128,vel)
+#define AWE_CHN_PRESSURE(dev,ch,vel) _AWE_CMD(dev,ch,_AWE_CHN_PRESSURE,vel,0)
+
+/*----------------------------------------------------------------*/
+
+/* reverb mode parameters */
+#define AWE_REVERB_ROOM1 0
+#define AWE_REVERB_ROOM2 1
+#define AWE_REVERB_ROOM3 2
+#define AWE_REVERB_HALL1 3
+#define AWE_REVERB_HALL2 4
+#define AWE_REVERB_PLATE 5
+#define AWE_REVERB_DELAY 6
+#define AWE_REVERB_PANNINGDELAY 7
+#define AWE_REVERB_PREDEFINED 8
+/* user can define reverb modes up to 32 */
+#define AWE_REVERB_NUMBERS 32
+
+typedef struct awe_reverb_fx_rec {
+ unsigned short parms[28];
+} awe_reverb_fx_rec;
+
+/*----------------------------------------------------------------*/
+
+/* chorus mode parameters */
+#define AWE_CHORUS_1 0
+#define AWE_CHORUS_2 1
+#define AWE_CHORUS_3 2
+#define AWE_CHORUS_4 3
+#define AWE_CHORUS_FEEDBACK 4
+#define AWE_CHORUS_FLANGER 5
+#define AWE_CHORUS_SHORTDELAY 6
+#define AWE_CHORUS_SHORTDELAY2 7
+#define AWE_CHORUS_PREDEFINED 8
+/* user can define chorus modes up to 32 */
+#define AWE_CHORUS_NUMBERS 32
+
+typedef struct awe_chorus_fx_rec {
+ unsigned short feedback; /* feedback level (0xE600-0xE6FF) */
+ unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */
+ unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */
+ unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
+ unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */
+} awe_chorus_fx_rec;
+
+/*----------------------------------------------------------------*/
+
+/* misc mode types */
+enum {
+/* 0*/ AWE_MD_EXCLUSIVE_OFF, /* obsolete */
+/* 1*/ AWE_MD_EXCLUSIVE_ON, /* obsolete */
+/* 2*/ AWE_MD_VERSION, /* read only */
+/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* 0/1: exclusive note on (default=1) */
+/* 4*/ AWE_MD_REALTIME_PAN, /* 0/1: do realtime pan change (default=1) */
+/* 5*/ AWE_MD_GUS_BANK, /* bank number for GUS patches (default=0) */
+/* 6*/ AWE_MD_KEEP_EFFECT, /* 0/1: keep effect values, (default=0) */
+/* 7*/ AWE_MD_ZERO_ATTEN, /* attenuation of max volume (default=32) */
+/* 8*/ AWE_MD_CHN_PRIOR, /* 0/1: set MIDI channel priority mode (default=1) */
+/* 9*/ AWE_MD_MOD_SENSE, /* integer: modwheel sensitivity (def=18) */
+/*10*/ AWE_MD_DEF_PRESET, /* integer: default preset number (def=0) */
+/*11*/ AWE_MD_DEF_BANK, /* integer: default bank number (def=0) */
+/*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number (def=0) */
+/*13*/ AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */
+/*14*/ AWE_MD_NEW_VOLUME_CALC, /* 0/1: volume calculation mode (def=1) */
+/*15*/ AWE_MD_CHORUS_MODE, /* integer: chorus mode (def=2) */
+/*16*/ AWE_MD_REVERB_MODE, /* integer: chorus mode (def=4) */
+/*17*/ AWE_MD_BASS_LEVEL, /* integer: bass level (def=5) */
+/*18*/ AWE_MD_TREBLE_LEVEL, /* integer: treble level (def=9) */
+/*19*/ AWE_MD_DEBUG_MODE, /* integer: debug level (def=0) */
+/*20*/ AWE_MD_PAN_EXCHANGE, /* 0/1: exchange panning direction (def=0) */
+ AWE_MD_END,
+};
+
+/*----------------------------------------------------------------*/
+
+/* effect parameters */
+enum {
+
+/* modulation envelope parameters */
+/* 0*/ AWE_FX_ENV1_DELAY, /* WORD: ENVVAL */
+/* 1*/ AWE_FX_ENV1_ATTACK, /* BYTE: up ATKHLD */
+/* 2*/ AWE_FX_ENV1_HOLD, /* BYTE: lw ATKHLD */
+/* 3*/ AWE_FX_ENV1_DECAY, /* BYTE: lw DCYSUS */
+/* 4*/ AWE_FX_ENV1_RELEASE, /* BYTE: lw DCYSUS */
+/* 5*/ AWE_FX_ENV1_SUSTAIN, /* BYTE: up DCYSUS */
+/* 6*/ AWE_FX_ENV1_PITCH, /* BYTE: up PEFE */
+/* 7*/ AWE_FX_ENV1_CUTOFF, /* BYTE: lw PEFE */
+
+/* volume envelope parameters */
+/* 8*/ AWE_FX_ENV2_DELAY, /* WORD: ENVVOL */
+/* 9*/ AWE_FX_ENV2_ATTACK, /* BYTE: up ATKHLDV */
+/*10*/ AWE_FX_ENV2_HOLD, /* BYTE: lw ATKHLDV */
+/*11*/ AWE_FX_ENV2_DECAY, /* BYTE: lw DCYSUSV */
+/*12*/ AWE_FX_ENV2_RELEASE, /* BYTE: lw DCYSUSV */
+/*13*/ AWE_FX_ENV2_SUSTAIN, /* BYTE: up DCYSUSV */
+
+/* LFO1 (tremolo & vibrato) parameters */
+/*14*/ AWE_FX_LFO1_DELAY, /* WORD: LFO1VAL */
+/*15*/ AWE_FX_LFO1_FREQ, /* BYTE: lo TREMFRQ */
+/*16*/ AWE_FX_LFO1_VOLUME, /* BYTE: up TREMFRQ */
+/*17*/ AWE_FX_LFO1_PITCH, /* BYTE: up FMMOD */
+/*18*/ AWE_FX_LFO1_CUTOFF, /* BYTE: lo FMMOD */
+
+/* LFO2 (vibrato) parameters */
+/*19*/ AWE_FX_LFO2_DELAY, /* WORD: LFO2VAL */
+/*20*/ AWE_FX_LFO2_FREQ, /* BYTE: lo FM2FRQ2 */
+/*21*/ AWE_FX_LFO2_PITCH, /* BYTE: up FM2FRQ2 */
+
+/* Other overall effect parameters */
+/*22*/ AWE_FX_INIT_PITCH, /* SHORT: pitch offset */
+/*23*/ AWE_FX_CHORUS, /* BYTE: chorus effects send (0-255) */
+/*24*/ AWE_FX_REVERB, /* BYTE: reverb effects send (0-255) */
+/*25*/ AWE_FX_CUTOFF, /* BYTE: up IFATN */
+/*26*/ AWE_FX_FILTERQ, /* BYTE: up CCCA */
+
+/* Sample / loop offset changes */
+/*27*/ AWE_FX_SAMPLE_START, /* SHORT: offset */
+/*28*/ AWE_FX_LOOP_START, /* SHORT: offset */
+/*29*/ AWE_FX_LOOP_END, /* SHORT: offset */
+/*30*/ AWE_FX_COARSE_SAMPLE_START, /* SHORT: upper word offset */
+/*31*/ AWE_FX_COARSE_LOOP_START, /* SHORT: upper word offset */
+/*32*/ AWE_FX_COARSE_LOOP_END, /* SHORT: upper word offset */
+/*33*/ AWE_FX_ATTEN, /* BYTE: lo IFATN */
+
+ AWE_FX_END,
+};
+
+#endif /* AWE_VOICE_H */
diff --git a/pfinet/linux-src/include/linux/ax25.h b/pfinet/linux-src/include/linux/ax25.h
new file mode 100644
index 00000000..1e492c8f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ax25.h
@@ -0,0 +1,98 @@
+/*
+ * These are the public elements of the Linux kernel AX.25 code. A similar
+ * file netrom.h exists for the NET/ROM protocol.
+ */
+
+#ifndef AX25_KERNEL_H
+#define AX25_KERNEL_H
+
+#define AX25_MTU 256
+#define AX25_MAX_DIGIS 8
+
+#define AX25_WINDOW 1
+#define AX25_T1 2
+#define AX25_N2 3
+#define AX25_T3 4
+#define AX25_T2 5
+#define AX25_BACKOFF 6
+#define AX25_EXTSEQ 7
+#define AX25_PIDINCL 8
+#define AX25_IDLE 9
+#define AX25_PACLEN 10
+#define AX25_IAMDIGI 12
+
+#define AX25_KILL 99
+
+#define SIOCAX25GETUID (SIOCPROTOPRIVATE+0)
+#define SIOCAX25ADDUID (SIOCPROTOPRIVATE+1)
+#define SIOCAX25DELUID (SIOCPROTOPRIVATE+2)
+#define SIOCAX25NOUID (SIOCPROTOPRIVATE+3)
+#define SIOCAX25OPTRT (SIOCPROTOPRIVATE+7)
+#define SIOCAX25CTLCON (SIOCPROTOPRIVATE+8)
+#define SIOCAX25GETINFO (SIOCPROTOPRIVATE+9)
+#define SIOCAX25ADDFWD (SIOCPROTOPRIVATE+10)
+#define SIOCAX25DELFWD (SIOCPROTOPRIVATE+11)
+
+#define AX25_SET_RT_IPMODE 2
+
+#define AX25_NOUID_DEFAULT 0
+#define AX25_NOUID_BLOCK 1
+
+typedef struct {
+ char ax25_call[7]; /* 6 call + SSID (shifted ascii!) */
+} ax25_address;
+
+struct sockaddr_ax25 {
+ sa_family_t sax25_family;
+ ax25_address sax25_call;
+ int sax25_ndigis;
+ /* Digipeater ax25_address sets follow */
+};
+
+#define sax25_uid sax25_ndigis
+
+struct full_sockaddr_ax25 {
+ struct sockaddr_ax25 fsa_ax25;
+ ax25_address fsa_digipeater[AX25_MAX_DIGIS];
+};
+
+struct ax25_routes_struct {
+ ax25_address port_addr;
+ ax25_address dest_addr;
+ unsigned char digi_count;
+ ax25_address digi_addr[AX25_MAX_DIGIS];
+};
+
+struct ax25_route_opt_struct {
+ ax25_address port_addr;
+ ax25_address dest_addr;
+ int cmd;
+ int arg;
+};
+
+struct ax25_ctl_struct {
+ ax25_address port_addr;
+ ax25_address source_addr;
+ ax25_address dest_addr;
+ unsigned int cmd;
+ unsigned long arg;
+ unsigned char digi_count;
+ ax25_address digi_addr[AX25_MAX_DIGIS];
+};
+
+struct ax25_info_struct {
+ unsigned int n2, n2count;
+ unsigned int t1, t1timer;
+ unsigned int t2, t2timer;
+ unsigned int t3, t3timer;
+ unsigned int idle, idletimer;
+ unsigned int state;
+ unsigned int rcv_q, snd_q;
+};
+
+struct ax25_fwd_struct {
+ ax25_address port_from;
+ ax25_address port_to;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/b1lli.h b/pfinet/linux-src/include/linux/b1lli.h
new file mode 100644
index 00000000..388ff80c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/b1lli.h
@@ -0,0 +1,136 @@
+/*
+ * $Id: b1lli.h,v 1.8 1999/07/01 15:26:54 calle Exp $
+ *
+ * ISDN lowlevel-module for AVM B1-card.
+ *
+ * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1lli.h,v $
+ * Revision 1.8 1999/07/01 15:26:54 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ * Revision 1.7 1999/06/21 15:24:25 calle
+ * extend information in /proc.
+ *
+ * Revision 1.6 1999/04/15 19:49:36 calle
+ * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ...
+ *
+ * Revision 1.5 1998/10/25 14:50:28 fritz
+ * Backported from MIPS (Cobalt).
+ *
+ * Revision 1.4 1998/03/29 16:05:02 calle
+ * changes from 2.0 tree merged.
+ *
+ * Revision 1.1.2.9 1998/03/20 14:30:02 calle
+ * added cardnr to detect if you try to add same T1 to different io address.
+ * change number of nccis depending on number of channels.
+ *
+ * Revision 1.1.2.8 1998/03/04 17:32:33 calle
+ * Changes for T1.
+ *
+ * Revision 1.1.2.7 1998/02/27 15:38:29 calle
+ * T1 running with slow link.
+ *
+ * Revision 1.1.2.6 1998/02/24 17:57:36 calle
+ * changes for T1.
+ *
+ * Revision 1.3 1998/01/31 10:54:37 calle
+ * include changes for PCMCIA cards from 2.0 version
+ *
+ * Revision 1.2 1997/12/10 19:38:42 calle
+ * get changes from 2.0 tree
+ *
+ * Revision 1.1.2.2 1997/11/26 16:57:26 calle
+ * more changes for B1/M1/T1.
+ *
+ * Revision 1.1.2.1 1997/11/26 10:47:01 calle
+ * prepared for M1 (Mobile) and T1 (PMX) cards.
+ * prepared to set configuration after load to support other D-channel
+ * protocols, point-to-point and leased lines.
+ *
+ * Revision 1.1 1997/03/04 21:27:32 calle
+ * First version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ */
+
+#ifndef _B1LLI_H_
+#define _B1LLI_H_
+/*
+ * struct for loading t4 file
+ */
+typedef struct avmb1_t4file {
+ int len;
+ unsigned char *data;
+} avmb1_t4file;
+
+typedef struct avmb1_loaddef {
+ int contr;
+ avmb1_t4file t4file;
+} avmb1_loaddef;
+
+typedef struct avmb1_loadandconfigdef {
+ int contr;
+ avmb1_t4file t4file;
+ avmb1_t4file t4config;
+} avmb1_loadandconfigdef;
+
+typedef struct avmb1_resetdef {
+ int contr;
+} avmb1_resetdef;
+
+typedef struct avmb1_getdef {
+ int contr;
+ int cardtype;
+ int cardstate;
+} avmb1_getdef;
+
+/*
+ * struct for adding new cards
+ */
+typedef struct avmb1_carddef {
+ int port;
+ int irq;
+} avmb1_carddef;
+
+#define AVM_CARDTYPE_B1 0
+#define AVM_CARDTYPE_T1 1
+#define AVM_CARDTYPE_M1 2
+#define AVM_CARDTYPE_M2 3
+
+typedef struct avmb1_extcarddef {
+ int port;
+ int irq;
+ int cardtype;
+ int cardnr; /* for HEMA/T1 */
+} avmb1_extcarddef;
+
+#define AVMB1_LOAD 0 /* load image to card */
+#define AVMB1_ADDCARD 1 /* add a new card */
+#define AVMB1_RESETCARD 2 /* reset a card */
+#define AVMB1_LOAD_AND_CONFIG 3 /* load image and config to card */
+#define AVMB1_ADDCARD_WITH_TYPE 4 /* add a new card, with cardtype */
+#define AVMB1_GET_CARDINFO 5 /* get cardtype */
+#define AVMB1_REMOVECARD 6 /* remove a card (useful for T1) */
+
+#define AVMB1_REGISTERCARD_IS_OBSOLETE
+
+#endif /* _B1LLI_H_ */
diff --git a/pfinet/linux-src/include/linux/b1pcmcia.h b/pfinet/linux-src/include/linux/b1pcmcia.h
new file mode 100644
index 00000000..e13307ba
--- /dev/null
+++ b/pfinet/linux-src/include/linux/b1pcmcia.h
@@ -0,0 +1,36 @@
+/*
+ * $Id: b1pcmcia.h,v 1.1 1999/07/01 15:26:56 calle Exp $
+ *
+ * Exported functions of module b1pcmcia to be called by
+ * avm_cs card services module.
+ *
+ * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1pcmcia.h,v $
+ * Revision 1.1 1999/07/01 15:26:56 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ */
+
+#ifndef _B1PCMCIA_H_
+#define _B1PCMCIA_H_
+
+int b1pcmcia_addcard_b1(unsigned int port, unsigned irq);
+int b1pcmcia_addcard_m1(unsigned int port, unsigned irq);
+int b1pcmcia_addcard_m2(unsigned int port, unsigned irq);
+int b1pcmcia_delcard(unsigned int port, unsigned irq);
+
+#endif /* _B1PCMCIA_H_ */
diff --git a/pfinet/linux-src/include/linux/baycom.h b/pfinet/linux-src/include/linux/baycom.h
new file mode 100644
index 00000000..81249e02
--- /dev/null
+++ b/pfinet/linux-src/include/linux/baycom.h
@@ -0,0 +1,39 @@
+/*
+ * The Linux BAYCOM driver for the Baycom serial 1200 baud modem
+ * and the parallel 9600 baud modem
+ * (C) 1997-1998 by Thomas Sailer, HB9JNX/AE4WA
+ */
+
+#ifndef _BAYCOM_H
+#define _BAYCOM_H
+
+/* -------------------------------------------------------------------- */
+/*
+ * structs for the IOCTL commands
+ */
+
+struct baycom_debug_data {
+ unsigned long debug1;
+ unsigned long debug2;
+ long debug3;
+};
+
+struct baycom_ioctl {
+ int cmd;
+ union {
+ struct baycom_debug_data dbg;
+ } data;
+};
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * ioctl values change for baycom
+ */
+#define BAYCOMCTL_GETDEBUG 0x92
+
+/* -------------------------------------------------------------------- */
+
+#endif /* _BAYCOM_H */
+
+/* --------------------------------------------------------------------- */
diff --git a/pfinet/linux-src/include/linux/binfmts.h b/pfinet/linux-src/include/linux/binfmts.h
new file mode 100644
index 00000000..0d34d35b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/binfmts.h
@@ -0,0 +1,77 @@
+#ifndef _LINUX_BINFMTS_H
+#define _LINUX_BINFMTS_H
+
+#include <linux/ptrace.h>
+#include <linux/capability.h>
+
+/*
+ * MAX_ARG_PAGES defines the number of pages allocated for arguments
+ * and envelope for the new program. 32 should suffice, this gives
+ * a maximum env+arg of 128kB w/4KB pages!
+ */
+#define MAX_ARG_PAGES 32
+
+#ifdef __KERNEL__
+
+/*
+ * This structure is used to hold the arguments that are used when loading binaries.
+ */
+struct linux_binprm{
+ char buf[128];
+ unsigned long page[MAX_ARG_PAGES];
+ unsigned long p;
+ int sh_bang;
+ int java; /* Java binary, prevent recursive invocation */
+ struct dentry * dentry;
+ int e_uid, e_gid;
+ kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
+ int argc, envc;
+ char * filename; /* Name of binary */
+ unsigned long loader, exec;
+};
+
+/*
+ * This structure defines the functions that are used to load the binary formats that
+ * linux accepts.
+ */
+struct linux_binfmt {
+ struct linux_binfmt * next;
+ struct module *module;
+ int (*load_binary)(struct linux_binprm *, struct pt_regs * regs);
+ int (*load_shlib)(int fd);
+ int (*core_dump)(long signr, struct pt_regs * regs);
+};
+
+extern int register_binfmt(struct linux_binfmt *);
+extern int unregister_binfmt(struct linux_binfmt *);
+
+extern int read_exec(struct dentry *, unsigned long offset,
+ char * addr, unsigned long count, int to_kmem);
+
+extern int open_dentry(struct dentry *, int mode);
+
+extern int init_elf_binfmt(void);
+extern int init_elf32_binfmt(void);
+extern int init_irix_binfmt(void);
+extern int init_aout_binfmt(void);
+extern int init_aout32_binfmt(void);
+extern int init_script_binfmt(void);
+extern int init_java_binfmt(void);
+extern int init_em86_binfmt(void);
+extern int init_misc_binfmt(void);
+
+extern int prepare_binprm(struct linux_binprm *);
+extern void remove_arg_zero(struct linux_binprm *);
+extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
+extern int flush_old_exec(struct linux_binprm * bprm);
+extern unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm);
+extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
+ unsigned long p, int from_kmem);
+
+extern void compute_creds(struct linux_binprm *binprm);
+
+/* this eventually goes away */
+#define change_ldt(a,b) setup_arg_pages(a,b)
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_BINFMTS_H */
diff --git a/pfinet/linux-src/include/linux/bios32.h b/pfinet/linux-src/include/linux/bios32.h
new file mode 100644
index 00000000..2f2c14b7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/bios32.h
@@ -0,0 +1,34 @@
+/*
+ * This is only a stub file to make drivers not yet converted to the new
+ * PCI probing mechanism work. [mj]
+ */
+
+#ifndef BIOS32_H
+#define BIOS32_H
+
+#include <linux/pci.h>
+
+#warning This driver uses the old PCI interface, please fix it (see Documentation/pci.txt)
+
+extern inline int __pcibios_read_irq(unsigned char bus, unsigned char dev_fn, unsigned char *to)
+{
+ struct pci_dev *pdev = pci_find_slot(bus, dev_fn);
+ if (!pdev) {
+ *to = 0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else {
+ *to = pdev->irq;
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+extern inline int __pcibios_read_config_byte(unsigned char bus,
+ unsigned char dev_fn, unsigned char where, unsigned char *to)
+{
+ return pcibios_read_config_byte(bus, dev_fn, where, to);
+}
+
+#define pcibios_read_config_byte(b,d,w,p) \
+ (((w) == PCI_INTERRUPT_LINE) ? __pcibios_read_irq(b,d,p) : __pcibios_read_config_byte(b,d,w,p))
+
+#endif
diff --git a/pfinet/linux-src/include/linux/bitops.h b/pfinet/linux-src/include/linux/bitops.h
new file mode 100644
index 00000000..ddb84dd6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/bitops.h
@@ -0,0 +1,72 @@
+#ifndef _LINUX_BITOPS_H
+#define _LINUX_BITOPS_H
+
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int generic_ffs(int x)
+{
+ int r = 1;
+
+ if (!x)
+ return 0;
+ if (!(x & 0xffff)) {
+ x >>= 16;
+ r += 16;
+ }
+ if (!(x & 0xff)) {
+ x >>= 8;
+ r += 8;
+ }
+ if (!(x & 0xf)) {
+ x >>= 4;
+ r += 4;
+ }
+ if (!(x & 3)) {
+ x >>= 2;
+ r += 2;
+ }
+ if (!(x & 1)) {
+ x >>= 1;
+ r += 1;
+ }
+ return r;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+extern __inline__ unsigned int generic_hweight32(unsigned int w)
+{
+ unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+ res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+ res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
+ res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
+ return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
+}
+
+extern __inline__ unsigned int generic_hweight16(unsigned int w)
+{
+ unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
+ res = (res & 0x3333) + ((res >> 2) & 0x3333);
+ res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
+ return (res & 0x00FF) + ((res >> 8) & 0x00FF);
+}
+
+extern __inline__ unsigned int generic_hweight8(unsigned int w)
+{
+ unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
+ res = (res & 0x33) + ((res >> 2) & 0x33);
+ return (res & 0x0F) + ((res >> 4) & 0x0F);
+}
+
+#include <asm/bitops.h>
+
+
+#endif
diff --git a/pfinet/linux-src/include/linux/blk.h b/pfinet/linux-src/include/linux/blk.h
new file mode 100644
index 00000000..44e05c7f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/blk.h
@@ -0,0 +1,489 @@
+#ifndef _BLK_H
+#define _BLK_H
+
+#include <linux/blkdev.h>
+#include <linux/locks.h>
+#include <linux/config.h>
+
+#include <asm/spinlock.h>
+
+/*
+ * Spinlock for protecting the request queue which
+ * is mucked around with in interrupts on potentially
+ * multiple CPU's..
+ */
+extern spinlock_t io_request_lock;
+
+/*
+ * NR_REQUEST is the number of entries in the request-queue.
+ * NOTE that writes may use only the low 2/3 of these: reads
+ * take precedence.
+ */
+#define NR_REQUEST 128
+
+/*
+ * This is used in the elevator algorithm. We don't prioritise reads
+ * over writes any more --- although reads are more time-critical than
+ * writes, by treating them equally we increase filesystem throughput.
+ * This turns out to give better overall performance. -- sct
+ */
+#define IN_ORDER(s1,s2) \
+((s1)->rq_dev < (s2)->rq_dev || (((s1)->rq_dev == (s2)->rq_dev && \
+(s1)->sector < (s2)->sector)))
+
+/*
+ * Initialization functions.
+ */
+extern int isp16_init(void);
+extern int cdu31a_init(void);
+extern int acsi_init(void);
+extern int mcd_init(void);
+extern int mcdx_init(void);
+extern int sbpcd_init(void);
+extern int aztcd_init(void);
+extern int sony535_init(void);
+extern int gscd_init(void);
+extern int cm206_init(void);
+extern int optcd_init(void);
+extern int sjcd_init(void);
+extern int cdi_init(void);
+extern int hd_init(void);
+extern int ide_init(void);
+extern int xd_init(void);
+extern int mfm_init(void);
+extern int loop_init(void);
+extern int md_init(void);
+extern int ap_init(void);
+extern int ddv_init(void);
+extern int z2_init(void);
+extern int swim3_init(void);
+extern int amiga_floppy_init(void);
+extern int atari_floppy_init(void);
+extern int nbd_init(void);
+extern int ez_init(void);
+extern int bpcd_init(void);
+extern int ps2esdi_init(void);
+
+#ifdef CONFIG_ARCH_S390
+extern int mdisk_init(void);
+extern int dasd_init(void);
+#endif /* CONFIG_ARCH_S390 */
+
+extern void set_device_ro(kdev_t dev,int flag);
+void add_blkdev_randomness(int major);
+
+extern int floppy_init(void);
+extern void rd_load(void);
+extern int rd_init(void);
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+#define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */
+
+extern unsigned long initrd_start,initrd_end;
+extern int mount_initrd; /* zero if initrd should not be mounted */
+extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */
+void initrd_init(void);
+
+#endif
+
+#define RO_IOCTLS(dev,where) \
+ case BLKROSET: { int __val; if (!capable(CAP_SYS_ADMIN)) return -EACCES; \
+ if (get_user(__val, (int *)(where))) return -EFAULT; \
+ set_device_ro((dev),__val); return 0; } \
+ case BLKROGET: { int __val = (is_read_only(dev) != 0) ; \
+ return put_user(__val,(int *) (where)); }
+
+/*
+ * end_request() and friends. Must be called with the request queue spinlock
+ * acquired. All functions called within end_request() _must_be_ atomic.
+ *
+ * Several drivers define their own end_request and call
+ * end_that_request_first() and end_that_request_last()
+ * for parts of the original function. This prevents
+ * code duplication in drivers.
+ */
+
+int end_that_request_first(struct request *req, int uptodate, char *name);
+void end_that_request_last(struct request *req);
+
+#if defined(MAJOR_NR) || defined(IDE_DRIVER)
+
+/*
+ * Add entries as needed.
+ */
+
+#ifdef IDE_DRIVER
+
+#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_ON(device) /* nothing */
+#define DEVICE_OFF(device) /* nothing */
+#define DEVICE_NAME "ide"
+
+#elif (MAJOR_NR == RAMDISK_MAJOR)
+
+/* ram disk */
+#define DEVICE_NAME "ramdisk"
+#define DEVICE_REQUEST rd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+#define DEVICE_NO_RANDOM
+
+#elif (MAJOR_NR == Z2RAM_MAJOR)
+
+/* Zorro II Ram */
+#define DEVICE_NAME "Z2RAM"
+#define DEVICE_REQUEST do_z2_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == FLOPPY_MAJOR)
+
+static void floppy_off(unsigned int nr);
+
+#define DEVICE_NAME "floppy"
+#define DEVICE_INTR do_floppy
+#define DEVICE_REQUEST do_fd_request
+#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 ))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
+
+#elif (MAJOR_NR == HD_MAJOR)
+
+/* Hard disk: timeout is 6 seconds. */
+#define DEVICE_NAME "hard disk"
+#define DEVICE_INTR do_hd
+#define DEVICE_TIMEOUT HD_TIMER
+#define TIMEOUT_VALUE (6*HZ)
+#define DEVICE_REQUEST do_hd_request
+#define DEVICE_NR(device) (MINOR(device)>>6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (SCSI_DISK_MAJOR(MAJOR_NR))
+
+#define DEVICE_NAME "scsidisk"
+#define DEVICE_INTR do_sd
+#define TIMEOUT_VALUE (2*HZ)
+#define DEVICE_REQUEST do_sd_request
+#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+/* Kludge to use the same number for both char and block major numbers */
+#elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)
+
+#define DEVICE_NAME "Multiple devices driver"
+#define DEVICE_REQUEST do_md_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == SCSI_TAPE_MAJOR)
+
+#define DEVICE_NAME "scsitape"
+#define DEVICE_INTR do_st
+#define DEVICE_NR(device) (MINOR(device) & 0x7f)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == SCSI_CDROM_MAJOR)
+
+#define DEVICE_NAME "CD-ROM"
+#define DEVICE_INTR do_sr
+#define DEVICE_REQUEST do_sr_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == XT_DISK_MAJOR)
+
+#define DEVICE_NAME "xt disk"
+#define DEVICE_REQUEST do_xd_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == PS2ESDI_MAJOR)
+
+#define DEVICE_NAME "PS/2 ESDI"
+#define DEVICE_REQUEST do_ps2esdi_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
+
+#define DEVICE_NAME "CDU31A"
+#define DEVICE_REQUEST do_cdu31a_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE))
+
+#define DEVICE_NAME "ACSI"
+#define DEVICE_INTR do_acsi
+#define DEVICE_REQUEST do_acsi_request
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
+
+#define DEVICE_NAME "Mitsumi CD-ROM"
+/* #define DEVICE_INTR do_mcd */
+#define DEVICE_REQUEST do_mcd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR)
+
+#define DEVICE_NAME "Mitsumi CD-ROM"
+/* #define DEVICE_INTR do_mcdx */
+#define DEVICE_REQUEST do_mcdx_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #1"
+#define DEVICE_REQUEST do_sbpcd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #2"
+#define DEVICE_REQUEST do_sbpcd2_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #3"
+#define DEVICE_REQUEST do_sbpcd3_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #4"
+#define DEVICE_REQUEST do_sbpcd4_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == AZTECH_CDROM_MAJOR)
+
+#define DEVICE_NAME "Aztech CD-ROM"
+#define DEVICE_REQUEST do_aztcd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == CDU535_CDROM_MAJOR)
+
+#define DEVICE_NAME "SONY-CDU535"
+#define DEVICE_INTR do_cdu535
+#define DEVICE_REQUEST do_cdu535_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR)
+
+#define DEVICE_NAME "Goldstar R420"
+#define DEVICE_REQUEST do_gscd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == CM206_CDROM_MAJOR)
+#define DEVICE_NAME "Philips/LMS CD-ROM cm206"
+#define DEVICE_REQUEST do_cm206_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == OPTICS_CDROM_MAJOR)
+
+#define DEVICE_NAME "DOLPHIN 8000AT CD-ROM"
+#define DEVICE_REQUEST do_optcd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == SANYO_CDROM_MAJOR)
+
+#define DEVICE_NAME "Sanyo H94A CD-ROM"
+#define DEVICE_REQUEST do_sjcd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == APBLOCK_MAJOR)
+
+#define DEVICE_NAME "apblock"
+#define DEVICE_REQUEST ap_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == DDV_MAJOR)
+
+#define DEVICE_NAME "ddv"
+#define DEVICE_REQUEST ddv_request
+#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MFM_ACORN_MAJOR)
+
+#define DEVICE_NAME "mfm disk"
+#define DEVICE_INTR do_mfm
+#define DEVICE_REQUEST do_mfm_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == MFM_ACORN_MAJOR)
+
+#define DEVICE_NAME "mfm disk"
+#define DEVICE_INTR do_mfm
+#define DEVICE_REQUEST do_mfm_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == NBD_MAJOR)
+
+#define DEVICE_NAME "nbd"
+#define DEVICE_REQUEST do_nbd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+
+#elif (MAJOR_NR == MDISK_MAJOR)
+
+#define DEVICE_NAME "mdisk"
+#define DEVICE_REQUEST mdisk_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == DASD_MAJOR)
+
+#define DEVICE_NAME "dasd"
+#define DEVICE_REQUEST do_dasd_request
+#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
+
+#define DEVICE_NAME "ida"
+#define TIMEOUT_VALUE (25*HZ)
+#define DEVICE_REQUEST do_ida_request0
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#endif /* MAJOR_NR == whatever */
+
+#if (MAJOR_NR != SCSI_TAPE_MAJOR)
+#if !defined(IDE_DRIVER)
+
+#ifndef CURRENT
+#define CURRENT (blk_dev[MAJOR_NR].current_request)
+#endif
+
+#ifndef DEVICE_NAME
+#define DEVICE_NAME "unknown"
+#endif
+
+#define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev)
+
+#ifdef DEVICE_INTR
+static void (*DEVICE_INTR)(void) = NULL;
+#endif
+
+#ifdef DEVICE_TIMEOUT
+
+#define SET_TIMER \
+((timer_table[DEVICE_TIMEOUT].expires = jiffies + TIMEOUT_VALUE), \
+(timer_active |= 1<<DEVICE_TIMEOUT))
+
+#define CLEAR_TIMER \
+timer_active &= ~(1<<DEVICE_TIMEOUT)
+
+#define SET_INTR(x) \
+if ((DEVICE_INTR = (x)) != NULL) \
+ SET_TIMER; \
+else \
+ CLEAR_TIMER;
+
+#else
+
+#define SET_INTR(x) (DEVICE_INTR = (x))
+
+#endif /* DEVICE_TIMEOUT */
+
+static void (DEVICE_REQUEST)(void);
+
+#ifdef DEVICE_INTR
+#define CLEAR_INTR SET_INTR(NULL)
+#else
+#define CLEAR_INTR
+#endif
+
+#define INIT_REQUEST \
+ if (!CURRENT) {\
+ CLEAR_INTR; \
+ return; \
+ } \
+ if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \
+ panic(DEVICE_NAME ": request list destroyed"); \
+ if (CURRENT->bh) { \
+ if (!buffer_locked(CURRENT->bh)) \
+ panic(DEVICE_NAME ": block not locked"); \
+ }
+
+#endif /* !defined(IDE_DRIVER) */
+
+#ifndef LOCAL_END_REQUEST /* If we have our own end_request, we do not want to include this mess */
+
+#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR)
+
+static void end_request(int uptodate) {
+ struct request *req = CURRENT;
+
+ if (end_that_request_first(req, uptodate, DEVICE_NAME))
+ return;
+
+#ifndef DEVICE_NO_RANDOM
+ add_blkdev_randomness(MAJOR(req->rq_dev));
+#endif
+ DEVICE_OFF(req->rq_dev);
+ CURRENT = req->next;
+ end_that_request_last(req);
+}
+
+#endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */
+#endif /* LOCAL_END_REQUEST */
+
+#endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) */
+#endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */
+
+#endif /* _BLK_H */
diff --git a/pfinet/linux-src/include/linux/blkdev.h b/pfinet/linux-src/include/linux/blkdev.h
new file mode 100644
index 00000000..87a9092b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/blkdev.h
@@ -0,0 +1,94 @@
+#ifndef _LINUX_BLKDEV_H
+#define _LINUX_BLKDEV_H
+
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/genhd.h>
+#include <linux/tqueue.h>
+
+/*
+ * Ok, this is an expanded form so that we can use the same
+ * request for paging requests when that is implemented. In
+ * paging, 'bh' is NULL, and the semaphore is used to wait
+ * for read/write completion.
+ */
+struct request {
+ volatile int rq_status; /* should split this into a few status bits */
+#define RQ_INACTIVE (-1)
+#define RQ_ACTIVE 1
+#define RQ_SCSI_BUSY 0xffff
+#define RQ_SCSI_DONE 0xfffe
+#define RQ_SCSI_DISCONNECTING 0xffe0
+
+ kdev_t rq_dev;
+ int cmd; /* READ or WRITE */
+ int errors;
+ unsigned long sector;
+ unsigned long nr_sectors;
+ unsigned long nr_segments;
+ unsigned long current_nr_sectors;
+ char * buffer;
+ struct semaphore * sem;
+ struct buffer_head * bh;
+ struct buffer_head * bhtail;
+ struct request * next;
+};
+
+typedef void (request_fn_proc) (void);
+typedef struct request ** (queue_proc) (kdev_t dev);
+
+struct blk_dev_struct {
+ request_fn_proc *request_fn;
+ /*
+ * queue_proc has to be atomic
+ */
+ queue_proc *queue;
+ void *data;
+ struct request *current_request;
+ struct request plug;
+ struct tq_struct plug_tq;
+};
+
+struct sec_size {
+ unsigned block_size;
+ unsigned block_size_bits;
+};
+
+extern struct sec_size * blk_sec[MAX_BLKDEV];
+extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
+extern struct wait_queue * wait_for_request;
+extern void resetup_one_dev(struct gendisk *dev, int drive);
+extern void unplug_device(void * data);
+extern void make_request(int major,int rw, struct buffer_head * bh);
+
+/* md needs this function to remap requests */
+extern int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size);
+extern int md_make_request (int minor, int rw, struct buffer_head * bh);
+extern int md_error (kdev_t mddev, kdev_t rdev);
+
+extern int * blk_size[MAX_BLKDEV];
+
+extern int * blksize_size[MAX_BLKDEV];
+
+extern int * hardsect_size[MAX_BLKDEV];
+
+extern int * max_readahead[MAX_BLKDEV];
+
+extern int * max_sectors[MAX_BLKDEV];
+
+extern int * max_segments[MAX_BLKDEV];
+
+#define MAX_SECTORS 128
+
+#define MAX_SEGMENTS MAX_SECTORS
+
+#define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK)
+#if 0 /* small readahead */
+#define MAX_READAHEAD PageAlignSize(4096*7)
+#define MIN_READAHEAD PageAlignSize(4096*2)
+#else /* large readahead */
+#define MAX_READAHEAD PageAlignSize(4096*31)
+#define MIN_READAHEAD PageAlignSize(4096*3)
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/bpqether.h b/pfinet/linux-src/include/linux/bpqether.h
new file mode 100644
index 00000000..a6c35e1a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/bpqether.h
@@ -0,0 +1,41 @@
+#ifndef __BPQETHER_H
+#define __BPQETHER_H
+
+/*
+ * Defines for the BPQETHER pseudo device driver
+ */
+
+#ifndef __LINUX_IF_ETHER_H
+#include <linux/if_ether.h>
+#endif
+
+#define SIOCSBPQETHOPT (SIOCDEVPRIVATE+0) /* reserved */
+#define SIOCSBPQETHADDR (SIOCDEVPRIVATE+1)
+
+struct bpq_ethaddr {
+ unsigned char destination[ETH_ALEN];
+ unsigned char accept[ETH_ALEN];
+};
+
+/*
+ * For SIOCSBPQETHOPT - this is compatible with PI2/PacketTwin card drivers,
+ * currently not implemented, though. If someone wants to hook a radio
+ * to his Ethernet card he may find this useful. ;-)
+ */
+
+#define SIOCGBPQETHPARAM 0x5000 /* get Level 1 parameters */
+#define SIOCSBPQETHPARAM 0x5001 /* set */
+
+struct bpq_req {
+ int cmd;
+ int speed; /* unused */
+ int clockmode; /* unused */
+ int txdelay;
+ unsigned char persist; /* unused */
+ int slotime; /* unused */
+ int squeldelay;
+ int dmachan; /* unused */
+ int irq; /* unused */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/busmouse.h b/pfinet/linux-src/include/linux/busmouse.h
new file mode 100644
index 00000000..eb71550d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/busmouse.h
@@ -0,0 +1,104 @@
+#ifndef _LINUX_BUSMOUSE_H
+#define _LINUX_BUSMOUSE_H
+
+/*
+ * linux/include/linux/busmouse.h: header file for Logitech Bus Mouse driver
+ * by James Banks
+ *
+ * based on information gleamed from various mouse drivers on the net
+ *
+ * Heavily modified by David giller (rafetmad@oxy.edu)
+ *
+ * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
+ * gt7080a@prism.gatech.edu (13JUL92)
+ *
+ * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92)
+ *
+ * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net)
+ * 8/28/92
+ *
+ * Microsoft Bus Mouse support folded into 0.97pl4 code
+ * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
+ * Changes: Logitech and Microsoft support in the same kernel.
+ * Defined new constants in busmouse.h for MS mice.
+ * Added int mse_busmouse_type to distinguish busmouse types
+ * Added a couple of new functions to handle differences in using
+ * MS vs. Logitech (where the int variable wasn't appropriate).
+ *
+ */
+
+#define MOUSE_IRQ 5
+#define LOGITECH_BUSMOUSE 0 /* Minor device # for Logitech */
+#define MICROSOFT_BUSMOUSE 2 /* Minor device # for Microsoft */
+
+/*--------- LOGITECH BUSMOUSE ITEMS -------------*/
+
+#define LOGIBM_BASE 0x23c
+#define MSE_DATA_PORT 0x23c
+#define MSE_SIGNATURE_PORT 0x23d
+#define MSE_CONTROL_PORT 0x23e
+#define MSE_INTERRUPT_PORT 0x23e
+#define MSE_CONFIG_PORT 0x23f
+#define LOGIBM_EXTENT 0x4
+
+#define MSE_ENABLE_INTERRUPTS 0x00
+#define MSE_DISABLE_INTERRUPTS 0x10
+
+#define MSE_READ_X_LOW 0x80
+#define MSE_READ_X_HIGH 0xa0
+#define MSE_READ_Y_LOW 0xc0
+#define MSE_READ_Y_HIGH 0xe0
+
+/* Magic number used to check if the mouse exists */
+#define MSE_CONFIG_BYTE 0x91
+#define MSE_DEFAULT_MODE 0x90
+#define MSE_SIGNATURE_BYTE 0xa5
+
+/* useful Logitech Mouse macros */
+
+#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
+#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
+
+/*--------- MICROSOFT BUSMOUSE ITEMS -------------*/
+
+#define MSBM_BASE 0x23d
+#define MS_MSE_DATA_PORT 0x23d
+#define MS_MSE_SIGNATURE_PORT 0x23e
+#define MS_MSE_CONTROL_PORT 0x23c
+#define MS_MSE_CONFIG_PORT 0x23f
+#define MSBM_EXTENT 0x3
+
+#define MS_MSE_ENABLE_INTERRUPTS 0x11
+#define MS_MSE_DISABLE_INTERRUPTS 0x10
+
+#define MS_MSE_READ_BUTTONS 0x00
+#define MS_MSE_READ_X 0x01
+#define MS_MSE_READ_Y 0x02
+
+#define MS_MSE_START 0x80
+#define MS_MSE_COMMAND_MODE 0x07
+
+/* useful microsoft busmouse macros */
+
+#define MS_MSE_INT_OFF() {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \
+ outb(MS_MSE_DISABLE_INTERRUPTS, MS_MSE_DATA_PORT);}
+#define MS_MSE_INT_ON() {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \
+ outb(MS_MSE_ENABLE_INTERRUPTS, MS_MSE_DATA_PORT);}
+
+
+struct mouse_status {
+ unsigned char buttons;
+ unsigned char latch_buttons;
+ int dx;
+ int dy;
+ int present;
+ int ready;
+ int active;
+ struct wait_queue *wait;
+ struct fasync_struct *fasyncptr;
+};
+
+/* Function Prototypes */
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/capability.h b/pfinet/linux-src/include/linux/capability.h
new file mode 100644
index 00000000..03c93dad
--- /dev/null
+++ b/pfinet/linux-src/include/linux/capability.h
@@ -0,0 +1,337 @@
+/*
+ * This is <linux/capability.h>
+ *
+ * Andrew G. Morgan <morgan@transmeta.com>
+ * Alexander Kjeldaas <astor@guardian.no>
+ * with help from Aleph1, Roland Buresund and Andrew Main.
+ */
+
+#ifndef _LINUX_CAPABILITY_H
+#define _LINUX_CAPABILITY_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+
+/* User-level do most of the mapping between kernel and user
+ capabilities based on the version tag given by the kernel. The
+ kernel might be somewhat backwards compatible, but don't bet on
+ it. */
+
+/* XXX - Note, cap_t, is defined by POSIX to be an "opaque" pointer to
+ a set of three capability sets. The transposition of 3*the
+ following structure to such a composite is better handled in a user
+ library since the draft standard requires the use of malloc/free
+ etc.. */
+
+#define _LINUX_CAPABILITY_VERSION 0x19980330
+
+typedef struct __user_cap_header_struct {
+ __u32 version;
+ int pid;
+} *cap_user_header_t;
+
+typedef struct __user_cap_data_struct {
+ __u32 effective;
+ __u32 permitted;
+ __u32 inheritable;
+} *cap_user_data_t;
+
+#ifdef __KERNEL__
+
+/* #define STRICT_CAP_T_TYPECHECKS */
+
+#ifdef STRICT_CAP_T_TYPECHECKS
+
+typedef struct kernel_cap_struct {
+ __u32 cap;
+} kernel_cap_t;
+
+#else
+
+typedef __u32 kernel_cap_t;
+
+#endif
+
+#define _USER_CAP_HEADER_SIZE (2*sizeof(__u32))
+#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
+
+#endif
+
+
+/**
+ ** POSIX-draft defined capabilities.
+ **/
+
+/* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
+ overrides the restriction of changing file ownership and group
+ ownership. */
+
+#define CAP_CHOWN 0
+
+/* Override all DAC access, including ACL execute access if
+ [_POSIX_ACL] is defined. Excluding DAC access covered by
+ CAP_LINUX_IMMUTABLE. */
+
+#define CAP_DAC_OVERRIDE 1
+
+/* Overrides all DAC restrictions regarding read and search on files
+ and directories, including ACL restrictions if [_POSIX_ACL] is
+ defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. */
+
+#define CAP_DAC_READ_SEARCH 2
+
+/* Overrides all restrictions about allowed operations on files, where
+ file owner ID must be equal to the user ID, except where CAP_FSETID
+ is applicable. It doesn't override MAC and DAC restrictions. */
+
+#define CAP_FOWNER 3
+
+/* Overrides the following restrictions that the effective user ID
+ shall match the file owner ID when setting the S_ISUID and S_ISGID
+ bits on that file; that the effective group ID (or one of the
+ supplementary group IDs) shall match the file owner ID when setting
+ the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
+ cleared on successful return from chown(2) (not implemented). */
+
+#define CAP_FSETID 4
+
+/* Used to decide between falling back on the old suser() or fsuser(). */
+
+#define CAP_FS_MASK 0x1f
+
+/* Overrides the restriction that the real or effective user ID of a
+ process sending a signal must match the real or effective user ID
+ of the process receiving the signal. */
+
+#define CAP_KILL 5
+
+/* Allows setgid(2) manipulation */
+/* Allows setgroups(2) */
+/* Allows forged gids on socket credentials passing. */
+
+#define CAP_SETGID 6
+
+/* Allows set*uid(2) manipulation (including fsuid). */
+/* Allows forged pids on socket credentials passing. */
+
+#define CAP_SETUID 7
+
+
+/**
+ ** Linux-specific capabilities
+ **/
+
+/* Transfer any capability in your permitted set to any pid,
+ remove any capability in your permitted set from any pid */
+
+#define CAP_SETPCAP 8
+
+/* Allow modification of S_IMMUTABLE and S_APPEND file attributes */
+
+#define CAP_LINUX_IMMUTABLE 9
+
+/* Allows binding to TCP/UDP sockets below 1024 */
+
+#define CAP_NET_BIND_SERVICE 10
+
+/* Allow broadcasting, listen to multicast */
+
+#define CAP_NET_BROADCAST 11
+
+/* Allow interface configuration */
+/* Allow administration of IP firewall, masquerading and accounting */
+/* Allow setting debug option on sockets */
+/* Allow modification of routing tables */
+/* Allow setting arbitrary process / process group ownership on
+ sockets */
+/* Allow binding to any address for transparent proxying */
+/* Allow setting TOS (type of service) */
+/* Allow setting promiscuous mode */
+/* Allow clearing driver statistics */
+/* Allow multicasting */
+/* Allow read/write of device-specific registers */
+
+#define CAP_NET_ADMIN 12
+
+/* Allow use of RAW sockets */
+/* Allow use of PACKET sockets */
+
+#define CAP_NET_RAW 13
+
+/* Allow locking of shared memory segments */
+/* Allow mlock and mlockall (which doesn't really have anything to do
+ with IPC) */
+
+#define CAP_IPC_LOCK 14
+
+/* Override IPC ownership checks */
+
+#define CAP_IPC_OWNER 15
+
+/* Insert and remove kernel modules */
+
+#define CAP_SYS_MODULE 16
+
+/* Allow ioperm/iopl access */
+
+#define CAP_SYS_RAWIO 17
+
+/* Allow use of chroot() */
+
+#define CAP_SYS_CHROOT 18
+
+/* Allow ptrace() of any process */
+
+#define CAP_SYS_PTRACE 19
+
+/* Allow configuration of process accounting */
+
+#define CAP_SYS_PACCT 20
+
+/* Allow configuration of the secure attention key */
+/* Allow administration of the random device */
+/* Allow device administration (mknod)*/
+/* Allow examination and configuration of disk quotas */
+/* Allow configuring the kernel's syslog (printk behaviour) */
+/* Allow setting the domainname */
+/* Allow setting the hostname */
+/* Allow calling bdflush() */
+/* Allow mount() and umount(), setting up new smb connection */
+/* Allow some autofs root ioctls */
+/* Allow nfsservctl */
+/* Allow VM86_REQUEST_IRQ */
+/* Allow to read/write pci config on alpha */
+/* Allow irix_prctl on mips (setstacksize) */
+/* Allow flushing all cache on m68k (sys_cacheflush) */
+/* Allow removing semaphores */
+/* Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores
+ and shared memory */
+/* Allow locking/unlocking of shared memory segment */
+/* Allow turning swap on/off */
+/* Allow forged pids on socket credentials passing */
+/* Allow setting readahead and flushing buffers on block devices */
+/* Allow setting geometry in floppy driver */
+/* Allow turning DMA on/off in xd driver */
+/* Allow administration of md devices (mostly the above, but some
+ extra ioctls) */
+/* Allow tuning the ide driver */
+/* Allow access to the nvram device */
+/* Allow administration of apm_bios, serial and bttv (TV) device */
+/* Allow manufacturer commands in isdn CAPI support driver */
+/* Allow reading non-standardized portions of pci configuration space */
+/* Allow DDI debug ioctl on sbpcd driver */
+/* Allow setting up serial ports */
+/* Allow sending raw qic-117 commands */
+/* Allow enabling/disabling tagged queuing on SCSI controllers and sending
+ arbitrary SCSI commands */
+/* Allow setting encryption key on loopback filesystem */
+
+#define CAP_SYS_ADMIN 21
+
+/* Allow use of reboot() */
+
+#define CAP_SYS_BOOT 22
+
+/* Allow raising priority and setting priority on other (different
+ UID) processes */
+/* Allow use of FIFO and round-robin (realtime) scheduling on own
+ processes and setting the scheduling algorithm used by another
+ process. */
+
+#define CAP_SYS_NICE 23
+
+/* Override resource limits. Set resource limits. */
+/* Override quota limits. */
+/* Override reserved space on ext2 filesystem */
+/* NOTE: ext2 honors fsuid when checking for resource overrides, so
+ you can override using fsuid too */
+/* Override size restrictions on IPC message queues */
+/* Allow more than 64hz interrupts from the real-time clock */
+/* Override max number of consoles on console allocation */
+/* Override max number of keymaps */
+
+#define CAP_SYS_RESOURCE 24
+
+/* Allow manipulation of system clock */
+/* Allow irix_stime on mips */
+/* Allow setting the real-time clock */
+
+#define CAP_SYS_TIME 25
+
+/* Allow configuration of tty devices */
+/* Allow vhangup() of tty */
+
+#define CAP_SYS_TTY_CONFIG 26
+
+#ifdef __KERNEL__
+/*
+ * Bounding set
+ */
+extern kernel_cap_t cap_bset;
+
+/*
+ * Internal kernel functions only
+ */
+
+#ifdef STRICT_CAP_T_TYPECHECKS
+
+#define to_cap_t(x) { x }
+#define cap_t(x) (x).cap
+
+#else
+
+#define to_cap_t(x) (x)
+#define cap_t(x) (x)
+
+#endif
+
+#define CAP_EMPTY_SET to_cap_t(0)
+#define CAP_FULL_SET to_cap_t(~0)
+#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
+#define CAP_INIT_INH_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
+
+#define CAP_TO_MASK(x) (1 << (x))
+#define cap_raise(c, flag) (cap_t(c) |= CAP_TO_MASK(flag))
+#define cap_lower(c, flag) (cap_t(c) &= ~CAP_TO_MASK(flag))
+#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag) & cap_bset)
+
+static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
+{
+ kernel_cap_t dest;
+ cap_t(dest) = cap_t(a) | cap_t(b);
+ return dest;
+}
+
+static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b)
+{
+ kernel_cap_t dest;
+ cap_t(dest) = cap_t(a) & cap_t(b);
+ return dest;
+}
+
+static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop)
+{
+ kernel_cap_t dest;
+ cap_t(dest) = cap_t(a) & ~cap_t(drop);
+ return dest;
+}
+
+static inline kernel_cap_t cap_invert(kernel_cap_t c)
+{
+ kernel_cap_t dest;
+ cap_t(dest) = ~cap_t(c);
+ return dest;
+}
+
+#define cap_isclear(c) (!cap_t(c))
+#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set)))
+
+#define cap_clear(c) do { cap_t(c) = 0; } while(0)
+#define cap_set_full(c) do { cap_t(c) = ~0; } while(0)
+#define cap_mask(c,mask) do { cap_t(c) &= cap_t(mask); } while(0)
+
+#define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK)
+
+#endif /* __KERNEL__ */
+
+#endif /* !_LINUX_CAPABILITY_H */
diff --git a/pfinet/linux-src/include/linux/capi.h b/pfinet/linux-src/include/linux/capi.h
new file mode 100644
index 00000000..9876da08
--- /dev/null
+++ b/pfinet/linux-src/include/linux/capi.h
@@ -0,0 +1,127 @@
+/*
+ * $Id: capi.h,v 1.1 1997/03/04 21:27:33 calle Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capi.h,v $
+ * Revision 1.1 1997/03/04 21:27:33 calle
+ * First version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ *
+ */
+
+#ifndef __LINUX_CAPI_H__
+#define __LINUX_CAPI_H__
+
+#include <asm/types.h>
+#include <linux/ioctl.h>
+#ifndef __KERNEL__
+#include <linux/kernelcapi.h>
+#endif
+
+/*
+ * CAPI_REGISTER
+ */
+
+typedef struct capi_register_params { /* CAPI_REGISTER */
+ __u32 level3cnt; /* No. of simulatneous user data connections */
+ __u32 datablkcnt; /* No. of buffered data messages */
+ __u32 datablklen; /* Size of buffered data messages */
+} capi_register_params;
+
+#define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params)
+
+/*
+ * CAPI_GET_MANUFACTURER
+ */
+
+#define CAPI_MANUFACTURER_LEN 64
+
+#define CAPI_GET_MANUFACTURER _IOWR('C',0x06,CAPI_MANUFACTURER_LEN)
+
+/*
+ * CAPI_GET_VERSION
+ */
+
+typedef struct capi_version {
+ __u32 majorversion;
+ __u32 minorversion;
+ __u32 majormanuversion;
+ __u32 minormanuversion;
+} capi_version;
+
+#define CAPI_GET_VERSION _IOWR('C',0x07,struct capi_version)
+
+/*
+ * CAPI_GET_SERIAL
+ */
+
+#define CAPI_SERIAL_LEN 8
+#define CAPI_GET_SERIAL _IOWR('C',0x08, CAPI_SERIAL_LEN)
+
+/*
+ * CAPI_GET_PROFILE
+ */
+
+typedef struct capi_profile {
+ __u16 ncontroller; /* number of installed controller */
+ __u16 nbchannel; /* number of B-Channels */
+ __u32 goptions; /* global options */
+ __u32 support1; /* B1 protocols support */
+ __u32 support2; /* B2 protocols support */
+ __u32 support3; /* B3 protocols support */
+ __u32 reserved[6]; /* reserved */
+ __u32 manu[5]; /* manufacturer specific information */
+} capi_profile;
+
+#define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile)
+
+typedef struct capi_manufacturer_cmd {
+ unsigned long cmd;
+ void *data;
+} capi_manufacturer_cmd;
+
+/*
+ * CAPI_MANUFACTURER_CMD
+ */
+
+#define CAPI_MANUFACTURER_CMD _IOWR('C',0x20, struct capi_manufacturer_cmd)
+
+/*
+ * CAPI_GET_ERRCODE
+ * capi errcode is set, * if read, write, or ioctl returns EIO,
+ * ioctl returns errcode directly, and in arg, if != 0
+ */
+
+#define CAPI_GET_ERRCODE _IOR('C',0x21, __u16)
+
+/*
+ * CAPI_INSTALLED
+ */
+#define CAPI_INSTALLED _IOR('C',0x22, __u16)
+
+/*
+ * member contr is input for
+ * CAPI_GET_MANUFACTURER, CAPI_VERSION, CAPI_GET_SERIAL
+ * and CAPI_GET_PROFILE
+ */
+typedef union capi_ioctl_struct {
+ __u32 contr;
+ capi_register_params rparams;
+ __u8 manufacturer[CAPI_MANUFACTURER_LEN];
+ capi_version version;
+ __u8 serial[CAPI_SERIAL_LEN];
+ capi_profile profile;
+ capi_manufacturer_cmd cmd;
+ __u16 errcode;
+} capi_ioctl_struct;
+
+#endif /* __LINUX_CAPI_H__ */
diff --git a/pfinet/linux-src/include/linux/cd1400.h b/pfinet/linux-src/include/linux/cd1400.h
new file mode 100644
index 00000000..d07d1e61
--- /dev/null
+++ b/pfinet/linux-src/include/linux/cd1400.h
@@ -0,0 +1,292 @@
+/*****************************************************************************/
+
+/*
+ * cd1400.h -- cd1400 UART hardware info.
+ *
+ * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*****************************************************************************/
+#ifndef _CD1400_H
+#define _CD1400_H
+/*****************************************************************************/
+
+/*
+ * Define the number of async ports per cd1400 uart chip.
+ */
+#define CD1400_PORTS 4
+
+/*
+ * Define the cd1400 uarts internal FIFO sizes.
+ */
+#define CD1400_TXFIFOSIZE 12
+#define CD1400_RXFIFOSIZE 12
+
+/*
+ * Local RX FIFO thresh hold level. Also define the RTS thresh hold
+ * based on the RX thresh hold.
+ */
+#define FIFO_RXTHRESHOLD 6
+#define FIFO_RTSTHRESHOLD 7
+
+/*****************************************************************************/
+
+/*
+ * Define the cd1400 register addresses. These are all the valid
+ * registers with the cd1400. Some are global, some virtual, some
+ * per port.
+ */
+#define GFRCR 0x40
+#define CAR 0x68
+#define GCR 0x4b
+#define SVRR 0x67
+#define RICR 0x44
+#define TICR 0x45
+#define MICR 0x46
+#define RIR 0x6b
+#define TIR 0x6a
+#define MIR 0x69
+#define PPR 0x7e
+
+#define RIVR 0x43
+#define TIVR 0x42
+#define MIVR 0x41
+#define TDR 0x63
+#define RDSR 0x62
+#define MISR 0x4c
+#define EOSRR 0x60
+
+#define LIVR 0x18
+#define CCR 0x05
+#define SRER 0x06
+#define COR1 0x08
+#define COR2 0x09
+#define COR3 0x0a
+#define COR4 0x1e
+#define COR5 0x1f
+#define CCSR 0x0b
+#define RDCR 0x0e
+#define SCHR1 0x1a
+#define SCHR2 0x1b
+#define SCHR3 0x1c
+#define SCHR4 0x1d
+#define SCRL 0x22
+#define SCRH 0x23
+#define LNC 0x24
+#define MCOR1 0x15
+#define MCOR2 0x16
+#define RTPR 0x21
+#define MSVR1 0x6c
+#define MSVR2 0x6d
+#define PSVR 0x6f
+#define RBPR 0x78
+#define RCOR 0x7c
+#define TBPR 0x72
+#define TCOR 0x76
+
+/*****************************************************************************/
+
+/*
+ * Define the set of baud rate clock divisors.
+ */
+#define CD1400_CLK0 8
+#define CD1400_CLK1 32
+#define CD1400_CLK2 128
+#define CD1400_CLK3 512
+#define CD1400_CLK4 2048
+
+#define CD1400_NUMCLKS 5
+
+/*****************************************************************************/
+
+/*
+ * Define the clock pre-scalar value to be a 5 ms clock. This should be
+ * OK for now. It would probably be better to make it 10 ms, but we
+ * can't fit that divisor into 8 bits!
+ */
+#define PPR_SCALAR 244
+
+/*****************************************************************************/
+
+/*
+ * Define values used to set character size options.
+ */
+#define COR1_CHL5 0x00
+#define COR1_CHL6 0x01
+#define COR1_CHL7 0x02
+#define COR1_CHL8 0x03
+
+/*
+ * Define values used to set the number of stop bits.
+ */
+#define COR1_STOP1 0x00
+#define COR1_STOP15 0x04
+#define COR1_STOP2 0x08
+
+/*
+ * Define values used to set the parity scheme in use.
+ */
+#define COR1_PARNONE 0x00
+#define COR1_PARFORCE 0x20
+#define COR1_PARENB 0x40
+#define COR1_PARIGNORE 0x10
+
+#define COR1_PARODD 0x80
+#define COR1_PAREVEN 0x00
+
+#define COR2_IXM 0x80
+#define COR2_TXIBE 0x40
+#define COR2_ETC 0x20
+#define COR2_LLM 0x10
+#define COR2_RLM 0x08
+#define COR2_RTSAO 0x04
+#define COR2_CTSAE 0x02
+
+#define COR3_SCDRNG 0x80
+#define COR3_SCD34 0x40
+#define COR3_FCT 0x20
+#define COR3_SCD12 0x10
+
+/*
+ * Define values used by COR4.
+ */
+#define COR4_BRKINT 0x08
+#define COR4_IGNBRK 0x18
+
+/*****************************************************************************/
+
+/*
+ * Define the modem control register values.
+ * Note that the actual hardware is a little different to the conventional
+ * pin names on the cd1400.
+ */
+#define MSVR1_DTR 0x01
+#define MSVR1_DSR 0x10
+#define MSVR1_RI 0x20
+#define MSVR1_CTS 0x40
+#define MSVR1_DCD 0x80
+
+#define MSVR2_RTS 0x02
+#define MSVR2_DSR 0x10
+#define MSVR2_RI 0x20
+#define MSVR2_CTS 0x40
+#define MSVR2_DCD 0x80
+
+#define MCOR1_DCD 0x80
+#define MCOR1_CTS 0x40
+#define MCOR1_RI 0x20
+#define MCOR1_DSR 0x10
+
+#define MCOR2_DCD 0x80
+#define MCOR2_CTS 0x40
+#define MCOR2_RI 0x20
+#define MCOR2_DSR 0x10
+
+/*****************************************************************************/
+
+/*
+ * Define the bits used with the service (interrupt) enable register.
+ */
+#define SRER_NNDT 0x01
+#define SRER_TXEMPTY 0x02
+#define SRER_TXDATA 0x04
+#define SRER_RXDATA 0x10
+#define SRER_MODEM 0x80
+
+/*****************************************************************************/
+
+/*
+ * Define operational commands for the command register.
+ */
+#define CCR_RESET 0x80
+#define CCR_CORCHANGE 0x4e
+#define CCR_SENDCH 0x20
+#define CCR_CHANCTRL 0x10
+
+#define CCR_TXENABLE (CCR_CHANCTRL | 0x08)
+#define CCR_TXDISABLE (CCR_CHANCTRL | 0x04)
+#define CCR_RXENABLE (CCR_CHANCTRL | 0x02)
+#define CCR_RXDISABLE (CCR_CHANCTRL | 0x01)
+
+#define CCR_SENDSCHR1 (CCR_SENDCH | 0x01)
+#define CCR_SENDSCHR2 (CCR_SENDCH | 0x02)
+#define CCR_SENDSCHR3 (CCR_SENDCH | 0x03)
+#define CCR_SENDSCHR4 (CCR_SENDCH | 0x04)
+
+#define CCR_RESETCHAN (CCR_RESET | 0x00)
+#define CCR_RESETFULL (CCR_RESET | 0x01)
+#define CCR_TXFLUSHFIFO (CCR_RESET | 0x02)
+
+#define CCR_MAXWAIT 10000
+
+/*****************************************************************************/
+
+/*
+ * Define the valid acknowledgement types (for hw ack cycle).
+ */
+#define ACK_TYPMASK 0x07
+#define ACK_TYPTX 0x02
+#define ACK_TYPMDM 0x01
+#define ACK_TYPRXGOOD 0x03
+#define ACK_TYPRXBAD 0x07
+
+#define SVRR_RX 0x01
+#define SVRR_TX 0x02
+#define SVRR_MDM 0x04
+
+#define ST_OVERRUN 0x01
+#define ST_FRAMING 0x02
+#define ST_PARITY 0x04
+#define ST_BREAK 0x08
+#define ST_SCHAR1 0x10
+#define ST_SCHAR2 0x20
+#define ST_SCHAR3 0x30
+#define ST_SCHAR4 0x40
+#define ST_RANGE 0x70
+#define ST_SCHARMASK 0x70
+#define ST_TIMEOUT 0x80
+
+#define MISR_DCD 0x80
+#define MISR_CTS 0x40
+#define MISR_RI 0x20
+#define MISR_DSR 0x10
+
+/*****************************************************************************/
+
+/*
+ * Defines for the CCSR status register.
+ */
+#define CCSR_RXENABLED 0x80
+#define CCSR_RXFLOWON 0x40
+#define CCSR_RXFLOWOFF 0x20
+#define CCSR_TXENABLED 0x08
+#define CCSR_TXFLOWON 0x04
+#define CCSR_TXFLOWOFF 0x02
+
+/*****************************************************************************/
+
+/*
+ * Define the embedded commands.
+ */
+#define ETC_CMD 0x00
+#define ETC_STARTBREAK 0x81
+#define ETC_DELAY 0x82
+#define ETC_STOPBREAK 0x83
+
+/*****************************************************************************/
+#endif
diff --git a/pfinet/linux-src/include/linux/cdk.h b/pfinet/linux-src/include/linux/cdk.h
new file mode 100644
index 00000000..2fab8949
--- /dev/null
+++ b/pfinet/linux-src/include/linux/cdk.h
@@ -0,0 +1,486 @@
+/*****************************************************************************/
+
+/*
+ * cdk.h -- CDK interface definitions.
+ *
+ * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*****************************************************************************/
+#ifndef _CDK_H
+#define _CDK_H
+/*****************************************************************************/
+
+#pragma pack(2)
+
+/*
+ * The following set of definitions is used to communicate with the
+ * shared memory interface of the Stallion intelligent multiport serial
+ * boards. The definitions in this file are taken directly from the
+ * document titled "Generic Stackable Interface, Downloader and
+ * Communications Development Kit".
+ */
+
+/*
+ * Define the set of important shared memory addresses. These are
+ * required to initialize the board and get things started. All of these
+ * addresses are relative to the start of the shared memory.
+ */
+#define CDK_SIGADDR 0x200
+#define CDK_FEATADDR 0x280
+#define CDK_CDKADDR 0x300
+#define CDK_RDYADDR 0x262
+
+#define CDK_ALIVEMARKER 13
+
+/*
+ * On hardware power up the ROMs located on the EasyConnection 8/64 will
+ * fill out the following signature information into shared memory. This
+ * way the host system can quickly determine that the board is present
+ * and is operational.
+ */
+typedef struct cdkecpsig {
+ unsigned long magic;
+ unsigned short romver;
+ unsigned short cputype;
+ unsigned char panelid[8];
+} cdkecpsig_t;
+
+#define ECP_MAGIC 0x21504345
+
+/*
+ * On hardware power up the ROMs located on the ONboard, Stallion and
+ * Brumbys will fill out the following signature information into shared
+ * memory. This way the host system can quickly determine that the board
+ * is present and is operational.
+ */
+typedef struct cdkonbsig {
+ unsigned short magic0;
+ unsigned short magic1;
+ unsigned short magic2;
+ unsigned short magic3;
+ unsigned short romver;
+ unsigned short memoff;
+ unsigned short memseg;
+ unsigned short amask0;
+ unsigned short pic;
+ unsigned short status;
+ unsigned short btype;
+ unsigned short clkticks;
+ unsigned short clkspeed;
+ unsigned short amask1;
+ unsigned short amask2;
+} cdkonbsig_t;
+
+#define ONB_MAGIC0 0xf2a7
+#define ONB_MAGIC1 0xa149
+#define ONB_MAGIC2 0x6352
+#define ONB_MAGIC3 0xf121
+
+/*
+ * Define the feature area structure. The feature area is the set of
+ * startup parameters used by the slave image when it starts executing.
+ * They allow for the specification of buffer sizes, debug trace, etc.
+ */
+typedef struct cdkfeature {
+ unsigned long debug;
+ unsigned long banner;
+ unsigned long etype;
+ unsigned long nrdevs;
+ unsigned long brdspec;
+ unsigned long txrqsize;
+ unsigned long rxrqsize;
+ unsigned long flags;
+} cdkfeature_t;
+
+#define ETYP_DDK 0
+#define ETYP_CDK 1
+
+/*
+ * Define the CDK header structure. This is the info that the slave
+ * environment sets up after it has been downloaded and started. It
+ * essentially provides a memory map for the shared memory interface.
+ */
+typedef struct cdkhdr {
+ unsigned short command;
+ unsigned short status;
+ unsigned short port;
+ unsigned short mode;
+ unsigned long cmd_buf[14];
+ unsigned short alive_cnt;
+ unsigned short intrpt_mode;
+ unsigned char intrpt_id[8];
+ unsigned char ver_release;
+ unsigned char ver_modification;
+ unsigned char ver_fix;
+ unsigned char deadman_restart;
+ unsigned short deadman;
+ unsigned short nrdevs;
+ unsigned long memp;
+ unsigned long hostp;
+ unsigned long slavep;
+ unsigned char hostreq;
+ unsigned char slavereq;
+ unsigned char cmd_reserved[30];
+} cdkhdr_t;
+
+#define MODE_DDK 0
+#define MODE_CDK 1
+
+#define IMD_INTR 0x0
+#define IMD_PPINTR 0x1
+#define IMD_POLL 0xff
+
+/*
+ * Define the memory mapping structure. This structure is pointed to by
+ * the memp field in the stlcdkhdr struct. As many as these structures
+ * as required are laid out in shared memory to define how the rest of
+ * shared memory is divided up. There will be one for each port.
+ */
+typedef struct cdkmem {
+ unsigned short dtype;
+ unsigned long offset;
+} cdkmem_t;
+
+#define TYP_UNDEFINED 0x0
+#define TYP_ASYNCTRL 0x1
+#define TYP_ASYNC 0x20
+#define TYP_PARALLEL 0x40
+#define TYP_SYNCX21 0x60
+
+/*****************************************************************************/
+
+/*
+ * Following is a set of defines and structures used to actually deal
+ * with the serial ports on the board. Firstly is the set of commands
+ * that can be applied to ports.
+ */
+#define ASYCMD (((unsigned long) 'a') << 8)
+
+#define A_NULL (ASYCMD | 0)
+#define A_FLUSH (ASYCMD | 1)
+#define A_BREAK (ASYCMD | 2)
+#define A_GETPORT (ASYCMD | 3)
+#define A_SETPORT (ASYCMD | 4)
+#define A_SETPORTF (ASYCMD | 5)
+#define A_SETPORTFTX (ASYCMD | 6)
+#define A_SETPORTFRX (ASYCMD | 7)
+#define A_GETSIGNALS (ASYCMD | 8)
+#define A_SETSIGNALS (ASYCMD | 9)
+#define A_SETSIGNALSF (ASYCMD | 10)
+#define A_SETSIGNALSFTX (ASYCMD | 11)
+#define A_SETSIGNALSFRX (ASYCMD | 12)
+#define A_GETNOTIFY (ASYCMD | 13)
+#define A_SETNOTIFY (ASYCMD | 14)
+#define A_NOTIFY (ASYCMD | 15)
+#define A_PORTCTRL (ASYCMD | 16)
+#define A_GETSTATS (ASYCMD | 17)
+#define A_RQSTATE (ASYCMD | 18)
+#define A_FLOWSTATE (ASYCMD | 19)
+#define A_CLEARSTATS (ASYCMD | 20)
+
+/*
+ * Define those arguments used for simple commands.
+ */
+#define FLUSHRX 0x1
+#define FLUSHTX 0x2
+
+#define BREAKON -1
+#define BREAKOFF -2
+
+/*
+ * Define the port setting structure, and all those defines that go along
+ * with it. Basically this structure defines the characteristics of this
+ * port: baud rate, chars, parity, input/output char cooking etc.
+ */
+typedef struct asyport {
+ unsigned long baudout;
+ unsigned long baudin;
+ unsigned long iflag;
+ unsigned long oflag;
+ unsigned long lflag;
+ unsigned long pflag;
+ unsigned long flow;
+ unsigned long spare1;
+ unsigned short vtime;
+ unsigned short vmin;
+ unsigned short txlo;
+ unsigned short txhi;
+ unsigned short rxlo;
+ unsigned short rxhi;
+ unsigned short rxhog;
+ unsigned short spare2;
+ unsigned char csize;
+ unsigned char stopbs;
+ unsigned char parity;
+ unsigned char stopin;
+ unsigned char startin;
+ unsigned char stopout;
+ unsigned char startout;
+ unsigned char parmark;
+ unsigned char brkmark;
+ unsigned char cc[11];
+} asyport_t;
+
+#define PT_STOP1 0x0
+#define PT_STOP15 0x1
+#define PT_STOP2 0x2
+
+#define PT_NOPARITY 0x0
+#define PT_ODDPARITY 0x1
+#define PT_EVENPARITY 0x2
+#define PT_MARKPARITY 0x3
+#define PT_SPACEPARITY 0x4
+
+#define F_NONE 0x0
+#define F_IXON 0x1
+#define F_IXOFF 0x2
+#define F_IXANY 0x4
+#define F_IOXANY 0x8
+#define F_RTSFLOW 0x10
+#define F_CTSFLOW 0x20
+#define F_DTRFLOW 0x40
+#define F_DCDFLOW 0x80
+#define F_DSROFLOW 0x100
+#define F_DSRIFLOW 0x200
+
+#define FI_NORX 0x1
+#define FI_RAW 0x2
+#define FI_ISTRIP 0x4
+#define FI_UCLC 0x8
+#define FI_INLCR 0x10
+#define FI_ICRNL 0x20
+#define FI_IGNCR 0x40
+#define FI_IGNBREAK 0x80
+#define FI_DSCRDBREAK 0x100
+#define FI_1MARKBREAK 0x200
+#define FI_2MARKBREAK 0x400
+#define FI_XCHNGBREAK 0x800
+#define FI_IGNRXERRS 0x1000
+#define FI_DSCDRXERRS 0x2000
+#define FI_1MARKRXERRS 0x4000
+#define FI_2MARKRXERRS 0x8000
+#define FI_XCHNGRXERRS 0x10000
+#define FI_DSCRDNULL 0x20000
+
+#define FO_OLCUC 0x1
+#define FO_ONLCR 0x2
+#define FO_OOCRNL 0x4
+#define FO_ONOCR 0x8
+#define FO_ONLRET 0x10
+#define FO_ONL 0x20
+#define FO_OBS 0x40
+#define FO_OVT 0x80
+#define FO_OFF 0x100
+#define FO_OTAB1 0x200
+#define FO_OTAB2 0x400
+#define FO_OTAB3 0x800
+#define FO_OCR1 0x1000
+#define FO_OCR2 0x2000
+#define FO_OCR3 0x4000
+#define FO_OFILL 0x8000
+#define FO_ODELL 0x10000
+
+#define P_RTSLOCK 0x1
+#define P_CTSLOCK 0x2
+#define P_MAPRTS 0x4
+#define P_MAPCTS 0x8
+#define P_LOOPBACK 0x10
+#define P_DTRFOLLOW 0x20
+#define P_FAKEDCD 0x40
+
+#define P_RXIMIN 0x10000
+#define P_RXITIME 0x20000
+#define P_RXTHOLD 0x40000
+
+/*
+ * Define a structure to communicate serial port signal and data state
+ * information.
+ */
+typedef struct asysigs {
+ unsigned long data;
+ unsigned long signal;
+ unsigned long sigvalue;
+} asysigs_t;
+
+#define DT_TXBUSY 0x1
+#define DT_TXEMPTY 0x2
+#define DT_TXLOW 0x4
+#define DT_TXHIGH 0x8
+#define DT_TXFULL 0x10
+#define DT_TXHOG 0x20
+#define DT_TXFLOWED 0x40
+#define DT_TXBREAK 0x80
+
+#define DT_RXBUSY 0x100
+#define DT_RXEMPTY 0x200
+#define DT_RXLOW 0x400
+#define DT_RXHIGH 0x800
+#define DT_RXFULL 0x1000
+#define DT_RXHOG 0x2000
+#define DT_RXFLOWED 0x4000
+#define DT_RXBREAK 0x8000
+
+#define SG_DTR 0x1
+#define SG_DCD 0x2
+#define SG_RTS 0x4
+#define SG_CTS 0x8
+#define SG_DSR 0x10
+#define SG_RI 0x20
+
+/*
+ * Define the notification setting structure. This is used to tell the
+ * port what events we want to be informed about. Fields here use the
+ * same defines as for the asysigs structure above.
+ */
+typedef struct asynotify {
+ unsigned long ctrl;
+ unsigned long data;
+ unsigned long signal;
+ unsigned long sigvalue;
+} asynotify_t;
+
+/*
+ * Define the port control structure. It is used to do fine grain
+ * control operations on the port.
+ */
+typedef struct {
+ unsigned long rxctrl;
+ unsigned long txctrl;
+ char rximdch;
+ char tximdch;
+ char spare1;
+ char spare2;
+} asyctrl_t;
+
+#define CT_ENABLE 0x1
+#define CT_DISABLE 0x2
+#define CT_STOP 0x4
+#define CT_START 0x8
+#define CT_STARTFLOW 0x10
+#define CT_STOPFLOW 0x20
+#define CT_SENDCHR 0x40
+
+/*
+ * Define the stats structure kept for each port. This is a useful set
+ * of data collected for each port on the slave. The A_GETSTATS command
+ * is used to retrieve this data from the slave.
+ */
+typedef struct asystats {
+ unsigned long opens;
+ unsigned long txchars;
+ unsigned long rxchars;
+ unsigned long txringq;
+ unsigned long rxringq;
+ unsigned long txmsgs;
+ unsigned long rxmsgs;
+ unsigned long txflushes;
+ unsigned long rxflushes;
+ unsigned long overruns;
+ unsigned long framing;
+ unsigned long parity;
+ unsigned long ringover;
+ unsigned long lost;
+ unsigned long rxstart;
+ unsigned long rxstop;
+ unsigned long txstart;
+ unsigned long txstop;
+ unsigned long dcdcnt;
+ unsigned long dtrcnt;
+ unsigned long ctscnt;
+ unsigned long rtscnt;
+ unsigned long dsrcnt;
+ unsigned long ricnt;
+ unsigned long txbreaks;
+ unsigned long rxbreaks;
+ unsigned long signals;
+ unsigned long state;
+ unsigned long hwid;
+} asystats_t;
+
+/*****************************************************************************/
+
+/*
+ * All command and control communication with a device on the slave is
+ * via a control block in shared memory. Each device has its own control
+ * block, defined by the following structure. The control block allows
+ * the host to open, close and control the device on the slave.
+ */
+typedef struct cdkctrl {
+ unsigned char open;
+ unsigned char close;
+ unsigned long openarg;
+ unsigned long closearg;
+ unsigned long cmd;
+ unsigned long status;
+ unsigned long args[32];
+} cdkctrl_t;
+
+/*
+ * Each device on the slave passes data to and from the host via a ring
+ * queue in shared memory. Define a ring queue structure to hold the
+ * vital information about each ring queue. Two ring queues will be
+ * allocated for each port, one for receive data and one for transmit
+ * data.
+ */
+typedef struct cdkasyrq {
+ unsigned long offset;
+ unsigned short size;
+ unsigned short head;
+ unsigned short tail;
+} cdkasyrq_t;
+
+/*
+ * Each asynchronous port is defined in shared memory by the following
+ * structure. It contains a control block to command a device, and also
+ * the necessary data channel information as well.
+ */
+typedef struct cdkasy {
+ cdkctrl_t ctrl;
+ unsigned short notify;
+ asynotify_t changed;
+ unsigned short receive;
+ cdkasyrq_t rxq;
+ unsigned short transmit;
+ cdkasyrq_t txq;
+} cdkasy_t;
+
+#pragma pack()
+
+/*****************************************************************************/
+
+/*
+ * Define the set of ioctls used by the driver to do special things
+ * to the board. These include interrupting it, and initializing
+ * the driver after board startup and shutdown.
+ */
+#include <linux/ioctl.h>
+
+#define STL_BINTR _IO('s',20)
+#define STL_BSTART _IO('s',21)
+#define STL_BSTOP _IO('s',22)
+#define STL_BRESET _IO('s',23)
+
+/*
+ * Define a set of ioctl extensions, used to get at special stuff.
+ */
+#define STL_GETPFLAG _IO('s',80)
+#define STL_SETPFLAG _IO('s',81)
+
+/*****************************************************************************/
+#endif
diff --git a/pfinet/linux-src/include/linux/cdrom.h b/pfinet/linux-src/include/linux/cdrom.h
new file mode 100644
index 00000000..4bbdbd44
--- /dev/null
+++ b/pfinet/linux-src/include/linux/cdrom.h
@@ -0,0 +1,433 @@
+/*
+ * -- <linux/cdrom.h>
+ * General header file for linux CD-ROM drivers
+ * Copyright (C) 1992 David Giller, rafetmad@oxy.edu
+ * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de
+ * 1996 David van Leeuwen, david@tm.tno.nl
+ * 1997, 1998 Erik Andersen, andersee@debian.org
+ * 1998, 1999 Jens Axboe, axboe@image.dk
+ */
+
+#ifndef _LINUX_CDROM_H
+#define _LINUX_CDROM_H
+
+/*******************************************************
+ * As of Linux 2.1.x, all Linux CD-ROM application programs will use this
+ * (and only this) include file. It is my hope to provide Linux with
+ * a uniform interface between software accessing CD-ROMs and the various
+ * device drivers that actually talk to the drives. There may still be
+ * 23 different kinds of strange CD-ROM drives, but at least there will
+ * now be one, and only one, Linux CD-ROM interface.
+ *
+ * Additionally, as of Linux 2.1.x, all Linux application programs
+ * should use the O_NONBLOCK option when opening a CD-ROM device
+ * for subsequent ioctl commands. This allows for neat system errors
+ * like "No medium found" or "Wrong medium type" upon attempting to
+ * mount or play an empty slot, mount an audio disc, or play a data disc.
+ * Generally, changing an application program to support O_NONBLOCK
+ * is as easy as the following:
+ * - drive = open("/dev/cdrom", O_RDONLY);
+ * + drive = open("/dev/cdrom", O_RDONLY | O_NONBLOCK);
+ * It is worth the small change.
+ *
+ * Patches for many common CD programs (provided by David A. van Leeuwen)
+ * can be found at: ftp://ftp.gwdg.de/pub/linux/cdrom/drivers/cm206/
+ *
+ *******************************************************/
+
+/* When a driver supports a certain function, but the cdrom drive we are
+ * using doesn't, we will return the error EDRIVE_CANT_DO_THIS. We will
+ * borrow the "Operation not supported" error from the network folks to
+ * accomplish this. Maybe someday we will get a more targeted error code,
+ * but this will do for now... */
+#define EDRIVE_CANT_DO_THIS EOPNOTSUPP
+
+/*******************************************************
+ * The CD-ROM IOCTL commands -- these should be supported by
+ * all the various cdrom drivers. For the CD-ROM ioctls, we
+ * will commandeer byte 0x53, or 'S'.
+ *******************************************************/
+#define CDROMPAUSE 0x5301 /* Pause Audio Operation */
+#define CDROMRESUME 0x5302 /* Resume paused Audio Operation */
+#define CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */
+#define CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index
+ (struct cdrom_ti) */
+#define CDROMREADTOCHDR 0x5305 /* Read TOC header
+ (struct cdrom_tochdr) */
+#define CDROMREADTOCENTRY 0x5306 /* Read TOC entry
+ (struct cdrom_tocentry) */
+#define CDROMSTOP 0x5307 /* Stop the cdrom drive */
+#define CDROMSTART 0x5308 /* Start the cdrom drive */
+#define CDROMEJECT 0x5309 /* Ejects the cdrom media */
+#define CDROMVOLCTRL 0x530a /* Control output volume
+ (struct cdrom_volctrl) */
+#define CDROMSUBCHNL 0x530b /* Read subchannel data
+ (struct cdrom_subchnl) */
+#define CDROMREADMODE2 0x530c /* Read CDROM mode 2 data (2336 Bytes)
+ (struct cdrom_read) */
+#define CDROMREADMODE1 0x530d /* Read CDROM mode 1 data (2048 Bytes)
+ (struct cdrom_read) */
+#define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */
+#define CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */
+#define CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session
+ address of multi session disks
+ (struct cdrom_multisession) */
+#define CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code"
+ if available (struct cdrom_mcn) */
+#define CDROM_GET_UPC CDROM_GET_MCN /* This one is depricated,
+ but here anyway for compatibility */
+#define CDROMRESET 0x5312 /* hard-reset the drive */
+#define CDROMVOLREAD 0x5313 /* Get the drive's volume setting
+ (struct cdrom_volctrl) */
+#define CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes)
+ (struct cdrom_read) */
+/*
+ * These ioctls are used only used in aztcd.c and optcd.c
+ */
+#define CDROMREADCOOKED 0x5315 /* read data in cooked mode */
+#define CDROMSEEK 0x5316 /* seek msf address */
+
+/*
+ * This ioctl is only used by the scsi-cd driver.
+ It is for playing audio in logical block addressing mode.
+ */
+#define CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */
+
+/*
+ * These ioctls are used only used in optcd.c
+ */
+#define CDROMREADALL 0x5318 /* read all 2646 bytes */
+#define CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */
+
+/*
+ * These ioctls are implemented through the uniform CD-ROM driver
+ * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM
+ * drivers are eventually ported to the uniform CD-ROM driver interface.
+ */
+#define CDROM_SET_OPTIONS 0x5320 /* Set behavior options */
+#define CDROM_CLEAR_OPTIONS 0x5321 /* Clear behavior options */
+#define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
+#define CDROM_SELECT_DISC 0x5323 /* Select disc (for juke-boxes) */
+#define CDROM_MEDIA_CHANGED 0x5325 /* Check is media changed */
+#define CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */
+#define CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */
+#define CDROM_CHANGER_NSLOTS 0x5328 /* Get number of slots */
+#define CDROM_LOCKDOOR 0x5329 /* lock or unlock door */
+#define CDROM_DEBUG 0x5330 /* Turn debug messages on/off */
+#define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
+
+/* This ioctl is only used by sbpcd at the moment */
+#define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */
+
+/*******************************************************
+ * CDROM IOCTL structures
+ *******************************************************/
+
+/* Address in MSF format */
+struct cdrom_msf0
+{
+ u_char minute;
+ u_char second;
+ u_char frame;
+};
+
+/* Address in either MSF or logical format */
+union cdrom_addr
+{
+ struct cdrom_msf0 msf;
+ int lba;
+};
+
+/* This struct is used by the CDROMPLAYMSF ioctl */
+struct cdrom_msf
+{
+ u_char cdmsf_min0; /* start minute */
+ u_char cdmsf_sec0; /* start second */
+ u_char cdmsf_frame0; /* start frame */
+ u_char cdmsf_min1; /* end minute */
+ u_char cdmsf_sec1; /* end second */
+ u_char cdmsf_frame1; /* end frame */
+};
+
+/* This struct is used by the CDROMPLAYTRKIND ioctl */
+struct cdrom_ti
+{
+ u_char cdti_trk0; /* start track */
+ u_char cdti_ind0; /* start index */
+ u_char cdti_trk1; /* end track */
+ u_char cdti_ind1; /* end index */
+};
+
+/* This struct is used by the CDROMREADTOCHDR ioctl */
+struct cdrom_tochdr
+{
+ u_char cdth_trk0; /* start track */
+ u_char cdth_trk1; /* end track */
+};
+
+/* This struct is used by the CDROMVOLCTRL and CDROMVOLREAD ioctls */
+struct cdrom_volctrl
+{
+ u_char channel0;
+ u_char channel1;
+ u_char channel2;
+ u_char channel3;
+};
+
+/* This struct is used by the CDROMSUBCHNL ioctl */
+struct cdrom_subchnl
+{
+ u_char cdsc_format;
+ u_char cdsc_audiostatus;
+ u_char cdsc_adr: 4;
+ u_char cdsc_ctrl: 4;
+ u_char cdsc_trk;
+ u_char cdsc_ind;
+ union cdrom_addr cdsc_absaddr;
+ union cdrom_addr cdsc_reladdr;
+};
+
+
+/* This struct is used by the CDROMREADTOCENTRY ioctl */
+struct cdrom_tocentry
+{
+ u_char cdte_track;
+ u_char cdte_adr :4;
+ u_char cdte_ctrl :4;
+ u_char cdte_format;
+ union cdrom_addr cdte_addr;
+ u_char cdte_datamode;
+};
+
+/* This struct is used by the CDROMREADMODE1, and CDROMREADMODE2 ioctls */
+struct cdrom_read
+{
+ int cdread_lba;
+ caddr_t cdread_bufaddr;
+ int cdread_buflen;
+};
+
+/* This struct is used by the CDROMREADAUDIO ioctl */
+struct cdrom_read_audio
+{
+ union cdrom_addr addr; /* frame address */
+ u_char addr_format; /* CDROM_LBA or CDROM_MSF */
+ int nframes; /* number of 2352-byte-frames to read at once */
+ u_char *buf; /* frame buffer (size: nframes*2352 bytes) */
+};
+
+/* This struct is used with the CDROMMULTISESSION ioctl */
+struct cdrom_multisession
+{
+ union cdrom_addr addr; /* frame address: start-of-last-session
+ (not the new "frame 16"!). Only valid
+ if the "xa_flag" is true. */
+ u_char xa_flag; /* 1: "is XA disk" */
+ u_char addr_format; /* CDROM_LBA or CDROM_MSF */
+};
+
+/* This struct is used with the CDROM_GET_MCN ioctl.
+ * Very few audio discs actually have Universal Product Code information,
+ * which should just be the Medium Catalog Number on the box. Also note
+ * that the way the codeis written on CD is _not_ uniform across all discs!
+ */
+struct cdrom_mcn
+{
+ u_char medium_catalog_number[14]; /* 13 ASCII digits, null-terminated */
+};
+
+/* This is used by the CDROMPLAYBLK ioctl */
+struct cdrom_blk
+{
+ unsigned from;
+ unsigned short len;
+};
+
+
+/*
+ * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336,
+ * 2340, or 2352 bytes long.
+
+* Sector types of the standard CD-ROM data formats:
+ *
+ * format sector type user data size (bytes)
+ * -----------------------------------------------------------------------------
+ * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW)
+ * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE)
+ * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0)
+ * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE)
+ * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes)
+ *
+ *
+ * The layout of the standard CD-ROM data formats:
+ * -----------------------------------------------------------------------------
+ * - audio (red): | audio_sample_bytes |
+ * | 2352 |
+ *
+ * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC |
+ * | 12 - 4 - 2048 - 4 - 8 - 276 |
+ *
+ * - data (yellow, mode2): | sync - head - data |
+ * | 12 - 4 - 2336 |
+ *
+ * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC |
+ * | 12 - 4 - 8 - 2048 - 4 - 276 |
+ *
+ * - XA data (green, mode2 form2): | sync - head - sub - data - Spare |
+ * | 12 - 4 - 8 - 2324 - 4 |
+ *
+ */
+
+/* Some generally useful CD-ROM information -- mostly based on the above */
+#define CD_MINS 74 /* max. minutes per CD, not really a limit */
+#define CD_SECS 60 /* seconds per minute */
+#define CD_FRAMES 75 /* frames per second */
+#define CD_SYNC_SIZE 12 /* 12 sync bytes per raw data frame */
+#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */
+#define CD_CHUNK_SIZE 24 /* lowest-level "data bytes piece" */
+#define CD_NUM_OF_CHUNKS 98 /* chunks per frame */
+#define CD_FRAMESIZE_SUB 96 /* subchannel data "frame" size */
+#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */
+#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */
+#define CD_EDC_SIZE 4 /* bytes EDC per most raw data frame types */
+#define CD_ZERO_SIZE 8 /* bytes zero per yellow book mode 1 frame */
+#define CD_ECC_SIZE 276 /* bytes ECC per most raw data frame types */
+#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
+#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */
+#define CD_FRAMESIZE_RAWER 2646 /* The maximum possible returned bytes */
+/* most drives don't deliver everything: */
+#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/
+#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/
+
+#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */
+#define CD_XA_TAIL (CD_EDC_SIZE+CD_ECC_SIZE) /* "after data" part of raw XA frame */
+#define CD_XA_SYNC_HEAD (CD_SYNC_SIZE+CD_XA_HEAD) /* sync bytes + header of XA frame */
+
+/* CD-ROM address types (cdrom_tocentry.cdte_format) */
+#define CDROM_LBA 0x01 /* "logical block": first frame is #0 */
+#define CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */
+
+/* bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl) */
+#define CDROM_DATA_TRACK 0x04
+
+/* The leadout track is always 0xAA, regardless of # of tracks on disc */
+#define CDROM_LEADOUT 0xAA
+
+/* audio states (from SCSI-2, but seen with other drives, too) */
+#define CDROM_AUDIO_INVALID 0x00 /* audio status not supported */
+#define CDROM_AUDIO_PLAY 0x11 /* audio play operation in progress */
+#define CDROM_AUDIO_PAUSED 0x12 /* audio play operation paused */
+#define CDROM_AUDIO_COMPLETED 0x13 /* audio play successfully completed */
+#define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */
+#define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */
+
+/* CD-ROM-specific SCSI command opcodes */
+#define SCMD_READ_TOC 0x43 /* read table of contents */
+#define SCMD_PLAYAUDIO_MSF 0x47 /* play data at time offset */
+#define SCMD_PLAYAUDIO_TI 0x48 /* play data at track/index */
+#define SCMD_PAUSE_RESUME 0x4B /* pause/resume audio */
+#define SCMD_READ_SUBCHANNEL 0x42 /* read SC info on playing disc */
+#define SCMD_PLAYAUDIO10 0x45 /* play data at logical block */
+
+/* capability flags used with the uniform CD-ROM driver */
+#define CDC_CLOSE_TRAY 0x1 /* caddy systems _can't_ close */
+#define CDC_OPEN_TRAY 0x2 /* but _can_ eject. */
+#define CDC_LOCK 0x4 /* disable manual eject */
+#define CDC_SELECT_SPEED 0x8 /* programmable speed */
+#define CDC_SELECT_DISC 0x10 /* select disc from juke-box */
+#define CDC_MULTI_SESSION 0x20 /* read sessions>1 */
+#define CDC_MCN 0x40 /* Medium Catalog Number */
+#define CDC_MEDIA_CHANGED 0x80 /* media changed */
+#define CDC_PLAY_AUDIO 0x100 /* audio functions */
+#define CDC_RESET 0x200 /* hard reset device */
+#define CDC_IOCTLS 0x400 /* driver has non-standard ioctls */
+#define CDC_DRIVE_STATUS 0x800 /* driver implements drive status */
+
+/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
+#define CDS_NO_INFO 0 /* if not implemented */
+#define CDS_NO_DISC 1
+#define CDS_TRAY_OPEN 2
+#define CDS_DRIVE_NOT_READY 3
+#define CDS_DISC_OK 4
+
+/* return values for the CDROM_DISC_STATUS ioctl */
+/* can also return CDS_NO_[INFO|DISC], from above */
+#define CDS_AUDIO 100
+#define CDS_DATA_1 101
+#define CDS_DATA_2 102
+#define CDS_XA_2_1 103
+#define CDS_XA_2_2 104
+#define CDS_MIXED 105
+
+/* User-configurable behavior options for the uniform CD-ROM driver */
+#define CDO_AUTO_CLOSE 0x1 /* close tray on first open() */
+#define CDO_AUTO_EJECT 0x2 /* open tray on last release() */
+#define CDO_USE_FFLAGS 0x4 /* use O_NONBLOCK information on open */
+#define CDO_LOCK 0x8 /* lock tray on open files */
+#define CDO_CHECK_TYPE 0x10 /* check type on open for data */
+
+/* Special codes used when specifying changer slots. */
+#define CDSL_NONE ((int) (~0U>>1)-1)
+#define CDSL_CURRENT ((int) (~0U>>1))
+
+#ifdef __KERNEL__
+/* Uniform cdrom data structures for cdrom.c */
+struct cdrom_device_info {
+ struct cdrom_device_ops *ops; /* link to device_ops */
+ struct cdrom_device_info *next; /* next device_info for this major */
+ void *handle; /* driver-dependent data */
+/* specifications */
+ kdev_t dev; /* device number */
+ int mask; /* mask of capability: disables them */
+ int speed; /* maximum speed for reading data */
+ int capacity; /* number of discs in jukebox */
+/* device-related storage */
+ int options : 30; /* options flags */
+ unsigned mc_flags : 2; /* media change buffer flags */
+ int use_count; /* number of times device opened */
+ char name[20]; /* name of the device type */
+
+};
+
+struct cdrom_device_ops {
+/* routines */
+ int (*open) (struct cdrom_device_info *, int);
+ void (*release) (struct cdrom_device_info *);
+ int (*drive_status) (struct cdrom_device_info *, int);
+ int (*media_changed) (struct cdrom_device_info *, int);
+ int (*tray_move) (struct cdrom_device_info *, int);
+ int (*lock_door) (struct cdrom_device_info *, int);
+ int (*select_speed) (struct cdrom_device_info *, int);
+ int (*select_disc) (struct cdrom_device_info *, int);
+ int (*get_last_session) (struct cdrom_device_info *,
+ struct cdrom_multisession *);
+ int (*get_mcn) (struct cdrom_device_info *,
+ struct cdrom_mcn *);
+ /* hard reset device */
+ int (*reset) (struct cdrom_device_info *);
+ /* play stuff */
+ int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *);
+ /* dev-specific */
+ int (*dev_ioctl) (struct cdrom_device_info *,
+ unsigned int, unsigned long);
+/* driver specifications */
+ const int capability; /* capability flags */
+ int n_minors; /* number of active minor devices */
+};
+
+/* the general file operations structure: */
+extern struct file_operations cdrom_fops;
+
+extern int register_cdrom(struct cdrom_device_info *cdi);
+extern int unregister_cdrom(struct cdrom_device_info *cdi);
+typedef struct {
+ int data;
+ int audio;
+ int cdi;
+ int xa;
+ long error;
+} tracktype;
+extern void cdrom_count_tracks(struct cdrom_device_info *cdi,tracktype* tracks);
+#endif /* End of kernel only stuff */
+
+#endif /* _LINUX_CDROM_H */
diff --git a/pfinet/linux-src/include/linux/coda.h b/pfinet/linux-src/include/linux/coda.h
new file mode 100644
index 00000000..8cb3ff46
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coda.h
@@ -0,0 +1,800 @@
+/*
+ You may distribute this file under either of the two licenses that
+ follow at your discretion.
+*/
+
+/* BLURB lgpl
+
+ Coda File System
+ Release 5
+
+ Copyright (c) 1987-1999 Carnegie Mellon University
+ Additional copyrights listed below
+
+This code is distributed "AS IS" without warranty of any kind under
+the terms of the GNU Library General Public Licence Version 2, as
+shown in the file LICENSE, or under the license shown below. The
+technical and financial contributors to Coda are listed in the file
+CREDITS.
+
+ Additional copyrights
+*/
+
+/*
+
+ Coda: an Experimental Distributed File System
+ Release 4.0
+
+ Copyright (c) 1987-1999 Carnegie Mellon University
+ All Rights Reserved
+
+Permission to use, copy, modify and distribute this software and its
+documentation is hereby granted, provided that both the copyright
+notice and this permission notice appear in all copies of the
+software, derivative works or modified versions, and any portions
+thereof, and that both notices appear in supporting documentation, and
+that credit is given to Carnegie Mellon University in all documents
+and publicity pertaining to direct or indirect use of this code or its
+derivatives.
+
+CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
+SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
+FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
+DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
+RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
+ANY DERIVATIVE WORK.
+
+Carnegie Mellon encourages users of this software to return any
+improvements or extensions that they make, and to grant Carnegie
+Mellon the rights to redistribute these changes without encumbrance.
+*/
+
+/*
+ *
+ * Based on cfs.h from Mach, but revamped for increased simplicity.
+ * Linux modifications by
+ * Peter Braam, Aug 1996
+ */
+
+#ifndef _CODA_HEADER_
+#define _CODA_HEADER_
+
+
+
+/* Catch new _KERNEL defn for NetBSD */
+#ifdef __NetBSD__
+#include <sys/types.h>
+#endif
+
+#ifndef CODA_MAXSYMLINKS
+#define CODA_MAXSYMLINKS 10
+#endif
+
+#if defined(DJGPP) || defined(__CYGWIN32__)
+#ifdef KERNEL
+typedef unsigned long u_long;
+typedef unsigned int u_int;
+typedef unsigned short u_short;
+typedef u_long ino_t;
+typedef u_long dev_t;
+typedef void * caddr_t;
+#ifdef DOS
+typedef unsigned __int64 u_quad_t;
+#else
+typedef unsigned long long u_quad_t;
+#endif
+
+#define inline
+
+struct timespec {
+ long ts_sec;
+ long ts_nsec;
+};
+#else /* DJGPP but not KERNEL */
+#include <sys/types.h>
+#include <sys/time.h>
+typedef unsigned long long u_quad_t;
+#endif /* !KERNEL */
+#endif /* !DJGPP */
+
+
+#if defined(__linux__)
+#define cdev_t u_quad_t
+#ifndef __KERNEL__
+#if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2)
+#define _UQUAD_T_ 1
+typedef unsigned long long u_quad_t;
+#endif
+#else /*__KERNEL__ */
+typedef unsigned long long u_quad_t;
+#endif /* __KERNEL__ */
+#else
+#define cdev_t dev_t
+#endif
+
+#ifdef __CYGWIN32__
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+#endif
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+typedef signed char int8_t;
+typedef unsigned char u_int8_t;
+typedef short int16_t;
+typedef unsigned short u_int16_t;
+typedef int int32_t;
+typedef unsigned int u_int32_t;
+#endif
+
+
+/*
+ * Cfs constants
+ */
+#define CODA_MAXNAMLEN 255
+#define CODA_MAXPATHLEN 1024
+#define CODA_MAXSYMLINK 10
+
+/* these are Coda's version of O_RDONLY etc combinations
+ * to deal with VFS open modes
+ */
+#define C_O_READ 0x001
+#define C_O_WRITE 0x002
+#define C_O_TRUNC 0x010
+#define C_O_EXCL 0x100
+#define C_O_CREAT 0x200
+
+/* these are to find mode bits in Venus */
+#define C_M_READ 00400
+#define C_M_WRITE 00200
+
+/* for access Venus will use */
+#define C_A_C_OK 8 /* Test for writing upon create. */
+#define C_A_R_OK 4 /* Test for read permission. */
+#define C_A_W_OK 2 /* Test for write permission. */
+#define C_A_X_OK 1 /* Test for execute permission. */
+#define C_A_F_OK 0 /* Test for existence. */
+
+
+
+#ifndef _VENUS_DIRENT_T_
+#define _VENUS_DIRENT_T_ 1
+struct venus_dirent {
+ unsigned long d_fileno; /* file number of entry */
+ unsigned short d_reclen; /* length of this record */
+ unsigned char d_type; /* file type, see below */
+ unsigned char d_namlen; /* length of string in d_name */
+ char d_name[CODA_MAXNAMLEN + 1];/* name must be no longer than this */
+};
+#undef DIRSIZ
+#define DIRSIZ(dp) ((sizeof (struct venus_dirent) - (CODA_MAXNAMLEN+1)) + \
+ (((dp)->d_namlen+1 + 3) &~ 3))
+
+/*
+ * File types
+ */
+#define CDT_UNKNOWN 0
+#define CDT_FIFO 1
+#define CDT_CHR 2
+#define CDT_DIR 4
+#define CDT_BLK 6
+#define CDT_REG 8
+#define CDT_LNK 10
+#define CDT_SOCK 12
+#define CDT_WHT 14
+
+/*
+ * Convert between stat structure types and directory types.
+ */
+#define IFTOCDT(mode) (((mode) & 0170000) >> 12)
+#define CDTTOIF(dirtype) ((dirtype) << 12)
+
+#endif
+
+#ifndef _FID_T_
+#define _FID_T_ 1
+typedef u_long VolumeId;
+typedef u_long VnodeId;
+typedef u_long Unique_t;
+typedef u_long FileVersion;
+#endif
+
+#ifndef _VICEFID_T_
+#define _VICEFID_T_ 1
+typedef struct ViceFid {
+ VolumeId Volume;
+ VnodeId Vnode;
+ Unique_t Unique;
+} ViceFid;
+#endif /* VICEFID */
+
+
+#ifdef __linux__
+static __inline__ ino_t coda_f2i(struct ViceFid *fid)
+{
+ if ( ! fid )
+ return 0;
+ if (fid->Vnode == 0xfffffffe || fid->Vnode == 0xffffffff)
+ return ((fid->Volume << 20) | (fid->Unique & 0xfffff));
+ else
+ return (fid->Unique + (fid->Vnode<<10) + (fid->Volume<<20));
+}
+
+#else
+#define coda_f2i(fid)\
+ ((fid) ? ((fid)->Unique + ((fid)->Vnode<<10) + ((fid)->Volume<<20)) : 0)
+#endif
+
+
+#ifndef _VUID_T_
+#define _VUID_T_
+typedef u_int32_t vuid_t;
+typedef u_int32_t vgid_t;
+#endif /*_VUID_T_ */
+
+#ifndef _CODACRED_T_
+#define _CODACRED_T_
+struct coda_cred {
+ vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, efftve, set, fs uid*/
+ vgid_t cr_groupid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */
+};
+#endif
+
+#ifndef _VENUS_VATTR_T_
+#define _VENUS_VATTR_T_
+/*
+ * Vnode types. VNON means no type.
+ */
+enum coda_vtype { C_VNON, C_VREG, C_VDIR, C_VBLK, C_VCHR, C_VLNK, C_VSOCK, C_VFIFO, C_VBAD };
+
+struct coda_vattr {
+ long va_type; /* vnode type (for create) */
+ u_short va_mode; /* files access mode and type */
+ short va_nlink; /* number of references to file */
+ vuid_t va_uid; /* owner user id */
+ vgid_t va_gid; /* owner group id */
+ long va_fileid; /* file id */
+ u_quad_t va_size; /* file size in bytes */
+ long va_blocksize; /* blocksize preferred for i/o */
+ struct timespec va_atime; /* time of last access */
+ struct timespec va_mtime; /* time of last modification */
+ struct timespec va_ctime; /* time file changed */
+ u_long va_gen; /* generation number of file */
+ u_long va_flags; /* flags defined for file */
+ cdev_t va_rdev; /* device special file represents */
+ u_quad_t va_bytes; /* bytes of disk space held by file */
+ u_quad_t va_filerev; /* file modification number */
+};
+
+#endif
+
+/* structure used by CODA_STATFS for getting cache information from venus */
+struct coda_statfs {
+ int32_t f_blocks;
+ int32_t f_bfree;
+ int32_t f_bavail;
+ int32_t f_files;
+ int32_t f_ffree;
+};
+
+/*
+ * Kernel <--> Venus communications.
+ */
+
+#define CODA_ROOT 2
+#define CODA_SYNC 3
+#define CODA_OPEN 4
+#define CODA_CLOSE 5
+#define CODA_IOCTL 6
+#define CODA_GETATTR 7
+#define CODA_SETATTR 8
+#define CODA_ACCESS 9
+#define CODA_LOOKUP 10
+#define CODA_CREATE 11
+#define CODA_REMOVE 12
+#define CODA_LINK 13
+#define CODA_RENAME 14
+#define CODA_MKDIR 15
+#define CODA_RMDIR 16
+#define CODA_READDIR 17
+#define CODA_SYMLINK 18
+#define CODA_READLINK 19
+#define CODA_FSYNC 20
+#define CODA_INACTIVE 21
+#define CODA_VGET 22
+#define CODA_SIGNAL 23
+#define CODA_REPLACE 24
+#define CODA_FLUSH 25
+#define CODA_PURGEUSER 26
+#define CODA_ZAPFILE 27
+#define CODA_ZAPDIR 28
+#define CODA_PURGEFID 30
+#define CODA_OPEN_BY_PATH 31
+#define CODA_RESOLVE 32
+#define CODA_REINTEGRATE 33
+#define CODA_STATFS 34
+#define CODA_NCALLS 35
+
+#define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID)
+
+#define VC_MAXDATASIZE 8192
+#define VC_MAXMSGSIZE sizeof(union inputArgs)+sizeof(union outputArgs) +\
+ VC_MAXDATASIZE
+
+#define CIOC_KERNEL_VERSION _IOWR('c', 10, sizeof (int))
+#if 0
+ /* don't care about kernel version number */
+#define CODA_KERNEL_VERSION 0
+ /* The old venus 4.6 compatible interface */
+#define CODA_KERNEL_VERSION 1
+#endif
+ /* venus_lookup gets an extra parameter to aid windows.*/
+#define CODA_KERNEL_VERSION 2
+
+/*
+ * Venus <-> Coda RPC arguments
+ */
+struct coda_in_hdr {
+ unsigned long opcode;
+ unsigned long unique; /* Keep multiple outstanding msgs distinct */
+ u_short pid; /* Common to all */
+ u_short pgid; /* Common to all */
+ u_short sid; /* Common to all */
+ struct coda_cred cred; /* Common to all */
+};
+
+/* Really important that opcode and unique are 1st two fields! */
+struct coda_out_hdr {
+ unsigned long opcode;
+ unsigned long unique;
+ unsigned long result;
+};
+
+/* coda_root: NO_IN */
+struct coda_root_out {
+ struct coda_out_hdr oh;
+ ViceFid VFid;
+};
+
+struct coda_root_in {
+ struct coda_in_hdr in;
+};
+
+/* coda_sync: */
+/* Nothing needed for coda_sync */
+
+/* coda_open: */
+struct coda_open_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int flags;
+};
+
+struct coda_open_out {
+ struct coda_out_hdr oh;
+ cdev_t dev;
+ ino_t inode;
+};
+
+
+/* coda_close: */
+struct coda_close_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int flags;
+};
+
+struct coda_close_out {
+ struct coda_out_hdr out;
+};
+
+/* coda_ioctl: */
+struct coda_ioctl_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int cmd;
+ int len;
+ int rwflag;
+ char *data; /* Place holder for data. */
+};
+
+struct coda_ioctl_out {
+ struct coda_out_hdr oh;
+ int len;
+ caddr_t data; /* Place holder for data. */
+};
+
+
+/* coda_getattr: */
+struct coda_getattr_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+};
+
+struct coda_getattr_out {
+ struct coda_out_hdr oh;
+ struct coda_vattr attr;
+};
+
+
+/* coda_setattr: NO_OUT */
+struct coda_setattr_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ struct coda_vattr attr;
+};
+
+struct coda_setattr_out {
+ struct coda_out_hdr out;
+};
+
+/* coda_access: NO_OUT */
+struct coda_access_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int flags;
+};
+
+struct coda_access_out {
+ struct coda_out_hdr out;
+};
+
+
+/* lookup flags */
+#define CLU_CASE_SENSITIVE 0x01
+#define CLU_CASE_INSENSITIVE 0x02
+
+/* coda_lookup: */
+struct coda_lookup_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int name; /* Place holder for data. */
+ int flags;
+};
+
+struct coda_lookup_out {
+ struct coda_out_hdr oh;
+ ViceFid VFid;
+ int vtype;
+};
+
+
+/* coda_create: */
+struct coda_create_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ struct coda_vattr attr;
+ int excl;
+ int mode;
+ int name; /* Place holder for data. */
+};
+
+struct coda_create_out {
+ struct coda_out_hdr oh;
+ ViceFid VFid;
+ struct coda_vattr attr;
+};
+
+
+/* coda_remove: NO_OUT */
+struct coda_remove_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int name; /* Place holder for data. */
+};
+
+struct coda_remove_out {
+ struct coda_out_hdr out;
+};
+
+/* coda_link: NO_OUT */
+struct coda_link_in {
+ struct coda_in_hdr ih;
+ ViceFid sourceFid; /* cnode to link *to* */
+ ViceFid destFid; /* Directory in which to place link */
+ int tname; /* Place holder for data. */
+};
+
+struct coda_link_out {
+ struct coda_out_hdr out;
+};
+
+
+/* coda_rename: NO_OUT */
+struct coda_rename_in {
+ struct coda_in_hdr ih;
+ ViceFid sourceFid;
+ int srcname;
+ ViceFid destFid;
+ int destname;
+};
+
+struct coda_rename_out {
+ struct coda_out_hdr out;
+};
+
+/* coda_mkdir: */
+struct coda_mkdir_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ struct coda_vattr attr;
+ int name; /* Place holder for data. */
+};
+
+struct coda_mkdir_out {
+ struct coda_out_hdr oh;
+ ViceFid VFid;
+ struct coda_vattr attr;
+};
+
+
+/* coda_rmdir: NO_OUT */
+struct coda_rmdir_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int name; /* Place holder for data. */
+};
+
+struct coda_rmdir_out {
+ struct coda_out_hdr out;
+};
+
+/* coda_readdir: */
+struct coda_readdir_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int count;
+ int offset;
+};
+
+struct coda_readdir_out {
+ struct coda_out_hdr oh;
+ int size;
+ caddr_t data; /* Place holder for data. */
+};
+
+/* coda_symlink: NO_OUT */
+struct coda_symlink_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid; /* Directory to put symlink in */
+ int srcname;
+ struct coda_vattr attr;
+ int tname;
+};
+
+struct coda_symlink_out {
+ struct coda_out_hdr out;
+};
+
+/* coda_readlink: */
+struct coda_readlink_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+};
+
+struct coda_readlink_out {
+ struct coda_out_hdr oh;
+ int count;
+ caddr_t data; /* Place holder for data. */
+};
+
+
+/* coda_fsync: NO_OUT */
+struct coda_fsync_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+};
+
+struct coda_fsync_out {
+ struct coda_out_hdr out;
+};
+
+/* coda_inactive: NO_OUT */
+struct coda_inactive_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+};
+
+/* coda_vget: */
+struct coda_vget_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+};
+
+struct coda_vget_out {
+ struct coda_out_hdr oh;
+ ViceFid VFid;
+ int vtype;
+};
+
+
+/* CODA_SIGNAL is out-of-band, doesn't need data. */
+/* CODA_INVALIDATE is a venus->kernel call */
+/* CODA_FLUSH is a venus->kernel call */
+
+/* coda_purgeuser: */
+/* CODA_PURGEUSER is a venus->kernel call */
+struct coda_purgeuser_out {
+ struct coda_out_hdr oh;
+ struct coda_cred cred;
+};
+
+/* coda_zapfile: */
+/* CODA_ZAPFILE is a venus->kernel call */
+struct coda_zapfile_out {
+ struct coda_out_hdr oh;
+ ViceFid CodaFid;
+};
+
+/* coda_zapdir: */
+/* CODA_ZAPDIR is a venus->kernel call */
+struct coda_zapdir_out {
+ struct coda_out_hdr oh;
+ ViceFid CodaFid;
+};
+
+/* coda_zapnode: */
+/* CODA_ZAPVNODE is a venus->kernel call */
+struct coda_zapvnode_out {
+ struct coda_out_hdr oh;
+ struct coda_cred cred;
+ ViceFid VFid;
+};
+
+/* coda_purgefid: */
+/* CODA_PURGEFID is a venus->kernel call */
+struct coda_purgefid_out {
+ struct coda_out_hdr oh;
+ ViceFid CodaFid;
+};
+
+/* coda_rdwr: */
+struct coda_rdwr_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int rwflag;
+ int count;
+ int offset;
+ int ioflag;
+ caddr_t data; /* Place holder for data. */
+};
+
+struct coda_rdwr_out {
+ struct coda_out_hdr oh;
+ int rwflag;
+ int count;
+ caddr_t data; /* Place holder for data. */
+};
+
+
+/* coda_replace: */
+/* CODA_REPLACE is a venus->kernel call */
+struct coda_replace_out { /* coda_replace is a venus->kernel call */
+ struct coda_out_hdr oh;
+ ViceFid NewFid;
+ ViceFid OldFid;
+};
+
+/* coda_open_by_path: */
+struct coda_open_by_path_in {
+ struct coda_in_hdr ih;
+ ViceFid VFid;
+ int flags;
+};
+
+struct coda_open_by_path_out {
+ struct coda_out_hdr oh;
+ int path;
+};
+
+/* coda_statfs: NO_IN */
+struct coda_statfs_in {
+ struct coda_in_hdr in;
+};
+
+struct coda_statfs_out {
+ struct coda_out_hdr oh;
+ struct coda_statfs stat;
+};
+
+/*
+ * Occasionally, we don't cache the fid returned by CODA_LOOKUP.
+ * For instance, if the fid is inconsistent.
+ * This case is handled by setting the top bit of the type result parameter.
+ */
+#define CODA_NOCACHE 0x80000000
+
+union inputArgs {
+ struct coda_in_hdr ih; /* NB: every struct below begins with an ih */
+ struct coda_open_in coda_open;
+ struct coda_close_in coda_close;
+ struct coda_ioctl_in coda_ioctl;
+ struct coda_getattr_in coda_getattr;
+ struct coda_setattr_in coda_setattr;
+ struct coda_access_in coda_access;
+ struct coda_lookup_in coda_lookup;
+ struct coda_create_in coda_create;
+ struct coda_remove_in coda_remove;
+ struct coda_link_in coda_link;
+ struct coda_rename_in coda_rename;
+ struct coda_mkdir_in coda_mkdir;
+ struct coda_rmdir_in coda_rmdir;
+ struct coda_readdir_in coda_readdir;
+ struct coda_symlink_in coda_symlink;
+ struct coda_readlink_in coda_readlink;
+ struct coda_fsync_in coda_fsync;
+ struct coda_inactive_in coda_inactive;
+ struct coda_vget_in coda_vget;
+ struct coda_rdwr_in coda_rdwr;
+ struct coda_open_by_path_in coda_open_by_path;
+ struct coda_statfs_in coda_statfs;
+};
+
+union outputArgs {
+ struct coda_out_hdr oh; /* NB: every struct below begins with an oh */
+ struct coda_root_out coda_root;
+ struct coda_open_out coda_open;
+ struct coda_ioctl_out coda_ioctl;
+ struct coda_getattr_out coda_getattr;
+ struct coda_lookup_out coda_lookup;
+ struct coda_create_out coda_create;
+ struct coda_mkdir_out coda_mkdir;
+ struct coda_readdir_out coda_readdir;
+ struct coda_readlink_out coda_readlink;
+ struct coda_vget_out coda_vget;
+ struct coda_purgeuser_out coda_purgeuser;
+ struct coda_zapfile_out coda_zapfile;
+ struct coda_zapdir_out coda_zapdir;
+ struct coda_zapvnode_out coda_zapvnode;
+ struct coda_purgefid_out coda_purgefid;
+ struct coda_rdwr_out coda_rdwr;
+ struct coda_replace_out coda_replace;
+ struct coda_open_by_path_out coda_open_by_path;
+ struct coda_statfs_out coda_statfs;
+};
+
+union coda_downcalls {
+ /* CODA_INVALIDATE is a venus->kernel call */
+ /* CODA_FLUSH is a venus->kernel call */
+ struct coda_purgeuser_out purgeuser;
+ struct coda_zapfile_out zapfile;
+ struct coda_zapdir_out zapdir;
+ struct coda_zapvnode_out zapvnode;
+ struct coda_purgefid_out purgefid;
+ struct coda_replace_out replace;
+};
+
+
+/*
+ * Used for identifying usage of "Control" and pioctls
+ */
+
+#define PIOCPARM_MASK 0x0000ffff
+struct ViceIoctl {
+ caddr_t in, out; /* Data to be transferred in, or out */
+ short in_size; /* Size of input buffer <= 2K */
+ short out_size; /* Maximum size of output buffer, <= 2K */
+};
+
+struct PioctlData {
+ const char *path;
+ int follow;
+ struct ViceIoctl vi;
+};
+
+#define CODA_CONTROL ".CONTROL"
+#define CODA_CONTROLLEN 8
+#define CTL_VOL -1
+#define CTL_VNO -1
+#define CTL_UNI -1
+#define CTL_INO -1
+#define CTL_FILE "/coda/.CONTROL"
+
+
+#define IS_CTL_FID(fidp) ((fidp)->Volume == CTL_VOL &&\
+ (fidp)->Vnode == CTL_VNO &&\
+ (fidp)->Unique == CTL_UNI)
+#endif
+
diff --git a/pfinet/linux-src/include/linux/coda_cache.h b/pfinet/linux-src/include/linux/coda_cache.h
new file mode 100644
index 00000000..e549b02e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coda_cache.h
@@ -0,0 +1,77 @@
+/* Coda filesystem -- Linux Minicache
+ *
+ * Copyright (C) 1989 - 1997 Carnegie Mellon University
+ *
+ * Carnegie Mellon University encourages users of this software to
+ * contribute improvements to the Coda project. Contact Peter Braam
+ * <coda@cs.cmu.edu>
+ */
+
+#ifndef _CFSNC_HEADER_
+#define _CFSNC_HEADER_
+
+/*
+ * Structure for an element in the Coda Credential Cache.
+ */
+
+struct coda_cache {
+ struct list_head cc_cclist; /* list of all cache entries */
+ struct list_head cc_cnlist; /* list of cache entries/cnode */
+ int cc_mask;
+ struct coda_cred cc_cred;
+};
+
+/* credential cache */
+void coda_cache_enter(struct inode *inode, int mask);
+void coda_cache_clear_inode(struct inode *);
+void coda_cache_clear_all(struct super_block *sb);
+void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred);
+int coda_cache_check(struct inode *inode, int mask);
+
+/* for downcalls and attributes and lookups */
+void coda_flag_inode(struct inode *inode, int flag);
+void coda_flag_inode_children(struct inode *inode, int flag);
+
+
+/*
+ * Structure to contain statistics on the cache usage
+ */
+
+struct cfsnc_statistics {
+ unsigned hits;
+ unsigned misses;
+ unsigned enters;
+ unsigned dbl_enters;
+ unsigned long_name_enters;
+ unsigned long_name_lookups;
+ unsigned long_remove;
+ unsigned lru_rm;
+ unsigned zapPfids;
+ unsigned zapFids;
+ unsigned zapFile;
+ unsigned zapUsers;
+ unsigned Flushes;
+ unsigned Sum_bucket_len;
+ unsigned Sum2_bucket_len;
+ unsigned Max_bucket_len;
+ unsigned Num_zero_len;
+ unsigned Search_len;
+};
+
+
+#define CFSNC_FIND ((u_long) 1)
+#define CFSNC_REMOVE ((u_long) 2)
+#define CFSNC_INIT ((u_long) 3)
+#define CFSNC_ENTER ((u_long) 4)
+#define CFSNC_LOOKUP ((u_long) 5)
+#define CFSNC_ZAPPFID ((u_long) 6)
+#define CFSNC_ZAPFID ((u_long) 7)
+#define CFSNC_ZAPVNODE ((u_long) 8)
+#define CFSNC_ZAPFILE ((u_long) 9)
+#define CFSNC_PURGEUSER ((u_long) 10)
+#define CFSNC_FLUSH ((u_long) 11)
+#define CFSNC_PRINTCFSNC ((u_long) 12)
+#define CFSNC_PRINTSTATS ((u_long) 13)
+#define CFSNC_REPLACE ((u_long) 14)
+
+#endif _CFSNC_HEADER_
diff --git a/pfinet/linux-src/include/linux/coda_fs_i.h b/pfinet/linux-src/include/linux/coda_fs_i.h
new file mode 100644
index 00000000..8a55e8e3
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coda_fs_i.h
@@ -0,0 +1,56 @@
+/*
+ * coda_fs_i.h
+ *
+ * Copyright (C) 1998 Carnegie Mellon University
+ *
+ */
+
+#ifndef _LINUX_CODA_FS_I
+#define _LINUX_CODA_FS_I
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/coda.h>
+
+
+
+#define CODA_CNODE_MAGIC 0x47114711
+/*
+ * coda fs inode data
+ */
+struct coda_inode_info {
+ /*
+ * This is a place holder so named pipes work (more or less
+ * correctly). This must be first in the struct because the
+ * data is really accessed via inode->u.pipe_i.
+ */
+ struct pipe_inode_info pipeinfo;
+
+ struct ViceFid c_fid; /* Coda identifier */
+ u_short c_flags; /* flags (see below) */
+ u_short c_ocount; /* count of openers */
+ u_short c_owrite; /* count of open for write */
+ u_short c_mmcount; /* count of mmappers */
+ struct inode *c_ovp; /* open inode pointer */
+ struct list_head c_cnhead; /* head of cache entries */
+ struct list_head c_volrootlist; /* list of volroot cnoddes */
+ struct inode *c_vnode; /* inode associated with cnode */
+ int c_magic; /* to verify the data structure */
+};
+
+/* flags */
+#define C_VATTR 0x1 /* Validity of vattr in inode */
+#define C_PURGE 0x8
+#define C_ZAPDIR 0x10
+#define C_DYING 0x4 /* from venus (which died) */
+#define C_INITED 0x20
+#define C_FLUSH 0x2 /* used after a flush */
+
+int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *);
+int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
+struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb);
+void coda_replace_fid(struct inode *, ViceFid *, ViceFid *);
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/coda_linux.h b/pfinet/linux-src/include/linux/coda_linux.h
new file mode 100644
index 00000000..cd0e46ce
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coda_linux.h
@@ -0,0 +1,143 @@
+/*
+ * Coda File System, Linux Kernel module
+ *
+ * Original version, adapted from cfs_mach.c, (C) Carnegie Mellon University
+ * Linux modifications (C) 1996, Peter J. Braam
+ * Rewritten for Linux 2.1 (C) 1997 Carnegie Mellon University
+ *
+ * Carnegie Mellon University encourages users of this software to
+ * contribute improvements to the Coda project.
+ */
+
+#ifndef _LINUX_CODA_FS
+#define _LINUX_CODA_FS
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/malloc.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+
+/* operations */
+extern struct inode_operations coda_dir_inode_operations;
+extern struct inode_operations coda_file_inode_operations;
+extern struct inode_operations coda_ioctl_inode_operations;
+extern struct inode_operations coda_symlink_inode_operations;
+
+extern struct file_operations coda_dir_operations;
+extern struct file_operations coda_file_operations;
+extern struct file_operations coda_ioctl_operations;
+
+/* operations shared over more than one file */
+int coda_open(struct inode *i, struct file *f);
+int coda_release(struct inode *i, struct file *f);
+int coda_permission(struct inode *inode, int mask);
+int coda_revalidate_inode(struct dentry *);
+
+/* global variables */
+extern int coda_debug;
+extern int coda_print_entry;
+extern int coda_access_cache;
+
+/* this file: heloers */
+static __inline__ struct ViceFid *coda_i2f(struct inode *);
+char *coda_f2s(ViceFid *f);
+char *coda_f2s2(ViceFid *f);
+int coda_isroot(struct inode *i);
+int coda_fid_is_volroot(struct ViceFid *);
+int coda_fid_is_weird(struct ViceFid *fid);
+int coda_iscontrol(const char *name, size_t length);
+
+void coda_load_creds(struct coda_cred *cred);
+int coda_mycred(struct coda_cred *);
+void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
+void coda_iattr_to_vattr(struct iattr *, struct coda_vattr *);
+unsigned short coda_flags_to_cflags(unsigned short);
+void print_vattr( struct coda_vattr *attr );
+int coda_cred_ok(struct coda_cred *cred);
+int coda_cred_eq(struct coda_cred *cred1, struct coda_cred *cred2);
+
+/* defined in file.c */
+void coda_prepare_openfile(struct inode *coda_inode, struct file *coda_file,
+ struct inode *open_inode, struct file *open_file,
+ struct dentry *open_dentry);
+void coda_restore_codafile(struct inode *coda_inode, struct file *coda_file,
+ struct inode *open_inode, struct file *open_file);
+int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind);
+
+#define NB_SFS_SIZ 0x895440
+
+/* cache.c */
+void coda_purge_children(struct inode *, int);
+void coda_purge_dentries(struct inode *);
+
+/* sysctl.h */
+void coda_sysctl_init(void);
+void coda_sysctl_clean(void);
+
+
+/* debugging masks */
+#define D_SUPER 1 /* print results returned by Venus */
+#define D_INODE 2 /* print entry and exit into procedure */
+#define D_FILE 4
+#define D_CACHE 8 /* cache debugging */
+#define D_MALLOC 16 /* print malloc, de-alloc information */
+#define D_CNODE 32
+#define D_UPCALL 64 /* up and downcall debugging */
+#define D_PSDEV 128
+#define D_PIOCTL 256
+#define D_SPECIAL 512
+#define D_TIMING 1024
+#define D_DOWNCALL 2048
+
+#define CDEBUG(mask, format, a...) \
+ do { \
+ if (coda_debug & mask) { \
+ printk("(%s,l. %d): ", __FUNCTION__, __LINE__); \
+ printk(format, ## a); } \
+} while (0) ;
+
+#define ENTRY \
+ if(coda_print_entry) printk("Process %d entered %s\n",current->pid,__FUNCTION__)
+
+#define EXIT \
+ if(coda_print_entry) printk("Process %d leaving %s\n",current->pid,__FUNCTION__)
+
+#define CHECK_CNODE(c) do { } while (0);
+
+#define CODA_ALLOC(ptr, cast, size) \
+do { \
+ if (size < 3000) { \
+ ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL); \
+ CDEBUG(D_MALLOC, "kmalloced: %lx at %p.\n", (long)size, ptr);\
+ } else { \
+ ptr = (cast)vmalloc((unsigned long) size); \
+ CDEBUG(D_MALLOC, "vmalloced: %lx at %p .\n", (long)size, ptr);}\
+ if (ptr == 0) { \
+ printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \
+ } \
+ memset( ptr, 0, size ); \
+} while (0)
+
+
+#define CODA_FREE(ptr,size) do {if (size < 3000) { kfree_s((ptr), (size)); CDEBUG(D_MALLOC, "kfreed: %lx at %p.\n", (long) size, ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %lx at %p.\n", (long) size, ptr);} } while (0)
+
+/* inode to cnode */
+
+static __inline__ struct ViceFid *coda_i2f(struct inode *inode)
+{
+ return &(inode->u.coda_i.c_fid);
+}
+
+#define ITOC(inode) (&((inode)->u.coda_i))
+
+
+
+
+
+
+#endif
diff --git a/pfinet/linux-src/include/linux/coda_opstats.h b/pfinet/linux-src/include/linux/coda_opstats.h
new file mode 100644
index 00000000..167490d8
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coda_opstats.h
@@ -0,0 +1,94 @@
+
+/*
+ * Operation statistics for Coda.
+ * Copyright (C) 1997 Carnegie Mellon University
+ *
+ * Carnegie Mellon University encourages users of this software
+ * to contribute improvements to the Coda project. Contact Peter Braam
+ * <coda@coda.cs.cmu.edu>.
+ */
+
+
+
+#define CFS_MOUNT_STATS 0
+#define CFS_UMOUNT_STATS 1
+#define CFS_ROOT_STATS 2
+#define CFS_STATFS_STATS 3
+#define CFS_SYNC_STATS 4
+#define CFS_VGET_STATS 5
+#define CFS_VFSOPS_SIZE 6
+
+/* vnodeops:
+ * open: all to venus
+ * close: all to venus
+ * rdrw: bogus. Maybe redirected to UFS.
+ * May call open/close for internal opens/closes
+ * (Does exec not call open?)
+ * ioctl: causes a lookupname
+ * passes through
+ * select: can't get there from here.
+ * getattr: can be satsified by cache
+ * setattr: all go through
+ * access: can be satisfied by cache
+ * readlink: can be satisfied by cache
+ * fsync: passes through
+ * inactive: passes through
+ * lookup: can be satisfied by cache
+ * create: passes through
+ * remove: passes through
+ * link: passes through
+ * rename: passes through
+ * mkdir: passes through
+ * rmdir: passes through
+ * symlink: passes through
+ * readdir: may be redirected to UFS
+ * may cause an "internal" open/close
+ */
+
+#define CFS_OPEN_STATS 0
+#define CFS_CLOSE_STATS 1
+#define CFS_RDWR_STATS 2
+#define CFS_IOCTL_STATS 3
+#define CFS_SELECT_STATS 4
+#define CFS_GETATTR_STATS 5
+#define CFS_SETATTR_STATS 6
+#define CFS_ACCESS_STATS 7
+#define CFS_READLINK_STATS 8
+#define CFS_FSYNC_STATS 9
+#define CFS_INACTIVE_STATS 10
+#define CFS_LOOKUP_STATS 11
+#define CFS_CREATE_STATS 12
+#define CFS_REMOVE_STATS 13
+#define CFS_LINK_STATS 14
+#define CFS_RENAME_STATS 15
+#define CFS_MKDIR_STATS 16
+#define CFS_RMDIR_STATS 17
+#define CFS_SYMLINK_STATS 18
+#define CFS_READDIR_STATS 19
+#define CFS_VNODEOPS_SIZE 20
+
+
+/*
+ * I propose the following structres:
+ */
+
+
+struct cfs_op_stats {
+ int opcode; /* vfs opcode */
+ long entries; /* number of times call attempted */
+ long sat_intrn; /* number of times call satisfied by cache */
+ long unsat_intrn; /* number of times call failed in cache, but
+ was not bounced to venus proper. */
+ long gen_intrn; /* number of times call generated internally */
+ /* (do we need that?) */
+};
+
+
+/*
+ * With each call to the minicache, we'll bump the counters whenever
+ * a call is satisfied internally (through the cache or through a
+ * redirect), and whenever an operation is caused internally.
+ * Then, we can add the total operations caught by the minicache
+ * to the world-wide totals, and leave a caveat for the specific
+ * graphs later.
+ */
diff --git a/pfinet/linux-src/include/linux/coda_proc.h b/pfinet/linux-src/include/linux/coda_proc.h
new file mode 100644
index 00000000..7c4ca8a0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coda_proc.h
@@ -0,0 +1,145 @@
+/*
+ * coda_statis.h
+ *
+ * CODA operation statistics
+ *
+ * (c) March, 1998
+ * by Michihiro Kuramochi, Zhenyu Xia and Zhanyong Wan
+ * zhanyong.wan@yale.edu
+ *
+ */
+
+#ifndef _CODA_PROC_H
+#define _CODA_PROC_H
+
+void coda_sysctl_init(void);
+void coda_sysctl_clean(void);
+void coda_upcall_stats(int opcode, unsigned long jiffies);
+
+#include <linux/sysctl.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda.h>
+
+/* these four files are presented to show the result of the statistics:
+ *
+ * /proc/fs/coda/vfs_stats
+ * upcall_stats
+ * permission_stats
+ * cache_inv_stats
+ *
+ * these four files are presented to reset the statistics to 0:
+ *
+ * /proc/sys/coda/vfs_stats
+ * upcall_stats
+ * permission_stats
+ * cache_inv_stats
+ */
+
+/* VFS operation statistics */
+struct coda_vfs_stats
+{
+ /* file operations */
+ int file_read;
+ int file_write;
+ int file_mmap;
+ int open;
+ int release;
+ int fsync;
+
+ /* dir operations */
+ int readdir;
+
+ /* inode operations */
+ int create;
+ int lookup;
+ int link;
+ int unlink;
+ int symlink;
+ int mkdir;
+ int rmdir;
+ int rename;
+ int permission;
+ int readpage;
+
+ /* symlink operatoins*/
+ int follow_link;
+ int readlink;
+};
+
+struct coda_upcall_stats_entry
+{
+ int count;
+ unsigned long time_sum;
+ unsigned long time_squared_sum;
+};
+
+
+
+/* cache hits for permissions statistics */
+struct coda_permission_stats
+{
+ int count;
+ int hit_count;
+};
+
+/* cache invalidation statistics */
+struct coda_cache_inv_stats
+{
+ int flush;
+ int purge_user;
+ int zap_dir;
+ int zap_file;
+ int zap_vnode;
+ int purge_fid;
+ int replace;
+};
+
+/* these global variables hold the actual statistics data */
+extern struct coda_vfs_stats coda_vfs_stat;
+extern struct coda_permission_stats coda_permission_stat;
+extern struct coda_cache_inv_stats coda_cache_inv_stat;
+extern int coda_upcall_timestamping;
+
+/* reset statistics to 0 */
+void reset_coda_vfs_stats( void );
+void reset_coda_upcall_stats( void );
+void reset_coda_permission_stats( void );
+void reset_coda_cache_inv_stats( void );
+
+/* some utitlities to make it easier for you to do statistics for time */
+void do_time_stats( struct coda_upcall_stats_entry * pentry,
+ unsigned long jiffy );
+/*
+double get_time_average( const struct coda_upcall_stats_entry * pentry );
+double get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
+*/
+unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry );
+unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
+
+/* like coda_dointvec, these functions are to be registered in the ctl_table
+ * data structure for /proc/sys/... files
+ */
+int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
+ void * buffer, size_t * lenp );
+int do_reset_coda_upcall_stats( ctl_table * table, int write,
+ struct file * filp, void * buffer,
+ size_t * lenp );
+int do_reset_coda_permission_stats( ctl_table * table, int write,
+ struct file * filp, void * buffer,
+ size_t * lenp );
+int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
+ struct file * filp, void * buffer,
+ size_t * lenp );
+
+/* these functions are called to form the content of /proc/fs/coda/... files */
+int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy );
+int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy );
+int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy );
+int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
+ int length, int dummy );
+
+
+#endif /* _CODA_PROC_H */
diff --git a/pfinet/linux-src/include/linux/coda_psdev.h b/pfinet/linux-src/include/linux/coda_psdev.h
new file mode 100644
index 00000000..8c564f9a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coda_psdev.h
@@ -0,0 +1,131 @@
+#ifndef __CODA_PSDEV_H
+#define __CODA_PSDEV_H
+
+#define CODA_PSDEV_MAJOR 67
+#define MAX_CODADEVS 5 /* how many do we allow */
+
+extern struct venus_comm coda_upc_comm;
+extern struct coda_sb_info coda_super_info;
+#define CODA_SUPER_MAGIC 0x73757245
+
+struct coda_sb_info
+{
+ struct inode * sbi_psdev; /* /dev/cfs? Venus/kernel device */
+ struct inode * sbi_ctlcp; /* control magic file */
+ int sbi_refct;
+ struct venus_comm * sbi_vcomm;
+ struct inode * sbi_root;
+ struct super_block *sbi_sb;
+ struct list_head sbi_cchead;
+ struct list_head sbi_volroothead;
+};
+
+/* communication pending/processing queues */
+struct venus_comm {
+ u_long vc_seq;
+ struct wait_queue *vc_waitq; /* Venus wait queue */
+ struct list_head vc_pending;
+ struct list_head vc_processing;
+ int vc_inuse;
+ pid_t vc_pid; /* Venus pid */
+};
+
+
+static inline struct coda_sb_info *coda_sbp(struct super_block *sb)
+{
+ return ((struct coda_sb_info *)((sb)->u.generic_sbp));
+}
+
+
+
+extern void coda_psdev_detach(int unit);
+extern int init_coda_psdev(void);
+
+
+/* upcalls */
+int venus_rootfid(struct super_block *sb, ViceFid *fidp);
+int venus_getattr(struct super_block *sb, struct ViceFid *fid,
+ struct coda_vattr *attr);
+int venus_setattr(struct super_block *, struct ViceFid *,
+ struct coda_vattr *);
+int venus_lookup(struct super_block *sb, struct ViceFid *fid,
+ const char *name, int length, int *type,
+ struct ViceFid *resfid);
+int venus_release(struct super_block *sb, struct ViceFid *fid, int flags,
+ struct coda_cred *);
+int venus_open(struct super_block *sb, struct ViceFid *fid,
+ int flags, ino_t *ino, dev_t *dev);
+int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
+ const char *name, int length,
+ struct ViceFid *newfid, struct coda_vattr *attrs);
+int venus_create(struct super_block *sb, struct ViceFid *dirfid,
+ const char *name, int length, int excl, int mode, int rdev,
+ struct ViceFid *newfid, struct coda_vattr *attrs) ;
+int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
+ const char *name, int length);
+int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
+ const char *name, int length);
+int venus_readlink(struct super_block *sb, struct ViceFid *fid,
+ char *buffer, int *length);
+int venus_rename(struct super_block *, struct ViceFid *new_fid,
+ struct ViceFid *old_fid, size_t old_length,
+ size_t new_length, const char *old_name,
+ const char *new_name);
+int venus_link(struct super_block *sb, struct ViceFid *fid,
+ struct ViceFid *dirfid, const char *name, int len );
+int venus_symlink(struct super_block *sb, struct ViceFid *fid,
+ const char *name, int len, const char *symname, int symlen);
+int venus_access(struct super_block *sb, struct ViceFid *fid, int mask);
+int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
+ unsigned int cmd, struct PioctlData *data);
+int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb);
+int venus_fsync(struct super_block *sb, struct ViceFid *fid);
+int venus_statfs(struct super_block *sb, struct statfs *sfs);
+
+
+/* messages between coda filesystem in kernel and Venus */
+extern int coda_hard;
+extern unsigned long coda_timeout;
+struct upc_req {
+ struct list_head uc_chain;
+ caddr_t uc_data;
+ u_short uc_flags;
+ u_short uc_inSize; /* Size is at most 5000 bytes */
+ u_short uc_outSize;
+ u_short uc_opcode; /* copied from data to save lookup */
+ int uc_unique;
+ struct wait_queue *uc_sleep; /* process' wait queue */
+ unsigned long uc_posttime;
+};
+
+#define REQ_ASYNC 0x1
+#define REQ_READ 0x2
+#define REQ_WRITE 0x4
+
+
+/*
+ * Statistics
+ */
+struct coda_upcallstats {
+ int ncalls; /* client requests */
+ int nbadcalls; /* upcall failures */
+ int reqs[CODA_NCALLS]; /* count of each request */
+} ;
+
+extern struct coda_upcallstats coda_callstats;
+
+static inline void clstats(int opcode)
+{
+ coda_callstats.ncalls++;
+ if ( (0 <= opcode) && (opcode <= CODA_NCALLS) )
+ coda_callstats.reqs[opcode]++;
+ else
+ printk("clstats called with bad opcode %d\n", opcode);
+}
+
+static inline void badclstats(void)
+{
+ coda_callstats.nbadcalls++;
+}
+
+#endif
diff --git a/pfinet/linux-src/include/linux/coff.h b/pfinet/linux-src/include/linux/coff.h
new file mode 100644
index 00000000..a1ba4666
--- /dev/null
+++ b/pfinet/linux-src/include/linux/coff.h
@@ -0,0 +1,351 @@
+/* This file is derived from the GAS 2.1.4 assembler control file.
+ The GAS product is under the GNU Public License, version 2 or later.
+ As such, this file is also under that license.
+
+ If the file format changes in the COFF object, this file should be
+ subsequently updated to reflect the changes.
+
+ The actual loader module only uses a few of these structures. The full
+ set is documented here because I received the full set. If you wish
+ more information about COFF, then O'Reilly has a very excellent book.
+*/
+
+#define E_SYMNMLEN 8 /* Number of characters in a symbol name */
+#define E_FILNMLEN 14 /* Number of characters in a file name */
+#define E_DIMNUM 4 /* Number of array dimensions in auxiliary entry */
+
+/*
+ * These defines are byte order independent. There is no alignment of fields
+ * permitted in the structures. Therefore they are declared as characters
+ * and the values loaded from the character positions. It also makes it
+ * nice to have it "endian" independent.
+ */
+
+/* Load a short int from the following tables with little-endian formats */
+#define COFF_SHORT_L(ps) ((short)(((unsigned short)((unsigned char)ps[1])<<8)|\
+ ((unsigned short)((unsigned char)ps[0]))))
+
+/* Load a long int from the following tables with little-endian formats */
+#define COFF_LONG_L(ps) (((long)(((unsigned long)((unsigned char)ps[3])<<24) |\
+ ((unsigned long)((unsigned char)ps[2])<<16) |\
+ ((unsigned long)((unsigned char)ps[1])<<8) |\
+ ((unsigned long)((unsigned char)ps[0])))))
+
+/* Load a short int from the following tables with big-endian formats */
+#define COFF_SHORT_H(ps) ((short)(((unsigned short)((unsigned char)ps[0])<<8)|\
+ ((unsigned short)((unsigned char)ps[1]))))
+
+/* Load a long int from the following tables with big-endian formats */
+#define COFF_LONG_H(ps) (((long)(((unsigned long)((unsigned char)ps[0])<<24) |\
+ ((unsigned long)((unsigned char)ps[1])<<16) |\
+ ((unsigned long)((unsigned char)ps[2])<<8) |\
+ ((unsigned long)((unsigned char)ps[3])))))
+
+/* These may be overridden later by brain dead implementations which generate
+ a big-endian header with little-endian data. In that case, generate a
+ replacement macro which tests a flag and uses either of the two above
+ as appropriate. */
+
+#define COFF_LONG(v) COFF_LONG_L(v)
+#define COFF_SHORT(v) COFF_SHORT_L(v)
+
+/*** coff information for Intel 386/486. */
+
+/********************** FILE HEADER **********************/
+
+struct COFF_filehdr {
+ char f_magic[2]; /* magic number */
+ char f_nscns[2]; /* number of sections */
+ char f_timdat[4]; /* time & date stamp */
+ char f_symptr[4]; /* file pointer to symtab */
+ char f_nsyms[4]; /* number of symtab entries */
+ char f_opthdr[2]; /* sizeof(optional hdr) */
+ char f_flags[2]; /* flags */
+};
+
+/*
+ * Bits for f_flags:
+ *
+ * F_RELFLG relocation info stripped from file
+ * F_EXEC file is executable (i.e. no unresolved external
+ * references)
+ * F_LNNO line numbers stripped from file
+ * F_LSYMS local symbols stripped from file
+ * F_MINMAL this is a minimal object file (".m") output of fextract
+ * F_UPDATE this is a fully bound update file, output of ogen
+ * F_SWABD this file has had its bytes swabbed (in names)
+ * F_AR16WR this file has the byte ordering of an AR16WR
+ * (e.g. 11/70) machine
+ * F_AR32WR this file has the byte ordering of an AR32WR machine
+ * (e.g. vax and iNTEL 386)
+ * F_AR32W this file has the byte ordering of an AR32W machine
+ * (e.g. 3b,maxi)
+ * F_PATCH file contains "patch" list in optional header
+ * F_NODF (minimal file only) no decision functions for
+ * replaced functions
+ */
+
+#define COFF_F_RELFLG 0000001
+#define COFF_F_EXEC 0000002
+#define COFF_F_LNNO 0000004
+#define COFF_F_LSYMS 0000010
+#define COFF_F_MINMAL 0000020
+#define COFF_F_UPDATE 0000040
+#define COFF_F_SWABD 0000100
+#define COFF_F_AR16WR 0000200
+#define COFF_F_AR32WR 0000400
+#define COFF_F_AR32W 0001000
+#define COFF_F_PATCH 0002000
+#define COFF_F_NODF 0002000
+
+#define COFF_I386MAGIC 0x14c /* Linux's system */
+
+#if 0 /* Perhaps, someday, these formats may be used. */
+#define COFF_I386PTXMAGIC 0x154
+#define COFF_I386AIXMAGIC 0x175 /* IBM's AIX system */
+#define COFF_I386BADMAG(x) ((COFF_SHORT((x).f_magic) != COFF_I386MAGIC) \
+ && COFF_SHORT((x).f_magic) != COFF_I386PTXMAGIC \
+ && COFF_SHORT((x).f_magic) != COFF_I386AIXMAGIC)
+#else
+#define COFF_I386BADMAG(x) (COFF_SHORT((x).f_magic) != COFF_I386MAGIC)
+#endif
+
+#define COFF_FILHDR struct COFF_filehdr
+#define COFF_FILHSZ sizeof(COFF_FILHDR)
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+/* Linux COFF must have this "optional" header. Standard COFF has no entry
+ location for the "entry" point. They normally would start with the first
+ location of the .text section. This is not a good idea for linux. So,
+ the use of this "optional" header is not optional. It is required.
+
+ Do not be tempted to assume that the size of the optional header is
+ a constant and simply index the next byte by the size of this structure.
+ Use the 'f_opthdr' field in the main coff header for the size of the
+ structure actually written to the file!!
+*/
+
+typedef struct
+{
+ char magic[2]; /* type of file */
+ char vstamp[2]; /* version stamp */
+ char tsize[4]; /* text size in bytes, padded to FW bdry */
+ char dsize[4]; /* initialized data " " */
+ char bsize[4]; /* uninitialized data " " */
+ char entry[4]; /* entry pt. */
+ char text_start[4]; /* base of text used for this file */
+ char data_start[4]; /* base of data used for this file */
+}
+COFF_AOUTHDR;
+
+#define COFF_AOUTSZ (sizeof(COFF_AOUTHDR))
+
+#define COFF_STMAGIC 0401
+#define COFF_OMAGIC 0404
+#define COFF_JMAGIC 0407 /* dirty text and data image, can't share */
+#define COFF_DMAGIC 0410 /* dirty text segment, data aligned */
+#define COFF_ZMAGIC 0413 /* The proper magic number for executables */
+#define COFF_SHMAGIC 0443 /* shared library header */
+
+/********************** SECTION HEADER **********************/
+
+struct COFF_scnhdr {
+ char s_name[8]; /* section name */
+ char s_paddr[4]; /* physical address, aliased s_nlib */
+ char s_vaddr[4]; /* virtual address */
+ char s_size[4]; /* section size */
+ char s_scnptr[4]; /* file ptr to raw data for section */
+ char s_relptr[4]; /* file ptr to relocation */
+ char s_lnnoptr[4]; /* file ptr to line numbers */
+ char s_nreloc[2]; /* number of relocation entries */
+ char s_nlnno[2]; /* number of line number entries */
+ char s_flags[4]; /* flags */
+};
+
+#define COFF_SCNHDR struct COFF_scnhdr
+#define COFF_SCNHSZ sizeof(COFF_SCNHDR)
+
+/*
+ * names of "special" sections
+ */
+
+#define COFF_TEXT ".text"
+#define COFF_DATA ".data"
+#define COFF_BSS ".bss"
+#define COFF_COMMENT ".comment"
+#define COFF_LIB ".lib"
+
+#define COFF_SECT_TEXT 0 /* Section for instruction code */
+#define COFF_SECT_DATA 1 /* Section for initialized globals */
+#define COFF_SECT_BSS 2 /* Section for un-initialized globals */
+#define COFF_SECT_REQD 3 /* Minimum number of sections for good file */
+
+#define COFF_STYP_REG 0x00 /* regular segment */
+#define COFF_STYP_DSECT 0x01 /* dummy segment */
+#define COFF_STYP_NOLOAD 0x02 /* no-load segment */
+#define COFF_STYP_GROUP 0x04 /* group segment */
+#define COFF_STYP_PAD 0x08 /* .pad segment */
+#define COFF_STYP_COPY 0x10 /* copy section */
+#define COFF_STYP_TEXT 0x20 /* .text segment */
+#define COFF_STYP_DATA 0x40 /* .data segment */
+#define COFF_STYP_BSS 0x80 /* .bss segment */
+#define COFF_STYP_INFO 0x200 /* .comment section */
+#define COFF_STYP_OVER 0x400 /* overlay section */
+#define COFF_STYP_LIB 0x800 /* library section */
+
+/*
+ * Shared libraries have the following section header in the data field for
+ * each library.
+ */
+
+struct COFF_slib {
+ char sl_entsz[4]; /* Size of this entry */
+ char sl_pathndx[4]; /* size of the header field */
+};
+
+#define COFF_SLIBHD struct COFF_slib
+#define COFF_SLIBSZ sizeof(COFF_SLIBHD)
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+
+struct COFF_lineno {
+ union {
+ char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
+ char l_paddr[4]; /* (physical) address of line number */
+ } l_addr;
+ char l_lnno[2]; /* line number */
+};
+
+#define COFF_LINENO struct COFF_lineno
+#define COFF_LINESZ 6
+
+/********************** SYMBOLS **********************/
+
+#define COFF_E_SYMNMLEN 8 /* # characters in a short symbol name */
+#define COFF_E_FILNMLEN 14 /* # characters in a file name */
+#define COFF_E_DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+/*
+ * All symbols and sections have the following definition
+ */
+
+struct COFF_syment
+{
+ union {
+ char e_name[E_SYMNMLEN]; /* Symbol name (first 8 characters) */
+ struct {
+ char e_zeroes[4]; /* Leading zeros */
+ char e_offset[4]; /* Offset if this is a header section */
+ } e;
+ } e;
+
+ char e_value[4]; /* Value (address) of the segment */
+ char e_scnum[2]; /* Section number */
+ char e_type[2]; /* Type of section */
+ char e_sclass[1]; /* Loader class */
+ char e_numaux[1]; /* Number of auxiliary entries which follow */
+};
+
+#define COFF_N_BTMASK (0xf) /* Mask for important class bits */
+#define COFF_N_TMASK (0x30) /* Mask for important type bits */
+#define COFF_N_BTSHFT (4) /* # bits to shift class field */
+#define COFF_N_TSHIFT (2) /* # bits to shift type field */
+
+/*
+ * Auxiliary entries because the main table is too limiting.
+ */
+
+union COFF_auxent {
+
+/*
+ * Debugger information
+ */
+
+ struct {
+ char x_tagndx[4]; /* str, un, or enum tag indx */
+ union {
+ struct {
+ char x_lnno[2]; /* declaration line number */
+ char x_size[2]; /* str/union/array size */
+ } x_lnsz;
+ char x_fsize[4]; /* size of function */
+ } x_misc;
+
+ union {
+ struct { /* if ISFCN, tag, or .bb */
+ char x_lnnoptr[4]; /* ptr to fcn line # */
+ char x_endndx[4]; /* entry ndx past block end */
+ } x_fcn;
+
+ struct { /* if ISARY, up to 4 dimen. */
+ char x_dimen[E_DIMNUM][2];
+ } x_ary;
+ } x_fcnary;
+
+ char x_tvndx[2]; /* tv index */
+ } x_sym;
+
+/*
+ * Source file names (debugger information)
+ */
+
+ union {
+ char x_fname[E_FILNMLEN];
+ struct {
+ char x_zeroes[4];
+ char x_offset[4];
+ } x_n;
+ } x_file;
+
+/*
+ * Section information
+ */
+
+ struct {
+ char x_scnlen[4]; /* section length */
+ char x_nreloc[2]; /* # relocation entries */
+ char x_nlinno[2]; /* # line numbers */
+ } x_scn;
+
+/*
+ * Transfer vector (branch table)
+ */
+
+ struct {
+ char x_tvfill[4]; /* tv fill value */
+ char x_tvlen[2]; /* length of .tv */
+ char x_tvran[2][2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+};
+
+#define COFF_SYMENT struct COFF_syment
+#define COFF_SYMESZ 18
+#define COFF_AUXENT union COFF_auxent
+#define COFF_AUXESZ 18
+
+#define COFF_ETEXT "etext"
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct COFF_reloc {
+ char r_vaddr[4]; /* Virtual address of item */
+ char r_symndx[4]; /* Symbol index in the symtab */
+ char r_type[2]; /* Relocation type */
+};
+
+#define COFF_RELOC struct COFF_reloc
+#define COFF_RELSZ 10
+
+#define COFF_DEF_DATA_SECTION_ALIGNMENT 4
+#define COFF_DEF_BSS_SECTION_ALIGNMENT 4
+#define COFF_DEF_TEXT_SECTION_ALIGNMENT 4
+
+/* For new sections we haven't heard of before */
+#define COFF_DEF_SECTION_ALIGNMENT 4
diff --git a/pfinet/linux-src/include/linux/comstats.h b/pfinet/linux-src/include/linux/comstats.h
new file mode 100644
index 00000000..06688859
--- /dev/null
+++ b/pfinet/linux-src/include/linux/comstats.h
@@ -0,0 +1,119 @@
+/*****************************************************************************/
+
+/*
+ * comstats.h -- Serial Port Stats.
+ *
+ * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*****************************************************************************/
+#ifndef _COMSTATS_H
+#define _COMSTATS_H
+/*****************************************************************************/
+
+/*
+ * Serial port stats structure. The structure itself is UART
+ * independent, but some fields may be UART/driver specific (for
+ * example state).
+ */
+
+typedef struct {
+ unsigned long brd;
+ unsigned long panel;
+ unsigned long port;
+ unsigned long hwid;
+ unsigned long type;
+ unsigned long txtotal;
+ unsigned long rxtotal;
+ unsigned long txbuffered;
+ unsigned long rxbuffered;
+ unsigned long rxoverrun;
+ unsigned long rxparity;
+ unsigned long rxframing;
+ unsigned long rxlost;
+ unsigned long txbreaks;
+ unsigned long rxbreaks;
+ unsigned long txxon;
+ unsigned long txxoff;
+ unsigned long rxxon;
+ unsigned long rxxoff;
+ unsigned long txctson;
+ unsigned long txctsoff;
+ unsigned long rxrtson;
+ unsigned long rxrtsoff;
+ unsigned long modem;
+ unsigned long state;
+ unsigned long flags;
+ unsigned long ttystate;
+ unsigned long cflags;
+ unsigned long iflags;
+ unsigned long oflags;
+ unsigned long lflags;
+ unsigned long signals;
+} comstats_t;
+
+
+/*
+ * Board stats structure. Returns useful info about the board.
+ */
+
+#define COM_MAXPANELS 8
+
+typedef struct {
+ unsigned long panel;
+ unsigned long type;
+ unsigned long hwid;
+ unsigned long nrports;
+} companel_t;
+
+typedef struct {
+ unsigned long brd;
+ unsigned long type;
+ unsigned long hwid;
+ unsigned long state;
+ unsigned long ioaddr;
+ unsigned long ioaddr2;
+ unsigned long memaddr;
+ unsigned long irq;
+ unsigned long nrpanels;
+ unsigned long nrports;
+ companel_t panels[COM_MAXPANELS];
+} combrd_t;
+
+
+/*
+ * Define the ioctl operations for stats stuff.
+ */
+#include <linux/ioctl.h>
+
+#define COM_GETPORTSTATS _IO('c',30)
+#define COM_CLRPORTSTATS _IO('c',31)
+#define COM_GETBRDSTATS _IO('c',32)
+
+
+/*
+ * Define the set of ioctls that give user level access to the
+ * private port, panel and board structures. The argument required
+ * will be driver dependent!
+ */
+#define COM_READPORT _IO('c',40)
+#define COM_READBOARD _IO('c',41)
+#define COM_READPANEL _IO('c',42)
+
+/*****************************************************************************/
+#endif
diff --git a/pfinet/linux-src/include/linux/concap.h b/pfinet/linux-src/include/linux/concap.h
new file mode 100644
index 00000000..b8e72dc6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/concap.h
@@ -0,0 +1,109 @@
+/* $Id: concap.h,v 1.2 1999/08/23 15:54:21 keil Exp $
+*/
+#ifndef _LINUX_CONCAP_H
+#define _LINUX_CONCAP_H
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+/* Stuff to support encapsulation protocols genericly. The encapsulation
+ protocol is processed at the uppermost layer of the network interface.
+
+ (c) 1997 by Henner Eisen <eis@baty.hanse.de>
+ This software is subject to the GNU General Public License.
+
+ Based on a ideas developed in a 'synchronous device' thread in the
+ linux-x25 mailing list contributed by Alan Cox, Thomasz Motylewski
+ and Jonathan Naylor.
+
+ For more documetation on this refer to Documentation/isdn/README.concap
+ */
+
+struct concap_proto_ops;
+struct concap_device_ops;
+
+/* this manages all data needed by the encapsulation protocol
+ */
+struct concap_proto{
+ struct device *net_dev; /* net device using our service */
+ struct concap_device_ops *dops; /* callbacks provided by device */
+ struct concap_proto_ops *pops; /* callbacks provided by us */
+ int flags;
+ void *proto_data; /* protocol specific private data, to
+ be accessed via *pops methods only*/
+ /*
+ :
+ whatever
+ :
+ */
+};
+
+/* Operations to be supported by the net device. Called by the encapsulation
+ * protocol entity. No receive method is offered because the encapsulation
+ * protocol directly calls netif_rx().
+ */
+struct concap_device_ops{
+
+ /* to request data is submitted by device*/
+ int (*data_req)(struct concap_proto *, struct sk_buff *);
+
+ /* Control methods must be set to NULL by devices which do not
+ support connection control.*/
+ /* to request a connection is set up */
+ int (*connect_req)(struct concap_proto *);
+
+ /* to request a connection is released */
+ int (*disconn_req)(struct concap_proto *);
+};
+
+/* Operations to be supported by the encapsulation protocol. Called by
+ * device driver.
+ */
+struct concap_proto_ops{
+
+ /* create a new encapsulation protocol instance of same type */
+ struct concap_proto * (*proto_new) (void);
+
+ /* delete encapsulation protocol instance and free all its resources.
+ cprot may no loger be referenced after calling this */
+ void (*proto_del)(struct concap_proto *cprot);
+
+ /* initialize the protocol's data. To be called at interface startup
+ or when the device driver resets the interface. All services of the
+ encapsulation protocol may be used after this*/
+ int (*restart)(struct concap_proto *cprot,
+ struct device *ndev,
+ struct concap_device_ops *dops);
+
+ /* inactivate an encapsulation protocol instance. The encapsulation
+ protocol may not call any *dops methods after this. */
+ int (*close)(struct concap_proto *cprot);
+
+ /* process a frame handed down to us by upper layer */
+ int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
+
+ /* to be called for each data entity received from lower layer*/
+ int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb);
+
+ /* to be called when a connection was set up/down.
+ Protocols that don't process these primitives might fill in
+ dummy methods here */
+ int (*connect_ind)(struct concap_proto *cprot);
+ int (*disconn_ind)(struct concap_proto *cprot);
+ /*
+ Some network device support functions, like net_header(), rebuild_header(),
+ and others, that depend solely on the encapsulation protocol, might
+ be provided here, too. The net device would just fill them in its
+ corresponding fields when it is opened.
+ */
+};
+
+/* dummy restart/close/connect/reset/disconn methods
+ */
+extern int concap_nop(struct concap_proto *cprot);
+
+/* dummy submit method
+ */
+extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb);
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/config.h b/pfinet/linux-src/include/linux/config.h
new file mode 100644
index 00000000..9d1c14f7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/config.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_CONFIG_H
+#define _LINUX_CONFIG_H
+
+#include <linux/autoconf.h>
+
+#endif
diff --git a/pfinet/linux-src/include/linux/console.h b/pfinet/linux-src/include/linux/console.h
new file mode 100644
index 00000000..efb0003e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/console.h
@@ -0,0 +1,115 @@
+/*
+ * linux/include/linux/console.h
+ *
+ * Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Changed:
+ * 10-Mar-94: Arno Griffioen: Conversion for vt100 emulator port from PC LINUX
+ */
+
+#ifndef _LINUX_CONSOLE_H_
+#define _LINUX_CONSOLE_H_ 1
+
+struct vc_data;
+struct console_font_op;
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c query.
+ */
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
+
+struct consw {
+ const char *(*con_startup)(void);
+ void (*con_init)(struct vc_data *, int);
+ void (*con_deinit)(struct vc_data *);
+ void (*con_clear)(struct vc_data *, int, int, int, int);
+ void (*con_putc)(struct vc_data *, int, int, int);
+ void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int);
+ void (*con_cursor)(struct vc_data *, int);
+ int (*con_scroll)(struct vc_data *, int, int, int, int);
+ void (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
+ int (*con_switch)(struct vc_data *);
+ int (*con_blank)(struct vc_data *, int);
+ int (*con_font_op)(struct vc_data *, struct console_font_op *);
+ int (*con_set_palette)(struct vc_data *, unsigned char *);
+ int (*con_scrolldelta)(struct vc_data *, int);
+ int (*con_set_origin)(struct vc_data *);
+ void (*con_save_screen)(struct vc_data *);
+ u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8);
+ void (*con_invert_region)(struct vc_data *, u16 *, int);
+ u16 *(*con_screen_pos)(struct vc_data *, int);
+ unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
+};
+
+extern struct consw *conswitchp;
+
+extern struct consw dummy_con; /* dummy console buffer */
+extern struct consw fb_con; /* frame buffer based console */
+extern struct consw vga_con; /* VGA text console */
+extern struct consw newport_con; /* SGI Newport console */
+extern struct consw prom_con; /* SPARC PROM console */
+
+void take_over_console(struct consw *sw, int first, int last, int deflt);
+void give_up_console(struct consw *sw);
+
+/* scroll */
+#define SM_UP (1)
+#define SM_DOWN (2)
+
+/* cursor */
+#define CM_DRAW (1)
+#define CM_ERASE (2)
+#define CM_MOVE (3)
+
+/*
+ * Array of consoles built from command line options (console=)
+ */
+struct console_cmdline
+{
+ char name[8]; /* Name of the driver */
+ int index; /* Minor dev. to use */
+ char *options; /* Options for the driver */
+};
+#define MAX_CMDLINECONSOLES 8
+extern struct console_cmdline console_list[MAX_CMDLINECONSOLES];
+
+/*
+ * The interface for a console, or any other device that
+ * wants to capture console messages (printer driver?)
+ */
+
+#define CON_PRINTBUFFER (1)
+#define CON_CONSDEV (2) /* Last on the command line */
+#define CON_ENABLED (4)
+
+struct console
+{
+ char name[8];
+ void (*write)(struct console *, const char *, unsigned);
+ int (*read)(struct console *, const char *, unsigned);
+ kdev_t (*device)(struct console *);
+ int (*wait_key)(struct console *);
+ void (*unblank)(void);
+ int (*setup)(struct console *, char *);
+ short flags;
+ short index;
+ int cflag;
+ struct console *next;
+};
+
+extern void register_console(struct console *);
+extern int unregister_console(struct console *);
+extern struct console *console_drivers;
+
+/* VESA Blanking Levels */
+#define VESA_NO_BLANKING 0
+#define VESA_VSYNC_SUSPEND 1
+#define VESA_HSYNC_SUSPEND 2
+#define VESA_POWERDOWN 3
+
+#endif /* _LINUX_CONSOLE_H */
diff --git a/pfinet/linux-src/include/linux/console_struct.h b/pfinet/linux-src/include/linux/console_struct.h
new file mode 100644
index 00000000..0f664086
--- /dev/null
+++ b/pfinet/linux-src/include/linux/console_struct.h
@@ -0,0 +1,109 @@
+/*
+ * console_struct.h
+ *
+ * Data structure describing single virtual console except for data
+ * used by vt.c.
+ *
+ * Fields marked with [#] must be set by the low-level driver.
+ * Fields marked with [!] can be changed by the low-level driver
+ * to achieve effects such as fast scrolling by changing the origin.
+ */
+
+#define NPAR 16
+
+struct vc_data {
+ unsigned short vc_num; /* Console number */
+ unsigned int vc_cols; /* [#] Console size */
+ unsigned int vc_rows;
+ unsigned int vc_size_row; /* Bytes per row */
+ struct consw *vc_sw;
+ unsigned short *vc_screenbuf; /* In-memory character/attribute buffer */
+ unsigned int vc_screenbuf_size;
+ unsigned char vc_attr; /* Current attributes */
+ unsigned char vc_def_color; /* Default colors */
+ unsigned char vc_color; /* Foreground & background */
+ unsigned char vc_s_color; /* Saved foreground & background */
+ unsigned char vc_ulcolor; /* Color for underline mode */
+ unsigned char vc_halfcolor; /* Color for half intensity mode */
+ unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */
+ unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
+ unsigned short vc_video_erase_char; /* Background erase character */
+ unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */
+ unsigned int vc_x, vc_y; /* Cursor position */
+ unsigned int vc_top, vc_bottom; /* Scrolling region */
+ unsigned int vc_state; /* Escape sequence parser state */
+ unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */
+ unsigned long vc_origin; /* [!] Start of real screen */
+ unsigned long vc_scr_end; /* [!] End of real screen */
+ unsigned long vc_visible_origin; /* [!] Top of visible window */
+ unsigned long vc_pos; /* Cursor address */
+ unsigned int vc_saved_x;
+ unsigned int vc_saved_y;
+ /* mode flags */
+ unsigned int vc_charset : 1; /* Character set G0 / G1 */
+ unsigned int vc_s_charset : 1; /* Saved character set */
+ unsigned int vc_disp_ctrl : 1; /* Display chars < 32? */
+ unsigned int vc_toggle_meta : 1; /* Toggle high bit? */
+ unsigned int vc_decscnm : 1; /* Screen Mode */
+ unsigned int vc_decom : 1; /* Origin Mode */
+ unsigned int vc_decawm : 1; /* Autowrap Mode */
+ unsigned int vc_deccm : 1; /* Cursor Visible */
+ unsigned int vc_decim : 1; /* Insert Mode */
+ unsigned int vc_deccolm : 1; /* 80/132 Column Mode */
+ /* attribute flags */
+ unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */
+ unsigned int vc_underline : 1;
+ unsigned int vc_blink : 1;
+ unsigned int vc_reverse : 1;
+ unsigned int vc_s_intensity : 2; /* saved rendition */
+ unsigned int vc_s_underline : 1;
+ unsigned int vc_s_blink : 1;
+ unsigned int vc_s_reverse : 1;
+ /* misc */
+ unsigned int vc_ques : 1;
+ unsigned int vc_need_wrap : 1;
+ unsigned int vc_can_do_color : 1;
+ unsigned int vc_report_mouse : 2;
+ unsigned int vc_kmalloced : 1;
+ unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */
+ unsigned char vc_utf_count;
+ int vc_utf_char;
+ unsigned int vc_tab_stop[5]; /* Tab stops. 160 columns. */
+ unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */
+ unsigned short * vc_translate;
+ unsigned char vc_G0_charset;
+ unsigned char vc_G1_charset;
+ unsigned char vc_saved_G0;
+ unsigned char vc_saved_G1;
+ unsigned int vc_bell_pitch; /* Console bell pitch */
+ unsigned int vc_bell_duration; /* Console bell duration */
+ unsigned int vc_cursor_type;
+ struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
+ unsigned long vc_uni_pagedir;
+ unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
+ /* additional information is in vt_kern.h */
+};
+
+struct vc {
+ struct vc_data *d;
+
+ /* might add scrmem, vt_struct, kbd at some time,
+ to have everything in one place - the disadvantage
+ would be that vc_cons etc can no longer be static */
+};
+
+extern struct vc vc_cons [MAX_NR_CONSOLES];
+
+#define CUR_DEF 0
+#define CUR_NONE 1
+#define CUR_UNDERLINE 2
+#define CUR_LOWER_THIRD 3
+#define CUR_LOWER_HALF 4
+#define CUR_TWO_THIRDS 5
+#define CUR_BLOCK 6
+#define CUR_HWMASK 0x0f
+#define CUR_SWMASK 0xfff0
+
+#define CUR_DEFAULT CUR_UNDERLINE
+
+#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp)
diff --git a/pfinet/linux-src/include/linux/consolemap.h b/pfinet/linux-src/include/linux/consolemap.h
new file mode 100644
index 00000000..dee4b654
--- /dev/null
+++ b/pfinet/linux-src/include/linux/consolemap.h
@@ -0,0 +1,15 @@
+/*
+ * consolemap.h
+ *
+ * Interface between console.c, selection.c and consolemap.c
+ */
+#define LAT1_MAP 0
+#define GRAF_MAP 1
+#define IBMPC_MAP 2
+#define USER_MAP 3
+
+struct vc_data;
+
+extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
+extern unsigned short *set_translate(int m,int currcons);
+extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
diff --git a/pfinet/linux-src/include/linux/ctype.h b/pfinet/linux-src/include/linux/ctype.h
new file mode 100644
index 00000000..afa36392
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ctype.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_CTYPE_H
+#define _LINUX_CTYPE_H
+
+/*
+ * NOTE! This ctype does not handle EOF like the standard C
+ * library is required to.
+ */
+
+#define _U 0x01 /* upper */
+#define _L 0x02 /* lower */
+#define _D 0x04 /* digit */
+#define _C 0x08 /* cntrl */
+#define _P 0x10 /* punct */
+#define _S 0x20 /* white space (space/lf/tab) */
+#define _X 0x40 /* hex digit */
+#define _SP 0x80 /* hard space (0x20) */
+
+extern unsigned char _ctype[];
+
+#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
+
+#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
+#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
+#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
+#define isdigit(c) ((__ismask(c)&(_D)) != 0)
+#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
+#define islower(c) ((__ismask(c)&(_L)) != 0)
+#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
+#define ispunct(c) ((__ismask(c)&(_P)) != 0)
+#define isspace(c) ((__ismask(c)&(_S)) != 0)
+#define isupper(c) ((__ismask(c)&(_U)) != 0)
+#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
+
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+#define toascii(c) (((unsigned char)(c))&0x7f)
+
+static inline unsigned char __tolower(unsigned char c)
+{
+ if (isupper(c))
+ c -= 'A'-'a';
+ return c;
+}
+
+static inline unsigned char __toupper(unsigned char c)
+{
+ if (islower(c))
+ c -= 'a'-'A';
+ return c;
+}
+
+#define tolower(c) __tolower(c)
+#define toupper(c) __toupper(c)
+
+#endif
diff --git a/pfinet/linux-src/include/linux/cyclades.h b/pfinet/linux-src/include/linux/cyclades.h
new file mode 100644
index 00000000..4e8333c1
--- /dev/null
+++ b/pfinet/linux-src/include/linux/cyclades.h
@@ -0,0 +1,814 @@
+/* $Revision: 2.6 $$Date: 1998/08/10 16:57:01 $
+ * linux/include/linux/cyclades.h
+ *
+ * This file was initially written by
+ * Randolph Bentson <bentson@grieg.seaslug.org> and is maintained by
+ * Ivan Passos <ivan@cyclades.com>.
+ *
+ * This file contains the general definitions for the cyclades.c driver
+ *$Log: cyclades.h,v $
+ *Revision 2.5 1998/08/03 16:57:01 ivan
+ *added cyclades_idle_stats structure;
+ *
+ *Revision 2.4 1998/06/01 12:09:53 ivan
+ *removed closing_wait2 from cyclades_port structure;
+ *
+ *Revision 2.3 1998/03/16 18:01:12 ivan
+ *changes in the cyclades_port structure to get it closer to the
+ *standard serial port structure;
+ *added constants for new ioctls;
+ *
+ *Revision 2.2 1998/02/17 16:50:00 ivan
+ *changes in the cyclades_port structure (addition of shutdown_wait and
+ *chip_rev variables);
+ *added constants for new ioctls and for CD1400 rev. numbers.
+ *
+ *Revision 2.1 1997/10/24 16:03:00 ivan
+ *added rflow (which allows enabling the CD1400 special flow control
+ *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to
+ *cyclades_port structure;
+ *added Alpha support
+ *
+ *Revision 2.0 1997/06/30 10:30:00 ivan
+ *added some new doorbell command constants related to IOCTLW and
+ *UART error signaling
+ *
+ *Revision 1.8 1997/06/03 15:30:00 ivan
+ *added constant ZFIRM_HLT
+ *added constant CyPCI_Ze_win ( = 2 * Cy_PCI_Zwin)
+ *
+ *Revision 1.7 1997/03/26 10:30:00 daniel
+ *new entries at the end of cyclades_port struct to reallocate
+ *variables illegally allocated within card memory.
+ *
+ *Revision 1.6 1996/09/09 18:35:30 bentson
+ *fold in changes for Cyclom-Z -- including structures for
+ *communicating with board as well modest changes to original
+ *structures to support new features.
+ *
+ *Revision 1.5 1995/11/13 21:13:31 bentson
+ *changes suggested by Michael Chastain <mec@duracef.shout.net>
+ *to support use of this file in non-kernel applications
+ *
+ *
+ */
+
+#ifndef _LINUX_CYCLADES_H
+#define _LINUX_CYCLADES_H
+
+struct cyclades_monitor {
+ unsigned long int_count;
+ unsigned long char_count;
+ unsigned long char_max;
+ unsigned long char_last;
+};
+
+/*
+ * These stats all reflect activity since the device was last initialized.
+ * (i.e., since the port was opened with no other processes already having it
+ * open)
+ */
+struct cyclades_idle_stats {
+ time_t in_use; /* Time device has been in use (secs) */
+ time_t recv_idle; /* Time since last char received (secs) */
+ time_t xmit_idle; /* Time since last char transmitted (secs) */
+ unsigned long recv_bytes; /* Bytes received */
+ unsigned long xmit_bytes; /* Bytes transmitted */
+ unsigned long overruns; /* Input overruns */
+ unsigned long frame_errs; /* Input framing errors */
+ unsigned long parity_errs; /* Input parity errors */
+};
+
+#define CYCLADES_MAGIC 0x4359
+
+#define CYGETMON 0x435901
+#define CYGETTHRESH 0x435902
+#define CYSETTHRESH 0x435903
+#define CYGETDEFTHRESH 0x435904
+#define CYSETDEFTHRESH 0x435905
+#define CYGETTIMEOUT 0x435906
+#define CYSETTIMEOUT 0x435907
+#define CYGETDEFTIMEOUT 0x435908
+#define CYSETDEFTIMEOUT 0x435909
+#define CYSETRFLOW 0x43590a
+#define CYGETRFLOW 0x43590b
+#define CYSETRTSDTR_INV 0x43590c
+#define CYGETRTSDTR_INV 0x43590d
+#define CYZSETPOLLCYCLE 0x43590e
+#define CYZGETPOLLCYCLE 0x43590f
+#define CYGETCD1400VER 0x435910
+#define CYGETCARDINFO 0x435911
+#define CYSETWAIT 0x435912
+#define CYGETWAIT 0x435913
+
+/*************** CYCLOM-Z ADDITIONS ***************/
+
+#define CZIOC ('M' << 8)
+#define CZ_NBOARDS (CZIOC|0xfa)
+#define CZ_BOOT_START (CZIOC|0xfb)
+#define CZ_BOOT_DATA (CZIOC|0xfc)
+#define CZ_BOOT_END (CZIOC|0xfd)
+#define CZ_TEST (CZIOC|0xfe)
+
+#define CZ_DEF_POLL (HZ/25)
+
+#define MAX_BOARD 4 /* Max number of boards */
+#define MAX_DEV 256 /* Max number of ports total */
+#define CYZ_MAX_SPEED 921600
+
+#define CYZ_FIFO_SIZE 16
+
+#define CYZ_BOOT_NWORDS 0x100
+struct CYZ_BOOT_CTRL {
+ unsigned short nboard;
+ int status[MAX_BOARD];
+ int nchannel[MAX_BOARD];
+ int fw_rev[MAX_BOARD];
+ unsigned long offset;
+ unsigned long data[CYZ_BOOT_NWORDS];
+};
+
+
+#ifndef DP_WINDOW_SIZE
+/* #include "cyclomz.h" */
+/****************** ****************** *******************/
+/*
+ * The data types defined below are used in all ZFIRM interface
+ * data structures. They accommodate differences between HW
+ * architectures and compilers.
+ */
+
+#if defined(__alpha__)
+typedef unsigned long ucdouble; /* 64 bits, unsigned */
+typedef unsigned int uclong; /* 32 bits, unsigned */
+#else
+typedef unsigned long uclong; /* 32 bits, unsigned */
+#endif
+typedef unsigned short ucshort; /* 16 bits, unsigned */
+typedef unsigned char ucchar; /* 8 bits, unsigned */
+
+/*
+ * Memory Window Sizes
+ */
+
+#define DP_WINDOW_SIZE (0x00080000) /* window size 512 Kb */
+#define ZE_DP_WINDOW_SIZE (0x00100000) /* window size 1 Mb (Ze and
+ 8Zo V.2 */
+#define CTRL_WINDOW_SIZE (0x00000080) /* runtime regs 128 bytes */
+
+/*
+ * CUSTOM_REG - Cyclom-Z/PCI Custom Registers Set. The driver
+ * normally will access only interested on the fpga_id, fpga_version,
+ * start_cpu and stop_cpu.
+ */
+
+struct CUSTOM_REG {
+ uclong fpga_id; /* FPGA Identification Register */
+ uclong fpga_version; /* FPGA Version Number Register */
+ uclong cpu_start; /* CPU start Register (write) */
+ uclong cpu_stop; /* CPU stop Register (write) */
+ uclong misc_reg; /* Miscellaneous Register */
+ uclong idt_mode; /* IDT mode Register */
+ uclong uart_irq_status; /* UART IRQ status Register */
+ uclong clear_timer0_irq; /* Clear timer interrupt Register */
+ uclong clear_timer1_irq; /* Clear timer interrupt Register */
+ uclong clear_timer2_irq; /* Clear timer interrupt Register */
+ uclong test_register; /* Test Register */
+ uclong test_count; /* Test Count Register */
+ uclong timer_select; /* Timer select register */
+ uclong pr_uart_irq_status; /* Prioritized UART IRQ stat Reg */
+ uclong ram_wait_state; /* RAM wait-state Register */
+ uclong uart_wait_state; /* UART wait-state Register */
+ uclong timer_wait_state; /* timer wait-state Register */
+ uclong ack_wait_state; /* ACK wait State Register */
+};
+
+/*
+ * RUNTIME_9060 - PLX PCI9060ES local configuration and shared runtime
+ * registers. This structure can be used to access the 9060 registers
+ * (memory mapped).
+ */
+
+struct RUNTIME_9060 {
+ uclong loc_addr_range; /* 00h - Local Address Range */
+ uclong loc_addr_base; /* 04h - Local Address Base */
+ uclong loc_arbitr; /* 08h - Local Arbitration */
+ uclong endian_descr; /* 0Ch - Big/Little Endian Descriptor */
+ uclong loc_rom_range; /* 10h - Local ROM Range */
+ uclong loc_rom_base; /* 14h - Local ROM Base */
+ uclong loc_bus_descr; /* 18h - Local Bus descriptor */
+ uclong loc_range_mst; /* 1Ch - Local Range for Master to PCI */
+ uclong loc_base_mst; /* 20h - Local Base for Master PCI */
+ uclong loc_range_io; /* 24h - Local Range for Master IO */
+ uclong pci_base_mst; /* 28h - PCI Base for Master PCI */
+ uclong pci_conf_io; /* 2Ch - PCI configuration for Master IO */
+ uclong filler1; /* 30h */
+ uclong filler2; /* 34h */
+ uclong filler3; /* 38h */
+ uclong filler4; /* 3Ch */
+ uclong mail_box_0; /* 40h - Mail Box 0 */
+ uclong mail_box_1; /* 44h - Mail Box 1 */
+ uclong mail_box_2; /* 48h - Mail Box 2 */
+ uclong mail_box_3; /* 4Ch - Mail Box 3 */
+ uclong filler5; /* 50h */
+ uclong filler6; /* 54h */
+ uclong filler7; /* 58h */
+ uclong filler8; /* 5Ch */
+ uclong pci_doorbell; /* 60h - PCI to Local Doorbell */
+ uclong loc_doorbell; /* 64h - Local to PCI Doorbell */
+ uclong intr_ctrl_stat; /* 68h - Interrupt Control/Status */
+ uclong init_ctrl; /* 6Ch - EEPROM control, Init Control, etc */
+};
+
+/* Values for the Local Base Address re-map register */
+
+#define WIN_RAM 0x00000001L /* set the sliding window to RAM */
+#define WIN_CREG 0x14000001L /* set the window to custom Registers */
+
+/* Values timer select registers */
+
+#define TIMER_BY_1M 0x00 /* clock divided by 1M */
+#define TIMER_BY_256K 0x01 /* clock divided by 256k */
+#define TIMER_BY_128K 0x02 /* clock divided by 128k */
+#define TIMER_BY_32K 0x03 /* clock divided by 32k */
+
+/****************** ****************** *******************/
+#endif
+
+#ifndef ZFIRM_ID
+/* #include "zfwint.h" */
+/****************** ****************** *******************/
+/*
+ * This file contains the definitions for interfacing with the
+ * Cyclom-Z ZFIRM Firmware.
+ */
+
+/* General Constant definitions */
+
+#define MAX_CHAN 64 /* max number of channels per board */
+
+/* firmware id structure (set after boot) */
+
+#define ID_ADDRESS 0x00000180L /* signature/pointer address */
+#define ZFIRM_ID 0x5557465AL /* ZFIRM/U signature */
+#define ZFIRM_HLT 0x59505B5CL /* ZFIRM needs external power supply */
+#define ZFIRM_RST 0x56040674L /* RST signal (due to FW reset) */
+
+#define ZF_TINACT_DEF 1000 /* default inactivity timeout
+ (1000 ms) */
+#define ZF_TINACT ZF_TINACT_DEF
+
+struct FIRM_ID {
+ uclong signature; /* ZFIRM/U signature */
+ uclong zfwctrl_addr; /* pointer to ZFW_CTRL structure */
+};
+
+/* Op. System id */
+
+#define C_OS_LINUX 0x00000030 /* generic Linux system */
+
+/* channel op_mode */
+
+#define C_CH_DISABLE 0x00000000 /* channel is disabled */
+#define C_CH_TXENABLE 0x00000001 /* channel Tx enabled */
+#define C_CH_RXENABLE 0x00000002 /* channel Rx enabled */
+#define C_CH_ENABLE 0x00000003 /* channel Tx/Rx enabled */
+#define C_CH_LOOPBACK 0x00000004 /* Loopback mode */
+
+/* comm_parity - parity */
+
+#define C_PR_NONE 0x00000000 /* None */
+#define C_PR_ODD 0x00000001 /* Odd */
+#define C_PR_EVEN 0x00000002 /* Even */
+#define C_PR_MARK 0x00000004 /* Mark */
+#define C_PR_SPACE 0x00000008 /* Space */
+#define C_PR_PARITY 0x000000ff
+
+#define C_PR_DISCARD 0x00000100 /* discard char with frame/par error */
+#define C_PR_IGNORE 0x00000200 /* ignore frame/par error */
+
+/* comm_data_l - data length and stop bits */
+
+#define C_DL_CS5 0x00000001
+#define C_DL_CS6 0x00000002
+#define C_DL_CS7 0x00000004
+#define C_DL_CS8 0x00000008
+#define C_DL_CS 0x0000000f
+#define C_DL_1STOP 0x00000010
+#define C_DL_15STOP 0x00000020
+#define C_DL_2STOP 0x00000040
+#define C_DL_STOP 0x000000f0
+
+/* interrupt enabling/status */
+
+#define C_IN_DISABLE 0x00000000 /* zero, disable interrupts */
+#define C_IN_TXBEMPTY 0x00000001 /* tx buffer empty */
+#define C_IN_TXLOWWM 0x00000002 /* tx buffer below LWM */
+#define C_IN_RXHIWM 0x00000010 /* rx buffer above HWM */
+#define C_IN_RXNNDT 0x00000020 /* rx no new data timeout */
+#define C_IN_MDCD 0x00000100 /* modem DCD change */
+#define C_IN_MDSR 0x00000200 /* modem DSR change */
+#define C_IN_MRI 0x00000400 /* modem RI change */
+#define C_IN_MCTS 0x00000800 /* modem CTS change */
+#define C_IN_RXBRK 0x00001000 /* Break received */
+#define C_IN_PR_ERROR 0x00002000 /* parity error */
+#define C_IN_FR_ERROR 0x00004000 /* frame error */
+#define C_IN_OVR_ERROR 0x00008000 /* overrun error */
+#define C_IN_RXOFL 0x00010000 /* RX buffer overflow */
+#define C_IN_IOCTLW 0x00020000 /* I/O control w/ wait */
+#define C_IN_MRTS 0x00040000 /* modem RTS drop */
+#define C_IN_ICHAR 0x00080000
+
+/* flow control */
+
+#define C_FL_OXX 0x00000001 /* output Xon/Xoff flow control */
+#define C_FL_IXX 0x00000002 /* output Xon/Xoff flow control */
+#define C_FL_OIXANY 0x00000004 /* output Xon/Xoff (any xon) */
+#define C_FL_SWFLOW 0x0000000f
+
+/* flow status */
+
+#define C_FS_TXIDLE 0x00000000 /* no Tx data in the buffer or UART */
+#define C_FS_SENDING 0x00000001 /* UART is sending data */
+#define C_FS_SWFLOW 0x00000002 /* Tx is stopped by received Xoff */
+
+/* rs_control/rs_status RS-232 signals */
+
+#define C_RS_PARAM 0x80000000 /* Indicates presence of parameter in
+ IOCTLM command */
+#define C_RS_RTS 0x00000001 /* RTS */
+#define C_RS_DTR 0x00000004 /* DTR */
+#define C_RS_DCD 0x00000100 /* CD */
+#define C_RS_DSR 0x00000200 /* DSR */
+#define C_RS_RI 0x00000400 /* RI */
+#define C_RS_CTS 0x00000800 /* CTS */
+
+/* commands Host <-> Board */
+
+#define C_CM_RESET 0x01 /* reset/flush buffers */
+#define C_CM_IOCTL 0x02 /* re-read CH_CTRL */
+#define C_CM_IOCTLW 0x03 /* re-read CH_CTRL, intr when done */
+#define C_CM_IOCTLM 0x04 /* RS-232 outputs change */
+#define C_CM_SENDXOFF 0x10 /* send Xoff */
+#define C_CM_SENDXON 0x11 /* send Xon */
+#define C_CM_CLFLOW 0x12 /* Clear flow control (resume) */
+#define C_CM_SENDBRK 0x41 /* send break */
+#define C_CM_INTBACK 0x42 /* Interrupt back */
+#define C_CM_SET_BREAK 0x43 /* Tx break on */
+#define C_CM_CLR_BREAK 0x44 /* Tx break off */
+#define C_CM_CMD_DONE 0x45 /* Previous command done */
+#define C_CM_INTBACK2 0x46 /* Alternate Interrupt back */
+#define C_CM_TINACT 0x51 /* set inactivity detection */
+#define C_CM_IRQ_ENBL 0x52 /* enable generation of interrupts */
+#define C_CM_IRQ_DSBL 0x53 /* disable generation of interrupts */
+#define C_CM_ACK_ENBL 0x54 /* enable acknowledged interrupt mode */
+#define C_CM_ACK_DSBL 0x55 /* disable acknowledged intr mode */
+#define C_CM_FLUSH_RX 0x56 /* flushes Rx buffer */
+#define C_CM_FLUSH_TX 0x57 /* flushes Tx buffer */
+#define C_CM_Q_ENABLE 0x58 /* enables queue access from the
+ driver */
+#define C_CM_Q_DISABLE 0x59 /* disables queue access from the
+ driver */
+
+#define C_CM_TXBEMPTY 0x60 /* Tx buffer is empty */
+#define C_CM_TXLOWWM 0x61 /* Tx buffer low water mark */
+#define C_CM_RXHIWM 0x62 /* Rx buffer high water mark */
+#define C_CM_RXNNDT 0x63 /* rx no new data timeout */
+#define C_CM_TXFEMPTY 0x64
+#define C_CM_ICHAR 0x65
+#define C_CM_MDCD 0x70 /* modem DCD change */
+#define C_CM_MDSR 0x71 /* modem DSR change */
+#define C_CM_MRI 0x72 /* modem RI change */
+#define C_CM_MCTS 0x73 /* modem CTS change */
+#define C_CM_MRTS 0x74 /* modem RTS drop */
+#define C_CM_RXBRK 0x84 /* Break received */
+#define C_CM_PR_ERROR 0x85 /* Parity error */
+#define C_CM_FR_ERROR 0x86 /* Frame error */
+#define C_CM_OVR_ERROR 0x87 /* Overrun error */
+#define C_CM_RXOFL 0x88 /* RX buffer overflow */
+#define C_CM_CMDERROR 0x90 /* command error */
+#define C_CM_FATAL 0x91 /* fatal error */
+#define C_CM_HW_RESET 0x92 /* reset board */
+
+/*
+ * CH_CTRL - This per port structure contains all parameters
+ * that control an specific port. It can be seen as the
+ * configuration registers of a "super-serial-controller".
+ */
+
+struct CH_CTRL {
+ uclong op_mode; /* operation mode */
+ uclong intr_enable; /* interrupt masking */
+ uclong sw_flow; /* SW flow control */
+ uclong flow_status; /* output flow status */
+ uclong comm_baud; /* baud rate - numerically specified */
+ uclong comm_parity; /* parity */
+ uclong comm_data_l; /* data length/stop */
+ uclong comm_flags; /* other flags */
+ uclong hw_flow; /* HW flow control */
+ uclong rs_control; /* RS-232 outputs */
+ uclong rs_status; /* RS-232 inputs */
+ uclong flow_xon; /* xon char */
+ uclong flow_xoff; /* xoff char */
+ uclong hw_overflow; /* hw overflow counter */
+ uclong sw_overflow; /* sw overflow counter */
+ uclong comm_error; /* frame/parity error counter */
+ uclong ichar;
+ uclong filler[7];
+};
+
+
+/*
+ * BUF_CTRL - This per channel structure contains
+ * all Tx and Rx buffer control for a given channel.
+ */
+
+struct BUF_CTRL {
+ uclong flag_dma; /* buffers are in Host memory */
+ uclong tx_bufaddr; /* address of the tx buffer */
+ uclong tx_bufsize; /* tx buffer size */
+ uclong tx_threshold; /* tx low water mark */
+ uclong tx_get; /* tail index tx buf */
+ uclong tx_put; /* head index tx buf */
+ uclong rx_bufaddr; /* address of the rx buffer */
+ uclong rx_bufsize; /* rx buffer size */
+ uclong rx_threshold; /* rx high water mark */
+ uclong rx_get; /* tail index rx buf */
+ uclong rx_put; /* head index rx buf */
+ uclong filler[5]; /* filler to align structures */
+};
+
+/*
+ * BOARD_CTRL - This per board structure contains all global
+ * control fields related to the board.
+ */
+
+struct BOARD_CTRL {
+
+ /* static info provided by the on-board CPU */
+ uclong n_channel; /* number of channels */
+ uclong fw_version; /* firmware version */
+
+ /* static info provided by the driver */
+ uclong op_system; /* op_system id */
+ uclong dr_version; /* driver version */
+
+ /* board control area */
+ uclong inactivity; /* inactivity control */
+
+ /* host to FW commands */
+ uclong hcmd_channel; /* channel number */
+ uclong hcmd_param; /* pointer to parameters */
+
+ /* FW to Host commands */
+ uclong fwcmd_channel; /* channel number */
+ uclong fwcmd_param; /* pointer to parameters */
+ uclong zf_int_queue_addr; /* offset for INT_QUEUE structure */
+
+ /* filler so the structures are aligned */
+ uclong filler[6];
+};
+
+/* Host Interrupt Queue */
+
+#define QUEUE_SIZE (10*MAX_CHAN)
+
+struct INT_QUEUE {
+ unsigned char intr_code[QUEUE_SIZE];
+ unsigned long channel[QUEUE_SIZE];
+ unsigned long param[QUEUE_SIZE];
+ unsigned long put;
+ unsigned long get;
+};
+
+/*
+ * ZFW_CTRL - This is the data structure that includes all other
+ * data structures used by the Firmware.
+ */
+
+struct ZFW_CTRL {
+ struct BOARD_CTRL board_ctrl;
+ struct CH_CTRL ch_ctrl[MAX_CHAN];
+ struct BUF_CTRL buf_ctrl[MAX_CHAN];
+};
+
+/****************** ****************** *******************/
+#endif
+
+/* Per card data structure */
+struct cyclades_card {
+ long base_addr;
+ long ctl_addr;
+ int irq;
+ int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */
+ int first_line; /* minor number of first channel on card */
+ int bus_index; /* address shift - 0 for ISA, 1 for PCI */
+ int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */
+#ifdef __KERNEL__
+ spinlock_t card_lock;
+#else
+ uclong filler;
+#endif
+};
+
+struct cyclades_chip {
+ int filler;
+};
+
+
+#ifdef __KERNEL__
+
+/***************************************
+ * Memory access functions/macros *
+ * (required to support Alpha systems) *
+ ***************************************/
+
+#define cy_writeb(port,val) {writeb((ucchar)(val),(ulong)(port)); mb();}
+#define cy_writew(port,val) {writew((ushort)(val),(ulong)(port)); mb();}
+#define cy_writel(port,val) {writel((uclong)(val),(ulong)(port)); mb();}
+
+#define cy_readb(port) readb(port)
+#define cy_readw(port) readw(port)
+#define cy_readl(port) readl(port)
+
+/*
+ * Statistics counters
+ */
+struct cyclades_icount {
+ __u32 cts, dsr, rng, dcd, tx, rx;
+ __u32 frame, parity, overrun, brk;
+ __u32 buf_overrun;
+};
+
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct cyclades_port {
+ int magic;
+ int card;
+ int line;
+ int flags; /* defined in tty.h */
+ int type; /* UART type */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int xmit_fifo_size;
+ int cor1,cor2,cor3,cor4,cor5;
+ int tbpr,tco,rbpr,rco;
+ int baud;
+ int rflow;
+ int rtsdtr_inv;
+ int chip_rev;
+ int custom_divisor;
+ int x_char; /* to be pushed out ASAP */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned long event;
+ unsigned long last_active;
+ int count; /* # of fd on device */
+ int breakon;
+ int breakoff;
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ int default_threshold;
+ int default_timeout;
+ unsigned long jiffies[3];
+ unsigned long rflush_count;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct cyclades_monitor mon;
+ struct cyclades_idle_stats idle_stats;
+ struct cyclades_icount icount;
+ struct tq_struct tqueue;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *shutdown_wait;
+ struct wait_queue *delta_msr_wait;
+};
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at cy interrupt time.
+ */
+#define Cy_EVENT_READ_PROCESS 0
+#define Cy_EVENT_WRITE_WAKEUP 1
+#define Cy_EVENT_HANGUP 2
+#define Cy_EVENT_BREAK 3
+#define Cy_EVENT_OPEN_WAKEUP 4
+#define Cy_EVENT_SHUTDOWN_WAKEUP 5
+#define Cy_EVENT_DELTA_WAKEUP 6
+#define Cy_EVENT_Z_RX_FULL 7
+
+#define CLOSING_WAIT_DELAY 30*HZ
+#define CY_CLOSING_WAIT_NONE 65535
+#define CY_CLOSING_WAIT_INF 0
+
+
+#define CyMAX_CHIPS_PER_CARD 8
+#define CyMAX_CHAR_FIFO 12
+#define CyPORTS_PER_CHIP 4
+#define CD1400_MAX_SPEED 115200
+
+#define CyISA_Ywin 0x2000
+
+#define CyPCI_Ywin 0x4000
+#define CyPCI_Yctl 0x80
+#define CyPCI_Zctl CTRL_WINDOW_SIZE
+#define CyPCI_Zwin 0x80000
+#define CyPCI_Ze_win (2 * CyPCI_Zwin)
+
+#define PCI_DEVICE_ID_MASK 0x06
+
+/**** CD1400 registers ****/
+
+#define CD1400_REV_G 0x46
+#define CD1400_REV_J 0x48
+
+#define CyRegSize 0x0400
+#define Cy_HwReset 0x1400
+#define Cy_ClrIntr 0x1800
+#define Cy_EpldRev 0x1e00
+
+/* Global Registers */
+
+#define CyGFRCR (0x40*2)
+#define CyRevE (44)
+#define CyCAR (0x68*2)
+#define CyCHAN_0 (0x00)
+#define CyCHAN_1 (0x01)
+#define CyCHAN_2 (0x02)
+#define CyCHAN_3 (0x03)
+#define CyGCR (0x4B*2)
+#define CyCH0_SERIAL (0x00)
+#define CyCH0_PARALLEL (0x80)
+#define CySVRR (0x67*2)
+#define CySRModem (0x04)
+#define CySRTransmit (0x02)
+#define CySRReceive (0x01)
+#define CyRICR (0x44*2)
+#define CyTICR (0x45*2)
+#define CyMICR (0x46*2)
+#define CyICR0 (0x00)
+#define CyICR1 (0x01)
+#define CyICR2 (0x02)
+#define CyICR3 (0x03)
+#define CyRIR (0x6B*2)
+#define CyTIR (0x6A*2)
+#define CyMIR (0x69*2)
+#define CyIRDirEq (0x80)
+#define CyIRBusy (0x40)
+#define CyIRUnfair (0x20)
+#define CyIRContext (0x1C)
+#define CyIRChannel (0x03)
+#define CyPPR (0x7E*2)
+#define CyCLOCK_20_1MS (0x27)
+#define CyCLOCK_25_1MS (0x31)
+#define CyCLOCK_25_5MS (0xf4)
+#define CyCLOCK_60_1MS (0x75)
+#define CyCLOCK_60_2MS (0xea)
+
+/* Virtual Registers */
+
+#define CyRIVR (0x43*2)
+#define CyTIVR (0x42*2)
+#define CyMIVR (0x41*2)
+#define CyIVRMask (0x07)
+#define CyIVRRxEx (0x07)
+#define CyIVRRxOK (0x03)
+#define CyIVRTxOK (0x02)
+#define CyIVRMdmOK (0x01)
+#define CyTDR (0x63*2)
+#define CyRDSR (0x62*2)
+#define CyTIMEOUT (0x80)
+#define CySPECHAR (0x70)
+#define CyBREAK (0x08)
+#define CyPARITY (0x04)
+#define CyFRAME (0x02)
+#define CyOVERRUN (0x01)
+#define CyMISR (0x4C*2)
+/* see CyMCOR_ and CyMSVR_ for bits*/
+#define CyEOSRR (0x60*2)
+
+/* Channel Registers */
+
+#define CyLIVR (0x18*2)
+#define CyMscsr (0x01)
+#define CyTdsr (0x02)
+#define CyRgdsr (0x03)
+#define CyRedsr (0x07)
+#define CyCCR (0x05*2)
+/* Format 1 */
+#define CyCHAN_RESET (0x80)
+#define CyCHIP_RESET (0x81)
+#define CyFlushTransFIFO (0x82)
+/* Format 2 */
+#define CyCOR_CHANGE (0x40)
+#define CyCOR1ch (0x02)
+#define CyCOR2ch (0x04)
+#define CyCOR3ch (0x08)
+/* Format 3 */
+#define CySEND_SPEC_1 (0x21)
+#define CySEND_SPEC_2 (0x22)
+#define CySEND_SPEC_3 (0x23)
+#define CySEND_SPEC_4 (0x24)
+/* Format 4 */
+#define CyCHAN_CTL (0x10)
+#define CyDIS_RCVR (0x01)
+#define CyENB_RCVR (0x02)
+#define CyDIS_XMTR (0x04)
+#define CyENB_XMTR (0x08)
+#define CySRER (0x06*2)
+#define CyMdmCh (0x80)
+#define CyRxData (0x10)
+#define CyTxRdy (0x04)
+#define CyTxMpty (0x02)
+#define CyNNDT (0x01)
+#define CyCOR1 (0x08*2)
+#define CyPARITY_NONE (0x00)
+#define CyPARITY_0 (0x20)
+#define CyPARITY_1 (0xA0)
+#define CyPARITY_E (0x40)
+#define CyPARITY_O (0xC0)
+#define Cy_1_STOP (0x00)
+#define Cy_1_5_STOP (0x04)
+#define Cy_2_STOP (0x08)
+#define Cy_5_BITS (0x00)
+#define Cy_6_BITS (0x01)
+#define Cy_7_BITS (0x02)
+#define Cy_8_BITS (0x03)
+#define CyCOR2 (0x09*2)
+#define CyIXM (0x80)
+#define CyTxIBE (0x40)
+#define CyETC (0x20)
+#define CyAUTO_TXFL (0x60)
+#define CyLLM (0x10)
+#define CyRLM (0x08)
+#define CyRtsAO (0x04)
+#define CyCtsAE (0x02)
+#define CyDsrAE (0x01)
+#define CyCOR3 (0x0A*2)
+#define CySPL_CH_DRANGE (0x80) /* special character detect range */
+#define CySPL_CH_DET1 (0x40) /* enable special character detection
+ on SCHR4-SCHR3 */
+#define CyFL_CTRL_TRNSP (0x20) /* Flow Control Transparency */
+#define CySPL_CH_DET2 (0x10) /* Enable special character detection
+ on SCHR2-SCHR1 */
+#define CyREC_FIFO (0x0F) /* Receive FIFO threshold */
+#define CyCOR4 (0x1E*2)
+#define CyCOR5 (0x1F*2)
+#define CyCCSR (0x0B*2)
+#define CyRxEN (0x80)
+#define CyRxFloff (0x40)
+#define CyRxFlon (0x20)
+#define CyTxEN (0x08)
+#define CyTxFloff (0x04)
+#define CyTxFlon (0x02)
+#define CyRDCR (0x0E*2)
+#define CySCHR1 (0x1A*2)
+#define CySCHR2 (0x1B*2)
+#define CySCHR3 (0x1C*2)
+#define CySCHR4 (0x1D*2)
+#define CySCRL (0x22*2)
+#define CySCRH (0x23*2)
+#define CyLNC (0x24*2)
+#define CyMCOR1 (0x15*2)
+#define CyMCOR2 (0x16*2)
+#define CyRTPR (0x21*2)
+#define CyMSVR1 (0x6C*2)
+#define CyMSVR2 (0x6D*2)
+#define CyANY_DELTA (0xF0)
+#define CyDSR (0x80)
+#define CyCTS (0x40)
+#define CyRI (0x20)
+#define CyDCD (0x10)
+#define CyDTR (0x02)
+#define CyRTS (0x01)
+#define CyPVSR (0x6F*2)
+#define CyRBPR (0x78*2)
+#define CyRCOR (0x7C*2)
+#define CyTBPR (0x72*2)
+#define CyTCOR (0x76*2)
+
+/* Custom Registers */
+
+#define CyPLX_VER (0x3400)
+#define PLX_9050 0x0b
+#define PLX_9060 0x0c
+#define PLX_9080 0x0d
+
+/***************************************************************************/
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_CYCLADES_H */
diff --git a/pfinet/linux-src/include/linux/dcache.h b/pfinet/linux-src/include/linux/dcache.h
new file mode 100644
index 00000000..9c1f8b5f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/dcache.h
@@ -0,0 +1,196 @@
+#ifndef __LINUX_DCACHE_H
+#define __LINUX_DCACHE_H
+
+#ifdef __KERNEL__
+
+/*
+ * linux/include/linux/dcache.h
+ *
+ * Dirent cache data structures
+ *
+ * (C) Copyright 1997 Thomas Schoebel-Theuer,
+ * with heavy changes by Linus Torvalds
+ */
+
+#define D_MAXLEN 1024
+
+#define IS_ROOT(x) ((x) == (x)->d_parent)
+
+/*
+ * "quick string" -- eases parameter passing, but more importantly
+ * saves "metadata" about the string (ie length and the hash).
+ */
+struct qstr {
+ const unsigned char * name;
+ unsigned int len;
+ unsigned int hash;
+};
+
+/* Name hashing routines. Initial hash value */
+#define init_name_hash() 0
+
+/* partial hash update function. Assume roughly 4 bits per character */
+static __inline__ unsigned long partial_name_hash(unsigned long c, unsigned long prevhash)
+{
+ prevhash = (prevhash << 4) | (prevhash >> (8*sizeof(unsigned long)-4));
+ return prevhash ^ c;
+}
+
+/* Finally: cut down the number of bits to a int value (and try to avoid losing bits) */
+static __inline__ unsigned long end_name_hash(unsigned long hash)
+{
+ if (sizeof(hash) > sizeof(unsigned int))
+ hash += hash >> 4*sizeof(hash);
+ return (unsigned int) hash;
+}
+
+/* Compute the hash for a name string. */
+static __inline__ unsigned int full_name_hash(const unsigned char * name, unsigned int len)
+{
+ unsigned long hash = init_name_hash();
+ while (len--)
+ hash = partial_name_hash(*name++, hash);
+ return end_name_hash(hash);
+}
+
+#define DNAME_INLINE_LEN 16
+
+struct dentry {
+ int d_count;
+ unsigned int d_flags;
+ struct inode * d_inode; /* Where the name belongs to - NULL is negative */
+ struct dentry * d_parent; /* parent directory */
+ struct dentry * d_mounts; /* mount information */
+ struct dentry * d_covers;
+ struct list_head d_hash; /* lookup hash list */
+ struct list_head d_lru; /* d_count = 0 LRU list */
+ struct list_head d_child; /* child of parent list */
+ struct list_head d_subdirs; /* our children */
+ struct list_head d_alias; /* inode alias list */
+ struct qstr d_name;
+ unsigned long d_time; /* used by d_revalidate */
+ struct dentry_operations *d_op;
+ struct super_block * d_sb; /* The root of the dentry tree */
+ unsigned long d_reftime; /* last time referenced */
+ void * d_fsdata; /* fs-specific data */
+ unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
+};
+
+struct dentry_operations {
+ int (*d_revalidate)(struct dentry *, int);
+ int (*d_hash) (struct dentry *, struct qstr *);
+ int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
+ void (*d_delete)(struct dentry *);
+ void (*d_release)(struct dentry *);
+ void (*d_iput)(struct dentry *, struct inode *);
+};
+
+/* the dentry parameter passed to d_hash and d_compare is the parent
+ * directory of the entries to be compared. It is used in case these
+ * functions need any directory specific information for determining
+ * equivalency classes. Using the dentry itself might not work, as it
+ * might be a negative dentry which has no information associated with
+ * it */
+
+
+
+/* d_flags entries */
+#define DCACHE_AUTOFS_PENDING 0x0001 /* autofs: "under construction" */
+#define DCACHE_NFSFS_RENAMED 0x0002 /* this dentry has been "silly
+ * renamed" and has to be
+ * deleted on the last dput()
+ */
+
+/*
+ * d_drop() unhashes the entry from the parent
+ * dentry hashes, so that it won't be found through
+ * a VFS lookup any more. Note that this is different
+ * from deleting the dentry - d_delete will try to
+ * mark the dentry negative if possible, giving a
+ * successful _negative_ lookup, while d_drop will
+ * just make the cache lookup fail.
+ *
+ * d_drop() is used mainly for stuff that wants
+ * to invalidate a dentry for some reason (NFS
+ * timeouts or autofs deletes).
+ */
+static __inline__ void d_drop(struct dentry * dentry)
+{
+ list_del(&dentry->d_hash);
+ INIT_LIST_HEAD(&dentry->d_hash);
+}
+
+static __inline__ int dname_external(struct dentry *d)
+{
+ return d->d_name.name != d->d_iname;
+}
+
+/*
+ * These are the low-level FS interfaces to the dcache..
+ */
+extern void d_instantiate(struct dentry *, struct inode *);
+extern void d_delete(struct dentry *);
+
+/* allocate/de-allocate */
+extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
+extern int prune_dcache(int, int);
+extern void shrink_dcache_sb(struct super_block *);
+extern void shrink_dcache_parent(struct dentry *);
+extern int d_invalidate(struct dentry *);
+
+#define shrink_dcache() prune_dcache(0, -1)
+
+/* dcache memory management */
+extern void shrink_dcache_memory(int, unsigned int);
+extern void check_dcache_memory(void);
+extern void free_inode_memory(int); /* defined in fs/inode.c */
+
+/* only used at mount-time */
+extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root);
+
+/* test whether root is busy without destroying dcache */
+extern int is_root_busy(struct dentry *);
+
+/* test whether we have any submounts in a subdir tree */
+extern int have_submounts(struct dentry *);
+
+/*
+ * This adds the entry to the hash queues.
+ */
+extern void d_rehash(struct dentry * entry);
+/*
+ * This adds the entry to the hash queues and initializes "d_inode".
+ * The entry was actually filled in earlier during "d_alloc()"
+ */
+static __inline__ void d_add(struct dentry * entry, struct inode * inode)
+{
+ d_rehash(entry);
+ d_instantiate(entry, inode);
+}
+
+/* used for rename() and baskets */
+extern void d_move(struct dentry * entry, struct dentry * newdentry);
+
+/* appendix may either be NULL or be used for transname suffixes */
+extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name);
+
+/* validate "insecure" dentry pointer */
+extern int d_validate(struct dentry *dentry, struct dentry *dparent,
+ unsigned int hash, unsigned int len);
+
+/* write full pathname into buffer and return start of pathname */
+extern char * d_path(struct dentry * entry, char * buf, int buflen);
+
+/* Allocation counts.. */
+static __inline__ struct dentry * dget(struct dentry *dentry)
+{
+ if (dentry)
+ dentry->d_count++;
+ return dentry;
+}
+
+extern void dput(struct dentry *);
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_DCACHE_H */
diff --git a/pfinet/linux-src/include/linux/delay.h b/pfinet/linux-src/include/linux/delay.h
new file mode 100644
index 00000000..e1cf03d6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/delay.h
@@ -0,0 +1,37 @@
+#ifndef _LINUX_DELAY_H
+#define _LINUX_DELAY_H
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines, using a pre-computed "loops_per_second" value.
+ */
+
+extern unsigned long loops_per_sec;
+
+#include <asm/delay.h>
+
+/*
+ * Using udelay() for intervals greater than a few milliseconds can
+ * risk overflow for high loops_per_sec (high bogomips) machines. The
+ * mdelay() provides a wrapper to prevent this. For delays greater
+ * than MAX_UDELAY_MS milliseconds, the wrapper is used. Architecture
+ * specific values can be defined in asm-???/delay.h as an override.
+ * The 2nd mdelay() definition ensures GCC will optimize away the
+ * while loop for the common cases where n <= MAX_UDELAY_MS -- Paul G.
+ */
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_MS 5
+#endif
+
+#ifdef notdef
+#define mdelay(n) (\
+ {unsigned long msec=(n); while (msec--) udelay(1000);})
+#else
+#define mdelay(n) (\
+ (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
+ ({unsigned long msec=(n); while (msec--) udelay(1000);}))
+#endif
+
+#endif /* defined(_LINUX_DELAY_H) */
diff --git a/pfinet/linux-src/include/linux/devpts_fs.h b/pfinet/linux-src/include/linux/devpts_fs.h
new file mode 100644
index 00000000..d9dfbb44
--- /dev/null
+++ b/pfinet/linux-src/include/linux/devpts_fs.h
@@ -0,0 +1,74 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/include/linux/devpts_fs.h
+ *
+ * Copyright 1998 H. Peter Anvin -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+/*
+ * Prototypes for the pty driver <-> devpts filesystem interface. Most
+ * of this is really just a hack so we can exclude it or build it as a
+ * module, and probably should go away eventually.
+ */
+
+#ifndef _LINUX_DEVPTS_FS_H
+#define _LINUX_DEVPTS_FS_H 1
+
+#include <linux/config.h>
+#include <linux/kdev_t.h>
+#include <linux/tty.h>
+
+#ifdef CONFIG_DEVPTS_FS
+
+void devpts_pty_new(int, kdev_t);
+void devpts_pty_kill(int);
+#define unix98_max_ptys NR_PTYS * UNIX98_NR_MAJORS;
+
+#elif defined(CONFIG_DEVPTS_FS_MODULE)
+
+#ifdef BUILDING_PTY_C
+void (*devpts_upcall_new)(int,kdev_t) = NULL;
+void (*devpts_upcall_kill)(int) = NULL;
+unsigned int unix98_max_ptys = NR_PTYS * UNIX98_NR_MAJORS;
+
+EXPORT_SYMBOL(devpts_upcall_new);
+EXPORT_SYMBOL(devpts_upcall_kill);
+EXPORT_SYMBOL(unix98_max_ptys);
+#else
+extern void (*devpts_upcall_new)(int,kdev_t);
+extern void (*devpts_upcall_kill)(int);
+extern unsigned int unix98_max_ptys;
+#endif
+
+#ifndef BUILDING_DEVPTS
+extern inline void
+devpts_pty_new(int line, kdev_t device)
+{
+ if ( devpts_upcall_new )
+ return devpts_upcall_new(line,device);
+}
+
+extern inline void
+devpts_pty_kill(int line)
+{
+ if ( devpts_upcall_kill )
+ return devpts_upcall_kill(line);
+}
+#endif
+
+#else /* No /dev/pts filesystem at all */
+
+extern inline void
+devpts_pty_new(int line, kdev_t device) { }
+
+extern inline void
+devpts_pty_kill(int line) { }
+
+#endif
+
+#endif /* _LINUX_DEVPTS_FS_H */
diff --git a/pfinet/linux-src/include/linux/digi1.h b/pfinet/linux-src/include/linux/digi1.h
new file mode 100644
index 00000000..184378d2
--- /dev/null
+++ b/pfinet/linux-src/include/linux/digi1.h
@@ -0,0 +1,100 @@
+/* Definitions for DigiBoard ditty(1) command. */
+
+#if !defined(TIOCMODG)
+#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
+#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCMSET)
+#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
+#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCMBIC)
+#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
+#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#endif
+
+#if !defined(TIOCSDTR)
+#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
+#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+
+#define DIGI_SETA ('e'<<8) | 95 /* Set params */
+#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
+#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+
+#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+ /* control characters */
+#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+ /* control characters */
+#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+ /* flow control chars */
+#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+ /* flow control chars */
+
+#define DIGI_GETINFO ('e'<<8) | 103 /* Fill in digi_info */
+#define DIGI_POLLER ('e'<<8) | 104 /* Turn on/off poller */
+#define DIGI_INIT ('e'<<8) | 105 /* Allow things to run. */
+
+struct digiflow_struct
+{
+ unsigned char startc; /* flow cntl start char */
+ unsigned char stopc; /* flow cntl stop char */
+};
+
+typedef struct digiflow_struct digiflow_t;
+
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
+#define DIGI_FAST 0x0002 /* Fast baud rates */
+#define RTSPACE 0x0004 /* RTS input flow control */
+#define CTSPACE 0x0008 /* CTS output flow control */
+#define DSRPACE 0x0010 /* DSR output flow control */
+#define DCDPACE 0x0020 /* DCD output flow control */
+#define DTRPACE 0x0040 /* DTR input flow control */
+#define DIGI_FORCEDCD 0x0100 /* Force carrier */
+#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
+#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
+
+
+/************************************************************************
+ * Values for digiDload
+ ************************************************************************/
+#define NORMAL 0
+#define PCI_CTL 1
+
+#define SIZE8 0
+#define SIZE16 1
+#define SIZE32 2
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_struct
+{
+ unsigned short digi_flags; /* Flags (see above) */
+};
+
+typedef struct digi_struct digi_t;
+
+struct digi_info
+{
+ unsigned long board; /* Which board is this ? */
+ unsigned char status; /* Alive or dead */
+ unsigned char type; /* see epca.h */
+ unsigned char subtype; /* For future XEM, XR, etc ... */
+ unsigned short numports; /* Number of ports configured */
+ unsigned char *port; /* I/O Address */
+ unsigned char *membase; /* DPR Address */
+ unsigned char *version; /* For future ... */
+ unsigned short windowData; /* For future ... */
+} ;
diff --git a/pfinet/linux-src/include/linux/digiFep1.h b/pfinet/linux-src/include/linux/digiFep1.h
new file mode 100644
index 00000000..c47d7fcb
--- /dev/null
+++ b/pfinet/linux-src/include/linux/digiFep1.h
@@ -0,0 +1,136 @@
+
+#define CSTART 0x400L
+#define CMAX 0x800L
+#define ISTART 0x800L
+#define IMAX 0xC00L
+#define CIN 0xD10L
+#define GLOBAL 0xD10L
+#define EIN 0xD18L
+#define FEPSTAT 0xD20L
+#define CHANSTRUCT 0x1000L
+#define RXTXBUF 0x4000L
+
+
+struct global_data
+{
+ volatile ushort cin;
+ volatile ushort cout;
+ volatile ushort cstart;
+ volatile ushort cmax;
+ volatile ushort ein;
+ volatile ushort eout;
+ volatile ushort istart;
+ volatile ushort imax;
+};
+
+
+struct board_chan
+{
+ int filler1;
+ int filler2;
+ volatile ushort tseg;
+ volatile ushort tin;
+ volatile ushort tout;
+ volatile ushort tmax;
+
+ volatile ushort rseg;
+ volatile ushort rin;
+ volatile ushort rout;
+ volatile ushort rmax;
+
+ volatile ushort tlow;
+ volatile ushort rlow;
+ volatile ushort rhigh;
+ volatile ushort incr;
+
+ volatile ushort etime;
+ volatile ushort edelay;
+ volatile unchar *dev;
+
+ volatile ushort iflag;
+ volatile ushort oflag;
+ volatile ushort cflag;
+ volatile ushort gmask;
+
+ volatile ushort col;
+ volatile ushort delay;
+ volatile ushort imask;
+ volatile ushort tflush;
+
+ int filler3;
+ int filler4;
+ int filler5;
+ int filler6;
+
+ volatile unchar num;
+ volatile unchar ract;
+ volatile unchar bstat;
+ volatile unchar tbusy;
+ volatile unchar iempty;
+ volatile unchar ilow;
+ volatile unchar idata;
+ volatile unchar eflag;
+
+ volatile unchar tflag;
+ volatile unchar rflag;
+ volatile unchar xmask;
+ volatile unchar xval;
+ volatile unchar mstat;
+ volatile unchar mchange;
+ volatile unchar mint;
+ volatile unchar lstat;
+
+ volatile unchar mtran;
+ volatile unchar orun;
+ volatile unchar startca;
+ volatile unchar stopca;
+ volatile unchar startc;
+ volatile unchar stopc;
+ volatile unchar vnext;
+ volatile unchar hflow;
+
+ volatile unchar fillc;
+ volatile unchar ochar;
+ volatile unchar omask;
+
+ unchar filler7;
+ unchar filler8[28];
+};
+
+
+#define SRXLWATER 0xE0
+#define SRXHWATER 0xE1
+#define STOUT 0xE2
+#define PAUSETX 0xE3
+#define RESUMETX 0xE4
+#define SAUXONOFFC 0xE6
+#define SENDBREAK 0xE8
+#define SETMODEM 0xE9
+#define SETIFLAGS 0xEA
+#define SONOFFC 0xEB
+#define STXLWATER 0xEC
+#define PAUSERX 0xEE
+#define RESUMERX 0xEF
+#define SETBUFFER 0xF2
+#define SETCOOKED 0xF3
+#define SETHFLOW 0xF4
+#define SETCTRLFLAGS 0xF5
+#define SETVNEXT 0xF6
+
+
+
+#define BREAK_IND 0x01
+#define LOWTX_IND 0x02
+#define EMPTYTX_IND 0x04
+#define DATA_IND 0x08
+#define MODEMCHG_IND 0x20
+
+#define FEP_HUPCL 0002000
+#if 0
+#define RTS 0x02
+#define CD 0x08
+#define DSR 0x10
+#define CTS 0x20
+#define RI 0x40
+#define DTR 0x80
+#endif
diff --git a/pfinet/linux-src/include/linux/digiPCI.h b/pfinet/linux-src/include/linux/digiPCI.h
new file mode 100644
index 00000000..6ca7819e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/digiPCI.h
@@ -0,0 +1,42 @@
+/*************************************************************************
+ * Defines and structure definitions for PCI BIOS Interface
+ *************************************************************************/
+#define PCIMAX 32 /* maximum number of PCI boards */
+
+
+#define PCI_VENDOR_DIGI 0x114F
+#define PCI_DEVICE_EPC 0x0002
+#define PCI_DEVICE_RIGHTSWITCH 0x0003 /* For testing */
+#define PCI_DEVICE_XEM 0x0004
+#define PCI_DEVICE_XR 0x0005
+#define PCI_DEVICE_CX 0x0006
+#define PCI_DEVICE_XRJ 0x0009 /* Jupiter boards with */
+#define PCI_DEVICE_EPCJ 0x000a /* PLX 9060 chip for PCI */
+
+
+/*
+ * On the PCI boards, there is no IO space allocated
+ * The I/O registers will be in the first 3 bytes of the
+ * upper 2MB of the 4MB memory space. The board memory
+ * will be mapped into the low 2MB of the 4MB memory space
+ */
+
+/* Potential location of PCI Bios from E0000 to FFFFF*/
+#define PCI_BIOS_SIZE 0x00020000
+
+/* Size of Memory and I/O for PCI (4MB) */
+#define PCI_RAM_SIZE 0x00400000
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE 0x00200000
+
+/* Offset of I/0 in Memory (2MB) */
+#define PCI_IO_OFFSET 0x00200000
+
+#define MEMOUTB(basemem, pnum, setmemval) *(caddr_t)((basemem) + ( PCI_IO_OFFSET | pnum << 4 | pnum )) = (setmemval)
+#define MEMINB(basemem, pnum) *(caddr_t)((basemem) + (PCI_IO_OFFSET | pnum << 4 | pnum )) /* for PCI I/O */
+
+
+
+
+
diff --git a/pfinet/linux-src/include/linux/dio.h b/pfinet/linux-src/include/linux/dio.h
new file mode 100644
index 00000000..087b06ec
--- /dev/null
+++ b/pfinet/linux-src/include/linux/dio.h
@@ -0,0 +1,204 @@
+/* header file for DIO boards for the HP300 architecture.
+ * Maybe this should handle DIO-II later?
+ * The general structure of this is vaguely based on how
+ * the Amiga port handles Zorro boards.
+ * Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk>
+ *
+ * The board IDs are from the NetBSD kernel, which for once provided
+ * helpful comments...
+ *
+ * This goes with arch/m68k/hp300/dio.c
+ */
+
+#ifndef _LINUX_DIO_H
+#define _LINUX_DIO_H
+
+/* The DIO boards in a system are distinguished by 'select codes' which
+ * range from 0-63 (DIO) and 132-255 (DIO-II).
+ * The DIO board with select code sc is located at physical address
+ * 0x600000 + sc * 0x10000
+ * So DIO cards cover [0x600000-0x800000); the areas [0x200000-0x400000) and
+ * [0x800000-0x1000000) are for additional space required by things
+ * like framebuffers. [0x400000-0x600000) is for miscellaneous internal I/O.
+ * On Linux, this is currently all mapped into the virtual address space
+ * at 0xf0000000 on bootup.
+ * DIO-II boards are at 0x1000000 + (sc - 132) * 0x400000
+ * which is address range [0x1000000-0x20000000) -- too big to map completely,
+ * so currently we just don't handle DIO-II boards. It wouldn't be hard to
+ * do with ioremap() though.
+ */
+#ifdef __KERNEL__
+/* DIO/DIO-II boards all have the following 8bit registers.
+ * These are offsets from the base of the device.
+ */
+#define DIO_IDOFF 0x01 /* primary device ID */
+#define DIO_IPLOFF 0x03 /* interrupt priority level */
+#define DIO_SECIDOFF 0x15 /* secondary device ID */
+#define DIOII_SIZEOFF 0x101 /* device size, DIO-II only */
+
+/* The internal HPIB device is special; this is its physaddr; its select code is 7.
+ * The reason why we have to treat it specially is because apparently it's broken:
+ * the device ID isn't consistent/reliable. *sigh*
+ */
+#define DIO_IHPIBADDR 0x47800
+#define DIO_IHPIBSCODE 7
+
+/* If we don't have the internal HPIB defined, then treat select code 7 like
+ * any other. If we *do* have internal HPIB, then we just have to assume that
+ * select code 7 is the internal HPIB regardless of the ID register :-<
+ */
+#define CONFIG_IHPIB /* hack hack : not yet a proper config option */
+#ifdef CONFIG_IHPIB
+#define DIO_ISIHPIB(scode) ((scode) == DIO_IHPIBSCODE)
+#else
+#define DIO_ISIHPIB(scode) 0
+#endif
+
+#define DIO_VIRADDRBASE 0xf0000000 /* vir addr where IOspace is mapped */
+
+#define DIO_BASE 0x600000 /* start of DIO space */
+#define DIO_END 0x1000000 /* end of DIO space */
+#define DIO_DEVSIZE 0x10000 /* size of a DIO device */
+
+#define DIOII_BASE 0x01000000 /* start of DIO-II space */
+#define DIOII_END 0x20000000 /* end of DIO-II space */
+#define DIOII_DEVSIZE 0x00400000 /* size of a DIO-II device */
+
+/* Highest valid select code. If we add DIO-II support this should become
+ * 256 for everything except HP320, which only has DIO.
+ */
+#define DIO_SCMAX 32
+#define DIOII_SCBASE 132 /* lowest DIO-II select code */
+#define DIO_SCINHOLE(scode) (((scode) >= 32) && ((scode) < DIOII_SCBASE))
+
+/* macros to read device IDs, given base address */
+#define DIO_ID(baseaddr) readb((baseaddr) + DIO_IDOFF)
+#define DIO_SECID(baseaddr) readb((baseaddr) + DIO_SECIDOFF)
+
+/* extract the interrupt level */
+#define DIO_IPL(baseaddr) (((readb((baseaddr) + DIO_IPLOFF) >> 4) & 0x03) + 3)
+
+/* find the size of a DIO-II board's address space.
+ * DIO boards are all fixed length.
+ */
+#define DIOII_SIZE(baseaddr) ((readb((baseaddr) + DIOII_SIZEOFF) + 1) * 0x100000)
+
+/* general purpose macro for both DIO and DIO-II */
+#define DIO_SIZE(scode, base) (DIO_ISDIOII((scode)) ? DIOII_SIZE((base)) : DIO_DEVSIZE)
+
+/* The hardware has primary and secondary IDs; we encode these in a single
+ * int as PRIMARY ID & (SECONDARY ID << 8).
+ * In practice this is only important for framebuffers,
+ * and everybody else just sets ID fields equal to the DIO_ID_FOO value.
+ */
+#define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) & ((int)pr & 0xff))
+/* macro to determine whether a given primary ID requires a secondary ID byte */
+#define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER)
+
+/* Now a whole slew of macros giving device IDs and descriptive strings: */
+#define DIO_ID_DCA0 0x02 /* 98644A serial */
+#define DIO_DESC_DCA0 "98644A DCA0 serial"
+#define DIO_ID_DCA0REM 0x82 /* 98644A serial */
+#define DIO_DESC_DCA0REM "98644A DCA0REM serial"
+#define DIO_ID_DCA1 0x42 /* 98644A serial */
+#define DIO_DESC_DCA1 "98644A DCA1 serial"
+#define DIO_ID_DCA1REM 0xc2 /* 98644A serial */
+#define DIO_DESC_DCA1REM "98644A DCA1REM serial"
+#define DIO_ID_DCM 0x05 /* 98642A serial MUX */
+#define DIO_DESC_DCM "98642A DCM serial MUX"
+#define DIO_ID_DCMREM 0x85 /* 98642A serial MUX */
+#define DIO_DESC_DCMREM "98642A DCMREM serial MUX"
+#define DIO_ID_LAN 0x15 /* 98643A LAN */
+#define DIO_DESC_LAN "98643A LAN"
+#define DIO_ID_FHPIB 0x08 /* 98625A/98625B fast HP-IB */
+#define DIO_DESC_FHPIB "98625A/98625B fast HPIB"
+#define DIO_ID_NHPIB 0x80 /* 98624A HP-IB (normal ie slow) */
+#define DIO_DESC_NHPIB "98624A HPIB"
+#define DIO_ID_IHPIB 0x00 /* internal HPIB (not its real ID, it hasn't got one! */
+#define DIO_DESC_IHPIB "internal HPIB"
+#define DIO_ID_SCSI0 0x07 /* 98625A SCSI */
+#define DIO_DESC_SCSI0 "98625A SCSI0"
+#define DIO_ID_SCSI1 0x27 /* ditto */
+#define DIO_DESC_SCSI1 "98625A SCSI1"
+#define DIO_ID_SCSI2 0x47 /* ditto */
+#define DIO_DESC_SCSI2 "98625A SCSI2"
+#define DIO_ID_SCSI3 0x67 /* ditto */
+#define DIO_DESC_SCSI3 "98625A SCSI3"
+#define DIO_ID_FBUFFER 0x39 /* framebuffer: flavour is distinguished by secondary ID */
+#define DIO_DESC_FBUFFER "bitmapped display"
+/* the NetBSD kernel source is a bit unsure as to what these next IDs actually do :-> */
+#define DIO_ID_MISC0 0x03 /* 98622A */
+#define DIO_DESC_MISC0 "98622A"
+#define DIO_ID_MISC1 0x04 /* 98623A */
+#define DIO_DESC_MISC1 "98623A"
+#define DIO_ID_PARALLEL 0x06 /* internal parallel */
+#define DIO_DESC_PARALLEL "internal parallel"
+#define DIO_ID_MISC2 0x09 /* 98287A keyboard */
+#define DIO_DESC_MISC2 "98287A keyboard"
+#define DIO_ID_MISC3 0x0a /* HP98635A FP accelerator */
+#define DIO_DESC_MISC3 "HP98635A FP accelerator"
+#define DIO_ID_MISC4 0x0b /* timer */
+#define DIO_DESC_MISC4 "timer"
+#define DIO_ID_MISC5 0x12 /* 98640A */
+#define DIO_DESC_MISC5 "98640A"
+#define DIO_ID_MISC6 0x16 /* 98659A */
+#define DIO_DESC_MISC6 "98659A"
+#define DIO_ID_MISC7 0x19 /* 237 display */
+#define DIO_DESC_MISC7 "237 display"
+#define DIO_ID_MISC8 0x1a /* quad-wide card */
+#define DIO_DESC_MISC8 "quad-wide card"
+#define DIO_ID_MISC9 0x1b /* 98253A */
+#define DIO_DESC_MISC9 "98253A"
+#define DIO_ID_MISC10 0x1c /* 98627A */
+#define DIO_DESC_MISC10 "98253A"
+#define DIO_ID_MISC11 0x1d /* 98633A */
+#define DIO_DESC_MISC11 "98633A"
+#define DIO_ID_MISC12 0x1e /* 98259A */
+#define DIO_DESC_MISC12 "98259A"
+#define DIO_ID_MISC13 0x1f /* 8741 */
+#define DIO_DESC_MISC13 "8741"
+#define DIO_ID_VME 0x31 /* 98577A VME adapter */
+#define DIO_DESC_VME "98577A VME adapter"
+#define DIO_ID_DCL 0x34 /* 98628A serial */
+#define DIO_DESC_DCL "98628A DCL serial"
+#define DIO_ID_DCLREM 0xb4 /* 98628A serial */
+#define DIO_DESC_DCLREM "98628A DCLREM serial"
+/* These are the secondary IDs for the framebuffers */
+#define DIO_ID2_GATORBOX 0x01 /* 98700/98710 "gatorbox" */
+#define DIO_DESC2_GATORBOX "98700/98710 \"gatorbox\" display"
+#define DIO_ID2_TOPCAT 0x02 /* 98544/98545/98547 "topcat" */
+#define DIO_DESC2_TOPCAT "98544/98545/98547 \"topcat\" display"
+#define DIO_ID2_RENAISSANCE 0x04 /* 98720/98721 "renaissance" */
+#define DIO_DESC2_RENAISSANCE "98720/98721 \"renaissance\" display"
+#define DIO_ID2_LRCATSEYE 0x05 /* lowres "catseye" */
+#define DIO_DESC2_LRCATSEYE "low-res catseye display"
+#define DIO_ID2_HRCCATSEYE 0x06 /* highres colour "catseye" */
+#define DIO_DESC2_HRCCATSEYE "high-res color catseye display"
+#define DIO_ID2_HRMCATSEYE 0x07 /* highres mono "catseye" */
+#define DIO_DESC2_HRMCATSEYE "high-res mono catseye display"
+#define DIO_ID2_DAVINCI 0x08 /* 98730/98731 "davinci" */
+#define DIO_DESC2_DAVINCI "98730/98731 \"davinci\" display"
+#define DIO_ID2_XXXCATSEYE 0x09 /* "catseye" */
+#define DIO_DESC2_XXXCATSEYE "catseye display"
+#define DIO_ID2_HYPERION 0x0e /* A1096A "hyperion" */
+#define DIO_DESC2_HYPERION "A1096A \"hyperion\" display"
+#define DIO_ID2_XGENESIS 0x0b /* "x-genesis"; no NetBSD support */
+#define DIO_DESC2_XGENESIS "\"x-genesis\" display"
+#define DIO_ID2_TIGER 0x0c /* "tiger"; no NetBSD support */
+#define DIO_DESC2_TIGER "\"tiger\" display"
+#define DIO_ID2_YGENESIS 0x0d /* "y-genesis"; no NetBSD support */
+#define DIO_DESC2_YGENESIS "\"y-genesis\" display"
+/* if you add new IDs then you should tell dio.c about them so it can
+ * identify them...
+ */
+
+extern void dio_init(void);
+extern int dio_find(int deviceid);
+extern void *dio_scodetoviraddr(int scode);
+extern int dio_scodetoipl(int scode);
+extern void dio_config_board(int scode);
+extern void dio_unconfig_board(int scode);
+
+
+#endif /* __KERNEL__ */
+#endif /* ndef _LINUX_DIO_H */
diff --git a/pfinet/linux-src/include/linux/dirent.h b/pfinet/linux-src/include/linux/dirent.h
new file mode 100644
index 00000000..a18f7e46
--- /dev/null
+++ b/pfinet/linux-src/include/linux/dirent.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_DIRENT_H
+#define _LINUX_DIRENT_H
+
+struct dirent {
+ long d_ino;
+ __kernel_off_t d_off;
+ unsigned short d_reclen;
+ char d_name[256]; /* We must not include limits.h! */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/dlists.h b/pfinet/linux-src/include/linux/dlists.h
new file mode 100644
index 00000000..f92485e4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/dlists.h
@@ -0,0 +1,108 @@
+#ifndef DLISTS_H
+#define DLISTS_H
+/*
+ * include/linux/dlists.h - macros for double linked lists
+ *
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+/* dlists are cyclic ringlists, so the last element cannot be tested
+ * for NULL. Use the following construct for traversing cyclic lists:
+ * ptr = anchor;
+ * if(ptr) do {
+ * ...
+ * ptr = ptr->{something}_{next,prev};
+ * } while(ptr != anchor);
+ * The effort here is paid off with much simpler inserts/removes.
+ * Examples for usage of these macros can be found in fs/ninode.c.
+ * To access the last element in constant time, simply use
+ * anchor->{something}_prev.
+ */
+
+#define DEF_GENERIC_INSERT(CHANGE,PREFIX,NAME,TYPE,NEXT,PREV) \
+static inline void PREFIX##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * oldfirst = *anchor;\
+ if(!oldfirst) {\
+ elem->NEXT = elem->PREV = *anchor = elem;\
+ } else {\
+ elem->PREV = oldfirst->PREV;\
+ elem->NEXT = oldfirst;\
+ oldfirst->PREV->NEXT = elem;\
+ oldfirst->PREV = elem;\
+ if(CHANGE)\
+ *anchor = elem;\
+ }\
+}
+
+/* insert_* is always at the first position */
+#define DEF_INSERT(NAME,TYPE,NEXT,PREV) \
+ DEF_GENERIC_INSERT(1,insert_,NAME,TYPE,NEXT,PREV)
+
+/* append_* is always at the tail */
+#define DEF_APPEND(NAME,TYPE,NEXT,PREV) \
+ DEF_GENERIC_INSERT(0,append_,NAME,TYPE,NEXT,PREV)
+
+/* use this to insert _before_ oldelem somewhere in the middle of the list.
+ * the list must not be empty, and oldelem must be already a member.*/
+#define DEF_INSERT_MIDDLE(NAME,TYPE) \
+static inline void insert_middle_##NAME(TYPE ** anchor, TYPE * oldelem, TYPE * elem)\
+{\
+ int status = (oldelem == *anchor);\
+ insert_##NAME(&oldelem, elem);\
+ if(status)\
+ *anchor = oldelem;\
+}
+
+/* remove can be done with any element in the list */
+#define DEF_REMOVE(NAME,TYPE,NEXT,PREV) \
+static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * next = elem->NEXT;\
+ if(next == elem) {\
+ *anchor = NULL;\
+ } else {\
+ TYPE * prev = elem->PREV;\
+ prev->NEXT = next;\
+ next->PREV = prev;\
+ elem->NEXT = elem->PREV = NULL;/*leave this during debugging*/\
+ if(*anchor == elem)\
+ *anchor = next;\
+ }\
+}
+
+
+/* According to ideas from David S. Miller, here is a slightly
+ * more efficient plug-in compatible version using non-cyclic lists,
+ * but allowing neither backward traversals nor constant time access
+ * to the last element.
+ * Note that although the interface is the same, the PPREV pointer must be
+ * declared doubly indirect and the test for end-of-list is different. */
+
+/* as above, this inserts always at the head */
+#define DEF_LIN_INSERT(NAME,TYPE,NEXT,PPREV) \
+static inline void insert_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * first;\
+ if((elem->NEXT = first = *anchor))\
+ first->PPREV = &elem->NEXT;\
+ *anchor = elem;\
+ elem->PPREV = anchor;\
+}
+
+/* as above, this works with any list element */
+#define DEF_LIN_REMOVE(NAME,TYPE,NEXT,PPREV) \
+static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+ TYPE * pprev;\
+ if((pprev = elem->PPREV)) {\
+ TYPE * next;\
+ if((next = elem->NEXT))\
+ next->PPREV = pprev;\
+ *pprev = next;\
+ elem->PPREV = elem->NEXT = NULL; /*leave this for debugging*/\
+ }\
+}
+
+#endif
diff --git a/pfinet/linux-src/include/linux/dmascc.h b/pfinet/linux-src/include/linux/dmascc.h
new file mode 100644
index 00000000..01b46df7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/dmascc.h
@@ -0,0 +1,43 @@
+/*
+ * $Id: dmascc.h,v 1.1 1997/12/01 10:44:55 oe1kib Exp $
+ *
+ * Driver for high-speed SCC boards (those with DMA support)
+ * Copyright (C) 1997 Klaus Kudielka
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Ioctls */
+#define SIOCGSCCPARAM SIOCDEVPRIVATE
+#define SIOCSSCCPARAM (SIOCDEVPRIVATE+1)
+
+/* Frequency of timer 0 */
+#define TMR_0_HZ 25600
+
+/* Configurable parameters */
+struct scc_param {
+ int pclk_hz; /* frequency of BRG input (read-only - don't change) */
+ int brg_tc; /* baud rate generator terminal count - BRG disabled if < 0 */
+ int nrzi; /* 0 (nrz), 1 (nrzi) */
+ int clocks; /* see documentation */
+ int txdelay; /* [1/TMR_0_HZ] */
+ int txtime; /* [1/HZ] */
+ int sqdelay; /* [1/TMR_0_HZ] */
+ int waittime; /* [1/TMR_0_HZ] */
+ int slottime; /* [1/TMR_0_HZ] */
+ int persist; /* 0 ... 255 */
+ int dma; /* 1, 3 */
+};
+
diff --git a/pfinet/linux-src/include/linux/dtlk.h b/pfinet/linux-src/include/linux/dtlk.h
new file mode 100644
index 00000000..07a6b82b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/dtlk.h
@@ -0,0 +1,104 @@
+#if 0
+
+#define TRACE_TXT(text) \
+ { \
+ if(dtlk_trace) \
+ { \
+ console_print(text); \
+ console_print("\n"); \
+ } \
+ }
+
+#define TRACE_CHR(chr) \
+ { \
+ if(dtlk_trace) \
+ console_print(chr); \
+ } \
+
+#endif
+
+#define DTLK_MINOR 0
+#define DTLK_IO_EXTENT 0x02
+
+ /* ioctl's use magic number of 0xa3 */
+#define DTLK_INTERROGATE 0xa390 /* get settings from the DoubleTalk */
+#define DTLK_STATUS 0xa391 /* get status from the DoubleTalk */
+
+
+#define DTLK_CLEAR 0x18 /* stops speech */
+
+#define DTLK_MAX_RETRIES (loops_per_sec/10000)
+
+ /* TTS Port Status Flags */
+#define TTS_READABLE 0x80 /* mask for bit which is nonzero if a
+ byte can be read from the TTS port */
+#define TTS_SPEAKING 0x40 /* mask for SYNC bit, which is nonzero
+ while DoubleTalk is producing
+ output with TTS, PCM or CVSD
+ synthesizers or tone generators
+ (that is, all but LPC) */
+#define TTS_SPEAKING2 0x20 /* mask for SYNC2 bit,
+ which falls to zero up to 0.4 sec
+ before speech stops */
+#define TTS_WRITABLE 0x10 /* mask for RDY bit, which when set to
+ 1, indicates the TTS port is ready
+ to accept a byte of data. The RDY
+ bit goes zero 2-3 usec after
+ writing, and goes 1 again 180-190
+ usec later. */
+#define TTS_ALMOST_FULL 0x08 /* mask for AF bit: When set to 1,
+ indicates that less than 300 free
+ bytes are available in the TTS
+ input buffer. AF is always 0 in the
+ PCM, TGN and CVSD modes. */
+#define TTS_ALMOST_EMPTY 0x04 /* mask for AE bit: When set to 1,
+ indicates that less than 300 bytes
+ of data remain in DoubleTalk's
+ input (TTS or PCM) buffer. AE is
+ always 1 in the TGN and CVSD
+ modes. */
+
+ /* LPC speak commands */
+#define LPC_5220_NORMAL 0x60 /* 5220 format decoding table, normal rate */
+#define LPC_5220_FAST 0x64 /* 5220 format decoding table, fast rate */
+#define LPC_D6_NORMAL 0x20 /* D6 format decoding table, normal rate */
+#define LPC_D6_FAST 0x24 /* D6 format decoding table, fast rate */
+
+ /* LPC Port Status Flags (valid only after one of the LPC
+ speak commands) */
+#define LPC_SPEAKING 0x80 /* mask for TS bit: When set to 1,
+ indicates the LPC synthesizer is
+ producing speech.*/
+#define LPC_BUFFER_LOW 0x40 /* mask for BL bit: When set to 1,
+ indicates that the hardware LPC
+ data buffer has less than 30 bytes
+ remaining. (Total internal buffer
+ size = 4096 bytes.) */
+#define LPC_BUFFER_EMPTY 0x20 /* mask for BE bit: When set to 1,
+ indicates that the LPC data buffer
+ ran out of data (error condition if
+ TS is also 1). */
+
+ /* data returned by Interrogate command */
+struct dtlk_settings
+{
+ unsigned short serial_number; /* 0-7Fh:0-7Fh */
+ unsigned char rom_version[24]; /* null terminated string */
+ unsigned char mode; /* 0=Character; 1=Phoneme; 2=Text */
+ unsigned char punc_level; /* nB; 0-7 */
+ unsigned char formant_freq; /* nF; 0-9 */
+ unsigned char pitch; /* nP; 0-99 */
+ unsigned char speed; /* nS; 0-9 */
+ unsigned char volume; /* nV; 0-9 */
+ unsigned char tone; /* nX; 0-2 */
+ unsigned char expression; /* nE; 0-9 */
+ unsigned char ext_dict_loaded; /* 1=exception dictionary loaded */
+ unsigned char ext_dict_status; /* 1=exception dictionary enabled */
+ unsigned char free_ram; /* # pages (truncated) remaining for
+ text buffer */
+ unsigned char articulation; /* nA; 0-9 */
+ unsigned char reverb; /* nR; 0-9 */
+ unsigned char eob; /* 7Fh value indicating end of
+ parameter block */
+ unsigned char has_indexing; /* nonzero if indexing is implemented */
+};
diff --git a/pfinet/linux-src/include/linux/efs_dir.h b/pfinet/linux-src/include/linux/efs_dir.h
new file mode 100644
index 00000000..33152413
--- /dev/null
+++ b/pfinet/linux-src/include/linux/efs_dir.h
@@ -0,0 +1,42 @@
+/*
+ * efs_dir.h
+ *
+ * Copyright (c) 1999 Al Smith
+ */
+
+#ifndef __EFS_DIR_H__
+#define __EFS_DIR_H__
+
+#define EFS_DIRBSIZE_BITS EFS_BLOCKSIZE_BITS
+#define EFS_DIRBSIZE (1 << EFS_DIRBSIZE_BITS)
+
+struct efs_dentry {
+ unsigned int inode;
+ unsigned char namelen;
+ char name[3];
+};
+
+#define EFS_DENTSIZE (sizeof(struct efs_dentry) - 3 + 1)
+#define EFS_MAXNAMELEN ((1 << (sizeof(char) * 8)) - 1)
+
+#define EFS_DIRBLK_HEADERSIZE 4
+#define EFS_DIRBLK_MAGIC 0xbeef /* moo */
+
+struct efs_dir {
+ unsigned short magic;
+ unsigned char firstused;
+ unsigned char slots;
+
+ unsigned char space[EFS_DIRBSIZE - EFS_DIRBLK_HEADERSIZE];
+};
+
+#define EFS_MAXENTS \
+ ((EFS_DIRBSIZE - EFS_DIRBLK_HEADERSIZE) / \
+ (EFS_DENTSIZE + sizeof(char)))
+
+#define EFS_SLOTAT(dir, slot) EFS_REALOFF((dir)->space[slot])
+
+#define EFS_REALOFF(offset) ((offset << 1))
+
+#endif /* __EFS_DIR_H__ */
+
diff --git a/pfinet/linux-src/include/linux/efs_fs.h b/pfinet/linux-src/include/linux/efs_fs.h
new file mode 100644
index 00000000..1e5fd23c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/efs_fs.h
@@ -0,0 +1,67 @@
+/*
+ * efs_fs.h
+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
+ */
+
+#ifndef __EFS_FS_H__
+#define __EFS_FS_H__
+
+#define EFS_VERSION "1.0b"
+
+static const char cprt[] = "EFS: "EFS_VERSION" - (c) 1999 Al Smith <Al.Smith@aeschi.ch.eu.org>";
+
+#include <asm/uaccess.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#if LINUX_VERSION_CODE < 0x20200
+#error This code is only for linux-2.2 and later.
+#endif
+
+/* 1 block is 512 bytes */
+#define EFS_BLOCKSIZE_BITS 9
+#define EFS_BLOCKSIZE (1 << EFS_BLOCKSIZE_BITS)
+
+#include <linux/efs_fs_i.h>
+#include <linux/efs_dir.h>
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifdef _EFS_USE_GENERIC
+#define INODE_INFO(i) (struct efs_inode_info *) &((i)->u.generic_ip)
+#define SUPER_INFO(s) (struct efs_sb_info *) &((s)->u.generic_sbp)
+#else
+#define INODE_INFO(i) &((i)->u.efs_i)
+#define SUPER_INFO(s) &((s)->u.efs_sb)
+#endif
+
+extern struct inode_operations efs_dir_inode_operations;
+extern struct inode_operations efs_file_inode_operations;
+extern struct inode_operations efs_symlink_inode_operations;
+
+extern int init_module(void);
+extern void cleanup_module(void);
+extern struct super_block *efs_read_super(struct super_block *, void *, int);
+extern void efs_put_super(struct super_block *);
+extern int efs_statfs(struct super_block *, struct statfs *, int);
+
+extern void efs_read_inode(struct inode *);
+extern efs_block_t efs_map_block(struct inode *, efs_block_t);
+
+extern struct dentry *efs_lookup(struct inode *, struct dentry *);
+extern int efs_bmap(struct inode *, int);
+
+extern int init_efs_fs(void);
+
+#endif /* __EFS_FS_H__ */
+
diff --git a/pfinet/linux-src/include/linux/efs_fs_i.h b/pfinet/linux-src/include/linux/efs_fs_i.h
new file mode 100644
index 00000000..453d706c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/efs_fs_i.h
@@ -0,0 +1,68 @@
+/*
+ * efs_fs_i.h
+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from IRIX header files (c) 1988 Silicon Graphics
+ */
+
+#ifndef __EFS_FS_I_H__
+#define __EFS_FS_I_H__
+
+typedef int32_t efs_block_t;
+typedef uint32_t efs_ino_t;
+
+#define EFS_DIRECTEXTENTS 12
+
+/*
+ * layout of an extent, in memory and on disk. 8 bytes exactly.
+ */
+typedef union extent_u {
+ unsigned char raw[8];
+ struct extent_s {
+ unsigned int ex_magic:8; /* magic # (zero) */
+ unsigned int ex_bn:24; /* basic block */
+ unsigned int ex_length:8; /* numblocks in this extent */
+ unsigned int ex_offset:24; /* logical offset into file */
+ } cooked;
+} efs_extent;
+
+typedef struct edevs {
+ short odev;
+ short dev_filler; /* force ndev to start */
+ unsigned int ndev; /* on a 32-bit boundary */
+} efs_devs;
+
+/*
+ * extent based filesystem inode as it appears on disk. The efs inode
+ * is exactly 128 bytes long.
+ */
+struct efs_dinode {
+ u_short di_mode; /* mode and type of file */
+ short di_nlink; /* number of links to file */
+ u_short di_uid; /* owner's user id */
+ u_short di_gid; /* owner's group id */
+ int32_t di_size; /* number of bytes in file */
+ int32_t di_atime; /* time last accessed */
+ int32_t di_mtime; /* time last modified */
+ int32_t di_ctime; /* time created */
+ uint32_t di_gen; /* generation number */
+ short di_numextents; /* # of extents */
+ u_char di_version; /* version of inode */
+ u_char di_spare; /* spare - used by AFS */
+ union di_addr {
+ efs_extent di_extents[EFS_DIRECTEXTENTS];
+ efs_devs di_dev; /* device for IFCHR/IFBLK */
+ } di_u;
+};
+
+/* efs inode storage in memory */
+struct efs_inode_info {
+ int numextents;
+ int lastextent;
+
+ efs_extent extents[EFS_DIRECTEXTENTS];
+};
+
+#endif /* __EFS_FS_I_H__ */
+
diff --git a/pfinet/linux-src/include/linux/efs_fs_sb.h b/pfinet/linux-src/include/linux/efs_fs_sb.h
new file mode 100644
index 00000000..95476663
--- /dev/null
+++ b/pfinet/linux-src/include/linux/efs_fs_sb.h
@@ -0,0 +1,63 @@
+/*
+ * efs_fs_sb.h
+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from IRIX header files (c) 1988 Silicon Graphics
+ */
+
+#ifndef __EFS_FS_SB_H__
+#define __EFS_FS_SB_H__
+
+/* statfs() magic number for EFS */
+#define EFS_SUPER_MAGIC 0x414A53
+
+/* EFS superblock magic numbers */
+#define EFS_MAGIC 0x072959
+#define EFS_NEWMAGIC 0x07295a
+
+#define IS_EFS_MAGIC(x) ((x == EFS_MAGIC) || (x == EFS_NEWMAGIC))
+
+#define EFS_SUPER 1
+#define EFS_ROOTINODE 2
+
+/* efs superblock on disk */
+struct efs_super {
+ int32_t fs_size; /* size of filesystem, in sectors */
+ int32_t fs_firstcg; /* bb offset to first cg */
+ int32_t fs_cgfsize; /* size of cylinder group in bb's */
+ short fs_cgisize; /* bb's of inodes per cylinder group */
+ short fs_sectors; /* sectors per track */
+ short fs_heads; /* heads per cylinder */
+ short fs_ncg; /* # of cylinder groups in filesystem */
+ short fs_dirty; /* fs needs to be fsck'd */
+ short fs_filler; /* force fs_time to start 2bytes later*/
+ int32_t fs_time; /* last super-block update */
+ int32_t fs_magic; /* magic number */
+ char fs_fname[6]; /* file system name */
+ char fs_fpack[6]; /* file system pack name */
+ int32_t fs_bmsize; /* size of bitmap in bytes */
+ int32_t fs_tfree; /* total free data blocks */
+ int32_t fs_tinode; /* total free inodes */
+ int32_t fs_bmblock; /* bitmap location. */
+ int32_t fs_replsb; /* Location of replicated superblock. */
+ int32_t fs_lastialloc; /* last allocated inode */
+ char fs_spare[20]; /* space for expansion - MUST BE ZERO */
+ int32_t fs_checksum; /* checksum of volume portion of fs */
+};
+
+/* efs superblock information in memory */
+struct efs_sb_info {
+ int32_t fs_magic; /* superblock magic number */
+ int32_t fs_start; /* first block of filesystem */
+ int32_t first_block; /* first data block in filesystem */
+ int32_t total_blocks; /* total number of blocks in filesystem */
+ int32_t group_size; /* # of blocks a group consists of */
+ int32_t data_free; /* # of free data blocks */
+ int32_t inode_free; /* # of free inodes */
+ short inode_blocks; /* # of blocks used for inodes in every grp */
+ short total_groups; /* # of groups */
+};
+
+#endif /* __EFS_FS_SB_H__ */
+
diff --git a/pfinet/linux-src/include/linux/efs_vh.h b/pfinet/linux-src/include/linux/efs_vh.h
new file mode 100644
index 00000000..b9d7e4dd
--- /dev/null
+++ b/pfinet/linux-src/include/linux/efs_vh.h
@@ -0,0 +1,70 @@
+/*
+ * efs_vh.h
+ *
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from IRIX header files (c) 1985 MIPS Computer Systems, Inc.
+ */
+
+#ifndef __EFS_VH_H__
+#define __EFS_VH_H__
+
+#define VHMAGIC 0xbe5a941 /* volume header magic number */
+#define NPARTAB 16 /* 16 unix partitions */
+#define NVDIR 15 /* max of 15 directory entries */
+#define BFNAMESIZE 16 /* max 16 chars in boot file name */
+#define VDNAMESIZE 8
+
+struct volume_directory {
+ char vd_name[VDNAMESIZE]; /* name */
+ int vd_lbn; /* logical block number */
+ int vd_nbytes; /* file length in bytes */
+};
+
+struct partition_table { /* one per logical partition */
+ int pt_nblks; /* # of logical blks in partition */
+ int pt_firstlbn; /* first lbn of partition */
+ int pt_type; /* use of partition */
+};
+
+struct volume_header {
+ int vh_magic; /* identifies volume header */
+ short vh_rootpt; /* root partition number */
+ short vh_swappt; /* swap partition number */
+ char vh_bootfile[BFNAMESIZE]; /* name of file to boot */
+ char pad[48]; /* device param space */
+ struct volume_directory vh_vd[NVDIR]; /* other vol hdr contents */
+ struct partition_table vh_pt[NPARTAB]; /* device partition layout */
+ int vh_csum; /* volume header checksum */
+ int vh_fill; /* fill out to 512 bytes */
+};
+
+/* partition type sysv is used for EFS format CD-ROM partitions */
+#define SGI_SYSV 0x05
+#define SGI_EFS 0x07
+#define IS_EFS(x) (((x) == SGI_EFS) || ((x) == SGI_SYSV))
+
+struct pt_types {
+ int pt_type;
+ char *pt_name;
+} sgi_pt_types[] = {
+ {0x00, "SGI vh"},
+ {0x01, "SGI trkrepl"},
+ {0x02, "SGI secrepl"},
+ {0x03, "SGI raw"},
+ {0x04, "SGI bsd"},
+ {SGI_SYSV, "SGI sysv"},
+ {0x06, "SGI vol"},
+ {SGI_EFS, "SGI efs"},
+ {0x08, "SGI lv"},
+ {0x09, "SGI rlv"},
+ {0x0A, "SGI xfs"},
+ {0x0B, "SGI xfslog"},
+ {0x0C, "SGI xlv"},
+ {0x82, "Linux swap"},
+ {0x83, "Linux native"},
+ {0, NULL}
+};
+
+#endif /* __EFS_VH_H__ */
+
diff --git a/pfinet/linux-src/include/linux/elf.h b/pfinet/linux-src/include/linux/elf.h
new file mode 100644
index 00000000..f1b9c912
--- /dev/null
+++ b/pfinet/linux-src/include/linux/elf.h
@@ -0,0 +1,601 @@
+#ifndef _LINUX_ELF_H
+#define _LINUX_ELF_H
+
+#include <linux/types.h>
+#include <asm/elf.h>
+
+/* 32-bit ELF base types. */
+typedef __u32 Elf32_Addr;
+typedef __u16 Elf32_Half;
+typedef __u32 Elf32_Off;
+typedef __s32 Elf32_Sword;
+typedef __u32 Elf32_Word;
+
+/* 64-bit ELF base types. */
+typedef __u64 Elf64_Addr;
+typedef __u16 Elf64_Half;
+typedef __s16 Elf64_SHalf;
+typedef __u64 Elf64_Off;
+typedef __s64 Elf64_Sword;
+typedef __u64 Elf64_Word;
+
+/* These constants are for the segment types stored in the image headers */
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+#define PT_MIPS_REGINFO 0x70000000
+
+/* Flags in the e_flags field of the header */
+#define EF_MIPS_NOREORDER 0x00000001
+#define EF_MIPS_PIC 0x00000002
+#define EF_MIPS_CPIC 0x00000004
+#define EF_MIPS_ARCH 0xf0000000
+
+/* These constants define the different elf file types */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* These constants define the various ELF target machines */
+#define EM_NONE 0
+#define EM_M32 1
+#define EM_SPARC 2
+#define EM_386 3
+#define EM_68K 4
+#define EM_88K 5
+#define EM_486 6 /* Perhaps disused */
+#define EM_860 7
+
+#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
+
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
+
+#define EM_PARISC 15 /* HPPA */
+
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+
+#define EM_PPC 20 /* PowerPC */
+
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+
+/*
+ * This is an interim value that we will use until the committee comes
+ * up with a final number.
+ */
+#define EM_ALPHA 0x9026
+
+/*
+ * This is an interim value for S390 architecture
+ */
+#define EM_S390 0xA390
+
+/* This is the info that is needed to parse the dynamic section of the file */
+#define DT_NULL 0
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_RELASZ 8
+#define DT_RELAENT 9
+#define DT_STRSZ 10
+#define DT_SYMENT 11
+#define DT_INIT 12
+#define DT_FINI 13
+#define DT_SONAME 14
+#define DT_RPATH 15
+#define DT_SYMBOLIC 16
+#define DT_REL 17
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_DEBUG 21
+#define DT_TEXTREL 22
+#define DT_JMPREL 23
+#define DT_LOPROC 0x70000000
+#define DT_HIPROC 0x7fffffff
+#define DT_MIPS_RLD_VERSION 0x70000001
+#define DT_MIPS_TIME_STAMP 0x70000002
+#define DT_MIPS_ICHECKSUM 0x70000003
+#define DT_MIPS_IVERSION 0x70000004
+#define DT_MIPS_FLAGS 0x70000005
+ #define RHF_NONE 0
+ #define RHF_HARDWAY 1
+ #define RHF_NOTPOT 2
+#define DT_MIPS_BASE_ADDRESS 0x70000006
+#define DT_MIPS_CONFLICT 0x70000008
+#define DT_MIPS_LIBLIST 0x70000009
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a
+#define DT_MIPS_CONFLICTNO 0x7000000b
+#define DT_MIPS_LIBLISTNO 0x70000010
+#define DT_MIPS_SYMTABNO 0x70000011
+#define DT_MIPS_UNREFEXTNO 0x70000012
+#define DT_MIPS_GOTSYM 0x70000013
+#define DT_MIPS_HIPAGENO 0x70000014
+#define DT_MIPS_RLD_MAP 0x70000016
+
+/* This info is needed when parsing the symbol table */
+#define STB_LOCAL 0
+#define STB_GLOBAL 1
+#define STB_WEAK 2
+
+#define STT_NOTYPE 0
+#define STT_OBJECT 1
+#define STT_FUNC 2
+#define STT_SECTION 3
+#define STT_FILE 4
+
+#define ELF32_ST_BIND(x) ((x) >> 4)
+#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
+
+/* Symbolic values for the entries in the auxiliary table
+ put on the initial stack */
+#define AT_NULL 0 /* end of vector */
+#define AT_IGNORE 1 /* entry should be ignored */
+#define AT_EXECFD 2 /* file descriptor of program */
+#define AT_PHDR 3 /* program headers for program */
+#define AT_PHENT 4 /* size of program header entry */
+#define AT_PHNUM 5 /* number of program headers */
+#define AT_PAGESZ 6 /* system page size */
+#define AT_BASE 7 /* base address of interpreter */
+#define AT_FLAGS 8 /* flags */
+#define AT_ENTRY 9 /* entry point of program */
+#define AT_NOTELF 10 /* program is not ELF */
+#define AT_UID 11 /* real uid */
+#define AT_EUID 12 /* effective uid */
+#define AT_GID 13 /* real gid */
+#define AT_EGID 14 /* effective gid */
+#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
+#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
+
+typedef struct dynamic{
+ Elf32_Sword d_tag;
+ union{
+ Elf32_Sword d_val;
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+ Elf64_Word d_tag; /* entry tag value */
+ union {
+ Elf64_Word d_val;
+ Elf64_Word d_ptr;
+ } d_un;
+} Elf64_Dyn;
+
+/* The following are used with relocations */
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x) ((x) & 0xff)
+
+#define R_386_NONE 0
+#define R_386_32 1
+#define R_386_PC32 2
+#define R_386_GOT32 3
+#define R_386_PLT32 4
+#define R_386_COPY 5
+#define R_386_GLOB_DAT 6
+#define R_386_JMP_SLOT 7
+#define R_386_RELATIVE 8
+#define R_386_GOTOFF 9
+#define R_386_GOTPC 10
+#define R_386_NUM 11
+
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+/* The remaining relocs are defined on Irix, although they are not
+ in the MIPS ELF ABI. */
+#define R_MIPS_UNUSED1 13
+#define R_MIPS_UNUSED2 14
+#define R_MIPS_UNUSED3 15
+#define R_MIPS_SHIFT5 16
+#define R_MIPS_SHIFT6 17
+#define R_MIPS_64 18
+#define R_MIPS_GOT_DISP 19
+#define R_MIPS_GOT_PAGE 20
+#define R_MIPS_GOT_OFST 21
+/*
+ * The following two relocation types are specified in the the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_GOTHI16 22
+#define R_MIPS_GOTLO16 23
+#define R_MIPS_SUB 24
+#define R_MIPS_INSERT_A 25
+#define R_MIPS_INSERT_B 26
+#define R_MIPS_DELETE 27
+#define R_MIPS_HIGHER 28
+#define R_MIPS_HIGHEST 29
+/*
+ * The following two relocation types are specified in the the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_CALLHI16 30
+#define R_MIPS_CALLLO16 31
+/*
+ * This range is reserved for vendor specific relocations.
+ */
+#define R_MIPS_LOVENDOR 100
+#define R_MIPS_HIVENDOR 127
+
+
+/*
+ * Sparc ELF relocation types
+ */
+#define R_SPARC_NONE 0
+#define R_SPARC_8 1
+#define R_SPARC_16 2
+#define R_SPARC_32 3
+#define R_SPARC_DISP8 4
+#define R_SPARC_DISP16 5
+#define R_SPARC_DISP32 6
+#define R_SPARC_WDISP30 7
+#define R_SPARC_WDISP22 8
+#define R_SPARC_HI22 9
+#define R_SPARC_22 10
+#define R_SPARC_13 11
+#define R_SPARC_LO10 12
+#define R_SPARC_GOT10 13
+#define R_SPARC_GOT13 14
+#define R_SPARC_GOT22 15
+#define R_SPARC_PC10 16
+#define R_SPARC_PC22 17
+#define R_SPARC_WPLT30 18
+#define R_SPARC_COPY 19
+#define R_SPARC_GLOB_DAT 20
+#define R_SPARC_JMP_SLOT 21
+#define R_SPARC_RELATIVE 22
+#define R_SPARC_UA32 23
+#define R_SPARC_PLT32 24
+#define R_SPARC_HIPLT22 25
+#define R_SPARC_LOPLT10 26
+#define R_SPARC_PCPLT32 27
+#define R_SPARC_PCPLT22 28
+#define R_SPARC_PCPLT10 29
+#define R_SPARC_10 30
+#define R_SPARC_11 31
+#define R_SPARC_WDISP16 40
+#define R_SPARC_WDISP19 41
+#define R_SPARC_7 43
+#define R_SPARC_5 44
+#define R_SPARC_6 45
+
+/* Bits present in AT_HWCAP, primarily for Sparc32. */
+
+#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
+#define HWCAP_SPARC_STBAR 2
+#define HWCAP_SPARC_SWAP 4
+#define HWCAP_SPARC_MULDIV 8
+#define HWCAP_SPARC_V9 16
+
+
+/*
+ * 68k ELF relocation types
+ */
+#define R_68K_NONE 0
+#define R_68K_32 1
+#define R_68K_16 2
+#define R_68K_8 3
+#define R_68K_PC32 4
+#define R_68K_PC16 5
+#define R_68K_PC8 6
+#define R_68K_GOT32 7
+#define R_68K_GOT16 8
+#define R_68K_GOT8 9
+#define R_68K_GOT32O 10
+#define R_68K_GOT16O 11
+#define R_68K_GOT8O 12
+#define R_68K_PLT32 13
+#define R_68K_PLT16 14
+#define R_68K_PLT8 15
+#define R_68K_PLT32O 16
+#define R_68K_PLT16O 17
+#define R_68K_PLT8O 18
+#define R_68K_COPY 19
+#define R_68K_GLOB_DAT 20
+#define R_68K_JMP_SLOT 21
+#define R_68K_RELATIVE 22
+
+/*
+ * Alpha ELF relocation types
+ */
+#define R_ALPHA_NONE 0 /* No reloc */
+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
+#define R_ALPHA_OP_PUSH 12 /* OP stack push */
+#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */
+#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */
+#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */
+#define R_ALPHA_GPVALUE 16
+#define R_ALPHA_GPRELHIGH 17
+#define R_ALPHA_GPRELLOW 18
+#define R_ALPHA_IMMED_GP_16 19
+#define R_ALPHA_IMMED_GP_HI32 20
+#define R_ALPHA_IMMED_SCN_HI32 21
+#define R_ALPHA_IMMED_BR_HI32 22
+#define R_ALPHA_IMMED_LO32 23
+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
+
+/* Legal values for e_flags field of Elf64_Ehdr. */
+
+#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */
+
+
+typedef struct elf32_rel {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct elf64_rel {
+ Elf64_Addr r_offset; /* Location at which to apply the action */
+ Elf64_Word r_info; /* index and type of relocation */
+} Elf64_Rel;
+
+typedef struct elf32_rela{
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+typedef struct elf64_rela {
+ Elf64_Addr r_offset; /* Location at which to apply the action */
+ Elf64_Word r_info; /* index and type of relocation */
+ Elf64_Word r_addend; /* Constant addend used to compute value */
+} Elf64_Rela;
+
+typedef struct elf32_sym{
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+typedef struct elf64_sym {
+ Elf32_Word st_name; /* Symbol name, index in string tbl (yes, Elf32) */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* No defined meaning, 0 */
+ Elf64_Half st_shndx; /* Associated section index */
+ Elf64_Addr st_value; /* Value of the symbol */
+ Elf64_Word st_size; /* Associated symbol size */
+} Elf64_Sym;
+
+
+#define EI_NIDENT 16
+
+typedef struct elf32_hdr{
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct elf64_hdr {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ Elf64_SHalf e_type;
+ Elf64_Half e_machine;
+ __s32 e_version;
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ __s32 e_flags;
+ Elf64_SHalf e_ehsize;
+ Elf64_SHalf e_phentsize;
+ Elf64_SHalf e_phnum;
+ Elf64_SHalf e_shentsize;
+ Elf64_SHalf e_shnum;
+ Elf64_SHalf e_shstrndx;
+} Elf64_Ehdr;
+
+/* These constants define the permissions on sections in the program
+ header, p_flags. */
+#define PF_R 0x4
+#define PF_W 0x2
+#define PF_X 0x1
+
+typedef struct elf32_phdr{
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct elf64_phdr {
+ __s32 p_type;
+ __s32 p_flags;
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Word p_filesz; /* Segment size in file */
+ Elf64_Word p_memsz; /* Segment size in memory */
+ Elf64_Word p_align; /* Segment alignment, file & memory */
+} Elf64_Phdr;
+
+/* sh_type */
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#define SHT_NUM 12
+#define SHT_LOPROC 0x70000000
+#define SHT_HIPROC 0x7fffffff
+#define SHT_LOUSER 0x80000000
+#define SHT_HIUSER 0xffffffff
+#define SHT_MIPS_LIST 0x70000000
+#define SHT_MIPS_CONFLICT 0x70000002
+#define SHT_MIPS_GPTAB 0x70000003
+#define SHT_MIPS_UCODE 0x70000004
+
+/* sh_flags */
+#define SHF_WRITE 0x1
+#define SHF_ALLOC 0x2
+#define SHF_EXECINSTR 0x4
+#define SHF_MASKPROC 0xf0000000
+#define SHF_MIPS_GPREL 0x10000000
+
+/* special section indexes */
+#define SHN_UNDEF 0
+#define SHN_LORESERVE 0xff00
+#define SHN_LOPROC 0xff00
+#define SHN_HIPROC 0xff1f
+#define SHN_ABS 0xfff1
+#define SHN_COMMON 0xfff2
+#define SHN_HIRESERVE 0xffff
+#define SHN_MIPS_ACCOMON 0xff00
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct elf64_shdr {
+ Elf32_Word sh_name; /* Section name, index in string tbl (yes Elf32) */
+ Elf32_Word sh_type; /* Type of section (yes Elf32) */
+ Elf64_Word sh_flags; /* Miscellaneous section attributes */
+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
+ Elf64_Off sh_offset; /* Section file offset */
+ Elf64_Word sh_size; /* Size of section in bytes */
+ Elf32_Word sh_link; /* Index of another section (yes Elf32) */
+ Elf32_Word sh_info; /* Additional section information (yes Elf32) */
+ Elf64_Word sh_addralign; /* Section alignment */
+ Elf64_Word sh_entsize; /* Entry size if section holds table */
+} Elf64_Shdr;
+
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_PAD 7
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define ELFCLASSNONE 0 /* EI_CLASS */
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFCLASSNUM 3
+
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_NONE 0 /* e_version, EI_VERSION */
+#define EV_CURRENT 1
+#define EV_NUM 2
+
+/* Notes used in ET_CORE */
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+#define NT_TASKSTRUCT 4
+
+/* Note header in a PT_NOTE section */
+typedef struct elf32_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf32_Nhdr;
+
+/* Note header in a PT_NOTE section */
+/*
+ * For now we use the 32 bit version of the structure until we figure
+ * out whether we need anything better. Note - on the Alpha, "unsigned int"
+ * is only 32 bits.
+ */
+typedef struct elf64_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf64_Nhdr;
+
+#if ELF_CLASS == ELFCLASS32
+
+extern Elf32_Dyn _DYNAMIC [];
+#define elfhdr elf32_hdr
+#define elf_phdr elf32_phdr
+#define elf_note elf32_note
+
+#else
+
+extern Elf64_Dyn _DYNAMIC [];
+#define elfhdr elf64_hdr
+#define elf_phdr elf64_phdr
+#define elf_note elf64_note
+
+#endif
+
+
+#endif /* _LINUX_ELF_H */
diff --git a/pfinet/linux-src/include/linux/elfcore.h b/pfinet/linux-src/include/linux/elfcore.h
new file mode 100644
index 00000000..5c1cb05b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/elfcore.h
@@ -0,0 +1,88 @@
+#ifndef _LINUX_ELFCORE_H
+#define _LINUX_ELFCORE_H
+
+#include <linux/types.h>
+#include <linux/signal.h>
+#include <linux/time.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+struct elf_siginfo
+{
+ int si_signo; /* signal number */
+ int si_code; /* extra code */
+ int si_errno; /* errno */
+};
+
+#include <asm/elf.h>
+
+#ifndef __KERNEL__
+typedef elf_greg_t greg_t;
+typedef elf_gregset_t gregset_t;
+typedef elf_fpregset_t fpregset_t;
+#define NGREG ELF_NGREG
+#endif
+
+/*
+ * Definitions to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided. This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ * Fields present but not used are marked with "XXX".
+ */
+struct elf_prstatus
+{
+#if 0
+ long pr_flags; /* XXX Process flags */
+ short pr_why; /* XXX Reason for process halt */
+ short pr_what; /* XXX More detailed reason */
+#endif
+ struct elf_siginfo pr_info; /* Info associated with signal */
+ short pr_cursig; /* Current signal */
+ unsigned long pr_sigpend; /* Set of pending signals */
+ unsigned long pr_sighold; /* Set of held signals */
+#if 0
+ struct sigaltstack pr_altstack; /* Alternate stack info */
+ struct sigaction pr_action; /* Signal action for current sig */
+#endif
+ pid_t pr_pid;
+ pid_t pr_ppid;
+ pid_t pr_pgrp;
+ pid_t pr_sid;
+ struct timeval pr_utime; /* User time */
+ struct timeval pr_stime; /* System time */
+ struct timeval pr_cutime; /* Cumulative user time */
+ struct timeval pr_cstime; /* Cumulative system time */
+#if 0
+ long pr_instr; /* Current instruction */
+#endif
+ elf_gregset_t pr_reg; /* GP registers */
+ int pr_fpvalid; /* True if math co-processor being used. */
+};
+
+#define ELF_PRARGSZ (80) /* Number of chars for args */
+
+struct elf_prpsinfo
+{
+ char pr_state; /* numeric process state */
+ char pr_sname; /* char for pr_state */
+ char pr_zomb; /* zombie */
+ char pr_nice; /* nice val */
+ unsigned long pr_flag; /* flags */
+ uid_t pr_uid;
+ gid_t pr_gid;
+ pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ /* Lots missing */
+ char pr_fname[16]; /* filename of executable */
+ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#ifndef __KERNEL__
+typedef struct elf_prstatus prstatus_t;
+typedef struct elf_prpsinfo prpsinfo_t;
+#define PRARGSZ ELF_PRARGSZ
+#endif
+
+#endif /* _LINUX_ELFCORE_H */
diff --git a/pfinet/linux-src/include/linux/epca.h b/pfinet/linux-src/include/linux/epca.h
new file mode 100644
index 00000000..50494814
--- /dev/null
+++ b/pfinet/linux-src/include/linux/epca.h
@@ -0,0 +1,170 @@
+#define XEMPORTS 0xC02
+#define XEPORTS 0xC22
+
+#define MAX_ALLOC 0x100
+
+#define MAXBOARDS 12
+#define FEPCODESEG 0x0200L
+#define FEPCODE 0x2000L
+#define BIOSCODE 0xf800L
+
+#define MISCGLOBAL 0x0C00L
+#define NPORT 0x0C22L
+#define MBOX 0x0C40L
+#define PORTBASE 0x0C90L
+
+/* Begin code defines used for epca_setup */
+
+#define INVALID_BOARD_TYPE 0x1
+#define INVALID_NUM_PORTS 0x2
+#define INVALID_MEM_BASE 0x4
+#define INVALID_PORT_BASE 0x8
+#define INVALID_BOARD_STATUS 0x10
+#define INVALID_ALTPIN 0x20
+
+/* End code defines used for epca_setup */
+
+
+#define FEPCLR 0x00
+#define FEPMEM 0x02
+#define FEPRST 0x04
+#define FEPINT 0x08
+#define FEPMASK 0x0e
+#define FEPWIN 0x80
+
+#define PCXE 0
+#define PCXEVE 1
+#define PCXEM 2
+#define EISAXEM 3
+#define PC64XE 4
+#define PCXI 5
+#define PCIXEM 7
+#define PCICX 8
+#define PCIXR 9
+#define PCIXRJ 10
+#define EPCA_NUM_TYPES 6
+
+
+static char *board_desc[] =
+{
+ "PC/Xe",
+ "PC/Xeve",
+ "PC/Xem",
+ "EISA/Xem",
+ "PC/64Xe",
+ "PC/Xi",
+ "unknown",
+ "PCI/Xem",
+ "PCI/CX",
+ "PCI/Xr",
+ "PCI/Xrj",
+};
+
+#define STARTC 021
+#define STOPC 023
+#define IAIXON 0x2000
+
+
+#define TXSTOPPED 0x1
+#define LOWWAIT 0x2
+#define EMPTYWAIT 0x4
+#define RXSTOPPED 0x8
+#define TXBUSY 0x10
+
+#define DISABLED 0
+#define ENABLED 1
+#define OFF 0
+#define ON 1
+
+#define FEPTIMEOUT 200000
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#define SERIAL_TYPE_INFO 3
+#define EPCA_EVENT_HANGUP 1
+#define EPCA_MAGIC 0x5c6df104L
+
+struct channel
+{
+ long magic;
+ unchar boardnum;
+ unchar channelnum;
+ unchar omodem; /* FEP output modem status */
+ unchar imodem; /* FEP input modem status */
+ unchar modemfake; /* Modem values to be forced */
+ unchar modem; /* Force values */
+ unchar hflow;
+ unchar dsr;
+ unchar dcd;
+ unchar m_rts ; /* The bits used in whatever FEP */
+ unchar m_dcd ; /* is indiginous to this board to */
+ unchar m_dsr ; /* represent each of the physical */
+ unchar m_cts ; /* handshake lines */
+ unchar m_ri ;
+ unchar m_dtr ;
+ unchar stopc;
+ unchar startc;
+ unchar stopca;
+ unchar startca;
+ unchar fepstopc;
+ unchar fepstartc;
+ unchar fepstopca;
+ unchar fepstartca;
+ unchar txwin;
+ unchar rxwin;
+ ushort fepiflag;
+ ushort fepcflag;
+ ushort fepoflag;
+ ushort txbufhead;
+ ushort txbufsize;
+ ushort rxbufhead;
+ ushort rxbufsize;
+ int close_delay;
+ int count;
+ int blocked_open;
+ int event;
+ int asyncflags;
+ uint dev;
+ long session;
+ long pgrp;
+ ulong statusflags;
+ ulong c_iflag;
+ ulong c_cflag;
+ ulong c_lflag;
+ ulong c_oflag;
+ unchar *txptr;
+ unchar *rxptr;
+ unchar *tmp_buf;
+ struct board_info *board;
+ volatile struct board_chan *brdchan;
+ struct digi_struct digiext;
+ struct tty_struct *tty;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct tq_struct tqueue;
+ volatile struct global_data *mailbox;
+};
+
+struct board_info
+{
+ unchar status;
+ unchar type;
+ unchar altpin;
+ ushort numports;
+ unchar *port;
+ unchar *membase;
+ unchar *re_map_port;
+ unchar *re_map_membase;
+ ulong memory_seg;
+ void ( * memwinon ) (struct board_info *, unsigned int) ;
+ void ( * memwinoff ) (struct board_info *, unsigned int) ;
+ void ( * globalwinon ) (struct channel *) ;
+ void ( * txwinon ) (struct channel *) ;
+ void ( * rxwinon ) (struct channel *) ;
+ void ( * memoff ) (struct channel *) ;
+ void ( * assertgwinon ) (struct channel *) ;
+ void ( * assertmemoff ) (struct channel *) ;
+ unchar poller_inhibited ;
+};
+
diff --git a/pfinet/linux-src/include/linux/epcaconfig.h b/pfinet/linux-src/include/linux/epcaconfig.h
new file mode 100644
index 00000000..c840c673
--- /dev/null
+++ b/pfinet/linux-src/include/linux/epcaconfig.h
@@ -0,0 +1,8 @@
+#define NUMCARDS 1
+#define NBDEVS 2
+
+struct board_info static_boards[NUMCARDS]={
+ { ENABLED, 0, OFF, 2, (unchar*) 0x320, (unchar*) 0xd0000 },
+};
+
+/* DO NOT HAND EDIT THIS FILE! */
diff --git a/pfinet/linux-src/include/linux/errno.h b/pfinet/linux-src/include/linux/errno.h
new file mode 100644
index 00000000..ac212844
--- /dev/null
+++ b/pfinet/linux-src/include/linux/errno.h
@@ -0,0 +1,16 @@
+#ifndef _LINUX_ERRNO_H
+#define _LINUX_ERRNO_H
+
+#include <asm/errno.h>
+
+#ifdef __KERNEL__
+
+/* Should never be seen by user programs */
+#define ERESTARTSYS 512
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514 /* restart if no handler.. */
+#define ENOIOCTLCMD 515 /* No ioctl command */
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/errqueue.h b/pfinet/linux-src/include/linux/errqueue.h
new file mode 100644
index 00000000..48d79561
--- /dev/null
+++ b/pfinet/linux-src/include/linux/errqueue.h
@@ -0,0 +1,44 @@
+#ifndef _LINUX_ERRQUEUE_H
+#define _LINUX_ERRQUEUE_H 1
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#endif
+
+struct sock_extended_err
+{
+ __u32 ee_errno;
+ __u8 ee_origin;
+ __u8 ee_type;
+ __u8 ee_code;
+ __u8 ee_pad;
+ __u32 ee_info;
+ __u32 ee_data;
+};
+
+#define SO_EE_ORIGIN_NONE 0
+#define SO_EE_ORIGIN_LOCAL 1
+#define SO_EE_ORIGIN_ICMP 2
+#define SO_EE_ORIGIN_ICMP6 3
+
+#define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1))
+
+#ifdef __KERNEL__
+#define SKB_EXT_ERR(skb) ((struct sock_exterr_skb *) ((skb)->cb))
+
+struct sock_exterr_skb
+{
+ union {
+ struct inet_skb_parm h4;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ struct inet6_skb_parm h6;
+#endif
+ } header;
+ struct sock_extended_err ee;
+ u16 addr_offset;
+ u16 port;
+};
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/etherdevice.h b/pfinet/linux-src/include/linux/etherdevice.h
new file mode 100644
index 00000000..9101855c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/etherdevice.h
@@ -0,0 +1,56 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. NET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the Ethernet handlers.
+ *
+ * Version: @(#)eth.h 1.0.4 05/13/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * Relocated to include/linux where it belongs by Alan Cox
+ * <gw4pts@gw4pts.ampr.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * WARNING: This move may well be temporary. This file will get merged with others RSN.
+ *
+ */
+#ifndef _LINUX_ETHERDEVICE_H
+#define _LINUX_ETHERDEVICE_H
+
+#include <linux/config.h>
+#include <linux/if_ether.h>
+
+#ifdef __KERNEL__
+extern int eth_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len);
+extern int eth_rebuild_header(struct sk_buff *skb);
+extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev);
+extern void eth_header_cache_update(struct hh_cache *hh, struct device *dev,
+ unsigned char * haddr);
+extern int eth_header_cache(struct neighbour *neigh,
+ struct hh_cache *hh);
+extern int eth_header_parse(struct sk_buff *skb,
+ unsigned char *haddr);
+extern struct device * init_etherdev(struct device *, int);
+
+#ifdef CONFIG_IP_ROUTER
+static __inline__ void eth_copy_and_sum (struct sk_buff *dest, unsigned char *src, int len, int base)
+{
+ memcpy (dest->data, src, len);
+}
+#else
+extern void eth_copy_and_sum(struct sk_buff *dest,
+ unsigned char *src, int length, int base);
+#endif
+
+#endif
+
+#endif /* _LINUX_ETHERDEVICE_H */
diff --git a/pfinet/linux-src/include/linux/ext2_fs.h b/pfinet/linux-src/include/linux/ext2_fs.h
new file mode 100644
index 00000000..840e7cad
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ext2_fs.h
@@ -0,0 +1,624 @@
+/*
+ * linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_H
+#define _LINUX_EXT2_FS_H
+
+#include <linux/types.h>
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT2FS_DEBUG to produce debug messages
+ */
+#undef EXT2FS_DEBUG
+
+/*
+ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
+ */
+#define EXT2_PREALLOCATE
+#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
+
+/*
+ * The second extended file system version
+ */
+#define EXT2FS_DATE "95/08/09"
+#define EXT2FS_VERSION "0.5b"
+
+/*
+ * Debug code
+ */
+#ifdef EXT2FS_DEBUG
+# define ext2_debug(f, a...) { \
+ printk ("EXT2-fs DEBUG (%s, %d): %s:", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ printk (f, ## a); \
+ }
+#else
+# define ext2_debug(f, a...) /**/
+#endif
+
+/*
+ * Special inodes numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT2_ACL_IDX_INO 3 /* ACL inode */
+#define EXT2_ACL_DATA_INO 4 /* ACL inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO 11
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX 32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_SIZE 1024
+#define EXT2_MAX_BLOCK_SIZE 4096
+#define EXT2_MIN_BLOCK_LOG_SIZE 10
+#ifdef __KERNEL__
+# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
+#else
+# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#endif
+#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#ifdef __KERNEL__
+# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
+#else
+# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#endif
+#ifdef __KERNEL__
+#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits)
+#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size)
+#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino)
+#else
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_INODE_SIZE : \
+ (s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_FIRST_INO : \
+ (s)->s_first_ino)
+#endif
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT2_MIN_FRAG_SIZE 1024
+#define EXT2_MAX_FRAG_SIZE 4096
+#define EXT2_MIN_FRAG_LOG_SIZE 10
+#ifdef __KERNEL__
+# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block)
+#else
+# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
+#endif
+
+/*
+ * ACL structures
+ */
+struct ext2_acl_header /* Header of Access Control Lists */
+{
+ __u32 aclh_size;
+ __u32 aclh_file_count;
+ __u32 aclh_acle_count;
+ __u32 aclh_first_acle;
+};
+
+struct ext2_acl_entry /* Access Control List Entry */
+{
+ __u32 acle_size;
+ __u16 acle_perms; /* Access permissions */
+ __u16 acle_type; /* Type of entry */
+ __u16 acle_tag; /* User or group identity */
+ __u16 acle_pad1;
+ __u32 acle_next; /* Pointer on next entry for the */
+ /* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_pad;
+ __u32 bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#ifdef __KERNEL__
+# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group)
+# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block)
+# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group)
+# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits)
+#else
+# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
+# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
+#endif
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL 0x00000002 /* Undelete */
+#define EXT2_COMPR_FL 0x00000004 /* Compress file */
+#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL 0x00000100
+#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
+#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
+#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
+#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_reserved1;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_version; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u32 l_i_reserved2[2];
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+};
+
+#define i_size_high i_dir_acl
+
+#if defined(__KERNEL__) || defined(__linux__)
+#define i_reserved1 osd1.linux1.l_i_reserved1
+#define i_frag osd2.linux2.l_i_frag
+#define i_fsize osd2.linux2.l_i_fsize
+#define i_reserved2 osd2.linux2.l_i_reserved2
+#endif
+
+#ifdef __hurd__
+#define i_translator osd1.hurd1.h_i_translator
+#define i_frag osd2.hurd2.h_i_frag;
+#define i_fsize osd2.hurd2.h_i_fsize;
+#define i_uid_high osd2.hurd2.h_i_uid_high
+#define i_gid_high osd2.hurd2.h_i_gid_high
+#define i_author osd2.hurd2.h_i_author
+#endif
+
+#ifdef __masix__
+#define i_reserved1 osd1.masix1.m_i_reserved1
+#define i_frag osd2.masix2.m_i_frag
+#define i_fsize osd2.masix2.m_i_fsize
+#define i_reserved2 osd2.masix2.m_i_reserved2
+#endif
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT2_ERROR_FS 0x0002 /* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK_NORMAL 0x0001 /* Do some more checks */
+#define EXT2_MOUNT_CHECK_STRICT 0x0002 /* Do again more checks */
+#define EXT2_MOUNT_CHECK (EXT2_MOUNT_CHECK_NORMAL | \
+ EXT2_MOUNT_CHECK_STRICT)
+#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
+
+#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \
+ EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level; /* minor revision level */
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_padding1;
+ __u32 s_reserved[204]; /* Padding to the end of the block */
+};
+
+#ifdef __KERNEL__
+#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
+#else
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+#endif
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX 0
+#define EXT2_OS_HURD 1
+#define EXT2_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT2_DEF_RESUID 0
+#define EXT2_DEF_RESGID 0
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u16 name_len; /* Name length */
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+
+#ifdef __KERNEL__
+
+/* Filesize hard limits for 64-bit file offsets */
+extern long long ext2_max_sizes[];
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext2 source programs needs to include it so they are duplicated here.
+ */
+# define NORET_TYPE /**/
+# define ATTRIB_NORET __attribute__((noreturn))
+# define NORET_AND noreturn,
+
+/* acl.c */
+extern int ext2_permission (struct inode *, int);
+
+/* balloc.c */
+extern int ext2_group_sparse(int group);
+extern int ext2_new_block (const struct inode *, unsigned long,
+ __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (const struct inode *, unsigned long,
+ unsigned long);
+extern unsigned long ext2_count_free_blocks (struct super_block *);
+extern void ext2_check_blocks_bitmap (struct super_block *);
+extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh);
+
+/* bitmap.c */
+extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
+
+/* dir.c */
+extern int ext2_check_dir_entry (const char *, struct inode *,
+ struct ext2_dir_entry_2 *, struct buffer_head *,
+ unsigned long);
+
+/* file.c */
+extern int ext2_read (struct inode *, struct file *, char *, int);
+extern int ext2_write (struct inode *, struct file *, char *, int);
+
+/* fsync.c */
+extern int ext2_sync_file (struct file *, struct dentry *);
+
+/* ialloc.c */
+extern struct inode * ext2_new_inode (const struct inode *, int, int *);
+extern void ext2_free_inode (struct inode *);
+extern unsigned long ext2_count_free_inodes (struct super_block *);
+extern void ext2_check_inodes_bitmap (struct super_block *);
+
+/* inode.c */
+extern int ext2_bmap (struct inode *, int);
+
+extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
+extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
+
+extern int ext2_getcluster (struct inode * inode, long block);
+extern void ext2_read_inode (struct inode *);
+extern void ext2_write_inode (struct inode *);
+extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
+extern int ext2_sync_inode (struct inode *);
+extern int ext2_notify_change(struct dentry *, struct iattr *);
+extern void ext2_discard_prealloc (struct inode *);
+
+/* ioctl.c */
+extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+/* namei.c */
+extern void ext2_release (struct inode *, struct file *);
+extern struct dentry *ext2_lookup (struct inode *, struct dentry *);
+extern int ext2_create (struct inode *,struct dentry *,int);
+extern int ext2_mkdir (struct inode *,struct dentry *,int);
+extern int ext2_rmdir (struct inode *,struct dentry *);
+extern int ext2_unlink (struct inode *,struct dentry *);
+extern int ext2_symlink (struct inode *,struct dentry *,const char *);
+extern int ext2_link (struct dentry *, struct inode *, struct dentry *);
+extern int ext2_mknod (struct inode *, struct dentry *, int, int);
+extern int ext2_rename (struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
+
+/* super.c */
+extern void ext2_error (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
+ const char *, ...)
+ __attribute__ ((NORET_AND format (printf, 3, 4)));
+extern void ext2_warning (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern void ext2_put_super (struct super_block *);
+extern void ext2_write_super (struct super_block *);
+extern int ext2_remount (struct super_block *, int *, char *);
+extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int init_ext2_fs(void);
+extern int ext2_statfs (struct super_block *, struct statfs *, int);
+
+/* truncate.c */
+extern void ext2_truncate (struct inode *);
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern struct inode_operations ext2_dir_inode_operations;
+
+/* file.c */
+extern struct inode_operations ext2_file_inode_operations;
+
+/* symlink.c */
+extern struct inode_operations ext2_symlink_inode_operations;
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_EXT2_FS_H */
diff --git a/pfinet/linux-src/include/linux/ext2_fs_i.h b/pfinet/linux-src/include/linux/ext2_fs_i.h
new file mode 100644
index 00000000..8f01f8ad
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ext2_fs_i.h
@@ -0,0 +1,42 @@
+/*
+ * linux/include/linux/ext2_fs_i.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs_i.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_I
+#define _LINUX_EXT2_FS_I
+
+/*
+ * second extended file system inode data in memory
+ */
+struct ext2_inode_info {
+ __u32 i_data[15];
+ __u32 i_flags;
+ __u32 i_faddr;
+ __u8 i_frag_no;
+ __u8 i_frag_size;
+ __u16 i_osync;
+ __u32 i_file_acl;
+ __u32 i_dir_acl;
+ __u32 i_dtime;
+ __u32 i_version;
+ __u32 i_block_group;
+ __u32 i_next_alloc_block;
+ __u32 i_next_alloc_goal;
+ __u32 i_prealloc_block;
+ __u32 i_prealloc_count;
+ __u32 i_high_size;
+ int i_new_inode:1; /* Is a freshly allocated inode */
+};
+
+#endif /* _LINUX_EXT2_FS_I */
diff --git a/pfinet/linux-src/include/linux/ext2_fs_sb.h b/pfinet/linux-src/include/linux/ext2_fs_sb.h
new file mode 100644
index 00000000..20721632
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ext2_fs_sb.h
@@ -0,0 +1,66 @@
+/*
+ * linux/include/linux/ext2_fs_sb.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs_sb.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_SB
+#define _LINUX_EXT2_FS_SB
+
+#include <linux/ext2_fs.h>
+
+/*
+ * The following is not needed anymore since the descriptors buffer
+ * heads are now dynamically allocated
+ */
+/* #define EXT2_MAX_GROUP_DESC 8 */
+
+#define EXT2_MAX_GROUP_LOADED 8
+
+/*
+ * second extended-fs super-block data in memory
+ */
+struct ext2_sb_info {
+ unsigned long s_frag_size; /* Size of a fragment in bytes */
+ unsigned long s_frags_per_block;/* Number of fragments per block */
+ unsigned long s_inodes_per_block;/* Number of inodes per block */
+ unsigned long s_frags_per_group;/* Number of fragments in a group */
+ unsigned long s_blocks_per_group;/* Number of blocks in a group */
+ unsigned long s_inodes_per_group;/* Number of inodes in a group */
+ unsigned long s_itb_per_group; /* Number of inode table blocks per group */
+ unsigned long s_db_per_group; /* Number of descriptor blocks per group */
+ unsigned long s_desc_per_block; /* Number of group descriptors per block */
+ unsigned long s_groups_count; /* Number of groups in the fs */
+ struct buffer_head * s_sbh; /* Buffer containing the super block */
+ struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */
+ struct buffer_head ** s_group_desc;
+ unsigned short s_loaded_inode_bitmaps;
+ unsigned short s_loaded_block_bitmaps;
+ unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED];
+ struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED];
+ unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
+ struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
+ unsigned long s_mount_opt;
+ unsigned short s_resuid;
+ unsigned short s_resgid;
+ unsigned short s_mount_state;
+ unsigned short s_pad;
+ int s_addr_per_block_bits;
+ int s_desc_per_block_bits;
+ int s_inode_size;
+ int s_first_ino;
+ int s_feature_compat;
+ int s_feature_incompat;
+ int s_feature_ro_compat;
+};
+
+#endif /* _LINUX_EXT2_FS_SB */
diff --git a/pfinet/linux-src/include/linux/fat_cvf.h b/pfinet/linux-src/include/linux/fat_cvf.h
new file mode 100644
index 00000000..1c4df58f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fat_cvf.h
@@ -0,0 +1,49 @@
+#ifndef _FAT_CVF
+#define _FAT_CVF
+
+#define CVF_USE_READPAGE 0x0001
+
+struct cvf_format
+{ int cvf_version;
+ char* cvf_version_text;
+ unsigned long flags;
+ int (*detect_cvf) (struct super_block*sb);
+ int (*mount_cvf) (struct super_block*sb,char*options);
+ int (*unmount_cvf) (struct super_block*sb);
+ struct buffer_head* (*cvf_bread) (struct super_block*sb,int block);
+ struct buffer_head* (*cvf_getblk) (struct super_block*sb,int block);
+ void (*cvf_brelse) (struct super_block *sb,struct buffer_head *bh);
+ void (*cvf_mark_buffer_dirty) (struct super_block *sb,
+ struct buffer_head *bh,
+ int dirty_val);
+ void (*cvf_set_uptodate) (struct super_block *sb,
+ struct buffer_head *bh,
+ int val);
+ int (*cvf_is_uptodate) (struct super_block *sb,struct buffer_head *bh);
+ void (*cvf_ll_rw_block) (struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32]);
+ int (*fat_access) (struct super_block *sb,int nr,int new_value);
+ int (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz);
+ int (*cvf_bmap) (struct inode *inode,int block);
+ int (*cvf_smap) (struct inode *inode,int sector);
+ ssize_t (*cvf_file_read) ( struct file *, char *, size_t, loff_t *);
+ ssize_t (*cvf_file_write) ( struct file *, const char *, size_t, loff_t *);
+ int (*cvf_mmap) (struct file *, struct vm_area_struct *);
+ int (*cvf_readpage) (struct inode *, struct page *);
+ int (*cvf_writepage) (struct inode *, struct page *);
+ int (*cvf_dir_ioctl) (struct inode * inode, struct file * filp,
+ unsigned int cmd, unsigned long arg);
+ void (*zero_out_cluster) (struct inode*, int clusternr);
+};
+
+int register_cvf_format(struct cvf_format*cvf_format);
+int unregister_cvf_format(struct cvf_format*cvf_format);
+void dec_cvf_format_use_count_by_version(int version);
+int detect_cvf(struct super_block*sb,char*force);
+
+extern struct cvf_format *cvf_formats[];
+extern int cvf_format_use_count[];
+
+#endif
diff --git a/pfinet/linux-src/include/linux/fb.h b/pfinet/linux-src/include/linux/fb.h
new file mode 100644
index 00000000..4170e030
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fb.h
@@ -0,0 +1,494 @@
+#ifndef _LINUX_FB_H
+#define _LINUX_FB_H
+
+#include <asm/types.h>
+
+/* Definitions of frame buffers */
+
+#define FB_MAJOR 29
+
+#define FB_MODES_SHIFT 5 /* 32 modes per framebuffer */
+#define FB_NUM_MINORS 256 /* 256 Minors */
+#define FB_MAX (FB_NUM_MINORS / (1 << FB_MODES_SHIFT))
+#define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT)
+
+/* ioctls
+ 0x46 is 'F' */
+#define FBIOGET_VSCREENINFO 0x4600
+#define FBIOPUT_VSCREENINFO 0x4601
+#define FBIOGET_FSCREENINFO 0x4602
+#define FBIOGETCMAP 0x4604
+#define FBIOPUTCMAP 0x4605
+#define FBIOPAN_DISPLAY 0x4606
+/* 0x4607-0x460B are defined below */
+/* #define FBIOGET_MONITORSPEC 0x460C */
+/* #define FBIOPUT_MONITORSPEC 0x460D */
+/* #define FBIOSWITCH_MONIBIT 0x460E */
+#define FBIOGET_CON2FBMAP 0x460F
+#define FBIOPUT_CON2FBMAP 0x4610
+#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */
+
+#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
+#define FB_TYPE_PLANES 1 /* Non interleaved planes */
+#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */
+#define FB_TYPE_TEXT 3 /* Text/attributes */
+#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */
+
+#define FB_AUX_TEXT_MDA 0 /* Monochrome text */
+#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */
+#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */
+#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */
+#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */
+
+#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */
+#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */
+#define FB_VISUAL_TRUECOLOR 2 /* True color */
+#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */
+#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */
+#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */
+
+#define FB_ACCEL_NONE 0 /* no hardware accelerator */
+#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */
+#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */
+#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */
+#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */
+#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */
+#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */
+#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */
+#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */
+#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */
+#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */
+#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */
+#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */
+#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */
+#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */
+#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */
+#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */
+#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */
+#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */
+#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */
+#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */
+#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */
+#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */
+#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */
+#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */
+#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */
+
+struct fb_fix_screeninfo {
+ char id[16]; /* identification string eg "TT Builtin" */
+ char *smem_start; /* Start of frame buffer mem */
+ /* (physical address) */
+ __u32 smem_len; /* Length of frame buffer mem */
+ __u32 type; /* see FB_TYPE_* */
+ __u32 type_aux; /* Interleave for interleaved Planes */
+ __u32 visual; /* see FB_VISUAL_* */
+ __u16 xpanstep; /* zero if no hardware panning */
+ __u16 ypanstep; /* zero if no hardware panning */
+ __u16 ywrapstep; /* zero if no hardware ywrap */
+ __u32 line_length; /* length of a line in bytes */
+ char *mmio_start; /* Start of Memory Mapped I/O */
+ /* (physical address) */
+ __u32 mmio_len; /* Length of Memory Mapped I/O */
+ __u32 accel; /* Type of acceleration available */
+ __u16 reserved[3]; /* Reserved for future compatibility */
+};
+
+/* Interpretation of offset for color fields: All offsets are from the right,
+ * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
+ * can use the offset as right argument to <<). A pixel afterwards is a bit
+ * stream and is written to video memory as that unmodified. This implies
+ * big-endian byte order if bits_per_pixel is greater than 8.
+ */
+struct fb_bitfield {
+ __u32 offset; /* beginning of bitfield */
+ __u32 length; /* length of bitfield */
+ __u32 msb_right; /* != 0 : Most significant bit is */
+ /* right */
+};
+
+#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */
+
+#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/
+#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */
+#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */
+#define FB_ACTIVATE_MASK 15
+ /* values */
+#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */
+#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */
+#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */
+
+#define FB_ACCELF_TEXT 1 /* text mode acceleration */
+
+#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */
+#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */
+#define FB_SYNC_EXT 4 /* external sync */
+#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */
+#define FB_SYNC_BROADCAST 16 /* broadcast video timings */
+ /* vtotal = 144d/288n/576i => PAL */
+ /* vtotal = 121d/242n/484i => NTSC */
+#define FB_SYNC_ON_GREEN 32 /* sync on green */
+
+#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
+#define FB_VMODE_INTERLACED 1 /* interlaced */
+#define FB_VMODE_DOUBLE 2 /* double scan */
+#define FB_VMODE_MASK 255
+
+#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
+#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
+#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */
+
+struct fb_var_screeninfo {
+ __u32 xres; /* visible resolution */
+ __u32 yres;
+ __u32 xres_virtual; /* virtual resolution */
+ __u32 yres_virtual;
+ __u32 xoffset; /* offset from virtual to visible */
+ __u32 yoffset; /* resolution */
+
+ __u32 bits_per_pixel; /* guess what */
+ __u32 grayscale; /* != 0 Graylevels instead of colors */
+
+ struct fb_bitfield red; /* bitfield in fb mem if true color, */
+ struct fb_bitfield green; /* else only length is significant */
+ struct fb_bitfield blue;
+ struct fb_bitfield transp; /* transparency */
+
+ __u32 nonstd; /* != 0 Non standard pixel format */
+
+ __u32 activate; /* see FB_ACTIVATE_* */
+
+ __u32 height; /* height of picture in mm */
+ __u32 width; /* width of picture in mm */
+
+ __u32 accel_flags; /* acceleration flags (hints) */
+
+ /* Timing: All values in pixclocks, except pixclock (of course) */
+ __u32 pixclock; /* pixel clock in ps (pico seconds) */
+ __u32 left_margin; /* time from sync to picture */
+ __u32 right_margin; /* time from picture to sync */
+ __u32 upper_margin; /* time from sync to picture */
+ __u32 lower_margin;
+ __u32 hsync_len; /* length of horizontal sync */
+ __u32 vsync_len; /* length of vertical sync */
+ __u32 sync; /* see FB_SYNC_* */
+ __u32 vmode; /* see FB_VMODE_* */
+ __u32 reserved[6]; /* Reserved for future compatibility */
+};
+
+struct fb_cmap {
+ __u32 start; /* First entry */
+ __u32 len; /* Number of entries */
+ __u16 *red; /* Red values */
+ __u16 *green;
+ __u16 *blue;
+ __u16 *transp; /* transparency, can be NULL */
+};
+
+struct fb_con2fbmap {
+ __u32 console;
+ __u32 framebuffer;
+};
+
+struct fb_monspecs {
+ __u32 hfmin; /* hfreq lower limit (Hz) */
+ __u32 hfmax; /* hfreq upper limit (Hz) */
+ __u16 vfmin; /* vfreq lower limit (Hz) */
+ __u16 vfmax; /* vfreq upper limit (Hz) */
+ unsigned dpms : 1; /* supports DPMS */
+};
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+
+
+struct fb_info;
+struct fb_info_gen;
+struct vm_area_struct;
+struct file;
+
+ /*
+ * Frame buffer operations
+ */
+
+struct fb_ops {
+ /* open/release and usage marking */
+ int (*fb_open)(struct fb_info *info, int user);
+ int (*fb_release)(struct fb_info *info, int user);
+ /* get non settable parameters */
+ int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+ /* get settable parameters */
+ int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+ /* set settable parameters */
+ int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+ /* get colormap */
+ int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+ /* set colormap */
+ int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+ /* pan display */
+ int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+ /* perform fb specific ioctl */
+ int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg, int con, struct fb_info *info);
+ /* perform fb specific mmap */
+ int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
+ /* switch to/from raster image mode */
+ int (*fb_rasterimg)(struct fb_info *info, int start);
+};
+
+
+ /*
+ * This is the interface between the low-level console driver and the
+ * low-level frame buffer device
+ */
+
+struct display {
+ /* Filled in by the frame buffer device */
+
+ struct fb_var_screeninfo var; /* variable infos. yoffset and vmode */
+ /* are updated by fbcon.c */
+ struct fb_cmap cmap; /* colormap */
+ char *screen_base; /* pointer to top of virtual screen */
+ /* (virtual address) */
+ int visual;
+ int type; /* see FB_TYPE_* */
+ int type_aux; /* Interleave for interleaved Planes */
+ u_short ypanstep; /* zero if no hardware ypan */
+ u_short ywrapstep; /* zero if no hardware ywrap */
+ u_long line_length; /* length of a line in bytes */
+ u_short can_soft_blank; /* zero if no hardware blanking */
+ u_short inverse; /* != 0 text black on white as default */
+ struct display_switch *dispsw; /* low level operations */
+ void *dispsw_data; /* optional dispsw helper data */
+
+#if 0
+ struct fb_fix_cursorinfo fcrsr;
+ struct fb_var_cursorinfo *vcrsr;
+ struct fb_cursorstate crsrstate;
+#endif
+
+ /* Filled in by the low-level console driver */
+
+ struct vc_data *conp; /* pointer to console data */
+ struct fb_info *fb_info; /* frame buffer for this console */
+ int vrows; /* number of virtual rows */
+ unsigned short cursor_x; /* current cursor position */
+ unsigned short cursor_y;
+ int fgcol; /* text colors */
+ int bgcol;
+ u_long next_line; /* offset to one line below */
+ u_long next_plane; /* offset to next plane */
+ u_char *fontdata; /* Font associated to this display */
+ unsigned short _fontheightlog;
+ unsigned short _fontwidthlog;
+ unsigned short _fontheight;
+ unsigned short _fontwidth;
+ int userfont; /* != 0 if fontdata kmalloc()ed */
+ u_short scrollmode; /* Scroll Method */
+ short yscroll; /* Hardware scrolling */
+ unsigned char fgshift, bgshift;
+ unsigned short charmask; /* 0xff or 0x1ff */
+};
+
+
+struct fb_info {
+ char modename[40]; /* default video mode */
+ kdev_t node;
+ int flags;
+#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
+ struct fb_ops *fbops;
+ struct fb_monspecs monspecs;
+ struct display *disp; /* initial display variable */
+ struct vc_data *display_fg; /* Console visible on this display */
+ char fontname[40]; /* default font name */
+ int (*changevar)(int); /* tell console var has changed */
+ int (*switch_con)(int, struct fb_info*);
+ /* tell fb to switch consoles */
+ int (*updatevar)(int, struct fb_info*);
+ /* tell fb to update the vars */
+ void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */
+ /* arg = 0: unblank */
+ /* arg > 0: VESA level (arg-1) */
+
+ /* From here on everything is device dependent */
+};
+
+#ifdef MODULE
+#define FBINFO_FLAG_DEFAULT FBINFO_FLAG_MODULE
+#else
+#define FBINFO_FLAG_DEFAULT 0
+#endif
+
+ /*
+ * This structure abstracts from the underlying hardware. It is not
+ * mandatory but used by the `generic' frame buffer operations.
+ * Read drivers/video/skeletonfb.c for more information.
+ */
+
+struct fbgen_hwswitch {
+ void (*detect)(void);
+ int (*encode_fix)(struct fb_fix_screeninfo *fix, const void *par,
+ struct fb_info_gen *info);
+ int (*decode_var)(const struct fb_var_screeninfo *var, void *par,
+ struct fb_info_gen *info);
+ int (*encode_var)(struct fb_var_screeninfo *var, const void *par,
+ struct fb_info_gen *info);
+ void (*get_par)(void *par, struct fb_info_gen *info);
+ void (*set_par)(const void *par, struct fb_info_gen *info);
+ int (*getcolreg)(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp, struct fb_info *info);
+ int (*setcolreg)(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info);
+ int (*pan_display)(const struct fb_var_screeninfo *var,
+ struct fb_info_gen *info);
+ int (*blank)(int blank_mode, struct fb_info_gen *info);
+ void (*set_disp)(const void *par, struct display *disp,
+ struct fb_info_gen *info);
+};
+
+struct fb_info_gen {
+ struct fb_info info;
+
+ /* Entries for a generic frame buffer device */
+ /* Yes, this starts looking like C++ */
+ u_int parsize;
+ struct fbgen_hwswitch *fbhw;
+
+ /* From here on everything is device dependent */
+};
+
+ /*
+ * `Generic' versions of the frame buffer device operations
+ */
+
+extern int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+extern int fbgen_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+extern int fbgen_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+extern int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+extern int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+extern int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+extern int fbgen_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
+
+ /*
+ * Helper functions
+ */
+
+extern int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info_gen *info);
+extern void fbgen_set_disp(int con, struct fb_info_gen *info);
+extern void fbgen_install_cmap(int con, struct fb_info_gen *info);
+extern int fbgen_update_var(int con, struct fb_info *info);
+extern int fbgen_switch(int con, struct fb_info *info);
+extern void fbgen_blank(int blank, struct fb_info *info);
+
+
+struct fb_videomode {
+ const char *name;
+ struct fb_var_screeninfo var;
+};
+
+
+/* drivers/char/fbmem.c */
+extern int register_framebuffer(struct fb_info *fb_info);
+extern int unregister_framebuffer(const struct fb_info *fb_info);
+extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
+ const struct fb_info *fb_info);
+extern int fbmon_dpms(const struct fb_info *fb_info);
+
+
+extern int num_registered_fb;
+extern struct fb_info *registered_fb[FB_MAX];
+extern char con2fb_map[MAX_NR_CONSOLES];
+
+/* drivers/video/fbcon.c */
+extern struct display fb_display[MAX_NR_CONSOLES];
+
+/* drivers/video/fbcmap.c */
+extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
+extern void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to,
+ int fsfromto);
+extern int fb_get_cmap(struct fb_cmap *cmap, int kspc,
+ int (*getcolreg)(u_int, u_int *, u_int *, u_int *,
+ u_int *, struct fb_info *),
+ struct fb_info *fb_info);
+extern int fb_set_cmap(struct fb_cmap *cmap, int kspc,
+ int (*setcolreg)(u_int, u_int, u_int, u_int, u_int,
+ struct fb_info *),
+ struct fb_info *fb_info);
+extern struct fb_cmap *fb_default_cmap(int len);
+extern void fb_invert_cmaps(void);
+
+/* VESA Blanking Levels */
+#define VESA_NO_BLANKING 0
+#define VESA_VSYNC_SUSPEND 1
+#define VESA_HSYNC_SUSPEND 2
+#define VESA_POWERDOWN 3
+
+#endif /* __KERNEL__ */
+
+#if 1
+
+#define FBCMD_GET_CURRENTPAR 0xDEAD0005
+#define FBCMD_SET_CURRENTPAR 0xDEAD8005
+
+#endif
+
+
+#if 1 /* Preliminary */
+
+ /*
+ * Hardware Cursor
+ */
+
+#define FBIOGET_FCURSORINFO 0x4607
+#define FBIOGET_VCURSORINFO 0x4608
+#define FBIOPUT_VCURSORINFO 0x4609
+#define FBIOGET_CURSORSTATE 0x460A
+#define FBIOPUT_CURSORSTATE 0x460B
+
+
+struct fb_fix_cursorinfo {
+ __u16 crsr_width; /* width and height of the cursor in */
+ __u16 crsr_height; /* pixels (zero if no cursor) */
+ __u16 crsr_xsize; /* cursor size in display pixels */
+ __u16 crsr_ysize;
+ __u16 crsr_color1; /* colormap entry for cursor color1 */
+ __u16 crsr_color2; /* colormap entry for cursor color2 */
+};
+
+struct fb_var_cursorinfo {
+ __u16 width;
+ __u16 height;
+ __u16 xspot;
+ __u16 yspot;
+ __u8 data[1]; /* field with [height][width] */
+};
+
+struct fb_cursorstate {
+ __s16 xoffset;
+ __s16 yoffset;
+ __u16 mode;
+};
+
+#define FB_CURSOR_OFF 0
+#define FB_CURSOR_ON 1
+#define FB_CURSOR_FLASH 2
+
+#endif /* Preliminary */
+
+#endif /* _LINUX_FB_H */
diff --git a/pfinet/linux-src/include/linux/fcdevice.h b/pfinet/linux-src/include/linux/fcdevice.h
new file mode 100644
index 00000000..22a1e454
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fcdevice.h
@@ -0,0 +1,40 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. NET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the Fibre Channel handlers.
+ *
+ * Version: @(#)fcdevice.h 1.0.0 09/26/98
+ *
+ * Authors: Vineet Abraham <vma@iol.unh.edu>
+ *
+ * Relocated to include/linux where it belongs by Alan Cox
+ * <gw4pts@gw4pts.ampr.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * WARNING: This move may well be temporary. This file will get merged with others RSN.
+ *
+ */
+#ifndef _LINUX_FCDEVICE_H
+#define _LINUX_FCDEVICE_H
+
+
+#include <linux/if_fc.h>
+
+#ifdef __KERNEL__
+extern int fc_header(struct sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len);
+extern int fc_rebuild_header(struct sk_buff *skb);
+//extern unsigned short fc_type_trans(struct sk_buff *skb, struct device *dev);
+
+extern struct device * init_fcdev(struct device *, int);
+
+#endif
+
+#endif /* _LINUX_FCDEVICE_H */
diff --git a/pfinet/linux-src/include/linux/fcntl.h b/pfinet/linux-src/include/linux/fcntl.h
new file mode 100644
index 00000000..9de3512e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fcntl.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_FCNTL_H
+#define _LINUX_FCNTL_H
+
+#include <asm/fcntl.h>
+
+#endif
diff --git a/pfinet/linux-src/include/linux/fd.h b/pfinet/linux-src/include/linux/fd.h
new file mode 100644
index 00000000..c0ed2792
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fd.h
@@ -0,0 +1,378 @@
+#ifndef _LINUX_FD_H
+#define _LINUX_FD_H
+
+#include <linux/ioctl.h>
+
+/* New file layout: Now the ioctl definitions immediately follow the
+ * definitions of the structures that they use */
+
+/*
+ * Geometry
+ */
+struct floppy_struct {
+ unsigned int size, /* nr of sectors total */
+ sect, /* sectors per track */
+ head, /* nr of heads */
+ track, /* nr of tracks */
+ stretch; /* !=0 means double track steps */
+#define FD_STRETCH 1
+#define FD_SWAPSIDES 2
+
+ unsigned char gap, /* gap1 size */
+
+ rate, /* data rate. |= 0x40 for perpendicular */
+#define FD_2M 0x4
+#define FD_SIZECODEMASK 0x38
+#define FD_SIZECODE(floppy) (((((floppy)->rate&FD_SIZECODEMASK)>> 3)+ 2) %8)
+#define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \
+ 512 : 128 << FD_SIZECODE(floppy) )
+#define FD_PERP 0x40
+
+ spec1, /* stepping rate, head unload time */
+ fmt_gap; /* gap2 size */
+ const char * name; /* used only for predefined formats */
+};
+
+
+/* commands needing write access have 0x40 set */
+/* commands needing super user access have 0x80 set */
+
+#define FDCLRPRM _IO(2, 0x41)
+/* clear user-defined parameters */
+
+#define FDSETPRM _IOW(2, 0x42, struct floppy_struct)
+#define FDSETMEDIAPRM FDSETPRM
+/* set user-defined parameters for current media */
+
+#define FDDEFPRM _IOW(2, 0x43, struct floppy_struct)
+#define FDGETPRM _IOR(2, 0x04, struct floppy_struct)
+#define FDDEFMEDIAPRM FDDEFPRM
+#define FDGETMEDIAPRM FDGETPRM
+/* set/get disk parameters */
+
+
+#define FDMSGON _IO(2,0x45)
+#define FDMSGOFF _IO(2,0x46)
+/* issue/don't issue kernel messages on media type change */
+
+
+/*
+ * Formatting (obsolete)
+ */
+#define FD_FILL_BYTE 0xF6 /* format fill byte. */
+
+struct format_descr {
+ unsigned int device,head,track;
+};
+
+#define FDFMTBEG _IO(2,0x47)
+/* begin formatting a disk */
+#define FDFMTTRK _IOW(2,0x48, struct format_descr)
+/* format the specified track */
+#define FDFMTEND _IO(2,0x49)
+/* end formatting a disk */
+
+
+/*
+ * Error thresholds
+ */
+struct floppy_max_errors {
+ unsigned int
+ abort, /* number of errors to be reached before aborting */
+ read_track, /* maximal number of errors permitted to read an
+ * entire track at once */
+ reset, /* maximal number of errors before a reset is tried */
+ recal, /* maximal number of errors before a recalibrate is
+ * tried */
+
+ /*
+ * Threshold for reporting FDC errors to the console.
+ * Setting this to zero may flood your screen when using
+ * ultra cheap floppies ;-)
+ */
+ reporting;
+
+};
+
+#define FDSETEMSGTRESH _IO(2,0x4a)
+/* set fdc error reporting threshold */
+
+#define FDFLUSH _IO(2,0x4b)
+/* flush buffers for media; either for verifying media, or for
+ * handling a media change without closing the file descriptor */
+
+#define FDSETMAXERRS _IOW(2, 0x4c, struct floppy_max_errors)
+#define FDGETMAXERRS _IOR(2, 0x0e, struct floppy_max_errors)
+/* set/get abortion and read_track threshold. See also floppy_drive_params
+ * structure */
+
+
+typedef char floppy_drive_name[16];
+#define FDGETDRVTYP _IOR(2, 0x0f, floppy_drive_name)
+/* get drive type: 5 1/4 or 3 1/2 */
+
+
+/*
+ * Drive parameters (user modifiable)
+ */
+struct floppy_drive_params {
+ signed char cmos; /* CMOS type */
+
+ /* Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms
+ * etc) and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
+ */
+ unsigned long max_dtr; /* Step rate, usec */
+ unsigned long hlt; /* Head load/settle time, msec */
+ unsigned long hut; /* Head unload time (remnant of
+ * 8" drives) */
+ unsigned long srt; /* Step rate, usec */
+
+ unsigned long spinup; /* time needed for spinup (expressed
+ * in jiffies) */
+ unsigned long spindown; /* timeout needed for spindown */
+ unsigned char spindown_offset; /* decides in which position the disk
+ * will stop */
+ unsigned char select_delay; /* delay to wait after select */
+ unsigned char rps; /* rotations per second */
+ unsigned char tracks; /* maximum number of tracks */
+ unsigned long timeout; /* timeout for interrupt requests */
+
+ unsigned char interleave_sect; /* if there are more sectors, use
+ * interleave */
+
+ struct floppy_max_errors max_errors;
+
+ char flags; /* various flags, including ftd_msg */
+/*
+ * Announce successful media type detection and media information loss after
+ * disk changes.
+ * Also used to enable/disable printing of overrun warnings.
+ */
+
+#define FTD_MSG 0x10
+#define FD_BROKEN_DCL 0x20
+#define FD_DEBUG 0x02
+#define FD_SILENT_DCL_CLEAR 0x4
+#define FD_INVERTED_DCL 0x80 /* must be 0x80, because of hardware
+ considerations */
+
+ char read_track; /* use readtrack during probing? */
+
+/*
+ * Auto-detection. Each drive type has eight formats which are
+ * used in succession to try to read the disk. If the FDC cannot lock onto
+ * the disk, the next format is tried. This uses the variable 'probing'.
+ */
+ short autodetect[8]; /* autodetected formats */
+
+ int checkfreq; /* how often should the drive be checked for disk
+ * changes */
+ int native_format; /* native format of this drive */
+};
+
+enum {
+ FD_NEED_TWADDLE_BIT, /* more magic */
+ FD_VERIFY_BIT, /* inquire for write protection */
+ FD_DISK_NEWCHANGE_BIT, /* change detected, and no action undertaken yet
+ * to clear media change status */
+ FD_UNUSED_BIT,
+ FD_DISK_CHANGED_BIT, /* disk has been changed since last i/o */
+ FD_DISK_WRITABLE_BIT /* disk is writable */
+};
+
+#define FDSETDRVPRM _IOW(2, 0x90, struct floppy_drive_params)
+#define FDGETDRVPRM _IOR(2, 0x11, struct floppy_drive_params)
+/* set/get drive parameters */
+
+
+/*
+ * Current drive state (not directly modifiable by user, readonly)
+ */
+struct floppy_drive_struct {
+ unsigned long flags;
+/* values for these flags */
+#define FD_NEED_TWADDLE (1 << FD_NEED_TWADDLE_BIT)
+#define FD_VERIFY (1 << FD_VERIFY_BIT)
+#define FD_DISK_NEWCHANGE (1 << FD_DISK_NEWCHANGE_BIT)
+#define FD_DISK_CHANGED (1 << FD_DISK_CHANGED_BIT)
+#define FD_DISK_WRITABLE (1 << FD_DISK_WRITABLE_BIT)
+
+ unsigned long spinup_date;
+ unsigned long select_date;
+ unsigned long first_read_date;
+ short probed_format;
+ short track; /* current track */
+ short maxblock; /* id of highest block read */
+ short maxtrack; /* id of highest half track read */
+ int generation; /* how many diskchanges? */
+
+/*
+ * (User-provided) media information is _not_ discarded after a media change
+ * if the corresponding keep_data flag is non-zero. Positive values are
+ * decremented after each probe.
+ */
+ int keep_data;
+
+ /* Prevent "aliased" accesses. */
+ int fd_ref;
+ int fd_device;
+ unsigned long last_checked; /* when was the drive last checked for a disk
+ * change? */
+
+ char *dmabuf;
+ int bufblocks;
+};
+
+#define FDGETDRVSTAT _IOR(2, 0x12, struct floppy_drive_struct)
+#define FDPOLLDRVSTAT _IOR(2, 0x13, struct floppy_drive_struct)
+/* get drive state: GET returns the cached state, POLL polls for new state */
+
+
+/*
+ * reset FDC
+ */
+enum reset_mode {
+ FD_RESET_IF_NEEDED, /* reset only if the reset flags is set */
+ FD_RESET_IF_RAWCMD, /* obsolete */
+ FD_RESET_ALWAYS /* reset always */
+};
+#define FDRESET _IO(2, 0x54)
+
+
+/*
+ * FDC state
+ */
+struct floppy_fdc_state {
+ int spec1; /* spec1 value last used */
+ int spec2; /* spec2 value last used */
+ int dtr;
+ unsigned char version; /* FDC version code */
+ unsigned char dor;
+ unsigned long address; /* io address */
+ unsigned int rawcmd:2;
+ unsigned int reset:1;
+ unsigned int need_configure:1;
+ unsigned int perp_mode:2;
+ unsigned int has_fifo:1;
+ unsigned int driver_version; /* version code for floppy driver */
+#define FD_DRIVER_VERSION 0x100
+/* user programs using the floppy API should use floppy_fdc_state to
+ * get the version number of the floppy driver that they are running
+ * on. If this version number is bigger than the one compiled into the
+ * user program (the FD_DRIVER_VERSION define), it should be prepared
+ * to bigger structures
+ */
+
+ unsigned char track[4];
+ /* Position of the heads of the 4 units attached to this FDC,
+ * as stored on the FDC. In the future, the position as stored
+ * on the FDC might not agree with the actual physical
+ * position of these drive heads. By allowing such
+ * disagreement, it will be possible to reset the FDC without
+ * incurring the expensive cost of repositioning all heads.
+ * Right now, these positions are hard wired to 0. */
+
+};
+
+#define FDGETFDCSTAT _IOR(2, 0x15, struct floppy_fdc_state)
+
+
+/*
+ * Asynchronous Write error tracking
+ */
+struct floppy_write_errors {
+ /* Write error logging.
+ *
+ * These fields can be cleared with the FDWERRORCLR ioctl.
+ * Only writes that were attempted but failed due to a physical media
+ * error are logged. write(2) calls that fail and return an error code
+ * to the user process are not counted.
+ */
+
+ unsigned int write_errors; /* number of physical write errors
+ * encountered */
+
+ /* position of first and last write errors */
+ unsigned long first_error_sector;
+ int first_error_generation;
+ unsigned long last_error_sector;
+ int last_error_generation;
+
+ unsigned int badness; /* highest retry count for a read or write
+ * operation */
+};
+
+#define FDWERRORCLR _IO(2, 0x56)
+/* clear write error and badness information */
+#define FDWERRORGET _IOR(2, 0x17, struct floppy_write_errors)
+/* get write error and badness information */
+
+
+/*
+ * Raw commands
+ */
+/* new interface flag: now we can do them in batches */
+#define FDHAVEBATCHEDRAWCMD
+
+struct floppy_raw_cmd {
+ unsigned int flags;
+#define FD_RAW_READ 1
+#define FD_RAW_WRITE 2
+#define FD_RAW_NO_MOTOR 4
+#define FD_RAW_DISK_CHANGE 4 /* out: disk change flag was set */
+#define FD_RAW_INTR 8 /* wait for an interrupt */
+#define FD_RAW_SPIN 0x10 /* spin up the disk for this command */
+#define FD_RAW_NO_MOTOR_AFTER 0x20 /* switch the motor off after command
+ * completion */
+#define FD_RAW_NEED_DISK 0x40 /* this command needs a disk to be present */
+#define FD_RAW_NEED_SEEK 0x80 /* this command uses an implied seek (soft) */
+
+/* more "in" flags */
+#define FD_RAW_MORE 0x100 /* more records follow */
+#define FD_RAW_STOP_IF_FAILURE 0x200 /* stop if we encounter a failure */
+#define FD_RAW_STOP_IF_SUCCESS 0x400 /* stop if command successful */
+#define FD_RAW_SOFTFAILURE 0x800 /* consider the return value for failure
+ * detection too */
+
+/* more "out" flags */
+#define FD_RAW_FAILURE 0x10000 /* command sent to fdc, fdc returned error */
+#define FD_RAW_HARDFAILURE 0x20000 /* fdc had to be reset, or timed out */
+
+ void *data;
+ char *kernel_data; /* location of data buffer in the kernel */
+ struct floppy_raw_cmd *next; /* used for chaining of raw cmd's
+ * within the kernel */
+ long length; /* in: length of dma transfer. out: remaining bytes */
+ long phys_length; /* physical length, if different from dma length */
+ int buffer_length; /* length of allocated buffer */
+
+ unsigned char rate;
+ unsigned char cmd_count;
+ unsigned char cmd[16];
+ unsigned char reply_count;
+ unsigned char reply[16];
+ int track;
+ int resultcode;
+
+ int reserved1;
+ int reserved2;
+};
+
+#define FDRAWCMD _IO(2, 0x58)
+/* send a raw command to the fdc. Structure size not included, because of
+ * batches */
+
+#define FDTWADDLE _IO(2, 0x59)
+/* flicker motor-on bit before reading a sector. Experimental */
+
+
+#define FDEJECT _IO(2, 0x5a)
+/* eject the disk */
+
+
+#ifdef __KERNEL__
+/* eject the boot floppy (if we need the drive for a different root floppy) */
+void floppy_eject(void);
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/fddidevice.h b/pfinet/linux-src/include/linux/fddidevice.h
new file mode 100644
index 00000000..a093ccf7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fddidevice.h
@@ -0,0 +1,39 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the FDDI handlers.
+ *
+ * Version: @(#)fddidevice.h 1.0.0 08/12/96
+ *
+ * Author: Lawrence V. Stefani, <stefani@lkg.dec.com>
+ *
+ * fddidevice.h is based on previous trdevice.h work by
+ * Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_FDDIDEVICE_H
+#define _LINUX_FDDIDEVICE_H
+
+#include <linux/if_fddi.h>
+
+#ifdef __KERNEL__
+extern int fddi_header(struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type,
+ void *daddr,
+ void *saddr,
+ unsigned len);
+extern int fddi_rebuild_header(struct sk_buff *skb);
+extern unsigned short fddi_type_trans(struct sk_buff *skb,
+ struct device *dev);
+#endif
+
+#endif /* _LINUX_FDDIDEVICE_H */
diff --git a/pfinet/linux-src/include/linux/fdreg.h b/pfinet/linux-src/include/linux/fdreg.h
new file mode 100644
index 00000000..1d9026ee
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fdreg.h
@@ -0,0 +1,143 @@
+#ifndef _LINUX_FDREG_H
+#define _LINUX_FDREG_H
+/*
+ * This file contains some defines for the floppy disk controller.
+ * Various sources. Mostly "IBM Microcomputers: A Programmers
+ * Handbook", Sanches and Canton.
+ */
+
+#ifdef FDPATCHES
+
+#define FD_IOPORT fdc_state[fdc].address
+
+/* Fd controller regs. S&C, about page 340 */
+#define FD_STATUS (4 + FD_IOPORT )
+#define FD_DATA (5 + FD_IOPORT )
+
+/* Digital Output Register */
+#define FD_DOR (2 + FD_IOPORT )
+
+/* Digital Input Register (read) */
+#define FD_DIR (7 + FD_IOPORT )
+
+/* Diskette Control Register (write)*/
+#define FD_DCR (7 + FD_IOPORT )
+
+#else
+
+#define FD_STATUS 0x3f4
+#define FD_DATA 0x3f5
+#define FD_DOR 0x3f2 /* Digital Output Register */
+#define FD_DIR 0x3f7 /* Digital Input Register (read) */
+#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/
+
+#endif
+
+/* Bits of main status register */
+#define STATUS_BUSYMASK 0x0F /* drive busy mask */
+#define STATUS_BUSY 0x10 /* FDC busy */
+#define STATUS_DMA 0x20 /* 0- DMA mode */
+#define STATUS_DIR 0x40 /* 0- cpu->fdc */
+#define STATUS_READY 0x80 /* Data reg ready */
+
+/* Bits of FD_ST0 */
+#define ST0_DS 0x03 /* drive select mask */
+#define ST0_HA 0x04 /* Head (Address) */
+#define ST0_NR 0x08 /* Not Ready */
+#define ST0_ECE 0x10 /* Equipment check error */
+#define ST0_SE 0x20 /* Seek end */
+#define ST0_INTR 0xC0 /* Interrupt code mask */
+
+/* Bits of FD_ST1 */
+#define ST1_MAM 0x01 /* Missing Address Mark */
+#define ST1_WP 0x02 /* Write Protect */
+#define ST1_ND 0x04 /* No Data - unreadable */
+#define ST1_OR 0x10 /* OverRun */
+#define ST1_CRC 0x20 /* CRC error in data or addr */
+#define ST1_EOC 0x80 /* End Of Cylinder */
+
+/* Bits of FD_ST2 */
+#define ST2_MAM 0x01 /* Missing Address Mark (again) */
+#define ST2_BC 0x02 /* Bad Cylinder */
+#define ST2_SNS 0x04 /* Scan Not Satisfied */
+#define ST2_SEH 0x08 /* Scan Equal Hit */
+#define ST2_WC 0x10 /* Wrong Cylinder */
+#define ST2_CRC 0x20 /* CRC error in data field */
+#define ST2_CM 0x40 /* Control Mark = deleted */
+
+/* Bits of FD_ST3 */
+#define ST3_HA 0x04 /* Head (Address) */
+#define ST3_DS 0x08 /* drive is double-sided */
+#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */
+#define ST3_RY 0x20 /* drive is ready */
+#define ST3_WP 0x40 /* Write Protect */
+#define ST3_FT 0x80 /* Drive Fault */
+
+/* Values for FD_COMMAND */
+#define FD_RECALIBRATE 0x07 /* move to track 0 */
+#define FD_SEEK 0x0F /* seek track */
+#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */
+#define FD_WRITE 0xC5 /* write with MT, MFM */
+#define FD_SENSEI 0x08 /* Sense Interrupt Status */
+#define FD_SPECIFY 0x03 /* specify HUT etc */
+#define FD_FORMAT 0x4D /* format one track */
+#define FD_VERSION 0x10 /* get version code */
+#define FD_CONFIGURE 0x13 /* configure FIFO operation */
+#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */
+#define FD_GETSTATUS 0x04 /* read ST3 */
+#define FD_DUMPREGS 0x0E /* dump the contents of the fdc regs */
+#define FD_READID 0xEA /* prints the header of a sector */
+#define FD_UNLOCK 0x14 /* Fifo config unlock */
+#define FD_LOCK 0x94 /* Fifo config lock */
+#define FD_RSEEK_OUT 0x8f /* seek out (i.e. to lower tracks) */
+#define FD_RSEEK_IN 0xcf /* seek in (i.e. to higher tracks) */
+
+/* the following commands are new in the 82078. They are not used in the
+ * floppy driver, except the first three. These commands may be useful for apps
+ * which use the FDRAWCMD interface. For doc, get the 82078 spec sheets at
+ * http://www-techdoc.intel.com/docs/periph/fd_contr/datasheets/ */
+
+#define FD_PARTID 0x18 /* part id ("extended" version cmd) */
+#define FD_SAVE 0x2e /* save fdc regs for later restore */
+#define FD_DRIVESPEC 0x8e /* drive specification: Access to the
+ * 2 Mbps data transfer rate for tape
+ * drives */
+
+#define FD_RESTORE 0x4e /* later restore */
+#define FD_POWERDOWN 0x27 /* configure FDC's powersave features */
+#define FD_FORMAT_N_WRITE 0xef /* format and write in one go. */
+#define FD_OPTION 0x33 /* ISO format (which is a clean way to
+ * pack more sectors on a track) */
+
+/* DMA commands */
+#define DMA_READ 0x46
+#define DMA_WRITE 0x4A
+
+/* FDC version return types */
+#define FDC_NONE 0x00
+#define FDC_UNKNOWN 0x10 /* DO NOT USE THIS TYPE EXCEPT IF IDENTIFICATION
+ FAILS EARLY */
+#define FDC_8272A 0x20 /* Intel 8272a, NEC 765 */
+#define FDC_765ED 0x30 /* Non-Intel 1MB-compatible FDC, can't detect */
+#define FDC_82072 0x40 /* Intel 82072; 8272a + FIFO + DUMPREGS */
+#define FDC_82072A 0x45 /* 82072A (on Sparcs) */
+#define FDC_82077_ORIG 0x51 /* Original version of 82077AA, sans LOCK */
+#define FDC_82077 0x52 /* 82077AA-1 */
+#define FDC_82078_UNKN 0x5f /* Unknown 82078 variant */
+#define FDC_82078 0x60 /* 44pin 82078 or 64pin 82078SL */
+#define FDC_82078_1 0x61 /* 82078-1 (2Mbps fdc) */
+#define FDC_S82078B 0x62 /* S82078B (first seen on Adaptec AVA-2825 VLB
+ * SCSI/EIDE/Floppy controller) */
+#define FDC_87306 0x63 /* National Semiconductor PC 87306 */
+
+/*
+ * Beware: the fdc type list is roughly sorted by increasing features.
+ * Presence of features is tested by comparing the FDC version id with the
+ * "oldest" version that has the needed feature.
+ * If during FDC detection, an obscure test fails late in the sequence, don't
+ * assign FDC_UNKNOWN. Else the FDC will be treated as a dumb 8272a, or worse.
+ * This is especially true if the tests are unneeded.
+ */
+
+#define FD_RESET_DELAY 20
+#endif
diff --git a/pfinet/linux-src/include/linux/file.h b/pfinet/linux-src/include/linux/file.h
new file mode 100644
index 00000000..05f388f0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/file.h
@@ -0,0 +1,71 @@
+/*
+ * Wrapper functions for accessing the file_struct fd array.
+ */
+
+#ifndef __LINUX_FILE_H
+#define __LINUX_FILE_H
+
+extern void __fput(struct file *);
+
+/*
+ * Check whether the specified task has the fd open. Since the task
+ * may not have a files_struct, we must test for p->files != NULL.
+ */
+extern inline struct file * fcheck_task(struct task_struct *p, unsigned int fd)
+{
+ struct file * file = NULL;
+
+ if (p->files && fd < p->files->max_fds)
+ file = p->files->fd[fd];
+ return file;
+}
+
+/*
+ * Check whether the specified fd has an open file.
+ */
+extern inline struct file * fcheck(unsigned int fd)
+{
+ struct file * file = NULL;
+
+ if (fd < current->files->max_fds)
+ file = current->files->fd[fd];
+ return file;
+}
+
+extern inline struct file * fget(unsigned int fd)
+{
+ struct file * file = fcheck(fd);
+
+ if (file)
+ file->f_count++;
+ return file;
+}
+
+/*
+ * Install a file pointer in the fd array.
+ */
+extern inline void fd_install(unsigned int fd, struct file *file)
+{
+ current->files->fd[fd] = file;
+}
+
+/*
+ * 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
+ *
+ * Since those functions where calling other functions, it was compleatly
+ * bogous to make them all "extern inline".
+ *
+ * The removal of this pseudo optimization saved me scandaleous:
+ *
+ * 3756 (i386 arch)
+ *
+ * precious bytes from my kernel, even without counting all the code compiled
+ * as module!
+ *
+ * I suspect there are many other similar "optimizations" across the
+ * kernel...
+ */
+extern void fput(struct file *file);
+extern void put_filp(struct file *file);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/filter.h b/pfinet/linux-src/include/linux/filter.h
new file mode 100644
index 00000000..58ad8b1b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/filter.h
@@ -0,0 +1,140 @@
+/*
+ * Linux Socket Filter Data Structures
+ */
+
+#ifndef __LINUX_FILTER_H__
+#define __LINUX_FILTER_H__
+
+/*
+ * Current version of the filter code architecture.
+ */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+/*
+ * Try and keep these values and structures similar to BSD, especially
+ * the BPF code definitions which need to match so you can share filters
+ */
+
+struct sock_filter /* Filter block */
+{
+ __u16 code; /* Actual filter code */
+ __u8 jt; /* Jump true */
+ __u8 jf; /* Jump false */
+ __u32 k; /* Generic multiuse field */
+};
+
+struct sock_fprog /* Required for SO_ATTACH_FILTER. */
+{
+ unsigned short len; /* Number of filter blocks */
+ struct sock_filter *filter;
+};
+
+#ifdef __KERNEL__
+struct sk_filter
+{
+ atomic_t refcnt;
+ unsigned int len; /* Number of filter blocks */
+ struct sock_filter insns[0];
+};
+
+extern __inline__ unsigned int sk_filter_len(struct sk_filter *fp)
+{
+ return fp->len*sizeof(struct sock_filter) + sizeof(*fp);
+}
+#endif
+
+/*
+ * Instruction classes
+ */
+
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define BPF_A 0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define BPF_TAX 0x00
+#define BPF_TXA 0x80
+
+#ifndef BPF_MAXINSNS
+#define BPF_MAXINSNS 4096
+#endif
+
+/*
+ * Macros for filter block array initializers.
+ */
+#ifndef BPF_STMT
+#define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k }
+#endif
+#ifndef BPF_JUMP
+#define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k }
+#endif
+
+/*
+ * Number of scratch memory words for: BPF_ST and BPF_STX
+ */
+#define BPF_MEMWORDS 16
+
+/* RATIONALE. Negative offsets are invalid in BPF.
+ We use them to reference ancillary data.
+ Unlike introduction new instructions, it does not break
+ existing compilers/optimizers.
+ */
+#define SKF_AD_OFF (-0x1000)
+#define SKF_AD_PROTOCOL 0
+#define SKF_AD_PKTTYPE 4
+#define SKF_AD_IFINDEX 8
+#define SKF_AD_MAX 12
+#define SKF_NET_OFF (-0x100000)
+#define SKF_LL_OFF (-0x200000)
+
+#ifdef __KERNEL__
+extern int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen);
+extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_FILTER_H__ */
diff --git a/pfinet/linux-src/include/linux/firewall.h b/pfinet/linux-src/include/linux/firewall.h
new file mode 100644
index 00000000..1747f381
--- /dev/null
+++ b/pfinet/linux-src/include/linux/firewall.h
@@ -0,0 +1,61 @@
+#ifndef __LINUX_FIREWALL_H
+#define __LINUX_FIREWALL_H
+
+#include <linux/config.h>
+
+/*
+ * Definitions for loadable firewall modules
+ */
+
+#define FW_QUEUE 0
+#define FW_BLOCK 1
+#define FW_ACCEPT 2
+#define FW_REJECT (-1)
+#define FW_REDIRECT 3
+#define FW_MASQUERADE 4
+#define FW_SKIP 5
+
+struct firewall_ops
+{
+ struct firewall_ops *next;
+ int (*fw_forward)(struct firewall_ops *this, int pf,
+ struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+ int (*fw_input)(struct firewall_ops *this, int pf,
+ struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+ int (*fw_output)(struct firewall_ops *this, int pf,
+ struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+ /* Data falling in the second 486 cache line isn't used directly
+ during a firewall call and scan, only by insert/delete and other
+ unusual cases
+ */
+ int fw_pf; /* Protocol family */
+ int fw_priority; /* Priority of chosen firewalls */
+};
+
+#ifdef __KERNEL__
+extern int register_firewall(int pf, struct firewall_ops *fw);
+extern int unregister_firewall(int pf, struct firewall_ops *fw);
+extern void fwchain_init(void);
+#ifdef CONFIG_FIREWALL
+extern int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+extern int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+extern int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+#else
+extern __inline__ int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+ return FW_ACCEPT;
+}
+
+extern __inline__ int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+ return FW_ACCEPT;
+}
+
+extern __inline__ int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+ return FW_ACCEPT;
+}
+
+#endif
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/fs.h b/pfinet/linux-src/include/linux/fs.h
new file mode 100644
index 00000000..548b9d74
--- /dev/null
+++ b/pfinet/linux-src/include/linux/fs.h
@@ -0,0 +1,910 @@
+#ifndef _LINUX_FS_H
+#define _LINUX_FS_H
+
+/*
+ * This file has definitions for some important file table
+ * structures etc.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/limits.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/vfs.h>
+#include <linux/net.h>
+#include <linux/kdev_t.h>
+#include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/dcache.h>
+#include <linux/stat.h>
+
+#include <asm/atomic.h>
+#include <linux/bitops.h>
+#include <asm/cache.h>
+#include <linux/stddef.h> /* just in case the #define NULL previously in here was needed */
+
+struct poll_table_struct;
+
+
+/*
+ * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
+ * the file limit at runtime and only root can increase the per-process
+ * nr_file rlimit, so it's safe to set up a ridiculously high absolute
+ * upper limit on files-per-process.
+ *
+ * Some programs (notably those using select()) may have to be
+ * recompiled to take full advantage of the new limits..
+ */
+
+/* Fixed constants first: */
+#undef NR_OPEN
+#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */
+#define INR_OPEN 1024 /* Initial setting for nfile rlimits */
+
+#define BLOCK_SIZE_BITS 10
+#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
+
+/* And dynamically-tunable limits and defaults: */
+extern int max_inodes;
+extern int max_files, nr_files, nr_free_files;
+extern int max_super_blocks, nr_super_blocks;
+
+#define NR_FILE 4096 /* this can well be larger on a larger system */
+#define NR_RESERVED_FILES 10 /* reserved for root */
+#define NR_SUPER 256
+
+#define MAY_EXEC 1
+#define MAY_WRITE 2
+#define MAY_READ 4
+
+#define FMODE_READ 1
+#define FMODE_WRITE 2
+
+#define READ 0
+#define WRITE 1
+#define READA 2 /* read-ahead - don't block if no resources */
+#define WRITEA 3 /* write-ahead - don't block if no resources */
+
+#define NIL_FILP ((struct file *)0)
+#define SEL_IN 1
+#define SEL_OUT 2
+#define SEL_EX 4
+
+/* public flags for file_system_type */
+#define FS_REQUIRES_DEV 1
+#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */
+#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
+ * FS_NO_DCACHE is not set.
+ */
+#define FS_IBASKET 8 /* FS does callback to free_ibasket() if space gets low. */
+
+/*
+ * These are the fs-independent mount-flags: up to 16 flags are supported
+ */
+#define MS_RDONLY 1 /* Mount read-only */
+#define MS_NOSUID 2 /* Ignore suid and sgid bits */
+#define MS_NODEV 4 /* Disallow access to device special files */
+#define MS_NOEXEC 8 /* Disallow program execution */
+#define MS_SYNCHRONOUS 16 /* Writes are synced at once */
+#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
+#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
+#define S_QUOTA 128 /* Quota initialized for file/directory/symlink */
+#define S_APPEND 256 /* Append-only file */
+#define S_IMMUTABLE 512 /* Immutable file */
+#define MS_NOATIME 1024 /* Do not update access times. */
+#define MS_NODIRATIME 2048 /* Do not update directory access times */
+
+#define MS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
+ * as nfs_rename() will be cleaned up
+ */
+
+/*
+ * Flags that can be altered by MS_REMOUNT
+ */
+#define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
+
+/*
+ * Magic mount flag number. Has to be or-ed to the flag values.
+ */
+#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */
+#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */
+
+/*
+ * Note that read-only etc flags are inode-specific: setting some file-system
+ * flags just means all the inodes inherit those flags by default. It might be
+ * possible to override it selectively if you really wanted to with some
+ * ioctl() that is not currently implemented.
+ *
+ * Exception: MS_RDONLY is always applied to the entire file system.
+ *
+ * Unfortunately, it is possible to change a filesystems flags with it mounted
+ * with files in use. This means that all of the inodes will not have their
+ * i_flags updated. Hence, i_flags no longer inherit the superblock mount
+ * flags, so these have to be checked separately. -- rmk@arm.uk.linux.org
+ */
+#define __IS_FLG(inode,flg) (((inode)->i_sb && (inode)->i_sb->s_flags & (flg)) \
+ || (inode)->i_flags & (flg))
+
+#define IS_RDONLY(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & MS_RDONLY))
+#define IS_NOSUID(inode) __IS_FLG(inode, MS_NOSUID)
+#define IS_NODEV(inode) __IS_FLG(inode, MS_NODEV)
+#define IS_NOEXEC(inode) __IS_FLG(inode, MS_NOEXEC)
+#define IS_SYNC(inode) __IS_FLG(inode, MS_SYNCHRONOUS)
+#define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK)
+
+#define IS_QUOTAINIT(inode) ((inode)->i_flags & S_QUOTA)
+#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
+#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
+#define IS_NOATIME(inode) __IS_FLG(inode, MS_NOATIME)
+#define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME)
+
+/* the read-only stuff doesn't really belong here, but any other place is
+ probably as bad and I don't want to create yet another include file. */
+
+#define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */
+#define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
+#define BLKRRPART _IO(0x12,95) /* re-read partition table */
+#define BLKGETSIZE _IO(0x12,96) /* return device size */
+#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
+#define BLKRASET _IO(0x12,98) /* Set read ahead for block device */
+#define BLKRAGET _IO(0x12,99) /* get current read ahead setting */
+#define BLKFRASET _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
+#define BLKFRAGET _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
+#define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
+#define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
+#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+
+#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
+#define FIBMAP _IO(0x00,1) /* bmap access */
+#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
+
+#ifdef __KERNEL__
+
+#include <asm/semaphore.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+
+extern void update_atime (struct inode *inode);
+#define UPDATE_ATIME(inode) update_atime (inode)
+
+extern void buffer_init(unsigned long);
+extern void inode_init(void);
+extern void file_table_init(void);
+extern void dcache_init(void);
+
+typedef char buffer_block[BLOCK_SIZE];
+
+/* bh state bits */
+#define BH_Uptodate 0 /* 1 if the buffer contains valid data */
+#define BH_Dirty 1 /* 1 if the buffer is dirty */
+#define BH_Lock 2 /* 1 if the buffer is locked */
+#define BH_Req 3 /* 0 if the buffer has been invalidated */
+#define BH_Protected 6 /* 1 if the buffer is protected */
+
+/*
+ * Try to keep the most commonly used fields in single cache lines (16
+ * bytes) to improve performance. This ordering should be
+ * particularly beneficial on 32-bit processors.
+ *
+ * We use the first 16 bytes for the data which is used in searches
+ * over the block hash lists (ie. getblk(), find_buffer() and
+ * friends).
+ *
+ * The second 16 bytes we use for lru buffer scans, as used by
+ * sync_buffers() and refill_freelist(). -- sct
+ */
+struct buffer_head {
+ /* First cache line: */
+ struct buffer_head * b_next; /* Hash queue list */
+ unsigned long b_blocknr; /* block number */
+ unsigned long b_size; /* block size */
+ kdev_t b_dev; /* device (B_FREE = free) */
+ kdev_t b_rdev; /* Real device */
+ unsigned long b_rsector; /* Real buffer location on disk */
+ struct buffer_head * b_this_page; /* circular list of buffers in one page */
+ unsigned long b_state; /* buffer state bitmap (see above) */
+ struct buffer_head * b_next_free;
+ unsigned int b_count; /* users using this block */
+
+ /* Non-performance-critical data follows. */
+ char * b_data; /* pointer to data block (1024 bytes) */
+ unsigned int b_list; /* List that this buffer appears */
+ unsigned long b_flushtime; /* Time when this (dirty) buffer
+ * should be written */
+ struct wait_queue * b_wait;
+ struct buffer_head ** b_pprev; /* doubly linked list of hash-queue */
+ struct buffer_head * b_prev_free; /* doubly linked list of buffers */
+ struct buffer_head * b_reqnext; /* request queue */
+
+ /*
+ * I/O completion
+ */
+ void (*b_end_io)(struct buffer_head *bh, int uptodate);
+ void *b_dev_id;
+};
+
+typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
+void init_buffer(struct buffer_head *bh, kdev_t dev, int block,
+ bh_end_io_t *handler, void *dev_id);
+
+static inline int buffer_uptodate(struct buffer_head * bh)
+{
+ return test_bit(BH_Uptodate, &bh->b_state);
+}
+
+static inline int buffer_dirty(struct buffer_head * bh)
+{
+ return test_bit(BH_Dirty, &bh->b_state);
+}
+
+static inline int buffer_locked(struct buffer_head * bh)
+{
+ return test_bit(BH_Lock, &bh->b_state);
+}
+
+static inline int buffer_req(struct buffer_head * bh)
+{
+ return test_bit(BH_Req, &bh->b_state);
+}
+
+static inline int buffer_protected(struct buffer_head * bh)
+{
+ return test_bit(BH_Protected, &bh->b_state);
+}
+
+#define buffer_page(bh) (mem_map + MAP_NR((bh)->b_data))
+#define touch_buffer(bh) set_bit(PG_referenced, &buffer_page(bh)->flags)
+
+#include <linux/pipe_fs_i.h>
+#include <linux/minix_fs_i.h>
+#include <linux/ext2_fs_i.h>
+#include <linux/hpfs_fs_i.h>
+#include <linux/ntfs_fs_i.h>
+#include <linux/msdos_fs_i.h>
+#include <linux/umsdos_fs_i.h>
+#include <linux/iso_fs_i.h>
+#include <linux/nfs_fs_i.h>
+#include <linux/sysv_fs_i.h>
+#include <linux/affs_fs_i.h>
+#include <linux/ufs_fs_i.h>
+#include <linux/efs_fs_i.h>
+#include <linux/coda_fs_i.h>
+#include <linux/romfs_fs_i.h>
+#include <linux/smb_fs_i.h>
+#include <linux/hfs_fs_i.h>
+#include <linux/adfs_fs_i.h>
+#include <linux/qnx4_fs_i.h>
+
+/*
+ * Attribute flags. These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE 1
+#define ATTR_UID 2
+#define ATTR_GID 4
+#define ATTR_SIZE 8
+#define ATTR_ATIME 16
+#define ATTR_MTIME 32
+#define ATTR_CTIME 64
+#define ATTR_ATIME_SET 128
+#define ATTR_MTIME_SET 256
+#define ATTR_FORCE 512 /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG 1024
+
+/*
+ * This is the Inode Attributes structure, used for notify_change(). It
+ * uses the above definitions as flags, to know which values have changed.
+ * Also, in this manner, a Filesystem can look at only the values it cares
+ * about. Basically, these are the attributes that the VFS layer can
+ * request to change from the FS layer.
+ *
+ * Derek Atkins <warlord@MIT.EDU> 94-10-20
+ */
+struct iattr {
+ unsigned int ia_valid;
+ umode_t ia_mode;
+ uid_t ia_uid;
+ gid_t ia_gid;
+ off_t ia_size;
+ time_t ia_atime;
+ time_t ia_mtime;
+ time_t ia_ctime;
+ unsigned int ia_attr_flags;
+};
+
+/*
+ * This is the inode attributes flag definitions
+ */
+#define ATTR_FLAG_SYNCRONOUS 1 /* Syncronous write */
+#define ATTR_FLAG_NOATIME 2 /* Don't update atime */
+#define ATTR_FLAG_APPEND 4 /* Append-only file */
+#define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */
+#define ATTR_FLAG_NODIRATIME 16 /* Don't update atime for directory */
+
+/*
+ * Includes for diskquotas and mount structures.
+ */
+#include <linux/quota.h>
+#include <linux/mount.h>
+
+struct inode {
+ struct list_head i_hash;
+ struct list_head i_list;
+ struct list_head i_dentry;
+
+ unsigned long i_ino;
+ unsigned int i_count;
+ kdev_t i_dev;
+ umode_t i_mode;
+ nlink_t i_nlink;
+ uid_t i_uid;
+ gid_t i_gid;
+ kdev_t i_rdev;
+ off_t i_size;
+ time_t i_atime;
+ time_t i_mtime;
+ time_t i_ctime;
+ unsigned long i_blksize;
+ unsigned long i_blocks;
+ unsigned long i_version;
+ unsigned long i_nrpages;
+ struct semaphore i_sem;
+ struct semaphore i_atomic_write;
+ struct inode_operations *i_op;
+ struct super_block *i_sb;
+ struct wait_queue *i_wait;
+ struct file_lock *i_flock;
+ struct vm_area_struct *i_mmap;
+ struct page *i_pages;
+ struct dquot *i_dquot[MAXQUOTAS];
+
+ unsigned long i_state;
+
+ unsigned int i_flags;
+ unsigned char i_pipe;
+ unsigned char i_sock;
+
+ int i_writecount;
+ unsigned int i_attr_flags;
+ __u32 i_generation;
+ union {
+ struct pipe_inode_info pipe_i;
+ struct minix_inode_info minix_i;
+ struct ext2_inode_info ext2_i;
+ struct hpfs_inode_info hpfs_i;
+ struct ntfs_inode_info ntfs_i;
+ struct msdos_inode_info msdos_i;
+ struct umsdos_inode_info umsdos_i;
+ struct iso_inode_info isofs_i;
+ struct nfs_inode_info nfs_i;
+ struct sysv_inode_info sysv_i;
+ struct affs_inode_info affs_i;
+ struct ufs_inode_info ufs_i;
+ struct efs_inode_info efs_i;
+ struct romfs_inode_info romfs_i;
+ struct coda_inode_info coda_i;
+ struct smb_inode_info smbfs_i;
+ struct hfs_inode_info hfs_i;
+ struct adfs_inode_info adfs_i;
+ struct qnx4_inode_info qnx4_i;
+ struct socket socket_i;
+ void *generic_ip;
+ } u;
+};
+
+/* Inode state bits.. */
+#define I_DIRTY 1
+#define I_LOCK 2
+#define I_FREEING 4
+
+extern void __mark_inode_dirty(struct inode *);
+static inline void mark_inode_dirty(struct inode *inode)
+{
+ if (!(inode->i_state & I_DIRTY))
+ __mark_inode_dirty(inode);
+}
+
+struct fown_struct {
+ int pid; /* pid or -pgrp where SIGIO should be sent */
+ uid_t uid, euid; /* uid/euid of process setting the owner */
+ int signum; /* posix.1b rt signal to be delivered on IO */
+};
+
+struct file {
+ struct file *f_next, **f_pprev;
+ struct dentry *f_dentry;
+ struct file_operations *f_op;
+ mode_t f_mode;
+ loff_t f_pos;
+ unsigned int f_count, f_flags;
+ unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
+ struct fown_struct f_owner;
+ unsigned int f_uid, f_gid;
+ int f_error;
+
+ unsigned long f_version;
+
+ /* needed for tty driver, and maybe others */
+ void *private_data;
+};
+
+extern int init_private_file(struct file *, struct dentry *, int);
+
+#define FL_POSIX 1
+#define FL_FLOCK 2
+#define FL_BROKEN 4 /* broken flock() emulation */
+#define FL_ACCESS 8 /* for processes suspended by mandatory locking */
+#define FL_LOCKD 16 /* lock held by rpc.lockd */
+
+/*
+ * The POSIX file lock owner is determined by
+ * the "struct files_struct" in the thread group
+ * (or NULL for no owner - BSD locks).
+ *
+ * Lockd stuffs a "host" pointer into this.
+ */
+typedef struct files_struct *fl_owner_t;
+
+struct file_lock {
+ struct file_lock *fl_next; /* singly linked list for this inode */
+ struct file_lock *fl_nextlink; /* doubly linked list of all locks */
+ struct file_lock *fl_prevlink; /* used to simplify lock removal */
+ struct file_lock *fl_nextblock; /* circular list of blocked processes */
+ struct file_lock *fl_prevblock;
+ fl_owner_t fl_owner;
+ unsigned int fl_pid;
+ struct wait_queue *fl_wait;
+ struct file *fl_file;
+ unsigned char fl_flags;
+ unsigned char fl_type;
+ off_t fl_start;
+ off_t fl_end;
+
+ void (*fl_notify)(struct file_lock *); /* unblock callback */
+
+ union {
+ struct nfs_lock_info nfs_fl;
+ } fl_u;
+};
+
+extern struct file_lock *file_lock_table;
+
+#include <linux/fcntl.h>
+
+extern int fcntl_getlk(unsigned int fd, struct flock *l);
+extern int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l);
+
+/* fs/locks.c */
+extern void locks_remove_posix(struct file *, fl_owner_t id);
+extern void locks_remove_flock(struct file *);
+extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
+extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
+extern void posix_block_lock(struct file_lock *, struct file_lock *);
+extern void posix_unblock_lock(struct file_lock *);
+
+struct fasync_struct {
+ int magic;
+ int fa_fd;
+ struct fasync_struct *fa_next; /* singly linked list */
+ struct file *fa_file;
+};
+
+#define FASYNC_MAGIC 0x4601
+
+extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
+
+#include <linux/minix_fs_sb.h>
+#include <linux/ext2_fs_sb.h>
+#include <linux/hpfs_fs_sb.h>
+#include <linux/ntfs_fs_sb.h>
+#include <linux/msdos_fs_sb.h>
+#include <linux/iso_fs_sb.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/sysv_fs_sb.h>
+#include <linux/affs_fs_sb.h>
+#include <linux/ufs_fs_sb.h>
+#include <linux/efs_fs_sb.h>
+#include <linux/romfs_fs_sb.h>
+#include <linux/smb_fs_sb.h>
+#include <linux/hfs_fs_sb.h>
+#include <linux/adfs_fs_sb.h>
+#include <linux/qnx4_fs_sb.h>
+
+extern struct list_head super_blocks;
+
+#define sb_entry(list) list_entry((list), struct super_block, s_list)
+struct super_block {
+ struct list_head s_list; /* Keep this first */
+ kdev_t s_dev;
+ unsigned long s_blocksize;
+ unsigned char s_blocksize_bits;
+ unsigned char s_lock;
+ unsigned char s_rd_only;
+ unsigned char s_dirt;
+ struct file_system_type *s_type;
+ struct super_operations *s_op;
+ struct dquot_operations *dq_op;
+ unsigned long s_flags;
+ unsigned long s_magic;
+ unsigned long s_time;
+ struct dentry *s_root;
+ struct wait_queue *s_wait;
+
+ struct inode *s_ibasket;
+ short int s_ibasket_count;
+ short int s_ibasket_max;
+ struct list_head s_dirty; /* dirty inodes */
+
+ union {
+ struct minix_sb_info minix_sb;
+ struct ext2_sb_info ext2_sb;
+ struct hpfs_sb_info hpfs_sb;
+ struct ntfs_sb_info ntfs_sb;
+ struct msdos_sb_info msdos_sb;
+ struct isofs_sb_info isofs_sb;
+ struct nfs_sb_info nfs_sb;
+ struct sysv_sb_info sysv_sb;
+ struct affs_sb_info affs_sb;
+ struct ufs_sb_info ufs_sb;
+ struct efs_sb_info efs_sb;
+ struct romfs_sb_info romfs_sb;
+ struct smb_sb_info smbfs_sb;
+ struct hfs_sb_info hfs_sb;
+ struct adfs_sb_info adfs_sb;
+ struct qnx4_sb_info qnx4_sb;
+ void *generic_sbp;
+ } u;
+ /*
+ * The next field is for VFS *only*. No filesystems have any business
+ * even looking at it. You had been warned.
+ */
+ struct semaphore s_vfs_rename_sem; /* Kludge */
+};
+
+/*
+ * VFS helper functions..
+ */
+extern int vfs_rmdir(struct inode *, struct dentry *);
+extern int vfs_unlink(struct inode *, struct dentry *);
+extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+
+/*
+ * This is the "filldir" function type, used by readdir() to let
+ * the kernel specify what kind of dirent layout it wants to have.
+ * This allows the kernel to read directories into kernel space or
+ * to have different dirent layouts depending on the binary type.
+ */
+typedef int (*filldir_t)(void *, const char *, int, off_t, ino_t);
+
+struct file_operations {
+ loff_t (*llseek) (struct file *, loff_t, int);
+ ssize_t (*read) (struct file *, char *, size_t, loff_t *);
+ ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
+ int (*readdir) (struct file *, void *, filldir_t);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+ int (*mmap) (struct file *, struct vm_area_struct *);
+ int (*open) (struct inode *, struct file *);
+ int (*flush) (struct file *);
+ int (*release) (struct inode *, struct file *);
+ int (*fsync) (struct file *, struct dentry *);
+ int (*fasync) (int, struct file *, int);
+ int (*check_media_change) (kdev_t dev);
+ int (*revalidate) (kdev_t dev);
+ int (*lock) (struct file *, int, struct file_lock *);
+};
+
+struct inode_operations {
+ struct file_operations * default_file_ops;
+ int (*create) (struct inode *,struct dentry *,int);
+ struct dentry * (*lookup) (struct inode *,struct dentry *);
+ int (*link) (struct dentry *,struct inode *,struct dentry *);
+ int (*unlink) (struct inode *,struct dentry *);
+ int (*symlink) (struct inode *,struct dentry *,const char *);
+ int (*mkdir) (struct inode *,struct dentry *,int);
+ int (*rmdir) (struct inode *,struct dentry *);
+ int (*mknod) (struct inode *,struct dentry *,int,int);
+ int (*rename) (struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
+ int (*readlink) (struct dentry *, char *,int);
+ struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
+ int (*readpage) (struct file *, struct page *);
+ int (*writepage) (struct file *, struct page *);
+ int (*bmap) (struct inode *,int);
+ void (*truncate) (struct inode *);
+ int (*permission) (struct inode *, int);
+ int (*smap) (struct inode *,int);
+ int (*updatepage) (struct file *, struct page *, unsigned long, unsigned int, int);
+ int (*revalidate) (struct dentry *);
+};
+
+struct super_operations {
+ void (*read_inode) (struct inode *);
+ void (*write_inode) (struct inode *);
+ void (*put_inode) (struct inode *);
+ void (*delete_inode) (struct inode *);
+ int (*notify_change) (struct dentry *, struct iattr *);
+ void (*put_super) (struct super_block *);
+ void (*write_super) (struct super_block *);
+ int (*statfs) (struct super_block *, struct statfs *, int);
+ int (*remount_fs) (struct super_block *, int *, char *);
+ void (*clear_inode) (struct inode *);
+ void (*umount_begin) (struct super_block *);
+};
+
+struct dquot_operations {
+ void (*initialize) (struct inode *, short);
+ void (*drop) (struct inode *);
+ int (*alloc_block) (const struct inode *, unsigned long, uid_t, char);
+ int (*alloc_inode) (const struct inode *, unsigned long, uid_t);
+ void (*free_block) (const struct inode *, unsigned long);
+ void (*free_inode) (const struct inode *, unsigned long);
+ int (*transfer) (struct dentry *, struct iattr *, uid_t);
+};
+
+struct file_system_type {
+ const char *name;
+ int fs_flags;
+ struct super_block *(*read_super) (struct super_block *, void *, int);
+ struct file_system_type * next;
+};
+
+extern int register_filesystem(struct file_system_type *);
+extern int unregister_filesystem(struct file_system_type *);
+
+/* Return value for VFS lock functions - tells locks.c to lock conventionally
+ * REALLY kosha for root NFS and nfs_lock
+ */
+#define LOCK_USE_CLNT 1
+
+#define FLOCK_VERIFY_READ 1
+#define FLOCK_VERIFY_WRITE 2
+
+extern int locks_mandatory_locked(struct inode *inode);
+extern int locks_mandatory_area(int read_write, struct inode *inode,
+ struct file *filp, loff_t offset,
+ size_t count);
+
+extern inline int locks_verify_locked(struct inode *inode)
+{
+ /* Candidates for mandatory locking have the setgid bit set
+ * but no group execute bit - an otherwise meaningless combination.
+ */
+ if (IS_MANDLOCK(inode) &&
+ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ return (locks_mandatory_locked(inode));
+ return (0);
+}
+
+extern inline int locks_verify_area(int read_write, struct inode *inode,
+ struct file *filp, loff_t offset,
+ size_t count)
+{
+ /* Candidates for mandatory locking have the setgid bit set
+ * but no group execute bit - an otherwise meaningless combination.
+ */
+ if (IS_MANDLOCK(inode) &&
+ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ return (locks_mandatory_area(read_write, inode, filp, offset,
+ count));
+ return (0);
+}
+
+
+/* fs/open.c */
+
+asmlinkage int sys_open(const char *, int, int);
+asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */
+extern int do_truncate(struct dentry *, unsigned long);
+extern int get_unused_fd(void);
+extern void put_unused_fd(unsigned int);
+
+extern struct file *filp_open(const char *, int, int);
+extern int filp_close(struct file *, fl_owner_t id);
+
+extern char * getname(const char * filename);
+#define __getname() ((char *) __get_free_page(GFP_KERNEL))
+#define putname(name) free_page((unsigned long)(name))
+
+extern void kill_fasync(struct fasync_struct *fa, int sig);
+extern int register_blkdev(unsigned int, const char *, struct file_operations *);
+extern int unregister_blkdev(unsigned int major, const char * name);
+extern int blkdev_open(struct inode * inode, struct file * filp);
+extern int blkdev_release (struct inode * inode);
+extern struct file_operations def_blk_fops;
+extern struct inode_operations blkdev_inode_operations;
+
+/* fs/devices.c */
+extern int register_chrdev(unsigned int, const char *, struct file_operations *);
+extern int unregister_chrdev(unsigned int major, const char * name);
+extern int chrdev_open(struct inode * inode, struct file * filp);
+extern struct file_operations def_chr_fops;
+extern struct inode_operations chrdev_inode_operations;
+extern char * bdevname(kdev_t dev);
+extern char * cdevname(kdev_t dev);
+extern char * kdevname(kdev_t dev);
+
+
+extern void init_fifo(struct inode * inode);
+extern struct inode_operations fifo_inode_operations;
+
+/* Invalid inode operations -- fs/bad_inode.c */
+extern void make_bad_inode(struct inode * inode);
+extern int is_bad_inode(struct inode * inode);
+
+extern struct file_operations connecting_fifo_fops;
+extern struct file_operations read_fifo_fops;
+extern struct file_operations write_fifo_fops;
+extern struct file_operations rdwr_fifo_fops;
+extern struct file_operations read_pipe_fops;
+extern struct file_operations write_pipe_fops;
+extern struct file_operations rdwr_pipe_fops;
+
+extern struct file_system_type *get_fs_type(const char *name);
+
+extern int fs_may_remount_ro(struct super_block *);
+extern int fs_may_mount(kdev_t dev);
+
+extern struct file *inuse_filps;
+
+extern void refile_buffer(struct buffer_head * buf);
+extern void set_writetime(struct buffer_head * buf, int flag);
+extern int try_to_free_buffers(struct page *);
+
+extern int nr_buffers;
+extern long buffermem;
+extern int nr_buffer_heads;
+
+#define BUF_CLEAN 0
+#define BUF_LOCKED 1 /* Buffers scheduled for write */
+#define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */
+#define NR_LIST 3
+
+void mark_buffer_uptodate(struct buffer_head * bh, int on);
+
+extern inline void mark_buffer_clean(struct buffer_head * bh)
+{
+ if (test_and_clear_bit(BH_Dirty, &bh->b_state)) {
+ if (bh->b_list == BUF_DIRTY)
+ refile_buffer(bh);
+ }
+}
+
+extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
+{
+ if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
+ set_writetime(bh, flag);
+ if (bh->b_list != BUF_DIRTY)
+ refile_buffer(bh);
+ }
+}
+
+extern int check_disk_change(kdev_t dev);
+extern int invalidate_inodes(struct super_block * sb);
+extern void invalidate_inode_pages(struct inode *);
+#define invalidate_buffers(dev) __invalidate_buffers((dev), 0)
+#define destroy_buffers(dev) __invalidate_buffers((dev), 1)
+extern void __invalidate_buffers(kdev_t dev, int);
+extern int floppy_is_wp(int minor);
+extern void sync_inodes(kdev_t dev);
+extern void write_inode_now(struct inode *inode);
+extern void sync_dev(kdev_t dev);
+extern int fsync_dev(kdev_t dev);
+extern void sync_supers(kdev_t dev);
+extern int bmap(struct inode * inode,int block);
+extern int notify_change(struct dentry *, struct iattr *);
+extern int permission(struct inode * inode,int mask);
+extern int get_write_access(struct inode *inode);
+extern void put_write_access(struct inode *inode);
+extern struct dentry * open_namei(const char * pathname, int flag, int mode);
+extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
+extern int do_pipe(int *);
+
+/* fs/dcache.c -- generic fs support functions */
+extern int is_subdir(struct dentry *, struct dentry *);
+extern ino_t find_inode_number(struct dentry *, struct qstr *);
+
+/*
+ * Kernel pointers have redundant information, so we can use a
+ * scheme where we can return either an error code or a dentry
+ * pointer with the same return value.
+ *
+ * This should be a per-architecture thing, to allow different
+ * error and pointer decisions.
+ */
+#define ERR_PTR(err) ((void *)((long)(err)))
+#define PTR_ERR(ptr) ((long)(ptr))
+#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
+
+/*
+ * The bitmask for a lookup event:
+ * - follow links at the end
+ * - require a directory
+ * - ending slashes ok even for nonexistent files
+ * - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW (1)
+#define LOOKUP_DIRECTORY (2)
+#define LOOKUP_SLASHOK (4)
+#define LOOKUP_CONTINUE (8)
+
+extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int);
+extern struct dentry * __namei(const char *, unsigned int);
+
+#define namei(pathname) __namei(pathname, 1)
+#define lnamei(pathname) __namei(pathname, 0)
+
+extern void iput(struct inode *);
+extern struct inode * igrab(struct inode *inode);
+extern ino_t iunique(struct super_block *, ino_t);
+extern struct inode * iget(struct super_block *, unsigned long);
+extern struct inode * iget_in_use (struct super_block *, unsigned long);
+extern void clear_inode(struct inode *);
+extern struct inode * get_empty_inode(void);
+
+extern void insert_inode_hash(struct inode *);
+extern void remove_inode_hash(struct inode *);
+extern struct file * get_empty_filp(void);
+extern struct buffer_head * get_hash_table(kdev_t, int, int);
+extern struct buffer_head * getblk(kdev_t, int, int);
+extern struct buffer_head * find_buffer(kdev_t dev, int block, int size);
+extern void ll_rw_block(int, int, struct buffer_head * bh[]);
+extern int is_read_only(kdev_t);
+extern void __brelse(struct buffer_head *);
+extern inline void brelse(struct buffer_head *buf)
+{
+ if (buf)
+ __brelse(buf);
+}
+extern void __bforget(struct buffer_head *buf);
+extern inline void bforget(struct buffer_head *buf)
+{
+ if (buf)
+ __bforget(buf);
+}
+extern void set_blocksize(kdev_t dev, int size);
+extern unsigned int get_hardblocksize(kdev_t dev);
+extern struct buffer_head * bread(kdev_t dev, int block, int size);
+extern struct buffer_head * breada(kdev_t dev,int block, int size,
+ unsigned int pos, unsigned int filesize);
+
+extern int brw_page(int, struct page *, kdev_t, int [], int, int);
+
+extern int generic_readpage(struct file *, struct page *);
+extern int generic_file_mmap(struct file *, struct vm_area_struct *);
+extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t generic_file_write(struct file *, const char*, size_t, loff_t*);
+
+extern struct super_block *get_super(kdev_t dev);
+extern void put_super(kdev_t dev);
+unsigned long generate_cluster(kdev_t dev, int b[], int size);
+unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size);
+extern kdev_t ROOT_DEV;
+
+extern void show_buffers(void);
+extern void mount_root(void);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern kdev_t real_root_dev;
+extern int change_root(kdev_t new_root_dev,const char *put_old);
+#endif
+
+extern ssize_t char_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t block_read(struct file *, char *, size_t, loff_t *);
+extern int read_ahead[];
+
+extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
+extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
+
+extern int block_fsync(struct file *, struct dentry *dir);
+extern int file_fsync(struct file *, struct dentry *dir);
+
+extern int inode_change_ok(struct inode *, struct iattr *);
+extern void inode_setattr(struct inode *, struct iattr *);
+
+extern __u32 inode_generation_count;
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/ftape-header-segment.h b/pfinet/linux-src/include/linux/ftape-header-segment.h
new file mode 100644
index 00000000..4732218f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ftape-header-segment.h
@@ -0,0 +1,122 @@
+#ifndef _FTAPE_HEADER_SEGMENT_H
+#define _FTAPE_HEADER_SEGMENT_H
+
+/*
+ * Copyright (C) 1996-1997 Claus-Justus Heine.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/include/linux/ftape-header-segment.h,v $
+ * $Revision: 1.2 $
+ * $Date: 1997/10/05 19:19:28 $
+ *
+ * This file defines some offsets into the header segment of a
+ * floppy tape cartridge. For use with the QIC-40/80/3010/3020
+ * floppy-tape driver "ftape" for Linux.
+ */
+
+#define FT_SIGNATURE 0 /* must be 0xaa55aa55 */
+#define FT_FMT_CODE 4
+#define FT_REV_LEVEL 5 /* only for QIC-80 since. Rev. L (== 0x0c) */
+#define FT_HSEG_1 6 /* first header segment, except for format code 6 */
+#define FT_HSEG_2 8 /* second header segment, except for format code 6 */
+#define FT_FRST_SEG 10 /* first data segment, except for format code 6 */
+#define FT_LAST_SEG 12 /* last data segment, except for format code 6 */
+#define FT_FMT_DATE 14 /* date and time of most recent format, see below */
+#define FT_WR_DATE 18 /* date and time of most recent write or format */
+#define FT_SPT 24 /* segments per track */
+#define FT_TPC 26 /* tracks per cartridge */
+#define FT_FHM 27 /* floppy drive head (maximum of it) */
+#define FT_FTM 28 /* floppy track max. */
+#define FT_FSM 29 /* floppy sector max. (128) */
+#define FT_LABEL 30 /* floppy tape label */
+#define FT_LABEL_DATE 74 /* date and time the tape label was written */
+#define FT_LABEL_SZ (FT_LABEL_DATE - FT_LABEL)
+#define FT_CMAP_START 78 /* starting segment of compression map */
+#define FT_FMT_ERROR 128 /* must be set to 0xff if remainder gets lost during
+ * tape format
+ */
+#define FT_SEG_CNT 130 /* number of seg. written, formatted or verified
+ * through lifetime of tape (why not read?)
+ */
+#define FT_INIT_DATE 138 /* date and time of initial tape format */
+#define FT_FMT_CNT 142 /* number of times tape has been formatted */
+#define FT_FSL_CNT 144 /* number of segments in failed sector log */
+#define FT_MK_CODE 146 /* id string of tape manufacturer */
+#define FT_LOT_CODE 190 /* tape manufacturer lot code */
+#define FT_6_HSEG_1 234 /* first header segment for format code 6 */
+#define FT_6_HSEG_2 238 /* second header segment for format code 6 */
+#define FT_6_FRST_SEG 242 /* first data segment for format code 6 */
+#define FT_6_LAST_SEG 246 /* last data segment for format code 6 */
+
+#define FT_FSL 256
+#define FT_HEADER_END 256 /* space beyond this point:
+ * format codes 2, 3 and 5:
+ * - failed sector log until byte 2047
+ * - bad sector map in the reamining part of segment
+ * format codes 4 and 6:
+ * - bad sector map starts hear
+ */
+
+
+/* value to be stored at the FT_SIGNATURE offset
+ */
+#define FT_HSEG_MAGIC 0xaa55aa55
+#define FT_D2G_MAGIC 0x82288228 /* Ditto 2GB */
+
+/* data and time encoding: */
+#define FT_YEAR_SHIFT 25
+#define FT_YEAR_MASK 0xfe000000
+#define FT_YEAR_0 1970
+#define FT_YEAR_MAX 127
+#define FT_YEAR(year) ((((year)-FT_YEAR_0)<<FT_YEAR_SHIFT)&FT_YEAR_MASK)
+
+#define FT_TIME_SHIFT 0
+#define FT_TIME_MASK 0x01FFFFFF
+#define FT_TIME_MAX 0x01ea6dff /* last second of a year */
+#define FT_TIME(mo,d,h,m,s) \
+ ((((s)+60*((m)+60*((h)+24*((d)+31*(mo))))) & FT_TIME_MASK))
+
+#define FT_TIME_STAMP(y,mo,d,h,m,s) (FT_YEAR(y) | FT_TIME(mo,d,h,m,s))
+
+/* values for the format code field */
+typedef enum {
+ fmt_normal = 2, /* QIC-80 post Rev. B 205Ft or 307Ft tape */
+ fmt_1100ft = 3, /* QIC-80 post Rev. B 1100Ft tape */
+ fmt_var = 4, /* QIC-80 post Rev. B variabel length format */
+ fmt_425ft = 5, /* QIC-80 post Rev. B 425Ft tape */
+ fmt_big = 6 /* QIC-3010/3020 variable length tape with more
+ * than 2^16 segments per tape
+ */
+} ft_format_type;
+
+/* definitions for the failed sector log */
+#define FT_FSL_SIZE (2 * FT_SECTOR_SIZE - FT_HEADER_END)
+#define FT_FSL_MAX_ENTRIES (FT_FSL_SIZE/sizeof(__u32))
+
+typedef struct ft_fsl_entry {
+ __u16 segment;
+ __u16 date;
+} __attribute__ ((packed)) ft_fsl_entry;
+
+
+/* date encoding for the failed sector log
+ * month: 1..12, day: 1..31, year: 1970..2097
+ */
+#define FT_FSL_TIME_STAMP(y,m,d) \
+ (((((y) - FT_YEAR_0)<<9)&0xfe00) | (((m)<<5)&0x01e0) | ((d)&0x001f))
+
+#endif /* _FTAPE_HEADER_SEGMENT_H */
diff --git a/pfinet/linux-src/include/linux/ftape-vendors.h b/pfinet/linux-src/include/linux/ftape-vendors.h
new file mode 100644
index 00000000..ec1a81f0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ftape-vendors.h
@@ -0,0 +1,137 @@
+#ifndef _FTAPE_VENDORS_H
+#define _FTAPE_VENDORS_H
+
+/*
+ * Copyright (C) 1993-1996 Bas Laarhoven,
+ * (C) 1996-1997 Claus-Justus Heine.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/include/linux/ftape-vendors.h,v $
+ * $Revision: 1.6 $
+ * $Date: 1997/10/09 15:38:11 $
+ *
+ * This file contains the supported drive types with their
+ * QIC-117 spec. vendor code and drive dependent configuration
+ * information.
+ */
+
+typedef enum {
+ unknown_wake_up = 0,
+ no_wake_up,
+ wake_up_colorado,
+ wake_up_mountain,
+ wake_up_insight,
+} wake_up_types;
+
+typedef struct {
+ wake_up_types wake_up; /* see wake_up_types */
+ char *name; /* Text describing the drive */
+} wakeup_method;
+
+/* Note: order of entries in WAKEUP_METHODS must be so that a variable
+ * of type wake_up_types can be used as an index in the array.
+ */
+#define WAKEUP_METHODS { \
+ { unknown_wake_up, "Unknown" }, \
+ { no_wake_up, "None" }, \
+ { wake_up_colorado, "Colorado" }, \
+ { wake_up_mountain, "Mountain" }, \
+ { wake_up_insight, "Motor-on" }, \
+}
+
+typedef struct {
+ unsigned int vendor_id; /* vendor id from drive */
+ int speed; /* maximum tape transport speed (ips) */
+ wake_up_types wake_up; /* see wake_up_types */
+ char *name; /* Text describing the drive */
+} vendor_struct;
+
+#define UNKNOWN_VENDOR (-1)
+
+#define QIC117_VENDORS { \
+/* see _vendor_struct */ \
+ { 0x00000, 82, wake_up_colorado, "Colorado DJ-10 (old)" }, \
+ { 0x00047, 90, wake_up_colorado, "Colorado DJ-10/DJ-20" }, \
+ { 0x011c2, 84, wake_up_colorado, "Colorado 700" }, \
+ { 0x011c3, 90, wake_up_colorado, "Colorado 1400" }, \
+ { 0x011c4, 84, wake_up_colorado, "Colorado DJ-10/DJ-20 (new)" }, \
+ { 0x011c5, 84, wake_up_colorado, "HP Colorado T1000" }, \
+ { 0x011c6, 90, wake_up_colorado, "HP Colorado T3000" }, \
+ { 0x00005, 45, wake_up_mountain, "Archive 5580i" }, \
+ { 0x10005, 50, wake_up_insight, "Insight 80Mb, Irwin 80SX" }, \
+ { 0x00140, 74, wake_up_mountain, "Archive S.Hornet [Identity/Escom]" }, \
+ { 0x00146, 72, wake_up_mountain, "Archive 31250Q [Escom]" }, \
+ { 0x0014a, 100, wake_up_mountain, "Archive XL9250i [Conner/Escom]" }, \
+ { 0x0014c, 98, wake_up_mountain, "Conner C250MQT" }, \
+ { 0x0014e, 80, wake_up_mountain, "Conner C250MQ" }, \
+ { 0x00150, 80, wake_up_mountain, "Conner TSM420R/TST800R" }, \
+ { 0x00152, 80, wake_up_mountain, "Conner TSM850R" }, \
+ { 0x00156, 80, wake_up_mountain, "Conner TSM850R/1700R/TST3200R" }, \
+ { 0x00180, 0, wake_up_mountain, "Summit SE 150" }, \
+ { 0x00181, 85, wake_up_mountain, "Summit SE 250, Mountain FS8000" }, \
+ { 0x001c1, 82, no_wake_up, "Wangtek 3040F" }, \
+ { 0x001c8, 64, no_wake_up, "Wangtek 3080F" }, \
+ { 0x001c8, 64, wake_up_colorado, "Wangtek 3080F" }, \
+ { 0x001ca, 67, no_wake_up, "Wangtek 3080F (new)" }, \
+ { 0x001cc, 77, wake_up_colorado, "Wangtek 3200 / Teac 700" }, \
+ { 0x001cd, 75, wake_up_colorado, "Reveal TB1400" }, \
+ { 0x00380, 85, wake_up_colorado, "Exabyte Eagle-96" }, \
+ { 0x00381, 85, wake_up_colorado, "Exabyte Eagle TR-3" }, \
+ { 0x00382, 85, wake_up_colorado, "Exabyte Eagle TR-3" }, \
+ { 0x003ce, 77, wake_up_colorado, "Teac 800" }, \
+ { 0x003cf, 0, wake_up_colorado, "Teac FT3010TR" }, \
+ { 0x08880, 64, no_wake_up, "Iomega 250, Ditto 800" }, \
+ { 0x08880, 64, wake_up_colorado, "Iomega 250, Ditto 800" }, \
+ { 0x08880, 64, wake_up_insight, "Iomega 250, Ditto 800" }, \
+ { 0x08881, 80, wake_up_colorado, "Iomega 700" }, \
+ { 0x08882, 80, wake_up_colorado, "Iomega 3200" }, \
+ { 0x08883, 80, wake_up_colorado, "Iomega DITTO 2GB" }, \
+ { 0x00021, 70, no_wake_up, "AIWA CT-803" }, \
+ { 0x004c0, 80, no_wake_up, "AIWA TD-S1600" }, \
+ { 0x00021, 0, wake_up_mountain, "COREtape QIC80" }, \
+ { 0x00441, 0, wake_up_mountain, "ComByte DoublePlay" }, \
+ { 0x00481, 127, wake_up_mountain, "PERTEC MyTape 800" }, \
+ { 0x00483, 130, wake_up_mountain, "PERTEC MyTape 3200" }, \
+ { UNKNOWN_VENDOR, 0, no_wake_up, "unknown" } \
+}
+
+#define QIC117_MAKE_CODES { \
+ { 0, "Unassigned" }, \
+ { 1, "Alloy Computer Products" }, \
+ { 2, "3M" }, \
+ { 3, "Tandberg Data" }, \
+ { 4, "Colorado" }, \
+ { 5, "Archive/Conner" }, \
+ { 6, "Mountain/Summit Memory Systems" }, \
+ { 7, "Wangtek/Rexon/Tecmar" }, \
+ { 8, "Sony" }, \
+ { 9, "Cipher Data Products" }, \
+ { 10, "Irwin Magnetic Systems" }, \
+ { 11, "Braemar" }, \
+ { 12, "Verbatim" }, \
+ { 13, "Core International" }, \
+ { 14, "Exabyte" }, \
+ { 15, "Teac" }, \
+ { 16, "Gigatek" }, \
+ { 17, "ComByte" }, \
+ { 18, "PERTEC Memories" }, \
+ { 19, "Aiwa" }, \
+ { 71, "Colorado" }, \
+ { 546, "Iomega Inc" }, \
+}
+
+#endif /* _FTAPE_VENDORS_H */
diff --git a/pfinet/linux-src/include/linux/ftape.h b/pfinet/linux-src/include/linux/ftape.h
new file mode 100644
index 00000000..a26f2e51
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ftape.h
@@ -0,0 +1,212 @@
+#ifndef _FTAPE_H
+#define _FTAPE_H
+
+/*
+ * Copyright (C) 1994-1996 Bas Laarhoven,
+ * (C) 1996-1997 Claus-Justus Heine.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/include/linux/ftape.h,v $
+ * $Revision: 1.17.6.4 $
+ * $Date: 1997/11/25 01:52:54 $
+ *
+ * This file contains global definitions, typedefs and macro's
+ * for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
+ */
+
+#define FTAPE_VERSION "ftape v3.04d 25/11/97"
+
+/* this makes the Kernel version numbers readable */
+#define KERNEL_VER(major,minor,sublvl) (((major)<<16)+((minor)<<8)+(sublvl))
+
+#ifdef __KERNEL__
+#include <linux/sched.h>
+#include <linux/mm.h>
+#endif
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#if LINUX_VERSION_CODE <= KERNEL_VER(1,2,13)
+typedef daddr_t __kernel_daddr_t; /* needed for mtio.h */
+#endif
+#include <linux/mtio.h>
+
+#define FT_SECTOR(x) (x+1) /* sector offset into real sector */
+#define FT_SECTOR_SIZE 1024
+#define FT_SECTORS_PER_SEGMENT 32
+#define FT_ECC_SECTORS 3
+#define FT_SEGMENT_SIZE ((FT_SECTORS_PER_SEGMENT - FT_ECC_SECTORS) * FT_SECTOR_SIZE)
+#define FT_BUFF_SIZE (FT_SECTORS_PER_SEGMENT * FT_SECTOR_SIZE)
+
+/*
+ * bits of the minor device number that define drive selection
+ * methods. Could be used one day to access multiple tape
+ * drives on the same controller.
+ */
+#define FTAPE_SEL_A 0
+#define FTAPE_SEL_B 1
+#define FTAPE_SEL_C 2
+#define FTAPE_SEL_D 3
+#define FTAPE_SEL_MASK 3
+#define FTAPE_SEL(unit) ((unit) & FTAPE_SEL_MASK)
+#define FTAPE_NO_REWIND 4 /* mask for minor nr */
+
+/* the following two may be reported when MTIOCGET is requested ... */
+typedef union {
+ struct {
+ __u8 error;
+ __u8 command;
+ } error;
+ long space;
+} ft_drive_error;
+typedef union {
+ struct {
+ __u8 drive_status;
+ __u8 drive_config;
+ __u8 tape_status;
+ } status;
+ long space;
+} ft_drive_status;
+
+#ifdef __KERNEL__
+
+#define FT_RQM_DELAY 12
+#define FT_MILLISECOND 1
+#define FT_SECOND 1000
+#define FT_FOREVER -1
+#ifndef HZ
+#error "HZ undefined."
+#endif
+#define FT_USPT (1000000/HZ) /* microseconds per tick */
+
+/* This defines the number of retries that the driver will allow
+ * before giving up (and letting a higher level handle the error).
+ */
+#ifdef TESTING
+#define FT_SOFT_RETRIES 1 /* number of low level retries */
+#define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */
+#else
+#define FT_SOFT_RETRIES 6 /* number of low level retries (triple) */
+#define FT_RETRIES_ON_ECC_ERROR 3 /* ecc error when correcting segment */
+#endif
+
+#ifndef THE_FTAPE_MAINTAINER
+#define THE_FTAPE_MAINTAINER "the ftape maintainer"
+#endif
+
+/* Initialize missing configuration parameters.
+ */
+#ifndef CONFIG_FT_NR_BUFFERS
+# define CONFIG_FT_NR_BUFFERS 3
+#endif
+#ifndef CONFIG_FT_FDC_THR
+# define CONFIG_FT_FDC_THR 8
+#endif
+#ifndef CONFIG_FT_FDC_MAX_RATE
+# define CONFIG_FT_FDC_MAX_RATE 2000
+#endif
+#ifndef CONFIG_FT_FDC_BASE
+# define CONFIG_FT_FDC_BASE 0
+#endif
+#ifndef CONFIG_FT_FDC_IRQ
+# define CONFIG_FT_FDC_IRQ 0
+#endif
+#ifndef CONFIG_FT_FDC_DMA
+# define CONFIG_FT_FDC_DMA 0
+#endif
+
+/* Turn some booleans into numbers.
+ */
+#ifdef CONFIG_FT_PROBE_FC10
+# undef CONFIG_FT_PROBE_FC10
+# define CONFIG_FT_PROBE_FC10 1
+#else
+# define CONFIG_FT_PROBE_FC10 0
+#endif
+#ifdef CONFIG_FT_MACH2
+# undef CONFIG_FT_MACH2
+# define CONFIG_FT_MACH2 1
+#else
+# define CONFIG_FT_MACH2 0
+#endif
+
+/* Insert default settings
+ */
+#if CONFIG_FT_PROBE_FC10 == 1
+# if CONFIG_FT_FDC_BASE == 0
+# undef CONFIG_FT_FDC_BASE
+# define CONFIG_FT_FDC_BASE 0x180
+# endif
+# if CONFIG_FT_FDC_IRQ == 0
+# undef CONFIG_FT_FDC_IRQ
+# define CONFIG_FT_FDC_IRQ 9
+# endif
+# if CONFIG_FT_FDC_DMA == 0
+# undef CONFIG_FT_FDC_DMA
+# define CONFIG_FT_FDC_DMA 3
+# endif
+#elif CONFIG_FT_MACH2 == 1 /* CONFIG_FT_PROBE_FC10 == 1 */
+# if CONFIG_FT_FDC_BASE == 0
+# undef CONFIG_FT_FDC_BASE
+# define CONFIG_FT_FDC_BASE 0x1E0
+# endif
+# if CONFIG_FT_FDC_IRQ == 0
+# undef CONFIG_FT_FDC_IRQ
+# define CONFIG_FT_FDC_IRQ 6
+# endif
+# if CONFIG_FT_FDC_DMA == 0
+# undef CONFIG_FT_FDC_DMA
+# define CONFIG_FT_FDC_DMA 2
+# endif
+#elif CONFIG_FT_ALT_FDC == 1 /* CONFIG_FT_MACH2 */
+# if CONFIG_FT_FDC_BASE == 0
+# undef CONFIG_FT_FDC_BASE
+# define CONFIG_FT_FDC_BASE 0x370
+# endif
+# if CONFIG_FT_FDC_IRQ == 0
+# undef CONFIG_FT_FDC_IRQ
+# define CONFIG_FT_FDC_IRQ 6
+# endif
+# if CONFIG_FT_FDC_DMA == 0
+# undef CONFIG_FT_FDC_DMA
+# define CONFIG_FT_FDC_DMA 2
+# endif
+#else /* CONFIG_FT_ALT_FDC */
+# if CONFIG_FT_FDC_BASE == 0
+# undef CONFIG_FT_FDC_BASE
+# define CONFIG_FT_FDC_BASE 0x3f0
+# endif
+# if CONFIG_FT_FDC_IRQ == 0
+# undef CONFIG_FT_FDC_IRQ
+# define CONFIG_FT_FDC_IRQ 6
+# endif
+# if CONFIG_FT_FDC_DMA == 0
+# undef CONFIG_FT_FDC_DMA
+# define CONFIG_FT_FDC_DMA 2
+# endif
+#endif /* standard FDC */
+
+/* some useful macro's
+ */
+#define ABS(a) ((a) < 0 ? -(a) : (a))
+#define NR_ITEMS(x) (int)(sizeof(x)/ sizeof(*x))
+
+extern int ftape_init(void);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/genhd.h b/pfinet/linux-src/include/linux/genhd.h
new file mode 100644
index 00000000..1b625319
--- /dev/null
+++ b/pfinet/linux-src/include/linux/genhd.h
@@ -0,0 +1,267 @@
+#ifndef _LINUX_GENHD_H
+#define _LINUX_GENHD_H
+
+/*
+ * genhd.h Copyright (C) 1992 Drew Eckhardt
+ * Generic hard disk header file by
+ * Drew Eckhardt
+ *
+ * <drew@colorado.edu>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/unaligned.h>
+
+#define CONFIG_MSDOS_PARTITION 1
+
+#ifdef __alpha__
+#define CONFIG_OSF_PARTITION 1
+#endif
+
+#if defined(__sparc__) || defined(CONFIG_SMD_DISKLABEL)
+#define CONFIG_SUN_PARTITION 1
+#endif
+
+#if defined(CONFIG_SGI)
+#define CONFIG_SGI_PARTITION 1
+#endif
+
+/* These three have identical behaviour; use the second one if DOS fdisk gets
+ confused about extended/logical partitions starting past cylinder 1023. */
+#define DOS_EXTENDED_PARTITION 5
+#define LINUX_EXTENDED_PARTITION 0x85
+#define WIN98_EXTENDED_PARTITION 0x0f
+
+#define LINUX_SWAP_PARTITION 0x82
+#define LINUX_RAID_PARTITION 0xfd /* autodetect RAID partition */
+#define LINUX_OLD_RAID_PARTITION 0x86
+
+#ifdef CONFIG_SOLARIS_X86_PARTITION
+#define SOLARIS_X86_PARTITION LINUX_SWAP_PARTITION
+#endif
+
+#define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */
+#define EZD_PARTITION 0x55 /* EZ-DRIVE: remap sector 1 to 0 */
+#define DM6_AUX1PARTITION 0x51 /* no DDO: use xlated geom */
+#define DM6_AUX3PARTITION 0x53 /* no DDO: use xlated geom */
+
+
+struct partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned int start_sect; /* starting sector counting from 0 */
+ unsigned int nr_sects; /* nr of sectors in partition */
+} __attribute__((packed));
+
+struct hd_struct {
+ long start_sect;
+ long nr_sects;
+ int type; /* RAID or normal */
+};
+
+/*
+ * partition types Linux cares about.
+ *
+ * currently there are 'normal' and RAID types.
+ */
+
+static inline unsigned int ptype (unsigned char raw_type)
+{
+ switch (raw_type) {
+ case LINUX_OLD_RAID_PARTITION:
+ return LINUX_OLD_RAID_PARTITION;
+ case LINUX_RAID_PARTITION:
+ return LINUX_RAID_PARTITION;
+ default:
+ }
+ return 0;
+}
+
+/*
+ * the maximum length a given partition name can take (eg. "scd11")
+ */
+#define MAX_DISKNAME_LEN 32
+
+struct gendisk {
+ int major; /* major number of driver */
+ const char *major_name; /* name of major driver */
+ int minor_shift; /* number of times minor is shifted to
+ get real minor */
+ int max_p; /* maximum partitions per device */
+ int max_nr; /* maximum number of real devices */
+
+ void (*init)(struct gendisk *); /* Initialization called before we do our thing */
+ struct hd_struct *part; /* partition table */
+ int *sizes; /* device size in blocks, copied to blk_size[] */
+ int nr_real; /* number of real devices */
+
+ void *real_devices; /* internal use */
+ struct gendisk *next;
+};
+
+#ifdef CONFIG_SOLARIS_X86_PARTITION
+
+#define SOLARIS_X86_NUMSLICE 8
+#define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL)
+
+struct solaris_x86_slice {
+ ushort s_tag; /* ID tag of partition */
+ ushort s_flag; /* permision flags */
+ daddr_t s_start; /* start sector no of partition */
+ long s_size; /* # of blocks in partition */
+};
+
+struct solaris_x86_vtoc {
+ unsigned long v_bootinfo[3]; /* info needed by mboot (unsupported) */
+ unsigned long v_sanity; /* to verify vtoc sanity */
+ unsigned long v_version; /* layout version */
+ char v_volume[8]; /* volume name */
+ ushort v_sectorsz; /* sector size in bytes */
+ ushort v_nparts; /* number of partitions */
+ unsigned long v_reserved[10]; /* free space */
+ struct solaris_x86_slice
+ v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */
+ time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */
+ char v_asciilabel[128]; /* for compatibility */
+};
+
+#endif /* CONFIG_SOLARIS_X86_PARTITION */
+
+#ifdef CONFIG_BSD_DISKLABEL
+/*
+ * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
+ * updated by Marc Espie <Marc.Espie@openbsd.org>
+ */
+#define FREEBSD_PARTITION 0xa5 /* FreeBSD Partition ID */
+#define OPENBSD_PARTITION 0xa6 /* OpenBSD Partition ID */
+#define NETBSD_PARTITION 0xa9 /* NetBSD Partition ID */
+#define BSDI_PARTITION 0xb7 /* BSDI Partition ID */
+
+/* Ours is not to wonder why.. */
+#define BSD_PARTITION FREEBSD_PARTITION
+
+/* check against BSD src/sys/sys/disklabel.h for consistency */
+
+#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
+#define BSD_MAXPARTITIONS 8
+#define OPENBSD_MAXPARTITIONS 16
+#define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
+struct bsd_disklabel {
+ __u32 d_magic; /* the magic number */
+ __s16 d_type; /* drive type */
+ __s16 d_subtype; /* controller/d_type specific */
+ char d_typename[16]; /* type name, e.g. "eagle" */
+ char d_packname[16]; /* pack identifier */
+ __u32 d_secsize; /* # of bytes per sector */
+ __u32 d_nsectors; /* # of data sectors per track */
+ __u32 d_ntracks; /* # of tracks per cylinder */
+ __u32 d_ncylinders; /* # of data cylinders per unit */
+ __u32 d_secpercyl; /* # of data sectors per cylinder */
+ __u32 d_secperunit; /* # of data sectors per unit */
+ __u16 d_sparespertrack; /* # of spare sectors per track */
+ __u16 d_sparespercyl; /* # of spare sectors per cylinder */
+ __u32 d_acylinders; /* # of alt. cylinders per unit */
+ __u16 d_rpm; /* rotational speed */
+ __u16 d_interleave; /* hardware sector interleave */
+ __u16 d_trackskew; /* sector 0 skew, per track */
+ __u16 d_cylskew; /* sector 0 skew, per cylinder */
+ __u32 d_headswitch; /* head switch time, usec */
+ __u32 d_trkseek; /* track-to-track seek, usec */
+ __u32 d_flags; /* generic flags */
+#define NDDATA 5
+ __u32 d_drivedata[NDDATA]; /* drive-type specific information */
+#define NSPARE 5
+ __u32 d_spare[NSPARE]; /* reserved for future use */
+ __u32 d_magic2; /* the magic number (again) */
+ __u16 d_checksum; /* xor of data incl. partitions */
+
+ /* filesystem and partition information: */
+ __u16 d_npartitions; /* number of partitions in following */
+ __u32 d_bbsize; /* size of boot area at sn0, bytes */
+ __u32 d_sbsize; /* max size of fs superblock, bytes */
+ struct bsd_partition { /* the partition table */
+ __u32 p_size; /* number of sectors in partition */
+ __u32 p_offset; /* starting sector */
+ __u32 p_fsize; /* filesystem basic fragment size */
+ __u8 p_fstype; /* filesystem type, see below */
+ __u8 p_frag; /* filesystem fragments per block */
+ __u16 p_cpg; /* filesystem cylinders per group */
+ } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+};
+
+#endif /* CONFIG_BSD_DISKLABEL */
+
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+/*
+ * Unixware slices support by Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
+ * and Krzysztof G. Baranowski <kgb@knm.org.pl>
+ */
+
+#define UNIXWARE_PARTITION 0x63 /* Partition ID, same as */
+ /* GNU_HURD and SCO Unix */
+#define UNIXWARE_DISKMAGIC (0xCA5E600DUL) /* The disk magic number */
+#define UNIXWARE_DISKMAGIC2 (0x600DDEEEUL) /* The slice table magic nr */
+#define UNIXWARE_NUMSLICE 16
+#define UNIXWARE_FS_UNUSED 0 /* Unused slice entry ID */
+
+struct unixware_slice {
+ __u16 s_label; /* label */
+ __u16 s_flags; /* permission flags */
+ __u32 start_sect; /* starting sector */
+ __u32 nr_sects; /* number of sectors in slice */
+};
+
+struct unixware_disklabel {
+ __u32 d_type; /* drive type */
+ __u32 d_magic; /* the magic number */
+ __u32 d_version; /* version number */
+ char d_serial[12]; /* serial number of the device */
+ __u32 d_ncylinders; /* # of data cylinders per device */
+ __u32 d_ntracks; /* # of tracks per cylinder */
+ __u32 d_nsectors; /* # of data sectors per track */
+ __u32 d_secsize; /* # of bytes per sector */
+ __u32 d_part_start; /* # of first sector of this partition */
+ __u32 d_unknown1[12]; /* ? */
+ __u32 d_alt_tbl; /* byte offset of alternate table */
+ __u32 d_alt_len; /* byte length of alternate table */
+ __u32 d_phys_cyl; /* # of physical cylinders per device */
+ __u32 d_phys_trk; /* # of physical tracks per cylinder */
+ __u32 d_phys_sec; /* # of physical sectors per track */
+ __u32 d_phys_bytes; /* # of physical bytes per sector */
+ __u32 d_unknown2; /* ? */
+ __u32 d_unknown3; /* ? */
+ __u32 d_pad[8]; /* pad */
+
+ struct unixware_vtoc {
+ __u32 v_magic; /* the magic number */
+ __u32 v_version; /* version number */
+ char v_name[8]; /* volume name */
+ __u16 v_nslices; /* # of slices */
+ __u16 v_unknown1; /* ? */
+ __u32 v_reserved[10]; /* reserved */
+ struct unixware_slice
+ v_slice[UNIXWARE_NUMSLICE]; /* slice headers */
+ } vtoc;
+
+}; /* 408 */
+
+#endif /* CONFIG_UNIXWARE_DISKLABEL */
+
+extern struct gendisk *gendisk_head; /* linked list of disks */
+
+/*
+ * disk_name() is used by genhd.c and md.c.
+ * It formats the devicename of the indicated disk
+ * into the supplied buffer, and returns a pointer
+ * to that same buffer (for convenience).
+ */
+char *disk_name (struct gendisk *hd, int minor, char *buf);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/ghash.h b/pfinet/linux-src/include/linux/ghash.h
new file mode 100644
index 00000000..278f6c2f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ghash.h
@@ -0,0 +1,218 @@
+/*
+ * include/linux/ghash.h -- generic hashing with fuzzy retrieval
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ *
+ * The algorithms implemented here seem to be a completely new invention,
+ * and I'll publish the fundamentals in a paper.
+ */
+
+#ifndef _GHASH_H
+#define _GHASH_H
+/* HASHSIZE _must_ be a power of two!!! */
+
+
+#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+ TYPE * hashtable[HASHSIZE];\
+ TYPE * sorted_list;\
+ int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+ TYPE * next_hash;\
+ TYPE * prev_hash;\
+ TYPE * next_sorted;\
+ TYPE * prev_sorted;\
+};
+
+#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ int ix = HASHFN(elem->KEY);\
+ TYPE ** base = &tbl->hashtable[ix];\
+ TYPE * ptr = *base;\
+ TYPE * prev = NULL;\
+\
+ tbl->nr_entries++;\
+ while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+ base = &ptr->PTRS.next_hash;\
+ prev = ptr;\
+ ptr = *base;\
+ }\
+ elem->PTRS.next_hash = ptr;\
+ elem->PTRS.prev_hash = prev;\
+ if(ptr) {\
+ ptr->PTRS.prev_hash = elem;\
+ }\
+ *base = elem;\
+\
+ ptr = prev;\
+ if(!ptr) {\
+ ptr = tbl->sorted_list;\
+ prev = NULL;\
+ } else {\
+ prev = ptr->PTRS.prev_sorted;\
+ }\
+ while(ptr) {\
+ TYPE * next = ptr->PTRS.next_hash;\
+ if(next && KEYCMP(next->KEY, elem->KEY)) {\
+ prev = ptr;\
+ ptr = next;\
+ } else if(KEYCMP(ptr->KEY, elem->KEY)) {\
+ prev = ptr;\
+ ptr = ptr->PTRS.next_sorted;\
+ } else\
+ break;\
+ }\
+ elem->PTRS.next_sorted = ptr;\
+ elem->PTRS.prev_sorted = prev;\
+ if(ptr) {\
+ ptr->PTRS.prev_sorted = elem;\
+ }\
+ if(prev) {\
+ prev->PTRS.next_sorted = elem;\
+ } else {\
+ tbl->sorted_list = elem;\
+ }\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ TYPE * next = elem->PTRS.next_hash;\
+ TYPE * prev = elem->PTRS.prev_hash;\
+\
+ tbl->nr_entries--;\
+ if(next)\
+ next->PTRS.prev_hash = prev;\
+ if(prev)\
+ prev->PTRS.next_hash = next;\
+ else {\
+ int ix = HASHFN(elem->KEY);\
+ tbl->hashtable[ix] = next;\
+ }\
+\
+ next = elem->PTRS.next_sorted;\
+ prev = elem->PTRS.prev_sorted;\
+ if(next)\
+ next->PTRS.prev_sorted = prev;\
+ if(prev)\
+ prev->PTRS.next_sorted = next;\
+ else\
+ tbl->sorted_list = next;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+ int ix = hashfn(pos);\
+ TYPE * ptr = tbl->hashtable[ix];\
+ while(ptr && KEYCMP(ptr->KEY, pos))\
+ ptr = ptr->PTRS.next_hash;\
+ if(ptr && !KEYEQ(ptr->KEY, pos))\
+ ptr = NULL;\
+ return ptr;\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+ int ix;\
+ int offset;\
+ TYPE * ptr;\
+ TYPE * next;\
+\
+ ptr = tbl->sorted_list;\
+ if(!ptr || KEYCMP(pos, ptr->KEY))\
+ return NULL;\
+ ix = HASHFN(pos);\
+ offset = HASHSIZE;\
+ do {\
+ offset >>= 1;\
+ next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\
+ if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\
+ && KEYCMP(ptr->KEY, next->KEY))\
+ ptr = next;\
+ } while(offset);\
+\
+ for(;;) {\
+ next = ptr->PTRS.next_hash;\
+ if(next) {\
+ if(KEYCMP(next->KEY, pos)) {\
+ ptr = next;\
+ continue;\
+ }\
+ }\
+ next = ptr->PTRS.next_sorted;\
+ if(next && KEYCMP(next->KEY, pos)) {\
+ ptr = next;\
+ continue;\
+ }\
+ return ptr;\
+ }\
+ return NULL;\
+}
+
+#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
+\
+struct NAME##_table {\
+ TYPE * hashtable[HASHSIZE];\
+ int nr_entries;\
+};\
+\
+struct NAME##_ptrs {\
+ TYPE * next_hash;\
+ TYPE * prev_hash;\
+};
+
+#define DEF_HASH(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
+\
+LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ int ix = HASHFN(elem->KEY);\
+ TYPE ** base = &tbl->hashtable[ix];\
+ TYPE * ptr = *base;\
+ TYPE * prev = NULL;\
+\
+ tbl->nr_entries++;\
+ while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
+ base = &ptr->PTRS.next_hash;\
+ prev = ptr;\
+ ptr = *base;\
+ }\
+ elem->PTRS.next_hash = ptr;\
+ elem->PTRS.prev_hash = prev;\
+ if(ptr) {\
+ ptr->PTRS.prev_hash = elem;\
+ }\
+ *base = elem;\
+}\
+\
+LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
+{\
+ TYPE * next = elem->PTRS.next_hash;\
+ TYPE * prev = elem->PTRS.prev_hash;\
+\
+ tbl->nr_entries--;\
+ if(next)\
+ next->PTRS.prev_hash = prev;\
+ if(prev)\
+ prev->PTRS.next_hash = next;\
+ else {\
+ int ix = HASHFN(elem->KEY);\
+ tbl->hashtable[ix] = next;\
+ }\
+}\
+\
+LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
+{\
+ int ix = hashfn(pos);\
+ TYPE * ptr = tbl->hashtable[ix];\
+ while(ptr && KEYCMP(ptr->KEY, pos))\
+ ptr = ptr->PTRS.next_hash;\
+ if(ptr && !KEYEQ(ptr->KEY, pos))\
+ ptr = NULL;\
+ return ptr;\
+}
+
+#endif
diff --git a/pfinet/linux-src/include/linux/hayesesp.h b/pfinet/linux-src/include/linux/hayesesp.h
new file mode 100644
index 00000000..2ed3903a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hayesesp.h
@@ -0,0 +1,127 @@
+#ifndef HAYESESP_H
+#define HAYESESP_H
+
+struct hayes_esp_config {
+ short flow_on;
+ short flow_off;
+ short rx_trigger;
+ short tx_trigger;
+ short pio_threshold;
+ unsigned char rx_timeout;
+ char dma_channel;
+};
+
+#ifdef __KERNEL__
+
+#define ESP_DMA_CHANNEL 0
+#define ESP_RX_TRIGGER 768
+#define ESP_TX_TRIGGER 768
+#define ESP_FLOW_OFF 1016
+#define ESP_FLOW_ON 944
+#define ESP_RX_TMOUT 128
+#define ESP_PIO_THRESHOLD 32
+
+#define ESP_IN_MAJOR 57 /* major dev # for dial in */
+#define ESP_OUT_MAJOR 58 /* major dev # for dial out */
+#define ESPC_SCALE 3
+#define UART_ESI_BASE 0x00
+#define UART_ESI_SID 0x01
+#define UART_ESI_RX 0x02
+#define UART_ESI_TX 0x02
+#define UART_ESI_CMD1 0x04
+#define UART_ESI_CMD2 0x05
+#define UART_ESI_STAT1 0x04
+#define UART_ESI_STAT2 0x05
+#define UART_ESI_RWS 0x07
+
+#define UART_IER_DMA_TMOUT 0x80
+#define UART_IER_DMA_TC 0x08
+
+#define ESI_SET_IRQ 0x04
+#define ESI_SET_DMA_TMOUT 0x05
+#define ESI_SET_SRV_MASK 0x06
+#define ESI_SET_ERR_MASK 0x07
+#define ESI_SET_FLOW_CNTL 0x08
+#define ESI_SET_FLOW_CHARS 0x09
+#define ESI_SET_FLOW_LVL 0x0a
+#define ESI_SET_TRIGGER 0x0b
+#define ESI_SET_RX_TIMEOUT 0x0c
+#define ESI_SET_FLOW_TMOUT 0x0d
+#define ESI_WRITE_UART 0x0e
+#define ESI_READ_UART 0x0f
+#define ESI_SET_MODE 0x10
+#define ESI_GET_ERR_STAT 0x12
+#define ESI_GET_UART_STAT 0x13
+#define ESI_GET_RX_AVAIL 0x14
+#define ESI_GET_TX_AVAIL 0x15
+#define ESI_START_DMA_RX 0x16
+#define ESI_START_DMA_TX 0x17
+#define ESI_ISSUE_BREAK 0x1a
+#define ESI_FLUSH_RX 0x1b
+#define ESI_FLUSH_TX 0x1c
+#define ESI_SET_BAUD 0x1d
+#define ESI_SET_ENH_IRQ 0x1f
+#define ESI_SET_REINTR 0x20
+#define ESI_SET_PRESCALAR 0x23
+#define ESI_NO_COMMAND 0xff
+
+#define ESP_STAT_RX_TIMEOUT 0x01
+#define ESP_STAT_DMA_RX 0x02
+#define ESP_STAT_DMA_TX 0x04
+#define ESP_STAT_NEVER_DMA 0x08
+#define ESP_STAT_USE_PIO 0x10
+
+#define ESP_EVENT_WRITE_WAKEUP 0
+#define ESP_MAGIC 0x53ee
+#define ESP_XMIT_SIZE 4096
+
+struct esp_struct {
+ int magic;
+ int port;
+ int irq;
+ int flags; /* defined in tty.h */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int stat_flags;
+ int custom_divisor;
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct tq_struct tqueue;
+ struct tq_struct tqueue_hangup;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *delta_msr_wait;
+ struct wait_queue *break_wait;
+ struct async_icount icount; /* kernel counters for the 4 input interrupts */
+ struct hayes_esp_config config; /* port configuration */
+ struct esp_struct *next_port; /* For the linked list */
+};
+
+struct esp_pio_buffer {
+ unsigned char data[1024];
+ struct esp_pio_buffer *next;
+};
+
+#endif /* __KERNEL__ */
+
+
+#endif /* ESP_H */
+
diff --git a/pfinet/linux-src/include/linux/hdlcdrv.h b/pfinet/linux-src/include/linux/hdlcdrv.h
new file mode 100644
index 00000000..11cd8c6a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hdlcdrv.h
@@ -0,0 +1,383 @@
+/*
+ * hdlcdrv.h -- HDLC packet radio network driver.
+ * The Linux soundcard driver for 1200 baud and 9600 baud packet radio
+ * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA
+ */
+
+#ifndef _HDLCDRV_H
+#define _HDLCDRV_H
+
+/* -------------------------------------------------------------------- */
+/*
+ * structs for the IOCTL commands
+ */
+
+struct hdlcdrv_params {
+ int iobase;
+ int irq;
+ int dma;
+ int dma2;
+ int seriobase;
+ int pariobase;
+ int midiiobase;
+};
+
+struct hdlcdrv_channel_params {
+ int tx_delay; /* the transmitter keyup delay in 10ms units */
+ int tx_tail; /* the transmitter keyoff delay in 10ms units */
+ int slottime; /* the slottime in 10ms; usually 10 = 100ms */
+ int ppersist; /* the p-persistence 0..255 */
+ int fulldup; /* some driver do not support full duplex, setting */
+ /* this just makes them send even if DCD is on */
+};
+
+struct hdlcdrv_old_channel_state {
+ int ptt;
+ int dcd;
+ int ptt_keyed;
+};
+
+struct hdlcdrv_channel_state {
+ int ptt;
+ int dcd;
+ int ptt_keyed;
+ unsigned long tx_packets;
+ unsigned long tx_errors;
+ unsigned long rx_packets;
+ unsigned long rx_errors;
+};
+
+struct hdlcdrv_ioctl {
+ int cmd;
+ union {
+ struct hdlcdrv_params mp;
+ struct hdlcdrv_channel_params cp;
+ struct hdlcdrv_channel_state cs;
+ struct hdlcdrv_old_channel_state ocs;
+ unsigned int calibrate;
+ unsigned char bits;
+ char modename[128];
+ char drivername[32];
+ } data;
+};
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * ioctl values
+ */
+#define HDLCDRVCTL_GETMODEMPAR 0
+#define HDLCDRVCTL_SETMODEMPAR 1
+#define HDLCDRVCTL_MODEMPARMASK 2 /* not handled by hdlcdrv */
+#define HDLCDRVCTL_GETCHANNELPAR 10
+#define HDLCDRVCTL_SETCHANNELPAR 11
+#define HDLCDRVCTL_OLDGETSTAT 20
+#define HDLCDRVCTL_CALIBRATE 21
+#define HDLCDRVCTL_GETSTAT 22
+
+/*
+ * these are mainly for debugging purposes
+ */
+#define HDLCDRVCTL_GETSAMPLES 30
+#define HDLCDRVCTL_GETBITS 31
+
+/*
+ * not handled by hdlcdrv, but by its depending drivers
+ */
+#define HDLCDRVCTL_GETMODE 40
+#define HDLCDRVCTL_SETMODE 41
+#define HDLCDRVCTL_MODELIST 42
+#define HDLCDRVCTL_DRIVERNAME 43
+
+/*
+ * mask of needed modem parameters, returned by HDLCDRVCTL_MODEMPARMASK
+ */
+#define HDLCDRV_PARMASK_IOBASE (1<<0)
+#define HDLCDRV_PARMASK_IRQ (1<<1)
+#define HDLCDRV_PARMASK_DMA (1<<2)
+#define HDLCDRV_PARMASK_DMA2 (1<<3)
+#define HDLCDRV_PARMASK_SERIOBASE (1<<4)
+#define HDLCDRV_PARMASK_PARIOBASE (1<<5)
+#define HDLCDRV_PARMASK_MIDIIOBASE (1<<6)
+
+/* -------------------------------------------------------------------- */
+
+#ifdef __KERNEL__
+
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <asm/spinlock.h>
+
+#define HDLCDRV_MAGIC 0x5ac6e778
+#define HDLCDRV_IFNAMELEN 6
+#define HDLCDRV_HDLCBUFFER 32 /* should be a power of 2 for speed reasons */
+#define HDLCDRV_BITBUFFER 256 /* should be a power of 2 for speed reasons */
+#undef HDLCDRV_LOOPBACK /* define for HDLC debugging purposes */
+#define HDLCDRV_DEBUG
+
+/* maximum packet length, excluding CRC */
+#define HDLCDRV_MAXFLEN 400
+
+
+struct hdlcdrv_hdlcbuffer {
+ spinlock_t lock;
+ unsigned rd, wr;
+ unsigned short buf[HDLCDRV_HDLCBUFFER];
+};
+
+#ifdef HDLCDRV_DEBUG
+struct hdlcdrv_bitbuffer {
+ unsigned int rd;
+ unsigned int wr;
+ unsigned int shreg;
+ unsigned char buffer[HDLCDRV_BITBUFFER];
+};
+
+extern inline void hdlcdrv_add_bitbuffer(struct hdlcdrv_bitbuffer *buf,
+ unsigned int bit)
+{
+ unsigned char new;
+
+ new = buf->shreg & 1;
+ buf->shreg >>= 1;
+ buf->shreg |= (!!bit) << 7;
+ if (new) {
+ buf->buffer[buf->wr] = buf->shreg;
+ buf->wr = (buf->wr+1) % sizeof(buf->buffer);
+ buf->shreg = 0x80;
+ }
+}
+
+extern inline void hdlcdrv_add_bitbuffer_word(struct hdlcdrv_bitbuffer *buf,
+ unsigned int bits)
+{
+ buf->buffer[buf->wr] = bits & 0xff;
+ buf->wr = (buf->wr+1) % sizeof(buf->buffer);
+ buf->buffer[buf->wr] = (bits >> 8) & 0xff;
+ buf->wr = (buf->wr+1) % sizeof(buf->buffer);
+
+}
+#endif /* HDLCDRV_DEBUG */
+
+/* -------------------------------------------------------------------- */
+/*
+ * Information that need to be kept for each driver.
+ */
+
+struct hdlcdrv_ops {
+ /*
+ * first some informations needed by the hdlcdrv routines
+ */
+ const char *drvname;
+ const char *drvinfo;
+ /*
+ * the routines called by the hdlcdrv routines
+ */
+ int (*open)(struct device *);
+ int (*close)(struct device *);
+ int (*ioctl)(struct device *, struct ifreq *,
+ struct hdlcdrv_ioctl *, int);
+};
+
+struct hdlcdrv_state {
+ int magic;
+
+ char ifname[HDLCDRV_IFNAMELEN];
+
+ const struct hdlcdrv_ops *ops;
+
+ struct {
+ int bitrate;
+ } par;
+
+ struct hdlcdrv_pttoutput {
+ int dma2;
+ int seriobase;
+ int pariobase;
+ int midiiobase;
+ unsigned int flags;
+ } ptt_out;
+
+ struct hdlcdrv_channel_params ch_params;
+
+ struct hdlcdrv_hdlcrx {
+ struct hdlcdrv_hdlcbuffer hbuf;
+ int in_hdlc_rx;
+ /* 0 = sync hunt, != 0 receiving */
+ int rx_state;
+ unsigned int bitstream;
+ unsigned int bitbuf;
+ int numbits;
+ unsigned char dcd;
+
+ int len;
+ unsigned char *bp;
+ unsigned char buffer[HDLCDRV_MAXFLEN+2];
+ } hdlcrx;
+
+ struct hdlcdrv_hdlctx {
+ struct hdlcdrv_hdlcbuffer hbuf;
+ int in_hdlc_tx;
+ /*
+ * 0 = send flags
+ * 1 = send txtail (flags)
+ * 2 = send packet
+ */
+ int tx_state;
+ int numflags;
+ unsigned int bitstream;
+ unsigned char ptt;
+ int calibrate;
+ int slotcnt;
+
+ unsigned int bitbuf;
+ int numbits;
+
+ int len;
+ unsigned char *bp;
+ unsigned char buffer[HDLCDRV_MAXFLEN+2];
+ } hdlctx;
+
+#ifdef HDLCDRV_DEBUG
+ struct hdlcdrv_bitbuffer bitbuf_channel;
+ struct hdlcdrv_bitbuffer bitbuf_hdlc;
+#endif /* HDLCDRV_DEBUG */
+
+#if LINUX_VERSION_CODE < 0x20119
+ struct enet_statistics stats;
+#else
+ struct net_device_stats stats;
+#endif
+ int ptt_keyed;
+
+ struct sk_buff_head send_queue; /* Packets awaiting transmission */
+};
+
+
+/* -------------------------------------------------------------------- */
+
+extern inline int hdlcdrv_hbuf_full(struct hdlcdrv_hdlcbuffer *hb)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hb->lock, flags);
+ ret = !((HDLCDRV_HDLCBUFFER - 1 + hb->rd - hb->wr) % HDLCDRV_HDLCBUFFER);
+ spin_unlock_irqrestore(&hb->lock, flags);
+ return ret;
+}
+
+/* -------------------------------------------------------------------- */
+
+extern inline int hdlcdrv_hbuf_empty(struct hdlcdrv_hdlcbuffer *hb)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hb->lock, flags);
+ ret = (hb->rd == hb->wr);
+ spin_unlock_irqrestore(&hb->lock, flags);
+ return ret;
+}
+
+/* -------------------------------------------------------------------- */
+
+extern inline unsigned short hdlcdrv_hbuf_get(struct hdlcdrv_hdlcbuffer *hb)
+{
+ unsigned long flags;
+ unsigned short val;
+ unsigned newr;
+
+ spin_lock_irqsave(&hb->lock, flags);
+ if (hb->rd == hb->wr)
+ val = 0;
+ else {
+ newr = (hb->rd+1) % HDLCDRV_HDLCBUFFER;
+ val = hb->buf[hb->rd];
+ hb->rd = newr;
+ }
+ spin_unlock_irqrestore(&hb->lock, flags);
+ return val;
+}
+
+/* -------------------------------------------------------------------- */
+
+extern inline void hdlcdrv_hbuf_put(struct hdlcdrv_hdlcbuffer *hb,
+ unsigned short val)
+{
+ unsigned newp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hb->lock, flags);
+ newp = (hb->wr+1) % HDLCDRV_HDLCBUFFER;
+ if (newp != hb->rd) {
+ hb->buf[hb->wr] = val & 0xffff;
+ hb->wr = newp;
+ }
+ spin_unlock_irqrestore(&hb->lock, flags);
+}
+
+/* -------------------------------------------------------------------- */
+
+extern inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits)
+{
+ hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, bits);
+}
+
+extern inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s)
+{
+ unsigned int ret;
+
+ if (hdlcdrv_hbuf_empty(&s->hdlctx.hbuf)) {
+ if (s->hdlctx.calibrate > 0)
+ s->hdlctx.calibrate--;
+ else
+ s->hdlctx.ptt = 0;
+ ret = 0;
+ } else
+ ret = hdlcdrv_hbuf_get(&s->hdlctx.hbuf);
+#ifdef HDLCDRV_LOOPBACK
+ hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, ret);
+#endif /* HDLCDRV_LOOPBACK */
+ return ret;
+}
+
+extern inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit)
+{
+#ifdef HDLCDRV_DEBUG
+ hdlcdrv_add_bitbuffer(&s->bitbuf_channel, bit);
+#endif /* HDLCDRV_DEBUG */
+}
+
+extern inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd)
+{
+ s->hdlcrx.dcd = !!dcd;
+}
+
+extern inline int hdlcdrv_ptt(struct hdlcdrv_state *s)
+{
+ return s->hdlctx.ptt || (s->hdlctx.calibrate > 0);
+}
+
+/* -------------------------------------------------------------------- */
+
+void hdlcdrv_receiver(struct device *, struct hdlcdrv_state *);
+void hdlcdrv_transmitter(struct device *, struct hdlcdrv_state *);
+void hdlcdrv_arbitrate(struct device *, struct hdlcdrv_state *);
+int hdlcdrv_register_hdlcdrv(struct device *dev, const struct hdlcdrv_ops *ops,
+ unsigned int privsize, char *ifname,
+ unsigned int baseaddr, unsigned int irq,
+ unsigned int dma);
+int hdlcdrv_unregister_hdlcdrv(struct device *dev);
+
+/* -------------------------------------------------------------------- */
+
+
+
+#endif /* __KERNEL__ */
+
+/* -------------------------------------------------------------------- */
+
+#endif /* _HDLCDRV_H */
+
+/* -------------------------------------------------------------------- */
diff --git a/pfinet/linux-src/include/linux/hdreg.h b/pfinet/linux-src/include/linux/hdreg.h
new file mode 100644
index 00000000..e467ae9b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hdreg.h
@@ -0,0 +1,282 @@
+#ifndef _LINUX_HDREG_H
+#define _LINUX_HDREG_H
+
+/*
+ * This file contains some defines for the AT-hd-controller.
+ * Various sources.
+ */
+
+#define HD_IRQ 14 /* the standard disk interrupt */
+
+/* ide.c has its own port definitions in "ide.h" */
+
+/* Hd controller regs. Ref: IBM AT Bios-listing */
+#define HD_DATA 0x1f0 /* _CTL when writing */
+#define HD_ERROR 0x1f1 /* see err-bits */
+#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */
+#define HD_SECTOR 0x1f3 /* starting sector */
+#define HD_LCYL 0x1f4 /* starting cylinder */
+#define HD_HCYL 0x1f5 /* high byte of starting cyl */
+#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS 0x1f7 /* see status-bits */
+#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
+#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
+#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
+
+#define HD_CMD 0x3f6 /* used for resets */
+#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */
+
+/* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
+
+/* Bits of HD_STATUS */
+#define ERR_STAT 0x01
+#define INDEX_STAT 0x02
+#define ECC_STAT 0x04 /* Corrected error */
+#define DRQ_STAT 0x08
+#define SEEK_STAT 0x10
+#define WRERR_STAT 0x20
+#define READY_STAT 0x40
+#define BUSY_STAT 0x80
+
+/* Values for HD_COMMAND */
+#define WIN_RESTORE 0x10
+#define WIN_READ 0x20
+#define WIN_WRITE 0x30
+#define WIN_WRITE_VERIFY 0x3C
+#define WIN_VERIFY 0x40
+#define WIN_FORMAT 0x50
+#define WIN_INIT 0x60
+#define WIN_SEEK 0x70
+#define WIN_DIAGNOSE 0x90
+#define WIN_SPECIFY 0x91 /* set drive geometry translation */
+#define WIN_SETIDLE1 0xE3
+#define WIN_SETIDLE2 0x97
+
+#define WIN_STANDBYNOW1 0xE0
+#define WIN_STANDBYNOW2 0x94
+#define WIN_SLEEPNOW1 0xE6
+#define WIN_SLEEPNOW2 0x99
+#define WIN_CHECKPOWERMODE1 0xE5
+#define WIN_CHECKPOWERMODE2 0x98
+
+#define WIN_DOORLOCK 0xde /* lock door on removable drives */
+#define WIN_DOORUNLOCK 0xdf /* unlock door on removable drives */
+
+#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode */
+#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
+#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
+#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES 0xEF /* set special drive features */
+#define WIN_READDMA 0xc8 /* read sectors using DMA transfers */
+#define WIN_WRITEDMA 0xca /* write sectors using DMA transfers */
+
+#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
+#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
+
+#define WIN_SMART 0xb0 /* self-monitoring and reporting */
+
+/* Additional drive command codes used by ATAPI devices. */
+#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
+#define WIN_SRST 0x08 /* ATAPI soft reset command */
+#define WIN_PACKETCMD 0xa0 /* Send a packet command. */
+
+/* WIN_SMART sub-commands */
+
+#define SMART_READ_VALUES 0xd0
+#define SMART_READ_THRESHOLDS 0xd1
+#define SMART_AUTOSAVE 0xd2
+#define SMART_SAVE 0xd3
+#define SMART_IMMEDIATE_OFFLINE 0xd4
+#define SMART_ENABLE 0xd8
+#define SMART_DISABLE 0xd9
+#define SMART_STATUS 0xda
+#define SMART_AUTO_OFFLINE 0xdb
+
+/* WIN_SECURITY sub-commands */
+#define SECURITY_SET_PASSWORD 0xBA /* 0xF1 */
+#define SECURITY_UNLOCK 0xBB /* 0xF2 */
+#define SECURITY_ERASE_PREPARE 0xBC /* 0xF3 */
+#define SECURITY_ERASE_UNIT 0xBD /* 0xF4 */
+#define SECURITY_FREEZE_LOCK 0xBE /* 0xF5 */
+#define SECURITY_DISABLE_PASSWORD 0xBF /* 0xF6 */
+
+/* Bits for HD_ERROR */
+#define MARK_ERR 0x01 /* Bad address mark */
+#define TRK0_ERR 0x02 /* couldn't find track 0 */
+#define ABRT_ERR 0x04 /* Command aborted */
+#define MCR_ERR 0x08 /* media change request */
+#define ID_ERR 0x10 /* ID field not found */
+#define ECC_ERR 0x40 /* Uncorrectable ECC error */
+#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
+#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
+
+struct hd_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ unsigned long start;
+};
+
+/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
+#define HDIO_GETGEO 0x0301 /* get device geometry */
+#define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */
+#define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */
+#define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */
+#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */
+#define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */
+#define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */
+#define HDIO_GET_DMA 0x030b /* get use-dma flag */
+#define HDIO_GET_NICE 0x030c /* get nice flags */
+#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */
+#define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */
+
+/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
+#define HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */
+#define HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */
+#define HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */
+#define HDIO_SET_32BIT 0x0324 /* change io_32bit flags */
+#define HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */
+#define HDIO_SET_DMA 0x0326 /* change use-dma flag */
+#define HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
+#define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */
+#define HDIO_SET_NICE 0x0329 /* set nice flags */
+#define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */
+
+/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
+struct hd_driveid {
+ unsigned short config; /* lots of obsolete bit flags */
+ unsigned short cyls; /* "physical" cyls */
+ unsigned short reserved2; /* reserved (word 2) */
+ unsigned short heads; /* "physical" heads */
+ unsigned short track_bytes; /* unformatted bytes per track */
+ unsigned short sector_bytes; /* unformatted bytes per sector */
+ unsigned short sectors; /* "physical" sectors per track */
+ unsigned short vendor0; /* vendor unique */
+ unsigned short vendor1; /* vendor unique */
+ unsigned short vendor2; /* vendor unique */
+ unsigned char serial_no[20]; /* 0 = not_specified */
+ unsigned short buf_type;
+ unsigned short buf_size; /* 512 byte increments; 0 = not_specified */
+ unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */
+ unsigned char fw_rev[8]; /* 0 = not_specified */
+ unsigned char model[40]; /* 0 = not_specified */
+ unsigned char max_multsect; /* 0=not_implemented */
+ unsigned char vendor3; /* vendor unique */
+ unsigned short dword_io; /* 0=not_implemented; 1=implemented */
+ unsigned char vendor4; /* vendor unique */
+ unsigned char capability; /* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/
+ unsigned short reserved50; /* reserved (word 50) */
+ unsigned char vendor5; /* vendor unique */
+ unsigned char tPIO; /* 0=slow, 1=medium, 2=fast */
+ unsigned char vendor6; /* vendor unique */
+ unsigned char tDMA; /* 0=slow, 1=medium, 2=fast */
+ unsigned short field_valid; /* bits 0:cur_ok 1:eide_ok */
+ unsigned short cur_cyls; /* logical cylinders */
+ unsigned short cur_heads; /* logical heads */
+ unsigned short cur_sectors; /* logical sectors per track */
+ unsigned short cur_capacity0; /* logical total sectors on drive */
+ unsigned short cur_capacity1; /* (2 words, misaligned int) */
+ unsigned char multsect; /* current multiple sector count */
+ unsigned char multsect_valid; /* when (bit0==1) multsect is ok */
+ unsigned int lba_capacity; /* total number of sectors */
+ unsigned short dma_1word; /* single-word dma info */
+ unsigned short dma_mword; /* multiple-word dma info */
+ unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */
+ unsigned short eide_dma_min; /* min mword dma cycle time (ns) */
+ unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */
+ unsigned short eide_pio; /* min cycle time (ns), no IORDY */
+ unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */
+ unsigned short word69;
+ unsigned short word70;
+ /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+ unsigned short word71;
+ unsigned short word72;
+ unsigned short word73;
+ unsigned short word74;
+ unsigned short word75;
+ unsigned short word76;
+ unsigned short word77;
+ unsigned short word78;
+ unsigned short word79;
+ unsigned short word80;
+ unsigned short word81;
+ unsigned short command_sets; /* bits 0:Smart 1:Security 2:Removable 3:PM */
+ unsigned short word83; /* bits 14:Smart Enabled 13:0 zero */
+ unsigned short word84;
+ unsigned short word85;
+ unsigned short word86;
+ unsigned short word87;
+ unsigned short dma_ultra;
+ unsigned short word89; /* reserved (word 89) */
+ unsigned short word90; /* reserved (word 90) */
+ unsigned short word91; /* reserved (word 91) */
+ unsigned short word92; /* reserved (word 92) */
+ unsigned short word93; /* reserved (word 93) */
+ unsigned short word94; /* reserved (word 94) */
+ unsigned short word95; /* reserved (word 95) */
+ unsigned short word96; /* reserved (word 96) */
+ unsigned short word97; /* reserved (word 97) */
+ unsigned short word98; /* reserved (word 98) */
+ unsigned short word99; /* reserved (word 99) */
+ unsigned short word100; /* reserved (word 100) */
+ unsigned short word101; /* reserved (word 101) */
+ unsigned short word102; /* reserved (word 102) */
+ unsigned short word103; /* reserved (word 103) */
+ unsigned short word104; /* reserved (word 104) */
+ unsigned short word105; /* reserved (word 105) */
+ unsigned short word106; /* reserved (word 106) */
+ unsigned short word107; /* reserved (word 107) */
+ unsigned short word108; /* reserved (word 108) */
+ unsigned short word109; /* reserved (word 109) */
+ unsigned short word110; /* reserved (word 110) */
+ unsigned short word111; /* reserved (word 111) */
+ unsigned short word112; /* reserved (word 112) */
+ unsigned short word113; /* reserved (word 113) */
+ unsigned short word114; /* reserved (word 114) */
+ unsigned short word115; /* reserved (word 115) */
+ unsigned short word116; /* reserved (word 116) */
+ unsigned short word117; /* reserved (word 117) */
+ unsigned short word118; /* reserved (word 118) */
+ unsigned short word119; /* reserved (word 119) */
+ unsigned short word120; /* reserved (word 120) */
+ unsigned short word121; /* reserved (word 121) */
+ unsigned short word122; /* reserved (word 122) */
+ unsigned short word123; /* reserved (word 123) */
+ unsigned short word124; /* reserved (word 124) */
+ unsigned short word125; /* reserved (word 125) */
+ unsigned short word126; /* reserved (word 126) */
+ unsigned short word127; /* reserved (word 127) */
+ unsigned short security; /* bits 0:support 1:enabled 2:locked 3:frozen */
+ unsigned short reserved[127];
+};
+
+/*
+ * IDE "nice" flags. These are used on a per drive basis to determine
+ * when to be nice and give more bandwidth to the other devices which
+ * share the same IDE bus.
+ */
+#define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */
+#define IDE_NICE_ATAPI_OVERLAP (1) /* not supported yet */
+#define IDE_NICE_0 (2) /* when sure that it won't affect us */
+#define IDE_NICE_1 (3) /* when probably won't affect us much */
+#define IDE_NICE_2 (4) /* when we know it's on our expense */
+
+#ifdef __KERNEL__
+/*
+ * These routines are used for kernel command line parameters from main.c:
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_BLK_DEV_HD
+void hd_setup(char *, int *);
+#endif /* CONFIG_BLK_DEV_HD */
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+int ide_register(int io_port, int ctl_port, int irq);
+void ide_unregister(unsigned int);
+#endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_HDREG_H */
diff --git a/pfinet/linux-src/include/linux/hfmodem.h b/pfinet/linux-src/include/linux/hfmodem.h
new file mode 100644
index 00000000..7b35f116
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hfmodem.h
@@ -0,0 +1,256 @@
+/*****************************************************************************/
+
+/*
+ * hfmodem.h -- Linux soundcard HF FSK driver.
+ *
+ * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Swiss Federal Institute of Technology (ETH), Electronics Lab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * This is the Linux realtime sound output driver
+ */
+
+/*****************************************************************************/
+
+#ifndef _HFMODEM_H
+#define _HFMODEM_H
+/* --------------------------------------------------------------------- */
+
+#include <linux/version.h>
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#if LINUX_VERSION_CODE >= 0x20100
+#include <linux/poll.h>
+#endif
+
+/* --------------------------------------------------------------------- */
+
+#define HFMODEM_MINOR 145
+
+#define HFMODEM_SRATE 8000
+#define HFMODEM_MAXBITS 4800 /* required for GTOR 300 baud mode */
+#define HFMODEM_MINBAUD 40
+#define HFMODEM_MAXBAUD 400
+#define HFMODEM_MAXCORRLEN ((HFMODEM_SRATE+HFMODEM_MINBAUD-1)/HFMODEM_MINBAUD)
+
+/* --------------------------------------------------------------------- */
+
+typedef unsigned long hfmodem_time_t;
+typedef int hfmodem_soft_t;
+typedef unsigned long hfmodem_id_t;
+
+/* --------------------------------------------------------------------- */
+
+struct hfmodem_ioctl_fsk_tx_request {
+ hfmodem_time_t tstart;
+ hfmodem_time_t tinc;
+ int inv;
+ hfmodem_id_t id;
+ unsigned int nbits;
+ unsigned char *data;
+ unsigned int freq[2];
+};
+
+struct hfmodem_ioctl_fsk_rx_request {
+ hfmodem_time_t tstart;
+ hfmodem_time_t tinc;
+ unsigned int baud;
+ hfmodem_id_t id;
+ unsigned int nbits;
+ hfmodem_soft_t *data;
+ unsigned int freq[2];
+};
+
+struct hfmodem_ioctl_mixer_params {
+ int src;
+ int igain;
+ int ogain;
+};
+
+struct hfmodem_ioctl_sample_params {
+ __s16 *data;
+ int len;
+};
+
+#define HFMODEM_IOCTL_FSKTXREQUEST _IOW('H', 0, struct hfmodem_ioctl_fsk_tx_request)
+#define HFMODEM_IOCTL_FSKRXREQUEST _IOW('H', 1, struct hfmodem_ioctl_fsk_rx_request)
+#define HFMODEM_IOCTL_CLEARRQ _IO('H', 3)
+#define HFMODEM_IOCTL_GETCURTIME _IOR('H', 4, hfmodem_time_t)
+#define HFMODEM_IOCTL_WAITRQ _IOR('H', 5, hfmodem_id_t)
+#define HFMODEM_IOCTL_MIXERPARAMS _IOW('H', 6, struct hfmodem_ioctl_mixer_params)
+#define HFMODEM_IOCTL_SAMPLESTART _IOW('H', 7, struct hfmodem_ioctl_sample_params)
+#define HFMODEM_IOCTL_SAMPLEFINISHED _IO('H', 8)
+
+/* --------------------------------------------------------------------- */
+#ifdef __KERNEL__
+
+#include <linux/parport.h>
+
+#define DMA_MODE_AUTOINIT 0x10
+
+#define NR_DEVICE 1
+
+#define HFMODEM_FRAGSAMPLES (HFMODEM_SRATE/100)
+#define HFMODEM_FRAGSIZE (HFMODEM_FRAGSAMPLES*2)
+#define HFMODEM_NUMFRAGS 8
+#define HFMODEM_EXCESSFRAGS 3
+
+#define HFMODEM_NUMRXSLOTS 20
+#define HFMODEM_NUMTXSLOTS 4
+
+#define HFMODEM_CORRELATOR_CACHE 8
+
+enum slot_st { ss_unused = 0, ss_ready, ss_oper, ss_retired };
+typedef int hfmodem_conv_t;
+
+struct hfmodem_state {
+ const struct hfmodem_scops *scops;
+
+ /* io params */
+ struct {
+ unsigned int base_addr;
+ unsigned int dma;
+ unsigned int irq;
+ } io;
+
+ struct {
+ unsigned int seriobase;
+ unsigned int pariobase;
+ unsigned int midiiobase;
+ unsigned int flags;
+ struct pardevice *pardev;
+ } ptt_out;
+
+ struct {
+ __s16 *buf;
+ unsigned int lastfrag;
+ unsigned int fragptr;
+ unsigned int last_dmaptr;
+ int ptt_frames;
+ } dma;
+
+ struct {
+ unsigned int last_tvusec;
+ unsigned long long time_cnt;
+ hfmodem_time_t lasttime;
+#ifdef __i386__
+ unsigned int starttime_lo, starttime_hi;
+#endif /* __i386__ */
+ } clk;
+
+ int active;
+ struct wait_queue *wait;
+
+ struct {
+ __s16 *kbuf;
+ __s16 *ubuf;
+ __s16 *kptr;
+ unsigned int size;
+ int rem;
+ } sbuf;
+
+ struct {
+ hfmodem_time_t last_time;
+ unsigned int tx_phase;
+
+ struct hfmodem_l1_rxslot {
+ enum slot_st state;
+ hfmodem_time_t tstart, tinc;
+ hfmodem_soft_t *data;
+ hfmodem_soft_t *userdata;
+ unsigned int nbits;
+ unsigned int cntbits;
+ hfmodem_id_t id;
+ unsigned int corrlen;
+ hfmodem_conv_t scale;
+ unsigned int corr_cache;
+ } rxslots[HFMODEM_NUMRXSLOTS];
+
+ struct hfmodem_l1_txslot {
+ enum slot_st state;
+ hfmodem_time_t tstart, tinc;
+ unsigned char *data;
+ unsigned int nbits;
+ unsigned int cntbits;
+ hfmodem_id_t id;
+ unsigned char inv;
+ unsigned int phinc;
+ unsigned int phase_incs[2];
+ } txslots[HFMODEM_NUMTXSLOTS];
+ } l1;
+};
+
+struct hfmodem_correlator_cache {
+ int refcnt;
+ int lru;
+ unsigned short phase_incs[2];
+ hfmodem_conv_t correlator[2][2][HFMODEM_MAXCORRLEN];
+};
+
+struct hfmodem_scops {
+ unsigned int extent;
+
+ void (*init)(struct hfmodem_state *dev);
+ void (*prepare_input)(struct hfmodem_state *dev);
+ void (*trigger_input)(struct hfmodem_state *dev);
+ void (*prepare_output)(struct hfmodem_state *dev);
+ void (*trigger_output)(struct hfmodem_state *dev);
+ void (*stop)(struct hfmodem_state *dev);
+ unsigned int (*intack)(struct hfmodem_state *dev);
+ void (*mixer)(struct hfmodem_state *dev, int src, int igain, int ogain);
+};
+
+/* --------------------------------------------------------------------- */
+
+extern int hfmodem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#if LINUX_VERSION_CODE >= 0x20100
+extern unsigned int hfmodem_poll(struct file *file, poll_table *wait);
+#else
+extern int hfmodem_select(struct inode *inode, struct file *file, int sel_type, select_table *wait);
+#endif
+
+extern void hfmodem_clear_rq(struct hfmodem_state *dev);
+extern void hfmodem_input_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
+ hfmodem_time_t tinc, __s16 *samples);
+extern int hfmodem_output_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
+ hfmodem_time_t tinc, __s16 *samples);
+extern long hfmodem_next_tx_event(struct hfmodem_state *dev, hfmodem_time_t curr);
+extern void hfmodem_finish_pending_rx_requests(struct hfmodem_state *dev);
+extern void hfmodem_wakeup(struct hfmodem_state *dev);
+
+
+extern int hfmodem_sbcprobe(struct hfmodem_state *dev);
+extern int hfmodem_wssprobe(struct hfmodem_state *dev);
+
+extern void hfmodem_refclock_probe(void);
+extern void hfmodem_refclock_init(struct hfmodem_state *dev);
+extern hfmodem_time_t hfmodem_refclock_current(struct hfmodem_state *dev, hfmodem_time_t expected, int exp_valid);
+
+/* --------------------------------------------------------------------- */
+
+extern const char hfmodem_drvname[];
+extern const char hfmodem_drvinfo[];
+
+extern struct hfmodem_state hfmodem_state[NR_DEVICE];
+extern struct hfmodem_correlator_cache hfmodem_correlator_cache[HFMODEM_CORRELATOR_CACHE];
+
+/* --------------------------------------------------------------------- */
+#endif /* __KERNEL__ */
+/* --------------------------------------------------------------------- */
+#endif /* _HFMODEM_H */
diff --git a/pfinet/linux-src/include/linux/hfs_fs.h b/pfinet/linux-src/include/linux/hfs_fs.h
new file mode 100644
index 00000000..851bcb0d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hfs_fs.h
@@ -0,0 +1,337 @@
+/*
+ * linux/include/linux/hfs_fs.h
+ *
+ * Copyright (C) 1995-1997 Paul H. Hargrove
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ * The source code distribution of the Columbia AppleTalk Package for
+ * UNIX, version 6.0, (CAP) was used as a specification of the
+ * location and format of files used by CAP's Aufs. No code from CAP
+ * appears in hfs_fs. hfs_fs is not a work ``derived'' from CAP in
+ * the sense of intellectual property law.
+ *
+ * The source code distributions of Netatalk, versions 1.3.3b2 and
+ * 1.4b2, were used as a specification of the location and format of
+ * files used by Netatalk's afpd. No code from Netatalk appears in
+ * hfs_fs. hfs_fs is not a work ``derived'' from Netatalk in the
+ * sense of intellectual property law.
+ */
+
+#ifndef _LINUX_HFS_FS_H
+#define _LINUX_HFS_FS_H
+
+#include <linux/hfs_sysdep.h>
+
+/* magic numbers for Apple Double header files */
+#define HFS_DBL_MAGIC 0x00051607
+#define HFS_SNGL_MAGIC 0x00051600
+#define HFS_HDR_VERSION_1 0x00010000
+#define HFS_HDR_VERSION_2 0x00020000
+
+/* magic numbers for various internal structures */
+#define HFS_INO_MAGIC 0x4821
+#define HFS_SB_MAGIC 0x4822
+
+/* The space used for the AppleDouble or AppleSingle headers */
+#define HFS_DBL_HDR_LEN 1024
+
+/* The space used for the Netatalk header */
+#define HFS_NAT_HDR_LEN 1024 /* 589 for an exact match */
+
+/* Macros to extract CNID and file "type" from the Linux inode number */
+#define HFS_CNID(X) ((X) & 0x3FFFFFFF)
+#define HFS_ITYPE(X) ((X) & 0xC0000000)
+
+/* Macros to enumerate types */
+#define HFS_ITYPE_TO_INT(X) ((X) >> 30)
+#define HFS_INT_TO_ITYPE(X) ((X) << 30)
+
+/* generic ITYPEs */
+#define HFS_ITYPE_0 0x00000000
+#define HFS_ITYPE_1 0x40000000
+#define HFS_ITYPE_2 0x80000000
+#define HFS_ITYPE_3 0xC0000000
+#define HFS_ITYPE_NORM HFS_ITYPE_0 /* "normal" directory or file */
+
+/* ITYPEs for CAP */
+#define HFS_CAP_NORM HFS_ITYPE_0 /* data fork or normal directory */
+#define HFS_CAP_DATA HFS_ITYPE_0 /* data fork of file */
+#define HFS_CAP_NDIR HFS_ITYPE_0 /* normal directory */
+#define HFS_CAP_FNDR HFS_ITYPE_1 /* finder info for file or dir */
+#define HFS_CAP_RSRC HFS_ITYPE_2 /* resource fork of file */
+#define HFS_CAP_RDIR HFS_ITYPE_2 /* .resource directory */
+#define HFS_CAP_FDIR HFS_ITYPE_3 /* .finderinfo directory */
+
+/* ITYPEs for Apple Double */
+#define HFS_DBL_NORM HFS_ITYPE_0 /* data fork or directory */
+#define HFS_DBL_DATA HFS_ITYPE_0 /* data fork of file */
+#define HFS_DBL_DIR HFS_ITYPE_0 /* directory */
+#define HFS_DBL_HDR HFS_ITYPE_1 /* AD header of file or dir */
+
+/* ITYPEs for netatalk */
+#define HFS_NAT_NORM HFS_ITYPE_0 /* data fork or directory */
+#define HFS_NAT_DATA HFS_ITYPE_0 /* data fork of file */
+#define HFS_NAT_NDIR HFS_ITYPE_0 /* normal directory */
+#define HFS_NAT_HDR HFS_ITYPE_1 /* AD header of file or dir */
+#define HFS_NAT_HDIR HFS_ITYPE_2 /* directory holding AD headers */
+
+/* ITYPEs for Apple Single */
+#define HFS_SGL_NORM HFS_ITYPE_0 /* AppleSingle file or directory */
+#define HFS_SGL_SNGL HFS_ITYPE_0 /* AppleSingle file */
+#define HFS_SGL_DIR HFS_ITYPE_0 /* directory */
+#define HFS_SGL_DINF HFS_ITYPE_1 /* %DirInfo for directory */
+
+/* IDs for elements of an AppleDouble or AppleSingle header */
+#define HFS_HDR_DATA 1 /* data fork */
+#define HFS_HDR_RSRC 2 /* resource fork */
+#define HFS_HDR_FNAME 3 /* full (31-character) name */
+#define HFS_HDR_COMNT 4 /* comment */
+#define HFS_HDR_BWICN 5 /* b/w icon */
+#define HFS_HDR_CICON 6 /* color icon info */
+#define HFS_HDR_OLDI 7 /* old file info */
+#define HFS_HDR_DATES 8 /* file dates info */
+#define HFS_HDR_FINFO 9 /* Finder info */
+#define HFS_HDR_MACI 10 /* Macintosh info */
+#define HFS_HDR_PRODOSI 11 /* ProDOS info */
+#define HFS_HDR_MSDOSI 12 /* MSDOS info */
+#define HFS_HDR_SNAME 13 /* short name */
+#define HFS_HDR_AFPI 14 /* AFP file info */
+#define HFS_HDR_DID 15 /* directory id */
+#define HFS_HDR_MAX 16
+
+/*
+ * There are three time systems. All three are based on seconds since
+ * a particular time/date.
+ * Unix: unsigned lil-endian since 00:00 GMT, Jan. 1, 1970
+ * mac: unsigned big-endian since 00:00 GMT, Jan. 1, 1904
+ * header: SIGNED big-endian since 00:00 GMT, Jan. 1, 2000
+ *
+ */
+#define hfs_h_to_mtime(ARG) htonl((hfs_s32)ntohl(ARG)+3029529600U)
+#define hfs_m_to_htime(ARG) ((hfs_s32)htonl(ntohl(ARG)-3029529600U))
+#define hfs_h_to_utime(ARG) ((hfs_s32)hfs_to_utc(ntohl(ARG)+946684800U))
+#define hfs_u_to_htime(ARG) ((hfs_s32)htonl(hfs_from_utc(ARG)-946684800U))
+#define hfs_u_to_mtime(ARG) htonl(hfs_from_utc(ARG)+2082844800U)
+#define hfs_m_to_utime(ARG) (hfs_to_utc(ntohl(ARG)-2082844800U))
+
+/*======== Data structures kept in memory ========*/
+
+/*
+ * A descriptor for a single entry within the header of an
+ * AppleDouble or AppleSingle header file.
+ * An array of these make up a table of contents for the file.
+ */
+struct hfs_hdr_descr {
+ hfs_u32 id; /* The Apple assigned ID for the entry type */
+ hfs_u32 offset; /* The offset to reach the entry */
+ hfs_u32 length; /* The length of the entry */
+};
+
+/*
+ * The info needed to reconstruct a given header layout
+ */
+struct hfs_hdr_layout {
+ hfs_u32 magic; /* AppleSingle or AppleDouble */
+ hfs_u32 version; /* 0x00010000 or 0x00020000 */
+ hfs_u16 entries; /* How many entries used */
+ struct hfs_hdr_descr
+ descr[HFS_HDR_MAX]; /* Descriptors */
+ struct hfs_hdr_descr
+ *order[HFS_HDR_MAX]; /* 'descr' ordered by offset */
+};
+
+/* header layout for netatalk's v1 appledouble file format */
+struct hfs_nat_hdr {
+ hfs_lword_t magic;
+ hfs_lword_t version;
+ hfs_byte_t homefs[16];
+ hfs_word_t entries;
+ hfs_byte_t descrs[12*5];
+ hfs_byte_t real_name[255]; /* id=3 */
+ hfs_byte_t comment[200]; /* id=4 XXX: not yet implemented */
+ hfs_byte_t old_info[16]; /* id=7 */
+ hfs_u8 finderinfo[32]; /* id=9 */
+};
+
+/*
+ * Default header layout for Netatalk and AppleDouble
+ */
+struct hfs_dbl_hdr {
+ hfs_lword_t magic;
+ hfs_lword_t version;
+ hfs_byte_t filler[16];
+ hfs_word_t entries;
+ hfs_byte_t descrs[12*HFS_HDR_MAX];
+ hfs_byte_t real_name[255]; /* id=3 */
+ hfs_byte_t comment[200]; /* id=4 XXX: not yet implemented */
+ hfs_u32 create_time; /* \ */
+ hfs_u32 modify_time; /* | id=8 (or 7) */
+ hfs_u32 backup_time; /* | */
+ hfs_u32 access_time; /* / (attributes with id=7) */
+ hfs_u8 finderinfo[32]; /* id=9 */
+ hfs_u32 fileinfo; /* id=10 */
+ hfs_u32 cnid; /* id=15 */
+ hfs_u8 short_name[12]; /* id=13 */
+ hfs_u8 prodosi[8]; /* id=11 */
+};
+
+/* finder metadata for CAP */
+struct hfs_cap_info {
+ hfs_byte_t fi_fndr[32]; /* Finder's info */
+ hfs_word_t fi_attr; /* AFP attributes (f=file/d=dir) */
+#define HFS_AFP_INV 0x001 /* Invisible bit (f/d) */
+#define HFS_AFP_EXPFOLDER 0x002 /* exported folder (d) */
+#define HFS_AFP_MULTI 0x002 /* Multiuser bit (f) */
+#define HFS_AFP_SYS 0x004 /* System bit (f/d) */
+#define HFS_AFP_DOPEN 0x008 /* data fork already open (f) */
+#define HFS_AFP_MOUNTED 0x008 /* mounted folder (d) */
+#define HFS_AFP_ROPEN 0x010 /* resource fork already open (f) */
+#define HFS_AFP_INEXPFOLDER 0x010 /* folder in shared area (d) */
+#define HFS_AFP_WRI 0x020 /* Write inhibit bit (readonly) (f) */
+#define HFS_AFP_BACKUP 0x040 /* backup needed bit (f/d) */
+#define HFS_AFP_RNI 0x080 /* Rename inhibit bit (f/d) */
+#define HFS_AFP_DEI 0x100 /* Delete inhibit bit (f/d) */
+#define HFS_AFP_NOCOPY 0x400 /* Copy protect bit (f) */
+#define HFS_AFP_RDONLY ( HFS_AFP_WRI|HFS_AFP_RNI|HFS_AFP_DEI)
+ hfs_byte_t fi_magic1; /* Magic number: */
+#define HFS_CAP_MAGIC1 0xFF
+ hfs_byte_t fi_version; /* Version of this structure: */
+#define HFS_CAP_VERSION 0x10
+ hfs_byte_t fi_magic; /* Another magic number: */
+#define HFS_CAP_MAGIC 0xDA
+ hfs_byte_t fi_bitmap; /* Bitmap of which names are valid: */
+#define HFS_CAP_SHORTNAME 0x01
+#define HFS_CAP_LONGNAME 0x02
+ hfs_byte_t fi_shortfilename[12+1]; /* "short name" (unused) */
+ hfs_byte_t fi_macfilename[32+1]; /* Original (Macintosh) name */
+ hfs_byte_t fi_comln; /* Length of comment (always 0) */
+ hfs_byte_t fi_comnt[200]; /* Finder comment (unused) */
+ /* optional: used by aufs only if compiled with USE_MAC_DATES */
+ hfs_byte_t fi_datemagic; /* Magic number for dates extension: */
+#define HFS_CAP_DMAGIC 0xDA
+ hfs_byte_t fi_datevalid; /* Bitmap of which dates are valid: */
+#define HFS_CAP_MDATE 0x01
+#define HFS_CAP_CDATE 0x02
+ hfs_lword_t fi_ctime; /* Creation date (in AFP format) */
+ hfs_lword_t fi_mtime; /* Modify date (in AFP format) */
+ hfs_lword_t fi_utime; /* Un*x time of last mtime change */
+ hfs_byte_t pad;
+};
+
+#ifdef __KERNEL__
+
+typedef ssize_t hfs_rwret_t;
+typedef size_t hfs_rwarg_t;
+
+#include <asm/uaccess.h>
+
+/* Some forward declarations */
+struct hfs_fork;
+struct hfs_cat_key;
+struct hfs_cat_entry;
+extern struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *,
+ const struct hfs_cat_key *);
+
+/* dir.c */
+extern hfs_rwret_t hfs_dir_read(struct file *, char *, hfs_rwarg_t,
+ loff_t *);
+extern int hfs_create(struct inode *, struct dentry *, int);
+extern int hfs_mkdir(struct inode *, struct dentry *, int);
+extern int hfs_mknod(struct inode *, struct dentry *, int, int);
+extern int hfs_unlink(struct inode *, struct dentry *);
+extern int hfs_rmdir(struct inode *, struct dentry *);
+extern int hfs_rename(struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
+
+/* dir_cap.c */
+extern const struct hfs_name hfs_cap_reserved1[];
+extern const struct hfs_name hfs_cap_reserved2[];
+extern struct inode_operations hfs_cap_ndir_inode_operations;
+extern struct inode_operations hfs_cap_fdir_inode_operations;
+extern struct inode_operations hfs_cap_rdir_inode_operations;
+extern void hfs_cap_drop_dentry(struct dentry *, const ino_t);
+
+/* dir_dbl.c */
+extern const struct hfs_name hfs_dbl_reserved1[];
+extern const struct hfs_name hfs_dbl_reserved2[];
+extern struct inode_operations hfs_dbl_dir_inode_operations;
+extern void hfs_dbl_drop_dentry(struct dentry *, const ino_t);
+
+/* dir_nat.c */
+extern const struct hfs_name hfs_nat_reserved1[];
+extern const struct hfs_name hfs_nat_reserved2[];
+extern struct inode_operations hfs_nat_ndir_inode_operations;
+extern struct inode_operations hfs_nat_hdir_inode_operations;
+extern void hfs_nat_drop_dentry(struct dentry *, const ino_t);
+
+/* dir_sngl.c */
+extern const struct hfs_name hfs_sngl_reserved1[];
+extern const struct hfs_name hfs_sngl_reserved2[];
+extern struct inode_operations hfs_sngl_dir_inode_operations;
+
+/* file.c */
+extern hfs_s32 hfs_do_read(struct inode *, struct hfs_fork *, hfs_u32,
+ char *, hfs_u32, int);
+extern hfs_s32 hfs_do_write(struct inode *, struct hfs_fork *, hfs_u32,
+ const char *, hfs_u32);
+extern void hfs_file_fix_mode(struct hfs_cat_entry *entry);
+extern struct inode_operations hfs_file_inode_operations;
+
+/* file_cap.c */
+extern struct inode_operations hfs_cap_info_inode_operations;
+
+/* file_hdr.c */
+extern struct inode_operations hfs_hdr_inode_operations;
+extern const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout;
+extern const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout;
+extern const struct hfs_hdr_layout hfs_nat_hdr_layout;
+extern const struct hfs_hdr_layout hfs_nat2_hdr_layout;
+extern const struct hfs_hdr_layout hfs_sngl_hdr_layout;
+
+/* inode.c */
+extern void hfs_put_inode(struct inode *);
+extern int hfs_notify_change(struct dentry *, struct iattr *);
+extern struct inode *hfs_iget(struct hfs_cat_entry *, ino_t, struct dentry *);
+
+extern void hfs_cap_ifill(struct inode *, ino_t, const int);
+extern void hfs_dbl_ifill(struct inode *, ino_t, const int);
+extern void hfs_nat_ifill(struct inode *, ino_t, const int);
+extern void hfs_sngl_ifill(struct inode *, ino_t, const int);
+
+/* super.c */
+extern struct super_block *hfs_read_super(struct super_block *,void *,int);
+extern int init_hfs_fs(void);
+
+/* trans.c */
+extern void hfs_colon2mac(struct hfs_name *, const char *, int);
+extern void hfs_prcnt2mac(struct hfs_name *, const char *, int);
+extern void hfs_triv2mac(struct hfs_name *, const char *, int);
+extern void hfs_latin2mac(struct hfs_name *, const char *, int);
+extern int hfs_mac2cap(char *, const struct hfs_name *);
+extern int hfs_mac2nat(char *, const struct hfs_name *);
+extern int hfs_mac2latin(char *, const struct hfs_name *);
+extern int hfs_mac2seven(char *, const struct hfs_name *);
+extern int hfs_mac2eight(char *, const struct hfs_name *);
+extern int hfs_mac2alpha(char *, const struct hfs_name *);
+extern int hfs_mac2triv(char *, const struct hfs_name *);
+extern void hfs_tolower(unsigned char *, int);
+
+#define HFS_I(X) (&((X)->u.hfs_i))
+#define HFS_SB(X) (&((X)->u.hfs_sb))
+
+extern __inline__ void hfs_nameout(struct inode *dir, struct hfs_name *out,
+ const char *in, int len) {
+ HFS_SB(dir->i_sb)->s_nameout(out, in, len);
+}
+
+extern __inline__ int hfs_namein(struct inode *dir, char *out,
+ const struct hfs_name *in) {
+ int len = HFS_SB(dir->i_sb)->s_namein(out, in);
+ if (HFS_SB(dir->i_sb)->s_lowercase) {
+ hfs_tolower(out, len);
+ }
+ return len;
+}
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/pfinet/linux-src/include/linux/hfs_fs_i.h b/pfinet/linux-src/include/linux/hfs_fs_i.h
new file mode 100644
index 00000000..03585a08
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hfs_fs_i.h
@@ -0,0 +1,43 @@
+/*
+ * linux/include/linux/hfs_fs_i.h
+ *
+ * Copyright (C) 1995, 1996 Paul H. Hargrove
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ * This file defines the type (struct hfs_inode_info) and the two
+ * subordinate types hfs_extent and hfs_file.
+ */
+
+#ifndef _LINUX_HFS_FS_I_H
+#define _LINUX_HFS_FS_I_H
+
+/*
+ * struct hfs_inode_info
+ *
+ * The HFS-specific part of a Linux (struct inode)
+ */
+struct hfs_inode_info {
+ int magic; /* A magic number */
+
+ struct hfs_cat_entry *entry;
+
+ /* For a regular or header file */
+ struct hfs_fork *fork;
+ int convert;
+
+ /* For a directory */
+ ino_t file_type;
+ char dir_size;
+
+ /* For header files */
+ const struct hfs_hdr_layout *default_layout;
+ struct hfs_hdr_layout *layout;
+
+ /* to deal with localtime ugliness */
+ int tz_secondswest;
+
+ /* for dentry cleanup */
+ void (*d_drop_op)(struct dentry *, const ino_t);
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/hfs_fs_sb.h b/pfinet/linux-src/include/linux/hfs_fs_sb.h
new file mode 100644
index 00000000..826f388c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hfs_fs_sb.h
@@ -0,0 +1,53 @@
+/*
+ * linux/include/linux/hfs_fs_sb.h
+ *
+ * Copyright (C) 1995-1997 Paul H. Hargrove
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ * This file defines the type (struct hfs_sb_info) which contains the
+ * HFS-specific information in the in-core superblock.
+ */
+
+#ifndef _LINUX_HFS_FS_SB_H
+#define _LINUX_HFS_FS_SB_H
+
+/* forward declaration: */
+struct hfs_name;
+
+typedef int (*hfs_namein_fn) (char *, const struct hfs_name *);
+typedef void (*hfs_nameout_fn) (struct hfs_name *, const char *, int);
+typedef void (*hfs_ifill_fn) (struct inode *, ino_t, const int);
+
+/*
+ * struct hfs_sb_info
+ *
+ * The HFS-specific part of a Linux (struct super_block)
+ */
+struct hfs_sb_info {
+ int magic; /* A magic number */
+ struct hfs_mdb *s_mdb; /* The HFS MDB */
+ int s_quiet; /* Silent failure when
+ changing owner or mode? */
+ int s_lowercase; /* Map names to lowercase? */
+ int s_afpd; /* AFPD compatible mode? */
+ int s_version; /* version info */
+ hfs_namein_fn s_namein; /* The function used to
+ map Mac filenames to
+ Linux filenames */
+ hfs_nameout_fn s_nameout; /* The function used to
+ map Linux filenames
+ to Mac filenames */
+ hfs_ifill_fn s_ifill; /* The function used
+ to fill in inode fields */
+ const struct hfs_name *s_reserved1; /* Reserved names */
+ const struct hfs_name *s_reserved2; /* Reserved names */
+ __u32 s_type; /* Type for new files */
+ __u32 s_creator; /* Creator for new files */
+ umode_t s_umask; /* The umask applied to the
+ permissions on all files */
+ uid_t s_uid; /* The uid of all files */
+ gid_t s_gid; /* The gid of all files */
+ char s_conv; /* Type of text conversion */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/hfs_sysdep.h b/pfinet/linux-src/include/linux/hfs_sysdep.h
new file mode 100644
index 00000000..00cc6400
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hfs_sysdep.h
@@ -0,0 +1,245 @@
+/*
+ * linux/include/linux/hfs_sysdep.h
+ *
+ * Copyright (C) 1996-1997 Paul H. Hargrove
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ * This file contains constants, types and inline
+ * functions for various system dependent things.
+ *
+ * "XXX" in a comment is a note to myself to consider changing something.
+ *
+ * In function preconditions the term "valid" applied to a pointer to
+ * a structure means that the pointer is non-NULL and the structure it
+ * points to has all fields initialized to consistent values.
+ */
+
+#ifndef _HFS_SYSDEP_H
+#define _HFS_SYSDEP_H
+
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/locks.h>
+#include <linux/fs.h>
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+extern struct timezone sys_tz;
+
+#undef offsetof
+#define offsetof(TYPE, MEMB) ((size_t) &((TYPE *)0)->MEMB)
+
+/* Typedefs for integer types by size and signedness */
+typedef __u8 hfs_u8;
+typedef __u16 hfs_u16;
+typedef __u32 hfs_u32;
+typedef __s8 hfs_s8;
+typedef __s16 hfs_s16;
+typedef __s32 hfs_s32;
+
+/* Typedefs for unaligned integer types */
+typedef unsigned char hfs_byte_t;
+typedef unsigned char hfs_word_t[2];
+typedef unsigned char hfs_lword_t[4];
+
+/* these funny looking things are GCC variable argument macros */
+#define hfs_warn(format, args...) printk(KERN_WARNING format , ## args)
+#define hfs_error(format, args...) printk(KERN_ERR format , ## args)
+
+
+#if defined(DEBUG_ALL) || defined(DEBUG_MEM)
+extern long int hfs_alloc;
+#endif
+
+extern inline void *hfs_malloc(unsigned int size) {
+#if defined(DEBUG_ALL) || defined(DEBUG_MEM)
+ hfs_warn("%ld bytes allocation at %s:%u\n",
+ (hfs_alloc += size), __FILE__, __LINE__);
+#endif
+ return kmalloc(size, GFP_KERNEL);
+}
+
+extern inline void hfs_free(void *ptr, unsigned int size) {
+ kfree_s(ptr, size);
+#if defined(DEBUG_ALL) || defined(DEBUG_MEM)
+ hfs_warn("%ld bytes allocation at %s:%u\n",
+ (hfs_alloc -= ptr ? size : 0), __FILE__, __LINE__);
+#endif
+}
+
+
+/* handle conversion between times.
+ *
+ * NOTE: hfs+ doesn't need this. also, we don't use tz_dsttime as that's
+ * not a good thing to do. instead, we depend upon tz_minuteswest
+ * having the correct daylight savings correction.
+ */
+extern inline hfs_u32 hfs_from_utc(hfs_s32 time)
+{
+ return time - sys_tz.tz_minuteswest*60;
+}
+
+extern inline hfs_s32 hfs_to_utc(hfs_u32 time)
+{
+ return time + sys_tz.tz_minuteswest*60;
+}
+
+extern inline hfs_u32 hfs_time(void) {
+ return htonl(hfs_from_utc(CURRENT_TIME)+2082844800U);
+}
+
+
+/*
+ * hfs_wait_queue
+ */
+typedef struct wait_queue *hfs_wait_queue;
+
+extern inline void hfs_init_waitqueue(hfs_wait_queue *queue) {
+ init_waitqueue(queue);
+}
+
+extern inline void hfs_sleep_on(hfs_wait_queue *queue) {
+ sleep_on(queue);
+}
+
+extern inline void hfs_wake_up(hfs_wait_queue *queue) {
+ wake_up(queue);
+}
+
+extern inline void hfs_relinquish(void) {
+ schedule();
+}
+
+
+/*
+ * hfs_sysmdb
+ */
+typedef struct super_block *hfs_sysmdb;
+
+extern inline void hfs_mdb_dirty(hfs_sysmdb sys_mdb) {
+ sys_mdb->s_dirt = 1;
+}
+
+extern inline char *hfs_mdb_name(hfs_sysmdb sys_mdb) {
+ return kdevname(sys_mdb->s_dev);
+}
+
+
+/*
+ * hfs_sysentry
+ */
+typedef struct dentry *hfs_sysentry[4];
+
+/*
+ * hfs_buffer
+ */
+typedef struct buffer_head *hfs_buffer;
+
+#define HFS_BAD_BUFFER NULL
+
+/* In sysdep.c, since it needs HFS_SECTOR_SIZE */
+extern hfs_buffer hfs_buffer_get(hfs_sysmdb, int, int);
+
+extern inline int hfs_buffer_ok(hfs_buffer buffer) {
+ return (buffer != NULL);
+}
+
+extern inline void hfs_buffer_put(hfs_buffer buffer) {
+ brelse(buffer);
+}
+
+extern inline void hfs_buffer_dirty(hfs_buffer buffer) {
+ mark_buffer_dirty(buffer, 1);
+}
+
+extern inline void hfs_buffer_sync(hfs_buffer buffer) {
+ while (buffer_locked(buffer)) {
+ wait_on_buffer(buffer);
+ }
+ if (buffer_dirty(buffer)) {
+ ll_rw_block(WRITE, 1, &buffer);
+ wait_on_buffer(buffer);
+ }
+}
+
+extern inline void *hfs_buffer_data(const hfs_buffer buffer) {
+ return buffer->b_data;
+}
+
+
+/*
+ * bit operations
+ */
+
+#undef BITNR
+#if defined(__BIG_ENDIAN)
+# define BITNR(X) ((X)^31)
+# if !defined(__constant_htonl)
+# define __constant_htonl(x) (x)
+# endif
+# if !defined(__constant_htons)
+# define __constant_htons(x) (x)
+# endif
+#elif defined(__LITTLE_ENDIAN)
+# define BITNR(X) ((X)^7)
+# if !defined(__constant_htonl)
+# define __constant_htonl(x) \
+ ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
+ (((unsigned long int)(x) & 0x0000ff00U) << 8) | \
+ (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
+ (((unsigned long int)(x) & 0xff000000U) >> 24)))
+# endif
+# if !defined(__constant_htons)
+# define __constant_htons(x) \
+ ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
+ (((unsigned short int)(x) & 0xff00) >> 8)))
+# endif
+#else
+# error "Don't know if bytes are big- or little-endian!"
+#endif
+
+extern inline int hfs_clear_bit(int bitnr, hfs_u32 *lword) {
+ return test_and_clear_bit(BITNR(bitnr), lword);
+}
+
+extern inline int hfs_set_bit(int bitnr, hfs_u32 *lword) {
+ return test_and_set_bit(BITNR(bitnr), lword);
+}
+
+extern inline int hfs_test_bit(int bitnr, const hfs_u32 *lword) {
+ /* the kernel should declare the second arg of test_bit as const */
+ return test_bit(BITNR(bitnr), (void *)lword);
+}
+
+#undef BITNR
+
+/*
+ * HFS structures have fields aligned to 16-bit boundaries.
+ * So, 16-bit get/put are easy while 32-bit get/put need
+ * some care on architectures like the DEC Alpha.
+ *
+ * In what follows:
+ * ns = 16-bit integer in network byte-order w/ 16-bit alignment
+ * hs = 16-bit integer in host byte-order w/ 16-bit alignment
+ * nl = 32-bit integer in network byte-order w/ unknown alignment
+ * hl = 32-bit integer in host byte-order w/ unknown alignment
+ * anl = 32-bit integer in network byte-order w/ 32-bit alignment
+ * ahl = 32-bit integer in host byte-order w/ 32-bit alignment
+ * Example: hfs_get_hl() gets an unaligned 32-bit integer converting
+ * it to host byte-order.
+ */
+#define hfs_get_hs(addr) ntohs(*((hfs_u16 *)(addr)))
+#define hfs_get_ns(addr) (*((hfs_u16 *)(addr)))
+#define hfs_get_hl(addr) ntohl(get_unaligned((hfs_u32 *)(addr)))
+#define hfs_get_nl(addr) get_unaligned((hfs_u32 *)(addr))
+#define hfs_get_ahl(addr) ntohl(*((hfs_u32 *)(addr)))
+#define hfs_get_anl(addr) (*((hfs_u32 *)(addr)))
+#define hfs_put_hs(val, addr) ((void)(*((hfs_u16 *)(addr)) = ntohs(val)))
+#define hfs_put_ns(val, addr) ((void)(*((hfs_u16 *)(addr)) = (val)))
+#define hfs_put_hl(val, addr) put_unaligned(htonl(val), (hfs_u32 *)(addr))
+#define hfs_put_nl(val, addr) put_unaligned((val), (hfs_u32 *)(addr))
+#define hfs_put_ahl(val, addr) ((void)(*((hfs_u32 *)(addr)) = ntohl(val)))
+#define hfs_put_anl(val, addr) ((void)(*((hfs_u32 *)(addr)) = (val)))
+
+#endif
diff --git a/pfinet/linux-src/include/linux/hippidevice.h b/pfinet/linux-src/include/linux/hippidevice.h
new file mode 100644
index 00000000..e345a9d2
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hippidevice.h
@@ -0,0 +1,58 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the HIPPI handlers.
+ *
+ * Version: @(#)hippidevice.h 1.0.0 05/26/97
+ *
+ * Author: Jes Sorensen, <Jes.Sorensen@cern.ch>
+ *
+ * hippidevice.h is based on previous fddidevice.h work by
+ * Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Lawrence V. Stefani, <stefani@lkg.dec.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_HIPPIDEVICE_H
+#define _LINUX_HIPPIDEVICE_H
+
+#include <linux/if_hippi.h>
+
+#ifdef __KERNEL__
+extern int hippi_header(struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type,
+ void *daddr,
+ void *saddr,
+ unsigned len);
+
+extern int hippi_rebuild_header(struct sk_buff *skb);
+
+extern unsigned short hippi_type_trans(struct sk_buff *skb,
+ struct device *dev);
+
+extern void hippi_header_cache_bind(struct hh_cache ** hhp,
+ struct device *dev,
+ unsigned short htype,
+ __u32 daddr);
+
+extern void hippi_header_cache_update(struct hh_cache *hh,
+ struct device *dev,
+ unsigned char * haddr);
+extern int hippi_header_parse(struct sk_buff *skb, unsigned char *haddr);
+
+extern void hippi_net_init(void);
+void hippi_setup(struct device *dev);
+
+extern struct device *init_hippi_dev(struct device *, int);
+extern void unregister_hipdev(struct device *dev);
+#endif
+
+#endif /* _LINUX_HIPPIDEVICE_H */
diff --git a/pfinet/linux-src/include/linux/hpfs_fs.h b/pfinet/linux-src/include/linux/hpfs_fs.h
new file mode 100644
index 00000000..2b7926ab
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hpfs_fs.h
@@ -0,0 +1,13 @@
+#ifndef _LINUX_HPFS_FS_H
+#define _LINUX_HPFS_FS_H
+
+/* HPFS magic number (word 0 of block 16) */
+
+#define HPFS_SUPER_MAGIC 0xf995e849
+
+/* The entry point for a VFS */
+
+extern struct super_block *hpfs_read_super (struct super_block *, void *, int);
+extern int init_hpfs_fs(void);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/hpfs_fs_i.h b/pfinet/linux-src/include/linux/hpfs_fs_i.h
new file mode 100644
index 00000000..d9aa8f34
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hpfs_fs_i.h
@@ -0,0 +1,24 @@
+#ifndef _HPFS_FS_I
+#define _HPFS_FS_I
+
+struct hpfs_inode_info {
+ ino_t i_parent_dir; /* (directories) gives fnode of parent dir */
+ unsigned i_dno; /* (directories) root dnode */
+ unsigned i_dpos; /* (directories) temp for readdir */
+ unsigned i_dsubdno; /* (directories) temp for readdir */
+ unsigned i_file_sec; /* (files) minimalist cache of alloc info */
+ unsigned i_disk_sec; /* (files) minimalist cache of alloc info */
+ unsigned i_n_secs; /* (files) minimalist cache of alloc info */
+ unsigned i_conv : 2; /* (files) crlf->newline hackery */
+};
+
+#define i_hpfs_dno u.hpfs_i.i_dno
+#define i_hpfs_parent_dir u.hpfs_i.i_parent_dir
+#define i_hpfs_n_secs u.hpfs_i.i_n_secs
+#define i_hpfs_file_sec u.hpfs_i.i_file_sec
+#define i_hpfs_disk_sec u.hpfs_i.i_disk_sec
+#define i_hpfs_dpos u.hpfs_i.i_dpos
+#define i_hpfs_dsubdno u.hpfs_i.i_dsubdno
+#define i_hpfs_conv u.hpfs_i.i_conv
+
+#endif
diff --git a/pfinet/linux-src/include/linux/hpfs_fs_sb.h b/pfinet/linux-src/include/linux/hpfs_fs_sb.h
new file mode 100644
index 00000000..a383e16b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/hpfs_fs_sb.h
@@ -0,0 +1,32 @@
+#ifndef _HPFS_FS_SB
+#define _HPFS_FS_SB
+
+struct hpfs_sb_info {
+ ino_t sb_root; /* inode number of root dir */
+ unsigned sb_fs_size; /* file system size, sectors */
+ unsigned sb_bitmaps; /* sector number of bitmap list */
+ unsigned sb_dirband_size; /* directory band size, dnodes */
+ unsigned sb_dmap; /* sector number of dnode bit map */
+ unsigned sb_n_free; /* free blocks for statfs, or -1 */
+ unsigned sb_n_free_dnodes; /* free dnodes for statfs, or -1 */
+ uid_t sb_uid; /* uid from mount options */
+ gid_t sb_gid; /* gid from mount options */
+ umode_t sb_mode; /* mode from mount options */
+ unsigned sb_lowercase : 1; /* downcase filenames hackery */
+ unsigned sb_conv : 2; /* crlf->newline hackery */
+};
+
+#define s_hpfs_root u.hpfs_sb.sb_root
+#define s_hpfs_fs_size u.hpfs_sb.sb_fs_size
+#define s_hpfs_bitmaps u.hpfs_sb.sb_bitmaps
+#define s_hpfs_dirband_size u.hpfs_sb.sb_dirband_size
+#define s_hpfs_dmap u.hpfs_sb.sb_dmap
+#define s_hpfs_uid u.hpfs_sb.sb_uid
+#define s_hpfs_gid u.hpfs_sb.sb_gid
+#define s_hpfs_mode u.hpfs_sb.sb_mode
+#define s_hpfs_n_free u.hpfs_sb.sb_n_free
+#define s_hpfs_n_free_dnodes u.hpfs_sb.sb_n_free_dnodes
+#define s_hpfs_lowercase u.hpfs_sb.sb_lowercase
+#define s_hpfs_conv u.hpfs_sb.sb_conv
+
+#endif
diff --git a/pfinet/linux-src/include/linux/i2c.h b/pfinet/linux-src/include/linux/i2c.h
new file mode 100644
index 00000000..8b355d9e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/i2c.h
@@ -0,0 +1,190 @@
+#ifndef I2C_H
+#define I2C_H
+
+/*
+ * linux i2c interface. Works a little bit like the scsi subsystem.
+ * There are:
+ *
+ * i2c the basic control module (like scsi_mod)
+ * bus driver a driver with a i2c bus (hostadapter driver)
+ * chip driver a driver for a chip connected
+ * to a i2c bus (cdrom/hd driver)
+ *
+ * A device will be attached to one bus and one chip driver. Every chip
+ * driver gets a unique ID.
+ *
+ * A chip driver can provide a ioctl-like callback for the
+ * communication with other parts of the kernel (not every i2c chip is
+ * useful without other devices, a TV card tuner for example).
+ *
+ * "i2c internal" parts of the structs: only the i2c module is allowed to
+ * write to them, for others they are read-only.
+ *
+ */
+
+#define I2C_BUS_MAX 4 /* max # of bus drivers */
+#define I2C_DRIVER_MAX 8 /* max # of chip drivers */
+#define I2C_DEVICE_MAX 8 /* max # if devices per bus/driver */
+
+struct i2c_bus;
+struct i2c_driver;
+struct i2c_device;
+
+#define I2C_DRIVERID_MSP3400 1
+#define I2C_DRIVERID_TUNER 2
+#define I2C_DRIVERID_VIDEOTEXT 3
+#define I2C_DRIVERID_VIDEODECODER 4
+#define I2C_DRIVERID_VIDEOENCODER 5
+
+#define I2C_BUSID_BT848 1 /* I2C bus on a BT848 */
+ /* 2 is used in 2.3.x */
+#define I2C_BUSID_BUZ 3 /* I2C bus on a BUZ */
+#define I2C_BUSID_ZORAN 4 /* I2C bus on a Zoran */
+#define I2C_BUSID_SGIVWFB 5 /* Moved to be unique */
+
+/*
+ * struct for a driver for a i2c chip (tuner, soundprocessor,
+ * videotext, ... ).
+ *
+ * a driver will register within the i2c module. The i2c module will
+ * callback the driver (i2c_attach) for every device it finds on a i2c
+ * bus at the specified address. If the driver decides to "accept"
+ * the, device, it must return a struct i2c_device, and NULL
+ * otherwise.
+ *
+ * i2c_detach = i2c_attach ** -1
+ *
+ * i2c_command will be used to pass commands to the driver in a
+ * ioctl-line manner.
+ *
+ */
+
+struct i2c_driver
+{
+ char name[32]; /* some useful label */
+ int id; /* device type ID */
+ unsigned char addr_l, addr_h; /* address range of the chip */
+
+ int (*attach)(struct i2c_device *device);
+ int (*detach)(struct i2c_device *device);
+ int (*command)(struct i2c_device *device,unsigned int cmd, void *arg);
+
+ /* i2c internal */
+ struct i2c_device *devices[I2C_DEVICE_MAX];
+ int devcount;
+};
+
+
+/*
+ * this holds the informations about a i2c bus available in the system.
+ *
+ * a chip with a i2c bus interface (like bt848) registers the bus within
+ * the i2c module. This struct provides functions to access the i2c bus.
+ *
+ * One must hold the spinlock to access the i2c bus (XXX: is the irqsave
+ * required? Maybe better use a semaphore?).
+ * [-AC-] having a spinlock_irqsave is only needed if we have drivers wishing
+ * to bang their i2c bus from an interrupt.
+ *
+ * attach/detach_inform is a callback to inform the bus driver about
+ * attached chip drivers.
+ *
+ */
+
+/* needed: unsigned long flags */
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x020100
+# if 0
+# define LOCK_FLAGS unsigned long flags;
+# define LOCK_I2C_BUS(bus) spin_lock_irqsave(&(bus->bus_lock),flags);
+# define UNLOCK_I2C_BUS(bus) spin_unlock_irqrestore(&(bus->bus_lock),flags);
+# else
+# define LOCK_FLAGS
+# define LOCK_I2C_BUS(bus) spin_lock(&(bus->bus_lock));
+# define UNLOCK_I2C_BUS(bus) spin_unlock(&(bus->bus_lock));
+# endif
+#else
+# define LOCK_FLAGS unsigned long flags;
+# define LOCK_I2C_BUS(bus) { save_flags(flags); cli(); }
+# define UNLOCK_I2C_BUS(bus) { restore_flags(flags); }
+#endif
+
+struct i2c_bus
+{
+ char name[32]; /* some useful label */
+ int id;
+ void *data; /* free for use by the bus driver */
+
+#if LINUX_VERSION_CODE >= 0x020100
+ spinlock_t bus_lock;
+#endif
+
+ /* attach/detach inform callbacks */
+ void (*attach_inform)(struct i2c_bus *bus, int id);
+ void (*detach_inform)(struct i2c_bus *bus, int id);
+
+ /* Software I2C */
+ void (*i2c_setlines)(struct i2c_bus *bus, int ctrl, int data);
+ int (*i2c_getdataline)(struct i2c_bus *bus);
+
+ /* Hardware I2C */
+ int (*i2c_read)(struct i2c_bus *bus, unsigned char addr);
+ int (*i2c_write)(struct i2c_bus *bus, unsigned char addr,
+ unsigned char b1, unsigned char b2, int both);
+
+ /* internal data for i2c module */
+ struct i2c_device *devices[I2C_DEVICE_MAX];
+ int devcount;
+};
+
+
+/*
+ * This holds per-device data for a i2c device
+ */
+
+struct i2c_device
+{
+ char name[32]; /* some useful label */
+ void *data; /* free for use by the chip driver */
+ unsigned char addr; /* chip addr */
+
+ /* i2c internal */
+ struct i2c_bus *bus;
+ struct i2c_driver *driver;
+};
+
+
+/* ------------------------------------------------------------------- */
+/* i2c module functions */
+
+/* register/unregister a i2c bus */
+int i2c_register_bus(struct i2c_bus *bus);
+int i2c_unregister_bus(struct i2c_bus *bus);
+
+/* register/unregister a chip driver */
+int i2c_register_driver(struct i2c_driver *driver);
+int i2c_unregister_driver(struct i2c_driver *driver);
+
+/* send a command to a chip using the ioctl-like callback interface */
+int i2c_control_device(struct i2c_bus *bus, int id,
+ unsigned int cmd, void *arg);
+
+/* i2c bus access functions */
+void i2c_start(struct i2c_bus *bus);
+void i2c_stop(struct i2c_bus *bus);
+void i2c_one(struct i2c_bus *bus);
+void i2c_zero(struct i2c_bus *bus);
+int i2c_ack(struct i2c_bus *bus);
+
+int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack);
+unsigned char i2c_readbyte(struct i2c_bus *bus,int last);
+
+/* i2c (maybe) hardware functions */
+int i2c_read(struct i2c_bus *bus, unsigned char addr);
+int i2c_write(struct i2c_bus *bus, unsigned char addr,
+ unsigned char b1, unsigned char b2, int both);
+
+int i2c_init(void);
+#endif /* I2C_H */
diff --git a/pfinet/linux/icmp.h b/pfinet/linux-src/include/linux/icmp.h
index 334c756d..fb4ed8b9 100644
--- a/pfinet/linux/icmp.h
+++ b/pfinet/linux-src/include/linux/icmp.h
@@ -30,6 +30,7 @@
#define ICMP_INFO_REPLY 16 /* Information Reply */
#define ICMP_ADDRESS 17 /* Address Mask Request */
#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */
+#define NR_ICMP_TYPES 18
/* Codes for UNREACH. */
@@ -46,6 +47,10 @@
#define ICMP_HOST_ANO 10
#define ICMP_NET_UNR_TOS 11
#define ICMP_HOST_UNR_TOS 12
+#define ICMP_PKT_FILTERED 13 /* Packet filtered */
+#define ICMP_PREC_VIOLATION 14 /* Precedence violation */
+#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */
+#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */
/* Codes for REDIRECT. */
#define ICMP_REDIR_NET 0 /* Redirect Net */
@@ -59,23 +64,39 @@
struct icmphdr {
- unsigned char type;
- unsigned char code;
- unsigned short checksum;
+ __u8 type;
+ __u8 code;
+ __u16 checksum;
union {
struct {
- unsigned short id;
- unsigned short sequence;
+ __u16 id;
+ __u16 sequence;
} echo;
- unsigned long gateway;
+ __u32 gateway;
+ struct {
+ __u16 __unused;
+ __u16 mtu;
+ } frag;
} un;
};
+#ifdef __KERNEL__
struct icmp_err {
- int error;
+ int errno;
unsigned fatal:1;
};
+#endif
+
+/*
+ * constants for (set|get)sockopt
+ */
+
+#define ICMP_FILTER 1
+
+struct icmp_filter {
+ __u32 data;
+};
#endif /* _LINUX_ICMP_H */
diff --git a/pfinet/linux-src/include/linux/icmpv6.h b/pfinet/linux-src/include/linux/icmpv6.h
new file mode 100644
index 00000000..fcd6fce2
--- /dev/null
+++ b/pfinet/linux-src/include/linux/icmpv6.h
@@ -0,0 +1,149 @@
+#ifndef _LINUX_ICMPV6_H
+#define _LINUX_ICMPV6_H
+
+#include <asm/byteorder.h>
+
+struct icmp6hdr {
+
+ __u8 icmp6_type;
+ __u8 icmp6_code;
+ __u16 icmp6_cksum;
+
+
+ union {
+ __u32 un_data32[1];
+ __u16 un_data16[2];
+ __u8 un_data8[4];
+
+ struct icmpv6_echo {
+ __u16 identifier;
+ __u16 sequence;
+ } u_echo;
+
+ struct icmpv6_nd_advt {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u32 reserved:5,
+ override:1,
+ solicited:1,
+ router:1,
+ reserved2:24;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u32 router:1,
+ solicited:1,
+ override:1,
+ reserved:29;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ } u_nd_advt;
+
+ struct icmpv6_nd_ra {
+ __u8 hop_limit;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 reserved:6,
+ other:1,
+ managed:1;
+
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 managed:1,
+ other:1,
+ reserved:6;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u16 rt_lifetime;
+ } u_nd_ra;
+
+ } icmp6_dataun;
+
+#define icmp6_identifier icmp6_dataun.u_echo.identifier
+#define icmp6_sequence icmp6_dataun.u_echo.sequence
+#define icmp6_pointer icmp6_dataun.un_data32[0]
+#define icmp6_mtu icmp6_dataun.un_data32[0]
+#define icmp6_unused icmp6_dataun.un_data32[0]
+#define icmp6_maxdelay icmp6_dataun.un_data16[0]
+#define icmp6_router icmp6_dataun.u_nd_advt.router
+#define icmp6_solicited icmp6_dataun.u_nd_advt.solicited
+#define icmp6_override icmp6_dataun.u_nd_advt.override
+#define icmp6_ndiscreserved icmp6_dataun.u_nd_advt.reserved
+#define icmp6_hop_limit icmp6_dataun.u_nd_ra.hop_limit
+#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
+#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
+#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
+};
+
+
+#define ICMPV6_DEST_UNREACH 1
+#define ICMPV6_PKT_TOOBIG 2
+#define ICMPV6_TIME_EXCEED 3
+#define ICMPV6_PARAMPROB 4
+
+#define ICMPV6_INFOMSG_MASK 0x80
+
+#define ICMPV6_ECHO_REQUEST 128
+#define ICMPV6_ECHO_REPLY 129
+#define ICMPV6_MGM_QUERY 130
+#define ICMPV6_MGM_REPORT 131
+#define ICMPV6_MGM_REDUCTION 132
+
+/*
+ * Codes for Destination Unreachable
+ */
+#define ICMPV6_NOROUTE 0
+#define ICMPV6_ADM_PROHIBITED 1
+#define ICMPV6_NOT_NEIGHBOUR 2
+#define ICMPV6_ADDR_UNREACH 3
+#define ICMPV6_PORT_UNREACH 4
+
+/*
+ * Codes for Time Exceeded
+ */
+#define ICMPV6_EXC_HOPLIMIT 0
+#define ICMPV6_EXC_FRAGTIME 1
+
+/*
+ * Codes for Parameter Problem
+ */
+#define ICMPV6_HDR_FIELD 0
+#define ICMPV6_UNK_NEXTHDR 1
+#define ICMPV6_UNK_OPTION 2
+
+/*
+ * constants for (set|get)sockopt
+ */
+
+#define ICMPV6_FILTER 1
+
+/*
+ * ICMPV6 filter
+ */
+
+#define ICMPV6_FILTER_BLOCK 1
+#define ICMPV6_FILTER_PASS 2
+#define ICMPV6_FILTER_BLOCKOTHERS 3
+#define ICMPV6_FILTER_PASSONLY 4
+
+struct icmp6_filter {
+ __u32 data[8];
+};
+
+#ifdef __KERNEL__
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+
+extern void icmpv6_send(struct sk_buff *skb,
+ int type, int code,
+ __u32 info,
+ struct device *dev);
+
+extern int icmpv6_init(struct net_proto_family *ops);
+extern int icmpv6_err_convert(int type, int code,
+ int *err);
+extern void icmpv6_cleanup(void);
+extern void icmpv6_param_prob(struct sk_buff *skb,
+ int code, void *pos);
+#endif
+
+#endif
diff --git a/pfinet/linux/if.h b/pfinet/linux-src/include/linux/if.h
index cb6b4e05..c95f372c 100644
--- a/pfinet/linux/if.h
+++ b/pfinet/linux-src/include/linux/if.h
@@ -19,7 +19,7 @@
#ifndef _LINUX_IF_H
#define _LINUX_IF_H
-#include <linux/types.h> /* for "caddr_t" et al */
+#include <linux/types.h> /* for "__kernel_caddr_t" et al */
#include <linux/socket.h> /* for "struct sockaddr" et al */
/* Standard interface flags. */
@@ -32,7 +32,6 @@
#define IFF_RUNNING 0x40 /* resources allocated */
#define IFF_NOARP 0x80 /* no ARP protocol */
#define IFF_PROMISC 0x100 /* receive all packets */
-/* Not supported */
#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/
#define IFF_MASTER 0x400 /* master of a load balancer */
@@ -40,27 +39,11 @@
#define IFF_MULTICAST 0x1000 /* Supports multicast */
-/*
- * The ifaddr structure contains information about one address
- * of an interface. They are maintained by the different address
- * families, are allocated and attached when an address is set,
- * and are linked together so all addresses for an interface can
- * be located.
- */
-
-struct ifaddr
-{
- struct sockaddr ifa_addr; /* address of interface */
- union {
- struct sockaddr ifu_broadaddr;
- struct sockaddr ifu_dstaddr;
- } ifa_ifu;
- struct iface *ifa_ifp; /* back-pointer to interface */
- struct ifaddr *ifa_next; /* next address for interface */
-};
+#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ALLMULTI)
-#define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */
-#define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */
+#define IFF_PORTSEL 0x2000 /* can set media type */
+#define IFF_AUTOMEDIA 0x4000 /* auto media select active */
+#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/
/*
* Device mapping structure. I'd just gone off and designed a
@@ -97,7 +80,6 @@ struct ifreq
union
{
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
- char ifrn_hwaddr[IFHWADDRLEN]; /* Obsolete */
} ifr_ifrn;
union {
@@ -107,27 +89,31 @@ struct ifreq
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short ifru_flags;
- int ifru_metric;
+ int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
- caddr_t ifru_data;
+ char ifru_newname[IFNAMSIZ];
+ char * ifru_data;
} ifr_ifru;
};
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
-#define old_ifr_hwaddr ifr_ifrn.ifrn_hwaddr /* interface hardware */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
-#define ifr_metric ifr_ifru.ifru_metric /* metric */
+#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
#define ifr_map ifr_ifru.ifru_map /* device map */
#define ifr_slave ifr_ifru.ifru_slave /* slave device */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
+#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
+#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
+#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
+#define ifr_newname ifr_ifru.ifru_newname /* New name */
/*
* Structure used in SIOCGIFCONF request.
@@ -141,16 +127,12 @@ struct ifconf
int ifc_len; /* size of buffer */
union
{
- caddr_t ifcu_buf;
- struct ifreq *ifcu_req;
+ char * ifcu_buf;
+ struct ifreq *ifcu_req;
} ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures */
-/* BSD UNIX expects to find these here, so here we go: */
-#include <linux/if_arp.h>
-#include <linux/route.h>
-
-#endif /* _NET_IF_H */
+#endif /* _LINUX_IF_H */
diff --git a/pfinet/linux-src/include/linux/if_arcnet.h b/pfinet/linux-src/include/linux/if_arcnet.h
new file mode 100644
index 00000000..8b2ba0aa
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_arcnet.h
@@ -0,0 +1,63 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the ARCnet interface.
+ *
+ * Version: $Id: if_arcnet.h,v 1.2 1997/09/05 08:57:54 mj Exp $
+ *
+ * Author: David Woodhouse <dwmw2@cam.ac.uk>
+ * Avery Pennarun <apenwarr@bond.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_ARCNET_H
+#define _LINUX_IF_ARCNET_H
+
+
+/*
+ * These are the defined ARCnet Protocol ID's.
+ */
+
+ /* RFC1201 Protocol ID's */
+#define ARC_P_IP 212 /* 0xD4 */
+#define ARC_P_ARP 213 /* 0xD5 */
+#define ARC_P_RARP 214 /* 0xD6 */
+#define ARC_P_IPX 250 /* 0xFA */
+#define ARC_P_NOVELL_EC 236 /* 0xEC */
+
+ /* Old RFC1051 Protocol ID's */
+#define ARC_P_IP_RFC1051 240 /* 0xF0 */
+#define ARC_P_ARP_RFC1051 241 /* 0xF1 */
+
+ /* MS LanMan/WfWg protocol */
+#define ARC_P_ETHER 0xE8
+
+ /* Unsupported/indirectly supported protocols */
+#define ARC_P_DATAPOINT_BOOT 0 /* very old Datapoint equipment */
+#define ARC_P_DATAPOINT_MOUNT 1
+#define ARC_P_POWERLAN_BEACON 8 /* Probably ATA-Netbios related */
+#define ARC_P_POWERLAN_BEACON2 243
+#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */
+#define ARC_P_ATALK 0xDD
+
+
+/*
+ * This is an ARCnet frame header.
+ */
+
+struct archdr /* was struct HardHeader */
+{
+ u_char source, /* source ARCnet - filled in automagically */
+ destination, /* destination ARCnet - 0 for broadcast */
+ offset1, /* offset of ClientData (256-byte packets) */
+ offset2; /* offset of ClientData (512-byte packets) */
+
+};
+
+#endif /* _LINUX_IF_ARCNET_H */
diff --git a/pfinet/linux/if_arp.h b/pfinet/linux-src/include/linux/if_arp.h
index 75f86b61..39007c8b 100644
--- a/pfinet/linux/if_arp.h
+++ b/pfinet/linux-src/include/linux/if_arp.h
@@ -11,7 +11,8 @@
* Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
* Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Florian La Roche.
+ * Florian La Roche,
+ * Jonathan Layes <layes@loran.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -21,6 +22,8 @@
#ifndef _LINUX_IF_ARP_H
#define _LINUX_IF_ARP_H
+#include <linux/netdevice.h>
+
/* ARP protocol HARDWARE identifiers. */
#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */
#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */
@@ -28,9 +31,12 @@
#define ARPHRD_AX25 3 /* AX.25 Level 2 */
#define ARPHRD_PRONET 4 /* PROnet token ring */
#define ARPHRD_CHAOS 5 /* Chaosnet */
-#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet- huh? */
+#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */
#define ARPHRD_ARCNET 7 /* ARCnet */
#define ARPHRD_APPLETLK 8 /* APPLEtalk */
+#define ARPHRD_DLCI 15 /* Frame Relay DLCI */
+#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */
+
/* Dummy types for non ARP hardware */
#define ARPHRD_SLIP 256
#define ARPHRD_CSLIP 257
@@ -38,8 +44,35 @@
#define ARPHRD_CSLIP6 259
#define ARPHRD_RSRVD 260 /* Notional KISS type */
#define ARPHRD_ADAPT 264
+#define ARPHRD_ROSE 270
+#define ARPHRD_X25 271 /* CCITT X.25 */
#define ARPHRD_PPP 512
+#define ARPHRD_HDLC 513 /* (Cisco) HDLC */
+#define ARPHRD_LAPB 516 /* LAPB */
+
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
+#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */
+#define ARPHRD_FRAD 770 /* Frame Relay Access Device */
+#define ARPHRD_SKIP 771 /* SKIP vif */
+#define ARPHRD_LOOPBACK 772 /* Loopback device */
+#define ARPHRD_LOCALTLK 773 /* Localtalk device */
+#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */
+#define ARPHRD_BIF 775 /* AP1000 BIF */
+#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */
+#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */
+#define ARPHRD_IPGRE 778 /* GRE over IP */
+#define ARPHRD_PIMREG 779 /* PIMSM register interface */
+#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */
+#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */
+#define ARPHRD_ECONET 782 /* Acorn Econet */
+#define ARPHRD_IRDA 783 /* Linux/IR */
+/* ARP works differently on different FC media .. so */
+#define ARPHRD_FCPP 784 /* Point to point fibrechanel */
+#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */
+#define ARPHRD_FCPL 786 /* Fibrechannel public loop */
+#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */
+ /* 787->799 reserved for fibrechannel media types */
+
/* ARP protocol opcodes. */
#define ARPOP_REQUEST 1 /* ARP request */
@@ -54,6 +87,14 @@ struct arpreq {
struct sockaddr arp_ha; /* hardware address */
int arp_flags; /* flags */
struct sockaddr arp_netmask; /* netmask (only for proxy arps) */
+ char arp_dev[16];
+};
+
+struct arpreq_old {
+ struct sockaddr arp_pa; /* protocol address */
+ struct sockaddr arp_ha; /* hardware address */
+ int arp_flags; /* flags */
+ struct sockaddr arp_netmask; /* netmask (only for proxy arps) */
};
/* ARP Flag values. */
@@ -63,6 +104,7 @@ struct arpreq {
#define ATF_USETRAILERS 0x10 /* has requested trailers */
#define ATF_NETMASK 0x20 /* want to use a netmask (only
for proxy entries) */
+#define ATF_DONTPUB 0x40 /* don't answer this addresses */
/*
* This structure defines an ethernet arp header.
diff --git a/pfinet/linux-src/include/linux/if_cablemodem.h b/pfinet/linux-src/include/linux/if_cablemodem.h
new file mode 100644
index 00000000..9ca1007e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_cablemodem.h
@@ -0,0 +1,22 @@
+#ifndef _LINUX_CABLEMODEM_H_
+#define _LINUX_CABLEMODEM_H_
+/*
+ * Author: Franco Venturi <fventuri@mediaone.net>
+ * Copyright 1998 Franco Venturi
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+/* some useful defines for sb1000.c e cmconfig.c - fv */
+#define SIOCGCMSTATS SIOCDEVPRIVATE+0 /* get cable modem stats */
+#define SIOCGCMFIRMWARE SIOCDEVPRIVATE+1 /* get cm firmware version */
+#define SIOCGCMFREQUENCY SIOCDEVPRIVATE+2 /* get cable modem frequency */
+#define SIOCSCMFREQUENCY SIOCDEVPRIVATE+3 /* set cable modem frequency */
+#define SIOCGCMPIDS SIOCDEVPRIVATE+4 /* get cable modem PIDs */
+#define SIOCSCMPIDS SIOCDEVPRIVATE+5 /* set cable modem PIDs */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_ec.h b/pfinet/linux-src/include/linux/if_ec.h
new file mode 100644
index 00000000..4883f16a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_ec.h
@@ -0,0 +1,47 @@
+/* Definitions for Econet sockets. */
+
+#ifndef __LINUX_IF_EC
+#define __LINUX_IF_EC
+
+/* User visible stuff. Glibc provides its own but libc5 folk will use these */
+
+struct ec_addr
+{
+ unsigned char station; /* Station number. */
+ unsigned char net; /* Network number. */
+};
+
+struct sockaddr_ec
+{
+ unsigned short sec_family;
+ unsigned char port; /* Port number. */
+ unsigned char cb; /* Control/flag byte. */
+ unsigned char type; /* Type of message. */
+ struct ec_addr addr;
+ unsigned long cookie;
+};
+
+#define ECTYPE_PACKET_RECEIVED 0 /* Packet received */
+#define ECTYPE_TRANSMIT_STATUS 0x10 /* Transmit completed,
+ low nibble holds status */
+
+#define ECTYPE_TRANSMIT_OK 1
+#define ECTYPE_TRANSMIT_NOT_LISTENING 2
+#define ECTYPE_TRANSMIT_NET_ERROR 3
+#define ECTYPE_TRANSMIT_NO_CLOCK 4
+#define ECTYPE_TRANSMIT_LINE_JAMMED 5
+#define ECTYPE_TRANSMIT_NOT_PRESENT 6
+
+#ifdef __KERNEL__
+
+struct econet_opt
+{
+ unsigned char cb;
+ unsigned char port;
+ unsigned char station;
+ unsigned char net;
+};
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_eql.h b/pfinet/linux-src/include/linux/if_eql.h
new file mode 100644
index 00000000..320dbebf
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_eql.h
@@ -0,0 +1,81 @@
+/*
+ * Equalizer Load-balancer for serial network interfaces.
+ *
+ * (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
+ * NCM: Network and Communications Management, Inc.
+ *
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * The author may be reached as simon@ncm.com, or C/O
+ * NCM
+ * Attn: Simon Janes
+ * 6803 Whittier Ave
+ * McLean VA 22101
+ * Phone: 1-703-847-0040 ext 103
+ */
+
+#ifndef _LINUX_IF_EQL_H
+#define _LINUX_IF_EQL_H
+
+#include <linux/timer.h>
+
+#define EQL_DEFAULT_SLAVE_PRIORITY 28800
+#define EQL_DEFAULT_MAX_SLAVES 4
+#define EQL_DEFAULT_MTU 576
+#define EQL_DEFAULT_RESCHED_IVAL 100
+
+#define EQL_ENSLAVE (SIOCDEVPRIVATE)
+#define EQL_EMANCIPATE (SIOCDEVPRIVATE + 1)
+
+#define EQL_GETSLAVECFG (SIOCDEVPRIVATE + 2)
+#define EQL_SETSLAVECFG (SIOCDEVPRIVATE + 3)
+
+#define EQL_GETMASTRCFG (SIOCDEVPRIVATE + 4)
+#define EQL_SETMASTRCFG (SIOCDEVPRIVATE + 5)
+
+typedef struct slave {
+ struct device *dev;
+ long priority;
+ long priority_bps;
+ long priority_Bps;
+ long bytes_queued;
+ struct slave *next;
+} slave_t;
+
+typedef struct slave_queue {
+ slave_t *head;
+ slave_t *best_slave;
+ int num_slaves;
+ struct device *master_dev;
+ char lock;
+} slave_queue_t;
+
+typedef struct equalizer {
+ slave_queue_t *queue;
+ int min_slaves;
+ int max_slaves;
+ struct enet_statistics *stats;
+ struct timer_list timer;
+ char timer_on;
+} equalizer_t;
+
+typedef struct master_config {
+ char master_name[16];
+ int max_slaves;
+ int min_slaves;
+} master_config_t;
+
+typedef struct slave_config {
+ char slave_name[16];
+ long priority;
+} slave_config_t;
+
+typedef struct slaving_request {
+ char slave_name[16];
+ long priority;
+} slaving_request_t;
+
+
+#endif /* _LINUX_EQL_H */
diff --git a/pfinet/linux-src/include/linux/if_ether.h b/pfinet/linux-src/include/linux/if_ether.h
new file mode 100644
index 00000000..99bb97fa
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_ether.h
@@ -0,0 +1,98 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the Ethernet IEEE 802.3 interface.
+ *
+ * Version: @(#)if_ether.h 1.0.1a 02/08/94
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <alan@redhat.com>
+ * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+/*
+ * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
+ * and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
+
+/*
+ * These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
+#define ETH_P_ECHO 0x0200 /* Ethernet Echo packet */
+#define ETH_P_PUP 0x0400 /* Xerox PUP packet */
+#define ETH_P_IP 0x0800 /* Internet Protocol packet */
+#define ETH_P_X25 0x0805 /* CCITT X.25 */
+#define ETH_P_ARP 0x0806 /* Address Resolution packet */
+#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
+#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
+#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
+#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
+#define ETH_P_LAT 0x6004 /* DEC LAT */
+#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
+#define ETH_P_CUST 0x6006 /* DEC Customer use */
+#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
+#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
+#define ETH_P_ATALK 0x809B /* Appletalk DDP */
+#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
+#define ETH_P_IPX 0x8137 /* IPX over DIX */
+#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
+
+/*
+ * Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
+#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
+#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
+#define ETH_P_802_2 0x0004 /* 802.2 frames */
+#define ETH_P_SNAP 0x0005 /* Internal only */
+#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
+#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
+#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
+#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
+#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
+#define ETH_P_IRDA 0x0017 /* Linux/IR */
+
+/*
+ * This is an Ethernet frame header.
+ */
+
+struct ethhdr
+{
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ unsigned short h_proto; /* packet type ID field */
+};
+
+/*
+ * We Have changed the ethernet statistics collection data. This
+ * is just for partial compatibility for now.
+ */
+
+
+#define enet_statistics net_device_stats
+
+#endif /* _LINUX_IF_ETHER_H */
diff --git a/pfinet/linux-src/include/linux/if_fc.h b/pfinet/linux-src/include/linux/if_fc.h
new file mode 100644
index 00000000..33330b45
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_fc.h
@@ -0,0 +1,50 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for Fibre Channel.
+ *
+ * Version: @(#)if_fc.h 0.0 11/20/98
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
+ * Vineet Abraham, <vma@iol.unh.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_FC_H
+#define _LINUX_IF_FC_H
+
+
+#define FC_ALEN 6 /* Octets in one ethernet addr */
+#define FC_HLEN (sizeof(struct fch_hdr)+sizeof(struct fcllc))
+#define FC_ID_LEN 3 /* Octets in a Fibre Channel Address */
+
+/* LLC and SNAP constants */
+#define EXTENDED_SAP 0xAA
+#define UI_CMD 0x03
+
+/* This is NOT the Fibre Channel frame header. The FC frame header is
+ * constructed in the driver as the Tachyon needs certain fields in
+ * certains positions. So, it can't be generalized here.*/
+
+struct fch_hdr {
+ __u8 daddr[FC_ALEN]; /* destination address */
+ __u8 saddr[FC_ALEN]; /* source address */
+};
+
+/* This is a Fibre Channel LLC structure */
+struct fcllc {
+ __u8 dsap; /* destination SAP */
+ __u8 ssap; /* source SAP */
+ __u8 llc; /* LLC control field */
+ __u8 protid[3]; /* protocol id */
+ __u16 ethertype; /* ether type field */
+};
+
+#endif /* _LINUX_IF_FC_H */
diff --git a/pfinet/linux-src/include/linux/if_fddi.h b/pfinet/linux-src/include/linux/if_fddi.h
new file mode 100644
index 00000000..22179636
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_fddi.h
@@ -0,0 +1,223 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the ANSI FDDI interface.
+ *
+ * Version: @(#)if_fddi.h 1.0.1 09/16/96
+ *
+ * Author: Lawrence V. Stefani, <stefani@lkg.dec.com>
+ *
+ * if_fddi.h is based on previous if_ether.h and if_tr.h work by
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <alan@redhat.com>
+ * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ * Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_FDDI_H
+#define _LINUX_IF_FDDI_H
+
+/*
+ * Define max and min legal sizes. The frame sizes do not include
+ * 4 byte FCS/CRC (frame check sequence).
+ */
+#define FDDI_K_ALEN 6 /* Octets in one FDDI address */
+#define FDDI_K_8022_HLEN 16 /* Total octets in 802.2 header */
+#define FDDI_K_SNAP_HLEN 21 /* Total octets in 802.2 SNAP header */
+#define FDDI_K_8022_ZLEN 16 /* Min octets in 802.2 frame sans FCS */
+#define FDDI_K_SNAP_ZLEN 21 /* Min octets in 802.2 SNAP frame sans FCS */
+#define FDDI_K_8022_DLEN 4475 /* Max octets in 802.2 payload */
+#define FDDI_K_SNAP_DLEN 4470 /* Max octets in 802.2 SNAP payload */
+#define FDDI_K_LLC_ZLEN 13 /* Min octets in LLC frame sans FCS */
+#define FDDI_K_LLC_LEN 4491 /* Max octets in LLC frame sans FCS */
+
+/* Define FDDI Frame Control (FC) Byte values */
+#define FDDI_FC_K_VOID 0x00
+#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80
+#define FDDI_FC_K_RESTRICTED_TOKEN 0xC0
+#define FDDI_FC_K_SMT_MIN 0x41
+#define FDDI_FC_K_SMT_MAX 0x4F
+#define FDDI_FC_K_MAC_MIN 0xC1
+#define FDDI_FC_K_MAC_MAX 0xCF
+#define FDDI_FC_K_ASYNC_LLC_MIN 0x50
+#define FDDI_FC_K_ASYNC_LLC_DEF 0x54
+#define FDDI_FC_K_ASYNC_LLC_MAX 0x5F
+#define FDDI_FC_K_SYNC_LLC_MIN 0xD0
+#define FDDI_FC_K_SYNC_LLC_MAX 0xD7
+#define FDDI_FC_K_IMPLEMENTOR_MIN 0x60
+#define FDDI_FC_K_IMPLEMENTOR_MAX 0x6F
+#define FDDI_FC_K_RESERVED_MIN 0x70
+#define FDDI_FC_K_RESERVED_MAX 0x7F
+
+/* Define LLC and SNAP constants */
+#define FDDI_EXTENDED_SAP 0xAA
+#define FDDI_UI_CMD 0x03
+
+/* Define 802.2 Type 1 header */
+struct fddi_8022_1_hdr
+ {
+ __u8 dsap; /* destination service access point */
+ __u8 ssap; /* source service access point */
+ __u8 ctrl; /* control byte #1 */
+ } __attribute__ ((packed));
+
+/* Define 802.2 Type 2 header */
+struct fddi_8022_2_hdr
+ {
+ __u8 dsap; /* destination service access point */
+ __u8 ssap; /* source service access point */
+ __u8 ctrl_1; /* control byte #1 */
+ __u8 ctrl_2; /* control byte #2 */
+ } __attribute__ ((packed));
+
+/* Define 802.2 SNAP header */
+#define FDDI_K_OUI_LEN 3
+struct fddi_snap_hdr
+ {
+ __u8 dsap; /* always 0xAA */
+ __u8 ssap; /* always 0xAA */
+ __u8 ctrl; /* always 0x03 */
+ __u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */
+ __u16 ethertype; /* packet type ID field */
+ } __attribute__ ((packed));
+
+/* Define FDDI LLC frame header */
+struct fddihdr
+ {
+ __u8 fc; /* frame control */
+ __u8 daddr[FDDI_K_ALEN]; /* destination address */
+ __u8 saddr[FDDI_K_ALEN]; /* source address */
+ union
+ {
+ struct fddi_8022_1_hdr llc_8022_1;
+ struct fddi_8022_2_hdr llc_8022_2;
+ struct fddi_snap_hdr llc_snap;
+ } hdr;
+ } __attribute__ ((packed));
+
+/* Define FDDI statistics structure */
+struct fddi_statistics
+ {
+ __u32 rx_packets; /* total packets received */
+ __u32 tx_packets; /* total packets transmitted */
+ __u32 rx_bytes; /* total bytes received */
+ __u32 tx_bytes; /* total bytes transmitted */
+ __u32 rx_errors; /* bad packets received */
+ __u32 tx_errors; /* packet transmit problems */
+ __u32 rx_dropped; /* no space in linux buffers */
+ __u32 tx_dropped; /* no space available in linux */
+ __u32 multicast; /* multicast packets received */
+ __u32 transmit_collision; /* always 0 for FDDI */
+
+ /* detailed rx_errors */
+ __u32 rx_length_errors;
+ __u32 rx_over_errors; /* receiver ring buff overflow */
+ __u32 rx_crc_errors; /* recved pkt with crc error */
+ __u32 rx_frame_errors; /* recv'd frame alignment error */
+ __u32 rx_fifo_errors; /* recv'r fifo overrun */
+ __u32 rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ __u32 tx_aborted_errors;
+ __u32 tx_carrier_errors;
+ __u32 tx_fifo_errors;
+ __u32 tx_heartbeat_errors;
+ __u32 tx_window_errors;
+
+ /* for cslip etc */
+ __u32 rx_compressed;
+ __u32 tx_compressed;
+
+ /* Detailed FDDI statistics. Adopted from RFC 1512 */
+
+ __u8 smt_station_id[8];
+ __u32 smt_op_version_id;
+ __u32 smt_hi_version_id;
+ __u32 smt_lo_version_id;
+ __u8 smt_user_data[32];
+ __u32 smt_mib_version_id;
+ __u32 smt_mac_cts;
+ __u32 smt_non_master_cts;
+ __u32 smt_master_cts;
+ __u32 smt_available_paths;
+ __u32 smt_config_capabilities;
+ __u32 smt_config_policy;
+ __u32 smt_connection_policy;
+ __u32 smt_t_notify;
+ __u32 smt_stat_rpt_policy;
+ __u32 smt_trace_max_expiration;
+ __u32 smt_bypass_present;
+ __u32 smt_ecm_state;
+ __u32 smt_cf_state;
+ __u32 smt_remote_disconnect_flag;
+ __u32 smt_station_status;
+ __u32 smt_peer_wrap_flag;
+ __u32 smt_time_stamp;
+ __u32 smt_transition_time_stamp;
+ __u32 mac_frame_status_functions;
+ __u32 mac_t_max_capability;
+ __u32 mac_tvx_capability;
+ __u32 mac_available_paths;
+ __u32 mac_current_path;
+ __u8 mac_upstream_nbr[FDDI_K_ALEN];
+ __u8 mac_downstream_nbr[FDDI_K_ALEN];
+ __u8 mac_old_upstream_nbr[FDDI_K_ALEN];
+ __u8 mac_old_downstream_nbr[FDDI_K_ALEN];
+ __u32 mac_dup_address_test;
+ __u32 mac_requested_paths;
+ __u32 mac_downstream_port_type;
+ __u8 mac_smt_address[FDDI_K_ALEN];
+ __u32 mac_t_req;
+ __u32 mac_t_neg;
+ __u32 mac_t_max;
+ __u32 mac_tvx_value;
+ __u32 mac_frame_cts;
+ __u32 mac_copied_cts;
+ __u32 mac_transmit_cts;
+ __u32 mac_error_cts;
+ __u32 mac_lost_cts;
+ __u32 mac_frame_error_threshold;
+ __u32 mac_frame_error_ratio;
+ __u32 mac_rmt_state;
+ __u32 mac_da_flag;
+ __u32 mac_una_da_flag;
+ __u32 mac_frame_error_flag;
+ __u32 mac_ma_unitdata_available;
+ __u32 mac_hardware_present;
+ __u32 mac_ma_unitdata_enable;
+ __u32 path_tvx_lower_bound;
+ __u32 path_t_max_lower_bound;
+ __u32 path_max_t_req;
+ __u32 path_configuration[8];
+ __u32 port_my_type[2];
+ __u32 port_neighbor_type[2];
+ __u32 port_connection_policies[2];
+ __u32 port_mac_indicated[2];
+ __u32 port_current_path[2];
+ __u8 port_requested_paths[3*2];
+ __u32 port_mac_placement[2];
+ __u32 port_available_paths[2];
+ __u32 port_pmd_class[2];
+ __u32 port_connection_capabilities[2];
+ __u32 port_bs_flag[2];
+ __u32 port_lct_fail_cts[2];
+ __u32 port_ler_estimate[2];
+ __u32 port_lem_reject_cts[2];
+ __u32 port_lem_cts[2];
+ __u32 port_ler_cutoff[2];
+ __u32 port_ler_alarm[2];
+ __u32 port_connect_state[2];
+ __u32 port_pcm_state[2];
+ __u32 port_pc_withhold[2];
+ __u32 port_ler_flag[2];
+ __u32 port_hardware_present[2];
+ };
+
+#endif /* _LINUX_IF_FDDI_H */
diff --git a/pfinet/linux-src/include/linux/if_frad.h b/pfinet/linux-src/include/linux/if_frad.h
new file mode 100644
index 00000000..4f1a1e2f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_frad.h
@@ -0,0 +1,201 @@
+/*
+ * DLCI/FRAD Definitions for Frame Relay Access Devices. DLCI devices are
+ * created for each DLCI associated with a FRAD. The FRAD driver
+ * is not truly a network device, but the lower level device
+ * handler. This allows other FRAD manufacturers to use the DLCI
+ * code, including its RFC1490 encapsulation alongside the current
+ * implementation for the Sangoma cards.
+ *
+ * Version: @(#)if_ifrad.h 0.15 31 Mar 96
+ *
+ * Author: Mike McLagan <mike.mclagan@linux.org>
+ *
+ * Changes:
+ * 0.15 Mike McLagan changed structure defs (packed)
+ * re-arranged flags
+ * added DLCI_RET vars
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _FRAD_H_
+#define _FRAD_H_
+
+#include <linux/config.h>
+#include <linux/if.h>
+
+#if defined(CONFIG_DLCI) || defined(CONFIG_DLCI_MODULE)
+
+/* Structures and constants associated with the DLCI device driver */
+
+struct dlci_add
+{
+ char devname[IFNAMSIZ];
+ short dlci;
+};
+
+#define DLCI_GET_CONF (SIOCDEVPRIVATE + 2)
+#define DLCI_SET_CONF (SIOCDEVPRIVATE + 3)
+
+/*
+ * These are related to the Sangoma SDLA and should remain in order.
+ * Code within the SDLA module is based on the specifics of this
+ * structure. Change at your own peril.
+ */
+struct dlci_conf {
+ short flags;
+ short CIR_fwd;
+ short Bc_fwd;
+ short Be_fwd;
+ short CIR_bwd;
+ short Bc_bwd;
+ short Be_bwd;
+
+/* these are part of the status read */
+ short Tc_fwd;
+ short Tc_bwd;
+ short Tf_max;
+ short Tb_max;
+
+/* add any new fields here above is a mirror of sdla_dlci_conf */
+};
+
+#define DLCI_GET_SLAVE (SIOCDEVPRIVATE + 4)
+
+/* configuration flags for DLCI */
+#define DLCI_IGNORE_CIR_OUT 0x0001
+#define DLCI_ACCOUNT_CIR_IN 0x0002
+#define DLCI_BUFFER_IF 0x0008
+
+#define DLCI_VALID_FLAGS 0x000B
+
+/* FRAD driver uses these to indicate what it did with packet */
+#define DLCI_RET_OK 0x00
+#define DLCI_RET_ERR 0x01
+#define DLCI_RET_DROP 0x02
+
+/* defines for the actual Frame Relay hardware */
+#define FRAD_GET_CONF (SIOCDEVPRIVATE)
+#define FRAD_SET_CONF (SIOCDEVPRIVATE + 1)
+
+#define FRAD_LAST_IOCTL FRAD_SET_CONF
+
+/*
+ * Based on the setup for the Sangoma SDLA. If changes are
+ * necessary to this structure, a routine will need to be
+ * added to that module to copy fields.
+ */
+struct frad_conf
+{
+ short station;
+ short flags;
+ short kbaud;
+ short clocking;
+ short mtu;
+ short T391;
+ short T392;
+ short N391;
+ short N392;
+ short N393;
+ short CIR_fwd;
+ short Bc_fwd;
+ short Be_fwd;
+ short CIR_bwd;
+ short Bc_bwd;
+ short Be_bwd;
+
+/* Add new fields here, above is a mirror of the sdla_conf */
+
+};
+
+#define FRAD_STATION_CPE 0x0000
+#define FRAD_STATION_NODE 0x0001
+
+#define FRAD_TX_IGNORE_CIR 0x0001
+#define FRAD_RX_ACCOUNT_CIR 0x0002
+#define FRAD_DROP_ABORTED 0x0004
+#define FRAD_BUFFERIF 0x0008
+#define FRAD_STATS 0x0010
+#define FRAD_MCI 0x0100
+#define FRAD_AUTODLCI 0x8000
+#define FRAD_VALID_FLAGS 0x811F
+
+#define FRAD_CLOCK_INT 0x0001
+#define FRAD_CLOCK_EXT 0x0000
+
+#ifdef __KERNEL__
+
+/* these are the fields of an RFC 1490 header */
+struct frhdr
+{
+ unsigned char control __attribute__((packed));
+
+ /* for IP packets, this can be the NLPID */
+ unsigned char pad __attribute__((packed));
+
+ unsigned char NLPID __attribute__((packed));
+ unsigned char OUI[3] __attribute__((packed));
+ unsigned short PID __attribute__((packed));
+
+#define IP_NLPID pad
+};
+
+/* see RFC 1490 for the definition of the following */
+#define FRAD_I_UI 0x03
+
+#define FRAD_P_PADDING 0x00
+#define FRAD_P_Q933 0x08
+#define FRAD_P_SNAP 0x80
+#define FRAD_P_CLNP 0x81
+#define FRAD_P_IP 0xCC
+
+struct dlci_local
+{
+ struct enet_statistics stats;
+ struct device *slave;
+ struct dlci_conf config;
+ int configured;
+
+ /* callback function */
+ void (*receive)(struct sk_buff *skb, struct device *);
+};
+
+struct frad_local
+{
+ struct enet_statistics stats;
+
+ /* devices which this FRAD is slaved to */
+ struct device *master[CONFIG_DLCI_MAX];
+ short dlci[CONFIG_DLCI_MAX];
+
+ struct frad_conf config;
+ int configured; /* has this device been configured */
+ int initialized; /* mem_start, port, irq set ? */
+
+ /* callback functions */
+ int (*activate)(struct device *, struct device *);
+ int (*deactivate)(struct device *, struct device *);
+ int (*assoc)(struct device *, struct device *);
+ int (*deassoc)(struct device *, struct device *);
+ int (*dlci_conf)(struct device *, struct device *, int get);
+
+ /* fields that are used by the Sangoma SDLA cards */
+ struct timer_list timer;
+ int type; /* adapter type */
+ int state; /* state of the S502/8 control latch */
+ int buffer; /* current buffer for S508 firmware */
+};
+
+int register_frad(const char *name);
+int unregister_frad(const char *name);
+
+int (*dlci_ioctl_hook)(unsigned int, void *);
+
+#endif __KERNEL__
+
+#endif /* CONFIG_DLCI || CONFIG_DLCI_MODULE */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_hippi.h b/pfinet/linux-src/include/linux/if_hippi.h
new file mode 100644
index 00000000..52c4a80b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_hippi.h
@@ -0,0 +1,157 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the HIPPI interface.
+ *
+ * Version: @(#)if_hippi.h 1.0.0 05/26/97
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <alan@redhat.com>
+ * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ * Jes Sorensen, <Jes.Sorensen@cern.ch>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_HIPPI_H
+#define _LINUX_IF_HIPPI_H
+
+#include <asm/byteorder.h>
+
+/*
+ * HIPPI magic constants.
+ */
+
+#define HIPPI_ALEN 6 /* Bytes in one HIPPI hw-addr */
+#define HIPPI_HLEN sizeof(struct hippi_hdr)
+#define HIPPI_ZLEN 0 /* Min. bytes in frame without FCS */
+#define HIPPI_DATA_LEN 65280 /* Max. bytes in payload */
+#define HIPPI_FRAME_LEN (HIPPI_DATA_LEN + HIPPI_HLEN)
+ /* Max. bytes in frame without FCS */
+
+/*
+ * Define LLC and SNAP constants.
+ */
+#define HIPPI_EXTENDED_SAP 0xAA
+#define HIPPI_UI_CMD 0x03
+
+
+/*
+ * Do we need to list some sort of ID's here?
+ */
+
+/*
+ * HIPPI statistics collection data.
+ */
+
+struct hipnet_statistics
+{
+ int rx_packets; /* total packets received */
+ int tx_packets; /* total packets transmitted */
+ int rx_errors; /* bad packets received */
+ int tx_errors; /* packet transmit problems */
+ int rx_dropped; /* no space in linux buffers */
+ int tx_dropped; /* no space available in linux */
+
+ /* detailed rx_errors: */
+ int rx_length_errors;
+ int rx_over_errors; /* receiver ring buff overflow */
+ int rx_crc_errors; /* recved pkt with crc error */
+ int rx_frame_errors; /* recv'd frame alignment error */
+ int rx_fifo_errors; /* recv'r fifo overrun */
+ int rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ int tx_aborted_errors;
+ int tx_carrier_errors;
+ int tx_fifo_errors;
+ int tx_heartbeat_errors;
+ int tx_window_errors;
+};
+
+
+struct hippi_fp_hdr
+{
+#if 0
+ __u8 ulp; /* must contain 4 */
+#if defined (__BIG_ENDIAN_BITFIELD)
+ __u8 d1_data_present:1; /* must be 1 */
+ __u8 start_d2_burst_boundary:1; /* must be zero */
+ __u8 reserved:6; /* must be zero */
+#if 0
+ __u16 reserved1:5;
+ __u16 d1_area_size:8; /* must be 3 */
+ __u16 d2_offset:3; /* must be zero */
+#endif
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 reserved:6; /* must be zero */
+ __u8 start_d2_burst_boundary:1; /* must be zero */
+ __u8 d1_data_present:1; /* must be 1 */
+#if 0
+ __u16 d2_offset:3; /* must be zero */
+ __u16 d1_area_size:8; /* must be 3 */
+ __u16 reserved1:5; /* must be zero */
+#endif
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+#else
+ __u32 fixed;
+#endif
+ __u32 d2_size;
+} __attribute__ ((packed));
+
+struct hippi_le_hdr
+{
+#if defined (__BIG_ENDIAN_BITFIELD)
+ unsigned long fc:3;
+ unsigned long double_wide:1;
+ unsigned long message_type:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned long message_type:4;
+ unsigned long double_wide:1;
+ unsigned long fc:3;
+#endif
+ __u8 dest_switch_addr[3];
+#if defined (__BIG_ENDIAN_BITFIELD)
+ __u8 dest_addr_type:4,
+ src_addr_type:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 src_addr_type:4,
+ dest_addr_type:4;
+#endif
+ __u8 src_switch_addr[3];
+ __u16 reserved;
+ __u8 daddr[HIPPI_ALEN];
+ __u16 locally_administered;
+ __u8 saddr[HIPPI_ALEN];
+} __attribute__ ((packed));
+
+#define HIPPI_OUI_LEN 3
+/*
+ * Looks like the dsap and ssap fields have been swapped by mistake in
+ * RFC 2067 "IP over HIPPI".
+ */
+struct hippi_snap_hdr
+{
+ __u8 dsap; /* always 0xAA */
+ __u8 ssap; /* always 0xAA */
+ __u8 ctrl; /* always 0x03 */
+ __u8 oui[HIPPI_OUI_LEN]; /* organizational universal id (zero)*/
+ __u16 ethertype; /* packet type ID field */
+} __attribute__ ((packed));
+
+struct hippi_hdr
+{
+ struct hippi_fp_hdr fp;
+ struct hippi_le_hdr le;
+ struct hippi_snap_hdr snap;
+} __attribute__ ((packed));
+
+#endif /* _LINUX_IF_HIPPI_H */
diff --git a/pfinet/linux-src/include/linux/if_ltalk.h b/pfinet/linux-src/include/linux/if_ltalk.h
new file mode 100644
index 00000000..d7b17d32
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_ltalk.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_LTALK_H
+#define __LINUX_LTALK_H
+
+#define LTALK_HLEN 1
+#define LTALK_MTU 600
+#define LTALK_ALEN 1
+
+#ifdef __KERNEL__
+extern void ltalk_setup(struct device *);
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_packet.h b/pfinet/linux-src/include/linux/if_packet.h
new file mode 100644
index 00000000..ad5655cf
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_packet.h
@@ -0,0 +1,50 @@
+#ifndef __LINUX_IF_PACKET_H
+#define __LINUX_IF_PACKET_H
+
+struct sockaddr_pkt
+{
+ unsigned short spkt_family;
+ unsigned char spkt_device[14];
+ unsigned short spkt_protocol;
+};
+
+struct sockaddr_ll
+{
+ unsigned short sll_family;
+ unsigned short sll_protocol;
+ int sll_ifindex;
+ unsigned short sll_hatype;
+ unsigned char sll_pkttype;
+ unsigned char sll_halen;
+ unsigned char sll_addr[8];
+};
+
+/* Packet types */
+
+#define PACKET_HOST 0 /* To us */
+#define PACKET_BROADCAST 1 /* To all */
+#define PACKET_MULTICAST 2 /* To group */
+#define PACKET_OTHERHOST 3 /* To someone else */
+#define PACKET_OUTGOING 4 /* Outgoing of any type */
+/* These ones are invisible by user level */
+#define PACKET_LOOPBACK 5 /* MC/BRD frame looped back */
+#define PACKET_FASTROUTE 6 /* Fastrouted frame */
+
+/* Packet socket options */
+
+#define PACKET_ADD_MEMBERSHIP 1
+#define PACKET_DROP_MEMBERSHIP 2
+
+struct packet_mreq
+{
+ int mr_ifindex;
+ unsigned short mr_type;
+ unsigned short mr_alen;
+ unsigned char mr_address[8];
+};
+
+#define PACKET_MR_MULTICAST 0
+#define PACKET_MR_PROMISC 1
+#define PACKET_MR_ALLMULTI 2
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_plip.h b/pfinet/linux-src/include/linux/if_plip.h
new file mode 100644
index 00000000..153a6499
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_plip.h
@@ -0,0 +1,28 @@
+/*
+ * NET3 PLIP tuning facilities for the new Niibe PLIP.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _LINUX_IF_PLIP_H
+#define _LINUX_IF_PLIP_H
+
+#include <linux/sockios.h>
+
+#define SIOCDEVPLIP SIOCDEVPRIVATE
+
+struct plipconf
+{
+ unsigned short pcmd;
+ unsigned long nibble;
+ unsigned long trigger;
+};
+
+#define PLIP_GET_TIMEOUT 0x1
+#define PLIP_SET_TIMEOUT 0x2
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_ppp.h b/pfinet/linux-src/include/linux/if_ppp.h
new file mode 100644
index 00000000..1d103bdc
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_ppp.h
@@ -0,0 +1,143 @@
+/* $Id: if_ppp.h,v 1.19 1999/03/31 06:07:57 paulus Exp $ */
+
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/*
+ * ==FILEVERSION 990331==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * if_ppp.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new if_ppp.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+#ifndef _IF_PPP_H_
+#define _IF_PPP_H_
+
+/*
+ * Packet sizes
+ */
+
+#define PPP_MTU 1500 /* Default MTU (size of Info field) */
+#define PPP_MAXMRU 65000 /* Largest MRU we allow */
+#define PPP_VERSION "2.3.7"
+#define PPP_MAGIC 0x5002 /* Magic value for the ppp structure */
+#define PROTO_IPX 0x002b /* protocol numbers */
+#define PROTO_DNA_RT 0x0027 /* DNA Routing */
+
+
+/*
+ * Bit definitions for flags.
+ */
+
+#define SC_COMP_PROT 0x00000001 /* protocol compression (output) */
+#define SC_COMP_AC 0x00000002 /* header compression (output) */
+#define SC_COMP_TCP 0x00000004 /* TCP (VJ) compression (output) */
+#define SC_NO_TCP_CCID 0x00000008 /* disable VJ connection-id comp. */
+#define SC_REJ_COMP_AC 0x00000010 /* reject adrs/ctrl comp. on input */
+#define SC_REJ_COMP_TCP 0x00000020 /* reject TCP (VJ) comp. on input */
+#define SC_CCP_OPEN 0x00000040 /* Look at CCP packets */
+#define SC_CCP_UP 0x00000080 /* May send/recv compressed packets */
+#define SC_ENABLE_IP 0x00000100 /* IP packets may be exchanged */
+#define SC_COMP_RUN 0x00001000 /* compressor has been inited */
+#define SC_DECOMP_RUN 0x00002000 /* decompressor has been inited */
+#define SC_DEBUG 0x00010000 /* enable debug messages */
+#define SC_LOG_INPKT 0x00020000 /* log contents of good pkts recvd */
+#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */
+#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
+#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
+#define SC_SYNC 0x00200000 /* synchronous serial mode */
+#define SC_MASK 0x0f2000ff /* bits that user can change */
+
+/* state bits */
+#define SC_XMIT_BUSY 0x10000000 /* (used by isdn_ppp?) */
+#define SC_RCV_ODDP 0x08000000 /* have rcvd char with odd parity */
+#define SC_RCV_EVNP 0x04000000 /* have rcvd char with even parity */
+#define SC_RCV_B7_1 0x02000000 /* have rcvd char with bit 7 = 1 */
+#define SC_RCV_B7_0 0x01000000 /* have rcvd char with bit 7 = 0 */
+#define SC_DC_FERROR 0x00800000 /* fatal decomp error detected */
+#define SC_DC_ERROR 0x00400000 /* non-fatal decomp error detected */
+
+/*
+ * Ioctl definitions.
+ */
+
+struct npioctl {
+ int protocol; /* PPP protocol, e.g. PPP_IP */
+ enum NPmode mode;
+};
+
+/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
+struct ppp_option_data {
+ __u8 *ptr;
+ __u32 length;
+ int transmit;
+};
+
+struct ifpppstatsreq {
+ struct ifreq b;
+ struct ppp_stats stats; /* statistic information */
+};
+
+struct ifpppcstatsreq {
+ struct ifreq b;
+ struct ppp_comp_stats stats;
+};
+
+#define ifr__name b.ifr_ifrn.ifrn_name
+#define stats_ptr b.ifr_ifru.ifru_data
+
+/*
+ * Ioctl definitions.
+ */
+
+#define PPPIOCGFLAGS _IOR('t', 90, int) /* get configuration flags */
+#define PPPIOCSFLAGS _IOW('t', 89, int) /* set configuration flags */
+#define PPPIOCGASYNCMAP _IOR('t', 88, int) /* get async map */
+#define PPPIOCSASYNCMAP _IOW('t', 87, int) /* set async map */
+#define PPPIOCGUNIT _IOR('t', 86, int) /* get ppp unit number */
+#define PPPIOCGRASYNCMAP _IOR('t', 85, int) /* get receive async map */
+#define PPPIOCSRASYNCMAP _IOW('t', 84, int) /* set receive async map */
+#define PPPIOCGMRU _IOR('t', 83, int) /* get max receive unit */
+#define PPPIOCSMRU _IOW('t', 82, int) /* set max receive unit */
+#define PPPIOCSMAXCID _IOW('t', 81, int) /* set VJ max slot ID */
+#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
+#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
+#define PPPIOCXFERUNIT _IO('t', 78) /* transfer PPP unit */
+#define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data)
+#define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */
+#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */
+#define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */
+#define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */
+#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
+
+#define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0)
+#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */
+#define SIOCGPPPCSTATS (SIOCDEVPRIVATE + 2)
+
+#if !defined(ifr_mtu)
+#define ifr_mtu ifr_ifru.ifru_metric
+#endif
+
+#endif /* _IF_PPP_H_ */
diff --git a/pfinet/linux-src/include/linux/if_pppvar.h b/pfinet/linux-src/include/linux/if_pppvar.h
new file mode 100644
index 00000000..d6cd0c25
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_pppvar.h
@@ -0,0 +1,135 @@
+/* From: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp */
+/*
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * ==FILEVERSION 990325==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * if_pppvar.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new if_pppvar.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+/*
+ * Supported network protocols. These values are used for
+ * indexing sc_npmode.
+ */
+
+#define NP_IP 0 /* Internet Protocol */
+#define NP_IPX 1 /* IPX protocol */
+#define NP_AT 2 /* Appletalk protocol */
+#define NP_IPV6 3 /* Internet Protocol */
+#define NUM_NP 4 /* Number of NPs. */
+
+#define OBUFSIZE 256 /* # chars of output buffering */
+
+/*
+ * Structure describing each ppp unit.
+ */
+
+struct ppp {
+ int magic; /* magic value for structure */
+ struct ppp *next; /* unit with next index */
+ unsigned long inuse; /* are we allocated? */
+ int line; /* network interface unit # */
+ __u32 flags; /* miscellaneous control flags */
+ int mtu; /* maximum xmit frame size */
+ int mru; /* maximum receive frame size */
+ struct slcompress *slcomp; /* for TCP header compression */
+ struct sk_buff_head xmt_q; /* frames to send from pppd */
+ struct sk_buff_head rcv_q; /* frames for pppd to read */
+ unsigned long xmit_busy; /* bit 0 set when xmitter busy */
+
+ /* Information specific to using ppp on async serial lines. */
+ struct tty_struct *tty; /* ptr to TTY structure */
+ struct tty_struct *backup_tty; /* TTY to use if tty gets closed */
+ __u8 escape; /* 0x20 if prev char was PPP_ESC */
+ __u8 toss; /* toss this frame */
+ volatile __u8 tty_pushing; /* internal state flag */
+ volatile __u8 woke_up; /* internal state flag */
+ __u32 xmit_async_map[8]; /* 1 bit means that given control
+ character is quoted on output*/
+ __u32 recv_async_map; /* 1 bit means that given control
+ character is ignored on input*/
+ __u32 bytes_sent; /* Bytes sent on frame */
+ __u32 bytes_rcvd; /* Bytes recvd on frame */
+
+ /* Async transmission information */
+ struct sk_buff *tpkt; /* frame currently being sent */
+ int tpkt_pos; /* how much of it we've done */
+ __u16 tfcs; /* FCS so far for it */
+ unsigned char *optr; /* where we're up to in sending */
+ unsigned char *olim; /* points past last valid char */
+
+ /* Async reception information */
+ struct sk_buff *rpkt; /* frame currently being rcvd */
+ __u16 rfcs; /* FCS so far of rpkt */
+
+ /* Queues for select() functionality */
+ struct wait_queue *read_wait; /* queue for reading processes */
+
+ /* info for detecting idle channels */
+ unsigned long last_xmit; /* time of last transmission */
+ unsigned long last_recv; /* time last packet received */
+
+ /* Statistic information */
+ struct pppstat stats; /* statistic information */
+
+ /* PPP compression protocol information */
+ struct compressor *sc_xcomp; /* transmit compressor */
+ void *sc_xc_state; /* transmit compressor state */
+ struct compressor *sc_rcomp; /* receive decompressor */
+ void *sc_rc_state; /* receive decompressor state */
+
+ enum NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
+ int sc_xfer; /* PID of reserved PPP table */
+ char name[8]; /* space for unit name */
+ struct device dev; /* net device structure */
+ struct enet_statistics estats; /* more detailed stats */
+
+ /* tty output buffer */
+ unsigned char obuf[OBUFSIZE]; /* buffer for characters to send */
+};
diff --git a/pfinet/linux-src/include/linux/if_shaper.h b/pfinet/linux-src/include/linux/if_shaper.h
new file mode 100644
index 00000000..e2e97c30
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_shaper.h
@@ -0,0 +1,64 @@
+#ifndef __LINUX_SHAPER_H
+#define __LINUX_SHAPER_H
+
+#ifdef __KERNEL__
+
+#define SHAPER_QLEN 10
+/*
+ * This is a bit speed dependent (read it shouldn't be a constant!)
+ *
+ * 5 is about right for 28.8 upwards. Below that double for every
+ * halving of speed or so. - ie about 20 for 9600 baud.
+ */
+#define SHAPER_LATENCY (5*HZ)
+#define SHAPER_MAXSLIP 2
+#define SHAPER_BURST (HZ/50) /* Good for >128K then */
+
+struct shaper
+{
+ struct sk_buff_head sendq;
+ __u32 bytespertick;
+ __u32 bitspersec;
+ __u32 shapelatency;
+ __u32 shapeclock;
+ __u32 recovery; /* Time we can next clock a packet out on
+ an empty queue */
+ unsigned long locked;
+ struct net_device_stats stats;
+ struct device *dev;
+ int (*hard_start_xmit) (struct sk_buff *skb,
+ struct device *dev);
+ int (*hard_header) (struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type,
+ void *daddr,
+ void *saddr,
+ unsigned len);
+ int (*rebuild_header)(struct sk_buff *skb);
+ int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh);
+ void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr);
+ struct net_device_stats* (*get_stats)(struct device *dev);
+ struct wait_queue *wait_queue;
+ struct timer_list timer;
+};
+
+#endif
+
+#define SHAPER_SET_DEV 0x0001
+#define SHAPER_SET_SPEED 0x0002
+#define SHAPER_GET_DEV 0x0003
+#define SHAPER_GET_SPEED 0x0004
+
+struct shaperconf
+{
+ __u16 ss_cmd;
+ union
+ {
+ char ssu_name[14];
+ __u32 ssu_speed;
+ } ss_u;
+#define ss_speed ss_u.ssu_speed
+#define ss_name ss_u.ssu_name
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_slip.h b/pfinet/linux-src/include/linux/if_slip.h
new file mode 100644
index 00000000..1eb4e3a8
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_slip.h
@@ -0,0 +1,30 @@
+/*
+ * Swansea University Computer Society NET3
+ *
+ * This file declares the constants of special use with the SLIP/CSLIP/
+ * KISS TNC driver.
+ */
+
+#ifndef __LINUX_SLIP_H
+#define __LINUX_SLIP_H
+
+#define SL_MODE_SLIP 0
+#define SL_MODE_CSLIP 1
+#define SL_MODE_KISS 4
+
+#define SL_OPT_SIXBIT 2
+#define SL_OPT_ADAPTIVE 8
+
+/*
+ * VSV = ioctl for keepalive & outfill in SLIP driver
+ */
+
+#define SIOCSKEEPALIVE (SIOCDEVPRIVATE) /* Set keepalive timeout in sec */
+#define SIOCGKEEPALIVE (SIOCDEVPRIVATE+1) /* Get keepalive timeout */
+#define SIOCSOUTFILL (SIOCDEVPRIVATE+2) /* Set outfill timeout */
+#define SIOCGOUTFILL (SIOCDEVPRIVATE+3) /* Get outfill timeout */
+#define SIOCSLEASE (SIOCDEVPRIVATE+4) /* Set "leased" line type */
+#define SIOCGLEASE (SIOCDEVPRIVATE+5) /* Get line type */
+
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_strip.h b/pfinet/linux-src/include/linux/if_strip.h
new file mode 100644
index 00000000..fb5c5c98
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_strip.h
@@ -0,0 +1,25 @@
+/*
+ * if_strip.h --
+ *
+ * Definitions for the STRIP interface
+ *
+ * Copyright 1996 The Board of Trustees of The Leland Stanford
+ * Junior University. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies. Stanford University
+ * makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#ifndef __LINUX_STRIP_H
+#define __LINUX_STRIP_H
+
+typedef struct {
+ __u8 c[6];
+} MetricomAddress;
+
+#endif
diff --git a/pfinet/linux-src/include/linux/if_tr.h b/pfinet/linux-src/include/linux/if_tr.h
new file mode 100644
index 00000000..f7c97eeb
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_tr.h
@@ -0,0 +1,100 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the Token-Ring IEEE 802.5 interface.
+ *
+ * Version: @(#)if_tr.h 0.0 07/11/94
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_TR_H
+#define _LINUX_IF_TR_H
+
+
+/* IEEE 802.5 Token-Ring magic constants. The frame sizes omit the preamble
+ and FCS/CRC (frame check sequence). */
+#define TR_ALEN 6 /* Octets in one ethernet addr */
+#define TR_HLEN (sizeof(struct trh_hdr)+sizeof(struct trllc))
+#define AC 0x10
+#define LLC_FRAME 0x40
+#if 0
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
+#endif
+
+
+/* LLC and SNAP constants */
+#define EXTENDED_SAP 0xAA
+#define UI_CMD 0x03
+
+/* This is an Token-Ring frame header. */
+struct trh_hdr {
+ __u8 ac; /* access control field */
+ __u8 fc; /* frame control field */
+ __u8 daddr[TR_ALEN]; /* destination address */
+ __u8 saddr[TR_ALEN]; /* source address */
+ __u16 rcf; /* route control field */
+ __u16 rseg[8]; /* routing registers */
+};
+
+/* This is an Token-Ring LLC structure */
+struct trllc {
+ __u8 dsap; /* destination SAP */
+ __u8 ssap; /* source SAP */
+ __u8 llc; /* LLC control field */
+ __u8 protid[3]; /* protocol id */
+ __u16 ethertype; /* ether type field */
+};
+
+/* Token-Ring statistics collection data. */
+struct tr_statistics {
+ unsigned long rx_packets; /* total packets received */
+ unsigned long tx_packets; /* total packets transmitted */
+ unsigned long rx_bytes; /* total bytes received */
+ unsigned long tx_bytes; /* total bytes transmitted */
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* no space in linux buffers */
+ unsigned long tx_dropped; /* no space available in linux */
+ unsigned long multicast; /* multicast packets received */
+ unsigned long transmit_collision;
+
+ /* detailed Token-Ring errors. See IBM Token-Ring Network
+ Architecture for more info */
+
+ unsigned long line_errors;
+ unsigned long internal_errors;
+ unsigned long burst_errors;
+ unsigned long A_C_errors;
+ unsigned long abort_delimiters;
+ unsigned long lost_frames;
+ unsigned long recv_congest_count;
+ unsigned long frame_copied_errors;
+ unsigned long frequency_errors;
+ unsigned long token_errors;
+ unsigned long dummy1;
+};
+
+/* source routing stuff */
+
+#define TR_RII 0x80
+#define TR_RCF_DIR_BIT 0x80
+#define TR_RCF_LEN_MASK 0x1f00
+#define TR_RCF_BROADCAST 0x8000 /* all-routes broadcast */
+#define TR_RCF_LIMITED_BROADCAST 0xC000 /* single-route broadcast */
+#define TR_RCF_FRAME2K 0x20
+#define TR_RCF_BROADCAST_MASK 0xC000
+#define TR_MAXRIFLEN 18
+
+#endif /* _LINUX_IF_TR_H */
diff --git a/pfinet/linux-src/include/linux/if_tunnel.h b/pfinet/linux-src/include/linux/if_tunnel.h
new file mode 100644
index 00000000..bef9f8fd
--- /dev/null
+++ b/pfinet/linux-src/include/linux/if_tunnel.h
@@ -0,0 +1,29 @@
+#ifndef _IF_TUNNEL_H_
+#define _IF_TUNNEL_H_
+
+#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
+#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
+#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2)
+#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3)
+
+#define GRE_CSUM __constant_htons(0x8000)
+#define GRE_ROUTING __constant_htons(0x4000)
+#define GRE_KEY __constant_htons(0x2000)
+#define GRE_SEQ __constant_htons(0x1000)
+#define GRE_STRICT __constant_htons(0x0800)
+#define GRE_REC __constant_htons(0x0700)
+#define GRE_FLAGS __constant_htons(0x00F8)
+#define GRE_VERSION __constant_htons(0x0007)
+
+struct ip_tunnel_parm
+{
+ char name[IFNAMSIZ];
+ int link;
+ __u16 i_flags;
+ __u16 o_flags;
+ __u32 i_key;
+ __u32 o_key;
+ struct iphdr iph;
+};
+
+#endif /* _IF_TUNNEL_H_ */
diff --git a/pfinet/linux-src/include/linux/igmp.h b/pfinet/linux-src/include/linux/igmp.h
new file mode 100644
index 00000000..c13afde2
--- /dev/null
+++ b/pfinet/linux-src/include/linux/igmp.h
@@ -0,0 +1,129 @@
+/*
+ * Linux NET3: Internet Group Management Protocol [IGMP]
+ *
+ * Authors:
+ * Alan Cox <Alan.Cox@linux.org>
+ *
+ * Extended to talk the BSD extended IGMP protocol of mrouted 3.6
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IGMP_H
+#define _LINUX_IGMP_H
+
+/*
+ * IGMP protocol structures
+ */
+
+/*
+ * Header in on cable format
+ */
+
+struct igmphdr
+{
+ __u8 type;
+ __u8 code; /* For newer IGMP */
+ __u16 csum;
+ __u32 group;
+};
+
+#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */
+#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */
+#define IGMP_DVMRP 0x13 /* DVMRP routing */
+#define IGMP_PIM 0x14 /* PIM routing */
+#define IGMP_TRACE 0x15
+#define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16 /* New version of 0x11 */
+#define IGMP_HOST_LEAVE_MESSAGE 0x17
+
+#define IGMP_MTRACE_RESP 0x1e
+#define IGMP_MTRACE 0x1f
+
+
+/*
+ * Use the BSD names for these for compatibility
+ */
+
+#define IGMP_DELAYING_MEMBER 0x01
+#define IGMP_IDLE_MEMBER 0x02
+#define IGMP_LAZY_MEMBER 0x03
+#define IGMP_SLEEPING_MEMBER 0x04
+#define IGMP_AWAKENING_MEMBER 0x05
+
+#define IGMP_MINLEN 8
+
+#define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */
+ /* query (in seconds) */
+
+#define IGMP_TIMER_SCALE 10 /* denotes that the igmphdr->timer field */
+ /* specifies time in 10th of seconds */
+
+#define IGMP_AGE_THRESHOLD 400 /* If this host don't hear any IGMP V1 */
+ /* message in this period of time, */
+ /* revert to IGMP v2 router. */
+
+#define IGMP_ALL_HOSTS htonl(0xE0000001L)
+#define IGMP_ALL_ROUTER htonl(0xE0000002L)
+#define IGMP_LOCAL_GROUP htonl(0xE0000000L)
+#define IGMP_LOCAL_GROUP_MASK htonl(0xFFFFFF00L)
+
+/*
+ * struct for keeping the multicast list in
+ */
+
+#ifdef __KERNEL__
+
+/* ip_mc_socklist is real list now. Speed is not argument;
+ this list never used in fast path code
+ */
+
+struct ip_mc_socklist
+{
+ struct ip_mc_socklist *next;
+ int count;
+ struct ip_mreqn multi;
+};
+
+struct ip_mc_list
+{
+ struct in_device *interface;
+ unsigned long multiaddr;
+ struct ip_mc_list *next;
+ struct timer_list timer;
+ int users;
+ char tm_running;
+ char reporter;
+ char unsolicit_count;
+ char loaded;
+};
+
+extern __inline__ int ip_check_mc(struct device *dev, u32 mc_addr)
+{
+ struct in_device *in_dev = dev->ip_ptr;
+ struct ip_mc_list *im;
+
+ if (in_dev) {
+ for (im=in_dev->mc_list; im; im=im->next)
+ if (im->multiaddr == mc_addr)
+ return 1;
+ }
+ return 0;
+}
+
+extern int igmp_rcv(struct sk_buff *, unsigned short);
+extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
+extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
+extern void ip_mc_drop_socket(struct sock *sk);
+extern void ip_mr_init(void);
+extern void ip_mc_init_dev(struct in_device *);
+extern void ip_mc_destroy_dev(struct in_device *);
+extern void ip_mc_up(struct in_device *);
+extern void ip_mc_down(struct in_device *);
+extern int ip_mc_dec_group(struct in_device *in_dev, u32 addr);
+extern void ip_mc_inc_group(struct in_device *in_dev, u32 addr);
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/in.h b/pfinet/linux-src/include/linux/in.h
new file mode 100644
index 00000000..37db22a9
--- /dev/null
+++ b/pfinet/linux-src/include/linux/in.h
@@ -0,0 +1,189 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions of the Internet Protocol.
+ *
+ * Version: @(#)in.h 1.0.1 04/21/93
+ *
+ * Authors: Original taken from the GNU Project <netinet/in.h> file.
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IN_H
+#define _LINUX_IN_H
+
+#include <linux/types.h>
+
+/* Standard well-defined IP protocols. */
+enum {
+ IPPROTO_IP = 0, /* Dummy protocol for TCP */
+ IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
+ IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
+ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
+ IPPROTO_TCP = 6, /* Transmission Control Protocol */
+ IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
+ IPPROTO_PUP = 12, /* PUP protocol */
+ IPPROTO_UDP = 17, /* User Datagram Protocol */
+ IPPROTO_IDP = 22, /* XNS IDP protocol */
+ IPPROTO_RSVP = 46, /* RSVP protocol */
+ IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
+
+ IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
+
+ IPPROTO_PIM = 103, /* Protocol Independent Multicast */
+
+ IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
+ IPPROTO_AH = 51, /* Authentication Header protocol */
+ IPPROTO_COMP = 108, /* Compression Header protocol */
+
+ IPPROTO_RAW = 255, /* Raw IP packets */
+ IPPROTO_MAX
+};
+
+
+/* Internet address. */
+struct in_addr {
+ __u32 s_addr;
+};
+
+#define IP_TOS 1
+#define IP_TTL 2
+#define IP_HDRINCL 3
+#define IP_OPTIONS 4
+#define IP_ROUTER_ALERT 5
+#define IP_RECVOPTS 6
+#define IP_RETOPTS 7
+#define IP_PKTINFO 8
+#define IP_PKTOPTIONS 9
+#define IP_MTU_DISCOVER 10
+#define IP_RECVERR 11
+#define IP_RECVTTL 12
+#define IP_RECVTOS 13
+#define IP_MTU 14
+
+/* BSD compatibility */
+#define IP_RECVRETOPTS IP_RETOPTS
+
+/* IP_MTU_DISCOVER values */
+#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
+#define IP_PMTUDISC_WANT 1 /* Use per route hints */
+#define IP_PMTUDISC_DO 2 /* Always DF */
+
+#define IP_MULTICAST_IF 32
+#define IP_MULTICAST_TTL 33
+#define IP_MULTICAST_LOOP 34
+#define IP_ADD_MEMBERSHIP 35
+#define IP_DROP_MEMBERSHIP 36
+
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+
+/* Request struct for multicast socket ops */
+
+struct ip_mreq
+{
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_interface; /* local IP address of interface */
+};
+
+struct ip_mreqn
+{
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_address; /* local IP address of interface */
+ int imr_ifindex; /* Interface index */
+};
+
+struct in_pktinfo
+{
+ int ipi_ifindex;
+ struct in_addr ipi_spec_dst;
+ struct in_addr ipi_addr;
+};
+
+/* Structure describing an Internet (IP) socket address. */
+#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
+struct sockaddr_in {
+ sa_family_t sin_family; /* Address family */
+ unsigned short int sin_port; /* Port number */
+ struct in_addr sin_addr; /* Internet address */
+
+ /* Pad to size of `struct sockaddr'. */
+ unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
+ sizeof(unsigned short int) - sizeof(struct in_addr)];
+};
+#define sin_zero __pad /* for BSD UNIX comp. -FvK */
+
+
+/*
+ * Definitions of the bits in an Internet address integer.
+ * On subnets, host and network parts are found according
+ * to the subnet mask, not these masks.
+ */
+#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0)
+#define IN_CLASSA_NET 0xff000000
+#define IN_CLASSA_NSHIFT 24
+#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
+#define IN_CLASSA_MAX 128
+
+#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET 0xffff0000
+#define IN_CLASSB_NSHIFT 16
+#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
+#define IN_CLASSB_MAX 65536
+
+#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000)
+#define IN_CLASSC_NET 0xffffff00
+#define IN_CLASSC_NSHIFT 8
+#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
+
+#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
+#define IN_MULTICAST(a) IN_CLASSD(a)
+#define IN_MULTICAST_NET 0xF0000000
+
+#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#define IN_BADCLASS(a) IN_EXPERIMENTAL((a))
+
+/* Address to accept any incoming messages. */
+#define INADDR_ANY ((unsigned long int) 0x00000000)
+
+/* Address to send to all hosts. */
+#define INADDR_BROADCAST ((unsigned long int) 0xffffffff)
+
+/* Address indicating an error return. */
+#define INADDR_NONE ((unsigned long int) 0xffffffff)
+
+/* Network number for local host loopback. */
+#define IN_LOOPBACKNET 127
+
+/* Address to loopback in software to local host. */
+#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
+#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
+
+/* Defines for Multicast INADDR */
+#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
+#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
+#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
+#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
+
+
+/* <asm/byteorder.h> contains the htonl type stuff.. */
+#include <asm/byteorder.h>
+
+#ifdef __KERNEL__
+/* Some random defines to make it easier in the kernel.. */
+#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000))
+#define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000))
+#define BADCLASS(x) (((x) & htonl(0xf0000000)) == htonl(0xf0000000))
+#define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000))
+#define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000))
+
+#endif
+
+#endif /* _LINUX_IN_H */
diff --git a/pfinet/linux-src/include/linux/in6.h b/pfinet/linux-src/include/linux/in6.h
new file mode 100644
index 00000000..ca5e768b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/in6.h
@@ -0,0 +1,193 @@
+/*
+ * Types and definitions for AF_INET6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Sources:
+ * IPv6 Program Interfaces for BSD Systems
+ * <draft-ietf-ipngwg-bsd-api-05.txt>
+ *
+ * Advanced Sockets API for IPv6
+ * <draft-stevens-advanced-api-00.txt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IN6_H
+#define _LINUX_IN6_H
+
+#include <linux/types.h>
+
+/*
+ * IPv6 address structure
+ */
+
+struct in6_addr
+{
+ union
+ {
+ __u8 u6_addr8[16];
+ __u16 u6_addr16[8];
+ __u32 u6_addr32[4];
+#if (~0UL) > 0xffffffff
+#ifndef __RELAX_IN6_ADDR_ALIGNMENT
+ /* Alas, protocols do not respect 64bit alignmnet.
+ rsvp/pim/... are broken. However, it is good
+ idea to force correct alignment always, when
+ it is possible.
+ */
+ __u64 u6_addr64[2];
+#endif
+#endif
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#define s6_addr64 in6_u.u6_addr64
+};
+
+struct sockaddr_in6 {
+ unsigned short int sin6_family; /* AF_INET6 */
+ __u16 sin6_port; /* Transport layer port # */
+ __u32 sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+};
+
+
+struct ipv6_mreq {
+ /* IPv6 multicast address of group */
+ struct in6_addr ipv6mr_multiaddr;
+
+ /* local IPv6 address of interface */
+ int ipv6mr_ifindex;
+};
+
+struct in6_flowlabel_req
+{
+ struct in6_addr flr_dst;
+ __u32 flr_label;
+ __u8 flr_action;
+ __u8 flr_share;
+ __u16 flr_flags;
+ __u16 flr_expires;
+ __u16 flr_linger;
+ __u32 __flr_pad;
+ /* Options in format of IPV6_PKTOPTIONS */
+};
+
+#define IPV6_FL_A_GET 0
+#define IPV6_FL_A_PUT 1
+#define IPV6_FL_A_RENEW 2
+
+#define IPV6_FL_F_CREATE 1
+#define IPV6_FL_F_EXCL 2
+
+#define IPV6_FL_S_NONE 0
+#define IPV6_FL_S_EXCL 1
+#define IPV6_FL_S_PROCESS 2
+#define IPV6_FL_S_USER 3
+#define IPV6_FL_S_ANY 255
+
+
+/*
+ * Bitmask constant declarations to help applications select out the
+ * flow label and priority fields.
+ *
+ * Note that this are in host byte order while the flowinfo field of
+ * sockaddr_in6 is in network byte order.
+ */
+
+#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff
+#define IPV6_FLOWINFO_PRIORITY 0x0ff00000
+
+/* These defintions are obsolete */
+#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000
+#define IPV6_PRIORITY_FILLER 0x0100
+#define IPV6_PRIORITY_UNATTENDED 0x0200
+#define IPV6_PRIORITY_RESERVED1 0x0300
+#define IPV6_PRIORITY_BULK 0x0400
+#define IPV6_PRIORITY_RESERVED2 0x0500
+#define IPV6_PRIORITY_INTERACTIVE 0x0600
+#define IPV6_PRIORITY_CONTROL 0x0700
+#define IPV6_PRIORITY_8 0x0800
+#define IPV6_PRIORITY_9 0x0900
+#define IPV6_PRIORITY_10 0x0a00
+#define IPV6_PRIORITY_11 0x0b00
+#define IPV6_PRIORITY_12 0x0c00
+#define IPV6_PRIORITY_13 0x0d00
+#define IPV6_PRIORITY_14 0x0e00
+#define IPV6_PRIORITY_15 0x0f00
+
+/*
+ * IPV6 extension headers
+ */
+#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
+#define IPPROTO_ROUTING 43 /* IPv6 routing header */
+#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
+#define IPPROTO_ICMPV6 58 /* ICMPv6 */
+#define IPPROTO_NONE 59 /* IPv6 no next header */
+#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
+
+/*
+ * IPv6 TLV options.
+ */
+#define IPV6_TLV_PAD0 0
+#define IPV6_TLV_PADN 1
+#define IPV6_TLV_ROUTERALERT 20
+#define IPV6_TLV_JUMBO 194
+
+/*
+ * IPV6 socket options
+ */
+
+#define IPV6_ADDRFORM 1
+#define IPV6_PKTINFO 2
+#define IPV6_HOPOPTS 3
+#define IPV6_DSTOPTS 4
+#define IPV6_RTHDR 5
+#define IPV6_PKTOPTIONS 6
+#define IPV6_CHECKSUM 7
+#define IPV6_HOPLIMIT 8
+#define IPV6_NEXTHOP 9
+#define IPV6_AUTHHDR 10
+#define IPV6_FLOWINFO 11
+
+#if 0
+/* Aliases for obsolete names */
+#define IPV6_RXHOPOPTS IPV6_HOPOPTS
+#define IPV6_RXDSTOPTS IPV6_DSTOPTS
+#define IPV6_RXSRCRT IPV6_RTHDR
+#endif
+
+/*
+ * Alternative names
+ */
+#define SCM_SRCRT IPV6_RXSRCRT
+
+#define IPV6_UNICAST_HOPS 16
+#define IPV6_MULTICAST_IF 17
+#define IPV6_MULTICAST_HOPS 18
+#define IPV6_MULTICAST_LOOP 19
+#define IPV6_ADD_MEMBERSHIP 20
+#define IPV6_DROP_MEMBERSHIP 21
+#define IPV6_ROUTER_ALERT 22
+#define IPV6_MTU_DISCOVER 23
+#define IPV6_MTU 24
+#define IPV6_RECVERR 25
+
+/* IPV6_MTU_DISCOVER values */
+#define IPV6_PMTUDISC_DONT 0
+#define IPV6_PMTUDISC_WANT 1
+#define IPV6_PMTUDISC_DO 2
+
+/* Flowlabel */
+#define IPV6_FLOWLABEL_MGR 32
+#define IPV6_FLOWINFO_SEND 33
+
+
+#endif
diff --git a/pfinet/linux-src/include/linux/in_route.h b/pfinet/linux-src/include/linux/in_route.h
new file mode 100644
index 00000000..61f25c30
--- /dev/null
+++ b/pfinet/linux-src/include/linux/in_route.h
@@ -0,0 +1,32 @@
+#ifndef _LINUX_IN_ROUTE_H
+#define _LINUX_IN_ROUTE_H
+
+/* IPv4 routing cache flags */
+
+#define RTCF_DEAD RTNH_F_DEAD
+#define RTCF_ONLINK RTNH_F_ONLINK
+
+/* Obsolete flag. About to be deleted */
+#define RTCF_NOPMTUDISC RTM_F_NOPMTUDISC
+
+#define RTCF_NOTIFY 0x00010000
+#define RTCF_DIRECTDST 0x00020000
+#define RTCF_REDIRECTED 0x00040000
+#define RTCF_TPROXY 0x00080000
+
+#define RTCF_FAST 0x00200000
+#define RTCF_MASQ 0x00400000
+#define RTCF_SNAT 0x00800000
+#define RTCF_DOREDIRECT 0x01000000
+#define RTCF_DIRECTSRC 0x04000000
+#define RTCF_DNAT 0x08000000
+#define RTCF_BROADCAST 0x10000000
+#define RTCF_MULTICAST 0x20000000
+#define RTCF_REJECT 0x40000000
+#define RTCF_LOCAL 0x80000000
+
+#define RTCF_NAT (RTCF_DNAT|RTCF_SNAT)
+
+#define RT_TOS(tos) ((tos)&IPTOS_TOS_MASK)
+
+#endif /* _LINUX_IN_ROUTE_H */
diff --git a/pfinet/linux-src/include/linux/in_systm.h b/pfinet/linux-src/include/linux/in_systm.h
new file mode 100644
index 00000000..eac9a588
--- /dev/null
+++ b/pfinet/linux-src/include/linux/in_systm.h
@@ -0,0 +1,32 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Miscellaneous internetwork definitions for kernel.
+ *
+ * Version: @(#)in_systm.h 1.0.0 12/17/93
+ *
+ * Authors: Original taken from Berkeley BSD UNIX 4.3-RENO.
+ * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IN_SYSTM_H
+#define _LINUX_IN_SYSTM_H
+
+/*
+ * Network types.
+ * The n_ types are network-order variants of their natural
+ * equivalents. The Linux kernel NET-2 code does not use
+ * them (yet), but it might in the future. This is mostly
+ * there for compatibility with BSD user-level programs.
+ */
+typedef u_short n_short; /* short as received from the net */
+typedef u_long n_long; /* long as received from the net */
+typedef u_long n_time; /* ms since 00:00 GMT, byte rev */
+
+#endif /* _LINUX_IN_SYSTM_H */
diff --git a/pfinet/linux-src/include/linux/inet.h b/pfinet/linux-src/include/linux/inet.h
new file mode 100644
index 00000000..acb93765
--- /dev/null
+++ b/pfinet/linux-src/include/linux/inet.h
@@ -0,0 +1,52 @@
+/*
+ * Swansea University Computer Society NET3
+ *
+ * This work is derived from NET2Debugged, which is in turn derived
+ * from NET2D which was written by:
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This work was derived from Ross Biro's inspirational work
+ * for the LINUX operating system. His version numbers were:
+ *
+ * $Id: Space.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $
+ * $Id: arp.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $
+ * $Id: arp.h,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $
+ * $Id: dev.c,v 0.8.4.13 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: dev.h,v 0.8.4.7 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: eth.c,v 0.8.4.4 1993/01/22 23:21:38 bir7 Exp $
+ * $Id: eth.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $
+ * $Id: icmp.c,v 0.8.4.9 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: icmp.h,v 0.8.4.2 1992/11/15 14:55:30 bir7 Exp $
+ * $Id: ip.c,v 0.8.4.8 1992/12/12 19:25:04 bir7 Exp $
+ * $Id: ip.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: loopback.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: packet.c,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $
+ * $Id: protocols.c,v 0.8.4.3 1992/11/15 14:55:30 bir7 Exp $
+ * $Id: raw.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $
+ * $Id: sock.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $
+ * $Id: sock.h,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $
+ * $Id: tcp.c,v 0.8.4.16 1993/01/26 22:04:00 bir7 Exp $
+ * $Id: tcp.h,v 0.8.4.7 1993/01/22 22:58:08 bir7 Exp $
+ * $Id: timer.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: timer.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: udp.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $
+ * $Id: udp.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $
+ * $Id: we.c,v 0.8.4.10 1993/01/23 18:00:11 bir7 Exp $
+ * $Id: wereg.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_INET_H
+#define _LINUX_INET_H
+
+#ifdef __KERNEL__
+
+extern void inet_proto_init(struct net_proto *pro);
+extern char *in_ntoa(__u32 in);
+extern __u32 in_aton(const char *str);
+
+#endif
+#endif /* _LINUX_INET_H */
diff --git a/pfinet/linux-src/include/linux/inetdevice.h b/pfinet/linux-src/include/linux/inetdevice.h
new file mode 100644
index 00000000..323a305c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/inetdevice.h
@@ -0,0 +1,128 @@
+#ifndef _LINUX_INETDEVICE_H
+#define _LINUX_INETDEVICE_H
+
+#ifdef __KERNEL__
+
+struct ipv4_devconf
+{
+ int accept_redirects;
+ int send_redirects;
+ int secure_redirects;
+ int shared_media;
+ int accept_source_route;
+ int rp_filter;
+ int proxy_arp;
+ int bootp_relay;
+ int log_martians;
+ int forwarding;
+ int mc_forwarding;
+ int hidden;
+ void *sysctl;
+};
+
+extern struct ipv4_devconf ipv4_devconf;
+
+struct in_device
+{
+ struct device *dev;
+ struct in_ifaddr *ifa_list; /* IP ifaddr chain */
+ struct ip_mc_list *mc_list; /* IP multicast filter chain */
+ unsigned long mr_v1_seen;
+ unsigned flags;
+ struct neigh_parms *arp_parms;
+ struct ipv4_devconf cnf;
+};
+
+#define IN_DEV_FORWARD(in_dev) ((in_dev)->cnf.forwarding)
+#define IN_DEV_MFORWARD(in_dev) (ipv4_devconf.mc_forwarding && (in_dev)->cnf.mc_forwarding)
+#define IN_DEV_RPFILTER(in_dev) (ipv4_devconf.rp_filter && (in_dev)->cnf.rp_filter)
+#define IN_DEV_SOURCE_ROUTE(in_dev) (ipv4_devconf.accept_source_route && (in_dev)->cnf.accept_source_route)
+#define IN_DEV_BOOTP_RELAY(in_dev) (ipv4_devconf.bootp_relay && (in_dev)->cnf.bootp_relay)
+
+#define IN_DEV_LOG_MARTIANS(in_dev) (ipv4_devconf.log_martians || (in_dev)->cnf.log_martians)
+#define IN_DEV_PROXY_ARP(in_dev) (ipv4_devconf.proxy_arp || (in_dev)->cnf.proxy_arp)
+#define IN_DEV_HIDDEN(in_dev) ((in_dev)->cnf.hidden && ipv4_devconf.hidden)
+#define IN_DEV_SHARED_MEDIA(in_dev) (ipv4_devconf.shared_media || (in_dev)->cnf.shared_media)
+#define IN_DEV_TX_REDIRECTS(in_dev) (ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects)
+#define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
+
+#define IN_DEV_RX_REDIRECTS(in_dev) \
+ ((IN_DEV_FORWARD(in_dev) && \
+ (ipv4_devconf.accept_redirects && (in_dev)->cnf.accept_redirects)) \
+ || (!IN_DEV_FORWARD(in_dev) && \
+ (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
+
+struct in_ifaddr
+{
+ struct in_ifaddr *ifa_next;
+ struct in_device *ifa_dev;
+ u32 ifa_local;
+ u32 ifa_address;
+ u32 ifa_mask;
+ u32 ifa_broadcast;
+ u32 ifa_anycast;
+ unsigned char ifa_scope;
+ unsigned char ifa_flags;
+ unsigned char ifa_prefixlen;
+ char ifa_label[IFNAMSIZ];
+};
+
+extern int register_inetaddr_notifier(struct notifier_block *nb);
+extern int unregister_inetaddr_notifier(struct notifier_block *nb);
+
+extern struct device *ip_dev_find(u32 addr);
+extern struct in_ifaddr *inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b);
+extern int devinet_ioctl(unsigned int cmd, void *);
+extern void devinet_init(void);
+extern struct in_device *inetdev_init(struct device *dev);
+extern struct in_device *inetdev_by_index(int);
+extern u32 inet_select_addr(struct device *dev, u32 dst, int scope);
+extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
+extern void inet_forward_change(void);
+
+extern __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
+{
+ return !((addr^ifa->ifa_address)&ifa->ifa_mask);
+}
+
+/*
+ * Check if a mask is acceptable.
+ */
+
+extern __inline__ int bad_mask(u32 mask, u32 addr)
+{
+ if (addr & (mask = ~mask))
+ return 1;
+ mask = ntohl(mask);
+ if (mask & (mask+1))
+ return 1;
+ return 0;
+}
+
+#define for_primary_ifa(in_dev) { struct in_ifaddr *ifa; \
+ for (ifa = (in_dev)->ifa_list; ifa && !(ifa->ifa_flags&IFA_F_SECONDARY); ifa = ifa->ifa_next)
+
+#define for_ifa(in_dev) { struct in_ifaddr *ifa; \
+ for (ifa = (in_dev)->ifa_list; ifa; ifa = ifa->ifa_next)
+
+
+#define endfor_ifa(in_dev) }
+
+#endif /* __KERNEL__ */
+
+extern __inline__ __u32 inet_make_mask(int logmask)
+{
+ if (logmask)
+ return htonl(~((1<<(32-logmask))-1));
+ return 0;
+}
+
+extern __inline__ int inet_mask_len(__u32 mask)
+{
+ if (!(mask = ntohl(mask)))
+ return 0;
+ return 32 - ffz(~mask);
+}
+
+
+#endif /* _LINUX_INETDEVICE_H */
diff --git a/pfinet/linux-src/include/linux/init.h b/pfinet/linux-src/include/linux/init.h
new file mode 100644
index 00000000..4465f38b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/init.h
@@ -0,0 +1,68 @@
+#ifndef _LINUX_INIT_H
+#define _LINUX_INIT_H
+
+/* These macros are used to mark some functions or
+ * initialized data (doesn't apply to uninitialized data)
+ * as `initialization' functions. The kernel can take this
+ * as hint that the function is used only during the initialization
+ * phase and free up used memory resources after
+ *
+ * Usage:
+ * For functions:
+ *
+ * You should add __init immediately before the function name, like:
+ *
+ * static void __init initme(int x, int y)
+ * {
+ * extern int z; z = x * y;
+ * }
+ *
+ * Depricated: you can surround the whole function declaration
+ * just before function body into __initfunc() macro, like:
+ *
+ * __initfunc (static void initme(int x, int y))
+ * {
+ * extern int z; z = x * y;
+ * }
+ *
+ * If the function has a prototype somewhere, you can also add
+ * __init between closing brace of the prototype and semicolon:
+ *
+ * extern int initialize_foobar_device(int, int, int) __init;
+ *
+ * For initialized data:
+ * You should insert __initdata between the variable name and equal
+ * sign followed by value, e.g.:
+ *
+ * static int init_variable __initdata = 0;
+ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ *
+ * For initialized data not at file scope, i.e. within a function,
+ * you should use __initlocaldata instead, due to a bug in GCC 2.7.
+ */
+
+/*
+ * Disable the __initfunc macros if a file that is a part of a
+ * module attempts to use them. We do not want to interfere
+ * with module linking.
+ */
+
+#ifndef MODULE
+#include <asm/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(__arginit) __arginit
+/* For assembly routines */
+#define __INIT
+#define __FINIT
+#define __INITDATA
+#endif
+
+#if __GNUC__ >= 2 && __GNUC_MINOR__ >= 8
+#define __initlocaldata __initdata
+#else
+#define __initlocaldata
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/interrupt.h b/pfinet/linux-src/include/linux/interrupt.h
new file mode 100644
index 00000000..3e3edd8b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/interrupt.h
@@ -0,0 +1,84 @@
+/* interrupt.h */
+#ifndef _LINUX_INTERRUPT_H
+#define _LINUX_INTERRUPT_H
+
+#include <linux/kernel.h>
+#include <asm/bitops.h>
+#include <asm/atomic.h>
+
+struct irqaction {
+ void (*handler)(int, void *, struct pt_regs *);
+ unsigned long flags;
+ unsigned long mask;
+ const char *name;
+ void *dev_id;
+ struct irqaction *next;
+};
+
+extern volatile unsigned char bh_running;
+
+extern atomic_t bh_mask_count[32];
+extern unsigned long bh_active;
+extern unsigned long bh_mask;
+extern void (*bh_base[32])(void);
+
+asmlinkage void do_bottom_half(void);
+
+/* Who gets which entry in bh_base. Things which will occur most often
+ should come first - in which case NET should be up the top with SERIAL/TQUEUE! */
+
+enum {
+ TIMER_BH = 0,
+ CONSOLE_BH,
+ TQUEUE_BH,
+ DIGI_BH,
+ SERIAL_BH,
+ RISCOM8_BH,
+ SPECIALIX_BH,
+ AURORA_BH,
+ ESP_BH,
+ NET_BH,
+ SCSI_BH,
+ IMMEDIATE_BH,
+ KEYBOARD_BH,
+ CYCLADES_BH,
+ CM206_BH,
+ JS_BH,
+ MACSERIAL_BH,
+ ISICOM_BH
+};
+
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
+/*
+ * Autoprobing for irqs:
+ *
+ * probe_irq_on() and probe_irq_off() provide robust primitives
+ * for accurate IRQ probing during kernel initialization. They are
+ * reasonably simple to use, are not "fooled" by spurious interrupts,
+ * and, unlike other attempts at IRQ probing, they do not get hung on
+ * stuck interrupts (such as unused PS2 mouse interfaces on ASUS boards).
+ *
+ * For reasonably foolproof probing, use them as follows:
+ *
+ * 1. clear and/or mask the device's internal interrupt.
+ * 2. sti();
+ * 3. irqs = probe_irq_on(); // "take over" all unassigned idle IRQs
+ * 4. enable the device and cause it to trigger an interrupt.
+ * 5. wait for the device to interrupt, using non-intrusive polling or a delay.
+ * 6. irq = probe_irq_off(irqs); // get IRQ number, 0=none, negative=multiple
+ * 7. service the device to clear its pending interrupt.
+ * 8. loop again if paranoia is required.
+ *
+ * probe_irq_on() returns a mask of allocated irq's.
+ *
+ * probe_irq_off() takes the mask as a parameter,
+ * and returns the irq number which occurred,
+ * or zero if none occurred, or a negative irq number
+ * if more than one irq occurred.
+ */
+extern unsigned long probe_irq_on(void); /* returns 0 on failure */
+extern int probe_irq_off(unsigned long); /* returns 0 or negative on failure */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/ioctl.h b/pfinet/linux-src/include/linux/ioctl.h
new file mode 100644
index 00000000..aa91eb39
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ioctl.h
@@ -0,0 +1,7 @@
+#ifndef _LINUX_IOCTL_H
+#define _LINUX_IOCTL_H
+
+#include <asm/ioctl.h>
+
+#endif /* _LINUX_IOCTL_H */
+
diff --git a/pfinet/linux-src/include/linux/ioport.h b/pfinet/linux-src/include/linux/ioport.h
new file mode 100644
index 00000000..b5eef44d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ioport.h
@@ -0,0 +1,35 @@
+/*
+ * portio.h Definitions of routines for detecting, reserving and
+ * allocating system resources.
+ *
+ * Version: 0.01 8/30/93
+ *
+ * Author: Donald Becker (becker@super.org)
+ */
+
+#ifndef _LINUX_PORTIO_H
+#define _LINUX_PORTIO_H
+
+#define HAVE_PORTRESERVE
+/*
+ * Call check_region() before probing for your hardware.
+ * Once you have found you hardware, register it with request_region().
+ * If you unload the driver, use release_region to free ports.
+ */
+extern void reserve_setup(char *str, int *ints);
+extern int check_region(unsigned long from, unsigned long extent);
+extern void request_region(unsigned long from, unsigned long extent,const char *name);
+extern void release_region(unsigned long from, unsigned long extent);
+extern int get_ioport_list(char *);
+
+#ifdef __sparc__
+extern unsigned long occupy_region(unsigned long base, unsigned long end,
+ unsigned long num, unsigned int align,
+ const char *name);
+#endif
+
+#define HAVE_AUTOIRQ
+extern void autoirq_setup(int waittime);
+extern int autoirq_report(int waittime);
+
+#endif /* _LINUX_PORTIO_H */
diff --git a/pfinet/linux-src/include/linux/ip.h b/pfinet/linux-src/include/linux/ip.h
new file mode 100644
index 00000000..7b642728
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ip.h
@@ -0,0 +1,138 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the IP protocol.
+ *
+ * Version: @(#)ip.h 1.0.2 04/28/93
+ *
+ * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IP_H
+#define _LINUX_IP_H
+#include <asm/byteorder.h>
+
+/* SOL_IP socket options */
+
+#define IPTOS_TOS_MASK 0x1E
+#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IPTOS_MINCOST 0x02
+
+#define IPTOS_PREC_MASK 0xE0
+#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
+#define IPTOS_PREC_NETCONTROL 0xe0
+#define IPTOS_PREC_INTERNETCONTROL 0xc0
+#define IPTOS_PREC_CRITIC_ECP 0xa0
+#define IPTOS_PREC_FLASHOVERRIDE 0x80
+#define IPTOS_PREC_FLASH 0x60
+#define IPTOS_PREC_IMMEDIATE 0x40
+#define IPTOS_PREC_PRIORITY 0x20
+#define IPTOS_PREC_ROUTINE 0x00
+
+
+/* IP options */
+#define IPOPT_COPY 0x80
+#define IPOPT_CLASS_MASK 0x60
+#define IPOPT_NUMBER_MASK 0x1f
+
+#define IPOPT_COPIED(o) ((o)&IPOPT_COPY)
+#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK)
+#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK)
+
+#define IPOPT_CONTROL 0x00
+#define IPOPT_RESERVED1 0x20
+#define IPOPT_MEASUREMENT 0x40
+#define IPOPT_RESERVED2 0x60
+
+#define IPOPT_END (0 |IPOPT_CONTROL)
+#define IPOPT_NOOP (1 |IPOPT_CONTROL)
+#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT)
+#define IPOPT_RR (7 |IPOPT_CONTROL)
+#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY)
+#define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY)
+
+#define IPVERSION 4
+#define MAXTTL 255
+#define IPDEFTTL 64
+
+/* struct timestamp, struct route and MAX_ROUTES are removed.
+
+ REASONS: it is clear that nobody used them because:
+ - MAX_ROUTES value was wrong.
+ - "struct route" was wrong.
+ - "struct timestamp" had fatally misaligned bitfields and was completely unusable.
+ */
+
+#define IPOPT_OPTVAL 0
+#define IPOPT_OLEN 1
+#define IPOPT_OFFSET 2
+#define IPOPT_MINOFF 4
+#define MAX_IPOPTLEN 40
+#define IPOPT_NOP IPOPT_NOOP
+#define IPOPT_EOL IPOPT_END
+#define IPOPT_TS IPOPT_TIMESTAMP
+
+#define IPOPT_TS_TSONLY 0 /* timestamps only */
+#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
+#define IPOPT_TS_PRESPEC 3 /* specified modules only */
+
+#ifdef __KERNEL__
+
+struct ip_options {
+ __u32 faddr; /* Saved first hop address */
+ unsigned char optlen;
+ unsigned char srr;
+ unsigned char rr;
+ unsigned char ts;
+ unsigned char is_setbyuser:1, /* Set by setsockopt? */
+ is_data:1, /* Options in __data, rather than skb */
+ is_strictroute:1, /* Strict source route */
+ srr_is_hit:1, /* Packet destination addr was our one */
+ is_changed:1, /* IP checksum more not valid */
+ rr_needaddr:1, /* Need to record addr of outgoing dev */
+ ts_needtime:1, /* Need to record timestamp */
+ ts_needaddr:1; /* Need to record addr of outgoing dev */
+ unsigned char router_alert;
+ unsigned char __pad1;
+ unsigned char __pad2;
+ unsigned char __data[0];
+};
+
+#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
+#endif
+
+struct iphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 ihl:4,
+ version:4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+ __u8 version:4,
+ ihl:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 tos;
+ __u16 tot_len;
+ __u16 id;
+ __u16 frag_off;
+ __u8 ttl;
+ __u8 protocol;
+ __u16 check;
+ __u32 saddr;
+ __u32 daddr;
+ /*The options start here. */
+};
+
+#endif /* _LINUX_IP_H */
diff --git a/pfinet/linux-src/include/linux/ip_fw.h b/pfinet/linux-src/include/linux/ip_fw.h
new file mode 100644
index 00000000..f36ec7e6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ip_fw.h
@@ -0,0 +1,193 @@
+/*
+ * This code is heavily based on the code in ip_fw.h; see that file for
+ * copyrights and attributions. This code is basically GPL.
+ *
+ * 15-Feb-1997: Major changes to allow graphs for firewall rules.
+ * Paul Russell <Paul.Russell@rustcorp.com.au> and
+ * Michael Neuling <Michael.Neuling@rustcorp.com.au>
+ * 2-Nov-1997: Changed types to __u16, etc.
+ * Removed IP_FW_F_TCPACK & IP_FW_F_BIDIR.
+ * Added inverse flags field.
+ * Removed multiple port specs.
+ */
+
+/*
+ * Format of an IP firewall descriptor
+ *
+ * src, dst, src_mask, dst_mask are always stored in network byte order.
+ * flags are stored in host byte order (of course).
+ * Port numbers are stored in HOST byte order.
+ */
+
+#ifndef _IP_FWCHAINS_H
+#define _IP_FWCHAINS_H
+
+#ifdef __KERNEL__
+#include <linux/icmp.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#endif /* __KERNEL__ */
+#define IP_FW_MAX_LABEL_LENGTH 8
+typedef char ip_chainlabel[IP_FW_MAX_LABEL_LENGTH+1];
+
+struct ip_fw
+{
+ struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
+ struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
+ __u32 fw_mark; /* ID to stamp on packet */
+ __u16 fw_proto; /* Protocol, 0 = ANY */
+ __u16 fw_flg; /* Flags word */
+ __u16 fw_invflg; /* Inverse flags */
+ __u16 fw_spts[2]; /* Source port range. */
+ __u16 fw_dpts[2]; /* Destination port range. */
+ __u16 fw_redirpt; /* Port to redirect to. */
+ __u16 fw_outputsize; /* Max amount to output to
+ NETLINK */
+ char fw_vianame[IFNAMSIZ]; /* name of interface "via" */
+ __u8 fw_tosand, fw_tosxor; /* Revised packet priority */
+};
+
+struct ip_fwuser
+{
+ struct ip_fw ipfw;
+ ip_chainlabel label;
+};
+
+/* Values for "fw_flg" field . */
+#define IP_FW_F_PRN 0x0001 /* Print packet if it matches */
+#define IP_FW_F_TCPSYN 0x0002 /* For tcp packets-check SYN only */
+#define IP_FW_F_FRAG 0x0004 /* Set if rule is a fragment rule */
+#define IP_FW_F_MARKABS 0x0008 /* Set the mark to fw_mark, not add. */
+#define IP_FW_F_WILDIF 0x0010 /* Need only match start of interface name. */
+#define IP_FW_F_NETLINK 0x0020 /* Redirect to netlink: 2.1.x only */
+#define IP_FW_F_MASK 0x003F /* All possible flag bits mask */
+
+/* Values for "fw_invflg" field. */
+#define IP_FW_INV_SRCIP 0x0001 /* Invert the sense of fw_src. */
+#define IP_FW_INV_DSTIP 0x0002 /* Invert the sense of fw_dst. */
+#define IP_FW_INV_PROTO 0x0004 /* Invert the sense of fw_proto. */
+#define IP_FW_INV_SRCPT 0x0008 /* Invert the sense of source ports. */
+#define IP_FW_INV_DSTPT 0x0010 /* Invert the sense of destination ports. */
+#define IP_FW_INV_VIA 0x0020 /* Invert the sense of fw_vianame. */
+#define IP_FW_INV_SYN 0x0040 /* Invert the sense of IP_FW_F_TCPSYN. */
+#define IP_FW_INV_FRAG 0x0080 /* Invert the sense of IP_FW_F_FRAG. */
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use
+ * a raw socket for this. Instead we check rights in the calls. */
+
+#define IP_FW_BASE_CTL 64 /* base for firewall socket options */
+
+#define IP_FW_APPEND (IP_FW_BASE_CTL) /* Takes ip_fwchange */
+#define IP_FW_REPLACE (IP_FW_BASE_CTL+1) /* Takes ip_fwnew */
+#define IP_FW_DELETE_NUM (IP_FW_BASE_CTL+2) /* Takes ip_fwdelnum */
+#define IP_FW_DELETE (IP_FW_BASE_CTL+3) /* Takes ip_fwchange */
+#define IP_FW_INSERT (IP_FW_BASE_CTL+4) /* Takes ip_fwnew */
+#define IP_FW_FLUSH (IP_FW_BASE_CTL+5) /* Takes ip_chainlabel */
+#define IP_FW_ZERO (IP_FW_BASE_CTL+6) /* Takes ip_chainlabel */
+#define IP_FW_CHECK (IP_FW_BASE_CTL+7) /* Takes ip_fwtest */
+#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+8) /* Takes 3 ints */
+#define IP_FW_CREATECHAIN (IP_FW_BASE_CTL+9) /* Takes ip_chainlabel */
+#define IP_FW_DELETECHAIN (IP_FW_BASE_CTL+10) /* Takes ip_chainlabel */
+#define IP_FW_POLICY (IP_FW_BASE_CTL+11) /* Takes ip_fwpolicy */
+/* Masquerade control, only 1 optname */
+
+#define IP_FW_MASQ_CTL (IP_FW_BASE_CTL+12) /* General ip_masq ctl */
+
+/* Builtin chain labels */
+#define IP_FW_LABEL_FORWARD "forward"
+#define IP_FW_LABEL_INPUT "input"
+#define IP_FW_LABEL_OUTPUT "output"
+
+/* Special targets */
+#define IP_FW_LABEL_MASQUERADE "MASQ"
+#define IP_FW_LABEL_REDIRECT "REDIRECT"
+#define IP_FW_LABEL_ACCEPT "ACCEPT"
+#define IP_FW_LABEL_BLOCK "DENY"
+#define IP_FW_LABEL_REJECT "REJECT"
+#define IP_FW_LABEL_RETURN "RETURN"
+#define IP_FW_LABEL_QUEUE "QUEUE"
+
+/* Files in /proc/net */
+#define IP_FW_PROC_CHAINS "ip_fwchains"
+#define IP_FW_PROC_CHAIN_NAMES "ip_fwnames"
+
+
+struct ip_fwpkt
+{
+ struct iphdr fwp_iph; /* IP header */
+ union {
+ struct tcphdr fwp_tcph; /* TCP header or */
+ struct udphdr fwp_udph; /* UDP header */
+ struct icmphdr fwp_icmph; /* ICMP header */
+ } fwp_protoh;
+ struct in_addr fwp_via; /* interface address */
+ char fwp_vianame[IFNAMSIZ]; /* interface name */
+};
+
+/* The argument to IP_FW_DELETE and IP_FW_APPEND */
+struct ip_fwchange
+{
+ struct ip_fwuser fwc_rule;
+ ip_chainlabel fwc_label;
+};
+
+/* The argument to IP_FW_CHECK. */
+struct ip_fwtest
+{
+ struct ip_fwpkt fwt_packet; /* Packet to be tested */
+ ip_chainlabel fwt_label; /* Block to start test in */
+};
+
+/* The argument to IP_FW_DELETE_NUM */
+struct ip_fwdelnum
+{
+ __u32 fwd_rulenum;
+ ip_chainlabel fwd_label;
+};
+
+/* The argument to IP_FW_REPLACE and IP_FW_INSERT */
+struct ip_fwnew
+{
+ __u32 fwn_rulenum;
+ struct ip_fwuser fwn_rule;
+ ip_chainlabel fwn_label;
+};
+
+/* The argument to IP_FW_POLICY */
+struct ip_fwpolicy
+{
+ ip_chainlabel fwp_policy;
+ ip_chainlabel fwp_label;
+};
+/*
+ * timeouts for ip masquerading
+ */
+
+extern int ip_fw_masq_timeouts(void *, int);
+
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#include <linux/init.h>
+extern void ip_fw_init(void) __init;
+#else /* 2.0.x */
+extern void ip_fw_init(void);
+#endif /* 2.1.x */
+extern int ip_fw_ctl(int, void *, int);
+#ifdef CONFIG_IP_MASQUERADE
+extern int ip_masq_uctl(int, char *, int);
+#endif
+#endif /* KERNEL */
+
+#endif /* _IP_FWCHAINS_H */
diff --git a/pfinet/linux-src/include/linux/ip_masq.h b/pfinet/linux-src/include/linux/ip_masq.h
new file mode 100644
index 00000000..ba893138
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ip_masq.h
@@ -0,0 +1,140 @@
+/*
+ * IP_MASQ user space control interface
+ * $Id: ip_masq.h,v 1.2 1998/12/08 05:41:48 davem Exp $
+ */
+
+#ifndef _LINUX_IP_MASQ_H
+#define _LINUX_IP_MASQ_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/stddef.h>
+#else
+#include <sys/types.h>
+#include <stddef.h>
+#endif
+
+struct ip_masq_user {
+ int protocol;
+ u_int16_t sport, dport, mport;
+ u_int32_t saddr, daddr, maddr;
+ u_int32_t rt_daddr; /* dst address to use for rt query */
+ u_int32_t rt_saddr;
+ u_int32_t ip_tos; /* TOS */
+ unsigned timeout; /* in ticks (HZ per sec) */
+ unsigned flags;
+ int fd; /* NOT IMPL: attach tunnel to this fd */
+ int state; /* NOT IMPL: return conn state */
+};
+
+#define IP_MASQ_USER_F_LISTEN 0x01 /* put entry to LISTEN state */
+#define IP_MASQ_USER_F_DEAD 0x02 /* mark as DEAD */
+#define IP_MASQ_USER_F_FORCE 0x04 /* force operation */
+
+struct ip_masq_timeout {
+ int protocol;
+ union {
+ struct {
+ unsigned established;
+ unsigned syn_sent;
+ unsigned syn_recv;
+ unsigned fin_wait;
+ unsigned time_wait;
+ unsigned close;
+ unsigned close_wait;
+ unsigned last_ack;
+ unsigned listen;
+ } tcp;
+ unsigned udp;
+ unsigned icmp;
+ } u;
+};
+
+/*
+ * AUTOFW stuff
+ */
+#define IP_FWD_RANGE 1
+#define IP_FWD_PORT 2
+#define IP_FWD_DIRECT 3
+
+#define IP_AUTOFW_ACTIVE 1
+#define IP_AUTOFW_USETIME 2
+#define IP_AUTOFW_SECURE 4
+
+
+/* WARNING: bitwise equal to ip_autofw in net/ip_autofw.h */
+struct ip_autofw_user {
+ void * next;
+ u_int16_t type;
+ u_int16_t low;
+ u_int16_t hidden;
+ u_int16_t high;
+ u_int16_t visible;
+ u_int16_t protocol;
+ u_int32_t lastcontact;
+ u_int32_t where;
+ u_int16_t ctlproto;
+ u_int16_t ctlport;
+ u_int16_t flags;
+ /* struct timer_list timer; */
+};
+
+/*
+ * PORTFW stuff
+ */
+struct ip_portfw_user {
+ u_int16_t protocol; /* Which protocol are we talking? */
+ u_int32_t laddr, raddr; /* Remote address */
+ u_int16_t lport, rport; /* Local and remote port */
+ int pref; /* Preference value */
+};
+
+/*
+ * MFW stuff
+ */
+struct ip_mfw_user {
+ u_int32_t fwmark; /* Firewalling mark */
+ u_int32_t raddr; /* remote port */
+ u_int16_t rport; /* remote port */
+ u_int16_t dummy; /* Make up to multiple of 4 */
+ int pref; /* Preference value */
+ unsigned flags; /* misc flags */
+};
+
+#define IP_MASQ_MFW_SCHED 0x01
+
+#define IP_FW_MASQCTL_MAX 256
+#define IP_MASQ_TNAME_MAX 32
+
+struct ip_masq_ctl {
+ int m_target;
+ int m_cmd;
+ char m_tname[IP_MASQ_TNAME_MAX];
+ union {
+ struct ip_portfw_user portfw_user;
+ struct ip_autofw_user autofw_user;
+ struct ip_mfw_user mfw_user;
+ struct ip_masq_user user;
+ unsigned char m_raw[IP_FW_MASQCTL_MAX];
+ } u;
+};
+
+#define IP_MASQ_CTL_BSIZE (offsetof (struct ip_masq_ctl,u))
+
+#define IP_MASQ_TARGET_CORE 1
+#define IP_MASQ_TARGET_MOD 2 /* masq_mod is selected by "name" */
+#define IP_MASQ_TARGET_USER 3
+#define IP_MASQ_TARGET_LAST 4
+
+#define IP_MASQ_CMD_NONE 0 /* just peek */
+#define IP_MASQ_CMD_INSERT 1
+#define IP_MASQ_CMD_ADD 2
+#define IP_MASQ_CMD_SET 3
+#define IP_MASQ_CMD_DEL 4
+#define IP_MASQ_CMD_GET 5
+#define IP_MASQ_CMD_FLUSH 6
+#define IP_MASQ_CMD_LIST 7 /* actually fake: done via /proc */
+#define IP_MASQ_CMD_ENABLE 8
+#define IP_MASQ_CMD_DISABLE 9
+
+#endif /* _LINUX_IP_MASQ_H */
diff --git a/pfinet/linux-src/include/linux/ipc.h b/pfinet/linux-src/include/linux/ipc.h
new file mode 100644
index 00000000..851ff4ce
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ipc.h
@@ -0,0 +1,49 @@
+#ifndef _LINUX_IPC_H
+#define _LINUX_IPC_H
+
+#include <linux/types.h>
+
+#define IPC_PRIVATE ((__kernel_key_t) 0)
+
+struct ipc_perm
+{
+ __kernel_key_t key;
+ __kernel_uid_t uid;
+ __kernel_gid_t gid;
+ __kernel_uid_t cuid;
+ __kernel_gid_t cgid;
+ __kernel_mode_t mode;
+ unsigned short seq;
+};
+
+/* resource get request flags */
+#define IPC_CREAT 00001000 /* create if key is nonexistent */
+#define IPC_EXCL 00002000 /* fail if key exists */
+#define IPC_NOWAIT 00004000 /* return error on wait */
+
+/* these fields are used by the DIPC package so the kernel as standard
+ should avoid using them if possible */
+
+#define IPC_DIPC 00010000 /* make it distributed */
+#define IPC_OWN 00020000 /* this machine is the DIPC owner */
+
+/*
+ * Control commands used with semctl, msgctl and shmctl
+ * see also specific commands in sem.h, msg.h and shm.h
+ */
+#define IPC_RMID 0 /* remove resource */
+#define IPC_SET 1 /* set ipc_perm options */
+#define IPC_STAT 2 /* get ipc_perm options */
+#define IPC_INFO 3 /* see ipcs */
+
+#ifdef __KERNEL__
+
+/* special shmsegs[id], msgque[id] or semary[id] values */
+#define IPC_UNUSED ((void *) -1)
+#define IPC_NOID ((void *) -2) /* being allocated/destroyed */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_IPC_H */
+
+
diff --git a/pfinet/linux-src/include/linux/ipsec.h b/pfinet/linux-src/include/linux/ipsec.h
new file mode 100644
index 00000000..b9d7bcc6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ipsec.h
@@ -0,0 +1,69 @@
+/*
+ * Definitions for the SECurity layer
+ *
+ * Author:
+ * Robert Muchsel <muchsel@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IPSEC_H
+#define _LINUX_IPSEC_H
+
+#include <linux/config.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <linux/skbuff.h>
+
+/* Values for the set/getsockopt calls */
+
+/* These defines are compatible with NRL IPv6, however their semantics
+ is different */
+
+#define IPSEC_LEVEL_NONE -1 /* send plaintext, accept any */
+#define IPSEC_LEVEL_DEFAULT 0 /* encrypt/authenticate if possible */
+ /* the default MUST be 0, because a */
+ /* socket is initialized with 0's */
+#define IPSEC_LEVEL_USE 1 /* use outbound, don't require inbound */
+#define IPSEC_LEVEL_REQUIRE 2 /* require both directions */
+#define IPSEC_LEVEL_UNIQUE 2 /* for compatibility only */
+
+#ifdef __KERNEL__
+
+/* skb bit flags set on packet input processing */
+
+#define RCV_SEC 0x0f /* options on receive */
+#define RCV_AUTH 0x01 /* was authenticated */
+#define RCV_CRYPT 0x02 /* was encrypted */
+#define RCV_TUNNEL 0x04 /* was tunneled */
+#define SND_SEC 0xf0 /* options on send, these are */
+#define SND_AUTH 0x10 /* currently unused */
+#define SND_CRYPT 0x20
+#define SND_TUNNEL 0x40
+
+/*
+ * FIXME: ignores network encryption for now..
+ */
+
+#ifdef CONFIG_NET_SECURITY
+extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+{
+ return ((sk->authentication < IPSEC_LEVEL_REQUIRE) ||
+ (skb->security & RCV_AUTH)) &&
+ ((sk->encryption < IPSEC_LEVEL_REQUIRE) ||
+ (skb->security & RCV_CRYPT));
+}
+
+#else
+
+extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+{
+ return 1;
+}
+#endif /* CONFIG */
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_IPSEC_H */
diff --git a/pfinet/linux-src/include/linux/ipv6.h b/pfinet/linux-src/include/linux/ipv6.h
new file mode 100644
index 00000000..84564bae
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ipv6.h
@@ -0,0 +1,123 @@
+#ifndef _IPV6_H
+#define _IPV6_H
+
+#include <linux/in6.h>
+#include <asm/byteorder.h>
+
+/* The latest drafts declared increase in minimal mtu up to 1280. */
+
+#define IPV6_MIN_MTU 1280
+
+/*
+ * Advanced API
+ * source interface/address selection, source routing, etc...
+ * *under construction*
+ */
+
+
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr;
+ int ipi6_ifindex;
+};
+
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ __u32 ifr6_prefixlen;
+ int ifr6_ifindex;
+};
+
+#define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */
+#define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */
+
+/*
+ * routing header
+ */
+struct ipv6_rt_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ __u8 type;
+ __u8 segments_left;
+
+ /*
+ * type specific data
+ * variable length field
+ */
+};
+
+
+struct ipv6_opt_hdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ /*
+ * TLV encoded option data follows.
+ */
+};
+
+#define ipv6_destopt_hdr ipv6_opt_hdr
+#define ipv6_hopopt_hdr ipv6_opt_hdr
+
+#ifdef __KERNEL__
+#define ipv6_optlen(p) (((p)->hdrlen+1) << 3)
+#endif
+
+/*
+ * routing header type 0 (used in cmsghdr struct)
+ */
+
+struct rt0_hdr {
+ struct ipv6_rt_hdr rt_hdr;
+ __u32 bitmap; /* strict/loose bit map */
+ struct in6_addr addr[0];
+
+#define rt0_type rt_hdr.type;
+};
+
+/*
+ * IPv6 fixed header
+ *
+ * BEWARE, it is incorrect. The first 4 bits of flow_lbl
+ * are glued to priority now, forming "class".
+ */
+
+struct ipv6hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 priority:4,
+ version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u8 version:4,
+ priority:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u8 flow_lbl[3];
+
+ __u16 payload_len;
+ __u8 nexthdr;
+ __u8 hop_limit;
+
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+};
+
+#ifdef __KERNEL__
+
+/*
+ This structure contains results of exthdrs parsing
+ as offsets from skb->nh.
+ */
+
+struct inet6_skb_parm
+{
+ int iif;
+ __u16 ra;
+ __u16 hop;
+ __u16 auth;
+ __u16 dst0;
+ __u16 srcrt;
+ __u16 dst1;
+};
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/ipv6_route.h b/pfinet/linux-src/include/linux/ipv6_route.h
new file mode 100644
index 00000000..a4861d05
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ipv6_route.h
@@ -0,0 +1,56 @@
+/*
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IPV6_ROUTE_H
+#define _LINUX_IPV6_ROUTE_H
+
+enum
+{
+ RTA_IPV6_UNSPEC,
+ RTA_IPV6_HOPLIMIT,
+};
+
+#define RTA_IPV6_MAX RTA_IPV6_HOPLIMIT
+
+
+#define RTF_DEFAULT 0x00010000 /* default - learned via ND */
+#define RTF_ALLONLINK 0x00020000 /* fallback, no routers on link */
+#define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */
+
+#define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */
+#define RTF_EXPIRES 0x00400000
+
+#define RTF_CACHE 0x01000000 /* cache entry */
+#define RTF_FLOW 0x02000000 /* flow significant route */
+#define RTF_POLICY 0x04000000 /* policy route */
+
+#define RTF_LOCAL 0x80000000
+
+struct in6_rtmsg {
+ struct in6_addr rtmsg_dst;
+ struct in6_addr rtmsg_src;
+ struct in6_addr rtmsg_gateway;
+ __u32 rtmsg_type;
+ __u16 rtmsg_dst_len;
+ __u16 rtmsg_src_len;
+ __u32 rtmsg_metric;
+ unsigned long rtmsg_info;
+ __u32 rtmsg_flags;
+ int rtmsg_ifindex;
+};
+
+#define RTMSG_NEWDEVICE 0x11
+#define RTMSG_DELDEVICE 0x12
+#define RTMSG_NEWROUTE 0x21
+#define RTMSG_DELROUTE 0x22
+
+#endif
diff --git a/pfinet/linux/ipx.h b/pfinet/linux-src/include/linux/ipx.h
index d3bff83b..8b9d6bb1 100644
--- a/pfinet/linux/ipx.h
+++ b/pfinet/linux-src/include/linux/ipx.h
@@ -1,16 +1,17 @@
#ifndef _IPX_H_
#define _IPX_H_
#include <linux/sockios.h>
+#include <linux/socket.h>
#define IPX_NODE_LEN 6
#define IPX_MTU 576
struct sockaddr_ipx
{
- short sipx_family;
- short sipx_port;
- unsigned long sipx_network;
- unsigned char sipx_node[IPX_NODE_LEN];
- unsigned char sipx_type;
+ sa_family_t sipx_family;
+ __u16 sipx_port;
+ __u32 sipx_network;
+ unsigned char sipx_node[IPX_NODE_LEN];
+ __u8 sipx_type;
unsigned char sipx_zero; /* 16 byte fill */
};
@@ -25,14 +26,14 @@ struct sockaddr_ipx
typedef struct ipx_route_definition
{
- unsigned long ipx_network;
- unsigned long ipx_router_network;
+ __u32 ipx_network;
+ __u32 ipx_router_network;
unsigned char ipx_router_node[IPX_NODE_LEN];
} ipx_route_definition;
typedef struct ipx_interface_definition
{
- unsigned long ipx_network;
+ __u32 ipx_network;
unsigned char ipx_device[16];
unsigned char ipx_dlink_type;
#define IPX_FRAME_NONE 0
@@ -40,6 +41,7 @@ typedef struct ipx_interface_definition
#define IPX_FRAME_8022 2
#define IPX_FRAME_ETHERII 3
#define IPX_FRAME_8023 4
+#define IPX_FRAME_TR_8022 5 /* obsolete */
unsigned char ipx_special;
#define IPX_SPECIAL_NONE 0
#define IPX_PRIMARY 1
@@ -59,8 +61,8 @@ typedef struct ipx_config_data
struct ipx_route_def
{
- unsigned long ipx_network;
- unsigned long ipx_router_network;
+ __u32 ipx_network;
+ __u32 ipx_router_network;
#define IPX_ROUTE_NO_ROUTER 0
unsigned char ipx_router_node[IPX_NODE_LEN];
unsigned char ipx_device[16];
@@ -74,5 +76,14 @@ struct ipx_route_def
#define SIOCAIPXITFCRT (SIOCPROTOPRIVATE)
#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE+1)
#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE+2)
-#endif
+#define SIOCIPXNCPCONN (SIOCPROTOPRIVATE+3)
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+extern int ipxrtr_route_skb(struct sk_buff *);
+extern int ipx_if_offset(unsigned long ipx_net_number);
+extern void ipx_remove_socket(struct sock *sk);
+#endif /* def __KERNEL__ */
+
+#endif /* def _IPX_H_ */
diff --git a/pfinet/linux-src/include/linux/irda.h b/pfinet/linux-src/include/linux/irda.h
new file mode 100644
index 00000000..275d82fc
--- /dev/null
+++ b/pfinet/linux-src/include/linux/irda.h
@@ -0,0 +1,120 @@
+/*********************************************************************
+ *
+ * Filename: irda.h
+ * Version:
+ * Description:
+ * Status: Experimental.
+ * Author: Dag Brattli <dagb@cs.uit.no>
+ * Created at: Mon Mar 8 14:06:12 1999
+ * Modified at: Mon Mar 22 14:14:54 1999
+ * Modified by: Dag Brattli <dagb@cs.uit.no>
+ *
+ * Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * provide warranty for any of this software. This material is
+ * provided "AS-IS" and at no charge.
+ *
+ ********************************************************************/
+
+#ifndef KERNEL_IRDA_H
+#define KERNEL_IRDA_H
+
+/* Hint bit positions for first hint byte */
+#define HINT_PNP 0x01
+#define HINT_PDA 0x02
+#define HINT_COMPUTER 0x04
+#define HINT_PRINTER 0x08
+#define HINT_MODEM 0x10
+#define HINT_FAX 0x20
+#define HINT_LAN 0x40
+#define HINT_EXTENSION 0x80
+
+/* Hint bit positions for second hint byte (first extension byte) */
+#define HINT_TELEPHONY 0x01
+#define HINT_FILE_SERVER 0x02
+#define HINT_COMM 0x04
+#define HINT_MESSAGE 0x08
+#define HINT_HTTP 0x10
+#define HINT_OBEX 0x20
+
+/* IrLMP character code values */
+#define CS_ASCII 0x00
+#define CS_ISO_8859_1 0x01
+#define CS_ISO_8859_2 0x02
+#define CS_ISO_8859_3 0x03
+#define CS_ISO_8859_4 0x04
+#define CS_ISO_8859_5 0x05
+#define CS_ISO_8859_6 0x06
+#define CS_ISO_8859_7 0x07
+#define CS_ISO_8859_8 0x08
+#define CS_ISO_8859_9 0x09
+#define CS_UNICODE 0xff
+
+#define SOL_IRLMP 266 /* Same as SOL_IRDA for now */
+#define SOL_IRTTP 266 /* Same as SOL_IRDA for now */
+
+#define IRLMP_ENUMDEVICES 1
+#define IRLMP_IAS_SET 2
+#define IRLMP_IAS_QUERY 3
+#define IRLMP_DISCOVERY_MASK_SET 4
+
+#define IRTTP_QOS_SET 5
+#define IRTTP_QOS_GET 6
+#define IRTTP_MAX_SDU_SIZE 7
+
+#define IAS_MAX_STRING 256
+#define IAS_MAX_OCTET_STRING 1024
+#define IAS_MAX_CLASSNAME 64
+#define IAS_MAX_ATTRIBNAME 256
+
+#define LSAP_ANY 0xff
+
+struct sockaddr_irda {
+ sa_family_t sir_family; /* AF_IRDA */
+ unsigned char sir_lsap_sel; /* LSAP/TSAP selector */
+ unsigned int sir_addr; /* Device address */
+ char sir_name[25]; /* Usually <service>:IrDA:TinyTP */
+};
+
+struct irda_device_info {
+ unsigned int saddr; /* Address of remote device */
+ unsigned int daddr; /* Link where it was discovered */
+ char info[22]; /* Description */
+ unsigned char charset; /* Charset used for description */
+ unsigned char hints[2]; /* Hint bits */
+};
+
+struct irda_device_list {
+ unsigned int len;
+ struct irda_device_info dev[0];
+};
+
+struct irda_ias_set {
+ char irda_class_name[IAS_MAX_CLASSNAME];
+ char irda_attrib_name[IAS_MAX_ATTRIBNAME];
+ unsigned int irda_attrib_type;
+ union {
+ unsigned int irda_attrib_int;
+ struct {
+ unsigned short len;
+ u_char OctetSeq[IAS_MAX_OCTET_STRING];
+ } irda_attrib_octet_seq;
+ struct {
+ unsigned char len;
+ unsigned char charset;
+ unsigned char string[IAS_MAX_STRING];
+ } irda_attrib_string;
+ } attribute;
+};
+
+#endif /* KERNEL_IRDA_H */
+
+
+
+
diff --git a/pfinet/linux-src/include/linux/isdn.h b/pfinet/linux-src/include/linux/isdn.h
new file mode 100644
index 00000000..742fe14b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/isdn.h
@@ -0,0 +1,936 @@
+/* $Id: isdn.h,v 1.81 1999/10/27 21:21:18 detabc Exp $
+ *
+ * Main header for the Linux ISDN subsystem (linklevel).
+ *
+ * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ *
+ * 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.
+ *
+ * $Log: isdn.h,v $
+ * Revision 1.81 1999/10/27 21:21:18 detabc
+ * Added support for building logically-bind-group's per interface.
+ * useful for outgoing call's with more then one isdn-card.
+ *
+ * Switchable support to dont reset the hangup-timeout for
+ * receive frames. Most part's of the timru-rules for receiving frames
+ * are now obsolete. If the input- or forwarding-firewall deny
+ * the frame, the line will be not hold open.
+ *
+ * Revision 1.80 1999/10/26 21:09:29 armin
+ * New bufferlen for phonenumber only with kernel 2.3.x
+ *
+ * Revision 1.79 1999/10/16 17:52:38 keil
+ * Changing the MSN length need new data versions
+ *
+ * Revision 1.78 1999/10/08 18:59:33 armin
+ * Bugfix of too small MSN buffer and checking phone number
+ * in isdn_tty_getdial()
+ *
+ * Revision 1.77 1999/09/23 22:22:42 detabc
+ * added tcp-keepalive-detect with local response (ipv4 only)
+ * added host-only-interface support
+ * (source ipaddr == interface ipaddr) (ipv4 only)
+ * ok with kernel 2.3.18 and 2.2.12
+ *
+ * Revision 1.76 1999/09/14 10:16:21 keil
+ * change ABC include
+ *
+ * Revision 1.75 1999/09/13 23:25:17 he
+ * serialized xmitting frames from isdn_ppp and BSENT statcallb
+ *
+ * Revision 1.74 1999/09/12 16:19:39 detabc
+ * added abc features
+ * low cost routing for net-interfaces (only the HL side).
+ * need more implementation in the isdnlog-utility
+ * udp info support (first part).
+ * different EAZ on outgoing call's.
+ * more checks on D-Channel callbacks (double use of channels).
+ * tested and running with kernel 2.3.17
+ *
+ * Revision 1.73 1999/09/06 07:29:36 fritz
+ * Changed my mail-address.
+ *
+ * Revision 1.72 1999/09/04 22:20:19 detabc
+ *
+ * Revision 1.71 1999/08/23 15:54:22 keil
+ * more backported changes from kernel 2.3.14
+ *
+ * Revision 1.70 1999/07/31 12:59:58 armin
+ * Added tty fax capabilities.
+ *
+ * Revision 1.69 1999/07/13 20:47:53 werner
+ * added channel bit ISDN_USAGE_DISABLED for limiting b-channel access.
+ *
+ * Revision 1.68 1999/07/11 17:07:37 armin
+ * Added tty modem register S23.
+ * Added new layer 2 and 3 protocols for Fax and DSP functions.
+ *
+ * Revision 1.67 1999/07/07 10:17:24 detabc
+ * remove unused messages
+ *
+ * Revision 1.66 1999/07/01 08:35:37 keil
+ * compatibility to 2.3
+ *
+ * Revision 1.65 1999/06/10 11:51:27 paul
+ * fixed comment for NET_DV
+ *
+ * Revision 1.64 1999/04/18 14:57:14 fritz
+ * Removed TIMRU stuff
+ *
+ * Revision 1.63 1999/04/18 14:07:18 fritz
+ * Removed TIMRU stuff.
+ *
+ * Revision 1.62 1999/04/12 13:16:54 fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.61 1999/03/02 11:43:21 armin
+ * Added variable to store connect-message of Modem.
+ * Added Timer-define for RegS7 (Wait for Carrier).
+ *
+ * Revision 1.60 1998/10/25 14:50:29 fritz
+ * Backported from MIPS (Cobalt).
+ *
+ * Revision 1.59 1998/10/23 10:18:55 paul
+ * Implementation of "dialmode" (successor of "status")
+ * You also need current isdnctrl for this!
+ *
+ * Revision 1.58 1998/10/23 10:10:06 fritz
+ * Test-Checkin
+ *
+ * Revision 1.57 1998/08/31 21:10:01 he
+ * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface'
+ * peer phone number)
+ *
+ * Revision 1.56 1998/07/26 18:46:52 armin
+ * Added silence detection in voice receive mode.
+ *
+ * Revision 1.55 1998/06/26 15:13:17 fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.54 1998/06/18 23:32:01 fritz
+ * Replaced cli()/restore_flags() in isdn_tty_write() by locking.
+ * Removed direct-senddown feature in isdn_tty_write because it will
+ * never succeed with locking and is useless anyway.
+ *
+ * Revision 1.53 1998/06/17 19:51:51 he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.46 1998/04/14 16:28:59 he
+ * Fixed user space access with interrupts off and remaining
+ * copy_{to,from}_user() -> -EFAULT return codes
+ *
+ * Revision 1.45 1998/03/24 16:33:12 hipp
+ * More CCP changes. BSD compression now "works" on a local loopback link.
+ * Moved some isdn_ppp stuff from isdn.h to isdn_ppp.h
+ *
+ * Revision 1.44 1998/03/22 18:50:56 hipp
+ * Added BSD Compression for syncPPP .. UNTESTED at the moment
+ *
+ * Revision 1.43 1998/03/09 17:46:44 he
+ * merged in 2.1.89 changes
+ *
+ *
+ * Revision 1.40 1998/03/08 01:08:29 fritz
+ * Increased NET_DV because of TIMRU
+ *
+ * Revision 1.39 1998/03/07 22:42:49 fritz
+ * Starting generic module support (Nothing usable yet).
+ *
+ * Revision 1.38 1998/03/07 18:21:29 cal
+ * Dynamic Timeout-Rule-Handling vs. 971110 included
+ *
+ * Revision 1.37 1998/02/22 19:45:24 fritz
+ * Some changes regarding V.110
+ *
+ * Revision 1.36 1998/02/20 17:35:55 fritz
+ * Added V.110 stuff.
+ *
+ * Revision 1.35 1998/01/31 22:14:14 keil
+ * changes for 2.1.82
+ *
+ * Revision 1.34 1997/10/09 21:28:11 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.33 1997/08/21 14:44:22 fritz
+ * Moved triggercps to end of struct for backwards-compatibility.
+ *
+ * Revision 1.32 1997/08/21 09:49:46 fritz
+ * Increased NET_DV
+ *
+ * Revision 1.31 1997/06/22 11:57:07 fritz
+ * Added ability to adjust slave triggerlevel.
+ *
+ * Revision 1.30 1997/06/17 13:07:23 hipp
+ * compression changes , MP changes
+ *
+ * Revision 1.29 1997/05/27 15:18:02 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where appropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.28 1997/03/07 01:33:01 fritz
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.27 1997/03/05 21:11:49 fritz
+ * Minor fixes.
+ *
+ * Revision 1.26 1997/02/28 02:37:53 fritz
+ * Added some comments.
+ *
+ * Revision 1.25 1997/02/23 16:54:23 hipp
+ * some initial changes for future PPP compresion
+ *
+ * Revision 1.24 1997/02/18 09:42:45 fritz
+ * Bugfix: Increased ISDN_MODEM_ANZREG.
+ * Increased TTY_DV.
+ *
+ * Revision 1.23 1997/02/10 22:07:13 fritz
+ * Added 2 modem registers for numbering plan and screening info.
+ *
+ * Revision 1.22 1997/02/03 23:42:08 fritz
+ * Added ISDN_TIMER_RINGING
+ * Misc. changes for Kernel 2.1.X compatibility
+ *
+ * Revision 1.21 1997/01/17 01:19:10 fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.20 1997/01/17 00:41:19 fritz
+ * Increased TTY_DV.
+ *
+ * Revision 1.19 1997/01/14 01:41:07 fritz
+ * Added ATI2 related variables.
+ * Added variables for audio support in skbuffs.
+ *
+ * Revision 1.18 1996/11/06 17:37:50 keil
+ * more changes for 2.1.X
+ *
+ * Revision 1.17 1996/09/07 12:53:57 hipp
+ * moved a few isdn_ppp.c specific defines to drives/isdn/isdn_ppp.h
+ *
+ * Revision 1.16 1996/08/12 16:20:56 hipp
+ * renamed ppp_minor to ppp_slot
+ *
+ * Revision 1.15 1996/06/15 14:56:57 fritz
+ * Added version signatures for data structures used
+ * by userlevel programs.
+ *
+ * Revision 1.14 1996/06/06 21:24:23 fritz
+ * Started adding support for suspend/resume.
+ *
+ * Revision 1.13 1996/06/05 02:18:20 fritz
+ * Added DTMF decoding stuff.
+ *
+ * Revision 1.12 1996/06/03 19:55:08 fritz
+ * Fixed typos.
+ *
+ * Revision 1.11 1996/05/31 01:37:47 fritz
+ * Minor changes, due to changes in isdn_tty.c
+ *
+ * Revision 1.10 1996/05/18 01:37:18 fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.9 1996/05/17 03:58:20 fritz
+ * Added flags for DLE handling.
+ *
+ * Revision 1.8 1996/05/11 21:49:55 fritz
+ * Removed queue management variables.
+ * Changed queue management to use sk_buffs.
+ *
+ * Revision 1.7 1996/05/07 09:10:06 fritz
+ * Reorganized tty-related structs.
+ *
+ * Revision 1.6 1996/05/06 11:38:27 hipp
+ * minor change in ippp struct
+ *
+ * Revision 1.5 1996/04/30 11:03:16 fritz
+ * Added Michael's ippp-bind patch.
+ *
+ * Revision 1.4 1996/04/29 23:00:02 fritz
+ * Added variables for voice-support.
+ *
+ * Revision 1.3 1996/04/20 16:54:58 fritz
+ * Increased maximum number of channels.
+ * Added some flags for isdn_net to handle callback more reliable.
+ * Fixed delay-definitions to be more accurate.
+ * Misc. typos
+ *
+ * Revision 1.2 1996/02/11 02:10:02 fritz
+ * Changed IOCTL-names
+ * Added rx_netdev, st_netdev, first_skb, org_hcb, and org_hcu to
+ * Netdevice-local struct.
+ *
+ * Revision 1.1 1996/01/10 20:55:07 fritz
+ * Initial revision
+ *
+ */
+
+#ifndef isdn_h
+#define isdn_h
+
+#include <linux/config.h>
+#include <linux/ioctl.h>
+
+#define ISDN_TTY_MAJOR 43
+#define ISDN_TTYAUX_MAJOR 44
+#define ISDN_MAJOR 45
+
+/* The minor-devicenumbers for Channel 0 and 1 are used as arguments for
+ * physical Channel-Mapping, so they MUST NOT be changed without changing
+ * the correspondent code in isdn.c
+ */
+
+#ifdef CONFIG_COBALT_MICRO_SERVER
+/* Save memory */
+#define ISDN_MAX_DRIVERS 2
+#define ISDN_MAX_CHANNELS 8
+#else
+#define ISDN_MAX_DRIVERS 32
+#define ISDN_MAX_CHANNELS 64
+#endif
+#define ISDN_MINOR_B 0
+#define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1)
+#define ISDN_MINOR_CTRL 64
+#define ISDN_MINOR_CTRLMAX (64 + (ISDN_MAX_CHANNELS-1))
+#define ISDN_MINOR_PPP 128
+#define ISDN_MINOR_PPPMAX (128 + (ISDN_MAX_CHANNELS-1))
+#define ISDN_MINOR_STATUS 255
+
+#undef CONFIG_ISDN_WITH_ABC_CALLB
+#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK
+#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
+#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
+#undef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
+#undef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
+#undef CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
+#undef CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
+#undef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
+#undef CONFIG_ISDN_WITH_ABC_ICALL_BIND
+
+
+/* New ioctl-codes */
+#define IIOCNETAIF _IO('I',1)
+#define IIOCNETDIF _IO('I',2)
+#define IIOCNETSCF _IO('I',3)
+#define IIOCNETGCF _IO('I',4)
+#define IIOCNETANM _IO('I',5)
+#define IIOCNETDNM _IO('I',6)
+#define IIOCNETGNM _IO('I',7)
+#define IIOCGETSET _IO('I',8) /* no longer supported */
+#define IIOCSETSET _IO('I',9) /* no longer supported */
+#define IIOCSETVER _IO('I',10)
+#define IIOCNETHUP _IO('I',11)
+#define IIOCSETGST _IO('I',12)
+#define IIOCSETBRJ _IO('I',13)
+#define IIOCSIGPRF _IO('I',14)
+#define IIOCGETPRF _IO('I',15)
+#define IIOCSETPRF _IO('I',16)
+#define IIOCGETMAP _IO('I',17)
+#define IIOCSETMAP _IO('I',18)
+#define IIOCNETASL _IO('I',19)
+#define IIOCNETDIL _IO('I',20)
+#define IIOCGETCPS _IO('I',21)
+#define IIOCGETDVR _IO('I',22)
+#define IIOCNETLCR _IO('I',23) /* dwabc ioctl for LCR from isdnlog */
+
+#define IIOCNETALN _IO('I',32)
+#define IIOCNETDLN _IO('I',33)
+
+#define IIOCNETGPN _IO('I',34)
+
+#define IIOCDBGVAR _IO('I',127)
+
+#define IIOCDRVCTL _IO('I',128)
+
+/* Packet encapsulations for net-interfaces */
+#define ISDN_NET_ENCAP_ETHER 0
+#define ISDN_NET_ENCAP_RAWIP 1
+#define ISDN_NET_ENCAP_IPTYP 2
+#define ISDN_NET_ENCAP_CISCOHDLC 3 /* Without SLARP and keepalive */
+#define ISDN_NET_ENCAP_SYNCPPP 4
+#define ISDN_NET_ENCAP_UIHDLC 5
+#define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive */
+#define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt*/
+#define ISDN_NET_ENCAP_MAX_ENCAP ISDN_NET_ENCAP_X25IFACE
+/* Facility which currently uses an ISDN-channel */
+#define ISDN_USAGE_NONE 0
+#define ISDN_USAGE_RAW 1
+#define ISDN_USAGE_MODEM 2
+#define ISDN_USAGE_NET 3
+#define ISDN_USAGE_VOICE 4
+#define ISDN_USAGE_FAX 5
+#define ISDN_USAGE_MASK 7 /* Mask to get plain usage */
+#define ISDN_USAGE_DISABLED 32 /* This bit is set, if channel is disabled */
+#define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */
+#define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing */
+
+#define ISDN_MODEM_ANZREG 24 /* Number of Modem-Registers */
+#define ISDN_LMSNLEN 255 /* Length of tty's Listen-MSN string */
+#define ISDN_CMSGLEN 50 /* Length of CONNECT-Message to add for Modem */
+
+#define ISDN_MSNLEN 20
+#define NET_DV 0x05 /* Data version for isdn_net_ioctl_cfg */
+#define TTY_DV 0x05 /* Data version for iprofd etc. */
+
+#define INF_DV 0x01 /* Data version for /dev/isdninfo */
+
+typedef struct {
+ char drvid[25];
+ unsigned long arg;
+} isdn_ioctl_struct;
+
+typedef struct {
+ unsigned long isdndev;
+ unsigned long atmodem[ISDN_MAX_CHANNELS];
+ unsigned long info[ISDN_MAX_CHANNELS];
+} debugvar_addr;
+
+typedef struct {
+ char name[10];
+ char phone[ISDN_MSNLEN];
+ int outgoing;
+} isdn_net_ioctl_phone;
+
+typedef struct {
+ char name[10]; /* Name of interface */
+ char master[10]; /* Name of Master for Bundling */
+ char slave[10]; /* Name of Slave for Bundling */
+ char eaz[256]; /* EAZ/MSN */
+ char drvid[25]; /* DriverId for Bindings */
+ int onhtime; /* Hangup-Timeout */
+ int charge; /* Charge-Units */
+ int l2_proto; /* Layer-2 protocol */
+ int l3_proto; /* Layer-3 protocol */
+ int p_encap; /* Encapsulation */
+ int exclusive; /* Channel, if bound exclusive */
+ int dialmax; /* Dial Retry-Counter */
+ int slavedelay; /* Delay until slave starts up */
+ int cbdelay; /* Delay before Callback */
+ int chargehup; /* Flag: Charge-Hangup */
+ int ihup; /* Flag: Hangup-Timeout on incoming line */
+ int secure; /* Flag: Secure */
+ int callback; /* Flag: Callback */
+ int cbhup; /* Flag: Reject Call before Callback */
+ int pppbind; /* ippp device for bindings */
+ int chargeint; /* Use fixed charge interval length */
+ int triggercps; /* BogoCPS needed for triggering slave */
+ int dialtimeout; /* Dial-Timeout */
+ int dialwait; /* Time to wait after failed dial */
+ int dialmode; /* Flag: off / on / auto */
+} isdn_net_ioctl_cfg;
+
+#define ISDN_NET_DIALMODE_MASK 0xC0 /* bits for status */
+#define ISDN_NET_DM_OFF 0x00 /* this interface is stopped */
+#define ISDN_NET_DM_MANUAL 0x40 /* this interface is on (manual) */
+#define ISDN_NET_DM_AUTO 0x80 /* this interface is autodial */
+#define ISDN_NET_DIALMODE(x) ((&(x))->flags & ISDN_NET_DIALMODE_MASK)
+
+#ifdef __KERNEL__
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/fcntl.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+
+#ifdef CONFIG_ISDN_PPP
+
+#ifdef CONFIG_ISDN_PPP_VJ
+# include <net/slhc_vj.h>
+#endif
+
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppvar.h>
+
+#include <linux/isdn_ppp.h>
+#endif
+
+#ifdef CONFIG_ISDN_X25
+# include <linux/concap.h>
+#endif
+
+#include <linux/isdnif.h>
+
+#define ISDN_DRVIOCTL_MASK 0x7f /* Mask for Device-ioctl */
+
+/* Until now unused */
+#define ISDN_SERVICE_VOICE 1
+#define ISDN_SERVICE_AB 1<<1
+#define ISDN_SERVICE_X21 1<<2
+#define ISDN_SERVICE_G4 1<<3
+#define ISDN_SERVICE_BTX 1<<4
+#define ISDN_SERVICE_DFUE 1<<5
+#define ISDN_SERVICE_X25 1<<6
+#define ISDN_SERVICE_TTX 1<<7
+#define ISDN_SERVICE_MIXED 1<<8
+#define ISDN_SERVICE_FW 1<<9
+#define ISDN_SERVICE_GTEL 1<<10
+#define ISDN_SERVICE_BTXN 1<<11
+#define ISDN_SERVICE_BTEL 1<<12
+
+/* Macros checking plain usage */
+#define USG_NONE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NONE)
+#define USG_RAW(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_RAW)
+#define USG_MODEM(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM)
+#define USG_VOICE(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE)
+#define USG_NET(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_NET)
+#define USG_FAX(x) ((x & ISDN_USAGE_MASK)==ISDN_USAGE_FAX)
+#define USG_OUTGOING(x) ((x & ISDN_USAGE_OUTGOING)==ISDN_USAGE_OUTGOING)
+#define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \
+ ((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) )
+
+/* Timer-delays and scheduling-flags */
+#define ISDN_TIMER_RES 3 /* Main Timer-Resolution */
+#define ISDN_TIMER_02SEC (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec */
+#define ISDN_TIMER_1SEC (HZ/(ISDN_TIMER_RES+1)) /* Slow-Timer2 1 sec */
+#define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */
+#define ISDN_TIMER_KEEPINT 10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */
+#define ISDN_TIMER_MODEMREAD 1
+#define ISDN_TIMER_MODEMPLUS 2
+#define ISDN_TIMER_MODEMRING 4
+#define ISDN_TIMER_MODEMXMIT 8
+#define ISDN_TIMER_NETDIAL 16
+#define ISDN_TIMER_NETHANGUP 32
+#define ISDN_TIMER_IPPP 64
+#define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */
+#define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */
+#define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
+ ISDN_TIMER_MODEMXMIT)
+#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
+ ISDN_TIMER_NETDIAL | ISDN_TIMER_KEEPALIVE | \
+ ISDN_TIMER_CARRIER)
+
+/* Timeout-Values for isdn_net_dial() */
+#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
+#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
+#define ISDN_TIMER_DTIMEOUT60 (60*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
+
+/* GLOBAL_FLAGS */
+#define ISDN_GLOBAL_STOPPED 1
+
+/*=================== Start of ip-over-ISDN stuff =========================*/
+
+/* Feature- and status-flags for a net-interface */
+#define ISDN_NET_CONNECTED 0x01 /* Bound to ISDN-Channel */
+#define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */
+#define ISDN_NET_CALLBACK 0x04 /* activate callback */
+#define ISDN_NET_CBHUP 0x08 /* hangup before callback */
+#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */
+
+#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */
+
+/* Phone-list-element */
+typedef struct {
+ void *next;
+ char num[ISDN_MSNLEN];
+} isdn_net_phone;
+
+/*
+ Principles when extending structures for generic encapsulation protocol
+ ("concap") support:
+ - Stuff which is hardware specific (here i4l-specific) goes in
+ the netdev -> local structure (here: isdn_net_local)
+ - Stuff which is encapsulation protocol specific goes in the structure
+ which holds the linux device structure (here: isdn_net_device)
+*/
+
+/* Local interface-data */
+typedef struct isdn_net_local_s {
+ ulong magic;
+ char name[10]; /* Name of device */
+ struct enet_statistics stats; /* Ethernet Statistics */
+ int isdn_device; /* Index to isdn-device */
+ int isdn_channel; /* Index to isdn-channel */
+ int ppp_slot; /* PPPD device slot number */
+ int pre_device; /* Preselected isdn-device */
+ int pre_channel; /* Preselected isdn-channel */
+ int exclusive; /* If non-zero idx to reserved chan.*/
+ int flags; /* Connection-flags */
+ int dialretry; /* Counter for Dialout-retries */
+ int dialmax; /* Max. Number of Dial-retries */
+ int cbdelay; /* Delay before Callback starts */
+ int dtimer; /* Timeout-counter for dialing */
+ char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
+ u_char cbhup; /* Flag: Reject Call before Callback*/
+ u_char dialstate; /* State for dialing */
+ u_char p_encap; /* Packet encapsulation */
+ /* 0 = Ethernet over ISDN */
+ /* 1 = RAW-IP */
+ /* 2 = IP with type field */
+ u_char l2_proto; /* Layer-2-protocol */
+ /* See ISDN_PROTO_L2..-constants in */
+ /* isdnif.h */
+ /* 0 = X75/LAPB with I-Frames */
+ /* 1 = X75/LAPB with UI-Frames */
+ /* 2 = X75/LAPB with BUI-Frames */
+ /* 3 = HDLC */
+ u_char l3_proto; /* Layer-3-protocol */
+ /* See ISDN_PROTO_L3..-constants in */
+ /* isdnif.h */
+ /* 0 = Transparent */
+ int huptimer; /* Timeout-counter for auto-hangup */
+ int charge; /* Counter for charging units */
+ int chargetime; /* Timer for Charging info */
+ int hupflags; /* Flags for charge-unit-hangup: */
+ /* bit0: chargeint is invalid */
+ /* bit1: Getting charge-interval */
+ /* bit2: Do charge-unit-hangup */
+ /* bit3: Do hangup even on incoming */
+ int outgoing; /* Flag: outgoing call */
+ int onhtime; /* Time to keep link up */
+ int chargeint; /* Interval between charge-infos */
+ int onum; /* Flag: at least 1 outgoing number */
+ int cps; /* current speed of this interface */
+ int transcount; /* byte-counter for cps-calculation */
+ int sqfull; /* Flag: netdev-queue overloaded */
+ ulong sqfull_stamp; /* Start-Time of overload */
+ ulong slavedelay; /* Dynamic bundling delaytime */
+ int triggercps; /* BogoCPS needed for trigger slave */
+ struct device *srobin; /* Ptr to Master device for slaves */
+ isdn_net_phone *phone[2]; /* List of remote-phonenumbers */
+ /* phone[0] = Incoming Numbers */
+ /* phone[1] = Outgoing Numbers */
+ isdn_net_phone *dial; /* Pointer to dialed number */
+ struct device *master; /* Ptr to Master device for slaves */
+ struct device *slave; /* Ptr to Slave device for masters */
+ struct isdn_net_local_s *next; /* Ptr to next link in bundle */
+ struct isdn_net_local_s *last; /* Ptr to last link in bundle */
+ struct isdn_net_dev_s *netdev; /* Ptr to netdev */
+ struct sk_buff *first_skb; /* Ptr to skb that triggers dialing */
+ struct sk_buff *volatile sav_skb; /* Ptr to skb, rejected by LL-driver*/
+ /* Ptr to orig. hard_header_cache */
+ int (*org_hhc)(
+ struct neighbour *neigh,
+ struct hh_cache *hh);
+ /* Ptr to orig. header_cache_update */
+ void (*org_hcu)(struct hh_cache *,
+ struct device *,
+ unsigned char *);
+ int pppbind; /* ippp device for bindings */
+ int dialtimeout; /* How long shall we try on dialing? (jiffies) */
+ int dialwait; /* How long shall we wait after failed attempt? (jiffies) */
+ ulong dialstarted; /* jiffies of first dialing-attempt */
+ ulong dialwait_timer; /* jiffies of earliest next dialing-attempt */
+ int huptimeout; /* How long will the connection be up? (seconds) */
+#ifdef CONFIG_ISDN_X25
+ struct concap_device_ops *dops; /* callbacks used by encapsulator */
+#endif
+ int cisco_loop; /* Loop counter for Cisco-SLARP */
+ ulong cisco_myseq; /* Local keepalive seq. for Cisco */
+ ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */
+} isdn_net_local;
+
+/* the interface itself */
+typedef struct isdn_net_dev_s {
+ isdn_net_local *local;
+ isdn_net_local *queue;
+ void *next; /* Pointer to next isdn-interface */
+ struct device dev; /* interface to upper levels */
+#ifdef CONFIG_ISDN_PPP
+ struct mpqueue *mp_last;
+ struct ippp_bundle ib;
+#endif
+#ifdef CONFIG_ISDN_X25
+ struct concap_proto *cprot; /* connection oriented encapsulation protocol */
+#endif
+
+} isdn_net_dev;
+
+/*===================== End of ip-over-ISDN stuff ===========================*/
+
+/*======================= Start of ISDN-tty stuff ===========================*/
+
+#define ISDN_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */
+#define ISDN_ASYNC_INITIALIZED 0x80000000 /* port was initialized */
+#define ISDN_ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device active */
+#define ISDN_ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device active */
+#define ISDN_ASYNC_CLOSING 0x08000000 /* Serial port is closing */
+#define ISDN_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ISDN_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+#define ISDN_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */
+#define ISDN_ASYNC_SESSION_LOCKOUT 0x0100 /* Lock cua opens on session */
+#define ISDN_ASYNC_PGRP_LOCKOUT 0x0200 /* Lock cua opens on pgrp */
+#define ISDN_ASYNC_CALLOUT_NOHUP 0x0400 /* No hangup for cui */
+#define ISDN_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */
+#define ISDN_SERIAL_XMIT_SIZE 1024 /* Default bufsize for write */
+#define ISDN_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */
+#define ISDN_SERIAL_TYPE_NORMAL 1
+#define ISDN_SERIAL_TYPE_CALLOUT 2
+
+#ifdef CONFIG_ISDN_AUDIO
+/* For using sk_buffs with audio we need some private variables
+ * within each sk_buff. For this purpose, we declare a struct here,
+ * and put it always at skb->head. A few macros help accessing the
+ * variables. Of course, we need to check skb_headroom prior to
+ * any access.
+ */
+typedef struct isdn_audio_skb {
+ unsigned short dle_count;
+ unsigned char lock;
+} isdn_audio_skb;
+
+#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdn_audio_skb*)skb->head)->dle_count)
+#define ISDN_AUDIO_SKB_LOCK(skb) (((isdn_audio_skb*)skb->head)->lock)
+#endif
+
+/* Private data of AT-command-interpreter */
+typedef struct atemu {
+ u_char profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */
+ u_char mdmreg[ISDN_MODEM_ANZREG]; /* Modem-Registers */
+ char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */
+ char msn[ISDN_MSNLEN]; /* EAZ/MSN */
+ char plmsn[ISDN_LMSNLEN]; /* Listening MSNs Profile 0 */
+ char lmsn[ISDN_LMSNLEN]; /* Listening MSNs */
+ char cpn[ISDN_MSNLEN]; /* CalledPartyNumber on incoming call */
+ char connmsg[ISDN_CMSGLEN]; /* CONNECT-Msg from HL-Driver */
+#ifdef CONFIG_ISDN_AUDIO
+ u_char vpar[10]; /* Voice-parameters */
+ int lastDLE; /* Flag for voice-coding: DLE seen */
+#endif
+ int mdmcmdl; /* Length of Modem-Commandbuffer */
+ int pluscount; /* Counter for +++ sequence */
+ int lastplus; /* Timestamp of last + */
+ int carrierwait; /* Seconds of carrier waiting */
+ char mdmcmd[255]; /* Modem-Commandbuffer */
+ unsigned int charge; /* Charge units of current connection */
+} atemu;
+
+/* Private data (similar to async_struct in <linux/serial.h>) */
+typedef struct modem_info {
+ int magic;
+ int flags; /* defined in tty.h */
+ int x_char; /* xon/xoff character */
+ int mcr; /* Modem control register */
+ int msr; /* Modem status register */
+ int lsr; /* Line status register */
+ int line;
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ int online; /* 1 = B-Channel is up, drop data */
+ /* 2 = B-Channel is up, deliver d.*/
+ int dialing; /* Dial in progress or ATA */
+ int rcvsched; /* Receive needs schedule */
+ int isdn_driver; /* Index to isdn-driver */
+ int isdn_channel; /* Index to isdn-channel */
+ int drv_index; /* Index to dev->usage */
+ int ncarrier; /* Flag: schedule NO CARRIER */
+ unsigned char last_cause[8]; /* Last cause message */
+ unsigned char last_num[ISDN_MSNLEN];
+ /* Last phone-number */
+ unsigned char last_l2; /* Last layer-2 protocol */
+ unsigned char last_si; /* Last service */
+ unsigned char last_lhup; /* Last hangup local? */
+ unsigned char last_dir; /* Last direction (in or out) */
+ struct timer_list nc_timer; /* Timer for delayed NO CARRIER */
+ int send_outstanding;/* # of outstanding send-requests */
+ int xmit_size; /* max. # of chars in xmit_buf */
+ int xmit_count; /* # of chars in xmit_buf */
+ unsigned char *xmit_buf; /* transmit buffer */
+ struct sk_buff_head xmit_queue; /* transmit queue */
+ atomic_t xmit_lock; /* Semaphore for isdn_tty_write */
+#ifdef CONFIG_ISDN_AUDIO
+ int vonline; /* Voice-channel status */
+ /* Bit 0 = recording */
+ /* Bit 1 = playback */
+ /* Bit 2 = playback, DLE-ETX seen */
+ struct sk_buff_head dtmf_queue; /* queue for dtmf results */
+ void *adpcms; /* state for adpcm decompression */
+ void *adpcmr; /* state for adpcm compression */
+ void *dtmf_state; /* state for dtmf decoder */
+ void *silence_state; /* state for silence detection */
+#endif
+#ifdef CONFIG_ISDN_TTY_FAX
+ struct T30_s *fax; /* T30 Fax Group 3 data/interface */
+ int faxonline; /* Fax-channel status */
+#endif
+ struct tty_struct *tty; /* Pointer to corresponding tty */
+ atemu emu; /* AT-emulator data */
+ struct termios normal_termios; /* For saving termios structs */
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct semaphore write_sem;
+} modem_info;
+
+#define ISDN_MODEM_WINSIZE 8
+
+/* Description of one ISDN-tty */
+typedef struct {
+ int refcount; /* Number of opens */
+ struct tty_driver tty_modem; /* tty-device */
+ struct tty_driver cua_modem; /* cua-device */
+ struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
+ struct termios *modem_termios[ISDN_MAX_CHANNELS];
+ struct termios *modem_termios_locked[ISDN_MAX_CHANNELS];
+ modem_info info[ISDN_MAX_CHANNELS]; /* Private data */
+} modem;
+
+/*======================= End of ISDN-tty stuff ============================*/
+
+/*======================== Start of V.110 stuff ============================*/
+#define V110_BUFSIZE 1024
+
+typedef struct {
+ int nbytes; /* 1 Matrixbyte -> nbytes in stream */
+ int nbits; /* Number of used bits in streambyte */
+ unsigned char key; /* Bitmask in stream eg. 11 (nbits=2) */
+ int decodelen; /* Amount of data in decodebuf */
+ int SyncInit; /* Number of sync frames to send */
+ unsigned char *OnlineFrame; /* Precalculated V110 idle frame */
+ unsigned char *OfflineFrame; /* Precalculated V110 sync Frame */
+ int framelen; /* Length of frames */
+ int skbuser; /* Number of unacked userdata skbs */
+ int skbidle; /* Number of unacked idle/sync skbs */
+ int introducer; /* Local vars for decoder */
+ int dbit;
+ unsigned char b;
+ int skbres; /* space to reserve in outgoing skb */
+ int maxsize; /* maxbufsize of lowlevel driver */
+ unsigned char *encodebuf; /* temporary buffer for encoding */
+ unsigned char decodebuf[V110_BUFSIZE]; /* incomplete V110 matrices */
+} isdn_v110_stream;
+
+/*========================= End of V.110 stuff =============================*/
+
+/*======================= Start of general stuff ===========================*/
+
+typedef struct {
+ char *next;
+ char *private;
+} infostruct;
+
+typedef struct isdn_module {
+ struct isdn_module *prev;
+ struct isdn_module *next;
+ char *name;
+ int (*get_free_channel)(int, int, int, int, int);
+ int (*free_channel)(int, int, int);
+ int (*status_callback)(isdn_ctrl *);
+ int (*command)(isdn_ctrl *);
+ int (*receive_callback)(int, int, struct sk_buff *);
+ int (*writebuf_skb)(int, int, int, struct sk_buff *);
+ int (*net_start_xmit)(struct sk_buff *, struct device *);
+ int (*net_receive)(struct device *, struct sk_buff *);
+ int (*net_open)(struct device *);
+ int (*net_close)(struct device *);
+ int priority;
+} isdn_module;
+
+#define DRV_FLAG_RUNNING 1
+#define DRV_FLAG_REJBUS 2
+#define DRV_FLAG_LOADED 4
+
+/* Description of hardware-level-driver */
+typedef struct {
+ ulong online; /* Channel-Online flags */
+ ulong flags; /* Misc driver Flags */
+ int locks; /* Number of locks for this driver */
+ int channels; /* Number of channels */
+ struct wait_queue *st_waitq; /* Wait-Queue for status-read's */
+ int maxbufsize; /* Maximum Buffersize supported */
+ unsigned long pktcount; /* Until now: unused */
+ int stavail; /* Chars avail on Status-device */
+ isdn_if *interface; /* Interface to driver */
+ int *rcverr; /* Error-counters for B-Ch.-receive */
+ int *rcvcount; /* Byte-counters for B-Ch.-receive */
+#ifdef CONFIG_ISDN_AUDIO
+ unsigned long DLEflag; /* Flags: Insert DLE at next read */
+#endif
+ struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */
+ struct wait_queue **rcv_waitq; /* Wait-Queues for B-Channel-Reads */
+ struct wait_queue **snd_waitq; /* Wait-Queue for B-Channel-Send's */
+ char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */
+} driver;
+
+/* Main driver-data */
+typedef struct isdn_devt {
+ unsigned short flags; /* Bitmapped Flags: */
+ /* */
+ int drivers; /* Current number of drivers */
+ int channels; /* Current number of channels */
+ int net_verbose; /* Verbose-Flag */
+ int modempoll; /* Flag: tty-read active */
+ int tflags; /* Timer-Flags: */
+ /* see ISDN_TIMER_..defines */
+ int global_flags;
+ infostruct *infochain; /* List of open info-devs. */
+ struct wait_queue *info_waitq; /* Wait-Queue for isdninfo */
+ struct timer_list timer; /* Misc.-function Timer */
+ int chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel */
+ int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */
+ int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */
+ char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
+ /* Remote number of active ch.*/
+ int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */
+ driver *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */
+ isdn_net_dev *netdev; /* Linked list of net-if's */
+ char drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID */
+ struct task_struct *profd; /* For iprofd */
+ modem mdm; /* tty-driver-data */
+ isdn_net_dev *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers */
+ isdn_net_dev *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers */
+ ulong ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes */
+ ulong obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes */
+ int v110emu[ISDN_MAX_CHANNELS];/* V.110 emulator-mode 0=none */
+ atomic_t v110use[ISDN_MAX_CHANNELS];/* Usage-Semaphore for stream */
+ isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */
+ struct semaphore sem; /* serialize list access*/
+ isdn_module *modules;
+} isdn_dev;
+
+extern isdn_dev *dev;
+
+
+
+/* Utility-Macros */
+#define MIN(a,b) ((a<b)?a:b)
+#define MAX(a,b) ((a>b)?a:b)
+#endif /* __KERNEL__ */
+#endif /* isdn_h */
diff --git a/pfinet/linux-src/include/linux/isdn_divertif.h b/pfinet/linux-src/include/linux/isdn_divertif.h
new file mode 100644
index 00000000..2892d021
--- /dev/null
+++ b/pfinet/linux-src/include/linux/isdn_divertif.h
@@ -0,0 +1,62 @@
+/*
+ * $Id: isdn_divertif.h,v 1.3 1999/07/05 20:22:00 werner Exp $
+ *
+ * Header for the diversion supplementary interface for i4l.
+ *
+ * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de)
+ *
+ * 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.
+ *
+ * $Log: isdn_divertif.h,v $
+ * Revision 1.3 1999/07/05 20:22:00 werner
+ * changes to use diversion sources for all kernel versions.
+ * removed static device, only proc filesystem used
+ *
+ * Revision 1.2 1999/07/04 21:38:38 werner
+ * ported from kernel version 2.0
+ *
+ *
+ */
+
+
+/***********************************************************/
+/* magic value is also used to control version information */
+/***********************************************************/
+#define DIVERT_IF_MAGIC 0x25873401
+#define DIVERT_CMD_REG 0x00 /* register command */
+#define DIVERT_CMD_REL 0x01 /* release command */
+#define DIVERT_NO_ERR 0x00 /* return value no error */
+#define DIVERT_CMD_ERR 0x01 /* invalid cmd */
+#define DIVERT_VER_ERR 0x02 /* magic/version invalid */
+#define DIVERT_REG_ERR 0x03 /* module already registered */
+#define DIVERT_REL_ERR 0x04 /* module not registered */
+#define DIVERT_REG_NAME isdn_register_divert
+
+/***************************************************************/
+/* structure exchanging data between isdn hl and divert module */
+/***************************************************************/
+typedef struct
+ { ulong if_magic; /* magic info and version */
+ int cmd; /* command */
+ int (*stat_callback)(isdn_ctrl *); /* supplied by divert module when calling */
+ int (*ll_cmd)(isdn_ctrl *); /* supplied by hl on return */
+ char * (*drv_to_name)(int); /* map a driver id to name, supplied by hl */
+ int (*name_to_drv)(char *); /* map a driver id to name, supplied by hl */
+ } isdn_divert_if;
+
+/*********************/
+/* function register */
+/*********************/
+extern int DIVERT_REG_NAME(isdn_divert_if *);
diff --git a/pfinet/linux-src/include/linux/isdn_ppp.h b/pfinet/linux-src/include/linux/isdn_ppp.h
new file mode 100644
index 00000000..e7682fb3
--- /dev/null
+++ b/pfinet/linux-src/include/linux/isdn_ppp.h
@@ -0,0 +1,236 @@
+/* -*- mode: c; c-basic-offset: 2 -*- */
+
+#ifndef _LINUX_ISDN_PPP_H
+#define _LINUX_ISDN_PPP_H
+
+#include <linux/config.h>
+
+#define CALLTYPE_INCOMING 0x1
+#define CALLTYPE_OUTGOING 0x2
+#define CALLTYPE_CALLBACK 0x4
+
+#define IPPP_VERSION "2.2.0"
+
+struct pppcallinfo
+{
+ int calltype;
+ unsigned char local_num[64];
+ unsigned char remote_num[64];
+ int charge_units;
+};
+
+#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
+#define PPPIOCBUNDLE _IOW('t',129,int)
+#define PPPIOCGMPFLAGS _IOR('t',130,int)
+#define PPPIOCSMPFLAGS _IOW('t',131,int)
+#define PPPIOCSMPMTU _IOW('t',132,int)
+#define PPPIOCSMPMRU _IOW('t',133,int)
+#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long [8])
+#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
+#define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] )
+
+#define PPP_MP 0x003d
+#define PPP_LINK_COMP 0x00fb
+#define PPP_LINK_CCP 0x80fb
+
+#define SC_MP_PROT 0x00000200
+#define SC_REJ_MP_PROT 0x00000400
+#define SC_OUT_SHORT_SEQ 0x00000800
+#define SC_IN_SHORT_SEQ 0x00004000
+
+#define SC_DECOMP_ON 0x01
+#define SC_COMP_ON 0x02
+#define SC_DECOMP_DISCARD 0x04
+#define SC_COMP_DISCARD 0x08
+#define SC_LINK_DECOMP_ON 0x10
+#define SC_LINK_COMP_ON 0x20
+#define SC_LINK_DECOMP_DISCARD 0x40
+#define SC_LINK_COMP_DISCARD 0x80
+
+#define DECOMP_ERR_NOMEM (-10)
+
+#define MP_END_FRAG 0x40
+#define MP_BEGIN_FRAG 0x80
+
+#define ISDN_PPP_COMP_MAX_OPTIONS 16
+
+#define IPPP_COMP_FLAG_XMIT 0x1
+#define IPPP_COMP_FLAG_LINK 0x2
+
+struct isdn_ppp_comp_data {
+ int num;
+ unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS];
+ int optlen;
+ int flags;
+};
+
+#ifdef __KERNEL__
+
+/*
+ * We need a way for the decompressor to influence the generation of CCP
+ * Reset-Requests in a variety of ways. The decompressor is already returning
+ * a lot of information (generated skb length, error conditions) so we use
+ * another parameter. This parameter is a pointer to a structure which is
+ * to be marked valid by the decompressor and only in this case is ever used.
+ * Furthermore, the only case where this data is used is when the decom-
+ * pressor returns DECOMP_ERROR.
+ *
+ * We use this same struct for the reset entry of the compressor to commu-
+ * nicate to its caller how to deal with sending of a Reset Ack. In this
+ * case, expra is not used, but other options still apply (suppressing
+ * sending with rsend, appending arbitrary data, etc).
+ */
+
+#define IPPP_RESET_MAXDATABYTES 32
+
+struct isdn_ppp_resetparams {
+ unsigned char valid:1; /* rw Is this structure filled at all ? */
+ unsigned char rsend:1; /* rw Should we send one at all ? */
+ unsigned char idval:1; /* rw Is the id field valid ? */
+ unsigned char dtval:1; /* rw Is the data field valid ? */
+ unsigned char expra:1; /* rw Is an Ack expected for this Req ? */
+ unsigned char id; /* wo Send CCP ResetReq with this id */
+ unsigned short maxdlen; /* ro Max bytes to be stored in data field */
+ unsigned short dlen; /* rw Bytes stored in data field */
+ unsigned char *data; /* wo Data for ResetReq info field */
+};
+
+/*
+ * this is an 'old friend' from ppp-comp.h under a new name
+ * check the original include for more information
+ */
+struct isdn_ppp_compressor {
+ struct isdn_ppp_compressor *next, *prev;
+ int num; /* CCP compression protocol number */
+
+ void *(*alloc) (struct isdn_ppp_comp_data *);
+ void (*free) (void *state);
+ int (*init) (void *state, struct isdn_ppp_comp_data *,
+ int unit,int debug);
+
+ /* The reset entry needs to get more exact information about the
+ ResetReq or ResetAck it was called with. The parameters are
+ obvious. If reset is called without a Req or Ack frame which
+ could be handed into it, code MUST be set to 0. Using rsparm,
+ the reset entry can control if and how a ResetAck is returned. */
+
+ void (*reset) (void *state, unsigned char code, unsigned char id,
+ unsigned char *data, unsigned len,
+ struct isdn_ppp_resetparams *rsparm);
+
+ int (*compress) (void *state, struct sk_buff *in,
+ struct sk_buff *skb_out, int proto);
+
+ int (*decompress) (void *state,struct sk_buff *in,
+ struct sk_buff *skb_out,
+ struct isdn_ppp_resetparams *rsparm);
+
+ void (*incomp) (void *state, struct sk_buff *in,int proto);
+ void (*stat) (void *state, struct compstat *stats);
+};
+
+extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
+extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
+extern int isdn_ppp_dial_slave(char *);
+extern int isdn_ppp_hangup_slave(char *);
+
+struct ippp_bundle {
+ int mp_mrru; /* unused */
+ struct mpqueue *last; /* currently defined in isdn_net_dev */
+ int min; /* currently calculated 'on the fly' */
+ long next_num; /* we wanna see this seq.-number next */
+ struct sqqueue *sq;
+ int modify:1; /* set to 1 while modifying sqqueue */
+ int bundled:1; /* bundle active ? */
+};
+
+#define NUM_RCV_BUFFS 64
+
+struct sqqueue {
+ struct sqqueue *next;
+ long sqno_start;
+ long sqno_end;
+ struct sk_buff *skb;
+ long timer;
+};
+
+struct mpqueue {
+ struct mpqueue *next;
+ struct mpqueue *last;
+ long sqno;
+ struct sk_buff *skb;
+ int BEbyte;
+ unsigned long time;
+};
+
+struct ippp_buf_queue {
+ struct ippp_buf_queue *next;
+ struct ippp_buf_queue *last;
+ char *buf; /* NULL here indicates end of queue */
+ int len;
+};
+
+/* The data structure for one CCP reset transaction */
+enum ippp_ccp_reset_states {
+ CCPResetIdle,
+ CCPResetSentReq,
+ CCPResetRcvdReq,
+ CCPResetSentAck,
+ CCPResetRcvdAck
+};
+
+struct ippp_ccp_reset_state {
+ enum ippp_ccp_reset_states state; /* State of this transaction */
+ struct ippp_struct *is; /* Backlink to device stuff */
+ unsigned char id; /* Backlink id index */
+ unsigned char ta:1; /* The timer is active (flag) */
+ unsigned char expra:1; /* We expect a ResetAck at all */
+ int dlen; /* Databytes stored in data */
+ struct timer_list timer; /* For timeouts/retries */
+ /* This is a hack but seems sufficient for the moment. We do not want
+ to have this be yet another allocation for some bytes, it is more
+ memory management overhead than the whole mess is worth. */
+ unsigned char data[IPPP_RESET_MAXDATABYTES];
+};
+
+/* The data structure keeping track of the currently outstanding CCP Reset
+ transactions. */
+struct ippp_ccp_reset {
+ struct ippp_ccp_reset_state *rs[256]; /* One per possible id */
+ unsigned char lastid; /* Last id allocated by the engine */
+};
+
+struct ippp_struct {
+ struct ippp_struct *next_link;
+ int state;
+ struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
+ struct ippp_buf_queue *first; /* pointer to (current) first packet */
+ struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */
+ struct wait_queue *wq;
+ struct task_struct *tk;
+ unsigned int mpppcfg;
+ unsigned int pppcfg;
+ unsigned int mru;
+ unsigned int mpmru;
+ unsigned int mpmtu;
+ unsigned int maxcid;
+ struct isdn_net_local_s *lp;
+ int unit;
+ int minor;
+ long last_link_seqno;
+ long mp_seqno;
+ long range;
+#ifdef CONFIG_ISDN_PPP_VJ
+ unsigned char *cbuf;
+ struct slcompress *slcomp;
+#endif
+ unsigned long debug;
+ struct isdn_ppp_compressor *compressor,*decompressor;
+ struct isdn_ppp_compressor *link_compressor,*link_decompressor;
+ void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
+ struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */
+ unsigned long compflags;
+};
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_ISDN_PPP_H */
diff --git a/pfinet/linux-src/include/linux/isdnif.h b/pfinet/linux-src/include/linux/isdnif.h
new file mode 100644
index 00000000..7380b326
--- /dev/null
+++ b/pfinet/linux-src/include/linux/isdnif.h
@@ -0,0 +1,631 @@
+/* $Id: isdnif.h,v 1.32 1999/10/11 22:03:00 keil Exp $
+ *
+ * Linux ISDN subsystem
+ *
+ * Definition of the interface between the subsystem and its low-level drivers.
+ *
+ * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
+ *
+ * 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.
+ *
+ * $Log: isdnif.h,v $
+ * Revision 1.32 1999/10/11 22:03:00 keil
+ * COMPAT_NEED_UACCESS (no include in isdn_compat.h)
+ *
+ * Revision 1.31 1999/09/06 07:29:36 fritz
+ * Changed my mail-address.
+ *
+ * Revision 1.30 1999/08/23 15:54:29 keil
+ * more backported changes from kernel 2.3.14
+ *
+ * Revision 1.29 1999/07/31 13:00:02 armin
+ * Added tty fax capabilities.
+ *
+ * Revision 1.28 1999/07/13 20:57:48 werner
+ * added callback ISDN_STAT_DISCH for limiting b-channel resources.
+ *
+ * Revision 1.27 1999/07/11 17:07:39 armin
+ * Added tty modem register S23.
+ * Added new layer 2 and 3 protocols for Fax and DSP functions.
+ *
+ * Revision 1.26 1999/07/01 08:35:44 keil
+ * compatibility to 2.3
+ *
+ * Revision 1.25 1998/06/17 19:51:55 he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.24 1998/03/19 13:18:57 keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
+ * Revision 1.23 1998/02/20 17:36:52 fritz
+ * Added L2-protocols for V.110, changed FEATURE-Flag-constants.
+ *
+ * Revision 1.22 1998/01/31 22:14:12 keil
+ * changes for 2.1.82
+ *
+ * Revision 1.21 1997/10/09 21:28:13 fritz
+ * New HL<->LL interface:
+ * New BSENT callback with nr. of bytes included.
+ * Sending without ACK.
+ * New L1 error status (not yet in use).
+ * Cleaned up obsolete structures.
+ * Implemented Cisco-SLARP.
+ * Changed local net-interface data to be dynamically allocated.
+ * Removed old 2.0 compatibility stuff.
+ *
+ * Revision 1.20 1997/05/27 15:18:06 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where appropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.19 1997/03/25 23:13:56 keil
+ * NI-1 US protocol
+ *
+ * Revision 1.18 1997/03/04 22:09:18 calle
+ * Change macros copy_from_user and copy_to_user in inline function.
+ * These are now correct replacements of the functions for 2.1.xx
+ *
+ * Revision 1.17 1997/02/10 21:12:53 fritz
+ * More setup-interface changes.
+ *
+ * Revision 1.16 1997/02/10 19:42:57 fritz
+ * New interface for reporting incoming calls.
+ *
+ * Revision 1.15 1997/02/09 00:18:42 keil
+ * leased line support
+ *
+ * Revision 1.14 1997/02/03 23:43:00 fritz
+ * Misc changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.13 1996/11/13 02:39:59 fritz
+ * More compatibility changes.
+ *
+ * Revision 1.12 1996/11/06 17:38:48 keil
+ * more changes for 2.1.X
+ *
+ * Revision 1.11 1996/10/23 11:59:42 fritz
+ * More compatibility changes.
+ *
+ * Revision 1.10 1996/10/22 23:14:19 fritz
+ * Changes for compatibility to 2.0.X and 2.1.X kernels.
+ *
+ * Revision 1.9 1996/06/06 21:24:24 fritz
+ * Started adding support for suspend/resume.
+ *
+ * Revision 1.8 1996/05/18 01:45:37 fritz
+ * More spelling corrections.
+ *
+ * Revision 1.7 1996/05/18 01:37:19 fritz
+ * Added spelling corrections and some minor changes
+ * to stay in sync with kernel.
+ *
+ * Revision 1.6 1996/05/17 03:59:28 fritz
+ * Marked rcvcallb and writebuf obsolete.
+ *
+ * Revision 1.5 1996/05/01 11:43:54 fritz
+ * Removed STANDALONE
+ *
+ * Revision 1.4 1996/05/01 11:38:40 fritz
+ * Added ISDN_FEATURE_L2_TRANS
+ *
+ * Revision 1.3 1996/04/29 22:57:54 fritz
+ * Added driverId and channel parameters to
+ * writecmd() and readstat().
+ * Added constant for voice-support.
+ *
+ * Revision 1.2 1996/04/20 17:02:40 fritz
+ * Changes to support skbuffs for Lowlevel-Drivers.
+ * Misc. typos
+ *
+ * Revision 1.1 1996/01/09 05:50:51 fritz
+ * Initial revision
+ *
+ */
+
+#ifndef isdnif_h
+#define isdnif_h
+
+#include <linux/config.h>
+
+/*
+ * Values for general protocol-selection
+ */
+#define ISDN_PTYPE_UNKNOWN 0 /* Protocol undefined */
+#define ISDN_PTYPE_1TR6 1 /* german 1TR6-protocol */
+#define ISDN_PTYPE_EURO 2 /* EDSS1-protocol */
+#define ISDN_PTYPE_LEASED 3 /* for leased lines */
+#define ISDN_PTYPE_NI1 4 /* US NI-1 protocol */
+#define ISDN_PTYPE_MAX 7 /* Max. 8 Protocols */
+
+/*
+ * Values for Layer-2-protocol-selection
+ */
+#define ISDN_PROTO_L2_X75I 0 /* X75/LAPB with I-Frames */
+#define ISDN_PROTO_L2_X75UI 1 /* X75/LAPB with UI-Frames */
+#define ISDN_PROTO_L2_X75BUI 2 /* X75/LAPB with UI-Frames */
+#define ISDN_PROTO_L2_HDLC 3 /* HDLC */
+#define ISDN_PROTO_L2_TRANS 4 /* Transparent (Voice) */
+#define ISDN_PROTO_L2_X25DTE 5 /* X25/LAPB DTE mode */
+#define ISDN_PROTO_L2_X25DCE 6 /* X25/LAPB DCE mode */
+#define ISDN_PROTO_L2_V11096 7 /* V.110 bitrate adaption 9600 Baud */
+#define ISDN_PROTO_L2_V11019 8 /* V.110 bitrate adaption 19200 Baud */
+#define ISDN_PROTO_L2_V11038 9 /* V.110 bitrate adaption 38400 Baud */
+#define ISDN_PROTO_L2_MODEM 10 /* Analog Modem on Board */
+#define ISDN_PROTO_L2_FAX 11 /* Fax Group 2/3 */
+#define ISDN_PROTO_L2_MAX 15 /* Max. 16 Protocols */
+
+/*
+ * Values for Layer-3-protocol-selection
+ */
+#define ISDN_PROTO_L3_TRANS 0 /* Transparent */
+#define ISDN_PROTO_L3_TRANSDSP 1 /* Transparent with DSP */
+#define ISDN_PROTO_L3_FAX 2 /* Fax Group 2/3 */
+#define ISDN_PROTO_L3_MAX 7 /* Max. 8 Protocols */
+
+#ifdef __KERNEL__
+
+#include <linux/skbuff.h>
+
+/***************************************************************************/
+/* Extensions made by Werner Cornelius (werner@ikt.de) */
+/* */
+/* The proceed command holds a incoming call in a state to leave processes */
+/* enough time to check whether ist should be accepted. */
+/* The PROT_IO Command extends the interface to make protocol dependent */
+/* features available (call diversion, call waiting...). */
+/* */
+/* The PROT_IO Command is executed with the desired driver id and the arg */
+/* parameter coded as follows: */
+/* The lower 8 bits of arg contain the desired protocol from ISDN_PTYPE */
+/* definitions. The upper 24 bits represent the protocol specific cmd/stat.*/
+/* Any additional data is protocol and command specific. */
+/* This mechanism also applies to the statcallb callback STAT_PROT. */
+/* */
+/* This suggested extension permits an easy expansion of protocol specific */
+/* handling. Extensions may be added at any time without changing the HL */
+/* driver code and not getting conflicts without certifications. */
+/* The well known CAPI 2.0 interface handles such extensions in a similar */
+/* way. Perhaps a protocol specific module may be added and separately */
+/* loaded and linked to the basic isdn module for handling. */
+/***************************************************************************/
+
+/*****************/
+/* DSS1 commands */
+/*****************/
+#define DSS1_CMD_INVOKE ((0x00 << 8) | ISDN_PTYPE_EURO) /* invoke a supplementary service */
+#define DSS1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_EURO) /* abort a invoke cmd */
+
+/*******************************/
+/* DSS1 Status callback values */
+/*******************************/
+#define DSS1_STAT_INVOKE_RES ((0x80 << 8) | ISDN_PTYPE_EURO) /* Result for invocation */
+#define DSS1_STAT_INVOKE_ERR ((0x81 << 8) | ISDN_PTYPE_EURO) /* Error Return for invocation */
+#define DSS1_STAT_INVOKE_BRD ((0x82 << 8) | ISDN_PTYPE_EURO) /* Deliver invoke broadcast info */
+
+
+/*********************************************************************/
+/* structures for DSS1 commands and callback */
+/* */
+/* An action is invoked by sending a DSS1_CMD_INVOKE. The ll_id, proc*/
+/* timeout, datalen and data fields must be set before calling. */
+/* */
+/* The return value is a positive hl_id value also delivered in the */
+/* hl_id field. A value of zero signals no more left hl_id capacitys.*/
+/* A negative return value signals errors in LL. So if the return */
+/* value is <= 0 no action in LL will be taken -> request ignored */
+/* */
+/* The timeout field must be filled with a positive value specifying */
+/* the amount of time the INVOKED process waits for a reaction from */
+/* the network. */
+/* If a response (either error or result) is received during this */
+/* intervall, a reporting callback is initiated and the process will */
+/* be deleted, the hl identifier will be freed. */
+/* If no response is received during the specified intervall, a error*/
+/* callback is initiated with timeout set to -1 and a datalen set */
+/* to 0. */
+/* If timeout is set to a value <= 0 during INVOCATION the process is*/
+/* immediately deleted after sending the data. No callback occurs ! */
+/* */
+/* A currently waiting process may be aborted with INVOKE_ABORT. No */
+/* callback will occur when a process has been aborted. */
+/* */
+/* Broadcast invoke frames from the network are reported via the */
+/* STAT_INVOKE_BRD callback. The ll_id is set to 0, the other fields */
+/* are supplied by the network and not by the HL. */
+/*********************************************************************/
+typedef struct
+ { ulong ll_id; /* ID supplied by LL when executing */
+ /* a command and returned by HL for */
+ /* INVOKE_RES and INVOKE_ERR */
+ int hl_id; /* ID supplied by HL when called */
+ /* for executing a cmd and delivered */
+ /* for results and errors */
+ /* must be supplied by LL when aborting*/
+ int proc; /* invoke procedure used by CMD_INVOKE */
+ /* returned by callback and broadcast */
+ int timeout; /* timeout for INVOKE CMD in ms */
+ /* -1 in stat callback when timed out */
+ /* error value when error callback */
+ int datalen; /* length of cmd or stat data */
+ u_char *data;/* pointer to data delivered or send */
+ } dss1_cmd_stat;
+
+/*
+ * Commands from linklevel to lowlevel
+ *
+ */
+#define ISDN_CMD_IOCTL 0 /* Perform ioctl */
+#define ISDN_CMD_DIAL 1 /* Dial out */
+#define ISDN_CMD_ACCEPTD 2 /* Accept an incoming call on D-Chan. */
+#define ISDN_CMD_ACCEPTB 3 /* Request B-Channel connect. */
+#define ISDN_CMD_HANGUP 4 /* Hangup */
+#define ISDN_CMD_CLREAZ 5 /* Clear EAZ(s) of channel */
+#define ISDN_CMD_SETEAZ 6 /* Set EAZ(s) of channel */
+#define ISDN_CMD_GETEAZ 7 /* Get EAZ(s) of channel */
+#define ISDN_CMD_SETSIL 8 /* Set Service-Indicator-List of channel */
+#define ISDN_CMD_GETSIL 9 /* Get Service-Indicator-List of channel */
+#define ISDN_CMD_SETL2 10 /* Set B-Chan. Layer2-Parameter */
+#define ISDN_CMD_GETL2 11 /* Get B-Chan. Layer2-Parameter */
+#define ISDN_CMD_SETL3 12 /* Set B-Chan. Layer3-Parameter */
+#define ISDN_CMD_GETL3 13 /* Get B-Chan. Layer3-Parameter */
+#define ISDN_CMD_LOCK 14 /* Signal usage by upper levels */
+#define ISDN_CMD_UNLOCK 15 /* Release usage-lock */
+#define ISDN_CMD_SUSPEND 16 /* Suspend connection */
+#define ISDN_CMD_RESUME 17 /* Resume connection */
+#define ISDN_CMD_PROCEED 18 /* Proceed with call establishment */
+#define ISDN_CMD_ALERT 19 /* Alert after Proceeding */
+#define ISDN_CMD_REDIR 20 /* Redir a incoming call */
+#define ISDN_CMD_PROT_IO 21 /* Protocol specific commands */
+#define CAPI_PUT_MESSAGE 22 /* CAPI message send down or up */
+#define ISDN_CMD_FAXCMD 23 /* FAX commands to HL-driver */
+#define ISDN_CMD_AUDIO 24 /* DSP, DTMF, ... settings */
+
+/*
+ * Status-Values delivered from lowlevel to linklevel via
+ * statcallb().
+ *
+ */
+#define ISDN_STAT_STAVAIL 256 /* Raw status-data available */
+#define ISDN_STAT_ICALL 257 /* Incoming call detected */
+#define ISDN_STAT_RUN 258 /* Signal protocol-code is running */
+#define ISDN_STAT_STOP 259 /* Signal halt of protocol-code */
+#define ISDN_STAT_DCONN 260 /* Signal D-Channel connect */
+#define ISDN_STAT_BCONN 261 /* Signal B-Channel connect */
+#define ISDN_STAT_DHUP 262 /* Signal D-Channel disconnect */
+#define ISDN_STAT_BHUP 263 /* Signal B-Channel disconnect */
+#define ISDN_STAT_CINF 264 /* Charge-Info */
+#define ISDN_STAT_LOAD 265 /* Signal new lowlevel-driver is loaded */
+#define ISDN_STAT_UNLOAD 266 /* Signal unload of lowlevel-driver */
+#define ISDN_STAT_BSENT 267 /* Signal packet sent */
+#define ISDN_STAT_NODCH 268 /* Signal no D-Channel */
+#define ISDN_STAT_ADDCH 269 /* Add more Channels */
+#define ISDN_STAT_CAUSE 270 /* Cause-Message */
+#define ISDN_STAT_ICALLW 271 /* Incoming call without B-chan waiting */
+#define ISDN_STAT_REDIR 272 /* Redir result */
+#define ISDN_STAT_PROT 273 /* protocol IO specific callback */
+#define ISDN_STAT_DISPLAY 274 /* deliver a received display message */
+#define ISDN_STAT_L1ERR 275 /* Signal Layer-1 Error */
+#define ISDN_STAT_FAXIND 276 /* FAX indications from HL-driver */
+#define ISDN_STAT_AUDIO 277 /* DTMF, DSP indications */
+#define ISDN_STAT_DISCH 278 /* Disable/Enable channel usage */
+
+/*
+ * Audio commands
+ */
+#define ISDN_AUDIO_SETDD 0 /* Set DTMF detection */
+#define ISDN_AUDIO_DTMF 1 /* Rx/Tx DTMF */
+
+/*
+ * Values for errcode field
+ */
+#define ISDN_STAT_L1ERR_SEND 1
+#define ISDN_STAT_L1ERR_RECV 2
+
+/*
+ * Values for feature-field of interface-struct.
+ */
+/* Layer 2 */
+#define ISDN_FEATURE_L2_X75I (0x0001 << ISDN_PROTO_L2_X75I)
+#define ISDN_FEATURE_L2_X75UI (0x0001 << ISDN_PROTO_L2_X75UI)
+#define ISDN_FEATURE_L2_X75BUI (0x0001 << ISDN_PROTO_L2_X75BUI)
+#define ISDN_FEATURE_L2_HDLC (0x0001 << ISDN_PROTO_L2_HDLC)
+#define ISDN_FEATURE_L2_TRANS (0x0001 << ISDN_PROTO_L2_TRANS)
+#define ISDN_FEATURE_L2_X25DTE (0x0001 << ISDN_PROTO_L2_X25DTE)
+#define ISDN_FEATURE_L2_X25DCE (0x0001 << ISDN_PROTO_L2_X25DCE)
+#define ISDN_FEATURE_L2_V11096 (0x0001 << ISDN_PROTO_L2_V11096)
+#define ISDN_FEATURE_L2_V11019 (0x0001 << ISDN_PROTO_L2_V11019)
+#define ISDN_FEATURE_L2_V11038 (0x0001 << ISDN_PROTO_L2_V11038)
+#define ISDN_FEATURE_L2_MODEM (0x0001 << ISDN_PROTO_L2_MODEM)
+#define ISDN_FEATURE_L2_FAX (0x0001 << ISDN_PROTO_L2_FAX)
+
+#define ISDN_FEATURE_L2_MASK (0x0FFFF) /* Max. 16 protocols */
+#define ISDN_FEATURE_L2_SHIFT (0)
+
+/* Layer 3 */
+#define ISDN_FEATURE_L3_TRANS (0x10000 << ISDN_PROTO_L3_TRANS)
+#define ISDN_FEATURE_L3_TRANSDSP (0x10000 << ISDN_PROTO_L3_TRANSDSP)
+#define ISDN_FEATURE_L3_FAX (0x10000 << ISDN_PROTO_L3_FAX)
+
+#define ISDN_FEATURE_L3_MASK (0x0FF0000) /* Max. 8 Protocols */
+#define ISDN_FEATURE_L3_SHIFT (16)
+
+/* Signaling */
+#define ISDN_FEATURE_P_UNKNOWN (0x1000000 << ISDN_PTYPE_UNKNOWN)
+#define ISDN_FEATURE_P_1TR6 (0x1000000 << ISDN_PTYPE_1TR6)
+#define ISDN_FEATURE_P_EURO (0x1000000 << ISDN_PTYPE_EURO)
+#define ISDN_FEATURE_P_NI1 (0x1000000 << ISDN_PTYPE_NI1)
+
+#define ISDN_FEATURE_P_MASK (0x0FF000000) /* Max. 8 Protocols */
+#define ISDN_FEATURE_P_SHIFT (24)
+
+typedef struct setup_parm {
+ unsigned char phone[32]; /* Remote Phone-Number */
+ unsigned char eazmsn[32]; /* Local EAZ or MSN */
+ unsigned char si1; /* Service Indicator 1 */
+ unsigned char si2; /* Service Indicator 2 */
+ unsigned char plan; /* Numbering plan */
+ unsigned char screen; /* Screening info */
+} setup_parm;
+
+
+#ifdef CONFIG_ISDN_TTY_FAX
+/* T.30 Fax G3 */
+
+#define FAXIDLEN 21
+
+typedef struct T30_s {
+ /* session parameters */
+ __u8 resolution __attribute__ ((packed));
+ __u8 rate __attribute__ ((packed));
+ __u8 width __attribute__ ((packed));
+ __u8 length __attribute__ ((packed));
+ __u8 compression __attribute__ ((packed));
+ __u8 ecm __attribute__ ((packed));
+ __u8 binary __attribute__ ((packed));
+ __u8 scantime __attribute__ ((packed));
+ __u8 id[FAXIDLEN] __attribute__ ((packed));
+ /* additional parameters */
+ __u8 phase __attribute__ ((packed));
+ __u8 direction __attribute__ ((packed));
+ __u8 code __attribute__ ((packed));
+ __u8 badlin __attribute__ ((packed));
+ __u8 badmul __attribute__ ((packed));
+ __u8 bor __attribute__ ((packed));
+ __u8 fet __attribute__ ((packed));
+ __u8 pollid[FAXIDLEN] __attribute__ ((packed));
+ __u8 cq __attribute__ ((packed));
+ __u8 cr __attribute__ ((packed));
+ __u8 ctcrty __attribute__ ((packed));
+ __u8 minsp __attribute__ ((packed));
+ __u8 phcto __attribute__ ((packed));
+ __u8 rel __attribute__ ((packed));
+ __u8 nbc __attribute__ ((packed));
+ /* remote station parameters */
+ __u8 r_resolution __attribute__ ((packed));
+ __u8 r_rate __attribute__ ((packed));
+ __u8 r_width __attribute__ ((packed));
+ __u8 r_length __attribute__ ((packed));
+ __u8 r_compression __attribute__ ((packed));
+ __u8 r_ecm __attribute__ ((packed));
+ __u8 r_binary __attribute__ ((packed));
+ __u8 r_scantime __attribute__ ((packed));
+ __u8 r_id[FAXIDLEN] __attribute__ ((packed));
+ __u8 r_code __attribute__ ((packed));
+} T30_s;
+
+#define ISDN_TTY_FAX_CONN_IN 0
+#define ISDN_TTY_FAX_CONN_OUT 1
+
+#define ISDN_TTY_FAX_FCON 0
+#define ISDN_TTY_FAX_DIS 1
+#define ISDN_TTY_FAX_FTT 2
+#define ISDN_TTY_FAX_MCF 3
+#define ISDN_TTY_FAX_DCS 4
+#define ISDN_TTY_FAX_TRAIN_OK 5
+#define ISDN_TTY_FAX_EOP 6
+#define ISDN_TTY_FAX_EOM 7
+#define ISDN_TTY_FAX_MPS 8
+#define ISDN_TTY_FAX_DTC 9
+#define ISDN_TTY_FAX_RID 10
+#define ISDN_TTY_FAX_HNG 11
+#define ISDN_TTY_FAX_DT 12
+#define ISDN_TTY_FAX_FCON_I 13
+#define ISDN_TTY_FAX_DR 14
+#define ISDN_TTY_FAX_ET 15
+#define ISDN_TTY_FAX_CFR 16
+#define ISDN_TTY_FAX_PTS 17
+#define ISDN_TTY_FAX_SENT 18
+
+#define ISDN_FAX_PHASE_IDLE 0
+#define ISDN_FAX_PHASE_A 1
+#define ISDN_FAX_PHASE_B 2
+#define ISDN_FAX_PHASE_C 3
+#define ISDN_FAX_PHASE_D 4
+#define ISDN_FAX_PHASE_E 5
+
+#endif /* TTY_FAX */
+
+/* CAPI structs */
+
+/* this is compatible to the old union size */
+#define MAX_CAPI_PARA_LEN 50
+
+typedef struct {
+ /* Header */
+ __u16 Length;
+ __u16 ApplId;
+ __u8 Command;
+ __u8 Subcommand;
+ __u16 Messagenumber;
+
+ /* Parameter */
+ union {
+ __u32 Controller;
+ __u32 PLCI;
+ __u32 NCCI;
+ } adr;
+ __u8 para[MAX_CAPI_PARA_LEN];
+} capi_msg;
+
+/*
+ * Structure for exchanging above infos
+ *
+ */
+typedef struct {
+ int driver; /* Lowlevel-Driver-ID */
+ int command; /* Command or Status (see above) */
+ ulong arg; /* Additional Data */
+ union {
+ ulong errcode; /* Type of error with STAT_L1ERR */
+ int length; /* Amount of bytes sent with STAT_BSENT */
+ u_char num[50];/* Additional Data */
+ setup_parm setup;/* For SETUP msg */
+ capi_msg cmsg; /* For CAPI like messages */
+ char display[85];/* display message data */
+ dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */
+#ifdef CONFIG_ISDN_TTY_FAX
+ T30_s *fax; /* Pointer to ttys fax struct */
+#endif
+ } parm;
+} isdn_ctrl;
+
+/*
+ * The interface-struct itself (initialized at load-time of lowlevel-driver)
+ *
+ * See Documentation/isdn/INTERFACE for a description, how the communication
+ * between the ISDN subsystem and its drivers is done.
+ *
+ */
+typedef struct {
+ /* Number of channels supported by this driver
+ */
+ int channels;
+
+ /*
+ * Maximum Size of transmit/receive-buffer this driver supports.
+ */
+ int maxbufsize;
+
+ /* Feature-Flags for this driver.
+ * See defines ISDN_FEATURE_... for Values
+ */
+ unsigned long features;
+
+ /*
+ * Needed for calculating
+ * dev->hard_header_len = linklayer header + hl_hdrlen;
+ * Drivers, not supporting sk_buff's should set this to 0.
+ */
+ unsigned short hl_hdrlen;
+
+ /*
+ * Receive-Callback using sk_buff's
+ * Parameters:
+ * int Driver-ID
+ * int local channel-number (0 ...)
+ * struct sk_buff *skb received Data
+ */
+ void (*rcvcallb_skb)(int, int, struct sk_buff *);
+
+ /* Status-Callback
+ * Parameters:
+ * isdn_ctrl*
+ * driver = Driver ID.
+ * command = One of above ISDN_STAT_... constants.
+ * arg = depending on status-type.
+ * num = depending on status-type.
+ */
+ int (*statcallb)(isdn_ctrl*);
+
+ /* Send command
+ * Parameters:
+ * isdn_ctrl*
+ * driver = Driver ID.
+ * command = One of above ISDN_CMD_... constants.
+ * arg = depending on command.
+ * num = depending on command.
+ */
+ int (*command)(isdn_ctrl*);
+
+ /*
+ * Send data using sk_buff's
+ * Parameters:
+ * int driverId
+ * int local channel-number (0...)
+ * int Flag: Need ACK for this packet.
+ * struct sk_buff *skb Data to send
+ */
+ int (*writebuf_skb) (int, int, int, struct sk_buff *);
+
+ /* Send raw D-Channel-Commands
+ * Parameters:
+ * u_char pointer data
+ * int length of data
+ * int Flag: 0 = Call form Kernel-Space (use memcpy,
+ * no schedule allowed)
+ * 1 = Data is in User-Space (use memcpy_fromfs,
+ * may schedule)
+ * int driverId
+ * int local channel-number (0 ...)
+ */
+ int (*writecmd)(const u_char*, int, int, int, int);
+
+ /* Read raw Status replies
+ * u_char pointer data (volatile)
+ * int length of buffer
+ * int Flag: 0 = Call form Kernel-Space (use memcpy,
+ * no schedule allowed)
+ * 1 = Data is in User-Space (use memcpy_fromfs,
+ * may schedule)
+ * int driverId
+ * int local channel-number (0 ...)
+ */
+ int (*readstat)(u_char*, int, int, int, int);
+
+ char id[20];
+} isdn_if;
+
+/*
+ * Function which must be called by lowlevel-driver at loadtime with
+ * the following fields of above struct set:
+ *
+ * channels Number of channels that will be supported.
+ * hl_hdrlen Space to preserve in sk_buff's when sending. Drivers, not
+ * supporting sk_buff's should set this to 0.
+ * command Address of Command-Handler.
+ * features Bitwise coded Features of this driver. (use ISDN_FEATURE_...)
+ * writebuf_skb Address of Skbuff-Send-Handler.
+ * writecmd " " D-Channel " which accepts raw D-Ch-Commands.
+ * readstat " " D-Channel " which delivers raw Status-Data.
+ *
+ * The linklevel-driver fills the following fields:
+ *
+ * channels Driver-ID assigned to this driver. (Must be used on all
+ * subsequent callbacks.
+ * rcvcallb_skb Address of handler for received Skbuff's.
+ * statcallb " " " for status-changes.
+ *
+ */
+extern int register_isdn(isdn_if*);
+#include <asm/uaccess.h>
+
+#endif /* __KERNEL__ */
+#endif /* isdnif_h */
diff --git a/pfinet/linux-src/include/linux/isicom.h b/pfinet/linux-src/include/linux/isicom.h
new file mode 100644
index 00000000..58372fdc
--- /dev/null
+++ b/pfinet/linux-src/include/linux/isicom.h
@@ -0,0 +1,310 @@
+#ifndef _LINUX_ISICOM_H
+#define _LINUX_ISICOM_H
+
+/*#define ISICOM_DEBUG*/
+/*#define ISICOM_DEBUG_DTR_RTS*/
+
+
+/*
+ * Firmware Loader definitions ...
+ */
+
+#define __MultiTech ('M'<<8)
+#define MIOCTL_LOAD_FIRMWARE (__MultiTech | 0x01)
+#define MIOCTL_READ_FIRMWARE (__MultiTech | 0x02)
+#define MIOCTL_XFER_CTRL (__MultiTech | 0x03)
+#define MIOCTL_RESET_CARD (__MultiTech | 0x04)
+
+#define DATA_SIZE 16
+
+typedef struct {
+ unsigned short exec_segment;
+ unsigned short exec_addr;
+} exec_record;
+
+typedef struct {
+ int board; /* Board to load */
+ unsigned short addr;
+ unsigned short count;
+} bin_header;
+
+typedef struct {
+ int board; /* Board to load */
+ unsigned short addr;
+ unsigned short count;
+ unsigned short segment;
+ unsigned char bin_data[DATA_SIZE];
+} bin_frame;
+
+#ifdef __KERNEL__
+
+#define YES 1
+#define NO 0
+
+#define ISILOAD_MISC_MINOR 155 /* /dev/isctl */
+#define ISILOAD_NAME "ISILoad"
+
+/*
+ * ISICOM Driver definitions ...
+ *
+ */
+
+#define ISICOM_NAME "ISICom"
+
+/*
+ * PCI definitions
+ */
+
+ #define DEVID_COUNT 9
+ #define VENDOR_ID 0x10b5
+
+/*
+ * These are now officially allocated numbers
+ */
+
+#define ISICOM_NMAJOR 112 /* normal */
+#define ISICOM_CMAJOR 113 /* callout */
+#define ISICOM_MAGIC (('M' << 8) | 'T')
+
+#define WAKEUP_CHARS 256 /* hard coded for now */
+#define TX_SIZE 254
+
+#define BOARD_COUNT 4
+#define PORT_COUNT (BOARD_COUNT*16)
+
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+/* character sizes */
+
+#define ISICOM_CS5 0x0000
+#define ISICOM_CS6 0x0001
+#define ISICOM_CS7 0x0002
+#define ISICOM_CS8 0x0003
+
+/* stop bits */
+
+#define ISICOM_1SB 0x0000
+#define ISICOM_2SB 0x0004
+
+/* parity */
+
+#define ISICOM_NOPAR 0x0000
+#define ISICOM_ODPAR 0x0008
+#define ISICOM_EVPAR 0x0018
+
+/* flow control */
+
+#define ISICOM_CTSRTS 0x03
+#define ISICOM_INITIATE_XONXOFF 0x04
+#define ISICOM_RESPOND_XONXOFF 0x08
+
+#define InterruptTheCard(base) (outw(0,(base)+0xc))
+#define ClearInterrupt(base) (inw((base)+0x0a))
+
+#define BOARD(line) (((line) >> 4) & 0x3)
+#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
+
+ /* isi kill queue bitmap */
+
+#define ISICOM_KILLTX 0x01
+#define ISICOM_KILLRX 0x02
+
+ /* isi_board status bitmap */
+
+#define FIRMWARE_LOADED 0x0001
+#define BOARD_ACTIVE 0x0002
+
+ /* isi_port status bitmap */
+
+#define ISI_CTS 0x1000
+#define ISI_DSR 0x2000
+#define ISI_RI 0x4000
+#define ISI_DCD 0x8000
+#define ISI_DTR 0x0100
+#define ISI_RTS 0x0200
+
+
+#define ISI_TXOK 0x0001
+
+struct isi_board {
+ unsigned short base;
+ unsigned char irq;
+ unsigned char port_count;
+ unsigned short status;
+ unsigned short port_status; /* each bit represents a single port */
+ unsigned short shift_count;
+ struct isi_port * ports;
+ signed char count;
+ unsigned char isa;
+};
+
+struct isi_port {
+ unsigned short magic;
+ unsigned int flags;
+ int count;
+ int blocked_open;
+ int close_delay;
+ unsigned short channel;
+ unsigned short status;
+ unsigned short closing_wait;
+ long session;
+ long pgrp;
+ struct isi_board * card;
+ struct tty_struct * tty;
+ struct wait_queue * close_wait;
+ struct wait_queue * open_wait;
+ struct tq_struct hangup_tq;
+ struct tq_struct bh_tqueue;
+ unsigned char * xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct termios normal_termios;
+ struct termios callout_termios;
+};
+
+
+/*
+ * ISI Card specific ops ...
+ */
+
+extern inline void raise_dtr(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+ short wait=400;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr.\n");
+ return;
+ }
+#ifdef ISICOM_DEBUG_DTR_RTS
+ printk(KERN_DEBUG "ISICOM: raise_dtr.\n");
+#endif
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0504, base);
+ InterruptTheCard(base);
+ port->status |= ISI_DTR;
+}
+
+extern inline void drop_dtr(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+ short wait=400;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr.\n");
+ return;
+ }
+#ifdef ISICOM_DEBUG_DTR_RTS
+ printk(KERN_DEBUG "ISICOM: drop_dtr.\n");
+#endif
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0404, base);
+ InterruptTheCard(base);
+ port->status &= ~ISI_DTR;
+}
+extern inline void raise_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+ short wait=400;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ printk(KERN_WARNING "ISICOM: Card found busy in raise_rts.\n");
+ return;
+ }
+#ifdef ISICOM_DEBUG_DTR_RTS
+ printk(KERN_DEBUG "ISICOM: raise_rts.\n");
+#endif
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0a04, base);
+ InterruptTheCard(base);
+ port->status |= ISI_RTS;
+}
+extern inline void drop_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+ short wait=400;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ printk(KERN_WARNING "ISICOM: Card found busy in drop_rts.\n");
+ return;
+ }
+#ifdef ISICOM_DEBUG_DTR_RTS
+ printk(KERN_DEBUG "ISICOM: drop_rts.\n");
+#endif
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0804, base);
+ InterruptTheCard(base);
+ port->status &= ~ISI_RTS;
+}
+extern inline void raise_dtr_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+ short wait=400;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr_rts.\n");
+ return;
+ }
+#ifdef ISICOM_DEBUG_DTR_RTS
+ printk(KERN_DEBUG "ISICOM: raise_dtr_rts.\n");
+#endif
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0f04, base);
+ InterruptTheCard(base);
+ port->status |= (ISI_DTR | ISI_RTS);
+}
+extern inline void drop_dtr_rts(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+ short wait=400;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr_rts.\n");
+ return;
+ }
+#ifdef ISICOM_DEBUG_DTR_RTS
+ printk(KERN_DEBUG "ISICOM: drop_dtr_rts.\n");
+#endif
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x0c04, base);
+ InterruptTheCard(base);
+ port->status &= ~(ISI_RTS | ISI_DTR);
+}
+
+extern inline void kill_queue(struct isi_port * port, short queue)
+{
+ struct isi_board * card = port->card;
+ unsigned short base = card->base;
+ unsigned char channel = port->channel;
+ short wait=400;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ printk(KERN_WARNING "ISICOM: Card found busy in kill_queue.\n");
+ return;
+ }
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: kill_queue 0x%x.\n", queue);
+#endif
+ outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw((queue << 8) | 0x06, base);
+ InterruptTheCard(base);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* ISICOM_H */
+
diff --git a/pfinet/linux-src/include/linux/iso_fs.h b/pfinet/linux-src/include/linux/iso_fs.h
new file mode 100644
index 00000000..0fcb4b82
--- /dev/null
+++ b/pfinet/linux-src/include/linux/iso_fs.h
@@ -0,0 +1,230 @@
+
+#ifndef _ISOFS_FS_H
+#define _ISOFS_FS_H
+
+#include <linux/types.h>
+/*
+ * The isofs filesystem constants/structures
+ */
+
+/* This part borrowed from the bsd386 isofs */
+#define ISODCL(from, to) (to - from + 1)
+
+struct iso_volume_descriptor {
+ char type[ISODCL(1,1)]; /* 711 */
+ char id[ISODCL(2,6)];
+ char version[ISODCL(7,7)];
+ char data[ISODCL(8,2048)];
+};
+
+/* volume descriptor types */
+#define ISO_VD_PRIMARY 1
+#define ISO_VD_SUPPLEMENTARY 2
+#define ISO_VD_END 255
+
+#define ISO_STANDARD_ID "CD001"
+
+struct iso_primary_descriptor {
+ char type [ISODCL ( 1, 1)]; /* 711 */
+ char id [ISODCL ( 2, 6)];
+ char version [ISODCL ( 7, 7)]; /* 711 */
+ char unused1 [ISODCL ( 8, 8)];
+ char system_id [ISODCL ( 9, 40)]; /* achars */
+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
+ char unused2 [ISODCL ( 73, 80)];
+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ char unused3 [ISODCL ( 89, 120)];
+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ char path_table_size [ISODCL (133, 140)]; /* 733 */
+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
+ char publisher_id [ISODCL (319, 446)]; /* achars */
+ char preparer_id [ISODCL (447, 574)]; /* achars */
+ char application_id [ISODCL (575, 702)]; /* achars */
+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ char unused4 [ISODCL (883, 883)];
+ char application_data [ISODCL (884, 1395)];
+ char unused5 [ISODCL (1396, 2048)];
+};
+
+/* Almost the same as the primary descriptor but two fields are specified */
+struct iso_supplementary_descriptor {
+ char type [ISODCL ( 1, 1)]; /* 711 */
+ char id [ISODCL ( 2, 6)];
+ char version [ISODCL ( 7, 7)]; /* 711 */
+ char flags [ISODCL ( 8, 8)]; /* 853 */
+ char system_id [ISODCL ( 9, 40)]; /* achars */
+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
+ char unused2 [ISODCL ( 73, 80)];
+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ char escape [ISODCL ( 89, 120)]; /* 856 */
+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ char path_table_size [ISODCL (133, 140)]; /* 733 */
+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
+ char publisher_id [ISODCL (319, 446)]; /* achars */
+ char preparer_id [ISODCL (447, 574)]; /* achars */
+ char application_id [ISODCL (575, 702)]; /* achars */
+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ char unused4 [ISODCL (883, 883)];
+ char application_data [ISODCL (884, 1395)];
+ char unused5 [ISODCL (1396, 2048)];
+};
+
+
+#define HS_STANDARD_ID "CDROM"
+
+struct hs_volume_descriptor {
+ char foo [ISODCL ( 1, 8)]; /* 733 */
+ char type [ISODCL ( 9, 9)]; /* 711 */
+ char id [ISODCL ( 10, 14)];
+ char version [ISODCL ( 15, 15)]; /* 711 */
+ char data[ISODCL(16,2048)];
+};
+
+
+struct hs_primary_descriptor {
+ char foo [ISODCL ( 1, 8)]; /* 733 */
+ char type [ISODCL ( 9, 9)]; /* 711 */
+ char id [ISODCL ( 10, 14)];
+ char version [ISODCL ( 15, 15)]; /* 711 */
+ char unused1 [ISODCL ( 16, 16)]; /* 711 */
+ char system_id [ISODCL ( 17, 48)]; /* achars */
+ char volume_id [ISODCL ( 49, 80)]; /* dchars */
+ char unused2 [ISODCL ( 81, 88)]; /* 733 */
+ char volume_space_size [ISODCL ( 89, 96)]; /* 733 */
+ char unused3 [ISODCL ( 97, 128)]; /* 733 */
+ char volume_set_size [ISODCL (129, 132)]; /* 723 */
+ char volume_sequence_number [ISODCL (133, 136)]; /* 723 */
+ char logical_block_size [ISODCL (137, 140)]; /* 723 */
+ char path_table_size [ISODCL (141, 148)]; /* 733 */
+ char type_l_path_table [ISODCL (149, 152)]; /* 731 */
+ char unused4 [ISODCL (153, 180)]; /* 733 */
+ char root_directory_record [ISODCL (181, 214)]; /* 9.1 */
+};
+
+/* We use this to help us look up the parent inode numbers. */
+
+struct iso_path_table{
+ unsigned char name_len[2]; /* 721 */
+ char extent[4]; /* 731 */
+ char parent[2]; /* 721 */
+ char name[0];
+};
+
+/* high sierra is identical to iso, except that the date is only 6 bytes, and
+ there is an extra reserved byte after the flags */
+
+struct iso_directory_record {
+ char length [ISODCL (1, 1)]; /* 711 */
+ char ext_attr_length [ISODCL (2, 2)]; /* 711 */
+ char extent [ISODCL (3, 10)]; /* 733 */
+ char size [ISODCL (11, 18)]; /* 733 */
+ char date [ISODCL (19, 25)]; /* 7 by 711 */
+ char flags [ISODCL (26, 26)];
+ char file_unit_size [ISODCL (27, 27)]; /* 711 */
+ char interleave [ISODCL (28, 28)]; /* 711 */
+ char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
+ unsigned char name_len [ISODCL (33, 33)]; /* 711 */
+ char name [0];
+};
+
+#define ISOFS_BLOCK_BITS 11
+#define ISOFS_BLOCK_SIZE 2048
+
+#define ISOFS_BUFFER_SIZE(INODE) ((INODE)->i_sb->s_blocksize)
+#define ISOFS_BUFFER_BITS(INODE) ((INODE)->i_sb->s_blocksize_bits)
+#define ISOFS_ZONE_BITS(INODE) ((INODE)->i_sb->u.isofs_sb.s_log_zone_size)
+
+#define ISOFS_SUPER_MAGIC 0x9660
+
+#ifdef __KERNEL__
+extern int isonum_711(char *);
+extern int isonum_712(char *);
+extern int isonum_721(char *);
+extern int isonum_722(char *);
+extern int isonum_723(char *);
+extern int isonum_731(char *);
+extern int isonum_732(char *);
+extern int isonum_733(char *);
+extern int iso_date(char *, int);
+
+extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
+extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
+
+extern char * get_rock_ridge_symlink(struct inode *);
+extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
+
+int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
+int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
+
+/* The stuff that follows may be totally unneeded. I have not checked to see
+ which prototypes we are still using. */
+
+extern int isofs_open(struct inode * inode, struct file * filp);
+extern void isofs_release(struct inode * inode, struct file * filp);
+extern struct dentry *isofs_lookup(struct inode * dir, struct dentry *);
+extern unsigned long isofs_count_free_inodes(struct super_block *sb);
+extern int isofs_new_block(int dev);
+extern int isofs_free_block(int dev, int block);
+extern int isofs_bmap(struct inode *,int);
+
+extern void isofs_put_super(struct super_block *);
+extern struct super_block *isofs_read_super(struct super_block *,void *,int);
+extern int init_iso9660_fs(void);
+extern void isofs_read_inode(struct inode *);
+extern void isofs_put_inode(struct inode *);
+extern int isofs_statfs(struct super_block *, struct statfs *, int);
+
+extern int isofs_lseek(struct inode *, struct file *, off_t, int);
+extern int isofs_read(struct inode *, struct file *, char *, int);
+extern int isofs_lookup_grandparent(struct inode *, int);
+
+extern struct inode_operations isofs_file_inode_operations;
+extern struct inode_operations isofs_dir_inode_operations;
+extern struct inode_operations isofs_symlink_inode_operations;
+extern struct inode_operations isofs_chrdev_inode_operations;
+extern struct inode_operations isofs_blkdev_inode_operations;
+extern struct inode_operations isofs_fifo_inode_operations;
+
+/* The following macros are used to check for memory leaks. */
+#ifdef LEAK_CHECK
+#define free_s leak_check_free_s
+#define malloc leak_check_malloc
+#define bread leak_check_bread
+#define brelse leak_check_brelse
+extern void * leak_check_malloc(unsigned int size);
+extern void leak_check_free_s(void * obj, int size);
+extern struct buffer_head * leak_check_bread(int dev, int block, int size);
+extern void leak_check_brelse(struct buffer_head * bh);
+#endif /* LEAK_CHECK */
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/iso_fs_i.h b/pfinet/linux-src/include/linux/iso_fs_i.h
new file mode 100644
index 00000000..02f17e07
--- /dev/null
+++ b/pfinet/linux-src/include/linux/iso_fs_i.h
@@ -0,0 +1,14 @@
+#ifndef _ISO_FS_I
+#define _ISO_FS_I
+
+/*
+ * iso fs inode data in memory
+ */
+struct iso_inode_info {
+ unsigned int i_first_extent;
+ unsigned char i_file_format;
+ unsigned long i_next_section_ino;
+ off_t i_section_size;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/iso_fs_sb.h b/pfinet/linux-src/include/linux/iso_fs_sb.h
new file mode 100644
index 00000000..7bb55a50
--- /dev/null
+++ b/pfinet/linux-src/include/linux/iso_fs_sb.h
@@ -0,0 +1,31 @@
+#ifndef _ISOFS_FS_SB
+#define _ISOFS_FS_SB
+
+/*
+ * iso9660 super-block data in memory
+ */
+struct isofs_sb_info {
+ unsigned long s_ninodes;
+ unsigned long s_nzones;
+ unsigned long s_firstdatazone;
+ unsigned long s_log_zone_size;
+ unsigned long s_max_size;
+
+ unsigned char s_high_sierra; /* A simple flag */
+ unsigned char s_mapping;
+ unsigned char s_rock;
+ unsigned char s_joliet_level;
+ unsigned char s_utf8;
+ unsigned char s_cruft; /* Broken disks with high
+ byte of length containing
+ junk */
+ unsigned char s_unhide;
+ unsigned char s_nosuid;
+ unsigned char s_nodev;
+ mode_t s_mode;
+ gid_t s_gid;
+ uid_t s_uid;
+ struct nls_table *s_nls_iocharset; /* Native language support table */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/istallion.h b/pfinet/linux-src/include/linux/istallion.h
new file mode 100644
index 00000000..269ef88b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/istallion.h
@@ -0,0 +1,134 @@
+/*****************************************************************************/
+
+/*
+ * istallion.h -- stallion intelligent multiport serial driver.
+ *
+ * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*****************************************************************************/
+#ifndef _ISTALLION_H
+#define _ISTALLION_H
+/*****************************************************************************/
+
+/*
+ * Define important driver constants here.
+ */
+#define STL_MAXBRDS 4
+#define STL_MAXPANELS 4
+#define STL_MAXPORTS 64
+#define STL_MAXCHANS (STL_MAXPORTS + 1)
+#define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS)
+
+
+/*
+ * Define a set of structures to hold all the board/panel/port info
+ * for our ports. These will be dynamically allocated as required at
+ * driver initialization time.
+ */
+
+/*
+ * Port and board structures to hold status info about each object.
+ * The board structure contains pointers to structures for each port
+ * connected to it. Panels are not distinguished here, since
+ * communication with the slave board will always be on a per port
+ * basis.
+ */
+typedef struct {
+ unsigned long magic;
+ int portnr;
+ int panelnr;
+ int brdnr;
+ unsigned long state;
+ int devnr;
+ int flags;
+ int baud_base;
+ int custom_divisor;
+ int close_delay;
+ int closing_wait;
+ int refcount;
+ int openwaitcnt;
+ int rc;
+ int argsize;
+ void *argp;
+ long session;
+ long pgrp;
+ unsigned int rxmarkmsk;
+ struct tty_struct *tty;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *raw_wait;
+ struct tq_struct tqhangup;
+ struct termios normaltermios;
+ struct termios callouttermios;
+ asysigs_t asig;
+ unsigned long addr;
+ unsigned long rxoffset;
+ unsigned long txoffset;
+ unsigned long sigs;
+ unsigned long pflag;
+ unsigned int rxsize;
+ unsigned int txsize;
+ unsigned char reqbit;
+ unsigned char portidx;
+ unsigned char portbit;
+} stliport_t;
+
+/*
+ * Use a structure of function pointers to do board level operations.
+ * These include, enable/disable, paging shared memory, interrupting, etc.
+ */
+typedef struct stlibrd {
+ unsigned long magic;
+ int brdnr;
+ int brdtype;
+ int state;
+ int nrpanels;
+ int nrports;
+ int nrdevs;
+ unsigned int iobase;
+ int iosize;
+ unsigned long memaddr;
+ void *membase;
+ int memsize;
+ int pagesize;
+ int hostoffset;
+ int slaveoffset;
+ int bitsize;
+ int enabval;
+ int panels[STL_MAXPANELS];
+ int panelids[STL_MAXPANELS];
+ void (*init)(struct stlibrd *brdp);
+ void (*enable)(struct stlibrd *brdp);
+ void (*reenable)(struct stlibrd *brdp);
+ void (*disable)(struct stlibrd *brdp);
+ char *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
+ void (*intr)(struct stlibrd *brdp);
+ void (*reset)(struct stlibrd *brdp);
+ stliport_t *ports[STL_MAXPORTS];
+} stlibrd_t;
+
+
+/*
+ * Define MAGIC numbers used for above structures.
+ */
+#define STLI_PORTMAGIC 0xe671c7a1
+#define STLI_BOARDMAGIC 0x4bc6c825
+
+/*****************************************************************************/
+#endif
diff --git a/pfinet/linux-src/include/linux/ixjuser.h b/pfinet/linux-src/include/linux/ixjuser.h
new file mode 100644
index 00000000..1ee0ee91
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ixjuser.h
@@ -0,0 +1,629 @@
+/*
+ * ixjuser.h
+ *
+ * User-space include file for the Internet PhoneJACK and
+ * Internet LineJACK Telephony Cards.
+ *
+ * (c) Copyright 1999 Quicknet Technologies, 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 of the License, or (at your option) any later version.
+ *
+ * Author: Ed Okerson, <eokerson@quicknet.net>
+ *
+ * Contributors: Greg Herlein, <gherlein@quicknet.net>
+ * David W. Erhart, <derhart@quicknet.net>
+ * John Sellers, <jsellers@quicknet.net>
+ * Mike Preston, <mpreston@quicknet.net>
+ *
+ * More information about the hardware related to this driver can be found
+ * at our website: http://www.quicknet.net
+ *
+ * Fixes:
+ */
+
+static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.4 1999/12/16 22:18:36 root Exp root $";
+
+#include <linux/telephony.h>
+
+/***************************************************************************
+
+ If you use the IXJCTL_TESTRAM command, the card must be power
+ cycled to reset the SRAM values before further use.
+
+***************************************************************************/
+#define IXJCTL_DSP_RESET _IO ('q', 0xC0)
+
+#define IXJCTL_RING PHONE_RING
+#define IXJCTL_HOOKSTATE PHONE_HOOKSTATE
+#define IXJCTL_MAXRINGS PHONE_MAXRINGS
+#define IXJCTL_RING_CADENCE PHONE_RING_CADENCE
+#define IXJCTL_RING_START PHONE_RING_START
+#define IXJCTL_RING_STOP PHONE_RING_STOP
+
+#define IXJCTL_CARDTYPE _IOR ('q', 0xC1, int)
+#define IXJCTL_SERIAL _IOR ('q', 0xC2, int)
+#define IXJCTL_DSP_TYPE _IOR ('q', 0xC3, int)
+#define IXJCTL_DSP_VERSION _IOR ('q', 0xC4, int)
+#define IXJCTL_DSP_IDLE _IO ('q', 0xC5)
+#define IXJCTL_TESTRAM _IO ('q', 0xC6)
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the record settings of the DSP
+*
+* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP.
+* Setting a lower depth reduces latency, but increases the demand of the
+* application to service the driver without frame loss. The DSP has 480
+* bytes of physical buffer memory for the record channel so the true
+* maximum limit is determined by how many frames will fit in the buffer.
+*
+* 1 uncompressed (480 byte) 16-bit linear frame.
+* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames.
+* 15 TrueSpeech 8.5 frames.
+* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames.
+*
+* The default in the driver is currently set to 2 frames.
+*
+* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8
+* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the
+* signal by 2.0, 0x80 scales the signal by 0.5. No protection is given
+* against over-scaling, if the multiplication factor times the input
+* signal exceeds 16 bits, overflow distortion will occur. The default
+* setting is 0x100 (1.0).
+*
+* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on
+* the most recently recorded frame as a 16 bit value.
+******************************************************************************/
+
+#define IXJCTL_REC_CODEC PHONE_REC_CODEC
+#define IXJCTL_REC_START PHONE_REC_START
+#define IXJCTL_REC_STOP PHONE_REC_STOP
+#define IXJCTL_REC_DEPTH PHONE_REC_DEPTH
+#define IXJCTL_FRAME PHONE_FRAME
+#define IXJCTL_REC_VOLUME PHONE_REC_VOLUME
+#define IXJCTL_REC_LEVEL PHONE_REC_LEVEL
+
+typedef enum {
+ f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50,
+ f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400,
+ f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450,
+ f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450,
+ f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587,
+ f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850,
+ f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400,
+ f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336,
+ lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860
+} IXJ_FILTER_FREQ;
+
+typedef struct {
+ unsigned int filter;
+ IXJ_FILTER_FREQ freq;
+ char enable;
+} IXJ_FILTER;
+
+#define IXJCTL_SET_FILTER _IOW ('q', 0xC7, IXJ_FILTER *)
+#define IXJCTL_GET_FILTER_HIST _IOW ('q', 0xC8, int)
+/******************************************************************************
+*
+* This IOCTL allows you to reassign values in the tone index table. The
+* tone table has 32 entries (0 - 31), but the driver only allows entries
+* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are
+* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D.
+* The positions used internally for Call Progress Tones are as follows:
+* Dial Tone - 25
+* Ring Back - 26
+* Busy Signal - 27
+*
+* The freq values are calculated as:
+* freq = cos(2 * PI * frequency / 8000)
+*
+* The most commonly needed values are already calculated and listed in the
+* enum IXJ_TONE_FREQ. Each tone index can have two frequencies with
+* different gains, if you are only using a single frequency set the unused
+* one to 0.
+*
+* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB
+* increments.
+*
+******************************************************************************/
+
+typedef enum {
+ hz20 = 0x7ffa,
+ hz50 = 0x7fe5,
+ hz133 = 0x7f4c,
+ hz200 = 0x7e6b,
+ hz261 = 0x7d50, /* .63 C1 */
+ hz277 = 0x7cfa, /* .18 CS1 */
+ hz293 = 0x7c9f, /* .66 D1 */
+ hz300 = 0x7c75,
+ hz311 = 0x7c32, /* .13 DS1 */
+ hz329 = 0x7bbf, /* .63 E1 */
+ hz330 = 0x7bb8,
+ hz340 = 0x7b75,
+ hz349 = 0x7b37, /* .23 F1 */
+ hz350 = 0x7b30,
+ hz360 = 0x7ae9,
+ hz369 = 0x7aa8, /* .99 FS1 */
+ hz380 = 0x7a56,
+ hz392 = 0x79fa, /* .00 G1 */
+ hz400 = 0x79bb,
+ hz415 = 0x7941, /* .30 GS1 */
+ hz420 = 0x7918,
+ hz425 = 0x78ee,
+ hz435 = 0x7899,
+ hz440 = 0x786d, /* .00 A1 */
+ hz445 = 0x7842,
+ hz450 = 0x7815,
+ hz452 = 0x7803,
+ hz466 = 0x7784, /* .16 AS1 */
+ hz475 = 0x7731,
+ hz480 = 0x7701,
+ hz493 = 0x7685, /* .88 B1 */
+ hz494 = 0x767b,
+ hz500 = 0x7640,
+ hz520 = 0x7578,
+ hz523 = 0x7559, /* .25 C2 */
+ hz525 = 0x7544,
+ hz540 = 0x74a7,
+ hz554 = 0x7411, /* .37 CS2 */
+ hz587 = 0x72a1, /* .33 D2 */
+ hz590 = 0x727f,
+ hz600 = 0x720b,
+ hz620 = 0x711e,
+ hz622 = 0x7106, /* .25 DS2 */
+ hz659 = 0x6f3b, /* .26 E2 */
+ hz660 = 0x6f2e,
+ hz698 = 0x6d3d, /* .46 F2 */
+ hz700 = 0x6d22,
+ hz739 = 0x6b09, /* .99 FS2 */
+ hz740 = 0x6afa,
+ hz750 = 0x6a6c,
+ hz770 = 0x694b,
+ hz783 = 0x688b, /* .99 G2 */
+ hz800 = 0x678d,
+ hz816 = 0x6698,
+ hz830 = 0x65bf, /* .61 GS2 */
+ hz850 = 0x6484,
+ hz857 = 0x6414,
+ hz880 = 0x629f, /* .00 A2 */
+ hz900 = 0x6154,
+ hz932 = 0x5f35, /* .33 AS2 */
+ hz935 = 0x5f01,
+ hz941 = 0x5e9a,
+ hz942 = 0x5e88,
+ hz950 = 0x5dfd,
+ hz975 = 0x5c44,
+ hz1000 = 0x5a81,
+ hz1020 = 0x5912,
+ hz1050 = 0x56e2,
+ hz1100 = 0x5320,
+ hz1140 = 0x5007,
+ hz1200 = 0x4b3b,
+ hz1209 = 0x4a80,
+ hz1215 = 0x4a02,
+ hz1250 = 0x471c,
+ hz1300 = 0x42e0,
+ hz1330 = 0x4049,
+ hz1336 = 0x3fc4,
+ hz1366 = 0x3d22,
+ hz1380 = 0x3be4,
+ hz1400 = 0x3a1b,
+ hz1450 = 0x3596,
+ hz1477 = 0x331c,
+ hz1500 = 0x30fb,
+ hz1600 = 0x278d,
+ hz1633 = 0x2462,
+ hz1638 = 0x23e7,
+ hz1645 = 0x233a,
+ hz1750 = 0x18f8,
+ hz1800 = 0x1405,
+ hz1860 = 0xe0b,
+ hz2100 = 0xf5f6,
+ hz2450 = 0xd3b3
+} IXJ_FREQ;
+
+typedef enum {
+ C1 = hz261,
+ CS1 = hz277,
+ D1 = hz293,
+ DS1 = hz311,
+ E1 = hz329,
+ F1 = hz349,
+ FS1 = hz369,
+ G1 = hz392,
+ GS1 = hz415,
+ A1 = hz440,
+ AS1 = hz466,
+ B1 = hz493,
+ C2 = hz523,
+ CS2 = hz554,
+ D2 = hz587,
+ DS2 = hz622,
+ E2 = hz659,
+ F2 = hz698,
+ FS2 = hz739,
+ G2 = hz783,
+ GS2 = hz830,
+ A2 = hz880,
+ AS2 = hz932,
+} IXJ_NOTE;
+
+typedef struct {
+ int tone_index;
+ int freq0;
+ int gain0;
+ int freq1;
+ int gain1;
+} IXJ_TONE;
+
+#define IXJCTL_INIT_TONE _IOW ('q', 0xC9, IXJ_TONE *)
+
+/******************************************************************************
+*
+* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various
+* Call Progress Tones (CPT). This is accomplished by setting up an array of
+* IXJ_CADENCE_ELEMENT structures that sequentially define the states of
+* the tone sequence. The tone_on_time and tone_off time are in
+* 250 microsecond intervals. A pointer to this array is passed to the
+* driver as the ce element of an IXJ_CADENCE structure. The elements_used
+* must be set to the number of IXJ_CADENCE_ELEMENTS in the array. The
+* termination variable defines what to do at the end of a cadence, the
+* options are to play the cadence once and stop, to repeat the last
+* element of the cadence indefinatly, or to repeat the entire cadence
+* indefinatly. The ce variable is a pointer to the array of IXJ_TONE
+* structures. If the freq0 variable is non-zero, the tone table contents
+* for the tone_index are updated to the frequencies and gains defined. It
+* should be noted that DTMF tones cannot be reassigned, so if DTMF tone
+* table indexs are used in a cadence the frequency and gain variables will
+* be ignored.
+*
+* If the array elements contain frequency parameters the driver will
+* initialize the needed tone table elements and begin playing the tone,
+* there is no preset limit on the number of elements in the cadence. If
+* there is more than one frequency used in the cadence, sequential elements
+* of different frequencies MUST use different tone table indexes. Only one
+* cadence can be played at a time. It is possible to build complex
+* cadences with multiple frequencies using 2 tone table indexes by
+* alternating between them.
+*
+******************************************************************************/
+
+typedef struct {
+ int index;
+ int tone_on_time;
+ int tone_off_time;
+ int freq0;
+ int gain0;
+ int freq1;
+ int gain1;
+} IXJ_CADENCE_ELEMENT;
+
+typedef enum {
+ PLAY_ONCE,
+ REPEAT_LAST_ELEMENT,
+ REPEAT_ALL
+} IXJ_CADENCE_TERM;
+
+typedef struct {
+ int elements_used;
+ IXJ_CADENCE_TERM termination;
+ IXJ_CADENCE_ELEMENT *ce;
+} IXJ_CADENCE;
+
+#define IXJCTL_TONE_CADENCE _IOW ('q', 0xCA, IXJ_CADENCE *)
+/******************************************************************************
+*
+* This group of IOCTLs deal with the playback settings of the DSP
+*
+******************************************************************************/
+
+#define IXJCTL_PLAY_CODEC PHONE_PLAY_CODEC
+#define IXJCTL_PLAY_START PHONE_PLAY_START
+#define IXJCTL_PLAY_STOP PHONE_PLAY_STOP
+#define IXJCTL_PLAY_DEPTH PHONE_PLAY_DEPTH
+#define IXJCTL_PLAY_VOLUME PHONE_PLAY_VOLUME
+#define IXJCTL_PLAY_LEVEL PHONE_PLAY_LEVEL
+
+/******************************************************************************
+*
+* This group of IOCTLs deal with the Acoustic Echo Cancellation settings
+* of the DSP
+*
+* Issuing the IXJCTL_AEC_START command with a value of AEC_OFF has the
+* same effect as IXJCTL_AEC_STOP. This is to simplify slider bar
+* controls. IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
+******************************************************************************/
+#define IXJCTL_AEC_START _IOW ('q', 0xCB, int)
+#define IXJCTL_AEC_STOP _IO ('q', 0xCC)
+#define IXJCTL_AEC_GET_LEVEL _IO ('q', 0xCD)
+
+#define AEC_OFF 0
+#define AEC_LOW 1
+#define AEC_MED 2
+#define AEC_HIGH 3
+/******************************************************************************
+*
+* Call Progress Tones, DTMF, etc.
+* IXJCTL_DTMF_OOB determines if dtmf signaling is sent as Out-Of-Band
+* only. If you pass a 1, dtmf is suppressed from the audio stream.
+* Tone on and off times are in 250 microsecond intervals so
+* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
+* will set the tone on time of board ixj1 to 360 * 250us = 90ms
+* the default values of tone on and off times is 840 or 210ms
+******************************************************************************/
+
+#define IXJCTL_DTMF_READY PHONE_DTMF_READY
+#define IXJCTL_GET_DTMF PHONE_GET_DTMF
+#define IXJCTL_GET_DTMF_ASCII PHONE_GET_DTMF_ASCII
+#define IXJCTL_DTMF_OOB PHONE_DTMF_OOB
+#define IXJCTL_EXCEPTION PHONE_EXCEPTION
+#define IXJCTL_PLAY_TONE PHONE_PLAY_TONE
+#define IXJCTL_SET_TONE_ON_TIME PHONE_SET_TONE_ON_TIME
+#define IXJCTL_SET_TONE_OFF_TIME PHONE_SET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_ON_TIME PHONE_GET_TONE_ON_TIME
+#define IXJCTL_GET_TONE_OFF_TIME PHONE_GET_TONE_OFF_TIME
+#define IXJCTL_GET_TONE_STATE PHONE_GET_TONE_STATE
+#define IXJCTL_BUSY PHONE_BUSY
+#define IXJCTL_RINGBACK PHONE_RINGBACK
+#define IXJCTL_DIALTONE PHONE_DIALTONE
+#define IXJCTL_CPT_STOP PHONE_CPT_STOP
+
+/******************************************************************************
+* LineJack specific IOCTLs
+*
+* The lsb 4 bits of the LED argument represent the state of each of the 4
+* LED's on the LineJack
+******************************************************************************/
+
+#define IXJCTL_SET_LED _IOW ('q', 0xCE, int)
+#define IXJCTL_MIXER _IOW ('q', 0xCF, int)
+
+/******************************************************************************
+*
+* The master volume controls use attenuation with 32 levels from 0 to -62dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+*
+******************************************************************************/
+#define MIXER_MASTER_L 0x0100
+#define MIXER_MASTER_R 0x0200
+#define ATT00DB 0x00
+#define ATT02DB 0x01
+#define ATT04DB 0x02
+#define ATT06DB 0x03
+#define ATT08DB 0x04
+#define ATT10DB 0x05
+#define ATT12DB 0x06
+#define ATT14DB 0x07
+#define ATT16DB 0x08
+#define ATT18DB 0x09
+#define ATT20DB 0x0A
+#define ATT22DB 0x0B
+#define ATT24DB 0x0C
+#define ATT26DB 0x0D
+#define ATT28DB 0x0E
+#define ATT30DB 0x0F
+#define ATT32DB 0x10
+#define ATT34DB 0x11
+#define ATT36DB 0x12
+#define ATT38DB 0x13
+#define ATT40DB 0x14
+#define ATT42DB 0x15
+#define ATT44DB 0x16
+#define ATT46DB 0x17
+#define ATT48DB 0x18
+#define ATT50DB 0x19
+#define ATT52DB 0x1A
+#define ATT54DB 0x1B
+#define ATT56DB 0x1C
+#define ATT58DB 0x1D
+#define ATT60DB 0x1E
+#define ATT62DB 0x1F
+#define MASTER_MUTE 0x80
+
+/******************************************************************************
+*
+* The input volume controls use gain with 32 levels from +12dB to -50dB
+* with steps of 2dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+*
+******************************************************************************/
+#define MIXER_PORT_CD_L 0x0600
+#define MIXER_PORT_CD_R 0x0700
+#define MIXER_PORT_LINE_IN_L 0x0800
+#define MIXER_PORT_LINE_IN_R 0x0900
+#define MIXER_PORT_POTS_REC 0x0C00
+#define MIXER_PORT_MIC 0x0E00
+
+#define GAIN12DB 0x00
+#define GAIN10DB 0x01
+#define GAIN08DB 0x02
+#define GAIN06DB 0x03
+#define GAIN04DB 0x04
+#define GAIN02DB 0x05
+#define GAIN00DB 0x06
+#define GAIN_02DB 0x07
+#define GAIN_04DB 0x08
+#define GAIN_06DB 0x09
+#define GAIN_08DB 0x0A
+#define GAIN_10DB 0x0B
+#define GAIN_12DB 0x0C
+#define GAIN_14DB 0x0D
+#define GAIN_16DB 0x0E
+#define GAIN_18DB 0x0F
+#define GAIN_20DB 0x10
+#define GAIN_22DB 0x11
+#define GAIN_24DB 0x12
+#define GAIN_26DB 0x13
+#define GAIN_28DB 0x14
+#define GAIN_30DB 0x15
+#define GAIN_32DB 0x16
+#define GAIN_34DB 0x17
+#define GAIN_36DB 0x18
+#define GAIN_38DB 0x19
+#define GAIN_40DB 0x1A
+#define GAIN_42DB 0x1B
+#define GAIN_44DB 0x1C
+#define GAIN_46DB 0x1D
+#define GAIN_48DB 0x1E
+#define GAIN_50DB 0x1F
+#define INPUT_MUTE 0x80
+
+/******************************************************************************
+*
+* The POTS volume control use attenuation with 8 levels from 0dB to -28dB
+* with steps of 4dB each, the defines should be OR'ed together then sent
+* as the parameter to the mixer command to change the mixer settings.
+*
+******************************************************************************/
+#define MIXER_PORT_POTS_PLAY 0x0F00
+
+#define POTS_ATT_00DB 0x00
+#define POTS_ATT_04DB 0x01
+#define POTS_ATT_08DB 0x02
+#define POTS_ATT_12DB 0x03
+#define POTS_ATT_16DB 0x04
+#define POTS_ATT_20DB 0x05
+#define POTS_ATT_24DB 0x06
+#define POTS_ATT_28DB 0x07
+#define POTS_MUTE 0x80
+
+/******************************************************************************
+*
+* The DAA controls the interface to the PSTN port. The driver loads the
+* US coefficients by default, so if you live in a different country you
+* need to load the set for your countries phone system.
+*
+******************************************************************************/
+#define IXJCTL_DAA_COEFF_SET _IOW ('q', 0xD0, int)
+
+#define DAA_US 1 //PITA 8kHz
+#define DAA_UK 2 //ISAR34 8kHz
+#define DAA_FRANCE 3 //
+#define DAA_GERMANY 4
+#define DAA_AUSTRALIA 5
+#define DAA_JAPAN 6
+
+/******************************************************************************
+*
+* Use IXJCTL_PORT to set or query the port the card is set to. If the
+* argument is set to PORT_QUERY, the return value of the ioctl will
+* indicate which port is currently in use, otherwise it will change the
+* port.
+*
+******************************************************************************/
+#define IXJCTL_PORT _IOW ('q', 0xD1, int)
+
+#define PORT_QUERY 0
+#define PORT_POTS 1
+#define PORT_PSTN 2
+#define PORT_SPEAKER 3
+#define PORT_HANDSET 4
+
+#define IXJCTL_PSTN_SET_STATE PHONE_PSTN_SET_STATE
+#define IXJCTL_PSTN_GET_STATE PHONE_PSTN_GET_STATE
+
+#define PSTN_ON_HOOK 0
+#define PSTN_RINGING 1
+#define PSTN_OFF_HOOK 2
+#define PSTN_PULSE_DIAL 3
+
+/******************************************************************************
+*
+* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR),
+* and the transmit gain (AGX). OR together the components and pass them
+* as the parameter to IXJCTL_DAA_AGAIN. The default setting is both at 0dB.
+*
+******************************************************************************/
+#define IXJCTL_DAA_AGAIN _IOW ('q', 0xD2, int)
+
+#define AGRR00DB 0x00 // Analog gain in receive direction 0dB
+#define AGRR3_5DB 0x10 // Analog gain in receive direction 3.5dB
+#define AGRR06DB 0x30 // Analog gain in receive direction 6dB
+
+#define AGX00DB 0x00 // Analog gain in transmit direction 0dB
+#define AGX_6DB 0x04 // Analog gain in transmit direction -6dB
+#define AGX3_5DB 0x08 // Analog gain in transmit direction 3.5dB
+#define AGX_2_5B 0x0C // Analog gain in transmit direction -2.5dB
+
+#define IXJCTL_PSTN_LINETEST _IO ('q', 0xD3)
+
+typedef struct {
+ char month[3];
+ char day[3];
+ char hour[3];
+ char min[3];
+ int numlen;
+ char number[11];
+ int namelen;
+ char name[80];
+} IXJ_CID;
+
+#define IXJCTL_CID _IOR ('q', 0xD4, IXJ_CID *)
+/******************************************************************************
+*
+* The wink duration is tunable with this ioctl. The default wink duration
+* is 320ms. You do not need to use this ioctl if you do not require a
+* different wink duration.
+*
+******************************************************************************/
+#define IXJCTL_WINK_DURATION PHONE_WINK_DURATION
+
+/******************************************************************************
+*
+* This ioctl will connect the POTS port to the PSTN port on the LineJACK
+* In order for this to work properly the port selection should be set to
+* the PSTN port with IXJCTL_PORT prior to calling this ioctl. This will
+* enable conference calls between PSTN callers and network callers.
+* Passing a 1 to this ioctl enables the POTS<->PSTN connection while
+* passing a 0 turns it back off.
+*
+******************************************************************************/
+#define IXJCTL_POTS_PSTN _IOW ('q', 0xD5, int)
+
+/******************************************************************************
+*
+* IOCTLs added by request.
+*
+* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in
+* /usr/include/asm/param.h, this determines the fundamental
+* frequency of the clock ticks on your Linux system. The kernel
+* must be rebuilt if you change this value, also all modules you
+* use (except this one) must be recompiled. The default value
+* is 100, and you only need to use this IOCTL if you use some
+* other value.
+*
+*
+* IXJCTL_RATE sets the number of times per second that the driver polls
+* the DSP. This value cannot be larger than HZ. By
+* increasing both of these values, you may be able to reduce
+* latency because the max hang time that can exist between the
+* driver and the DSP will be reduced.
+*
+******************************************************************************/
+
+#define IXJCTL_HZ _IOW ('q', 0xE0, int)
+#define IXJCTL_RATE _IOW ('q', 0xE1, int)
+#define IXJCTL_FRAMES_READ _IOR ('q', 0xE2, unsigned long)
+#define IXJCTL_FRAMES_WRITTEN _IOR ('q', 0xE3, unsigned long)
+#define IXJCTL_READ_WAIT _IOR ('q', 0xE4, unsigned long)
+#define IXJCTL_WRITE_WAIT _IOR ('q', 0xE5, unsigned long)
+#define IXJCTL_DRYBUFFER_READ _IOR ('q', 0xE6, unsigned long)
+#define IXJCTL_DRYBUFFER_CLEAR _IO ('q', 0xE7)
+
+/******************************************************************************
+*
+* The intercom IOCTL's short the output from one card to the input of the
+* other and vice versa (actually done in the DSP read function). It is only
+* necessary to execute the IOCTL on one card, but it is necessary to have
+* both devices open to be able to detect hook switch changes. The record
+* codec and rate of each card must match the playback codec and rate of
+* the other card for this to work properly.
+*
+******************************************************************************/
+
+#define IXJCTL_INTERCOM_START _IOW ('q', 0xFD, int)
+#define IXJCTL_INTERCOM_STOP _IOW ('q', 0xFE, int)
diff --git a/pfinet/linux-src/include/linux/joystick.h b/pfinet/linux-src/include/linux/joystick.h
new file mode 100644
index 00000000..b5b39d0f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/joystick.h
@@ -0,0 +1,280 @@
+#ifndef _LINUX_JOYSTICK_H
+#define _LINUX_JOYSTICK_H
+
+/*
+ * /usr/include/linux/joystick.h Version 1.2
+ *
+ * Copyright (C) 1996-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/types.h>
+#include <linux/module.h>
+
+/*
+ * Version
+ */
+
+#define JS_VERSION 0x01020f
+
+/*
+ * Types and constants for reading from /dev/js
+ */
+
+#define JS_EVENT_BUTTON 0x01 /* button pressed/released */
+#define JS_EVENT_AXIS 0x02 /* joystick moved */
+#define JS_EVENT_INIT 0x80 /* initial state of device */
+
+struct js_event {
+ __u32 time; /* event timestamp in miliseconds */
+ __s16 value; /* value */
+ __u8 type; /* event type */
+ __u8 number; /* axis/button number */
+};
+
+/*
+ * IOCTL commands for joystick driver
+ */
+
+#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */
+
+#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */
+#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */
+#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */
+
+#define JSIOCSCORR _IOW('j', 0x21, struct js_corr) /* set correction values */
+#define JSIOCGCORR _IOR('j', 0x22, struct js_corr) /* get correction values */
+
+/*
+ * Types and constants for get/set correction
+ */
+
+#define JS_CORR_NONE 0x00 /* returns raw values */
+#define JS_CORR_BROKEN 0x01 /* broken line */
+
+struct js_corr {
+ __s32 coef[8];
+ __s16 prec;
+ __u16 type;
+};
+
+/*
+ * v0.x compatibility definitions
+ */
+
+#define JS_RETURN sizeof(struct JS_DATA_TYPE)
+#define JS_TRUE 1
+#define JS_FALSE 0
+#define JS_X_0 0x01
+#define JS_Y_0 0x02
+#define JS_X_1 0x04
+#define JS_Y_1 0x08
+#define JS_MAX 2
+
+#define JS_DEF_TIMEOUT 0x1300
+#define JS_DEF_CORR 0
+#define JS_DEF_TIMELIMIT 10L
+
+#define JS_SET_CAL 1
+#define JS_GET_CAL 2
+#define JS_SET_TIMEOUT 3
+#define JS_GET_TIMEOUT 4
+#define JS_SET_TIMELIMIT 5
+#define JS_GET_TIMELIMIT 6
+#define JS_GET_ALL 7
+#define JS_SET_ALL 8
+
+struct JS_DATA_TYPE {
+ int buttons;
+ int x;
+ int y;
+};
+
+struct JS_DATA_SAVE_TYPE {
+ int JS_TIMEOUT;
+ int BUSY;
+ long JS_EXPIRETIME;
+ long JS_TIMELIMIT;
+ struct JS_DATA_TYPE JS_SAVE;
+ struct JS_DATA_TYPE JS_CORR;
+};
+
+/*
+ * Internal definitions
+ */
+
+#ifdef __KERNEL__
+
+#define JS_BUFF_SIZE 64 /* output buffer size */
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
+#error "You need to use at least v2.2 Linux kernel."
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#include <asm/spinlock.h>
+typedef struct wait_queue *wait_queue_head_t;
+#define __setup(a,b)
+#define BASE_ADDRESS(x,i) ((x)->base_address[i])
+#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = { y, NULL }
+#define init_waitqueue_head(x) do { *(x) = NULL; } while (0)
+#define __set_current_state(x) current->state = x
+#define SETUP_PARAM char *str, int *ints
+#define SETUP_PARSE(x) do {} while (0)
+#else
+#include <linux/spinlock.h>
+#define BASE_ADDRESS(x,i) ((x)->resource[i].start)
+#define SETUP_PARAM char *str
+#define SETUP_PARSE(x) int ints[x]; get_options(str, x, ints)
+#endif
+
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+
+/*
+ * Parport stuff
+ */
+
+#include <linux/parport.h>
+
+#define JS_PAR_STATUS_INVERT (0x80)
+#define JS_PAR_CTRL_INVERT (0x04)
+#define JS_PAR_DATA_IN(y) parport_read_data(y->port)
+#define JS_PAR_DATA_OUT(x,y) parport_write_data(y->port, x)
+#define JS_PAR_STATUS(y) parport_read_status(y->port)
+
+#ifndef PARPORT_NEED_GENERIC_OPS
+#define JS_PAR_CTRL_IN(y) parport_read_control(y->port)
+#else
+#define JS_PAR_CTRL_IN(y) inb(y->port->base+2)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define JS_PAR_CTRL_OUT(x,y) parport_write_control(y->port, x)
+#define JS_PAR_ECTRL_OUT(x,y) parport_write_econtrol(y->port, x)
+#else
+#define JS_PAR_CTRL_OUT(x,y) \
+ do { \
+ if ((x) & 0x20) parport_data_reverse(y->port); \
+ else parport_data_forward(y->port); \
+ parport_write_control(y->port, (x) & ~0x20); \
+ } while (0)
+#define JS_PAR_ECTRL_OUT(x,y) /*parport sets PS/2 mode on ECR chips */
+#define PARPORT_MODE_PCPS2 PARPORT_MODE_TRISTATE
+#define PARPORT_MODE_PCECPPS2 PARPORT_MODE_TRISTATE
+#endif
+
+/*
+ * Internal types
+ */
+
+struct js_dev;
+
+typedef int (*js_read_func)(void *info, int **axes, int **buttons);
+typedef int (*js_ops_func)(struct js_dev *dev);
+
+struct js_data {
+ int *axes;
+ int *buttons;
+};
+
+struct js_dev {
+ struct js_dev *next;
+ struct js_list *list;
+ struct js_port *port;
+ wait_queue_head_t wait;
+ struct js_data cur;
+ struct js_data new;
+ struct js_corr *corr;
+ struct js_event buff[JS_BUFF_SIZE];
+ js_ops_func open;
+ js_ops_func close;
+ int ahead;
+ int bhead;
+ int tail;
+ int num_axes;
+ int num_buttons;
+ char *name;
+};
+
+struct js_list {
+ struct js_list *next;
+ struct js_dev *dev;
+ int tail;
+ int startup;
+};
+
+struct js_port {
+ struct js_port *next;
+ struct js_port *prev;
+ js_read_func read;
+ struct js_dev **devs;
+ int **axes;
+ int **buttons;
+ struct js_corr **corr;
+ void *info;
+ int ndevs;
+ int fail;
+ int total;
+};
+
+/*
+ * Sub-module interface
+ */
+
+extern struct js_port *js_register_port(struct js_port *port, void *info,
+ int devs, int infos, js_read_func read);
+extern struct js_port *js_unregister_port(struct js_port *port);
+
+extern int js_register_device(struct js_port *port, int number, int axes,
+ int buttons, char *name, js_ops_func open, js_ops_func close);
+extern void js_unregister_device(struct js_dev *dev);
+
+/*
+ * Kernel interface
+ */
+
+extern int js_init(void);
+extern int js_am_init(void);
+extern int js_an_init(void);
+extern int js_as_init(void);
+extern int js_console_init(void);
+extern int js_cr_init(void);
+extern int js_db9_init(void);
+extern int js_gr_init(void);
+extern int js_l4_init(void);
+extern int js_lt_init(void);
+extern int js_mag_init(void);
+extern int js_pci_init(void);
+extern int js_sw_init(void);
+extern int js_sball_init(void);
+extern int js_orb_init(void);
+extern int js_tm_init(void);
+extern int js_tg_init(void);
+extern int js_war_init(void);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_JOYSTICK_H */
diff --git a/pfinet/linux-src/include/linux/kbd_diacr.h b/pfinet/linux-src/include/linux/kbd_diacr.h
new file mode 100644
index 00000000..1c1a3ff0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kbd_diacr.h
@@ -0,0 +1,8 @@
+#ifndef _DIACR_H
+#define _DIACR_H
+#include <linux/kd.h>
+
+extern struct kbdiacr accent_table[];
+extern unsigned int accent_table_size;
+
+#endif /* _DIACR_H */
diff --git a/pfinet/linux-src/include/linux/kbd_kern.h b/pfinet/linux-src/include/linux/kbd_kern.h
new file mode 100644
index 00000000..f5ae9ed9
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kbd_kern.h
@@ -0,0 +1,164 @@
+#ifndef _KBD_KERN_H
+#define _KBD_KERN_H
+
+#include <linux/interrupt.h>
+#include <linux/keyboard.h>
+
+extern int shift_state;
+
+extern char *func_table[MAX_NR_FUNC];
+extern char func_buf[];
+extern char *funcbufptr;
+extern int funcbufsize, funcbufleft;
+
+/*
+ * kbd->xxx contains the VC-local things (flag settings etc..)
+ *
+ * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h
+ * The code in KDGETLED / KDSETLED depends on the internal and
+ * external order being the same.
+ *
+ * Note: lockstate is used as index in the array key_map.
+ */
+struct kbd_struct {
+
+ unsigned char lockstate;
+/* 8 modifiers - the names do not have any meaning at all;
+ they can be associated to arbitrarily chosen keys */
+#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */
+#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */
+#define VC_CTRLLOCK KG_CTRL /* control lock mode */
+#define VC_ALTLOCK KG_ALT /* alt lock mode */
+#define VC_SHIFTLLOCK KG_SHIFTL /* shiftl lock mode */
+#define VC_SHIFTRLOCK KG_SHIFTR /* shiftr lock mode */
+#define VC_CTRLLLOCK KG_CTRLL /* ctrll lock mode */
+#define VC_CTRLRLOCK KG_CTRLR /* ctrlr lock mode */
+ unsigned char slockstate; /* for `sticky' Shift, Ctrl, etc. */
+
+ unsigned char ledmode:2; /* one 2-bit value */
+#define LED_SHOW_FLAGS 0 /* traditional state */
+#define LED_SHOW_IOCTL 1 /* only change leds upon ioctl */
+#define LED_SHOW_MEM 2 /* `heartbeat': peek into memory */
+
+ unsigned char ledflagstate:3; /* flags, not lights */
+ unsigned char default_ledflagstate:3;
+#define VC_SCROLLOCK 0 /* scroll-lock mode */
+#define VC_NUMLOCK 1 /* numeric lock mode */
+#define VC_CAPSLOCK 2 /* capslock mode */
+
+ unsigned char kbdmode:2; /* one 2-bit value */
+#define VC_XLATE 0 /* translate keycodes using keymap */
+#define VC_MEDIUMRAW 1 /* medium raw (keycode) mode */
+#define VC_RAW 2 /* raw (scancode) mode */
+#define VC_UNICODE 3 /* Unicode mode */
+
+ unsigned char modeflags:5;
+#define VC_APPLIC 0 /* application key mode */
+#define VC_CKMODE 1 /* cursor key mode */
+#define VC_REPEAT 2 /* keyboard repeat */
+#define VC_CRLF 3 /* 0 - enter sends CR, 1 - enter sends CRLF */
+#define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */
+};
+
+extern struct kbd_struct kbd_table[];
+
+extern int kbd_init(void);
+
+extern unsigned char getledstate(void);
+extern void setledstate(struct kbd_struct *kbd, unsigned int led);
+
+extern int do_poke_blanked_console;
+
+extern inline void show_console(void)
+{
+ do_poke_blanked_console = 1;
+ mark_bh(CONSOLE_BH);
+}
+
+extern inline void set_console(int nr)
+{
+ want_console = nr;
+ mark_bh(CONSOLE_BH);
+}
+
+extern inline void set_leds(void)
+{
+ mark_bh(KEYBOARD_BH);
+}
+
+extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ return ((kbd->modeflags >> flag) & 1);
+}
+
+extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ return ((kbd->ledflagstate >> flag) & 1);
+}
+
+extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ kbd->modeflags |= 1 << flag;
+}
+
+extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ kbd->ledflagstate |= 1 << flag;
+}
+
+extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ kbd->modeflags &= ~(1 << flag);
+}
+
+extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ kbd->ledflagstate &= ~(1 << flag);
+}
+
+extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+{
+ kbd->lockstate ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
+{
+ kbd->slockstate ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ kbd->modeflags ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ kbd->ledflagstate ^= 1 << flag;
+}
+
+#define U(x) ((x) ^ 0xf000)
+
+/* keyboard.c */
+
+struct console;
+
+int getkeycode(unsigned int scancode);
+int setkeycode(unsigned int scancode, unsigned int keycode);
+void compute_shiftstate(void);
+int keyboard_wait_for_keypress(struct console *);
+
+/* defkeymap.c */
+
+extern unsigned int keymap_count;
+
+/* console.c */
+
+extern task_queue con_task_queue;
+
+extern inline void con_schedule_flip(struct tty_struct *t)
+{
+ queue_task(&t->flip.tqueue, &con_task_queue);
+ mark_bh(CONSOLE_BH);
+}
+
+#endif
diff --git a/pfinet/linux-src/include/linux/kbd_ll.h b/pfinet/linux-src/include/linux/kbd_ll.h
new file mode 100644
index 00000000..02ebf8ec
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kbd_ll.h
@@ -0,0 +1,12 @@
+/*
+ * Interface between the low-level keyboard driver and the keymapper
+ */
+
+#ifndef _KBD_LL_H
+#define _KBD_LL_H
+
+extern struct pt_regs *kbd_pt_regs;
+
+void handle_scancode(unsigned char scancode, int down);
+
+#endif /* _KBD_LL_H */
diff --git a/pfinet/linux-src/include/linux/kd.h b/pfinet/linux-src/include/linux/kd.h
new file mode 100644
index 00000000..c717c198
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kd.h
@@ -0,0 +1,180 @@
+#ifndef _LINUX_KD_H
+#define _LINUX_KD_H
+#include <linux/types.h>
+
+/* 0x4B is 'K', to avoid collision with termios and vt */
+
+#define GIO_FONT 0x4B60 /* gets font in expanded form */
+#define PIO_FONT 0x4B61 /* use font in expanded form */
+
+#define GIO_FONTX 0x4B6B /* get font using struct consolefontdesc */
+#define PIO_FONTX 0x4B6C /* set font using struct consolefontdesc */
+struct consolefontdesc {
+ unsigned short charcount; /* characters in font (256 or 512) */
+ unsigned short charheight; /* scan lines per character (1-32) */
+ char *chardata; /* font data in expanded form */
+};
+
+#define PIO_FONTRESET 0x4B6D /* reset to default font */
+
+#define GIO_CMAP 0x4B70 /* gets colour palette on VGA+ */
+#define PIO_CMAP 0x4B71 /* sets colour palette on VGA+ */
+
+#define KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
+#define KDMKTONE 0x4B30 /* generate tone */
+
+#define KDGETLED 0x4B31 /* return current led state */
+#define KDSETLED 0x4B32 /* set led state [lights, not flags] */
+#define LED_SCR 0x01 /* scroll lock led */
+#define LED_CAP 0x04 /* caps lock led */
+#define LED_NUM 0x02 /* num lock led */
+
+#define KDGKBTYPE 0x4B33 /* get keyboard type */
+#define KB_84 0x01
+#define KB_101 0x02 /* this is what we always answer */
+#define KB_OTHER 0x03
+
+#define KDADDIO 0x4B34 /* add i/o port as valid */
+#define KDDELIO 0x4B35 /* del i/o port as valid */
+#define KDENABIO 0x4B36 /* enable i/o to video board */
+#define KDDISABIO 0x4B37 /* disable i/o to video board */
+
+#define KDSETMODE 0x4B3A /* set text/graphics mode */
+#define KD_TEXT 0x00
+#define KD_GRAPHICS 0x01
+#define KD_TEXT0 0x02 /* obsolete */
+#define KD_TEXT1 0x03 /* obsolete */
+#define KDGETMODE 0x4B3B /* get current mode */
+
+#define KDMAPDISP 0x4B3C /* map display into address space */
+#define KDUNMAPDISP 0x4B3D /* unmap display from address space */
+
+typedef char scrnmap_t;
+#define E_TABSZ 256
+#define GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */
+#define PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */
+#define GIO_UNISCRNMAP 0x4B69 /* get full Unicode screen mapping */
+#define PIO_UNISCRNMAP 0x4B6A /* set full Unicode screen mapping */
+
+#define GIO_UNIMAP 0x4B66 /* get unicode-to-font mapping from kernel */
+struct unipair {
+ unsigned short unicode;
+ unsigned short fontpos;
+};
+struct unimapdesc {
+ unsigned short entry_ct;
+ struct unipair *entries;
+};
+#define PIO_UNIMAP 0x4B67 /* put unicode-to-font mapping in kernel */
+#define PIO_UNIMAPCLR 0x4B68 /* clear table, possibly advise hash algorithm */
+struct unimapinit {
+ unsigned short advised_hashsize; /* 0 if no opinion */
+ unsigned short advised_hashstep; /* 0 if no opinion */
+ unsigned short advised_hashlevel; /* 0 if no opinion */
+};
+
+#define UNI_DIRECT_BASE 0xF000 /* start of Direct Font Region */
+#define UNI_DIRECT_MASK 0x01FF /* Direct Font Region bitmask */
+
+#define K_RAW 0x00
+#define K_XLATE 0x01
+#define K_MEDIUMRAW 0x02
+#define K_UNICODE 0x03
+#define KDGKBMODE 0x4B44 /* gets current keyboard mode */
+#define KDSKBMODE 0x4B45 /* sets current keyboard mode */
+
+#define K_METABIT 0x03
+#define K_ESCPREFIX 0x04
+#define KDGKBMETA 0x4B62 /* gets meta key handling mode */
+#define KDSKBMETA 0x4B63 /* sets meta key handling mode */
+
+#define K_SCROLLLOCK 0x01
+#define K_CAPSLOCK 0x02
+#define K_NUMLOCK 0x04
+#define KDGKBLED 0x4B64 /* get led flags (not lights) */
+#define KDSKBLED 0x4B65 /* set led flags (not lights) */
+
+struct kbentry {
+ unsigned char kb_table;
+ unsigned char kb_index;
+ unsigned short kb_value;
+};
+#define K_NORMTAB 0x00
+#define K_SHIFTTAB 0x01
+#define K_ALTTAB 0x02
+#define K_ALTSHIFTTAB 0x03
+
+#define KDGKBENT 0x4B46 /* gets one entry in translation table */
+#define KDSKBENT 0x4B47 /* sets one entry in translation table */
+
+struct kbsentry {
+ unsigned char kb_func;
+ unsigned char kb_string[512];
+};
+#define KDGKBSENT 0x4B48 /* gets one function key string entry */
+#define KDSKBSENT 0x4B49 /* sets one function key string entry */
+
+struct kbdiacr {
+ unsigned char diacr, base, result;
+};
+struct kbdiacrs {
+ unsigned int kb_cnt; /* number of entries in following array */
+ struct kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */
+};
+#define KDGKBDIACR 0x4B4A /* read kernel accent table */
+#define KDSKBDIACR 0x4B4B /* write kernel accent table */
+
+struct kbkeycode {
+ unsigned int scancode, keycode;
+};
+#define KDGETKEYCODE 0x4B4C /* read kernel keycode table entry */
+#define KDSETKEYCODE 0x4B4D /* write kernel keycode table entry */
+
+#define KDSIGACCEPT 0x4B4E /* accept kbd generated signals */
+
+struct hwclk_time {
+ unsigned sec; /* 0..59 */
+ unsigned min; /* 0..59 */
+ unsigned hour; /* 0..23 */
+ unsigned day; /* 1..31 */
+ unsigned mon; /* 0..11 */
+ unsigned year; /* 70... */
+ int wday; /* 0..6, 0 is Sunday, -1 means unknown/don't set */
+};
+
+#define KDGHWCLK 0x4B50 /* get hardware clock */
+#define KDSHWCLK 0x4B51 /* set hardware clock */
+
+struct kbd_repeat {
+ int delay; /* in msec; <= 0: don't change */
+ int rate; /* in msec; <= 0: don't change */
+};
+
+#define KDKBDREP 0x4B52 /* set keyboard delay/repeat rate;
+ * actually used values are returned */
+
+#define KDFONTOP 0x4B72 /* font operations */
+
+struct console_font_op {
+ unsigned int op; /* operation code KD_FONT_OP_* */
+ unsigned int flags; /* KD_FONT_FLAG_* */
+ unsigned int width, height; /* font size */
+ unsigned int charcount;
+ unsigned char *data; /* font data with height fixed to 32 */
+};
+
+#define KD_FONT_OP_SET 0 /* Set font */
+#define KD_FONT_OP_GET 1 /* Get font */
+#define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, data points to name / NULL */
+#define KD_FONT_OP_COPY 3 /* Copy from another console */
+
+#define KD_FONT_FLAG_DONT_RECALC 1 /* Don't recalculate hw charcell size [compat] */
+#ifdef __KERNEL__
+#define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface [compat] */
+#endif
+
+/* note: 0x4B00-0x4B4E all have had a value at some time;
+ don't reuse for the time being */
+/* note: 0x4B60-0x4B6D, 0x4B70-0x4B72 used above */
+
+#endif /* _LINUX_KD_H */
diff --git a/pfinet/linux-src/include/linux/kdev_t.h b/pfinet/linux-src/include/linux/kdev_t.h
new file mode 100644
index 00000000..a06cdb9e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kdev_t.h
@@ -0,0 +1,114 @@
+#ifndef _LINUX_KDEV_T_H
+#define _LINUX_KDEV_T_H
+#ifdef __KERNEL__
+/*
+As a preparation for the introduction of larger device numbers,
+we introduce a type kdev_t to hold them. No information about
+this type is known outside of this include file.
+
+Objects of type kdev_t designate a device. Outside of the kernel
+the corresponding things are objects of type dev_t - usually an
+integral type with the device major and minor in the high and low
+bits, respectively. Conversion is done by
+
+extern kdev_t to_kdev_t(int);
+
+It is up to the various file systems to decide how objects of type
+dev_t are stored on disk.
+The only other point of contact between kernel and outside world
+are the system calls stat and mknod, new versions of which will
+eventually have to be used in libc.
+
+[Unfortunately, the floppy control ioctls fail to hide the internal
+kernel structures, and the fd_device field of a struct floppy_drive_struct
+is user-visible. So, it remains a dev_t for the moment, with some ugly
+conversions in floppy.c.]
+
+Inside the kernel, we aim for a kdev_t type that is a pointer
+to a structure with information about the device (like major,
+minor, size, blocksize, sectorsize, name, read-only flag,
+struct file_operations etc.).
+
+However, for the time being we let kdev_t be almost the same as dev_t:
+
+typedef struct { unsigned short major, minor; } kdev_t;
+
+Admissible operations on an object of type kdev_t:
+- passing it along
+- comparing it for equality with another such object
+- storing it in ROOT_DEV, inode->i_dev, inode->i_rdev, sb->s_dev,
+ bh->b_dev, req->rq_dev, de->dc_dev, tty->device
+- using its bit pattern as argument in a hash function
+- finding its major and minor
+- complaining about it
+
+An object of type kdev_t is created only by the function MKDEV(),
+with the single exception of the constant 0 (no device).
+
+Right now the other information mentioned above is usually found
+in static arrays indexed by major or major,minor.
+
+An obstacle to immediately using
+ typedef struct { ... (* lots of information *) } *kdev_t
+is the case of mknod used to create a block device that the
+kernel doesn't know about at present (but first learns about
+when some module is inserted).
+
+aeb - 950811
+*/
+
+/* Since MINOR(dev) is used as index in static arrays,
+ the kernel is not quite ready yet for larger minors.
+ However, everything runs fine with an arbitrary kdev_t type. */
+
+#define MINORBITS 8
+#define MINORMASK ((1U << MINORBITS) - 1)
+
+typedef unsigned short kdev_t;
+
+#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
+#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
+#define HASHDEV(dev) ((unsigned int) (dev))
+#define NODEV 0
+#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
+#define B_FREE 0xffff /* yuk */
+
+extern char * kdevname(kdev_t); /* note: returns pointer to static data! */
+
+/*
+As long as device numbers in the outside world have 16 bits only,
+we use these conversions.
+*/
+
+static inline unsigned int kdev_t_to_nr(kdev_t dev) {
+ return (MAJOR(dev)<<8) | MINOR(dev);
+}
+
+static inline kdev_t to_kdev_t(int dev)
+{
+ int major, minor;
+#if 0
+ major = (dev >> 16);
+ if (!major) {
+ major = (dev >> 8);
+ minor = (dev & 0xff);
+ } else
+ minor = (dev & 0xffff);
+#else
+ major = (dev >> 8);
+ minor = (dev & 0xff);
+#endif
+ return MKDEV(major, minor);
+}
+
+#else /* __KERNEL__ */
+
+/*
+Some programs want their definitions of MAJOR and MINOR and MKDEV
+from the kernel sources. These must be the externally visible ones.
+*/
+#define MAJOR(dev) ((dev)>>8)
+#define MINOR(dev) ((dev) & 0xff)
+#define MKDEV(ma,mi) ((ma)<<8 | (mi))
+#endif /* __KERNEL__ */
+#endif
diff --git a/pfinet/linux-src/include/linux/kernel.h b/pfinet/linux-src/include/linux/kernel.h
new file mode 100644
index 00000000..73a0a689
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kernel.h
@@ -0,0 +1,96 @@
+#ifndef _LINUX_KERNEL_H
+#define _LINUX_KERNEL_H
+
+/*
+ * 'kernel.h' contains some often-used function prototypes etc
+ */
+
+#ifdef __KERNEL__
+
+#include <stdarg.h>
+#include <linux/linkage.h>
+
+/* Optimization barrier */
+/* The "volatile" is due to gcc bugs */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#define INT_MAX ((int)(~0U>>1))
+#define UINT_MAX (~0U)
+#define LONG_MAX ((long)(~0UL>>1))
+#define ULONG_MAX (~0UL)
+
+#define STACK_MAGIC 0xdeadbeef
+
+#define KERN_EMERG "<0>" /* system is unusable */
+#define KERN_ALERT "<1>" /* action must be taken immediately */
+#define KERN_CRIT "<2>" /* critical conditions */
+#define KERN_ERR "<3>" /* error conditions */
+#define KERN_WARNING "<4>" /* warning conditions */
+#define KERN_NOTICE "<5>" /* normal but significant condition */
+#define KERN_INFO "<6>" /* informational */
+#define KERN_DEBUG "<7>" /* debug-level messages */
+
+# define NORET_TYPE /**/
+# define ATTRIB_NORET __attribute__((noreturn))
+# define NORET_AND noreturn,
+
+#ifdef __i386__
+#define FASTCALL(x) x __attribute__((regparm(3)))
+#else
+#define FASTCALL(x) x
+#endif
+
+extern void math_error(void);
+extern struct notifier_block *panic_notifier_list;
+NORET_TYPE void panic(const char * fmt, ...)
+ __attribute__ ((NORET_AND format (printf, 1, 2)));
+NORET_TYPE void do_exit(long error_code)
+ ATTRIB_NORET;
+extern unsigned long simple_strtoul(const char *,char **,unsigned int);
+extern long simple_strtol(const char *,char **,unsigned int);
+extern int sprintf(char * buf, const char * fmt, ...);
+extern int vsprintf(char *buf, const char *, va_list);
+
+extern int session_of_pgrp(int pgrp);
+
+asmlinkage int printk(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+#if DEBUG
+#define pr_debug(fmt,arg...) \
+ printk(KERN_DEBUG fmt,##arg)
+#else
+#define pr_debug(fmt,arg...) \
+ do { } while (0)
+#endif
+
+#define pr_info(fmt,arg...) \
+ printk(KERN_INFO fmt,##arg)
+
+/*
+ * Display an IP address in readable format.
+ */
+
+#define NIPQUAD(addr) \
+ ((unsigned char *)&addr)[0], \
+ ((unsigned char *)&addr)[1], \
+ ((unsigned char *)&addr)[2], \
+ ((unsigned char *)&addr)[3]
+
+#endif /* __KERNEL__ */
+
+#define SI_LOAD_SHIFT 16
+struct sysinfo {
+ long uptime; /* Seconds since boot */
+ unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
+ unsigned long totalram; /* Total usable main memory size */
+ unsigned long freeram; /* Available memory size */
+ unsigned long sharedram; /* Amount of shared memory */
+ unsigned long bufferram; /* Memory used by buffers */
+ unsigned long totalswap; /* Total swap space size */
+ unsigned long freeswap; /* swap space still available */
+ unsigned short procs; /* Number of current processes */
+ char _f[22]; /* Pads structure to 64 bytes */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/kernel_stat.h b/pfinet/linux-src/include/linux/kernel_stat.h
new file mode 100644
index 00000000..cd584c1a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kernel_stat.h
@@ -0,0 +1,50 @@
+#ifndef _LINUX_KERNEL_STAT_H
+#define _LINUX_KERNEL_STAT_H
+
+#include <asm/irq.h>
+#include <linux/smp.h>
+#include <linux/tasks.h>
+
+/*
+ * 'kernel_stat.h' contains the definitions needed for doing
+ * some kernel statistics (CPU usage, context switches ...),
+ * used by rstatd/perfmeter
+ */
+
+#define DK_NDRIVE 4
+
+struct kernel_stat {
+ unsigned int cpu_user, cpu_nice, cpu_system;
+ unsigned int per_cpu_user[NR_CPUS],
+ per_cpu_nice[NR_CPUS],
+ per_cpu_system[NR_CPUS];
+ unsigned int dk_drive[DK_NDRIVE];
+ unsigned int dk_drive_rio[DK_NDRIVE];
+ unsigned int dk_drive_wio[DK_NDRIVE];
+ unsigned int dk_drive_rblk[DK_NDRIVE];
+ unsigned int dk_drive_wblk[DK_NDRIVE];
+ unsigned int pgpgin, pgpgout;
+ unsigned int pswpin, pswpout;
+ unsigned int irqs[NR_CPUS][NR_IRQS];
+ unsigned int ipackets, opackets;
+ unsigned int ierrors, oerrors;
+ unsigned int collisions;
+ unsigned int context_swtch;
+};
+
+extern struct kernel_stat kstat;
+
+/*
+ * Number of interrupts per specific IRQ source, since bootup
+ */
+extern inline int kstat_irqs (int irq)
+{
+ int i, sum=0;
+
+ for (i = 0 ; i < smp_num_cpus ; i++)
+ sum += kstat.irqs[cpu_logical_map(i)][irq];
+
+ return sum;
+}
+
+#endif /* _LINUX_KERNEL_STAT_H */
diff --git a/pfinet/linux-src/include/linux/kernelcapi.h b/pfinet/linux-src/include/linux/kernelcapi.h
new file mode 100644
index 00000000..5778d2eb
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kernelcapi.h
@@ -0,0 +1,140 @@
+/*
+ * $Id: kernelcapi.h,v 1.4 1999/09/10 17:24:19 calle Exp $
+ *
+ * Kernel CAPI 2.0 Interface for Linux
+ *
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: kernelcapi.h,v $
+ * Revision 1.4 1999/09/10 17:24:19 calle
+ * Changes for proposed standard for CAPI2.0:
+ * - AK148 "Linux Exention"
+ *
+ * Revision 1.3 1999/07/01 15:26:56 calle
+ * complete new version (I love it):
+ * + new hardware independed "capi_driver" interface that will make it easy to:
+ * - support other controllers with CAPI-2.0 (i.e. USB Controller)
+ * - write a CAPI-2.0 for the passive cards
+ * - support serial link CAPI-2.0 boxes.
+ * + wrote "capi_driver" for all supported cards.
+ * + "capi_driver" (supported cards) now have to be configured with
+ * make menuconfig, in the past all supported cards where included
+ * at once.
+ * + new and better informations in /proc/capi/
+ * + new ioctl to switch trace of capi messages per controller
+ * using "avmcapictrl trace [contr] on|off|...."
+ * + complete testcircle with all supported cards and also the
+ * PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
+ *
+ * Revision 1.2 1999/06/21 15:24:26 calle
+ * extend information in /proc.
+ *
+ * Revision 1.1 1997/03/04 21:27:33 calle
+ * First version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ *
+ */
+#ifndef __KERNELCAPI_H__
+#define __KERNELCAPI_H__
+
+#define CAPI_MAXAPPL 20 /*
+ * maximum number of applications
+ */
+#define CAPI_MAXCONTR 10 /*
+ * maximum number of controller
+ */
+#define CAPI_MAXDATAWINDOW 8
+
+
+typedef struct kcapi_flagdef {
+ int contr;
+ int flag;
+} kcapi_flagdef;
+
+/* new ioctls >= 10 */
+#define KCAPI_CMD_TRACE 10
+
+/*
+ * flag > 2 => trace also data
+ * flag & 1 => show trace
+ */
+#define KCAPI_TRACE_OFF 0
+#define KCAPI_TRACE_SHORT_NO_DATA 1
+#define KCAPI_TRACE_FULL_NO_DATA 2
+#define KCAPI_TRACE_SHORT 3
+#define KCAPI_TRACE_FULL 4
+
+
+#ifdef __KERNEL__
+
+struct capi_interface {
+ __u16 (*capi_isinstalled) (void);
+
+ __u16 (*capi_register) (capi_register_params * rparam, __u16 * applidp);
+ __u16 (*capi_release) (__u16 applid);
+ __u16 (*capi_put_message) (__u16 applid, struct sk_buff * msg);
+ __u16 (*capi_get_message) (__u16 applid, struct sk_buff ** msgp);
+ __u16 (*capi_set_signal) (__u16 applid,
+ void (*signal) (__u16 applid, __u32 param),
+ __u32 param);
+ __u16 (*capi_get_manufacturer) (__u32 contr, __u8 buf[CAPI_MANUFACTURER_LEN]);
+ __u16 (*capi_get_version) (__u32 contr, struct capi_version * verp);
+ __u16(*capi_get_serial) (__u32 contr, __u8 serial[CAPI_SERIAL_LEN]);
+ __u16(*capi_get_profile) (__u32 contr, struct capi_profile * profp);
+
+ /*
+ * to init controllers, data is always in user memory
+ */
+ int (*capi_manufacturer) (unsigned int cmd, void *data);
+
+};
+
+#define KCI_CONTRUP 0
+#define KCI_CONTRDOWN 1
+
+struct capi_interface_user {
+ char name[20];
+ void (*callback) (unsigned int cmd, __u32 contr, void *data);
+ /* internal */
+ struct capi_interface_user *next;
+};
+
+struct capi_interface *attach_capi_interface(struct capi_interface_user *);
+int detach_capi_interface(struct capi_interface_user *);
+
+
+#define CAPI_NOERROR 0x0000
+
+#define CAPI_TOOMANYAPPLS 0x1001
+#define CAPI_LOGBLKSIZETOSMALL 0x1002
+#define CAPI_BUFFEXECEEDS64K 0x1003
+#define CAPI_MSGBUFSIZETOOSMALL 0x1004
+#define CAPI_ANZLOGCONNNOTSUPPORTED 0x1005
+#define CAPI_REGRESERVED 0x1006
+#define CAPI_REGBUSY 0x1007
+#define CAPI_REGOSRESOURCEERR 0x1008
+#define CAPI_REGNOTINSTALLED 0x1009
+#define CAPI_REGCTRLERNOTSUPPORTEXTEQUIP 0x100a
+#define CAPI_REGCTRLERONLYSUPPORTEXTEQUIP 0x100b
+
+#define CAPI_ILLAPPNR 0x1101
+#define CAPI_ILLCMDORSUBCMDORMSGTOSMALL 0x1102
+#define CAPI_SENDQUEUEFULL 0x1103
+#define CAPI_RECEIVEQUEUEEMPTY 0x1104
+#define CAPI_RECEIVEOVERFLOW 0x1105
+#define CAPI_UNKNOWNNOTPAR 0x1106
+#define CAPI_MSGBUSY 0x1107
+#define CAPI_MSGOSRESOURCEERR 0x1108
+#define CAPI_MSGNOTINSTALLED 0x1109
+#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a
+#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b
+
+#endif /* __KERNEL__ */
+
+#endif /* __KERNELCAPI_H__ */
diff --git a/pfinet/linux-src/include/linux/keyboard.h b/pfinet/linux-src/include/linux/keyboard.h
new file mode 100644
index 00000000..6829c653
--- /dev/null
+++ b/pfinet/linux-src/include/linux/keyboard.h
@@ -0,0 +1,430 @@
+#ifndef __LINUX_KEYBOARD_H
+#define __LINUX_KEYBOARD_H
+
+#define KG_SHIFT 0
+#define KG_CTRL 2
+#define KG_ALT 3
+#define KG_ALTGR 1
+#define KG_SHIFTL 4
+#define KG_SHIFTR 5
+#define KG_CTRLL 6
+#define KG_CTRLR 7
+#define KG_CAPSSHIFT 8
+
+#define NR_SHIFT 9
+
+#define NR_KEYS 128
+#define MAX_NR_KEYMAPS 256
+/* This means 64Kb if all keymaps are allocated. Only the superuser
+ may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */
+#define MAX_NR_OF_USER_KEYMAPS 256 /* should be at least 7 */
+
+#ifdef __KERNEL__
+extern const int NR_TYPES;
+extern const int max_vals[];
+extern unsigned short *key_maps[MAX_NR_KEYMAPS];
+extern unsigned short plain_map[NR_KEYS];
+extern struct wait_queue * keypress_wait;
+extern unsigned char keyboard_type;
+#endif
+
+#define MAX_NR_FUNC 256 /* max nr of strings assigned to keys */
+
+#define KT_LATIN 0 /* we depend on this being zero */
+#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */
+#define KT_FN 1
+#define KT_SPEC 2
+#define KT_PAD 3
+#define KT_DEAD 4
+#define KT_CONS 5
+#define KT_CUR 6
+#define KT_SHIFT 7
+#define KT_META 8
+#define KT_ASCII 9
+#define KT_LOCK 10
+#define KT_SLOCK 12
+
+#define K(t,v) (((t)<<8)|(v))
+#define KTYP(x) ((x) >> 8)
+#define KVAL(x) ((x) & 0xff)
+
+#define K_F1 K(KT_FN,0)
+#define K_F2 K(KT_FN,1)
+#define K_F3 K(KT_FN,2)
+#define K_F4 K(KT_FN,3)
+#define K_F5 K(KT_FN,4)
+#define K_F6 K(KT_FN,5)
+#define K_F7 K(KT_FN,6)
+#define K_F8 K(KT_FN,7)
+#define K_F9 K(KT_FN,8)
+#define K_F10 K(KT_FN,9)
+#define K_F11 K(KT_FN,10)
+#define K_F12 K(KT_FN,11)
+#define K_F13 K(KT_FN,12)
+#define K_F14 K(KT_FN,13)
+#define K_F15 K(KT_FN,14)
+#define K_F16 K(KT_FN,15)
+#define K_F17 K(KT_FN,16)
+#define K_F18 K(KT_FN,17)
+#define K_F19 K(KT_FN,18)
+#define K_F20 K(KT_FN,19)
+#define K_FIND K(KT_FN,20)
+#define K_INSERT K(KT_FN,21)
+#define K_REMOVE K(KT_FN,22)
+#define K_SELECT K(KT_FN,23)
+#define K_PGUP K(KT_FN,24) /* PGUP is a synonym for PRIOR */
+#define K_PGDN K(KT_FN,25) /* PGDN is a synonym for NEXT */
+#define K_MACRO K(KT_FN,26)
+#define K_HELP K(KT_FN,27)
+#define K_DO K(KT_FN,28)
+#define K_PAUSE K(KT_FN,29)
+#define K_F21 K(KT_FN,30)
+#define K_F22 K(KT_FN,31)
+#define K_F23 K(KT_FN,32)
+#define K_F24 K(KT_FN,33)
+#define K_F25 K(KT_FN,34)
+#define K_F26 K(KT_FN,35)
+#define K_F27 K(KT_FN,36)
+#define K_F28 K(KT_FN,37)
+#define K_F29 K(KT_FN,38)
+#define K_F30 K(KT_FN,39)
+#define K_F31 K(KT_FN,40)
+#define K_F32 K(KT_FN,41)
+#define K_F33 K(KT_FN,42)
+#define K_F34 K(KT_FN,43)
+#define K_F35 K(KT_FN,44)
+#define K_F36 K(KT_FN,45)
+#define K_F37 K(KT_FN,46)
+#define K_F38 K(KT_FN,47)
+#define K_F39 K(KT_FN,48)
+#define K_F40 K(KT_FN,49)
+#define K_F41 K(KT_FN,50)
+#define K_F42 K(KT_FN,51)
+#define K_F43 K(KT_FN,52)
+#define K_F44 K(KT_FN,53)
+#define K_F45 K(KT_FN,54)
+#define K_F46 K(KT_FN,55)
+#define K_F47 K(KT_FN,56)
+#define K_F48 K(KT_FN,57)
+#define K_F49 K(KT_FN,58)
+#define K_F50 K(KT_FN,59)
+#define K_F51 K(KT_FN,60)
+#define K_F52 K(KT_FN,61)
+#define K_F53 K(KT_FN,62)
+#define K_F54 K(KT_FN,63)
+#define K_F55 K(KT_FN,64)
+#define K_F56 K(KT_FN,65)
+#define K_F57 K(KT_FN,66)
+#define K_F58 K(KT_FN,67)
+#define K_F59 K(KT_FN,68)
+#define K_F60 K(KT_FN,69)
+#define K_F61 K(KT_FN,70)
+#define K_F62 K(KT_FN,71)
+#define K_F63 K(KT_FN,72)
+#define K_F64 K(KT_FN,73)
+#define K_F65 K(KT_FN,74)
+#define K_F66 K(KT_FN,75)
+#define K_F67 K(KT_FN,76)
+#define K_F68 K(KT_FN,77)
+#define K_F69 K(KT_FN,78)
+#define K_F70 K(KT_FN,79)
+#define K_F71 K(KT_FN,80)
+#define K_F72 K(KT_FN,81)
+#define K_F73 K(KT_FN,82)
+#define K_F74 K(KT_FN,83)
+#define K_F75 K(KT_FN,84)
+#define K_F76 K(KT_FN,85)
+#define K_F77 K(KT_FN,86)
+#define K_F78 K(KT_FN,87)
+#define K_F79 K(KT_FN,88)
+#define K_F80 K(KT_FN,89)
+#define K_F81 K(KT_FN,90)
+#define K_F82 K(KT_FN,91)
+#define K_F83 K(KT_FN,92)
+#define K_F84 K(KT_FN,93)
+#define K_F85 K(KT_FN,94)
+#define K_F86 K(KT_FN,95)
+#define K_F87 K(KT_FN,96)
+#define K_F88 K(KT_FN,97)
+#define K_F89 K(KT_FN,98)
+#define K_F90 K(KT_FN,99)
+#define K_F91 K(KT_FN,100)
+#define K_F92 K(KT_FN,101)
+#define K_F93 K(KT_FN,102)
+#define K_F94 K(KT_FN,103)
+#define K_F95 K(KT_FN,104)
+#define K_F96 K(KT_FN,105)
+#define K_F97 K(KT_FN,106)
+#define K_F98 K(KT_FN,107)
+#define K_F99 K(KT_FN,108)
+#define K_F100 K(KT_FN,109)
+#define K_F101 K(KT_FN,110)
+#define K_F102 K(KT_FN,111)
+#define K_F103 K(KT_FN,112)
+#define K_F104 K(KT_FN,113)
+#define K_F105 K(KT_FN,114)
+#define K_F106 K(KT_FN,115)
+#define K_F107 K(KT_FN,116)
+#define K_F108 K(KT_FN,117)
+#define K_F109 K(KT_FN,118)
+#define K_F110 K(KT_FN,119)
+#define K_F111 K(KT_FN,120)
+#define K_F112 K(KT_FN,121)
+#define K_F113 K(KT_FN,122)
+#define K_F114 K(KT_FN,123)
+#define K_F115 K(KT_FN,124)
+#define K_F116 K(KT_FN,125)
+#define K_F117 K(KT_FN,126)
+#define K_F118 K(KT_FN,127)
+#define K_F119 K(KT_FN,128)
+#define K_F120 K(KT_FN,129)
+#define K_F121 K(KT_FN,130)
+#define K_F122 K(KT_FN,131)
+#define K_F123 K(KT_FN,132)
+#define K_F124 K(KT_FN,133)
+#define K_F125 K(KT_FN,134)
+#define K_F126 K(KT_FN,135)
+#define K_F127 K(KT_FN,136)
+#define K_F128 K(KT_FN,137)
+#define K_F129 K(KT_FN,138)
+#define K_F130 K(KT_FN,139)
+#define K_F131 K(KT_FN,140)
+#define K_F132 K(KT_FN,141)
+#define K_F133 K(KT_FN,142)
+#define K_F134 K(KT_FN,143)
+#define K_F135 K(KT_FN,144)
+#define K_F136 K(KT_FN,145)
+#define K_F137 K(KT_FN,146)
+#define K_F138 K(KT_FN,147)
+#define K_F139 K(KT_FN,148)
+#define K_F140 K(KT_FN,149)
+#define K_F141 K(KT_FN,150)
+#define K_F142 K(KT_FN,151)
+#define K_F143 K(KT_FN,152)
+#define K_F144 K(KT_FN,153)
+#define K_F145 K(KT_FN,154)
+#define K_F146 K(KT_FN,155)
+#define K_F147 K(KT_FN,156)
+#define K_F148 K(KT_FN,157)
+#define K_F149 K(KT_FN,158)
+#define K_F150 K(KT_FN,159)
+#define K_F151 K(KT_FN,160)
+#define K_F152 K(KT_FN,161)
+#define K_F153 K(KT_FN,162)
+#define K_F154 K(KT_FN,163)
+#define K_F155 K(KT_FN,164)
+#define K_F156 K(KT_FN,165)
+#define K_F157 K(KT_FN,166)
+#define K_F158 K(KT_FN,167)
+#define K_F159 K(KT_FN,168)
+#define K_F160 K(KT_FN,169)
+#define K_F161 K(KT_FN,170)
+#define K_F162 K(KT_FN,171)
+#define K_F163 K(KT_FN,172)
+#define K_F164 K(KT_FN,173)
+#define K_F165 K(KT_FN,174)
+#define K_F166 K(KT_FN,175)
+#define K_F167 K(KT_FN,176)
+#define K_F168 K(KT_FN,177)
+#define K_F169 K(KT_FN,178)
+#define K_F170 K(KT_FN,179)
+#define K_F171 K(KT_FN,180)
+#define K_F172 K(KT_FN,181)
+#define K_F173 K(KT_FN,182)
+#define K_F174 K(KT_FN,183)
+#define K_F175 K(KT_FN,184)
+#define K_F176 K(KT_FN,185)
+#define K_F177 K(KT_FN,186)
+#define K_F178 K(KT_FN,187)
+#define K_F179 K(KT_FN,188)
+#define K_F180 K(KT_FN,189)
+#define K_F181 K(KT_FN,190)
+#define K_F182 K(KT_FN,191)
+#define K_F183 K(KT_FN,192)
+#define K_F184 K(KT_FN,193)
+#define K_F185 K(KT_FN,194)
+#define K_F186 K(KT_FN,195)
+#define K_F187 K(KT_FN,196)
+#define K_F188 K(KT_FN,197)
+#define K_F189 K(KT_FN,198)
+#define K_F190 K(KT_FN,199)
+#define K_F191 K(KT_FN,200)
+#define K_F192 K(KT_FN,201)
+#define K_F193 K(KT_FN,202)
+#define K_F194 K(KT_FN,203)
+#define K_F195 K(KT_FN,204)
+#define K_F196 K(KT_FN,205)
+#define K_F197 K(KT_FN,206)
+#define K_F198 K(KT_FN,207)
+#define K_F199 K(KT_FN,208)
+#define K_F200 K(KT_FN,209)
+#define K_F201 K(KT_FN,210)
+#define K_F202 K(KT_FN,211)
+#define K_F203 K(KT_FN,212)
+#define K_F204 K(KT_FN,213)
+#define K_F205 K(KT_FN,214)
+#define K_F206 K(KT_FN,215)
+#define K_F207 K(KT_FN,216)
+#define K_F208 K(KT_FN,217)
+#define K_F209 K(KT_FN,218)
+#define K_F210 K(KT_FN,219)
+#define K_F211 K(KT_FN,220)
+#define K_F212 K(KT_FN,221)
+#define K_F213 K(KT_FN,222)
+#define K_F214 K(KT_FN,223)
+#define K_F215 K(KT_FN,224)
+#define K_F216 K(KT_FN,225)
+#define K_F217 K(KT_FN,226)
+#define K_F218 K(KT_FN,227)
+#define K_F219 K(KT_FN,228)
+#define K_F220 K(KT_FN,229)
+#define K_F221 K(KT_FN,230)
+#define K_F222 K(KT_FN,231)
+#define K_F223 K(KT_FN,232)
+#define K_F224 K(KT_FN,233)
+#define K_F225 K(KT_FN,234)
+#define K_F226 K(KT_FN,235)
+#define K_F227 K(KT_FN,236)
+#define K_F228 K(KT_FN,237)
+#define K_F229 K(KT_FN,238)
+#define K_F230 K(KT_FN,239)
+#define K_F231 K(KT_FN,240)
+#define K_F232 K(KT_FN,241)
+#define K_F233 K(KT_FN,242)
+#define K_F234 K(KT_FN,243)
+#define K_F235 K(KT_FN,244)
+#define K_F236 K(KT_FN,245)
+#define K_F237 K(KT_FN,246)
+#define K_F238 K(KT_FN,247)
+#define K_F239 K(KT_FN,248)
+#define K_F240 K(KT_FN,249)
+#define K_F241 K(KT_FN,250)
+#define K_F242 K(KT_FN,251)
+#define K_F243 K(KT_FN,252)
+#define K_F244 K(KT_FN,253)
+#define K_F245 K(KT_FN,254)
+#define K_UNDO K(KT_FN,255)
+
+
+#define K_HOLE K(KT_SPEC,0)
+#define K_ENTER K(KT_SPEC,1)
+#define K_SH_REGS K(KT_SPEC,2)
+#define K_SH_MEM K(KT_SPEC,3)
+#define K_SH_STAT K(KT_SPEC,4)
+#define K_BREAK K(KT_SPEC,5)
+#define K_CONS K(KT_SPEC,6)
+#define K_CAPS K(KT_SPEC,7)
+#define K_NUM K(KT_SPEC,8)
+#define K_HOLD K(KT_SPEC,9)
+#define K_SCROLLFORW K(KT_SPEC,10)
+#define K_SCROLLBACK K(KT_SPEC,11)
+#define K_BOOT K(KT_SPEC,12)
+#define K_CAPSON K(KT_SPEC,13)
+#define K_COMPOSE K(KT_SPEC,14)
+#define K_SAK K(KT_SPEC,15)
+#define K_DECRCONSOLE K(KT_SPEC,16)
+#define K_INCRCONSOLE K(KT_SPEC,17)
+#define K_SPAWNCONSOLE K(KT_SPEC,18)
+#define K_BARENUMLOCK K(KT_SPEC,19)
+
+#define K_ALLOCATED K(KT_SPEC,126) /* dynamically allocated keymap */
+#define K_NOSUCHMAP K(KT_SPEC,127) /* returned by KDGKBENT */
+
+#define K_P0 K(KT_PAD,0)
+#define K_P1 K(KT_PAD,1)
+#define K_P2 K(KT_PAD,2)
+#define K_P3 K(KT_PAD,3)
+#define K_P4 K(KT_PAD,4)
+#define K_P5 K(KT_PAD,5)
+#define K_P6 K(KT_PAD,6)
+#define K_P7 K(KT_PAD,7)
+#define K_P8 K(KT_PAD,8)
+#define K_P9 K(KT_PAD,9)
+#define K_PPLUS K(KT_PAD,10) /* key-pad plus */
+#define K_PMINUS K(KT_PAD,11) /* key-pad minus */
+#define K_PSTAR K(KT_PAD,12) /* key-pad asterisk (star) */
+#define K_PSLASH K(KT_PAD,13) /* key-pad slash */
+#define K_PENTER K(KT_PAD,14) /* key-pad enter */
+#define K_PCOMMA K(KT_PAD,15) /* key-pad comma: kludge... */
+#define K_PDOT K(KT_PAD,16) /* key-pad dot (period): kludge... */
+#define K_PPLUSMINUS K(KT_PAD,17) /* key-pad plus/minus */
+#define K_PPARENL K(KT_PAD,18) /* key-pad left parenthesis */
+#define K_PPARENR K(KT_PAD,19) /* key-pad right parenthesis */
+
+#define NR_PAD 20
+
+#define K_DGRAVE K(KT_DEAD,0)
+#define K_DACUTE K(KT_DEAD,1)
+#define K_DCIRCM K(KT_DEAD,2)
+#define K_DTILDE K(KT_DEAD,3)
+#define K_DDIERE K(KT_DEAD,4)
+#define K_DCEDIL K(KT_DEAD,5)
+
+#define NR_DEAD 6
+
+#define K_DOWN K(KT_CUR,0)
+#define K_LEFT K(KT_CUR,1)
+#define K_RIGHT K(KT_CUR,2)
+#define K_UP K(KT_CUR,3)
+
+#define K_SHIFT K(KT_SHIFT,KG_SHIFT)
+#define K_CTRL K(KT_SHIFT,KG_CTRL)
+#define K_ALT K(KT_SHIFT,KG_ALT)
+#define K_ALTGR K(KT_SHIFT,KG_ALTGR)
+#define K_SHIFTL K(KT_SHIFT,KG_SHIFTL)
+#define K_SHIFTR K(KT_SHIFT,KG_SHIFTR)
+#define K_CTRLL K(KT_SHIFT,KG_CTRLL)
+#define K_CTRLR K(KT_SHIFT,KG_CTRLR)
+#define K_CAPSSHIFT K(KT_SHIFT,KG_CAPSSHIFT)
+
+#define K_ASC0 K(KT_ASCII,0)
+#define K_ASC1 K(KT_ASCII,1)
+#define K_ASC2 K(KT_ASCII,2)
+#define K_ASC3 K(KT_ASCII,3)
+#define K_ASC4 K(KT_ASCII,4)
+#define K_ASC5 K(KT_ASCII,5)
+#define K_ASC6 K(KT_ASCII,6)
+#define K_ASC7 K(KT_ASCII,7)
+#define K_ASC8 K(KT_ASCII,8)
+#define K_ASC9 K(KT_ASCII,9)
+#define K_HEX0 K(KT_ASCII,10)
+#define K_HEX1 K(KT_ASCII,11)
+#define K_HEX2 K(KT_ASCII,12)
+#define K_HEX3 K(KT_ASCII,13)
+#define K_HEX4 K(KT_ASCII,14)
+#define K_HEX5 K(KT_ASCII,15)
+#define K_HEX6 K(KT_ASCII,16)
+#define K_HEX7 K(KT_ASCII,17)
+#define K_HEX8 K(KT_ASCII,18)
+#define K_HEX9 K(KT_ASCII,19)
+#define K_HEXa K(KT_ASCII,20)
+#define K_HEXb K(KT_ASCII,21)
+#define K_HEXc K(KT_ASCII,22)
+#define K_HEXd K(KT_ASCII,23)
+#define K_HEXe K(KT_ASCII,24)
+#define K_HEXf K(KT_ASCII,25)
+
+#define NR_ASCII 26
+
+#define K_SHIFTLOCK K(KT_LOCK,KG_SHIFT)
+#define K_CTRLLOCK K(KT_LOCK,KG_CTRL)
+#define K_ALTLOCK K(KT_LOCK,KG_ALT)
+#define K_ALTGRLOCK K(KT_LOCK,KG_ALTGR)
+#define K_SHIFTLLOCK K(KT_LOCK,KG_SHIFTL)
+#define K_SHIFTRLOCK K(KT_LOCK,KG_SHIFTR)
+#define K_CTRLLLOCK K(KT_LOCK,KG_CTRLL)
+#define K_CTRLRLOCK K(KT_LOCK,KG_CTRLR)
+
+#define K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT)
+#define K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL)
+#define K_ALT_SLOCK K(KT_SLOCK,KG_ALT)
+#define K_ALTGR_SLOCK K(KT_SLOCK,KG_ALTGR)
+#define K_SHIFTL_SLOCK K(KT_SLOCK,KG_SHIFTL)
+#define K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR)
+#define K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL)
+#define K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR)
+
+#define NR_LOCK 8
+
+#define MAX_DIACR 256
+#endif
diff --git a/pfinet/linux-src/include/linux/kmod.h b/pfinet/linux-src/include/linux/kmod.h
new file mode 100644
index 00000000..7392910d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/kmod.h
@@ -0,0 +1,12 @@
+/*
+ kmod header
+*/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_KMOD
+extern int request_module(const char * name);
+#else
+#define request_module(x) do {} while(0)
+#endif
+
diff --git a/pfinet/linux-src/include/linux/lapb.h b/pfinet/linux-src/include/linux/lapb.h
new file mode 100644
index 00000000..bf1825a6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/lapb.h
@@ -0,0 +1,56 @@
+/*
+ * These are the public elements of the Linux LAPB module.
+ */
+
+#ifndef LAPB_KERNEL_H
+#define LAPB_KERNEL_H
+
+#define LAPB_OK 0
+#define LAPB_BADTOKEN 1
+#define LAPB_INVALUE 2
+#define LAPB_CONNECTED 3
+#define LAPB_NOTCONNECTED 4
+#define LAPB_REFUSED 5
+#define LAPB_TIMEDOUT 6
+#define LAPB_NOMEM 7
+
+#define LAPB_STANDARD 0x00
+#define LAPB_EXTENDED 0x01
+
+#define LAPB_SLP 0x00
+#define LAPB_MLP 0x02
+
+#define LAPB_DTE 0x00
+#define LAPB_DCE 0x04
+
+struct lapb_register_struct {
+ void (*connect_confirmation)(void *token, int reason);
+ void (*connect_indication)(void *token, int reason);
+ void (*disconnect_confirmation)(void *token, int reason);
+ void (*disconnect_indication)(void *token, int reason);
+ void (*data_indication)(void *token, struct sk_buff *skb);
+ void (*data_transmit)(void *token, struct sk_buff *skb);
+};
+
+struct lapb_parms_struct {
+ unsigned int t1;
+ unsigned int t1timer;
+ unsigned int t2;
+ unsigned int t2timer;
+ unsigned int n2;
+ unsigned int n2count;
+ unsigned int window;
+ unsigned int state;
+ unsigned int mode;
+};
+
+extern int lapb_register(void *token, struct lapb_register_struct *callbacks);
+extern int lapb_unregister(void *token);
+extern int lapb_getparms(void *token, struct lapb_parms_struct *parms);
+extern int lapb_setparms(void *token, struct lapb_parms_struct *parms);
+extern int lapb_connect_request(void *token);
+extern int lapb_disconnect_request(void *token);
+extern int lapb_data_request(void *token, struct sk_buff *skb);
+extern int lapb_data_received(void *token, struct sk_buff *skb);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/limits.h b/pfinet/linux-src/include/linux/limits.h
new file mode 100644
index 00000000..5848688e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/limits.h
@@ -0,0 +1,19 @@
+#ifndef _LINUX_LIMITS_H
+#define _LINUX_LIMITS_H
+
+#define NR_OPEN 1024
+
+#define NGROUPS_MAX 32 /* supplemental group IDs are available */
+#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
+#define CHILD_MAX 999 /* no limit :-) */
+#define OPEN_MAX 256 /* # open files a process may have */
+#define LINK_MAX 127 /* # links a file may have */
+#define MAX_CANON 255 /* size of the canonical input queue */
+#define MAX_INPUT 255 /* size of the type-ahead buffer */
+#define NAME_MAX 255 /* # chars in a file name */
+#define PATH_MAX 4095 /* # chars in a path name */
+#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */
+
+#define RTSIG_MAX 32
+
+#endif
diff --git a/pfinet/linux-src/include/linux/linkage.h b/pfinet/linux-src/include/linux/linkage.h
new file mode 100644
index 00000000..190202f0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/linkage.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_LINKAGE_H
+#define _LINUX_LINKAGE_H
+
+#ifdef __cplusplus
+#define CPP_ASMLINKAGE extern "C"
+#else
+#define CPP_ASMLINKAGE
+#endif
+
+#if defined __i386__ && (__GNUC__ > 2 || __GNUC_MINOR__ > 7)
+#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
+#else
+#define asmlinkage CPP_ASMLINKAGE
+#endif
+
+#define SYMBOL_NAME_STR(X) #X
+#define SYMBOL_NAME(X) X
+#ifdef __STDC__
+#define SYMBOL_NAME_LABEL(X) X##:
+#else
+#define SYMBOL_NAME_LABEL(X) X/**/:
+#endif
+
+#ifdef __arm__
+#define __ALIGN .align 0
+#define __ALIGN_STR ".align 0"
+#else
+#ifdef __mc68000__
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+#else
+#if !defined(__i486__) && !defined(__i586__)
+#define __ALIGN .align 4,0x90
+#define __ALIGN_STR ".align 4,0x90"
+#else /* __i486__/__i586__ */
+#define __ALIGN .align 16,0x90
+#define __ALIGN_STR ".align 16,0x90"
+#endif /* __i486__/__i586__ */
+#endif /* __mc68000__ */
+#endif /* __arm__ */
+
+#ifdef __ASSEMBLY__
+
+#define ALIGN __ALIGN
+#define ALIGN_STR __ALIGN_STR
+
+#define ENTRY(name) \
+ .globl SYMBOL_NAME(name); \
+ ALIGN; \
+ SYMBOL_NAME_LABEL(name)
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/linux_logo.h b/pfinet/linux-src/include/linux/linux_logo.h
new file mode 100644
index 00000000..9aa712eb
--- /dev/null
+++ b/pfinet/linux-src/include/linux/linux_logo.h
@@ -0,0 +1,1445 @@
+/* $Id: linux_logo.h,v 1.5 1998/07/30 16:30:58 jj Exp $
+ * include/linux/linux_logo.h: This is a linux logo
+ * to be displayed on boot.
+ *
+ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * image size has to be 80x80
+ * values have to start from 0x20
+ * (i.e. RGB(linux_logo_red[0],
+ * linux_logo_green[0],
+ * linux_logo_blue[0]) is color 0x20)
+ * BW image has to be 80x80 as well, with MS bit
+ * on the left
+ * Serial_console ascii image can be any size,
+ * but should contain %s to display the version
+ */
+
+#if LINUX_LOGO_COLORS == 214
+
+unsigned char linux_logo_red[] __initdata = {
+ 0x02, 0x9E, 0xE9, 0xC4, 0x50, 0xC9, 0xC4, 0xE9,
+ 0x65, 0xE3, 0xC2, 0x25, 0xA4, 0xEC, 0x90, 0xA6,
+ 0xC4, 0x6A, 0xD1, 0xF3, 0x12, 0xED, 0xA0, 0xC2,
+ 0xB8, 0xD5, 0xDB, 0xD2, 0x3E, 0x16, 0xEB, 0x54,
+ 0xA9, 0xCD, 0xF5, 0x0A, 0xBA, 0xB3, 0xDC, 0x74,
+ 0xCE, 0xF6, 0xD3, 0xC5, 0xEA, 0xB8, 0xED, 0x5E,
+ 0xE5, 0x26, 0xF4, 0xA9, 0x82, 0x94, 0xE6, 0x38,
+ 0xF2, 0x0F, 0x7F, 0x49, 0xE5, 0xF4, 0xD3, 0xC3,
+ 0xC2, 0x1E, 0xD5, 0xC6, 0xA4, 0xFA, 0x0A, 0xBA,
+ 0xD4, 0xEB, 0xEA, 0xEC, 0xA8, 0xBC, 0xB4, 0xDC,
+ 0x84, 0xE4, 0xCE, 0xEC, 0x92, 0xCD, 0xDC, 0x8B,
+ 0xCC, 0x1E, 0xF6, 0xB2, 0x60, 0x2A, 0x96, 0x52,
+ 0x0F, 0xBD, 0xFA, 0xCC, 0xB8, 0x7A, 0x4C, 0xD2,
+ 0x06, 0xEF, 0x44, 0x64, 0xF4, 0xBA, 0xCE, 0xE6,
+ 0x8A, 0x6F, 0x3C, 0x70, 0x7C, 0x9C, 0xBA, 0xDF,
+ 0x2C, 0x4D, 0x3B, 0xCA, 0xDE, 0xCE, 0xEE, 0x46,
+ 0x6A, 0xAC, 0x96, 0xE5, 0x96, 0x7A, 0xBA, 0xB6,
+ 0xE2, 0x7E, 0xAA, 0xC5, 0x96, 0x9E, 0xC2, 0xAA,
+ 0xDA, 0x35, 0xB6, 0x82, 0x88, 0xBE, 0xC2, 0x9E,
+ 0xB4, 0xD5, 0xDA, 0x9C, 0xA0, 0xD0, 0xA8, 0xC7,
+ 0x72, 0xF2, 0xDB, 0x76, 0xDC, 0xBE, 0xAA, 0xF4,
+ 0x87, 0x2F, 0x53, 0x8E, 0x36, 0xCE, 0xE6, 0xCA,
+ 0xCB, 0xE4, 0xD6, 0xAA, 0x42, 0x5D, 0xB4, 0x59,
+ 0x1C, 0xC8, 0x96, 0x6C, 0xDA, 0xCE, 0xE6, 0xCB,
+ 0x96, 0x16, 0xFA, 0xBE, 0xAE, 0xFE, 0x6E, 0xD6,
+ 0xCE, 0xB6, 0xE5, 0xED, 0xDB, 0xDC, 0xF4, 0x72,
+ 0x1F, 0xAE, 0xE6, 0xC2, 0xCA, 0xC4
+};
+
+unsigned char linux_logo_green[] __initdata = {
+ 0x02, 0x88, 0xC4, 0x85, 0x44, 0xA2, 0xA8, 0xE5,
+ 0x65, 0xA6, 0xC2, 0x24, 0xA4, 0xB4, 0x62, 0x86,
+ 0x94, 0x44, 0xD2, 0xB6, 0x12, 0xD4, 0x73, 0x96,
+ 0x92, 0x95, 0xB2, 0xC2, 0x36, 0x0E, 0xBC, 0x54,
+ 0x75, 0xA5, 0xF5, 0x0A, 0xB2, 0x83, 0xC2, 0x74,
+ 0x9B, 0xBD, 0xA2, 0xCA, 0xDA, 0x8C, 0xCB, 0x42,
+ 0xAC, 0x12, 0xDA, 0x7B, 0x54, 0x94, 0xD2, 0x24,
+ 0xBE, 0x06, 0x65, 0x33, 0xBB, 0xBC, 0xAB, 0x8C,
+ 0x92, 0x1E, 0x9B, 0xB6, 0x6E, 0xFB, 0x04, 0xA2,
+ 0xC8, 0xBD, 0xAD, 0xEC, 0x92, 0xBC, 0x7B, 0x9D,
+ 0x84, 0xC4, 0xC4, 0xB4, 0x6C, 0x93, 0xA3, 0x5E,
+ 0x8D, 0x13, 0xD6, 0x82, 0x4C, 0x2A, 0x7A, 0x5A,
+ 0x0D, 0x82, 0xBB, 0xCC, 0x8B, 0x6A, 0x3C, 0xBE,
+ 0x06, 0xC4, 0x44, 0x45, 0xDB, 0x96, 0xB6, 0xDE,
+ 0x8A, 0x4D, 0x3C, 0x5A, 0x7C, 0x9C, 0xAA, 0xCB,
+ 0x1C, 0x4D, 0x2E, 0xB2, 0xBE, 0xAA, 0xDE, 0x3E,
+ 0x6A, 0xAC, 0x82, 0xE5, 0x72, 0x62, 0x92, 0x9E,
+ 0xCA, 0x4A, 0x8E, 0xBE, 0x86, 0x6B, 0xAA, 0x9A,
+ 0xBE, 0x34, 0xAB, 0x76, 0x6E, 0x9A, 0x9E, 0x62,
+ 0x76, 0xCE, 0xD3, 0x92, 0x7C, 0xB8, 0x7E, 0xC6,
+ 0x5E, 0xE2, 0xC3, 0x54, 0xAA, 0x9E, 0x8A, 0xCA,
+ 0x63, 0x2D, 0x3B, 0x8E, 0x1A, 0x9E, 0xC2, 0xA6,
+ 0xCB, 0xDC, 0xD6, 0x8E, 0x26, 0x5C, 0xB4, 0x45,
+ 0x1C, 0xB8, 0x6E, 0x4C, 0xBC, 0xAE, 0xD6, 0x92,
+ 0x63, 0x16, 0xF6, 0x8C, 0x7A, 0xFE, 0x6E, 0xBA,
+ 0xC6, 0x86, 0xAA, 0xAE, 0xDB, 0xA4, 0xD4, 0x56,
+ 0x0E, 0x6E, 0xB6, 0xB2, 0xBE, 0xBE
+};
+
+unsigned char linux_logo_blue[] __initdata = {
+ 0x04, 0x28, 0x10, 0x0B, 0x14, 0x14, 0x74, 0xC7,
+ 0x64, 0x0E, 0xC3, 0x24, 0xA4, 0x0C, 0x10, 0x20,
+ 0x0D, 0x04, 0xD1, 0x0D, 0x13, 0x22, 0x0A, 0x40,
+ 0x14, 0x0C, 0x11, 0x94, 0x0C, 0x08, 0x0B, 0x56,
+ 0x09, 0x47, 0xF4, 0x0B, 0x9C, 0x07, 0x54, 0x74,
+ 0x0F, 0x0C, 0x0F, 0xC7, 0x6C, 0x14, 0x14, 0x11,
+ 0x0B, 0x04, 0x12, 0x0C, 0x05, 0x94, 0x94, 0x0A,
+ 0x34, 0x09, 0x14, 0x08, 0x2F, 0x15, 0x19, 0x11,
+ 0x28, 0x0C, 0x0B, 0x94, 0x08, 0xFA, 0x08, 0x7C,
+ 0xBC, 0x15, 0x0A, 0xEC, 0x64, 0xBB, 0x0A, 0x0C,
+ 0x84, 0x2C, 0xA0, 0x15, 0x10, 0x0D, 0x0B, 0x0E,
+ 0x0A, 0x07, 0x10, 0x3C, 0x24, 0x2C, 0x28, 0x5C,
+ 0x0A, 0x0D, 0x0A, 0xC1, 0x22, 0x4C, 0x10, 0x94,
+ 0x04, 0x0F, 0x45, 0x08, 0x31, 0x54, 0x3C, 0xBC,
+ 0x8C, 0x09, 0x3C, 0x18, 0x7C, 0x9C, 0x7C, 0x91,
+ 0x0C, 0x4D, 0x17, 0x74, 0x0C, 0x48, 0x9C, 0x3C,
+ 0x6A, 0xAC, 0x5C, 0xE3, 0x29, 0x3C, 0x2C, 0x7C,
+ 0x6C, 0x04, 0x14, 0xA9, 0x74, 0x07, 0x2C, 0x74,
+ 0x4C, 0x34, 0x97, 0x5C, 0x38, 0x0C, 0x5C, 0x04,
+ 0x0C, 0xBA, 0xBC, 0x78, 0x18, 0x88, 0x24, 0xC2,
+ 0x3C, 0xB4, 0x87, 0x0C, 0x14, 0x4C, 0x3C, 0x10,
+ 0x17, 0x2C, 0x0A, 0x8C, 0x04, 0x1C, 0x44, 0x2C,
+ 0xCD, 0xD8, 0xD4, 0x34, 0x0C, 0x5B, 0xB4, 0x1E,
+ 0x1D, 0xAC, 0x24, 0x18, 0x20, 0x5C, 0xB4, 0x1C,
+ 0x09, 0x14, 0xFC, 0x0C, 0x10, 0xFC, 0x6C, 0x7C,
+ 0xB4, 0x1C, 0x15, 0x17, 0xDB, 0x18, 0x21, 0x24,
+ 0x04, 0x04, 0x44, 0x8C, 0x8C, 0xB7
+};
+
+unsigned char linux_logo[] __initdata = {
+ 0xBF, 0x95, 0x90, 0xCB, 0x95, 0xA1, 0x2C, 0x2C,
+ 0x95, 0x55, 0xCB, 0x90, 0xCB, 0x95, 0x2C, 0x95,
+ 0xCB, 0x47, 0x94, 0x95, 0xA1, 0xD6, 0xD6, 0x2C,
+ 0x90, 0x47, 0x70, 0x2C, 0x6D, 0x2A, 0x6D, 0xD6,
+ 0xA1, 0x2C, 0x55, 0x95, 0x2C, 0x2C, 0x55, 0x55,
+ 0x95, 0xA1, 0xA1, 0xA1, 0x6D, 0xBF, 0x2A, 0x2A,
+ 0xBF, 0x83, 0xBF, 0x95, 0x90, 0xCB, 0x95, 0xA1,
+ 0x2C, 0x2C, 0x95, 0x55, 0xCB, 0x90, 0xCB, 0x95,
+ 0x2C, 0x95, 0xCB, 0x47, 0x94, 0x95, 0xA1, 0xD6,
+ 0xD6, 0x2C, 0x90, 0x47, 0x70, 0x2C, 0x6D, 0x2A,
+ 0x95, 0x47, 0x47, 0x90, 0x2C, 0x2C, 0x2C, 0x95,
+ 0x55, 0x55, 0xCB, 0x90, 0xCB, 0x55, 0x55, 0xCB,
+ 0x47, 0xE6, 0x70, 0x95, 0xD6, 0xD6, 0xA1, 0x2C,
+ 0x55, 0x55, 0x95, 0xD6, 0x6D, 0xD6, 0xA1, 0x2C,
+ 0x2C, 0x95, 0x55, 0x95, 0x95, 0x95, 0x2C, 0x2C,
+ 0xA1, 0xA1, 0x2C, 0x2C, 0xA1, 0xD6, 0xD6, 0xD6,
+ 0xD6, 0xD6, 0x95, 0x47, 0x47, 0x90, 0x2C, 0x2C,
+ 0x2C, 0x95, 0x55, 0x55, 0xCB, 0x90, 0xCB, 0x55,
+ 0x55, 0xCB, 0x47, 0xE6, 0x70, 0x95, 0xD6, 0xD6,
+ 0xA1, 0x2C, 0x55, 0x55, 0x95, 0xD6, 0x6D, 0xD6,
+ 0x90, 0x47, 0x47, 0x70, 0x2C, 0xA1, 0x2C, 0x95,
+ 0x55, 0x55, 0x90, 0xCB, 0x55, 0x55, 0x55, 0x70,
+ 0x94, 0x70, 0x95, 0xA1, 0xD6, 0xD6, 0xA1, 0x2C,
+ 0x95, 0x95, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C,
+ 0x95, 0x55, 0xCB, 0x95, 0xD6, 0xA1, 0x2C, 0x95,
+ 0xA1, 0xD6, 0xD6, 0xA1, 0xA1, 0xD6, 0xA1, 0xA1,
+ 0xA1, 0x2C, 0x90, 0x47, 0x47, 0x70, 0x2C, 0xA1,
+ 0x2C, 0x95, 0x55, 0x55, 0x90, 0xCB, 0x55, 0x55,
+ 0x55, 0x70, 0x94, 0x70, 0x95, 0xA1, 0xD6, 0xD6,
+ 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0xD6, 0xD6, 0xA1,
+ 0x94, 0xA0, 0x47, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
+ 0x55, 0x55, 0xCB, 0xCB, 0x55, 0x55, 0xCB, 0xCB,
+ 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6, 0xA1, 0x2C,
+ 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x95,
+ 0x55, 0x55, 0x2C, 0x3F, 0x80, 0x20, 0x88, 0x88,
+ 0x88, 0x20, 0x88, 0xB1, 0x2C, 0xA1, 0x2C, 0x2C,
+ 0x95, 0xCB, 0x94, 0xA0, 0x47, 0x55, 0x2C, 0xD6,
+ 0xA1, 0x95, 0x55, 0x55, 0xCB, 0xCB, 0x55, 0x55,
+ 0xCB, 0xCB, 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6,
+ 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0x94, 0x94, 0x70, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C,
+ 0x55, 0x55, 0xCB, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x95, 0x2C, 0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x95,
+ 0x55, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x2C, 0x94, 0x80, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x88, 0x92, 0xA1, 0x95,
+ 0x55, 0x90, 0x94, 0x94, 0x70, 0x2C, 0xA1, 0xD6,
+ 0xA1, 0x2C, 0x55, 0x55, 0xCB, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x95, 0x2C, 0xD6, 0xD6, 0xD6, 0xA1,
+ 0x2C, 0x95, 0x55, 0x55, 0x55, 0x95, 0x95, 0x95,
+ 0x70, 0x70, 0x55, 0x2C, 0xD6, 0xD6, 0xA1, 0x95,
+ 0x55, 0x90, 0xCB, 0xCB, 0x55, 0x55, 0x2C, 0x2C,
+ 0xA1, 0xD6, 0xA1, 0xA1, 0x2C, 0x2C, 0x95, 0x55,
+ 0x55, 0x55, 0x95, 0x95, 0x2C, 0x95, 0x95, 0xD6,
+ 0xB1, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x80, 0x34, 0x88, 0x43, 0x47,
+ 0x95, 0xCB, 0x70, 0x70, 0x55, 0x2C, 0xD6, 0xD6,
+ 0xA1, 0x95, 0x55, 0x90, 0xCB, 0xCB, 0x55, 0x55,
+ 0x2C, 0x2C, 0xA1, 0xD6, 0xA1, 0xA1, 0xA1, 0x2C,
+ 0x55, 0x55, 0x55, 0x55, 0x2C, 0x95, 0x2C, 0x2C,
+ 0x55, 0x55, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x55,
+ 0x90, 0x70, 0x90, 0x55, 0x95, 0x95, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x95, 0x95, 0x95,
+ 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0xD5,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x88, 0x7D, 0x3F, 0xB1, 0x80, 0x20,
+ 0x99, 0x2C, 0x55, 0x55, 0x95, 0x2C, 0xA1, 0xA1,
+ 0x2C, 0x55, 0x90, 0x70, 0x90, 0x55, 0x95, 0x95,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C, 0x2C,
+ 0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0x95, 0x90, 0x55, 0x2C, 0xA1, 0xA1, 0x95, 0xCB,
+ 0x70, 0x94, 0x90, 0x55, 0x95, 0xA1, 0xA1, 0xA1,
+ 0x2C, 0x2C, 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0xA1, 0x88,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0xB1, 0x47, 0xD5, 0x7D, 0x43,
+ 0x20, 0x70, 0x95, 0x90, 0x55, 0x2C, 0xA1, 0xA1,
+ 0x95, 0xCB, 0x70, 0x94, 0x90, 0x55, 0x95, 0xA1,
+ 0xA1, 0xA1, 0x2C, 0x95, 0x2C, 0x2C, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x2C, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x90, 0x55, 0x2C, 0xD6, 0xD6, 0x2C, 0x90,
+ 0x94, 0x70, 0x55, 0x95, 0x2C, 0xD6, 0xD6, 0xA1,
+ 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x95, 0x55, 0x55,
+ 0xCB, 0xCB, 0xCB, 0x55, 0xCB, 0x55, 0x47, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x88, 0xB1, 0x3F, 0x92, 0x2B, 0x80,
+ 0x20, 0x80, 0xD6, 0x70, 0x55, 0x2C, 0xD6, 0xD6,
+ 0x2C, 0x90, 0x94, 0x70, 0x55, 0x95, 0x2C, 0xD6,
+ 0xD6, 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x95,
+ 0x95, 0x55, 0x90, 0xCB, 0xCB, 0xCB, 0xCB, 0x55,
+ 0xD6, 0x55, 0x95, 0xA1, 0xD6, 0xA1, 0x55, 0x70,
+ 0x94, 0x55, 0x95, 0xA1, 0xA1, 0xA1, 0xA1, 0x95,
+ 0x55, 0x55, 0x55, 0x95, 0x55, 0x55, 0xCB, 0x90,
+ 0x70, 0x90, 0xCB, 0x55, 0x55, 0xA1, 0xD8, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x88, 0xD8, 0xE1, 0x88, 0x20, 0x20,
+ 0x88, 0x88, 0xE6, 0x55, 0x2C, 0xA1, 0xD6, 0xA1,
+ 0x55, 0x70, 0x94, 0x55, 0x95, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0x95, 0x55, 0x55, 0x95, 0x95, 0x55, 0x55,
+ 0x90, 0x90, 0x90, 0x90, 0xCB, 0x55, 0x55, 0x55,
+ 0xD6, 0x2C, 0xA1, 0xD6, 0xD6, 0xA1, 0xCB, 0x70,
+ 0x70, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0x55,
+ 0xCB, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x95, 0x2C, 0x95, 0x2C, 0xD6, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x80, 0xD6, 0xA1, 0xD6, 0xD6, 0xA1,
+ 0xCB, 0x70, 0x70, 0x95, 0x2C, 0xA1, 0xA1, 0x2C,
+ 0x2C, 0x55, 0xCB, 0xCB, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0xD6, 0xA1, 0xA1, 0xA1, 0xA1, 0x55, 0x70, 0x94,
+ 0xCB, 0x95, 0xA1, 0xA1, 0x2C, 0x95, 0xCB, 0x55,
+ 0x90, 0xCB, 0x55, 0x55, 0x55, 0x55, 0x95, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x95, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x88, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x88, 0x95, 0xA1, 0xA1, 0xA1, 0x55,
+ 0x70, 0x94, 0xCB, 0x95, 0xA1, 0xA1, 0x2C, 0x95,
+ 0xCB, 0xCB, 0x90, 0xCB, 0x55, 0x55, 0x55, 0x55,
+ 0x95, 0x2C, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0x2C, 0x2C, 0x2C, 0x95, 0x95, 0xCB, 0x70, 0x70,
+ 0x95, 0x2C, 0x2C, 0x95, 0xCB, 0x70, 0x90, 0xCB,
+ 0xCB, 0x55, 0x55, 0xCB, 0x55, 0x55, 0x2C, 0xD6,
+ 0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x70, 0x20, 0x20,
+ 0x88, 0x43, 0xD8, 0x43, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x88, 0x88, 0x43, 0x2B, 0xD8, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x3F, 0x2C, 0x95, 0x95, 0xCB,
+ 0x70, 0x70, 0x95, 0x2C, 0x2C, 0x95, 0xCB, 0x90,
+ 0x90, 0xCB, 0x55, 0xCB, 0x55, 0xCB, 0x55, 0x95,
+ 0x2C, 0xD6, 0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x2C,
+ 0xA1, 0x95, 0x95, 0x55, 0xCB, 0x70, 0x90, 0x55,
+ 0x2C, 0x2C, 0x2C, 0x55, 0x70, 0x70, 0x55, 0x95,
+ 0x95, 0xCB, 0x90, 0x90, 0x90, 0x95, 0x2C, 0xA1,
+ 0xD6, 0xD6, 0x2C, 0x2C, 0x95, 0x70, 0x20, 0x20,
+ 0x80, 0x2B, 0x34, 0x2B, 0x88, 0x20, 0x20, 0x20,
+ 0x88, 0xB1, 0x28, 0x28, 0x2B, 0x7D, 0x80, 0x20,
+ 0x20, 0x20, 0x20, 0x92, 0x95, 0x55, 0xCB, 0x70,
+ 0x90, 0x55, 0x2C, 0x2C, 0x2C, 0x55, 0x70, 0x70,
+ 0x55, 0x95, 0x55, 0x55, 0x90, 0x90, 0x90, 0x55,
+ 0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C, 0x95, 0x95,
+ 0xA1, 0x95, 0x55, 0xCB, 0x90, 0x70, 0xCB, 0x95,
+ 0xA1, 0x95, 0x95, 0xCB, 0x90, 0xCB, 0x95, 0x2C,
+ 0x95, 0x70, 0x70, 0x90, 0x55, 0x2C, 0xA1, 0xA1,
+ 0x2C, 0x2C, 0x55, 0xCB, 0x55, 0x90, 0x20, 0x34,
+ 0x90, 0x6D, 0x70, 0xD8, 0x43, 0x20, 0x20, 0x88,
+ 0x3F, 0x55, 0xA1, 0x2A, 0xD6, 0x7D, 0x43, 0x20,
+ 0x20, 0x20, 0x88, 0x7D, 0x55, 0xCB, 0x90, 0x70,
+ 0xCB, 0x95, 0xA1, 0x95, 0x95, 0xCB, 0x70, 0xCB,
+ 0x95, 0xA1, 0x95, 0x70, 0x70, 0xCB, 0x55, 0x2C,
+ 0xA1, 0xA1, 0xA1, 0x95, 0x55, 0x55, 0x55, 0x95,
+ 0x2C, 0x55, 0x90, 0x70, 0x94, 0x90, 0x95, 0x2C,
+ 0x2C, 0x95, 0xCB, 0x90, 0x55, 0x95, 0xA1, 0xA1,
+ 0x95, 0x90, 0x90, 0x95, 0xA1, 0xD6, 0xD6, 0x6D,
+ 0xA1, 0x95, 0x55, 0xCB, 0x55, 0xCB, 0x20, 0x99,
+ 0xBF, 0xA3, 0xA3, 0x90, 0x20, 0x20, 0x20, 0x92,
+ 0x83, 0x6B, 0x6B, 0x6B, 0xA3, 0x70, 0x88, 0x20,
+ 0x20, 0x20, 0x20, 0x2B, 0x90, 0x70, 0x94, 0x90,
+ 0x95, 0x2C, 0x2C, 0x95, 0xCB, 0x90, 0x55, 0x95,
+ 0xA1, 0x2C, 0x55, 0x90, 0x90, 0x95, 0xA1, 0xD6,
+ 0xD6, 0x6D, 0xA1, 0x95, 0x55, 0xCB, 0x55, 0x55,
+ 0x2C, 0x55, 0x70, 0x70, 0x94, 0x90, 0x95, 0x2C,
+ 0x2C, 0x55, 0xCB, 0xCB, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x55, 0x55, 0x95, 0xA1, 0x6D, 0xBF, 0x6D, 0xD6,
+ 0x95, 0x55, 0x90, 0xCB, 0x55, 0x95, 0x88, 0x95,
+ 0x2C, 0x3F, 0x6D, 0x6B, 0x34, 0x20, 0x20, 0x47,
+ 0x65, 0xD6, 0xE1, 0x3F, 0x2A, 0x6B, 0x2B, 0x20,
+ 0x20, 0x20, 0x20, 0x43, 0x70, 0x70, 0x94, 0x90,
+ 0x95, 0x2C, 0x2C, 0x55, 0x55, 0x55, 0x95, 0x2C,
+ 0xA1, 0x2C, 0x55, 0xCB, 0x95, 0xA1, 0x6D, 0xBF,
+ 0x6D, 0xD6, 0x2C, 0x55, 0x90, 0xCB, 0x95, 0x95,
+ 0x95, 0x55, 0x70, 0x94, 0x70, 0x55, 0x2C, 0xA1,
+ 0x2C, 0x55, 0xCB, 0x55, 0x2C, 0x95, 0x2C, 0x95,
+ 0x95, 0x95, 0xA1, 0x6D, 0xBF, 0x2A, 0xD6, 0x95,
+ 0x70, 0x94, 0x94, 0x70, 0x55, 0x55, 0x20, 0xBF,
+ 0xC9, 0xB1, 0x99, 0x42, 0xB1, 0x61, 0x7D, 0x94,
+ 0x65, 0xB1, 0x88, 0x99, 0xD5, 0xE5, 0x7F, 0x20,
+ 0x20, 0x20, 0x20, 0x43, 0x70, 0x94, 0x70, 0x55,
+ 0x2C, 0xA1, 0x2C, 0x55, 0x90, 0x55, 0x2C, 0x95,
+ 0x2C, 0x95, 0x95, 0x2C, 0xA1, 0x6D, 0xBF, 0xBF,
+ 0xD6, 0x55, 0x70, 0x94, 0x94, 0x70, 0xCB, 0x55,
+ 0x55, 0xCB, 0x70, 0x94, 0x70, 0x95, 0xA1, 0xA1,
+ 0x95, 0x55, 0x55, 0x95, 0x2C, 0x95, 0x95, 0x95,
+ 0x95, 0xA1, 0x6D, 0x2A, 0x2A, 0xD6, 0x55, 0x94,
+ 0xE6, 0xE6, 0x47, 0x70, 0x55, 0x95, 0x20, 0x2A,
+ 0xD8, 0x43, 0xC9, 0x83, 0x98, 0x79, 0x34, 0x9F,
+ 0x6B, 0x43, 0x20, 0x88, 0x2B, 0x65, 0xA0, 0x20,
+ 0x20, 0x20, 0x20, 0xE1, 0x70, 0x94, 0x70, 0x95,
+ 0xA1, 0xA1, 0x95, 0x55, 0x55, 0x95, 0x2C, 0x95,
+ 0x95, 0x95, 0x95, 0xA1, 0x6D, 0xBF, 0x2A, 0xD6,
+ 0x55, 0x94, 0xE6, 0xE6, 0x47, 0x70, 0x55, 0x55,
+ 0x94, 0x70, 0x94, 0x47, 0x70, 0x95, 0x2C, 0x2C,
+ 0x95, 0xCB, 0x95, 0x2C, 0x2C, 0xA1, 0x2C, 0x2C,
+ 0xA1, 0xD6, 0x6D, 0x6D, 0xA1, 0xCB, 0x47, 0x28,
+ 0xE6, 0x47, 0x70, 0x55, 0x95, 0xA1, 0x20, 0x2C,
+ 0x7F, 0x88, 0xF0, 0xC6, 0x25, 0x5E, 0xCF, 0x2F,
+ 0xE7, 0x9A, 0x20, 0x88, 0x99, 0x65, 0x3F, 0x20,
+ 0x20, 0x20, 0x20, 0x34, 0x94, 0x47, 0x70, 0x95,
+ 0xA1, 0x2C, 0x55, 0xCB, 0x95, 0x2C, 0x2C, 0xA1,
+ 0x2C, 0x2C, 0xA1, 0xD6, 0x6D, 0x6D, 0xA1, 0xCB,
+ 0x94, 0x28, 0xA0, 0x47, 0x70, 0x55, 0x95, 0x95,
+ 0x47, 0x70, 0x90, 0x94, 0x70, 0x95, 0xA1, 0x2C,
+ 0x55, 0x55, 0x2C, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C,
+ 0xA1, 0x6D, 0x2A, 0xD6, 0x55, 0x47, 0x28, 0x28,
+ 0x47, 0x70, 0x55, 0x95, 0x2C, 0xA1, 0x20, 0x28,
+ 0xEC, 0x86, 0xBE, 0x48, 0x3E, 0x3E, 0x3A, 0x25,
+ 0x4E, 0xAE, 0x93, 0xD7, 0xEC, 0xD1, 0x34, 0x20,
+ 0x20, 0x20, 0x20, 0x43, 0x55, 0x94, 0x70, 0x95,
+ 0xA1, 0xA1, 0x55, 0xCB, 0x2C, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0x2C, 0xA1, 0x6D, 0x6D, 0xD6, 0x55, 0x47,
+ 0x28, 0x28, 0x47, 0x70, 0x55, 0x95, 0x2C, 0x2C,
+ 0x95, 0x95, 0x55, 0x90, 0xCB, 0x2C, 0xA1, 0xA1,
+ 0x55, 0x55, 0x2C, 0xD6, 0xD6, 0xA1, 0xA1, 0x2C,
+ 0xD6, 0x6D, 0x6D, 0xA1, 0x70, 0x28, 0xD5, 0xE6,
+ 0x70, 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0x20, 0xE1,
+ 0x26, 0x84, 0x76, 0x73, 0x9C, 0x22, 0x4E, 0x35,
+ 0x8C, 0x7A, 0x4E, 0xDC, 0x8E, 0x7E, 0x3D, 0x88,
+ 0x20, 0x20, 0x20, 0x88, 0x2C, 0x90, 0x90, 0x95,
+ 0xA1, 0x2C, 0x55, 0x55, 0x2C, 0xD6, 0xD6, 0xD6,
+ 0x2C, 0x2C, 0xD6, 0x2A, 0x6D, 0x2C, 0x70, 0x28,
+ 0xD5, 0xE6, 0x70, 0x55, 0x95, 0xA1, 0x2C, 0xA1,
+ 0xBF, 0xA1, 0x95, 0xCB, 0xCB, 0x2C, 0xA1, 0xA1,
+ 0x95, 0x95, 0xA1, 0xD6, 0xD6, 0xA1, 0x2C, 0x95,
+ 0xD6, 0x6D, 0xD6, 0x95, 0x94, 0x28, 0xE6, 0x70,
+ 0x55, 0x95, 0xA1, 0xA1, 0xA1, 0xD6, 0x20, 0x57,
+ 0xE4, 0xDF, 0x50, 0x3E, 0x22, 0x4E, 0x35, 0x8C,
+ 0x8C, 0x52, 0x52, 0x7A, 0x4E, 0x58, 0xD7, 0x20,
+ 0x20, 0x20, 0x20, 0x88, 0x2C, 0xCB, 0x55, 0x2C,
+ 0xA1, 0xA1, 0x95, 0x95, 0xA1, 0xD6, 0xD6, 0xA1,
+ 0x2C, 0x95, 0xA1, 0x6D, 0x6D, 0x95, 0x47, 0xA0,
+ 0xE6, 0x70, 0x55, 0x95, 0x2C, 0xA1, 0xA1, 0xA1,
+ 0xD2, 0x95, 0x55, 0x90, 0x55, 0x2C, 0xD6, 0xA1,
+ 0x95, 0x95, 0xA1, 0xD6, 0xD6, 0x2C, 0x95, 0x2C,
+ 0xA1, 0x6D, 0xA1, 0x55, 0x94, 0x47, 0x94, 0xCB,
+ 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6, 0x59, 0xC8,
+ 0xE3, 0x76, 0x2D, 0x3E, 0x22, 0x4E, 0x8C, 0x35,
+ 0x52, 0x52, 0xEE, 0x3A, 0x4D, 0xED, 0x24, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x28, 0xCB, 0x55, 0x2C,
+ 0xD6, 0xA1, 0x95, 0x95, 0xA1, 0xD6, 0xA1, 0x2C,
+ 0x95, 0x2C, 0xD6, 0x6D, 0xA1, 0x55, 0x94, 0xE6,
+ 0x70, 0xCB, 0x55, 0x95, 0xA1, 0xD6, 0xD6, 0xA1,
+ 0xD0, 0x94, 0x94, 0x90, 0x55, 0x2C, 0xA1, 0xA1,
+ 0x55, 0x95, 0xA1, 0xA1, 0xA1, 0x2C, 0x95, 0x2C,
+ 0xA1, 0xD6, 0x2C, 0x70, 0x94, 0x94, 0x94, 0x94,
+ 0x70, 0x55, 0xA1, 0xD6, 0xA1, 0xD6, 0x88, 0x77,
+ 0x38, 0xC4, 0x3E, 0x69, 0x4E, 0x35, 0x8C, 0xEE,
+ 0x35, 0x89, 0x30, 0x30, 0x4A, 0x48, 0x3C, 0x20,
+ 0x20, 0x88, 0x20, 0x20, 0xD8, 0x2C, 0x55, 0x2C,
+ 0xD6, 0xA1, 0x95, 0x95, 0x2C, 0xD6, 0xA1, 0x2C,
+ 0x95, 0x2C, 0xA1, 0xD6, 0x2C, 0x90, 0x94, 0x47,
+ 0x94, 0x94, 0x70, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
+ 0x95, 0x28, 0x47, 0x90, 0x95, 0x2C, 0xA1, 0x2C,
+ 0x95, 0x55, 0x95, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C,
+ 0xA1, 0xA1, 0x55, 0x70, 0x94, 0x47, 0x94, 0x94,
+ 0x70, 0x2C, 0xD6, 0xD6, 0x2C, 0xA1, 0x43, 0x98,
+ 0x54, 0x48, 0x3E, 0x22, 0x35, 0xEE, 0xEE, 0x9C,
+ 0x4D, 0x45, 0x75, 0x4A, 0xDF, 0x7B, 0x3D, 0x20,
+ 0xD8, 0x28, 0x2B, 0x88, 0x20, 0x95, 0x95, 0x2C,
+ 0xA1, 0x2C, 0x55, 0x55, 0x2C, 0xA1, 0xD6, 0xA1,
+ 0x2C, 0x95, 0xA1, 0x2C, 0x55, 0x70, 0x94, 0x94,
+ 0x94, 0x94, 0x70, 0x95, 0xD6, 0xD6, 0x2C, 0x95,
+ 0x70, 0x28, 0x47, 0x55, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x95, 0x95, 0x95, 0xA1, 0xA1, 0xA1, 0x95, 0x55,
+ 0x95, 0x95, 0x55, 0x70, 0x70, 0x70, 0x94, 0x70,
+ 0x55, 0xD6, 0x6D, 0xD6, 0x95, 0x2C, 0x20, 0x43,
+ 0xBB, 0xC8, 0x36, 0x30, 0x30, 0x38, 0x45, 0x6E,
+ 0xE3, 0x75, 0x78, 0x37, 0xBD, 0xD9, 0x3F, 0x20,
+ 0x88, 0xD5, 0x70, 0xB1, 0x88, 0xA0, 0x95, 0x2C,
+ 0x2C, 0xA1, 0x95, 0x55, 0x95, 0xA1, 0xA1, 0xA1,
+ 0x2C, 0x55, 0x95, 0x2C, 0x55, 0x70, 0x70, 0x70,
+ 0x94, 0x70, 0x55, 0xD6, 0x6D, 0x6D, 0x95, 0x55,
+ 0x94, 0x47, 0x70, 0x95, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x55,
+ 0x55, 0x95, 0x95, 0x55, 0x55, 0x55, 0x55, 0x95,
+ 0xA1, 0x6D, 0x4B, 0xD6, 0x55, 0xD6, 0x20, 0xD8,
+ 0xD6, 0x67, 0xDA, 0x4D, 0xED, 0x62, 0x78, 0x78,
+ 0x23, 0x84, 0x67, 0xF5, 0x4B, 0xBF, 0x90, 0x88,
+ 0x88, 0x2B, 0x47, 0x99, 0x20, 0x43, 0xD6, 0x2C,
+ 0x2C, 0xA1, 0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1,
+ 0x95, 0x95, 0x55, 0x95, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x95, 0xD6, 0x6D, 0xBF, 0xD6, 0x55, 0xCB,
+ 0x55, 0x55, 0x55, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0x2C, 0x2C, 0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0x95,
+ 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0x6D, 0x2A, 0x2A, 0xA1, 0x55, 0x55, 0x20, 0xD8,
+ 0x6D, 0xAB, 0x96, 0x7E, 0x64, 0x53, 0x36, 0x36,
+ 0xC6, 0x63, 0x6D, 0xD0, 0x6B, 0xE5, 0xA3, 0x7D,
+ 0x20, 0x88, 0x80, 0x88, 0x20, 0x20, 0xC9, 0xA1,
+ 0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0xA1, 0xA1, 0xA1,
+ 0x95, 0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x2C, 0xA1, 0x6D, 0xBF, 0x6D, 0xA1, 0x55, 0x55,
+ 0x95, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0xA1, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x95,
+ 0x55, 0x55, 0x2C, 0x2C, 0xA1, 0xA1, 0xD6, 0xD6,
+ 0x6D, 0x6D, 0xA1, 0x55, 0x2C, 0xD8, 0x20, 0xB1,
+ 0xA3, 0x4B, 0x6D, 0xD9, 0xA7, 0x6C, 0xAF, 0xB2,
+ 0x6D, 0x2A, 0x83, 0x42, 0xE5, 0xE5, 0x65, 0x2C,
+ 0x20, 0x20, 0x88, 0x20, 0x20, 0x20, 0x88, 0x95,
+ 0x2C, 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x2C, 0x95, 0x55, 0x55, 0x2C, 0x2C, 0xA1, 0xA1,
+ 0xD6, 0xD6, 0x6D, 0x6D, 0xA1, 0x55, 0xCB, 0x55,
+ 0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x95, 0x2C,
+ 0x2C, 0x95, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x95,
+ 0x55, 0x95, 0x2C, 0x2C, 0xA1, 0xA1, 0xD6, 0xA1,
+ 0xA1, 0x2C, 0x55, 0x55, 0x28, 0x88, 0x43, 0x2A,
+ 0xE5, 0xA3, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
+ 0xBF, 0xA3, 0x42, 0xE5, 0xE5, 0xE5, 0xE5, 0x65,
+ 0xB1, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xD8,
+ 0xD6, 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x2C,
+ 0x95, 0x95, 0x55, 0x95, 0x2C, 0x2C, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0x2C, 0x95, 0x90, 0x90, 0x55,
+ 0x90, 0xCB, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x2C, 0x2C, 0x95, 0x55, 0x95, 0x95, 0x95, 0x55,
+ 0x55, 0xCB, 0x55, 0x2C, 0x95, 0x95, 0x95, 0x95,
+ 0x55, 0x90, 0x90, 0x90, 0xE1, 0x43, 0x28, 0xE5,
+ 0xE5, 0x65, 0xD0, 0x6D, 0x6D, 0x6D, 0x2A, 0xD2,
+ 0x42, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xD6, 0x20, 0x20, 0x20, 0x20, 0x20, 0x88, 0x88,
+ 0xD5, 0x2C, 0x2C, 0x2C, 0x95, 0x55, 0x95, 0x95,
+ 0x95, 0x55, 0x55, 0xCB, 0x55, 0x95, 0x2C, 0x95,
+ 0x95, 0x95, 0x55, 0x90, 0x70, 0x70, 0x70, 0x90,
+ 0x70, 0x70, 0xCB, 0x55, 0x55, 0x95, 0x95, 0x95,
+ 0x2C, 0x95, 0x95, 0x55, 0x55, 0x55, 0x55, 0xCB,
+ 0x70, 0x70, 0x70, 0xCB, 0x90, 0x90, 0x70, 0x94,
+ 0x94, 0x94, 0x2C, 0x80, 0x20, 0xE1, 0xA3, 0xE5,
+ 0xE5, 0xE5, 0x42, 0xEC, 0xD0, 0x83, 0xA3, 0x65,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0x65, 0x7D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x88, 0x2C, 0x95, 0x95, 0x95, 0x55, 0x55, 0x55,
+ 0x55, 0xCB, 0x70, 0x70, 0x90, 0x90, 0x90, 0x90,
+ 0x70, 0x94, 0x94, 0x94, 0x70, 0x70, 0x70, 0x70,
+ 0x70, 0x55, 0x55, 0x55, 0x95, 0x95, 0x95, 0x95,
+ 0x2C, 0x2C, 0x95, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x90, 0x70, 0x90, 0x55, 0x55, 0xCB, 0x70, 0x94,
+ 0x94, 0x95, 0xD8, 0x20, 0x88, 0x70, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0x47, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0xE1, 0x6D, 0x2C, 0x95, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x90, 0x70, 0x70, 0x55, 0x55, 0xCB,
+ 0x70, 0x94, 0x94, 0x94, 0x70, 0x90, 0x70, 0x94,
+ 0x55, 0x2C, 0x2C, 0x2C, 0x95, 0x2C, 0x95, 0x95,
+ 0x2C, 0x2C, 0x2C, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0xCB, 0xCB, 0x95, 0x2C, 0x2C, 0x95, 0x55, 0x90,
+ 0x55, 0x99, 0x20, 0x20, 0xE1, 0xA3, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xD6, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x2B, 0x6D, 0x95, 0x95, 0x55, 0x55,
+ 0x55, 0x55, 0xCB, 0x55, 0x95, 0x2C, 0x2C, 0x95,
+ 0x55, 0x90, 0xCB, 0xCB, 0xCB, 0xCB, 0x90, 0x70,
+ 0x2C, 0xD6, 0xD6, 0x2C, 0x2C, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x2C, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x2C, 0xA1, 0x2C, 0x95, 0x55, 0x95,
+ 0xE6, 0x88, 0x20, 0x20, 0x3F, 0xA3, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0x42, 0xA3, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x88, 0x2B, 0xD6, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x2C, 0xA1, 0x2C, 0x95,
+ 0x55, 0x55, 0x95, 0x95, 0x95, 0x55, 0x55, 0x55,
+ 0xA1, 0xD6, 0xD6, 0xA1, 0x2C, 0x2C, 0x95, 0x2C,
+ 0x2C, 0x2C, 0x95, 0x2C, 0x95, 0x95, 0x55, 0x95,
+ 0x95, 0x2C, 0x2C, 0x2C, 0x95, 0xCB, 0xCB, 0x94,
+ 0x20, 0x20, 0x20, 0x20, 0xE6, 0x83, 0x65, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0x6B, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0x6B, 0xA3, 0xD2,
+ 0xD2, 0x6B, 0xC9, 0x20, 0x20, 0x88, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x88, 0x8A, 0xA1, 0x95, 0x95,
+ 0x95, 0x55, 0x95, 0x2C, 0xA1, 0x2C, 0x95, 0xCB,
+ 0xCB, 0x55, 0x95, 0x95, 0x95, 0x55, 0x55, 0x95,
+ 0x6D, 0x6D, 0x6D, 0xD6, 0xA1, 0x2C, 0x2C, 0x95,
+ 0x2C, 0x95, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x55, 0x70, 0x70, 0x2C, 0x80,
+ 0x88, 0x20, 0x20, 0x80, 0x94, 0xD6, 0x32, 0x6B,
+ 0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xA3, 0xD2, 0xD0, 0xBF, 0x2A,
+ 0x2A, 0xD0, 0x6D, 0x34, 0x20, 0xE1, 0x88, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x88, 0xA1, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x55, 0x70, 0x70,
+ 0x70, 0x90, 0xCB, 0xCB, 0xCB, 0x95, 0x95, 0x2C,
+ 0xD0, 0x6D, 0xD6, 0xD6, 0xA1, 0xA1, 0xA1, 0x2C,
+ 0x2C, 0x2C, 0x2C, 0x95, 0x55, 0x55, 0x55, 0x95,
+ 0x95, 0x2C, 0x95, 0x55, 0xCB, 0xCB, 0x95, 0x88,
+ 0x20, 0x20, 0x88, 0xD8, 0x2C, 0xD1, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x65, 0x65, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x42, 0x6B, 0xEC,
+ 0xBF, 0x2A, 0xEC, 0x95, 0x20, 0x34, 0x2B, 0xE1,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x99, 0x95, 0x55,
+ 0x55, 0x55, 0x95, 0x95, 0x95, 0x55, 0xCB, 0xCB,
+ 0x55, 0x55, 0xCB, 0xCB, 0xCB, 0x55, 0x95, 0x95,
+ 0x32, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C,
+ 0xA1, 0x95, 0x95, 0x95, 0x55, 0xCB, 0xCB, 0x55,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x55, 0x99, 0x20,
+ 0xE1, 0xE1, 0x43, 0x47, 0x6B, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0x42, 0xEC, 0xBF, 0xA3, 0x8A, 0x20, 0x88, 0xD8,
+ 0x2B, 0x20, 0x20, 0x20, 0x88, 0x88, 0x2C, 0xCB,
+ 0xCB, 0x95, 0x95, 0x2C, 0x95, 0x95, 0x55, 0x95,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x95, 0x55, 0x95,
+ 0x6D, 0x55, 0x55, 0x55, 0x95, 0x95, 0x2C, 0x95,
+ 0x2C, 0x95, 0x95, 0x55, 0x55, 0x55, 0x55, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0xA1, 0x34, 0x20,
+ 0xC9, 0x20, 0xE1, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xA3, 0x83, 0x6D, 0x20, 0x88, 0x88,
+ 0x2B, 0x34, 0x20, 0x20, 0x20, 0x88, 0xD5, 0x55,
+ 0x55, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x55, 0x55, 0x95, 0x95,
+ 0x2C, 0x55, 0xCB, 0x55, 0xCB, 0x55, 0x55, 0x95,
+ 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0x2C, 0x95, 0x95, 0x55, 0x95, 0x2C, 0x20, 0xD8,
+ 0xE1, 0x20, 0x70, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x65, 0xA3, 0x92, 0x43, 0x7D,
+ 0xD8, 0xC9, 0x88, 0x20, 0x20, 0x20, 0x43, 0xD6,
+ 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x55, 0x95, 0x2C,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x95, 0x2C,
+ 0xA1, 0x55, 0x55, 0x55, 0x55, 0x95, 0x95, 0x55,
+ 0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0xA1, 0x2C,
+ 0xA1, 0x2C, 0x2C, 0x95, 0x2C, 0x99, 0x88, 0xB1,
+ 0x20, 0xD8, 0x42, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x34, 0x8A,
+ 0xC9, 0x34, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x90,
+ 0xA1, 0xA1, 0xA1, 0x2C, 0x2C, 0x95, 0x95, 0x2C,
+ 0x2C, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
+ 0xD6, 0x2C, 0x55, 0x55, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x55, 0xCB, 0x55, 0x2C, 0x2C, 0xA1, 0x2C, 0xA1,
+ 0xA1, 0xA1, 0x2C, 0x2C, 0x6D, 0x43, 0xD8, 0x80,
+ 0x88, 0xCB, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x32, 0x80, 0xE1,
+ 0x80, 0x20, 0xB1, 0x20, 0x20, 0x20, 0x20, 0xC9,
+ 0xD6, 0xA1, 0xA1, 0xA1, 0x2C, 0xA1, 0x2C, 0x2C,
+ 0x2C, 0x55, 0x55, 0x55, 0x95, 0x95, 0x95, 0x55,
+ 0xD6, 0x95, 0x95, 0x95, 0x2C, 0xA1, 0x2C, 0x2C,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x2C, 0x95, 0x2C,
+ 0x2C, 0x2C, 0x2C, 0x95, 0xCB, 0x20, 0xC9, 0x20,
+ 0xE1, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xD8, 0x20,
+ 0x20, 0x20, 0x2B, 0x43, 0x20, 0x20, 0x20, 0x88,
+ 0xD6, 0x2C, 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x55,
+ 0x95, 0x55, 0x55, 0xCB, 0x55, 0xCB, 0xCB, 0x55,
+ 0x2C, 0x55, 0x55, 0x95, 0x2C, 0x2C, 0xA1, 0x95,
+ 0x55, 0x95, 0x55, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x55, 0xCB, 0x70, 0xCB, 0xC9, 0x80, 0x2B, 0x20,
+ 0xA0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x92, 0x20,
+ 0x20, 0x20, 0xE1, 0xD8, 0x20, 0x20, 0x20, 0x20,
+ 0x95, 0x95, 0x55, 0xCB, 0x90, 0x90, 0x70, 0x90,
+ 0x90, 0x90, 0xCB, 0xCB, 0xCB, 0xCB, 0x55, 0x95,
+ 0x95, 0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x95, 0x95, 0x55, 0x55, 0x55, 0x95, 0x95, 0x55,
+ 0x90, 0x47, 0xA0, 0x55, 0x20, 0x2B, 0x43, 0x88,
+ 0x6D, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x28, 0x20,
+ 0x20, 0x20, 0xE1, 0xE1, 0x20, 0x20, 0x20, 0x20,
+ 0x28, 0x55, 0x90, 0x47, 0xA0, 0x47, 0x94, 0x70,
+ 0x55, 0x95, 0x95, 0x55, 0xCB, 0x55, 0x55, 0x2C,
+ 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x95, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x95, 0x55,
+ 0x94, 0xE6, 0x70, 0x2B, 0x88, 0x2B, 0x88, 0xE1,
+ 0x65, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x47, 0x20,
+ 0x20, 0x20, 0xE1, 0x34, 0x20, 0x20, 0x20, 0x20,
+ 0xB1, 0x95, 0x94, 0xE6, 0xA0, 0x47, 0x70, 0x55,
+ 0x2C, 0xA1, 0x2C, 0x55, 0x90, 0xCB, 0x2C, 0xD6,
+ 0x6D, 0xA1, 0x2C, 0x95, 0x95, 0xA1, 0x2C, 0xA1,
+ 0x2C, 0x2C, 0x95, 0x95, 0x95, 0x95, 0x95, 0x55,
+ 0x70, 0xE6, 0x70, 0x20, 0x20, 0x7D, 0x20, 0x8A,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x65, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x94, 0x20,
+ 0x20, 0x20, 0xD8, 0x88, 0x20, 0x20, 0x20, 0x20,
+ 0xD8, 0x2C, 0x94, 0x47, 0x47, 0x90, 0x95, 0x95,
+ 0xA1, 0x6D, 0xA1, 0x90, 0x94, 0x55, 0x2C, 0xD6,
+ 0xD0, 0xA1, 0x95, 0x95, 0x2C, 0x2C, 0xA1, 0x2C,
+ 0x95, 0x95, 0x55, 0x55, 0x55, 0x95, 0x2C, 0x2C,
+ 0xCB, 0x95, 0xD8, 0x20, 0x20, 0xB1, 0x88, 0x28,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE2, 0xA3, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x20,
+ 0x20, 0x20, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x88, 0xD6, 0x55, 0x47, 0x94, 0x55, 0x2C, 0xA1,
+ 0xA1, 0xD6, 0x95, 0x94, 0x94, 0x55, 0xD6, 0x6D,
+ 0xBF, 0x95, 0x90, 0xCB, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0x55, 0x95, 0xCB, 0x90, 0x90, 0x95, 0x2C, 0x95,
+ 0x90, 0x70, 0x20, 0x20, 0x34, 0x8A, 0x20, 0x94,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x65, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x20,
+ 0x20, 0x88, 0x2B, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x88, 0xD6, 0xCB, 0x47, 0x94, 0x55, 0xA1, 0xD6,
+ 0xD6, 0x2C, 0xCB, 0x47, 0x70, 0xA1, 0x6D, 0x2A,
+ 0x95, 0x47, 0x47, 0x70, 0x95, 0xA1, 0x2C, 0x95,
+ 0x55, 0x55, 0x90, 0x90, 0x55, 0x55, 0x55, 0x90,
+ 0x47, 0xD5, 0x20, 0x20, 0x80, 0xD5, 0x43, 0xCB,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x42, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xCB, 0x20,
+ 0x20, 0x80, 0x34, 0x20, 0x20, 0x20, 0x88, 0x20,
+ 0x20, 0x2C, 0x47, 0xE6, 0x70, 0x2C, 0xD6, 0xD6,
+ 0xA1, 0x2C, 0x55, 0xCB, 0x95, 0xA1, 0x6D, 0xD6,
+ 0x90, 0x47, 0x47, 0x90, 0x2C, 0xA1, 0x2C, 0x95,
+ 0x55, 0x55, 0x90, 0x90, 0x55, 0x55, 0x55, 0x70,
+ 0x94, 0x8A, 0x20, 0x88, 0x88, 0xE1, 0xD8, 0x95,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE2, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x47, 0x20,
+ 0x43, 0x7D, 0x43, 0x80, 0x88, 0x20, 0x20, 0x20,
+ 0x88, 0xCB, 0x94, 0x70, 0x55, 0xA1, 0xD6, 0xD6,
+ 0xA1, 0x2C, 0x2C, 0x95, 0xA1, 0xA1, 0xD6, 0xA1,
+ 0x94, 0xE6, 0x47, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
+ 0x55, 0x55, 0xCB, 0xCB, 0x55, 0x55, 0xCB, 0xCB,
+ 0x55, 0xA0, 0x43, 0x86, 0x86, 0x43, 0xD8, 0xCB,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x65, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x3F, 0x80,
+ 0xD8, 0x80, 0x88, 0x34, 0xD8, 0x2B, 0xD8, 0x20,
+ 0x99, 0x90, 0x55, 0x95, 0x2C, 0xA1, 0xD6, 0xD6,
+ 0xA1, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0x94, 0x94, 0x70, 0x2C, 0xA1, 0xD6, 0xA1, 0x2C,
+ 0x55, 0x55, 0xCB, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x95, 0x44, 0xBC, 0x3E, 0x5D, 0xD3, 0x79, 0x92,
+ 0xA3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x65, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0x9A, 0x34,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x99, 0xE1,
+ 0x70, 0x55, 0x95, 0xA1, 0xD6, 0xD6, 0xD6, 0xA1,
+ 0x2C, 0x95, 0x55, 0x55, 0x95, 0x95, 0x95, 0x95,
+ 0x70, 0x70, 0x55, 0x2C, 0xD6, 0xD6, 0xA1, 0x95,
+ 0x55, 0x90, 0xCB, 0xCB, 0x55, 0x55, 0x2C, 0x2C,
+ 0x32, 0x9D, 0xEB, 0x5D, 0x69, 0x49, 0x84, 0xF0,
+ 0xB1, 0xEC, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x42, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xC1, 0x4E, 0x21, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0xC9, 0xD8,
+ 0xBB, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C,
+ 0x95, 0x55, 0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C,
+ 0x55, 0xCB, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x55,
+ 0x90, 0x70, 0x90, 0x55, 0x95, 0x95, 0x6D, 0xD0,
+ 0xC2, 0x48, 0x6A, 0x49, 0x69, 0x82, 0x5D, 0x2F,
+ 0x59, 0x7D, 0xBF, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x65, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xEA, 0xC7, 0x7E, 0x66,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x43, 0x5A,
+ 0x46, 0x27, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x95,
+ 0x95, 0x55, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0x95, 0x90, 0x55, 0x2C, 0xA1, 0xA1, 0x95, 0x55,
+ 0x94, 0x94, 0x2C, 0x2A, 0x72, 0x3B, 0x56, 0xDD,
+ 0xDF, 0x29, 0x5D, 0x49, 0x89, 0x5D, 0x3E, 0x69,
+ 0x93, 0x66, 0x34, 0xA1, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x65, 0x42, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xEA, 0x3E, 0x5A, 0x66,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x5B, 0x73,
+ 0x89, 0x4C, 0xBF, 0x2C, 0x95, 0x2C, 0x2C, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x2C, 0x70, 0x55, 0x2C, 0xD6, 0xD6, 0x2C, 0xCB,
+ 0x70, 0x55, 0xE7, 0x60, 0x4A, 0x48, 0xCD, 0x4A,
+ 0x29, 0x73, 0x5D, 0x82, 0x49, 0x49, 0x49, 0x49,
+ 0x3A, 0x57, 0x88, 0x88, 0x70, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0x42, 0x73, 0x50, 0xBE, 0x79,
+ 0x20, 0x20, 0x20, 0x20, 0x66, 0xCC, 0x37, 0x9C,
+ 0x3E, 0xCE, 0xBF, 0x95, 0x95, 0x95, 0x2C, 0x95,
+ 0x95, 0x55, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0x55,
+ 0xA1, 0x55, 0x95, 0xA1, 0xD6, 0xA1, 0x55, 0x94,
+ 0x94, 0xE8, 0x60, 0xC4, 0x3E, 0x2D, 0x2D, 0x2D,
+ 0x33, 0x5D, 0x82, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x89, 0xAA, 0x59, 0x20, 0x20, 0x28, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xEC, 0x4A, 0x2D, 0x50, 0x78, 0x2E,
+ 0x57, 0x51, 0xF0, 0x57, 0x31, 0x4D, 0x50, 0x2D,
+ 0x5D, 0xF2, 0xA1, 0x2C, 0x95, 0x95, 0x55, 0x55,
+ 0x90, 0x90, 0x70, 0x90, 0xCB, 0x55, 0x55, 0x55,
+ 0x6D, 0x2C, 0xA1, 0xD6, 0xD6, 0xA1, 0x55, 0x94,
+ 0x70, 0xB9, 0x75, 0x50, 0x3E, 0x49, 0x49, 0x49,
+ 0x5D, 0x82, 0x49, 0x49, 0x82, 0x49, 0x49, 0x49,
+ 0x89, 0x69, 0x4F, 0x20, 0x20, 0x20, 0x8A, 0x42,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0x83, 0x4A, 0x3A, 0x50, 0x62, 0x23,
+ 0x81, 0xB8, 0xB8, 0xE9, 0x5F, 0x29, 0x33, 0x5D,
+ 0x5D, 0x73, 0xE8, 0xCB, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0xD6, 0xA1, 0xA1, 0xA1, 0xA1, 0x55, 0x70, 0x70,
+ 0xCB, 0x68, 0x75, 0x50, 0x82, 0x49, 0x49, 0x49,
+ 0x5D, 0x49, 0x49, 0x5D, 0x49, 0x49, 0x5D, 0x82,
+ 0x69, 0x5D, 0x25, 0xF0, 0x20, 0x20, 0x20, 0xE1,
+ 0x2A, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0x4B, 0xF4, 0xDF, 0x50, 0x73, 0x76, 0x48,
+ 0x75, 0xDF, 0x75, 0x62, 0xC4, 0x33, 0x82, 0x49,
+ 0x5D, 0x5D, 0xA8, 0xF5, 0x55, 0x55, 0x55, 0x55,
+ 0x2C, 0x2C, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0x2C, 0x2C, 0x2C, 0x95, 0x95, 0xCB, 0x70, 0x70,
+ 0x95, 0x83, 0x5F, 0xEA, 0x2D, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x5D, 0x49, 0x22, 0x5A, 0x79, 0x20, 0x20, 0x20,
+ 0x80, 0xD2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0x65, 0xD0, 0x63, 0x5F, 0x29, 0x2D, 0x2D, 0xEA,
+ 0x29, 0x29, 0x76, 0x50, 0x2D, 0x82, 0x49, 0x49,
+ 0x3E, 0x49, 0x5C, 0xB0, 0xBA, 0x95, 0x55, 0x55,
+ 0x2C, 0xA1, 0xD6, 0xD6, 0xD6, 0xA1, 0x2C, 0x2C,
+ 0xA1, 0x95, 0x95, 0x55, 0xCB, 0x70, 0x70, 0x55,
+ 0x2C, 0x83, 0x60, 0x76, 0x5D, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x5D, 0x89, 0xDC, 0x8B, 0x20, 0x20, 0x20,
+ 0x20, 0x95, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE2, 0x32, 0x85, 0xE3, 0x29, 0x2D, 0x33, 0x2D,
+ 0x2D, 0x2D, 0x6A, 0x2D, 0x33, 0x5D, 0x49, 0x82,
+ 0x49, 0x49, 0x82, 0x73, 0x5C, 0x9E, 0x2C, 0x55,
+ 0x2C, 0xA1, 0xD6, 0xA1, 0x2C, 0x2C, 0x95, 0x95,
+ 0x2C, 0x95, 0x55, 0xCB, 0x90, 0x90, 0xCB, 0x95,
+ 0x2C, 0x6D, 0x41, 0x6F, 0x3E, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x82, 0x3E, 0x4E, 0x38, 0xCA, 0x20, 0x20,
+ 0x20, 0x55, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0x65,
+ 0x42, 0xA0, 0xD4, 0xE3, 0x29, 0x2D, 0x82, 0x5D,
+ 0x5D, 0x82, 0x82, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x3E, 0x49, 0x49, 0x49, 0x5C, 0x56, 0xD6,
+ 0xA1, 0xA1, 0xA1, 0x95, 0x55, 0x55, 0x55, 0x95,
+ 0xA1, 0x55, 0x90, 0x70, 0x94, 0x70, 0x95, 0x2C,
+ 0x2C, 0xD6, 0xDD, 0x6F, 0x33, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x5D, 0x5D, 0x82, 0x69, 0x22, 0x62, 0x80, 0x34,
+ 0x94, 0x6B, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0xE5, 0x65, 0x6B,
+ 0xD5, 0x88, 0x5B, 0xE3, 0x29, 0x5D, 0x5D, 0x5D,
+ 0x5D, 0x5D, 0x5D, 0x5D, 0x49, 0x49, 0x49, 0x82,
+ 0x49, 0x49, 0x89, 0x49, 0x82, 0x49, 0x71, 0xBA,
+ 0x6D, 0x6D, 0xA1, 0x95, 0x55, 0xCB, 0x55, 0x55,
+ 0x2C, 0x55, 0x70, 0x70, 0x70, 0x90, 0x95, 0xA1,
+ 0x2C, 0xA1, 0x41, 0x76, 0x5D, 0x5D, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x5D, 0x82, 0x5D, 0x89, 0x5E, 0x96, 0x65,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0x65, 0x65, 0xEC, 0xB1,
+ 0x20, 0x20, 0xCA, 0x23, 0x29, 0x33, 0x49, 0x5D,
+ 0x49, 0x82, 0x49, 0x49, 0x49, 0x49, 0x49, 0x82,
+ 0x49, 0x82, 0x5D, 0x5D, 0x5D, 0x2D, 0x5C, 0x8F,
+ 0x6D, 0xD6, 0x2C, 0x55, 0x90, 0xCB, 0x95, 0x95,
+ 0x95, 0x55, 0x70, 0x94, 0x70, 0x55, 0x2C, 0xA1,
+ 0x95, 0xE8, 0x5F, 0x76, 0x33, 0x5D, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x3E, 0x9C, 0x2F, 0x68,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0x65, 0xE5, 0x65, 0xE5, 0x6B, 0x90, 0x80, 0x20,
+ 0x20, 0x20, 0x4F, 0x81, 0x50, 0x3E, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x69, 0x69, 0x49, 0x5D, 0x2D, 0xC4, 0x46, 0xA3,
+ 0xD6, 0x55, 0x70, 0x94, 0x94, 0x70, 0xCB, 0x55,
+ 0x55, 0xCB, 0x70, 0x47, 0x70, 0x95, 0xA1, 0xA1,
+ 0x95, 0xBD, 0x75, 0x2D, 0x33, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x5D, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x5D, 0x2D, 0xB5, 0xDB,
+ 0xD6, 0x65, 0xE5, 0x65, 0xE5, 0xE5, 0x65, 0xE5,
+ 0x65, 0x65, 0x6B, 0x95, 0x2B, 0x88, 0x20, 0x20,
+ 0x20, 0x20, 0x8B, 0x81, 0x29, 0x33, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x3E, 0x3E, 0x5E, 0x41, 0x97, 0x27, 0xD6,
+ 0x55, 0x94, 0xE6, 0xE6, 0x47, 0x70, 0x55, 0x55,
+ 0x94, 0x70, 0x94, 0x94, 0x70, 0x55, 0xA1, 0x2C,
+ 0x6D, 0xC5, 0x39, 0x6A, 0x5D, 0x5D, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x3E, 0xEA, 0x30, 0x77,
+ 0xE1, 0xC9, 0x94, 0x2C, 0xD6, 0xD6, 0xA1, 0x55,
+ 0x47, 0x9F, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x80, 0x91, 0x81, 0x6A, 0x2D, 0x49, 0x49,
+ 0x49, 0x5D, 0x5D, 0x49, 0x49, 0x5D, 0x5D, 0x82,
+ 0xEB, 0x4A, 0x41, 0xC2, 0x8F, 0xF5, 0xA1, 0x55,
+ 0x94, 0x28, 0xA0, 0x47, 0x70, 0x55, 0x95, 0x95,
+ 0x47, 0x70, 0x70, 0x94, 0x90, 0x95, 0xA1, 0x2C,
+ 0xE8, 0xA6, 0x39, 0x76, 0x50, 0x50, 0x2D, 0x2D,
+ 0x3E, 0x3E, 0x5D, 0x3E, 0x5D, 0x5D, 0x49, 0x82,
+ 0x49, 0x49, 0x49, 0x82, 0x82, 0x50, 0x75, 0xE0,
+ 0x57, 0x20, 0x88, 0x88, 0x20, 0x20, 0x88, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x79, 0x91, 0x81, 0x76, 0x33, 0x49, 0x49,
+ 0x5D, 0x82, 0x49, 0x49, 0x3E, 0x6A, 0xEA, 0x29,
+ 0xDF, 0x97, 0xBF, 0x6D, 0x6D, 0xD6, 0x55, 0x47,
+ 0x28, 0x28, 0x47, 0x70, 0x55, 0x95, 0x2C, 0x2C,
+ 0x95, 0x95, 0x55, 0x90, 0x90, 0x95, 0xA1, 0xA1,
+ 0xD6, 0x26, 0x45, 0x81, 0x5F, 0x30, 0x48, 0x6F,
+ 0x6F, 0x29, 0x29, 0x6A, 0x2D, 0x2D, 0x5D, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x2D, 0x76, 0x6E, 0x77,
+ 0x5B, 0x66, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x79, 0xA9, 0xB8, 0x39, 0x50, 0x5D, 0x5D,
+ 0x5D, 0x5D, 0x3E, 0x2D, 0x29, 0x76, 0xCD, 0x37,
+ 0xB9, 0xA1, 0xA1, 0x6D, 0x6D, 0x2C, 0x94, 0x28,
+ 0xD5, 0xE6, 0x70, 0x55, 0x95, 0xA1, 0x2C, 0xA1,
+ 0xBF, 0xA1, 0x95, 0xCB, 0x55, 0x95, 0xA1, 0x2C,
+ 0x95, 0x83, 0xDE, 0x87, 0xB6, 0xBE, 0x40, 0x6E,
+ 0x81, 0x81, 0x78, 0x78, 0x39, 0x6F, 0xEA, 0x2D,
+ 0x2D, 0x33, 0x33, 0x33, 0x76, 0x30, 0x64, 0x54,
+ 0x5B, 0x66, 0x20, 0x20, 0x66, 0x20, 0x88, 0x20,
+ 0x20, 0x20, 0x88, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x88, 0x34, 0x8B, 0xF1, 0x23, 0x6F, 0x50, 0x2D,
+ 0x2D, 0x6A, 0x29, 0x6F, 0x78, 0x84, 0x9B, 0xD2,
+ 0x2C, 0x2C, 0xD6, 0x6D, 0x6D, 0x2C, 0x47, 0xA0,
+ 0xE6, 0x70, 0x55, 0x95, 0x2C, 0xA1, 0xA1, 0xA1,
+ 0xD2, 0x95, 0x55, 0xCB, 0x55, 0x2C, 0xD6, 0xA1,
+ 0x95, 0x95, 0xA1, 0xD6, 0x6D, 0x6D, 0xBA, 0xF3,
+ 0x8D, 0x36, 0x74, 0x36, 0xF1, 0xB8, 0x23, 0x78,
+ 0x62, 0x4A, 0x29, 0x62, 0x23, 0xF1, 0x54, 0x31,
+ 0x57, 0x2B, 0x90, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C, 0x2C, 0xCB,
+ 0xE6, 0x7D, 0xCA, 0xB7, 0xB8, 0x75, 0x6F, 0x6F,
+ 0x76, 0x6F, 0x78, 0x81, 0x53, 0xBD, 0x6D, 0x2C,
+ 0x95, 0x95, 0xA1, 0x6D, 0xA1, 0x55, 0x94, 0xE6,
+ 0x70, 0xCB, 0x55, 0x95, 0xA1, 0xD6, 0xD6, 0xA1,
+ 0xD0, 0x94, 0x94, 0x90, 0x95, 0x2C, 0xD6, 0xA1,
+ 0x95, 0x55, 0x2C, 0xA1, 0xD6, 0xA1, 0x95, 0x2C,
+ 0xD6, 0x68, 0xAB, 0x6C, 0xA4, 0x77, 0x77, 0xAD,
+ 0x40, 0x53, 0x6E, 0x40, 0xB7, 0x54, 0x31, 0xD7,
+ 0xAC, 0xD6, 0x55, 0x55, 0x95, 0x95, 0x95, 0x55,
+ 0x95, 0x2C, 0x2C, 0xA1, 0x95, 0x95, 0x2C, 0xA1,
+ 0x6D, 0xD2, 0x7C, 0x54, 0xAD, 0x40, 0x6E, 0x81,
+ 0x81, 0x6E, 0x36, 0xDA, 0xE8, 0xD6, 0xD6, 0x2C,
+ 0x2C, 0x2C, 0xA1, 0xD6, 0x95, 0x90, 0x94, 0x47,
+ 0x94, 0x94, 0x70, 0x55, 0x2C, 0xD6, 0xA1, 0x95,
+ 0x95, 0x28, 0x47, 0x90, 0x95, 0x2C, 0xA1, 0x2C,
+ 0x55, 0x95, 0x2C, 0xA1, 0xA1, 0x2C, 0x2C, 0x2C,
+ 0x2C, 0xA1, 0x55, 0x70, 0x95, 0x2C, 0xB2, 0xB4,
+ 0xC3, 0xC3, 0x54, 0x54, 0xA9, 0x31, 0xCA, 0x2A,
+ 0x95, 0x90, 0x55, 0x95, 0x2C, 0xA1, 0x2C, 0x95,
+ 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0xD6,
+ 0x6D, 0x2A, 0xB2, 0x4F, 0x31, 0x2E, 0xE0, 0xAD,
+ 0xB7, 0xC8, 0xB4, 0xF5, 0x2C, 0xA1, 0xA1, 0xA1,
+ 0x95, 0x2C, 0xA1, 0x2C, 0x95, 0x70, 0x94, 0x94,
+ 0x94, 0x94, 0x70, 0x95, 0xD6, 0xD6, 0x2C, 0x95,
+ 0x94, 0x28, 0x47, 0xCB, 0x95, 0x2C, 0xA1, 0xA1,
+ 0x95, 0x55, 0x2C, 0xA1, 0xD6, 0xA1, 0x95, 0x95,
+ 0x95, 0x2C, 0x55, 0x70, 0x70, 0x70, 0x94, 0x2C,
+ 0x63, 0xBB, 0xA5, 0xD7, 0xCA, 0xB3, 0x6D, 0x2C,
+ 0x55, 0x55, 0x95, 0x2C, 0x2C, 0x2C, 0x95, 0x95,
+ 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0xD6, 0x2C, 0x70, 0x95, 0xAC, 0xC0, 0xDB, 0xEF,
+ 0xEF, 0xA2, 0xE8, 0x95, 0x95, 0xA1, 0xD6, 0xA1,
+ 0x95, 0x55, 0x2C, 0x95, 0x55, 0x70, 0x70, 0x70,
+ 0x94, 0x70, 0x55, 0xD6, 0x6D, 0x6D, 0x95, 0x55,
+ 0x70, 0x47, 0x70, 0x95, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1, 0x95, 0x55,
+ 0x55, 0x95, 0x55, 0x55, 0x55, 0x55, 0x55, 0x95,
+ 0xA1, 0xF5, 0xBF, 0xBF, 0xA1, 0x95, 0x95, 0x95,
+ 0x95, 0x55, 0x2C, 0x2C, 0x95, 0x55, 0x55, 0x95,
+ 0x95, 0x95, 0xA1, 0xA1, 0xA1, 0xA1, 0x2C, 0xA1,
+ 0x2C, 0x55, 0x70, 0x94, 0x90, 0x2C, 0x6D, 0x6D,
+ 0x6D, 0xA1, 0x2C, 0x95, 0x2C, 0xA1, 0xD6, 0xA1,
+ 0x2C, 0x55, 0x55, 0x95, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x95, 0xD6, 0x6D, 0xBF, 0xD6, 0x55, 0xCB,
+ 0x55, 0x55, 0x55, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0xA1, 0x95, 0x2C, 0xA1, 0xA1, 0xA1, 0x2C, 0x95,
+ 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C, 0xA1,
+ 0x6D, 0xBF, 0x6D, 0x2C, 0x55, 0x55, 0x95, 0x95,
+ 0xCB, 0xCB, 0x55, 0x55, 0xCB, 0x55, 0x55, 0x95,
+ 0x95, 0x2C, 0x2C, 0xA1, 0xA1, 0xA1, 0x2C, 0x2C,
+ 0xA1, 0x95, 0xCB, 0xCB, 0x95, 0x95, 0x2C, 0x2C,
+ 0x2C, 0xA1, 0x2C, 0x2C, 0x2C, 0xA1, 0xA1, 0x2C,
+ 0x2C, 0x95, 0x55, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x2C, 0xA1, 0x6D, 0xBF, 0x6D, 0xA1, 0x55, 0x55,
+ 0x95, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x2C,
+ 0x2C, 0x95, 0x95, 0x95, 0x2C, 0x2C, 0x2C, 0x95,
+ 0x55, 0x95, 0x2C, 0x2C, 0xA1, 0xA1, 0xD6, 0xD6,
+ 0x6D, 0x6D, 0xA1, 0x95, 0xCB, 0x55, 0x95, 0x55,
+ 0x90, 0x70, 0xCB, 0xCB, 0x90, 0xCB, 0x95, 0x95,
+ 0x2C, 0x2C, 0xA1, 0xD6, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0x2C, 0x95, 0x95, 0x2C, 0x2C, 0x2C,
+ 0x2C, 0xA1, 0x2C, 0x95, 0x95, 0x95, 0x2C, 0x2C,
+ 0x2C, 0x95, 0x55, 0x55, 0x2C, 0x2C, 0xA1, 0xA1,
+ 0xD6, 0xD6, 0x6D, 0x6D, 0xA1, 0x55, 0xCB, 0x55
+};
+
+#endif
+
+#ifdef INCLUDE_LINUX_LOGOBW
+
+unsigned char linux_logo_bw[] __initdata = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
+ 0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
+ 0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
+ 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
+ 0x99, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF9, 0xF3, 0xBC, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
+ 0x19, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF9, 0xC0, 0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
+ 0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF9, 0xC0, 0x21, 0xD8, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0xC0, 0x1F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
+ 0xC0, 0x7C, 0x04, 0x81, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE3, 0x80, 0x00, 0x7C, 0x40, 0x11, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0xD2, 0x29,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
+ 0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
+ 0x00, 0x3F, 0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x1E, 0x00, 0x00, 0x1F, 0x80, 0x19, 0xFF, 0xFF,
+ 0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1E, 0x80, 0x19,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1E,
+ 0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
+ 0x00, 0x0F, 0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC,
+ 0xF8, 0x00, 0x00, 0x0E, 0x80, 0x11, 0xFF, 0xFF,
+ 0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x06, 0x00, 0x11,
+ 0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x06,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
+ 0x00, 0x02, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xF1,
+ 0xF0, 0x00, 0x00, 0x02, 0x80, 0x10, 0xFF, 0xFF,
+ 0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0x97, 0x10,
+ 0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
+ 0xDF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
+ 0x00, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xC7,
+ 0xC0, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
+ 0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8,
+ 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
+ 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
+ 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x9F,
+ 0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
+ 0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0x18,
+ 0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
+ 0xA8, 0x11, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
+ 0x00, 0x02, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x99,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xFF, 0xFF,
+ 0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x01,
+ 0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
+ 0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0x40,
+ 0x38, 0x00, 0x00, 0x00, 0xFE, 0x47, 0xFF, 0xFF,
+ 0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x23,
+ 0xFF, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
+ 0x78, 0x11, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
+ 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
+ 0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
+ 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
+ 0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
+ 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
+ 0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
+ 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
+ 0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
+ 0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
+ 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
+ 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
+ 0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
+ 0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
+ 0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
+ 0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
+ 0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
+ 0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
+ 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
+ 0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+#endif
+
+#ifdef INCLUDE_LINUX_LOGO16
+
+unsigned char linux_logo16_red[] __initdata = {
+ 0x00, 0x90, 0xb0, 0x9c, 0xf7, 0x35, 0x83, 0xa5,
+ 0x65, 0x8f, 0x98, 0xc9, 0xdb, 0xe1, 0xe7, 0xf8
+};
+
+unsigned char linux_logo16_green[] __initdata = {
+ 0x00, 0x90, 0xb0, 0x9c, 0xf7, 0x2e, 0x83, 0xa5,
+ 0x65, 0x6e, 0x98, 0x89, 0xbf, 0xac, 0xda, 0xf8
+};
+
+unsigned char linux_logo16_blue[] __initdata = {
+ 0x00, 0x90, 0xaf, 0x9c, 0xf7, 0x2b, 0x82, 0xa5,
+ 0x65, 0x41, 0x97, 0x1e, 0x60, 0x29, 0xa5, 0xf8
+};
+
+unsigned char linux_logo16[] __initdata = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa1, 0x11, 0x11,
+ 0x61, 0x16, 0x66, 0x66, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0xa8, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x87, 0x77, 0x77, 0x77, 0x77,
+ 0x77, 0x77, 0x73, 0x33, 0x33, 0x3a, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x77,
+ 0x77, 0x27, 0x77, 0x77, 0x77, 0x33, 0x3a, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xa3, 0x33, 0x33, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x55, 0x50, 0x08, 0x33, 0x77, 0x77,
+ 0x77, 0x72, 0x72, 0x27, 0x77, 0x77, 0x33, 0x33,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xa3, 0x33, 0x33, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x58, 0x85, 0x00, 0x11, 0x11, 0xaa,
+ 0xa3, 0x37, 0x77, 0x72, 0x22, 0x22, 0x77, 0x73,
+ 0x33, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3,
+ 0x33, 0x37, 0x77, 0x33, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x56, 0x85, 0x00, 0x06, 0x66, 0x11,
+ 0x11, 0x1a, 0xa3, 0x37, 0x77, 0x72, 0x22, 0x77,
+ 0x73, 0x33, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33,
+ 0x33, 0x33, 0x33, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x55, 0x00, 0x00, 0x06, 0x66, 0x66,
+ 0x66, 0x66, 0x11, 0x1a, 0xa3, 0x77, 0x72, 0x22,
+ 0x77, 0x73, 0x3a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33,
+ 0x33, 0x33, 0x33, 0xa0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,
+ 0x66, 0x66, 0x66, 0x66, 0x11, 0xa3, 0x77, 0x22,
+ 0x22, 0x77, 0x33, 0x33, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x33,
+ 0x33, 0x3a, 0xa1, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x33,
+ 0xaa, 0x11, 0x16, 0x66, 0x66, 0x61, 0x1a, 0x37,
+ 0x22, 0x22, 0x77, 0x33, 0x3a, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0x33,
+ 0x3a, 0xa1, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x22,
+ 0x22, 0x77, 0x3a, 0x11, 0x66, 0x66, 0x66, 0x1a,
+ 0x37, 0x22, 0x22, 0x77, 0x33, 0x3a, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x33, 0x3a,
+ 0xa1, 0x11, 0x11, 0x10, 0x00, 0x00, 0x50, 0x00,
+ 0x00, 0x05, 0x80, 0x50, 0x00, 0x00, 0x07, 0x72,
+ 0x22, 0x22, 0x22, 0x73, 0xa1, 0x66, 0x66, 0x61,
+ 0x1a, 0x77, 0x22, 0x27, 0x73, 0x33, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x33, 0x3a, 0xaa,
+ 0x11, 0x11, 0x1a, 0xa0, 0x08, 0x71, 0x05, 0x00,
+ 0x00, 0x12, 0x22, 0x50, 0x00, 0x00, 0x07, 0x77,
+ 0x77, 0x72, 0x22, 0x22, 0x27, 0x31, 0x16, 0x66,
+ 0x61, 0x13, 0x77, 0x22, 0x77, 0x33, 0x3a, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0xaa, 0xa1,
+ 0x11, 0x1a, 0x33, 0x70, 0x07, 0x2e, 0x70, 0x00,
+ 0x01, 0x44, 0x42, 0x60, 0x00, 0x00, 0x02, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x27, 0x31, 0x66,
+ 0x66, 0x61, 0xa3, 0x72, 0x22, 0x77, 0x33, 0xaa,
+ 0xaa, 0xaa, 0xa3, 0x33, 0x33, 0xaa, 0xaa, 0x11,
+ 0x1a, 0x33, 0x77, 0x30, 0x04, 0x82, 0x40, 0x00,
+ 0x54, 0x48, 0x54, 0x40, 0x00, 0x00, 0x01, 0xaa,
+ 0x32, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x31,
+ 0x66, 0x66, 0x11, 0x37, 0x22, 0x27, 0x73, 0x3a,
+ 0xaa, 0xaa, 0xa3, 0x33, 0x3a, 0xaa, 0xaa, 0xaa,
+ 0xa3, 0x77, 0xaa, 0x10, 0x50, 0x08, 0x46, 0x05,
+ 0x54, 0x80, 0x50, 0x42, 0x00, 0x00, 0x08, 0x66,
+ 0x66, 0x1a, 0x32, 0x22, 0x22, 0x22, 0x22, 0x27,
+ 0x31, 0x66, 0x66, 0x13, 0x72, 0x22, 0x77, 0x33,
+ 0xaa, 0xaa, 0xaa, 0x33, 0xaa, 0xa1, 0xaa, 0xa3,
+ 0x37, 0xa1, 0x1a, 0x30, 0x50, 0x06, 0x26, 0x00,
+ 0x54, 0x00, 0x00, 0x44, 0x00, 0x00, 0x08, 0xe2,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22, 0x22,
+ 0x27, 0xa6, 0x66, 0x61, 0xa7, 0x72, 0x27, 0x73,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33,
+ 0x31, 0x11, 0x37, 0x70, 0x02, 0x00, 0xab, 0xbb,
+ 0xb6, 0x00, 0x00, 0xf4, 0x00, 0x00, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22,
+ 0x22, 0x23, 0x16, 0x66, 0x1a, 0x37, 0x22, 0x77,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0x3a,
+ 0x11, 0xa7, 0x33, 0x10, 0x04, 0x09, 0xbd, 0xdd,
+ 0xbd, 0xd0, 0x04, 0x45, 0x00, 0x0e, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x22,
+ 0x22, 0x22, 0x71, 0x66, 0x66, 0x13, 0x72, 0x27,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x33, 0x11,
+ 0xa3, 0x73, 0xa1, 0x60, 0x08, 0xbd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdb, 0x90, 0x00, 0x02, 0xec, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xce, 0x22,
+ 0x22, 0x22, 0x27, 0xa6, 0x66, 0x61, 0x37, 0x27,
+ 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0xa3, 0xa1, 0x1a,
+ 0x33, 0xa1, 0x16, 0x60, 0x0b, 0xbd, 0xdd, 0xdd,
+ 0xcd, 0xdd, 0xdd, 0xd9, 0x00, 0x00, 0xec, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0xa2,
+ 0x22, 0x22, 0x22, 0x7a, 0x66, 0x66, 0x13, 0x77,
+ 0x1a, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x11, 0x33,
+ 0xaa, 0x11, 0x66, 0x60, 0x9b, 0xdd, 0xdd, 0xdd,
+ 0xcd, 0xdd, 0xdb, 0xb9, 0x00, 0x00, 0xec, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xee, 0x61,
+ 0x72, 0x22, 0x22, 0x22, 0xa1, 0x66, 0x61, 0x37,
+ 0x1a, 0xaa, 0xaa, 0xaa, 0xa3, 0xa1, 0x13, 0x3a,
+ 0x11, 0x11, 0x11, 0x10, 0x5b, 0xdd, 0xdd, 0xdc,
+ 0xdd, 0xdd, 0xbd, 0xd9, 0x00, 0x00, 0xec, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xee, 0x86,
+ 0x17, 0x22, 0x22, 0x22, 0x23, 0x16, 0x66, 0xaa,
+ 0xaa, 0xa3, 0x3a, 0xaa, 0xaa, 0x1a, 0x3a, 0xa1,
+ 0x11, 0x11, 0x1a, 0x70, 0x05, 0xbd, 0xdd, 0xdd,
+ 0xdb, 0x5b, 0xdd, 0xb0, 0x00, 0x60, 0x2e, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xe6, 0x88,
+ 0x66, 0x32, 0x22, 0x22, 0x22, 0x36, 0x66, 0x11,
+ 0x33, 0x33, 0x3a, 0xaa, 0x11, 0xaa, 0xaa, 0xa1,
+ 0x11, 0x1a, 0x3a, 0x60, 0x02, 0x99, 0xbb, 0xb9,
+ 0x9b, 0xbb, 0xbc, 0x22, 0x00, 0x86, 0x5e, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xe1, 0x68,
+ 0x86, 0x63, 0x22, 0x22, 0x22, 0x2a, 0x66, 0x66,
+ 0x33, 0x33, 0xaa, 0xaa, 0x1a, 0xaa, 0xaa, 0x11,
+ 0x1a, 0xa7, 0x68, 0x80, 0x02, 0x2b, 0xbd, 0xbb,
+ 0xbb, 0xb9, 0x22, 0x22, 0x00, 0x06, 0x6e, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc7, 0xa6,
+ 0x88, 0x86, 0x32, 0x22, 0x22, 0x27, 0xa6, 0x66,
+ 0x33, 0x3a, 0xaa, 0xa1, 0xaa, 0xaa, 0xa1, 0x11,
+ 0xa3, 0xa6, 0x88, 0x80, 0x02, 0x22, 0x9b, 0xbb,
+ 0xbb, 0x22, 0x24, 0xf4, 0x60, 0x00, 0x0c, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xc2, 0x21,
+ 0x68, 0x88, 0x63, 0x22, 0x22, 0x22, 0x71, 0x66,
+ 0x33, 0x3a, 0x11, 0x11, 0xaa, 0xaa, 0x11, 0xaa,
+ 0x71, 0x88, 0x88, 0x00, 0x02, 0xe2, 0x26, 0x99,
+ 0x22, 0x22, 0x4f, 0xf4, 0x40, 0x00, 0x0c, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x22, 0x22,
+ 0x16, 0x88, 0x86, 0xa2, 0x22, 0x22, 0x27, 0x11,
+ 0x33, 0xa1, 0x11, 0x11, 0xaa, 0x31, 0x1a, 0xa3,
+ 0x68, 0x88, 0x81, 0x00, 0x54, 0x42, 0x22, 0x22,
+ 0x22, 0x44, 0xff, 0xff, 0x48, 0x00, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x22, 0x22,
+ 0x21, 0x88, 0x88, 0x6a, 0x22, 0x22, 0x22, 0x31,
+ 0x3a, 0xa1, 0x11, 0x1a, 0xa3, 0x11, 0x33, 0x36,
+ 0x88, 0x86, 0x30, 0x00, 0x4f, 0x44, 0x22, 0x22,
+ 0x24, 0xff, 0xff, 0xff, 0x44, 0x00, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x95, 0x22, 0x72,
+ 0x22, 0x18, 0x88, 0x86, 0x32, 0x22, 0x22, 0x27,
+ 0xaa, 0x11, 0x11, 0x1a, 0x31, 0x13, 0x33, 0x68,
+ 0x88, 0x6a, 0x00, 0x02, 0x4f, 0x4f, 0x42, 0x24,
+ 0x4f, 0xff, 0xff, 0xff, 0xf4, 0x50, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x22, 0x73,
+ 0x72, 0x26, 0x88, 0x88, 0x63, 0x22, 0x22, 0x22,
+ 0x11, 0x11, 0x11, 0xa3, 0xa1, 0x73, 0xa6, 0x88,
+ 0x81, 0xa5, 0x00, 0x04, 0x4f, 0x4f, 0x44, 0x4f,
+ 0xff, 0xff, 0xff, 0xff, 0xf4, 0x40, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x12, 0x27,
+ 0xaa, 0x22, 0x68, 0x55, 0x86, 0x72, 0x22, 0x22,
+ 0x11, 0x11, 0x1a, 0x33, 0x13, 0x3a, 0x18, 0x88,
+ 0x1a, 0x10, 0x00, 0x44, 0x4f, 0x4f, 0xff, 0x4f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x61, 0x22,
+ 0x3a, 0xa2, 0x26, 0x85, 0x58, 0x67, 0x22, 0x22,
+ 0x61, 0x61, 0x1a, 0x7a, 0x37, 0x31, 0x88, 0x81,
+ 0x11, 0x00, 0x05, 0xe4, 0x44, 0xff, 0xff, 0xff,
+ 0x4f, 0xf4, 0x44, 0xff, 0xff, 0xf5, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x88, 0x12,
+ 0x2a, 0xaa, 0x72, 0x68, 0x55, 0x81, 0x22, 0x22,
+ 0x66, 0x61, 0xa3, 0x33, 0x73, 0x16, 0x88, 0x11,
+ 0x10, 0x00, 0x08, 0x74, 0x44, 0x4f, 0x44, 0x44,
+ 0xf4, 0xf4, 0x44, 0x44, 0xe2, 0x44, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x88, 0x81,
+ 0x22, 0xaa, 0xa7, 0x26, 0x85, 0x88, 0x12, 0x22,
+ 0x66, 0x61, 0x37, 0xa7, 0x3a, 0x66, 0x66, 0x11,
+ 0x80, 0x00, 0x0a, 0x72, 0x44, 0x4f, 0x44, 0x4f,
+ 0xff, 0x44, 0x44, 0x22, 0x22, 0x24, 0x00, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0x85, 0x88,
+ 0x12, 0x2a, 0xaa, 0x22, 0x68, 0x58, 0x63, 0x22,
+ 0x66, 0x1a, 0x73, 0x77, 0x31, 0x66, 0x61, 0x11,
+ 0x00, 0x00, 0x07, 0x44, 0xff, 0x4f, 0xf4, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0x42, 0x22, 0x40, 0x9b,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x85, 0x55,
+ 0x81, 0x27, 0xaa, 0xa2, 0x78, 0x88, 0x86, 0x72,
+ 0x66, 0x13, 0x77, 0x73, 0x11, 0x66, 0x61, 0x76,
+ 0x00, 0x50, 0x84, 0xf4, 0xff, 0x4f, 0xf4, 0xff,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x42, 0x40, 0x9b,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x68, 0x55,
+ 0x58, 0x12, 0x3a, 0xaa, 0x23, 0x88, 0x88, 0xa7,
+ 0x66, 0xa7, 0x77, 0x7a, 0x16, 0x66, 0x1a, 0x15,
+ 0x05, 0x00, 0x4f, 0xf4, 0xff, 0x4f, 0xf4, 0xff,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0x24, 0x9b,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xb9, 0x26, 0x55,
+ 0x55, 0x81, 0x23, 0xaa, 0x32, 0x18, 0x88, 0x6a,
+ 0x61, 0x37, 0x77, 0x31, 0x66, 0x66, 0x17, 0x60,
+ 0x05, 0x08, 0x4f, 0xf4, 0xff, 0x4f, 0xf4, 0xff,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x4e, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x99, 0xa2, 0x65,
+ 0x55, 0x58, 0xa2, 0x7a, 0xa2, 0x26, 0x88, 0x61,
+ 0x61, 0x32, 0x27, 0xa1, 0x66, 0x61, 0x31, 0x60,
+ 0x00, 0x04, 0x4f, 0xf4, 0xff, 0x44, 0x44, 0xff,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0xf4, 0x99,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x9b, 0xaa, 0x26,
+ 0x55, 0x55, 0x87, 0x27, 0x33, 0x27, 0x68, 0x61,
+ 0x1a, 0x72, 0x27, 0xa6, 0x66, 0x6a, 0x71, 0x00,
+ 0x80, 0x84, 0xff, 0xf4, 0xff, 0x44, 0x44, 0xff,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x44, 0xf4, 0x99,
+ 0x9b, 0x9b, 0x99, 0xb9, 0xb9, 0x99, 0xaa, 0xa2,
+ 0x85, 0x55, 0x56, 0x22, 0x27, 0x22, 0x36, 0x66,
+ 0x13, 0x22, 0x23, 0x16, 0x86, 0x63, 0x73, 0x00,
+ 0x00, 0x44, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0xff,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x4f, 0x99,
+ 0x9b, 0x99, 0x99, 0x99, 0xb9, 0x99, 0xaa, 0xaa,
+ 0x28, 0x55, 0x58, 0x12, 0x22, 0x22, 0x21, 0x11,
+ 0xa3, 0x27, 0x7a, 0x66, 0x86, 0x17, 0x75, 0x05,
+ 0x05, 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0xff,
+ 0xff, 0x4f, 0x44, 0x4f, 0x4f, 0x44, 0x4f, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x3a, 0xaa,
+ 0xa2, 0x85, 0x58, 0x67, 0x72, 0x22, 0x27, 0xa1,
+ 0x37, 0x27, 0x7a, 0x68, 0x86, 0xa2, 0x70, 0x00,
+ 0x02, 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0xf4, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x23, 0xaa,
+ 0xa7, 0x78, 0x88, 0x81, 0x77, 0x22, 0x27, 0x3a,
+ 0x72, 0x73, 0x71, 0x68, 0x66, 0x32, 0x50, 0x00,
+ 0x04, 0x4f, 0xf4, 0xf4, 0xff, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0x44, 0x95,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x55, 0x12, 0x3a,
+ 0xaa, 0x21, 0x88, 0x81, 0x77, 0x27, 0x73, 0x73,
+ 0x72, 0x33, 0x36, 0x86, 0x61, 0x72, 0x00, 0x00,
+ 0x04, 0x44, 0xf4, 0xf4, 0xf4, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x44, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x8a, 0x27,
+ 0xaa, 0x77, 0x68, 0x61, 0x23, 0x71, 0x11, 0x3a,
+ 0x27, 0xa3, 0x36, 0x86, 0x61, 0x20, 0x00, 0x00,
+ 0x04, 0xf4, 0xf4, 0xf4, 0xf4, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x41, 0x59,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x95, 0x58, 0x77,
+ 0x27, 0x32, 0x36, 0x63, 0x23, 0x71, 0x66, 0x11,
+ 0x27, 0x13, 0xa6, 0x86, 0x6a, 0x20, 0x00, 0x50,
+ 0x04, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x41, 0x99,
+ 0x9b, 0xbb, 0xbb, 0xbb, 0xb9, 0x99, 0x68, 0x13,
+ 0x32, 0x22, 0x73, 0xa7, 0x2a, 0x31, 0x88, 0x66,
+ 0x7a, 0x13, 0x18, 0x66, 0x63, 0x20, 0x00, 0x06,
+ 0x0f, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xff, 0x4f, 0x4f, 0x49, 0x95,
+ 0xa9, 0xa9, 0x99, 0x97, 0x92, 0x99, 0x65, 0x6a,
+ 0x17, 0x22, 0x23, 0x72, 0x27, 0xaa, 0x88, 0x88,
+ 0xa1, 0x17, 0x68, 0x66, 0x67, 0x70, 0x00, 0x05,
+ 0x0f, 0x4f, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xff, 0xf4, 0xf4, 0x49, 0x9c,
+ 0x2e, 0xee, 0xee, 0xee, 0xee, 0xa9, 0x65, 0x8a,
+ 0x1a, 0xaa, 0x37, 0x72, 0x27, 0x37, 0x88, 0x88,
+ 0x11, 0x17, 0x68, 0x66, 0x67, 0x10, 0x9d, 0xd0,
+ 0x84, 0x44, 0xff, 0x4f, 0x4f, 0x44, 0xf4, 0x4f,
+ 0xff, 0x4f, 0x44, 0xff, 0xf4, 0xf4, 0x4f, 0x69,
+ 0xcc, 0xee, 0xee, 0xee, 0xec, 0x99, 0x88, 0x63,
+ 0x61, 0x68, 0x61, 0x72, 0x22, 0x7a, 0x68, 0x88,
+ 0x11, 0x17, 0x88, 0x66, 0x12, 0x1b, 0xdd, 0xdd,
+ 0x02, 0x44, 0x4f, 0x4f, 0x4f, 0x44, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xff, 0xff, 0x4f, 0x4c, 0xc5,
+ 0x0c, 0xc1, 0x11, 0x1c, 0xc0, 0x26, 0x66, 0x17,
+ 0x66, 0x88, 0x88, 0x12, 0x22, 0x23, 0xa8, 0x88,
+ 0x11, 0x13, 0x88, 0x66, 0x17, 0xbb, 0xdd, 0xdd,
+ 0xd0, 0x8f, 0xff, 0xf4, 0xf4, 0x44, 0xf4, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0x4f, 0x44, 0xdd, 0xdd,
+ 0x00, 0x00, 0x00, 0x05, 0x9d, 0x21, 0x66, 0x27,
+ 0xa6, 0x65, 0x58, 0x67, 0x22, 0x27, 0x28, 0x88,
+ 0x11, 0xaa, 0x86, 0x68, 0x1a, 0xbb, 0xdd, 0xdd,
+ 0xdb, 0x05, 0xf4, 0xf4, 0xf4, 0xf4, 0x44, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0xf4, 0xdd, 0xdb,
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0xda, 0x66, 0x22,
+ 0x71, 0x15, 0x55, 0x81, 0x22, 0x22, 0x76, 0x88,
+ 0x11, 0x31, 0x88, 0x88, 0xab, 0xbd, 0xdd, 0xdd,
+ 0xdd, 0x00, 0x04, 0x44, 0xff, 0xff, 0x4f, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0xf4, 0x44, 0xdd, 0xdb,
+ 0x00, 0x00, 0x00, 0x0b, 0xdd, 0xda, 0x11, 0x22,
+ 0x23, 0x68, 0x55, 0x86, 0x22, 0x22, 0x7a, 0x88,
+ 0x1a, 0x71, 0x88, 0x89, 0xbb, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xd0, 0x00, 0x4f, 0x44, 0xff, 0x4f, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0xff, 0xe2, 0xdd, 0xdb,
+ 0x90, 0x00, 0x05, 0xbd, 0xdd, 0xb8, 0x63, 0x22,
+ 0x27, 0xa6, 0x55, 0x88, 0x77, 0x22, 0x22, 0x88,
+ 0x1a, 0x28, 0xbd, 0xdb, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdb, 0x00, 0x07, 0x44, 0x4f, 0x4f, 0x4f,
+ 0xff, 0x4f, 0x44, 0x4f, 0x4f, 0x22, 0xdd, 0xdb,
+ 0xbb, 0x9b, 0xbb, 0xbd, 0xdd, 0xd5, 0x86, 0x22,
+ 0x22, 0x77, 0x85, 0x88, 0x17, 0x22, 0x22, 0x88,
+ 0xaa, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0x00, 0x00, 0x54, 0x4f, 0x4f, 0x4f,
+ 0xff, 0x4f, 0x44, 0xf4, 0x44, 0x22, 0xbd, 0xdd,
+ 0xbb, 0xbb, 0xbb, 0xdd, 0xdd, 0xdd, 0x88, 0x72,
+ 0x27, 0x22, 0x88, 0x88, 0x67, 0x72, 0x22, 0x18,
+ 0x33, 0x2d, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xd0, 0x00, 0x05, 0x4f, 0x4f, 0x4f,
+ 0xff, 0x4f, 0x44, 0x44, 0x4f, 0x22, 0xbd, 0xdd,
+ 0xdb, 0xbb, 0xdd, 0xdd, 0xdd, 0xdd, 0x88, 0x17,
+ 0x27, 0x72, 0x68, 0x88, 0x87, 0x32, 0x22, 0x36,
+ 0x37, 0x2d, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xd5, 0x00, 0x00, 0x4f, 0x4f, 0x4f,
+ 0xff, 0xf4, 0xf4, 0xf4, 0xf4, 0x22, 0xbb, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd8, 0x67,
+ 0x72, 0x77, 0x38, 0x88, 0x83, 0x37, 0x22, 0x26,
+ 0x72, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x4f, 0x4f, 0x4f,
+ 0xff, 0xf4, 0xf4, 0xf4, 0x44, 0x25, 0xbb, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd3,
+ 0x32, 0x73, 0x76, 0x88, 0x81, 0x33, 0x22, 0x2a,
+ 0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xb0, 0x54, 0x4f, 0x4f, 0x4f,
+ 0xff, 0xf4, 0xf4, 0xff, 0x44, 0x00, 0xbb, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xa7, 0x73, 0x26, 0x88, 0x86, 0x7a, 0x72, 0x27,
+ 0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdb, 0x44, 0xff, 0x4f, 0x4f,
+ 0xff, 0xf4, 0xf4, 0x44, 0x40, 0x05, 0xbb, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0x13, 0x23, 0x21, 0x68, 0x86, 0x17, 0x72, 0x22,
+ 0x22, 0x2b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdb, 0x44, 0x4f, 0x4f, 0x4f,
+ 0xff, 0xff, 0x44, 0x42, 0x00, 0x05, 0xbd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0x87, 0x27, 0x27, 0x16, 0x66, 0x67, 0x22, 0x22,
+ 0x72, 0x7b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0x94, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x00, 0x00, 0x05, 0xbb, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xb8,
+ 0x86, 0x22, 0x22, 0x7a, 0x68, 0x81, 0x22, 0x22,
+ 0x37, 0x7b, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdb, 0xb5, 0x44, 0x44, 0x44,
+ 0x44, 0x47, 0x00, 0x00, 0x00, 0x05, 0xbd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xd8, 0x68,
+ 0x58, 0x72, 0x22, 0x27, 0x18, 0x86, 0x72, 0x22,
+ 0x1a, 0xbb, 0xbd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdb, 0xb5, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xbb, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xb9, 0x18, 0x85,
+ 0x58, 0x12, 0x22, 0x36, 0x18, 0x88, 0x32, 0x22,
+ 0x61, 0x3b, 0xbb, 0xbb, 0xbd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdb, 0xb9, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xbb, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xb9, 0x7a, 0x68, 0x85,
+ 0x88, 0x62, 0x27, 0x16, 0x18, 0x88, 0x12, 0x27,
+ 0x86, 0x18, 0x9b, 0xbb, 0xbb, 0xbb, 0xbb, 0xbd,
+ 0xdd, 0xdd, 0xdd, 0xbb, 0xb5, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xbb, 0xbd,
+ 0xdd, 0xdd, 0xdb, 0xbb, 0x87, 0x31, 0x68, 0x65,
+ 0x88, 0x82, 0x23, 0x16, 0x18, 0x88, 0x12, 0x23,
+ 0x88, 0x67, 0x27, 0xa8, 0x9b, 0xbb, 0xbb, 0xbb,
+ 0xbd, 0xdd, 0xbb, 0xbb, 0x95, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x9b, 0xbb,
+ 0xbb, 0xbb, 0xbb, 0x96, 0x87, 0x16, 0x68, 0x18,
+ 0x88, 0x62, 0x31, 0x66, 0x18, 0x88, 0x62, 0x73,
+ 0x88, 0x63, 0x27, 0x33, 0x65, 0x55, 0x99, 0x9b,
+ 0xbb, 0xbb, 0xbb, 0x99, 0x55, 0x0a, 0xa1, 0x86,
+ 0x81, 0x68, 0x88, 0x55, 0x58, 0x85, 0x9b, 0xbb,
+ 0xbb, 0xbb, 0x95, 0x88, 0x83, 0x66, 0x66, 0x18,
+ 0x66, 0x82, 0xa1, 0x66, 0x18, 0x88, 0x62, 0x33,
+ 0x88, 0x81, 0x27, 0x7a, 0x18, 0x58, 0x86, 0x85,
+ 0x99, 0x99, 0x99, 0x95, 0x53, 0x2a, 0xaa, 0x88,
+ 0x67, 0x31, 0x68, 0x55, 0x58, 0x85, 0x59, 0xbb,
+ 0xbb, 0xb9, 0x58, 0x68, 0x83, 0x66, 0x61, 0x16,
+ 0x66, 0x62, 0x16, 0x66, 0x68, 0x88, 0x62, 0xaa,
+ 0x88, 0x86, 0x27, 0x77, 0x78, 0x55, 0x88, 0x22,
+ 0x25, 0x55, 0x95, 0x55, 0x6a, 0xa2, 0x2a, 0x88,
+ 0x62, 0x27, 0x37, 0x38, 0x88, 0x87, 0x55, 0x59,
+ 0x95, 0x58, 0x16, 0x88, 0x8a, 0x66, 0x63, 0x68,
+ 0x86, 0x67, 0x66, 0x66, 0x68, 0x88, 0x12, 0x11,
+ 0x88, 0x88, 0x72, 0x77, 0x78, 0x85, 0x58, 0x17,
+ 0x23, 0x32, 0x55, 0x55, 0x81, 0x13, 0x73, 0x66,
+ 0x62, 0x7a, 0xaa, 0x38, 0x88, 0x58, 0x27, 0x55,
+ 0x58, 0x32, 0x38, 0x88, 0x81, 0x66, 0xa2, 0x88,
+ 0x86, 0x61, 0x66, 0x61, 0x66, 0x68, 0x13, 0x11,
+ 0x88, 0x88, 0x12, 0x22, 0x71, 0x85, 0x58, 0x62,
+ 0x23, 0xa2, 0x68, 0x88, 0x81, 0x66, 0x88, 0x88,
+ 0x63, 0x2a, 0xaa, 0x28, 0x88, 0x55, 0x86, 0x61,
+ 0x66, 0x66, 0x68, 0x88, 0x66, 0x66, 0x77, 0x88,
+ 0x68, 0x16, 0x66, 0x62, 0x66, 0x68, 0xa1, 0x61,
+ 0x88, 0x88, 0x62, 0x22, 0x22, 0x85, 0x55, 0x83,
+ 0x72, 0x37, 0xa8, 0x88, 0x61, 0x66, 0x85, 0x55,
+ 0x86, 0x23, 0xaa, 0x71, 0x88, 0x85, 0x88, 0x66,
+ 0x88, 0x86, 0x88, 0x88, 0x16, 0x61, 0x21, 0x88,
+ 0x66, 0xa6, 0x86, 0x17, 0x66, 0x66, 0x31, 0x61,
+ 0x88, 0x88, 0x87, 0x72, 0x22, 0x68, 0x55, 0x86,
+ 0x77, 0x77, 0x36, 0x88, 0x13, 0x68, 0x85, 0x55,
+ 0x58, 0x12, 0x73, 0x72, 0x76, 0x88, 0x88, 0x68,
+ 0x88, 0x88, 0x88, 0x66, 0x36, 0x63, 0x26, 0x86,
+ 0x86, 0x36, 0x86, 0x11, 0x66, 0x66, 0x76, 0x61,
+ 0x88, 0x88, 0x81, 0x22, 0x22, 0x38, 0x85, 0x58,
+ 0x37, 0x22, 0x21, 0x68, 0xa2, 0x31, 0x68, 0x55,
+ 0x55, 0x81, 0x22, 0x22, 0xa8, 0x88, 0x88, 0x68,
+ 0x86, 0x88, 0x68, 0x81, 0x36, 0x17, 0x21, 0x68,
+ 0x86, 0x16, 0x66, 0x26, 0x66, 0x61, 0x36, 0x66,
+ 0x68, 0x88, 0x86, 0x27, 0x22, 0x28, 0x88, 0x88,
+ 0x17, 0x72, 0x2a, 0x66, 0xa2, 0x22, 0x36, 0x55,
+ 0x55, 0x58, 0x37, 0x3a, 0x16, 0x66, 0x66, 0x66,
+ 0x66, 0x18, 0x88, 0x67, 0x16, 0x12, 0x71, 0x68,
+ 0x81, 0x68, 0x61, 0x76, 0x66, 0x6a, 0x16, 0x66,
+ 0x88, 0x88, 0x86, 0x77, 0x22, 0x26, 0x88, 0x88,
+ 0x13, 0x37, 0x71, 0x66, 0xa2, 0x33, 0x2a, 0x85,
+ 0x55, 0x55, 0x17, 0x73, 0x16, 0x66, 0x66, 0x68,
+ 0x63, 0x88, 0x88, 0xa2, 0x66, 0xa2, 0xa6, 0x88,
+ 0x61, 0x68, 0x6a, 0x76, 0x66, 0x6a, 0x66, 0x6a
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/list.h b/pfinet/linux-src/include/linux/list.h
new file mode 100644
index 00000000..e77559a6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/list.h
@@ -0,0 +1,99 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#ifdef __KERNEL__
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD(name) \
+ struct list_head name = { &name, &name }
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+ struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/*
+ * Insert a new entry after the specified head..
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+static __inline__ void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+static __inline__ int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/*
+ * Splice in "list" into "head"
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+ struct list_head *first = list->next;
+
+ if (first != list) {
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+ }
+}
+
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/lists.h b/pfinet/linux-src/include/linux/lists.h
new file mode 100644
index 00000000..6a2240a2
--- /dev/null
+++ b/pfinet/linux-src/include/linux/lists.h
@@ -0,0 +1,62 @@
+/*
+ * lists.h: Simple list macros for Linux
+ */
+
+#define DLNODE(ptype) \
+ struct { \
+ ptype * dl_prev; \
+ ptype * dl_next; \
+ }
+
+#define DNODE_SINGLE(node) {(node),(node)}
+#define DNODE_NULL {0,0}
+
+#define DLIST_INIT(listnam) \
+ (listnam).dl_prev = &(listnam); \
+ (listnam).dl_next = &(listnam);
+
+#define DLIST_NEXT(listnam) listnam.dl_next
+#define DLIST_PREV(listnam) listnam.dl_prev
+
+#define DLIST_INSERT_AFTER(node, new, listnam) do { \
+ (new)->listnam.dl_prev = (node); \
+ (new)->listnam.dl_next = (node)->listnam.dl_next; \
+ (node)->listnam.dl_next->listnam.dl_prev = (new); \
+ (node)->listnam.dl_next = (new); \
+ } while (0)
+
+#define DLIST_INSERT_BEFORE(node, new, listnam) do { \
+ (new)->listnam.dl_next = (node); \
+ (new)->listnam.dl_prev = (node)->listnam.dl_prev; \
+ (node)->listnam.dl_prev->listnam.dl_next = (new); \
+ (node)->listnam.dl_prev = (new); \
+ } while (0)
+
+#define DLIST_DELETE(node, listnam) do { \
+ node->listnam.dl_prev->listnam.dl_next = \
+ node->listnam.dl_next; \
+ node->listnam.dl_next->listnam.dl_prev = \
+ node->listnam.dl_prev; \
+ } while (0)
+
+/*
+ * queue-style operations, which have a head and tail
+ */
+
+#define QUEUE_INIT(head, listnam, ptype) \
+ (head)->listnam.dl_prev = (head)->listnam.dl_next = (ptype)(head);
+
+#define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam)
+#define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam)
+#define QUEUE_EMPTY(head, listnam) \
+ ((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \
+ ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head))
+
+#define QUEUE_ENTER(head, new, listnam, ptype) do { \
+ (new)->listnam.dl_prev = (ptype)(head); \
+ (new)->listnam.dl_next = (head)->listnam.dl_next; \
+ (head)->listnam.dl_next->listnam.dl_prev = (new); \
+ (head)->listnam.dl_next = (new); \
+ } while (0)
+
+#define QUEUE_REMOVE(head, node, listnam) DLIST_DELETE(node, listnam)
diff --git a/pfinet/linux-src/include/linux/locks.h b/pfinet/linux-src/include/linux/locks.h
new file mode 100644
index 00000000..2094a4d1
--- /dev/null
+++ b/pfinet/linux-src/include/linux/locks.h
@@ -0,0 +1,62 @@
+#ifndef _LINUX_LOCKS_H
+#define _LINUX_LOCKS_H
+
+#ifndef _LINUX_MM_H
+#include <linux/mm.h>
+#endif
+#ifndef _LINUX_PAGEMAP_H
+#include <linux/pagemap.h>
+#endif
+
+/*
+ * Buffer cache locking - note that interrupts may only unlock, not
+ * lock buffers.
+ */
+extern void __wait_on_buffer(struct buffer_head *);
+
+extern inline void wait_on_buffer(struct buffer_head * bh)
+{
+ if (test_bit(BH_Lock, &bh->b_state))
+ __wait_on_buffer(bh);
+}
+
+extern inline void lock_buffer(struct buffer_head * bh)
+{
+ while (test_and_set_bit(BH_Lock, &bh->b_state))
+ __wait_on_buffer(bh);
+}
+
+extern inline void unlock_buffer(struct buffer_head *bh)
+{
+ clear_bit(BH_Lock, &bh->b_state);
+ wake_up(&bh->b_wait);
+}
+
+/*
+ * super-block locking. Again, interrupts may only unlock
+ * a super-block (although even this isn't done right now.
+ * nfs may need it).
+ */
+extern void __wait_on_super(struct super_block *);
+
+extern inline void wait_on_super(struct super_block * sb)
+{
+ if (sb->s_lock)
+ __wait_on_super(sb);
+}
+
+extern inline void lock_super(struct super_block * sb)
+{
+ if (sb->s_lock)
+ __wait_on_super(sb);
+ sb->s_lock = 1;
+}
+
+extern inline void unlock_super(struct super_block * sb)
+{
+ sb->s_lock = 0;
+ wake_up(&sb->s_wait);
+}
+
+#endif /* _LINUX_LOCKS_H */
+
diff --git a/pfinet/linux-src/include/linux/loop.h b/pfinet/linux-src/include/linux/loop.h
new file mode 100644
index 00000000..43b3bd69
--- /dev/null
+++ b/pfinet/linux-src/include/linux/loop.h
@@ -0,0 +1,130 @@
+#ifndef _LINUX_LOOP_H
+#define _LINUX_LOOP_H
+
+#include <linux/kdev_t.h>
+
+/*
+ * include/linux/loop.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
+ * permitted under the GNU Public License.
+ */
+
+#define LO_NAME_SIZE 64
+#define LO_KEY_SIZE 32
+
+#ifdef __KERNEL__
+
+struct loop_device {
+ int lo_number;
+ struct dentry *lo_dentry;
+ int lo_refcnt;
+ kdev_t lo_device;
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size;
+ int lo_flags;
+ int (*transfer)(struct loop_device *, int cmd,
+ char *raw_buf, char *loop_buf, int size,
+ int real_block);
+ char lo_name[LO_NAME_SIZE];
+ char lo_encrypt_key[LO_KEY_SIZE];
+ __u32 lo_init[2];
+ uid_t lo_key_owner; /* Who set the key */
+ int (*ioctl)(struct loop_device *, int cmd,
+ unsigned long arg);
+
+ struct file * lo_backing_file;
+ void *key_data;
+ char key_reserved[48]; /* for use by the filter modules */
+};
+
+typedef int (* transfer_proc_t)(struct loop_device *, int cmd,
+ char *raw_buf, char *loop_buf, int size,
+ int real_block);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Loop flags
+ */
+#define LO_FLAGS_DO_BMAP 0x00000001
+#define LO_FLAGS_READ_ONLY 0x00000002
+
+/*
+ * Note that this structure gets the wrong offsets when directly used
+ * from a glibc program, because glibc has a 32bit dev_t.
+ * Prevent people from shooting in their own foot.
+ */
+#if __GLIBC__ >= 2 && !defined(dev_t)
+#error "Wrong dev_t in loop.h"
+#endif
+
+/*
+ * This uses kdev_t because glibc currently has no appropriate
+ * conversion version for the loop ioctls.
+ * The situation is very unpleasant
+ */
+
+struct loop_info {
+ int lo_number; /* ioctl r/o */
+ dev_t lo_device; /* ioctl r/o */
+ unsigned long lo_inode; /* ioctl r/o */
+ dev_t lo_rdevice; /* ioctl r/o */
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size; /* ioctl w/o */
+ int lo_flags; /* ioctl r/o */
+ char lo_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+ unsigned long lo_init[2];
+ char reserved[4];
+};
+
+/*
+ * Loop filter types
+ */
+
+#define LO_CRYPT_NONE 0
+#define LO_CRYPT_XOR 1
+#define LO_CRYPT_DES 2
+#define LO_CRYPT_FISH2 3 /* Brand new Twofish encryption */
+#define LO_CRYPT_BLOW 4
+#define LO_CRYPT_CAST128 5
+#define LO_CRYPT_IDEA 6
+#define LO_CRYPT_DUMMY 9
+#define LO_CRYPT_SKIPJACK 10
+#define MAX_LO_CRYPT 20
+
+#ifdef __KERNEL__
+/* Support for loadable transfer modules */
+struct loop_func_table {
+ int number; /* filter type */
+ int (*transfer)(struct loop_device *lo, int cmd,
+ char *raw_buf, char *loop_buf, int size,
+ int real_block);
+ int (*init)(struct loop_device *, struct loop_info *);
+ /* release is called from loop_unregister_transfer or clr_fd */
+ int (*release)(struct loop_device *);
+ int (*ioctl)(struct loop_device *, int cmd, unsigned long arg);
+ /* lock and unlock manage the module use counts */
+ void (*lock)(struct loop_device *);
+ void (*unlock)(struct loop_device *);
+};
+
+int loop_register_transfer(struct loop_func_table *funcs);
+int loop_unregister_transfer(int number);
+
+#endif
+/*
+ * IOCTL commands --- we will commandeer 0x4C ('L')
+ */
+
+#define LOOP_SET_FD 0x4C00
+#define LOOP_CLR_FD 0x4C01
+#define LOOP_SET_STATUS 0x4C02
+#define LOOP_GET_STATUS 0x4C03
+
+#endif
diff --git a/pfinet/linux-src/include/linux/lp.h b/pfinet/linux-src/include/linux/lp.h
new file mode 100644
index 00000000..139ad843
--- /dev/null
+++ b/pfinet/linux-src/include/linux/lp.h
@@ -0,0 +1,188 @@
+#ifndef _LINUX_LP_H
+#define _LINUX_LP_H
+
+/*
+ * usr/include/linux/lp.h c.1991-1992 James Wiegand
+ * many modifications copyright (C) 1992 Michael K. Johnson
+ * Interrupt support added 1993 Nigel Gamble
+ */
+
+/*
+ * Per POSIX guidelines, this module reserves the LP and lp prefixes
+ * These are the lp_table[minor].flags flags...
+ */
+#define LP_EXIST 0x0001
+#define LP_SELEC 0x0002
+#define LP_BUSY 0x0004
+#define LP_BUSY_BIT_POS 2
+#define LP_OFFL 0x0008
+#define LP_NOPA 0x0010
+#define LP_ERR 0x0020
+#define LP_ABORT 0x0040
+#define LP_CAREFUL 0x0080
+#define LP_ABORTOPEN 0x0100
+#define LP_TRUST_IRQ 0x0200
+
+/* timeout for each character. This is relative to bus cycles -- it
+ * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you
+ * have extremely slow printing, or if the machine seems to slow down
+ * a lot when you print. If you have slow printing, increase this
+ * number and recompile, and if your system gets bogged down, decrease
+ * this number. This can be changed with the tunelp(8) command as well.
+ */
+
+#define LP_INIT_CHAR 1000
+
+/* The parallel port specs apparently say that there needs to be
+ * a .5usec wait before and after the strobe.
+ */
+
+#define LP_INIT_WAIT 1
+
+/* This is the amount of time that the driver waits for the printer to
+ * catch up when the printer's buffer appears to be filled. If you
+ * want to tune this and have a fast printer (i.e. HPIIIP), decrease
+ * this number, and if you have a slow printer, increase this number.
+ * This is in hundredths of a second, the default 2 being .05 second.
+ * Or use the tunelp(8) command, which is especially nice if you want
+ * change back and forth between character and graphics printing, which
+ * are wildly different...
+ */
+
+#define LP_INIT_TIME 2
+
+/* IOCTL numbers */
+#define LPCHAR 0x0601 /* corresponds to LP_INIT_CHAR */
+#define LPTIME 0x0602 /* corresponds to LP_INIT_TIME */
+#define LPABORT 0x0604 /* call with TRUE arg to abort on error,
+ FALSE to retry. Default is retry. */
+#define LPSETIRQ 0x0605 /* call with new IRQ number,
+ or 0 for polling (no IRQ) */
+#define LPGETIRQ 0x0606 /* get the current IRQ number */
+#define LPWAIT 0x0608 /* corresponds to LP_INIT_WAIT */
+/* NOTE: LPCAREFUL is obsoleted and it' s always the default right now -arca */
+#define LPCAREFUL 0x0609 /* call with TRUE arg to require out-of-paper, off-
+ line, and error indicators good on all writes,
+ FALSE to ignore them. Default is ignore. */
+#define LPABORTOPEN 0x060a /* call with TRUE arg to abort open() on error,
+ FALSE to ignore error. Default is ignore. */
+#define LPGETSTATUS 0x060b /* return LP_S(minor) */
+#define LPRESET 0x060c /* reset printer */
+#ifdef LP_STATS
+#define LPGETSTATS 0x060d /* get statistics (struct lp_stats) */
+#endif
+#define LPGETFLAGS 0x060e /* get status flags */
+#define LPTRUSTIRQ 0x060f /* set/unset the LP_TRUST_IRQ flag */
+
+/* timeout for printk'ing a timeout, in jiffies (100ths of a second).
+ This is also used for re-checking error conditions if LP_ABORT is
+ not set. This is the default behavior. */
+
+#define LP_TIMEOUT_INTERRUPT (60 * HZ)
+#define LP_TIMEOUT_POLLED (10 * HZ)
+
+#ifdef __KERNEL__
+
+/* Magic numbers for defining port-device mappings */
+#define LP_PARPORT_UNSPEC -4
+#define LP_PARPORT_AUTO -3
+#define LP_PARPORT_OFF -2
+#define LP_PARPORT_NONE -1
+
+#define LP_F(minor) lp_table[(minor)].flags /* flags for busy, etc. */
+#define LP_CHAR(minor) lp_table[(minor)].chars /* busy timeout */
+#define LP_TIME(minor) lp_table[(minor)].time /* wait time */
+#define LP_WAIT(minor) lp_table[(minor)].wait /* strobe wait */
+#define LP_IRQ(minor) lp_table[(minor)].dev->port->irq /* interrupt # */
+ /* PARPORT_IRQ_NONE means polled */
+#ifdef LP_STATS
+#define LP_STAT(minor) lp_table[(minor)].stats /* statistics area */
+#endif
+#define LP_BUFFER_SIZE 256
+
+#define LP_BASE(x) lp_table[(x)].dev->port->base
+
+#ifdef LP_STATS
+struct lp_stats {
+ unsigned long chars;
+ unsigned long sleeps;
+ unsigned int maxrun;
+ unsigned int maxwait;
+ unsigned int meanwait;
+ unsigned int mdev;
+};
+#endif
+
+struct lp_struct {
+ struct pardevice *dev;
+ unsigned long flags;
+ unsigned int chars;
+ unsigned int time;
+ unsigned int wait;
+ char *lp_buffer;
+#ifdef LP_STATS
+ unsigned int lastcall;
+ unsigned int runchars;
+ struct lp_stats stats;
+#endif
+ struct wait_queue *wait_q;
+ unsigned int last_error;
+ volatile unsigned int irq_detected:1;
+ volatile unsigned int irq_missed:1;
+};
+
+/*
+ * The following constants describe the various signals of the printer port
+ * hardware. Note that the hardware inverts some signals and that some
+ * signals are active low. An example is LP_STROBE, which must be programmed
+ * with 1 for being active and 0 for being inactive, because the strobe signal
+ * gets inverted, but it is also active low.
+ */
+
+/*
+ * bit defines for 8255 status port
+ * base + 1
+ * accessed with LP_S(minor), which gets the byte...
+ */
+#define LP_PBUSY 0x80 /* inverted input, active high */
+#define LP_PACK 0x40 /* unchanged input, active low */
+#define LP_POUTPA 0x20 /* unchanged input, active high */
+#define LP_PSELECD 0x10 /* unchanged input, active high */
+#define LP_PERRORP 0x08 /* unchanged input, active low */
+
+/*
+ * defines for 8255 control port
+ * base + 2
+ * accessed with LP_C(minor)
+ */
+#define LP_PINTEN 0x10 /* high to read data in or-ed with data out */
+#define LP_PSELECP 0x08 /* inverted output, active low */
+#define LP_PINITP 0x04 /* unchanged output, active low */
+#define LP_PAUTOLF 0x02 /* inverted output, active low */
+#define LP_PSTROBE 0x01 /* short high output on raising edge */
+
+/*
+ * the value written to ports to test existence. PC-style ports will
+ * return the value written. AT-style ports will return 0. so why not
+ * make them the same ?
+ */
+#define LP_DUMMY 0x00
+
+/*
+ * This is the port delay time, in microseconds.
+ * It is used only in the lp_init() and lp_reset() routine.
+ */
+#define LP_DELAY 50
+
+#define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE)
+#define LP_PREEMPTED(minor) (lp_table[(minor)].dev->port->waithead != NULL)
+
+/*
+ * function prototypes
+ */
+
+extern int lp_init(void);
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/lp_intern.h b/pfinet/linux-src/include/linux/lp_intern.h
new file mode 100644
index 00000000..c7af535f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/lp_intern.h
@@ -0,0 +1,22 @@
+#ifndef _LINUX_LP_INTERN_H_
+#define _LINUX_LP_INTERN_H_
+
+/*
+ * split in two parts by Joerg Dorchain
+ * usr/include/linux/lp.h modified for Amiga by Michael Rausch
+ * modified for Atari by Andreas Schwab
+ * bug fixed by Jes Sorensen 18/8-94:
+ * It was not possible to compile the kernel only for Atari or Amiga.
+ *
+ * linux i386 version c.1991-1992 James Wiegand
+ * many modifications copyright (C) 1992 Michael K. Johnson
+ * Interrupt support added 1993 Nigel Gamble
+ */
+
+#include <linux/types.h>
+#include <linux/lp_m68k.h>
+
+int lp_internal_init(void);
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/lp_m68k.h b/pfinet/linux-src/include/linux/lp_m68k.h
new file mode 100644
index 00000000..cddecc98
--- /dev/null
+++ b/pfinet/linux-src/include/linux/lp_m68k.h
@@ -0,0 +1,135 @@
+#ifndef _LINUX_LP_H
+#define _LINUX_LP_H
+
+/*
+ * split in two parts by Joerg Dorchain
+ * usr/include/linux/lp.h modified for Amiga by Michael Rausch
+ * modified for Atari by Andreas Schwab
+ * bug fixed by Jes Sorensen 18/8-94:
+ * It was not possible to compile the kernel only for Atari or Amiga.
+ *
+ * linux i386 version c.1991-1992 James Wiegand
+ * many modifications copyright (C) 1992 Michael K. Johnson
+ * Interrupt support added 1993 Nigel Gamble
+ */
+
+/*
+ * many many printers are we going to support? currently, this is the
+ * hardcoded limit
+ */
+#define MAX_LP 5
+
+/*
+ * Per POSIX guidelines, this module reserves the LP and lp prefixes
+ * These are the lp_table[minor].flags flags...
+ */
+#define LP_EXIST 0x0001
+#define LP_BUSY 0x0004
+#define LP_ABORT 0x0040
+#define LP_CAREFUL 0x0080
+#define LP_ABORTOPEN 0x0100
+
+/* timeout for each character. This is relative to bus cycles -- it
+ * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you
+ * have extremely slow printing, or if the machine seems to slow down
+ * a lot when you print. If you have slow printing, increase this
+ * number and recompile, and if your system gets bogged down, decrease
+ * this number. This can be changed with the tunelp(8) command as well.
+ */
+
+#define LP_INIT_CHAR 1000
+
+/* The parallel port specs apparently say that there needs to be
+ * a .5usec wait before and after the strobe. Since there are wildly
+ * different computers running linux, I can't come up with a perfect
+ * value, but since it worked well on most printers before without,
+ * I'll initialize it to 0.
+ */
+
+#define LP_INIT_WAIT 0
+
+/* This is the amount of time that the driver waits for the printer to
+ * catch up when the printer's buffer appears to be filled. If you
+ * want to tune this and have a fast printer (i.e. HPIIIP), decrease
+ * this number, and if you have a slow printer, increase this number.
+ * This is in hundredths of a second, the default 2 being .05 second.
+ * Or use the tunelp(8) command, which is especially nice if you want
+ * change back and forth between character and graphics printing, which
+ * are wildly different...
+ */
+
+#define LP_INIT_TIME 40
+
+/* IOCTL numbers */
+#define LPCHAR 0x0601 /* corresponds to LP_INIT_CHAR */
+#define LPTIME 0x0602 /* corresponds to LP_INIT_TIME */
+#define LPABORT 0x0604 /* call with TRUE arg to abort on error,
+ FALSE to retry. Default is retry. */
+#define LPSETIRQ 0x0605 /* call with new IRQ number,
+ or 0 for polling (no IRQ) */
+#define LPGETIRQ 0x0606 /* get the current IRQ number */
+#define LPWAIT 0x0608 /* corresponds to LP_INIT_WAIT */
+#define LPCAREFUL 0x0609 /* call with TRUE arg to require out-of-paper, off-
+ line, and error indicators good on all writes,
+ FALSE to ignore them. Default is ignore. */
+#define LPABORTOPEN 0x060a /* call with TRUE arg to abort open() on error,
+ FALSE to ignore error. Default is ignore. */
+#define LPGETSTATUS 0x060b /* return LP_S(minor) */
+#define LPRESET 0x060c /* reset printer */
+
+/* timeout for printk'ing a timeout, in jiffies (100ths of a second).
+ This is also used for re-checking error conditions if LP_ABORT is
+ not set. This is the default behavior. */
+
+#define LP_TIMEOUT_INTERRUPT (60 * HZ)
+#define LP_TIMEOUT_POLLED (10 * HZ)
+
+
+#define LP_BUFFER_SIZE 1024 /*256*/
+
+enum lp_type {
+LP_UNKNOWN = 0,
+LP_AMIGA = 1,
+LP_ATARI = 2,
+LP_MFC = 3,
+LP_IOEXT = 4,
+LP_MVME167 = 5,
+LP_BVME6000 = 6
+};
+
+/*
+ * warning: this structure is in kernel space and has to fit in one page,
+ * i.e. must not be larger than 4k
+ */
+struct lp_struct {
+ char *name;
+ unsigned int irq;
+ void (*lp_out)(int,int); /*output char function*/
+ int (*lp_is_busy)(int);
+ int (*lp_has_pout)(int);
+ int (*lp_is_online)(int);
+ int (*lp_dummy)(int);
+ int (*lp_ioctl)(int, unsigned int, unsigned long);
+ int (*lp_open)(int); /* for module use counter */
+ void (*lp_release)(int); /* for module use counter */
+ int flags; /*for BUSY... */
+ unsigned int chars; /*busy timeout */
+ unsigned int time; /*wait time */
+ unsigned int wait;
+ struct wait_queue *lp_wait_q; /*strobe wait */
+ void *base; /* hardware drivers internal use*/
+ enum lp_type type;
+ char lp_buffer[LP_BUFFER_SIZE];
+ int do_print;
+ unsigned long copy_size,bytes_written;
+};
+
+extern struct lp_struct *lp_table[MAX_LP];
+extern unsigned int lp_irq;
+
+void lp_interrupt(int dev);
+int lp_m68k_init(void);
+int register_parallel(struct lp_struct *, int);
+void unregister_parallel(int);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/lp_mfc.h b/pfinet/linux-src/include/linux/lp_mfc.h
new file mode 100644
index 00000000..cf8cfb44
--- /dev/null
+++ b/pfinet/linux-src/include/linux/lp_mfc.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_LP_MFC_H_
+#define _LINUX_LP_MFC_H_
+
+/*
+ * created 6.11.95 Joerg Dorchain
+ */
+
+#include <linux/types.h>
+#include <linux/lp_m68k.h>
+
+int lp_mfc_init(void);
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/major.h b/pfinet/linux-src/include/linux/major.h
new file mode 100644
index 00000000..2db0a0af
--- /dev/null
+++ b/pfinet/linux-src/include/linux/major.h
@@ -0,0 +1,135 @@
+#ifndef _LINUX_MAJOR_H
+#define _LINUX_MAJOR_H
+
+/*
+ * This file has definitions for major device numbers.
+ * For the device number assignments, see Documentation/devices.txt.
+ */
+
+/* limits */
+
+/*
+ * Important: Don't change this to 256. Major number 255 is and must be
+ * reserved for future expansion into a larger dev_t space.
+ */
+#define MAX_CHRDEV 255
+#define MAX_BLKDEV 255
+
+#define UNNAMED_MAJOR 0
+#define MEM_MAJOR 1
+#define RAMDISK_MAJOR 1
+#define FLOPPY_MAJOR 2
+#define PTY_MASTER_MAJOR 2
+#define IDE0_MAJOR 3
+#define PTY_SLAVE_MAJOR 3
+#define HD_MAJOR IDE0_MAJOR
+#define TTY_MAJOR 4
+#define TTYAUX_MAJOR 5
+#define LP_MAJOR 6
+#define VCS_MAJOR 7
+#define LOOP_MAJOR 7
+#define SCSI_DISK0_MAJOR 8
+#define SCSI_TAPE_MAJOR 9
+#define MD_MAJOR 9
+#define MISC_MAJOR 10
+#define SCSI_CDROM_MAJOR 11
+#define QIC02_TAPE_MAJOR 12
+#define XT_DISK_MAJOR 13
+#define SOUND_MAJOR 14
+#define CDU31A_CDROM_MAJOR 15
+#define JOYSTICK_MAJOR 15
+#define GOLDSTAR_CDROM_MAJOR 16
+#define OPTICS_CDROM_MAJOR 17
+#define SANYO_CDROM_MAJOR 18
+#define CYCLADES_MAJOR 19
+#define CYCLADESAUX_MAJOR 20
+#define MITSUMI_X_CDROM_MAJOR 20
+#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */
+#define SCSI_GENERIC_MAJOR 21
+#define Z8530_MAJOR 34
+#define DIGI_MAJOR 23
+#define IDE1_MAJOR 22
+#define DIGICU_MAJOR 22
+#define MITSUMI_CDROM_MAJOR 23
+#define CDU535_CDROM_MAJOR 24
+#define STL_SERIALMAJOR 24
+#define MATSUSHITA_CDROM_MAJOR 25
+#define STL_CALLOUTMAJOR 25
+#define MATSUSHITA_CDROM2_MAJOR 26
+#define QIC117_TAPE_MAJOR 27
+#define MATSUSHITA_CDROM3_MAJOR 27
+#define MATSUSHITA_CDROM4_MAJOR 28
+#define STL_SIOMEMMAJOR 28
+#define ACSI_MAJOR 28
+#define AZTECH_CDROM_MAJOR 29
+#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */
+#define SHMIQ_MAJOR 85 /* Linux/MIPS, SGI /dev/shmiq */
+#define CM206_CDROM_MAJOR 32
+#define IDE2_MAJOR 33
+#define IDE3_MAJOR 34
+#define NETLINK_MAJOR 36
+#define PS2ESDI_MAJOR 36
+#define IDETAPE_MAJOR 37
+#define Z2RAM_MAJOR 37
+#define APBLOCK_MAJOR 38 /* AP1000 Block device */
+#define DDV_MAJOR 39 /* AP1000 DDV block device */
+#define NBD_MAJOR 43 /* Network block device */
+#define RISCOM8_NORMAL_MAJOR 48
+#define DAC960_MAJOR 48 /* 48..55 */
+#define RISCOM8_CALLOUT_MAJOR 49
+#define MKISS_MAJOR 55
+#define DSP56K_MAJOR 55 /* DSP56001 processor device */
+
+#define IDE4_MAJOR 56
+#define IDE5_MAJOR 57
+
+#define SCSI_DISK1_MAJOR 65
+#define SCSI_DISK2_MAJOR 66
+#define SCSI_DISK3_MAJOR 67
+#define SCSI_DISK4_MAJOR 68
+#define SCSI_DISK5_MAJOR 69
+#define SCSI_DISK6_MAJOR 70
+#define SCSI_DISK7_MAJOR 71
+
+#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */
+
+#define COMPAQ_SMART2_MAJOR 72
+#define COMPAQ_SMART2_MAJOR1 73
+#define COMPAQ_SMART2_MAJOR2 74
+#define COMPAQ_SMART2_MAJOR3 75
+#define COMPAQ_SMART2_MAJOR4 76
+#define COMPAQ_SMART2_MAJOR5 77
+#define COMPAQ_SMART2_MAJOR6 78
+#define COMPAQ_SMART2_MAJOR7 79
+
+#define SPECIALIX_NORMAL_MAJOR 75
+#define SPECIALIX_CALLOUT_MAJOR 76
+
+#define DASD_MAJOR 94 /* Official assignations from Peter */
+
+#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */
+
+#define MDISK_MAJOR 95 /* Official assignations from Peter */
+
+#define AURORA_MAJOR 79
+
+#define UNIX98_PTY_MASTER_MAJOR 128
+#define UNIX98_PTY_MAJOR_COUNT 8
+#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
+
+/*
+ * Tests for SCSI devices.
+ */
+
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+ ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
+
+#define SCSI_BLK_MAJOR(M) \
+ (SCSI_DISK_MAJOR(M) \
+ || (M) == SCSI_CDROM_MAJOR)
+
+static __inline__ int scsi_blk_major(int m) {
+ return SCSI_BLK_MAJOR(m);
+}
+
+#endif
diff --git a/pfinet/linux-src/include/linux/malloc.h b/pfinet/linux-src/include/linux/malloc.h
new file mode 100644
index 00000000..f3ebf185
--- /dev/null
+++ b/pfinet/linux-src/include/linux/malloc.h
@@ -0,0 +1,5 @@
+#ifndef _LINUX_MALLOC_H
+#define _LINUX_MALLOC_H
+
+#include <linux/slab.h>
+#endif /* _LINUX_MALLOC_H */
diff --git a/pfinet/linux-src/include/linux/mc146818rtc.h b/pfinet/linux-src/include/linux/mc146818rtc.h
new file mode 100644
index 00000000..0a2efb6e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mc146818rtc.h
@@ -0,0 +1,149 @@
+/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM
+ * Copyright Torsten Duwe <duwe@informatik.uni-erlangen.de> 1993
+ * derived from Data Sheet, Copyright Motorola 1984 (!).
+ * It was written to be part of the Linux operating system.
+ */
+/* permission is hereby granted to copy, modify and redistribute this code
+ * in terms of the GNU Library General Public License, Version 2 or later,
+ * at your option.
+ */
+
+#ifndef _MC146818RTC_H
+#define _MC146818RTC_H
+#include <asm/io.h>
+
+#ifndef RTC_PORT
+#define RTC_PORT(x) (0x70 + (x))
+#define RTC_ALWAYS_BCD 1
+#endif
+
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+inb_p(RTC_PORT(1)); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+outb_p((val),RTC_PORT(1)); \
+})
+
+/**********************************************************************
+ * register summary
+ **********************************************************************/
+#define RTC_SECONDS 0
+#define RTC_SECONDS_ALARM 1
+#define RTC_MINUTES 2
+#define RTC_MINUTES_ALARM 3
+#define RTC_HOURS 4
+#define RTC_HOURS_ALARM 5
+/* RTC_*_alarm is always true if 2 MSBs are set */
+# define RTC_ALARM_DONT_CARE 0xC0
+
+#define RTC_DAY_OF_WEEK 6
+#define RTC_DAY_OF_MONTH 7
+#define RTC_MONTH 8
+#define RTC_YEAR 9
+
+/* control registers - Moto names
+ */
+#define RTC_REG_A 10
+#define RTC_REG_B 11
+#define RTC_REG_C 12
+#define RTC_REG_D 13
+
+/**********************************************************************
+ * register details
+ **********************************************************************/
+#define RTC_FREQ_SELECT RTC_REG_A
+
+/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
+ * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
+ * totalling to a max high interval of 2.228 ms.
+ */
+# define RTC_UIP 0x80
+# define RTC_DIV_CTL 0x70
+ /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
+# define RTC_REF_CLCK_4MHZ 0x00
+# define RTC_REF_CLCK_1MHZ 0x10
+# define RTC_REF_CLCK_32KHZ 0x20
+ /* 2 values for divider stage reset, others for "testing purposes only" */
+# define RTC_DIV_RESET1 0x60
+# define RTC_DIV_RESET2 0x70
+ /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
+# define RTC_RATE_SELECT 0x0F
+
+/**********************************************************************/
+#define RTC_CONTROL RTC_REG_B
+# define RTC_SET 0x80 /* disable updates for clock setting */
+# define RTC_PIE 0x40 /* periodic interrupt enable */
+# define RTC_AIE 0x20 /* alarm interrupt enable */
+# define RTC_UIE 0x10 /* update-finished interrupt enable */
+# define RTC_SQWE 0x08 /* enable square-wave output */
+# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
+# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
+# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
+
+/**********************************************************************/
+#define RTC_INTR_FLAGS RTC_REG_C
+/* caution - cleared by read */
+# define RTC_IRQF 0x80 /* any of the following 3 is active */
+# define RTC_PF 0x40
+# define RTC_AF 0x20
+# define RTC_UF 0x10
+
+/**********************************************************************/
+#define RTC_VALID RTC_REG_D
+# define RTC_VRT 0x80 /* valid RAM and time */
+/**********************************************************************/
+
+/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+ * determines if the following two #defines are needed
+ */
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+/*
+ * The struct used to pass data via the following ioctl. Similar to the
+ * struct tm in <time.h>, but it needs to be here so that the kernel
+ * source is self contained, allowing cross-compiles, etc. etc.
+ */
+
+struct rtc_time {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+/*
+ * ioctl calls that are permitted to the /dev/rtc interface, if
+ * CONFIG_RTC was enabled.
+ */
+
+#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */
+#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */
+#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
+#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */
+#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */
+#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */
+
+#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */
+#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */
+#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */
+#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */
+#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */
+#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */
+#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
+#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
+
+
+#endif /* _MC146818RTC_H */
diff --git a/pfinet/linux-src/include/linux/mca.h b/pfinet/linux-src/include/linux/mca.h
new file mode 100644
index 00000000..5b6a6ebf
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mca.h
@@ -0,0 +1,100 @@
+/*
+ * Header for Microchannel Architecture Bus
+ * Written by Martin Kolinek, February 1996
+*/
+
+#ifndef _LINUX_MCA_H
+#define _LINUX_MCA_H
+
+/* The detection of MCA bus is done in the real mode (using BIOS).
+ * The information is exported to the protected code, where this
+ * variable is set to one in case MCA bus was detected.
+*/
+extern int MCA_bus;
+
+/* maximal number of MCA slots - actually, some machines have less, but
+they all have sufficient number of POS registers to cover 8. */
+#define MCA_MAX_SLOT_NR 8
+
+/* MCA_NOTFOUND is an error condition. The other two indicate
+ motherboard POS registers contain the adapter. They might be
+ returned by the mca_find_adapter() function, and can be used as
+ arguments to mca_read_stored_pos(). I'm not going to allow direct
+ access to the motherboard registers until we run across an adapter
+ that requires it. We don't know enough about them to know if it's
+ safe.
+
+ See Documentation/mca.txt or one of the existing drivers for
+ more information.
+*/
+#define MCA_NOTFOUND (-1)
+#define MCA_INTEGSCSI (MCA_MAX_SLOT_NR)
+#define MCA_INTEGVIDEO (MCA_MAX_SLOT_NR+1)
+
+/* max number of adapters, including both slots and various integrated
+things. */
+#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+2)
+
+/* returns the slot of the first enabled adapter matching id. User can
+specify a starting slot beyond zero, to deal with detecting multiple
+devices. Returns MCA_NOTFOUND if id not found. Also checks the
+integrated adapters. */
+extern int mca_find_adapter(int id, int start);
+extern int mca_find_unused_adapter(int id, int start);
+
+/* adapter state info - returns 0 if no */
+extern int mca_isadapter(int slot);
+extern int mca_isenabled(int slot);
+
+extern int mca_is_adapter_used(int slot);
+extern int mca_mark_as_used(int slot);
+extern void mca_mark_as_unused(int slot);
+
+/* gets a byte out of POS register (stored in memory) */
+extern unsigned char mca_read_stored_pos(int slot, int reg);
+
+/*
+ This can be expanded later. Right now, it gives us a way of
+ getting meaningful information into the MCA_info structure,
+ so we can have a more interesting /proc/mca.
+*/
+extern void mca_set_adapter_name(int slot, char* name);
+extern char* mca_get_adapter_name(int slot);
+
+/*
+ This sets up an information callback for /proc/mca/slot?. The
+ function is called with the buffer, slot, and device pointer (or
+ some equally informative context information, or nothing, if you
+ prefer), and is expected to put useful information into the
+ buffer. The adapter name, id, and POS registers get printed
+ before this is called though, so don't do it again.
+
+ This should be called with a NULL procfn when a module
+ unregisters, thus preventing kernel crashes and other such
+ nastiness.
+*/
+typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev);
+extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
+
+/* These routines actually mess with the hardware POS registers. They
+temporarily disable the device (and interrupts), so make sure you know
+what you're doing if you use them. Furthermore, writing to a POS may
+result in two devices trying to share a resource, which in turn can
+result in multiple devices sharing memory spaces, IRQs, or even trashing
+hardware. YOU HAVE BEEN WARNED.
+
+You can only access slots with this. Motherboard registers are off
+limits.
+*/
+
+/* read a byte from the specified POS register. */
+extern unsigned char mca_read_pos(int slot, int reg);
+
+/* write a byte to the specified POS register. */
+extern void mca_write_pos(int slot, int reg, unsigned char byte);
+
+/* Should only be called by the NMI interrupt handler, this will do some
+fancy stuff to figure out what might have generated a NMI. */
+extern void mca_handle_nmi(void);
+
+#endif /* _LINUX_MCA_H */
diff --git a/pfinet/linux-src/include/linux/md.h b/pfinet/linux-src/include/linux/md.h
new file mode 100644
index 00000000..f4f4f548
--- /dev/null
+++ b/pfinet/linux-src/include/linux/md.h
@@ -0,0 +1,300 @@
+/*
+ md.h : Multiple Devices driver for Linux
+ Copyright (C) 1994-96 Marc ZYNGIER
+ <zyngier@ufr-info-p7.ibp.fr> or
+ <maz@gloups.fdn.fr>
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ (for example /usr/src/linux/COPYING); if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _MD_H
+#define _MD_H
+
+#include <linux/major.h>
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/*
+ * Different major versions are not compatible.
+ * Different minor versions are only downward compatible.
+ * Different patchlevel versions are downward and upward compatible.
+ */
+#define MD_MAJOR_VERSION 0
+#define MD_MINOR_VERSION 36
+#define MD_PATCHLEVEL_VERSION 6
+
+#define MD_DEFAULT_DISK_READAHEAD (256 * 1024)
+
+/* ioctls */
+#define REGISTER_DEV _IO (MD_MAJOR, 1)
+#define START_MD _IO (MD_MAJOR, 2)
+#define STOP_MD _IO (MD_MAJOR, 3)
+#define REGISTER_DEV_NEW _IO (MD_MAJOR, 4)
+
+/*
+ personalities :
+ Byte 0 : Chunk size factor
+ Byte 1 : Fault tolerance count for each physical device
+ ( 0 means no fault tolerance,
+ 0xFF means always tolerate faults), not used by now.
+ Byte 2 : Personality
+ Byte 3 : Reserved.
+ */
+
+#define FAULT_SHIFT 8
+#define PERSONALITY_SHIFT 16
+
+#define FACTOR_MASK 0x000000FFUL
+#define FAULT_MASK 0x0000FF00UL
+#define PERSONALITY_MASK 0x00FF0000UL
+
+#define MD_RESERVED 0 /* Not used by now */
+#define LINEAR (1UL << PERSONALITY_SHIFT)
+#define STRIPED (2UL << PERSONALITY_SHIFT)
+#define RAID0 STRIPED
+#define RAID1 (3UL << PERSONALITY_SHIFT)
+#define RAID5 (4UL << PERSONALITY_SHIFT)
+#define MAX_PERSONALITY 5
+
+/*
+ * MD superblock.
+ *
+ * The MD superblock maintains some statistics on each MD configuration.
+ * Each real device in the MD set contains it near the end of the device.
+ * Some of the ideas are copied from the ext2fs implementation.
+ *
+ * We currently use 4096 bytes as follows:
+ *
+ * word offset function
+ *
+ * 0 - 31 Constant generic MD device information.
+ * 32 - 63 Generic state information.
+ * 64 - 127 Personality specific information.
+ * 128 - 511 12 32-words descriptors of the disks in the raid set.
+ * 512 - 911 Reserved.
+ * 912 - 1023 Disk specific descriptor.
+ */
+
+/*
+ * If x is the real device size in bytes, we return an apparent size of:
+ *
+ * y = (x & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES
+ *
+ * and place the 4kB superblock at offset y.
+ */
+#define MD_RESERVED_BYTES (64 * 1024)
+#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
+#define MD_RESERVED_BLOCKS (MD_RESERVED_BYTES / BLOCK_SIZE)
+
+#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) - MD_RESERVED_SECTORS)
+#define MD_NEW_SIZE_BLOCKS(x) ((x & ~(MD_RESERVED_BLOCKS - 1)) - MD_RESERVED_BLOCKS)
+
+#define MD_SB_BYTES 4096
+#define MD_SB_WORDS (MD_SB_BYTES / 4)
+#define MD_SB_BLOCKS (MD_SB_BYTES / BLOCK_SIZE)
+#define MD_SB_SECTORS (MD_SB_BYTES / 512)
+
+/*
+ * The following are counted in 32-bit words
+ */
+#define MD_SB_GENERIC_OFFSET 0
+#define MD_SB_PERSONALITY_OFFSET 64
+#define MD_SB_DISKS_OFFSET 128
+#define MD_SB_DESCRIPTOR_OFFSET 992
+
+#define MD_SB_GENERIC_CONSTANT_WORDS 32
+#define MD_SB_GENERIC_STATE_WORDS 32
+#define MD_SB_GENERIC_WORDS (MD_SB_GENERIC_CONSTANT_WORDS + MD_SB_GENERIC_STATE_WORDS)
+#define MD_SB_PERSONALITY_WORDS 64
+#define MD_SB_DISKS_WORDS 384
+#define MD_SB_DESCRIPTOR_WORDS 32
+#define MD_SB_RESERVED_WORDS (1024 - MD_SB_GENERIC_WORDS - MD_SB_PERSONALITY_WORDS - MD_SB_DISKS_WORDS - MD_SB_DESCRIPTOR_WORDS)
+#define MD_SB_EQUAL_WORDS (MD_SB_GENERIC_WORDS + MD_SB_PERSONALITY_WORDS + MD_SB_DISKS_WORDS)
+#define MD_SB_DISKS (MD_SB_DISKS_WORDS / MD_SB_DESCRIPTOR_WORDS)
+
+/*
+ * Device "operational" state bits
+ */
+#define MD_FAULTY_DEVICE 0 /* Device is faulty / operational */
+#define MD_ACTIVE_DEVICE 1 /* Device is a part or the raid set / spare disk */
+#define MD_SYNC_DEVICE 2 /* Device is in sync with the raid set */
+
+typedef struct md_device_descriptor_s {
+ __u32 number; /* 0 Device number in the entire set */
+ __u32 major; /* 1 Device major number */
+ __u32 minor; /* 2 Device minor number */
+ __u32 raid_disk; /* 3 The role of the device in the raid set */
+ __u32 state; /* 4 Operational state */
+ __u32 reserved[MD_SB_DESCRIPTOR_WORDS - 5];
+} md_descriptor_t;
+
+#define MD_SB_MAGIC 0xa92b4efc
+
+/*
+ * Superblock state bits
+ */
+#define MD_SB_CLEAN 0
+#define MD_SB_ERRORS 1
+
+typedef struct md_superblock_s {
+
+ /*
+ * Constant generic information
+ */
+ __u32 md_magic; /* 0 MD identifier */
+ __u32 major_version; /* 1 major version to which the set conforms */
+ __u32 minor_version; /* 2 minor version to which the set conforms */
+ __u32 patch_version; /* 3 patchlevel version to which the set conforms */
+ __u32 gvalid_words; /* 4 Number of non-reserved words in this section */
+ __u32 set_magic; /* 5 Raid set identifier */
+ __u32 ctime; /* 6 Creation time */
+ __u32 level; /* 7 Raid personality (mirroring, raid5, ...) */
+ __u32 size; /* 8 Apparent size of each individual disk, in kB */
+ __u32 nr_disks; /* 9 Number of total disks in the raid set */
+ __u32 raid_disks; /* 10 Number of disks in a fully functional raid set */
+ __u32 gstate_creserved[MD_SB_GENERIC_CONSTANT_WORDS - 11];
+
+ /*
+ * Generic state information
+ */
+ __u32 utime; /* 0 Superblock update time */
+ __u32 state; /* 1 State bits (clean, ...) */
+ __u32 active_disks; /* 2 Number of currently active disks (some non-faulty disks might not be in sync) */
+ __u32 working_disks; /* 3 Number of working disks */
+ __u32 failed_disks; /* 4 Number of failed disks */
+ __u32 spare_disks; /* 5 Number of spare disks */
+ __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 6];
+
+ /*
+ * Personality information
+ */
+ __u32 parity_algorithm;
+ __u32 chunk_size;
+ __u32 pstate_reserved[MD_SB_PERSONALITY_WORDS - 2];
+
+ /*
+ * Disks information
+ */
+ md_descriptor_t disks[MD_SB_DISKS];
+
+ /*
+ * Reserved
+ */
+ __u32 reserved[MD_SB_RESERVED_WORDS];
+
+ /*
+ * Active descriptor
+ */
+ md_descriptor_t descriptor;
+} md_superblock_t;
+
+#ifdef __KERNEL__
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <asm/semaphore.h>
+
+/*
+ * Kernel-based reconstruction is mostly working, but still requires
+ * some additional work.
+ */
+#define SUPPORT_RECONSTRUCTION 0
+
+#define MAX_REAL 8 /* Max number of physical dev per md dev */
+#define MAX_MD_DEV 4 /* Max number of md dev */
+
+#define FACTOR(a) ((a)->repartition & FACTOR_MASK)
+#define MAX_FAULT(a) (((a)->repartition & FAULT_MASK)>>8)
+#define PERSONALITY(a) ((a)->repartition & PERSONALITY_MASK)
+
+#define FACTOR_SHIFT(a) (PAGE_SHIFT + (a) - 10)
+
+struct real_dev
+{
+ kdev_t dev; /* Device number */
+ int size; /* Device size (in blocks) */
+ int offset; /* Real device offset (in blocks) in md dev
+ (only used in linear mode) */
+ struct inode *inode; /* Lock inode */
+ md_superblock_t *sb;
+ u32 sb_offset;
+};
+
+struct md_dev;
+
+#define SPARE_INACTIVE 0
+#define SPARE_WRITE 1
+#define SPARE_ACTIVE 2
+
+struct md_personality
+{
+ char *name;
+ int (*map)(struct md_dev *mddev, kdev_t *rdev,
+ unsigned long *rsector, unsigned long size);
+ int (*make_request)(struct md_dev *mddev, int rw, struct buffer_head * bh);
+ void (*end_request)(struct buffer_head * bh, int uptodate);
+ int (*run)(int minor, struct md_dev *mddev);
+ int (*stop)(int minor, struct md_dev *mddev);
+ int (*status)(char *page, int minor, struct md_dev *mddev);
+ int (*ioctl)(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+ int max_invalid_dev;
+ int (*error_handler)(struct md_dev *mddev, kdev_t dev);
+
+/*
+ * Some personalities (RAID-1, RAID-5) can get disks hot-added and
+ * hot-removed. Hot removal is different from failure. (failure marks
+ * a disk inactive, but the disk is still part of the array)
+ */
+ int (*hot_add_disk) (struct md_dev *mddev, kdev_t dev);
+ int (*hot_remove_disk) (struct md_dev *mddev, kdev_t dev);
+ int (*mark_spare) (struct md_dev *mddev, md_descriptor_t *descriptor, int state);
+};
+
+struct md_dev
+{
+ struct real_dev devices[MAX_REAL];
+ struct md_personality *pers;
+ md_superblock_t *sb;
+ int sb_dirty;
+ int repartition;
+ int busy;
+ int nb_dev;
+ void *private;
+};
+
+struct md_thread {
+ void (*run) (void *data);
+ void *data;
+ struct wait_queue *wqueue;
+ unsigned long flags;
+ struct semaphore *sem;
+ struct task_struct *tsk;
+};
+
+#define THREAD_WAKEUP 0
+
+extern struct md_dev md_dev[MAX_MD_DEV];
+extern int md_size[MAX_MD_DEV];
+extern int md_maxreadahead[MAX_MD_DEV];
+
+extern char *partition_name (kdev_t dev);
+
+extern int register_md_personality (int p_num, struct md_personality *p);
+extern int unregister_md_personality (int p_num);
+extern struct md_thread *md_register_thread (void (*run) (void *data), void *data);
+extern void md_unregister_thread (struct md_thread *thread);
+extern void md_wakeup_thread(struct md_thread *thread);
+extern int md_update_sb (int minor);
+extern int md_do_sync(struct md_dev *mddev);
+
+#endif __KERNEL__
+#endif _MD_H
diff --git a/pfinet/linux-src/include/linux/minix_fs.h b/pfinet/linux-src/include/linux/minix_fs.h
new file mode 100644
index 00000000..4682ee56
--- /dev/null
+++ b/pfinet/linux-src/include/linux/minix_fs.h
@@ -0,0 +1,127 @@
+#ifndef _LINUX_MINIX_FS_H
+#define _LINUX_MINIX_FS_H
+
+/*
+ * The minix filesystem constants/structures
+ */
+
+/*
+ * Thanks to Kees J Bot for sending me the definitions of the new
+ * minix filesystem (aka V2) with bigger inodes and 32-bit block
+ * pointers.
+ */
+
+#define MINIX_ROOT_INO 1
+
+/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
+#define MINIX_LINK_MAX 250
+#define MINIX2_LINK_MAX 65530
+
+#define MINIX_I_MAP_SLOTS 8
+#define MINIX_Z_MAP_SLOTS 64
+#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
+#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
+#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
+#define MINIX_VALID_FS 0x0001 /* Clean fs. */
+#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+#define MINIX_V1 0x0001 /* original minix fs */
+#define MINIX_V2 0x0002 /* minix V2 fs */
+
+#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
+
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix_inode {
+ __u16 i_mode;
+ __u16 i_uid;
+ __u32 i_size;
+ __u32 i_time;
+ __u8 i_gid;
+ __u8 i_nlinks;
+ __u16 i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+ __u16 i_mode;
+ __u16 i_nlinks;
+ __u16 i_uid;
+ __u16 i_gid;
+ __u32 i_size;
+ __u32 i_atime;
+ __u32 i_mtime;
+ __u32 i_ctime;
+ __u32 i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+ __u16 s_ninodes;
+ __u16 s_nzones;
+ __u16 s_imap_blocks;
+ __u16 s_zmap_blocks;
+ __u16 s_firstdatazone;
+ __u16 s_log_zone_size;
+ __u32 s_max_size;
+ __u16 s_magic;
+ __u16 s_state;
+ __u32 s_zones;
+};
+
+struct minix_dir_entry {
+ __u16 inode;
+ char name[0];
+};
+
+#ifdef __KERNEL__
+
+extern struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry);
+extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
+extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
+extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
+extern int minix_unlink(struct inode * dir, struct dentry *dentry);
+extern int minix_symlink(struct inode * inode, struct dentry *dentry,
+ const char * symname);
+extern int minix_link(struct dentry * old_dentry, struct inode * dir, struct dentry *dentry);
+extern int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev);
+extern int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir, struct dentry *new_dentry);
+extern struct inode * minix_new_inode(const struct inode * dir);
+extern void minix_free_inode(struct inode * inode);
+extern unsigned long minix_count_free_inodes(struct super_block *sb);
+extern int minix_new_block(struct super_block * sb);
+extern void minix_free_block(struct super_block * sb, int block);
+extern unsigned long minix_count_free_blocks(struct super_block *sb);
+
+extern int minix_bmap(struct inode *,int);
+
+extern struct buffer_head * minix_getblk(struct inode *, int, int);
+extern struct buffer_head * minix_bread(struct inode *, int, int);
+
+extern void minix_truncate(struct inode *);
+extern int init_minix_fs(void);
+extern int minix_sync_inode(struct inode *);
+extern int minix_sync_file(struct file *, struct dentry *);
+
+extern struct inode_operations minix_file_inode_operations;
+extern struct inode_operations minix_dir_inode_operations;
+extern struct inode_operations minix_symlink_inode_operations;
+extern struct dentry_operations minix_dentry_operations;
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/minix_fs_i.h b/pfinet/linux-src/include/linux/minix_fs_i.h
new file mode 100644
index 00000000..c3711e52
--- /dev/null
+++ b/pfinet/linux-src/include/linux/minix_fs_i.h
@@ -0,0 +1,14 @@
+#ifndef _MINIX_FS_I
+#define _MINIX_FS_I
+
+/*
+ * minix fs inode data in memory
+ */
+struct minix_inode_info {
+ union {
+ __u16 i1_data[16];
+ __u32 i2_data[16];
+ } u;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/minix_fs_sb.h b/pfinet/linux-src/include/linux/minix_fs_sb.h
new file mode 100644
index 00000000..54c82af9
--- /dev/null
+++ b/pfinet/linux-src/include/linux/minix_fs_sb.h
@@ -0,0 +1,26 @@
+#ifndef _MINIX_FS_SB
+#define _MINIX_FS_SB
+
+/*
+ * minix super-block data in memory
+ */
+struct minix_sb_info {
+ unsigned long s_ninodes;
+ unsigned long s_nzones;
+ unsigned long s_imap_blocks;
+ unsigned long s_zmap_blocks;
+ unsigned long s_firstdatazone;
+ unsigned long s_log_zone_size;
+ unsigned long s_max_size;
+ int s_dirsize;
+ int s_namelen;
+ int s_link_max;
+ struct buffer_head ** s_imap;
+ struct buffer_head ** s_zmap;
+ struct buffer_head * s_sbh;
+ struct minix_super_block * s_ms;
+ unsigned short s_mount_state;
+ unsigned short s_version;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/miscdevice.h b/pfinet/linux-src/include/linux/miscdevice.h
new file mode 100644
index 00000000..e04dc1b4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/miscdevice.h
@@ -0,0 +1,43 @@
+#ifndef _LINUX_MISCDEVICE_H
+#define _LINUX_MISCDEVICE_H
+
+#define BUSMOUSE_MINOR 0
+#define PSMOUSE_MINOR 1
+#define MS_BUSMOUSE_MINOR 2
+#define ATIXL_BUSMOUSE_MINOR 3
+#define AMIGAMOUSE_MINOR 4
+#define ATARIMOUSE_MINOR 5
+#define SUN_MOUSE_MINOR 6
+#define APOLLO_MOUSE_MINOR 7
+#define PC110PAD_MINOR 9
+#define MAC_MOUSE_MINOR 10
+#define WATCHDOG_MINOR 130 /* Watchdog timer */
+#define TEMP_MINOR 131 /* Temperature Sensor */
+#define RTC_MINOR 135
+#define SUN_OPENPROM_MINOR 139
+#define NVRAM_MINOR 144
+#define I2O_MINOR 166
+#define MISC_DYNAMIC_MINOR 255
+
+#define SGI_GRAPHICS_MINOR 146
+#define SGI_OPENGL_MINOR 147
+#define SGI_GFX_MINOR 148
+#define SGI_STREAMS_MOUSE 149
+#define SGI_STREAMS_KEYBOARD 150
+/* drivers/sgi/char/usema.c */
+#define SGI_USEMACLONE 151
+
+extern int misc_init(void);
+
+struct miscdevice
+{
+ int minor;
+ const char *name;
+ struct file_operations *fops;
+ struct miscdevice * next, * prev;
+};
+
+extern int misc_register(struct miscdevice * misc);
+extern int misc_deregister(struct miscdevice * misc);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/mm.h b/pfinet/linux-src/include/linux/mm.h
new file mode 100644
index 00000000..232c53dc
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mm.h
@@ -0,0 +1,392 @@
+#ifndef _LINUX_MM_H
+#define _LINUX_MM_H
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+
+#ifdef __KERNEL__
+
+#include <linux/string.h>
+
+extern unsigned long max_mapnr;
+extern unsigned long num_physpages;
+extern void * high_memory;
+extern int page_cluster;
+
+#include <asm/page.h>
+#include <asm/atomic.h>
+
+/*
+ * Linux kernel virtual memory manager primitives.
+ * The idea being to have a "virtual" mm in the same way
+ * we have a virtual fs - giving a cleaner interface to the
+ * mm details, and allowing different kinds of memory mappings
+ * (from shared memory to executable loading to arbitrary
+ * mmap() functions).
+ */
+
+/*
+ * This struct defines a memory VMM memory area. There is one of these
+ * per VM-area/task. A VM area is any part of the process virtual memory
+ * space that has a special rule for the page-fault handlers (ie a shared
+ * library, the executable area etc).
+ */
+struct vm_area_struct {
+ struct mm_struct * vm_mm; /* VM area parameters */
+ unsigned long vm_start;
+ unsigned long vm_end;
+
+ /* linked list of VM areas per task, sorted by address */
+ struct vm_area_struct *vm_next;
+
+ pgprot_t vm_page_prot;
+ unsigned short vm_flags;
+
+ /* AVL tree of VM areas per task, sorted by address */
+ short vm_avl_height;
+ struct vm_area_struct * vm_avl_left;
+ struct vm_area_struct * vm_avl_right;
+
+ /* For areas with inode, the list inode->i_mmap, for shm areas,
+ * the list of attaches, otherwise unused.
+ */
+ struct vm_area_struct *vm_next_share;
+ struct vm_area_struct **vm_pprev_share;
+
+ struct vm_operations_struct * vm_ops;
+ unsigned long vm_offset;
+ struct file * vm_file;
+ unsigned long vm_pte; /* shared mem */
+};
+
+/*
+ * vm_flags..
+ */
+#define VM_READ 0x0001 /* currently active flags */
+#define VM_WRITE 0x0002
+#define VM_EXEC 0x0004
+#define VM_SHARED 0x0008
+
+#define VM_MAYREAD 0x0010 /* limits for mprotect() etc */
+#define VM_MAYWRITE 0x0020
+#define VM_MAYEXEC 0x0040
+#define VM_MAYSHARE 0x0080
+
+#define VM_GROWSDOWN 0x0100 /* general info on the segment */
+#define VM_GROWSUP 0x0200
+#define VM_SHM 0x0400 /* shared memory area, don't swap out */
+#define VM_DENYWRITE 0x0800 /* ETXTBSY on write attempts.. */
+
+#define VM_EXECUTABLE 0x1000
+#define VM_LOCKED 0x2000
+#define VM_IO 0x4000 /* Memory mapped I/O or similar */
+
+#define VM_STACK_FLAGS 0x0177
+
+/*
+ * mapping from the currently active vm_flags protection bits (the
+ * low four bits) to a page protection mask..
+ */
+extern pgprot_t protection_map[16];
+
+
+/*
+ * These are the virtual MM functions - opening of an area, closing and
+ * unmapping it (needed to keep files on disk up-to-date etc), pointer
+ * to the functions called when a no-page or a wp-page exception occurs.
+ */
+struct vm_operations_struct {
+ void (*open)(struct vm_area_struct * area);
+ void (*close)(struct vm_area_struct * area);
+ void (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
+ void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot);
+ int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
+ void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise);
+ unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access);
+ unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
+ unsigned long page);
+ int (*swapout)(struct vm_area_struct *, struct page *);
+ pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
+};
+
+/*
+ * Try to keep the most commonly accessed fields in single cache lines
+ * here (16 bytes or greater). This ordering should be particularly
+ * beneficial on 32-bit processors.
+ *
+ * The first line is data used in page cache lookup, the second line
+ * is used for linear searches (eg. clock algorithm scans).
+ */
+typedef struct page {
+ /* these must be first (free area handling) */
+ struct page *next;
+ struct page *prev;
+ struct inode *inode;
+ unsigned long offset;
+ struct page *next_hash;
+ atomic_t count;
+ unsigned long flags; /* atomic flags, some possibly updated asynchronously */
+ struct wait_queue *wait;
+ struct page **pprev_hash;
+ struct buffer_head * buffers;
+} mem_map_t;
+
+/* Page flag bit values */
+#define PG_locked 0
+#define PG_error 1
+#define PG_referenced 2
+#define PG_dirty 3
+#define PG_uptodate 4
+#define PG_free_after 5
+#define PG_decr_after 6
+#define PG_swap_unlock_after 7
+#define PG_DMA 8
+#define PG_Slab 9
+#define PG_swap_cache 10
+#define PG_skip 11
+#define PG_reserved 31
+
+/* Make it prettier to test the above... */
+#define PageLocked(page) (test_bit(PG_locked, &(page)->flags))
+#define PageError(page) (test_bit(PG_error, &(page)->flags))
+#define PageReferenced(page) (test_bit(PG_referenced, &(page)->flags))
+#define PageDirty(page) (test_bit(PG_dirty, &(page)->flags))
+#define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags))
+#define PageFreeAfter(page) (test_bit(PG_free_after, &(page)->flags))
+#define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags))
+#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
+#define PageDMA(page) (test_bit(PG_DMA, &(page)->flags))
+#define PageSlab(page) (test_bit(PG_Slab, &(page)->flags))
+#define PageSwapCache(page) (test_bit(PG_swap_cache, &(page)->flags))
+#define PageReserved(page) (test_bit(PG_reserved, &(page)->flags))
+
+#define PageSetSlab(page) (set_bit(PG_Slab, &(page)->flags))
+#define PageSetSwapCache(page) (set_bit(PG_swap_cache, &(page)->flags))
+
+#define PageTestandSetDirty(page) \
+ (test_and_set_bit(PG_dirty, &(page)->flags))
+#define PageTestandSetSwapCache(page) \
+ (test_and_set_bit(PG_swap_cache, &(page)->flags))
+
+#define PageClearSlab(page) (clear_bit(PG_Slab, &(page)->flags))
+#define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags))
+
+#define PageTestandClearDirty(page) \
+ (test_and_clear_bit(PG_dirty, &(page)->flags))
+#define PageTestandClearSwapCache(page) \
+ (test_and_clear_bit(PG_swap_cache, &(page)->flags))
+
+/*
+ * Various page->flags bits:
+ *
+ * PG_reserved is set for a page which must never be accessed (which
+ * may not even be present).
+ *
+ * PG_DMA is set for those pages which lie in the range of
+ * physical addresses capable of carrying DMA transfers.
+ *
+ * Multiple processes may "see" the same page. E.g. for untouched
+ * mappings of /dev/null, all processes see the same page full of
+ * zeroes, and text pages of executables and shared libraries have
+ * only one copy in memory, at most, normally.
+ *
+ * For the non-reserved pages, page->count denotes a reference count.
+ * page->count == 0 means the page is free.
+ * page->count == 1 means the page is used for exactly one purpose
+ * (e.g. a private data page of one process).
+ *
+ * A page may be used for kmalloc() or anyone else who does a
+ * get_free_page(). In this case the page->count is at least 1, and
+ * all other fields are unused but should be 0 or NULL. The
+ * management of this page is the responsibility of the one who uses
+ * it.
+ *
+ * The other pages (we may call them "process pages") are completely
+ * managed by the Linux memory manager: I/O, buffers, swapping etc.
+ * The following discussion applies only to them.
+ *
+ * A page may belong to an inode's memory mapping. In this case,
+ * page->inode is the pointer to the inode, and page->offset is the
+ * file offset of the page (not necessarily a multiple of PAGE_SIZE).
+ *
+ * A page may have buffers allocated to it. In this case,
+ * page->buffers is a circular list of these buffer heads. Else,
+ * page->buffers == NULL.
+ *
+ * For pages belonging to inodes, the page->count is the number of
+ * attaches, plus 1 if buffers are allocated to the page.
+ *
+ * All pages belonging to an inode make up a doubly linked list
+ * inode->i_pages, using the fields page->next and page->prev. (These
+ * fields are also used for freelist management when page->count==0.)
+ * There is also a hash table mapping (inode,offset) to the page
+ * in memory if present. The lists for this hash table use the fields
+ * page->next_hash and page->pprev_hash.
+ *
+ * All process pages can do I/O:
+ * - inode pages may need to be read from disk,
+ * - inode pages which have been modified and are MAP_SHARED may need
+ * to be written to disk,
+ * - private pages which have been modified may need to be swapped out
+ * to swap space and (later) to be read back into memory.
+ * During disk I/O, PG_locked is used. This bit is set before I/O
+ * and reset when I/O completes. page->wait is a wait queue of all
+ * tasks waiting for the I/O on this page to complete.
+ * PG_uptodate tells whether the page's contents is valid.
+ * When a read completes, the page becomes uptodate, unless a disk I/O
+ * error happened.
+ * When a write completes, and PG_free_after is set, the page is
+ * freed without any further delay.
+ *
+ * For choosing which pages to swap out, inode pages carry a
+ * PG_referenced bit, which is set any time the system accesses
+ * that page through the (inode,offset) hash table.
+ *
+ * PG_skip is used on sparc/sparc64 architectures to "skip" certain
+ * parts of the address space.
+ *
+ * PG_error is set to indicate that an I/O error occurred on this page.
+ */
+
+extern mem_map_t * mem_map;
+
+/*
+ * This is timing-critical - most of the time in getting a new page
+ * goes to clearing the page. If you want a page without the clearing
+ * overhead, just use __get_free_page() directly..
+ */
+#define __get_free_page(gfp_mask) __get_free_pages((gfp_mask),0)
+#define __get_dma_pages(gfp_mask, order) __get_free_pages((gfp_mask) | GFP_DMA,(order))
+extern unsigned long FASTCALL(__get_free_pages(int gfp_mask, unsigned long gfp_order));
+
+extern inline unsigned long get_free_page(int gfp_mask)
+{
+ unsigned long page;
+
+ page = __get_free_page(gfp_mask);
+ if (page)
+ clear_page(page);
+ return page;
+}
+
+extern int low_on_memory;
+
+/* memory.c & swap.c*/
+
+#define free_page(addr) free_pages((addr),0)
+extern void FASTCALL(free_pages(unsigned long addr, unsigned long order));
+extern void FASTCALL(__free_page(struct page *));
+
+extern void show_free_areas(void);
+extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
+ unsigned long address);
+
+extern void free_page_tables(struct mm_struct * mm);
+extern void clear_page_tables(struct mm_struct *, unsigned long, int);
+extern int new_page_tables(struct task_struct * tsk);
+
+extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
+extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
+extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
+extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
+
+extern void vmtruncate(struct inode * inode, unsigned long offset);
+extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern int make_pages_present(unsigned long addr, unsigned long end);
+
+extern int pgt_cache_water[2];
+extern int check_pgt_cache(void);
+
+extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
+extern void mem_init(unsigned long start_mem, unsigned long end_mem);
+extern void show_mem(void);
+extern void si_meminfo(struct sysinfo * val);
+
+/* mmap.c */
+extern void vma_init(void);
+extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
+extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
+extern void build_mmap_avl(struct mm_struct *);
+extern void exit_mmap(struct mm_struct *);
+extern unsigned long get_unmapped_area(unsigned long, unsigned long);
+
+extern unsigned long do_mmap(struct file *, unsigned long, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+extern int do_munmap(unsigned long, size_t);
+
+/* filemap.c */
+extern void remove_inode_page(struct page *);
+extern unsigned long page_unuse(struct page *);
+extern int shrink_mmap(int, int);
+extern void truncate_inode_pages(struct inode *, unsigned long);
+extern unsigned long get_cached_page(struct inode *, unsigned long, int);
+extern void put_cached_page(unsigned long);
+
+/*
+ * GFP bitmasks..
+ */
+#define __GFP_WAIT 0x01
+#define __GFP_LOW 0x02
+#define __GFP_MED 0x04
+#define __GFP_HIGH 0x08
+#define __GFP_IO 0x10
+#define __GFP_SWAP 0x20
+
+#define __GFP_DMA 0x80
+
+#define GFP_BUFFER (__GFP_LOW | __GFP_WAIT)
+#define GFP_ATOMIC (__GFP_HIGH)
+#define GFP_USER (__GFP_LOW | __GFP_WAIT | __GFP_IO)
+#define GFP_KERNEL (__GFP_MED | __GFP_WAIT | __GFP_IO)
+#define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO)
+#define GFP_KSWAPD (__GFP_IO | __GFP_SWAP)
+
+/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
+ platforms, used as appropriate on others */
+
+#define GFP_DMA __GFP_DMA
+
+/* vma is the first one with address < vma->vm_end,
+ * and even address < vma->vm_start. Have to extend vma. */
+static inline int expand_stack(struct vm_area_struct * vma, unsigned long address)
+{
+ unsigned long grow;
+
+ address &= PAGE_MASK;
+ grow = vma->vm_start - address;
+ if ((vma->vm_end - address
+ > current->rlim[RLIMIT_STACK].rlim_cur) ||
+ ((current->rlim[RLIMIT_AS].rlim_cur < RLIM_INFINITY) &&
+ ((vma->vm_mm->total_vm << PAGE_SHIFT) + grow
+ > current->rlim[RLIMIT_AS].rlim_cur)))
+ return -ENOMEM;
+ vma->vm_start = address;
+ vma->vm_offset -= grow;
+ vma->vm_mm->total_vm += grow >> PAGE_SHIFT;
+ if (vma->vm_flags & VM_LOCKED)
+ vma->vm_mm->locked_vm += grow >> PAGE_SHIFT;
+ return 0;
+}
+
+/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
+extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
+
+/* Look up the first VMA which intersects the interval start_addr..end_addr-1,
+ NULL if none. Assume start_addr < end_addr. */
+static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
+{
+ struct vm_area_struct * vma = find_vma(mm,start_addr);
+
+ if (vma && end_addr <= vma->vm_start)
+ vma = NULL;
+ return vma;
+}
+
+#define buffer_under_min() ((buffermem >> PAGE_SHIFT) * 100 < \
+ buffer_mem.min_percent * num_physpages)
+#define pgcache_under_min() (page_cache_size * 100 < \
+ page_cache.min_percent * num_physpages)
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/mman.h b/pfinet/linux-src/include/linux/mman.h
new file mode 100644
index 00000000..3bc0430b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mman.h
@@ -0,0 +1,8 @@
+#ifndef _LINUX_MMAN_H
+#define _LINUX_MMAN_H
+
+#include <asm/mman.h>
+
+#define MREMAP_MAYMOVE 1
+
+#endif /* _LINUX_MMAN_H */
diff --git a/pfinet/linux-src/include/linux/modsetver.h b/pfinet/linux-src/include/linux/modsetver.h
new file mode 100644
index 00000000..7d0b9d37
--- /dev/null
+++ b/pfinet/linux-src/include/linux/modsetver.h
@@ -0,0 +1,10 @@
+/* Symbol versioning nastiness. */
+
+#define __SYMBOL_VERSION(x) __ver_ ## x
+#define __VERSIONED_SYMBOL2(x,v) x ## _R ## v
+#define __VERSIONED_SYMBOL1(x,v) __VERSIONED_SYMBOL2(x,v)
+#define __VERSIONED_SYMBOL(x) __VERSIONED_SYMBOL1(x,__SYMBOL_VERSION(x))
+
+#ifndef _set_ver
+#define _set_ver(x) __VERSIONED_SYMBOL(x)
+#endif
diff --git a/pfinet/linux-src/include/linux/module.h b/pfinet/linux-src/include/linux/module.h
new file mode 100644
index 00000000..585a8d1d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/module.h
@@ -0,0 +1,287 @@
+/*
+ * Dynamic loading of modules into the kernel.
+ *
+ * Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
+ */
+
+#ifndef _LINUX_MODULE_H
+#define _LINUX_MODULE_H
+
+#include <linux/config.h>
+
+#ifdef __GENKSYMS__
+# define _set_ver(sym) sym
+# undef MODVERSIONS
+# define MODVERSIONS
+#else /* ! __GENKSYMS__ */
+# if !defined(MODVERSIONS) && defined(EXPORT_SYMTAB)
+# define _set_ver(sym) sym
+# include <linux/modversions.h>
+# endif
+#endif /* __GENKSYMS__ */
+
+#include <asm/atomic.h>
+
+/* Don't need to bring in all of uaccess.h just for this decl. */
+struct exception_table_entry;
+
+/* Used by get_kernel_syms, which is obsolete. */
+struct kernel_sym
+{
+ unsigned long value;
+ char name[60]; /* should have been 64-sizeof(long); oh well */
+};
+
+struct module_symbol
+{
+ unsigned long value;
+ const char *name;
+};
+
+struct module_ref
+{
+ struct module *dep; /* "parent" pointer */
+ struct module *ref; /* "child" pointer */
+ struct module_ref *next_ref;
+};
+
+/* TBD */
+struct module_persist;
+
+struct module
+{
+ unsigned long size_of_struct; /* == sizeof(module) */
+ struct module *next;
+ const char *name;
+ unsigned long size;
+
+ union
+ {
+ atomic_t usecount;
+ long pad;
+ } uc; /* Needs to keep its size - so says rth */
+
+ unsigned long flags; /* AUTOCLEAN et al */
+
+ unsigned nsyms;
+ unsigned ndeps;
+
+ struct module_symbol *syms;
+ struct module_ref *deps;
+ struct module_ref *refs;
+ int (*init)(void);
+ void (*cleanup)(void);
+ const struct exception_table_entry *ex_table_start;
+ const struct exception_table_entry *ex_table_end;
+#ifdef __alpha__
+ unsigned long gp;
+#endif
+ /* Members past this point are extensions to the basic
+ module support and are optional. Use mod_opt_member()
+ to examine them. */
+ const struct module_persist *persist_start;
+ const struct module_persist *persist_end;
+ int (*can_unload)(void);
+};
+
+struct module_info
+{
+ unsigned long addr;
+ unsigned long size;
+ unsigned long flags;
+ long usecount;
+};
+
+/* Bits of module.flags. */
+
+#define MOD_UNINITIALIZED 0
+#define MOD_RUNNING 1
+#define MOD_DELETED 2
+#define MOD_AUTOCLEAN 4
+#define MOD_VISITED 8
+#define MOD_USED_ONCE 16
+#define MOD_JUST_FREED 32
+
+/* Values for query_module's which. */
+
+#define QM_MODULES 1
+#define QM_DEPS 2
+#define QM_REFS 3
+#define QM_SYMBOLS 4
+#define QM_INFO 5
+
+/* When struct module is extended, we must test whether the new member
+ is present in the header received from insmod before we can use it.
+ This function returns true if the member is present. */
+
+#define mod_member_present(mod,member) \
+ ((unsigned long)(&((struct module *)0L)->member + 1) \
+ <= (mod)->size_of_struct)
+
+/* Backwards compatibility definition. */
+
+#define GET_USE_COUNT(module) (atomic_read(&(module)->uc.usecount))
+
+/* Poke the use count of a module. */
+
+#define __MOD_INC_USE_COUNT(mod) \
+ (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
+#define __MOD_DEC_USE_COUNT(mod) \
+ (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
+#define __MOD_IN_USE(mod) \
+ (mod_member_present((mod), can_unload) && (mod)->can_unload \
+ ? (mod)->can_unload() : atomic_read(&(mod)->uc.usecount))
+
+/* Indirect stringification. */
+
+#define __MODULE_STRING_1(x) #x
+#define __MODULE_STRING(x) __MODULE_STRING_1(x)
+
+/* Find a symbol exported by the kernel or another module */
+extern unsigned long get_module_symbol(char *, char *);
+
+#if defined(MODULE) && !defined(__GENKSYMS__)
+
+/* Embedded module documentation macros. */
+
+/* For documentation purposes only. */
+
+#define MODULE_AUTHOR(name) \
+const char __module_author[] __attribute__((section(".modinfo"))) = \
+"author=" name
+
+#define MODULE_DESCRIPTION(desc) \
+const char __module_description[] __attribute__((section(".modinfo"))) = \
+"description=" desc
+
+/* Could potentially be used by kmod... */
+
+#define MODULE_SUPPORTED_DEVICE(dev) \
+const char __module_device[] __attribute__((section(".modinfo"))) = \
+"device=" dev
+
+/* Used to verify parameters given to the module. The TYPE arg should
+ be a string in the following format:
+ [min[-max]]{b,h,i,l,s}
+ The MIN and MAX specifiers delimit the length of the array. If MAX
+ is omitted, it defaults to MIN; if both are omitted, the default is 1.
+ The final character is a type specifier:
+ b byte
+ h short
+ i int
+ l long
+ s string
+*/
+
+#define MODULE_PARM(var,type) \
+const char __module_parm_##var[] \
+__attribute__((section(".modinfo"))) = \
+"parm_" __MODULE_STRING(var) "=" type
+
+#define MODULE_PARM_DESC(var,desc) \
+const char __module_parm_desc_##var[] \
+__attribute__((section(".modinfo"))) = \
+"parm_desc_" __MODULE_STRING(var) "=" desc
+
+/* The attributes of a section are set the first time the section is
+ seen; we want .modinfo to not be allocated. */
+
+__asm__(".section .modinfo\n\t.previous");
+
+/* Define the module variable, and usage macros. */
+extern struct module __this_module;
+
+#define MOD_INC_USE_COUNT __MOD_INC_USE_COUNT(&__this_module)
+#define MOD_DEC_USE_COUNT __MOD_DEC_USE_COUNT(&__this_module)
+#define MOD_IN_USE __MOD_IN_USE(&__this_module)
+
+#ifndef __NO_VERSION__
+#include <linux/version.h>
+const char __module_kernel_version[] __attribute__((section(".modinfo"))) =
+"kernel_version=" UTS_RELEASE;
+#ifdef MODVERSIONS
+const char __module_using_checksums[] __attribute__((section(".modinfo"))) =
+"using_checksums=1";
+#endif
+#endif
+
+#else /* MODULE */
+
+#define MODULE_AUTHOR(name)
+#define MODULE_DESCRIPTION(desc)
+#define MODULE_SUPPORTED_DEVICE(name)
+#define MODULE_PARM(var,type)
+#define MODULE_PARM_DESC(var,desc)
+
+#ifndef __GENKSYMS__
+
+#define MOD_INC_USE_COUNT do { } while (0)
+#define MOD_DEC_USE_COUNT do { } while (0)
+#define MOD_IN_USE 1
+
+extern struct module *module_list;
+
+#endif /* !__GENKSYMS__ */
+
+#endif /* MODULE */
+
+/* Export a symbol either from the kernel or a module.
+
+ In the kernel, the symbol is added to the kernel's global symbol table.
+
+ In a module, it controls which variables are exported. If no
+ variables are explicitly exported, the action is controlled by the
+ insmod -[xX] flags. Otherwise, only the variables listed are exported.
+ This obviates the need for the old register_symtab() function. */
+
+#if defined(__GENKSYMS__)
+
+/* We want the EXPORT_SYMBOL tag left intact for recognition. */
+
+#elif !defined(AUTOCONF_INCLUDED)
+
+#define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module
+#define EXPORT_SYMBOL(var) error config_must_be_included_before_module
+#define EXPORT_SYMBOL_NOVERS(var) error config_must_be_included_before_module
+
+#elif !defined(CONFIG_MODULES)
+
+#define __EXPORT_SYMBOL(sym,str)
+#define EXPORT_SYMBOL(var)
+#define EXPORT_SYMBOL_NOVERS(var)
+
+#elif !defined(EXPORT_SYMTAB)
+
+/* If things weren't set up in the Makefiles to get EXPORT_SYMTAB defined,
+ then they weren't set up to run genksyms properly so MODVERSIONS breaks. */
+#define __EXPORT_SYMBOL(sym,str) error EXPORT_SYMTAB_not_defined
+#define EXPORT_SYMBOL(var) error EXPORT_SYMTAB_not_defined
+#define EXPORT_SYMBOL_NOVERS(var) error EXPORT_SYMTAB_not_defined
+
+#else
+
+#define __EXPORT_SYMBOL(sym, str) \
+const char __kstrtab_##sym[] \
+__attribute__((section(".kstrtab"))) = str; \
+const struct module_symbol __ksymtab_##sym \
+__attribute__((section("__ksymtab"))) = \
+{ (unsigned long)&sym, __kstrtab_##sym }
+
+#if defined(MODVERSIONS) || !defined(CONFIG_MODVERSIONS)
+#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var))
+#else
+#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
+#endif
+
+#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var))
+
+#endif /* __GENKSYMS__ */
+
+#ifdef MODULE
+/* Force a module to export no symbols. */
+#define EXPORT_NO_SYMBOLS __asm__(".section __ksymtab\n.previous")
+#else
+#define EXPORT_NO_SYMBOLS
+#endif /* MODULE */
+
+#endif /* _LINUX_MODULE_H */
diff --git a/pfinet/linux-src/include/linux/mount.h b/pfinet/linux-src/include/linux/mount.h
new file mode 100644
index 00000000..1e697071
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mount.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Definitions for mount interface. This describes the in the kernel build
+ * linkedlist with mounted filesystems.
+ *
+ * Author: Marco van Wieringen <mvw@planets.elm.net>
+ *
+ * Version: $Id: mount.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $
+ *
+ */
+#ifndef _LINUX_MOUNT_H
+#define _LINUX_MOUNT_H
+
+#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */
+#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */
+
+struct quota_mount_options
+{
+ unsigned int flags; /* Flags for diskquotas on this device */
+ struct semaphore dqio_sem; /* lock device while I/O in progress */
+ struct semaphore dqoff_sem; /* serialize quota_off() and quota_on() on device */
+ struct file *files[MAXQUOTAS]; /* fp's to quotafiles */
+ time_t inode_expire[MAXQUOTAS]; /* expiretime for inode-quota */
+ time_t block_expire[MAXQUOTAS]; /* expiretime for block-quota */
+ char rsquash[MAXQUOTAS]; /* for quotas treat root as any other user */
+};
+
+struct vfsmount
+{
+ kdev_t mnt_dev; /* Device this applies to */
+ char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
+ char *mnt_dirname; /* Name of directory mounted on */
+ unsigned int mnt_flags; /* Flags of this device */
+ struct super_block *mnt_sb; /* pointer to superblock */
+ struct quota_mount_options mnt_dquot; /* Diskquota specific mount options */
+ struct vfsmount *mnt_next; /* pointer to next in linkedlist */
+};
+
+struct vfsmount *lookup_vfsmnt(kdev_t dev);
+
+/*
+ * Umount options
+ */
+
+#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
+
+#endif /* _LINUX_MOUNT_H */
diff --git a/pfinet/linux-src/include/linux/mpp.h b/pfinet/linux-src/include/linux/mpp.h
new file mode 100644
index 00000000..2dd02ff4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mpp.h
@@ -0,0 +1,18 @@
+#ifndef _LINUX_MPP_H
+#define _LINUX_MPP_H
+
+/*
+ * Definitions related to Massively Parallel Processing support.
+ */
+
+/* All mpp implementations must supply these functions */
+
+extern void mpp_init(void);
+extern void mpp_hw_init(void);
+extern void mpp_procfs_init(void);
+
+extern int mpp_num_cells(void);
+extern int mpp_cid(void);
+extern int get_mppinfo(char *buffer);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/mroute.h b/pfinet/linux-src/include/linux/mroute.h
new file mode 100644
index 00000000..b57519b7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mroute.h
@@ -0,0 +1,223 @@
+#ifndef __LINUX_MROUTE_H
+#define __LINUX_MROUTE_H
+
+#include <linux/sockios.h>
+#include <linux/in.h>
+
+/*
+ * Based on the MROUTING 3.5 defines primarily to keep
+ * source compatibility with BSD.
+ *
+ * See the mrouted code for the original history.
+ *
+ * Protocol Independent Multicast (PIM) data structures included
+ * Carlos Picoto (cap@di.fc.ul.pt)
+ *
+ */
+
+#define MRT_BASE 200
+#define MRT_INIT (MRT_BASE) /* Activate the kernel mroute code */
+#define MRT_DONE (MRT_BASE+1) /* Shutdown the kernel mroute */
+#define MRT_ADD_VIF (MRT_BASE+2) /* Add a virtual interface */
+#define MRT_DEL_VIF (MRT_BASE+3) /* Delete a virtual interface */
+#define MRT_ADD_MFC (MRT_BASE+4) /* Add a multicast forwarding entry */
+#define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */
+#define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */
+#define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */
+#define MRT_PIM (MRT_BASE+8) /* enable PIM code */
+
+#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */
+#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1)
+#define SIOCGETRPF (SIOCPROTOPRIVATE+2)
+
+#define MAXVIFS 32
+typedef unsigned long vifbitmap_t; /* User mode code depends on this lot */
+typedef unsigned short vifi_t;
+#define ALL_VIFS ((vifi_t)(-1))
+
+/*
+ * Same idea as select
+ */
+
+#define VIFM_SET(n,m) ((m)|=(1<<(n)))
+#define VIFM_CLR(n,m) ((m)&=~(1<<(n)))
+#define VIFM_ISSET(n,m) ((m)&(1<<(n)))
+#define VIFM_CLRALL(m) ((m)=0)
+#define VIFM_COPY(mfrom,mto) ((mto)=(mfrom))
+#define VIFM_SAME(m1,m2) ((m1)==(m2))
+
+/*
+ * Passed by mrouted for an MRT_ADD_VIF - again we use the
+ * mrouted 3.6 structures for compatibility
+ */
+
+struct vifctl {
+ vifi_t vifc_vifi; /* Index of VIF */
+ unsigned char vifc_flags; /* VIFF_ flags */
+ unsigned char vifc_threshold; /* ttl limit */
+ unsigned int vifc_rate_limit; /* Rate limiter values (NI) */
+ struct in_addr vifc_lcl_addr; /* Our address */
+ struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */
+};
+
+#define VIFF_TUNNEL 0x1 /* IPIP tunnel */
+#define VIFF_SRCRT 0x2 /* NI */
+#define VIFF_REGISTER 0x4 /* register vif */
+
+/*
+ * Cache manipulation structures for mrouted and PIMd
+ */
+
+struct mfcctl
+{
+ struct in_addr mfcc_origin; /* Origin of mcast */
+ struct in_addr mfcc_mcastgrp; /* Group in question */
+ vifi_t mfcc_parent; /* Where it arrived */
+ unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */
+ unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */
+ unsigned int mfcc_byte_cnt;
+ unsigned int mfcc_wrong_if;
+ int mfcc_expire;
+};
+
+/*
+ * Group count retrieval for mrouted
+ */
+
+struct sioc_sg_req
+{
+ struct in_addr src;
+ struct in_addr grp;
+ unsigned long pktcnt;
+ unsigned long bytecnt;
+ unsigned long wrong_if;
+};
+
+/*
+ * To get vif packet counts
+ */
+
+struct sioc_vif_req
+{
+ vifi_t vifi; /* Which iface */
+ unsigned long icount; /* In packets */
+ unsigned long ocount; /* Out packets */
+ unsigned long ibytes; /* In bytes */
+ unsigned long obytes; /* Out bytes */
+};
+
+/*
+ * This is the format the mroute daemon expects to see IGMP control
+ * data. Magically happens to be like an IP packet as per the original
+ */
+
+struct igmpmsg
+{
+ __u32 unused1,unused2;
+ unsigned char im_msgtype; /* What is this */
+ unsigned char im_mbz; /* Must be zero */
+ unsigned char im_vif; /* Interface (this ought to be a vifi_t!) */
+ unsigned char unused3;
+ struct in_addr im_src,im_dst;
+};
+
+/*
+ * That's all usermode folks
+ */
+
+#ifdef __KERNEL__
+extern struct sock *mroute_socket;
+extern int ip_mroute_setsockopt(struct sock *, int, char *, int);
+extern int ip_mroute_getsockopt(struct sock *, int, char *, int *);
+extern int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern void mroute_close(struct sock *sk);
+extern void ipmr_forward(struct sk_buff *skb, int is_frag);
+extern int ip_mr_find_tunnel(__u32, __u32);
+extern void ip_mr_init(void);
+
+
+struct vif_device
+{
+ struct device *dev; /* Device we are using */
+ unsigned long bytes_in,bytes_out;
+ unsigned long pkt_in,pkt_out; /* Statistics */
+ unsigned long rate_limit; /* Traffic shaping (NI) */
+ unsigned char threshold; /* TTL threshold */
+ unsigned short flags; /* Control flags */
+ __u32 local,remote; /* Addresses(remote for tunnels)*/
+ int link; /* Physical interface index */
+};
+
+struct mfc_cache
+{
+ struct mfc_cache *next; /* Next entry on cache line */
+ __u32 mfc_mcastgrp; /* Group the entry belongs to */
+ __u32 mfc_origin; /* Source of packet */
+ vifi_t mfc_parent; /* Source interface */
+ struct timer_list mfc_timer; /* Expiry timer */
+ int mfc_flags; /* Flags on line */
+ struct sk_buff_head mfc_unresolved; /* Unresolved buffers */
+ int mfc_queuelen; /* Unresolved buffer counter */
+ unsigned long mfc_last_assert;
+ int mfc_minvif;
+ int mfc_maxvif;
+ unsigned long mfc_bytes;
+ unsigned long mfc_pkt;
+ unsigned long mfc_wrong_if;
+ unsigned char mfc_ttls[MAXVIFS]; /* TTL thresholds */
+};
+
+#define MFC_QUEUED 1
+#define MFC_RESOLVED 2
+#define MFC_NOTIFY 4
+
+
+#define MFC_LINES 64
+
+#ifdef __BIG_ENDIAN
+#define MFC_HASH(a,b) ((((a)>>24)^((b)>>26))&(MFC_LINES-1))
+#else
+#define MFC_HASH(a,b) (((a)^((b)>>2))&(MFC_LINES-1))
+#endif
+
+#endif
+
+
+#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */
+
+/*
+ * Pseudo messages used by mrouted
+ */
+
+#define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */
+#define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */
+#define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */
+
+#ifdef __KERNEL__
+
+#define PIM_V1_VERSION __constant_htonl(0x10000000)
+#define PIM_V1_REGISTER 1
+
+#define PIM_VERSION 2
+#define PIM_REGISTER 1
+
+#define PIM_NULL_REGISTER __constant_htonl(0x40000000)
+
+/* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */
+
+struct pimreghdr
+{
+ __u8 type;
+ __u8 reserved;
+ __u16 csum;
+ __u32 flags;
+};
+
+extern int pim_rcv(struct sk_buff * , unsigned short);
+extern int pim_rcv_v1(struct sk_buff * , unsigned short len);
+
+struct rtmsg;
+extern int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait);
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/msdos_fs.h b/pfinet/linux-src/include/linux/msdos_fs.h
new file mode 100644
index 00000000..f9ef19e8
--- /dev/null
+++ b/pfinet/linux-src/include/linux/msdos_fs.h
@@ -0,0 +1,336 @@
+#ifndef _LINUX_MSDOS_FS_H
+#define _LINUX_MSDOS_FS_H
+
+/*
+ * The MS-DOS filesystem constants/structures
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/fd.h>
+
+#include <asm/byteorder.h>
+
+#define MSDOS_ROOT_INO 1 /* == MINIX_ROOT_INO */
+#define SECTOR_SIZE 512 /* sector size (bytes) */
+#define SECTOR_BITS 9 /* log2(SECTOR_SIZE) */
+#define MSDOS_DPB (MSDOS_DPS) /* dir entries per block */
+#define MSDOS_DPB_BITS 4 /* log2(MSDOS_DPB) */
+#define MSDOS_DPS (SECTOR_SIZE/sizeof(struct msdos_dir_entry))
+#define MSDOS_DPS_BITS 4 /* log2(MSDOS_DPS) */
+#define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */
+
+#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
+
+#define FAT_CACHE 8 /* FAT cache size */
+
+#define MSDOS_MAX_EXTRA 3 /* tolerate up to that number of clusters which are
+ inaccessible because the FAT is too short */
+
+#define ATTR_RO 1 /* read-only */
+#define ATTR_HIDDEN 2 /* hidden */
+#define ATTR_SYS 4 /* system */
+#define ATTR_VOLUME 8 /* volume label */
+#define ATTR_DIR 16 /* directory */
+#define ATTR_ARCH 32 /* archived */
+
+#define ATTR_NONE 0 /* no attribute bits */
+#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
+ /* attribute bits that are copied "as is" */
+#define ATTR_EXT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME)
+ /* bits that are used by the Windows 95/Windows NT extended FAT */
+
+#define ATTR_DIR_READ_BOTH 512 /* read both short and long names from the
+ * vfat filesystem. This is used by Samba
+ * to export the vfat filesystem with correct
+ * shortnames. */
+#define ATTR_DIR_READ_SHORT 1024
+
+#define CASE_LOWER_BASE 8 /* base is lower case */
+#define CASE_LOWER_EXT 16 /* extension is lower case */
+
+#define SCAN_ANY 0 /* either hidden or not */
+#define SCAN_HID 1 /* only hidden */
+#define SCAN_NOTHID 2 /* only not hidden */
+#define SCAN_NOTANY 3 /* test name, then use SCAN_HID or SCAN_NOTHID */
+
+#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
+#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG || \
+ *(const unsigned char *) (n) == FD_FILL_BYTE)
+
+#define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)
+ /* valid file mode bits */
+
+#define MSDOS_SB(s) (&((s)->u.msdos_sb))
+#define MSDOS_I(i) (&((i)->u.msdos_i))
+
+#define MSDOS_NAME 11 /* maximum name length */
+#define MSDOS_LONGNAME 256 /* maximum name length */
+#define MSDOS_SLOTS 21 /* max # of slots needed for short and long names */
+#define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */
+#define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */
+
+#define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */
+
+#define EOF_FAT12 0xFF8 /* standard EOF */
+#define EOF_FAT16 0xFFF8
+#define EOF_FAT32 0xFFFFFF8
+#define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
+ MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
+
+/*
+ * Inode flags
+ */
+#define FAT_BINARY_FL 0x00000001 /* File contains binary data */
+
+/*
+ * ioctl commands
+ */
+#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
+#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
+
+/*
+ * Conversion from and to little-endian byte order. (no-op on i386/i486)
+ *
+ * Naming: Ca_b_c, where a: F = from, T = to, b: LE = little-endian,
+ * BE = big-endian, c: W = word (16 bits), L = longword (32 bits)
+ */
+
+#define CF_LE_W(v) le16_to_cpu(v)
+#define CF_LE_L(v) le32_to_cpu(v)
+#define CT_LE_W(v) cpu_to_le16(v)
+#define CT_LE_L(v) cpu_to_le32(v)
+
+struct fat_boot_sector {
+ __s8 ignored[3]; /* Boot strap short or near jump */
+ __s8 system_id[8]; /* Name - can be used to special case
+ partition manager volumes */
+ __u8 sector_size[2]; /* bytes per logical sector */
+ __u8 cluster_size; /* sectors/cluster */
+ __u16 reserved; /* reserved sectors */
+ __u8 fats; /* number of FATs */
+ __u8 dir_entries[2]; /* root directory entries */
+ __u8 sectors[2]; /* number of sectors */
+ __u8 media; /* media code (unused) */
+ __u16 fat_length; /* sectors/FAT */
+ __u16 secs_track; /* sectors per track */
+ __u16 heads; /* number of heads */
+ __u32 hidden; /* hidden sectors (unused) */
+ __u32 total_sect; /* number of sectors (if sectors == 0) */
+
+ /* The following fields are only used by FAT32 */
+ __u32 fat32_length; /* sectors/FAT */
+ __u16 flags; /* bit 8: fat mirroring, low 4: active fat */
+ __u8 version[2]; /* major, minor filesystem version */
+ __u32 root_cluster; /* first cluster in root directory */
+ __u16 info_sector; /* filesystem info sector */
+ __u16 backup_boot; /* backup boot sector */
+ __u16 reserved2[6]; /* Unused */
+};
+
+struct fat_boot_fsinfo {
+ __u32 reserved1; /* Nothing as far as I can tell */
+ __u32 signature; /* 0x61417272L */
+ __u32 free_clusters; /* Free cluster count. -1 if unknown */
+ __u32 next_cluster; /* Most recently allocated cluster.
+ * Unused under Linux. */
+ __u32 reserved2[4];
+};
+
+struct msdos_dir_entry {
+ __s8 name[8],ext[3]; /* name and extension */
+ __u8 attr; /* attribute bits */
+ __u8 lcase; /* Case for base and extension */
+ __u8 ctime_ms; /* Creation time, milliseconds */
+ __u16 ctime; /* Creation time */
+ __u16 cdate; /* Creation date */
+ __u16 adate; /* Last access date */
+ __u16 starthi; /* High 16 bits of cluster in FAT32 */
+ __u16 time,date,start;/* time, date and first cluster */
+ __u32 size; /* file size (in bytes) */
+};
+
+/* Up to 13 characters of the name */
+struct msdos_dir_slot {
+ __u8 id; /* sequence number for slot */
+ __u8 name0_4[10]; /* first 5 characters in name */
+ __u8 attr; /* attribute byte */
+ __u8 reserved; /* always 0 */
+ __u8 alias_checksum; /* checksum for 8.3 alias */
+ __u8 name5_10[12]; /* 6 more characters in name */
+ __u16 start; /* starting cluster number, 0 in long slots */
+ __u8 name11_12[4]; /* last 2 characters in name */
+};
+
+struct vfat_slot_info {
+ int is_long; /* was the found entry long */
+ int long_slots; /* number of long slots in filename */
+ int total_slots; /* total slots (long and short) */
+ loff_t longname_offset; /* dir offset for longname start */
+ loff_t shortname_offset; /* dir offset for shortname start */
+ int ino; /* ino for the file */
+};
+
+/* Determine whether this FS has kB-aligned data. */
+#define MSDOS_CAN_BMAP(mib) (!(((mib)->cluster_size & 1) || \
+ ((mib)->data_start & 1)))
+
+/* Convert attribute bits and a mask to the UNIX mode. */
+#define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO))
+
+/* Convert the UNIX mode to MS-DOS attribute bits. */
+#define MSDOS_MKATTR(m) ((m & S_IWUGO) ? ATTR_NONE : ATTR_RO)
+
+
+#ifdef __KERNEL__
+
+struct fat_cache {
+ kdev_t device; /* device number. 0 means unused. */
+ int start_cluster; /* first cluster of the chain. */
+ int file_cluster; /* cluster number in the file. */
+ int disk_cluster; /* cluster number on disk. */
+ struct fat_cache *next; /* next cache entry */
+};
+
+/* misc.c */
+extern int fat_is_binary(char conversion,char *extension);
+extern void lock_fat(struct super_block *sb);
+extern void unlock_fat(struct super_block *sb);
+extern int fat_add_cluster(struct inode *inode);
+extern struct buffer_head *fat_add_cluster1(struct inode *inode);
+extern int date_dos2unix(__u16 time, __u16 date);
+extern void fat_fs_panic(struct super_block *s,const char *msg);
+extern void fat_lock_creation(void);
+extern void fat_unlock_creation(void);
+extern void fat_date_unix2dos(int unix_date,__u16 *time, __u16 *date);
+extern int fat__get_entry(struct inode *dir,loff_t *pos,struct buffer_head **bh,
+ struct msdos_dir_entry **de,int *ino);
+static __inline__ int fat_get_entry(struct inode *dir,loff_t *pos,
+ struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
+{
+ /* Fast stuff first */
+ if (*bh && *de &&
+ (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_DPB-1) {
+ *pos += sizeof(struct msdos_dir_entry);
+ (*de)++;
+ (*ino)++;
+ return 0;
+ }
+ return fat__get_entry(dir,pos,bh,de,ino);
+}
+extern int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
+ struct msdos_dir_entry **res_de,int *ino);
+extern int fat_parent_ino(struct inode *dir,int locked);
+extern int fat_subdirs(struct inode *dir);
+void fat_clusters_flush(struct super_block *sb);
+
+/* fat.c */
+extern int fat_access(struct super_block *sb,int nr,int new_value);
+extern int fat_smap(struct inode *inode,int sector);
+extern int fat_free(struct inode *inode,int skip);
+void fat_cache_inval_inode(struct inode *inode);
+void fat_cache_inval_dev(kdev_t device);
+extern void fat_cache_init(void);
+void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu);
+void fat_cache_add(struct inode *inode,int f_clu,int d_clu);
+int fat_get_cluster(struct inode *inode,int cluster);
+
+/* inode.c */
+extern void fat_hash_init(void);
+extern int fat_bmap(struct inode *inode,int block);
+extern int fat_notify_change(struct dentry *, struct iattr *);
+extern void fat_clear_inode(struct inode *inode);
+extern void fat_delete_inode(struct inode *inode);
+extern void fat_put_super(struct super_block *sb);
+extern void fat_attach(struct inode *inode, int ino);
+extern void fat_detach(struct inode *inode);
+extern struct inode *fat_iget(struct super_block*,int);
+extern struct inode *fat_build_inode(struct super_block*,struct msdos_dir_entry*,int,int*);
+extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent, struct inode_operations *dir_ops);
+extern void msdos_put_super(struct super_block *sb);
+extern int fat_statfs(struct super_block *sb,struct statfs *buf, int);
+extern void fat_write_inode(struct inode *inode);
+
+/* dir.c */
+extern struct file_operations fat_dir_operations;
+extern int fat_search_long(struct inode *dir, const char *name, int len,
+ int anycase, loff_t *spos, loff_t *lpos);
+extern int fat_readdir(struct file *filp,
+ void *dirent, filldir_t);
+extern int fat_dir_ioctl(struct inode * inode, struct file * filp,
+ unsigned int cmd, unsigned long arg);
+int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
+ struct msdos_dir_entry **de, int *ino);
+int fat_dir_empty(struct inode *dir);
+
+/* file.c */
+extern struct inode_operations fat_file_inode_operations;
+extern struct inode_operations fat_file_inode_operations_1024;
+extern struct inode_operations fat_file_inode_operations_readpage;
+extern ssize_t fat_file_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t fat_file_write(struct file *, const char *, size_t, loff_t *);
+extern void fat_truncate(struct inode *inode);
+
+/* mmap.c */
+extern int fat_mmap(struct file *, struct vm_area_struct *);
+extern int fat_readpage(struct file *, struct page *);
+
+
+/* vfat.c */
+extern int init_vfat_fs(void);
+
+
+/* msdosfs_syms.c */
+extern int init_msdos_fs(void);
+extern struct file_system_type msdos_fs_type;
+
+/* msdos.c */
+extern struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent);
+
+/* msdos.c - these are for Umsdos */
+extern void msdos_read_inode(struct inode *inode);
+extern struct dentry *msdos_lookup(struct inode *dir,struct dentry *);
+extern int msdos_create(struct inode *dir,struct dentry *dentry,int mode);
+extern int msdos_rmdir(struct inode *dir,struct dentry *dentry);
+extern int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode);
+extern int msdos_unlink(struct inode *dir,struct dentry *dentry);
+extern int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
+ struct inode *new_dir,struct dentry *new_dentry);
+
+/* nls.c */
+extern int init_fat_nls(void);
+extern struct fat_nls_table *fat_load_nls(int codepage);
+
+/* tables.c */
+extern unsigned char fat_uni2esc[];
+extern unsigned char fat_esc2uni[];
+
+/* fatfs_syms.c */
+extern int init_fat_fs(void);
+extern void cleanup_fat_fs(void);
+
+/* nls.c */
+extern int fat_register_nls(struct fat_nls_table * fmt);
+extern int fat_unregister_nls(struct fat_nls_table * fmt);
+extern struct fat_nls_table *fat_find_nls(int codepage);
+extern struct fat_nls_table *fat_load_nls(int codepage);
+extern void fat_unload_nls(int codepage);
+extern int init_fat_nls(void);
+
+/* vfat/namei.c - these are for dmsdos */
+extern int vfat_create(struct inode *dir,struct dentry *dentry,int mode);
+extern int vfat_unlink(struct inode *dir,struct dentry *dentry);
+extern int vfat_mkdir(struct inode *dir,struct dentry *dentry,int mode);
+extern int vfat_rmdir(struct inode *dir,struct dentry *dentry);
+extern int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
+ struct inode *new_dir,struct dentry *new_dentry);
+extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
+ int silent);
+extern void vfat_read_inode(struct inode *inode);
+extern struct dentry *vfat_lookup(struct inode *dir,struct dentry *);
+
+/* vfat/vfatfs_syms.c */
+extern struct file_system_type vfat_fs_type;
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/msdos_fs_i.h b/pfinet/linux-src/include/linux/msdos_fs_i.h
new file mode 100644
index 00000000..929de3db
--- /dev/null
+++ b/pfinet/linux-src/include/linux/msdos_fs_i.h
@@ -0,0 +1,39 @@
+#ifndef _MSDOS_FS_I
+#define _MSDOS_FS_I
+
+#ifndef _LINUX_PIPE_FS_I_H
+#include <linux/pipe_fs_i.h>
+#endif
+
+/*
+ * MS-DOS file system inode data in memory
+ */
+
+struct msdos_inode_info {
+ /*
+ UMSDOS manage special file and fifo as normal empty
+ msdos file. fifo inode processing conflict with msdos
+ processing. So I insert the pipe_inode_info so the
+ information does not overlap. This increases the size of
+ the msdos_inode_info, but the clear winner here is
+ the ext2_inode_info. So it does not change anything to
+ the total size of a struct inode.
+
+ I have not put it conditional. With the advent of loadable
+ file system drivers, it would be very easy to compile
+ a MS-DOS FS driver unaware of UMSDOS and then later to
+ load a (then incompatible) UMSDOS FS driver.
+ */
+ struct pipe_inode_info reserved;
+ int i_start; /* first cluster or 0 */
+ int i_logstart; /* logical first cluster */
+ int i_attrs; /* unused attribute bits */
+ int i_ctime_ms; /* unused change time in milliseconds */
+ int i_binary; /* file contains non-text data */
+ int i_location; /* on-disk position of directory entry or 0 */
+ struct inode *i_fat_inode; /* struct inode of this one */
+ struct list_head i_fat_hash; /* hash by i_location */
+ off_t i_last_pos;/* position of last lookup */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/msdos_fs_sb.h b/pfinet/linux-src/include/linux/msdos_fs_sb.h
new file mode 100644
index 00000000..ae86a980
--- /dev/null
+++ b/pfinet/linux-src/include/linux/msdos_fs_sb.h
@@ -0,0 +1,59 @@
+#ifndef _MSDOS_FS_SB
+#define _MSDOS_FS_SB
+#include<linux/fat_cvf.h>
+
+/*
+ * MS-DOS file system in-core superblock data
+ */
+
+struct fat_mount_options {
+ uid_t fs_uid;
+ gid_t fs_gid;
+ unsigned short fs_umask;
+ unsigned short codepage; /* Codepage for shortname conversions */
+ char *iocharset; /* Charset used for filename input/display */
+ unsigned char name_check; /* r = relaxed, n = normal, s = strict */
+ unsigned char conversion; /* b = binary, t = text, a = auto */
+ unsigned quiet:1, /* set = fake successful chmods and chowns */
+ showexec:1, /* set = only set x bit for com/exe/bat */
+ sys_immutable:1, /* set = system files are immutable */
+ dotsOK:1, /* set = hidden and system files are named '.filename' */
+ isvfat:1, /* 0=no vfat long filename support, 1=vfat support */
+ utf8:1, /* Use of UTF8 character set (Default) */
+ unicode_xlate:1, /* create escape sequences for unhandled Unicode */
+ posixfs:1, /* Allow names like makefile and Makefile to coexist */
+ numtail:1, /* Does first alias have a numeric '~1' type tail? */
+ atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */
+ fat32:1; /* Is this a FAT32 partition? */
+};
+
+struct vfat_unicode {
+ unsigned char uni1;
+ unsigned char uni2;
+};
+
+struct msdos_sb_info {
+ unsigned short cluster_size; /* sectors/cluster */
+ unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
+ unsigned short fat_start;
+ unsigned long fat_length; /* FAT start & length (sec.) */
+ unsigned long dir_start;
+ unsigned short dir_entries; /* root dir start & entries */
+ unsigned long data_start; /* first data sector */
+ unsigned long clusters; /* number of clusters */
+ unsigned long root_cluster; /* first cluster of the root directory */
+ unsigned long fsinfo_offset; /* FAT32 fsinfo offset from start of disk */
+ struct wait_queue *fat_wait;
+ int fat_lock;
+ int prev_free; /* previously returned free cluster number */
+ int free_clusters; /* -1 if undefined */
+ struct fat_mount_options options;
+ struct nls_table *nls_disk; /* Codepage used on disk */
+ struct nls_table *nls_io; /* Charset used for input and display */
+ struct cvf_format* cvf_format;
+ void *dir_ops; /* Opaque; default directory operations */
+ void (*put_super_callback)(struct super_block *);
+ void *private_data;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/msg.h b/pfinet/linux-src/include/linux/msg.h
new file mode 100644
index 00000000..0312b5de
--- /dev/null
+++ b/pfinet/linux-src/include/linux/msg.h
@@ -0,0 +1,81 @@
+#ifndef _LINUX_MSG_H
+#define _LINUX_MSG_H
+
+#include <linux/ipc.h>
+
+/* ipcs ctl commands */
+#define MSG_STAT 11
+#define MSG_INFO 12
+
+/* msgrcv options */
+#define MSG_NOERROR 010000 /* no error if message is too big */
+#define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/
+
+/* one msqid structure for each queue on the system */
+struct msqid_ds {
+ struct ipc_perm msg_perm;
+ struct msg *msg_first; /* first message on queue */
+ struct msg *msg_last; /* last message in queue */
+ __kernel_time_t msg_stime; /* last msgsnd time */
+ __kernel_time_t msg_rtime; /* last msgrcv time */
+ __kernel_time_t msg_ctime; /* last change time */
+ struct wait_queue *wwait;
+ struct wait_queue *rwait;
+ unsigned short msg_cbytes; /* current number of bytes on queue */
+ unsigned short msg_qnum; /* number of messages in queue */
+ unsigned short msg_qbytes; /* max number of bytes on queue */
+ __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */
+};
+
+/* message buffer for msgsnd and msgrcv calls */
+struct msgbuf {
+ long mtype; /* type of message */
+ char mtext[1]; /* message text */
+};
+
+/* buffer for msgctl calls IPC_INFO, MSG_INFO */
+struct msginfo {
+ int msgpool;
+ int msgmap;
+ int msgmax;
+ int msgmnb;
+ int msgmni;
+ int msgssz;
+ int msgtql;
+ unsigned short msgseg;
+};
+
+#define MSGMNI 128 /* <= 1K */ /* max # of msg queue identifiers */
+#define MSGMAX 4056 /* <= 4056 */ /* max size of message (bytes) */
+#define MSGMNB 16384 /* ? */ /* default max size of a message queue */
+#define MSGQNUM 1024 /* <=65535 */ /* Max messages in flight / queue */
+
+/* unused */
+#define MSGPOOL (MSGMNI*MSGMNB/1024) /* size in kilobytes of message pool */
+#define MSGTQL MSGMNB /* number of system message headers */
+#define MSGMAP MSGMNB /* number of entries in message map */
+#define MSGSSZ 16 /* message segment size */
+#define __MSGSEG ((MSGPOOL*1024)/ MSGSSZ) /* max no. of segments */
+#define MSGSEG (__MSGSEG <= 0xffff ? __MSGSEG : 0xffff)
+
+#ifdef __KERNEL__
+
+/* one msg structure for each message */
+struct msg {
+ struct msg *msg_next; /* next message on queue */
+ long msg_type;
+ char *msg_spot; /* message text address */
+ time_t msg_stime; /* msgsnd time */
+ short msg_ts; /* message text size */
+};
+
+asmlinkage int sys_msgget (key_t key, int msgflg);
+asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
+asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp,
+ int msgflg);
+asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_MSG_H */
diff --git a/pfinet/linux-src/include/linux/mtio.h b/pfinet/linux-src/include/linux/mtio.h
new file mode 100644
index 00000000..c794ed89
--- /dev/null
+++ b/pfinet/linux-src/include/linux/mtio.h
@@ -0,0 +1,373 @@
+/*
+ * linux/mtio.h header file for Linux. Written by H. Bergman
+ *
+ * Modified for special ioctls provided by zftape in September 1997
+ * by C.-J. Heine.
+ */
+
+#ifndef _LINUX_MTIO_H
+#define _LINUX_MTIO_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/qic117.h>
+
+/*
+ * Structures and definitions for mag tape io control commands
+ */
+
+/* structure for MTIOCTOP - mag tape op command */
+struct mtop {
+ short mt_op; /* operations defined below */
+ int mt_count; /* how many of them */
+};
+
+/* Magnetic Tape operations [Not all operations supported by all drivers]: */
+#define MTRESET 0 /* +reset drive in case of problems */
+#define MTFSF 1 /* forward space over FileMark,
+ * position at first record of next file
+ */
+#define MTBSF 2 /* backward space FileMark (position before FM) */
+#define MTFSR 3 /* forward space record */
+#define MTBSR 4 /* backward space record */
+#define MTWEOF 5 /* write an end-of-file record (mark) */
+#define MTREW 6 /* rewind */
+#define MTOFFL 7 /* rewind and put the drive offline (eject?) */
+#define MTNOP 8 /* no op, set status only (read with MTIOCGET) */
+#define MTRETEN 9 /* retension tape */
+#define MTBSFM 10 /* +backward space FileMark, position at FM */
+#define MTFSFM 11 /* +forward space FileMark, position at FM */
+#define MTEOM 12 /* goto end of recorded media (for appending files).
+ * MTEOM positions after the last FM, ready for
+ * appending another file.
+ */
+#define MTERASE 13 /* erase tape -- be careful! */
+
+#define MTRAS1 14 /* run self test 1 (nondestructive) */
+#define MTRAS2 15 /* run self test 2 (destructive) */
+#define MTRAS3 16 /* reserved for self test 3 */
+
+#define MTSETBLK 20 /* set block length (SCSI) */
+#define MTSETDENSITY 21 /* set tape density (SCSI) */
+#define MTSEEK 22 /* seek to block (Tandberg, etc.) */
+#define MTTELL 23 /* tell block (Tandberg, etc.) */
+#define MTSETDRVBUFFER 24 /* set the drive buffering according to SCSI-2 */
+ /* ordinary buffered operation with code 1 */
+#define MTFSS 25 /* space forward over setmarks */
+#define MTBSS 26 /* space backward over setmarks */
+#define MTWSM 27 /* write setmarks */
+
+#define MTLOCK 28 /* lock the drive door */
+#define MTUNLOCK 29 /* unlock the drive door */
+#define MTLOAD 30 /* execute the SCSI load command */
+#define MTUNLOAD 31 /* execute the SCSI unload command */
+#define MTCOMPRESSION 32/* control compression with SCSI mode page 15 */
+#define MTSETPART 33 /* Change the active tape partition */
+#define MTMKPART 34 /* Format the tape with one or two partitions */
+
+/* structure for MTIOCGET - mag tape get status command */
+
+struct mtget {
+ long mt_type; /* type of magtape device */
+ long mt_resid; /* residual count: (not sure)
+ * number of bytes ignored, or
+ * number of files not skipped, or
+ * number of records not skipped.
+ */
+ /* the following registers are device dependent */
+ long mt_dsreg; /* status register */
+ long mt_gstat; /* generic (device independent) status */
+ long mt_erreg; /* error register */
+ /* The next two fields are not always used */
+ __kernel_daddr_t mt_fileno; /* number of current file on tape */
+ __kernel_daddr_t mt_blkno; /* current block number */
+};
+
+
+
+/*
+ * Constants for mt_type. Not all of these are supported,
+ * and these are not all of the ones that are supported.
+ */
+#define MT_ISUNKNOWN 0x01
+#define MT_ISQIC02 0x02 /* Generic QIC-02 tape streamer */
+#define MT_ISWT5150 0x03 /* Wangtek 5150EQ, QIC-150, QIC-02 */
+#define MT_ISARCHIVE_5945L2 0x04 /* Archive 5945L-2, QIC-24, QIC-02? */
+#define MT_ISCMSJ500 0x05 /* CMS Jumbo 500 (QIC-02?) */
+#define MT_ISTDC3610 0x06 /* Tandberg 6310, QIC-24 */
+#define MT_ISARCHIVE_VP60I 0x07 /* Archive VP60i, QIC-02 */
+#define MT_ISARCHIVE_2150L 0x08 /* Archive Viper 2150L */
+#define MT_ISARCHIVE_2060L 0x09 /* Archive Viper 2060L */
+#define MT_ISARCHIVESC499 0x0A /* Archive SC-499 QIC-36 controller */
+#define MT_ISQIC02_ALL_FEATURES 0x0F /* Generic QIC-02 with all features */
+#define MT_ISWT5099EEN24 0x11 /* Wangtek 5099-een24, 60MB, QIC-24 */
+#define MT_ISTEAC_MT2ST 0x12 /* Teac MT-2ST 155mb drive, Teac DC-1 card (Wangtek type) */
+#define MT_ISEVEREX_FT40A 0x32 /* Everex FT40A (QIC-40) */
+#define MT_ISDDS1 0x51 /* DDS device without partitions */
+#define MT_ISDDS2 0x52 /* DDS device with partitions */
+#define MT_ISSCSI1 0x71 /* Generic ANSI SCSI-1 tape unit */
+#define MT_ISSCSI2 0x72 /* Generic ANSI SCSI-2 tape unit */
+
+/* QIC-40/80/3010/3020 ftape supported drives.
+ * 20bit vendor ID + 0x800000 (see ftape-vendors.h)
+ */
+#define MT_ISFTAPE_UNKNOWN 0x800000 /* obsolete */
+#define MT_ISFTAPE_FLAG 0x800000
+
+struct mt_tape_info {
+ long t_type; /* device type id (mt_type) */
+ char *t_name; /* descriptive name */
+};
+
+#define MT_TAPE_INFO { \
+ {MT_ISUNKNOWN, "Unknown type of tape device"}, \
+ {MT_ISQIC02, "Generic QIC-02 tape streamer"}, \
+ {MT_ISWT5150, "Wangtek 5150, QIC-150"}, \
+ {MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, \
+ {MT_ISCMSJ500, "CMS Jumbo 500"}, \
+ {MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \
+ {MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \
+ {MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \
+ {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \
+ {MT_ISARCHIVESC499, "Archive SC-499 QIC-36 controller"}, \
+ {MT_ISQIC02_ALL_FEATURES, "Generic QIC-02 tape, all features"}, \
+ {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \
+ {MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \
+ {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \
+ {MT_ISSCSI1, "Generic SCSI-1 tape"}, \
+ {MT_ISSCSI2, "Generic SCSI-2 tape"}, \
+ {0, NULL} \
+}
+
+
+/* structure for MTIOCPOS - mag tape get position command */
+
+struct mtpos {
+ long mt_blkno; /* current block number */
+};
+
+
+/* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended
+ * as an interim solution for QIC-02 until DDI is fully implemented.
+ */
+struct mtconfiginfo {
+ long mt_type; /* drive type */
+ long ifc_type; /* interface card type */
+ unsigned short irqnr; /* IRQ number to use */
+ unsigned short dmanr; /* DMA channel to use */
+ unsigned short port; /* IO port base address */
+
+ unsigned long debug; /* debugging flags */
+
+ unsigned have_dens:1;
+ unsigned have_bsf:1;
+ unsigned have_fsr:1;
+ unsigned have_bsr:1;
+ unsigned have_eod:1;
+ unsigned have_seek:1;
+ unsigned have_tell:1;
+ unsigned have_ras1:1;
+ unsigned have_ras2:1;
+ unsigned have_ras3:1;
+ unsigned have_qfa:1;
+
+ unsigned pad1:5;
+ char reserved[10];
+};
+
+/* structure for MTIOCVOLINFO, query information about the volume
+ * currently positioned at (zftape)
+ */
+struct mtvolinfo {
+ unsigned int mt_volno; /* vol-number */
+ unsigned int mt_blksz; /* blocksize used when recording */
+ unsigned int mt_rawsize; /* raw tape space consumed, in kb */
+ unsigned int mt_size; /* volume size after decompression, in kb */
+ unsigned int mt_cmpr:1; /* this volume has been compressed */
+};
+
+/* raw access to a floppy drive, read and write an arbitrary segment.
+ * For ftape/zftape to support formatting etc.
+ */
+#define MT_FT_RD_SINGLE 0
+#define MT_FT_RD_AHEAD 1
+#define MT_FT_WR_ASYNC 0 /* start tape only when all buffers are full */
+#define MT_FT_WR_MULTI 1 /* start tape, continue until buffers are empty */
+#define MT_FT_WR_SINGLE 2 /* write a single segment and stop afterwards */
+#define MT_FT_WR_DELETE 3 /* write deleted data marks, one segment at time */
+
+struct mtftseg
+{
+ unsigned mt_segno; /* the segment to read or write */
+ unsigned mt_mode; /* modes for read/write (sync/async etc.) */
+ int mt_result; /* result of r/w request, not of the ioctl */
+ void *mt_data; /* User space buffer: must be 29kb */
+};
+
+/* get tape capacity (ftape/zftape)
+ */
+struct mttapesize {
+ unsigned long mt_capacity; /* entire, uncompressed capacity
+ * of a cartridge
+ */
+ unsigned long mt_used; /* what has been used so far, raw
+ * uncompressed amount
+ */
+};
+
+/* possible values of the ftfmt_op field
+ */
+#define FTFMT_SET_PARMS 1 /* set software parms */
+#define FTFMT_GET_PARMS 2 /* get software parms */
+#define FTFMT_FORMAT_TRACK 3 /* start formatting a tape track */
+#define FTFMT_STATUS 4 /* monitor formatting a tape track */
+#define FTFMT_VERIFY 5 /* verify the given segment */
+
+struct ftfmtparms {
+ unsigned char ft_qicstd; /* QIC-40/QIC-80/QIC-3010/QIC-3020 */
+ unsigned char ft_fmtcode; /* Refer to the QIC specs */
+ unsigned char ft_fhm; /* floppy head max */
+ unsigned char ft_ftm; /* floppy track max */
+ unsigned short ft_spt; /* segments per track */
+ unsigned short ft_tpc; /* tracks per cartridge */
+};
+
+struct ftfmttrack {
+ unsigned int ft_track; /* track to format */
+ unsigned char ft_gap3; /* size of gap3, for FORMAT_TRK */
+};
+
+struct ftfmtstatus {
+ unsigned int ft_segment; /* segment currently being formatted */
+};
+
+struct ftfmtverify {
+ unsigned int ft_segment; /* segment to verify */
+ unsigned long ft_bsm; /* bsm as result of VERIFY cmd */
+};
+
+struct mtftformat {
+ unsigned int fmt_op; /* operation to perform */
+ union fmt_arg {
+ struct ftfmtparms fmt_parms; /* format parameters */
+ struct ftfmttrack fmt_track; /* ctrl while formatting */
+ struct ftfmtstatus fmt_status;
+ struct ftfmtverify fmt_verify; /* for verifying */
+ } fmt_arg;
+};
+
+struct mtftcmd {
+ unsigned int ft_wait_before; /* timeout to wait for drive to get ready
+ * before command is sent. Milliseconds
+ */
+ qic117_cmd_t ft_cmd; /* command to send */
+ unsigned char ft_parm_cnt; /* zero: no parm is sent. */
+ unsigned char ft_parms[3]; /* parameter(s) to send to
+ * the drive. The parms are nibbles
+ * driver sends cmd + 2 step pulses */
+ unsigned int ft_result_bits; /* if non zero, number of bits
+ * returned by the tape drive
+ */
+ unsigned int ft_result; /* the result returned by the tape drive*/
+ unsigned int ft_wait_after; /* timeout to wait for drive to get ready
+ * after command is sent. 0: don't wait */
+ int ft_status; /* status returned by ready wait
+ * undefined if timeout was 0.
+ */
+ int ft_error; /* error code if error status was set by
+ * command
+ */
+};
+
+/* mag tape io control commands */
+#define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */
+#define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */
+#define MTIOCPOS _IOR('m', 3, struct mtpos) /* get tape position */
+
+/* The next two are used by the QIC-02 driver for runtime reconfiguration.
+ * See tpqic02.h for struct mtconfiginfo.
+ */
+#define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) /* get tape config */
+#define MTIOCSETCONFIG _IOW('m', 5, struct mtconfiginfo) /* set tape config */
+
+/* the next six are used by the floppy ftape drivers and its frontends
+ * sorry, but MTIOCTOP commands are write only.
+ */
+#define MTIOCRDFTSEG _IOWR('m', 6, struct mtftseg) /* read a segment */
+#define MTIOCWRFTSEG _IOWR('m', 7, struct mtftseg) /* write a segment */
+#define MTIOCVOLINFO _IOR('m', 8, struct mtvolinfo) /* info about volume */
+#define MTIOCGETSIZE _IOR('m', 9, struct mttapesize)/* get cartridge size*/
+#define MTIOCFTFORMAT _IOWR('m', 10, struct mtftformat) /* format ftape */
+#define MTIOCFTCMD _IOWR('m', 11, struct mtftcmd) /* send QIC-117 cmd */
+
+/* Generic Mag Tape (device independent) status macros for examining
+ * mt_gstat -- HP-UX compatible.
+ * There is room for more generic status bits here, but I don't
+ * know which of them are reserved. At least three or so should
+ * be added to make this really useful.
+ */
+#define GMT_EOF(x) ((x) & 0x80000000)
+#define GMT_BOT(x) ((x) & 0x40000000)
+#define GMT_EOT(x) ((x) & 0x20000000)
+#define GMT_SM(x) ((x) & 0x10000000) /* DDS setmark */
+#define GMT_EOD(x) ((x) & 0x08000000) /* DDS EOD */
+#define GMT_WR_PROT(x) ((x) & 0x04000000)
+/* #define GMT_ ? ((x) & 0x02000000) */
+#define GMT_ONLINE(x) ((x) & 0x01000000)
+#define GMT_D_6250(x) ((x) & 0x00800000)
+#define GMT_D_1600(x) ((x) & 0x00400000)
+#define GMT_D_800(x) ((x) & 0x00200000)
+/* #define GMT_ ? ((x) & 0x00100000) */
+/* #define GMT_ ? ((x) & 0x00080000) */
+#define GMT_DR_OPEN(x) ((x) & 0x00040000) /* door open (no tape) */
+/* #define GMT_ ? ((x) & 0x00020000) */
+#define GMT_IM_REP_EN(x) ((x) & 0x00010000) /* immediate report mode */
+/* 16 generic status bits unused */
+
+
+/* SCSI-tape specific definitions */
+/* Bitfield shifts in the status */
+#define MT_ST_BLKSIZE_SHIFT 0
+#define MT_ST_BLKSIZE_MASK 0xffffff
+#define MT_ST_DENSITY_SHIFT 24
+#define MT_ST_DENSITY_MASK 0xff000000
+
+#define MT_ST_SOFTERR_SHIFT 0
+#define MT_ST_SOFTERR_MASK 0xffff
+
+/* Bitfields for the MTSETDRVBUFFER ioctl */
+#define MT_ST_OPTIONS 0xf0000000
+#define MT_ST_BOOLEANS 0x10000000
+#define MT_ST_SETBOOLEANS 0x30000000
+#define MT_ST_CLEARBOOLEANS 0x40000000
+#define MT_ST_WRITE_THRESHOLD 0x20000000
+#define MT_ST_DEF_BLKSIZE 0x50000000
+#define MT_ST_DEF_OPTIONS 0x60000000
+#define MT_ST_TIMEOUTS 0x70000000
+#define MT_ST_SET_TIMEOUT (MT_ST_TIMEOUTS | 0x000000)
+#define MT_ST_SET_LONG_TIMEOUT (MT_ST_TIMEOUTS | 0x100000)
+
+#define MT_ST_BUFFER_WRITES 0x1
+#define MT_ST_ASYNC_WRITES 0x2
+#define MT_ST_READ_AHEAD 0x4
+#define MT_ST_DEBUGGING 0x8
+#define MT_ST_TWO_FM 0x10
+#define MT_ST_FAST_MTEOM 0x20
+#define MT_ST_AUTO_LOCK 0x40
+#define MT_ST_DEF_WRITES 0x80
+#define MT_ST_CAN_BSR 0x100
+#define MT_ST_NO_BLKLIMS 0x200
+#define MT_ST_CAN_PARTITIONS 0x400
+#define MT_ST_SCSI2LOGICAL 0x800
+#define MT_ST_SYSV 0x1000
+
+/* The mode parameters to be controlled. Parameter chosen with bits 20-28 */
+#define MT_ST_CLEAR_DEFAULT 0xfffff
+#define MT_ST_DEF_DENSITY (MT_ST_DEF_OPTIONS | 0x100000)
+#define MT_ST_DEF_COMPRESSION (MT_ST_DEF_OPTIONS | 0x200000)
+#define MT_ST_DEF_DRVBUFFER (MT_ST_DEF_OPTIONS | 0x300000)
+
+/* The offset for the arguments for the special HP changer load command. */
+#define MT_ST_HPLOADER_OFFSET 10000
+
+#endif /* _LINUX_MTIO_H */
diff --git a/pfinet/linux-src/include/linux/nbd.h b/pfinet/linux-src/include/linux/nbd.h
new file mode 100644
index 00000000..c2c0431f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nbd.h
@@ -0,0 +1,85 @@
+#ifndef LINUX_NBD_H
+#define LINUX_NBD_H
+
+#define NBD_SET_SOCK _IO( 0xab, 0 )
+#define NBD_SET_BLKSIZE _IO( 0xab, 1 )
+#define NBD_SET_SIZE _IO( 0xab, 2 )
+#define NBD_DO_IT _IO( 0xab, 3 )
+#define NBD_CLEAR_SOCK _IO( 0xab, 4 )
+#define NBD_CLEAR_QUE _IO( 0xab, 5 )
+#define NBD_PRINT_DEBUG _IO( 0xab, 6 )
+#define NBD_SET_SIZE_BLOCKS _IO( 0xab, 7 )
+
+#ifdef MAJOR_NR
+
+#include <linux/locks.h>
+#include <asm/semaphore.h>
+
+#define LOCAL_END_REQUEST
+
+#include <linux/blk.h>
+
+#ifdef PARANOIA
+extern int requests_in;
+extern int requests_out;
+#endif
+
+static void
+nbd_end_request(struct request *req)
+{
+#ifdef PARANOIA
+ requests_out++;
+#endif
+ if (end_that_request_first( req, !req->errors, "nbd" ))
+ return;
+ end_that_request_last( req );
+}
+
+#define MAX_NBD 128
+
+struct nbd_device {
+ int refcnt;
+ int flags;
+ int harderror; /* Code of hard error */
+#define NBD_READ_ONLY 0x0001
+#define NBD_WRITE_NOCHK 0x0002
+#define NBD_INITIALISED 0x0004
+ struct socket * sock;
+ struct file * file; /* If == NULL, device is not ready, yet */
+ int magic; /* FIXME: not if debugging is off */
+ struct request *head; /* Requests are added here... */
+ struct request *tail;
+ struct semaphore queue_lock;
+};
+#endif
+
+/* This now IS in some kind of include file... */
+
+/* These are send over network in request/reply magic field */
+
+#define NBD_REQUEST_MAGIC 0x25609513
+#define NBD_REPLY_MAGIC 0x67446698
+/* Do *not* use magics: 0x12560953 0x96744668. */
+
+/*
+ * This is packet used for communication between client and
+ * server. All data are in network byte order.
+ */
+struct nbd_request {
+ u32 magic;
+ u32 type; /* == READ || == WRITE */
+ char handle[8];
+ u64 from;
+ u32 len;
+}
+#ifdef __GNUC__
+ __attribute__ ((packed))
+#endif
+;
+
+struct nbd_reply {
+ u32 magic;
+ u32 error; /* 0 = ok, else error */
+ char handle[8]; /* handle you got from request */
+};
+#endif
diff --git a/pfinet/linux-src/include/linux/ncp.h b/pfinet/linux-src/include/linux/ncp.h
new file mode 100644
index 00000000..229618db
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ncp.h
@@ -0,0 +1,204 @@
+/*
+ * ncp.h
+ *
+ * Copyright (C) 1995 by Volker Lendecke
+ * Modified for sparc by J.F. Chadima
+ * Modified for __constant_ntoh by Frank A. Vorstenbosch
+ *
+ */
+
+#ifndef _LINUX_NCP_H
+#define _LINUX_NCP_H
+
+#include <linux/types.h>
+#include <linux/ipx.h>
+
+#define NCP_PTYPE (0x11)
+#define NCP_PORT (0x0451)
+
+#define NCP_ALLOC_SLOT_REQUEST (0x1111)
+#define NCP_REQUEST (0x2222)
+#define NCP_DEALLOC_SLOT_REQUEST (0x5555)
+
+struct ncp_request_header {
+ __u16 type __attribute__((packed));
+ __u8 sequence __attribute__((packed));
+ __u8 conn_low __attribute__((packed));
+ __u8 task __attribute__((packed));
+ __u8 conn_high __attribute__((packed));
+ __u8 function __attribute__((packed));
+ __u8 data[0] __attribute__((packed));
+};
+
+#define NCP_REPLY (0x3333)
+#define NCP_POSITIVE_ACK (0x9999)
+
+struct ncp_reply_header {
+ __u16 type __attribute__((packed));
+ __u8 sequence __attribute__((packed));
+ __u8 conn_low __attribute__((packed));
+ __u8 task __attribute__((packed));
+ __u8 conn_high __attribute__((packed));
+ __u8 completion_code __attribute__((packed));
+ __u8 connection_state __attribute__((packed));
+ __u8 data[0] __attribute__((packed));
+};
+
+#define NCP_VOLNAME_LEN (16)
+#define NCP_NUMBER_OF_VOLUMES (64)
+struct ncp_volume_info {
+ __u32 total_blocks;
+ __u32 free_blocks;
+ __u32 purgeable_blocks;
+ __u32 not_yet_purgeable_blocks;
+ __u32 total_dir_entries;
+ __u32 available_dir_entries;
+ __u8 sectors_per_block;
+ char volume_name[NCP_VOLNAME_LEN + 1];
+};
+
+/* these define the attribute byte as seen by NCP */
+#define aRONLY (ntohl(0x01000000))
+#define aHIDDEN (__constant_ntohl(0x02000000))
+#define aSYSTEM (__constant_ntohl(0x04000000))
+#define aEXECUTE (ntohl(0x08000000))
+#define aDIR (ntohl(0x10000000))
+#define aARCH (ntohl(0x20000000))
+#define aSHARED (ntohl(0x80000000))
+#define aDONTSUBALLOCATE (ntohl(1L<<(11+8)))
+#define aTRANSACTIONAL (ntohl(1L<<(12+8)))
+#define aPURGE (ntohl(1L<<(16-8)))
+#define aRENAMEINHIBIT (ntohl(1L<<(17-8)))
+#define aDELETEINHIBIT (ntohl(1L<<(18-8)))
+#define aDONTCOMPRESS (nothl(1L<<(27-24)))
+
+#define AR_READ (ntohs(0x0100))
+#define AR_WRITE (ntohs(0x0200))
+#define AR_EXCLUSIVE (ntohs(0x2000))
+
+#define NCP_FILE_ID_LEN 6
+
+/* Defines for Name Spaces */
+#define NW_NS_DOS 0
+#define NW_NS_MAC 1
+#define NW_NS_NFS 2
+#define NW_NS_FTAM 3
+#define NW_NS_OS2 4
+
+/* Defines for ReturnInformationMask */
+#define RIM_NAME (ntohl(0x01000000L))
+#define RIM_SPACE_ALLOCATED (ntohl(0x02000000L))
+#define RIM_ATTRIBUTES (ntohl(0x04000000L))
+#define RIM_DATA_SIZE (ntohl(0x08000000L))
+#define RIM_TOTAL_SIZE (ntohl(0x10000000L))
+#define RIM_EXT_ATTR_INFO (ntohl(0x20000000L))
+#define RIM_ARCHIVE (ntohl(0x40000000L))
+#define RIM_MODIFY (ntohl(0x80000000L))
+#define RIM_CREATION (ntohl(0x00010000L))
+#define RIM_OWNING_NAMESPACE (ntohl(0x00020000L))
+#define RIM_DIRECTORY (ntohl(0x00040000L))
+#define RIM_RIGHTS (ntohl(0x00080000L))
+#define RIM_ALL (ntohl(0xFF0F0000L))
+#define RIM_COMPRESSED_INFO (ntohl(0x00000080L))
+
+/* open/create modes */
+#define OC_MODE_OPEN 0x01
+#define OC_MODE_TRUNCATE 0x02
+#define OC_MODE_REPLACE 0x02
+#define OC_MODE_CREATE 0x08
+
+/* open/create results */
+#define OC_ACTION_NONE 0x00
+#define OC_ACTION_OPEN 0x01
+#define OC_ACTION_CREATE 0x02
+#define OC_ACTION_TRUNCATE 0x04
+#define OC_ACTION_REPLACE 0x04
+
+/* access rights attributes */
+#ifndef AR_READ_ONLY
+#define AR_READ_ONLY 0x0001
+#define AR_WRITE_ONLY 0x0002
+#define AR_DENY_READ 0x0004
+#define AR_DENY_WRITE 0x0008
+#define AR_COMPATIBILITY 0x0010
+#define AR_WRITE_THROUGH 0x0040
+#define AR_OPEN_COMPRESSED 0x0100
+#endif
+
+struct nw_info_struct {
+ __u32 spaceAlloc __attribute__((packed));
+ __u32 attributes __attribute__((packed));
+ __u16 flags __attribute__((packed));
+ __u32 dataStreamSize __attribute__((packed));
+ __u32 totalStreamSize __attribute__((packed));
+ __u16 numberOfStreams __attribute__((packed));
+ __u16 creationTime __attribute__((packed));
+ __u16 creationDate __attribute__((packed));
+ __u32 creatorID __attribute__((packed));
+ __u16 modifyTime __attribute__((packed));
+ __u16 modifyDate __attribute__((packed));
+ __u32 modifierID __attribute__((packed));
+ __u16 lastAccessDate __attribute__((packed));
+ __u16 archiveTime __attribute__((packed));
+ __u16 archiveDate __attribute__((packed));
+ __u32 archiverID __attribute__((packed));
+ __u16 inheritedRightsMask __attribute__((packed));
+ __u32 dirEntNum __attribute__((packed));
+ __u32 DosDirNum __attribute__((packed));
+ __u32 volNumber __attribute__((packed));
+ __u32 EADataSize __attribute__((packed));
+ __u32 EAKeyCount __attribute__((packed));
+ __u32 EAKeySize __attribute__((packed));
+ __u32 NSCreator __attribute__((packed));
+ __u8 nameLen __attribute__((packed));
+ __u8 entryName[256] __attribute__((packed));
+};
+
+/* modify mask - use with MODIFY_DOS_INFO structure */
+#define DM_ATTRIBUTES (ntohl(0x02000000L))
+#define DM_CREATE_DATE (ntohl(0x04000000L))
+#define DM_CREATE_TIME (ntohl(0x08000000L))
+#define DM_CREATOR_ID (ntohl(0x10000000L))
+#define DM_ARCHIVE_DATE (ntohl(0x20000000L))
+#define DM_ARCHIVE_TIME (ntohl(0x40000000L))
+#define DM_ARCHIVER_ID (ntohl(0x80000000L))
+#define DM_MODIFY_DATE (ntohl(0x00010000L))
+#define DM_MODIFY_TIME (ntohl(0x00020000L))
+#define DM_MODIFIER_ID (ntohl(0x00040000L))
+#define DM_LAST_ACCESS_DATE (ntohl(0x00080000L))
+#define DM_INHERITED_RIGHTS_MASK (ntohl(0x00100000L))
+#define DM_MAXIMUM_SPACE (ntohl(0x00200000L))
+
+struct nw_modify_dos_info {
+ __u32 attributes __attribute__((packed));
+ __u16 creationDate __attribute__((packed));
+ __u16 creationTime __attribute__((packed));
+ __u32 creatorID __attribute__((packed));
+ __u16 modifyDate __attribute__((packed));
+ __u16 modifyTime __attribute__((packed));
+ __u32 modifierID __attribute__((packed));
+ __u16 archiveDate __attribute__((packed));
+ __u16 archiveTime __attribute__((packed));
+ __u32 archiverID __attribute__((packed));
+ __u16 lastAccessDate __attribute__((packed));
+ __u16 inheritanceGrantMask __attribute__((packed));
+ __u16 inheritanceRevokeMask __attribute__((packed));
+ __u32 maximumSpace __attribute__((packed));
+};
+
+struct nw_file_info {
+ struct nw_info_struct i;
+ int opened;
+ int access;
+ __u32 server_file_handle __attribute__((packed));
+ __u8 open_create_action __attribute__((packed));
+ __u8 file_handle[6] __attribute__((packed));
+};
+
+struct nw_search_sequence {
+ __u8 volNumber __attribute__((packed));
+ __u32 dirBase __attribute__((packed));
+ __u32 sequence __attribute__((packed));
+};
+
+#endif /* _LINUX_NCP_H */
diff --git a/pfinet/linux-src/include/linux/ncp_fs.h b/pfinet/linux-src/include/linux/ncp_fs.h
new file mode 100644
index 00000000..9c5df534
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ncp_fs.h
@@ -0,0 +1,331 @@
+/*
+ * ncp_fs.h
+ *
+ * Copyright (C) 1995, 1996 by Volker Lendecke
+ *
+ */
+
+#ifndef _LINUX_NCP_FS_H
+#define _LINUX_NCP_FS_H
+
+#include <linux/fs.h>
+#include <linux/in.h>
+#include <linux/types.h>
+
+#include <linux/ncp_mount.h>
+
+/* NLS charsets by ioctl */
+#define NCP_IOCSNAME_LEN 20
+struct ncp_nls_ioctl
+{
+ unsigned char codepage[NCP_IOCSNAME_LEN+1];
+ unsigned char iocharset[NCP_IOCSNAME_LEN+1];
+};
+
+#include <linux/ncp_fs_sb.h>
+#include <linux/ncp_fs_i.h>
+
+/*
+ * ioctl commands
+ */
+
+struct ncp_ioctl_request {
+ unsigned int function;
+ unsigned int size;
+ char *data;
+};
+
+struct ncp_fs_info {
+ int version;
+ struct sockaddr_ipx addr;
+ __kernel_uid_t mounted_uid;
+ int connection; /* Connection number the server assigned us */
+ int buffer_size; /* The negotiated buffer size, to be
+ used for read/write requests! */
+
+ int volume_number;
+ __u32 directory_id;
+};
+
+struct ncp_sign_init
+{
+ char sign_root[8];
+ char sign_last[16];
+};
+
+struct ncp_lock_ioctl
+{
+#define NCP_LOCK_LOG 0
+#define NCP_LOCK_SH 1
+#define NCP_LOCK_EX 2
+#define NCP_LOCK_CLEAR 256
+ int cmd;
+ int origin;
+ unsigned int offset;
+ unsigned int length;
+#define NCP_LOCK_DEFAULT_TIMEOUT 18
+#define NCP_LOCK_MAX_TIMEOUT 180
+ int timeout;
+};
+
+struct ncp_setroot_ioctl
+{
+ int volNumber;
+ int namespace;
+ __u32 dirEntNum;
+};
+
+struct ncp_objectname_ioctl
+{
+#define NCP_AUTH_NONE 0x00
+#define NCP_AUTH_BIND 0x31
+#define NCP_AUTH_NDS 0x32
+ int auth_type;
+ size_t object_name_len;
+ void* object_name; /* an userspace data, in most cases user name */
+};
+
+struct ncp_privatedata_ioctl
+{
+ size_t len;
+ void* data; /* ~1000 for NDS */
+};
+
+#define NCP_IOC_NCPREQUEST _IOR('n', 1, struct ncp_ioctl_request)
+#define NCP_IOC_GETMOUNTUID _IOW('n', 2, __kernel_uid_t)
+
+#if 1
+#ifdef __KERNEL__
+/* remove after ncpfs-2.0.13 gets released or at the beginning of kernel-2.1. codefreeze */
+#define NCP_IOC_GETMOUNTUID_INT _IOW('n', 2, unsigned int)
+#endif
+#endif
+
+#define NCP_IOC_CONN_LOGGED_IN _IO('n', 3)
+
+#define NCP_GET_FS_INFO_VERSION (1)
+#define NCP_IOC_GET_FS_INFO _IOWR('n', 4, struct ncp_fs_info)
+
+#define NCP_IOC_SIGN_INIT _IOR('n', 5, struct ncp_sign_init)
+#define NCP_IOC_SIGN_WANTED _IOR('n', 6, int)
+#define NCP_IOC_SET_SIGN_WANTED _IOW('n', 6, int)
+
+#define NCP_IOC_LOCKUNLOCK _IOR('n', 7, struct ncp_lock_ioctl)
+
+#define NCP_IOC_GETROOT _IOW('n', 8, struct ncp_setroot_ioctl)
+#define NCP_IOC_SETROOT _IOR('n', 8, struct ncp_setroot_ioctl)
+
+#define NCP_IOC_GETOBJECTNAME _IOWR('n', 9, struct ncp_objectname_ioctl)
+#define NCP_IOC_SETOBJECTNAME _IOR('n', 9, struct ncp_objectname_ioctl)
+#define NCP_IOC_GETPRIVATEDATA _IOWR('n', 10, struct ncp_privatedata_ioctl)
+#define NCP_IOC_SETPRIVATEDATA _IOR('n', 10, struct ncp_privatedata_ioctl)
+
+#define NCP_IOC_GETCHARSETS _IOWR('n', 11, struct ncp_nls_ioctl)
+#define NCP_IOC_SETCHARSETS _IOR('n', 11, struct ncp_nls_ioctl)
+
+/*
+ * The packet size to allocate. One page should be enough.
+ */
+#define NCP_PACKET_SIZE 4070
+
+#define NCP_MAXPATHLEN 255
+#define NCP_MAXNAMELEN 14
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#undef NCPFS_PARANOIA
+#ifndef DEBUG_NCP
+#define DEBUG_NCP 0
+#endif
+#if DEBUG_NCP > 0
+#define DPRINTK(format, args...) printk(format , ## args)
+#else
+#define DPRINTK(format, args...)
+#endif
+
+#if DEBUG_NCP > 1
+#define DDPRINTK(format, args...) printk(format , ## args)
+#else
+#define DDPRINTK(format, args...)
+#endif
+
+/* The readdir cache size controls how many directory entries are
+ * cached.
+ */
+#define NCP_READDIR_CACHE_SIZE 64
+
+#define NCP_MAX_RPC_TIMEOUT (6*HZ)
+
+/*
+ * This is the ncpfs part of the inode structure. This must contain
+ * all the information we need to work with an inode after creation.
+ * (Move to ncp_fs_i.h once it stabilizes, and add a union in fs.h)
+ */
+struct ncpfs_i {
+ __u32 dirEntNum __attribute__((packed));
+ __u32 DosDirNum __attribute__((packed));
+ __u32 volNumber __attribute__((packed));
+#ifdef CONFIG_NCPFS_SMALLDOS
+ __u32 origNS;
+#endif
+#ifdef CONFIG_NCPFS_STRONG
+ __u32 nwattr;
+#endif
+ int opened;
+ int access;
+ __u32 server_file_handle __attribute__((packed));
+ __u8 open_create_action __attribute__((packed));
+ __u8 file_handle[6] __attribute__((packed));
+};
+
+/*
+ * This is an extension of the nw_file_info structure with
+ * the additional information we need to create an inode.
+ */
+struct ncpfs_inode_info {
+ ino_t ino; /* dummy inode number */
+ struct nw_file_info nw_info;
+};
+
+/* Guess, what 0x564c is :-) */
+#define NCP_SUPER_MAGIC 0x564c
+
+
+#define NCP_SBP(sb) ((struct ncp_server *)((sb)->u.generic_sbp))
+
+#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
+/* We don't have an ncpfs union yet, so use smbfs ... */
+#define NCP_FINFO(inode) ((struct ncpfs_i *)&((inode)->u.smbfs_i))
+
+#ifdef DEBUG_NCP_MALLOC
+
+#include <linux/malloc.h>
+
+extern int ncp_malloced;
+extern int ncp_current_malloced;
+
+static inline void *
+ ncp_kmalloc(unsigned int size, int priority)
+{
+ ncp_malloced += 1;
+ ncp_current_malloced += 1;
+ return kmalloc(size, priority);
+}
+
+static inline void ncp_kfree_s(void *obj, int size)
+{
+ ncp_current_malloced -= 1;
+ kfree_s(obj, size);
+}
+
+#else /* DEBUG_NCP_MALLOC */
+
+#define ncp_kmalloc(s,p) kmalloc(s,p)
+#define ncp_kfree_s(o,s) kfree_s(o,s)
+
+#endif /* DEBUG_NCP_MALLOC */
+
+/* linux/fs/ncpfs/inode.c */
+int ncp_notify_change(struct dentry *, struct iattr *attr);
+struct super_block *ncp_read_super(struct super_block *, void *, int);
+struct inode *ncp_iget(struct super_block *, struct ncpfs_inode_info *);
+void ncp_update_inode(struct inode *, struct nw_file_info *);
+void ncp_update_inode2(struct inode *, struct nw_file_info *);
+extern int init_ncp_fs(void);
+
+/* linux/fs/ncpfs/dir.c */
+extern struct inode_operations ncp_dir_inode_operations;
+int ncp_conn_logged_in(struct ncp_server *);
+void ncp_init_dir_cache(void);
+void ncp_invalid_dir_cache(struct inode *);
+void ncp_free_dir_cache(void);
+int ncp_date_dos2unix(__u16 time, __u16 date);
+void ncp_date_unix2dos(int unix_date, __u16 * time, __u16 * date);
+
+/* linux/fs/ncpfs/ioctl.c */
+int ncp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+/* linux/fs/ncpfs/sock.c */
+int ncp_request2(struct ncp_server *server, int function,
+ void* reply, int max_reply_size);
+static int inline ncp_request(struct ncp_server *server, int function) {
+ return ncp_request2(server, function, server->packet, server->packet_size);
+}
+int ncp_connect(struct ncp_server *server);
+int ncp_disconnect(struct ncp_server *server);
+void ncp_lock_server(struct ncp_server *server);
+void ncp_unlock_server(struct ncp_server *server);
+
+/* linux/fs/ncpfs/file.c */
+extern struct inode_operations ncp_file_inode_operations;
+int ncp_make_open(struct inode *, int);
+
+/* linux/fs/ncpfs/mmap.c */
+int ncp_mmap(struct file *, struct vm_area_struct *);
+
+/* linux/fs/ncpfs/ncplib_kernel.c */
+int ncp_make_closed(struct inode *);
+
+static inline void str_upper(char *name)
+{
+ while (*name) {
+ if (*name >= 'a' && *name <= 'z') {
+ *name -= ('a' - 'A');
+ }
+ name++;
+ }
+}
+
+static inline void str_lower(char *name)
+{
+ while (*name) {
+ if (*name >= 'A' && *name <= 'Z') {
+ *name += ('a' - 'A');
+ }
+ name++;
+ }
+}
+
+static inline int ncp_namespace(struct inode *inode)
+{
+ struct ncp_server *server = NCP_SERVER(inode);
+ return server->name_space[NCP_FINFO(inode)->volNumber];
+}
+
+static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator) {
+#if defined(CONFIG_NCPFS_NFS_NS) || defined(CONFIG_NCPFS_OS2_NS)
+ int ns = ncp_namespace(i);
+#endif
+#if defined(CONFIG_NCPFS_SMALLDOS) && defined(CONFIG_NCPFS_OS2_NS)
+ if ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
+ return 0;
+#endif
+ return
+#ifdef CONFIG_NCPFS_OS2_NS
+ (ns == NW_NS_OS2) ||
+#endif /* CONFIG_NCPFS_OS2_NS */
+#ifdef CONFIG_NCPFS_NFS_NS
+ (ns == NW_NS_NFS) ||
+#endif /* CONFIG_NCPFS_NFS_NS */
+ 0;
+}
+
+static inline int ncp_preserve_case(struct inode *i)
+{
+ return ncp_preserve_entry_case(i, NW_NS_OS2);
+}
+
+static inline int ncp_case_sensitive(struct inode *i)
+{
+#ifdef CONFIG_NCPFS_NFS_NS
+ return ncp_namespace(i) == NW_NS_NFS;
+#else
+ return 0;
+#endif /* CONFIG_NCPFS_NFS_NS */
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_NCP_FS_H */
diff --git a/pfinet/linux-src/include/linux/ncp_fs_i.h b/pfinet/linux-src/include/linux/ncp_fs_i.h
new file mode 100644
index 00000000..3df38b28
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ncp_fs_i.h
@@ -0,0 +1,36 @@
+/*
+ * ncp_fs_i.h
+ *
+ * Copyright (C) 1995 Volker Lendecke
+ *
+ */
+
+#ifndef _LINUX_NCP_FS_I
+#define _LINUX_NCP_FS_I
+
+#include <linux/ncp.h>
+
+#ifdef __KERNEL__
+
+enum ncp_inode_state {
+ NCP_INODE_VALID = 19, /* Inode currently in use */
+ NCP_INODE_LOOKED_UP, /* directly before iget */
+ NCP_INODE_CACHED, /* in a path to an inode which is in use */
+ NCP_INODE_INVALID
+};
+
+/*
+ * ncp fs inode data (in memory only)
+ */
+struct ncp_inode_info {
+ enum ncp_inode_state state;
+ int nused; /* for directories:
+ number of references in memory */
+ struct ncp_inode_info *dir;
+ struct ncp_inode_info *next, *prev;
+ struct inode *inode;
+ struct nw_file_info finfo;
+};
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/ncp_fs_sb.h b/pfinet/linux-src/include/linux/ncp_fs_sb.h
new file mode 100644
index 00000000..43f902be
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ncp_fs_sb.h
@@ -0,0 +1,96 @@
+/*
+ * ncp_fs_sb.h
+ *
+ * Copyright (C) 1995, 1996 by Volker Lendecke
+ *
+ */
+
+#ifndef _NCP_FS_SB
+#define _NCP_FS_SB
+
+#include <asm/semaphore.h>
+#include <linux/ncp_mount.h>
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+#define NCP_DEFAULT_BUFSIZE 1024
+#define NCP_DEFAULT_OPTIONS 0 /* 2 for packet signatures */
+
+struct ncp_server {
+
+ struct ncp_mount_data m; /* Nearly all of the mount data is of
+ interest for us later, so we store
+ it completely. */
+
+ __u8 name_space[NCP_NUMBER_OF_VOLUMES + 2];
+
+ struct file *ncp_filp; /* File pointer to ncp socket */
+
+ u8 sequence;
+ u8 task;
+ u16 connection; /* Remote connection number */
+
+ u8 completion; /* Status message from server */
+ u8 conn_status; /* Bit 4 = 1 ==> Server going down, no
+ requests allowed anymore.
+ Bit 0 = 1 ==> Server is down. */
+
+ int buffer_size; /* Negotiated bufsize */
+
+ int reply_size; /* Size of last reply */
+
+ int packet_size;
+ unsigned char *packet; /* Here we prepare requests and
+ receive replies */
+
+ int lock; /* To prevent mismatch in protocols. */
+ struct semaphore sem;
+
+ int current_size; /* for packet preparation */
+ int has_subfunction;
+ int ncp_reply_size;
+
+ struct ncp_inode_info root;
+ struct dentry* root_dentry;
+
+ int root_setuped;
+
+/* info for packet signing */
+ int sign_wanted; /* 1=Server needs signed packets */
+ int sign_active; /* 0=don't do signing, 1=do */
+ char sign_root[8]; /* generated from password and encr. key */
+ char sign_last[16];
+
+ /* Authentication info: NDS or BINDERY, username */
+ struct {
+ int auth_type;
+ size_t object_name_len;
+ void* object_name;
+ int object_type;
+ } auth;
+ /* Password info */
+ struct {
+ size_t len;
+ void* data;
+ } priv;
+
+ struct ncp_nls_ioctl nls_charsets; /* NLS user data */
+ struct nls_table *nls_vol; /* codepage used on volume */
+ struct nls_table *nls_io; /* charset used for input and display */
+};
+
+static inline int ncp_conn_valid(struct ncp_server *server)
+{
+ return ((server->conn_status & 0x11) == 0);
+}
+
+static inline void ncp_invalidate_conn(struct ncp_server *server)
+{
+ server->conn_status |= 0x01;
+}
+
+#endif /* __KERNEL__ */
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/ncp_mount.h b/pfinet/linux-src/include/linux/ncp_mount.h
new file mode 100644
index 00000000..a214372a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ncp_mount.h
@@ -0,0 +1,45 @@
+/*
+ * ncp_mount.h
+ *
+ * Copyright (C) 1995, 1996 by Volker Lendecke
+ *
+ */
+
+#ifndef _LINUX_NCP_MOUNT_H
+#define _LINUX_NCP_MOUNT_H
+
+#include <linux/types.h>
+#include <linux/ipx.h>
+#include <linux/ncp.h>
+#include <linux/ncp_fs_i.h>
+
+#define NCP_MOUNT_VERSION 3
+
+/* Values for flags */
+#define NCP_MOUNT_SOFT 0x0001
+#define NCP_MOUNT_INTR 0x0002
+#define NCP_MOUNT_STRONG 0x0004 /* enable delete/rename of r/o files */
+#define NCP_MOUNT_NO_OS2 0x0008 /* do not use OS/2 (LONG) namespace */
+#define NCP_MOUNT_NO_NFS 0x0010 /* do not use NFS namespace */
+#define NCP_MOUNT_EXTRAS 0x0020
+#define NCP_MOUNT_SYMLINKS 0x0040 /* enable symlinks */
+
+struct ncp_mount_data {
+ int version;
+ unsigned int ncp_fd; /* The socket to the ncp port */
+ __kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */
+ __kernel_pid_t wdog_pid; /* Who cares for our watchdog packets? */
+
+ unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
+ unsigned int time_out; /* How long should I wait after
+ sending a NCP request? */
+ unsigned int retry_count; /* And how often should I retry? */
+ unsigned int flags;
+
+ __kernel_uid_t uid;
+ __kernel_gid_t gid;
+ __kernel_mode_t file_mode;
+ __kernel_mode_t dir_mode;
+};
+
+#endif
diff --git a/pfinet/linux/net.h b/pfinet/linux-src/include/linux/net.h
index 341d0253..b224c49e 100644
--- a/pfinet/linux/net.h
+++ b/pfinet/linux-src/include/linux/net.h
@@ -18,14 +18,11 @@
#ifndef _LINUX_NET_H
#define _LINUX_NET_H
-
-#include <linux/wait.h>
#include <linux/socket.h>
+struct poll_table_struct;
-#define NSOCKETS 2000 /* Dynamic, this is MAX LIMIT */
-#define NSOCKETS_UNIX 128 /* unix domain static limit */
-#define NPROTO 16 /* should be enough for now.. */
+#define NPROTO 32 /* should be enough for now.. */
#define SYS_SOCKET 1 /* sys_socket(2) */
@@ -43,6 +40,8 @@
#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */
#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */
#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */
+#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
+#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
typedef enum {
@@ -58,42 +57,38 @@ typedef enum {
#define SO_NOSPACE (1<<18) /* no space to write */
#ifdef __KERNEL__
-/*
- * Internal representation of a socket. not all the fields are used by
- * all configurations:
- *
- * server client
- * conn client connected to server connected to
- * iconn list of clients -unused-
- * awaiting connections
- * wait sleep for clients, sleep for connection,
- * sleep for i/o sleep for i/o
- */
-struct socket {
- short type; /* SOCK_STREAM, ... */
- socket_state state;
- long flags;
+
+struct file; /* forward decl magic */
+struct socket
+{
+ socket_state state;
+
+ unsigned long flags;
+ struct proto_ops *ops;
+ struct inode *inode;
#ifdef _HURD_
- int userflags; /* O_* */
- int refcnt;
- mach_port_t identity;
+ uint_fast32_t refcnt; /* # of sock_user's pointing to this */
+ mach_port_t identity; /* for io_identity */
+ ino_t st_ino;
+#else
+ struct fasync_struct *fasync_list; /* Asynchronous wake up list */
+ struct file *file; /* File back pointer for gc */
#endif
- struct proto_ops *ops; /* protocols do most everything */
- void *data; /* protocol data */
- struct socket *conn; /* server socket connected to */
- struct socket *iconn; /* incomplete client conn.s */
- struct socket *next;
- struct wait_queue **wait; /* ptr to place to wait on */
- struct inode *inode;
- struct fasync_struct *fasync_list; /* Asynchronous wake up list */
+ struct sock *sk;
+ struct wait_queue *wait;
+
+ short type;
+ unsigned char passcred;
+ unsigned char tli;
};
#define SOCK_INODE(S) ((S)->inode)
+struct scm_cookie;
+
struct proto_ops {
int family;
- int (*create) (struct socket *sock, int protocol);
int (*dup) (struct socket *newsock, struct socket *oldsock);
int (*release) (struct socket *sock, struct socket *peer);
int (*bind) (struct socket *sock, struct sockaddr *umyaddr,
@@ -105,42 +100,53 @@ struct proto_ops {
int flags);
int (*getname) (struct socket *sock, struct sockaddr *uaddr,
int *usockaddr_len, int peer);
- int (*read) (struct socket *sock, char *ubuf, int size,
- int nonblock);
- int (*write) (struct socket *sock, char *ubuf, int size,
- int nonblock);
- int (*select) (struct socket *sock, int sel_type,
- select_table *wait);
+ unsigned int (*poll) (struct file *file, struct socket *sock, struct poll_table_struct *wait);
int (*ioctl) (struct socket *sock, unsigned int cmd,
unsigned long arg);
int (*listen) (struct socket *sock, int len);
- int (*send) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags);
- int (*recv) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags);
- int (*sendto) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags, struct sockaddr *, int addr_len);
- int (*recvfrom) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags, struct sockaddr *, int *addr_len);
int (*shutdown) (struct socket *sock, int flags);
int (*setsockopt) (struct socket *sock, int level, int optname,
char *optval, int optlen);
int (*getsockopt) (struct socket *sock, int level, int optname,
char *optval, int *optlen);
int (*fcntl) (struct socket *sock, unsigned int cmd,
- unsigned long arg);
+ unsigned long arg);
+ int (*sendmsg) (struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm);
+ int (*recvmsg) (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
+};
+
+struct net_proto_family
+{
+ int family;
+ int (*create)(struct socket *sock, int protocol);
+ /* These are counters for the number of different methods of
+ each we support */
+ short authentication;
+ short encryption;
+ short encrypt_net;
};
-struct net_proto {
- char *name; /* Protocol name */
+struct net_proto
+{
+ const char *name; /* Protocol name */
void (*init_func)(struct net_proto *); /* Bootstrap */
};
-extern int sock_awaitconn(struct socket *mysock, struct socket *servsock, int flags);
-extern int sock_wake_async(struct socket *sock, int how);
-extern int sock_register(int family, struct proto_ops *ops);
+extern struct net_proto_family *net_families[];
+extern int sock_wake_async(struct socket *sk, int how);
+extern int sock_register(struct net_proto_family *fam);
extern int sock_unregister(int family);
extern struct socket *sock_alloc(void);
-extern void sock_release(struct socket *sock);
+extern int sock_create(int family, int type, int proto, struct socket **);
+extern void sock_release(struct socket *);
+extern int sock_sendmsg(struct socket *, struct msghdr *m, int len);
+extern int sock_recvmsg(struct socket *, struct msghdr *m, int len, int flags);
+extern int sock_readv_writev(int type, struct inode * inode, struct file * file,
+ const struct iovec * iov, long count, long size);
+
+extern int net_ratelimit(void);
+extern unsigned long net_random(void);
+extern void net_srandom(unsigned long);
+
#endif /* __KERNEL__ */
#endif /* _LINUX_NET_H */
diff --git a/pfinet/linux-src/include/linux/netbeui.h b/pfinet/linux-src/include/linux/netbeui.h
new file mode 100644
index 00000000..2fb2f71b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/netbeui.h
@@ -0,0 +1,16 @@
+#ifndef _LINUX_NETBEUI_H
+#define _LINUX_NETBEUI_H
+
+#include <linux/if.h>
+
+#define NB_NAME_LEN 20 /* Set this properly from the full docs when
+ I get them */
+
+struct sockaddr_netbeui
+{
+ sa_family snb_family;
+ char snb_name[NB_NAME_LEN];
+ char snb_devhint[IFNAMSIZ];
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/netdevice.h b/pfinet/linux-src/include/linux/netdevice.h
new file mode 100644
index 00000000..86f84a90
--- /dev/null
+++ b/pfinet/linux-src/include/linux/netdevice.h
@@ -0,0 +1,466 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the Interfaces handler.
+ *
+ * Version: @(#)dev.h 1.0.10 08/12/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Donald J. Becker, <becker@cesdis.gsfc.nasa.gov>
+ * Alan Cox, <Alan.Cox@linux.org>
+ * Bjorn Ekwall. <bj0rn@blox.se>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Moved to /usr/include/linux for NET3
+ */
+#ifndef _LINUX_NETDEVICE_H
+#define _LINUX_NETDEVICE_H
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#endif
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+#include <asm/atomic.h>
+
+#ifdef __KERNEL__
+#ifdef CONFIG_NET_PROFILE
+#include <net/profile.h>
+#endif
+#endif
+
+/*
+ * For future expansion when we will have different priorities.
+ */
+
+#define MAX_ADDR_LEN 7 /* Largest hardware address length */
+
+/*
+ * Compute the worst case header length according to the protocols
+ * used.
+ */
+
+#if !defined(CONFIG_AX25) && !defined(CONFIG_AX25_MODULE) && !defined(CONFIG_TR)
+#define LL_MAX_HEADER 32
+#else
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+#define LL_MAX_HEADER 96
+#else
+#define LL_MAX_HEADER 48
+#endif
+#endif
+
+#if !defined(CONFIG_NET_IPIP) && \
+ !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
+#define MAX_HEADER LL_MAX_HEADER
+#else
+#define MAX_HEADER (LL_MAX_HEADER + 48)
+#endif
+
+/*
+ * Network device statistics. Akin to the 2.0 ether stats but
+ * with byte counters.
+ */
+
+struct net_device_stats
+{
+ unsigned long rx_packets; /* total packets received */
+ unsigned long tx_packets; /* total packets transmitted */
+ unsigned long rx_bytes; /* total bytes received */
+ unsigned long tx_bytes; /* total bytes transmitted */
+ unsigned long rx_errors; /* bad packets received */
+ unsigned long tx_errors; /* packet transmit problems */
+ unsigned long rx_dropped; /* no space in linux buffers */
+ unsigned long tx_dropped; /* no space available in linux */
+ unsigned long multicast; /* multicast packets received */
+ unsigned long collisions;
+
+ /* detailed rx_errors: */
+ unsigned long rx_length_errors;
+ unsigned long rx_over_errors; /* receiver ring buff overflow */
+ unsigned long rx_crc_errors; /* recved pkt with crc error */
+ unsigned long rx_frame_errors; /* recv'd frame alignment error */
+ unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+ unsigned long rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ unsigned long tx_aborted_errors;
+ unsigned long tx_carrier_errors;
+ unsigned long tx_fifo_errors;
+ unsigned long tx_heartbeat_errors;
+ unsigned long tx_window_errors;
+
+ /* for cslip etc */
+ unsigned long rx_compressed;
+ unsigned long tx_compressed;
+};
+
+#ifdef CONFIG_NET_FASTROUTE
+struct net_fastroute_stats
+{
+ int hits;
+ int succeed;
+ int deferred;
+ int latency_reduction;
+};
+#endif
+
+/* Media selection options. */
+enum {
+ IF_PORT_UNKNOWN = 0,
+ IF_PORT_10BASE2,
+ IF_PORT_10BASET,
+ IF_PORT_AUI,
+ IF_PORT_100BASET,
+ IF_PORT_100BASETX,
+ IF_PORT_100BASEFX
+};
+
+#ifdef __KERNEL__
+
+extern const char *if_port_text[];
+
+#include <linux/skbuff.h>
+
+struct neighbour;
+struct neigh_parms;
+struct sk_buff;
+
+/*
+ * We tag multicasts with these structures.
+ */
+
+struct dev_mc_list
+{
+ struct dev_mc_list *next;
+ __u8 dmi_addr[MAX_ADDR_LEN];
+ unsigned char dmi_addrlen;
+ int dmi_users;
+ int dmi_gusers;
+};
+
+struct hh_cache
+{
+ struct hh_cache *hh_next; /* Next entry */
+ atomic_t hh_refcnt; /* number of users */
+ unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP */
+ int (*hh_output)(struct sk_buff *skb);
+ rwlock_t hh_lock;
+ /* cached hardware header; allow for machine alignment needs. */
+ unsigned long hh_data[16/sizeof(unsigned long)];
+};
+
+
+/*
+ * The DEVICE structure.
+ * Actually, this whole structure is a big mistake. It mixes I/O
+ * data with strictly "high-level" data, and it has to know about
+ * almost every data structure used in the INET module.
+ *
+ * FIXME: cleanup struct device such that network protocol info
+ * moves out.
+ */
+
+struct device
+{
+
+ /*
+ * This is the first field of the "visible" part of this structure
+ * (i.e. as seen by users in the "Space.c" file). It is the name
+ * the interface.
+ */
+ char *name;
+
+ /*
+ * I/O specific fields
+ * FIXME: Merge these and struct ifmap into one
+ */
+ unsigned long rmem_end; /* shmem "recv" end */
+ unsigned long rmem_start; /* shmem "recv" start */
+ unsigned long mem_end; /* shared mem end */
+ unsigned long mem_start; /* shared mem start */
+ unsigned long base_addr; /* device I/O address */
+ unsigned int irq; /* device IRQ number */
+
+ /* Low-level status flags. */
+ volatile unsigned char start; /* start an operation */
+ /*
+ * These two are just single-bit flags, but due to atomicity
+ * reasons they have to be inside a "unsigned long". However,
+ * they should be inside the SAME unsigned long instead of
+ * this wasteful use of memory..
+ */
+ unsigned long interrupt; /* bitops.. */
+ unsigned long tbusy; /* transmitter busy */
+
+ struct device *next;
+
+ /* The device initialization function. Called only once. */
+ int (*init)(struct device *dev);
+ void (*destructor)(struct device *dev);
+
+ /* Interface index. Unique device identifier */
+ int ifindex;
+ int iflink;
+
+ /*
+ * Some hardware also needs these fields, but they are not
+ * part of the usual set specified in Space.c.
+ */
+
+ unsigned char if_port; /* Selectable AUI, TP,..*/
+ unsigned char dma; /* DMA channel */
+
+ struct net_device_stats* (*get_stats)(struct device *dev);
+ struct iw_statistics* (*get_wireless_stats)(struct device *dev);
+
+ /*
+ * This marks the end of the "visible" part of the structure. All
+ * fields hereafter are internal to the system, and may change at
+ * will (read: may be cleaned up at will).
+ */
+
+ /* These may be needed for future network-power-down code. */
+ unsigned long trans_start; /* Time (in jiffies) of last Tx */
+ unsigned long last_rx; /* Time of last Rx */
+
+ unsigned short flags; /* interface flags (a la BSD) */
+ unsigned short gflags;
+ unsigned mtu; /* interface MTU value */
+ unsigned short type; /* interface hardware type */
+ unsigned short hard_header_len; /* hardware hdr length */
+ void *priv; /* pointer to private data */
+
+ /* Interface address info. */
+ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
+ unsigned char pad; /* make dev_addr aligned to 8 bytes */
+ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */
+ unsigned char addr_len; /* hardware address length */
+
+ struct dev_mc_list *mc_list; /* Multicast mac addresses */
+ int mc_count; /* Number of installed mcasts */
+ int promiscuity;
+ int allmulti;
+
+ /* For load balancing driver pair support */
+
+ unsigned long pkt_queue; /* Packets queued */
+ struct device *slave; /* Slave device */
+
+ /* Protocol specific pointers */
+
+ void *atalk_ptr; /* AppleTalk link */
+ void *ip_ptr; /* IPv4 specific data */
+ void *dn_ptr; /* DECnet specific data */
+
+ struct Qdisc *qdisc;
+ struct Qdisc *qdisc_sleeping;
+ struct Qdisc *qdisc_list;
+ unsigned long tx_queue_len; /* Max frames per queue allowed */
+
+ /* Bridge stuff */
+ int bridge_port_id;
+
+ /* Pointers to interface service routines. */
+ int (*open)(struct device *dev);
+ int (*stop)(struct device *dev);
+ int (*hard_start_xmit) (struct sk_buff *skb,
+ struct device *dev);
+ int (*hard_header) (struct sk_buff *skb,
+ struct device *dev,
+ unsigned short type,
+ void *daddr,
+ void *saddr,
+ unsigned len);
+ int (*rebuild_header)(struct sk_buff *skb);
+#define HAVE_MULTICAST
+ void (*set_multicast_list)(struct device *dev);
+#define HAVE_SET_MAC_ADDR
+ int (*set_mac_address)(struct device *dev,
+ void *addr);
+#define HAVE_PRIVATE_IOCTL
+ int (*do_ioctl)(struct device *dev,
+ struct ifreq *ifr, int cmd);
+#define HAVE_SET_CONFIG
+ int (*set_config)(struct device *dev,
+ struct ifmap *map);
+#define HAVE_HEADER_CACHE
+ int (*hard_header_cache)(struct neighbour *neigh,
+ struct hh_cache *hh);
+ void (*header_cache_update)(struct hh_cache *hh,
+ struct device *dev,
+ unsigned char * haddr);
+#define HAVE_CHANGE_MTU
+ int (*change_mtu)(struct device *dev, int new_mtu);
+
+ int (*hard_header_parse)(struct sk_buff *skb,
+ unsigned char *haddr);
+ int (*neigh_setup)(struct device *dev, struct neigh_parms *);
+ int (*accept_fastpath)(struct device *, struct dst_entry*);
+
+#ifdef CONFIG_NET_FASTROUTE
+ /* Really, this semaphore may be necessary and for not fastroute code;
+ f.e. SMP??
+ */
+ int tx_semaphore;
+#define NETDEV_FASTROUTE_HMASK 0xF
+ /* Semi-private data. Keep it at the end of device struct. */
+ struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1];
+#endif
+};
+
+
+struct packet_type
+{
+ unsigned short type; /* This is really htons(ether_type). */
+ struct device *dev; /* NULL is wildcarded here */
+ int (*func) (struct sk_buff *, struct device *,
+ struct packet_type *);
+ void *data; /* Private to the packet type */
+ struct packet_type *next;
+};
+
+
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+
+extern struct device loopback_dev; /* The loopback */
+extern struct device *dev_base; /* All devices */
+extern struct packet_type *ptype_base[16]; /* Hashed types */
+extern int netdev_dropping;
+extern int net_cpu_congestion;
+
+extern struct device *dev_getbyhwaddr(unsigned short type, char *hwaddr);
+extern void dev_add_pack(struct packet_type *pt);
+extern void dev_remove_pack(struct packet_type *pt);
+extern struct device *dev_get(const char *name);
+extern struct device *dev_alloc(const char *name, int *err);
+extern int dev_alloc_name(struct device *dev, const char *name);
+extern int dev_open(struct device *dev);
+extern int dev_close(struct device *dev);
+extern int dev_queue_xmit(struct sk_buff *skb);
+extern void dev_loopback_xmit(struct sk_buff *skb);
+extern int register_netdevice(struct device *dev);
+extern int unregister_netdevice(struct device *dev);
+extern int register_netdevice_notifier(struct notifier_block *nb);
+extern int unregister_netdevice_notifier(struct notifier_block *nb);
+extern int dev_new_index(void);
+extern struct device *dev_get_by_index(int ifindex);
+extern int dev_restart(struct device *dev);
+
+typedef int gifconf_func_t(struct device * dev, char * bufptr, int len);
+extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf);
+extern __inline__ int unregister_gifconf(unsigned int family)
+{
+ return register_gifconf(family, 0);
+}
+
+#define HAVE_NETIF_RX 1
+extern void netif_rx(struct sk_buff *skb);
+extern void net_bh(void);
+extern int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
+extern int dev_ioctl(unsigned int cmd, void *);
+extern int dev_change_flags(struct device *, unsigned);
+extern void dev_queue_xmit_nit(struct sk_buff *skb, struct device *dev);
+
+extern void dev_init(void);
+
+extern int netdev_nit;
+
+/* Locking protection for page faults during outputs to devices unloaded during the fault */
+
+extern atomic_t dev_lockct;
+
+/*
+ * These two don't currently need to be atomic
+ * but they may do soon. Do it properly anyway.
+ */
+
+extern __inline__ void dev_lock_list(void)
+{
+ atomic_inc(&dev_lockct);
+}
+
+extern __inline__ void dev_unlock_list(void)
+{
+ atomic_dec(&dev_lockct);
+}
+
+/*
+ * This almost never occurs, isn't in performance critical paths
+ * and we can thus be relaxed about it.
+ *
+ * FIXME: What if this is being run as a real time process ??
+ * Linus: We need a way to force a yield here ?
+ *
+ * FIXME: Though dev_lockct is atomic varible, locking procedure
+ * is not atomic.
+ */
+
+extern __inline__ void dev_lock_wait(void)
+{
+ while (atomic_read(&dev_lockct)) {
+ current->policy |= SCHED_YIELD;
+ schedule();
+ }
+}
+
+extern __inline__ void dev_init_buffers(struct device *dev)
+{
+ /* DO NOTHING */
+}
+
+/* These functions live elsewhere (drivers/net/net_init.c, but related) */
+
+extern void ether_setup(struct device *dev);
+extern void fddi_setup(struct device *dev);
+extern void tr_setup(struct device *dev);
+extern void fc_setup(struct device *dev);
+extern void tr_freedev(struct device *dev);
+extern void fc_freedev(struct device *dev);
+extern int ether_config(struct device *dev, struct ifmap *map);
+/* Support for loadable net-drivers */
+extern int register_netdev(struct device *dev);
+extern void unregister_netdev(struct device *dev);
+extern int register_trdev(struct device *dev);
+extern void unregister_trdev(struct device *dev);
+extern int register_fcdev(struct device *dev);
+extern void unregister_fcdev(struct device *dev);
+/* Functions used for multicast support */
+extern void dev_mc_upload(struct device *dev);
+extern int dev_mc_delete(struct device *dev, void *addr, int alen, int all);
+extern int dev_mc_add(struct device *dev, void *addr, int alen, int newonly);
+extern void dev_mc_discard(struct device *dev);
+extern void dev_set_promiscuity(struct device *dev, int inc);
+extern void dev_set_allmulti(struct device *dev, int inc);
+extern void netdev_state_change(struct device *dev);
+/* Load a device via the kmod */
+extern void dev_load(const char *name);
+extern void dev_mcast_init(void);
+extern int netdev_register_fc(struct device *dev, void (*stimul)(struct device *dev));
+extern void netdev_unregister_fc(int bit);
+extern int netdev_dropping;
+extern int netdev_max_backlog;
+extern atomic_t netdev_rx_dropped;
+extern unsigned long netdev_fc_xoff;
+#ifdef CONFIG_NET_FASTROUTE
+extern int netdev_fastroute;
+extern int netdev_fastroute_obstacles;
+extern void dev_clear_fastroute(struct device *dev);
+extern struct net_fastroute_stats dev_fastroute_stat;
+#endif
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DEV_H */
diff --git a/pfinet/linux-src/include/linux/netlink.h b/pfinet/linux-src/include/linux/netlink.h
new file mode 100644
index 00000000..59075b07
--- /dev/null
+++ b/pfinet/linux-src/include/linux/netlink.h
@@ -0,0 +1,158 @@
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#define NETLINK_ROUTE 0 /* Routing/device hook */
+#define NETLINK_SKIP 1 /* Reserved for ENskip */
+#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Firewalling hook */
+#define NETLINK_ARPD 8
+#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
+#define NETLINK_IP6_FW 13
+#define NETLINK_TAPBASE 16 /* 16 to 31 are ethertap */
+
+#define MAX_LINKS 32
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family; /* AF_NETLINK */
+ unsigned short nl_pad; /* zero */
+ __u32 nl_pid; /* process pid */
+ __u32 nl_groups; /* multicast groups mask */
+};
+
+struct nlmsghdr
+{
+ __u32 nlmsg_len; /* Length of message including header */
+ __u16 nlmsg_type; /* Message content */
+ __u16 nlmsg_flags; /* Additional flags */
+ __u32 nlmsg_seq; /* Sequence number */
+ __u32 nlmsg_pid; /* Sending process PID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST 1 /* It is request message. */
+#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 4 /* If succeed, reply with ack */
+#define NLM_F_ECHO 8 /* Echo this request */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT 0x100 /* specify tree root */
+#define NLM_F_MATCH 0x200 /* return all matching */
+#define NLM_F_ATOMIC 0x400 /* atomic GET */
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE 0x100 /* Override existing */
+#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
+#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
+#define NLM_F_APPEND 0x800 /* Add to end of list */
+
+/*
+ 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
+ 4.4BSD CHANGE NLM_F_REPLACE
+
+ True CHANGE NLM_F_CREATE|NLM_F_REPLACE
+ Append NLM_F_CREATE
+ Check NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) > 0 && (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP 0x1 /* Nothing. */
+#define NLMSG_ERROR 0x2 /* Error */
+#define NLMSG_DONE 0x3 /* End of a dump */
+#define NLMSG_OVERRUN 0x4 /* Data lost */
+
+struct nlmsgerr
+{
+ int error;
+ struct nlmsghdr msg;
+};
+
+#define NET_MAJOR 36 /* Major 36 is reserved for networking */
+
+#ifdef __KERNEL__
+
+struct netlink_skb_parms
+{
+ struct ucred creds; /* Skb credentials */
+ __u32 pid;
+ __u32 groups;
+ __u32 dst_pid;
+ __u32 dst_groups;
+ kernel_cap_t eff_cap;
+};
+
+#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))
+#define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds)
+
+
+extern int netlink_attach(int unit, int (*function)(int,struct sk_buff *skb));
+extern void netlink_detach(int unit);
+extern int netlink_post(int unit, struct sk_buff *skb);
+extern int init_netlink(void);
+extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
+extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
+extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
+extern void netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
+ __u32 group, int allocation);
+extern void netlink_set_err(struct sock *ssk, __u32 pid, __u32 group, int code);
+
+/*
+ * skb should fit one page. This choice is good for headerless malloc.
+ *
+ * FIXME: What is the best size for SLAB???? --ANK
+ */
+#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
+
+
+struct netlink_callback
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ int (*dump)(struct sk_buff * skb, struct netlink_callback *cb);
+ int (*done)(struct netlink_callback *cb);
+ int family;
+ long args[4];
+};
+
+extern __inline__ struct nlmsghdr *
+__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
+{
+ struct nlmsghdr *nlh;
+ int size = NLMSG_LENGTH(len);
+
+ nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
+ nlh->nlmsg_type = type;
+ nlh->nlmsg_len = size;
+ nlh->nlmsg_flags = 0;
+ nlh->nlmsg_pid = pid;
+ nlh->nlmsg_seq = seq;
+ return nlh;
+}
+
+#define NLMSG_PUT(skb, pid, seq, type, len) \
+({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; \
+ __nlmsg_put(skb, pid, seq, type, len); })
+
+extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
+ struct nlmsghdr *nlh,
+ int (*dump)(struct sk_buff *skb, struct netlink_callback*),
+ int (*done)(struct netlink_callback*));
+
+
+extern void netlink_proto_init(struct net_proto *pro);
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_NETLINK_H */
diff --git a/pfinet/linux-src/include/linux/netrom.h b/pfinet/linux-src/include/linux/netrom.h
new file mode 100644
index 00000000..6939b32f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/netrom.h
@@ -0,0 +1,34 @@
+/*
+ * These are the public elements of the Linux kernel NET/ROM implementation.
+ * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the
+ * definition of the ax25_address structure.
+ */
+
+#ifndef NETROM_KERNEL_H
+#define NETROM_KERNEL_H
+
+#define NETROM_MTU 236
+
+#define NETROM_T1 1
+#define NETROM_T2 2
+#define NETROM_N2 3
+#define NETROM_T4 6
+#define NETROM_IDLE 7
+
+#define SIOCNRDECOBS (SIOCPROTOPRIVATE+2)
+
+struct nr_route_struct {
+#define NETROM_NEIGH 0
+#define NETROM_NODE 1
+ int type;
+ ax25_address callsign;
+ char device[16];
+ unsigned int quality;
+ char mnemonic[7];
+ ax25_address neighbour;
+ unsigned int obs_count;
+ unsigned int ndigis;
+ ax25_address digipeaters[AX25_MAX_DIGIS];
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nfs.h b/pfinet/linux-src/include/linux/nfs.h
new file mode 100644
index 00000000..7936d5a7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nfs.h
@@ -0,0 +1,226 @@
+/*
+ * NFS protocol definitions
+ */
+#ifndef _LINUX_NFS_H
+#define _LINUX_NFS_H
+
+#include <linux/sunrpc/msg_prot.h>
+
+#define NFS_PORT 2049
+#define NFS_MAXDATA 8192
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_MAXGROUPS 16
+#define NFS_FHSIZE 32
+#define NFS_COOKIESIZE 4
+#define NFS_FIFO_DEV (-1)
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+
+enum nfs_stat {
+ NFS_OK = 0,
+ NFSERR_PERM = 1,
+ NFSERR_NOENT = 2,
+ NFSERR_IO = 5,
+ NFSERR_NXIO = 6,
+ NFSERR_EAGAIN = 11,
+ NFSERR_ACCES = 13,
+ NFSERR_EXIST = 17,
+ NFSERR_XDEV = 18,
+ NFSERR_NODEV = 19,
+ NFSERR_NOTDIR = 20,
+ NFSERR_ISDIR = 21,
+ NFSERR_INVAL = 22, /* that Sun forgot */
+ NFSERR_FBIG = 27,
+ NFSERR_NOSPC = 28,
+ NFSERR_ROFS = 30,
+ NFSERR_OPNOTSUPP = 45,
+ NFSERR_NAMETOOLONG = 63,
+ NFSERR_NOTEMPTY = 66,
+ NFSERR_DQUOT = 69,
+ NFSERR_STALE = 70,
+ NFSERR_WFLUSH = 99
+};
+
+enum nfs_ftype {
+ NFNON = 0,
+ NFREG = 1,
+ NFDIR = 2,
+ NFBLK = 3,
+ NFCHR = 4,
+ NFLNK = 5,
+ NFSOCK = 6,
+ NFBAD = 7,
+ NFFIFO = 8
+};
+
+struct nfs_fh {
+ char data[NFS_FHSIZE];
+};
+
+#define NFS_PROGRAM 100003
+#define NFS_VERSION 2
+#define NFSPROC_NULL 0
+#define NFSPROC_GETATTR 1
+#define NFSPROC_SETATTR 2
+#define NFSPROC_ROOT 3
+#define NFSPROC_LOOKUP 4
+#define NFSPROC_READLINK 5
+#define NFSPROC_READ 6
+#define NFSPROC_WRITECACHE 7
+#define NFSPROC_WRITE 8
+#define NFSPROC_CREATE 9
+#define NFSPROC_REMOVE 10
+#define NFSPROC_RENAME 11
+#define NFSPROC_LINK 12
+#define NFSPROC_SYMLINK 13
+#define NFSPROC_MKDIR 14
+#define NFSPROC_RMDIR 15
+#define NFSPROC_READDIR 16
+#define NFSPROC_STATFS 17
+
+/* Mount support for NFSroot */
+#ifdef __KERNEL__
+#define NFS_MNT_PROGRAM 100005
+#define NFS_MNT_VERSION 1
+#define NFS_MNT_PORT 627
+#define NFS_MNTPROC_MNT 1
+#define NFS_MNTPROC_UMNT 3
+#endif
+
+#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
+
+extern struct rpc_program nfs_program;
+extern struct rpc_stat nfs_rpcstat;
+
+struct nfs_time {
+ __u32 seconds;
+ __u32 useconds;
+};
+
+struct nfs_fattr {
+ enum nfs_ftype type;
+ __u32 mode;
+ __u32 nlink;
+ __u32 uid;
+ __u32 gid;
+ __u32 size;
+ __u32 blocksize;
+ __u32 rdev;
+ __u32 blocks;
+ __u32 fsid;
+ __u32 fileid;
+ struct nfs_time atime;
+ struct nfs_time mtime;
+ struct nfs_time ctime;
+};
+
+struct nfs_sattr {
+ __u32 mode;
+ __u32 uid;
+ __u32 gid;
+ __u32 size;
+ struct nfs_time atime;
+ struct nfs_time mtime;
+};
+
+struct nfs_fsinfo {
+ __u32 tsize;
+ __u32 bsize;
+ __u32 blocks;
+ __u32 bfree;
+ __u32 bavail;
+};
+
+struct nfs_writeargs {
+ struct nfs_fh * fh;
+ __u32 offset;
+ __u32 count;
+ const void * buffer;
+};
+
+#ifdef NFS_NEED_XDR_TYPES
+
+struct nfs_sattrargs {
+ struct nfs_fh * fh;
+ struct nfs_sattr * sattr;
+};
+
+struct nfs_diropargs {
+ struct nfs_fh * fh;
+ const char * name;
+};
+
+struct nfs_readargs {
+ struct nfs_fh * fh;
+ __u32 offset;
+ __u32 count;
+ void * buffer;
+};
+
+struct nfs_createargs {
+ struct nfs_fh * fh;
+ const char * name;
+ struct nfs_sattr * sattr;
+};
+
+struct nfs_renameargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ struct nfs_fh * tofh;
+ const char * toname;
+};
+
+struct nfs_linkargs {
+ struct nfs_fh * fromfh;
+ struct nfs_fh * tofh;
+ const char * toname;
+};
+
+struct nfs_symlinkargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ const char * topath;
+ struct nfs_sattr * sattr;
+};
+
+struct nfs_readdirargs {
+ struct nfs_fh * fh;
+ __u32 cookie;
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs_diropok {
+ struct nfs_fh * fh;
+ struct nfs_fattr * fattr;
+};
+
+struct nfs_readres {
+ struct nfs_fattr * fattr;
+ unsigned int count;
+};
+
+struct nfs_readlinkres {
+ char ** string;
+ unsigned int * lenp;
+ unsigned int maxlen;
+ void * buffer;
+};
+
+struct nfs_readdirres {
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+#endif /* NFS_NEED_XDR_TYPES */
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nfs3.h b/pfinet/linux-src/include/linux/nfs3.h
new file mode 100644
index 00000000..94ec44b6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nfs3.h
@@ -0,0 +1,252 @@
+/*
+ * NFSv3 protocol definitions
+ */
+#ifndef _LINUX_NFS3_H
+#define _LINUX_NFS3_H
+
+#include <linux/sunrpc/msg_prot.h>
+#include <linux/nfs.h>
+
+#define NFS3_PORT 2049
+#define NFS3_MAXDATA 8192
+#define NFS3_MAXPATHLEN PATH_MAX
+#define NFS3_MAXNAMLEN NAME_MAX
+#define NFS3_MAXGROUPS 16
+#define NFS3_FHSIZE NFS_FHSIZE
+#define NFS3_COOKIESIZE 4
+#define NFS3_FIFO_DEV (-1)
+#define NFS3MODE_FMT 0170000
+#define NFS3MODE_DIR 0040000
+#define NFS3MODE_CHR 0020000
+#define NFS3MODE_BLK 0060000
+#define NFS3MODE_REG 0100000
+#define NFS3MODE_LNK 0120000
+#define NFS3MODE_SOCK 0140000
+#define NFS3MODE_FIFO 0010000
+
+
+enum nfs3_stat {
+ NFS3_OK = 0,
+ NFS3ERR_PERM = 1,
+ NFS3ERR_NOENT = 2,
+ NFS3ERR_IO = 5,
+ NFS3ERR_NXIO = 6,
+ NFS3ERR_EAGAIN = 11,
+ NFS3ERR_ACCES = 13,
+ NFS3ERR_EXIST = 17,
+ NFS3ERR_XDEV = 18, /* new in NFSv3 */
+ NFS3ERR_NODEV = 19,
+ NFS3ERR_NOTDIR = 20,
+ NFS3ERR_ISDIR = 21,
+ NFS3ERR_INVAL = 22, /* new in NFSv3 */
+ NFS3ERR_FBIG = 27,
+ NFS3ERR_NOSPC = 28,
+ NFS3ERR_ROFS = 30,
+ NFS3ERR_MLINK = 31, /* new in NFSv3 */
+ NFS3ERR_NAMETOOLONG = 63,
+ NFS3ERR_NOTEMPTY = 66,
+ NFS3ERR_DQUOT = 69,
+ NFS3ERR_STALE = 70,
+ NFS3ERR_REMOTE = 71, /* new in NFSv3 */
+ NFS3ERR_BADHANDLE = 10001,/* ditto */
+ NFS3ERR_NOT_SYNC = 10002,/* ditto */
+ NFS3ERR_BAD_COOKIE = 10003,/* ditto */
+ NFS3ERR_NOTSUPP = 10004,/* ditto */
+ NFS3ERR_TOOSMALL = 10005,/* ditto */
+ NFS3ERR_SERVERFAULT = 10006,/* ditto */
+ NFS3ERR_BADTYPE = 10007,/* ditto */
+ NFS3ERR_JUKEBOX = 10008,/* ditto */
+};
+
+enum nfs3_ftype {
+ NF3NON = 0,
+ NF3REG = 1,
+ NF3DIR = 2,
+ NF3BLK = 3,
+ NF3CHR = 4,
+ NF3LNK = 5,
+ NF3SOCK = 6,
+ NF3FIFO = 7, /* changed from NFSv2 (was 8) */
+ NF3BAD = 8
+};
+
+#define NFS3_VERSION 3
+#define NFSPROC_NULL 0
+#define NFSPROC_GETATTR 1
+#define NFSPROC_SETATTR 2
+#define NFSPROC_ROOT 3
+#define NFSPROC_LOOKUP 4
+#define NFSPROC_READLINK 5
+#define NFSPROC_READ 6
+#define NFSPROC_WRITECACHE 7
+#define NFSPROC_WRITE 8
+#define NFSPROC_CREATE 9
+#define NFSPROC_REMOVE 10
+#define NFSPROC_RENAME 11
+#define NFSPROC_LINK 12
+#define NFSPROC_SYMLINK 13
+#define NFSPROC_MKDIR 14
+#define NFSPROC_RMDIR 15
+#define NFSPROC_READDIR 16
+#define NFSPROC_STATFS 17
+
+#if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
+
+struct nfs3_fh {
+ __u32 size;
+ __u8 data[NFS3_FHSIZE];
+};
+
+struct nfs3_fattr {
+ enum nfs3_ftype type;
+ __u32 mode;
+ __u32 nlink;
+ __u32 uid;
+ __u32 gid;
+ __u64 size;
+ __u64 used;
+ __u32 rdev_maj;
+ __u32 rdev_min;
+ __u32 fsid;
+ __u32 fileid;
+ struct nfs_time atime;
+ struct nfs_time mtime;
+ struct nfs_time ctime;
+};
+
+struct nfs3_wcc_attr {
+ __u64 size;
+ struct nfs_time mtime;
+ struct nfs_time ctime;
+};
+
+struct nfs3_wcc_data {
+ struct nfs3_wcc_attr before;
+ struct nfs3_wcc_attr after;
+};
+
+struct nfs3_sattr {
+ __u32 valid;
+ __u32 mode;
+ __u32 uid;
+ __u32 gid;
+ __u64 size;
+ struct nfs_time atime;
+ struct nfs_time mtime;
+};
+
+struct nfs3_entry {
+ __u32 fileid;
+ char * name;
+ unsigned int length;
+ __u32 cookie;
+ __u32 eof;
+};
+
+struct nfs3_fsinfo {
+ __u32 tsize;
+ __u32 bsize;
+ __u32 blocks;
+ __u32 bfree;
+ __u32 bavail;
+};
+
+#ifdef NFS_NEED_XDR_TYPES
+
+struct nfs3_sattrargs {
+ struct nfs_fh * fh;
+ struct nfs_sattr * sattr;
+};
+
+struct nfs3_diropargs {
+ struct nfs_fh * fh;
+ const char * name;
+};
+
+struct nfs3_readargs {
+ struct nfs_fh * fh;
+ __u32 offset;
+ __u32 count;
+ void * buffer;
+};
+
+struct nfs3_writeargs {
+ struct nfs_fh * fh;
+ __u32 offset;
+ __u32 count;
+ const void * buffer;
+};
+
+struct nfs3_createargs {
+ struct nfs_fh * fh;
+ const char * name;
+ struct nfs_sattr * sattr;
+};
+
+struct nfs3_renameargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ struct nfs_fh * tofh;
+ const char * toname;
+};
+
+struct nfs3_linkargs {
+ struct nfs_fh * fromfh;
+ struct nfs_fh * tofh;
+ const char * toname;
+};
+
+struct nfs3_symlinkargs {
+ struct nfs_fh * fromfh;
+ const char * fromname;
+ const char * topath;
+ struct nfs_sattr * sattr;
+};
+
+struct nfs3_readdirargs {
+ struct nfs_fh * fh;
+ __u32 cookie;
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+struct nfs3_diropok {
+ struct nfs_fh * fh;
+ struct nfs_fattr * fattr;
+};
+
+struct nfs3_readres {
+ struct nfs_fattr * fattr;
+ unsigned int count;
+};
+
+struct nfs3_readlinkres {
+ char ** string;
+ unsigned int * lenp;
+ unsigned int maxlen;
+ void * buffer;
+};
+
+struct nfs3_readdirres {
+ void * buffer;
+ unsigned int bufsiz;
+};
+
+/*
+ * The following are for NFSv3
+ */
+struct nfs3_fh {
+ __u32 size;
+ __u8 data[NFS3_FHSIZE]
+};
+
+struct nfs3_wcc_attr {
+ __u64 size;
+ struct nfs_time mtime;
+ struct nfs_time ctime;
+};
+
+#endif /* NFS_NEED_XDR_TYPES */
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nfs_fs.h b/pfinet/linux-src/include/linux/nfs_fs.h
new file mode 100644
index 00000000..af961506
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nfs_fs.h
@@ -0,0 +1,284 @@
+/*
+ * linux/include/linux/nfs_fs.h
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * OS-specific nfs filesystem definitions and declarations
+ */
+
+#ifndef _LINUX_NFS_FS_H
+#define _LINUX_NFS_FS_H
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+
+#include <linux/sunrpc/sched.h>
+#include <linux/nfs.h>
+#include <linux/nfs_mount.h>
+
+/*
+ * Enable debugging support for nfs client.
+ * Requires RPC_DEBUG.
+ */
+#ifdef RPC_DEBUG
+# define NFS_DEBUG
+#endif
+
+/*
+ * NFS_MAX_DIRCACHE controls the number of simultaneously cached
+ * directory chunks. Each chunk holds the list of nfs_entry's returned
+ * in a single readdir call in a memory region of size PAGE_SIZE.
+ *
+ * Note that at most server->rsize bytes of the cache memory are used.
+ */
+#define NFS_MAX_DIRCACHE 16
+
+#define NFS_MAX_FILE_IO_BUFFER_SIZE 16384
+#define NFS_DEF_FILE_IO_BUFFER_SIZE 4096
+
+/*
+ * The upper limit on timeouts for the exponential backoff algorithm.
+ */
+#define NFS_MAX_RPC_TIMEOUT (6*HZ)
+
+/*
+ * Size of the lookup cache in units of number of entries cached.
+ * It is better not to make this too large although the optimum
+ * depends on a usage and environment.
+ */
+#define NFS_LOOKUP_CACHE_SIZE 64
+
+/*
+ * superblock magic number for NFS
+ */
+#define NFS_SUPER_MAGIC 0x6969
+
+#define NFS_FH(dentry) ((struct nfs_fh *) ((dentry)->d_fsdata))
+#define NFS_DSERVER(dentry) (&(dentry)->d_sb->u.nfs_sb.s_server)
+#define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server)
+#define NFS_CLIENT(inode) (NFS_SERVER(inode)->client)
+#define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode)))
+#define NFS_CONGESTED(inode) (RPC_CONGESTED(NFS_CLIENT(inode)))
+
+#define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies)
+#define NFS_OLDMTIME(inode) ((inode)->u.nfs_i.read_cache_mtime)
+#define NFS_CACHEINV(inode) \
+do { \
+ NFS_READTIME(inode) = jiffies - 1000000; \
+ NFS_OLDMTIME(inode) = 0; \
+} while (0)
+#define NFS_ATTRTIMEO(inode) ((inode)->u.nfs_i.attrtimeo)
+#define NFS_MINATTRTIMEO(inode) \
+ (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
+ : NFS_SERVER(inode)->acregmin)
+#define NFS_MAXATTRTIMEO(inode) \
+ (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
+ : NFS_SERVER(inode)->acregmax)
+
+#define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags)
+#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATE)
+#define NFS_WRITEBACK(inode) ((inode)->u.nfs_i.writeback)
+
+/*
+ * These are the default flags for swap requests
+ */
+#define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
+
+/* Flags in the RPC client structure */
+#define NFS_CLNTF_BUFSIZE 0x0001 /* readdir buffer in longwords */
+
+#ifdef __KERNEL__
+
+/*
+ * This struct describes a file region to be written.
+ * It's kind of a pity we have to keep all these lists ourselves, rather
+ * than sticking an extra pointer into struct page.
+ */
+struct nfs_wreq {
+ struct rpc_listitem wb_list; /* linked list of req's */
+ struct rpc_task wb_task; /* RPC task */
+ struct file * wb_file; /* dentry referenced */
+ struct page * wb_page; /* page to be written */
+ struct wait_queue * wb_wait; /* wait for completion */
+ unsigned int wb_offset; /* offset within page */
+ unsigned int wb_bytes; /* dirty range */
+ unsigned int wb_count; /* user count */
+ int wb_status;
+ pid_t wb_pid; /* owner process */
+ unsigned short wb_flags; /* status flags */
+
+ struct nfs_writeargs wb_args; /* NFS RPC stuff */
+ struct nfs_fattr wb_fattr; /* file attributes */
+};
+
+#define WB_NEXT(req) ((struct nfs_wreq *) ((req)->wb_list.next))
+
+/*
+ * Various flags for wb_flags
+ */
+#define NFS_WRITE_CANCELLED 0x0004 /* has been cancelled */
+#define NFS_WRITE_UNCOMMITTED 0x0008 /* written but uncommitted (NFSv3) */
+#define NFS_WRITE_INVALIDATE 0x0010 /* invalidate after write */
+#define NFS_WRITE_INPROGRESS 0x0100 /* RPC call in progress */
+#define NFS_WRITE_COMPLETE 0x0200 /* RPC call completed */
+
+#define WB_CANCELLED(req) ((req)->wb_flags & NFS_WRITE_CANCELLED)
+#define WB_UNCOMMITTED(req) ((req)->wb_flags & NFS_WRITE_UNCOMMITTED)
+#define WB_INVALIDATE(req) ((req)->wb_flags & NFS_WRITE_INVALIDATE)
+#define WB_INPROGRESS(req) ((req)->wb_flags & NFS_WRITE_INPROGRESS)
+#define WB_COMPLETE(req) ((req)->wb_flags & NFS_WRITE_COMPLETE)
+
+/*
+ * linux/fs/nfs/proc.c
+ */
+extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr);
+extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_sattr *sattr, struct nfs_fattr *fattr);
+extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr);
+extern int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
+ void **p0, char **string, unsigned int *len,
+ unsigned int maxlen);
+extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
+ int swap, unsigned long offset, unsigned int count,
+ void *buffer, struct nfs_fattr *fattr);
+extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
+ int swap, unsigned long offset, unsigned int count,
+ const void *buffer, struct nfs_fattr *fattr);
+extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_sattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name);
+extern int nfs_proc_rename(struct nfs_server *server,
+ struct nfs_fh *old_dir, const char *old_name,
+ struct nfs_fh *new_dir, const char *new_name);
+extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fh *dir, const char *name);
+extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, const char *path,
+ struct nfs_sattr *sattr);
+extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_sattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name);
+extern int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
+ u32 cookie, unsigned int size, __u32 *entry);
+extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *res);
+
+
+/*
+ * linux/fs/nfs/inode.c
+ */
+extern struct super_block *nfs_read_super(struct super_block *, void *, int);
+extern int init_nfs_fs(void);
+extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
+ struct nfs_fattr *);
+extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+extern int nfs_revalidate(struct dentry *);
+extern int nfs_open(struct inode *, struct file *);
+extern int nfs_release(struct inode *, struct file *);
+extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *);
+
+/*
+ * linux/fs/nfs/file.c
+ */
+extern struct inode_operations nfs_file_inode_operations;
+
+/*
+ * linux/fs/nfs/dir.c
+ */
+extern struct inode_operations nfs_dir_inode_operations;
+extern struct dentry_operations nfs_dentry_operations;
+extern void nfs_free_dircache(void);
+extern void nfs_invalidate_dircache(struct inode *);
+extern void nfs_invalidate_dircache_sb(struct super_block *);
+
+/*
+ * linux/fs/nfs/symlink.c
+ */
+extern struct inode_operations nfs_symlink_inode_operations;
+
+/*
+ * linux/fs/nfs/locks.c
+ */
+extern int nfs_lock(struct file *, int, struct file_lock *);
+
+/*
+ * linux/fs/nfs/write.c
+ */
+extern int nfs_writepage(struct file *, struct page *);
+extern int nfs_check_failed_request(struct inode *);
+
+/*
+ * Try to write back everything synchronously (but check the
+ * return value!)
+ */
+extern int nfs_wb_all(struct inode *);
+extern int nfs_wb_page(struct inode *, struct page *);
+extern int nfs_wb_file(struct inode *, struct file *);
+
+/*
+ * Invalidate write-backs, possibly trying to write them
+ * back first..
+ */
+extern void nfs_inval(struct inode *);
+extern int nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int, int);
+
+/*
+ * linux/fs/nfs/read.c
+ */
+extern int nfs_readpage(struct file *, struct page *);
+
+/*
+ * linux/fs/mount_clnt.c
+ * (Used only by nfsroot module)
+ */
+extern int nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+
+/*
+ * inline functions
+ */
+static inline int
+nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
+ return 0;
+ return _nfs_revalidate_inode(server, dentry);
+}
+
+/* NFS root */
+
+extern int nfs_root_mount(struct super_block *sb);
+
+#endif /* __KERNEL__ */
+
+/*
+ * NFS debug flags
+ */
+#define NFSDBG_VFS 0x0001
+#define NFSDBG_DIRCACHE 0x0002
+#define NFSDBG_LOOKUPCACHE 0x0004
+#define NFSDBG_PAGECACHE 0x0008
+#define NFSDBG_PROC 0x0010
+#define NFSDBG_XDR 0x0020
+#define NFSDBG_FILE 0x0040
+#define NFSDBG_ROOT 0x0080
+#define NFSDBG_ALL 0xFFFF
+
+#ifdef __KERNEL__
+# undef ifdebug
+# ifdef NFS_DEBUG
+# define ifdebug(fac) if (nfs_debug & NFSDBG_##fac)
+# else
+# define ifdebug(fac) if (0)
+# endif
+#endif /* __KERNEL */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nfs_fs_i.h b/pfinet/linux-src/include/linux/nfs_fs_i.h
new file mode 100644
index 00000000..885f21f0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nfs_fs_i.h
@@ -0,0 +1,71 @@
+#ifndef _NFS_FS_I
+#define _NFS_FS_I
+
+#include <linux/nfs.h>
+#include <linux/pipe_fs_i.h>
+
+/*
+ * nfs fs inode data in memory
+ */
+struct nfs_inode_info {
+ /*
+ * This is a place holder so named pipes on NFS filesystems
+ * work (more or less correctly). This must be first in the
+ * struct because the data is really accessed via inode->u.pipe_i.
+ */
+ struct pipe_inode_info pipeinfo;
+
+ /*
+ * Various flags
+ */
+ unsigned short flags;
+
+ /*
+ * read_cache_jiffies is when we started read-caching this inode,
+ * and read_cache_mtime is the mtime of the inode at that time.
+ * attrtimeo is for how long the cached information is assumed
+ * to be valid. A successful attribute revalidation doubles
+ * attrtimeo (up to acregmax/acdirmax), a failure resets it to
+ * acregmin/acdirmin.
+ *
+ * We need to revalidate the cached attrs for this inode if
+ *
+ * jiffies - read_cache_jiffies > attrtimeo
+ *
+ * and invalidate any cached data/flush out any dirty pages if
+ * we find that
+ *
+ * mtime != read_cache_mtime
+ */
+ unsigned long read_cache_jiffies;
+ unsigned long read_cache_mtime;
+ unsigned long attrtimeo;
+
+ /*
+ * This is the list of dirty unwritten pages.
+ * NFSv3 will want to add a list for written but uncommitted
+ * pages.
+ */
+ struct nfs_wreq * writeback;
+};
+
+/*
+ * Legal inode flag values
+ */
+#define NFS_INO_REVALIDATE 0x0001 /* revalidating attrs */
+#define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */
+
+/*
+ * NFS lock info
+ */
+struct nfs_lock_info {
+ u32 state;
+ u32 flags;
+};
+
+/*
+ * Lock flag values
+ */
+#define NFS_LCK_GRANTED 0x0001 /* lock has been granted */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nfs_fs_sb.h b/pfinet/linux-src/include/linux/nfs_fs_sb.h
new file mode 100644
index 00000000..343455ec
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nfs_fs_sb.h
@@ -0,0 +1,31 @@
+#ifndef _NFS_FS_SB
+#define _NFS_FS_SB
+
+#include <linux/nfs.h>
+#include <linux/in.h>
+
+/*
+ * NFS client parameters stored in the superblock.
+ */
+struct nfs_server {
+ struct rpc_clnt * client; /* RPC client handle */
+ int flags; /* various flags */
+ int rsize; /* read size */
+ int wsize; /* write size */
+ unsigned int bsize; /* server block size */
+ unsigned int acregmin; /* attr cache timeouts */
+ unsigned int acregmax;
+ unsigned int acdirmin;
+ unsigned int acdirmax;
+ char * hostname; /* remote hostname */
+};
+
+/*
+ * nfs super-block data in memory
+ */
+struct nfs_sb_info {
+ struct nfs_server s_server;
+ struct nfs_fh s_root;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nfs_mount.h b/pfinet/linux-src/include/linux/nfs_mount.h
new file mode 100644
index 00000000..60493b15
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nfs_mount.h
@@ -0,0 +1,53 @@
+#ifndef _LINUX_NFS_MOUNT_H
+#define _LINUX_NFS_MOUNT_H
+
+/*
+ * linux/include/linux/nfs_mount.h
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * structure passed from user-space to kernel-space during an nfs mount
+ */
+
+/*
+ * WARNING! Do not delete or change the order of these fields. If
+ * a new field is required then add it to the end. The version field
+ * tracks which fields are present. This will ensure some measure of
+ * mount-to-kernel version compatibility. Some of these aren't used yet
+ * but here they are anyway.
+ */
+#define NFS_MOUNT_VERSION 3
+
+struct nfs_mount_data {
+ int version; /* 1 */
+ int fd; /* 1 */
+ struct nfs_fh root; /* 1 */
+ int flags; /* 1 */
+ int rsize; /* 1 */
+ int wsize; /* 1 */
+ int timeo; /* 1 */
+ int retrans; /* 1 */
+ int acregmin; /* 1 */
+ int acregmax; /* 1 */
+ int acdirmin; /* 1 */
+ int acdirmax; /* 1 */
+ struct sockaddr_in addr; /* 1 */
+ char hostname[256]; /* 1 */
+ int namlen; /* 2 */
+ unsigned int bsize; /* 3 */
+};
+
+/* bits in the flags field */
+
+#define NFS_MOUNT_SOFT 0x0001 /* 1 */
+#define NFS_MOUNT_INTR 0x0002 /* 1 */
+#define NFS_MOUNT_SECURE 0x0004 /* 1 */
+#define NFS_MOUNT_POSIX 0x0008 /* 1 */
+#define NFS_MOUNT_NOCTO 0x0010 /* 1 */
+#define NFS_MOUNT_NOAC 0x0020 /* 1 */
+#define NFS_MOUNT_TCP 0x0040 /* 2 */
+#define NFS_MOUNT_VER3 0x0080 /* 3 */
+#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
+#define NFS_MOUNT_NONLM 0x0200 /* 3 */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nfsiod.h b/pfinet/linux-src/include/linux/nfsiod.h
new file mode 100644
index 00000000..fdd07a2d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nfsiod.h
@@ -0,0 +1,52 @@
+/*
+ * linux/include/linux/nfsiod.h
+ *
+ * Declarations for asynchronous NFS RPC calls.
+ *
+ */
+
+#ifndef _LINUX_NFSIOD_H
+#define _LINUX_NFSIOD_H
+
+#include <linux/rpcsock.h>
+#include <linux/nfs_fs.h>
+
+#ifdef __KERNEL__
+
+/*
+ * This is the callback handler for nfsiod requests.
+ * Note that the callback procedure must NOT sleep.
+ */
+struct nfsiod_req;
+typedef int (*nfsiod_callback_t)(int result, struct nfsiod_req *);
+
+/*
+ * This is the nfsiod request struct.
+ */
+struct nfsiod_req {
+ struct nfsiod_req * rq_next;
+ struct nfsiod_req * rq_prev;
+ struct wait_queue * rq_wait;
+ struct rpc_ioreq rq_rpcreq;
+ nfsiod_callback_t rq_callback;
+ struct nfs_server * rq_server;
+ struct inode * rq_inode;
+ struct page * rq_page;
+
+ /* user creds */
+ uid_t rq_fsuid;
+ gid_t rq_fsgid;
+ int rq_groups[NGROUPS];
+
+ /* retry handling */
+ int rq_retries;
+};
+
+struct nfsiod_req * nfsiod_reserve(struct nfs_server *);
+void nfsiod_release(struct nfsiod_req *);
+void nfsiod_enqueue(struct nfsiod_req *);
+int nfsiod(void);
+
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_NFSIOD_H */
diff --git a/pfinet/linux-src/include/linux/nls.h b/pfinet/linux-src/include/linux/nls.h
new file mode 100644
index 00000000..efcd5892
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nls.h
@@ -0,0 +1,56 @@
+struct nls_unicode {
+ unsigned char uni1;
+ unsigned char uni2;
+};
+
+struct nls_table {
+ char *charset;
+ unsigned char **page_uni2charset;
+ struct nls_unicode *charset2uni;
+
+ void (*inc_use_count) (void);
+ void (*dec_use_count) (void);
+ struct nls_table *next;
+};
+
+/* nls.c */
+extern int init_nls(void);
+extern int register_nls(struct nls_table *);
+extern int unregister_nls(struct nls_table *);
+extern struct nls_table *find_nls(char *);
+extern struct nls_table *load_nls(char *);
+extern void unload_nls(struct nls_table *);
+extern struct nls_table *load_nls_default(void);
+
+extern int utf8_mbtowc(__u16 *, const __u8 *, int);
+extern int utf8_mbstowcs(__u16 *, const __u8 *, int);
+extern int utf8_wctomb(__u8 *, __u16, int);
+extern int utf8_wcstombs(__u8 *, const __u16 *, int);
+
+extern int init_nls_iso8859_1(void);
+extern int init_nls_iso8859_2(void);
+extern int init_nls_iso8859_3(void);
+extern int init_nls_iso8859_4(void);
+extern int init_nls_iso8859_5(void);
+extern int init_nls_iso8859_6(void);
+extern int init_nls_iso8859_7(void);
+extern int init_nls_iso8859_8(void);
+extern int init_nls_iso8859_9(void);
+extern int init_nls_iso8859_15(void);
+extern int init_nls_cp437(void);
+extern int init_nls_cp737(void);
+extern int init_nls_cp775(void);
+extern int init_nls_cp850(void);
+extern int init_nls_cp852(void);
+extern int init_nls_cp855(void);
+extern int init_nls_cp857(void);
+extern int init_nls_cp860(void);
+extern int init_nls_cp861(void);
+extern int init_nls_cp862(void);
+extern int init_nls_cp863(void);
+extern int init_nls_cp864(void);
+extern int init_nls_cp865(void);
+extern int init_nls_cp866(void);
+extern int init_nls_cp869(void);
+extern int init_nls_cp874(void);
+extern int init_nls_koi8_r(void);
diff --git a/pfinet/linux/notifier.h b/pfinet/linux-src/include/linux/notifier.h
index 78a44649..1e8bf707 100644
--- a/pfinet/linux/notifier.h
+++ b/pfinet/linux-src/include/linux/notifier.h
@@ -13,7 +13,7 @@
struct notifier_block
{
- int (*notifier_call)(unsigned long, void *);
+ int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
struct notifier_block *next;
int priority;
};
@@ -68,7 +68,7 @@ extern __inline__ int notifier_call_chain(struct notifier_block **n, unsigned lo
struct notifier_block *nb = *n;
while(nb)
{
- ret=nb->notifier_call(val,v);
+ ret=nb->notifier_call(nb,val,v);
if(ret&NOTIFY_STOP_MASK)
return ret;
nb=nb->next;
@@ -92,5 +92,24 @@ extern __inline__ int notifier_call_chain(struct notifier_block **n, unsigned lo
detected a hardware crash and restarted
- we can use this eg to kick tcp sessions
once done */
+#define NETDEV_CHANGE 0x0004 /* Notify device state change */
+#define NETDEV_REGISTER 0x0005
+#define NETDEV_UNREGISTER 0x0006
+#define NETDEV_CHANGEMTU 0x0007
+#define NETDEV_CHANGEADDR 0x0008
+#define NETDEV_GOING_DOWN 0x0009
+#define NETDEV_CHANGENAME 0x000A
+
+#define SYS_DOWN 0x0001 /* Notify of system down */
+#define SYS_RESTART SYS_DOWN
+#define SYS_HALT 0x0002 /* Notify of system halt */
+#define SYS_POWER_OFF 0x0003 /* Notify of system power off */
+
+/*
+ * Publicly visible notifier objects
+ */
+
+extern struct notifier_block *boot_notifier_list;
+
#endif
#endif
diff --git a/pfinet/linux-src/include/linux/ntfs_fs.h b/pfinet/linux-src/include/linux/ntfs_fs.h
new file mode 100644
index 00000000..acbfc293
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ntfs_fs.h
@@ -0,0 +1,7 @@
+#ifndef _LINUX_NTFS_FS_H
+#define _LINUX_NTFS_FS_H
+
+int init_ntfs_fs(void);
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/ntfs_fs_i.h b/pfinet/linux-src/include/linux/ntfs_fs_i.h
new file mode 100644
index 00000000..cab27748
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ntfs_fs_i.h
@@ -0,0 +1,83 @@
+#ifndef _LINUX_NTFS_FS_I_H
+#define _LINUX_NTFS_FS_I_H
+
+/* Forward declarations, to keep number of mutual includes low */
+struct ntfs_attribute;
+struct ntfs_sb_info;
+
+/* Duplicate definitions from ntfs/ntfstypes.h */
+#ifndef NTFS_INTEGRAL_TYPES
+#define NTFS_INTEGRAL_TYPES
+typedef u8 ntfs_u8;
+typedef u16 ntfs_u16;
+typedef u32 ntfs_u32;
+typedef u64 ntfs_u64;
+typedef s8 ntfs_s8;
+typedef s16 ntfs_s16;
+typedef s32 ntfs_s32;
+typedef s64 ntfs_s64;
+#endif
+
+#ifndef NTMODE_T
+#define NTMODE_T
+typedef __kernel_mode_t ntmode_t;
+#endif
+#ifndef NTFS_UID_T
+#define NTFS_UID_T
+typedef __kernel_uid_t ntfs_uid_t;
+#endif
+#ifndef NTFS_GID_T
+#define NTFS_GID_T
+typedef __kernel_gid_t ntfs_gid_t;
+#endif
+#ifndef NTFS_SIZE_T
+#define NTFS_SIZE_T
+typedef __kernel_size_t ntfs_size_t;
+#endif
+#ifndef NTFS_TIME_T
+#define NTFS_TIME_T
+typedef __kernel_time_t ntfs_time_t;
+#endif
+
+/* unicode character type */
+#ifndef NTFS_WCHAR_T
+#define NTFS_WCHAR_T
+typedef unsigned short ntfs_wchar_t;
+#endif
+/* file offset */
+#ifndef NTFS_OFFSET_T
+#define NTFS_OFFSET_T
+typedef unsigned long long ntfs_offset_t;
+#endif
+/* UTC */
+#ifndef NTFS_TIME64_T
+#define NTFS_TIME64_T
+typedef unsigned long long ntfs_time64_t;
+#endif
+/* This is really unsigned long long. So we support only volumes up to 2 TB */
+#ifndef NTFS_CLUSTER_T
+#define NTFS_CLUSTER_T
+typedef unsigned int ntfs_cluster_t;
+#endif
+
+/* Definition of NTFS in-memory inode structure */
+struct ntfs_inode_info{
+ struct ntfs_sb_info *vol;
+ int i_number; /* should be really 48 bits */
+ unsigned sequence_number;
+ unsigned char* attr; /* array of the attributes */
+ int attr_count; /* size of attrs[] */
+ struct ntfs_attribute *attrs;
+ int record_count; /* size of records[] */
+ /* array of the record numbers of the MFT
+ whose attributes have been inserted in the inode */
+ int *records;
+ union{
+ struct{
+ int recordsize;
+ int clusters_per_record;
+ }index;
+ } u;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/ntfs_fs_sb.h b/pfinet/linux-src/include/linux/ntfs_fs_sb.h
new file mode 100644
index 00000000..898ef710
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ntfs_fs_sb.h
@@ -0,0 +1,44 @@
+#ifndef _LINUX_NTFS_FS_SB_H
+#define _LINUX_NTFS_FS_SB_H
+
+struct ntfs_sb_info{
+ /* Configuration provided by user at mount time */
+ ntfs_uid_t uid;
+ ntfs_gid_t gid;
+ ntmode_t umask;
+ unsigned int nct;
+ void *nls_map;
+ unsigned int ngt;
+ /* Configuration provided by user with ntfstools */
+ ntfs_size_t partition_bias; /* for access to underlying device */
+ /* Attribute definitions */
+ ntfs_u32 at_standard_information;
+ ntfs_u32 at_attribute_list;
+ ntfs_u32 at_file_name;
+ ntfs_u32 at_security_descriptor;
+ ntfs_u32 at_data;
+ ntfs_u32 at_index_root;
+ ntfs_u32 at_index_allocation;
+ ntfs_u32 at_bitmap;
+ ntfs_u32 at_symlink; /* aka SYMBOLIC_LINK or REPARSE_POINT */
+ /* Data read from the boot file */
+ int blocksize;
+ int clusterfactor;
+ int clustersize;
+ int mft_recordsize;
+ int mft_clusters_per_record;
+ int index_recordsize;
+ int index_clusters_per_record;
+ int mft_cluster;
+ /* data read from special files */
+ unsigned char *mft;
+ unsigned short *upcase;
+ unsigned int upcase_length;
+ /* inodes we always hold onto */
+ struct ntfs_inode_info *mft_ino;
+ struct ntfs_inode_info *mftmirr;
+ struct ntfs_inode_info *bitmap;
+ struct super_block *sb;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/nubus.h b/pfinet/linux-src/include/linux/nubus.h
new file mode 100644
index 00000000..c09b95a9
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nubus.h
@@ -0,0 +1,96 @@
+
+struct nubus_slot
+{
+ int slot_flags;
+#define NUBUS_DEVICE_PRESENT 1
+#define NUBUS_DEVICE_ACTIVE 2
+#define NUBUS_DEVICE_IRQ 4
+ __u32 slot_directory;
+ __u32 slot_dlength;
+ __u32 slot_crc;
+ __u8 slot_rev;
+ __u8 slot_format;
+ __u8 slot_lanes;
+ /*
+ * Stuff we pulled from the directory
+ */
+ __u32 slot_dirbase;
+ __u32 slot_thisdir;
+ char slot_vendor[64];
+ char slot_cardname[64];
+};
+
+struct nbnamevec
+{
+ char *name;
+ int id;
+};
+
+struct nubus_dir
+{
+ unsigned char *base;
+ int length;
+ int count;
+ int mask;
+};
+
+struct nubus_dirent
+{
+ unsigned char type;
+ int value; /* Actually 24bits used */
+ int mask;
+ int base; /* For dirptr function */
+};
+
+struct nubus_type
+{
+ __u16 category;
+ __u16 type;
+ __u16 DrHW;
+ __u16 DrSW;
+};
+
+#define NUBUS_CAT_BOARD 0x0001
+#define NUBUS_CAT_DISPLAY 0x0003
+#define NUBUS_CAT_NETWORK 0x0004
+#define NUBUS_CAT_COMMUNICATIONS 0x0006
+#define NUBUS_CAT_FONT 0x0009
+#define NUBUS_CAT_CPU 0x000A
+
+#define RES_ID_TYPE 0x0001
+#define RES_ID_NAME 0x0002
+#define RES_ID_BOARD_DIR 0x0001
+#define RES_ID_FLAGS 0x0007
+
+struct nubus_device_specifier
+{
+ int (*setup)(struct nubus_device_specifier *, int slot, struct nubus_type *);
+ struct nubus_device_specifier *next;
+};
+
+
+extern void register_nubus_device(struct nubus_device_specifier *nb);
+extern void unregister_nubus_device(struct nubus_device_specifier *nb);
+
+extern struct nubus_dir *nubus_openrootdir(int slot);
+extern struct nubus_dir *nubus_opensubdir(struct nubus_dirent *d);
+extern void nubus_closedir(struct nubus_dir *);
+extern struct nubus_dirent *nubus_readdir(struct nubus_dir *);
+extern unsigned char *nubus_dirptr(struct nubus_dirent *d);
+extern void nubus_strncpy(int slot, void *to, unsigned char *p, int len);
+extern void nubus_memcpy(int slot, void *to, unsigned char *p, int len);
+extern void nubus_init(void);
+extern void nubus_sweep_video(void);
+extern int nubus_ethernet_addr(int slot, unsigned char *addr);
+
+extern __inline void *nubus_slot_addr(int slot)
+{
+ return (void *)(0xF0000000|(slot<<24));
+}
+
+extern int nubus_hwreg_present(volatile void *ptr);
+
+extern void nubus_init_via(void);
+extern int nubus_free_irq(int slot);
+extern int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct pt_regs *));
+
diff --git a/pfinet/linux-src/include/linux/nvram.h b/pfinet/linux-src/include/linux/nvram.h
new file mode 100644
index 00000000..9e05db19
--- /dev/null
+++ b/pfinet/linux-src/include/linux/nvram.h
@@ -0,0 +1,18 @@
+#ifndef _LINUX_NVRAM_H
+#define _LINUX_NVRAM_H
+
+#include <linux/ioctl.h>
+
+/* /dev/nvram ioctls */
+#define NVRAM_INIT _IO('p', 0x40) /* initialize NVRAM and set checksum */
+#define NVRAM_SETCKS _IO('p', 0x41) /* recalculate checksum */
+
+#ifdef __KERNEL__
+extern unsigned char nvram_read_byte( int i );
+extern void nvram_write_byte( unsigned char c, int i );
+extern int nvram_check_checksum( void );
+extern void nvram_set_checksum( void );
+extern int nvram_init( void );
+#endif
+
+#endif /* _LINUX_NVRAM_H */
diff --git a/pfinet/linux-src/include/linux/openpic.h b/pfinet/linux-src/include/linux/openpic.h
new file mode 100644
index 00000000..68102042
--- /dev/null
+++ b/pfinet/linux-src/include/linux/openpic.h
@@ -0,0 +1,362 @@
+/*
+ * linux/openpic.h -- OpenPIC definitions
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * This file is based on the following documentation:
+ *
+ * The Open Programmable Interrupt Controller (PIC)
+ * Register Interface Specification Revision 1.2
+ *
+ * Issue Date: October 1995
+ *
+ * Issued jointly by Advanced Micro Devices and Cyrix Corporation
+ *
+ * AMD is a registered trademark of Advanced Micro Devices, Inc.
+ * Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
+ * All Rights Reserved.
+ *
+ * To receive a copy of this documentation, send an email to openpic@amd.com.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _LINUX_OPENPIC_H
+#define _LINUX_OPENPIC_H
+
+#if !defined(__powerpc__) && !defined(__i386__)
+#error Unsupported OpenPIC platform
+#endif
+
+
+#ifdef __KERNEL__
+
+ /*
+ * OpenPIC supports up to 2048 interrupt sources and up to 32 processors
+ */
+
+#define OPENPIC_MAX_SOURCES 2048
+#define OPENPIC_MAX_PROCESSORS 32
+
+#define OPENPIC_NUM_TIMERS 4
+#define OPENPIC_NUM_IPI 4
+#define OPENPIC_NUM_PRI 16
+#define OPENPIC_NUM_VECTORS 256
+
+
+ /*
+ * Vector numbers
+ */
+
+#define OPENPIC_VEC_TIMER 64 /* and up */
+#define OPENPIC_VEC_IPI 70 /* and up */
+#define OPENPIC_VEC_SPURIOUS 127
+
+
+ /*
+ * OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
+ */
+
+typedef struct _OpenPIC_Reg {
+ u_int Reg; /* Little endian! */
+ char Pad[0xc];
+} OpenPIC_Reg;
+
+
+ /*
+ * Per Processor Registers
+ */
+
+typedef struct _OpenPIC_Processor {
+ /*
+ * Private Shadow Registers (for SLiC backwards compatibility)
+ */
+ u_int IPI0_Dispatch_Shadow; /* Write Only */
+ char Pad1[0x4];
+ u_int IPI0_Vector_Priority_Shadow; /* Read/Write */
+ char Pad2[0x34];
+ /*
+ * Interprocessor Interrupt Command Ports
+ */
+ OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI]; /* Write Only */
+ /*
+ * Current Task Priority Register
+ */
+ OpenPIC_Reg _Current_Task_Priority; /* Read/Write */
+#ifndef __powerpc__
+ /*
+ * Who Am I Register
+ */
+ OpenPIC_Reg _Who_Am_I; /* Read Only */
+#else
+ char Pad3[0x10];
+#endif
+#ifndef __i386__
+ /*
+ * Interrupt Acknowledge Register
+ */
+ OpenPIC_Reg _Interrupt_Acknowledge; /* Read Only */
+#else
+ char Pad4[0x10];
+#endif
+ /*
+ * End of Interrupt (EOI) Register
+ */
+ OpenPIC_Reg _EOI; /* Read/Write */
+ char Pad5[0xf40];
+} OpenPIC_Processor;
+
+
+ /*
+ * Timer Registers
+ */
+
+typedef struct _OpenPIC_Timer {
+ OpenPIC_Reg _Current_Count; /* Read Only */
+ OpenPIC_Reg _Base_Count; /* Read/Write */
+ OpenPIC_Reg _Vector_Priority; /* Read/Write */
+ OpenPIC_Reg _Destination; /* Read/Write */
+} OpenPIC_Timer;
+
+
+ /*
+ * Global Registers
+ */
+
+typedef struct _OpenPIC_Global {
+ /*
+ * Feature Reporting Registers
+ */
+ OpenPIC_Reg _Feature_Reporting0; /* Read Only */
+ OpenPIC_Reg _Feature_Reporting1; /* Future Expansion */
+ /*
+ * Global Configuration Registers
+ */
+ OpenPIC_Reg _Global_Configuration0; /* Read/Write */
+ OpenPIC_Reg _Global_Configuration1; /* Future Expansion */
+ /*
+ * Vendor Specific Registers
+ */
+ OpenPIC_Reg _Vendor_Specific[4];
+ /*
+ * Vendor Identification Register
+ */
+ OpenPIC_Reg _Vendor_Identification; /* Read Only */
+ /*
+ * Processor Initialization Register
+ */
+ OpenPIC_Reg _Processor_Initialization; /* Read/Write */
+ /*
+ * IPI Vector/Priority Registers
+ */
+ OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */
+ /*
+ * Spurious Vector Register
+ */
+ OpenPIC_Reg _Spurious_Vector; /* Read/Write */
+ /*
+ * Global Timer Registers
+ */
+ OpenPIC_Reg _Timer_Frequency; /* Read/Write */
+ OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
+ char Pad1[0xee00];
+} OpenPIC_Global;
+
+
+ /*
+ * Interrupt Source Registers
+ */
+
+typedef struct _OpenPIC_Source {
+ OpenPIC_Reg _Vector_Priority; /* Read/Write */
+ OpenPIC_Reg _Destination; /* Read/Write */
+} OpenPIC_Source;
+
+
+ /*
+ * OpenPIC Register Map
+ */
+
+struct OpenPIC {
+#ifndef __powerpc__
+ /*
+ * Per Processor Registers --- Private Access
+ */
+ OpenPIC_Processor Private;
+#else
+ char Pad1[0x1000];
+#endif
+ /*
+ * Global Registers
+ */
+ OpenPIC_Global Global;
+ /*
+ * Interrupt Source Configuration Registers
+ */
+ OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
+ /*
+ * Per Processor Registers
+ */
+ OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
+};
+
+extern volatile struct OpenPIC *OpenPIC;
+extern u_int OpenPIC_NumInitSenses;
+extern u_char *OpenPIC_InitSenses;
+
+
+ /*
+ * Current Task Priority Register
+ */
+
+#define OPENPIC_CURRENT_TASK_PRIORITY_MASK 0x0000000f
+
+ /*
+ * Who Am I Register
+ */
+
+#define OPENPIC_WHO_AM_I_ID_MASK 0x0000001f
+
+ /*
+ * Feature Reporting Register 0
+ */
+
+#define OPENPIC_FEATURE_LAST_SOURCE_MASK 0x07ff0000
+#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT 16
+#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK 0x00001f00
+#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT 8
+#define OPENPIC_FEATURE_VERSION_MASK 0x000000ff
+
+ /*
+ * Global Configuration Register 0
+ */
+
+#define OPENPIC_CONFIG_RESET 0x80000000
+#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE 0x20000000
+#define OPENPIC_CONFIG_BASE_MASK 0x000fffff
+
+ /*
+ * Vendor Identification Register
+ */
+
+#define OPENPIC_VENDOR_ID_STEPPING_MASK 0x00ff0000
+#define OPENPIC_VENDOR_ID_STEPPING_SHIFT 16
+#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00
+#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT 8
+#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK 0x000000ff
+
+ /*
+ * Vector/Priority Registers
+ */
+
+#define OPENPIC_MASK 0x80000000
+#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */
+#define OPENPIC_PRIORITY_MASK 0x000f0000
+#define OPENPIC_PRIORITY_SHIFT 16
+#define OPENPIC_VECTOR_MASK 0x000000ff
+
+
+ /*
+ * Interrupt Source Registers
+ */
+
+#define OPENPIC_SENSE_POLARITY 0x00800000 /* Undoc'd */
+#define OPENPIC_SENSE_LEVEL 0x00400000
+
+
+ /*
+ * Timer Registers
+ */
+
+#define OPENPIC_COUNT_MASK 0x7fffffff
+#define OPENPIC_TIMER_TOGGLE 0x80000000
+#define OPENPIC_TIMER_COUNT_INHIBIT 0x80000000
+
+
+ /*
+ * Aliases to make life simpler
+ */
+
+/* Per Processor Registers */
+#define IPI_Dispatch(i) _IPI_Dispatch[i].Reg
+#define Current_Task_Priority _Current_Task_Priority.Reg
+#ifndef __powerpc__
+#define Who_Am_I _Who_Am_I.Reg
+#endif
+#ifndef __i386__
+#define Interrupt_Acknowledge _Interrupt_Acknowledge.Reg
+#endif
+#define EOI _EOI.Reg
+
+/* Global Registers */
+#define Feature_Reporting0 _Feature_Reporting0.Reg
+#define Feature_Reporting1 _Feature_Reporting1.Reg
+#define Global_Configuration0 _Global_Configuration0.Reg
+#define Global_Configuration1 _Global_Configuration1.Reg
+#define Vendor_Specific(i) _Vendor_Specific[i].Reg
+#define Vendor_Identification _Vendor_Identification.Reg
+#define Processor_Initialization _Processor_Initialization.Reg
+#define IPI_Vector_Priority(i) _IPI_Vector_Priority[i].Reg
+#define Spurious_Vector _Spurious_Vector.Reg
+#define Timer_Frequency _Timer_Frequency.Reg
+
+/* Timer Registers */
+#define Current_Count _Current_Count.Reg
+#define Base_Count _Base_Count.Reg
+#define Vector_Priority _Vector_Priority.Reg
+#define Destination _Destination.Reg
+
+/* Interrupt Source Registers */
+#define Vector_Priority _Vector_Priority.Reg
+#define Destination _Destination.Reg
+
+ /*
+ * OpenPIC Operations
+ */
+
+/* Global Operations */
+extern void openpic_init(int);
+extern void openpic_reset(void);
+extern void openpic_enable_8259_pass_through(void);
+extern void openpic_disable_8259_pass_through(void);
+#ifndef __i386__
+extern u_int openpic_irq(u_int cpu);
+#endif
+#ifndef __powerpc__
+extern void openpic_eoi(void);
+extern u_int openpic_get_priority(void);
+extern void openpic_set_priority(u_int pri);
+#else
+extern void openpic_eoi(u_int cpu);
+extern u_int openpic_get_priority(u_int cpu);
+extern void openpic_set_priority(u_int cpu, u_int pri);
+#endif
+extern u_int openpic_get_spurious(void);
+extern void openpic_set_spurious(u_int vector);
+extern void openpic_init_processor(u_int cpumask);
+
+/* Interprocessor Interrupts */
+extern void openpic_initipi(u_int ipi, u_int pri, u_int vector);
+#ifndef __powerpc__
+extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
+#else
+extern void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask);
+#endif
+
+/* Timer Interrupts */
+extern void openpic_inittimer(u_int timer, u_int pri, u_int vector);
+extern void openpic_maptimer(u_int timer, u_int cpumask);
+
+/* Interrupt Sources */
+extern void openpic_enable_irq(u_int irq);
+extern void openpic_disable_irq(u_int irq);
+extern void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
+ int is_level);
+extern void openpic_mapirq(u_int irq, u_int cpumask);
+extern void openpic_set_sense(u_int irq, int sense);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_OPENPIC_H */
diff --git a/pfinet/linux-src/include/linux/pagemap.h b/pfinet/linux-src/include/linux/pagemap.h
new file mode 100644
index 00000000..9bf5efd8
--- /dev/null
+++ b/pfinet/linux-src/include/linux/pagemap.h
@@ -0,0 +1,156 @@
+#ifndef _LINUX_PAGEMAP_H
+#define _LINUX_PAGEMAP_H
+
+#include <asm/system.h>
+
+/*
+ * Page-mapping primitive inline functions
+ *
+ * Copyright 1995 Linus Torvalds
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+
+static inline unsigned long page_address(struct page * page)
+{
+ return PAGE_OFFSET + PAGE_SIZE * (page - mem_map);
+}
+
+/*
+ * The page cache can done in larger chunks than
+ * one page, because it allows for more efficient
+ * throughput (it can then be mapped into user
+ * space in smaller chunks for same flexibility).
+ *
+ * Or rather, it _will_ be done in larger chunks.
+ */
+#define PAGE_CACHE_SHIFT PAGE_SHIFT
+#define PAGE_CACHE_SIZE PAGE_SIZE
+#define PAGE_CACHE_MASK PAGE_MASK
+
+#define page_cache_alloc() __get_free_page(GFP_USER)
+#define page_cache_free(x) free_page(x)
+#define page_cache_release(x) __free_page(x)
+
+/*
+ * From a kernel address, get the "struct page *"
+ */
+#define page_cache_entry(x) (mem_map + MAP_NR(x))
+
+#define PAGE_HASH_BITS page_hash_bits
+#define PAGE_HASH_MASK page_hash_mask
+
+extern unsigned long page_cache_size; /* # of pages currently in the hash table */
+extern unsigned int page_hash_bits;
+extern unsigned int page_hash_mask;
+extern struct page **page_hash_table;
+
+extern void page_cache_init(unsigned long);
+
+/*
+ * We use a power-of-two hash table to avoid a modulus,
+ * and get a reasonable hash by knowing roughly how the
+ * inode pointer and offsets are distributed (ie, we
+ * roughly know which bits are "significant")
+ */
+static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
+{
+#define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
+#define o ((offset >> PAGE_SHIFT) + (offset & ~PAGE_MASK))
+ return ((i+o) & PAGE_HASH_MASK);
+#undef i
+#undef o
+}
+
+#define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))
+
+static inline struct page * __find_page(struct inode * inode, unsigned long offset, struct page *page)
+{
+ goto inside;
+ for (;;) {
+ page = page->next_hash;
+inside:
+ if (!page)
+ goto not_found;
+ if (page->inode != inode)
+ continue;
+ if (page->offset == offset)
+ break;
+ }
+ /* Found the page. */
+ atomic_inc(&page->count);
+ set_bit(PG_referenced, &page->flags);
+not_found:
+ return page;
+}
+
+static inline struct page *find_page(struct inode * inode, unsigned long offset)
+{
+ return __find_page(inode, offset, *page_hash(inode, offset));
+}
+
+static inline void remove_page_from_hash_queue(struct page * page)
+{
+ if(page->pprev_hash) {
+ if(page->next_hash)
+ page->next_hash->pprev_hash = page->pprev_hash;
+ *page->pprev_hash = page->next_hash;
+ page->pprev_hash = NULL;
+ }
+ page_cache_size--;
+}
+
+static inline void __add_page_to_hash_queue(struct page * page, struct page **p)
+{
+ page_cache_size++;
+ if((page->next_hash = *p) != NULL)
+ (*p)->pprev_hash = &page->next_hash;
+ *p = page;
+ page->pprev_hash = p;
+}
+
+static inline void add_page_to_hash_queue(struct page * page, struct inode * inode, unsigned long offset)
+{
+ __add_page_to_hash_queue(page, page_hash(inode,offset));
+}
+
+static inline void remove_page_from_inode_queue(struct page * page)
+{
+ struct inode * inode = page->inode;
+
+ page->inode = NULL;
+ inode->i_nrpages--;
+ if (inode->i_pages == page)
+ inode->i_pages = page->next;
+ if (page->next)
+ page->next->prev = page->prev;
+ if (page->prev)
+ page->prev->next = page->next;
+ page->next = NULL;
+ page->prev = NULL;
+}
+
+static inline void add_page_to_inode_queue(struct inode * inode, struct page * page)
+{
+ struct page **p = &inode->i_pages;
+
+ inode->i_nrpages++;
+ page->inode = inode;
+ page->prev = NULL;
+ if ((page->next = *p) != NULL)
+ page->next->prev = page;
+ *p = page;
+}
+
+extern void __wait_on_page(struct page *);
+static inline void wait_on_page(struct page * page)
+{
+ if (PageLocked(page))
+ __wait_on_page(page);
+}
+
+extern void update_vm_cache_conditional(struct inode *, unsigned long, const char *, int, unsigned long);
+extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/param.h b/pfinet/linux-src/include/linux/param.h
new file mode 100644
index 00000000..092e92f6
--- /dev/null
+++ b/pfinet/linux-src/include/linux/param.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_PARAM_H
+#define _LINUX_PARAM_H
+
+#include <asm/param.h>
+
+#endif
diff --git a/pfinet/linux-src/include/linux/parport.h b/pfinet/linux-src/include/linux/parport.h
new file mode 100644
index 00000000..856fc016
--- /dev/null
+++ b/pfinet/linux-src/include/linux/parport.h
@@ -0,0 +1,396 @@
+/* $Id: parport.h,v 1.1 1998/05/17 10:57:52 andrea Exp andrea $ */
+
+#ifndef _PARPORT_H_
+#define _PARPORT_H_
+
+/* Start off with user-visible constants */
+
+/* Maximum of 8 ports per machine */
+#define PARPORT_MAX 8
+
+/* Magic numbers */
+#define PARPORT_IRQ_NONE -1
+#define PARPORT_DMA_NONE -1
+#define PARPORT_IRQ_AUTO -2
+#define PARPORT_DMA_AUTO -2
+#define PARPORT_DISABLE -2
+#define PARPORT_IRQ_PROBEONLY -3
+
+#define PARPORT_CONTROL_STROBE 0x1
+#define PARPORT_CONTROL_AUTOFD 0x2
+#define PARPORT_CONTROL_INIT 0x4
+#define PARPORT_CONTROL_SELECT 0x8
+#define PARPORT_CONTROL_INTEN 0x10
+#define PARPORT_CONTROL_DIRECTION 0x20
+
+#define PARPORT_STATUS_ERROR 0x8
+#define PARPORT_STATUS_SELECT 0x10
+#define PARPORT_STATUS_PAPEROUT 0x20
+#define PARPORT_STATUS_ACK 0x40
+#define PARPORT_STATUS_BUSY 0x80
+
+/* Type classes for Plug-and-Play probe. */
+typedef enum {
+ PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */
+ PARPORT_CLASS_PRINTER,
+ PARPORT_CLASS_MODEM,
+ PARPORT_CLASS_NET,
+ PARPORT_CLASS_HDC, /* Hard disk controller */
+ PARPORT_CLASS_PCMCIA,
+ PARPORT_CLASS_MEDIA, /* Multimedia device */
+ PARPORT_CLASS_FDC, /* Floppy disk controller */
+ PARPORT_CLASS_PORTS,
+ PARPORT_CLASS_SCANNER,
+ PARPORT_CLASS_DIGCAM,
+ PARPORT_CLASS_OTHER, /* Anything else */
+ PARPORT_CLASS_UNSPEC /* No CLS field in ID */
+} parport_device_class;
+
+/* The "modes" entry in parport is a bit field representing the following
+ * modes.
+ * Note that PARPORT_MODE_PCECPEPP is for the SMC EPP+ECP mode which is NOT
+ * 100% compatible with EPP.
+ */
+#define PARPORT_MODE_PCSPP 0x0001
+#define PARPORT_MODE_PCPS2 0x0002
+#define PARPORT_MODE_PCEPP 0x0004
+#define PARPORT_MODE_PCECP 0x0008
+#define PARPORT_MODE_PCECPEPP 0x0010
+#define PARPORT_MODE_PCECR 0x0020 /* ECR Register Exists */
+#define PARPORT_MODE_PCECPPS2 0x0040
+
+/* The rest is for the kernel only */
+#ifdef __KERNEL__
+
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/config.h>
+
+#define PARPORT_NEED_GENERIC_OPS
+
+/* Define this later. */
+struct parport;
+
+struct pc_parport_state {
+ unsigned int ctr;
+ unsigned int ecr;
+};
+
+struct parport_state {
+ union {
+ struct pc_parport_state pc;
+ /* ARC has no state. */
+ /* AX uses same state information as PC */
+ void *misc;
+ } u;
+};
+
+struct parport_operations {
+ void (*write_data)(struct parport *, unsigned char);
+ unsigned char (*read_data)(struct parport *);
+ void (*write_control)(struct parport *, unsigned char);
+ unsigned char (*read_control)(struct parport *);
+ unsigned char (*frob_control)(struct parport *, unsigned char mask, unsigned char val);
+ void (*write_econtrol)(struct parport *, unsigned char);
+ unsigned char (*read_econtrol)(struct parport *);
+ unsigned char (*frob_econtrol)(struct parport *, unsigned char mask, unsigned char val);
+ void (*write_status)(struct parport *, unsigned char);
+ unsigned char (*read_status)(struct parport *);
+ void (*write_fifo)(struct parport *, unsigned char);
+ unsigned char (*read_fifo)(struct parport *);
+
+ void (*change_mode)(struct parport *, int);
+
+ void (*release_resources)(struct parport *);
+ int (*claim_resources)(struct parport *);
+
+ void (*epp_write_data)(struct parport *, unsigned char);
+ unsigned char (*epp_read_data)(struct parport *);
+ void (*epp_write_addr)(struct parport *, unsigned char);
+ unsigned char (*epp_read_addr)(struct parport *);
+ int (*epp_check_timeout)(struct parport *);
+ size_t (*epp_write_block)(struct parport *, void *, size_t);
+ size_t (*epp_read_block)(struct parport *, void *, size_t);
+
+ int (*ecp_write_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
+ int (*ecp_read_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
+
+ void (*init_state)(struct parport_state *);
+ void (*save_state)(struct parport *, struct parport_state *);
+ void (*restore_state)(struct parport *, struct parport_state *);
+
+ void (*enable_irq)(struct parport *);
+ void (*disable_irq)(struct parport *);
+ void (*interrupt)(int, void *, struct pt_regs *);
+
+ void (*inc_use_count)(void);
+ void (*dec_use_count)(void);
+ void (*fill_inode)(struct inode *inode, int fill);
+};
+
+struct parport_device_info {
+ parport_device_class class;
+ const char *class_name;
+ const char *mfr;
+ const char *model;
+ const char *cmdset;
+ const char *description;
+};
+
+/* Each device can have two callback functions:
+ * 1) a preemption function, called by the resource manager to request
+ * that the driver relinquish control of the port. The driver should
+ * return zero if it agrees to release the port, and nonzero if it
+ * refuses. Do not call parport_release() - the kernel will do this
+ * implicitly.
+ *
+ * 2) a wake-up function, called by the resource manager to tell drivers
+ * that the port is available to be claimed. If a driver wants to use
+ * the port, it should call parport_claim() here.
+ */
+
+/* A parallel port device */
+struct pardevice {
+ const char *name;
+ struct parport *port;
+ int (*preempt)(void *);
+ void (*wakeup)(void *);
+ void *private;
+ void (*irq_func)(int, void *, struct pt_regs *);
+ unsigned int flags;
+ struct pardevice *next;
+ struct pardevice *prev;
+ struct parport_state *state; /* saved status over preemption */
+ struct wait_queue *wait_q;
+ unsigned long int time;
+ unsigned long int timeslice;
+ unsigned int waiting;
+ struct pardevice *waitprev;
+ struct pardevice *waitnext;
+};
+
+/* Directory information for the /proc interface */
+struct parport_dir {
+ struct proc_dir_entry *entry; /* Directory /proc/parport/X */
+ struct proc_dir_entry *irq; /* .../irq */
+ struct proc_dir_entry *devices; /* .../devices */
+ struct proc_dir_entry *hardware; /* .../hardware */
+ struct proc_dir_entry *probe; /* .../autoprobe */
+ char name[4];
+};
+
+/* A parallel port */
+struct parport {
+ unsigned long base; /* base address */
+ unsigned int size; /* IO extent */
+ const char *name;
+ int irq; /* interrupt (or -1 for none) */
+ int dma;
+ unsigned int modes;
+
+ struct pardevice *devices;
+ struct pardevice *cad; /* port owner */
+
+ struct pardevice *waithead;
+ struct pardevice *waittail;
+
+ struct parport *next;
+ unsigned int flags;
+
+ struct parport_dir pdir;
+ struct parport_device_info probe_info;
+
+ struct parport_operations *ops;
+ void *private_data; /* for lowlevel driver */
+
+ int number; /* port index - the `n' in `parportn' */
+ spinlock_t pardevice_lock;
+ spinlock_t waitlist_lock;
+ rwlock_t cad_lock;
+
+ /* PCI parallel I/O card support. */
+ unsigned long base_hi; /* base address (hi - ECR) */
+};
+
+/* parport_register_port registers a new parallel port at the given address (if
+ * one does not already exist) and returns a pointer to it. This entails
+ * claiming the I/O region, IRQ and DMA.
+ * NULL is returned if initialisation fails.
+ */
+struct parport *parport_register_port(unsigned long base, int irq, int dma,
+ struct parport_operations *ops);
+
+/* Unregister a port. */
+extern void parport_unregister_port(struct parport *port);
+
+/* parport_in_use returns nonzero if there are devices attached to a port. */
+#define parport_in_use(x) ((x)->devices != NULL)
+
+/* Put a parallel port to sleep; release its hardware resources. Only possible
+ * if no devices are registered. */
+extern void parport_quiesce(struct parport *);
+
+/* parport_enumerate returns a pointer to the linked list of all the ports
+ * in this machine.
+ */
+struct parport *parport_enumerate(void);
+
+/* parport_register_device declares that a device is connected to a port, and
+ * tells the kernel all it needs to know.
+ * pf is the preemption function (may be NULL for no callback)
+ * kf is the wake-up function (may be NULL for no callback)
+ * irq_func is the interrupt handler (may be NULL for no interrupts)
+ * handle is a user pointer that gets handed to callback functions.
+ */
+struct pardevice *parport_register_device(struct parport *port,
+ const char *name,
+ int (*pf)(void *), void (*kf)(void *),
+ void (*irq_func)(int, void *, struct pt_regs *),
+ int flags, void *handle);
+
+/* parport_unregister unlinks a device from the chain. */
+extern void parport_unregister_device(struct pardevice *dev);
+
+/* parport_claim tries to gain ownership of the port for a particular driver.
+ * This may fail (return non-zero) if another driver is busy. If this
+ * driver has registered an interrupt handler, it will be enabled.
+ */
+extern int parport_claim(struct pardevice *dev);
+
+/* parport_claim_or_block is the same, but sleeps if the port cannot be
+ claimed. Return value is 1 if it slept, 0 normally and -errno on error. */
+extern int parport_claim_or_block(struct pardevice *dev);
+
+/* parport_release reverses a previous parport_claim. This can never fail,
+ * though the effects are undefined (except that they are bad) if you didn't
+ * previously own the port. Once you have released the port you should make
+ * sure that neither your code nor the hardware on the port tries to initiate
+ * any communication without first re-claiming the port.
+ * If you mess with the port state (enabling ECP for example) you should
+ * clean up before releasing the port.
+ */
+
+extern void parport_release(struct pardevice *dev);
+
+/* parport_yield relinquishes the port if it would be helpful to other
+ * drivers. The return value is the same as for parport_claim.
+ */
+extern __inline__ int parport_yield(struct pardevice *dev)
+{
+ unsigned long int timeslip = (jiffies - dev->time);
+ if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
+ return 0;
+ parport_release(dev);
+ return parport_claim(dev);
+}
+
+/* parport_yield_blocking is the same but uses parport_claim_or_block
+ * instead of parport_claim.
+ */
+extern __inline__ int parport_yield_blocking(struct pardevice *dev)
+{
+ unsigned long int timeslip = (jiffies - dev->time);
+ if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
+ return 0;
+ parport_release(dev);
+ return parport_claim_or_block(dev);
+}
+
+/*
+ * Lowlevel drivers _can_ call this support function to handle irqs.
+ */
+extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+ struct pt_regs *regs)
+{
+ read_lock(&port->cad_lock);
+ if (!port->cad)
+ goto out_unlock;
+ if (port->cad->irq_func)
+ port->cad->irq_func(irq, port->cad->private, regs);
+ else
+ printk(KERN_ERR "%s: irq%d happened with irq_func NULL "
+ "with %s as cad!\n", port->name, irq, port->cad->name);
+ out_unlock:
+ read_unlock(&port->cad_lock);
+}
+
+/* Flags used to identify what a device does. */
+#define PARPORT_DEV_TRAN 0 /* WARNING !! DEPRECATED !! */
+#define PARPORT_DEV_LURK (1<<0) /* WARNING !! DEPRECATED !! */
+#define PARPORT_DEV_EXCL (1<<1) /* Need exclusive access. */
+
+#define PARPORT_FLAG_COMA (1<<0)
+#define PARPORT_FLAG_EXCL (1<<1) /* EXCL driver registered. */
+
+extern void parport_parse_irqs(int, const char *[], int irqval[]);
+extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
+extern int parport_wait_peripheral(struct parport *, unsigned char, unsigned
+ char);
+
+/* Prototypes from parport_procfs */
+extern int parport_proc_init(void);
+extern void parport_proc_cleanup(void);
+extern int parport_proc_register(struct parport *pp);
+extern int parport_proc_unregister(struct parport *pp);
+
+extern void dec_parport_count(void);
+extern void inc_parport_count(void);
+
+extern int parport_probe(struct parport *port, char *buffer, int len);
+extern void parport_probe_one(struct parport *port);
+extern void (*parport_probe_hook)(struct parport *port);
+
+/* If PC hardware is the only type supported, we can optimise a bit. */
+#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#undef PARPORT_NEED_GENERIC_OPS
+#include <linux/parport_pc.h>
+#define parport_write_data(p,x) parport_pc_write_data(p,x)
+#define parport_read_data(p) parport_pc_read_data(p)
+#define parport_write_control(p,x) parport_pc_write_control(p,x)
+#define parport_read_control(p) parport_pc_read_control(p)
+#define parport_frob_control(p,m,v) parport_pc_frob_control(p,m,v)
+#define parport_write_econtrol(p,x) parport_pc_write_econtrol(p,x)
+#define parport_read_econtrol(p) parport_pc_read_econtrol(p)
+#define parport_frob_econtrol(p,m,v) parport_pc_frob_econtrol(p,m,v)
+#define parport_write_status(p,v) parport_pc_write_status(p,v)
+#define parport_read_status(p) parport_pc_read_status(p)
+#define parport_write_fifo(p,v) parport_pc_write_fifo(p,v)
+#define parport_read_fifo(p) parport_pc_read_fifo(p)
+#define parport_change_mode(p,m) parport_pc_change_mode(p,m)
+#define parport_release_resources(p) parport_pc_release_resources(p)
+#define parport_claim_resources(p) parport_pc_claim_resources(p)
+#define parport_epp_write_data(p,x) parport_pc_write_epp(p,x)
+#define parport_epp_read_data(p) parport_pc_read_epp(p)
+#define parport_epp_write_addr(p,x) parport_pc_write_epp_addr(p,x)
+#define parport_epp_read_addr(p) parport_pc_read_epp_addr(p)
+#define parport_epp_check_timeout(p) parport_pc_check_epp_timeout(p)
+#endif
+
+#ifdef PARPORT_NEED_GENERIC_OPS
+/* Generic operations vector through the dispatch table. */
+#define parport_write_data(p,x) (p)->ops->write_data(p,x)
+#define parport_read_data(p) (p)->ops->read_data(p)
+#define parport_write_control(p,x) (p)->ops->write_control(p,x)
+#define parport_read_control(p) (p)->ops->read_control(p)
+#define parport_frob_control(p,m,v) (p)->ops->frob_control(p,m,v)
+#define parport_write_econtrol(p,x) (p)->ops->write_econtrol(p,x)
+#define parport_read_econtrol(p) (p)->ops->read_econtrol(p)
+#define parport_frob_econtrol(p,m,v) (p)->ops->frob_econtrol(p,m,v)
+#define parport_write_status(p,v) (p)->ops->write_status(p,v)
+#define parport_read_status(p) (p)->ops->read_status(p)
+#define parport_write_fifo(p,v) (p)->ops->write_fifo(p,v)
+#define parport_read_fifo(p) (p)->ops->read_fifo(p)
+#define parport_change_mode(p,m) (p)->ops->change_mode(p,m)
+#define parport_release_resources(p) (p)->ops->release_resources(p)
+#define parport_claim_resources(p) (p)->ops->claim_resources(p)
+#define parport_epp_write_data(p,x) (p)->ops->epp_write_data(p,x)
+#define parport_epp_read_data(p) (p)->ops->epp_read_data(p)
+#define parport_epp_write_addr(p,x) (p)->ops->epp_write_addr(p,x)
+#define parport_epp_read_addr(p) (p)->ops->epp_read_addr(p)
+#define parport_epp_check_timeout(p) (p)->ops->epp_check_timeout(p)
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* _PARPORT_H_ */
diff --git a/pfinet/linux-src/include/linux/parport_pc.h b/pfinet/linux-src/include/linux/parport_pc.h
new file mode 100644
index 00000000..f7ef3406
--- /dev/null
+++ b/pfinet/linux-src/include/linux/parport_pc.h
@@ -0,0 +1,152 @@
+#ifndef __LINUX_PARPORT_PC_H
+#define __LINUX_PARPORT_PC_H
+
+#include <asm/io.h>
+
+/* --- register definitions ------------------------------- */
+
+#define ECONTROL(p) ((p)->base_hi + 0x2)
+#define CONFIGB(p) ((p)->base_hi + 0x1)
+#define CONFIGA(p) ((p)->base_hi + 0x0)
+#define FIFO(p) ((p)->base_hi + 0x0)
+#define EPPDATA(p) ((p)->base + 0x4)
+#define EPPADDR(p) ((p)->base + 0x3)
+#define CONTROL(p) ((p)->base + 0x2)
+#define STATUS(p) ((p)->base + 0x1)
+#define DATA(p) ((p)->base + 0x0)
+
+/* Private data for PC low-level driver. */
+struct parport_pc_private {
+ /* Contents of CTR. */
+ unsigned char ctr;
+};
+
+extern int parport_pc_epp_clear_timeout(struct parport *pb);
+
+extern volatile unsigned char parport_pc_ctr;
+
+extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
+{
+ outb(d, EPPDATA(p));
+}
+
+extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
+{
+ return inb(EPPDATA(p));
+}
+
+extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+{
+ outb(d, EPPADDR(p));
+}
+
+extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
+{
+ return inb(EPPADDR(p));
+}
+
+extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
+{
+ if (!(inb(STATUS(p)) & 1))
+ return 0;
+ parport_pc_epp_clear_timeout(p);
+ return 1;
+}
+
+extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
+{
+ return inb(CONFIGB(p));
+}
+
+extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
+{
+ outb(d, DATA(p));
+}
+
+extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
+{
+ return inb(DATA(p));
+}
+
+extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
+{
+ struct parport_pc_private *priv = p->private_data;
+ priv->ctr = d;/* update soft copy */
+ outb(d, CONTROL(p));
+}
+
+extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
+{
+ struct parport_pc_private *priv = p->private_data;
+ return priv->ctr;
+}
+
+extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
+{
+ struct parport_pc_private *priv = p->private_data;
+ unsigned char ctr = priv->ctr;
+ ctr = (ctr & ~mask) ^ val;
+ outb (ctr, CONTROL(p));
+ return priv->ctr = ctr; /* update soft copy */
+}
+
+extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
+{
+ outb(d, STATUS(p));
+}
+
+extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
+{
+ return inb(STATUS(p));
+}
+
+extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d)
+{
+ outb(d, ECONTROL(p));
+}
+
+extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p)
+{
+ return inb(ECONTROL(p));
+}
+
+extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
+{
+ unsigned char old = inb(ECONTROL(p));
+ outb(((old & ~mask) ^ val), ECONTROL(p));
+ return old;
+}
+
+extern void parport_pc_change_mode(struct parport *p, int m);
+
+extern void parport_pc_write_fifo(struct parport *p, unsigned char v);
+
+extern unsigned char parport_pc_read_fifo(struct parport *p);
+
+extern void parport_pc_disable_irq(struct parport *p);
+
+extern void parport_pc_enable_irq(struct parport *p);
+
+extern void parport_pc_release_resources(struct parport *p);
+
+extern int parport_pc_claim_resources(struct parport *p);
+
+extern void parport_pc_init_state(struct parport_state *s);
+
+extern void parport_pc_save_state(struct parport *p, struct parport_state *s);
+
+extern void parport_pc_restore_state(struct parport *p, struct parport_state *s);
+
+extern size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length);
+
+extern size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length);
+
+extern int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
+
+extern int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
+
+extern void parport_pc_inc_use_count(void);
+
+extern void parport_pc_dec_use_count(void);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/pc_keyb.h b/pfinet/linux-src/include/linux/pc_keyb.h
new file mode 100644
index 00000000..29ccd395
--- /dev/null
+++ b/pfinet/linux-src/include/linux/pc_keyb.h
@@ -0,0 +1,130 @@
+/*
+ * include/linux/pc_keyb.h
+ *
+ * PC Keyboard And Keyboard Controller
+ *
+ * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+/*
+ * Configuration Switches
+ */
+
+#undef KBD_REPORT_ERR /* Report keyboard errors */
+#define KBD_REPORT_UNKN /* Report unknown scan codes */
+#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */
+#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
+#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */
+
+
+
+#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */
+#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
+#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */
+
+/*
+ * Internal variables of the driver
+ */
+
+extern unsigned char pckbd_read_mask;
+extern unsigned char aux_device_present;
+
+/*
+ * Keyboard Controller Registers on normal PCs.
+ */
+
+#define KBD_STATUS_REG 0x64 /* Status register (R) */
+#define KBD_CNTL_REG 0x64 /* Controller command register (W) */
+#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
+
+/*
+ * Keyboard Controller Commands
+ */
+
+#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
+#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
+#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
+#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
+#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
+#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
+ initiated by the auxiliary device */
+#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
+
+/*
+ * Keyboard Commands
+ */
+
+#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
+#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
+#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
+#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */
+#define KBD_CMD_RESET 0xFF /* Reset */
+
+/*
+ * Keyboard Replies
+ */
+
+#define KBD_REPLY_POR 0xAA /* Power on reset */
+#define KBD_REPLY_ACK 0xFA /* Command ACK */
+#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
+
+/*
+ * Status Register Bits
+ */
+
+#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
+#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
+#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
+#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
+#define KBD_STAT_PERR 0x80 /* Parity error */
+
+#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
+
+/*
+ * Controller Mode Register Bits
+ */
+
+#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
+#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS 0x04 /* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
+#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
+#define KBD_MODE_RFU 0x80
+
+/*
+ * Mouse Commands
+ */
+
+#define AUX_SET_RES 0xE8 /* Set resolution */
+#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
+#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
+#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
+#define AUX_SET_STREAM 0xEA /* Set stream mode */
+#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
+#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
+#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
+#define AUX_RESET 0xFF /* Reset aux device */
+#define AUX_ACK 0xFA /* Command byte ACK. */
+
+#define AUX_BUF_SIZE 2048 /* This might be better divisible by
+ three to make overruns stay in sync
+ but then the read function would need
+ a lock etc - ick */
+
+struct aux_queue {
+ unsigned long head;
+ unsigned long tail;
+ struct wait_queue *proc_list;
+ struct fasync_struct *fasync;
+ unsigned char buf[AUX_BUF_SIZE];
+};
diff --git a/pfinet/linux-src/include/linux/pci.h b/pfinet/linux-src/include/linux/pci.h
new file mode 100644
index 00000000..6ad71fa4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/pci.h
@@ -0,0 +1,1359 @@
+/*
+ * $Id: pci.h,v 1.87 1998/10/11 15:13:12 mj Exp $
+ *
+ * PCI defines and function prototypes
+ * Copyright 1994, Drew Eckhardt
+ * Copyright 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ */
+
+#ifndef LINUX_PCI_H
+#define LINUX_PCI_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
+#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
+#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
+#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
+#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
+#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
+#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
+#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
+#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
+
+#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
+#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF 0x40 /* Support User Definable Features */
+#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
+#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
+#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
+#define PCI_STATUS_DEVSEL_FAST 0x000
+#define PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define PCI_STATUS_DEVSEL_SLOW 0x400
+#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8
+ revision */
+#define PCI_REVISION_ID 0x08 /* Revision ID */
+#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+
+#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
+#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
+#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+#define PCI_HEADER_TYPE_NORMAL 0
+#define PCI_HEADER_TYPE_BRIDGE 1
+#define PCI_HEADER_TYPE_CARDBUS 2
+
+#define PCI_BIST 0x0f /* 8 bits */
+#define PCI_BIST_CODE_MASK 0x0f /* Return result */
+#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back. Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
+#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
+#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
+#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
+#define PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
+#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
+#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS 0x28
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+#define PCI_SUBSYSTEM_ID 0x2e
+#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
+#define PCI_MIN_GNT 0x3e /* 8 bits */
+#define PCI_MAX_LAT 0x3f /* 8 bits */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
+#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
+#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
+#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
+#define PCI_IO_LIMIT 0x1d
+#define PCI_IO_RANGE_TYPE_MASK 0x0f /* I/O bridging type */
+#define PCI_IO_RANGE_TYPE_16 0x00
+#define PCI_IO_RANGE_TYPE_32 0x01
+#define PCI_IO_RANGE_MASK ~0x0f
+#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
+#define PCI_MEMORY_LIMIT 0x22
+#define PCI_MEMORY_RANGE_TYPE_MASK 0x0f
+#define PCI_MEMORY_RANGE_MASK ~0x0f
+#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT 0x26
+#define PCI_PREF_RANGE_TYPE_MASK 0x0f
+#define PCI_PREF_RANGE_TYPE_32 0x00
+#define PCI_PREF_RANGE_TYPE_64 0x01
+#define PCI_PREF_RANGE_MASK ~0x0f
+#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32 0x2c
+#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16 0x32
+/* 0x34-0x3b is reserved */
+#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL 0x3e
+#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */
+#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
+#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */
+#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
+#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
+#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
+#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+/* 0x14-0x15 reserved */
+#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
+#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
+#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0 0x1c
+#define PCI_CB_MEMORY_LIMIT_0 0x20
+#define PCI_CB_MEMORY_BASE_1 0x24
+#define PCI_CB_MEMORY_LIMIT_1 0x28
+#define PCI_CB_IO_BASE_0 0x2c
+#define PCI_CB_IO_BASE_0_HI 0x2e
+#define PCI_CB_IO_LIMIT_0 0x30
+#define PCI_CB_IO_LIMIT_0_HI 0x32
+#define PCI_CB_IO_BASE_1 0x34
+#define PCI_CB_IO_BASE_1_HI 0x36
+#define PCI_CB_IO_LIMIT_1 0x38
+#define PCI_CB_IO_LIMIT_1_HI 0x3a
+#define PCI_CB_IO_RANGE_MASK ~0x03
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL 0x3e
+#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */
+#define PCI_CB_BRIDGE_CTL_SERR 0x02
+#define PCI_CB_BRIDGE_CTL_ISA 0x04
+#define PCI_CB_BRIDGE_CTL_VGA 0x08
+#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
+#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
+#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
+#define PCI_CB_SUBSYSTEM_ID 0x42
+#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+#define PCI_CAP_LIST_ID 0 /* Capability ID */
+#define PCI_CAP_ID_PM 0x01 /* Power Management */
+#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
+#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED 0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA 0x0001
+
+#define PCI_BASE_CLASS_STORAGE 0x01
+#define PCI_CLASS_STORAGE_SCSI 0x0100
+#define PCI_CLASS_STORAGE_IDE 0x0101
+#define PCI_CLASS_STORAGE_FLOPPY 0x0102
+#define PCI_CLASS_STORAGE_IPI 0x0103
+#define PCI_CLASS_STORAGE_RAID 0x0104
+#define PCI_CLASS_STORAGE_OTHER 0x0180
+
+#define PCI_BASE_CLASS_NETWORK 0x02
+#define PCI_CLASS_NETWORK_ETHERNET 0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201
+#define PCI_CLASS_NETWORK_FDDI 0x0202
+#define PCI_CLASS_NETWORK_ATM 0x0203
+#define PCI_CLASS_NETWORK_OTHER 0x0280
+
+#define PCI_BASE_CLASS_DISPLAY 0x03
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_DISPLAY_XGA 0x0301
+#define PCI_CLASS_DISPLAY_OTHER 0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA 0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
+#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
+
+#define PCI_BASE_CLASS_MEMORY 0x05
+#define PCI_CLASS_MEMORY_RAM 0x0500
+#define PCI_CLASS_MEMORY_FLASH 0x0501
+#define PCI_CLASS_MEMORY_OTHER 0x0580
+
+#define PCI_BASE_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_HOST 0x0600
+#define PCI_CLASS_BRIDGE_ISA 0x0601
+#define PCI_CLASS_BRIDGE_EISA 0x0602
+#define PCI_CLASS_BRIDGE_MC 0x0603
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+#define PCI_CLASS_BRIDGE_PCMCIA 0x0605
+#define PCI_CLASS_BRIDGE_NUBUS 0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS 0x0607
+#define PCI_CLASS_BRIDGE_OTHER 0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION 0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
+
+#define PCI_BASE_CLASS_SYSTEM 0x08
+#define PCI_CLASS_SYSTEM_PIC 0x0800
+#define PCI_CLASS_SYSTEM_DMA 0x0801
+#define PCI_CLASS_SYSTEM_TIMER 0x0802
+#define PCI_CLASS_SYSTEM_RTC 0x0803
+#define PCI_CLASS_SYSTEM_OTHER 0x0880
+
+#define PCI_BASE_CLASS_INPUT 0x09
+#define PCI_CLASS_INPUT_KEYBOARD 0x0900
+#define PCI_CLASS_INPUT_PEN 0x0901
+#define PCI_CLASS_INPUT_MOUSE 0x0902
+#define PCI_CLASS_INPUT_OTHER 0x0980
+
+#define PCI_BASE_CLASS_DOCKING 0x0a
+#define PCI_CLASS_DOCKING_GENERIC 0x0a00
+#define PCI_CLASS_DOCKING_OTHER 0x0a01
+
+#define PCI_BASE_CLASS_PROCESSOR 0x0b
+#define PCI_CLASS_PROCESSOR_386 0x0b00
+#define PCI_CLASS_PROCESSOR_486 0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
+#define PCI_CLASS_PROCESSOR_CO 0x0b40
+
+#define PCI_BASE_CLASS_SERIAL 0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
+#define PCI_CLASS_SERIAL_ACCESS 0x0c01
+#define PCI_CLASS_SERIAL_SSA 0x0c02
+#define PCI_CLASS_SERIAL_USB 0x0c03
+#define PCI_CLASS_SERIAL_FIBER 0x0c04
+
+#define PCI_CLASS_HOT_SWAP_CONTROLLER 0xff00
+
+#define PCI_CLASS_OTHERS 0xff
+
+/*
+ * Vendor and card ID's: sort these numerically according to vendor
+ * (and according to card ID within vendor). Send all updates to
+ * <linux-pcisupport@cck.uni-kl.de>.
+ */
+#define PCI_VENDOR_ID_COMPAQ 0x0e11
+#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508
+#define PCI_DEVICE_ID_COMPAQ_1280 0x3033
+#define PCI_DEVICE_ID_COMPAQ_TRIFLEX 0x4000
+#define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae10
+#define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32
+#define PCI_DEVICE_ID_COMPAQ_NETEL10 0xae34
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I 0xae35
+#define PCI_DEVICE_ID_COMPAQ_NETEL100D 0xae40
+#define PCI_DEVICE_ID_COMPAQ_NETEL100PI 0xae43
+#define PCI_DEVICE_ID_COMPAQ_NETEL100I 0xb011
+#define PCI_DEVICE_ID_COMPAQ_THUNDER 0xf130
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B 0xf150
+
+#define PCI_VENDOR_ID_NCR 0x1000
+#define PCI_DEVICE_ID_NCR_53C810 0x0001
+#define PCI_DEVICE_ID_NCR_53C820 0x0002
+#define PCI_DEVICE_ID_NCR_53C825 0x0003
+#define PCI_DEVICE_ID_NCR_53C815 0x0004
+#define PCI_DEVICE_ID_NCR_53C860 0x0006
+#define PCI_DEVICE_ID_NCR_53C1510D 0x000a
+#define PCI_DEVICE_ID_NCR_53C896 0x000b
+#define PCI_DEVICE_ID_NCR_53C895 0x000c
+#define PCI_DEVICE_ID_NCR_53C885 0x000d
+#define PCI_DEVICE_ID_NCR_53C875 0x000f
+#define PCI_DEVICE_ID_NCR_53C1510 0x0010
+#define PCI_DEVICE_ID_NCR_53C875J 0x008f
+
+#define PCI_VENDOR_ID_ATI 0x1002
+#define PCI_DEVICE_ID_ATI_68800 0x4158
+#define PCI_DEVICE_ID_ATI_215CT222 0x4354
+#define PCI_DEVICE_ID_ATI_210888CX 0x4358
+#define PCI_DEVICE_ID_ATI_215GB 0x4742
+#define PCI_DEVICE_ID_ATI_215GD 0x4744
+#define PCI_DEVICE_ID_ATI_215GI 0x4749
+#define PCI_DEVICE_ID_ATI_215GP 0x4750
+#define PCI_DEVICE_ID_ATI_215GQ 0x4751
+#define PCI_DEVICE_ID_ATI_215GT 0x4754
+#define PCI_DEVICE_ID_ATI_215GTB 0x4755
+#define PCI_DEVICE_ID_ATI_210888GX 0x4758
+#define PCI_DEVICE_ID_ATI_215LG 0x4c47
+#define PCI_DEVICE_ID_ATI_264LT 0x4c54
+#define PCI_DEVICE_ID_ATI_264VT 0x5654
+
+#define PCI_VENDOR_ID_VLSI 0x1004
+#define PCI_DEVICE_ID_VLSI_82C592 0x0005
+#define PCI_DEVICE_ID_VLSI_82C593 0x0006
+#define PCI_DEVICE_ID_VLSI_82C594 0x0007
+#define PCI_DEVICE_ID_VLSI_82C597 0x0009
+#define PCI_DEVICE_ID_VLSI_82C541 0x000c
+#define PCI_DEVICE_ID_VLSI_82C543 0x000d
+#define PCI_DEVICE_ID_VLSI_82C532 0x0101
+#define PCI_DEVICE_ID_VLSI_82C534 0x0102
+#define PCI_DEVICE_ID_VLSI_82C535 0x0104
+#define PCI_DEVICE_ID_VLSI_82C147 0x0105
+#define PCI_DEVICE_ID_VLSI_VAS96011 0x0702
+
+#define PCI_VENDOR_ID_ADL 0x1005
+#define PCI_DEVICE_ID_ADL_2301 0x2301
+
+#define PCI_VENDOR_ID_NS 0x100b
+#define PCI_DEVICE_ID_NS_87415 0x0002
+#define PCI_DEVICE_ID_NS_87410 0xd001
+
+#define PCI_VENDOR_ID_TSENG 0x100c
+#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202
+#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205
+#define PCI_DEVICE_ID_TSENG_W32P_c 0x3206
+#define PCI_DEVICE_ID_TSENG_W32P_d 0x3207
+#define PCI_DEVICE_ID_TSENG_ET6000 0x3208
+
+#define PCI_VENDOR_ID_WEITEK 0x100e
+#define PCI_DEVICE_ID_WEITEK_P9000 0x9001
+#define PCI_DEVICE_ID_WEITEK_P9100 0x9100
+
+#define PCI_VENDOR_ID_DEC 0x1011
+#define PCI_DEVICE_ID_DEC_BRD 0x0001
+#define PCI_DEVICE_ID_DEC_TULIP 0x0002
+#define PCI_DEVICE_ID_DEC_TGA 0x0004
+#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
+#define PCI_DEVICE_ID_DEC_TGA2 0x000D
+#define PCI_DEVICE_ID_DEC_FDDI 0x000F
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
+#define PCI_DEVICE_ID_DEC_21142 0x0019
+#define PCI_DEVICE_ID_DEC_21052 0x0021
+#define PCI_DEVICE_ID_DEC_21150 0x0022
+#define PCI_DEVICE_ID_DEC_21152 0x0024
+#define PCI_DEVICE_ID_DEC_21153 0x0025
+#define PCI_DEVICE_ID_DEC_21154 0x0026
+#define PCI_DEVICE_ID_DEC_21285 0x1065
+#define PCI_DEVICE_ID_COMPAQ_42XX 0x0046
+
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+#define PCI_DEVICE_ID_CIRRUS_7548 0x0038
+#define PCI_DEVICE_ID_CIRRUS_5430 0x00a0
+#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4
+#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8
+#define PCI_DEVICE_ID_CIRRUS_5436 0x00ac
+#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8
+#define PCI_DEVICE_ID_CIRRUS_5480 0x00bc
+#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4
+#define PCI_DEVICE_ID_CIRRUS_5465 0x00d6
+#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
+#define PCI_DEVICE_ID_CIRRUS_6832 0x1110
+#define PCI_DEVICE_ID_CIRRUS_7542 0x1200
+#define PCI_DEVICE_ID_CIRRUS_7543 0x1202
+#define PCI_DEVICE_ID_CIRRUS_7541 0x1204
+
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_DEVICE_ID_IBM_FIRE_CORAL 0x000a
+#define PCI_DEVICE_ID_IBM_TR 0x0018
+#define PCI_DEVICE_ID_IBM_82G2675 0x001d
+#define PCI_DEVICE_ID_IBM_MCA 0x0020
+#define PCI_DEVICE_ID_IBM_82351 0x0022
+#define PCI_DEVICE_ID_IBM_PYTHON 0x002d
+#define PCI_DEVICE_ID_IBM_SERVERAID 0x002e
+#define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e
+#define PCI_DEVICE_ID_IBM_MPIC 0x0046
+#define PCI_DEVICE_ID_IBM_3780IDSP 0x007d
+#define PCI_DEVICE_ID_IBM_MPIC_2 0xffff
+
+#define PCI_VENDOR_ID_WD 0x101c
+#define PCI_DEVICE_ID_WD_7197 0x3296
+
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_DEVICE_ID_AMD_LANCE 0x2000
+#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
+#define PCI_DEVICE_ID_AMD_SCSI 0x2020
+
+#define PCI_VENDOR_ID_TRIDENT 0x1023
+#define PCI_DEVICE_ID_TRIDENT_9397 0x9397
+#define PCI_DEVICE_ID_TRIDENT_9420 0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440 0x9440
+#define PCI_DEVICE_ID_TRIDENT_9660 0x9660
+#define PCI_DEVICE_ID_TRIDENT_9750 0x9750
+
+#define PCI_VENDOR_ID_AI 0x1025
+#define PCI_DEVICE_ID_AI_M1435 0x1435
+
+#define PCI_VENDOR_ID_MATROX 0x102B
+#define PCI_DEVICE_ID_MATROX_MGA_2 0x0518
+#define PCI_DEVICE_ID_MATROX_MIL 0x0519
+#define PCI_DEVICE_ID_MATROX_MYS 0x051A
+#define PCI_DEVICE_ID_MATROX_MIL_2 0x051b
+#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f
+#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
+#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
+#define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10
+#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000
+#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
+
+#define PCI_VENDOR_ID_CT 0x102c
+#define PCI_DEVICE_ID_CT_65545 0x00d8
+#define PCI_DEVICE_ID_CT_65548 0x00dc
+#define PCI_DEVICE_ID_CT_65550 0x00e0
+#define PCI_DEVICE_ID_CT_65554 0x00e4
+#define PCI_DEVICE_ID_CT_65555 0x00e5
+
+#define PCI_VENDOR_ID_MIRO 0x1031
+#define PCI_DEVICE_ID_MIRO_36050 0x5601
+
+#define PCI_VENDOR_ID_NEC 0x1033
+#define PCI_DEVICE_ID_NEC_PCX2 0x0046
+
+#define PCI_VENDOR_ID_FD 0x1036
+#define PCI_DEVICE_ID_FD_36C70 0x0000
+
+#define PCI_VENDOR_ID_SI 0x1039
+#define PCI_DEVICE_ID_SI_5591_AGP 0x0001
+#define PCI_DEVICE_ID_SI_6202 0x0002
+#define PCI_DEVICE_ID_SI_503 0x0008
+#define PCI_DEVICE_ID_SI_ACPI 0x0009
+#define PCI_DEVICE_ID_SI_5597_VGA 0x0200
+#define PCI_DEVICE_ID_SI_6205 0x0205
+#define PCI_DEVICE_ID_SI_501 0x0406
+#define PCI_DEVICE_ID_SI_496 0x0496
+#define PCI_DEVICE_ID_SI_601 0x0601
+#define PCI_DEVICE_ID_SI_5107 0x5107
+#define PCI_DEVICE_ID_SI_5511 0x5511
+#define PCI_DEVICE_ID_SI_5513 0x5513
+#define PCI_DEVICE_ID_SI_5571 0x5571
+#define PCI_DEVICE_ID_SI_5591 0x5591
+#define PCI_DEVICE_ID_SI_5597 0x5597
+#define PCI_DEVICE_ID_SI_7001 0x7001
+
+#define PCI_VENDOR_ID_HP 0x103c
+#define PCI_DEVICE_ID_HP_J2585A 0x1030
+#define PCI_DEVICE_ID_HP_J2585B 0x1031
+
+#define PCI_VENDOR_ID_PCTECH 0x1042
+#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000
+#define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_0 0x3000
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_1 0x3010
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
+
+#define PCI_VENDOR_ID_DPT 0x1044
+#define PCI_DEVICE_ID_DPT 0xa400
+
+#define PCI_VENDOR_ID_OPTI 0x1045
+#define PCI_DEVICE_ID_OPTI_92C178 0xc178
+#define PCI_DEVICE_ID_OPTI_82C557 0xc557
+#define PCI_DEVICE_ID_OPTI_82C558 0xc558
+#define PCI_DEVICE_ID_OPTI_82C621 0xc621
+#define PCI_DEVICE_ID_OPTI_82C700 0xc700
+#define PCI_DEVICE_ID_OPTI_82C701 0xc701
+#define PCI_DEVICE_ID_OPTI_82C814 0xc814
+#define PCI_DEVICE_ID_OPTI_82C822 0xc822
+#define PCI_DEVICE_ID_OPTI_82C861 0xc861
+#define PCI_DEVICE_ID_OPTI_82C825 0xd568
+
+#define PCI_VENDOR_ID_SGS 0x104a
+#define PCI_DEVICE_ID_SGS_2000 0x0008
+#define PCI_DEVICE_ID_SGS_1764 0x0009
+
+#define PCI_VENDOR_ID_BUSLOGIC 0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040
+#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130
+
+#define PCI_VENDOR_ID_TI 0x104c
+#define PCI_DEVICE_ID_TI_TVP4010 0x3d04
+#define PCI_DEVICE_ID_TI_TVP4020 0x3d07
+#define PCI_DEVICE_ID_TI_PCI1130 0xac12
+#define PCI_DEVICE_ID_TI_PCI1031 0xac13
+#define PCI_DEVICE_ID_TI_PCI1131 0xac15
+#define PCI_DEVICE_ID_TI_PCI1250 0xac16
+#define PCI_DEVICE_ID_TI_PCI1220 0xac17
+
+#define PCI_VENDOR_ID_OAK 0x104e
+#define PCI_DEVICE_ID_OAK_OTI107 0x0107
+
+/* Winbond have two vendor IDs! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2 0x1050
+#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
+
+#define PCI_VENDOR_ID_MOTOROLA 0x1057
+#define PCI_VENDOR_ID_MOTOROLA_OOPS 0x1507
+#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001
+#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
+#define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802
+#define PCI_DEVICE_ID_MOTOROLA_CPX8216 0x4806
+
+#define PCI_VENDOR_ID_PROMISE 0x105a
+#define PCI_DEVICE_ID_PROMISE_20246 0x4d33
+#define PCI_DEVICE_ID_PROMISE_5300 0x5300
+
+#define PCI_VENDOR_ID_N9 0x105d
+#define PCI_DEVICE_ID_N9_I128 0x2309
+#define PCI_DEVICE_ID_N9_I128_2 0x2339
+#define PCI_DEVICE_ID_N9_I128_T2R 0x493d
+
+#define PCI_VENDOR_ID_UMC 0x1060
+#define PCI_DEVICE_ID_UMC_UM8673F 0x0101
+#define PCI_DEVICE_ID_UMC_UM8891A 0x0891
+#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a
+#define PCI_DEVICE_ID_UMC_UM8886A 0x886a
+#define PCI_DEVICE_ID_UMC_UM8881F 0x8881
+#define PCI_DEVICE_ID_UMC_UM8886F 0x8886
+#define PCI_DEVICE_ID_UMC_UM9017F 0x9017
+#define PCI_DEVICE_ID_UMC_UM8886N 0xe886
+#define PCI_DEVICE_ID_UMC_UM8891N 0xe891
+
+#define PCI_VENDOR_ID_X 0x1061
+#define PCI_DEVICE_ID_X_AGX016 0x0001
+
+#define PCI_VENDOR_ID_PICOP 0x1066
+#define PCI_DEVICE_ID_PICOP_PT86C52X 0x0001
+#define PCI_DEVICE_ID_PICOP_PT80C524 0x8002
+
+#define PCI_VENDOR_ID_MYLEX 0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V2 0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V3 0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V4 0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V5 0x0020
+
+#define PCI_VENDOR_ID_APPLE 0x106b
+#define PCI_DEVICE_ID_APPLE_BANDIT 0x0001
+#define PCI_DEVICE_ID_APPLE_GC 0x0002
+#define PCI_DEVICE_ID_APPLE_HYDRA 0x000e
+
+#define PCI_VENDOR_ID_NEXGEN 0x1074
+#define PCI_DEVICE_ID_NEXGEN_82C501 0x4e78
+
+#define PCI_VENDOR_ID_QLOGIC 0x1077
+#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020
+#define PCI_DEVICE_ID_QLOGIC_ISP1022 0x1022
+#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100
+#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200
+
+#define PCI_VENDOR_ID_CYRIX 0x1078
+#define PCI_DEVICE_ID_CYRIX_5510 0x0000
+#define PCI_DEVICE_ID_CYRIX_PCI_MASTER 0x0001
+#define PCI_DEVICE_ID_CYRIX_5520 0x0002
+#define PCI_DEVICE_ID_CYRIX_5530_LEGACY 0x0100
+#define PCI_DEVICE_ID_CYRIX_5530_SMI 0x0101
+#define PCI_DEVICE_ID_CYRIX_5530_IDE 0x0102
+#define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103
+#define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104
+
+#define PCI_VENDOR_ID_LEADTEK 0x107d
+#define PCI_DEVICE_ID_LEADTEK_805 0x0000
+
+#define PCI_VENDOR_ID_CONTAQ 0x1080
+#define PCI_DEVICE_ID_CONTAQ_82C599 0x0600
+#define PCI_DEVICE_ID_CONTAQ_82C693 0xc693
+
+#define PCI_VENDOR_ID_FOREX 0x1083
+
+#define PCI_VENDOR_ID_OLICOM 0x108d
+#define PCI_DEVICE_ID_OLICOM_OC3136 0x0001
+#define PCI_DEVICE_ID_OLICOM_OC2315 0x0011
+#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012
+#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013
+#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014
+#define PCI_DEVICE_ID_OLICOM_OC6151 0x0021
+
+#define PCI_VENDOR_ID_SUN 0x108e
+#define PCI_DEVICE_ID_SUN_EBUS 0x1000
+#define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001
+#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
+#define PCI_DEVICE_ID_SUN_PBM 0x8000
+#define PCI_DEVICE_ID_SUN_SABRE 0xa000
+
+#define PCI_VENDOR_ID_CMD 0x1095
+#define PCI_DEVICE_ID_CMD_640 0x0640
+#define PCI_DEVICE_ID_CMD_643 0x0643
+#define PCI_DEVICE_ID_CMD_646 0x0646
+#define PCI_DEVICE_ID_CMD_647 0x0647
+#define PCI_DEVICE_ID_CMD_670 0x0670
+
+#define PCI_VENDOR_ID_VISION 0x1098
+#define PCI_DEVICE_ID_VISION_QD8500 0x0001
+#define PCI_DEVICE_ID_VISION_QD8580 0x0002
+
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#define PCI_DEVICE_ID_BROOKTREE_848 0x0350
+#define PCI_DEVICE_ID_BROOKTREE_849A 0x0351
+#define PCI_DEVICE_ID_BROOKTREE_878_1 0x036e
+#define PCI_DEVICE_ID_BROOKTREE_878 0x0878
+#define PCI_DEVICE_ID_BROOKTREE_8474 0x8474
+
+#define PCI_VENDOR_ID_SIERRA 0x10a8
+#define PCI_DEVICE_ID_SIERRA_STB 0x0000
+
+#define PCI_VENDOR_ID_ACC 0x10aa
+#define PCI_DEVICE_ID_ACC_2056 0x0000
+
+#define PCI_VENDOR_ID_WINBOND 0x10ad
+#define PCI_DEVICE_ID_WINBOND_83769 0x0001
+#define PCI_DEVICE_ID_WINBOND_82C105 0x0105
+#define PCI_DEVICE_ID_WINBOND_83C553 0x0565
+
+#define PCI_VENDOR_ID_DATABOOK 0x10b3
+#define PCI_DEVICE_ID_DATABOOK_87144 0xb106
+
+#define PCI_VENDOR_ID_PLX 0x10b5
+#define PCI_DEVICE_ID_PLX_9050 0x9050
+#define PCI_DEVICE_ID_PLX_9060 0x9060
+#define PCI_DEVICE_ID_PLX_9060ES 0x906E
+#define PCI_DEVICE_ID_PLX_9060SD 0x906D
+#define PCI_DEVICE_ID_PLX_9080 0x9080
+
+#define PCI_VENDOR_ID_MADGE 0x10b6
+#define PCI_DEVICE_ID_MADGE_MK2 0x0002
+#define PCI_DEVICE_ID_MADGE_C155S 0x1001
+
+#define PCI_VENDOR_ID_3COM 0x10b7
+#define PCI_DEVICE_ID_3COM_3C985 0x0001
+#define PCI_DEVICE_ID_3COM_3C339 0x3390
+#define PCI_DEVICE_ID_3COM_3C590 0x5900
+#define PCI_DEVICE_ID_3COM_3C595TX 0x5950
+#define PCI_DEVICE_ID_3COM_3C595T4 0x5951
+#define PCI_DEVICE_ID_3COM_3C595MII 0x5952
+#define PCI_DEVICE_ID_3COM_3C900TPO 0x9000
+#define PCI_DEVICE_ID_3COM_3C900COMBO 0x9001
+#define PCI_DEVICE_ID_3COM_3C905TX 0x9050
+#define PCI_DEVICE_ID_3COM_3C905T4 0x9051
+#define PCI_DEVICE_ID_3COM_3C905B_TX 0x9055
+
+#define PCI_VENDOR_ID_SMC 0x10b8
+#define PCI_DEVICE_ID_SMC_EPIC100 0x0005
+
+#define PCI_VENDOR_ID_AL 0x10b9
+#define PCI_DEVICE_ID_AL_M1445 0x1445
+#define PCI_DEVICE_ID_AL_M1449 0x1449
+#define PCI_DEVICE_ID_AL_M1451 0x1451
+#define PCI_DEVICE_ID_AL_M1461 0x1461
+#define PCI_DEVICE_ID_AL_M1489 0x1489
+#define PCI_DEVICE_ID_AL_M1511 0x1511
+#define PCI_DEVICE_ID_AL_M1513 0x1513
+#define PCI_DEVICE_ID_AL_M1521 0x1521
+#define PCI_DEVICE_ID_AL_M1523 0x1523
+#define PCI_DEVICE_ID_AL_M1531 0x1531
+#define PCI_DEVICE_ID_AL_M1533 0x1533
+#define PCI_DEVICE_ID_AL_M3307 0x3307
+#define PCI_DEVICE_ID_AL_M4803 0x5215
+#define PCI_DEVICE_ID_AL_M5219 0x5219
+#define PCI_DEVICE_ID_AL_M5229 0x5229
+#define PCI_DEVICE_ID_AL_M5237 0x5237
+#define PCI_DEVICE_ID_AL_M7101 0x7101
+
+#define PCI_VENDOR_ID_MITSUBISHI 0x10ba
+
+#define PCI_VENDOR_ID_SURECOM 0x10bd
+#define PCI_DEVICE_ID_SURECOM_NE34 0x0e34
+
+#define PCI_VENDOR_ID_NEOMAGIC 0x10c8
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128V 0x0002
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZV 0x0003
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICMEDIA_256AV 0x0005
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZVPLUS 0x0083
+
+#define PCI_VENDOR_ID_ASP 0x10cd
+#define PCI_DEVICE_ID_ASP_ABP940 0x1200
+#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
+#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
+
+#define PCI_VENDOR_ID_MACRONIX 0x10d9
+#define PCI_DEVICE_ID_MACRONIX_MX98713 0x0512
+#define PCI_DEVICE_ID_MACRONIX_MX987x5 0x0531
+
+#define PCI_VENDOR_ID_CERN 0x10dc
+#define PCI_DEVICE_ID_CERN_SPSB_PMC 0x0001
+#define PCI_DEVICE_ID_CERN_SPSB_PCI 0x0002
+#define PCI_DEVICE_ID_CERN_HIPPI_DST 0x0021
+#define PCI_DEVICE_ID_CERN_HIPPI_SRC 0x0022
+
+#define PCI_VENDOR_ID_NVIDIA 0x10de
+
+#define PCI_VENDOR_ID_IMS 0x10e0
+#define PCI_DEVICE_ID_IMS_8849 0x8849
+
+#define PCI_VENDOR_ID_TEKRAM2 0x10e1
+#define PCI_DEVICE_ID_TEKRAM2_690c 0x690c
+
+#define PCI_VENDOR_ID_TUNDRA 0x10e3
+#define PCI_DEVICE_ID_TUNDRA_CA91C042 0x0000
+
+#define PCI_VENDOR_ID_AMCC 0x10e8
+#define PCI_DEVICE_ID_AMCC_MYRINET 0x8043
+#define PCI_DEVICE_ID_AMCC_PARASTATION 0x8062
+#define PCI_DEVICE_ID_AMCC_S5933 0x807d
+#define PCI_DEVICE_ID_AMCC_S5933_HEPC3 0x809c
+
+#define PCI_VENDOR_ID_INTERG 0x10ea
+#define PCI_DEVICE_ID_INTERG_1680 0x1680
+#define PCI_DEVICE_ID_INTERG_1682 0x1682
+
+#define PCI_VENDOR_ID_REALTEK 0x10ec
+#define PCI_DEVICE_ID_REALTEK_8029 0x8029
+#define PCI_DEVICE_ID_REALTEK_8129 0x8129
+#define PCI_DEVICE_ID_REALTEK_8139 0x8139
+
+#define PCI_VENDOR_ID_TRUEVISION 0x10fa
+#define PCI_DEVICE_ID_TRUEVISION_T1000 0x000c
+
+#define PCI_VENDOR_ID_INIT 0x1101
+#define PCI_DEVICE_ID_INIT_320P 0x9100
+#define PCI_DEVICE_ID_INIT_360P 0x9500
+
+#define PCI_VENDOR_ID_TTI 0x1103
+#define PCI_DEVICE_ID_TTI_HPT343 0x0003
+
+#define PCI_VENDOR_ID_VIA 0x1106
+#define PCI_DEVICE_ID_VIA_82C505 0x0505
+#define PCI_DEVICE_ID_VIA_82C561 0x0561
+#define PCI_DEVICE_ID_VIA_82C586_1 0x0571
+#define PCI_DEVICE_ID_VIA_82C576 0x0576
+#define PCI_DEVICE_ID_VIA_82C585 0x0585
+#define PCI_DEVICE_ID_VIA_82C586_0 0x0586
+#define PCI_DEVICE_ID_VIA_82C595 0x0595
+#define PCI_DEVICE_ID_VIA_82C596_0 0x0596
+#define PCI_DEVICE_ID_VIA_82C597_0 0x0597
+#define PCI_DEVICE_ID_VIA_82C598_0 0x0598
+#define PCI_DEVICE_ID_VIA_82C926 0x0926
+#define PCI_DEVICE_ID_VIA_82C416 0x1571
+#define PCI_DEVICE_ID_VIA_82C595_97 0x1595
+#define PCI_DEVICE_ID_VIA_82C586_2 0x3038
+#define PCI_DEVICE_ID_VIA_82C586_3 0x3040
+#define PCI_DEVICE_ID_VIA_82C686_5 0x3058
+#define PCI_DEVICE_ID_VIA_86C100A 0x6100
+#define PCI_DEVICE_ID_VIA_82C597_1 0x8597
+#define PCI_DEVICE_ID_VIA_82C598_1 0x8598
+
+#define PCI_VENDOR_ID_SMC2 0x1113
+#define PCI_DEVICE_ID_SMC2_1211TX 0x1211
+
+#define PCI_VENDOR_ID_VORTEX 0x1119
+#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000
+#define PCI_DEVICE_ID_VORTEX_GDT6000B 0x0001
+#define PCI_DEVICE_ID_VORTEX_GDT6x10 0x0002
+#define PCI_DEVICE_ID_VORTEX_GDT6x20 0x0003
+#define PCI_DEVICE_ID_VORTEX_GDT6530 0x0004
+#define PCI_DEVICE_ID_VORTEX_GDT6550 0x0005
+#define PCI_DEVICE_ID_VORTEX_GDT6x17 0x0006
+#define PCI_DEVICE_ID_VORTEX_GDT6x27 0x0007
+#define PCI_DEVICE_ID_VORTEX_GDT6537 0x0008
+#define PCI_DEVICE_ID_VORTEX_GDT6557 0x0009
+#define PCI_DEVICE_ID_VORTEX_GDT6x15 0x000a
+#define PCI_DEVICE_ID_VORTEX_GDT6x25 0x000b
+#define PCI_DEVICE_ID_VORTEX_GDT6535 0x000c
+#define PCI_DEVICE_ID_VORTEX_GDT6555 0x000d
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x0100
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x0101
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x0102
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x0103
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x0104
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x0105
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP1 0x0110
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP1 0x0111
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP1 0x0112
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP1 0x0113
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP1 0x0114
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP1 0x0115
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP2 0x0120
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP2 0x0121
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP2 0x0122
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP2 0x0123
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP2 0x0124
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP2 0x0125
+
+#define PCI_VENDOR_ID_EF 0x111a
+#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000
+#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002
+
+#define PCI_VENDOR_ID_FORE 0x1127
+#define PCI_DEVICE_ID_FORE_PCA200PC 0x0210
+#define PCI_DEVICE_ID_FORE_PCA200E 0x0300
+
+#define PCI_VENDOR_ID_IMAGINGTECH 0x112f
+#define PCI_DEVICE_ID_IMAGINGTECH_ICPCI 0x0000
+
+#define PCI_VENDOR_ID_PHILIPS 0x1131
+#define PCI_DEVICE_ID_PHILIPS_SAA7145 0x7145
+#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146
+
+#define PCI_VENDOR_ID_CYCLONE 0x113c
+#define PCI_DEVICE_ID_CYCLONE_SDK 0x0001
+
+#define PCI_VENDOR_ID_ALLIANCE 0x1142
+#define PCI_DEVICE_ID_ALLIANCE_PROMOTIO 0x3210
+#define PCI_DEVICE_ID_ALLIANCE_PROVIDEO 0x6422
+#define PCI_DEVICE_ID_ALLIANCE_AT24 0x6424
+#define PCI_DEVICE_ID_ALLIANCE_AT3D 0x643d
+
+#define PCI_VENDOR_ID_SYSKONNECT 0x1148
+#define PCI_DEVICE_ID_SYSKONNECT_FP 0x4000
+#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200
+#define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300
+
+#define PCI_VENDOR_ID_VMIC 0x114a
+#define PCI_DEVICE_ID_VMIC_VME 0x7587
+
+#define PCI_VENDOR_ID_DIGI 0x114f
+#define PCI_DEVICE_ID_DIGI_EPC 0x0002
+#define PCI_DEVICE_ID_DIGI_RIGHTSWITCH 0x0003
+#define PCI_DEVICE_ID_DIGI_XEM 0x0004
+#define PCI_DEVICE_ID_DIGI_XR 0x0005
+#define PCI_DEVICE_ID_DIGI_CX 0x0006
+#define PCI_DEVICE_ID_DIGI_XRJ 0x0009
+#define PCI_DEVICE_ID_DIGI_EPCJ 0x000a
+#define PCI_DEVICE_ID_DIGI_XR_920 0x0027
+
+#define PCI_VENDOR_ID_MUTECH 0x1159
+#define PCI_DEVICE_ID_MUTECH_MV1000 0x0001
+
+#define PCI_VENDOR_ID_RENDITION 0x1163
+#define PCI_DEVICE_ID_RENDITION_VERITE 0x0001
+#define PCI_DEVICE_ID_RENDITION_VERITE2100 0x2000
+
+#define PCI_VENDOR_ID_TOSHIBA 0x1179
+#define PCI_DEVICE_ID_TOSHIBA_601 0x0601
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f
+
+#define PCI_VENDOR_ID_RICOH 0x1180
+#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
+#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
+#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475
+#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478
+
+#define PCI_VENDOR_ID_ARTOP 0x1191
+#define PCI_DEVICE_ID_ARTOP_ATP8400 0x0004
+#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005
+
+#define PCI_VENDOR_ID_ZEITNET 0x1193
+#define PCI_DEVICE_ID_ZEITNET_1221 0x0001
+#define PCI_DEVICE_ID_ZEITNET_1225 0x0002
+
+#define PCI_VENDOR_ID_OMEGA 0x119b
+#define PCI_DEVICE_ID_OMEGA_82C092G 0x1221
+
+#define PCI_VENDOR_ID_GALILEO 0x11ab
+#define PCI_DEVICE_ID_GALILEO_GT64011 0x4146
+
+#define PCI_VENDOR_ID_LITEON 0x11ad
+#define PCI_DEVICE_ID_LITEON_LNE100TX 0x0002
+
+#define PCI_VENDOR_ID_NP 0x11bc
+#define PCI_DEVICE_ID_NP_PCI_FDDI 0x0001
+
+#define PCI_VENDOR_ID_ATT 0x11c1
+#define PCI_DEVICE_ID_ATT_L56XMF 0x0440
+
+#define PCI_VENDOR_ID_SPECIALIX 0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000
+#define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000
+#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000
+
+#define PCI_VENDOR_ID_AURAVISION 0x11d1
+#define PCI_DEVICE_ID_AURAVISION_VXP524 0x01f7
+
+#define PCI_VENDOR_ID_IKON 0x11d5
+#define PCI_DEVICE_ID_IKON_10115 0x0115
+#define PCI_DEVICE_ID_IKON_10117 0x0117
+
+#define PCI_VENDOR_ID_ZORAN 0x11de
+#define PCI_DEVICE_ID_ZORAN_36057 0x6057
+#define PCI_DEVICE_ID_ZORAN_36120 0x6120
+
+#define PCI_VENDOR_ID_KINETIC 0x11f4
+#define PCI_DEVICE_ID_KINETIC_2915 0x2915
+
+#define PCI_VENDOR_ID_COMPEX 0x11f6
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
+#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401
+
+#define PCI_VENDOR_ID_RP 0x11fe
+#define PCI_DEVICE_ID_RP32INTF 0x0001
+#define PCI_DEVICE_ID_RP8INTF 0x0002
+#define PCI_DEVICE_ID_RP16INTF 0x0003
+#define PCI_DEVICE_ID_RP4QUAD 0x0004
+#define PCI_DEVICE_ID_RP8OCTA 0x0005
+#define PCI_DEVICE_ID_RP8J 0x0006
+#define PCI_DEVICE_ID_RPP4 0x000A
+#define PCI_DEVICE_ID_RPP8 0x000B
+#define PCI_DEVICE_ID_RP8M 0x000C
+
+#define PCI_VENDOR_ID_CYCLADES 0x120e
+#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100
+#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101
+#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102
+#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103
+#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104
+#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105
+#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200
+#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201
+
+#define PCI_VENDOR_ID_ESSENTIAL 0x120f
+#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001
+
+#define PCI_VENDOR_ID_O2 0x1217
+#define PCI_DEVICE_ID_O2_6729 0x6729
+#define PCI_DEVICE_ID_O2_6730 0x673a
+#define PCI_DEVICE_ID_O2_6832 0x6832
+#define PCI_DEVICE_ID_O2_6836 0x6836
+
+#define PCI_VENDOR_ID_3DFX 0x121a
+#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001
+#define PCI_DEVICE_ID_3DFX_VOODOO2 0x0002
+#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
+
+#define PCI_VENDOR_ID_SIGMADES 0x1236
+#define PCI_DEVICE_ID_SIGMADES_6425 0x6401
+
+#define PCI_VENDOR_ID_CCUBE 0x123f
+
+#define PCI_VENDOR_ID_AVM 0x1244
+#define PCI_DEVICE_ID_AVM_A1 0x0a00
+
+#define PCI_VENDOR_ID_DIPIX 0x1246
+
+#define PCI_VENDOR_ID_STALLION 0x124d
+#define PCI_DEVICE_ID_STALLION_ECHPCI832 0x0000
+#define PCI_DEVICE_ID_STALLION_ECHPCI864 0x0002
+#define PCI_DEVICE_ID_STALLION_EIOPCI 0x0003
+
+#define PCI_VENDOR_ID_OPTIBASE 0x1255
+#define PCI_DEVICE_ID_OPTIBASE_FORGE 0x1110
+#define PCI_DEVICE_ID_OPTIBASE_FUSION 0x1210
+#define PCI_DEVICE_ID_OPTIBASE_VPLEX 0x2110
+#define PCI_DEVICE_ID_OPTIBASE_VPLEXCC 0x2120
+#define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130
+
+#define PCI_VENDOR_ID_SATSAGEM 0x1267
+#define PCI_DEVICE_ID_SATSAGEM_PCR2101 0x5352
+#define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
+
+#define PCI_VENDOR_ID_HUGHES 0x1273
+#define PCI_DEVICE_ID_HUGHES_DIRECPC 0x0002
+
+#define PCI_VENDOR_ID_ENSONIQ 0x1274
+#define PCI_DEVICE_ID_ENSONIQ_AUDIOPCI 0x5000
+#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
+
+#define PCI_VENDOR_ID_ALTEON 0x12ae
+#define PCI_DEVICE_ID_ALTEON_ACENIC 0x0001
+
+#define PCI_VENDOR_ID_PICTUREL 0x12c5
+#define PCI_DEVICE_ID_PICTUREL_PCIVST 0x0081
+
+#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2
+#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
+
+#define PCI_VENDOR_ID_CBOARDS 0x1307
+#define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
+
+#define PCI_VENDOR_ID_SIIG 0x131f
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036
+#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
+
+#define PCI_VENDOR_ID_NETGEAR 0x1385
+#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
+
+#define PCI_VENDOR_ID_LAVA 0x1407
+#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */
+
+#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
+#define PCI_DEVICE_ID_SYMPHONY_101 0x0001
+
+#define PCI_VENDOR_ID_TEKRAM 0x1de1
+#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
+
+#define PCI_VENDOR_ID_3DLABS 0x3d3d
+#define PCI_DEVICE_ID_3DLABS_300SX 0x0001
+#define PCI_DEVICE_ID_3DLABS_500TX 0x0002
+#define PCI_DEVICE_ID_3DLABS_DELTA 0x0003
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA 0x0004
+#define PCI_DEVICE_ID_3DLABS_MX 0x0006
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007
+#define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009
+
+#define PCI_VENDOR_ID_AVANCE 0x4005
+#define PCI_DEVICE_ID_AVANCE_ALG2064 0x2064
+#define PCI_DEVICE_ID_AVANCE_2302 0x2302
+
+#define PCI_VENDOR_ID_NETVIN 0x4a14
+#define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000
+
+#define PCI_VENDOR_ID_S3 0x5333
+#define PCI_DEVICE_ID_S3_PLATO_PXS 0x0551
+#define PCI_DEVICE_ID_S3_ViRGE 0x5631
+#define PCI_DEVICE_ID_S3_TRIO 0x8811
+#define PCI_DEVICE_ID_S3_AURORA64VP 0x8812
+#define PCI_DEVICE_ID_S3_TRIO64UVP 0x8814
+#define PCI_DEVICE_ID_S3_ViRGE_VX 0x883d
+#define PCI_DEVICE_ID_S3_868 0x8880
+#define PCI_DEVICE_ID_S3_928 0x88b0
+#define PCI_DEVICE_ID_S3_864_1 0x88c0
+#define PCI_DEVICE_ID_S3_864_2 0x88c1
+#define PCI_DEVICE_ID_S3_964_1 0x88d0
+#define PCI_DEVICE_ID_S3_964_2 0x88d1
+#define PCI_DEVICE_ID_S3_968 0x88f0
+#define PCI_DEVICE_ID_S3_TRIO64V2 0x8901
+#define PCI_DEVICE_ID_S3_PLATO_PXG 0x8902
+#define PCI_DEVICE_ID_S3_ViRGE_DXGX 0x8a01
+#define PCI_DEVICE_ID_S3_ViRGE_GX2 0x8a10
+#define PCI_DEVICE_ID_S3_ViRGE_MX 0x8c01
+#define PCI_DEVICE_ID_S3_ViRGE_MXP 0x8c02
+#define PCI_DEVICE_ID_S3_ViRGE_MXPMV 0x8c03
+#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
+
+#define PCI_VENDOR_ID_DCI 0x6666
+#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
+
+#define PCI_VENDOR_ID_GENROCO 0x5555
+#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003
+
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_21145 0x0039
+#define PCI_DEVICE_ID_INTEL_82375 0x0482
+#define PCI_DEVICE_ID_INTEL_82424 0x0483
+#define PCI_DEVICE_ID_INTEL_82378 0x0484
+#define PCI_DEVICE_ID_INTEL_82430 0x0486
+#define PCI_DEVICE_ID_INTEL_82434 0x04a3
+#define PCI_DEVICE_ID_INTEL_I960 0x0960
+#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
+#define PCI_DEVICE_ID_INTEL_82092AA_1 0x1222
+#define PCI_DEVICE_ID_INTEL_7116 0x1223
+#define PCI_DEVICE_ID_INTEL_82596 0x1226
+#define PCI_DEVICE_ID_INTEL_82865 0x1227
+#define PCI_DEVICE_ID_INTEL_82557 0x1229
+#define PCI_DEVICE_ID_INTEL_82437 0x122d
+#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e
+#define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230
+#define PCI_DEVICE_ID_INTEL_82371MX 0x1234
+#define PCI_DEVICE_ID_INTEL_82437MX 0x1235
+#define PCI_DEVICE_ID_INTEL_82441 0x1237
+#define PCI_DEVICE_ID_INTEL_82380FB 0x124b
+#define PCI_DEVICE_ID_INTEL_82439 0x1250
+#define PCI_DEVICE_ID_INTEL_MEGARAID 0x1960
+#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
+#define PCI_DEVICE_ID_INTEL_82437VX 0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX 0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+#define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180
+#define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181
+#define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192
+#define PCI_DEVICE_ID_INTEL_P6 0x84c4
+#define PCI_DEVICE_ID_INTEL_82450GX 0x84c4
+#define PCI_DEVICE_ID_INTEL_82453GX 0x84c5
+#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb
+
+#define PCI_VENDOR_ID_COMPUTONE 0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291
+
+#define PCI_VENDOR_ID_KTI 0x8e2e
+#define PCI_DEVICE_ID_KTI_ET32P2 0x3000
+
+#define PCI_VENDOR_ID_ADAPTEC 0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810 0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821 0x2178
+#define PCI_DEVICE_ID_ADAPTEC_38602 0x3860
+#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078
+#define PCI_DEVICE_ID_ADAPTEC_7855 0x5578
+#define PCI_DEVICE_ID_ADAPTEC_5800 0x5800
+#define PCI_DEVICE_ID_ADAPTEC_3860 0x6038
+#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
+#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078
+#define PCI_DEVICE_ID_ADAPTEC_7861 0x6178
+#define PCI_DEVICE_ID_ADAPTEC_7870 0x7078
+#define PCI_DEVICE_ID_ADAPTEC_7871 0x7178
+#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278
+#define PCI_DEVICE_ID_ADAPTEC_7873 0x7378
+#define PCI_DEVICE_ID_ADAPTEC_7874 0x7478
+#define PCI_DEVICE_ID_ADAPTEC_7895 0x7895
+#define PCI_DEVICE_ID_ADAPTEC_7880 0x8078
+#define PCI_DEVICE_ID_ADAPTEC_7881 0x8178
+#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278
+#define PCI_DEVICE_ID_ADAPTEC_7883 0x8378
+#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885 0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886 0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887 0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888 0x8878
+#define PCI_DEVICE_ID_ADAPTEC_1030 0x8b78
+
+#define PCI_VENDOR_ID_ADAPTEC2 0x9005
+#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B 0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f
+#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051
+#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A 0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B 0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D 0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P 0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A 0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B 0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D 0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf
+
+#define PCI_VENDOR_ID_ATRONICS 0x907f
+#define PCI_DEVICE_ID_ATRONICS_2015 0x2015
+
+#define PCI_VENDOR_ID_HOLTEK 0x9412
+#define PCI_DEVICE_ID_HOLTEK_6565 0x6565
+
+#define PCI_VENDOR_ID_TIGERJET 0xe159
+#define PCI_DEVICE_ID_TIGERJET_300 0x0001
+
+#define PCI_VENDOR_ID_ARK 0xedd8
+#define PCI_DEVICE_ID_ARK_STING 0xa091
+#define PCI_DEVICE_ID_ARK_STINGARK 0xa099
+#define PCI_DEVICE_ID_ARK_2000MT 0xa0a1
+
+#define PCI_VENDOR_ID_INTERPHASE 0x107e
+#define PCI_DEVICE_ID_INTERPHASE_5526 0x0004
+#define PCI_DEVICE_ID_INTERPHASE_55x6 0x0005
+
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices. The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ * 7:3 = slot
+ * 2:0 = function
+ */
+#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/config.h>
+
+/*
+ * There is one pci_dev structure for each slot-number/function-number
+ * combination:
+ */
+struct pci_dev {
+ struct pci_bus *bus; /* bus this device is on */
+ struct pci_dev *sibling; /* next device on this bus */
+ struct pci_dev *next; /* chain of all devices */
+
+ void *sysdata; /* hook for sys-specific extension */
+ struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
+
+ unsigned int devfn; /* encoded device & function index */
+ unsigned short vendor;
+ unsigned short device;
+ unsigned int class; /* 3 bytes: (base,sub,prog-if) */
+ unsigned int hdr_type; /* PCI header type */
+ unsigned int master : 1; /* set if device is master capable */
+ /*
+ * In theory, the irq level can be read from configuration
+ * space and all would be fine. However, old PCI chips don't
+ * support these registers and return 0 instead. For example,
+ * the Vision864-P rev 0 chip can uses INTA, but returns 0 in
+ * the interrupt line and pin registers. pci_init()
+ * initializes this field with the value at PCI_INTERRUPT_LINE
+ * and it is the job of pcibios_fixup() to change it if
+ * necessary. The field must not be 0 unless the device
+ * cannot generate interrupts at all.
+ */
+ unsigned int irq; /* irq generated by this device */
+
+ /* Base registers for this device, can be adjusted by
+ * pcibios_fixup() as necessary.
+ */
+ unsigned long base_address[6];
+ unsigned long rom_address;
+};
+
+struct pci_bus {
+ struct pci_bus *parent; /* parent bus this bridge is on */
+ struct pci_bus *children; /* chain of P2P bridges on this bus */
+ struct pci_bus *next; /* chain of all PCI buses */
+
+ struct pci_dev *self; /* bridge device as seen by parent */
+ struct pci_dev *devices; /* devices behind this bridge */
+
+ void *sysdata; /* hook for sys-specific extension */
+ struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
+
+ unsigned char number; /* bus number */
+ unsigned char primary; /* number of primary bridge */
+ unsigned char secondary; /* number of secondary bridge */
+ unsigned char subordinate; /* max number of subordinate buses */
+};
+
+extern struct pci_bus pci_root; /* root bus */
+extern struct pci_dev *pci_devices; /* list of all devices */
+
+/*
+ * Error values that may be returned by the PCI bios.
+ */
+#define PCIBIOS_SUCCESSFUL 0x00
+#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
+#define PCIBIOS_BAD_VENDOR_ID 0x83
+#define PCIBIOS_DEVICE_NOT_FOUND 0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
+#define PCIBIOS_SET_FAILED 0x88
+#define PCIBIOS_BUFFER_TOO_SMALL 0x89
+
+/* Low-level architecture-dependent routines */
+
+int pcibios_present (void);
+void pcibios_init(void);
+void pcibios_fixup(void);
+void pcibios_fixup_bus(struct pci_bus *);
+char *pcibios_setup (char *str);
+int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned char *val);
+int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned short *val);
+int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned int *val);
+int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned char val);
+int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned short val);
+int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
+ unsigned char where, unsigned int val);
+
+/* Don't use these in new code, use pci_find_... instead */
+
+int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn);
+int pcibios_find_device (unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *dev_fn);
+
+/* Generic PCI interface functions */
+
+void pci_init(void);
+void pci_setup(char *str, int *ints);
+void pci_quirks_init(void);
+unsigned int pci_scan_bus(struct pci_bus *bus);
+struct pci_bus *pci_scan_peer_bridge(int bus);
+void pci_proc_init(void);
+void proc_old_pci_init(void);
+int get_pci_list(char *buf);
+int pci_proc_attach_device(struct pci_dev *dev);
+int pci_proc_detach_device(struct pci_dev *dev);
+
+struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
+struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from);
+struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
+
+#define pci_present pcibios_present
+int pci_read_config_byte(struct pci_dev *dev, u8 where, u8 *val);
+int pci_read_config_word(struct pci_dev *dev, u8 where, u16 *val);
+int pci_read_config_dword(struct pci_dev *dev, u8 where, u32 *val);
+int pci_write_config_byte(struct pci_dev *dev, u8 where, u8 val);
+int pci_write_config_word(struct pci_dev *dev, u8 where, u16 val);
+int pci_write_config_dword(struct pci_dev *dev, u8 where, u32 val);
+void pci_set_master(struct pci_dev *dev);
+
+#ifndef CONFIG_PCI
+/* If the system does not have PCI, clearly these return errors. Define
+ these as simple inline functions to avoid hair in drivers. */
+extern inline int pcibios_present(void) { return 0; }
+
+#define _PCI_NOP(o,s,t) \
+ extern inline int pcibios_##o##_config_##s## (u8 bus, u8 dfn, u8 where, t val) \
+ { return PCIBIOS_FUNC_NOT_SUPPORTED; } \
+ extern inline int pci_##o##_config_##s## (struct pci_dev *dev, u8 where, t val) \
+ { return PCIBIOS_FUNC_NOT_SUPPORTED; }
+#define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \
+ _PCI_NOP(o,word,u16 x) \
+ _PCI_NOP(o,dword,u32 x)
+_PCI_NOP_ALL(read, *)
+_PCI_NOP_ALL(write,)
+
+extern inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
+{ return NULL; }
+
+extern inline struct pci_dev *pci_find_class(unsigned int class, struct pci_dev *from)
+{ return NULL; }
+
+extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
+{ return NULL; }
+
+extern inline void pci_set_master(struct pci_dev *dev)
+{ return; }
+
+#endif /* !CONFIG_PCI */
+
+#endif /* __KERNEL__ */
+#endif /* LINUX_PCI_H */
diff --git a/pfinet/linux-src/include/linux/personality.h b/pfinet/linux-src/include/linux/personality.h
new file mode 100644
index 00000000..a927b9e7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/personality.h
@@ -0,0 +1,57 @@
+#ifndef _PERSONALITY_H
+#define _PERSONALITY_H
+
+#include <linux/linkage.h>
+#include <linux/ptrace.h>
+
+
+/* Flags for bug emulation. These occupy the top three bytes. */
+#define STICKY_TIMEOUTS 0x4000000
+#define WHOLE_SECONDS 0x2000000
+#define ADDR_LIMIT_32BIT 0x0800000
+
+/* Personality types. These go in the low byte. Avoid using the top bit,
+ * it will conflict with error returns.
+ */
+#define PER_MASK (0x00ff)
+#define PER_LINUX (0x0000)
+#define PER_LINUX_32BIT (0x0000 | ADDR_LIMIT_32BIT)
+#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS)
+#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS)
+#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
+#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS)
+#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS)
+#define PER_BSD (0x0006)
+#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
+#define PER_LINUX32 (0x0008)
+#define PER_IRIX32 (0x0009 | STICKY_TIMEOUTS) /* IRIX5 32-bit */
+#define PER_IRIXN32 (0x000a | STICKY_TIMEOUTS) /* IRIX6 new 32-bit */
+#define PER_IRIX64 (0x000b | STICKY_TIMEOUTS) /* IRIX6 64-bit */
+
+/* Prototype for an lcall7 syscall handler. */
+typedef void (*lcall7_func)(struct pt_regs *);
+
+
+/* Description of an execution domain - personality range supported,
+ * lcall7 syscall handler, start up / shut down functions etc.
+ * N.B. The name and lcall7 handler must be where they are since the
+ * offset of the handler is hard coded in kernel/sys_call.S.
+ */
+struct exec_domain {
+ const char *name;
+ lcall7_func handler;
+ unsigned char pers_low, pers_high;
+ unsigned long * signal_map;
+ unsigned long * signal_invmap;
+ struct module * module;
+ struct exec_domain *next;
+};
+
+extern struct exec_domain default_exec_domain;
+
+extern struct exec_domain *lookup_exec_domain(unsigned long personality);
+extern int register_exec_domain(struct exec_domain *it);
+extern int unregister_exec_domain(struct exec_domain *it);
+asmlinkage int sys_personality(unsigned long personality);
+
+#endif /* _PERSONALITY_H */
diff --git a/pfinet/linux-src/include/linux/pg.h b/pfinet/linux-src/include/linux/pg.h
new file mode 100644
index 00000000..c752a97c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/pg.h
@@ -0,0 +1,63 @@
+/* pg.h (c) 1998 Grant R. Guenther <grant@torque.net>
+ Under the terms of the GNU public license
+
+
+ pg.h defines the user interface to the generic ATAPI packet
+ command driver for parallel port ATAPI devices (pg). The
+ driver is loosely modelled after the generic SCSI driver, sg,
+ although the actual interface is different.
+
+ The pg driver provides a simple character device interface for
+ sending ATAPI commands to a device. With the exception of the
+ ATAPI reset operation, all operations are performed by a pair
+ of read and write operations to the appropriate /dev/pgN device.
+ A write operation delivers a command and any outbound data in
+ a single buffer. Normally, the write will succeed unless the
+ device is offline or malfunctioning, or there is already another
+ command pending. If the write succeeds, it should be followed
+ immediately by a read operation, to obtain any returned data and
+ status information. A read will fail if there is no operation
+ in progress.
+
+ As a special case, the device can be reset with a write operation,
+ and in this case, no following read is expected, or permitted.
+
+ There are no ioctl() operations. Any single operation
+ may transfer at most PG_MAX_DATA bytes. Note that the driver must
+ copy the data through an internal buffer. In keeping with all
+ current ATAPI devices, command packets are assumed to be exactly
+ 12 bytes in length.
+
+ To permit future changes to this interface, the headers in the
+ read and write buffers contain a single character "magic" flag.
+ Currently this flag must be the character "P".
+
+*/
+
+#define PG_MAGIC 'P'
+#define PG_RESET 'Z'
+#define PG_COMMAND 'C'
+
+#define PG_MAX_DATA 32768
+
+struct pg_write_hdr {
+
+ char magic; /* == PG_MAGIC */
+ char func; /* PG_RESET or PG_COMMAND */
+ int dlen; /* number of bytes expected to transfer */
+ int timeout; /* number of seconds before timeout */
+ char packet[12]; /* packet command */
+
+};
+
+struct pg_read_hdr {
+
+ char magic; /* == PG_MAGIC */
+ char scsi; /* "scsi" status == sense key */
+ int dlen; /* size of device transfer request */
+ int duration; /* time in seconds command took */
+ char pad[12]; /* not used */
+
+};
+
+/* end of pg.h */
diff --git a/pfinet/linux-src/include/linux/phonedev.h b/pfinet/linux-src/include/linux/phonedev.h
new file mode 100644
index 00000000..d54049ee
--- /dev/null
+++ b/pfinet/linux-src/include/linux/phonedev.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_PHONEDEV_H
+#define __LINUX_PHONEDEV_H
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+struct phone_device {
+ struct phone_device *next;
+ struct file_operations *f_op;
+ int (*open) (struct phone_device *, struct file *);
+ int board; /* Device private index */
+ int minor;
+};
+
+extern int phonedev_init(void);
+#define PHONE_MAJOR 100
+extern int phone_register_device(struct phone_device *, int unit);
+#define PHONE_UNIT_ANY -1
+extern void phone_unregister_device(struct phone_device *);
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/pipe_fs_i.h b/pfinet/linux-src/include/linux/pipe_fs_i.h
new file mode 100644
index 00000000..3a847d72
--- /dev/null
+++ b/pfinet/linux-src/include/linux/pipe_fs_i.h
@@ -0,0 +1,34 @@
+#ifndef _LINUX_PIPE_FS_I_H
+#define _LINUX_PIPE_FS_I_H
+
+struct pipe_inode_info {
+ struct wait_queue * wait;
+ char * base;
+ unsigned int start;
+ unsigned int lock;
+ unsigned int rd_openers;
+ unsigned int wr_openers;
+ unsigned int readers;
+ unsigned int writers;
+};
+
+#define PIPE_WAIT(inode) ((inode).u.pipe_i.wait)
+#define PIPE_BASE(inode) ((inode).u.pipe_i.base)
+#define PIPE_START(inode) ((inode).u.pipe_i.start)
+#define PIPE_LEN(inode) ((inode).i_size)
+#define PIPE_RD_OPENERS(inode) ((inode).u.pipe_i.rd_openers)
+#define PIPE_WR_OPENERS(inode) ((inode).u.pipe_i.wr_openers)
+#define PIPE_READERS(inode) ((inode).u.pipe_i.readers)
+#define PIPE_WRITERS(inode) ((inode).u.pipe_i.writers)
+#define PIPE_LOCK(inode) ((inode).u.pipe_i.lock)
+#define PIPE_SIZE(inode) PIPE_LEN(inode)
+
+#define PIPE_EMPTY(inode) (PIPE_SIZE(inode)==0)
+#define PIPE_FULL(inode) (PIPE_SIZE(inode)==PIPE_BUF)
+#define PIPE_FREE(inode) (PIPE_BUF - PIPE_LEN(inode))
+#define PIPE_END(inode) ((PIPE_START(inode)+PIPE_LEN(inode))&\
+ (PIPE_BUF-1))
+#define PIPE_MAX_RCHUNK(inode) (PIPE_BUF - PIPE_START(inode))
+#define PIPE_MAX_WCHUNK(inode) (PIPE_BUF - PIPE_END(inode))
+
+#endif
diff --git a/pfinet/linux-src/include/linux/pkt_cls.h b/pfinet/linux-src/include/linux/pkt_cls.h
new file mode 100644
index 00000000..36935ed3
--- /dev/null
+++ b/pfinet/linux-src/include/linux/pkt_cls.h
@@ -0,0 +1,146 @@
+#ifndef __LINUX_PKT_CLS_H
+#define __LINUX_PKT_CLS_H
+
+struct tc_police
+{
+ __u32 index;
+ int action;
+#define TC_POLICE_UNSPEC (-1)
+#define TC_POLICE_OK 0
+#define TC_POLICE_RECLASSIFY 1
+#define TC_POLICE_SHOT 2
+
+ __u32 limit;
+ __u32 burst;
+ __u32 mtu;
+ struct tc_ratespec rate;
+ struct tc_ratespec peakrate;
+};
+
+enum
+{
+ TCA_POLICE_UNSPEC,
+ TCA_POLICE_TBF,
+ TCA_POLICE_RATE,
+ TCA_POLICE_PEAKRATE,
+ TCA_POLICE_AVRATE,
+ TCA_POLICE_RESULT
+#define TCA_POLICE_RESULT TCA_POLICE_RESULT
+};
+
+#define TCA_POLICE_MAX TCA_POLICE_RESULT
+
+/* U32 filters */
+
+#define TC_U32_HTID(h) ((h)&0xFFF00000)
+#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20)
+#define TC_U32_HASH(h) (((h)>>12)&0xFF)
+#define TC_U32_NODE(h) ((h)&0xFFF)
+#define TC_U32_KEY(h) ((h)&0xFFFFF)
+#define TC_U32_UNSPEC 0
+#define TC_U32_ROOT (0xFFF00000)
+
+enum
+{
+ TCA_U32_UNSPEC,
+ TCA_U32_CLASSID,
+ TCA_U32_HASH,
+ TCA_U32_LINK,
+ TCA_U32_DIVISOR,
+ TCA_U32_SEL,
+ TCA_U32_POLICE,
+};
+
+#define TCA_U32_MAX TCA_U32_POLICE
+
+struct tc_u32_key
+{
+ __u32 mask;
+ __u32 val;
+ int off;
+ int offmask;
+};
+
+struct tc_u32_sel
+{
+ unsigned char flags;
+ unsigned char offshift;
+ unsigned char nkeys;
+
+ __u16 offmask;
+ __u16 off;
+ short offoff;
+
+ short hoff;
+ __u32 hmask;
+
+ struct tc_u32_key keys[0];
+};
+
+/* Flags */
+
+#define TC_U32_TERMINAL 1
+#define TC_U32_OFFSET 2
+#define TC_U32_VAROFFSET 4
+#define TC_U32_EAT 8
+
+#define TC_U32_MAXDEPTH 8
+
+
+/* RSVP filter */
+
+enum
+{
+ TCA_RSVP_UNSPEC,
+ TCA_RSVP_CLASSID,
+ TCA_RSVP_DST,
+ TCA_RSVP_SRC,
+ TCA_RSVP_PINFO,
+ TCA_RSVP_POLICE,
+};
+
+#define TCA_RSVP_MAX TCA_RSVP_POLICE
+
+struct tc_rsvp_gpi
+{
+ __u32 key;
+ __u32 mask;
+ int offset;
+};
+
+struct tc_rsvp_pinfo
+{
+ struct tc_rsvp_gpi dpi;
+ struct tc_rsvp_gpi spi;
+ __u8 protocol;
+ __u8 tunnelid;
+ __u8 tunnelhdr;
+};
+
+/* ROUTE filter */
+
+enum
+{
+ TCA_ROUTE4_UNSPEC,
+ TCA_ROUTE4_CLASSID,
+ TCA_ROUTE4_TO,
+ TCA_ROUTE4_FROM,
+ TCA_ROUTE4_IIF,
+ TCA_ROUTE4_POLICE,
+};
+
+#define TCA_ROUTE4_MAX TCA_ROUTE4_POLICE
+
+
+/* FW filter */
+
+enum
+{
+ TCA_FW_UNSPEC,
+ TCA_FW_CLASSID,
+ TCA_FW_POLICE,
+};
+
+#define TCA_FW_MAX TCA_FW_POLICE
+
+#endif
diff --git a/pfinet/linux-src/include/linux/pkt_sched.h b/pfinet/linux-src/include/linux/pkt_sched.h
new file mode 100644
index 00000000..4ec170db
--- /dev/null
+++ b/pfinet/linux-src/include/linux/pkt_sched.h
@@ -0,0 +1,277 @@
+#ifndef __LINUX_PKT_SCHED_H
+#define __LINUX_PKT_SCHED_H
+
+/* Logical priority bands not depending on specific packet scheduler.
+ Every scheduler will map them to real traffic classes, if it has
+ no more precise mechanism to classify packets.
+
+ These numbers have no special meaning, though their coincidence
+ with obsolete IPv6 values is not occasional :-). New IPv6 drafts
+ preferred full anarchy inspired by diffserv group.
+
+ Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy
+ class, actually, as rule it will be handled with more care than
+ filler or even bulk.
+ */
+
+#define TC_PRIO_BESTEFFORT 0
+#define TC_PRIO_FILLER 1
+#define TC_PRIO_BULK 2
+#define TC_PRIO_INTERACTIVE_BULK 4
+#define TC_PRIO_INTERACTIVE 6
+#define TC_PRIO_CONTROL 7
+
+#define TC_PRIO_MAX 15
+
+/* Generic queue statistics, available for all the elements.
+ Particular schedulers may have also their private records.
+ */
+
+struct tc_stats
+{
+ __u64 bytes; /* NUmber of enqueues bytes */
+ __u32 packets; /* Number of enqueued packets */
+ __u32 drops; /* Packets dropped because of lack of resources */
+ __u32 overlimits; /* Number of throttle events when this
+ * flow goes out of allocated bandwidth */
+ __u32 bps; /* Current flow byte rate */
+ __u32 pps; /* Current flow packet rate */
+ __u32 qlen;
+ __u32 backlog;
+};
+
+struct tc_estimator
+{
+ char interval;
+ unsigned char ewma_log;
+};
+
+/* "Handles"
+ ---------
+
+ All the traffic control objects have 32bit identifiers, or "handles".
+
+ They can be considered as opaque numbers from user API viewpoint,
+ but actually they always consist of two fields: major and
+ minor numbers, which are interpreted by kernel specially,
+ that may be used by applications, though not recommended.
+
+ F.e. qdisc handles always have minor number equal to zero,
+ classes (or flows) have major equal to parent qdisc major, and
+ minor uniquely identifying class inside qdisc.
+
+ Macros to manipulate handles:
+ */
+
+#define TC_H_MAJ_MASK (0xFFFF0000U)
+#define TC_H_MIN_MASK (0x0000FFFFU)
+#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK)
+#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK)
+#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK))
+
+#define TC_H_UNSPEC (0U)
+#define TC_H_ROOT (0xFFFFFFFFU)
+
+struct tc_ratespec
+{
+ unsigned char cell_log;
+ unsigned char __reserved;
+ unsigned short feature;
+ short addend;
+ unsigned short mpu;
+ __u32 rate;
+};
+
+/* FIFO section */
+
+struct tc_fifo_qopt
+{
+ __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */
+};
+
+/* PRIO section */
+
+#define TCQ_PRIO_BANDS 16
+
+struct tc_prio_qopt
+{
+ int bands; /* Number of bands */
+ __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
+};
+
+/* CSZ section */
+
+struct tc_csz_qopt
+{
+ int flows; /* Maximal number of guaranteed flows */
+ unsigned char R_log; /* Fixed point position for round number */
+ unsigned char delta_log; /* Log of maximal managed time interval */
+ __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> CSZ band */
+};
+
+struct tc_csz_copt
+{
+ struct tc_ratespec slice;
+ struct tc_ratespec rate;
+ struct tc_ratespec peakrate;
+ __u32 limit;
+ __u32 buffer;
+ __u32 mtu;
+};
+
+enum
+{
+ TCA_CSZ_UNSPEC,
+ TCA_CSZ_PARMS,
+ TCA_CSZ_RTAB,
+ TCA_CSZ_PTAB,
+};
+
+/* TBF section */
+
+struct tc_tbf_qopt
+{
+ struct tc_ratespec rate;
+ struct tc_ratespec peakrate;
+ __u32 limit;
+ __u32 buffer;
+ __u32 mtu;
+};
+
+enum
+{
+ TCA_TBF_UNSPEC,
+ TCA_TBF_PARMS,
+ TCA_TBF_RTAB,
+ TCA_TBF_PTAB,
+};
+
+
+/* TEQL section */
+
+/* TEQL does not require any parameters */
+
+/* SFQ section */
+
+struct tc_sfq_qopt
+{
+ unsigned quantum; /* Bytes per round allocated to flow */
+ int perturb_period; /* Period of hash perturbation */
+ __u32 limit; /* Maximal packets in queue */
+ unsigned divisor; /* Hash divisor */
+ unsigned flows; /* Maximal number of flows */
+};
+
+/*
+ * NOTE: limit, divisor and flows are hardwired to code at the moment.
+ *
+ * limit=flows=128, divisor=1024;
+ *
+ * The only reason for this is efficiency, it is possible
+ * to change these parameters in compile time.
+ */
+
+/* RED section */
+
+enum
+{
+ TCA_RED_UNSPEC,
+ TCA_RED_PARMS,
+ TCA_RED_STAB,
+};
+
+struct tc_red_qopt
+{
+ __u32 limit; /* HARD maximal queue length (bytes) */
+ __u32 qth_min; /* Min average length threshold (bytes) */
+ __u32 qth_max; /* Max average length threshold (bytes) */
+ unsigned char Wlog; /* log(W) */
+ unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
+ unsigned char Scell_log; /* cell size for idle damping */
+};
+
+/* CBQ section */
+
+#define TC_CBQ_MAXPRIO 8
+#define TC_CBQ_MAXLEVEL 8
+#define TC_CBQ_DEF_EWMA 5
+
+struct tc_cbq_lssopt
+{
+ unsigned char change;
+ unsigned char flags;
+#define TCF_CBQ_LSS_BOUNDED 1
+#define TCF_CBQ_LSS_ISOLATED 2
+ unsigned char ewma_log;
+ unsigned char level;
+#define TCF_CBQ_LSS_FLAGS 1
+#define TCF_CBQ_LSS_EWMA 2
+#define TCF_CBQ_LSS_MAXIDLE 4
+#define TCF_CBQ_LSS_MINIDLE 8
+#define TCF_CBQ_LSS_OFFTIME 0x10
+#define TCF_CBQ_LSS_AVPKT 0x20
+ __u32 maxidle;
+ __u32 minidle;
+ __u32 offtime;
+ __u32 avpkt;
+};
+
+struct tc_cbq_wrropt
+{
+ unsigned char flags;
+ unsigned char priority;
+ unsigned char cpriority;
+ unsigned char __reserved;
+ __u32 allot;
+ __u32 weight;
+};
+
+struct tc_cbq_ovl
+{
+ unsigned char strategy;
+#define TC_CBQ_OVL_CLASSIC 0
+#define TC_CBQ_OVL_DELAY 1
+#define TC_CBQ_OVL_LOWPRIO 2
+#define TC_CBQ_OVL_DROP 3
+#define TC_CBQ_OVL_RCLASSIC 4
+ unsigned char priority2;
+ __u32 penalty;
+};
+
+struct tc_cbq_police
+{
+ unsigned char police;
+ unsigned char __res1;
+ unsigned short __res2;
+};
+
+struct tc_cbq_fopt
+{
+ __u32 split;
+ __u32 defmap;
+ __u32 defchange;
+};
+
+struct tc_cbq_xstats
+{
+ __u32 borrows;
+ __u32 overactions;
+ __s32 avgidle;
+ __s32 undertime;
+};
+
+enum
+{
+ TCA_CBQ_UNSPEC,
+ TCA_CBQ_LSSOPT,
+ TCA_CBQ_WRROPT,
+ TCA_CBQ_FOPT,
+ TCA_CBQ_OVL_STRATEGY,
+ TCA_CBQ_RATE,
+ TCA_CBQ_RTAB,
+ TCA_CBQ_POLICE,
+};
+
+#define TCA_CBQ_MAX TCA_CBQ_POLICE
+
+#endif
diff --git a/pfinet/linux-src/include/linux/poll.h b/pfinet/linux-src/include/linux/poll.h
new file mode 100644
index 00000000..991204f1
--- /dev/null
+++ b/pfinet/linux-src/include/linux/poll.h
@@ -0,0 +1,107 @@
+#ifndef _LINUX_POLL_H
+#define _LINUX_POLL_H
+
+#include <asm/poll.h>
+
+#ifdef __KERNEL__
+
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+
+
+struct poll_table_entry {
+ struct file * filp;
+ struct wait_queue wait;
+ struct wait_queue ** wait_address;
+};
+
+typedef struct poll_table_struct {
+ struct poll_table_struct * next;
+ unsigned int nr;
+ struct poll_table_entry * entry;
+} poll_table;
+
+#define __MAX_POLL_TABLE_ENTRIES ((PAGE_SIZE - sizeof (poll_table)) / sizeof (struct poll_table_entry))
+
+extern void __pollwait(struct file * filp, struct wait_queue ** wait_address, poll_table *p);
+
+extern inline void poll_wait(struct file * filp, struct wait_queue ** wait_address, poll_table *p)
+{
+ if (p && wait_address)
+ __pollwait(filp, wait_address, p);
+}
+
+/*
+ * For the kernel fd_set we use a fixed set-size for allocation purposes.
+ * This set-size doesn't necessarily bear any relation to the size the user
+ * uses, but should preferably obviously be larger than any possible user
+ * size (NR_OPEN bits).
+ *
+ * We need 6 bitmaps (in/out/ex for both incoming and outgoing), and we
+ * allocate one page for all the bitmaps. Thus we have 8*PAGE_SIZE bits,
+ * to be divided by 6. And we'd better make sure we round to a full
+ * long-word (in fact, we'll round to 64 bytes).
+ */
+
+
+#define KFDS_64BLOCK ((PAGE_SIZE/(6*64))*64)
+#define KFDS_NR (KFDS_64BLOCK*8 > NR_OPEN ? NR_OPEN : KFDS_64BLOCK*8)
+typedef unsigned long kernel_fd_set[KFDS_NR/__NFDBITS];
+
+/*
+ * Scalable version of the fd_set.
+ */
+
+typedef struct {
+ unsigned long *in, *out, *ex;
+ unsigned long *res_in, *res_out, *res_ex;
+} fd_set_bits;
+
+/*
+ * How many longwords for "nr" bits?
+ */
+#define FDS_BITPERLONG (8*sizeof(long))
+#define FDS_LONGS(nr) (((nr)+FDS_BITPERLONG-1)/FDS_BITPERLONG)
+#define FDS_BYTES(nr) (FDS_LONGS(nr)*sizeof(long))
+
+/*
+ * We do a VERIFY_WRITE here even though we are only reading this time:
+ * we'll write to it eventually..
+ *
+ * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned.
+ */
+static inline
+int get_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset)
+{
+ nr = FDS_BYTES(nr);
+ if (ufdset) {
+ int error;
+ error = verify_area(VERIFY_WRITE, ufdset, nr);
+ if (!error && __copy_from_user(fdset, ufdset, nr))
+ error = -EFAULT;
+ return error;
+ }
+ memset(fdset, 0, nr);
+ return 0;
+}
+
+static inline
+void set_fd_set(unsigned long nr, void *ufdset, unsigned long *fdset)
+{
+ if (ufdset)
+ __copy_to_user(ufdset, fdset, FDS_BYTES(nr));
+}
+
+static inline
+void zero_fd_set(unsigned long nr, unsigned long *fdset)
+{
+ memset(fdset, 0, FDS_BYTES(nr));
+}
+
+extern int do_select(int n, fd_set_bits *fds, long *timeout);
+
+#endif /* KERNEL */
+
+#endif /* _LINUX_POLL_H */
diff --git a/pfinet/linux-src/include/linux/posix_types.h b/pfinet/linux-src/include/linux/posix_types.h
new file mode 100644
index 00000000..3ee2ed9d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/posix_types.h
@@ -0,0 +1,48 @@
+#ifndef _LINUX_POSIX_TYPES_H
+#define _LINUX_POSIX_TYPES_H
+
+#include <linux/stddef.h>
+
+/*
+ * This allows for 1024 file descriptors: if NR_OPEN is ever grown
+ * beyond that you'll have to change this too. But 1024 fd's seem to be
+ * enough even for such "real" unices like OSF/1, so hopefully this is
+ * one limit that doesn't have to be changed [again].
+ *
+ * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in
+ * <sys/time.h> (and thus <linux/time.h>) - but this is a more logical
+ * place for them. Solved by having dummy defines in <sys/time.h>.
+ */
+
+/*
+ * Those macros may have been defined in <gnu/types.h>. But we always
+ * use the ones here.
+ */
+#undef __NFDBITS
+#define __NFDBITS (8 * sizeof(unsigned long))
+
+#undef __FD_SETSIZE
+#define __FD_SETSIZE 1024
+
+#undef __FDSET_LONGS
+#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS)
+
+#undef __FDELT
+#define __FDELT(d) ((d) / __NFDBITS)
+
+#undef __FDMASK
+#define __FDMASK(d) (1UL << ((d) % __NFDBITS))
+
+typedef struct {
+ unsigned long fds_bits [__FDSET_LONGS];
+} __kernel_fd_set;
+
+/* Type of a signal handler. */
+typedef void (*__kernel_sighandler_t)(int);
+
+/* Type of a SYSV IPC key. */
+typedef int __kernel_key_t;
+
+#include <asm/posix_types.h>
+
+#endif /* _LINUX_POSIX_TYPES_H */
diff --git a/pfinet/linux-src/include/linux/ppp-comp.h b/pfinet/linux-src/include/linux/ppp-comp.h
new file mode 100644
index 00000000..3a5d5865
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ppp-comp.h
@@ -0,0 +1,198 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp-comp.h,v 1.6 1997/11/27 06:04:44 paulus Exp $
+ */
+
+/*
+ * ==FILEVERSION 980319==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * ppp-comp.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new ppp-comp.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS 1 /* by default, include BSD-Compress */
+#endif
+#ifndef DO_DEFLATE
+#define DO_DEFLATE 1 /* by default, include Deflate */
+#endif
+#define DO_PREDICTOR_1 0
+#define DO_PREDICTOR_2 0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+
+struct compressor {
+ int compress_proto; /* CCP compression protocol number */
+
+ /* Allocate space for a compressor (transmit side) */
+ void *(*comp_alloc) (unsigned char *options, int opt_len);
+
+ /* Free space used by a compressor */
+ void (*comp_free) (void *state);
+
+ /* Initialize a compressor */
+ int (*comp_init) (void *state, unsigned char *options,
+ int opt_len, int unit, int opthdr, int debug);
+
+ /* Reset a compressor */
+ void (*comp_reset) (void *state);
+
+ /* Compress a packet */
+ int (*compress) (void *state, unsigned char *rptr,
+ unsigned char *obuf, int isize, int osize);
+
+ /* Return compression statistics */
+ void (*comp_stat) (void *state, struct compstat *stats);
+
+ /* Allocate space for a decompressor (receive side) */
+ void *(*decomp_alloc) (unsigned char *options, int opt_len);
+
+ /* Free space used by a decompressor */
+ void (*decomp_free) (void *state);
+
+ /* Initialize a decompressor */
+ int (*decomp_init) (void *state, unsigned char *options,
+ int opt_len, int unit, int opthdr, int mru,
+ int debug);
+
+ /* Reset a decompressor */
+ void (*decomp_reset) (void *state);
+
+ /* Decompress a packet. */
+ int (*decompress) (void *state, unsigned char *ibuf, int isize,
+ unsigned char *obuf, int osize);
+
+ /* Update state for an incompressible packet received */
+ void (*incomp) (void *state, unsigned char *ibuf, int icnt);
+
+ /* Return decompression statistics */
+ void (*decomp_stat) (void *state, struct compstat *stats);
+};
+
+/*
+ * The return value from decompress routine is the length of the
+ * decompressed packet if successful, otherwise DECOMP_ERROR
+ * or DECOMP_FATALERROR if an error occurred.
+ *
+ * We need to make this distinction so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression. This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+
+#define DECOMP_ERROR -1 /* error detected before decomp. */
+#define DECOMP_FATALERROR -2 /* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+
+#define CCP_CONFREQ 1
+#define CCP_CONFACK 2
+#define CCP_TERMREQ 5
+#define CCP_TERMACK 6
+#define CCP_RESETREQ 14
+#define CCP_RESETACK 15
+
+/*
+ * Max # bytes for a CCP option
+ */
+
+#define CCP_MAX_OPTION_LENGTH 32
+
+/*
+ * Parts of a CCP packet.
+ */
+
+#define CCP_CODE(dp) ((dp)[0])
+#define CCP_ID(dp) ((dp)[1])
+#define CCP_LENGTH(dp) (((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN 4
+
+#define CCP_OPT_CODE(dp) ((dp)[0])
+#define CCP_OPT_LENGTH(dp) ((dp)[1])
+#define CCP_OPT_MINLEN 2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+
+#define CI_BSD_COMPRESS 21 /* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS 3 /* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x) ((x) & 0x1F) /* number of bits requested */
+#define BSD_VERSION(x) ((x) >> 5) /* version of option format */
+#define BSD_CURRENT_VERSION 1 /* current version number */
+#define BSD_MAKE_OPT(v, n) (((v) << 5) | (n))
+
+#define BSD_MIN_BITS 9 /* smallest code size supported */
+#define BSD_MAX_BITS 15 /* largest code size supported */
+
+/*
+ * Definitions for Deflate.
+ */
+
+#define CI_DEFLATE 26 /* config option for Deflate */
+#define CI_DEFLATE_DRAFT 24 /* value used in original draft RFC */
+#define CILEN_DEFLATE 4 /* length of its config option */
+
+#define DEFLATE_MIN_SIZE 8
+#define DEFLATE_MAX_SIZE 15
+#define DEFLATE_METHOD_VAL 8
+#define DEFLATE_SIZE(x) (((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x) ((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w) ((((w) - DEFLATE_MIN_SIZE) << 4) \
+ + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE 0
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+
+#define CI_PREDICTOR_1 1 /* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1 2 /* length of its config option */
+#define CI_PREDICTOR_2 2 /* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2 2 /* length of its config option */
+
+#endif /* _NET_PPP_COMP_H */
diff --git a/pfinet/linux-src/include/linux/ppp.h b/pfinet/linux-src/include/linux/ppp.h
new file mode 100644
index 00000000..233f961e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ppp.h
@@ -0,0 +1,4 @@
+/*
+ * Back compatibility for a while.
+ */
+#include <linux/if_ppp.h>
diff --git a/pfinet/linux-src/include/linux/ppp_defs.h b/pfinet/linux-src/include/linux/ppp_defs.h
new file mode 100644
index 00000000..c506c90a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ppp_defs.h
@@ -0,0 +1,182 @@
+/* $Id: ppp_defs.h,v 1.2 1994/09/21 01:31:06 paulus Exp $ */
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+/*
+ * ==FILEVERSION 990114==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+ * ppp_defs.h is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new ppp_defs.h
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN 4 /* octets for standard ppp header */
+#define PPP_FCSLEN 2 /* octets for FCS */
+#define PPP_MRU 1500 /* default MRU = max length of info field */
+
+#define PPP_ADDRESS(p) (((__u8 *)(p))[0])
+#define PPP_CONTROL(p) (((__u8 *)(p))[1])
+#define PPP_PROTOCOL(p) ((((__u8 *)(p))[2] << 8) + ((__u8 *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
+#define PPP_UI 0x03 /* Unnumbered Information */
+#define PPP_FLAG 0x7e /* Flag Sequence */
+#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */
+#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP 0x21 /* Internet Protocol */
+#define PPP_AT 0x29 /* AppleTalk Protocol */
+#define PPP_IPX 0x2b /* IPX protocol */
+#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
+#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
+#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */
+#define PPP_COMP 0xfd /* compressed packet */
+#define PPP_IPCP 0x8021 /* IP Control Protocol */
+#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */
+#define PPP_IPXCP 0x802b /* IPX Control Protocol */
+#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */
+#define PPP_CCP 0x80fd /* Compression Control Protocol */
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_PAP 0xc023 /* Password Authentication Protocol */
+#define PPP_LQR 0xc025 /* Link Quality Report protocol */
+#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP 0xc029 /* Callback Control Protocol */
+
+/*
+ * Values for FCS calculations.
+ */
+
+#define PPP_INITFCS 0xffff /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+
+typedef __u32 ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+ NPMODE_PASS, /* pass the packet through */
+ NPMODE_DROP, /* silently drop the packet */
+ NPMODE_ERROR, /* return an error */
+ NPMODE_QUEUE /* save it up for later. */
+};
+
+/*
+ * Statistics for LQRP and pppstats
+ */
+struct pppstat {
+ __u32 ppp_discards; /* # frames discarded */
+
+ __u32 ppp_ibytes; /* bytes received */
+ __u32 ppp_ioctects; /* bytes received not in error */
+ __u32 ppp_ipackets; /* packets received */
+ __u32 ppp_ierrors; /* receive errors */
+ __u32 ppp_ilqrs; /* # LQR frames received */
+
+ __u32 ppp_obytes; /* raw bytes sent */
+ __u32 ppp_ooctects; /* frame bytes sent */
+ __u32 ppp_opackets; /* packets sent */
+ __u32 ppp_oerrors; /* transmit errors */
+ __u32 ppp_olqrs; /* # LQR frames sent */
+};
+
+struct vjstat {
+ __u32 vjs_packets; /* outbound packets */
+ __u32 vjs_compressed; /* outbound compressed packets */
+ __u32 vjs_searches; /* searches for connection state */
+ __u32 vjs_misses; /* times couldn't find conn. state */
+ __u32 vjs_uncompressedin; /* inbound uncompressed packets */
+ __u32 vjs_compressedin; /* inbound compressed packets */
+ __u32 vjs_errorin; /* inbound unknown type packets */
+ __u32 vjs_tossed; /* inbound packets tossed because of error */
+};
+
+struct compstat {
+ __u32 unc_bytes; /* total uncompressed bytes */
+ __u32 unc_packets; /* total uncompressed packets */
+ __u32 comp_bytes; /* compressed bytes */
+ __u32 comp_packets; /* compressed packets */
+ __u32 inc_bytes; /* incompressible bytes */
+ __u32 inc_packets; /* incompressible packets */
+
+ /* the compression ratio is defined as in_count / bytes_out */
+ __u32 in_count; /* Bytes received */
+ __u32 bytes_out; /* Bytes transmitted */
+
+ double ratio; /* not computed in kernel. */
+};
+
+struct ppp_stats {
+ struct pppstat p; /* basic PPP statistics */
+ struct vjstat vj; /* VJ header compression statistics */
+};
+
+struct ppp_comp_stats {
+ struct compstat c; /* packet compression statistics */
+ struct compstat d; /* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+ time_t xmit_idle; /* time since last NP packet sent */
+ time_t recv_idle; /* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
diff --git a/pfinet/linux-src/include/linux/prctl.h b/pfinet/linux-src/include/linux/prctl.h
new file mode 100644
index 00000000..f08f3c36
--- /dev/null
+++ b/pfinet/linux-src/include/linux/prctl.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_PRCTL_H
+#define _LINUX_PRCTL_H
+
+/* Values to pass as first argument to prctl() */
+
+#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */
+
+
+#endif /* _LINUX_PRCTL_H */
diff --git a/pfinet/linux-src/include/linux/proc_fs.h b/pfinet/linux-src/include/linux/proc_fs.h
new file mode 100644
index 00000000..77d7d741
--- /dev/null
+++ b/pfinet/linux-src/include/linux/proc_fs.h
@@ -0,0 +1,472 @@
+#ifndef _LINUX_PROC_FS_H
+#define _LINUX_PROC_FS_H
+
+#include <linux/config.h>
+#include <linux/malloc.h>
+
+/*
+ * The proc filesystem constants/structures
+ */
+
+/*
+ * We always define these enumerators
+ */
+
+enum root_directory_inos {
+ PROC_ROOT_INO = 1,
+ PROC_LOADAVG,
+ PROC_UPTIME,
+ PROC_MEMINFO,
+ PROC_KMSG,
+ PROC_VERSION,
+ PROC_CPUINFO,
+ PROC_PCI,
+ PROC_MCA,
+ PROC_NUBUS,
+ PROC_SELF, /* will change inode # */
+ PROC_NET,
+ PROC_SCSI,
+ PROC_MALLOC,
+ PROC_KCORE,
+ PROC_MODULES,
+ PROC_STAT,
+ PROC_DEVICES,
+ PROC_PARTITIONS,
+ PROC_INTERRUPTS,
+ PROC_FILESYSTEMS,
+ PROC_KSYMS,
+ PROC_DMA,
+ PROC_IOPORTS,
+ PROC_PROFILE, /* whether enabled or not */
+ PROC_CMDLINE,
+ PROC_SYS,
+ PROC_MTAB,
+ PROC_SWAP,
+ PROC_MD,
+ PROC_RTC,
+ PROC_LOCKS,
+ PROC_HARDWARE,
+ PROC_SLABINFO,
+ PROC_PARPORT,
+ PROC_PPC_HTAB,
+ PROC_STRAM,
+ PROC_SOUND,
+ PROC_MTRR, /* whether enabled or not */
+ PROC_FS
+};
+
+enum pid_directory_inos {
+ PROC_PID_INO = 2,
+ PROC_PID_STATUS,
+ PROC_PID_MEM,
+ PROC_PID_CWD,
+ PROC_PID_ROOT,
+ PROC_PID_EXE,
+ PROC_PID_FD,
+ PROC_PID_ENVIRON,
+ PROC_PID_CMDLINE,
+ PROC_PID_STAT,
+ PROC_PID_STATM,
+ PROC_PID_MAPS,
+#if CONFIG_AP1000
+ PROC_PID_RINGBUF,
+#endif
+ PROC_PID_CPU,
+};
+
+enum pid_subdirectory_inos {
+ PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */
+};
+
+enum net_directory_inos {
+ PROC_NET_UNIX = 128,
+ PROC_NET_ARP,
+ PROC_NET_ROUTE,
+ PROC_NET_DEV,
+ PROC_NET_RAW,
+ PROC_NET_RAW6,
+ PROC_NET_TCP,
+ PROC_NET_TCP6,
+ PROC_NET_UDP,
+ PROC_NET_UDP6,
+ PROC_NET_SNMP,
+ PROC_NET_RARP,
+ PROC_NET_IGMP,
+ PROC_NET_IPMR_VIF,
+ PROC_NET_IPMR_MFC,
+ PROC_NET_IPFWFWD,
+ PROC_NET_IPFWIN,
+ PROC_NET_IPFWOUT,
+ PROC_NET_IPACCT,
+ PROC_NET_IPMSQHST,
+ PROC_NET_WIRELESS,
+ PROC_NET_IPX_INTERFACE,
+ PROC_NET_IPX_ROUTE,
+ PROC_NET_IPX,
+ PROC_NET_ATALK,
+ PROC_NET_AT_ROUTE,
+ PROC_NET_ATIF,
+ PROC_NET_AX25_ROUTE,
+ PROC_NET_AX25,
+ PROC_NET_AX25_CALLS,
+ PROC_NET_BMAC,
+ PROC_NET_NR_NODES,
+ PROC_NET_NR_NEIGH,
+ PROC_NET_NR,
+ PROC_NET_SOCKSTAT,
+ PROC_NET_SOCKSTAT6,
+ PROC_NET_RTCACHE,
+ PROC_NET_AX25_BPQETHER,
+ PROC_NET_IP_MASQ_APP,
+ PROC_NET_RT6,
+ PROC_NET_SNMP6,
+ PROC_NET_RT6_STATS,
+ PROC_NET_NDISC,
+ PROC_NET_STRIP_STATUS,
+ PROC_NET_STRIP_TRACE,
+ PROC_NET_Z8530,
+ PROC_NET_RS_NODES,
+ PROC_NET_RS_NEIGH,
+ PROC_NET_RS_ROUTES,
+ PROC_NET_RS,
+ PROC_NET_CL2LLC,
+ PROC_NET_X25_ROUTES,
+ PROC_NET_X25,
+ PROC_NET_TR_RIF,
+ PROC_NET_DN_DEV,
+ PROC_NET_DN_ADJ,
+ PROC_NET_DN_L1,
+ PROC_NET_DN_L2,
+ PROC_NET_DN_CACHE,
+ PROC_NET_DN_SKT,
+ PROC_NET_DN_FW,
+ PROC_NET_DN_RAW,
+ PROC_NET_NETSTAT,
+ PROC_NET_IPFW_CHAINS,
+ PROC_NET_IPFW_CHAIN_NAMES,
+ PROC_NET_AT_AARP,
+ PROC_NET_BRIDGE,
+ PROC_NET_LAST
+};
+
+enum scsi_directory_inos {
+ PROC_SCSI_SCSI = 256,
+ PROC_SCSI_ADVANSYS,
+ PROC_SCSI_PCI2000,
+ PROC_SCSI_PCI2220I,
+ PROC_SCSI_PSI240I,
+ PROC_SCSI_EATA,
+ PROC_SCSI_EATA_PIO,
+ PROC_SCSI_AHA152X,
+ PROC_SCSI_AHA1542,
+ PROC_SCSI_AHA1740,
+ PROC_SCSI_AIC7XXX,
+ PROC_SCSI_BUSLOGIC,
+ PROC_SCSI_U14_34F,
+ PROC_SCSI_FDOMAIN,
+ PROC_SCSI_GDTH,
+ PROC_SCSI_GENERIC_NCR5380,
+ PROC_SCSI_IN2000,
+ PROC_SCSI_PAS16,
+ PROC_SCSI_QLOGICFAS,
+ PROC_SCSI_QLOGICISP,
+ PROC_SCSI_QLOGICFC,
+ PROC_SCSI_SEAGATE,
+ PROC_SCSI_T128,
+ PROC_SCSI_NCR53C7xx,
+ PROC_SCSI_SYM53C8XX,
+ PROC_SCSI_NCR53C8XX,
+ PROC_SCSI_ULTRASTOR,
+ PROC_SCSI_7000FASST,
+ PROC_SCSI_IBMMCA,
+ PROC_SCSI_FD_MCS,
+ PROC_SCSI_EATA2X,
+ PROC_SCSI_DC390T,
+ PROC_SCSI_AM53C974,
+ PROC_SCSI_SSC,
+ PROC_SCSI_NCR53C406A,
+ PROC_SCSI_SYM53C416,
+ PROC_SCSI_MEGARAID,
+ PROC_SCSI_PPA,
+ PROC_SCSI_ATP870U,
+ PROC_SCSI_ESP,
+ PROC_SCSI_QLOGICPTI,
+ PROC_SCSI_AMIGA7XX,
+ PROC_SCSI_MVME16x,
+ PROC_SCSI_BVME6000,
+ PROC_SCSI_SIM710,
+ PROC_SCSI_A3000,
+ PROC_SCSI_A2091,
+ PROC_SCSI_GVP11,
+ PROC_SCSI_ATARI,
+ PROC_SCSI_MAC,
+ PROC_SCSI_IDESCSI,
+ PROC_SCSI_SGIWD93,
+ PROC_SCSI_MESH,
+ PROC_SCSI_53C94,
+ PROC_SCSI_PLUTO,
+ PROC_SCSI_INI9100U,
+ PROC_SCSI_INIA100,
+ PROC_SCSI_IPH5526_FC,
+ PROC_SCSI_FCAL,
+ PROC_SCSI_I2O,
+ PROC_SCSI_USB_SCSI,
+ PROC_SCSI_SCSI_DEBUG,
+ PROC_SCSI_NOT_PRESENT,
+ PROC_SCSI_FILE, /* I'm assuming here that we */
+ PROC_SCSI_LAST = (PROC_SCSI_FILE + 16) /* won't ever see more than */
+}; /* 16 HBAs in one machine */
+
+enum mca_directory_inos {
+ PROC_MCA_MACHINE = (PROC_SCSI_LAST+1),
+ PROC_MCA_REGISTERS,
+ PROC_MCA_VIDEO,
+ PROC_MCA_SCSI,
+ PROC_MCA_SLOT, /* the 8 adapter slots */
+ PROC_MCA_LAST = (PROC_MCA_SLOT + 8)
+};
+
+enum bus_directory_inos {
+ PROC_BUS_PCI = PROC_MCA_LAST,
+ PROC_BUS_PCI_DEVICES,
+ PROC_BUS_ZORRO,
+ PROC_BUS_ZORRO_DEVICES,
+ PROC_BUS_LAST
+};
+
+enum fs_directory_inos {
+ PROC_FS_CODA = PROC_BUS_LAST,
+ PROC_FS_LAST
+};
+
+enum fs_coda_directory_inos {
+ PROC_VFS_STATS = PROC_FS_LAST,
+ PROC_UPCALL_STATS,
+ PROC_PERMISSION_STATS,
+ PROC_CACHE_INV_STATS,
+ PROC_CODA_FS_LAST
+};
+
+/* Finally, the dynamically allocatable proc entries are reserved: */
+
+#define PROC_DYNAMIC_FIRST 4096
+#define PROC_NDYNAMIC 4096
+#define PROC_OPENPROM_FIRST (PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
+#define PROC_OPENPROM PROC_OPENPROM_FIRST
+#define PROC_NOPENPROM 4096
+#define PROC_OPENPROMD_FIRST (PROC_OPENPROM_FIRST+PROC_NOPENPROM)
+#define PROC_NOPENPROMD 4096
+
+#define PROC_SUPER_MAGIC 0x9fa0
+
+/*
+ * This is not completely implemented yet. The idea is to
+ * create an in-memory tree (like the actual /proc filesystem
+ * tree) of these proc_dir_entries, so that we can dynamically
+ * add new files to /proc.
+ *
+ * The "next" pointer creates a linked list of one /proc directory,
+ * while parent/subdir create the directory structure (every
+ * /proc file has a parent, but "subdir" is NULL for all
+ * non-directory entries).
+ *
+ * "get_info" is called at "read", while "fill_inode" is used to
+ * fill in file type/protection/owner information specific to the
+ * particular /proc file.
+ */
+struct proc_dir_entry {
+ unsigned short low_ino;
+ unsigned short namelen;
+ const char *name;
+ mode_t mode;
+ nlink_t nlink;
+ uid_t uid;
+ gid_t gid;
+ unsigned long size;
+ struct inode_operations * ops;
+ int (*get_info)(char *, char **, off_t, int, int);
+ void (*fill_inode)(struct inode *, int);
+ struct proc_dir_entry *next, *parent, *subdir;
+ void *data;
+ int (*read_proc)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+ int (*write_proc)(struct file *file, const char *buffer,
+ unsigned long count, void *data);
+ int (*readlink_proc)(struct proc_dir_entry *de, char *page);
+ unsigned int count; /* use count */
+ int deleted; /* delete flag */
+};
+
+typedef int (read_proc_t)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+typedef int (write_proc_t)(struct file *file, const char *buffer,
+ unsigned long count, void *data);
+
+extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
+ off_t offset, int length, int inout);
+
+#ifdef CONFIG_PROC_FS
+
+extern struct proc_dir_entry proc_root;
+extern struct proc_dir_entry proc_root_fs;
+extern struct proc_dir_entry *proc_net;
+extern struct proc_dir_entry *proc_scsi;
+extern struct proc_dir_entry proc_sys;
+extern struct proc_dir_entry proc_openprom;
+extern struct proc_dir_entry proc_pid;
+extern struct proc_dir_entry proc_pid_fd;
+extern struct proc_dir_entry proc_mca;
+extern struct proc_dir_entry *proc_bus;
+
+extern struct inode_operations proc_scsi_inode_operations;
+
+extern void proc_root_init(void);
+extern void proc_base_init(void);
+
+extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *);
+extern int proc_unregister(struct proc_dir_entry *, int);
+
+static inline int proc_net_register(struct proc_dir_entry * x)
+{
+ return proc_register(proc_net, x);
+}
+
+static inline int proc_net_unregister(int x)
+{
+ return proc_unregister(proc_net, x);
+}
+
+static inline int proc_scsi_register(struct proc_dir_entry *driver,
+ struct proc_dir_entry *x)
+{
+ x->ops = &proc_scsi_inode_operations;
+ if(x->low_ino < PROC_SCSI_FILE){
+ return(proc_register(proc_scsi, x));
+ }else{
+ return(proc_register(driver, x));
+ }
+}
+
+static inline int proc_scsi_unregister(struct proc_dir_entry *driver, int x)
+{
+ extern void scsi_init_free(char *ptr, unsigned int size);
+
+ if(x < PROC_SCSI_FILE)
+ return(proc_unregister(proc_scsi, x));
+ else {
+ struct proc_dir_entry **p = &driver->subdir, *dp;
+ int ret;
+
+ while ((dp = *p) != NULL) {
+ if (dp->low_ino == x)
+ break;
+ p = &dp->next;
+ }
+ ret = proc_unregister(driver, x);
+ scsi_init_free((char *) dp, sizeof(struct proc_dir_entry) + 4);
+ return(ret);
+ }
+}
+
+extern struct dentry_operations proc_dentry_operations;
+extern struct super_block *proc_read_super(struct super_block *,void *,int);
+extern int init_proc_fs(void);
+extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
+extern int proc_statfs(struct super_block *, struct statfs *, int);
+extern void proc_read_inode(struct inode *);
+extern void proc_write_inode(struct inode *);
+extern int proc_permission(struct inode *, int);
+
+extern int proc_match(int, const char *,struct proc_dir_entry *);
+
+/*
+ * These are generic /proc routines that use the internal
+ * "struct proc_dir_entry" tree to traverse the filesystem.
+ *
+ * The /proc root directory has extended versions to take care
+ * of the /proc/<pid> subdirectories.
+ */
+extern int proc_readdir(struct file *, void *, filldir_t);
+extern struct dentry *proc_lookup(struct inode *, struct dentry *);
+
+struct openpromfs_dev {
+ struct openpromfs_dev *next;
+ u32 node;
+ ino_t inode;
+ kdev_t rdev;
+ mode_t mode;
+ char name[32];
+};
+extern struct inode_operations *
+proc_openprom_register(int (*readdir)(struct file *, void *, filldir_t),
+ struct dentry * (*lookup)(struct inode *, struct dentry *),
+ void (*use)(struct inode *, int),
+ struct openpromfs_dev ***);
+extern void proc_openprom_deregister(void);
+extern void (*proc_openprom_use)(struct inode *,int);
+extern int proc_openprom_regdev(struct openpromfs_dev *);
+extern int proc_openprom_unregdev(struct openpromfs_dev *);
+
+extern struct inode_operations proc_dir_inode_operations;
+extern struct inode_operations proc_file_inode_operations;
+extern struct inode_operations proc_net_inode_operations;
+extern struct inode_operations proc_netdir_inode_operations;
+extern struct inode_operations proc_openprom_inode_operations;
+extern struct inode_operations proc_mem_inode_operations;
+extern struct inode_operations proc_sys_inode_operations;
+extern struct inode_operations proc_array_inode_operations;
+extern struct inode_operations proc_arraylong_inode_operations;
+extern struct inode_operations proc_kcore_inode_operations;
+extern struct inode_operations proc_profile_inode_operations;
+extern struct inode_operations proc_kmsg_inode_operations;
+extern struct inode_operations proc_link_inode_operations;
+extern struct inode_operations proc_fd_inode_operations;
+#if CONFIG_AP1000
+extern struct inode_operations proc_ringbuf_inode_operations;
+#endif
+extern struct inode_operations proc_omirr_inode_operations;
+extern struct inode_operations proc_ppc_htab_inode_operations;
+
+/*
+ * generic.c
+ */
+struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
+ struct proc_dir_entry *parent);
+void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
+
+/*
+ * proc_tty.c
+ */
+extern void proc_tty_init(void);
+extern void proc_tty_register_driver(struct tty_driver *driver);
+extern void proc_tty_unregister_driver(struct tty_driver *driver);
+
+/*
+ * proc_devtree.c
+ */
+extern void proc_device_tree_init(void);
+
+#else
+
+extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) { return 0; };
+extern inline int proc_unregister(struct proc_dir_entry *a, int b) { return 0; };
+extern inline int proc_net_register(struct proc_dir_entry *a) { return 0; };
+extern inline int proc_net_unregister(int x) { return 0; };
+extern inline int proc_scsi_register(struct proc_dir_entry *b, struct proc_dir_entry *c) { return 0; };
+extern inline int proc_scsi_unregister(struct proc_dir_entry *a, int x) { return 0; };
+
+extern inline struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
+ struct proc_dir_entry *parent)
+{
+ return NULL;
+}
+
+extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {};
+
+extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
+extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
+
+extern struct proc_dir_entry proc_root;
+
+#endif /* CONFIG_PROC_FS */
+#endif /* _LINUX_PROC_FS_H */
diff --git a/pfinet/linux-src/include/linux/ps2esdi.h b/pfinet/linux-src/include/linux/ps2esdi.h
new file mode 100644
index 00000000..c0e050b1
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ps2esdi.h
@@ -0,0 +1,98 @@
+#ifndef _PS2ESDI_H_
+#define _PS2ESDI_H_
+
+#define NRML_ESDI_ID 0xddff
+#define INTG_ESDI_ID 0xdf9f
+
+#define PRIMARY_IO_BASE 0x3510
+#define ALT_IO_BASE 0x3518
+
+#define ESDI_CMD_INT (io_base+0)
+#define ESDI_STT_INT (io_base+0)
+#define ESDI_CONTROL (io_base+2)
+#define ESDI_STATUS (io_base+2)
+#define ESDI_ATTN (io_base+3)
+#define ESDI_INTRPT (io_base+3)
+
+#define STATUS_ENABLED 0x01
+#define STATUS_ALTERNATE 0x02
+#define STATUS_BUSY 0x10
+#define STATUS_STAT_AVAIL 0x08
+#define STATUS_INTR 0x01
+#define STATUS_RESET_FAIL 0xea
+#define STATUS_CMD_INF 0x04
+
+#define CTRL_SOFT_RESET 0xe4
+#define CTRL_HARD_RESET 0x80
+#define CTRL_EOI 0xe2
+#define CTRL_ENABLE_DMA 0x02
+#define CTRL_ENABLE_INTR 0x01
+#define CTRL_DISABLE_INTR 0x00
+
+#define ATT_EOI 0x02
+
+/* bits of word 0 of configuration status block. more info see p.38 of tech ref */
+#define CONFIG_IS 0x10 /* Invalid Secondary */
+#define CONFIG_ZD 0x08 /* Zero Defect */
+#define CONFIG_SF 0x04 /* Skewed Format */
+#define CONFIG_FR 0x02 /* Removable */
+#define CONFIG_RT 0x01 /* Retries */
+
+#define PORT_SYS_A 0x92
+#define PORT_DMA_FN 0x18
+#define PORT_DMA_EX 0x1a
+
+#define ON (unsigned char)0x40
+#define OFF (unsigned char)~ON
+#define LITE_ON outb(inb(PORT_SYS_A) | ON,PORT_SYS_A)
+#define LITE_OFF outb((inb(PORT_SYS_A) & OFF),PORT_SYS_A)
+
+#define FAIL 0
+#define SUCCES 1
+
+#define INT_CMD_COMPLETE 0x01
+#define INT_CMD_ECC 0x03
+#define INT_CMD_RETRY 0x05
+#define INT_CMD_FORMAT 0x06
+#define INT_CMD_ECC_RETRY 0x07
+#define INT_CMD_WARNING 0x08
+#define INT_CMD_ABORT 0x09
+#define INT_RESET 0x0A
+#define INT_TRANSFER_REQ 0x0B
+#define INT_CMD_FAILED 0x0C
+#define INT_DMA_ERR 0x0D
+#define INT_CMD_BLK_ERR 0x0E
+#define INT_ATTN_ERROR 0x0F
+
+#define DMA_MASK_CHAN 0x90
+#define DMA_UNMASK_CHAN 0xA0
+#define DMA_WRITE_ADDR 0x20
+#define DMA_WRITE_TC 0x40
+#define DMA_WRITE_MODE 0x70
+
+#define CMD_GET_DEV_CONFIG 0x09
+#define CMD_READ 0x4601
+#define CMD_WRITE 0x4602
+#define DMA_READ_16 0x4C
+#define DMA_WRITE_16 0x44
+
+
+#define MB 1024*1024
+#define SECT_SIZE 512
+
+#define ERROR 1
+#define OK 0
+
+#define HDIO_GETGEO 0x0301
+
+#define FALSE 0
+#define TRUE !FALSE
+
+struct ps2esdi_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ unsigned long start;
+};
+
+#endif /* _PS2ESDI_H_ */
diff --git a/pfinet/linux-src/include/linux/ptrace.h b/pfinet/linux-src/include/linux/ptrace.h
new file mode 100644
index 00000000..0a02879d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ptrace.h
@@ -0,0 +1,26 @@
+#ifndef _LINUX_PTRACE_H
+#define _LINUX_PTRACE_H
+/* ptrace.h */
+/* structs and defines to help the user use the ptrace system call. */
+
+/* has the defines to get at the registers. */
+
+#define PTRACE_TRACEME 0
+#define PTRACE_PEEKTEXT 1
+#define PTRACE_PEEKDATA 2
+#define PTRACE_PEEKUSR 3
+#define PTRACE_POKETEXT 4
+#define PTRACE_POKEDATA 5
+#define PTRACE_POKEUSR 6
+#define PTRACE_CONT 7
+#define PTRACE_KILL 8
+#define PTRACE_SINGLESTEP 9
+
+#define PTRACE_ATTACH 0x10
+#define PTRACE_DETACH 0x11
+
+#define PTRACE_SYSCALL 24
+
+#include <asm/ptrace.h>
+
+#endif
diff --git a/pfinet/linux-src/include/linux/qic117.h b/pfinet/linux-src/include/linux/qic117.h
new file mode 100644
index 00000000..07b537e5
--- /dev/null
+++ b/pfinet/linux-src/include/linux/qic117.h
@@ -0,0 +1,290 @@
+#ifndef _QIC117_H
+#define _QIC117_H
+
+/*
+ * Copyright (C) 1993-1996 Bas Laarhoven,
+ * (C) 1997 Claus-Justus Heine.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/include/linux/qic117.h,v $
+ * $Revision: 1.2 $
+ * $Date: 1997/10/05 19:19:32 $
+ *
+ * This file contains QIC-117 spec. related definitions for the
+ * QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
+ *
+ * These data were taken from the Quarter-Inch Cartridge
+ * Drive Standards, Inc. document titled:
+ * `Common Command Set Interface Specification for Flexible
+ * Disk Controller Based Minicartridge Tape Drives'
+ * document QIC-117 Revision J, 28 Aug 96.
+ * For more information, contact:
+ * Quarter-Inch Cartridge Drive Standards, Inc.
+ * 311 East Carrillo Street
+ * Santa Barbara, California 93101
+ * Telephone (805) 963-3853
+ * Fax (805) 962-1541
+ * WWW http://www.qic.org
+ *
+ * Current QIC standard revisions (of interest) are:
+ * QIC-40-MC, Rev. M, 2 Sep 92.
+ * QIC-80-MC, Rev. N, 20 Mar 96.
+ * QIC-80-MC, Rev. K, 15 Dec 94.
+ * QIC-113, Rev. G, 15 Jun 95.
+ * QIC-117, Rev. J, 28 Aug 96.
+ * QIC-122, Rev. B, 6 Mar 91.
+ * QIC-130, Rev. C, 2 Sep 92.
+ * QIC-3010-MC, Rev. F, 14 Jun 95.
+ * QIC-3020-MC, Rev. G, 31 Aug 95.
+ * QIC-CRF3, Rev. B, 15 Jun 95.
+ * */
+
+/*
+ * QIC-117 common command set rev. J.
+ * These commands are sent to the tape unit
+ * as number of pulses over the step line.
+ */
+
+typedef enum {
+ QIC_NO_COMMAND = 0,
+ QIC_RESET = 1,
+ QIC_REPORT_NEXT_BIT = 2,
+ QIC_PAUSE = 3,
+ QIC_MICRO_STEP_PAUSE = 4,
+ QIC_ALTERNATE_TIMEOUT = 5,
+ QIC_REPORT_DRIVE_STATUS = 6,
+ QIC_REPORT_ERROR_CODE = 7,
+ QIC_REPORT_DRIVE_CONFIGURATION = 8,
+ QIC_REPORT_ROM_VERSION = 9,
+ QIC_LOGICAL_FORWARD = 10,
+ QIC_PHYSICAL_REVERSE = 11,
+ QIC_PHYSICAL_FORWARD = 12,
+ QIC_SEEK_HEAD_TO_TRACK = 13,
+ QIC_SEEK_LOAD_POINT = 14,
+ QIC_ENTER_FORMAT_MODE = 15,
+ QIC_WRITE_REFERENCE_BURST = 16,
+ QIC_ENTER_VERIFY_MODE = 17,
+ QIC_STOP_TAPE = 18,
+/* commands 19-20: reserved */
+ QIC_MICRO_STEP_HEAD_UP = 21,
+ QIC_MICRO_STEP_HEAD_DOWN = 22,
+ QIC_SOFT_SELECT = 23,
+ QIC_SOFT_DESELECT = 24,
+ QIC_SKIP_REVERSE = 25,
+ QIC_SKIP_FORWARD = 26,
+ QIC_SELECT_RATE = 27,
+/* command 27, in ccs2: Select Rate or Format */
+ QIC_ENTER_DIAGNOSTIC_1 = 28,
+ QIC_ENTER_DIAGNOSTIC_2 = 29,
+ QIC_ENTER_PRIMARY_MODE = 30,
+/* command 31: vendor unique */
+ QIC_REPORT_VENDOR_ID = 32,
+ QIC_REPORT_TAPE_STATUS = 33,
+ QIC_SKIP_EXTENDED_REVERSE = 34,
+ QIC_SKIP_EXTENDED_FORWARD = 35,
+ QIC_CALIBRATE_TAPE_LENGTH = 36,
+ QIC_REPORT_FORMAT_SEGMENTS = 37,
+ QIC_SET_FORMAT_SEGMENTS = 38,
+/* commands 39-45: reserved */
+ QIC_PHANTOM_SELECT = 46,
+ QIC_PHANTOM_DESELECT = 47
+} qic117_cmd_t;
+
+typedef enum {
+ discretional = 0, required, ccs1, ccs2
+} qic_compatibility;
+
+typedef enum {
+ unused, mode, motion, report
+} command_types;
+
+struct qic117_command_table {
+ char *name;
+ __u8 mask;
+ __u8 state;
+ __u8 cmd_type;
+ __u8 non_intr;
+ __u8 level;
+};
+
+#define QIC117_COMMANDS {\
+/* command mask state cmd_type */\
+/* | name | | | non_intr */\
+/* | | | | | | level */\
+/* 0*/ {NULL, 0x00, 0x00, mode, 0, discretional},\
+/* 1*/ {"soft reset", 0x00, 0x00, motion, 1, required},\
+/* 2*/ {"report next bit", 0x00, 0x00, report, 0, required},\
+/* 3*/ {"pause", 0x36, 0x24, motion, 1, required},\
+/* 4*/ {"micro step pause", 0x36, 0x24, motion, 1, required},\
+/* 5*/ {"alternate command timeout", 0x00, 0x00, mode, 0, required},\
+/* 6*/ {"report drive status", 0x00, 0x00, report, 0, required},\
+/* 7*/ {"report error code", 0x01, 0x01, report, 0, required},\
+/* 8*/ {"report drive configuration",0x00, 0x00, report, 0, required},\
+/* 9*/ {"report rom version", 0x00, 0x00, report, 0, required},\
+/*10*/ {"logical forward", 0x37, 0x25, motion, 0, required},\
+/*11*/ {"physical reverse", 0x17, 0x05, motion, 0, required},\
+/*12*/ {"physical forward", 0x17, 0x05, motion, 0, required},\
+/*13*/ {"seek head to track", 0x37, 0x25, motion, 0, required},\
+/*14*/ {"seek load point", 0x17, 0x05, motion, 1, required},\
+/*15*/ {"enter format mode", 0x1f, 0x05, mode, 0, required},\
+/*16*/ {"write reference burst", 0x1f, 0x05, motion, 1, required},\
+/*17*/ {"enter verify mode", 0x37, 0x25, mode, 0, required},\
+/*18*/ {"stop tape", 0x00, 0x00, motion, 1, required},\
+/*19*/ {"reserved (19)", 0x00, 0x00, unused, 0, discretional},\
+/*20*/ {"reserved (20)", 0x00, 0x00, unused, 0, discretional},\
+/*21*/ {"micro step head up", 0x02, 0x00, motion, 0, required},\
+/*22*/ {"micro step head down", 0x02, 0x00, motion, 0, required},\
+/*23*/ {"soft select", 0x00, 0x00, mode, 0, discretional},\
+/*24*/ {"soft deselect", 0x00, 0x00, mode, 0, discretional},\
+/*25*/ {"skip segments reverse", 0x36, 0x24, motion, 1, required},\
+/*26*/ {"skip segments forward", 0x36, 0x24, motion, 1, required},\
+/*27*/ {"select rate or format", 0x03, 0x01, mode, 0, required /* [ccs2] */},\
+/*28*/ {"enter diag mode 1", 0x00, 0x00, mode, 0, discretional},\
+/*29*/ {"enter diag mode 2", 0x00, 0x00, mode, 0, discretional},\
+/*30*/ {"enter primary mode", 0x00, 0x00, mode, 0, required},\
+/*31*/ {"vendor unique (31)", 0x00, 0x00, unused, 0, discretional},\
+/*32*/ {"report vendor id", 0x00, 0x00, report, 0, required},\
+/*33*/ {"report tape status", 0x04, 0x04, report, 0, ccs1},\
+/*34*/ {"skip extended reverse", 0x36, 0x24, motion, 1, ccs1},\
+/*35*/ {"skip extended forward", 0x36, 0x24, motion, 1, ccs1},\
+/*36*/ {"calibrate tape length", 0x17, 0x05, motion, 1, ccs2},\
+/*37*/ {"report format segments", 0x17, 0x05, report, 0, ccs2},\
+/*38*/ {"set format segments", 0x17, 0x05, mode, 0, ccs2},\
+/*39*/ {"reserved (39)", 0x00, 0x00, unused, 0, discretional},\
+/*40*/ {"vendor unique (40)", 0x00, 0x00, unused, 0, discretional},\
+/*41*/ {"vendor unique (41)", 0x00, 0x00, unused, 0, discretional},\
+/*42*/ {"vendor unique (42)", 0x00, 0x00, unused, 0, discretional},\
+/*43*/ {"vendor unique (43)", 0x00, 0x00, unused, 0, discretional},\
+/*44*/ {"vendor unique (44)", 0x00, 0x00, unused, 0, discretional},\
+/*45*/ {"vendor unique (45)", 0x00, 0x00, unused, 0, discretional},\
+/*46*/ {"phantom select", 0x00, 0x00, mode, 0, discretional},\
+/*47*/ {"phantom deselect", 0x00, 0x00, mode, 0, discretional},\
+}
+
+/*
+ * Status bits returned by QIC_REPORT_DRIVE_STATUS
+ */
+
+#define QIC_STATUS_READY 0x01 /* Drive is ready or idle. */
+#define QIC_STATUS_ERROR 0x02 /* Error detected, must read
+ error code to clear this */
+#define QIC_STATUS_CARTRIDGE_PRESENT 0x04 /* Tape is present */
+#define QIC_STATUS_WRITE_PROTECT 0x08 /* Tape is write protected */
+#define QIC_STATUS_NEW_CARTRIDGE 0x10 /* New cartridge inserted, must
+ read error status to clear. */
+#define QIC_STATUS_REFERENCED 0x20 /* Cartridge appears to have been
+ formatted. */
+#define QIC_STATUS_AT_BOT 0x40 /* Cartridge is at physical
+ beginning of tape. */
+#define QIC_STATUS_AT_EOT 0x80 /* Cartridge is at physical end
+ of tape. */
+/*
+ * Status bits returned by QIC_REPORT_DRIVE_CONFIGURATION
+ */
+
+#define QIC_CONFIG_RATE_MASK 0x18
+#define QIC_CONFIG_RATE_SHIFT 3
+#define QIC_CONFIG_RATE_250 0
+#define QIC_CONFIG_RATE_500 2
+#define QIC_CONFIG_RATE_1000 3
+#define QIC_CONFIG_RATE_2000 1
+#define QIC_CONFIG_RATE_4000 0 /* since QIC-117 Rev. J */
+
+#define QIC_CONFIG_LONG 0x40 /* Extra Length Tape Detected */
+#define QIC_CONFIG_80 0x80 /* QIC-80 detected. */
+
+/*
+ * Status bits returned by QIC_REPORT_TAPE_STATUS
+ */
+
+#define QIC_TAPE_STD_MASK 0x0f
+#define QIC_TAPE_QIC40 0x01
+#define QIC_TAPE_QIC80 0x02
+#define QIC_TAPE_QIC3020 0x03
+#define QIC_TAPE_QIC3010 0x04
+
+#define QIC_TAPE_LEN_MASK 0x70
+#define QIC_TAPE_205FT 0x10
+#define QIC_TAPE_307FT 0x20
+#define QIC_TAPE_VARIABLE 0x30
+#define QIC_TAPE_1100FT 0x40
+#define QIC_TAPE_FLEX 0x60
+
+#define QIC_TAPE_WIDE 0x80
+
+/* Define a value (in feet) slightly higher than
+ * the possible maximum tape length.
+ */
+#define QIC_TOP_TAPE_LEN 1500
+
+/*
+ * Errors: List of error codes, and their severity.
+ */
+
+typedef struct {
+ char *message; /* Text describing the error. */
+ unsigned int fatal:1; /* Non-zero if the error is fatal. */
+} ftape_error;
+
+#define QIC117_ERRORS {\
+ /* 0*/ { "No error", 0, },\
+ /* 1*/ { "Command Received while Drive Not Ready", 0, },\
+ /* 2*/ { "Cartridge Not Present or Removed", 1, },\
+ /* 3*/ { "Motor Speed Error (not within 1%)", 1, },\
+ /* 4*/ { "Motor Speed Fault (jammed, or gross speed error", 1, },\
+ /* 5*/ { "Cartridge Write Protected", 1, },\
+ /* 6*/ { "Undefined or Reserved Command Code", 1, },\
+ /* 7*/ { "Illegal Track Address Specified for Seek", 1, },\
+ /* 8*/ { "Illegal Command in Report Subcontext", 0, },\
+ /* 9*/ { "Illegal Entry into a Diagnostic Mode", 1, },\
+ /*10*/ { "Broken Tape Detected (based on hole sensor)", 1, },\
+ /*11*/ { "Warning--Read Gain Setting Error", 1, },\
+ /*12*/ { "Command Received While Error Status Pending (obs)", 1, },\
+ /*13*/ { "Command Received While New Cartridge Pending", 1, },\
+ /*14*/ { "Command Illegal or Undefined in Primary Mode", 1, },\
+ /*15*/ { "Command Illegal or Undefined in Format Mode", 1, },\
+ /*16*/ { "Command Illegal or Undefined in Verify Mode", 1, },\
+ /*17*/ { "Logical Forward Not at Logical BOT or no Format Segments in Format Mode", 1, },\
+ /*18*/ { "Logical EOT Before All Segments generated", 1, },\
+ /*19*/ { "Command Illegal When Cartridge Not Referenced", 1, },\
+ /*20*/ { "Self-Diagnostic Failed (cannot be cleared)", 1, },\
+ /*21*/ { "Warning EEPROM Not Initialized, Defaults Set", 1, },\
+ /*22*/ { "EEPROM Corrupted or Hardware Failure", 1, },\
+ /*23*/ { "Motion Time-out Error", 1, },\
+ /*24*/ { "Data Segment Too Long -- Logical Forward or Pause", 1, },\
+ /*25*/ { "Transmit Overrun (obs)", 1, },\
+ /*26*/ { "Power On Reset Occurred", 0, },\
+ /*27*/ { "Software Reset Occurred", 0, },\
+ /*28*/ { "Diagnostic Mode 1 Error", 1, },\
+ /*29*/ { "Diagnostic Mode 2 Error", 1, },\
+ /*30*/ { "Command Received During Non-Interruptible Process", 1, },\
+ /*31*/ { "Rate or Format Selection Error", 1, },\
+ /*32*/ { "Illegal Command While in High Speed Mode", 1, },\
+ /*33*/ { "Illegal Seek Segment Value", 1, },\
+ /*34*/ { "Invalid Media", 1, },\
+ /*35*/ { "Head Positioning Failure", 1, },\
+ /*36*/ { "Write Reference Burst Failure", 1, },\
+ /*37*/ { "Prom Code Missing", 1, },\
+ /*38*/ { "Invalid Format", 1, },\
+ /*39*/ { "EOT/BOT System Failure", 1, },\
+ /*40*/ { "Prom A Checksum Error", 1, },\
+ /*41*/ { "Drive Wakeup Reset Occurred", 1, },\
+ /*42*/ { "Prom B Checksum Error", 1, },\
+ /*43*/ { "Illegal Entry into Format Mode", 1, },\
+}
+
+#endif /* _QIC117_H */
diff --git a/pfinet/linux-src/include/linux/qnx4_fs.h b/pfinet/linux-src/include/linux/qnx4_fs.h
new file mode 100644
index 00000000..c5a01039
--- /dev/null
+++ b/pfinet/linux-src/include/linux/qnx4_fs.h
@@ -0,0 +1,123 @@
+/*
+ * Name : qnx4_fs.h
+ * Author : Richard Frowijn
+ * Function : qnx4 global filesystem definitions
+ * Version : 1.0
+ * Last modified : 23-03-1998
+ *
+ * History : 23-03-1998 created
+ */
+#ifndef _LINUX_QNX4_FS_H
+#define _LINUX_QNX4_FS_H
+
+#include <linux/qnxtypes.h>
+
+#define QNX4_ROOT_INO 1
+
+#define _MAX_XTNTS_PER_XBLK 60
+/* for di_status */
+#define QNX4_FILE_USED 0x01
+#define QNX4_FILE_MODIFIED 0x02
+#define QNX4_FILE_BUSY 0x04
+#define QNX4_FILE_LINK 0x08
+#define QNX4_FILE_INODE 0x10
+#define QNX4_FILE_FSYSCLEAN 0x20
+
+#define QNX4_I_MAP_SLOTS 8
+#define QNX4_Z_MAP_SLOTS 64
+#define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */
+#define QNX4_VALID_FS 0x0001 /* Clean fs. */
+#define QNX4_ERROR_FS 0x0002 /* fs has errors. */
+#define QNX4_BLOCK_SIZE 0x200 /* blocksize of 512 bytes */
+#define QNX4_DIR_ENTRY_SIZE 0x040 /* dir entry size */
+#define QNX4_XBLK_ENTRY_SIZE 0x200 /* xblk entry size */
+#define QNX4_INODES_PER_BLOCK 0x08 /* 512 / 64 */
+
+/* for filenames */
+#define _SHORT_NAME_MAX 16
+#define QNX4_NAME_MAX 48
+
+/*
+ * This is the original qnx4 inode layout on disk.
+ */
+struct qnx4_inode_entry {
+ char di_fname[16];
+ off_t di_size;
+ _xtnt_t di_first_xtnt;
+ long di_xblk;
+ time_t di_ftime;
+ time_t di_mtime;
+ time_t di_atime;
+ time_t di_ctime;
+ _nxtnt_t di_num_xtnts;
+ mode_t di_mode;
+ muid_t di_uid;
+ mgid_t di_gid;
+ nlink_t di_nlink;
+ char di_zero[4];
+ _ftype_t di_type;
+ unsigned char di_status;
+};
+
+struct qnx4_link_info {
+ char dl_fname[QNX4_NAME_MAX];
+ long dl_inode_blk;
+ unsigned char dl_inode_ndx;
+ unsigned char dl_spare[10];
+ unsigned char dl_status;
+};
+
+struct qnx4_xblk {
+ long xblk_next_xblk;
+ long xblk_prev_xblk;
+ unsigned char xblk_num_xtnts;
+ char xblk_spare[3];
+ long xblk_num_blocks;
+ _xtnt_t xblk_xnts[_MAX_XTNTS_PER_XBLK];
+ char xblk_signature[8];
+ _xtnt_t xblk_first_xtnt;
+};
+
+struct qnx4_super_block {
+ struct qnx4_inode_entry RootDir;
+ struct qnx4_inode_entry Inode;
+ struct qnx4_inode_entry Boot;
+ struct qnx4_inode_entry AltBoot;
+};
+
+#ifdef __KERNEL__
+
+#define QNX4_DEBUG 0
+
+#if QNX4_DEBUG
+#define QNX4DEBUG(X) printk X
+#else
+#define QNX4DEBUG(X) (void) 0
+#endif
+
+extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
+extern unsigned long qnx4_count_free_inodes(struct super_block *sb);
+extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
+
+extern struct buffer_head *qnx4_getblk(struct inode *, int, int);
+extern struct buffer_head *qnx4_bread(struct inode *, int, int);
+
+extern int init_qnx4_fs(void);
+extern int qnx4_create(struct inode *dir, struct dentry *dentry, int mode);
+extern struct inode_operations qnx4_file_inode_operations;
+extern struct inode_operations qnx4_dir_inode_operations;
+extern struct inode_operations qnx4_symlink_inode_operations;
+extern int qnx4_is_free(struct super_block *sb, int block);
+extern int qnx4_set_bitmap(struct super_block *sb, int block, int busy);
+extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode);
+extern void qnx4_truncate(struct inode *inode);
+extern void qnx4_free_inode(struct inode *inode);
+extern int qnx4_unlink(struct inode *dir, struct dentry *dentry);
+extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry);
+extern int qnx4_sync_file(struct file *file, struct dentry *dentry);
+extern int qnx4_sync_inode(struct inode *inode);
+extern int qnx4_bmap(struct inode *inode, int block);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/qnx4_fs_i.h b/pfinet/linux-src/include/linux/qnx4_fs_i.h
new file mode 100644
index 00000000..83d53e52
--- /dev/null
+++ b/pfinet/linux-src/include/linux/qnx4_fs_i.h
@@ -0,0 +1,38 @@
+/*
+ * Name : qnx4_fs_i.h
+ * Author : Richard Frowijn
+ * Function : qnx4 inode definitions
+ * Version : 1.0
+ * Last modified : 25-05-1998
+ *
+ * History : 23-03-1998 created
+ *
+ */
+#ifndef _QNX4_FS_I
+#define _QNX4_FS_I
+
+#include <linux/qnxtypes.h>
+
+/*
+ * qnx4 fs inode entry
+ */
+struct qnx4_inode_info {
+ char i_reserved[16]; /* 16 */
+ off_t i_size; /* 4 */
+ _xtnt_t i_first_xtnt; /* 8 */
+ long i_xblk; /* 4 */
+ time_t i_ftime; /* 4 */
+ time_t i_mtime; /* 4 */
+ time_t i_atime; /* 4 */
+ time_t i_ctime; /* 4 */
+ _nxtnt_t i_num_xtnts; /* 2 */
+ mode_t i_mode; /* 2 */
+ muid_t i_uid; /* 2 */
+ mgid_t i_gid; /* 2 */
+ nlink_t i_nlink; /* 2 */
+ char i_zero[4]; /* 4 */
+ _ftype_t i_type; /* 1 */
+ unsigned char i_status; /* 1 */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/qnx4_fs_sb.h b/pfinet/linux-src/include/linux/qnx4_fs_sb.h
new file mode 100644
index 00000000..9f28d3cb
--- /dev/null
+++ b/pfinet/linux-src/include/linux/qnx4_fs_sb.h
@@ -0,0 +1,27 @@
+/*
+ * Name : qnx4_fs_sb.h
+ * Author : Richard Frowijn
+ * Function : qnx4 superblock definitions
+ * Version : 1.0
+ * Last modified : 20-05-1998
+ *
+ * History : 23-03-1998 created
+ *
+ */
+#ifndef _QNX4_FS_SB
+#define _QNX4_FS_SB
+
+#include <linux/qnxtypes.h>
+
+/*
+ * qnx4 super-block data in memory
+ */
+
+struct qnx4_sb_info {
+ struct buffer_head *sb_buf; /* superblock buffer */
+ struct qnx4_super_block *sb; /* our superblock */
+ unsigned int Version; /* may be useful */
+ struct qnx4_inode_entry *BitMap; /* useful */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/qnxtypes.h b/pfinet/linux-src/include/linux/qnxtypes.h
new file mode 100644
index 00000000..054da0d1
--- /dev/null
+++ b/pfinet/linux-src/include/linux/qnxtypes.h
@@ -0,0 +1,28 @@
+/*
+ * Name : qnxtypes.h
+ * Author : Richard Frowijn
+ * Function : standard qnx types
+ * Version : 1.0
+ * Last modified : 22-03-1998
+ *
+ * History : 22-03-1998 created
+ *
+ */
+
+#ifndef _QNX4TYPES_H
+#define _QNX4TYPES_H
+
+typedef unsigned short _nxtnt_t;
+typedef unsigned char _ftype_t;
+
+typedef struct {
+ long xtnt_blk;
+ long xtnt_size;
+} _xtnt_t;
+
+typedef unsigned short muid_t;
+typedef unsigned short mgid_t;
+typedef unsigned long qnx_off_t;
+typedef unsigned short qnx_nlink_t;
+
+#endif
diff --git a/pfinet/linux-src/include/linux/quota.h b/pfinet/linux-src/include/linux/quota.h
new file mode 100644
index 00000000..2c4a5bce
--- /dev/null
+++ b/pfinet/linux-src/include/linux/quota.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Version: $Id: quota.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $
+ */
+
+#ifndef _LINUX_QUOTA_
+#define _LINUX_QUOTA_
+
+#include <linux/errno.h>
+
+/*
+ * Convert diskblocks to blocks and the other way around.
+ */
+#define dbtob(num) (num << 10)
+#define btodb(num) (num >> 10)
+
+/*
+ * Convert count of filesystem blocks to diskquota blocks, meant
+ * for filesystems where i_blksize != BLOCK_SIZE
+ */
+#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE)
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits Linux).
+ *
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */
+
+#define MAXQUOTAS 2
+#define USRQUOTA 0 /* element used for user quotas */
+#define GRPQUOTA 1 /* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+ "user", /* USRQUOTA */ \
+ "group", /* GRPQUOTA */ \
+ "undefined", \
+};
+
+#define QUOTAFILENAME "quota"
+#define QUOTAGROUP "staff"
+
+extern int nr_dquots, nr_free_dquots;
+extern int max_dquots;
+extern int dquot_root_squash;
+
+#define NR_DQHASH 43 /* Just an arbitrary number */
+#define NR_DQUOTS 1024 /* Maximum number of quotas active at one time (Configurable from /proc/sys/fs) */
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK 0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define Q_QUOTAON 0x0100 /* enable quotas */
+#define Q_QUOTAOFF 0x0200 /* disable quotas */
+#define Q_GETQUOTA 0x0300 /* get limits and usage */
+#define Q_SETQUOTA 0x0400 /* set limits and usage */
+#define Q_SETUSE 0x0500 /* set usage */
+#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
+#define Q_SETQLIM 0x0700 /* set limits */
+#define Q_GETSTATS 0x0800 /* get collected stats */
+#define Q_RSQUASH 0x1000 /* set root_squash option */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.
+ */
+struct dqblk {
+ __u32 dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ __u32 dqb_bsoftlimit; /* preferred limit on disk blks */
+ __u32 dqb_curblocks; /* current block count */
+ __u32 dqb_ihardlimit; /* absolute limit on allocated inodes */
+ __u32 dqb_isoftlimit; /* preferred inode limit */
+ __u32 dqb_curinodes; /* current # allocated inodes */
+ time_t dqb_btime; /* time limit for excessive disk use */
+ time_t dqb_itime; /* time limit for excessive inode use */
+};
+
+/*
+ * Shorthand notation.
+ */
+#define dq_bhardlimit dq_dqb.dqb_bhardlimit
+#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit
+#define dq_curblocks dq_dqb.dqb_curblocks
+#define dq_ihardlimit dq_dqb.dqb_ihardlimit
+#define dq_isoftlimit dq_dqb.dqb_isoftlimit
+#define dq_curinodes dq_dqb.dqb_curinodes
+#define dq_btime dq_dqb.dqb_btime
+#define dq_itime dq_dqb.dqb_itime
+
+#define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk)))
+
+struct dqstats {
+ __u32 lookups;
+ __u32 drops;
+ __u32 reads;
+ __u32 writes;
+ __u32 cache_hits;
+ __u32 allocated_dquots;
+ __u32 free_dquots;
+ __u32 syncs;
+};
+
+#ifdef __KERNEL__
+
+/*
+ * Maximum length of a message generated in the quota system,
+ * that needs to be kicked onto the tty.
+ */
+#define MAX_QUOTA_MESSAGE 75
+
+#define DQ_LOCKED 0x01 /* locked for update */
+#define DQ_WANT 0x02 /* wanted for update */
+#define DQ_MOD 0x04 /* dquot modified since read */
+#define DQ_BLKS 0x10 /* uid/gid has been warned about blk limit */
+#define DQ_INODES 0x20 /* uid/gid has been warned about inode limit */
+#define DQ_FAKE 0x40 /* no limits only usage */
+
+struct dquot {
+ struct dquot *dq_next; /* Pointer to next dquot */
+ struct dquot **dq_pprev;
+ struct list_head dq_free; /* free list element */
+ struct dquot *dq_hash_next; /* Pointer to next in dquot_hash */
+ struct dquot **dq_hash_pprev; /* Pointer to previous in dquot_hash */
+ struct wait_queue *dq_wait; /* Pointer to waitqueue */
+ int dq_count; /* Reference count */
+
+ /* fields after this point are cleared when invalidating */
+ struct vfsmount *dq_mnt; /* VFS_mount_point this applies to */
+ unsigned int dq_id; /* ID this applies to (uid, gid) */
+ kdev_t dq_dev; /* Device this applies to */
+ short dq_type; /* Type of quota */
+ short dq_flags; /* See DQ_* */
+ unsigned long dq_referenced; /* Number of times this dquot was
+ referenced during its lifetime */
+ struct dqblk dq_dqb; /* Diskquota usage */
+};
+
+#define NODQUOT (struct dquot *)NULL
+
+/*
+ * Flags used for set_dqblk.
+ */
+#define QUOTA_SYSCALL 0x01
+#define SET_QUOTA 0x02
+#define SET_USE 0x04
+#define SET_QLIMIT 0x08
+
+#define QUOTA_OK 0
+#define NO_QUOTA 1
+
+#else
+
+# /* nodep */ include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int quotactl __P ((int, const char *, int, caddr_t));
+__END_DECLS
+
+#endif /* __KERNEL__ */
+#endif /* _QUOTA_ */
diff --git a/pfinet/linux-src/include/linux/quotaops.h b/pfinet/linux-src/include/linux/quotaops.h
new file mode 100644
index 00000000..bb76e715
--- /dev/null
+++ b/pfinet/linux-src/include/linux/quotaops.h
@@ -0,0 +1,134 @@
+/*
+ * Definitions for diskquota-operations. When diskquota is configured these
+ * macros expand to the right source-code.
+ *
+ * Author: Marco van Wieringen <mvw@planets.elm.net>
+ *
+ * Version: $Id: quotaops.h,v 1.2 1998/01/15 16:22:26 ecd Exp $
+ *
+ */
+#ifndef _LINUX_QUOTAOPS_
+#define _LINUX_QUOTAOPS_
+
+#include <linux/config.h>
+
+#if defined(CONFIG_QUOTA)
+
+/*
+ * declaration of quota_function calls in kernel.
+ */
+extern void dquot_initialize(struct inode *inode, short type);
+extern void dquot_drop(struct inode *inode);
+extern void invalidate_dquots(kdev_t dev, short type);
+extern int quota_off(kdev_t dev, short type);
+extern int sync_dquots(kdev_t dev, short type);
+
+extern int dquot_alloc_block(const struct inode *inode, unsigned long number,
+ uid_t initiator, char warn);
+extern int dquot_alloc_inode(const struct inode *inode, unsigned long number,
+ uid_t initiator);
+
+extern void dquot_free_block(const struct inode *inode, unsigned long number);
+extern void dquot_free_inode(const struct inode *inode, unsigned long number);
+
+extern int dquot_transfer(struct dentry *dentry, struct iattr *iattr,
+ uid_t initiator);
+
+/*
+ * Operations supported for diskquotas.
+ */
+extern __inline__ void DQUOT_INIT(struct inode *inode)
+{
+ if (inode->i_sb && inode->i_sb->dq_op)
+ inode->i_sb->dq_op->initialize(inode, -1);
+}
+
+extern __inline__ void DQUOT_DROP(struct inode *inode)
+{
+ if (IS_QUOTAINIT(inode)) {
+ if (inode->i_sb && inode->i_sb->dq_op)
+ inode->i_sb->dq_op->drop(inode);
+ }
+}
+
+extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+{
+ if (sb->dq_op) {
+ if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize),
+ current->fsuid, 0) == NO_QUOTA)
+ return 1;
+ }
+ return 0;
+}
+
+extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+{
+ if (sb->dq_op) {
+ if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize),
+ current->fsuid, 1) == NO_QUOTA)
+ return 1;
+ }
+ return 0;
+}
+
+extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
+{
+ if (sb->dq_op) {
+ sb->dq_op->initialize (inode, -1);
+ if (sb->dq_op->alloc_inode (inode, 1, current->fsuid))
+ return 1;
+ }
+ inode->i_flags |= S_QUOTA;
+ return 0;
+}
+
+extern __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+{
+ if (sb->dq_op)
+ sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize));
+}
+
+extern __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
+{
+ if (sb->dq_op)
+ sb->dq_op->free_inode(inode, 1);
+}
+
+extern __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
+{
+ int error = -EDQUOT;
+
+ if (dentry->d_inode->i_sb->dq_op) {
+ dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1);
+ error = dentry->d_inode->i_sb->dq_op->transfer(dentry, iattr, current->fsuid);
+ } else {
+ error = notify_change(dentry, iattr);
+ }
+ return error;
+}
+
+#define DQUOT_SYNC(dev) sync_dquots(dev, -1)
+#define DQUOT_OFF(dev) quota_off(dev, -1)
+
+#else
+
+/*
+ * NO-OP when quota not configured.
+ */
+#define DQUOT_INIT(inode) do { } while(0)
+#define DQUOT_DROP(inode) do { } while(0)
+#define DQUOT_PREALLOC_BLOCK(sb, inode, nr) (0)
+#define DQUOT_ALLOC_BLOCK(sb, inode, nr) (0)
+#define DQUOT_ALLOC_INODE(sb, inode) (0)
+#define DQUOT_FREE_BLOCK(sb, inode, nr) do { } while(0)
+#define DQUOT_FREE_INODE(sb, inode) do { } while(0)
+#define DQUOT_SYNC(dev) do { } while(0)
+#define DQUOT_OFF(dev) do { } while(0)
+
+/*
+ * Special case expands to a simple notify_change.
+ */
+#define DQUOT_TRANSFER(dentry, iattr) notify_change(dentry, iattr)
+
+#endif /* CONFIG_QUOTA */
+#endif /* _LINUX_QUOTAOPS_ */
diff --git a/pfinet/linux-src/include/linux/raid0.h b/pfinet/linux-src/include/linux/raid0.h
new file mode 100644
index 00000000..e1ae51c0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/raid0.h
@@ -0,0 +1,27 @@
+#ifndef _RAID0_H
+#define _RAID0_H
+
+struct strip_zone
+{
+ int zone_offset; /* Zone offset in md_dev */
+ int dev_offset; /* Zone offset in real dev */
+ int size; /* Zone size */
+ int nb_dev; /* Number of devices attached to the zone */
+ struct real_dev *dev[MAX_REAL]; /* Devices attached to the zone */
+};
+
+struct raid0_hash
+{
+ struct strip_zone *zone0, *zone1;
+};
+
+struct raid0_data
+{
+ struct raid0_hash *hash_table; /* Dynamically allocated */
+ struct strip_zone *strip_zone; /* This one too */
+ int nr_strip_zones;
+ struct strip_zone *smallest;
+ int nr_zones;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/raid1.h b/pfinet/linux-src/include/linux/raid1.h
new file mode 100644
index 00000000..4b031e68
--- /dev/null
+++ b/pfinet/linux-src/include/linux/raid1.h
@@ -0,0 +1,49 @@
+#ifndef _RAID1_H
+#define _RAID1_H
+
+#include <linux/md.h>
+
+struct mirror_info {
+ int number;
+ int raid_disk;
+ kdev_t dev;
+ int next;
+ int sect_limit;
+
+ /*
+ * State bits:
+ */
+ int operational;
+ int write_only;
+ int spare;
+};
+
+struct raid1_data {
+ struct md_dev *mddev;
+ struct mirror_info mirrors[MD_SB_DISKS]; /* RAID1 devices, 2 to MD_SB_DISKS */
+ int raid_disks;
+ int working_disks; /* Number of working disks */
+ int last_used;
+ unsigned long next_sect;
+ int sect_count;
+ int resync_running;
+};
+
+/*
+ * this is our 'private' 'collective' RAID1 buffer head.
+ * it contains information about what kind of IO operations were started
+ * for this RAID5 operation, and about their status:
+ */
+
+struct raid1_bh {
+ unsigned int remaining;
+ int cmd;
+ unsigned long state;
+ struct md_dev *mddev;
+ struct buffer_head *master_bh;
+ struct buffer_head *mirror_bh [MD_SB_DISKS];
+ struct buffer_head bh_req;
+ struct buffer_head *next_retry;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/raid5.h b/pfinet/linux-src/include/linux/raid5.h
new file mode 100644
index 00000000..5efd211a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/raid5.h
@@ -0,0 +1,110 @@
+#ifndef _RAID5_H
+#define _RAID5_H
+
+#ifdef __KERNEL__
+#include <linux/md.h>
+#include <asm/atomic.h>
+
+struct disk_info {
+ kdev_t dev;
+ int operational;
+ int number;
+ int raid_disk;
+ int write_only;
+ int spare;
+};
+
+struct stripe_head {
+ struct stripe_head *hash_next, **hash_pprev; /* hash pointers */
+ struct stripe_head *free_next; /* pool of free sh's */
+ struct buffer_head *buffer_pool; /* pool of free buffers */
+ struct buffer_head *bh_pool; /* pool of free bh's */
+ struct raid5_data *raid_conf;
+ struct buffer_head *bh_old[MD_SB_DISKS]; /* disk image */
+ struct buffer_head *bh_new[MD_SB_DISKS]; /* buffers of the MD device (present in buffer cache) */
+ struct buffer_head *bh_copy[MD_SB_DISKS]; /* copy on write of bh_new (bh_new can change from under us) */
+ struct buffer_head *bh_req[MD_SB_DISKS]; /* copy of bh_new (only the buffer heads), queued to the lower levels */
+ int cmd_new[MD_SB_DISKS]; /* READ/WRITE for new */
+ int new[MD_SB_DISKS]; /* buffer added since the last handle_stripe() */
+ unsigned long sector; /* sector of this row */
+ int size; /* buffers size */
+ int pd_idx; /* parity disk index */
+ int nr_pending; /* nr of pending cmds */
+ unsigned long state; /* state flags */
+ int cmd; /* stripe cmd */
+ int count; /* nr of waiters */
+ int write_method; /* reconstruct-write / read-modify-write */
+ int phase; /* PHASE_BEGIN, ..., PHASE_COMPLETE */
+ struct wait_queue *wait; /* processes waiting for this stripe */
+};
+
+/*
+ * Phase
+ */
+#define PHASE_BEGIN 0
+#define PHASE_READ_OLD 1
+#define PHASE_WRITE 2
+#define PHASE_READ 3
+#define PHASE_COMPLETE 4
+
+/*
+ * Write method
+ */
+#define METHOD_NONE 0
+#define RECONSTRUCT_WRITE 1
+#define READ_MODIFY_WRITE 2
+
+/*
+ * Stripe state
+ */
+#define STRIPE_LOCKED 0
+#define STRIPE_ERROR 1
+
+/*
+ * Stripe commands
+ */
+#define STRIPE_NONE 0
+#define STRIPE_WRITE 1
+#define STRIPE_READ 2
+
+struct raid5_data {
+ struct stripe_head **stripe_hashtbl;
+ struct md_dev *mddev;
+ struct md_thread *thread, *resync_thread;
+ struct disk_info disks[MD_SB_DISKS];
+ struct disk_info *spare;
+ int buffer_size;
+ int chunk_size, level, algorithm;
+ int raid_disks, working_disks, failed_disks;
+ int sector_count;
+ unsigned long next_sector;
+ atomic_t nr_handle;
+ struct stripe_head *next_free_stripe;
+ int nr_stripes;
+ int resync_parity;
+ int max_nr_stripes;
+ int clock;
+ int nr_hashed_stripes;
+ int nr_locked_stripes;
+ int nr_pending_stripes;
+ int nr_cached_stripes;
+
+ /*
+ * Free stripes pool
+ */
+ int nr_free_sh;
+ struct stripe_head *free_sh_list;
+ struct wait_queue *wait_for_stripe;
+};
+
+#endif
+
+/*
+ * Our supported algorithms
+ */
+#define ALGORITHM_LEFT_ASYMMETRIC 0
+#define ALGORITHM_RIGHT_ASYMMETRIC 1
+#define ALGORITHM_LEFT_SYMMETRIC 2
+#define ALGORITHM_RIGHT_SYMMETRIC 3
+
+#endif
diff --git a/pfinet/linux-src/include/linux/random.h b/pfinet/linux-src/include/linux/random.h
new file mode 100644
index 00000000..58c93b9b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/random.h
@@ -0,0 +1,73 @@
+/*
+ * include/linux/random.h
+ *
+ * Include file for the random number generator.
+ */
+
+#ifndef _LINUX_RANDOM_H
+#define _LINUX_RANDOM_H
+
+#include <linux/ioctl.h>
+
+/* ioctl()'s for the random number generator */
+
+/* Get the entropy count. */
+#define RNDGETENTCNT _IOR( 'R', 0x00, int )
+
+/* Add to (or subtract from) the entropy count. (Superuser only.) */
+#define RNDADDTOENTCNT _IOW( 'R', 0x01, int )
+
+/* Get the contents of the entropy pool. (Superuser only.) */
+#define RNDGETPOOL _IOR( 'R', 0x02, int [2] )
+
+/*
+ * Write bytes into the entropy pool and add to the entropy count.
+ * (Superuser only.)
+ */
+#define RNDADDENTROPY _IOW( 'R', 0x03, int [2] )
+
+/* Clear entropy count to 0. (Superuser only.) */
+#define RNDZAPENTCNT _IO( 'R', 0x04 )
+
+/* Clear the entropy pool and associated counters. (Superuser only.) */
+#define RNDCLEARPOOL _IO( 'R', 0x06 )
+
+struct rand_pool_info {
+ int entropy_count;
+ int buf_size;
+ __u32 buf[0];
+};
+
+/* Exported functions */
+
+#ifdef __KERNEL__
+
+extern void rand_initialize(void);
+extern void rand_initialize_irq(int irq);
+extern void rand_initialize_blkdev(int irq, int mode);
+
+extern void add_keyboard_randomness(unsigned char scancode);
+extern void add_mouse_randomness(__u32 mouse_data);
+extern void add_interrupt_randomness(int irq);
+extern void add_blkdev_randomness(int major);
+
+extern void get_random_bytes(void *buf, int nbytes);
+
+extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
+ __u16 sport, __u16 dport);
+extern __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr,
+ __u16 sport, __u16 dport,
+ __u32 sseq, __u32 count,
+ __u32 data);
+extern __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr,
+ __u32 daddr, __u16 sport,
+ __u16 dport, __u32 sseq,
+ __u32 count, __u32 maxdiff);
+
+#ifndef MODULE
+extern struct file_operations random_fops, urandom_fops;
+#endif
+
+#endif /* __KERNEL___ */
+
+#endif /* _LINUX_RANDOM_H */
diff --git a/pfinet/linux-src/include/linux/reboot.h b/pfinet/linux-src/include/linux/reboot.h
new file mode 100644
index 00000000..463350f5
--- /dev/null
+++ b/pfinet/linux-src/include/linux/reboot.h
@@ -0,0 +1,52 @@
+#ifndef _LINUX_REBOOT_H
+#define _LINUX_REBOOT_H
+
+/*
+ * Magic values required to use _reboot() system call.
+ */
+
+#define LINUX_REBOOT_MAGIC1 0xfee1dead
+#define LINUX_REBOOT_MAGIC2 672274793
+#define LINUX_REBOOT_MAGIC2A 85072278
+#define LINUX_REBOOT_MAGIC2B 369367448
+
+
+/*
+ * Commands accepted by the _reboot() system call.
+ *
+ * RESTART Restart system using default command and mode.
+ * HALT Stop OS and give system control to ROM monitor, if any.
+ * CAD_ON Ctrl-Alt-Del sequence causes RESTART command.
+ * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task.
+ * POWER_OFF Stop OS and remove all power from system, if possible.
+ * RESTART2 Restart system using given command string.
+ */
+
+#define LINUX_REBOOT_CMD_RESTART 0x01234567
+#define LINUX_REBOOT_CMD_HALT 0xCDEF0123
+#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF
+#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
+#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC
+#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
+
+
+#ifdef __KERNEL__
+
+#include <linux/notifier.h>
+
+extern struct notifier_block *reboot_notifier_list;
+extern int register_reboot_notifier(struct notifier_block *);
+extern int unregister_reboot_notifier(struct notifier_block *);
+
+
+/*
+ * Architecture-specific implementations of sys_reboot commands.
+ */
+
+extern void machine_restart(char *cmd);
+extern void machine_halt(void);
+extern void machine_power_off(void);
+
+#endif
+
+#endif /* _LINUX_REBOOT_H */
diff --git a/pfinet/linux-src/include/linux/resource.h b/pfinet/linux-src/include/linux/resource.h
new file mode 100644
index 00000000..f3bffbd7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/resource.h
@@ -0,0 +1,60 @@
+#ifndef _LINUX_RESOURCE_H
+#define _LINUX_RESOURCE_H
+
+#include <linux/time.h>
+
+/*
+ * Resource control/accounting header file for linux
+ */
+
+/*
+ * Definition of struct rusage taken from BSD 4.3 Reno
+ *
+ * We don't support all of these yet, but we might as well have them....
+ * Otherwise, each time we add new items, programs which depend on this
+ * structure will lose. This reduces the chances of that happening.
+ */
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN (-1)
+#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */
+
+struct rusage {
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
+ long ru_maxrss; /* maximum resident set size */
+ long ru_ixrss; /* integral shared memory size */
+ long ru_idrss; /* integral unshared data size */
+ long ru_isrss; /* integral unshared stack size */
+ long ru_minflt; /* page reclaims */
+ long ru_majflt; /* page faults */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary " */
+};
+
+#define RLIM_INFINITY ((long)(~0UL>>1))
+
+struct rlimit {
+ long rlim_cur;
+ long rlim_max;
+};
+
+#define PRIO_MIN (-20)
+#define PRIO_MAX 20
+
+#define PRIO_PROCESS 0
+#define PRIO_PGRP 1
+#define PRIO_USER 2
+
+/*
+ * Due to binary compatibility, the actual resource numbers
+ * may be different for different linux versions..
+ */
+#include <asm/resource.h>
+
+#endif
diff --git a/pfinet/linux-src/include/linux/rocket.h b/pfinet/linux-src/include/linux/rocket.h
new file mode 100644
index 00000000..2019d4d3
--- /dev/null
+++ b/pfinet/linux-src/include/linux/rocket.h
@@ -0,0 +1,55 @@
+/*
+ * This file contains the exported interface of the rocket driver to
+ * its configuration program.
+ */
+
+struct rocket_config {
+ int line;
+ int flags;
+ int closing_wait;
+ int close_delay;
+ int port;
+ int reserved[32];
+};
+
+struct rocket_ports {
+ int tty_major;
+ int callout_major;
+ int port_bitmap[4];
+ int reserved[32];
+};
+
+/*
+ * Rocketport flags
+ */
+#define ROCKET_CALLOUT_NOHUP 0x00000001
+#define ROCKET_FORCE_CD 0x00000002
+#define ROCKET_HUP_NOTIFY 0x00000004
+#define ROCKET_SPLIT_TERMIOS 0x00000008
+#define ROCKET_SPD_MASK 0x00000070
+#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */
+#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps*/
+#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps*/
+#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps*/
+#define ROCKET_SAK 0x00000080
+#define ROCKET_SESSION_LOCKOUT 0x00000100
+#define ROCKET_PGRP_LOCKOUT 0x00000200
+
+#define ROCKET_FLAGS 0x000003FF
+
+#define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/*
+ * For closing_wait and closing_wait2
+ */
+#define ROCKET_CLOSING_WAIT_NONE 65535
+#define ROCKET_CLOSING_WAIT_INF 0
+
+/*
+ * Rocketport ioctls -- "RP"
+ */
+#define RCKP_GET_STRUCT 0x00525001
+#define RCKP_GET_CONFIG 0x00525002
+#define RCKP_SET_CONFIG 0x00525003
+#define RCKP_GET_PORTS 0x00525004
diff --git a/pfinet/linux-src/include/linux/romfs_fs.h b/pfinet/linux-src/include/linux/romfs_fs.h
new file mode 100644
index 00000000..844e22f9
--- /dev/null
+++ b/pfinet/linux-src/include/linux/romfs_fs.h
@@ -0,0 +1,62 @@
+#ifndef __LINUX_ROMFS_FS_H
+#define __LINUX_ROMFS_FS_H
+
+/* The basic structures of the romfs filesystem */
+
+#define ROMBSIZE BLOCK_SIZE
+#define ROMBSBITS BLOCK_SIZE_BITS
+#define ROMBMASK (ROMBSIZE-1)
+#define ROMFS_MAGIC 0x7275
+
+#define ROMFS_MAXFN 128
+
+#define __mkw(h,l) (((h)&0x00ff)<< 8|((l)&0x00ff))
+#define __mkl(h,l) (((h)&0xffff)<<16|((l)&0xffff))
+#define __mk4(a,b,c,d) htonl(__mkl(__mkw(a,b),__mkw(c,d)))
+#define ROMSB_WORD0 __mk4('-','r','o','m')
+#define ROMSB_WORD1 __mk4('1','f','s','-')
+
+/* On-disk "super block" */
+
+struct romfs_super_block {
+ __u32 word0;
+ __u32 word1;
+ __u32 size;
+ __u32 checksum;
+ char name[0]; /* volume name */
+};
+
+/* On disk inode */
+
+struct romfs_inode {
+ __u32 next; /* low 4 bits see ROMFH_ */
+ __u32 spec;
+ __u32 size;
+ __u32 checksum;
+ char name[0];
+};
+
+#define ROMFH_TYPE 7
+#define ROMFH_HRD 0
+#define ROMFH_DIR 1
+#define ROMFH_REG 2
+#define ROMFH_SYM 3
+#define ROMFH_BLK 4
+#define ROMFH_CHR 5
+#define ROMFH_SCK 6
+#define ROMFH_FIF 7
+#define ROMFH_EXEC 8
+
+/* Alignment */
+
+#define ROMFH_SIZE 16
+#define ROMFH_PAD (ROMFH_SIZE-1)
+#define ROMFH_MASK (~ROMFH_PAD)
+
+#ifdef __KERNEL__
+
+/* Not much now */
+extern int init_romfs_fs(void);
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/pfinet/linux-src/include/linux/romfs_fs_i.h b/pfinet/linux-src/include/linux/romfs_fs_i.h
new file mode 100644
index 00000000..1ffe4b7d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/romfs_fs_i.h
@@ -0,0 +1,11 @@
+#ifndef __ROMFS_FS_I
+#define __ROMFS_FS_I
+
+/* inode in-kernel data */
+
+struct romfs_inode_info {
+ unsigned long i_metasize; /* size of non-data area */
+ unsigned long i_dataoffset; /* from the start of fs */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/romfs_fs_sb.h b/pfinet/linux-src/include/linux/romfs_fs_sb.h
new file mode 100644
index 00000000..02da2280
--- /dev/null
+++ b/pfinet/linux-src/include/linux/romfs_fs_sb.h
@@ -0,0 +1,10 @@
+#ifndef __ROMFS_FS_SB
+#define __ROMFS_FS_SB
+
+/* romfs superblock in-core data */
+
+struct romfs_sb_info {
+ unsigned long s_maxsize;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/rose.h b/pfinet/linux-src/include/linux/rose.h
new file mode 100644
index 00000000..c7b4b184
--- /dev/null
+++ b/pfinet/linux-src/include/linux/rose.h
@@ -0,0 +1,87 @@
+/*
+ * These are the public elements of the Linux kernel Rose implementation.
+ * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the
+ * definition of the ax25_address structure.
+ */
+
+#ifndef ROSE_KERNEL_H
+#define ROSE_KERNEL_H
+
+#define ROSE_MTU 251
+
+#define ROSE_MAX_DIGIS 6
+
+#define ROSE_DEFER 1
+#define ROSE_T1 2
+#define ROSE_T2 3
+#define ROSE_T3 4
+#define ROSE_IDLE 5
+#define ROSE_QBITINCL 6
+#define ROSE_HOLDBACK 7
+
+#define SIOCRSGCAUSE (SIOCPROTOPRIVATE+0)
+#define SIOCRSSCAUSE (SIOCPROTOPRIVATE+1)
+#define SIOCRSL2CALL (SIOCPROTOPRIVATE+2)
+#define SIOCRSSL2CALL (SIOCPROTOPRIVATE+2)
+#define SIOCRSACCEPT (SIOCPROTOPRIVATE+3)
+#define SIOCRSCLRRT (SIOCPROTOPRIVATE+4)
+#define SIOCRSGL2CALL (SIOCPROTOPRIVATE+5)
+#define SIOCRSGFACILITIES (SIOCPROTOPRIVATE+6)
+
+#define ROSE_DTE_ORIGINATED 0x00
+#define ROSE_NUMBER_BUSY 0x01
+#define ROSE_INVALID_FACILITY 0x03
+#define ROSE_NETWORK_CONGESTION 0x05
+#define ROSE_OUT_OF_ORDER 0x09
+#define ROSE_ACCESS_BARRED 0x0B
+#define ROSE_NOT_OBTAINABLE 0x0D
+#define ROSE_REMOTE_PROCEDURE 0x11
+#define ROSE_LOCAL_PROCEDURE 0x13
+#define ROSE_SHIP_ABSENT 0x39
+
+typedef struct {
+ char rose_addr[5];
+} rose_address;
+
+struct sockaddr_rose {
+ sa_family_t srose_family;
+ rose_address srose_addr;
+ ax25_address srose_call;
+ int srose_ndigis;
+ ax25_address srose_digi;
+};
+
+struct full_sockaddr_rose {
+ sa_family_t srose_family;
+ rose_address srose_addr;
+ ax25_address srose_call;
+ unsigned int srose_ndigis;
+ ax25_address srose_digis[ROSE_MAX_DIGIS];
+};
+
+struct rose_route_struct {
+ rose_address address;
+ unsigned short mask;
+ ax25_address neighbour;
+ char device[16];
+ unsigned char ndigis;
+ ax25_address digipeaters[AX25_MAX_DIGIS];
+};
+
+struct rose_cause_struct {
+ unsigned char cause;
+ unsigned char diagnostic;
+};
+
+struct rose_facilities_struct {
+ rose_address source_addr, dest_addr;
+ ax25_address source_call, dest_call;
+ unsigned char source_ndigis, dest_ndigis;
+ ax25_address source_digis[ROSE_MAX_DIGIS];
+ ax25_address dest_digis[ROSE_MAX_DIGIS];
+ unsigned int rand;
+ rose_address fail_addr;
+ ax25_address fail_call;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/route.h b/pfinet/linux-src/include/linux/route.h
new file mode 100644
index 00000000..e670dbac
--- /dev/null
+++ b/pfinet/linux-src/include/linux/route.h
@@ -0,0 +1,70 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the IP router interface.
+ *
+ * Version: @(#)route.h 1.0.3 05/27/93
+ *
+ * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ * for the purposes of compatibility only.
+ *
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * Changes:
+ * Mike McLagan : Routing by source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_ROUTE_H
+#define _LINUX_ROUTE_H
+
+#include <linux/if.h>
+
+
+/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */
+struct rtentry
+{
+ unsigned long rt_pad1;
+ struct sockaddr rt_dst; /* target address */
+ struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
+ struct sockaddr rt_genmask; /* target network mask (IP) */
+ unsigned short rt_flags;
+ short rt_pad2;
+ unsigned long rt_pad3;
+ void *rt_pad4;
+ short rt_metric; /* +1 for binary compatibility! */
+ char *rt_dev; /* forcing the device at add */
+ unsigned long rt_mtu; /* per route MTU/Window */
+#ifndef __KERNEL__
+#define rt_mss rt_mtu /* Compatibility :-( */
+#endif
+ unsigned long rt_window; /* Window clamping */
+ unsigned short rt_irtt; /* Initial RTT */
+};
+
+
+#define RTF_UP 0x0001 /* route usable */
+#define RTF_GATEWAY 0x0002 /* destination is a gateway */
+#define RTF_HOST 0x0004 /* host entry (net otherwise) */
+#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
+#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
+#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
+#define RTF_MTU 0x0040 /* specific MTU for this route */
+#define RTF_MSS RTF_MTU /* Compatibility :-( */
+#define RTF_WINDOW 0x0080 /* per route window clamping */
+#define RTF_IRTT 0x0100 /* Initial round trip time */
+#define RTF_REJECT 0x0200 /* Reject route */
+
+/*
+ * <linux/ipv6_route.h> uses RTF values >= 64k
+ */
+
+
+
+#endif /* _LINUX_ROUTE_H */
+
diff --git a/pfinet/linux-src/include/linux/rpcsock.h b/pfinet/linux-src/include/linux/rpcsock.h
new file mode 100644
index 00000000..80f1fc4c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/rpcsock.h
@@ -0,0 +1,121 @@
+/*
+ * rpcsock.h Declarations for the RPC call interface.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+
+#ifndef _LINUX_RPCSOCK_H
+#define _LINUX_RPCSOCK_H
+
+/*
+ * The rpcsock code maintains an estimate on the maximum number of out-
+ * standing RPC requests, using the congestion avoidance implemented in
+ * 44BSD. This is basically the Van Jacobson slow start algorithm: If a
+ * retransmit occurs, the congestion window is halved; otherwise, it is
+ * incremented by 1/cwnd when a reply is received and a full number of
+ * requests are outstanding.
+ *
+ * Upper procedures may check whether a request would block waiting for
+ * a free RPC slot by using the RPC_CONGESTED() macro.
+ *
+ * Note: on machines with low memory we should probably use a smaller
+ * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment
+ * reassembly will frequently run out of memory.
+ */
+#define RPC_MAXREQS 32
+#define RPC_CWNDSCALE 256
+#define RPC_MAXCWND (RPC_MAXREQS * RPC_CWNDSCALE)
+/* #define RPC_INITCWND (RPC_MAXCWND / 2) */
+#define RPC_INITCWND RPC_CWNDSCALE
+#define RPC_CONGESTED(rsock) ((rsock)->cong >= (rsock)->cwnd)
+
+/* RPC reply header size: xid, direction, status, accept_status (verifier
+ * size computed separately)
+ */
+#define RPC_HDRSIZE (4 * 4)
+
+/*
+ * This describes a timeout strategy
+ */
+struct rpc_timeout {
+ unsigned long to_initval,
+ to_maxval,
+ to_increment;
+ int to_retries;
+ char to_exponential;
+};
+
+/*
+ * This describes a complete RPC request
+ */
+struct rpc_ioreq {
+ struct rpc_wait * rq_slot;
+ struct sockaddr * rq_addr;
+ int rq_alen;
+ struct iovec rq_svec[UIO_FASTIOV];
+ unsigned int rq_snr;
+ unsigned long rq_slen;
+ struct iovec rq_rvec[UIO_FASTIOV];
+ unsigned int rq_rnr;
+ unsigned long rq_rlen;
+};
+
+/*
+ * This is the callback handler for async RPC.
+ */
+struct rpc_wait;
+typedef void (*rpc_callback_fn_t)(int, struct rpc_wait *, void *);
+
+/*
+ * Wait information. This struct defines all the state of an RPC
+ * request currently in flight.
+ */
+struct rpc_wait {
+ struct rpc_sock * w_sock;
+ struct rpc_wait * w_prev;
+ struct rpc_wait * w_next;
+ struct rpc_ioreq * w_req;
+ int w_result;
+ struct wait_queue * w_wait;
+ rpc_callback_fn_t w_handler;
+ void * w_cdata;
+ char w_queued;
+ char w_gotit;
+ __u32 w_xid;
+};
+
+struct rpc_sock {
+ struct file * file;
+ struct socket * sock;
+ struct sock * inet;
+ struct rpc_wait waiting[RPC_MAXREQS];
+ unsigned long cong;
+ unsigned long cwnd;
+ struct rpc_wait * pending;
+ struct rpc_wait * free;
+ struct wait_queue * backlog;
+ struct wait_queue * shutwait;
+ int shutdown;
+};
+
+#ifdef __KERNEL__
+
+/* rpc_call: Call synchronously */
+int rpc_call(struct rpc_sock *, struct rpc_ioreq *,
+ struct rpc_timeout *);
+/* These implement asynch calls for nfsiod: Process calls rpc_reserve and
+ * rpc_transmits, then passes the request to nfsiod, which collects the
+ * results via rpc_doio
+ */
+int rpc_reserve(struct rpc_sock *, struct rpc_ioreq *, int);
+void rpc_release(struct rpc_sock *, struct rpc_ioreq *);
+int rpc_transmit(struct rpc_sock *, struct rpc_ioreq *);
+int rpc_doio(struct rpc_sock *, struct rpc_ioreq *,
+ struct rpc_timeout *, int);
+struct rpc_sock * rpc_makesock(struct file *);
+int rpc_closesock(struct rpc_sock *);
+
+#endif /* __KERNEL__*/
+
+#endif /* _LINUX_RPCSOCK_H */
diff --git a/pfinet/linux-src/include/linux/rtnetlink.h b/pfinet/linux-src/include/linux/rtnetlink.h
new file mode 100644
index 00000000..548a9b14
--- /dev/null
+++ b/pfinet/linux-src/include/linux/rtnetlink.h
@@ -0,0 +1,673 @@
+#ifndef __LINUX_RTNETLINK_H
+#define __LINUX_RTNETLINK_H
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#endif
+#include <linux/netlink.h>
+
+#define RTNL_DEBUG 1
+
+
+/****
+ * Routing/neighbour discovery messages.
+ ****/
+
+/* Types of messages */
+
+#define RTM_BASE 0x10
+
+#define RTM_NEWLINK (RTM_BASE+0)
+#define RTM_DELLINK (RTM_BASE+1)
+#define RTM_GETLINK (RTM_BASE+2)
+
+#define RTM_NEWADDR (RTM_BASE+4)
+#define RTM_DELADDR (RTM_BASE+5)
+#define RTM_GETADDR (RTM_BASE+6)
+
+#define RTM_NEWROUTE (RTM_BASE+8)
+#define RTM_DELROUTE (RTM_BASE+9)
+#define RTM_GETROUTE (RTM_BASE+10)
+
+#define RTM_NEWNEIGH (RTM_BASE+12)
+#define RTM_DELNEIGH (RTM_BASE+13)
+#define RTM_GETNEIGH (RTM_BASE+14)
+
+#define RTM_NEWRULE (RTM_BASE+16)
+#define RTM_DELRULE (RTM_BASE+17)
+#define RTM_GETRULE (RTM_BASE+18)
+
+#define RTM_NEWQDISC (RTM_BASE+20)
+#define RTM_DELQDISC (RTM_BASE+21)
+#define RTM_GETQDISC (RTM_BASE+22)
+
+#define RTM_NEWTCLASS (RTM_BASE+24)
+#define RTM_DELTCLASS (RTM_BASE+25)
+#define RTM_GETTCLASS (RTM_BASE+26)
+
+#define RTM_NEWTFILTER (RTM_BASE+28)
+#define RTM_DELTFILTER (RTM_BASE+29)
+#define RTM_GETTFILTER (RTM_BASE+30)
+
+#define RTM_MAX (RTM_BASE+31)
+
+/*
+ Generic structure for encapsulation optional route information.
+ It is reminiscent of sockaddr, but with sa_family replaced
+ with attribute type.
+ */
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+/* Macros to handle rtattributes */
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
+#define RTA_OK(rta,len) ((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+ (rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+ (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
+#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
+
+
+
+
+/******************************************************************************
+ * Definitions used in routing table administation.
+ ****/
+
+struct rtmsg
+{
+ unsigned char rtm_family;
+ unsigned char rtm_dst_len;
+ unsigned char rtm_src_len;
+ unsigned char rtm_tos;
+
+ unsigned char rtm_table; /* Routing table id */
+ unsigned char rtm_protocol; /* Routing protocol; see below */
+ unsigned char rtm_scope; /* See below */
+ unsigned char rtm_type; /* See below */
+
+ unsigned rtm_flags;
+};
+
+/* rtm_type */
+
+enum
+{
+ RTN_UNSPEC,
+ RTN_UNICAST, /* Gateway or direct route */
+ RTN_LOCAL, /* Accept locally */
+ RTN_BROADCAST, /* Accept locally as broadcast,
+ send as broadcast */
+ RTN_ANYCAST, /* Accept locally as broadcast,
+ but send as unicast */
+ RTN_MULTICAST, /* Multicast route */
+ RTN_BLACKHOLE, /* Drop */
+ RTN_UNREACHABLE, /* Destination is unreachable */
+ RTN_PROHIBIT, /* Administratively prohibited */
+ RTN_THROW, /* Not in this table */
+ RTN_NAT, /* Translate this address */
+ RTN_XRESOLVE, /* Use external resolver */
+};
+
+#define RTN_MAX RTN_XRESOLVE
+
+
+/* rtm_protocol */
+
+#define RTPROT_UNSPEC 0
+#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects;
+ not used by current IPv4 */
+#define RTPROT_KERNEL 2 /* Route installed by kernel */
+#define RTPROT_BOOT 3 /* Route installed during boot */
+#define RTPROT_STATIC 4 /* Route installed by administrator */
+
+/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
+ they just passed from user and back as is.
+ It will be used by hypothetical multiple routing daemons.
+ Note that protocol values should be standardized in order to
+ avoid conflicts.
+ */
+
+#define RTPROT_GATED 8 /* Apparently, GateD */
+#define RTPROT_RA 9 /* RDISC/ND router advertisements */
+#define RTPROT_MRT 10 /* Merit MRT */
+#define RTPROT_ZEBRA 11 /* Zebra */
+#define RTPROT_BIRD 12 /* BIRD */
+
+/* rtm_scope
+
+ Really it is not scope, but sort of distance to the destination.
+ NOWHERE are reserved for not existing destinations, HOST is our
+ local addresses, LINK are destinations, located on directly attached
+ link and UNIVERSE is everywhere in the Universe.
+
+ Intermediate values are also possible f.e. interior routes
+ could be assigned a value between UNIVERSE and LINK.
+*/
+
+enum rt_scope_t
+{
+ RT_SCOPE_UNIVERSE=0,
+/* User defined values */
+ RT_SCOPE_SITE=200,
+ RT_SCOPE_LINK=253,
+ RT_SCOPE_HOST=254,
+ RT_SCOPE_NOWHERE=255
+};
+
+/* rtm_flags */
+
+#define RTM_F_NOTIFY 0x100 /* Notify user of route change */
+#define RTM_F_CLONED 0x200 /* This route is cloned */
+#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
+
+/* Reserved table identifiers */
+
+enum rt_class_t
+{
+ RT_TABLE_UNSPEC=0,
+/* User defined values */
+ RT_TABLE_DEFAULT=253,
+ RT_TABLE_MAIN=254,
+ RT_TABLE_LOCAL=255
+};
+#define RT_TABLE_MAX RT_TABLE_LOCAL
+
+
+
+/* Routing message attributes */
+
+enum rtattr_type_t
+{
+ RTA_UNSPEC,
+ RTA_DST,
+ RTA_SRC,
+ RTA_IIF,
+ RTA_OIF,
+ RTA_GATEWAY,
+ RTA_PRIORITY,
+ RTA_PREFSRC,
+ RTA_METRICS,
+ RTA_MULTIPATH,
+ RTA_PROTOINFO,
+ RTA_FLOW,
+ RTA_CACHEINFO
+};
+
+#define RTA_MAX RTA_CACHEINFO
+
+#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
+#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
+
+/* RTM_MULTIPATH --- array of struct rtnexthop.
+ *
+ * "struct rtnexthop" describres all necessary nexthop information,
+ * i.e. parameters of path to a destination via this nextop.
+ *
+ * At the moment it is impossible to set different prefsrc, mtu, window
+ * and rtt for different paths from multipath.
+ */
+
+struct rtnexthop
+{
+ unsigned short rtnh_len;
+ unsigned char rtnh_flags;
+ unsigned char rtnh_hops;
+ int rtnh_ifindex;
+};
+
+/* rtnh_flags */
+
+#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
+#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
+#define RTNH_F_ONLINK 4 /* Gateway is forced on link */
+
+/* Macros to handle hexthops */
+
+#define RTNH_ALIGNTO 4
+#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) )
+#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \
+ ((int)(rtnh)->rtnh_len) <= (len))
+#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len)))
+#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len))
+#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
+#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+
+/* RTM_CACHEINFO */
+
+struct rta_cacheinfo
+{
+ __u32 rta_clntref;
+ __u32 rta_lastuse;
+ __s32 rta_expires;
+ __u32 rta_error;
+ __u32 rta_used;
+};
+
+/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
+
+enum
+{
+ RTAX_UNSPEC,
+ RTAX_LOCK,
+ RTAX_MTU,
+ RTAX_WINDOW,
+ RTAX_RTT,
+ RTAX_HOPS,
+ RTAX_SSTHRESH,
+ RTAX_CWND,
+};
+
+#define RTAX_MAX RTAX_CWND
+
+
+
+/*********************************************************
+ * Interface address.
+ ****/
+
+struct ifaddrmsg
+{
+ unsigned char ifa_family;
+ unsigned char ifa_prefixlen; /* The prefix length */
+ unsigned char ifa_flags; /* Flags */
+ unsigned char ifa_scope; /* See above */
+ int ifa_index; /* Link index */
+};
+
+enum
+{
+ IFA_UNSPEC,
+ IFA_ADDRESS,
+ IFA_LOCAL,
+ IFA_LABEL,
+ IFA_BROADCAST,
+ IFA_ANYCAST,
+ IFA_CACHEINFO
+};
+
+#define IFA_MAX IFA_CACHEINFO
+
+/* ifa_flags */
+
+#define IFA_F_SECONDARY 0x01
+
+#define IFA_F_DEPRECATED 0x20
+#define IFA_F_TENTATIVE 0x40
+#define IFA_F_PERMANENT 0x80
+
+struct ifa_cacheinfo
+{
+ __s32 ifa_prefered;
+ __s32 ifa_valid;
+};
+
+
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+/*
+ Important comment:
+ IFA_ADDRESS is prefix address, rather than local interface address.
+ It makes no difference for normally configured broadcast interfaces,
+ but for point-to-point IFA_ADDRESS is DESTINATION address,
+ local address is supplied in IFA_LOCAL attribute.
+ */
+
+/**************************************************************
+ * Neighbour discovery.
+ ****/
+
+struct ndmsg
+{
+ unsigned char ndm_family;
+ unsigned char ndm_pad1;
+ unsigned short ndm_pad2;
+ int ndm_ifindex; /* Link index */
+ __u16 ndm_state;
+ __u8 ndm_flags;
+ __u8 ndm_type;
+};
+
+enum
+{
+ NDA_UNSPEC,
+ NDA_DST,
+ NDA_LLADDR,
+ NDA_CACHEINFO
+};
+
+#define NDA_MAX NDA_CACHEINFO
+
+#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
+
+/*
+ * Neighbor Cache Entry Flags
+ */
+
+#define NTF_PROXY 0x08 /* == ATF_PUBL */
+#define NTF_ROUTER 0x80
+
+/*
+ * Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE 0x02
+#define NUD_STALE 0x04
+#define NUD_DELAY 0x08
+#define NUD_PROBE 0x10
+#define NUD_FAILED 0x20
+
+/* Dummy states */
+#define NUD_NOARP 0x40
+#define NUD_PERMANENT 0x80
+#define NUD_NONE 0x00
+
+
+struct nda_cacheinfo
+{
+ __u32 ndm_confirmed;
+ __u32 ndm_used;
+ __u32 ndm_updated;
+ __u32 ndm_refcnt;
+};
+
+/****
+ * General form of address family dependent message.
+ ****/
+
+struct rtgenmsg
+{
+ unsigned char rtgen_family;
+};
+
+/*****************************************************************
+ * Link layer specific messages.
+ ****/
+
+/* struct ifinfomsg
+ * passes link level specific information, not dependent
+ * on network protocol.
+ */
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type; /* ARPHRD_* */
+ int ifi_index; /* Link index */
+ unsigned ifi_flags; /* IFF_* flags */
+ unsigned ifi_change; /* IFF_* change mask */
+};
+
+enum
+{
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS
+};
+
+
+#define IFLA_MAX IFLA_STATS
+
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
+/* ifi_flags.
+
+ IFF_* flags.
+
+ The only change is:
+ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+ more not changeable by user. They describe link media
+ characteristics and set by device driver.
+
+ Comments:
+ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+ - If neiher of these three flags are set;
+ the interface is NBMA.
+
+ - IFF_MULTICAST does not mean anything special:
+ multicasts can be used on all not-NBMA links.
+ IFF_MULTICAST means that this media uses special encapsulation
+ for multicast frames. Apparently, all IFF_POINTOPOINT and
+ IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* ifi_link.
+ For usual devices it is equal ifi_index.
+ If it is a "virtual interface" (f.e. tunnel), ifi_link
+ can point to real physical interface (f.e. for bandwidth calculations),
+ or maybe 0, what means, that real media is unknown (usual
+ for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/*****************************************************************
+ * Traffic control messages.
+ ****/
+
+struct tcmsg
+{
+ unsigned char tcm_family;
+ unsigned char tcm__pad1;
+ unsigned short tcm__pad2;
+ int tcm_ifindex;
+ __u32 tcm_handle;
+ __u32 tcm_parent;
+ __u32 tcm_info;
+};
+
+enum
+{
+ TCA_UNSPEC,
+ TCA_KIND,
+ TCA_OPTIONS,
+ TCA_STATS,
+ TCA_XSTATS,
+ TCA_RATE,
+};
+
+#define TCA_MAX TCA_RATE
+
+#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
+#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
+
+
+/* SUMMARY: maximal rtattr understood by kernel */
+
+#define RTATTR_MAX RTA_MAX
+
+/* RTnetlink multicast groups */
+
+#define RTMGRP_LINK 1
+#define RTMGRP_NOTIFY 2
+#define RTMGRP_NEIGH 4
+#define RTMGRP_TC 8
+
+#define RTMGRP_IPV4_IFADDR 0x10
+#define RTMGRP_IPV4_MROUTE 0x20
+#define RTMGRP_IPV4_ROUTE 0x40
+
+#define RTMGRP_IPV6_IFADDR 0x100
+#define RTMGRP_IPV6_MROUTE 0x200
+#define RTMGRP_IPV6_ROUTE 0x400
+
+/* End of information exported to user level */
+
+#ifdef __KERNEL__
+
+extern atomic_t rtnl_rlockct;
+extern struct wait_queue *rtnl_wait;
+
+extern __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
+{
+ int len = strlen(str) + 1;
+ return len > rta->rta_len || memcmp(RTA_DATA(rta), str, len);
+}
+
+extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len);
+
+#ifdef CONFIG_RTNETLINK
+extern struct sock *rtnl;
+
+struct rtnetlink_link
+{
+ int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr);
+ int (*dumpit)(struct sk_buff *, struct netlink_callback *cb);
+};
+
+extern struct rtnetlink_link * rtnetlink_links[NPROTO];
+extern int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb);
+extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo);
+
+extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data);
+
+#define RTA_PUT(skb, attrtype, attrlen, data) \
+({ if (skb_tailroom(skb) < (int)RTA_SPACE(attrlen)) goto rtattr_failure; \
+ __rta_fill(skb, attrtype, attrlen, data); })
+
+extern unsigned long rtnl_wlockct;
+
+/* NOTE: these locks are not interrupt safe, are not SMP safe,
+ * they are even not atomic. 8)8)8) ... and it is not a bug.
+ * Really, if these locks will be programmed correctly,
+ * all the addressing/routing machine would become SMP safe,
+ * but is absolutely useless at the moment, because all the kernel
+ * is not reenterable in any case. --ANK
+ *
+ * Well, atomic_* and set_bit provide the only thing here:
+ * gcc is confused not to overoptimize them, that's all.
+ * I remember as gcc splitted ++ operation, but cannot reproduce
+ * it with gcc-2.7.*. --ANK
+ *
+ * One more note: rwlock facility should be written and put
+ * to a kernel wide location: f.e. current implementation of semaphores
+ * (especially, for x86) looks like a wonder. It would be good
+ * to have something similar for rwlock. Recursive lock could be also
+ * useful thing. --ANK
+ */
+
+extern __inline__ int rtnl_shlock_nowait(void)
+{
+ atomic_inc(&rtnl_rlockct);
+ if (test_bit(0, &rtnl_wlockct)) {
+ atomic_dec(&rtnl_rlockct);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+extern __inline__ void rtnl_shlock(void)
+{
+ while (rtnl_shlock_nowait())
+ sleep_on(&rtnl_wait);
+}
+
+/* Check for possibility to PROMOTE shared lock to exclusive.
+ Shared lock must be already grabbed with rtnl_shlock*().
+ */
+
+extern __inline__ int rtnl_exlock_nowait(void)
+{
+ if (atomic_read(&rtnl_rlockct) > 1)
+ return -EAGAIN;
+ if (test_and_set_bit(0, &rtnl_wlockct))
+ return -EAGAIN;
+ return 0;
+}
+
+extern __inline__ void rtnl_exlock(void)
+{
+ while (rtnl_exlock_nowait())
+ sleep_on(&rtnl_wait);
+}
+
+#if 0
+extern __inline__ void rtnl_shunlock(void)
+{
+ atomic_dec(&rtnl_rlockct);
+ if (atomic_read(&rtnl_rlockct) <= 1) {
+ wake_up(&rtnl_wait);
+ if (rtnl && rtnl->receive_queue.qlen)
+ rtnl->data_ready(rtnl, 0);
+ }
+}
+#else
+
+/* The problem: inline requires to include <net/sock.h> and, hence,
+ almost all of net includes :-(
+ */
+
+#define rtnl_shunlock() ({ \
+ atomic_dec(&rtnl_rlockct); \
+ if (atomic_read(&rtnl_rlockct) <= 1) { \
+ wake_up(&rtnl_wait); \
+ if (rtnl && rtnl->receive_queue.qlen) \
+ rtnl->data_ready(rtnl, 0); \
+ } \
+})
+#endif
+
+/* Release exclusive lock. Note, that we do not wake up rtnetlink socket,
+ * it will be done later after releasing shared lock.
+ */
+
+extern __inline__ void rtnl_exunlock(void)
+{
+ clear_bit(0, &rtnl_wlockct);
+ wake_up(&rtnl_wait);
+}
+
+#else
+
+extern __inline__ void rtnl_shlock(void)
+{
+#ifndef _HURD_
+ while (atomic_read(&rtnl_rlockct))
+ sleep_on(&rtnl_wait);
+ atomic_inc(&rtnl_rlockct);
+#endif
+}
+
+extern __inline__ void rtnl_shunlock(void)
+{
+#ifndef _HURD_
+ if (atomic_dec_and_test(&rtnl_rlockct))
+ wake_up(&rtnl_wait);
+#endif
+}
+
+extern __inline__ void rtnl_exlock(void)
+{
+}
+
+extern __inline__ void rtnl_exunlock(void)
+{
+}
+
+#endif
+
+extern void rtnl_lock(void);
+extern void rtnl_unlock(void);
+extern void rtnetlink_init(void);
+
+#endif /* __KERNEL__ */
+
+
+#endif /* __LINUX_RTNETLINK_H */
diff --git a/pfinet/linux-src/include/linux/sc26198.h b/pfinet/linux-src/include/linux/sc26198.h
new file mode 100644
index 00000000..38685e07
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sc26198.h
@@ -0,0 +1,533 @@
+/*****************************************************************************/
+
+/*
+ * sc26198.h -- SC26198 UART hardware info.
+ *
+ * Copyright (C) 1995-1998 Stallion Technologies (support@stallion.oz.au).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*****************************************************************************/
+#ifndef _SC26198_H
+#define _SC26198_H
+/*****************************************************************************/
+
+/*
+ * Define the number of async ports per sc26198 uart device.
+ */
+#define SC26198_PORTS 8
+
+/*
+ * Baud rate timing clocks. All derived from a master 14.7456 MHz clock.
+ */
+#define SC26198_MASTERCLOCK 14745600L
+#define SC26198_DCLK (SC26198_MASTERCLOCK)
+#define SC26198_CCLK (SC26198_MASTERCLOCK / 2)
+#define SC26198_BCLK (SC26198_MASTERCLOCK / 4)
+
+/*
+ * Define internal FIFO sizes for the 26198 ports.
+ */
+#define SC26198_TXFIFOSIZE 16
+#define SC26198_RXFIFOSIZE 16
+
+/*****************************************************************************/
+
+/*
+ * Global register definitions. These registers are global to each 26198
+ * device, not specific ports on it.
+ */
+#define TSTR 0x0d
+#define GCCR 0x0f
+#define ICR 0x1b
+#define WDTRCR 0x1d
+#define IVR 0x1f
+#define BRGTRUA 0x84
+#define GPOSR 0x87
+#define GPOC 0x8b
+#define UCIR 0x8c
+#define CIR 0x8c
+#define BRGTRUB 0x8d
+#define GRXFIFO 0x8e
+#define GTXFIFO 0x8e
+#define GCCR2 0x8f
+#define BRGTRLA 0x94
+#define GPOR 0x97
+#define GPOD 0x9b
+#define BRGTCR 0x9c
+#define GICR 0x9c
+#define BRGTRLB 0x9d
+#define GIBCR 0x9d
+#define GITR 0x9f
+
+/*
+ * Per port channel registers. These are the register offsets within
+ * the port address space, so need to have the port address (0 to 7)
+ * inserted in bit positions 4:6.
+ */
+#define MR0 0x00
+#define MR1 0x01
+#define IOPCR 0x02
+#define BCRBRK 0x03
+#define BCRCOS 0x04
+#define BCRX 0x06
+#define BCRA 0x07
+#define XONCR 0x08
+#define XOFFCR 0x09
+#define ARCR 0x0a
+#define RXCSR 0x0c
+#define TXCSR 0x0e
+#define MR2 0x80
+#define SR 0x81
+#define SCCR 0x81
+#define ISR 0x82
+#define IMR 0x82
+#define TXFIFO 0x83
+#define RXFIFO 0x83
+#define IPR 0x84
+#define IOPIOR 0x85
+#define XISR 0x86
+
+/*
+ * For any given port calculate the address to use to access a specified
+ * register. This is only used for unusual access, mostly this is done
+ * through the assembler access routines.
+ */
+#define SC26198_PORTREG(port,reg) ((((port) & 0x07) << 4) | (reg))
+
+/*****************************************************************************/
+
+/*
+ * Global configuration control register bit definitions.
+ */
+#define GCCR_NOACK 0x00
+#define GCCR_IVRACK 0x02
+#define GCCR_IVRCHANACK 0x04
+#define GCCR_IVRTYPCHANACK 0x06
+#define GCCR_ASYNCCYCLE 0x00
+#define GCCR_SYNCCYCLE 0x40
+
+/*****************************************************************************/
+
+/*
+ * Mode register 0 bit definitions.
+ */
+#define MR0_ADDRNONE 0x00
+#define MR0_AUTOWAKE 0x01
+#define MR0_AUTODOZE 0x02
+#define MR0_AUTOWAKEDOZE 0x03
+#define MR0_SWFNONE 0x00
+#define MR0_SWFTX 0x04
+#define MR0_SWFRX 0x08
+#define MR0_SWFRXTX 0x0c
+#define MR0_TXMASK 0x30
+#define MR0_TXEMPTY 0x00
+#define MR0_TXHIGH 0x10
+#define MR0_TXHALF 0x20
+#define MR0_TXRDY 0x00
+#define MR0_ADDRNT 0x00
+#define MR0_ADDRT 0x40
+#define MR0_SWFNT 0x00
+#define MR0_SWFT 0x80
+
+/*
+ * Mode register 1 bit definitions.
+ */
+#define MR1_CS5 0x00
+#define MR1_CS6 0x01
+#define MR1_CS7 0x02
+#define MR1_CS8 0x03
+#define MR1_PAREVEN 0x00
+#define MR1_PARODD 0x04
+#define MR1_PARENB 0x00
+#define MR1_PARFORCE 0x08
+#define MR1_PARNONE 0x10
+#define MR1_PARSPECIAL 0x18
+#define MR1_ERRCHAR 0x00
+#define MR1_ERRBLOCK 0x20
+#define MR1_ISRUNMASKED 0x00
+#define MR1_ISRMASKED 0x40
+#define MR1_AUTORTS 0x80
+
+/*
+ * Mode register 2 bit definitions.
+ */
+#define MR2_STOP1 0x00
+#define MR2_STOP15 0x01
+#define MR2_STOP2 0x02
+#define MR2_STOP916 0x03
+#define MR2_RXFIFORDY 0x00
+#define MR2_RXFIFOHALF 0x04
+#define MR2_RXFIFOHIGH 0x08
+#define MR2_RXFIFOFULL 0x0c
+#define MR2_AUTOCTS 0x10
+#define MR2_TXRTS 0x20
+#define MR2_MODENORM 0x00
+#define MR2_MODEAUTOECHO 0x40
+#define MR2_MODELOOP 0x80
+#define MR2_MODEREMECHO 0xc0
+
+/*****************************************************************************/
+
+/*
+ * Baud Rate Generator (BRG) selector values.
+ */
+#define BRG_50 0x00
+#define BRG_75 0x01
+#define BRG_150 0x02
+#define BRG_200 0x03
+#define BRG_300 0x04
+#define BRG_450 0x05
+#define BRG_600 0x06
+#define BRG_900 0x07
+#define BRG_1200 0x08
+#define BRG_1800 0x09
+#define BRG_2400 0x0a
+#define BRG_3600 0x0b
+#define BRG_4800 0x0c
+#define BRG_7200 0x0d
+#define BRG_9600 0x0e
+#define BRG_14400 0x0f
+#define BRG_19200 0x10
+#define BRG_28200 0x11
+#define BRG_38400 0x12
+#define BRG_57600 0x13
+#define BRG_115200 0x14
+#define BRG_230400 0x15
+#define BRG_GIN0 0x16
+#define BRG_GIN1 0x17
+#define BRG_CT0 0x18
+#define BRG_CT1 0x19
+#define BRG_RX2TX316 0x1b
+#define BRG_RX2TX31 0x1c
+
+#define SC26198_MAXBAUD 921600
+
+/*****************************************************************************/
+
+/*
+ * Command register command definitions.
+ */
+#define CR_NULL 0x04
+#define CR_ADDRNORMAL 0x0c
+#define CR_RXRESET 0x14
+#define CR_TXRESET 0x1c
+#define CR_CLEARRXERR 0x24
+#define CR_BREAKRESET 0x2c
+#define CR_TXSTARTBREAK 0x34
+#define CR_TXSTOPBREAK 0x3c
+#define CR_RTSON 0x44
+#define CR_RTSOFF 0x4c
+#define CR_ADDRINIT 0x5c
+#define CR_RXERRBLOCK 0x6c
+#define CR_TXSENDXON 0x84
+#define CR_TXSENDXOFF 0x8c
+#define CR_GANGXONSET 0x94
+#define CR_GANGXOFFSET 0x9c
+#define CR_GANGXONINIT 0xa4
+#define CR_GANGXOFFINIT 0xac
+#define CR_HOSTXON 0xb4
+#define CR_HOSTXOFF 0xbc
+#define CR_CANCELXOFF 0xc4
+#define CR_ADDRRESET 0xdc
+#define CR_RESETALLPORTS 0xf4
+#define CR_RESETALL 0xfc
+
+#define CR_RXENABLE 0x01
+#define CR_TXENABLE 0x02
+
+/*****************************************************************************/
+
+/*
+ * Channel status register.
+ */
+#define SR_RXRDY 0x01
+#define SR_RXFULL 0x02
+#define SR_TXRDY 0x04
+#define SR_TXEMPTY 0x08
+#define SR_RXOVERRUN 0x10
+#define SR_RXPARITY 0x20
+#define SR_RXFRAMING 0x40
+#define SR_RXBREAK 0x80
+
+#define SR_RXERRS (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN)
+
+/*****************************************************************************/
+
+/*
+ * Interrupt status register and interrupt mask register bit definitions.
+ */
+#define IR_TXRDY 0x01
+#define IR_RXRDY 0x02
+#define IR_RXBREAK 0x04
+#define IR_XONXOFF 0x10
+#define IR_ADDRRECOG 0x20
+#define IR_RXWATCHDOG 0x40
+#define IR_IOPORT 0x80
+
+/*****************************************************************************/
+
+/*
+ * Interrupt vector register field definitions.
+ */
+#define IVR_CHANMASK 0x07
+#define IVR_TYPEMASK 0x18
+#define IVR_CONSTMASK 0xc0
+
+#define IVR_RXDATA 0x10
+#define IVR_RXBADDATA 0x18
+#define IVR_TXDATA 0x08
+#define IVR_OTHER 0x00
+
+/*****************************************************************************/
+
+/*
+ * BRG timer control register bit definitions.
+ */
+#define BRGCTCR_DISABCLK0 0x00
+#define BRGCTCR_ENABCLK0 0x08
+#define BRGCTCR_DISABCLK1 0x00
+#define BRGCTCR_ENABCLK1 0x80
+
+#define BRGCTCR_0SCLK16 0x00
+#define BRGCTCR_0SCLK32 0x01
+#define BRGCTCR_0SCLK64 0x02
+#define BRGCTCR_0SCLK128 0x03
+#define BRGCTCR_0X1 0x04
+#define BRGCTCR_0X12 0x05
+#define BRGCTCR_0IO1A 0x06
+#define BRGCTCR_0GIN0 0x07
+
+#define BRGCTCR_1SCLK16 0x00
+#define BRGCTCR_1SCLK32 0x10
+#define BRGCTCR_1SCLK64 0x20
+#define BRGCTCR_1SCLK128 0x30
+#define BRGCTCR_1X1 0x40
+#define BRGCTCR_1X12 0x50
+#define BRGCTCR_1IO1B 0x60
+#define BRGCTCR_1GIN1 0x70
+
+/*****************************************************************************/
+
+/*
+ * Watch dog timer enable register.
+ */
+#define WDTRCR_ENABALL 0xff
+
+/*****************************************************************************/
+
+/*
+ * XON/XOFF interrupt status register.
+ */
+#define XISR_TXCHARMASK 0x03
+#define XISR_TXCHARNORMAL 0x00
+#define XISR_TXWAIT 0x01
+#define XISR_TXXOFFPEND 0x02
+#define XISR_TXXONPEND 0x03
+
+#define XISR_TXFLOWMASK 0x0c
+#define XISR_TXNORMAL 0x00
+#define XISR_TXSTOPPEND 0x04
+#define XISR_TXSTARTED 0x08
+#define XISR_TXSTOPPED 0x0c
+
+#define XISR_RXFLOWMASK 0x30
+#define XISR_RXFLOWNONE 0x00
+#define XISR_RXXONSENT 0x10
+#define XISR_RXXOFFSENT 0x20
+
+#define XISR_RXXONGOT 0x40
+#define XISR_RXXOFFGOT 0x80
+
+/*****************************************************************************/
+
+/*
+ * Current interrupt register.
+ */
+#define CIR_TYPEMASK 0xc0
+#define CIR_TYPEOTHER 0x00
+#define CIR_TYPETX 0x40
+#define CIR_TYPERXGOOD 0x80
+#define CIR_TYPERXBAD 0xc0
+
+#define CIR_RXDATA 0x80
+#define CIR_RXBADDATA 0x40
+#define CIR_TXDATA 0x40
+
+#define CIR_CHANMASK 0x07
+#define CIR_CNTMASK 0x38
+
+#define CIR_SUBTYPEMASK 0x38
+#define CIR_SUBNONE 0x00
+#define CIR_SUBCOS 0x08
+#define CIR_SUBADDR 0x10
+#define CIR_SUBXONXOFF 0x18
+#define CIR_SUBBREAK 0x28
+
+/*****************************************************************************/
+
+/*
+ * Global interrupting channel register.
+ */
+#define GICR_CHANMASK 0x07
+
+/*****************************************************************************/
+
+/*
+ * Global interrupting byte count register.
+ */
+#define GICR_COUNTMASK 0x0f
+
+/*****************************************************************************/
+
+/*
+ * Global interrupting type register.
+ */
+#define GITR_RXMASK 0xc0
+#define GITR_RXNONE 0x00
+#define GITR_RXBADDATA 0x80
+#define GITR_RXGOODDATA 0xc0
+#define GITR_TXDATA 0x20
+
+#define GITR_SUBTYPEMASK 0x07
+#define GITR_SUBNONE 0x00
+#define GITR_SUBCOS 0x01
+#define GITR_SUBADDR 0x02
+#define GITR_SUBXONXOFF 0x03
+#define GITR_SUBBREAK 0x05
+
+/*****************************************************************************/
+
+/*
+ * Input port change register.
+ */
+#define IPR_CTS 0x01
+#define IPR_DTR 0x02
+#define IPR_RTS 0x04
+#define IPR_DCD 0x08
+#define IPR_CTSCHANGE 0x10
+#define IPR_DTRCHANGE 0x20
+#define IPR_RTSCHANGE 0x40
+#define IPR_DCDCHANGE 0x80
+
+#define IPR_CHANGEMASK 0xf0
+
+/*****************************************************************************/
+
+/*
+ * IO port interrupt and output register.
+ */
+#define IOPR_CTS 0x01
+#define IOPR_DTR 0x02
+#define IOPR_RTS 0x04
+#define IOPR_DCD 0x08
+#define IOPR_CTSCOS 0x10
+#define IOPR_DTRCOS 0x20
+#define IOPR_RTSCOS 0x40
+#define IOPR_DCDCOS 0x80
+
+/*****************************************************************************/
+
+/*
+ * IO port configuration register.
+ */
+#define IOPCR_SETCTS 0x00
+#define IOPCR_SETDTR 0x04
+#define IOPCR_SETRTS 0x10
+#define IOPCR_SETDCD 0x00
+
+#define IOPCR_SETSIGS (IOPCR_SETRTS | IOPCR_SETRTS | IOPCR_SETDTR | IOPCR_SETDCD)
+
+/*****************************************************************************/
+
+/*
+ * General purpose output select register.
+ */
+#define GPORS_TXC1XA 0x08
+#define GPORS_TXC16XA 0x09
+#define GPORS_RXC16XA 0x0a
+#define GPORS_TXC16XB 0x0b
+#define GPORS_GPOR3 0x0c
+#define GPORS_GPOR2 0x0d
+#define GPORS_GPOR1 0x0e
+#define GPORS_GPOR0 0x0f
+
+/*****************************************************************************/
+
+/*
+ * General purpose output register.
+ */
+#define GPOR_0 0x01
+#define GPOR_1 0x02
+#define GPOR_2 0x04
+#define GPOR_3 0x08
+
+/*****************************************************************************/
+
+/*
+ * General purpose output clock register.
+ */
+#define GPORC_0NONE 0x00
+#define GPORC_0GIN0 0x01
+#define GPORC_0GIN1 0x02
+#define GPORC_0IO3A 0x02
+
+#define GPORC_1NONE 0x00
+#define GPORC_1GIN0 0x04
+#define GPORC_1GIN1 0x08
+#define GPORC_1IO3C 0x0c
+
+#define GPORC_2NONE 0x00
+#define GPORC_2GIN0 0x10
+#define GPORC_2GIN1 0x20
+#define GPORC_2IO3E 0x20
+
+#define GPORC_3NONE 0x00
+#define GPORC_3GIN0 0x40
+#define GPORC_3GIN1 0x80
+#define GPORC_3IO3G 0xc0
+
+/*****************************************************************************/
+
+/*
+ * General purpose output data register.
+ */
+#define GPOD_0MASK 0x03
+#define GPOD_0SET1 0x00
+#define GPOD_0SET0 0x01
+#define GPOD_0SETR0 0x02
+#define GPOD_0SETIO3B 0x03
+
+#define GPOD_1MASK 0x0c
+#define GPOD_1SET1 0x00
+#define GPOD_1SET0 0x04
+#define GPOD_1SETR0 0x08
+#define GPOD_1SETIO3D 0x0c
+
+#define GPOD_2MASK 0x30
+#define GPOD_2SET1 0x00
+#define GPOD_2SET0 0x10
+#define GPOD_2SETR0 0x20
+#define GPOD_2SETIO3F 0x30
+
+#define GPOD_3MASK 0xc0
+#define GPOD_3SET1 0x00
+#define GPOD_3SET0 0x40
+#define GPOD_3SETR0 0x80
+#define GPOD_3SETIO3H 0xc0
+
+/*****************************************************************************/
+#endif
diff --git a/pfinet/linux-src/include/linux/scc.h b/pfinet/linux-src/include/linux/scc.h
new file mode 100644
index 00000000..7ad72e10
--- /dev/null
+++ b/pfinet/linux-src/include/linux/scc.h
@@ -0,0 +1,258 @@
+/* $Id: scc.h,v 1.29 1997/04/02 14:56:45 jreuter Exp jreuter $ */
+
+#ifndef _SCC_H
+#define _SCC_H
+
+#include <linux/config.h>
+
+/* selection of hardware types */
+
+#define PA0HZP 0x00 /* hardware type for PA0HZP SCC card and compatible */
+#define EAGLE 0x01 /* hardware type for EAGLE card */
+#define PC100 0x02 /* hardware type for PC100 card */
+#define PRIMUS 0x04 /* hardware type for PRIMUS-PC (DG9BL) card */
+#define DRSI 0x08 /* hardware type for DRSI PC*Packet card */
+#define BAYCOM 0x10 /* hardware type for BayCom (U)SCC */
+
+/* DEV ioctl() commands */
+
+enum SCC_ioctl_cmds {
+ SIOCSCCRESERVED = SIOCDEVPRIVATE,
+ SIOCSCCCFG,
+ SIOCSCCINI,
+ SIOCSCCCHANINI,
+ SIOCSCCSMEM,
+ SIOCSCCGKISS,
+ SIOCSCCSKISS,
+ SIOCSCCGSTAT,
+ SIOCSCCCAL
+};
+
+/* magic number */
+
+#define SCC_MAGIC 0x8530 /* ;-) */
+
+/* Device parameter control (from WAMPES) */
+
+enum L1_params {
+ PARAM_DATA,
+ PARAM_TXDELAY,
+ PARAM_PERSIST,
+ PARAM_SLOTTIME,
+ PARAM_TXTAIL,
+ PARAM_FULLDUP,
+ PARAM_SOFTDCD, /* was: PARAM_HW */
+ PARAM_MUTE, /* ??? */
+ PARAM_DTR,
+ PARAM_RTS,
+ PARAM_SPEED,
+ PARAM_ENDDELAY, /* ??? */
+ PARAM_GROUP,
+ PARAM_IDLE,
+ PARAM_MIN,
+ PARAM_MAXKEY,
+ PARAM_WAIT,
+ PARAM_MAXDEFER,
+ PARAM_TX,
+ PARAM_HWEVENT = 31,
+ PARAM_RETURN = 255 /* reset kiss mode */
+};
+
+/* fulldup parameter */
+
+enum FULLDUP_modes {
+ KISS_DUPLEX_HALF, /* normal CSMA operation */
+ KISS_DUPLEX_FULL, /* fullduplex, key down trx after transmission */
+ KISS_DUPLEX_LINK, /* fullduplex, key down trx after 'idletime' sec */
+ KISS_DUPLEX_OPTIMA /* fullduplex, let the protocol layer control the hw */
+};
+
+/* misc. parameters */
+
+#define TIMER_OFF 65535U /* to switch off timers */
+#define NO_SUCH_PARAM 65534U /* param not implemented */
+
+/* HWEVENT parameter */
+
+enum HWEVENT_opts {
+ HWEV_DCD_ON,
+ HWEV_DCD_OFF,
+ HWEV_ALL_SENT
+};
+
+/* channel grouping */
+
+#define RXGROUP 0100 /* if set, only tx when all channels clear */
+#define TXGROUP 0200 /* if set, don't transmit simultaneously */
+
+/* Tx/Rx clock sources */
+
+enum CLOCK_sources {
+ CLK_DPLL, /* normal halfduplex operation */
+ CLK_EXTERNAL, /* external clocking (G3RUH/DF9IC modems) */
+ CLK_DIVIDER, /* Rx = DPLL, Tx = divider (fullduplex with */
+ /* modems without clock regeneration */
+ CLK_BRG /* experimental fullduplex mode with DPLL/BRG for */
+ /* MODEMs without clock recovery */
+};
+
+/* Tx state */
+
+enum TX_state {
+ TXS_IDLE, /* Transmitter off, no data pending */
+ TXS_BUSY, /* waiting for permission to send / tailtime */
+ TXS_ACTIVE, /* Transmitter on, sending data */
+ TXS_NEWFRAME, /* reset CRC and send (next) frame */
+ TXS_IDLE2, /* Transmitter on, no data pending */
+ TXS_WAIT, /* Waiting for Mintime to expire */
+ TXS_TIMEOUT /* We had a transmission timeout */
+};
+
+typedef unsigned long io_port; /* type definition for an 'io port address' */
+
+/* SCC statistical information */
+
+struct scc_stat {
+ long rxints; /* Receiver interrupts */
+ long txints; /* Transmitter interrupts */
+ long exints; /* External/status interrupts */
+ long spints; /* Special receiver interrupts */
+
+ long txframes; /* Packets sent */
+ long rxframes; /* Number of Frames Actually Received */
+ long rxerrs; /* CRC Errors */
+ long txerrs; /* KISS errors */
+
+ unsigned int nospace; /* "Out of buffers" */
+ unsigned int rx_over; /* Receiver Overruns */
+ unsigned int tx_under; /* Transmitter Underruns */
+
+ unsigned int tx_state; /* Transmitter state */
+ int tx_queued; /* tx frames enqueued */
+
+ unsigned int maxqueue; /* allocated tx_buffers */
+ unsigned int bufsize; /* used buffersize */
+};
+
+struct scc_modem {
+ long speed; /* Line speed, bps */
+ char clocksrc; /* 0 = DPLL, 1 = external, 2 = divider */
+ char nrz; /* NRZ instead of NRZI */
+};
+
+struct scc_kiss_cmd {
+ int command; /* one of the KISS-Commands defined above */
+ unsigned param; /* KISS-Param */
+};
+
+struct scc_hw_config {
+ io_port data_a; /* data port channel A */
+ io_port ctrl_a; /* control port channel A */
+ io_port data_b; /* data port channel B */
+ io_port ctrl_b; /* control port channel B */
+ io_port vector_latch; /* INTACK-Latch (#) */
+ io_port special; /* special function port */
+
+ int irq; /* irq */
+ long clock; /* clock */
+ char option; /* command for function port */
+
+ char brand; /* hardware type */
+ char escc; /* use ext. features of a 8580/85180/85280 */
+};
+
+/* (#) only one INTACK latch allowed. */
+
+
+struct scc_mem_config {
+ unsigned int dummy;
+ unsigned int bufsize;
+};
+
+struct scc_calibrate {
+ unsigned int time;
+ unsigned char pattern;
+};
+
+#ifdef __KERNEL__
+
+enum {TX_OFF, TX_ON}; /* command for scc_key_trx() */
+
+/* Vector masks in RR2B */
+
+#define VECTOR_MASK 0x06
+#define TXINT 0x00
+#define EXINT 0x02
+#define RXINT 0x04
+#define SPINT 0x06
+
+#ifdef CONFIG_SCC_DELAY
+#define Inb(port) inb_p(port)
+#define Outb(port, val) outb_p(val, port)
+#else
+#define Inb(port) inb(port)
+#define Outb(port, val) outb(val, port)
+#endif
+
+/* SCC channel control structure for KISS */
+
+struct scc_kiss {
+ unsigned char txdelay; /* Transmit Delay 10 ms/cnt */
+ unsigned char persist; /* Persistence (0-255) as a % */
+ unsigned char slottime; /* Delay to wait on persistence hit */
+ unsigned char tailtime; /* Delay after last byte written */
+ unsigned char fulldup; /* Full Duplex mode 0=CSMA 1=DUP 2=ALWAYS KEYED */
+ unsigned char waittime; /* Waittime before any transmit attempt */
+ unsigned int maxkeyup; /* Maximum time to transmit (seconds) */
+ unsigned char mintime; /* Minimal offtime after MAXKEYUP timeout (seconds) */
+ unsigned int idletime; /* Maximum idle time in ALWAYS KEYED mode (seconds) */
+ unsigned int maxdefer; /* Timer for CSMA channel busy limit */
+ unsigned char tx_inhibit; /* Transmit is not allowed when set */
+ unsigned char group; /* Group ID for AX.25 TX interlocking */
+ unsigned char mode; /* 'normal' or 'hwctrl' mode (unused) */
+ unsigned char softdcd; /* Use DPLL instead of DCD pin for carrier detect */
+};
+
+
+/* SCC channel structure */
+
+struct scc_channel {
+ int magic; /* magic word */
+
+ int init; /* channel exists? */
+
+ struct device *dev; /* link to device control structure */
+ struct net_device_stats dev_stat;/* device statistics */
+
+ char brand; /* manufacturer of the board */
+ long clock; /* used clock */
+
+ io_port ctrl; /* I/O address of CONTROL register */
+ io_port data; /* I/O address of DATA register */
+ io_port special; /* I/O address of special function port */
+ int irq; /* Number of Interrupt */
+
+ char option;
+ char enhanced; /* Enhanced SCC support */
+
+ unsigned char wreg[16]; /* Copy of last written value in WRx */
+ unsigned char status; /* Copy of R0 at last external interrupt */
+ unsigned char dcd; /* DCD status */
+
+ struct scc_kiss kiss; /* control structure for KISS params */
+ struct scc_stat stat; /* statistical information */
+ struct scc_modem modem; /* modem information */
+
+ struct sk_buff_head tx_queue; /* next tx buffer */
+ struct sk_buff *rx_buff; /* pointer to frame currently received */
+ struct sk_buff *tx_buff; /* pointer to frame currently transmitted */
+
+ /* Timer */
+
+ struct timer_list tx_t; /* tx timer for this channel */
+ struct timer_list tx_wdog; /* tx watchdogs */
+};
+
+int scc_init(void);
+#endif /* defined(__KERNEL__) */
+#endif /* defined(_SCC_H) */
diff --git a/pfinet/linux-src/include/linux/sched.h b/pfinet/linux-src/include/linux/sched.h
new file mode 100644
index 00000000..d983c17e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sched.h
@@ -0,0 +1,813 @@
+#ifndef _LINUX_SCHED_H
+#define _LINUX_SCHED_H
+
+#include <asm/param.h> /* for HZ */
+
+extern unsigned long global_event;
+
+#include <linux/binfmts.h>
+#include <linux/personality.h>
+#include <linux/tasks.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/times.h>
+#include <linux/timex.h>
+
+#include <asm/system.h>
+#include <asm/semaphore.h>
+#include <asm/page.h>
+
+#include <linux/smp.h>
+#include <linux/tty.h>
+#include <linux/sem.h>
+#include <linux/signal.h>
+#include <linux/securebits.h>
+
+/*
+ * cloning flags:
+ */
+#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */
+#define CLONE_VM 0x00000100 /* set if VM shared between processes */
+#define CLONE_FS 0x00000200 /* set if fs info shared between processes */
+#define CLONE_FILES 0x00000400 /* set if open files shared between processes */
+#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */
+#define CLONE_PID 0x00001000 /* set if pid shared */
+#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */
+#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */
+
+/*
+ * These are the constant used to fake the fixed-point load-average
+ * counting. Some notes:
+ * - 11 bit fractions expand to 22 bits by the multiplies: this gives
+ * a load-average precision of 10 bits integer + 11 bits fractional
+ * - if you want to count load-averages more often, you need more
+ * precision, or rounding will get you. With 2-second counting freq,
+ * the EXP_n values would be 1981, 2034 and 2043 if still using only
+ * 11 bit fractions.
+ */
+extern unsigned long avenrun[]; /* Load averages */
+
+#define FSHIFT 11 /* nr of bits of precision */
+#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
+#define LOAD_FREQ (5*HZ) /* 5 sec intervals */
+#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */
+#define EXP_5 2014 /* 1/exp(5sec/5min) */
+#define EXP_15 2037 /* 1/exp(5sec/15min) */
+
+#define CALC_LOAD(load,exp,n) \
+ load *= exp; \
+ load += n*(FIXED_1-exp); \
+ load >>= FSHIFT;
+
+#define CT_TO_SECS(x) ((x) / HZ)
+#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ)
+
+extern int nr_running, nr_tasks;
+extern int last_pid;
+
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/param.h>
+#include <linux/resource.h>
+#include <linux/timer.h>
+
+#include <asm/processor.h>
+
+#define TASK_RUNNING 0
+#define TASK_INTERRUPTIBLE 1
+#define TASK_UNINTERRUPTIBLE 2
+#define TASK_ZOMBIE 4
+#define TASK_STOPPED 8
+#define TASK_SWAPPING 16
+
+/*
+ * Scheduling policies
+ */
+#define SCHED_OTHER 0
+#define SCHED_FIFO 1
+#define SCHED_RR 2
+
+/*
+ * This is an additional bit set when we want to
+ * yield the CPU for one re-schedule..
+ */
+#define SCHED_YIELD 0x10
+
+struct sched_param {
+ int sched_priority;
+};
+
+#ifdef __KERNEL__
+
+#include <asm/spinlock.h>
+
+/*
+ * This serializes "schedule()" and also protects
+ * the run-queue from deletions/modifications (but
+ * _adding_ to the beginning of the run-queue has
+ * a separate lock).
+ */
+extern rwlock_t tasklist_lock;
+extern spinlock_t runqueue_lock;
+
+extern void sched_init(void);
+extern void init_idle(void);
+extern void show_state(void);
+extern void trap_init(void);
+
+#define MAX_SCHEDULE_TIMEOUT LONG_MAX
+extern signed long FASTCALL(schedule_timeout(signed long timeout));
+asmlinkage void schedule(void);
+
+/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
+ * Open file table structure
+ */
+struct files_struct {
+ atomic_t count;
+ int max_fds;
+ int max_fdset;
+ int next_fd;
+ struct file ** fd; /* current fd array */
+ fd_set *close_on_exec;
+ fd_set *open_fds;
+ fd_set close_on_exec_init;
+ fd_set open_fds_init;
+ struct file * fd_array[NR_OPEN_DEFAULT];
+};
+
+#define INIT_FILES { \
+ ATOMIC_INIT(1), \
+ NR_OPEN_DEFAULT, \
+ __FD_SETSIZE, \
+ 0, \
+ &init_files.fd_array[0], \
+ &init_files.close_on_exec_init, \
+ &init_files.open_fds_init, \
+ { { 0, } }, \
+ { { 0, } }, \
+ { NULL, } \
+}
+
+struct fs_struct {
+ atomic_t count;
+ int umask;
+ struct dentry * root, * pwd;
+};
+
+#define INIT_FS { \
+ ATOMIC_INIT(1), \
+ 0022, \
+ NULL, NULL \
+}
+
+/* Maximum number of active map areas.. This is a random (large) number */
+#define MAX_MAP_COUNT (65536)
+
+/* Number of map areas at which the AVL tree is activated. This is arbitrary. */
+#define AVL_MIN_MAP_COUNT 32
+
+struct mm_struct {
+ struct vm_area_struct *mmap; /* list of VMAs */
+ struct vm_area_struct *mmap_avl; /* tree of VMAs */
+ struct vm_area_struct *mmap_cache; /* last find_vma result */
+ pgd_t * pgd;
+ atomic_t count;
+ int map_count; /* number of VMAs */
+ struct semaphore mmap_sem;
+ unsigned long context;
+ unsigned long start_code, end_code, start_data, end_data;
+ unsigned long start_brk, brk, start_stack;
+ unsigned long arg_start, arg_end, env_start, env_end;
+ unsigned long rss, total_vm, locked_vm;
+ unsigned long def_flags;
+ unsigned long cpu_vm_mask;
+ unsigned long swap_cnt; /* number of pages to swap on next pass */
+ unsigned long swap_address;
+ /*
+ * This is an architecture-specific pointer: the portable
+ * part of Linux does not know about any segments.
+ */
+ void * segments;
+};
+
+#define INIT_MM { \
+ &init_mmap, NULL, NULL, \
+ swapper_pg_dir, \
+ ATOMIC_INIT(1), 1, \
+ MUTEX, \
+ 0, \
+ 0, 0, 0, 0, \
+ 0, 0, 0, \
+ 0, 0, 0, 0, \
+ 0, 0, 0, \
+ 0, 0, 0, 0, NULL }
+
+struct signal_struct {
+ atomic_t count;
+ struct k_sigaction action[_NSIG];
+ spinlock_t siglock;
+};
+
+
+#define INIT_SIGNALS { \
+ ATOMIC_INIT(1), \
+ { {{0,}}, }, \
+ SPIN_LOCK_UNLOCKED }
+
+/*
+ * Some day this will be a full-fledged user tracking system..
+ * Right now it is only used to track how many processes a
+ * user has, but it has the potential to track memory usage etc.
+ */
+struct user_struct;
+
+struct task_struct {
+/* these are hardcoded - don't touch */
+ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
+ unsigned long flags; /* per process flags, defined below */
+ int sigpending;
+ mm_segment_t addr_limit; /* thread address space:
+ 0-0xBFFFFFFF for user-thead
+ 0-0xFFFFFFFF for kernel-thread
+ */
+ struct exec_domain *exec_domain;
+ long need_resched;
+
+/* various fields */
+ long counter;
+ long priority;
+ cycles_t avg_slice;
+/* SMP and runqueue state */
+ int has_cpu;
+ int processor;
+ int last_processor;
+ int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */
+ struct task_struct *next_task, *prev_task;
+ struct task_struct *next_run, *prev_run;
+
+/* task state */
+ struct linux_binfmt *binfmt;
+ int exit_code, exit_signal;
+ int pdeath_signal; /* The signal sent when the parent dies */
+ /* ??? */
+ unsigned long personality;
+ int dumpable:1;
+ int did_exec:1;
+ pid_t pid;
+ pid_t pgrp;
+ pid_t tty_old_pgrp;
+ pid_t session;
+ /* boolean value for session group leader */
+ int leader;
+ /*
+ * pointers to (original) parent process, youngest child, younger sibling,
+ * older sibling, respectively. (p->father can be replaced with
+ * p->p_pptr->pid)
+ */
+ struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+
+ /* PID hash table linkage. */
+ struct task_struct *pidhash_next;
+ struct task_struct **pidhash_pprev;
+
+ /* Pointer to task[] array linkage. */
+ struct task_struct **tarray_ptr;
+
+ struct wait_queue *wait_chldexit; /* for wait4() */
+ struct semaphore *vfork_sem; /* for vfork() */
+ unsigned long policy, rt_priority;
+ unsigned long it_real_value, it_prof_value, it_virt_value;
+ unsigned long it_real_incr, it_prof_incr, it_virt_incr;
+ struct timer_list real_timer;
+ struct tms times;
+ unsigned long start_time;
+ long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
+/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
+ unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
+ int swappable:1;
+/* process credentials */
+ uid_t uid,euid,suid,fsuid;
+ gid_t gid,egid,sgid,fsgid;
+ int ngroups;
+ gid_t groups[NGROUPS];
+ kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
+ struct user_struct *user;
+/* limits */
+ struct rlimit rlim[RLIM_NLIMITS];
+ unsigned short used_math;
+ char comm[16];
+/* file system info */
+ int link_count;
+ struct tty_struct *tty; /* NULL if no tty */
+/* ipc stuff */
+ struct sem_undo *semundo;
+ struct sem_queue *semsleeping;
+/* tss for this task */
+ struct thread_struct tss;
+/* filesystem information */
+ struct fs_struct *fs;
+/* open file information */
+ struct files_struct *files;
+/* memory management info */
+ struct mm_struct *mm;
+
+/* signal handlers */
+ spinlock_t sigmask_lock; /* Protects signal and blocked */
+ struct signal_struct *sig;
+ sigset_t signal, blocked;
+ struct signal_queue *sigqueue, **sigqueue_tail;
+ unsigned long sas_ss_sp;
+ size_t sas_ss_size;
+
+/* Thread group tracking */
+ u32 parent_exec_id;
+ u32 self_exec_id;
+};
+
+/*
+ * Per process flags
+ */
+#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */
+ /* Not implemented yet, only for 486*/
+#define PF_STARTING 0x00000002 /* being created */
+#define PF_EXITING 0x00000004 /* getting shut down */
+#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called */
+#define PF_TRACESYS 0x00000020 /* tracing system calls */
+#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */
+#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */
+#define PF_DUMPCORE 0x00000200 /* dumped core */
+#define PF_SIGNALED 0x00000400 /* killed by a signal */
+#define PF_MEMALLOC 0x00000800 /* Allocating memory */
+#define PF_VFORK 0x00001000 /* Wake up parent in mm_release */
+
+#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */
+#define PF_DTRACE 0x00200000 /* delayed trace (used on m68k, i386) */
+
+/*
+ * Limit the stack by to some sane default: root can always
+ * increase this limit if needed.. 8MB seems reasonable.
+ */
+#define _STK_LIM (8*1024*1024)
+
+#define DEF_PRIORITY (20*HZ/100) /* 210 ms time slices */
+
+/*
+ * INIT_TASK is used to set up the first task table, touch at
+ * your own risk!. Base=0, limit=0x1fffff (=2MB)
+ */
+#define INIT_TASK \
+/* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain,0, \
+/* counter */ DEF_PRIORITY,DEF_PRIORITY,0, \
+/* SMP */ 0,0,0,-1, \
+/* schedlink */ &init_task,&init_task, &init_task, &init_task, \
+/* binfmt */ NULL, \
+/* ec,brk... */ 0,0,0,0,0,0, \
+/* pid etc.. */ 0,0,0,0,0, \
+/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
+/* pidhash */ NULL, NULL, \
+/* tarray */ &task[0], \
+/* chld wait */ NULL, NULL, \
+/* timeout */ SCHED_OTHER,0,0,0,0,0,0,0, \
+/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \
+/* utime */ {0,0,0,0},0, \
+/* per CPU times */ {0, }, {0, }, \
+/* flt */ 0,0,0,0,0,0, \
+/* swp */ 0, \
+/* process credentials */ \
+/* uid etc */ 0,0,0,0,0,0,0,0, \
+/* suppl grps*/ 0, {0,}, \
+/* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \
+/* user */ NULL, \
+/* rlimits */ INIT_RLIMITS, \
+/* math */ 0, \
+/* comm */ "swapper", \
+/* fs info */ 0,NULL, \
+/* ipc */ NULL, NULL, \
+/* tss */ INIT_TSS, \
+/* fs */ &init_fs, \
+/* files */ &init_files, \
+/* mm */ &init_mm, \
+/* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
+/* exec cts */ 0,0, \
+}
+
+union task_union {
+ struct task_struct task;
+ unsigned long stack[2048];
+};
+
+extern union task_union init_task_union;
+
+extern struct mm_struct init_mm;
+extern struct task_struct *task[NR_TASKS];
+
+extern struct task_struct **tarray_freelist;
+extern spinlock_t taskslot_lock;
+
+extern __inline__ void add_free_taskslot(struct task_struct **t)
+{
+ spin_lock(&taskslot_lock);
+ *t = (struct task_struct *) tarray_freelist;
+ tarray_freelist = t;
+ spin_unlock(&taskslot_lock);
+}
+
+extern __inline__ struct task_struct **get_free_taskslot(void)
+{
+ struct task_struct **tslot;
+
+ spin_lock(&taskslot_lock);
+ if((tslot = tarray_freelist) != NULL)
+ tarray_freelist = (struct task_struct **) *tslot;
+ spin_unlock(&taskslot_lock);
+
+ return tslot;
+}
+
+/* PID hashing. */
+#define PIDHASH_SZ (NR_TASKS >> 2)
+extern struct task_struct *pidhash[PIDHASH_SZ];
+
+#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
+
+extern __inline__ void hash_pid(struct task_struct *p)
+{
+ struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
+
+ if((p->pidhash_next = *htable) != NULL)
+ (*htable)->pidhash_pprev = &p->pidhash_next;
+ *htable = p;
+ p->pidhash_pprev = htable;
+}
+
+extern __inline__ void unhash_pid(struct task_struct *p)
+{
+ if(p->pidhash_next)
+ p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
+ *p->pidhash_pprev = p->pidhash_next;
+}
+
+extern __inline__ struct task_struct *find_task_by_pid(int pid)
+{
+ struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
+
+ for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
+ ;
+
+ return p;
+}
+
+/* per-UID process charging. */
+extern int alloc_uid(struct task_struct *p);
+void free_uid(struct task_struct *p);
+
+#include <asm/current.h>
+
+extern unsigned long volatile jiffies;
+extern unsigned long itimer_ticks;
+extern unsigned long itimer_next;
+extern struct timeval xtime;
+extern void do_timer(struct pt_regs *);
+
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+
+#define CURRENT_TIME (xtime.tv_sec)
+
+extern void FASTCALL(__wake_up(struct wait_queue ** p, unsigned int mode));
+extern void FASTCALL(sleep_on(struct wait_queue ** p));
+extern long FASTCALL(sleep_on_timeout(struct wait_queue ** p,
+ signed long timeout));
+extern void FASTCALL(interruptible_sleep_on(struct wait_queue ** p));
+extern long FASTCALL(interruptible_sleep_on_timeout(struct wait_queue ** p,
+ signed long timeout));
+extern void FASTCALL(wake_up_process(struct task_struct * tsk));
+
+#define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
+#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE)
+
+extern int in_group_p(gid_t grp);
+
+extern void flush_signals(struct task_struct *);
+extern void flush_signal_handlers(struct task_struct *);
+extern int dequeue_signal(sigset_t *block, siginfo_t *);
+extern int send_sig_info(int, struct siginfo *info, struct task_struct *);
+extern int force_sig_info(int, struct siginfo *info, struct task_struct *);
+extern int kill_pg_info(int, struct siginfo *info, pid_t);
+extern int kill_sl_info(int, struct siginfo *info, pid_t);
+extern int kill_proc_info(int, struct siginfo *info, pid_t);
+extern int kill_something_info(int, struct siginfo *info, int);
+extern void notify_parent(struct task_struct * tsk, int);
+extern void force_sig(int sig, struct task_struct * p);
+extern int send_sig(int sig, struct task_struct * p, int priv);
+extern int kill_pg(pid_t, int, int);
+extern int kill_sl(pid_t, int, int);
+extern int kill_proc(pid_t, int, int);
+extern int do_sigaction(int sig, const struct k_sigaction *act,
+ struct k_sigaction *oact);
+extern int do_sigaltstack(const stack_t *ss, stack_t *oss, unsigned long sp);
+
+extern inline int signal_pending(struct task_struct *p)
+{
+ return (p->sigpending != 0);
+}
+
+/* Reevaluate whether the task has signals pending delivery.
+ This is required every time the blocked sigset_t changes.
+ All callers should have t->sigmask_lock. */
+
+static inline void recalc_sigpending(struct task_struct *t)
+{
+ unsigned long ready;
+ long i;
+
+ switch (_NSIG_WORDS) {
+ default:
+ for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;)
+ ready |= t->signal.sig[i] &~ t->blocked.sig[i];
+ break;
+
+ case 4: ready = t->signal.sig[3] &~ t->blocked.sig[3];
+ ready |= t->signal.sig[2] &~ t->blocked.sig[2];
+ ready |= t->signal.sig[1] &~ t->blocked.sig[1];
+ ready |= t->signal.sig[0] &~ t->blocked.sig[0];
+ break;
+
+ case 2: ready = t->signal.sig[1] &~ t->blocked.sig[1];
+ ready |= t->signal.sig[0] &~ t->blocked.sig[0];
+ break;
+
+ case 1: ready = t->signal.sig[0] &~ t->blocked.sig[0];
+ }
+
+ t->sigpending = (ready != 0);
+}
+
+/* True if we are on the alternate signal stack. */
+
+static inline int on_sig_stack(unsigned long sp)
+{
+ return (sp >= current->sas_ss_sp
+ && sp < current->sas_ss_sp + current->sas_ss_size);
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+ return (current->sas_ss_size == 0 ? SS_DISABLE
+ : on_sig_stack(sp) ? SS_ONSTACK : 0);
+}
+
+extern int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags,
+ const char *device,
+ void *dev_id);
+extern void free_irq(unsigned int irq, void *dev_id);
+
+/*
+ * This has now become a routine instead of a macro, it sets a flag if
+ * it returns true (to do BSD-style accounting where the process is flagged
+ * if it uses root privs). The implication of this is that you should do
+ * normal permissions checks first, and check suser() last.
+ *
+ * [Dec 1997 -- Chris Evans]
+ * For correctness, the above considerations need to be extended to
+ * fsuser(). This is done, along with moving fsuser() checks to be
+ * last.
+ *
+ * These will be removed, but in the mean time, when the SECURE_NOROOT
+ * flag is set, uids don't grant privilege.
+ */
+extern inline int suser(void)
+{
+ if (!issecure(SECURE_NOROOT) && current->euid == 0) {
+ current->flags |= PF_SUPERPRIV;
+ return 1;
+ }
+ return 0;
+}
+
+extern inline int fsuser(void)
+{
+ if (!issecure(SECURE_NOROOT) && current->fsuid == 0) {
+ current->flags |= PF_SUPERPRIV;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * capable() checks for a particular capability.
+ * New privilege checks should use this interface, rather than suser() or
+ * fsuser(). See include/linux/capability.h for defined capabilities.
+ */
+
+extern inline int capable(int cap)
+{
+#if 1 /* ok now */
+ if (cap_raised(current->cap_effective, cap))
+#else
+ if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0)
+#endif
+ {
+ current->flags |= PF_SUPERPRIV;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Routines for handling mm_structs
+ */
+extern struct mm_struct * mm_alloc(void);
+static inline void mmget(struct mm_struct * mm)
+{
+ atomic_inc(&mm->count);
+}
+extern void mmput(struct mm_struct *);
+/* Remove the current tasks stale references to the old mm_struct */
+extern void mm_release(void);
+
+/*
+ * Routines for handling the fd arrays
+ */
+extern struct file ** alloc_fd_array(int);
+extern int expand_fd_array(struct files_struct *, int nr);
+extern void free_fd_array(struct file **, int);
+
+extern fd_set *alloc_fdset(int);
+extern int expand_fdset(struct files_struct *, int nr);
+extern void free_fdset(fd_set *, int);
+
+/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded,
+ * we may have blocked. */
+static inline int expand_files(struct files_struct *files, int nr)
+{
+ int err, expand = 0;
+#ifdef FDSET_DEBUG
+ printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr);
+#endif
+
+ if (nr >= files->max_fdset) {
+ expand = 1;
+ if ((err = expand_fdset(files, nr + 1)))
+ goto out;
+ }
+ if (nr >= files->max_fds) {
+ expand = 1;
+ if ((err = expand_fd_array(files, nr + 1)))
+ goto out;
+ }
+ err = expand;
+ out:
+#ifdef FDSET_DEBUG
+ if (err)
+ printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err);
+#endif
+ return err;
+}
+
+extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
+extern void flush_thread(void);
+extern void exit_thread(void);
+
+extern void exit_mm(struct task_struct *);
+extern void exit_fs(struct task_struct *);
+extern void exit_files(struct task_struct *);
+extern void exit_sighand(struct task_struct *);
+
+extern int do_execve(char *, char **, char **, struct pt_regs *);
+extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
+
+/*
+ * The wait-queues are circular lists, and you have to be *very* sure
+ * to keep them correct. Use only these two functions to add/remove
+ * entries in the queues.
+ */
+extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ wait->next = *p ? : WAIT_QUEUE_HEAD(p);
+ *p = wait;
+}
+
+extern rwlock_t waitqueue_lock;
+
+extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&waitqueue_lock, flags);
+ __add_wait_queue(p, wait);
+ write_unlock_irqrestore(&waitqueue_lock, flags);
+}
+
+extern inline void __remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ struct wait_queue * next = wait->next;
+ struct wait_queue * head = next;
+ struct wait_queue * tmp;
+
+ while ((tmp = head->next) != wait) {
+ head = tmp;
+ }
+ head->next = next;
+}
+
+extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&waitqueue_lock, flags);
+ __remove_wait_queue(p, wait);
+ write_unlock_irqrestore(&waitqueue_lock, flags);
+}
+
+#define __wait_event(wq, condition) \
+do { \
+ struct wait_queue __wait; \
+ \
+ __wait.task = current; \
+ add_wait_queue(&wq, &__wait); \
+ for (;;) { \
+ current->state = TASK_UNINTERRUPTIBLE; \
+ mb(); \
+ if (condition) \
+ break; \
+ schedule(); \
+ } \
+ current->state = TASK_RUNNING; \
+ remove_wait_queue(&wq, &__wait); \
+} while (0)
+
+#define wait_event(wq, condition) \
+do { \
+ if (condition) \
+ break; \
+ __wait_event(wq, condition); \
+} while (0)
+
+#define __wait_event_interruptible(wq, condition, ret) \
+do { \
+ struct wait_queue __wait; \
+ \
+ __wait.task = current; \
+ add_wait_queue(&wq, &__wait); \
+ for (;;) { \
+ current->state = TASK_INTERRUPTIBLE; \
+ mb(); \
+ if (condition) \
+ break; \
+ if (!signal_pending(current)) { \
+ schedule(); \
+ continue; \
+ } \
+ ret = -ERESTARTSYS; \
+ break; \
+ } \
+ current->state = TASK_RUNNING; \
+ remove_wait_queue(&wq, &__wait); \
+} while (0)
+
+#define wait_event_interruptible(wq, condition) \
+({ \
+ int __ret = 0; \
+ if (!(condition)) \
+ __wait_event_interruptible(wq, condition, __ret); \
+ __ret; \
+})
+
+#define REMOVE_LINKS(p) do { \
+ (p)->next_task->prev_task = (p)->prev_task; \
+ (p)->prev_task->next_task = (p)->next_task; \
+ if ((p)->p_osptr) \
+ (p)->p_osptr->p_ysptr = (p)->p_ysptr; \
+ if ((p)->p_ysptr) \
+ (p)->p_ysptr->p_osptr = (p)->p_osptr; \
+ else \
+ (p)->p_pptr->p_cptr = (p)->p_osptr; \
+ } while (0)
+
+#define SET_LINKS(p) do { \
+ (p)->next_task = &init_task; \
+ (p)->prev_task = init_task.prev_task; \
+ init_task.prev_task->next_task = (p); \
+ init_task.prev_task = (p); \
+ (p)->p_ysptr = NULL; \
+ if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \
+ (p)->p_osptr->p_ysptr = p; \
+ (p)->p_pptr->p_cptr = p; \
+ } while (0)
+
+#define for_each_task(p) \
+ for (p = &init_task ; (p = p->next_task) != &init_task ; )
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/sdla.h b/pfinet/linux-src/include/linux/sdla.h
new file mode 100644
index 00000000..44ae55b1
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdla.h
@@ -0,0 +1,339 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the Frame relay interface.
+ *
+ * Version: @(#)if_ifrad.h 0.20 13 Apr 96
+ *
+ * Author: Mike McLagan <mike.mclagan@linux.org>
+ *
+ * Changes:
+ * 0.15 Mike McLagan Structure packing
+ *
+ * 0.20 Mike McLagan New flags for S508 buffer handling
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef SDLA_H
+#define SDLA_H
+
+/* adapter type */
+#define SDLA_TYPES
+#define SDLA_S502A 5020
+#define SDLA_S502E 5021
+#define SDLA_S503 5030
+#define SDLA_S507 5070
+#define SDLA_S508 5080
+#define SDLA_S509 5090
+#define SDLA_UNKNOWN -1
+
+/* port selection flags for the S508 */
+#define SDLA_S508_PORT_V35 0x00
+#define SDLA_S508_PORT_RS232 0x02
+
+/* Z80 CPU speeds */
+#define SDLA_CPU_3M 0x00
+#define SDLA_CPU_5M 0x01
+#define SDLA_CPU_7M 0x02
+#define SDLA_CPU_8M 0x03
+#define SDLA_CPU_10M 0x04
+#define SDLA_CPU_16M 0x05
+#define SDLA_CPU_12M 0x06
+
+/* some private IOCTLs */
+#define SDLA_IDENTIFY (FRAD_LAST_IOCTL + 1)
+#define SDLA_CPUSPEED (FRAD_LAST_IOCTL + 2)
+#define SDLA_PROTOCOL (FRAD_LAST_IOCTL + 3)
+
+#define SDLA_CLEARMEM (FRAD_LAST_IOCTL + 4)
+#define SDLA_WRITEMEM (FRAD_LAST_IOCTL + 5)
+#define SDLA_READMEM (FRAD_LAST_IOCTL + 6)
+
+struct sdla_mem {
+ int addr;
+ int len;
+ void *data;
+};
+
+#define SDLA_START (FRAD_LAST_IOCTL + 7)
+#define SDLA_STOP (FRAD_LAST_IOCTL + 8)
+
+/* some offsets in the Z80's memory space */
+#define SDLA_NMIADDR 0x0000
+#define SDLA_CONF_ADDR 0x0010
+#define SDLA_S502A_NMIADDR 0x0066
+#define SDLA_CODE_BASEADDR 0x0100
+#define SDLA_WINDOW_SIZE 0x2000
+#define SDLA_ADDR_MASK 0x1FFF
+
+/* largest handleable block of data */
+#define SDLA_MAX_DATA 4080
+#define SDLA_MAX_MTU 4072 /* MAX_DATA - sizeof(fradhdr) */
+#define SDLA_MAX_DLCI 24
+
+/* this should be the same as frad_conf */
+struct sdla_conf {
+ short station;
+ short config;
+ short kbaud;
+ short clocking;
+ short max_frm;
+ short T391;
+ short T392;
+ short N391;
+ short N392;
+ short N393;
+ short CIR_fwd;
+ short Bc_fwd;
+ short Be_fwd;
+ short CIR_bwd;
+ short Bc_bwd;
+ short Be_bwd;
+};
+
+/* this should be the same as dlci_conf */
+struct sdla_dlci_conf {
+ short config;
+ short CIR_fwd;
+ short Bc_fwd;
+ short Be_fwd;
+ short CIR_bwd;
+ short Bc_bwd;
+ short Be_bwd;
+ short Tc_fwd;
+ short Tc_bwd;
+ short Tf_max;
+ short Tb_max;
+};
+
+#ifndef __KERNEL__
+
+void sdla(void *cfg_info, char *dev, struct frad_conf *conf, int quiet);
+
+#else
+
+/* important Z80 window addresses */
+#define SDLA_CONTROL_WND 0xE000
+
+#define SDLA_502_CMD_BUF 0xEF60
+#define SDLA_502_RCV_BUF 0xA900
+#define SDLA_502_TXN_AVAIL 0xFFF1
+#define SDLA_502_RCV_AVAIL 0xFFF2
+#define SDLA_502_EVENT_FLAGS 0xFFF3
+#define SDLA_502_MDM_STATUS 0xFFF4
+#define SDLA_502_IRQ_INTERFACE 0xFFFD
+#define SDLA_502_IRQ_PERMISSION 0xFFFE
+#define SDLA_502_DATA_OFS 0x0010
+
+#define SDLA_508_CMD_BUF 0xE000
+#define SDLA_508_TXBUF_INFO 0xF100
+#define SDLA_508_RXBUF_INFO 0xF120
+#define SDLA_508_EVENT_FLAGS 0xF003
+#define SDLA_508_MDM_STATUS 0xF004
+#define SDLA_508_IRQ_INTERFACE 0xF010
+#define SDLA_508_IRQ_PERMISSION 0xF011
+#define SDLA_508_TSE_OFFSET 0xF012
+
+/* Event flags */
+#define SDLA_EVENT_STATUS 0x01
+#define SDLA_EVENT_DLCI_STATUS 0x02
+#define SDLA_EVENT_BAD_DLCI 0x04
+#define SDLA_EVENT_LINK_DOWN 0x40
+
+/* IRQ Trigger flags */
+#define SDLA_INTR_RX 0x01
+#define SDLA_INTR_TX 0x02
+#define SDLA_INTR_MODEM 0x04
+#define SDLA_INTR_COMPLETE 0x08
+#define SDLA_INTR_STATUS 0x10
+#define SDLA_INTR_TIMER 0x20
+
+/* DLCI status bits */
+#define SDLA_DLCI_DELETED 0x01
+#define SDLA_DLCI_ACTIVE 0x02
+#define SDLA_DLCI_WAITING 0x04
+#define SDLA_DLCI_NEW 0x08
+#define SDLA_DLCI_INCLUDED 0x40
+
+/* valid command codes */
+#define SDLA_INFORMATION_WRITE 0x01
+#define SDLA_INFORMATION_READ 0x02
+#define SDLA_ISSUE_IN_CHANNEL_SIGNAL 0x03
+#define SDLA_SET_DLCI_CONFIGURATION 0x10
+#define SDLA_READ_DLCI_CONFIGURATION 0x11
+#define SDLA_DISABLE_COMMUNICATIONS 0x12
+#define SDLA_ENABLE_COMMUNICATIONS 0x13
+#define SDLA_READ_DLC_STATUS 0x14
+#define SDLA_READ_DLC_STATISTICS 0x15
+#define SDLA_FLUSH_DLC_STATISTICS 0x16
+#define SDLA_LIST_ACTIVE_DLCI 0x17
+#define SDLA_FLUSH_INFORMATION_BUFFERS 0x18
+#define SDLA_ADD_DLCI 0x20
+#define SDLA_DELETE_DLCI 0x21
+#define SDLA_ACTIVATE_DLCI 0x22
+#define SDLA_DEACTIVATE_DLCI 0x23
+#define SDLA_READ_MODEM_STATUS 0x30
+#define SDLA_SET_MODEM_STATUS 0x31
+#define SDLA_READ_COMMS_ERR_STATS 0x32
+#define SDLA_FLUSH_COMMS_ERR_STATS 0x33
+#define SDLA_READ_CODE_VERSION 0x40
+#define SDLA_SET_IRQ_TRIGGER 0x50
+#define SDLA_GET_IRQ_TRIGGER 0x51
+
+/* In channel signal types */
+#define SDLA_ICS_LINK_VERIFY 0x02
+#define SDLA_ICS_STATUS_ENQ 0x03
+
+/* modem status flags */
+#define SDLA_MODEM_DTR_HIGH 0x01
+#define SDLA_MODEM_RTS_HIGH 0x02
+#define SDLA_MODEM_DCD_HIGH 0x08
+#define SDLA_MODEM_CTS_HIGH 0x20
+
+/* used for RET_MODEM interpretation */
+#define SDLA_MODEM_DCD_LOW 0x01
+#define SDLA_MODEM_CTS_LOW 0x02
+
+/* return codes */
+#define SDLA_RET_OK 0x00
+#define SDLA_RET_COMMUNICATIONS 0x01
+#define SDLA_RET_CHANNEL_INACTIVE 0x02
+#define SDLA_RET_DLCI_INACTIVE 0x03
+#define SDLA_RET_DLCI_CONFIG 0x04
+#define SDLA_RET_BUF_TOO_BIG 0x05
+#define SDLA_RET_NO_DATA 0x05
+#define SDLA_RET_BUF_OVERSIZE 0x06
+#define SDLA_RET_CIR_OVERFLOW 0x07
+#define SDLA_RET_NO_BUFS 0x08
+#define SDLA_RET_TIMEOUT 0x0A
+#define SDLA_RET_MODEM 0x10
+#define SDLA_RET_CHANNEL_OFF 0x11
+#define SDLA_RET_CHANNEL_ON 0x12
+#define SDLA_RET_DLCI_STATUS 0x13
+#define SDLA_RET_DLCI_UNKNOWN 0x14
+#define SDLA_RET_COMMAND_INVALID 0x1F
+
+/* Configuration flags */
+#define SDLA_DIRECT_RECV 0x0080
+#define SDLA_TX_NO_EXCEPT 0x0020
+#define SDLA_NO_ICF_MSGS 0x1000
+#define SDLA_TX50_RX50 0x0000
+#define SDLA_TX70_RX30 0x2000
+#define SDLA_TX30_RX70 0x4000
+
+/* IRQ selection flags */
+#define SDLA_IRQ_RECEIVE 0x01
+#define SDLA_IRQ_TRANSMIT 0x02
+#define SDLA_IRQ_MODEM_STAT 0x04
+#define SDLA_IRQ_COMMAND 0x08
+#define SDLA_IRQ_CHANNEL 0x10
+#define SDLA_IRQ_TIMER 0x20
+
+/* definitions for PC memory mapping */
+#define SDLA_8K_WINDOW 0x01
+#define SDLA_S502_SEG_A 0x10
+#define SDLA_S502_SEG_C 0x20
+#define SDLA_S502_SEG_D 0x00
+#define SDLA_S502_SEG_E 0x30
+#define SDLA_S507_SEG_A 0x00
+#define SDLA_S507_SEG_B 0x40
+#define SDLA_S507_SEG_C 0x80
+#define SDLA_S507_SEG_E 0xC0
+#define SDLA_S508_SEG_A 0x00
+#define SDLA_S508_SEG_C 0x10
+#define SDLA_S508_SEG_D 0x08
+#define SDLA_S508_SEG_E 0x18
+
+/* SDLA adapter port constants */
+#define SDLA_IO_EXTENTS 0x04
+
+#define SDLA_REG_CONTROL 0x00
+#define SDLA_REG_PC_WINDOW 0x01 /* offset for PC window select latch */
+#define SDLA_REG_Z80_WINDOW 0x02 /* offset for Z80 window select latch */
+#define SDLA_REG_Z80_CONTROL 0x03 /* offset for Z80 control latch */
+
+#define SDLA_S502_STS 0x00 /* status reg for 502, 502E, 507 */
+#define SDLA_S508_GNRL 0x00 /* general purp. reg for 508 */
+#define SDLA_S508_STS 0x01 /* status reg for 508 */
+#define SDLA_S508_IDR 0x02 /* ID reg for 508 */
+
+/* control register flags */
+#define SDLA_S502A_START 0x00 /* start the CPU */
+#define SDLA_S502A_INTREQ 0x02
+#define SDLA_S502A_INTEN 0x04
+#define SDLA_S502A_HALT 0x08 /* halt the CPU */
+#define SDLA_S502A_NMI 0x10 /* issue an NMI to the CPU */
+
+#define SDLA_S502E_CPUEN 0x01
+#define SDLA_S502E_ENABLE 0x02
+#define SDLA_S502E_INTACK 0x04
+
+#define SDLA_S507_ENABLE 0x01
+#define SDLA_S507_IRQ3 0x00
+#define SDLA_S507_IRQ4 0x20
+#define SDLA_S507_IRQ5 0x40
+#define SDLA_S507_IRQ7 0x60
+#define SDLA_S507_IRQ10 0x80
+#define SDLA_S507_IRQ11 0xA0
+#define SDLA_S507_IRQ12 0xC0
+#define SDLA_S507_IRQ15 0xE0
+
+#define SDLA_HALT 0x00
+#define SDLA_CPUEN 0x02
+#define SDLA_MEMEN 0x04
+#define SDLA_S507_EPROMWR 0x08
+#define SDLA_S507_EPROMCLK 0x10
+#define SDLA_S508_INTRQ 0x08
+#define SDLA_S508_INTEN 0x10
+
+struct sdla_cmd {
+ char opp_flag __attribute__((packed));
+ char cmd __attribute__((packed));
+ short length __attribute__((packed));
+ char retval __attribute__((packed));
+ short dlci __attribute__((packed));
+ char flags __attribute__((packed));
+ short rxlost_int __attribute__((packed));
+ long rxlost_app __attribute__((packed));
+ char reserve[2] __attribute__((packed));
+ char data[SDLA_MAX_DATA] __attribute__((packed)); /* transfer data buffer */
+};
+
+struct intr_info {
+ char flags __attribute__((packed));
+ short txlen __attribute__((packed));
+ char irq __attribute__((packed));
+ char flags2 __attribute__((packed));
+ short timeout __attribute__((packed));
+};
+
+/* found in the 508's control window at RXBUF_INFO */
+struct buf_info {
+ unsigned short rse_num __attribute__((packed));
+ unsigned long rse_base __attribute__((packed));
+ unsigned long rse_next __attribute__((packed));
+ unsigned long buf_base __attribute__((packed));
+ unsigned short reserved __attribute__((packed));
+ unsigned long buf_top __attribute__((packed));
+};
+
+/* structure pointed to by rse_base in RXBUF_INFO struct */
+struct buf_entry {
+ char opp_flag __attribute__((packed));
+ short length __attribute__((packed));
+ short dlci __attribute__((packed));
+ char flags __attribute__((packed));
+ short timestamp __attribute__((packed));
+ short reserved[2] __attribute__((packed));
+ long buf_addr __attribute__((packed));
+};
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/sdla_chdlc.h b/pfinet/linux-src/include/linux/sdla_chdlc.h
new file mode 100644
index 00000000..c82fe14b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdla_chdlc.h
@@ -0,0 +1,808 @@
+/*************************************************************************
+ sdla_chdlc.h Sangoma Cisco HDLC firmware API definitions
+
+ Author: Gideon Hack
+ Nenad Corbic <ncorbic@sangoma.com>
+
+ Copyright: (c) 1995-1999 Sangoma Technologies Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the term of the GNU General Public License
+ as published by the Free Software Foundation; either version
+ 2 of the License, or (at your option) any later version.
+
+===========================================================================
+ Oct 04, 1999 Nenad Corbic Updated API support
+ Jun 02, 1999 Gideon Hack Changes for S514 usage.
+ Oct 28, 1998 Jaspreet Singh Made changes for Dual Port CHDLC.
+ Jun 11, 1998 David Fong Initial version.
+===========================================================================
+
+ Organization
+ - Compatibility notes
+ - Constants defining the shared memory control block (mailbox)
+ - Interface commands
+ - Return code from interface commands
+ - Constants for the commands (structures for casting data)
+ - UDP Management constants and structures
+
+*************************************************************************/
+
+#ifndef _SDLA_CHDLC_H
+# define _SDLC_CHDLC_H
+
+/*------------------------------------------------------------------------
+ Notes:
+
+ All structres defined in this file are byte-aligned.
+
+ Compiler Platform
+ ------------------------
+ GNU C Linux
+
+------------------------------------------------------------------------*/
+
+#ifndef PACKED
+#define PACKED __attribute__((packed))
+#endif /* PACKED */
+
+
+/* ----------------------------------------------------------------------------
+ * Constants defining the shared memory control block (mailbox)
+ * --------------------------------------------------------------------------*/
+
+#define PRI_BASE_ADDR_MB_STRUCT 0xE000 /* the base address of the mailbox structure on the adapter */
+#define SEC_BASE_ADDR_MB_STRUCT 0xE800 /* the base address of the mailbox structure on the adapter */
+#define SIZEOF_MB_DATA_BFR 2032 /* the size of the actual mailbox data area */
+#define NUMBER_MB_RESERVED_BYTES 0x0B /* the number of reserved bytes in the mailbox header area */
+
+
+#define MIN_LGTH_CHDLC_DATA_CFG 300 /* min length of the CHDLC data field (for configuration purposes) */
+#define PRI_MAX_NO_DATA_BYTES_IN_FRAME 15354 /* PRIMARY - max length of the CHDLC data field */
+
+typedef struct {
+ unsigned char opp_flag PACKED; /* the opp flag */
+ unsigned char command PACKED; /* the user command */
+ unsigned short buffer_length PACKED; /* the data length */
+ unsigned char return_code PACKED; /* the return code */
+ unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */
+ unsigned char data[SIZEOF_MB_DATA_BFR] PACKED; /* the data area */
+} CHDLC_MAILBOX_STRUCT;
+
+typedef struct {
+ pid_t pid_num PACKED;
+ CHDLC_MAILBOX_STRUCT cmdarea PACKED;
+
+} CMDBLOCK_STRUCT;
+
+
+
+
+/* ----------------------------------------------------------------------------
+ * Interface commands
+ * --------------------------------------------------------------------------*/
+
+/* global interface commands */
+#define READ_GLOBAL_EXCEPTION_CONDITION 0x01
+#define SET_GLOBAL_CONFIGURATION 0x02
+#define READ_GLOBAL_CONFIGURATION 0x03
+#define READ_GLOBAL_STATISTICS 0x04
+#define FLUSH_GLOBAL_STATISTICS 0x05
+#define SET_MODEM_STATUS 0x06 /* set status of DTR or RTS */
+#define READ_MODEM_STATUS 0x07 /* read status of CTS and DCD */
+#define READ_COMMS_ERROR_STATS 0x08
+#define FLUSH_COMMS_ERROR_STATS 0x09
+#define SET_TRACE_CONFIGURATION 0x0A /* set the line trace config */
+#define READ_TRACE_CONFIGURATION 0x0B /* read the line trace config */
+#define READ_TRACE_STATISTICS 0x0C /* read the trace statistics */
+#define FLUSH_TRACE_STATISTICS 0x0D /* flush the trace statistics */
+#define FT1_MONITOR_STATUS_CTRL 0x1C /* set the status of the S508/FT1 monitoring */
+#define SET_FT1_CONFIGURATION 0x18 /* set the FT1 configuration */
+#define READ_FT1_CONFIGURATION 0x19 /* read the FT1 configuration */
+#define TRANSMIT_ASYNC_DATA_TO_FT1 0x1A /* output asynchronous data to the FT1 */
+#define RECEIVE_ASYNC_DATA_FROM_FT1 0x1B /* receive asynchronous data from the FT1 */
+#define FT1_MONITOR_STATUS_CTRL 0x1C /* set the status of the FT1 monitoring */
+
+#define READ_FT1_OPERATIONAL_STATS 0x1D /* read the S508/FT1 operational statistics */
+#define SET_FT1_MODE 0x1E /* set the operational mode of the S508/FT1 module */
+
+/* CHDLC-level interface commands */
+#define READ_CHDLC_CODE_VERSION 0x20
+#define READ_CHDLC_EXCEPTION_CONDITION 0x21 /* read exception condition from the adapter */
+#define SET_CHDLC_CONFIGURATION 0x22
+#define READ_CHDLC_CONFIGURATION 0x23
+#define ENABLE_CHDLC_COMMUNICATIONS 0x24
+#define DISABLE_CHDLC_COMMUNICATIONS 0x25
+#define READ_CHDLC_LINK_STATUS 0x26
+#define READ_CHDLC_OPERATIONAL_STATS 0x27
+#define FLUSH_CHDLC_OPERATIONAL_STATS 0x28
+#define SET_CHDLC_INTERRUPT_TRIGGERS 0x30 /* set application interrupt triggers */
+#define READ_CHDLC_INTERRUPT_TRIGGERS 0x31 /* read application interrupt trigger configuration */
+
+/* Special UDP drivers management commands */
+#define CPIPE_ENABLE_TRACING 0x50
+#define CPIPE_DISABLE_TRACING 0x51
+#define CPIPE_GET_TRACE_INFO 0x52
+#define CPIPE_GET_IBA_DATA 0x53
+#define CPIPE_FT1_READ_STATUS 0x54
+#define CPIPE_DRIVER_STAT_IFSEND 0x55
+#define CPIPE_DRIVER_STAT_INTR 0x56
+#define CPIPE_DRIVER_STAT_GEN 0x57
+#define CPIPE_FLUSH_DRIVER_STATS 0x58
+#define CPIPE_ROUTER_UP_TIME 0x59
+
+/* Driver specific commands for API */
+#define CHDLC_READ_TRACE_DATA 0xE4 /* read trace data */
+#define TRACE_ALL 0x00
+#define TRACE_PROT 0x01
+#define TRACE_DATA 0x02
+
+/* ----------------------------------------------------------------------------
+ * Return codes from interface commands
+ * --------------------------------------------------------------------------*/
+
+#define COMMAND_OK 0x00
+
+/* return codes from global interface commands */
+#define NO_GLOBAL_EXCEP_COND_TO_REPORT 0x01 /* there is no CHDLC exception condition to report */
+#define LGTH_GLOBAL_CFG_DATA_INVALID 0x01 /* the length of the passed global configuration data is invalid */
+#define LGTH_TRACE_CFG_DATA_INVALID 0x01 /* the length of the passed trace configuration data is invalid */
+#define IRQ_TIMEOUT_VALUE_INVALID 0x02 /* an invalid application IRQ timeout value was selected */
+#define TRACE_CONFIG_INVALID 0x02 /* the passed line trace configuration is invalid */
+#define ADAPTER_OPERATING_FREQ_INVALID 0x03 /* an invalid adapter operating frequency was selected */
+#define TRC_DEAC_TMR_INVALID 0x03 /* the trace deactivation timer is invalid */
+#define S508_FT1_ADPTR_NOT_PRESENT 0x0C /* the S508/FT1 adapter is not present */
+#define INVALID_FT1_STATUS_SELECTION 0x0D /* the S508/FT1 status selection is invalid */
+#define FT1_OP_STATS_NOT_ENABLED 0x0D /* the FT1 operational statistics have not been enabled */
+#define FT1_OP_STATS_NOT_AVAILABLE 0x0E /* the FT1 operational statistics are not currently available */
+#define S508_FT1_MODE_SELECTION_BUSY 0x0E /* the S508/FT1 adapter is busy selecting the operational mode */
+
+/* return codes from command READ_GLOBAL_EXCEPTION_CONDITION */
+#define EXCEP_MODEM_STATUS_CHANGE 0x10 /* a modem status change occurred */
+#define EXCEP_TRC_DISABLED 0x11 /* the trace has been disabled */
+#define EXCEP_IRQ_TIMEOUT 0x12 /* IRQ timeout */
+
+/* return codes from CHDLC-level interface commands */
+#define NO_CHDLC_EXCEP_COND_TO_REPORT 0x21 /* there is no CHDLC exception condition to report */
+#define CHDLC_COMMS_DISABLED 0x21 /* communications are not currently enabled */
+#define CHDLC_COMMS_ENABLED 0x21 /* communications are currently enabled */
+#define DISABLE_CHDLC_COMMS_BEFORE_CFG 0x21 /* CHDLC communications must be disabled before setting the configuration */
+#define ENABLE_CHDLC_COMMS_BEFORE_CONN 0x21 /* communications must be enabled before using the CHDLC_CONNECT conmmand */
+#define CHDLC_CFG_BEFORE_COMMS_ENABLED 0x22 /* perform a SET_CHDLC_CONFIGURATION before enabling comms */
+#define LGTH_CHDLC_CFG_DATA_INVALID 0x22 /* the length of the passed CHDLC configuration data is invalid */
+#define LGTH_INT_TRIGGERS_DATA_INVALID 0x22 /* the length of the passed interrupt trigger data is invalid */
+#define INVALID_IRQ_SELECTED 0x23 /* in invalid IRQ was selected in the SET_CHDLC_INTERRUPT_TRIGGERS */
+#define INVALID_CHDLC_CFG_DATA 0x23 /* the passed CHDLC configuration data is invalid */
+#define IRQ_TMR_VALUE_INVALID 0x24 /* an invalid application IRQ timer value was selected */
+#define LARGER_PERCENT_TX_BFR_REQUIRED 0x24 /* a larger Tx buffer percentage is required */
+#define LARGER_PERCENT_RX_BFR_REQUIRED 0x25 /* a larger Rx buffer percentage is required */
+#define S514_BOTH_PORTS_SAME_CLK_MODE 0x26 /* S514 - both ports must have same clock mode */
+#define INVALID_CMND_HDLC_STREAM_MODE 0x4E /* the CHDLC interface command is invalid for HDLC streaming mode */
+#define INVALID_CHDLC_COMMAND 0x4F /* the defined CHDLC interface command is invalid */
+
+/* return codes from command READ_CHDLC_EXCEPTION_CONDITION */
+#define EXCEP_LINK_ACTIVE 0x30 /* the CHDLC link has become active */
+#define EXCEP_LINK_INACTIVE_MODEM 0x31 /* the CHDLC link has become inactive (modem status) */
+#define EXCEP_LINK_INACTIVE_KPALV 0x32 /* the CHDLC link has become inactive (keepalive status) */
+#define EXCEP_IP_ADDRESS_DISCOVERED 0x33 /* the IP address has been discovered */
+#define EXCEP_LOOPBACK_CONDITION 0x34 /* a loopback condition has occurred */
+
+
+/* return code from command CHDLC_SEND_WAIT and CHDLC_SEND_NO_WAIT */
+#define LINK_DISCONNECTED 0x21
+#define NO_TX_BFRS_AVAIL 0x24
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the SET_GLOBAL_CONFIGURATION/READ_GLOBAL_CONFIGURATION commands
+ * --------------------------------------------------------------------------*/
+
+/* the global configuration structure */
+typedef struct {
+ unsigned short adapter_config_options PACKED; /* adapter config options */
+ unsigned short app_IRQ_timeout PACKED; /* application IRQ timeout */
+ unsigned long adapter_operating_frequency PACKED; /* adapter operating frequency */
+} GLOBAL_CONFIGURATION_STRUCT;
+
+/* settings for the 'app_IRQ_timeout' */
+#define MAX_APP_IRQ_TIMEOUT_VALUE 5000 /* the maximum permitted IRQ timeout */
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the READ_GLOBAL_STATISTICS command
+ * --------------------------------------------------------------------------*/
+
+/* the global statistics structure */
+typedef struct {
+ unsigned short app_IRQ_timeout_count PACKED;
+} GLOBAL_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the READ_COMMS_ERROR_STATS command
+ * --------------------------------------------------------------------------*/
+
+/* the communications error statistics structure */
+typedef struct {
+ unsigned short Rx_overrun_err_count PACKED;
+ unsigned short CRC_err_count PACKED; /* receiver CRC error count */
+ unsigned short Rx_abort_count PACKED; /* abort frames recvd count */
+ unsigned short Rx_dis_pri_bfrs_full_count PACKED;/* receiver disabled */
+ unsigned short comms_err_stat_reserved_1 PACKED;/* reserved for later */
+ unsigned short sec_Tx_abort_msd_Tx_int_count PACKED; /* secondary - abort frames transmitted count (missed Tx interrupt) */
+ unsigned short missed_Tx_und_int_count PACKED; /* missed tx underrun interrupt count */
+ unsigned short sec_Tx_abort_count PACKED; /*secondary-abort frames tx count */
+ unsigned short DCD_state_change_count PACKED; /* DCD state change */
+ unsigned short CTS_state_change_count PACKED; /* CTS state change */
+} COMMS_ERROR_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants used for line tracing
+ * --------------------------------------------------------------------------*/
+
+/* the trace configuration structure (SET_TRACE_CONFIGURATION/READ_TRACE_CONFIGURATION commands) */
+typedef struct {
+ unsigned char trace_config PACKED; /* trace configuration */
+ unsigned short trace_deactivation_timer PACKED; /* trace deactivation timer */
+ unsigned long ptr_trace_stat_el_cfg_struct PACKED; /* a pointer to the line trace element configuration structure */
+} LINE_TRACE_CONFIG_STRUCT;
+
+/* 'trace_config' bit settings */
+#define TRACE_INACTIVE 0x00 /* trace is inactive */
+#define TRACE_ACTIVE 0x01 /* trace is active */
+#define TRACE_DELAY_MODE 0x04 /* operate the trace in delay mode */
+#define TRACE_DATA_FRAMES 0x08 /* trace Data frames */
+#define TRACE_SLARP_FRAMES 0x10 /* trace SLARP frames */
+#define TRACE_CDP_FRAMES 0x20 /* trace CDP frames */
+
+/* the line trace status element configuration structure */
+typedef struct {
+ unsigned short number_trace_status_elements PACKED; /* number of line trace elements */
+ unsigned long base_addr_trace_status_elements PACKED; /* base address of the trace element list */
+ unsigned long next_trace_element_to_use PACKED; /* pointer to the next trace element to be used */
+ unsigned long base_addr_trace_buffer PACKED; /* base address of the trace data buffer */
+ unsigned long end_addr_trace_buffer PACKED; /* end address of the trace data buffer */
+} TRACE_STATUS_EL_CFG_STRUCT;
+
+/* the line trace status element structure */
+typedef struct {
+ unsigned char opp_flag PACKED; /* opp flag */
+ unsigned short trace_length PACKED; /* trace length */
+ unsigned char trace_type PACKED; /* trace type */
+ unsigned short trace_time_stamp PACKED; /* time stamp */
+ unsigned short trace_reserved_1 PACKED; /* reserved for later use */
+ unsigned long trace_reserved_2 PACKED; /* reserved for later use */
+ unsigned long ptr_data_bfr PACKED; /* ptr to the trace data buffer */
+} TRACE_STATUS_ELEMENT_STRUCT;
+
+/* "trace_type" bit settings */
+#define TRACE_INCOMING 0x00
+#define TRACE_OUTGOINGING 0x01
+#define TRACE_INCOMING_ABORTED 0x10
+#define TRACE_INCOMING_CRC_ERROR 0x20
+#define TRACE_INCOMING_OVERRUN_ERROR 0x40
+
+
+
+/* the line trace statistics structure */
+typedef struct {
+ unsigned long frames_traced_count PACKED; /* number of frames traced */
+ unsigned long trc_frms_not_recorded_count PACKED; /* number of trace frames discarded */
+} LINE_TRACE_STATS_STRUCT;
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the FT1_MONITOR_STATUS_CTRL command
+ * --------------------------------------------------------------------------*/
+
+#define DISABLE_FT1_STATUS_STATISTICS 0x00 /* disable the FT1 status and statistics monitoring */
+#define ENABLE_READ_FT1_STATUS 0x01 /* read the FT1 operational status */
+#define ENABLE_READ_FT1_OP_STATS 0x02 /* read the FT1 operational statistics */
+#define FLUSH_FT1_OP_STATS 0x04 /* flush the FT1 operational statistics */
+
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the SET_CHDLC_CONFIGURATION command
+ * --------------------------------------------------------------------------*/
+
+/* the CHDLC configuration structure */
+typedef struct {
+ unsigned long baud_rate PACKED; /* the baud rate */
+ unsigned short line_config_options PACKED; /* line configuration options */
+ unsigned short modem_config_options PACKED; /* modem configration options */
+ unsigned short modem_status_timer PACKED; /* timer for monitoring modem status changes */
+ unsigned short CHDLC_API_options PACKED; /* CHDLC API options */
+ unsigned short CHDLC_protocol_options PACKED; /* CHDLC protocol options */
+ unsigned short percent_data_buffer_for_Tx PACKED; /* percentage data buffering used for Tx */
+ unsigned short CHDLC_statistics_options PACKED; /* CHDLC operational statistics options */
+ unsigned short max_CHDLC_data_field_length PACKED; /* the maximum length of the CHDLC Data field */
+ unsigned short transmit_keepalive_timer PACKED; /* the transmit keepalive timer */
+ unsigned short receive_keepalive_timer PACKED; /* the receive keepalive timer */
+ unsigned short keepalive_error_tolerance PACKED; /* the receive keepalive error tolerance */
+ unsigned short SLARP_request_timer PACKED; /* the SLARP request timer */
+ unsigned long IP_address PACKED; /* the IP address */
+ unsigned long IP_netmask PACKED; /* the IP netmask */
+ unsigned long ptr_shared_mem_info_struct PACKED; /* a pointer to the shared memory area information structure */
+ unsigned long ptr_CHDLC_Tx_stat_el_cfg_struct PACKED; /* a pointer to the transmit status element configuration structure */
+ unsigned long ptr_CHDLC_Rx_stat_el_cfg_struct PACKED; /* a pointer to the receive status element configuration structure */
+} CHDLC_CONFIGURATION_STRUCT;
+
+/* settings for the 'line_config_options' */
+#define INTERFACE_LEVEL_V35 0x0000 /* V.35 interface level */
+#define INTERFACE_LEVEL_RS232 0x0001 /* RS-232 interface level */
+
+/* settings for the 'modem_config_options' */
+
+#define DONT_RAISE_DTR_RTS_ON_EN_COMMS 0x0001
+/* don't automatically raise DTR and RTS when performing an
+ ENABLE_CHDLC_COMMUNICATIONS command */
+
+#define DONT_REPORT_CHG_IN_MODEM_STAT 0x0002
+/* don't report changes in modem status to the application */
+
+
+/* bit settings for the 'CHDLC_protocol_options' byte */
+
+#define IGNORE_DCD_FOR_LINK_STAT 0x0001
+/* ignore DCD in determining the CHDLC link status */
+
+#define IGNORE_CTS_FOR_LINK_STAT 0x0002
+/* ignore CTS in determining the CHDLC link status */
+
+#define IGNORE_KPALV_FOR_LINK_STAT 0x0004
+/* ignore keepalive frames in determining the CHDLC link status */
+
+#define HDLC_STREAMING_MODE 0x8000
+
+/* settings for the 'CHDLC_statistics_options' */
+
+#define CHDLC_TX_DATA_BYTE_COUNT_STAT 0x0001
+/* record the number of Data bytes transmitted */
+
+#define CHDLC_RX_DATA_BYTE_COUNT_STAT 0x0002
+/* record the number of Data bytes received */
+
+#define CHDLC_TX_THROUGHPUT_STAT 0x0004
+/* compute the Data frame transmit throughput */
+
+#define CHDLC_RX_THROUGHPUT_STAT 0x0008
+/* compute the Data frame receive throughput */
+
+
+/* permitted minimum and maximum values for setting the CHDLC configuration */
+#define PRI_MAX_BAUD_RATE_S508 2666666 /* PRIMARY - maximum baud rate (S508) */
+#define SEC_MAX_BAUD_RATE_S508 258064 /* SECONDARY - maximum baud rate (S508) */
+#define PRI_MAX_BAUD_RATE_S514 2750000 /* PRIMARY - maximum baud rate (S508) */
+#define SEC_MAX_BAUD_RATE_S514 515625 /* SECONDARY - maximum baud rate (S508) */
+
+#define MIN_MODEM_TIMER 0 /* minimum modem status timer */
+#define MAX_MODEM_TIMER 5000 /* maximum modem status timer */
+
+#define SEC_MAX_NO_DATA_BYTES_IN_FRAME 2048 /* SECONDARY - max length of the CHDLC data field */
+
+#define MIN_Tx_KPALV_TIMER 0 /* minimum transmit keepalive timer */
+#define MAX_Tx_KPALV_TIMER 60000 /* maximum transmit keepalive timer */
+#define DEFAULT_Tx_KPALV_TIMER 10000 /* default transmit keepalive timer */
+
+#define MIN_Rx_KPALV_TIMER 10 /* minimum receive keepalive timer */
+#define MAX_Rx_KPALV_TIMER 60000 /* maximum receive keepalive timer */
+#define DEFAULT_Rx_KPALV_TIMER 10000 /* default receive keepalive timer */
+
+#define MIN_KPALV_ERR_TOL 1 /* min kpalv error tolerance count */
+#define MAX_KPALV_ERR_TOL 20 /* max kpalv error tolerance count */
+#define DEFAULT_KPALV_ERR_TOL 3 /* default value */
+
+#define MIN_SLARP_REQ_TIMER 0 /* min transmit SLARP Request timer */
+#define MAX_SLARP_REQ_TIMER 60000 /* max transmit SLARP Request timer */
+#define DEFAULT_SLARP_REQ_TIMER 0 /* default value -- no SLARP */
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the READ_CHDLC_LINK_STATUS command
+ * --------------------------------------------------------------------------*/
+
+/* the CHDLC status structure */
+typedef struct {
+ unsigned char CHDLC_link_status PACKED; /* CHDLC link status */
+ unsigned char no_Data_frms_for_app PACKED; /* number of Data frames available for the application */
+ unsigned char receiver_status PACKED; /* enabled/disabled */
+ unsigned char SLARP_state PACKED; /* internal SLARP state */
+} CHDLC_LINK_STATUS_STRUCT;
+
+/* settings for the 'CHDLC_link_status' variable */
+#define CHDLC_LINK_INACTIVE 0x00 /* the CHDLC link is inactive */
+#define CHDLC_LINK_ACTIVE 0x01 /* the CHDLC link is active */
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for the READ_CHDLC_OPERATIONAL_STATS command
+ * --------------------------------------------------------------------------*/
+
+/* the CHDLC operational statistics structure */
+typedef struct {
+
+ /* Data frame transmission statistics */
+ unsigned long Data_frames_Tx_count PACKED; /* # of frames transmitted */
+ unsigned long Data_bytes_Tx_count PACKED; /* # of bytes transmitted */
+ unsigned long Data_Tx_throughput PACKED; /* transmit throughput */
+ unsigned long no_ms_for_Data_Tx_thruput_comp PACKED; /* millisecond time used for the Tx throughput computation */
+ unsigned long Tx_Data_discard_lgth_err_count PACKED; /* number of Data frames discarded (length error) */
+ unsigned long reserved_Data_frm_Tx_stat1 PACKED; /* reserved for later */
+ unsigned long reserved_Data_frm_Tx_stat2 PACKED; /* reserved for later */
+ unsigned long reserved_Data_frm_Tx_stat3 PACKED; /* reserved for later */
+
+ /* Data frame reception statistics */
+ unsigned long Data_frames_Rx_count PACKED; /* number of frames received */
+ unsigned long Data_bytes_Rx_count PACKED; /* number of bytes received */
+ unsigned long Data_Rx_throughput PACKED; /* receive throughput */
+ unsigned long no_ms_for_Data_Rx_thruput_comp PACKED; /* millisecond time used for the Rx throughput computation */
+ unsigned long Rx_Data_discard_short_count PACKED; /* received Data frames discarded (too short) */
+ unsigned long Rx_Data_discard_long_count PACKED; /* received Data frames discarded (too long) */
+ unsigned long Rx_Data_discard_inactive_count PACKED; /* received Data frames discarded (link inactive) */
+ unsigned long reserved_Data_frm_Rx_stat1 PACKED; /* reserved for later */
+
+ /* SLARP frame transmission/reception statistics */
+ unsigned long CHDLC_SLARP_REQ_Tx_count PACKED; /* number of SLARP Request frames transmitted */
+ unsigned long CHDLC_SLARP_REQ_Rx_count PACKED; /* number of SLARP Request frames received */
+ unsigned long CHDLC_SLARP_REPLY_Tx_count PACKED; /* number of SLARP Reply frames transmitted */
+ unsigned long CHDLC_SLARP_REPLY_Rx_count PACKED; /* number of SLARP Reply frames received */
+ unsigned long CHDLC_SLARP_KPALV_Tx_count PACKED; /* number of SLARP keepalive frames transmitted */
+ unsigned long CHDLC_SLARP_KPALV_Rx_count PACKED; /* number of SLARP keepalive frames received */
+ unsigned long reserved_SLARP_stat1 PACKED; /* reserved for later */
+ unsigned long reserved_SLARP_stat2 PACKED; /* reserved for later */
+
+ /* CDP frame transmission/reception statistics */
+ unsigned long CHDLC_CDP_Tx_count PACKED; /* number of CDP frames transmitted */
+ unsigned long CHDLC_CDP_Rx_count PACKED; /* number of CDP frames received */
+ unsigned long reserved_CDP_stat1 PACKED; /* reserved for later */
+ unsigned long reserved_CDP_stat2 PACKED; /* reserved for later */
+ unsigned long reserved_CDP_stat3 PACKED; /* reserved for later */
+ unsigned long reserved_CDP_stat4 PACKED; /* reserved for later */
+ unsigned long reserved_CDP_stat5 PACKED; /* reserved for later */
+ unsigned long reserved_CDP_stat6 PACKED; /* reserved for later */
+
+ /* Incomming frames with a format error statistics */
+ unsigned short Rx_frm_incomp_CHDLC_hdr_count PACKED; /* frames received of with incomplete Cisco HDLC header */
+ unsigned short Rx_frms_too_long_count PACKED; /* frames received of excessive length count */
+ unsigned short Rx_invalid_CHDLC_addr_count PACKED; /* frames received with an invalid CHDLC address count */
+ unsigned short Rx_invalid_CHDLC_ctrl_count PACKED; /* frames received with an invalid CHDLC control field count */
+ unsigned short Rx_invalid_CHDLC_type_count PACKED; /* frames received of an invalid CHDLC frame type count */
+ unsigned short Rx_SLARP_invalid_code_count PACKED; /* SLARP frame received with an invalid packet code */
+ unsigned short Rx_SLARP_Reply_bad_IP_addr PACKED; /* SLARP Reply received - bad IP address */
+ unsigned short Rx_SLARP_Reply_bad_netmask PACKED; /* SLARP Reply received - bad netmask */
+ unsigned long reserved_frm_format_err1 PACKED; /* reserved for later */
+ unsigned long reserved_frm_format_err2 PACKED; /* reserved for later */
+ unsigned long reserved_frm_format_err3 PACKED; /* reserved for later */
+ unsigned long reserved_frm_format_err4 PACKED; /* reserved for later */
+
+ /* CHDLC timeout/retry statistics */
+ unsigned short SLARP_Rx_keepalive_TO_count PACKED; /* timeout count for incomming SLARP frames */
+ unsigned short SLARP_Request_TO_count PACKED; /* timeout count for SLARP Request frames */
+ unsigned long To_retry_reserved_stat1 PACKED; /* reserved for later */
+ unsigned long To_retry_reserved_stat2 PACKED; /* reserved for later */
+ unsigned long To_retry_reserved_stat3 PACKED; /* reserved for later */
+
+ /* CHDLC link active/inactive and loopback statistics */
+ unsigned short link_active_count PACKED; /* number of times that the link went active */
+ unsigned short link_inactive_modem_count PACKED; /* number of times that the link went inactive (modem failure) */
+ unsigned short link_inactive_keepalive_count PACKED; /* number of times that the link went inactive (keepalive failure) */
+ unsigned short link_looped_count PACKED; /* link looped count */
+ unsigned long link_status_reserved_stat1 PACKED; /* reserved for later use */
+ unsigned long link_status_reserved_stat2 PACKED; /* reserved for later use */
+
+ /* miscellaneous statistics */
+ unsigned long reserved_misc_stat1 PACKED; /* reserved for later */
+ unsigned long reserved_misc_stat2 PACKED; /* reserved for later */
+ unsigned long reserved_misc_stat3 PACKED; /* reserved for later */
+ unsigned long reserved_misc_stat4 PACKED; /* reserved for later */
+
+} CHDLC_OPERATIONAL_STATS_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for using application interrupts
+ * --------------------------------------------------------------------------*/
+
+/* the structure used for the SET_CHDLC_INTERRUPT_TRIGGERS/READ_CHDLC_INTERRUPT_TRIGGERS command */
+typedef struct {
+ unsigned char CHDLC_interrupt_triggers PACKED; /* CHDLC interrupt trigger configuration */
+ unsigned char IRQ PACKED; /* IRQ to be used */
+ unsigned short interrupt_timer PACKED; /* interrupt timer */
+ unsigned short misc_interrupt_bits PACKED; /* miscellaneous bits */
+} CHDLC_INT_TRIGGERS_STRUCT;
+
+/* 'CHDLC_interrupt_triggers' bit settings */
+#define APP_INT_ON_RX_FRAME 0x01 /* interrupt on Data frame reception */
+#define APP_INT_ON_TX_FRAME 0x02 /* interrupt when an Data frame may be transmitted */
+#define APP_INT_ON_COMMAND_COMPLETE 0x04 /* interrupt when an interface command is complete */
+#define APP_INT_ON_TIMER 0x08 /* interrupt on a defined millisecond timeout */
+#define APP_INT_ON_GLOBAL_EXCEP_COND 0x10 /* interrupt on a global exception condition */
+#define APP_INT_ON_CHDLC_EXCEP_COND 0x20 /* interrupt on an CHDLC exception condition */
+#define APP_INT_ON_TRACE_DATA_AVAIL 0x80 /* interrupt when trace data is available */
+
+/* interrupt types indicated at 'interrupt_type' byte of the INTERRUPT_INFORMATION_STRUCT */
+#define NO_APP_INTS_PEND 0x00 /* no interrups are pending */
+#define RX_APP_INT_PEND 0x01 /* a receive interrupt is pending */
+#define TX_APP_INT_PEND 0x02 /* a transmit interrupt is pending */
+#define COMMAND_COMPLETE_APP_INT_PEND 0x04 /* a 'command complete' interrupt is pending */
+#define TIMER_APP_INT_PEND 0x08 /* a timer interrupt is pending */
+#define GLOBAL_EXCEP_COND_APP_INT_PEND 0x10 /* a global exception condition interrupt is pending */
+#define CHDLC_EXCEP_COND_APP_INT_PEND 0x20 /* an CHDLC exception condition interrupt is pending */
+#define TRACE_DATA_AVAIL_APP_INT_PEND 0x80 /* a trace data available interrupt is pending */
+
+
+/* modem status changes */
+#define DCD_HIGH 0x08
+#define CTS_HIGH 0x20
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for Data frame transmission
+ * --------------------------------------------------------------------------*/
+
+/* the Data frame transmit status element configuration structure */
+typedef struct {
+ unsigned short number_Tx_status_elements PACKED; /* number of transmit status elements */
+ unsigned long base_addr_Tx_status_elements PACKED; /* base address of the transmit element list */
+ unsigned long next_Tx_status_element_to_use PACKED; /* pointer to the next transmit element to be used */
+} CHDLC_TX_STATUS_EL_CFG_STRUCT;
+
+/* the Data frame transmit status element structure */
+typedef struct {
+ unsigned char opp_flag PACKED; /* opp flag */
+ unsigned short frame_length PACKED; /* length of the frame to be transmitted */
+ unsigned char reserved_1 PACKED; /* reserved for internal use */
+ unsigned long reserved_2 PACKED; /* reserved for internal use */
+ unsigned long reserved_3 PACKED; /* reserved for internal use */
+ unsigned long ptr_data_bfr PACKED; /* pointer to the data area */
+} CHDLC_DATA_TX_STATUS_EL_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants for Data frame reception
+ * --------------------------------------------------------------------------*/
+
+/* the Data frame receive status element configuration structure */
+typedef struct {
+ unsigned short number_Rx_status_elements PACKED; /* number of receive status elements */
+ unsigned long base_addr_Rx_status_elements PACKED; /* base address of the receive element list */
+ unsigned long next_Rx_status_element_to_use PACKED; /* pointer to the next receive element to be used */
+ unsigned long base_addr_Rx_buffer PACKED; /* base address of the receive data buffer */
+ unsigned long end_addr_Rx_buffer PACKED; /* end address of the receive data buffer */
+} CHDLC_RX_STATUS_EL_CFG_STRUCT;
+
+/* the Data frame receive status element structure */
+typedef struct {
+ unsigned char opp_flag PACKED; /* opp flag */
+ unsigned short frame_length PACKED; /* length of the received frame */
+ unsigned char error_flag PACKED; /* frame errors (HDLC_STREAMING_MODE)*/
+ unsigned short time_stamp PACKED; /* receive time stamp (HDLC_STREAMING_MODE) */
+ unsigned long reserved_1 PACKED; /* reserved for internal use */
+ unsigned short reserved_2 PACKED; /* reserved for internal use */
+ unsigned long ptr_data_bfr PACKED; /* pointer to the data area */
+} CHDLC_DATA_RX_STATUS_EL_STRUCT;
+
+
+
+/* ----------------------------------------------------------------------------
+ * Constants defining the shared memory information area
+ * --------------------------------------------------------------------------*/
+
+/* the global information structure */
+typedef struct {
+ unsigned char global_status PACKED; /* global status */
+ unsigned char modem_status PACKED; /* current modem status */
+ unsigned char global_excep_conditions PACKED; /* global exception conditions */
+ unsigned char glob_info_reserved[5] PACKED; /* reserved */
+ unsigned char codename[4] PACKED; /* Firmware name */
+ unsigned char codeversion[4] PACKED; /* Firmware version */
+} GLOBAL_INFORMATION_STRUCT;
+
+/* the CHDLC information structure */
+typedef struct {
+ unsigned char CHDLC_status PACKED; /* CHDLC status */
+ unsigned char CHDLC_excep_conditions PACKED; /* CHDLC exception conditions */
+ unsigned char CHDLC_info_reserved[14] PACKED; /* reserved */
+} CHDLC_INFORMATION_STRUCT;
+
+/* the interrupt information structure */
+typedef struct {
+ unsigned char interrupt_type PACKED; /* type of interrupt triggered */
+ unsigned char interrupt_permission PACKED; /* interrupt permission mask */
+ unsigned char int_info_reserved[14] PACKED; /* reserved */
+} INTERRUPT_INFORMATION_STRUCT;
+
+/* the S508/FT1 information structure */
+typedef struct {
+ unsigned char parallel_port_A_input PACKED; /* input - parallel port A */
+ unsigned char parallel_port_B_input PACKED; /* input - parallel port B */
+ unsigned char FT1_info_reserved[14] PACKED; /* reserved */
+} FT1_INFORMATION_STRUCT;
+
+/* the shared memory area information structure */
+typedef struct {
+ GLOBAL_INFORMATION_STRUCT global_info_struct PACKED; /* the global information structure */
+ CHDLC_INFORMATION_STRUCT CHDLC_info_struct PACKED; /* the CHDLC information structure */
+ INTERRUPT_INFORMATION_STRUCT interrupt_info_struct PACKED; /* the interrupt information structure */
+ FT1_INFORMATION_STRUCT FT1_info_struct PACKED; /* the S508/FT1 information structure */
+} SHARED_MEMORY_INFO_STRUCT;
+
+/* ----------------------------------------------------------------------------
+ * UDP Management constants and structures
+ * --------------------------------------------------------------------------*/
+
+/* The embedded control block for UDP mgmt
+ This is essentially a mailbox structure, without the large data field */
+
+typedef struct {
+ unsigned char opp_flag PACKED; /* the opp flag */
+ unsigned char command PACKED; /* the user command */
+ unsigned short buffer_length PACKED; /* the data length */
+ unsigned char return_code PACKED; /* the return code */
+ unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED; /* reserved for later */
+} cblock_t;
+
+
+/* UDP management packet layout (data area of ip packet) */
+/*
+typedef struct {
+ unsigned char signature[8] PACKED;
+ unsigned char request_reply PACKED;
+ unsigned char id PACKED;
+ unsigned char reserved[6] PACKED;
+ cblock_t cblock PACKED;
+ unsigned char num_frames PACKED;
+ unsigned char ismoredata PACKED;
+ unsigned char data[SIZEOF_MB_DATA_BFR] PACKED;
+} udp_management_packet_t;
+
+*/
+
+typedef struct {
+ unsigned char num_frames PACKED;
+ unsigned char ismoredata PACKED;
+} trace_info_t;
+
+typedef struct {
+ ip_pkt_t ip_pkt PACKED;
+ udp_pkt_t udp_pkt PACKED;
+ wp_mgmt_t wp_mgmt PACKED;
+ cblock_t cblock PACKED;
+ trace_info_t trace_info PACKED;
+ unsigned char data[SIZEOF_MB_DATA_BFR] PACKED;
+} chdlc_udp_pkt_t;
+
+typedef struct ft1_exec_cmd{
+ unsigned char command PACKED; /* the user command */
+ unsigned short buffer_length PACKED; /* the data length */
+ unsigned char return_code PACKED; /* the return code */
+ unsigned char MB_reserved[NUMBER_MB_RESERVED_BYTES] PACKED;
+} ft1_exec_cmd_t;
+
+typedef struct {
+ unsigned char opp_flag PACKED;
+ ft1_exec_cmd_t cmd PACKED;
+ unsigned char data[SIZEOF_MB_DATA_BFR] PACKED;
+} ft1_exec_t;
+
+#define UDPMGMT_SIGNATURE "CTPIPEAB"
+
+
+/* UDP/IP packet (for UDP management) layout */
+/*
+typedef struct {
+ unsigned char reserved[2] PACKED;
+ unsigned short ip_length PACKED;
+ unsigned char reserved2[4] PACKED;
+ unsigned char ip_ttl PACKED;
+ unsigned char ip_protocol PACKED;
+ unsigned short ip_checksum PACKED;
+ unsigned long ip_src_address PACKED;
+ unsigned long ip_dst_address PACKED;
+ unsigned short udp_src_port PACKED;
+ unsigned short udp_dst_port PACKED;
+ unsigned short udp_length PACKED;
+ unsigned short udp_checksum PACKED;
+ udp_management_packet_t um_packet PACKED;
+} ip_packet_t;
+*/
+
+/* valid ip_protocol for UDP management */
+#define UDPMGMT_UDP_PROTOCOL 0x11
+
+
+typedef struct {
+ unsigned char status PACKED;
+ unsigned char data_avail PACKED;
+ unsigned short real_length PACKED;
+ unsigned short time_stamp PACKED;
+ unsigned char data[1] PACKED;
+} trace_pkt_t;
+
+typedef struct {
+ unsigned char error_flag PACKED;
+ unsigned short time_stamp PACKED;
+ unsigned char reserved[13] PACKED;
+} api_rx_hdr_t;
+
+typedef struct {
+ api_rx_hdr_t api_rx_hdr PACKED;
+ void * data PACKED;
+} api_rx_element_t;
+
+typedef struct {
+ unsigned char attr PACKED;
+ unsigned char reserved[15] PACKED;
+} api_tx_hdr_t;
+
+typedef struct {
+ api_tx_hdr_t api_tx_hdr PACKED;
+ void * data PACKED;
+} api_tx_element_t;
+
+/* ----------------------------------------------------------------------------
+ * Constants for the SET_FT1_CONFIGURATION/READ_FT1_CONFIGURATION command
+ * --------------------------------------------------------------------------*/
+
+/* the FT1 configuration structure */
+typedef struct {
+ unsigned short framing_mode;
+ unsigned short encoding_mode;
+ unsigned short line_build_out;
+ unsigned short channel_base;
+ unsigned short baud_rate_kbps; /* the baud rate (in kbps) */
+ unsigned short clock_mode;
+} ft1_config_t;
+
+/* settings for the 'framing_mode' */
+#define ESF_FRAMING 0x00 /* ESF framing */
+#define D4_FRAMING 0x01 /* D4 framing */
+
+/* settings for the 'encoding_mode' */
+#define B8ZS_ENCODING 0x00 /* B8ZS encoding */
+#define AMI_ENCODING 0x01 /* AMI encoding */
+
+/* settings for the 'line_build_out' */
+#define LN_BLD_CSU_0dB_DSX1_0_to_133 0x00 /* set build out to CSU (0db) or DSX-1 (0-133ft) */
+#define LN_BLD_DSX1_133_to_266 0x01 /* set build out DSX-1 (133-266ft) */
+#define LN_BLD_DSX1_266_to_399 0x02 /* set build out DSX-1 (266-399ft) */
+#define LN_BLD_DSX1_399_to_533 0x03 /* set build out DSX-1 (399-533ft) */
+#define LN_BLD_DSX1_533_to_655 0x04 /* set build out DSX-1 (533-655ft) */
+#define LN_BLD_CSU_NEG_7dB 0x05 /* set build out to CSU (-7.5db) */
+#define LN_BLD_CSU_NEG_15dB 0x06 /* set build out to CSU (-15db) */
+#define LN_BLD_CSU_NEG_22dB 0x07 /* set build out to CSU (-22.5db) */
+
+/* settings for the 'channel_base' */
+#define MIN_CHANNEL_BASE_VALUE 1 /* the minimum permitted channel base value */
+#define MAX_CHANNEL_BASE_VALUE 24 /* the maximum permitted channel base value */
+
+/* settings for the 'baud_rate_kbps' */
+#define MIN_BAUD_RATE_KBPS 0 /* the minimum permitted baud rate (kbps) */
+#define MAX_BAUD_RATE_KBPS 1536 /* the maximum permitted baud rate (kbps) */
+#define BAUD_RATE_FT1_AUTO_CONFIG 0xFFFF /* the baud rate used to trigger an automatic FT1 configuration */
+
+/* settings for the 'clock_mode' */
+#define CLOCK_MODE_NORMAL 0x00 /* clock mode set to normal (slave) */
+#define CLOCK_MODE_MASTER 0x01 /* clock mode set to master */
+
+
+#define BAUD_RATE_FT1_AUTO_CONFIG 0xFFFF
+#define AUTO_FT1_CONFIG_NOT_COMPLETE 0x08
+#define AUTO_FT1_CFG_FAIL_OP_MODE 0x0C
+#define AUTO_FT1_CFG_FAIL_INVALID_LINE 0x0D
+
+
+#ifdef _MSC_
+# pragma pack()
+#endif
+#endif /* _SDLA_CHDLC_H */
diff --git a/pfinet/linux-src/include/linux/sdla_fr.h b/pfinet/linux-src/include/linux/sdla_fr.h
new file mode 100644
index 00000000..f5aef96a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdla_fr.h
@@ -0,0 +1,638 @@
+/*****************************************************************************
+* sdla_fr.h Sangoma frame relay firmware API definitions.
+*
+* Author: Gideon Hack
+* Nenad Corbic <ncorbic@sangoma.com>
+*
+* Copyright: (c) 1995-1999 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Oct 04, 1999 Gideon Hack Updated API structures
+* Jun 02, 1999 Gideon Hack Modifications for S514 support
+* Oct 12, 1997 Jaspreet Singh Added FR_READ_DLCI_IB_MAPPING
+* Jul 21, 1997 Jaspreet Singh Changed FRRES_TOO_LONG and FRRES_TOO_MANY to
+* 0x05 and 0x06 respectively.
+* Dec 23, 1996 Gene Kozin v2.0
+* Apr 29, 1996 Gene Kozin v1.0 (merged version S502 & S508 definitions).
+* Sep 26, 1995 Gene Kozin Initial version.
+*****************************************************************************/
+#ifndef _SDLA_FR_H
+#define _SDLA_FR_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.
+ *
+ * Compiler Platform
+ * -------- --------
+ * GNU C Linux
+ */
+
+#ifndef PACKED
+# define PACKED __attribute__((packed))
+#endif /* PACKED */
+
+/* Adapter memory layout */
+#define FR_MB_VECTOR 0xE000 /* mailbox window vector */
+#define FR502_RX_VECTOR 0xA000 /* S502 direct receive window vector */
+#define FR502_MBOX_OFFS 0xF60 /* S502 mailbox offset */
+#define FR508_MBOX_OFFS 0 /* S508 mailbox offset */
+#define FR502_FLAG_OFFS 0x1FF0 /* S502 status flags offset */
+#define FR508_FLAG_OFFS 0x1000 /* S508 status flags offset */
+#define FR502_RXMB_OFFS 0x900 /* S502 direct receive mailbox offset */
+#define FR508_TXBC_OFFS 0x1100 /* S508 Tx buffer info offset */
+#define FR508_RXBC_OFFS 0x1120 /* S508 Rx buffer info offset */
+
+/* Important constants */
+#define FR502_MAX_DATA 4096 /* maximum data buffer length */
+#define FR508_MAX_DATA 4080 /* maximum data buffer length */
+#define MIN_LGTH_FR_DATA_CFG 300 /* min Information frame length
+(for configuration purposes) */
+#define FR_MAX_NO_DATA_BYTES_IN_FRAME 15354 /* max Information frame length */
+
+#define HIGHEST_VALID_DLCI 991
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * Frame relay command block.
+ */
+typedef struct fr_cmd
+{
+ unsigned char command PACKED; /* command code */
+ unsigned short length PACKED; /* length of data buffer */
+ unsigned char result PACKED; /* return code */
+ unsigned short dlci PACKED; /* DLCI number */
+ unsigned char attr PACKED; /* FECN, BECN, DE and C/R bits */
+ unsigned short rxlost1 PACKED; /* frames discarded at int. level */
+ unsigned long rxlost2 PACKED; /* frames discarded at app. level */
+ unsigned char rsrv[2] PACKED; /* reserved for future use */
+} fr_cmd_t;
+
+/* 'command' field defines */
+#define FR_WRITE 0x01
+#define FR_READ 0x02
+#define FR_ISSUE_IS_FRAME 0x03
+#define FR_SET_CONFIG 0x10
+#define FR_READ_CONFIG 0x11
+#define FR_COMM_DISABLE 0x12
+#define FR_COMM_ENABLE 0x13
+#define FR_READ_STATUS 0x14
+#define FR_READ_STATISTICS 0x15
+#define FR_FLUSH_STATISTICS 0x16
+#define FR_LIST_ACTIVE_DLCI 0x17
+#define FR_FLUSH_DATA_BUFFERS 0x18
+#define FR_READ_ADD_DLC_STATS 0x19
+#define FR_ADD_DLCI 0x20
+#define FR_DELETE_DLCI 0x21
+#define FR_ACTIVATE_DLCI 0x22
+#define FR_DEACTIVATE_DLCI 0x22
+#define FR_READ_MODEM_STATUS 0x30
+#define FR_SET_MODEM_STATUS 0x31
+#define FR_READ_ERROR_STATS 0x32
+#define FR_FLUSH_ERROR_STATS 0x33
+#define FR_READ_DLCI_IB_MAPPING 0x34
+#define FR_READ_CODE_VERSION 0x40
+#define FR_SET_INTR_MODE 0x50
+#define FR_READ_INTR_MODE 0x51
+#define FR_SET_TRACE_CONFIG 0x60
+#define FR_FT1_STATUS_CTRL 0x80
+#define FR_SET_FT1_MODE 0x81
+
+/* Special UDP drivers management commands */
+#define FPIPE_ENABLE_TRACING 0x41
+#define FPIPE_DISABLE_TRACING 0x42
+#define FPIPE_GET_TRACE_INFO 0x43
+#define FPIPE_FT1_READ_STATUS 0x44
+#define FPIPE_DRIVER_STAT_IFSEND 0x45
+#define FPIPE_DRIVER_STAT_INTR 0x46
+#define FPIPE_DRIVER_STAT_GEN 0x47
+#define FPIPE_FLUSH_DRIVER_STATS 0x48
+#define FPIPE_ROUTER_UP_TIME 0x49
+
+/* 'result' field defines */
+#define FRRES_OK 0x00 /* command executed successfully */
+#define FRRES_DISABLED 0x01 /* communications not enabled */
+#define FRRES_INOPERATIVE 0x02 /* channel inoperative */
+#define FRRES_DLCI_INACTIVE 0x03 /* DLCI is inactive */
+#define FRRES_DLCI_INVALID 0x04 /* DLCI is not configured */
+#define FRRES_TOO_LONG 0x05
+#define FRRES_TOO_MANY 0x06
+#define FRRES_CIR_OVERFLOW 0x07 /* Tx throughput has exceeded CIR */
+#define FRRES_BUFFER_OVERFLOW 0x08
+#define FRRES_MODEM_FAILURE 0x10 /* DCD and/or CTS dropped */
+#define FRRES_CHANNEL_DOWN 0x11 /* channel became inoperative */
+#define FRRES_CHANNEL_UP 0x12 /* channel became operative */
+#define FRRES_DLCI_CHANGE 0x13 /* DLCI status (or number) changed */
+#define FRRES_DLCI_MISMATCH 0x14
+#define FRRES_INVALID_CMD 0x1F /* invalid command */
+
+/* 'attr' field defines */
+#define FRATTR_
+
+/*----------------------------------------------------------------------------
+ * Frame relay mailbox.
+ * This structure is located at offset FR50?_MBOX_OFFS into FR_MB_VECTOR.
+ * For S502 it is also located at offset FR502_RXMB_OFFS into
+ * FR502_RX_VECTOR.
+ */
+typedef struct fr_mbox
+{
+ unsigned char opflag PACKED; /* 00h: execution flag */
+ fr_cmd_t cmd PACKED; /* 01h: command block */
+ unsigned char data[1] PACKED; /* 10h: variable length data buffer */
+} fr_mbox_t;
+
+/*----------------------------------------------------------------------------
+ * S502 frame relay status flags.
+ * This structure is located at offset FR502_FLAG_OFFS into FR_MB_VECTOR.
+ */
+typedef struct fr502_flags
+{
+ unsigned char rsrv1[1] PACKED; /* 00h: */
+ unsigned char tx_ready PACKED; /* 01h: Tx buffer available */
+ unsigned char rx_ready PACKED; /* 02h: Rx frame available */
+ unsigned char event PACKED; /* 03h: asynchronous event */
+ unsigned char mstatus PACKED; /* 04h: modem status */
+ unsigned char rsrv2[8] PACKED; /* 05h: */
+ unsigned char iflag PACKED; /* 0Dh: interrupt flag */
+ unsigned char imask PACKED; /* 0Eh: interrupt mask */
+} fr502_flags_t;
+
+/*----------------------------------------------------------------------------
+ * S508 frame relay status flags.
+ * This structure is located at offset FR508_FLAG_OFFS into FR_MB_VECTOR.
+ */
+typedef struct fr508_flags
+{
+ unsigned char rsrv1[3] PACKED; /* 00h: reserved */
+ unsigned char event PACKED; /* 03h: asynchronous event */
+ unsigned char mstatus PACKED; /* 04h: modem status */
+ unsigned char rsrv2[11] PACKED; /* 05h: reserved */
+ unsigned char iflag PACKED; /* 10h: interrupt flag */
+ unsigned char imask PACKED; /* 11h: interrupt mask */
+ unsigned long tse_offs PACKED; /* 12h: Tx status element */
+ unsigned short dlci PACKED; /* 16h: DLCI NUMBER */
+} fr508_flags_t;
+
+/* 'event' field defines */
+#define FR_EVENT_STATUS 0x01 /* channel status change */
+#define FR_EVENT_DLC_STATUS 0x02 /* DLC status change */
+#define FR_EVENT_BAD_DLCI 0x04 /* FSR included wrong DLCI */
+#define FR_EVENT_LINK_DOWN 0x40 /* DCD or CTS low */
+
+/* 'mstatus' field defines */
+#define FR_MDM_DCD 0x08 /* mdm_status: DCD */
+#define FR_MDM_CTS 0x20 /* mdm_status: CTS */
+
+/* 'iflag' & 'imask' fields defines */
+#define FR_INTR_RXRDY 0x01 /* Rx ready */
+#define FR_INTR_TXRDY 0x02 /* Tx ready */
+#define FR_INTR_MODEM 0x04 /* modem status change (DCD, CTS) */
+#define FR_INTR_READY 0x08 /* interface command completed */
+#define FR_INTR_DLC 0x10 /* DLC status change */
+#define FR_INTR_TIMER 0x20 /* millisecond timer */
+#define FR_INTR_TX_MULT_DLCIs 0x80 /* Tx interrupt on multiple DLCIs */
+
+
+/*----------------------------------------------------------------------------
+ * Receive Buffer Configuration Info. S508 only!
+ * This structure is located at offset FR508_RXBC_OFFS into FR_MB_VECTOR.
+ */
+typedef struct fr_buf_info
+{
+ unsigned short rse_num PACKED; /* 00h: number of status elements */
+ unsigned long rse_base PACKED; /* 02h: receive status array base */
+ unsigned long rse_next PACKED; /* 06h: next status element */
+ unsigned long buf_base PACKED; /* 0Ah: rotational buffer base */
+ unsigned short reserved PACKED; /* 0Eh: */
+ unsigned long buf_top PACKED; /* 10h: rotational buffer top */
+} fr_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * Buffer Status Element. S508 only!
+ * Array of structures of this type is located at offset defined by the
+ * 'rse_base' field of the frBufInfo_t structure into absolute adapter
+ * memory address space.
+ */
+typedef struct fr_rx_buf_ctl
+{
+ unsigned char flag PACKED; /* 00h: ready flag */
+ unsigned short length PACKED; /* 01h: frame length */
+ unsigned short dlci PACKED; /* 03h: DLCI */
+ unsigned char attr PACKED; /* 05h: FECN/BECN/DE/CR */
+ unsigned short tmstamp PACKED; /* 06h: time stamp */
+ unsigned short rsrv[2] PACKED; /* 08h: */
+ unsigned long offset PACKED; /* 0Ch: buffer absolute address */
+} fr_rx_buf_ctl_t;
+
+typedef struct fr_tx_buf_ctl
+{
+ unsigned char flag PACKED; /* 00h: ready flag */
+ unsigned short rsrv0[2] PACKED; /* 01h: */
+ unsigned short length PACKED; /* 05h: frame length */
+ unsigned short dlci PACKED; /* 07h: DLCI */
+ unsigned char attr PACKED; /* 09h: FECN/BECN/DE/CR */
+ unsigned short rsrv1 PACKED; /* 0Ah: */
+ unsigned long offset PACKED; /* 0Ch: buffer absolute address */
+} fr_tx_buf_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * Global Configuration Block. Passed to FR_SET_CONFIG command when dlci == 0.
+ */
+typedef struct fr_conf
+{
+ unsigned short station PACKED; /* 00h: CPE/Node */
+ unsigned short options PACKED; /* 02h: configuration options */
+ unsigned short kbps PACKED; /* 04h: baud rate in kbps */
+ unsigned short port PACKED; /* 06h: RS-232/V.35 */
+ unsigned short mtu PACKED; /* 08h: max. transmit length */
+ unsigned short t391 PACKED; /* 0Ah: */
+ unsigned short t392 PACKED; /* 0Ch: */
+ unsigned short n391 PACKED; /* 0Eh: */
+ unsigned short n392 PACKED; /* 10h: */
+ unsigned short n393 PACKED; /* 12h: */
+ unsigned short cir_fwd PACKED; /* 14h: */
+ unsigned short bc_fwd PACKED; /* 16h: */
+ unsigned short be_fwd PACKED; /* 18h: */
+ unsigned short cir_bwd PACKED; /* 1Ah: */
+ unsigned short bc_bwd PACKED; /* 1Ch: */
+ unsigned short be_bwd PACKED; /* 1Eh: */
+ unsigned short dlci[0] PACKED; /* 20h: */
+} fr_conf_t;
+
+/* 'station_type' defines */
+#define FRCFG_STATION_CPE 0
+#define FRCFG_STATION_NODE 1
+
+/* 'conf_flags' defines */
+#define FRCFG_IGNORE_TX_CIR 0x0001
+#define FRCFG_IGNORE_RX_CIR 0x0002
+#define FRCFG_DONT_RETRANSMIT 0x0004
+#define FRCFG_IGNORE_CBS 0x0008
+#define FRCFG_THROUGHPUT 0x0010 /* enable throughput calculation */
+#define FRCFG_DIRECT_RX 0x0080 /* enable direct receive buffer */
+#define FRCFG_AUTO_CONFIG 0x8000 /* enable auto DLCI configuration */
+
+/* 'baud_rate' defines */
+#define FRCFG_BAUD_1200 12
+#define FRCFG_BAUD_2400 24
+#define FRCFG_BAUD_4800 48
+#define FRCFG_BAUD_9600 96
+#define FRCFG_BAUD_19200 19
+#define FRCFG_BAUD_38400 38
+#define FRCFG_BAUD_56000 56
+#define FRCFG_BAUD_64000 64
+#define FRCFG_BAUD_128000 128
+
+/* 'port_mode' defines */
+#define FRCFG_MODE_EXT_CLK 0x0000
+#define FRCFG_MODE_INT_CLK 0x0001
+#define FRCFG_MODE_V35 0x0000 /* S508 only */
+#define FRCFG_MODE_RS232 0x0002 /* S508 only */
+
+/* defines for line tracing */
+
+/* the line trace status element presented by the frame relay code */
+typedef struct {
+ unsigned char flag PACKED; /* ready flag */
+ unsigned short length PACKED; /* trace length */
+ unsigned char rsrv0[2] PACKED; /* reserved */
+ unsigned char attr PACKED; /* trace attributes */
+ unsigned short tmstamp PACKED; /* time stamp */
+ unsigned char rsrv1[4] PACKED; /* reserved */
+ unsigned long offset PACKED; /* buffer absolute address */
+} fr_trc_el_t;
+
+typedef struct {
+ unsigned char status PACKED; /* status flag */
+ unsigned char data_passed PACKED; /* 0 if no data passed, 1 if */
+ /* data passed */
+ unsigned short length PACKED; /* frame length */
+ unsigned short tmstamp PACKED; /* time stamp */
+} fpipemon_trc_hdr_t;
+
+typedef struct {
+ fpipemon_trc_hdr_t fpipemon_trc_hdr PACKED;
+ unsigned char data[FR_MAX_NO_DATA_BYTES_IN_FRAME] PACKED;
+} fpipemon_trc_t;
+
+/* bit settings for the 'status' byte - note that bits 1, 2 and 3 are used */
+/* for returning the number of frames being passed to fpipemon */
+#define TRC_OUTGOING_FRM 0x01
+#define TRC_ABORT_ERROR 0x10
+#define TRC_CRC_ERROR 0x20
+#define TRC_OVERRUN_ERROR 0x40
+#define MORE_TRC_DATA 0x80
+
+#define MAX_FRMS_TRACED 0x07
+
+#define NO_TRC_ELEMENTS_OFF 0x9000
+#define BASE_TRC_ELEMENTS_OFF 0x9002
+#define TRC_ACTIVE 0x01
+#define FLUSH_TRC_BUFFERS 0x02
+#define FLUSH_TRC_STATISTICS 0x04
+#define TRC_SIGNALLING_FRMS 0x10
+#define TRC_INFO_FRMS 0x20
+#define ACTIVATE_TRC (TRC_ACTIVE | TRC_SIGNALLING_FRMS | TRC_INFO_FRMS)
+#define RESET_TRC (FLUSH_TRC_BUFFERS | FLUSH_TRC_STATISTICS)
+
+/*----------------------------------------------------------------------------
+ * Channel configuration.
+ * This structure is passed to the FR_SET_CONFIG command when dlci != 0.
+ */
+typedef struct fr_dlc_conf
+{
+ unsigned short conf_flags PACKED; /* 00h: configuration bits */
+ unsigned short cir_fwd PACKED; /* 02h: */
+ unsigned short bc_fwd PACKED; /* 04h: */
+ unsigned short be_fwd PACKED; /* 06h: */
+ unsigned short cir_bwd PACKED; /* 08h: */
+ unsigned short bc_bwd PACKED; /* 0Ah: */
+ unsigned short be_bwd PACKED; /* 0Ch: */
+} fr_dlc_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S502 interrupt mode control block.
+ * This structure is passed to the FR_SET_INTR_FLAGS and returned by the
+ * FR_READ_INTR_FLAGS commands.
+ */
+typedef struct fr502_intr_ctl
+{
+ unsigned char mode PACKED; /* 00h: interrupt enable flags */
+ unsigned short tx_len PACKED; /* 01h: required Tx buffer size */
+} fr502_intr_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * S508 interrupt mode control block.
+ * This structure is passed to the FR_SET_INTR_FLAGS and returned by the
+ * FR_READ_INTR_FLAGS commands.
+ */
+typedef struct fr508_intr_ctl
+{
+ unsigned char mode PACKED; /* 00h: interrupt enable flags */
+ unsigned short tx_len PACKED; /* 01h: required Tx buffer size */
+ unsigned char irq PACKED; /* 03h: IRQ level to activate */
+ unsigned char flags PACKED; /* 04h: ?? */
+ unsigned short timeout PACKED; /* 05h: ms, for timer interrupt */
+} fr508_intr_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * Channel status.
+ * This structure is returned by the FR_READ_STATUS command.
+ */
+typedef struct fr_dlc_Status
+{
+ unsigned char status PACKED; /* 00h: link/DLCI status */
+ struct
+ {
+ unsigned short dlci PACKED; /* 01h: DLCI number */
+ unsigned char status PACKED; /* 03h: DLCI status */
+ } circuit[1] PACKED;
+} fr_dlc_status_t;
+
+/* 'status' defines */
+#define FR_LINK_INOPER 0x00 /* for global status (DLCI == 0) */
+#define FR_LINK_OPER 0x01
+#define FR_DLCI_DELETED 0x01 /* for circuit status (DLCI != 0) */
+#define FR_DLCI_ACTIVE 0x02
+#define FR_DLCI_WAITING 0x04
+#define FR_DLCI_NEW 0x08
+#define FR_DLCI_REPORT 0x40
+
+/*----------------------------------------------------------------------------
+ * Global Statistics Block.
+ * This structure is returned by the FR_READ_STATISTICS command when
+ * dcli == 0.
+ */
+typedef struct fr_link_stat
+{
+ unsigned short rx_too_long PACKED; /* 00h: */
+ unsigned short rx_dropped PACKED; /* 02h: */
+ unsigned short rx_dropped2 PACKED; /* 04h: */
+ unsigned short rx_bad_dlci PACKED; /* 06h: */
+ unsigned short rx_bad_format PACKED; /* 08h: */
+ unsigned short retransmitted PACKED; /* 0Ah: */
+ unsigned short cpe_tx_FSE PACKED; /* 0Ch: */
+ unsigned short cpe_tx_LIV PACKED; /* 0Eh: */
+ unsigned short cpe_rx_FSR PACKED; /* 10h: */
+ unsigned short cpe_rx_LIV PACKED; /* 12h: */
+ unsigned short node_rx_FSE PACKED; /* 14h: */
+ unsigned short node_rx_LIV PACKED; /* 16h: */
+ unsigned short node_tx_FSR PACKED; /* 18h: */
+ unsigned short node_tx_LIV PACKED; /* 1Ah: */
+ unsigned short rx_ISF_err PACKED; /* 1Ch: */
+ unsigned short rx_unsolicited PACKED; /* 1Eh: */
+ unsigned short rx_SSN_err PACKED; /* 20h: */
+ unsigned short rx_RSN_err PACKED; /* 22h: */
+ unsigned short T391_timeouts PACKED; /* 24h: */
+ unsigned short T392_timeouts PACKED; /* 26h: */
+ unsigned short N392_reached PACKED; /* 28h: */
+ unsigned short cpe_SSN_RSN PACKED; /* 2Ah: */
+ unsigned short current_SSN PACKED; /* 2Ch: */
+ unsigned short current_RSN PACKED; /* 2Eh: */
+ unsigned short curreny_T391 PACKED; /* 30h: */
+ unsigned short current_T392 PACKED; /* 32h: */
+ unsigned short current_N392 PACKED; /* 34h: */
+ unsigned short current_N393 PACKED; /* 36h: */
+} fr_link_stat_t;
+
+/*----------------------------------------------------------------------------
+ * DLCI statistics.
+ * This structure is returned by the FR_READ_STATISTICS command when
+ * dlci != 0.
+ */
+typedef struct fr_dlci_stat
+{
+ unsigned long tx_frames PACKED; /* 00h: */
+ unsigned long tx_bytes PACKED; /* 04h: */
+ unsigned long rx_frames PACKED; /* 08h: */
+ unsigned long rx_bytes PACKED; /* 0Ch: */
+ unsigned long rx_dropped PACKED; /* 10h: */
+ unsigned long rx_inactive PACKED; /* 14h: */
+ unsigned long rx_exceed_CIR PACKED; /* 18h: */
+ unsigned long rx_DE_set PACKED; /* 1Ch: */
+ unsigned long tx_throughput PACKED; /* 20h: */
+ unsigned long tx_calc_timer PACKED; /* 24h: */
+ unsigned long rx_throughput PACKED; /* 28h: */
+ unsigned long rx_calc_timer PACKED; /* 2Ch: */
+} fr_dlci_stat_t;
+
+/*----------------------------------------------------------------------------
+ * Communications error statistics.
+ * This structure is returned by the FR_READ_ERROR_STATS command.
+ */
+typedef struct fr_comm_stat
+{
+ unsigned char rx_overruns PACKED; /* 00h: */
+ unsigned char rx_bad_crc PACKED; /* 01h: */
+ unsigned char rx_aborts PACKED; /* 02h: */
+ unsigned char rx_too_long PACKED; /* 03h: */
+ unsigned char tx_aborts PACKED; /* 04h: */
+ unsigned char tx_underruns PACKED; /* 05h: */
+ unsigned char tx_missed_undr PACKED; /* 06h: */
+ unsigned char dcd_dropped PACKED; /* 07h: */
+ unsigned char cts_dropped PACKED; /* 08h: */
+} fr_comm_stat_t;
+
+/*----------------------------------------------------------------------------
+ * Defines for the FR_ISSUE_IS_FRAME command.
+ */
+#define FR_ISF_LVE 2 /* issue Link Verification Enquiry */
+#define FR_ISF_FSE 3 /* issue Full Status Enquiry */
+
+/*----------------------------------------------------------------------------
+ * Frame Relay ARP Header -- Used for Dynamic route creation with InvARP
+ */
+
+typedef struct arphdr_fr
+ {
+ unsigned short ar_hrd PACKED; /* format of hardware addr */
+ unsigned short ar_pro PACKED; /* format of protocol addr */
+ unsigned char ar_hln PACKED; /* length of hardware addr */
+ unsigned char ar_pln PACKED; /* length of protocol addr */
+ unsigned short ar_op PACKED; /* ARP opcode */
+ unsigned short ar_sha PACKED; /* Sender DLCI addr 2 bytes */
+ unsigned long ar_sip PACKED; /* Sender IP addr 4 bytes */
+ unsigned short ar_tha PACKED; /* Target DLCI addr 2 bytes */
+ unsigned long ar_tip PACKED; /* Target IP addr 4 bytes */
+ } arphdr_fr_t;
+
+/*----------------------------------------------------------------------------
+ * Frame Relay RFC 1490 SNAP Header -- Used to check for ARP packets
+ */
+typedef struct arphdr_1490
+ {
+ unsigned char control PACKED; /* UI, etc... */
+ unsigned char pad PACKED; /* Pad */
+ unsigned char NLPID PACKED; /* SNAP */
+ unsigned char OUI[3] PACKED; /* Ethertype, etc... */
+ unsigned short PID PACKED; /* ARP, IP, etc... */
+ } arphdr_1490_t;
+
+/* UDP/IP packet (for UDP management) layout */
+
+/* The embedded control block for UDP mgmt
+ This is essentially a mailbox structure, without the large data field */
+
+typedef struct {
+ unsigned char opp_flag PACKED; /* the opp flag */
+ unsigned char command PACKED; /* command code */
+ unsigned short length PACKED; /* length of data buffer */
+ unsigned char result PACKED; /* return code */
+ unsigned short dlci PACKED; /* DLCI number */
+ unsigned char attr PACKED; /* FECN, BECN, DE and C/R bits */
+ unsigned short rxlost1 PACKED; /* frames discarded at int. level */
+ unsigned long rxlost2 PACKED; /* frames discarded at app. level */
+ unsigned char rsrv[2] PACKED; /* reserved for future use */
+} cblock_t;
+
+
+/* UDP management packet layout (data area of ip packet) */
+
+typedef struct {
+ unsigned char control PACKED;
+ unsigned char NLPID PACKED;
+} fr_encap_hdr_t;
+
+typedef struct {
+ fr_encap_hdr_t fr_encap_hdr PACKED;
+ ip_pkt_t ip_pkt PACKED;
+ udp_pkt_t udp_pkt PACKED;
+ wp_mgmt_t wp_mgmt PACKED;
+ cblock_t cblock PACKED;
+ unsigned char data[4080] PACKED;
+} fr_udp_pkt_t;
+
+
+/* valid ip_protocol for UDP management */
+#define UDPMGMT_UDP_PROTOCOL 0x11
+
+#define UDPMGMT_FPIPE_SIGNATURE "FPIPE8ND"
+#define UDPMGMT_DRVRSTATS_SIGNATURE "DRVSTATS"
+
+/* values for request/reply byte */
+#define UDPMGMT_REQUEST 0x01
+#define UDPMGMT_REPLY 0x02
+#define UDP_OFFSET 12
+
+typedef struct {
+ unsigned long if_send_entry;
+ unsigned long if_send_skb_null;
+ unsigned long if_send_broadcast;
+ unsigned long if_send_multicast;
+ unsigned long if_send_critical_ISR;
+ unsigned long if_send_critical_non_ISR;
+ unsigned long if_send_busy;
+ unsigned long if_send_busy_timeout;
+ unsigned long if_send_DRVSTATS_request;
+ unsigned long if_send_FPIPE_request;
+ unsigned long if_send_wan_disconnected;
+ unsigned long if_send_dlci_disconnected;
+ unsigned long if_send_no_bfrs;
+ unsigned long if_send_adptr_bfrs_full;
+ unsigned long if_send_bfrs_passed_to_adptr;
+ unsigned long if_send_consec_send_fail;
+} drvstats_if_send_t;
+
+typedef struct {
+ unsigned long rx_intr_no_socket;
+ unsigned long rx_intr_dev_not_started;
+ unsigned long rx_intr_DRVSTATS_request;
+ unsigned long rx_intr_FPIPE_request;
+ unsigned long rx_intr_bfr_not_passed_to_stack;
+ unsigned long rx_intr_bfr_passed_to_stack;
+ } drvstats_rx_intr_t;
+
+typedef struct {
+ unsigned long UDP_FPIPE_mgmt_kmalloc_err;
+ unsigned long UDP_FPIPE_mgmt_direction_err;
+ unsigned long UDP_FPIPE_mgmt_adptr_type_err;
+ unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK;
+ unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout;
+ unsigned long UDP_FPIPE_mgmt_adptr_send_passed;
+ unsigned long UDP_FPIPE_mgmt_adptr_send_failed;
+ unsigned long UDP_FPIPE_mgmt_not_passed_to_stack;
+ unsigned long UDP_FPIPE_mgmt_passed_to_stack;
+ unsigned long UDP_FPIPE_mgmt_no_socket;
+ unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed;
+ unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed;
+ unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack;
+ unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
+ unsigned long UDP_DRVSTATS_mgmt_no_socket;
+} drvstats_gen_t;
+
+typedef struct {
+ unsigned char attr PACKED;
+ unsigned short time_stamp PACKED;
+ unsigned char reserved[13] PACKED;
+} api_rx_hdr_t;
+
+typedef struct {
+ api_rx_hdr_t api_rx_hdr PACKED;
+ void * data PACKED;
+} api_rx_element_t;
+
+typedef struct {
+ unsigned char attr PACKED;
+ unsigned char reserved[15] PACKED;
+} api_tx_hdr_t;
+
+typedef struct {
+ api_tx_hdr_t api_tx_hdr PACKED;
+ void * data PACKED;
+} api_tx_element_t;
+
+#ifdef _MSC_
+# pragma pack()
+#endif
+#endif /* _SDLA_FR_H */
+
diff --git a/pfinet/linux-src/include/linux/sdla_ppp.h b/pfinet/linux-src/include/linux/sdla_ppp.h
new file mode 100644
index 00000000..95d5c0fe
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdla_ppp.h
@@ -0,0 +1,573 @@
+/*****************************************************************************
+* sdla_ppp.h Sangoma PPP firmware API definitions.
+*
+* Author: Gene Kozin <74604.152@compuserve.com>
+*
+* Copyright: (c) 1995-1997 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Jan 06, 1997 Gene Kozin v2.0
+* Apr 11, 1996 Gene Kozin Initial version.
+*****************************************************************************/
+#ifndef _SDLA_PPP_H
+#define _SDLA_PPP_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-alined.
+ *
+ * Compiler Platform
+ * -------- --------
+ * GNU C Linux
+ */
+
+#ifndef PACKED
+# define PACKED __attribute__((packed))
+#endif /* PACKED */
+
+/* Adapter memory layout and important constants */
+#define PPP508_MB_VECT 0xE000 /* mailbox window vector */
+#define PPP508_MB_OFFS 0 /* mailbox offset */
+#define PPP508_FLG_OFFS 0x1000 /* status flags offset */
+#define PPP508_BUF_OFFS 0x1100 /* buffer info block offset */
+#define PPP514_MB_OFFS 0xE000 /* mailbox offset */
+#define PPP514_FLG_OFFS 0xF000 /* status flags offset */
+#define PPP514_BUF_OFFS 0xF100 /* buffer info block offset */
+
+#define PPP_MAX_DATA 1008 /* command block data buffer length */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * PPP Command Block.
+ */
+typedef struct ppp_cmd{
+ unsigned char command PACKED; /* command code */
+ unsigned short length PACKED; /* length of data buffer */
+ unsigned char result PACKED; /* return code */
+ unsigned char rsrv[11] PACKED; /* reserved for future use */
+} ppp_cmd_t;
+
+typedef struct cblock{
+ unsigned char opp_flag PACKED;
+ unsigned char command PACKED; /* command code */
+ unsigned short length PACKED; /* length of data buffer */
+ unsigned char result PACKED; /* return code */
+ unsigned char rsrv[11] PACKED; /* reserved for future use */
+} cblock_t;
+
+typedef struct ppp_udp_pkt{
+ ip_pkt_t ip_pkt PACKED;
+ udp_pkt_t udp_pkt PACKED;
+ wp_mgmt_t wp_mgmt PACKED;
+ cblock_t cblock PACKED;
+ unsigned char data[MAX_LGTH_UDP_MGNT_PKT] PACKED;
+} ppp_udp_pkt_t;
+
+typedef struct {
+ unsigned char status PACKED;
+ unsigned char data_avail PACKED;
+ unsigned short real_length PACKED;
+ unsigned short time_stamp PACKED;
+ unsigned char data[1] PACKED;
+} trace_pkt_t;
+
+
+typedef struct {
+ unsigned char opp_flag PACKED;
+ unsigned char trace_type PACKED;
+ unsigned short trace_length PACKED;
+ unsigned short trace_data_ptr PACKED;
+ unsigned short trace_time_stamp PACKED;
+} trace_element_t;
+
+/* 'command' field defines */
+#define PPP_READ_CODE_VERSION 0x10 /* configuration commands */
+#define PPP_SET_CONFIG 0x05
+#define PPP_READ_CONFIG 0x06
+#define PPP_SET_INTR_FLAGS 0x20
+#define PPP_READ_INTR_FLAGS 0x21
+#define PPP_SET_INBOUND_AUTH 0x30
+#define PPP_SET_OUTBOUND_AUTH 0x31
+#define PPP_GET_CONNECTION_INFO 0x32
+
+#define PPP_COMM_ENABLE 0x03 /* operational commands */
+#define PPP_COMM_DISABLE 0x04
+#define PPP_SEND_SIGN_FRAME 0x23
+#define PPP_READ_SIGN_RESPONSE 0x24
+#define PPP_DATALINE_MONITOR 0x33
+
+#define PPP_READ_STATISTICS 0x07 /* statistics commands */
+#define PPP_FLUSH_STATISTICS 0x08
+#define PPP_READ_ERROR_STATS 0x09
+#define PPP_FLUSH_ERROR_STATS 0x0A
+#define PPP_READ_PACKET_STATS 0x12
+#define PPP_FLUSH_PACKET_STATS 0x13
+#define PPP_READ_LCP_STATS 0x14
+#define PPP_FLUSH_LCP_STATS 0x15
+#define PPP_READ_LPBK_STATS 0x16
+#define PPP_FLUSH_LPBK_STATS 0x17
+#define PPP_READ_IPCP_STATS 0x18
+#define PPP_FLUSH_IPCP_STATS 0x19
+#define PPP_READ_IPXCP_STATS 0x1A
+#define PPP_FLUSH_IPXCP_STATS 0x1B
+#define PPP_READ_PAP_STATS 0x1C
+#define PPP_FLUSH_PAP_STATS 0x1D
+#define PPP_READ_CHAP_STATS 0x1E
+#define PPP_FLUSH_CHAP_STATS 0x1F
+
+/* 'result' field defines */
+#define PPPRES_OK 0x00 /* command executed successfully */
+#define PPPRES_INVALID_STATE 0x09 /* invalid command in this context */
+
+/*----------------------------------------------------------------------------
+ * PPP Mailbox.
+ * This structure is located at offset PPP???_MB_OFFS into PPP???_MB_VECT
+ */
+typedef struct ppp_mbox
+{
+ unsigned char flag PACKED; /* 00h: command execution flag */
+ ppp_cmd_t cmd PACKED; /* 01h: command block */
+ unsigned char data[1] PACKED; /* 10h: variable length data buffer */
+} ppp_mbox_t;
+
+/*----------------------------------------------------------------------------
+ * PPP Status Flags.
+ * This structure is located at offset PPP???_FLG_OFFS into
+ * PPP???_MB_VECT.
+ */
+typedef struct ppp_flags
+{
+ unsigned char iflag PACKED; /* 00: interrupt flag */
+ unsigned char imask PACKED; /* 01: interrupt mask */
+ unsigned char resrv PACKED;
+ unsigned char mstatus PACKED; /* 03: modem status */
+ unsigned char lcp_state PACKED; /* 04: LCP state */
+ unsigned char ppp_phase PACKED; /* 05: PPP phase */
+ unsigned char ip_state PACKED; /* 06: IPCP state */
+ unsigned char ipx_state PACKED; /* 07: IPXCP state */
+ unsigned char pap_state PACKED; /* 08: PAP state */
+ unsigned char chap_state PACKED; /* 09: CHAP state */
+ unsigned short disc_cause PACKED; /* 0A: disconnection cause */
+} ppp_flags_t;
+
+/* 'iflag' defines */
+#define PPP_INTR_RXRDY 0x01 /* Rx ready */
+#define PPP_INTR_TXRDY 0x02 /* Tx ready */
+#define PPP_INTR_MODEM 0x04 /* modem status change (DCD, CTS) */
+#define PPP_INTR_CMD 0x08 /* interface command completed */
+#define PPP_INTR_DISC 0x10 /* data link disconnected */
+#define PPP_INTR_OPEN 0x20 /* data link open */
+#define PPP_INTR_DROP_DTR 0x40 /* DTR drop timeout expired */
+#define PPP_INTR_TIMER 0x80 /* timer interrupt */
+
+
+/* 'mstatus' defines */
+#define PPP_MDM_DCD 0x08 /* mdm_status: DCD */
+#define PPP_MDM_CTS 0x20 /* mdm_status: CTS */
+
+/* 'disc_cause' defines */
+#define PPP_LOCAL_TERMINATION 0x0001 /* Local Request by PPP termination phase */
+#define PPP_DCD_CTS_DROP 0x0002 /* DCD and/or CTS dropped. Link down */
+#define PPP_REMOTE_TERMINATION 0x0800 /* Remote Request by PPP termination phase */
+
+/* 'misc_config_bits' defines */
+#define DONT_RE_TX_ABORTED_I_FRAMES 0x01
+#define TX_FRM_BYTE_COUNT_STATS 0x02
+#define RX_FRM_BYTE_COUNT_STATS 0x04
+#define TIME_STAMP_IN_RX_FRAMES 0x08
+#define NON_STD_ADPTR_FREQ 0x10
+#define INTERFACE_LEVEL_RS232 0x20
+#define AUTO_LINK_RECOVERY 0x100
+#define DONT_TERMINATE_LNK_MAX_CONFIG 0x200
+
+/* 'authentication options' defines */
+#define NO_AUTHENTICATION 0x00
+#define INBOUND_AUTH 0x80
+#define PAP_AUTH 0x01
+#define CHAP_AUTH 0x02
+
+/* 'ip options' defines */
+#define L_AND_R_IP_NO_ASSIG 0x00
+#define L_IP_LOCAL_ASSIG 0x01
+#define L_IP_REMOTE_ASSIG 0x02
+#define R_IP_LOCAL_ASSIG 0x04
+#define R_IP_REMOTE_ASSIG 0x08
+#define ENABLE_IP 0x80
+
+/* 'ipx options' defines */
+#define ROUTING_PROT_DEFAULT 0x20
+#define ENABLE_IPX 0x80
+#define DISABLE_IPX 0x00
+
+/*----------------------------------------------------------------------------
+ * PPP Buffer Info.
+ * This structure is located at offset PPP508_BUF_OFFS into
+ * PPP508_MB_VECT.
+ */
+typedef struct ppp508_buf_info
+{
+ unsigned short txb_num PACKED; /* 00: number of transmit buffers */
+ unsigned long txb_ptr PACKED; /* 02: pointer to the buffer ctl. */
+ unsigned char rsrv1[26] PACKED;
+ unsigned short rxb_num PACKED; /* 20: number of receive buffers */
+ unsigned long rxb_ptr PACKED; /* 22: pointer to the buffer ctl. */
+ unsigned long rxb1_ptr PACKED; /* 26: pointer to the first buf.ctl. */
+ unsigned long rxb_base PACKED; /* 2A: pointer to the buffer base */
+ unsigned char rsrv2[2] PACKED;
+ unsigned long rxb_end PACKED; /* 30: pointer to the buffer end */
+} ppp508_buf_info_t;
+
+/*----------------------------------------------------------------------------
+ * Transmit/Receive Buffer Control Block.
+ */
+typedef struct ppp_buf_ctl
+{
+ unsigned char flag PACKED; /* 00: 'buffer ready' flag */
+ unsigned short length PACKED; /* 01: length of data */
+ unsigned char reserved1[1] PACKED; /* 03: */
+ unsigned char proto PACKED; /* 04: protocol */
+ unsigned short timestamp PACKED; /* 05: time stamp (Rx only) */
+ unsigned char reserved2[5] PACKED; /* 07: */
+ union
+ {
+ unsigned short o_p[2]; /* 1C: buffer offset & page (S502) */
+ unsigned long ptr; /* 1C: buffer pointer (S508) */
+ } buf PACKED;
+} ppp_buf_ctl_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Adapter Configuration Block (passed to the PPP_SET_CONFIG command).
+ */
+typedef struct ppp508_conf
+{
+ unsigned long line_speed PACKED; /* 00: baud rate, bps */
+ unsigned short txbuf_percent PACKED; /* 04: % of Tx buffer */
+ unsigned short conf_flags PACKED; /* 06: configuration bits */
+ unsigned short mtu_local PACKED; /* 08: local MTU */
+ unsigned short mtu_remote PACKED; /* 0A: remote MTU */
+ unsigned short restart_tmr PACKED; /* 0C: restart timer */
+ unsigned short auth_rsrt_tmr PACKED; /* 0E: authentication timer */
+ unsigned short auth_wait_tmr PACKED; /* 10: authentication timer */
+ unsigned short mdm_fail_tmr PACKED; /* 12: modem failure timer */
+ unsigned short dtr_drop_tmr PACKED; /* 14: DTR drop timer */
+ unsigned short connect_tmout PACKED; /* 16: connection timeout */
+ unsigned short conf_retry PACKED; /* 18: max. retry */
+ unsigned short term_retry PACKED; /* 1A: max. retry */
+ unsigned short fail_retry PACKED; /* 1C: max. retry */
+ unsigned short auth_retry PACKED; /* 1E: max. retry */
+ unsigned char auth_options PACKED; /* 20: authentication opt. */
+ unsigned char ip_options PACKED; /* 21: IP options */
+ unsigned long ip_local PACKED; /* 22: local IP address */
+ unsigned long ip_remote PACKED; /* 26: remote IP address */
+ unsigned char ipx_options PACKED; /* 2A: IPX options */
+ unsigned char ipx_netno[4] PACKED; /* 2B: IPX net number */
+ unsigned char ipx_local[6] PACKED; /* 2F: local IPX node number*/
+ unsigned char ipx_remote[6] PACKED; /* 35: remote IPX node num.*/
+ unsigned char ipx_router[48] PACKED; /* 3B: IPX router name*/
+ unsigned long alt_cpu_clock PACKED; /* 6B: */
+} ppp508_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Adapter Read Connection Information Block
+ * Returned by the PPP_GET_CONNECTION_INFO command
+ */
+typedef struct ppp508_connect_info
+{
+ unsigned short mru PACKED; /* 00-01 Remote Max Rec' Unit */
+ unsigned char ip_options PACKED; /* 02: Negotiated ip options */
+ unsigned long ip_local PACKED; /* 03-06: local IP address */
+ unsigned long ip_remote PACKED; /* 07-0A: remote IP address */
+ unsigned char ipx_options PACKED; /* 0B: Negotiated ipx options */
+ unsigned char ipx_netno[4] PACKED; /* 0C-0F: IPX net number */
+ unsigned char ipx_local[6] PACKED; /* 10-1F: local IPX node # */
+ unsigned char ipx_remote[6] PACKED; /* 16-1B: remote IPX node # */
+ unsigned char ipx_router[48] PACKED; /* 1C-4B: IPX router name */
+ unsigned char auth_status PACKED; /* 4C: Authentication Status */
+ unsigned char inbd_auth_peerID[1] PACKED; /* 4D: variable length inbound authenticated peer ID */
+} ppp508_connect_info_t;
+
+/* 'line_speed' field */
+#define PPP_BITRATE_1200 0x01
+#define PPP_BITRATE_2400 0x02
+#define PPP_BITRATE_4800 0x03
+#define PPP_BITRATE_9600 0x04
+#define PPP_BITRATE_19200 0x05
+#define PPP_BITRATE_38400 0x06
+#define PPP_BITRATE_45000 0x07
+#define PPP_BITRATE_56000 0x08
+#define PPP_BITRATE_64000 0x09
+#define PPP_BITRATE_74000 0x0A
+#define PPP_BITRATE_112000 0x0B
+#define PPP_BITRATE_128000 0x0C
+#define PPP_BITRATE_156000 0x0D
+
+/* Defines for the 'conf_flags' field */
+#define PPP_IGNORE_TX_ABORT 0x01 /* don't re-transmit aborted frames */
+#define PPP_ENABLE_TX_STATS 0x02 /* enable Tx statistics */
+#define PPP_ENABLE_RX_STATS 0x04 /* enable Rx statistics */
+#define PPP_ENABLE_TIMESTAMP 0x08 /* enable timestamp */
+
+/* 'ip_options' defines */
+#define PPP_LOCAL_IP_LOCAL 0x01
+#define PPP_LOCAL_IP_REMOTE 0x02
+#define PPP_REMOTE_IP_LOCAL 0x04
+#define PPP_REMOTE_IP_REMOTE 0x08
+
+/* 'ipx_options' defines */
+#define PPP_REMOTE_IPX_NETNO 0x01
+#define PPP_REMOTE_IPX_LOCAL 0x02
+#define PPP_REMOTE_IPX_REMOTE 0x04
+#define PPP_IPX_ROUTE_RIP_SAP 0x08
+#define PPP_IPX_ROUTE_NLSP 0x10
+#define PPP_IPX_ROUTE_DEFAULT 0x20
+#define PPP_IPX_CONF_COMPLETE 0x40
+#define PPP_IPX_ENABLE 0x80
+
+/*----------------------------------------------------------------------------
+ * S508 Adapter Configuration Block (returned by the PPP_READ_CONFIG command).
+ */
+typedef struct ppp508_get_conf
+{
+ unsigned long bps PACKED; /* 00: baud rate, bps */
+ ppp508_conf_t conf PACKED; /* 04: requested config. */
+ unsigned short txb_num PACKED; /* 6F: number of Tx buffers */
+ unsigned short rxb_num PACKED; /* 71: number of Rx buffers */
+} ppp508_get_conf_t;
+
+/*----------------------------------------------------------------------------
+ * S508 Operational Statistics (returned by the PPP_READ_STATISTIC command).
+ */
+typedef struct ppp508_stats
+{
+ unsigned short reserved1 PACKED; /* 00: */
+ unsigned short rx_bad_len PACKED; /* 02: */
+ unsigned short reserved2 PACKED; /* 04: */
+ unsigned long tx_frames PACKED; /* 06: */
+ unsigned long tx_bytes PACKED; /* 0A: */
+ unsigned long rx_frames PACKED; /* 0E: */
+ unsigned long rx_bytes PACKED; /* 12: */
+} ppp508_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Adapter Error Statistics (returned by the PPP_READ_ERROR_STATS command).
+ */
+typedef struct ppp_err_stats
+{
+ unsigned char rx_overrun PACKED; /* 00: Rx overrun errors */
+ unsigned char rx_bad_crc PACKED; /* 01: Rx CRC errors */
+ unsigned char rx_abort PACKED; /* 02: Rx aborted frames */
+ unsigned char rx_lost PACKED; /* 03: Rx frames lost */
+ unsigned char tx_abort PACKED; /* 04: Tx aborted frames */
+ unsigned char tx_underrun PACKED; /* 05: Tx underrun errors */
+ unsigned char tx_missed_intr PACKED; /* 06: Tx underruns missed */
+ unsigned char reserved PACKED; /* 07: Tx underruns missed */
+ unsigned char dcd_trans PACKED; /* 08: DCD transitions */
+ unsigned char cts_trans PACKED; /* 09: CTS transitions */
+} ppp_err_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Packet Statistics (returned by the PPP_READ_PACKET_STATS command).
+ */
+typedef struct ppp_pkt_stats
+{
+ unsigned short rx_bad_header PACKED; /* 00: */
+ unsigned short rx_prot_unknwn PACKED; /* 02: */
+ unsigned short rx_too_large PACKED; /* 04: */
+ unsigned short rx_lcp PACKED; /* 06: */
+ unsigned short tx_lcp PACKED; /* 08: */
+ unsigned short rx_ipcp PACKED; /* 0A: */
+ unsigned short tx_ipcp PACKED; /* 0C: */
+ unsigned short rx_ipxcp PACKED; /* 0E: */
+ unsigned short tx_ipxcp PACKED; /* 10: */
+ unsigned short rx_pap PACKED; /* 12: */
+ unsigned short tx_pap PACKED; /* 14: */
+ unsigned short rx_chap PACKED; /* 16: */
+ unsigned short tx_chap PACKED; /* 18: */
+ unsigned short rx_lqr PACKED; /* 1A: */
+ unsigned short tx_lqr PACKED; /* 1C: */
+ unsigned short rx_ip PACKED; /* 1E: */
+ unsigned short tx_ip PACKED; /* 20: */
+ unsigned short rx_ipx PACKED; /* 22: */
+ unsigned short tx_ipx PACKED; /* 24: */
+} ppp_pkt_stats_t;
+
+/*----------------------------------------------------------------------------
+ * LCP Statistics (returned by the PPP_READ_LCP_STATS command).
+ */
+typedef struct ppp_lcp_stats
+{
+ unsigned short rx_unknown PACKED; /* 00: unknown LCP type */
+ unsigned short rx_conf_rqst PACKED; /* 02: Configure-Request */
+ unsigned short rx_conf_ack PACKED; /* 04: Configure-Ack */
+ unsigned short rx_conf_nak PACKED; /* 06: Configure-Nak */
+ unsigned short rx_conf_rej PACKED; /* 08: Configure-Reject */
+ unsigned short rx_term_rqst PACKED; /* 0A: Terminate-Request */
+ unsigned short rx_term_ack PACKED; /* 0C: Terminate-Ack */
+ unsigned short rx_code_rej PACKED; /* 0E: Code-Reject */
+ unsigned short rx_proto_rej PACKED; /* 10: Protocol-Reject */
+ unsigned short rx_echo_rqst PACKED; /* 12: Echo-Request */
+ unsigned short rx_echo_reply PACKED; /* 14: Echo-Reply */
+ unsigned short rx_disc_rqst PACKED; /* 16: Discard-Request */
+ unsigned short tx_conf_rqst PACKED; /* 18: Configure-Request */
+ unsigned short tx_conf_ack PACKED; /* 1A: Configure-Ack */
+ unsigned short tx_conf_nak PACKED; /* 1C: Configure-Nak */
+ unsigned short tx_conf_rej PACKED; /* 1E: Configure-Reject */
+ unsigned short tx_term_rqst PACKED; /* 20: Terminate-Request */
+ unsigned short tx_term_ack PACKED; /* 22: Terminate-Ack */
+ unsigned short tx_code_rej PACKED; /* 24: Code-Reject */
+ unsigned short tx_proto_rej PACKED; /* 26: Protocol-Reject */
+ unsigned short tx_echo_rqst PACKED; /* 28: Echo-Request */
+ unsigned short tx_echo_reply PACKED; /* 2A: Echo-Reply */
+ unsigned short tx_disc_rqst PACKED; /* 2E: Discard-Request */
+ unsigned short rx_too_large PACKED; /* 30: packets too large */
+ unsigned short rx_ack_inval PACKED; /* 32: invalid Conf-Ack */
+ unsigned short rx_rej_inval PACKED; /* 34: invalid Conf-Reject */
+ unsigned short rx_rej_badid PACKED; /* 36: Conf-Reject w/bad ID */
+} ppp_lcp_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Loopback Error Statistics (returned by the PPP_READ_LPBK_STATS command).
+ */
+typedef struct ppp_lpbk_stats
+{
+ unsigned short conf_magic PACKED; /* 00: */
+ unsigned short loc_echo_rqst PACKED; /* 02: */
+ unsigned short rem_echo_rqst PACKED; /* 04: */
+ unsigned short loc_echo_reply PACKED; /* 06: */
+ unsigned short rem_echo_reply PACKED; /* 08: */
+ unsigned short loc_disc_rqst PACKED; /* 0A: */
+ unsigned short rem_disc_rqst PACKED; /* 0C: */
+ unsigned short echo_tx_collsn PACKED; /* 0E: */
+ unsigned short echo_rx_collsn PACKED; /* 10: */
+} ppp_lpbk_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Protocol Statistics (returned by the PPP_READ_IPCP_STATS and
+ * PPP_READ_IPXCP_STATS commands).
+ */
+typedef struct ppp_prot_stats
+{
+ unsigned short rx_unknown PACKED; /* 00: unknown type */
+ unsigned short rx_conf_rqst PACKED; /* 02: Configure-Request */
+ unsigned short rx_conf_ack PACKED; /* 04: Configure-Ack */
+ unsigned short rx_conf_nak PACKED; /* 06: Configure-Nak */
+ unsigned short rx_conf_rej PACKED; /* 08: Configure-Reject */
+ unsigned short rx_term_rqst PACKED; /* 0A: Terminate-Request */
+ unsigned short rx_term_ack PACKED; /* 0C: Terminate-Ack */
+ unsigned short rx_code_rej PACKED; /* 0E: Code-Reject */
+ unsigned short reserved PACKED; /* 10: */
+ unsigned short tx_conf_rqst PACKED; /* 12: Configure-Request */
+ unsigned short tx_conf_ack PACKED; /* 14: Configure-Ack */
+ unsigned short tx_conf_nak PACKED; /* 16: Configure-Nak */
+ unsigned short tx_conf_rej PACKED; /* 18: Configure-Reject */
+ unsigned short tx_term_rqst PACKED; /* 1A: Terminate-Request */
+ unsigned short tx_term_ack PACKED; /* 1C: Terminate-Ack */
+ unsigned short tx_code_rej PACKED; /* 1E: Code-Reject */
+ unsigned short rx_too_large PACKED; /* 20: packets too large */
+ unsigned short rx_ack_inval PACKED; /* 22: invalid Conf-Ack */
+ unsigned short rx_rej_inval PACKED; /* 24: invalid Conf-Reject */
+ unsigned short rx_rej_badid PACKED; /* 26: Conf-Reject w/bad ID */
+} ppp_prot_stats_t;
+
+/*----------------------------------------------------------------------------
+ * PAP Statistics (returned by the PPP_READ_PAP_STATS command).
+ */
+typedef struct ppp_pap_stats
+{
+ unsigned short rx_unknown PACKED; /* 00: unknown type */
+ unsigned short rx_auth_rqst PACKED; /* 02: Authenticate-Request */
+ unsigned short rx_auth_ack PACKED; /* 04: Authenticate-Ack */
+ unsigned short rx_auth_nak PACKED; /* 06: Authenticate-Nak */
+ unsigned short reserved PACKED; /* 08: */
+ unsigned short tx_auth_rqst PACKED; /* 0A: Authenticate-Request */
+ unsigned short tx_auth_ack PACKED; /* 0C: Authenticate-Ack */
+ unsigned short tx_auth_nak PACKED; /* 0E: Authenticate-Nak */
+ unsigned short rx_too_large PACKED; /* 10: packets too large */
+ unsigned short rx_bad_peerid PACKED; /* 12: invalid peer ID */
+ unsigned short rx_bad_passwd PACKED; /* 14: invalid password */
+} ppp_pap_stats_t;
+
+/*----------------------------------------------------------------------------
+ * CHAP Statistics (returned by the PPP_READ_CHAP_STATS command).
+ */
+typedef struct ppp_chap_stats
+{
+ unsigned short rx_unknown PACKED; /* 00: unknown type */
+ unsigned short rx_challenge PACKED; /* 02: Authenticate-Request */
+ unsigned short rx_response PACKED; /* 04: Authenticate-Ack */
+ unsigned short rx_success PACKED; /* 06: Authenticate-Nak */
+ unsigned short rx_failure PACKED; /* 08: Authenticate-Nak */
+ unsigned short reserved PACKED; /* 0A: */
+ unsigned short tx_challenge PACKED; /* 0C: Authenticate-Request */
+ unsigned short tx_response PACKED; /* 0E: Authenticate-Ack */
+ unsigned short tx_success PACKED; /* 10: Authenticate-Nak */
+ unsigned short tx_failure PACKED; /* 12: Authenticate-Nak */
+ unsigned short rx_too_large PACKED; /* 14: packets too large */
+ unsigned short rx_bad_peerid PACKED; /* 16: invalid peer ID */
+ unsigned short rx_bad_passwd PACKED; /* 18: invalid password */
+ unsigned short rx_bad_md5 PACKED; /* 1A: invalid MD5 format */
+ unsigned short rx_bad_resp PACKED; /* 1C: invalid response */
+} ppp_chap_stats_t;
+
+/*----------------------------------------------------------------------------
+ * Connection Information (returned by the PPP_GET_CONNECTION_INFO command).
+ */
+typedef struct ppp_conn_info
+{
+ unsigned short remote_mru PACKED; /* 00: */
+ unsigned char ip_options PACKED; /* 02: */
+ unsigned char ip_local[4] PACKED; /* 03: */
+ unsigned char ip_remote[4] PACKED; /* 07: */
+ unsigned char ipx_options PACKED; /* 0B: */
+ unsigned char ipx_network[4] PACKED; /* 0C: */
+ unsigned char ipx_local[6] PACKED; /* 10: */
+ unsigned char ipx_remote[6] PACKED; /* 16: */
+ unsigned char ipx_router[48] PACKED; /* 1C: */
+ unsigned char auth_status PACKED; /* 4C: */
+ unsigned char peer_id[0] PACKED; /* 4D: */
+} ppp_conn_info_t;
+
+/* Data structure for SET_TRIGGER_INTR command
+ */
+
+typedef struct ppp_intr_info{
+ unsigned char i_enable PACKED; /* 0 Interrupt enable bits */
+ unsigned char irq PACKED; /* 1 Irq number */
+ unsigned short timer_len PACKED; /* 2 Timer delay */
+} ppp_intr_info_t;
+
+
+#define FT1_MONITOR_STATUS_CTRL 0x80
+#define SET_FT1_MODE 0x81
+
+
+
+/* Special UDP drivers management commands */
+#define PPIPE_ENABLE_TRACING 0x20
+#define PPIPE_DISABLE_TRACING 0x21
+#define PPIPE_GET_TRACE_INFO 0x22
+#define PPIPE_GET_IBA_DATA 0x23
+#define PPIPE_KILL_BOARD 0x24
+#define PPIPE_FT1_READ_STATUS 0x25
+#define PPIPE_DRIVER_STAT_IFSEND 0x26
+#define PPIPE_DRIVER_STAT_INTR 0x27
+#define PPIPE_DRIVER_STAT_GEN 0x28
+#define PPIPE_FLUSH_DRIVER_STATS 0x29
+#define PPIPE_ROUTER_UP_TIME 0x30
+
+#define DISABLE_TRACING 0x00
+#define TRACE_SIGNALLING_FRAMES 0x01
+#define TRACE_DATA_FRAMES 0x02
+
+
+
+#ifdef _MSC_
+# pragma pack()
+#endif
+#endif /* _SDLA_PPP_H */
diff --git a/pfinet/linux-src/include/linux/sdla_x25.h b/pfinet/linux-src/include/linux/sdla_x25.h
new file mode 100644
index 00000000..58214a08
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdla_x25.h
@@ -0,0 +1,625 @@
+/*****************************************************************************
+* sdla_x25.h Sangoma X.25 firmware API definitions.
+*
+* Author: Gene Kozin <74604.152@compuserve.com>
+*
+* Copyright: (c) 1995-1996 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Dec 13, 1996 Gene Kozin Initial version
+*****************************************************************************/
+#ifndef _SDLA_X25_H
+#define _SDLA_X25_H
+
+/*----------------------------------------------------------------------------
+ * Notes:
+ * ------
+ * 1. All structures defined in this file are byte-aligned. To ensure
+ * portability of this code between different platforms and compilers, one
+ * of the following defines must be defined before including this file:
+ *
+ * Compiler Platform Define Use option
+ * -------- -------- ------ ----------
+ * GNU C Linux _GNUC_ -
+ * Microsoft C DOS/Windows _MSC_ -
+ *
+ */
+
+#ifdef _GNUC_
+# ifndef PACKED
+# define PACKED __attribute__((packed))
+# endif /* PACKED */
+#else
+# define PACKED
+#endif
+#ifdef _MSC_
+# pragma pack(1)
+#endif
+
+/****** CONSTANTS DEFINITIONS ***********************************************/
+
+#define X25_MAX_CHAN 255 /* max number of open X.25 circuits */
+#define X25_MAX_DATA 1024 /* max length of X.25 data buffer */
+
+/*
+ * X.25 shared memory layout.
+ */
+#define X25_MBOX_OFFS 0x16B0 /* general mailbox block */
+#define X25_RXMBOX_OFFS 0x1AD0 /* receive mailbox */
+#define X25_STATUS_OFFS 0x1EF0 /* X.25 status structure */
+
+/****** DATA STRUCTURES *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * X.25 Command Block.
+ */
+typedef struct X25Cmd
+{
+ unsigned char command PACKED; /* command code */
+ unsigned short length PACKED; /* transfer data length */
+ unsigned char result PACKED; /* return code */
+ unsigned char pf PACKED; /* P/F bit */
+ unsigned short lcn PACKED; /* logical channel */
+ unsigned char qdm PACKED; /* Q/D/M bits */
+ unsigned char cause PACKED; /* cause field */
+ unsigned char diagn PACKED; /* diagnostics */
+ unsigned char pktType PACKED; /* packet type */
+ unsigned char resrv[4] PACKED; /* reserved */
+} TX25Cmd;
+
+/*
+ * Defines for the 'command' field.
+ */
+/*----- General commands --------------*/
+#define X25_SET_GLOBAL_VARS 0x0B /* set global variables */
+#define X25_READ_MODEM_STATUS 0x0C /* read modem status */
+#define X25_READ_CODE_VERSION 0x15 /* read firmware version number */
+#define X25_TRACE_CONFIGURE 0x14 /* configure trace facility */
+#define X25_READ_TRACE_DATA 0x16 /* read trace data */
+#define X25_SET_INTERRUPT_MODE 0x17 /* set interrupt generation mode */
+#define X25_READ_INTERRUPT_MODE 0x18 /* read interrupt generation mode */
+/*----- HDLC-level commands -----------*/
+#define X25_HDLC_LINK_CONFIGURE 0x01 /* configure HDLC link level */
+#define X25_HDLC_LINK_OPEN 0x02 /* open HDLC link */
+#define X25_HDLC_LINK_CLOSE 0x03 /* close HDLC link */
+#define X25_HDLC_LINK_SETUP 0x04 /* set up HDLC link */
+#define X25_HDLC_LINK_DISC 0x05 /* disconnect DHLC link */
+#define X25_HDLC_LINK_STATUS 0x06 /* read DHLC link status */
+#define X25_HDLC_READ_STATS 0x07 /* read operational statistics */
+#define X25_HDLC_FLUSH_STATS 0x08 /* flush operational statistics */
+#define X25_HDLC_READ_COMM_ERR 0x09 /* read error statistics */
+#define X25_HDLC_FLUSH_COMM_ERR 0x0A /* flush error statistics */
+#define X25_HDLC_FLUSH_BUFFERS 0x0D /* flush HDLC-level data buffers */
+#define X25_HDLC_SPRVS_CNT_STAT 0x0F /* read surervisory count status */
+#define X25_HDLC_SEND_UI_FRAME 0x10 /* send unnumbered information frame */
+#define X25_HDLC_WRITE 0x11 /* send HDLC information frame */
+#define X25_HDLC_READ 0x21 /* read HDLC information frame */
+#define X25_HDLC_READ_CONFIG 0x12 /* read HDLC configuration */
+#define X25_HDLC_SET_CONFIG 0x13 /* set HDLC configuration */
+/*----- X.25-level commands -----------*/
+#define X25_READ 0x22 /* read X.25 packet */
+#define X25_WRITE 0x23 /* send X.25 packet */
+#define X25_PLACE_CALL 0x30 /* place a call on SVC */
+#define X25_ACCEPT_CALL 0x31 /* accept incoming call */
+#define X25_CLEAR_CALL 0x32 /* clear call */
+#define X25_CLEAR_CONFRM 0x33 /* send clear confirmation packet */
+#define X25_RESET 0x34 /* send reset request packet */
+#define X25_RESET_CONFRM 0x35 /* send reset confirmation packet */
+#define X25_RESTART 0x36 /* send restart request packet */
+#define X25_RESTART_CONFRM 0x37 /* send restart confirmation packet */
+#define X25_INTERRUPT 0x38 /* send interrupt request packet */
+#define X25_INTERRUPT_CONFRM 0x39 /* send interrupt confirmation pkt */
+#define X25_REGISTRATION_RQST 0x3A /* send registration request packet */
+#define X25_REGISTRATION_CONFRM 0x3B /* send registration confirmation */
+#define X25_IS_DATA_AVAILABLE 0x40 /* querry receive queue */
+#define X25_INCOMING_CALL_CTL 0x41 /* select incoming call options */
+#define X25_CONFIGURE_PVC 0x42 /* configure PVC */
+#define X25_GET_ACTIVE_CHANNELS 0x43 /* get a list of active circuits */
+#define X25_READ_CHANNEL_CONFIG 0x44 /* read virt. circuit configuration */
+#define X25_FLUSH_DATA_BUFFERS 0x45 /* flush X.25-level data buffers */
+#define X25_READ_HISTORY_TABLE 0x46 /* read asynchronous event log */
+#define X25_HISTORY_TABLE_CTL 0x47 /* control asynchronous event log */
+#define X25_GET_TX_D_BIT_STATUS 0x48 /* is packet with D-bit acknowledged */
+#define X25_READ_STATISTICS 0x49 /* read X.25-level statistics */
+#define X25_FLUSH_STATISTICS 0x4A /* flush X.25-level statistics */
+#define X25_READ_CONFIGURATION 0x50 /* read HDLC & X.25 configuration */
+#define X25_SET_CONFIGURATION 0x51 /* set HDLC & X.25 configuration */
+
+/*
+ * Defines for the 'result' field.
+ */
+/*----- General results ---------------*/
+#define X25RES_OK 0x00
+#define X25RES_ERROR 0x01
+#define X25RES_LINK_NOT_IN_ABM 0x02 /* link is not in ABM mode */
+#define X25RES_LINK_CLOSED 0x03
+#define X25RES_INVAL_LENGTH 0x04
+#define X25RES_INVAL_CMD 0x05
+#define X25RES_UNNUMBERED_FRAME 0x06 /* unnumbered frame received */
+#define X25RES_FRM_REJECT_MODE 0x07 /* link is in Frame Reject mode */
+#define X25RES_MODEM_FAILURE 0x08 /* DCD and/or CTS dropped */
+#define X25RES_N2_RETRY_LIMIT 0x09 /* N2 retry limit has been exceeded */
+#define X25RES_INVAL_LCN 0x30 /* invalid logical channel number */
+#define X25RES_INVAL_STATE 0x31 /* channel is not in data xfer mode */
+#define X25RES_INVAL_DATA_LEN 0x32 /* invalid data length */
+#define X25RES_NOT_READY 0x33 /* no data available / buffers full */
+#define X25RES_NETWORK_DOWN 0x34
+#define X25RES_CHANNEL_IN_USE 0x35 /* there is data queued on this LCN */
+#define X25RES_REGST_NOT_SUPPRT 0x36 /* registration not supported */
+#define X25RES_INVAL_FORMAT 0x37 /* invalid packet format */
+#define X25RES_D_BIT_NOT_SUPPRT 0x38 /* D-bit pragmatics not supported */
+#define X25RES_FACIL_NOT_SUPPRT 0x39 /* Call facility not supported */
+#define X25RES_INVAL_CALL_ARG 0x3A /* erroneous call arguments */
+#define X25RES_INVAL_CALL_DATA 0x3B /* erroneous call user data */
+#define X25RES_ASYNC_PACKET 0x40 /* asynchronous packet received */
+#define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occurred */
+#define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */
+#define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */
+/*----- Command-dependent results -----*/
+#define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */
+#define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */
+#define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/
+#define X25RES_TRACE_INACTIVE 0x02 /* READ_TRACE_DATA */
+#define X25RES_LINK_IS_OPEN 0x01 /* HDLC_LINK_OPEN */
+#define X25RES_LINK_IS_DISC 0x02 /* HDLC_LINK_DISC */
+#define X25RES_LINK_IS_CLOSED 0x03 /* HDLC_LINK_CLOSE */
+#define X25RES_INVAL_PARAM 0x31 /* INCOMING_CALL_CTL */
+#define X25RES_INVAL_CONFIG 0x35 /* REGISTR_RQST/CONFRM */
+
+/*
+ * Defines for the 'qdm_bits' field.
+ */
+#define X25CMD_Q_BIT_MASK 0x04
+#define X25CMD_D_BIT_MASK 0x02
+#define X25CMD_M_BIT_MASK 0x01
+
+/*
+ * Defines for the 'pkt_type' field.
+ */
+/*----- Asynchronous events ------*/
+#define ASE_CLEAR_RQST 0x02
+#define ASE_RESET_RQST 0x04
+#define ASE_RESTART_RQST 0x08
+#define ASE_INTERRUPT 0x10
+#define ASE_DTE_REGISTR_RQST 0x20
+#define ASE_CALL_RQST 0x30
+#define ASE_CALL_ACCEPTED 0x31
+#define ASE_CLEAR_CONFRM 0x32
+#define ASE_RESET_CONFRM 0x33
+#define ASE_RESTART_CONFRM 0x34
+#define ASE_INTERRUPT_CONFRM 0x35
+#define ASE_DCE_REGISTR_CONFRM 0x36
+#define ASE_DIAGNOSTIC 0x37
+#define ASE_CALL_AUTO_CLEAR 0x38
+#define AUTO_RESPONSE_FLAG 0x80
+/*----- Time-Out events ----------*/
+#define TOE_RESTART_RQST 0x03
+#define TOE_CALL_RQST 0x05
+#define TOE_CLEAR_RQST 0x08
+#define TOE_RESET_RQST 0x0A
+/*----- Protocol Violation events */
+#define PVE_CLEAR_RQST 0x32
+#define PVE_RESET_RQST 0x33
+#define PVE_RESTART_RQST 0x34
+#define PVE_DIAGNOSTIC 0x37
+
+/*----------------------------------------------------------------------------
+ * X.25 Mailbox.
+ * This structure is located at offsets X25_MBOX_OFFS and X25_RXMBOX_OFFS
+ * into shared memory window.
+ */
+typedef struct X25Mbox
+{
+ unsigned char opflag PACKED; /* 00h: execution flag */
+ TX25Cmd cmd PACKED; /* 01h: command block */
+ unsigned char data[1] PACKED; /* 10h: data buffer */
+} TX25Mbox;
+
+/*----------------------------------------------------------------------------
+ * X.25 Time Stamp Structure.
+ */
+typedef struct X25TimeStamp
+{
+ unsigned char month PACKED;
+ unsigned char date PACKED;
+ unsigned char sec PACKED;
+ unsigned char min PACKED;
+ unsigned char hour PACKED;
+} TX25TimeStamp;
+
+/*----------------------------------------------------------------------------
+ * X.25 Status Block.
+ * This structure is located at offset X25_STATUS_OFF into shared memory
+ * window.
+ */
+typedef struct X25Status
+{
+ unsigned short pvc_map PACKED; /* 00h: PVC map */
+ unsigned short icc_map PACKED; /* 02h: Incoming Chan. map */
+ unsigned short twc_map PACKED; /* 04h: Two-way Cnan. map */
+ unsigned short ogc_map PACKED; /* 06h: Outgoing Chan. map */
+ TX25TimeStamp tstamp PACKED; /* 08h: timestamp (BCD) */
+ unsigned char iflags PACKED; /* 0Dh: interrupt flags */
+ unsigned char imask PACKED; /* 0Eh: interrupt mask */
+ unsigned char resrv PACKED; /* 0Eh: */
+ unsigned char gflags PACKED; /* 10h: misc. HDLC/X25 flags */
+ unsigned char cflags[X25_MAX_CHAN] PACKED; /* channel status bytes */
+} TX25Status;
+
+/*
+ * Bitmasks for the 'iflags' field.
+ */
+#define X25_RX_INTR 0x01 /* receive interrupt */
+#define X25_TX_INTR 0x02 /* transmit interrupt */
+#define X25_MODEM_INTR 0x04 /* modem status interrupt (CTS/DCD) */
+#define X25_EVENT_INTR 0x10 /* asynchronous event encountered */
+#define X25_CMD_INTR 0x08 /* interface command complete */
+
+/*
+ * Bitmasks for the 'gflags' field.
+ */
+#define X25_HDLC_ABM 0x01 /* HDLC is in ABM mode */
+#define X25_RX_READY 0x02 /* X.25 data available */
+#define X25_TRACE_READY 0x08 /* trace data available */
+#define X25_EVENT_IND 0x20 /* asynchronous event indicator */
+#define X25_TX_READY 0x40 /* space is available in Tx buf.*/
+
+/*
+ * Bitmasks for the 'cflags' field.
+ */
+#define X25_XFER_MODE 0x80 /* channel is in data transfer mode */
+#define X25_TXWIN_OPEN 0x40 /* transmit window open */
+#define X25_RXBUF_MASK 0x3F /* number of data buffers available */
+
+/*****************************************************************************
+ * Following definitions structurize contents of the TX25Mbox.data field for
+ * different X.25 interface commands.
+ ****************************************************************************/
+
+/* ---------------------------------------------------------------------------
+ * X25_SET_GLOBAL_VARS Command.
+ */
+typedef struct X25GlobalVars
+{
+ unsigned char resrv PACKED; /* 00h: reserved */
+ unsigned char dtrCtl PACKED; /* 01h: DTR control code */
+ unsigned char resErr PACKED; /* 01h: '1' - reset modem error */
+} TX25GlobalVars;
+
+/*
+ * Defines for the 'dtrCtl' field.
+ */
+#define X25_RAISE_DTR 0x01
+#define X25_DROP_DTR 0x02
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_MODEM_STATUS Command.
+ */
+typedef struct X25ModemStatus
+{
+ unsigned char status PACKED; /* 00h: modem status */
+} TX25ModemStatus;
+
+/*
+ * Defines for the 'status' field.
+ */
+#define X25_CTS_MASK 0x20
+#define X25_DCD_MASK 0x08
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_LINK_STATUS Command.
+ */
+typedef struct X25LinkStatus
+{
+ unsigned char txQueued PACKED; /* 00h: queued Tx I-frames*/
+ unsigned char rxQueued PACKED; /* 01h: queued Rx I-frames*/
+ unsigned char station PACKED; /* 02h: DTE/DCE config. */
+ unsigned char reserved PACKED; /* 03h: reserved */
+ unsigned char sfTally PACKED; /* 04h: supervisory frame tally */
+} TX25LinkStatus;
+
+/*
+ * Defines for the 'station' field.
+ */
+#define X25_STATION_DTE 0x01 /* station configured as DTE */
+#define X25_STATION_DCE 0x02 /* station configured as DCE */
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_READ_STATS Command.
+ */
+typedef struct HdlcStats
+{ /* a number of ... */
+ unsigned short rxIFrames PACKED; /* 00h: ready Rx I-frames */
+ unsigned short rxNoseq PACKED; /* 02h: frms out-of-sequence */
+ unsigned short rxNodata PACKED; /* 04h: I-frms without data */
+ unsigned short rxDiscarded PACKED; /* 06h: discarded frames */
+ unsigned short rxTooLong PACKED; /* 08h: frames too long */
+ unsigned short rxBadAddr PACKED; /* 0Ah: frms with inval.addr*/
+ unsigned short txAcked PACKED; /* 0Ch: acknowledged I-frms */
+ unsigned short txRetransm PACKED; /* 0Eh: re-transmit. I-frms */
+ unsigned short t1Timeout PACKED; /* 10h: T1 timeouts */
+ unsigned short rxSABM PACKED; /* 12h: received SABM frames */
+ unsigned short rxDISC PACKED; /* 14h: received DISC frames */
+ unsigned short rxDM PACKED; /* 16h: received DM frames */
+ unsigned short rxFRMR PACKED; /* 18h: FRMR frames received */
+ unsigned short txSABM PACKED; /* 1Ah: transm. SABM frames*/
+ unsigned short txDISC PACKED; /* 1Ch: transm. DISC frames*/
+ unsigned short txDM PACKED; /* 1Eh: transm. DM frames */
+ unsigned short txFRMR PACKED; /* 20h: transm. FRMR frames*/
+} THdlcStats;
+
+/* ---------------------------------------------------------------------------
+ * X25_HDLC_READ_COMM_ERR Command.
+ */
+typedef struct HdlcCommErr
+{ /* a number of ... */
+ unsigned char rxOverrun PACKED; /* 00h: Rx overrun errors */
+ unsigned char rxBadCrc PACKED; /* 01h: Rx CRC errors */
+ unsigned char rxAborted PACKED; /* 02h: Rx aborted frames */
+ unsigned char rxDropped PACKED; /* 03h: frames lost */
+ unsigned char txAborted PACKED; /* 04h: Tx aborted frames */
+ unsigned char txUnderrun PACKED; /* 05h: Tx underrun errors */
+ unsigned char txMissIntr PACKED; /* 06h: missed underrun ints */
+ unsigned char reserved PACKED; /* 07h: reserved */
+ unsigned char droppedDCD PACKED; /* 08h: times DCD dropped */
+ unsigned char droppedCTS PACKED; /* 09h: times CTS dropped */
+} THdlcCommErr;
+
+/* ---------------------------------------------------------------------------
+ * X25_SET_CONFIGURATION & X25_READ_CONFIGURATION Commands.
+ */
+typedef struct X25Config
+{
+ unsigned char baudRate PACKED; /* 00h: */
+ unsigned char t1 PACKED; /* 01h: */
+ unsigned char t2 PACKED; /* 02h: */
+ unsigned char n2 PACKED; /* 03h: */
+ unsigned short hdlcMTU PACKED; /* 04h: */
+ unsigned char hdlcWindow PACKED; /* 06h: */
+ unsigned char t4 PACKED; /* 07h: */
+ unsigned char autoModem PACKED; /* 08h: */
+ unsigned char autoHdlc PACKED; /* 09h: */
+ unsigned char hdlcOptions PACKED; /* 0Ah: */
+ unsigned char station PACKED; /* 0Bh: */
+ unsigned char pktWindow PACKED; /* 0Ch: */
+ unsigned short defPktSize PACKED; /* 0Dh: */
+ unsigned short pktMTU PACKED; /* 0Fh: */
+ unsigned short loPVC PACKED; /* 11h: */
+ unsigned short hiPVC PACKED; /* 13h: */
+ unsigned short loIncomingSVC PACKED; /* 15h: */
+ unsigned short hiIncomingSVC PACKED; /* 17h: */
+ unsigned short loTwoWaySVC PACKED; /* 19h: */
+ unsigned short hiTwoWaySVC PACKED; /* 1Bh: */
+ unsigned short loOutgoingSVC PACKED; /* 1Dh: */
+ unsigned short hiOutgoingSVC PACKED; /* 1Fh: */
+ unsigned short options PACKED; /* 21h: */
+ unsigned char responseOpt PACKED; /* 23h: */
+ unsigned short facil1 PACKED; /* 24h: */
+ unsigned short facil2 PACKED; /* 26h: */
+ unsigned short ccittFacil PACKED; /* 28h: */
+ unsigned short otherFacil PACKED; /* 2Ah: */
+ unsigned short ccittCompat PACKED; /* 2Ch: */
+ unsigned char t10t20 PACKED; /* 2Eh: */
+ unsigned char t11t21 PACKED; /* 2Fh: */
+ unsigned char t12t22 PACKED; /* 30h: */
+ unsigned char t13t23 PACKED; /* 31h: */
+ unsigned char t16t26 PACKED; /* 32H: */
+ unsigned char t28 PACKED; /* 33h: */
+ unsigned char r10r20 PACKED; /* 34h: */
+ unsigned char r12r22 PACKED; /* 35h: */
+ unsigned char r13r23 PACKED; /* 36h: */
+} TX25Config;
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_CHANNEL_CONFIG Command.
+ */
+typedef struct X25ChanAlloc /*----- Channel allocation -*/
+{
+ unsigned short loPVC PACKED; /* 00h: lowest PVC number */
+ unsigned short hiPVC PACKED; /* 02h: highest PVC number */
+ unsigned short loIncomingSVC PACKED; /* 04h: lowest incoming SVC */
+ unsigned short hiIncomingSVC PACKED; /* 06h: highest incoming SVC */
+ unsigned short loTwoWaySVC PACKED; /* 08h: lowest two-way SVC */
+ unsigned short hiTwoWaySVC PACKED; /* 0Ah: highest two-way SVC */
+ unsigned short loOutgoingSVC PACKED; /* 0Ch: lowest outgoing SVC */
+ unsigned short hiOutgoingSVC PACKED; /* 0Eh: highest outgoing SVC */
+} TX25ChanAlloc;
+
+typedef struct X25ChanCfg /*------ Channel configuration -----*/
+{
+ unsigned char type PACKED; /* 00h: channel type */
+ unsigned char txConf PACKED; /* 01h: Tx packet and window sizes */
+ unsigned char rxConf PACKED; /* 01h: Rx packet and window sizes */
+} TX25ChanCfg;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25_PVC 0x01 /* PVC */
+#define X25_SVC_IN 0x03 /* Incoming SVC */
+#define X25_SVC_TWOWAY 0x07 /* Two-way SVC */
+#define X25_SVC_OUT 0x0B /* Outgoing SVC */
+
+/*----------------------------------------------------------------------------
+ * X25_READ_STATISTICS Command.
+ */
+typedef struct X25Stats
+{ /* number of packets Tx/Rx'ed */
+ unsigned short txRestartRqst PACKED; /* 00h: Restart Request */
+ unsigned short rxRestartRqst PACKED; /* 02h: Restart Request */
+ unsigned short txRestartConf PACKED; /* 04h: Restart Confirmation */
+ unsigned short rxRestartConf PACKED; /* 06h: Restart Confirmation */
+ unsigned short txResetRqst PACKED; /* 08h: Reset Request */
+ unsigned short rxResetRqst PACKED; /* 0Ah: Reset Request */
+ unsigned short txResetConf PACKED; /* 0Ch: Reset Confirmation */
+ unsigned short rxResetConf PACKED; /* 0Eh: Reset Confirmation */
+ unsigned short txCallRequest PACKED; /* 10h: Call Request */
+ unsigned short rxCallRequest PACKED; /* 12h: Call Request */
+ unsigned short txCallAccept PACKED; /* 14h: Call Accept */
+ unsigned short rxCallAccept PACKED; /* 16h: Call Accept */
+ unsigned short txClearRqst PACKED; /* 18h: Clear Request */
+ unsigned short rxClearRqst PACKED; /* 1Ah: Clear Request */
+ unsigned short txClearConf PACKED; /* 1Ch: Clear Confirmation */
+ unsigned short rxClearConf PACKED; /* 1Eh: Clear Confirmation */
+ unsigned short txDiagnostic PACKED; /* 20h: Diagnostic */
+ unsigned short rxDiagnostic PACKED; /* 22h: Diagnostic */
+ unsigned short txRegRqst PACKED; /* 24h: Registration Request */
+ unsigned short rxRegRqst PACKED; /* 26h: Registration Request */
+ unsigned short txRegConf PACKED; /* 28h: Registration Confirm.*/
+ unsigned short rxRegConf PACKED; /* 2Ah: Registration Confirm.*/
+ unsigned short txInterrupt PACKED; /* 2Ch: Interrupt */
+ unsigned short rxInterrupt PACKED; /* 2Eh: Interrupt */
+ unsigned short txIntrConf PACKED; /* 30h: Interrupt Confirm. */
+ unsigned short rxIntrConf PACKED; /* 32h: Interrupt Confirm. */
+ unsigned short txData PACKED; /* 34h: Data */
+ unsigned short rxData PACKED; /* 36h: Data */
+ unsigned short txRR PACKED; /* 38h: RR */
+ unsigned short rxRR PACKED; /* 3Ah: RR */
+ unsigned short txRNR PACKED; /* 3Ch: RNR */
+ unsigned short rxRNR PACKED; /* 3Eh: RNR */
+} TX25Stats;
+
+/*----------------------------------------------------------------------------
+ * X25_READ_HISTORY_TABLE Command.
+ */
+typedef struct X25EventLog
+{
+ unsigned char type PACKED; /* 00h: transaction type */
+ unsigned short lcn PACKED; /* 01h: logical channel num */
+ unsigned char packet PACKED; /* 03h: async packet type */
+ unsigned char cause PACKED; /* 04h: X.25 cause field */
+ unsigned char diag PACKED; /* 05h: X.25 diag field */
+ TX25TimeStamp ts PACKED; /* 06h: time stamp */
+} TX25EventLog;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25LOG_INCOMING 0x00
+#define X25LOG_APPLICATION 0x01
+#define X25LOG_AUTOMATIC 0x02
+#define X25LOG_ERROR 0x04
+#define X25LOG_TIMEOUT 0x08
+#define X25LOG_RECOVERY 0x10
+
+/*
+ * Defines for the 'packet' field.
+ */
+#define X25LOG_CALL_RQST 0x0B
+#define X25LOG_CALL_ACCEPTED 0x0F
+#define X25LOG_CLEAR_RQST 0x13
+#define X25LOG_CLEAR_CONFRM 0x17
+#define X25LOG_RESET_RQST 0x1B
+#define X25LOG_RESET_CONFRM 0x1F
+#define X25LOG_RESTART_RQST 0xFB
+#define X25LOG_RESTART_COMFRM 0xFF
+#define X25LOG_DIAGNOSTIC 0xF1
+#define X25LOG_DTE_REG_RQST 0xF3
+#define X25LOG_DTE_REG_COMFRM 0xF7
+
+/* ---------------------------------------------------------------------------
+ * X25_TRACE_CONFIGURE Command.
+ */
+typedef struct X25TraceCfg
+{
+ unsigned char flags PACKED; /* 00h: trace configuration flags */
+ unsigned char timeout PACKED; /* 01h: timeout for trace delay mode*/
+} TX25TraceCfg;
+
+/*
+ * Defines for the 'flags' field.
+ */
+#define X25_TRC_ENABLE 0x01 /* bit0: '1' - trace enabled */
+#define X25_TRC_TIMESTAMP 0x02 /* bit1: '1' - time stamping enabled*/
+#define X25_TRC_DELAY 0x04 /* bit2: '1' - trace delay enabled */
+#define X25_TRC_DATA 0x08 /* bit3: '1' - trace data packets */
+#define X25_TRC_SUPERVISORY 0x10 /* bit4: '1' - trace suprvisory pkts*/
+#define X25_TRC_ASYNCHRONOUS 0x20 /* bit5: '1' - trace asynch. packets*/
+#define X25_TRC_HDLC 0x40 /* bit6: '1' - trace all packets */
+#define X25_TRC_READ 0x80 /* bit7: '1' - get current config. */
+
+/* ---------------------------------------------------------------------------
+ * X25_READ_TRACE_DATA Command.
+ */
+typedef struct X25Trace /*----- Trace data structure -------*/
+{
+ unsigned short length PACKED; /* 00h: trace data length */
+ unsigned char type PACKED; /* 02h: trace type */
+ unsigned char lost_cnt PACKED; /* 03h: N of traces lost */
+ TX25TimeStamp tstamp PACKED; /* 04h: mon/date/sec/min/hour */
+ unsigned short millisec PACKED; /* 09h: ms time stamp */
+ unsigned char data[0] PACKED; /* 0Bh: traced frame */
+} TX25Trace;
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25_TRC_TYPE_MASK 0x0F /* bits 0..3: trace type */
+#define X25_TRC_TYPE_RX_FRAME 0x00 /* received frame trace */
+#define X25_TRC_TYPE_TX_FRAME 0x01 /* transmitted frame */
+#define X25_TRC_TYPE_ERR_FRAME 0x02 /* error frame */
+
+#define X25_TRC_ERROR_MASK 0xF0 /* bits 4..7: error code */
+#define X25_TRCERR_RX_ABORT 0x10 /* receive abort error */
+#define X25_TRCERR_RX_BADCRC 0x20 /* receive CRC error */
+#define X25_TRCERR_RX_OVERRUN 0x30 /* receiver overrun error */
+#define X25_TRCERR_RX_TOO_LONG 0x40 /* excessive frame length error */
+#define X25_TRCERR_TX_ABORT 0x70 /* aborted frame transmission error */
+#define X25_TRCERR_TX_UNDERRUN 0x80 /* transmit underrun error */
+
+/*****************************************************************************
+ * Following definitions describe HDLC frame and X.25 packet formats.
+ ****************************************************************************/
+
+typedef struct HDLCFrame /*----- DHLC Frame Format ----------*/
+{
+ unsigned char addr PACKED; /* address field */
+ unsigned char cntl PACKED; /* control field */
+ unsigned char data[0] PACKED;
+} THDLCFrame;
+
+typedef struct X25Pkt /*----- X.25 Packet Format ----------*/
+{
+ unsigned char lcn_hi PACKED; /* 4 MSB of Logical Channel Number */
+ unsigned char lcn_lo PACKED; /* 8 LSB of Logical Channel Number */
+ unsigned char type PACKED;
+ unsigned char data[0] PACKED;
+} TX25Pkt;
+
+/*
+ * Defines for the 'lcn_hi' field.
+ */
+#define X25_Q_BIT_MASK 0x80 /* Data Qualifier Bit mask */
+#define X25_D_BIT_MASK 0x40 /* Delivery Confirmation Bit mask */
+#define X25_M_BITS_MASK 0x30 /* Modulo Bits mask */
+#define X25_LCN_MSB_MASK 0x0F /* LCN most significant bits mask */
+
+/*
+ * Defines for the 'type' field.
+ */
+#define X25PKT_DATA 0x01 /* Data packet mask */
+#define X25PKT_SUPERVISORY 0x02 /* Supervisory packet mask */
+#define X25PKT_CALL_RQST 0x0B /* Call Request/Incoming */
+#define X25PKT_CALL_ACCEPTED 0x0F /* Call Accepted/Connected */
+#define X25PKT_CLEAR_RQST 0x13 /* Clear Request/Indication */
+#define X25PKT_CLEAR_CONFRM 0x17 /* Clear Confirmation */
+#define X25PKT_RESET_RQST 0x1B /* Reset Request/Indication */
+#define X25PKT_RESET_CONFRM 0x1F /* Reset Confirmation */
+#define X25PKT_RESTART_RQST 0xFB /* Restart Request/Indication */
+#define X25PKT_RESTART_CONFRM 0xFF /* Restart Confirmation */
+#define X25PKT_INTERRUPT 0x23 /* Interrupt */
+#define X25PKT_INTERRUPT_CONFRM 0x27 /* Interrupt Confirmation */
+#define X25PKT_DIAGNOSTIC 0xF1 /* Diagnostic */
+#define X25PKT_REGISTR_RQST 0xF3 /* Registration Request */
+#define X25PKT_REGISTR_CONFRM 0xF7 /* Registration Confirmation */
+#define X25PKT_RR_MASKED 0x01 /* Receive Ready packet after masking */
+#define X25PKT_RNR_MASKED 0x05 /* Receive Not Ready after masking */
+
+#ifdef _MSC_
+# pragma pack()
+#endif
+#endif /* _SDLA_X25_H */
diff --git a/pfinet/linux-src/include/linux/sdladrv.h b/pfinet/linux-src/include/linux/sdladrv.h
new file mode 100644
index 00000000..724fd6c7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdladrv.h
@@ -0,0 +1,77 @@
+/*****************************************************************************
+* sdladrv.h SDLA Support Module. Kernel API Definitions.
+*
+* Author: Gideon Hack
+*
+* Copyright: (c) 1995-1999 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Jun 02, 1999 Gideon Hack Added support for the S514 PCI adapter.
+* Dec 11, 1996 Gene Kozin Complete overhaul.
+* Oct 17, 1996 Gene Kozin Minor bug fixes.
+* Jun 12, 1996 Gene Kozin Added support for S503 card.
+* Dec 06, 1995 Gene Kozin Initial version.
+*****************************************************************************/
+#ifndef _SDLADRV_H
+#define _SDLADRV_H
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 0x020100
+#define LINUX_2_1
+#endif
+
+#define SDLA_MAXIORANGE 4 /* maximum I/O port range */
+#define SDLA_WINDOWSIZE 0x2000 /* default dual-port memory window size */
+
+/****** Data Structures *****************************************************/
+
+/*----------------------------------------------------------------------------
+ * Adapter hardware configuration. Pointer to this structure is passed to all
+ * APIs.
+ */
+typedef struct sdlahw
+{
+ unsigned type; /* adapter type */
+ unsigned fwid; /* firmware ID */
+ unsigned port; /* adapter I/O port base */
+ int irq; /* interrupt request level */
+ char S514_cpu_no[1]; /* PCI CPU Number */
+ unsigned char S514_slot_no; /* PCI Slot Number */
+#ifdef LINUX_2_1
+ struct pci_dev *pci_dev; /* PCI device */
+#else
+ unsigned char pci_bus; /* PCI bus number */
+ unsigned char pci_dev_func; /* PCI device/function number */
+#endif
+ void * dpmbase; /* dual-port memory base */
+ unsigned dpmsize; /* dual-port memory size */
+ unsigned pclk; /* CPU clock rate, kHz */
+ unsigned long memory; /* memory size */
+ unsigned long vector; /* local offset of the DPM window */
+ unsigned io_range; /* I/O port range */
+ unsigned char regs[SDLA_MAXIORANGE]; /* was written to registers */
+ unsigned reserved[5];
+} sdlahw_t;
+
+/****** Function Prototypes *************************************************/
+
+extern int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len);
+extern int sdla_down (sdlahw_t* hw);
+extern int sdla_inten (sdlahw_t* hw);
+extern int sdla_intde (sdlahw_t* hw);
+extern int sdla_intack (sdlahw_t* hw);
+extern void S514_intack (sdlahw_t* hw, u32 int_status);
+extern void read_S514_int_stat (sdlahw_t* hw, u32* int_status);
+extern int sdla_intr (sdlahw_t* hw);
+extern int sdla_mapmem (sdlahw_t* hw, unsigned long addr);
+extern int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf,
+ unsigned len);
+extern int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf,
+ unsigned len);
+extern int sdla_exec (void* opflag);
+
+#endif /* _SDLADRV_H */
diff --git a/pfinet/linux-src/include/linux/sdlapci.h b/pfinet/linux-src/include/linux/sdlapci.h
new file mode 100644
index 00000000..857fd062
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdlapci.h
@@ -0,0 +1,68 @@
+/*****************************************************************************
+* sdlapci.h WANPIPE(tm) Multiprotocol WAN Link Driver.
+* Definitions for the SDLA PCI adapter.
+*
+* Author: Gideon Hack <ghack@sangoma.com>
+*
+* Copyright: (c) 1999 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Jun 02, 1999 Gideon Hack Initial version.
+*****************************************************************************/
+#ifndef _SDLAPCI_H
+#define _SDLAPCI_H
+
+/****** Defines *************************************************************/
+
+/* Definitions for identifying and finding S514 PCI adapters */
+#define V3_VENDOR_ID 0x11B0 /* V3 vendor ID number */
+#define V3_DEVICE_ID 0x0002 /* V3 device ID number */
+#define SANGOMA_SUBSYS_VENDOR 0x4753 /* ID for Sangoma */
+#define PCI_DEV_SLOT_MASK 0x1F /* mask for slot numbering */
+#define PCI_IRQ_NOT_ALLOCATED 0xFF /* interrupt line for no IRQ */
+
+/* Local PCI register offsets */
+#define PCI_VENDOR_ID_WORD 0x00 /* vendor ID */
+#define PCI_IO_BASE_DWORD 0x10 /* IO base */
+#define PCI_MEM_BASE0_DWORD 0x14 /* memory base - apperture 0 */
+#define PCI_MEM_BASE1_DWORD 0x18 /* memory base - apperture 1 */
+#define PCI_SUBSYS_VENDOR_WORD 0x2C /* subsystem vendor ID */
+#define PCI_INT_LINE_BYTE 0x3C /* interrupt line */
+#define PCI_INT_PIN_BYTE 0x3D /* interrupt pin */
+#define PCI_MAP0_DWORD 0x40 /* PCI to local bus address 0 */
+#define PCI_MAP1_DWORD 0x44 /* PCI to local bus address 1 */
+#define PCI_INT_STATUS 0x48 /* interrupt status */
+#define PCI_INT_CONFIG 0x4C /* interrupt configuration */
+
+/* Local PCI register usage */
+#define PCI_MEMORY_ENABLE 0x00000003 /* enable PCI memory */
+#define PCI_CPU_A_MEM_DISABLE 0x00000002 /* disable CPU A memory */
+#define PCI_CPU_B_MEM_DISABLE 0x00100002 /* disable CPU B memory */
+#define PCI_ENABLE_IRQ_CPU_A 0x005A0004 /* enable IRQ for CPU A */
+#define PCI_ENABLE_IRQ_CPU_B 0x005A0008 /* enable IRQ for CPU B */
+#define PCI_DISABLE_IRQ_CPU_A 0x00000004 /* disable IRQ for CPU A */
+#define PCI_DISABLE_IRQ_CPU_B 0x00000008 /* disable IRQ for CPU B */
+
+/* Setting for the Interrupt Status register */
+#define IRQ_CPU_A 0x04 /* IRQ for CPU A */
+#define IRQ_CPU_B 0x08 /* IRQ for CPU B */
+
+/* The maximum size of the S514 memory */
+#define MAX_SIZEOF_S514_MEMORY (256 * 1024)
+
+/* S514 control register offsets within the memory address space */
+#define S514_CTRL_REG_BYTE 0x80000
+
+/* S514 adapter control bytes */
+#define S514_CPU_HALT 0x00
+#define S514_CPU_START 0x01
+
+/* The maximum number of S514 adapters supported */
+#define MAX_S514_CARDS 8
+
+#endif /* _SDLAPCI_H */
+
diff --git a/pfinet/linux-src/include/linux/sdlasfm.h b/pfinet/linux-src/include/linux/sdlasfm.h
new file mode 100644
index 00000000..94aaa8ad
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sdlasfm.h
@@ -0,0 +1,104 @@
+/*****************************************************************************
+* sdlasfm.h WANPIPE(tm) Multiprotocol WAN Link Driver.
+* Definitions for the SDLA Firmware Module (SFM).
+*
+* Author: Gideon Hack
+*
+* Copyright: (c) 1995-1999 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
+* Dec 11, 1996 Gene Kozin Cosmetic changes
+* Apr 16, 1996 Gene Kozin Changed adapter & firmware IDs. Version 2
+* Dec 15, 1995 Gene Kozin Structures chaned
+* Nov 09, 1995 Gene Kozin Initial version.
+*****************************************************************************/
+#ifndef _SDLASFM_H
+#define _SDLASFM_H
+
+/****** Defines *************************************************************/
+
+#define SFM_VERSION 2
+#define SFM_SIGNATURE "SFM - Sangoma SDLA Firmware Module"
+
+/* min/max */
+#define SFM_IMAGE_SIZE 0x8000 /* max size of SDLA code image file */
+#define SFM_DESCR_LEN 256 /* max length of description string */
+#define SFM_MAX_SDLA 16 /* max number of compatible adapters */
+
+/* Adapter types */
+#define SDLA_S502A 5020
+#define SDLA_S502E 5021
+#define SDLA_S503 5030
+#define SDLA_S508 5080
+#define SDLA_S507 5070
+#define SDLA_S509 5090
+#define SDLA_S514 5140
+
+/* S514 PCI adapter CPU numbers */
+#define S514_CPU_A 'A'
+#define S514_CPU_B 'B'
+
+
+/* Firmware identification numbers:
+ * 0 .. 999 Test & Diagnostics
+ * 1000 .. 1999 Streaming HDLC
+ * 2000 .. 2999 Bisync
+ * 3000 .. 3999 SDLC
+ * 4000 .. 4999 HDLC
+ * 5000 .. 5999 X.25
+ * 6000 .. 6999 Frame Relay
+ * 7000 .. 7999 PPP
+ * 8000 .. 8999 Cisco HDLC
+ */
+#define SFID_CALIB502 200
+#define SFID_STRM502 1200
+#define SFID_STRM508 1800
+#define SFID_BSC502 2200
+#define SFID_SDLC502 3200
+#define SFID_HDLC502 4200
+#define SFID_HDLC508 4800
+#define SFID_X25_502 5200
+#define SFID_X25_508 5800
+#define SFID_FR502 6200
+#define SFID_FR508 6800
+#define SFID_PPP502 7200
+#define SFID_PPP508 7800
+#define SFID_PPP514 7140
+#define SFID_CHDLC508 8800
+#define SFID_CHDLC514 8140
+
+/****** Data Types **********************************************************/
+
+typedef struct sfm_info /* firmware module information */
+{
+ unsigned short codeid; /* firmware ID */
+ unsigned short version; /* firmaware version number */
+ unsigned short adapter[SFM_MAX_SDLA]; /* compatible adapter types */
+ unsigned long memsize; /* minimum memory size */
+ unsigned short reserved[2]; /* reserved */
+ unsigned short startoffs; /* entry point offset */
+ unsigned short winoffs; /* dual-port memory window offset */
+ unsigned short codeoffs; /* code load offset */
+ unsigned short codesize; /* code size */
+ unsigned short dataoffs; /* configuration data load offset */
+ unsigned short datasize; /* configuration data size */
+} sfm_info_t;
+
+typedef struct sfm /* SDLA firmware file structire */
+{
+ char signature[80]; /* SFM file signature */
+ unsigned short version; /* file format version */
+ unsigned short checksum; /* info + image */
+ unsigned short reserved[6]; /* reserved */
+ char descr[SFM_DESCR_LEN]; /* description string */
+ sfm_info_t info; /* firmware module info */
+ unsigned char image[1]; /* code image (variable size) */
+} sfm_t;
+
+#endif /* _SDLASFM_H */
+
diff --git a/pfinet/linux-src/include/linux/securebits.h b/pfinet/linux-src/include/linux/securebits.h
new file mode 100644
index 00000000..1e10badc
--- /dev/null
+++ b/pfinet/linux-src/include/linux/securebits.h
@@ -0,0 +1,30 @@
+#ifndef _LINUX_SECUREBITS_H
+#define _LINUX_SECUREBITS_H 1
+
+#define SECUREBITS_DEFAULT 0x00000000
+
+extern unsigned securebits;
+
+/* When set UID 0 has no special privileges. When unset, we support
+ inheritance of root-permissions and suid-root executablew under
+ compatibility mode. We raise the effective and inheritable bitmasks
+ *of the executable file* if the effective uid of the new process is
+ 0. If the real uid is 0, we raise the inheritable bitmask of the
+ executable file. */
+#define SECURE_NOROOT 0
+
+/* When set, setuid to/from uid 0 does not trigger capability-"fixes"
+ to be compatible with old programs relying on set*uid to loose
+ privileges. When unset, setuid doesn't change privileges. */
+#define SECURE_NO_SETUID_FIXUP 2
+
+/* Each securesetting is implemented using two bits. One bit specify
+ whether the setting is on or off. The other bit specify whether the
+ setting is fixed or not. A setting which is fixed cannot be changed
+ from user-level. */
+
+#define issecure(X) ( (1 << (X+1)) & SECUREBITS_DEFAULT ? \
+ (1 << (X)) & SECUREBITS_DEFAULT : \
+ (1 << (X)) & securebits )
+
+#endif /* !_LINUX_SECUREBITS_H */
diff --git a/pfinet/linux-src/include/linux/selection.h b/pfinet/linux-src/include/linux/selection.h
new file mode 100644
index 00000000..74d1b24d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/selection.h
@@ -0,0 +1,44 @@
+/*
+ * selection.h
+ *
+ * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c
+ */
+
+#ifndef _LINUX_SELECTION_H_
+#define _LINUX_SELECTION_H_
+
+#include <linux/vt_buffer.h>
+
+extern int sel_cons;
+
+extern void clear_selection(void);
+extern int set_selection(const unsigned long arg, struct tty_struct *tty, int user);
+extern int paste_selection(struct tty_struct *tty);
+extern int sel_loadlut(const unsigned long arg);
+extern int mouse_reporting(void);
+extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
+
+#define video_num_columns (vc_cons[currcons].d->vc_cols)
+#define video_num_lines (vc_cons[currcons].d->vc_rows)
+#define video_size_row (vc_cons[currcons].d->vc_size_row)
+#define can_do_color (vc_cons[currcons].d->vc_can_do_color)
+
+extern int console_blanked;
+
+extern unsigned char color_table[];
+extern int default_red[];
+extern int default_grn[];
+extern int default_blu[];
+
+extern unsigned short *screen_pos(int currcons, int w_offset, int viewed);
+extern u16 screen_glyph(int currcons, int offset);
+extern void complement_pos(int currcons, int offset);
+extern void invert_screen(int currcons, int offset, int count, int shift);
+
+extern void getconsxy(int currcons, char *p);
+extern void putconsxy(int currcons, char *p);
+
+extern u16 vcs_scr_readw(int currcons, const u16 *org);
+extern void vcs_scr_writew(int currcons, u16 val, u16 *org);
+
+#endif
diff --git a/pfinet/linux-src/include/linux/sem.h b/pfinet/linux-src/include/linux/sem.h
new file mode 100644
index 00000000..13c9a8ac
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sem.h
@@ -0,0 +1,114 @@
+#ifndef _LINUX_SEM_H
+#define _LINUX_SEM_H
+
+#include <linux/ipc.h>
+
+/* semop flags */
+#define SEM_UNDO 0x1000 /* undo the operation on exit */
+
+/* semctl Command Definitions. */
+#define GETPID 11 /* get sempid */
+#define GETVAL 12 /* get semval */
+#define GETALL 13 /* get all semval's */
+#define GETNCNT 14 /* get semncnt */
+#define GETZCNT 15 /* get semzcnt */
+#define SETVAL 16 /* set semval */
+#define SETALL 17 /* set all semval's */
+
+/* ipcs ctl cmds */
+#define SEM_STAT 18
+#define SEM_INFO 19
+
+/* One semid data structure for each set of semaphores in the system. */
+struct semid_ds {
+ struct ipc_perm sem_perm; /* permissions .. see ipc.h */
+ __kernel_time_t sem_otime; /* last semop time */
+ __kernel_time_t sem_ctime; /* last change time */
+ struct sem *sem_base; /* ptr to first semaphore in array */
+ struct sem_queue *sem_pending; /* pending operations to be processed */
+ struct sem_queue **sem_pending_last; /* last pending operation */
+ struct sem_undo *undo; /* undo requests on this array */
+ unsigned short sem_nsems; /* no. of semaphores in array */
+};
+
+/* semop system calls takes an array of these. */
+struct sembuf {
+ unsigned short sem_num; /* semaphore index in array */
+ short sem_op; /* semaphore operation */
+ short sem_flg; /* operation flags */
+};
+
+/* arg for semctl system calls. */
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
+ unsigned short *array; /* array for GETALL & SETALL */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+ void *__pad;
+};
+
+struct seminfo {
+ int semmap;
+ int semmni;
+ int semmns;
+ int semmnu;
+ int semmsl;
+ int semopm;
+ int semume;
+ int semusz;
+ int semvmx;
+ int semaem;
+};
+
+#define SEMMNI 128 /* ? max # of semaphore identifiers */
+#define SEMMSL 250 /* <= 512 max num of semaphores per id */
+#define SEMMNS (SEMMNI*SEMMSL) /* ? max # of semaphores in system */
+#define SEMOPM 32 /* ~ 100 max num of ops per semop call */
+#define SEMVMX 32767 /* semaphore maximum value */
+
+/* unused */
+#define SEMUME SEMOPM /* max num of undo entries per process */
+#define SEMMNU SEMMNS /* num of undo structures system wide */
+#define SEMAEM (SEMVMX >> 1) /* adjust on exit max value */
+#define SEMMAP SEMMNS /* # of entries in semaphore map */
+#define SEMUSZ 20 /* sizeof struct sem_undo */
+
+#ifdef __KERNEL__
+
+/* One semaphore structure for each semaphore in the system. */
+struct sem {
+ int semval; /* current value */
+ int sempid; /* pid of last operation */
+};
+
+/* One queue for each semaphore set in the system. */
+struct sem_queue {
+ struct sem_queue * next; /* next entry in the queue */
+ struct sem_queue ** prev; /* previous entry in the queue, *(q->prev) == q */
+ struct wait_queue * sleeper; /* sleeping process */
+ struct sem_undo * undo; /* undo structure */
+ int pid; /* process id of requesting process */
+ int status; /* completion status of operation */
+ struct semid_ds * sma; /* semaphore array for operations */
+ struct sembuf * sops; /* array of pending operations */
+ int nsops; /* number of operations */
+ int alter; /* operation will alter semaphore */
+};
+
+/* Each task has a list of undo requests. They are executed automatically
+ * when the process exits.
+ */
+struct sem_undo {
+ struct sem_undo * proc_next; /* next entry on this process */
+ struct sem_undo * id_next; /* next entry on this semaphore set */
+ int semid; /* semaphore set identifier */
+ short * semadj; /* array of adjustments, one per semaphore */
+};
+
+asmlinkage int sys_semget (key_t key, int nsems, int semflg);
+asmlinkage int sys_semop (int semid, struct sembuf *sops, unsigned nsops);
+asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SEM_H */
diff --git a/pfinet/linux-src/include/linux/serial.h b/pfinet/linux-src/include/linux/serial.h
new file mode 100644
index 00000000..929618dd
--- /dev/null
+++ b/pfinet/linux-src/include/linux/serial.h
@@ -0,0 +1,142 @@
+/*
+ * include/linux/serial.h
+ *
+ * Copyright (C) 1992 by Theodore Ts'o.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _LINUX_SERIAL_H
+#define _LINUX_SERIAL_H
+
+struct serial_struct {
+ int type;
+ int line;
+ int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char reserved_char[2];
+ int hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ int reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output. 65535 means don't wait at all.
+ */
+#define ASYNC_CLOSING_WAIT_INF 0
+#define ASYNC_CLOSING_WAIT_NONE 65535
+
+/*
+ * These are the supported serial types.
+ */
+#define PORT_UNKNOWN 0
+#define PORT_8250 1
+#define PORT_16450 2
+#define PORT_16550 3
+#define PORT_16550A 4
+#define PORT_CIRRUS 5 /* usurped by cyclades.c */
+#define PORT_16650 6
+#define PORT_16650V2 7
+#define PORT_16750 8
+#define PORT_STARTECH 9 /* usurped by cyclades.c */
+#define PORT_MAX 9
+
+struct serial_uart_config {
+ char *name;
+ int dfl_xmit_fifo_size;
+ int flags;
+};
+
+#define UART_CLEAR_FIFO 0x01
+#define UART_USE_FIFO 0x02
+#define UART_STARTECH 0x04
+
+/*
+ * Definitions for async_struct (and serial_struct) flags field
+ */
+#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
+ on the callout port */
+#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ASYNC_SPD_MASK 0x1030
+#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+
+#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ASYNC_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define ASYNC_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define ASYNC_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ASYNC_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define ASYNC_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define ASYNC_HARDPPS_CD 0x0800 /* Call hardpps when CD goes high */
+
+#define ASYNC_SPD_SHI 0x1000 /* Use 230400 instead of 38400 bps */
+#define ASYNC_SPD_WARP 0x1010 /* Use 460800 instead of 38400 bps */
+
+#define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */
+
+#define ASYNC_FLAGS 0x3FFF /* Possible legal async flags */
+#define ASYNC_USR_MASK 0x3430 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define ASYNC_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */
+#define ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+#define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards */
+
+#define ASYNC_INTERNAL_FLAGS 0xFF000000 /* Internal flags */
+
+/*
+ * Multiport serial configuration structure --- external structure
+ */
+struct serial_multiport_struct {
+ int irq;
+ int port1;
+ unsigned char mask1, match1;
+ int port2;
+ unsigned char mask2, match2;
+ int port3;
+ unsigned char mask3, match3;
+ int port4;
+ unsigned char mask4, match4;
+ int port_monitor;
+ int reserved[32];
+};
+
+/*
+ * Serial input interrupt line counters -- external structure
+ * Four lines can interrupt: CTS, DSR, RI, DCD
+ */
+struct serial_icounter_struct {
+ int cts, dsr, rng, dcd;
+ int rx, tx;
+ int frame, overrun, parity, brk;
+ int buf_overrun;
+ int reserved[9];
+};
+
+
+#ifdef __KERNEL__
+/* Export to allow PCMCIA to use this - Dave Hinds */
+extern int register_serial(struct serial_struct *req);
+extern void unregister_serial(int line);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_SERIAL_H */
diff --git a/pfinet/linux-src/include/linux/serial167.h b/pfinet/linux-src/include/linux/serial167.h
new file mode 100644
index 00000000..9f01f361
--- /dev/null
+++ b/pfinet/linux-src/include/linux/serial167.h
@@ -0,0 +1,175 @@
+/*
+ * serial167.h
+ *
+ * Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on cyclades.h
+ */
+
+struct cyclades_monitor {
+ unsigned long int_count;
+ unsigned long char_count;
+ unsigned long char_max;
+ unsigned long char_last;
+};
+
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct cyclades_port {
+ int magic;
+ int type;
+ int card;
+ int line;
+ int flags; /* defined in tty.h */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int timeout;
+ int xmit_fifo_size;
+ int cor1,cor2,cor3,cor4,cor5,cor6,cor7;
+ int tbpr,tco,rbpr,rco;
+ int ignore_status_mask;
+ int close_delay;
+ int IER; /* Interrupt Enable Register */
+ int event;
+ unsigned long last_active;
+ int count; /* # of fd on device */
+ int x_char; /* to be pushed out ASAP */
+ int x_break;
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ int default_threshold;
+ int default_timeout;
+ struct tq_struct tqueue;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct cyclades_monitor mon;
+};
+
+#define CYCLADES_MAGIC 0x4359
+
+#define CYGETMON 0x435901
+#define CYGETTHRESH 0x435902
+#define CYSETTHRESH 0x435903
+#define CYGETDEFTHRESH 0x435904
+#define CYSETDEFTHRESH 0x435905
+#define CYGETTIMEOUT 0x435906
+#define CYSETTIMEOUT 0x435907
+#define CYGETDEFTIMEOUT 0x435908
+#define CYSETDEFTIMEOUT 0x435909
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at cy interrupt time.
+ */
+#define Cy_EVENT_READ_PROCESS 0
+#define Cy_EVENT_WRITE_WAKEUP 1
+#define Cy_EVENT_HANGUP 2
+#define Cy_EVENT_BREAK 3
+#define Cy_EVENT_OPEN_WAKEUP 4
+
+
+
+#define CyMaxChipsPerCard 1
+
+/**** cd2401 registers ****/
+
+#define CyGFRCR (0x81)
+#define CyCCR (0x13)
+#define CyCLR_CHAN (0x40)
+#define CyINIT_CHAN (0x20)
+#define CyCHIP_RESET (0x10)
+#define CyENB_XMTR (0x08)
+#define CyDIS_XMTR (0x04)
+#define CyENB_RCVR (0x02)
+#define CyDIS_RCVR (0x01)
+#define CyCAR (0xee)
+#define CyIER (0x11)
+#define CyMdmCh (0x80)
+#define CyRxExc (0x20)
+#define CyRxData (0x08)
+#define CyTxMpty (0x02)
+#define CyTxRdy (0x01)
+#define CyLICR (0x26)
+#define CyRISR (0x89)
+#define CyTIMEOUT (0x80)
+#define CySPECHAR (0x70)
+#define CyOVERRUN (0x08)
+#define CyPARITY (0x04)
+#define CyFRAME (0x02)
+#define CyBREAK (0x01)
+#define CyREOIR (0x84)
+#define CyTEOIR (0x85)
+#define CyMEOIR (0x86)
+#define CyNOTRANS (0x08)
+#define CyRFOC (0x30)
+#define CyRDR (0xf8)
+#define CyTDR (0xf8)
+#define CyMISR (0x8b)
+#define CyRISR (0x89)
+#define CyTISR (0x8a)
+#define CyMSVR1 (0xde)
+#define CyMSVR2 (0xdf)
+#define CyDSR (0x80)
+#define CyDCD (0x40)
+#define CyCTS (0x20)
+#define CyDTR (0x02)
+#define CyRTS (0x01)
+#define CyRTPRL (0x25)
+#define CyRTPRH (0x24)
+#define CyCOR1 (0x10)
+#define CyPARITY_NONE (0x00)
+#define CyPARITY_E (0x40)
+#define CyPARITY_O (0xC0)
+#define Cy_5_BITS (0x04)
+#define Cy_6_BITS (0x05)
+#define Cy_7_BITS (0x06)
+#define Cy_8_BITS (0x07)
+#define CyCOR2 (0x17)
+#define CyETC (0x20)
+#define CyCtsAE (0x02)
+#define CyCOR3 (0x16)
+#define Cy_1_STOP (0x02)
+#define Cy_2_STOP (0x04)
+#define CyCOR4 (0x15)
+#define CyREC_FIFO (0x0F) /* Receive FIFO threshold */
+#define CyCOR5 (0x14)
+#define CyCOR6 (0x18)
+#define CyCOR7 (0x07)
+#define CyRBPR (0xcb)
+#define CyRCOR (0xc8)
+#define CyTBPR (0xc3)
+#define CyTCOR (0xc0)
+#define CySCHR1 (0x1f)
+#define CySCHR2 (0x1e)
+#define CyTPR (0xda)
+#define CyPILR1 (0xe3)
+#define CyPILR2 (0xe0)
+#define CyPILR3 (0xe1)
+#define CyCMR (0x1b)
+#define CyASYNC (0x02)
+#define CyLICR (0x26)
+#define CyLIVR (0x09)
+#define CySCRL (0x23)
+#define CySCRH (0x22)
+#define CyTFTC (0x80)
+
+
+/* max number of chars in the FIFO */
+
+#define CyMAX_CHAR_FIFO 12
+
+/***************************************************************************/
diff --git a/pfinet/linux-src/include/linux/serialP.h b/pfinet/linux-src/include/linux/serialP.h
new file mode 100644
index 00000000..6bf0746e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/serialP.h
@@ -0,0 +1,119 @@
+/*
+ * Private header file for the (dumb) serial driver
+ *
+ * Copyright (C) 1997 by Theodore Ts'o.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _LINUX_SERIALP_H
+#define _LINUX_SERIALP_H
+
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+#include <linux/termios.h>
+#include <linux/tqueue.h>
+
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+struct async_icount {
+ __u32 cts, dsr, rng, dcd, tx, rx;
+ __u32 frame, parity, overrun, brk;
+ __u32 buf_overrun;
+};
+
+struct serial_state {
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+ int flags;
+ int hub6;
+ int type;
+ int line;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int count;
+ unsigned short close_delay;
+ unsigned short closing_wait; /* time to wait before closing */
+ struct async_icount icount;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct async_struct *info;
+};
+
+struct async_struct {
+ int magic;
+ int port;
+ int hub6;
+ int flags;
+ int xmit_fifo_size;
+ struct serial_state *state;
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int quot;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct tq_struct tqueue;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *delta_msr_wait;
+ struct async_struct *next_port; /* For the linked list */
+ struct async_struct *prev_port;
+};
+
+#define SERIAL_MAGIC 0x5301
+#define SSTATE_MAGIC 0x5302
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+/*
+ * Multiport serial configuration structure --- internal structure
+ */
+struct rs_multiport_struct {
+ int port1;
+ unsigned char mask1, match1;
+ int port2;
+ unsigned char mask2, match2;
+ int port3;
+ unsigned char mask3, match3;
+ int port4;
+ unsigned char mask4, match4;
+ int port_monitor;
+};
+
+#endif /* _LINUX_SERIAL_H */
diff --git a/pfinet/linux-src/include/linux/serial_reg.h b/pfinet/linux-src/include/linux/serial_reg.h
new file mode 100644
index 00000000..713227a5
--- /dev/null
+++ b/pfinet/linux-src/include/linux/serial_reg.h
@@ -0,0 +1,144 @@
+/*
+ * include/linux/serial_reg.h
+ *
+ * Copyright (C) 1992, 1994 by Theodore Ts'o.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ *
+ * These are the UART port assignments, expressed as offsets from the base
+ * register. These assignments should hold for any serial port based on
+ * a 8250, 16450, or 16550(A).
+ */
+
+#ifndef _LINUX_SERIAL_REG_H
+#define _LINUX_SERIAL_REG_H
+
+#define UART_RX 0 /* In: Receive buffer (DLAB=0) */
+#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */
+#define UART_IER 1 /* Out: Interrupt Enable Register */
+#define UART_IIR 2 /* In: Interrupt ID Register */
+#define UART_FCR 2 /* Out: FIFO Control Register */
+#define UART_EFR 2 /* I/O: Extended Features Register */
+ /* (DLAB=1, 16C660 only) */
+#define UART_LCR 3 /* Out: Line Control Register */
+#define UART_MCR 4 /* Out: Modem Control Register */
+#define UART_LSR 5 /* In: Line Status Register */
+#define UART_MSR 6 /* In: Modem Status Register */
+#define UART_SCR 7 /* I/O: Scratch Register */
+
+/*
+ * These are the definitions for the FIFO Control Register
+ * (16650 only)
+ */
+#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
+#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
+#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
+#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */
+#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
+#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */
+#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
+#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
+#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
+/* 16650 redefinitions */
+#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
+#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
+#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
+#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
+#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
+#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
+#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
+#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
+/* TI 16750 definitions */
+#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode */
+
+/*
+ * These are the definitions for the Line Control Register
+ *
+ * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
+ * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
+ */
+#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
+#define UART_LCR_SBC 0x40 /* Set break control */
+#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
+#define UART_LCR_EPAR 0x10 /* Even parity select */
+#define UART_LCR_PARITY 0x08 /* Parity Enable */
+#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
+#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
+#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
+#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
+#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
+
+/*
+ * These are the definitions for the Line Status Register
+ */
+#define UART_LSR_TEMT 0x40 /* Transmitter empty */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+#define UART_LSR_BI 0x10 /* Break interrupt indicator */
+#define UART_LSR_FE 0x08 /* Frame error indicator */
+#define UART_LSR_PE 0x04 /* Parity error indicator */
+#define UART_LSR_OE 0x02 /* Overrun error indicator */
+#define UART_LSR_DR 0x01 /* Receiver data ready */
+
+/*
+ * These are the definitions for the Interrupt Identification Register
+ */
+#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
+#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
+
+#define UART_IIR_MSI 0x00 /* Modem status interrupt */
+#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
+#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
+#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
+
+/*
+ * These are the definitions for the Interrupt Enable Register
+ */
+#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
+#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
+#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
+#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
+/*
+ * Sleep mode for ST16650 and TI16750.
+ * Note that for 16650, EFR-bit 4 must be selected as well.
+ */
+#define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
+
+/*
+ * These are the definitions for the Modem Control Register
+ */
+#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
+#define UART_MCR_OUT2 0x08 /* Out2 complement */
+#define UART_MCR_OUT1 0x04 /* Out1 complement */
+#define UART_MCR_RTS 0x02 /* RTS complement */
+#define UART_MCR_DTR 0x01 /* DTR complement */
+
+/*
+ * These are the definitions for the Modem Status Register
+ */
+#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
+#define UART_MSR_RI 0x40 /* Ring Indicator */
+#define UART_MSR_DSR 0x20 /* Data Set Ready */
+#define UART_MSR_CTS 0x10 /* Clear to Send */
+#define UART_MSR_DDCD 0x08 /* Delta DCD */
+#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
+#define UART_MSR_DDSR 0x02 /* Delta DSR */
+#define UART_MSR_DCTS 0x01 /* Delta CTS */
+#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
+
+/*
+ * These are the definitions for the Extended Features Register
+ * (StarTech 16C660 only, when DLAB=1)
+ */
+#define UART_EFR_CTS 0x80 /* CTS flow control */
+#define UART_EFR_RTS 0x40 /* RTS flow control */
+#define UART_EFR_SCD 0x20 /* Special character detect */
+#define UART_EFR_ECB 0x10 /* Enhanced control bit */
+/*
+ * the low four bits control software flow control
+ */
+
+#endif /* _LINUX_SERIAL_REG_H */
+
diff --git a/pfinet/linux-src/include/linux/shm.h b/pfinet/linux-src/include/linux/shm.h
new file mode 100644
index 00000000..a6d13e8d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/shm.h
@@ -0,0 +1,79 @@
+#ifndef _LINUX_SHM_H_
+#define _LINUX_SHM_H_
+
+#include <linux/ipc.h>
+
+#include <asm/shmparam.h>
+
+struct shmid_ds {
+ struct ipc_perm shm_perm; /* operation perms */
+ int shm_segsz; /* size of segment (bytes) */
+ __kernel_time_t shm_atime; /* last attach time */
+ __kernel_time_t shm_dtime; /* last detach time */
+ __kernel_time_t shm_ctime; /* last change time */
+ __kernel_ipc_pid_t shm_cpid; /* pid of creator */
+ __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
+ unsigned short shm_nattch; /* no. of current attaches */
+ unsigned short shm_unused; /* compatibility */
+ void *shm_unused2; /* ditto - used by DIPC */
+ void *shm_unused3; /* unused */
+};
+
+struct shmid_kernel
+{
+ struct shmid_ds u;
+ /* the following are private */
+ unsigned long shm_npages; /* size of segment (pages) */
+ unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */
+ struct vm_area_struct *attaches; /* descriptors for attaches */
+};
+
+/* permission flag for shmget */
+#define SHM_R 0400 /* or S_IRUGO from <linux/stat.h> */
+#define SHM_W 0200 /* or S_IWUGO from <linux/stat.h> */
+
+/* mode for attach */
+#define SHM_RDONLY 010000 /* read-only access */
+#define SHM_RND 020000 /* round attach address to SHMLBA boundary */
+#define SHM_REMAP 040000 /* take-over region on attach */
+
+/* super user shmctl commands */
+#define SHM_LOCK 11
+#define SHM_UNLOCK 12
+
+/* ipcs ctl commands */
+#define SHM_STAT 13
+#define SHM_INFO 14
+
+struct shminfo {
+ int shmmax;
+ int shmmin;
+ int shmmni;
+ int shmseg;
+ int shmall;
+};
+
+struct shm_info {
+ int used_ids;
+ unsigned long shm_tot; /* total allocated shm */
+ unsigned long shm_rss; /* total resident shm */
+ unsigned long shm_swp; /* total swapped shm */
+ unsigned long swap_attempts;
+ unsigned long swap_successes;
+};
+
+#ifdef __KERNEL__
+
+/* shm_mode upper byte flags */
+#define SHM_DEST 01000 /* segment will be destroyed on last detach */
+#define SHM_LOCKED 02000 /* segment will not be swapped */
+
+asmlinkage int sys_shmget (key_t key, int size, int flag);
+asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr);
+asmlinkage int sys_shmdt (char *shmaddr);
+asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
+extern void shm_unuse(unsigned long entry, unsigned long page);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SHM_H_ */
diff --git a/pfinet/linux-src/include/linux/signal.h b/pfinet/linux-src/include/linux/signal.h
new file mode 100644
index 00000000..d6e82ae0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/signal.h
@@ -0,0 +1,212 @@
+#ifndef _LINUX_SIGNAL_H
+#define _LINUX_SIGNAL_H
+
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+
+#ifdef __KERNEL__
+/*
+ * Real Time signals may be queued.
+ */
+
+struct signal_queue
+{
+ struct signal_queue *next;
+ siginfo_t info;
+};
+
+/*
+ * Define some primitives to manipulate sigset_t.
+ */
+
+#ifndef __HAVE_ARCH_SIG_BITOPS
+#include <asm/bitops.h>
+
+/* We don't use <asm/bitops.h> for these because there is no need to
+ be atomic. */
+extern inline void sigaddset(sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+ if (_NSIG_WORDS == 1)
+ set->sig[0] |= 1UL << sig;
+ else
+ set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW);
+}
+
+extern inline void sigdelset(sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+ if (_NSIG_WORDS == 1)
+ set->sig[0] &= ~(1UL << sig);
+ else
+ set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW));
+}
+
+extern inline int sigismember(sigset_t *set, int _sig)
+{
+ unsigned long sig = _sig - 1;
+ if (_NSIG_WORDS == 1)
+ return 1 & (set->sig[0] >> sig);
+ else
+ return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
+}
+
+extern inline int sigfindinword(unsigned long word)
+{
+ return ffz(~word);
+}
+
+#define sigmask(sig) (1UL << ((sig) - 1))
+
+#endif /* __HAVE_ARCH_SIG_BITOPS */
+
+#ifndef __HAVE_ARCH_SIG_SETOPS
+#include <linux/string.h>
+
+#define _SIG_SET_BINOP(name, op) \
+extern inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \
+{ \
+ unsigned long a0, a1, a2, a3, b0, b1, b2, b3; \
+ unsigned long i; \
+ \
+ for (i = 0; i < _NSIG_WORDS/4; ++i) { \
+ a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; \
+ a2 = a->sig[4*i+2]; a3 = a->sig[4*i+3]; \
+ b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; \
+ b2 = b->sig[4*i+2]; b3 = b->sig[4*i+3]; \
+ r->sig[4*i+0] = op(a0, b0); \
+ r->sig[4*i+1] = op(a1, b1); \
+ r->sig[4*i+2] = op(a2, b2); \
+ r->sig[4*i+3] = op(a3, b3); \
+ } \
+ switch (_NSIG_WORDS % 4) { \
+ case 3: \
+ a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; a2 = a->sig[4*i+2]; \
+ b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; b2 = b->sig[4*i+2]; \
+ r->sig[4*i+0] = op(a0, b0); \
+ r->sig[4*i+1] = op(a1, b1); \
+ r->sig[4*i+2] = op(a2, b2); \
+ break; \
+ case 2: \
+ a0 = a->sig[4*i+0]; a1 = a->sig[4*i+1]; \
+ b0 = b->sig[4*i+0]; b1 = b->sig[4*i+1]; \
+ r->sig[4*i+0] = op(a0, b0); \
+ r->sig[4*i+1] = op(a1, b1); \
+ break; \
+ case 1: \
+ a0 = a->sig[4*i+0]; b0 = b->sig[4*i+0]; \
+ r->sig[4*i+0] = op(a0, b0); \
+ break; \
+ } \
+}
+
+#define _sig_or(x,y) ((x) | (y))
+_SIG_SET_BINOP(sigorsets, _sig_or)
+
+#define _sig_and(x,y) ((x) & (y))
+_SIG_SET_BINOP(sigandsets, _sig_and)
+
+#define _sig_nand(x,y) ((x) & ~(y))
+_SIG_SET_BINOP(signandsets, _sig_nand)
+
+#undef _SIG_SET_BINOP
+#undef _sig_or
+#undef _sig_and
+#undef _sig_nand
+
+#define _SIG_SET_OP(name, op) \
+extern inline void name(sigset_t *set) \
+{ \
+ unsigned long i; \
+ \
+ for (i = 0; i < _NSIG_WORDS/4; ++i) { \
+ set->sig[4*i+0] = op(set->sig[4*i+0]); \
+ set->sig[4*i+1] = op(set->sig[4*i+1]); \
+ set->sig[4*i+2] = op(set->sig[4*i+2]); \
+ set->sig[4*i+3] = op(set->sig[4*i+3]); \
+ } \
+ switch (_NSIG_WORDS % 4) { \
+ case 3: set->sig[4*i+2] = op(set->sig[4*i+2]); \
+ case 2: set->sig[4*i+1] = op(set->sig[4*i+1]); \
+ case 1: set->sig[4*i+0] = op(set->sig[4*i+0]); \
+ } \
+}
+
+#define _sig_not(x) (~(x))
+_SIG_SET_OP(signotset, _sig_not)
+
+#undef _SIG_SET_OP
+#undef _sig_not
+
+extern inline void sigemptyset(sigset_t *set)
+{
+ switch (_NSIG_WORDS) {
+ default:
+ memset(set, 0, sizeof(sigset_t));
+ break;
+ case 2: set->sig[1] = 0;
+ case 1: set->sig[0] = 0;
+ break;
+ }
+}
+
+extern inline void sigfillset(sigset_t *set)
+{
+ switch (_NSIG_WORDS) {
+ default:
+ memset(set, -1, sizeof(sigset_t));
+ break;
+ case 2: set->sig[1] = -1;
+ case 1: set->sig[0] = -1;
+ break;
+ }
+}
+
+extern char * render_sigset_t(sigset_t *set, char *buffer);
+
+/* Some extensions for manipulating the low 32 signals in particular. */
+
+extern inline void sigaddsetmask(sigset_t *set, unsigned long mask)
+{
+ set->sig[0] |= mask;
+}
+
+extern inline void sigdelsetmask(sigset_t *set, unsigned long mask)
+{
+ set->sig[0] &= ~mask;
+}
+
+extern inline int sigtestsetmask(sigset_t *set, unsigned long mask)
+{
+ return (set->sig[0] & mask) != 0;
+}
+
+extern inline void siginitset(sigset_t *set, unsigned long mask)
+{
+ set->sig[0] = mask;
+ switch (_NSIG_WORDS) {
+ default:
+ memset(&set->sig[1], 0, sizeof(long)*(_NSIG_WORDS-1));
+ break;
+ case 2: set->sig[1] = 0;
+ case 1:
+ }
+}
+
+extern inline void siginitsetinv(sigset_t *set, unsigned long mask)
+{
+ set->sig[0] = ~mask;
+ switch (_NSIG_WORDS) {
+ default:
+ memset(&set->sig[1], -1, sizeof(long)*(_NSIG_WORDS-1));
+ break;
+ case 2: set->sig[1] = -1;
+ case 1:
+ }
+}
+
+#endif /* __HAVE_ARCH_SIG_SETOPS */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SIGNAL_H */
diff --git a/pfinet/linux-src/include/linux/skbuff.h b/pfinet/linux-src/include/linux/skbuff.h
new file mode 100644
index 00000000..82d5da6e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/skbuff.h
@@ -0,0 +1,584 @@
+/*
+ * Definitions for the 'struct sk_buff' memory handlers.
+ *
+ * Authors:
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Florian La Roche, <rzsfl@rz.uni-sb.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_SKBUFF_H
+#define _LINUX_SKBUFF_H
+
+#include <linux/config.h>
+#include <linux/time.h>
+
+#include <asm/atomic.h>
+#include <asm/types.h>
+#include <asm/spinlock.h>
+
+#define HAVE_ALLOC_SKB /* For the drivers to know */
+#define HAVE_ALIGNABLE_SKB /* Ditto 8) */
+#define SLAB_SKB /* Slabified skbuffs */
+
+#define CHECKSUM_NONE 0
+#define CHECKSUM_HW 1
+#define CHECKSUM_UNNECESSARY 2
+
+struct sk_buff_head {
+ struct sk_buff * next;
+ struct sk_buff * prev;
+ __u32 qlen; /* Must be same length as a pointer
+ for using debugging */
+};
+
+struct sk_buff {
+ struct sk_buff * next; /* Next buffer in list */
+ struct sk_buff * prev; /* Previous buffer in list */
+ struct sk_buff_head * list; /* List we are on */
+ struct sock *sk; /* Socket we are owned by */
+ struct timeval stamp; /* Time we arrived */
+ struct device *dev; /* Device we arrived on/are leaving by */
+
+ /* Transport layer header */
+ union
+ {
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct icmphdr *icmph;
+ struct igmphdr *igmph;
+ struct iphdr *ipiph;
+ struct spxhdr *spxh;
+ unsigned char *raw;
+ } h;
+
+ /* Network layer header */
+ union
+ {
+ struct iphdr *iph;
+ struct ipv6hdr *ipv6h;
+ struct arphdr *arph;
+ struct ipxhdr *ipxh;
+ unsigned char *raw;
+ } nh;
+
+ /* Link layer header */
+ union
+ {
+ struct ethhdr *ethernet;
+ unsigned char *raw;
+ } mac;
+
+ struct dst_entry *dst;
+
+ char cb[48];
+
+ unsigned int len; /* Length of actual data */
+ unsigned int csum; /* Checksum */
+ volatile char used; /* Data moved to user and not MSG_PEEK */
+ unsigned char is_clone, /* We are a clone */
+ cloned, /* head may be cloned (check refcnt to be sure). */
+ pkt_type, /* Packet class */
+ pkt_bridged, /* Tracker for bridging */
+ ip_summed; /* Driver fed us an IP checksum */
+ __u32 priority; /* Packet queueing priority */
+ atomic_t users; /* User count - see datagram.c,tcp.c */
+ unsigned short protocol; /* Packet protocol from driver. */
+ unsigned short security; /* Security level of packet */
+ unsigned int truesize; /* Buffer size */
+
+ unsigned char *head; /* Head of buffer */
+ unsigned char *data; /* Data head pointer */
+ unsigned char *tail; /* Tail pointer */
+ unsigned char *end; /* End pointer */
+ void (*destructor)(struct sk_buff *); /* Destruct function */
+#ifdef CONFIG_IP_FIREWALL
+ __u32 fwmark; /* Label made by fwchains, used by pktsched */
+#endif
+#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
+ __u32 shapelatency; /* Latency on frame */
+ __u32 shapeclock; /* Time it should go out */
+ __u32 shapelen; /* Frame length in clocks */
+ __u32 shapestamp; /* Stamp for shaper */
+ __u16 shapepend; /* Pending */
+#endif
+
+#if defined(CONFIG_HIPPI)
+ union{
+ __u32 ifield;
+ } private;
+#endif
+};
+
+/* These are just the default values. This is run time configurable.
+ * FIXME: Probably the config option should go away. -- erics
+ */
+#ifdef CONFIG_SKB_LARGE
+#define SK_WMEM_MAX 65535
+#define SK_RMEM_MAX 65535
+#else
+#define SK_WMEM_MAX 32767
+#define SK_RMEM_MAX 32767
+#endif
+
+#ifdef __KERNEL__
+/*
+ * Handling routines are only of interest to the kernel
+ */
+#include <linux/malloc.h>
+
+#include <asm/system.h>
+
+extern void __kfree_skb(struct sk_buff *skb);
+extern void skb_queue_head_init(struct sk_buff_head *list);
+extern void skb_queue_head(struct sk_buff_head *list,struct sk_buff *buf);
+extern void skb_queue_tail(struct sk_buff_head *list,struct sk_buff *buf);
+extern struct sk_buff * skb_dequeue(struct sk_buff_head *list);
+extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk);
+extern void skb_append(struct sk_buff *old,struct sk_buff *newsk);
+extern void skb_unlink(struct sk_buff *buf);
+extern __u32 skb_queue_len(struct sk_buff_head *list);
+extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list);
+extern struct sk_buff * alloc_skb(unsigned int size, int priority);
+extern struct sk_buff * dev_alloc_skb(unsigned int size);
+extern void kfree_skbmem(struct sk_buff *skb);
+extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority);
+extern struct sk_buff * skb_copy(struct sk_buff *skb, int priority);
+extern struct sk_buff * skb_realloc_headroom(struct sk_buff *skb, int newheadroom);
+#define dev_kfree_skb(a) kfree_skb(a)
+extern unsigned char * skb_put(struct sk_buff *skb, unsigned int len);
+extern unsigned char * skb_push(struct sk_buff *skb, unsigned int len);
+extern unsigned char * skb_pull(struct sk_buff *skb, unsigned int len);
+extern int skb_headroom(struct sk_buff *skb);
+extern int skb_tailroom(struct sk_buff *skb);
+extern void skb_reserve(struct sk_buff *skb, unsigned int len);
+extern void skb_trim(struct sk_buff *skb, unsigned int len);
+extern void skb_over_panic(struct sk_buff *skb, int len, void *here);
+extern void skb_under_panic(struct sk_buff *skb, int len, void *here);
+
+/* Internal */
+extern __inline__ atomic_t *skb_datarefp(struct sk_buff *skb)
+{
+ return (atomic_t *)(skb->end);
+}
+
+extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
+{
+ return (list->next == (struct sk_buff *) list);
+}
+
+extern __inline__ void kfree_skb(struct sk_buff *skb)
+{
+ if (atomic_dec_and_test(&skb->users))
+ __kfree_skb(skb);
+}
+
+/* Use this if you didn't touch the skb state [for fast switching] */
+extern __inline__ void kfree_skb_fast(struct sk_buff *skb)
+{
+ if (atomic_dec_and_test(&skb->users))
+ kfree_skbmem(skb);
+}
+
+extern __inline__ int skb_cloned(struct sk_buff *skb)
+{
+ return skb->cloned && atomic_read(skb_datarefp(skb)) != 1;
+}
+
+extern __inline__ int skb_shared(struct sk_buff *skb)
+{
+ return (atomic_read(&skb->users) != 1);
+}
+
+/*
+ * Copy shared buffers into a new sk_buff. We effectively do COW on
+ * packets to handle cases where we have a local reader and forward
+ * and a couple of other messy ones. The normal one is tcpdumping
+ * a packet thats being forwarded.
+ */
+
+extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri)
+{
+ struct sk_buff *nskb;
+ if(!skb_cloned(skb))
+ return skb;
+ nskb=skb_copy(skb, pri);
+ kfree_skb(skb); /* Free our shared copy */
+ return nskb;
+}
+
+/*
+ * Peek an sk_buff. Unlike most other operations you _MUST_
+ * be careful with this one. A peek leaves the buffer on the
+ * list and someone else may run off with it. For an interrupt
+ * type system cli() peek the buffer copy the data and sti();
+ */
+
+extern __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
+{
+ struct sk_buff *list = ((struct sk_buff *)list_)->next;
+ if (list == (struct sk_buff *)list_)
+ list = NULL;
+ return list;
+}
+
+extern __inline__ struct sk_buff *skb_peek_tail(struct sk_buff_head *list_)
+{
+ struct sk_buff *list = ((struct sk_buff *)list_)->prev;
+ if (list == (struct sk_buff *)list_)
+ list = NULL;
+ return list;
+}
+
+/*
+ * Return the length of an sk_buff queue
+ */
+
+extern __inline__ __u32 skb_queue_len(struct sk_buff_head *list_)
+{
+ return(list_->qlen);
+}
+
+extern __inline__ void skb_queue_head_init(struct sk_buff_head *list)
+{
+ list->prev = (struct sk_buff *)list;
+ list->next = (struct sk_buff *)list;
+ list->qlen = 0;
+}
+
+/*
+ * Insert an sk_buff at the start of a list.
+ *
+ * The "__skb_xxxx()" functions are the non-atomic ones that
+ * can only be called with interrupts disabled.
+ */
+
+extern __inline__ void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
+{
+ struct sk_buff *prev, *next;
+
+ newsk->list = list;
+ list->qlen++;
+ prev = (struct sk_buff *)list;
+ next = prev->next;
+ newsk->next = next;
+ newsk->prev = prev;
+ next->prev = newsk;
+ prev->next = newsk;
+}
+
+extern spinlock_t skb_queue_lock;
+
+extern __inline__ void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ __skb_queue_head(list, newsk);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+}
+
+/*
+ * Insert an sk_buff at the end of a list.
+ */
+
+extern __inline__ void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
+{
+ struct sk_buff *prev, *next;
+
+ newsk->list = list;
+ list->qlen++;
+ next = (struct sk_buff *)list;
+ prev = next->prev;
+ newsk->next = next;
+ newsk->prev = prev;
+ next->prev = newsk;
+ prev->next = newsk;
+}
+
+extern __inline__ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ __skb_queue_tail(list, newsk);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+}
+
+/*
+ * Remove an sk_buff from a list.
+ */
+
+extern __inline__ struct sk_buff *__skb_dequeue(struct sk_buff_head *list)
+{
+ struct sk_buff *next, *prev, *result;
+
+ prev = (struct sk_buff *) list;
+ next = prev->next;
+ result = NULL;
+ if (next != prev) {
+ result = next;
+ next = next->next;
+ list->qlen--;
+ next->prev = prev;
+ prev->next = next;
+ result->next = NULL;
+ result->prev = NULL;
+ result->list = NULL;
+ }
+ return result;
+}
+
+extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list)
+{
+ long flags;
+ struct sk_buff *result;
+
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ result = __skb_dequeue(list);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+ return result;
+}
+
+/*
+ * Insert a packet on a list.
+ */
+
+extern __inline__ void __skb_insert(struct sk_buff *newsk,
+ struct sk_buff * prev, struct sk_buff *next,
+ struct sk_buff_head * list)
+{
+ newsk->next = next;
+ newsk->prev = prev;
+ next->prev = newsk;
+ prev->next = newsk;
+ newsk->list = list;
+ list->qlen++;
+}
+
+/*
+ * Place a packet before a given packet in a list
+ */
+extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ __skb_insert(newsk, old->prev, old, old->list);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+}
+
+/*
+ * Place a packet after a given packet in a list.
+ */
+
+extern __inline__ void __skb_append(struct sk_buff *old, struct sk_buff *newsk)
+{
+ __skb_insert(newsk, old, old->next, old->list);
+}
+
+extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ __skb_append(old, newsk);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+}
+
+/*
+ * remove sk_buff from list. _Must_ be called atomically, and with
+ * the list known..
+ */
+extern __inline__ void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
+{
+ struct sk_buff * next, * prev;
+
+ list->qlen--;
+ next = skb->next;
+ prev = skb->prev;
+ skb->next = NULL;
+ skb->prev = NULL;
+ skb->list = NULL;
+ next->prev = prev;
+ prev->next = next;
+}
+
+/*
+ * Remove an sk_buff from its list. Works even without knowing the list it
+ * is sitting on, which can be handy at times. It also means that THE LIST
+ * MUST EXIST when you unlink. Thus a list must have its contents unlinked
+ * _FIRST_.
+ */
+
+extern __inline__ void skb_unlink(struct sk_buff *skb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ if(skb->list)
+ __skb_unlink(skb, skb->list);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+}
+
+/* XXX: more streamlined implementation */
+extern __inline__ struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list)
+{
+ struct sk_buff *skb = skb_peek_tail(list);
+ if (skb)
+ __skb_unlink(skb, list);
+ return skb;
+}
+
+extern __inline__ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
+{
+ long flags;
+ struct sk_buff *result;
+
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ result = __skb_dequeue_tail(list);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+ return result;
+}
+
+/*
+ * Add data to an sk_buff
+ */
+
+extern __inline__ unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
+{
+ unsigned char *tmp=skb->tail;
+ skb->tail+=len;
+ skb->len+=len;
+ return tmp;
+}
+
+extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
+{
+ unsigned char *tmp=skb->tail;
+ skb->tail+=len;
+ skb->len+=len;
+ if(skb->tail>skb->end)
+ {
+ __label__ here;
+ skb_over_panic(skb, len, &&here);
+here: ;
+ }
+ return tmp;
+}
+
+extern __inline__ unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
+{
+ skb->data-=len;
+ skb->len+=len;
+ return skb->data;
+}
+
+extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
+{
+ skb->data-=len;
+ skb->len+=len;
+ if(skb->data<skb->head)
+ {
+ __label__ here;
+ skb_under_panic(skb, len, &&here);
+here: ;
+ }
+ return skb->data;
+}
+
+extern __inline__ char *__skb_pull(struct sk_buff *skb, unsigned int len)
+{
+ skb->len-=len;
+ return skb->data+=len;
+}
+
+extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
+{
+ if (len > skb->len)
+ return NULL;
+ return __skb_pull(skb,len);
+}
+
+extern __inline__ int skb_headroom(struct sk_buff *skb)
+{
+ return skb->data-skb->head;
+}
+
+extern __inline__ int skb_tailroom(struct sk_buff *skb)
+{
+ return skb->end-skb->tail;
+}
+
+extern __inline__ void skb_reserve(struct sk_buff *skb, unsigned int len)
+{
+ skb->data+=len;
+ skb->tail+=len;
+}
+
+extern __inline__ void __skb_trim(struct sk_buff *skb, unsigned int len)
+{
+ skb->len = len;
+ skb->tail = skb->data+len;
+}
+
+extern __inline__ void skb_trim(struct sk_buff *skb, unsigned int len)
+{
+ if (skb->len > len) {
+ __skb_trim(skb, len);
+ }
+}
+
+extern __inline__ void skb_orphan(struct sk_buff *skb)
+{
+ if (skb->destructor)
+ skb->destructor(skb);
+ skb->destructor = NULL;
+ skb->sk = NULL;
+}
+
+extern __inline__ void skb_queue_purge(struct sk_buff_head *list)
+{
+ struct sk_buff *skb;
+ while ((skb=skb_dequeue(list))!=NULL)
+ kfree_skb(skb);
+}
+
+extern __inline__ struct sk_buff *dev_alloc_skb(unsigned int length)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(length+16, GFP_ATOMIC);
+ if (skb)
+ skb_reserve(skb,16);
+ return skb;
+}
+
+extern __inline__ struct sk_buff *
+skb_cow(struct sk_buff *skb, unsigned int headroom)
+{
+ headroom = (headroom+15)&~15;
+
+ if ((unsigned)skb_headroom(skb) < headroom || skb_cloned(skb)) {
+ struct sk_buff *skb2 = skb_realloc_headroom(skb, headroom);
+ kfree_skb(skb);
+ skb = skb2;
+ }
+ return skb;
+}
+
+extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
+extern unsigned int datagram_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait);
+extern int skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
+extern int skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
+extern void skb_free_datagram(struct sock * sk, struct sk_buff *skb);
+
+extern void skb_init(void);
+extern void skb_add_mtu(int mtu);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_SKBUFF_H */
diff --git a/pfinet/linux-src/include/linux/slab.h b/pfinet/linux-src/include/linux/slab.h
new file mode 100644
index 00000000..0b46d3b7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/slab.h
@@ -0,0 +1,71 @@
+/*
+ * linux/mm/slab.h
+ * Written by Mark Hemment, 1996.
+ * (markhe@nextd.demon.co.uk)
+ */
+
+#if !defined(_LINUX_SLAB_H)
+#define _LINUX_SLAB_H
+
+#if defined(__KERNEL__)
+
+typedef struct kmem_cache_s kmem_cache_t;
+
+#include <linux/mm.h>
+#include <asm/cache.h>
+
+/* flags for kmem_cache_alloc() */
+#define SLAB_BUFFER GFP_BUFFER
+#define SLAB_ATOMIC GFP_ATOMIC
+#define SLAB_USER GFP_USER
+#define SLAB_KERNEL GFP_KERNEL
+#define SLAB_NFS GFP_NFS
+#define SLAB_DMA GFP_DMA
+
+#define SLAB_LEVEL_MASK 0x0000007fUL
+#define SLAB_NO_GROW 0x00001000UL /* don't grow a cache */
+
+/* flags to pass to kmem_cache_create().
+ * The first 3 are only valid when the allocator as been build
+ * SLAB_DEBUG_SUPPORT.
+ */
+#define SLAB_DEBUG_FREE 0x00000100UL /* Peform (expensive) checks on free */
+#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor (as verifier) */
+#define SLAB_RED_ZONE 0x00000400UL /* Red zone objs in a cache */
+#define SLAB_POISON 0x00000800UL /* Poison objects */
+#define SLAB_NO_REAP 0x00001000UL /* never reap from the cache */
+#define SLAB_HWCACHE_ALIGN 0x00002000UL /* align objs on a h/w cache lines */
+#if 0
+#define SLAB_HIGH_PACK 0x00004000UL /* XXX */
+#endif
+
+/* flags passed to a constructor func */
+#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */
+#define SLAB_CTOR_ATOMIC 0x002UL /* tell constructor it can't sleep */
+#define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */
+
+/* prototypes */
+extern long kmem_cache_init(long, long);
+extern void kmem_cache_sizes_init(void);
+extern kmem_cache_t *kmem_find_general_cachep(size_t);
+extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
+ void (*)(void *, kmem_cache_t *, unsigned long),
+ void (*)(void *, kmem_cache_t *, unsigned long));
+extern int kmem_cache_shrink(kmem_cache_t *);
+extern void *kmem_cache_alloc(kmem_cache_t *, int);
+extern void kmem_cache_free(kmem_cache_t *, void *);
+
+extern void *kmalloc(size_t, int);
+extern void kfree(const void *);
+extern void kfree_s(const void *, size_t);
+
+extern void kmem_cache_reap(int);
+extern int get_slabinfo(char *);
+
+/* System wide caches */
+extern kmem_cache_t *vm_area_cachep;
+extern kmem_cache_t *mm_cachep;
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SLAB_H */
diff --git a/pfinet/linux-src/include/linux/smb.h b/pfinet/linux-src/include/linux/smb.h
new file mode 100644
index 00000000..852d5b0d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smb.h
@@ -0,0 +1,123 @@
+/*
+ * smb.h
+ *
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ */
+
+#ifndef _LINUX_SMB_H
+#define _LINUX_SMB_H
+
+#include <linux/types.h>
+
+enum smb_protocol {
+ SMB_PROTOCOL_NONE,
+ SMB_PROTOCOL_CORE,
+ SMB_PROTOCOL_COREPLUS,
+ SMB_PROTOCOL_LANMAN1,
+ SMB_PROTOCOL_LANMAN2,
+ SMB_PROTOCOL_NT1
+};
+
+enum smb_case_hndl {
+ SMB_CASE_DEFAULT,
+ SMB_CASE_LOWER,
+ SMB_CASE_UPPER
+};
+
+struct smb_dskattr {
+ __u16 total;
+ __u16 allocblocks;
+ __u16 blocksize;
+ __u16 free;
+};
+
+struct smb_conn_opt {
+
+ /* The socket */
+ unsigned int fd;
+
+ enum smb_protocol protocol;
+ enum smb_case_hndl case_handling;
+
+ /* Connection-Options */
+
+ __u32 max_xmit;
+ __u16 server_uid;
+ __u16 tid;
+
+ /* The following are LANMAN 1.0 options */
+ __u16 secmode;
+ __u16 maxmux;
+ __u16 maxvcs;
+ __u16 rawmode;
+ __u32 sesskey;
+
+ /* The following are NT LM 0.12 options */
+ __u32 maxraw;
+ __u32 capabilities;
+ __s16 serverzone;
+};
+
+#ifdef __KERNEL__
+
+#define SMB_MAXNAMELEN 255
+#define SMB_MAXPATHLEN 1024
+
+/*
+ * Contains all relevant data on a SMB networked file.
+ */
+struct smb_fattr {
+
+ __u16 attr;
+
+ unsigned long f_ino;
+ umode_t f_mode;
+ nlink_t f_nlink;
+ uid_t f_uid;
+ gid_t f_gid;
+ kdev_t f_rdev;
+ off_t f_size;
+ time_t f_atime;
+ time_t f_mtime;
+ time_t f_ctime;
+ unsigned long f_blksize;
+ unsigned long f_blocks;
+};
+
+struct smb_dirent {
+ struct smb_fattr attr;
+
+ int f_pos;
+ int len;
+ __u8 name[SMB_MAXNAMELEN];
+};
+
+enum smb_conn_state {
+ CONN_VALID, /* everything's fine */
+ CONN_INVALID, /* Something went wrong, but did not
+ try to reconnect yet. */
+ CONN_RETRIED /* Tried a reconnection, but was refused */
+};
+
+/*
+ * The readdir cache size controls how many directory entries are cached.
+ */
+#define SMB_READDIR_CACHE_SIZE 64
+
+#define SMB_SUPER_MAGIC 0x517B
+
+#define SMB_SERVER(inode) (&(inode->i_sb->u.smbfs_sb))
+#define SMB_INOP(inode) (&(inode->u.smbfs_i))
+
+#define SMB_HEADER_LEN 37 /* includes everything up to, but not
+ * including smb_bcc */
+#define SMB_DEF_MAX_XMIT 32768
+#define SMB_INITIAL_PACKET_SIZE 4000
+
+/* Allocate max. 1 page */
+#define TRANS2_MAX_TRANSFER (4096-17)
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/smb_fs.h b/pfinet/linux-src/include/linux/smb_fs.h
new file mode 100644
index 00000000..11dfce7d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smb_fs.h
@@ -0,0 +1,240 @@
+/*
+ * smb_fs.h
+ *
+ * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ */
+
+#ifndef _LINUX_SMB_FS_H
+#define _LINUX_SMB_FS_H
+
+#include <linux/smb.h>
+
+/*
+ * ioctl commands
+ */
+#define SMB_IOC_GETMOUNTUID _IOR('u', 1, __kernel_uid_t)
+#define SMB_IOC_NEWCONN _IOW('u', 2, struct smb_conn_opt)
+
+#ifdef __KERNEL__
+
+#include <asm/unaligned.h>
+
+#define WVAL(buf,pos) \
+(le16_to_cpu(get_unaligned((__u16 *)((__u8 *)(buf) + (pos)))))
+#define DVAL(buf,pos) \
+(le32_to_cpu(get_unaligned((__u32 *)((__u8 *)(buf) + (pos)))))
+#define WSET(buf,pos,val) \
+put_unaligned(cpu_to_le16((__u16)(val)), (__u16 *)((__u8 *)(buf) + (pos)))
+#define DSET(buf,pos,val) \
+put_unaligned(cpu_to_le32((__u32)(val)), (__u32 *)((__u8 *)(buf) + (pos)))
+
+/* where to find the base of the SMB packet proper */
+#define smb_base(buf) ((__u8 *)(((__u8 *)(buf))+4))
+
+#include <linux/vmalloc.h>
+
+#ifdef DEBUG_SMB_MALLOC
+
+extern int smb_malloced;
+extern int smb_current_vmalloced;
+
+static inline void *
+smb_vmalloc(unsigned int size)
+{
+ smb_malloced += 1;
+ smb_current_vmalloced += 1;
+ return vmalloc(size);
+}
+
+static inline void
+smb_vfree(void *obj)
+{
+ smb_current_vmalloced -= 1;
+ vfree(obj);
+}
+
+#else /* DEBUG_SMB_MALLOC */
+
+#define smb_kmalloc(s,p) kmalloc(s,p)
+#define smb_kfree_s(o,s) kfree_s(o,s)
+#define smb_vmalloc(s) vmalloc(s)
+#define smb_vfree(o) vfree(o)
+
+#endif /* DEBUG_SMB_MALLOC */
+
+/*
+ * Flags for the in-memory inode
+ */
+#define SMB_F_CACHEVALID 0x01 /* directory cache valid */
+#define SMB_F_LOCALWRITE 0x02 /* file modified locally */
+
+/*
+ * Bug fix flags
+ */
+#define SMB_FIX_WIN95 0x0001 /* Win 95 server */
+#define SMB_FIX_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */
+#define SMB_FIX_DIRATTR 0x0004 /* Use find_first for getattr */
+
+
+/* NT1 protocol capability bits */
+#define SMB_CAP_RAW_MODE 0x0001
+#define SMB_CAP_MPX_MODE 0x0002
+#define SMB_CAP_UNICODE 0x0004
+#define SMB_CAP_LARGE_FILES 0x0008
+#define SMB_CAP_NT_SMBS 0x0010
+#define SMB_CAP_RPC_REMOTE_APIS 0x0020
+#define SMB_CAP_STATUS32 0x0040
+#define SMB_CAP_LEVEL_II_OPLOCKS 0x0080
+#define SMB_CAP_LOCK_AND_READ 0x0100
+#define SMB_CAP_NT_FIND 0x0200
+#define SMB_CAP_DFS 0x1000
+#define SMB_CAP_LARGE_READX 0x4000
+
+
+/* linux/fs/smbfs/mmap.c */
+int smb_mmap(struct file *, struct vm_area_struct *);
+
+/* linux/fs/smbfs/file.c */
+extern struct inode_operations smb_file_inode_operations;
+
+/* linux/fs/smbfs/dir.c */
+extern struct inode_operations smb_dir_inode_operations;
+void smb_renew_times(struct dentry *);
+
+/* linux/fs/smbfs/ioctl.c */
+int smb_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
+
+/* linux/fs/smbfs/inode.c */
+struct super_block *smb_read_super(struct super_block *, void *, int);
+void smb_get_inode_attr(struct inode *, struct smb_fattr *);
+void smb_invalidate_inodes(struct smb_sb_info *);
+int smb_revalidate_inode(struct dentry *);
+int smb_notify_change(struct dentry *, struct iattr *);
+unsigned long smb_invent_inos(unsigned long);
+struct inode *smb_iget(struct super_block *, struct smb_fattr *);
+extern int init_smb_fs(void);
+
+/* linux/fs/smbfs/proc.c */
+__u32 smb_len(unsigned char *);
+__u8 *smb_encode_smb_length(__u8 *, __u32);
+__u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
+int smb_get_rsize(struct smb_sb_info *);
+int smb_get_wsize(struct smb_sb_info *);
+int smb_newconn(struct smb_sb_info *, struct smb_conn_opt *);
+int smb_errno(struct smb_sb_info *);
+int smb_close(struct inode *);
+void smb_close_dentry(struct dentry *);
+int smb_close_fileid(struct dentry *, __u16);
+int smb_open(struct dentry *, int);
+int smb_proc_read(struct dentry *, off_t, int, char *);
+int smb_proc_write(struct dentry *, off_t, int, const char *);
+int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
+int smb_proc_mv(struct dentry *, struct dentry *);
+int smb_proc_mkdir(struct dentry *);
+int smb_proc_rmdir(struct dentry *);
+int smb_proc_unlink(struct dentry *);
+int smb_proc_readdir(struct dentry *, int, void *);
+int smb_proc_getattr(struct dentry *, struct smb_fattr *);
+int smb_proc_setattr(struct dentry *, struct smb_fattr *);
+int smb_proc_settime(struct dentry *, struct smb_fattr *);
+int smb_proc_dskattr(struct super_block *, struct statfs *);
+int smb_proc_reconnect(struct smb_sb_info *);
+int smb_proc_connect(struct smb_sb_info *);
+int smb_proc_disconnect(struct smb_sb_info *);
+int smb_proc_trunc(struct smb_sb_info *, __u16, __u32);
+void smb_init_root_dirent(struct smb_sb_info *, struct smb_fattr *);
+
+static inline int
+smb_is_open(struct inode *i)
+{
+ return (i->u.smbfs_i.open == SMB_SERVER(i)->generation);
+}
+
+/* linux/fs/smbfs/sock.c */
+int smb_round_length(int);
+int smb_valid_socket(struct inode *);
+void smb_close_socket(struct smb_sb_info *);
+int smb_release(struct smb_sb_info *server);
+int smb_connect(struct smb_sb_info *server);
+int smb_request(struct smb_sb_info *server);
+int smb_request_read_raw(struct smb_sb_info *, unsigned char *, int);
+int smb_request_write_raw(struct smb_sb_info *, unsigned const char *, int);
+int smb_catch_keepalive(struct smb_sb_info *server);
+int smb_dont_catch_keepalive(struct smb_sb_info *server);
+int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
+ int ldata, unsigned char *data,
+ int lparam, unsigned char *param,
+ int *lrdata, unsigned char **rdata,
+ int *lrparam, unsigned char **rparam);
+
+/* fs/smbfs/cache.c */
+
+/*
+ * The cache index describes the pages mapped starting
+ * at offset PAGE_SIZE. We keep only a minimal amount
+ * of information here.
+ */
+struct cache_index {
+ unsigned short num_entries;
+ unsigned short space;
+ struct cache_block * block;
+};
+
+#define NINDEX (PAGE_SIZE-64)/sizeof(struct cache_index)
+/*
+ * The cache head is mapped as the page at offset 0.
+ */
+struct cache_head {
+ int valid;
+ int status; /* error code or 0 */
+ int entries; /* total entries */
+ int pages; /* number of data pages */
+ int idx; /* index of current data page */
+ struct cache_index index[NINDEX];
+};
+
+/*
+ * An array of cache_entry structures holds information
+ * for each object in the cache_block.
+ */
+struct cache_entry {
+ ino_t ino;
+ unsigned short namelen;
+ unsigned short offset;
+};
+
+/*
+ * The cache blocks hold the actual data. The entry table grows up
+ * while the names grow down, and we have space until they meet.
+ */
+struct cache_block {
+ union {
+ struct cache_entry table[1];
+ char names[PAGE_SIZE];
+ } cb_data;
+};
+
+/*
+ * To return an entry, we can pass a reference to the
+ * name instead of having to copy it.
+ */
+struct cache_dirent {
+ ino_t ino;
+ unsigned long pos;
+ int len;
+ char * name;
+};
+
+struct cache_head * smb_get_dircache(struct dentry *);
+void smb_init_dircache(struct cache_head *);
+void smb_free_dircache(struct cache_head *);
+int smb_refill_dircache(struct cache_head *, struct dentry *);
+void smb_add_to_cache(struct cache_head *, struct cache_dirent *, off_t);
+int smb_find_in_cache(struct cache_head *, off_t, struct cache_dirent *);
+void smb_invalid_dir_cache(struct inode *);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SMB_FS_H */
diff --git a/pfinet/linux-src/include/linux/smb_fs_i.h b/pfinet/linux-src/include/linux/smb_fs_i.h
new file mode 100644
index 00000000..4aea02c3
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smb_fs_i.h
@@ -0,0 +1,35 @@
+/*
+ * smb_fs_i.h
+ *
+ * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ */
+
+#ifndef _LINUX_SMB_FS_I
+#define _LINUX_SMB_FS_I
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+
+/*
+ * smb fs inode data (in memory only)
+ */
+struct smb_inode_info {
+
+ /*
+ * file handles are local to a connection. A file is open if
+ * (open == generation).
+ */
+ unsigned int open; /* open generation */
+ __u16 fileid; /* What id to handle a file with? */
+ __u16 attr; /* Attribute fields, DOS value */
+
+ __u16 access; /* Access mode */
+ __u16 cache_valid; /* dircache valid? */
+ unsigned long oldmtime; /* last time refreshed */
+ unsigned long closed; /* timestamp when closed */
+};
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/smb_fs_sb.h b/pfinet/linux-src/include/linux/smb_fs_sb.h
new file mode 100644
index 00000000..cedbb5ab
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smb_fs_sb.h
@@ -0,0 +1,50 @@
+/*
+ * smb_fs_sb.h
+ *
+ * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ */
+
+#ifndef _SMB_FS_SB
+#define _SMB_FS_SB
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/smb.h>
+
+/* Get the server for the specified dentry */
+#define server_from_dentry(dentry) &dentry->d_sb->u.smbfs_sb
+#define SB_of(server) ((struct super_block *) ((char *)(server) - \
+ (unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
+
+struct smb_sb_info {
+ enum smb_conn_state state;
+ struct file * sock_file;
+
+ struct smb_mount_data *mnt;
+ unsigned char *temp_buf;
+
+ /* Connections are counted. Each time a new socket arrives,
+ * generation is incremented.
+ */
+ unsigned int generation;
+ pid_t conn_pid;
+ struct smb_conn_opt opt;
+
+ struct semaphore sem;
+ struct wait_queue * wait;
+
+ __u32 packet_size;
+ unsigned char * packet;
+ unsigned short rcls; /* The error codes we received */
+ unsigned short err;
+
+ /* We use our on data_ready callback, but need the original one */
+ void *data_ready;
+};
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/smb_mount.h b/pfinet/linux-src/include/linux/smb_mount.h
new file mode 100644
index 00000000..886d945d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smb_mount.h
@@ -0,0 +1,25 @@
+/*
+ * smb_mount.h
+ *
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1997 by Volker Lendecke
+ *
+ */
+
+#ifndef _LINUX_SMB_MOUNT_H
+#define _LINUX_SMB_MOUNT_H
+
+#include <linux/types.h>
+
+#define SMB_MOUNT_VERSION 6
+
+struct smb_mount_data {
+ int version;
+ __kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */
+ __kernel_uid_t uid;
+ __kernel_gid_t gid;
+ __kernel_mode_t file_mode;
+ __kernel_mode_t dir_mode;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/smbno.h b/pfinet/linux-src/include/linux/smbno.h
new file mode 100644
index 00000000..0f25e026
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smbno.h
@@ -0,0 +1,278 @@
+#ifndef _SMBNO_H_
+#define _SMBNO_H_
+
+/* these define the attribute byte as seen by DOS */
+#define aRONLY (1L<<0)
+#define aHIDDEN (1L<<1)
+#define aSYSTEM (1L<<2)
+#define aVOLID (1L<<3)
+#define aDIR (1L<<4)
+#define aARCH (1L<<5)
+
+/* error classes */
+#define SUCCESS 0 /* The request was successful. */
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
+#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
+#define ERRHRD 0x03 /* Error is an hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+/* SMB X/Open error codes for the ERRdos error class */
+
+#define ERRbadfunc 1 /* Invalid function (or system call) */
+#define ERRbadfile 2 /* File not found (pathname error) */
+#define ERRbadpath 3 /* Directory not found */
+#define ERRnofids 4 /* Too many open files */
+#define ERRnoaccess 5 /* Access denied */
+#define ERRbadfid 6 /* Invalid fid */
+#define ERRbadmcb 7 /* Memory control blocks destroyed */
+#define ERRnomem 8 /* Out of memory */
+#define ERRbadmem 9 /* Invalid memory block address */
+#define ERRbadenv 10 /* Invalid environment */
+#define ERRbadformat 11 /* Invalid format */
+#define ERRbadaccess 12 /* Invalid open mode */
+#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
+#define ERRres 14 /* reserved */
+#define ERRbaddrive 15 /* Invalid drive */
+#define ERRremcd 16 /* Attempt to delete current directory */
+#define ERRdiffdevice 17 /* rename/move across different filesystems */
+#define ERRnofiles 18 /* no more files found in file search */
+#define ERRbadshare 32 /* Share mode on file conflict with open mode */
+#define ERRlock 33 /* Lock request conflicts with existing lock */
+#define ERRfilexists 80 /* File in operation already exists */
+#define ERRundocumented1 123 /* Invalid name?? e.g. .tmp* */
+#define ERRbadpipe 230 /* Named pipe invalid */
+#define ERRpipebusy 231 /* All instances of pipe are busy */
+#define ERRpipeclosing 232 /* named pipe close in progress */
+#define ERRnotconnected 233 /* No process on other end of named pipe */
+#define ERRmoredata 234 /* More data to be returned */
+#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
+#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not supported */
+
+/* Error codes for the ERRSRV class */
+
+#define ERRerror 1 /* Non specific error code */
+#define ERRbadpw 2 /* Bad password */
+#define ERRbadtype 3 /* reserved */
+#define ERRaccess 4 /* No permissions to do the requested operation */
+#define ERRinvnid 5 /* tid invalid */
+#define ERRinvnetname 6 /* Invalid servername */
+#define ERRinvdevice 7 /* Invalid device */
+#define ERRqfull 49 /* Print queue full */
+#define ERRqtoobig 50 /* Queued item too big */
+#define ERRinvpfid 52 /* Invalid print file in smb_fid */
+#define ERRsmbcmd 64 /* Unrecognised command */
+#define ERRsrverror 65 /* smb server internal error */
+#define ERRfilespecs 67 /* fid and pathname invalid combination */
+#define ERRbadlink 68 /* reserved */
+#define ERRbadpermits 69 /* Access specified for a file is not valid */
+#define ERRbadpid 70 /* reserved */
+#define ERRsetattrmode 71 /* attribute mode invalid */
+#define ERRpaused 81 /* Message server paused */
+#define ERRmsgoff 82 /* Not receiving messages */
+#define ERRnoroom 83 /* No room for message */
+#define ERRrmuns 87 /* too many remote usernames */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* too many userids */
+#define ERRbaduid 91 /* bad userid */
+#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
+#define ERRuseSTD 251 /* temporarily unable to use raw mode, use std.mode */
+#define ERRcontMPX 252 /* resume MPX mode */
+#define ERRbadPW /* reserved */
+#define ERRnosupport 0xFFFF
+
+/* Error codes for the ERRHRD class */
+
+#define ERRnowrite 19 /* read only media */
+#define ERRbadunit 20 /* Unknown device */
+#define ERRnotready 21 /* Drive not ready */
+#define ERRbadcmd 22 /* Unknown command */
+#define ERRdata 23 /* Data (CRC) error */
+#define ERRbadreq 24 /* Bad request structure length */
+#define ERRseek 25
+#define ERRbadmedia 26
+#define ERRbadsector 27
+#define ERRnopaper 28
+#define ERRwrite 29 /* write fault */
+#define ERRread 30 /* read fault */
+#define ERRgeneral 31 /* General hardware failure */
+#define ERRwrongdisk 34
+#define ERRFCBunavail 35
+#define ERRsharebufexc 36 /* share buffer exceeded */
+#define ERRdiskfull 39
+
+/*
+ * Access modes when opening a file
+ */
+#define SMB_ACCMASK 0x0003
+#define SMB_O_RDONLY 0x0000
+#define SMB_O_WRONLY 0x0001
+#define SMB_O_RDWR 0x0002
+
+/* offsets into message for common items */
+#define smb_com 8
+#define smb_rcls 9
+#define smb_reh 10
+#define smb_err 11
+#define smb_flg 13
+#define smb_flg2 14
+#define smb_reb 13
+#define smb_tid 28
+#define smb_pid 30
+#define smb_uid 32
+#define smb_mid 34
+#define smb_wct 36
+#define smb_vwv 37
+#define smb_vwv0 37
+#define smb_vwv1 39
+#define smb_vwv2 41
+#define smb_vwv3 43
+#define smb_vwv4 45
+#define smb_vwv5 47
+#define smb_vwv6 49
+#define smb_vwv7 51
+#define smb_vwv8 53
+#define smb_vwv9 55
+#define smb_vwv10 57
+#define smb_vwv11 59
+#define smb_vwv12 61
+#define smb_vwv13 63
+#define smb_vwv14 65
+
+/* these are the trans2 sub fields for primary requests */
+#define smb_tpscnt smb_vwv0
+#define smb_tdscnt smb_vwv1
+#define smb_mprcnt smb_vwv2
+#define smb_mdrcnt smb_vwv3
+#define smb_msrcnt smb_vwv4
+#define smb_flags smb_vwv5
+#define smb_timeout smb_vwv6
+#define smb_pscnt smb_vwv9
+#define smb_psoff smb_vwv10
+#define smb_dscnt smb_vwv11
+#define smb_dsoff smb_vwv12
+#define smb_suwcnt smb_vwv13
+#define smb_setup smb_vwv14
+#define smb_setup0 smb_setup
+#define smb_setup1 (smb_setup+2)
+#define smb_setup2 (smb_setup+4)
+
+/* these are for the secondary requests */
+#define smb_spscnt smb_vwv2
+#define smb_spsoff smb_vwv3
+#define smb_spsdisp smb_vwv4
+#define smb_sdscnt smb_vwv5
+#define smb_sdsoff smb_vwv6
+#define smb_sdsdisp smb_vwv7
+#define smb_sfid smb_vwv8
+
+/* and these for responses */
+#define smb_tprcnt smb_vwv0
+#define smb_tdrcnt smb_vwv1
+#define smb_prcnt smb_vwv3
+#define smb_proff smb_vwv4
+#define smb_prdisp smb_vwv5
+#define smb_drcnt smb_vwv6
+#define smb_droff smb_vwv7
+#define smb_drdisp smb_vwv8
+
+/* the complete */
+#define SMBmkdir 0x00 /* create directory */
+#define SMBrmdir 0x01 /* delete directory */
+#define SMBopen 0x02 /* open file */
+#define SMBcreate 0x03 /* create file */
+#define SMBclose 0x04 /* close file */
+#define SMBflush 0x05 /* flush file */
+#define SMBunlink 0x06 /* delete file */
+#define SMBmv 0x07 /* rename file */
+#define SMBgetatr 0x08 /* get file attributes */
+#define SMBsetatr 0x09 /* set file attributes */
+#define SMBread 0x0A /* read from file */
+#define SMBwrite 0x0B /* write to file */
+#define SMBlock 0x0C /* lock byte range */
+#define SMBunlock 0x0D /* unlock byte range */
+#define SMBctemp 0x0E /* create temporary file */
+#define SMBmknew 0x0F /* make new file */
+#define SMBchkpth 0x10 /* check directory path */
+#define SMBexit 0x11 /* process exit */
+#define SMBlseek 0x12 /* seek */
+#define SMBtcon 0x70 /* tree connect */
+#define SMBtconX 0x75 /* tree connect and X*/
+#define SMBtdis 0x71 /* tree disconnect */
+#define SMBnegprot 0x72 /* negotiate protocol */
+#define SMBdskattr 0x80 /* get disk attributes */
+#define SMBsearch 0x81 /* search directory */
+#define SMBsplopen 0xC0 /* open print spool file */
+#define SMBsplwr 0xC1 /* write to print spool file */
+#define SMBsplclose 0xC2 /* close print spool file */
+#define SMBsplretq 0xC3 /* return print queue */
+#define SMBsends 0xD0 /* send single block message */
+#define SMBsendb 0xD1 /* send broadcast message */
+#define SMBfwdname 0xD2 /* forward user name */
+#define SMBcancelf 0xD3 /* cancel forward */
+#define SMBgetmac 0xD4 /* get machine name */
+#define SMBsendstrt 0xD5 /* send start of multi-block message */
+#define SMBsendend 0xD6 /* send end of multi-block message */
+#define SMBsendtxt 0xD7 /* send text of multi-block message */
+
+/* Core+ protocol */
+#define SMBlockread 0x13 /* Lock a range and read */
+#define SMBwriteunlock 0x14 /* Unlock a range then write */
+#define SMBreadbraw 0x1a /* read a block of data with no smb header */
+#define SMBwritebraw 0x1d /* write a block of data with no smb header */
+#define SMBwritec 0x20 /* secondary write request */
+#define SMBwriteclose 0x2c /* write a file then close it */
+
+/* dos extended protocol */
+#define SMBreadBraw 0x1A /* read block raw */
+#define SMBreadBmpx 0x1B /* read block multiplexed */
+#define SMBreadBs 0x1C /* read block (secondary response) */
+#define SMBwriteBraw 0x1D /* write block raw */
+#define SMBwriteBmpx 0x1E /* write block multiplexed */
+#define SMBwriteBs 0x1F /* write block (secondary request) */
+#define SMBwriteC 0x20 /* write complete response */
+#define SMBsetattrE 0x22 /* set file attributes expanded */
+#define SMBgetattrE 0x23 /* get file attributes expanded */
+#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */
+#define SMBtrans 0x25 /* transaction - name, bytes in/out */
+#define SMBtranss 0x26 /* transaction (secondary request/response) */
+#define SMBioctl 0x27 /* IOCTL */
+#define SMBioctls 0x28 /* IOCTL (secondary request/response) */
+#define SMBcopy 0x29 /* copy */
+#define SMBmove 0x2A /* move */
+#define SMBecho 0x2B /* echo */
+#define SMBopenX 0x2D /* open and X */
+#define SMBreadX 0x2E /* read and X */
+#define SMBwriteX 0x2F /* write and X */
+#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */
+#define SMBtconX 0x75 /* tree connect and X */
+#define SMBffirst 0x82 /* find first */
+#define SMBfunique 0x83 /* find unique */
+#define SMBfclose 0x84 /* find close */
+#define SMBinvalid 0xFE /* invalid command */
+
+
+/* Extended 2.0 protocol */
+#define SMBtrans2 0x32 /* TRANS2 protocol set */
+#define SMBtranss2 0x33 /* TRANS2 protocol set, secondary command */
+#define SMBfindclose 0x34 /* Terminate a TRANSACT2_FINDFIRST */
+#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
+#define SMBulogoffX 0x74 /* user logoff */
+
+/* these are the TRANS2 sub commands */
+#define TRANSACT2_OPEN 0
+#define TRANSACT2_FINDFIRST 1
+#define TRANSACT2_FINDNEXT 2
+#define TRANSACT2_QFSINFO 3
+#define TRANSACT2_SETFSINFO 4
+#define TRANSACT2_QPATHINFO 5
+#define TRANSACT2_SETPATHINFO 6
+#define TRANSACT2_QFILEINFO 7
+#define TRANSACT2_SETFILEINFO 8
+#define TRANSACT2_FSCTL 9
+#define TRANSACT2_IOCTL 10
+#define TRANSACT2_FINDNOTIFYFIRST 11
+#define TRANSACT2_FINDNOTIFYNEXT 12
+#define TRANSACT2_MKDIR 13
+
+#endif /* _SMBNO_H_ */
diff --git a/pfinet/linux-src/include/linux/smp.h b/pfinet/linux-src/include/linux/smp.h
new file mode 100644
index 00000000..eae12907
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smp.h
@@ -0,0 +1,86 @@
+#ifndef __LINUX_SMP_H
+#define __LINUX_SMP_H
+
+/*
+ * Generic SMP support
+ * Alan Cox. <alan@redhat.com>
+ */
+
+#ifdef __SMP__
+
+#include <asm/smp.h>
+
+/*
+ * main cross-CPU interfaces, handles INIT, TLB flush, STOP, etc.
+ * (defined in asm header):
+ */
+
+/*
+ * stops all CPUs but the current one:
+ */
+extern void smp_send_stop(void);
+
+/*
+ * sends a 'reschedule' event to another CPU:
+ */
+extern void FASTCALL(smp_send_reschedule(int cpu));
+
+
+/*
+ * Boot processor call to load the other CPU's
+ */
+extern void smp_boot_cpus(void);
+
+/*
+ * Processor call in. Must hold processors until ..
+ */
+extern void smp_callin(void);
+
+/*
+ * Multiprocessors may now schedule
+ */
+extern void smp_commence(void);
+
+/*
+ * Call a function on all other processors
+ */
+extern int smp_call_function (void (*func) (void *info), void *info,
+ int retry, int wait);
+
+/*
+ * True once the per process idle is forked
+ */
+extern int smp_threads_ready;
+
+extern int smp_num_cpus;
+
+extern volatile unsigned long smp_msg_data;
+extern volatile int smp_src_cpu;
+extern volatile int smp_msg_id;
+
+#define MSG_ALL_BUT_SELF 0x8000 /* Assume <32768 CPU's */
+#define MSG_ALL 0x8001
+
+#define MSG_INVALIDATE_TLB 0x0001 /* Remote processor TLB invalidate */
+#define MSG_STOP_CPU 0x0002 /* Sent to shut down slave CPU's
+ * when rebooting
+ */
+#define MSG_RESCHEDULE 0x0003 /* Reschedule request from master CPU*/
+#define MSG_CALL_FUNCTION 0x0004 /* Call function on all other CPUs */
+
+#else
+
+/*
+ * These macros fold the SMP functionality into a single CPU system
+ */
+
+#define smp_num_cpus 1
+#define smp_processor_id() 0
+#define hard_smp_processor_id() 0
+#define smp_threads_ready 1
+#define kernel_lock()
+#define cpu_logical_map(cpu) 0
+#define smp_call_function(func,info,retry,wait)
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/linux/smp_lock.h b/pfinet/linux-src/include/linux/smp_lock.h
new file mode 100644
index 00000000..4583e2f5
--- /dev/null
+++ b/pfinet/linux-src/include/linux/smp_lock.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_SMPLOCK_H
+#define __LINUX_SMPLOCK_H
+
+#ifndef __SMP__
+
+#define lock_kernel() do { } while(0)
+#define unlock_kernel() do { } while(0)
+#define release_kernel_lock(task, cpu) do { } while(0)
+#define reacquire_kernel_lock(task) do { } while(0)
+
+#else
+
+#include <asm/smplock.h>
+
+#endif /* __SMP__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/socket.h b/pfinet/linux-src/include/linux/socket.h
new file mode 100644
index 00000000..b427f992
--- /dev/null
+++ b/pfinet/linux-src/include/linux/socket.h
@@ -0,0 +1,280 @@
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#include <asm/socket.h> /* arch-dependent defines */
+#include <linux/sockios.h> /* the SIOCxxx I/O controls */
+#include <linux/uio.h> /* iovec support */
+#include <linux/types.h> /* pid_t */
+
+typedef unsigned short sa_family_t;
+
+/*
+ * 1003.1g requires sa_family_t and that sa_data is char.
+ */
+
+struct sockaddr {
+ sa_family_t sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+struct linger {
+ int l_onoff; /* Linger active */
+ int l_linger; /* How long to linger for */
+};
+
+/*
+ * As we do 4.4BSD message passing we use a 4.4BSD message passing
+ * system, not 4.3. Thus msg_accrights(len) are now missing. They
+ * belong in an obscure libc emulation or the bin.
+ */
+
+struct msghdr {
+ void * msg_name; /* Socket name */
+ int msg_namelen; /* Length of name */
+ struct iovec * msg_iov; /* Data blocks */
+ __kernel_size_t msg_iovlen; /* Number of blocks */
+ void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
+ __kernel_size_t msg_controllen; /* Length of cmsg list */
+ unsigned msg_flags;
+};
+
+/*
+ * POSIX 1003.1g - ancillary data object information
+ * Ancillary data consits of a sequence of pairs of
+ * (cmsghdr, cmsg_data[])
+ */
+
+struct cmsghdr {
+ __kernel_size_t cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+};
+
+/*
+ * Ancillary data object information MACROS
+ * Table 5-14 of POSIX 1003.1g
+ */
+
+#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg))
+#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
+
+#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
+
+#define CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
+#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+
+#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \
+ (struct cmsghdr *)(ctl) : \
+ (struct cmsghdr *)NULL)
+#define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+
+/*
+ * This mess will go away with glibc
+ */
+
+#ifdef __KERNEL__
+#define __KINLINE extern __inline__
+#elif defined(__GNUC__)
+#define __KINLINE static __inline__
+#elif defined(__cplusplus)
+#define __KINLINE static inline
+#else
+#define __KINLINE static
+#endif
+
+
+/*
+ * Get the next cmsg header
+ *
+ * PLEASE, do not touch this function. If you think, that it is
+ * incorrect, grep kernel sources and think about consequences
+ * before trying to improve it.
+ *
+ * Now it always returns valid, not truncated ancillary object
+ * HEADER. But caller still MUST check, that cmsg->cmsg_len is
+ * inside range, given by msg->msg_controllen before using
+ * ansillary object DATA. --ANK (980731)
+ */
+
+__KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
+ struct cmsghdr *__cmsg)
+{
+ struct cmsghdr * __ptr;
+
+ __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len));
+ if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+ return (struct cmsghdr*)0;
+
+ return __ptr;
+}
+
+__KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
+{
+ return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
+}
+
+/* "Socket"-level control message types: */
+
+#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
+#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
+#define SCM_CONNECT 0x03 /* rw: struct scm_connect */
+
+struct ucred {
+ __u32 pid;
+ __u32 uid;
+ __u32 gid;
+};
+
+
+/* Supported address families. */
+#define AF_UNSPEC 0
+#define AF_UNIX 1 /* Unix domain sockets */
+#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+#define AF_INET 2 /* Internet IP Protocol */
+#define AF_AX25 3 /* Amateur Radio AX.25 */
+#define AF_IPX 4 /* Novell IPX */
+#define AF_APPLETALK 5 /* AppleTalk DDP */
+#define AF_NETROM 6 /* Amateur Radio NET/ROM */
+#define AF_BRIDGE 7 /* Multiprotocol bridge */
+#define AF_ATMPVC 8 /* ATM PVCs */
+#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
+#define AF_ROSE 11 /* Amateur Radio X.25 PLP */
+#define AF_DECnet 12 /* Reserved for DECnet project */
+#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
+#define AF_SECURITY 14 /* Security callback pseudo AF */
+#define AF_KEY 15 /* PF_KEY key management API */
+#define AF_NETLINK 16
+#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */
+#define AF_PACKET 17 /* Packet family */
+#define AF_ASH 18 /* Ash */
+#define AF_ECONET 19 /* Acorn Econet */
+#define AF_ATMSVC 20 /* ATM SVCs */
+#define AF_SNA 22 /* Linux SNA Project (nutters!) */
+#define AF_IRDA 23 /* IRDA sockets */
+#define AF_MAX 32 /* For now.. */
+
+/* Protocol families, same as address families. */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_LOCAL AF_LOCAL
+#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NETROM AF_NETROM
+#define PF_BRIDGE AF_BRIDGE
+#define PF_ATMPVC AF_ATMPVC
+#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
+#define PF_ROSE AF_ROSE
+#define PF_DECnet AF_DECnet
+#define PF_NETBEUI AF_NETBEUI
+#define PF_SECURITY AF_SECURITY
+#define PF_KEY AF_KEY
+#define PF_NETLINK AF_NETLINK
+#define PF_ROUTE AF_ROUTE
+#define PF_PACKET AF_PACKET
+#define PF_ASH AF_ASH
+#define PF_ECONET AF_ECONET
+#define PF_ATMSVC AF_ATMSVC
+#define PF_SNA AF_SNA
+#define PF_IRDA AF_IRDA
+
+#define PF_MAX AF_MAX
+
+/* Maximum queue length specifiable by listen. */
+#define SOMAXCONN 128
+
+/* Flags we can use with send/ and recv.
+ Added those for 1003.1g not all are supported yet
+ */
+
+#define MSG_OOB 1
+#define MSG_PEEK 2
+#define MSG_DONTROUTE 4
+#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */
+#define MSG_CTRUNC 8
+#define MSG_PROXY 0x10 /* Supply or ask second address. */
+#define MSG_TRUNC 0x20
+#define MSG_DONTWAIT 0x40 /* Nonblocking io */
+#define MSG_EOR 0x80 /* End of record */
+#define MSG_WAITALL 0x100 /* Wait for a full request */
+#define MSG_FIN 0x200
+#define MSG_SYN 0x400
+#define MSG_URG 0x800
+#define MSG_RST 0x1000
+#define MSG_ERRQUEUE 0x2000
+#define MSG_NOSIGNAL 0x4000
+
+#define MSG_CTLIGNORE 0x80000000
+
+#define MSG_EOF MSG_FIN
+#define MSG_CTLFLAGS (MSG_OOB|MSG_URG|MSG_FIN|MSG_SYN|MSG_RST)
+
+
+/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
+#define SOL_IP 0
+/* #define SOL_ICMP 1 No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */
+#define SOL_TCP 6
+#define SOL_UDP 17
+#define SOL_IPV6 41
+#define SOL_ICMPV6 58
+#define SOL_RAW 255
+#define SOL_IPX 256
+#define SOL_AX25 257
+#define SOL_ATALK 258
+#define SOL_NETROM 259
+#define SOL_ROSE 260
+#define SOL_DECNET 261
+#define SOL_X25 262
+#define SOL_PACKET 263
+#define SOL_ATM 264 /* ATM layer (cell level) */
+#define SOL_AAL 265 /* ATM Adaption Layer (packet level) */
+#define SOL_IRDA 266
+
+/* IPX options */
+#define IPX_TYPE 1
+
+/* TCP options - this way around because someone left a set in the c library includes */
+#define TCP_NODELAY 1
+#define TCP_MAXSEG 2
+#define TCP_CORK 3 /* Linux specific (for use with sendfile) */
+
+#ifdef __KERNEL__
+extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
+extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov,
+ int offset, int len);
+extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
+ struct iovec *iov,
+ int offset,
+ unsigned int len, int *csump);
+
+extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
+extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
+extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len);
+extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
+extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
+extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
+#endif
+#endif /* not kernel and not glibc */
+
+#if !defined(__KERNEL__) && (!defined(__GLIBC__) || (__GLIBC__ < 2))
+
+/* Socket types for libc5 compatibility -- KTK */
+
+#define SOCK_STREAM 1 /* stream (connection) socket */
+#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
+#define SOCK_RAW 3 /* raw socket */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequential packet socket */
+#define SOCK_PACKET 10 /* linux specific way of */
+ /* getting packets at the dev */
+ /* level. For writing rarp and */
+ /* other similar things on the */
+ /* user level. */
+#endif /* libc<=5 && !kernel */
+#endif /* _LINUX_SOCKET_H */
diff --git a/pfinet/linux-src/include/linux/sockios.h b/pfinet/linux-src/include/linux/sockios.h
new file mode 100644
index 00000000..995e43e9
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sockios.h
@@ -0,0 +1,109 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions of the socket-level I/O control calls.
+ *
+ * Version: @(#)sockios.h 1.0.2 03/09/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_SOCKIOS_H
+#define _LINUX_SOCKIOS_H
+
+#include <asm/sockios.h>
+
+/* Routing table calls. */
+#define SIOCADDRT 0x890B /* add routing table entry */
+#define SIOCDELRT 0x890C /* delete routing table entry */
+#define SIOCRTMSG 0x890D /* call to routing system */
+
+/* Socket configuration controls. */
+#define SIOCGIFNAME 0x8910 /* get iface name */
+#define SIOCSIFLINK 0x8911 /* set iface channel */
+#define SIOCGIFCONF 0x8912 /* get iface list */
+#define SIOCGIFFLAGS 0x8913 /* get flags */
+#define SIOCSIFFLAGS 0x8914 /* set flags */
+#define SIOCGIFADDR 0x8915 /* get PA address */
+#define SIOCSIFADDR 0x8916 /* set PA address */
+#define SIOCGIFDSTADDR 0x8917 /* get remote PA address */
+#define SIOCSIFDSTADDR 0x8918 /* set remote PA address */
+#define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */
+#define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */
+#define SIOCGIFNETMASK 0x891b /* get network PA mask */
+#define SIOCSIFNETMASK 0x891c /* set network PA mask */
+#define SIOCGIFMETRIC 0x891d /* get metric */
+#define SIOCSIFMETRIC 0x891e /* set metric */
+#define SIOCGIFMEM 0x891f /* get memory address (BSD) */
+#define SIOCSIFMEM 0x8920 /* set memory address (BSD) */
+#define SIOCGIFMTU 0x8921 /* get MTU size */
+#define SIOCSIFMTU 0x8922 /* set MTU size */
+#define SIOCSIFNAME 0x8923 /* set interface name */
+#define SIOCSIFHWADDR 0x8924 /* set hardware address */
+#define SIOCGIFENCAP 0x8925 /* get/set encapsulations */
+#define SIOCSIFENCAP 0x8926
+#define SIOCGIFHWADDR 0x8927 /* Get hardware address */
+#define SIOCGIFSLAVE 0x8929 /* Driver slaving support */
+#define SIOCSIFSLAVE 0x8930
+#define SIOCADDMULTI 0x8931 /* Multicast address lists */
+#define SIOCDELMULTI 0x8932
+#define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */
+#define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */
+#define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */
+#define SIOCGIFPFLAGS 0x8935
+#define SIOCDIFADDR 0x8936 /* delete PA address */
+#define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */
+#define SIOCGIFCOUNT 0x8938 /* get number of devices */
+
+#define SIOCGIFBR 0x8940 /* Bridging support */
+#define SIOCSIFBR 0x8941 /* Set bridging options */
+
+#define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */
+#define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */
+
+
+/* ARP cache control calls. */
+ /* 0x8950 - 0x8952 * obsolete calls, don't re-use */
+#define SIOCDARP 0x8953 /* delete ARP table entry */
+#define SIOCGARP 0x8954 /* get ARP table entry */
+#define SIOCSARP 0x8955 /* set ARP table entry */
+
+/* RARP cache control calls. */
+#define SIOCDRARP 0x8960 /* delete RARP table entry */
+#define SIOCGRARP 0x8961 /* get RARP table entry */
+#define SIOCSRARP 0x8962 /* set RARP table entry */
+
+/* Driver configuration calls */
+
+#define SIOCGIFMAP 0x8970 /* Get device parameters */
+#define SIOCSIFMAP 0x8971 /* Set device parameters */
+
+/* DLCI configuration calls */
+
+#define SIOCADDDLCI 0x8980 /* Create new DLCI device */
+#define SIOCDELDLCI 0x8981 /* Delete DLCI device */
+
+/* Device private ioctl calls */
+
+/*
+ * These 16 ioctls are available to devices via the do_ioctl() device
+ * vector. Each device should include this file and redefine these names
+ * as their own. Because these are device dependent it is a good idea
+ * _NOT_ to issue them to random objects and hope.
+ */
+
+#define SIOCDEVPRIVATE 0x89F0 /* to 89FF */
+
+/*
+ * These 16 ioctl calls are protocol private
+ */
+
+#define SIOCPROTOPRIVATE 0x89E0 /* to 89EF */
+#endif /* _LINUX_SOCKIOS_H */
diff --git a/pfinet/linux-src/include/linux/sound.h b/pfinet/linux-src/include/linux/sound.h
new file mode 100644
index 00000000..4921b90e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sound.h
@@ -0,0 +1,15 @@
+/*
+ * Sound core interface functions
+ */
+
+extern int register_sound_special(struct file_operations *fops, int unit);
+extern int register_sound_mixer(struct file_operations *fops, int dev);
+extern int register_sound_midi(struct file_operations *fops, int dev);
+extern int register_sound_dsp(struct file_operations *fops, int dev);
+extern int register_sound_synth(struct file_operations *fops, int dev);
+
+extern void unregister_sound_special(int unit);
+extern void unregister_sound_mixer(int unit);
+extern void unregister_sound_midi(int unit);
+extern void unregister_sound_dsp(int unit);
+extern void unregister_sound_synth(int unit);
diff --git a/pfinet/linux-src/include/linux/soundcard.h b/pfinet/linux-src/include/linux/soundcard.h
new file mode 100644
index 00000000..2041b4d4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/soundcard.h
@@ -0,0 +1,1270 @@
+#ifndef SOUNDCARD_H
+#define 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
+
+/* In Linux we need to be prepared for cross compiling */
+#include <linux/ioctl.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
+#if defined(_IOWR) && (defined(_AIX) || (!defined(sun) && !defined(sparc) && !defined(__INCioctlh) && !defined(__Lynx__)))
+/* Use already defined ioctl defines if they exist (except with Sun) */
+#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
+#else
+
+/* Ioctl's have the command encoded in the lower word,
+ * and the size of any in or out parameters in the upper
+ * word. The high 2 bits of the upper word are used
+ * to encode the in/out status of the parameter; for now
+ * we restrict parameters to at most 8191 bytes.
+ */
+/* #define SIOCTYPE (0xff<<8) */
+#define SIOCPARM_MASK 0x1fff /* parameters must be < 8192 bytes */
+#define SIOC_VOID 0x00000000 /* no parameters */
+#define SIOC_OUT 0x20000000 /* copy out parameters */
+#define SIOC_IN 0x40000000 /* copy in parameters */
+#define SIOC_INOUT (SIOC_IN|SIOC_OUT)
+/* the 0x20000000 is so we can distinguish new ioctl's from old */
+#define _SIO(x,y) ((int)(SIOC_VOID|(x<<8)|y))
+#define _SIOR(x,y,t) ((int)(SIOC_OUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+#define _SIOW(x,y,t) ((int)(SIOC_IN|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+/* this should be _SIORW, but stdio got there first */
+#define _SIOWR(x,y,t) ((int)(SIOC_INOUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+#define _SIOC_SIZE(x) ((x>>16)&SIOCPARM_MASK)
+#define _SIOC_DIR(x) (x & 0xf0000000)
+#define _SIOC_NONE SIOC_VOID
+#define _SIOC_READ SIOC_OUT
+#define _SIOC_WRITE SIOC_IN
+# endif /* _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
+{
+ int devno; /* Synthesizer # */
+ char data[4000]; /* Device spesific command/data record */
+}synth_control;
+
+typedef struct remove_sample
+{
+ int devno; /* Synthesizer # */
+ int bankno; /* MIDI bank # (0=General MIDI) */
+ int instrno; /* MIDI instrument number */
+} remove_sample;
+
+typedef struct seq_event_rec {
+ unsigned char arr[8];
+} seq_event_rec;
+
+#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(_AIX) || defined(AIX) || defined(sparc) || defined(HPPA) || defined(PPC)
+/* Big endian machines */
+# define _PATCHKEY(id) (0xfd00|id)
+# define AFMT_S16_NE AFMT_S16_BE
+#else
+# define _PATCHKEY(id) ((id<<8)|0xfd)
+# define AFMT_S16_NE AFMT_S16_LE
+#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) */
+ };
+
+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 */
+ };
+
+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 */
+ };
+
+/********************************************
+ * ioctl commands for the /dev/midi##
+ */
+typedef struct {
+ unsigned char cmd;
+ char nr_args, nr_returns;
+ unsigned char data[30];
+ } mpu_command_rec;
+
+#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 */
+
+/*
+ * 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 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 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 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;
+#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)
+
+/*
+ * 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;
+
+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;
+
+typedef struct copr_msg {
+ int len;
+ unsigned char data[4000];
+ } copr_msg;
+
+#define SNDCTL_COPR_RESET _SIO ('C', 0)
+#define SNDCTL_COPR_LOAD _SIOWR('C', 1, copr_buffer)
+#define SNDCTL_COPR_RDATA _SIOWR('C', 2, copr_debug_buf)
+#define SNDCTL_COPR_RCODE _SIOWR('C', 3, copr_debug_buf)
+#define SNDCTL_COPR_WDATA _SIOW ('C', 4, copr_debug_buf)
+#define SNDCTL_COPR_WCODE _SIOW ('C', 5, copr_debug_buf)
+#define SNDCTL_COPR_RUN _SIOWR('C', 6, copr_debug_buf)
+#define SNDCTL_COPR_HALT _SIOWR('C', 7, copr_debug_buf)
+#define SNDCTL_COPR_SENDMSG _SIOWR('C', 8, copr_msg)
+#define SNDCTL_COPR_RCVMSG _SIOR ('C', 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('M', 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('M', 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];
+ char name[32];
+ int modify_counter;
+ int fillers[10];
+} mixer_info;
+
+typedef struct _old_mixer_info /* Obsolete */
+{
+ char id[16];
+ char name[32];
+} _old_mixer_info;
+
+#define SOUND_MIXER_INFO _SIOR ('M', 101, mixer_info)
+#define SOUND_OLD_MIXER_INFO _SIOR ('M', 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];
+
+#define SOUND_MIXER_ACCESS _SIOWR('M', 102, mixer_record)
+
+/*
+ * Two ioctls for special souncard function
+ */
+#define SOUND_MIXER_AGC _SIOWR('M', 103, int)
+#define SOUND_MIXER_3DSE _SIOWR('M', 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('M', 111, int)
+#define SOUND_MIXER_PRIVATE2 _SIOWR('M', 112, int)
+#define SOUND_MIXER_PRIVATE3 _SIOWR('M', 113, int)
+#define SOUND_MIXER_PRIVATE4 _SIOWR('M', 114, int)
+#define SOUND_MIXER_PRIVATE5 _SIOWR('M', 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 {
+ int num; /* Index to volume table */
+ char name[32];
+ int levels[32];
+} mixer_vol_table;
+
+#define SOUND_MIXER_GETLEVELS _SIOWR('M', 116, mixer_vol_table)
+#define SOUND_MIXER_SETLEVELS _SIOWR('M', 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 ('M', 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 synchronization 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
diff --git a/pfinet/linux-src/include/linux/soundmodem.h b/pfinet/linux-src/include/linux/soundmodem.h
new file mode 100644
index 00000000..10d0799d
--- /dev/null
+++ b/pfinet/linux-src/include/linux/soundmodem.h
@@ -0,0 +1,90 @@
+/*
+ * The Linux soundcard driver for 1200 baud and 9600 baud packet radio
+ * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA
+ */
+
+#ifndef _SOUNDMODEM_H
+#define _SOUNDMODEM_H
+
+/* -------------------------------------------------------------------- */
+/*
+ * structs for the IOCTL commands
+ */
+
+struct sm_debug_data {
+ unsigned int int_rate;
+ unsigned int mod_cycles;
+ unsigned int demod_cycles;
+ unsigned int dma_residue;
+};
+
+struct sm_diag_data {
+ unsigned int mode;
+ unsigned int flags;
+ unsigned int samplesperbit;
+ unsigned int datalen;
+ short *data;
+};
+
+struct sm_mixer_data {
+ unsigned int mixer_type;
+ unsigned int sample_rate;
+ unsigned int bit_rate;
+ unsigned int reg;
+ unsigned int data;
+};
+
+struct sm_config {
+ int hardware;
+ int mode;
+};
+
+struct sm_ioctl {
+ int cmd;
+ union {
+ struct sm_config cfg;
+ struct sm_diag_data diag;
+ struct sm_mixer_data mix;
+ struct sm_debug_data dbg;
+ } data;
+};
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * diagnose modes
+ */
+#define SM_DIAGMODE_OFF 0
+#define SM_DIAGMODE_INPUT 1
+#define SM_DIAGMODE_DEMOD 2
+#define SM_DIAGMODE_CONSTELLATION 3
+
+/*
+ * diagnose flags
+ */
+#define SM_DIAGFLAG_DCDGATE (1<<0)
+#define SM_DIAGFLAG_VALID (1<<1)
+
+/*
+ * mixer types
+ */
+#define SM_MIXER_INVALID 0
+#define SM_MIXER_AD1848 0x10
+#define SM_MIXER_CRYSTAL 0x11
+#define SM_MIXER_CT1335 0x20
+#define SM_MIXER_CT1345 0x21
+#define SM_MIXER_CT1745 0x22
+
+/*
+ * ioctl values
+ */
+#define SMCTL_DIAGNOSE 0x82
+#define SMCTL_GETMIXER 0x83
+#define SMCTL_SETMIXER 0x84
+#define SMCTL_GETDEBUG 0x85
+
+/* -------------------------------------------------------------------- */
+
+#endif /* _SOUNDMODEM_H */
+
+/* --------------------------------------------------------------------- */
diff --git a/pfinet/linux-src/include/linux/stallion.h b/pfinet/linux-src/include/linux/stallion.h
new file mode 100644
index 00000000..35274488
--- /dev/null
+++ b/pfinet/linux-src/include/linux/stallion.h
@@ -0,0 +1,156 @@
+/*****************************************************************************/
+
+/*
+ * stallion.h -- stallion multiport serial driver.
+ *
+ * Copyright (C) 1996-1998 Stallion Technologies (support@stallion.oz.au).
+ * Copyright (C) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*****************************************************************************/
+#ifndef _STALLION_H
+#define _STALLION_H
+/*****************************************************************************/
+
+/*
+ * Define important driver constants here.
+ */
+#define STL_MAXBRDS 4
+#define STL_MAXPANELS 4
+#define STL_MAXBANKS 8
+#define STL_PORTSPERPANEL 16
+#define STL_MAXPORTS 64
+#define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS)
+
+
+/*
+ * Define a set of structures to hold all the board/panel/port info
+ * for our ports. These will be dynamically allocated as required.
+ */
+
+/*
+ * Define a ring queue structure for each port. This will hold the
+ * TX data waiting to be output. Characters are fed into this buffer
+ * from the line discipline (or even direct from user space!) and
+ * then fed into the UARTs during interrupts. Will use a classic ring
+ * queue here for this. The good thing about this type of ring queue
+ * is that the head and tail pointers can be updated without interrupt
+ * protection - since "write" code only needs to change the head, and
+ * interrupt code only needs to change the tail.
+ */
+typedef struct {
+ char *buf;
+ char *head;
+ char *tail;
+} stlrq_t;
+
+/*
+ * Port, panel and board structures to hold status info about each.
+ * The board structure contains pointers to structures for each panel
+ * connected to it, and in turn each panel structure contains pointers
+ * for each port structure for each port on that panel. Note that
+ * the port structure also contains the board and panel number that it
+ * is associated with, this makes it (fairly) easy to get back to the
+ * board/panel info for a port.
+ */
+typedef struct stlport {
+ unsigned long magic;
+ int portnr;
+ int panelnr;
+ int brdnr;
+ int ioaddr;
+ int uartaddr;
+ int pagenr;
+ int istate;
+ int flags;
+ int baud_base;
+ int custom_divisor;
+ int close_delay;
+ int closing_wait;
+ int refcount;
+ int openwaitcnt;
+ int brklen;
+ long session;
+ long pgrp;
+ unsigned int sigs;
+ unsigned int rxignoremsk;
+ unsigned int rxmarkmsk;
+ unsigned int imr;
+ unsigned int crenable;
+ unsigned long clk;
+ unsigned long hwid;
+ void *uartp;
+ struct tty_struct *tty;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct termios normaltermios;
+ struct termios callouttermios;
+ struct tq_struct tqueue;
+ comstats_t stats;
+ stlrq_t tx;
+} stlport_t;
+
+typedef struct stlpanel {
+ unsigned long magic;
+ int panelnr;
+ int brdnr;
+ int pagenr;
+ int nrports;
+ int iobase;
+ void *uartp;
+ void (*isr)(struct stlpanel *panelp, unsigned int iobase);
+ unsigned int hwid;
+ unsigned int ackmask;
+ stlport_t *ports[STL_PORTSPERPANEL];
+} stlpanel_t;
+
+typedef struct stlbrd {
+ unsigned long magic;
+ int brdnr;
+ int brdtype;
+ int state;
+ int nrpanels;
+ int nrports;
+ int nrbnks;
+ int irq;
+ int irqtype;
+ void (*isr)(struct stlbrd *brdp);
+ unsigned int ioaddr1;
+ unsigned int ioaddr2;
+ unsigned int iosize1;
+ unsigned int iosize2;
+ unsigned int iostatus;
+ unsigned int ioctrl;
+ unsigned int ioctrlval;
+ unsigned int hwid;
+ unsigned long clk;
+ unsigned int bnkpageaddr[STL_MAXBANKS];
+ unsigned int bnkstataddr[STL_MAXBANKS];
+ stlpanel_t *bnk2panel[STL_MAXBANKS];
+ stlpanel_t *panels[STL_MAXPANELS];
+} stlbrd_t;
+
+
+/*
+ * Define MAGIC numbers used for above structures.
+ */
+#define STL_PORTMAGIC 0x5a7182c9
+#define STL_PANELMAGIC 0x7ef621a1
+#define STL_BOARDMAGIC 0xa2267f52
+
+/*****************************************************************************/
+#endif
diff --git a/pfinet/linux-src/include/linux/stat.h b/pfinet/linux-src/include/linux/stat.h
new file mode 100644
index 00000000..e43e241f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/stat.h
@@ -0,0 +1,57 @@
+#ifndef _LINUX_STAT_H
+#define _LINUX_STAT_H
+
+#ifdef __KERNEL__
+
+#include <asm/stat.h>
+
+#endif
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#endif
+
+#ifdef __KERNEL__
+#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
+#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
+#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/stddef.h b/pfinet/linux-src/include/linux/stddef.h
new file mode 100644
index 00000000..dfa23221
--- /dev/null
+++ b/pfinet/linux-src/include/linux/stddef.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_STDDEF_H
+#define _LINUX_STDDEF_H
+
+#undef NULL
+#if defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif
diff --git a/pfinet/linux-src/include/linux/string.h b/pfinet/linux-src/include/linux/string.h
new file mode 100644
index 00000000..9ea63cd0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/string.h
@@ -0,0 +1,43 @@
+#ifndef _LINUX_STRING_H_
+#define _LINUX_STRING_H_
+
+#include <linux/types.h> /* for size_t */
+#include <linux/stddef.h> /* for NULL */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char * ___strtok;
+extern char * strcpy(char *,const char *);
+extern char * strncpy(char *,const char *, __kernel_size_t);
+extern char * strcat(char *, const char *);
+extern char * strncat(char *, const char *, __kernel_size_t);
+extern char * strchr(const char *,int);
+extern char * strrchr(const char *,int);
+extern char * strpbrk(const char *,const char *);
+extern char * strtok(char *,const char *);
+extern char * strstr(const char *,const char *);
+extern __kernel_size_t strlen(const char *);
+extern __kernel_size_t strnlen(const char *,__kernel_size_t);
+extern __kernel_size_t strspn(const char *,const char *);
+extern int strcmp(const char *,const char *);
+extern int strncmp(const char *,const char *,__kernel_size_t);
+extern int strnicmp(const char *, const char *, __kernel_size_t);
+
+extern void * memset(void *,int,__kernel_size_t);
+extern void * memcpy(void *,const void *,__kernel_size_t);
+extern void * memmove(void *,const void *,__kernel_size_t);
+extern void * memscan(void *,int,__kernel_size_t);
+extern int memcmp(const void *,const void *,__kernel_size_t);
+
+/*
+ * Include machine specific inline routines
+ */
+#include <asm/string.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LINUX_STRING_H_ */
diff --git a/pfinet/linux-src/include/linux/swap.h b/pfinet/linux-src/include/linux/swap.h
new file mode 100644
index 00000000..0e3d2763
--- /dev/null
+++ b/pfinet/linux-src/include/linux/swap.h
@@ -0,0 +1,175 @@
+#ifndef _LINUX_SWAP_H
+#define _LINUX_SWAP_H
+
+#include <asm/page.h>
+
+#define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */
+#define SWAP_FLAG_PRIO_MASK 0x7fff
+#define SWAP_FLAG_PRIO_SHIFT 0
+
+#define MAX_SWAPFILES 8
+
+union swap_header {
+ struct
+ {
+ char reserved[PAGE_SIZE - 10];
+ char magic[10];
+ } magic;
+ struct
+ {
+ char bootbits[1024]; /* Space for disklabel etc. */
+ unsigned int version;
+ unsigned int last_page;
+ unsigned int nr_badpages;
+ unsigned int padding[125];
+ unsigned int badpages[1];
+ } info;
+};
+
+#ifdef __KERNEL__
+
+/*
+ * Max bad pages in the new format..
+ */
+#define __swapoffset(x) ((unsigned long)&((union swap_header *)0)->x)
+#define MAX_SWAP_BADPAGES \
+ ((__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int))
+
+#undef DEBUG_SWAP
+
+#include <asm/atomic.h>
+
+#define SWP_USED 1
+#define SWP_WRITEOK 3
+
+#define SWAP_CLUSTER_MAX 32
+
+#define SWAP_MAP_MAX 0x7fff
+#define SWAP_MAP_BAD 0x8000
+
+struct swap_info_struct {
+ unsigned int flags;
+ kdev_t swap_device;
+ struct dentry * swap_file;
+ unsigned short * swap_map;
+ unsigned char * swap_lockmap;
+ unsigned int lowest_bit;
+ unsigned int highest_bit;
+ unsigned int cluster_next;
+ unsigned int cluster_nr;
+ int prio; /* swap priority */
+ int pages;
+ unsigned long max;
+ int next; /* next entry on swap list */
+};
+
+extern int nr_swap_pages;
+extern int nr_free_pages;
+extern atomic_t nr_async_pages;
+extern struct inode swapper_inode;
+extern unsigned long page_cache_size;
+extern long buffermem;
+
+/* Incomplete types for prototype declarations: */
+struct task_struct;
+struct vm_area_struct;
+struct sysinfo;
+
+/* linux/ipc/shm.c */
+extern int shm_swap (int, int);
+
+/* linux/mm/swap.c */
+extern void swap_setup (void);
+
+/* linux/mm/vmscan.c */
+extern int try_to_free_pages(unsigned int gfp_mask);
+
+/* linux/mm/page_io.c */
+extern void rw_swap_page(int, unsigned long, char *, int);
+extern void rw_swap_page_nocache(int, unsigned long, char *);
+extern void rw_swap_page_nolock(int, unsigned long, char *, int);
+extern void swap_after_unlock_page (unsigned long entry);
+
+/* linux/mm/page_alloc.c */
+extern int swap_in(struct task_struct *, struct vm_area_struct *,
+ pte_t *, unsigned long, int);
+
+
+/* linux/mm/swap_state.c */
+extern void show_swap_cache_info(void);
+extern int add_to_swap_cache(struct page *, unsigned long);
+extern int swap_duplicate(unsigned long);
+extern int swap_check_entry(unsigned long);
+struct page * lookup_swap_cache(unsigned long);
+extern struct page * read_swap_cache_async(unsigned long, int);
+#define read_swap_cache(entry) read_swap_cache_async(entry, 1);
+extern int FASTCALL(swap_count(unsigned long));
+/*
+ * Make these inline later once they are working properly.
+ */
+extern void delete_from_swap_cache(struct page *page);
+extern void free_page_and_swap_cache(unsigned long addr);
+
+/* linux/mm/swapfile.c */
+extern unsigned int nr_swapfiles;
+extern struct swap_info_struct swap_info[];
+void si_swapinfo(struct sysinfo *);
+unsigned long get_swap_page(void);
+extern void FASTCALL(swap_free(unsigned long));
+struct swap_list_t {
+ int head; /* head of priority-ordered swapfile list */
+ int next; /* swapfile to be used next */
+};
+extern struct swap_list_t swap_list;
+asmlinkage int sys_swapoff(const char *);
+asmlinkage int sys_swapon(const char *, int);
+
+/*
+ * vm_ops not present page codes for shared memory.
+ *
+ * Will go away eventually..
+ */
+#define SHM_SWP_TYPE 0x20
+
+/*
+ * swap cache stuff (in linux/mm/swap_state.c)
+ */
+
+#define SWAP_CACHE_INFO
+
+#ifdef SWAP_CACHE_INFO
+extern unsigned long swap_cache_add_total;
+extern unsigned long swap_cache_del_total;
+extern unsigned long swap_cache_find_total;
+extern unsigned long swap_cache_find_success;
+#endif
+
+extern inline unsigned long in_swap_cache(struct page *page)
+{
+ if (PageSwapCache(page))
+ return page->offset;
+ return 0;
+}
+
+/*
+ * Work out if there are any other processes sharing this page, ignoring
+ * any page reference coming from the swap cache, or from outstanding
+ * swap IO on this page. (The page cache _does_ count as another valid
+ * reference to the page, however.)
+ */
+static inline int is_page_shared(struct page *page)
+{
+ unsigned int count;
+ if (PageReserved(page))
+ return 1;
+ count = atomic_read(&page->count);
+ if (PageSwapCache(page))
+ count += swap_count(page->offset) - 2;
+ if (PageFreeAfter(page))
+ count--;
+ return count > 1;
+}
+
+#endif /* __KERNEL__*/
+
+#endif /* _LINUX_SWAP_H */
diff --git a/pfinet/linux-src/include/linux/swapctl.h b/pfinet/linux-src/include/linux/swapctl.h
new file mode 100644
index 00000000..f9f2d2ac
--- /dev/null
+++ b/pfinet/linux-src/include/linux/swapctl.h
@@ -0,0 +1,35 @@
+#ifndef _LINUX_SWAPCTL_H
+#define _LINUX_SWAPCTL_H
+
+#include <asm/page.h>
+#include <linux/fs.h>
+
+typedef struct buffer_mem_v1
+{
+ unsigned int min_percent;
+ unsigned int borrow_percent;
+ unsigned int max_percent;
+} buffer_mem_v1;
+typedef buffer_mem_v1 buffer_mem_t;
+extern buffer_mem_t buffer_mem;
+extern buffer_mem_t page_cache;
+
+typedef struct freepages_v1
+{
+ unsigned int min;
+ unsigned int low;
+ unsigned int high;
+} freepages_v1;
+typedef freepages_v1 freepages_t;
+extern freepages_t freepages;
+
+typedef struct pager_daemon_v1
+{
+ unsigned int tries_base;
+ unsigned int tries_min;
+ unsigned int swap_cluster;
+} pager_daemon_v1;
+typedef pager_daemon_v1 pager_daemon_t;
+extern pager_daemon_t pager_daemon;
+
+#endif /* _LINUX_SWAPCTL_H */
diff --git a/pfinet/linux-src/include/linux/synclink.h b/pfinet/linux-src/include/linux/synclink.h
new file mode 100644
index 00000000..450341b7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/synclink.h
@@ -0,0 +1,255 @@
+/*
+ * SyncLink Multiprotocol Serial Adapter Driver
+ *
+ * ==FILEDATE 19990810==
+ *
+ * Copyright (C) 1998 by Microgate Corporation
+ *
+ * Redistribution of this file is permitted under
+ * the terms of the GNU Public License (GPL)
+ */
+
+#ifndef _SYNCLINK_H_
+#define _SYNCLINK_H_
+
+#define BOOLEAN int
+#define TRUE 1
+#define FALSE 0
+
+#define BIT0 0x0001
+#define BIT1 0x0002
+#define BIT2 0x0004
+#define BIT3 0x0008
+#define BIT4 0x0010
+#define BIT5 0x0020
+#define BIT6 0x0040
+#define BIT7 0x0080
+#define BIT8 0x0100
+#define BIT9 0x0200
+#define BIT10 0x0400
+#define BIT11 0x0800
+#define BIT12 0x1000
+#define BIT13 0x2000
+#define BIT14 0x4000
+#define BIT15 0x8000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+
+
+#define HDLC_MAX_FRAME_SIZE 65535
+#define MAX_ASYNC_TRANSMIT 4096
+#define MAX_ASYNC_BUFFER_SIZE 4096
+
+#define ASYNC_PARITY_NONE 0
+#define ASYNC_PARITY_EVEN 1
+#define ASYNC_PARITY_ODD 2
+#define ASYNC_PARITY_SPACE 3
+
+#define HDLC_FLAG_UNDERRUN_ABORT7 0x0000
+#define HDLC_FLAG_UNDERRUN_ABORT15 0x0001
+#define HDLC_FLAG_UNDERRUN_FLAG 0x0002
+#define HDLC_FLAG_UNDERRUN_CRC 0x0004
+#define HDLC_FLAG_SHARE_ZERO 0x0010
+#define HDLC_FLAG_AUTO_CTS 0x0020
+#define HDLC_FLAG_AUTO_DCD 0x0040
+#define HDLC_FLAG_AUTO_RTS 0x0080
+#define HDLC_FLAG_RXC_DPLL 0x0100
+#define HDLC_FLAG_RXC_BRG 0x0200
+#define HDLC_FLAG_RXC_TXCPIN 0x8000
+#define HDLC_FLAG_RXC_RXCPIN 0x0000
+#define HDLC_FLAG_TXC_DPLL 0x0400
+#define HDLC_FLAG_TXC_BRG 0x0800
+#define HDLC_FLAG_TXC_TXCPIN 0x0000
+#define HDLC_FLAG_TXC_RXCPIN 0x0008
+#define HDLC_FLAG_DPLL_DIV8 0x1000
+#define HDLC_FLAG_DPLL_DIV16 0x2000
+#define HDLC_FLAG_DPLL_DIV32 0x0000
+#define HDLC_FLAG_HDLC_LOOPMODE 0x4000
+
+#define HDLC_CRC_NONE 0
+#define HDLC_CRC_16_CCITT 1
+#define HDLC_CRC_32_CCITT 2
+
+#define HDLC_TXIDLE_FLAGS 0
+#define HDLC_TXIDLE_ALT_ZEROS_ONES 1
+#define HDLC_TXIDLE_ZEROS 2
+#define HDLC_TXIDLE_ONES 3
+#define HDLC_TXIDLE_ALT_MARK_SPACE 4
+#define HDLC_TXIDLE_SPACE 5
+#define HDLC_TXIDLE_MARK 6
+
+#define HDLC_ENCODING_NRZ 0
+#define HDLC_ENCODING_NRZB 1
+#define HDLC_ENCODING_NRZI_MARK 2
+#define HDLC_ENCODING_NRZI_SPACE 3
+#define HDLC_ENCODING_NRZI HDLC_ENCODING_NRZI_SPACE
+#define HDLC_ENCODING_BIPHASE_MARK 4
+#define HDLC_ENCODING_BIPHASE_SPACE 5
+#define HDLC_ENCODING_BIPHASE_LEVEL 6
+#define HDLC_ENCODING_DIFF_BIPHASE_LEVEL 7
+
+#define HDLC_PREAMBLE_LENGTH_8BITS 0
+#define HDLC_PREAMBLE_LENGTH_16BITS 1
+#define HDLC_PREAMBLE_LENGTH_32BITS 2
+#define HDLC_PREAMBLE_LENGTH_64BITS 3
+
+#define HDLC_PREAMBLE_PATTERN_NONE 0
+#define HDLC_PREAMBLE_PATTERN_ZEROS 1
+#define HDLC_PREAMBLE_PATTERN_FLAGS 2
+#define HDLC_PREAMBLE_PATTERN_10 3
+#define HDLC_PREAMBLE_PATTERN_01 4
+#define HDLC_PREAMBLE_PATTERN_ONES 5
+
+#define MGSL_MODE_ASYNC 1
+#define MGSL_MODE_HDLC 2
+
+#define MGSL_BUS_TYPE_ISA 1
+#define MGSL_BUS_TYPE_EISA 2
+#define MGSL_BUS_TYPE_PCI 5
+
+typedef struct _MGSL_PARAMS
+{
+ /* Common */
+
+ unsigned long mode; /* Asynchronous or HDLC */
+ unsigned char loopback; /* internal loopback mode */
+
+ /* HDLC Only */
+
+ unsigned short flags;
+ unsigned char encoding; /* NRZ, NRZI, etc. */
+ unsigned long clock_speed; /* external clock speed in bits per second */
+ unsigned char addr_filter; /* receive HDLC address filter, 0xFF = disable */
+ unsigned short crc_type; /* None, CRC16-CCITT, or CRC32-CCITT */
+ unsigned char preamble_length;
+ unsigned char preamble;
+
+ /* Async Only */
+
+ unsigned long data_rate; /* bits per second */
+ unsigned char data_bits; /* 7 or 8 data bits */
+ unsigned char stop_bits; /* 1 or 2 stop bits */
+ unsigned char parity; /* none, even, or odd */
+
+} MGSL_PARAMS, *PMGSL_PARAMS;
+
+#define MICROGATE_VENDOR_ID 0x13c0
+#define SYNCLINK_DEVICE_ID 0x0010
+#define MGSL_MAX_SERIAL_NUMBER 30
+
+/*
+** device diagnostics status
+*/
+
+#define DiagStatus_OK 0
+#define DiagStatus_AddressFailure 1
+#define DiagStatus_AddressConflict 2
+#define DiagStatus_IrqFailure 3
+#define DiagStatus_IrqConflict 4
+#define DiagStatus_DmaFailure 5
+#define DiagStatus_DmaConflict 6
+#define DiagStatus_PciAdapterNotFound 7
+#define DiagStatus_CantAssignPciResources 8
+#define DiagStatus_CantAssignPciMemAddr 9
+#define DiagStatus_CantAssignPciIoAddr 10
+#define DiagStatus_CantAssignPciIrq 11
+#define DiagStatus_MemoryError 12
+
+#define SerialSignal_DCD 0x01 /* Data Carrier Detect */
+#define SerialSignal_TXD 0x02 /* Transmit Data */
+#define SerialSignal_RI 0x04 /* Ring Indicator */
+#define SerialSignal_RXD 0x08 /* Receive Data */
+#define SerialSignal_CTS 0x10 /* Clear to Send */
+#define SerialSignal_RTS 0x20 /* Request to Send */
+#define SerialSignal_DSR 0x40 /* Data Set Ready */
+#define SerialSignal_DTR 0x80 /* Data Terminal Ready */
+
+
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+struct mgsl_icount {
+ __u32 cts, dsr, rng, dcd, tx, rx;
+ __u32 frame, parity, overrun, brk;
+ __u32 buf_overrun;
+ __u32 txok;
+ __u32 txunder;
+ __u32 txabort;
+ __u32 txtimeout;
+ __u32 rxshort;
+ __u32 rxlong;
+ __u32 rxabort;
+ __u32 rxover;
+ __u32 rxcrc;
+ __u32 rxok;
+ __u32 exithunt;
+ __u32 rxidle;
+};
+
+
+#define DEBUG_LEVEL_DATA 1
+#define DEBUG_LEVEL_ERROR 2
+#define DEBUG_LEVEL_INFO 3
+#define DEBUG_LEVEL_BH 4
+#define DEBUG_LEVEL_ISR 5
+
+/*
+** Event bit flags for use with MgslWaitEvent
+*/
+
+#define MgslEvent_DsrActive 0x0001
+#define MgslEvent_DsrInactive 0x0002
+#define MgslEvent_Dsr 0x0003
+#define MgslEvent_CtsActive 0x0004
+#define MgslEvent_CtsInactive 0x0008
+#define MgslEvent_Cts 0x000c
+#define MgslEvent_DcdActive 0x0010
+#define MgslEvent_DcdInactive 0x0020
+#define MgslEvent_Dcd 0x0030
+#define MgslEvent_RiActive 0x0040
+#define MgslEvent_RiInactive 0x0080
+#define MgslEvent_Ri 0x00c0
+#define MgslEvent_ExitHuntMode 0x0100
+#define MgslEvent_IdleReceived 0x0200
+
+/* Private IOCTL codes:
+ *
+ * MGSL_IOCSPARAMS set MGSL_PARAMS structure values
+ * MGSL_IOCGPARAMS get current MGSL_PARAMS structure values
+ * MGSL_IOCSTXIDLE set current transmit idle mode
+ * MGSL_IOCGTXIDLE get current transmit idle mode
+ * MGSL_IOCTXENABLE enable or disable transmitter
+ * MGSL_IOCRXENABLE enable or disable receiver
+ * MGSL_IOCTXABORT abort transmitting frame (HDLC)
+ * MGSL_IOCGSTATS return current statistics
+ * MGSL_IOCWAITEVENT wait for specified event to occur
+ * MGSL_LOOPTXDONE transmit in HDLC LoopMode done
+ */
+#define MGSL_MAGIC_IOC 'm'
+#define MGSL_IOCSPARAMS _IOW(MGSL_MAGIC_IOC,0,struct _MGSL_PARAMS)
+#define MGSL_IOCGPARAMS _IOR(MGSL_MAGIC_IOC,1,struct _MGSL_PARAMS)
+#define MGSL_IOCSTXIDLE _IO(MGSL_MAGIC_IOC,2)
+#define MGSL_IOCGTXIDLE _IO(MGSL_MAGIC_IOC,3)
+#define MGSL_IOCTXENABLE _IO(MGSL_MAGIC_IOC,4)
+#define MGSL_IOCRXENABLE _IO(MGSL_MAGIC_IOC,5)
+#define MGSL_IOCTXABORT _IO(MGSL_MAGIC_IOC,6)
+#define MGSL_IOCGSTATS _IO(MGSL_MAGIC_IOC,7)
+#define MGSL_IOCWAITEVENT _IOWR(MGSL_MAGIC_IOC,8,int)
+#define MGSL_IOCCLRMODCOUNT _IO(MGSL_MAGIC_IOC,15)
+#define MGSL_IOCLOOPTXDONE _IO(MGSL_MAGIC_IOC,9)
+
+#endif /* _SYNCLINK_H_ */
diff --git a/pfinet/linux-src/include/linux/sys.h b/pfinet/linux-src/include/linux/sys.h
new file mode 100644
index 00000000..dcd32566
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sys.h
@@ -0,0 +1,30 @@
+#ifndef _LINUX_SYS_H
+#define _LINUX_SYS_H
+
+/*
+ * system call entry points ... but not all are defined
+ */
+#define NR_syscalls 256
+
+/*
+ * These are system calls that will be removed at some time
+ * due to newer versions existing..
+ * (please be careful - ibcs2 may need some of these).
+ */
+#ifdef notdef
+#define _sys_waitpid _sys_old_syscall /* _sys_wait4 */
+#define _sys_olduname _sys_old_syscall /* _sys_newuname */
+#define _sys_uname _sys_old_syscall /* _sys_newuname */
+#define _sys_stat _sys_old_syscall /* _sys_newstat */
+#define _sys_fstat _sys_old_syscall /* _sys_newfstat */
+#define _sys_lstat _sys_old_syscall /* _sys_newlstat */
+#define _sys_signal _sys_old_syscall /* _sys_sigaction */
+#define _sys_sgetmask _sys_old_syscall /* _sys_sigprocmask */
+#define _sys_ssetmask _sys_old_syscall /* _sys_sigprocmask */
+#endif
+
+/*
+ * These are system calls that haven't been implemented yet
+ * but have an entry in the table for future expansion..
+ */
+#endif
diff --git a/pfinet/linux-src/include/linux/sysctl.h b/pfinet/linux-src/include/linux/sysctl.h
new file mode 100644
index 00000000..00bebabe
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sysctl.h
@@ -0,0 +1,559 @@
+/*
+ * sysctl.h: General linux system control interface
+ *
+ * Begun 24 March 1995, Stephen Tweedie
+ *
+ ****************************************************************
+ ****************************************************************
+ **
+ ** WARNING:
+ ** The values in this file are exported to user space via
+ ** the sysctl() binary interface. Do *NOT* change the
+ ** numbering of any existing values here, and do not change
+ ** any numbers within any one set of values. If you have
+ ** to redefine an existing interface, use a new number for it.
+ ** The kernel will then return ENOTDIR to any application using
+ ** the old binary interface.
+ **
+ ** --sct
+ **
+ ****************************************************************
+ ****************************************************************
+ */
+
+#include <linux/lists.h>
+
+#ifndef _LINUX_SYSCTL_H
+#define _LINUX_SYSCTL_H
+
+#define CTL_MAXNAME 10
+
+struct __sysctl_args {
+ int *name;
+ int nlen;
+ void *oldval;
+ size_t *oldlenp;
+ void *newval;
+ size_t newlen;
+ unsigned long __unused[4];
+};
+
+/* Define sysctl names first */
+
+/* Top-level names: */
+
+/* For internal pattern-matching use only: */
+#ifdef __KERNEL__
+#define CTL_ANY -1 /* Matches any name */
+#define CTL_NONE 0
+#endif
+
+enum
+{
+ CTL_KERN=1, /* General kernel info and control */
+ CTL_VM=2, /* VM management */
+ CTL_NET=3, /* Networking */
+ CTL_PROC=4, /* Process info */
+ CTL_FS=5, /* Filesystems */
+ CTL_DEBUG=6, /* Debugging */
+ CTL_DEV=7, /* Devices */
+ CTL_BUS=8 /* Buses */
+};
+
+/* CTL_BUS names: */
+enum
+{
+ BUS_ISA=1 /* ISA */
+};
+
+/* CTL_KERN names: */
+enum
+{
+ KERN_OSTYPE=1, /* string: system version */
+ KERN_OSRELEASE=2, /* string: system release */
+ KERN_OSREV=3, /* int: system revision */
+ KERN_VERSION=4, /* string: compile time info */
+ KERN_SECUREMASK=5, /* struct: maximum rights mask */
+ KERN_PROF=6, /* table: profiling information */
+ KERN_NODENAME=7,
+ KERN_DOMAINNAME=8,
+
+ KERN_CAP_BSET=14, /* int: capability bounding set */
+ KERN_PANIC=15, /* int: panic timeout */
+ KERN_REALROOTDEV=16, /* real root device to mount after initrd */
+
+ KERN_JAVA_INTERPRETER=19, /* path to Java(tm) interpreter */
+ KERN_JAVA_APPLETVIEWER=20, /* path to Java(tm) appletviewer */
+ KERN_SPARC_REBOOT=21, /* reboot command on Sparc */
+ KERN_CTLALTDEL=22, /* int: allow ctl-alt-del to reboot */
+ KERN_PRINTK=23, /* struct: control printk logging parameters */
+ KERN_NAMETRANS=24, /* Name translation */
+ KERN_PPC_HTABRECLAIM=25, /* turn htab reclaimation on/off on PPC */
+ KERN_PPC_ZEROPAGED=26, /* turn idle page zeroing on/off on PPC */
+ KERN_PPC_POWERSAVE_NAP=27, /* use nap mode for power saving */
+ KERN_MODPROBE=28,
+ KERN_SG_BIG_BUFF=29,
+ KERN_ACCT=30, /* BSD process accounting parameters */
+ KERN_PPC_L2CR=31, /* l2cr register on PPC */
+
+ KERN_RTSIGNR=32, /* Number of rt sigs queued */
+ KERN_RTSIGMAX=33, /* Max queuable */
+
+ KERN_SHMMAX=34, /* int: Maximum shared memory segment */
+ KERN_MSGMAX=35, /* int: Maximum size of a messege */
+ KERN_MSGMNB=36, /* int: Maximum message queue size */
+ KERN_MSGPOOL=37, /* int: Maximum system message pool size */
+ KERN_SYSRQ=38, /* int: Sysreq enable */
+ KERN_SHMALL=41, /* int: maximum size of shared memory */
+ KERN_SPARC_STOP_A=44, /* int: Sparc Stop-A enable */
+};
+
+
+/* CTL_VM names: */
+enum
+{
+ VM_SWAPCTL=1, /* struct: Set vm swapping control */
+ VM_SWAPOUT=2, /* int: Background pageout interval */
+ VM_FREEPG=3, /* struct: Set free page thresholds */
+ VM_BDFLUSH=4, /* struct: Control buffer cache flushing */
+ VM_OVERCOMMIT_MEMORY=5, /* Turn off the virtual memory safety limit */
+ VM_BUFFERMEM=6, /* struct: Set buffer memory thresholds */
+ VM_PAGECACHE=7, /* struct: Set cache memory thresholds */
+ VM_PAGERDAEMON=8, /* struct: Control kswapd behaviour */
+ VM_PGT_CACHE=9, /* struct: Set page table cache parameters */
+ VM_PAGE_CLUSTER=10 /* int: set number of pages to swap together */
+};
+
+
+/* CTL_NET names: */
+enum
+{
+ NET_CORE=1,
+ NET_ETHER=2,
+ NET_802=3,
+ NET_UNIX=4,
+ NET_IPV4=5,
+ NET_IPX=6,
+ NET_ATALK=7,
+ NET_NETROM=8,
+ NET_AX25=9,
+ NET_BRIDGE=10,
+ NET_ROSE=11,
+ NET_IPV6=12,
+ NET_X25=13,
+ NET_TR=14,
+ NET_DECNET=15,
+ NET_ECONET=16
+};
+
+/* /proc/sys/bus/isa */
+enum
+{
+ BUS_ISA_MEM_BASE=1,
+ BUS_ISA_PORT_BASE=2,
+ BUS_ISA_PORT_SHIFT=3
+};
+
+/* /proc/sys/net/core */
+enum
+{
+ NET_CORE_WMEM_MAX=1,
+ NET_CORE_RMEM_MAX=2,
+ NET_CORE_WMEM_DEFAULT=3,
+ NET_CORE_RMEM_DEFAULT=4,
+/* was NET_CORE_DESTROY_DELAY */
+ NET_CORE_MAX_BACKLOG=6,
+ NET_CORE_FASTROUTE=7,
+ NET_CORE_MSG_COST=8,
+ NET_CORE_MSG_BURST=9,
+ NET_CORE_OPTMEM_MAX=10
+};
+
+/* /proc/sys/net/ethernet */
+
+/* /proc/sys/net/802 */
+
+/* /proc/sys/net/unix */
+
+enum
+{
+ NET_UNIX_DESTROY_DELAY=1,
+ NET_UNIX_DELETE_DELAY=2,
+ NET_UNIX_MAX_DGRAM_QLEN=3,
+};
+
+/* /proc/sys/net/ipv4 */
+enum
+{
+ /* v2.0 compatibile variables */
+ NET_IPV4_FORWARD=8,
+ NET_IPV4_DYNADDR=9,
+
+ NET_IPV4_CONF=16,
+ NET_IPV4_NEIGH=17,
+ NET_IPV4_ROUTE=18,
+ NET_IPV4_FIB_HASH=19,
+
+ NET_IPV4_TCP_TIMESTAMPS=33,
+ NET_IPV4_TCP_WINDOW_SCALING=34,
+ NET_IPV4_TCP_SACK=35,
+ NET_IPV4_TCP_RETRANS_COLLAPSE=36,
+ NET_IPV4_DEFAULT_TTL=37,
+ NET_IPV4_AUTOCONFIG=38,
+ NET_IPV4_NO_PMTU_DISC=39,
+ NET_IPV4_TCP_SYN_RETRIES=40,
+ NET_IPV4_IPFRAG_HIGH_THRESH=41,
+ NET_IPV4_IPFRAG_LOW_THRESH=42,
+ NET_IPV4_IPFRAG_TIME=43,
+ NET_IPV4_TCP_MAX_KA_PROBES=44,
+ NET_IPV4_TCP_KEEPALIVE_TIME=45,
+ NET_IPV4_TCP_KEEPALIVE_PROBES=46,
+ NET_IPV4_TCP_RETRIES1=47,
+ NET_IPV4_TCP_RETRIES2=48,
+ NET_IPV4_TCP_FIN_TIMEOUT=49,
+ NET_IPV4_IP_MASQ_DEBUG=50,
+ NET_TCP_SYNCOOKIES=51,
+ NET_TCP_STDURG=52,
+ NET_TCP_RFC1337=53,
+ NET_TCP_SYN_TAILDROP=54,
+ NET_TCP_MAX_SYN_BACKLOG=55,
+ NET_IPV4_LOCAL_PORT_RANGE=56,
+ NET_IPV4_ICMP_ECHO_IGNORE_ALL=57,
+ NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS=58,
+ NET_IPV4_ICMP_SOURCEQUENCH_RATE=59,
+ NET_IPV4_ICMP_DESTUNREACH_RATE=60,
+ NET_IPV4_ICMP_TIMEEXCEED_RATE=61,
+ NET_IPV4_ICMP_PARAMPROB_RATE=62,
+ NET_IPV4_ICMP_ECHOREPLY_RATE=63,
+ NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
+ NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
+ NET_IPV4_ALWAYS_DEFRAG=67
+};
+
+enum {
+ NET_IPV4_ROUTE_FLUSH=1,
+ NET_IPV4_ROUTE_MIN_DELAY=2,
+ NET_IPV4_ROUTE_MAX_DELAY=3,
+ NET_IPV4_ROUTE_GC_THRESH=4,
+ NET_IPV4_ROUTE_MAX_SIZE=5,
+ NET_IPV4_ROUTE_GC_MIN_INTERVAL=6,
+ NET_IPV4_ROUTE_GC_TIMEOUT=7,
+ NET_IPV4_ROUTE_GC_INTERVAL=8,
+ NET_IPV4_ROUTE_REDIRECT_LOAD=9,
+ NET_IPV4_ROUTE_REDIRECT_NUMBER=10,
+ NET_IPV4_ROUTE_REDIRECT_SILENCE=11,
+ NET_IPV4_ROUTE_ERROR_COST=12,
+ NET_IPV4_ROUTE_ERROR_BURST=13,
+ NET_IPV4_ROUTE_GC_ELASTICITY=14,
+ NET_IPV4_ROUTE_MTU_EXPIRES=15
+};
+
+enum
+{
+ NET_PROTO_CONF_ALL=-2,
+ NET_PROTO_CONF_DEFAULT=-3
+
+ /* And device ifindices ... */
+};
+
+enum
+{
+ NET_IPV4_CONF_FORWARDING=1,
+ NET_IPV4_CONF_MC_FORWARDING=2,
+ NET_IPV4_CONF_PROXY_ARP=3,
+ NET_IPV4_CONF_ACCEPT_REDIRECTS=4,
+ NET_IPV4_CONF_SECURE_REDIRECTS=5,
+ NET_IPV4_CONF_SEND_REDIRECTS=6,
+ NET_IPV4_CONF_SHARED_MEDIA=7,
+ NET_IPV4_CONF_RP_FILTER=8,
+ NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,
+ NET_IPV4_CONF_BOOTP_RELAY=10,
+ NET_IPV4_CONF_LOG_MARTIANS=11,
+ NET_IPV4_CONF_HIDDEN=12
+};
+
+/* /proc/sys/net/ipv6 */
+enum {
+ NET_IPV6_CONF=16,
+ NET_IPV6_NEIGH=17,
+ NET_IPV6_ROUTE=18
+};
+
+enum {
+ NET_IPV6_ROUTE_FLUSH=1,
+ NET_IPV6_ROUTE_GC_THRESH=2,
+ NET_IPV6_ROUTE_MAX_SIZE=3,
+ NET_IPV6_ROUTE_GC_MIN_INTERVAL=4,
+ NET_IPV6_ROUTE_GC_TIMEOUT=5,
+ NET_IPV6_ROUTE_GC_INTERVAL=6,
+ NET_IPV6_ROUTE_GC_ELASTICITY=7,
+ NET_IPV6_ROUTE_MTU_EXPIRES=8
+};
+
+enum {
+ NET_IPV6_FORWARDING=1,
+ NET_IPV6_HOP_LIMIT=2,
+ NET_IPV6_MTU=3,
+ NET_IPV6_ACCEPT_RA=4,
+ NET_IPV6_ACCEPT_REDIRECTS=5,
+ NET_IPV6_AUTOCONF=6,
+ NET_IPV6_DAD_TRANSMITS=7,
+ NET_IPV6_RTR_SOLICITS=8,
+ NET_IPV6_RTR_SOLICIT_INTERVAL=9,
+ NET_IPV6_RTR_SOLICIT_DELAY=10
+};
+
+/* /proc/sys/net/<protocol>/neigh/<dev> */
+enum {
+ NET_NEIGH_MCAST_SOLICIT=1,
+ NET_NEIGH_UCAST_SOLICIT=2,
+ NET_NEIGH_APP_SOLICIT=3,
+ NET_NEIGH_RETRANS_TIME=4,
+ NET_NEIGH_REACHABLE_TIME=5,
+ NET_NEIGH_DELAY_PROBE_TIME=6,
+ NET_NEIGH_GC_STALE_TIME=7,
+ NET_NEIGH_UNRES_QLEN=8,
+ NET_NEIGH_PROXY_QLEN=9,
+ NET_NEIGH_ANYCAST_DELAY=10,
+ NET_NEIGH_PROXY_DELAY=11,
+ NET_NEIGH_LOCKTIME=12,
+ NET_NEIGH_GC_INTERVAL=13,
+ NET_NEIGH_GC_THRESH1=14,
+ NET_NEIGH_GC_THRESH2=15,
+ NET_NEIGH_GC_THRESH3=16
+};
+
+/* /proc/sys/net/ipx */
+
+
+/* /proc/sys/net/appletalk */
+enum {
+ NET_ATALK_AARP_EXPIRY_TIME=1,
+ NET_ATALK_AARP_TICK_TIME=2,
+ NET_ATALK_AARP_RETRANSMIT_LIMIT=3,
+ NET_ATALK_AARP_RESOLVE_TIME=4
+};
+
+
+/* /proc/sys/net/netrom */
+enum {
+ NET_NETROM_DEFAULT_PATH_QUALITY=1,
+ NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER=2,
+ NET_NETROM_NETWORK_TTL_INITIALISER=3,
+ NET_NETROM_TRANSPORT_TIMEOUT=4,
+ NET_NETROM_TRANSPORT_MAXIMUM_TRIES=5,
+ NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY=6,
+ NET_NETROM_TRANSPORT_BUSY_DELAY=7,
+ NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE=8,
+ NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT=9,
+ NET_NETROM_ROUTING_CONTROL=10,
+ NET_NETROM_LINK_FAILS_COUNT=11
+};
+
+/* /proc/sys/net/ax25 */
+enum {
+ NET_AX25_IP_DEFAULT_MODE=1,
+ NET_AX25_DEFAULT_MODE=2,
+ NET_AX25_BACKOFF_TYPE=3,
+ NET_AX25_CONNECT_MODE=4,
+ NET_AX25_STANDARD_WINDOW=5,
+ NET_AX25_EXTENDED_WINDOW=6,
+ NET_AX25_T1_TIMEOUT=7,
+ NET_AX25_T2_TIMEOUT=8,
+ NET_AX25_T3_TIMEOUT=9,
+ NET_AX25_IDLE_TIMEOUT=10,
+ NET_AX25_N2=11,
+ NET_AX25_PACLEN=12,
+ NET_AX25_PROTOCOL=13,
+ NET_AX25_DAMA_SLAVE_TIMEOUT=14
+};
+
+/* /proc/sys/net/rose */
+enum {
+ NET_ROSE_RESTART_REQUEST_TIMEOUT=1,
+ NET_ROSE_CALL_REQUEST_TIMEOUT=2,
+ NET_ROSE_RESET_REQUEST_TIMEOUT=3,
+ NET_ROSE_CLEAR_REQUEST_TIMEOUT=4,
+ NET_ROSE_ACK_HOLD_BACK_TIMEOUT=5,
+ NET_ROSE_ROUTING_CONTROL=6,
+ NET_ROSE_LINK_FAIL_TIMEOUT=7,
+ NET_ROSE_MAX_VCS=8,
+ NET_ROSE_WINDOW_SIZE=9,
+ NET_ROSE_NO_ACTIVITY_TIMEOUT=10
+};
+
+/* /proc/sys/net/x25 */
+enum {
+ NET_X25_RESTART_REQUEST_TIMEOUT=1,
+ NET_X25_CALL_REQUEST_TIMEOUT=2,
+ NET_X25_RESET_REQUEST_TIMEOUT=3,
+ NET_X25_CLEAR_REQUEST_TIMEOUT=4,
+ NET_X25_ACK_HOLD_BACK_TIMEOUT=5
+};
+
+/* /proc/sys/net/token-ring */
+enum
+{
+ NET_TR_RIF_TIMEOUT=1
+};
+
+/* /proc/sys/net/decnet */
+enum {
+ NET_DECNET_DEF_T3_BROADCAST=1,
+ NET_DECNET_DEF_T3_POINTTOPOINT=2,
+ NET_DECNET_DEF_T1=3,
+ NET_DECNET_DEF_BCT1=4,
+ NET_DECNET_CACHETIMEOUT=5,
+ NET_DECNET_DEBUG_LEVEL=6
+};
+
+/* CTL_PROC names: */
+
+/* CTL_FS names: */
+enum
+{
+ FS_NRINODE=1, /* int:current number of allocated inodes */
+ FS_STATINODE=2,
+ FS_MAXINODE=3, /* int:maximum number of inodes that can be allocated */
+ FS_NRDQUOT=4, /* int:current number of allocated dquots */
+ FS_MAXDQUOT=5, /* int:maximum number of dquots that can be allocated */
+ FS_NRFILE=6, /* int:current number of allocated filedescriptors */
+ FS_MAXFILE=7, /* int:maximum number of filedescriptors that can be allocated */
+ FS_DENTRY=8,
+ FS_NRSUPER=9, /* int:current number of allocated super_blocks */
+ FS_MAXSUPER=10 /* int:maximum number of super_blocks that can be allocated */
+};
+
+/* CTL_DEBUG names: */
+
+/* CTL_DEV names: */
+enum {
+ DEV_CDROM=1,
+ DEV_HWMON=2
+};
+
+/* /proc/sys/dev/cdrom */
+enum {
+ DEV_CDROM_INFO=1
+};
+
+#ifdef __KERNEL__
+
+extern asmlinkage int sys_sysctl(struct __sysctl_args *);
+extern void sysctl_init(void);
+
+typedef struct ctl_table ctl_table;
+
+typedef int ctl_handler (ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen,
+ void **context);
+
+typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp);
+
+extern int proc_dostring(ctl_table *, int, struct file *,
+ void *, size_t *);
+extern int proc_dointvec(ctl_table *, int, struct file *,
+ void *, size_t *);
+extern int proc_dointvec_bset(ctl_table *, int, struct file *,
+ void *, size_t *);
+extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
+ void *, size_t *);
+extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
+ void *, size_t *);
+
+extern int do_sysctl (int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen);
+
+extern int do_sysctl_strategy (ctl_table *table,
+ int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void ** context);
+
+extern ctl_handler sysctl_string;
+extern ctl_handler sysctl_intvec;
+extern ctl_handler sysctl_jiffies;
+
+extern int do_string (
+ void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+ int rdwr, char *data, size_t max);
+extern int do_int (
+ void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+ int rdwr, int *data);
+extern int do_struct (
+ void *oldval, size_t *oldlenp, void *newval, size_t newlen,
+ int rdwr, void *data, size_t len);
+
+
+/*
+ * Register a set of sysctl names by calling register_sysctl_table
+ * with an initialised array of ctl_table's. An entry with zero
+ * ctl_name terminates the table. table->de will be set up by the
+ * registration and need not be initialised in advance.
+ *
+ * sysctl names can be mirrored automatically under /proc/sys. The
+ * procname supplied controls /proc naming.
+ *
+ * The table's mode will be honoured both for sys_sysctl(2) and
+ * proc-fs access.
+ *
+ * Leaf nodes in the sysctl tree will be represented by a single file
+ * under /proc; non-leaf nodes will be represented by directories. A
+ * null procname disables /proc mirroring at this node.
+ *
+ * sysctl(2) can automatically manage read and write requests through
+ * the sysctl table. The data and maxlen fields of the ctl_table
+ * struct enable minimal validation of the values being written to be
+ * performed, and the mode field allows minimal authentication.
+ *
+ * More sophisticated management can be enabled by the provision of a
+ * strategy routine with the table entry. This will be called before
+ * any automatic read or write of the data is performed.
+ *
+ * The strategy routine may return:
+ * <0: Error occurred (error is passed to user process)
+ * 0: OK - proceed with automatic read or write.
+ * >0: OK - read or write has been done by the strategy routine, so
+ * return immediately.
+ *
+ * There must be a proc_handler routine for any terminal nodes
+ * mirrored under /proc/sys (non-terminals are handled by a built-in
+ * directory handler). Several default handlers are available to
+ * cover common cases.
+ */
+
+/* A sysctl table is an array of struct ctl_table: */
+struct ctl_table
+{
+ int ctl_name; /* Binary ID */
+ const char *procname; /* Text ID for /proc/sys, or zero */
+ void *data;
+ int maxlen;
+ mode_t mode;
+ ctl_table *child;
+ proc_handler *proc_handler; /* Callback for text formatting */
+ ctl_handler *strategy; /* Callback function for all r/w */
+ struct proc_dir_entry *de; /* /proc control block */
+ void *extra1;
+ void *extra2;
+};
+
+/* struct ctl_table_header is used to maintain dynamic lists of
+ ctl_table trees. */
+struct ctl_table_header
+{
+ ctl_table *ctl_table;
+ DLNODE(struct ctl_table_header) ctl_entry;
+};
+
+struct ctl_table_header * register_sysctl_table(ctl_table * table,
+ int insert_at_head);
+void unregister_sysctl_table(struct ctl_table_header * table);
+
+#else /* __KERNEL__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SYSCTL_H */
diff --git a/pfinet/linux-src/include/linux/sysrq.h b/pfinet/linux-src/include/linux/sysrq.h
new file mode 100644
index 00000000..6c080adb
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sysrq.h
@@ -0,0 +1,40 @@
+/* -*- linux-c -*-
+ *
+ * $Id: sysrq.h,v 1.3 1997/07/17 11:54:33 mj Exp $
+ *
+ * Linux Magic System Request Key Hacks
+ *
+ * (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/config.h>
+
+struct pt_regs;
+struct kbd_struct;
+struct tty_struct;
+
+/* Generic SysRq interface -- you may call it from any device driver, supplying
+ * ASCII code of the key, pointer to registers and kbd/tty structs (if they
+ * are available -- else NULL's).
+ */
+
+void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+
+/* Deferred actions */
+
+extern int emergency_sync_scheduled;
+
+#define EMERG_SYNC 1
+#define EMERG_REMOUNT 2
+
+void do_emergency_sync(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#define CHECK_EMERGENCY_SYNC \
+ if (emergency_sync_scheduled) \
+ do_emergency_sync();
+#else
+#define CHECK_EMERGENCY_SYNC
+#endif
+
+extern int sysrq_enabled;
diff --git a/pfinet/linux-src/include/linux/sysv_fs.h b/pfinet/linux-src/include/linux/sysv_fs.h
new file mode 100644
index 00000000..49d9d24f
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sysv_fs.h
@@ -0,0 +1,414 @@
+#ifndef _LINUX_SYSV_FS_H
+#define _LINUX_SYSV_FS_H
+
+/*
+ * The SystemV/Coherent filesystem constants/structures/macros
+ */
+
+
+/* This code assumes
+ - a little endian processor like 386,
+ - sizeof(short) = 2, sizeof(int) = 4, sizeof(long) = 4,
+ - alignof(short) = 2, alignof(long) = 4.
+*/
+
+#ifdef __GNUC__
+#define __packed2__ __attribute__ ((packed, aligned(2)))
+#else
+#error I want gcc!
+#endif
+
+#include <linux/stat.h> /* declares S_IFLNK etc. */
+#include <linux/sched.h> /* declares wake_up() */
+#include <linux/sysv_fs_sb.h> /* defines the sv_... shortcuts */
+
+
+/* Layout on disk */
+/* ============== */
+
+
+/* The block size is sb->sv_block_size which may be smaller than BLOCK_SIZE. */
+
+/* zones (= data allocation units) are blocks */
+
+/* On Coherent FS, 32 bit quantities are stored using (I quote the Coherent
+ manual) a "canonical byte ordering". This is the PDP-11 byte ordering:
+ x = 2^24 * byte3 + 2^16 * byte2 + 2^8 * byte1 + byte0 is stored
+ as { byte2, byte3, byte0, byte1 }. We need conversions.
+*/
+
+typedef u32 coh_ulong;
+
+static inline coh_ulong to_coh_ulong (u32 x)
+{
+ return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
+}
+
+static inline u32 from_coh_ulong (coh_ulong x)
+{
+ return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
+}
+
+/* inode numbers are 16 bit */
+
+typedef u16 sysv_ino_t;
+
+/* Block numbers are 24 bit, sometimes stored in 32 bit.
+ On Coherent FS, they are always stored in PDP-11 manner: the least
+ significant 16 bits come last.
+*/
+
+typedef u32 sysv_zone_t;
+
+/* Among the blocks ... */
+/* Xenix FS, Coherent FS: block 0 is the boot block, block 1 the super-block.
+ SystemV FS: block 0 contains both the boot sector and the super-block. */
+/* The first inode zone is sb->sv_firstinodezone (1 or 2). */
+
+/* Among the inodes ... */
+/* 0 is non-existent */
+#define SYSV_BADBL_INO 1 /* inode of bad blocks file */
+#define SYSV_ROOT_INO 2 /* inode of root directory */
+
+
+/* Xenix super-block data on disk */
+#define XENIX_NICINOD 100 /* number of inode cache entries */
+#define XENIX_NICFREE 100 /* number of free block list chunk entries */
+struct xenix_super_block {
+ u16 s_isize; /* index of first data zone */
+ u32 s_fsize __packed2__; /* total number of zones of this fs */
+ /* the start of the free block list: */
+ u16 s_nfree; /* number of free blocks in s_free, <= XENIX_NICFREE */
+ u32 s_free[XENIX_NICFREE]; /* first free block list chunk */
+ /* the cache of free inodes: */
+ u16 s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */
+ sysv_ino_t s_inode[XENIX_NICINOD]; /* some free inodes */
+ /* locks, not used by Linux: */
+ char s_flock; /* lock during free block list manipulation */
+ char s_ilock; /* lock during inode cache manipulation */
+ char s_fmod; /* super-block modified flag */
+ char s_ronly; /* flag whether fs is mounted read-only */
+ u32 s_time __packed2__; /* time of last super block update */
+ u32 s_tfree __packed2__; /* total number of free zones */
+ u16 s_tinode; /* total number of free inodes */
+ s16 s_dinfo[4]; /* device information ?? */
+ char s_fname[6]; /* file system volume name */
+ char s_fpack[6]; /* file system pack name */
+ char s_clean; /* set to 0x46 when filesystem is properly unmounted */
+ char s_fill[371];
+ s32 s_magic; /* version of file system */
+ s32 s_type; /* type of file system: 1 for 512 byte blocks
+ 2 for 1024 byte blocks
+ 3 for 2048 byte blocks */
+
+};
+
+/* Xenix free list block on disk */
+struct xenix_freelist_chunk {
+ u16 fl_nfree; /* number of free blocks in fl_free, <= XENIX_NICFREE] */
+ u32 fl_free[XENIX_NICFREE] __packed2__;
+};
+
+/* SystemV FS comes in two variants:
+ * sysv2: System V Release 2 (e.g. Microport), structure elements aligned(2).
+ * sysv4: System V Release 4 (e.g. Consensys), structure elements aligned(4).
+ */
+#define SYSV_NICINOD 100 /* number of inode cache entries */
+#define SYSV_NICFREE 50 /* number of free block list chunk entries */
+
+/* SystemV4 super-block data on disk */
+struct sysv4_super_block {
+ u16 s_isize; /* index of first data zone */
+ u16 s_pad0;
+ u32 s_fsize; /* total number of zones of this fs */
+ /* the start of the free block list: */
+ u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */
+ u16 s_pad1;
+ u32 s_free[SYSV_NICFREE]; /* first free block list chunk */
+ /* the cache of free inodes: */
+ u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */
+ u16 s_pad2;
+ sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */
+ /* locks, not used by Linux: */
+ char s_flock; /* lock during free block list manipulation */
+ char s_ilock; /* lock during inode cache manipulation */
+ char s_fmod; /* super-block modified flag */
+ char s_ronly; /* flag whether fs is mounted read-only */
+ u32 s_time; /* time of last super block update */
+ s16 s_dinfo[4]; /* device information ?? */
+ u32 s_tfree; /* total number of free zones */
+ u16 s_tinode; /* total number of free inodes */
+ u16 s_pad3;
+ char s_fname[6]; /* file system volume name */
+ char s_fpack[6]; /* file system pack name */
+ s32 s_fill[12];
+ s32 s_state; /* file system state: 0x7c269d38-s_time means clean */
+ s32 s_magic; /* version of file system */
+ s32 s_type; /* type of file system: 1 for 512 byte blocks
+ 2 for 1024 byte blocks */
+};
+
+/* SystemV4 free list block on disk */
+struct sysv4_freelist_chunk {
+ u16 fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */
+ u32 fl_free[SYSV_NICFREE];
+};
+
+/* SystemV2 super-block data on disk */
+struct sysv2_super_block {
+ u16 s_isize; /* index of first data zone */
+ u32 s_fsize __packed2__; /* total number of zones of this fs */
+ /* the start of the free block list: */
+ u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */
+ u32 s_free[SYSV_NICFREE]; /* first free block list chunk */
+ /* the cache of free inodes: */
+ u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */
+ sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */
+ /* locks, not used by Linux: */
+ char s_flock; /* lock during free block list manipulation */
+ char s_ilock; /* lock during inode cache manipulation */
+ char s_fmod; /* super-block modified flag */
+ char s_ronly; /* flag whether fs is mounted read-only */
+ u32 s_time __packed2__; /* time of last super block update */
+ s16 s_dinfo[4]; /* device information ?? */
+ u32 s_tfree __packed2__; /* total number of free zones */
+ u16 s_tinode; /* total number of free inodes */
+ char s_fname[6]; /* file system volume name */
+ char s_fpack[6]; /* file system pack name */
+ s32 s_fill[14];
+ s32 s_state; /* file system state: 0xcb096f43 means clean */
+ s32 s_magic; /* version of file system */
+ s32 s_type; /* type of file system: 1 for 512 byte blocks
+ 2 for 1024 byte blocks */
+};
+
+/* SystemV2 free list block on disk */
+struct sysv2_freelist_chunk {
+ u16 fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */
+ u32 fl_free[SYSV_NICFREE] __packed2__;
+};
+
+/* Coherent super-block data on disk */
+#define COH_NICINOD 100 /* number of inode cache entries */
+#define COH_NICFREE 64 /* number of free block list chunk entries */
+struct coh_super_block {
+ u16 s_isize; /* index of first data zone */
+ coh_ulong s_fsize __packed2__; /* total number of zones of this fs */
+ /* the start of the free block list: */
+ u16 s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */
+ coh_ulong s_free[COH_NICFREE] __packed2__; /* first free block list chunk */
+ /* the cache of free inodes: */
+ u16 s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */
+ sysv_ino_t s_inode[COH_NICINOD]; /* some free inodes */
+ /* locks, not used by Linux: */
+ char s_flock; /* lock during free block list manipulation */
+ char s_ilock; /* lock during inode cache manipulation */
+ char s_fmod; /* super-block modified flag */
+ char s_ronly; /* flag whether fs is mounted read-only */
+ coh_ulong s_time __packed2__; /* time of last super block update */
+ coh_ulong s_tfree __packed2__; /* total number of free zones */
+ u16 s_tinode; /* total number of free inodes */
+ u16 s_interleave_m; /* interleave factor */
+ u16 s_interleave_n;
+ char s_fname[6]; /* file system volume name */
+ char s_fpack[6]; /* file system pack name */
+ u32 s_unique; /* zero, not used */
+};
+
+/* Coherent free list block on disk */
+struct coh_freelist_chunk {
+ u16 fl_nfree; /* number of free blocks in fl_free, <= COH_NICFREE] */
+ u32 fl_free[COH_NICFREE] __packed2__;
+};
+
+
+/* SystemV/Coherent inode data on disk */
+
+struct sysv_inode {
+ u16 i_mode;
+ u16 i_nlink;
+ u16 i_uid;
+ u16 i_gid;
+ u32 i_size;
+ union { /* directories, regular files, ... */
+ unsigned char i_addb[3*(10+1+1+1)+1]; /* zone numbers: max. 10 data blocks,
+ * then 1 indirection block,
+ * then 1 double indirection block,
+ * then 1 triple indirection block.
+ * Then maybe a "file generation number" ??
+ */
+ /* devices */
+ dev_t i_rdev;
+ /* named pipes on Coherent */
+ struct {
+ char p_addp[30];
+ s16 p_pnc;
+ s16 p_prx;
+ s16 p_pwx;
+ } i_p;
+ } i_a;
+ u32 i_atime; /* time of last access */
+ u32 i_mtime; /* time of last modification */
+ u32 i_ctime; /* time of creation */
+};
+
+/* The admissible values for i_mode are listed in <linux/stat.h> :
+ * #define S_IFMT 00170000 mask for type
+ * #define S_IFREG 0100000 type = regular file
+ * #define S_IFBLK 0060000 type = block device
+ * #define S_IFDIR 0040000 type = directory
+ * #define S_IFCHR 0020000 type = character device
+ * #define S_IFIFO 0010000 type = named pipe
+ * #define S_ISUID 0004000 set user id
+ * #define S_ISGID 0002000 set group id
+ * #define S_ISVTX 0001000 save swapped text even after use
+ * Additionally for SystemV:
+ * #define S_IFLNK 0120000 type = symbolic link
+ * #define S_IFNAM 0050000 type = XENIX special named file ??
+ * Additionally for Coherent:
+ * #define S_IFMPB 0070000 type = multiplexed block device ??
+ * #define S_IFMPC 0030000 type = multiplexed character device ??
+ *
+ * Since Coherent doesn't know about symbolic links, we use a kludgey
+ * implementation of symbolic links: i_mode = COH_KLUDGE_SYMLINK_MODE
+ * denotes a symbolic link. When a regular file should get this mode by
+ * accident, it is automatically converted to COH_KLUDGE_NOT_SYMLINK.
+ * We use S_IFREG because only regular files (and Coherent pipes...) can have
+ * data blocks with arbitrary contents associated with them, and S_ISVTX
+ * ("save swapped text after use") because it is unused on both Linux and
+ * Coherent: Linux does much more intelligent paging, and Coherent hasn't
+ * virtual memory at all.
+ * Same trick for Xenix.
+ */
+#define COH_KLUDGE_SYMLINK_MODE (S_IFREG | S_ISVTX)
+#define COH_KLUDGE_NOT_SYMLINK (S_IFREG | S_ISVTX | S_IRUSR) /* force read access */
+extern inline mode_t from_coh_imode(unsigned short mode)
+{
+ if (mode == COH_KLUDGE_SYMLINK_MODE)
+ return (S_IFLNK | 0777);
+ else
+ return mode;
+}
+extern inline unsigned short to_coh_imode(mode_t mode)
+{
+ if (S_ISLNK(mode))
+ return COH_KLUDGE_SYMLINK_MODE;
+ else if (mode == COH_KLUDGE_SYMLINK_MODE)
+ return COH_KLUDGE_NOT_SYMLINK;
+ else
+ return mode;
+}
+
+/* Admissible values for i_nlink: 0.._LINK_MAX */
+#define XENIX_LINK_MAX 126 /* ?? */
+#define SYSV_LINK_MAX 126 /* 127? 251? */
+#define COH_LINK_MAX 10000 /* max number of hard links to an inode */
+
+/* The number of inodes per block is
+ sb->sv_inodes_per_block = block_size / sizeof(struct sysv_inode) */
+/* The number of indirect pointers per block is
+ sb->sv_ind_per_block = block_size / sizeof(u32) */
+
+
+/* SystemV/Coherent directory entry on disk */
+
+#define SYSV_NAMELEN 14 /* max size of name in struct sysv_dir_entry */
+
+struct sysv_dir_entry {
+ sysv_ino_t inode;
+ char name[SYSV_NAMELEN]; /* up to 14 characters, the rest are zeroes */
+};
+
+#define SYSV_DIRSIZE sizeof(struct sysv_dir_entry) /* size of every directory entry */
+
+
+/* Operations */
+/* ========== */
+
+
+/* identify the FS in memory */
+#define FSTYPE_XENIX 1
+#define FSTYPE_SYSV4 2
+#define FSTYPE_SYSV2 3
+#define FSTYPE_COH 4
+
+#define SYSV_MAGIC_BASE 0x012FF7B3
+
+#define XENIX_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_XENIX)
+#define SYSV4_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV4)
+#define SYSV2_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV2)
+#define COH_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_COH)
+
+#ifdef __KERNEL__
+
+/* sv_get_hash_table(sb,dev,block) is equivalent to get_hash_table(dev,block,block_size) */
+static inline struct buffer_head *
+sv_get_hash_table (struct super_block *sb, kdev_t dev, unsigned int block)
+{
+ return get_hash_table (dev, block + sb->sv_block_base, sb->sv_block_size);
+}
+
+/* sv_getblk(sb,dev,block) is equivalent to getblk(dev,block,block_size) */
+static inline struct buffer_head *
+sv_getblk (struct super_block *sb, kdev_t dev, unsigned int block)
+{
+ return getblk (dev, block + sb->sv_block_base, sb->sv_block_size);
+}
+
+/* sv_bread(sb,dev,block) is equivalent to bread(dev,block,block_size) */
+static inline struct buffer_head *
+sv_bread (struct super_block *sb, kdev_t dev, unsigned int block)
+{
+ return bread (dev, block + sb->sv_block_base, sb->sv_block_size);
+}
+
+
+/*
+ * Function prototypes
+ */
+
+extern struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry);
+extern int sysv_create(struct inode * dir, struct dentry * dentry, int mode);
+extern int sysv_mkdir(struct inode * dir, struct dentry * dentry, int mode);
+extern int sysv_rmdir(struct inode * dir, struct dentry * dentry);
+extern int sysv_unlink(struct inode * dir, struct dentry * dentry);
+extern int sysv_symlink(struct inode * inode, struct dentry * dentry, const char * symname);
+extern int sysv_link(struct dentry * old_dentry, struct inode * dir, struct dentry * dentry);
+extern int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev);
+extern int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry);
+extern struct inode * sysv_new_inode(const struct inode * dir);
+extern void sysv_free_inode(struct inode * inode);
+extern unsigned long sysv_count_free_inodes(struct super_block *sb);
+extern int sysv_new_block(struct super_block * sb);
+extern void sysv_free_block(struct super_block * sb, unsigned int block);
+extern unsigned long sysv_count_free_blocks(struct super_block *sb);
+
+extern int sysv_bmap(struct inode *,int);
+
+extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int);
+extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
+extern ssize_t sysv_file_read(struct file *, char *, size_t, loff_t *);
+
+extern void sysv_truncate(struct inode *);
+extern void sysv_put_super(struct super_block *);
+extern struct super_block *sysv_read_super(struct super_block *,void *,int);
+extern int init_sysv_fs(void);
+extern void sysv_write_super(struct super_block *);
+extern void sysv_read_inode(struct inode *);
+extern int sysv_notify_change(struct dentry *, struct iattr *);
+extern void sysv_write_inode(struct inode *);
+extern int sysv_statfs(struct super_block *, struct statfs *, int);
+extern int sysv_sync_inode(struct inode *);
+extern int sysv_sync_file(struct file *, struct dentry *);
+extern int sysv_mmap(struct file *, struct vm_area_struct *);
+
+extern struct inode_operations sysv_file_inode_operations;
+extern struct inode_operations sysv_file_inode_operations_with_bmap;
+extern struct inode_operations sysv_dir_inode_operations;
+extern struct inode_operations sysv_symlink_inode_operations;
+
+#endif /* __KERNEL__ */
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/sysv_fs_i.h b/pfinet/linux-src/include/linux/sysv_fs_i.h
new file mode 100644
index 00000000..990b3543
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sysv_fs_i.h
@@ -0,0 +1,16 @@
+#ifndef _SYSV_FS_I
+#define _SYSV_FS_I
+
+/*
+ * SystemV/Coherent FS inode data in memory
+ */
+struct sysv_inode_info {
+ u32 i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks,
+ * then 1 indirection block,
+ * then 1 double indirection block,
+ * then 1 triple indirection block.
+ */
+};
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/sysv_fs_sb.h b/pfinet/linux-src/include/linux/sysv_fs_sb.h
new file mode 100644
index 00000000..df886f65
--- /dev/null
+++ b/pfinet/linux-src/include/linux/sysv_fs_sb.h
@@ -0,0 +1,122 @@
+#ifndef _SYSV_FS_SB
+#define _SYSV_FS_SB
+
+/*
+ * SystemV/Coherent super-block data in memory
+ * The SystemV/Coherent superblock contains dynamic data (it gets modified
+ * while the system is running). This is in contrast to the Minix and Berkeley
+ * filesystems (where the superblock is never modified). This affects the
+ * sync() operation: we must keep the superblock in a disk buffer and use this
+ * one as our "working copy".
+ */
+
+struct sysv_sb_info {
+ int s_type; /* file system type: FSTYPE_{XENIX|SYSV|COH} */
+ unsigned int s_block_size; /* zone size, = 512 or = 1024 */
+ unsigned int s_block_size_1; /* block_size - 1 */
+ unsigned int s_block_size_bits; /* log2(block_size) */
+ unsigned int s_block_size_inc_bits; /* log2(block_size/BLOCK_SIZE) if >0 */
+ unsigned int s_block_size_dec_bits; /* log2(BLOCK_SIZE/block_size) if >0 */
+ char s_convert; /* flag whether byte ordering requires conversion */
+ char s_kludge_symlinks; /* flag whether symlinks have a kludgey mode */
+ char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */
+ /* if 0: they are disallowed (ENAMETOOLONG) */
+ nlink_t s_link_max; /* max number of hard links to a file */
+ unsigned int s_inodes_per_block; /* number of inodes per block */
+ unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */
+ unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */
+ unsigned int s_ind_per_block; /* number of indirections per block */
+ unsigned int s_ind_per_block_1; /* ind_per_block - 1 */
+ unsigned int s_ind_per_block_bits; /* log2(ind_per_block) */
+ unsigned int s_ind_per_block_2; /* ind_per_block ^ 2 */
+ unsigned int s_ind_per_block_2_1; /* ind_per_block ^ 2 - 1 */
+ unsigned int s_ind_per_block_2_bits; /* log2(ind_per_block^2) */
+ unsigned int s_ind_per_block_3; /* ind_per_block ^ 3 */
+ unsigned int s_ind_per_block_block_size_1; /* ind_per_block*block_size - 1 */
+ unsigned int s_ind_per_block_block_size_bits; /* log2(ind_per_block*block_size) */
+ unsigned int s_ind_per_block_2_block_size_1; /* ind_per_block^2 * block_size - 1 */
+ unsigned int s_ind_per_block_2_block_size_bits; /* log2(ind_per_block^2 * block_size) */
+ unsigned int s_ind0_size; /* 10 * block_size */
+ unsigned int s_ind1_size; /* (10 + ipb) * block_size */
+ unsigned int s_ind2_size; /* (10 + ipb + ipb^2) * block_size */
+ unsigned int s_toobig_block; /* 10 + ipb + ipb^2 + ipb^3 */
+ unsigned int s_block_base; /* physical block number of block 0 */
+ unsigned short s_fic_size; /* free inode cache size, NICINOD */
+ unsigned short s_flc_size; /* free block list chunk size, NICFREE */
+ /* The superblock is kept in one or two disk buffers: */
+ struct buffer_head *s_bh1;
+ struct buffer_head *s_bh2;
+ /* These are pointers into the disk buffer, to compensate for
+ different superblock layout. */
+ char * s_sbd1; /* entire superblock data, for part 1 */
+ char * s_sbd2; /* entire superblock data, for part 2 */
+ u16 *s_sb_fic_count; /* pointer to s_sbd->s_ninode */
+ u16 *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */
+ u16 *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */
+ u16 *s_sb_flc_count; /* pointer to s_sbd->s_nfree */
+ u32 *s_sb_flc_blocks; /* pointer to s_sbd->s_free */
+ u32 *s_sb_total_free_blocks;/* pointer to s_sbd->s_tfree */
+ u32 *s_sb_time; /* pointer to s_sbd->s_time */
+ u32 *s_sb_state; /* pointer to s_sbd->s_state, only FSTYPE_SYSV */
+ /* We keep those superblock entities that don't change here;
+ this saves us an indirection and perhaps a conversion. */
+ u32 s_firstinodezone; /* index of first inode zone */
+ u32 s_firstdatazone; /* same as s_sbd->s_isize */
+ u32 s_ninodes; /* total number of inodes */
+ u32 s_ndatazones; /* total number of data zones */
+ u32 s_nzones; /* same as s_sbd->s_fsize */
+};
+/* The fields s_ind_per_block_2_1, s_toobig_block are currently unused. */
+
+/* sv_ == u.sysv_sb.s_ */
+#define sv_type u.sysv_sb.s_type
+#define sv_block_size u.sysv_sb.s_block_size
+#define sv_block_size_1 u.sysv_sb.s_block_size_1
+#define sv_block_size_bits u.sysv_sb.s_block_size_bits
+#define sv_block_size_inc_bits u.sysv_sb.s_block_size_inc_bits
+#define sv_block_size_dec_bits u.sysv_sb.s_block_size_dec_bits
+#define sv_convert u.sysv_sb.s_convert
+#define sv_kludge_symlinks u.sysv_sb.s_kludge_symlinks
+#define sv_truncate u.sysv_sb.s_truncate
+#define sv_link_max u.sysv_sb.s_link_max
+#define sv_inodes_per_block u.sysv_sb.s_inodes_per_block
+#define sv_inodes_per_block_1 u.sysv_sb.s_inodes_per_block_1
+#define sv_inodes_per_block_bits u.sysv_sb.s_inodes_per_block_bits
+#define sv_ind_per_block u.sysv_sb.s_ind_per_block
+#define sv_ind_per_block_1 u.sysv_sb.s_ind_per_block_1
+#define sv_ind_per_block_bits u.sysv_sb.s_ind_per_block_bits
+#define sv_ind_per_block_2 u.sysv_sb.s_ind_per_block_2
+#define sv_ind_per_block_2_1 u.sysv_sb.s_ind_per_block_2_1
+#define sv_ind_per_block_2_bits u.sysv_sb.s_ind_per_block_2_bits
+#define sv_ind_per_block_3 u.sysv_sb.s_ind_per_block_3
+#define sv_ind_per_block_block_size_1 u.sysv_sb.s_ind_per_block_block_size_1
+#define sv_ind_per_block_block_size_bits u.sysv_sb.s_ind_per_block_block_size_bits
+#define sv_ind_per_block_2_block_size_1 u.sysv_sb.s_ind_per_block_2_block_size_1
+#define sv_ind_per_block_2_block_size_bits u.sysv_sb.s_ind_per_block_2_block_size_bits
+#define sv_ind0_size u.sysv_sb.s_ind0_size
+#define sv_ind1_size u.sysv_sb.s_ind1_size
+#define sv_ind2_size u.sysv_sb.s_ind2_size
+#define sv_toobig_block u.sysv_sb.s_toobig_block
+#define sv_block_base u.sysv_sb.s_block_base
+#define sv_fic_size u.sysv_sb.s_fic_size
+#define sv_flc_size u.sysv_sb.s_flc_size
+#define sv_bh1 u.sysv_sb.s_bh1
+#define sv_bh2 u.sysv_sb.s_bh2
+#define sv_sbd1 u.sysv_sb.s_sbd1
+#define sv_sbd2 u.sysv_sb.s_sbd2
+#define sv_sb_fic_count u.sysv_sb.s_sb_fic_count
+#define sv_sb_fic_inodes u.sysv_sb.s_sb_fic_inodes
+#define sv_sb_total_free_inodes u.sysv_sb.s_sb_total_free_inodes
+#define sv_sb_flc_count u.sysv_sb.s_sb_flc_count
+#define sv_sb_flc_blocks u.sysv_sb.s_sb_flc_blocks
+#define sv_sb_total_free_blocks u.sysv_sb.s_sb_total_free_blocks
+#define sv_sb_time u.sysv_sb.s_sb_time
+#define sv_sb_state u.sysv_sb.s_sb_state
+#define sv_firstinodezone u.sysv_sb.s_firstinodezone
+#define sv_firstdatazone u.sysv_sb.s_firstdatazone
+#define sv_ninodes u.sysv_sb.s_ninodes
+#define sv_ndatazones u.sysv_sb.s_ndatazones
+#define sv_nzones u.sysv_sb.s_nzones
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/tasks.h b/pfinet/linux-src/include/linux/tasks.h
new file mode 100644
index 00000000..91b758f4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/tasks.h
@@ -0,0 +1,25 @@
+#ifndef _LINUX_TASKS_H
+#define _LINUX_TASKS_H
+
+/*
+ * This is the maximum nr of tasks - change it if you need to
+ */
+
+#ifdef __SMP__
+#define NR_CPUS 32 /* Max processors that can be running in SMP */
+#else
+#define NR_CPUS 1
+#endif
+
+#define NR_TASKS 512 /* On x86 Max 4092, or 4090 w/APM configured. */
+
+#define MAX_TASKS_PER_USER (NR_TASKS/2)
+#define MIN_TASKS_LEFT_FOR_ROOT 4
+
+
+/*
+ * This controls the maximum pid allocated to a process
+ */
+#define PID_MAX 0x8000
+
+#endif
diff --git a/pfinet/linux/tcp.h b/pfinet/linux-src/include/linux/tcp.h
index 32ef0ad1..9ee71810 100644
--- a/pfinet/linux/tcp.h
+++ b/pfinet/linux-src/include/linux/tcp.h
@@ -17,16 +17,15 @@
#ifndef _LINUX_TCP_H
#define _LINUX_TCP_H
-
-#define HEADER_SIZE 64 /* maximum header size */
-
+#include <linux/types.h>
+#include <asm/byteorder.h>
struct tcphdr {
__u16 source;
__u16 dest;
__u32 seq;
__u32 ack_seq;
-#if defined(__i386__)
+#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
@@ -36,58 +35,18 @@ struct tcphdr {
ack:1,
urg:1,
res2:2;
-#elif defined(__mc68000__)
- __u16 res2:2,
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u16 doff:4,
+ res1:4,
+ res2:2,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
- fin:1,
- doff:4,
- res1:4;
-#elif defined(__MIPSEL__)
- __u16 res1:4,
- doff:4,
- fin:1,
- syn:1,
- rst:1,
- psh:1,
- ack:1,
- urg:1,
- res2:2;
-#elif defined(__MIPSEB__)
- __u16 res2:2,
- urg:1,
- ack:1,
- psh:1,
- rst:1,
- syn:1,
- fin:1,
- doff:4,
- res1:4;
-#elif defined(__alpha__)
- __u16 res1:4,
- doff:4,
- fin:1,
- syn:1,
- rst:1,
- psh:1,
- ack:1,
- urg:1,
- res2:2;
-#elif defined(__sparc__)
- __u16 res2:2,
- urg:1,
- ack:1,
- psh:1,
- rst:1,
- syn:1,
- fin:1,
- doff:4,
- res1:4;
+ fin:1;
#else
-#error "Adjust this structure for your cpu alignment rules"
+#error "Adjust your <asm/byteorder.h> defines"
#endif
__u16 window;
__u16 check;
@@ -106,7 +65,26 @@ enum {
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_LISTEN,
- TCP_CLOSING /* now a valid state */
+ TCP_CLOSING, /* now a valid state */
+
+ TCP_MAX_STATES /* Leave at the end! */
+};
+
+#define TCP_STATE_MASK 0xF
+#define TCP_ACTION_FIN (1 << 7)
+
+enum {
+ TCPF_ESTABLISHED = (1 << 1),
+ TCPF_SYN_SENT = (1 << 2),
+ TCPF_SYN_RECV = (1 << 3),
+ TCPF_FIN_WAIT1 = (1 << 4),
+ TCPF_FIN_WAIT2 = (1 << 5),
+ TCPF_TIME_WAIT = (1 << 6),
+ TCPF_CLOSE = (1 << 7),
+ TCPF_CLOSE_WAIT = (1 << 8),
+ TCPF_LAST_ACK = (1 << 9),
+ TCPF_LISTEN = (1 << 10),
+ TCPF_CLOSING = (1 << 11)
};
#endif /* _LINUX_TCP_H */
diff --git a/pfinet/linux-src/include/linux/telephony.h b/pfinet/linux-src/include/linux/telephony.h
new file mode 100644
index 00000000..0e4a95a4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/telephony.h
@@ -0,0 +1,200 @@
+/*
+ * telephony.h
+ *
+ * Basic Linux Telephony Interface
+ *
+ * (c) Copyright 1999 Quicknet Technologies, 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 of the License, or (at your option) any later version.
+ *
+ * Authors: Ed Okerson, <eokerson@quicknet.net>
+ * Greg Herlein, <gherlein@quicknet.net>
+ *
+ * Contributors: Alan Cox, <acox@redhat.com>
+ * David Erhart, <derhart@quicknet.net>
+ *
+ * Version: 0.1.0 - December 19, 1999
+ *
+ * Fixes:
+ */
+
+#ifndef TELEPHONY_H
+#define TELEPHONY_H
+
+/* vendor identification numbers */
+#define PHONE_VENDOR_IXJ 1
+#define PHONE_VENDOR_QUICKNET PHONE_IXJ
+#define PHONE_VENDOR_VOICETRONIX 2
+#define PHONE_VENDOR_ACULAB 3
+#define PHONE_VENDOR_DIGI 4
+#define PHONE_VENDOR_FRANKLIN 5
+
+/******************************************************************************
+ * Vendor Summary Information Area
+ *
+ * Quicknet Technologies, Inc. - makes low density analog telephony cards
+ * with audio compression, POTS and PSTN interfaces (www.quicknet.net)
+ *
+ * (other vendors following this API shuld add a short description of
+ * the telephony products they support under Linux)
+ *
+ *****************************************************************************/
+
+
+/******************************************************************************
+*
+* The capabilities ioctls can inform you of the capabilities of each phone
+* device installed in your system. The PHONECTL_CAPABILITIES ioctl
+* returns an integer value indicating the number of capabilities the
+* device has. The PHONECTL_CAPABILITIES_LIST will fill an array of
+* capability structs with all of it's capabilities. The
+* PHONECTL_CAPABILITIES_CHECK takes a single capability struct and returns
+* a TRUE if the device has that capability, otherwise it returns false.
+*
+******************************************************************************/
+typedef enum {
+ vendor = 0,
+ device,
+ port,
+ codec,
+ dsp
+} phone_cap;
+
+struct phone_capability {
+ char desc[80];
+ phone_cap captype;
+ int cap;
+ int handle;
+};
+
+typedef enum {
+ pots = 0,
+ pstn,
+ handset,
+ speaker
+} phone_ports;
+
+#define PHONE_CAPABILITIES _IO ('q', 0x80)
+#define PHONE_CAPABILITIES_LIST _IOR ('q', 0x81, struct phone_capability *)
+#define PHONE_CAPABILITIES_CHECK _IOW ('q', 0x82, struct phone_capability *)
+
+#define PHONE_RING _IO ('q', 0x83)
+#define PHONE_HOOKSTATE _IO ('q', 0x84)
+#define PHONE_MAXRINGS _IOW ('q', 0x85, char)
+#define PHONE_RING_CADENCE _IOW ('q', 0x86, short)
+#define PHONE_RING_START _IO ('q', 0x87)
+#define PHONE_RING_STOP _IO ('q', 0x88)
+
+#define USA_RING_CADENCE 0xC0C0
+
+#define PHONE_REC_CODEC _IOW ('q', 0x89, int)
+#define PHONE_REC_START _IO ('q', 0x8A)
+#define PHONE_REC_STOP _IO ('q', 0x8B)
+#define PHONE_REC_DEPTH _IOW ('q', 0x8C, int)
+#define PHONE_FRAME _IOW ('q', 0x8D, int)
+#define PHONE_REC_VOLUME _IOW ('q', 0x8E, int)
+#define PHONE_REC_LEVEL _IO ('q', 0x8F)
+
+#define PHONE_PLAY_CODEC _IOW ('q', 0x90, int)
+#define PHONE_PLAY_START _IO ('q', 0x91)
+#define PHONE_PLAY_STOP _IO ('q', 0x92)
+#define PHONE_PLAY_DEPTH _IOW ('q', 0x93, int)
+#define PHONE_PLAY_VOLUME _IOW ('q', 0x94, int)
+#define PHONE_PLAY_LEVEL _IO ('q', 0x95)
+#define PHONE_DTMF_READY _IOR ('q', 0x96, int)
+#define PHONE_GET_DTMF _IOR ('q', 0x97, int)
+#define PHONE_GET_DTMF_ASCII _IOR ('q', 0x98, int)
+#define PHONE_DTMF_OOB _IOW ('q', 0x99, int)
+#define PHONE_EXCEPTION _IOR ('q', 0x9A, int)
+#define PHONE_PLAY_TONE _IOW ('q', 0x9B, char)
+#define PHONE_SET_TONE_ON_TIME _IOW ('q', 0x9C, int)
+#define PHONE_SET_TONE_OFF_TIME _IOW ('q', 0x9D, int)
+#define PHONE_GET_TONE_ON_TIME _IO ('q', 0x9E)
+#define PHONE_GET_TONE_OFF_TIME _IO ('q', 0x9F)
+#define PHONE_GET_TONE_STATE _IO ('q', 0xA0)
+#define PHONE_BUSY _IO ('q', 0xA1)
+#define PHONE_RINGBACK _IO ('q', 0xA2)
+#define PHONE_DIALTONE _IO ('q', 0xA3)
+#define PHONE_CPT_STOP _IO ('q', 0xA4)
+
+#define PHONE_PSTN_SET_STATE _IOW ('q', 0xA4, int)
+#define PHONE_PSTN_GET_STATE _IO ('q', 0xA5)
+
+#define PSTN_ON_HOOK 0
+#define PSTN_RINGING 1
+#define PSTN_OFF_HOOK 2
+#define PSTN_PULSE_DIAL 3
+
+/******************************************************************************
+*
+* The wink duration is tunable with this ioctl. The default wink duration
+* is 320ms. You do not need to use this ioctl if you do not require a
+* different wink duration.
+*
+******************************************************************************/
+#define PHONE_WINK_DURATION _IOW ('q', 0xA6, int)
+
+
+/******************************************************************************
+*
+* Codec Definitions
+*
+******************************************************************************/
+typedef enum {
+ G723_63 = 1,
+ G723_53 = 2,
+ TS85 = 3,
+ TS48 = 4,
+ TS41 = 5,
+ G728 = 6,
+ G729 = 7,
+ ULAW = 8,
+ ALAW = 9,
+ LINEAR16 = 10,
+ LINEAR8 = 11,
+ WSS = 12
+} phone_codec;
+
+/******************************************************************************
+*
+* The exception structure allows us to multiplex multiple events onto the
+* select() exception set. If any of these flags are set select() will
+* return with a positive indication on the exception set. The dtmf_ready
+* bit indicates if there is data waiting in the DTMF buffer. The
+* hookstate bit is set if there is a change in hookstate status, it does not
+* indicate the current state of the hookswitch. The pstn_ring bit
+* indicates that the DAA on a LineJACK card has detected ring voltage on
+* the PSTN port. The caller_id bit indicates that caller_id data has been
+* received and is available. The pstn_wink bit indicates that the DAA on
+* the LineJACK has received a wink from the telco switch. The f0, f1, f2
+* and f3 bits indicate that the filter has been triggered by detecting the
+* frequency programmed into that filter.
+*
+* The remaining bits should be set to zero. They will become defined over time
+* for other interface cards and their needs.
+*
+******************************************************************************/
+struct phone_except
+{
+ unsigned int dtmf_ready:1;
+ unsigned int hookstate:1;
+ unsigned int pstn_ring:1;
+ unsigned int caller_id:1;
+ unsigned int pstn_wink:1;
+ unsigned int f0:1;
+ unsigned int f1:1;
+ unsigned int f2:1;
+ unsigned int f3:1;
+ unsigned int reserved:23;
+};
+
+union telephony_exception {
+ struct phone_except bits;
+ unsigned int bytes;
+};
+
+
+#endif /* TELEPHONY_H */
diff --git a/pfinet/linux-src/include/linux/termios.h b/pfinet/linux-src/include/linux/termios.h
new file mode 100644
index 00000000..47866288
--- /dev/null
+++ b/pfinet/linux-src/include/linux/termios.h
@@ -0,0 +1,7 @@
+#ifndef _LINUX_TERMIOS_H
+#define _LINUX_TERMIOS_H
+
+#include <linux/types.h>
+#include <asm/termios.h>
+
+#endif
diff --git a/pfinet/linux-src/include/linux/time.h b/pfinet/linux-src/include/linux/time.h
new file mode 100644
index 00000000..53a125a0
--- /dev/null
+++ b/pfinet/linux-src/include/linux/time.h
@@ -0,0 +1,92 @@
+#ifndef _LINUX_TIME_H
+#define _LINUX_TIME_H
+
+#include <asm/param.h>
+#include <linux/types.h>
+
+#ifndef _STRUCT_TIMESPEC
+#define _STRUCT_TIMESPEC
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+#endif /* _STRUCT_TIMESPEC */
+
+/*
+ * Change timeval to jiffies, trying to avoid the
+ * most obvious overflows..
+ *
+ * And some not so obvious.
+ *
+ * Note that we don't want to return MAX_LONG, because
+ * for various timeout reasons we often end up having
+ * to wait "jiffies+1" in order to guarantee that we wait
+ * at _least_ "jiffies" - so "jiffies+1" had better still
+ * be positive.
+ */
+#define MAX_JIFFY_OFFSET ((~0UL >> 1)-1)
+
+static __inline__ unsigned long
+timespec_to_jiffies(struct timespec *value)
+{
+ unsigned long sec = value->tv_sec;
+ long nsec = value->tv_nsec;
+
+ if (sec >= (MAX_JIFFY_OFFSET / HZ))
+ return MAX_JIFFY_OFFSET;
+ nsec += 1000000000L / HZ - 1;
+ nsec /= 1000000000L / HZ;
+ return HZ * sec + nsec;
+}
+
+static __inline__ void
+jiffies_to_timespec(unsigned long jiffies, struct timespec *value)
+{
+ value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ);
+ value->tv_sec = jiffies / HZ;
+}
+
+struct timeval {
+ time_t tv_sec; /* seconds */
+ suseconds_t tv_usec; /* microseconds */
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+#define NFDBITS __NFDBITS
+
+#ifdef __KERNEL__
+extern void do_gettimeofday(struct timeval *tv);
+extern void do_settimeofday(struct timeval *tv);
+extern void get_fast_time(struct timeval *tv);
+extern void (*do_get_fast_time)(struct timeval *);
+#endif
+
+#define FD_SETSIZE __FD_SETSIZE
+#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp)
+#define FD_CLR(fd,fdsetp) __FD_CLR(fd,fdsetp)
+#define FD_ISSET(fd,fdsetp) __FD_ISSET(fd,fdsetp)
+#define FD_ZERO(fdsetp) __FD_ZERO(fdsetp)
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+struct itimerspec {
+ struct timespec it_interval; /* timer period */
+ struct timespec it_value; /* timer expiration */
+};
+
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/timer.h b/pfinet/linux-src/include/linux/timer.h
new file mode 100644
index 00000000..56f39893
--- /dev/null
+++ b/pfinet/linux-src/include/linux/timer.h
@@ -0,0 +1,96 @@
+#ifndef _LINUX_TIMER_H
+#define _LINUX_TIMER_H
+
+/*
+ * Old-style timers. Please don't use for any new code.
+ *
+ * Numbering of these timers should be consecutive to minimize
+ * processing delays. [MJ]
+ */
+
+#define BLANK_TIMER 0 /* Console screen-saver */
+#define BEEP_TIMER 1 /* Console beep */
+#define RS_TIMER 2 /* RS-232 ports */
+#define SWAP_TIMER 3 /* Background pageout */
+#define BACKGR_TIMER 4 /* io_request background I/O */
+#define HD_TIMER 5 /* Old IDE driver */
+#define FLOPPY_TIMER 6 /* Floppy */
+#define QIC02_TAPE_TIMER 7 /* QIC 02 tape */
+#define MCD_TIMER 8 /* Mitsumi CDROM */
+#define GSCD_TIMER 9 /* Goldstar CDROM */
+#define COMTROL_TIMER 10 /* Comtrol serial */
+#define DIGI_TIMER 11 /* Digi serial */
+#define GDTH_TIMER 12 /* Ugh - gdth scsi driver */
+
+#define COPRO_TIMER 31 /* 387 timeout for buggy hardware (boot only) */
+
+struct timer_struct {
+ unsigned long expires;
+ void (*fn)(void);
+};
+
+extern unsigned long timer_active;
+extern struct timer_struct timer_table[32];
+
+/*
+ * This is completely separate from the above, and is the
+ * "new and improved" way of handling timers more dynamically.
+ * Hopefully efficient and general enough for most things.
+ *
+ * The "hardcoded" timers above are still useful for well-
+ * defined problems, but the timer-list is probably better
+ * when you need multiple outstanding timers or similar.
+ *
+ * The "data" field is in case you want to use the same
+ * timeout function for several timeouts. You can use this
+ * to distinguish between the different invocations.
+ */
+struct timer_list {
+ struct timer_list *next; /* MUST be first element */
+ struct timer_list *prev;
+ unsigned long expires;
+ unsigned long data;
+ void (*function)(unsigned long);
+};
+
+extern void add_timer(struct timer_list * timer);
+extern int del_timer(struct timer_list * timer);
+
+/*
+ * mod_timer is a more efficient way to update the expire field of an
+ * active timer (if the timer is inactive it will be activated)
+ * mod_timer(a,b) is equivalent to del_timer(a); a->expires = b; add_timer(a)
+ */
+void mod_timer(struct timer_list *timer, unsigned long expires);
+
+extern void it_real_fn(unsigned long);
+
+extern inline void init_timer(struct timer_list * timer)
+{
+ timer->next = NULL;
+ timer->prev = NULL;
+}
+
+extern inline int timer_pending(struct timer_list * timer)
+{
+ return timer->prev != NULL;
+}
+
+/*
+ * These inlines deal with timer wrapping correctly. You are
+ * strongly encouraged to use them
+ * 1. Because people otherwise forget
+ * 2. Because if the timer wrap changes in future you wont have to
+ * alter your driver code.
+ *
+ * Do this with "<0" and ">=0" to only test the sign of the result. A
+ * good compiler would generate better code (and a really good compiler
+ * wouldn't care). Gcc is currently neither.
+ */
+#define time_after(a,b) ((long)(b) - (long)(a) < 0)
+#define time_before(a,b) time_after(b,a)
+
+#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0)
+#define time_before_eq(a,b) time_after_eq(b,a)
+
+#endif
diff --git a/pfinet/linux-src/include/linux/times.h b/pfinet/linux-src/include/linux/times.h
new file mode 100644
index 00000000..569349ef
--- /dev/null
+++ b/pfinet/linux-src/include/linux/times.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_TIMES_H
+#define _LINUX_TIMES_H
+
+struct tms {
+ clock_t tms_utime;
+ clock_t tms_stime;
+ clock_t tms_cutime;
+ clock_t tms_cstime;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/timex.h b/pfinet/linux-src/include/linux/timex.h
new file mode 100644
index 00000000..653009ad
--- /dev/null
+++ b/pfinet/linux-src/include/linux/timex.h
@@ -0,0 +1,277 @@
+/*****************************************************************************
+ * *
+ * Copyright (c) David L. Mills 1993 *
+ * *
+ * Permission to use, copy, modify, and distribute this software and its *
+ * documentation for any purpose and without fee is hereby granted, provided *
+ * that the above copyright notice appears in all copies and that both the *
+ * copyright notice and this permission notice appear in supporting *
+ * documentation, and that the name University of Delaware not be used in *
+ * advertising or publicity pertaining to distribution of the software *
+ * without specific, written prior permission. The University of Delaware *
+ * makes no representations about the suitability this software for any *
+ * purpose. It is provided "as is" without express or implied warranty. *
+ * *
+ *****************************************************************************/
+
+/*
+ * Modification history timex.h
+ *
+ * 29 Dec 97 Russell King
+ * Moved CLOCK_TICK_RATE, CLOCK_TICK_FACTOR and FINETUNE to asm/timex.h
+ * for ARM machines
+ *
+ * 9 Jan 97 Adrian Sun
+ * Shifted LATCH define to allow access to alpha machines.
+ *
+ * 26 Sep 94 David L. Mills
+ * Added defines for hybrid phase/frequency-lock loop.
+ *
+ * 19 Mar 94 David L. Mills
+ * Moved defines from kernel routines to header file and added new
+ * defines for PPS phase-lock loop.
+ *
+ * 20 Feb 94 David L. Mills
+ * Revised status codes and structures for external clock and PPS
+ * signal discipline.
+ *
+ * 28 Nov 93 David L. Mills
+ * Adjusted parameters to improve stability and increase poll
+ * interval.
+ *
+ * 17 Sep 93 David L. Mills
+ * Created file $NTP/include/sys/timex.h
+ * 07 Oct 93 Torsten Duwe
+ * Derived linux/timex.h
+ * 1995-08-13 Torsten Duwe
+ * kernel PLL updated to 1994-12-13 specs (rfc-1589)
+ * 1997-08-30 Ulrich Windl
+ * Added new constant NTP_PHASE_LIMIT
+ */
+#ifndef _LINUX_TIMEX_H
+#define _LINUX_TIMEX_H
+
+/*
+ * The following defines establish the engineering parameters of the PLL
+ * model. The HZ variable establishes the timer interrupt frequency, 100 Hz
+ * for the SunOS kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the
+ * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the
+ * nearest power of two in order to avoid hardware multiply operations.
+ */
+#ifdef __alpha__
+# define SHIFT_HZ 10 /* log2(HZ) */
+#else
+# define SHIFT_HZ 7 /* log2(HZ) */
+#endif
+
+/*
+ * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
+ * for a slightly underdamped convergence characteristic. SHIFT_KH
+ * establishes the damping of the FLL and is chosen by wisdom and black
+ * art.
+ *
+ * MAXTC establishes the maximum time constant of the PLL. With the
+ * SHIFT_KG and SHIFT_KF values given and a time constant range from
+ * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
+ * respectively.
+ */
+#define SHIFT_KG 6 /* phase factor (shift) */
+#define SHIFT_KF 16 /* PLL frequency factor (shift) */
+#define SHIFT_KH 2 /* FLL frequency factor (shift) */
+#define MAXTC 6 /* maximum time constant (shift) */
+
+/*
+ * The SHIFT_SCALE define establishes the decimal point of the time_phase
+ * variable which serves as an extension to the low-order bits of the
+ * system clock variable. The SHIFT_UPDATE define establishes the decimal
+ * point of the time_offset variable which represents the current offset
+ * with respect to standard time. The FINEUSEC define represents 1 usec in
+ * scaled units.
+ *
+ * SHIFT_USEC defines the scaling (shift) of the time_freq and
+ * time_tolerance variables, which represent the current frequency
+ * offset and maximum frequency tolerance.
+ *
+ * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable.
+ */
+#define SHIFT_SCALE 22 /* phase scale (shift) */
+#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
+#define SHIFT_USEC 16 /* frequency offset scale (shift) */
+#define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */
+
+#define MAXPHASE 512000L /* max phase error (us) */
+#define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */
+#define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */
+#define MINSEC 16L /* min interval between updates (s) */
+#define MAXSEC 1200L /* max interval between updates (s) */
+#define NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */
+
+/*
+ * The following defines are used only if a pulse-per-second (PPS)
+ * signal is available and connected via a modem control lead, such as
+ * produced by the optional ppsclock feature incorporated in the Sun
+ * asynch driver. They establish the design parameters of the frequency-
+ * lock loop used to discipline the CPU clock oscillator to the PPS
+ * signal.
+ *
+ * PPS_AVG is the averaging factor for the frequency loop, as well as
+ * the time and frequency dispersion.
+ *
+ * PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum
+ * calibration intervals, respectively, in seconds as a power of two.
+ *
+ * PPS_VALID is the maximum interval before the PPS signal is considered
+ * invalid and protocol updates used directly instead.
+ *
+ * MAXGLITCH is the maximum interval before a time offset of more than
+ * MAXTIME is believed.
+ */
+#define PPS_AVG 2 /* pps averaging constant (shift) */
+#define PPS_SHIFT 2 /* min interval duration (s) (shift) */
+#define PPS_SHIFTMAX 8 /* max interval duration (s) (shift) */
+#define PPS_VALID 120 /* pps signal watchdog max (s) */
+#define MAXGLITCH 30 /* pps signal glitch max (s) */
+
+/*
+ * Pick up the architecture specific timex specifications
+ */
+#include <asm/timex.h>
+
+/* LATCH is used in the interval timer and ftape setup. */
+#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
+
+/*
+ * syscall interface - used (mainly by NTP daemon)
+ * to discipline kernel clock oscillator
+ */
+struct timex {
+ unsigned int modes; /* mode selector */
+ long offset; /* time offset (usec) */
+ long freq; /* frequency offset (scaled ppm) */
+ long maxerror; /* maximum error (usec) */
+ long esterror; /* estimated error (usec) */
+ int status; /* clock command/status */
+ long constant; /* pll time constant */
+ long precision; /* clock precision (usec) (read only) */
+ long tolerance; /* clock frequency tolerance (ppm)
+ * (read only)
+ */
+ struct timeval time; /* (read only) */
+ long tick; /* (modified) usecs between clock ticks */
+
+ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ long jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro) */
+ long stabil; /* pps stability (scaled ppm) (ro) */
+ long jitcnt; /* jitter limit exceeded (ro) */
+ long calcnt; /* calibration intervals (ro) */
+ long errcnt; /* calibration errors (ro) */
+ long stbcnt; /* stability limit exceeded (ro) */
+
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+};
+
+/*
+ * Mode codes (timex.mode)
+ */
+#define ADJ_OFFSET 0x0001 /* time offset */
+#define ADJ_FREQUENCY 0x0002 /* frequency offset */
+#define ADJ_MAXERROR 0x0004 /* maximum time error */
+#define ADJ_ESTERROR 0x0008 /* estimated time error */
+#define ADJ_STATUS 0x0010 /* clock status */
+#define ADJ_TIMECONST 0x0020 /* pll time constant */
+#define ADJ_TICK 0x4000 /* tick value */
+#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
+
+/* xntp 3.4 compatibility names */
+#define MOD_OFFSET ADJ_OFFSET
+#define MOD_FREQUENCY ADJ_FREQUENCY
+#define MOD_MAXERROR ADJ_MAXERROR
+#define MOD_ESTERROR ADJ_ESTERROR
+#define MOD_STATUS ADJ_STATUS
+#define MOD_TIMECONST ADJ_TIMECONST
+#define MOD_CLKB ADJ_TICK
+#define MOD_CLKA ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
+
+
+/*
+ * Status codes (timex.status)
+ */
+#define STA_PLL 0x0001 /* enable PLL updates (rw) */
+#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */
+#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */
+#define STA_FLL 0x0008 /* select frequency-lock mode (rw) */
+
+#define STA_INS 0x0010 /* insert leap (rw) */
+#define STA_DEL 0x0020 /* delete leap (rw) */
+#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */
+#define STA_FREQHOLD 0x0080 /* hold frequency (rw) */
+
+#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */
+#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */
+#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */
+#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
+
+#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
+
+#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
+ STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
+
+/*
+ * Clock states (time_state)
+ */
+#define TIME_OK 0 /* clock synchronized, no leap second */
+#define TIME_INS 1 /* insert leap second */
+#define TIME_DEL 2 /* delete leap second */
+#define TIME_OOP 3 /* leap second in progress */
+#define TIME_WAIT 4 /* leap second has occurred */
+#define TIME_ERROR 5 /* clock not synchronized */
+#define TIME_BAD TIME_ERROR /* bw compat */
+
+#ifdef __KERNEL__
+/*
+ * kernel variables
+ * Note: maximum error = NTP synch distance = dispersion + delay / 2;
+ * estimated error = NTP dispersion.
+ */
+extern long tick; /* timer interrupt period */
+extern int tickadj; /* amount of adjustment per tick */
+
+/*
+ * phase-lock loop variables
+ */
+extern int time_state; /* clock status */
+extern int time_status; /* clock synchronization status bits */
+extern long time_offset; /* time adjustment (us) */
+extern long time_constant; /* pll time constant */
+extern long time_tolerance; /* frequency tolerance (ppm) */
+extern long time_precision; /* clock precision (us) */
+extern long time_maxerror; /* maximum error */
+extern long time_esterror; /* estimated error */
+
+extern long time_phase; /* phase offset (scaled us) */
+extern long time_freq; /* frequency offset (scaled ppm) */
+extern long time_adj; /* tick adjust (scaled 1 / HZ) */
+extern long time_reftime; /* time at last adjustment (s) */
+
+extern long time_adjust; /* The amount of adjtime left */
+
+/* interface variables pps->timer interrupt */
+extern long pps_offset; /* pps time offset (us) */
+extern long pps_jitter; /* time dispersion (jitter) (us) */
+extern long pps_freq; /* frequency offset (scaled ppm) */
+extern long pps_stabil; /* frequency dispersion (scaled ppm) */
+extern long pps_valid; /* pps signal watchdog counter */
+
+/* interface variables pps->adjtimex */
+extern int pps_shift; /* interval duration (s) (shift) */
+extern long pps_jitcnt; /* jitter limit exceeded */
+extern long pps_calcnt; /* calibration intervals */
+extern long pps_errcnt; /* calibration errors */
+extern long pps_stbcnt; /* stability limit exceeded */
+
+#endif /* KERNEL */
+
+#endif /* LINUX_TIMEX_H */
diff --git a/pfinet/linux-src/include/linux/tpqic02.h b/pfinet/linux-src/include/linux/tpqic02.h
new file mode 100644
index 00000000..790e0e5a
--- /dev/null
+++ b/pfinet/linux-src/include/linux/tpqic02.h
@@ -0,0 +1,739 @@
+/* $Id: tpqic02.h,v 1.5 1996/12/14 23:01:38 root Exp root $
+ *
+ * Include file for QIC-02 driver for Linux.
+ *
+ * Copyright (c) 1992--1995 by H. H. Bergman. All rights reserved.
+ *
+ * ******* USER CONFIG SECTION BELOW (Near line 70) *******
+ */
+
+#ifndef _LINUX_TPQIC02_H
+#define _LINUX_TPQIC02_H
+
+#include <linux/config.h>
+
+#if CONFIG_QIC02_TAPE || CONFIG_QIC02_TAPE_MODULE
+
+/* need to have QIC02_TAPE_DRIVE and QIC02_TAPE_IFC expand to something */
+#include <linux/mtio.h>
+
+
+/* Make QIC02_TAPE_IFC expand to something.
+ *
+ * The only difference between WANGTEK and EVEREX is in the
+ * handling of the DMA channel 3.
+ * Note that the driver maps EVEREX to WANGTEK internally for speed
+ * reasons. Externally WANGTEK==1, EVEREX==2, ARCHIVE==3.
+ * These must correspond to the values used in qic02config(1).
+ *
+ * Support for Mountain controllers was added by Erik Jacobson
+ * and severely hacked by me. -- hhb
+ *
+ * Support for Emerald controllers by Alan Bain <afrb2@chiark.chu.cam.ac.uk>
+ * with more hacks by me. -- hhb
+ */
+#define WANGTEK 1 /* don't know about Wangtek QIC-36 */
+#define EVEREX (WANGTEK+1) /* I heard *some* of these are identical */
+#define EVEREX_811V EVEREX /* With TEAC MT 2ST 45D */
+#define EVEREX_831V EVEREX
+#define ARCHIVE 3
+#define ARCHIVE_SC400 ARCHIVE /* rumoured to be from the pre-SMD-age */
+#define ARCHIVE_SC402 ARCHIVE /* don't know much about SC400 */
+#define ARCHIVE_SC499 ARCHIVE /* SC402 and SC499R should be identical */
+
+#define MOUNTAIN 5 /* Mountain Computer Interface */
+#define EMERALD 6 /* Emerald Interface card */
+
+
+
+#define QIC02_TAPE_PORT_RANGE 8 /* number of IO locations to reserve */
+
+
+/*********** START OF USER CONFIGURABLE SECTION ************/
+
+/* Tape configuration: Select DRIVE, IFC, PORT, IRQ and DMA below.
+ * Runtime (re)configuration is not supported yet.
+ *
+ * Tape drive configuration: (MT_IS* constants are defined in mtio.h)
+ *
+ * QIC02_TAPE_DRIVE = MT_ISWT5150
+ * - Wangtek 5150, format: up to QIC-150.
+ * QIC02_TAPE_DRIVE = MT_ISQIC02_ALL_FEATURES
+ * - Enables some optional QIC02 commands that some drives may lack.
+ * It is provided so you can check which are supported by your drive.
+ * Refer to tpqic02.h for others.
+ *
+ * Supported interface cards: QIC02_TAPE_IFC =
+ * WANGTEK,
+ * ARCHIVE_SC402, ARCHIVE_SC499. (both same programming interface)
+ *
+ * Make sure you have the I/O ports/DMA channels
+ * and IRQ stuff configured properly!
+ * NOTE: There may be other device drivers using the same major
+ * number. This must be avoided. Check for timer.h conflicts too.
+ *
+ * If you have an EVEREX EV-831 card and you are using DMA channel 3,
+ * you will probably have to ``#define QIC02_TAPE_DMA3_FIX'' below.
+ */
+
+/* CONFIG_QIC02_DYNCONF can be defined in autoconf.h, by `make config' */
+
+/*** #undef CONFIG_QIC02_DYNCONF ***/
+
+#ifndef CONFIG_QIC02_DYNCONF
+
+#define QIC02_TAPE_DRIVE MT_ISQIC02_ALL_FEATURES /* drive type */
+/* #define QIC02_TAPE_DRIVE MT_ISWT5150 */
+/* #define QIC02_TAPE_DRIVE MT_ISARCHIVE_5945L2 */
+/* #define QIC02_TAPE_DRIVE MT_ISTEAC_MT2ST */
+/* #define QIC02_TAPE_DRIVE MT_ISARCHIVE_2150L */
+/* #define QIC02_TAPE_DRIVE MT_ISARCHIVESC499 */
+
+/* Either WANGTEK, ARCHIVE or MOUNTAIN. Not EVEREX.
+ * If you have an EVEREX, use WANGTEK and try the DMA3_FIX below.
+ */
+#define QIC02_TAPE_IFC WANGTEK /* interface card type */
+/* #define QIC02_TAPE_IFC ARCHIVE */
+/* #define QIC02_TAPE_IFC MOUNTAIN */
+
+#define QIC02_TAPE_PORT 0x300 /* controller port address */
+#define QIC02_TAPE_IRQ 5 /* For IRQ2, use 9 here, others normal. */
+#define QIC02_TAPE_DMA 1 /* either 1 or 3, because 2 is used by the floppy */
+
+/* If DMA3 doesn't work, but DMA1 does, and you have a
+ * Wangtek/Everex card, you can try #define-ing the flag
+ * below. Note that you should also change the DACK jumper
+ * for Wangtek/Everex cards when changing the DMA channel.
+ */
+#undef QIC02_TAPE_DMA3_FIX
+
+/************ END OF USER CONFIGURABLE SECTION *************/
+
+/* I put the stuff above in config.in, but a few recompiles, to
+ * verify different configurations, and several days later I decided
+ * to change it back again.
+ */
+
+
+
+/* NOTE: TP_HAVE_DENS should distinguish between available densities (?)
+ * NOTE: Drive select is not implemented -- I have only one tape streamer,
+ * so I'm unable and unmotivated to test and implement that. ;-) ;-)
+ */
+#if QIC02_TAPE_DRIVE == MT_ISWT5150
+#define TP_HAVE_DENS 1
+#define TP_HAVE_BSF 0 /* nope */
+#define TP_HAVE_FSR 0 /* nope */
+#define TP_HAVE_BSR 0 /* nope */
+#define TP_HAVE_EOD 0 /* most of the time */
+#define TP_HAVE_SEEK 0
+#define TP_HAVE_TELL 0
+#define TP_HAVE_RAS1 1
+#define TP_HAVE_RAS2 1
+
+#elif QIC02_TAPE_DRIVE == MT_ISARCHIVESC499 /* Archive SC-499 QIC-36 controller */
+#define TP_HAVE_DENS 1 /* can do set density (QIC-11 / QIC-24) */
+#define TP_HAVE_BSF 0
+#define TP_HAVE_FSR 1 /* can skip one block forwards */
+#define TP_HAVE_BSR 1 /* can skip one block backwards */
+#define TP_HAVE_EOD 1 /* can seek to end of recorded data */
+#define TP_HAVE_SEEK 0
+#define TP_HAVE_TELL 0
+#define TP_HAVE_RAS1 1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 1 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+#elif (QIC02_TAPE_DRIVE == MT_ISARCHIVE_2060L) || (QIC02_TAPE_DRIVE == MT_ISARCHIVE_2150L)
+#define TP_HAVE_DENS 1 /* can do set density (QIC-24 / QIC-120 / QIC-150) */
+#define TP_HAVE_BSF 0
+#define TP_HAVE_FSR 1 /* can skip one block forwards */
+#define TP_HAVE_BSR 1 /* can skip one block backwards */
+#define TP_HAVE_EOD 1 /* can seek to end of recorded data */
+#define TP_HAVE_TELL 1 /* can read current block address */
+#define TP_HAVE_SEEK 1 /* can seek to block */
+#define TP_HAVE_RAS1 1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 1 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+#elif QIC02_TAPE_DRIVE == MT_ISARCHIVE_5945L2
+/* can anyone verify this entry?? */
+#define TP_HAVE_DENS 1 /* can do set density?? (QIC-24??) */
+#define TP_HAVE_BSF 0
+#define TP_HAVE_FSR 1 /* can skip one block forwards */
+#define TP_HAVE_BSR 1 /* can skip one block backwards */
+#define TP_HAVE_EOD 1 /* can seek to end of recorded data */
+#define TP_HAVE_TELL 1 /* can read current block address */
+#define TP_HAVE_SEEK 1 /* can seek to block */
+#define TP_HAVE_RAS1 1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 1 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+#elif QIC02_TAPE_DRIVE == MT_ISTEAC_MT2ST
+/* can anyone verify this entry?? */
+#define TP_HAVE_DENS 0 /* cannot do set density?? (QIC-150?) */
+#define TP_HAVE_BSF 0
+#define TP_HAVE_FSR 1 /* can skip one block forwards */
+#define TP_HAVE_BSR 1 /* can skip one block backwards */
+#define TP_HAVE_EOD 1 /* can seek to end of recorded data */
+#define TP_HAVE_SEEK 1 /* can seek to block */
+#define TP_HAVE_TELL 1 /* can read current block address */
+#define TP_HAVE_RAS1 1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 1 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+#elif QIC02_TAPE_DRIVE == MT_ISQIC02_ALL_FEATURES
+#define TP_HAVE_DENS 1 /* can do set density */
+#define TP_HAVE_BSF 1 /* can search filemark backwards */
+#define TP_HAVE_FSR 1 /* can skip one block forwards */
+#define TP_HAVE_BSR 1 /* can skip one block backwards */
+#define TP_HAVE_EOD 1 /* can seek to end of recorded data */
+#define TP_HAVE_SEEK 1 /* seek to block address */
+#define TP_HAVE_TELL 1 /* tell current block address */
+#define TP_HAVE_RAS1 1 /* can run selftest 1 */
+#define TP_HAVE_RAS2 1 /* can run selftest 2 */
+/* These last two selftests shouldn't be used yet! */
+
+
+#else
+#error No QIC-02 tape drive type defined!
+/* If your drive is not listed above, first try the 'ALL_FEATURES',
+ * to see what commands are supported, then create your own entry in
+ * the list above. You may want to mail it to me, so that I can include
+ * it in the next release.
+ */
+#endif
+
+#endif /* !CONFIG_QIC02_DYNCONF */
+
+
+/* WANGTEK interface card specifics */
+#define WT_QIC02_STAT_PORT (QIC02_TAPE_PORT)
+#define WT_QIC02_CTL_PORT (QIC02_TAPE_PORT)
+#define WT_QIC02_CMD_PORT (QIC02_TAPE_PORT+1)
+#define WT_QIC02_DATA_PORT (QIC02_TAPE_PORT+1)
+
+/* status register bits (Active LOW!) */
+#define WT_QIC02_STAT_POLARITY 0
+#define WT_QIC02_STAT_READY 0x01
+#define WT_QIC02_STAT_EXCEPTION 0x02
+#define WT_QIC02_STAT_MASK (WT_QIC02_STAT_READY|WT_QIC02_STAT_EXCEPTION)
+
+#define WT_QIC02_STAT_RESETMASK 0x07
+#define WT_QIC02_STAT_RESETVAL (WT_QIC02_STAT_RESETMASK & ~WT_QIC02_STAT_EXCEPTION)
+
+/* controller register (QIC02_CTL_PORT) bits */
+#define WT_QIC02_CTL_RESET 0x02
+#define WT_QIC02_CTL_REQUEST 0x04
+#define WT_CTL_ONLINE 0x01
+#define WT_CTL_CMDOFF 0xC0
+
+#define WT_CTL_DMA3 0x10 /* enable dma chan3 */
+#define WT_CTL_DMA1 0x08 /* enable dma chan1 or chan2 */
+
+/* EMERALD interface card specifics
+ * Much like Wangtek, only different polarity and bit locations
+ */
+#define EMR_QIC02_STAT_PORT (QIC02_TAPE_PORT)
+#define EMR_QIC02_CTL_PORT (QIC02_TAPE_PORT)
+#define EMR_QIC02_CMD_PORT (QIC02_TAPE_PORT+1)
+#define EMR_QIC02_DATA_PORT (QIC02_TAPE_PORT+1)
+
+/* status register bits (Active High!) */
+#define EMR_QIC02_STAT_POLARITY 1
+#define EMR_QIC02_STAT_READY 0x01
+#define EMR_QIC02_STAT_EXCEPTION 0x02
+#define EMR_QIC02_STAT_MASK (EMR_QIC02_STAT_READY|EMR_QIC02_STAT_EXCEPTION)
+
+#define EMR_QIC02_STAT_RESETMASK 0x07
+#define EMR_QIC02_STAT_RESETVAL (EMR_QIC02_STAT_RESETMASK & ~EMR_QIC02_STAT_EXCEPTION)
+
+/* controller register (QIC02_CTL_PORT) bits */
+#define EMR_QIC02_CTL_RESET 0x02
+#define EMR_QIC02_CTL_REQUEST 0x04
+#define EMR_CTL_ONLINE 0x01
+#define EMR_CTL_CMDOFF 0xC0
+
+#define EMR_CTL_DMA3 0x10 /* enable dma chan3 */
+#define EMR_CTL_DMA1 0x08 /* enable dma chan1 or chan2 */
+
+
+
+/* ARCHIVE interface card specifics */
+#define AR_QIC02_STAT_PORT (QIC02_TAPE_PORT+1)
+#define AR_QIC02_CTL_PORT (QIC02_TAPE_PORT+1)
+#define AR_QIC02_CMD_PORT (QIC02_TAPE_PORT)
+#define AR_QIC02_DATA_PORT (QIC02_TAPE_PORT)
+
+#define AR_START_DMA_PORT (QIC02_TAPE_PORT+2)
+#define AR_RESET_DMA_PORT (QIC02_TAPE_PORT+3)
+
+/* STAT port bits */
+#define AR_QIC02_STAT_POLARITY 0
+#define AR_STAT_IRQF 0x80 /* active high, interrupt request flag */
+#define AR_QIC02_STAT_READY 0x40 /* active low */
+#define AR_QIC02_STAT_EXCEPTION 0x20 /* active low */
+#define AR_QIC02_STAT_MASK (AR_QIC02_STAT_READY|AR_QIC02_STAT_EXCEPTION)
+#define AR_STAT_DMADONE 0x10 /* active high, DMA done */
+#define AR_STAT_DIRC 0x08 /* active high, direction */
+
+#define AR_QIC02_STAT_RESETMASK 0x70 /* check RDY,EXC,DMADONE */
+#define AR_QIC02_STAT_RESETVAL ((AR_QIC02_STAT_RESETMASK & ~AR_STAT_IRQF & ~AR_QIC02_STAT_EXCEPTION) | AR_STAT_DMADONE)
+
+/* CTL port bits */
+#define AR_QIC02_CTL_RESET 0x80 /* drive reset */
+#define AR_QIC02_CTL_REQUEST 0x40 /* notify of new command */
+#define AR_CTL_IEN 0x20 /* interrupt enable */
+#define AR_CTL_DNIEN 0x10 /* done-interrupt enable */
+ /* Note: All of these bits are cleared automatically when writing to
+ * AR_RESET_DMA_PORT. So AR_CTL_IEN and AR_CTL_DNIEN must be
+ * reprogrammed before the write to AR_START_DMA_PORT.
+ */
+
+
+/* MOUNTAIN interface specifics */
+#define MTN_QIC02_STAT_PORT (QIC02_TAPE_PORT+1)
+#define MTN_QIC02_CTL_PORT (QIC02_TAPE_PORT+1)
+#define MTN_QIC02_CMD_PORT (QIC02_TAPE_PORT)
+#define MTN_QIC02_DATA_PORT (QIC02_TAPE_PORT)
+
+#define MTN_W_SELECT_DMA_PORT (QIC02_TAPE_PORT+2)
+#define MTN_R_DESELECT_DMA_PORT (QIC02_TAPE_PORT+2)
+#define MTN_W_DMA_WRITE_PORT (QIC02_TAPE_PORT+3)
+
+/* STAT port bits */
+#define MTN_QIC02_STAT_POLARITY 0
+#define MTN_QIC02_STAT_READY 0x02 /* active low */
+#define MTN_QIC02_STAT_EXCEPTION 0x04 /* active low */
+#define MTN_QIC02_STAT_MASK (MTN_QIC02_STAT_READY|MTN_QIC02_STAT_EXCEPTION)
+#define MTN_STAT_DMADONE 0x01 /* active high, DMA done */
+
+#define MTN_QIC02_STAT_RESETMASK 0x07 /* check RDY,EXC,DMADONE */
+#define MTN_QIC02_STAT_RESETVAL ((MTN_QIC02_STAT_RESETMASK & ~MTN_QIC02_STAT_EXCEPTION) | MTN_STAT_DMADONE)
+
+/* CTL port bits */
+#define MTN_QIC02_CTL_RESET_NOT 0x80 /* drive reset, active low */
+#define MTN_QIC02_CTL_RESET 0x80 /* Fodder #definition to keep gcc happy */
+
+#define MTN_QIC02_CTL_ONLINE 0x40 /* Put drive on line */
+#define MTN_QIC02_CTL_REQUEST 0x20 /* notify of new command */
+#define MTN_QIC02_CTL_IRQ_DRIVER 0x10 /* Enable IRQ tristate driver */
+#define MTN_QIC02_CTL_DMA_DRIVER 0x08 /* Enable DMA tristate driver */
+#define MTN_CTL_EXC_IEN 0x04 /* Exception interrupt enable */
+#define MTN_CTL_RDY_IEN 0x02 /* Ready interrupt enable */
+#define MTN_CTL_DNIEN 0x01 /* done-interrupt enable */
+
+#define MTN_CTL_ONLINE (MTN_QIC02_CTL_RESET_NOT | MTN_QIC02_CTL_IRQ_DRIVER | MTN_QIC02_CTL_DMA_DRIVER)
+
+
+#ifndef CONFIG_QIC02_DYNCONF
+
+# define QIC02_TAPE_DEBUG (qic02_tape_debug)
+
+# if QIC02_TAPE_IFC == WANGTEK
+# define QIC02_STAT_POLARITY WT_QIC02_STAT_POLARITY
+# define QIC02_STAT_PORT WT_QIC02_STAT_PORT
+# define QIC02_CTL_PORT WT_QIC02_CTL_PORT
+# define QIC02_CMD_PORT WT_QIC02_CMD_PORT
+# define QIC02_DATA_PORT WT_QIC02_DATA_PORT
+
+# define QIC02_STAT_READY WT_QIC02_STAT_READY
+# define QIC02_STAT_EXCEPTION WT_QIC02_STAT_EXCEPTION
+# define QIC02_STAT_MASK WT_QIC02_STAT_MASK
+# define QIC02_STAT_RESETMASK WT_QIC02_STAT_RESETMASK
+# define QIC02_STAT_RESETVAL WT_QIC02_STAT_RESETVAL
+
+# define QIC02_CTL_RESET WT_QIC02_CTL_RESET
+# define QIC02_CTL_REQUEST WT_QIC02_CTL_REQUEST
+
+# if QIC02_TAPE_DMA == 3
+# ifdef QIC02_TAPE_DMA3_FIX
+# define WT_CTL_DMA WT_CTL_DMA1
+# else
+# define WT_CTL_DMA WT_CTL_DMA3
+# endif
+# elif QIC02_TAPE_DMA == 1
+# define WT_CTL_DMA WT_CTL_DMA1
+# else
+# error Unsupported or incorrect DMA configuration.
+# endif
+
+# elif QIC02_TAPE_IFC == EMERALD
+# define QIC02_STAT_POLARITY EMR_QIC02_STAT_POLARITY
+# define QIC02_STAT_PORT EMR_QIC02_STAT_PORT
+# define QIC02_CTL_PORT EMR_QIC02_CTL_PORT
+# define QIC02_CMD_PORT EMR_QIC02_CMD_PORT
+# define QIC02_DATA_PORT EMR_QIC02_DATA_PORT
+
+# define QIC02_STAT_READY EMR_QIC02_STAT_READY
+# define QIC02_STAT_EXCEPTION EMR_QIC02_STAT_EXCEPTION
+# define QIC02_STAT_MASK EMR_QIC02_STAT_MASK
+# define QIC02_STAT_RESETMASK EMR_QIC02_STAT_RESETMASK
+# define QIC02_STAT_RESETVAL EMR_QIC02_STAT_RESETVAL
+
+# define QIC02_CTL_RESET EMR_QIC02_CTL_RESET
+# define QIC02_CTL_REQUEST EMR_QIC02_CTL_REQUEST
+
+# if QIC02_TAPE_DMA == 3
+# ifdef QIC02_TAPE_DMA3_FIX
+# define EMR_CTL_DMA EMR_CTL_DMA1
+# else
+# define EMR_CTL_DMA EMR_CTL_DMA3
+# endif
+# elif QIC02_TAPE_DMA == 1
+# define EMR_CTL_DMA EMR_CTL_DMA1
+# else
+# error Unsupported or incorrect DMA configuration.
+# endif
+
+# elif QIC02_TAPE_IFC == ARCHIVE
+# define QIC02_STAT_POLARITY AR_QIC02_STAT_POLARITY
+# define QIC02_STAT_PORT AR_QIC02_STAT_PORT
+# define QIC02_CTL_PORT AR_QIC02_CTL_PORT
+# define QIC02_CMD_PORT AR_QIC02_CMD_PORT
+# define QIC02_DATA_PORT AR_QIC02_DATA_PORT
+
+# define QIC02_STAT_READY AR_QIC02_STAT_READY
+# define QIC02_STAT_EXCEPTION AR_QIC02_STAT_EXCEPTION
+# define QIC02_STAT_MASK AR_QIC02_STAT_MASK
+# define QIC02_STAT_RESETMASK AR_QIC02_STAT_RESETMASK
+# define QIC02_STAT_RESETVAL AR_QIC02_STAT_RESETVAL
+
+# define QIC02_CTL_RESET AR_QIC02_CTL_RESET
+# define QIC02_CTL_REQUEST AR_QIC02_CTL_REQUEST
+
+# if QIC02_TAPE_DMA > 3 /* channel 2 is used by the floppy driver */
+# error DMA channels other than 1 and 3 are not supported.
+# endif
+
+# elif QIC02_TAPE_IFC == MOUNTAIN
+# define QIC02_STAT_POLARITY MTN_QIC02_STAT_POLARITY
+# define QIC02_STAT_PORT MTN_QIC02_STAT_PORT
+# define QIC02_CTL_PORT MTN_QIC02_CTL_PORT
+# define QIC02_CMD_PORT MTN_QIC02_CMD_PORT
+# define QIC02_DATA_PORT MTN_QIC02_DATA_PORT
+
+# define QIC02_STAT_READY MTN_QIC02_STAT_READY
+# define QIC02_STAT_EXCEPTION MTN_QIC02_STAT_EXCEPTION
+# define QIC02_STAT_MASK MTN_QIC02_STAT_MASK
+# define QIC02_STAT_RESETMASK MTN_QIC02_STAT_RESETMASK
+# define QIC02_STAT_RESETVAL MTN_QIC02_STAT_RESETVAL
+
+# define QIC02_CTL_RESET MTN_QIC02_CTL_RESET
+# define QIC02_CTL_REQUEST MTN_QIC02_CTL_REQUEST
+
+# if QIC02_TAPE_DMA > 3 /* channel 2 is used by the floppy driver */
+# error DMA channels other than 1 and 3 are not supported.
+# endif
+
+# else
+# error No valid interface card specified!
+# endif /* QIC02_TAPE_IFC */
+
+
+ /* An ugly hack to make sure WT_CTL_DMA is defined even for the
+ * static, non-Wangtek case. The alternative was even worse.
+ */
+# ifndef WT_CTL_DMA
+# define WT_CTL_DMA WT_CTL_DMA1
+# endif
+
+/*******************/
+
+#else /* !CONFIG_QIC02_DYNCONF */
+
+/* Now the runtime config version, using variables instead of constants.
+ *
+ * qic02_tape_dynconf is R/O for the kernel, set from userspace.
+ * qic02_tape_ccb is private to the driver, R/W.
+ */
+
+# define QIC02_TAPE_DRIVE (qic02_tape_dynconf.mt_type)
+# define QIC02_TAPE_IFC (qic02_tape_ccb.ifc_type)
+# define QIC02_TAPE_IRQ (qic02_tape_dynconf.irqnr)
+# define QIC02_TAPE_DMA (qic02_tape_dynconf.dmanr)
+# define QIC02_TAPE_PORT (qic02_tape_dynconf.port)
+# define WT_CTL_DMA (qic02_tape_ccb.dma_enable_value)
+# define QIC02_TAPE_DEBUG (qic02_tape_dynconf.debug)
+
+# define QIC02_STAT_PORT (qic02_tape_ccb.port_stat)
+# define QIC02_CTL_PORT (qic02_tape_ccb.port_ctl)
+# define QIC02_CMD_PORT (qic02_tape_ccb.port_cmd)
+# define QIC02_DATA_PORT (qic02_tape_ccb.port_data)
+
+# define QIC02_STAT_POLARITY (qic02_tape_ccb.stat_polarity)
+# define QIC02_STAT_READY (qic02_tape_ccb.stat_ready)
+# define QIC02_STAT_EXCEPTION (qic02_tape_ccb.stat_exception)
+# define QIC02_STAT_MASK (qic02_tape_ccb.stat_mask)
+
+# define QIC02_STAT_RESETMASK (qic02_tape_ccb.stat_resetmask)
+# define QIC02_STAT_RESETVAL (qic02_tape_ccb.stat_resetval)
+
+# define QIC02_CTL_RESET (qic02_tape_ccb.ctl_reset)
+# define QIC02_CTL_REQUEST (qic02_tape_ccb.ctl_request)
+
+# define TP_HAVE_DENS (qic02_tape_dynconf.have_dens)
+# define TP_HAVE_BSF (qic02_tape_dynconf.have_bsf)
+# define TP_HAVE_FSR (qic02_tape_dynconf.have_fsr)
+# define TP_HAVE_BSR (qic02_tape_dynconf.have_bsr)
+# define TP_HAVE_EOD (qic02_tape_dynconf.have_eod)
+# define TP_HAVE_SEEK (qic02_tape_dynconf.have_seek)
+# define TP_HAVE_TELL (qic02_tape_dynconf.have_tell)
+# define TP_HAVE_RAS1 (qic02_tape_dynconf.have_ras1)
+# define TP_HAVE_RAS2 (qic02_tape_dynconf.have_ras2)
+
+#endif /* CONFIG_QIC02_DYNCONF */
+
+
+/* "Vendor Unique" codes */
+/* Archive seek & tell stuff */
+#define AR_QCMDV_TELL_BLK 0xAE /* read current block address */
+#define AR_QCMDV_SEEK_BLK 0xAD /* seek to specific block */
+#define AR_SEEK_BUF_SIZE 3 /* address is 3 bytes */
+
+
+
+/*
+ * Misc common stuff
+ */
+
+/* Standard QIC-02 commands -- rev F. All QIC-02 drives must support these */
+#define QCMD_SEL_1 0x01 /* select drive 1 */
+#define QCMD_SEL_2 0x02 /* select drive 2 */
+#define QCMD_SEL_3 0x04 /* select drive 3 */
+#define QCMD_SEL_4 0x08 /* select drive 4 */
+#define QCMD_REWIND 0x21 /* rewind tape */
+#define QCMD_ERASE 0x22 /* erase tape */
+#define QCMD_RETEN 0x24 /* retension tape */
+#define QCMD_WRT_DATA 0x40 /* write data */
+#define QCMD_WRT_FM 0x60 /* write file mark */
+#define QCMD_RD_DATA 0x80 /* read data */
+#define QCMD_RD_FM 0xA0 /* read file mark (forward direction) */
+#define QCMD_RD_STAT 0xC0 /* read status */
+
+/* Other (optional/vendor unique) commands */
+ /* Density commands are only valid when TP_BOM is set! */
+#define QCMD_DENS_11 0x26 /* QIC-11 */
+#define QCMD_DENS_24 0x27 /* QIC-24: 9 track 60MB */
+#define QCMD_DENS_120 0x28 /* QIC-120: 15 track 120MB */
+#define QCMD_DENS_150 0x29 /* QIC-150: 18 track 150MB */
+#define QCMD_DENS_300 0x2A /* QIC-300/QIC-2100 */
+#define QCMD_DENS_600 0x2B /* QIC-600/QIC-2200 */
+/* don't know about QIC-1000 and QIC-1350 */
+
+#define QCMD_WRTNU_DATA 0x40 /* write data, no underruns, insert filler. */
+#define QCMD_SPACE_FWD 0x81 /* skip next block */
+#define QCMD_SPACE_BCK 0x89 /* move tape head one block back -- very useful! */
+#define QCMD_RD_FM_BCK 0xA8 /* read filemark (backwards) */
+#define QCMD_SEEK_EOD 0xA3 /* skip to EOD */
+#define QCMD_RD_STAT_X1 0xC1 /* read extended status 1 */
+#define QCMD_RD_STAT_X2 0xC4 /* read extended status 2 */
+#define QCMD_RD_STAT_X3 0xE0 /* read extended status 3 */
+#define QCMD_SELF_TST1 0xC2 /* run self test 1 (nondestructive) */
+#define QCMD_SELF_TST2 0xCA /* run self test 2 (destructive) */
+
+
+
+/* Optional, QFA (Quick File Access) commands.
+ * Not all drives support this, but those that do could use these commands
+ * to implement semi-non-sequential access. `mt fsf` would benefit from this.
+ * QFA divides the tape into 2 partitions, a data and a directory partition,
+ * causing some incompatibility problems wrt std QIC-02 data exchange.
+ * It would be useful to cache the directory info, but that might be tricky
+ * to do in kernel-space. [Size constraints.]
+ * Refer to the QIC-02 specs, appendix A for more information.
+ * I have no idea how other *nix variants implement QFA.
+ * I have no idea which drives support QFA and which don't.
+ */
+#define QFA_ENABLE 0x2D /* enter QFA mode, give @ BOT only */
+#define QFA_DATA 0x20 /* select data partition */
+#define QFA_DIR 0x23 /* select directory partition */
+#define QFA_RD_POS 0xCF /* read position+status bytes */
+#define QFA_SEEK_EOD 0xA1 /* seek EOD within current partition */
+#define QFA_SEEK_BLK 0xAF /* seek to a block within current partition */
+
+
+
+
+/*
+ * Debugging flags
+ */
+#define TPQD_SENSE_TEXT 0x0001
+#define TPQD_SENSE_CNTS 0x0002
+#define TPQD_REWIND 0x0004
+#define TPQD_TERM_CYCLE 0x0008
+#define TPQD_IOCTLS 0x0010
+#define TPQD_DMAX 0x0020
+#define TPQD_BLKSZ 0x0040
+#define TPQD_MISC 0x0080
+
+#define TPQD_DEBUG 0x0100
+
+#define TPQD_DIAGS 0x1000
+
+#define TPQD_ALWAYS 0x8000
+
+#define TPQD_DEFAULT_FLAGS 0x00fc
+
+
+#define TPQDBG(f) ((QIC02_TAPE_DEBUG) & (TPQD_##f))
+
+
+/* Minor device codes for tapes:
+ * |7|6|5|4|3|2|1|0|
+ * | \ | / \ | / |_____ 1=rewind on close, 0=no rewind on close
+ * | \|/ |_________ Density: 000=none, 001=QIC-11, 010=24, 011=120,
+ * | | 100=QIC-150, 101..111 reserved.
+ * | |_______________ Reserved for unit numbers.
+ * |___________________ Reserved for diagnostics during debugging.
+ */
+
+#define TP_REWCLOSE(d) ((MINOR(d)&0x01) == 1) /* rewind bit */
+ /* rewind is only done if data has been transferred */
+#define TP_DENS(dev) ((MINOR(dev) >> 1) & 0x07) /* tape density */
+#define TP_UNIT(dev) ((MINOR(dev) >> 4) & 0x07) /* unit number */
+
+/* print excessive diagnostics */
+#define TP_DIAGS(dev) (QIC02_TAPE_DEBUG & TPQD_DIAGS)
+
+/* status codes returned by a WTS_RDSTAT call */
+struct tpstatus { /* sizeof(short)==2), LSB first */
+ unsigned short exs; /* Drive exception flags */
+ unsigned short dec; /* data error count: nr of blocks rewritten/soft read errors */
+ unsigned short urc; /* underrun count: nr of times streaming was interrupted */
+};
+#define TPSTATSIZE sizeof(struct tpstatus)
+
+
+/* defines for tpstatus.exs -- taken from 386BSD wt driver */
+#define TP_POR 0x100 /* Power on or reset occurred */
+#define TP_EOR 0x200 /* REServed for end of RECORDED media */
+#define TP_PAR 0x400 /* REServed for bus parity */
+#define TP_BOM 0x800 /* Beginning of media */
+#define TP_MBD 0x1000 /* Marginal block detected */
+#define TP_NDT 0x2000 /* No data detected */
+#define TP_ILL 0x4000 /* Illegal command */
+#define TP_ST1 0x8000 /* Status byte 1 flag */
+#define TP_FIL 0x01 /* File mark detected */
+#define TP_BNL 0x02 /* Bad block not located */
+#define TP_UDA 0x04 /* Unrecoverable data error */
+#define TP_EOM 0x08 /* End of media */
+#define TP_WRP 0x10 /* Write protected cartridge */
+#define TP_USL 0x20 /* Unselected drive */
+#define TP_CNI 0x40 /* Cartridge not in place */
+#define TP_ST0 0x80 /* Status byte 0 flag */
+
+#define REPORT_ERR0 (TP_CNI|TP_USL|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL)
+#define REPORT_ERR1 (TP_ILL|TP_NDT|TP_MBD|TP_PAR)
+
+
+/* exception numbers */
+#define EXC_UNKNOWN 0 /* (extra) Unknown exception code */
+#define EXC_NDRV 1 /* No drive */
+#define EXC_NCART 2 /* No cartridge */
+#define EXC_WP 3 /* Write protected */
+#define EXC_EOM 4 /* EOM */
+#define EXC_RWA 5 /* read/write abort */
+#define EXC_XBAD 6 /* read error, bad block transferred */
+#define EXC_XFILLER 7 /* read error, filler block transferred */
+#define EXC_NDT 8 /* read error, no data */
+#define EXC_NDTEOM 9 /* read error, no data & EOM */
+#define EXC_NDTBOM 10 /* read error, no data & BOM */
+#define EXC_FM 11 /* Read a filemark */
+#define EXC_ILL 12 /* Illegal command */
+#define EXC_POR 13 /* Power on/reset */
+#define EXC_MARGINAL 14 /* Marginal block detected */
+#define EXC_EOR 15 /* (extra, for SEEKEOD) End Of Recorded data reached */
+#define EXC_BOM 16 /* (extra) BOM reached */
+
+
+#define TAPE_NOTIFY_TIMEOUT 1000000
+
+/* internal function return codes */
+#define TE_OK 0 /* everything is fine */
+#define TE_EX 1 /* exception detected */
+#define TE_ERR 2 /* some error */
+#define TE_NS 3 /* can't read status */
+#define TE_TIM 4 /* timed out */
+#define TE_DEAD 5 /* tape drive doesn't respond */
+#define TE_END 6 /******** Archive hack *****/
+
+/* timeout timer values -- check these! */
+#define TIM_S (4*HZ) /* 4 seconds (normal cmds) */
+#define TIM_M (30*HZ) /* 30 seconds (write FM) */
+#define TIM_R (8*60*HZ) /* 8 minutes (retensioning) */
+#define TIM_F (2*3600*HZ) /* est. 1.2hr for full tape read/write+2 retens */
+
+#define TIMERON(t) timer_table[QIC02_TAPE_TIMER].expires = jiffies + (t); \
+ timer_active |= (1<<QIC02_TAPE_TIMER)
+#define TIMEROFF timer_active &= ~(1<<QIC02_TAPE_TIMER)
+#define TIMERCONT timer_active |= (1<<QIC02_TAPE_TIMER)
+
+
+typedef char flag;
+#define NO 0 /* NO must be 0 */
+#define YES 1 /* YES must be != 0 */
+
+
+#ifdef TDEBUG
+# define TPQDEB(s) s
+# define TPQPUTS(s) tpqputs(s)
+#else
+# define TPQDEB(s)
+# define TPQPUTS(s)
+#endif
+
+
+/* NR_BLK_BUF is a `tuneable parameter'. If you're really low on
+ * kernel space, you could decrease it to 1, or if you got a very
+ * slow machine, you could increase it up to 127 blocks. Less kernel
+ * buffer blocks result in more context-switching.
+ */
+#define NR_BLK_BUF 20 /* max 127 blocks */
+#define TAPE_BLKSIZE 512 /* streamer tape block size (fixed) */
+#define TPQBUF_SIZE (TAPE_BLKSIZE*NR_BLK_BUF) /* buffer size */
+
+
+#define BLOCKS_BEYOND_EW 2 /* nr of blocks after Early Warning hole */
+#define BOGUS_IRQ 32009
+
+
+/* This is internal data, filled in based on the ifc_type field given
+ * by the user. Everex is mapped to Wangtek with a different
+ * `dma_enable_value', if dmanr==3.
+ */
+struct qic02_ccb {
+ long ifc_type;
+
+ unsigned short port_stat; /* Status port address */
+ unsigned short port_ctl; /* Control port address */
+ unsigned short port_cmd; /* Command port address */
+ unsigned short port_data; /* Data port address */
+
+ /* status register bits */
+ unsigned short stat_polarity; /* invert status bits or not */
+ unsigned short stat_ready; /* drive ready */
+ unsigned short stat_exception; /* drive signals exception */
+ unsigned short stat_mask;
+ unsigned short stat_resetmask;
+ unsigned short stat_resetval;
+
+ /* control register bits */
+ unsigned short ctl_reset; /* reset drive */
+ unsigned short ctl_request; /* latch command */
+
+ /* This is used to change the DMA3 behaviour */
+ unsigned short dma_enable_value;
+};
+
+#if MODULE
+static int qic02_tape_init(void);
+#else
+extern int qic02_tape_init(void); /* for mem.c */
+#endif
+
+
+
+#endif /* CONFIG_QIC02_TAPE */
+
+#endif /* _LINUX_TPQIC02_H */
+
diff --git a/pfinet/linux-src/include/linux/tqueue.h b/pfinet/linux-src/include/linux/tqueue.h
new file mode 100644
index 00000000..d886f753
--- /dev/null
+++ b/pfinet/linux-src/include/linux/tqueue.h
@@ -0,0 +1,124 @@
+/*
+ * tqueue.h --- task queue handling for Linux.
+ *
+ * Mostly based on a proposed bottom-half replacement code written by
+ * Kai Petzke, wpp@marie.physik.tu-berlin.de.
+ *
+ * Modified for use in the Linux kernel by Theodore Ts'o,
+ * tytso@mit.edu. Any bugs are my fault, not Kai's.
+ *
+ * The original comment follows below.
+ */
+
+#ifndef _LINUX_TQUEUE_H
+#define _LINUX_TQUEUE_H
+
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+/*
+ * New proposed "bottom half" handlers:
+ * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de
+ *
+ * Advantages:
+ * - Bottom halfs are implemented as a linked list. You can have as many
+ * of them, as you want.
+ * - No more scanning of a bit field is required upon call of a bottom half.
+ * - Support for chained bottom half lists. The run_task_queue() function can be
+ * used as a bottom half handler. This is for example useful for bottom
+ * halfs, which want to be delayed until the next clock tick.
+ *
+ * Problems:
+ * - The queue_task_irq() inline function is only atomic with respect to itself.
+ * Problems can occur, when queue_task_irq() is called from a normal system
+ * call, and an interrupt comes in. No problems occur, when queue_task_irq()
+ * is called from an interrupt or bottom half, and interrupted, as run_task_queue()
+ * will not be executed/continued before the last interrupt returns. If in
+ * doubt, use queue_task(), not queue_task_irq().
+ * - Bottom halfs are called in the reverse order that they were linked into
+ * the list.
+ */
+
+struct tq_struct {
+ struct tq_struct *next; /* linked list of active bh's */
+ unsigned long sync; /* must be initialized to zero */
+ void (*routine)(void *); /* function to call */
+ void *data; /* argument to function */
+};
+
+typedef struct tq_struct * task_queue;
+
+#define DECLARE_TASK_QUEUE(q) task_queue q = NULL
+
+extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk;
+
+/*
+ * To implement your own list of active bottom halfs, use the following
+ * two definitions:
+ *
+ * struct tq_struct *my_bh = NULL;
+ * struct tq_struct run_my_bh = {
+ * 0, 0, (void (*)(void *)) run_task_queue, &my_bh
+ * };
+ *
+ * To activate a bottom half on your list, use:
+ *
+ * queue_task(tq_pointer, &my_bh);
+ *
+ * To run the bottom halfs on your list put them on the immediate list by:
+ *
+ * queue_task(&run_my_bh, &tq_immediate);
+ *
+ * This allows you to do deferred procession. For example, you could
+ * have a bottom half list tq_timer, which is marked active by the timer
+ * interrupt.
+ */
+
+extern spinlock_t tqueue_lock;
+
+/*
+ * queue_task
+ */
+extern __inline__ void queue_task(struct tq_struct *bh_pointer,
+ task_queue *bh_list)
+{
+ if (!test_and_set_bit(0,&bh_pointer->sync)) {
+ unsigned long flags;
+ spin_lock_irqsave(&tqueue_lock, flags);
+ bh_pointer->next = *bh_list;
+ *bh_list = bh_pointer;
+ spin_unlock_irqrestore(&tqueue_lock, flags);
+ }
+}
+
+/*
+ * Call all "bottom halfs" on a given list.
+ */
+extern __inline__ void run_task_queue(task_queue *list)
+{
+ if (*list) {
+ unsigned long flags;
+ struct tq_struct *p;
+
+ spin_lock_irqsave(&tqueue_lock, flags);
+ p = *list;
+ *list = NULL;
+ spin_unlock_irqrestore(&tqueue_lock, flags);
+
+ while (p) {
+ void *arg;
+ void (*f) (void *);
+ struct tq_struct *save_p;
+ arg = p -> data;
+ f = p -> routine;
+ save_p = p;
+ p = p -> next;
+ mb();
+ save_p -> sync = 0;
+ (*f)(arg);
+ }
+ }
+}
+
+#endif /* _LINUX_TQUEUE_H */
diff --git a/pfinet/linux/etherdevice.h b/pfinet/linux-src/include/linux/trdevice.h
index 41073fcb..8689db32 100644
--- a/pfinet/linux/etherdevice.h
+++ b/pfinet/linux-src/include/linux/trdevice.h
@@ -3,7 +3,7 @@
* operating system. NET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
- * Definitions for the Ethernet handlers.
+ * Definitions for the Token-ring handlers.
*
* Version: @(#)eth.h 1.0.4 05/13/93
*
@@ -21,21 +21,20 @@
* WARNING: This move may well be temporary. This file will get merged with others RSN.
*
*/
-#ifndef _LINUX_ETHERDEVICE_H
-#define _LINUX_ETHERDEVICE_H
+#ifndef _LINUX_TRDEVICE_H
+#define _LINUX_TRDEVICE_H
-#include <linux/if_ether.h>
+#include <linux/if_tr.h>
#ifdef __KERNEL__
-extern int eth_header(unsigned char *buff, struct device *dev,
+extern int tr_header(struct sk_buff *skb, struct device *dev,
unsigned short type, void *daddr,
- void *saddr, unsigned len,
- struct sk_buff *skb);
-extern int eth_rebuild_header(void *buff, struct device *dev,
- unsigned long raddr, struct sk_buff *skb);
-extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev);
+ void *saddr, unsigned len);
+extern int tr_rebuild_header(struct sk_buff *skb);
+extern unsigned short tr_type_trans(struct sk_buff *skb, struct device *dev);
+extern struct device * init_trdev(struct device *, int);
#endif
-#endif /* _LINUX_ETHERDEVICE_H */
+#endif /* _LINUX_TRDEVICE_H */
diff --git a/pfinet/linux-src/include/linux/tty.h b/pfinet/linux-src/include/linux/tty.h
new file mode 100644
index 00000000..3112c349
--- /dev/null
+++ b/pfinet/linux-src/include/linux/tty.h
@@ -0,0 +1,417 @@
+#ifndef _LINUX_TTY_H
+#define _LINUX_TTY_H
+
+/*
+ * 'tty.h' defines some structures used by tty_io.c and some defines.
+ */
+
+/*
+ * These constants are also useful for user-level apps (e.g., VC
+ * resizing).
+ */
+#define MIN_NR_CONSOLES 1 /* must be at least 1 */
+#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */
+#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */
+ /* Note: the ioctl VT_GETSTATE does not work for
+ consoles 16 and higher (since it returns a short) */
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/termios.h>
+#include <linux/tqueue.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_ldisc.h>
+#include <linux/serialP.h>
+
+#include <asm/system.h>
+
+
+/*
+ * Note: don't mess with NR_PTYS until you understand the tty minor
+ * number allocation game...
+ * (Note: the *_driver.minor_start values 1, 64, 128, 192 are
+ * hardcoded at present.)
+ */
+#define NR_PTYS 256 /* ptys/major */
+#define NR_LDISCS 16
+
+/*
+ * Unix98 PTY's can be defined as any multiple of NR_PTYS up to
+ * UNIX98_PTY_MAJOR_COUNT; this section defines what we need from the
+ * config options
+ */
+#ifdef CONFIG_UNIX98_PTYS
+# define UNIX98_NR_MAJORS ((CONFIG_UNIX98_PTY_COUNT+NR_PTYS-1)/NR_PTYS)
+# if UNIX98_NR_MAJORS <= 0
+# undef CONFIG_UNIX98_PTYS
+# elif UNIX98_NR_MAJORS > UNIX98_PTY_MAJOR_COUNT
+# error Too many Unix98 ptys defined
+# undef UNIX98_NR_MAJORS
+# define UNIX98_NR_MAJORS UNIX98_PTY_MAJOR_COUNT
+# endif
+#endif
+
+/*
+ * These are set up by the setup-routine at boot-time:
+ */
+
+struct screen_info {
+ unsigned char orig_x; /* 0x00 */
+ unsigned char orig_y; /* 0x01 */
+ unsigned short dontuse1; /* 0x02 -- EXT_MEM_K sits here */
+ unsigned short orig_video_page; /* 0x04 */
+ unsigned char orig_video_mode; /* 0x06 */
+ unsigned char orig_video_cols; /* 0x07 */
+ unsigned short unused2; /* 0x08 */
+ unsigned short orig_video_ega_bx; /* 0x0a */
+ unsigned short unused3; /* 0x0c */
+ unsigned char orig_video_lines; /* 0x0e */
+ unsigned char orig_video_isVGA; /* 0x0f */
+ unsigned short orig_video_points; /* 0x10 */
+
+ /* VESA graphic mode -- linear frame buffer */
+ unsigned short lfb_width; /* 0x12 */
+ unsigned short lfb_height; /* 0x14 */
+ unsigned short lfb_depth; /* 0x16 */
+ unsigned long lfb_base; /* 0x18 */
+ unsigned long lfb_size; /* 0x1c */
+ unsigned short dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
+ unsigned short lfb_linelength; /* 0x24 */
+ unsigned char red_size; /* 0x26 */
+ unsigned char red_pos; /* 0x27 */
+ unsigned char green_size; /* 0x28 */
+ unsigned char green_pos; /* 0x29 */
+ unsigned char blue_size; /* 0x2a */
+ unsigned char blue_pos; /* 0x2b */
+ unsigned char rsvd_size; /* 0x2c */
+ unsigned char rsvd_pos; /* 0x2d */
+ unsigned short vesapm_seg; /* 0x2e */
+ unsigned short vesapm_off; /* 0x30 */
+ unsigned short pages; /* 0x32 */
+ /* 0x34 -- 0x3f reserved for future expansion */
+};
+
+extern struct screen_info screen_info;
+
+#define ORIG_X (screen_info.orig_x)
+#define ORIG_Y (screen_info.orig_y)
+#define ORIG_VIDEO_MODE (screen_info.orig_video_mode)
+#define ORIG_VIDEO_COLS (screen_info.orig_video_cols)
+#define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx)
+#define ORIG_VIDEO_LINES (screen_info.orig_video_lines)
+#define ORIG_VIDEO_ISVGA (screen_info.orig_video_isVGA)
+#define ORIG_VIDEO_POINTS (screen_info.orig_video_points)
+
+#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
+#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
+#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
+#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */
+#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */
+#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */
+
+#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */
+
+#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */
+#define VIDEO_TYPE_SUNPCI 0x51 /* Sun PCI based frame buffer. */
+
+#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */
+
+#define VIDEO_TYPE_SGI 0x70 /* Various SGI graphics hardware */
+#define VIDEO_TYPE_MIPS_G364 0x71 /* MIPS Magnum 4000 G364 video */
+
+/*
+ * This character is the same as _POSIX_VDISABLE: it cannot be used as
+ * a c_cc[] character, but indicates that a particular special character
+ * isn't in use (eg VINTR has no character etc)
+ */
+#define __DISABLED_CHAR '\0'
+
+/*
+ * This is the flip buffer used for the tty driver. The buffer is
+ * located in the tty structure, and is used as a high speed interface
+ * between the tty driver and the tty line discipline.
+ */
+#define TTY_FLIPBUF_SIZE 512
+
+struct tty_flip_buffer {
+ struct tq_struct tqueue;
+ struct semaphore pty_sem;
+ char *char_buf_ptr;
+ unsigned char *flag_buf_ptr;
+ int count;
+ int buf_num;
+ unsigned char char_buf[2*TTY_FLIPBUF_SIZE];
+ char flag_buf[2*TTY_FLIPBUF_SIZE];
+ unsigned char slop[4]; /* N.B. bug overwrites buffer by 1 */
+};
+/*
+ * The pty uses char_buf and flag_buf as a contiguous buffer
+ */
+#define PTY_BUF_SIZE 4*TTY_FLIPBUF_SIZE
+
+/*
+ * When a break, frame error, or parity error happens, these codes are
+ * stuffed into the flags buffer.
+ */
+#define TTY_NORMAL 0
+#define TTY_BREAK 1
+#define TTY_FRAME 2
+#define TTY_PARITY 3
+#define TTY_OVERRUN 4
+
+#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
+#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
+#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
+#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
+#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
+#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME])
+#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN])
+#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC])
+#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
+#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
+#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
+#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
+#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT])
+#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD])
+#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
+#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT])
+#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
+
+#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f))
+#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f))
+#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f))
+#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f))
+
+#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK)
+#define I_BRKINT(tty) _I_FLAG((tty),BRKINT)
+#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR)
+#define I_PARMRK(tty) _I_FLAG((tty),PARMRK)
+#define I_INPCK(tty) _I_FLAG((tty),INPCK)
+#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
+#define I_INLCR(tty) _I_FLAG((tty),INLCR)
+#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
+#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
+#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
+#define I_IXON(tty) _I_FLAG((tty),IXON)
+#define I_IXANY(tty) _I_FLAG((tty),IXANY)
+#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
+#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
+
+#define O_OPOST(tty) _O_FLAG((tty),OPOST)
+#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
+#define O_ONLCR(tty) _O_FLAG((tty),ONLCR)
+#define O_OCRNL(tty) _O_FLAG((tty),OCRNL)
+#define O_ONOCR(tty) _O_FLAG((tty),ONOCR)
+#define O_ONLRET(tty) _O_FLAG((tty),ONLRET)
+#define O_OFILL(tty) _O_FLAG((tty),OFILL)
+#define O_OFDEL(tty) _O_FLAG((tty),OFDEL)
+#define O_NLDLY(tty) _O_FLAG((tty),NLDLY)
+#define O_CRDLY(tty) _O_FLAG((tty),CRDLY)
+#define O_TABDLY(tty) _O_FLAG((tty),TABDLY)
+#define O_BSDLY(tty) _O_FLAG((tty),BSDLY)
+#define O_VTDLY(tty) _O_FLAG((tty),VTDLY)
+#define O_FFDLY(tty) _O_FLAG((tty),FFDLY)
+
+#define C_BAUD(tty) _C_FLAG((tty),CBAUD)
+#define C_CSIZE(tty) _C_FLAG((tty),CSIZE)
+#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB)
+#define C_CREAD(tty) _C_FLAG((tty),CREAD)
+#define C_PARENB(tty) _C_FLAG((tty),PARENB)
+#define C_PARODD(tty) _C_FLAG((tty),PARODD)
+#define C_HUPCL(tty) _C_FLAG((tty),HUPCL)
+#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL)
+#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD)
+#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS)
+
+#define L_ISIG(tty) _L_FLAG((tty),ISIG)
+#define L_ICANON(tty) _L_FLAG((tty),ICANON)
+#define L_XCASE(tty) _L_FLAG((tty),XCASE)
+#define L_ECHO(tty) _L_FLAG((tty),ECHO)
+#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
+#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
+#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
+#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
+#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
+#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
+#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT)
+#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
+#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO)
+#define L_PENDIN(tty) _L_FLAG((tty),PENDIN)
+#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
+
+/*
+ * Where all of the state associated with a tty is kept while the tty
+ * is open. Since the termios state should be kept even if the tty
+ * has been closed --- for things like the baud rate, etc --- it is
+ * not stored here, but rather a pointer to the real state is stored
+ * here. Possible the winsize structure should have the same
+ * treatment, but (1) the default 80x24 is usually right and (2) it's
+ * most often used by a windowing system, which will set the correct
+ * size each time the window is created or resized anyway.
+ * IMPORTANT: since this structure is dynamically allocated, it must
+ * be no larger than 4096 bytes. Changing TTY_FLIPBUF_SIZE will change
+ * the size of this structure, and it needs to be done with care.
+ * - TYT, 9/14/92
+ */
+struct tty_struct {
+ int magic;
+ struct tty_driver driver;
+ struct tty_ldisc ldisc;
+ struct termios *termios, *termios_locked;
+ int pgrp;
+ int session;
+ kdev_t device;
+ unsigned long flags;
+ int count;
+ struct winsize winsize;
+ unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
+ unsigned char low_latency:1, warned:1;
+ unsigned char ctrl_status;
+
+ struct tty_struct *link;
+ struct fasync_struct *fasync;
+ struct tty_flip_buffer flip;
+ int max_flip_cnt;
+ int alt_speed; /* For magic substitution of 38400 bps */
+ struct wait_queue *write_wait;
+ struct wait_queue *read_wait;
+ struct tq_struct tq_hangup;
+ void *disc_data;
+ void *driver_data;
+
+#define N_TTY_BUF_SIZE 4096
+
+ /*
+ * The following is data for the N_TTY line discipline. For
+ * historical reasons, this is included in the tty structure.
+ */
+ unsigned int column;
+ unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+ unsigned char closing:1;
+ unsigned short minimum_to_wake;
+ unsigned overrun_time;
+ int num_overrun;
+ unsigned long process_char_map[256/(8*sizeof(unsigned long))];
+ char *read_buf;
+ int read_head;
+ int read_tail;
+ int read_cnt;
+ unsigned long read_flags[N_TTY_BUF_SIZE/(8*sizeof(unsigned long))];
+ int canon_data;
+ unsigned long canon_head;
+ unsigned int canon_column;
+ struct semaphore atomic_read;
+ struct semaphore atomic_write;
+};
+
+/* tty magic number */
+#define TTY_MAGIC 0x5401
+
+/*
+ * These bits are used in the flags field of the tty structure.
+ *
+ * So that interrupts won't be able to mess up the queues,
+ * copy_to_cooked must be atomic with respect to itself, as must
+ * tty->write. Thus, you must use the inline functions set_bit() and
+ * clear_bit() to make things atomic.
+ */
+#define TTY_THROTTLED 0
+#define TTY_IO_ERROR 1
+#define TTY_OTHER_CLOSED 2
+#define TTY_EXCLUSIVE 3
+#define TTY_DEBUG 4
+#define TTY_DO_WRITE_WAKEUP 5
+#define TTY_PUSH 6
+#define TTY_CLOSING 7
+#define TTY_DONT_FLIP 8
+#define TTY_HW_COOK_OUT 14
+#define TTY_HW_COOK_IN 15
+#define TTY_PTY_LOCK 16
+#define TTY_NO_WRITE_SPLIT 17
+
+#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
+
+extern void tty_write_flush(struct tty_struct *);
+
+extern struct termios tty_std_termios;
+extern struct tty_struct * redirect;
+extern struct tty_ldisc ldiscs[];
+extern int fg_console, last_console, want_console;
+
+extern int kmsg_redirect;
+
+extern unsigned long con_init(unsigned long);
+
+extern int rs_init(void);
+extern int lp_init(void);
+extern int pty_init(void);
+extern int tty_init(void);
+extern int mxser_init(void);
+extern int moxa_init(void);
+extern int ip2_init(void);
+extern int pcxe_init(void);
+extern int pc_init(void);
+extern int vcs_init(void);
+extern int rp_init(void);
+extern int cy_init(void);
+extern int stl_init(void);
+extern int stli_init(void);
+extern int riscom8_init(void);
+extern int specialix_init(void);
+extern int espserial_init(void);
+extern int macserial_init(void);
+
+extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
+ const char *routine);
+extern char *tty_name(struct tty_struct *tty, char *buf);
+extern void tty_wait_until_sent(struct tty_struct * tty, long timeout);
+extern int tty_check_change(struct tty_struct * tty);
+extern void stop_tty(struct tty_struct * tty);
+extern void start_tty(struct tty_struct * tty);
+extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
+extern int tty_register_driver(struct tty_driver *driver);
+extern int tty_unregister_driver(struct tty_driver *driver);
+extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
+ int buflen);
+extern void tty_write_message(struct tty_struct *tty, char *msg);
+
+extern int is_orphaned_pgrp(int pgrp);
+extern int is_ignored(int sig);
+extern int tty_signal(int sig, struct tty_struct *tty);
+extern void tty_hangup(struct tty_struct * tty);
+extern void tty_vhangup(struct tty_struct * tty);
+extern void tty_unhangup(struct file *filp);
+extern int tty_hung_up_p(struct file * filp);
+extern void do_SAK(struct tty_struct *tty);
+extern void disassociate_ctty(int priv);
+extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern int tty_get_baud_rate(struct tty_struct *tty);
+
+/* n_tty.c */
+extern struct tty_ldisc tty_ldisc_N_TTY;
+
+/* tty_ioctl.c */
+extern int n_tty_ioctl(struct tty_struct * tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+
+/* serial.c */
+
+extern long serial_console_init(long kmem_start, long kmem_end);
+
+/* pcxx.c */
+
+extern int pcxe_open(struct tty_struct *tty, struct file *filp);
+
+/* printk.c */
+
+extern void console_print(const char *);
+
+/* vt.c */
+
+extern int vt_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/pfinet/linux-src/include/linux/tty_driver.h b/pfinet/linux-src/include/linux/tty_driver.h
new file mode 100644
index 00000000..46ace283
--- /dev/null
+++ b/pfinet/linux-src/include/linux/tty_driver.h
@@ -0,0 +1,227 @@
+#ifndef _LINUX_TTY_DRIVER_H
+#define _LINUX_TTY_DRIVER_H
+
+/*
+ * This structure defines the interface between the low-level tty
+ * driver and the tty routines. The following routines can be
+ * defined; unless noted otherwise, they are optional, and can be
+ * filled in with a null pointer.
+ *
+ * int (*open)(struct tty_struct * tty, struct file * filp);
+ *
+ * This routine is called when a particular tty device is opened.
+ * This routine is mandatory; if this routine is not filled in,
+ * the attempted open will fail with ENODEV.
+ *
+ * void (*close)(struct tty_struct * tty, struct file * filp);
+ *
+ * This routine is called when a particular tty device is closed.
+ *
+ * int (*write)(struct tty_struct * tty, int from_user,
+ * const unsigned char *buf, int count);
+ *
+ * This routine is called by the kernel to write a series of
+ * characters to the tty device. The characters may come from
+ * user space or kernel space. This routine will return the
+ * number of characters actually accepted for writing. This
+ * routine is mandatory.
+ *
+ * void (*put_char)(struct tty_struct *tty, unsigned char ch);
+ *
+ * This routine is called by the kernel to write a single
+ * character to the tty device. If the kernel uses this routine,
+ * it must call the flush_chars() routine (if defined) when it is
+ * done stuffing characters into the driver. If there is no room
+ * in the queue, the character is ignored.
+ *
+ * void (*flush_chars)(struct tty_struct *tty);
+ *
+ * This routine is called by the kernel after it has written a
+ * series of characters to the tty device using put_char().
+ *
+ * int (*write_room)(struct tty_struct *tty);
+ *
+ * This routine returns the numbers of characters the tty driver
+ * will accept for queuing to be written. This number is subject
+ * to change as output buffers get emptied, or if the output flow
+ * control is acted.
+ *
+ * int (*ioctl)(struct tty_struct *tty, struct file * file,
+ * unsigned int cmd, unsigned long arg);
+ *
+ * This routine allows the tty driver to implement
+ * device-specific ioctl's. If the ioctl number passed in cmd
+ * is not recognized by the driver, it should return ENOIOCTLCMD.
+ *
+ * void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ *
+ * This routine allows the tty driver to be notified when
+ * device's termios settings have changed. Note that a
+ * well-designed tty driver should be prepared to accept the case
+ * where old == NULL, and try to do something rational.
+ *
+ * void (*set_ldisc)(struct tty_struct *tty);
+ *
+ * This routine allows the tty driver to be notified when the
+ * device's termios settings have changed.
+ *
+ * void (*throttle)(struct tty_struct * tty);
+ *
+ * This routine notifies the tty driver that input buffers for
+ * the line discipline are close to full, and it should somehow
+ * signal that no more characters should be sent to the tty.
+ *
+ * void (*unthrottle)(struct tty_struct * tty);
+ *
+ * This routine notifies the tty drivers that it should signals
+ * that characters can now be sent to the tty without fear of
+ * overrunning the input buffers of the line disciplines.
+ *
+ * void (*stop)(struct tty_struct *tty);
+ *
+ * This routine notifies the tty driver that it should stop
+ * outputting characters to the tty device.
+ *
+ * void (*start)(struct tty_struct *tty);
+ *
+ * This routine notifies the tty driver that it resume sending
+ * characters to the tty device.
+ *
+ * void (*hangup)(struct tty_struct *tty);
+ *
+ * This routine notifies the tty driver that it should hangup the
+ * tty device.
+ *
+ * void (*break_ctl)(struct tty_stuct *tty, int state);
+ *
+ * This optional routine requests the tty driver to turn on or
+ * off BREAK status on the RS-232 port. If state is -1,
+ * then the BREAK status should be turned on; if state is 0, then
+ * BREAK should be turned off.
+ *
+ * If this routine is implemented, the high-level tty driver will
+ * handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK,
+ * TIOCCBRK. Otherwise, these ioctls will be passed down to the
+ * driver to handle.
+ *
+ * void (*wait_until_sent)(struct tty_struct *tty, int timeout);
+ *
+ * This routine waits until the device has written out all of the
+ * characters in its transmitter FIFO.
+ *
+ * void (*send_xchar)(struct tty_struct *tty, char ch);
+ *
+ * This routine is used to send a high-priority XON/XOFF
+ * character to the device.
+ */
+
+#include <linux/fs.h>
+
+struct tty_driver {
+ int magic; /* magic number for this structure */
+ const char *driver_name;
+ const char *name;
+ int name_base; /* offset of printed name */
+ short major; /* major device number */
+ short minor_start; /* start of minor device number*/
+ short num; /* number of devices */
+ short type; /* type of tty driver */
+ short subtype; /* subtype of tty driver */
+ struct termios init_termios; /* Initial termios */
+ int flags; /* tty driver flags */
+ int *refcount; /* for loadable tty drivers */
+ struct proc_dir_entry *proc_entry; /* /proc fs entry */
+ struct tty_driver *other; /* only used for the PTY driver */
+
+ /*
+ * Pointer to the tty data structures
+ */
+ struct tty_struct **table;
+ struct termios **termios;
+ struct termios **termios_locked;
+ void *driver_state; /* only used for the PTY driver */
+
+ /*
+ * Interface routines from the upper tty layer to the tty
+ * driver.
+ */
+ int (*open)(struct tty_struct * tty, struct file * filp);
+ void (*close)(struct tty_struct * tty, struct file * filp);
+ int (*write)(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count);
+ void (*put_char)(struct tty_struct *tty, unsigned char ch);
+ void (*flush_chars)(struct tty_struct *tty);
+ int (*write_room)(struct tty_struct *tty);
+ int (*chars_in_buffer)(struct tty_struct *tty);
+ int (*ioctl)(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+ void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ void (*throttle)(struct tty_struct * tty);
+ void (*unthrottle)(struct tty_struct * tty);
+ void (*stop)(struct tty_struct *tty);
+ void (*start)(struct tty_struct *tty);
+ void (*hangup)(struct tty_struct *tty);
+ void (*break_ctl)(struct tty_struct *tty, int state);
+ void (*flush_buffer)(struct tty_struct *tty);
+ void (*set_ldisc)(struct tty_struct *tty);
+ void (*wait_until_sent)(struct tty_struct *tty, int timeout);
+ void (*send_xchar)(struct tty_struct *tty, char ch);
+ int (*read_proc)(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+ int (*write_proc)(struct file *file, const char *buffer,
+ unsigned long count, void *data);
+
+ /*
+ * linked list pointers
+ */
+ struct tty_driver *next;
+ struct tty_driver *prev;
+};
+
+/* tty driver magic number */
+#define TTY_DRIVER_MAGIC 0x5402
+
+/*
+ * tty driver flags
+ *
+ * TTY_DRIVER_RESET_TERMIOS --- requests the tty layer to reset the
+ * termios setting when the last process has closed the device.
+ * Used for PTY's, in particular.
+ *
+ * TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will
+ * guarantee never not to set any special character handling
+ * flags if ((IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR ||
+ * !INPCK)). That is, if there is no reason for the driver to
+ * send notifications of parity and break characters up to the
+ * line driver, it won't do so. This allows the line driver to
+ * optimize for this case if this flag is set. (Note that there
+ * is also a promise, if the above case is true, not to signal
+ * overruns, either.)
+ */
+#define TTY_DRIVER_INSTALLED 0x0001
+#define TTY_DRIVER_RESET_TERMIOS 0x0002
+#define TTY_DRIVER_REAL_RAW 0x0004
+
+/* tty driver types */
+#define TTY_DRIVER_TYPE_SYSTEM 0x0001
+#define TTY_DRIVER_TYPE_CONSOLE 0x0002
+#define TTY_DRIVER_TYPE_SERIAL 0x0003
+#define TTY_DRIVER_TYPE_PTY 0x0004
+#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */
+#define TTY_DRIVER_TYPE_SYSCONS 0x0006
+
+/* system subtypes (magic, used by tty_io.c) */
+#define SYSTEM_TYPE_TTY 0x0001
+#define SYSTEM_TYPE_CONSOLE 0x0002
+#define SYSTEM_TYPE_SYSCONS 0x0003
+#define SYSTEM_TYPE_SYSPTMX 0x0004
+
+/* pty subtypes (magic, used by tty_io.c) */
+#define PTY_TYPE_MASTER 0x0001
+#define PTY_TYPE_SLAVE 0x0002
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+
+#endif /* #ifdef _LINUX_TTY_DRIVER_H */
diff --git a/pfinet/linux-src/include/linux/tty_flip.h b/pfinet/linux-src/include/linux/tty_flip.h
new file mode 100644
index 00000000..948e5455
--- /dev/null
+++ b/pfinet/linux-src/include/linux/tty_flip.h
@@ -0,0 +1,35 @@
+#ifndef _LINUX_TTY_FLIP_H
+#define _LINUX_TTY_FLIP_H
+
+#ifdef INCLUDE_INLINE_FUNCS
+#define _INLINE_ extern
+#else
+#define _INLINE_ extern __inline__
+#endif
+
+_INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
+ unsigned char ch, char flag)
+{
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = flag;
+ *tty->flip.char_buf_ptr++ = ch;
+ }
+}
+
+_INLINE_ void tty_schedule_flip(struct tty_struct *tty)
+{
+ queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+#undef _INLINE_
+
+
+#endif /* _LINUX_TTY_FLIP_H */
+
+
+
+
+
+
+
diff --git a/pfinet/linux-src/include/linux/tty_ldisc.h b/pfinet/linux-src/include/linux/tty_ldisc.h
new file mode 100644
index 00000000..4e904f83
--- /dev/null
+++ b/pfinet/linux-src/include/linux/tty_ldisc.h
@@ -0,0 +1,138 @@
+#ifndef _LINUX_TTY_LDISC_H
+#define _LINUX_TTY_LDISC_H
+
+/*
+ * This structure defines the interface between the tty line discpline
+ * implementation and the tty routines. The following routines can be
+ * defined; unless noted otherwise, they are optional, and can be
+ * filled in with a null pointer.
+ *
+ * int (*open)(struct tty_struct *);
+ *
+ * This function is called when the line discpline is associated
+ * with the tty. The line discpline can use this as an
+ * opportunity to initialize any state needed by the ldisc routines.
+ *
+ * void (*close)(struct tty_struct *);
+ *
+ * This function is called when the line discpline is being
+ * shutdown, either because the tty is being closed or because
+ * the tty is being changed to use a new line discpline
+ *
+ * void (*flush_buffer)(struct tty_struct *tty);
+ *
+ * This function instructs the line discipline to clear its
+ * buffers of any input characters it may have queued to be
+ * delivered to the user mode process.
+ *
+ * ssize_t (*chars_in_buffer)(struct tty_struct *tty);
+ *
+ * This function returns the number of input characters the line
+ * iscpline may have queued up to be delivered to the user mode
+ * process.
+ *
+ * ssize_t (*read)(struct tty_struct * tty, struct file * file,
+ * unsigned char * buf, size_t nr);
+ *
+ * This function is called when the user requests to read from
+ * the tty. The line discpline will return whatever characters
+ * it has buffered up for the user. If this function is not
+ * defined, the user will receive an EIO error.
+ *
+ * ssize_t (*write)(struct tty_struct * tty, struct file * file,
+ * const unsigned char * buf, size_t nr);
+ *
+ * This function is called when the user requests to write to the
+ * tty. The line discpline will deliver the characters to the
+ * low-level tty device for transmission, optionally performing
+ * some processing on the characters first. If this function is
+ * not defined, the user will receive an EIO error.
+ *
+ * int (*ioctl)(struct tty_struct * tty, struct file * file,
+ * unsigned int cmd, unsigned long arg);
+ *
+ * This function is called when the user requests an ioctl which
+ * is not handled by the tty layer or the low-level tty driver.
+ * It is intended for ioctls which affect line discpline
+ * operation. Not that the search order for ioctls is (1) tty
+ * layer, (2) tty low-level driver, (3) line discpline. So a
+ * low-level driver can "grab" an ioctl request before the line
+ * discpline has a chance to see it.
+ *
+ * void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ *
+ * This function notifies the line discpline that a change has
+ * been made to the termios structure.
+ *
+ * int (*poll)(struct tty_struct * tty, struct file * file,
+ * poll_table *wait);
+ *
+ * This function is called when a user attempts to select/poll on a
+ * tty device. It is solely the responsibility of the line
+ * discipline to handle poll requests.
+ *
+ * void (*receive_buf)(struct tty_struct *, const unsigned char *cp,
+ * char *fp, int count);
+ *
+ * This function is called by the low-level tty driver to send
+ * characters received by the hardware to the line discpline for
+ * processing. <cp> is a pointer to the buffer of input
+ * character received by the device. <fp> is a pointer to a
+ * pointer of flag bytes which indicate whether a character was
+ * received with a parity error, etc.
+ *
+ * int (*receive_room)(struct tty_struct *);
+ *
+ * This function is called by the low-level tty driver to
+ * determine how many characters the line discpline can accept.
+ * The low-level driver must not send more characters than was
+ * indicated by receive_room, or the line discpline may drop
+ * those characters.
+ *
+ * void (*write_wakeup)(struct tty_struct *);
+ *
+ * This function is called by the low-level tty driver to signal
+ * that line discpline should try to send more characters to the
+ * low-level driver for transmission. If the line discpline does
+ * not have any more data to send, it can just return.
+ */
+
+#include <linux/fs.h>
+#include <linux/wait.h>
+
+struct tty_ldisc {
+ int magic;
+ char *name;
+ int num;
+ int flags;
+ /*
+ * The following routines are called from above.
+ */
+ int (*open)(struct tty_struct *);
+ void (*close)(struct tty_struct *);
+ void (*flush_buffer)(struct tty_struct *tty);
+ ssize_t (*chars_in_buffer)(struct tty_struct *tty);
+ ssize_t (*read)(struct tty_struct * tty, struct file * file,
+ unsigned char * buf, size_t nr);
+ ssize_t (*write)(struct tty_struct * tty, struct file * file,
+ const unsigned char * buf, size_t nr);
+ int (*ioctl)(struct tty_struct * tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
+ void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ unsigned int (*poll)(struct tty_struct *, struct file *,
+ struct poll_table_struct *);
+
+ /*
+ * The following routines are called from below.
+ */
+ void (*receive_buf)(struct tty_struct *, const unsigned char *cp,
+ char *fp, int count);
+ int (*receive_room)(struct tty_struct *);
+ void (*write_wakeup)(struct tty_struct *);
+};
+
+#define TTY_LDISC_MAGIC 0x5403
+
+#define LDISC_FLAG_DEFINED 0x00000001
+
+#endif /* _LINUX_TTY_LDISC_H */
diff --git a/pfinet/linux-src/include/linux/types.h b/pfinet/linux-src/include/linux/types.h
new file mode 100644
index 00000000..a53a4ccc
--- /dev/null
+++ b/pfinet/linux-src/include/linux/types.h
@@ -0,0 +1,108 @@
+#ifndef _LINUX_TYPES_H
+#define _LINUX_TYPES_H
+
+#include <linux/posix_types.h>
+#include <asm/types.h>
+
+#ifndef __KERNEL_STRICT_NAMES
+
+typedef __kernel_fd_set fd_set;
+typedef __kernel_dev_t dev_t;
+typedef __kernel_ino_t ino_t;
+typedef __kernel_mode_t mode_t;
+typedef __kernel_nlink_t nlink_t;
+typedef __kernel_off_t off_t;
+typedef __kernel_pid_t pid_t;
+typedef __kernel_uid_t uid_t;
+typedef __kernel_gid_t gid_t;
+typedef __kernel_daddr_t daddr_t;
+typedef __kernel_key_t key_t;
+typedef __kernel_suseconds_t suseconds_t;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __kernel_loff_t loff_t;
+#endif
+
+/*
+ * The following typedefs are also protected by individual ifdefs for
+ * historical reasons:
+ */
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __kernel_size_t size_t;
+#endif
+
+#ifndef _SSIZE_T
+#define _SSIZE_T
+typedef __kernel_ssize_t ssize_t;
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef __kernel_ptrdiff_t ptrdiff_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef __kernel_time_t time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef __kernel_clock_t clock_t;
+#endif
+
+#ifndef _CADDR_T
+#define _CADDR_T
+typedef __kernel_caddr_t caddr_t;
+#endif
+
+/* bsd */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* sysv */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef __u8 u_int8_t;
+typedef __s8 int8_t;
+typedef __u16 u_int16_t;
+typedef __s16 int16_t;
+typedef __u32 u_int32_t;
+typedef __s32 int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+typedef __u8 uint8_t;
+typedef __u16 uint16_t;
+typedef __u32 uint32_t;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __u64 uint64_t;
+typedef __u64 u_int64_t;
+typedef __s64 int64_t;
+#endif
+
+#endif /* __KERNEL_STRICT_NAMES */
+
+/*
+ * Below are truly Linux-specific types that should never collide with
+ * any application/library that wants linux/types.h.
+ */
+
+struct ustat {
+ __kernel_daddr_t f_tfree;
+ __kernel_ino_t f_tinode;
+ char f_fname[6];
+ char f_fpack[6];
+};
+
+#endif /* _LINUX_TYPES_H */
diff --git a/pfinet/linux/udp.h b/pfinet/linux-src/include/linux/udp.h
index 471301a2..ab75a1e8 100644
--- a/pfinet/linux/udp.h
+++ b/pfinet/linux-src/include/linux/udp.h
@@ -19,10 +19,10 @@
struct udphdr {
- unsigned short source;
- unsigned short dest;
- unsigned short len;
- unsigned short check;
+ __u16 source;
+ __u16 dest;
+ __u16 len;
+ __u16 check;
};
diff --git a/pfinet/linux-src/include/linux/ufs_fs.h b/pfinet/linux-src/include/linux/ufs_fs.h
new file mode 100644
index 00000000..38604163
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ufs_fs.h
@@ -0,0 +1,571 @@
+/*
+ * linux/include/linux/ufs_fs.h
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * Clean swab support by Fare <fare@tunes.org>
+ * just hope no one is using NNUUXXI on __?64 structure elements
+ * 64-bit clean thanks to Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
+ *
+ * Write support by Daniel Pirkl <daniel.pirkl@email.cz>
+ */
+
+#ifndef __LINUX_UFS_FS_H
+#define __LINUX_UFS_FS_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/stat.h>
+
+#define UFS_BBLOCK 0
+#define UFS_BBSIZE 8192
+#define UFS_SBLOCK 8192
+#define UFS_SBSIZE 8192
+
+#define UFS_SECTOR_SIZE 512
+#define UFS_SECTOR_BITS 9
+#define UFS_MAGIC 0x00011954
+#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */
+
+#define UFS_BSIZE 8192
+#define UFS_MINBSIZE 4096
+#define UFS_FSIZE 1024
+#define UFS_MAXFRAG (UFS_BSIZE / UFS_FSIZE)
+
+#define UFS_NDADDR 12
+#define UFS_NINDIR 3
+
+#define UFS_IND_BLOCK (UFS_NDADDR + 0)
+#define UFS_DIND_BLOCK (UFS_NDADDR + 1)
+#define UFS_TIND_BLOCK (UFS_NDADDR + 2)
+
+#define UFS_NDIR_FRAGMENT (UFS_NDADDR << uspi->s_fpbshift)
+#define UFS_IND_FRAGMENT (UFS_IND_BLOCK << uspi->s_fpbshift)
+#define UFS_DIND_FRAGMENT (UFS_DIND_BLOCK << uspi->s_fpbshift)
+#define UFS_TIND_FRAGMENT (UFS_TIND_BLOCK << uspi->s_fpbshift)
+
+#define UFS_ROOTINO 2
+#define UFS_FIRST_INO (UFS_ROOTINO + 1)
+
+#define UFS_USEEFT ((__u16)65535)
+
+#define UFS_FSOK 0x7c269d38
+#define UFS_FSACTIVE ((char)0x00)
+#define UFS_FSCLEAN ((char)0x01)
+#define UFS_FSSTABLE ((char)0x02)
+#define UFS_FSOSF1 ((char)0x03) /* is this correct for DEC OSF/1? */
+#define UFS_FSBAD ((char)0xff)
+
+/* From here to next blank line, s_flags for ufs_sb_info */
+/* endianness */
+#define UFS_BYTESEX 0x00000001 /* mask; leave room to 0xF */
+#if defined(__LITTLE_ENDIAN) || defined(__BIG_ENDIAN)
+/* these are for sane architectures */
+#define UFS_NATIVE_ENDIAN 0x00000000
+#define UFS_SWABBED_ENDIAN 0x00000001
+#else
+/* these are for pervert architectures */
+#define UFS_LITTLE_ENDIAN 0x00000000
+#define UFS_BIG_ENDIAN 0x00000001
+#endif
+/* directory entry encoding */
+#define UFS_DE_MASK 0x00000010 /* mask for the following */
+#define UFS_DE_OLD 0x00000000
+#define UFS_DE_44BSD 0x00000010
+/* uid encoding */
+#define UFS_UID_MASK 0x00000060 /* mask for the following */
+#define UFS_UID_OLD 0x00000000
+#define UFS_UID_44BSD 0x00000020
+#define UFS_UID_EFT 0x00000040
+/* superblock state encoding */
+#define UFS_ST_MASK 0x00000700 /* mask for the following */
+#define UFS_ST_OLD 0x00000000
+#define UFS_ST_44BSD 0x00000100
+#define UFS_ST_SUN 0x00000200
+#define UFS_ST_SUNx86 0x00000400
+/*cylinder group encoding */
+#define UFS_CG_MASK 0x00003000 /* mask for the following */
+#define UFS_CG_OLD 0x00000000
+#define UFS_CG_44BSD 0x00002000
+#define UFS_CG_SUN 0x00001000
+
+/* fs_inodefmt options */
+#define UFS_42INODEFMT -1
+#define UFS_44INODEFMT 2
+
+/* mount options */
+#define UFS_MOUNT_ONERROR 0x0000000F
+#define UFS_MOUNT_ONERROR_PANIC 0x00000001
+#define UFS_MOUNT_ONERROR_LOCK 0x00000002
+#define UFS_MOUNT_ONERROR_UMOUNT 0x00000004
+#define UFS_MOUNT_ONERROR_REPAIR 0x00000008
+
+#define UFS_MOUNT_UFSTYPE 0x000007F0
+#define UFS_MOUNT_UFSTYPE_OLD 0x00000010
+#define UFS_MOUNT_UFSTYPE_44BSD 0x00000020
+#define UFS_MOUNT_UFSTYPE_SUN 0x00000040
+#define UFS_MOUNT_UFSTYPE_NEXTSTEP 0x00000080
+#define UFS_MOUNT_UFSTYPE_NEXTSTEP_CD 0x00000100
+#define UFS_MOUNT_UFSTYPE_OPENSTEP 0x00000200
+#define UFS_MOUNT_UFSTYPE_SUNx86 0x00000400
+
+#define ufs_clear_opt(o,opt) o &= ~UFS_MOUNT_##opt
+#define ufs_set_opt(o,opt) o |= UFS_MOUNT_##opt
+#define ufs_test_opt(o,opt) ((o) & UFS_MOUNT_##opt)
+
+/*
+ * MINFREE gives the minimum acceptable percentage of file system
+ * blocks which may be free. If the freelist drops below this level
+ * only the superuser may continue to allocate blocks. This may
+ * be set to 0 if no reserve of free blocks is deemed necessary,
+ * however throughput drops by fifty percent if the file system
+ * is run at between 95% and 100% full; thus the minimum default
+ * value of fs_minfree is 5%. However, to get good clustering
+ * performance, 10% is a better choice. hence we use 10% as our
+ * default value. With 10% free space, fragmentation is not a
+ * problem, so we choose to optimize for time.
+ */
+#define UFS_MINFREE 5
+#define UFS_DEFAULTOPT UFS_OPTTIME
+
+/*
+ * Turn file system block numbers into disk block addresses.
+ * This maps file system blocks to device size blocks.
+ */
+#define ufs_fsbtodb(uspi, b) ((b) << (uspi)->s_fsbtodb)
+#define ufs_dbtofsb(uspi, b) ((b) >> (uspi)->s_fsbtodb)
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc file system addresses of cylinder group data structures.
+ */
+#define ufs_cgbase(c) (uspi->s_fpg * (c))
+#define ufs_cgstart(c) (ufs_cgbase(c) + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask))
+#define ufs_cgsblock(c) (ufs_cgstart(c) + uspi->s_sblkno) /* super blk */
+#define ufs_cgcmin(c) (ufs_cgstart(c) + uspi->s_cblkno) /* cg block */
+#define ufs_cgimin(c) (ufs_cgstart(c) + uspi->s_iblkno) /* inode blk */
+#define ufs_cgdmin(c) (ufs_cgstart(c) + uspi->s_dblkno) /* 1st data */
+
+/*
+ * Macros for handling inode numbers:
+ * inode number to file system block offset.
+ * inode number to cylinder group number.
+ * inode number to file system block address.
+ */
+#define ufs_inotocg(x) ((x) / uspi->s_ipg)
+#define ufs_inotocgoff(x) ((x) % uspi->s_ipg)
+#define ufs_inotofsba(x) (ufs_cgimin(ufs_inotocg(x)) + ufs_inotocgoff(x) / uspi->s_inopf)
+#define ufs_inotofsbo(x) ((x) % uspi->s_inopf)
+
+/*
+ * Give cylinder group number for a file system block.
+ * Give cylinder group block number for a file system block.
+ */
+#define ufs_dtog(d) ((d) / uspi->s_fpg)
+#define ufs_dtogd(d) ((d) % uspi->s_fpg)
+
+/*
+ * Compute the cylinder and rotational position of a cyl block addr.
+ */
+#define ufs_cbtocylno(bno) \
+ ((bno) * uspi->s_nspf / uspi->s_spc)
+#define ufs_cbtorpos(bno) \
+ ((((bno) * uspi->s_nspf % uspi->s_spc / uspi->s_nsect \
+ * uspi->s_trackskew + (bno) * uspi->s_nspf % uspi->s_spc \
+ % uspi->s_nsect * uspi->s_interleave) % uspi->s_nsect \
+ * uspi->s_nrpos) / uspi->s_npsect)
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define ufs_blkoff(loc) ((loc) & uspi->s_qbmask)
+#define ufs_fragoff(loc) ((loc) & uspi->s_qfmask)
+#define ufs_lblktosize(blk) ((blk) << uspi->s_bshift)
+#define ufs_lblkno(loc) ((loc) >> uspi->s_bshift)
+#define ufs_numfrags(loc) ((loc) >> uspi->s_fshift)
+#define ufs_blkroundup(size) (((size) + uspi->s_qbmask) & uspi->s_bmask)
+#define ufs_fragroundup(size) (((size) + uspi->s_qfmask) & uspi->s_fmask)
+#define ufs_fragstoblks(frags) ((frags) >> uspi->s_fpbshift)
+#define ufs_blkstofrags(blks) ((blks) << uspi->s_fpbshift)
+#define ufs_fragnum(fsb) ((fsb) & uspi->s_fpbmask)
+#define ufs_blknum(fsb) ((fsb) & ~uspi->s_fpbmask)
+
+#define UFS_MAXNAMLEN 255
+#define UFS_MAXMNTLEN 512
+#define UFS_MAXCSBUFS 31
+#define UFS_LINK_MAX 32000
+
+/*
+ * UFS_DIR_PAD defines the directory entries boundaries
+ * (must be a multiple of 4)
+ */
+#define UFS_DIR_PAD 4
+#define UFS_DIR_ROUND (UFS_DIR_PAD - 1)
+#define UFS_DIR_REC_LEN(name_len) (((name_len) + 1 + 8 + UFS_DIR_ROUND) & ~UFS_DIR_ROUND)
+
+struct ufs_timeval {
+ __s32 tv_sec;
+ __s32 tv_usec;
+};
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+struct ufs_dir_entry {
+ __u32 d_ino; /* inode number of this entry */
+ __u16 d_reclen; /* length of this entry */
+ union {
+ __u16 d_namlen; /* actual length of d_name */
+ struct {
+ __u8 d_type; /* file type */
+ __u8 d_namlen; /* length of string in d_name */
+ } d_44;
+ } d_u;
+ __u8 d_name[UFS_MAXNAMLEN + 1]; /* file name */
+};
+
+struct ufs_csum {
+ __u32 cs_ndir; /* number of directories */
+ __u32 cs_nbfree; /* number of free blocks */
+ __u32 cs_nifree; /* number of free inodes */
+ __u32 cs_nffree; /* number of free frags */
+};
+
+/*
+ * This is the actual superblock, as it is laid out on the disk.
+ */
+struct ufs_super_block {
+ __u32 fs_link; /* UNUSED */
+ __u32 fs_rlink; /* UNUSED */
+ __u32 fs_sblkno; /* addr of super-block in filesys */
+ __u32 fs_cblkno; /* offset of cyl-block in filesys */
+ __u32 fs_iblkno; /* offset of inode-blocks in filesys */
+ __u32 fs_dblkno; /* offset of first data after cg */
+ __u32 fs_cgoffset; /* cylinder group offset in cylinder */
+ __u32 fs_cgmask; /* used to calc mod fs_ntrak */
+ __u32 fs_time; /* last time written -- time_t */
+ __u32 fs_size; /* number of blocks in fs */
+ __u32 fs_dsize; /* number of data blocks in fs */
+ __u32 fs_ncg; /* number of cylinder groups */
+ __u32 fs_bsize; /* size of basic blocks in fs */
+ __u32 fs_fsize; /* size of frag blocks in fs */
+ __u32 fs_frag; /* number of frags in a block in fs */
+/* these are configuration parameters */
+ __u32 fs_minfree; /* minimum percentage of free blocks */
+ __u32 fs_rotdelay; /* num of ms for optimal next block */
+ __u32 fs_rps; /* disk revolutions per second */
+/* these fields can be computed from the others */
+ __u32 fs_bmask; /* ``blkoff'' calc of blk offsets */
+ __u32 fs_fmask; /* ``fragoff'' calc of frag offsets */
+ __u32 fs_bshift; /* ``lblkno'' calc of logical blkno */
+ __u32 fs_fshift; /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+ __u32 fs_maxcontig; /* max number of contiguous blks */
+ __u32 fs_maxbpg; /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+ __u32 fs_fragshift; /* block to frag shift */
+ __u32 fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ __u32 fs_sbsize; /* actual size of super block */
+ __u32 fs_csmask; /* csum block offset */
+ __u32 fs_csshift; /* csum block number */
+ __u32 fs_nindir; /* value of NINDIR */
+ __u32 fs_inopb; /* value of INOPB */
+ __u32 fs_nspf; /* value of NSPF */
+/* yet another configuration parameter */
+ __u32 fs_optim; /* optimization preference, see below */
+/* these fields are derived from the hardware */
+ union {
+ struct {
+ __u32 fs_npsect; /* # sectors/track including spares */
+ } fs_sun;
+ struct {
+ __s32 fs_state; /* file system state time stamp */
+ } fs_sunx86;
+ } fs_u1;
+ __u32 fs_interleave; /* hardware sector interleave */
+ __u32 fs_trackskew; /* sector 0 skew, per track */
+/* a unique id for this filesystem (currently unused and unmaintained) */
+/* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */
+/* Neither of those fields is used in the Tahoe code right now but */
+/* there could be problems if they are. */
+ __u32 fs_id[2]; /* file system id */
+/* sizes determined by number of cylinder groups and their sizes */
+ __u32 fs_csaddr; /* blk addr of cyl grp summary area */
+ __u32 fs_cssize; /* size of cyl grp summary area */
+ __u32 fs_cgsize; /* cylinder group size */
+/* these fields are derived from the hardware */
+ __u32 fs_ntrak; /* tracks per cylinder */
+ __u32 fs_nsect; /* sectors per track */
+ __u32 fs_spc; /* sectors per cylinder */
+/* this comes from the disk driver partitioning */
+ __u32 fs_ncyl; /* cylinders in file system */
+/* these fields can be computed from the others */
+ __u32 fs_cpg; /* cylinders per group */
+ __u32 fs_ipg; /* inodes per group */
+ __u32 fs_fpg; /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+ struct ufs_csum fs_cstotal; /* cylinder summary information */
+/* these fields are cleared at mount time */
+ __s8 fs_fmod; /* super block modified flag */
+ __s8 fs_clean; /* file system is clean flag */
+ __s8 fs_ronly; /* mounted read-only flag */
+ __s8 fs_flags; /* currently unused flag */
+ __s8 fs_fsmnt[UFS_MAXMNTLEN]; /* name mounted on */
+/* these fields retain the current block allocation info */
+ __u32 fs_cgrotor; /* last cg searched */
+ __u32 fs_csp[UFS_MAXCSBUFS]; /* list of fs_cs info buffers */
+ __u32 fs_maxcluster;
+ __u32 fs_cpc; /* cyl per cycle in postbl */
+ __u16 fs_opostbl[16][8]; /* old rotation block list head */
+ union {
+ struct {
+ __s32 fs_sparecon[53];/* reserved for future constants */
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __s32 fs_state; /* file system state time stamp */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sun;
+ struct {
+ __s32 fs_sparecon[53];/* reserved for future constants */
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __u32 fs_npsect; /* # sectors/track including spares */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sunx86;
+ struct {
+ __s32 fs_sparecon[50];/* reserved for future constants */
+ __s32 fs_contigsumsize;/* size of cluster summary array */
+ __s32 fs_maxsymlinklen;/* max length of an internal symlink */
+ __s32 fs_inodefmt; /* format of on-disk inodes */
+ __u32 fs_maxfilesize[2]; /* max representable file size */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ __s32 fs_state; /* file system state time stamp */
+ } fs_44;
+ } fs_u2;
+ __s32 fs_postblformat; /* format of positional layout tables */
+ __s32 fs_nrpos; /* number of rotational positions */
+ __s32 fs_postbloff; /* (__s16) rotation block list head */
+ __s32 fs_rotbloff; /* (__u8) blocks for each rotation */
+ __s32 fs_magic; /* magic number */
+ __u8 fs_space[1]; /* list of blocks for each rotation */
+};
+
+/*
+ * Preference for optimization.
+ */
+#define UFS_OPTTIME 0 /* minimize allocation time */
+#define UFS_OPTSPACE 1 /* minimize disk fragmentation */
+
+/*
+ * Rotational layout table format types
+ */
+#define UFS_42POSTBLFMT -1 /* 4.2BSD rotational table format */
+#define UFS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */
+
+/*
+ * Convert cylinder group to base address of its global summary info.
+ */
+#define fs_cs(indx) \
+ u.ufs_sb.s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask]
+
+/*
+ * Cylinder group block for a file system.
+ *
+ * Writable fields in the cylinder group are protected by the associated
+ * super block lock fs->fs_lock.
+ */
+#define CG_MAGIC 0x090255
+#define ufs_cg_chkmagic(ucg) (SWAB32((ucg)->cg_magic) == CG_MAGIC)
+
+/*
+ * size of this structure is 172 B
+ */
+struct ufs_cylinder_group {
+ __u32 cg_link; /* linked list of cyl groups */
+ __u32 cg_magic; /* magic number */
+ __u32 cg_time; /* time last written */
+ __u32 cg_cgx; /* we are the cgx'th cylinder group */
+ __u16 cg_ncyl; /* number of cyl's this cg */
+ __u16 cg_niblk; /* number of inode blocks this cg */
+ __u32 cg_ndblk; /* number of data blocks this cg */
+ struct ufs_csum cg_cs; /* cylinder summary information */
+ __u32 cg_rotor; /* position of last used block */
+ __u32 cg_frotor; /* position of last used frag */
+ __u32 cg_irotor; /* position of last used inode */
+ __u32 cg_frsum[UFS_MAXFRAG]; /* counts of available frags */
+ __u32 cg_btotoff; /* (__u32) block totals per cylinder */
+ __u32 cg_boff; /* (short) free block positions */
+ __u32 cg_iusedoff; /* (char) used inode map */
+ __u32 cg_freeoff; /* (u_char) free block map */
+ __u32 cg_nextfreeoff; /* (u_char) next available space */
+ union {
+ struct {
+ __u32 cg_clustersumoff; /* (u_int32) counts of avail clusters */
+ __u32 cg_clusteroff; /* (u_int8) free cluster map */
+ __u32 cg_nclusterblks; /* number of clusters this cg */
+ __u32 cg_sparecon[13]; /* reserved for future use */
+ } cg_44;
+ __u32 cg_sparecon[16]; /* reserved for future use */
+ } cg_u;
+ __u8 cg_space[1]; /* space for cylinder group maps */
+/* actually longer */
+};
+
+/*
+ * structure of an on-disk inode
+ */
+struct ufs_inode {
+ __u16 ui_mode; /* 0x0 */
+ __u16 ui_nlink; /* 0x2 */
+ union {
+ struct {
+ __u16 ui_suid; /* 0x4 */
+ __u16 ui_sgid; /* 0x6 */
+ } oldids;
+ __u32 ui_inumber; /* 0x4 lsf: inode number */
+ __u32 ui_author; /* 0x4 GNU HURD: author */
+ } ui_u1;
+ __u64 ui_size; /* 0x8 */
+ struct ufs_timeval ui_atime; /* 0x10 access */
+ struct ufs_timeval ui_mtime; /* 0x18 modification */
+ struct ufs_timeval ui_ctime; /* 0x20 creation */
+ union {
+ struct {
+ __u32 ui_db[UFS_NDADDR];/* 0x28 data blocks */
+ __u32 ui_ib[UFS_NINDIR];/* 0x58 indirect blocks */
+ } ui_addr;
+ __u8 ui_symlink[4*(UFS_NDADDR+UFS_NINDIR)];/* 0x28 fast symlink */
+ } ui_u2;
+ __u32 ui_flags; /* 0x64 immutable, append-only... */
+ __u32 ui_blocks; /* 0x68 blocks in use */
+ __u32 ui_gen; /* 0x6c like ext2 i_version, for NFS support */
+ union {
+ struct {
+ __u32 ui_shadow; /* 0x70 shadow inode with security data */
+ __u32 ui_uid; /* 0x74 long EFT version of uid */
+ __u32 ui_gid; /* 0x78 long EFT version of gid */
+ __u32 ui_oeftflag; /* 0x7c reserved */
+ } ui_sun;
+ struct {
+ __u32 ui_uid; /* 0x70 File owner */
+ __u32 ui_gid; /* 0x74 File group */
+ __s32 ui_spare[2]; /* 0x78 reserved */
+ } ui_44;
+ struct {
+ __u32 ui_uid; /* 0x70 */
+ __u32 ui_gid; /* 0x74 */
+ __u16 ui_modeh; /* 0x78 mode high bits */
+ __u16 ui_spare; /* 0x7A unused */
+ __u32 ui_trans; /* 0x7c filesystem translator */
+ } ui_hurd;
+ } ui_u3;
+};
+
+/* FreeBSD has these in sys/stat.h */
+/* ui_flags that can be set by a file owner */
+#define UFS_UF_SETTABLE 0x0000ffff
+#define UFS_UF_NODUMP 0x00000001 /* do not dump */
+#define UFS_UF_IMMUTABLE 0x00000002 /* immutable (can't "change") */
+#define UFS_UF_APPEND 0x00000004 /* append-only */
+#define UFS_UF_OPAQUE 0x00000008 /* directory is opaque (unionfs) */
+#define UFS_UF_NOUNLINK 0x00000010 /* can't be removed or renamed */
+/* ui_flags that only root can set */
+#define UFS_SF_SETTABLE 0xffff0000
+#define UFS_SF_ARCHIVED 0x00010000 /* archived */
+#define UFS_SF_IMMUTABLE 0x00020000 /* immutable (can't "change") */
+#define UFS_SF_APPEND 0x00040000 /* append-only */
+#define UFS_SF_NOUNLINK 0x00100000 /* can't be removed or renamed */
+
+#ifdef __KERNEL__
+
+/* acl.c */
+extern int ufs_permission (struct inode *, int);
+
+/* balloc.c */
+extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
+extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
+extern unsigned ufs_new_fragments (struct inode *, u32 *, unsigned, unsigned, unsigned, int *);
+
+/* cylinder.c */
+extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);
+extern void ufs_put_cylinder (struct super_block *, unsigned);
+
+/* dir.c */
+extern struct inode_operations ufs_dir_inode_operations;
+extern struct file_operations ufs_dir_operations;
+extern int ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, struct buffer_head *, unsigned long);
+
+/* file.c */
+extern struct inode_operations ufs_file_inode_operations;
+extern struct file_operations ufs_file_operations;
+
+/* ialloc.c */
+extern void ufs_free_inode (struct inode *inode);
+extern struct inode * ufs_new_inode (const struct inode *, int, int *);
+
+/* inode.c */
+extern int ufs_bmap (struct inode *, int);
+extern void ufs_read_inode (struct inode *);
+extern void ufs_put_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern int ufs_sync_inode (struct inode *);
+extern void ufs_write_inode (struct inode *);
+extern void ufs_delete_inode (struct inode *);
+extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
+extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
+
+/* namei.c */
+extern struct dentry *ufs_lookup (struct inode *, struct dentry *);
+extern int ufs_mkdir(struct inode *, struct dentry *, int);
+extern int ufs_rmdir (struct inode *, struct dentry *);
+extern int ufs_unlink (struct inode *, struct dentry *);
+extern int ufs_create (struct inode *, struct dentry *, int);
+extern int ufs_rename (struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int ufs_mknod (struct inode *, struct dentry *, int, int);
+extern int ufs_symlink (struct inode *, struct dentry *, const char *);
+extern int ufs_link (struct dentry *, struct inode *, struct dentry *);
+
+/* super.c */
+extern struct super_operations ufs_super_ops;
+extern struct file_system_type ufs_fs_type;
+extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+extern int init_ufs_fs(void);
+extern void ufs_write_super (struct super_block *);
+
+/* symlink.c */
+extern struct inode_operations ufs_symlink_inode_operations;
+
+/* truncate.c */
+extern void ufs_truncate (struct inode *);
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_UFS_FS_H */
diff --git a/pfinet/linux-src/include/linux/ufs_fs_i.h b/pfinet/linux-src/include/linux/ufs_fs_i.h
new file mode 100644
index 00000000..df4c7575
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ufs_fs_i.h
@@ -0,0 +1,32 @@
+/*
+ * linux/include/linux/ufs_fs_i.h
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
+ */
+
+#ifndef _LINUX_UFS_FS_I_H
+#define _LINUX_UFS_FS_I_H
+
+struct ufs_inode_info {
+ union {
+ __u32 i_data[15];
+ __u8 i_symlink[4*15];
+ } i_u1;
+ __u64 i_size;
+ __u32 i_flags;
+ __u32 i_gen;
+ __u32 i_shadow;
+ __u32 i_uid;
+ __u32 i_gid;
+ __u32 i_oeftflag;
+ __u16 i_osync;
+ __u32 i_lastfrag;
+};
+
+#endif /* _LINUX_UFS_FS_I_H */
diff --git a/pfinet/linux-src/include/linux/ufs_fs_sb.h b/pfinet/linux-src/include/linux/ufs_fs_sb.h
new file mode 100644
index 00000000..2fc49e99
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ufs_fs_sb.h
@@ -0,0 +1,245 @@
+/*
+ * linux/include/linux/ufs_fs_sb.h
+ *
+ * Copyright (C) 1996
+ * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
+ * Laboratory for Computer Science Research Computing Facility
+ * Rutgers, The State University of New Jersey
+ *
+ * $Id: ufs_fs_sb.h,v 1.8 1998/05/06 12:04:40 jj Exp $
+ *
+ * Write support by Daniel Pirkl <daniel.pirkl@email.cz>
+ */
+
+#ifndef __LINUX_UFS_FS_SB_H
+#define __LINUX_UFS_FS_SB_H
+
+#include <linux/ufs_fs.h>
+
+/*
+ * This structure is used for reading disk structures larger
+ * than the size of fragment.
+ */
+struct ufs_buffer_head {
+ unsigned fragment; /* first fragment */
+ unsigned count; /* number of fragments */
+ struct buffer_head * bh[UFS_MAXFRAG]; /* buffers */
+};
+
+struct ufs_cg_private_info {
+ struct ufs_cylinder_group ucg;
+ __u32 c_cgx; /* number of cylidner group */
+ __u16 c_ncyl; /* number of cyl's this cg */
+ __u16 c_niblk; /* number of inode blocks this cg */
+ __u32 c_ndblk; /* number of data blocks this cg */
+ __u32 c_rotor; /* position of last used block */
+ __u32 c_frotor; /* position of last used frag */
+ __u32 c_irotor; /* position of last used inode */
+ __u32 c_btotoff; /* (__u32) block totals per cylinder */
+ __u32 c_boff; /* (short) free block positions */
+ __u32 c_iusedoff; /* (char) used inode map */
+ __u32 c_freeoff; /* (u_char) free block map */
+ __u32 c_nextfreeoff; /* (u_char) next available space */
+ __u32 c_clustersumoff;/* (u_int32) counts of avail clusters */
+ __u32 c_clusteroff; /* (u_int8) free cluster map */
+ __u32 c_nclusterblks; /* number of clusters this cg */
+};
+
+struct ufs_sb_private_info {
+ struct ufs_buffer_head s_ubh; /* buffer containing super block */
+ __u32 s_sblkno; /* offset of super-blocks in filesys */
+ __u32 s_cblkno; /* offset of cg-block in filesys */
+ __u32 s_iblkno; /* offset of inode-blocks in filesys */
+ __u32 s_dblkno; /* offset of first data after cg */
+ __u32 s_cgoffset; /* cylinder group offset in cylinder */
+ __u32 s_cgmask; /* used to calc mod fs_ntrak */
+ __u32 s_size; /* number of blocks (fragments) in fs */
+ __u32 s_dsize; /* number of data blocks in fs */
+ __u32 s_ncg; /* number of cylinder groups */
+ __u32 s_bsize; /* size of basic blocks */
+ __u32 s_fsize; /* size of fragments */
+ __u32 s_fpb; /* fragments per block */
+ __u32 s_minfree; /* minimum percentage of free blocks */
+ __u32 s_bmask; /* `blkoff'' calc of blk offsets */
+ __u32 s_fmask; /* s_fsize mask */
+ __u32 s_bshift; /* `lblkno'' calc of logical blkno */
+ __u32 s_fshift; /* s_fsize shift */
+ __u32 s_fpbshift; /* fragments per block shift */
+ __u32 s_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ __u32 s_sbsize; /* actual size of super block */
+ __u32 s_csmask; /* csum block offset */
+ __u32 s_csshift; /* csum block number */
+ __u32 s_nindir; /* value of NINDIR */
+ __u32 s_inopb; /* value of INOPB */
+ __u32 s_nspf; /* value of NSPF */
+ __u32 s_npsect; /* # sectors/track including spares */
+ __u32 s_interleave; /* hardware sector interleave */
+ __u32 s_trackskew; /* sector 0 skew, per track */
+ __u32 s_csaddr; /* blk addr of cyl grp summary area */
+ __u32 s_cssize; /* size of cyl grp summary area */
+ __u32 s_cgsize; /* cylinder group size */
+ __u32 s_ntrak; /* tracks per cylinder */
+ __u32 s_nsect; /* sectors per track */
+ __u32 s_spc; /* sectors per cylinder */
+ __u32 s_ipg; /* inodes per group */
+ __u32 s_fpg; /* fragments per group */
+ __u32 s_cpc; /* cyl per cycle in postbl */
+ __s32 s_contigsumsize;/* size of cluster summary array, 44bsd */
+ __s64 s_qbmask; /* ~usb_bmask */
+ __s64 s_qfmask; /* ~usb_fmask */
+ __s32 s_postblformat; /* format of positional layout tables */
+ __s32 s_nrpos; /* number of rotational positions */
+ __s32 s_postbloff; /* (__s16) rotation block list head */
+ __s32 s_rotbloff; /* (__u8) blocks for each rotation */
+
+ __u32 s_fpbmask; /* fragments per block mask */
+ __u32 s_apb; /* address per block */
+ __u32 s_2apb; /* address per block^2 */
+ __u32 s_3apb; /* address per block^3 */
+ __u32 s_apbmask; /* address per block mask */
+ __u32 s_apbshift; /* address per block shift */
+ __u32 s_2apbshift; /* address per block shift * 2 */
+ __u32 s_3apbshift; /* address per block shift * 3 */
+ __u32 s_nspfshift; /* number of sector per fragment shift */
+ __u32 s_nspb; /* number of sector per block */
+ __u32 s_inopf; /* inodes per fragment */
+ __u32 s_sbbase; /* offset of NeXTstep superblock */
+ __u32 s_bpf; /* bits per fragment */
+ __u32 s_bpfshift; /* bits per fragment shift*/
+ __u32 s_bpfmask; /* bits per fragment mask */
+};
+
+
+#define UFS_MAX_GROUP_LOADED 8
+#define UFS_CGNO_EMPTY ((unsigned)-1)
+
+struct ufs_sb_info {
+ struct ufs_sb_private_info * s_uspi;
+ struct ufs_csum * s_csp[UFS_MAXCSBUFS];
+ unsigned s_swab;
+ unsigned s_flags;
+ struct buffer_head ** s_ucg;
+ struct ufs_cg_private_info * s_ucpi[UFS_MAX_GROUP_LOADED];
+ unsigned s_cgno[UFS_MAX_GROUP_LOADED];
+ unsigned short s_cg_loaded;
+ unsigned s_mount_opt;
+};
+
+/*
+ * Sizes of this structures are:
+ * ufs_super_block_first 512
+ * ufs_super_block_second 512
+ * ufs_super_block_third 356
+ */
+struct ufs_super_block_first {
+ __u32 fs_link;
+ __u32 fs_rlink;
+ __u32 fs_sblkno;
+ __u32 fs_cblkno;
+ __u32 fs_iblkno;
+ __u32 fs_dblkno;
+ __u32 fs_cgoffset;
+ __u32 fs_cgmask;
+ __u32 fs_time;
+ __u32 fs_size;
+ __u32 fs_dsize;
+ __u32 fs_ncg;
+ __u32 fs_bsize;
+ __u32 fs_fsize;
+ __u32 fs_frag;
+ __u32 fs_minfree;
+ __u32 fs_rotdelay;
+ __u32 fs_rps;
+ __u32 fs_bmask;
+ __u32 fs_fmask;
+ __u32 fs_bshift;
+ __u32 fs_fshift;
+ __u32 fs_maxcontig;
+ __u32 fs_maxbpg;
+ __u32 fs_fragshift;
+ __u32 fs_fsbtodb;
+ __u32 fs_sbsize;
+ __u32 fs_csmask;
+ __u32 fs_csshift;
+ __u32 fs_nindir;
+ __u32 fs_inopb;
+ __u32 fs_nspf;
+ __u32 fs_optim;
+ union {
+ struct {
+ __u32 fs_npsect;
+ } fs_sun;
+ struct {
+ __s32 fs_state;
+ } fs_sunx86;
+ } fs_u1;
+ __u32 fs_interleave;
+ __u32 fs_trackskew;
+ __u32 fs_id[2];
+ __u32 fs_csaddr;
+ __u32 fs_cssize;
+ __u32 fs_cgsize;
+ __u32 fs_ntrak;
+ __u32 fs_nsect;
+ __u32 fs_spc;
+ __u32 fs_ncyl;
+ __u32 fs_cpg;
+ __u32 fs_ipg;
+ __u32 fs_fpg;
+ struct ufs_csum fs_cstotal;
+ __s8 fs_fmod;
+ __s8 fs_clean;
+ __s8 fs_ronly;
+ __s8 fs_flags;
+ __s8 fs_fsmnt[UFS_MAXMNTLEN - 212];
+
+};
+
+struct ufs_super_block_second {
+ __s8 fs_fsmnt[212];
+ __u32 fs_cgrotor;
+ __u32 fs_csp[UFS_MAXCSBUFS];
+ __u32 fs_maxcluster;
+ __u32 fs_cpc;
+ __u16 fs_opostbl[82];
+};
+
+struct ufs_super_block_third {
+ __u16 fs_opostbl[46];
+ union {
+ struct {
+ __s32 fs_sparecon[53];/* reserved for future constants */
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __s32 fs_state; /* file system state time stamp */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sun;
+ struct {
+ __s32 fs_sparecon[53];/* reserved for future constants */
+ __s32 fs_reclaim;
+ __s32 fs_sparecon2[1];
+ __u32 fs_npsect; /* # sectors/track including spares */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sunx86;
+ struct {
+ __s32 fs_sparecon[50];/* reserved for future constants */
+ __s32 fs_contigsumsize;/* size of cluster summary array */
+ __s32 fs_maxsymlinklen;/* max length of an internal symlink */
+ __s32 fs_inodefmt; /* format of on-disk inodes */
+ __u32 fs_maxfilesize[2]; /* max representable file size */
+ __u32 fs_qbmask[2]; /* ~usb_bmask */
+ __u32 fs_qfmask[2]; /* ~usb_fmask */
+ __s32 fs_state; /* file system state time stamp */
+ } fs_44;
+ } fs_u2;
+ __s32 fs_postblformat;
+ __s32 fs_nrpos;
+ __s32 fs_postbloff;
+ __s32 fs_rotbloff;
+ __s32 fs_magic;
+ __u8 fs_space[1];
+};
+
+#endif /* __LINUX_UFS_FS_SB_H */
diff --git a/pfinet/linux-src/include/linux/uio.h b/pfinet/linux-src/include/linux/uio.h
new file mode 100644
index 00000000..beaafffd
--- /dev/null
+++ b/pfinet/linux-src/include/linux/uio.h
@@ -0,0 +1,37 @@
+#ifndef __LINUX_UIO_H
+#define __LINUX_UIO_H
+
+#include <linux/types.h>
+
+/*
+ * Berkeley style UIO structures - Alan Cox 1994.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+/* A word of warning: Our uio structure will clash with the C library one (which is now obsolete). Remove the C
+ library one from sys/uio.h if you have a very old library set */
+
+struct iovec
+{
+ void *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
+ __kernel_size_t iov_len; /* Must be size_t (1003.1g) */
+};
+
+/*
+ * UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1)
+ */
+
+#define UIO_FASTIOV 8
+#define UIO_MAXIOV 1024
+#if 0
+#define UIO_MAXIOV 16 /* Maximum iovec's in one operation
+ 16 matches BSD */
+ /* Beg pardon: BSD has 1024 --ANK */
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/ultrasound.h b/pfinet/linux-src/include/linux/ultrasound.h
new file mode 100644
index 00000000..6b7703e7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/ultrasound.h
@@ -0,0 +1,103 @@
+#ifndef _ULTRASOUND_H_
+#define _ULTRASOUND_H_
+/*
+ * ultrasound.h - Macros for programming the Gravis Ultrasound
+ * These macros are extremely device dependent
+ * and not portable.
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1997
+ *
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+
+
+/*
+ * Private events for Gravis Ultrasound (GUS)
+ *
+ * Format:
+ * byte 0 - SEQ_PRIVATE (0xfe)
+ * byte 1 - Synthesizer device number (0-N)
+ * byte 2 - Command (see below)
+ * byte 3 - Voice number (0-31)
+ * bytes 4 and 5 - parameter P1 (unsigned short)
+ * bytes 6 and 7 - parameter P2 (unsigned short)
+ *
+ * Commands:
+ * Each command affects one voice defined in byte 3.
+ * Unused parameters (P1 and/or P2 *MUST* be initialized to zero).
+ * _GUS_NUMVOICES - Sets max. number of concurrent voices (P1=14-31, default 16)
+ * _GUS_VOICESAMPLE- ************ OBSOLETE *************
+ * _GUS_VOICEON - Starts voice (P1=voice mode)
+ * _GUS_VOICEOFF - Stops voice (no parameters)
+ * _GUS_VOICEFADE - Stops the voice smoothly.
+ * _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode)
+ * _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7)
+ * _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz)
+ * _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
+ * _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
+ * (Like GUS_VOICEVOL but doesn't change the hw
+ * volume. It just updates volume in the voice table).
+ *
+ * _GUS_RAMPRANGE - Sets limits for volume ramping (P1=low volume, P2=high volume)
+ * _GUS_RAMPRATE - Sets the speed for volume ramping (P1=scale, P2=rate)
+ * _GUS_RAMPMODE - Sets the volume ramping mode (P1=ramping mode)
+ * _GUS_RAMPON - Starts volume ramping (no parameters)
+ * _GUS_RAMPOFF - Stops volume ramping (no parameters)
+ * _GUS_VOLUME_SCALE - Changes the volume calculation constants
+ * for all voices.
+ */
+
+#define _GUS_NUMVOICES 0x00
+#define _GUS_VOICESAMPLE 0x01 /* OBSOLETE */
+#define _GUS_VOICEON 0x02
+#define _GUS_VOICEOFF 0x03
+#define _GUS_VOICEMODE 0x04
+#define _GUS_VOICEBALA 0x05
+#define _GUS_VOICEFREQ 0x06
+#define _GUS_VOICEVOL 0x07
+#define _GUS_RAMPRANGE 0x08
+#define _GUS_RAMPRATE 0x09
+#define _GUS_RAMPMODE 0x0a
+#define _GUS_RAMPON 0x0b
+#define _GUS_RAMPOFF 0x0c
+#define _GUS_VOICEFADE 0x0d
+#define _GUS_VOLUME_SCALE 0x0e
+#define _GUS_VOICEVOL2 0x0f
+#define _GUS_VOICE_POS 0x10
+
+/*
+ * GUS API macros
+ */
+
+#define _GUS_CMD(chn, voice, cmd, p1, p2) \
+ {_SEQ_NEEDBUF(8); _seqbuf[_seqbufptr] = SEQ_PRIVATE;\
+ _seqbuf[_seqbufptr+1] = (chn); _seqbuf[_seqbufptr+2] = cmd;\
+ _seqbuf[_seqbufptr+3] = voice;\
+ *(unsigned short*)&_seqbuf[_seqbufptr+4] = p1;\
+ *(unsigned short*)&_seqbuf[_seqbufptr+6] = p2;\
+ _SEQ_ADVBUF(8);}
+
+#define GUS_NUMVOICES(chn, p1) _GUS_CMD(chn, 0, _GUS_NUMVOICES, (p1), 0)
+#define GUS_VOICESAMPLE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICESAMPLE, (p1), 0) /* OBSOLETE */
+#define GUS_VOICEON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEON, (p1), 0)
+#define GUS_VOICEOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEOFF, 0, 0)
+#define GUS_VOICEFADE(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEFADE, 0, 0)
+#define GUS_VOICEMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEMODE, (p1), 0)
+#define GUS_VOICEBALA(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEBALA, (p1), 0)
+#define GUS_VOICEFREQ(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICEFREQ, \
+ (p) & 0xffff, ((p) >> 16) & 0xffff)
+#define GUS_VOICEVOL(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL, (p1), 0)
+#define GUS_VOICEVOL2(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL2, (p1), 0)
+#define GUS_RAMPRANGE(chn, voice, low, high) _GUS_CMD(chn, voice, _GUS_RAMPRANGE, (low), (high))
+#define GUS_RAMPRATE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_RAMPRATE, (p1), (p2))
+#define GUS_RAMPMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPMODE, (p1), 0)
+#define GUS_RAMPON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPON, (p1), 0)
+#define GUS_RAMPOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_RAMPOFF, 0, 0)
+#define GUS_VOLUME_SCALE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_VOLUME_SCALE, (p1), (p2))
+#define GUS_VOICE_POS(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICE_POS, \
+ (p) & 0xffff, ((p) >> 16) & 0xffff)
+
+#endif
diff --git a/pfinet/linux-src/include/linux/umsdos_fs.h b/pfinet/linux-src/include/linux/umsdos_fs.h
new file mode 100644
index 00000000..14bdb829
--- /dev/null
+++ b/pfinet/linux-src/include/linux/umsdos_fs.h
@@ -0,0 +1,188 @@
+#ifndef LINUX_UMSDOS_FS_H
+#define LINUX_UMSDOS_FS_H
+
+
+#define UMS_DEBUG 1 /* define for check_* functions */
+/*#define UMSDOS_DEBUG 1*/
+#define UMSDOS_PARANOIA 1
+
+#define UMSDOS_VERSION 0
+#define UMSDOS_RELEASE 4
+
+#define UMSDOS_ROOT_INO 1
+
+/* This is the file acting as a directory extension */
+#define UMSDOS_EMD_FILE "--linux-.---"
+#define UMSDOS_EMD_NAMELEN 12
+#define UMSDOS_PSDROOT_NAME "linux"
+#define UMSDOS_PSDROOT_LEN 5
+
+#ifndef _LINUX_TYPES_H
+#include <linux/types.h>
+#endif
+#ifndef _LINUX_LIMITS_H
+#include <linux/limits.h>
+#endif
+#ifndef _LINUX_DIRENT_H
+#include <linux/dirent.h>
+#endif
+#ifndef _LINUX_IOCTL_H
+#include <linux/ioctl.h>
+#endif
+
+
+#ifdef __KERNEL__
+/* #Specification: convention / PRINTK Printk and printk
+ * Here is the convention for the use of printk inside fs/umsdos
+ *
+ * printk carry important message (error or status).
+ * Printk is for debugging (it is a macro defined at the beginning of
+ * most source.
+ * PRINTK is a nulled Printk macro.
+ *
+ * This convention makes the source easier to read, and Printk easier
+ * to shut off.
+ */
+# define PRINTK(x)
+# ifdef UMSDOS_DEBUG
+# define Printk(x) printk x
+# else
+# define Printk(x)
+# endif
+#endif
+
+
+struct umsdos_fake_info {
+ char fname[13];
+ int len;
+};
+
+#define UMSDOS_MAXNAME 220
+/* This structure is 256 bytes large, depending on the name, only part */
+/* of it is written to disk */
+/* nice though it would be, I can't change this and preserve backward compatibility */
+struct umsdos_dirent {
+ unsigned char name_len; /* if == 0, then this entry is not used */
+ unsigned char flags; /* UMSDOS_xxxx */
+ unsigned short nlink; /* How many hard links point to this entry */
+ uid_t uid; /* Owner user id */
+ gid_t gid; /* Group id */
+ time_t atime; /* Access time */
+ time_t mtime; /* Last modification time */
+ time_t ctime; /* Creation time */
+ dev_t rdev; /* major and minor number of a device */
+ /* special file */
+ umode_t mode; /* Standard UNIX permissions bits + type of */
+ char spare[12]; /* unused bytes for future extensions */
+ /* file, see linux/stat.h */
+ char name[UMSDOS_MAXNAME]; /* Not '\0' terminated */
+ /* but '\0' padded, so it will allow */
+ /* for adding news fields in this record */
+ /* by reducing the size of name[] */
+};
+
+#define UMSDOS_HIDDEN 1 /* Never show this entry in directory search */
+#define UMSDOS_HLINK 2 /* It is a (pseudo) hard link */
+
+/* #Specification: EMD file / record size
+ * Entry are 64 bytes wide in the EMD file. It allows for a 30 characters
+ * name. If a name is longer, contiguous entries are allocated. So a
+ * umsdos_dirent may span multiple records.
+ */
+
+#define UMSDOS_REC_SIZE 64
+
+/* Translation between MSDOS name and UMSDOS name */
+
+struct umsdos_info {
+ int msdos_reject; /* Tell if the file name is invalid for MSDOS */
+ /* See umsdos_parse */
+ struct umsdos_fake_info fake;
+ struct umsdos_dirent entry;
+ off_t f_pos; /* offset of the entry in the EMD file
+ * or offset where the entry may be store
+ * if it is a new entry
+ */
+ int recsize; /* Record size needed to store entry */
+};
+
+/* Definitions for ioctl (number randomly chosen)
+ * The next ioctl commands operate only on the DOS directory
+ * The file umsdos_progs/umsdosio.c contain a string table
+ * based on the order of those definition. Keep it in sync
+ */
+#define UMSDOS_READDIR_DOS _IO(0x04,210) /* Do a readdir of the DOS directory */
+#define UMSDOS_UNLINK_DOS _IO(0x04,211) /* Erase in the DOS directory only */
+#define UMSDOS_RMDIR_DOS _IO(0x04,212) /* rmdir in the DOS directory only */
+#define UMSDOS_STAT_DOS _IO(0x04,213) /* Get info about a file */
+
+/* The next ioctl commands operate only on the EMD file */
+#define UMSDOS_CREAT_EMD _IO(0x04,214) /* Create a file */
+#define UMSDOS_UNLINK_EMD _IO(0x04,215) /* unlink (rmdir) a file */
+#define UMSDOS_READDIR_EMD _IO(0x04,216) /* read the EMD file only. */
+#define UMSDOS_GETVERSION _IO(0x04,217) /* Get the release number of UMSDOS */
+#define UMSDOS_INIT_EMD _IO(0x04,218) /* Create the EMD file if not there */
+#define UMSDOS_DOS_SETUP _IO(0x04,219) /* Set the defaults of the MS-DOS driver. */
+
+#define UMSDOS_RENAME_DOS _IO(0x04,220) /* rename a file/directory in the DOS
+ * directory only */
+struct umsdos_ioctl {
+ struct dirent dos_dirent;
+ struct umsdos_dirent umsdos_dirent;
+ /* The following structure is used to exchange some data
+ * with utilities (umsdos_progs/util/umsdosio.c). The first
+ * releases were using struct stat from "sys/stat.h". This was
+ * causing some problem for cross compilation of the kernel
+ * Since I am not really using the structure stat, but only some field
+ * of it, I have decided to replicate the structure here
+ * for compatibility with the binaries out there
+ * FIXME PTW 1998, this has probably changed
+ */
+
+ struct {
+ dev_t st_dev;
+ unsigned short __pad1;
+ ino_t st_ino;
+ umode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ unsigned short __pad2;
+ off_t st_size;
+ unsigned long st_blksize;
+ unsigned long st_blocks;
+ time_t st_atime;
+ unsigned long __unused1;
+ time_t st_mtime;
+ unsigned long __unused2;
+ time_t st_ctime;
+ unsigned long __unused3;
+ unsigned long __unused4;
+ unsigned long __unused5;
+ } stat;
+ char version, release;
+};
+
+/* Different macros to access struct umsdos_dirent */
+#define EDM_ENTRY_ISUSED(e) ((e)->name_len!=0)
+
+#ifdef __KERNEL__
+
+#ifndef LINUX_FS_H
+#include <linux/fs.h>
+#endif
+
+extern struct inode_operations umsdos_dir_inode_operations;
+extern struct file_operations umsdos_file_operations;
+extern struct inode_operations umsdos_file_inode_operations;
+extern struct inode_operations umsdos_file_inode_operations_no_bmap;
+extern struct inode_operations umsdos_file_inode_operations_readpage;
+extern struct inode_operations umsdos_symlink_inode_operations;
+extern int init_umsdos_fs (void);
+
+#include <linux/umsdos_fs.p>
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/umsdos_fs.p b/pfinet/linux-src/include/linux/umsdos_fs.p
new file mode 100644
index 00000000..de436f0e
--- /dev/null
+++ b/pfinet/linux-src/include/linux/umsdos_fs.p
@@ -0,0 +1,118 @@
+/* check.c 23/01/95 03.38.30 */
+void check_page_tables (void);
+
+/* dir.c 22/06/95 00.22.12 */
+int dummy_dir_read ( struct file *filp,
+ char *buf,
+ size_t size,
+ loff_t *count);
+char * umsdos_d_path(struct dentry *, char *, int);
+void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *);
+int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry);
+struct dentry *umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo);
+struct dentry *UMSDOS_lookup(struct inode *, struct dentry *);
+struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int);
+struct dentry *umsdos_covered(struct dentry *, char *, int);
+
+struct dentry *umsdos_solve_hlink (struct dentry *hlink);
+
+/* emd.c 22/06/95 00.22.04 */
+ssize_t umsdos_file_write_kmem_real (struct file *filp,
+ const char *buf,
+ size_t count);
+
+ssize_t umsdos_file_read_kmem (struct file *filp,
+ char *buf,
+ size_t count);
+ssize_t umsdos_file_write_kmem (struct file *filp,
+ const char *buf,
+ size_t count);
+ssize_t umsdos_emd_dir_write (struct file *filp,
+ char *buf,
+ size_t count);
+ssize_t umsdos_emd_dir_read (struct file *filp,
+ char *buf,
+ size_t count);
+struct dentry *umsdos_get_emd_dentry(struct dentry *);
+int umsdos_have_emd(struct dentry *);
+int umsdos_make_emd(struct dentry *);
+int umsdos_emd_dir_readentry (struct file *, struct umsdos_dirent *);
+int umsdos_newentry (struct dentry *, struct umsdos_info *);
+int umsdos_newhidden (struct dentry *, struct umsdos_info *);
+int umsdos_delentry (struct dentry *, struct umsdos_info *, int);
+int umsdos_findentry (struct dentry *, struct umsdos_info *, int);
+int umsdos_isempty (struct dentry *);
+
+/* file.c 25/01/95 02.25.38 */
+
+/* inode.c 12/06/95 09.49.40 */
+void fill_new_filp (struct file *filp, struct dentry *dentry);
+void UMSDOS_read_inode (struct inode *);
+void UMSDOS_write_inode (struct inode *);
+int UMSDOS_notify_change (struct dentry *, struct iattr *attr);
+int umsdos_notify_change_locked(struct dentry *, struct iattr *attr);
+void UMSDOS_put_inode (struct inode *);
+int UMSDOS_statfs (struct super_block *, struct statfs *, int);
+struct super_block *UMSDOS_read_super (struct super_block *, void *, int);
+void UMSDOS_put_super (struct super_block *);
+
+void umsdos_setup_dir(struct dentry *);
+void umsdos_set_dirinfo_new(struct dentry *, off_t);
+void umsdos_patch_dentry_inode (struct dentry *, off_t);
+int umsdos_get_dirowner (struct inode *inode, struct inode **result);
+
+/* ioctl.c 22/06/95 00.22.08 */
+int UMSDOS_ioctl_dir (struct inode *dir,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long data);
+
+/* mangle.c 25/01/95 02.25.38 */
+void umsdos_manglename (struct umsdos_info *info);
+int umsdos_evalrecsize (int len);
+int umsdos_parse (const char *name,int len, struct umsdos_info *info);
+
+/* namei.c 25/01/95 02.25.38 */
+void umsdos_lockcreate (struct inode *dir);
+void umsdos_startlookup (struct inode *dir);
+void umsdos_unlockcreate (struct inode *dir);
+void umsdos_endlookup (struct inode *dir);
+
+int umsdos_readlink_x ( struct dentry *dentry,
+ char *buffer,
+ int bufsiz);
+int UMSDOS_symlink (struct inode *dir,
+ struct dentry *dentry,
+ const char *symname);
+int UMSDOS_link (struct dentry *olddentry,
+ struct inode *dir,
+ struct dentry *dentry);
+int UMSDOS_create (struct inode *dir,
+ struct dentry *dentry,
+ int mode);
+
+int UMSDOS_mkdir (struct inode *dir,
+ struct dentry *dentry,
+ int mode);
+int UMSDOS_mknod (struct inode *dir,
+ struct dentry *dentry,
+ int mode,
+ int rdev);
+int UMSDOS_rmdir (struct inode *dir,struct dentry *dentry);
+int UMSDOS_unlink (struct inode *dir, struct dentry *dentry);
+int UMSDOS_rename (struct inode *old_dir,
+ struct dentry *old_dentry,
+ struct inode *new_dir,
+ struct dentry *new_dentry);
+
+/* rdir.c 22/03/95 03.31.42 */
+struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
+struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry);
+
+/* symlink.c 23/01/95 03.38.30 */
+
+/* check.c */
+void checkd_inode (struct inode *inode);
+void check_inode (struct inode *inode);
+void check_dentry (struct dentry *dentry);
+void check_dentry_path (struct dentry *dentry, const char *desc);
diff --git a/pfinet/linux-src/include/linux/umsdos_fs_i.h b/pfinet/linux-src/include/linux/umsdos_fs_i.h
new file mode 100644
index 00000000..111fd913
--- /dev/null
+++ b/pfinet/linux-src/include/linux/umsdos_fs_i.h
@@ -0,0 +1,75 @@
+#ifndef UMSDOS_FS_I_H
+#define UMSDOS_FS_I_H
+
+#ifndef _LINUX_TYPES_H
+#include <linux/types.h>
+#endif
+
+#include <linux/msdos_fs_i.h>
+#include <linux/pipe_fs_i.h>
+
+/* #Specification: strategy / in memory inode
+ * Here is the information specific to the inode of the UMSDOS file
+ * system. This information is added to the end of the standard struct
+ * inode. Each file system has its own extension to struct inode,
+ * so do the umsdos file system.
+ *
+ * The strategy is to have the umsdos_inode_info as a superset of
+ * the msdos_inode_info, since most of the time the job is done
+ * by the msdos fs code.
+ *
+ * So we duplicate the msdos_inode_info, and add our own info at the
+ * end.
+ *
+ * For all file type (and directory) the inode has a reference to:
+ * the directory which hold this entry: i_dir_owner
+ * The EMD file of i_dir_owner: i_emd_owner
+ * The offset in this EMD file of the entry: pos
+ *
+ * For directory, we also have a reference to the inode of its
+ * own EMD file. Also, we have dir_locking_info to help synchronise
+ * file creation and file lookup. This data is sharing space with
+ * the pipe_inode_info not used by directory. See also msdos_fs_i.h
+ * for more information about pipe_inode_info and msdos_inode_info.
+ *
+ * Special file and fifo do have an inode which correspond to an
+ * empty MSDOS file.
+ *
+ * symlink are processed mostly like regular file. The content is the
+ * link.
+ *
+ * fifos add there own extension to the inode. I have reserved some
+ * space for fifos side by side with msdos_inode_info. This is just
+ * to for the show, because msdos_inode_info already include the
+ * pipe_inode_info.
+ *
+ * The UMSDOS specific extension is placed after the union.
+ */
+
+struct dir_locking_info {
+ struct wait_queue *p;
+ short int looking; /* How many process doing a lookup */
+ short int creating; /* Is there any creation going on here
+ * Only one at a time, although one
+ * may recursively lock, so it is a counter
+ */
+ long pid; /* pid of the process owning the creation */
+ /* lock */
+};
+
+struct umsdos_inode_info {
+ union {
+ struct msdos_inode_info msdos_info;
+ struct pipe_inode_info pipe_info;
+ struct dir_locking_info dir_info;
+ } u;
+ int i_patched; /* Inode has been patched */
+ int i_is_hlink; /* Resolved hardlink inode? */
+ unsigned long i_emd_owner; /* Is this the EMD file inode? */
+ off_t pos; /* Entry offset in the emd_owner file */
+ /* The rest is used only if this inode describes a directory */
+ struct dentry *i_emd_dentry; /* EMD dentry for this directory */
+ unsigned long i_emd_dir; /* Inode of the EMD file */
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/un.h b/pfinet/linux-src/include/linux/un.h
new file mode 100644
index 00000000..45561c56
--- /dev/null
+++ b/pfinet/linux-src/include/linux/un.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_UN_H
+#define _LINUX_UN_H
+
+#define UNIX_PATH_MAX 108
+
+struct sockaddr_un {
+ sa_family_t sun_family; /* AF_UNIX */
+ char sun_path[UNIX_PATH_MAX]; /* pathname */
+};
+
+#endif /* _LINUX_UN_H */
diff --git a/pfinet/linux-src/include/linux/unistd.h b/pfinet/linux-src/include/linux/unistd.h
new file mode 100644
index 00000000..10ed9834
--- /dev/null
+++ b/pfinet/linux-src/include/linux/unistd.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_UNISTD_H_
+#define _LINUX_UNISTD_H_
+
+extern int errno;
+
+/*
+ * Include machine specific syscallX macros
+ */
+#include <asm/unistd.h>
+
+#endif /* _LINUX_UNISTD_H_ */
diff --git a/pfinet/linux-src/include/linux/user.h b/pfinet/linux-src/include/linux/user.h
new file mode 100644
index 00000000..68daf840
--- /dev/null
+++ b/pfinet/linux-src/include/linux/user.h
@@ -0,0 +1 @@
+#include <asm/user.h>
diff --git a/pfinet/linux-src/include/linux/utime.h b/pfinet/linux-src/include/linux/utime.h
new file mode 100644
index 00000000..c6bf27b7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/utime.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_UTIME_H
+#define _LINUX_UTIME_H
+
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/uts.h b/pfinet/linux-src/include/linux/uts.h
new file mode 100644
index 00000000..39e09ae1
--- /dev/null
+++ b/pfinet/linux-src/include/linux/uts.h
@@ -0,0 +1,23 @@
+#ifndef _LINUX_UTS_H
+#define _LINUX_UTS_H
+
+/*
+ * Defines for what uname() should return
+ */
+#ifndef UTS_SYSNAME
+#define UTS_SYSNAME "Linux"
+#endif
+
+#ifndef UTS_MACHINE
+#define UTS_MACHINE "unknown"
+#endif
+
+#ifndef UTS_NODENAME
+#define UTS_NODENAME "(none)" /* set by sethostname() */
+#endif
+
+#ifndef UTS_DOMAINNAME
+#define UTS_DOMAINNAME "(none)" /* set by setdomainname() */
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/utsname.h b/pfinet/linux-src/include/linux/utsname.h
new file mode 100644
index 00000000..a83503f9
--- /dev/null
+++ b/pfinet/linux-src/include/linux/utsname.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_UTSNAME_H
+#define _LINUX_UTSNAME_H
+
+#define __OLD_UTS_LEN 8
+
+struct oldold_utsname {
+ char sysname[9];
+ char nodename[9];
+ char release[9];
+ char version[9];
+ char machine[9];
+};
+
+#define __NEW_UTS_LEN 64
+
+struct old_utsname {
+ char sysname[65];
+ char nodename[65];
+ char release[65];
+ char version[65];
+ char machine[65];
+};
+
+struct new_utsname {
+ char sysname[65];
+ char nodename[65];
+ char release[65];
+ char version[65];
+ char machine[65];
+ char domainname[65];
+};
+
+extern struct new_utsname system_utsname;
+
+extern struct semaphore uts_sem;
+#endif
diff --git a/pfinet/linux-src/include/linux/vfs.h b/pfinet/linux-src/include/linux/vfs.h
new file mode 100644
index 00000000..b3a58657
--- /dev/null
+++ b/pfinet/linux-src/include/linux/vfs.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_VFS_H
+#define _LINUX_VFS_H
+
+#include <asm/statfs.h>
+
+#endif
diff --git a/pfinet/linux-src/include/linux/video_decoder.h b/pfinet/linux-src/include/linux/video_decoder.h
new file mode 100644
index 00000000..1302c7f4
--- /dev/null
+++ b/pfinet/linux-src/include/linux/video_decoder.h
@@ -0,0 +1,37 @@
+#ifndef _LINUX_VIDEO_DECODER_H
+#define _LINUX_VIDEO_DECODER_H
+
+struct video_decoder_capability { /* this name is too long */
+ __u32 flags;
+#define VIDEO_DECODER_PAL 1 /* can decode PAL signal */
+#define VIDEO_DECODER_NTSC 2 /* can decode NTSC */
+#define VIDEO_DECODER_SECAM 4 /* can decode SECAM */
+#define VIDEO_DECODER_AUTO 8 /* can autosense norm */
+#define VIDEO_DECODER_CCIR 16 /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+ int inputs; /* number of inputs */
+ int outputs; /* number of outputs */
+};
+
+/*
+DECODER_GET_STATUS returns the following flags. The only one you need is
+DECODER_STATUS_GOOD, the others are just nice things to know.
+*/
+#define DECODER_STATUS_GOOD 1 /* receiving acceptable input */
+#define DECODER_STATUS_COLOR 2 /* receiving color information */
+#define DECODER_STATUS_PAL 4 /* auto detected */
+#define DECODER_STATUS_NTSC 8 /* auto detected */
+#define DECODER_STATUS_SECAM 16 /* auto detected */
+
+
+#define DECODER_GET_CAPABILITIES _IOR('d', 1, struct video_decoder_capability)
+#define DECODER_GET_STATUS _IOR('d', 2, int)
+#define DECODER_SET_NORM _IOW('d', 3, int)
+#define DECODER_SET_INPUT _IOW('d', 4, int) /* 0 <= input < #inputs */
+#define DECODER_SET_OUTPUT _IOW('d', 5, int) /* 0 <= output < #outputs */
+#define DECODER_ENABLE_OUTPUT _IOW('d', 6, int) /* boolean output enable control */
+#define DECODER_SET_PICTURE _IOW('d', 7, struct video_picture)
+
+#define DECODER_DUMP _IO('d', 192) /* debug hook */
+
+
+#endif
diff --git a/pfinet/linux-src/include/linux/video_encoder.h b/pfinet/linux-src/include/linux/video_encoder.h
new file mode 100644
index 00000000..4b0e6907
--- /dev/null
+++ b/pfinet/linux-src/include/linux/video_encoder.h
@@ -0,0 +1,21 @@
+#ifndef _LINUX_VIDEO_ENCODER_H
+#define _LINUX_VIDEO_ENCODER_H
+
+struct video_encoder_capability { /* this name is too long */
+ __u32 flags;
+#define VIDEO_ENCODER_PAL 1 /* can encode PAL signal */
+#define VIDEO_ENCODER_NTSC 2 /* can encode NTSC */
+#define VIDEO_ENCODER_SECAM 4 /* can encode SECAM */
+#define VIDEO_ENCODER_CCIR 16 /* CCIR-601 pixel rate (720 pixels per line) instead of square pixel rate */
+ int inputs; /* number of inputs */
+ int outputs; /* number of outputs */
+};
+
+#define ENCODER_GET_CAPABILITIES _IOR('e', 1, struct video_encoder_capability)
+#define ENCODER_SET_NORM _IOW('e', 2, int)
+#define ENCODER_SET_INPUT _IOW('e', 3, int) /* 0 <= input < #inputs */
+#define ENCODER_SET_OUTPUT _IOW('e', 4, int) /* 0 <= output < #outputs */
+#define ENCODER_ENABLE_OUTPUT _IOW('e', 5, int) /* boolean output enable control */
+
+
+#endif
diff --git a/pfinet/linux-src/include/linux/videodev.h b/pfinet/linux-src/include/linux/videodev.h
new file mode 100644
index 00000000..b3427409
--- /dev/null
+++ b/pfinet/linux-src/include/linux/videodev.h
@@ -0,0 +1,293 @@
+#ifndef __LINUX_VIDEODEV_H
+#define __LINUX_VIDEODEV_H
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+
+#if LINUX_VERSION_CODE >= 0x020100
+#include <linux/poll.h>
+#endif
+
+struct video_device
+{
+ char name[32];
+ int type;
+ int hardware;
+
+ int (*open)(struct video_device *, int mode);
+ void (*close)(struct video_device *);
+ long (*read)(struct video_device *, char *, unsigned long, int noblock);
+ /* Do we need a write method ? */
+ long (*write)(struct video_device *, const char *, unsigned long, int noblock);
+#if LINUX_VERSION_CODE >= 0x020100
+ unsigned int (*poll)(struct video_device *, struct file *, poll_table *);
+#endif
+ int (*ioctl)(struct video_device *, unsigned int , void *);
+ int (*mmap)(struct video_device *, const char *, unsigned long);
+ int (*initialize)(struct video_device *);
+ void *priv; /* Used to be 'private' but that upsets C++ */
+ int busy;
+ int minor;
+};
+
+extern int videodev_init(void);
+#define VIDEO_MAJOR 81
+extern int video_register_device(struct video_device *, int type);
+
+#define VFL_TYPE_GRABBER 0
+#define VFL_TYPE_VBI 1
+#define VFL_TYPE_RADIO 2
+#define VFL_TYPE_VTX 3
+
+extern void video_unregister_device(struct video_device *);
+#endif
+
+
+#define VID_TYPE_CAPTURE 1 /* Can capture */
+#define VID_TYPE_TUNER 2 /* Can tune */
+#define VID_TYPE_TELETEXT 4 /* Does teletext */
+#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
+#define VID_TYPE_CLIPPING 32 /* Can clip */
+#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
+#define VID_TYPE_SCALES 128 /* Scalable */
+#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
+#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */
+
+struct video_capability
+{
+ char name[32];
+ int type;
+ int channels; /* Num channels */
+ int audios; /* Num audio devices */
+ int maxwidth; /* Supported width */
+ int maxheight; /* And height */
+ int minwidth; /* Supported width */
+ int minheight; /* And height */
+};
+
+
+struct video_channel
+{
+ int channel;
+ char name[32];
+ int tuners;
+ __u32 flags;
+#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
+#define VIDEO_VC_AUDIO 2 /* Channel has audio */
+ __u16 type;
+#define VIDEO_TYPE_TV 1
+#define VIDEO_TYPE_CAMERA 2
+ __u16 norm; /* Norm set by channel */
+};
+
+struct video_tuner
+{
+ int tuner;
+ char name[32];
+ ulong rangelow, rangehigh; /* Tuner range */
+ __u32 flags;
+#define VIDEO_TUNER_PAL 1
+#define VIDEO_TUNER_NTSC 2
+#define VIDEO_TUNER_SECAM 4
+#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
+#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */
+#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
+#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */
+#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */
+ __u16 mode; /* PAL/NTSC/SECAM/OTHER */
+#define VIDEO_MODE_PAL 0
+#define VIDEO_MODE_NTSC 1
+#define VIDEO_MODE_SECAM 2
+#define VIDEO_MODE_AUTO 3
+ __u16 signal; /* Signal strength 16bit scale */
+};
+
+struct video_picture
+{
+ __u16 brightness;
+ __u16 hue;
+ __u16 colour;
+ __u16 contrast;
+ __u16 whiteness; /* Black and white only */
+ __u16 depth; /* Capture depth */
+ __u16 palette; /* Palette in use */
+#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
+#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
+#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
+#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
+#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
+#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
+#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
+#define VIDEO_PALETTE_YUYV 8
+#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
+#define VIDEO_PALETTE_YUV420 10
+#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
+#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
+#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
+#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
+#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
+#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
+#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
+#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
+};
+
+struct video_audio
+{
+ int audio; /* Audio channel */
+ __u16 volume; /* If settable */
+ __u16 bass, treble;
+ __u32 flags;
+#define VIDEO_AUDIO_MUTE 1
+#define VIDEO_AUDIO_MUTABLE 2
+#define VIDEO_AUDIO_VOLUME 4
+#define VIDEO_AUDIO_BASS 8
+#define VIDEO_AUDIO_TREBLE 16
+ char name[16];
+#define VIDEO_SOUND_MONO 1
+#define VIDEO_SOUND_STEREO 2
+#define VIDEO_SOUND_LANG1 4
+#define VIDEO_SOUND_LANG2 8
+ __u16 mode;
+ __u16 balance; /* Stereo balance */
+ __u16 step; /* Step actual volume uses */
+};
+
+struct video_clip
+{
+ __s32 x,y;
+ __s32 width, height;
+ struct video_clip *next; /* For user use/driver use only */
+};
+
+struct video_window
+{
+ __u32 x,y; /* Position of window */
+ __u32 width,height; /* Its size */
+ __u32 chromakey;
+ __u32 flags;
+ struct video_clip *clips; /* Set only */
+ int clipcount;
+#define VIDEO_WINDOW_INTERLACE 1
+#define VIDEO_CLIP_BITMAP -1
+/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
+#define VIDEO_CLIPMAP_SIZE (128 * 625)
+};
+
+struct video_capture
+{
+ __u32 x,y; /* Offsets into image */
+ __u32 width, height; /* Area to capture */
+ __u16 decimation; /* Decimation divder */
+ __u16 flags; /* Flags for capture */
+#define VIDEO_CAPTURE_ODD 0 /* Temporal */
+#define VIDEO_CAPTURE_EVEN 1
+};
+
+struct video_buffer
+{
+ void *base;
+ int height,width;
+ int depth;
+ int bytesperline;
+};
+
+struct video_mmap
+{
+ unsigned int frame; /* Frame (0 - n) for double buffer */
+ int height,width;
+ unsigned int format; /* should be VIDEO_PALETTE_* */
+};
+
+struct video_key
+{
+ __u8 key[8];
+ __u32 flags;
+};
+
+
+#define VIDEO_MAX_FRAME 32
+
+struct video_mbuf
+{
+ int size; /* Total memory to map */
+ int frames; /* Frames */
+ int offsets[VIDEO_MAX_FRAME];
+};
+
+
+#define VIDEO_NO_UNIT (-1)
+
+
+struct video_unit
+{
+ int video; /* Video minor */
+ int vbi; /* VBI minor */
+ int radio; /* Radio minor */
+ int audio; /* Audio minor */
+ int teletext; /* Teletext minor */
+};
+
+#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
+#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
+#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */
+#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
+#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
+#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
+#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
+#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
+#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Set the video overlay window */
+#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
+#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
+#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
+#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
+#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
+#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
+#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
+#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
+#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
+#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
+#define VIDIOCGMBUF _IOR('v', 20, struct video_mbuf) /* Memory map buffer info */
+#define VIDIOCGUNIT _IOR('v', 21, struct video_unit) /* Get attached units */
+#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get frame buffer */
+#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set frame buffer - root only */
+
+#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
+
+
+#define VID_HARDWARE_BT848 1
+#define VID_HARDWARE_QCAM_BW 2
+#define VID_HARDWARE_PMS 3
+#define VID_HARDWARE_QCAM_C 4
+#define VID_HARDWARE_PSEUDO 5
+#define VID_HARDWARE_SAA5249 6
+#define VID_HARDWARE_AZTECH 7
+#define VID_HARDWARE_SF16MI 8
+#define VID_HARDWARE_RTRACK 9
+#define VID_HARDWARE_ZOLTRIX 10
+#define VID_HARDWARE_SAA7146 11
+#define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */
+#define VID_HARDWARE_RTRACK2 13
+#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */
+#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */
+#define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */
+#define VID_HARDWARE_BROADWAY 17 /* Broadway project */
+#define VID_HARDWARE_GEMTEK 18
+#define VID_HARDWARE_TYPHOON 19
+#define VID_HARDWARE_VINO 20 /* Reserved for SGI Indy Vino */
+#define VID_HARDWARE_CADET 21 /* Cadet radio */
+#define VID_HARDWARE_TRUST 22 /* Trust FM Radio */
+
+/*
+ * Initialiser list
+ */
+
+struct video_init
+{
+ char *name;
+ int (*init)(struct video_init *);
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/videotext.h b/pfinet/linux-src/include/linux/videotext.h
new file mode 100644
index 00000000..78faf6af
--- /dev/null
+++ b/pfinet/linux-src/include/linux/videotext.h
@@ -0,0 +1,144 @@
+#ifndef _VTX_H
+#define _VTX_H
+
+/* $Id: videotext.h,v 1.1 1998/03/30 22:26:39 alan Exp $
+ *
+ * Copyright (c) 1994-97 Martin Buck <martin-2.buck@student.uni-ulm.de>
+ * Read COPYING for more information
+ *
+ */
+
+
+/*
+ * Videotext ioctls
+ */
+#define VTXIOCGETINFO 0x7101 /* get version of driver & capabilities of vtx-chipset */
+#define VTXIOCCLRPAGE 0x7102 /* clear page-buffer */
+#define VTXIOCCLRFOUND 0x7103 /* clear bits indicating that page was found */
+#define VTXIOCPAGEREQ 0x7104 /* search for page */
+#define VTXIOCGETSTAT 0x7105 /* get status of page-buffer */
+#define VTXIOCGETPAGE 0x7106 /* get contents of page-buffer */
+#define VTXIOCSTOPDAU 0x7107 /* stop data acquisition unit */
+#define VTXIOCPUTPAGE 0x7108 /* display page on TV-screen */
+#define VTXIOCSETDISP 0x7109 /* set TV-mode */
+#define VTXIOCPUTSTAT 0x710a /* set status of TV-output-buffer */
+#define VTXIOCCLRCACHE 0x710b /* clear cache on VTX-interface (if avail.) */
+#define VTXIOCSETVIRT 0x710c /* turn on virtual mode (this disables TV-display) */
+
+
+/*
+ * Definitions for VTXIOCGETINFO
+ */
+
+#define SAA5243 0
+#define SAA5246 1
+#define SAA5249 2
+#define SAA5248 3
+#define XSTV5346 4
+
+typedef struct {
+ int version_major, version_minor; /* version of driver; if version_major changes, driver */
+ /* is not backward compatible!!! CHECK THIS!!! */
+ int numpages; /* number of page-buffers of vtx-chipset */
+ int cct_type; /* type of vtx-chipset (SAA5243, SAA5246, SAA5248 or
+ * SAA5249) */
+}
+vtx_info_t;
+
+
+/*
+ * Definitions for VTXIOC{CLRPAGE,CLRFOUND,PAGEREQ,GETSTAT,GETPAGE,STOPDAU,PUTPAGE,SETDISP}
+ */
+
+#define MIN_UNIT (1<<0)
+#define MIN_TEN (1<<1)
+#define HR_UNIT (1<<2)
+#define HR_TEN (1<<3)
+#define PG_UNIT (1<<4)
+#define PG_TEN (1<<5)
+#define PG_HUND (1<<6)
+#define PGMASK_MAX (1<<7)
+#define PGMASK_PAGE (PG_HUND | PG_TEN | PG_UNIT)
+#define PGMASK_HOUR (HR_TEN | HR_UNIT)
+#define PGMASK_MINUTE (MIN_TEN | MIN_UNIT)
+
+typedef struct
+{
+ int page; /* number of requested page (hexadecimal) */
+ int hour; /* requested hour (hexadecimal) */
+ int minute; /* requested minute (hexadecimal) */
+ int pagemask; /* mask defining which values of the above are set */
+ int pgbuf; /* buffer where page will be stored */
+ int start; /* start of requested part of page */
+ int end; /* end of requested part of page */
+ void *buffer; /* pointer to beginning of destination buffer */
+}
+vtx_pagereq_t;
+
+
+/*
+ * Definitions for VTXIOC{GETSTAT,PUTSTAT}
+ */
+
+#define VTX_PAGESIZE (40 * 24)
+#define VTX_VIRTUALSIZE (40 * 49)
+
+typedef struct
+{
+ int pagenum; /* number of page (hexadecimal) */
+ int hour; /* hour (hexadecimal) */
+ int minute; /* minute (hexadecimal) */
+ int charset; /* national charset */
+ unsigned delete : 1; /* delete page (C4) */
+ unsigned headline : 1; /* insert headline (C5) */
+ unsigned subtitle : 1; /* insert subtitle (C6) */
+ unsigned supp_header : 1; /* suppress header (C7) */
+ unsigned update : 1; /* update page (C8) */
+ unsigned inter_seq : 1; /* interrupted sequence (C9) */
+ unsigned dis_disp : 1; /* disable/suppress display (C10) */
+ unsigned serial : 1; /* serial mode (C11) */
+ unsigned notfound : 1; /* /FOUND */
+ unsigned pblf : 1; /* PBLF */
+ unsigned hamming : 1; /* hamming-error occurred */
+}
+vtx_pageinfo_t;
+
+
+/*
+ * Definitions for VTXIOCSETDISP
+ */
+
+typedef enum {
+ DISPOFF, DISPNORM, DISPTRANS, DISPINS, INTERLACE_OFFSET
+} vtxdisp_t;
+
+
+
+/*
+ * Tuner ioctls
+ */
+
+#define TUNIOCGETINFO 0x7201 /* get version of driver & capabilities of tuner */
+#define TUNIOCRESET 0x7202 /* reset tuner */
+#define TUNIOCSETFREQ 0x7203 /* set tuning frequency (unit: kHz) */
+#define TUNIOCGETFREQ 0x7204 /* get tuning frequency (unit: kHz) */
+#define TUNIOCSETCHAN 0x7205 /* set tuning channel */
+#define TUNIOCGETCHAN 0x7206 /* get tuning channel */
+
+
+typedef struct
+{
+ int version_major, version_minor; /* version of driver; if version_major changes, driver */
+ /* is not backward compatible!!! CHECK THIS!!! */
+ unsigned freq : 1; /* tuner can be set to given frequency */
+ unsigned chan : 1; /* tuner stores several channels */
+ unsigned scan : 1; /* tuner supports scanning */
+ unsigned autoscan : 1; /* tuner supports scanning with automatic stop */
+ unsigned afc : 1; /* tuner supports AFC */
+ unsigned dummy1, dummy2, dummy3, dummy4, dummy5, dummy6, dummy7, dummy8, dummy9, dummy10,
+ dummy11 : 1;
+ int dummy12, dummy13, dummy14, dummy15, dummy16, dummy17, dummy18, dummy19;
+} tuner_info_t;
+
+
+#endif /* _VTX_H */
diff --git a/pfinet/linux-src/include/linux/vmalloc.h b/pfinet/linux-src/include/linux/vmalloc.h
new file mode 100644
index 00000000..340544fd
--- /dev/null
+++ b/pfinet/linux-src/include/linux/vmalloc.h
@@ -0,0 +1,24 @@
+#ifndef __LINUX_VMALLOC_H
+#define __LINUX_VMALLOC_H
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+
+struct vm_struct {
+ unsigned long flags;
+ void * addr;
+ unsigned long size;
+ struct vm_struct * next;
+};
+
+struct vm_struct * get_vm_area(unsigned long size);
+void vfree(void * addr);
+void * vmalloc(unsigned long size);
+long vread(char *buf, char *addr, unsigned long count);
+void vmfree_area_pages(unsigned long address, unsigned long size);
+int vmalloc_area_pages(unsigned long address, unsigned long size);
+
+#endif
+
diff --git a/pfinet/linux-src/include/linux/vt.h b/pfinet/linux-src/include/linux/vt.h
new file mode 100644
index 00000000..9f95b0be
--- /dev/null
+++ b/pfinet/linux-src/include/linux/vt.h
@@ -0,0 +1,54 @@
+#ifndef _LINUX_VT_H
+#define _LINUX_VT_H
+
+/* 0x56 is 'V', to avoid collision with termios and kd */
+
+#define VT_OPENQRY 0x5600 /* find available vt */
+
+struct vt_mode {
+ char mode; /* vt mode */
+ char waitv; /* if set, hang on writes if not active */
+ short relsig; /* signal to raise on release req */
+ short acqsig; /* signal to raise on acquisition */
+ short frsig; /* unused (set to 0) */
+};
+#define VT_GETMODE 0x5601 /* get mode of active vt */
+#define VT_SETMODE 0x5602 /* set mode of active vt */
+#define VT_AUTO 0x00 /* auto vt switching */
+#define VT_PROCESS 0x01 /* process controls switching */
+#define VT_ACKACQ 0x02 /* acknowledge switch */
+
+struct vt_stat {
+ unsigned short v_active; /* active vt */
+ unsigned short v_signal; /* signal to send */
+ unsigned short v_state; /* vt bitmask */
+};
+#define VT_GETSTATE 0x5603 /* get global vt state info */
+#define VT_SENDSIG 0x5604 /* signal to send to bitmask of vts */
+
+#define VT_RELDISP 0x5605 /* release display */
+
+#define VT_ACTIVATE 0x5606 /* make vt active */
+#define VT_WAITACTIVE 0x5607 /* wait for vt active */
+#define VT_DISALLOCATE 0x5608 /* free memory associated to vt */
+
+struct vt_sizes {
+ unsigned short v_rows; /* number of rows */
+ unsigned short v_cols; /* number of columns */
+ unsigned short v_scrollsize; /* number of lines of scrollback */
+};
+#define VT_RESIZE 0x5609 /* set kernel's idea of screensize */
+
+struct vt_consize {
+ unsigned short v_rows; /* number of rows */
+ unsigned short v_cols; /* number of columns */
+ unsigned short v_vlin; /* number of pixel rows on screen */
+ unsigned short v_clin; /* number of pixel rows per character */
+ unsigned short v_vcol; /* number of pixel columns on screen */
+ unsigned short v_ccol; /* number of pixel columns per character */
+};
+#define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */
+#define VT_LOCKSWITCH 0x560B /* disallow vt switching */
+#define VT_UNLOCKSWITCH 0x560C /* allow vt switching */
+
+#endif /* _LINUX_VT_H */
diff --git a/pfinet/linux-src/include/linux/vt_buffer.h b/pfinet/linux-src/include/linux/vt_buffer.h
new file mode 100644
index 00000000..ca1ec519
--- /dev/null
+++ b/pfinet/linux-src/include/linux/vt_buffer.h
@@ -0,0 +1,83 @@
+/*
+ * include/linux/vt_buffer.h -- Access to VT screen buffer
+ *
+ * (c) 1998 Martin Mares <mj@ucw.cz>
+ *
+ * This is a set of macros and functions which are used in the
+ * console driver and related code to access the screen buffer.
+ * In most cases the console works with simple in-memory buffer,
+ * but when handling hardware text mode consoles, we store
+ * the foreground console directly in video memory.
+ */
+
+#ifndef _LINUX_VT_BUFFER_H_
+#define _LINUX_VT_BUFFER_H_
+
+#include <linux/config.h>
+
+#ifdef CONFIG_VGA_CONSOLE
+#include <asm/vga.h>
+#endif
+
+#ifndef VT_BUF_HAVE_RW
+#define scr_writew(val, addr) (*(addr) = (val))
+#define scr_readw(addr) (*(addr))
+#define scr_memcpyw(d, s, c) memcpy(d, s, c)
+#define scr_memmovew(d, s, c) memmove(d, s, c)
+#define VT_BUF_HAVE_MEMCPYW
+#define VT_BUF_HAVE_MEMMOVEW
+#define scr_memcpyw_from(d, s, c) memcpy(d, s, c)
+#define scr_memcpyw_to(d, s, c) memcpy(d, s, c)
+#define VT_BUF_HAVE_MEMCPYF
+#endif
+
+#ifndef VT_BUF_HAVE_MEMSETW
+extern inline void scr_memsetw(u16 *s, u16 c, unsigned int count)
+{
+ count /= 2;
+ while (count--)
+ scr_writew(c, s++);
+}
+#endif
+
+#ifndef VT_BUF_HAVE_MEMCPYW
+extern inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
+{
+ count /= 2;
+ while (count--)
+ scr_writew(scr_readw(s++), d++);
+}
+#endif
+
+#ifndef VT_BUF_HAVE_MEMMOVEW
+extern inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count)
+{
+ if (d < s)
+ scr_memcpyw(d, s, count);
+ else {
+ count /= 2;
+ d += count;
+ s += count;
+ while (count--)
+ scr_writew(scr_readw(--s), --d);
+ }
+}
+#endif
+
+#ifndef VT_BUF_HAVE_MEMCPYF
+extern inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count)
+{
+ count /= 2;
+ while (count--)
+ *d++ = scr_readw(s++);
+}
+
+extern inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count)
+{
+ count /= 2;
+ while (count--)
+ scr_writew(*s++, d++);
+}
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/vt_kern.h b/pfinet/linux-src/include/linux/vt_kern.h
new file mode 100644
index 00000000..e1b72768
--- /dev/null
+++ b/pfinet/linux-src/include/linux/vt_kern.h
@@ -0,0 +1,94 @@
+#ifndef _VT_KERN_H
+#define _VT_KERN_H
+
+/*
+ * this really is an extension of the vc_cons structure in console.c, but
+ * with information needed by the vt package
+ */
+
+#include <linux/config.h>
+#include <linux/vt.h>
+
+/*
+ * Presently, a lot of graphics programs do not restore the contents of
+ * the higher font pages. Defining this flag will avoid use of them, but
+ * will lose support for PIO_FONTRESET. Note that many font operations are
+ * not likely to work with these programs anyway; they need to be
+ * fixed. The linux/Documentation directory includes a code snippet
+ * to save and restore the text font.
+ */
+#ifdef CONFIG_VGA_CONSOLE
+#define BROKEN_GRAPHICS_PROGRAMS 1
+#endif
+
+extern struct vt_struct {
+ int vc_num; /* The console number */
+ unsigned char vc_mode; /* KD_TEXT, ... */
+ struct vt_mode vt_mode;
+ int vt_pid;
+ int vt_newvt;
+ struct wait_queue *paste_wait;
+} *vt_cons[MAX_NR_CONSOLES];
+
+void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+
+/* console.c */
+
+struct console_font_op;
+struct consw;
+
+int vc_allocate(unsigned int console);
+int vc_cons_allocated(unsigned int console);
+int vc_resize(unsigned int lines, unsigned int cols,
+ unsigned int first, unsigned int last);
+#define vc_resize_all(l, c) vc_resize(l, c, 0, MAX_NR_CONSOLES-1)
+#define vc_resize_con(l, c, x) vc_resize(l, c, x, x)
+void vc_disallocate(unsigned int console);
+void reset_palette(int currcons);
+void set_palette(int currcons);
+void do_blank_screen(int gfx_mode);
+void unblank_screen(void);
+void poke_blanked_console(void);
+int con_font_op(int currcons, struct console_font_op *op);
+int con_set_cmap(unsigned char *cmap);
+int con_get_cmap(unsigned char *cmap);
+void scrollback(int);
+void scrollfront(int);
+void update_region(int currcons, unsigned long start, int count);
+void redraw_screen(int new_console, int is_switch);
+#define update_screen(x) redraw_screen(x, 0)
+#define switch_screen(x) redraw_screen(x, 1)
+
+struct tty_struct;
+int tioclinux(struct tty_struct *tty, unsigned long arg);
+
+/* consolemap.c */
+
+struct unimapinit;
+struct unipair;
+
+int con_set_trans_old(unsigned char * table);
+int con_get_trans_old(unsigned char * table);
+int con_set_trans_new(unsigned short * table);
+int con_get_trans_new(unsigned short * table);
+int con_clear_unimap(int currcons, struct unimapinit *ui);
+int con_set_unimap(int currcons, ushort ct, struct unipair *list);
+int con_get_unimap(int currcons, ushort ct, ushort *uct, struct unipair *list);
+int con_set_default_unimap(int currcons);
+void con_free_unimap(int currcons);
+void con_protect_unimap(int currcons, int rdonly);
+int con_copy_unimap(int dstcons, int srccons);
+
+/* vt.c */
+
+extern unsigned int video_font_height;
+extern unsigned int default_font_height;
+extern unsigned int video_scan_lines;
+
+void complete_change_console(unsigned int new_console);
+int vt_waitactive(int vt);
+void change_console(unsigned int);
+void reset_vc(unsigned int new_console);
+int vt_waitactive(int vt);
+
+#endif /* _VT_KERN_H */
diff --git a/pfinet/linux-src/include/linux/wait.h b/pfinet/linux-src/include/linux/wait.h
new file mode 100644
index 00000000..6514693c
--- /dev/null
+++ b/pfinet/linux-src/include/linux/wait.h
@@ -0,0 +1,33 @@
+#ifndef _LINUX_WAIT_H
+#define _LINUX_WAIT_H
+
+#define WNOHANG 0x00000001
+#define WUNTRACED 0x00000002
+
+#define __WCLONE 0x80000000
+
+#ifdef __KERNEL__
+
+#include <asm/page.h>
+
+struct wait_queue {
+ struct task_struct * task;
+ struct wait_queue * next;
+};
+
+#define WAIT_QUEUE_HEAD(x) ((struct wait_queue *)((x)-1))
+
+static inline void init_waitqueue(struct wait_queue **q)
+{
+ *q = WAIT_QUEUE_HEAD(q);
+}
+
+static inline int waitqueue_active(struct wait_queue **q)
+{
+ struct wait_queue *head = *q;
+ return head && head != WAIT_QUEUE_HEAD(q);
+}
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/pfinet/linux-src/include/linux/wanpipe.h b/pfinet/linux-src/include/linux/wanpipe.h
new file mode 100644
index 00000000..f0dbd6f5
--- /dev/null
+++ b/pfinet/linux-src/include/linux/wanpipe.h
@@ -0,0 +1,372 @@
+/*****************************************************************************
+* wanpipe.h WANPIPE(tm) Multiprotocol WAN Link Driver.
+* User-level API definitions.
+*
+* Author: Nenad Corbic <ncorbic@sangoma.com>
+* Gideon Hack
+*
+* Copyright: (c) 1995-1999 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Oct 04, 1999 Nenad Corbic New CHDLC and FRAME RELAY code, SMP support
+* Jun 02, 1999 Gideon Hack Added 'update_call_count' for Cisco HDLC
+* support
+* Jun 26, 1998 David Fong Added 'ip_mode' in sdla_t.u.p for dynamic IP
+* routing mode configuration
+* Jun 12, 1998 David Fong Added Cisco HDLC union member in sdla_t
+* Dec 08, 1997 Jaspreet Singh Added 'authenticator' in union of 'sdla_t'
+* Nov 26, 1997 Jaspreet Singh Added 'load_sharing' structure. Also added
+* 'devs_struct','dev_to_devtint_next' to 'sdla_t'
+* Nov 24, 1997 Jaspreet Singh Added 'irq_dis_if_send_count',
+* 'irq_dis_poll_count' to 'sdla_t'.
+* Nov 06, 1997 Jaspreet Singh Added a define called 'INTR_TEST_MODE'
+* Oct 20, 1997 Jaspreet Singh Added 'buff_intr_mode_unbusy' and
+* 'dlci_intr_mode_unbusy' to 'sdla_t'
+* Oct 18, 1997 Jaspreet Singh Added structure to maintain global driver
+* statistics.
+* Jan 15, 1997 Gene Kozin Version 3.1.0
+* o added UDP management stuff
+* Jan 02, 1997 Gene Kozin Version 3.0.0
+*****************************************************************************/
+#ifndef _WANPIPE_H
+#define _WANPIPE_H
+
+#ifdef __SMP__
+#include <asm/spinlock.h> /* Support for SMP Locking */
+#endif
+
+#include <linux/wanrouter.h>
+
+/* Defines */
+
+#ifndef PACKED
+#define PACKED __attribute__((packed))
+#endif
+
+#define WANPIPE_MAGIC 0x414C4453L /* signatire: 'SDLA' reversed */
+
+/* IOCTL numbers (up to 16) */
+#define WANPIPE_DUMP (ROUTER_USER+0) /* dump adapter's memory */
+#define WANPIPE_EXEC (ROUTER_USER+1) /* execute firmware command */
+
+#define TRACE_ALL 0x00
+#define TRACE_PROT 0x01
+#define TRACE_DATA 0x02
+
+/* values for request/reply byte */
+#define UDPMGMT_REQUEST 0x01
+#define UDPMGMT_REPLY 0x02
+#define UDP_OFFSET 12
+
+
+/*
+ * Data structures for IOCTL calls.
+ */
+
+typedef struct sdla_dump /* WANPIPE_DUMP */
+{
+ unsigned long magic; /* for verification */
+ unsigned long offset; /* absolute adapter memory address */
+ unsigned long length; /* block length */
+ void* ptr; /* -> buffer */
+} sdla_dump_t;
+
+typedef struct sdla_exec /* WANPIPE_EXEC */
+{
+ unsigned long magic; /* for verification */
+ void* cmd; /* -> command structure */
+ void* data; /* -> data buffer */
+} sdla_exec_t;
+
+/* UDP management stuff */
+
+typedef struct wum_header
+{
+ unsigned char signature[8]; /* 00h: signature */
+ unsigned char type; /* 08h: request/reply */
+ unsigned char command; /* 09h: commnand */
+ unsigned char reserved[6]; /* 0Ah: reserved */
+} wum_header_t;
+
+/*************************************************************************
+ Data Structure for global statistics
+*************************************************************************/
+
+typedef struct global_stats
+{
+ unsigned long isr_entry;
+ unsigned long isr_already_critical;
+ unsigned long isr_rx;
+ unsigned long isr_tx;
+ unsigned long isr_intr_test;
+ unsigned long isr_spurious;
+ unsigned long isr_enable_tx_int;
+ unsigned long rx_intr_corrupt_rx_bfr;
+ unsigned long rx_intr_on_orphaned_DLCI;
+ unsigned long rx_intr_dev_not_started;
+ unsigned long tx_intr_dev_not_started;
+ unsigned long poll_entry;
+ unsigned long poll_already_critical;
+ unsigned long poll_processed;
+ unsigned long poll_tbusy_bad_status;
+ unsigned long poll_host_disable_irq;
+ unsigned long poll_host_enable_irq;
+
+} global_stats_t;
+
+
+typedef struct{
+ unsigned short udp_src_port PACKED;
+ unsigned short udp_dst_port PACKED;
+ unsigned short udp_length PACKED;
+ unsigned short udp_checksum PACKED;
+} udp_pkt_t;
+
+
+typedef struct {
+ unsigned char ver_inet_hdr_length PACKED;
+ unsigned char service_type PACKED;
+ unsigned short total_length PACKED;
+ unsigned short identifier PACKED;
+ unsigned short flags_frag_offset PACKED;
+ unsigned char ttl PACKED;
+ unsigned char protocol PACKED;
+ unsigned short hdr_checksum PACKED;
+ unsigned long ip_src_address PACKED;
+ unsigned long ip_dst_address PACKED;
+} ip_pkt_t;
+
+
+typedef struct {
+ unsigned char signature[8] PACKED;
+ unsigned char request_reply PACKED;
+ unsigned char id PACKED;
+ unsigned char reserved[6] PACKED;
+} wp_mgmt_t;
+
+/*************************************************************************
+ Data Structure for if_send statistics
+*************************************************************************/
+typedef struct if_send_stat{
+ unsigned long if_send_entry;
+ unsigned long if_send_skb_null;
+ unsigned long if_send_broadcast;
+ unsigned long if_send_multicast;
+ unsigned long if_send_critical_ISR;
+ unsigned long if_send_critical_non_ISR;
+ unsigned long if_send_tbusy;
+ unsigned long if_send_tbusy_timeout;
+ unsigned long if_send_PIPE_request;
+ unsigned long if_send_wan_disconnected;
+ unsigned long if_send_dlci_disconnected;
+ unsigned long if_send_no_bfrs;
+ unsigned long if_send_adptr_bfrs_full;
+ unsigned long if_send_bfr_passed_to_adptr;
+ unsigned long if_send_protocol_error;
+ unsigned long if_send_bfr_not_passed_to_adptr;
+ unsigned long if_send_tx_int_enabled;
+ unsigned long if_send_consec_send_fail;
+} if_send_stat_t;
+
+typedef struct rx_intr_stat{
+ unsigned long rx_intr_no_socket;
+ unsigned long rx_intr_dev_not_started;
+ unsigned long rx_intr_PIPE_request;
+ unsigned long rx_intr_bfr_not_passed_to_stack;
+ unsigned long rx_intr_bfr_passed_to_stack;
+} rx_intr_stat_t;
+
+typedef struct pipe_mgmt_stat{
+ unsigned long UDP_PIPE_mgmt_kmalloc_err;
+ unsigned long UDP_PIPE_mgmt_direction_err;
+ unsigned long UDP_PIPE_mgmt_adptr_type_err;
+ unsigned long UDP_PIPE_mgmt_adptr_cmnd_OK;
+ unsigned long UDP_PIPE_mgmt_adptr_cmnd_timeout;
+ unsigned long UDP_PIPE_mgmt_adptr_send_passed;
+ unsigned long UDP_PIPE_mgmt_adptr_send_failed;
+ unsigned long UDP_PIPE_mgmt_not_passed_to_stack;
+ unsigned long UDP_PIPE_mgmt_passed_to_stack;
+ unsigned long UDP_PIPE_mgmt_no_socket;
+ unsigned long UDP_PIPE_mgmt_passed_to_adptr;
+} pipe_mgmt_stat_t;
+
+
+
+#define MAX_LGTH_UDP_MGNT_PKT 2000
+
+
+/* This is used for interrupt testing */
+#define INTR_TEST_MODE 0x02
+
+#define WUM_SIGNATURE_L 0x50495046
+#define WUM_SIGNATURE_H 0x444E3845
+
+#define WUM_KILL 0x50
+#define WUM_EXEC 0x51
+
+#ifdef __KERNEL__
+/****** Kernel Interface ****************************************************/
+
+#include <linux/sdladrv.h> /* SDLA support module API definitions */
+#include <linux/sdlasfm.h> /* SDLA firmware module definitions */
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0)
+#define is_alpha(ch) ((((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'z')||\
+ ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'Z'))?1:0)
+#define is_hex_digit(ch) ((((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')||\
+ ((ch)>=(unsigned)'a'&&(ch)<=(unsigned)'f')||\
+ ((ch)>=(unsigned)'A'&&(ch)<=(unsigned)'F'))?1:0)
+
+/****** Data Structures *****************************************************/
+
+/* Adapter Data Space.
+ * This structure is needed because we handle multiple cards, otherwise
+ * static data would do it.
+ */
+typedef struct sdla
+{
+ char devname[WAN_DRVNAME_SZ+1]; /* card name */
+ sdlahw_t hw; /* hardware configuration */
+ wan_device_t wandev; /* WAN device data space */
+ unsigned open_cnt; /* number of open interfaces */
+ unsigned long state_tick; /* link state timestamp */
+ unsigned intr_mode; /* Type of Interrupt Mode */
+ char in_isr; /* interrupt-in-service flag */
+ char buff_int_mode_unbusy; /* flag for carrying out dev_tint */
+ char dlci_int_mode_unbusy; /* flag for carrying out dev_tint */
+ char configured; /* flag for previous configurations */
+ unsigned short irq_dis_if_send_count; /* Disabling irqs in if_send*/
+ unsigned short irq_dis_poll_count; /* Disabling irqs in poll routine*/
+ unsigned short force_enable_irq;
+ char TracingEnabled; /* flag for enabling trace */
+ global_stats_t statistics; /* global statistics */
+#ifdef __SMP__
+ spinlock_t lock; /* Support for SMP Locking */
+#endif
+ void* mbox; /* -> mailbox */
+ void* rxmb; /* -> receive mailbox */
+ void* flags; /* -> adapter status flags */
+ void (*isr)(struct sdla* card); /* interrupt service routine */
+ void (*poll)(struct sdla* card); /* polling routine */
+ int (*exec)(struct sdla* card, void* u_cmd, void* u_data);
+
+ struct sdla *next; /* Secondary Port Device: Piggibacking */
+ union
+ {
+ struct
+ { /****** X.25 specific data **********/
+ unsigned lo_pvc;
+ unsigned hi_pvc;
+ unsigned lo_svc;
+ unsigned hi_svc;
+ } x;
+ struct
+ { /****** frame relay specific data ***/
+ void* rxmb_base; /* -> first Rx buffer */
+ void* rxmb_last; /* -> last Rx buffer */
+ unsigned rx_base; /* S508 receive buffer base */
+ unsigned rx_top; /* S508 receive buffer end */
+ unsigned short node_dlci[100];
+ unsigned short dlci_num;
+ struct device *dlci_to_dev_map[991 + 1];
+ unsigned tx_interrupts_pending;
+ unsigned short timer_int_enabled;
+ unsigned short udp_pkt_lgth;
+ int udp_type;
+ char udp_pkt_src;
+ unsigned udp_dlci;
+ char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
+ void* trc_el_base; /* first trace element */
+ void* trc_el_last; /* last trace element */
+ void *curr_trc_el; /* current trace element */
+ unsigned short trc_bfr_space; /* trace buffer space */
+ unsigned char update_comms_stats;
+ } f;
+ struct /****** PPP-specific data ***********/
+ {
+ char if_name[WAN_IFNAME_SZ+1]; /* interface name */
+ void* txbuf; /* -> current Tx buffer */
+ void* txbuf_base; /* -> first Tx buffer */
+ void* txbuf_last; /* -> last Tx buffer */
+ void* rxbuf_base; /* -> first Rx buffer */
+ void* rxbuf_last; /* -> last Rx buffer */
+ unsigned rx_base; /* S508 receive buffer base */
+ unsigned rx_top; /* S508 receive buffer end */
+ char ip_mode; /* STATIC/HOST/PEER IP Mode */
+ char authenticator; /* Authenticator for PAP/CHAP */
+ } p;
+ struct /* Cisco HDLC-specific data */
+ {
+ char if_name[WAN_IFNAME_SZ+1]; /* interface name */
+ unsigned char comm_port;/* Communication Port O or 1 */
+ unsigned char usedby; /* Used by WANPIPE or API */
+ void* rxmb; /* Receive mail box */
+ void* flags; /* flags */
+ void* tx_status; /* Tx status element */
+ void* rx_status; /* Rx status element */
+ void* txbuf; /* -> current Tx buffer */
+ void* txbuf_base; /* -> first Tx buffer */
+ void* txbuf_last; /* -> last Tx buffer */
+ void* rxbuf_base; /* -> first Rx buffer */
+ void* rxbuf_last; /* -> last Rx buffer */
+ unsigned rx_base; /* S508 receive buffer base */
+ unsigned rx_top; /* S508 receive buffer end */
+ unsigned short protocol_options;
+ unsigned short kpalv_tx; /* Tx kpalv timer */
+ unsigned short kpalv_rx; /* Rx kpalv timer */
+ unsigned short kpalv_err; /* Error tolerance */
+ unsigned short slarp_timer; /* SLARP req timer */
+ unsigned state; /* state of the link */
+ unsigned char api_status;
+ unsigned char update_call_count;
+ } c;
+ struct
+ {
+ void* tx_status; /* Tx status element */
+ void* rx_status; /* Rx status element */
+ void* trace_status; /* Trace status element */
+ void* txbuf; /* -> current Tx buffer */
+ void* txbuf_base; /* -> first Tx buffer */
+ void* txbuf_last; /* -> last Tx buffer */
+ void* rxbuf_base; /* -> first Rx buffer */
+ void* rxbuf_last; /* -> last Rx buffer */
+ void* tracebuf; /* -> current Trace buffer */
+ void* tracebuf_base; /* -> current Trace buffer */
+ void* tracebuf_last; /* -> current Trace buffer */
+ unsigned rx_base; /* receive buffer base */
+ unsigned rx_end; /* receive buffer end */
+ unsigned trace_base; /* trace buffer base */
+ unsigned trace_end; /* trace buffer end */
+
+ } h;
+ } u;
+} sdla_t;
+
+/****** Public Functions ****************************************************/
+
+void wanpipe_open (sdla_t* card); /* wpmain.c */
+void wanpipe_close (sdla_t* card); /* wpmain.c */
+void wanpipe_set_state (sdla_t* card, int state); /* wpmain.c */
+
+int wpx_init (sdla_t* card, wandev_conf_t* conf); /* wpx.c */
+int wpf_init (sdla_t* card, wandev_conf_t* conf); /* wpf.c */
+int wpp_init (sdla_t* card, wandev_conf_t* conf); /* wpp.c */
+int wpc_init (sdla_t* card, wandev_conf_t* conf); /* Cisco HDLC */
+int bsc_init (sdla_t* card, wandev_conf_t* conf); /* BSC streaming */
+int hdlc_init(sdla_t* card, wandev_conf_t* conf); /* HDLC support */
+int wpft1_init (sdla_t* card, wandev_conf_t* conf); /* FT1 Config support */
+
+#endif /* __KERNEL__ */
+#endif /* _WANPIPE_H */
+
diff --git a/pfinet/linux-src/include/linux/wanrouter.h b/pfinet/linux-src/include/linux/wanrouter.h
new file mode 100644
index 00000000..530783f7
--- /dev/null
+++ b/pfinet/linux-src/include/linux/wanrouter.h
@@ -0,0 +1,476 @@
+/*****************************************************************************
+* wanrouter.h Definitions for the WAN Multiprotocol Router Module.
+* This module provides API and common services for WAN Link
+* Drivers and is completely hardware-independent.
+*
+* Author: Nenad Corbic <ncorbic@sangoma.com>
+* Gideon Hack
+*
+* Copyright: (c) 1995-1999 Sangoma Technologies 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 of the License, or (at your option) any later version.
+* ============================================================================
+* Oct 04, 1999 Nenad Corbic Updated for 2.1.0 release
+* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
+* Jul 20, 1998 David Fong Added Inverse ARP options to 'wanif_conf_t'
+* Jun 12, 1998 David Fong Added Cisco HDLC support.
+* Dec 16, 1997 Jaspreet Singh Moved 'enable_IPX' and 'network_number' to
+* 'wanif_conf_t'
+* Dec 05, 1997 Jaspreet Singh Added 'pap', 'chap' to 'wanif_conf_t'
+* Added 'authenticator' to 'wan_ppp_conf_t'
+* Nov 06, 1997 Jaspreet Singh Changed Router Driver version to 1.1 from 1.0
+* Oct 20, 1997 Jaspreet Singh Added 'cir','bc','be' and 'mc' to 'wanif_conf_t'
+* Added 'enable_IPX' and 'network_number' to
+* 'wan_device_t'. Also added defines for
+* UDP PACKET TYPE, Interrupt test, critical values
+* for RACE conditions.
+* Oct 05, 1997 Jaspreet Singh Added 'dlci_num' and 'dlci[100]' to
+* 'wan_fr_conf_t' to configure a list of dlci(s)
+* for a NODE
+* Jul 07, 1997 Jaspreet Singh Added 'ttl' to 'wandev_conf_t' & 'wan_device_t'
+* May 29, 1997 Jaspreet Singh Added 'tx_int_enabled' to 'wan_device_t'
+* May 21, 1997 Jaspreet Singh Added 'udp_port' to 'wan_device_t'
+* Apr 25, 1997 Farhan Thawar Added 'udp_port' to 'wandev_conf_t'
+* Jan 16, 1997 Gene Kozin router_devlist made public
+* Jan 02, 1997 Gene Kozin Initial version (based on wanpipe.h).
+*****************************************************************************/
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x020100
+#define LINUX_2_1
+#endif
+
+#ifndef _ROUTER_H
+#define _ROUTER_H
+
+#define ROUTER_NAME "wanrouter" /* in case we ever change it */
+#define ROUTER_VERSION 1 /* version number */
+#define ROUTER_RELEASE 1 /* release (minor version) number */
+#define ROUTER_IOCTL 'W' /* for IOCTL calls */
+#define ROUTER_MAGIC 0x524D4157L /* signature: 'WANR' reversed */
+
+/* IOCTL codes for /proc/router/<device> entries (up to 255) */
+enum router_ioctls
+{
+ ROUTER_SETUP = ROUTER_IOCTL<<8, /* configure device */
+ ROUTER_DOWN, /* shut down device */
+ ROUTER_STAT, /* get device status */
+ ROUTER_IFNEW, /* add interface */
+ ROUTER_IFDEL, /* delete interface */
+ ROUTER_IFSTAT, /* get interface status */
+ ROUTER_USER = (ROUTER_IOCTL<<8)+16, /* driver-specific calls */
+ ROUTER_USER_MAX = (ROUTER_IOCTL<<8)+31
+};
+
+/* identifiers for displaying proc file data for dual port adapters */
+#define PROC_DATA_PORT_0 0x8000 /* the data is for port 0 */
+#define PROC_DATA_PORT_1 0x8001 /* the data is for port 1 */
+
+/* NLPID for packet encapsulation (ISO/IEC TR 9577) */
+#define NLPID_IP 0xCC /* Internet Protocol Datagram */
+#define NLPID_SNAP 0x80 /* IEEE Subnetwork Access Protocol */
+#define NLPID_CLNP 0x81 /* ISO/IEC 8473 */
+#define NLPID_ESIS 0x82 /* ISO/IEC 9542 */
+#define NLPID_ISIS 0x83 /* ISO/IEC ISIS */
+#define NLPID_Q933 0x08 /* CCITT Q.933 */
+
+/* Miscellaneous */
+#define WAN_IFNAME_SZ 15 /* max length of the interface name */
+#define WAN_DRVNAME_SZ 15 /* max length of the link driver name */
+#define WAN_ADDRESS_SZ 31 /* max length of the WAN media address */
+#define USED_BY_FIELD 8 /* max length of the used by field */
+
+/* Defines for UDP PACKET TYPE */
+#define UDP_PTPIPE_TYPE 0x01
+#define UDP_FPIPE_TYPE 0x02
+#define UDP_CPIPE_TYPE 0x03
+#define UDP_DRVSTATS_TYPE 0x04
+#define UDP_INVALID_TYPE 0x05
+
+/* Command return code */
+#define CMD_OK 0 /* normal firmware return code */
+#define CMD_TIMEOUT 0xFF /* firmware command timed out */
+
+/* UDP Packet Management */
+#define UDP_PKT_FRM_STACK 0x00
+#define UDP_PKT_FRM_NETWORK 0x01
+
+/* Maximum interrupt test counter */
+#define MAX_INTR_TEST_COUNTER 100
+
+/* Critical Values for RACE conditions*/
+#define CRITICAL_IN_ISR 0xA1
+#define CRITICAL_INTR_HANDLED 0xB1
+
+/****** Data Types **********************************************************/
+
+/*----------------------------------------------------------------------------
+ * X.25-specific link-level configuration.
+ */
+typedef struct wan_x25_conf
+{
+ unsigned lo_pvc; /* lowest permanent circuit number */
+ unsigned hi_pvc; /* highest permanent circuit number */
+ unsigned lo_svc; /* lowest switched circuit number */
+ unsigned hi_svc; /* highest switched circuit number */
+ unsigned hdlc_window; /* HDLC window size (1..7) */
+ unsigned pkt_window; /* X.25 packet window size (1..7) */
+ unsigned t1; /* HDLC timer T1, sec (1..30) */
+ unsigned t2; /* HDLC timer T2, sec (0..29) */
+ unsigned t4; /* HDLC supervisory frame timer = T4 * T1 */
+ unsigned n2; /* HDLC retransmission limit (1..30) */
+ unsigned t10_t20; /* X.25 RESTART timeout, sec (1..255) */
+ unsigned t11_t21; /* X.25 CALL timeout, sec (1..255) */
+ unsigned t12_t22; /* X.25 RESET timeout, sec (1..255) */
+ unsigned t13_t23; /* X.25 CLEAR timeout, sec (1..255) */
+ unsigned t16_t26; /* X.25 INTERRUPT timeout, sec (1..255) */
+ unsigned t28; /* X.25 REGISTRATION timeout, sec (1..255) */
+ unsigned r10_r20; /* RESTART retransmission limit (0..250) */
+ unsigned r12_r22; /* RESET retransmission limit (0..250) */
+ unsigned r13_r23; /* CLEAR retransmission limit (0..250) */
+ unsigned ccitt_compat; /* compatibility mode: 1988/1984/1980 */
+} wan_x25_conf_t;
+
+/*----------------------------------------------------------------------------
+ * Frame relay specific link-level configuration.
+ */
+typedef struct wan_fr_conf
+{
+ unsigned signalling; /* local in-channel signalling type */
+ unsigned t391; /* link integrity verification timer */
+ unsigned t392; /* polling verification timer */
+ unsigned n391; /* full status polling cycle counter */
+ unsigned n392; /* error threshold counter */
+ unsigned n393; /* monitored events counter */
+ unsigned dlci_num; /* number of DLCs (access node) */
+ unsigned dlci[100]; /* List of all DLCIs */
+} wan_fr_conf_t;
+
+/*----------------------------------------------------------------------------
+ * PPP-specific link-level configuration.
+ */
+typedef struct wan_ppp_conf
+{
+ unsigned restart_tmr; /* restart timer */
+ unsigned auth_rsrt_tmr; /* authentication timer */
+ unsigned auth_wait_tmr; /* authentication timer */
+ unsigned mdm_fail_tmr; /* modem failure timer */
+ unsigned dtr_drop_tmr; /* DTR drop timer */
+ unsigned connect_tmout; /* connection timeout */
+ unsigned conf_retry; /* max. retry */
+ unsigned term_retry; /* max. retry */
+ unsigned fail_retry; /* max. retry */
+ unsigned auth_retry; /* max. retry */
+ unsigned auth_options; /* authentication opt. */
+ unsigned ip_options; /* IP options */
+ char authenticator; /* AUTHENTICATOR or not */
+ char ip_mode; /* Static/Host/Peer */
+} wan_ppp_conf_t;
+
+/*----------------------------------------------------------------------------
+ * CHDLC-specific link-level configuration.
+ */
+typedef struct wan_chdlc_conf
+{
+ unsigned char ignore_dcd; /* Protocol options: */
+ unsigned char ignore_cts; /* Ignore these to determine */
+ unsigned char ignore_keepalive; /* link status (Yes or No) */
+ unsigned char hdlc_streaming; /* hdlc_streaming mode (Y/N) */
+ unsigned keepalive_tx_tmr; /* transmit keepalive timer */
+ unsigned keepalive_rx_tmr; /* receive keepalive timer */
+ unsigned keepalive_err_margin; /* keepalive_error_tolerance */
+ unsigned slarp_timer; /* SLARP request timer */
+} wan_chdlc_conf_t;
+
+
+/*----------------------------------------------------------------------------
+ * WAN device configuration. Passed to ROUTER_SETUP IOCTL.
+ */
+typedef struct wandev_conf
+{
+ unsigned magic; /* magic number (for verification) */
+ unsigned config_id; /* configuration structure identifier */
+ /****** hardware configuration ******/
+ unsigned ioport; /* adapter I/O port base */
+ unsigned long maddr; /* dual-port memory address */
+ unsigned msize; /* dual-port memory size */
+ int irq; /* interrupt request level */
+ int dma; /* DMA request level */
+ char S514_CPU_no[1]; /* S514 PCI adapter CPU number ('A' or 'B') */
+ unsigned PCI_slot_no; /* S514 PCI adapter slot number */
+ char comm_port; /* Communication Port (PRI=0, SEC=1) */
+ unsigned bps; /* data transfer rate */
+ unsigned mtu; /* maximum transmit unit size */
+ unsigned udp_port; /* UDP port for management */
+ unsigned char ttl; /* Time To Live for UDP security */
+ unsigned char ft1; /* FT1 Configurator Option */
+ char interface; /* RS-232/V.35, etc. */
+ char clocking; /* external/internal */
+ char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */
+ char station; /* DTE/DCE, primary/secondary, etc. */
+ char connection; /* permanent/switched/on-demand */
+ char read_mode; /* read mode: Polling or interrupt */
+ unsigned hw_opt[4]; /* other hardware options */
+ unsigned reserved[4];
+ /****** arbitrary data ***************/
+ unsigned data_size; /* data buffer size */
+ void* data; /* data buffer, e.g. firmware */
+ union /****** protocol-specific ************/
+ {
+ wan_x25_conf_t x25; /* X.25 configuration */
+ wan_ppp_conf_t ppp; /* PPP configuration */
+ wan_fr_conf_t fr; /* frame relay configuration */
+ wan_chdlc_conf_t chdlc; /* Cisco HDLC configuration */
+ } u;
+} wandev_conf_t;
+
+/* 'config_id' definitions */
+#define WANCONFIG_X25 101 /* X.25 link */
+#define WANCONFIG_FR 102 /* frame relay link */
+#define WANCONFIG_PPP 103 /* synchronous PPP link */
+#define WANCONFIG_CHDLC 104 /* Cisco HDLC Link */
+#define WANCONFIG_BSC 105 /* BiSync Streaming */
+#define WANCONFIG_HDLC 106 /* HDLC Support */
+
+/*
+ * Configuration options defines.
+ */
+/* general options */
+#define WANOPT_OFF 0
+#define WANOPT_ON 1
+#define WANOPT_NO 0
+#define WANOPT_YES 1
+
+/* intercace options */
+#define WANOPT_RS232 0
+#define WANOPT_V35 1
+
+/* data encoding options */
+#define WANOPT_NRZ 0
+#define WANOPT_NRZI 1
+#define WANOPT_FM0 2
+#define WANOPT_FM1 3
+
+/* link type options */
+#define WANOPT_POINTTOPOINT 0 /* RTS always active */
+#define WANOPT_MULTIDROP 1 /* RTS is active when transmitting */
+
+/* clocking options */
+#define WANOPT_EXTERNAL 0
+#define WANOPT_INTERNAL 1
+
+/* station options */
+#define WANOPT_DTE 0
+#define WANOPT_DCE 1
+#define WANOPT_CPE 0
+#define WANOPT_NODE 1
+#define WANOPT_SECONDARY 0
+#define WANOPT_PRIMARY 1
+
+/* connection options */
+#define WANOPT_PERMANENT 0 /* DTR always active */
+#define WANOPT_SWITCHED 1 /* use DTR to setup link (dial-up) */
+#define WANOPT_ONDEMAND 2 /* activate DTR only before sending */
+
+/* frame relay in-channel signalling */
+#define WANOPT_FR_ANSI 1 /* ANSI T1.617 Annex D */
+#define WANOPT_FR_Q933 2 /* ITU Q.933A */
+#define WANOPT_FR_LMI 3 /* LMI */
+
+/* PPP IP Mode Options */
+#define WANOPT_PPP_STATIC 0
+#define WANOPT_PPP_HOST 1
+#define WANOPT_PPP_PEER 2
+
+/* CHDLC Protocol Options */
+/* DF Commmented out for now.
+
+#define WANOPT_CHDLC_NO_DCD IGNORE_DCD_FOR_LINK_STAT
+#define WANOPT_CHDLC_NO_CTS IGNORE_CTS_FOR_LINK_STAT
+#define WANOPT_CHDLC_NO_KEEPALIVE IGNORE_KPALV_FOR_LINK_STAT
+*/
+
+/* Port options */
+#define WANOPT_PRI 0
+#define WANOPT_SEC 1
+/* read mode */
+#define WANOPT_INTR 0
+#define WANOPT_POLL 1
+
+/*----------------------------------------------------------------------------
+ * WAN Link Status Info (for ROUTER_STAT IOCTL).
+ */
+typedef struct wandev_stat
+{
+ unsigned state; /* link state */
+ unsigned ndev; /* number of configured interfaces */
+
+ /* link/interface configuration */
+ unsigned connection; /* permanent/switched/on-demand */
+ unsigned media_type; /* Frame relay/PPP/X.25/SDLC, etc. */
+ unsigned mtu; /* max. transmit unit for this device */
+
+ /* physical level statistics */
+ unsigned modem_status; /* modem status */
+ unsigned rx_frames; /* received frames count */
+ unsigned rx_overruns; /* receiver overrun error count */
+ unsigned rx_crc_err; /* receive CRC error count */
+ unsigned rx_aborts; /* received aborted frames count */
+ unsigned rx_bad_length; /* unexpetedly long/short frames count */
+ unsigned rx_dropped; /* frames discarded at device level */
+ unsigned tx_frames; /* transmitted frames count */
+ unsigned tx_underruns; /* aborted transmissions (underruns) count */
+ unsigned tx_timeouts; /* transmission timeouts */
+ unsigned tx_rejects; /* other transmit errors */
+
+ /* media level statistics */
+ unsigned rx_bad_format; /* frames with invalid format */
+ unsigned rx_bad_addr; /* frames with invalid media address */
+ unsigned tx_retries; /* frames re-transmitted */
+ unsigned reserved[16]; /* reserved for future use */
+} wandev_stat_t;
+
+/* 'state' defines */
+enum wan_states
+{
+ WAN_UNCONFIGURED, /* link/channel is not configured */
+ WAN_DISCONNECTED, /* link/channel is disconnected */
+ WAN_CONNECTING, /* connection is in progress */
+ WAN_CONNECTED, /* link/channel is operational */
+ WAN_LIMIT, /* for verification only */
+ WAN_DUALPORT /* for Dual Port cards */
+};
+
+/* 'modem_status' masks */
+#define WAN_MODEM_CTS 0x0001 /* CTS line active */
+#define WAN_MODEM_DCD 0x0002 /* DCD line active */
+#define WAN_MODEM_DTR 0x0010 /* DTR line active */
+#define WAN_MODEM_RTS 0x0020 /* RTS line active */
+
+/*----------------------------------------------------------------------------
+ * WAN interface (logical channel) configuration (for ROUTER_IFNEW IOCTL).
+ */
+typedef struct wanif_conf
+{
+ unsigned magic; /* magic number */
+ unsigned config_id; /* configuration identifier */
+ char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
+ char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
+ char usedby[USED_BY_FIELD]; /* used by API or WANPIPE */
+ unsigned idle_timeout; /* sec, before disconnecting */
+ unsigned hold_timeout; /* sec, before re-connecting */
+ unsigned cir; /* Committed Information Rate fwd,bwd*/
+ unsigned bc; /* Committed Burst Size fwd, bwd */
+ unsigned be; /* Excess Burst Size fwd, bwd */
+ unsigned char enable_IPX; /* Enable or Disable IPX */
+ unsigned char inarp; /* Send Inverse ARP requests Y/N */
+ unsigned inarp_interval; /* sec, between InARP requests */
+ unsigned long network_number; /* Network Number for IPX */
+ char mc; /* Multicast on or off */
+ char pap; /* PAP enabled or disabled */
+ char chap; /* CHAP enabled or disabled */
+ unsigned char userid[511]; /* List of User Id */
+ unsigned char passwd[511]; /* List of passwords */
+ unsigned char sysname[31]; /* Name of the system */
+ unsigned char ignore_dcd; /* Protocol options: */
+ unsigned char ignore_cts; /* Ignore these to determine */
+ unsigned char ignore_keepalive; /* link status (Yes or No) */
+ unsigned char hdlc_streaming; /* Hdlc streaming mode (Y/N) */
+ unsigned keepalive_tx_tmr; /* transmit keepalive timer */
+ unsigned keepalive_rx_tmr; /* receive keepalive timer */
+ unsigned keepalive_err_margin; /* keepalive_error_tolerance */
+ unsigned slarp_timer; /* SLARP request timer */
+ unsigned char ttl; /* Time To Live for UDP security */
+ char interface; /* RS-232/V.35, etc. */
+ char clocking; /* external/internal */
+ unsigned bps; /* data transfer rate */
+ unsigned mtu; /* maximum transmit unit size */
+} wanif_conf_t;
+
+#ifdef __KERNEL__
+/****** Kernel Interface ****************************************************/
+
+#include <linux/fs.h> /* support for device drivers */
+#include <linux/proc_fs.h> /* proc filesystem pragmatics */
+#include <linux/inet.h> /* in_aton(), in_ntoa() prototypes */
+#include <linux/netdevice.h> /* support for network drivers */
+/*----------------------------------------------------------------------------
+ * WAN device data space.
+ */
+typedef struct wan_device
+{
+ unsigned magic; /* magic number */
+ char* name; /* -> WAN device name (ASCIIZ) */
+ void* private; /* -> driver private data */
+ unsigned config_id; /* Configuration ID */
+ /****** hardware configuration ******/
+ unsigned ioport; /* adapter I/O port base #1 */
+ char S514_cpu_no[1]; /* PCI CPU Number */
+ unsigned char S514_slot_no; /* PCI Slot Number */
+ unsigned long maddr; /* dual-port memory address */
+ unsigned msize; /* dual-port memory size */
+ int irq; /* interrupt request level */
+ int dma; /* DMA request level */
+ unsigned bps; /* data transfer rate */
+ unsigned mtu; /* max physical transmit unit size */
+ unsigned udp_port; /* UDP port for management */
+ unsigned char ttl; /* Time To Live for UDP security */
+ unsigned enable_tx_int; /* Transmit Interrupt enabled or not */
+ char interface; /* RS-232/V.35, etc. */
+ char clocking; /* external/internal */
+ char line_coding; /* NRZ/NRZI/FM0/FM1, etc. */
+ char station; /* DTE/DCE, primary/secondary, etc. */
+ char connection; /* permanent/switched/on-demand */
+ char signalling; /* Signalling RS232 or V35 */
+ char read_mode; /* read mode: Polling or interrupt */
+ char new_if_cnt; /* Number of interfaces per wanpipe */
+ char del_if_cnt; /* Number of times del_if() gets called */
+ unsigned char piggyback; /* Piggibacking a port */
+ unsigned hw_opt[4]; /* other hardware options */
+ /****** status and statistics *******/
+ char state; /* device state */
+ char api_status; /* device api status */
+#ifdef LINUX_2_1
+ struct net_device_stats stats; /* interface statistics */
+#else
+ struct enet_statistics stats; /* interface statistics */
+#endif
+ unsigned reserved[16]; /* reserved for future use */
+ unsigned critical; /* critical section flag */
+ /****** device management methods ***/
+ int (*setup) (struct wan_device *wandev, wandev_conf_t *conf);
+ int (*shutdown) (struct wan_device *wandev);
+ int (*update) (struct wan_device *wandev);
+ int (*ioctl) (struct wan_device *wandev, unsigned cmd,
+ unsigned long arg);
+ int (*new_if) (struct wan_device *wandev, struct device *dev,
+ wanif_conf_t *conf);
+ int (*del_if) (struct wan_device *wandev, struct device *dev);
+ /****** maintained by the router ****/
+ struct wan_device* next; /* -> next device */
+ struct device* dev; /* list of network interfaces */
+ unsigned ndev; /* number of interfaces */
+ struct proc_dir_entry dent; /* proc filesystem entry */
+} wan_device_t;
+
+/* Public functions available for device drivers */
+extern int register_wan_device(wan_device_t *wandev);
+extern int unregister_wan_device(char *name);
+unsigned short wanrouter_type_trans(struct sk_buff *skb, struct device *dev);
+int wanrouter_encapsulate(struct sk_buff *skb, struct device *dev);
+
+/* Proc interface functions. These must not be called by the drivers! */
+extern int wanrouter_proc_init(void);
+extern void wanrouter_proc_cleanup(void);
+extern int wanrouter_proc_add(wan_device_t *wandev);
+extern int wanrouter_proc_delete(wan_device_t *wandev);
+extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+/* Public Data */
+extern wan_device_t *router_devlist; /* list of registered devices */
+
+#endif /* __KERNEL__ */
+#endif /* _ROUTER_H */
diff --git a/pfinet/linux-src/include/linux/watchdog.h b/pfinet/linux-src/include/linux/watchdog.h
new file mode 100644
index 00000000..3f358258
--- /dev/null
+++ b/pfinet/linux-src/include/linux/watchdog.h
@@ -0,0 +1,40 @@
+/*
+ * Generic watchdog defines. Derived from..
+ *
+ * Berkshire PC Watchdog Defines
+ * by Ken Hollis <khollis@bitgate.com>
+ *
+ */
+
+#include <linux/ioctl.h>
+
+#define WATCHDOG_IOCTL_BASE 'W'
+
+struct watchdog_info {
+ u32 options; /* Options the card/driver supports */
+ u32 firmware_version; /* Firmware version of the card */
+ u8 identity[32]; /* Identity of the board */
+};
+
+#define WDIOC_GETSUPPORT _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
+#define WDIOC_GETSTATUS _IOR(WATCHDOG_IOCTL_BASE, 1, int)
+#define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
+#define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int)
+#define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int)
+#define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
+
+#define WDIOF_UNKNOWN -1 /* Unknown flag error */
+#define WDIOS_UNKNOWN -1 /* Unknown status error */
+
+#define WDIOF_OVERHEAT 0x0001 /* Reset due to CPU overheat */
+#define WDIOF_FANFAULT 0x0002 /* Fan failed */
+#define WDIOF_EXTERN1 0x0004 /* External relay 1 */
+#define WDIOF_EXTERN2 0x0008 /* External relay 2 */
+#define WDIOF_POWERUNDER 0x0010 /* Power bad/power fault */
+#define WDIOF_CARDRESET 0x0020 /* Card previously reset the CPU */
+#define WDIOF_POWEROVER 0x0040 /* Power over voltage */
+#define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */
+
+#define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */
+#define WDIOS_ENABLECARD 0x0002 /* Turn on the watchdog timer */
+#define WDIOS_TEMPPANIC 0x0004 /* Kernel panic on temperature trip */
diff --git a/pfinet/linux-src/include/linux/wavefront.h b/pfinet/linux-src/include/linux/wavefront.h
new file mode 100644
index 00000000..f816f940
--- /dev/null
+++ b/pfinet/linux-src/include/linux/wavefront.h
@@ -0,0 +1,675 @@
+#ifndef __wavefront_h__
+#define __wavefront_h__
+
+/* WaveFront header file.
+ *
+ * Copyright (C) by Paul Barton-Davis 1998
+ *
+ * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+
+#if (!defined(__GNUC__) && !defined(__GNUG__))
+
+ You will not be able to compile this file correctly without gcc, because
+ it is necessary to pack the "wavefront_alias" structure to a size
+ of 22 bytes, corresponding to 16-bit alignment (as would have been
+ the case on the original platform, MS-DOS). If this is not done,
+ then WavePatch-format files cannot be read/written correctly.
+ The method used to do this here ("__attribute__((packed)") is
+ completely compiler dependent.
+
+ All other wavefront_* types end up aligned to 32 bit values and
+ still have the same (correct) size.
+
+#else
+
+ /* However, note that as of G++ 2.7.3.2, g++ was unable to
+ correctly parse *type* __attribute__ tags. It will do the
+ right thing if we use the "packed" attribute on each struct
+ member, which has the same semantics anyway.
+ */
+
+#endif __GNUC__
+
+/***************************** WARNING ********************************
+ PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO
+ BE USED WITH EITHER C *OR* C++.
+ **********************************************************************/
+
+#ifndef NUM_MIDIKEYS
+#define NUM_MIDIKEYS 128
+#endif NUM_MIDIKEYS
+
+#ifndef NUM_MIDICHANNELS
+#define NUM_MIDICHANNELS 16
+#endif NUM_MIDICHANNELS
+
+/* These are very useful/important. the original wavefront interface
+ was developed on a 16 bit system, where sizeof(int) = 2
+ bytes. Defining things like this makes the code much more portable, and
+ easier to understand without having to toggle back and forth
+ between a 16-bit view of the world and a 32-bit one.
+ */
+
+typedef short INT16;
+typedef unsigned short UINT16;
+typedef int INT32;
+typedef unsigned int UINT32;
+typedef char CHAR8;
+typedef unsigned char UCHAR8;
+
+/* Pseudo-commands not part of the WaveFront command set.
+ These are used for various driver controls and direct
+ hardware control.
+ */
+
+#define WFC_DEBUG_DRIVER 0
+#define WFC_FX_IOCTL 1
+#define WFC_PATCH_STATUS 2
+#define WFC_PROGRAM_STATUS 3
+#define WFC_SAMPLE_STATUS 4
+#define WFC_DISABLE_INTERRUPTS 5
+#define WFC_ENABLE_INTERRUPTS 6
+#define WFC_INTERRUPT_STATUS 7
+#define WFC_ROMSAMPLES_RDONLY 8
+#define WFC_IDENTIFY_SLOT_TYPE 9
+
+/* Wavefront synth commands
+ */
+
+#define WFC_DOWNLOAD_SAMPLE 0x80
+#define WFC_DOWNLOAD_BLOCK 0x81
+#define WFC_DOWNLOAD_MULTISAMPLE 0x82
+#define WFC_DOWNLOAD_SAMPLE_ALIAS 0x83
+#define WFC_DELETE_SAMPLE 0x84
+#define WFC_REPORT_FREE_MEMORY 0x85
+#define WFC_DOWNLOAD_PATCH 0x86
+#define WFC_DOWNLOAD_PROGRAM 0x87
+#define WFC_SET_SYNTHVOL 0x89
+#define WFC_SET_NVOICES 0x8B
+#define WFC_DOWNLOAD_DRUM 0x90
+#define WFC_GET_SYNTHVOL 0x92
+#define WFC_GET_NVOICES 0x94
+#define WFC_DISABLE_CHANNEL 0x9A
+#define WFC_ENABLE_CHANNEL 0x9B
+#define WFC_MISYNTH_OFF 0x9D
+#define WFC_MISYNTH_ON 0x9E
+#define WFC_FIRMWARE_VERSION 0x9F
+#define WFC_GET_NSAMPLES 0xA0
+#define WFC_DISABLE_DRUM_PROGRAM 0xA2
+#define WFC_UPLOAD_PATCH 0xA3
+#define WFC_UPLOAD_PROGRAM 0xA4
+#define WFC_SET_TUNING 0xA6
+#define WFC_GET_TUNING 0xA7
+#define WFC_VMIDI_ON 0xA8
+#define WFC_VMIDI_OFF 0xA9
+#define WFC_MIDI_STATUS 0xAA
+#define WFC_GET_CHANNEL_STATUS 0xAB
+#define WFC_DOWNLOAD_SAMPLE_HEADER 0xAC
+#define WFC_UPLOAD_SAMPLE_HEADER 0xAD
+#define WFC_UPLOAD_MULTISAMPLE 0xAE
+#define WFC_UPLOAD_SAMPLE_ALIAS 0xAF
+#define WFC_IDENTIFY_SAMPLE_TYPE 0xB0
+#define WFC_DOWNLOAD_EDRUM_PROGRAM 0xB1
+#define WFC_UPLOAD_EDRUM_PROGRAM 0xB2
+#define WFC_SET_EDRUM_CHANNEL 0xB3
+#define WFC_INSTOUT_LEVELS 0xB4
+#define WFC_PEAKOUT_LEVELS 0xB5
+#define WFC_REPORT_CHANNEL_PROGRAMS 0xB6
+#define WFC_HARDWARE_VERSION 0xCF
+#define WFC_UPLOAD_SAMPLE_PARAMS 0xD7
+#define WFC_DOWNLOAD_OS 0xF1
+#define WFC_NOOP 0xFF
+
+#define WF_MAX_SAMPLE 512
+#define WF_MAX_PATCH 256
+#define WF_MAX_PROGRAM 128
+
+#define WF_SECTION_MAX 44 /* longest OS section length */
+
+/* # of bytes we send to the board when sending it various kinds of
+ substantive data, such as samples, patches and programs.
+*/
+
+#define WF_PROGRAM_BYTES 32
+#define WF_PATCH_BYTES 132
+#define WF_SAMPLE_BYTES 27
+#define WF_SAMPLE_HDR_BYTES 25
+#define WF_ALIAS_BYTES 25
+#define WF_DRUM_BYTES 9
+#define WF_MSAMPLE_BYTES 259 /* (MIDI_KEYS * 2) + 3 */
+
+#define WF_ACK 0x80
+#define WF_DMA_ACK 0x81
+
+/* OR-values for MIDI status bits */
+
+#define WF_MIDI_VIRTUAL_ENABLED 0x1
+#define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2
+#define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4
+
+/* slot indexes for struct address_info: makes code a little more mnemonic */
+
+#define WF_SYNTH_SLOT 0
+#define WF_INTERNAL_MIDI_SLOT 1
+#define WF_EXTERNAL_MIDI_SLOT 2
+
+/* Magic MIDI bytes used to switch I/O streams on the ICS2115 MPU401
+ emulation. Note these NEVER show up in output from the device and
+ should NEVER be used in input unless Virtual MIDI mode has been
+ disabled. If they do show up as input, the results are unpredictable.
+*/
+
+#define WF_EXTERNAL_SWITCH 0xFD
+#define WF_INTERNAL_SWITCH 0xF9
+
+/* Debugging flags */
+
+#define WF_DEBUG_CMD 0x1
+#define WF_DEBUG_DATA 0x2
+#define WF_DEBUG_LOAD_PATCH 0x4
+#define WF_DEBUG_IO 0x8
+
+/* WavePatch file format stuff */
+
+#define WF_WAVEPATCH_VERSION 120; /* Current version number (1.2) */
+#define WF_MAX_COMMENT 64 /* Comment length */
+#define WF_NUM_LAYERS 4
+#define WF_NAME_LENGTH 32
+#define WF_SOURCE_LENGTH 260
+
+#define BankFileID "Bank"
+#define DrumkitFileID "DrumKit"
+#define ProgramFileID "Program"
+
+struct wf_envelope
+{
+ UCHAR8 attack_time:7;
+ UCHAR8 Unused1:1;
+
+ UCHAR8 decay1_time:7;
+ UCHAR8 Unused2:1;
+
+ UCHAR8 decay2_time:7;
+ UCHAR8 Unused3:1;
+
+ UCHAR8 sustain_time:7;
+ UCHAR8 Unused4:1;
+
+ UCHAR8 release_time:7;
+ UCHAR8 Unused5:1;
+
+ UCHAR8 release2_time:7;
+ UCHAR8 Unused6:1;
+
+ CHAR8 attack_level;
+ CHAR8 decay1_level;
+ CHAR8 decay2_level;
+ CHAR8 sustain_level;
+ CHAR8 release_level;
+
+ UCHAR8 attack_velocity:7;
+ UCHAR8 Unused7:1;
+
+ UCHAR8 volume_velocity:7;
+ UCHAR8 Unused8:1;
+
+ UCHAR8 keyboard_scaling:7;
+ UCHAR8 Unused9:1;
+};
+typedef struct wf_envelope wavefront_envelope;
+
+struct wf_lfo
+{
+ UCHAR8 sample_number;
+
+ UCHAR8 frequency:7;
+ UCHAR8 Unused1:1;
+
+ UCHAR8 am_src:4;
+ UCHAR8 fm_src:4;
+
+ CHAR8 fm_amount;
+ CHAR8 am_amount;
+ CHAR8 start_level;
+ CHAR8 end_level;
+
+ UCHAR8 ramp_delay:7;
+ UCHAR8 wave_restart:1; /* for LFO2 only */
+
+ UCHAR8 ramp_time:7;
+ UCHAR8 Unused2:1;
+};
+typedef struct wf_lfo wavefront_lfo;
+
+struct wf_patch
+{
+ INT16 frequency_bias; /* ** THIS IS IN MOTOROLA FORMAT!! ** */
+
+ UCHAR8 amplitude_bias:7;
+ UCHAR8 Unused1:1;
+
+ UCHAR8 portamento:7;
+ UCHAR8 Unused2:1;
+
+ UCHAR8 sample_number;
+
+ UCHAR8 pitch_bend:4;
+ UCHAR8 sample_msb:1;
+ UCHAR8 Unused3:3;
+
+ UCHAR8 mono:1;
+ UCHAR8 retrigger:1;
+ UCHAR8 nohold:1;
+ UCHAR8 restart:1;
+ UCHAR8 filterconfig:2; /* SDK says "not used" */
+ UCHAR8 reuse:1;
+ UCHAR8 reset_lfo:1;
+
+ UCHAR8 fm_src2:4;
+ UCHAR8 fm_src1:4;
+
+ CHAR8 fm_amount1;
+ CHAR8 fm_amount2;
+
+ UCHAR8 am_src:4;
+ UCHAR8 Unused4:4;
+
+ CHAR8 am_amount;
+
+ UCHAR8 fc1_mode:4;
+ UCHAR8 fc2_mode:4;
+
+ CHAR8 fc1_mod_amount;
+ CHAR8 fc1_keyboard_scaling;
+ CHAR8 fc1_bias;
+ CHAR8 fc2_mod_amount;
+ CHAR8 fc2_keyboard_scaling;
+ CHAR8 fc2_bias;
+
+ UCHAR8 randomizer:7;
+ UCHAR8 Unused5:1;
+
+ struct wf_envelope envelope1;
+ struct wf_envelope envelope2;
+ struct wf_lfo lfo1;
+ struct wf_lfo lfo2;
+};
+typedef struct wf_patch wavefront_patch;
+
+struct wf_layer
+{
+ UCHAR8 patch_number;
+
+ UCHAR8 mix_level:7;
+ UCHAR8 mute:1;
+
+ UCHAR8 split_point:7;
+ UCHAR8 play_below:1;
+
+ UCHAR8 pan_mod_src:2;
+ UCHAR8 pan_or_mod:1;
+ UCHAR8 pan:4;
+ UCHAR8 split_type:1;
+};
+typedef struct wf_layer wavefront_layer;
+
+struct wf_program
+{
+ struct wf_layer layer[WF_NUM_LAYERS];
+};
+typedef struct wf_program wavefront_program;
+
+struct wf_sample_offset
+{
+ INT32 Fraction:4;
+ INT32 Integer:20;
+ INT32 Unused:8;
+};
+typedef struct wf_sample_offset wavefront_sample_offset;
+
+/* Sample slot types */
+
+#define WF_ST_SAMPLE 0
+#define WF_ST_MULTISAMPLE 1
+#define WF_ST_ALIAS 2
+#define WF_ST_EMPTY 3
+
+/* pseudo's */
+
+#define WF_ST_DRUM 4
+#define WF_ST_PROGRAM 5
+#define WF_ST_PATCH 6
+#define WF_ST_SAMPLEHDR 7
+
+#define WF_ST_MASK 0xf
+
+/* Flags for slot status. These occupy the upper bits of the same byte
+ as a sample type.
+*/
+
+#define WF_SLOT_USED 0x80 /* XXX don't rely on this being accurate */
+#define WF_SLOT_FILLED 0x40
+#define WF_SLOT_ROM 0x20
+
+#define WF_SLOT_MASK 0xf0
+
+/* channel constants */
+
+#define WF_CH_MONO 0
+#define WF_CH_LEFT 1
+#define WF_CH_RIGHT 2
+
+/* Sample formats */
+
+#define LINEAR_16BIT 0
+#define WHITE_NOISE 1
+#define LINEAR_8BIT 2
+#define MULAW_8BIT 3
+
+#define WF_SAMPLE_IS_8BIT(smpl) ((smpl)->SampleResolution&2)
+
+
+/*
+
+ Because most/all of the sample data we pass in via pointers has
+ never been copied (just mmap-ed into user space straight from the
+ disk), it would be nice to allow handling of multi-channel sample
+ data without forcing user-level extraction of the relevant bytes.
+
+ So, we need a way of specifying which channel to use (the WaveFront
+ only handles mono samples in a given slot), and the only way to do
+ this without using some struct other than wavefront_sample as the
+ interface is the awful hack of using the unused bits in a
+ wavefront_sample:
+
+ Val Meaning
+ --- -------
+ 0 no channel selection (use channel 1, sample is MONO)
+ 1 use first channel, and skip one
+ 2 use second channel, and skip one
+ 3 use third channel, and skip two
+ 4 use fourth channel, skip three
+ 5 use fifth channel, skip four
+ 6 use six channel, skip five
+
+
+ This can handle up to 4 channels, and anyone downloading >4 channels
+ of sample data just to select one of them needs to find some tools
+ like sox ...
+
+ NOTE: values 0, 1 and 2 correspond to WF_CH_* above. This is
+ important.
+
+*/
+
+#define WF_SET_CHANNEL(samp,chn) \
+ (samp)->Unused1 = chn & 0x1; \
+ (samp)->Unused2 = chn & 0x2; \
+ (samp)->Unused3 = chn & 0x4
+
+#define WF_GET_CHANNEL(samp) \
+ (((samp)->Unused3 << 2)|((samp)->Unused2<<1)|(samp)->Unused1)
+
+typedef struct wf_sample {
+ struct wf_sample_offset sampleStartOffset;
+ struct wf_sample_offset loopStartOffset;
+ struct wf_sample_offset loopEndOffset;
+ struct wf_sample_offset sampleEndOffset;
+ INT16 FrequencyBias;
+ UCHAR8 SampleResolution:2; /* sample_format */
+ UCHAR8 Unused1:1;
+ UCHAR8 Loop:1;
+ UCHAR8 Bidirectional:1;
+ UCHAR8 Unused2:1;
+ UCHAR8 Reverse:1;
+ UCHAR8 Unused3:1;
+} wavefront_sample;
+
+typedef struct wf_multisample {
+ INT16 NumberOfSamples; /* log2 of the number of samples */
+ INT16 SampleNumber[NUM_MIDIKEYS];
+} wavefront_multisample;
+
+typedef struct wf_alias {
+ INT16 OriginalSample __attribute__ ((packed));
+
+ struct wf_sample_offset sampleStartOffset __attribute__ ((packed));
+ struct wf_sample_offset loopStartOffset __attribute__ ((packed));
+ struct wf_sample_offset sampleEndOffset __attribute__ ((packed));
+ struct wf_sample_offset loopEndOffset __attribute__ ((packed));
+
+ INT16 FrequencyBias __attribute__ ((packed));
+
+ UCHAR8 SampleResolution:2 __attribute__ ((packed));
+ UCHAR8 Unused1:1 __attribute__ ((packed));
+ UCHAR8 Loop:1 __attribute__ ((packed));
+ UCHAR8 Bidirectional:1 __attribute__ ((packed));
+ UCHAR8 Unused2:1 __attribute__ ((packed));
+ UCHAR8 Reverse:1 __attribute__ ((packed));
+ UCHAR8 Unused3:1 __attribute__ ((packed));
+
+ /* This structure is meant to be padded only to 16 bits on their
+ original. Of course, whoever wrote their documentation didn't
+ realize that sizeof(struct) can be >=
+ sum(sizeof(struct-fields)) and so thought that giving a C level
+ description of the structs used in WavePatch files was
+ sufficient. I suppose it was, as long as you remember the
+ standard 16->32 bit issues.
+ */
+
+ UCHAR8 sixteen_bit_padding __attribute__ ((packed));
+} wavefront_alias;
+
+typedef struct wf_drum {
+ UCHAR8 PatchNumber;
+ UCHAR8 MixLevel:7;
+ UCHAR8 Unmute:1;
+ UCHAR8 Group:4;
+ UCHAR8 Unused1:4;
+ UCHAR8 PanModSource:2;
+ UCHAR8 PanModulated:1;
+ UCHAR8 PanAmount:4;
+ UCHAR8 Unused2:1;
+} wavefront_drum;
+
+typedef struct wf_drumkit {
+ struct wf_drum drum[NUM_MIDIKEYS];
+} wavefront_drumkit;
+
+typedef struct wf_channel_programs {
+ UCHAR8 Program[NUM_MIDICHANNELS];
+} wavefront_channel_programs;
+
+/* How to get MIDI channel status from the data returned by
+ a WFC_GET_CHANNEL_STATUS command (a struct wf_channel_programs)
+*/
+
+#define WF_CHANNEL_STATUS(ch,wcp) (wcp)[(ch/7)] & (1<<((ch)%7))
+
+typedef union wf_any {
+ wavefront_sample s;
+ wavefront_multisample ms;
+ wavefront_alias a;
+ wavefront_program pr;
+ wavefront_patch p;
+ wavefront_drum d;
+} wavefront_any;
+
+/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h
+ might work for other wave-table based patch loading situations.
+ Alas, his fears were correct. The WaveFront doesn't even come with
+ just "patches", but several different kind of structures that
+ control the sound generation process.
+ */
+
+typedef struct wf_patch_info {
+
+ /* the first two fields are used by the OSS "patch loading" interface
+ only, and are unused by the current user-level library.
+ */
+
+ INT16 key; /* Use WAVEFRONT_PATCH here */
+ UINT16 devno; /* fill in when sending */
+ UCHAR8 subkey; /* WF_ST_{SAMPLE,ALIAS,etc.} */
+
+#define WAVEFRONT_FIND_FREE_SAMPLE_SLOT 999
+
+ UINT16 number; /* patch/sample/prog number */
+
+ UINT32 size; /* size of any data included in
+ one of the fields in `hdrptr', or
+ as `dataptr'.
+
+ NOTE: for actual samples, this is
+ the size of the *SELECTED CHANNEL*
+ even if more data is actually available.
+
+ So, a stereo sample (2 channels) of
+ 6000 bytes total has `size' = 3000.
+
+ See the macros and comments for
+ WF_{GET,SET}_CHANNEL above.
+
+ */
+ wavefront_any *hdrptr; /* user-space ptr to hdr bytes */
+ UINT16 *dataptr; /* actual sample data */
+
+ wavefront_any hdr; /* kernel-space copy of hdr bytes */
+} wavefront_patch_info;
+
+/* The maximum number of bytes we will ever move to or from user space
+ in response to a WFC_* command. This obviously doesn't cover
+ actual sample data.
+*/
+
+#define WF_MAX_READ sizeof(wavefront_multisample)
+#define WF_MAX_WRITE sizeof(wavefront_multisample)
+
+/*
+ This allows us to execute any WF command except the download/upload
+ ones, which are handled differently due to copyin/copyout issues as
+ well as data-nybbling to/from the card.
+ */
+
+typedef struct wavefront_control {
+ int cmd; /* WFC_* */
+ char status; /* return status to user-space */
+ unsigned char rbuf[WF_MAX_READ]; /* bytes read from card */
+ unsigned char wbuf[WF_MAX_WRITE]; /* bytes written to card */
+} wavefront_control;
+
+#define WFCTL_WFCMD 0x1
+#define WFCTL_LOAD_SPP 0x2
+
+/* Modulator table */
+
+#define WF_MOD_LFO1 0
+#define WF_MOD_LFO2 1
+#define WF_MOD_ENV1 2
+#define WF_MOD_ENV2 3
+#define WF_MOD_KEYBOARD 4
+#define WF_MOD_LOGKEY 5
+#define WF_MOD_VELOCITY 6
+#define WF_MOD_LOGVEL 7
+#define WF_MOD_RANDOM 8
+#define WF_MOD_PRESSURE 9
+#define WF_MOD_MOD_WHEEL 10
+#define WF_MOD_1 WF_MOD_MOD_WHEEL
+#define WF_MOD_BREATH 11
+#define WF_MOD_2 WF_MOD_BREATH
+#define WF_MOD_FOOT 12
+#define WF_MOD_4 WF_MOD_FOOT
+#define WF_MOD_VOLUME 13
+#define WF_MOD_7 WF_MOD_VOLUME
+#define WF_MOD_PAN 14
+#define WF_MOD_10 WF_MOD_PAN
+#define WF_MOD_EXPR 15
+#define WF_MOD_11 WF_MOD_EXPR
+
+/* FX-related material */
+
+typedef struct wf_fx_info {
+ int request; /* see list below */
+ int data[4]; /* we don't need much */
+} wavefront_fx_info;
+
+/* support for each of these will be forthcoming once I or someone
+ else has figured out which of the addresses on page 6 and page 7 of
+ the YSS225 control each parameter. Incidentally, these come from
+ the Windows driver interface, but again, Turtle Beach didn't
+ document the API to use them.
+*/
+
+#define WFFX_SETOUTGAIN 0
+#define WFFX_SETSTEREOOUTGAIN 1
+#define WFFX_SETREVERBIN1GAIN 2
+#define WFFX_SETREVERBIN2GAIN 3
+#define WFFX_SETREVERBIN3GAIN 4
+#define WFFX_SETCHORUSINPORT 5
+#define WFFX_SETREVERBIN1PORT 6
+#define WFFX_SETREVERBIN2PORT 7
+#define WFFX_SETREVERBIN3PORT 8
+#define WFFX_SETEFFECTPORT 9
+#define WFFX_SETAUXPORT 10
+#define WFFX_SETREVERBTYPE 11
+#define WFFX_SETREVERBDELAY 12
+#define WFFX_SETCHORUSLFO 13
+#define WFFX_SETCHORUSPMD 14
+#define WFFX_SETCHORUSAMD 15
+#define WFFX_SETEFFECT 16
+#define WFFX_SETBASEALL 17
+#define WFFX_SETREVERBALL 18
+#define WFFX_SETCHORUSALL 20
+#define WFFX_SETREVERBDEF 22
+#define WFFX_SETCHORUSDEF 23
+#define WFFX_DELAYSETINGAIN 24
+#define WFFX_DELAYSETFBGAIN 25
+#define WFFX_DELAYSETFBLPF 26
+#define WFFX_DELAYSETGAIN 27
+#define WFFX_DELAYSETTIME 28
+#define WFFX_DELAYSETFBTIME 29
+#define WFFX_DELAYSETALL 30
+#define WFFX_DELAYSETDEF 32
+#define WFFX_SDELAYSETINGAIN 33
+#define WFFX_SDELAYSETFBGAIN 34
+#define WFFX_SDELAYSETFBLPF 35
+#define WFFX_SDELAYSETGAIN 36
+#define WFFX_SDELAYSETTIME 37
+#define WFFX_SDELAYSETFBTIME 38
+#define WFFX_SDELAYSETALL 39
+#define WFFX_SDELAYSETDEF 41
+#define WFFX_DEQSETINGAIN 42
+#define WFFX_DEQSETFILTER 43
+#define WFFX_DEQSETALL 44
+#define WFFX_DEQSETDEF 46
+#define WFFX_MUTE 47
+#define WFFX_FLANGESETBALANCE 48
+#define WFFX_FLANGESETDELAY 49
+#define WFFX_FLANGESETDWFFX_TH 50
+#define WFFX_FLANGESETFBGAIN 51
+#define WFFX_FLANGESETINGAIN 52
+#define WFFX_FLANGESETLFO 53
+#define WFFX_FLANGESETALL 54
+#define WFFX_FLANGESETDEF 56
+#define WFFX_PITCHSETSHIFT 57
+#define WFFX_PITCHSETBALANCE 58
+#define WFFX_PITCHSETALL 59
+#define WFFX_PITCHSETDEF 61
+#define WFFX_SRSSETINGAIN 62
+#define WFFX_SRSSETSPACE 63
+#define WFFX_SRSSETCENTER 64
+#define WFFX_SRSSETGAIN 65
+#define WFFX_SRSSETMODE 66
+#define WFFX_SRSSETDEF 68
+
+/* Allow direct user-space control over FX memory/coefficient data.
+ In theory this could be used to download the FX microprogram,
+ but it would be a little slower, and involve some weird code.
+ */
+
+#define WFFX_MEMSET 69
+
+#endif __wavefront_h__
diff --git a/pfinet/linux-src/include/linux/wireless.h b/pfinet/linux-src/include/linux/wireless.h
new file mode 100644
index 00000000..61f85152
--- /dev/null
+++ b/pfinet/linux-src/include/linux/wireless.h
@@ -0,0 +1,448 @@
+/*
+ * This file define a set of standard wireless extensions
+ *
+ * Version : 9 16.10.99
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ */
+
+#ifndef _LINUX_WIRELESS_H
+#define _LINUX_WIRELESS_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Basically, the wireless extensions are for now a set of standard ioctl
+ * call + /proc/net/wireless
+ *
+ * The entry /proc/net/wireless give statistics and information on the
+ * driver.
+ * This is better than having each driver having its entry because
+ * its centralised and we may remove the driver module safely.
+ *
+ * Ioctl are used to configure the driver and issue commands. This is
+ * better than command line options of insmod because we may want to
+ * change dynamically (while the driver is running) some parameters.
+ *
+ * The ioctl mechanimsm are copied from standard devices ioctl.
+ * We have the list of command plus a structure descibing the
+ * data exchanged...
+ * Note that to add these ioctl, I was obliged to modify :
+ * net/core/dev.c (two place + add include)
+ * net/ipv4/af_inet.c (one place + add include)
+ *
+ * /proc/net/wireless is a copy of /proc/net/dev.
+ * We have a structure for data passed from the driver to /proc/net/wireless
+ * Too add this, I've modified :
+ * net/core/dev.c (two other places)
+ * include/linux/netdevice.h (one place)
+ * include/linux/proc_fs.h (one place)
+ *
+ * Do not add here things that are redundant with other mechanisms
+ * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
+ * wireless specific.
+ *
+ * These wireless extensions are not magic : each driver has to provide
+ * support for them...
+ *
+ * IMPORTANT NOTE : As everything in the kernel, this is very much a
+ * work in progress. Contact me if you have ideas of improvements...
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/types.h> /* for "caddr_t" et al */
+#include <linux/socket.h> /* for "struct sockaddr" et al */
+#include <linux/if.h> /* for IFNAMSIZ and co... */
+
+/**************************** CONSTANTS ****************************/
+
+/* --------------------------- VERSION --------------------------- */
+/*
+ * This constant is used to know the availability of the wireless
+ * extensions and to know which version of wireless extensions it is
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+#define WIRELESS_EXT 9
+
+/*
+ * Changes :
+ *
+ * V2 to V3
+ * --------
+ * Alan Cox start some incompatibles changes. I've integrated a bit more.
+ * - Encryption renamed to Encode to avoid US regulation problems
+ * - Frequency changed from float to struct to avoid problems on old 386
+ *
+ * V3 to V4
+ * --------
+ * - Add sensitivity
+ *
+ * V4 to V5
+ * --------
+ * - Missing encoding definitions in range
+ * - Access points stuff
+ *
+ * V5 to V6
+ * --------
+ * - 802.11 support (ESSID ioctls)
+ *
+ * V6 to V7
+ * --------
+ * - define IW_ESSID_MAX_SIZE and IW_MAX_AP
+ *
+ * V7 to V8
+ * --------
+ * - Changed my e-mail address
+ * - More 802.11 support (nickname, rate, rts, frag)
+ * - List index in frequencies
+ *
+ * V8 to V9
+ * --------
+ * - Support for 'mode of operation' (ad-hoc, managed...)
+ * - Support for unicast and multicast power saving
+ * - Change encoding to support larger tokens (>64 bits)
+ * - Updated iw_params (disable, flags) and use it for NWID
+ * - Extracted iw_point from iwreq for clarity
+ */
+
+/* -------------------------- IOCTL LIST -------------------------- */
+
+/* Basic operations */
+#define SIOCSIWNAME 0x8B00 /* Unused ??? */
+#define SIOCGIWNAME 0x8B01 /* get name */
+#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */
+#define SIOCGIWNWID 0x8B03 /* get network id */
+#define SIOCSIWFREQ 0x8B04 /* set channel/frequency */
+#define SIOCGIWFREQ 0x8B05 /* get channel/frequency */
+#define SIOCSIWMODE 0x8B06 /* set operation mode */
+#define SIOCGIWMODE 0x8B07 /* get operation mode */
+#define SIOCSIWSENS 0x8B08 /* set sensitivity */
+#define SIOCGIWSENS 0x8B09 /* get sensitivity */
+
+/* Informative stuff */
+#define SIOCSIWRANGE 0x8B0A /* Unused ??? */
+#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */
+#define SIOCSIWPRIV 0x8B0C /* Unused ??? */
+#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */
+
+/* Mobile IP support */
+#define SIOCSIWSPY 0x8B10 /* set spy addresses */
+#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */
+
+/* Access Point manipulation */
+#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */
+#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */
+#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */
+
+/* 802.11 specific support */
+#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */
+#define SIOCGIWESSID 0x8B1B /* get ESSID */
+#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */
+#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */
+/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
+ * within the 'iwreq' structure, so we need to use the 'data' member to
+ * point to a string in user space, like it is done for RANGE...
+ * The "flags" member indicate if the ESSID is active or not (promiscuous).
+ */
+
+/* Other parameters useful in 802.11 and some other devices */
+#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */
+#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */
+#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */
+#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */
+#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */
+#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */
+
+/* Encoding stuff (scrambling, hardware security, WEP...) */
+#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */
+#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */
+/* Power saving stuff (power management, unicast and multicast) */
+#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */
+#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */
+
+/* ------------------------- IOCTL STUFF ------------------------- */
+
+/* The first and the last (range) */
+#define SIOCIWFIRST 0x8B00
+#define SIOCIWLAST 0x8B30
+
+/* Even : get (world access), odd : set (root access) */
+#define IW_IS_SET(cmd) (!((cmd) & 0x1))
+#define IW_IS_GET(cmd) ((cmd) & 0x1)
+
+/* ------------------------- PRIVATE INFO ------------------------- */
+/*
+ * The following is used with SIOCGIWPRIV. It allow a driver to define
+ * the interface (name, type of data) for its private ioctl.
+ * Privates ioctl are SIOCDEVPRIVATE -> SIOCDEVPRIVATE + 0xF
+ */
+
+#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */
+#define IW_PRIV_TYPE_NONE 0x0000
+#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */
+#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */
+#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */
+#define IW_PRIV_TYPE_FLOAT 0x5000
+
+#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */
+
+#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */
+
+/*
+ * Note : if the number of args is fixed and the size < 16 octets,
+ * instead of passing a pointer we will put args in the iwreq struct...
+ */
+
+/* ----------------------- OTHER CONSTANTS ----------------------- */
+
+/* Maximum frequencies in the range struct */
+#define IW_MAX_FREQUENCIES 16
+/* Note : if you have something like 80 frequencies,
+ * don't increase this constant and don't fill the frequency list.
+ * The user will be able to set by channel anyway... */
+
+/* Maximum bit rates in the range struct */
+#define IW_MAX_BITRATES 8
+
+/* Maximum of address that you may set with SPY */
+#define IW_MAX_SPY 8
+
+/* Maximum of address that you may get in the
+ list of access points in range */
+#define IW_MAX_AP 8
+
+/* Maximum size of the ESSID and NICKN strings */
+#define IW_ESSID_MAX_SIZE 32
+
+/* Modes of operation */
+#define IW_MODE_AUTO 0 /* Let the driver decides */
+#define IW_MODE_ADHOC 1 /* Single cell network */
+#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */
+#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */
+#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */
+#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
+
+/* Maximum number of size of encoding token available
+ * they are listed in the range structure */
+#define IW_MAX_ENCODING_SIZES 8
+
+/* Maximum size of the encoding token in bytes */
+#define IW_ENCODING_TOKEN_MAX 32 /* 256 bits (for now) */
+
+/* Flags for encoding (along with the token) */
+#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */
+#define IW_ENCODE_FLAGS 0xF000 /* Flags defined below */
+#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */
+#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */
+#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */
+#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */
+
+/* Power management flags available (along with the value, if any) */
+#define IW_POWER_ON 0x0000 /* No details... */
+#define IW_POWER_TYPE 0xF000 /* Type of parameter */
+#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */
+#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */
+#define IW_POWER_MODE 0x0F00 /* Power Management mode */
+#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */
+#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */
+#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */
+#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */
+#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */
+
+/****************************** TYPES ******************************/
+
+/* --------------------------- SUBTYPES --------------------------- */
+/*
+ * Generic format for most parameters that fit in an int
+ */
+struct iw_param
+{
+ __s32 value; /* The value of the parameter itself */
+ __u8 fixed; /* Hardware should not use auto select */
+ __u8 disabled; /* Disable the feature */
+ __u16 flags; /* Various specifc flags (if any) */
+};
+
+/*
+ * For all data larger than 16 octets, we need to use a
+ * pointer to memory alocated in user space.
+ */
+struct iw_point
+{
+ caddr_t pointer; /* Pointer to the data (in user space) */
+ __u16 length; /* number of fields or size in bytes */
+ __u16 flags; /* Optional params */
+};
+
+/*
+ * A frequency
+ * For numbers lower than 10^9, we encode the number in 'm' and
+ * set 'e' to 0
+ * For number greater than 10^9, we divide it by the lowest power
+ * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
+ * The power of 10 is in 'e', the result of the division is in 'm'.
+ */
+struct iw_freq
+{
+ __u32 m; /* Mantissa */
+ __u16 e; /* Exponent */
+ __u8 i; /* List index (when in range struct) */
+};
+
+/*
+ * Quality of the link
+ */
+struct iw_quality
+{
+ __u8 qual; /* link quality (%retries, SNR or better...) */
+ __u8 level; /* signal level */
+ __u8 noise; /* noise level */
+ __u8 updated; /* Flags to know if updated */
+};
+
+/*
+ * Packet discarded in the wireless adapter due to
+ * "wireless" specific problems...
+ */
+struct iw_discarded
+{
+ __u32 nwid; /* Wrong nwid */
+ __u32 code; /* Unable to code/decode */
+ __u32 misc; /* Others cases */
+};
+
+/* ------------------------ WIRELESS STATS ------------------------ */
+/*
+ * Wireless statistics (used for /proc/net/wireless)
+ */
+struct iw_statistics
+{
+ __u16 status; /* Status
+ * - device dependent for now */
+
+ struct iw_quality qual; /* Quality of the link
+ * (instant/mean/max) */
+ struct iw_discarded discard; /* Packet discarded counts */
+};
+
+/* ------------------------ IOCTL REQUEST ------------------------ */
+/*
+ * The structure to exchange data for ioctl.
+ * This structure is the same as 'struct ifreq', but (re)defined for
+ * convenience...
+ *
+ * Note that it should fit on the same memory footprint !
+ * You should check this when increasing the above structures (16 octets)
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ */
+struct iwreq
+{
+ union
+ {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
+ } ifr_ifrn;
+
+ /* Data part */
+ union
+ {
+ /* Config - generic */
+ char name[IFNAMSIZ];
+ /* Name : used to verify the presence of wireless extensions.
+ * Name of the protocol/provider... */
+
+ struct iw_point essid; /* Extended network name */
+ struct iw_param nwid; /* network id (or domain - the cell) */
+ struct iw_freq freq; /* frequency or channel :
+ * 0-1000 = channel
+ * > 1000 = frequency in Hz */
+
+ struct iw_param sens; /* signal level threshold */
+ struct iw_param bitrate; /* default bit rate */
+ struct iw_param rts; /* RTS threshold threshold */
+ struct iw_param frag; /* Fragmentation threshold */
+ __u32 mode; /* Operation mode */
+
+ struct iw_point encoding; /* Encoding stuff : tokens */
+ struct iw_param power; /* PM duration/timeout */
+
+ struct sockaddr ap_addr; /* Access point address */
+
+ struct iw_point data; /* Other large parameters */
+ } u;
+};
+
+/* -------------------------- IOCTL DATA -------------------------- */
+/*
+ * For those ioctl which want to exchange mode data that what could
+ * fit in the above structure...
+ */
+
+/*
+ * Range of parameters
+ */
+
+struct iw_range
+{
+ /* Informative stuff (to choose between different interface) */
+ __u32 throughput; /* To give an idea... */
+ /* In theory this value should be the maximum benchmarked
+ * TCP/IP throughput, because with most of these devices the
+ * bit rate is meaningless (overhead an co) to estimate how
+ * fast the connection will go and pick the fastest one.
+ * I suggest people to play with Netperf or any benchmark...
+ */
+
+ /* NWID (or domain id) */
+ __u32 min_nwid; /* Minimal NWID we are able to set */
+ __u32 max_nwid; /* Maximal NWID we are able to set */
+
+ /* Frequency */
+ __u16 num_channels; /* Number of channels [0; num - 1] */
+ __u8 num_frequency; /* Number of entry in the list */
+ struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
+ /* Note : this frequency list doesn't need to fit channel numbers */
+
+ /* signal level threshold range */
+ __s32 sensitivity;
+
+ /* Quality of link & SNR stuff */
+ struct iw_quality max_qual; /* Quality of the link */
+
+ /* Rates */
+ __u8 num_bitrates; /* Number of entries in the list */
+ __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */
+
+ /* RTS threshold */
+ __s32 min_rts; /* Minimal RTS threshold */
+ __s32 max_rts; /* Maximal RTS threshold */
+
+ /* Frag threshold */
+ __s32 min_frag; /* Minimal frag threshold */
+ __s32 max_frag; /* Maximal frag threshold */
+
+ /* Power Management duration & timeout */
+ __s32 min_pmd; /* Minimal PM duration */
+ __s32 max_pmd; /* Maximal PM duration */
+ __s32 min_pmt; /* Minimal PM timeout */
+ __s32 max_pmt; /* Maximal PM timeout */
+
+ /* Encoder stuff */
+ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */
+ __u8 num_encoding_sizes; /* Number of entry in the list */
+ __u8 max_encoding_tokens; /* Max number of tokens */
+};
+
+/*
+ * Private ioctl interface information
+ */
+
+struct iw_priv_args
+{
+ __u32 cmd; /* Number of the ioctl to issue */
+ __u16 set_args; /* Type and number of args */
+ __u16 get_args; /* Type and number of args */
+ char name[IFNAMSIZ]; /* Name of the extension */
+};
+
+#endif /* _LINUX_WIRELESS_H */
diff --git a/pfinet/linux-src/include/linux/wrapper.h b/pfinet/linux-src/include/linux/wrapper.h
new file mode 100644
index 00000000..d8a73117
--- /dev/null
+++ b/pfinet/linux-src/include/linux/wrapper.h
@@ -0,0 +1,40 @@
+#ifndef _WRAPPER_H_
+#define _WRAPPER_H_
+#define wait_handle struct wait_queue
+#define file_handle struct file
+#define inode_handle struct inode
+#define select_table_handle select_table
+#define vm_area_handle struct vm_area_struct
+#define file_operation_handle file_operations
+
+#define connect_wrapper(x) 0
+#define current_got_fatal_signal() (signal_pending(current))
+#define current_set_timeout(val) current->timeout = val
+
+#define module_interruptible_sleep_on interruptible_sleep_on
+#define module_wake_up wake_up
+#define module_select_wait select_wait
+#define module_register_chrdev register_chrdev
+#define module_unregister_chrdev unregister_chrdev
+#define module_register_blkdev register_blkdev
+#define module_unregister_blkdev unregister_blkdev
+
+#define inode_get_rdev(i) i->i_rdev
+#define inode_get_count(i) i->i_count
+#define inode_inc_count(i) i->i_count++
+#define inode_dec_count(i) i->i_count--
+
+#define file_get_flags(f) f->f_flags
+
+#define vma_set_inode(v,i) v->vm_inode = i
+#define vma_get_flags(v) v->vm_flags
+#define vma_get_offset(v) v->vm_offset
+#define vma_get_start(v) v->vm_start
+#define vma_get_end(v) v->vm_end
+#define vma_get_page_prot(v) v->vm_page_prot
+
+#define mem_map_reserve(p) set_bit(PG_reserved, &mem_map[p].flags)
+#define mem_map_unreserve(p) clear_bit(PG_reserved, &mem_map[p].flags)
+#define mem_map_inc_count(p) atomic_inc(&(mem_map[p].count))
+#define mem_map_dec_count(p) atomic_dec(&(mem_map[p].count))
+#endif
diff --git a/pfinet/linux-src/include/linux/x25.h b/pfinet/linux-src/include/linux/x25.h
new file mode 100644
index 00000000..6f3f300b
--- /dev/null
+++ b/pfinet/linux-src/include/linux/x25.h
@@ -0,0 +1,93 @@
+/*
+ * These are the public elements of the Linux kernel X.25 implementation.
+ */
+
+#ifndef X25_KERNEL_H
+#define X25_KERNEL_H
+
+#define SIOCX25GSUBSCRIP (SIOCPROTOPRIVATE + 0)
+#define SIOCX25SSUBSCRIP (SIOCPROTOPRIVATE + 1)
+#define SIOCX25GFACILITIES (SIOCPROTOPRIVATE + 2)
+#define SIOCX25SFACILITIES (SIOCPROTOPRIVATE + 3)
+#define SIOCX25GCALLUSERDATA (SIOCPROTOPRIVATE + 4)
+#define SIOCX25SCALLUSERDATA (SIOCPROTOPRIVATE + 5)
+#define SIOCX25GCAUSEDIAG (SIOCPROTOPRIVATE + 6)
+
+/*
+ * Values for {get,set}sockopt.
+ */
+#define X25_QBITINCL 1
+
+/*
+ * X.25 Packet Size values.
+ */
+#define X25_PS16 4
+#define X25_PS32 5
+#define X25_PS64 6
+#define X25_PS128 7
+#define X25_PS256 8
+#define X25_PS512 9
+#define X25_PS1024 10
+#define X25_PS2048 11
+#define X25_PS4096 12
+
+/*
+ * An X.121 address, it is held as ASCII text, null terminated, up to 15
+ * digits and a null terminator.
+ */
+typedef struct {
+ char x25_addr[16];
+} x25_address;
+
+/*
+ * Linux X.25 Address structure, used for bind, and connect mostly.
+ */
+struct sockaddr_x25 {
+ sa_family_t sx25_family; /* Must be AF_X25 */
+ x25_address sx25_addr; /* X.121 Address */
+};
+
+/*
+ * DTE/DCE subscription options.
+ */
+struct x25_subscrip_struct {
+ char device[200];
+ unsigned int extended;
+};
+
+/*
+ * Routing table control structure.
+ */
+struct x25_route_struct {
+ x25_address address;
+ unsigned int sigdigits;
+ char device[200];
+};
+
+/*
+ * Facilities structure.
+ */
+struct x25_facilities {
+ unsigned int winsize_in, winsize_out;
+ unsigned int pacsize_in, pacsize_out;
+ unsigned int throughput;
+ unsigned int reverse;
+};
+
+/*
+ * Call User Data structure.
+ */
+struct x25_calluserdata {
+ unsigned int cudlength;
+ unsigned char cuddata[128];
+};
+
+/*
+ * Call clearing Cause and Diagnostic structure.
+ */
+struct x25_causediag {
+ unsigned char cause;
+ unsigned char diagnostic;
+};
+
+#endif
diff --git a/pfinet/linux-src/include/linux/yam.h b/pfinet/linux-src/include/linux/yam.h
new file mode 100644
index 00000000..7fe28228
--- /dev/null
+++ b/pfinet/linux-src/include/linux/yam.h
@@ -0,0 +1,82 @@
+/*****************************************************************************/
+
+/*
+ * yam.h -- YAM radio modem driver.
+ *
+ * Copyright (C) 1998 Frederic Rible F1OAT (frible@teaser.fr)
+ * Adapted from baycom.c driver written by Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please note that the GPL allows you to use the driver, NOT the radio.
+ * In order to use the radio, you need a license from the communications
+ * authority of your country.
+ *
+ *
+ */
+
+/*****************************************************************************/
+
+#define SIOCYAMRESERVED (0)
+#define SIOCYAMSCFG (1) /* Set configuration */
+#define SIOCYAMGCFG (2) /* Get configuration */
+#define SIOCYAMSMCS (3) /* Set mcs data */
+
+#define YAM_IOBASE (1 << 0)
+#define YAM_IRQ (1 << 1)
+#define YAM_BITRATE (1 << 2) /* Bit rate of radio port ->57600 */
+#define YAM_MODE (1 << 3) /* 0=simplex 1=duplex 2=duplex+tempo */
+#define YAM_HOLDDLY (1 << 4) /* duplex tempo (sec) */
+#define YAM_TXDELAY (1 << 5) /* Tx Delay (ms) */
+#define YAM_TXTAIL (1 << 6) /* Tx Tail (ms) */
+#define YAM_PERSIST (1 << 7) /* Persist (ms) */
+#define YAM_SLOTTIME (1 << 8) /* Slottime (ms) */
+#define YAM_BAUDRATE (1 << 9) /* Baud rate of rs232 port ->115200 */
+
+#define YAM_MAXBITRATE 57600
+#define YAM_MAXBAUDRATE 115200
+#define YAM_MAXMODE 2
+#define YAM_MAXHOLDDLY 99
+#define YAM_MAXTXDELAY 999
+#define YAM_MAXTXTAIL 999
+#define YAM_MAXPERSIST 255
+#define YAM_MAXSLOTTIME 999
+
+#define YAM_FPGA_SIZE 5302
+
+struct yamcfg {
+ unsigned int mask; /* Mask of commands */
+ unsigned int iobase; /* IO Base of COM port */
+ unsigned int irq; /* IRQ of COM port */
+ unsigned int bitrate; /* Bit rate of radio port */
+ unsigned int baudrate; /* Baud rate of the RS232 port */
+ unsigned int txdelay; /* TxDelay */
+ unsigned int txtail; /* TxTail */
+ unsigned int persist; /* Persistence */
+ unsigned int slottime; /* Slottime */
+ unsigned int mode; /* mode 0 (simp), 1(Dupl), 2(Dupl+delay) */
+ unsigned int holddly; /* PTT delay in FullDuplex 2 mode */
+};
+
+struct yamdrv_ioctl_cfg {
+ int cmd;
+ struct yamcfg cfg;
+};
+
+struct yamdrv_ioctl_mcs {
+ int cmd;
+ int bitrate;
+ unsigned char bits[YAM_FPGA_SIZE];
+};
diff --git a/pfinet/linux-src/include/linux/zftape.h b/pfinet/linux-src/include/linux/zftape.h
new file mode 100644
index 00000000..ec5d2ffe
--- /dev/null
+++ b/pfinet/linux-src/include/linux/zftape.h
@@ -0,0 +1,87 @@
+#ifndef _ZFTAPE_H
+#define _ZFTAPE_H
+
+/*
+ * Copyright (C) 1996, 1997 Claus-Justus Heine.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *
+ * $Source: /homes/cvs/ftape-stacked/include/linux/zftape.h,v $
+ * $Revision: 1.12 $
+ * $Date: 1997/10/21 11:02:37 $
+ *
+ * Special ioctl and other global info for the zftape VFS
+ * interface for the QIC-40/80/3010/3020 floppy-tape driver for
+ * Linux.
+ */
+
+#define ZFTAPE_VERSION "zftape for " FTAPE_VERSION
+
+#include <linux/ftape.h>
+
+#define ZFTAPE_LABEL "Ftape - The Linux Floppy Tape Project!"
+
+/* Bits of the minor device number that control the operation mode */
+#define ZFT_Q80_MODE (1 << 3)
+#define ZFT_ZIP_MODE (1 << 4)
+#define ZFT_RAW_MODE (1 << 5)
+#define ZFT_MINOR_OP_MASK (ZFT_Q80_MODE | \
+ ZFT_ZIP_MODE | \
+ ZFT_RAW_MODE)
+#define ZFT_MINOR_MASK (FTAPE_SEL_MASK | \
+ ZFT_MINOR_OP_MASK | \
+ FTAPE_NO_REWIND)
+
+#ifdef ZFT_OBSOLETE
+struct mtblksz {
+ unsigned int mt_blksz;
+};
+#define MTIOC_ZFTAPE_GETBLKSZ _IOR('m', 104, struct mtblksz)
+#endif
+
+#ifdef __KERNEL__
+
+extern int zft_init(void);
+
+extern inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz)
+{
+ if (blk_sz == 1) {
+ return value;
+ } else {
+ return (__s64)(((__u32)(value >> 10) + (blk_sz >> 10) - 1)
+ / (blk_sz >> 10));
+ }
+}
+
+extern inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz)
+{
+ if (blk_sz == 1) {
+ return value;
+ } else {
+ /* if blk_sz != 1, then it is a multiple of 1024. In
+ * this case, `value' will also fit into 32 bits.
+ *
+ * Actually, this limits the capacity to 42
+ * bits. This is (2^32)*1024, roughly a thousand
+ * times 2GB, or 3 Terabytes. Hopefully this is enough
+ */
+ return(__s64)(((__u32)(value)*(blk_sz>>10))<<10);
+ }
+}
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/linux/zorro.h b/pfinet/linux-src/include/linux/zorro.h
new file mode 100644
index 00000000..9ec9ca71
--- /dev/null
+++ b/pfinet/linux-src/include/linux/zorro.h
@@ -0,0 +1,736 @@
+/*
+ * linux/zorro.h -- Amiga AutoConfig (Zorro) Bus Definitions
+ *
+ * Copyright (C) 1995-1998 Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _LINUX_ZORRO_H
+#define _LINUX_ZORRO_H
+
+#ifndef __ASSEMBLY__
+
+ /*
+ * Known Zorro Boards
+ *
+ * Each Zorro board has a 32-bit ID of the form
+ *
+ * mmmmmmmmmmmmmmmmppppppppeeeeeeee
+ *
+ * with
+ *
+ * mmmmmmmmmmmmmmmm 16-bit Manufacturer ID (assigned by CBM (sigh))
+ * pppppppp 8-bit Product ID (assigned by manufacturer)
+ * eeeeeeee 8-bit Extended Product ID (currently only used
+ * for some GVP boards)
+ */
+
+
+#define ZORRO_MANUF(id) ((id) >> 16)
+#define ZORRO_PROD(id) (((id) >> 8) & 0xff)
+#define ZORRO_EPC(id) ((id) & 0xff)
+
+#define ZORRO_ID(manuf, prod, epc) \
+ ((ZORRO_MANUF_##manuf << 16) | ((prod) << 8) | (epc))
+
+typedef __u32 zorro_id;
+
+
+#define ZORRO_MANUF_PACIFIC_PERIPHERALS 0x00D3
+#define ZORRO_PROD_PACIFIC_PERIPHERALS_SE_2000_A500 ZORRO_ID(PACIFIC_PERIPHERALS, 0x00, 0)
+#define ZORRO_PROD_PACIFIC_PERIPHERALS_SCSI ZORRO_ID(PACIFIC_PERIPHERALS, 0x0A, 0)
+
+#define ZORRO_MANUF_MACROSYSTEMS_USA_2 0x0100
+#define ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE ZORRO_ID(MACROSYSTEMS_USA_2, 0x13, 0)
+
+#define ZORRO_MANUF_KUPKE_1 0x00DD
+#define ZORRO_PROD_KUPKE_GOLEM_RAM_BOX_2MB ZORRO_ID(KUPKE_1, 0x00, 0)
+
+#define ZORRO_MANUF_MEMPHIS 0x0100
+#define ZORRO_PROD_MEMPHIS_STORMBRINGER ZORRO_ID(MEMPHIS, 0x00, 0)
+
+#define ZORRO_MANUF_3_STATE 0x0200
+#define ZORRO_PROD_3_STATE_MEGAMIX_2000 ZORRO_ID(3_STATE, 0x02, 0)
+
+#define ZORRO_MANUF_COMMODORE_BRAUNSCHWEIG 0x0201
+#define ZORRO_PROD_CBM_A2088_A2286 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x01, 0)
+#define ZORRO_PROD_CBM_A2286 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x02, 0)
+#define ZORRO_PROD_CBM_A4091_1 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x54, 0)
+#define ZORRO_PROD_CBM_A2386SX_1 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x67, 0)
+
+#define ZORRO_MANUF_COMMODORE_WEST_CHESTER_1 0x0202
+#define ZORRO_PROD_CBM_A2090A ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x01, 0)
+#define ZORRO_PROD_CBM_A590_A2091_1 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x02, 0)
+#define ZORRO_PROD_CBM_A590_A2091_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x03, 0)
+#define ZORRO_PROD_CBM_A2090B ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x04, 0)
+#define ZORRO_PROD_CBM_A2060 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x09, 0)
+#define ZORRO_PROD_CBM_A590_A2052_A2058_A2091 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x0A, 0)
+#define ZORRO_PROD_CBM_A560_RAM ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x20, 0)
+#define ZORRO_PROD_CBM_A2232_PROTOTYPE ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x45, 0)
+#define ZORRO_PROD_CBM_A2232 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x46, 0)
+#define ZORRO_PROD_CBM_A2620 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x50, 0)
+#define ZORRO_PROD_CBM_A2630 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x51, 0)
+#define ZORRO_PROD_CBM_A4091_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x54, 0)
+#define ZORRO_PROD_CBM_A2065_1 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x5A, 0)
+#define ZORRO_PROD_CBM_ROMULATOR ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x60, 0)
+#define ZORRO_PROD_CBM_A3000_TEST_FIXTURE ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x61, 0)
+#define ZORRO_PROD_CBM_A2386SX_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x67, 0)
+#define ZORRO_PROD_CBM_A2065_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x70, 0)
+
+#define ZORRO_MANUF_COMMODORE_WEST_CHESTER_2 0x0203
+#define ZORRO_PROD_CBM_A2090A_CM ZORRO_ID(COMMODORE_WEST_CHESTER_2, 0x03, 0)
+
+#define ZORRO_MANUF_PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2 0x02F4
+#define ZORRO_PROD_PPS_EXP8000 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2, 0x02, 0)
+
+#define ZORRO_MANUF_KOLFF_COMPUTER_SUPPLIES 0x02FF
+#define ZORRO_PROD_KCS_POWER_PC_BOARD ZORRO_ID(KOLFF_COMPUTER_SUPPLIES, 0x00, 0)
+
+#define ZORRO_MANUF_CARDCO_1 0x03EC
+#define ZORRO_PROD_CARDCO_KRONOS_2000_1 ZORRO_ID(CARDCO_1, 0x04, 0)
+#define ZORRO_PROD_CARDCO_A1000_1 ZORRO_ID(CARDCO_1, 0x0C, 0)
+#define ZORRO_PROD_CARDCO_ESCORT ZORRO_ID(CARDCO_1, 0x0E, 0)
+#define ZORRO_PROD_CARDCO_A2410 ZORRO_ID(CARDCO_1, 0xF5, 0)
+
+#define ZORRO_MANUF_A_SQUARED 0x03ED
+#define ZORRO_PROD_A_SQUARED_LIVE_2000 ZORRO_ID(A_SQUARED, 0x01, 0)
+
+#define ZORRO_MANUF_COMSPEC_COMMUNICATIONS 0x03EE
+#define ZORRO_PROD_COMSPEC_COMMUNICATIONS_AX2000 ZORRO_ID(COMSPEC_COMMUNICATIONS, 0x01, 0)
+
+#define ZORRO_MANUF_ANAKIN_RESEARCH 0x03F1
+#define ZORRO_PROD_ANAKIN_RESEARCH_EASYL ZORRO_ID(ANAKIN_RESEARCH, 0x01, 0)
+
+#define ZORRO_MANUF_MICROBOTICS 0x03F2
+#define ZORRO_PROD_MICROBOTICS_STARBOARD_II ZORRO_ID(MICROBOTICS, 0x00, 0)
+#define ZORRO_PROD_MICROBOTICS_STARDRIVE ZORRO_ID(MICROBOTICS, 0x02, 0)
+#define ZORRO_PROD_MICROBOTICS_8_UP_A ZORRO_ID(MICROBOTICS, 0x03, 0)
+#define ZORRO_PROD_MICROBOTICS_8_UP_Z ZORRO_ID(MICROBOTICS, 0x04, 0)
+#define ZORRO_PROD_MICROBOTICS_DELTA_RAM ZORRO_ID(MICROBOTICS, 0x20, 0)
+#define ZORRO_PROD_MICROBOTICS_8_STAR_RAM ZORRO_ID(MICROBOTICS, 0x40, 0)
+#define ZORRO_PROD_MICROBOTICS_8_STAR ZORRO_ID(MICROBOTICS, 0x41, 0)
+#define ZORRO_PROD_MICROBOTICS_VXL_RAM_32 ZORRO_ID(MICROBOTICS, 0x44, 0)
+#define ZORRO_PROD_MICROBOTICS_VXL_68030 ZORRO_ID(MICROBOTICS, 0x45, 0)
+#define ZORRO_PROD_MICROBOTICS_DELTA ZORRO_ID(MICROBOTICS, 0x60, 0)
+#define ZORRO_PROD_MICROBOTICS_MBX_1200_1200Z_RAM ZORRO_ID(MICROBOTICS, 0x81, 0)
+#define ZORRO_PROD_MICROBOTICS_HARDFRAME_2000_1 ZORRO_ID(MICROBOTICS, 0x96, 0)
+#define ZORRO_PROD_MICROBOTICS_HARDFRAME_2000_2 ZORRO_ID(MICROBOTICS, 0x9E, 0)
+#define ZORRO_PROD_MICROBOTICS_MBX_1200_1200Z ZORRO_ID(MICROBOTICS, 0xC1, 0)
+
+#define ZORRO_MANUF_ACCESS_ASSOCIATES_ALEGRA 0x03F4
+
+#define ZORRO_MANUF_EXPANSION_TECHNOLOGIES 0x03F6
+
+#define ZORRO_MANUF_ASDG 0x03FF
+#define ZORRO_PROD_ASDG_MEMORY_1 ZORRO_ID(ASDG, 0x01, 0)
+#define ZORRO_PROD_ASDG_MEMORY_2 ZORRO_ID(ASDG, 0x02, 0)
+#define ZORRO_PROD_ASDG_EB920_LAN_ROVER ZORRO_ID(ASDG, 0xFE, 0)
+#define ZORRO_PROD_ASDG_GPIB_DUALIEEE488_TWIN_X ZORRO_ID(ASDG, 0xFF, 0)
+
+#define ZORRO_MANUF_IMTRONICS_1 0x0404
+#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_1 ZORRO_ID(IMTRONICS_1, 0x39, 0)
+#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_2 ZORRO_ID(IMTRONICS_1, 0x57, 0)
+
+#define ZORRO_MANUF_CBM_UNIVERSITY_OF_LOWELL 0x0406
+#define ZORRO_PROD_CBM_A2410 ZORRO_ID(CBM_UNIVERSITY_OF_LOWELL, 0x00, 0)
+
+#define ZORRO_MANUF_AMERISTAR 0x041D
+#define ZORRO_PROD_AMERISTAR_A2065 ZORRO_ID(AMERISTAR, 0x01, 0)
+#define ZORRO_PROD_AMERISTAR_A560 ZORRO_ID(AMERISTAR, 0x09, 0)
+#define ZORRO_PROD_AMERISTAR_A4066 ZORRO_ID(AMERISTAR, 0x0A, 0)
+
+#define ZORRO_MANUF_SUPRA 0x0420
+#define ZORRO_PROD_SUPRA_SUPRADRIVE_4x4 ZORRO_ID(SUPRA, 0x01, 0)
+#define ZORRO_PROD_SUPRA_1000_RAM ZORRO_ID(SUPRA, 0x02, 0)
+#define ZORRO_PROD_SUPRA_2000_DMA ZORRO_ID(SUPRA, 0x03, 0)
+#define ZORRO_PROD_SUPRA_500 ZORRO_ID(SUPRA, 0x05, 0)
+#define ZORRO_PROD_SUPRA_500_SCSI ZORRO_ID(SUPRA, 0x08, 0)
+#define ZORRO_PROD_SUPRA_500XP_2000_RAM ZORRO_ID(SUPRA, 0x09, 0)
+#define ZORRO_PROD_SUPRA_500RX_2000_RAM ZORRO_ID(SUPRA, 0x0A, 0)
+#define ZORRO_PROD_SUPRA_2400ZI ZORRO_ID(SUPRA, 0x0B, 0)
+#define ZORRO_PROD_SUPRA_500XP_SUPRADRIVE_WORDSYNC ZORRO_ID(SUPRA, 0x0C, 0)
+#define ZORRO_PROD_SUPRA_SUPRADRIVE_WORDSYNC_II ZORRO_ID(SUPRA, 0x0D, 0)
+#define ZORRO_PROD_SUPRA_2400ZIPLUS ZORRO_ID(SUPRA, 0x10, 0)
+
+#define ZORRO_MANUF_COMPUTER_SYSTEMS_ASSOCIATES 0x0422
+#define ZORRO_PROD_CSA_MAGNUM ZORRO_ID(COMPUTER_SYSTEMS_ASSOCIATES, 0x11, 0)
+#define ZORRO_PROD_CSA_12_GAUGE ZORRO_ID(COMPUTER_SYSTEMS_ASSOCIATES, 0x15, 0)
+
+#define ZORRO_MANUF_MARC_MICHAEL_GROTH 0x0439
+
+#define ZORRO_MANUF_M_TECH 0x0502
+#define ZORRO_PROD_MTEC_AT500_1 ZORRO_ID(M_TECH, 0x03, 0)
+
+#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_1 0x06E1
+#define ZORRO_PROD_GVP_IMPACT_SERIES_I ZORRO_ID(GREAT_VALLEY_PRODUCTS_1, 0x08, 0)
+
+#define ZORRO_MANUF_BYTEBOX 0x07DA
+#define ZORRO_PROD_BYTEBOX_A500 ZORRO_ID(BYTEBOX, 0x00, 0)
+
+#define ZORRO_MANUF_DKB_POWER_COMPUTING 0x07DC
+#define ZORRO_PROD_DKB_POWER_COMPUTING_SECUREKEY ZORRO_ID(DKB_POWER_COMPUTING, 0x09, 0)
+#define ZORRO_PROD_DKB_POWER_COMPUTING_DKM_3128 ZORRO_ID(DKB_POWER_COMPUTING, 0x0E, 0)
+#define ZORRO_PROD_DKB_POWER_COMPUTING_RAPID_FIRE ZORRO_ID(DKB_POWER_COMPUTING, 0x0F, 0)
+#define ZORRO_PROD_DKB_POWER_COMPUTING_DKM_1202 ZORRO_ID(DKB_POWER_COMPUTING, 0x10, 0)
+#define ZORRO_PROD_DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030 ZORRO_ID(DKB_POWER_COMPUTING, 0x12, 0)
+#define ZORRO_PROD_DKB_POWER_COMPUTING_WILDFIRE_060_1 ZORRO_ID(DKB_POWER_COMPUTING, 0x17, 0)
+#define ZORRO_PROD_DKB_POWER_COMPUTING_WILDFIRE_060_2 ZORRO_ID(DKB_POWER_COMPUTING, 0xFF, 0)
+
+#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_2 0x07E1
+#define ZORRO_PROD_GVP_IMPACT_SERIES_I_4K ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x01, 0)
+#define ZORRO_PROD_GVP_IMPACT_SERIES_I_16K_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x02, 0)
+#define ZORRO_PROD_GVP_IMPACT_SERIES_I_16K_3 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x03, 0)
+#define ZORRO_PROD_GVP_IMPACT_3001_IDE_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x08, 0)
+#define ZORRO_PROD_GVP_IMPACT_3001_RAM ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x09, 0)
+#define ZORRO_PROD_GVP_IMPACT_SERIES_II_RAM_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0A, 0)
+#define ZORRO_PROD_GVP_EPC_BASE ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0)
+#define ZORRO_PROD_GVP_GFORCE_040_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x20)
+#define ZORRO_PROD_GVP_GFORCE_040_SCSI_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x30)
+#define ZORRO_PROD_GVP_A1291 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x40)
+#define ZORRO_PROD_GVP_COMBO_030_R4 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x60)
+#define ZORRO_PROD_GVP_COMBO_030_R4_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x70)
+#define ZORRO_PROD_GVP_PHONEPAK ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x78)
+#define ZORRO_PROD_GVP_IO_EXTENDER ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x98)
+#define ZORRO_PROD_GVP_GFORCE_030 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xa0)
+#define ZORRO_PROD_GVP_GFORCE_030_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xb0)
+#define ZORRO_PROD_GVP_A530 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xc0)
+#define ZORRO_PROD_GVP_A530_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xd0)
+#define ZORRO_PROD_GVP_COMBO_030_R3 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xe0)
+#define ZORRO_PROD_GVP_COMBO_030_R3_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xf0)
+#define ZORRO_PROD_GVP_SERIES_II ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xf8)
+#define ZORRO_PROD_GVP_IMPACT_3001_IDE_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0)
+/*#define ZORRO_PROD_GVP_A2000_030 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0)*/
+/*#define ZORRO_PROD_GVP_GFORCE_040_SCSI_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0)*/
+#define ZORRO_PROD_GVP_GFORCE_040_060 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x16, 0)
+#define ZORRO_PROD_GVP_IMPACT_VISION_24 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x20, 0)
+#define ZORRO_PROD_GVP_GFORCE_040_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0xFF, 0)
+
+#define ZORRO_MANUF_CALIFORNIA_ACCESS_SYNERGY 0x07E5
+#define ZORRO_PROD_CALIFORNIA_ACCESS_SYNERGY_MALIBU ZORRO_ID(CALIFORNIA_ACCESS_SYNERGY, 0x01, 0)
+
+#define ZORRO_MANUF_XETEC 0x07E6
+#define ZORRO_PROD_XETEC_FASTCARD ZORRO_ID(XETEC, 0x01, 0)
+#define ZORRO_PROD_XETEC_FASTCARD_RAM ZORRO_ID(XETEC, 0x02, 0)
+#define ZORRO_PROD_XETEC_FASTCARD_PLUS ZORRO_ID(XETEC, 0x03, 0)
+
+#define ZORRO_MANUF_PROGRESSIVE_PERIPHERALS_AND_SYSTEMS 0x07EA
+#define ZORRO_PROD_PPS_MERCURY ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x00, 0)
+#define ZORRO_PROD_PPS_A3000_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x01, 0)
+#define ZORRO_PROD_PPS_A2000_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x69, 0)
+#define ZORRO_PROD_PPS_ZEUS ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x96, 0)
+#define ZORRO_PROD_PPS_A500_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0xBB, 0)
+
+#define ZORRO_MANUF_XEBEC 0x07EC
+
+#define ZORRO_MANUF_SPIRIT_TECHNOLOGY 0x07F2
+#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INSIDER_IN1000 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x01, 0)
+#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INSIDER_IN500 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x02, 0)
+#define ZORRO_PROD_SPIRIT_TECHNOLOGY_SIN500 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x03, 0)
+#define ZORRO_PROD_SPIRIT_TECHNOLOGY_HDA_506 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x04, 0)
+#define ZORRO_PROD_SPIRIT_TECHNOLOGY_AX_S ZORRO_ID(SPIRIT_TECHNOLOGY, 0x05, 0)
+#define ZORRO_PROD_SPIRIT_TECHNOLOGY_OCTABYTE ZORRO_ID(SPIRIT_TECHNOLOGY, 0x06, 0)
+#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INMATE ZORRO_ID(SPIRIT_TECHNOLOGY, 0x08, 0)
+
+#define ZORRO_MANUF_SPIRIT_TECHNOLOGY_2 0x07F3
+
+#define ZORRO_MANUF_BSC_ALFADATA_1 0x07FE
+#define ZORRO_PROD_BSC_ALF_3_1 ZORRO_ID(BSC_ALFADATA_1, 0x03, 0)
+
+#define ZORRO_MANUF_BSC_ALFADATA_2 0x0801
+#define ZORRO_PROD_BSC_ALF_2_1 ZORRO_ID(BSC_ALFADATA_2, 0x01, 0)
+#define ZORRO_PROD_BSC_ALF_2_2 ZORRO_ID(BSC_ALFADATA_2, 0x02, 0)
+#define ZORRO_PROD_BSC_ALF_3_2 ZORRO_ID(BSC_ALFADATA_2, 0x03, 0)
+
+#define ZORRO_MANUF_CARDCO_2 0x0802
+#define ZORRO_PROD_CARDCO_KRONOS_2000_2 ZORRO_ID(CARDCO_2, 0x04, 0)
+#define ZORRO_PROD_CARDCO_A1000_2 ZORRO_ID(CARDCO_2, 0x0C, 0)
+
+#define ZORRO_MANUF_JOCHHEIM 0x0804
+#define ZORRO_PROD_JOCHHEIM_RAM ZORRO_ID(JOCHHEIM, 0x01, 0)
+
+#define ZORRO_MANUF_CHECKPOINT_TECHNOLOGIES 0x0807
+#define ZORRO_PROD_CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION ZORRO_ID(CHECKPOINT_TECHNOLOGIES, 0x00, 0)
+
+#define ZORRO_MANUF_EDOTRONIK 0x0810
+#define ZORRO_PROD_EDOTRONIK_IEEE_488 ZORRO_ID(EDOTRONIK, 0x01, 0)
+#define ZORRO_PROD_EDOTRONIK_8032 ZORRO_ID(EDOTRONIK, 0x02, 0)
+#define ZORRO_PROD_EDOTRONIK_MULTISERIAL ZORRO_ID(EDOTRONIK, 0x03, 0)
+#define ZORRO_PROD_EDOTRONIK_VIDEODIGITIZER ZORRO_ID(EDOTRONIK, 0x04, 0)
+#define ZORRO_PROD_EDOTRONIK_PARALLEL_IO ZORRO_ID(EDOTRONIK, 0x05, 0)
+#define ZORRO_PROD_EDOTRONIK_PIC_PROTOYPING ZORRO_ID(EDOTRONIK, 0x06, 0)
+#define ZORRO_PROD_EDOTRONIK_ADC ZORRO_ID(EDOTRONIK, 0x07, 0)
+#define ZORRO_PROD_EDOTRONIK_VME ZORRO_ID(EDOTRONIK, 0x08, 0)
+#define ZORRO_PROD_EDOTRONIK_DSP96000 ZORRO_ID(EDOTRONIK, 0x09, 0)
+
+#define ZORRO_MANUF_NES_INC 0x0813
+#define ZORRO_PROD_NES_INC_RAM ZORRO_ID(NES_INC, 0x00, 0)
+
+#define ZORRO_MANUF_ICD 0x0817
+#define ZORRO_PROD_ICD_ADVANTAGE_2000_SCSI ZORRO_ID(ICD, 0x01, 0)
+#define ZORRO_PROD_ICD_ADVANTAGE_IDE ZORRO_ID(ICD, 0x03, 0)
+#define ZORRO_PROD_ICD_ADVANTAGE_2080_RAM ZORRO_ID(ICD, 0x04, 0)
+
+#define ZORRO_MANUF_KUPKE_2 0x0819
+#define ZORRO_PROD_KUPKE_OMTI ZORRO_ID(KUPKE_2, 0x01, 0)
+#define ZORRO_PROD_KUPKE_SCSI_II ZORRO_ID(KUPKE_2, 0x02, 0)
+#define ZORRO_PROD_KUPKE_GOLEM_BOX ZORRO_ID(KUPKE_2, 0x03, 0)
+#define ZORRO_PROD_KUPKE_030_882 ZORRO_ID(KUPKE_2, 0x04, 0)
+#define ZORRO_PROD_KUPKE_SCSI_AT ZORRO_ID(KUPKE_2, 0x05, 0)
+
+#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_3 0x081D
+#define ZORRO_PROD_GVP_A2000_RAM8 ZORRO_ID(GREAT_VALLEY_PRODUCTS_3, 0x09, 0)
+#define ZORRO_PROD_GVP_IMPACT_SERIES_II_RAM_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_3, 0x0A, 0)
+
+#define ZORRO_MANUF_INTERWORKS_NETWORK 0x081E
+
+#define ZORRO_MANUF_HARDITAL_SYNTHESIS 0x0820
+#define ZORRO_PROD_HARDITAL_SYNTHESIS_TQM_68030_68882 ZORRO_ID(HARDITAL_SYNTHESIS, 0x14, 0)
+
+#define ZORRO_MANUF_APPLIED_ENGINEERING 0x0828
+#define ZORRO_PROD_APPLIED_ENGINEERING_DL2000 ZORRO_ID(APPLIED_ENGINEERING, 0x10, 0)
+#define ZORRO_PROD_APPLIED_ENGINEERING_RAM_WORKS ZORRO_ID(APPLIED_ENGINEERING, 0xE0, 0)
+
+#define ZORRO_MANUF_BSC_ALFADATA_3 0x082C
+#define ZORRO_PROD_BSC_OKTAGON_2008 ZORRO_ID(BSC_ALFADATA_3, 0x05, 0)
+#define ZORRO_PROD_BSC_TANDEM_AT_2008_508 ZORRO_ID(BSC_ALFADATA_3, 0x06, 0)
+#define ZORRO_PROD_BSC_ALFA_RAM_1200 ZORRO_ID(BSC_ALFADATA_3, 0x07, 0)
+#define ZORRO_PROD_BSC_OKTAGON_2008_RAM ZORRO_ID(BSC_ALFADATA_3, 0x08, 0)
+#define ZORRO_PROD_BSC_MULTIFACE_I ZORRO_ID(BSC_ALFADATA_3, 0x10, 0)
+#define ZORRO_PROD_BSC_MULTIFACE_II ZORRO_ID(BSC_ALFADATA_3, 0x11, 0)
+#define ZORRO_PROD_BSC_MULTIFACE_III ZORRO_ID(BSC_ALFADATA_3, 0x12, 0)
+#define ZORRO_PROD_BSC_FRAMEMASTER_II ZORRO_ID(BSC_ALFADATA_3, 0x20, 0)
+#define ZORRO_PROD_BSC_GRAFFITI_RAM ZORRO_ID(BSC_ALFADATA_3, 0x21, 0)
+#define ZORRO_PROD_BSC_GRAFFITI_REG ZORRO_ID(BSC_ALFADATA_3, 0x22, 0)
+#define ZORRO_PROD_BSC_ISDN_MASTERCARD ZORRO_ID(BSC_ALFADATA_3, 0x40, 0)
+#define ZORRO_PROD_BSC_ISDN_MASTERCARD_II ZORRO_ID(BSC_ALFADATA_3, 0x41, 0)
+
+#define ZORRO_MANUF_PHOENIX 0x0835
+#define ZORRO_PROD_PHOENIX_ST506 ZORRO_ID(PHOENIX, 0x21, 0)
+#define ZORRO_PROD_PHOENIX_SCSI ZORRO_ID(PHOENIX, 0x22, 0)
+#define ZORRO_PROD_PHOENIX_RAM ZORRO_ID(PHOENIX, 0xBE, 0)
+
+#define ZORRO_MANUF_ADVANCED_STORAGE_SYSTEMS 0x0836
+#define ZORRO_PROD_ADVANCED_STORAGE_SYSTEMS_NEXUS ZORRO_ID(ADVANCED_STORAGE_SYSTEMS, 0x01, 0)
+#define ZORRO_PROD_ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM ZORRO_ID(ADVANCED_STORAGE_SYSTEMS, 0x08, 0)
+
+#define ZORRO_MANUF_IMPULSE 0x0838
+#define ZORRO_PROD_IMPULSE_FIRECRACKER_24 ZORRO_ID(IMPULSE, 0x00, 0)
+
+#define ZORRO_MANUF_IVS 0x0840
+#define ZORRO_PROD_IVS_GRANDSLAM_PIC_2 ZORRO_ID(IVS, 0x02, 0)
+#define ZORRO_PROD_IVS_GRANDSLAM_PIC_1 ZORRO_ID(IVS, 0x04, 0)
+#define ZORRO_PROD_IVS_OVERDRIVE ZORRO_ID(IVS, 0x10, 0)
+#define ZORRO_PROD_IVS_TRUMPCARD_CLASSIC ZORRO_ID(IVS, 0x30, 0)
+#define ZORRO_PROD_IVS_TRUMPCARD_PRO_GRANDSLAM ZORRO_ID(IVS, 0x34, 0)
+#define ZORRO_PROD_IVS_META_4 ZORRO_ID(IVS, 0x40, 0)
+#define ZORRO_PROD_IVS_WAVETOOLS ZORRO_ID(IVS, 0xBF, 0)
+#define ZORRO_PROD_IVS_VECTOR_1 ZORRO_ID(IVS, 0xF3, 0)
+#define ZORRO_PROD_IVS_VECTOR_2 ZORRO_ID(IVS, 0xF4, 0)
+
+#define ZORRO_MANUF_VECTOR_1 0x0841
+#define ZORRO_PROD_VECTOR_CONNECTION_1 ZORRO_ID(VECTOR_1, 0xE3, 0)
+
+#define ZORRO_MANUF_XPERT_PRODEV 0x0845
+#define ZORRO_PROD_XPERT_PRODEV_VISIONA_RAM ZORRO_ID(XPERT_PRODEV, 0x01, 0)
+#define ZORRO_PROD_XPERT_PRODEV_VISIONA_REG ZORRO_ID(XPERT_PRODEV, 0x02, 0)
+#define ZORRO_PROD_XPERT_PRODEV_MERLIN_RAM ZORRO_ID(XPERT_PRODEV, 0x03, 0)
+#define ZORRO_PROD_XPERT_PRODEV_MERLIN_REG_1 ZORRO_ID(XPERT_PRODEV, 0x04, 0)
+#define ZORRO_PROD_XPERT_PRODEV_MERLIN_REG_2 ZORRO_ID(XPERT_PRODEV, 0xC9, 0)
+
+#define ZORRO_MANUF_HYDRA_SYSTEMS 0x0849
+#define ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET ZORRO_ID(HYDRA_SYSTEMS, 0x01, 0)
+
+#define ZORRO_MANUF_SUNRIZE_INDUSTRIES 0x084F
+#define ZORRO_PROD_SUNRIZE_INDUSTRIES_AD1012 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x01, 0)
+#define ZORRO_PROD_SUNRIZE_INDUSTRIES_AD516 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x02, 0)
+#define ZORRO_PROD_SUNRIZE_INDUSTRIES_DD512 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x03, 0)
+
+#define ZORRO_MANUF_TRICERATOPS 0x0850
+#define ZORRO_PROD_TRICERATOPS_MULTI_IO ZORRO_ID(TRICERATOPS, 0x01, 0)
+
+#define ZORRO_MANUF_APPLIED_MAGIC 0x0851
+#define ZORRO_PROD_APPLIED_MAGIC_DMI_RESOLVER ZORRO_ID(APPLIED_MAGIC, 0x01, 0)
+#define ZORRO_PROD_APPLIED_MAGIC_DIGITAL_BROADCASTER ZORRO_ID(APPLIED_MAGIC, 0x06, 0)
+
+#define ZORRO_MANUF_GFX_BASE 0x085E
+#define ZORRO_PROD_GFX_BASE_GDA_1_VRAM ZORRO_ID(GFX_BASE, 0x00, 0)
+#define ZORRO_PROD_GFX_BASE_GDA_1 ZORRO_ID(GFX_BASE, 0x01, 0)
+
+#define ZORRO_MANUF_ROCTEC 0x0860
+#define ZORRO_PROD_ROCTEC_RH_800C ZORRO_ID(ROCTEC, 0x01, 0)
+#define ZORRO_PROD_ROCTEC_RH_800C_RAM ZORRO_ID(ROCTEC, 0x01, 0)
+
+#define ZORRO_MANUF_KATO 0x0861
+#define ZORRO_PROD_KATO_MELODY ZORRO_ID(KATO, 0x80, 0)
+/* ID clash!! */
+#define ZORRO_MANUF_HELFRICH_1 0x0861
+#define ZORRO_PROD_HELFRICH_RAINBOW_II ZORRO_ID(HELFRICH_1, 0x20, 0)
+#define ZORRO_PROD_HELFRICH_RAINBOW_III ZORRO_ID(HELFRICH_1, 0x21, 0)
+
+#define ZORRO_MANUF_ATLANTIS 0x0862
+
+#define ZORRO_MANUF_PROTAR 0x0864
+
+#define ZORRO_MANUF_ACS 0x0865
+
+#define ZORRO_MANUF_SOFTWARE_RESULTS_ENTERPRISES 0x0866
+#define ZORRO_PROD_SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS ZORRO_ID(SOFTWARE_RESULTS_ENTERPRISES, 0x01, 0)
+
+#define ZORRO_MANUF_MASOBOSHI 0x086D
+#define ZORRO_PROD_MASOBOSHI_MASTER_CARD_SC201 ZORRO_ID(MASOBOSHI, 0x03, 0)
+#define ZORRO_PROD_MASOBOSHI_MASTER_CARD_MC702 ZORRO_ID(MASOBOSHI, 0x04, 0)
+#define ZORRO_PROD_MASOBOSHI_MVD_819 ZORRO_ID(MASOBOSHI, 0x07, 0)
+
+#define ZORRO_MANUF_MAINHATTAN_DATA 0x086F
+#define ZORRO_PROD_MAINHATTAN_DATA_IDE ZORRO_ID(MAINHATTAN_DATA, 0x01, 0)
+
+#define ZORRO_MANUF_VILLAGE_TRONIC 0x0877
+#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_RAM ZORRO_ID(VILLAGE_TRONIC, 0x01, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_REG ZORRO_ID(VILLAGE_TRONIC, 0x02, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE ZORRO_ID(VILLAGE_TRONIC, 0x03, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM ZORRO_ID(VILLAGE_TRONIC, 0x0B, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG ZORRO_ID(VILLAGE_TRONIC, 0x0C, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE ZORRO_ID(VILLAGE_TRONIC, 0x0D, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1 ZORRO_ID(VILLAGE_TRONIC, 0x15, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2 ZORRO_ID(VILLAGE_TRONIC, 0x16, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG ZORRO_ID(VILLAGE_TRONIC, 0x17, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 ZORRO_ID(VILLAGE_TRONIC, 0x18, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE ZORRO_ID(VILLAGE_TRONIC, 0xC9, 0)
+#define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2 ZORRO_ID(VILLAGE_TRONIC, 0xCA, 0)
+
+#define ZORRO_MANUF_UTILITIES_UNLIMITED 0x087B
+#define ZORRO_PROD_UTILITIES_UNLIMITED_EMPLANT_DELUXE ZORRO_ID(UTILITIES_UNLIMITED, 0x15, 0)
+#define ZORRO_PROD_UTILITIES_UNLIMITED_EMPLANT_DELUXE2 ZORRO_ID(UTILITIES_UNLIMITED, 0x20, 0)
+
+#define ZORRO_MANUF_AMITRIX 0x0880
+#define ZORRO_PROD_AMITRIX_MULTI_IO ZORRO_ID(AMITRIX, 0x01, 0)
+#define ZORRO_PROD_AMITRIX_CD_RAM ZORRO_ID(AMITRIX, 0x02, 0)
+
+#define ZORRO_MANUF_ARMAX 0x0885
+#define ZORRO_PROD_ARMAX_OMNIBUS ZORRO_ID(ARMAX, 0x00, 0)
+
+#define ZORRO_MANUF_ZEUS 0x088D
+#define ZORRO_PROD_ZEUS_SPIDER ZORRO_ID(ZEUS, 0x04, 0)
+
+#define ZORRO_MANUF_NEWTEK 0x088F
+#define ZORRO_PROD_NEWTEK_VIDEOTOASTER ZORRO_ID(NEWTEK, 0x00, 0)
+
+#define ZORRO_MANUF_M_TECH_GERMANY 0x0890
+#define ZORRO_PROD_MTEC_AT500_2 ZORRO_ID(M_TECH_GERMANY, 0x01, 0)
+#define ZORRO_PROD_MTEC_68030 ZORRO_ID(M_TECH_GERMANY, 0x03, 0)
+#define ZORRO_PROD_MTEC_68020I ZORRO_ID(M_TECH_GERMANY, 0x06, 0)
+#define ZORRO_PROD_MTEC_A1200_T68030_RTC ZORRO_ID(M_TECH_GERMANY, 0x20, 0)
+#define ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530 ZORRO_ID(M_TECH_GERMANY, 0x21, 0)
+#define ZORRO_PROD_MTEC_8_MB_RAM ZORRO_ID(M_TECH_GERMANY, 0x22, 0)
+#define ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE ZORRO_ID(M_TECH_GERMANY, 0x24, 0)
+
+#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_4 0x0891
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM ZORRO_ID(GREAT_VALLEY_PRODUCTS_4, 0x01, 0)
+#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG ZORRO_ID(GREAT_VALLEY_PRODUCTS_4, 0x02, 0)
+
+#define ZORRO_MANUF_APOLLO_1 0x0892
+#define ZORRO_PROD_APOLLO_A1200 ZORRO_ID(APOLLO_1, 0x01, 0)
+
+#define ZORRO_MANUF_HELFRICH_2 0x0893
+#define ZORRO_PROD_HELFRICH_PICCOLO_RAM ZORRO_ID(HELFRICH_2, 0x05, 0)
+#define ZORRO_PROD_HELFRICH_PICCOLO_REG ZORRO_ID(HELFRICH_2, 0x06, 0)
+#define ZORRO_PROD_HELFRICH_PEGGY_PLUS_MPEG ZORRO_ID(HELFRICH_2, 0x07, 0)
+#define ZORRO_PROD_HELFRICH_VIDEOCRUNCHER ZORRO_ID(HELFRICH_2, 0x08, 0)
+#define ZORRO_PROD_HELFRICH_SD64_RAM ZORRO_ID(HELFRICH_2, 0x0A, 0)
+#define ZORRO_PROD_HELFRICH_SD64_REG ZORRO_ID(HELFRICH_2, 0x0B, 0)
+
+#define ZORRO_MANUF_MACROSYSTEMS_USA 0x089B
+#define ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx ZORRO_ID(MACROSYSTEMS_USA, 0x13, 0)
+
+#define ZORRO_MANUF_ELBOX_COMPUTER 0x089E
+#define ZORRO_PROD_ELBOX_COMPUTER_1200_4 ZORRO_ID(ELBOX_COMPUTER, 0x06, 0)
+
+#define ZORRO_MANUF_HARMS_PROFESSIONAL 0x0A00
+#define ZORRO_PROD_HARMS_PROFESSIONAL_030_PLUS ZORRO_ID(HARMS_PROFESSIONAL, 0x10, 0)
+#define ZORRO_PROD_HARMS_PROFESSIONAL_3500 ZORRO_ID(HARMS_PROFESSIONAL, 0xD0, 0)
+
+#define ZORRO_MANUF_MICRONIK 0x0A50
+#define ZORRO_PROD_MICRONIK_RCA_120 ZORRO_ID(MICRONIK, 0x0A, 0)
+
+#define ZORRO_MANUF_MICRONIK2 0x0F0F
+#define ZORRO_PROD_MICRONIK2_Z3I ZORRO_ID(MICRONIK2, 0x01, 0)
+
+#define ZORRO_MANUF_MEGAMICRO 0x1000
+#define ZORRO_PROD_MEGAMICRO_SCRAM_500 ZORRO_ID(MEGAMICRO, 0x03, 0)
+#define ZORRO_PROD_MEGAMICRO_SCRAM_500_RAM ZORRO_ID(MEGAMICRO, 0x04, 0)
+
+#define ZORRO_MANUF_IMTRONICS_2 0x1028
+#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_3 ZORRO_ID(IMTRONICS_2, 0x39, 0)
+#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_4 ZORRO_ID(IMTRONICS_2, 0x57, 0)
+
+/* unofficial ID */
+#define ZORRO_MANUF_INDIVIDUAL_COMPUTERS 0x1212
+#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x00, 0)
+#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x2A, 0)
+
+#define ZORRO_MANUF_KUPKE_3 0x1248
+#define ZORRO_PROD_KUPKE_GOLEM_HD_3000 ZORRO_ID(KUPKE_3, 0x01, 0)
+
+#define ZORRO_MANUF_ITH 0x1388
+#define ZORRO_PROD_ITH_ISDN_MASTER_II ZORRO_ID(ITH, 0x01, 0)
+
+#define ZORRO_MANUF_VMC 0x1389
+#define ZORRO_PROD_VMC_ISDN_BLASTER_Z2 ZORRO_ID(VMC, 0x01, 0)
+#define ZORRO_PROD_VMC_HYPERCOM_4 ZORRO_ID(VMC, 0x02, 0)
+
+#define ZORRO_MANUF_INFORMATION 0x157C
+#define ZORRO_PROD_INFORMATION_ISDN_ENGINE_I ZORRO_ID(INFORMATION, 0x64, 0)
+
+#define ZORRO_MANUF_VORTEX 0x2017
+#define ZORRO_PROD_VORTEX_GOLDEN_GATE_80386SX ZORRO_ID(VORTEX, 0x07, 0)
+#define ZORRO_PROD_VORTEX_GOLDEN_GATE_RAM ZORRO_ID(VORTEX, 0x08, 0)
+#define ZORRO_PROD_VORTEX_GOLDEN_GATE_80486 ZORRO_ID(VORTEX, 0x09, 0)
+
+#define ZORRO_MANUF_EXPANSION_SYSTEMS 0x2062
+#define ZORRO_PROD_EXPANSION_SYSTEMS_DATAFLYER_4000SX ZORRO_ID(EXPANSION_SYSTEMS, 0x01, 0)
+#define ZORRO_PROD_EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM ZORRO_ID(EXPANSION_SYSTEMS, 0x02, 0)
+
+#define ZORRO_MANUF_READYSOFT 0x2100
+#define ZORRO_PROD_READYSOFT_AMAX_II_IV ZORRO_ID(READYSOFT, 0x01, 0)
+
+#define ZORRO_MANUF_PHASE5 0x2140
+#define ZORRO_PROD_PHASE5_BLIZZARD_RAM ZORRO_ID(PHASE5, 0x01, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD ZORRO_ID(PHASE5, 0x02, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD_1220_IV ZORRO_ID(PHASE5, 0x06, 0)
+#define ZORRO_PROD_PHASE5_FASTLANE_Z3_RAM ZORRO_ID(PHASE5, 0x0A, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060 ZORRO_ID(PHASE5, 0x0B, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM ZORRO_ID(PHASE5, 0x0C, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD_1230 ZORRO_ID(PHASE5, 0x0D, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260 ZORRO_ID(PHASE5, 0x11, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD_2060 ZORRO_ID(PHASE5, 0x18, 0)
+#define ZORRO_PROD_PHASE5_CYBERSTORM_MK_II ZORRO_ID(PHASE5, 0x19, 0)
+#define ZORRO_PROD_PHASE5_CYBERVISION64 ZORRO_ID(PHASE5, 0x22, 0)
+#define ZORRO_PROD_PHASE5_CYBERVISION64_3D_PROTOTYPE ZORRO_ID(PHASE5, 0x32, 0)
+#define ZORRO_PROD_PHASE5_CYBERVISION64_3D ZORRO_ID(PHASE5, 0x43, 0)
+#define ZORRO_PROD_PHASE5_CYBERSTORM_MK_III ZORRO_ID(PHASE5, 0x64, 0)
+#define ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS ZORRO_ID(PHASE5, 0x6e, 0)
+
+#define ZORRO_MANUF_DPS 0x2169
+#define ZORRO_PROD_DPS_PERSONAL_ANIMATION_RECORDER ZORRO_ID(DPS, 0x01, 0)
+
+#define ZORRO_MANUF_APOLLO_2 0x2200
+#define ZORRO_PROD_APOLLO_A620_68020_1 ZORRO_ID(APOLLO_2, 0x00, 0)
+#define ZORRO_PROD_APOLLO_A620_68020_2 ZORRO_ID(APOLLO_2, 0x01, 0)
+
+#define ZORRO_MANUF_APOLLO_3 0x2222
+#define ZORRO_PROD_APOLLO_AT_APOLLO ZORRO_ID(APOLLO_3, 0x22, 0)
+#define ZORRO_PROD_APOLLO_1230_1240_1260_2030_4040_4060 ZORRO_ID(APOLLO_3, 0x23, 0)
+
+#define ZORRO_MANUF_PETSOFF_LP 0x38A5
+#define ZORRO_PROD_PETSOFF_LP_DELFINA ZORRO_ID(PETSOFF_LP, 0x00, 0)
+#define ZORRO_PROD_PETSOFF_LP_DELFINA_LITE ZORRO_ID(PETSOFF_LP, 0x01, 0)
+
+#define ZORRO_MANUF_UWE_GERLACH 0x3FF7
+#define ZORRO_PROD_UWE_GERLACH_RAM_ROM ZORRO_ID(UWE_GERLACH, 0xd4, 0)
+
+#define ZORRO_MANUF_ACT 0x4231
+#define ZORRO_PROD_ACT_PRELUDE ZORRO_ID(ACT, 0x01, 0)
+
+#define ZORRO_MANUF_MACROSYSTEMS_GERMANY 0x4754
+#define ZORRO_PROD_MACROSYSTEMS_MAESTRO ZORRO_ID(MACROSYSTEMS_GERMANY, 0x03, 0)
+#define ZORRO_PROD_MACROSYSTEMS_VLAB ZORRO_ID(MACROSYSTEMS_GERMANY, 0x04, 0)
+#define ZORRO_PROD_MACROSYSTEMS_MAESTRO_PRO ZORRO_ID(MACROSYSTEMS_GERMANY, 0x05, 0)
+#define ZORRO_PROD_MACROSYSTEMS_RETINA ZORRO_ID(MACROSYSTEMS_GERMANY, 0x06, 0)
+#define ZORRO_PROD_MACROSYSTEMS_MULTI_EVOLUTION ZORRO_ID(MACROSYSTEMS_GERMANY, 0x08, 0)
+#define ZORRO_PROD_MACROSYSTEMS_TOCCATA ZORRO_ID(MACROSYSTEMS_GERMANY, 0x0C, 0)
+#define ZORRO_PROD_MACROSYSTEMS_RETINA_Z3 ZORRO_ID(MACROSYSTEMS_GERMANY, 0x10, 0)
+#define ZORRO_PROD_MACROSYSTEMS_VLAB_MOTION ZORRO_ID(MACROSYSTEMS_GERMANY, 0x12, 0)
+#define ZORRO_PROD_MACROSYSTEMS_ALTAIS ZORRO_ID(MACROSYSTEMS_GERMANY, 0x13, 0)
+#define ZORRO_PROD_MACROSYSTEMS_FALCON_040 ZORRO_ID(MACROSYSTEMS_GERMANY, 0xFD, 0)
+
+#define ZORRO_MANUF_COMBITEC 0x6766
+
+#define ZORRO_MANUF_SKI_PERIPHERALS 0x8000
+#define ZORRO_PROD_SKI_PERIPHERALS_MAST_FIREBALL ZORRO_ID(SKI_PERIPHERALS, 0x08, 0)
+#define ZORRO_PROD_SKI_PERIPHERALS_SCSI_DUAL_SERIAL ZORRO_ID(SKI_PERIPHERALS, 0x80, 0)
+
+#define ZORRO_MANUF_REIS_WARE_2 0xA9AD
+#define ZORRO_PROD_REIS_WARE_SCAN_KING ZORRO_ID(REIS_WARE_2, 0x11, 0)
+
+#define ZORRO_MANUF_CAMERON 0xAA01
+#define ZORRO_PROD_CAMERON_PERSONAL_A4 ZORRO_ID(CAMERON, 0x10, 0)
+
+#define ZORRO_MANUF_REIS_WARE 0xAA11
+#define ZORRO_PROD_REIS_WARE_HANDYSCANNER ZORRO_ID(REIS_WARE, 0x11, 0)
+
+#define ZORRO_MANUF_PHOENIX_2 0xB5A8
+#define ZORRO_PROD_PHOENIX_ST506_2 ZORRO_ID(PHOENIX_2, 0x21, 0)
+#define ZORRO_PROD_PHOENIX_SCSI_2 ZORRO_ID(PHOENIX_2, 0x22, 0)
+#define ZORRO_PROD_PHOENIX_RAM_2 ZORRO_ID(PHOENIX_2, 0xBE, 0)
+
+#define ZORRO_MANUF_COMBITEC_2 0xC008
+#define ZORRO_PROD_COMBITEC_HD ZORRO_ID(COMBITEC_2, 0x2A, 0)
+#define ZORRO_PROD_COMBITEC_SRAM ZORRO_ID(COMBITEC_2, 0x2B, 0)
+
+
+ /*
+ * Test and illegal Manufacturer IDs.
+ */
+
+#define ZORRO_MANUF_HACKER 0x07DB
+#define ZORRO_PROD_GENERAL_PROTOTYPE ZORRO_ID(HACKER, 0x00, 0)
+#define ZORRO_PROD_HACKER_SCSI ZORRO_ID(HACKER, 0x01, 0)
+#define ZORRO_PROD_RESOURCE_MANAGEMENT_FORCE_QUICKNET_QN2000 ZORRO_ID(HACKER, 0x02, 0)
+#define ZORRO_PROD_VECTOR_CONNECTION_2 ZORRO_ID(HACKER, 0xE0, 0)
+#define ZORRO_PROD_VECTOR_CONNECTION_3 ZORRO_ID(HACKER, 0xE1, 0)
+#define ZORRO_PROD_VECTOR_CONNECTION_4 ZORRO_ID(HACKER, 0xE2, 0)
+#define ZORRO_PROD_VECTOR_CONNECTION_5 ZORRO_ID(HACKER, 0xE3, 0)
+
+
+ /*
+ * GVP identifies most of its products through the 'extended product code'
+ * (epc). The epc has to be ANDed with the GVP_PRODMASK before the
+ * identification.
+ */
+
+#define GVP_PRODMASK (0xf8)
+#define GVP_SCSICLKMASK (0x01)
+
+enum GVP_flags {
+ GVP_IO = 0x01,
+ GVP_ACCEL = 0x02,
+ GVP_SCSI = 0x04,
+ GVP_24BITDMA = 0x08,
+ GVP_25BITDMA = 0x10,
+ GVP_NOBANK = 0x20,
+ GVP_14MHZ = 0x40,
+};
+
+
+struct Node {
+ struct Node *ln_Succ; /* Pointer to next (successor) */
+ struct Node *ln_Pred; /* Pointer to previous (predecessor) */
+ __u8 ln_Type;
+ __s8 ln_Pri; /* Priority, for sorting */
+ __s8 *ln_Name; /* ID string, null terminated */
+} __attribute__ ((packed));
+
+struct ExpansionRom {
+ /* -First 16 bytes of the expansion ROM */
+ __u8 er_Type; /* Board type, size and flags */
+ __u8 er_Product; /* Product number, assigned by manufacturer */
+ __u8 er_Flags; /* Flags */
+ __u8 er_Reserved03; /* Must be zero ($ff inverted) */
+ __u16 er_Manufacturer; /* Unique ID, ASSIGNED BY COMMODORE-AMIGA! */
+ __u32 er_SerialNumber; /* Available for use by manufacturer */
+ __u16 er_InitDiagVec; /* Offset to optional "DiagArea" structure */
+ __u8 er_Reserved0c;
+ __u8 er_Reserved0d;
+ __u8 er_Reserved0e;
+ __u8 er_Reserved0f;
+} __attribute__ ((packed));
+
+/* er_Type board type bits */
+#define ERT_TYPEMASK 0xc0
+#define ERT_ZORROII 0xc0
+#define ERT_ZORROIII 0x80
+
+/* other bits defined in er_Type */
+#define ERTB_MEMLIST 5 /* Link RAM into free memory list */
+#define ERTF_MEMLIST (1<<5)
+
+struct ConfigDev {
+ struct Node cd_Node;
+ __u8 cd_Flags; /* (read/write) */
+ __u8 cd_Pad; /* reserved */
+ struct ExpansionRom cd_Rom; /* copy of board's expansion ROM */
+ void *cd_BoardAddr; /* where in memory the board was placed */
+ __u32 cd_BoardSize; /* size of board in bytes */
+ __u16 cd_SlotAddr; /* which slot number (PRIVATE) */
+ __u16 cd_SlotSize; /* number of slots (PRIVATE) */
+ void *cd_Driver; /* pointer to node of driver */
+ struct ConfigDev *cd_NextCD; /* linked list of drivers to config */
+ __u32 cd_Unused[4]; /* for whatever the driver wants */
+} __attribute__ ((packed));
+
+#else /* __ASSEMBLY__ */
+
+LN_Succ = 0
+LN_Pred = LN_Succ+4
+LN_Type = LN_Pred+4
+LN_Pri = LN_Type+1
+LN_Name = LN_Pri+1
+LN_sizeof = LN_Name+4
+
+ER_Type = 0
+ER_Product = ER_Type+1
+ER_Flags = ER_Product+1
+ER_Reserved03 = ER_Flags+1
+ER_Manufacturer = ER_Reserved03+1
+ER_SerialNumber = ER_Manufacturer+2
+ER_InitDiagVec = ER_SerialNumber+4
+ER_Reserved0c = ER_InitDiagVec+2
+ER_Reserved0d = ER_Reserved0c+1
+ER_Reserved0e = ER_Reserved0d+1
+ER_Reserved0f = ER_Reserved0e+1
+ER_sizeof = ER_Reserved0f+1
+
+CD_Node = 0
+CD_Flags = CD_Node+LN_sizeof
+CD_Pad = CD_Flags+1
+CD_Rom = CD_Pad+1
+CD_BoardAddr = CD_Rom+ER_sizeof
+CD_BoardSize = CD_BoardAddr+4
+CD_SlotAddr = CD_BoardSize+4
+CD_SlotSize = CD_SlotAddr+2
+CD_Driver = CD_SlotSize+2
+CD_NextCD = CD_Driver+4
+CD_Unused = CD_NextCD+4
+CD_sizeof = CD_Unused+(4*4)
+
+#endif /* __ASSEMBLY__ */
+
+#ifndef __ASSEMBLY__
+
+#define ZORRO_NUM_AUTO 16
+
+#ifdef __KERNEL__
+
+extern unsigned int zorro_num_autocon; /* # of autoconfig devices found */
+extern struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
+
+
+ /*
+ * Zorro Functions
+ */
+
+extern void zorro_init(void);
+extern void zorro_proc_init(void);
+
+extern unsigned int zorro_find(zorro_id id, unsigned int part, unsigned int index);
+extern const struct ConfigDev *zorro_get_board(unsigned int key);
+extern void zorro_config_board(unsigned int key, unsigned int part);
+extern void zorro_unconfig_board(unsigned int key, unsigned int part);
+
+
+ /*
+ * Bitmask indicating portions of available Zorro II RAM that are unused
+ * by the system. Every bit represents a 64K chunk, for a maximum of 8MB
+ * (128 chunks, physical 0x00200000-0x009fffff).
+ *
+ * If you want to use (= allocate) portions of this RAM, you should clear
+ * the corresponding bits.
+ */
+
+extern __u32 zorro_unused_z2ram[4];
+
+#define Z2RAM_START (0x00200000)
+#define Z2RAM_END (0x00a00000)
+#define Z2RAM_SIZE (0x00800000)
+#define Z2RAM_CHUNKSIZE (0x00010000)
+#define Z2RAM_CHUNKMASK (0x0000ffff)
+#define Z2RAM_CHUNKSHIFT (16)
+
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_ZORRO_H */
diff --git a/pfinet/linux-src/include/net/addrconf.h b/pfinet/linux-src/include/net/addrconf.h
new file mode 100644
index 00000000..d711d0d5
--- /dev/null
+++ b/pfinet/linux-src/include/net/addrconf.h
@@ -0,0 +1,158 @@
+#ifndef _ADDRCONF_H
+#define _ADDRCONF_H
+
+#define RETRANS_TIMER HZ
+
+#define MAX_RTR_SOLICITATIONS 3
+#define RTR_SOLICITATION_INTERVAL (4*HZ)
+
+#define ADDR_CHECK_FREQUENCY (120*HZ)
+
+struct prefix_info {
+ __u8 type;
+ __u8 length;
+ __u8 prefix_len;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 onlink : 1,
+ autoconf : 1,
+ reserved : 6;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 reserved : 6,
+ autoconf : 1,
+ onlink : 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ __u32 valid;
+ __u32 prefered;
+ __u32 reserved2;
+
+ struct in6_addr prefix;
+};
+
+
+#ifdef __KERNEL__
+
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <net/if_inet6.h>
+
+#define IN6_ADDR_HSIZE 16
+
+extern void addrconf_init(void);
+extern void addrconf_cleanup(void);
+
+extern int addrconf_notify(struct notifier_block *this,
+ unsigned long event,
+ void * data);
+
+extern int addrconf_add_ifaddr(void *arg);
+extern int addrconf_del_ifaddr(void *arg);
+extern int addrconf_set_dstaddr(void *arg);
+
+extern struct inet6_ifaddr * ipv6_chk_addr(struct in6_addr *addr,
+ struct device *dev, int nd);
+extern int ipv6_get_saddr(struct dst_entry *dst,
+ struct in6_addr *daddr,
+ struct in6_addr *saddr);
+extern struct inet6_ifaddr * ipv6_get_lladdr(struct device *dev);
+
+/*
+ * multicast prototypes (mcast.c)
+ */
+extern int ipv6_sock_mc_join(struct sock *sk,
+ int ifindex,
+ struct in6_addr *addr);
+extern int ipv6_sock_mc_drop(struct sock *sk,
+ int ifindex,
+ struct in6_addr *addr);
+extern void ipv6_sock_mc_close(struct sock *sk);
+
+extern int ipv6_dev_mc_inc(struct device *dev,
+ struct in6_addr *addr);
+extern int ipv6_dev_mc_dec(struct device *dev,
+ struct in6_addr *addr);
+extern void ipv6_mc_up(struct inet6_dev *idev);
+extern void ipv6_mc_down(struct inet6_dev *idev);
+extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
+extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
+
+extern int ipv6_chk_mcast_addr(struct device *dev,
+ struct in6_addr *addr);
+
+extern void addrconf_prefix_rcv(struct device *dev,
+ u8 *opt, int len);
+
+extern struct inet6_dev * ipv6_get_idev(struct device *dev);
+
+extern void addrconf_forwarding_on(void);
+/*
+ * Hash function taken from net_alias.c
+ */
+
+static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr)
+{
+ __u32 word;
+ unsigned tmp;
+
+ /*
+ * We perform the hash function over the last 64 bits of the address
+ * This will include the IEEE address token on links that support it.
+ */
+
+ word = addr->s6_addr[2] ^ addr->s6_addr32[3];
+ tmp = word ^ (word>>16);
+ tmp ^= (tmp >> 8);
+
+ return ((tmp ^ (tmp >> 4)) & 0x0f);
+}
+
+static __inline__ int ipv6_devindex_hash(int ifindex)
+{
+ return ifindex & (IN6_ADDR_HSIZE - 1);
+}
+
+/*
+ * compute link-local solicited-node multicast address
+ */
+
+extern __inline__ void addrconf_addr_solict_mult_old(struct in6_addr *addr,
+ struct in6_addr *solicited)
+{
+ ipv6_addr_set(solicited,
+ __constant_htonl(0xFF020000), 0,
+ __constant_htonl(0x1), addr->s6_addr32[3]);
+}
+
+extern __inline__ void addrconf_addr_solict_mult_new(struct in6_addr *addr,
+ struct in6_addr *solicited)
+{
+ ipv6_addr_set(solicited,
+ __constant_htonl(0xFF020000), 0,
+ __constant_htonl(0x1),
+ __constant_htonl(0xFF000000) | addr->s6_addr32[3]);
+}
+
+
+extern __inline__ void ipv6_addr_all_nodes(struct in6_addr *addr)
+{
+ ipv6_addr_set(addr,
+ __constant_htonl(0xFF020000), 0, 0,
+ __constant_htonl(0x1));
+}
+
+extern __inline__ void ipv6_addr_all_routers(struct in6_addr *addr)
+{
+ ipv6_addr_set(addr,
+ __constant_htonl(0xFF020000), 0, 0,
+ __constant_htonl(0x2));
+}
+
+extern __inline__ int ipv6_addr_is_multicast(struct in6_addr *addr)
+{
+ return (addr->s6_addr32[0] & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000);
+}
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/net/af_unix.h b/pfinet/linux-src/include/net/af_unix.h
new file mode 100644
index 00000000..06970ac6
--- /dev/null
+++ b/pfinet/linux-src/include/net/af_unix.h
@@ -0,0 +1,35 @@
+#ifndef __LINUX_NET_AFUNIX_H
+#define __LINUX_NET_AFUNIX_H
+extern void unix_proto_init(struct net_proto *pro);
+extern struct proto_ops unix_proto_ops;
+extern void unix_inflight(struct file *fp);
+extern void unix_notinflight(struct file *fp);
+typedef struct sock unix_socket;
+extern void unix_gc(void);
+
+#define UNIX_HASH_SIZE 16
+
+extern unix_socket *unix_socket_table[UNIX_HASH_SIZE+1];
+
+#define forall_unix_sockets(i, s) for (i=0; i<=UNIX_HASH_SIZE; i++) \
+ for (s=unix_socket_table[i]; s; s=s->next)
+
+struct unix_address
+{
+ atomic_t refcnt;
+ int len;
+ unsigned hash;
+ struct sockaddr_un name[0];
+};
+
+struct unix_skb_parms
+{
+ struct ucred creds; /* Skb credentials */
+ struct scm_fp_list *fp; /* Passed files */
+ unsigned attr; /* Special attributes */
+};
+
+#define UNIXCB(skb) (*(struct unix_skb_parms*)&((skb)->cb))
+#define UNIXCREDS(skb) (&UNIXCB((skb)).creds)
+
+#endif
diff --git a/pfinet/linux-src/include/net/arp.h b/pfinet/linux-src/include/net/arp.h
new file mode 100644
index 00000000..b672bacb
--- /dev/null
+++ b/pfinet/linux-src/include/net/arp.h
@@ -0,0 +1,24 @@
+/* linux/net/inet/arp.h */
+#ifndef _ARP_H
+#define _ARP_H
+
+#include <linux/if_arp.h>
+#include <net/neighbour.h>
+
+extern struct neigh_table arp_tbl;
+
+extern void arp_init(void);
+extern int arp_rcv(struct sk_buff *skb, struct device *dev,
+ struct packet_type *pt);
+extern int arp_find(unsigned char *haddr, struct sk_buff *skb);
+extern int arp_ioctl(unsigned int cmd, void *arg);
+extern void arp_send(int type, int ptype, u32 dest_ip,
+ struct device *dev, u32 src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th);
+extern int arp_bind_neighbour(struct dst_entry *dst);
+extern int arp_mc_map(u32 addr, u8 *haddr, struct device *dev, int dir);
+extern void arp_ifdown(struct device *dev);
+
+extern struct neigh_ops arp_broken_ops;
+
+#endif /* _ARP_H */
diff --git a/pfinet/linux-src/include/net/atalkcall.h b/pfinet/linux-src/include/net/atalkcall.h
new file mode 100644
index 00000000..726e33cd
--- /dev/null
+++ b/pfinet/linux-src/include/net/atalkcall.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void atalk_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/include/net/ax25.h b/pfinet/linux-src/include/net/ax25.h
new file mode 100644
index 00000000..2c8d20a6
--- /dev/null
+++ b/pfinet/linux-src/include/net/ax25.h
@@ -0,0 +1,349 @@
+/*
+ * Declarations of AX.25 type objects.
+ *
+ * Alan Cox (GW4PTS) 10/11/93
+ */
+
+#ifndef _AX25_H
+#define _AX25_H
+#include <linux/config.h>
+#include <linux/ax25.h>
+
+#define AX25_T1CLAMPLO 1
+#define AX25_T1CLAMPHI (30 * HZ)
+
+#define AX25_BPQ_HEADER_LEN 16
+#define AX25_KISS_HEADER_LEN 1
+
+#define AX25_HEADER_LEN 17
+#define AX25_ADDR_LEN 7
+#define AX25_DIGI_HEADER_LEN (AX25_MAX_DIGIS * AX25_ADDR_LEN)
+#define AX25_MAX_HEADER_LEN (AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN)
+
+/* AX.25 Protocol IDs */
+#define AX25_P_ROSE 0x01
+#define AX25_P_IP 0xCC
+#define AX25_P_ARP 0xCD
+#define AX25_P_TEXT 0xF0
+#define AX25_P_NETROM 0xCF
+#define AX25_P_SEGMENT 0x08
+
+/* AX.25 Segment control values */
+#define AX25_SEG_REM 0x7F
+#define AX25_SEG_FIRST 0x80
+
+#define AX25_CBIT 0x80 /* Command/Response bit */
+#define AX25_EBIT 0x01 /* HDLC Address Extension bit */
+#define AX25_HBIT 0x80 /* Has been repeated bit */
+
+#define AX25_SSSID_SPARE 0x60 /* Unused bits in SSID for standard AX.25 */
+#define AX25_ESSID_SPARE 0x20 /* Unused bits in SSID for extended AX.25 */
+#define AX25_DAMA_FLAG 0x20 /* Well, it is *NOT* unused! (dl1bke 951121 */
+
+#define AX25_COND_ACK_PENDING 0x01
+#define AX25_COND_REJECT 0x02
+#define AX25_COND_PEER_RX_BUSY 0x04
+#define AX25_COND_OWN_RX_BUSY 0x08
+#define AX25_COND_DAMA_MODE 0x10
+
+#ifndef _LINUX_NETDEVICE_H
+#include <linux/netdevice.h>
+#endif
+
+/* Upper sub-layer (LAPB) definitions */
+
+/* Control field templates */
+#define AX25_I 0x00 /* Information frames */
+#define AX25_S 0x01 /* Supervisory frames */
+#define AX25_RR 0x01 /* Receiver ready */
+#define AX25_RNR 0x05 /* Receiver not ready */
+#define AX25_REJ 0x09 /* Reject */
+#define AX25_U 0x03 /* Unnumbered frames */
+#define AX25_SABM 0x2f /* Set Asynchronous Balanced Mode */
+#define AX25_SABME 0x6f /* Set Asynchronous Balanced Mode Extended */
+#define AX25_DISC 0x43 /* Disconnect */
+#define AX25_DM 0x0f /* Disconnected mode */
+#define AX25_UA 0x63 /* Unnumbered acknowledge */
+#define AX25_FRMR 0x87 /* Frame reject */
+#define AX25_UI 0x03 /* Unnumbered information */
+
+#define AX25_PF 0x10 /* Poll/final bit for standard AX.25 */
+#define AX25_EPF 0x01 /* Poll/final bit for extended AX.25 */
+
+#define AX25_ILLEGAL 0x100 /* Impossible to be a real frame type */
+
+#define AX25_POLLOFF 0
+#define AX25_POLLON 1
+
+/* AX25 L2 C-bit */
+#define AX25_COMMAND 1
+#define AX25_RESPONSE 2
+
+/* Define Link State constants. */
+
+enum {
+ AX25_STATE_0,
+ AX25_STATE_1,
+ AX25_STATE_2,
+ AX25_STATE_3,
+ AX25_STATE_4
+};
+
+#define AX25_MODULUS 8 /* Standard AX.25 modulus */
+#define AX25_EMODULUS 128 /* Extended AX.25 modulus */
+
+enum {
+ AX25_PROTO_STD_SIMPLEX,
+ AX25_PROTO_STD_DUPLEX,
+ AX25_PROTO_DAMA_SLAVE,
+ AX25_PROTO_DAMA_MASTER
+};
+
+enum {
+ AX25_VALUES_IPDEFMODE, /* 0=DG 1=VC */
+ AX25_VALUES_AXDEFMODE, /* 0=Normal 1=Extended Seq Nos */
+ AX25_VALUES_BACKOFF, /* 0=None 1=Linear 2=Exponential */
+ AX25_VALUES_CONMODE, /* Allow connected modes - 0=No 1=no "PID text" 2=all PIDs */
+ AX25_VALUES_WINDOW, /* Default window size for standard AX.25 */
+ AX25_VALUES_EWINDOW, /* Default window size for extended AX.25 */
+ AX25_VALUES_T1, /* Default T1 timeout value */
+ AX25_VALUES_T2, /* Default T2 timeout value */
+ AX25_VALUES_T3, /* Default T3 timeout value */
+ AX25_VALUES_IDLE, /* Connected mode idle timer */
+ AX25_VALUES_N2, /* Default N2 value */
+ AX25_VALUES_PACLEN, /* AX.25 MTU */
+ AX25_VALUES_PROTOCOL, /* Std AX.25, DAMA Slave, DAMA Master */
+ AX25_VALUES_DS_TIMEOUT, /* DAMA Slave timeout */
+ AX25_MAX_VALUES /* THIS MUST REMAIN THE LAST ENTRY OF THIS LIST */
+};
+
+#define AX25_DEF_IPDEFMODE 0 /* Datagram */
+#define AX25_DEF_AXDEFMODE 0 /* Normal */
+#define AX25_DEF_BACKOFF 1 /* Linear backoff */
+#define AX25_DEF_CONMODE 2 /* Connected mode allowed */
+#define AX25_DEF_WINDOW 2 /* Window=2 */
+#define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */
+#define AX25_DEF_T1 (10 * HZ) /* T1=10s */
+#define AX25_DEF_T2 (3 * HZ) /* T2=3s */
+#define AX25_DEF_T3 (300 * HZ) /* T3=300s */
+#define AX25_DEF_N2 10 /* N2=10 */
+#define AX25_DEF_IDLE (0 * 60 * HZ) /* Idle=None */
+#define AX25_DEF_PACLEN 256 /* Paclen=256 */
+#define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */
+#define AX25_DEF_DS_TIMEOUT (3 * 60 * HZ) /* DAMA timeout 3 minutes */
+
+typedef struct ax25_uid_assoc {
+ struct ax25_uid_assoc *next;
+ uid_t uid;
+ ax25_address call;
+} ax25_uid_assoc;
+
+typedef struct {
+ ax25_address calls[AX25_MAX_DIGIS];
+ unsigned char repeated[AX25_MAX_DIGIS];
+ unsigned char ndigi;
+ char lastrepeat;
+} ax25_digi;
+
+typedef struct ax25_route {
+ struct ax25_route *next;
+ ax25_address callsign;
+ struct device *dev;
+ ax25_digi *digipeat;
+ char ip_mode;
+} ax25_route;
+
+typedef struct {
+ char slave; /* slave_mode? */
+ struct timer_list slave_timer; /* timeout timer */
+ unsigned short slave_timeout; /* when? */
+} ax25_dama_info;
+
+#ifndef _LINUX_SYSCTL_H
+#include <linux/sysctl.h>
+#endif
+
+typedef struct ax25_dev {
+ struct ax25_dev *next;
+ struct device *dev;
+ struct device *forward;
+ struct ctl_table systable[AX25_MAX_VALUES+1];
+ int values[AX25_MAX_VALUES];
+#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
+ ax25_dama_info dama;
+#endif
+} ax25_dev;
+
+typedef struct ax25_cb {
+ struct ax25_cb *next;
+ ax25_address source_addr, dest_addr;
+ ax25_digi *digipeat;
+ ax25_dev *ax25_dev;
+ unsigned char iamdigi;
+ unsigned char state, modulus, pidincl;
+ unsigned short vs, vr, va;
+ unsigned char condition, backoff;
+ unsigned char n2, n2count;
+ struct timer_list t1timer, t2timer, t3timer, idletimer;
+ unsigned long t1, t2, t3, idle, rtt;
+ unsigned short paclen, fragno, fraglen;
+ struct sk_buff_head write_queue;
+ struct sk_buff_head reseq_queue;
+ struct sk_buff_head ack_queue;
+ struct sk_buff_head frag_queue;
+ unsigned char window;
+ struct timer_list timer;
+ struct sock *sk; /* Backlink to socket */
+} ax25_cb;
+
+/* af_ax25.c */
+extern ax25_cb *volatile ax25_list;
+extern void ax25_free_cb(ax25_cb *);
+extern void ax25_insert_socket(ax25_cb *);
+struct sock *ax25_find_listener(ax25_address *, int, struct device *, int);
+struct sock *ax25_find_socket(ax25_address *, ax25_address *, int);
+extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct device *);
+extern struct sock *ax25_addr_match(ax25_address *);
+extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int);
+extern void ax25_destroy_socket(ax25_cb *);
+extern ax25_cb *ax25_create_cb(void);
+extern void ax25_fillin_cb(ax25_cb *, ax25_dev *);
+extern int ax25_create(struct socket *, int);
+extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
+
+/* ax25_addr.c */
+extern ax25_address null_ax25_address;
+extern char *ax2asc(ax25_address *);
+extern ax25_address *asc2ax(char *);
+extern int ax25cmp(ax25_address *, ax25_address *);
+extern int ax25digicmp(ax25_digi *, ax25_digi *);
+extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *);
+extern int ax25_addr_build(unsigned char *, ax25_address *, ax25_address *, ax25_digi *, int, int);
+extern int ax25_addr_size(ax25_digi *);
+extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
+
+/* ax25_dev.c */
+extern ax25_dev *ax25_dev_list;
+extern ax25_dev *ax25_dev_ax25dev(struct device *);
+extern ax25_dev *ax25_addr_ax25dev(ax25_address *);
+extern void ax25_dev_device_up(struct device *);
+extern void ax25_dev_device_down(struct device *);
+extern int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *);
+extern struct device *ax25_fwd_dev(struct device *);
+extern void ax25_dev_free(void);
+
+/* ax25_ds_in.c */
+extern int ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int);
+
+/* ax25_ds_subr.c */
+extern void ax25_ds_nr_error_recovery(ax25_cb *);
+extern void ax25_ds_enquiry_response(ax25_cb *);
+extern void ax25_ds_establish_data_link(ax25_cb *);
+extern void ax25_dev_dama_on(ax25_dev *);
+extern void ax25_dev_dama_off(ax25_dev *);
+extern void ax25_dama_on(ax25_cb *);
+extern void ax25_dama_off(ax25_cb *);
+
+/* ax25_ds_timer.c */
+extern void ax25_ds_set_timer(ax25_dev *);
+extern void ax25_ds_del_timer(ax25_dev *);
+extern void ax25_ds_timer(ax25_cb *);
+extern void ax25_ds_t1_timeout(ax25_cb *);
+extern void ax25_ds_heartbeat_expiry(ax25_cb *);
+extern void ax25_ds_t3timer_expiry(ax25_cb *);
+extern void ax25_ds_idletimer_expiry(ax25_cb *);
+
+#include <net/ax25call.h>
+
+/* ax25_iface.c */
+extern int ax25_protocol_register(unsigned int, int (*)(struct sk_buff *, ax25_cb *));
+extern void ax25_protocol_release(unsigned int);
+extern int ax25_linkfail_register(void (*)(ax25_cb *, int));
+extern void ax25_linkfail_release(void (*)(ax25_cb *, int));
+extern int ax25_listen_register(ax25_address *, struct device *);
+extern void ax25_listen_release(ax25_address *, struct device *);
+extern int (*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *);
+extern int ax25_listen_mine(ax25_address *, struct device *);
+extern void ax25_link_failed(ax25_cb *, int);
+extern int ax25_protocol_is_registered(unsigned int);
+
+/* ax25_in.c */
+extern int ax25_rx_iframe(ax25_cb *, struct sk_buff *);
+extern int ax25_kiss_rcv(struct sk_buff *, struct device *, struct packet_type *);
+
+/* ax25_ip.c */
+extern int ax25_encapsulate(struct sk_buff *, struct device *, unsigned short, void *, void *, unsigned int);
+extern int ax25_rebuild_header(struct sk_buff *);
+
+/* ax25_out.c */
+extern ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, ax25_digi *, struct device *);
+extern void ax25_output(ax25_cb *, int, struct sk_buff *);
+extern void ax25_kick(ax25_cb *);
+extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
+extern void ax25_queue_xmit(struct sk_buff *);
+extern int ax25_check_iframes_acked(ax25_cb *, unsigned short);
+
+/* ax25_route.c */
+extern void ax25_rt_device_down(struct device *);
+extern int ax25_rt_ioctl(unsigned int, void *);
+extern int ax25_rt_get_info(char *, char **, off_t, int, int);
+extern int ax25_rt_autobind(ax25_cb *, ax25_address *);
+extern ax25_route *ax25_rt_find_route(ax25_address *, struct device *);
+extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
+extern void ax25_rt_free(void);
+
+/* ax25_std_in.c */
+extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
+
+/* ax25_std_subr.c */
+extern void ax25_std_nr_error_recovery(ax25_cb *);
+extern void ax25_std_establish_data_link(ax25_cb *);
+extern void ax25_std_transmit_enquiry(ax25_cb *);
+extern void ax25_std_enquiry_response(ax25_cb *);
+extern void ax25_std_timeout_response(ax25_cb *);
+
+/* ax25_std_timer.c */
+extern void ax25_std_heartbeat_expiry(ax25_cb *);
+extern void ax25_std_t1timer_expiry(ax25_cb *);
+extern void ax25_std_t2timer_expiry(ax25_cb *);
+extern void ax25_std_t3timer_expiry(ax25_cb *);
+extern void ax25_std_idletimer_expiry(ax25_cb *);
+
+/* ax25_subr.c */
+extern void ax25_clear_queues(ax25_cb *);
+extern void ax25_frames_acked(ax25_cb *, unsigned short);
+extern void ax25_requeue_frames(ax25_cb *);
+extern int ax25_validate_nr(ax25_cb *, unsigned short);
+extern int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *);
+extern void ax25_send_control(ax25_cb *, int, int, int);
+extern void ax25_return_dm(struct device *, ax25_address *, ax25_address *, ax25_digi *);
+extern void ax25_calculate_t1(ax25_cb *);
+extern void ax25_calculate_rtt(ax25_cb *);
+extern void ax25_disconnect(ax25_cb *, int);
+
+/* ax25_timer.c */
+extern void ax25_start_heartbeat(ax25_cb *);
+extern void ax25_start_t1timer(ax25_cb *);
+extern void ax25_start_t2timer(ax25_cb *);
+extern void ax25_start_t3timer(ax25_cb *);
+extern void ax25_start_idletimer(ax25_cb *);
+extern void ax25_stop_heartbeat(ax25_cb *);
+extern void ax25_stop_t1timer(ax25_cb *);
+extern void ax25_stop_t2timer(ax25_cb *);
+extern void ax25_stop_t3timer(ax25_cb *);
+extern void ax25_stop_idletimer(ax25_cb *);
+extern int ax25_t1timer_running(ax25_cb *);
+extern unsigned long ax25_display_timer(struct timer_list *);
+
+/* ax25_uid.c */
+extern int ax25_uid_policy;
+extern ax25_address *ax25_findbyuid(uid_t);
+extern int ax25_uid_ioctl(int, struct sockaddr_ax25 *);
+extern int ax25_uid_get_info(char *, char **, off_t, int, int);
+extern void ax25_uid_free(void);
+
+/* sysctl_net_ax25.c */
+extern void ax25_register_sysctl(void);
+extern void ax25_unregister_sysctl(void);
+
+#endif
diff --git a/pfinet/linux-src/include/net/ax25call.h b/pfinet/linux-src/include/net/ax25call.h
new file mode 100644
index 00000000..68b8a70c
--- /dev/null
+++ b/pfinet/linux-src/include/net/ax25call.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void ax25_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/include/net/br.h b/pfinet/linux-src/include/net/br.h
new file mode 100644
index 00000000..cbf4b4c3
--- /dev/null
+++ b/pfinet/linux-src/include/net/br.h
@@ -0,0 +1,331 @@
+/*
+ * Constants and structure definitions for the bridging code
+ */
+
+#if !defined(One)
+#define Zero 0
+#define One 1
+#endif /* !defined(One) */
+
+#if !defined(TRUE)
+#define FALSE 0
+#define TRUE 1
+#endif /* !defined(TRUE) */
+
+/** port states. **/
+#define Disabled 0 /* (4.4 5) */
+#define Listening 1 /* (4.4.2) */
+#define Learning 2 /* (4.4.3) */
+#define Forwarding 3 /* (4 4 4) */
+#define Blocking 4 /* (4.4.1) */
+
+
+/* MAG Yich! Easiest way of giving a configurable number of ports
+ * If you want more than 32, change BR_MAX_PORTS and recompile brcfg!
+ */
+#define BR_MAX_PORTS (32)
+#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS
+#undef CONFIG_BRIDGE_NUM_PORTS
+#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS
+#endif
+#define No_of_ports CONFIG_BRIDGE_NUM_PORTS
+/* arbitrary choice, to allow the code below to compile */
+
+#define All_ports (No_of_ports + 1)
+
+/*
+ * We time out our entries in the FDB after this many seconds.
+ */
+#define FDB_TIMEOUT 20 /* JRP: 20s as NSC bridge code, was 300 for Linux */
+
+/*
+ * the following defines are the initial values used when the
+ * bridge is booted. These may be overridden when this bridge is
+ * not the root bridge. These are the recommended default values
+ * from the 802.1d specification.
+ */
+#define BRIDGE_MAX_AGE 20
+#define BRIDGE_HELLO_TIME 2
+#define BRIDGE_FORWARD_DELAY 15
+#define HOLD_TIME 1
+
+/* broacast/multicast storm limitation. This per source. */
+#define MAX_MCAST_PER_PERIOD 4
+#define MCAST_HOLD_TIME (10*HZ/100)
+
+#define Default_path_cost 10
+
+/*
+ * minimum increment possible to avoid underestimating age, allows for BPDU
+ * transmission time
+ */
+#define Message_age_increment 1
+
+#define No_port 0
+/*
+ * reserved value for Bridge's root port parameter indicating no root port,
+ * used when Bridge is the root - also used to indicate the source when
+ * a frame is being generated by a higher layer protocol on this host
+ */
+
+/** Configuration BPDU Parameters (4.5.1) **/
+
+typedef struct {
+ union {
+ struct {
+ unsigned short priority;
+ unsigned char ula[6];
+ } p_u;
+ unsigned int id[2];
+ } bi;
+} bridge_id_t;
+
+#define BRIDGE_PRIORITY bi.p_u.priority
+#define BRIDGE_ID_ULA bi.p_u.ula
+#define BRIDGE_ID bi.id
+
+/* JRP: on the network the flags field is between "type" and "root_id"
+ * this is unfortunated! To make the code portable to a RISC machine
+ * the pdus are now massaged a little bit for processing
+ */
+#define TOPOLOGY_CHANGE 0x01
+#define TOPOLOGY_CHANGE_ACK 0x80
+#define BRIDGE_BPDU_8021_CONFIG_SIZE 35 /* real size */
+#define BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET 4
+#define BRIDGE_BPDU_8021_PROTOCOL_ID 0
+#define BRIDGE_BPDU_8021_PROTOCOL_VERSION_ID 0
+#define BRIDGE_LLC1_HS 3
+#define BRIDGE_LLC1_DSAP 0x42
+#define BRIDGE_LLC1_SSAP 0x42
+#define BRIDGE_LLC1_CTRL 0x03
+
+typedef struct {
+ unsigned short protocol_id;
+ unsigned char protocol_version_id;
+ unsigned char type;
+ bridge_id_t root_id; /* (4.5.1.1) */
+ unsigned int root_path_cost; /* (4.5.1.2) */
+ bridge_id_t bridge_id; /* (4.5.1.3) */
+ unsigned short port_id; /* (4.5.1.4) */
+ unsigned short message_age; /* (4.5.1.5) */
+ unsigned short max_age; /* (4.5.1.6) */
+ unsigned short hello_time; /* (4.5.1.7) */
+ unsigned short forward_delay; /* (4.5.1.8) */
+ unsigned char top_change_ack;
+ unsigned char top_change;
+} Config_bpdu;
+
+#ifdef __LITTLE_ENDIAN
+#define config_bpdu_hton(config_bpdu) \
+ (config_bpdu)->root_path_cost = htonl((config_bpdu)->root_path_cost); \
+ (config_bpdu)->port_id = htons((config_bpdu)->port_id); \
+ (config_bpdu)->message_age = htons((config_bpdu)->message_age); \
+ (config_bpdu)->max_age = htons((config_bpdu)->max_age); \
+ (config_bpdu)->hello_time = htons((config_bpdu)->hello_time); \
+ (config_bpdu)->forward_delay = htons((config_bpdu)->forward_delay);
+#else
+#define config_bpdu_hton(config_bpdu)
+#endif
+#define config_bpdu_ntoh config_bpdu_hton
+
+
+/** Topology Change Notification BPDU Parameters (4.5.2) **/
+
+typedef struct {
+ unsigned short protocol_id;
+ unsigned char protocol_version_id;
+ unsigned char type;
+} Tcn_bpdu;
+
+#define BPDU_TYPE_CONFIG 0
+#define BPDU_TYPE_TOPO_CHANGE 128
+
+/** Bridge Parameters (4.5.3) **/
+typedef struct {
+ bridge_id_t designated_root; /* (4.5.3.1) */
+ unsigned int root_path_cost; /* (4.5.3.2) */
+ unsigned int root_port; /* (4.5.3.3) */
+ unsigned short max_age; /* (4.5.3.4) */
+ unsigned short hello_time; /* (4.5.3.5) */
+ unsigned short forward_delay; /* (4.5.3.6) */
+ bridge_id_t bridge_id; /* (4.5.3.7) */
+ unsigned short bridge_max_age; /* (4.5.3.8) */
+ unsigned short bridge_hello_time; /* (4.5.3.9) */
+ unsigned short bridge_forward_delay; /* (4.5.3.10) */
+ unsigned int top_change_detected; /* (4.5.3.11) */
+ unsigned int top_change; /* (4.5.3.12) */
+ unsigned short topology_change_time; /* (4.5.3.13) */
+ unsigned short hold_time; /* (4.5.3.14) */
+ unsigned int instance;
+} Bridge_data;
+
+/** Port Parameters (4.5.5) **/
+typedef struct {
+ unsigned short port_id; /* (4.5.5.1) */
+ unsigned int state; /* (4.5.5.2) */
+ unsigned int path_cost; /* (4.5.5.3) */
+ bridge_id_t designated_root; /* (4.5.5.4) */
+ unsigned int designated_cost; /* (4.5.5.5) */
+ bridge_id_t designated_bridge; /* (4.5.5.6) */
+ unsigned short designated_port; /* (4.5.5.7) */
+ unsigned int top_change_ack; /* (4.5.5.8) */
+ unsigned int config_pending; /* (4.5.5.9) */
+ bridge_id_t ifmac;
+ unsigned int admin_state;
+ char ifname[IFNAMSIZ]; /* Make life easier for brcfg */
+ struct device *dev;
+ struct fdb *fdb; /* head of per port fdb chain */
+} Port_data;
+
+
+
+/** types to support timers for this pseudo-implementation. **/
+typedef struct {
+ unsigned int active; /* timer in use. */
+ unsigned int value; /* current value of timer,
+ * counting up. */
+} Timer;
+
+struct fdb {
+ unsigned char ula[6];
+ unsigned char pad[2];
+ unsigned short port;
+ unsigned int timer;
+ unsigned short flags;
+#define FDB_ENT_VALID 0x01
+ unsigned short mcast_count;
+ unsigned int mcast_timer; /* oldest xxxxxcast */
+
+/* AVL tree of all addresses, sorted by address */
+ short fdb_avl_height;
+ struct fdb *fdb_avl_left;
+ struct fdb *fdb_avl_right;
+/* linked list of addresses for each port */
+ struct fdb *fdb_next;
+};
+
+/* data returned on BRCMD_DISPLAY_FDB */
+struct fdb_info {
+ unsigned char ula[6];
+ unsigned char port;
+ unsigned char flags;
+ unsigned int timer;
+};
+struct fdb_info_hdr {
+ int copied; /* nb of entries copied to user */
+ int not_copied; /* when user buffer is too small */
+ int cmd_time;
+};
+
+#define IS_BRIDGED 0x2e
+
+
+#define BR_MAX_PROTOCOLS 32
+#define BR_MAX_PROT_STATS BR_MAX_PROTOCOLS
+
+/* policy values for policy field */
+#define BR_ACCEPT 1
+#define BR_REJECT 0
+
+/* JRP: extra statistics for debug */
+typedef struct {
+ /* br_receive_frame counters */
+ int port_disable_up_stack;
+ int rcv_bpdu;
+ int notForwarding;
+ int forwarding_up_stack;
+ int unknown_state;
+
+ /* br_tx_frame counters */
+ int port_disable;
+ int port_not_disable;
+
+ /* br_forward counters */
+ int local_multicast;
+ int forwarded_multicast; /* up stack as well */
+ int flood_unicast;
+ int aged_flood_unicast;
+ int forwarded_unicast;
+ int forwarded_unicast_up_stack;
+ int forwarded_ip_up_stack;
+ int forwarded_ip_up_stack_lie; /* received on alternate device */
+ int arp_for_local_mac;
+ int drop_same_port;
+ int drop_same_port_aged;
+ int drop_multicast;
+} br_stats_counter;
+
+struct br_stat {
+ unsigned int flags;
+ Bridge_data bridge_data;
+ unsigned int policy;
+ unsigned int exempt_protocols;
+ unsigned short protocols[BR_MAX_PROTOCOLS];
+ unsigned short prot_id[BR_MAX_PROT_STATS]; /* Protocol encountered */
+ unsigned int prot_counter[BR_MAX_PROT_STATS]; /* How many packets ? */
+ br_stats_counter packet_cnts;
+ unsigned int num_ports;
+ Port_data port_data[BR_MAX_PORTS + 1];
+};
+
+/* defined flags for br_stat.flags */
+#define BR_UP 0x0001 /* bridging enabled */
+#define BR_DEBUG 0x0002 /* debugging enabled */
+#define BR_PROT_STATS 0x0004 /* protocol statistics enabled */
+#define BR_STP_DISABLED 0x0008 /* Spanning tree protocol disabled */
+
+struct br_cf {
+ unsigned int cmd;
+ unsigned int arg1;
+ unsigned int arg2;
+};
+
+/* defined cmds */
+#define BRCMD_BRIDGE_ENABLE 1
+#define BRCMD_BRIDGE_DISABLE 2
+#define BRCMD_PORT_ENABLE 3 /* arg1 = port */
+#define BRCMD_PORT_DISABLE 4 /* arg1 = port */
+#define BRCMD_SET_BRIDGE_PRIORITY 5 /* arg1 = priority */
+#define BRCMD_SET_PORT_PRIORITY 6 /* arg1 = port, arg2 = priority */
+#define BRCMD_SET_PATH_COST 7 /* arg1 = port, arg2 = cost */
+#define BRCMD_DISPLAY_FDB 8
+#define BRCMD_ENABLE_DEBUG 9
+#define BRCMD_DISABLE_DEBUG 10
+#define BRCMD_SET_POLICY 11 /* arg1 = default policy (1==bridge all) */
+#define BRCMD_EXEMPT_PROTOCOL 12 /* arg1 = protocol (see net/if_ether.h) */
+#define BRCMD_ENABLE_PROT_STATS 13
+#define BRCMD_DISABLE_PROT_STATS 14
+#define BRCMD_ZERO_PROT_STATS 15
+#define BRCMD_TOGGLE_STP 16
+#define BRCMD_IF_ENABLE 17 /* arg1 = if_index */
+#define BRCMD_IF_DISABLE 18 /* arg1 = if_index */
+#define BRCMD_SET_IF_PRIORITY 19 /* arg1 = if_index, arg2 = priority */
+#define BRCMD_SET_IF_PATH_COST 20 /* arg1 = if_index, arg2 = cost */
+
+/* prototypes of exported bridging functions... */
+
+#ifdef __KERNEL__
+void br_init(void);
+int br_receive_frame(struct sk_buff *skb); /* 3.5 */
+int br_tx_frame(struct sk_buff *skb);
+int brg_init(void);
+int br_ioctl(unsigned int cmd, void *arg);
+void requeue_fdb(struct fdb *node, int new_port);
+
+struct fdb *br_avl_find_addr(unsigned char addr[6]);
+struct fdb *br_avl_insert (struct fdb * new_node);
+void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length);
+int br_tree_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
+void br_avl_delete_by_port(int port);
+int br_call_bridge(struct sk_buff *skb, unsigned short type);
+void br_spacedevice_register(void);
+
+/* externs */
+
+extern struct br_stat br_stats;
+extern Port_data port_info[];
+
+#endif
+
+
+
diff --git a/pfinet/linux-src/include/net/checksum.h b/pfinet/linux-src/include/net/checksum.h
new file mode 100644
index 00000000..041d4760
--- /dev/null
+++ b/pfinet/linux-src/include/net/checksum.h
@@ -0,0 +1,110 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Checksumming functions for IP, TCP, UDP and so on
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Borrows very liberally from tcp.c and ip.c, see those
+ * files for more names.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Fixes:
+ *
+ * Ralf Baechle : generic ipv6 checksum
+ * <ralf@waldorf-gmbh.de>
+ */
+
+#ifndef _CHECKSUM_H
+#define _CHECKSUM_H
+
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <net/ip.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+
+#ifndef _HAVE_ARCH_IPV6_CSUM
+
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u16 len,
+ unsigned short proto,
+ unsigned int csum)
+{
+
+ int carry;
+ __u32 ulen;
+ __u32 uproto;
+
+ csum += saddr->s6_addr32[0];
+ carry = (csum < saddr->s6_addr32[0]);
+ csum += carry;
+
+ csum += saddr->s6_addr32[1];
+ carry = (csum < saddr->s6_addr32[1]);
+ csum += carry;
+
+ csum += saddr->s6_addr32[2];
+ carry = (csum < saddr->s6_addr32[2]);
+ csum += carry;
+
+ csum += saddr->s6_addr32[3];
+ carry = (csum < saddr->s6_addr32[3]);
+ csum += carry;
+
+ csum += daddr->s6_addr32[0];
+ carry = (csum < daddr->s6_addr32[0]);
+ csum += carry;
+
+ csum += daddr->s6_addr32[1];
+ carry = (csum < daddr->s6_addr32[1]);
+ csum += carry;
+
+ csum += daddr->s6_addr32[2];
+ carry = (csum < daddr->s6_addr32[2]);
+ csum += carry;
+
+ csum += daddr->s6_addr32[3];
+ carry = (csum < daddr->s6_addr32[3]);
+ csum += carry;
+
+ ulen = htonl((__u32) len);
+ csum += ulen;
+ carry = (csum < ulen);
+ csum += carry;
+
+ uproto = htonl(proto);
+ csum += uproto;
+ carry = (csum < uproto);
+ csum += carry;
+
+ return csum_fold(csum);
+}
+
+#endif
+
+#ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+extern __inline__
+unsigned int csum_and_copy_from_user (const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ if (verify_area(VERIFY_READ, src, len) == 0)
+ return csum_partial_copy_from_user(src, dst, len, sum, err_ptr);
+
+ if (len)
+ *err_ptr = -EFAULT;
+
+ return sum;
+}
+#endif
+
+#endif
diff --git a/pfinet/linux-inet/datalink.h b/pfinet/linux-src/include/net/datalink.h
index 34ae08da..44e56990 100644
--- a/pfinet/linux-inet/datalink.h
+++ b/pfinet/linux-src/include/net/datalink.h
@@ -4,7 +4,7 @@
struct datalink_proto {
unsigned short type_len;
unsigned char type[8];
- char *string_name;
+ const char *string_name;
unsigned short header_length;
int (*rcvfunc)(struct sk_buff *, struct device *,
struct packet_type *);
@@ -14,4 +14,3 @@ struct datalink_proto {
};
#endif
-
diff --git a/pfinet/linux-src/include/net/dst.h b/pfinet/linux-src/include/net/dst.h
new file mode 100644
index 00000000..baf4f414
--- /dev/null
+++ b/pfinet/linux-src/include/net/dst.h
@@ -0,0 +1,178 @@
+/*
+ * net/dst.h Protocol independent destination cache definitions.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#ifndef _NET_DST_H
+#define _NET_DST_H
+
+#include <linux/config.h>
+#include <net/neighbour.h>
+
+/*
+ * 0 - no debugging messages
+ * 1 - rare events and bugs (default)
+ * 2 - trace mode.
+ */
+#define RT_CACHE_DEBUG 0
+
+#define DST_GC_MIN (1*HZ)
+#define DST_GC_INC (5*HZ)
+#define DST_GC_MAX (120*HZ)
+
+struct sk_buff;
+
+struct dst_entry
+{
+ struct dst_entry *next;
+ atomic_t refcnt; /* tree/hash references */
+ atomic_t use; /* client references */
+ struct device *dev;
+ int obsolete;
+ unsigned long lastuse;
+ unsigned long expires;
+ unsigned mxlock;
+ unsigned pmtu;
+ unsigned window;
+ unsigned rtt;
+ unsigned long rate_last; /* rate limiting for ICMP */
+ unsigned long rate_tokens;
+
+ int error;
+
+ struct neighbour *neighbour;
+ struct hh_cache *hh;
+
+ int (*input)(struct sk_buff*);
+ int (*output)(struct sk_buff*);
+
+#ifdef CONFIG_NET_CLS_ROUTE
+ __u32 tclassid;
+#endif
+
+ struct dst_ops *ops;
+
+ char info[0];
+};
+
+
+struct dst_ops
+{
+ unsigned short family;
+ unsigned short protocol;
+ unsigned gc_thresh;
+
+ int (*gc)(void);
+ struct dst_entry * (*check)(struct dst_entry *, __u32 cookie);
+ struct dst_entry * (*reroute)(struct dst_entry *,
+ struct sk_buff *);
+ void (*destroy)(struct dst_entry *);
+ struct dst_entry * (*negative_advice)(struct dst_entry *);
+ void (*link_failure)(struct sk_buff *);
+
+ atomic_t entries;
+};
+
+#ifdef __KERNEL__
+
+extern struct dst_entry * dst_garbage_list;
+extern atomic_t dst_total;
+
+extern __inline__
+struct dst_entry * dst_clone(struct dst_entry * dst)
+{
+ if (dst)
+ atomic_inc(&dst->use);
+ return dst;
+}
+
+extern __inline__
+void dst_release(struct dst_entry * dst)
+{
+ if (dst)
+ atomic_dec(&dst->use);
+}
+
+/* The following primitive should be use if and only if
+ destination entry has just been removed from a location
+ accessed directly by hard irq.
+ */
+extern __inline__
+void dst_release_irqwait(struct dst_entry * dst)
+{
+ if (dst) {
+ synchronize_irq();
+ atomic_dec(&dst->use);
+ }
+}
+
+extern __inline__
+struct dst_entry * dst_check(struct dst_entry ** dst_p, u32 cookie)
+{
+ struct dst_entry * dst = *dst_p;
+ if (dst && dst->obsolete)
+ dst = dst->ops->check(dst, cookie);
+ return (*dst_p = dst);
+}
+
+extern __inline__
+struct dst_entry * dst_reroute(struct dst_entry ** dst_p, struct sk_buff *skb)
+{
+ struct dst_entry * dst = *dst_p;
+ if (dst && dst->obsolete)
+ dst = dst->ops->reroute(dst, skb);
+ return (*dst_p = dst);
+}
+
+
+extern void * dst_alloc(int size, struct dst_ops * ops);
+extern void __dst_free(struct dst_entry * dst);
+extern void dst_destroy(struct dst_entry * dst);
+
+extern __inline__
+void dst_free(struct dst_entry * dst)
+{
+ if (dst->obsolete > 1)
+ return;
+ if (!atomic_read(&dst->use)) {
+ dst_destroy(dst);
+ return;
+ }
+ __dst_free(dst);
+}
+
+extern __inline__ void dst_confirm(struct dst_entry *dst)
+{
+ if (dst)
+ neigh_confirm(dst->neighbour);
+}
+
+extern __inline__ void dst_negative_advice(struct dst_entry **dst_p)
+{
+ struct dst_entry * dst = *dst_p;
+ if (dst && dst->ops->negative_advice)
+ *dst_p = dst->ops->negative_advice(dst);
+}
+
+extern __inline__ void dst_link_failure(struct sk_buff *skb)
+{
+ struct dst_entry * dst = skb->dst;
+ if (dst && dst->ops && dst->ops->link_failure)
+ dst->ops->link_failure(skb);
+}
+
+extern __inline__ void dst_set_expires(struct dst_entry *dst, int timeout)
+{
+ unsigned long expires = jiffies + timeout;
+
+ if (expires == 0)
+ expires = 1;
+
+ if (dst->expires == 0 || (long)(dst->expires - expires) > 0)
+ dst->expires = expires;
+}
+#endif
+
+#endif /* _NET_DST_H */
diff --git a/pfinet/linux-src/include/net/flow.h b/pfinet/linux-src/include/net/flow.h
new file mode 100644
index 00000000..e1ce1b2a
--- /dev/null
+++ b/pfinet/linux-src/include/net/flow.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * Flow based forwarding rules (usage: firewalling, etc)
+ *
+ */
+
+#ifndef _NET_FLOW_H
+#define _NET_FLOW_H
+
+struct flowi {
+ int proto; /* {TCP, UDP, ICMP} */
+
+ union {
+ struct {
+ __u32 daddr;
+ __u32 saddr;
+ } ip4_u;
+
+ struct {
+ struct in6_addr * daddr;
+ struct in6_addr * saddr;
+ __u32 flowlabel;
+ } ip6_u;
+ } nl_u;
+#define fl6_dst nl_u.ip6_u.daddr
+#define fl6_src nl_u.ip6_u.saddr
+#define fl6_flowlabel nl_u.ip6_u.flowlabel
+#define fl4_dst nl_u.ip4_u.daddr
+#define fl4_src nl_u.ip4_u.saddr
+
+ int oif;
+
+ union {
+ struct {
+ __u16 sport;
+ __u16 dport;
+ } ports;
+
+ struct {
+ __u8 type;
+ __u8 code;
+ } icmpt;
+
+ unsigned long data;
+ } uli_u;
+};
+
+#define FLOWR_NODECISION 0 /* rule not appliable to flow */
+#define FLOWR_SELECT 1 /* flow must follow this rule */
+#define FLOWR_CLEAR 2 /* priority level clears flow */
+#define FLOWR_ERROR 3
+
+struct fl_acc_args {
+ int type;
+
+
+#define FL_ARG_FORWARD 1
+#define FL_ARG_ORIGIN 2
+
+ union {
+ struct sk_buff *skb;
+ struct {
+ struct sock *sk;
+ struct flowi *flow;
+ } fl_o;
+ } fl_u;
+};
+
+
+struct pkt_filter {
+ atomic_t refcnt;
+ unsigned int offset;
+ __u32 value;
+ __u32 mask;
+ struct pkt_filter *next;
+};
+
+#define FLR_INPUT 1
+#define FLR_OUTPUT 2
+
+struct flow_filter {
+ int type;
+ union {
+ struct pkt_filter *filter;
+ struct sock *sk;
+ } u;
+};
+
+struct flow_rule {
+ struct flow_rule_ops *ops;
+ unsigned char private[0];
+};
+
+struct flow_rule_ops {
+ int (*accept)(struct rt6_info *rt,
+ struct rt6_info *rule,
+ struct fl_acc_args *args,
+ struct rt6_info **nrt);
+};
+
+#endif
diff --git a/pfinet/linux-inet/icmp.h b/pfinet/linux-src/include/net/icmp.h
index 8f1c3498..6e9c5418 100644
--- a/pfinet/linux-inet/icmp.h
+++ b/pfinet/linux-src/include/net/icmp.h
@@ -19,20 +19,24 @@
#define _ICMP_H
#include <linux/icmp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/protocol.h>
extern struct icmp_err icmp_err_convert[];
extern struct icmp_mib icmp_statistics;
-
extern void icmp_send(struct sk_buff *skb_in, int type, int code,
- unsigned long info, struct device *dev);
-extern int icmp_rcv(struct sk_buff *skb1, struct device *dev,
- struct options *opt, unsigned long daddr,
- unsigned short len, unsigned long saddr,
- int redo, struct inet_protocol *protocol);
+ unsigned long info);
+extern int icmp_rcv(struct sk_buff *skb, unsigned short len);
+extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern void icmp_init(struct net_proto_family *ops);
+
+/* Move into dst.h ? */
+extern int xrlim_allow(struct dst_entry *dst, int timeout);
-extern int icmp_ioctl(struct sock *sk, int cmd,
- unsigned long arg);
+/* CONFIG_IP_TRANSPARENT_PROXY */
+extern int icmp_chkaddr(struct sk_buff *skb);
#endif /* _ICMP_H */
diff --git a/pfinet/linux-src/include/net/if_inet6.h b/pfinet/linux-src/include/net/if_inet6.h
new file mode 100644
index 00000000..4e9ed978
--- /dev/null
+++ b/pfinet/linux-src/include/net/if_inet6.h
@@ -0,0 +1,134 @@
+/*
+ * inet6 interface/address list definitions
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_IF_INET6_H
+#define _NET_IF_INET6_H
+
+/* These flags match corresponding IFA_F_* flags but ADDR_INVALID,
+ which is invisible externally.
+ */
+
+#define ADDR_PERMANENT 0x80
+
+#define DAD_COMPLETE 0x00
+#define DAD_INCOMPLETE 0x40
+#define DAD_STATUS 0x40
+
+#define ADDR_STATUS 0x21
+#define ADDR_DEPRECATED 0x20
+#define ADDR_INVALID 0x01
+
+
+
+#define IF_RA_RCVD 0x20
+#define IF_RS_SENT 0x10
+
+#ifdef __KERNEL__
+
+struct inet6_ifaddr
+{
+ struct in6_addr addr;
+ __u32 prefix_len;
+
+ __u32 valid_lft;
+ __u32 prefered_lft;
+ unsigned long tstamp;
+
+ __u8 probes;
+ __u8 flags;
+
+ __u16 scope;
+
+ struct timer_list timer;
+
+ struct inet6_dev *idev;
+
+ struct inet6_ifaddr *lst_next; /* next addr in addr_lst */
+ struct inet6_ifaddr *if_next; /* next addr in inet6_dev */
+};
+
+
+struct ipv6_mc_socklist
+{
+ struct in6_addr addr;
+ int ifindex;
+ struct ipv6_mc_socklist *next;
+};
+
+#define MAF_TIMER_RUNNING 0x01
+#define MAF_LAST_REPORTER 0x02
+#define MAF_LOADED 0x04
+
+struct ifmcaddr6
+{
+ struct in6_addr mca_addr;
+ struct device *dev;
+ struct ifmcaddr6 *next;
+ struct ifmcaddr6 *if_next;
+ struct timer_list mca_timer;
+ unsigned mca_flags;
+ atomic_t mca_users;
+};
+
+#define IFA_HOST IPV6_ADDR_LOOPBACK
+#define IFA_LINK IPV6_ADDR_LINKLOCAL
+#define IFA_SITE IPV6_ADDR_SITELOCAL
+#define IFA_GLOBAL 0x0000U
+
+struct ipv6_devconf
+{
+ int forwarding;
+ int hop_limit;
+ int mtu6;
+ int accept_ra;
+ int accept_redirects;
+ int autoconf;
+ int dad_transmits;
+ int rtr_solicits;
+ int rtr_solicit_interval;
+ int rtr_solicit_delay;
+
+ void *sysctl;
+};
+
+struct inet6_dev
+{
+ struct device *dev;
+
+ struct inet6_ifaddr *addr_list;
+ struct ifmcaddr6 *mc_list;
+ __u32 if_flags;
+
+ struct neigh_parms *nd_parms;
+ struct inet6_dev *next;
+ struct ipv6_devconf cnf;
+};
+
+extern struct ipv6_devconf ipv6_devconf;
+
+extern __inline__ void ipv6_eth_mc_map(struct in6_addr *addr, char *buf)
+{
+ /*
+ * +-------+-------+-------+-------+-------+-------+
+ * | 33 | 33 | DST13 | DST14 | DST15 | DST16 |
+ * +-------+-------+-------+-------+-------+-------+
+ */
+
+ buf[0]= 0x33;
+ buf[1]= 0x33;
+
+ memcpy(buf + 2, &addr->s6_addr32[3], sizeof(__u32));
+}
+#endif
+#endif
diff --git a/pfinet/linux-src/include/net/inet_common.h b/pfinet/linux-src/include/net/inet_common.h
new file mode 100644
index 00000000..9c7c8b94
--- /dev/null
+++ b/pfinet/linux-src/include/net/inet_common.h
@@ -0,0 +1,45 @@
+#ifndef _INET_COMMON_H
+#define _INET_COMMON_H
+
+extern struct proto_ops inet_stream_ops;
+extern struct proto_ops inet_dgram_ops;
+
+/*
+ * INET4 prototypes used by INET6
+ */
+
+extern void inet_remove_sock(struct sock *sk1);
+extern void inet_put_sock(unsigned short num,
+ struct sock *sk);
+extern int inet_release(struct socket *sock,
+ struct socket *peer);
+extern int inet_stream_connect(struct socket *sock,
+ struct sockaddr * uaddr,
+ int addr_len, int flags);
+extern int inet_dgram_connect(struct socket *sock,
+ struct sockaddr * uaddr,
+ int addr_len, int flags);
+extern int inet_accept(struct socket *sock,
+ struct socket *newsock, int flags);
+extern int inet_recvmsg(struct socket *sock,
+ struct msghdr *ubuf,
+ int size, int flags, struct scm_cookie *scm);
+extern int inet_sendmsg(struct socket *sock,
+ struct msghdr *msg,
+ int size, struct scm_cookie *scm);
+extern int inet_shutdown(struct socket *sock, int how);
+extern unsigned int inet_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait);
+extern int inet_setsockopt(struct socket *sock, int level,
+ int optname, char *optval,
+ int optlen);
+extern int inet_getsockopt(struct socket *sock, int level,
+ int optname, char *optval,
+ int *optlen);
+extern int inet_fcntl(struct socket *sock,
+ unsigned int cmd,
+ unsigned long arg);
+extern int inet_listen(struct socket *sock, int backlog);
+
+#endif
+
+
diff --git a/pfinet/linux-src/include/net/ip.h b/pfinet/linux-src/include/net/ip.h
new file mode 100644
index 00000000..1a6cb610
--- /dev/null
+++ b/pfinet/linux-src/include/net/ip.h
@@ -0,0 +1,267 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the IP module.
+ *
+ * Version: @(#)ip.h 1.0.2 05/07/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ *
+ * Changes:
+ * Mike McLagan : Routing by source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _IP_H
+#define _IP_H
+
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/ip.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/in_route.h>
+#include <net/route.h>
+#include <net/arp.h>
+
+#ifndef _SNMP_H
+#include <net/snmp.h>
+#endif
+
+#include <net/sock.h> /* struct sock */
+
+struct inet_skb_parm
+{
+ struct ip_options opt; /* Compiled IP options */
+ u16 redirport; /* Redirect port */
+ unsigned char flags;
+
+#define IPSKB_MASQUERADED 1
+#define IPSKB_TRANSLATED 2
+#define IPSKB_FORWARDED 4
+};
+
+struct ipcm_cookie
+{
+ u32 addr;
+ int oif;
+ struct ip_options *opt;
+};
+
+#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
+
+struct ip_ra_chain
+{
+ struct ip_ra_chain *next;
+ struct sock *sk;
+ void (*destructor)(struct sock *);
+};
+
+extern struct ip_ra_chain *ip_ra_chain;
+
+/* IP flags. */
+#define IP_CE 0x8000 /* Flag: "Congestion" */
+#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
+#define IP_MF 0x2000 /* Flag: "More Fragments" */
+#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */
+
+#define IP_FRAG_TIME (30 * HZ) /* fragment lifetime */
+
+extern void ip_mc_dropsocket(struct sock *);
+extern void ip_mc_dropdevice(struct device *dev);
+extern int ip_mc_procinfo(char *, char **, off_t, int, int);
+
+/*
+ * Functions provided by ip.c
+ */
+
+extern int ip_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern void ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+ u32 saddr, u32 daddr,
+ struct ip_options *opt);
+extern int ip_rcv(struct sk_buff *skb, struct device *dev,
+ struct packet_type *pt);
+extern int ip_local_deliver(struct sk_buff *skb);
+extern int ip_mr_input(struct sk_buff *skb);
+extern int ip_output(struct sk_buff *skb);
+extern int ip_mc_output(struct sk_buff *skb);
+extern void ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*));
+extern int ip_do_nat(struct sk_buff *skb);
+extern void ip_send_check(struct iphdr *ip);
+extern int ip_id_count;
+extern void ip_queue_xmit(struct sk_buff *skb);
+extern void ip_init(void);
+extern int ip_build_xmit(struct sock *sk,
+ int getfrag (const void *,
+ char *,
+ unsigned int,
+ unsigned int),
+ const void *frag,
+ unsigned length,
+ struct ipcm_cookie *ipc,
+ struct rtable *rt,
+ int flags);
+
+
+struct ip_reply_arg {
+ struct iovec iov[2];
+ int n_iov; /* redundant */
+ u32 csum;
+ int csumoffset; /* u16 offset of csum in iov[0].iov_base */
+ /* -1 if not needed */
+};
+
+void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
+ unsigned int len);
+
+extern int __ip_finish_output(struct sk_buff *skb);
+
+struct ipv4_config
+{
+ int log_martians;
+ int autoconfig;
+ int no_pmtu_disc;
+};
+
+extern struct ipv4_config ipv4_config;
+extern struct ip_mib ip_statistics;
+extern struct linux_mib net_statistics;
+
+extern int sysctl_local_port_range[2];
+
+extern __inline__ int ip_finish_output(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb->dst;
+ struct device *dev = dst->dev;
+ struct hh_cache *hh = dst->hh;
+
+ skb->dev = dev;
+ skb->protocol = __constant_htons(ETH_P_IP);
+
+ if (hh) {
+ read_lock_irq(&hh->hh_lock);
+ memcpy(skb->data - 16, hh->hh_data, 16);
+ read_unlock_irq(&hh->hh_lock);
+ skb_push(skb, dev->hard_header_len);
+ return hh->hh_output(skb);
+ } else if (dst->neighbour)
+ return dst->neighbour->output(skb);
+
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+extern __inline__ void ip_send(struct sk_buff *skb)
+{
+ if (skb->len > skb->dst->pmtu)
+ ip_fragment(skb, __ip_finish_output);
+ else
+ ip_finish_output(skb);
+}
+
+extern __inline__
+int ip_decrease_ttl(struct iphdr *iph)
+{
+ u16 check = iph->check;
+ check = ntohs(check) + 0x0100;
+ if ((check & 0xFF00) == 0)
+ check++; /* carry overflow */
+ iph->check = htons(check);
+ return --iph->ttl;
+}
+
+extern __inline__
+int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
+{
+ return (sk->ip_pmtudisc == IP_PMTUDISC_DO ||
+ (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
+ !(dst->mxlock&(1<<RTAX_MTU))));
+}
+
+/*
+ * Map a multicast IP onto multicast MAC for type ethernet.
+ */
+
+extern __inline__ void ip_eth_mc_map(u32 addr, char *buf)
+{
+ addr=ntohl(addr);
+ buf[0]=0x01;
+ buf[1]=0x00;
+ buf[2]=0x5e;
+ buf[5]=addr&0xFF;
+ addr>>=8;
+ buf[4]=addr&0xFF;
+ addr>>=8;
+ buf[3]=addr&0x7F;
+}
+
+/*
+ * Map a multicast IP onto multicast MAC for type Token Ring.
+ * This conforms to RFC1469 Option 2 Multicasting i.e.
+ * using a functional address to transmit / receive
+ * multicast packets.
+ */
+
+extern __inline__ void ip_tr_mc_map(u32 addr, char *buf)
+{
+ buf[0]=0xC0;
+ buf[1]=0x00;
+ buf[2]=0x00;
+ buf[3]=0x04;
+ buf[4]=0x00;
+ buf[5]=0x00;
+}
+
+extern int ip_call_ra_chain(struct sk_buff *skb);
+
+/*
+ * Functions provided by ip_fragment.o
+ */
+
+struct sk_buff *ip_defrag(struct sk_buff *skb);
+
+/*
+ * Functions provided by ip_forward.c
+ */
+
+extern int ip_forward(struct sk_buff *skb);
+extern int ip_net_unreachable(struct sk_buff *skb);
+
+/*
+ * Functions provided by ip_options.c
+ */
+
+extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, u32 daddr, struct rtable *rt, int is_frag);
+extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb);
+extern void ip_options_fragment(struct sk_buff *skb);
+extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb);
+extern int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, int user);
+extern void ip_options_undo(struct ip_options * opt);
+extern void ip_forward_options(struct sk_buff *skb);
+extern int ip_options_rcv_srr(struct sk_buff *skb);
+
+/*
+ * Functions provided by ip_sockglue.c
+ */
+
+extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
+extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc);
+extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
+extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
+extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *));
+
+extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len);
+extern void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+ u16 port, u32 info, u8 *payload);
+extern void ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
+ u32 info);
+
+#endif /* _IP_H */
diff --git a/pfinet/linux-src/include/net/ip6_fib.h b/pfinet/linux-src/include/net/ip6_fib.h
new file mode 100644
index 00000000..efd652f2
--- /dev/null
+++ b/pfinet/linux-src/include/net/ip6_fib.h
@@ -0,0 +1,177 @@
+/*
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _IP6_FIB_H
+#define _IP6_FIB_H
+
+#ifdef __KERNEL__
+
+#include <linux/ipv6_route.h>
+
+#include <net/dst.h>
+#include <net/flow.h>
+#include <linux/rtnetlink.h>
+
+struct rt6_info;
+
+struct fib6_node
+{
+ struct fib6_node *parent;
+ struct fib6_node *left;
+ struct fib6_node *right;
+
+ struct fib6_node *subtree;
+
+ struct rt6_info *leaf;
+
+ __u16 fn_bit; /* bit key */
+ __u16 fn_flags;
+ __u32 fn_sernum;
+};
+
+
+/*
+ * routing information
+ *
+ */
+
+struct rt6key
+{
+ struct in6_addr addr;
+ int plen;
+};
+
+struct rt6_info
+{
+ union {
+ struct dst_entry dst;
+ struct rt6_info *next;
+ } u;
+
+#define rt6i_dev u.dst.dev
+#define rt6i_nexthop u.dst.neighbour
+#define rt6i_expires u.dst.expires
+
+ struct fib6_node *rt6i_node;
+
+ struct in6_addr rt6i_gateway;
+
+ u32 rt6i_flags;
+ u32 rt6i_metric;
+ u8 rt6i_hoplimit;
+ atomic_t rt6i_ref;
+
+ union {
+ struct flow_rule *rt6iu_flowr;
+ struct flow_filter *rt6iu_filter;
+ } flow_u;
+
+#define rt6i_flowr flow_u.rt6iu_flowr
+#define rt6i_filter flow_u.rt6iu_filter
+
+ struct rt6key rt6i_dst;
+ struct rt6key rt6i_src;
+};
+
+struct fib6_walker_t
+{
+ struct fib6_walker_t *prev, *next;
+ struct fib6_node *root, *node;
+ struct rt6_info *leaf;
+ unsigned char state;
+ unsigned char prune;
+ int (*func)(struct fib6_walker_t *);
+ void *args;
+};
+
+extern struct fib6_walker_t fib6_walker_list;
+
+extern __inline__ void fib6_walker_link(struct fib6_walker_t *w)
+{
+ w->next = fib6_walker_list.next;
+ w->prev = &fib6_walker_list;
+ w->next->prev = w;
+ w->prev->next = w;
+}
+
+extern __inline__ void fib6_walker_unlink(struct fib6_walker_t *w)
+{
+ w->next->prev = w->prev;
+ w->prev->next = w->next;
+ w->prev = w->next = w;
+}
+
+struct rt6_statistics {
+ __u32 fib_nodes;
+ __u32 fib_route_nodes;
+ __u32 fib_rt_alloc; /* permanet routes */
+ __u32 fib_rt_entries; /* rt entries in table */
+ __u32 fib_rt_cache; /* cache routes */
+};
+
+#define RTN_TL_ROOT 0x0001
+#define RTN_ROOT 0x0002 /* tree root node */
+#define RTN_RTINFO 0x0004 /* node with valid routing info */
+
+/*
+ * priority levels (or metrics)
+ *
+ */
+
+#define RTPRI_FIREWALL 8 /* Firewall control information */
+#define RTPRI_FLOW 16 /* Flow based forwarding rules */
+#define RTPRI_KERN_CTL 32 /* Kernel control routes */
+
+#define RTPRI_USER_MIN 256 /* Mimimum user priority */
+#define RTPRI_USER_MAX 1024 /* Maximum user priority */
+
+#define RTPRI_KERN_DFLT 4096 /* Kernel default routes */
+
+#define MAX_FLOW_BACKTRACE 32
+
+
+typedef void (*f_pnode)(struct fib6_node *fn, void *);
+
+extern struct fib6_node ip6_routing_table;
+
+/*
+ * exported functions
+ */
+
+extern struct fib6_node *fib6_lookup(struct fib6_node *root,
+ struct in6_addr *daddr,
+ struct in6_addr *saddr);
+
+struct fib6_node *fib6_locate(struct fib6_node *root,
+ struct in6_addr *daddr, int dst_len,
+ struct in6_addr *saddr, int src_len);
+
+extern void fib6_clean_tree(struct fib6_node *root,
+ int (*func)(struct rt6_info *, void *arg),
+ int prune, void *arg);
+
+extern int fib6_walk(struct fib6_walker_t *w);
+extern int fib6_walk_continue(struct fib6_walker_t *w);
+
+extern int fib6_add(struct fib6_node *root,
+ struct rt6_info *rt);
+
+extern int fib6_del(struct rt6_info *rt);
+
+extern void inet6_rt_notify(int event, struct rt6_info *rt);
+
+extern void fib6_run_gc(unsigned long dummy);
+
+extern void fib6_gc_cleanup(void);
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/net/ip6_fw.h b/pfinet/linux-src/include/net/ip6_fw.h
new file mode 100644
index 00000000..7866273d
--- /dev/null
+++ b/pfinet/linux-src/include/net/ip6_fw.h
@@ -0,0 +1,54 @@
+#ifndef __NET_IP6_FW_H
+#define __NET_IP6_FW_H
+
+#define IP6_FW_LISTHEAD 0x1000
+#define IP6_FW_ACCEPT 0x0001
+#define IP6_FW_REJECT 0x0002
+
+#define IP6_FW_DEBUG 2
+
+#define IP6_FW_MSG_ADD 1
+#define IP6_FW_MSG_DEL 2
+#define IP6_FW_MSG_REPORT 3
+
+
+/*
+ * Fast "hack" user interface
+ */
+struct ip6_fw_msg {
+ struct in6_addr dst;
+ struct in6_addr src;
+ int dst_len;
+ int src_len;
+ int action;
+ int policy;
+ int proto;
+ union {
+ struct {
+ __u16 sport;
+ __u16 dport;
+ } transp;
+
+ unsigned long data;
+
+ int icmp_type;
+ } u;
+
+ int msg_len;
+};
+
+#ifdef __KERNEL__
+
+#include <net/flow.h>
+
+struct ip6_fw_rule {
+ struct flow_rule flowr;
+ struct ip6_fw_rule *next;
+ struct ip6_fw_rule *prev;
+ struct flowi info;
+ unsigned long policy;
+};
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/net/ip6_route.h b/pfinet/linux-src/include/net/ip6_route.h
new file mode 100644
index 00000000..9311cc34
--- /dev/null
+++ b/pfinet/linux-src/include/net/ip6_route.h
@@ -0,0 +1,111 @@
+#ifndef _NET_IP6_ROUTE_H
+#define _NET_IP6_ROUTE_H
+
+#define IP6_RT_PRIO_FW 16
+#define IP6_RT_PRIO_USER 1024
+#define IP6_RT_PRIO_ADDRCONF 256
+#define IP6_RT_PRIO_KERN 512
+#define IP6_RT_FLOW_MASK 0x00ff
+
+#ifdef __KERNEL__
+
+#include <net/flow.h>
+#include <net/ip6_fib.h>
+
+struct pol_chain {
+ int type;
+ int priority;
+ struct fib6_node *rules;
+ struct pol_chain *next;
+};
+
+extern struct rt6_info ip6_null_entry;
+
+extern int ip6_rt_max_size;
+extern int ip6_rt_gc_min;
+extern int ip6_rt_gc_timeout;
+extern int ip6_rt_gc_interval;
+
+extern void ip6_route_input(struct sk_buff *skb);
+
+extern struct dst_entry * ip6_route_output(struct sock *sk,
+ struct flowi *fl);
+
+extern void ip6_route_init(void);
+extern void ip6_route_cleanup(void);
+
+extern int ipv6_route_ioctl(unsigned int cmd, void *arg);
+
+extern int ip6_route_add(struct in6_rtmsg *rtmsg);
+extern int ip6_del_rt(struct rt6_info *);
+
+extern int ip6_rt_addr_add(struct in6_addr *addr,
+ struct device *dev);
+
+extern int ip6_rt_addr_del(struct in6_addr *addr,
+ struct device *dev);
+
+extern void rt6_sndmsg(int type, struct in6_addr *dst,
+ struct in6_addr *src,
+ struct in6_addr *gw,
+ struct device *dev,
+ int dstlen, int srclen,
+ int metric, __u32 flags);
+
+extern struct rt6_info *rt6_lookup(struct in6_addr *daddr,
+ struct in6_addr *saddr,
+ int oif, int flags);
+
+/*
+ * support functions for ND
+ *
+ */
+extern struct rt6_info * rt6_get_dflt_router(struct in6_addr *addr,
+ struct device *dev);
+extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr,
+ struct device *dev);
+
+extern void rt6_purge_dflt_routers(int lst_resort);
+
+extern void rt6_redirect(struct in6_addr *dest,
+ struct in6_addr *saddr,
+ struct neighbour *neigh,
+ int on_link);
+
+extern void rt6_pmtu_discovery(struct in6_addr *daddr,
+ struct in6_addr *saddr,
+ struct device *dev,
+ u32 pmtu);
+
+struct nlmsghdr;
+struct netlink_callback;
+extern int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
+extern int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+
+extern void rt6_ifdown(struct device *dev);
+extern void rt6_mtu_change(struct device *dev, unsigned mtu);
+
+/*
+ * Store a destination cache entry in a socket
+ * For UDP/RAW sockets this is done on udp_connect.
+ */
+
+extern __inline__ void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
+ struct in6_addr *daddr)
+{
+ struct ipv6_pinfo *np;
+ struct rt6_info *rt;
+
+ np = &sk->net_pinfo.af_inet6;
+ dst_release(xchg(&sk->dst_cache,dst));
+
+ rt = (struct rt6_info *) dst;
+
+ np->daddr_cache = daddr;
+ np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+}
+
+#endif
+#endif
diff --git a/pfinet/linux-src/include/net/ip_fib.h b/pfinet/linux-src/include/net/ip_fib.h
new file mode 100644
index 00000000..76a2fbc3
--- /dev/null
+++ b/pfinet/linux-src/include/net/ip_fib.h
@@ -0,0 +1,257 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the Forwarding Information Base.
+ *
+ * Authors: A.N.Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_IP_FIB_H
+#define _NET_IP_FIB_H
+
+#include <linux/config.h>
+
+struct kern_rta
+{
+ void *rta_dst;
+ void *rta_src;
+ int *rta_iif;
+ int *rta_oif;
+ void *rta_gw;
+ u32 *rta_priority;
+ void *rta_prefsrc;
+ struct rtattr *rta_mx;
+ struct rtattr *rta_mp;
+ unsigned char *rta_protoinfo;
+ unsigned char *rta_flow;
+ struct rta_cacheinfo *rta_ci;
+};
+
+struct fib_nh
+{
+ struct device *nh_dev;
+ unsigned nh_flags;
+ unsigned char nh_scope;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ int nh_weight;
+ int nh_power;
+#endif
+#ifdef CONFIG_NET_CLS_ROUTE
+ __u32 nh_tclassid;
+#endif
+ int nh_oif;
+ u32 nh_gw;
+};
+
+/*
+ * This structure contains data shared by many of routes.
+ */
+
+struct fib_info
+{
+ struct fib_info *fib_next;
+ struct fib_info *fib_prev;
+ int fib_refcnt;
+ unsigned fib_flags;
+ int fib_protocol;
+ u32 fib_prefsrc;
+ u32 fib_priority;
+#define FIB_MAX_METRICS RTAX_RTT
+ unsigned fib_metrics[FIB_MAX_METRICS];
+#define fib_mtu fib_metrics[RTAX_MTU-1]
+#define fib_window fib_metrics[RTAX_WINDOW-1]
+#define fib_rtt fib_metrics[RTAX_RTT-1]
+ int fib_nhs;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ int fib_power;
+#endif
+ struct fib_nh fib_nh[0];
+#define fib_dev fib_nh[0].nh_dev
+};
+
+
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+struct fib_rule;
+#endif
+
+struct fib_result
+{
+ u32 *prefix;
+ unsigned char prefixlen;
+ unsigned char nh_sel;
+ unsigned char type;
+ unsigned char scope;
+ struct fib_info *fi;
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ struct fib_rule *r;
+#endif
+};
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+
+#define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel])
+#define FIB_RES_RESET(res) ((res).nh_sel = 0)
+
+#else /* CONFIG_IP_ROUTE_MULTIPATH */
+
+#define FIB_RES_NH(res) ((res).fi->fib_nh[0])
+#define FIB_RES_RESET(res)
+
+#endif /* CONFIG_IP_ROUTE_MULTIPATH */
+
+#define FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __fib_res_prefsrc(&res))
+#define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw)
+#define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev)
+#define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif)
+
+struct fib_table
+{
+ unsigned char tb_id;
+ unsigned tb_stamp;
+ int (*tb_lookup)(struct fib_table *tb, const struct rt_key *key, struct fib_result *res);
+ int (*tb_insert)(struct fib_table *table, struct rtmsg *r,
+ struct kern_rta *rta, struct nlmsghdr *n,
+ struct netlink_skb_parms *req);
+ int (*tb_delete)(struct fib_table *table, struct rtmsg *r,
+ struct kern_rta *rta, struct nlmsghdr *n,
+ struct netlink_skb_parms *req);
+ int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
+ struct netlink_callback *cb);
+ int (*tb_flush)(struct fib_table *table);
+ int (*tb_get_info)(struct fib_table *table, char *buf,
+ int first, int count);
+ void (*tb_select_default)(struct fib_table *table,
+ const struct rt_key *key, struct fib_result *res);
+
+ unsigned char tb_data[0];
+};
+
+#ifndef CONFIG_IP_MULTIPLE_TABLES
+
+extern struct fib_table *local_table;
+extern struct fib_table *main_table;
+
+extern __inline__ struct fib_table *fib_get_table(int id)
+{
+ if (id != RT_TABLE_LOCAL)
+ return main_table;
+ return local_table;
+}
+
+extern __inline__ struct fib_table *fib_new_table(int id)
+{
+ return fib_get_table(id);
+}
+
+extern __inline__ int fib_lookup(const struct rt_key *key, struct fib_result *res)
+{
+ if (local_table->tb_lookup(local_table, key, res) &&
+ main_table->tb_lookup(main_table, key, res))
+ return -ENETUNREACH;
+ return 0;
+}
+
+extern __inline__ void fib_select_default(const struct rt_key *key, struct fib_result *res)
+{
+ if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
+ main_table->tb_select_default(main_table, key, res);
+}
+
+#else /* CONFIG_IP_MULTIPLE_TABLES */
+#define local_table (fib_tables[RT_TABLE_LOCAL])
+#define main_table (fib_tables[RT_TABLE_MAIN])
+
+extern struct fib_table * fib_tables[RT_TABLE_MAX+1];
+extern int fib_lookup(const struct rt_key *key, struct fib_result *res);
+extern struct fib_table *__fib_new_table(int id);
+
+extern __inline__ struct fib_table *fib_get_table(int id)
+{
+ if (id == 0)
+ id = RT_TABLE_MAIN;
+
+ return fib_tables[id];
+}
+
+extern __inline__ struct fib_table *fib_new_table(int id)
+{
+ if (id == 0)
+ id = RT_TABLE_MAIN;
+
+ return fib_tables[id] ? : __fib_new_table(id);
+}
+
+extern void fib_select_default(const struct rt_key *key, struct fib_result *res);
+
+#endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+/* Exported by fib_frontend.c */
+extern void ip_fib_init(void);
+extern void fib_flush(void);
+extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
+extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
+ struct device *dev, u32 *spec_dst, u32 *itag);
+extern void fib_select_multipath(const struct rt_key *key, struct fib_result *res);
+
+/* Exported by fib_semantics.c */
+extern int ip_fib_check_default(u32 gw, struct device *dev);
+extern void fib_release_info(struct fib_info *);
+extern int fib_semantic_match(int type, struct fib_info *,
+ const struct rt_key *, struct fib_result*);
+extern struct fib_info *fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
+ const struct nlmsghdr *, int *err);
+extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *, struct kern_rta *rta, struct fib_info *fi);
+extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+ u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos,
+ struct fib_info *fi);
+extern int fib_sync_down(u32 local, struct device *dev, int force);
+extern int fib_sync_up(struct device *dev);
+extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
+ struct kern_rta *rta, struct rtentry *r);
+extern void fib_node_get_info(int type, int dead, struct fib_info *fi, u32 prefix, u32 mask, char *buffer);
+extern u32 __fib_res_prefsrc(struct fib_result *res);
+
+/* Exported by fib_hash.c */
+extern struct fib_table *fib_hash_init(int id);
+
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+/* Exported by fib_rules.c */
+
+extern int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
+extern int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
+extern u32 fib_rules_map_destination(u32 daddr, struct fib_result *res);
+#ifdef CONFIG_NET_CLS_ROUTE
+extern u32 fib_rules_tclass(struct fib_result *res);
+#endif
+extern u32 fib_rules_policy(u32 saddr, struct fib_result *res, unsigned *flags);
+extern void fib_rules_init(void);
+#endif
+
+extern __inline__ void fib_combine_itag(u32 *itag, struct fib_result *res)
+{
+#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ u32 rtag;
+#endif
+ *itag = FIB_RES_NH(*res).nh_tclassid<<16;
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ rtag = fib_rules_tclass(res);
+ if (*itag == 0)
+ *itag = (rtag<<16);
+ *itag |= (rtag>>16);
+#endif
+#endif
+}
+
+#endif /* _NET_FIB_H */
diff --git a/pfinet/linux-src/include/net/ip_masq.h b/pfinet/linux-src/include/net/ip_masq.h
new file mode 100644
index 00000000..1e050359
--- /dev/null
+++ b/pfinet/linux-src/include/net/ip_masq.h
@@ -0,0 +1,362 @@
+/*
+ * IP masquerading functionality definitions
+ */
+
+#include <linux/config.h> /* for CONFIG_IP_MASQ_DEBUG */
+#ifndef _IP_MASQ_H
+#define _IP_MASQ_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/list.h>
+#endif /* __KERNEL__ */
+
+/*
+ * This define affects the number of ports that can be handled
+ * by each of the protocol helper modules.
+ */
+#define MAX_MASQ_APP_PORTS 12
+
+/*
+ * Linux ports don't normally get allocated above 32K.
+ * I used an extra 4K port-space
+ */
+
+#define PORT_MASQ_BEGIN 61000
+#define PORT_MASQ_END (PORT_MASQ_BEGIN+4096)
+
+#define MASQUERADE_EXPIRE_TCP 15*60*HZ
+#define MASQUERADE_EXPIRE_TCP_FIN 2*60*HZ
+#define MASQUERADE_EXPIRE_UDP 5*60*HZ
+/*
+ * ICMP can no longer be modified on the fly using an ioctl - this
+ * define is the only way to change the timeouts
+ */
+#define MASQUERADE_EXPIRE_ICMP 125*HZ
+
+#define IP_MASQ_MOD_CTL 0x00
+#define IP_MASQ_USER_CTL 0x01
+
+#ifdef __KERNEL__
+
+#define IP_MASQ_TAB_SIZE 256
+
+#define IP_MASQ_F_NO_DADDR 0x0001 /* no daddr yet */
+#define IP_MASQ_F_NO_DPORT 0x0002 /* no dport set yet */
+#define IP_MASQ_F_NO_SADDR 0x0004 /* no sport set yet */
+#define IP_MASQ_F_NO_SPORT 0x0008 /* no sport set yet */
+
+#define IP_MASQ_F_DLOOSE 0x0010 /* loose dest binding */
+#define IP_MASQ_F_NO_REPLY 0x0080 /* no reply yet from outside */
+
+#define IP_MASQ_F_HASHED 0x0100 /* hashed entry */
+#define IP_MASQ_F_OUT_SEQ 0x0200 /* must do output seq adjust */
+#define IP_MASQ_F_IN_SEQ 0x0400 /* must do input seq adjust */
+
+#define IP_MASQ_F_MPORT 0x1000 /* own mport specified */
+#define IP_MASQ_F_USER 0x2000 /* from uspace */
+#define IP_MASQ_F_SIMPLE_HASH 0x8000 /* prevent s+d and m+d hashing */
+
+/*
+ * Delta seq. info structure
+ * Each MASQ struct has 2 (output AND input seq. changes).
+ */
+
+struct ip_masq_seq {
+ __u32 init_seq; /* Add delta from this seq */
+ short delta; /* Delta in sequence numbers */
+ short previous_delta; /* Delta in sequence numbers before last resized pkt */
+};
+
+/*
+ * MASQ structure allocated for each masqueraded association
+ */
+struct ip_masq {
+ struct list_head m_list, s_list, d_list;
+ /* hashed d-linked list heads */
+ atomic_t refcnt; /* reference count */
+ struct timer_list timer; /* Expiration timer */
+ __u16 protocol; /* Which protocol are we talking? */
+ __u16 sport, dport, mport; /* src, dst & masq ports */
+ __u32 saddr, daddr, maddr; /* src, dst & masq addresses */
+ struct ip_masq_seq out_seq, in_seq;
+ struct ip_masq_app *app; /* bound ip_masq_app object */
+ void *app_data; /* Application private data */
+ struct ip_masq *control; /* Master control connection */
+ atomic_t n_control; /* Number of "controlled" masqs */
+ unsigned flags; /* status flags */
+ unsigned timeout; /* timeout */
+ unsigned state; /* state info */
+ struct ip_masq_timeout_table *timeout_table;
+};
+
+/*
+ * Timeout values
+ * ipchains holds a copy of this definition
+ */
+
+struct ip_fw_masq {
+ int tcp_timeout;
+ int tcp_fin_timeout;
+ int udp_timeout;
+};
+
+union ip_masq_tphdr {
+ unsigned char *raw;
+ struct udphdr *uh;
+ struct tcphdr *th;
+ struct icmphdr *icmph;
+ __u16 *portp;
+};
+/*
+ * [0]: UDP free_ports
+ * [1]: TCP free_ports
+ * [2]: ICMP free_ports
+ */
+
+extern atomic_t ip_masq_free_ports[3];
+
+/*
+ * ip_masq initializer (registers symbols and /proc/net entries)
+ */
+extern int ip_masq_init(void);
+
+/*
+ * functions called from ip layer
+ */
+extern int ip_fw_masquerade(struct sk_buff **, __u32 maddr);
+extern int ip_fw_masq_icmp(struct sk_buff **, __u32 maddr);
+extern int ip_fw_unmasq_icmp(struct sk_buff *);
+extern int ip_fw_demasquerade(struct sk_buff **);
+
+/*
+ * ip_masq obj creation/deletion functions.
+ */
+extern struct ip_masq *ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags);
+
+extern void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms);
+extern void ip_masq_control_del(struct ip_masq *ms);
+extern struct ip_masq * ip_masq_control_get(struct ip_masq *ms);
+
+struct ip_masq_ctl;
+
+struct ip_masq_hook {
+ int (*ctl)(int, struct ip_masq_ctl *, int);
+ int (*info)(char *, char **, off_t, int, int);
+};
+
+extern struct list_head ip_masq_m_table[IP_MASQ_TAB_SIZE];
+extern struct list_head ip_masq_s_table[IP_MASQ_TAB_SIZE];
+extern struct list_head ip_masq_d_table[IP_MASQ_TAB_SIZE];
+extern const char * ip_masq_state_name(int state);
+extern struct ip_masq_hook *ip_masq_user_hook;
+extern u32 ip_masq_select_addr(struct device *dev, u32 dst, int scope);
+/*
+ *
+ * IP_MASQ_APP: IP application masquerading definitions
+ *
+ */
+
+struct ip_masq_app
+{
+ struct ip_masq_app *next;
+ char *name; /* name of application proxy */
+ unsigned type; /* type = proto<<16 | port (host byte order)*/
+ int n_attach;
+ int (*masq_init_1) /* ip_masq initializer */
+ (struct ip_masq_app *, struct ip_masq *);
+ int (*masq_done_1) /* ip_masq fin. */
+ (struct ip_masq_app *, struct ip_masq *);
+ int (*pkt_out) /* output (masquerading) hook */
+ (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32);
+ int (*pkt_in) /* input (demasq) hook */
+ (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, __u32);
+};
+
+/*
+ * ip_masq_app initializer
+ */
+extern int ip_masq_app_init(void);
+
+/*
+ * ip_masq_app object registration functions (port: host byte order)
+ */
+extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port);
+extern int unregister_ip_masq_app(struct ip_masq_app *mapp);
+
+/*
+ * get ip_masq_app obj by proto,port(net_byte_order)
+ */
+extern struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port);
+
+/*
+ * ip_masq TO ip_masq_app (un)binding functions.
+ */
+extern struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms);
+extern int ip_masq_unbind_app(struct ip_masq *ms);
+
+/*
+ * output and input app. masquerading hooks.
+ *
+ */
+extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr);
+extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, __u32 maddr);
+
+/*
+ * service routine(s).
+ */
+
+extern struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+extern struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+
+extern int ip_masq_listen(struct ip_masq *);
+
+static __inline__ struct ip_masq * ip_masq_in_get_iph(const struct iphdr *iph)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ return ip_masq_in_get(iph->protocol,
+ iph->saddr, portp[0],
+ iph->daddr, portp[1]);
+}
+
+static __inline__ struct ip_masq * ip_masq_out_get_iph(const struct iphdr *iph)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ return ip_masq_out_get(iph->protocol,
+ iph->saddr, portp[0],
+ iph->daddr, portp[1]);
+}
+
+extern void ip_masq_put(struct ip_masq *ms);
+
+
+extern rwlock_t __ip_masq_lock;
+
+#ifdef __SMP__
+#define read_lock_bh(lock) do { start_bh_atomic(); read_lock(lock); \
+ } while (0)
+#define read_unlock_bh(lock) do { read_unlock(lock); end_bh_atomic(); \
+ } while (0)
+#define write_lock_bh(lock) do { start_bh_atomic(); write_lock(lock); \
+ } while (0)
+#define write_unlock_bh(lock) do { write_unlock(lock); end_bh_atomic(); \
+ } while (0)
+#else
+#define read_lock_bh(lock) start_bh_atomic()
+#define read_unlock_bh(lock) end_bh_atomic()
+#define write_lock_bh(lock) start_bh_atomic()
+#define write_unlock_bh(lock) end_bh_atomic()
+#endif
+/*
+ *
+ */
+
+/*
+ * Debugging stuff
+ */
+
+extern int ip_masq_get_debug_level(void);
+
+#ifdef CONFIG_IP_MASQ_DEBUG
+#define IP_MASQ_DEBUG(level, msg...) do { \
+ if (level <= ip_masq_get_debug_level()) \
+ printk(KERN_DEBUG "IP_MASQ:" ## msg); \
+ } while (0)
+#else /* NO DEBUGGING at ALL */
+#define IP_MASQ_DEBUG(level, msg...) do { } while (0)
+#endif
+
+#define IP_MASQ_INFO(msg...) \
+ printk(KERN_INFO "IP_MASQ:" ## msg)
+
+#define IP_MASQ_ERR(msg...) \
+ printk(KERN_ERR "IP_MASQ:" ## msg)
+
+#define IP_MASQ_WARNING(msg...) \
+ printk(KERN_WARNING "IP_MASQ:" ## msg)
+
+
+/*
+ * /proc/net entry
+ */
+extern int ip_masq_proc_register(struct proc_dir_entry *);
+extern void ip_masq_proc_unregister(struct proc_dir_entry *);
+extern int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy);
+
+/*
+ * skb_replace function used by "client" modules to replace
+ * a segment of skb.
+ */
+extern struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len);
+
+/*
+ * masq_proto_num returns 0 for UDP, 1 for TCP, 2 for ICMP
+ */
+
+static __inline__ int masq_proto_num(unsigned proto)
+{
+ switch (proto)
+ {
+ case IPPROTO_UDP: return (0); break;
+ case IPPROTO_TCP: return (1); break;
+ case IPPROTO_ICMP: return (2); break;
+ default: return (-1); break;
+ }
+}
+
+static __inline__ const char *masq_proto_name(unsigned proto)
+{
+ static char buf[20];
+ static const char *strProt[] = {"UDP","TCP","ICMP"};
+ int msproto = masq_proto_num(proto);
+
+ if (msproto<0||msproto>2) {
+ sprintf(buf, "IP_%d", proto);
+ return buf;
+ }
+ return strProt[msproto];
+}
+
+enum {
+ IP_MASQ_S_NONE = 0,
+ IP_MASQ_S_ESTABLISHED,
+ IP_MASQ_S_SYN_SENT,
+ IP_MASQ_S_SYN_RECV,
+ IP_MASQ_S_FIN_WAIT,
+ IP_MASQ_S_TIME_WAIT,
+ IP_MASQ_S_CLOSE,
+ IP_MASQ_S_CLOSE_WAIT,
+ IP_MASQ_S_LAST_ACK,
+ IP_MASQ_S_LISTEN,
+ IP_MASQ_S_UDP,
+ IP_MASQ_S_ICMP,
+ IP_MASQ_S_LAST
+};
+
+struct ip_masq_timeout_table {
+ atomic_t refcnt;
+ int scale;
+ int timeout[IP_MASQ_S_LAST+1];
+};
+
+static __inline__ void ip_masq_timeout_attach(struct ip_masq *ms, struct ip_masq_timeout_table *mstim)
+{
+ atomic_inc (&mstim->refcnt);
+ ms->timeout_table=mstim;
+}
+
+static __inline__ void ip_masq_timeout_detach(struct ip_masq *ms)
+{
+ struct ip_masq_timeout_table *mstim = ms->timeout_table;
+
+ if (!mstim)
+ return;
+ atomic_dec(&mstim->refcnt);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _IP_MASQ_H */
diff --git a/pfinet/linux-src/include/net/ip_masq_mod.h b/pfinet/linux-src/include/net/ip_masq_mod.h
new file mode 100644
index 00000000..a7a67d6f
--- /dev/null
+++ b/pfinet/linux-src/include/net/ip_masq_mod.h
@@ -0,0 +1,86 @@
+/*
+ * IP Masquerading Modules Support
+ *
+ * Version: @(#)ip_masq_mod.h 0.01 97/10/30
+ *
+ * Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ */
+
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/ip_fw.h>
+#include <linux/proc_fs.h>
+#include <net/ip_masq.h>
+
+#define IP_MASQ_MOD_NOP 0
+#define IP_MASQ_MOD_ACCEPT 1
+#define IP_MASQ_MOD_REJECT -1
+
+struct ip_masq_mod {
+ struct ip_masq_mod *next; /* next mod for addrs. lookups */
+ struct ip_masq_mod *next_reg; /* next mod for configuration ctls */
+ char *mmod_name;
+ atomic_t refcnt;
+ atomic_t mmod_nent; /* number of entries */
+ struct proc_dir_entry *mmod_proc_ent;
+ int (*mmod_ctl) (int optname, struct ip_masq_ctl *, int optlen);
+ int (*mmod_init) (void);
+ int (*mmod_done) (void);
+ int (*mmod_in_rule) (const struct sk_buff *, const struct iphdr *);
+ int (*mmod_in_update) (const struct sk_buff *, const struct iphdr *,
+ struct ip_masq *);
+ struct ip_masq * (*mmod_in_create) (const struct sk_buff *, const struct iphdr *, __u32);
+ int (*mmod_out_rule) (const struct sk_buff *, const struct iphdr *);
+ int (*mmod_out_update) (const struct sk_buff *, const struct iphdr *,
+ struct ip_masq *);
+ struct ip_masq * (*mmod_out_create) (const struct sk_buff *, const struct iphdr *, __u32);
+};
+
+/*
+ * Service routines (called from ip_masq.c)
+ */
+
+int ip_masq_mod_out_rule(const struct sk_buff *, const struct iphdr *);
+int ip_masq_mod_out_update(const struct sk_buff *, const struct iphdr *, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *, const struct iphdr *iph, __u32 maddr);
+
+int ip_masq_mod_in_rule(const struct sk_buff *, const struct iphdr *iph);
+int ip_masq_mod_in_update(const struct sk_buff *, const struct iphdr *iph, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_in_create(const struct sk_buff *, const struct iphdr *iph, __u32 maddr);
+
+extern int ip_masq_mod_ctl(int optname, struct ip_masq_ctl *, int len);
+
+/*
+ * ip_masq_mod registration functions
+ */
+extern int register_ip_masq_mod(struct ip_masq_mod *mmod);
+extern int unregister_ip_masq_mod(struct ip_masq_mod *mmod);
+extern int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod);
+extern int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod);
+
+/*
+ * init functions protos
+ */
+extern int ip_portfw_init(void);
+extern int ip_mfw_init(void);
+extern int ip_autofw_init(void);
+
+/*
+ * Utility ...
+ */
+static __inline__ void ip_masq_mod_dec_nent(struct ip_masq_mod *mmod)
+{
+ if (atomic_dec_and_test(&mmod->mmod_nent)) {
+ ip_masq_mod_lkp_unlink(mmod);
+ }
+}
+static __inline__ void ip_masq_mod_inc_nent(struct ip_masq_mod *mmod)
+{
+ atomic_inc(&mmod->mmod_nent);
+ if (atomic_read(&mmod->mmod_nent)==1)
+ ip_masq_mod_lkp_link(mmod);
+}
+
+#endif /* __KERNEL__ */
diff --git a/pfinet/linux-src/include/net/ipconfig.h b/pfinet/linux-src/include/net/ipconfig.h
new file mode 100644
index 00000000..f9356946
--- /dev/null
+++ b/pfinet/linux-src/include/net/ipconfig.h
@@ -0,0 +1,21 @@
+/*
+ * $Id: ipconfig.h,v 1.3 1999/01/04 20:13:29 davem Exp $
+ *
+ * Copyright (C) 1997 Martin Mares
+ *
+ * Automatic IP Layer Configuration
+ */
+
+extern __u32 root_server_addr;
+extern u8 root_server_path[];
+extern u32 ic_myaddr;
+extern u32 ic_servaddr;
+extern u32 ic_gateway;
+extern u32 ic_netmask;
+extern int ic_enable;
+extern int ic_host_name_set;
+extern int ic_set_manually;
+extern int ic_proto_enabled;
+
+#define IC_BOOTP 1
+#define IC_RARP 2
diff --git a/pfinet/linux-src/include/net/ipip.h b/pfinet/linux-src/include/net/ipip.h
new file mode 100644
index 00000000..22c464c3
--- /dev/null
+++ b/pfinet/linux-src/include/net/ipip.h
@@ -0,0 +1,33 @@
+#ifndef __NET_IPIP_H
+#define __NET_IPIP_H 1
+
+#include <linux/if_tunnel.h>
+
+/* Keep error state on tunnel for 30 sec */
+#define IPTUNNEL_ERR_TIMEO (30*HZ)
+
+struct ip_tunnel
+{
+ struct ip_tunnel *next;
+ struct device *dev;
+ struct net_device_stats stat;
+
+ int recursion; /* Depth of hard_start_xmit recursion */
+ int err_count; /* Number of arrived ICMP errors */
+ unsigned long err_time; /* Time when the last ICMP error arrived */
+
+ /* These four fields used only by GRE */
+ __u32 i_seqno; /* The last seen seqno */
+ __u32 o_seqno; /* The last output seqno */
+ int hlen; /* Precalculated GRE header length */
+ int mlink;
+
+ struct ip_tunnel_parm parms;
+};
+
+extern int ipip_init(void);
+extern int ipgre_init(void);
+extern int sit_init(void);
+extern void sit_cleanup(void);
+
+#endif
diff --git a/pfinet/linux-src/include/net/ipv6.h b/pfinet/linux-src/include/net/ipv6.h
new file mode 100644
index 00000000..50e2299f
--- /dev/null
+++ b/pfinet/linux-src/include/net/ipv6.h
@@ -0,0 +1,325 @@
+/*
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: ipv6.h,v 1.16 1999/04/22 10:07:27 davem Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_IPV6_H
+#define _NET_IPV6_H
+
+#include <linux/ipv6.h>
+#include <asm/hardirq.h>
+#include <net/ndisc.h>
+#include <net/flow.h>
+
+/*
+ * NextHeader field of IPv6 header
+ */
+
+#define NEXTHDR_HOP 0 /* Hop-by-hop option header. */
+#define NEXTHDR_TCP 6 /* TCP segment. */
+#define NEXTHDR_UDP 17 /* UDP message. */
+#define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */
+#define NEXTHDR_ROUTING 43 /* Routing header. */
+#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */
+#define NEXTHDR_ESP 50 /* Encapsulating security payload. */
+#define NEXTHDR_AUTH 51 /* Authentication header. */
+#define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
+#define NEXTHDR_NONE 59 /* No next header */
+#define NEXTHDR_DEST 60 /* Destination options header. */
+
+#define NEXTHDR_MAX 255
+
+
+
+#define IPV6_DEFAULT_HOPLIMIT 64
+#define IPV6_DEFAULT_MCASTHOPS 1
+
+/*
+ * Addr type
+ *
+ * type - unicast | multicast | anycast
+ * scope - local | site | global
+ * v4 - compat
+ * v4mapped
+ * any
+ * loopback
+ */
+
+#define IPV6_ADDR_ANY 0x0000U
+
+#define IPV6_ADDR_UNICAST 0x0001U
+#define IPV6_ADDR_MULTICAST 0x0002U
+#define IPV6_ADDR_ANYCAST 0x0004U
+
+#define IPV6_ADDR_LOOPBACK 0x0010U
+#define IPV6_ADDR_LINKLOCAL 0x0020U
+#define IPV6_ADDR_SITELOCAL 0x0040U
+
+#define IPV6_ADDR_COMPATv4 0x0080U
+
+#define IPV6_ADDR_SCOPE_MASK 0x00f0U
+
+#define IPV6_ADDR_MAPPED 0x1000U
+#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
+
+/*
+ * fragmentation header
+ */
+
+struct frag_hdr {
+ unsigned char nexthdr;
+ unsigned char reserved;
+ unsigned short frag_off;
+ __u32 identification;
+};
+
+#ifdef __KERNEL__
+
+#include <net/sock.h>
+
+extern struct ipv6_mib ipv6_statistics;
+extern struct icmpv6_mib icmpv6_statistics;
+extern struct udp_mib udp_stats_in6;
+
+struct ip6_ra_chain
+{
+ struct ip6_ra_chain *next;
+ struct sock *sk;
+ int sel;
+ void (*destructor)(struct sock *);
+};
+
+extern struct ip6_ra_chain *ip6_ra_chain;
+
+/*
+ This structure is prepared by protocol, when parsing
+ ancillary data and passed to IPv6.
+ */
+
+struct ipv6_txoptions
+{
+ /* Length of this structure */
+ int tot_len;
+
+ /* length of extension headers */
+
+ __u16 opt_flen; /* after fragment hdr */
+ __u16 opt_nflen; /* before fragment hdr */
+
+ struct ipv6_opt_hdr *hopopt;
+ struct ipv6_opt_hdr *dst0opt;
+ struct ipv6_rt_hdr *srcrt; /* Routing Header */
+ struct ipv6_opt_hdr *auth;
+ struct ipv6_opt_hdr *dst1opt;
+
+ /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
+};
+
+struct ip6_flowlabel
+{
+ struct ip6_flowlabel *next;
+ u32 label;
+ struct in6_addr dst;
+ struct ipv6_txoptions *opt;
+ atomic_t users;
+ u32 linger;
+ u8 share;
+ u32 owner;
+ unsigned long lastuse;
+ unsigned long expires;
+};
+
+#define IPV6_FLOWINFO_MASK __constant_htonl(0x0FFFFFFF)
+#define IPV6_FLOWLABEL_MASK __constant_htonl(0x000FFFFF)
+
+struct ipv6_fl_socklist
+{
+ struct ipv6_fl_socklist *next;
+ struct ip6_flowlabel *fl;
+};
+
+extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, u32 label);
+extern struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
+ struct ip6_flowlabel * fl,
+ struct ipv6_txoptions * fopt);
+extern void fl6_free_socklist(struct sock *sk);
+extern int ipv6_flowlabel_opt(struct sock *sk, char *optval, int optlen);
+extern void ip6_flowlabel_init(void);
+extern void ip6_flowlabel_cleanup(void);
+
+extern __inline__ void fl6_sock_release(struct ip6_flowlabel *fl)
+{
+ if (fl)
+ atomic_dec(&fl->users);
+}
+
+extern int ip6_ra_control(struct sock *sk, int sel,
+ void (*destructor)(struct sock *));
+
+
+extern int ip6_call_ra_chain(struct sk_buff *skb, int sel);
+
+extern u8 * ipv6_reassembly(struct sk_buff **skb, u8 *nhptr);
+
+extern u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr);
+
+extern u8 * ipv6_parse_exthdrs(struct sk_buff **skb, u8 *nhptr);
+
+extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt);
+
+#define IPV6_FRAG_TIMEOUT (60*HZ) /* 60 seconds */
+
+/*
+ * Function prototype for build_xmit
+ */
+
+typedef int (*inet_getfrag_t) (const void *data,
+ struct in6_addr *addr,
+ char *,
+ unsigned int, unsigned int);
+
+
+extern int ipv6_addr_type(struct in6_addr *addr);
+
+extern __inline__ int ipv6_addr_scope(struct in6_addr *addr)
+{
+ return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+}
+
+extern __inline__ int ipv6_addr_cmp(struct in6_addr *a1, struct in6_addr *a2)
+{
+ return memcmp((void *) a1, (void *) a2, sizeof(struct in6_addr));
+}
+
+extern __inline__ void ipv6_addr_copy(struct in6_addr *a1, struct in6_addr *a2)
+{
+ memcpy((void *) a1, (void *) a2, sizeof(struct in6_addr));
+}
+
+#ifndef __HAVE_ARCH_ADDR_SET
+extern __inline__ void ipv6_addr_set(struct in6_addr *addr,
+ __u32 w1, __u32 w2,
+ __u32 w3, __u32 w4)
+{
+ addr->s6_addr32[0] = w1;
+ addr->s6_addr32[1] = w2;
+ addr->s6_addr32[2] = w3;
+ addr->s6_addr32[3] = w4;
+}
+#endif
+
+extern __inline__ int ipv6_addr_any(struct in6_addr *a)
+{
+ return ((a->s6_addr32[0] | a->s6_addr32[1] |
+ a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
+}
+
+/*
+ * Prototypes exported by ipv6
+ */
+
+/*
+ * rcv function (called from netdevice level)
+ */
+
+extern int ipv6_rcv(struct sk_buff *skb,
+ struct device *dev,
+ struct packet_type *pt);
+
+/*
+ * upper-layer output functions
+ */
+extern int ip6_xmit(struct sock *sk,
+ struct sk_buff *skb,
+ struct flowi *fl,
+ struct ipv6_txoptions *opt);
+
+extern int ip6_nd_hdr(struct sock *sk,
+ struct sk_buff *skb,
+ struct device *dev,
+ struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ int proto, int len);
+
+extern int ip6_build_xmit(struct sock *sk,
+ inet_getfrag_t getfrag,
+ const void *data,
+ struct flowi *fl,
+ unsigned length,
+ struct ipv6_txoptions *opt,
+ int hlimit, int flags);
+
+/*
+ * skb processing functions
+ */
+
+extern int ip6_output(struct sk_buff *skb);
+extern int ip6_forward(struct sk_buff *skb);
+extern int ip6_input(struct sk_buff *skb);
+extern int ip6_mc_input(struct sk_buff *skb);
+
+/*
+ * Extension header (options) processing
+ */
+
+extern u8 * ipv6_build_nfrag_opts(struct sk_buff *skb,
+ u8 *prev_hdr,
+ struct ipv6_txoptions *opt,
+ struct in6_addr *daddr,
+ u32 jumbolen);
+extern u8 * ipv6_build_frag_opts(struct sk_buff *skb,
+ u8 *prev_hdr,
+ struct ipv6_txoptions *opt);
+extern void ipv6_push_nfrag_opts(struct sk_buff *skb,
+ struct ipv6_txoptions *opt,
+ u8 *proto,
+ struct in6_addr **daddr_p);
+extern void ipv6_push_frag_opts(struct sk_buff *skb,
+ struct ipv6_txoptions *opt,
+ u8 *proto);
+
+extern u8 * ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr,
+ u8 *nexthdrp, int len);
+
+extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk,
+ struct ipv6_rt_hdr *hdr);
+
+
+/*
+ * socket options (ipv6_sockglue.c)
+ */
+
+extern int ipv6_setsockopt(struct sock *sk, int level,
+ int optname, char *optval,
+ int optlen);
+extern int ipv6_getsockopt(struct sock *sk, int level,
+ int optname, char *optval,
+ int *optlen);
+
+extern void ipv6_packet_init(void);
+
+extern void ipv6_netdev_notif_init(void);
+
+extern void ipv6_packet_cleanup(void);
+
+extern void ipv6_netdev_notif_cleanup(void);
+
+extern int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len);
+extern void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, u16 port,
+ u32 info, u8 *payload);
+extern void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info);
+
+#endif /* __KERNEL__ */
+#endif /* _NET_IPV6_H */
+
+
+
diff --git a/pfinet/linux-inet/ipx.h b/pfinet/linux-src/include/net/ipx.h
index 6842c832..2152e388 100644
--- a/pfinet/linux-inet/ipx.h
+++ b/pfinet/linux-src/include/net/ipx.h
@@ -1,4 +1,3 @@
-
/*
* The following information is in its entirety obtained from:
*
@@ -11,46 +10,42 @@
#ifndef _NET_INET_IPX_H_
#define _NET_INET_IPX_H_
-#include <linux/skbuff.h>
-#include "datalink.h"
+#include <linux/netdevice.h>
+#include <net/datalink.h>
#include <linux/ipx.h>
typedef struct
{
- unsigned long net;
- unsigned char node[IPX_NODE_LEN];
- unsigned short sock;
+ __u32 net;
+ __u8 node[IPX_NODE_LEN];
+ __u16 sock;
} ipx_address;
#define ipx_broadcast_node "\377\377\377\377\377\377"
+#define ipx_this_node "\0\0\0\0\0\0"
-typedef struct ipx_packet
+struct ipxhdr
{
- unsigned short ipx_checksum;
+ __u16 ipx_checksum __attribute__ ((packed));
#define IPX_NO_CHECKSUM 0xFFFF
- unsigned short ipx_pktsize;
- unsigned char ipx_tctrl;
- unsigned char ipx_type;
+ __u16 ipx_pktsize __attribute__ ((packed));
+ __u8 ipx_tctrl;
+ __u8 ipx_type;
#define IPX_TYPE_UNKNOWN 0x00
#define IPX_TYPE_RIP 0x01 /* may also be 0 */
#define IPX_TYPE_SAP 0x04 /* may also be 0 */
-#define IPX_TYPE_SPX 0x05 /* Not yet implemented */
+#define IPX_TYPE_SPX 0x05 /* SPX protocol */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */
ipx_address ipx_dest __attribute__ ((packed));
ipx_address ipx_source __attribute__ ((packed));
-} ipx_packet;
-
+};
-typedef struct sock ipx_socket;
-
-#include "ipxcall.h"
-extern int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
-extern void ipxrtr_device_down(struct device *dev);
+#include <net/ipxcall.h>
typedef struct ipx_interface {
/* IPX address */
- unsigned long if_netnum;
+ __u32 if_netnum;
unsigned char if_node[IPX_NODE_LEN];
/* physical device info */
@@ -60,7 +55,7 @@ typedef struct ipx_interface {
/* socket support */
unsigned short if_sknum;
- ipx_socket *if_sklist;
+ struct sock *if_sklist;
/* administrative overhead */
int if_ipx_offset;
@@ -71,7 +66,7 @@ typedef struct ipx_interface {
} ipx_interface;
typedef struct ipx_route {
- unsigned long ir_net;
+ __u32 ir_net;
ipx_interface *ir_intrfc;
unsigned char ir_routed;
unsigned char ir_router_node[IPX_NODE_LEN];
@@ -81,4 +76,7 @@ typedef struct ipx_route {
#define IPX_MIN_EPHEMERAL_SOCKET 0x4000
#define IPX_MAX_EPHEMERAL_SOCKET 0x7fff
-#endif
+extern int ipx_register_spx(struct proto_ops **, struct net_proto_family *);
+extern int ipx_unregister_spx(void);
+
+#endif /* def _NET_INET_IPX_H_ */
diff --git a/pfinet/linux-inet/ipxcall.h b/pfinet/linux-src/include/net/ipxcall.h
index eb5bd2bd..eb5bd2bd 100644
--- a/pfinet/linux-inet/ipxcall.h
+++ b/pfinet/linux-src/include/net/ipxcall.h
diff --git a/pfinet/linux-src/include/net/lapb.h b/pfinet/linux-src/include/net/lapb.h
new file mode 100644
index 00000000..7cc9b345
--- /dev/null
+++ b/pfinet/linux-src/include/net/lapb.h
@@ -0,0 +1,150 @@
+#ifndef _LAPB_H
+#define _LAPB_H
+#include <linux/lapb.h>
+
+#define LAPB_HEADER_LEN 20 /* LAPB over Ethernet + a bit more */
+
+#define LAPB_ACK_PENDING_CONDITION 0x01
+#define LAPB_REJECT_CONDITION 0x02
+#define LAPB_PEER_RX_BUSY_CONDITION 0x04
+
+/* Control field templates */
+#define LAPB_I 0x00 /* Information frames */
+#define LAPB_S 0x01 /* Supervisory frames */
+#define LAPB_U 0x03 /* Unnumbered frames */
+
+#define LAPB_RR 0x01 /* Receiver ready */
+#define LAPB_RNR 0x05 /* Receiver not ready */
+#define LAPB_REJ 0x09 /* Reject */
+
+#define LAPB_SABM 0x2F /* Set Asynchronous Balanced Mode */
+#define LAPB_SABME 0x6F /* Set Asynchronous Balanced Mode Extended */
+#define LAPB_DISC 0x43 /* Disconnect */
+#define LAPB_DM 0x0F /* Disconnected mode */
+#define LAPB_UA 0x63 /* Unnumbered acknowledge */
+#define LAPB_FRMR 0x87 /* Frame reject */
+
+#define LAPB_ILLEGAL 0x100 /* Impossible to be a real frame type */
+
+#define LAPB_SPF 0x10 /* Poll/final bit for standard LAPB */
+#define LAPB_EPF 0x01 /* Poll/final bit for extended LAPB */
+
+#define LAPB_FRMR_W 0x01 /* Control field invalid */
+#define LAPB_FRMR_X 0x02 /* I field invalid */
+#define LAPB_FRMR_Y 0x04 /* I field too long */
+#define LAPB_FRMR_Z 0x08 /* Invalid N(R) */
+
+#define LAPB_POLLOFF 0
+#define LAPB_POLLON 1
+
+/* LAPB C-bit */
+#define LAPB_COMMAND 1
+#define LAPB_RESPONSE 2
+
+#define LAPB_ADDR_A 0x03
+#define LAPB_ADDR_B 0x01
+#define LAPB_ADDR_C 0x0F
+#define LAPB_ADDR_D 0x07
+
+/* Define Link State constants. */
+enum {
+ LAPB_STATE_0, /* Disconnected State */
+ LAPB_STATE_1, /* Awaiting Connection State */
+ LAPB_STATE_2, /* Awaiting Disconnection State */
+ LAPB_STATE_3, /* Data Transfer State */
+ LAPB_STATE_4 /* Frame Reject State */
+};
+
+#define LAPB_DEFAULT_MODE (LAPB_STANDARD | LAPB_SLP | LAPB_DTE)
+#define LAPB_DEFAULT_WINDOW 7 /* Window=7 */
+#define LAPB_DEFAULT_T1 (5 * HZ) /* T1=5s */
+#define LAPB_DEFAULT_T2 (1 * HZ) /* T2=1s */
+#define LAPB_DEFAULT_N2 20 /* N2=20 */
+
+#define LAPB_SMODULUS 8
+#define LAPB_EMODULUS 128
+
+/*
+ * Information about the current frame.
+ */
+struct lapb_frame {
+ unsigned short type; /* Parsed type */
+ unsigned short nr, ns; /* N(R), N(S) */
+ unsigned char cr; /* Command/Response */
+ unsigned char pf; /* Poll/Final */
+ unsigned char control[2]; /* Original control data*/
+};
+
+/*
+ * The per LAPB connection control structure.
+ */
+typedef struct lapb_cb {
+ struct lapb_cb *next;
+ void *token;
+
+ /* Link status fields */
+ unsigned int mode;
+ unsigned char state;
+ unsigned short vs, vr, va;
+ unsigned char condition;
+ unsigned short n2, n2count;
+ unsigned short t1, t2;
+ struct timer_list t1timer, t2timer;
+
+ /* Internal control information */
+ struct sk_buff_head write_queue;
+ struct sk_buff_head ack_queue;
+ unsigned char window;
+ struct lapb_register_struct callbacks;
+
+ /* FRMR control information */
+ struct lapb_frame frmr_data;
+ unsigned char frmr_type;
+} lapb_cb;
+
+/* lapb_iface.c */
+extern void lapb_connect_confirmation(lapb_cb *, int);
+extern void lapb_connect_indication(lapb_cb *, int);
+extern void lapb_disconnect_confirmation(lapb_cb *, int);
+extern void lapb_disconnect_indication(lapb_cb *, int);
+extern int lapb_data_indication(lapb_cb *, struct sk_buff *);
+extern int lapb_data_transmit(lapb_cb *, struct sk_buff *);
+
+/* lapb_in.c */
+extern void lapb_data_input(lapb_cb *, struct sk_buff *);
+
+/* lapb_out.c */
+extern void lapb_kick(lapb_cb *);
+extern void lapb_transmit_buffer(lapb_cb *, struct sk_buff *, int);
+extern void lapb_establish_data_link(lapb_cb *);
+extern void lapb_enquiry_response(lapb_cb *);
+extern void lapb_timeout_response(lapb_cb *);
+extern void lapb_check_iframes_acked(lapb_cb *, unsigned short);
+extern void lapb_check_need_response(lapb_cb *, int, int);
+
+/* lapb_subr.c */
+extern void lapb_clear_queues(lapb_cb *);
+extern void lapb_frames_acked(lapb_cb *, unsigned short);
+extern void lapb_requeue_frames(lapb_cb *);
+extern int lapb_validate_nr(lapb_cb *, unsigned short);
+extern void lapb_decode(lapb_cb *, struct sk_buff *, struct lapb_frame *);
+extern void lapb_send_control(lapb_cb *, int, int, int);
+extern void lapb_transmit_frmr(lapb_cb *);
+
+/* lapb_timer.c */
+extern void lapb_start_t1timer(lapb_cb *);
+extern void lapb_start_t2timer(lapb_cb *);
+extern void lapb_stop_t1timer(lapb_cb *);
+extern void lapb_stop_t2timer(lapb_cb *);
+extern int lapb_t1timer_running(lapb_cb *);
+
+/*
+ * Debug levels.
+ * 0 = Off
+ * 1 = State Changes
+ * 2 = Packets I/O and State Changes
+ * 3 = Hex dumps, Packets I/O and State Changes.
+ */
+#define LAPB_DEBUG 0
+
+#endif
diff --git a/pfinet/linux-src/include/net/lapbcall.h b/pfinet/linux-src/include/net/lapbcall.h
new file mode 100644
index 00000000..825e7f2c
--- /dev/null
+++ b/pfinet/linux-src/include/net/lapbcall.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void lapb_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/include/net/llc.h b/pfinet/linux-src/include/net/llc.h
new file mode 100644
index 00000000..654a658d
--- /dev/null
+++ b/pfinet/linux-src/include/net/llc.h
@@ -0,0 +1,135 @@
+#include <linux/skbuff.h>
+
+#define LLC_MODULE
+
+typedef struct llc_struct llc;
+typedef struct llc_struct *llcptr;
+
+/*
+ * LLC private data area structure.
+ */
+
+struct llc_struct
+{
+ char eye[4]; /* To recognize llc area in dump */
+ int retry_count; /* LLC link state variables */
+ unsigned char name[9]; /* name of this llc instance */
+ unsigned char s_flag;
+ unsigned char p_flag;
+ unsigned char f_flag;
+ unsigned char data_flag;
+ unsigned char cause_flag;
+ unsigned char vs; /* Send state variable */
+ unsigned char vr; /* Receive state variable */
+ unsigned char remote_busy;
+ unsigned char state; /* Current state of type2 llc procedure */
+ int n1; /* Maximum number of bytes in I pdu 7.8.2 */
+ int n2; /* Naximum number of retransmissions 7.8.2 */
+ unsigned char k; /* Transmit window size 7.8.4, tw in IBM doc*/
+ unsigned char rw; /* Receive window size */
+ struct
+ {
+ /*
+ * FRMR_RSP info field structure: 5.4.2.3.5 p55
+ */
+
+ unsigned char cntl1;
+ unsigned char cntl2;
+ unsigned char vs;
+ unsigned char vr_cr;
+ unsigned char xxyz;
+ } frmr_info_fld;
+
+ /*
+ * Timers in 7.8.1 page 78
+ */
+
+#define P_TIMER 0
+#define REJ_TIMER 1
+#define ACK_TIMER 2
+#define BUSY_TIMER 3
+ unsigned long timer_expire_time[4];
+ unsigned char timer_state[4]; /* The state of each timer */
+#define TIMER_IDLE 0
+#define TIMER_RUNNING 1
+#define TIMER_EXPIRED 2
+ unsigned long timer_interval[4];
+ struct timer_list tl[4];
+
+ /*
+ * Client entry point, called by the LLC.
+ */
+
+ void (*llc_event)(struct llc_struct *);
+
+ /*
+ * Mux and Demux variables
+ */
+
+ char * client_data; /* Pointer to clients context */
+ unsigned char local_sap;
+ unsigned char remote_sap ;
+ char remote_mac[MAX_ADDR_LEN]; /* MAC address of remote session partner */
+ struct device *dev; /* Device we are attached to */
+
+ unsigned char llc_mode; /* See doc 7.1 on p70 */
+#define MODE_ADM 1
+#define MODE_ABM 2
+
+ int llc_callbacks; /* Pending callbacks */
+#define LLC_CONN_INDICATION 1 /* We have to ensure the names don't */
+#define LLC_CONN_CONFIRM 2 /* mix up with the 802 state table */
+#define LLC_DATA_INDIC 4
+#define LLC_DISC_INDICATION 8
+#define LLC_RESET_INDIC_LOC 16
+#define LLC_RESET_INDIC_REM 32
+#define LLC_RST_CONFIRM 64
+#define LLC_FRMR_RECV 128
+#define LLC_FRMR_SENT 256
+#define LLC_REMOTE_BUSY 512
+#define LLC_REMOTE_NOTBUSY 1024
+#define LLC_TEST_INDICATION 2048
+#define LLC_XID_INDICATION 4096
+#define LLC_UI_DATA 8192
+
+ struct sk_buff *inc_skb; /* Saved data buffer for indications */
+
+ struct sk_buff_head rtq; /* Retransmit queue */
+ struct sk_buff_head atq; /* Await transit queue */
+
+ unsigned char xid_count;
+
+ struct llc_struct *nextllc; /* ptr to next llc struct in proto chain */
+};
+
+#define ADD_TO_RTQ(skb) skb_queue_tail(&lp->rtq,skb)
+#define ADD_TO_ATQ(skb) skb_queue_tail(&lp->atq,skb)
+
+void llc_cancel_timers(llcptr lp);
+int llc_decode_frametype(frameptr fr);
+llcptr llc_find(void);
+int llc_free_acknowledged_skbs(llcptr lp, unsigned char ack);
+void llc_handle_xid_indication( char *chsp, short int ll, char *xid_data);
+void llc_interpret_pseudo_code(llcptr lp, int pc_label, struct sk_buff *skb, char type);
+void llc_add_to_queue(struct sk_buff *skb, struct sk_buff **f, struct sk_buff **b);
+void llc_process_otype2_frame(llcptr lp, struct sk_buff *skb, char type);
+struct sk_buff *llc_pull_from_atq(llcptr lp);
+int llc_resend_ipdu(llcptr lp, unsigned char ack_nr, unsigned char type, char p);
+void llc_sendpdu(llcptr lp, char type, char pf, int data_len, char *pdu_data);
+void llc_sendipdu(llcptr lp, char type, char pf, struct sk_buff *skb);
+void llc_start_timer(llcptr lp, int t);
+void llc_stop_timer(llcptr lp, int t);
+void llc_timer_expired(llcptr lp, int t);
+int llc_validate_seq_nos(llcptr lp, frameptr fr);
+
+int llc_data_request(llcptr lp, struct sk_buff *skb);
+void llc_unit_data_request(llcptr lp, int ll, char * data);
+void llc_disconnect_request(llcptr lp);
+void llc_connect_request(llcptr lp);
+void llc_xid_request(llcptr lp, char opt, int data_len, char *pdu_data);
+void llc_test_request(llcptr lp, int data_len, char *pdu_data);
+
+int register_cl2llc_client(llcptr llc, const char *device, void (*ops)(llcptr), u8 *rmac, u8 ssap, u8 dsap);
+void unregister_cl2llc_client(llcptr lp);
+int llc_mac_data_indicate(llcptr lp, struct sk_buff *skb );
+
diff --git a/pfinet/linux-src/include/net/llc_frame.h b/pfinet/linux-src/include/net/llc_frame.h
new file mode 100644
index 00000000..e8fb198d
--- /dev/null
+++ b/pfinet/linux-src/include/net/llc_frame.h
@@ -0,0 +1,98 @@
+/* if_ether.h needed for definition of ETH_DATA_LEN and ETH_ALEN
+ */
+#include "linux/if_ether.h"
+
+/* frame layout based on par3.2 "LLC PDU format"
+ */
+typedef union { /* pdu layout from pages 40 & 44 */
+ struct { /* general header, all pdu types */
+ unsigned dsap : 8; /* dest service access point */
+ unsigned ssap : 8; /* source service access point */
+ unsigned f1 : 1; /* I- U- or S- format id bits */
+ unsigned f2 : 1;
+ unsigned : 6;
+ unsigned : 8;
+ } pdu_hdr;
+ struct {
+ char dummy1[2]; /* dsap + ssap */
+ char byte1;
+ char byte2;
+ } pdu_cntl; /* unformatted control bytes */
+ struct { /* header of an Information pdu */
+ unsigned char dummy2[2];
+ unsigned : 1;
+ unsigned ns : 7;
+ unsigned i_pflag : 1; /* poll/final bit */
+ unsigned nr : 7; /* N(R) */
+ unsigned char is_info[ ETH_DATA_LEN ];
+ } i_hdr;
+ struct { /* header of a Supervisory pdu */
+ unsigned char dummy3[2];
+ unsigned : 2;
+ unsigned ss : 2; /* supervisory function bits */
+ unsigned : 4;
+ unsigned s_pflag : 1; /* poll/final bit */
+ unsigned nr : 7; /* N(R) */
+ } s_hdr;
+
+/* when accessing the P/F bit or the N(R) field there's no need to distinguish
+ I pdus from S pdus i_pflag and s_pflag / i_nr and s_nr map to the same
+ physical location.
+ */
+ struct { /* header of an Unnumbered pdu */
+ unsigned char dummy4[2];
+ unsigned : 2;
+ unsigned mm1 : 2; /* modifier function part1 */
+ unsigned u_pflag : 1; /* P/F for U- pdus */
+ unsigned mm2 : 3; /* modifier function part2 */
+ unsigned char u_info[ ETH_DATA_LEN-1];
+ } u_hdr;
+ struct { /* mm field in an Unnumbered pdu */
+ unsigned char dummy5[2];
+ unsigned : 2;
+ unsigned mm : 6; /* must be masked to get ridd of P/F ! */
+ } u_mm;
+
+} frame_type, *frameptr;
+
+/* frame format test macros: */
+
+#define IS_UFRAME( fr ) ( ( (fr)->pdu_hdr.f1) & ( (fr)->pdu_hdr.f2) )
+
+#define IS_IFRAME( fr ) ( !( (fr)->pdu_hdr.f1) )
+
+#define IS_SFRAME( fr ) ( ( (fr)->pdu_hdr.f1) & !( (fr)->pdu_hdr.f2) )
+
+#define IS_RSP( fr ) ( fr->pdu_hdr.ssap & 0x01 )
+
+
+/* The transition table, the _encode tables and some tests in the
+ source code depend on the numeric order of these values.
+ Think twice before changing.
+ */
+
+/* frame names for TYPE 2 operation: */
+#define I_CMD 0
+#define RR_CMD 1
+#define RNR_CMD 2
+#define REJ_CMD 3
+#define DISC_CMD 4
+#define SABME_CMD 5
+#define I_RSP 6
+#define RR_RSP 7
+#define RNR_RSP 8
+#define REJ_RSP 9
+#define UA_RSP 10
+#define DM_RSP 11
+#define FRMR_RSP 12
+
+/* junk frame name: */
+#define BAD_FRAME 13
+#define NO_FRAME 13
+
+/* frame names for TYPE 1 operation: */
+#define UI_CMD 14
+#define XID_CMD 15
+#define TEST_CMD 16
+#define XID_RSP 17
+#define TEST_RSP 18
diff --git a/pfinet/linux-src/include/net/llc_name.h b/pfinet/linux-src/include/net/llc_name.h
new file mode 100644
index 00000000..72128719
--- /dev/null
+++ b/pfinet/linux-src/include/net/llc_name.h
@@ -0,0 +1,7 @@
+char *frame_names[] =
+ {"I_CMD","RR_CMD","RNR_CMD","REJ_CMD","DISC_CMD",
+ "SABME_CMD","I_RSP","RR_RSP","RNR_RSP","REJ_RSP",
+ "UA_RSP","DM_RSP","FRMR_RSP","BAD_FRAME","UI_CMD",
+ "XID_CMD","TEST_CMD","XID_RSP","TEST_RSP"
+};
+
diff --git a/pfinet/linux-src/include/net/llc_state.h b/pfinet/linux-src/include/net/llc_state.h
new file mode 100644
index 00000000..bb18e9bd
--- /dev/null
+++ b/pfinet/linux-src/include/net/llc_state.h
@@ -0,0 +1,4 @@
+char *state_names[] = {
+ "ADM","CONN","RESET_WAIT","RESET_CHECK","SETUP",
+ "RESET","D_CONN","ERROR","NORMAL"
+};
diff --git a/pfinet/linux-src/include/net/llccall.h b/pfinet/linux-src/include/net/llccall.h
new file mode 100644
index 00000000..07013ba3
--- /dev/null
+++ b/pfinet/linux-src/include/net/llccall.h
@@ -0,0 +1,3 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void llc_init(struct net_proto *pro);
+
diff --git a/pfinet/linux-src/include/net/ndisc.h b/pfinet/linux-src/include/net/ndisc.h
new file mode 100644
index 00000000..7a51f367
--- /dev/null
+++ b/pfinet/linux-src/include/net/ndisc.h
@@ -0,0 +1,123 @@
+#ifndef _NDISC_H
+#define _NDISC_H
+
+/*
+ * ICMP codes for neighbour discovery messages
+ */
+
+#define NDISC_ROUTER_SOLICITATION 133
+#define NDISC_ROUTER_ADVERTISEMENT 134
+#define NDISC_NEIGHBOUR_SOLICITATION 135
+#define NDISC_NEIGHBOUR_ADVERTISEMENT 136
+#define NDISC_REDIRECT 137
+
+/*
+ * ndisc options
+ */
+
+#define ND_OPT_SOURCE_LL_ADDR 1
+#define ND_OPT_TARGET_LL_ADDR 2
+#define ND_OPT_PREFIX_INFO 3
+#define ND_OPT_REDIRECT_HDR 4
+#define ND_OPT_MTU 5
+
+#define MAX_RTR_SOLICITATION_DELAY HZ
+
+#define ND_REACHABLE_TIME (30*HZ)
+#define ND_RETRANS_TIMER HZ
+
+#define ND_MIN_RANDOM_FACTOR (1/2)
+#define ND_MAX_RANDOM_FACTOR (3/2)
+
+#ifdef __KERNEL__
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/icmpv6.h>
+#include <net/neighbour.h>
+#include <asm/atomic.h>
+
+extern struct neigh_table nd_tbl;
+
+struct nd_msg {
+ struct icmp6hdr icmph;
+ struct in6_addr target;
+ struct {
+ __u8 opt_type;
+ __u8 opt_len;
+ __u8 link_addr[MAX_ADDR_LEN];
+ } opt;
+};
+
+struct ra_msg {
+ struct icmp6hdr icmph;
+ __u32 reachable_time;
+ __u32 retrans_timer;
+};
+
+
+extern int ndisc_init(struct net_proto_family *ops);
+
+extern void ndisc_cleanup(void);
+
+extern int ndisc_rcv(struct sk_buff *skb, unsigned long len);
+
+extern void ndisc_send_ns(struct device *dev,
+ struct neighbour *neigh,
+ struct in6_addr *solicit,
+ struct in6_addr *daddr,
+ struct in6_addr *saddr);
+
+extern void ndisc_send_rs(struct device *dev,
+ struct in6_addr *saddr,
+ struct in6_addr *daddr);
+
+extern void ndisc_forwarding_on(void);
+extern void ndisc_forwarding_off(void);
+
+extern void ndisc_send_redirect(struct sk_buff *skb,
+ struct neighbour *neigh,
+ struct in6_addr *target);
+
+extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct device *dev, int dir);
+
+
+struct rt6_info * dflt_rt_lookup(void);
+
+/*
+ * IGMP
+ */
+extern int igmp6_init(struct net_proto_family *ops);
+
+extern void igmp6_cleanup(void);
+
+extern int igmp6_event_query(struct sk_buff *skb,
+ struct icmp6hdr *hdr,
+ int len);
+
+extern int igmp6_event_report(struct sk_buff *skb,
+ struct icmp6hdr *hdr,
+ int len);
+
+extern void igmp6_cleanup(void);
+
+extern __inline__ struct neighbour * ndisc_get_neigh(struct device *dev, struct in6_addr *addr)
+{
+
+ if (dev) {
+ struct neighbour *neigh;
+
+ start_bh_atomic();
+ neigh = __neigh_lookup(&nd_tbl, addr, dev, 1);
+ end_bh_atomic();
+
+ return neigh;
+ }
+ return NULL;
+}
+
+
+#endif /* __KERNEL__ */
+
+
+#endif
diff --git a/pfinet/linux-src/include/net/neighbour.h b/pfinet/linux-src/include/net/neighbour.h
new file mode 100644
index 00000000..5c5d90bb
--- /dev/null
+++ b/pfinet/linux-src/include/net/neighbour.h
@@ -0,0 +1,272 @@
+#ifndef _NET_NEIGHBOUR_H
+#define _NET_NEIGHBOUR_H
+
+/*
+ * Generic neighbour manipulation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ */
+
+/* The following flags & states are exported to user space,
+ so that they should be moved to include/linux/ directory.
+ */
+
+/*
+ * Neighbor Cache Entry Flags
+ */
+
+#define NTF_PROXY 0x08 /* == ATF_PUBL */
+#define NTF_ROUTER 0x80
+
+/*
+ * Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE 0x02
+#define NUD_STALE 0x04
+#define NUD_DELAY 0x08
+#define NUD_PROBE 0x10
+#define NUD_FAILED 0x20
+
+/* Dummy states */
+#define NUD_NOARP 0x40
+#define NUD_PERMANENT 0x80
+#define NUD_NONE 0x00
+
+/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
+ and make no address resolution or NUD.
+ NUD_PERMANENT is also cannot be deleted by garbage collectors.
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/atomic.h>
+#include <linux/skbuff.h>
+
+#define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_DELAY|NUD_PROBE)
+#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
+#define NUD_CONNECTED (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)
+
+struct neigh_parms
+{
+ struct neigh_parms *next;
+ int (*neigh_setup)(struct neighbour *);
+ struct neigh_table *tbl;
+ int entries;
+ void *priv;
+
+ void *sysctl_table;
+
+ int base_reachable_time;
+ int retrans_time;
+ int gc_staletime;
+ int reachable_time;
+ int delay_probe_time;
+
+ int queue_len;
+ int ucast_probes;
+ int app_probes;
+ int mcast_probes;
+ int anycast_delay;
+ int proxy_delay;
+ int proxy_qlen;
+ int locktime;
+};
+
+struct neigh_statistics
+{
+ unsigned long allocs;
+ unsigned long res_failed;
+ unsigned long rcv_probes_mcast;
+ unsigned long rcv_probes_ucast;
+};
+
+struct neighbour
+{
+ struct neighbour *next;
+ struct neigh_table *tbl;
+ struct neigh_parms *parms;
+ struct device *dev;
+ unsigned long used;
+ unsigned long confirmed;
+ unsigned long updated;
+ __u8 flags;
+ __u8 nud_state;
+ __u8 type;
+ __u8 probes;
+ unsigned char ha[MAX_ADDR_LEN];
+ struct hh_cache *hh;
+ atomic_t refcnt;
+ int (*output)(struct sk_buff *skb);
+ struct sk_buff_head arp_queue;
+ struct timer_list timer;
+ struct neigh_ops *ops;
+ u8 primary_key[0];
+};
+
+struct neigh_ops
+{
+ int family;
+ void (*destructor)(struct neighbour *);
+ void (*solicit)(struct neighbour *, struct sk_buff*);
+ void (*error_report)(struct neighbour *, struct sk_buff*);
+ int (*output)(struct sk_buff*);
+ int (*connected_output)(struct sk_buff*);
+ int (*hh_output)(struct sk_buff*);
+ int (*queue_xmit)(struct sk_buff*);
+};
+
+struct pneigh_entry
+{
+ struct pneigh_entry *next;
+ struct device *dev;
+ u8 key[0];
+};
+
+#define NEIGH_HASHMASK 0x1F
+#define PNEIGH_HASHMASK 0xF
+
+/*
+ * neighbour table manipulation
+ */
+
+
+struct neigh_table
+{
+ struct neigh_table *next;
+ int family;
+ int entry_size;
+ int key_len;
+ int (*constructor)(struct neighbour *);
+ int (*pconstructor)(struct pneigh_entry *);
+ void (*pdestructor)(struct pneigh_entry *);
+ void (*proxy_redo)(struct sk_buff *skb);
+ struct neigh_parms parms;
+ /* HACK. gc_* shoul follow parms without a gap! */
+ int gc_interval;
+ int gc_thresh1;
+ int gc_thresh2;
+ int gc_thresh3;
+ unsigned long last_flush;
+ struct timer_list gc_timer;
+ struct timer_list proxy_timer;
+ struct sk_buff_head proxy_queue;
+ int entries;
+ atomic_t lock;
+ unsigned long last_rand;
+ struct neigh_parms *parms_list;
+ struct neigh_statistics stats;
+ struct neighbour *hash_buckets[NEIGH_HASHMASK+1];
+ struct pneigh_entry *phash_buckets[PNEIGH_HASHMASK+1];
+};
+
+extern void neigh_table_init(struct neigh_table *tbl);
+extern int neigh_table_clear(struct neigh_table *tbl);
+extern struct neighbour *__neigh_lookup(struct neigh_table *tbl,
+ const void *pkey, struct device *dev,
+ int creat);
+extern void neigh_destroy(struct neighbour *neigh);
+extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
+extern int neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int arp);
+extern int neigh_ifdown(struct neigh_table *tbl, struct device *dev);
+extern int neigh_resolve_output(struct sk_buff *skb);
+extern int neigh_connected_output(struct sk_buff *skb);
+extern int neigh_compat_output(struct sk_buff *skb);
+extern struct neighbour *neigh_event_ns(struct neigh_table *tbl,
+ u8 *lladdr, void *saddr,
+ struct device *dev);
+
+extern struct neigh_parms *neigh_parms_alloc(struct device *dev, struct neigh_table *tbl);
+extern void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms);
+extern unsigned long neigh_rand_reach_time(unsigned long base);
+
+extern void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
+ struct sk_buff *skb);
+extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, const void *key, struct device *dev, int creat);
+extern int pneigh_delete(struct neigh_table *tbl, const void *key, struct device *dev);
+
+struct netlink_callback;
+struct nlmsghdr;
+extern int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb);
+extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
+extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
+extern void neigh_app_ns(struct neighbour *n);
+
+extern int neigh_sysctl_register(struct device *dev, struct neigh_parms *p,
+ int p_id, int pdev_id, char *p_name);
+extern void neigh_sysctl_unregister(struct neigh_parms *p);
+
+/*
+ * Neighbour references
+ *
+ * When neighbour pointers are passed to "client" code the
+ * reference count is increased. The count is 0 if the node
+ * is only referenced by the corresponding table.
+ */
+
+extern __inline__ void neigh_release(struct neighbour *neigh)
+{
+ if (atomic_dec_and_test(&neigh->refcnt) && neigh->tbl == NULL)
+ neigh_destroy(neigh);
+}
+
+extern __inline__ struct neighbour * neigh_clone(struct neighbour *neigh)
+{
+ if (neigh)
+ atomic_inc(&neigh->refcnt);
+ return neigh;
+}
+
+extern __inline__ void neigh_confirm(struct neighbour *neigh)
+{
+ if (neigh)
+ neigh->confirmed = jiffies;
+}
+
+extern __inline__ struct neighbour *
+neigh_lookup(struct neigh_table *tbl, const void *pkey, struct device *dev)
+{
+ struct neighbour *neigh;
+ start_bh_atomic();
+ neigh = __neigh_lookup(tbl, pkey, dev, 0);
+ end_bh_atomic();
+ return neigh;
+}
+
+extern __inline__ int neigh_is_connected(struct neighbour *neigh)
+{
+ return neigh->nud_state&NUD_CONNECTED;
+}
+
+extern __inline__ int neigh_is_valid(struct neighbour *neigh)
+{
+ return neigh->nud_state&NUD_VALID;
+}
+
+extern __inline__ int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+{
+ neigh->used = jiffies;
+ if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
+ return __neigh_event_send(neigh, skb);
+ return 0;
+}
+
+extern __inline__ void neigh_table_lock(struct neigh_table *tbl)
+{
+ atomic_inc(&tbl->lock);
+ synchronize_bh();
+}
+
+extern __inline__ void neigh_table_unlock(struct neigh_table *tbl)
+{
+ atomic_dec(&tbl->lock);
+}
+
+
+#endif
+#endif
+
+
diff --git a/pfinet/linux-src/include/net/netbeuicall.h b/pfinet/linux-src/include/net/netbeuicall.h
new file mode 100644
index 00000000..5176f82b
--- /dev/null
+++ b/pfinet/linux-src/include/net/netbeuicall.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void netbeui_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/include/net/netrom.h b/pfinet/linux-src/include/net/netrom.h
new file mode 100644
index 00000000..356a7d27
--- /dev/null
+++ b/pfinet/linux-src/include/net/netrom.h
@@ -0,0 +1,181 @@
+/*
+ * Declarations of NET/ROM type objects.
+ *
+ * Jonathan Naylor G4KLX 9/4/95
+ */
+
+#ifndef _NETROM_H
+#define _NETROM_H
+#include <linux/netrom.h>
+
+#define NR_NETWORK_LEN 15
+#define NR_TRANSPORT_LEN 5
+
+#define NR_PROTO_IP 0x0C
+
+#define NR_PROTOEXT 0x00
+#define NR_CONNREQ 0x01
+#define NR_CONNACK 0x02
+#define NR_DISCREQ 0x03
+#define NR_DISCACK 0x04
+#define NR_INFO 0x05
+#define NR_INFOACK 0x06
+
+#define NR_CHOKE_FLAG 0x80
+#define NR_NAK_FLAG 0x40
+#define NR_MORE_FLAG 0x20
+
+/* Define Link State constants. */
+enum {
+ NR_STATE_0,
+ NR_STATE_1,
+ NR_STATE_2,
+ NR_STATE_3
+};
+
+#define NR_COND_ACK_PENDING 0x01
+#define NR_COND_REJECT 0x02
+#define NR_COND_PEER_RX_BUSY 0x04
+#define NR_COND_OWN_RX_BUSY 0x08
+
+#define NR_DEFAULT_T1 (120 * HZ) /* Outstanding frames - 120 seconds */
+#define NR_DEFAULT_T2 (5 * HZ) /* Response delay - 5 seconds */
+#define NR_DEFAULT_N2 3 /* Number of Retries - 3 */
+#define NR_DEFAULT_T4 (180 * HZ) /* Busy Delay - 180 seconds */
+#define NR_DEFAULT_IDLE (0 * 60 * HZ) /* No Activity Timeout - none */
+#define NR_DEFAULT_WINDOW 4 /* Default Window Size - 4 */
+#define NR_DEFAULT_OBS 6 /* Default Obsolescence Count - 6 */
+#define NR_DEFAULT_QUAL 10 /* Default Neighbour Quality - 10 */
+#define NR_DEFAULT_TTL 16 /* Default Time To Live - 16 */
+#define NR_DEFAULT_ROUTING 1 /* Is routing enabled ? */
+#define NR_DEFAULT_FAILS 2 /* Link fails until route fails */
+
+#define NR_MODULUS 256
+#define NR_MAX_WINDOW_SIZE 127 /* Maximum Window Allowable - 127 */
+#define NR_MAX_PACKET_SIZE 236 /* Maximum Packet Length - 236 */
+
+typedef struct {
+ ax25_address user_addr, source_addr, dest_addr;
+ struct device *device;
+ unsigned char my_index, my_id;
+ unsigned char your_index, your_id;
+ unsigned char state, condition, bpqext, window;
+ unsigned short vs, vr, va, vl;
+ unsigned char n2, n2count;
+ unsigned long t1, t2, t4, idle;
+ unsigned short fraglen;
+ struct timer_list t1timer;
+ struct timer_list t2timer;
+ struct timer_list t4timer;
+ struct timer_list idletimer;
+ struct sk_buff_head ack_queue;
+ struct sk_buff_head reseq_queue;
+ struct sk_buff_head frag_queue;
+ struct sock *sk; /* Backlink to socket */
+} nr_cb;
+
+struct nr_neigh {
+ struct nr_neigh *next;
+ ax25_address callsign;
+ ax25_digi *digipeat;
+ ax25_cb *ax25;
+ struct device *dev;
+ unsigned char quality;
+ unsigned char locked;
+ unsigned short count;
+ unsigned int number;
+ unsigned char failed;
+};
+
+struct nr_route {
+ unsigned char quality;
+ unsigned char obs_count;
+ struct nr_neigh *neighbour;
+};
+
+struct nr_node {
+ struct nr_node *next;
+ ax25_address callsign;
+ char mnemonic[7];
+ unsigned char which;
+ unsigned char count;
+ struct nr_route routes[3];
+};
+
+/* af_netrom.c */
+extern int sysctl_netrom_default_path_quality;
+extern int sysctl_netrom_obsolescence_count_initialiser;
+extern int sysctl_netrom_network_ttl_initialiser;
+extern int sysctl_netrom_transport_timeout;
+extern int sysctl_netrom_transport_maximum_tries;
+extern int sysctl_netrom_transport_acknowledge_delay;
+extern int sysctl_netrom_transport_busy_delay;
+extern int sysctl_netrom_transport_requested_window_size;
+extern int sysctl_netrom_transport_no_activity_timeout;
+extern int sysctl_netrom_routing_control;
+extern int sysctl_netrom_link_fails_count;
+extern int nr_rx_frame(struct sk_buff *, struct device *);
+extern void nr_destroy_socket(struct sock *);
+
+/* nr_dev.c */
+extern int nr_rx_ip(struct sk_buff *, struct device *);
+extern int nr_init(struct device *);
+
+#include <net/nrcall.h>
+
+/* nr_in.c */
+extern int nr_process_rx_frame(struct sock *, struct sk_buff *);
+
+/* nr_loopback.c */
+extern void nr_loopback_init(void);
+extern void nr_loopback_clear(void);
+extern int nr_loopback_queue(struct sk_buff *);
+
+/* nr_out.c */
+extern void nr_output(struct sock *, struct sk_buff *);
+extern void nr_send_nak_frame(struct sock *);
+extern void nr_kick(struct sock *);
+extern void nr_transmit_buffer(struct sock *, struct sk_buff *);
+extern void nr_establish_data_link(struct sock *);
+extern void nr_enquiry_response(struct sock *);
+extern void nr_check_iframes_acked(struct sock *, unsigned short);
+
+/* nr_route.c */
+extern void nr_rt_device_down(struct device *);
+extern struct device *nr_dev_first(void);
+extern struct device *nr_dev_get(ax25_address *);
+extern int nr_rt_ioctl(unsigned int, void *);
+extern void nr_link_failed(ax25_cb *, int);
+extern int nr_route_frame(struct sk_buff *, ax25_cb *);
+extern int nr_nodes_get_info(char *, char **, off_t, int, int);
+extern int nr_neigh_get_info(char *, char **, off_t, int, int);
+extern void nr_rt_free(void);
+
+/* nr_subr.c */
+extern void nr_clear_queues(struct sock *);
+extern void nr_frames_acked(struct sock *, unsigned short);
+extern void nr_requeue_frames(struct sock *);
+extern int nr_validate_nr(struct sock *, unsigned short);
+extern int nr_in_rx_window(struct sock *, unsigned short);
+extern void nr_write_internal(struct sock *, int);
+extern void nr_transmit_refusal(struct sk_buff *, int);
+extern void nr_disconnect(struct sock *, int);
+
+/* nr_timer.c */
+extern void nr_start_heartbeat(struct sock *);
+extern void nr_start_t1timer(struct sock *);
+extern void nr_start_t2timer(struct sock *);
+extern void nr_start_t4timer(struct sock *);
+extern void nr_start_idletimer(struct sock *);
+extern void nr_stop_heartbeat(struct sock *);
+extern void nr_stop_t1timer(struct sock *);
+extern void nr_stop_t2timer(struct sock *);
+extern void nr_stop_t4timer(struct sock *);
+extern void nr_stop_idletimer(struct sock *);
+extern int nr_t1timer_running(struct sock *);
+
+/* sysctl_net_netrom.c */
+extern void nr_register_sysctl(void);
+extern void nr_unregister_sysctl(void);
+
+#endif
diff --git a/pfinet/linux-src/include/net/nrcall.h b/pfinet/linux-src/include/net/nrcall.h
new file mode 100644
index 00000000..09ee699d
--- /dev/null
+++ b/pfinet/linux-src/include/net/nrcall.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void nr_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/include/net/p8022.h b/pfinet/linux-src/include/net/p8022.h
new file mode 100644
index 00000000..03d7c3d6
--- /dev/null
+++ b/pfinet/linux-src/include/net/p8022.h
@@ -0,0 +1,7 @@
+#ifndef _NET_P8022_H
+#define _NET_P8022_H
+
+extern struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *));
+extern void unregister_8022_client(unsigned char type);
+
+#endif
diff --git a/pfinet/linux-inet/p8022call.h b/pfinet/linux-src/include/net/p8022call.h
index 14f0c2ce..14f0c2ce 100644
--- a/pfinet/linux-inet/p8022call.h
+++ b/pfinet/linux-src/include/net/p8022call.h
diff --git a/pfinet/linux-src/include/net/pkt_cls.h b/pfinet/linux-src/include/net/pkt_cls.h
new file mode 100644
index 00000000..b8547e60
--- /dev/null
+++ b/pfinet/linux-src/include/net/pkt_cls.h
@@ -0,0 +1,93 @@
+#ifndef __NET_PKT_CLS_H
+#define __NET_PKT_CLS_H
+
+
+#include <linux/pkt_cls.h>
+
+struct rtattr;
+struct tcmsg;
+
+/* Basic packet classifier frontend definitions. */
+
+struct tcf_result
+{
+ unsigned long class;
+ u32 classid;
+};
+
+struct tcf_proto
+{
+ /* Fast access part */
+ struct tcf_proto *next;
+ void *root;
+ int (*classify)(struct sk_buff*, struct tcf_proto*, struct tcf_result *);
+ u32 protocol;
+
+ /* All the rest */
+ u32 prio;
+ u32 classid;
+ struct Qdisc *q;
+ void *data;
+ struct tcf_proto_ops *ops;
+};
+
+struct tcf_walker
+{
+ int stop;
+ int skip;
+ int count;
+ int (*fn)(struct tcf_proto *, unsigned long node, struct tcf_walker *);
+};
+
+struct tcf_proto_ops
+{
+ struct tcf_proto_ops *next;
+ char kind[IFNAMSIZ];
+
+ int (*classify)(struct sk_buff*, struct tcf_proto*, struct tcf_result *);
+ int (*init)(struct tcf_proto*);
+ void (*destroy)(struct tcf_proto*);
+
+ unsigned long (*get)(struct tcf_proto*, u32 handle);
+ void (*put)(struct tcf_proto*, unsigned long);
+ int (*change)(struct tcf_proto*, unsigned long, u32 handle, struct rtattr **, unsigned long *);
+ int (*delete)(struct tcf_proto*, unsigned long);
+ void (*walk)(struct tcf_proto*, struct tcf_walker *arg);
+
+ /* rtnetlink specific */
+ int (*dump)(struct tcf_proto*, unsigned long, struct sk_buff *skb, struct tcmsg*);
+};
+
+/* Main classifier routine: scans classifier chain attached
+ to this qdisc, (optionally) tests for protocol and asks
+ specific classifiers.
+ */
+
+extern __inline__ int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res)
+{
+ int err = 0;
+ u32 protocol = skb->protocol;
+
+ for ( ; tp; tp = tp->next) {
+ if ((tp->protocol == protocol ||
+ tp->protocol == __constant_htons(ETH_P_ALL)) &&
+ (err = tp->classify(skb, tp, res)) >= 0)
+ return err;
+ }
+ return -1;
+}
+
+extern __inline__ unsigned long cls_set_class(unsigned long *clp, unsigned long cl)
+{
+ unsigned long old_cl;
+
+ old_cl = *clp;
+ *clp = cl;
+ synchronize_bh();
+ return old_cl;
+}
+
+extern int register_tcf_proto_ops(struct tcf_proto_ops *ops);
+extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
+
+#endif
diff --git a/pfinet/linux-src/include/net/pkt_sched.h b/pfinet/linux-src/include/net/pkt_sched.h
new file mode 100644
index 00000000..c2ef8656
--- /dev/null
+++ b/pfinet/linux-src/include/net/pkt_sched.h
@@ -0,0 +1,407 @@
+#ifndef __NET_PKT_SCHED_H
+#define __NET_PKT_SCHED_H
+
+#define PSCHED_GETTIMEOFDAY 1
+#define PSCHED_JIFFIES 2
+#define PSCHED_CPU 3
+
+#define PSCHED_CLOCK_SOURCE PSCHED_JIFFIES
+
+#include <linux/pkt_sched.h>
+#include <net/pkt_cls.h>
+
+struct rtattr;
+struct Qdisc;
+
+struct qdisc_walker
+{
+ int stop;
+ int skip;
+ int count;
+ int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *);
+};
+
+struct Qdisc_class_ops
+{
+ /* Child qdisc manipulation */
+ int (*graft)(struct Qdisc *, unsigned long cl, struct Qdisc *, struct Qdisc **);
+ struct Qdisc * (*leaf)(struct Qdisc *, unsigned long cl);
+
+ /* Class manipulation routines */
+ unsigned long (*get)(struct Qdisc *, u32 classid);
+ void (*put)(struct Qdisc *, unsigned long);
+ int (*change)(struct Qdisc *, u32, u32, struct rtattr **, unsigned long *);
+ int (*delete)(struct Qdisc *, unsigned long);
+ void (*walk)(struct Qdisc *, struct qdisc_walker * arg);
+
+ /* Filter manipulation */
+ struct tcf_proto ** (*tcf_chain)(struct Qdisc *, unsigned long);
+ unsigned long (*bind_tcf)(struct Qdisc *, unsigned long, u32 classid);
+ void (*unbind_tcf)(struct Qdisc *, unsigned long);
+
+ /* rtnetlink specific */
+ int (*dump)(struct Qdisc *, unsigned long, struct sk_buff *skb, struct tcmsg*);
+};
+
+struct Qdisc_ops
+{
+ struct Qdisc_ops *next;
+ struct Qdisc_class_ops *cl_ops;
+ char id[IFNAMSIZ];
+ int priv_size;
+
+ int (*enqueue)(struct sk_buff *, struct Qdisc *);
+ struct sk_buff * (*dequeue)(struct Qdisc *);
+ int (*requeue)(struct sk_buff *, struct Qdisc *);
+ int (*drop)(struct Qdisc *);
+
+ int (*init)(struct Qdisc *, struct rtattr *arg);
+ void (*reset)(struct Qdisc *);
+ void (*destroy)(struct Qdisc *);
+ int (*change)(struct Qdisc *, struct rtattr *arg);
+
+ int (*dump)(struct Qdisc *, struct sk_buff *);
+};
+
+struct Qdisc_head
+{
+ struct Qdisc_head *forw;
+};
+
+extern struct Qdisc_head qdisc_head;
+
+struct Qdisc
+{
+ struct Qdisc_head h;
+ int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
+ struct sk_buff * (*dequeue)(struct Qdisc *dev);
+ unsigned flags;
+#define TCQ_F_BUILTIN 1
+#define TCQ_F_THROTTLED 2
+ struct Qdisc_ops *ops;
+ struct Qdisc *next;
+ u32 handle;
+ atomic_t refcnt;
+ struct sk_buff_head q;
+ struct device *dev;
+
+ struct tc_stats stats;
+ unsigned long tx_timeo;
+ unsigned long tx_last;
+ int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q);
+
+ /* This field is deprecated, but it is still used by CBQ
+ * and it will live until better solution will be invented.
+ */
+ struct Qdisc *__parent;
+
+ char data[0];
+};
+
+struct qdisc_rate_table
+{
+ struct tc_ratespec rate;
+ u32 data[256];
+ struct qdisc_rate_table *next;
+ int refcnt;
+};
+
+
+/*
+ Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth
+
+ Normal IP packet size ~ 512byte, hence:
+
+ 0.5Kbyte/1Mbyte/sec = 0.5msec, so that we need 50usec timer for
+ 10Mbit ethernet.
+
+ 10msec resolution -> <50Kbit/sec.
+
+ The result: [34]86 is not good choice for QoS router :-(
+
+ The things are not so bad, because we may use artificial
+ clock evaluated by integration of network data flow
+ in the most critical places.
+
+ Note: we do not use fastgettimeofday.
+ The reason is that, when it is not the same thing as
+ gettimeofday, it returns invalid timestamp, which is
+ not updated, when net_bh is active.
+
+ So, use PSCHED_CLOCK_SOURCE = PSCHED_CPU on alpha and pentiums
+ with rtdsc. And PSCHED_JIFFIES on all other architectures, including [34]86
+ and pentiums without rtdsc.
+ You can use PSCHED_GETTIMEOFDAY on another architectures,
+ which have fast and precise clock source, but it is too expensive.
+ */
+
+/* General note about internal clock.
+
+ Any clock source returns time intervals, measured in units
+ close to 1usec. With source PSCHED_GETTIMEOFDAY it is precisely
+ microseconds, otherwise something close but different chosen to minimize
+ arithmetic cost. Ratio usec/internal untis in form nominator/denominator
+ may be read from /proc/net/psched.
+ */
+
+
+#if PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY
+
+typedef struct timeval psched_time_t;
+typedef long psched_tdiff_t;
+
+#define PSCHED_GET_TIME(stamp) do_gettimeofday(&(stamp))
+#define PSCHED_US2JIFFIE(usecs) (((usecs)+(1000000/HZ-1))/(1000000/HZ))
+
+#define PSCHED_EXPORTLIST EXPORT_SYMBOL(psched_tod_diff);
+
+#else /* PSCHED_CLOCK_SOURCE != PSCHED_GETTIMEOFDAY */
+
+#define PSCHED_EXPORTLIST PSCHED_EXPORTLIST_1 PSCHED_EXPORTLIST_2
+
+typedef u64 psched_time_t;
+typedef long psched_tdiff_t;
+
+extern psched_time_t psched_time_base;
+
+#if PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES
+
+#if HZ == 100
+#define PSCHED_JSCALE 13
+#elif HZ == 1024
+#define PSCHED_JSCALE 10
+#else
+#define PSCHED_JSCALE 0
+#endif
+
+#define PSCHED_EXPORTLIST_2
+
+#if ~0UL == 0xFFFFFFFF
+
+#define PSCHED_WATCHER unsigned long
+
+extern PSCHED_WATCHER psched_time_mark;
+
+#define PSCHED_GET_TIME(stamp) ((stamp) = psched_time_base + (((unsigned long)(jiffies-psched_time_mark))<<PSCHED_JSCALE))
+
+#define PSCHED_EXPORTLIST_1 EXPORT_SYMBOL(psched_time_base); \
+ EXPORT_SYMBOL(psched_time_mark);
+
+#else
+
+#define PSCHED_GET_TIME(stamp) ((stamp) = (jiffies<<PSCHED_JSCALE))
+
+#define PSCHED_EXPORTLIST_1
+
+#endif
+
+#define PSCHED_US2JIFFIE(delay) (((delay)+(1<<PSCHED_JSCALE)-1)>>PSCHED_JSCALE)
+
+#elif PSCHED_CLOCK_SOURCE == PSCHED_CPU
+
+extern psched_tdiff_t psched_clock_per_hz;
+extern int psched_clock_scale;
+
+#define PSCHED_EXPORTLIST_2 EXPORT_SYMBOL(psched_clock_per_hz); \
+ EXPORT_SYMBOL(psched_clock_scale);
+
+#define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz)
+
+#if CPU == 586 || CPU == 686
+
+#define PSCHED_GET_TIME(stamp) \
+({ u64 __cur; \
+ __asm__ __volatile__ (".byte 0x0f,0x31" :"=A" (__cur)); \
+ (stamp) = __cur>>psched_clock_scale; \
+})
+
+#define PSCHED_EXPORTLIST_1
+
+#elif defined (__alpha__)
+
+#define PSCHED_WATCHER u32
+
+extern PSCHED_WATCHER psched_time_mark;
+
+#define PSCHED_GET_TIME(stamp) \
+({ u32 __res; \
+ __asm__ __volatile__ ("rpcc %0" : "r="(__res)); \
+ if (__res <= psched_time_mark) psched_time_base += 0x100000000UL; \
+ psched_time_mark = __res; \
+ (stamp) = (psched_time_base + __res)>>psched_clock_scale; \
+})
+
+#define PSCHED_EXPORTLIST_1 EXPORT_SYMBOL(psched_time_base); \
+ EXPORT_SYMBOL(psched_time_mark);
+
+#else
+
+#error PSCHED_CLOCK_SOURCE=PSCHED_CPU is not supported on this arch.
+
+#endif /* ARCH */
+
+#endif /* PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES */
+
+#endif /* PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY */
+
+#if PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY
+#define PSCHED_TDIFF(tv1, tv2) \
+({ \
+ int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \
+ int __delta = (tv1).tv_usec - (tv2).tv_usec; \
+ if (__delta_sec) { \
+ switch (__delta_sec) { \
+ default: \
+ __delta = 0; \
+ case 2: \
+ __delta += 1000000; \
+ case 1: \
+ __delta += 1000000; \
+ } \
+ } \
+ __delta; \
+})
+
+extern int psched_tod_diff(int delta_sec, int bound);
+
+#define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \
+({ \
+ int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \
+ int __delta = (tv1).tv_usec - (tv2).tv_usec; \
+ switch (__delta_sec) { \
+ default: \
+ __delta = psched_tod_diff(__delta_sec, bound); guard; break; \
+ case 2: \
+ __delta += 1000000; \
+ case 1: \
+ __delta += 1000000; \
+ case 0: ; \
+ } \
+ __delta; \
+})
+
+#define PSCHED_TLESS(tv1, tv2) (((tv1).tv_usec < (tv2).tv_usec && \
+ (tv1).tv_sec <= (tv2).tv_sec) || \
+ (tv1).tv_sec < (tv2).tv_sec)
+
+#define PSCHED_TADD2(tv, delta, tv_res) \
+({ \
+ int __delta = (tv).tv_usec + (delta); \
+ (tv_res).tv_sec = (tv).tv_sec; \
+ if (__delta > 1000000) { (tv_res).tv_sec++; __delta -= 1000000; } \
+ (tv_res).tv_usec = __delta; \
+})
+
+#define PSCHED_TADD(tv, delta) \
+({ \
+ (tv).tv_usec += (delta); \
+ if ((tv).tv_usec > 1000000) { (tv).tv_sec++; \
+ (tv).tv_usec -= 1000000; } \
+})
+
+/* Set/check that time is in the "past perfect";
+ it depends on concrete representation of system time
+ */
+
+#define PSCHED_SET_PASTPERFECT(t) ((t).tv_sec = 0)
+#define PSCHED_IS_PASTPERFECT(t) ((t).tv_sec == 0)
+
+#define PSCHED_AUDIT_TDIFF(t) ({ if ((t) > 2000000) (t) = 2000000; })
+
+#else
+
+#define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2))
+#define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \
+({ \
+ long __delta = (tv1) - (tv2); \
+ if ( __delta > (bound)) { __delta = (bound); guard; } \
+ __delta; \
+})
+
+
+#define PSCHED_TLESS(tv1, tv2) ((tv1) < (tv2))
+#define PSCHED_TADD2(tv, delta, tv_res) ((tv_res) = (tv) + (delta))
+#define PSCHED_TADD(tv, delta) ((tv) += (delta))
+#define PSCHED_SET_PASTPERFECT(t) ((t) = 0)
+#define PSCHED_IS_PASTPERFECT(t) ((t) == 0)
+#define PSCHED_AUDIT_TDIFF(t)
+
+#endif
+
+struct tcf_police
+{
+ struct tcf_police *next;
+ int refcnt;
+ u32 index;
+
+ int action;
+ int result;
+ u32 ewma_rate;
+ u32 burst;
+ u32 mtu;
+
+ u32 toks;
+ u32 ptoks;
+ psched_time_t t_c;
+ struct qdisc_rate_table *R_tab;
+ struct qdisc_rate_table *P_tab;
+
+ struct tc_stats stats;
+};
+
+extern void tcf_police_destroy(struct tcf_police *p);
+extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est);
+extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p);
+extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
+
+extern __inline__ void tcf_police_release(struct tcf_police *p)
+{
+ if (p && --p->refcnt == 0)
+ tcf_police_destroy(p);
+}
+
+extern struct Qdisc noop_qdisc;
+extern struct Qdisc_ops noop_qdisc_ops;
+extern struct Qdisc_ops pfifo_qdisc_ops;
+extern struct Qdisc_ops bfifo_qdisc_ops;
+
+int register_qdisc(struct Qdisc_ops *qops);
+int unregister_qdisc(struct Qdisc_ops *qops);
+struct Qdisc *qdisc_lookup(struct device *dev, u32 handle);
+struct Qdisc *qdisc_lookup_class(struct device *dev, u32 handle);
+void dev_init_scheduler(struct device *dev);
+void dev_shutdown(struct device *dev);
+void dev_activate(struct device *dev);
+void dev_deactivate(struct device *dev);
+void qdisc_reset(struct Qdisc *qdisc);
+void qdisc_destroy(struct Qdisc *qdisc);
+struct Qdisc * qdisc_create_dflt(struct device *dev, struct Qdisc_ops *ops);
+int qdisc_new_estimator(struct tc_stats *stats, struct rtattr *opt);
+void qdisc_kill_estimator(struct tc_stats *stats);
+struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab);
+void qdisc_put_rtab(struct qdisc_rate_table *tab);
+int teql_init(void);
+int tc_filter_init(void);
+int pktsched_init(void);
+
+void qdisc_run_queues(void);
+int qdisc_restart(struct device *dev);
+
+extern __inline__ void qdisc_wakeup(struct device *dev)
+{
+ if (!dev->tbusy) {
+ struct Qdisc *q = dev->qdisc;
+ if (qdisc_restart(dev) && q->h.forw == NULL) {
+ q->h.forw = qdisc_head.forw;
+ qdisc_head.forw = &q->h;
+ }
+ }
+}
+
+extern __inline__ unsigned psched_mtu(struct device *dev)
+{
+ unsigned mtu = dev->mtu;
+ return dev->hard_header ? mtu + dev->hard_header_len : mtu;
+}
+
+#endif
diff --git a/pfinet/linux-src/include/net/profile.h b/pfinet/linux-src/include/net/profile.h
new file mode 100644
index 00000000..82fad0a3
--- /dev/null
+++ b/pfinet/linux-src/include/net/profile.h
@@ -0,0 +1,311 @@
+#include <linux/config.h> /* for CONFIG_NET_PROFILE */
+#ifndef _NET_PROFILE_H_
+#define _NET_PROFILE_H_ 1
+
+#ifdef CONFIG_NET_PROFILE
+
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+struct net_profile_slot
+{
+ char id[16];
+ struct net_profile_slot *next;
+ struct timeval entered;
+ struct timeval accumulator;
+ struct timeval irq;
+ int hits;
+ int active;
+ int underflow;
+};
+
+extern atomic_t net_profile_active;
+extern struct timeval net_profile_adjust;
+extern void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved);
+
+#if CPU == 586 || CPU == 686
+
+
+extern __inline__ void net_profile_stamp(struct timeval *pstamp)
+{
+ __asm__ __volatile__ (".byte 0x0f,0x31"
+ :"=a" (pstamp->tv_usec),
+ "=d" (pstamp->tv_sec));
+}
+
+extern __inline__ void net_profile_accumulate(struct timeval *entered,
+ struct timeval *leaved,
+ struct timeval *acc)
+{
+ __asm__ __volatile__ ("subl %2,%0\n\t"
+ "sbbl %3,%1\n\t"
+ "addl %4,%0\n\t"
+ "adcl %5,%1\n\t"
+ "subl " SYMBOL_NAME_STR(net_profile_adjust) "+4,%0\n\t"
+ "sbbl $0,%1\n\t"
+ : "=r" (acc->tv_usec), "=r" (acc->tv_sec)
+ : "g" (entered->tv_usec), "g" (entered->tv_sec),
+ "g" (leaved->tv_usec), "g" (leaved->tv_sec),
+ "0" (acc->tv_usec), "1" (acc->tv_sec));
+}
+
+extern __inline__ void net_profile_sub(struct timeval *sub,
+ struct timeval *acc)
+{
+ __asm__ __volatile__ ("subl %2,%0\n\t"
+ "sbbl %3,%1\n\t"
+ : "=r" (acc->tv_usec), "=r" (acc->tv_sec)
+ : "g" (sub->tv_usec), "g" (sub->tv_sec),
+ "0" (acc->tv_usec), "1" (acc->tv_sec));
+}
+
+extern __inline__ void net_profile_add(struct timeval *add,
+ struct timeval *acc)
+{
+ __asm__ __volatile__ ("addl %2,%0\n\t"
+ "adcl %3,%1\n\t"
+ : "=r" (acc->tv_usec), "=r" (acc->tv_sec)
+ : "g" (add->tv_usec), "g" (add->tv_sec),
+ "0" (acc->tv_usec), "1" (acc->tv_sec));
+}
+
+
+#elif defined (__alpha__)
+
+extern __u32 alpha_lo;
+extern long alpha_hi;
+
+/* On alpha cycle counter has only 32 bits :-( :-( */
+
+extern __inline__ void net_profile_stamp(struct timeval *pstamp)
+{
+ __u32 result;
+ __asm__ __volatile__ ("rpcc %0" : "r="(result));
+ if (result <= alpha_lo)
+ alpha_hi++;
+ alpha_lo = result;
+ pstamp->tv_sec = alpha_hi;
+ pstamp->tv_usec = alpha_lo;
+}
+
+extern __inline__ void net_profile_accumulate(struct timeval *entered,
+ struct timeval *leaved,
+ struct timeval *acc)
+{
+ time_t usecs = acc->tv_usec + leaved->tv_usec - entered->tv_usec
+ - net_profile_adjust.tv_usec;
+ time_t secs = acc->tv_sec + leaved->tv_sec - entered->tv_sec;
+
+ if (usecs >= 0x100000000L) {
+ usecs -= 0x100000000L;
+ secs++;
+ } else if (usecs < -0x100000000L) {
+ usecs += 0x200000000L;
+ secs -= 2;
+ } else if (usecs < 0) {
+ usecs += 0x100000000L;
+ secs--;
+ }
+ acc->tv_sec = secs;
+ acc->tv_usec = usecs;
+}
+
+extern __inline__ void net_profile_sub(struct timeval *entered,
+ struct timeval *leaved)
+{
+ time_t usecs = leaved->tv_usec - entered->tv_usec;
+ time_t secs = leaved->tv_sec - entered->tv_sec;
+
+ if (usecs < 0) {
+ usecs += 0x100000000L;
+ secs--;
+ }
+ leaved->tv_sec = secs;
+ leaved->tv_usec = usecs;
+}
+
+extern __inline__ void net_profile_add(struct timeval *entered, struct timeval *leaved)
+{
+ time_t usecs = leaved->tv_usec + entered->tv_usec;
+ time_t secs = leaved->tv_sec + entered->tv_sec;
+
+ if (usecs >= 0x100000000L) {
+ usecs -= 0x100000000L;
+ secs++;
+ }
+ leaved->tv_sec = secs;
+ leaved->tv_usec = usecs;
+}
+
+
+#else
+
+extern __inline__ void net_profile_stamp(struct timeval *pstamp)
+{
+ /* Not "fast" counterpart! On architectures without
+ cpu clock "fast" routine is absolutely useless in this
+ situation. do_gettimeofday still says something on slow-slow-slow
+ boxes, though it eats more cpu time than the sobject of
+ investigation :-) :-)
+ */
+ do_gettimeofday(pstamp);
+}
+
+extern __inline__ void net_profile_accumulate(struct timeval *entered,
+ struct timeval *leaved,
+ struct timeval *acc)
+{
+ time_t usecs = acc->tv_usec + leaved->tv_usec - entered->tv_usec
+ - net_profile_adjust.tv_usec;
+ time_t secs = acc->tv_sec + leaved->tv_sec - entered->tv_sec;
+
+ if (usecs >= 1000000) {
+ usecs -= 1000000;
+ secs++;
+ } else if (usecs < -1000000) {
+ usecs += 2000000;
+ secs -= 2;
+ } else if (usecs < 0) {
+ usecs += 1000000;
+ secs--;
+ }
+ acc->tv_sec = secs;
+ acc->tv_usec = usecs;
+}
+
+extern __inline__ void net_profile_sub(struct timeval *entered,
+ struct timeval *leaved)
+{
+ time_t usecs = leaved->tv_usec - entered->tv_usec;
+ time_t secs = leaved->tv_sec - entered->tv_sec;
+
+ if (usecs < 0) {
+ usecs += 1000000;
+ secs--;
+ }
+ leaved->tv_sec = secs;
+ leaved->tv_usec = usecs;
+}
+
+extern __inline__ void net_profile_add(struct timeval *entered, struct timeval *leaved)
+{
+ time_t usecs = leaved->tv_usec + entered->tv_usec;
+ time_t secs = leaved->tv_sec + entered->tv_sec;
+
+ if (usecs >= 1000000) {
+ usecs -= 1000000;
+ secs++;
+ }
+ leaved->tv_sec = secs;
+ leaved->tv_usec = usecs;
+}
+
+
+
+#endif
+
+extern __inline__ void net_profile_enter(struct net_profile_slot *s)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (s->active++ == 0) {
+ net_profile_stamp(&s->entered);
+ atomic_inc(&net_profile_active);
+ }
+ restore_flags(flags);
+}
+
+extern __inline__ void net_profile_leave_irq(struct net_profile_slot *s)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (--s->active <= 0) {
+ if (s->active == 0) {
+ struct timeval curr_pstamp;
+ net_profile_stamp(&curr_pstamp);
+ net_profile_accumulate(&s->entered, &curr_pstamp, &s->accumulator);
+ if (!atomic_dec_and_test(&net_profile_active))
+ net_profile_irq_adjust(&s->entered, &curr_pstamp);
+ } else {
+ s->underflow++;
+ }
+ }
+ s->hits++;
+ restore_flags(flags);
+}
+
+extern __inline__ void net_profile_leave(struct net_profile_slot *s)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ if (--s->active <= 0) {
+ if (s->active == 0) {
+ struct timeval curr_pstamp;
+ net_profile_stamp(&curr_pstamp);
+ net_profile_accumulate(&s->entered, &curr_pstamp, &s->accumulator);
+ atomic_dec(&net_profile_active);
+ } else {
+ s->underflow++;
+ }
+ }
+ s->hits++;
+ restore_flags(flags);
+}
+
+
+#define NET_PROFILE_ENTER(slot) net_profile_enter(&net_prof_##slot)
+#define NET_PROFILE_LEAVE(slot) net_profile_leave(&net_prof_##slot)
+#define NET_PROFILE_LEAVE_IRQ(slot) net_profile_leave_irq(&net_prof_##slot)
+
+#define NET_PROFILE_SKB_CLEAR(skb) ({ \
+ skb->pstamp.tv_usec = 0; \
+})
+
+#define NET_PROFILE_SKB_INIT(skb) ({ \
+ net_profile_stamp(&skb->pstamp); \
+})
+
+#define NET_PROFILE_SKB_PASSED(skb, slot) ({ \
+ if (skb->pstamp.tv_usec) { \
+ struct timeval cur_pstamp = skb->pstamp; \
+ net_profile_stamp(&skb->pstamp); \
+ net_profile_accumulate(&cur_pstamp, &skb->pstamp, &net_prof_##slot.accumulator); \
+ net_prof_##slot.hits++; \
+ }})
+
+#define NET_PROFILE_DECL(slot) \
+ extern struct net_profile_slot net_prof_##slot;
+
+#define NET_PROFILE_DEFINE(slot) \
+ struct net_profile_slot net_prof_##slot = { #slot, };
+
+#define NET_PROFILE_REGISTER(slot) net_profile_register(&net_prof_##slot)
+#define NET_PROFILE_UNREGISTER(slot) net_profile_unregister(&net_prof_##slot)
+
+extern int net_profile_init(void);
+extern int net_profile_register(struct net_profile_slot *);
+extern int net_profile_unregister(struct net_profile_slot *);
+
+#else
+
+#define NET_PROFILE_ENTER(slot) do { /* nothing */ } while(0)
+#define NET_PROFILE_LEAVE(slot) do { /* nothing */ } while(0)
+#define NET_PROFILE_LEAVE_IRQ(slot) do { /* nothing */ } while(0)
+#define NET_PROFILE_SKB_CLEAR(skb) do { /* nothing */ } while(0)
+#define NET_PROFILE_SKB_INIT(skb) do { /* nothing */ } while(0)
+#define NET_PROFILE_SKB_PASSED(skb, slot) do { /* nothing */ } while(0)
+#define NET_PROFILE_DECL(slot)
+#define NET_PROFILE_DEFINE(slot)
+#define NET_PROFILE_REGISTER(slot) do { /* nothing */ } while(0)
+#define NET_PROFILE_UNREGISTER(slot) do { /* nothing */ } while(0)
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/net/protocol.h b/pfinet/linux-src/include/net/protocol.h
new file mode 100644
index 00000000..f6e947b1
--- /dev/null
+++ b/pfinet/linux-src/include/net/protocol.h
@@ -0,0 +1,82 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the protocol dispatcher.
+ *
+ * Version: @(#)protocol.h 1.0.2 05/07/93
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ * Alan Cox : Added a name field and a frag handler
+ * field for later.
+ * Alan Cox : Cleaned up, and sorted types.
+ * Pedro Roque : inet6 protocols
+ */
+
+#ifndef _PROTOCOL_H
+#define _PROTOCOL_H
+
+#include <linux/config.h>
+#include <linux/in6.h>
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+#include <linux/ipv6.h>
+#endif
+
+#define MAX_INET_PROTOS 32 /* Must be a power of 2 */
+
+
+/* This is used to register protocols. */
+struct inet_protocol
+{
+ int (*handler)(struct sk_buff *skb, unsigned short len);
+ void (*err_handler)(struct sk_buff *skb, unsigned char *dp, int len);
+ struct inet_protocol *next;
+ unsigned char protocol;
+ unsigned char copy:1;
+ void *data;
+ const char *name;
+};
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+struct inet6_protocol
+{
+ int (*handler)(struct sk_buff *skb,
+ unsigned long len);
+
+ void (*err_handler)(struct sk_buff *skb, struct ipv6hdr *hdr,
+ struct inet6_skb_parm *opt,
+ int type, int code, unsigned char *buff,
+ __u32 info);
+ struct inet6_protocol *next;
+ unsigned char protocol;
+ unsigned char copy:1;
+ void *data;
+ const char *name;
+};
+#endif
+
+extern struct inet_protocol *inet_protocol_base;
+extern struct inet_protocol *inet_protos[MAX_INET_PROTOS];
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+extern struct inet6_protocol *inet6_protocol_base;
+extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
+#endif
+
+extern void inet_add_protocol(struct inet_protocol *prot);
+extern int inet_del_protocol(struct inet_protocol *prot);
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+extern void inet6_add_protocol(struct inet6_protocol *prot);
+extern int inet6_del_protocol(struct inet6_protocol *prot);
+#endif
+
+#endif /* _PROTOCOL_H */
diff --git a/pfinet/linux-src/include/net/psnap.h b/pfinet/linux-src/include/net/psnap.h
new file mode 100644
index 00000000..49a68f7e
--- /dev/null
+++ b/pfinet/linux-src/include/net/psnap.h
@@ -0,0 +1,7 @@
+#ifndef _NET_PSNAP_H
+#define _NET_PSNAP_H
+
+extern struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *));
+extern void unregister_snap_client(unsigned char *desc);
+
+#endif
diff --git a/pfinet/linux-inet/psnapcall.h b/pfinet/linux-src/include/net/psnapcall.h
index 9da5763c..9da5763c 100644
--- a/pfinet/linux-inet/psnapcall.h
+++ b/pfinet/linux-src/include/net/psnapcall.h
diff --git a/pfinet/linux-inet/rarp.h b/pfinet/linux-src/include/net/rarp.h
index 02ee7784..7bfb08ef 100644
--- a/pfinet/linux-inet/rarp.h
+++ b/pfinet/linux-src/include/net/rarp.h
@@ -3,12 +3,10 @@
#define _RARP_H
extern int rarp_ioctl(unsigned int cmd, void *arg);
-extern int rarp_rcv(struct sk_buff *skb,
- struct device *dev,
- struct packet_type *pt);
extern int rarp_get_info(char *buffer,
char **start,
off_t offset,
- int length);
+ int length,
+ int dummy);
#endif /* _RARP_H */
diff --git a/pfinet/linux-inet/raw.h b/pfinet/linux-src/include/net/raw.h
index 8f1cf0c2..4d2e6e98 100644
--- a/pfinet/linux-inet/raw.h
+++ b/pfinet/linux-src/include/net/raw.h
@@ -21,14 +21,18 @@
extern struct proto raw_prot;
-extern void raw_err(int err, unsigned char *header, unsigned long daddr,
- unsigned long saddr, struct inet_protocol *protocol);
-extern int raw_recvfrom(struct sock *sk, unsigned char *to,
- int len, int noblock, unsigned flags,
- struct sockaddr_in *sin, int *addr_len);
-extern int raw_read(struct sock *sk, unsigned char *buff,
- int len, int noblock, unsigned flags);
-extern int raw_rcv(struct sock *, struct sk_buff *, struct device *,
- long, long);
+extern void raw_err(struct sock *, struct sk_buff *);
+extern int raw_rcv(struct sock *, struct sk_buff *);
+
+/* Note: v4 ICMP wants to get at this stuff, if you change the
+ * hashing mechanism, make sure you update icmp.c as well.
+ */
+#define RAWV4_HTABLE_SIZE MAX_INET_PROTOS
+extern struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
+
+
+extern struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
+ unsigned long raddr, unsigned long laddr,
+ int dif);
#endif /* _RAW_H */
diff --git a/pfinet/linux-src/include/net/rawv6.h b/pfinet/linux-src/include/net/rawv6.h
new file mode 100644
index 00000000..d54572d1
--- /dev/null
+++ b/pfinet/linux-src/include/net/rawv6.h
@@ -0,0 +1,27 @@
+#ifndef _NET_RAWV6_H
+#define _NET_RAWV6_H
+
+#ifdef __KERNEL__
+
+#define RAWV6_HTABLE_SIZE MAX_INET_PROTOS
+extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
+
+
+extern struct sock *raw_v6_lookup(struct sock *sk, unsigned short num,
+ struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
+
+extern int rawv6_rcv(struct sock *sk,
+ struct sk_buff *skb,
+ unsigned long len);
+
+
+extern void rawv6_err(struct sock *sk,
+ struct sk_buff *skb,
+ struct ipv6hdr *hdr,
+ struct inet6_skb_parm *opt,
+ int type, int code,
+ unsigned char *buff, u32 info);
+
+#endif
+
+#endif
diff --git a/pfinet/linux-src/include/net/rose.h b/pfinet/linux-src/include/net/rose.h
new file mode 100644
index 00000000..1c8684d2
--- /dev/null
+++ b/pfinet/linux-src/include/net/rose.h
@@ -0,0 +1,241 @@
+/*
+ * Declarations of Rose type objects.
+ *
+ * Jonathan Naylor G4KLX 25/8/96
+ */
+
+#ifndef _ROSE_H
+#define _ROSE_H
+#include <linux/rose.h>
+
+#define ROSE_ADDR_LEN 5
+
+#define ROSE_MIN_LEN 3
+
+#define ROSE_GFI 0x10
+#define ROSE_Q_BIT 0x80
+#define ROSE_D_BIT 0x40
+#define ROSE_M_BIT 0x10
+
+#define ROSE_CALL_REQUEST 0x0B
+#define ROSE_CALL_ACCEPTED 0x0F
+#define ROSE_CLEAR_REQUEST 0x13
+#define ROSE_CLEAR_CONFIRMATION 0x17
+#define ROSE_DATA 0x00
+#define ROSE_INTERRUPT 0x23
+#define ROSE_INTERRUPT_CONFIRMATION 0x27
+#define ROSE_RR 0x01
+#define ROSE_RNR 0x05
+#define ROSE_REJ 0x09
+#define ROSE_RESET_REQUEST 0x1B
+#define ROSE_RESET_CONFIRMATION 0x1F
+#define ROSE_REGISTRATION_REQUEST 0xF3
+#define ROSE_REGISTRATION_CONFIRMATION 0xF7
+#define ROSE_RESTART_REQUEST 0xFB
+#define ROSE_RESTART_CONFIRMATION 0xFF
+#define ROSE_DIAGNOSTIC 0xF1
+#define ROSE_ILLEGAL 0xFD
+
+/* Define Link State constants. */
+
+enum {
+ ROSE_STATE_0, /* Ready */
+ ROSE_STATE_1, /* Awaiting Call Accepted */
+ ROSE_STATE_2, /* Awaiting Clear Confirmation */
+ ROSE_STATE_3, /* Data Transfer */
+ ROSE_STATE_4, /* Awaiting Reset Confirmation */
+ ROSE_STATE_5 /* Deferred Call Acceptance */
+};
+
+#define ROSE_DEFAULT_T0 (180 * HZ) /* Default T10 T20 value */
+#define ROSE_DEFAULT_T1 (200 * HZ) /* Default T11 T21 value */
+#define ROSE_DEFAULT_T2 (180 * HZ) /* Default T12 T22 value */
+#define ROSE_DEFAULT_T3 (180 * HZ) /* Default T13 T23 value */
+#define ROSE_DEFAULT_HB (5 * HZ) /* Default Holdback value */
+#define ROSE_DEFAULT_IDLE (0 * 60 * HZ) /* No Activity Timeout - none */
+#define ROSE_DEFAULT_ROUTING 1 /* Default routing flag */
+#define ROSE_DEFAULT_FAIL_TIMEOUT (120 * HZ) /* Time until link considered usable */
+#define ROSE_DEFAULT_MAXVC 50 /* Maximum number of VCs per neighbour */
+#define ROSE_DEFAULT_WINDOW_SIZE 7 /* Default window size */
+
+#define ROSE_MODULUS 8
+#define ROSE_MAX_PACKET_SIZE 251 /* Maximum packet size */
+
+#define ROSE_COND_ACK_PENDING 0x01
+#define ROSE_COND_PEER_RX_BUSY 0x02
+#define ROSE_COND_OWN_RX_BUSY 0x04
+
+#define FAC_NATIONAL 0x00
+#define FAC_CCITT 0x0F
+
+#define FAC_NATIONAL_RAND 0x7F
+#define FAC_NATIONAL_FLAGS 0x3F
+#define FAC_NATIONAL_DEST_DIGI 0xE9
+#define FAC_NATIONAL_SRC_DIGI 0xEB
+#define FAC_NATIONAL_FAIL_CALL 0xED
+#define FAC_NATIONAL_FAIL_ADD 0xEE
+#define FAC_NATIONAL_DIGIS 0xEF
+
+#define FAC_CCITT_DEST_NSAP 0xC9
+#define FAC_CCITT_SRC_NSAP 0xCB
+
+struct rose_neigh {
+ struct rose_neigh *next;
+ ax25_address callsign;
+ ax25_digi *digipeat;
+ ax25_cb *ax25;
+ struct device *dev;
+ unsigned short count;
+ unsigned short use;
+ unsigned int number;
+ char restarted;
+ char dce_mode;
+ char loopback;
+ struct sk_buff_head queue;
+ struct timer_list t0timer;
+ struct timer_list ftimer;
+};
+
+struct rose_node {
+ struct rose_node *next;
+ rose_address address;
+ unsigned short mask;
+ unsigned char count;
+ char loopback;
+ struct rose_neigh *neighbour[3];
+};
+
+struct rose_route {
+ struct rose_route *next;
+ unsigned int lci1, lci2;
+ rose_address src_addr, dest_addr;
+ ax25_address src_call, dest_call;
+ struct rose_neigh *neigh1, *neigh2;
+ unsigned int rand;
+};
+
+typedef struct {
+ rose_address source_addr, dest_addr;
+ ax25_address source_call, dest_call;
+ unsigned char source_ndigis, dest_ndigis;
+ ax25_address source_digis[ROSE_MAX_DIGIS];
+ ax25_address dest_digis[ROSE_MAX_DIGIS];
+ struct rose_neigh *neighbour;
+ struct device *device;
+ unsigned int lci, rand;
+ unsigned char state, condition, qbitincl, defer;
+ unsigned char cause, diagnostic;
+ unsigned short vs, vr, va, vl;
+ unsigned long t1, t2, t3, hb, idle;
+#ifdef M_BIT
+ unsigned short fraglen;
+ struct sk_buff_head frag_queue;
+#endif
+ struct sk_buff_head ack_queue;
+ struct rose_facilities_struct facilities;
+ struct timer_list timer;
+ struct timer_list idletimer;
+ struct sock *sk; /* Backlink to socket */
+} rose_cb;
+
+/* af_rose.c */
+extern ax25_address rose_callsign;
+extern int sysctl_rose_restart_request_timeout;
+extern int sysctl_rose_call_request_timeout;
+extern int sysctl_rose_reset_request_timeout;
+extern int sysctl_rose_clear_request_timeout;
+extern int sysctl_rose_no_activity_timeout;
+extern int sysctl_rose_ack_hold_back_timeout;
+extern int sysctl_rose_routing_control;
+extern int sysctl_rose_link_fail_timeout;
+extern int sysctl_rose_maximum_vcs;
+extern int sysctl_rose_window_size;
+extern int rosecmp(rose_address *, rose_address *);
+extern int rosecmpm(rose_address *, rose_address *, unsigned short);
+extern char *rose2asc(rose_address *);
+extern struct sock *rose_find_socket(unsigned int, struct rose_neigh *);
+extern void rose_kill_by_neigh(struct rose_neigh *);
+extern unsigned int rose_new_lci(struct rose_neigh *);
+extern int rose_rx_call_request(struct sk_buff *, struct device *, struct rose_neigh *, unsigned int);
+extern void rose_destroy_socket(struct sock *);
+
+/* rose_dev.c */
+extern int rose_rx_ip(struct sk_buff *, struct device *);
+extern int rose_init(struct device *);
+
+#include <net/rosecall.h>
+
+/* rose_in.c */
+extern int rose_process_rx_frame(struct sock *, struct sk_buff *);
+
+/* rose_link.c */
+extern void rose_start_ftimer(struct rose_neigh *);
+extern void rose_start_t0timer(struct rose_neigh *);
+extern void rose_stop_ftimer(struct rose_neigh *);
+extern void rose_stop_t0timer(struct rose_neigh *);
+extern int rose_ftimer_running(struct rose_neigh *);
+extern int rose_t0timer_running(struct rose_neigh *);
+extern void rose_link_rx_restart(struct sk_buff *, struct rose_neigh *, unsigned short);
+extern void rose_transmit_restart_request(struct rose_neigh *);
+extern void rose_transmit_restart_confirmation(struct rose_neigh *);
+extern void rose_transmit_diagnostic(struct rose_neigh *, unsigned char);
+extern void rose_transmit_clear_request(struct rose_neigh *, unsigned int, unsigned char, unsigned char);
+extern void rose_transmit_link(struct sk_buff *, struct rose_neigh *);
+
+/* rose_loopback.c */
+extern void rose_loopback_init(void);
+extern void rose_loopback_clear(void);
+extern int rose_loopback_queue(struct sk_buff *, struct rose_neigh *);
+
+/* rose_out.c */
+extern void rose_kick(struct sock *);
+extern void rose_enquiry_response(struct sock *);
+
+/* rose_route.c */
+extern struct rose_neigh *rose_loopback_neigh;
+
+extern int rose_add_loopback_neigh(void);
+extern int rose_add_loopback_node(rose_address *);
+extern void rose_del_loopback_node(rose_address *);
+extern void rose_rt_device_down(struct device *);
+extern void rose_link_device_down(struct device *);
+extern struct device *rose_dev_first(void);
+extern struct device *rose_dev_get(rose_address *);
+extern struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *);
+extern struct device *rose_ax25_dev_get(char *);
+extern struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsigned char *);
+extern int rose_rt_ioctl(unsigned int, void *);
+extern void rose_link_failed(ax25_cb *, int);
+extern int rose_route_frame(struct sk_buff *, ax25_cb *);
+extern int rose_nodes_get_info(char *, char **, off_t, int, int);
+extern int rose_neigh_get_info(char *, char **, off_t, int, int);
+extern int rose_routes_get_info(char *, char **, off_t, int, int);
+extern void rose_rt_free(void);
+
+/* rose_subr.c */
+extern void rose_clear_queues(struct sock *);
+extern void rose_frames_acked(struct sock *, unsigned short);
+extern void rose_requeue_frames(struct sock *);
+extern int rose_validate_nr(struct sock *, unsigned short);
+extern void rose_write_internal(struct sock *, int);
+extern int rose_decode(struct sk_buff *, int *, int *, int *, int *, int *);
+extern int rose_parse_facilities(unsigned char *, struct rose_facilities_struct *);
+extern int rose_create_facilities(unsigned char *, rose_cb *);
+extern void rose_disconnect(struct sock *, int, int, int);
+
+/* rose_timer.c */
+extern void rose_start_heartbeat(struct sock *);
+extern void rose_start_t1timer(struct sock *);
+extern void rose_start_t2timer(struct sock *);
+extern void rose_start_t3timer(struct sock *);
+extern void rose_start_hbtimer(struct sock *);
+extern void rose_start_idletimer(struct sock *);
+extern void rose_stop_heartbeat(struct sock *);
+extern void rose_stop_timer(struct sock *);
+extern void rose_stop_idletimer(struct sock *);
+
+/* sysctl_net_rose.c */
+extern void rose_register_sysctl(void);
+extern void rose_unregister_sysctl(void);
+
+#endif
diff --git a/pfinet/linux-src/include/net/rosecall.h b/pfinet/linux-src/include/net/rosecall.h
new file mode 100644
index 00000000..5bbe69cc
--- /dev/null
+++ b/pfinet/linux-src/include/net/rosecall.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void rose_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/include/net/route.h b/pfinet/linux-src/include/net/route.h
new file mode 100644
index 00000000..66df4712
--- /dev/null
+++ b/pfinet/linux-src/include/net/route.h
@@ -0,0 +1,153 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the IP router.
+ *
+ * Version: @(#)route.h 1.0.4 05/27/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Fixes:
+ * Alan Cox : Reformatted. Added ip_rt_local()
+ * Alan Cox : Support for TCP parameters.
+ * Alexey Kuznetsov: Major changes for new routing code.
+ * Mike McLagan : Routing by source
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ROUTE_H
+#define _ROUTE_H
+
+#include <linux/config.h>
+#include <net/dst.h>
+#include <linux/in_route.h>
+#include <linux/rtnetlink.h>
+#include <linux/route.h>
+
+#ifndef __KERNEL__
+#warning This file is not supposed to be used outside of kernel.
+#endif
+
+#define RT_HASH_DIVISOR 256
+
+/*
+ * Prevents LRU trashing, entries considered equivalent,
+ * if the difference between last use times is less then this number.
+ */
+#define RT_CACHE_BUBBLE_THRESHOLD (5*HZ)
+
+
+#define RTO_ONLINK 0x01
+#define RTO_TPROXY 0x80000000
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+#define RTO_CONN RTO_TPROXY
+#else
+#define RTO_CONN 0
+#endif
+
+struct rt_key
+{
+ __u32 dst;
+ __u32 src;
+ int iif;
+ int oif;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ __u32 fwmark;
+#endif
+ __u8 tos;
+ __u8 scope;
+};
+
+struct rtable
+{
+ union
+ {
+ struct dst_entry dst;
+ struct rtable *rt_next;
+ } u;
+
+ unsigned rt_flags;
+ unsigned rt_type;
+
+ __u32 rt_dst; /* Path destination */
+ __u32 rt_src; /* Path source */
+ int rt_iif;
+
+ /* Info on neighbour */
+ __u32 rt_gateway;
+
+ /* Cache lookup keys */
+ struct rt_key key;
+
+ /* Miscellaneous cached information */
+ __u32 rt_spec_dst; /* RFC1122 specific destination */
+
+#ifdef CONFIG_IP_ROUTE_NAT
+ __u32 rt_src_map;
+ __u32 rt_dst_map;
+#endif
+};
+
+extern struct rtable *rt_hash_table[RT_HASH_DIVISOR];
+
+struct ip_rt_acct
+{
+ __u32 o_bytes;
+ __u32 o_packets;
+ __u32 i_bytes;
+ __u32 i_packets;
+};
+
+extern struct ip_rt_acct ip_rt_acct[256];
+
+extern void ip_rt_init(void);
+extern void ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
+ u32 src, u8 tos, struct device *dev);
+extern void ip_rt_advice(struct rtable **rp, int advice);
+extern void rt_cache_flush(int how);
+extern int ip_route_output(struct rtable **, u32 dst, u32 src, u32 tos, int oif);
+extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct device *devin);
+extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
+extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
+extern void ip_rt_send_redirect(struct sk_buff *skb);
+
+extern unsigned inet_addr_type(u32 addr);
+extern void ip_rt_multicast_event(struct in_device *);
+extern int ip_rt_ioctl(unsigned int cmd, void *arg);
+extern void ip_rt_get_source(u8 *src, struct rtable *rt);
+extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb);
+
+
+extern __inline__ void ip_rt_put(struct rtable * rt)
+{
+ if (rt)
+ dst_release(&rt->u.dst);
+}
+
+extern __u8 ip_tos2prio[16];
+
+extern __inline__ char rt_tos2priority(u8 tos)
+{
+ return ip_tos2prio[IPTOS_TOS(tos)>>1];
+}
+
+extern __inline__ int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif)
+{
+ int err;
+ err = ip_route_output(rp, dst, src, tos, oif);
+ if (err || (dst && src))
+ return err;
+ dst = (*rp)->rt_dst;
+ src = (*rp)->rt_src;
+ ip_rt_put(*rp);
+ *rp = NULL;
+ return ip_route_output(rp, dst, src, tos, oif);
+}
+
+#endif /* _ROUTE_H */
diff --git a/pfinet/linux-src/include/net/scm.h b/pfinet/linux-src/include/net/scm.h
new file mode 100644
index 00000000..98c2dc91
--- /dev/null
+++ b/pfinet/linux-src/include/net/scm.h
@@ -0,0 +1,67 @@
+#ifndef __LINUX_NET_SCM_H
+#define __LINUX_NET_SCM_H
+
+/* Well, we should have at least one descriptor open
+ * to accept passed FDs 8)
+ */
+#define SCM_MAX_FD (OPEN_MAX-1)
+
+struct scm_fp_list
+{
+ int count;
+ struct file *fp[SCM_MAX_FD];
+};
+
+struct scm_cookie
+{
+ struct ucred creds; /* Skb credentials */
+ struct scm_fp_list *fp; /* Passed files */
+ unsigned long seq; /* Connection seqno */
+};
+
+extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
+extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
+extern void __scm_destroy(struct scm_cookie *scm);
+extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
+
+static __inline__ void scm_destroy(struct scm_cookie *scm)
+{
+ if (scm && scm->fp)
+ __scm_destroy(scm);
+}
+
+static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
+ struct scm_cookie *scm)
+{
+ memset(scm, 0, sizeof(*scm));
+ scm->creds.uid = current->uid;
+ scm->creds.gid = current->gid;
+ scm->creds.pid = current->pid;
+ if (msg->msg_controllen <= 0)
+ return 0;
+ return __scm_send(sock, msg, scm);
+}
+
+static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
+ struct scm_cookie *scm, int flags)
+{
+ if (!msg->msg_control)
+ {
+ if (sock->passcred || scm->fp)
+ msg->msg_flags |= MSG_CTRUNC;
+ scm_destroy(scm);
+ return;
+ }
+
+ if (sock->passcred)
+ put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
+
+ if (!scm->fp)
+ return;
+
+ scm_detach_fds(msg, scm);
+}
+
+
+#endif __LINUX_NET_SCM_H
+
diff --git a/pfinet/linux-src/include/net/slhc.h b/pfinet/linux-src/include/net/slhc.h
new file mode 100644
index 00000000..c7b39db5
--- /dev/null
+++ b/pfinet/linux-src/include/net/slhc.h
@@ -0,0 +1,6 @@
+#ifndef __NET_SLHC_H
+#define __NET_SLHC_H
+
+extern void slhc_install(void);
+
+#endif
diff --git a/pfinet/linux-src/include/net/slhc_vj.h b/pfinet/linux-src/include/net/slhc_vj.h
new file mode 100644
index 00000000..04387d8a
--- /dev/null
+++ b/pfinet/linux-src/include/net/slhc_vj.h
@@ -0,0 +1,187 @@
+#ifndef _SLHC_H
+#define _SLHC_H
+/*
+ * Definitions for tcp compression routines.
+ *
+ * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $
+ *
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ *
+ *
+ * modified for KA9Q Internet Software Package by
+ * Katie Stevens (dkstevens@ucdavis.edu)
+ * University of California, Davis
+ * Computing Services
+ * - 01-31-90 initial adaptation
+ *
+ * - Feb 1991 Bill_Simpson@um.cc.umich.edu
+ * variable number of conversation slots
+ * allow zero or one slots
+ * separate routines
+ * status display
+ */
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits). The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet. The next two octets are the TCP checksum
+ * from the original datagram. The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowledgment, sequence number and IP ID. (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.) Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0. (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type. There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows. Top
+ * three bits are actual packet type. For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* SLIP compression masks for len/vers byte */
+#define SL_TYPE_IP 0x40
+#define SL_TYPE_UNCOMPRESSED_TCP 0x70
+#define SL_TYPE_COMPRESSED_TCP 0x80
+#define SL_TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C 0x40 /* flag bits for what changed in a packet */
+#define NEW_I 0x20
+#define NEW_S 0x08
+#define NEW_A 0x04
+#define NEW_W 0x02
+#define NEW_U 0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+/*
+ * data type and sizes conversion assumptions:
+ *
+ * VJ code KA9Q style generic
+ * u_char byte_t unsigned char 8 bits
+ * u_short int16 unsigned short 16 bits
+ * u_int int16 unsigned short 16 bits
+ * u_long unsigned long unsigned long 32 bits
+ * int int32 long 32 bits
+ */
+
+typedef __u8 byte_t;
+typedef __u32 int32;
+
+/*
+ * "state" data for each active tcp conversation on the wire. This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+ byte_t cs_this; /* connection id number (xmit) */
+ struct cstate *next; /* next in ring (xmit) */
+ struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */
+ struct tcphdr cs_tcp;
+ unsigned char cs_ipopt[64];
+ unsigned char cs_tcpopt[64];
+ int cs_hsize;
+};
+#define NULLSLSTATE (struct cstate *)0
+
+/*
+ * all the state data for one serial line (we need one of these per line).
+ */
+struct slcompress {
+ struct cstate *tstate; /* transmit connection states (array)*/
+ struct cstate *rstate; /* receive connection states (array)*/
+
+ byte_t tslot_limit; /* highest transmit slot id (0-l)*/
+ byte_t rslot_limit; /* highest receive slot id (0-l)*/
+
+ byte_t xmit_oldest; /* oldest xmit in ring */
+ byte_t xmit_current; /* most recent xmit id */
+ byte_t recv_current; /* most recent rcvd id */
+
+ byte_t flags;
+#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */
+
+ int32 sls_o_nontcp; /* outbound non-TCP packets */
+ int32 sls_o_tcp; /* outbound TCP packets */
+ int32 sls_o_uncompressed; /* outbound uncompressed packets */
+ int32 sls_o_compressed; /* outbound compressed packets */
+ int32 sls_o_searches; /* searches for connection state */
+ int32 sls_o_misses; /* times couldn't find conn. state */
+
+ int32 sls_i_uncompressed; /* inbound uncompressed packets */
+ int32 sls_i_compressed; /* inbound compressed packets */
+ int32 sls_i_error; /* inbound error packets */
+ int32 sls_i_tossed; /* inbound packets tossed because of error */
+
+ int32 sls_i_runt;
+ int32 sls_i_badcheck;
+};
+#define NULLSLCOMPR (struct slcompress *)0
+
+#define __ARGS(x) x
+
+/* In slhc.c: */
+struct slcompress *slhc_init __ARGS((int rslots, int tslots));
+void slhc_free __ARGS((struct slcompress *comp));
+
+int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp,
+ int isize, unsigned char *ocp, unsigned char **cpp,
+ int compress_cid));
+int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp,
+ int isize));
+int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp,
+ int isize));
+int slhc_toss __ARGS((struct slcompress *comp));
+
+void slhc_i_status __ARGS((struct slcompress *comp));
+void slhc_o_status __ARGS((struct slcompress *comp));
+
+#endif /* _SLHC_H */
diff --git a/pfinet/linux-inet/snmp.h b/pfinet/linux-src/include/net/snmp.h
index 552292be..cc8354b6 100644
--- a/pfinet/linux-inet/snmp.h
+++ b/pfinet/linux-src/include/net/snmp.h
@@ -48,6 +48,31 @@ struct ip_mib
unsigned long IpFragCreates;
};
+struct ipv6_mib
+{
+ unsigned long Ip6InReceives;
+ unsigned long Ip6InHdrErrors;
+ unsigned long Ip6InTooBigErrors;
+ unsigned long Ip6InNoRoutes;
+ unsigned long Ip6InAddrErrors;
+ unsigned long Ip6InUnknownProtos;
+ unsigned long Ip6InTruncatedPkts;
+ unsigned long Ip6InDiscards;
+ unsigned long Ip6InDelivers;
+ unsigned long Ip6OutForwDatagrams;
+ unsigned long Ip6OutRequests;
+ unsigned long Ip6OutDiscards;
+ unsigned long Ip6OutNoRoutes;
+ unsigned long Ip6ReasmTimeout;
+ unsigned long Ip6ReasmReqds;
+ unsigned long Ip6ReasmOKs;
+ unsigned long Ip6ReasmFails;
+ unsigned long Ip6FragOKs;
+ unsigned long Ip6FragFails;
+ unsigned long Ip6FragCreates;
+ unsigned long Ip6InMcastPkts;
+ unsigned long Ip6OutMcastPkts;
+};
struct icmp_mib
{
@@ -78,6 +103,43 @@ struct icmp_mib
unsigned long IcmpOutAddrMasks;
unsigned long IcmpOutAddrMaskReps;
};
+
+struct icmpv6_mib
+{
+ unsigned long Icmp6InMsgs;
+ unsigned long Icmp6InErrors;
+
+ unsigned long Icmp6InDestUnreachs;
+ unsigned long Icmp6InPktTooBigs;
+ unsigned long Icmp6InTimeExcds;
+ unsigned long Icmp6InParmProblems;
+
+ unsigned long Icmp6InEchos;
+ unsigned long Icmp6InEchoReplies;
+ unsigned long Icmp6InGroupMembQueries;
+ unsigned long Icmp6InGroupMembResponses;
+ unsigned long Icmp6InGroupMembReductions;
+ unsigned long Icmp6InRouterSolicits;
+ unsigned long Icmp6InRouterAdvertisements;
+ unsigned long Icmp6InNeighborSolicits;
+ unsigned long Icmp6InNeighborAdvertisements;
+ unsigned long Icmp6InRedirects;
+
+ unsigned long Icmp6OutMsgs;
+
+ unsigned long Icmp6OutDestUnreachs;
+ unsigned long Icmp6OutPktTooBigs;
+ unsigned long Icmp6OutTimeExcds;
+ unsigned long Icmp6OutParmProblems;
+
+ unsigned long Icmp6OutEchoReplies;
+ unsigned long Icmp6OutRouterSolicits;
+ unsigned long Icmp6OutNeighborSolicits;
+ unsigned long Icmp6OutNeighborAdvertisements;
+ unsigned long Icmp6OutRedirects;
+ unsigned long Icmp6OutGroupMembResponses;
+ unsigned long Icmp6OutGroupMembReductions;
+};
struct tcp_mib
{
@@ -93,6 +155,8 @@ struct tcp_mib
unsigned long TcpInSegs;
unsigned long TcpOutSegs;
unsigned long TcpRetransSegs;
+ unsigned long TcpInErrs;
+ unsigned long TcpOutRsts;
};
struct udp_mib
@@ -102,6 +166,18 @@ struct udp_mib
unsigned long UdpInErrors;
unsigned long UdpOutDatagrams;
};
-
+
+struct linux_mib
+{
+ unsigned long SyncookiesSent;
+ unsigned long SyncookiesRecv;
+ unsigned long SyncookiesFailed;
+ unsigned long EmbryonicRsts;
+ unsigned long PruneCalled;
+ unsigned long RcvPruned;
+ unsigned long OfoPruned;
+ unsigned long OutOfWindowIcmps;
+ unsigned long LockDroppedIcmps;
+};
#endif
diff --git a/pfinet/linux-src/include/net/sock.h b/pfinet/linux-src/include/net/sock.h
new file mode 100644
index 00000000..7789ec40
--- /dev/null
+++ b/pfinet/linux-src/include/net/sock.h
@@ -0,0 +1,950 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the AF_INET socket handler.
+ *
+ * Version: @(#)sock.h 1.0.4 05/13/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Florian La Roche <flla@stud.uni-sb.de>
+ *
+ * Fixes:
+ * Alan Cox : Volatiles in skbuff pointers. See
+ * skbuff comments. May be overdone,
+ * better to prove they can be removed
+ * than the reverse.
+ * Alan Cox : Added a zapped field for tcp to note
+ * a socket is reset and must stay shut up
+ * Alan Cox : New fields for options
+ * Pauline Middelink : identd support
+ * Alan Cox : Eliminate low level recv/recvfrom
+ * David S. Miller : New socket lookup architecture.
+ * Steve Whitehouse: Default routines for sock_ops
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _SOCK_H
+#define _SOCK_H
+
+#include <linux/config.h>
+#include <linux/timer.h>
+#include <linux/in.h> /* struct sockaddr_in */
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+#include <linux/in6.h> /* struct sockaddr_in6 */
+#include <linux/ipv6.h> /* dest_cache, inet6_options */
+#include <linux/icmpv6.h>
+#include <net/if_inet6.h> /* struct ipv6_mc_socklist */
+#endif
+
+#if defined(CONFIG_INET) || defined (CONFIG_INET_MODULE)
+#include <linux/icmp.h>
+#endif
+#include <linux/tcp.h> /* struct tcphdr */
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h> /* struct sk_buff */
+#include <net/protocol.h> /* struct inet_protocol */
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <net/x25.h>
+#endif
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+#include <net/ax25.h>
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#include <net/netrom.h>
+#endif
+#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
+#include <net/rose.h>
+#endif
+#endif
+
+#if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
+#if defined(CONFIG_SPX) || defined(CONFIG_SPX_MODULE)
+#include <net/spx.h>
+#else
+#include <net/ipx.h>
+#endif /* CONFIG_SPX */
+#endif /* CONFIG_IPX */
+
+#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
+#include <linux/atalk.h>
+#endif
+
+#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
+#include <net/dn.h>
+#endif
+
+#if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE)
+#include <net/irda/irda.h>
+#endif
+
+#ifdef CONFIG_FILTER
+#include <linux/filter.h>
+#endif
+
+#include <asm/atomic.h>
+
+#define MIN_WRITE_SPACE 2048
+
+/* The AF_UNIX specific socket options */
+struct unix_opt {
+ int family;
+ char * name;
+ int locks;
+ struct unix_address *addr;
+ struct dentry * dentry;
+ struct semaphore readsem;
+ struct sock * other;
+ struct sock ** list;
+ struct sock * gc_tree;
+ int inflight;
+};
+
+#ifdef CONFIG_NETLINK
+struct netlink_callback;
+
+struct netlink_opt {
+ pid_t pid;
+ unsigned groups;
+ pid_t dst_pid;
+ unsigned dst_groups;
+ int (*handler)(int unit, struct sk_buff *skb);
+ atomic_t locks;
+ struct netlink_callback *cb;
+};
+#endif
+
+/* Once the IPX ncpd patches are in these are going into protinfo. */
+#if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
+struct ipx_opt {
+ ipx_address dest_addr;
+ ipx_interface *intrfc;
+ unsigned short port;
+#ifdef CONFIG_IPX_INTERN
+ unsigned char node[IPX_NODE_LEN];
+#endif
+ unsigned short type;
+/*
+ * To handle special ncp connection-handling sockets for mars_nwe,
+ * the connection number must be stored in the socket.
+ */
+ unsigned short ipx_ncp_conn;
+};
+#endif
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+struct ipv6_pinfo {
+ struct in6_addr saddr;
+ struct in6_addr rcv_saddr;
+ struct in6_addr daddr;
+ struct in6_addr *daddr_cache;
+
+ __u32 flow_label;
+ __u32 frag_size;
+ int hop_limit;
+ int mcast_hops;
+ int mcast_oif;
+
+ /* pktoption flags */
+ union {
+ struct {
+ __u8 srcrt:2,
+ rxinfo:1,
+ rxhlim:1,
+ hopopts:1,
+ dstopts:1,
+ authhdr:1,
+ rxflow:1;
+ } bits;
+ __u8 all;
+ } rxopt;
+
+ /* sockopt flags */
+ __u8 mc_loop:1,
+ recverr:1,
+ sndflow:1,
+ pmtudisc:2;
+
+ struct ipv6_mc_socklist *ipv6_mc_list;
+ struct ipv6_fl_socklist *ipv6_fl_list;
+ __u32 dst_cookie;
+
+ struct ipv6_txoptions *opt;
+ struct sk_buff *pktoptions;
+};
+
+struct raw6_opt {
+ __u32 checksum; /* perform checksum */
+ __u32 offset; /* checksum offset */
+
+ struct icmp6_filter filter;
+};
+
+#endif /* IPV6 */
+
+#if defined(CONFIG_INET) || defined(CONFIG_INET_MODULE)
+struct raw_opt {
+ struct icmp_filter filter;
+};
+#endif
+
+/* This defines a selective acknowledgement block. */
+struct tcp_sack_block {
+ __u32 start_seq;
+ __u32 end_seq;
+};
+
+struct tcp_opt {
+ int tcp_header_len; /* Bytes of tcp header to send */
+
+/*
+ * Header prediction flags
+ * 0x5?10 << 16 + snd_wnd in net byte order
+ */
+ __u32 pred_flags;
+
+/*
+ * RFC793 variables by their proper names. This means you can
+ * read the code and the spec side by side (and laugh ...)
+ * See RFC793 and RFC1122. The RFC writes these in capitals.
+ */
+ __u32 rcv_nxt; /* What we want to receive next */
+ __u32 snd_nxt; /* Next sequence we send */
+
+ __u32 snd_una; /* First byte we want an ack for */
+ __u32 rcv_tstamp; /* timestamp of last received packet */
+ __u32 lrcvtime; /* timestamp of last received data packet*/
+ __u32 srtt; /* smothed round trip time << 3 */
+
+ __u32 ato; /* delayed ack timeout */
+ __u32 snd_wl1; /* Sequence for window update */
+
+ __u32 snd_wl2; /* Ack sequence for update */
+ __u32 snd_wnd; /* The window we expect to receive */
+ __u32 max_window;
+ __u32 pmtu_cookie; /* Last pmtu seen by socket */
+ __u16 mss_cache; /* Cached effective mss, not including SACKS */
+ __u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
+ __u16 ext_header_len; /* Dave, do you allow mw to use this hole? 8) --ANK */
+ __u8 pending; /* pending events */
+ __u8 retransmits;
+ __u32 last_ack_sent; /* last ack we sent */
+
+ __u32 backoff; /* backoff */
+ __u32 mdev; /* medium deviation */
+ __u32 snd_cwnd; /* Sending congestion window */
+ __u32 rto; /* retransmit timeout */
+
+ __u32 packets_out; /* Packets which are "in flight" */
+ __u32 fackets_out; /* Non-retrans SACK'd packets */
+ __u32 retrans_out; /* Fast-retransmitted packets out */
+ __u32 high_seq; /* snd_nxt at onset of congestion */
+/*
+ * Slow start and congestion control (see also Nagle, and Karn & Partridge)
+ */
+ __u32 snd_ssthresh; /* Slow start size threshold */
+ __u16 snd_cwnd_cnt; /* Linear increase counter */
+ __u8 dup_acks; /* Consequetive duplicate acks seen from other end */
+ __u8 delayed_acks;
+ __u16 user_mss; /* mss requested by user in ioctl */
+
+ /* Two commonly used timers in both sender and receiver paths. */
+ struct timer_list retransmit_timer; /* Resend (no ack) */
+ struct timer_list delack_timer; /* Ack delay */
+
+ struct sk_buff_head out_of_order_queue; /* Out of order segments go here */
+
+ struct tcp_func *af_specific; /* Operations which are AF_INET{4,6} specific */
+ struct sk_buff *send_head; /* Front of stuff to transmit */
+ struct sk_buff *retrans_head; /* retrans head can be
+ * different to the head of
+ * write queue if we are doing
+ * fast retransmit
+ */
+
+ __u32 rcv_wnd; /* Current receiver window */
+ __u32 rcv_wup; /* rcv_nxt on last window update sent */
+ __u32 write_seq;
+ __u32 copied_seq;
+/*
+ * Options received (usually on last packet, some only on SYN packets).
+ */
+ char tstamp_ok, /* TIMESTAMP seen on SYN packet */
+ wscale_ok, /* Wscale seen on SYN packet */
+ sack_ok; /* SACK seen on SYN packet */
+ char saw_tstamp; /* Saw TIMESTAMP on last packet */
+ __u8 snd_wscale; /* Window scaling received from sender */
+ __u8 rcv_wscale; /* Window scaling to send to receiver */
+ __u8 rexmt_done; /* Retransmitted up to send head? */
+ __u32 rcv_tsval; /* Time stamp value */
+ __u32 rcv_tsecr; /* Time stamp echo reply */
+ __u32 ts_recent; /* Time stamp to echo next */
+ __u32 ts_recent_stamp;/* Time we stored ts_recent (for aging) */
+ int num_sacks; /* Number of SACK blocks */
+ struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
+
+ struct timer_list probe_timer; /* Probes */
+ __u32 window_clamp; /* XXX Document this... -DaveM */
+ __u32 probes_out; /* unanswered 0 window probes */
+ __u32 syn_seq;
+ __u32 fin_seq;
+ __u32 urg_seq;
+ __u32 urg_data;
+
+ __u32 last_seg_size; /* Size of last incoming segment */
+ __u32 rcv_mss; /* MSS used for delayed ACK decisions */
+ __u32 partial_writers; /* # of clients wanting at the head packet */
+
+ struct open_request *syn_wait_queue;
+ struct open_request **syn_wait_last;
+
+ int syn_backlog; /* Backlog of received SYNs */
+};
+
+
+/*
+ * This structure really needs to be cleaned up.
+ * Most of it is for TCP, and not used by any of
+ * the other protocols.
+ */
+
+/*
+ * The idea is to start moving to a newer struct gradualy
+ *
+ * IMHO the newer struct should have the following format:
+ *
+ * struct sock {
+ * sockmem [mem, proto, callbacks]
+ *
+ * union or struct {
+ * ax25;
+ * } ll_pinfo;
+ *
+ * union {
+ * ipv4;
+ * ipv6;
+ * ipx;
+ * netrom;
+ * rose;
+ * x25;
+ * } net_pinfo;
+ *
+ * union {
+ * tcp;
+ * udp;
+ * spx;
+ * netrom;
+ * } tp_pinfo;
+ *
+ * }
+ */
+
+/* Define this to get the sk->debug debugging facility. */
+#define SOCK_DEBUGGING
+#ifdef SOCK_DEBUGGING
+#define SOCK_DEBUG(sk, msg...) do { if((sk) && ((sk)->debug)) printk(KERN_DEBUG msg); } while (0)
+#else
+#define SOCK_DEBUG(sk, msg...) do { } while (0)
+#endif
+
+struct sock {
+ /* This must be first. */
+ struct sock *sklist_next;
+ struct sock *sklist_prev;
+
+ /* Local port binding hash linkage. */
+ struct sock *bind_next;
+ struct sock **bind_pprev;
+
+ /* Socket demultiplex comparisons on incoming packets. */
+ __u32 daddr; /* Foreign IPv4 addr */
+ __u32 rcv_saddr; /* Bound local IPv4 addr */
+ __u16 dport; /* Destination port */
+ unsigned short num; /* Local port */
+ int bound_dev_if; /* Bound device index if != 0 */
+
+ /* Main hash linkage for various protocol lookup tables. */
+ struct sock *next;
+ struct sock **pprev;
+
+ volatile unsigned char state, /* Connection state */
+ zapped; /* In ax25 & ipx means not linked */
+ __u16 sport; /* Source port */
+
+ unsigned short family; /* Address family */
+ unsigned char reuse, /* SO_REUSEADDR setting */
+ nonagle; /* Disable Nagle algorithm? */
+
+ atomic_t sock_readers; /* User count */
+ int rcvbuf; /* Size of receive buffer in bytes */
+
+ struct wait_queue **sleep; /* Sock wait queue */
+ struct dst_entry *dst_cache; /* Destination cache */
+ atomic_t rmem_alloc; /* Receive queue bytes committed */
+ struct sk_buff_head receive_queue; /* Incoming packets */
+ atomic_t wmem_alloc; /* Transmit queue bytes committed */
+ struct sk_buff_head write_queue; /* Packet sending queue */
+ atomic_t omem_alloc; /* "o" is "option" or "other" */
+ __u32 saddr; /* Sending source */
+ unsigned int allocation; /* Allocation mode */
+ int sndbuf; /* Size of send buffer in bytes */
+ struct sock *prev;
+
+ /* Not all are volatile, but some are, so we might as well say they all are.
+ * XXX Make this a flag word -DaveM
+ */
+ volatile char dead,
+ done,
+ urginline,
+ keepopen,
+ linger,
+ destroy,
+ no_check,
+ broadcast,
+ bsdism;
+ unsigned char debug;
+ int proc;
+ unsigned long lingertime;
+
+ int hashent;
+ struct sock *pair;
+
+ /* Error and backlog packet queues, rarely used. */
+ struct sk_buff_head back_log,
+ error_queue;
+
+ struct proto *prot;
+
+ unsigned short shutdown;
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ union {
+ struct ipv6_pinfo af_inet6;
+ } net_pinfo;
+#endif
+
+ union {
+ struct tcp_opt af_tcp;
+#if defined(CONFIG_INET) || defined (CONFIG_INET_MODULE)
+ struct raw_opt tp_raw4;
+#endif
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ struct raw6_opt tp_raw;
+#endif /* CONFIG_IPV6 */
+#if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+ struct spx_opt af_spx;
+#endif /* CONFIG_SPX */
+
+ } tp_pinfo;
+
+ int err, err_soft; /* Soft holds errors that don't
+ cause failure but are the cause
+ of a persistent failure not just
+ 'timed out' */
+ unsigned short ack_backlog;
+ unsigned short max_ack_backlog;
+ __u32 priority;
+ unsigned short type;
+ unsigned char localroute; /* Route locally only */
+ unsigned char protocol;
+ struct ucred peercred;
+
+#ifdef CONFIG_FILTER
+ /* Socket Filtering Instructions */
+ struct sk_filter *filter;
+#endif /* CONFIG_FILTER */
+
+ /* This is where all the private (optional) areas that don't
+ * overlap will eventually live.
+ */
+ union {
+ void *destruct_hook;
+ struct unix_opt af_unix;
+#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
+ struct atalk_sock af_at;
+#endif
+#if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
+ struct ipx_opt af_ipx;
+#endif
+#if defined (CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
+ struct dn_scp dn;
+#endif
+#if defined (CONFIG_PACKET) || defined(CONFIG_PACKET_MODULE)
+ struct packet_opt *af_packet;
+#endif
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+ x25_cb *x25;
+#endif
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+ ax25_cb *ax25;
+#endif
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+ nr_cb *nr;
+#endif
+#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
+ rose_cb *rose;
+#endif
+#ifdef CONFIG_NETLINK
+ struct netlink_opt af_netlink;
+#endif
+#if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
+ struct econet_opt *af_econet;
+#endif
+#if defined(CONFIG_IRDA) || defined(CONFIG_IRDA_MODULE)
+ struct irda_sock *irda;
+#endif
+ } protinfo;
+
+ /* IP 'private area' or will be eventually. */
+ int ip_ttl; /* TTL setting */
+ int ip_tos; /* TOS */
+ unsigned ip_cmsg_flags;
+ struct ip_options *opt;
+ unsigned char ip_hdrincl; /* Include headers ? */
+ __u8 ip_mc_ttl; /* Multicasting TTL */
+ __u8 ip_mc_loop; /* Loopback */
+ __u8 ip_recverr;
+ __u8 ip_pmtudisc;
+ int ip_mc_index; /* Multicast device index */
+ __u32 ip_mc_addr;
+ struct ip_mc_socklist *ip_mc_list; /* Group array */
+
+ /* This part is used for the timeout functions (timer.c). */
+ int timeout; /* What are we waiting for? */
+ struct timer_list timer; /* This is the sock cleanup timer. */
+ struct timeval stamp;
+
+ /* Identd */
+ struct socket *socket;
+
+ /* RPC layer private data */
+ void *user_data;
+
+ /* Callbacks */
+ void (*state_change)(struct sock *sk);
+ void (*data_ready)(struct sock *sk,int bytes);
+ void (*write_space)(struct sock *sk);
+ void (*error_report)(struct sock *sk);
+
+ int (*backlog_rcv) (struct sock *sk,
+ struct sk_buff *skb);
+ void (*destruct)(struct sock *sk);
+};
+
+/* IP protocol blocks we attach to sockets.
+ * socket layer -> transport layer interface
+ * transport -> network interface is defined by struct inet_proto
+ */
+struct proto {
+ /* These must be first. */
+ struct sock *sklist_next;
+ struct sock *sklist_prev;
+
+ void (*close)(struct sock *sk,
+ long timeout);
+ int (*connect)(struct sock *sk,
+ struct sockaddr *uaddr,
+ int addr_len);
+
+ struct sock * (*accept) (struct sock *sk, int flags);
+ void (*retransmit)(struct sock *sk, int all);
+ void (*write_wakeup)(struct sock *sk);
+ void (*read_wakeup)(struct sock *sk);
+
+ unsigned int (*poll)(struct file * file, struct socket *sock,
+ struct poll_table_struct *wait);
+
+ int (*ioctl)(struct sock *sk, int cmd,
+ unsigned long arg);
+ int (*init)(struct sock *sk);
+ int (*destroy)(struct sock *sk);
+ void (*shutdown)(struct sock *sk, int how);
+ int (*setsockopt)(struct sock *sk, int level,
+ int optname, char *optval, int optlen);
+ int (*getsockopt)(struct sock *sk, int level,
+ int optname, char *optval,
+ int *option);
+ int (*sendmsg)(struct sock *sk, struct msghdr *msg,
+ int len);
+ int (*recvmsg)(struct sock *sk, struct msghdr *msg,
+ int len, int noblock, int flags,
+ int *addr_len);
+ int (*bind)(struct sock *sk,
+ struct sockaddr *uaddr, int addr_len);
+
+ int (*backlog_rcv) (struct sock *sk,
+ struct sk_buff *skb);
+
+ /* Keeping track of sk's, looking them up, and port selection methods. */
+ void (*hash)(struct sock *sk);
+ void (*unhash)(struct sock *sk);
+ int (*get_port)(struct sock *sk, unsigned short snum);
+
+ unsigned short max_header;
+ unsigned long retransmits;
+ char name[32];
+ int inuse, highestinuse;
+};
+
+#define TIME_WRITE 1 /* Not yet used */
+#define TIME_RETRANS 2 /* Retransmit timer */
+#define TIME_DACK 3 /* Delayed ack timer */
+#define TIME_CLOSE 4
+#define TIME_KEEPOPEN 5
+#define TIME_DESTROY 6
+#define TIME_DONE 7 /* Used to absorb those last few packets */
+#define TIME_PROBE0 8
+
+/* About 10 seconds */
+#define SOCK_DESTROY_TIME (10*HZ)
+
+/* Sockets 0-1023 can't be bound to unless you are superuser */
+#define PROT_SOCK 1024
+
+#define SHUTDOWN_MASK 3
+#define RCV_SHUTDOWN 1
+#define SEND_SHUTDOWN 2
+
+/* Per-protocol hash table implementations use this to make sure
+ * nothing changes.
+ */
+#define SOCKHASH_LOCK() start_bh_atomic()
+#define SOCKHASH_UNLOCK() end_bh_atomic()
+
+/* Some things in the kernel just want to get at a protocols
+ * entire socket list commensurate, thus...
+ */
+static __inline__ void __add_to_prot_sklist(struct sock *sk)
+{
+ struct proto *p = sk->prot;
+
+ sk->sklist_prev = (struct sock *) p;
+ sk->sklist_next = p->sklist_next;
+ p->sklist_next->sklist_prev = sk;
+ p->sklist_next = sk;
+
+ /* Charge the protocol. */
+ sk->prot->inuse += 1;
+ if(sk->prot->highestinuse < sk->prot->inuse)
+ sk->prot->highestinuse = sk->prot->inuse;
+}
+
+static __inline__ void add_to_prot_sklist(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if(!sk->sklist_next)
+ __add_to_prot_sklist(sk);
+ SOCKHASH_UNLOCK();
+}
+
+static __inline__ void del_from_prot_sklist(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if(sk->sklist_next) {
+ sk->sklist_next->sklist_prev = sk->sklist_prev;
+ sk->sklist_prev->sklist_next = sk->sklist_next;
+ sk->sklist_next = NULL;
+ sk->prot->inuse--;
+ }
+ SOCKHASH_UNLOCK();
+}
+
+/*
+ * Used by processes to "lock" a socket state, so that
+ * interrupts and bottom half handlers won't change it
+ * from under us. It essentially blocks any incoming
+ * packets, so that we won't get any new data or any
+ * packets that change the state of the socket.
+ *
+ * Note the 'barrier()' calls: gcc may not move a lock
+ * "downwards" or a unlock "upwards" when optimizing.
+ */
+extern void __release_sock(struct sock *sk);
+
+static inline void lock_sock(struct sock *sk)
+{
+#if 0
+/* debugging code: the test isn't even 100% correct, but it can catch bugs */
+/* Note that a double lock is ok in theory - it's just _usually_ a bug */
+/* Actually it can easily happen with multiple writers */
+ if (atomic_read(&sk->sock_readers)) {
+ printk("double lock on socket at %p\n", gethere());
+here:
+ }
+#endif
+ atomic_inc(&sk->sock_readers);
+ synchronize_bh();
+}
+
+static inline void release_sock(struct sock *sk)
+{
+ barrier();
+ if (atomic_dec_and_test(&sk->sock_readers))
+ __release_sock(sk);
+}
+
+/*
+ * This might not be the most appropriate place for this two
+ * but since they are used by a lot of the net related code
+ * at least they get declared on a include that is common to all
+ */
+
+static __inline__ int min(unsigned int a, unsigned int b)
+{
+ if (a > b)
+ a = b;
+ return a;
+}
+
+static __inline__ int max(unsigned int a, unsigned int b)
+{
+ if (a < b)
+ a = b;
+ return a;
+}
+
+extern struct sock * sk_alloc(int family, int priority, int zero_it);
+extern void sk_free(struct sock *sk);
+extern void destroy_sock(struct sock *sk);
+
+extern struct sk_buff *sock_wmalloc(struct sock *sk,
+ unsigned long size, int force,
+ int priority);
+extern struct sk_buff *sock_rmalloc(struct sock *sk,
+ unsigned long size, int force,
+ int priority);
+extern void sock_wfree(struct sk_buff *skb);
+extern void sock_rfree(struct sk_buff *skb);
+extern unsigned long sock_rspace(struct sock *sk);
+extern unsigned long sock_wspace(struct sock *sk);
+
+extern int sock_setsockopt(struct socket *sock, int level,
+ int op, char *optval,
+ int optlen);
+
+extern int sock_getsockopt(struct socket *sock, int level,
+ int op, char *optval,
+ int *optlen);
+extern struct sk_buff *sock_alloc_send_skb(struct sock *sk,
+ unsigned long size,
+ unsigned long fallback,
+ int noblock,
+ int *errcode);
+extern void *sock_kmalloc(struct sock *sk, int size, int priority);
+extern void sock_kfree_s(struct sock *sk, void *mem, int size);
+
+
+/*
+ * Functions to fill in entries in struct proto_ops when a protocol
+ * does not implement a particular function.
+ */
+extern int sock_no_dup(struct socket *, struct socket *);
+extern int sock_no_release(struct socket *,
+ struct socket *);
+extern int sock_no_bind(struct socket *,
+ struct sockaddr *, int);
+extern int sock_no_connect(struct socket *,
+ struct sockaddr *, int, int);
+extern int sock_no_socketpair(struct socket *,
+ struct socket *);
+extern int sock_no_accept(struct socket *,
+ struct socket *, int);
+extern int sock_no_getname(struct socket *,
+ struct sockaddr *, int *, int);
+extern unsigned int sock_no_poll(struct file *, struct socket *,
+ struct poll_table_struct *);
+extern int sock_no_ioctl(struct socket *, unsigned int,
+ unsigned long);
+extern int sock_no_listen(struct socket *, int);
+extern int sock_no_shutdown(struct socket *, int);
+extern int sock_no_getsockopt(struct socket *, int , int,
+ char *, int *);
+extern int sock_no_setsockopt(struct socket *, int, int,
+ char *, int);
+extern int sock_no_fcntl(struct socket *,
+ unsigned int, unsigned long);
+extern int sock_no_sendmsg(struct socket *,
+ struct msghdr *, int,
+ struct scm_cookie *);
+extern int sock_no_recvmsg(struct socket *,
+ struct msghdr *, int,
+ struct scm_cookie *);
+
+/*
+ * Default socket callbacks and setup code
+ */
+
+extern void sock_def_callback1(struct sock *);
+extern void sock_def_callback2(struct sock *, int);
+extern void sock_def_callback3(struct sock *);
+extern void sock_def_destruct(struct sock *);
+
+/* Initialise core socket variables */
+extern void sock_init_data(struct socket *sock, struct sock *sk);
+
+extern void sklist_remove_socket(struct sock **list, struct sock *sk);
+extern void sklist_insert_socket(struct sock **list, struct sock *sk);
+extern void sklist_destroy_socket(struct sock **list, struct sock *sk);
+
+#ifdef CONFIG_FILTER
+/*
+ * Run the filter code and then cut skb->data to correct size returned by
+ * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
+ * than pkt_len we keep whole skb->data.
+ */
+extern __inline__ int sk_filter(struct sk_buff *skb, struct sk_filter *filter)
+{
+ int pkt_len;
+
+ pkt_len = sk_run_filter(skb, filter->insns, filter->len);
+ if(!pkt_len)
+ return 1; /* Toss Packet */
+ else
+ skb_trim(skb, pkt_len);
+
+ return 0;
+}
+
+extern __inline__ void sk_filter_release(struct sock *sk, struct sk_filter *fp)
+{
+ unsigned int size = sk_filter_len(fp);
+
+ atomic_sub(size, &sk->omem_alloc);
+
+ if (atomic_dec_and_test(&fp->refcnt))
+ kfree_s(fp, size);
+}
+
+extern __inline__ void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
+{
+ atomic_inc(&fp->refcnt);
+ atomic_add(sk_filter_len(fp), &sk->omem_alloc);
+}
+
+#endif /* CONFIG_FILTER */
+
+/*
+ * Queue a received datagram if it will fit. Stream and sequenced
+ * protocols can't normally use this as they need to fit buffers in
+ * and play with them.
+ *
+ * Inlined as it's very short and called for pretty much every
+ * packet ever received.
+ */
+
+extern __inline__ void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
+{
+ skb->sk = sk;
+ skb->destructor = sock_wfree;
+ atomic_add(skb->truesize, &sk->wmem_alloc);
+}
+
+extern __inline__ void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
+{
+ skb->sk = sk;
+ skb->destructor = sock_rfree;
+ atomic_add(skb->truesize, &sk->rmem_alloc);
+}
+
+
+extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+#ifdef CONFIG_FILTER
+ struct sk_filter *filter;
+#endif
+ /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
+ number of warnings when compiling with -W --ANK
+ */
+ if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
+ return -ENOMEM;
+
+#ifdef CONFIG_FILTER
+ if ((filter = sk->filter) != NULL && sk_filter(skb, filter))
+ return -EPERM; /* Toss packet */
+#endif /* CONFIG_FILTER */
+
+ skb_set_owner_r(skb, sk);
+ skb_queue_tail(&sk->receive_queue, skb);
+ if (!sk->dead)
+ sk->data_ready(sk,skb->len);
+ return 0;
+}
+
+extern __inline__ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
+{
+ /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
+ number of warnings when compiling with -W --ANK
+ */
+ if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
+ return -ENOMEM;
+ skb_set_owner_r(skb, sk);
+ skb_queue_tail(&sk->error_queue,skb);
+ if (!sk->dead)
+ sk->data_ready(sk,skb->len);
+ return 0;
+}
+
+/*
+ * Recover an error report and clear atomically
+ */
+
+extern __inline__ int sock_error(struct sock *sk)
+{
+ int err=xchg(&sk->err,0);
+ return -err;
+}
+
+extern __inline__ unsigned long sock_wspace(struct sock *sk)
+{
+ int amt = 0;
+
+ if (!(sk->shutdown & SEND_SHUTDOWN)) {
+ amt = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+ if (amt < 0)
+ amt = 0;
+ }
+ return amt;
+}
+
+/*
+ * Default write policy as shown to user space via poll/select/SIGIO
+ * Kernel internally doesn't use the MIN_WRITE_SPACE threshold.
+ */
+extern __inline__ int sock_writeable(struct sock *sk)
+{
+ return sock_wspace(sk) >= MIN_WRITE_SPACE;
+}
+
+/*
+ * Declarations from timer.c
+ */
+
+extern struct sock *timer_base;
+
+extern void net_delete_timer (struct sock *);
+extern void net_reset_timer (struct sock *, int, unsigned long);
+extern void net_timer (unsigned long);
+
+extern __inline__ int gfp_any(void)
+{
+ return in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+}
+
+/*
+ * Enable debug/info messages
+ */
+
+#if 1
+#define NETDEBUG(x) do { } while (0)
+#else
+#define NETDEBUG(x) do { x; } while (0)
+#endif
+
+#endif /* _SOCK_H */
diff --git a/pfinet/linux-src/include/net/spx.h b/pfinet/linux-src/include/net/spx.h
new file mode 100644
index 00000000..a449b891
--- /dev/null
+++ b/pfinet/linux-src/include/net/spx.h
@@ -0,0 +1,93 @@
+#ifndef __NET_SPX_H
+#define __NET_SPX_H
+
+#include <net/ipx.h>
+
+struct spxhdr
+{ __u8 cctl;
+ __u8 dtype;
+#define SPX_DTYPE_ECONN 0xFE /* Finished */
+#define SPX_DTYPE_ECACK 0xFF /* Ok */
+ __u16 sconn; /* Connection ID */
+ __u16 dconn; /* Connection ID */
+ __u16 sequence;
+ __u16 ackseq;
+ __u16 allocseq;
+};
+
+struct ipxspxhdr
+{ struct ipxhdr ipx;
+ struct spxhdr spx;
+};
+
+#define SPX_SYS_PKT_LEN (sizeof(struct ipxspxhdr))
+
+#ifdef __KERNEL__
+struct spx_opt
+{ int state;
+ int sndbuf;
+ int retries; /* Number of WD retries */
+ int retransmits; /* Number of retransmits */
+ int max_retries;
+ int wd_interval;
+ void *owner;
+ __u16 dest_connid; /* Net order */
+ __u16 source_connid; /* Net order */
+ __u16 sequence; /* Host order - our current pkt # */
+ __u16 alloc; /* Host order - max seq we can rcv now */
+ __u16 rmt_ack; /* Host order - last pkt ACKd by remote */
+ __u16 rmt_seq;
+ __u16 acknowledge;
+ __u16 rmt_alloc; /* Host order - max seq remote can handle now */
+ ipx_address dest_addr;
+ ipx_address source_addr;
+ struct timer_list watchdog; /* Idle watch */
+ struct timer_list retransmit; /* Retransmit timer */
+ struct sk_buff_head rcv_queue;
+ struct sk_buff_head transmit_queue;
+ struct sk_buff_head retransmit_queue;
+};
+
+/* Packet connectino control defines */
+#define CCTL_SPXII_XHD 0x01 /* SPX2 extended header */
+#define CCTL_SPX_UNKNOWN 0x02 /* Unknown (unused ??) */
+#define CCTL_SPXII_NEG 0x04 /* Negotiate size */
+#define CCTL_SPXII 0x08 /* Set for SPX2 */
+#define CCTL_EOM 0x10 /* End of message marker */
+#define CCTL_URG 0x20 /* Urgent marker in SPP (not used in SPX?) */
+#define CCTL_ACK 0x40 /* Send me an ACK */
+#define CCTL_CTL 0x80 /* Control message */
+#define CCTL_SYS CCTL_CTL /* Spec uses CCTL_SYS */
+
+/* Connection state defines */
+#define SPX_CLOSED 7
+#define SPX_CONNECTING 8
+#define SPX_CONNECTED 9
+
+/* Packet transmit types - Internal */
+#define DATA 0 /* Data */
+#define ACK 1 /* Data ACK */
+#define WDACK 2 /* WD ACK */
+#define CONACK 3 /* Connection Request ACK */
+#define CONREQ 4 /* Connection Request */
+#define WDREQ 5 /* WD Request */
+#define DISCON 6 /* Informed Disconnect */
+#define DISACK 7 /* Informed Disconnect ACK */
+#define RETRAN 8 /* Int. Retransmit of packet */
+#define TQUEUE 9 /* Int. Transmit of a queued packet */
+
+/*
+ * These are good canidates for IOcontrol calls
+ */
+
+/* Watchdog defines */
+#define VERIFY_TIMEOUT 3 * HZ
+#define ABORT_TIMEOUT 30 * HZ
+
+/* Packet retransmit defines */
+#define RETRY_COUNT 10
+#define RETRY_TIME 1 * HZ
+#define MAX_RETRY_DELAY 5 * HZ
+
+#endif /* __KERNEL__ */
+#endif /* def __NET_SPX_H */
diff --git a/pfinet/linux-src/include/net/spxcall.h b/pfinet/linux-src/include/net/spxcall.h
new file mode 100644
index 00000000..0461fbbe
--- /dev/null
+++ b/pfinet/linux-src/include/net/spxcall.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void spx_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/include/net/tcp.h b/pfinet/linux-src/include/net/tcp.h
new file mode 100644
index 00000000..abb4b210
--- /dev/null
+++ b/pfinet/linux-src/include/net/tcp.h
@@ -0,0 +1,1097 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the TCP module.
+ *
+ * Version: @(#)tcp.h 1.0.5 05/23/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _TCP_H
+#define _TCP_H
+
+#include <linux/config.h>
+#include <linux/tcp.h>
+#include <linux/slab.h>
+#include <net/checksum.h>
+
+/* This is for all connections with a full identity, no wildcards.
+ * Half of the table is for TIME_WAIT, the other half is for the
+ * rest.
+ *
+ * This needs to be shared by v4 and v6 because the lookup and hashing
+ * code needs to work with different AF's yet the port space is
+ * shared.
+ */
+extern unsigned int tcp_ehash_size;
+extern struct sock **tcp_ehash;
+
+/* This is for listening sockets, thus all sockets which possess wildcards. */
+#define TCP_LHTABLE_SIZE 32 /* Yes, really, this is all you need. */
+extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
+
+/* There are a few simple rules, which allow for local port reuse by
+ * an application. In essence:
+ *
+ * 1) Sockets bound to different interfaces may share a local port.
+ * Failing that, goto test 2.
+ * 2) If all sockets have sk->reuse set, and none of them are in
+ * TCP_LISTEN state, the port may be shared.
+ * Failing that, goto test 3.
+ * 3) If all sockets are bound to a specific sk->rcv_saddr local
+ * address, and none of them are the same, the port may be
+ * shared.
+ * Failing this, the port cannot be shared.
+ *
+ * The interesting point, is test #2. This is what an FTP server does
+ * all day. To optimize this case we use a specific flag bit defined
+ * below. As we add sockets to a bind bucket list, we perform a
+ * check of: (newsk->reuse && (newsk->state != TCP_LISTEN))
+ * As long as all sockets added to a bind bucket pass this test,
+ * the flag bit will be set.
+ * The resulting situation is that tcp_v[46]_verify_bind() can just check
+ * for this flag bit, if it is set and the socket trying to bind has
+ * sk->reuse set, we don't even have to walk the owners list at all,
+ * we return that it is ok to bind this socket to the requested local port.
+ *
+ * Sounds like a lot of work, but it is worth it. In a more naive
+ * implementation (ie. current FreeBSD etc.) the entire list of ports
+ * must be walked for each data port opened by an ftp server. Needless
+ * to say, this does not scale at all. With a couple thousand FTP
+ * users logged onto your box, isn't it nice to know that new data
+ * ports are created in O(1) time? I thought so. ;-) -DaveM
+ */
+struct tcp_bind_bucket {
+ unsigned short port;
+ unsigned short fastreuse;
+ struct tcp_bind_bucket *next;
+ struct sock *owners;
+ struct tcp_bind_bucket **pprev;
+};
+
+extern unsigned int tcp_bhash_size;
+extern struct tcp_bind_bucket **tcp_bhash;
+extern kmem_cache_t *tcp_bucket_cachep;
+extern struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum);
+extern void tcp_bucket_unlock(struct sock *sk);
+extern int tcp_port_rover;
+
+/* Level-1 socket-demux cache. */
+#define TCP_NUM_REGS 32
+extern struct sock *tcp_regs[TCP_NUM_REGS];
+
+#define TCP_RHASH_FN(__fport) \
+ ((((__fport) >> 7) ^ (__fport)) & (TCP_NUM_REGS - 1))
+#define TCP_RHASH(__fport) tcp_regs[TCP_RHASH_FN((__fport))]
+#define TCP_SK_RHASH_FN(__sock) TCP_RHASH_FN((__sock)->dport)
+#define TCP_SK_RHASH(__sock) tcp_regs[TCP_SK_RHASH_FN((__sock))]
+
+static __inline__ void tcp_reg_zap(struct sock *sk)
+{
+ struct sock **rpp;
+
+ rpp = &(TCP_SK_RHASH(sk));
+ if(*rpp == sk)
+ *rpp = NULL;
+}
+
+/* These are AF independent. */
+static __inline__ int tcp_bhashfn(__u16 lport)
+{
+ return (lport & (tcp_bhash_size - 1));
+}
+
+/* This is a TIME_WAIT bucket. It works around the memory consumption
+ * problems of sockets in such a state on heavily loaded servers, but
+ * without violating the protocol specification.
+ */
+struct tcp_tw_bucket {
+ /* These _must_ match the beginning of struct sock precisely.
+ * XXX Yes I know this is gross, but I'd have to edit every single
+ * XXX networking file if I created a "struct sock_header". -DaveM
+ * Just don't forget -fno-strict-aliasing, but it should be really
+ * fixed -AK
+ */
+ struct sock *sklist_next;
+ struct sock *sklist_prev;
+ struct sock *bind_next;
+ struct sock **bind_pprev;
+ __u32 daddr;
+ __u32 rcv_saddr;
+ __u16 dport;
+ unsigned short num;
+ int bound_dev_if;
+ struct sock *next;
+ struct sock **pprev;
+ unsigned char state,
+ zapped;
+ __u16 sport;
+ unsigned short family;
+ unsigned char reuse,
+ nonagle;
+
+ /* And these are ours. */
+ __u32 rcv_nxt, snd_nxt;
+ __u16 window;
+ struct tcp_func *af_specific;
+ struct tcp_bind_bucket *tb;
+ struct tcp_tw_bucket *next_death;
+ struct tcp_tw_bucket **pprev_death;
+ int death_slot;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct in6_addr v6_daddr;
+ struct in6_addr v6_rcv_saddr;
+#endif
+};
+
+extern kmem_cache_t *tcp_timewait_cachep;
+
+/* Socket demux engine toys. */
+#ifdef __BIG_ENDIAN
+#define TCP_COMBINED_PORTS(__sport, __dport) \
+ (((__u32)(__sport)<<16) | (__u32)(__dport))
+#else /* __LITTLE_ENDIAN */
+#define TCP_COMBINED_PORTS(__sport, __dport) \
+ (((__u32)(__dport)<<16) | (__u32)(__sport))
+#endif
+
+#if (BITS_PER_LONG == 64)
+#ifdef __BIG_ENDIAN
+#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) \
+ __u64 __name = (((__u64)(__saddr))<<32)|((__u64)(__daddr));
+#else /* __LITTLE_ENDIAN */
+#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) \
+ __u64 __name = (((__u64)(__daddr))<<32)|((__u64)(__saddr));
+#endif /* __BIG_ENDIAN */
+#define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+ (((*((__u64 *)&((__sk)->daddr)))== (__cookie)) && \
+ ((*((__u32 *)&((__sk)->dport)))== (__ports)) && \
+ (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+#else /* 32-bit arch */
+#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr)
+#define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+ (((__sk)->daddr == (__saddr)) && \
+ ((__sk)->rcv_saddr == (__daddr)) && \
+ ((*((__u32 *)&((__sk)->dport)))== (__ports)) && \
+ (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+#endif /* 64-bit arch */
+
+#define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif) \
+ (((*((__u32 *)&((__sk)->dport)))== (__ports)) && \
+ ((__sk)->family == AF_INET6) && \
+ !ipv6_addr_cmp(&(__sk)->net_pinfo.af_inet6.daddr, (__saddr)) && \
+ !ipv6_addr_cmp(&(__sk)->net_pinfo.af_inet6.rcv_saddr, (__daddr)) && \
+ (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+
+/* These can have wildcards, don't try too hard. */
+static __inline__ int tcp_lhashfn(unsigned short num)
+{
+ return num & (TCP_LHTABLE_SIZE - 1);
+}
+
+static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
+{
+ return tcp_lhashfn(sk->num);
+}
+
+/* Note, that it is > than ipv6 header */
+#define NETHDR_SIZE (sizeof(struct iphdr) + 40)
+
+/*
+ * 40 is maximal IP options size
+ * 20 is the maximum TCP options size we can currently construct on a SYN.
+ * 40 is the maximum possible TCP options size.
+ */
+
+#define MAX_SYN_SIZE (NETHDR_SIZE + sizeof(struct tcphdr) + 20 + MAX_HEADER + 15)
+#define MAX_FIN_SIZE (NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
+#define BASE_ACK_SIZE (NETHDR_SIZE + MAX_HEADER + 15)
+#define MAX_ACK_SIZE (NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
+#define MAX_RESET_SIZE (NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
+#define MAX_TCPHEADER_SIZE (NETHDR_SIZE + sizeof(struct tcphdr) + 20 + MAX_HEADER + 15)
+
+/*
+ * Never offer a window over 32767 without using window scaling. Some
+ * poor stacks do signed 16bit maths!
+ */
+#define MAX_WINDOW 32767
+#define MIN_WINDOW 2048
+#define MAX_ACK_BACKLOG 2
+#define MAX_DELAY_ACK 2
+#define TCP_WINDOW_DIFF 2048
+
+/* urg_data states */
+#define URG_VALID 0x0100
+#define URG_NOTYET 0x0200
+#define URG_READ 0x0400
+
+#define TCP_RETR1 7 /*
+ * This is how many retries it does before it
+ * tries to figure out if the gateway is
+ * down.
+ */
+
+#define TCP_RETR2 15 /*
+ * This should take at least
+ * 90 minutes to time out.
+ */
+
+#define TCP_TIMEOUT_LEN (15*60*HZ) /* should be about 15 mins */
+#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to successfully
+ * close the socket, about 60 seconds */
+#define TCP_FIN_TIMEOUT (3*60*HZ) /* BSD style FIN_WAIT2 deadlock breaker */
+
+#define TCP_ACK_TIME (3*HZ) /* time to delay before sending an ACK */
+#define TCP_DONE_TIME (5*HZ/2)/* maximum time to wait before actually
+ * destroying a socket */
+#define TCP_WRITE_TIME (30*HZ) /* initial time to wait for an ACK,
+ * after last transmit */
+#define TCP_TIMEOUT_INIT (3*HZ) /* RFC 1122 initial timeout value */
+#define TCP_SYN_RETRIES 10 /* number of times to retry opening a
+ * connection (TCP_RETR2-....) */
+#define TCP_PROBEWAIT_LEN (1*HZ)/* time to wait between probes when
+ * I've got something to write and
+ * there is no window */
+#define TCP_KEEPALIVE_TIME (120*60*HZ) /* two hours */
+#define TCP_KEEPALIVE_PROBES 9 /* Max of 9 keepalive probes */
+#define TCP_KEEPALIVE_PERIOD ((75*HZ)>>2) /* period of keepalive check */
+
+#define TCP_SYNACK_PERIOD (HZ/2) /* How often to run the synack slow timer */
+#define TCP_QUICK_TRIES 8 /* How often we try to retransmit, until
+ * we tell the link layer that it is something
+ * wrong (e.g. that it can expire redirects) */
+
+#define TCP_BUCKETGC_PERIOD (HZ)
+
+/* TIME_WAIT reaping mechanism. */
+#define TCP_TWKILL_SLOTS 8 /* Please keep this a power of 2. */
+#define TCP_TWKILL_PERIOD ((HZ*60)/TCP_TWKILL_SLOTS)
+
+/*
+ * TCP option
+ */
+
+#define TCPOPT_NOP 1 /* Padding */
+#define TCPOPT_EOL 0 /* End of options */
+#define TCPOPT_MSS 2 /* Segment size negotiating */
+#define TCPOPT_WINDOW 3 /* Window scaling */
+#define TCPOPT_SACK_PERM 4 /* SACK Permitted */
+#define TCPOPT_SACK 5 /* SACK Block */
+#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
+
+/*
+ * TCP option lengths
+ */
+
+#define TCPOLEN_MSS 4
+#define TCPOLEN_WINDOW 3
+#define TCPOLEN_SACK_PERM 2
+#define TCPOLEN_TIMESTAMP 10
+
+/* But this is what stacks really send out. */
+#define TCPOLEN_TSTAMP_ALIGNED 12
+#define TCPOLEN_WSCALE_ALIGNED 4
+#define TCPOLEN_SACKPERM_ALIGNED 4
+#define TCPOLEN_SACK_BASE 2
+#define TCPOLEN_SACK_BASE_ALIGNED 4
+#define TCPOLEN_SACK_PERBLOCK 8
+
+struct open_request;
+
+struct or_calltable {
+ void (*rtx_syn_ack) (struct sock *sk, struct open_request *req);
+ void (*destructor) (struct open_request *req);
+ void (*send_reset) (struct sk_buff *skb);
+};
+
+struct tcp_v4_open_req {
+ __u32 loc_addr;
+ __u32 rmt_addr;
+ struct ip_options *opt;
+};
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+struct tcp_v6_open_req {
+ struct in6_addr loc_addr;
+ struct in6_addr rmt_addr;
+ struct sk_buff *pktopts;
+ int iif;
+};
+#endif
+
+/* this structure is too big */
+struct open_request {
+ struct open_request *dl_next; /* Must be first member! */
+ __u32 rcv_isn;
+ __u32 snt_isn;
+ __u16 rmt_port;
+ __u16 mss;
+ __u8 retrans;
+ __u8 __pad;
+ unsigned snd_wscale : 4,
+ rcv_wscale : 4,
+ tstamp_ok : 1,
+ sack_ok : 1,
+ wscale_ok : 1;
+ /* The following two fields can be easily recomputed I think -AK */
+ __u32 window_clamp; /* window clamp at creation time */
+ __u32 rcv_wnd; /* rcv_wnd offered first time */
+ __u32 ts_recent;
+ unsigned long expires;
+ struct or_calltable *class;
+ struct sock *sk;
+ union {
+ struct tcp_v4_open_req v4_req;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ struct tcp_v6_open_req v6_req;
+#endif
+ } af;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ __u16 lcl_port; /* LVE */
+#endif
+};
+
+/* SLAB cache for open requests. */
+extern kmem_cache_t *tcp_openreq_cachep;
+
+#define tcp_openreq_alloc() kmem_cache_alloc(tcp_openreq_cachep, SLAB_ATOMIC)
+#define tcp_openreq_free(req) kmem_cache_free(tcp_openreq_cachep, req)
+
+/*
+ * Pointers to address related TCP functions
+ * (i.e. things that depend on the address family)
+ *
+ * BUGGG_FUTURE: all the idea behind this struct is wrong.
+ * It mixes socket frontend with transport function.
+ * With port sharing between IPv6/v4 it gives the only advantage,
+ * only poor IPv6 needs to permanently recheck, that it
+ * is still IPv6 8)8) It must be cleaned up as soon as possible.
+ * --ANK (980802)
+ */
+
+struct tcp_func {
+ void (*queue_xmit) (struct sk_buff *skb);
+
+ void (*send_check) (struct sock *sk,
+ struct tcphdr *th,
+ int len,
+ struct sk_buff *skb);
+
+ int (*rebuild_header) (struct sock *sk);
+
+ int (*conn_request) (struct sock *sk,
+ struct sk_buff *skb,
+ __u32 isn);
+
+ struct sock * (*syn_recv_sock) (struct sock *sk,
+ struct sk_buff *skb,
+ struct open_request *req,
+ struct dst_entry *dst);
+
+ struct sock * (*get_sock) (struct sk_buff *skb,
+ struct tcphdr *th);
+
+ __u16 net_header_len;
+
+
+
+ int (*setsockopt) (struct sock *sk,
+ int level,
+ int optname,
+ char *optval,
+ int optlen);
+
+ int (*getsockopt) (struct sock *sk,
+ int level,
+ int optname,
+ char *optval,
+ int *optlen);
+
+
+ void (*addr2sockaddr) (struct sock *sk,
+ struct sockaddr *);
+
+ int sockaddr_len;
+};
+
+/*
+ * The next routines deal with comparing 32 bit unsigned ints
+ * and worry about wraparound (automatic with unsigned arithmetic).
+ */
+
+extern __inline int before(__u32 seq1, __u32 seq2)
+{
+ return (__s32)(seq1-seq2) < 0;
+}
+
+extern __inline int after(__u32 seq1, __u32 seq2)
+{
+ return (__s32)(seq2-seq1) < 0;
+}
+
+
+/* is s2<=s1<=s3 ? */
+extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
+{
+ return seq3 - seq2 >= seq1 - seq2;
+}
+
+
+extern struct proto tcp_prot;
+extern struct tcp_mib tcp_statistics;
+
+extern void tcp_put_port(struct sock *sk);
+extern void __tcp_put_port(struct sock *sk);
+extern void tcp_inherit_port(struct sock *sk, struct sock *child);
+
+extern void tcp_v4_err(struct sk_buff *skb,
+ unsigned char *, int);
+
+extern void tcp_shutdown (struct sock *sk, int how);
+
+extern int tcp_v4_rcv(struct sk_buff *skb,
+ unsigned short len);
+
+extern int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg);
+
+extern int tcp_ioctl(struct sock *sk,
+ int cmd,
+ unsigned long arg);
+
+extern int tcp_rcv_state_process(struct sock *sk,
+ struct sk_buff *skb,
+ struct tcphdr *th,
+ unsigned len);
+
+extern int tcp_rcv_established(struct sock *sk,
+ struct sk_buff *skb,
+ struct tcphdr *th,
+ unsigned len);
+
+enum tcp_tw_status {
+ TCP_TW_SUCCESS = 0,
+ TCP_TW_RST = 1,
+ TCP_TW_ACK = 2
+ };
+
+extern enum tcp_tw_status tcp_timewait_state_process(struct tcp_tw_bucket *tw,
+ struct sk_buff *skb,
+ struct tcphdr *th,
+ unsigned len);
+
+extern void tcp_close(struct sock *sk,
+ long timeout);
+extern struct sock * tcp_accept(struct sock *sk, int flags);
+extern unsigned int tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait);
+extern void tcp_write_space(struct sock *sk);
+
+extern int tcp_getsockopt(struct sock *sk, int level,
+ int optname, char *optval,
+ int *optlen);
+extern int tcp_setsockopt(struct sock *sk, int level,
+ int optname, char *optval,
+ int optlen);
+extern void tcp_set_keepalive(struct sock *sk, int val);
+extern int tcp_recvmsg(struct sock *sk,
+ struct msghdr *msg,
+ int len, int nonblock,
+ int flags, int *addr_len);
+
+extern void tcp_parse_options(struct sock *sk, struct tcphdr *th,
+ struct tcp_opt *tp, int no_fancy);
+
+/*
+ * TCP v4 functions exported for the inet6 API
+ */
+
+extern int tcp_v4_rebuild_header(struct sock *sk);
+
+extern int tcp_v4_build_header(struct sock *sk,
+ struct sk_buff *skb);
+
+extern void tcp_v4_send_check(struct sock *sk,
+ struct tcphdr *th, int len,
+ struct sk_buff *skb);
+
+extern int tcp_v4_conn_request(struct sock *sk,
+ struct sk_buff *skb,
+ __u32 isn);
+
+extern struct sock * tcp_create_openreq_child(struct sock *sk,
+ struct open_request *req,
+ struct sk_buff *skb);
+
+extern struct sock * tcp_v4_syn_recv_sock(struct sock *sk,
+ struct sk_buff *skb,
+ struct open_request *req,
+ struct dst_entry *dst);
+
+extern int tcp_v4_do_rcv(struct sock *sk,
+ struct sk_buff *skb);
+
+extern int tcp_v4_connect(struct sock *sk,
+ struct sockaddr *uaddr,
+ int addr_len);
+
+extern void tcp_connect(struct sock *sk,
+ struct sk_buff *skb,
+ int est_mss);
+
+extern struct sk_buff * tcp_make_synack(struct sock *sk,
+ struct dst_entry *dst,
+ struct open_request *req,
+ int mss);
+
+
+/* From syncookies.c */
+extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
+ struct ip_options *opt);
+extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
+ __u16 *mss);
+
+/* tcp_output.c */
+
+extern void tcp_read_wakeup(struct sock *);
+extern void tcp_write_xmit(struct sock *);
+extern void tcp_time_wait(struct sock *);
+extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
+extern void tcp_fack_retransmit(struct sock *);
+extern void tcp_xmit_retransmit_queue(struct sock *);
+extern void tcp_simple_retransmit(struct sock *);
+
+extern void tcp_send_probe0(struct sock *);
+extern void tcp_send_partial(struct sock *);
+extern void tcp_write_wakeup(struct sock *);
+extern void tcp_send_fin(struct sock *sk);
+extern void tcp_send_active_reset(struct sock *sk);
+extern int tcp_send_synack(struct sock *);
+extern void tcp_transmit_skb(struct sock *, struct sk_buff *);
+extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue);
+extern void tcp_send_ack(struct sock *sk);
+extern void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout);
+
+/* CONFIG_IP_TRANSPARENT_PROXY */
+extern int tcp_chkaddr(struct sk_buff *);
+
+/* tcp_timer.c */
+#define tcp_reset_msl_timer(x,y,z) net_reset_timer(x,y,z)
+extern void tcp_reset_xmit_timer(struct sock *, int, unsigned long);
+extern void tcp_init_xmit_timers(struct sock *);
+extern void tcp_clear_xmit_timers(struct sock *);
+
+extern void tcp_retransmit_timer(unsigned long);
+extern void tcp_delack_timer(unsigned long);
+extern void tcp_probe_timer(unsigned long);
+
+extern struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+ struct open_request *req);
+
+/*
+ * TCP slow timer
+ */
+extern struct timer_list tcp_slow_timer;
+
+struct tcp_sl_timer {
+ atomic_t count;
+ unsigned long period;
+ unsigned long last;
+ void (*handler) (unsigned long);
+};
+
+#define TCP_SLT_SYNACK 0
+#define TCP_SLT_KEEPALIVE 1
+#define TCP_SLT_TWKILL 2
+#define TCP_SLT_MAX 3
+
+extern struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX];
+
+extern int tcp_sync_mss(struct sock *sk, u32 pmtu);
+
+/* Compute the current effective MSS, taking SACKs and IP options,
+ * and even PMTU discovery events into account.
+ */
+
+static __inline__ unsigned int tcp_current_mss(struct sock *sk)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct dst_entry *dst = sk->dst_cache;
+ int mss_now = tp->mss_cache;
+
+ if (dst && dst->pmtu != tp->pmtu_cookie)
+ mss_now = tcp_sync_mss(sk, dst->pmtu);
+
+ if(tp->sack_ok && tp->num_sacks)
+ mss_now -= (TCPOLEN_SACK_BASE_ALIGNED +
+ (tp->num_sacks * TCPOLEN_SACK_PERBLOCK));
+ return mss_now > 8 ? mss_now : 8;
+}
+
+/* Compute the actual receive window we are currently advertising.
+ * Rcv_nxt can be after the window if our peer push more data
+ * than the offered window.
+ */
+static __inline__ u32 tcp_receive_window(struct tcp_opt *tp)
+{
+ s32 win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt;
+
+ if (win < 0)
+ win = 0;
+ return (u32) win;
+}
+
+/* Choose a new window, without checks for shrinking, and without
+ * scaling applied to the result. The caller does these things
+ * if necessary. This is a "raw" window selection.
+ */
+extern u32 __tcp_select_window(struct sock *sk);
+
+/* Chose a new window to advertise, update state in tcp_opt for the
+ * socket, and return result with RFC1323 scaling applied. The return
+ * value can be stuffed directly into th->window for an outgoing
+ * frame.
+ */
+extern __inline__ u16 tcp_select_window(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ u32 cur_win = tcp_receive_window(tp);
+ u32 new_win = __tcp_select_window(sk);
+
+ /* Never shrink the offered window */
+ if(new_win < cur_win) {
+ /* Danger Will Robinson!
+ * Don't update rcv_wup/rcv_wnd here or else
+ * we will not be able to advertise a zero
+ * window in time. --DaveM
+ */
+ new_win = cur_win;
+ } else {
+ tp->rcv_wnd = new_win;
+ tp->rcv_wup = tp->rcv_nxt;
+ }
+
+ /* RFC1323 scaling applied */
+ return new_win >> tp->rcv_wscale;
+}
+
+/* See if we can advertise non-zero, and if so how much we
+ * can increase our advertisement. If it becomes more than
+ * twice what we are talking about right now, return true.
+ */
+extern __inline__ int tcp_raise_window(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ u32 cur_win = tcp_receive_window(tp);
+ u32 new_win = __tcp_select_window(sk);
+
+ return (new_win && (new_win > (cur_win << 1)));
+}
+
+/* Recalculate snd_ssthresh, we want to set it to:
+ *
+ * one half the current congestion window, but no
+ * less than two segments
+ *
+ * We must take into account the current send window
+ * as well, however we keep track of that using different
+ * units so a conversion is necessary. -DaveM
+ */
+extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
+{
+ __u32 snd_wnd_packets = tp->snd_wnd / max(tp->mss_cache, 1);
+
+ return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2);
+}
+
+/* TCP timestamps are only 32-bits, this causes a slight
+ * complication on 64-bit systems since we store a snapshot
+ * of jiffies in the buffer control blocks below. We decidedly
+ * only use of the low 32-bits of jiffies and hide the ugly
+ * casts with the following macro.
+ */
+#define tcp_time_stamp ((__u32)(jiffies))
+
+/* This is what the send packet queueing engine uses to pass
+ * TCP per-packet control information to the transmission
+ * code. We also store the host-order sequence numbers in
+ * here too. This is 36 bytes on 32-bit architectures,
+ * 40 bytes on 64-bit machines, if this grows please adjust
+ * skbuff.h:skbuff->cb[xxx] size appropriately.
+ */
+struct tcp_skb_cb {
+ union {
+ struct inet_skb_parm h4;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ struct inet6_skb_parm h6;
+#endif
+ } header; /* For incoming frames */
+ __u32 seq; /* Starting sequence number */
+ __u32 end_seq; /* SEQ + FIN + SYN + datalen */
+ __u32 when; /* used to compute rtt's */
+ __u8 flags; /* TCP header flags. */
+
+ /* NOTE: These must match up to the flags byte in a
+ * real TCP header.
+ */
+#define TCPCB_FLAG_FIN 0x01
+#define TCPCB_FLAG_SYN 0x02
+#define TCPCB_FLAG_RST 0x04
+#define TCPCB_FLAG_PSH 0x08
+#define TCPCB_FLAG_ACK 0x10
+#define TCPCB_FLAG_URG 0x20
+
+ __u8 sacked; /* State flags for SACK/FACK. */
+#define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block */
+#define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */
+
+ __u16 urg_ptr; /* Valid w/URG flags is set. */
+ __u32 ack_seq; /* Sequence number ACK'd */
+};
+
+#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))
+
+/* This determines how many packets are "in the network" to the best
+ * of our knowledge. In many cases it is conservative, but where
+ * detailed information is available from the receiver (via SACK
+ * blocks etc.) we can make more aggressive calculations.
+ *
+ * Use this for decisions involving congestion control, use just
+ * tp->packets_out to determine if the send queue is empty or not.
+ *
+ * Read this equation as:
+ *
+ * "Packets sent once on transmission queue" MINUS
+ * "Packets acknowledged by FACK information" PLUS
+ * "Packets fast retransmitted"
+ */
+static __inline__ int tcp_packets_in_flight(struct tcp_opt *tp)
+{
+ return tp->packets_out - tp->fackets_out + tp->retrans_out;
+}
+
+/* This checks if the data bearing packet SKB (usually tp->send_head)
+ * should be put on the wire right now.
+ */
+static __inline__ int tcp_snd_test(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int nagle_check = 1;
+
+ /* RFC 1122 - section 4.2.3.4
+ *
+ * We must queue if
+ *
+ * a) The right edge of this frame exceeds the window
+ * b) There are packets in flight and we have a small segment
+ * [SWS avoidance and Nagle algorithm]
+ * (part of SWS is done on packetization)
+ * c) We are retransmiting [Nagle]
+ * d) We have too many packets 'in flight'
+ *
+ * Don't use the nagle rule for urgent data (or
+ * for the final FIN -DaveM).
+ */
+ if ((sk->nonagle == 2 && (skb->len < tp->mss_cache)) ||
+ (!sk->nonagle &&
+ skb->len < (tp->mss_cache >> 1) &&
+ tp->packets_out &&
+ !(TCP_SKB_CB(skb)->flags & (TCPCB_FLAG_URG|TCPCB_FLAG_FIN))))
+ nagle_check = 0;
+
+ /* Don't be strict about the congestion window for the
+ * final FIN frame. -DaveM
+ */
+ return (nagle_check &&
+ ((tcp_packets_in_flight(tp) < tp->snd_cwnd) ||
+ (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) &&
+ !after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
+ tp->retransmits == 0);
+}
+
+/* Push out any pending frames which were held back due to
+ * TCP_CORK or attempt at coalescing tiny packets.
+ * The socket must be locked by the caller.
+ */
+static __inline__ void tcp_push_pending_frames(struct sock *sk, struct tcp_opt *tp)
+{
+ if(tp->send_head) {
+ if(tcp_snd_test(sk, tp->send_head))
+ tcp_write_xmit(sk);
+ else if(tp->packets_out == 0 && !tp->pending) {
+ /* We held off on this in tcp_send_skb() */
+ tp->pending = TIME_PROBE0;
+ tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
+ }
+ }
+}
+
+/* This tells the input processing path that an ACK should go out
+ * right now.
+ */
+#define tcp_enter_quickack_mode(__tp) ((__tp)->ato |= (1<<31))
+#define tcp_exit_quickack_mode(__tp) ((__tp)->ato &= ~(1<<31))
+#define tcp_in_quickack_mode(__tp) (((__tp)->ato & (1 << 31)) != 0)
+
+/*
+ * List all states of a TCP socket that can be viewed as a "connected"
+ * state. This now includes TCP_SYN_RECV, although I am not yet fully
+ * convinced that this is the solution for the 'getpeername(2)'
+ * problem. Thanks to Stephen A. Wood <saw@cebaf.gov> -FvK
+ */
+
+extern __inline const int tcp_connected(const int state)
+{
+ return ((1 << state) &
+ (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT1|
+ TCPF_FIN_WAIT2|TCPF_SYN_RECV));
+}
+
+/*
+ * Calculate(/check) TCP checksum
+ */
+static __inline__ u16 tcp_v4_check(struct tcphdr *th, int len,
+ unsigned long saddr, unsigned long daddr,
+ unsigned long base)
+{
+ return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base);
+}
+
+#undef STATE_TRACE
+
+#ifdef STATE_TRACE
+static char *statename[]={
+ "Unused","Established","Syn Sent","Syn Recv",
+ "Fin Wait 1","Fin Wait 2","Time Wait", "Close",
+ "Close Wait","Last ACK","Listen","Closing"
+};
+#endif
+
+static __inline__ void tcp_set_state(struct sock *sk, int state)
+{
+ int oldstate = sk->state;
+
+ sk->state = state;
+
+#ifdef STATE_TRACE
+ SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]);
+#endif
+
+ switch (state) {
+ case TCP_ESTABLISHED:
+ if (oldstate != TCP_ESTABLISHED)
+ tcp_statistics.TcpCurrEstab++;
+ break;
+
+ case TCP_CLOSE:
+ {
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ /* Should be about 2 rtt's */
+ net_reset_timer(sk, TIME_DONE, min(tp->srtt * 2, TCP_DONE_TIME));
+ sk->prot->unhash(sk);
+ /* fall through */
+ }
+ default:
+ if (oldstate==TCP_ESTABLISHED)
+ tcp_statistics.TcpCurrEstab--;
+ }
+}
+
+static __inline__ void tcp_build_and_update_options(__u32 *ptr, struct tcp_opt *tp, __u32 tstamp)
+{
+ if (tp->tstamp_ok) {
+ *ptr++ = __constant_htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl(tstamp);
+ *ptr++ = htonl(tp->ts_recent);
+ }
+ if(tp->sack_ok && tp->num_sacks) {
+ int this_sack;
+
+ *ptr++ = __constant_htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_SACK << 8) |
+ (TCPOLEN_SACK_BASE +
+ (tp->num_sacks * TCPOLEN_SACK_PERBLOCK)));
+ for(this_sack = 0; this_sack < tp->num_sacks; this_sack++) {
+ *ptr++ = htonl(tp->selective_acks[this_sack].start_seq);
+ *ptr++ = htonl(tp->selective_acks[this_sack].end_seq);
+ }
+ }
+}
+
+/* Construct a tcp options header for a SYN or SYN_ACK packet.
+ * If this is every changed make sure to change the definition of
+ * MAX_SYN_SIZE to match the new maximum number of options that you
+ * can generate.
+ */
+extern __inline__ void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
+ int offer_wscale, int wscale, __u32 tstamp, __u32 ts_recent)
+{
+ /* We always get an MSS option.
+ * The option bytes which will be seen in normal data
+ * packets should timestamps be used, must be in the MSS
+ * advertised. But we subtract them from sk->mss so
+ * that calculations in tcp_sendmsg are simpler etc.
+ * So account for this fact here if necessary. If we
+ * don't do this correctly, as a receiver we won't
+ * recognize data packets as being full sized when we
+ * should, and thus we won't abide by the delayed ACK
+ * rules correctly.
+ * SACKs don't matter, we never delay an ACK when we
+ * have any of those going out.
+ */
+ *ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
+ if (ts) {
+ if(sack)
+ *ptr++ = __constant_htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) |
+ (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+ else
+ *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl(tstamp); /* TSVAL */
+ *ptr++ = htonl(ts_recent); /* TSECR */
+ } else if(sack)
+ *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+ (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM);
+ if (offer_wscale)
+ *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale));
+}
+
+/* Determine a window scaling and initial window to offer.
+ * Based on the assumption that the given amount of space
+ * will be offered. Store the results in the tp structure.
+ * NOTE: for smooth operation initial space offering should
+ * be a multiple of mss if possible. We assume here that mss >= 1.
+ * This MUST be enforced by all callers.
+ */
+extern __inline__ void tcp_select_initial_window(__u32 space, __u16 mss,
+ __u32 *rcv_wnd,
+ __u32 *window_clamp,
+ int wscale_ok,
+ __u8 *rcv_wscale)
+{
+ /* If no clamp set the clamp to the max possible scaled window */
+ if (*window_clamp == 0)
+ (*window_clamp) = (65535<<14);
+ space = min(*window_clamp,space);
+
+ /* Quantize space offering to a multiple of mss if possible. */
+ if (space > mss)
+ space = (space/mss)*mss;
+
+ /* NOTE: offering an initial window larger than 32767
+ * will break some buggy TCP stacks. We try to be nice.
+ * If we are not window scaling, then this truncates
+ * our initial window offering to 32k. There should also
+ * be a sysctl option to stop being nice.
+ */
+ (*rcv_wnd) = min(space, MAX_WINDOW);
+ (*rcv_wscale) = 0;
+ if (wscale_ok) {
+ /* See RFC1323 for an explanation of the limit to 14 */
+ while (space > 65535 && (*rcv_wscale) < 14) {
+ space >>= 1;
+ (*rcv_wscale)++;
+ }
+ }
+ /* Set the clamp no higher than max representable value */
+ (*window_clamp) = min(65535<<(*rcv_wscale),*window_clamp);
+}
+
+extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request *prev)
+{
+ if(!req->dl_next)
+ tp->syn_wait_last = (struct open_request **)prev;
+ prev->dl_next = req->dl_next;
+}
+
+extern __inline__ void tcp_synq_queue(struct tcp_opt *tp, struct open_request *req)
+{
+ req->dl_next = NULL;
+ *tp->syn_wait_last = req;
+ tp->syn_wait_last = &req->dl_next;
+}
+
+extern __inline__ void tcp_synq_init(struct tcp_opt *tp)
+{
+ tp->syn_wait_queue = NULL;
+ tp->syn_wait_last = &tp->syn_wait_queue;
+}
+
+extern void __tcp_inc_slow_timer(struct tcp_sl_timer *slt);
+extern __inline__ void tcp_inc_slow_timer(int timer)
+{
+ struct tcp_sl_timer *slt = &tcp_slt_array[timer];
+
+ if (atomic_read(&slt->count) == 0)
+ {
+ __tcp_inc_slow_timer(slt);
+ }
+
+ atomic_inc(&slt->count);
+}
+
+extern __inline__ void tcp_dec_slow_timer(int timer)
+{
+ struct tcp_sl_timer *slt = &tcp_slt_array[timer];
+
+ atomic_dec(&slt->count);
+}
+
+extern const char timer_bug_msg[];
+
+static inline void tcp_clear_xmit_timer(struct sock *sk, int what)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct timer_list *timer;
+
+ switch (what) {
+ case TIME_RETRANS:
+ timer = &tp->retransmit_timer;
+ break;
+ case TIME_DACK:
+ timer = &tp->delack_timer;
+ break;
+ case TIME_PROBE0:
+ timer = &tp->probe_timer;
+ break;
+ default:
+ printk("%s", timer_bug_msg);
+ return;
+ };
+ if(timer->prev != NULL)
+ del_timer(timer);
+}
+
+static inline int tcp_timer_is_set(struct sock *sk, int what)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ switch (what) {
+ case TIME_RETRANS:
+ return tp->retransmit_timer.prev != NULL;
+ break;
+ case TIME_DACK:
+ return tp->delack_timer.prev != NULL;
+ break;
+ case TIME_PROBE0:
+ return tp->probe_timer.prev != NULL;
+ break;
+ default:
+ printk("%s", timer_bug_msg);
+ };
+ return 0;
+}
+
+
+#endif /* _TCP_H */
diff --git a/pfinet/linux-src/include/net/transp_v6.h b/pfinet/linux-src/include/net/transp_v6.h
new file mode 100644
index 00000000..d49bc86e
--- /dev/null
+++ b/pfinet/linux-src/include/net/transp_v6.h
@@ -0,0 +1,46 @@
+#ifndef _TRANSP_V6_H
+#define _TRANSP_V6_H
+
+#include <net/checksum.h>
+
+/*
+ * IPv6 transport protocols
+ */
+
+#ifdef __KERNEL__
+
+extern struct proto rawv6_prot;
+extern struct proto udpv6_prot;
+extern struct proto tcpv6_prot;
+
+struct flowi;
+
+extern void rawv6_init(void);
+extern void udpv6_init(void);
+extern void tcpv6_init(void);
+
+extern int udpv6_connect(struct sock *sk,
+ struct sockaddr *uaddr,
+ int addr_len);
+
+extern int datagram_recv_ctl(struct sock *sk,
+ struct msghdr *msg,
+ struct sk_buff *skb);
+
+extern int datagram_send_ctl(struct msghdr *msg,
+ struct flowi *fl,
+ struct ipv6_txoptions *opt,
+ int *hlimit);
+
+#define LOOPBACK4_IPV6 __constant_htonl(0x7f000006)
+
+/*
+ * address family specific functions
+ */
+extern struct tcp_func ipv4_specific;
+
+extern int inet6_destroy_sock(struct sock *sk);
+
+#endif
+
+#endif
diff --git a/pfinet/linux-inet/udp.h b/pfinet/linux-src/include/net/udp.h
index 6bfbb3cb..f3ceadb5 100644
--- a/pfinet/linux-inet/udp.h
+++ b/pfinet/linux-src/include/net/udp.h
@@ -23,28 +23,44 @@
#define _UDP_H
#include <linux/udp.h>
+#include <net/sock.h>
+#define UDP_HTABLE_SIZE 128
+
+/* udp.c: This needs to be shared by v4 and v6 because the lookup
+ * and hashing code needs to work with different AF's yet
+ * the port space is shared.
+ */
+extern struct sock *udp_hash[UDP_HTABLE_SIZE];
#define UDP_NO_CHECK 0
+extern int udp_port_rover;
+
+static inline int udp_lport_inuse(u16 num)
+{
+ struct sock *sk = udp_hash[num & (UDP_HTABLE_SIZE - 1)];
+
+ for(; sk != NULL; sk = sk->next) {
+ if(sk->num == num)
+ return 1;
+ }
+ return 0;
+}
extern struct proto udp_prot;
-extern void udp_err(int err, unsigned char *header, unsigned long daddr,
- unsigned long saddr, struct inet_protocol *protocol);
-extern int udp_recvfrom(struct sock *sk, unsigned char *to,
- int len, int noblock, unsigned flags,
- struct sockaddr_in *sin, int *addr_len);
-extern int udp_read(struct sock *sk, unsigned char *buff,
- int len, int noblock, unsigned flags);
+extern void udp_err(struct sk_buff *, unsigned char *, int);
extern int udp_connect(struct sock *sk,
- struct sockaddr_in *usin, int addr_len);
-extern int udp_rcv(struct sk_buff *skb, struct device *dev,
- struct options *opt, unsigned long daddr,
- unsigned short len, unsigned long saddr, int redo,
- struct inet_protocol *protocol);
+ struct sockaddr *usin, int addr_len);
+
+extern int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len);
+
+extern int udp_rcv(struct sk_buff *skb, unsigned short len);
extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+/* CONFIG_IP_TRANSPARENT_PROXY */
+extern int udp_chkaddr(struct sk_buff *skb);
#endif /* _UDP_H */
diff --git a/pfinet/linux-src/include/net/x25.h b/pfinet/linux-src/include/net/x25.h
new file mode 100644
index 00000000..5ac507bd
--- /dev/null
+++ b/pfinet/linux-src/include/net/x25.h
@@ -0,0 +1,221 @@
+/*
+ * Declarations of X.25 Packet Layer type objects.
+ *
+ * Jonathan Naylor 17/11/96
+ */
+
+#ifndef _X25_H
+#define _X25_H
+#include <linux/x25.h>
+
+#define X25_ADDR_LEN 16
+
+#define X25_MAX_L2_LEN 18 /* 802.2 LLC */
+
+#define X25_STD_MIN_LEN 3
+#define X25_EXT_MIN_LEN 4
+
+#define X25_GFI_SEQ_MASK 0x30
+#define X25_GFI_STDSEQ 0x10
+#define X25_GFI_EXTSEQ 0x20
+
+#define X25_Q_BIT 0x80
+#define X25_D_BIT 0x40
+#define X25_STD_M_BIT 0x10
+#define X25_EXT_M_BIT 0x01
+
+#define X25_CALL_REQUEST 0x0B
+#define X25_CALL_ACCEPTED 0x0F
+#define X25_CLEAR_REQUEST 0x13
+#define X25_CLEAR_CONFIRMATION 0x17
+#define X25_DATA 0x00
+#define X25_INTERRUPT 0x23
+#define X25_INTERRUPT_CONFIRMATION 0x27
+#define X25_RR 0x01
+#define X25_RNR 0x05
+#define X25_REJ 0x09
+#define X25_RESET_REQUEST 0x1B
+#define X25_RESET_CONFIRMATION 0x1F
+#define X25_REGISTRATION_REQUEST 0xF3
+#define X25_REGISTRATION_CONFIRMATION 0xF7
+#define X25_RESTART_REQUEST 0xFB
+#define X25_RESTART_CONFIRMATION 0xFF
+#define X25_DIAGNOSTIC 0xF1
+#define X25_ILLEGAL 0xFD
+
+/* Define the various conditions that may exist */
+
+#define X25_COND_ACK_PENDING 0x01
+#define X25_COND_OWN_RX_BUSY 0x02
+#define X25_COND_PEER_RX_BUSY 0x04
+
+/* Define Link State constants. */
+enum {
+ X25_STATE_0, /* Ready */
+ X25_STATE_1, /* Awaiting Call Accepted */
+ X25_STATE_2, /* Awaiting Clear Confirmation */
+ X25_STATE_3, /* Data Transfer */
+ X25_STATE_4 /* Awaiting Reset Confirmation */
+};
+
+enum {
+ X25_LINK_STATE_0,
+ X25_LINK_STATE_1,
+ X25_LINK_STATE_2,
+ X25_LINK_STATE_3
+};
+
+#define X25_DEFAULT_T20 (180 * HZ) /* Default T20 value */
+#define X25_DEFAULT_T21 (200 * HZ) /* Default T21 value */
+#define X25_DEFAULT_T22 (180 * HZ) /* Default T22 value */
+#define X25_DEFAULT_T23 (180 * HZ) /* Default T23 value */
+#define X25_DEFAULT_T2 (3 * HZ) /* Default ack holdback value */
+
+#define X25_DEFAULT_WINDOW_SIZE 2 /* Default Window Size */
+#define X25_DEFAULT_PACKET_SIZE X25_PS128 /* Default Packet Size */
+#define X25_DEFAULT_THROUGHPUT 0x0A /* Deafult Throughput */
+#define X25_DEFAULT_REVERSE 0x00 /* Default Reverse Charging */
+
+#define X25_SMODULUS 8
+#define X25_EMODULUS 128
+
+/*
+ * X.25 Facilities constants.
+ */
+
+#define X25_FAC_CLASS_MASK 0xC0
+
+#define X25_FAC_CLASS_A 0x00
+#define X25_FAC_CLASS_B 0x40
+#define X25_FAC_CLASS_C 0x80
+#define X25_FAC_CLASS_D 0xC0
+
+#define X25_FAC_REVERSE 0x01
+#define X25_FAC_THROUGHPUT 0x02
+#define X25_FAC_PACKET_SIZE 0x42
+#define X25_FAC_WINDOW_SIZE 0x43
+
+#define X25_MAX_FAC_LEN 20 /* Plenty to spare */
+#define X25_MAX_CUD_LEN 128
+
+struct x25_route {
+ struct x25_route *next;
+ x25_address address; /* Start of address range */
+ unsigned int sigdigits; /* Number of sig digits */
+ struct device *dev; /* More than one for MLP */
+};
+
+struct x25_neigh {
+ struct x25_neigh *next;
+ struct device *dev;
+ unsigned int state;
+ unsigned int extended;
+ struct sk_buff_head queue;
+ unsigned long t20;
+ struct timer_list t20timer;
+};
+
+typedef struct {
+ x25_address source_addr, dest_addr;
+ struct x25_neigh *neighbour;
+ unsigned int lci;
+ unsigned char state, condition, qbitincl, intflag;
+ unsigned short vs, vr, va, vl;
+ unsigned long t2, t21, t22, t23;
+ unsigned short fraglen;
+ struct sk_buff_head ack_queue;
+ struct sk_buff_head fragment_queue;
+ struct sk_buff_head interrupt_in_queue;
+ struct sk_buff_head interrupt_out_queue;
+ struct sock *sk; /* Backlink to socket */
+ struct timer_list timer;
+ struct x25_causediag causediag;
+ struct x25_facilities facilities;
+ struct x25_calluserdata calluserdata;
+} x25_cb;
+
+/* af_x25.c */
+extern int sysctl_x25_restart_request_timeout;
+extern int sysctl_x25_call_request_timeout;
+extern int sysctl_x25_reset_request_timeout;
+extern int sysctl_x25_clear_request_timeout;
+extern int sysctl_x25_ack_holdback_timeout;
+
+extern int x25_addr_ntoa(unsigned char *, x25_address *, x25_address *);
+extern int x25_addr_aton(unsigned char *, x25_address *, x25_address *);
+extern unsigned int x25_new_lci(struct x25_neigh *);
+extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
+extern void x25_destroy_socket(struct sock *);
+extern int x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
+extern void x25_kill_by_neigh(struct x25_neigh *);
+
+#include <net/x25call.h>
+
+/* x25_dev.c */
+extern void x25_send_frame(struct sk_buff *, struct x25_neigh *);
+extern int x25_lapb_receive_frame(struct sk_buff *, struct device *, struct packet_type *);
+extern int x25_llc_receive_frame(struct sk_buff *, struct device *, struct packet_type *);
+extern void x25_establish_link(struct x25_neigh *);
+extern void x25_terminate_link(struct x25_neigh *);
+
+/* x25_facilities.c */
+extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *);
+extern int x25_create_facilities(unsigned char *, struct x25_facilities *);
+extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *);
+extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
+
+/* x25_in.c */
+extern int x25_process_rx_frame(struct sock *, struct sk_buff *);
+
+/* x25_link.c */
+extern void x25_link_control(struct sk_buff *, struct x25_neigh *, unsigned short);
+extern void x25_link_device_up(struct device *);
+extern void x25_link_device_down(struct device *);
+extern void x25_link_established(struct x25_neigh *);
+extern void x25_link_terminated(struct x25_neigh *);
+extern void x25_transmit_restart_request(struct x25_neigh *);
+extern void x25_transmit_restart_confirmation(struct x25_neigh *);
+extern void x25_transmit_diagnostic(struct x25_neigh *, unsigned char);
+extern void x25_transmit_clear_request(struct x25_neigh *, unsigned int, unsigned char);
+extern void x25_transmit_link(struct sk_buff *, struct x25_neigh *);
+extern int x25_subscr_ioctl(unsigned int, void *);
+extern struct x25_neigh *x25_get_neigh(struct device *);
+extern void x25_link_free(void);
+
+/* x25_out.c */
+extern void x25_output(struct sock *, struct sk_buff *);
+extern void x25_kick(struct sock *);
+extern void x25_enquiry_response(struct sock *);
+
+/* x25_route.c */
+extern struct device *x25_get_route(x25_address *);
+extern struct device *x25_dev_get(char *);
+extern void x25_route_device_down(struct device *);
+extern int x25_route_ioctl(unsigned int, void *);
+extern int x25_routes_get_info(char *, char **, off_t, int, int);
+extern void x25_route_free(void);
+
+/* x25_subr.c */
+extern void x25_clear_queues(struct sock *);
+extern void x25_frames_acked(struct sock *, unsigned short);
+extern void x25_requeue_frames(struct sock *);
+extern int x25_validate_nr(struct sock *, unsigned short);
+extern void x25_write_internal(struct sock *, int);
+extern int x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *);
+extern void x25_disconnect(struct sock *, int, unsigned char, unsigned char);
+
+/* x25_timer.c */
+extern void x25_start_heartbeat(struct sock *);
+extern void x25_start_t2timer(struct sock *);
+extern void x25_start_t21timer(struct sock *);
+extern void x25_start_t22timer(struct sock *);
+extern void x25_start_t23timer(struct sock *);
+extern void x25_stop_heartbeat(struct sock *);
+extern void x25_stop_timer(struct sock *);
+extern unsigned long x25_display_timer(struct sock *);
+
+/* sysctl_net_x25.c */
+extern void x25_register_sysctl(void);
+extern void x25_unregister_sysctl(void);
+
+#endif
diff --git a/pfinet/linux-src/include/net/x25call.h b/pfinet/linux-src/include/net/x25call.h
new file mode 100644
index 00000000..7c478a1d
--- /dev/null
+++ b/pfinet/linux-src/include/net/x25call.h
@@ -0,0 +1,2 @@
+/* Separate to keep compilation of protocols.c simpler */
+extern void x25_proto_init(struct net_proto *pro);
diff --git a/pfinet/linux-src/net/core/Makefile b/pfinet/linux-src/net/core/Makefile
new file mode 100644
index 00000000..5df65cd2
--- /dev/null
+++ b/pfinet/linux-src/net/core/Makefile
@@ -0,0 +1,41 @@
+#
+# Makefile for the Linux networking core.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := core.o
+
+O_OBJS := sock.o skbuff.o iovec.o datagram.o scm.o
+
+ifeq ($(CONFIG_SYSCTL),y)
+ifeq ($(CONFIG_NET),y)
+O_OBJS += sysctl_net_core.o
+endif
+endif
+
+ifdef CONFIG_FILTER
+O_OBJS += filter.o
+endif
+
+ifdef CONFIG_NET
+
+O_OBJS += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o
+
+ifdef CONFIG_FIREWALL
+OX_OBJS += firewall.o
+endif
+
+endif
+
+ifdef CONFIG_NET_PROFILE
+OX_OBJS += profile.o
+endif
+
+include $(TOPDIR)/Rules.make
+
+tar:
+ tar -cvf /dev/f1 .
diff --git a/pfinet/linux-src/net/core/datagram.c b/pfinet/linux-src/net/core/datagram.c
new file mode 100644
index 00000000..9bb68fa4
--- /dev/null
+++ b/pfinet/linux-src/net/core/datagram.c
@@ -0,0 +1,249 @@
+/*
+ * SUCS NET3:
+ *
+ * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
+ * of these would make sense. Not tonight however 8-).
+ * This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical poll code and mostly
+ * identical recvmsg() code. So we share it here. The poll was shared before but buried in udp.c so I moved it.
+ *
+ * Authors: Alan Cox <alan@redhat.com>. (datagram_poll() from old udp.c code)
+ *
+ * Fixes:
+ * Alan Cox : NULL return from skb_peek_copy() understood
+ * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
+ * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
+ * AX.25 now works right, and SPX is feasible.
+ * Alan Cox : Fixed write poll of non IP protocol crash.
+ * Florian La Roche: Changed for my new skbuff handling.
+ * Darryl Miles : Fixed non-blocking SOCK_SEQPACKET.
+ * Linus Torvalds : BSD semantic fixes.
+ * Alan Cox : Datagram iovec handling
+ * Darryl Miles : Fixed non-blocking SOCK_STREAM.
+ * Alan Cox : POSIXisms
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+
+
+/*
+ * Wait for a packet..
+ *
+ * Interrupts off so that no packet arrives before we begin sleeping.
+ * Otherwise we might miss our wake up
+ */
+
+static inline void wait_for_packet(struct sock * sk)
+{
+ struct wait_queue wait = { current, NULL };
+
+ add_wait_queue(sk->sleep, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ if (skb_peek(&sk->receive_queue) == NULL)
+ schedule();
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+}
+
+/*
+ * Is a socket 'connection oriented' ?
+ */
+
+static inline int connection_based(struct sock *sk)
+{
+ return (sk->type==SOCK_SEQPACKET || sk->type==SOCK_STREAM);
+}
+
+/*
+ * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
+ * races. This replaces identical code in packet,raw and udp, as well as the IPX
+ * AX.25 and Appletalk. It also finally fixes the long standing peek and read
+ * race for datagram sockets. If you alter this routine remember it must be
+ * re-entrant.
+ *
+ * This function will lock the socket if a skb is returned, so the caller
+ * needs to unlock the socket in that case (usually by calling skb_free_datagram)
+ *
+ * * It does not lock socket since today. This function is
+ * * free of race conditions. This measure should/can improve
+ * * significantly datagram socket latencies at high loads,
+ * * when data copying to user space takes lots of time.
+ * * (BTW I've just killed the last cli() in IP/IPv6/core/netlink/packet
+ * * 8) Great win.)
+ * * --ANK (980729)
+ *
+ * The order of the tests when we find no data waiting are specified
+ * quite explicitly by POSIX 1003.1g, don't change them without having
+ * the standard around please.
+ */
+
+struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
+{
+ int error;
+ struct sk_buff *skb;
+
+ /* Caller is allowed not to check sk->err before skb_recv_datagram() */
+ error = sock_error(sk);
+ if (error)
+ goto no_packet;
+
+restart:
+ while(skb_queue_empty(&sk->receive_queue)) /* No data */
+ {
+ /* Socket errors? */
+ error = sock_error(sk);
+ if (error)
+ goto no_packet;
+
+ /* Socket shut down? */
+ if (sk->shutdown & RCV_SHUTDOWN)
+ goto no_packet;
+
+ /* Sequenced packets can come disconnected. If so we report the problem */
+ error = -ENOTCONN;
+ if(connection_based(sk) && sk->state!=TCP_ESTABLISHED)
+ goto no_packet;
+
+ /* handle signals */
+ error = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto no_packet;
+
+ /* User doesn't want to wait */
+ error = -EAGAIN;
+ if (noblock)
+ goto no_packet;
+
+ wait_for_packet(sk);
+ }
+
+ /* Again only user level code calls this function, so nothing interrupt level
+ will suddenly eat the receive_queue */
+ if (flags & MSG_PEEK)
+ {
+ unsigned long cpu_flags;
+
+ /* It is the only POTENTIAL race condition
+ in this function. skb may be stolen by
+ another receiver after peek, but before
+ incrementing use count, provided kernel
+ is reentearble (it is not) or this function
+ is called by interrupts.
+
+ Protect it with global skb spinlock,
+ though for now even this is overkill.
+ --ANK (980728)
+ */
+ spin_lock_irqsave(&skb_queue_lock, cpu_flags);
+ skb = skb_peek(&sk->receive_queue);
+ if(skb!=NULL)
+ atomic_inc(&skb->users);
+ spin_unlock_irqrestore(&skb_queue_lock, cpu_flags);
+ } else
+ skb = skb_dequeue(&sk->receive_queue);
+
+ if (!skb) /* Avoid race if someone beats us to the data */
+ goto restart;
+ return skb;
+
+no_packet:
+ *err = error;
+ return NULL;
+}
+
+void skb_free_datagram(struct sock * sk, struct sk_buff *skb)
+{
+ kfree_skb(skb);
+}
+
+/*
+ * Copy a datagram to a linear buffer.
+ */
+
+int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
+{
+ int err = -EFAULT;
+
+ if (!copy_to_user(to, skb->h.raw + offset, size))
+ err = 0;
+ return err;
+}
+
+
+/*
+ * Copy a datagram to an iovec.
+ * Note: the iovec is modified during the copy.
+ */
+
+int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to,
+ int size)
+{
+ return memcpy_toiovec(to, skb->h.raw + offset, size);
+}
+
+/*
+ * Datagram poll: Again totally generic. This also handles
+ * sequenced packet sockets providing the socket receive queue
+ * is only ever holding data ready to receive.
+ *
+ * Note: when you _don't_ use this routine for this protocol,
+ * and you use a different write policy from sock_writeable()
+ * then please supply your own write_space callback.
+ */
+
+unsigned int datagram_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+ struct sock *sk = sock->sk;
+ unsigned int mask;
+
+ poll_wait(file, sk->sleep, wait);
+ mask = 0;
+
+ /* exceptional events? */
+ if (sk->err || !skb_queue_empty(&sk->error_queue))
+ mask |= POLLERR;
+ if (sk->shutdown & RCV_SHUTDOWN)
+ mask |= POLLHUP;
+
+ /* readable? */
+ if (!skb_queue_empty(&sk->receive_queue))
+ mask |= POLLIN | POLLRDNORM;
+
+ /* Connection-based need to check for termination and startup */
+ if (connection_based(sk)) {
+ if (sk->state==TCP_CLOSE)
+ mask |= POLLHUP;
+ /* connection hasn't started yet? */
+ if (sk->state == TCP_SYN_SENT)
+ return mask;
+ }
+
+ /* writable? */
+ if (sock_writeable(sk))
+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+ else
+ sk->socket->flags |= SO_NOSPACE;
+
+ return mask;
+}
diff --git a/pfinet/linux-src/net/core/dev.c b/pfinet/linux-src/net/core/dev.c
new file mode 100644
index 00000000..92e105a1
--- /dev/null
+++ b/pfinet/linux-src/net/core/dev.c
@@ -0,0 +1,2071 @@
+/*
+ * NET3 Protocol independent device support routines.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Derived from the non IP parts of dev.c 1.0.19
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ *
+ * Additional Authors:
+ * Florian la Roche <rzsfl@rz.uni-sb.de>
+ * Alan Cox <gw4pts@gw4pts.ampr.org>
+ * David Hinds <dhinds@allegro.stanford.edu>
+ * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ * Adam Sulmicki <adam@cfar.umd.edu>
+ *
+ * Changes:
+ * Marcelo Tosatti <marcelo@conectiva.com.br> : dont accept mtu 0 or <
+ * Alan Cox : device private ioctl copies fields back.
+ * Alan Cox : Transmit queue code does relevant stunts to
+ * keep the queue safe.
+ * Alan Cox : Fixed double lock.
+ * Alan Cox : Fixed promisc NULL pointer trap
+ * ???????? : Support the full private ioctl range
+ * Alan Cox : Moved ioctl permission check into drivers
+ * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI
+ * Alan Cox : 100 backlog just doesn't cut it when
+ * you start doing multicast video 8)
+ * Alan Cox : Rewrote net_bh and list manager.
+ * Alan Cox : Fix ETH_P_ALL echoback lengths.
+ * Alan Cox : Took out transmit every packet pass
+ * Saved a few bytes in the ioctl handler
+ * Alan Cox : Network driver sets packet type before calling netif_rx. Saves
+ * a function call a packet.
+ * Alan Cox : Hashed net_bh()
+ * Richard Kooijman: Timestamp fixes.
+ * Alan Cox : Wrong field in SIOCGIFDSTADDR
+ * Alan Cox : Device lock protection.
+ * Alan Cox : Fixed nasty side effect of device close changes.
+ * Rudi Cilibrasi : Pass the right thing to set_mac_address()
+ * Dave Miller : 32bit quantity for the device lock to make it work out
+ * on a Sparc.
+ * Bjorn Ekwall : Added KERNELD hack.
+ * Alan Cox : Cleaned up the backlog initialise.
+ * Craig Metz : SIOCGIFCONF fix if space for under
+ * 1 device.
+ * Thomas Bogendoerfer : Return ENODEV for dev_open, if there
+ * is no device open function.
+ * Andi Kleen : Fix error reporting for SIOCGIFCONF
+ * Michael Chastain : Fix signed/unsigned for SIOCGIFCONF
+ * Cyrus Durgin : Cleaned for KMOD
+ * Adam Sulmicki : Bug Fix : Network Device Unload
+ * A network device unload needs to purge
+ * the backlog queue.
+ * Paul Rusty Russel : SIOCSIFNAME
+ * Andrea Arcangeli : dev_clear_backlog() needs the
+ * skb_queue_lock held.
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/notifier.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/rtnetlink.h>
+#include <net/slhc.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <net/br.h>
+#include <net/dst.h>
+#include <net/pkt_sched.h>
+#include <net/profile.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>
+#endif /* CONFIG_NET_RADIO */
+#ifdef CONFIG_PLIP
+extern int plip_init(void);
+#endif
+
+NET_PROFILE_DEFINE(dev_queue_xmit)
+NET_PROFILE_DEFINE(net_bh)
+NET_PROFILE_DEFINE(net_bh_skb)
+
+
+const char *if_port_text[] = {
+ "unknown",
+ "BNC",
+ "10baseT",
+ "AUI",
+ "100baseT",
+ "100baseTX",
+ "100baseFX"
+};
+
+/*
+ * The list of packet types we will receive (as opposed to discard)
+ * and the routines to invoke.
+ *
+ * Why 16. Because with 16 the only overlap we get on a hash of the
+ * low nibble of the protocol value is RARP/SNAP/X.25.
+ *
+ * 0800 IP
+ * 0001 802.3
+ * 0002 AX.25
+ * 0004 802.2
+ * 8035 RARP
+ * 0005 SNAP
+ * 0805 X.25
+ * 0806 ARP
+ * 8137 IPX
+ * 0009 Localtalk
+ * 86DD IPv6
+ */
+
+struct packet_type *ptype_base[16]; /* 16 way hashed list */
+struct packet_type *ptype_all = NULL; /* Taps */
+
+/*
+ * Device list lock. Setting it provides that interface
+ * will not disappear unexpectedly while kernel sleeps.
+ */
+
+atomic_t dev_lockct = ATOMIC_INIT(0);
+
+/*
+ * Our notifier list
+ */
+
+#ifdef _HURD_
+struct notifier_block *netdev_chain=NULL;
+#else
+static struct notifier_block *netdev_chain=NULL;
+#endif
+
+/*
+ * Device drivers call our routines to queue packets here. We empty the
+ * queue in the bottom half handler.
+ */
+
+static struct sk_buff_head backlog;
+
+#ifdef CONFIG_NET_FASTROUTE
+int netdev_fastroute;
+int netdev_fastroute_obstacles;
+struct net_fastroute_stats dev_fastroute_stat;
+#endif
+
+static void dev_clear_backlog(struct device *dev);
+
+
+/******************************************************************************************
+
+ Protocol management and registration routines
+
+*******************************************************************************************/
+
+/*
+ * For efficiency
+ */
+
+int netdev_nit=0;
+
+/*
+ * Add a protocol ID to the list. Now that the input handler is
+ * smarter we can dispense with all the messy stuff that used to be
+ * here.
+ *
+ * BEWARE!!! Protocol handlers, mangling input packets,
+ * MUST BE last in hash buckets and checking protocol handlers
+ * MUST start from promiscuous ptype_all chain in net_bh.
+ * It is true now, do not change it.
+ * Explantion follows: if protocol handler, mangling packet, will
+ * be the first on list, it is not able to sense, that packet
+ * is cloned and should be copied-on-write, so that it will
+ * change it and subsequent readers will get broken packet.
+ * --ANK (980803)
+ */
+
+void dev_add_pack(struct packet_type *pt)
+{
+ int hash;
+#ifdef CONFIG_NET_FASTROUTE
+ /* Hack to detect packet socket */
+ if (pt->data) {
+ netdev_fastroute_obstacles++;
+ dev_clear_fastroute(pt->dev);
+ }
+#endif
+ if(pt->type==htons(ETH_P_ALL))
+ {
+ netdev_nit++;
+ pt->next=ptype_all;
+ ptype_all=pt;
+ }
+ else
+ {
+ hash=ntohs(pt->type)&15;
+ pt->next = ptype_base[hash];
+ ptype_base[hash] = pt;
+ }
+}
+
+
+/*
+ * Remove a protocol ID from the list.
+ */
+
+void dev_remove_pack(struct packet_type *pt)
+{
+ struct packet_type **pt1;
+ if(pt->type==htons(ETH_P_ALL))
+ {
+ netdev_nit--;
+ pt1=&ptype_all;
+ }
+ else
+ pt1=&ptype_base[ntohs(pt->type)&15];
+ for(; (*pt1)!=NULL; pt1=&((*pt1)->next))
+ {
+ if(pt==(*pt1))
+ {
+ *pt1=pt->next;
+ synchronize_bh();
+#ifdef CONFIG_NET_FASTROUTE
+ if (pt->data)
+ netdev_fastroute_obstacles--;
+#endif
+ return;
+ }
+ }
+ printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
+}
+
+/*****************************************************************************************
+
+ Device Interface Subroutines
+
+******************************************************************************************/
+
+/*
+ * Find an interface by name.
+ */
+
+struct device *dev_get(const char *name)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if (strcmp(dev->name, name) == 0)
+ return(dev);
+ }
+ return NULL;
+}
+
+struct device * dev_get_by_index(int ifindex)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if (dev->ifindex == ifindex)
+ return(dev);
+ }
+ return NULL;
+}
+
+struct device *dev_getbyhwaddr(unsigned short type, char *ha)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ if (dev->type == type &&
+ memcmp(dev->dev_addr, ha, dev->addr_len) == 0)
+ return(dev);
+ }
+ return(NULL);
+}
+
+/*
+ * Passed a format string - eg "lt%d" it will try and find a suitable
+ * id. Not efficient for many devices, not called a lot..
+ */
+
+int dev_alloc_name(struct device *dev, const char *name)
+{
+ int i;
+ /*
+ * If you need over 100 please also fix the algorithm...
+ */
+ for(i=0;i<100;i++)
+ {
+ sprintf(dev->name,name,i);
+ if(dev_get(dev->name)==NULL)
+ return i;
+ }
+ return -ENFILE; /* Over 100 of the things .. bail out! */
+}
+
+struct device *dev_alloc(const char *name, int *err)
+{
+ struct device *dev=kmalloc(sizeof(struct device)+16, GFP_KERNEL);
+ if(dev==NULL)
+ {
+ *err=-ENOBUFS;
+ return NULL;
+ }
+ dev->name=(char *)(dev+1); /* Name string space */
+ *err=dev_alloc_name(dev,name);
+ if(*err<0)
+ {
+ kfree(dev);
+ return NULL;
+ }
+ return dev;
+}
+
+void netdev_state_change(struct device *dev)
+{
+ if (dev->flags&IFF_UP)
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
+}
+
+
+/*
+ * Find and possibly load an interface.
+ */
+
+#ifdef CONFIG_KMOD
+
+void dev_load(const char *name)
+{
+ if(!dev_get(name) && capable(CAP_SYS_MODULE))
+ request_module(name);
+}
+
+#else
+
+extern inline void dev_load(const char *unused){;}
+
+#endif
+
+static int default_rebuild_header(struct sk_buff *skb)
+{
+ printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n", skb->dev ? skb->dev->name : "NULL!!!");
+ kfree_skb(skb);
+ return 1;
+}
+
+/*
+ * Prepare an interface for use.
+ */
+
+int dev_open(struct device *dev)
+{
+ int ret = 0;
+
+ /*
+ * Is it already up?
+ */
+
+ if (dev->flags&IFF_UP)
+ return 0;
+
+ /*
+ * Call device private open method
+ */
+
+ if (dev->open)
+ ret = dev->open(dev);
+
+ /*
+ * If it went open OK then:
+ */
+
+ if (ret == 0)
+ {
+ /*
+ * nil rebuild_header routine,
+ * that should be never called and used as just bug trap.
+ */
+
+ if (dev->rebuild_header == NULL)
+ dev->rebuild_header = default_rebuild_header;
+
+ /*
+ * Set the flags.
+ */
+ dev->flags |= (IFF_UP | IFF_RUNNING);
+
+ /*
+ * Initialize multicasting status
+ */
+ dev_mc_upload(dev);
+
+ /*
+ * Wakeup transmit queue engine
+ */
+ dev_activate(dev);
+
+ /*
+ * ... and announce new interface.
+ */
+ notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
+
+ }
+ return(ret);
+}
+
+#ifdef CONFIG_NET_FASTROUTE
+
+static __inline__ void dev_do_clear_fastroute(struct device *dev)
+{
+ if (dev->accept_fastpath) {
+ int i;
+
+ for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++)
+ dst_release_irqwait(xchg(dev->fastpath+i, NULL));
+ }
+}
+
+void dev_clear_fastroute(struct device *dev)
+{
+ if (dev) {
+ dev_do_clear_fastroute(dev);
+ } else {
+ for (dev = dev_base; dev; dev = dev->next)
+ dev_do_clear_fastroute(dev);
+ }
+}
+#endif
+
+/*
+ * Completely shutdown an interface.
+ */
+
+int dev_close(struct device *dev)
+{
+ if (!(dev->flags&IFF_UP))
+ return 0;
+
+ dev_deactivate(dev);
+
+ dev_lock_wait();
+
+ /*
+ * Call the device specific close. This cannot fail.
+ * Only if device is UP
+ */
+
+ if (dev->stop)
+ dev->stop(dev);
+
+ if (dev->start)
+ printk("dev_close: bug %s still running\n", dev->name);
+
+ /*
+ * Device is now down.
+ */
+ dev_clear_backlog(dev);
+
+ dev->flags&=~(IFF_UP|IFF_RUNNING);
+#ifdef CONFIG_NET_FASTROUTE
+ dev_clear_fastroute(dev);
+#endif
+
+ /*
+ * Tell people we are going down
+ */
+ notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
+
+ return(0);
+}
+
+
+/*
+ * Device change register/unregister. These are not inline or static
+ * as we export them to the world.
+ */
+
+int register_netdevice_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_register(&netdev_chain, nb);
+}
+
+int unregister_netdevice_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_unregister(&netdev_chain,nb);
+}
+
+/*
+ * Support routine. Sends outgoing frames to any network
+ * taps currently in use.
+ */
+
+void dev_queue_xmit_nit(struct sk_buff *skb, struct device *dev)
+{
+ struct packet_type *ptype;
+ get_fast_time(&skb->stamp);
+
+ for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next)
+ {
+ /* Never send packets back to the socket
+ * they originated from - MvS (miquels@drinkel.ow.org)
+ */
+ if ((ptype->dev == dev || !ptype->dev) &&
+ ((struct sock *)ptype->data != skb->sk))
+ {
+ struct sk_buff *skb2;
+ if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
+ break;
+
+ /* Code, following below is wrong.
+
+ The only reason, why it does work is that
+ ONLY packet sockets receive outgoing
+ packets. If such a packet will be (occasionally)
+ received by normal packet handler, which expects
+ that mac header is pulled...
+ */
+
+ /* More sensible variant. skb->nh should be correctly
+ set by sender, so that the second statement is
+ just protection against buggy protocols.
+ */
+ skb2->mac.raw = skb2->data;
+
+ if (skb2->nh.raw < skb2->data || skb2->nh.raw >= skb2->tail) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name);
+ skb2->nh.raw = skb2->data;
+ if (dev->hard_header)
+ skb2->nh.raw += dev->hard_header_len;
+ }
+
+ skb2->h.raw = skb2->nh.raw;
+ skb2->pkt_type = PACKET_OUTGOING;
+ ptype->func(skb2, skb->dev, ptype);
+ }
+ }
+}
+
+/*
+ * Fast path for loopback frames.
+ */
+
+void dev_loopback_xmit(struct sk_buff *skb)
+{
+ struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
+ if (newskb==NULL)
+ return;
+
+ newskb->mac.raw = newskb->data;
+ skb_pull(newskb, newskb->nh.raw - newskb->data);
+ newskb->pkt_type = PACKET_LOOPBACK;
+ newskb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (newskb->dst==NULL)
+ printk(KERN_DEBUG "BUG: packet without dst looped back 1\n");
+ netif_rx(newskb);
+}
+
+int dev_queue_xmit(struct sk_buff *skb)
+{
+ struct device *dev = skb->dev;
+ struct Qdisc *q;
+
+#ifdef CONFIG_NET_PROFILE
+ start_bh_atomic();
+ NET_PROFILE_ENTER(dev_queue_xmit);
+#endif
+
+ start_bh_atomic();
+ q = dev->qdisc;
+ if (q->enqueue) {
+ q->enqueue(skb, q);
+ qdisc_wakeup(dev);
+ end_bh_atomic();
+
+#ifdef CONFIG_NET_PROFILE
+ NET_PROFILE_LEAVE(dev_queue_xmit);
+ end_bh_atomic();
+#endif
+
+ return 0;
+ }
+
+ /* The device has no queue. Common case for software devices:
+ loopback, all the sorts of tunnels...
+
+ Really, it is unlikely that bh protection is necessary here:
+ virtual devices do not generate EOI events.
+ However, it is possible, that they rely on bh protection
+ made by us here.
+ */
+ if (dev->flags&IFF_UP) {
+ if (netdev_nit)
+ dev_queue_xmit_nit(skb,dev);
+ if (dev->hard_start_xmit(skb, dev) == 0) {
+ end_bh_atomic();
+
+#ifdef CONFIG_NET_PROFILE
+ NET_PROFILE_LEAVE(dev_queue_xmit);
+ end_bh_atomic();
+#endif
+
+ return 0;
+ }
+ if (net_ratelimit())
+ printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name);
+ }
+ end_bh_atomic();
+
+ kfree_skb(skb);
+
+#ifdef CONFIG_NET_PROFILE
+ NET_PROFILE_LEAVE(dev_queue_xmit);
+ end_bh_atomic();
+#endif
+
+ return 0;
+}
+
+
+/*=======================================================================
+ Receiver rotutines
+ =======================================================================*/
+
+int netdev_dropping = 0;
+int netdev_max_backlog = 300;
+atomic_t netdev_rx_dropped;
+#ifdef CONFIG_CPU_IS_SLOW
+int net_cpu_congestion;
+#endif
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+int netdev_throttle_events;
+static unsigned long netdev_fc_mask = 1;
+unsigned long netdev_fc_xoff = 0;
+
+static struct
+{
+ void (*stimul)(struct device *);
+ struct device *dev;
+} netdev_fc_slots[32];
+
+int netdev_register_fc(struct device *dev, void (*stimul)(struct device *dev))
+{
+ int bit = 0;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (netdev_fc_mask != ~0UL) {
+ bit = ffz(netdev_fc_mask);
+ netdev_fc_slots[bit].stimul = stimul;
+ netdev_fc_slots[bit].dev = dev;
+ set_bit(bit, &netdev_fc_mask);
+ clear_bit(bit, &netdev_fc_xoff);
+ }
+ restore_flags(flags);
+ return bit;
+}
+
+void netdev_unregister_fc(int bit)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (bit > 0) {
+ netdev_fc_slots[bit].stimul = NULL;
+ netdev_fc_slots[bit].dev = NULL;
+ clear_bit(bit, &netdev_fc_mask);
+ clear_bit(bit, &netdev_fc_xoff);
+ }
+ restore_flags(flags);
+}
+
+static void netdev_wakeup(void)
+{
+ unsigned long xoff;
+
+ cli();
+ xoff = netdev_fc_xoff;
+ netdev_fc_xoff = 0;
+ netdev_dropping = 0;
+ netdev_throttle_events++;
+ while (xoff) {
+ int i = ffz(~xoff);
+ xoff &= ~(1<<i);
+ netdev_fc_slots[i].stimul(netdev_fc_slots[i].dev);
+ }
+ sti();
+}
+#endif
+
+static void dev_clear_backlog(struct device *dev)
+{
+ struct sk_buff *curr;
+ unsigned long flags;
+
+ /*
+ *
+ * Let now clear backlog queue. -AS
+ *
+ * We are competing here both with netif_rx() and net_bh().
+ * We don't want either of those to mess with skb ptrs
+ * while we work on them, thus we must grab the
+ * skb_queue_lock.
+ */
+
+ if (backlog.qlen) {
+ repeat:
+ spin_lock_irqsave(&skb_queue_lock, flags);
+ for (curr = backlog.next;
+ curr != (struct sk_buff *)(&backlog);
+ curr = curr->next)
+ if (curr->dev == dev)
+ {
+ __skb_unlink(curr, &backlog);
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+ kfree_skb(curr);
+ goto repeat;
+ }
+ spin_unlock_irqrestore(&skb_queue_lock, flags);
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if (netdev_dropping)
+ netdev_wakeup();
+#else
+ netdev_dropping = 0;
+#endif
+ }
+}
+
+/*
+ * Receive a packet from a device driver and queue it for the upper
+ * (protocol) levels. It always succeeds.
+ */
+
+void netif_rx(struct sk_buff *skb)
+{
+#ifndef CONFIG_CPU_IS_SLOW
+ if(skb->stamp.tv_sec==0)
+ get_fast_time(&skb->stamp);
+#else
+ skb->stamp = xtime;
+#endif
+
+ /* The code is rearranged so that the path is the most
+ short when CPU is congested, but is still operating.
+ */
+
+ if (backlog.qlen <= netdev_max_backlog) {
+ if (backlog.qlen) {
+ if (netdev_dropping == 0) {
+ skb_queue_tail(&backlog,skb);
+ mark_bh(NET_BH);
+ return;
+ }
+ atomic_inc(&netdev_rx_dropped);
+ kfree_skb(skb);
+ return;
+ }
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if (netdev_dropping)
+ netdev_wakeup();
+#else
+ netdev_dropping = 0;
+#endif
+ skb_queue_tail(&backlog,skb);
+ mark_bh(NET_BH);
+ return;
+ }
+ netdev_dropping = 1;
+ atomic_inc(&netdev_rx_dropped);
+ kfree_skb(skb);
+}
+
+#ifdef CONFIG_BRIDGE
+static inline void handle_bridge(struct sk_buff *skb, unsigned short type)
+{
+ /*
+ * The br_stats.flags is checked here to save the expense of a
+ * function call.
+ */
+ if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type))
+ {
+ /*
+ * We pass the bridge a complete frame. This means
+ * recovering the MAC header first.
+ */
+
+ int offset;
+
+ skb=skb_clone(skb, GFP_ATOMIC);
+ if(skb==NULL)
+ return;
+
+ offset=skb->data-skb->mac.raw;
+ skb_push(skb,offset); /* Put header back on for bridge */
+
+ if(br_receive_frame(skb))
+ return;
+ kfree_skb(skb);
+ }
+ return;
+}
+#endif
+
+/*
+ * When we are called the queue is ready to grab, the interrupts are
+ * on and hardware can interrupt and queue to the receive queue as we
+ * run with no problems.
+ * This is run as a bottom half after an interrupt handler that does
+ * mark_bh(NET_BH);
+ */
+
+void net_bh(void)
+{
+ struct packet_type *ptype;
+ struct packet_type *pt_prev;
+ unsigned short type;
+#ifndef _HURD_
+ unsigned long start_time = jiffies;
+#ifdef CONFIG_CPU_IS_SLOW
+ static unsigned long start_busy = 0;
+ static unsigned long ave_busy = 0;
+
+ if (start_busy == 0)
+ start_busy = start_time;
+ net_cpu_congestion = ave_busy>>8;
+#endif
+#endif
+
+ NET_PROFILE_ENTER(net_bh);
+ /*
+ * Can we send anything now? We want to clear the
+ * decks for any more sends that get done as we
+ * process the input. This also minimises the
+ * latency on a transmit interrupt bh.
+ */
+
+ if (qdisc_head.forw != &qdisc_head)
+ qdisc_run_queues();
+
+ /*
+ * Any data left to process. This may occur because a
+ * mark_bh() is done after we empty the queue including
+ * that from the device which does a mark_bh() just after
+ */
+
+ /*
+ * While the queue is not empty..
+ *
+ * Note that the queue never shrinks due to
+ * an interrupt, so we can do this test without
+ * disabling interrupts.
+ */
+
+ while (!skb_queue_empty(&backlog))
+ {
+ struct sk_buff * skb;
+
+#ifndef _HURD_
+ /* Give chance to other bottom halves to run */
+ if (jiffies - start_time > 1)
+ goto net_bh_break;
+#endif
+
+ /*
+ * We have a packet. Therefore the queue has shrunk
+ */
+ skb = skb_dequeue(&backlog);
+
+#ifndef _HURD_
+#ifdef CONFIG_CPU_IS_SLOW
+ if (ave_busy > 128*16) {
+ kfree_skb(skb);
+ while ((skb = skb_dequeue(&backlog)) != NULL)
+ kfree_skb(skb);
+ break;
+ }
+#endif
+#endif
+
+
+#if 0
+ NET_PROFILE_SKB_PASSED(skb, net_bh_skb);
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+ if (skb->pkt_type == PACKET_FASTROUTE) {
+ dev_queue_xmit(skb);
+ continue;
+ }
+#endif
+
+ /*
+ * Bump the pointer to the next structure.
+ *
+ * On entry to the protocol layer. skb->data and
+ * skb->nh.raw point to the MAC and encapsulated data
+ */
+
+ /* XXX until we figure out every place to modify.. */
+ skb->h.raw = skb->nh.raw = skb->data;
+
+ if (skb->mac.raw < skb->head || skb->mac.raw > skb->data) {
+ printk(KERN_CRIT "%s: wrong mac.raw ptr, proto=%04x\n", skb->dev->name, skb->protocol);
+ kfree_skb(skb);
+ continue;
+ }
+
+ /*
+ * Fetch the packet protocol ID.
+ */
+
+ type = skb->protocol;
+
+#ifdef CONFIG_BRIDGE
+ /*
+ * If we are bridging then pass the frame up to the
+ * bridging code (if this protocol is to be bridged).
+ * If it is bridged then move on
+ */
+ handle_bridge(skb, type);
+#endif
+
+ /*
+ * We got a packet ID. Now loop over the "known protocols"
+ * list. There are two lists. The ptype_all list of taps (normally empty)
+ * and the main protocol list which is hashed perfectly for normal protocols.
+ */
+
+ pt_prev = NULL;
+ for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)
+ {
+ if (!ptype->dev || ptype->dev == skb->dev) {
+ if(pt_prev)
+ {
+ struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);
+ if(skb2)
+ pt_prev->func(skb2,skb->dev, pt_prev);
+ }
+ pt_prev=ptype;
+ }
+ }
+
+ for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next)
+ {
+ if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev))
+ {
+ /*
+ * We already have a match queued. Deliver
+ * to it and then remember the new match
+ */
+ if(pt_prev)
+ {
+ struct sk_buff *skb2;
+
+ skb2=skb_clone(skb, GFP_ATOMIC);
+
+ /*
+ * Kick the protocol handler. This should be fast
+ * and efficient code.
+ */
+
+ if(skb2)
+ pt_prev->func(skb2, skb->dev, pt_prev);
+ }
+ /* Remember the current last to do */
+ pt_prev=ptype;
+ }
+ } /* End of protocol list loop */
+
+ /*
+ * Is there a last item to send to ?
+ */
+
+ if(pt_prev)
+ pt_prev->func(skb, skb->dev, pt_prev);
+ /*
+ * Has an unknown packet has been received ?
+ */
+
+ else {
+ kfree_skb(skb);
+ }
+ } /* End of queue loop */
+
+ /*
+ * We have emptied the queue
+ */
+
+ /*
+ * One last output flush.
+ */
+
+ if (qdisc_head.forw != &qdisc_head)
+ qdisc_run_queues();
+
+#ifndef _HURD_
+#ifdef CONFIG_CPU_IS_SLOW
+ if (1) {
+ unsigned long start_idle = jiffies;
+ ave_busy += ((start_idle - start_busy)<<3) - (ave_busy>>4);
+ start_busy = 0;
+ }
+#endif
+#endif
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if (netdev_dropping)
+ netdev_wakeup();
+#else
+ netdev_dropping = 0;
+#endif
+ NET_PROFILE_LEAVE(net_bh);
+ return;
+
+#ifndef _HURD_
+net_bh_break:
+ mark_bh(NET_BH);
+ NET_PROFILE_LEAVE(net_bh);
+ return;
+#endif
+}
+
+/* Protocol dependent address dumping routines */
+
+static gifconf_func_t * gifconf_list [NPROTO];
+
+int register_gifconf(unsigned int family, gifconf_func_t * gifconf)
+{
+ if (family>=NPROTO)
+ return -EINVAL;
+ gifconf_list[family] = gifconf;
+ return 0;
+}
+
+
+/*
+ * Map an interface index to its name (SIOCGIFNAME)
+ */
+
+/*
+ * This call is useful, but I'd remove it too.
+ *
+ * The reason is purely aestetical, it is the only call
+ * from SIOC* family using struct ifreq in reversed manner.
+ * Besides that, it is pretty silly to put "drawing" facility
+ * to kernel, it is useful only to print ifindices
+ * in readable form, is not it? --ANK
+ *
+ * We need this ioctl for efficient implementation of the
+ * if_indextoname() function required by the IPv6 API. Without
+ * it, we would have to search all the interfaces to find a
+ * match. --pb
+ */
+
+static int dev_ifname(struct ifreq *arg)
+{
+ struct device *dev;
+ struct ifreq ifr;
+ int err;
+
+ /*
+ * Fetch the caller's info block.
+ */
+
+ err = copy_from_user(&ifr, arg, sizeof(struct ifreq));
+ if (err)
+ return -EFAULT;
+
+ dev = dev_get_by_index(ifr.ifr_ifindex);
+ if (!dev)
+ return -ENODEV;
+
+ strcpy(ifr.ifr_name, dev->name);
+
+ err = copy_to_user(arg, &ifr, sizeof(struct ifreq));
+ return (err)?-EFAULT:0;
+}
+
+/*
+ * Perform a SIOCGIFCONF call. This structure will change
+ * size eventually, and there is nothing I can do about it.
+ * Thus we will need a 'compatibility mode'.
+ */
+
+#ifdef _HURD_
+int dev_ifconf(char *arg)
+#else
+static int dev_ifconf(char *arg)
+#endif
+{
+ struct ifconf ifc;
+ struct device *dev;
+ char *pos;
+ int len;
+ int total;
+ int i;
+
+ /*
+ * Fetch the caller's info block.
+ */
+
+ if (copy_from_user(&ifc, arg, sizeof(struct ifconf)))
+ return -EFAULT;
+
+ pos = ifc.ifc_buf;
+ len = ifc.ifc_len;
+
+ /*
+ * Loop over the interfaces, and write an info block for each.
+ */
+
+ total = 0;
+ for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for (i=0; i<NPROTO; i++) {
+ if (gifconf_list[i]) {
+ int done;
+ if (pos==NULL) {
+ done = gifconf_list[i](dev, NULL, 0);
+ } else {
+ done = gifconf_list[i](dev, pos+total, len-total);
+ }
+ if (done<0)
+ return -EFAULT;
+ total += done;
+ }
+ }
+ }
+
+ /*
+ * All done. Write the updated control block back to the caller.
+ */
+ ifc.ifc_len = total;
+
+ if (copy_to_user(arg, &ifc, sizeof(struct ifconf)))
+ return -EFAULT;
+
+ /*
+ * Both BSD and Solaris return 0 here, so we do too.
+ */
+ return 0;
+}
+
+/*
+ * This is invoked by the /proc filesystem handler to display a device
+ * in detail.
+ */
+
+#ifdef CONFIG_PROC_FS
+static int sprintf_stats(char *buffer, struct device *dev)
+{
+ struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
+ int size;
+
+ if (stats)
+ size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+ dev->name,
+ stats->rx_bytes,
+ stats->rx_packets, stats->rx_errors,
+ stats->rx_dropped + stats->rx_missed_errors,
+ stats->rx_fifo_errors,
+ stats->rx_length_errors + stats->rx_over_errors
+ + stats->rx_crc_errors + stats->rx_frame_errors,
+ stats->rx_compressed, stats->multicast,
+ stats->tx_bytes,
+ stats->tx_packets, stats->tx_errors, stats->tx_dropped,
+ stats->tx_fifo_errors, stats->collisions,
+ stats->tx_carrier_errors + stats->tx_aborted_errors
+ + stats->tx_window_errors + stats->tx_heartbeat_errors,
+ stats->tx_compressed);
+ else
+ size = sprintf(buffer, "%6s: No statistics available.\n", dev->name);
+
+ return size;
+}
+
+/*
+ * Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface
+ * to create /proc/net/dev
+ */
+
+int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int len=0;
+ off_t begin=0;
+ off_t pos=0;
+ int size;
+
+ struct device *dev;
+
+
+ size = sprintf(buffer,
+ "Inter-| Receive | Transmit\n"
+ " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n");
+
+ pos+=size;
+ len+=size;
+
+
+ for (dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ size = sprintf_stats(buffer+len, dev);
+ len+=size;
+ pos=begin+len;
+
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ break;
+ }
+
+ *start=buffer+(offset-begin); /* Start of wanted data */
+ len-=(offset-begin); /* Start slop */
+ if(len>length)
+ len=length; /* Ending slop */
+ return len;
+}
+
+static int dev_proc_stats(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(buffer, "%08x %08x %08x %08x %08x\n",
+ atomic_read(&netdev_rx_dropped),
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ netdev_throttle_events,
+#else
+ 0,
+#endif
+#ifdef CONFIG_NET_FASTROUTE
+ dev_fastroute_stat.hits,
+ dev_fastroute_stat.succeed,
+ dev_fastroute_stat.deferred
+#else
+ 0, 0, 0
+#endif
+ );
+
+ len -= offset;
+
+ if (len > length)
+ len = length;
+ if(len < 0)
+ len = 0;
+
+ *start = buffer + offset;
+ *eof = 1;
+
+ return len;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+
+#ifdef CONFIG_NET_RADIO
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Print one entry of /proc/net/wireless
+ * This is a clone of /proc/net/dev (just above)
+ */
+static int sprintf_wireless_stats(char *buffer, struct device *dev)
+{
+ /* Get stats from the driver */
+ struct iw_statistics *stats = (dev->get_wireless_stats ?
+ dev->get_wireless_stats(dev) :
+ (struct iw_statistics *) NULL);
+ int size;
+
+ if(stats != (struct iw_statistics *) NULL)
+ {
+ size = sprintf(buffer,
+ "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d\n",
+ dev->name,
+ stats->status,
+ stats->qual.qual,
+ stats->qual.updated & 1 ? '.' : ' ',
+ stats->qual.level,
+ stats->qual.updated & 2 ? '.' : ' ',
+ stats->qual.noise,
+ stats->qual.updated & 4 ? '.' : ' ',
+ stats->discard.nwid,
+ stats->discard.code,
+ stats->discard.misc);
+ stats->qual.updated = 0;
+ }
+ else
+ size = 0;
+
+ return size;
+}
+
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ * This is a clone of /proc/net/dev (just above)
+ */
+int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+ int length, int dummy)
+{
+ int len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+ int size;
+
+ struct device * dev;
+
+ size = sprintf(buffer,
+ "Inter-| sta-| Quality | Discarded packets\n"
+ " face | tus | link level noise | nwid crypt misc\n"
+ );
+
+ pos+=size;
+ len+=size;
+
+ for(dev = dev_base; dev != NULL; dev = dev->next)
+ {
+ size = sprintf_wireless_stats(buffer+len, dev);
+ len+=size;
+ pos=begin+len;
+
+ if(pos < offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos > offset + length)
+ break;
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if(len > length)
+ len = length; /* Ending slop */
+
+ return len;
+}
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_NET_RADIO */
+
+void dev_set_promiscuity(struct device *dev, int inc)
+{
+ unsigned short old_flags = dev->flags;
+
+ dev->flags |= IFF_PROMISC;
+ if ((dev->promiscuity += inc) == 0)
+ dev->flags &= ~IFF_PROMISC;
+ if (dev->flags^old_flags) {
+#ifdef CONFIG_NET_FASTROUTE
+ if (dev->flags&IFF_PROMISC) {
+ netdev_fastroute_obstacles++;
+ dev_clear_fastroute(dev);
+ } else
+ netdev_fastroute_obstacles--;
+#endif
+ dev_mc_upload(dev);
+ printk(KERN_INFO "device %s %s promiscuous mode\n",
+ dev->name, (dev->flags&IFF_PROMISC) ? "entered" : "left");
+ }
+}
+
+void dev_set_allmulti(struct device *dev, int inc)
+{
+ unsigned short old_flags = dev->flags;
+
+ dev->flags |= IFF_ALLMULTI;
+ if ((dev->allmulti += inc) == 0)
+ dev->flags &= ~IFF_ALLMULTI;
+ if (dev->flags^old_flags)
+ dev_mc_upload(dev);
+}
+
+int dev_change_flags(struct device *dev, unsigned flags)
+{
+ int ret;
+ int old_flags = dev->flags;
+
+ /*
+ * Set the flags on our device.
+ */
+
+ dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_RUNNING|IFF_NOARP|
+ IFF_SLAVE|IFF_MASTER|IFF_DYNAMIC|
+ IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) |
+ (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI));
+
+ /*
+ * Load in the correct multicast list now the flags have changed.
+ */
+
+ dev_mc_upload(dev);
+
+ /*
+ * Have we downed the interface. We handle IFF_UP ourselves
+ * according to user attempts to set it, rather than blindly
+ * setting it.
+ */
+
+ ret = 0;
+ if ((old_flags^flags)&IFF_UP) /* Bit is different ? */
+ {
+ ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
+
+ if (ret == 0)
+ dev_mc_upload(dev);
+ }
+
+ if (dev->flags&IFF_UP &&
+ ((old_flags^dev->flags)&~(IFF_UP|IFF_RUNNING|IFF_PROMISC|IFF_ALLMULTI|IFF_VOLATILE)))
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
+
+ if ((flags^dev->gflags)&IFF_PROMISC) {
+ int inc = (flags&IFF_PROMISC) ? +1 : -1;
+ dev->gflags ^= IFF_PROMISC;
+ dev_set_promiscuity(dev, inc);
+ }
+
+ /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI
+ is important. Some (broken) drivers set IFF_PROMISC, when
+ IFF_ALLMULTI is requested not asking us and not reporting.
+ */
+ if ((flags^dev->gflags)&IFF_ALLMULTI) {
+ int inc = (flags&IFF_ALLMULTI) ? +1 : -1;
+ dev->gflags ^= IFF_ALLMULTI;
+ dev_set_allmulti(dev, inc);
+ }
+
+ return ret;
+}
+
+#ifdef _HURD_
+
+#define dev_ioctl 0
+
+#else
+
+/*
+ * Perform the SIOCxIFxxx calls.
+ */
+
+static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
+{
+ struct device *dev;
+ int err;
+
+ if ((dev = dev_get(ifr->ifr_name)) == NULL)
+ return -ENODEV;
+
+ switch(cmd)
+ {
+ case SIOCGIFFLAGS: /* Get interface flags */
+ ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+ |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));
+ return 0;
+
+ case SIOCSIFFLAGS: /* Set interface flags */
+ return dev_change_flags(dev, ifr->ifr_flags);
+
+ case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */
+ ifr->ifr_metric = 0;
+ return 0;
+
+ case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */
+ return -EOPNOTSUPP;
+
+ case SIOCGIFMTU: /* Get the MTU of a device */
+ ifr->ifr_mtu = dev->mtu;
+ return 0;
+
+ case SIOCSIFMTU: /* Set the MTU of a device */
+ if (ifr->ifr_mtu == dev->mtu)
+ return 0;
+
+ /*
+ * MTU must be positive.
+ */
+
+ if (ifr->ifr_mtu<=0)
+ return -EINVAL;
+
+ if (dev->change_mtu)
+ err = dev->change_mtu(dev, ifr->ifr_mtu);
+ else {
+ dev->mtu = ifr->ifr_mtu;
+ err = 0;
+ }
+ if (!err && dev->flags&IFF_UP)
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev);
+ return err;
+
+ case SIOCGIFHWADDR:
+ memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN);
+ ifr->ifr_hwaddr.sa_family=dev->type;
+ return 0;
+
+ case SIOCSIFHWADDR:
+ if(dev->set_mac_address==NULL)
+ return -EOPNOTSUPP;
+ if(ifr->ifr_hwaddr.sa_family!=dev->type)
+ return -EINVAL;
+ err=dev->set_mac_address(dev,&ifr->ifr_hwaddr);
+ if (!err)
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+ return err;
+
+ case SIOCSIFHWBROADCAST:
+ if(ifr->ifr_hwaddr.sa_family!=dev->type)
+ return -EINVAL;
+ memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN);
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+ return 0;
+
+ case SIOCGIFMAP:
+ ifr->ifr_map.mem_start=dev->mem_start;
+ ifr->ifr_map.mem_end=dev->mem_end;
+ ifr->ifr_map.base_addr=dev->base_addr;
+ ifr->ifr_map.irq=dev->irq;
+ ifr->ifr_map.dma=dev->dma;
+ ifr->ifr_map.port=dev->if_port;
+ return 0;
+
+ case SIOCSIFMAP:
+ if (dev->set_config)
+ return dev->set_config(dev,&ifr->ifr_map);
+ return -EOPNOTSUPP;
+
+ case SIOCADDMULTI:
+ if(dev->set_multicast_list==NULL ||
+ ifr->ifr_hwaddr.sa_family!=AF_UNSPEC)
+ return -EINVAL;
+ dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1);
+ return 0;
+
+ case SIOCDELMULTI:
+ if(dev->set_multicast_list==NULL ||
+ ifr->ifr_hwaddr.sa_family!=AF_UNSPEC)
+ return -EINVAL;
+ dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1);
+ return 0;
+
+ case SIOCGIFINDEX:
+ ifr->ifr_ifindex = dev->ifindex;
+ return 0;
+
+ case SIOCGIFTXQLEN:
+ ifr->ifr_qlen = dev->tx_queue_len;
+ return 0;
+
+ case SIOCSIFTXQLEN:
+ if(ifr->ifr_qlen<0)
+ return -EINVAL;
+ dev->tx_queue_len = ifr->ifr_qlen;
+ return 0;
+
+ case SIOCSIFNAME:
+ if (dev->flags&IFF_UP)
+ return -EBUSY;
+ if (dev_get(ifr->ifr_newname))
+ return -EEXIST;
+ memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);
+ dev->name[IFNAMSIZ-1] = 0;
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+ return 0;
+
+ /*
+ * Unknown or private ioctl
+ */
+
+ default:
+ if(cmd >= SIOCDEVPRIVATE &&
+ cmd <= SIOCDEVPRIVATE + 15) {
+ if (dev->do_ioctl)
+ return dev->do_ioctl(dev, ifr, cmd);
+ return -EOPNOTSUPP;
+ }
+
+#ifdef CONFIG_NET_RADIO
+ if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
+ if (dev->do_ioctl)
+ return dev->do_ioctl(dev, ifr, cmd);
+ return -EOPNOTSUPP;
+ }
+#endif /* CONFIG_NET_RADIO */
+
+ }
+ return -EINVAL;
+}
+
+
+/*
+ * This function handles all "interface"-type I/O control requests. The actual
+ * 'doing' part of this is dev_ifsioc above.
+ */
+
+int dev_ioctl(unsigned int cmd, void *arg)
+{
+ struct ifreq ifr;
+ int ret;
+ char *colon;
+
+ /* One special case: SIOCGIFCONF takes ifconf argument
+ and requires shared lock, because it sleeps writing
+ to user space.
+ */
+
+ if (cmd == SIOCGIFCONF) {
+ rtnl_shlock();
+ ret = dev_ifconf((char *) arg);
+ rtnl_shunlock();
+ return ret;
+ }
+ if (cmd == SIOCGIFNAME) {
+ return dev_ifname((struct ifreq *)arg);
+ }
+
+ if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
+ return -EFAULT;
+
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+
+ colon = strchr(ifr.ifr_name, ':');
+ if (colon)
+ *colon = 0;
+
+ /*
+ * See which interface the caller is talking about.
+ */
+
+ switch(cmd)
+ {
+ /*
+ * These ioctl calls:
+ * - can be done by all.
+ * - atomic and do not require locking.
+ * - return a value
+ */
+
+ case SIOCGIFFLAGS:
+ case SIOCGIFMETRIC:
+ case SIOCGIFMTU:
+ case SIOCGIFHWADDR:
+ case SIOCGIFSLAVE:
+ case SIOCGIFMAP:
+ case SIOCGIFINDEX:
+ case SIOCGIFTXQLEN:
+ dev_load(ifr.ifr_name);
+ ret = dev_ifsioc(&ifr, cmd);
+ if (!ret) {
+ if (colon)
+ *colon = ':';
+ if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+ return -EFAULT;
+ }
+ return ret;
+
+ /*
+ * These ioctl calls:
+ * - require superuser power.
+ * - require strict serialization.
+ * - do not return a value
+ */
+
+ case SIOCSIFFLAGS:
+ case SIOCSIFMETRIC:
+ case SIOCSIFMTU:
+ case SIOCSIFMAP:
+ case SIOCSIFHWADDR:
+ case SIOCSIFSLAVE:
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ case SIOCSIFHWBROADCAST:
+ case SIOCSIFTXQLEN:
+ case SIOCSIFNAME:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ dev_load(ifr.ifr_name);
+ rtnl_lock();
+ ret = dev_ifsioc(&ifr, cmd);
+ rtnl_unlock();
+ return ret;
+
+ case SIOCGIFMEM:
+ /* Get the per device memory space. We can add this but currently
+ do not support it */
+ case SIOCSIFMEM:
+ /* Set the per device memory buffer space. Not applicable in our case */
+ case SIOCSIFLINK:
+ return -EINVAL;
+
+ /*
+ * Unknown or private ioctl.
+ */
+
+ default:
+ if (cmd >= SIOCDEVPRIVATE &&
+ cmd <= SIOCDEVPRIVATE + 15) {
+ dev_load(ifr.ifr_name);
+ rtnl_lock();
+ ret = dev_ifsioc(&ifr, cmd);
+ rtnl_unlock();
+ if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+ return -EFAULT;
+ return ret;
+ }
+#ifdef CONFIG_NET_RADIO
+ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
+ dev_load(ifr.ifr_name);
+ if (IW_IS_SET(cmd)) {
+ if (!suser())
+ return -EPERM;
+ rtnl_lock();
+ }
+ ret = dev_ifsioc(&ifr, cmd);
+ if (IW_IS_SET(cmd))
+ rtnl_unlock();
+ if (!ret && IW_IS_GET(cmd) &&
+ copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+ return -EFAULT;
+ return ret;
+ }
+#endif /* CONFIG_NET_RADIO */
+ return -EINVAL;
+ }
+}
+
+#endif
+
+int dev_new_index(void)
+{
+ static int ifindex;
+ for (;;) {
+ if (++ifindex <= 0)
+ ifindex=1;
+ if (dev_get_by_index(ifindex) == NULL)
+ return ifindex;
+ }
+}
+
+static int dev_boot_phase = 1;
+
+
+int register_netdevice(struct device *dev)
+{
+ struct device *d, **dp;
+
+ if (dev_boot_phase) {
+ /* This is NOT bug, but I am not sure, that all the
+ devices, initialized before netdev module is started
+ are sane.
+
+ Now they are chained to device boot list
+ and probed later. If a module is initialized
+ before netdev, but assumes that dev->init
+ is really called by register_netdev(), it will fail.
+
+ So that this message should be printed for a while.
+ */
+ printk(KERN_INFO "early initialization of device %s is deferred\n", dev->name);
+
+ /* Check for existence, and append to tail of chain */
+ for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
+ if (d == dev || strcmp(d->name, dev->name) == 0)
+ return -EEXIST;
+ }
+ dev->next = NULL;
+ *dp = dev;
+ return 0;
+ }
+
+ dev->iflink = -1;
+
+ /* Init, if this function is available */
+ if (dev->init && dev->init(dev) != 0)
+ return -EIO;
+
+ /* Check for existence, and append to tail of chain */
+ for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
+ if (d == dev || strcmp(d->name, dev->name) == 0)
+ return -EEXIST;
+ }
+ dev->next = NULL;
+ dev_init_scheduler(dev);
+ dev->ifindex = dev_new_index();
+ if (dev->iflink == -1)
+ dev->iflink = dev->ifindex;
+ *dp = dev;
+
+ /* Notify protocols, that a new device appeared. */
+ notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
+
+ return 0;
+}
+
+int unregister_netdevice(struct device *dev)
+{
+ struct device *d, **dp;
+
+ if (dev_boot_phase == 0) {
+ /* If device is running, close it.
+ It is very bad idea, really we should
+ complain loudly here, but random hackery
+ in linux/drivers/net likes it.
+ */
+ if (dev->flags & IFF_UP)
+ dev_close(dev);
+
+#ifdef CONFIG_NET_FASTROUTE
+ dev_clear_fastroute(dev);
+#endif
+
+ /* Shutdown queueing discipline. */
+ dev_shutdown(dev);
+
+ /* Notify protocols, that we are about to destroy
+ this device. They should clean all the things.
+ */
+ notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
+
+ /*
+ * Flush the multicast chain
+ */
+ dev_mc_discard(dev);
+
+ /* To avoid pointers looking to nowhere,
+ we wait for end of critical section */
+ dev_lock_wait();
+ }
+
+ /* And unlink it from device chain. */
+ for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) {
+ if (d == dev) {
+ *dp = d->next;
+ synchronize_bh();
+ d->next = NULL;
+
+ if (dev->destructor)
+ dev->destructor(dev);
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+
+/*
+ * Initialize the DEV module. At boot time this walks the device list and
+ * unhooks any devices that fail to initialise (normally hardware not
+ * present) and leaves us with a valid list of present and active devices.
+ *
+ */
+extern int lance_init(void);
+extern int bpq_init(void);
+extern int scc_init(void);
+extern void sdla_setup(void);
+extern void sdla_c_setup(void);
+extern void dlci_setup(void);
+extern int dmascc_init(void);
+extern int sm_init(void);
+
+extern int baycom_ser_fdx_init(void);
+extern int baycom_ser_hdx_init(void);
+extern int baycom_par_init(void);
+
+extern int lapbeth_init(void);
+extern int comx_init(void);
+extern void arcnet_init(void);
+extern void ip_auto_config(void);
+#ifdef CONFIG_8xx
+extern int cpm_enet_init(void);
+#endif /* CONFIG_8xx */
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_dev = {
+ PROC_NET_DEV, 3, "dev",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ dev_get_info
+};
+#endif
+
+#ifdef CONFIG_NET_RADIO
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_wireless = {
+ PROC_NET_WIRELESS, 8, "wireless",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ dev_get_wireless_info
+};
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_NET_RADIO */
+
+__initfunc(int net_dev_init(void))
+{
+ struct device *dev, **dp;
+
+#ifdef CONFIG_NET_SCHED
+ pktsched_init();
+#endif
+
+ /*
+ * Initialise the packet receive queue.
+ */
+
+ skb_queue_head_init(&backlog);
+
+ /*
+ * The bridge has to be up before the devices
+ */
+
+#ifdef CONFIG_BRIDGE
+ br_init();
+#endif
+
+ /*
+ * This is Very Ugly(tm).
+ *
+ * Some devices want to be initialized early..
+ */
+
+#if defined(CONFIG_SCC)
+ scc_init();
+#endif
+#if defined(CONFIG_DMASCC)
+ dmascc_init();
+#endif
+#if defined(CONFIG_BPQETHER)
+ bpq_init();
+#endif
+#if defined(CONFIG_DLCI)
+ dlci_setup();
+#endif
+#if defined(CONFIG_SDLA)
+ sdla_c_setup();
+#endif
+#if defined(CONFIG_BAYCOM_PAR)
+ baycom_par_init();
+#endif
+#if defined(CONFIG_BAYCOM_SER_FDX)
+ baycom_ser_fdx_init();
+#endif
+#if defined(CONFIG_BAYCOM_SER_HDX)
+ baycom_ser_hdx_init();
+#endif
+#if defined(CONFIG_SOUNDMODEM)
+ sm_init();
+#endif
+#if defined(CONFIG_LAPBETHER)
+ lapbeth_init();
+#endif
+#if defined(CONFIG_PLIP)
+ plip_init();
+#endif
+#if defined(CONFIG_ARCNET)
+ arcnet_init();
+#endif
+#if defined(CONFIG_8xx)
+ cpm_enet_init();
+#endif
+#if defined(CONFIG_COMX)
+ comx_init();
+#endif
+ /*
+ * SLHC if present needs attaching so other people see it
+ * even if not opened.
+ */
+
+#ifdef CONFIG_INET
+#if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \
+ || defined(CONFIG_PPP) \
+ || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP))
+ slhc_install();
+#endif
+#endif
+
+#ifdef CONFIG_NET_PROFILE
+ net_profile_init();
+ NET_PROFILE_REGISTER(dev_queue_xmit);
+ NET_PROFILE_REGISTER(net_bh);
+#if 0
+ NET_PROFILE_REGISTER(net_bh_skb);
+#endif
+#endif
+ /*
+ * Add the devices.
+ * If the call to dev->init fails, the dev is removed
+ * from the chain disconnecting the device until the
+ * next reboot.
+ */
+
+ dp = &dev_base;
+ while ((dev = *dp) != NULL)
+ {
+ dev->iflink = -1;
+ if (dev->init && dev->init(dev))
+ {
+ /*
+ * It failed to come up. Unhook it.
+ */
+ *dp = dev->next;
+ synchronize_bh();
+ }
+ else
+ {
+ dp = &dev->next;
+ dev->ifindex = dev_new_index();
+ if (dev->iflink == -1)
+ dev->iflink = dev->ifindex;
+ dev_init_scheduler(dev);
+ }
+ }
+
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_net_dev);
+ {
+ struct proc_dir_entry *ent = create_proc_entry("net/dev_stat", 0, 0);
+ ent->read_proc = dev_proc_stats;
+ }
+#endif
+
+#ifdef CONFIG_NET_RADIO
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_net_wireless);
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_NET_RADIO */
+
+ init_bh(NET_BH, net_bh);
+
+ dev_boot_phase = 0;
+
+ dev_mcast_init();
+
+#ifdef CONFIG_BRIDGE
+ /*
+ * Register any statically linked ethernet devices with the bridge
+ */
+ br_spacedevice_register();
+#endif
+
+#ifdef CONFIG_IP_PNP
+ ip_auto_config();
+#endif
+
+ return 0;
+}
diff --git a/pfinet/linux-src/net/core/dev_mcast.c b/pfinet/linux-src/net/core/dev_mcast.c
new file mode 100644
index 00000000..bce3f4a4
--- /dev/null
+++ b/pfinet/linux-src/net/core/dev_mcast.c
@@ -0,0 +1,252 @@
+/*
+ * Linux NET3: Multicast List maintenance.
+ *
+ * Authors:
+ * Tim Kordas <tjk@nostromo.eeap.cwru.edu>
+ * Richard Underwood <richard@wuzz.demon.co.uk>
+ *
+ * Stir fried together from the IP multicast and CAP patches above
+ * Alan Cox <Alan.Cox@linux.org>
+ *
+ * Fixes:
+ * Alan Cox : Update the device on a real delete
+ * rather than any time but...
+ * Alan Cox : IFF_ALLMULTI support.
+ * Alan Cox : New format set_multicast_list() calls.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/arp.h>
+
+
+/*
+ * Device multicast list maintenance.
+ *
+ * This is used both by IP and by the user level maintenance functions.
+ * Unlike BSD we maintain a usage count on a given multicast address so
+ * that a casual user application can add/delete multicasts used by
+ * protocols without doing damage to the protocols when it deletes the
+ * entries. It also helps IP as it tracks overlapping maps.
+ *
+ * Device mc lists are changed by bh at least if IPv6 is enabled,
+ * so that it must be bh protected.
+ */
+
+/*
+ * Update the multicast list into the physical NIC controller.
+ */
+
+void dev_mc_upload(struct device *dev)
+{
+ /* Don't do anything till we up the interface
+ [dev_open will call this function so the list will
+ stay sane] */
+
+ if(!(dev->flags&IFF_UP))
+ return;
+
+ /*
+ * Devices with no set multicast don't get set
+ */
+
+ if(dev->set_multicast_list==NULL)
+ return;
+
+ start_bh_atomic();
+ dev->set_multicast_list(dev);
+ end_bh_atomic();
+}
+
+/*
+ * Delete a device level multicast
+ */
+
+int dev_mc_delete(struct device *dev, void *addr, int alen, int glbl)
+{
+ int err = 0;
+ struct dev_mc_list *dmi, **dmip;
+
+ start_bh_atomic();
+ for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
+ /*
+ * Find the entry we want to delete. The device could
+ * have variable length entries so check these too.
+ */
+ if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && alen==dmi->dmi_addrlen) {
+ if (glbl) {
+ int old_glbl = dmi->dmi_gusers;
+ dmi->dmi_gusers = 0;
+ if (old_glbl == 0)
+ break;
+ }
+ if(--dmi->dmi_users)
+ goto done;
+
+ /*
+ * Last user. So delete the entry.
+ */
+ *dmip = dmi->next;
+ dev->mc_count--;
+ kfree_s(dmi,sizeof(*dmi));
+ /*
+ * We have altered the list, so the card
+ * loaded filter is now wrong. Fix it
+ */
+ end_bh_atomic();
+ dev_mc_upload(dev);
+ return 0;
+ }
+ }
+ err = -ENOENT;
+done:
+ end_bh_atomic();
+ return err;
+}
+
+/*
+ * Add a device level multicast
+ */
+
+int dev_mc_add(struct device *dev, void *addr, int alen, int glbl)
+{
+ int err = 0;
+ struct dev_mc_list *dmi, *dmi1;
+
+ dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), gfp_any());
+
+ start_bh_atomic();
+ for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) {
+ if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) {
+ if (glbl) {
+ int old_glbl = dmi->dmi_gusers;
+ dmi->dmi_gusers = 1;
+ if (old_glbl)
+ goto done;
+ }
+ dmi->dmi_users++;
+ goto done;
+ }
+ }
+
+ if ((dmi=dmi1)==NULL)
+ return -ENOMEM;
+ memcpy(dmi->dmi_addr, addr, alen);
+ dmi->dmi_addrlen=alen;
+ dmi->next=dev->mc_list;
+ dmi->dmi_users=1;
+ dmi->dmi_gusers=glbl ? 1 : 0;
+ dev->mc_list=dmi;
+ dev->mc_count++;
+ end_bh_atomic();
+ dev_mc_upload(dev);
+ return 0;
+
+done:
+ end_bh_atomic();
+ if (dmi1)
+ kfree(dmi1);
+ return err;
+}
+
+/*
+ * Discard multicast list when a device is downed
+ */
+
+void dev_mc_discard(struct device *dev)
+{
+ start_bh_atomic();
+ while (dev->mc_list!=NULL) {
+ struct dev_mc_list *tmp=dev->mc_list;
+ dev->mc_list=tmp->next;
+ if (tmp->dmi_users > tmp->dmi_gusers)
+ printk("dev_mc_discard: multicast leakage! dmi_users=%d\n", tmp->dmi_users);
+ kfree_s(tmp,sizeof(*tmp));
+ }
+ dev->mc_count=0;
+ end_bh_atomic();
+}
+
+#ifdef CONFIG_PROC_FS
+static int dev_mc_read_proc(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
+{
+ off_t pos=0, begin=0;
+ struct dev_mc_list *m;
+ int len=0;
+ struct device *dev;
+
+ start_bh_atomic();
+
+ for (dev = dev_base; dev; dev = dev->next) {
+ for (m = dev->mc_list; m; m = m->next) {
+ int i;
+
+ len += sprintf(buffer+len,"%-4d %-15s %-5d %-5d ", dev->ifindex, dev->name,
+ m->dmi_users, m->dmi_gusers);
+
+ for (i=0; i<m->dmi_addrlen; i++)
+ len += sprintf(buffer+len, "%02x", m->dmi_addr[i]);
+
+ len+=sprintf(buffer+len, "\n");
+
+ pos=begin+len;
+ if (pos < offset) {
+ len=0;
+ begin=pos;
+ }
+ if (pos > offset+length)
+ goto done;
+ }
+ }
+ *eof = 1;
+
+done:
+ end_bh_atomic();
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ if(len<0)
+ len=0;
+ return len;
+}
+#endif
+
+__initfunc(void dev_mcast_init(void))
+{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent;
+
+ ent = create_proc_entry("net/dev_mcast", 0, 0);
+ ent->read_proc = dev_mc_read_proc;
+#endif
+}
+
diff --git a/pfinet/linux-src/net/core/dst.c b/pfinet/linux-src/net/core/dst.c
new file mode 100644
index 00000000..9007dde6
--- /dev/null
+++ b/pfinet/linux-src/net/core/dst.c
@@ -0,0 +1,145 @@
+/*
+ * net/dst.c Protocol independent destination cache.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include <net/dst.h>
+
+struct dst_entry * dst_garbage_list;
+atomic_t dst_total = ATOMIC_INIT(0);
+
+static unsigned long dst_gc_timer_expires;
+static unsigned long dst_gc_timer_inc = DST_GC_MAX;
+static void dst_run_gc(unsigned long);
+
+static struct timer_list dst_gc_timer =
+ { NULL, NULL, DST_GC_MIN, 0L, dst_run_gc };
+
+#if RT_CACHE_DEBUG >= 2
+atomic_t hh_count;
+#endif
+
+static void dst_run_gc(unsigned long dummy)
+{
+ int delayed = 0;
+ struct dst_entry * dst, **dstp;
+
+ del_timer(&dst_gc_timer);
+ dstp = &dst_garbage_list;
+ while ((dst = *dstp) != NULL) {
+ if (atomic_read(&dst->use)) {
+ dstp = &dst->next;
+ delayed++;
+ continue;
+ }
+ *dstp = dst->next;
+ dst_destroy(dst);
+ }
+ if (!dst_garbage_list) {
+ dst_gc_timer_inc = DST_GC_MAX;
+ return;
+ }
+ if ((dst_gc_timer_expires += dst_gc_timer_inc) > DST_GC_MAX)
+ dst_gc_timer_expires = DST_GC_MAX;
+ dst_gc_timer_inc += DST_GC_INC;
+ dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
+#if RT_CACHE_DEBUG >= 2
+ printk("dst_total: %d/%d %ld\n",
+ atomic_read(&dst_total), delayed, dst_gc_timer_expires);
+#endif
+ add_timer(&dst_gc_timer);
+}
+
+static int dst_discard(struct sk_buff *skb)
+{
+ kfree_skb(skb);
+ return 0;
+}
+
+static int dst_blackhole(struct sk_buff *skb)
+{
+ kfree_skb(skb);
+ return 0;
+}
+
+void * dst_alloc(int size, struct dst_ops * ops)
+{
+ struct dst_entry * dst;
+
+ if (ops->gc && atomic_read(&ops->entries) > ops->gc_thresh) {
+ if (ops->gc())
+ return NULL;
+ }
+ dst = kmalloc(size, GFP_ATOMIC);
+ if (!dst)
+ return NULL;
+ memset(dst, 0, size);
+ dst->ops = ops;
+ atomic_set(&dst->refcnt, 0);
+ dst->lastuse = jiffies;
+ dst->input = dst_discard;
+ dst->output = dst_blackhole;
+ atomic_inc(&dst_total);
+ atomic_inc(&ops->entries);
+ return dst;
+}
+
+void __dst_free(struct dst_entry * dst)
+{
+ start_bh_atomic();
+ /* The first case (dev==NULL) is required, when
+ protocol module is unloaded.
+ */
+ if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) {
+ dst->input = dst_discard;
+ dst->output = dst_blackhole;
+ dst->dev = &loopback_dev;
+ }
+ dst->obsolete = 2;
+ dst->next = dst_garbage_list;
+ dst_garbage_list = dst;
+ if (dst_gc_timer_inc > DST_GC_INC) {
+ del_timer(&dst_gc_timer);
+ dst_gc_timer_inc = DST_GC_INC;
+ dst_gc_timer_expires = DST_GC_MIN;
+ dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
+ add_timer(&dst_gc_timer);
+ }
+ end_bh_atomic();
+}
+
+void dst_destroy(struct dst_entry * dst)
+{
+ struct neighbour *neigh = dst->neighbour;
+ struct hh_cache *hh = dst->hh;
+
+ dst->hh = NULL;
+ if (hh && atomic_dec_and_test(&hh->hh_refcnt))
+ kfree(hh);
+
+ if (neigh) {
+ dst->neighbour = NULL;
+ neigh_release(neigh);
+ }
+
+ atomic_dec(&dst->ops->entries);
+
+ if (dst->ops->destroy)
+ dst->ops->destroy(dst);
+ atomic_dec(&dst_total);
+ kfree(dst);
+}
diff --git a/pfinet/linux-src/net/core/filter.c b/pfinet/linux-src/net/core/filter.c
new file mode 100644
index 00000000..8e1ffb62
--- /dev/null
+++ b/pfinet/linux-src/net/core/filter.c
@@ -0,0 +1,454 @@
+/*
+ * Linux Socket Filter - Kernel level socket filtering
+ *
+ * Author:
+ * Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
+ *
+ * Based on the design of:
+ * - The Berkeley Packet Filter
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Andi Kleen - Fix a few bad bugs and races.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_FILTER)
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_packet.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/filter.h>
+
+/* No hurry in this branch */
+
+static u8 *load_pointer(struct sk_buff *skb, int k)
+{
+ u8 *ptr = NULL;
+
+ if (k>=SKF_NET_OFF)
+ ptr = skb->nh.raw + k - SKF_NET_OFF;
+ else if (k>=SKF_LL_OFF)
+ ptr = skb->mac.raw + k - SKF_LL_OFF;
+
+ if (ptr<skb->head && ptr < skb->tail)
+ return ptr;
+ return NULL;
+}
+
+/*
+ * Decode and apply filter instructions to the skb->data.
+ * Return length to keep, 0 for none. skb is the data we are
+ * filtering, filter is the array of filter instructions, and
+ * len is the number of filter blocks in the array.
+ */
+
+int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
+{
+ unsigned char *data = skb->data;
+ /* len is UNSIGNED. Byte wide insns relies only on implicit
+ type casts to prevent reading arbitrary memory locations.
+ */
+ unsigned int len = skb->len;
+ struct sock_filter *fentry; /* We walk down these */
+ u32 A = 0; /* Accumulator */
+ u32 X = 0; /* Index Register */
+ u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */
+ int k;
+ int pc;
+
+ /*
+ * Process array of filter instructions.
+ */
+
+ for(pc = 0; pc < flen; pc++)
+ {
+ fentry = &filter[pc];
+
+ switch(fentry->code)
+ {
+ case BPF_ALU|BPF_ADD|BPF_X:
+ A += X;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ A += fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ A -= X;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ A -= fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ A *= X;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ A *= fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ if(X == 0)
+ return (0);
+ A /= X;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ if(fentry->k == 0)
+ return (0);
+ A /= fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ A &= X;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ A &= fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ A |= X;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ A |= fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ A <<= X;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ A <<= fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ A >>= X;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ A >>= fentry->k;
+ continue;
+
+ case BPF_ALU|BPF_NEG:
+ A = -A;
+ continue;
+
+ case BPF_JMP|BPF_JA:
+ pc += fentry->k;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ pc += (A > fentry->k) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ pc += (A >= fentry->k) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ pc += (A == fentry->k) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ pc += (A & fentry->k) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ pc += (A > X) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ pc += (A >= X) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ pc += (A == X) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ pc += (A & X) ? fentry->jt : fentry->jf;
+ continue;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ k = fentry->k;
+load_w:
+ if(k+sizeof(u32) <= len) {
+ A = ntohl(*(u32*)&data[k]);
+ continue;
+ }
+ if (k<0) {
+ u8 *ptr;
+
+ if (k>=SKF_AD_OFF)
+ break;
+ if ((ptr = load_pointer(skb, k)) != NULL) {
+ A = ntohl(*(u32*)ptr);
+ continue;
+ }
+ }
+ return 0;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ k = fentry->k;
+load_h:
+ if(k + sizeof(u16) <= len) {
+ A = ntohs(*(u16*)&data[k]);
+ continue;
+ }
+ if (k<0) {
+ u8 *ptr;
+
+ if (k>=SKF_AD_OFF)
+ break;
+ if ((ptr = load_pointer(skb, k)) != NULL) {
+ A = ntohs(*(u16*)ptr);
+ continue;
+ }
+ }
+ return 0;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ k = fentry->k;
+load_b:
+ if(k < len) {
+ A = data[k];
+ continue;
+ }
+ if (k<0) {
+ u8 *ptr;
+
+ if (k>=SKF_AD_OFF)
+ break;
+ if ((ptr = load_pointer(skb, k)) != NULL) {
+ A = *ptr;
+ continue;
+ }
+ }
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ A = len;
+ continue;
+
+ case BPF_LDX|BPF_W|BPF_LEN:
+ X = len;
+ continue;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ k = X + fentry->k;
+ goto load_w;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ k = X + fentry->k;
+ goto load_h;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ k = X + fentry->k;
+ goto load_b;
+
+ case BPF_LDX|BPF_B|BPF_MSH:
+ k = fentry->k;
+ if(k >= len)
+ return (0);
+ X = (data[k] & 0xf) << 2;
+ continue;
+
+ case BPF_LD|BPF_IMM:
+ A = fentry->k;
+ continue;
+
+ case BPF_LDX|BPF_IMM:
+ X = fentry->k;
+ continue;
+
+ case BPF_LD|BPF_MEM:
+ A = mem[fentry->k];
+ continue;
+
+ case BPF_LDX|BPF_MEM:
+ X = mem[fentry->k];
+ continue;
+
+ case BPF_MISC|BPF_TAX:
+ X = A;
+ continue;
+
+ case BPF_MISC|BPF_TXA:
+ A = X;
+ continue;
+
+ case BPF_RET|BPF_K:
+ return ((unsigned int)fentry->k);
+
+ case BPF_RET|BPF_A:
+ return ((unsigned int)A);
+
+ case BPF_ST:
+ mem[fentry->k] = A;
+ continue;
+
+ case BPF_STX:
+ mem[fentry->k] = X;
+ continue;
+
+ default:
+ /* Invalid instruction counts as RET */
+ return (0);
+ }
+
+ /* Handle ancillary data, which are impossible
+ (or very difficult) to get parsing packet contents.
+ */
+ switch (k-SKF_AD_OFF) {
+ case SKF_AD_PROTOCOL:
+ A = htons(skb->protocol);
+ continue;
+ case SKF_AD_PKTTYPE:
+ A = skb->pkt_type;
+ continue;
+ case SKF_AD_IFINDEX:
+ A = skb->dev->ifindex;
+ continue;
+ default:
+ return 0;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Check the user's filter code. If we let some ugly
+ * filter code slip through kaboom!
+ */
+
+int sk_chk_filter(struct sock_filter *filter, int flen)
+{
+ struct sock_filter *ftest;
+ int pc;
+
+ /*
+ * Check the filter code now.
+ */
+ for(pc = 0; pc < flen; pc++)
+ {
+ /*
+ * All jumps are forward as they are not signed
+ */
+
+ ftest = &filter[pc];
+ if(BPF_CLASS(ftest->code) == BPF_JMP)
+ {
+ /*
+ * But they mustn't jump off the end.
+ */
+ if(BPF_OP(ftest->code) == BPF_JA)
+ {
+ /* Note, the large ftest->k might cause
+ loops. Compare this with conditional
+ jumps below, where offsets are limited. --ANK (981016)
+ */
+ if (ftest->k >= (unsigned)(flen-pc-1))
+ return (-EINVAL);
+ }
+ else
+ {
+ /*
+ * For conditionals both must be safe
+ */
+ if(pc + ftest->jt +1 >= flen || pc + ftest->jf +1 >= flen)
+ return (-EINVAL);
+ }
+ }
+
+ /*
+ * Check that memory operations use valid addresses.
+ */
+
+ if (ftest->k >= BPF_MEMWORDS)
+ {
+ /*
+ * But it might not be a memory operation...
+ */
+ switch (ftest->code) {
+ case BPF_ST:
+ case BPF_STX:
+ case BPF_LD|BPF_MEM:
+ case BPF_LDX|BPF_MEM:
+ return -EINVAL;
+ }
+ }
+ }
+
+ /*
+ * The program must end with a return. We don't care where they
+ * jumped within the script (its always forwards) but in the
+ * end they _will_ hit this.
+ */
+
+ return (BPF_CLASS(filter[flen - 1].code) == BPF_RET)?0:-EINVAL;
+}
+
+/*
+ * Attach the user's filter code. We first run some sanity checks on
+ * it to make sure it does not explode on us later.
+ */
+
+int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
+{
+ struct sk_filter *fp;
+ unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
+ int err;
+
+ /* Make sure new filter is there and in the right amounts. */
+ if (fprog->filter == NULL || fprog->len > BPF_MAXINSNS)
+ return (-EINVAL);
+
+ fp = (struct sk_filter *)sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL);
+ if(fp == NULL)
+ return (-ENOMEM);
+
+ if (copy_from_user(fp->insns, fprog->filter, fsize)) {
+ sock_kfree_s(sk, fp, fsize+sizeof(*fp));
+ return -EFAULT;
+ }
+
+ atomic_set(&fp->refcnt, 1);
+ fp->len = fprog->len;
+
+ if ((err = sk_chk_filter(fp->insns, fp->len))==0) {
+ struct sk_filter *old_fp = sk->filter;
+ sk->filter = fp;
+ synchronize_bh();
+ fp = old_fp;
+ }
+
+ if (fp)
+ sk_filter_release(sk, fp);
+
+ return (err);
+}
+#endif /* CONFIG_FILTER */
diff --git a/pfinet/linux-src/net/core/firewall.c b/pfinet/linux-src/net/core/firewall.c
new file mode 100644
index 00000000..fc7b1a51
--- /dev/null
+++ b/pfinet/linux-src/net/core/firewall.c
@@ -0,0 +1,160 @@
+/*
+ * Generic loadable firewalls. At the moment only IP will actually
+ * use these, but people can add the others as they are needed.
+ *
+ * Authors: Dave Bonn (for IP)
+ * much hacked by: Alan Cox
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/firewall.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+
+struct semaphore firewall_sem = MUTEX;
+static int firewall_policy[NPROTO];
+static struct firewall_ops *firewall_chain[NPROTO];
+
+/*
+ * Register a firewall
+ */
+
+int register_firewall(int pf, struct firewall_ops *fw)
+{
+ struct firewall_ops **p;
+
+ if(pf<0||pf>=NPROTO)
+ return -EINVAL;
+
+ /*
+ * Don't allow two people to adjust at once.
+ */
+
+ down(&firewall_sem);
+
+ p=&firewall_chain[pf];
+
+ while(*p)
+ {
+ if(fw->fw_priority > (*p)->fw_priority)
+ break;
+ p=&((*p)->next);
+ }
+
+ /*
+ * We need to use a memory barrier to make sure that this
+ * works correctly even in SMP with weakly ordered writes.
+ *
+ * This is atomic wrt interrupts (and generally walking the
+ * chain), but not wrt itself (so you can't call this from
+ * an interrupt. Not that you'd want to).
+ */
+
+ fw->next=*p;
+ mb();
+ *p = fw;
+
+ /*
+ * And release the sleep lock
+ */
+
+ up(&firewall_sem);
+ return 0;
+}
+
+/*
+ * Unregister a firewall
+ */
+
+int unregister_firewall(int pf, struct firewall_ops *fw)
+{
+ struct firewall_ops **nl;
+
+ if(pf<0||pf>=NPROTO)
+ return -EINVAL;
+
+ /*
+ * Don't allow two people to adjust at once.
+ */
+
+ down(&firewall_sem);
+
+ nl=&firewall_chain[pf];
+
+ while(*nl!=NULL)
+ {
+ if(*nl==fw)
+ {
+ struct firewall_ops *f=fw->next;
+ *nl = f;
+ up(&firewall_sem);
+ synchronize_bh();
+ return 0;
+ }
+ nl=&((*nl)->next);
+ }
+ up(&firewall_sem);
+ return -ENOENT;
+}
+
+int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+ struct firewall_ops *fw=firewall_chain[pf];
+
+ while(fw!=NULL)
+ {
+ int rc=fw->fw_forward(fw,pf,dev,phdr,arg,skb);
+ if(rc!=FW_SKIP)
+ return rc;
+ fw=fw->next;
+ }
+ return firewall_policy[pf];
+}
+
+/*
+ * Actual invocation of the chains
+ */
+
+int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+ struct firewall_ops *fw=firewall_chain[pf];
+
+ while(fw!=NULL)
+ {
+ int rc=fw->fw_input(fw,pf,dev,phdr,arg,skb);
+ if(rc!=FW_SKIP)
+ return rc;
+ fw=fw->next;
+ }
+ return firewall_policy[pf];
+}
+
+int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+ struct firewall_ops *fw=firewall_chain[pf];
+
+ while(fw!=NULL)
+ {
+ int rc=fw->fw_output(fw,pf,dev,phdr,arg,skb);
+ if(rc!=FW_SKIP)
+ return rc;
+ fw=fw->next;
+ }
+ /* alan, is this right? */
+ return firewall_policy[pf];
+}
+
+EXPORT_SYMBOL(register_firewall);
+EXPORT_SYMBOL(unregister_firewall);
+EXPORT_SYMBOL(call_in_firewall);
+EXPORT_SYMBOL(call_out_firewall);
+EXPORT_SYMBOL(call_fw_firewall);
+
+__initfunc(void fwchain_init(void))
+{
+ int i;
+ for(i=0;i<NPROTO;i++)
+ firewall_policy[i]=FW_ACCEPT;
+}
diff --git a/pfinet/linux-src/net/core/iovec.c b/pfinet/linux-src/net/core/iovec.c
new file mode 100644
index 00000000..c20f8530
--- /dev/null
+++ b/pfinet/linux-src/net/core/iovec.c
@@ -0,0 +1,278 @@
+/*
+ * iovec manipulation routines.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ * Andrew Lunn : Errors in iovec copying.
+ * Pedro Roque : Added memcpy_fromiovecend and
+ * csum_..._fromiovecend.
+ * Andi Kleen : fixed error handling for 2.1
+ * Alexey Kuznetsov: 2.1 optimisations
+ * Andi Kleen : Fix csum*fromiovecend for IPv6.
+ */
+
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <net/checksum.h>
+
+/*
+ * Verify iovec. The caller must ensure that the iovec is big enough
+ * to hold the message iovec.
+ *
+ * Save time not doing verify_area. copy_*_user will make this work
+ * in any case.
+ */
+
+int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
+{
+ int size, err, ct;
+
+ if(m->msg_namelen)
+ {
+ if(mode==VERIFY_READ)
+ {
+ err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
+ if(err<0)
+ goto out;
+ }
+
+ m->msg_name = address;
+ } else
+ m->msg_name = NULL;
+
+ err = -EFAULT;
+ size = m->msg_iovlen * sizeof(struct iovec);
+ if (copy_from_user(iov, m->msg_iov, size))
+ goto out;
+ m->msg_iov=iov;
+
+ for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) {
+ err += iov[ct].iov_len;
+ /* Goal is not to verify user data, but to prevent returning
+ negative value, which is interpreted as errno.
+ Overflow is still possible, but it is harmless.
+ */
+ if (err < 0)
+ return -EMSGSIZE;
+ }
+out:
+ return err;
+}
+
+/*
+ * Copy kernel to iovec. Returns -EFAULT on error.
+ *
+ * Note: this modifies the original iovec.
+ */
+
+int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
+{
+ int err = -EFAULT;
+
+ while(len>0)
+ {
+ if(iov->iov_len)
+ {
+ int copy = min(iov->iov_len, len);
+ if (copy_to_user(iov->iov_base, kdata, copy))
+ goto out;
+ kdata+=copy;
+ len-=copy;
+ iov->iov_len-=copy;
+ iov->iov_base+=copy;
+ }
+ iov++;
+ }
+ err = 0;
+out:
+ return err;
+}
+
+/*
+ * In kernel copy to iovec. Returns -EFAULT on error.
+ *
+ * Note: this modifies the original iovec.
+ */
+
+void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len)
+{
+ while(len>0)
+ {
+ if(iov->iov_len)
+ {
+ int copy = min(iov->iov_len, len);
+ memcpy(iov->iov_base, kdata, copy);
+ kdata+=copy;
+ len-=copy;
+ iov->iov_len-=copy;
+ iov->iov_base+=copy;
+ }
+ iov++;
+ }
+}
+
+
+/*
+ * Copy iovec to kernel. Returns -EFAULT on error.
+ *
+ * Note: this modifies the original iovec.
+ */
+
+int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
+{
+ int err = -EFAULT;
+
+ while(len>0)
+ {
+ if(iov->iov_len)
+ {
+ int copy = min(len, iov->iov_len);
+ if (copy_from_user(kdata, iov->iov_base, copy))
+ goto out;
+ len-=copy;
+ kdata+=copy;
+ iov->iov_base+=copy;
+ iov->iov_len-=copy;
+ }
+ iov++;
+ }
+ err = 0;
+out:
+ return err;
+}
+
+
+/*
+ * For use with ip_build_xmit
+ */
+
+int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
+ int len)
+{
+ int err = -EFAULT;
+
+ /* Skip over the finished iovecs */
+ while(offset >= iov->iov_len)
+ {
+ offset -= iov->iov_len;
+ iov++;
+ }
+
+ while (len > 0)
+ {
+ u8 *base = iov->iov_base + offset;
+ int copy = min(len, iov->iov_len - offset);
+
+ offset = 0;
+ if (copy_from_user(kdata, base, copy))
+ goto out;
+ len -= copy;
+ kdata += copy;
+ iov++;
+ }
+ err = 0;
+out:
+ return err;
+}
+
+/*
+ * And now for the all-in-one: copy and checksum from a user iovec
+ * directly to a datagram
+ * Calls to csum_partial but the last must be in 32 bit chunks
+ *
+ * ip_build_xmit must ensure that when fragmenting only the last
+ * call to this function will be unaligned also.
+ */
+
+int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
+ int offset, unsigned int len, int *csump)
+{
+ int csum = *csump;
+ int partial_cnt = 0, err = 0;
+
+ /* Skip over the finished iovecs */
+ while (offset >= iov->iov_len)
+ {
+ offset -= iov->iov_len;
+ iov++;
+ }
+
+ while (len > 0)
+ {
+ u8 *base = iov->iov_base + offset;
+ unsigned int copy = min(len, iov->iov_len - offset);
+
+ offset = 0;
+ /* There is a remnant from previous iov. */
+ if (partial_cnt)
+ {
+ int par_len = 4 - partial_cnt;
+
+ /* iov component is too short ... */
+ if (par_len > copy) {
+ if (copy_from_user(kdata, base, copy))
+ goto out_fault;
+ kdata += copy;
+ base += copy;
+ partial_cnt += copy;
+ len -= copy;
+ iov++;
+ if (len)
+ continue;
+ *csump = csum_partial(kdata - partial_cnt,
+ partial_cnt, csum);
+ goto out;
+ }
+ if (copy_from_user(kdata, base, par_len))
+ goto out_fault;
+ csum = csum_partial(kdata - partial_cnt, 4, csum);
+ kdata += par_len;
+ base += par_len;
+ copy -= par_len;
+ len -= par_len;
+ partial_cnt = 0;
+ }
+
+ if (len > copy)
+ {
+ partial_cnt = copy % 4;
+ if (partial_cnt)
+ {
+ copy -= partial_cnt;
+ if (copy_from_user(kdata + copy, base + copy,
+ partial_cnt))
+ goto out_fault;
+ }
+ }
+
+ if (copy) {
+ csum = csum_and_copy_from_user(base, kdata, copy,
+ csum, &err);
+ if (err)
+ goto out;
+ }
+ len -= copy + partial_cnt;
+ kdata += copy + partial_cnt;
+ iov++;
+ }
+ *csump = csum;
+out:
+ return err;
+
+out_fault:
+ err = -EFAULT;
+ goto out;
+}
diff --git a/pfinet/linux-src/net/core/neighbour.c b/pfinet/linux-src/net/core/neighbour.c
new file mode 100644
index 00000000..6afbfdcc
--- /dev/null
+++ b/pfinet/linux-src/net/core/neighbour.c
@@ -0,0 +1,1394 @@
+/*
+ * Generic address resolution entity
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/socket.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+#include <net/neighbour.h>
+#include <net/dst.h>
+#include <net/sock.h>
+#include <linux/rtnetlink.h>
+
+/*
+ NOTE. The most unpleasent question is serialization of
+ accesses to resolved addresses. The problem is that addresses
+ are modified by bh, but they are referenced from normal
+ kernel thread. Before today no locking was made.
+ My reasoning was that corrupted address token will be copied
+ to packet with cosmologically small probability
+ (it is even difficult to estimate such small number)
+ and it is very silly to waste cycles in fast path to lock them.
+
+ But now I changed my mind, but not because previous statement
+ is wrong. Actually, neigh->ha MAY BE not opaque byte array,
+ but reference to some private data. In this case even neglibible
+ corruption probability becomes bug.
+
+ - hh cache is protected by rwlock. It assumes that
+ hh cache update procedure is short and fast, and that
+ read_lock is cheaper than start_bh_atomic().
+ - ha tokens, saved in neighbour entries, are protected
+ by bh_atomic().
+ - no protection is made in /proc reading. It is OK, because
+ /proc is broken by design in any case, and
+ corrupted output is normal behaviour there.
+
+ --ANK (981025)
+ */
+
+#define NEIGH_DEBUG 1
+
+#define NEIGH_PRINTK(x...) printk(x)
+#define NEIGH_NOPRINTK(x...) do { ; } while(0)
+#define NEIGH_PRINTK0 NEIGH_PRINTK
+#define NEIGH_PRINTK1 NEIGH_NOPRINTK
+#define NEIGH_PRINTK2 NEIGH_NOPRINTK
+
+#if NEIGH_DEBUG >= 1
+#undef NEIGH_PRINTK1
+#define NEIGH_PRINTK1 NEIGH_PRINTK
+#endif
+#if NEIGH_DEBUG >= 2
+#undef NEIGH_PRINTK2
+#define NEIGH_PRINTK2 NEIGH_PRINTK
+#endif
+
+static void neigh_timer_handler(unsigned long arg);
+#ifdef CONFIG_ARPD
+static void neigh_app_notify(struct neighbour *n);
+#endif
+static int pneigh_ifdown(struct neigh_table *tbl, struct device *dev);
+
+static int neigh_glbl_allocs;
+static struct neigh_table *neigh_tables;
+
+static int neigh_blackhole(struct sk_buff *skb)
+{
+ kfree_skb(skb);
+ return -ENETDOWN;
+}
+
+/*
+ * It is random distribution in the interval (1/2)*base...(3/2)*base.
+ * It corresponds to default IPv6 settings and is not overridable,
+ * because it is really reasonbale choice.
+ */
+
+unsigned long neigh_rand_reach_time(unsigned long base)
+{
+ return (net_random() % base) + (base>>1);
+}
+
+
+static int neigh_forced_gc(struct neigh_table *tbl)
+{
+ int shrunk = 0;
+ int i;
+
+ if (atomic_read(&tbl->lock))
+ return 0;
+
+ for (i=0; i<=NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ /* Neighbour record may be discarded if:
+ - nobody refers to it.
+ - it is not premanent
+ - (NEW and probably wrong)
+ INCOMPLETE entries are kept at least for
+ n->parms->retrans_time, otherwise we could
+ flood network with resolution requests.
+ It is not clear, what is better table overflow
+ or flooding.
+ */
+ if (atomic_read(&n->refcnt) == 0 &&
+ !(n->nud_state&NUD_PERMANENT) &&
+ (n->nud_state != NUD_INCOMPLETE ||
+ jiffies - n->used > n->parms->retrans_time)) {
+ *np = n->next;
+ n->tbl = NULL;
+ tbl->entries--;
+ shrunk = 1;
+ neigh_destroy(n);
+ continue;
+ }
+ np = &n->next;
+ }
+ }
+
+ tbl->last_flush = jiffies;
+ return shrunk;
+}
+
+int neigh_ifdown(struct neigh_table *tbl, struct device *dev)
+{
+ int i;
+
+ if (atomic_read(&tbl->lock)) {
+ NEIGH_PRINTK1("neigh_ifdown: impossible event 1763\n");
+ return -EBUSY;
+ }
+
+ start_bh_atomic();
+ for (i=0; i<=NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ if (dev && n->dev != dev) {
+ np = &n->next;
+ continue;
+ }
+ *np = n->next;
+ n->tbl = NULL;
+ tbl->entries--;
+ if (atomic_read(&n->refcnt)) {
+ /* The most unpleasant situation.
+ We must destroy neighbour entry,
+ but someone still uses it.
+
+ The destroy will be delayed until
+ the last user releases us, but
+ we must kill timers etc. and move
+ it to safe state.
+ */
+ if (n->nud_state & NUD_IN_TIMER)
+ del_timer(&n->timer);
+ n->parms = &tbl->parms;
+ skb_queue_purge(&n->arp_queue);
+ n->output = neigh_blackhole;
+ if (n->nud_state&NUD_VALID)
+ n->nud_state = NUD_NOARP;
+ else
+ n->nud_state = NUD_NONE;
+ NEIGH_PRINTK2("neigh %p is stray.\n", n);
+ } else
+ neigh_destroy(n);
+ }
+ }
+
+ del_timer(&tbl->proxy_timer);
+ skb_queue_purge(&tbl->proxy_queue);
+ pneigh_ifdown(tbl, dev);
+ end_bh_atomic();
+ return 0;
+}
+
+static struct neighbour *neigh_alloc(struct neigh_table *tbl, int creat)
+{
+ struct neighbour *n;
+ unsigned long now = jiffies;
+
+ if (tbl->entries > tbl->gc_thresh1) {
+ if (creat < 0)
+ return NULL;
+ if (tbl->entries > tbl->gc_thresh3 ||
+ (tbl->entries > tbl->gc_thresh2 &&
+ now - tbl->last_flush > 5*HZ)) {
+ if (neigh_forced_gc(tbl) == 0 &&
+ tbl->entries > tbl->gc_thresh3)
+ return NULL;
+ }
+ }
+
+ n = kmalloc(tbl->entry_size, GFP_ATOMIC);
+ if (n == NULL)
+ return NULL;
+
+ memset(n, 0, tbl->entry_size);
+
+ skb_queue_head_init(&n->arp_queue);
+ n->updated = n->used = now;
+ n->nud_state = NUD_NONE;
+ n->output = neigh_blackhole;
+ n->parms = &tbl->parms;
+ init_timer(&n->timer);
+ n->timer.function = neigh_timer_handler;
+ n->timer.data = (unsigned long)n;
+ tbl->stats.allocs++;
+ neigh_glbl_allocs++;
+ return n;
+}
+
+
+struct neighbour * __neigh_lookup(struct neigh_table *tbl, const void *pkey,
+ struct device *dev, int creat)
+{
+ struct neighbour *n;
+ u32 hash_val;
+ int key_len = tbl->key_len;
+
+ hash_val = *(u32*)(pkey + key_len - 4);
+ hash_val ^= (hash_val>>16);
+ hash_val ^= hash_val>>8;
+ hash_val ^= hash_val>>3;
+ hash_val = (hash_val^dev->ifindex)&NEIGH_HASHMASK;
+
+ for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
+ if (dev == n->dev &&
+ memcmp(n->primary_key, pkey, key_len) == 0) {
+ atomic_inc(&n->refcnt);
+ return n;
+ }
+ }
+ if (!creat)
+ return NULL;
+
+ n = neigh_alloc(tbl, creat);
+ if (n == NULL)
+ return NULL;
+
+ memcpy(n->primary_key, pkey, key_len);
+ n->dev = dev;
+
+ /* Protocol specific setup. */
+ if (tbl->constructor && tbl->constructor(n) < 0) {
+ neigh_destroy(n);
+ return NULL;
+ }
+
+ /* Device specific setup. */
+ if (n->parms && n->parms->neigh_setup && n->parms->neigh_setup(n) < 0) {
+ neigh_destroy(n);
+ return NULL;
+ }
+
+ n->confirmed = jiffies - (n->parms->base_reachable_time<<1);
+ atomic_set(&n->refcnt, 1);
+ tbl->entries++;
+ n->next = tbl->hash_buckets[hash_val];
+ tbl->hash_buckets[hash_val] = n;
+ n->tbl = tbl;
+ NEIGH_PRINTK2("neigh %p is created.\n", n);
+ return n;
+}
+
+struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, const void *pkey,
+ struct device *dev, int creat)
+{
+ struct pneigh_entry *n;
+ u32 hash_val;
+ int key_len = tbl->key_len;
+
+ hash_val = *(u32*)(pkey + key_len - 4);
+ hash_val ^= (hash_val>>16);
+ hash_val ^= hash_val>>8;
+ hash_val ^= hash_val>>4;
+ hash_val &= PNEIGH_HASHMASK;
+
+ for (n = tbl->phash_buckets[hash_val]; n; n = n->next) {
+ if (memcmp(n->key, pkey, key_len) == 0 &&
+ (n->dev == dev || !n->dev))
+ return n;
+ }
+ if (!creat)
+ return NULL;
+
+ n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
+ if (n == NULL)
+ return NULL;
+
+ memcpy(n->key, pkey, key_len);
+ n->dev = dev;
+
+ if (tbl->pconstructor && tbl->pconstructor(n)) {
+ kfree(n);
+ return NULL;
+ }
+
+ n->next = tbl->phash_buckets[hash_val];
+ tbl->phash_buckets[hash_val] = n;
+ return n;
+}
+
+
+int pneigh_delete(struct neigh_table *tbl, const void *pkey, struct device *dev)
+{
+ struct pneigh_entry *n, **np;
+ u32 hash_val;
+ int key_len = tbl->key_len;
+
+ hash_val = *(u32*)(pkey + key_len - 4);
+ hash_val ^= (hash_val>>16);
+ hash_val ^= hash_val>>8;
+ hash_val ^= hash_val>>4;
+ hash_val &= PNEIGH_HASHMASK;
+
+ for (np = &tbl->phash_buckets[hash_val]; (n=*np) != NULL; np = &n->next) {
+ if (memcmp(n->key, pkey, key_len) == 0 && n->dev == dev) {
+ *np = n->next;
+ synchronize_bh();
+ if (tbl->pdestructor)
+ tbl->pdestructor(n);
+ kfree(n);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+static int pneigh_ifdown(struct neigh_table *tbl, struct device *dev)
+{
+ struct pneigh_entry *n, **np;
+ u32 h;
+
+ for (h=0; h<=PNEIGH_HASHMASK; h++) {
+ np = &tbl->phash_buckets[h];
+ while ((n=*np) != NULL) {
+ if (n->dev == dev || dev == NULL) {
+ *np = n->next;
+ synchronize_bh();
+ if (tbl->pdestructor)
+ tbl->pdestructor(n);
+ kfree(n);
+ continue;
+ }
+ np = &n->next;
+ }
+ }
+ return -ENOENT;
+}
+
+
+/*
+ * neighbour must already be out of the table;
+ *
+ */
+void neigh_destroy(struct neighbour *neigh)
+{
+ struct hh_cache *hh;
+
+ if (neigh->tbl || atomic_read(&neigh->refcnt)) {
+ NEIGH_PRINTK1("neigh_destroy: neighbour is use tbl=%p, ref=%d: "
+ "called from %p\n", neigh->tbl, atomic_read(&neigh->refcnt), __builtin_return_address(0));
+ return;
+ }
+
+ if (neigh->nud_state&NUD_IN_TIMER)
+ del_timer(&neigh->timer);
+
+ while ((hh = neigh->hh) != NULL) {
+ neigh->hh = hh->hh_next;
+ hh->hh_next = NULL;
+ hh->hh_output = neigh_blackhole;
+ if (atomic_dec_and_test(&hh->hh_refcnt))
+ kfree(hh);
+ }
+
+ if (neigh->ops && neigh->ops->destructor)
+ (neigh->ops->destructor)(neigh);
+
+ skb_queue_purge(&neigh->arp_queue);
+
+ NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
+
+ neigh_glbl_allocs--;
+ kfree(neigh);
+}
+
+/* Neighbour state is suspicious;
+ disable fast path.
+ */
+static void neigh_suspect(struct neighbour *neigh)
+{
+ struct hh_cache *hh;
+
+ NEIGH_PRINTK2("neigh %p is suspecteded.\n", neigh);
+
+ neigh->output = neigh->ops->output;
+
+ for (hh = neigh->hh; hh; hh = hh->hh_next)
+ hh->hh_output = neigh->ops->output;
+}
+
+/* Neighbour state is OK;
+ enable fast path.
+ */
+static void neigh_connect(struct neighbour *neigh)
+{
+ struct hh_cache *hh;
+
+ NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
+
+ neigh->output = neigh->ops->connected_output;
+
+ for (hh = neigh->hh; hh; hh = hh->hh_next)
+ hh->hh_output = neigh->ops->hh_output;
+}
+
+/*
+ Transitions NUD_STALE <-> NUD_REACHABLE do not occur
+ when fast path is built: we have no timers assotiated with
+ these states, we do not have time to check state when sending.
+ neigh_periodic_timer check periodically neigh->confirmed
+ time and moves NUD_REACHABLE -> NUD_STALE.
+
+ If a routine wants to know TRUE entry state, it calls
+ neigh_sync before checking state.
+ */
+
+static void neigh_sync(struct neighbour *n)
+{
+ unsigned long now = jiffies;
+ u8 state = n->nud_state;
+
+ if (state&(NUD_NOARP|NUD_PERMANENT))
+ return;
+ if (state&NUD_REACHABLE) {
+ if (now - n->confirmed > n->parms->reachable_time) {
+ n->nud_state = NUD_STALE;
+ neigh_suspect(n);
+ }
+ } else if (state&NUD_VALID) {
+ if (now - n->confirmed < n->parms->reachable_time) {
+ if (state&NUD_IN_TIMER)
+ del_timer(&n->timer);
+ n->nud_state = NUD_REACHABLE;
+ neigh_connect(n);
+ }
+ }
+}
+
+static void neigh_periodic_timer(unsigned long arg)
+{
+ struct neigh_table *tbl = (struct neigh_table*)arg;
+ unsigned long now = jiffies;
+ int i;
+
+ if (atomic_read(&tbl->lock)) {
+ tbl->gc_timer.expires = now + 1*HZ;
+ add_timer(&tbl->gc_timer);
+ return;
+ }
+
+ /*
+ * periodicly recompute ReachableTime from random function
+ */
+
+ if (now - tbl->last_rand > 300*HZ) {
+ struct neigh_parms *p;
+ tbl->last_rand = now;
+ for (p=&tbl->parms; p; p = p->next)
+ p->reachable_time = neigh_rand_reach_time(p->base_reachable_time);
+ }
+
+ for (i=0; i <= NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ unsigned state = n->nud_state;
+
+ if (state&(NUD_PERMANENT|NUD_IN_TIMER))
+ goto next_elt;
+
+ if ((long)(n->used - n->confirmed) < 0)
+ n->used = n->confirmed;
+
+ if (atomic_read(&n->refcnt) == 0 &&
+ (state == NUD_FAILED || now - n->used > n->parms->gc_staletime)) {
+ *np = n->next;
+ n->tbl = NULL;
+ n->next = NULL;
+ tbl->entries--;
+ neigh_destroy(n);
+ continue;
+ }
+
+ if (n->nud_state&NUD_REACHABLE &&
+ now - n->confirmed > n->parms->reachable_time) {
+ n->nud_state = NUD_STALE;
+ neigh_suspect(n);
+ }
+
+next_elt:
+ np = &n->next;
+ }
+ }
+
+ tbl->gc_timer.expires = now + tbl->gc_interval;
+ add_timer(&tbl->gc_timer);
+}
+
+static __inline__ int neigh_max_probes(struct neighbour *n)
+{
+ struct neigh_parms *p = n->parms;
+ return p->ucast_probes + p->app_probes + p->mcast_probes;
+}
+
+
+/* Called when a timer expires for a neighbour entry. */
+
+static void neigh_timer_handler(unsigned long arg)
+{
+ unsigned long now = jiffies;
+ struct neighbour *neigh = (struct neighbour*)arg;
+ unsigned state = neigh->nud_state;
+
+ if (!(state&NUD_IN_TIMER)) {
+ NEIGH_PRINTK1("neigh: timer & !nud_in_timer\n");
+ return;
+ }
+
+ if ((state&NUD_VALID) &&
+ now - neigh->confirmed < neigh->parms->reachable_time) {
+ neigh->nud_state = NUD_REACHABLE;
+ NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
+ neigh_connect(neigh);
+ return;
+ }
+ if (state == NUD_DELAY) {
+ NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
+ neigh->nud_state = NUD_PROBE;
+ neigh->probes = 0;
+ }
+
+ if (neigh->probes >= neigh_max_probes(neigh)) {
+ struct sk_buff *skb;
+
+ neigh->nud_state = NUD_FAILED;
+ neigh->tbl->stats.res_failed++;
+ NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
+
+ /* It is very thin place. report_unreachable is very complicated
+ routine. Particularly, it can hit the same neighbour entry!
+
+ So that, we try to be accurate and avoid dead loop. --ANK
+ */
+ while(neigh->nud_state==NUD_FAILED && (skb=__skb_dequeue(&neigh->arp_queue)) != NULL)
+ neigh->ops->error_report(neigh, skb);
+ skb_queue_purge(&neigh->arp_queue);
+ return;
+ }
+
+ neigh->timer.expires = now + neigh->parms->retrans_time;
+ add_timer(&neigh->timer);
+
+ neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue));
+ neigh->probes++;
+}
+
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+{
+ start_bh_atomic();
+ if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) {
+ if (!(neigh->nud_state&(NUD_STALE|NUD_INCOMPLETE))) {
+ if (neigh->tbl == NULL) {
+ NEIGH_PRINTK2("neigh %p used after death.\n", neigh);
+ if (skb)
+ kfree_skb(skb);
+ end_bh_atomic();
+ return 1;
+ }
+ if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
+ neigh->probes = neigh->parms->ucast_probes;
+ neigh->nud_state = NUD_INCOMPLETE;
+ neigh->timer.expires = jiffies + neigh->parms->retrans_time;
+ add_timer(&neigh->timer);
+
+ neigh->ops->solicit(neigh, skb);
+ neigh->probes++;
+ } else {
+ neigh->nud_state = NUD_FAILED;
+ if (skb)
+ kfree_skb(skb);
+ end_bh_atomic();
+ return 1;
+ }
+ }
+ if (neigh->nud_state == NUD_INCOMPLETE) {
+ if (skb) {
+ if (skb_queue_len(&neigh->arp_queue) >= neigh->parms->queue_len) {
+ struct sk_buff *buff;
+ buff = neigh->arp_queue.prev;
+ __skb_unlink(buff, &neigh->arp_queue);
+ kfree_skb(buff);
+ }
+ __skb_queue_head(&neigh->arp_queue, skb);
+ }
+ end_bh_atomic();
+ return 1;
+ }
+ if (neigh->nud_state == NUD_STALE) {
+ NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
+ neigh->nud_state = NUD_DELAY;
+ neigh->timer.expires = jiffies + neigh->parms->delay_probe_time;
+ add_timer(&neigh->timer);
+ }
+ }
+ end_bh_atomic();
+ return 0;
+}
+
+static __inline__ void neigh_update_hhs(struct neighbour *neigh)
+{
+ struct hh_cache *hh;
+ void (*update)(struct hh_cache*, struct device*, unsigned char*) =
+ neigh->dev->header_cache_update;
+
+ if (update) {
+ for (hh=neigh->hh; hh; hh=hh->hh_next) {
+ write_lock_irq(&hh->hh_lock);
+ update(hh, neigh->dev, neigh->ha);
+ write_unlock_irq(&hh->hh_lock);
+ }
+ }
+}
+
+
+
+/* Generic update routine.
+ -- lladdr is new lladdr or NULL, if it is not supplied.
+ -- new is new state.
+ -- override==1 allows to override existing lladdr, if it is different.
+ -- arp==0 means that the change is administrative.
+ */
+
+int neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int arp)
+{
+ u8 old = neigh->nud_state;
+ struct device *dev = neigh->dev;
+
+ if (arp && (old&(NUD_NOARP|NUD_PERMANENT)))
+ return -EPERM;
+
+ if (!(new&NUD_VALID)) {
+ if (old&NUD_IN_TIMER)
+ del_timer(&neigh->timer);
+ if (old&NUD_CONNECTED)
+ neigh_suspect(neigh);
+ neigh->nud_state = new;
+ return 0;
+ }
+
+ /* Compare new lladdr with cached one */
+ if (dev->addr_len == 0) {
+ /* First case: device needs no address. */
+ lladdr = neigh->ha;
+ } else if (lladdr) {
+ /* The second case: if something is already cached
+ and a new address is proposed:
+ - compare new & old
+ - if they are different, check override flag
+ */
+ if (old&NUD_VALID) {
+ if (memcmp(lladdr, neigh->ha, dev->addr_len) == 0)
+ lladdr = neigh->ha;
+ else if (!override)
+ return -EPERM;
+ }
+ } else {
+ /* No address is supplied; if we know something,
+ use it, otherwise discard the request.
+ */
+ if (!(old&NUD_VALID))
+ return -EINVAL;
+ lladdr = neigh->ha;
+ }
+
+ neigh_sync(neigh);
+ old = neigh->nud_state;
+ if (new&NUD_CONNECTED)
+ neigh->confirmed = jiffies;
+ neigh->updated = jiffies;
+
+ /* If entry was valid and address is not changed,
+ do not change entry state, if new one is STALE.
+ */
+ if (old&NUD_VALID) {
+ if (lladdr == neigh->ha)
+ if (new == old || (new == NUD_STALE && (old&NUD_CONNECTED)))
+ return 0;
+ }
+ if (old&NUD_IN_TIMER)
+ del_timer(&neigh->timer);
+ neigh->nud_state = new;
+ if (lladdr != neigh->ha) {
+ memcpy(&neigh->ha, lladdr, dev->addr_len);
+ neigh_update_hhs(neigh);
+ neigh->confirmed = jiffies - (neigh->parms->base_reachable_time<<1);
+#ifdef CONFIG_ARPD
+ if (neigh->parms->app_probes)
+ neigh_app_notify(neigh);
+#endif
+ }
+ if (new == old)
+ return 0;
+ if (new&NUD_CONNECTED)
+ neigh_connect(neigh);
+ else
+ neigh_suspect(neigh);
+ if (!(old&NUD_VALID)) {
+ struct sk_buff *skb;
+
+ /* Again: avoid dead loop if something went wrong */
+
+ while (neigh->nud_state&NUD_VALID &&
+ (skb=__skb_dequeue(&neigh->arp_queue)) != NULL) {
+ struct neighbour *n1 = neigh;
+ /* On shaper/eql skb->dst->neighbour != neigh :( */
+ if (skb->dst && skb->dst->neighbour)
+ n1 = skb->dst->neighbour;
+ n1->output(skb);
+ }
+ skb_queue_purge(&neigh->arp_queue);
+ }
+ return 0;
+}
+
+struct neighbour * neigh_event_ns(struct neigh_table *tbl,
+ u8 *lladdr, void *saddr,
+ struct device *dev)
+{
+ struct neighbour *neigh;
+
+ neigh = __neigh_lookup(tbl, saddr, dev, lladdr || !dev->addr_len);
+ if (neigh)
+ neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
+ return neigh;
+}
+
+static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, u16 protocol)
+{
+ struct hh_cache *hh = NULL;
+ struct device *dev = dst->dev;
+
+ for (hh=n->hh; hh; hh = hh->hh_next)
+ if (hh->hh_type == protocol)
+ break;
+
+ if (!hh && (hh = kmalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
+ memset(hh, 0, sizeof(struct hh_cache));
+ hh->hh_type = protocol;
+ atomic_set(&hh->hh_refcnt, 0);
+ hh->hh_next = NULL;
+ if (dev->hard_header_cache(n, hh)) {
+ kfree(hh);
+ hh = NULL;
+ } else {
+ atomic_inc(&hh->hh_refcnt);
+ hh->hh_next = n->hh;
+ n->hh = hh;
+ if (n->nud_state&NUD_CONNECTED)
+ hh->hh_output = n->ops->hh_output;
+ else
+ hh->hh_output = n->ops->output;
+ }
+ }
+ if (hh) {
+ atomic_inc(&hh->hh_refcnt);
+ dst->hh = hh;
+ }
+}
+
+/* This function can be used in contexts, where only old dev_queue_xmit
+ worked, f.e. if you want to override normal output path (eql, shaper),
+ but resoltution is not made yet.
+ */
+
+int neigh_compat_output(struct sk_buff *skb)
+{
+ struct device *dev = skb->dev;
+
+ __skb_pull(skb, skb->nh.raw - skb->data);
+
+ if (dev->hard_header &&
+ dev->hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, skb->len) < 0 &&
+ dev->rebuild_header(skb))
+ return 0;
+
+ return dev_queue_xmit(skb);
+}
+
+/* Slow and careful. */
+
+int neigh_resolve_output(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb->dst;
+ struct neighbour *neigh;
+
+ if (!dst || !(neigh = dst->neighbour))
+ goto discard;
+
+ __skb_pull(skb, skb->nh.raw - skb->data);
+
+ if (neigh_event_send(neigh, skb) == 0) {
+ int err;
+ struct device *dev = neigh->dev;
+ if (dev->hard_header_cache && dst->hh == NULL) {
+ start_bh_atomic();
+ if (dst->hh == NULL)
+ neigh_hh_init(neigh, dst, dst->ops->protocol);
+ err = dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len);
+ end_bh_atomic();
+ } else {
+ start_bh_atomic();
+ err = dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len);
+ end_bh_atomic();
+ }
+ if (err >= 0)
+ return neigh->ops->queue_xmit(skb);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ return 0;
+
+discard:
+ NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n", dst, dst ? dst->neighbour : NULL);
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+/* As fast as possible without hh cache */
+
+int neigh_connected_output(struct sk_buff *skb)
+{
+ int err;
+ struct dst_entry *dst = skb->dst;
+ struct neighbour *neigh = dst->neighbour;
+ struct device *dev = neigh->dev;
+
+ __skb_pull(skb, skb->nh.raw - skb->data);
+
+ start_bh_atomic();
+ err = dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len);
+ end_bh_atomic();
+ if (err >= 0)
+ return neigh->ops->queue_xmit(skb);
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+static void neigh_proxy_process(unsigned long arg)
+{
+ struct neigh_table *tbl = (struct neigh_table *)arg;
+ long sched_next = 0;
+ unsigned long now = jiffies;
+ struct sk_buff *skb = tbl->proxy_queue.next;
+
+ while (skb != (struct sk_buff*)&tbl->proxy_queue) {
+ struct sk_buff *back = skb;
+ long tdif = back->stamp.tv_usec - now;
+
+ skb = skb->next;
+ if (tdif <= 0) {
+ __skb_unlink(back, &tbl->proxy_queue);
+ if (tbl->proxy_redo)
+ tbl->proxy_redo(back);
+ else
+ kfree_skb(back);
+ } else if (!sched_next || tdif < sched_next)
+ sched_next = tdif;
+ }
+ del_timer(&tbl->proxy_timer);
+ if (sched_next) {
+ tbl->proxy_timer.expires = jiffies + sched_next;
+ add_timer(&tbl->proxy_timer);
+ }
+}
+
+void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
+ struct sk_buff *skb)
+{
+ unsigned long now = jiffies;
+ long sched_next = net_random()%p->proxy_delay;
+
+ if (tbl->proxy_queue.qlen > p->proxy_qlen) {
+ kfree_skb(skb);
+ return;
+ }
+ skb->stamp.tv_sec = 0;
+ skb->stamp.tv_usec = now + sched_next;
+ if (del_timer(&tbl->proxy_timer)) {
+ long tval = tbl->proxy_timer.expires - now;
+ if (tval < sched_next)
+ sched_next = tval;
+ }
+ tbl->proxy_timer.expires = now + sched_next;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ __skb_queue_tail(&tbl->proxy_queue, skb);
+ add_timer(&tbl->proxy_timer);
+}
+
+
+struct neigh_parms *neigh_parms_alloc(struct device *dev, struct neigh_table *tbl)
+{
+ struct neigh_parms *p;
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p) {
+ memcpy(p, &tbl->parms, sizeof(*p));
+ p->tbl = tbl;
+ p->reachable_time = neigh_rand_reach_time(p->base_reachable_time);
+ if (dev && dev->neigh_setup) {
+ if (dev->neigh_setup(dev, p)) {
+ kfree(p);
+ return NULL;
+ }
+ }
+ p->next = tbl->parms.next;
+ tbl->parms.next = p;
+ }
+ return p;
+}
+
+void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
+{
+ struct neigh_parms **p;
+
+ if (parms == NULL || parms == &tbl->parms)
+ return;
+ for (p = &tbl->parms.next; *p; p = &(*p)->next) {
+ if (*p == parms) {
+ *p = parms->next;
+ synchronize_bh();
+#ifdef CONFIG_SYSCTL
+ neigh_sysctl_unregister(parms);
+#endif
+ kfree(parms);
+ return;
+ }
+ }
+ NEIGH_PRINTK1("neigh_release_parms: not found\n");
+}
+
+
+void neigh_table_init(struct neigh_table *tbl)
+{
+ unsigned long now = jiffies;
+
+ tbl->parms.reachable_time = neigh_rand_reach_time(tbl->parms.base_reachable_time);
+
+ init_timer(&tbl->gc_timer);
+ tbl->gc_timer.data = (unsigned long)tbl;
+ tbl->gc_timer.function = neigh_periodic_timer;
+ tbl->gc_timer.expires = now + tbl->gc_interval + tbl->parms.reachable_time;
+ add_timer(&tbl->gc_timer);
+
+ init_timer(&tbl->proxy_timer);
+ tbl->proxy_timer.data = (unsigned long)tbl;
+ tbl->proxy_timer.function = neigh_proxy_process;
+ skb_queue_head_init(&tbl->proxy_queue);
+
+ tbl->last_flush = now;
+ tbl->last_rand = now + tbl->parms.reachable_time*20;
+ tbl->next = neigh_tables;
+ neigh_tables = tbl;
+}
+
+int neigh_table_clear(struct neigh_table *tbl)
+{
+ struct neigh_table **tp;
+
+ start_bh_atomic();
+ del_timer(&tbl->gc_timer);
+ del_timer(&tbl->proxy_timer);
+ skb_queue_purge(&tbl->proxy_queue);
+ neigh_ifdown(tbl, NULL);
+ end_bh_atomic();
+ if (tbl->entries)
+ printk(KERN_CRIT "neighbour leakage\n");
+ for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
+ if (*tp == tbl) {
+ *tp = tbl->next;
+ synchronize_bh();
+ break;
+ }
+ }
+#ifdef CONFIG_SYSCTL
+ neigh_sysctl_unregister(&tbl->parms);
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_RTNETLINK
+
+
+int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct ndmsg *ndm = NLMSG_DATA(nlh);
+ struct rtattr **nda = arg;
+ struct neigh_table *tbl;
+ struct device *dev = NULL;
+
+ if (ndm->ndm_ifindex) {
+ if ((dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
+ return -ENODEV;
+ }
+
+ for (tbl=neigh_tables; tbl; tbl = tbl->next) {
+ int err = 0;
+ struct neighbour *n;
+
+ if (tbl->family != ndm->ndm_family)
+ continue;
+
+ if (nda[NDA_DST-1] == NULL ||
+ nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len))
+ return -EINVAL;
+
+ if (ndm->ndm_flags&NTF_PROXY)
+ return pneigh_delete(tbl, RTA_DATA(nda[NDA_DST-1]), dev);
+
+ if (dev == NULL)
+ return -EINVAL;
+
+ start_bh_atomic();
+ n = __neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 0);
+ if (n) {
+ err = neigh_update(n, NULL, NUD_FAILED, 1, 0);
+ neigh_release(n);
+ }
+ end_bh_atomic();
+ return err;
+ }
+
+ return -EADDRNOTAVAIL;
+}
+
+int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct ndmsg *ndm = NLMSG_DATA(nlh);
+ struct rtattr **nda = arg;
+ struct neigh_table *tbl;
+ struct device *dev = NULL;
+
+ if (ndm->ndm_ifindex) {
+ if ((dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
+ return -ENODEV;
+ }
+
+ for (tbl=neigh_tables; tbl; tbl = tbl->next) {
+ int err = 0;
+ struct neighbour *n;
+
+ if (tbl->family != ndm->ndm_family)
+ continue;
+ if (nda[NDA_DST-1] == NULL ||
+ nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len))
+ return -EINVAL;
+ if (ndm->ndm_flags&NTF_PROXY) {
+ if (pneigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 1))
+ return 0;
+ return -ENOBUFS;
+ }
+ if (dev == NULL)
+ return -EINVAL;
+ if (nda[NDA_LLADDR-1] != NULL &&
+ nda[NDA_LLADDR-1]->rta_len != RTA_LENGTH(dev->addr_len))
+ return -EINVAL;
+ start_bh_atomic();
+ n = __neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 0);
+ if (n) {
+ if (nlh->nlmsg_flags&NLM_F_EXCL)
+ err = -EEXIST;
+ } else if (!(nlh->nlmsg_flags&NLM_F_CREATE))
+ err = -ENOENT;
+ else {
+ n = __neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 1);
+ if (n == NULL)
+ err = -ENOBUFS;
+ }
+ if (err == 0) {
+ err = neigh_update(n, nda[NDA_LLADDR-1] ? RTA_DATA(nda[NDA_LLADDR-1]) : NULL,
+ ndm->ndm_state,
+ nlh->nlmsg_flags&NLM_F_REPLACE, 0);
+ }
+ if (n)
+ neigh_release(n);
+ end_bh_atomic();
+ return err;
+ }
+
+ return -EADDRNOTAVAIL;
+}
+
+
+static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
+ u32 pid, u32 seq, int event)
+{
+ unsigned long now = jiffies;
+ struct ndmsg *ndm;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+ struct nda_cacheinfo ci;
+
+ nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ndm));
+ ndm = NLMSG_DATA(nlh);
+ ndm->ndm_family = n->ops->family;
+ ndm->ndm_flags = n->flags;
+ ndm->ndm_type = n->type;
+ ndm->ndm_state = n->nud_state;
+ ndm->ndm_ifindex = n->dev->ifindex;
+ RTA_PUT(skb, NDA_DST, n->tbl->key_len, n->primary_key);
+ if (n->nud_state&NUD_VALID)
+ RTA_PUT(skb, NDA_LLADDR, n->dev->addr_len, n->ha);
+ ci.ndm_used = now - n->used;
+ ci.ndm_confirmed = now - n->confirmed;
+ ci.ndm_updated = now - n->updated;
+ ci.ndm_refcnt = atomic_read(&n->refcnt);
+ RTA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+
+static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct neighbour *n;
+ int h, s_h;
+ int idx, s_idx;
+
+ s_h = cb->args[1];
+ s_idx = idx = cb->args[2];
+ for (h=0; h <= NEIGH_HASHMASK; h++) {
+ if (h < s_h) continue;
+ if (h > s_h)
+ s_idx = 0;
+ start_bh_atomic();
+ for (n = tbl->hash_buckets[h], idx = 0; n;
+ n = n->next, idx++) {
+ if (idx < s_idx)
+ continue;
+ if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, RTM_NEWNEIGH) <= 0) {
+ end_bh_atomic();
+ cb->args[1] = h;
+ cb->args[2] = idx;
+ return -1;
+ }
+ }
+ end_bh_atomic();
+ }
+
+ cb->args[1] = h;
+ cb->args[2] = idx;
+ return skb->len;
+}
+
+int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int t;
+ int s_t;
+ struct neigh_table *tbl;
+ int family = ((struct rtgenmsg*)NLMSG_DATA(cb->nlh))->rtgen_family;
+
+ s_t = cb->args[0];
+
+ for (tbl=neigh_tables, t=0; tbl; tbl = tbl->next, t++) {
+ if (t < s_t) continue;
+ if (family && tbl->family != family)
+ continue;
+ if (t > s_t)
+ memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
+ if (neigh_dump_table(tbl, skb, cb) < 0)
+ break;
+ }
+
+ cb->args[0] = t;
+
+ return skb->len;
+}
+
+#ifdef CONFIG_ARPD
+void neigh_app_ns(struct neighbour *n)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ int size = NLMSG_SPACE(sizeof(struct ndmsg)+256);
+
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH) < 0) {
+ kfree_skb(skb);
+ return;
+ }
+ nlh = (struct nlmsghdr*)skb->data;
+ nlh->nlmsg_flags = NLM_F_REQUEST;
+ NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH;
+ netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);
+}
+
+static void neigh_app_notify(struct neighbour *n)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ int size = NLMSG_SPACE(sizeof(struct ndmsg)+256);
+
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH) < 0) {
+ kfree_skb(skb);
+ return;
+ }
+ nlh = (struct nlmsghdr*)skb->data;
+ NETLINK_CB(skb).dst_groups = RTMGRP_NEIGH;
+ netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);
+}
+
+
+
+#endif
+
+
+#endif
+
+#ifdef CONFIG_SYSCTL
+
+struct neigh_sysctl_table
+{
+ struct ctl_table_header *sysctl_header;
+ ctl_table neigh_vars[17];
+ ctl_table neigh_dev[2];
+ ctl_table neigh_neigh_dir[2];
+ ctl_table neigh_proto_dir[2];
+ ctl_table neigh_root_dir[2];
+} neigh_sysctl_template = {
+ NULL,
+ {{NET_NEIGH_MCAST_SOLICIT, "mcast_solicit",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_UCAST_SOLICIT, "ucast_solicit",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_APP_SOLICIT, "app_solicit",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_RETRANS_TIME, "retrans_time",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_REACHABLE_TIME, "base_reachable_time",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_NEIGH_DELAY_PROBE_TIME, "delay_first_probe_time",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_NEIGH_GC_STALE_TIME, "gc_stale_time",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_NEIGH_UNRES_QLEN, "unres_qlen",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_PROXY_QLEN, "proxy_qlen",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_ANYCAST_DELAY, "anycast_delay",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_PROXY_DELAY, "proxy_delay",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_LOCKTIME, "locktime",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_GC_INTERVAL, "gc_interval",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_NEIGH_GC_THRESH1, "gc_thresh1",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_GC_THRESH2, "gc_thresh2",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_NEIGH_GC_THRESH3, "gc_thresh3",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {0}},
+
+ {{NET_PROTO_CONF_DEFAULT, "default", NULL, 0, 0555, NULL},{0}},
+ {{0, "neigh", NULL, 0, 0555, NULL},{0}},
+ {{0, NULL, NULL, 0, 0555, NULL},{0}},
+ {{CTL_NET, "net", NULL, 0, 0555, NULL},{0}}
+};
+
+int neigh_sysctl_register(struct device *dev, struct neigh_parms *p,
+ int p_id, int pdev_id, char *p_name)
+{
+ struct neigh_sysctl_table *t;
+
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOBUFS;
+ memcpy(t, &neigh_sysctl_template, sizeof(*t));
+ t->neigh_vars[0].data = &p->mcast_probes;
+ t->neigh_vars[1].data = &p->ucast_probes;
+ t->neigh_vars[2].data = &p->app_probes;
+ t->neigh_vars[3].data = &p->retrans_time;
+ t->neigh_vars[4].data = &p->base_reachable_time;
+ t->neigh_vars[5].data = &p->delay_probe_time;
+ t->neigh_vars[6].data = &p->gc_staletime;
+ t->neigh_vars[7].data = &p->queue_len;
+ t->neigh_vars[8].data = &p->proxy_qlen;
+ t->neigh_vars[9].data = &p->anycast_delay;
+ t->neigh_vars[10].data = &p->proxy_delay;
+ t->neigh_vars[11].data = &p->locktime;
+ if (dev) {
+ t->neigh_dev[0].procname = dev->name;
+ t->neigh_dev[0].ctl_name = dev->ifindex;
+ memset(&t->neigh_vars[12], 0, sizeof(ctl_table));
+ } else {
+ t->neigh_vars[12].data = (int*)(p+1);
+ t->neigh_vars[13].data = (int*)(p+1) + 1;
+ t->neigh_vars[14].data = (int*)(p+1) + 2;
+ t->neigh_vars[15].data = (int*)(p+1) + 3;
+ }
+ t->neigh_neigh_dir[0].ctl_name = pdev_id;
+
+ t->neigh_proto_dir[0].procname = p_name;
+ t->neigh_proto_dir[0].ctl_name = p_id;
+
+ t->neigh_dev[0].child = t->neigh_vars;
+ t->neigh_neigh_dir[0].child = t->neigh_dev;
+ t->neigh_proto_dir[0].child = t->neigh_neigh_dir;
+ t->neigh_root_dir[0].child = t->neigh_proto_dir;
+
+ t->sysctl_header = register_sysctl_table(t->neigh_root_dir, 0);
+ if (t->sysctl_header == NULL) {
+ kfree(t);
+ return -ENOBUFS;
+ }
+ p->sysctl_table = t;
+ return 0;
+}
+
+void neigh_sysctl_unregister(struct neigh_parms *p)
+{
+ if (p->sysctl_table) {
+ struct neigh_sysctl_table *t = p->sysctl_table;
+ p->sysctl_table = NULL;
+ unregister_sysctl_table(t->sysctl_header);
+ kfree(t);
+ }
+}
+
+#endif /* CONFIG_SYSCTL */
diff --git a/pfinet/linux-src/net/core/profile.c b/pfinet/linux-src/net/core/profile.c
new file mode 100644
index 00000000..fc7464b7
--- /dev/null
+++ b/pfinet/linux-src/net/core/profile.c
@@ -0,0 +1,305 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/inet.h>
+#include <net/checksum.h>
+
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <net/profile.h>
+
+#ifdef CONFIG_NET_PROFILE
+
+atomic_t net_profile_active;
+struct timeval net_profile_adjust;
+
+NET_PROFILE_DEFINE(total);
+
+struct net_profile_slot *net_profile_chain = &net_prof_total;
+
+#ifdef __alpha__
+__u32 alpha_lo;
+long alpha_hi;
+
+static void alpha_tick(unsigned long);
+
+static struct timer_list alpha_timer =
+ { NULL, NULL, 0, 0L, alpha_tick };
+
+void alpha_tick(unsigned long dummy)
+{
+ struct timeval dummy_stamp;
+ net_profile_stamp(&dummy_stamp);
+ alpha_timer.expires = jiffies + 4*HZ;
+ add_timer(&alpha_timer);
+}
+
+#endif
+
+void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved)
+{
+ struct net_profile_slot *s;
+
+ net_profile_sub(entered, leaved);
+ for (s = net_profile_chain; s; s = s->next) {
+ if (s->active)
+ net_profile_add(leaved, &s->irq);
+ }
+}
+
+
+#ifdef CONFIG_PROC_FS
+static int profile_read_proc(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
+{
+ off_t pos=0;
+ off_t begin=0;
+ int len=0;
+ struct net_profile_slot *s;
+
+ len+= sprintf(buffer, "Slot Hits Hi Lo OnIrqHi OnIrqLo Ufl\n");
+
+ if (offset == 0) {
+ cli();
+ net_prof_total.active = 1;
+ atomic_inc(&net_profile_active);
+ NET_PROFILE_LEAVE(total);
+ sti();
+ }
+ for (s = net_profile_chain; s; s = s->next) {
+ struct net_profile_slot tmp;
+
+ cli();
+ tmp = *s;
+
+ /* Wrong, but pretty close to truth */
+
+ s->accumulator.tv_sec = 0;
+ s->accumulator.tv_usec = 0;
+ s->irq.tv_sec = 0;
+ s->irq.tv_usec = 0;
+ s->hits = 0;
+ s->underflow = 0;
+ /* Repair active count, it is possible, only if code has a bug */
+ if (s->active) {
+ s->active = 0;
+ atomic_dec(&net_profile_active);
+ }
+ sti();
+
+ net_profile_sub(&tmp.irq, &tmp.accumulator);
+
+ len += sprintf(buffer+len,"%-15s %-10d %-10ld %-10lu %-10lu %-10lu %d/%d",
+ tmp.id,
+ tmp.hits,
+ tmp.accumulator.tv_sec,
+ tmp.accumulator.tv_usec,
+ tmp.irq.tv_sec,
+ tmp.irq.tv_usec,
+ tmp.underflow, tmp.active);
+
+ buffer[len++]='\n';
+
+ pos=begin+len;
+ if(pos<offset) {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ goto done;
+ }
+ *eof = 1;
+
+done:
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ if (len < 0) {
+ len = 0;
+ printk(KERN_CRIT "Yep, guys... our template for proc_*_read is crappy :-)\n");
+ }
+ if (offset == 0) {
+ cli();
+ net_prof_total.active = 0;
+ net_prof_total.hits = 0;
+ net_profile_stamp(&net_prof_total.entered);
+ sti();
+ }
+ return len;
+}
+#endif
+
+struct iphdr whitehole_iph;
+int whitehole_count;
+
+static int whitehole_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct net_device_stats *stats;
+ dev_kfree_skb(skb);
+ stats = (struct net_device_stats *)dev->priv;
+ stats->tx_packets++;
+ stats->tx_bytes+=skb->len;
+
+ return 0;
+}
+
+static void whitehole_inject(unsigned long);
+int whitehole_init(struct device *dev);
+
+static struct timer_list whitehole_timer =
+ { NULL, NULL, 0, 0L, whitehole_inject };
+
+static struct device whitehole_dev = {
+ "whitehole", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, whitehole_init, };
+
+static int whitehole_open(struct device *dev)
+{
+ whitehole_count = 100000;
+ whitehole_timer.expires = jiffies + 5*HZ;
+ add_timer(&whitehole_timer);
+ return 0;
+}
+
+static int whitehole_close(struct device *dev)
+{
+ del_timer(&whitehole_timer);
+ return 0;
+}
+
+static void whitehole_inject(unsigned long dummy)
+{
+ struct net_device_stats *stats = (struct net_device_stats *)whitehole_dev.priv;
+ extern int netdev_dropping;
+
+ do {
+ struct iphdr *iph;
+ struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
+ if (!skb)
+ break;
+ skb_reserve(skb, 32);
+ iph = (struct iphdr*)skb_put(skb, sizeof(*iph));
+ skb->mac.raw = ((u8*)iph) - 14;
+ memcpy(iph, &whitehole_iph, sizeof(*iph));
+ skb->protocol = __constant_htons(ETH_P_IP);
+ skb->dev = &whitehole_dev;
+ skb->pkt_type = PACKET_HOST;
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+ netif_rx(skb);
+ whitehole_count--;
+ } while (netdev_dropping == 0 && whitehole_count>0);
+ if (whitehole_count > 0) {
+ whitehole_timer.expires = jiffies + 1;
+ add_timer(&whitehole_timer);
+ }
+}
+
+static struct net_device_stats *whitehole_get_stats(struct device *dev)
+{
+ struct net_device_stats *stats = (struct net_device_stats *) dev->priv;
+ return stats;
+}
+
+__initfunc(int whitehole_init(struct device *dev))
+{
+ dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOBUFS;
+ memset(dev->priv, 0, sizeof(struct net_device_stats));
+ dev->get_stats = whitehole_get_stats;
+ dev->hard_start_xmit = whitehole_xmit;
+ dev->open = whitehole_open;
+ dev->stop = whitehole_close;
+ ether_setup(dev);
+ dev->tx_queue_len = 0;
+ dev->flags |= IFF_NOARP;
+ dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST);
+ dev->iflink = 0;
+ whitehole_iph.ihl = 5;
+ whitehole_iph.version = 4;
+ whitehole_iph.ttl = 2;
+ whitehole_iph.saddr = in_aton("193.233.7.21");
+ whitehole_iph.daddr = in_aton("193.233.7.10");
+ whitehole_iph.tot_len = htons(20);
+ whitehole_iph.check = ip_compute_csum((void *)&whitehole_iph, 20);
+ return 0;
+}
+
+int net_profile_register(struct net_profile_slot *slot)
+{
+ cli();
+ slot->next = net_profile_chain;
+ net_profile_chain = slot;
+ sti();
+ return 0;
+}
+
+int net_profile_unregister(struct net_profile_slot *slot)
+{
+ struct net_profile_slot **sp, *s;
+
+ for (sp = &net_profile_chain; (s = *sp) != NULL; sp = &s->next) {
+ if (s == slot) {
+ cli();
+ *sp = s->next;
+ sti();
+ return 0;
+ }
+ }
+ return -ESRCH;
+}
+
+
+__initfunc(int net_profile_init(void))
+{
+ int i;
+
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent;
+
+ ent = create_proc_entry("net/profile", 0, 0);
+ ent->read_proc = profile_read_proc;
+#endif
+
+ register_netdevice(&whitehole_dev);
+
+ printk("Evaluating net profiler cost ...");
+#if CPU == 586 || CPU == 686
+ if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC)) {
+ printk(KERN_ERR "Sorry, your CPU does not support TSC. Net profiler disabled.\n");
+ return -1;
+ }
+#endif
+ start_bh_atomic();
+#ifdef __alpha__
+ alpha_tick(0);
+#endif
+ for (i=0; i<1024; i++) {
+ NET_PROFILE_ENTER(total);
+ NET_PROFILE_LEAVE(total);
+ }
+ if (net_prof_total.accumulator.tv_sec) {
+ printk(" too high!\n");
+ } else {
+ net_profile_adjust.tv_usec = net_prof_total.accumulator.tv_usec>>10;
+ printk("%ld units\n", net_profile_adjust.tv_usec);
+ }
+ net_prof_total.hits = 0;
+ net_profile_stamp(&net_prof_total.entered);
+ end_bh_atomic();
+ return 0;
+}
+
+#endif
diff --git a/pfinet/linux-src/net/core/rtnetlink.c b/pfinet/linux-src/net/core/rtnetlink.c
new file mode 100644
index 00000000..7f89e54a
--- /dev/null
+++ b/pfinet/linux-src/net/core/rtnetlink.c
@@ -0,0 +1,512 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Routing netlink socket interface: protocol independent part.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ * Vitaly E. Lavrov RTA_OK arithmetics was wrong.
+ * Alexey Zhuravlev ifi_change does something useful
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/capability.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/string.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/arp.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+
+atomic_t rtnl_rlockct;
+struct wait_queue *rtnl_wait;
+
+
+void rtnl_lock()
+{
+ rtnl_shlock();
+ rtnl_exlock();
+}
+
+void rtnl_unlock()
+{
+ rtnl_exunlock();
+ rtnl_shunlock();
+}
+
+int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
+{
+ memset(tb, 0, sizeof(struct rtattr*)*maxattr);
+
+ while (RTA_OK(rta, len)) {
+ unsigned flavor = rta->rta_type;
+ if (flavor && flavor <= maxattr)
+ tb[flavor-1] = rta;
+ rta = RTA_NEXT(rta, len);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_RTNETLINK
+struct sock *rtnl;
+
+unsigned long rtnl_wlockct;
+
+struct rtnetlink_link * rtnetlink_links[NPROTO];
+
+#define _S 1 /* superuser privileges required */
+#define _X 2 /* exclusive access to tables required */
+#define _G 4 /* GET request */
+
+static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] =
+{
+ NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ NLMSG_LENGTH(sizeof(struct rtmsg)),
+ NLMSG_LENGTH(sizeof(struct ndmsg)),
+ NLMSG_LENGTH(sizeof(struct rtmsg)),
+ NLMSG_LENGTH(sizeof(struct tcmsg)),
+ NLMSG_LENGTH(sizeof(struct tcmsg)),
+ NLMSG_LENGTH(sizeof(struct tcmsg))
+};
+
+static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] =
+{
+ IFLA_MAX,
+ IFA_MAX,
+ RTA_MAX,
+ NDA_MAX,
+ RTA_MAX,
+ TCA_MAX,
+ TCA_MAX,
+ TCA_MAX
+};
+
+void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
+{
+ struct rtattr *rta;
+ int size = RTA_LENGTH(attrlen);
+
+ rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size));
+ rta->rta_type = attrtype;
+ rta->rta_len = size;
+ memcpy(RTA_DATA(rta), data, attrlen);
+}
+
+int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
+{
+ int err = 0;
+
+ NETLINK_CB(skb).dst_groups = group;
+ if (echo)
+ atomic_inc(&skb->users);
+ netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL);
+ if (echo)
+ err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
+ return err;
+}
+
+static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct device *dev,
+ int type, u32 pid, u32 seq, u32 change)
+{
+ struct ifinfomsg *r;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*r));
+ if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
+ r = NLMSG_DATA(nlh);
+ r->ifi_family = AF_UNSPEC;
+ r->ifi_type = dev->type;
+ r->ifi_index = dev->ifindex;
+ r->ifi_flags = dev->flags;
+ r->ifi_change = change;
+
+ RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
+ if (dev->addr_len) {
+ RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
+ RTA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
+ }
+ if (1) {
+ unsigned mtu = dev->mtu;
+ RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu);
+ }
+ if (dev->ifindex != dev->iflink)
+ RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink);
+ if (dev->qdisc_sleeping)
+ RTA_PUT(skb, IFLA_QDISC,
+ strlen(dev->qdisc_sleeping->ops->id) + 1,
+ dev->qdisc_sleeping->ops->id);
+ if (dev->get_stats) {
+ struct net_device_stats *stats = dev->get_stats(dev);
+ if (stats)
+ RTA_PUT(skb, IFLA_STATS, sizeof(*stats), stats);
+ }
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx;
+ int s_idx = cb->args[0];
+ struct device *dev;
+
+ for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+ if (idx < s_idx)
+ continue;
+ if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 0) <= 0)
+ break;
+ }
+ cb->args[0] = idx;
+
+ return skb->len;
+}
+
+int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx;
+ int s_idx = cb->family;
+
+ if (s_idx == 0)
+ s_idx = 1;
+ for (idx=1; idx<NPROTO; idx++) {
+ int type = cb->nlh->nlmsg_type-RTM_BASE;
+ if (idx < s_idx || idx == PF_PACKET)
+ continue;
+ if (rtnetlink_links[idx] == NULL ||
+ rtnetlink_links[idx][type].dumpit == NULL)
+ continue;
+ if (idx > s_idx)
+ memset(&cb->args[0], 0, sizeof(cb->args));
+ if (rtnetlink_links[idx][type].dumpit(skb, cb) == 0)
+ continue;
+ if (skb_tailroom(skb) < 256)
+ break;
+ }
+ cb->family = idx;
+
+ return skb->len;
+}
+
+void rtmsg_ifinfo(int type, struct device *dev)
+{
+ struct sk_buff *skb;
+ int size = NLMSG_GOODSIZE;
+
+ skb = alloc_skb(size, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, ~0U) < 0) {
+ kfree_skb(skb);
+ return;
+ }
+ NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
+ netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_KERNEL);
+}
+
+static int rtnetlink_done(struct netlink_callback *cb)
+{
+ if (cap_raised(NETLINK_CB(cb->skb).eff_cap, CAP_NET_ADMIN) && cb->nlh->nlmsg_flags&NLM_F_ATOMIC)
+ rtnl_shunlock();
+ return 0;
+}
+
+/* Process one rtnetlink message. */
+
+extern __inline__ int
+rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
+{
+ struct rtnetlink_link *link;
+ struct rtnetlink_link *link_tab;
+ struct rtattr *rta[RTATTR_MAX];
+
+ int exclusive = 0;
+ int sz_idx, kind;
+ int min_len;
+ int family;
+ int type;
+ int err;
+
+ /* Only requests are handled by kernel now */
+ if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
+ return 0;
+
+ type = nlh->nlmsg_type;
+
+ /* A control message: ignore them */
+ if (type < RTM_BASE)
+ return 0;
+
+ /* Unknown message: reply with EINVAL */
+ if (type > RTM_MAX)
+ goto err_inval;
+
+ type -= RTM_BASE;
+
+ /* All the messages must have at least 1 byte length */
+ if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg)))
+ return 0;
+
+ family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;
+ if (family > NPROTO) {
+ *errp = -EAFNOSUPPORT;
+ return -1;
+ }
+
+ link_tab = rtnetlink_links[family];
+ if (link_tab == NULL)
+ link_tab = rtnetlink_links[PF_UNSPEC];
+ link = &link_tab[type];
+
+ sz_idx = type>>2;
+ kind = type&3;
+
+ if (kind != 2 && !cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
+ *errp = -EPERM;
+ return -1;
+ }
+
+ if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
+ u32 rlen;
+
+ if (link->dumpit == NULL)
+ link = &(rtnetlink_links[PF_UNSPEC][type]);
+
+ if (link->dumpit == NULL)
+ goto err_inval;
+
+ /* Super-user locks all the tables to get atomic snapshot */
+ if (cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)
+ && nlh->nlmsg_flags&NLM_F_ATOMIC)
+ atomic_inc(&rtnl_rlockct);
+ if ((*errp = netlink_dump_start(rtnl, skb, nlh,
+ link->dumpit,
+ rtnetlink_done)) != 0) {
+ if (cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN) && nlh->nlmsg_flags&NLM_F_ATOMIC)
+ atomic_dec(&rtnl_rlockct);
+ return -1;
+ }
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
+ skb_pull(skb, rlen);
+ return -1;
+ }
+
+ if (kind != 2) {
+ if (rtnl_exlock_nowait()) {
+ *errp = 0;
+ return -1;
+ }
+ exclusive = 1;
+ }
+
+ memset(&rta, 0, sizeof(rta));
+
+ min_len = rtm_min[sz_idx];
+ if (nlh->nlmsg_len < min_len)
+ goto err_inval;
+
+ if (nlh->nlmsg_len > min_len) {
+ int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+ struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len);
+
+ while (RTA_OK(attr, attrlen)) {
+ unsigned flavor = attr->rta_type;
+ if (flavor) {
+ if (flavor > rta_max[sz_idx])
+ goto err_inval;
+ rta[flavor-1] = attr;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+ }
+
+ if (link->doit == NULL)
+ link = &(rtnetlink_links[PF_UNSPEC][type]);
+ if (link->doit == NULL)
+ goto err_inval;
+ err = link->doit(skb, nlh, (void *)&rta);
+
+ if (exclusive)
+ rtnl_exunlock();
+ *errp = err;
+ return err;
+
+err_inval:
+ if (exclusive)
+ rtnl_exunlock();
+ *errp = -EINVAL;
+ return -1;
+}
+
+/*
+ * Process one packet of messages.
+ * Malformed skbs with wrong lengths of messages are discarded silently.
+ */
+
+extern __inline__ int rtnetlink_rcv_skb(struct sk_buff *skb)
+{
+ int err;
+ struct nlmsghdr * nlh;
+
+ while (skb->len >= NLMSG_SPACE(0)) {
+ u32 rlen;
+
+ nlh = (struct nlmsghdr *)skb->data;
+ if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+ return 0;
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
+ if (rtnetlink_rcv_msg(skb, nlh, &err)) {
+ /* Not error, but we must interrupt processing here:
+ * Note, that in this case we do not pull message
+ * from skb, it will be processed later.
+ */
+ if (err == 0)
+ return -1;
+ netlink_ack(skb, nlh, err);
+ } else if (nlh->nlmsg_flags&NLM_F_ACK)
+ netlink_ack(skb, nlh, 0);
+ skb_pull(skb, rlen);
+ }
+
+ return 0;
+}
+
+/*
+ * rtnetlink input queue processing routine:
+ * - try to acquire shared lock. If it is failed, defer processing.
+ * - feed skbs to rtnetlink_rcv_skb, until it refuse a message,
+ * that will occur, when a dump started and/or acquisition of
+ * exclusive lock failed.
+ */
+
+static void rtnetlink_rcv(struct sock *sk, int len)
+{
+ struct sk_buff *skb;
+
+ if (rtnl_shlock_nowait())
+ return;
+
+ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+ if (rtnetlink_rcv_skb(skb)) {
+ if (skb->len)
+ skb_queue_head(&sk->receive_queue, skb);
+ else
+ kfree_skb(skb);
+ break;
+ }
+ kfree_skb(skb);
+ }
+
+ rtnl_shunlock();
+}
+
+static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
+{
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, rtnetlink_dump_ifinfo, },
+ { NULL, NULL, },
+
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, rtnetlink_dump_all, },
+ { NULL, NULL, },
+
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, rtnetlink_dump_all, },
+ { NULL, NULL, },
+
+ { neigh_add, NULL, },
+ { neigh_delete, NULL, },
+ { NULL, neigh_dump_info, },
+ { NULL, NULL, },
+
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+};
+
+
+static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+ switch (event) {
+ case NETDEV_UNREGISTER:
+ rtmsg_ifinfo(RTM_DELLINK, dev);
+ break;
+ default:
+ rtmsg_ifinfo(RTM_NEWLINK, dev);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+struct notifier_block rtnetlink_dev_notifier = {
+ rtnetlink_event,
+ NULL,
+ 0
+};
+
+
+__initfunc(void rtnetlink_init(void))
+{
+#ifdef RTNL_DEBUG
+ printk("Initializing RT netlink socket\n");
+#endif
+ rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv);
+ if (rtnl == NULL)
+ panic("rtnetlink_init: cannot initialize rtnetlink\n");
+ register_netdevice_notifier(&rtnetlink_dev_notifier);
+ rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table;
+ rtnetlink_links[PF_PACKET] = link_rtnetlink_table;
+}
+
+
+
+#endif
diff --git a/pfinet/linux-src/net/core/scm.c b/pfinet/linux-src/net/core/scm.c
new file mode 100644
index 00000000..cdb5f3d0
--- /dev/null
+++ b/pfinet/linux-src/net/core/scm.c
@@ -0,0 +1,280 @@
+/* scm.c - Socket level control messages processing.
+ *
+ * Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ * Alignment and value checking mods by Craig Metz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/net.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/inet.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/rarp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/scm.h>
+
+
+/*
+ * Only allow a user to send credentials, that they could set with
+ * setu(g)id.
+ */
+
+static __inline__ int scm_check_creds(struct ucred *creds)
+{
+ if ((creds->pid == current->pid || capable(CAP_SYS_ADMIN)) &&
+ ((creds->uid == current->uid || creds->uid == current->euid ||
+ creds->uid == current->suid) || capable(CAP_SETUID)) &&
+ ((creds->gid == current->gid || creds->gid == current->egid ||
+ creds->gid == current->sgid) || capable(CAP_SETGID))) {
+ return 0;
+ }
+ return -EPERM;
+}
+
+static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
+{
+ int *fdp = (int*)CMSG_DATA(cmsg);
+ struct scm_fp_list *fpl = *fplp;
+ struct file **fpp;
+ int i, num;
+
+ num = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)))/sizeof(int);
+
+ if (num <= 0)
+ return 0;
+
+ if (num > SCM_MAX_FD)
+ return -EINVAL;
+
+ if (!fpl)
+ {
+ fpl = kmalloc(sizeof(struct scm_fp_list), GFP_KERNEL);
+ if (!fpl)
+ return -ENOMEM;
+ *fplp = fpl;
+ fpl->count = 0;
+ }
+ fpp = &fpl->fp[fpl->count];
+
+ if (fpl->count + num > SCM_MAX_FD)
+ return -EINVAL;
+
+ /*
+ * Verify the descriptors and increment the usage count.
+ */
+
+ for (i=0; i< num; i++)
+ {
+ int fd = fdp[i];
+ struct file *file;
+
+ if (fd < 0 || !(file = fget(fd)))
+ return -EBADF;
+ *fpp++ = file;
+ fpl->count++;
+ }
+ return num;
+}
+
+void __scm_destroy(struct scm_cookie *scm)
+{
+ struct scm_fp_list *fpl = scm->fp;
+ int i;
+
+ if (fpl) {
+ scm->fp = NULL;
+ for (i=fpl->count-1; i>=0; i--)
+ fput(fpl->fp[i]);
+ kfree(fpl);
+ }
+}
+
+int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
+{
+ struct cmsghdr *cmsg;
+ int err;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
+ {
+ err = -EINVAL;
+
+ /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */
+ /* The first check was omitted in <= 2.2.5. The reasoning was
+ that parser checks cmsg_len in any case, so that
+ additional check would be work duplication.
+ But if cmsg_level is not SOL_SOCKET, we do not check
+ for too short ancillary data object at all! Oops.
+ OK, let's add it...
+ */
+ if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
+ (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
+ + cmsg->cmsg_len) > msg->msg_controllen)
+ goto error;
+
+ if (cmsg->cmsg_level != SOL_SOCKET)
+ continue;
+
+ switch (cmsg->cmsg_type)
+ {
+ case SCM_RIGHTS:
+ err=scm_fp_copy(cmsg, &p->fp);
+ if (err<0)
+ goto error;
+ break;
+ case SCM_CREDENTIALS:
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
+ goto error;
+ memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred));
+ err = scm_check_creds(&p->creds);
+ if (err)
+ goto error;
+ break;
+ default:
+ goto error;
+ }
+ }
+
+ if (p->fp && !p->fp->count)
+ {
+ kfree(p->fp);
+ p->fp = NULL;
+ }
+
+ err = -EINVAL;
+ if (msg->msg_flags & MSG_CTLFLAGS)
+ goto error;
+
+ return 0;
+
+error:
+ scm_destroy(p);
+ return err;
+}
+
+int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
+{
+ struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
+ struct cmsghdr cmhdr;
+ int cmlen = CMSG_LEN(len);
+ int err;
+
+ if (cm==NULL || msg->msg_controllen < sizeof(*cm)) {
+ msg->msg_flags |= MSG_CTRUNC;
+ return 0; /* XXX: return error? check spec. */
+ }
+ if (msg->msg_controllen < cmlen) {
+ msg->msg_flags |= MSG_CTRUNC;
+ cmlen = msg->msg_controllen;
+ }
+ cmhdr.cmsg_level = level;
+ cmhdr.cmsg_type = type;
+ cmhdr.cmsg_len = cmlen;
+
+ err = -EFAULT;
+ if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
+ goto out;
+ if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
+ goto out;
+ cmlen = CMSG_SPACE(len);
+ msg->msg_control += cmlen;
+ msg->msg_controllen -= cmlen;
+ err = 0;
+out:
+ return err;
+}
+
+void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
+{
+ struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
+
+ int fdmax = (msg->msg_controllen - sizeof(struct cmsghdr))/sizeof(int);
+ int fdnum = scm->fp->count;
+ struct file **fp = scm->fp->fp;
+ int *cmfptr;
+ int err = 0, i;
+
+ if (fdnum < fdmax)
+ fdmax = fdnum;
+
+ for (i=0, cmfptr=(int*)CMSG_DATA(cm); i<fdmax; i++, cmfptr++)
+ {
+ int new_fd;
+ err = get_unused_fd();
+ if (err < 0)
+ break;
+ new_fd = err;
+ err = put_user(new_fd, cmfptr);
+ if (err) {
+ put_unused_fd(new_fd);
+ break;
+ }
+ /* Bump the usage count and install the file. */
+ fp[i]->f_count++;
+ current->files->fd[new_fd] = fp[i];
+ }
+
+ if (i > 0)
+ {
+ int cmlen = CMSG_LEN(i*sizeof(int));
+ if (!err)
+ err = put_user(SOL_SOCKET, &cm->cmsg_level);
+ if (!err)
+ err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+ if (!err)
+ err = put_user(cmlen, &cm->cmsg_len);
+ if (!err) {
+ cmlen = CMSG_SPACE(i*sizeof(int));
+ msg->msg_control += cmlen;
+ msg->msg_controllen -= cmlen;
+ }
+ }
+ if (i < fdnum)
+ msg->msg_flags |= MSG_CTRUNC;
+
+ /*
+ * All of the files that fit in the message have had their
+ * usage counts incremented, so we just free the list.
+ */
+ __scm_destroy(scm);
+}
+
+struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
+{
+ struct scm_fp_list *new_fpl;
+ int i;
+
+ if (!fpl)
+ return NULL;
+
+ new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL);
+ if (new_fpl) {
+ memcpy(new_fpl, fpl, sizeof(*fpl));
+
+ for (i=fpl->count-1; i>=0; i--)
+ fpl->fp[i]->f_count++;
+ }
+ return new_fpl;
+}
diff --git a/pfinet/linux-src/net/core/skbuff.c b/pfinet/linux-src/net/core/skbuff.c
new file mode 100644
index 00000000..b7636437
--- /dev/null
+++ b/pfinet/linux-src/net/core/skbuff.c
@@ -0,0 +1,385 @@
+/*
+ * Routines having to do with the 'struct sk_buff' memory handlers.
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
+ * Florian La Roche <rzsfl@rz.uni-sb.de>
+ *
+ * Version: $Id: skbuff.c,v 1.55 1999/02/23 08:12:27 davem Exp $
+ *
+ * Fixes:
+ * Alan Cox : Fixed the worst of the load balancer bugs.
+ * Dave Platt : Interrupt stacking fix.
+ * Richard Kooijman : Timestamp fixes.
+ * Alan Cox : Changed buffer format.
+ * Alan Cox : destructor hook for AF_UNIX etc.
+ * Linus Torvalds : Better skb_clone.
+ * Alan Cox : Added skb_copy.
+ * Alan Cox : Added all the changed routines Linus
+ * only put in the headers
+ * Ray VanTassle : Fixed --skb->lock in free
+ * Alan Cox : skb_copy copy arp field
+ * Andi Kleen : slabified it.
+ *
+ * NOTE:
+ * The __skb_ routines should be called with interrupts
+ * disabled, or you better be *real* sure that the operation is atomic
+ * with respect to whatever list is being frobbed (e.g. via lock_sock()
+ * or via disabling bottom half handlers, etc).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The functions in this file will not compile correctly with gcc 2.4.x
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/malloc.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/dst.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+/*
+ * Skb list spinlock
+ */
+spinlock_t skb_queue_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Resource tracking variables
+ */
+
+static atomic_t net_skbcount = ATOMIC_INIT(0);
+static atomic_t net_allocs = ATOMIC_INIT(0);
+static atomic_t net_fails = ATOMIC_INIT(0);
+
+extern atomic_t ip_frag_mem;
+
+static kmem_cache_t *skbuff_head_cache;
+
+/*
+ * Keep out-of-line to prevent kernel bloat.
+ * __builtin_return_address is not used because it is not always
+ * reliable.
+ */
+
+void skb_over_panic(struct sk_buff *skb, int sz, void *here)
+{
+ panic("skput:over: %p:%d put:%d dev:%s",
+ here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
+
+void skb_under_panic(struct sk_buff *skb, int sz, void *here)
+{
+ panic("skput:under: %p:%d put:%d dev:%s",
+ here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
+}
+
+void show_net_buffers(void)
+{
+ printk("Networking buffers in use : %u\n",
+ atomic_read(&net_skbcount));
+ printk("Total network buffer allocations : %u\n",
+ atomic_read(&net_allocs));
+ printk("Total failed network buffer allocs : %u\n",
+ atomic_read(&net_fails));
+#ifdef CONFIG_INET
+ printk("IP fragment buffer size : %u\n",
+ atomic_read(&ip_frag_mem));
+#endif
+}
+
+/* Allocate a new skbuff. We do this ourselves so we can fill in a few
+ * 'private' fields and also do memory statistics to find all the
+ * [BEEP] leaks.
+ *
+ */
+
+struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
+{
+ struct sk_buff *skb;
+ u8 *data;
+
+ if (in_interrupt() && (gfp_mask & __GFP_WAIT)) {
+ static int count = 0;
+ if (++count < 5) {
+ printk(KERN_ERR "alloc_skb called nonatomically "
+ "from interrupt %p\n", __builtin_return_address(0));
+ }
+ gfp_mask &= ~__GFP_WAIT;
+ }
+
+ /* Get the HEAD */
+ skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
+ if (skb == NULL)
+ goto nohead;
+
+ /* Get the DATA. Size must match skb_add_mtu(). */
+ size = ((size + 15) & ~15);
+ data = kmalloc(size + sizeof(atomic_t), gfp_mask);
+ if (data == NULL)
+ goto nodata;
+
+ /* Note that this counter is useless now - you can just look in the
+ * skbuff_head entry in /proc/slabinfo. We keep it only for emergency
+ * cases.
+ */
+ atomic_inc(&net_allocs);
+
+ skb->truesize = size;
+
+ atomic_inc(&net_skbcount);
+
+ /* Load the data pointers. */
+ skb->head = data;
+ skb->data = data;
+ skb->tail = data;
+ skb->end = data + size;
+
+ /* Set up other state */
+ skb->len = 0;
+ skb->is_clone = 0;
+ skb->cloned = 0;
+
+ atomic_set(&skb->users, 1);
+ atomic_set(skb_datarefp(skb), 1);
+ return skb;
+
+nodata:
+ kmem_cache_free(skbuff_head_cache, skb);
+nohead:
+ atomic_inc(&net_fails);
+ return NULL;
+}
+
+
+/*
+ * Slab constructor for a skb head.
+ */
+static inline void skb_headerinit(void *p, kmem_cache_t *cache,
+ unsigned long flags)
+{
+ struct sk_buff *skb = p;
+
+ skb->destructor = NULL;
+ skb->pkt_type = PACKET_HOST; /* Default type */
+ skb->pkt_bridged = 0; /* Not bridged */
+ skb->prev = skb->next = NULL;
+ skb->list = NULL;
+ skb->sk = NULL;
+ skb->stamp.tv_sec=0; /* No idea about time */
+ skb->ip_summed = 0;
+ skb->security = 0; /* By default packets are insecure */
+ skb->dst = NULL;
+#ifdef CONFIG_IP_FIREWALL
+ skb->fwmark = 0;
+#endif
+ memset(skb->cb, 0, sizeof(skb->cb));
+ skb->priority = 0;
+}
+
+/*
+ * Free an skbuff by memory without cleaning the state.
+ */
+void kfree_skbmem(struct sk_buff *skb)
+{
+ if (!skb->cloned || atomic_dec_and_test(skb_datarefp(skb)))
+ kfree(skb->head);
+
+ kmem_cache_free(skbuff_head_cache, skb);
+ atomic_dec(&net_skbcount);
+}
+
+/*
+ * Free an sk_buff. Release anything attached to the buffer. Clean the state.
+ */
+
+void __kfree_skb(struct sk_buff *skb)
+{
+ if (skb->list)
+ printk(KERN_WARNING "Warning: kfree_skb passed an skb still "
+ "on a list (from %p).\n", __builtin_return_address(0));
+
+ dst_release(skb->dst);
+ if(skb->destructor)
+ skb->destructor(skb);
+ skb_headerinit(skb, NULL, 0); /* clean state */
+ kfree_skbmem(skb);
+}
+
+/*
+ * Duplicate an sk_buff. The new one is not owned by a socket.
+ */
+
+struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
+{
+ struct sk_buff *n;
+
+ n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
+ if (!n)
+ return NULL;
+
+ memcpy(n, skb, sizeof(*n));
+ atomic_inc(skb_datarefp(skb));
+ skb->cloned = 1;
+
+ atomic_inc(&net_allocs);
+ atomic_inc(&net_skbcount);
+ dst_clone(n->dst);
+ n->cloned = 1;
+ n->next = n->prev = NULL;
+ n->list = NULL;
+ n->sk = NULL;
+ n->is_clone = 1;
+ atomic_set(&n->users, 1);
+ n->destructor = NULL;
+ return n;
+}
+
+/*
+ * This is slower, and copies the whole data area
+ */
+
+struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask)
+{
+ struct sk_buff *n;
+ unsigned long offset;
+
+ /*
+ * Allocate the copy buffer
+ */
+
+ n=alloc_skb(skb->end - skb->head, gfp_mask);
+ if(n==NULL)
+ return NULL;
+
+ /*
+ * Shift between the two data areas in bytes
+ */
+
+ offset=n->head-skb->head;
+
+ /* Set the data pointer */
+ skb_reserve(n,skb->data-skb->head);
+ /* Set the tail pointer and length */
+ skb_put(n,skb->len);
+ /* Copy the bytes */
+ memcpy(n->head,skb->head,skb->end-skb->head);
+ n->csum = skb->csum;
+ n->list=NULL;
+ n->sk=NULL;
+ n->dev=skb->dev;
+ n->priority=skb->priority;
+ n->protocol=skb->protocol;
+ n->dst=dst_clone(skb->dst);
+ n->h.raw=skb->h.raw+offset;
+ n->nh.raw=skb->nh.raw+offset;
+ n->mac.raw=skb->mac.raw+offset;
+ memcpy(n->cb, skb->cb, sizeof(skb->cb));
+ n->used=skb->used;
+ n->is_clone=0;
+ atomic_set(&n->users, 1);
+ n->pkt_type=skb->pkt_type;
+ n->stamp=skb->stamp;
+ n->destructor = NULL;
+ n->security=skb->security;
+#ifdef CONFIG_IP_FIREWALL
+ n->fwmark = skb->fwmark;
+#endif
+ return n;
+}
+
+struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom)
+{
+ struct sk_buff *n;
+ unsigned long offset;
+ int headroom = skb_headroom(skb);
+
+ /*
+ * Allocate the copy buffer
+ */
+
+ n=alloc_skb(skb->truesize+newheadroom-headroom, GFP_ATOMIC);
+ if(n==NULL)
+ return NULL;
+
+ skb_reserve(n,newheadroom);
+
+ /*
+ * Shift between the two data areas in bytes
+ */
+
+ offset=n->data-skb->data;
+
+ /* Set the tail pointer and length */
+ skb_put(n,skb->len);
+ /* Copy the bytes */
+ memcpy(n->data,skb->data,skb->len);
+ n->list=NULL;
+ n->sk=NULL;
+ n->priority=skb->priority;
+ n->protocol=skb->protocol;
+ n->dev=skb->dev;
+ n->dst=dst_clone(skb->dst);
+ n->h.raw=skb->h.raw+offset;
+ n->nh.raw=skb->nh.raw+offset;
+ n->mac.raw=skb->mac.raw+offset;
+ memcpy(n->cb, skb->cb, sizeof(skb->cb));
+ n->used=skb->used;
+ n->is_clone=0;
+ atomic_set(&n->users, 1);
+ n->pkt_type=skb->pkt_type;
+ n->stamp=skb->stamp;
+ n->destructor = NULL;
+ n->security=skb->security;
+#ifdef CONFIG_IP_FIREWALL
+ n->fwmark = skb->fwmark;
+#endif
+
+ return n;
+}
+
+#if 0
+/*
+ * Tune the memory allocator for a new MTU size.
+ */
+void skb_add_mtu(int mtu)
+{
+ /* Must match allocation in alloc_skb */
+ mtu = ((mtu + 15) & ~15) + sizeof(atomic_t);
+
+ kmem_add_cache_size(mtu);
+}
+#endif
+
+void __init skb_init(void)
+{
+ skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
+ sizeof(struct sk_buff),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ skb_headerinit, NULL);
+ if (!skbuff_head_cache)
+ panic("cannot create skbuff cache");
+}
diff --git a/pfinet/linux-src/net/core/sock.c b/pfinet/linux-src/net/core/sock.c
new file mode 100644
index 00000000..c47c935b
--- /dev/null
+++ b/pfinet/linux-src/net/core/sock.c
@@ -0,0 +1,1051 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Generic socket support routines. Memory allocators, socket lock/release
+ * handler for protocols to use and generic option handler.
+ *
+ *
+ * Version: $Id: sock.c,v 1.80 1999/05/08 03:04:34 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ * Alan Cox, <A.Cox@swansea.ac.uk>
+ *
+ * Fixes:
+ * Alan Cox : Numerous verify_area() problems
+ * Alan Cox : Connecting on a connecting socket
+ * now returns an error for tcp.
+ * Alan Cox : sock->protocol is set correctly.
+ * and is not sometimes left as 0.
+ * Alan Cox : connect handles icmp errors on a
+ * connect properly. Unfortunately there
+ * is a restart syscall nasty there. I
+ * can't match BSD without hacking the C
+ * library. Ideas urgently sought!
+ * Alan Cox : Disallow bind() to addresses that are
+ * not ours - especially broadcast ones!!
+ * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost)
+ * Alan Cox : sock_wfree/sock_rfree don't destroy sockets,
+ * instead they leave that for the DESTROY timer.
+ * Alan Cox : Clean up error flag in accept
+ * Alan Cox : TCP ack handling is buggy, the DESTROY timer
+ * was buggy. Put a remove_sock() in the handler
+ * for memory when we hit 0. Also altered the timer
+ * code. The ACK stuff can wait and needs major
+ * TCP layer surgery.
+ * Alan Cox : Fixed TCP ack bug, removed remove sock
+ * and fixed timer/inet_bh race.
+ * Alan Cox : Added zapped flag for TCP
+ * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code
+ * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
+ * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources
+ * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing.
+ * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so...
+ * Rick Sladkey : Relaxed UDP rules for matching packets.
+ * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support
+ * Pauline Middelink : identd support
+ * Alan Cox : Fixed connect() taking signals I think.
+ * Alan Cox : SO_LINGER supported
+ * Alan Cox : Error reporting fixes
+ * Anonymous : inet_create tidied up (sk->reuse setting)
+ * Alan Cox : inet sockets don't set sk->type!
+ * Alan Cox : Split socket option code
+ * Alan Cox : Callbacks
+ * Alan Cox : Nagle flag for Charles & Johannes stuff
+ * Alex : Removed restriction on inet fioctl
+ * Alan Cox : Splitting INET from NET core
+ * Alan Cox : Fixed bogus SO_TYPE handling in getsockopt()
+ * Adam Caldwell : Missing return in SO_DONTROUTE/SO_DEBUG code
+ * Alan Cox : Split IP from generic code
+ * Alan Cox : New kfree_skbmem()
+ * Alan Cox : Make SO_DEBUG superuser only.
+ * Alan Cox : Allow anyone to clear SO_DEBUG
+ * (compatibility fix)
+ * Alan Cox : Added optimistic memory grabbing for AF_UNIX throughput.
+ * Alan Cox : Allocator for a socket is settable.
+ * Alan Cox : SO_ERROR includes soft errors.
+ * Alan Cox : Allow NULL arguments on some SO_ opts
+ * Alan Cox : Generic socket allocation to make hooks
+ * easier (suggested by Craig Metz).
+ * Michael Pall : SO_ERROR returns positive errno again
+ * Steve Whitehouse: Added default destructor to free
+ * protocol private data.
+ * Steve Whitehouse: Added various other default routines
+ * common to several socket families.
+ * Chris Evans : Call suser() check last on F_SETOWN
+ * Jay Schulist : Added SO_ATTACH_FILTER and SO_DETACH_FILTER.
+ * Andi Kleen : Add sock_kmalloc()/sock_kfree_s()
+ * Andi Kleen : Fix write_space callback
+ *
+ * To Fix:
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/arp.h>
+#include <net/rarp.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/raw.h>
+#include <net/icmp.h>
+#include <linux/ipsec.h>
+
+#ifdef CONFIG_FILTER
+#include <linux/filter.h>
+#endif
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+/* Run time adjustable parameters. */
+__u32 sysctl_wmem_max = SK_WMEM_MAX;
+__u32 sysctl_rmem_max = SK_RMEM_MAX;
+__u32 sysctl_wmem_default = SK_WMEM_MAX;
+__u32 sysctl_rmem_default = SK_RMEM_MAX;
+
+/* Maximal space eaten by iovec or ancillary data plus some space */
+int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512);
+
+/*
+ * This is meant for all protocols to use and covers goings on
+ * at the socket level. Everything here is generic.
+ */
+
+int sock_setsockopt(struct socket *sock, int level, int optname,
+ char *optval, int optlen)
+{
+ struct sock *sk=sock->sk;
+#ifdef CONFIG_FILTER
+ struct sk_filter *filter;
+#endif
+ int val;
+ int valbool;
+ int err;
+ struct linger ling;
+ int ret = 0;
+
+ /*
+ * Options without arguments
+ */
+
+#ifdef SO_DONTLINGER /* Compatibility item... */
+ switch(optname)
+ {
+ case SO_DONTLINGER:
+ sk->linger=0;
+ return 0;
+ }
+#endif
+
+ if(optlen<sizeof(int))
+ return(-EINVAL);
+
+ err = get_user(val, (int *)optval);
+ if (err)
+ return err;
+
+ valbool = val?1:0;
+
+ switch(optname)
+ {
+ case SO_DEBUG:
+ if(val && !capable(CAP_NET_ADMIN))
+ {
+ ret = -EACCES;
+ }
+ else
+ sk->debug=valbool;
+ break;
+ case SO_REUSEADDR:
+ sk->reuse = valbool;
+ break;
+ case SO_TYPE:
+ case SO_ERROR:
+ ret = -ENOPROTOOPT;
+ break;
+ case SO_DONTROUTE:
+ sk->localroute=valbool;
+ break;
+ case SO_BROADCAST:
+ sk->broadcast=valbool;
+ break;
+ case SO_SNDBUF:
+ /* Don't error on this BSD doesn't and if you think
+ about it this is right. Otherwise apps have to
+ play 'guess the biggest size' games. RCVBUF/SNDBUF
+ are treated in BSD as hints */
+
+ if (val > sysctl_wmem_max)
+ val = sysctl_wmem_max;
+
+ sk->sndbuf = max(val*2,2048);
+
+ /*
+ * Wake up sending tasks if we
+ * upped the value.
+ */
+ sk->write_space(sk);
+ break;
+
+ case SO_RCVBUF:
+ /* Don't error on this BSD doesn't and if you think
+ about it this is right. Otherwise apps have to
+ play 'guess the biggest size' games. RCVBUF/SNDBUF
+ are treated in BSD as hints */
+
+ if (val > sysctl_rmem_max)
+ val = sysctl_rmem_max;
+
+ /* FIXME: is this lower bound the right one? */
+ sk->rcvbuf = max(val*2,256);
+ break;
+
+ case SO_KEEPALIVE:
+#ifdef CONFIG_INET
+ if (sk->protocol == IPPROTO_TCP)
+ {
+ tcp_set_keepalive(sk, valbool);
+ }
+#endif
+ sk->keepopen = valbool;
+ break;
+
+ case SO_OOBINLINE:
+ sk->urginline = valbool;
+ break;
+
+ case SO_NO_CHECK:
+ sk->no_check = valbool;
+ break;
+
+ case SO_PRIORITY:
+ if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN))
+ sk->priority = val;
+ else
+ return(-EPERM);
+ break;
+
+ case SO_LINGER:
+ if(optlen<sizeof(ling))
+ return -EINVAL; /* 1003.1g */
+ err = copy_from_user(&ling,optval,sizeof(ling));
+ if (err)
+ {
+ ret = -EFAULT;
+ break;
+ }
+ if(ling.l_onoff==0)
+ sk->linger=0;
+ else
+ {
+ sk->lingertime=ling.l_linger;
+ sk->linger=1;
+ }
+ break;
+
+ case SO_BSDCOMPAT:
+ sk->bsdism = valbool;
+ break;
+
+ case SO_PASSCRED:
+ sock->passcred = valbool;
+ break;
+
+
+#ifdef CONFIG_NETDEVICES
+ case SO_BINDTODEVICE:
+ {
+ char devname[IFNAMSIZ];
+
+ /* Sorry... */
+ if (!capable(CAP_NET_RAW))
+ return -EPERM;
+
+ /* Bind this socket to a particular device like "eth0",
+ * as specified in the passed interface name. If the
+ * name is "" or the option length is zero the socket
+ * is not bound.
+ */
+
+ if (!valbool) {
+ sk->bound_dev_if = 0;
+ } else {
+ if (optlen > IFNAMSIZ)
+ optlen = IFNAMSIZ;
+ if (copy_from_user(devname, optval, optlen))
+ return -EFAULT;
+
+ /* Remove any cached route for this socket. */
+ lock_sock(sk);
+ dst_release(xchg(&sk->dst_cache, NULL));
+ release_sock(sk);
+
+ if (devname[0] == '\0') {
+ sk->bound_dev_if = 0;
+ } else {
+ struct device *dev = dev_get(devname);
+ if (!dev)
+ return -EINVAL;
+ sk->bound_dev_if = dev->ifindex;
+ }
+ return 0;
+ }
+ }
+#endif
+
+
+#ifdef CONFIG_FILTER
+ case SO_ATTACH_FILTER:
+ ret = -EINVAL;
+ if (optlen == sizeof(struct sock_fprog)) {
+ struct sock_fprog fprog;
+
+ ret = -EFAULT;
+ if (copy_from_user(&fprog, optval, sizeof(fprog)))
+ break;
+
+ ret = sk_attach_filter(&fprog, sk);
+ }
+ break;
+
+ case SO_DETACH_FILTER:
+ filter = sk->filter;
+ if(filter) {
+ sk->filter = NULL;
+ synchronize_bh();
+ sk_filter_release(sk, filter);
+ return 0;
+ }
+ return -ENOENT;
+#endif
+ /* We implement the SO_SNDLOWAT etc to
+ not be settable (1003.1g 5.3) */
+ default:
+ return(-ENOPROTOOPT);
+ }
+ return ret;
+}
+
+
+int sock_getsockopt(struct socket *sock, int level, int optname,
+ char *optval, int *optlen)
+{
+ struct sock *sk = sock->sk;
+
+ union
+ {
+ int val;
+ struct linger ling;
+ struct timeval tm;
+ } v;
+
+ int lv=sizeof(int),len;
+
+ if(get_user(len,optlen))
+ return -EFAULT;
+
+ switch(optname)
+ {
+ case SO_DEBUG:
+ v.val = sk->debug;
+ break;
+
+ case SO_DONTROUTE:
+ v.val = sk->localroute;
+ break;
+
+ case SO_BROADCAST:
+ v.val= sk->broadcast;
+ break;
+
+ case SO_SNDBUF:
+ v.val=sk->sndbuf;
+ break;
+
+ case SO_RCVBUF:
+ v.val =sk->rcvbuf;
+ break;
+
+ case SO_REUSEADDR:
+ v.val = sk->reuse;
+ break;
+
+ case SO_KEEPALIVE:
+ v.val = sk->keepopen;
+ break;
+
+ case SO_TYPE:
+ v.val = sk->type;
+ break;
+
+ case SO_ERROR:
+ v.val = -sock_error(sk);
+ if(v.val==0)
+ v.val=xchg(&sk->err_soft,0);
+ break;
+
+ case SO_OOBINLINE:
+ v.val = sk->urginline;
+ break;
+
+ case SO_NO_CHECK:
+ v.val = sk->no_check;
+ break;
+
+ case SO_PRIORITY:
+ v.val = sk->priority;
+ break;
+
+ case SO_LINGER:
+ lv=sizeof(v.ling);
+ v.ling.l_onoff=sk->linger;
+ v.ling.l_linger=sk->lingertime;
+ break;
+
+ case SO_BSDCOMPAT:
+ v.val = sk->bsdism;
+ break;
+
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ lv=sizeof(struct timeval);
+ v.tm.tv_sec=0;
+ v.tm.tv_usec=0;
+ break;
+
+ case SO_RCVLOWAT:
+ case SO_SNDLOWAT:
+ v.val=1;
+ break;
+
+ case SO_PASSCRED:
+ v.val = sock->passcred;
+ break;
+
+ case SO_PEERCRED:
+ lv=sizeof(sk->peercred);
+ len=min(len, lv);
+ if(copy_to_user((void*)optval, &sk->peercred, len))
+ return -EFAULT;
+ goto lenout;
+
+ default:
+ return(-ENOPROTOOPT);
+ }
+ len=min(len,lv);
+ if(copy_to_user(optval,&v,len))
+ return -EFAULT;
+lenout:
+ if(put_user(len, optlen))
+ return -EFAULT;
+ return 0;
+}
+
+static kmem_cache_t *sk_cachep;
+
+/*
+ * All socket objects are allocated here. This is for future
+ * usage.
+ */
+
+struct sock *sk_alloc(int family, int priority, int zero_it)
+{
+ struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
+
+ if(sk) {
+ if (zero_it)
+ memset(sk, 0, sizeof(struct sock));
+ sk->family = family;
+ }
+
+ return sk;
+}
+
+void sk_free(struct sock *sk)
+{
+#ifdef CONFIG_FILTER
+ struct sk_filter *filter;
+#endif
+ if (sk->destruct)
+ sk->destruct(sk);
+
+#ifdef CONFIG_FILTER
+ filter = sk->filter;
+ if (filter) {
+ sk_filter_release(sk, filter);
+ sk->filter = NULL;
+ }
+#endif
+
+ if (atomic_read(&sk->omem_alloc))
+ printk(KERN_DEBUG "sk_free: optmem leakage (%d bytes) detected.\n", atomic_read(&sk->omem_alloc));
+
+ kmem_cache_free(sk_cachep, sk);
+}
+
+void __init sk_init(void)
+{
+ sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
+ SLAB_HWCACHE_ALIGN, 0, 0);
+
+}
+
+/*
+ * Simple resource managers for sockets.
+ */
+
+
+/*
+ * Write buffer destructor automatically called from kfree_skb.
+ */
+void sock_wfree(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ /* In case it might be waiting for more memory. */
+ atomic_sub(skb->truesize, &sk->wmem_alloc);
+ sk->write_space(sk);
+}
+
+/*
+ * Read buffer destructor automatically called from kfree_skb.
+ */
+void sock_rfree(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ atomic_sub(skb->truesize, &sk->rmem_alloc);
+}
+
+
+/*
+ * Allocate a skb from the socket's send buffer.
+ */
+struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
+{
+ if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
+ struct sk_buff * skb = alloc_skb(size, priority);
+ if (skb) {
+ atomic_add(skb->truesize, &sk->wmem_alloc);
+ skb->destructor = sock_wfree;
+ skb->sk = sk;
+ return skb;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Allocate a skb from the socket's receive buffer.
+ */
+struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
+{
+ if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) {
+ struct sk_buff *skb = alloc_skb(size, priority);
+ if (skb) {
+ atomic_add(skb->truesize, &sk->rmem_alloc);
+ skb->destructor = sock_rfree;
+ skb->sk = sk;
+ return skb;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Allocate a memory block from the socket's option memory buffer.
+ */
+void *sock_kmalloc(struct sock *sk, int size, int priority)
+{
+ if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {
+ void *mem;
+ /* First do the add, to avoid the race if kmalloc
+ * might sleep.
+ */
+ atomic_add(size, &sk->omem_alloc);
+ mem = kmalloc(size, priority);
+ if (mem)
+ return mem;
+ atomic_sub(size, &sk->omem_alloc);
+ }
+ return NULL;
+}
+
+/*
+ * Free an option memory block.
+ */
+void sock_kfree_s(struct sock *sk, void *mem, int size)
+{
+ kfree_s(mem, size);
+ atomic_sub(size, &sk->omem_alloc);
+}
+
+/* FIXME: this is insane. We are trying suppose to be controlling how
+ * how much space we have for data bytes, not packet headers.
+ * This really points out that we need a better system for doing the
+ * receive buffer. -- erics
+ * WARNING: This is currently ONLY used in tcp. If you need it else where
+ * this will probably not be what you want. Possibly these two routines
+ * should move over to the ipv4 directory.
+ */
+unsigned long sock_rspace(struct sock *sk)
+{
+ int amt = 0;
+
+ if (sk != NULL) {
+ /* This used to have some bizarre complications that
+ * to attempt to reserve some amount of space. This doesn't
+ * make sense, since the number returned here does not
+ * actually reflect allocated space, but rather the amount
+ * of space we committed to. We gamble that we won't
+ * run out of memory, and returning a smaller number does
+ * not change the gamble. If we lose the gamble tcp still
+ * works, it may just slow down for retransmissions.
+ */
+ amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc);
+ if (amt < 0)
+ amt = 0;
+ }
+ return amt;
+}
+
+
+/* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
+ I think, these locks should be removed for datagram sockets.
+ */
+static void sock_wait_for_wmem(struct sock * sk)
+{
+ struct wait_queue wait = { current, NULL };
+
+ sk->socket->flags &= ~SO_NOSPACE;
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ if (signal_pending(current))
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ if (atomic_read(&sk->wmem_alloc) < sk->sndbuf)
+ break;
+ if (sk->shutdown & SEND_SHUTDOWN)
+ break;
+ if (sk->err)
+ break;
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+}
+
+
+/*
+ * Generic send/receive buffer handlers
+ */
+
+struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
+ unsigned long fallback, int noblock, int *errcode)
+{
+ int err;
+ struct sk_buff *skb;
+
+ while (1) {
+ unsigned long try_size = size;
+
+ err = sock_error(sk);
+ if (err != 0)
+ goto failure;
+
+ /*
+ * We should send SIGPIPE in these cases according to
+ * 1003.1g draft 6.4. If we (the user) did a shutdown()
+ * call however we should not.
+ *
+ * Note: This routine isn't just used for datagrams and
+ * anyway some datagram protocols have a notion of
+ * close down.
+ */
+
+ err = -EPIPE;
+ if (sk->shutdown&SEND_SHUTDOWN)
+ goto failure;
+
+ if (fallback) {
+ /* The buffer get won't block, or use the atomic queue.
+ * It does produce annoying no free page messages still.
+ */
+ skb = sock_wmalloc(sk, size, 0, GFP_BUFFER);
+ if (skb)
+ break;
+ try_size = fallback;
+ }
+ skb = sock_wmalloc(sk, try_size, 0, sk->allocation);
+ if (skb)
+ break;
+
+ /*
+ * This means we have too many buffers for this socket already.
+ */
+
+ sk->socket->flags |= SO_NOSPACE;
+ err = -EAGAIN;
+ if (noblock)
+ goto failure;
+ err = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto failure;
+ sock_wait_for_wmem(sk);
+ }
+
+ return skb;
+
+failure:
+ *errcode = err;
+ return NULL;
+}
+
+
+void __release_sock(struct sock *sk)
+{
+#ifdef CONFIG_INET
+ if (!sk->prot || !sk->backlog_rcv)
+ return;
+
+ /* See if we have any packets built up. */
+ start_bh_atomic();
+ while (!skb_queue_empty(&sk->back_log)) {
+ struct sk_buff * skb = sk->back_log.next;
+ __skb_unlink(skb, &sk->back_log);
+ sk->backlog_rcv(sk, skb);
+ }
+ end_bh_atomic();
+#endif
+}
+
+
+/*
+ * Generic socket manager library. Most simpler socket families
+ * use this to manage their socket lists. At some point we should
+ * hash these. By making this generic we get the lot hashed for free.
+ */
+
+void sklist_remove_socket(struct sock **list, struct sock *sk)
+{
+ struct sock *s;
+
+ start_bh_atomic();
+
+ s= *list;
+ if(s==sk)
+ {
+ *list = s->next;
+ end_bh_atomic();
+ return;
+ }
+ while(s && s->next)
+ {
+ if(s->next==sk)
+ {
+ s->next=sk->next;
+ break;
+ }
+ s=s->next;
+ }
+ end_bh_atomic();
+}
+
+void sklist_insert_socket(struct sock **list, struct sock *sk)
+{
+ start_bh_atomic();
+ sk->next= *list;
+ *list=sk;
+ end_bh_atomic();
+}
+
+/*
+ * This is only called from user mode. Thus it protects itself against
+ * interrupt users but doesn't worry about being called during work.
+ * Once it is removed from the queue no interrupt or bottom half will
+ * touch it and we are (fairly 8-) ) safe.
+ */
+
+void sklist_destroy_socket(struct sock **list, struct sock *sk);
+
+/*
+ * Handler for deferred kills.
+ */
+
+static void sklist_destroy_timer(unsigned long data)
+{
+ struct sock *sk=(struct sock *)data;
+ sklist_destroy_socket(NULL,sk);
+}
+
+/*
+ * Destroy a socket. We pass NULL for a list if we know the
+ * socket is not on a list.
+ */
+
+void sklist_destroy_socket(struct sock **list,struct sock *sk)
+{
+ struct sk_buff *skb;
+ if(list)
+ sklist_remove_socket(list, sk);
+
+ while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+ {
+ kfree_skb(skb);
+ }
+
+ if(atomic_read(&sk->wmem_alloc) == 0 &&
+ atomic_read(&sk->rmem_alloc) == 0 &&
+ sk->dead)
+ {
+ sk_free(sk);
+ }
+ else
+ {
+ /*
+ * Someone is using our buffers still.. defer
+ */
+ init_timer(&sk->timer);
+ sk->timer.expires=jiffies+SOCK_DESTROY_TIME;
+ sk->timer.function=sklist_destroy_timer;
+ sk->timer.data = (unsigned long)sk;
+ add_timer(&sk->timer);
+ }
+}
+
+/*
+ * Set of default routines for initialising struct proto_ops when
+ * the protocol does not support a particular function. In certain
+ * cases where it makes no sense for a protocol to have a "do nothing"
+ * function, some default processing is provided.
+ */
+
+int sock_no_dup(struct socket *newsock, struct socket *oldsock)
+{
+ struct sock *sk = oldsock->sk;
+
+ return net_families[sk->family]->create(newsock, sk->protocol);
+}
+
+int sock_no_release(struct socket *sock, struct socket *peersock)
+{
+ return 0;
+}
+
+int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_connect(struct socket *sock, struct sockaddr *saddr,
+ int len, int flags)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_socketpair(struct socket *sock1, struct socket *sock2)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_getname(struct socket *sock, struct sockaddr *saddr,
+ int *len, int peer)
+{
+ return -EOPNOTSUPP;
+}
+
+unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt)
+{
+ return 0;
+}
+
+int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_listen(struct socket *sock, int backlog)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_shutdown(struct socket *sock, int how)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_setsockopt(struct socket *sock, int level, int optname,
+ char *optval, int optlen)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_getsockopt(struct socket *sock, int level, int optname,
+ char *optval, int *optlen)
+{
+ return -EOPNOTSUPP;
+}
+
+/*
+ * Note: if you add something that sleeps here then change sock_fcntl()
+ * to do proper fd locking.
+ */
+int sock_no_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct sock *sk = sock->sk;
+
+ switch(cmd)
+ {
+ case F_SETOWN:
+ /*
+ * This is a little restrictive, but it's the only
+ * way to make sure that you can't send a sigurg to
+ * another process.
+ */
+ if (current->pgrp != -arg &&
+ current->pid != arg &&
+ !capable(CAP_KILL)) return(-EPERM);
+ sk->proc = arg;
+ return(0);
+ case F_GETOWN:
+ return(sk->proc);
+ default:
+ return(-EINVAL);
+ }
+}
+
+int sock_no_sendmsg(struct socket *sock, struct msghdr *m, int flags,
+ struct scm_cookie *scm)
+{
+ return -EOPNOTSUPP;
+}
+
+int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int flags,
+ struct scm_cookie *scm)
+{
+ return -EOPNOTSUPP;
+}
+
+
+
+/*
+ * Default Socket Callbacks
+ */
+
+void sock_def_wakeup(struct sock *sk)
+{
+ if(!sk->dead)
+ wake_up_interruptible(sk->sleep);
+}
+
+void sock_def_error_report(struct sock *sk)
+{
+ if (!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket,0);
+ }
+}
+
+void sock_def_readable(struct sock *sk, int len)
+{
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket,1);
+ }
+}
+
+void sock_def_write_space(struct sock *sk)
+{
+ /* Do not wake up a writer until he can make "significant"
+ * progress. --DaveM
+ */
+ if(!sk->dead &&
+ ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) {
+ wake_up_interruptible(sk->sleep);
+
+ /* Should agree with poll, otherwise some programs break */
+ if (sock_writeable(sk))
+ sock_wake_async(sk->socket, 2);
+ }
+}
+
+void sock_def_destruct(struct sock *sk)
+{
+ if (sk->protinfo.destruct_hook)
+ kfree(sk->protinfo.destruct_hook);
+}
+
+void sock_init_data(struct socket *sock, struct sock *sk)
+{
+ skb_queue_head_init(&sk->receive_queue);
+ skb_queue_head_init(&sk->write_queue);
+ skb_queue_head_init(&sk->back_log);
+ skb_queue_head_init(&sk->error_queue);
+
+ init_timer(&sk->timer);
+
+ sk->allocation = GFP_KERNEL;
+ sk->rcvbuf = sysctl_rmem_default;
+ sk->sndbuf = sysctl_wmem_default;
+ sk->state = TCP_CLOSE;
+ sk->zapped = 1;
+ sk->socket = sock;
+
+ if(sock)
+ {
+ sk->type = sock->type;
+ sk->sleep = &sock->wait;
+ sock->sk = sk;
+ }
+
+ sk->state_change = sock_def_wakeup;
+ sk->data_ready = sock_def_readable;
+ sk->write_space = sock_def_write_space;
+ sk->error_report = sock_def_error_report;
+ sk->destruct = sock_def_destruct;
+
+ sk->peercred.pid = 0;
+ sk->peercred.uid = -1;
+ sk->peercred.gid = -1;
+
+}
diff --git a/pfinet/linux-src/net/core/sysctl_net_core.c b/pfinet/linux-src/net/core/sysctl_net_core.c
new file mode 100644
index 00000000..446ca145
--- /dev/null
+++ b/pfinet/linux-src/net/core/sysctl_net_core.c
@@ -0,0 +1,61 @@
+/* -*- linux-c -*-
+ * sysctl_net_core.c: sysctl interface to net core subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/core directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_SYSCTL
+
+extern int netdev_max_backlog;
+extern int netdev_fastroute;
+extern int net_msg_cost;
+extern int net_msg_burst;
+
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
+extern __u32 sysctl_wmem_default;
+extern __u32 sysctl_rmem_default;
+
+extern int sysctl_core_destroy_delay;
+extern int sysctl_optmem_max;
+
+ctl_table core_table[] = {
+#ifdef CONFIG_NET
+ {NET_CORE_WMEM_MAX, "wmem_max",
+ &sysctl_wmem_max, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_CORE_RMEM_MAX, "rmem_max",
+ &sysctl_rmem_max, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_CORE_WMEM_DEFAULT, "wmem_default",
+ &sysctl_wmem_default, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_CORE_RMEM_DEFAULT, "rmem_default",
+ &sysctl_rmem_default, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_CORE_MAX_BACKLOG, "netdev_max_backlog",
+ &netdev_max_backlog, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+#ifdef CONFIG_NET_FASTROUTE
+ {NET_CORE_FASTROUTE, "netdev_fastroute",
+ &netdev_fastroute, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+#endif
+ {NET_CORE_MSG_COST, "message_cost",
+ &net_msg_cost, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_CORE_MSG_BURST, "message_burst",
+ &net_msg_burst, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_CORE_OPTMEM_MAX, "optmem_max",
+ &sysctl_optmem_max, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+#endif /* CONFIG_NET */
+ { 0 }
+};
+#endif
diff --git a/pfinet/linux-src/net/core/utils.c b/pfinet/linux-src/net/core/utils.c
new file mode 100644
index 00000000..415926b8
--- /dev/null
+++ b/pfinet/linux-src/net/core/utils.c
@@ -0,0 +1,66 @@
+/*
+ * Generic address resultion entity
+ *
+ * Authors:
+ * net_random Alan Cox
+ * net_ratelimit Andy Kleen
+ *
+ * Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+
+static unsigned long net_rand_seed = 152L;
+
+unsigned long net_random(void)
+{
+ net_rand_seed=net_rand_seed*69069L+1;
+ return net_rand_seed^jiffies;
+}
+
+void net_srandom(unsigned long entropy)
+{
+ net_rand_seed ^= entropy;
+ net_random();
+}
+
+int net_msg_cost = 5*HZ;
+int net_msg_burst = 10*5*HZ;
+
+/*
+ * This enforces a rate limit: not more than one kernel message
+ * every 5secs to make a denial-of-service attack impossible.
+ *
+ * All warning printk()s should be guarded by this function.
+ */
+int net_ratelimit(void)
+{
+ static unsigned long toks = 10*5*HZ;
+ static unsigned long last_msg;
+ static int missed;
+ unsigned long now = jiffies;
+
+ toks += now - xchg(&last_msg, now);
+ if (toks > net_msg_burst)
+ toks = net_msg_burst;
+ if (toks >= net_msg_cost) {
+ toks -= net_msg_cost;
+ if (missed)
+ printk(KERN_WARNING "NET: %d messages suppressed.\n", missed);
+ missed = 0;
+ return 1;
+ }
+ missed++;
+ return 0;
+}
diff --git a/pfinet/linux-src/net/ethernet/Makefile b/pfinet/linux-src/net/ethernet/Makefile
new file mode 100644
index 00000000..193d6af8
--- /dev/null
+++ b/pfinet/linux-src/net/ethernet/Makefile
@@ -0,0 +1,33 @@
+#
+# Makefile for the Linux Ethernet layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := ethernet.o
+
+OBJS := eth.o
+
+ifeq ($(CONFIG_SYSCTL),y)
+OBJS += sysctl_net_ether.o
+endif
+
+ifdef CONFIG_IPX
+OBJ2 := pe2.o
+endif
+
+ifdef CONFIG_ATALK
+OBJ2 := pe2.o
+endif
+
+ifdef CONFIG_NET
+O_OBJS := $(OBJS) $(OBJ2)
+endif
+
+include $(TOPDIR)/Rules.make
+
+tar:
+ tar -cvf /dev/f1 .
diff --git a/pfinet/linux-inet/eth.c b/pfinet/linux-src/net/ethernet/eth.c
index cbd2c94b..945f4a06 100644
--- a/pfinet/linux-inet/eth.c
+++ b/pfinet/linux-src/net/ethernet/eth.c
@@ -24,15 +24,18 @@
* and changes for new arp and skbuff.
* Alan Cox : Redid header building to reflect new format.
* Alan Cox : ARP only when compiled with CONFIG_INET
- * Greg Page : 802.2 and SNAP stuff
+ * Greg Page : 802.2 and SNAP stuff.
+ * Alan Cox : MAC layer pointers/new format.
+ * Paul Gortmaker : eth_copy_and_sum shouldn't csum padding.
+ * Alan Cox : Protect against forwarding explosions with
+ * older network drivers and IFF_ALLMULTI.
+ * Christer Weinigel : Better rebuild header message.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/segment.h>
-#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -41,15 +44,24 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
+#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/config.h>
+#include <linux/init.h>
+#include <net/dst.h>
+#include <net/arp.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/ip.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/checksum.h>
-#include "arp.h"
-void eth_setup(char *str, int *ints)
+__initfunc(void eth_setup(char *str, int *ints))
{
struct device *d = dev_base;
@@ -81,11 +93,10 @@ void eth_setup(char *str, int *ints)
* daddr=NULL means leave destination address (eg unresolved arp)
*/
-int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len,
- struct sk_buff *skb)
+int eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+ void *daddr, void *saddr, unsigned len)
{
- struct ethhdr *eth = (struct ethhdr *)buff;
+ struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);
/*
* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
@@ -110,7 +121,7 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
* Anyway, the loopback-device should never use this function...
*/
- if (dev->flags & IFF_LOOPBACK)
+ if (dev->flags & (IFF_LOOPBACK|IFF_NOARP))
{
memset(eth->h_dest, 0, dev->addr_len);
return(dev->hard_header_len);
@@ -130,32 +141,32 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
* Rebuild the Ethernet MAC header. This is called after an ARP
* (or in future other address resolution) has completed on this
* sk_buff. We now let ARP fill in the other fields.
+ *
+ * This routine CANNOT use cached dst->neigh!
+ * Really, it is used only when dst->neigh is wrong.
*/
-
-int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst,
- struct sk_buff *skb)
+
+int eth_rebuild_header(struct sk_buff *skb)
{
- struct ethhdr *eth = (struct ethhdr *)buff;
+ struct ethhdr *eth = (struct ethhdr *)skb->data;
+ struct device *dev = skb->dev;
- /*
- * Only ARP/IP is currently supported
- */
-
- if(eth->h_proto != htons(ETH_P_IP))
+ switch (eth->h_proto)
{
- printk("eth_rebuild_header: Don't know how to resolve type %d addresses?\n",(int)eth->h_proto);
+#ifdef CONFIG_INET
+ case __constant_htons(ETH_P_IP):
+ return arp_find(eth->h_dest, skb);
+#endif
+ default:
+ printk(KERN_DEBUG
+ "%s: unable to resolve type %X addresses.\n",
+ dev->name, (int)eth->h_proto);
+
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return 0;
+ break;
}
- /*
- * Try and get ARP to resolve the header.
- */
-#ifdef CONFIG_INET
- return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;
-#else
- return 0;
-#endif
+ return 0;
}
@@ -167,9 +178,13 @@ int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst,
unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
{
- struct ethhdr *eth = (struct ethhdr *) skb->data;
+ struct ethhdr *eth;
unsigned char *rawp;
+ skb->mac.raw=skb->data;
+ skb_pull(skb,dev->hard_header_len);
+ eth= skb->mac.ethernet;
+
if(*eth->h_dest&1)
{
if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
@@ -178,7 +193,15 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
skb->pkt_type=PACKET_MULTICAST;
}
- if(dev->flags&IFF_PROMISC)
+ /*
+ * This ALLMULTI check should be redundant by 1.4
+ * so don't forget to remove it.
+ *
+ * Seems, you forgot to remove it. All silly devices
+ * seems to set IFF_PROMISC.
+ */
+
+ else if(1 /*dev->flags&IFF_PROMISC*/)
{
if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
skb->pkt_type=PACKET_OTHERHOST;
@@ -187,10 +210,89 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
- rawp = (unsigned char *)(eth + 1);
+ rawp = skb->data;
+ /*
+ * This is a magic hack to spot IPX packets. Older Novell breaks
+ * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+ * won't work for fault tolerant netware but does for the rest.
+ */
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
+ /*
+ * Real 802.2 LLC
+ */
return htons(ETH_P_802_2);
}
+
+int eth_header_parse(struct sk_buff *skb, unsigned char *haddr)
+{
+ struct ethhdr *eth = skb->mac.ethernet;
+ memcpy(haddr, eth->h_source, ETH_ALEN);
+ return ETH_ALEN;
+}
+
+int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+ unsigned short type = hh->hh_type;
+ struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2);
+ struct device *dev = neigh->dev;
+
+ if (type == __constant_htons(ETH_P_802_3))
+ return -1;
+
+ eth->h_proto = type;
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ memcpy(eth->h_dest, neigh->ha, dev->addr_len);
+ return 0;
+}
+
+/*
+ * Called by Address Resolution module to notify changes in address.
+ */
+
+void eth_header_cache_update(struct hh_cache *hh, struct device *dev, unsigned char * haddr)
+{
+ memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
+}
+
+#ifndef CONFIG_IP_ROUTER
+
+/*
+ * Copy from an ethernet device memory space to an sk_buff while checksumming if IP
+ */
+
+void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base)
+{
+ struct ethhdr *eth;
+ struct iphdr *iph;
+ int ip_length;
+
+ eth=(struct ethhdr *)src;
+ if(eth->h_proto!=htons(ETH_P_IP))
+ {
+ memcpy(dest->data,src,length);
+ return;
+ }
+ /*
+ * We have to watch for padded packets. The csum doesn't include the
+ * padding, and there is no point in copying the padding anyway.
+ * We have to use the smaller of length and ip_length because it
+ * can happen that ip_length > length.
+ */
+ memcpy(dest->data,src,sizeof(struct iphdr)+ETH_HLEN); /* ethernet is always >= 34 */
+ length -= sizeof(struct iphdr) + ETH_HLEN;
+ iph=(struct iphdr*)(src+ETH_HLEN);
+ ip_length = ntohs(iph->tot_len) - sizeof(struct iphdr);
+
+ /* Also watch out for bogons - min IP size is 8 (rfc-1042) */
+ if ((ip_length <= length) && (ip_length > 7))
+ length=ip_length;
+
+ dest->csum=csum_partial_copy(src+sizeof(struct iphdr)+ETH_HLEN,dest->data+sizeof(struct iphdr)+ETH_HLEN,length,base);
+ dest->ip_summed=1;
+}
+
+#endif /* !(CONFIG_IP_ROUTER) */
diff --git a/pfinet/linux-inet/pe2.c b/pfinet/linux-src/net/ethernet/pe2.c
index 856e454b..4915f070 100644
--- a/pfinet/linux-inet/pe2.c
+++ b/pfinet/linux-src/net/ethernet/pe2.c
@@ -1,6 +1,6 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
-#include "datalink.h"
+#include <net/datalink.h>
#include <linux/mm.h>
#include <linux/in.h>
@@ -9,12 +9,10 @@ pEII_datalink_header(struct datalink_proto *dl,
struct sk_buff *skb, unsigned char *dest_node)
{
struct device *dev = skb->dev;
- unsigned long len = skb->len;
- unsigned long hard_len = dev->hard_header_len;
- dev->hard_header(skb->data, dev, ETH_P_IPX,
- dest_node, NULL, len - hard_len, skb);
- skb->h.raw = skb->data + hard_len;
+ skb->protocol = htons (ETH_P_IPX);
+ if(dev->hard_header)
+ dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
}
struct datalink_proto *
@@ -33,3 +31,8 @@ make_EII_client(void)
return proto;
}
+void destroy_EII_client(struct datalink_proto *dl)
+{
+ if (dl)
+ kfree_s(dl, sizeof(struct datalink_proto));
+}
diff --git a/pfinet/linux-src/net/ethernet/sysctl_net_ether.c b/pfinet/linux-src/net/ethernet/sysctl_net_ether.c
new file mode 100644
index 00000000..b81a6d53
--- /dev/null
+++ b/pfinet/linux-src/net/ethernet/sysctl_net_ether.c
@@ -0,0 +1,13 @@
+/* -*- linux-c -*-
+ * sysctl_net_ether.c: sysctl interface to net Ethernet subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/ether directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table ether_table[] = {
+ {0}
+};
diff --git a/pfinet/linux-src/net/ipv4/Config.in b/pfinet/linux-src/net/ipv4/Config.in
new file mode 100644
index 00000000..8982bc1e
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/Config.in
@@ -0,0 +1,85 @@
+#
+# IP configuration
+#
+bool 'IP: multicasting' CONFIG_IP_MULTICAST
+bool 'IP: advanced router' CONFIG_IP_ADVANCED_ROUTER
+if [ "$CONFIG_IP_ADVANCED_ROUTER" = "y" ]; then
+ define_bool CONFIG_RTNETLINK y
+ define_bool CONFIG_NETLINK y
+ bool 'IP: policy routing' CONFIG_IP_MULTIPLE_TABLES
+ bool 'IP: equal cost multipath' CONFIG_IP_ROUTE_MULTIPATH
+ bool 'IP: use TOS value as routing key' CONFIG_IP_ROUTE_TOS
+ bool 'IP: verbose route monitoring' CONFIG_IP_ROUTE_VERBOSE
+ bool 'IP: large routing tables' CONFIG_IP_ROUTE_LARGE_TABLES
+ if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then
+ bool 'IP: fast network address translation' CONFIG_IP_ROUTE_NAT
+ fi
+fi
+bool 'IP: kernel level autoconfiguration' CONFIG_IP_PNP
+if [ "$CONFIG_IP_PNP" = "y" ]; then
+ bool ' BOOTP support' CONFIG_IP_PNP_BOOTP
+ bool ' RARP support' CONFIG_IP_PNP_RARP
+# not yet ready..
+# bool ' ARP support' CONFIG_IP_PNP_ARP
+fi
+if [ "$CONFIG_FIREWALL" = "y" ]; then
+ bool 'IP: firewalling' CONFIG_IP_FIREWALL
+ if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
+ if [ "$CONFIG_NETLINK" = "y" ]; then
+ bool 'IP: firewall packet netlink device' CONFIG_IP_FIREWALL_NETLINK
+ if [ "$CONFIG_IP_FIREWALL_NETLINK" = "y" ]; then
+ define_bool CONFIG_NETLINK_DEV y
+ fi
+ fi
+ if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then
+ bool 'IP: use FWMARK value as routing key' CONFIG_IP_ROUTE_FWMARK
+ fi
+ fi
+fi
+if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
+ bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY
+ bool 'IP: masquerading' CONFIG_IP_MASQUERADE
+ if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
+ comment 'Protocol-specific masquerading support will be built as modules.'
+ bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
+ comment 'Protocol-specific masquerading support will be built as modules.'
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'IP: masquerading special modules support' CONFIG_IP_MASQUERADE_MOD
+ if [ "$CONFIG_IP_MASQUERADE_MOD" = "y" ]; then
+ tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
+ tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW
+ tristate 'IP: ip fwmark masq-forwarding support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_MFW
+ fi
+ fi
+ fi
+fi
+bool 'IP: optimize as router not host' CONFIG_IP_ROUTER
+tristate 'IP: tunneling' CONFIG_NET_IPIP
+tristate 'IP: GRE tunnels over IP' CONFIG_NET_IPGRE
+if [ "$CONFIG_IP_MULTICAST" = "y" ]; then
+ if [ "$CONFIG_NET_IPGRE" != "n" ]; then
+ bool 'IP: broadcast GRE over IP' CONFIG_NET_IPGRE_BROADCAST
+ fi
+ bool 'IP: multicast routing' CONFIG_IP_MROUTE
+ if [ "$CONFIG_IP_MROUTE" = "y" ]; then
+ bool 'IP: PIM-SM version 1 support' CONFIG_IP_PIMSM_V1
+ bool 'IP: PIM-SM version 2 support' CONFIG_IP_PIMSM_V2
+ fi
+fi
+bool 'IP: aliasing support' CONFIG_IP_ALIAS
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_RTNETLINK" = "y" ]; then
+ bool 'IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
+ fi
+fi
+bool 'IP: TCP syncookie support (not enabled per default)' CONFIG_SYN_COOKIES
+comment '(it is safe to leave these untouched)'
+#bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
+tristate 'IP: Reverse ARP' CONFIG_INET_RARP
+#bool 'IP: Path MTU Discovery (normally enabled)' CONFIG_PATH_MTU_DISCOVERY
+#bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF
+bool 'IP: Allow large windows (not recommended if <16Mb of memory)' CONFIG_SKB_LARGE
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#bool 'IP: support experimental checksum copy to user for UDP' CONFIG_UDP_DELAY_CSUM
+#fi
+
diff --git a/pfinet/linux-src/net/ipv4/Makefile b/pfinet/linux-src/net/ipv4/Makefile
new file mode 100644
index 00000000..8ab280de
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/Makefile
@@ -0,0 +1,116 @@
+#
+# Makefile for the Linux TCP/IP (INET) layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := ipv4.o
+IPV4_OBJS := utils.o route.o proc.o timer.o protocol.o \
+ ip_input.o ip_fragment.o ip_forward.o ip_options.o \
+ ip_output.o ip_sockglue.o \
+ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o\
+ raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
+ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o
+IPV4X_OBJS :=
+
+MOD_LIST_NAME := IPV4_MODULES
+M_OBJS :=
+
+ifeq ($(CONFIG_IP_FIREWALL),y)
+IPV4_OBJS += ip_fw.o
+endif
+
+ifeq ($(CONFIG_IP_MULTIPLE_TABLES),y)
+IPV4_OBJS += fib_rules.o
+endif
+
+ifeq ($(CONFIG_IP_ROUTE_NAT),y)
+IPV4_OBJS += ip_nat_dumb.o
+endif
+
+ifeq ($(CONFIG_IP_MROUTE),y)
+IPV4_OBJS += ipmr.o
+endif
+
+ifeq ($(CONFIG_INET_RARP),y)
+IPV4_OBJS += rarp.o
+else
+ ifeq ($(CONFIG_INET_RARP),m)
+ M_OBJS += rarp.o
+ endif
+endif
+
+ifeq ($(CONFIG_NET_IPIP),y)
+IPV4X_OBJS += ipip.o
+else
+ ifeq ($(CONFIG_NET_IPIP),m)
+ MX_OBJS += ipip.o
+ endif
+endif
+
+ifeq ($(CONFIG_NET_IPGRE),y)
+IPV4X_OBJS += ip_gre.o
+else
+ ifeq ($(CONFIG_NET_IPGRE),m)
+ MX_OBJS += ip_gre.o
+ endif
+endif
+
+ifeq ($(CONFIG_IP_MASQUERADE),y)
+IPV4X_OBJS += ip_masq.o ip_masq_app.o
+
+ifeq ($(CONFIG_IP_MASQUERADE_MOD),y)
+ IPV4X_OBJS += ip_masq_mod.o
+
+ ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),y)
+ IPV4_OBJS += ip_masq_autofw.o
+ else
+ ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),m)
+ M_OBJS += ip_masq_autofw.o
+ endif
+ endif
+
+ ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),y)
+ IPV4_OBJS += ip_masq_portfw.o
+ else
+ ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),m)
+ M_OBJS += ip_masq_portfw.o
+ endif
+ endif
+
+ ifeq ($(CONFIG_IP_MASQUERADE_MFW),y)
+ IPV4_OBJS += ip_masq_mfw.o
+ else
+ ifeq ($(CONFIG_IP_MASQUERADE_MFW),m)
+ M_OBJS += ip_masq_mfw.o
+ endif
+ endif
+
+endif
+
+M_OBJS += ip_masq_user.o
+M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o
+M_OBJS += ip_masq_vdolive.o ip_masq_cuseeme.o
+endif
+
+ifeq ($(CONFIG_SYN_COOKIES),y)
+IPV4_OBJS += syncookies.o
+# module not supported, because it would be too messy.
+endif
+
+ifeq ($(CONFIG_IP_PNP),y)
+IPV4_OBJS += ipconfig.o
+endif
+
+ifdef CONFIG_INET
+O_OBJS := $(IPV4_OBJS)
+OX_OBJS := $(IPV4X_OBJS)
+endif
+
+include $(TOPDIR)/Rules.make
+
+tar:
+ tar -cvf /dev/f1 .
diff --git a/pfinet/linux-src/net/ipv4/af_inet.c b/pfinet/linux-src/net/ipv4/af_inet.c
new file mode 100644
index 00000000..04e05107
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/af_inet.c
@@ -0,0 +1,1167 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * PF_INET protocol family socket handler.
+ *
+ * Version: $Id: af_inet.c,v 1.87.2.5 1999/08/08 08:43:10 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ * Alan Cox, <A.Cox@swansea.ac.uk>
+ *
+ * Changes (see also sock.c)
+ *
+ * A.N.Kuznetsov : Socket death error in accept().
+ * John Richardson : Fix non blocking error in connect()
+ * so sockets that fail to connect
+ * don't return -EINPROGRESS.
+ * Alan Cox : Asynchronous I/O support
+ * Alan Cox : Keep correct socket pointer on sock structures
+ * when accept() ed
+ * Alan Cox : Semantics of SO_LINGER aren't state moved
+ * to close when you look carefully. With
+ * this fixed and the accept bug fixed
+ * some RPC stuff seems happier.
+ * Niibe Yutaka : 4.4BSD style write async I/O
+ * Alan Cox,
+ * Tony Gale : Fixed reuse semantics.
+ * Alan Cox : bind() shouldn't abort existing but dead
+ * sockets. Stops FTP netin:.. I hope.
+ * Alan Cox : bind() works correctly for RAW sockets. Note
+ * that FreeBSD at least was broken in this respect
+ * so be careful with compatibility tests...
+ * Alan Cox : routing cache support
+ * Alan Cox : memzero the socket structure for compactness.
+ * Matt Day : nonblock connect error handler
+ * Alan Cox : Allow large numbers of pending sockets
+ * (eg for big web sites), but only if
+ * specifically application requested.
+ * Alan Cox : New buffering throughout IP. Used dumbly.
+ * Alan Cox : New buffering now used smartly.
+ * Alan Cox : BSD rather than common sense interpretation of
+ * listen.
+ * Germano Caronni : Assorted small races.
+ * Alan Cox : sendmsg/recvmsg basic support.
+ * Alan Cox : Only sendmsg/recvmsg now supported.
+ * Alan Cox : Locked down bind (see security list).
+ * Alan Cox : Loosened bind a little.
+ * Mike McLagan : ADD/DEL DLCI Ioctls
+ * Willy Konynenberg : Transparent proxying support.
+ * David S. Miller : New socket lookup architecture.
+ * Some other random speedups.
+ * Cyrus Durgin : Cleaned up file for kmod hacks.
+ * Andi Kleen : Fix inet_stream_connect TCP race.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/arp.h>
+#include <net/rarp.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/raw.h>
+#include <net/icmp.h>
+#include <net/ipip.h>
+#include <net/inet_common.h>
+#include <linux/ip_fw.h>
+#ifdef CONFIG_IP_MROUTE
+#include <linux/mroute.h>
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
+#ifdef CONFIG_BRIDGE
+#include <net/br.h>
+#endif
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+#ifdef CONFIG_NET_RADIO
+#include <linux/wireless.h>
+#endif /* CONFIG_NET_RADIO */
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+struct linux_mib net_statistics;
+
+extern int raw_get_info(char *, char **, off_t, int, int);
+extern int snmp_get_info(char *, char **, off_t, int, int);
+extern int netstat_get_info(char *, char **, off_t, int, int);
+extern int afinet_get_info(char *, char **, off_t, int, int);
+extern int tcp_get_info(char *, char **, off_t, int, int);
+extern int udp_get_info(char *, char **, off_t, int, int);
+extern void ip_mc_drop_socket(struct sock *sk);
+
+#ifdef CONFIG_DLCI
+extern int dlci_ioctl(unsigned int, void*);
+#endif
+
+#ifdef CONFIG_DLCI_MODULE
+int (*dlci_ioctl_hook)(unsigned int, void *) = NULL;
+#endif
+
+int (*rarp_ioctl_hook)(unsigned int,void*) = NULL;
+
+/*
+ * Destroy an AF_INET socket
+ */
+
+static __inline__ void kill_sk_queues(struct sock *sk)
+{
+ struct sk_buff *skb;
+
+ /* First the read buffer. */
+ while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
+ kfree_skb(skb);
+
+ /* Next, the error queue. */
+ while((skb = skb_dequeue(&sk->error_queue)) != NULL)
+ kfree_skb(skb);
+
+ /* Now the backlog. */
+ while((skb=skb_dequeue(&sk->back_log)) != NULL)
+ kfree_skb(skb);
+}
+
+static __inline__ void kill_sk_now(struct sock *sk)
+{
+ /* No longer exists. */
+ del_from_prot_sklist(sk);
+
+ /* Remove from protocol hash chains. */
+ sk->prot->unhash(sk);
+
+ if(sk->opt)
+ kfree(sk->opt);
+ dst_release(sk->dst_cache);
+ sk_free(sk);
+}
+
+static __inline__ void kill_sk_later(struct sock *sk)
+{
+ /* this should never happen. */
+ /* actually it can if an ack has just been sent. */
+ /*
+ * It's more normal than that...
+ * It can happen because a skb is still in the device queues
+ * [PR]
+ */
+
+ NETDEBUG(printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n",
+ atomic_read(&sk->rmem_alloc),
+ atomic_read(&sk->wmem_alloc)));
+
+ sk->ack_backlog = 0;
+ release_sock(sk);
+ net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
+}
+
+void destroy_sock(struct sock *sk)
+{
+ lock_sock(sk); /* just to be safe. */
+
+ /* Now we can no longer get new packets or once the
+ * timers are killed, send them.
+ */
+ net_delete_timer(sk);
+
+ if (sk->prot->destroy && !sk->destroy)
+ sk->prot->destroy(sk);
+
+ sk->destroy = 1;
+
+ kill_sk_queues(sk);
+
+ /* Now if everything is gone we can free the socket
+ * structure, otherwise we need to keep it around until
+ * everything is gone.
+ */
+ if (atomic_read(&sk->rmem_alloc) == 0 && atomic_read(&sk->wmem_alloc) == 0)
+ kill_sk_now(sk);
+ else
+ kill_sk_later(sk);
+}
+
+/*
+ * The routines beyond this point handle the behaviour of an AF_INET
+ * socket object. Mostly it punts to the subprotocols of IP to do
+ * the work.
+ */
+
+
+/*
+ * Set socket options on an inet socket.
+ */
+
+int inet_setsockopt(struct socket *sock, int level, int optname,
+ char *optval, int optlen)
+{
+ struct sock *sk=sock->sk;
+ if (sk->prot->setsockopt==NULL)
+ return(-EOPNOTSUPP);
+ return sk->prot->setsockopt(sk,level,optname,optval,optlen);
+}
+
+/*
+ * Get a socket option on an AF_INET socket.
+ *
+ * FIX: POSIX 1003.1g is very ambiguous here. It states that
+ * asynchronous errors should be reported by getsockopt. We assume
+ * this means if you specify SO_ERROR (otherwise whats the point of it).
+ */
+
+int inet_getsockopt(struct socket *sock, int level, int optname,
+ char *optval, int *optlen)
+{
+ struct sock *sk=sock->sk;
+ if (sk->prot->getsockopt==NULL)
+ return(-EOPNOTSUPP);
+ return sk->prot->getsockopt(sk,level,optname,optval,optlen);
+}
+
+/*
+ * Automatically bind an unbound socket.
+ */
+
+static int inet_autobind(struct sock *sk)
+{
+ /* We may need to bind the socket. */
+ if (sk->num == 0) {
+ if (sk->prot->get_port(sk, 0) != 0)
+ return(-EAGAIN);
+ sk->sport = htons(sk->num);
+ sk->prot->hash(sk);
+ add_to_prot_sklist(sk);
+ }
+ return 0;
+}
+
+/*
+ * Move a socket into listening state.
+ */
+
+int inet_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+ unsigned char old_state;
+
+ if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
+ return(-EINVAL);
+
+ if ((unsigned) backlog == 0) /* BSDism */
+ backlog = 1;
+ if ((unsigned) backlog > SOMAXCONN)
+ backlog = SOMAXCONN;
+ sk->max_ack_backlog = backlog;
+
+ /* Really, if the socket is already in listen state
+ * we can only allow the backlog to be adjusted.
+ */
+ old_state = sk->state;
+ if (old_state != TCP_LISTEN) {
+ sk->state = TCP_LISTEN;
+ sk->ack_backlog = 0;
+ if (sk->num == 0) {
+ if (sk->prot->get_port(sk, 0) != 0) {
+ sk->state = old_state;
+ return -EAGAIN;
+ }
+ sk->sport = htons(sk->num);
+ add_to_prot_sklist(sk);
+ } else {
+ if (sk->prev)
+ ((struct tcp_bind_bucket*)sk->prev)->fastreuse = 0;
+ }
+
+ dst_release(xchg(&sk->dst_cache, NULL));
+ sk->prot->hash(sk);
+ sk->socket->flags |= SO_ACCEPTCON;
+ }
+ return 0;
+}
+
+/*
+ * Create an inet socket.
+ *
+ * FIXME: Gcc would generate much better code if we set the parameters
+ * up in in-memory structure order. Gcc68K even more so
+ */
+
+static int inet_create(struct socket *sock, int protocol)
+{
+ struct sock *sk;
+ struct proto *prot;
+
+ /* Compatibility */
+ if (sock->type == SOCK_PACKET) {
+ static int warned;
+ if (net_families[PF_PACKET]==NULL)
+ {
+#if defined(CONFIG_KMOD) && defined(CONFIG_PACKET_MODULE)
+ char module_name[30];
+ sprintf(module_name,"net-pf-%d", PF_PACKET);
+ request_module(module_name);
+ if (net_families[PF_PACKET] == NULL)
+#endif
+ return -ESOCKTNOSUPPORT;
+ }
+ if (!warned++)
+ printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);
+ return net_families[PF_PACKET]->create(sock, protocol);
+ }
+
+ sock->state = SS_UNCONNECTED;
+ sk = sk_alloc(PF_INET, GFP_KERNEL, 1);
+ if (sk == NULL)
+ goto do_oom;
+
+ switch (sock->type) {
+ case SOCK_STREAM:
+ if (protocol && protocol != IPPROTO_TCP)
+ goto free_and_noproto;
+ protocol = IPPROTO_TCP;
+ if (ipv4_config.no_pmtu_disc)
+ sk->ip_pmtudisc = IP_PMTUDISC_DONT;
+ else
+ sk->ip_pmtudisc = IP_PMTUDISC_WANT;
+ prot = &tcp_prot;
+ sock->ops = &inet_stream_ops;
+ break;
+ case SOCK_SEQPACKET:
+ goto free_and_badtype;
+ case SOCK_DGRAM:
+ if (protocol && protocol != IPPROTO_UDP)
+ goto free_and_noproto;
+ protocol = IPPROTO_UDP;
+ sk->no_check = UDP_NO_CHECK;
+ sk->ip_pmtudisc = IP_PMTUDISC_DONT;
+ prot=&udp_prot;
+ sock->ops = &inet_dgram_ops;
+ break;
+ case SOCK_RAW:
+ if (!capable(CAP_NET_RAW))
+ goto free_and_badperm;
+ if (!protocol)
+ goto free_and_noproto;
+ prot = &raw_prot;
+ sk->reuse = 1;
+ sk->ip_pmtudisc = IP_PMTUDISC_DONT;
+ sk->num = protocol;
+ sock->ops = &inet_dgram_ops;
+ if (protocol == IPPROTO_RAW)
+ sk->ip_hdrincl = 1;
+ break;
+ default:
+ goto free_and_badtype;
+ }
+
+ sock_init_data(sock,sk);
+
+ sk->destruct = NULL;
+
+ sk->zapped=0;
+#ifdef CONFIG_TCP_NAGLE_OFF
+ sk->nonagle = 1;
+#endif
+ sk->family = PF_INET;
+ sk->protocol = protocol;
+
+ sk->prot = prot;
+ sk->backlog_rcv = prot->backlog_rcv;
+
+ sk->timer.data = (unsigned long)sk;
+ sk->timer.function = &net_timer;
+
+ sk->ip_ttl=ip_statistics.IpDefaultTTL;
+
+ sk->ip_mc_loop=1;
+ sk->ip_mc_ttl=1;
+ sk->ip_mc_index=0;
+ sk->ip_mc_list=NULL;
+
+ if (sk->num) {
+ /* It assumes that any protocol which allows
+ * the user to assign a number at socket
+ * creation time automatically
+ * shares.
+ */
+ sk->sport = htons(sk->num);
+
+ /* Add to protocol hash chains. */
+ sk->prot->hash(sk);
+ add_to_prot_sklist(sk);
+ }
+
+ if (sk->prot->init) {
+ int err = sk->prot->init(sk);
+ if (err != 0) {
+ destroy_sock(sk);
+ return(err);
+ }
+ }
+ return(0);
+
+free_and_badtype:
+ sk_free(sk);
+ return -ESOCKTNOSUPPORT;
+
+free_and_badperm:
+ sk_free(sk);
+ return -EPERM;
+
+free_and_noproto:
+ sk_free(sk);
+ return -EPROTONOSUPPORT;
+
+do_oom:
+ return -ENOBUFS;
+}
+
+
+/*
+ * The peer socket should always be NULL (or else). When we call this
+ * function we are destroying the object and from then on nobody
+ * should refer to it.
+ */
+
+int inet_release(struct socket *sock, struct socket *peersock)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk) {
+ long timeout;
+
+ /* Begin closedown and wake up sleepers. */
+ if (sock->state != SS_UNCONNECTED)
+ sock->state = SS_DISCONNECTING;
+ sk->state_change(sk);
+
+ /* Applications forget to leave groups before exiting */
+ ip_mc_drop_socket(sk);
+
+ /* If linger is set, we don't return until the close
+ * is complete. Otherwise we return immediately. The
+ * actually closing is done the same either way.
+ *
+ * If the close is due to the process exiting, we never
+ * linger..
+ */
+ timeout = 0;
+ if (sk->linger && !(current->flags & PF_EXITING)) {
+ timeout = HZ * sk->lingertime;
+ if (!timeout)
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ }
+ sock->sk = NULL;
+ sk->socket = NULL;
+ sk->prot->close(sk, timeout);
+ }
+ return(0);
+}
+
+static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_in *addr=(struct sockaddr_in *)uaddr;
+ struct sock *sk=sock->sk;
+ unsigned short snum;
+ int chk_addr_ret;
+
+ /* If the socket has its own bind function then use it. (RAW) */
+ if(sk->prot->bind)
+ return sk->prot->bind(sk, uaddr, addr_len);
+
+ /* Check these errors (active socket, bad address length, double bind). */
+ if ((sk->state != TCP_CLOSE) ||
+ (addr_len < sizeof(struct sockaddr_in)) ||
+ (sk->num != 0))
+ return -EINVAL;
+
+ chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
+ if (addr->sin_addr.s_addr != 0 && chk_addr_ret != RTN_LOCAL &&
+ chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) {
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /* Superuser may bind to any address to allow transparent proxying. */
+ if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN))
+#endif
+ return -EADDRNOTAVAIL; /* Source address MUST be ours! */
+ }
+
+ /* We keep a pair of addresses. rcv_saddr is the one
+ * used by hash lookups, and saddr is used for transmit.
+ *
+ * In the BSD API these are the same except where it
+ * would be illegal to use them (multicast/broadcast) in
+ * which case the sending device address is used.
+ */
+ sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
+ if(chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
+ sk->saddr = 0; /* Use device */
+
+ snum = ntohs(addr->sin_port);
+#ifdef CONFIG_IP_MASQUERADE
+ /* The kernel masquerader needs some ports. */
+ if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END))
+ return -EADDRINUSE;
+#endif
+ if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+ return(-EACCES);
+
+ /* Make sure we are allowed to bind here. */
+ if (sk->prot->get_port(sk, snum) != 0)
+ return -EADDRINUSE;
+
+ sk->sport = htons(sk->num);
+ sk->daddr = 0;
+ sk->dport = 0;
+ sk->prot->hash(sk);
+ add_to_prot_sklist(sk);
+ dst_release(sk->dst_cache);
+ sk->dst_cache=NULL;
+ return(0);
+}
+
+int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
+ int addr_len, int flags)
+{
+ struct sock *sk=sock->sk;
+ int err;
+
+ if (inet_autobind(sk) != 0)
+ return(-EAGAIN);
+ if (sk->prot->connect == NULL)
+ return(-EOPNOTSUPP);
+ err = sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len);
+ if (err < 0)
+ return(err);
+ return(0);
+}
+
+static void inet_wait_for_connect(struct sock *sk)
+{
+ struct wait_queue wait = { current, NULL };
+
+ add_wait_queue(sk->sleep, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ while (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
+ if (signal_pending(current))
+ break;
+ if (sk->err)
+ break;
+ schedule();
+ current->state = TASK_INTERRUPTIBLE;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+}
+
+/*
+ * Connect to a remote host. There is regrettably still a little
+ * TCP 'magic' in here.
+ */
+
+int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
+ int addr_len, int flags)
+{
+ struct sock *sk=sock->sk;
+ int err;
+
+ if(sock->state != SS_UNCONNECTED && sock->state != SS_CONNECTING) {
+ if(sock->state == SS_CONNECTED)
+ return -EISCONN;
+ return -EINVAL;
+ }
+
+ if(sock->state == SS_CONNECTING) {
+ /* Note: tcp_connected contains SYN_RECV, which may cause
+ bogus results here. -AK */
+ if(tcp_connected(sk->state)) {
+ sock->state = SS_CONNECTED;
+ return 0;
+ }
+ if (sk->zapped || sk->err)
+ goto sock_error;
+ if (flags & O_NONBLOCK)
+ return -EALREADY;
+ } else {
+ if (sk->prot->connect == NULL)
+ return(-EOPNOTSUPP);
+
+ /* We may need to bind the socket. */
+ if (inet_autobind(sk) != 0)
+ return(-EAGAIN);
+
+ err = sk->prot->connect(sk, uaddr, addr_len);
+ /* Note: there is a theoretical race here when an wake up
+ occurred before inet_wait_for_connect is entered. In 2.3
+ the wait queue setup should be moved before the low level
+ connect call. -AK*/
+ if (err < 0)
+ return(err);
+ sock->state = SS_CONNECTING;
+ }
+
+ if (sk->state > TCP_FIN_WAIT2 && sock->state == SS_CONNECTING)
+ goto sock_error;
+
+ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
+ return (-EINPROGRESS);
+
+ if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
+ inet_wait_for_connect(sk);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+
+ sock->state = SS_CONNECTED;
+ if ((sk->state != TCP_ESTABLISHED) && sk->err)
+ goto sock_error;
+ return(0);
+
+sock_error:
+ /* This is ugly but needed to fix a race in the ICMP error handler */
+ if (sk->zapped && sk->state != TCP_CLOSE) {
+ lock_sock(sk);
+ tcp_set_state(sk, TCP_CLOSE);
+ release_sock(sk);
+ sk->zapped = 0;
+ }
+ sock->state = SS_UNCONNECTED;
+ return sock_error(sk);
+}
+
+/*
+ * Accept a pending connection. The TCP layer now gives BSD semantics.
+ */
+
+int inet_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ struct sock *sk1 = sock->sk, *sk2;
+ struct sock *newsk = newsock->sk;
+ int err = -EINVAL;
+
+ if (sock->state != SS_UNCONNECTED || !(sock->flags & SO_ACCEPTCON))
+ goto do_err;
+
+ err = -EOPNOTSUPP;
+ if (sk1->prot->accept == NULL)
+ goto do_err;
+
+ if((sk2 = sk1->prot->accept(sk1,flags)) == NULL)
+ goto do_sk1_err;
+
+ /*
+ * We've been passed an extra socket.
+ * We need to free it up because the tcp module creates
+ * its own when it accepts one.
+ */
+ sk2->sleep = newsk->sleep;
+
+ newsock->sk = sk2;
+ sk2->socket = newsock;
+ newsk->socket = NULL;
+
+ if (flags & O_NONBLOCK)
+ goto do_half_success;
+
+ if(sk2->state == TCP_ESTABLISHED)
+ goto do_full_success;
+ if(sk2->err > 0)
+ goto do_connect_err;
+ err = -ECONNABORTED;
+ if (sk2->state == TCP_CLOSE)
+ goto do_bad_connection;
+do_full_success:
+ destroy_sock(newsk);
+ newsock->state = SS_CONNECTED;
+ return 0;
+
+do_half_success:
+ destroy_sock(newsk);
+ return(0);
+
+do_connect_err:
+ err = sock_error(sk2);
+do_bad_connection:
+ sk2->sleep = NULL;
+ sk2->socket = NULL;
+ destroy_sock(sk2);
+ newsock->sk = newsk;
+ newsk->socket = newsock;
+ return err;
+
+do_sk1_err:
+ err = sock_error(sk1);
+do_err:
+ return err;
+}
+
+
+/*
+ * This does both peername and sockname.
+ */
+
+static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
+ int *uaddr_len, int peer)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
+
+ sin->sin_family = AF_INET;
+ if (peer) {
+ if (!tcp_connected(sk->state))
+ return(-ENOTCONN);
+ sin->sin_port = sk->dport;
+ sin->sin_addr.s_addr = sk->daddr;
+ } else {
+ __u32 addr = sk->rcv_saddr;
+ if (!addr)
+ addr = sk->saddr;
+ sin->sin_port = sk->sport;
+ sin->sin_addr.s_addr = addr;
+ }
+ *uaddr_len = sizeof(*sin);
+ return(0);
+}
+
+
+
+int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+ int flags, struct scm_cookie *scm)
+{
+ struct sock *sk = sock->sk;
+ int addr_len = 0;
+ int err;
+
+ if (sock->flags & SO_ACCEPTCON)
+ return(-EINVAL);
+ if (sk->prot->recvmsg == NULL)
+ return(-EOPNOTSUPP);
+ /* We may need to bind the socket. */
+ if (inet_autobind(sk) != 0)
+ return(-EAGAIN);
+ err = sk->prot->recvmsg(sk, msg, size, flags&MSG_DONTWAIT,
+ flags&~MSG_DONTWAIT, &addr_len);
+ if (err >= 0)
+ msg->msg_namelen = addr_len;
+ return err;
+}
+
+
+int inet_sendmsg(struct socket *sock, struct msghdr *msg, int size,
+ struct scm_cookie *scm)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk->shutdown & SEND_SHUTDOWN) {
+ if (!(msg->msg_flags&MSG_NOSIGNAL))
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ if (sk->prot->sendmsg == NULL)
+ return(-EOPNOTSUPP);
+ if(sk->err)
+ return sock_error(sk);
+
+ /* We may need to bind the socket. */
+ if (inet_autobind(sk) != 0)
+ return -EAGAIN;
+
+ return sk->prot->sendmsg(sk, msg, size);
+}
+
+
+int inet_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+
+ /* This should really check to make sure
+ * the socket is a TCP socket. (WHY AC...)
+ */
+ how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
+ 1->2 bit 2 snds.
+ 2->3 */
+ if ((how & ~SHUTDOWN_MASK) || how==0) /* MAXINT->0 */
+ return(-EINVAL);
+ if (!sk)
+ return(-ENOTCONN);
+ if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
+ sock->state = SS_CONNECTED;
+ if (!tcp_connected(sk->state))
+ return(-ENOTCONN);
+ sk->shutdown |= how;
+ if (sk->prot->shutdown)
+ sk->prot->shutdown(sk, how);
+ /* Wake up anyone sleeping in poll. */
+ sk->state_change(sk);
+ return(0);
+}
+
+
+unsigned int inet_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk->prot->poll == NULL)
+ return(0);
+ return sk->prot->poll(file, sock, wait);
+}
+
+#ifdef _HURD_
+#define inet_ioctl 0
+#else
+
+/*
+ * ioctl() calls you can issue on an INET socket. Most of these are
+ * device configuration and stuff and very rarely used. Some ioctls
+ * pass on to the socket itself.
+ *
+ * NOTE: I like the idea of a module for the config stuff. ie ifconfig
+ * loads the devconfigure module does its configuring and unloads it.
+ * There's a good 20K of config code hanging around the kernel.
+ */
+
+static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct sock *sk = sock->sk;
+ int err;
+ int pid;
+
+ switch(cmd)
+ {
+ case FIOSETOWN:
+ case SIOCSPGRP:
+ err = get_user(pid, (int *) arg);
+ if (err)
+ return err;
+ if (current->pid != pid && current->pgrp != -pid &&
+ !capable(CAP_NET_ADMIN))
+ return -EPERM;
+ sk->proc = pid;
+ return(0);
+ case FIOGETOWN:
+ case SIOCGPGRP:
+ return put_user(sk->proc, (int *)arg);
+ case SIOCGSTAMP:
+ if(sk->stamp.tv_sec==0)
+ return -ENOENT;
+ err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
+ if (err)
+ err = -EFAULT;
+ return err;
+ case SIOCADDRT:
+ case SIOCDELRT:
+ case SIOCRTMSG:
+ return(ip_rt_ioctl(cmd,(void *) arg));
+ case SIOCDARP:
+ case SIOCGARP:
+ case SIOCSARP:
+ return(arp_ioctl(cmd,(void *) arg));
+ case SIOCDRARP:
+ case SIOCGRARP:
+ case SIOCSRARP:
+#ifdef CONFIG_KMOD
+ if (rarp_ioctl_hook == NULL)
+ request_module("rarp");
+#endif
+ if (rarp_ioctl_hook != NULL)
+ return(rarp_ioctl_hook(cmd,(void *) arg));
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCSIFPFLAGS:
+ case SIOCGIFPFLAGS:
+ case SIOCSIFFLAGS:
+ return(devinet_ioctl(cmd,(void *) arg));
+ case SIOCGIFBR:
+ case SIOCSIFBR:
+#ifdef CONFIG_BRIDGE
+ return(br_ioctl(cmd,(void *) arg));
+#else
+ return -ENOPKG;
+#endif
+
+ case SIOCADDDLCI:
+ case SIOCDELDLCI:
+#ifdef CONFIG_DLCI
+ return(dlci_ioctl(cmd, (void *) arg));
+#endif
+
+#ifdef CONFIG_DLCI_MODULE
+
+#ifdef CONFIG_KMOD
+ if (dlci_ioctl_hook == NULL)
+ request_module("dlci");
+#endif
+
+ if (dlci_ioctl_hook)
+ return((*dlci_ioctl_hook)(cmd, (void *) arg));
+#endif
+ return -ENOPKG;
+
+ default:
+ if ((cmd >= SIOCDEVPRIVATE) &&
+ (cmd <= (SIOCDEVPRIVATE + 15)))
+ return(dev_ioctl(cmd,(void *) arg));
+
+#ifdef CONFIG_NET_RADIO
+ if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST))
+ return(dev_ioctl(cmd,(void *) arg));
+#endif
+
+ if (sk->prot->ioctl==NULL || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD)
+ return(dev_ioctl(cmd,(void *) arg));
+ return err;
+ }
+ /*NOTREACHED*/
+ return(0);
+}
+
+#endif
+
+struct proto_ops inet_stream_ops = {
+ PF_INET,
+
+ sock_no_dup,
+ inet_release,
+ inet_bind,
+ inet_stream_connect,
+ sock_no_socketpair,
+ inet_accept,
+ inet_getname,
+ inet_poll,
+ inet_ioctl,
+ inet_listen,
+ inet_shutdown,
+ inet_setsockopt,
+ inet_getsockopt,
+ sock_no_fcntl,
+ inet_sendmsg,
+ inet_recvmsg
+};
+
+struct proto_ops inet_dgram_ops = {
+ PF_INET,
+
+ sock_no_dup,
+ inet_release,
+ inet_bind,
+ inet_dgram_connect,
+ sock_no_socketpair,
+ sock_no_accept,
+ inet_getname,
+ datagram_poll,
+ inet_ioctl,
+ sock_no_listen,
+ inet_shutdown,
+ inet_setsockopt,
+ inet_getsockopt,
+ sock_no_fcntl,
+ inet_sendmsg,
+ inet_recvmsg
+};
+
+struct net_proto_family inet_family_ops = {
+ PF_INET,
+ inet_create
+};
+
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_INET_RARP
+static struct proc_dir_entry proc_net_rarp = {
+ PROC_NET_RARP, 4, "rarp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ rarp_get_info
+};
+#endif /* RARP */
+static struct proc_dir_entry proc_net_raw = {
+ PROC_NET_RAW, 3, "raw",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ raw_get_info
+};
+static struct proc_dir_entry proc_net_netstat = {
+ PROC_NET_NETSTAT, 7, "netstat",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ netstat_get_info
+};
+static struct proc_dir_entry proc_net_snmp = {
+ PROC_NET_SNMP, 4, "snmp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ snmp_get_info
+};
+static struct proc_dir_entry proc_net_sockstat = {
+ PROC_NET_SOCKSTAT, 8, "sockstat",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ afinet_get_info
+};
+static struct proc_dir_entry proc_net_tcp = {
+ PROC_NET_TCP, 3, "tcp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ tcp_get_info
+};
+static struct proc_dir_entry proc_net_udp = {
+ PROC_NET_UDP, 3, "udp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ udp_get_info
+};
+#endif /* CONFIG_PROC_FS */
+
+extern void tcp_init(void);
+extern void tcp_v4_init(struct net_proto_family *);
+
+
+/*
+ * Called by socket.c on kernel startup.
+ */
+
+__initfunc(void inet_proto_init(struct net_proto *pro))
+{
+ struct sk_buff *dummy_skb;
+ struct inet_protocol *p;
+
+ printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n");
+
+ if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb))
+ {
+ printk(KERN_CRIT "inet_proto_init: panic\n");
+ return;
+ }
+
+ /*
+ * Tell SOCKET that we are alive...
+ */
+
+ (void) sock_register(&inet_family_ops);
+
+ /*
+ * Add all the protocols.
+ */
+
+ printk(KERN_INFO "IP Protocols: ");
+ for(p = inet_protocol_base; p != NULL;)
+ {
+ struct inet_protocol *tmp = (struct inet_protocol *) p->next;
+ inet_add_protocol(p);
+ printk("%s%s",p->name,tmp?", ":"\n");
+ p = tmp;
+ }
+
+ /*
+ * Set the ARP module up
+ */
+
+ arp_init();
+
+ /*
+ * Set the IP module up
+ */
+
+ ip_init();
+
+ tcp_v4_init(&inet_family_ops);
+
+ /* Setup TCP slab cache for open requests. */
+ tcp_init();
+
+
+ /*
+ * Set the ICMP layer up
+ */
+
+ icmp_init(&inet_family_ops);
+
+ /* I wish inet_add_protocol had no constructor hook...
+ I had to move IPIP from net/ipv4/protocol.c :-( --ANK
+ */
+#ifdef CONFIG_NET_IPIP
+ ipip_init();
+#endif
+#ifdef CONFIG_NET_IPGRE
+ ipgre_init();
+#endif
+
+ /*
+ * Set the firewalling up
+ */
+#if defined(CONFIG_IP_FIREWALL)
+ ip_fw_init();
+#endif
+
+#ifdef CONFIG_IP_MASQUERADE
+ ip_masq_init();
+#endif
+
+ /*
+ * Initialise the multicast router
+ */
+#if defined(CONFIG_IP_MROUTE)
+ ip_mr_init();
+#endif
+
+#ifdef CONFIG_INET_RARP
+ rarp_ioctl_hook = rarp_ioctl;
+#endif
+ /*
+ * Create all the /proc entries.
+ */
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_INET_RARP
+ proc_net_register(&proc_net_rarp);
+#endif /* RARP */
+ proc_net_register(&proc_net_raw);
+ proc_net_register(&proc_net_snmp);
+ proc_net_register(&proc_net_netstat);
+ proc_net_register(&proc_net_sockstat);
+ proc_net_register(&proc_net_tcp);
+ proc_net_register(&proc_net_udp);
+#endif /* CONFIG_PROC_FS */
+}
diff --git a/pfinet/linux-src/net/ipv4/arp.c b/pfinet/linux-src/net/ipv4/arp.c
new file mode 100644
index 00000000..53d155a9
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/arp.c
@@ -0,0 +1,1191 @@
+/* linux/net/inet/arp.c
+ *
+ * Version: $Id: arp.c,v 1.77.2.4 1999/09/23 19:03:36 davem Exp $
+ *
+ * Copyright (C) 1994 by Florian La Roche
+ *
+ * This module implements the Address Resolution Protocol ARP (RFC 826),
+ * which is used to convert IP addresses (or in the future maybe other
+ * high-level addresses) into a low-level hardware address (like an Ethernet
+ * address).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ * Alan Cox : Removed the Ethernet assumptions in
+ * Florian's code
+ * Alan Cox : Fixed some small errors in the ARP
+ * logic
+ * Alan Cox : Allow >4K in /proc
+ * Alan Cox : Make ARP add its own protocol entry
+ * Ross Martin : Rewrote arp_rcv() and arp_get_info()
+ * Stephen Henson : Add AX25 support to arp_get_info()
+ * Alan Cox : Drop data when a device is downed.
+ * Alan Cox : Use init_timer().
+ * Alan Cox : Double lock fixes.
+ * Martin Seine : Move the arphdr structure
+ * to if_arp.h for compatibility.
+ * with BSD based programs.
+ * Andrew Tridgell : Added ARP netmask code and
+ * re-arranged proxy handling.
+ * Alan Cox : Changed to use notifiers.
+ * Niibe Yutaka : Reply for this device or proxies only.
+ * Alan Cox : Don't proxy across hardware types!
+ * Jonathan Naylor : Added support for NET/ROM.
+ * Mike Shaver : RFC1122 checks.
+ * Jonathan Naylor : Only lookup the hardware address for
+ * the correct hardware type.
+ * Germano Caronni : Assorted subtle races.
+ * Craig Schlenter : Don't modify permanent entry
+ * during arp_rcv.
+ * Russ Nelson : Tidied up a few bits.
+ * Alexey Kuznetsov: Major changes to caching and behaviour,
+ * eg intelligent arp probing and
+ * generation
+ * of host down events.
+ * Alan Cox : Missing unlock in device events.
+ * Eckes : ARP ioctl control errors.
+ * Alexey Kuznetsov: Arp free fix.
+ * Manuel Rodriguez: Gratuitous ARP.
+ * Jonathan Layes : Added arpd support through kerneld
+ * message queue (960314)
+ * Mike Shaver : /proc/sys/net/ipv4/arp_* support
+ * Mike McLagan : Routing by source
+ * Stuart Cheshire : Metricom and grat arp fixes
+ * *** FOR 2.1 clean this up ***
+ * Lawrence V. Stefani: (08/12/96) Added FDDI support.
+ * Alan Cox : Took the AP1000 nasty FDDI hack and
+ * folded into the mainstream FDDI code.
+ * Ack spit, Linus how did you allow that
+ * one in...
+ * Jes Sorensen : Make FDDI work again in 2.1.x and
+ * clean up the APFDDI & gen. FDDI bits.
+ * Alexey Kuznetsov: new arp state machine;
+ * now it is in net/core/neighbour.c.
+ * Julian Anastasov: "hidden" flag: hide the
+ * interface and don't reply for it
+ */
+
+/* RFC1122 Status:
+ 2.3.2.1 (ARP Cache Validation):
+ MUST provide mechanism to flush stale cache entries (OK)
+ SHOULD be able to configure cache timeout (OK)
+ MUST throttle ARP retransmits (OK)
+ 2.3.2.2 (ARP Packet Queue):
+ SHOULD save at least one packet from each "conversation" with an
+ unresolved IP address. (OK)
+ 950727 -- MS
+*/
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/config.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/mm.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/if_arp.h>
+#include <linux/trdevice.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/route.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+#include <net/ax25.h>
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#include <net/netrom.h>
+#endif
+#endif
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*
+ * Interface to generic neighbour cache.
+ */
+static int arp_constructor(struct neighbour *neigh);
+static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
+static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
+static void parp_redo(struct sk_buff *skb);
+
+static struct neigh_ops arp_generic_ops =
+{
+ AF_INET,
+ NULL,
+ arp_solicit,
+ arp_error_report,
+ neigh_resolve_output,
+ neigh_connected_output,
+ dev_queue_xmit,
+ dev_queue_xmit
+};
+
+static struct neigh_ops arp_hh_ops =
+{
+ AF_INET,
+ NULL,
+ arp_solicit,
+ arp_error_report,
+ neigh_resolve_output,
+ neigh_resolve_output,
+ dev_queue_xmit,
+ dev_queue_xmit
+};
+
+static struct neigh_ops arp_direct_ops =
+{
+ AF_INET,
+ NULL,
+ NULL,
+ NULL,
+ dev_queue_xmit,
+ dev_queue_xmit,
+ dev_queue_xmit,
+ dev_queue_xmit
+};
+
+struct neigh_ops arp_broken_ops =
+{
+ AF_INET,
+ NULL,
+ arp_solicit,
+ arp_error_report,
+ neigh_compat_output,
+ neigh_compat_output,
+ dev_queue_xmit,
+ dev_queue_xmit,
+};
+
+struct neigh_table arp_tbl =
+{
+ NULL,
+ AF_INET,
+ sizeof(struct neighbour) + 4,
+ 4,
+ arp_constructor,
+ NULL,
+ NULL,
+ parp_redo,
+ { NULL, NULL, &arp_tbl, 0, NULL, NULL,
+ 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 1*HZ },
+ 30*HZ, 128, 512, 1024,
+};
+
+int arp_mc_map(u32 addr, u8 *haddr, struct device *dev, int dir)
+{
+ switch (dev->type) {
+ case ARPHRD_ETHER:
+ case ARPHRD_FDDI:
+ ip_eth_mc_map(addr, haddr) ;
+ return 0 ;
+ case ARPHRD_IEEE802:
+ if ( (dev->name[0] == 't') && (dev->name[1] == 'r')) /* Token Ring */
+ ip_tr_mc_map(addr,haddr) ;
+ else
+ ip_eth_mc_map(addr, haddr);
+ return 0;
+ default:
+ if (dir) {
+ memcpy(haddr, dev->broadcast, dev->addr_len);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+
+
+static int arp_constructor(struct neighbour *neigh)
+{
+ u32 addr = *(u32*)neigh->primary_key;
+ struct device *dev = neigh->dev;
+ struct in_device *in_dev = dev->ip_ptr;
+
+ if (in_dev == NULL)
+ return -EINVAL;
+
+ neigh->type = inet_addr_type(addr);
+ if (in_dev->arp_parms)
+ neigh->parms = in_dev->arp_parms;
+
+ if (dev->hard_header == NULL) {
+ neigh->nud_state = NUD_NOARP;
+ neigh->ops = &arp_direct_ops;
+ neigh->output = neigh->ops->queue_xmit;
+ } else {
+ /* Good devices (checked by reading texts, but only Ethernet is
+ tested)
+
+ ARPHRD_ETHER: (ethernet, apfddi)
+ ARPHRD_FDDI: (fddi)
+ ARPHRD_IEEE802: (tr)
+ ARPHRD_METRICOM: (strip)
+ ARPHRD_ARCNET:
+ etc. etc. etc.
+
+ ARPHRD_IPDDP will also work, if author repairs it.
+ I did not it, because this driver does not work even
+ in old paradigm.
+ */
+
+#if 1
+ /* So... these "amateur" devices are hopeless.
+ The only thing, that I can say now:
+ It is very sad that we need to keep ugly obsolete
+ code to make them happy.
+
+ They should be moved to more reasonable state, now
+ they use rebuild_header INSTEAD OF hard_start_xmit!!!
+ Besides that, they are sort of out of date
+ (a lot of redundant clones/copies, useless in 2.1),
+ I wonder why people believe that they work.
+ */
+ switch (dev->type) {
+ default:
+ break;
+ case ARPHRD_ROSE:
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+ case ARPHRD_AX25:
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+ case ARPHRD_NETROM:
+#endif
+ neigh->ops = &arp_broken_ops;
+ neigh->output = neigh->ops->output;
+ return 0;
+#endif
+ break;
+ }
+#endif
+ if (neigh->type == RTN_MULTICAST) {
+ neigh->nud_state = NUD_NOARP;
+ arp_mc_map(addr, neigh->ha, dev, 1);
+ } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
+ neigh->nud_state = NUD_NOARP;
+ memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
+ } else if (neigh->type == RTN_BROADCAST || dev->flags&IFF_POINTOPOINT) {
+ neigh->nud_state = NUD_NOARP;
+ memcpy(neigh->ha, dev->broadcast, dev->addr_len);
+ }
+ if (dev->hard_header_cache)
+ neigh->ops = &arp_hh_ops;
+ else
+ neigh->ops = &arp_generic_ops;
+ if (neigh->nud_state&NUD_VALID)
+ neigh->output = neigh->ops->connected_output;
+ else
+ neigh->output = neigh->ops->output;
+ }
+
+ return 0;
+}
+
+static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb)
+{
+ dst_link_failure(skb);
+ kfree_skb(skb);
+}
+
+static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
+{
+ u32 saddr;
+ u8 *dst_ha = NULL;
+ struct device *dev = neigh->dev;
+ struct device *dev2;
+ struct in_device *in_dev2;
+ u32 target = *(u32*)neigh->primary_key;
+ int probes = neigh->probes;
+
+ if (skb &&
+ (dev2 = ip_dev_find(skb->nh.iph->saddr)) != NULL &&
+ (in_dev2 = dev2->ip_ptr) != NULL &&
+ !IN_DEV_HIDDEN(in_dev2))
+ saddr = skb->nh.iph->saddr;
+ else
+ saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
+
+ if ((probes -= neigh->parms->ucast_probes) < 0) {
+ if (!(neigh->nud_state&NUD_VALID))
+ printk(KERN_DEBUG "trying to ucast probe in NUD_INVALID\n");
+ dst_ha = neigh->ha;
+ } else if ((probes -= neigh->parms->app_probes) < 0) {
+#ifdef CONFIG_ARPD
+ neigh_app_ns(neigh);
+#endif
+ return;
+ }
+
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
+ dst_ha, dev->dev_addr, NULL);
+}
+
+/* OBSOLETE FUNCTIONS */
+
+/*
+ * Find an arp mapping in the cache. If not found, post a request.
+ *
+ * It is very UGLY routine: it DOES NOT use skb->dst->neighbour,
+ * even if it exists. It is supposed that skb->dev was mangled
+ * by a virtual device (eql, shaper). Nobody but broken devices
+ * is allowed to use this function, it is scheduled to be removed. --ANK
+ */
+
+static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct device * dev)
+{
+ switch (addr_hint) {
+ case RTN_LOCAL:
+ printk(KERN_DEBUG "ARP: arp called for own IP address\n");
+ memcpy(haddr, dev->dev_addr, dev->addr_len);
+ return 1;
+ case RTN_MULTICAST:
+ arp_mc_map(paddr, haddr, dev, 1);
+ return 1;
+ case RTN_BROADCAST:
+ memcpy(haddr, dev->broadcast, dev->addr_len);
+ return 1;
+ }
+ return 0;
+}
+
+
+int arp_find(unsigned char *haddr, struct sk_buff *skb)
+{
+ struct device *dev = skb->dev;
+ u32 paddr;
+ struct neighbour *n;
+
+ if (!skb->dst) {
+ printk(KERN_DEBUG "arp_find is called with dst==NULL\n");
+ kfree_skb(skb);
+ return 1;
+ }
+
+ paddr = ((struct rtable*)skb->dst)->rt_gateway;
+
+ if (arp_set_predefined(inet_addr_type(paddr), haddr, paddr, dev))
+ return 0;
+
+ start_bh_atomic();
+ n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);
+
+ if (n) {
+ n->used = jiffies;
+ if (n->nud_state&NUD_VALID || neigh_event_send(n, skb) == 0) {
+ memcpy(haddr, n->ha, dev->addr_len);
+ neigh_release(n);
+ end_bh_atomic();
+ return 0;
+ }
+ neigh_release(n);
+ } else
+ kfree_skb(skb);
+ end_bh_atomic();
+ return 1;
+}
+
+/* END OF OBSOLETE FUNCTIONS */
+
+/*
+ * Note: requires bh_atomic locking.
+ */
+int arp_bind_neighbour(struct dst_entry *dst)
+{
+ struct device *dev = dst->dev;
+
+ if (dev == NULL)
+ return 0;
+ if (dst->neighbour == NULL) {
+ u32 nexthop = ((struct rtable*)dst)->rt_gateway;
+ if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
+ nexthop = 0;
+ dst->neighbour = __neigh_lookup(&arp_tbl, &nexthop, dev, 1);
+ }
+ return (dst->neighbour != NULL);
+}
+
+/*
+ * Interface to link layer: send routine and receive handler.
+ */
+
+/*
+ * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast
+ * message.
+ */
+
+void arp_send(int type, int ptype, u32 dest_ip,
+ struct device *dev, u32 src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw,
+ unsigned char *target_hw)
+{
+ struct sk_buff *skb;
+ struct arphdr *arp;
+ unsigned char *arp_ptr;
+
+ /*
+ * No arp on this interface.
+ */
+
+ if (dev->flags&IFF_NOARP)
+ return;
+
+ /*
+ * Allocate a buffer
+ */
+
+ skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
+ + dev->hard_header_len + 15, GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+
+ skb_reserve(skb, (dev->hard_header_len+15)&~15);
+ skb->nh.raw = skb->data;
+ arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
+ skb->dev = dev;
+ skb->protocol = __constant_htons (ETH_P_ARP);
+ if (src_hw == NULL)
+ src_hw = dev->dev_addr;
+ if (dest_hw == NULL)
+ dest_hw = dev->broadcast;
+
+ /*
+ * Fill the device header for the ARP frame
+ */
+ dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len);
+
+ /*
+ * Fill out the arp protocol part.
+ *
+ * The arp hardware type should match the device type, except for FDDI,
+ * which (according to RFC 1390) should always equal 1 (Ethernet).
+ */
+ /*
+ * Exceptions everywhere. AX.25 uses the AX.25 PID value not the
+ * DIX code for the protocol. Make these device structure fields.
+ */
+ switch (dev->type) {
+ default:
+ arp->ar_hrd = htons(dev->type);
+ arp->ar_pro = __constant_htons(ETH_P_IP);
+ break;
+
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+ case ARPHRD_AX25:
+ arp->ar_hrd = __constant_htons(ARPHRD_AX25);
+ arp->ar_pro = __constant_htons(AX25_P_IP);
+ break;
+
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+ case ARPHRD_NETROM:
+ arp->ar_hrd = __constant_htons(ARPHRD_NETROM);
+ arp->ar_pro = __constant_htons(AX25_P_IP);
+ break;
+#endif
+#endif
+
+#ifdef CONFIG_FDDI
+ case ARPHRD_FDDI:
+ arp->ar_hrd = __constant_htons(ARPHRD_ETHER);
+ arp->ar_pro = __constant_htons(ETH_P_IP);
+ break;
+#endif
+ }
+
+ arp->ar_hln = dev->addr_len;
+ arp->ar_pln = 4;
+ arp->ar_op = htons(type);
+
+ arp_ptr=(unsigned char *)(arp+1);
+
+ memcpy(arp_ptr, src_hw, dev->addr_len);
+ arp_ptr+=dev->addr_len;
+ memcpy(arp_ptr, &src_ip,4);
+ arp_ptr+=4;
+ if (target_hw != NULL)
+ memcpy(arp_ptr, target_hw, dev->addr_len);
+ else
+ memset(arp_ptr, 0, dev->addr_len);
+ arp_ptr+=dev->addr_len;
+ memcpy(arp_ptr, &dest_ip, 4);
+ skb->dev = dev;
+
+ dev_queue_xmit(skb);
+}
+
+static void parp_redo(struct sk_buff *skb)
+{
+ arp_rcv(skb, skb->dev, NULL);
+}
+
+/*
+ * Receive an arp request by the device layer.
+ */
+
+int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+ struct arphdr *arp = skb->nh.arph;
+ unsigned char *arp_ptr= (unsigned char *)(arp+1);
+ struct rtable *rt;
+ unsigned char *sha, *tha;
+ u32 sip, tip;
+ u16 dev_type = dev->type;
+ int addr_type;
+ struct in_device *in_dev = dev->ip_ptr;
+ struct neighbour *n;
+
+/*
+ * The hardware length of the packet should match the hardware length
+ * of the device. Similarly, the hardware types should match. The
+ * device should be ARP-able. Also, if pln is not 4, then the lookup
+ * is not from an IP number. We can't currently handle this, so toss
+ * it.
+ */
+ if (in_dev == NULL ||
+ arp->ar_hln != dev->addr_len ||
+ dev->flags & IFF_NOARP ||
+ skb->pkt_type == PACKET_OTHERHOST ||
+ skb->pkt_type == PACKET_LOOPBACK ||
+ arp->ar_pln != 4)
+ goto out;
+
+ switch (dev_type) {
+ default:
+ if (arp->ar_pro != __constant_htons(ETH_P_IP))
+ goto out;
+ if (htons(dev_type) != arp->ar_hrd)
+ goto out;
+ break;
+#ifdef CONFIG_NET_ETHERNET
+ case ARPHRD_ETHER:
+ /*
+ * ETHERNET devices will accept ARP hardware types of either
+ * 1 (Ethernet) or 6 (IEEE 802.2).
+ */
+ if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
+ arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
+ goto out;
+ if (arp->ar_pro != __constant_htons(ETH_P_IP))
+ goto out;
+ break;
+#endif
+#ifdef CONFIG_FDDI
+ case ARPHRD_FDDI:
+ /*
+ * According to RFC 1390, FDDI devices should accept ARP hardware types
+ * of 1 (Ethernet). However, to be more robust, we'll accept hardware
+ * types of either 1 (Ethernet) or 6 (IEEE 802.2).
+ */
+ if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) &&
+ arp->ar_hrd != __constant_htons(ARPHRD_IEEE802))
+ goto out;
+ if (arp->ar_pro != __constant_htons(ETH_P_IP))
+ goto out;
+ break;
+#endif
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+ case ARPHRD_AX25:
+ if (arp->ar_pro != __constant_htons(AX25_P_IP))
+ goto out;
+ if (arp->ar_hrd != __constant_htons(ARPHRD_AX25))
+ goto out;
+ break;
+#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+ case ARPHRD_NETROM:
+ if (arp->ar_pro != __constant_htons(AX25_P_IP))
+ goto out;
+ if (arp->ar_hrd != __constant_htons(ARPHRD_NETROM))
+ goto out;
+ break;
+#endif
+#endif
+ }
+
+ /* Undertsand only these message types */
+
+ if (arp->ar_op != __constant_htons(ARPOP_REPLY) &&
+ arp->ar_op != __constant_htons(ARPOP_REQUEST))
+ goto out;
+
+/*
+ * Extract fields
+ */
+ sha=arp_ptr;
+ arp_ptr += dev->addr_len;
+ memcpy(&sip, arp_ptr, 4);
+ arp_ptr += 4;
+ tha=arp_ptr;
+ arp_ptr += dev->addr_len;
+ memcpy(&tip, arp_ptr, 4);
+/*
+ * Check for bad requests for 127.x.x.x and requests for multicast
+ * addresses. If this is one such, delete it.
+ */
+ if (LOOPBACK(tip) || MULTICAST(tip))
+ goto out;
+
+/*
+ * Process entry. The idea here is we want to send a reply if it is a
+ * request for us or if it is a request for someone else that we hold
+ * a proxy for. We want to add an entry to our cache if it is a reply
+ * to us or if it is a request for our address.
+ * (The assumption for this last is that if someone is requesting our
+ * address, they are probably intending to talk to us, so it saves time
+ * if we cache their address. Their address is also probably not in
+ * our cache, since ours is not in their cache.)
+ *
+ * Putting this another way, we only care about replies if they are to
+ * us, in which case we add them to the cache. For requests, we care
+ * about those for us and those for our proxies. We reply to both,
+ * and in the case of requests for us we add the requester to the arp
+ * cache.
+ */
+
+ /* Special case: IPv4 duplicate address detection packet (RFC2131) */
+ if (sip == 0) {
+ struct device *dev2;
+ struct in_device *in_dev2;
+
+ if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
+ (dev2 = ip_dev_find(tip)) != NULL &&
+ (dev2 == dev ||
+ ((in_dev2 = dev2->ip_ptr) != NULL &&
+ !IN_DEV_HIDDEN(in_dev2))))
+ arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
+ goto out;
+ }
+
+ if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
+ ip_route_input(skb, tip, sip, 0, dev) == 0) {
+
+ rt = (struct rtable*)skb->dst;
+ addr_type = rt->rt_type;
+
+ if (addr_type == RTN_LOCAL) {
+ n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
+ if (n) {
+ if (ipv4_devconf.hidden &&
+ skb->pkt_type != PACKET_HOST) {
+ struct device *dev2;
+ struct in_device *in_dev2;
+
+ if ((dev2 = ip_dev_find(tip)) != NULL &&
+ dev2 != dev &&
+ (in_dev2 = dev2->ip_ptr) != NULL &&
+ IN_DEV_HIDDEN(in_dev2)) {
+ neigh_release(n);
+ goto out;
+ }
+ }
+
+ arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+ neigh_release(n);
+ }
+ goto out;
+ } else if (IN_DEV_FORWARD(in_dev)) {
+ if ((rt->rt_flags&RTCF_DNAT) ||
+ (addr_type == RTN_UNICAST && rt->u.dst.dev != dev &&
+ (IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
+ n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
+ neigh_release(n);
+
+ if (skb->stamp.tv_sec == 0 ||
+ skb->pkt_type == PACKET_HOST ||
+ in_dev->arp_parms->proxy_delay == 0) {
+ arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+ } else {
+ pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
+ return 0;
+ }
+ goto out;
+ }
+ }
+ }
+
+ /* Update our ARP tables */
+
+ n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
+
+#ifdef CONFIG_IP_ACCEPT_UNSOLICITED_ARP
+ /* Unsolicited ARP is not accepted by default.
+ It is possible, that this option should be enabled for some
+ devices (strip is candidate)
+ */
+ if (n == NULL &&
+ arp->ar_op == __constant_htons(ARPOP_REPLY) &&
+ inet_addr_type(sip) == RTN_UNICAST)
+ n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
+#endif
+
+ if (n) {
+ int state = NUD_REACHABLE;
+ int override = 0;
+
+ /* If several different ARP replies follows back-to-back,
+ use the FIRST one. It is possible, if several proxy
+ agents are active. Taking the first reply prevents
+ arp trashing and chooses the fastest router.
+ */
+ if (jiffies - n->updated >= n->parms->locktime)
+ override = 1;
+
+ /* Broadcast replies and request packets
+ do not assert neighbour reachability.
+ */
+ if (arp->ar_op != __constant_htons(ARPOP_REPLY) ||
+ skb->pkt_type != PACKET_HOST)
+ state = NUD_STALE;
+ neigh_update(n, sha, state, override, 1);
+ neigh_release(n);
+ }
+
+out:
+ kfree_skb(skb);
+ return 0;
+}
+
+
+
+/*
+ * User level interface (ioctl, /proc)
+ */
+
+/*
+ * Set (create) an ARP cache entry.
+ */
+
+int arp_req_set(struct arpreq *r, struct device * dev)
+{
+ u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+ struct neighbour *neigh;
+ int err;
+
+ if (r->arp_flags&ATF_PUBL) {
+ u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
+ if (mask && mask != 0xFFFFFFFF)
+ return -EINVAL;
+ if (!dev && (r->arp_flags & ATF_COM)) {
+ dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data);
+ if (!dev)
+ return -ENODEV;
+ }
+ if (mask) {
+ if (pneigh_lookup(&arp_tbl, &ip, dev, 1) == NULL)
+ return -ENOBUFS;
+ return 0;
+ }
+ if (dev == NULL) {
+ ipv4_devconf.proxy_arp = 1;
+ return 0;
+ }
+ if (dev->ip_ptr) {
+ ((struct in_device*)dev->ip_ptr)->cnf.proxy_arp = 1;
+ return 0;
+ }
+ return -ENXIO;
+ }
+
+ if (r->arp_flags & ATF_PERM)
+ r->arp_flags |= ATF_COM;
+ if (dev == NULL) {
+ struct rtable * rt;
+ if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0)
+ return err;
+ dev = rt->u.dst.dev;
+ ip_rt_put(rt);
+ if (!dev)
+ return -EINVAL;
+ }
+ if (r->arp_ha.sa_family != dev->type)
+ return -EINVAL;
+
+ err = -ENOBUFS;
+ start_bh_atomic();
+ neigh = __neigh_lookup(&arp_tbl, &ip, dev, 1);
+ if (neigh) {
+ unsigned state = NUD_STALE;
+ if (r->arp_flags & ATF_PERM)
+ state = NUD_PERMANENT;
+ err = neigh_update(neigh, (r->arp_flags&ATF_COM) ?
+ r->arp_ha.sa_data : NULL, state, 1, 0);
+ neigh_release(neigh);
+ }
+ end_bh_atomic();
+ return err;
+}
+
+static unsigned arp_state_to_flags(struct neighbour *neigh)
+{
+ unsigned flags = 0;
+ if (neigh->nud_state&NUD_PERMANENT)
+ flags = ATF_PERM|ATF_COM;
+ else if (neigh->nud_state&NUD_VALID)
+ flags = ATF_COM;
+ return flags;
+}
+
+/*
+ * Get an ARP cache entry.
+ */
+
+static int arp_req_get(struct arpreq *r, struct device *dev)
+{
+ u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+ struct neighbour *neigh;
+ int err = -ENXIO;
+
+ start_bh_atomic();
+ neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0);
+ if (neigh) {
+ memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
+ r->arp_ha.sa_family = dev->type;
+ strncpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
+ r->arp_flags = arp_state_to_flags(neigh);
+ neigh_release(neigh);
+ err = 0;
+ }
+ end_bh_atomic();
+ return err;
+}
+
+int arp_req_delete(struct arpreq *r, struct device * dev)
+{
+ int err;
+ u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
+ struct neighbour *neigh;
+
+ if (r->arp_flags & ATF_PUBL) {
+ u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
+ if (mask == 0xFFFFFFFF)
+ return pneigh_delete(&arp_tbl, &ip, dev);
+ if (mask == 0) {
+ if (dev == NULL) {
+ ipv4_devconf.proxy_arp = 0;
+ return 0;
+ }
+ if (dev->ip_ptr) {
+ ((struct in_device*)dev->ip_ptr)->cnf.proxy_arp = 0;
+ return 0;
+ }
+ return -ENXIO;
+ }
+ return -EINVAL;
+ }
+
+ if (dev == NULL) {
+ struct rtable * rt;
+ if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0)
+ return err;
+ dev = rt->u.dst.dev;
+ ip_rt_put(rt);
+ if (!dev)
+ return -EINVAL;
+ }
+ err = -ENXIO;
+ start_bh_atomic();
+ neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0);
+ if (neigh) {
+ if (neigh->nud_state&~NUD_NOARP)
+ err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0);
+ neigh_release(neigh);
+ }
+ end_bh_atomic();
+ return err;
+}
+
+#ifdef _HURD_
+#define arp_ioctl 0
+#else
+/*
+ * Handle an ARP layer I/O control request.
+ */
+
+int arp_ioctl(unsigned int cmd, void *arg)
+{
+ int err;
+ struct arpreq r;
+ struct device * dev = NULL;
+
+ switch(cmd) {
+ case SIOCDARP:
+ case SIOCSARP:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ case SIOCGARP:
+ err = copy_from_user(&r, arg, sizeof(struct arpreq));
+ if (err)
+ return -EFAULT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (r.arp_pa.sa_family != AF_INET)
+ return -EPFNOSUPPORT;
+
+ if (!(r.arp_flags & ATF_PUBL) &&
+ (r.arp_flags & (ATF_NETMASK|ATF_DONTPUB)))
+ return -EINVAL;
+ if (!(r.arp_flags & ATF_NETMASK))
+ ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=__constant_htonl(0xFFFFFFFFUL);
+
+ rtnl_lock();
+ if (r.arp_dev[0]) {
+ err = -ENODEV;
+ if ((dev = dev_get(r.arp_dev)) == NULL)
+ goto out;
+
+ /* Mmmm... It is wrong... ARPHRD_NETROM==0 */
+ if (!r.arp_ha.sa_family)
+ r.arp_ha.sa_family = dev->type;
+ err = -EINVAL;
+ if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type)
+ goto out;
+ } else if (cmd == SIOCGARP) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ switch(cmd) {
+ case SIOCDARP:
+ err = arp_req_delete(&r, dev);
+ break;
+ case SIOCSARP:
+ err = arp_req_set(&r, dev);
+ break;
+ case SIOCGARP:
+ err = arp_req_get(&r, dev);
+ if (!err && copy_to_user(arg, &r, sizeof(r)))
+ err = -EFAULT;
+ break;
+ }
+out:
+ rtnl_unlock();
+ return err;
+}
+#endif
+
+/*
+ * Write the contents of the ARP cache to a PROCfs file.
+ */
+#ifdef CONFIG_PROC_FS
+
+#define HBUFFERLEN 30
+
+int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int len=0;
+ off_t pos=0;
+ int size;
+ char hbuffer[HBUFFERLEN];
+ int i,j,k;
+ const char hexbuf[] = "0123456789ABCDEF";
+
+ size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n");
+
+ pos+=size;
+ len+=size;
+
+ neigh_table_lock(&arp_tbl);
+
+ for(i=0; i<=NEIGH_HASHMASK; i++) {
+ struct neighbour *n;
+ for (n=arp_tbl.hash_buckets[i]; n; n=n->next) {
+ struct device *dev = n->dev;
+ int hatype = dev->type;
+
+ /* Do not confuse users "arp -a" with magic entries */
+ if (!(n->nud_state&~NUD_NOARP))
+ continue;
+
+ /* I'd get great pleasure deleting
+ this ugly code. Let's output it in hexadecimal format.
+ "arp" utility will eventually repaired --ANK
+ */
+#if 1 /* UGLY CODE */
+/*
+ * Convert hardware address to XX:XX:XX:XX ... form.
+ */
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+ if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM)
+ strcpy(hbuffer,ax2asc((ax25_address *)n->ha));
+ else {
+#endif
+ for (k=0,j=0;k<HBUFFERLEN-3 && j<dev->addr_len;j++) {
+ hbuffer[k++]=hexbuf[(n->ha[j]>>4)&15 ];
+ hbuffer[k++]=hexbuf[n->ha[j]&15 ];
+ hbuffer[k++]=':';
+ }
+ hbuffer[--k]=0;
+
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+ }
+#endif
+#else
+ if ((neigh->nud_state&NUD_VALID) && dev->addr_len) {
+ int j;
+ for (j=0; j < dev->addr_len; j++)
+ sprintf(hbuffer+2*j, "%02x", neigh->ha[j]);
+ } else
+ sprintf(hbuffer, "0");
+#endif
+
+ size = sprintf(buffer+len,
+ "%-17s0x%-10x0x%-10x%s",
+ in_ntoa(*(u32*)n->primary_key),
+ hatype,
+ arp_state_to_flags(n),
+ hbuffer);
+ size += sprintf(buffer+len+size,
+ " %-17s %s\n",
+ "*", dev->name);
+
+ len += size;
+ pos += size;
+
+ if (pos <= offset)
+ len=0;
+ if (pos >= offset+length)
+ goto done;
+ }
+ }
+
+ for (i=0; i<=PNEIGH_HASHMASK; i++) {
+ struct pneigh_entry *n;
+ for (n=arp_tbl.phash_buckets[i]; n; n=n->next) {
+ struct device *dev = n->dev;
+ int hatype = dev ? dev->type : 0;
+
+ size = sprintf(buffer+len,
+ "%-17s0x%-10x0x%-10x%s",
+ in_ntoa(*(u32*)n->key),
+ hatype,
+ ATF_PUBL|ATF_PERM,
+ "00:00:00:00:00:00");
+ size += sprintf(buffer+len+size,
+ " %-17s %s\n",
+ "*", dev ? dev->name : "*");
+
+ len += size;
+ pos += size;
+
+ if (pos <= offset)
+ len=0;
+ if (pos >= offset+length)
+ goto done;
+ }
+ }
+
+done:
+ neigh_table_unlock(&arp_tbl);
+
+ *start = buffer+len-(pos-offset); /* Start of wanted data */
+ len = pos-offset; /* Start slop */
+ if (len>length)
+ len = length; /* Ending slop */
+ if (len<0)
+ len = 0;
+ return len;
+}
+#endif
+
+/* Note, that it is not on notifier chain.
+ It is necessary, that this routine was called after route cache will be
+ flushed.
+ */
+void arp_ifdown(struct device *dev)
+{
+ neigh_ifdown(&arp_tbl, dev);
+}
+
+
+/*
+ * Called once on startup.
+ */
+
+static struct packet_type arp_packet_type =
+{
+ __constant_htons(ETH_P_ARP),
+ NULL, /* All devices */
+ arp_rcv,
+ NULL,
+ NULL
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_arp = {
+ PROC_NET_ARP, 3, "arp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ arp_get_info
+};
+#endif
+
+__initfunc(void arp_init (void))
+{
+ neigh_table_init(&arp_tbl);
+
+ dev_add_pack(&arp_packet_type);
+
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_net_arp);
+#endif
+#ifdef CONFIG_SYSCTL
+ neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
+#endif
+}
+
+
+#ifdef CONFIG_AX25_MODULE
+
+/*
+ * ax25 -> ASCII conversion
+ */
+char *ax2asc(ax25_address *a)
+{
+ static char buf[11];
+ char c, *s;
+ int n;
+
+ for (n = 0, s = buf; n < 6; n++) {
+ c = (a->ax25_call[n] >> 1) & 0x7F;
+
+ if (c != ' ') *s++ = c;
+ }
+
+ *s++ = '-';
+
+ if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
+ *s++ = '1';
+ n -= 10;
+ }
+
+ *s++ = n + '0';
+ *s++ = '\0';
+
+ if (*buf == '\0' || *buf == '-')
+ return "*";
+
+ return buf;
+
+}
+
+#endif
diff --git a/pfinet/linux-src/net/ipv4/devinet.c b/pfinet/linux-src/net/ipv4/devinet.c
new file mode 100644
index 00000000..0416ee82
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/devinet.c
@@ -0,0 +1,1121 @@
+/*
+ * NET3 IP device support routines.
+ *
+ * Version: $Id: devinet.c,v 1.28.2.2 1999/08/07 10:56:18 davem Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Derived from the IP parts of dev.c 1.0.19
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ *
+ * Additional Authors:
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Changes:
+ * Alexey Kuznetsov: pa_* fields are replaced with ifaddr lists.
+ * Cyrus Durgin: updated for kmod
+ */
+
+#include <linux/config.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+
+struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, };
+static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, };
+
+#ifdef CONFIG_RTNETLINK
+static void rtmsg_ifa(int event, struct in_ifaddr *);
+#else
+#define rtmsg_ifa(a,b) do { } while(0)
+#endif
+
+static struct notifier_block *inetaddr_chain;
+static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy);
+#ifdef CONFIG_SYSCTL
+static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p);
+static void devinet_sysctl_unregister(struct ipv4_devconf *p);
+#endif
+
+int inet_ifa_count;
+int inet_dev_count;
+
+static struct in_ifaddr * inet_alloc_ifa(void)
+{
+ struct in_ifaddr *ifa;
+
+ ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
+ if (ifa) {
+ memset(ifa, 0, sizeof(*ifa));
+ inet_ifa_count++;
+ }
+
+ return ifa;
+}
+
+static __inline__ void inet_free_ifa(struct in_ifaddr *ifa)
+{
+ kfree_s(ifa, sizeof(*ifa));
+ inet_ifa_count--;
+}
+
+struct in_device *inetdev_init(struct device *dev)
+{
+ struct in_device *in_dev;
+
+ if (dev->mtu < 68)
+ return NULL;
+
+ in_dev = kmalloc(sizeof(*in_dev), GFP_KERNEL);
+ if (!in_dev)
+ return NULL;
+ inet_dev_count++;
+ memset(in_dev, 0, sizeof(*in_dev));
+ memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
+ in_dev->cnf.sysctl = NULL;
+ in_dev->dev = dev;
+ if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) {
+ kfree(in_dev);
+ return NULL;
+ }
+#ifdef CONFIG_SYSCTL
+ neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
+#endif
+ dev->ip_ptr = in_dev;
+#ifdef CONFIG_SYSCTL
+ devinet_sysctl_register(in_dev, &in_dev->cnf);
+#endif
+ if (dev->flags&IFF_UP)
+ ip_mc_up(in_dev);
+ return in_dev;
+}
+
+static void inetdev_destroy(struct in_device *in_dev)
+{
+ struct in_ifaddr *ifa;
+
+ ip_mc_destroy_dev(in_dev);
+
+ while ((ifa = in_dev->ifa_list) != NULL) {
+ inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
+ inet_free_ifa(ifa);
+ }
+
+#ifdef CONFIG_SYSCTL
+ devinet_sysctl_unregister(&in_dev->cnf);
+#endif
+ in_dev->dev->ip_ptr = NULL;
+ synchronize_bh();
+ neigh_parms_release(&arp_tbl, in_dev->arp_parms);
+ kfree(in_dev);
+}
+
+struct in_ifaddr * inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
+{
+ for_primary_ifa(in_dev) {
+ if (inet_ifa_match(a, ifa)) {
+ if (!b || inet_ifa_match(b, ifa))
+ return ifa;
+ }
+ } endfor_ifa(in_dev);
+ return NULL;
+}
+
+static void
+inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
+{
+ struct in_ifaddr *ifa1 = *ifap;
+
+ /* 1. Deleting primary ifaddr forces deletion all secondaries */
+
+ if (!(ifa1->ifa_flags&IFA_F_SECONDARY)) {
+ struct in_ifaddr *ifa;
+ struct in_ifaddr **ifap1 = &ifa1->ifa_next;
+
+ while ((ifa=*ifap1) != NULL) {
+ if (!(ifa->ifa_flags&IFA_F_SECONDARY) ||
+ ifa1->ifa_mask != ifa->ifa_mask ||
+ !inet_ifa_match(ifa1->ifa_address, ifa)) {
+ ifap1 = &ifa->ifa_next;
+ continue;
+ }
+ *ifap1 = ifa->ifa_next;
+ synchronize_bh();
+
+ rtmsg_ifa(RTM_DELADDR, ifa);
+ notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
+ inet_free_ifa(ifa);
+ }
+ }
+
+ /* 2. Unlink it */
+
+ *ifap = ifa1->ifa_next;
+ synchronize_bh();
+
+ /* 3. Announce address deletion */
+
+ /* Send message first, then call notifier.
+ At first sight, FIB update triggered by notifier
+ will refer to already deleted ifaddr, that could confuse
+ netlink listeners. It is not true: look, gated sees
+ that route deleted and if it still thinks that ifaddr
+ is valid, it will try to restore deleted routes... Grr.
+ So that, this order is correct.
+ */
+ rtmsg_ifa(RTM_DELADDR, ifa1);
+ notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
+ if (destroy) {
+ inet_free_ifa(ifa1);
+ if (in_dev->ifa_list == NULL)
+ inetdev_destroy(in_dev);
+ }
+}
+
+static int
+inet_insert_ifa(struct in_device *in_dev, struct in_ifaddr *ifa)
+{
+ struct in_ifaddr *ifa1, **ifap, **last_primary;
+
+ if (ifa->ifa_local == 0) {
+ inet_free_ifa(ifa);
+ return 0;
+ }
+
+ ifa->ifa_flags &= ~IFA_F_SECONDARY;
+ last_primary = &in_dev->ifa_list;
+
+ for (ifap=&in_dev->ifa_list; (ifa1=*ifap)!=NULL; ifap=&ifa1->ifa_next) {
+ if (!(ifa1->ifa_flags&IFA_F_SECONDARY) && ifa->ifa_scope <= ifa1->ifa_scope)
+ last_primary = &ifa1->ifa_next;
+ if (ifa1->ifa_mask == ifa->ifa_mask && inet_ifa_match(ifa1->ifa_address, ifa)) {
+ if (ifa1->ifa_local == ifa->ifa_local) {
+ inet_free_ifa(ifa);
+ return -EEXIST;
+ }
+ if (ifa1->ifa_scope != ifa->ifa_scope) {
+ inet_free_ifa(ifa);
+ return -EINVAL;
+ }
+ ifa->ifa_flags |= IFA_F_SECONDARY;
+ }
+ }
+
+ if (!(ifa->ifa_flags&IFA_F_SECONDARY)) {
+ net_srandom(ifa->ifa_local);
+ ifap = last_primary;
+ }
+
+ ifa->ifa_next = *ifap;
+ wmb();
+ *ifap = ifa;
+
+ /* Send message first, then call notifier.
+ Notifier will trigger FIB update, so that
+ listeners of netlink will know about new ifaddr */
+ rtmsg_ifa(RTM_NEWADDR, ifa);
+ notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
+
+ return 0;
+}
+
+static int
+inet_set_ifa(struct device *dev, struct in_ifaddr *ifa)
+{
+ struct in_device *in_dev = dev->ip_ptr;
+
+ if (in_dev == NULL) {
+ in_dev = inetdev_init(dev);
+ if (in_dev == NULL) {
+ inet_free_ifa(ifa);
+ return -ENOBUFS;
+ }
+ }
+ ifa->ifa_dev = in_dev;
+ if (LOOPBACK(ifa->ifa_local))
+ ifa->ifa_scope = RT_SCOPE_HOST;
+ return inet_insert_ifa(in_dev, ifa);
+}
+
+struct in_device *inetdev_by_index(int ifindex)
+{
+ struct device *dev;
+ dev = dev_get_by_index(ifindex);
+ if (dev)
+ return dev->ip_ptr;
+ return NULL;
+}
+
+struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask)
+{
+ for_primary_ifa(in_dev) {
+ if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
+ return ifa;
+ } endfor_ifa(in_dev);
+ return NULL;
+}
+
+#ifdef CONFIG_RTNETLINK
+
+/* rtm_{add|del} functions are not reenterable, so that
+ this structure can be made static
+ */
+
+int
+inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct in_device *in_dev;
+ struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+ struct in_ifaddr *ifa, **ifap;
+
+ if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
+ return -EADDRNOTAVAIL;
+
+ for (ifap=&in_dev->ifa_list; (ifa=*ifap)!=NULL; ifap=&ifa->ifa_next) {
+ if ((rta[IFA_LOCAL-1] && memcmp(RTA_DATA(rta[IFA_LOCAL-1]), &ifa->ifa_local, 4)) ||
+ (rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)) ||
+ (rta[IFA_ADDRESS-1] &&
+ (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
+ !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS-1]), ifa))))
+ continue;
+ inet_del_ifa(in_dev, ifap, 1);
+ return 0;
+ }
+
+ return -EADDRNOTAVAIL;
+}
+
+int
+inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct device *dev;
+ struct in_device *in_dev;
+ struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+ struct in_ifaddr *ifa;
+
+ if (ifm->ifa_prefixlen > 32 || rta[IFA_LOCAL-1] == NULL)
+ return -EINVAL;
+
+ if ((dev = dev_get_by_index(ifm->ifa_index)) == NULL)
+ return -ENODEV;
+
+ if ((in_dev = dev->ip_ptr) == NULL) {
+ in_dev = inetdev_init(dev);
+ if (!in_dev)
+ return -ENOBUFS;
+ }
+
+ if ((ifa = inet_alloc_ifa()) == NULL)
+ return -ENOBUFS;
+
+ if (rta[IFA_ADDRESS-1] == NULL)
+ rta[IFA_ADDRESS-1] = rta[IFA_LOCAL-1];
+ memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 4);
+ memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-1]), 4);
+ ifa->ifa_prefixlen = ifm->ifa_prefixlen;
+ ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
+ if (rta[IFA_BROADCAST-1])
+ memcpy(&ifa->ifa_broadcast, RTA_DATA(rta[IFA_BROADCAST-1]), 4);
+ if (rta[IFA_ANYCAST-1])
+ memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST-1]), 4);
+ ifa->ifa_flags = ifm->ifa_flags;
+ ifa->ifa_scope = ifm->ifa_scope;
+ ifa->ifa_dev = in_dev;
+ if (rta[IFA_LABEL-1])
+ memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL-1]), IFNAMSIZ);
+ else
+ memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+
+ return inet_insert_ifa(in_dev, ifa);
+}
+
+#endif
+
+/*
+ * Determine a default network mask, based on the IP address.
+ */
+
+static __inline__ int inet_abc_len(u32 addr)
+{
+ if (ZERONET(addr))
+ return 0;
+
+ addr = ntohl(addr);
+ if (IN_CLASSA(addr))
+ return 8;
+ if (IN_CLASSB(addr))
+ return 16;
+ if (IN_CLASSC(addr))
+ return 24;
+
+ /*
+ * Something else, probably a multicast.
+ */
+
+ return -1;
+}
+
+
+#ifdef _HURD_
+
+#define devinet_ioctl 0
+
+error_t
+configure_device (struct device *dev,
+ uint32_t addr, uint32_t netmask, uint32_t peer,
+ uint32_t broadcast)
+{
+ struct in_device *in_dev = dev->ip_ptr;
+ struct in_ifaddr *ifa = in_dev ? in_dev->ifa_list : 0;
+
+ if (ifa)
+ {
+ inet_del_ifa (in_dev, &in_dev->ifa_list, 0);
+ ifa->ifa_broadcast = 0;
+ ifa->ifa_anycast = 0;
+ }
+ else
+ {
+ ifa = inet_alloc_ifa ();
+ if (!ifa)
+ return ENOBUFS;
+ memcpy (ifa->ifa_label, dev->name, IFNAMSIZ);
+
+ ifa->ifa_address = INADDR_NONE;
+ ifa->ifa_mask = INADDR_NONE;
+ ifa->ifa_broadcast = INADDR_NONE;
+ ifa->ifa_local = INADDR_NONE;
+ }
+
+ if (addr != INADDR_NONE)
+ ifa->ifa_address = ifa->ifa_local = addr;
+ if (netmask != INADDR_NONE && !(dev->flags & IFF_POINTOPOINT))
+ {
+ ifa->ifa_mask = netmask;
+ ifa->ifa_prefixlen = inet_mask_len (ifa->ifa_mask);
+ if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)
+ ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask;
+ else
+ ifa->ifa_broadcast = 0;
+ }
+ if (peer != INADDR_NONE && (dev->flags & IFF_POINTOPOINT))
+ {
+ ifa->ifa_prefixlen = 32;
+ ifa->ifa_mask = inet_make_mask(32);
+ ifa->ifa_address = peer;
+ }
+
+ if (broadcast != INADDR_NONE)
+ ifa->ifa_broadcast = broadcast;
+
+ return - (inet_set_ifa (dev, ifa)
+ ?: dev_change_flags (dev, dev->flags | IFF_UP));
+}
+
+void
+inquire_device (struct device *dev,
+ uint32_t *addr, uint32_t *netmask, uint32_t *peer,
+ uint32_t *broadcast)
+{
+ struct in_device *in_dev = dev->ip_ptr;
+ struct in_ifaddr *ifa = in_dev ? in_dev->ifa_list : 0;
+
+ if (ifa)
+ {
+ *addr = ifa->ifa_local;
+ *netmask = ifa->ifa_mask;
+ *peer = ifa->ifa_address;
+ *broadcast = ifa->ifa_broadcast;
+ }
+ else
+ *addr = *netmask = *peer = *broadcast = INADDR_NONE;
+}
+
+#else
+
+int devinet_ioctl(unsigned int cmd, void *arg)
+{
+ struct ifreq ifr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ struct in_device *in_dev;
+ struct in_ifaddr **ifap = NULL;
+ struct in_ifaddr *ifa = NULL;
+ struct device *dev;
+#ifdef CONFIG_IP_ALIAS
+ char *colon;
+#endif
+ int exclusive = 0;
+ int ret = 0;
+
+ /*
+ * Fetch the caller's info block into kernel space
+ */
+
+ if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
+ return -EFAULT;
+ ifr.ifr_name[IFNAMSIZ-1] = 0;
+
+#ifdef CONFIG_IP_ALIAS
+ colon = strchr(ifr.ifr_name, ':');
+ if (colon)
+ *colon = 0;
+#endif
+
+#ifdef CONFIG_KMOD
+ dev_load(ifr.ifr_name);
+#endif
+
+ switch(cmd) {
+ case SIOCGIFADDR: /* Get interface address */
+ case SIOCGIFBRDADDR: /* Get the broadcast address */
+ case SIOCGIFDSTADDR: /* Get the destination address */
+ case SIOCGIFNETMASK: /* Get the netmask for the interface */
+ /* Note that this ioctls will not sleep,
+ so that we do not impose a lock.
+ One day we will be forced to put shlock here (I mean SMP)
+ */
+ memset(sin, 0, sizeof(*sin));
+ sin->sin_family = AF_INET;
+ break;
+
+ case SIOCSIFFLAGS:
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+ rtnl_lock();
+ exclusive = 1;
+ break;
+ case SIOCSIFADDR: /* Set interface address (and family) */
+ case SIOCSIFBRDADDR: /* Set the broadcast address */
+ case SIOCSIFDSTADDR: /* Set the destination address */
+ case SIOCSIFNETMASK: /* Set the netmask for the interface */
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+ if (sin->sin_family != AF_INET)
+ return -EINVAL;
+ rtnl_lock();
+ exclusive = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ if ((dev = dev_get(ifr.ifr_name)) == NULL) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+#ifdef CONFIG_IP_ALIAS
+ if (colon)
+ *colon = ':';
+#endif
+
+ if ((in_dev=dev->ip_ptr) != NULL) {
+ for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
+ if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
+ break;
+ }
+
+ if (ifa == NULL && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) {
+ ret = -EADDRNOTAVAIL;
+ goto done;
+ }
+
+ switch(cmd) {
+ case SIOCGIFADDR: /* Get interface address */
+ sin->sin_addr.s_addr = ifa->ifa_local;
+ goto rarok;
+
+ case SIOCGIFBRDADDR: /* Get the broadcast address */
+ sin->sin_addr.s_addr = ifa->ifa_broadcast;
+ goto rarok;
+
+ case SIOCGIFDSTADDR: /* Get the destination address */
+ sin->sin_addr.s_addr = ifa->ifa_address;
+ goto rarok;
+
+ case SIOCGIFNETMASK: /* Get the netmask for the interface */
+ sin->sin_addr.s_addr = ifa->ifa_mask;
+ goto rarok;
+
+ case SIOCSIFFLAGS:
+#ifdef CONFIG_IP_ALIAS
+ if (colon) {
+ if (ifa == NULL) {
+ ret = -EADDRNOTAVAIL;
+ break;
+ }
+ if (!(ifr.ifr_flags&IFF_UP))
+ inet_del_ifa(in_dev, ifap, 1);
+ break;
+ }
+#endif
+ ret = dev_change_flags(dev, ifr.ifr_flags);
+ break;
+
+ case SIOCSIFADDR: /* Set interface address (and family) */
+ if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!ifa) {
+ if ((ifa = inet_alloc_ifa()) == NULL) {
+ ret = -ENOBUFS;
+ break;
+ }
+#ifdef CONFIG_IP_ALIAS
+ if (colon)
+ memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
+ else
+#endif
+ memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+ } else {
+ ret = 0;
+ if (ifa->ifa_local == sin->sin_addr.s_addr)
+ break;
+ inet_del_ifa(in_dev, ifap, 0);
+ ifa->ifa_broadcast = 0;
+ ifa->ifa_anycast = 0;
+ }
+
+ ifa->ifa_address =
+ ifa->ifa_local = sin->sin_addr.s_addr;
+
+ if (!(dev->flags&IFF_POINTOPOINT)) {
+ ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
+ ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
+ if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)
+ ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask;
+ } else {
+ ifa->ifa_prefixlen = 32;
+ ifa->ifa_mask = inet_make_mask(32);
+ }
+ ret = inet_set_ifa(dev, ifa);
+ break;
+
+ case SIOCSIFBRDADDR: /* Set the broadcast address */
+ if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
+ inet_del_ifa(in_dev, ifap, 0);
+ ifa->ifa_broadcast = sin->sin_addr.s_addr;
+ inet_insert_ifa(in_dev, ifa);
+ }
+ break;
+
+ case SIOCSIFDSTADDR: /* Set the destination address */
+ if (ifa->ifa_address != sin->sin_addr.s_addr) {
+ if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
+ ret = -EINVAL;
+ break;
+ }
+ inet_del_ifa(in_dev, ifap, 0);
+ ifa->ifa_address = sin->sin_addr.s_addr;
+ inet_insert_ifa(in_dev, ifa);
+ }
+ break;
+
+ case SIOCSIFNETMASK: /* Set the netmask for the interface */
+
+ /*
+ * The mask we set must be legal.
+ */
+ if (bad_mask(sin->sin_addr.s_addr, 0)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ifa->ifa_mask != sin->sin_addr.s_addr) {
+ inet_del_ifa(in_dev, ifap, 0);
+ ifa->ifa_mask = sin->sin_addr.s_addr;
+ ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
+ inet_set_ifa(dev, ifa);
+ }
+ break;
+ }
+done:
+ if (exclusive)
+ rtnl_unlock();
+ return ret;
+
+rarok:
+ if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+ return -EFAULT;
+ return 0;
+}
+
+#endif
+
+static int
+inet_gifconf(struct device *dev, char *buf, int len)
+{
+ struct in_device *in_dev = dev->ip_ptr;
+ struct in_ifaddr *ifa;
+ struct ifreq ifr;
+ int done=0;
+
+ if (in_dev==NULL || (ifa=in_dev->ifa_list)==NULL)
+ return 0;
+
+ for ( ; ifa; ifa = ifa->ifa_next) {
+ if (!buf) {
+ done += sizeof(ifr);
+ continue;
+ }
+ if (len < (int) sizeof(ifr))
+ return done;
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (ifa->ifa_label)
+ strcpy(ifr.ifr_name, ifa->ifa_label);
+ else
+ strcpy(ifr.ifr_name, dev->name);
+
+#ifdef _HURD_
+ (*(struct sockaddr_in *) &ifr.ifr_addr).sin_len = sizeof (struct sockaddr_in);
+#endif
+ (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET;
+ (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = ifa->ifa_local;
+
+ if (copy_to_user(buf, &ifr, sizeof(struct ifreq)))
+ return -EFAULT;
+ buf += sizeof(struct ifreq);
+ len -= sizeof(struct ifreq);
+ done += sizeof(struct ifreq);
+ }
+ return done;
+}
+
+u32 inet_select_addr(struct device *dev, u32 dst, int scope)
+{
+ u32 addr = 0;
+ struct in_device *in_dev = dev->ip_ptr;
+
+ if (in_dev == NULL)
+ return 0;
+
+ for_primary_ifa(in_dev) {
+ if (ifa->ifa_scope > scope)
+ continue;
+ if (!dst || inet_ifa_match(dst, ifa))
+ return ifa->ifa_local;
+ if (!addr)
+ addr = ifa->ifa_local;
+ } endfor_ifa(in_dev);
+
+ if (addr)
+ return addr;
+
+ /* Not loopback addresses on loopback should be preferred
+ in this case. It is importnat that lo is the first interface
+ in dev_base list.
+ */
+ for (dev=dev_base; dev; dev=dev->next) {
+ if ((in_dev=dev->ip_ptr) == NULL)
+ continue;
+
+ for_primary_ifa(in_dev) {
+ if (!IN_DEV_HIDDEN(in_dev) &&
+ ifa->ifa_scope <= scope &&
+ ifa->ifa_scope != RT_SCOPE_LINK)
+ return ifa->ifa_local;
+ } endfor_ifa(in_dev);
+ }
+
+ return 0;
+}
+
+/*
+ * Device notifier
+ */
+
+int register_inetaddr_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_register(&inetaddr_chain, nb);
+}
+
+int unregister_inetaddr_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_unregister(&inetaddr_chain,nb);
+}
+
+static int inetdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+ struct in_device *in_dev = dev->ip_ptr;
+
+ if (in_dev == NULL)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_REGISTER:
+ if (in_dev)
+ printk(KERN_DEBUG "inetdev_event: bug\n");
+ dev->ip_ptr = NULL;
+ break;
+ case NETDEV_UP:
+ if (dev == &loopback_dev) {
+ struct in_ifaddr *ifa;
+ if ((ifa = inet_alloc_ifa()) != NULL) {
+ ifa->ifa_local =
+ ifa->ifa_address = htonl(INADDR_LOOPBACK);
+ ifa->ifa_prefixlen = 8;
+ ifa->ifa_mask = inet_make_mask(8);
+ ifa->ifa_dev = in_dev;
+ ifa->ifa_scope = RT_SCOPE_HOST;
+ memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+ inet_insert_ifa(in_dev, ifa);
+ }
+ }
+ ip_mc_up(in_dev);
+ break;
+ case NETDEV_DOWN:
+ ip_mc_down(in_dev);
+ break;
+ case NETDEV_CHANGEMTU:
+ if (dev->mtu >= 68)
+ break;
+ /* MTU falled under minimal IP mtu. Disable IP. */
+ case NETDEV_UNREGISTER:
+ inetdev_destroy(in_dev);
+ break;
+ case NETDEV_CHANGENAME:
+ if (in_dev->ifa_list) {
+ struct in_ifaddr *ifa;
+ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
+ memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+ /* Do not notify about label change, this event is
+ not interesting to applications using netlink.
+ */
+ }
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block ip_netdev_notifier={
+ inetdev_event,
+ NULL,
+ 0
+};
+
+#ifdef CONFIG_RTNETLINK
+
+static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
+ u32 pid, u32 seq, int event)
+{
+ struct ifaddrmsg *ifm;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
+ ifm = NLMSG_DATA(nlh);
+ ifm->ifa_family = AF_INET;
+ ifm->ifa_prefixlen = ifa->ifa_prefixlen;
+ ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;
+ ifm->ifa_scope = ifa->ifa_scope;
+ ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
+ if (ifa->ifa_address)
+ RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address);
+ if (ifa->ifa_local)
+ RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local);
+ if (ifa->ifa_broadcast)
+ RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast);
+ if (ifa->ifa_anycast)
+ RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast);
+ if (ifa->ifa_label[0])
+ RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx, ip_idx;
+ int s_idx, s_ip_idx;
+ struct device *dev;
+ struct in_device *in_dev;
+ struct in_ifaddr *ifa;
+
+ s_idx = cb->args[0];
+ s_ip_idx = ip_idx = cb->args[1];
+ for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+ if (idx < s_idx)
+ continue;
+ if (idx > s_idx)
+ s_ip_idx = 0;
+ if ((in_dev = dev->ip_ptr) == NULL)
+ continue;
+ for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
+ ifa = ifa->ifa_next, ip_idx++) {
+ if (ip_idx < s_ip_idx)
+ continue;
+ if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0)
+ goto done;
+ }
+ }
+done:
+ cb->args[0] = idx;
+ cb->args[1] = ip_idx;
+
+ return skb->len;
+}
+
+static void rtmsg_ifa(int event, struct in_ifaddr * ifa)
+{
+ struct sk_buff *skb;
+ int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128);
+
+ skb = alloc_skb(size, GFP_KERNEL);
+ if (!skb) {
+ netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS);
+ return;
+ }
+ if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
+ kfree_skb(skb);
+ netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL);
+ return;
+ }
+ NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_IFADDR;
+ netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV4_IFADDR, GFP_KERNEL);
+}
+
+
+static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
+{
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+
+ { inet_rtm_newaddr, NULL, },
+ { inet_rtm_deladdr, NULL, },
+ { NULL, inet_dump_ifaddr, },
+ { NULL, NULL, },
+
+ { inet_rtm_newroute, NULL, },
+ { inet_rtm_delroute, NULL, },
+ { inet_rtm_getroute, inet_dump_fib, },
+ { NULL, NULL, },
+
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ { inet_rtm_newrule, NULL, },
+ { inet_rtm_delrule, NULL, },
+ { NULL, inet_dump_rules, },
+ { NULL, NULL, },
+#else
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+#endif
+};
+
+#endif /* CONFIG_RTNETLINK */
+
+
+#ifdef CONFIG_SYSCTL
+
+void inet_forward_change()
+{
+ struct device *dev;
+ int on = ipv4_devconf.forwarding;
+
+ ipv4_devconf.accept_redirects = !on;
+ ipv4_devconf_dflt.forwarding = on;
+
+ for (dev = dev_base; dev; dev = dev->next) {
+ struct in_device *in_dev = dev->ip_ptr;
+ if (in_dev)
+ in_dev->cnf.forwarding = on;
+ }
+
+ rt_cache_flush(0);
+
+ ip_statistics.IpForwarding = on ? 1 : 2;
+}
+
+static
+int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp)
+{
+ int *valp = ctl->data;
+ int val = *valp;
+ int ret;
+
+ ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+ if (write && *valp != val) {
+ if (valp == &ipv4_devconf.forwarding)
+ inet_forward_change();
+ else if (valp != &ipv4_devconf_dflt.forwarding)
+ rt_cache_flush(0);
+ }
+
+ return ret;
+}
+
+static struct devinet_sysctl_table
+{
+ struct ctl_table_header *sysctl_header;
+ ctl_table devinet_vars[13];
+ ctl_table devinet_dev[2];
+ ctl_table devinet_conf_dir[2];
+ ctl_table devinet_proto_dir[2];
+ ctl_table devinet_root_dir[2];
+} devinet_sysctl = {
+ NULL,
+ {{NET_IPV4_CONF_FORWARDING, "forwarding",
+ &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
+ &devinet_sysctl_forward},
+ {NET_IPV4_CONF_MC_FORWARDING, "mc_forwarding",
+ &ipv4_devconf.mc_forwarding, sizeof(int), 0444, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_ACCEPT_REDIRECTS, "accept_redirects",
+ &ipv4_devconf.accept_redirects, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_SECURE_REDIRECTS, "secure_redirects",
+ &ipv4_devconf.secure_redirects, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_SHARED_MEDIA, "shared_media",
+ &ipv4_devconf.shared_media, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_RP_FILTER, "rp_filter",
+ &ipv4_devconf.rp_filter, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_SEND_REDIRECTS, "send_redirects",
+ &ipv4_devconf.send_redirects, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, "accept_source_route",
+ &ipv4_devconf.accept_source_route, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_PROXY_ARP, "proxy_arp",
+ &ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay",
+ &ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_LOG_MARTIANS, "log_martians",
+ &ipv4_devconf.log_martians, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_CONF_HIDDEN, "hidden",
+ &ipv4_devconf.hidden, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {0}},
+
+ {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
+ {{NET_IPV4_CONF, "conf", NULL, 0, 0555, devinet_sysctl.devinet_dev},{0}},
+ {{NET_IPV4, "ipv4", NULL, 0, 0555, devinet_sysctl.devinet_conf_dir},{0}},
+ {{CTL_NET, "net", NULL, 0, 0555, devinet_sysctl.devinet_proto_dir},{0}}
+};
+
+static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p)
+{
+ int i;
+ struct device *dev = in_dev ? in_dev->dev : NULL;
+ struct devinet_sysctl_table *t;
+
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return;
+ memcpy(t, &devinet_sysctl, sizeof(*t));
+ for (i=0; i<sizeof(t->devinet_vars)/sizeof(t->devinet_vars[0])-1; i++) {
+ t->devinet_vars[i].data += (char*)p - (char*)&ipv4_devconf;
+ t->devinet_vars[i].de = NULL;
+ }
+ if (dev) {
+ t->devinet_dev[0].procname = dev->name;
+ t->devinet_dev[0].ctl_name = dev->ifindex;
+ } else {
+ t->devinet_dev[0].procname = "default";
+ t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
+ }
+ t->devinet_dev[0].child = t->devinet_vars;
+ t->devinet_dev[0].de = NULL;
+ t->devinet_conf_dir[0].child = t->devinet_dev;
+ t->devinet_conf_dir[0].de = NULL;
+ t->devinet_proto_dir[0].child = t->devinet_conf_dir;
+ t->devinet_proto_dir[0].de = NULL;
+ t->devinet_root_dir[0].child = t->devinet_proto_dir;
+ t->devinet_root_dir[0].de = NULL;
+
+ t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0);
+ if (t->sysctl_header == NULL)
+ kfree(t);
+ else
+ p->sysctl = t;
+}
+
+static void devinet_sysctl_unregister(struct ipv4_devconf *p)
+{
+ if (p->sysctl) {
+ struct devinet_sysctl_table *t = p->sysctl;
+ p->sysctl = NULL;
+ unregister_sysctl_table(t->sysctl_header);
+ kfree(t);
+ }
+}
+#endif
+
+__initfunc(void devinet_init(void))
+{
+ register_gifconf(PF_INET, inet_gifconf);
+ register_netdevice_notifier(&ip_netdev_notifier);
+#ifdef CONFIG_RTNETLINK
+ rtnetlink_links[PF_INET] = inet_rtnetlink_table;
+#endif
+#ifdef CONFIG_SYSCTL
+ devinet_sysctl.sysctl_header =
+ register_sysctl_table(devinet_sysctl.devinet_root_dir, 0);
+ devinet_sysctl_register(NULL, &ipv4_devconf_dflt);
+#endif
+}
diff --git a/pfinet/linux-src/net/ipv4/fib_frontend.c b/pfinet/linux-src/net/ipv4/fib_frontend.c
new file mode 100644
index 00000000..a1747048
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/fib_frontend.c
@@ -0,0 +1,628 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IPv4 Forwarding Information Base: FIB frontend.
+ *
+ * Version: $Id: fib_frontend.c,v 1.15 1999/03/21 05:22:31 davem Exp $
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/init.h>
+
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/arp.h>
+#include <net/ip_fib.h>
+
+#define FFprint(a...) printk(KERN_DEBUG a)
+
+#ifndef CONFIG_IP_MULTIPLE_TABLES
+
+#define RT_TABLE_MIN RT_TABLE_MAIN
+
+struct fib_table *local_table;
+struct fib_table *main_table;
+
+#else
+
+#define RT_TABLE_MIN 1
+
+struct fib_table *fib_tables[RT_TABLE_MAX+1];
+
+struct fib_table *__fib_new_table(int id)
+{
+ struct fib_table *tb;
+
+ tb = fib_hash_init(id);
+ if (!tb)
+ return NULL;
+ fib_tables[id] = tb;
+ return tb;
+}
+
+
+#endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+
+void fib_flush(void)
+{
+ int flushed = 0;
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ struct fib_table *tb;
+ int id;
+
+ for (id = RT_TABLE_MAX; id>0; id--) {
+ if ((tb = fib_get_table(id))==NULL)
+ continue;
+ flushed += tb->tb_flush(tb);
+ }
+#else /* CONFIG_IP_MULTIPLE_TABLES */
+ flushed += main_table->tb_flush(main_table);
+ flushed += local_table->tb_flush(local_table);
+#endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+ if (flushed)
+ rt_cache_flush(-1);
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Called from the PROCfs module. This outputs /proc/net/route.
+ *
+ * It always works in backward compatibility mode.
+ * The format of the file is not supposed to be changed.
+ */
+
+static int
+fib_get_procinfo(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int first = offset/128;
+ char *ptr = buffer;
+ int count = (length+127)/128;
+ int len;
+
+ *start = buffer + offset%128;
+
+ if (--first < 0) {
+ sprintf(buffer, "%-127s\n", "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
+ --count;
+ ptr += 128;
+ first = 0;
+ }
+
+ /* rtnl_shlock(); -- it is pointless at the moment --ANK */
+ if (main_table && count > 0) {
+ int n = main_table->tb_get_info(main_table, ptr, first, count);
+ count -= n;
+ ptr += n*128;
+ }
+ /* rtnl_shunlock(); */
+ len = ptr - *start;
+ if (len >= length)
+ return length;
+ if (len >= 0)
+ return len;
+ return 0;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * Find the first device with a given source address.
+ */
+
+struct device * ip_dev_find(u32 addr)
+{
+ struct rt_key key;
+ struct fib_result res;
+
+ memset(&key, 0, sizeof(key));
+ key.dst = addr;
+
+ if (!local_table || local_table->tb_lookup(local_table, &key, &res)
+ || res.type != RTN_LOCAL)
+ return NULL;
+
+ return FIB_RES_DEV(res);
+}
+
+unsigned inet_addr_type(u32 addr)
+{
+ struct rt_key key;
+ struct fib_result res;
+
+ if (ZERONET(addr) || BADCLASS(addr))
+ return RTN_BROADCAST;
+ if (MULTICAST(addr))
+ return RTN_MULTICAST;
+
+ memset(&key, 0, sizeof(key));
+ key.dst = addr;
+
+ if (local_table) {
+ if (local_table->tb_lookup(local_table, &key, &res) == 0)
+ return res.type;
+ return RTN_UNICAST;
+ }
+ return RTN_BROADCAST;
+}
+
+/* Given (packet source, input interface) and optional (dst, oif, tos):
+ - (main) check, that source is valid i.e. not broadcast or our local
+ address.
+ - figure out what "logical" interface this packet arrived
+ and calculate "specific destination" address.
+ - check, that packet arrived from expected physical interface.
+ */
+
+int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
+ struct device *dev, u32 *spec_dst, u32 *itag)
+{
+ struct in_device *in_dev = dev->ip_ptr;
+ struct rt_key key;
+ struct fib_result res;
+
+ key.dst = src;
+ key.src = dst;
+ key.tos = tos;
+ key.oif = 0;
+ key.iif = oif;
+ key.scope = RT_SCOPE_UNIVERSE;
+
+ if (in_dev == NULL)
+ return -EINVAL;
+ if (fib_lookup(&key, &res))
+ goto last_resort;
+ if (res.type != RTN_UNICAST)
+ return -EINVAL;
+ *spec_dst = FIB_RES_PREFSRC(res);
+ if (itag)
+ fib_combine_itag(itag, &res);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
+#else
+ if (FIB_RES_DEV(res) == dev)
+#endif
+ return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
+
+ if (in_dev->ifa_list == NULL)
+ goto last_resort;
+ if (IN_DEV_RPFILTER(in_dev))
+ return -EINVAL;
+ key.oif = dev->ifindex;
+ if (fib_lookup(&key, &res) == 0 && res.type == RTN_UNICAST) {
+ *spec_dst = FIB_RES_PREFSRC(res);
+ return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
+ }
+ return 0;
+
+last_resort:
+ if (IN_DEV_RPFILTER(in_dev))
+ return -EINVAL;
+ *spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
+ *itag = 0;
+ return 0;
+}
+
+#ifndef CONFIG_IP_NOSIOCRT
+
+/*
+ * Handle IP routing ioctl calls. These are used to manipulate the routing tables
+ */
+
+int ip_rt_ioctl(unsigned int cmd, void *arg)
+{
+ int err;
+ struct kern_rta rta;
+ struct rtentry r;
+ struct {
+ struct nlmsghdr nlh;
+ struct rtmsg rtm;
+ } req;
+
+ switch (cmd) {
+ case SIOCADDRT: /* Add a route */
+ case SIOCDELRT: /* Delete a route */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&r, arg, sizeof(struct rtentry)))
+ return -EFAULT;
+ rtnl_lock();
+ err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r);
+ if (err == 0) {
+ if (cmd == SIOCDELRT) {
+ struct fib_table *tb = fib_get_table(req.rtm.rtm_table);
+ err = -ESRCH;
+ if (tb)
+ err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
+ } else {
+ struct fib_table *tb = fib_new_table(req.rtm.rtm_table);
+ err = -ENOBUFS;
+ if (tb)
+ err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
+ }
+ if (rta.rta_mx)
+ kfree(rta.rta_mx);
+ }
+ rtnl_unlock();
+ return err;
+ }
+ return -EINVAL;
+}
+
+#else
+
+int ip_rt_ioctl(unsigned int cmd, void *arg)
+{
+ return -EINVAL;
+}
+
+#endif
+
+#ifdef CONFIG_RTNETLINK
+
+static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
+{
+ int i;
+
+ for (i=1; i<=RTA_MAX; i++) {
+ struct rtattr *attr = rta[i-1];
+ if (attr) {
+ if (RTA_PAYLOAD(attr) < 4)
+ return -EINVAL;
+ if (i != RTA_MULTIPATH && i != RTA_METRICS)
+ rta[i-1] = (struct rtattr*)RTA_DATA(attr);
+ }
+ }
+ return 0;
+}
+
+int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct fib_table * tb;
+ struct rtattr **rta = arg;
+ struct rtmsg *r = NLMSG_DATA(nlh);
+
+ if (inet_check_attr(r, rta))
+ return -EINVAL;
+
+ tb = fib_get_table(r->rtm_table);
+ if (tb)
+ return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
+ return -ESRCH;
+}
+
+int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct fib_table * tb;
+ struct rtattr **rta = arg;
+ struct rtmsg *r = NLMSG_DATA(nlh);
+
+ if (inet_check_attr(r, rta))
+ return -EINVAL;
+
+ tb = fib_new_table(r->rtm_table);
+ if (tb)
+ return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb));
+ return -ENOBUFS;
+}
+
+int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int t;
+ int s_t;
+ struct fib_table *tb;
+
+ if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
+ ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
+ return ip_rt_dump(skb, cb);
+
+ s_t = cb->args[0];
+ if (s_t == 0)
+ s_t = cb->args[0] = RT_TABLE_MIN;
+
+ for (t=s_t; t<=RT_TABLE_MAX; t++) {
+ if (t < s_t) continue;
+ if (t > s_t)
+ memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
+ if ((tb = fib_get_table(t))==NULL)
+ continue;
+ if (tb->tb_dump(tb, skb, cb) < 0)
+ break;
+ }
+
+ cb->args[0] = t;
+
+ return skb->len;
+}
+
+#endif
+
+/* Prepare and feed intra-kernel routing request.
+ Really, it should be netlink message, but :-( netlink
+ can be not configured, so that we feed it directly
+ to fib engine. It is legal, because all events occur
+ only when netlink is already locked.
+ */
+
+static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa)
+{
+ struct fib_table * tb;
+ struct {
+ struct nlmsghdr nlh;
+ struct rtmsg rtm;
+ } req;
+ struct kern_rta rta;
+
+ memset(&req.rtm, 0, sizeof(req.rtm));
+ memset(&rta, 0, sizeof(rta));
+
+ if (type == RTN_UNICAST)
+ tb = fib_new_table(RT_TABLE_MAIN);
+ else
+ tb = fib_new_table(RT_TABLE_LOCAL);
+
+ if (tb == NULL)
+ return;
+
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = cmd;
+ req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = 0;
+
+ req.rtm.rtm_dst_len = dst_len;
+ req.rtm.rtm_table = tb->tb_id;
+ req.rtm.rtm_protocol = RTPROT_KERNEL;
+ req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
+ req.rtm.rtm_type = type;
+
+ rta.rta_dst = &dst;
+ rta.rta_prefsrc = &ifa->ifa_local;
+ rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
+
+ if (cmd == RTM_NEWROUTE)
+ tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
+ else
+ tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
+}
+
+static void fib_add_ifaddr(struct in_ifaddr *ifa)
+{
+ struct in_device *in_dev = ifa->ifa_dev;
+ struct device *dev = in_dev->dev;
+ struct in_ifaddr *prim = ifa;
+ u32 mask = ifa->ifa_mask;
+ u32 addr = ifa->ifa_local;
+ u32 prefix = ifa->ifa_address&mask;
+
+ if (ifa->ifa_flags&IFA_F_SECONDARY) {
+ prim = inet_ifa_byprefix(in_dev, prefix, mask);
+ if (prim == NULL) {
+ printk(KERN_DEBUG "fib_add_ifaddr: bug: prim == NULL\n");
+ return;
+ }
+ }
+
+ fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
+
+ if (!(dev->flags&IFF_UP))
+ return;
+
+ /* Add broadcast address, if it is explicitly assigned. */
+ if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
+ fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
+
+ if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
+ (prefix != addr || ifa->ifa_prefixlen < 32)) {
+ fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
+ RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
+
+ /* Add network specific broadcasts, when it takes a sense */
+ if (ifa->ifa_prefixlen < 31) {
+ fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
+ fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
+ }
+ }
+}
+
+static void fib_del_ifaddr(struct in_ifaddr *ifa)
+{
+ struct in_device *in_dev = ifa->ifa_dev;
+ struct device *dev = in_dev->dev;
+ struct in_ifaddr *ifa1;
+ struct in_ifaddr *prim = ifa;
+ u32 brd = ifa->ifa_address|~ifa->ifa_mask;
+ u32 any = ifa->ifa_address&ifa->ifa_mask;
+#define LOCAL_OK 1
+#define BRD_OK 2
+#define BRD0_OK 4
+#define BRD1_OK 8
+ unsigned ok = 0;
+
+ if (!(ifa->ifa_flags&IFA_F_SECONDARY))
+ fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
+ RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
+ else {
+ prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
+ if (prim == NULL) {
+ printk(KERN_DEBUG "fib_del_ifaddr: bug: prim == NULL\n");
+ return;
+ }
+ }
+
+ /* Deletion is more complicated than add.
+ We should take care of not to delete too much :-)
+
+ Scan address list to be sure that addresses are really gone.
+ */
+
+ for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
+ if (ifa->ifa_local == ifa1->ifa_local)
+ ok |= LOCAL_OK;
+ if (ifa->ifa_broadcast == ifa1->ifa_broadcast)
+ ok |= BRD_OK;
+ if (brd == ifa1->ifa_broadcast)
+ ok |= BRD1_OK;
+ if (any == ifa1->ifa_broadcast)
+ ok |= BRD0_OK;
+ }
+
+ if (!(ok&BRD_OK))
+ fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
+ if (!(ok&BRD1_OK))
+ fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
+ if (!(ok&BRD0_OK))
+ fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
+ if (!(ok&LOCAL_OK)) {
+ fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
+
+ /* Check, that this local address finally disappeared. */
+ if (inet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
+ /* And the last, but not the least thing.
+ We must flush stray FIB entries.
+
+ First of all, we scan fib_info list searching
+ for stray nexthop entries, then ignite fib_flush.
+ */
+ if (fib_sync_down(ifa->ifa_local, NULL, 0))
+ fib_flush();
+ }
+ }
+#undef LOCAL_OK
+#undef BRD_OK
+#undef BRD0_OK
+#undef BRD1_OK
+}
+
+static void fib_disable_ip(struct device *dev, int force)
+{
+ if (fib_sync_down(0, dev, force))
+ fib_flush();
+ rt_cache_flush(0);
+ arp_ifdown(dev);
+}
+
+static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr*)ptr;
+
+ switch (event) {
+ case NETDEV_UP:
+ fib_add_ifaddr(ifa);
+ rt_cache_flush(-1);
+ break;
+ case NETDEV_DOWN:
+ if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
+ /* Last address was deleted from this interface.
+ Disable IP.
+ */
+ fib_disable_ip(ifa->ifa_dev->dev, 1);
+ } else {
+ fib_del_ifaddr(ifa);
+ rt_cache_flush(-1);
+ }
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+ struct in_device *in_dev = dev->ip_ptr;
+
+ if (!in_dev)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_UP:
+ for_ifa(in_dev) {
+ fib_add_ifaddr(ifa);
+ } endfor_ifa(in_dev);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(dev);
+#endif
+ rt_cache_flush(-1);
+ break;
+ case NETDEV_DOWN:
+ fib_disable_ip(dev, 0);
+ break;
+ case NETDEV_UNREGISTER:
+ fib_disable_ip(dev, 1);
+ break;
+ case NETDEV_CHANGEMTU:
+ case NETDEV_CHANGE:
+ rt_cache_flush(0);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+struct notifier_block fib_inetaddr_notifier = {
+ fib_inetaddr_event,
+ NULL,
+ 0
+};
+
+struct notifier_block fib_netdev_notifier = {
+ fib_netdev_event,
+ NULL,
+ 0
+};
+
+__initfunc(void ip_fib_init(void))
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&(struct proc_dir_entry) {
+ PROC_NET_ROUTE, 5, "route",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ fib_get_procinfo
+ });
+#endif /* CONFIG_PROC_FS */
+
+#ifndef CONFIG_IP_MULTIPLE_TABLES
+ local_table = fib_hash_init(RT_TABLE_LOCAL);
+ main_table = fib_hash_init(RT_TABLE_MAIN);
+#else
+ fib_rules_init();
+#endif
+
+ register_netdevice_notifier(&fib_netdev_notifier);
+ register_inetaddr_notifier(&fib_inetaddr_notifier);
+}
+
diff --git a/pfinet/linux-src/net/ipv4/fib_hash.c b/pfinet/linux-src/net/ipv4/fib_hash.c
new file mode 100644
index 00000000..d9e029ce
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/fib_hash.c
@@ -0,0 +1,885 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IPv4 FIB: lookup engine and maintenance routines.
+ *
+ * Version: $Id: fib_hash.c,v 1.8 1999/03/25 10:04:17 davem Exp $
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/init.h>
+
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/sock.h>
+#include <net/ip_fib.h>
+
+#define FTprint(a...)
+/*
+ printk(KERN_DEBUG a)
+ */
+
+/*
+ These bizarre types are just to force strict type checking.
+ When I reversed order of bytes and changed to natural mask lengths,
+ I forgot to make fixes in several places. Now I am lazy to return
+ it back.
+ */
+
+typedef struct {
+ u32 datum;
+} fn_key_t;
+
+typedef struct {
+ u32 datum;
+} fn_hash_idx_t;
+
+struct fib_node
+{
+ struct fib_node *fn_next;
+ struct fib_info *fn_info;
+#define FIB_INFO(f) ((f)->fn_info)
+ fn_key_t fn_key;
+ u8 fn_tos;
+ u8 fn_type;
+ u8 fn_scope;
+ u8 fn_state;
+};
+
+#define FN_S_ZOMBIE 1
+#define FN_S_ACCESSED 2
+
+static int fib_hash_zombies;
+
+struct fn_zone
+{
+ struct fn_zone *fz_next; /* Next not empty zone */
+ struct fib_node **fz_hash; /* Hash table pointer */
+ int fz_nent; /* Number of entries */
+
+ int fz_divisor; /* Hash divisor */
+ u32 fz_hashmask; /* (1<<fz_divisor) - 1 */
+#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
+
+ int fz_order; /* Zone order */
+ u32 fz_mask;
+#define FZ_MASK(fz) ((fz)->fz_mask)
+};
+
+/* NOTE. On fast computers evaluation of fz_hashmask and fz_mask
+ can be cheaper than memory lookup, so that FZ_* macros are used.
+ */
+
+struct fn_hash
+{
+ struct fn_zone *fn_zones[33];
+ struct fn_zone *fn_zone_list;
+};
+
+static __inline__ fn_hash_idx_t fn_hash(fn_key_t key, struct fn_zone *fz)
+{
+ u32 h = ntohl(key.datum)>>(32 - fz->fz_order);
+ h ^= (h>>20);
+ h ^= (h>>10);
+ h ^= (h>>5);
+ h &= FZ_HASHMASK(fz);
+ return *(fn_hash_idx_t*)&h;
+}
+
+#define fz_key_0(key) ((key).datum = 0)
+#define fz_prefix(key,fz) ((key).datum)
+
+static __inline__ fn_key_t fz_key(u32 dst, struct fn_zone *fz)
+{
+ fn_key_t k;
+ k.datum = dst & FZ_MASK(fz);
+ return k;
+}
+
+static __inline__ struct fib_node ** fz_chain_p(fn_key_t key, struct fn_zone *fz)
+{
+ return &fz->fz_hash[fn_hash(key, fz).datum];
+}
+
+static __inline__ struct fib_node * fz_chain(fn_key_t key, struct fn_zone *fz)
+{
+ return fz->fz_hash[fn_hash(key, fz).datum];
+}
+
+extern __inline__ int fn_key_eq(fn_key_t a, fn_key_t b)
+{
+ return a.datum == b.datum;
+}
+
+extern __inline__ int fn_key_leq(fn_key_t a, fn_key_t b)
+{
+ return a.datum <= b.datum;
+}
+
+#define FZ_MAX_DIVISOR 1024
+
+#ifdef CONFIG_IP_ROUTE_LARGE_TABLES
+
+static __inline__ void fn_rebuild_zone(struct fn_zone *fz,
+ struct fib_node **old_ht,
+ int old_divisor)
+{
+ int i;
+ struct fib_node *f, **fp, *next;
+
+ for (i=0; i<old_divisor; i++) {
+ for (f=old_ht[i]; f; f=next) {
+ next = f->fn_next;
+ for (fp = fz_chain_p(f->fn_key, fz);
+ *fp && fn_key_leq((*fp)->fn_key, f->fn_key);
+ fp = &(*fp)->fn_next)
+ /* NONE */;
+ f->fn_next = *fp;
+ *fp = f;
+ }
+ }
+}
+
+static void fn_rehash_zone(struct fn_zone *fz)
+{
+ struct fib_node **ht, **old_ht;
+ int old_divisor, new_divisor;
+ u32 new_hashmask;
+
+ old_divisor = fz->fz_divisor;
+
+ switch (old_divisor) {
+ case 16:
+ new_divisor = 256;
+ new_hashmask = 0xFF;
+ break;
+ case 256:
+ new_divisor = 1024;
+ new_hashmask = 0x3FF;
+ break;
+ default:
+ printk(KERN_CRIT "route.c: bad divisor %d!\n", old_divisor);
+ return;
+ }
+#if RT_CACHE_DEBUG >= 2
+ printk("fn_rehash_zone: hash for zone %d grows from %d\n", fz->fz_order, old_divisor);
+#endif
+
+ ht = kmalloc(new_divisor*sizeof(struct fib_node*), GFP_KERNEL);
+
+ if (ht) {
+ memset(ht, 0, new_divisor*sizeof(struct fib_node*));
+ start_bh_atomic();
+ old_ht = fz->fz_hash;
+ fz->fz_hash = ht;
+ fz->fz_hashmask = new_hashmask;
+ fz->fz_divisor = new_divisor;
+ fn_rebuild_zone(fz, old_ht, old_divisor);
+ end_bh_atomic();
+ kfree(old_ht);
+ }
+}
+#endif /* CONFIG_IP_ROUTE_LARGE_TABLES */
+
+static void fn_free_node(struct fib_node * f)
+{
+ fib_release_info(FIB_INFO(f));
+ kfree_s(f, sizeof(struct fib_node));
+}
+
+
+static struct fn_zone *
+fn_new_zone(struct fn_hash *table, int z)
+{
+ int i;
+ struct fn_zone *fz = kmalloc(sizeof(struct fn_zone), GFP_KERNEL);
+ if (!fz)
+ return NULL;
+
+ memset(fz, 0, sizeof(struct fn_zone));
+ if (z) {
+ fz->fz_divisor = 16;
+ fz->fz_hashmask = 0xF;
+ } else {
+ fz->fz_divisor = 1;
+ fz->fz_hashmask = 0;
+ }
+ fz->fz_hash = kmalloc(fz->fz_divisor*sizeof(struct fib_node*), GFP_KERNEL);
+ if (!fz->fz_hash) {
+ kfree(fz);
+ return NULL;
+ }
+ memset(fz->fz_hash, 0, fz->fz_divisor*sizeof(struct fib_node*));
+ fz->fz_order = z;
+ fz->fz_mask = inet_make_mask(z);
+
+ /* Find the first not empty zone with more specific mask */
+ for (i=z+1; i<=32; i++)
+ if (table->fn_zones[i])
+ break;
+ if (i>32) {
+ /* No more specific masks, we are the first. */
+ fz->fz_next = table->fn_zone_list;
+ table->fn_zone_list = fz;
+ } else {
+ fz->fz_next = table->fn_zones[i]->fz_next;
+ table->fn_zones[i]->fz_next = fz;
+ }
+ table->fn_zones[z] = fz;
+ return fz;
+}
+
+static int
+fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
+{
+ int err;
+ struct fn_zone *fz;
+ struct fn_hash *t = (struct fn_hash*)tb->tb_data;
+
+ for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
+ struct fib_node *f;
+ fn_key_t k = fz_key(key->dst, fz);
+
+ for (f = fz_chain(k, fz); f; f = f->fn_next) {
+ if (!fn_key_eq(k, f->fn_key)) {
+ if (fn_key_leq(k, f->fn_key))
+ break;
+ else
+ continue;
+ }
+#ifdef CONFIG_IP_ROUTE_TOS
+ if (f->fn_tos && f->fn_tos != key->tos)
+ continue;
+#endif
+ f->fn_state |= FN_S_ACCESSED;
+
+ if (f->fn_state&FN_S_ZOMBIE)
+ continue;
+ if (f->fn_scope < key->scope)
+ continue;
+
+ err = fib_semantic_match(f->fn_type, FIB_INFO(f), key, res);
+ if (err == 0) {
+ res->type = f->fn_type;
+ res->scope = f->fn_scope;
+ res->prefixlen = fz->fz_order;
+ res->prefix = &fz_prefix(f->fn_key, fz);
+ return 0;
+ }
+ if (err < 0)
+ return err;
+ }
+ }
+ return 1;
+}
+
+static int fn_hash_last_dflt=-1;
+
+static int fib_detect_death(struct fib_info *fi, int order,
+ struct fib_info **last_resort, int *last_idx)
+{
+ struct neighbour *n;
+ int state = NUD_NONE;
+
+ n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
+ if (n) {
+ state = n->nud_state;
+ neigh_release(n);
+ }
+ if (state==NUD_REACHABLE)
+ return 0;
+ if ((state&NUD_VALID) && order != fn_hash_last_dflt)
+ return 0;
+ if ((state&NUD_VALID) ||
+ (*last_idx<0 && order > fn_hash_last_dflt)) {
+ *last_resort = fi;
+ *last_idx = order;
+ }
+ return 1;
+}
+
+static void
+fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
+{
+ int order, last_idx;
+ struct fib_node *f;
+ struct fib_info *fi = NULL;
+ struct fib_info *last_resort;
+ struct fn_hash *t = (struct fn_hash*)tb->tb_data;
+ struct fn_zone *fz = t->fn_zones[0];
+
+ if (fz == NULL)
+ return;
+
+ last_idx = -1;
+ last_resort = NULL;
+ order = -1;
+
+ for (f = fz->fz_hash[0]; f; f = f->fn_next) {
+ struct fib_info *next_fi = FIB_INFO(f);
+
+ if ((f->fn_state&FN_S_ZOMBIE) ||
+ f->fn_scope != res->scope ||
+ f->fn_type != RTN_UNICAST)
+ continue;
+
+ if (next_fi->fib_priority > res->fi->fib_priority)
+ break;
+ if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
+ continue;
+ f->fn_state |= FN_S_ACCESSED;
+
+ if (fi == NULL) {
+ if (next_fi != res->fi)
+ break;
+ } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
+ res->fi = fi;
+ fn_hash_last_dflt = order;
+ return;
+ }
+ fi = next_fi;
+ order++;
+ }
+
+ if (order<=0 || fi==NULL) {
+ fn_hash_last_dflt = -1;
+ return;
+ }
+
+ if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
+ res->fi = fi;
+ fn_hash_last_dflt = order;
+ return;
+ }
+
+ if (last_idx >= 0)
+ res->fi = last_resort;
+ fn_hash_last_dflt = last_idx;
+}
+
+#define FIB_SCAN(f, fp) \
+for ( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
+
+#define FIB_SCAN_KEY(f, fp, key) \
+for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
+
+#ifndef CONFIG_IP_ROUTE_TOS
+#define FIB_SCAN_TOS(f, fp, key, tos) FIB_SCAN_KEY(f, fp, key)
+#else
+#define FIB_SCAN_TOS(f, fp, key, tos) \
+for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)) && \
+ (f)->fn_tos == (tos) ; (fp) = &(f)->fn_next)
+#endif
+
+
+#ifdef CONFIG_RTNETLINK
+static void rtmsg_fib(int, struct fib_node*, int, int,
+ struct nlmsghdr *n,
+ struct netlink_skb_parms *);
+#else
+#define rtmsg_fib(a, b, c, d, e, f)
+#endif
+
+
+static int
+fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
+ struct nlmsghdr *n, struct netlink_skb_parms *req)
+{
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+ struct fib_node *new_f, *f, **fp, **del_fp;
+ struct fn_zone *fz;
+ struct fib_info *fi;
+
+ int z = r->rtm_dst_len;
+ int type = r->rtm_type;
+#ifdef CONFIG_IP_ROUTE_TOS
+ u8 tos = r->rtm_tos;
+#endif
+ fn_key_t key;
+ int err;
+
+FTprint("tb(%d)_insert: %d %08x/%d %d %08x\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
+*(u32*)rta->rta_dst : 0, z, rta->rta_oif ? *rta->rta_oif : -1,
+rta->rta_prefsrc ? *(u32*)rta->rta_prefsrc : 0);
+ if (z > 32)
+ return -EINVAL;
+ fz = table->fn_zones[z];
+ if (!fz && !(fz = fn_new_zone(table, z)))
+ return -ENOBUFS;
+
+ fz_key_0(key);
+ if (rta->rta_dst) {
+ u32 dst;
+ memcpy(&dst, rta->rta_dst, 4);
+ if (dst & ~FZ_MASK(fz))
+ return -EINVAL;
+ key = fz_key(dst, fz);
+ }
+
+ if ((fi = fib_create_info(r, rta, n, &err)) == NULL)
+ return err;
+
+#ifdef CONFIG_IP_ROUTE_LARGE_TABLES
+ if (fz->fz_nent > (fz->fz_divisor<<2) &&
+ fz->fz_divisor < FZ_MAX_DIVISOR &&
+ (z==32 || (1<<z) > fz->fz_divisor))
+ fn_rehash_zone(fz);
+#endif
+
+ fp = fz_chain_p(key, fz);
+
+ /*
+ * Scan list to find the first route with the same destination
+ */
+ FIB_SCAN(f, fp) {
+ if (fn_key_leq(key,f->fn_key))
+ break;
+ }
+
+#ifdef CONFIG_IP_ROUTE_TOS
+ /*
+ * Find route with the same destination and tos.
+ */
+ FIB_SCAN_KEY(f, fp, key) {
+ if (f->fn_tos <= tos)
+ break;
+ }
+#endif
+
+ del_fp = NULL;
+
+ if (f && (f->fn_state&FN_S_ZOMBIE) &&
+#ifdef CONFIG_IP_ROUTE_TOS
+ f->fn_tos == tos &&
+#endif
+ fn_key_eq(f->fn_key, key)) {
+ del_fp = fp;
+ fp = &f->fn_next;
+ f = *fp;
+ goto create;
+ }
+
+ FIB_SCAN_TOS(f, fp, key, tos) {
+ if (fi->fib_priority <= FIB_INFO(f)->fib_priority)
+ break;
+ }
+
+ /* Now f==*fp points to the first node with the same
+ keys [prefix,tos,priority], if such key already
+ exists or to the node, before which we will insert new one.
+ */
+
+ if (f &&
+#ifdef CONFIG_IP_ROUTE_TOS
+ f->fn_tos == tos &&
+#endif
+ fn_key_eq(f->fn_key, key) &&
+ fi->fib_priority == FIB_INFO(f)->fib_priority) {
+ struct fib_node **ins_fp;
+
+ err = -EEXIST;
+ if (n->nlmsg_flags&NLM_F_EXCL)
+ goto out;
+
+ if (n->nlmsg_flags&NLM_F_REPLACE) {
+ del_fp = fp;
+ fp = &f->fn_next;
+ f = *fp;
+ goto replace;
+ }
+
+ ins_fp = fp;
+ err = -EEXIST;
+
+ FIB_SCAN_TOS(f, fp, key, tos) {
+ if (fi->fib_priority != FIB_INFO(f)->fib_priority)
+ break;
+ if (f->fn_type == type && f->fn_scope == r->rtm_scope
+ && FIB_INFO(f) == fi)
+ goto out;
+ }
+
+ if (!(n->nlmsg_flags&NLM_F_APPEND)) {
+ fp = ins_fp;
+ f = *fp;
+ }
+ }
+
+create:
+ err = -ENOENT;
+ if (!(n->nlmsg_flags&NLM_F_CREATE))
+ goto out;
+
+replace:
+ err = -ENOBUFS;
+ new_f = (struct fib_node *) kmalloc(sizeof(struct fib_node), GFP_KERNEL);
+ if (new_f == NULL)
+ goto out;
+
+ memset(new_f, 0, sizeof(struct fib_node));
+
+ new_f->fn_key = key;
+#ifdef CONFIG_IP_ROUTE_TOS
+ new_f->fn_tos = tos;
+#endif
+ new_f->fn_type = type;
+ new_f->fn_scope = r->rtm_scope;
+ FIB_INFO(new_f) = fi;
+
+ /*
+ * Insert new entry to the list.
+ */
+
+ new_f->fn_next = f;
+ *fp = new_f;
+ fz->fz_nent++;
+
+ if (del_fp) {
+ f = *del_fp;
+ /* Unlink replaced node */
+ *del_fp = f->fn_next;
+ synchronize_bh();
+
+ if (!(f->fn_state&FN_S_ZOMBIE))
+ rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
+ if (f->fn_state&FN_S_ACCESSED)
+ rt_cache_flush(-1);
+ fn_free_node(f);
+ fz->fz_nent--;
+ } else {
+ rt_cache_flush(-1);
+ }
+ rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->tb_id, n, req);
+ return 0;
+
+out:
+ fib_release_info(fi);
+ return err;
+}
+
+
+static int
+fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
+ struct nlmsghdr *n, struct netlink_skb_parms *req)
+{
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+ struct fib_node **fp, **del_fp, *f;
+ int z = r->rtm_dst_len;
+ struct fn_zone *fz;
+ fn_key_t key;
+ int matched;
+#ifdef CONFIG_IP_ROUTE_TOS
+ u8 tos = r->rtm_tos;
+#endif
+
+FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
+ *(u32*)rta->rta_dst : 0, z, rta->rta_oif ? *rta->rta_oif : -1);
+ if (z > 32)
+ return -EINVAL;
+ if ((fz = table->fn_zones[z]) == NULL)
+ return -ESRCH;
+
+ fz_key_0(key);
+ if (rta->rta_dst) {
+ u32 dst;
+ memcpy(&dst, rta->rta_dst, 4);
+ if (dst & ~FZ_MASK(fz))
+ return -EINVAL;
+ key = fz_key(dst, fz);
+ }
+
+ fp = fz_chain_p(key, fz);
+
+ FIB_SCAN(f, fp) {
+ if (fn_key_eq(f->fn_key, key))
+ break;
+ if (fn_key_leq(key, f->fn_key))
+ return -ESRCH;
+ }
+#ifdef CONFIG_IP_ROUTE_TOS
+ FIB_SCAN_KEY(f, fp, key) {
+ if (f->fn_tos == tos)
+ break;
+ }
+#endif
+
+ matched = 0;
+ del_fp = NULL;
+ FIB_SCAN_TOS(f, fp, key, tos) {
+ struct fib_info * fi = FIB_INFO(f);
+
+ if (f->fn_state&FN_S_ZOMBIE)
+ return -ESRCH;
+
+ matched++;
+
+ if (del_fp == NULL &&
+ (!r->rtm_type || f->fn_type == r->rtm_type) &&
+ (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
+ (!r->rtm_protocol || fi->fib_protocol == r->rtm_protocol) &&
+ fib_nh_match(r, n, rta, fi) == 0)
+ del_fp = fp;
+ }
+
+ if (del_fp) {
+ f = *del_fp;
+ rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
+
+ if (matched != 1) {
+ *del_fp = f->fn_next;
+ synchronize_bh();
+
+ if (f->fn_state&FN_S_ACCESSED)
+ rt_cache_flush(-1);
+ fn_free_node(f);
+ fz->fz_nent--;
+ } else {
+ f->fn_state |= FN_S_ZOMBIE;
+ if (f->fn_state&FN_S_ACCESSED) {
+ f->fn_state &= ~FN_S_ACCESSED;
+ rt_cache_flush(-1);
+ }
+ if (++fib_hash_zombies > 128)
+ fib_flush();
+ }
+
+ return 0;
+ }
+ return -ESRCH;
+}
+
+extern __inline__ int
+fn_flush_list(struct fib_node ** fp, int z, struct fn_hash *table)
+{
+ int found = 0;
+ struct fib_node *f;
+
+ while ((f = *fp) != NULL) {
+ struct fib_info *fi = FIB_INFO(f);
+
+ if (fi && ((f->fn_state&FN_S_ZOMBIE) || (fi->fib_flags&RTNH_F_DEAD))) {
+ *fp = f->fn_next;
+ synchronize_bh();
+
+ fn_free_node(f);
+ found++;
+ continue;
+ }
+ fp = &f->fn_next;
+ }
+ return found;
+}
+
+static int fn_hash_flush(struct fib_table *tb)
+{
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+ struct fn_zone *fz;
+ int found = 0;
+
+ fib_hash_zombies = 0;
+ for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
+ int i;
+ int tmp = 0;
+ for (i=fz->fz_divisor-1; i>=0; i--)
+ tmp += fn_flush_list(&fz->fz_hash[i], fz->fz_order, table);
+ fz->fz_nent -= tmp;
+ found += tmp;
+ }
+ return found;
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+static int fn_hash_get_info(struct fib_table *tb, char *buffer, int first, int count)
+{
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+ struct fn_zone *fz;
+ int pos = 0;
+ int n = 0;
+
+ for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {
+ int i;
+ struct fib_node *f;
+ int maxslot = fz->fz_divisor;
+ struct fib_node **fp = fz->fz_hash;
+
+ if (fz->fz_nent == 0)
+ continue;
+
+ if (pos + fz->fz_nent <= first) {
+ pos += fz->fz_nent;
+ continue;
+ }
+
+ for (i=0; i < maxslot; i++, fp++) {
+ for (f = *fp; f; f = f->fn_next) {
+ if (++pos <= first)
+ continue;
+ fib_node_get_info(f->fn_type,
+ f->fn_state&FN_S_ZOMBIE,
+ FIB_INFO(f),
+ fz_prefix(f->fn_key, fz),
+ FZ_MASK(fz), buffer);
+ buffer += 128;
+ if (++n >= count)
+ return n;
+ }
+ }
+ }
+ return n;
+}
+#endif
+
+
+#ifdef CONFIG_RTNETLINK
+
+extern __inline__ int
+fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
+ struct fib_table *tb,
+ struct fn_zone *fz,
+ struct fib_node *f)
+{
+ int i, s_i;
+
+ s_i = cb->args[3];
+ for (i=0; f; i++, f=f->fn_next) {
+ if (i < s_i) continue;
+ if (f->fn_state&FN_S_ZOMBIE) continue;
+ if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+ RTM_NEWROUTE,
+ tb->tb_id, (f->fn_state&FN_S_ZOMBIE) ? 0 : f->fn_type, f->fn_scope,
+ &f->fn_key, fz->fz_order, f->fn_tos,
+ f->fn_info) < 0) {
+ cb->args[3] = i;
+ return -1;
+ }
+ }
+ cb->args[3] = i;
+ return skb->len;
+}
+
+extern __inline__ int
+fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
+ struct fib_table *tb,
+ struct fn_zone *fz)
+{
+ int h, s_h;
+
+ s_h = cb->args[2];
+ for (h=0; h < fz->fz_divisor; h++) {
+ if (h < s_h) continue;
+ if (h > s_h)
+ memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
+ if (fz->fz_hash == NULL || fz->fz_hash[h] == NULL)
+ continue;
+ if (fn_hash_dump_bucket(skb, cb, tb, fz, fz->fz_hash[h]) < 0) {
+ cb->args[2] = h;
+ return -1;
+ }
+ }
+ cb->args[2] = h;
+ return skb->len;
+}
+
+static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int m, s_m;
+ struct fn_zone *fz;
+ struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+
+ s_m = cb->args[1];
+ for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
+ if (m < s_m) continue;
+ if (m > s_m)
+ memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
+ if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
+ cb->args[1] = m;
+ return -1;
+ }
+ }
+ cb->args[1] = m;
+ return skb->len;
+}
+
+static void rtmsg_fib(int event, struct fib_node* f, int z, int tb_id,
+ struct nlmsghdr *n, struct netlink_skb_parms *req)
+{
+ struct sk_buff *skb;
+ u32 pid = req ? req->pid : 0;
+ int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
+
+ skb = alloc_skb(size, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id,
+ f->fn_type, f->fn_scope, &f->fn_key, z, f->fn_tos,
+ FIB_INFO(f)) < 0) {
+ kfree_skb(skb);
+ return;
+ }
+ NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_ROUTE;
+ if (n->nlmsg_flags&NLM_F_ECHO)
+ atomic_inc(&skb->users);
+ netlink_broadcast(rtnl, skb, pid, RTMGRP_IPV4_ROUTE, GFP_KERNEL);
+ if (n->nlmsg_flags&NLM_F_ECHO)
+ netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
+}
+
+#endif /* CONFIG_RTNETLINK */
+
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+struct fib_table * fib_hash_init(int id)
+#else
+__initfunc(struct fib_table * fib_hash_init(int id))
+#endif
+{
+ struct fib_table *tb;
+ tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash), GFP_KERNEL);
+ if (tb == NULL)
+ return NULL;
+ tb->tb_id = id;
+ tb->tb_lookup = fn_hash_lookup;
+ tb->tb_insert = fn_hash_insert;
+ tb->tb_delete = fn_hash_delete;
+ tb->tb_flush = fn_hash_flush;
+ tb->tb_select_default = fn_hash_select_default;
+#ifdef CONFIG_RTNETLINK
+ tb->tb_dump = fn_hash_dump;
+#endif
+#ifdef CONFIG_PROC_FS
+ tb->tb_get_info = fn_hash_get_info;
+#endif
+ memset(tb->tb_data, 0, sizeof(struct fn_hash));
+ return tb;
+}
diff --git a/pfinet/linux-src/net/ipv4/fib_rules.c b/pfinet/linux-src/net/ipv4/fib_rules.c
new file mode 100644
index 00000000..868c44c3
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/fib_rules.c
@@ -0,0 +1,419 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IPv4 Forwarding Information Base: policy rules.
+ *
+ * Version: $Id: fib_rules.c,v 1.9 1999/03/25 10:04:23 davem Exp $
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ * Rani Assaf : local_rule cannot be deleted
+ * Marc Boucher : routing by fwmark
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/init.h>
+
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/sock.h>
+#include <net/ip_fib.h>
+
+#define FRprintk(a...)
+
+struct fib_rule
+{
+ struct fib_rule *r_next;
+ u32 r_preference;
+ unsigned char r_table;
+ unsigned char r_action;
+ unsigned char r_dst_len;
+ unsigned char r_src_len;
+ u32 r_src;
+ u32 r_srcmask;
+ u32 r_dst;
+ u32 r_dstmask;
+ u32 r_srcmap;
+ u8 r_flags;
+ u8 r_tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ u32 r_fwmark;
+#endif
+ int r_ifindex;
+#ifdef CONFIG_NET_CLS_ROUTE
+ __u32 r_tclassid;
+#endif
+ char r_ifname[IFNAMSIZ];
+};
+
+static struct fib_rule default_rule = { NULL, 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST, };
+static struct fib_rule main_rule = { &default_rule, 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST, };
+static struct fib_rule local_rule = { &main_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST, };
+
+static struct fib_rule *fib_rules = &local_rule;
+
+int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct rtmsg *rtm = NLMSG_DATA(nlh);
+ struct fib_rule *r, **rp;
+
+ for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
+ if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
+ rtm->rtm_src_len == r->r_src_len &&
+ rtm->rtm_dst_len == r->r_dst_len &&
+ (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 4) == 0) &&
+ rtm->rtm_tos == r->r_tos &&
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
+#endif
+ (!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
+ (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
+ (!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) &&
+ (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
+ if (r == &local_rule)
+ return -EPERM;
+
+ *rp = r->r_next;
+ synchronize_bh();
+
+ if (r != &default_rule && r != &main_rule)
+ kfree(r);
+ return 0;
+ }
+ }
+ return -ESRCH;
+}
+
+/* Allocate new unique table id */
+
+static struct fib_table *fib_empty_table(void)
+{
+ int id;
+
+ for (id = 1; id <= RT_TABLE_MAX; id++)
+ if (fib_tables[id] == NULL)
+ return __fib_new_table(id);
+ return NULL;
+}
+
+
+int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct rtmsg *rtm = NLMSG_DATA(nlh);
+ struct fib_rule *r, *new_r, **rp;
+ unsigned char table_id;
+
+ if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 ||
+ (rtm->rtm_tos & ~IPTOS_TOS_MASK))
+ return -EINVAL;
+
+ if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
+ return -EINVAL;
+
+ table_id = rtm->rtm_table;
+ if (table_id == RT_TABLE_UNSPEC) {
+ struct fib_table *table;
+ if (rtm->rtm_type == RTN_UNICAST || rtm->rtm_type == RTN_NAT) {
+ if ((table = fib_empty_table()) == NULL)
+ return -ENOBUFS;
+ table_id = table->tb_id;
+ }
+ }
+
+ new_r = kmalloc(sizeof(*new_r), GFP_KERNEL);
+ if (!new_r)
+ return -ENOMEM;
+ memset(new_r, 0, sizeof(*new_r));
+ if (rta[RTA_SRC-1])
+ memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4);
+ if (rta[RTA_DST-1])
+ memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 4);
+ if (rta[RTA_GATEWAY-1])
+ memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 4);
+ new_r->r_src_len = rtm->rtm_src_len;
+ new_r->r_dst_len = rtm->rtm_dst_len;
+ new_r->r_srcmask = inet_make_mask(rtm->rtm_src_len);
+ new_r->r_dstmask = inet_make_mask(rtm->rtm_dst_len);
+ new_r->r_tos = rtm->rtm_tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ if (rta[RTA_PROTOINFO-1])
+ memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
+#endif
+ new_r->r_action = rtm->rtm_type;
+ new_r->r_flags = rtm->rtm_flags;
+ if (rta[RTA_PRIORITY-1])
+ memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
+ new_r->r_table = table_id;
+ if (rta[RTA_IIF-1]) {
+ struct device *dev;
+ memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
+ new_r->r_ifname[IFNAMSIZ-1] = 0;
+ new_r->r_ifindex = -1;
+ dev = dev_get(new_r->r_ifname);
+ if (dev)
+ new_r->r_ifindex = dev->ifindex;
+ }
+#ifdef CONFIG_NET_CLS_ROUTE
+ if (rta[RTA_FLOW-1])
+ memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
+#endif
+
+ rp = &fib_rules;
+ if (!new_r->r_preference) {
+ r = fib_rules;
+ if (r && (r = r->r_next) != NULL) {
+ rp = &fib_rules->r_next;
+ if (r->r_preference)
+ new_r->r_preference = r->r_preference - 1;
+ }
+ }
+
+ while ( (r = *rp) != NULL ) {
+ if (r->r_preference > new_r->r_preference)
+ break;
+ rp = &r->r_next;
+ }
+
+ new_r->r_next = r;
+ *rp = new_r;
+ return 0;
+}
+
+u32 fib_rules_map_destination(u32 daddr, struct fib_result *res)
+{
+ u32 mask = inet_make_mask(res->prefixlen);
+ return (daddr&~mask)|res->fi->fib_nh->nh_gw;
+}
+
+u32 fib_rules_policy(u32 saddr, struct fib_result *res, unsigned *flags)
+{
+ struct fib_rule *r = res->r;
+
+ if (r->r_action == RTN_NAT) {
+ int addrtype = inet_addr_type(r->r_srcmap);
+
+ if (addrtype == RTN_NAT) {
+ /* Packet is from translated source; remember it */
+ saddr = (saddr&~r->r_srcmask)|r->r_srcmap;
+ *flags |= RTCF_SNAT;
+ } else if (addrtype == RTN_LOCAL || r->r_srcmap == 0) {
+ /* Packet is from masqueraded source; remember it */
+ saddr = r->r_srcmap;
+ *flags |= RTCF_MASQ;
+ }
+ }
+ return saddr;
+}
+
+#ifdef CONFIG_NET_CLS_ROUTE
+u32 fib_rules_tclass(struct fib_result *res)
+{
+ if (res->r)
+ return res->r->r_tclassid;
+ return 0;
+}
+#endif
+
+
+static void fib_rules_detach(struct device *dev)
+{
+ struct fib_rule *r;
+
+ for (r=fib_rules; r; r=r->r_next) {
+ if (r->r_ifindex == dev->ifindex)
+ r->r_ifindex = -1;
+ }
+}
+
+static void fib_rules_attach(struct device *dev)
+{
+ struct fib_rule *r;
+
+ for (r=fib_rules; r; r=r->r_next) {
+ if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
+ r->r_ifindex = dev->ifindex;
+ }
+}
+
+int fib_lookup(const struct rt_key *key, struct fib_result *res)
+{
+ int err;
+ struct fib_rule *r, *policy;
+ struct fib_table *tb;
+
+ u32 daddr = key->dst;
+ u32 saddr = key->src;
+
+FRprintk("Lookup: %08x <- %08x ", key->dst, key->src);
+ for (r = fib_rules; r; r=r->r_next) {
+ if (((saddr^r->r_src) & r->r_srcmask) ||
+ ((daddr^r->r_dst) & r->r_dstmask) ||
+#ifdef CONFIG_IP_ROUTE_TOS
+ (r->r_tos && r->r_tos != key->tos) ||
+#endif
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ (r->r_fwmark && r->r_fwmark != key->fwmark) ||
+#endif
+ (r->r_ifindex && r->r_ifindex != key->iif))
+ continue;
+
+FRprintk("tb %d r %d ", r->r_table, r->r_action);
+ switch (r->r_action) {
+ case RTN_UNICAST:
+ case RTN_NAT:
+ policy = r;
+ break;
+ case RTN_UNREACHABLE:
+ return -ENETUNREACH;
+ default:
+ case RTN_BLACKHOLE:
+ return -EINVAL;
+ case RTN_PROHIBIT:
+ return -EACCES;
+ }
+
+ if ((tb = fib_get_table(r->r_table)) == NULL)
+ continue;
+ err = tb->tb_lookup(tb, key, res);
+ if (err == 0) {
+FRprintk("ok\n");
+ res->r = policy;
+ return 0;
+ }
+ if (err < 0 && err != -EAGAIN)
+ return err;
+ }
+FRprintk("FAILURE\n");
+ return -ENETUNREACH;
+}
+
+void fib_select_default(const struct rt_key *key, struct fib_result *res)
+{
+ if (res->r && res->r->r_action == RTN_UNICAST &&
+ FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
+ struct fib_table *tb;
+ if ((tb = fib_get_table(res->r->r_table)) != NULL)
+ tb->tb_select_default(tb, key, res);
+ }
+}
+
+static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct device *dev = ptr;
+
+ if (event == NETDEV_UNREGISTER)
+ fib_rules_detach(dev);
+ else if (event == NETDEV_REGISTER)
+ fib_rules_attach(dev);
+ return NOTIFY_DONE;
+}
+
+
+struct notifier_block fib_rules_notifier = {
+ fib_rules_event,
+ NULL,
+ 0
+};
+
+#ifdef CONFIG_RTNETLINK
+
+extern __inline__ int inet_fill_rule(struct sk_buff *skb,
+ struct fib_rule *r,
+ struct netlink_callback *cb)
+{
+ struct rtmsg *rtm;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm));
+ rtm = NLMSG_DATA(nlh);
+ rtm->rtm_family = AF_INET;
+ rtm->rtm_dst_len = r->r_dst_len;
+ rtm->rtm_src_len = r->r_src_len;
+ rtm->rtm_tos = r->r_tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ if (r->r_fwmark)
+ RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
+#endif
+ rtm->rtm_table = r->r_table;
+ rtm->rtm_protocol = 0;
+ rtm->rtm_scope = 0;
+ rtm->rtm_type = r->r_action;
+ rtm->rtm_flags = r->r_flags;
+
+ if (r->r_dst_len)
+ RTA_PUT(skb, RTA_DST, 4, &r->r_dst);
+ if (r->r_src_len)
+ RTA_PUT(skb, RTA_SRC, 4, &r->r_src);
+ if (r->r_ifname[0])
+ RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
+ if (r->r_preference)
+ RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
+ if (r->r_srcmap)
+ RTA_PUT(skb, RTA_GATEWAY, 4, &r->r_srcmap);
+#ifdef CONFIG_NET_CLS_ROUTE
+ if (r->r_tclassid)
+ RTA_PUT(skb, RTA_FLOW, 4, &r->r_tclassid);
+#endif
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_put(skb, b - skb->tail);
+ return -1;
+}
+
+int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx;
+ int s_idx = cb->args[0];
+ struct fib_rule *r;
+
+ for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
+ if (idx < s_idx)
+ continue;
+ if (inet_fill_rule(skb, r, cb) < 0)
+ break;
+ }
+ cb->args[0] = idx;
+
+ return skb->len;
+}
+
+#endif /* CONFIG_RTNETLINK */
+
+__initfunc(void fib_rules_init(void))
+{
+ register_netdevice_notifier(&fib_rules_notifier);
+}
diff --git a/pfinet/linux-src/net/ipv4/fib_semantics.c b/pfinet/linux-src/net/ipv4/fib_semantics.c
new file mode 100644
index 00000000..b7edb29b
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/fib_semantics.c
@@ -0,0 +1,991 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IPv4 Forwarding Information Base: semantics.
+ *
+ * Version: $Id: fib_semantics.c,v 1.13 1999/03/21 05:22:34 davem Exp $
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/init.h>
+
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/sock.h>
+#include <net/ip_fib.h>
+
+#define FSprintk(a...)
+
+static struct fib_info *fib_info_list;
+
+#define for_fib_info() { struct fib_info *fi; \
+ for (fi = fib_info_list; fi; fi = fi->fib_next)
+
+#define endfor_fib_info() }
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+
+#define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
+for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
+
+#define change_nexthops(fi) { int nhsel; struct fib_nh * nh; \
+for (nhsel=0, nh = (struct fib_nh*)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
+
+#else /* CONFIG_IP_ROUTE_MULTIPATH */
+
+/* Hope, that gcc will optimize it to get rid of dummy loop */
+
+#define for_nexthops(fi) { int nhsel=0; const struct fib_nh * nh = (fi)->fib_nh; \
+for (nhsel=0; nhsel < 1; nhsel++)
+
+#define change_nexthops(fi) { int nhsel=0; struct fib_nh * nh = (struct fib_nh*)((fi)->fib_nh); \
+for (nhsel=0; nhsel < 1; nhsel++)
+
+#endif /* CONFIG_IP_ROUTE_MULTIPATH */
+
+#define endfor_nexthops(fi) }
+
+
+static struct
+{
+ int error;
+ u8 scope;
+} fib_props[RTA_MAX+1] = {
+ { 0, RT_SCOPE_NOWHERE}, /* RTN_UNSPEC */
+ { 0, RT_SCOPE_UNIVERSE}, /* RTN_UNICAST */
+ { 0, RT_SCOPE_HOST}, /* RTN_LOCAL */
+ { 0, RT_SCOPE_LINK}, /* RTN_BROADCAST */
+ { 0, RT_SCOPE_LINK}, /* RTN_ANYCAST */
+ { 0, RT_SCOPE_UNIVERSE}, /* RTN_MULTICAST */
+ { -EINVAL, RT_SCOPE_UNIVERSE}, /* RTN_BLACKHOLE */
+ { -EHOSTUNREACH, RT_SCOPE_UNIVERSE},/* RTN_UNREACHABLE */
+ { -EACCES, RT_SCOPE_UNIVERSE}, /* RTN_PROHIBIT */
+ { -EAGAIN, RT_SCOPE_UNIVERSE}, /* RTN_THROW */
+#ifdef CONFIG_IP_ROUTE_NAT
+ { 0, RT_SCOPE_HOST}, /* RTN_NAT */
+#else
+ { -EINVAL, RT_SCOPE_NOWHERE}, /* RTN_NAT */
+#endif
+ { -EINVAL, RT_SCOPE_NOWHERE} /* RTN_XRESOLVE */
+};
+
+/* Release a nexthop info record */
+
+void fib_release_info(struct fib_info *fi)
+{
+ if (fi && !--fi->fib_refcnt) {
+ if (fi->fib_next)
+ fi->fib_next->fib_prev = fi->fib_prev;
+ if (fi->fib_prev)
+ fi->fib_prev->fib_next = fi->fib_next;
+ if (fi == fib_info_list)
+ fib_info_list = fi->fib_next;
+ kfree(fi);
+ }
+}
+
+extern __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
+{
+ const struct fib_nh *onh = ofi->fib_nh;
+
+ for_nexthops(fi) {
+ if (nh->nh_oif != onh->nh_oif ||
+ nh->nh_gw != onh->nh_gw ||
+ nh->nh_scope != onh->nh_scope ||
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ nh->nh_weight != onh->nh_weight ||
+#endif
+#ifdef CONFIG_NET_CLS_ROUTE
+ nh->nh_tclassid != onh->nh_tclassid ||
+#endif
+ ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
+ return -1;
+ onh++;
+ } endfor_nexthops(fi);
+ return 0;
+}
+
+extern __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
+{
+ for_fib_info() {
+ if (fi->fib_nhs != nfi->fib_nhs)
+ continue;
+ if (nfi->fib_protocol == fi->fib_protocol &&
+ nfi->fib_prefsrc == fi->fib_prefsrc &&
+ nfi->fib_priority == fi->fib_priority &&
+ nfi->fib_mtu == fi->fib_mtu &&
+ nfi->fib_rtt == fi->fib_rtt &&
+ nfi->fib_window == fi->fib_window &&
+ ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
+ (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
+ return fi;
+ } endfor_fib_info();
+ return NULL;
+}
+
+/* Check, that the gateway is already configured.
+ Used only by redirect accept routine.
+ */
+
+int ip_fib_check_default(u32 gw, struct device *dev)
+{
+ for_fib_info() {
+ if (fi->fib_flags & RTNH_F_DEAD)
+ continue;
+ for_nexthops(fi) {
+ if (nh->nh_dev == dev && nh->nh_gw == gw &&
+ !(nh->nh_flags&RTNH_F_DEAD))
+ return 0;
+ } endfor_nexthops(fi);
+ } endfor_fib_info();
+ return -1;
+}
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+
+static u32 fib_get_attr32(struct rtattr *attr, int attrlen, int type)
+{
+ while (RTA_OK(attr,attrlen)) {
+ if (attr->rta_type == type)
+ return *(u32*)RTA_DATA(attr);
+ attr = RTA_NEXT(attr, attrlen);
+ }
+ return 0;
+}
+
+static int
+fib_count_nexthops(struct rtattr *rta)
+{
+ int nhs = 0;
+ struct rtnexthop *nhp = RTA_DATA(rta);
+ int nhlen = RTA_PAYLOAD(rta);
+
+ while (nhlen >= (int)sizeof(struct rtnexthop)) {
+ if ((nhlen -= nhp->rtnh_len) < 0)
+ return 0;
+ nhs++;
+ nhp = RTNH_NEXT(nhp);
+ };
+ return nhs;
+}
+
+static int
+fib_get_nhs(struct fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
+{
+ struct rtnexthop *nhp = RTA_DATA(rta);
+ int nhlen = RTA_PAYLOAD(rta);
+
+ change_nexthops(fi) {
+ int attrlen = nhlen - sizeof(struct rtnexthop);
+ if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
+ return -EINVAL;
+ nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
+ nh->nh_oif = nhp->rtnh_ifindex;
+ nh->nh_weight = nhp->rtnh_hops + 1;
+ if (attrlen) {
+ nh->nh_gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+#ifdef CONFIG_NET_CLS_ROUTE
+ nh->nh_tclassid = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW);
+#endif
+ }
+ nhp = RTNH_NEXT(nhp);
+ } endfor_nexthops(fi);
+ return 0;
+}
+
+#endif
+
+int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta,
+ struct fib_info *fi)
+{
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ struct rtnexthop *nhp;
+ int nhlen;
+#endif
+
+ if (rta->rta_priority &&
+ *rta->rta_priority != fi->fib_priority)
+ return 1;
+
+ if (rta->rta_oif || rta->rta_gw) {
+ if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
+ (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0))
+ return 0;
+ return 1;
+ }
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (rta->rta_mp == NULL)
+ return 0;
+ nhp = RTA_DATA(rta->rta_mp);
+ nhlen = RTA_PAYLOAD(rta->rta_mp);
+
+ for_nexthops(fi) {
+ int attrlen = nhlen - sizeof(struct rtnexthop);
+ u32 gw;
+
+ if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
+ return -EINVAL;
+ if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
+ return 1;
+ if (attrlen) {
+ gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+ if (gw && gw != nh->nh_gw)
+ return 1;
+#ifdef CONFIG_NET_CLS_ROUTE
+ gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW);
+ if (gw && gw != nh->nh_tclassid)
+ return 1;
+#endif
+ }
+ nhp = RTNH_NEXT(nhp);
+ } endfor_nexthops(fi);
+#endif
+ return 0;
+}
+
+
+/*
+ Picture
+ -------
+
+ Semantics of nexthop is very messy by historical reasons.
+ We have to take into account, that:
+ a) gateway can be actually local interface address,
+ so that gatewayed route is direct.
+ b) gateway must be on-link address, possibly
+ described not by an ifaddr, but also by a direct route.
+ c) If both gateway and interface are specified, they should not
+ contradict.
+ d) If we use tunnel routes, gateway could be not on-link.
+
+ Attempt to reconcile all of these (alas, self-contradictory) conditions
+ results in pretty ugly and hairy code with obscure logic.
+
+ I chose to generalize it instead, so that the size
+ of code does not increase practically, but it becomes
+ much more general.
+ Every prefix is assigned a "scope" value: "host" is local address,
+ "link" is direct route,
+ [ ... "site" ... "interior" ... ]
+ and "universe" is true gateway route with global meaning.
+
+ Every prefix refers to a set of "nexthop"s (gw, oif),
+ where gw must have narrower scope. This recursion stops
+ when gw has LOCAL scope or if "nexthop" is declared ONLINK,
+ which means that gw is forced to be on link.
+
+ Code is still hairy, but now it is apparently logically
+ consistent and very flexible. F.e. as by-product it allows
+ to co-exists in peace independent exterior and interior
+ routing processes.
+
+ Normally it looks as following.
+
+ {universe prefix} -> (gw, oif) [scope link]
+ |
+ |-> {link prefix} -> (gw, oif) [scope local]
+ |
+ |-> {local prefix} (terminal node)
+ */
+
+static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh)
+{
+ int err;
+
+ if (nh->nh_gw) {
+ struct rt_key key;
+ struct fib_result res;
+
+#ifdef CONFIG_IP_ROUTE_PERVASIVE
+ if (nh->nh_flags&RTNH_F_PERVASIVE)
+ return 0;
+#endif
+ if (nh->nh_flags&RTNH_F_ONLINK) {
+ struct device *dev;
+
+ if (r->rtm_scope >= RT_SCOPE_LINK)
+ return -EINVAL;
+ if (inet_addr_type(nh->nh_gw) != RTN_UNICAST)
+ return -EINVAL;
+ if ((dev = dev_get_by_index(nh->nh_oif)) == NULL)
+ return -ENODEV;
+ if (!(dev->flags&IFF_UP))
+ return -ENETDOWN;
+ nh->nh_dev = dev;
+ nh->nh_scope = RT_SCOPE_LINK;
+ return 0;
+ }
+ memset(&key, 0, sizeof(key));
+ key.dst = nh->nh_gw;
+ key.oif = nh->nh_oif;
+ key.scope = r->rtm_scope + 1;
+
+ /* It is not necessary, but requires a bit of thinking */
+ if (key.scope < RT_SCOPE_LINK)
+ key.scope = RT_SCOPE_LINK;
+
+ if ((err = fib_lookup(&key, &res)) != 0)
+ return err;
+ nh->nh_scope = res.scope;
+ nh->nh_oif = FIB_RES_OIF(res);
+ nh->nh_dev = FIB_RES_DEV(res);
+ } else {
+ struct in_device *in_dev;
+
+ if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
+ return -EINVAL;
+
+ in_dev = inetdev_by_index(nh->nh_oif);
+ if (in_dev == NULL)
+ return -ENODEV;
+ if (!(in_dev->dev->flags&IFF_UP))
+ return -ENETDOWN;
+ nh->nh_dev = in_dev->dev;
+ nh->nh_scope = RT_SCOPE_HOST;
+ }
+ return 0;
+}
+
+struct fib_info *
+fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
+ const struct nlmsghdr *nlh, int *errp)
+{
+ int err;
+ struct fib_info *fi = NULL;
+ struct fib_info *ofi;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ int nhs = 1;
+#else
+ const int nhs = 1;
+#endif
+
+ /* Fast check to catch the most weird cases */
+ if (fib_props[r->rtm_type].scope > r->rtm_scope)
+ goto err_inval;
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (rta->rta_mp) {
+ nhs = fib_count_nexthops(rta->rta_mp);
+ if (nhs == 0)
+ goto err_inval;
+ }
+#endif
+
+ fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL);
+ err = -ENOBUFS;
+ if (fi == NULL)
+ goto failure;
+ memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct fib_nh));
+
+ fi->fib_protocol = r->rtm_protocol;
+ fi->fib_nhs = nhs;
+ fi->fib_flags = r->rtm_flags;
+ if (rta->rta_priority)
+ fi->fib_priority = *rta->rta_priority;
+ if (rta->rta_mx) {
+ int attrlen = RTA_PAYLOAD(rta->rta_mx);
+ struct rtattr *attr = RTA_DATA(rta->rta_mx);
+
+ while (RTA_OK(attr, attrlen)) {
+ unsigned flavor = attr->rta_type;
+ if (flavor) {
+ if (flavor > FIB_MAX_METRICS)
+ goto err_inval;
+ fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+ }
+ if (rta->rta_prefsrc)
+ memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4);
+
+ if (rta->rta_mp) {
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if ((err = fib_get_nhs(fi, rta->rta_mp, r)) != 0)
+ goto failure;
+ if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
+ goto err_inval;
+ if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4))
+ goto err_inval;
+#ifdef CONFIG_NET_CLS_ROUTE
+ if (rta->rta_flow && memcmp(&fi->fib_nh->nh_tclassid, rta->rta_flow, 4))
+ goto err_inval;
+#endif
+#else
+ goto err_inval;
+#endif
+ } else {
+ struct fib_nh *nh = fi->fib_nh;
+ if (rta->rta_oif)
+ nh->nh_oif = *rta->rta_oif;
+ if (rta->rta_gw)
+ memcpy(&nh->nh_gw, rta->rta_gw, 4);
+#ifdef CONFIG_NET_CLS_ROUTE
+ if (rta->rta_flow)
+ memcpy(&nh->nh_tclassid, rta->rta_flow, 4);
+#endif
+ nh->nh_flags = r->rtm_flags;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ nh->nh_weight = 1;
+#endif
+ }
+
+#ifdef CONFIG_IP_ROUTE_NAT
+ if (r->rtm_type == RTN_NAT) {
+ if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
+ goto err_inval;
+ memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 4);
+ goto link_it;
+ }
+#endif
+
+ if (fib_props[r->rtm_type].error) {
+ if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
+ goto err_inval;
+ goto link_it;
+ }
+
+ if (r->rtm_scope > RT_SCOPE_HOST)
+ goto err_inval;
+
+ if (r->rtm_scope == RT_SCOPE_HOST) {
+ struct fib_nh *nh = fi->fib_nh;
+
+ /* Local address is added. */
+ if (nhs != 1 || nh->nh_gw)
+ goto err_inval;
+ nh->nh_scope = RT_SCOPE_NOWHERE;
+ nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif);
+ err = -ENODEV;
+ if (nh->nh_dev == NULL)
+ goto failure;
+ } else {
+ change_nexthops(fi) {
+ if ((err = fib_check_nh(r, fi, nh)) != 0)
+ goto failure;
+ } endfor_nexthops(fi)
+ }
+
+ if (fi->fib_prefsrc) {
+ if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
+ memcmp(&fi->fib_prefsrc, rta->rta_dst, 4))
+ if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
+ goto err_inval;
+ }
+
+link_it:
+ if ((ofi = fib_find_info(fi)) != NULL) {
+ kfree(fi);
+ ofi->fib_refcnt++;
+ return ofi;
+ }
+
+ fi->fib_refcnt++;
+ fi->fib_next = fib_info_list;
+ fi->fib_prev = NULL;
+ if (fib_info_list)
+ fib_info_list->fib_prev = fi;
+ fib_info_list = fi;
+ return fi;
+
+err_inval:
+ err = -EINVAL;
+
+failure:
+ *errp = err;
+ if (fi)
+ kfree(fi);
+ return NULL;
+}
+
+int
+fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key, struct fib_result *res)
+{
+ int err = fib_props[type].error;
+
+ if (err == 0) {
+ if (fi->fib_flags&RTNH_F_DEAD)
+ return 1;
+
+ res->fi = fi;
+
+ switch (type) {
+#ifdef CONFIG_IP_ROUTE_NAT
+ case RTN_NAT:
+ FIB_RES_RESET(*res);
+ return 0;
+#endif
+ case RTN_UNICAST:
+ case RTN_LOCAL:
+ case RTN_BROADCAST:
+ case RTN_ANYCAST:
+ case RTN_MULTICAST:
+ for_nexthops(fi) {
+ if (nh->nh_flags&RTNH_F_DEAD)
+ continue;
+ if (!key->oif || key->oif == nh->nh_oif)
+ break;
+ }
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (nhsel < fi->fib_nhs) {
+ res->nh_sel = nhsel;
+ return 0;
+ }
+#else
+ if (nhsel < 1)
+ return 0;
+#endif
+ endfor_nexthops(fi);
+ return 1;
+ default:
+ printk(KERN_DEBUG "impossible 102\n");
+ return -EINVAL;
+ }
+ }
+ return err;
+}
+
+/* Find appropriate source address to this destination */
+
+u32 __fib_res_prefsrc(struct fib_result *res)
+{
+ return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);
+}
+
+#ifdef CONFIG_RTNETLINK
+
+int
+fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+ u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos,
+ struct fib_info *fi)
+{
+ struct rtmsg *rtm;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm));
+ rtm = NLMSG_DATA(nlh);
+ rtm->rtm_family = AF_INET;
+ rtm->rtm_dst_len = dst_len;
+ rtm->rtm_src_len = 0;
+ rtm->rtm_tos = tos;
+ rtm->rtm_table = tb_id;
+ rtm->rtm_type = type;
+ rtm->rtm_flags = fi->fib_flags;
+ rtm->rtm_scope = scope;
+ if (rtm->rtm_dst_len)
+ RTA_PUT(skb, RTA_DST, 4, dst);
+ rtm->rtm_protocol = fi->fib_protocol;
+ if (fi->fib_priority)
+ RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
+#ifdef CONFIG_NET_CLS_ROUTE
+ if (fi->fib_nh[0].nh_tclassid)
+ RTA_PUT(skb, RTA_FLOW, 4, &fi->fib_nh[0].nh_tclassid);
+#endif
+ if (fi->fib_mtu || fi->fib_window || fi->fib_rtt) {
+ int i;
+ struct rtattr *mx = (struct rtattr *)skb->tail;
+ RTA_PUT(skb, RTA_METRICS, 0, NULL);
+ for (i=0; i<FIB_MAX_METRICS; i++) {
+ if (fi->fib_metrics[i])
+ RTA_PUT(skb, i+1, sizeof(unsigned), fi->fib_metrics + i);
+ }
+ mx->rta_len = skb->tail - (u8*)mx;
+ }
+ if (fi->fib_prefsrc)
+ RTA_PUT(skb, RTA_PREFSRC, 4, &fi->fib_prefsrc);
+ if (fi->fib_nhs == 1) {
+ if (fi->fib_nh->nh_gw)
+ RTA_PUT(skb, RTA_GATEWAY, 4, &fi->fib_nh->nh_gw);
+ if (fi->fib_nh->nh_oif)
+ RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif);
+ }
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (fi->fib_nhs > 1) {
+ struct rtnexthop *nhp;
+ struct rtattr *mp_head;
+ if (skb_tailroom(skb) <= RTA_SPACE(0))
+ goto rtattr_failure;
+ mp_head = (struct rtattr*)skb_put(skb, RTA_SPACE(0));
+
+ for_nexthops(fi) {
+ if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
+ goto rtattr_failure;
+ nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
+ nhp->rtnh_flags = nh->nh_flags & 0xFF;
+ nhp->rtnh_hops = nh->nh_weight-1;
+ nhp->rtnh_ifindex = nh->nh_oif;
+ if (nh->nh_gw)
+ RTA_PUT(skb, RTA_GATEWAY, 4, &nh->nh_gw);
+ nhp->rtnh_len = skb->tail - (unsigned char*)nhp;
+ } endfor_nexthops(fi);
+ mp_head->rta_type = RTA_MULTIPATH;
+ mp_head->rta_len = skb->tail - (u8*)mp_head;
+ }
+#endif
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+#endif /* CONFIG_RTNETLINK */
+
+#ifndef CONFIG_IP_NOSIOCRT
+
+int
+fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
+ struct kern_rta *rta, struct rtentry *r)
+{
+ int plen;
+ u32 *ptr;
+
+ memset(rtm, 0, sizeof(*rtm));
+ memset(rta, 0, sizeof(*rta));
+
+ if (r->rt_dst.sa_family != AF_INET)
+ return -EAFNOSUPPORT;
+
+ /* Check mask for validity:
+ a) it must be contiguous.
+ b) destination must have all host bits clear.
+ c) if application forgot to set correct family (AF_INET),
+ reject request unless it is absolutely clear i.e.
+ both family and mask are zero.
+ */
+ plen = 32;
+ ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr;
+ if (!(r->rt_flags&RTF_HOST)) {
+ u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;
+ if (r->rt_genmask.sa_family != AF_INET) {
+ if (mask || r->rt_genmask.sa_family)
+ return -EAFNOSUPPORT;
+ }
+ if (bad_mask(mask, *ptr))
+ return -EINVAL;
+ plen = inet_mask_len(mask);
+ }
+
+ nl->nlmsg_flags = NLM_F_REQUEST;
+ nl->nlmsg_pid = 0;
+ nl->nlmsg_seq = 0;
+ nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm));
+ if (cmd == SIOCDELRT) {
+ nl->nlmsg_type = RTM_DELROUTE;
+ nl->nlmsg_flags = 0;
+ } else {
+ nl->nlmsg_type = RTM_NEWROUTE;
+ nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
+ rtm->rtm_protocol = RTPROT_BOOT;
+ }
+
+ rtm->rtm_dst_len = plen;
+ rta->rta_dst = ptr;
+
+ if (r->rt_metric) {
+ *(u32*)&r->rt_pad3 = r->rt_metric - 1;
+ rta->rta_priority = (u32*)&r->rt_pad3;
+ }
+ if (r->rt_flags&RTF_REJECT) {
+ rtm->rtm_scope = RT_SCOPE_HOST;
+ rtm->rtm_type = RTN_UNREACHABLE;
+ return 0;
+ }
+ rtm->rtm_scope = RT_SCOPE_NOWHERE;
+ rtm->rtm_type = RTN_UNICAST;
+
+ if (r->rt_dev) {
+#ifdef CONFIG_IP_ALIAS
+ char *colon;
+#endif
+ struct device *dev;
+ char devname[IFNAMSIZ];
+
+ if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1))
+ return -EFAULT;
+ devname[IFNAMSIZ-1] = 0;
+#ifdef CONFIG_IP_ALIAS
+ colon = strchr(devname, ':');
+ if (colon)
+ *colon = 0;
+#endif
+ dev = dev_get(devname);
+ if (!dev)
+ return -ENODEV;
+ rta->rta_oif = &dev->ifindex;
+#ifdef CONFIG_IP_ALIAS
+ if (colon) {
+ struct in_ifaddr *ifa;
+ struct in_device *in_dev = dev->ip_ptr;
+ if (!in_dev)
+ return -ENODEV;
+ *colon = ':';
+ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
+ if (strcmp(ifa->ifa_label, devname) == 0)
+ break;
+ if (ifa == NULL)
+ return -ENODEV;
+ rta->rta_prefsrc = &ifa->ifa_local;
+ }
+#endif
+ }
+
+ ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr;
+ if (r->rt_gateway.sa_family == AF_INET && *ptr) {
+ rta->rta_gw = ptr;
+ if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST)
+ rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+ }
+
+ if (cmd == SIOCDELRT)
+ return 0;
+
+ if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL)
+ return -EINVAL;
+
+ if (rtm->rtm_scope == RT_SCOPE_NOWHERE)
+ rtm->rtm_scope = RT_SCOPE_LINK;
+
+ if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
+ struct rtattr *rec;
+ struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
+ if (mx == NULL)
+ return -ENOMEM;
+ rta->rta_mx = mx;
+ mx->rta_type = RTA_METRICS;
+ mx->rta_len = RTA_LENGTH(0);
+ if (r->rt_flags&RTF_MTU) {
+ rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+ rec->rta_type = RTAX_MTU;
+ rec->rta_len = RTA_LENGTH(4);
+ mx->rta_len += RTA_LENGTH(4);
+ *(u32*)RTA_DATA(rec) = r->rt_mtu;
+ }
+ if (r->rt_flags&RTF_WINDOW) {
+ rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+ rec->rta_type = RTAX_WINDOW;
+ rec->rta_len = RTA_LENGTH(4);
+ mx->rta_len += RTA_LENGTH(4);
+ *(u32*)RTA_DATA(rec) = r->rt_window;
+ }
+ if (r->rt_flags&RTF_IRTT) {
+ rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));
+ rec->rta_type = RTAX_RTT;
+ rec->rta_len = RTA_LENGTH(4);
+ mx->rta_len += RTA_LENGTH(4);
+ *(u32*)RTA_DATA(rec) = r->rt_irtt;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+/*
+ Update FIB if:
+ - local address disappeared -> we must delete all the entries
+ referring to it.
+ - device went down -> we must shutdown all nexthops going via it.
+ */
+
+int fib_sync_down(u32 local, struct device *dev, int force)
+{
+ int ret = 0;
+ int scope = RT_SCOPE_NOWHERE;
+
+ if (force)
+ scope = -1;
+
+ for_fib_info() {
+ if (local && fi->fib_prefsrc == local) {
+ fi->fib_flags |= RTNH_F_DEAD;
+ ret++;
+ } else if (dev && fi->fib_nhs) {
+ int dead = 0;
+
+ change_nexthops(fi) {
+ if (nh->nh_flags&RTNH_F_DEAD)
+ dead++;
+ else if (nh->nh_dev == dev &&
+ nh->nh_scope != scope) {
+ nh->nh_flags |= RTNH_F_DEAD;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fi->fib_power -= nh->nh_power;
+ nh->nh_power = 0;
+#endif
+ dead++;
+ }
+ } endfor_nexthops(fi)
+ if (dead == fi->fib_nhs) {
+ fi->fib_flags |= RTNH_F_DEAD;
+ ret++;
+ }
+ }
+ } endfor_fib_info();
+ return ret;
+}
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+
+/*
+ Dead device goes up. We wake up dead nexthops.
+ It takes sense only on multipath routes.
+ */
+
+int fib_sync_up(struct device *dev)
+{
+ int ret = 0;
+
+ if (!(dev->flags&IFF_UP))
+ return 0;
+
+ for_fib_info() {
+ int alive = 0;
+
+ change_nexthops(fi) {
+ if (!(nh->nh_flags&RTNH_F_DEAD)) {
+ alive++;
+ continue;
+ }
+ if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
+ continue;
+ if (nh->nh_dev != dev || dev->ip_ptr == NULL)
+ continue;
+ alive++;
+ nh->nh_power = 0;
+ nh->nh_flags &= ~RTNH_F_DEAD;
+ } endfor_nexthops(fi)
+
+ if (alive == fi->fib_nhs) {
+ fi->fib_flags &= ~RTNH_F_DEAD;
+ ret++;
+ }
+ } endfor_fib_info();
+ return ret;
+}
+
+/*
+ The algorithm is suboptimal, but it provides really
+ fair weighted route distribution.
+ */
+
+void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
+{
+ struct fib_info *fi = res->fi;
+ int w;
+
+ if (fi->fib_power <= 0) {
+ int power = 0;
+ change_nexthops(fi) {
+ if (!(nh->nh_flags&RTNH_F_DEAD)) {
+ power += nh->nh_weight;
+ nh->nh_power = nh->nh_weight;
+ }
+ } endfor_nexthops(fi);
+ fi->fib_power = power;
+#if 1
+ if (power <= 0) {
+ printk(KERN_CRIT "impossible 777\n");
+ return;
+ }
+#endif
+ }
+
+
+ /* w should be random number [0..fi->fib_power-1],
+ it is pretty bad approximation.
+ */
+
+ w = jiffies % fi->fib_power;
+
+ change_nexthops(fi) {
+ if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
+ if ((w -= nh->nh_power) <= 0) {
+ nh->nh_power--;
+ fi->fib_power--;
+ res->nh_sel = nhsel;
+ return;
+ }
+ }
+ } endfor_nexthops(fi);
+
+#if 1
+ printk(KERN_CRIT "impossible 888\n");
+#endif
+ return;
+}
+#endif
+
+
+#ifdef CONFIG_PROC_FS
+
+static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi)
+{
+ static unsigned type2flags[RTN_MAX+1] = {
+ 0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0
+ };
+ unsigned flags = type2flags[type];
+
+ if (fi && fi->fib_nh->nh_gw)
+ flags |= RTF_GATEWAY;
+ if (mask == 0xFFFFFFFF)
+ flags |= RTF_HOST;
+ if (!dead)
+ flags |= RTF_UP;
+ return flags;
+}
+
+void fib_node_get_info(int type, int dead, struct fib_info *fi, u32 prefix, u32 mask, char *buffer)
+{
+ int len;
+ unsigned flags = fib_flag_trans(type, dead, mask, fi);
+
+ if (fi) {
+ len = sprintf(buffer, "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+ fi->fib_dev ? fi->fib_dev->name : "*", prefix,
+ fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
+ mask, fi->fib_mtu, fi->fib_window, fi->fib_rtt);
+ } else {
+ len = sprintf(buffer, "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+ prefix, 0,
+ flags, 0, 0, 0,
+ mask, 0, 0, 0);
+ }
+ memset(buffer+len, ' ', 127-len);
+ buffer[127] = '\n';
+}
+
+#endif
diff --git a/pfinet/linux-src/net/ipv4/icmp.c b/pfinet/linux-src/net/ipv4/icmp.c
new file mode 100644
index 00000000..7fad4783
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/icmp.c
@@ -0,0 +1,1156 @@
+/*
+ * NET3: Implementation of the ICMP protocol layer.
+ *
+ * Alan Cox, <alan@redhat.com>
+ *
+ * Version: $Id: icmp.c,v 1.52.2.4 1999/11/16 02:28:40 davem Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Some of the function names and the icmp unreach table for this
+ * module were derived from [icmp.c 1.0.11 06/02/93] by
+ * Ross Biro, Fred N. van Kempen, Mark Evans, Alan Cox, Gerhard Koerting.
+ * Other than that this module is a complete rewrite.
+ *
+ * Fixes:
+ * Mike Shaver : RFC1122 checks.
+ * Alan Cox : Multicast ping reply as self.
+ * Alan Cox : Fix atomicity lockup in ip_build_xmit
+ * call.
+ * Alan Cox : Added 216,128 byte paths to the MTU
+ * code.
+ * Martin Mares : RFC1812 checks.
+ * Martin Mares : Can be configured to follow redirects
+ * if acting as a router _without_ a
+ * routing protocol (RFC 1812).
+ * Martin Mares : Echo requests may be configured to
+ * be ignored (RFC 1812).
+ * Martin Mares : Limitation of ICMP error message
+ * transmit rate (RFC 1812).
+ * Martin Mares : TOS and Precedence set correctly
+ * (RFC 1812).
+ * Martin Mares : Now copying as much data from the
+ * original packet as we can without
+ * exceeding 576 bytes (RFC 1812).
+ * Willy Konynenberg : Transparent proxying support.
+ * Keith Owens : RFC1191 correction for 4.2BSD based
+ * path MTU bug.
+ * Thomas Quinot : ICMP Dest Unreach codes up to 15 are
+ * valid (RFC 1812).
+ * Andi Kleen : Check all packet lengths properly
+ * and moved all kfree_skb() up to
+ * icmp_rcv.
+ * Andi Kleen : Move the rate limit bookkeeping
+ * into the dest entry and use a token
+ * bucket filter (thanks to ANK). Make
+ * the rates sysctl configurable.
+ * Yu Tianli : Fixed two ugly bugs in icmp_send
+ * - IP option length was accounted wrongly
+ * - ICMP header length was not accounted at all.
+ * Tristan Greaves : Added sysctl option to ignore bogus broadcast
+ * responses from broken routers.
+ *
+ * To Fix:
+ *
+ * - Should use skb_pull() instead of all the manual checking.
+ * This would also greatly simply some upper layer error handlers. --AK
+ *
+ * RFC1122 (Host Requirements -- Comm. Layer) Status:
+ * (boy, are there a lot of rules for ICMP)
+ * 3.2.2 (Generic ICMP stuff)
+ * MUST discard messages of unknown type. (OK)
+ * MUST copy at least the first 8 bytes from the offending packet
+ * when sending ICMP errors. (OBSOLETE -- see RFC1812)
+ * MUST pass received ICMP errors up to protocol level. (OK)
+ * SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812)
+ * MUST NOT send ICMP errors in reply to:
+ * ICMP errors (OK)
+ * Broadcast/multicast datagrams (OK)
+ * MAC broadcasts (OK)
+ * Non-initial fragments (OK)
+ * Datagram with a source address that isn't a single host. (OK)
+ * 3.2.2.1 (Destination Unreachable)
+ * All the rules govern the IP layer, and are dealt with in ip.c, not here.
+ * 3.2.2.2 (Redirect)
+ * Host SHOULD NOT send ICMP_REDIRECTs. (OK)
+ * MUST update routing table in response to host or network redirects.
+ * (host OK, network OBSOLETE)
+ * SHOULD drop redirects if they're not from directly connected gateway
+ * (OK -- we drop it if it's not from our old gateway, which is close
+ * enough)
+ * 3.2.2.3 (Source Quench)
+ * MUST pass incoming SOURCE_QUENCHs to transport layer (OK)
+ * Other requirements are dealt with at the transport layer.
+ * 3.2.2.4 (Time Exceeded)
+ * MUST pass TIME_EXCEEDED to transport layer (OK)
+ * Other requirements dealt with at IP (generating TIME_EXCEEDED).
+ * 3.2.2.5 (Parameter Problem)
+ * SHOULD generate these (OK)
+ * MUST pass received PARAMPROBLEM to transport layer (NOT YET)
+ * [Solaris 2.X seems to assert EPROTO when this occurs] -- AC
+ * 3.2.2.6 (Echo Request/Reply)
+ * MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK)
+ * MAY discard broadcast ECHO_REQUESTs. (Configurable with a sysctl.)
+ * MUST reply using same source address as the request was sent to.
+ * We're OK for unicast ECHOs, and it doesn't say anything about
+ * how to handle broadcast ones, since it's optional.
+ * MUST copy data from REQUEST to REPLY (OK)
+ * unless it would require illegal fragmentation (OK)
+ * MUST pass REPLYs to transport/user layer (OK)
+ * MUST use any provided source route (reversed) for REPLY. (NOT YET)
+ * 3.2.2.7 (Information Request/Reply)
+ * MUST NOT implement this. (I guess that means silently discard...?) (OK)
+ * 3.2.2.8 (Timestamp Request/Reply)
+ * MAY implement (OK)
+ * SHOULD be in-kernel for "minimum variability" (OK)
+ * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency)
+ * MUST reply using same source address as the request was sent to. (OK)
+ * MUST reverse source route, as per ECHO (NOT YET)
+ * MUST pass REPLYs to transport/user layer (requires RAW, just like
+ * ECHO) (OK)
+ * MUST update clock for timestamp at least 15 times/sec (OK)
+ * MUST be "correct within a few minutes" (OK)
+ * 3.2.2.9 (Address Mask Request/Reply)
+ * MAY implement (OK)
+ * MUST send a broadcast REQUEST if using this system to set netmask
+ * (OK... we don't use it)
+ * MUST discard received REPLYs if not using this system (OK)
+ * MUST NOT send replies unless specifically made agent for this sort
+ * of thing. (OK)
+ *
+ *
+ * RFC 1812 (IPv4 Router Requirements) Status (even longer):
+ * 4.3.2.1 (Unknown Message Types)
+ * MUST pass messages of unknown type to ICMP user iface or silently discard
+ * them (OK)
+ * 4.3.2.2 (ICMP Message TTL)
+ * MUST initialize TTL when originating an ICMP message (OK)
+ * 4.3.2.3 (Original Message Header)
+ * SHOULD copy as much data from the offending packet as possible without
+ * the length of the ICMP datagram exceeding 576 bytes (OK)
+ * MUST leave original IP header of the offending packet, but we're not
+ * required to undo modifications made (OK)
+ * 4.3.2.4 (Original Message Source Address)
+ * MUST use one of addresses for the interface the orig. packet arrived as
+ * source address (OK)
+ * 4.3.2.5 (TOS and Precedence)
+ * SHOULD leave TOS set to the same value unless the packet would be
+ * discarded for that reason (OK)
+ * MUST use TOS=0 if not possible to leave original value (OK)
+ * MUST leave IP Precedence for Source Quench messages (OK -- not sent
+ * at all)
+ * SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control)
+ * for all other error messages (OK, we use 6)
+ * MAY allow configuration of IP Precedence (OK -- not done)
+ * MUST leave IP Precedence and TOS for reply messages (OK)
+ * 4.3.2.6 (Source Route)
+ * SHOULD use reverse source route UNLESS sending Parameter Problem on source
+ * routing and UNLESS the packet would be immediately discarded (NOT YET)
+ * 4.3.2.7 (When Not to Send ICMP Errors)
+ * MUST NOT send ICMP errors in reply to:
+ * ICMP errors (OK)
+ * Packets failing IP header validation tests unless otherwise noted (OK)
+ * Broadcast/multicast datagrams (OK)
+ * MAC broadcasts (OK)
+ * Non-initial fragments (OK)
+ * Datagram with a source address that isn't a single host. (OK)
+ * 4.3.2.8 (Rate Limiting)
+ * SHOULD be able to limit error message rate (OK)
+ * SHOULD allow setting of rate limits (OK, in the source)
+ * 4.3.3.1 (Destination Unreachable)
+ * All the rules govern the IP layer, and are dealt with in ip.c, not here.
+ * 4.3.3.2 (Redirect)
+ * MAY ignore ICMP Redirects if running a routing protocol or if forwarding
+ * is enabled on the interface (OK -- ignores)
+ * 4.3.3.3 (Source Quench)
+ * SHOULD NOT originate SQ messages (OK)
+ * MUST be able to limit SQ rate if originates them (OK as we don't
+ * send them)
+ * MAY ignore SQ messages it receives (OK -- we don't)
+ * 4.3.3.4 (Time Exceeded)
+ * Requirements dealt with at IP (generating TIME_EXCEEDED).
+ * 4.3.3.5 (Parameter Problem)
+ * MUST generate these for all errors not covered by other messages (OK)
+ * MUST include original value of the value pointed by (OK)
+ * 4.3.3.6 (Echo Request)
+ * MUST implement echo server function (OK)
+ * MUST process at ER of at least max(576, MTU) (OK)
+ * MAY reject broadcast/multicast ER's (We don't, but that's OK)
+ * SHOULD have a config option for silently ignoring ER's (OK)
+ * MUST have a default value for the above switch = NO (OK)
+ * MUST have application layer interface for Echo Request/Reply (OK)
+ * MUST reply using same source address as the request was sent to.
+ * We're OK for unicast ECHOs, and it doesn't say anything about
+ * how to handle broadcast ones, since it's optional.
+ * MUST copy data from Request to Reply (OK)
+ * SHOULD update Record Route / Timestamp options (??)
+ * MUST use reversed Source Route for Reply if possible (NOT YET)
+ * 4.3.3.7 (Information Request/Reply)
+ * SHOULD NOT originate or respond to these (OK)
+ * 4.3.3.8 (Timestamp / Timestamp Reply)
+ * MAY implement (OK)
+ * MUST reply to every Timestamp message received (OK)
+ * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency)
+ * MUST reply using same source address as the request was sent to. (OK)
+ * MUST use reversed Source Route if possible (NOT YET)
+ * SHOULD update Record Route / Timestamp options (??)
+ * MUST pass REPLYs to transport/user layer (requires RAW, just like
+ * ECHO) (OK)
+ * MUST update clock for timestamp at least 16 times/sec (OK)
+ * MUST be "correct within a few minutes" (OK)
+ * 4.3.3.9 (Address Mask Request/Reply)
+ * MUST have support for receiving AMRq and responding with AMRe (OK,
+ * but only as a compile-time option)
+ * SHOULD have option for each interface for AMRe's, MUST default to
+ * NO (NOT YET)
+ * MUST NOT reply to AMRq before knows the correct AM (OK)
+ * MUST NOT respond to AMRq with source address 0.0.0.0 on physical
+ * interfaces having multiple logical i-faces with different masks
+ * (NOT YET)
+ * SHOULD examine all AMRe's it receives and check them (NOT YET)
+ * SHOULD log invalid AMRe's (AM+sender) (NOT YET)
+ * MUST NOT use contents of AMRe to determine correct AM (OK)
+ * MAY broadcast AMRe's after having configured address masks (OK -- doesn't)
+ * MUST NOT do broadcast AMRe's if not set by extra option (OK, no option)
+ * MUST use the { <NetPrefix>, -1 } form of broadcast addresses (OK)
+ * 4.3.3.10 (Router Advertisement and Solicitations)
+ * MUST support router part of Router Discovery Protocol on all networks we
+ * support broadcast or multicast addressing. (OK -- done by gated)
+ * MUST have all config parameters with the respective defaults (OK)
+ * 5.2.7.1 (Destination Unreachable)
+ * MUST generate DU's (OK)
+ * SHOULD choose a best-match response code (OK)
+ * SHOULD NOT generate Host Isolated codes (OK)
+ * SHOULD use Communication Administratively Prohibited when administratively
+ * filtering packets (NOT YET -- bug-to-bug compatibility)
+ * MAY include config option for not generating the above and silently
+ * discard the packets instead (OK)
+ * MAY include config option for not generating Precedence Violation and
+ * Precedence Cutoff messages (OK as we don't generate them at all)
+ * MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts
+ * on the same network might be reachable (OK -- no net unreach's at all)
+ * MUST use new form of Fragmentation Needed and DF Set messages (OK)
+ * 5.2.7.2 (Redirect)
+ * MUST NOT generate network redirects (OK)
+ * MUST be able to generate host redirects (OK)
+ * SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS)
+ * MUST have an option to use Host redirects instead of Host+TOS ones (OK as
+ * no Host+TOS Redirects are used)
+ * MUST NOT generate redirects unless forwarding to the same i-face and the
+ * dest. address is on the same subnet as the src. address and no source
+ * routing is in use. (OK)
+ * MUST NOT follow redirects when using a routing protocol (OK)
+ * MAY use redirects if not using a routing protocol (OK, compile-time option)
+ * MUST comply to Host Requirements when not acting as a router (OK)
+ * 5.2.7.3 (Time Exceeded)
+ * MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK)
+ * MAY have a per-interface option to disable origination of TE messages, but
+ * it MUST default to "originate" (OK -- we don't support it)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <net/snmp.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/protocol.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <net/snmp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+/*
+ * Statistics
+ */
+
+struct icmp_mib icmp_statistics;
+
+/* An array of errno for error messages from dest unreach. */
+/* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOS_UNREACH and SR_FAIELD MUST be considered 'transient errs'. */
+
+struct icmp_err icmp_err_convert[] = {
+ { ENETUNREACH, 0 }, /* ICMP_NET_UNREACH */
+ { EHOSTUNREACH, 0 }, /* ICMP_HOST_UNREACH */
+ { ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */
+ { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */
+ { EMSGSIZE, 0 }, /* ICMP_FRAG_NEEDED */
+ { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */
+ { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */
+ { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */
+ { ENONET, 1 }, /* ICMP_HOST_ISOLATED */
+ { ENETUNREACH, 1 }, /* ICMP_NET_ANO */
+ { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */
+ { ENETUNREACH, 0 }, /* ICMP_NET_UNR_TOS */
+ { EHOSTUNREACH, 0 }, /* ICMP_HOST_UNR_TOS */
+ { EHOSTUNREACH, 1 }, /* ICMP_PKT_FILTERED */
+ { EHOSTUNREACH, 1 }, /* ICMP_PREC_VIOLATION */
+ { EHOSTUNREACH, 1 } /* ICMP_PREC_CUTOFF */
+};
+
+/* Control parameters for ECHO relies. */
+int sysctl_icmp_echo_ignore_all = 0;
+int sysctl_icmp_echo_ignore_broadcasts = 0;
+
+/* Control parameter - ignore bogus broadcast responses? */
+int sysctl_icmp_ignore_bogus_error_responses =0;
+
+extern int sysctl_ip_always_defrag;
+
+/*
+ * ICMP control array. This specifies what to do with each ICMP.
+ */
+
+struct icmp_control
+{
+ unsigned long *output; /* Address to increment on output */
+ unsigned long *input; /* Address to increment on input */
+ void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len);
+ short error; /* This ICMP is classed as an error message */
+ int *timeout; /* Rate limit */
+};
+
+static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
+
+/*
+ * Build xmit assembly blocks
+ */
+
+struct icmp_bxm
+{
+ void *data_ptr;
+ int data_len;
+ struct icmphdr icmph;
+ unsigned long csum;
+ struct ip_options replyopts;
+ unsigned char optbuf[40];
+};
+
+/*
+ * The ICMP socket. This is the most convenient way to flow control
+ * our ICMP output as well as maintain a clean interface throughout
+ * all layers. All Socketless IP sends will soon be gone.
+ */
+
+struct inode icmp_inode;
+struct socket *icmp_socket=&icmp_inode.u.socket_i;
+
+/*
+ * Send an ICMP frame.
+ */
+
+/*
+ * Check transmit rate limitation for given message.
+ * The rate information is held in the destination cache now.
+ * This function is generic and could be used for other purposes
+ * too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
+ *
+ * Note that the same dst_entry fields are modified by functions in
+ * route.c too, but these work for packet destinations while xrlim_allow
+ * works for icmp destinations. This means the rate limiting information
+ * for one "ip object" is shared.
+ *
+ * Note that the same dst_entry fields are modified by functions in
+ * route.c too, but these work for packet destinations while xrlim_allow
+ * works for icmp destinations. This means the rate limiting information
+ * for one "ip object" is shared - and these ICMPs are twice limited:
+ * by source and by destination.
+ *
+ * RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
+ * SHOULD allow setting of rate limits
+ *
+ * Shared between ICMPv4 and ICMPv6.
+ */
+#define XRLIM_BURST_FACTOR 6
+int xrlim_allow(struct dst_entry *dst, int timeout)
+{
+ unsigned long now;
+
+ now = jiffies;
+ dst->rate_tokens += now - dst->rate_last;
+ dst->rate_last = now;
+ if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)
+ dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;
+ if (dst->rate_tokens >= timeout) {
+ dst->rate_tokens -= timeout;
+ return 1;
+ }
+ return 0;
+}
+
+static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code)
+{
+ struct dst_entry *dst = &rt->u.dst;
+
+ if (type > NR_ICMP_TYPES || !icmp_pointers[type].timeout)
+ return 1;
+
+ /* Don't limit PMTU discovery. */
+ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
+ return 1;
+
+ /* Redirect has its own rate limit mechanism */
+ if (type == ICMP_REDIRECT)
+ return 1;
+
+ /* No rate limit on loopback */
+ if (dst->dev && (dst->dev->flags&IFF_LOOPBACK))
+ return 1;
+
+ return xrlim_allow(dst, *(icmp_pointers[type].timeout));
+}
+
+/*
+ * Maintain the counters used in the SNMP statistics for outgoing ICMP
+ */
+
+static void icmp_out_count(int type)
+{
+ if (type>NR_ICMP_TYPES)
+ return;
+ (*icmp_pointers[type].output)++;
+ icmp_statistics.IcmpOutMsgs++;
+}
+
+/*
+ * Checksum each fragment, and on the first include the headers and final checksum.
+ */
+
+static int icmp_glue_bits(const void *p, char *to, unsigned int offset, unsigned int fraglen)
+{
+ struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
+ struct icmphdr *icmph;
+ unsigned long csum;
+
+ if (offset) {
+ icmp_param->csum=csum_partial_copy(icmp_param->data_ptr+offset-sizeof(struct icmphdr),
+ to, fraglen,icmp_param->csum);
+ return 0;
+ }
+
+ /*
+ * First fragment includes header. Note that we've done
+ * the other fragments first, so that we get the checksum
+ * for the whole packet here.
+ */
+ csum = csum_partial_copy((void *)&icmp_param->icmph,
+ to, sizeof(struct icmphdr),
+ icmp_param->csum);
+ csum = csum_partial_copy(icmp_param->data_ptr,
+ to+sizeof(struct icmphdr),
+ fraglen-sizeof(struct icmphdr), csum);
+ icmph=(struct icmphdr *)to;
+ icmph->checksum = csum_fold(csum);
+ return 0;
+}
+
+/*
+ * Driving logic for building and sending ICMP messages.
+ */
+
+static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
+{
+ struct sock *sk=icmp_socket->sk;
+ struct ipcm_cookie ipc;
+ struct rtable *rt = (struct rtable*)skb->dst;
+ u32 daddr;
+
+ if (ip_options_echo(&icmp_param->replyopts, skb))
+ return;
+
+ icmp_param->icmph.checksum=0;
+ icmp_param->csum=0;
+ icmp_out_count(icmp_param->icmph.type);
+
+ sk->ip_tos = skb->nh.iph->tos;
+ daddr = ipc.addr = rt->rt_src;
+ ipc.opt = &icmp_param->replyopts;
+ if (ipc.opt->srr)
+ daddr = icmp_param->replyopts.faddr;
+ if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
+ return;
+ ip_build_xmit(sk, icmp_glue_bits, icmp_param,
+ icmp_param->data_len+sizeof(struct icmphdr),
+ &ipc, rt, MSG_DONTWAIT);
+ ip_rt_put(rt);
+}
+
+
+/*
+ * Send an ICMP message in response to a situation
+ *
+ * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
+ * MUST NOT change this header information.
+ * MUST NOT reply to a multicast/broadcast IP address.
+ * MUST NOT reply to a multicast/broadcast MAC address.
+ * MUST reply to only the first fragment.
+ */
+
+void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info)
+{
+ struct iphdr *iph;
+ struct icmphdr *icmph;
+ int room;
+ struct icmp_bxm icmp_param;
+ struct rtable *rt = (struct rtable*)skb_in->dst;
+ struct ipcm_cookie ipc;
+ u32 saddr;
+ u8 tos;
+
+ /*
+ * Find the original header
+ */
+
+ iph = skb_in->nh.iph;
+
+ /*
+ * No replies to physical multicast/broadcast
+ */
+
+ if (skb_in->pkt_type!=PACKET_HOST)
+ return;
+
+ /*
+ * Now check at the protocol level
+ */
+ if (!rt) {
+ if (sysctl_ip_always_defrag == 0 &&
+ net_ratelimit())
+ printk(KERN_DEBUG "icmp_send: destinationless packet\n");
+ return;
+ }
+ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
+ return;
+
+
+ /*
+ * Only reply to fragment 0. We byte re-order the constant
+ * mask for efficiency.
+ */
+
+ if (iph->frag_off&htons(IP_OFFSET))
+ return;
+
+ /*
+ * If we send an ICMP error to an ICMP error a mess would result..
+ */
+
+ if (icmp_pointers[type].error) {
+ /*
+ * We are an error, check if we are replying to an ICMP error
+ */
+
+ if (iph->protocol==IPPROTO_ICMP) {
+ icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+ /*
+ * Assume any unknown ICMP type is an error. This isn't
+ * specified by the RFC, but think about it..
+ */
+ if (icmph->type>NR_ICMP_TYPES || icmp_pointers[icmph->type].error)
+ return;
+ }
+ }
+
+
+ /*
+ * Construct source address and options.
+ */
+
+#ifdef CONFIG_IP_ROUTE_NAT
+ /*
+ * Restore original addresses if packet has been translated.
+ */
+ if (rt->rt_flags&RTCF_NAT && IPCB(skb_in)->flags&IPSKB_TRANSLATED) {
+ iph->daddr = rt->key.dst;
+ iph->saddr = rt->key.src;
+ }
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+ if (type==ICMP_DEST_UNREACH && IPCB(skb_in)->flags&IPSKB_MASQUERADED) {
+ ip_fw_unmasq_icmp(skb_in);
+ }
+#endif
+
+ saddr = iph->daddr;
+ if (!(rt->rt_flags & RTCF_LOCAL))
+ saddr = 0;
+
+ tos = icmp_pointers[type].error ?
+ ((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) :
+ iph->tos;
+
+ /* XXX: use a more aggressive expire for routes created by
+ * this call (not longer than the rate limit timeout).
+ * It could be also worthwhile to not put them into ipv4
+ * fast routing cache at first. Otherwise an attacker can
+ * grow the routing table.
+ */
+ if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
+ return;
+
+ if (ip_options_echo(&icmp_param.replyopts, skb_in))
+ goto ende;
+
+
+ /*
+ * Prepare data for ICMP header.
+ */
+
+ icmp_param.icmph.type=type;
+ icmp_param.icmph.code=code;
+ icmp_param.icmph.un.gateway = info;
+ icmp_param.icmph.checksum=0;
+ icmp_param.csum=0;
+ icmp_param.data_ptr=iph;
+ icmp_out_count(icmp_param.icmph.type);
+ icmp_socket->sk->ip_tos = tos;
+ ipc.addr = iph->saddr;
+ ipc.opt = &icmp_param.replyopts;
+ if (icmp_param.replyopts.srr) {
+ ip_rt_put(rt);
+ if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos), 0))
+ return;
+ }
+
+ if (!icmpv4_xrlim_allow(rt, type, code))
+ goto ende;
+
+ /* RFC says return as much as we can without exceeding 576 bytes. */
+
+ room = rt->u.dst.pmtu;
+ if (room > 576)
+ room = 576;
+ room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
+ room -= sizeof(struct icmphdr);
+
+ icmp_param.data_len=(iph->ihl<<2)+skb_in->len;
+ if (icmp_param.data_len > room)
+ icmp_param.data_len = room;
+
+ ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param,
+ icmp_param.data_len+sizeof(struct icmphdr),
+ &ipc, rt, MSG_DONTWAIT);
+
+ende:
+ ip_rt_put(rt);
+}
+
+
+/*
+ * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.
+ */
+
+static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
+{
+ struct iphdr *iph;
+ int hash;
+ struct inet_protocol *ipprot;
+ unsigned char *dp;
+ struct sock *raw_sk;
+
+ /*
+ * Incomplete header ?
+ * Only checks for the IP header, there should be an
+ * additional check for longer headers in upper levels.
+ */
+
+ if(len<sizeof(struct iphdr)) {
+ icmp_statistics.IcmpInErrors++;
+ return;
+ }
+
+ iph = (struct iphdr *) (icmph + 1);
+ dp = (unsigned char*)iph;
+
+ if(icmph->type==ICMP_DEST_UNREACH) {
+ switch(icmph->code & 15) {
+ case ICMP_NET_UNREACH:
+ break;
+ case ICMP_HOST_UNREACH:
+ break;
+ case ICMP_PROT_UNREACH:
+ break;
+ case ICMP_PORT_UNREACH:
+ break;
+ case ICMP_FRAG_NEEDED:
+ if (ipv4_config.no_pmtu_disc) {
+ if (sysctl_ip_always_defrag == 0 && net_ratelimit())
+ printk(KERN_INFO "ICMP: %d.%d.%d.%d: fragmentation needed and DF set.\n",
+ NIPQUAD(iph->daddr));
+ } else {
+ unsigned short new_mtu;
+ new_mtu = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));
+ if (!new_mtu)
+ return;
+ icmph->un.frag.mtu = htons(new_mtu);
+ }
+ break;
+ case ICMP_SR_FAILED:
+ if (sysctl_ip_always_defrag == 0 && net_ratelimit())
+ printk(KERN_INFO "ICMP: %d.%d.%d.%d: Source Route Failed.\n", NIPQUAD(iph->daddr));
+ break;
+ default:
+ break;
+ }
+ if (icmph->code>NR_ICMP_UNREACH)
+ return;
+ }
+
+ /*
+ * Throw it at our lower layers
+ *
+ * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed header.
+ * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer.
+ * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer.
+ */
+
+ /*
+ * Check the other end isn't violating RFC 1122. Some routers send
+ * bogus responses to broadcast frames. If you see this message
+ * first check your netmask matches at both ends, if it does then
+ * get the other vendor to fix their kit.
+ */
+
+ if (!sysctl_icmp_ignore_bogus_error_responses)
+ {
+
+ if (inet_addr_type(iph->daddr) == RTN_BROADCAST)
+ {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%d.%d.%d.%d sent an invalid ICMP error to a broadcast.\n",
+ NIPQUAD(skb->nh.iph->saddr));
+ return;
+ }
+ }
+
+ /*
+ * Deliver ICMP message to raw sockets. Pretty useless feature?
+ */
+
+ /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
+ hash = iph->protocol & (MAX_INET_PROTOS - 1);
+ if ((raw_sk = raw_v4_htable[hash]) != NULL)
+ {
+ while ((raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr,
+ iph->daddr, skb->dev->ifindex)) != NULL) {
+ raw_err(raw_sk, skb);
+ raw_sk = raw_sk->next;
+ }
+ }
+
+ /*
+ * This can't change while we are doing it.
+ */
+
+ ipprot = (struct inet_protocol *) inet_protos[hash];
+ while(ipprot != NULL) {
+ struct inet_protocol *nextip;
+
+ nextip = (struct inet_protocol *) ipprot->next;
+
+ /*
+ * Pass it off to everyone who wants it.
+ */
+
+ /* RFC1122: OK. Passes appropriate ICMP errors to the */
+ /* appropriate protocol layer (MUST), as per 3.2.2. */
+
+ if (iph->protocol == ipprot->protocol && ipprot->err_handler)
+ ipprot->err_handler(skb, dp, len);
+
+ ipprot = nextip;
+ }
+}
+
+
+/*
+ * Handle ICMP_REDIRECT.
+ */
+
+static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, int len)
+{
+ struct iphdr *iph;
+ unsigned long ip;
+
+ if (len < sizeof(struct iphdr)) {
+ icmp_statistics.IcmpInErrors++;
+ return;
+ }
+
+ /*
+ * Get the copied header of the packet that caused the redirect
+ */
+
+ iph = (struct iphdr *) (icmph + 1);
+ ip = iph->daddr;
+
+ switch(icmph->code & 7) {
+ case ICMP_REDIR_NET:
+ case ICMP_REDIR_NETTOS:
+ /*
+ * As per RFC recommendations now handle it as
+ * a host redirect.
+ */
+
+ case ICMP_REDIR_HOST:
+ case ICMP_REDIR_HOSTTOS:
+ ip_rt_redirect(skb->nh.iph->saddr, ip, icmph->un.gateway, iph->saddr, iph->tos, skb->dev);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Handle ICMP_ECHO ("ping") requests.
+ *
+ * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo requests.
+ * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be included in the reply.
+ * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring echo requests, MUST have default=NOT.
+ * See also WRT handling of options once they are done and working.
+ */
+
+static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, int len)
+{
+ if (!sysctl_icmp_echo_ignore_all) {
+ struct icmp_bxm icmp_param;
+
+ icmp_param.icmph=*icmph;
+ icmp_param.icmph.type=ICMP_ECHOREPLY;
+ icmp_param.data_ptr=(icmph+1);
+ icmp_param.data_len=len;
+ icmp_reply(&icmp_param, skb);
+ }
+}
+
+/*
+ * Handle ICMP Timestamp requests.
+ * RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests.
+ * SHOULD be in the kernel for minimum random latency.
+ * MUST be accurate to a few minutes.
+ * MUST be updated at least at 15Hz.
+ */
+
+static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, int len)
+{
+ struct timeval tv;
+ __u32 times[3]; /* So the new timestamp works on ALPHA's.. */
+ struct icmp_bxm icmp_param;
+
+ /*
+ * Too short.
+ */
+
+ if(len<12) {
+ icmp_statistics.IcmpInErrors++;
+ return;
+ }
+
+ /*
+ * Fill in the current time as ms since midnight UT:
+ */
+
+ do_gettimeofday(&tv);
+ times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+ times[2] = times[1];
+ memcpy((void *)&times[0], icmph+1, 4); /* Incoming stamp */
+ icmp_param.icmph=*icmph;
+ icmp_param.icmph.type=ICMP_TIMESTAMPREPLY;
+ icmp_param.icmph.code=0;
+ icmp_param.data_ptr=&times;
+ icmp_param.data_len=12;
+ icmp_reply(&icmp_param, skb);
+}
+
+
+/*
+ * Handle ICMP_ADDRESS_MASK requests. (RFC950)
+ *
+ * RFC1122 (3.2.2.9). A host MUST only send replies to
+ * ADDRESS_MASK requests if it's been configured as an address mask
+ * agent. Receiving a request doesn't constitute implicit permission to
+ * act as one. Of course, implementing this correctly requires (SHOULD)
+ * a way to turn the functionality on and off. Another one for sysctl(),
+ * I guess. -- MS
+ *
+ * RFC1812 (4.3.3.9). A router MUST implement it.
+ * A router SHOULD have switch turning it on/off.
+ * This switch MUST be ON by default.
+ *
+ * Gratuitous replies, zero-source replies are not implemented,
+ * that complies with RFC. DO NOT implement them!!! All the idea
+ * of broadcast addrmask replies as specified in RFC950 is broken.
+ * The problem is that it is not uncommon to have several prefixes
+ * on one physical interface. Moreover, addrmask agent can even be
+ * not aware of existing another prefixes.
+ * If source is zero, addrmask agent cannot choose correct prefix.
+ * Gratuitous mask announcements suffer from the same problem.
+ * RFC1812 explains it, but still allows to use ADDRMASK,
+ * that is pretty silly. --ANK
+ *
+ * All these rules are so bizarre, that I removed kernel addrmask
+ * support at all. It is wrong, it is obsolete, nobody uses it in
+ * any case. --ANK
+ *
+ * Furthermore you can do it with a usermode address agent program
+ * anyway...
+ */
+
+static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, int len)
+{
+#if 0
+ if (sysctl_ip_always_defrag == 0 && net_ratelimit())
+ printk(KERN_DEBUG "a guy asks for address mask. Who is it?\n");
+#endif
+}
+
+/*
+ * RFC1812 (4.3.3.9). A router SHOULD listen all replies, and complain
+ * loudly if an inconsistency is found.
+ */
+
+static void icmp_address_reply(struct icmphdr *icmph, struct sk_buff *skb, int len)
+{
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct device *dev = skb->dev;
+ struct in_device *in_dev = dev->ip_ptr;
+ struct in_ifaddr *ifa;
+ u32 mask;
+
+ if (!in_dev || !in_dev->ifa_list ||
+ !IN_DEV_LOG_MARTIANS(in_dev) ||
+ !IN_DEV_FORWARD(in_dev) ||
+ len < 4 ||
+ !(rt->rt_flags&RTCF_DIRECTSRC))
+ return;
+
+ mask = *(u32*)&icmph[1];
+ for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
+ if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa))
+ return;
+ }
+ if (sysctl_ip_always_defrag == 0 && net_ratelimit())
+ printk(KERN_INFO "Wrong address mask %08X from %08X/%s\n",
+ ntohl(mask), ntohl(rt->rt_src), dev->name);
+}
+
+static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, int len)
+{
+}
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+/*
+ * Check incoming icmp packets not addressed locally, to check whether
+ * they relate to a (proxying) socket on our system.
+ * Needed for transparent proxying.
+ *
+ * This code is presently ugly and needs cleanup.
+ * Probably should add a chkaddr entry to ipprot to call a chk routine
+ * in udp.c or tcp.c...
+ */
+
+/* This should work with the new hashes now. -DaveM */
+extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
+extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
+
+int icmp_chkaddr(struct sk_buff *skb)
+{
+ struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + skb->nh.iph->ihl*4);
+ struct iphdr *iph = (struct iphdr *) (icmph + 1);
+ void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len) = icmp_pointers[icmph->type].handler;
+
+ if (handler == icmp_unreach || handler == icmp_redirect) {
+ struct sock *sk;
+
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ {
+ struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
+
+ sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex);
+ if (!sk || (sk->state == TCP_LISTEN))
+ return 0;
+ /*
+ * This packet came from us.
+ */
+ return 1;
+ }
+ case IPPROTO_UDP:
+ {
+ struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
+
+ sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex);
+ if (!sk) return 0;
+ if (sk->saddr != iph->saddr && inet_addr_type(iph->saddr) != RTN_LOCAL)
+ return 0;
+ /*
+ * This packet may have come from us.
+ * Assume it did.
+ */
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+#endif
+
+/*
+ * Deal with incoming ICMP packets.
+ */
+
+int icmp_rcv(struct sk_buff *skb, unsigned short len)
+{
+ struct icmphdr *icmph = skb->h.icmph;
+ struct rtable *rt = (struct rtable*)skb->dst;
+
+ icmp_statistics.IcmpInMsgs++;
+
+ /*
+ * 18 is the highest 'known' ICMP type. Anything else is a mystery
+ *
+ * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded.
+ */
+ if(len < sizeof(struct icmphdr) ||
+ ip_compute_csum((unsigned char *) icmph, len) ||
+ icmph->type > NR_ICMP_TYPES)
+ goto error;
+
+ /*
+ * Parse the ICMP message
+ */
+
+ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) {
+ /*
+ * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be
+ * silently ignored (we let user decide with a sysctl).
+ * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently
+ * discarded if to broadcast/multicast.
+ */
+ if (icmph->type == ICMP_ECHO &&
+ sysctl_icmp_echo_ignore_broadcasts) {
+ goto error;
+ }
+ if (icmph->type != ICMP_ECHO &&
+ icmph->type != ICMP_TIMESTAMP &&
+ icmph->type != ICMP_ADDRESS &&
+ icmph->type != ICMP_ADDRESSREPLY) {
+ goto error;
+ }
+ }
+
+ len -= sizeof(struct icmphdr);
+ (*icmp_pointers[icmph->type].input)++;
+ (icmp_pointers[icmph->type].handler)(icmph, skb, len);
+
+drop:
+ kfree_skb(skb);
+ return 0;
+error:
+ icmp_statistics.IcmpInErrors++;
+ goto drop;
+}
+
+/*
+ * A spare long used to speed up statistics updating
+ */
+
+static unsigned long dummy;
+
+/*
+ * Configurable rate limits.
+ * Someone should check if these default values are correct.
+ * Note that these values interact with the routing cache GC timeout.
+ * If you chose them too high they won't take effect, because the
+ * dst_entry gets expired too early. The same should happen when
+ * the cache grows too big.
+ */
+int sysctl_icmp_destunreach_time = 1*HZ;
+int sysctl_icmp_timeexceed_time = 1*HZ;
+int sysctl_icmp_paramprob_time = 1*HZ;
+int sysctl_icmp_echoreply_time = 0; /* don't limit it per default. */
+
+/*
+ * This table is the definition of how we handle ICMP.
+ */
+
+static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
+/* ECHO REPLY (0) */
+ { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, &sysctl_icmp_echoreply_time},
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+/* DEST UNREACH (3) */
+ { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time },
+/* SOURCE QUENCH (4) */
+ { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, },
+/* REDIRECT (5) */
+ { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+/* ECHO (8) */
+ { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0, },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+/* TIME EXCEEDED (11) */
+ { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1, &sysctl_icmp_timeexceed_time },
+/* PARAMETER PROBLEM (12) */
+ { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_unreach, 1, &sysctl_icmp_paramprob_time },
+/* TIMESTAMP (13) */
+ { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0, },
+/* TIMESTAMP REPLY (14) */
+ { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0, },
+/* INFO (15) */
+ { &dummy, &dummy, icmp_discard, 0, },
+/* INFO REPLY (16) */
+ { &dummy, &dummy, icmp_discard, 0, },
+/* ADDR MASK (17) */
+ { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0, },
+/* ADDR MASK REPLY (18) */
+ { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_address_reply, 0, }
+};
+
+__initfunc(void icmp_init(struct net_proto_family *ops))
+{
+ int err;
+
+ icmp_inode.i_mode = S_IFSOCK;
+ icmp_inode.i_sock = 1;
+ icmp_inode.i_uid = 0;
+ icmp_inode.i_gid = 0;
+
+ icmp_socket->inode = &icmp_inode;
+ icmp_socket->state = SS_UNCONNECTED;
+ icmp_socket->type=SOCK_RAW;
+
+ if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0)
+ panic("Failed to create the ICMP control socket.\n");
+ icmp_socket->sk->allocation=GFP_ATOMIC;
+ icmp_socket->sk->num = 256; /* Don't receive any data */
+ icmp_socket->sk->ip_ttl = MAXTTL;
+}
diff --git a/pfinet/linux-src/net/ipv4/igmp.c b/pfinet/linux-src/net/ipv4/igmp.c
new file mode 100644
index 00000000..934e8601
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/igmp.c
@@ -0,0 +1,698 @@
+/*
+ * Linux NET3: Internet Group Management Protocol [IGMP]
+ *
+ * This code implements the IGMP protocol as defined in RFC1112. There has
+ * been a further revision of this protocol since which is now supported.
+ *
+ * If you have trouble with this module be careful what gcc you have used,
+ * the older version didn't come out right using gcc 2.5.8, the newer one
+ * seems to fall out with gcc 2.6.2.
+ *
+ * Version: $Id: igmp.c,v 1.30.2.1 1999/07/23 15:29:22 davem Exp $
+ *
+ * Authors:
+ * Alan Cox <Alan.Cox@linux.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ *
+ * Alan Cox : Added lots of __inline__ to optimise
+ * the memory usage of all the tiny little
+ * functions.
+ * Alan Cox : Dumped the header building experiment.
+ * Alan Cox : Minor tweaks ready for multicast routing
+ * and extended IGMP protocol.
+ * Alan Cox : Removed a load of inline directives. Gcc 2.5.8
+ * writes utterly bogus code otherwise (sigh)
+ * fixed IGMP loopback to behave in the manner
+ * desired by mrouted, fixed the fact it has been
+ * broken since 1.3.6 and cleaned up a few minor
+ * points.
+ *
+ * Chih-Jen Chang : Tried to revise IGMP to Version 2
+ * Tsu-Sheng Tsao E-mail: chihjenc@scf.usc.edu and tsusheng@scf.usc.edu
+ * The enhancements are mainly based on Steve Deering's
+ * ipmulti-3.5 source code.
+ * Chih-Jen Chang : Added the igmp_get_mrouter_info and
+ * Tsu-Sheng Tsao igmp_set_mrouter_info to keep track of
+ * the mrouted version on that device.
+ * Chih-Jen Chang : Added the max_resp_time parameter to
+ * Tsu-Sheng Tsao igmp_heard_query(). Using this parameter
+ * to identify the multicast router version
+ * and do what the IGMP version 2 specified.
+ * Chih-Jen Chang : Added a timer to revert to IGMP V2 router
+ * Tsu-Sheng Tsao if the specified time expired.
+ * Alan Cox : Stop IGMP from 0.0.0.0 being accepted.
+ * Alan Cox : Use GFP_ATOMIC in the right places.
+ * Christian Daudt : igmp timer wasn't set for local group
+ * memberships but was being deleted,
+ * which caused a "del_timer() called
+ * from %p with timer not initialized\n"
+ * message (960131).
+ * Christian Daudt : removed del_timer from
+ * igmp_timer_expire function (960205).
+ * Christian Daudt : igmp_heard_report now only calls
+ * igmp_timer_expire if tm->running is
+ * true (960216).
+ * Malcolm Beattie : ttl comparison wrong in igmp_rcv made
+ * igmp_heard_query never trigger. Expiry
+ * miscalculation fixed in igmp_heard_query
+ * and random() made to return unsigned to
+ * prevent negative expiry times.
+ * Alexey Kuznetsov: Wrong group leaving behaviour, backport
+ * fix from pending 2.1.x patches.
+ * Alan Cox: Forget to enable FDDI support earlier.
+ * Alexey Kuznetsov: Fixed leaving groups on device down.
+ * Alexey Kuznetsov: Accordance to igmp-v2-06 draft.
+ */
+
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/sock.h>
+#include <net/checksum.h>
+#ifdef CONFIG_IP_MROUTE
+#include <linux/mroute.h>
+#endif
+
+#define IP_MAX_MEMBERSHIPS 20
+
+#ifdef CONFIG_IP_MULTICAST
+
+/* Parameter names and values are taken from igmp-v2-06 draft */
+
+#define IGMP_V1_Router_Present_Timeout (400*HZ)
+#define IGMP_Unsolicited_Report_Interval (10*HZ)
+#define IGMP_Query_Response_Interval (10*HZ)
+#define IGMP_Unsolicited_Report_Count 2
+
+
+#define IGMP_Initial_Report_Delay (1*HZ)
+
+/* IGMP_Initial_Report_Delay is not from IGMP specs!
+ * IGMP specs require to report membership immediately after
+ * joining a group, but we delay the first report by a
+ * small interval. It seems more natural and still does not
+ * contradict to specs provided this delay is small enough.
+ */
+
+#define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && (long)(jiffies - (in_dev)->mr_v1_seen) < 0)
+
+/*
+ * Timer management
+ */
+
+static __inline__ void igmp_stop_timer(struct ip_mc_list *im)
+{
+ if (im->tm_running) {
+ del_timer(&im->timer);
+ im->tm_running=0;
+ }
+}
+
+static __inline__ void igmp_start_timer(struct ip_mc_list *im, int max_delay)
+{
+ int tv;
+ if (im->tm_running)
+ return;
+ tv=net_random() % max_delay;
+ im->timer.expires=jiffies+tv+2;
+ im->tm_running=1;
+ add_timer(&im->timer);
+}
+
+/*
+ * Send an IGMP report.
+ */
+
+#define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
+
+static int igmp_send_report(struct device *dev, u32 group, int type)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct igmphdr *ih;
+ struct rtable *rt;
+ u32 dst;
+
+ /* According to IGMPv2 specs, LEAVE messages are
+ * sent to all-routers group.
+ */
+ dst = group;
+ if (type == IGMP_HOST_LEAVE_MESSAGE)
+ dst = IGMP_ALL_ROUTER;
+
+ if (ip_route_output(&rt, dst, 0, 0, dev->ifindex))
+ return -1;
+ if (rt->rt_src == 0) {
+ ip_rt_put(rt);
+ return -1;
+ }
+
+ skb=alloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC);
+ if (skb == NULL) {
+ ip_rt_put(rt);
+ return -1;
+ }
+
+ skb->dst = &rt->u.dst;
+
+ skb_reserve(skb, (dev->hard_header_len+15)&~15);
+
+ skb->nh.iph = iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4);
+
+ iph->version = 4;
+ iph->ihl = (sizeof(struct iphdr)+4)>>2;
+ iph->tos = 0;
+ iph->frag_off = 0;
+ iph->ttl = 1;
+ iph->daddr = dst;
+ iph->saddr = rt->rt_src;
+ iph->protocol = IPPROTO_IGMP;
+ iph->tot_len = htons(IGMP_SIZE);
+ iph->id = htons(ip_id_count++);
+ ((u8*)&iph[1])[0] = IPOPT_RA;
+ ((u8*)&iph[1])[1] = 4;
+ ((u8*)&iph[1])[2] = 0;
+ ((u8*)&iph[1])[3] = 0;
+ ip_send_check(iph);
+
+ ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
+ ih->type=type;
+ ih->code=0;
+ ih->csum=0;
+ ih->group=group;
+ ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
+
+ return skb->dst->output(skb);
+}
+
+
+static void igmp_timer_expire(unsigned long data)
+{
+ struct ip_mc_list *im=(struct ip_mc_list *)data;
+ struct in_device *in_dev = im->interface;
+ int err;
+
+ im->tm_running=0;
+
+ if (IGMP_V1_SEEN(in_dev))
+ err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
+ else
+ err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
+
+ /* Failed. Retry later. */
+ if (err) {
+ igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
+ return;
+ }
+
+ if (im->unsolicit_count) {
+ im->unsolicit_count--;
+ igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
+ }
+ im->reporter = 1;
+}
+
+static void igmp_heard_report(struct in_device *in_dev, u32 group)
+{
+ struct ip_mc_list *im;
+
+ /* Timers are only set for non-local groups */
+
+ if (group == IGMP_ALL_HOSTS)
+ return;
+
+ for (im=in_dev->mc_list; im!=NULL; im=im->next) {
+ if (im->multiaddr == group) {
+ igmp_stop_timer(im);
+ im->reporter = 0;
+ im->unsolicit_count = 0;
+ return;
+ }
+ }
+}
+
+static void igmp_heard_query(struct in_device *in_dev, unsigned char max_resp_time,
+ u32 group)
+{
+ struct ip_mc_list *im;
+ int max_delay;
+
+ max_delay = max_resp_time*(HZ/IGMP_TIMER_SCALE);
+
+ if (max_resp_time == 0) {
+ /* Alas, old v1 router presents here. */
+
+ max_delay = IGMP_Query_Response_Interval;
+ in_dev->mr_v1_seen = jiffies + IGMP_V1_Router_Present_Timeout;
+ group = 0;
+ }
+
+ /*
+ * - Start the timers in all of our membership records
+ * that the query applies to for the interface on
+ * which the query arrived excl. those that belong
+ * to a "local" group (224.0.0.X)
+ * - For timers already running check if they need to
+ * be reset.
+ * - Use the igmp->igmp_code field as the maximum
+ * delay possible
+ */
+ for (im=in_dev->mc_list; im!=NULL; im=im->next) {
+ if (group && group != im->multiaddr)
+ continue;
+ if (im->multiaddr == IGMP_ALL_HOSTS)
+ continue;
+ im->unsolicit_count = 0;
+ if (im->tm_running && (long)(im->timer.expires-jiffies) > max_delay)
+ igmp_stop_timer(im);
+ igmp_start_timer(im, max_delay);
+ }
+}
+
+int igmp_rcv(struct sk_buff *skb, unsigned short len)
+{
+ /* This basically follows the spec line by line -- see RFC1112 */
+ struct igmphdr *ih = skb->h.igmph;
+ struct in_device *in_dev = skb->dev->ip_ptr;
+
+ if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)
+ || in_dev==NULL) {
+ kfree_skb(skb);
+ return 0;
+ }
+
+ switch (ih->type) {
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ igmp_heard_query(in_dev, ih->code, ih->group);
+ break;
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
+ /* Is it our report looped back? */
+ if (((struct rtable*)skb->dst)->key.iif == 0)
+ break;
+ igmp_heard_report(in_dev, ih->group);
+ break;
+ case IGMP_PIM:
+#ifdef CONFIG_IP_PIMSM_V1
+ return pim_rcv_v1(skb, len);
+#endif
+ case IGMP_DVMRP:
+ case IGMP_TRACE:
+ case IGMP_HOST_LEAVE_MESSAGE:
+ case IGMP_MTRACE:
+ case IGMP_MTRACE_RESP:
+ break;
+ default:
+ NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type));
+ }
+ kfree_skb(skb);
+ return 0;
+}
+
+#endif
+
+
+/*
+ * Add a filter to a device
+ */
+
+static void ip_mc_filter_add(struct in_device *in_dev, u32 addr)
+{
+ char buf[MAX_ADDR_LEN];
+ struct device *dev = in_dev->dev;
+
+ /* Checking for IFF_MULTICAST here is WRONG-WRONG-WRONG.
+ We will get multicast token leakage, when IFF_MULTICAST
+ is changed. This check should be done in dev->set_multicast_list
+ routine. Something sort of:
+ if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; }
+ --ANK
+ */
+ if (arp_mc_map(addr, buf, dev, 0) == 0)
+ dev_mc_add(dev,buf,dev->addr_len,0);
+}
+
+/*
+ * Remove a filter from a device
+ */
+
+static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
+{
+ char buf[MAX_ADDR_LEN];
+ struct device *dev = in_dev->dev;
+
+ if (arp_mc_map(addr, buf, dev, 0) == 0)
+ dev_mc_delete(dev,buf,dev->addr_len,0);
+}
+
+static void igmp_group_dropped(struct ip_mc_list *im)
+{
+ if (im->loaded) {
+ im->loaded = 0;
+ ip_mc_filter_del(im->interface, im->multiaddr);
+ }
+
+#ifdef CONFIG_IP_MULTICAST
+ if (im->multiaddr == IGMP_ALL_HOSTS)
+ return;
+
+ start_bh_atomic();
+ igmp_stop_timer(im);
+ end_bh_atomic();
+
+ if (im->reporter && !IGMP_V1_SEEN(im->interface))
+ igmp_send_report(im->interface->dev, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
+#endif
+}
+
+static void igmp_group_added(struct ip_mc_list *im)
+{
+ if (im->loaded == 0) {
+ im->loaded = 1;
+ ip_mc_filter_add(im->interface, im->multiaddr);
+ }
+
+#ifdef CONFIG_IP_MULTICAST
+ if (im->multiaddr == IGMP_ALL_HOSTS)
+ return;
+
+ start_bh_atomic();
+ igmp_start_timer(im, IGMP_Initial_Report_Delay);
+ end_bh_atomic();
+#endif
+}
+
+
+/*
+ * Multicast list managers
+ */
+
+
+/*
+ * A socket has joined a multicast group on device dev.
+ */
+
+void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
+{
+ struct ip_mc_list *i, *im;
+
+ im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL);
+
+ for (i=in_dev->mc_list; i; i=i->next) {
+ if (i->multiaddr == addr) {
+ i->users++;
+ if (im)
+ kfree(im);
+ return;
+ }
+ }
+ if (!im)
+ return;
+ im->users=1;
+ im->interface=in_dev;
+ im->multiaddr=addr;
+#ifdef CONFIG_IP_MULTICAST
+ im->tm_running=0;
+ init_timer(&im->timer);
+ im->timer.data=(unsigned long)im;
+ im->timer.function=&igmp_timer_expire;
+ im->unsolicit_count = IGMP_Unsolicited_Report_Count;
+ im->reporter = 0;
+ im->loaded = 0;
+#endif
+ im->next=in_dev->mc_list;
+ in_dev->mc_list=im;
+ igmp_group_added(im);
+ if (in_dev->dev->flags & IFF_UP)
+ ip_rt_multicast_event(in_dev);
+ return;
+}
+
+/*
+ * A socket has left a multicast group on device dev
+ */
+
+int ip_mc_dec_group(struct in_device *in_dev, u32 addr)
+{
+ struct ip_mc_list *i, **ip;
+
+ for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
+ if (i->multiaddr==addr) {
+ if (--i->users == 0) {
+ *ip = i->next;
+ synchronize_bh();
+
+ igmp_group_dropped(i);
+ if (in_dev->dev->flags & IFF_UP)
+ ip_rt_multicast_event(in_dev);
+ kfree_s(i, sizeof(*i));
+ }
+ return 0;
+ }
+ }
+ return -ESRCH;
+}
+
+/* Device going down */
+
+void ip_mc_down(struct in_device *in_dev)
+{
+ struct ip_mc_list *i;
+
+ for (i=in_dev->mc_list; i; i=i->next)
+ igmp_group_dropped(i);
+
+ ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
+}
+
+/* Device going up */
+
+void ip_mc_up(struct in_device *in_dev)
+{
+ struct ip_mc_list *i;
+
+ ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
+
+ for (i=in_dev->mc_list; i; i=i->next)
+ igmp_group_added(i);
+}
+
+/*
+ * Device is about to be destroyed: clean up.
+ */
+
+void ip_mc_destroy_dev(struct in_device *in_dev)
+{
+ struct ip_mc_list *i;
+
+ while ((i = in_dev->mc_list) != NULL) {
+ in_dev->mc_list = i->next;
+ igmp_group_dropped(i);
+ kfree_s(i, sizeof(*i));
+ }
+}
+
+static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
+{
+ struct rtable *rt;
+ struct device *dev = NULL;
+
+ if (imr->imr_address.s_addr) {
+ dev = ip_dev_find(imr->imr_address.s_addr);
+ if (!dev)
+ return NULL;
+ }
+
+ if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) {
+ dev = rt->u.dst.dev;
+ ip_rt_put(rt);
+ }
+ if (dev) {
+ imr->imr_ifindex = dev->ifindex;
+ return dev->ip_ptr;
+ }
+ return NULL;
+}
+
+/*
+ * Join a socket to a group
+ */
+int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
+
+int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
+{
+ int err;
+ u32 addr = imr->imr_multiaddr.s_addr;
+ struct ip_mc_socklist *iml, *i;
+ struct in_device *in_dev;
+ int count = 0;
+
+ if (!MULTICAST(addr))
+ return -EINVAL;
+
+ rtnl_shlock();
+
+ if (!imr->imr_ifindex)
+ in_dev = ip_mc_find_dev(imr);
+ else
+ in_dev = inetdev_by_index(imr->imr_ifindex);
+
+ if (!in_dev) {
+ iml = NULL;
+ err = -ENODEV;
+ goto done;
+ }
+
+ iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
+
+ err = -EADDRINUSE;
+ for (i=sk->ip_mc_list; i; i=i->next) {
+ if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {
+ /* New style additions are reference counted */
+ if (imr->imr_address.s_addr == 0) {
+ i->count++;
+ err = 0;
+ }
+ goto done;
+ }
+ count++;
+ }
+ err = -ENOBUFS;
+ if (iml == NULL || count >= sysctl_igmp_max_memberships)
+ goto done;
+ memcpy(&iml->multi, imr, sizeof(*imr));
+ iml->next = sk->ip_mc_list;
+ iml->count = 1;
+ sk->ip_mc_list = iml;
+ ip_mc_inc_group(in_dev, addr);
+ iml = NULL;
+ err = 0;
+done:
+ rtnl_shunlock();
+ if (iml)
+ sock_kfree_s(sk, iml, sizeof(*iml));
+ return err;
+}
+
+/*
+ * Ask a socket to leave a group.
+ */
+
+int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
+{
+ struct ip_mc_socklist *iml, **imlp;
+
+ for (imlp=&sk->ip_mc_list; (iml=*imlp)!=NULL; imlp=&iml->next) {
+ if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr &&
+ iml->multi.imr_address.s_addr==imr->imr_address.s_addr &&
+ (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) {
+ struct in_device *in_dev;
+ if (--iml->count)
+ return 0;
+
+ *imlp = iml->next;
+ synchronize_bh();
+
+ in_dev = inetdev_by_index(iml->multi.imr_ifindex);
+ if (in_dev)
+ ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr);
+ sock_kfree_s(sk, iml, sizeof(*iml));
+ return 0;
+ }
+ }
+ return -EADDRNOTAVAIL;
+}
+
+/*
+ * A socket is closing.
+ */
+
+void ip_mc_drop_socket(struct sock *sk)
+{
+ struct ip_mc_socklist *iml;
+
+ while ((iml=sk->ip_mc_list) != NULL) {
+ struct in_device *in_dev;
+ sk->ip_mc_list = iml->next;
+ if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL)
+ ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
+ sock_kfree_s(sk, iml, sizeof(*iml));
+ }
+}
+
+
+#ifdef CONFIG_IP_MULTICAST
+
+int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ off_t pos=0, begin=0;
+ struct ip_mc_list *im;
+ int len=0;
+ struct device *dev;
+
+ len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
+
+ for(dev = dev_base; dev; dev = dev->next)
+ {
+ struct in_device *in_dev = dev->ip_ptr;
+ char *querier = "NONE";
+
+ if (in_dev == NULL)
+ continue;
+
+ querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
+
+ len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
+ dev->ifindex, dev->name, dev->mc_count, querier);
+
+ for (im = in_dev->mc_list; im; im = im->next) {
+ len+=sprintf(buffer+len,
+ "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
+ im->multiaddr, im->users,
+ im->tm_running, im->timer.expires-jiffies, im->reporter);
+
+ pos=begin+len;
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ goto done;
+ }
+ }
+done:
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ if(len<0)
+ len=0;
+ return len;
+}
+#endif
+
diff --git a/pfinet/linux-src/net/ipv4/ip_forward.c b/pfinet/linux-src/net/ipv4/ip_forward.c
new file mode 100644
index 00000000..fd8c0435
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_forward.c
@@ -0,0 +1,292 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * The IP forwarding functionality.
+ *
+ * Version: $Id: ip_forward.c,v 1.43.2.1 1999/11/16 06:33:43 davem Exp $
+ *
+ * Authors: see ip.c
+ *
+ * Fixes:
+ * Joseph Gooch : Removed maddr selection for ip_masq, now done in ip_masq.c
+ * Many : Split from ip.c , see ip_input.c for
+ * history.
+ * Dave Gregorich : NULL ip_rt_put fix for multicast
+ * routing.
+ * Jos Vos : Add call_out_firewall before sending,
+ * use output device for accounting.
+ * Jos Vos : Call forward firewall after routing
+ * (always use output device).
+ * Mike McLagan : Routing by source
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/icmp.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/firewall.h>
+#include <linux/ip_fw.h>
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
+#include <net/checksum.h>
+#include <linux/route.h>
+#include <net/route.h>
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+/*
+ * Check the packet against our socket administration to see
+ * if it is related to a connection on our system.
+ * Needed for transparent proxying.
+ */
+
+int ip_chksock(struct sk_buff *skb)
+{
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_ICMP:
+ return icmp_chkaddr(skb);
+ case IPPROTO_TCP:
+ return tcp_chkaddr(skb);
+ case IPPROTO_UDP:
+ return udp_chkaddr(skb);
+ default:
+ return 0;
+ }
+}
+#endif
+
+
+int ip_forward(struct sk_buff *skb)
+{
+ struct device *dev2; /* Output device */
+ struct iphdr *iph; /* Our header */
+ struct rtable *rt; /* Route we use */
+ struct ip_options * opt = &(IPCB(skb)->opt);
+ unsigned short mtu;
+#if defined(CONFIG_FIREWALL) || defined(CONFIG_IP_MASQUERADE)
+ int fw_res = 0;
+#endif
+
+ if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
+ return 0;
+
+ if (skb->pkt_type != PACKET_HOST)
+ goto drop;
+
+ /*
+ * According to the RFC, we must first decrease the TTL field. If
+ * that reaches zero, we must reply an ICMP control message telling
+ * that the packet's lifetime expired.
+ */
+
+ iph = skb->nh.iph;
+ rt = (struct rtable*)skb->dst;
+
+#ifdef CONFIG_CPU_IS_SLOW
+ if (net_cpu_congestion > 1 && !(iph->tos&IPTOS_RELIABILITY) &&
+ IPTOS_PREC(iph->tos) < IPTOS_PREC_INTERNETCONTROL) {
+ if (((xtime.tv_usec&0xF)<<net_cpu_congestion) > 0x1C)
+ goto drop;
+ }
+#endif
+
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (ip_chksock(skb))
+ goto local_pkt;
+#endif
+
+ if (iph->ttl <= 1)
+ goto too_many_hops;
+
+ if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
+ goto sr_failed;
+
+ /*
+ * Having picked a route we can now send the frame out
+ * after asking the firewall permission to do so.
+ */
+
+ skb->priority = rt_tos2priority(iph->tos);
+ dev2 = rt->u.dst.dev;
+ mtu = rt->u.dst.pmtu;
+
+#ifdef CONFIG_NET_SECURITY
+ call_fw_firewall(PF_SECURITY, dev2, NULL, &mtu, NULL);
+#endif
+
+ /*
+ * We now generate an ICMP HOST REDIRECT giving the route
+ * we calculated.
+ */
+ if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)
+ ip_rt_send_redirect(skb);
+
+ /* We are about to mangle packet. Copy it! */
+ if ((skb = skb_cow(skb, dev2->hard_header_len)) == NULL)
+ return -1;
+ iph = skb->nh.iph;
+ opt = &(IPCB(skb)->opt);
+
+ /* Decrease ttl after skb cow done */
+ ip_decrease_ttl(iph);
+
+ /*
+ * We now may allocate a new buffer, and copy the datagram into it.
+ * If the indicated interface is up and running, kick it.
+ */
+
+ if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF))
+ goto frag_needed;
+
+#ifdef CONFIG_IP_ROUTE_NAT
+ if (rt->rt_flags & RTCF_NAT) {
+ if (ip_do_nat(skb)) {
+ kfree_skb(skb);
+ return -1;
+ }
+ }
+#endif
+
+#ifdef CONFIG_IP_MASQUERADE
+ if(!(IPCB(skb)->flags&IPSKB_MASQUERADED)) {
+ /*
+ * Check that any ICMP packets are not for a
+ * masqueraded connection. If so rewrite them
+ * and skip the firewall checks
+ */
+ if (iph->protocol == IPPROTO_ICMP) {
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ struct icmphdr *icmph = (struct icmphdr *)((char*)iph + (iph->ihl << 2));
+ if ((icmph->type==ICMP_DEST_UNREACH)||
+ (icmph->type==ICMP_SOURCE_QUENCH)||
+ (icmph->type==ICMP_TIME_EXCEEDED))
+ {
+#endif
+ fw_res = ip_fw_masquerade(&skb, 0);
+ if (fw_res < 0) {
+ kfree_skb(skb);
+ return -1;
+ }
+
+ if (fw_res)
+ /* ICMP matched - skip firewall */
+ goto skip_call_fw_firewall;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ }
+#endif
+ }
+ if (rt->rt_flags&RTCF_MASQ)
+ goto skip_call_fw_firewall;
+#endif /* CONFIG_IP_MASQUERADE */
+
+#ifdef CONFIG_FIREWALL
+ fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL, &skb);
+ switch (fw_res) {
+ case FW_ACCEPT:
+ case FW_MASQUERADE:
+ break;
+ case FW_REJECT:
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
+ /* fall thru */
+ default:
+ kfree_skb(skb);
+ return -1;
+ }
+#endif
+
+#ifdef CONFIG_IP_MASQUERADE
+ }
+
+skip_call_fw_firewall:
+ /*
+ * If this fragment needs masquerading, make it so...
+ * (Don't masquerade de-masqueraded fragments)
+ */
+ if (!(IPCB(skb)->flags&IPSKB_MASQUERADED) &&
+ (fw_res==FW_MASQUERADE || rt->rt_flags&RTCF_MASQ)) {
+ u32 maddr = 0;
+
+#ifdef CONFIG_IP_ROUTE_NAT
+ maddr = (rt->rt_flags&RTCF_MASQ) ? rt->rt_src_map : 0;
+#endif
+ if (ip_fw_masquerade(&skb, maddr) < 0) {
+ kfree_skb(skb);
+ return -1;
+ } else {
+ /*
+ * Masquerader may have changed skb
+ */
+ iph = skb->nh.iph;
+ opt = &(IPCB(skb)->opt);
+ }
+ }
+#endif
+
+
+#ifdef CONFIG_FIREWALL
+ if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL,&skb)) < FW_ACCEPT) {
+ /* FW_ACCEPT and FW_MASQUERADE are treated equal:
+ masquerading is only supported via forward rules */
+ if (fw_res == FW_REJECT)
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
+ kfree_skb(skb);
+ return -1;
+ }
+#endif
+
+ ip_statistics.IpForwDatagrams++;
+
+ if (opt->optlen == 0) {
+#ifdef CONFIG_NET_FASTROUTE
+ if (rt->rt_flags&RTCF_FAST && !netdev_fastroute_obstacles) {
+ unsigned h = ((*(u8*)&rt->key.dst)^(*(u8*)&rt->key.src))&NETDEV_FASTROUTE_HMASK;
+ /* Time to switch to functional programming :-) */
+ dst_release_irqwait(xchg(&skb->dev->fastpath[h], dst_clone(&rt->u.dst)));
+ }
+#endif
+ ip_send(skb);
+ return 0;
+ }
+
+ ip_forward_options(skb);
+ ip_send(skb);
+ return 0;
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+local_pkt:
+ return ip_local_deliver(skb);
+#endif
+
+frag_needed:
+ ip_statistics.IpFragFails++;
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+ goto drop;
+
+sr_failed:
+ /*
+ * Strict routing permits no gatewaying
+ */
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
+ goto drop;
+
+too_many_hops:
+ /* Tell the sender its packet died... */
+ icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
+drop:
+ kfree_skb(skb);
+ return -1;
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_fragment.c b/pfinet/linux-src/net/ipv4/ip_fragment.c
new file mode 100644
index 00000000..f066e607
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_fragment.c
@@ -0,0 +1,593 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * The IP fragmentation functionality.
+ *
+ * Version: $Id: ip_fragment.c,v 1.40 1999/03/20 23:58:34 davem Exp $
+ *
+ * Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
+ * Alan Cox <Alan.Cox@linux.org>
+ *
+ * Fixes:
+ * Alan Cox : Split from ip.c , see ip_input.c for history.
+ * David S. Miller : Begin massive cleanup...
+ * Andi Kleen : Add sysctls.
+ * xxxx : Overlapfrag bug.
+ * Ultima : ip_expire() kernel panic.
+ * Bill Hawes : Frag accounting and evictor fixes.
+ * John McDonald : 0 length frag bug.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/inet.h>
+#include <linux/firewall.h>
+#include <linux/ip_fw.h>
+
+/* Fragment cache limits. We will commit 256K at one time. Should we
+ * cross that limit we will prune down to 192K. This should cope with
+ * even the most extreme cases without allowing an attacker to measurably
+ * harm machine performance.
+ */
+int sysctl_ipfrag_high_thresh = 256*1024;
+int sysctl_ipfrag_low_thresh = 192*1024;
+
+int sysctl_ipfrag_time = IP_FRAG_TIME;
+
+/* Describe an IP fragment. */
+struct ipfrag {
+ int offset; /* offset of fragment in IP datagram */
+ int end; /* last byte of data in datagram */
+ int len; /* length of this fragment */
+ struct sk_buff *skb; /* complete received fragment */
+ unsigned char *ptr; /* pointer into real fragment data */
+ struct ipfrag *next; /* linked list pointers */
+ struct ipfrag *prev;
+};
+
+/* Describe an entry in the "incomplete datagrams" queue. */
+struct ipq {
+ struct iphdr *iph; /* pointer to IP header */
+ struct ipq *next; /* linked list pointers */
+ struct ipfrag *fragments; /* linked list of received fragments */
+ int len; /* total length of original datagram */
+ short ihlen; /* length of the IP header */
+ struct timer_list timer; /* when will this queue expire? */
+ struct ipq **pprev;
+ struct device *dev; /* Device - for icmp replies */
+};
+
+#define IPQ_HASHSZ 64
+
+struct ipq *ipq_hash[IPQ_HASHSZ];
+
+#define ipqhashfn(id, saddr, daddr, prot) \
+ ((((id) >> 1) ^ (saddr) ^ (daddr) ^ (prot)) & (IPQ_HASHSZ - 1))
+
+atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */
+
+/* Memory Tracking Functions. */
+extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
+{
+ atomic_sub(skb->truesize, &ip_frag_mem);
+ kfree_skb(skb);
+}
+
+extern __inline__ void frag_kfree_s(void *ptr, int len)
+{
+ atomic_sub(len, &ip_frag_mem);
+ kfree(ptr);
+}
+
+extern __inline__ void *frag_kmalloc(int size, int pri)
+{
+ void *vp = kmalloc(size, pri);
+
+ if(!vp)
+ return NULL;
+ atomic_add(size, &ip_frag_mem);
+ return vp;
+}
+
+/* Create a new fragment entry. */
+static struct ipfrag *ip_frag_create(int offset, int end,
+ struct sk_buff *skb, unsigned char *ptr)
+{
+ struct ipfrag *fp;
+
+ fp = (struct ipfrag *) frag_kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
+ if (fp == NULL)
+ goto out_nomem;
+
+ /* Fill in the structure. */
+ fp->offset = offset;
+ fp->end = end;
+ fp->len = end - offset;
+ fp->skb = skb;
+ fp->ptr = ptr;
+ fp->next = fp->prev = NULL;
+
+ /* Charge for the SKB as well. */
+ atomic_add(skb->truesize, &ip_frag_mem);
+
+ return(fp);
+
+out_nomem:
+ NETDEBUG(printk(KERN_ERR "IP: frag_create: no memory left !\n"));
+ return(NULL);
+}
+
+/* Find the correct entry in the "incomplete datagrams" queue for
+ * this IP datagram, and return the queue entry address if found.
+ */
+static inline struct ipq *ip_find(struct iphdr *iph, struct dst_entry *dst)
+{
+ __u16 id = iph->id;
+ __u32 saddr = iph->saddr;
+ __u32 daddr = iph->daddr;
+ __u8 protocol = iph->protocol;
+ unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
+ struct ipq *qp;
+
+ /* Always, we are in a BH context, so no locking. -DaveM */
+ for(qp = ipq_hash[hash]; qp; qp = qp->next) {
+ if(qp->iph->id == id &&
+ qp->iph->saddr == saddr &&
+ qp->iph->daddr == daddr &&
+ qp->iph->protocol == protocol) {
+ del_timer(&qp->timer);
+ break;
+ }
+ }
+ return qp;
+}
+
+/* Remove an entry from the "incomplete datagrams" queue, either
+ * because we completed, reassembled and processed it, or because
+ * it timed out.
+ *
+ * This is called _only_ from BH contexts, on packet reception
+ * processing and from frag queue expiration timers. -DaveM
+ */
+static void ip_free(struct ipq *qp)
+{
+ struct ipfrag *fp;
+
+ /* Stop the timer for this entry. */
+ del_timer(&qp->timer);
+
+ /* Remove this entry from the "incomplete datagrams" queue. */
+ if(qp->next)
+ qp->next->pprev = qp->pprev;
+ *qp->pprev = qp->next;
+
+ /* Release all fragment data. */
+ fp = qp->fragments;
+ while (fp) {
+ struct ipfrag *xp = fp->next;
+
+ frag_kfree_skb(fp->skb);
+ frag_kfree_s(fp, sizeof(struct ipfrag));
+ fp = xp;
+ }
+
+ /* Release the IP header. */
+ frag_kfree_s(qp->iph, 64 + 8);
+
+ /* Finally, release the queue descriptor itself. */
+ frag_kfree_s(qp, sizeof(struct ipq));
+}
+
+/*
+ * Oops, a fragment queue timed out. Kill it and send an ICMP reply.
+ */
+static void ip_expire(unsigned long arg)
+{
+ struct ipq *qp = (struct ipq *) arg;
+
+ if(!qp->fragments)
+ {
+#ifdef IP_EXPIRE_DEBUG
+ printk("warning: possible ip-expire attack\n");
+#endif
+ goto out;
+ }
+
+ /* Send an ICMP "Fragment Reassembly Timeout" message. */
+ ip_statistics.IpReasmTimeout++;
+ ip_statistics.IpReasmFails++;
+ icmp_send(qp->fragments->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+
+out:
+ /* Nuke the fragment queue. */
+ ip_free(qp);
+}
+
+/* Memory limiting on fragments. Evictor trashes the oldest
+ * fragment queue until we are back under the low threshold.
+ */
+static void ip_evictor(void)
+{
+ int i, progress;
+
+restart:
+ progress = 0;
+ /* FIXME: Make LRU queue of frag heads. -DaveM */
+ for (i = 0; i < IPQ_HASHSZ; i++) {
+ struct ipq *qp;
+ if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh)
+ return;
+ /* We are in a BH context, so these queue
+ * accesses are safe. -DaveM
+ */
+ qp = ipq_hash[i];
+ if (qp) {
+ /* find the oldest queue for this hash bucket */
+ while (qp->next)
+ qp = qp->next;
+ ip_free(qp);
+ progress = 1;
+ }
+ }
+ if (progress)
+ goto restart;
+ panic("ip_evictor: memcount");
+}
+
+/* Add an entry to the 'ipq' queue for a newly received IP datagram.
+ * We will (hopefully :-) receive all other fragments of this datagram
+ * in time, so we just create a queue for this datagram, in which we
+ * will insert the received fragments at their respective positions.
+ */
+static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph)
+{
+ struct ipq *qp;
+ unsigned int hash;
+ int ihlen;
+
+ qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
+ if (qp == NULL)
+ goto out_nomem;
+
+ /* Allocate memory for the IP header (plus 8 octets for ICMP). */
+ ihlen = iph->ihl * 4;
+
+ qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC);
+ if (qp->iph == NULL)
+ goto out_free;
+
+ memcpy(qp->iph, iph, ihlen + 8);
+ qp->len = 0;
+ qp->ihlen = ihlen;
+ qp->fragments = NULL;
+ qp->dev = skb->dev;
+
+ /* Initialize a timer for this entry. */
+ init_timer(&qp->timer);
+ qp->timer.expires = 0; /* (to be set later) */
+ qp->timer.data = (unsigned long) qp; /* pointer to queue */
+ qp->timer.function = ip_expire; /* expire function */
+
+ /* Add this entry to the queue. */
+ hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
+
+ /* We are in a BH context, no locking necessary. -DaveM */
+ if((qp->next = ipq_hash[hash]) != NULL)
+ qp->next->pprev = &qp->next;
+ ipq_hash[hash] = qp;
+ qp->pprev = &ipq_hash[hash];
+
+ return qp;
+
+out_free:
+ frag_kfree_s(qp, sizeof(struct ipq));
+out_nomem:
+ NETDEBUG(printk(KERN_ERR "IP: create: no memory left !\n"));
+ return(NULL);
+}
+
+/* See if a fragment queue is complete. */
+static int ip_done(struct ipq *qp)
+{
+ struct ipfrag *fp;
+ int offset;
+
+ /* Only possible if we received the final fragment. */
+ if (qp->len == 0)
+ return 0;
+
+ /* Check all fragment offsets to see if they connect. */
+ fp = qp->fragments;
+ offset = 0;
+ while (fp) {
+ if (fp->offset > offset)
+ return(0); /* fragment(s) missing */
+ offset = fp->end;
+ fp = fp->next;
+ }
+
+ /* All fragments are present. */
+ return 1;
+}
+
+/* Build a new IP datagram from all its fragments.
+ *
+ * FIXME: We copy here because we lack an effective way of handling lists
+ * of bits on input. Until the new skb data handling is in I'm not going
+ * to touch this with a bargepole.
+ */
+static struct sk_buff *ip_glue(struct ipq *qp)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct ipfrag *fp;
+ unsigned char *ptr;
+ int count, len;
+
+ /* Allocate a new buffer for the datagram. */
+ len = qp->ihlen + qp->len;
+
+ if(len > 65535)
+ goto out_oversize;
+
+ skb = dev_alloc_skb(len);
+ if (!skb)
+ goto out_nomem;
+
+ /* Fill in the basic details. */
+ skb->mac.raw = ptr = skb->data;
+ skb->nh.iph = iph = (struct iphdr *) skb_put(skb, len);
+
+ /* Copy the original IP headers into the new buffer. */
+ memcpy(ptr, qp->iph, qp->ihlen);
+ ptr += qp->ihlen;
+
+ /* Copy the data portions of all fragments into the new buffer. */
+ fp = qp->fragments;
+ count = qp->ihlen;
+ while(fp) {
+ if ((fp->len <= 0) || ((count + fp->len) > skb->len))
+ goto out_invalid;
+ memcpy((ptr + fp->offset), fp->ptr, fp->len);
+ if (count == qp->ihlen) {
+ skb->dst = dst_clone(fp->skb->dst);
+ skb->dev = fp->skb->dev;
+ }
+ count += fp->len;
+ fp = fp->next;
+ }
+
+ skb->pkt_type = qp->fragments->skb->pkt_type;
+ skb->protocol = qp->fragments->skb->protocol;
+ /*
+ * Clearly bogus, because security markings of the individual
+ * fragments should have been checked for consistency before
+ * gluing, and intermediate coalescing of fragments may have
+ * taken place in ip_defrag() before ip_glue() ever got called.
+ * If we're not going to do the consistency checking, we might
+ * as well take the value associated with the first fragment.
+ * --rct
+ */
+ skb->security = qp->fragments->skb->security;
+
+ /* Done with all fragments. Fixup the new IP header. */
+ iph = skb->nh.iph;
+ iph->frag_off = 0;
+ iph->tot_len = htons(count);
+ ip_statistics.IpReasmOKs++;
+ return skb;
+
+out_invalid:
+ NETDEBUG(printk(KERN_ERR
+ "Invalid fragment list: Fragment over size.\n"));
+ kfree_skb(skb);
+ goto out_fail;
+out_nomem:
+ NETDEBUG(printk(KERN_ERR
+ "IP: queue_glue: no memory for gluing queue %p\n",
+ qp));
+ goto out_fail;
+out_oversize:
+ if (net_ratelimit())
+ printk(KERN_INFO
+ "Oversized IP packet from %d.%d.%d.%d.\n",
+ NIPQUAD(qp->iph->saddr));
+out_fail:
+ ip_statistics.IpReasmFails++;
+ return NULL;
+}
+
+/* Process an incoming IP datagram fragment. */
+struct sk_buff *ip_defrag(struct sk_buff *skb)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct ipfrag *prev, *next, *tmp, *tfp;
+ struct ipq *qp;
+ unsigned char *ptr;
+ int flags, offset;
+ int i, ihl, end;
+
+ ip_statistics.IpReasmReqds++;
+
+ /* Start by cleaning up the memory. */
+ if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
+ ip_evictor();
+
+ /*
+ * Look for the entry for this IP datagram in the
+ * "incomplete datagrams" queue. If found, the
+ * timer is removed.
+ */
+ qp = ip_find(iph, skb->dst);
+
+ /* Is this a non-fragmented datagram? */
+ offset = ntohs(iph->frag_off);
+ flags = offset & ~IP_OFFSET;
+ offset &= IP_OFFSET;
+
+ offset <<= 3; /* offset is in 8-byte chunks */
+ ihl = iph->ihl * 4;
+
+ /*
+ * Check whether to create a fresh queue entry. If the
+ * queue already exists, its timer will be restarted as
+ * long as we continue to receive fragments.
+ */
+ if (qp) {
+ /* ANK. If the first fragment is received,
+ * we should remember the correct IP header (with options)
+ */
+ if (offset == 0) {
+ /* Fragmented frame replaced by unfragmented copy? */
+ if ((flags & IP_MF) == 0)
+ goto out_freequeue;
+ qp->ihlen = ihl;
+ memcpy(qp->iph, iph, (ihl + 8));
+ }
+ } else {
+ /* Fragmented frame replaced by unfragmented copy? */
+ if ((offset == 0) && ((flags & IP_MF) == 0))
+ goto out_skb;
+
+ /* If we failed to create it, then discard the frame. */
+ qp = ip_create(skb, iph);
+ if (!qp)
+ goto out_freeskb;
+ }
+
+ /* Attempt to construct an oversize packet. */
+ if((ntohs(iph->tot_len) + ((int) offset)) > 65535)
+ goto out_oversize;
+
+ /* Determine the position of this fragment. */
+ end = offset + ntohs(iph->tot_len) - ihl;
+
+ /* Is this the final fragment? */
+ if ((flags & IP_MF) == 0)
+ qp->len = end;
+
+ /* Find out which fragments are in front and at the back of us
+ * in the chain of fragments so far. We must know where to put
+ * this fragment, right?
+ */
+ prev = NULL;
+ for(next = qp->fragments; next != NULL; next = next->next) {
+ if (next->offset >= offset)
+ break; /* bingo! */
+ prev = next;
+ }
+
+ /* Point into the IP datagram 'data' part. */
+ ptr = skb->data + ihl;
+
+ /* We found where to put this one. Check for overlap with
+ * preceding fragment, and, if needed, align things so that
+ * any overlaps are eliminated.
+ */
+ if ((prev != NULL) && (offset < prev->end)) {
+ i = prev->end - offset;
+ offset += i; /* ptr into datagram */
+ ptr += i; /* ptr into fragment data */
+ }
+
+ /* Look for overlap with succeeding segments.
+ * If we can merge fragments, do it.
+ */
+ for (tmp = next; tmp != NULL; tmp = tfp) {
+ tfp = tmp->next;
+ if (tmp->offset >= end)
+ break; /* no overlaps at all */
+
+ i = end - next->offset; /* overlap is 'i' bytes */
+ tmp->len -= i; /* so reduce size of */
+ tmp->offset += i; /* next fragment */
+ tmp->ptr += i;
+
+ /* If we get a frag size of <= 0, remove it and the packet
+ * that it goes with.
+ */
+ if (tmp->len <= 0) {
+ if (tmp->prev != NULL)
+ tmp->prev->next = tmp->next;
+ else
+ qp->fragments = tmp->next;
+
+ if (tmp->next != NULL)
+ tmp->next->prev = tmp->prev;
+
+ /* We have killed the original next frame. */
+ next = tfp;
+
+ frag_kfree_skb(tmp->skb);
+ frag_kfree_s(tmp, sizeof(struct ipfrag));
+ }
+ }
+
+ /*
+ * Create a fragment to hold this skb.
+ * No memory to save the fragment? throw the lot ...
+ */
+ tfp = ip_frag_create(offset, end, skb, ptr);
+ if (!tfp)
+ goto out_freeskb;
+
+ /* Insert this fragment in the chain of fragments. */
+ tfp->prev = prev;
+ tfp->next = next;
+ if (prev != NULL)
+ prev->next = tfp;
+ else
+ qp->fragments = tfp;
+
+ if (next != NULL)
+ next->prev = tfp;
+
+ /* OK, so we inserted this new fragment into the chain.
+ * Check if we now have a full IP datagram which we can
+ * bump up to the IP layer...
+ */
+ if (ip_done(qp)) {
+ /* Glue together the fragments. */
+ skb = ip_glue(qp);
+ /* Free the queue entry. */
+out_freequeue:
+ ip_free(qp);
+out_skb:
+ return skb;
+ }
+
+ /*
+ * The queue is still active ... reset its timer.
+ */
+out_timer:
+ mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time); /* ~ 30 seconds */
+out:
+ return NULL;
+
+ /*
+ * Error exits ... we need to reset the timer if there's a queue.
+ */
+out_oversize:
+ if (net_ratelimit())
+ printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n",
+ NIPQUAD(iph->saddr));
+ /* the skb isn't in a fragment, so fall through to free it */
+out_freeskb:
+ kfree_skb(skb);
+ ip_statistics.IpReasmFails++;
+ if (qp)
+ goto out_timer;
+ goto out;
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_fw.c b/pfinet/linux-src/net/ipv4/ip_fw.c
new file mode 100644
index 00000000..73af70ae
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_fw.c
@@ -0,0 +1,1773 @@
+/*
+ * This code is heavily based on the code on the old ip_fw.c code; see below for
+ * copyrights and attributions of the old code. This code is basically GPL.
+ *
+ * 15-Aug-1997: Major changes to allow graphs for firewall rules.
+ * Paul Russell <Paul.Russell@rustcorp.com.au> and
+ * Michael Neuling <Michael.Neuling@rustcorp.com.au>
+ * 24-Aug-1997: Generalised protocol handling (not just TCP/UDP/ICMP).
+ * Added explicit RETURN from chains.
+ * Removed TOS mangling (done in ipchains 1.0.1).
+ * Fixed read & reset bug by reworking proc handling.
+ * Paul Russell <Paul.Russell@rustcorp.com.au>
+ * 28-Sep-1997: Added packet marking for net sched code.
+ * Removed fw_via comparisons: all done on device name now,
+ * similar to changes in ip_fw.c in DaveM's CVS970924 tree.
+ * Paul Russell <Paul.Russell@rustcorp.com.au>
+ * 2-Nov-1997: Moved types across to __u16, etc.
+ * Added inverse flags.
+ * Fixed fragment bug (in args to port_match).
+ * Changed mark to only one flag (MARKABS).
+ * 21-Nov-1997: Added ability to test ICMP code.
+ * 19-Jan-1998: Added wildcard interfaces.
+ * 6-Feb-1998: Merged 2.0 and 2.1 versions.
+ * Initialised ip_masq for 2.0.x version.
+ * Added explicit NETLINK option for 2.1.x version.
+ * Added packet and byte counters for policy matches.
+ * 26-Feb-1998: Fixed race conditions, added SMP support.
+ * 18-Mar-1998: Fix SMP, fix race condition fix.
+ * 1-May-1998: Remove caching of device pointer.
+ * 12-May-1998: Allow tiny fragment case for TCP/UDP.
+ * 15-May-1998: Treat short packets as fragments, don't just block.
+ * 3-Jan-1999: Fixed serious procfs security hole -- users should never
+ * be allowed to view the chains!
+ * Marc Santoro <ultima@snicker.emoti.com>
+ * 29-Jan-1999: Locally generated bogus IPs dealt with, rather than crash
+ * during dump_packet. --RR.
+ * 19-May-1999: Star Wars: The Phantom Menace opened. Rule num
+ * printed in log (modified from Michael Hasenstein's patch).
+ * Added SYN in log message. --RR
+ * 23-Jul-1999: Fixed small fragment security exposure opened on 15-May-1998.
+ * John McDonald <jm@dataprotect.com>
+ * Thomas Lopatic <tl@dataprotect.com>
+ * 21-Oct-1999: Applied count fix by Emanuele Caratti <wiz@iol.it> --RR
+ */
+
+/*
+ *
+ * The original Linux port was done Alan Cox, with changes/fixes from
+ * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan
+ * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others.
+ *
+ * Copyright from the original FreeBSD version follows:
+ *
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind. */
+
+
+#include <linux/config.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/icmp.h>
+#include <linux/udp.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/ip_masq.h>
+#include <linux/netlink.h>
+#include <linux/init.h>
+#include <linux/firewall.h>
+#include <linux/ip_fw.h>
+
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
+
+#include <net/checksum.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+/* Understanding locking in this code: (thanks to Alan Cox for using
+ * little words to explain this to me). -- PR
+ *
+ * In UP, there can be two packets traversing the chains:
+ * 1) A packet from the current userspace context
+ * 2) A packet off the bh handlers (timer or net).
+ *
+ * For SMP (kernel v2.1+), multiply this by # CPUs.
+ *
+ * [Note that this in not correct for 2.2 - because the socket code always
+ * uses lock_kernel() to serialize, and bottom halves (timers and net_bhs)
+ * only run on one CPU at a time. This will probably change for 2.3.
+ * It is still good to use spinlocks because that avoids the global cli()
+ * for updating the tables, which is rather costly in SMP kernels -AK]
+ *
+ * This means counters and backchains can get corrupted if no precautions
+ * are taken.
+ *
+ * To actually alter a chain on UP, we need only do a cli(), as this will
+ * stop a bh handler firing, as we are in the current userspace context
+ * (coming from a setsockopt()).
+ *
+ * On SMP, we need a write_lock_irqsave(), which is a simple cli() in
+ * UP.
+ *
+ * For backchains and counters, we use an array, indexed by
+ * [cpu_number_map[smp_processor_id()]*2 + !in_interrupt()]; the array is of
+ * size [smp_num_cpus*2]. For v2.0, smp_num_cpus is effectively 1. So,
+ * confident of uniqueness, we modify counters even though we only
+ * have a read lock (to read the counters, you need a write lock,
+ * though). */
+
+/* Why I didn't use straight locking... -- PR
+ *
+ * The backchains can be separated out of the ip_chains structure, and
+ * allocated as needed inside ip_fw_check().
+ *
+ * The counters, however, can't. Trying to lock these means blocking
+ * interrupts every time we want to access them. This would suck HARD
+ * performance-wise. Not locking them leads to possible corruption,
+ * made worse on 32-bit machines (counters are 64-bit). */
+
+/*#define DEBUG_IP_FIREWALL*/
+/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
+/*#define DEBUG_IP_FIREWALL_USER*/
+/*#define DEBUG_IP_FIREWALL_LOCKING*/
+
+#ifdef CONFIG_IP_FIREWALL_NETLINK
+static struct sock *ipfwsk;
+#endif
+
+#ifdef __SMP__
+#define SLOT_NUMBER() (cpu_number_map[smp_processor_id()]*2 + !in_interrupt())
+#else
+#define SLOT_NUMBER() (!in_interrupt())
+#endif
+#define NUM_SLOTS (smp_num_cpus*2)
+
+#define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \
+ + NUM_SLOTS*sizeof(struct ip_reent))
+#define SIZEOF_STRUCT_IP_FW_KERNEL (sizeof(struct ip_fwkernel) \
+ + NUM_SLOTS*sizeof(struct ip_counters))
+
+#ifdef DEBUG_IP_FIREWALL_LOCKING
+static unsigned int fwc_rlocks, fwc_wlocks;
+#define FWC_DEBUG_LOCK(d) \
+do { \
+ FWC_DONT_HAVE_LOCK(d); \
+ d |= (1 << SLOT_NUMBER()); \
+} while (0)
+
+#define FWC_DEBUG_UNLOCK(d) \
+do { \
+ FWC_HAVE_LOCK(d); \
+ d &= ~(1 << SLOT_NUMBER()); \
+} while (0)
+
+#define FWC_DONT_HAVE_LOCK(d) \
+do { \
+ if ((d) & (1 << SLOT_NUMBER())) \
+ printk("%s:%i: Got lock on %i already!\n", \
+ __FILE__, __LINE__, SLOT_NUMBER()); \
+} while(0)
+
+#define FWC_HAVE_LOCK(d) \
+do { \
+ if (!((d) & (1 << SLOT_NUMBER()))) \
+ printk("%s:%i:No lock on %i!\n", \
+ __FILE__, __LINE__, SLOT_NUMBER()); \
+} while (0)
+
+#else
+#define FWC_DEBUG_LOCK(d) do { } while(0)
+#define FWC_DEBUG_UNLOCK(d) do { } while(0)
+#define FWC_DONT_HAVE_LOCK(d) do { } while(0)
+#define FWC_HAVE_LOCK(d) do { } while(0)
+#endif /*DEBUG_IP_FIRWALL_LOCKING*/
+
+#define FWC_READ_LOCK(l) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock(l); } while (0)
+#define FWC_WRITE_LOCK(l) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock(l); } while (0)
+#define FWC_READ_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock_irqsave(l,f); } while (0)
+#define FWC_WRITE_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock_irqsave(l,f); } while (0)
+#define FWC_READ_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock(l); } while (0)
+#define FWC_WRITE_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock(l); } while (0)
+#define FWC_READ_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock_irqrestore(l,f); } while (0)
+#define FWC_WRITE_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock_irqrestore(l,f); } while (0)
+
+struct ip_chain;
+
+struct ip_counters
+{
+ __u64 pcnt, bcnt; /* Packet and byte counters */
+};
+
+struct ip_fwkernel
+{
+ struct ip_fw ipfw;
+ struct ip_fwkernel *next; /* where to go next if current
+ * rule doesn't match */
+ struct ip_chain *branch; /* which branch to jump to if
+ * current rule matches */
+ int simplebranch; /* Use this if branch == NULL */
+ struct ip_counters counters[0]; /* Actually several of these */
+};
+
+struct ip_reent
+{
+ struct ip_chain *prevchain; /* Pointer to referencing chain */
+ struct ip_fwkernel *prevrule; /* Pointer to referencing rule */
+ unsigned int count;
+ struct ip_counters counters;
+};
+
+struct ip_chain
+{
+ ip_chainlabel label; /* Defines the label for each block */
+ struct ip_chain *next; /* Pointer to next block */
+ struct ip_fwkernel *chain; /* Pointer to first rule in block */
+ __u32 refcount; /* Number of references to block */
+ int policy; /* Default rule for chain. Only *
+ * used in built in chains */
+ struct ip_reent reent[0]; /* Actually several of these */
+};
+
+/*
+ * Implement IP packet firewall
+ */
+
+#ifdef DEBUG_IP_FIREWALL
+#define dprintf(format, args...) printk(format , ## args)
+#else
+#define dprintf(format, args...)
+#endif
+
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+/* Lock around ip_fw_chains linked list structure */
+rwlock_t ip_fw_lock = RW_LOCK_UNLOCKED;
+
+/* Head of linked list of fw rules */
+static struct ip_chain *ip_fw_chains;
+
+#define IP_FW_INPUT_CHAIN ip_fw_chains
+#define IP_FW_FORWARD_CHAIN (ip_fw_chains->next)
+#define IP_FW_OUTPUT_CHAIN (ip_fw_chains->next->next)
+
+/* Returns 1 if the port is matched by the range, 0 otherwise */
+extern inline int port_match(__u16 min, __u16 max, __u16 port,
+ int frag, int invert)
+{
+ if (frag) /* Fragments fail ANY port test. */
+ return (min == 0 && max == 0xFFFF);
+ else return (port >= min && port <= max) ^ invert;
+}
+
+/* Returns whether matches rule or not. */
+static int ip_rule_match(struct ip_fwkernel *f,
+ const char *ifname,
+ struct iphdr *ip,
+ char tcpsyn,
+ __u16 src_port, __u16 dst_port,
+ char isfrag)
+{
+#define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg))
+ /*
+ * This is a bit simpler as we don't have to walk
+ * an interface chain as you do in BSD - same logic
+ * however.
+ */
+
+ if (FWINV((ip->saddr&f->ipfw.fw_smsk.s_addr) != f->ipfw.fw_src.s_addr,
+ IP_FW_INV_SRCIP)
+ || FWINV((ip->daddr&f->ipfw.fw_dmsk.s_addr)!=f->ipfw.fw_dst.s_addr,
+ IP_FW_INV_DSTIP)) {
+ dprintf("Source or dest mismatch.\n");
+
+ dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
+ f->ipfw.fw_smsk.s_addr, f->ipfw.fw_src.s_addr,
+ f->ipfw.fw_invflg & IP_FW_INV_SRCIP ? " (INV)" : "");
+ dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
+ f->ipfw.fw_dmsk.s_addr, f->ipfw.fw_dst.s_addr,
+ f->ipfw.fw_invflg & IP_FW_INV_DSTIP ? " (INV)" : "");
+ return 0;
+ }
+
+ /*
+ * Look for a VIA device match
+ */
+ if (f->ipfw.fw_flg & IP_FW_F_WILDIF) {
+ if (FWINV(strncmp(ifname, f->ipfw.fw_vianame,
+ strlen(f->ipfw.fw_vianame)) != 0,
+ IP_FW_INV_VIA)) {
+ dprintf("Wildcard interface mismatch.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_VIA ? " (INV)" : "");
+ return 0; /* Mismatch */
+ }
+ }
+ else if (FWINV(strcmp(ifname, f->ipfw.fw_vianame) != 0,
+ IP_FW_INV_VIA)) {
+ dprintf("Interface name does not match.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_VIA
+ ? " (INV)" : "");
+ return 0; /* Mismatch */
+ }
+
+ /*
+ * Ok the chain addresses match.
+ */
+
+ /* If we have a fragment rule but the packet is not a fragment
+ * the we return zero */
+ if (FWINV((f->ipfw.fw_flg&IP_FW_F_FRAG) && !isfrag, IP_FW_INV_FRAG)) {
+ dprintf("Fragment rule but not fragment.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_FRAG ? " (INV)" : "");
+ return 0;
+ }
+
+ /* Fragment NEVER passes a SYN test, even an inverted one. */
+ if (FWINV((f->ipfw.fw_flg&IP_FW_F_TCPSYN) && !tcpsyn, IP_FW_INV_SYN)
+ || (isfrag && (f->ipfw.fw_flg&IP_FW_F_TCPSYN))) {
+ dprintf("Rule requires SYN and packet has no SYN.%s\n",
+ f->ipfw.fw_invflg & IP_FW_INV_SYN ? " (INV)" : "");
+ return 0;
+ }
+
+ if (f->ipfw.fw_proto) {
+ /*
+ * Specific firewall - packet's protocol
+ * must match firewall's.
+ */
+
+ if (FWINV(ip->protocol!=f->ipfw.fw_proto, IP_FW_INV_PROTO)) {
+ dprintf("Packet protocol %hi does not match %hi.%s\n",
+ ip->protocol, f->ipfw.fw_proto,
+ f->ipfw.fw_invflg&IP_FW_INV_PROTO ? " (INV)":"");
+ return 0;
+ }
+
+ /* For non TCP/UDP/ICMP, port range is max anyway. */
+ if (!port_match(f->ipfw.fw_spts[0],
+ f->ipfw.fw_spts[1],
+ src_port, isfrag,
+ !!(f->ipfw.fw_invflg&IP_FW_INV_SRCPT))
+ || !port_match(f->ipfw.fw_dpts[0],
+ f->ipfw.fw_dpts[1],
+ dst_port, isfrag,
+ !!(f->ipfw.fw_invflg
+ &IP_FW_INV_DSTPT))) {
+ dprintf("Port match failed.\n");
+ return 0;
+ }
+ }
+
+ dprintf("Match succeeded.\n");
+ return 1;
+}
+
+static const char *branchname(struct ip_chain *branch,int simplebranch)
+{
+ if (branch)
+ return branch->label;
+ switch (simplebranch)
+ {
+ case FW_BLOCK: return IP_FW_LABEL_BLOCK;
+ case FW_ACCEPT: return IP_FW_LABEL_ACCEPT;
+ case FW_REJECT: return IP_FW_LABEL_REJECT;
+ case FW_REDIRECT: return IP_FW_LABEL_REDIRECT;
+ case FW_MASQUERADE: return IP_FW_LABEL_MASQUERADE;
+ case FW_SKIP: return "-";
+ case FW_SKIP+1: return IP_FW_LABEL_RETURN;
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/*
+ * VERY ugly piece of code which actually
+ * makes kernel printf for matching packets...
+ */
+static void dump_packet(const struct iphdr *ip,
+ const char *ifname,
+ struct ip_fwkernel *f,
+ const ip_chainlabel chainlabel,
+ __u16 src_port,
+ __u16 dst_port,
+ unsigned int count,
+ int syn)
+{
+ __u32 *opt = (__u32 *) (ip + 1);
+ int opti;
+
+ if (f)
+ {
+ printk(KERN_INFO "Packet log: %s ",chainlabel);
+
+ printk("%s ",branchname(f->branch,f->simplebranch));
+ if (f->simplebranch==FW_REDIRECT)
+ printk("%d ",f->ipfw.fw_redirpt);
+ }
+
+ printk("%s PROTO=%d %d.%d.%d.%d:%hu %d.%d.%d.%d:%hu"
+ " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
+ ifname, ip->protocol,
+ (ntohl(ip->saddr)>>24)&0xFF,
+ (ntohl(ip->saddr)>>16)&0xFF,
+ (ntohl(ip->saddr)>>8)&0xFF,
+ (ntohl(ip->saddr))&0xFF,
+ src_port,
+ (ntohl(ip->daddr)>>24)&0xFF,
+ (ntohl(ip->daddr)>>16)&0xFF,
+ (ntohl(ip->daddr)>>8)&0xFF,
+ (ntohl(ip->daddr))&0xFF,
+ dst_port,
+ ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
+ ntohs(ip->frag_off), ip->ttl);
+
+ for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
+ printk(" O=0x%8.8X", *opt++);
+ printk(" %s(#%d)\n", syn ? "SYN " : /* "PENANCE" */ "", count);
+}
+
+/* function for checking chain labels for user space. */
+static int check_label(ip_chainlabel label)
+{
+ unsigned int i;
+ /* strlen must be < IP_FW_MAX_LABEL_LENGTH. */
+ for (i = 0; i < IP_FW_MAX_LABEL_LENGTH + 1; i++)
+ if (label[i] == '\0') return 1;
+
+ return 0;
+}
+
+/* This function returns a pointer to the first chain with a label
+ * that matches the one given. */
+static struct ip_chain *find_label(ip_chainlabel label)
+{
+ struct ip_chain *tmp;
+ FWC_HAVE_LOCK(fwc_rlocks | fwc_wlocks);
+ for (tmp = ip_fw_chains; tmp; tmp = tmp->next)
+ if (strcmp(tmp->label,label) == 0)
+ break;
+ return tmp;
+}
+
+/* This function returns a boolean which when true sets answer to one
+ of the FW_*. */
+static int find_special(ip_chainlabel label, int *answer)
+{
+ if (label[0] == '\0') {
+ *answer = FW_SKIP; /* => pass-through rule */
+ return 1;
+ } else if (strcmp(label,IP_FW_LABEL_ACCEPT) == 0) {
+ *answer = FW_ACCEPT;
+ return 1;
+ } else if (strcmp(label,IP_FW_LABEL_BLOCK) == 0) {
+ *answer = FW_BLOCK;
+ return 1;
+ } else if (strcmp(label,IP_FW_LABEL_REJECT) == 0) {
+ *answer = FW_REJECT;
+ return 1;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ } else if (strcmp(label,IP_FW_LABEL_REDIRECT) == 0) {
+ extern int sysctl_ip_always_defrag;
+ static int enabled = 0;
+
+ if(!enabled)
+ {
+ enabled=1;
+ sysctl_ip_always_defrag++;
+ }
+ *answer = FW_REDIRECT;
+ return 1;
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+ } else if (strcmp(label,IP_FW_LABEL_MASQUERADE) == 0) {
+ *answer = FW_MASQUERADE;
+ return 1;
+#endif
+ } else if (strcmp(label, IP_FW_LABEL_RETURN) == 0) {
+ *answer = FW_SKIP+1;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* This function cleans up the prevchain and prevrule. If the verbose
+ * flag is set then he names of the chains will be printed as it
+ * cleans up. */
+static void cleanup(struct ip_chain *chain,
+ const int verbose,
+ unsigned int slot)
+{
+ struct ip_chain *tmpchain = chain->reent[slot].prevchain;
+ if (verbose)
+ printk(KERN_ERR "Chain backtrace: ");
+ while (tmpchain) {
+ if (verbose)
+ printk("%s<-",chain->label);
+ chain->reent[slot].prevchain = NULL;
+ chain = tmpchain;
+ tmpchain = chain->reent[slot].prevchain;
+ }
+ if (verbose)
+ printk("%s\n",chain->label);
+}
+
+static inline int
+ip_fw_domatch(struct ip_fwkernel *f,
+ struct iphdr *ip,
+ const char *rif,
+ const ip_chainlabel label,
+ struct sk_buff *skb,
+ unsigned int slot,
+ __u16 src_port, __u16 dst_port,
+ unsigned int count,
+ int tcpsyn)
+{
+ f->counters[slot].bcnt+=ntohs(ip->tot_len);
+ f->counters[slot].pcnt++;
+ if (f->ipfw.fw_flg & IP_FW_F_PRN) {
+ dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn);
+ }
+ ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor;
+
+/* This functionality is useless in stock 2.0.x series, but we don't
+ * discard the mark thing altogether, to avoid breaking ipchains (and,
+ * more importantly, the ipfwadm wrapper) --PR */
+ if (f->ipfw.fw_flg & IP_FW_F_MARKABS)
+ skb->fwmark = f->ipfw.fw_mark;
+ else
+ skb->fwmark+=f->ipfw.fw_mark;
+#ifdef CONFIG_IP_FIREWALL_NETLINK
+ if (f->ipfw.fw_flg & IP_FW_F_NETLINK) {
+ size_t len = min(f->ipfw.fw_outputsize, ntohs(ip->tot_len))
+ + sizeof(__u32) + sizeof(skb->fwmark) + IFNAMSIZ;
+ struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC);
+
+ duprintf("Sending packet out NETLINK (length = %u).\n",
+ (unsigned int)len);
+ if (outskb) {
+ /* Prepend length, mark & interface */
+ skb_put(outskb, len);
+ *((__u32 *)outskb->data) = (__u32)len;
+ *((__u32 *)(outskb->data+sizeof(__u32))) = skb->fwmark;
+ strcpy(outskb->data+sizeof(__u32)*2, rif);
+ memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip,
+ len-(sizeof(__u32)*2+IFNAMSIZ));
+ netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL);
+ }
+ else {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ip_fw: packet drop due to "
+ "netlink failure\n");
+ return 0;
+ }
+ }
+#endif
+ return 1;
+}
+
+/*
+ * Returns one of the generic firewall policies, like FW_ACCEPT.
+ *
+ * The testing is either false for normal firewall mode or true for
+ * user checking mode (counters are not updated, TOS & mark not done).
+ */
+static int
+ip_fw_check(struct iphdr *ip,
+ const char *rif,
+ __u16 *redirport,
+ struct ip_chain *chain,
+ struct sk_buff *skb,
+ unsigned int slot,
+ int testing)
+{
+ struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
+ struct udphdr *udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
+ struct icmphdr *icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
+ __u32 src, dst;
+ __u16 src_port = 0xFFFF, dst_port = 0xFFFF;
+ char tcpsyn=0;
+ __u16 offset;
+ unsigned char oldtos;
+ struct ip_fwkernel *f;
+ int ret = FW_SKIP+2;
+ unsigned int count;
+
+ /* We handle fragments by dealing with the first fragment as
+ * if it was a normal packet. All other fragments are treated
+ * normally, except that they will NEVER match rules that ask
+ * things we don't know, ie. tcp syn flag or ports). If the
+ * rule is also a fragment-specific rule, non-fragments won't
+ * match it. */
+
+ offset = ntohs(ip->frag_off) & IP_OFFSET;
+
+ /*
+ * Don't allow a fragment of TCP 8 bytes in. Nobody
+ * normal causes this. Its a cracker trying to break
+ * in by doing a flag overwrite to pass the direction
+ * checks.
+ */
+
+ if (offset == 1 && ip->protocol == IPPROTO_TCP) {
+ if (!testing && net_ratelimit()) {
+ printk("Suspect TCP fragment.\n");
+ dump_packet(ip,rif,NULL,NULL,0,0,0,0);
+ }
+ return FW_BLOCK;
+ }
+
+ /* If we can't investigate ports, treat as fragment. It's
+ * either a trucated whole packet, or a truncated first
+ * fragment, or a TCP first fragment of length 8-15, in which
+ * case the above rule stops reassembly.
+ */
+ if (offset == 0) {
+ unsigned int size_req;
+ switch (ip->protocol) {
+ case IPPROTO_TCP:
+ /* Don't care about things past flags word */
+ size_req = 16;
+ break;
+
+ case IPPROTO_UDP:
+ case IPPROTO_ICMP:
+ size_req = 8;
+ break;
+
+ default:
+ size_req = 0;
+ }
+ offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req);
+
+ /* If it is a truncated first fragment then it can be
+ * used to rewrite port information, and thus should
+ * be blocked.
+ */
+ if (offset && (ntohs(ip->frag_off) & IP_MF)) {
+ if (!testing && net_ratelimit()) {
+ printk("Suspect short first fragment.\n");
+ dump_packet(ip,rif,NULL,NULL,0,0,0,0);
+ }
+ return FW_BLOCK;
+ }
+ }
+
+ src = ip->saddr;
+ dst = ip->daddr;
+ oldtos = ip->tos;
+
+ /*
+ * If we got interface from which packet came
+ * we can use the address directly. Linux 2.1 now uses address
+ * chains per device too, but unlike BSD we first check if the
+ * incoming packet matches a device address and the routing
+ * table before calling the firewall.
+ */
+
+ dprintf("Packet ");
+ switch(ip->protocol)
+ {
+ case IPPROTO_TCP:
+ dprintf("TCP ");
+ if (!offset) {
+ src_port=ntohs(tcp->source);
+ dst_port=ntohs(tcp->dest);
+
+ /* Connection initilisation can only
+ * be made when the syn bit is set and
+ * neither of the ack or reset is
+ * set. */
+ if(tcp->syn && !(tcp->ack || tcp->rst))
+ tcpsyn=1;
+ }
+ break;
+ case IPPROTO_UDP:
+ dprintf("UDP ");
+ if (!offset) {
+ src_port=ntohs(udp->source);
+ dst_port=ntohs(udp->dest);
+ }
+ break;
+ case IPPROTO_ICMP:
+ if (!offset) {
+ src_port=(__u16)icmp->type;
+ dst_port=(__u16)icmp->code;
+ }
+ dprintf("ICMP ");
+ break;
+ default:
+ dprintf("p=%d ",ip->protocol);
+ break;
+ }
+#ifdef DEBUG_IP_FIREWALL
+ print_ip(ip->saddr);
+
+ if (offset)
+ dprintf(":fragment (%i) ", ((int)offset)<<2);
+ else if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP
+ || ip->protocol==IPPROTO_ICMP)
+ dprintf(":%hu:%hu", src_port, dst_port);
+ dprintf("\n");
+#endif
+
+ if (!testing) FWC_READ_LOCK(&ip_fw_lock);
+ else FWC_HAVE_LOCK(fwc_rlocks);
+
+ f = chain->chain;
+ count = 0;
+ do {
+ for (; f; f = f->next) {
+ count++;
+ if (ip_rule_match(f,rif,ip,
+ tcpsyn,src_port,dst_port,offset)) {
+ if (!testing
+ && !ip_fw_domatch(f, ip, rif, chain->label,
+ skb, slot,
+ src_port, dst_port,
+ count, tcpsyn)) {
+ ret = FW_BLOCK;
+ goto out;
+ }
+ break;
+ }
+ }
+ if (f) {
+ if (f->branch) {
+ /* Do sanity check to see if we have
+ * already set prevchain and if so we
+ * must be in a loop */
+ if (f->branch->reent[slot].prevchain) {
+ if (!testing) {
+ printk(KERN_ERR
+ "IP firewall: "
+ "Loop detected "
+ "at `%s'.\n",
+ f->branch->label);
+ cleanup(chain, 1, slot);
+ ret = FW_BLOCK;
+ } else {
+ cleanup(chain, 0, slot);
+ ret = FW_SKIP+1;
+ }
+ }
+ else {
+ f->branch->reent[slot].prevchain
+ = chain;
+ f->branch->reent[slot].count = count;
+ f->branch->reent[slot].prevrule
+ = f->next;
+ chain = f->branch;
+ f = chain->chain;
+ count = 0;
+ }
+ }
+ else if (f->simplebranch == FW_SKIP)
+ f = f->next;
+ else if (f->simplebranch == FW_SKIP+1) {
+ /* Just like falling off the chain */
+ goto fall_off_chain;
+ }
+ else {
+ cleanup(chain, 0, slot);
+ ret = f->simplebranch;
+ }
+ } /* f == NULL */
+ else {
+ fall_off_chain:
+ if (chain->reent[slot].prevchain) {
+ struct ip_chain *tmp = chain;
+ f = chain->reent[slot].prevrule;
+ count = chain->reent[slot].count;
+ chain = chain->reent[slot].prevchain;
+ tmp->reent[slot].prevchain = NULL;
+ }
+ else {
+ ret = chain->policy;
+ if (!testing) {
+ chain->reent[slot].counters.pcnt++;
+ chain->reent[slot].counters.bcnt
+ += ntohs(ip->tot_len);
+ }
+ }
+ }
+ } while (ret == FW_SKIP+2);
+
+ out:
+ if (!testing) FWC_READ_UNLOCK(&ip_fw_lock);
+
+ /* Recalculate checksum if not going to reject, and TOS changed. */
+ if (ip->tos != oldtos
+ && ret != FW_REJECT && ret != FW_BLOCK
+ && !testing)
+ ip_send_check(ip);
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (ret == FW_REDIRECT && redirport) {
+ if ((*redirport = htons(f->ipfw.fw_redirpt)) == 0) {
+ /* Wildcard redirection.
+ * Note that redirport will become
+ * 0xFFFF for non-TCP/UDP packets.
+ */
+ *redirport = htons(dst_port);
+ }
+ }
+#endif
+
+#ifdef DEBUG_ALLOW_ALL
+ return (testing ? ret : FW_ACCEPT);
+#else
+ return ret;
+#endif
+}
+
+/* Must have write lock & interrupts off for any of these */
+
+/* This function sets all the byte counters in a chain to zero. The
+ * input is a pointer to the chain required for zeroing */
+static int zero_fw_chain(struct ip_chain *chainptr)
+{
+ struct ip_fwkernel *i;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ for (i = chainptr->chain; i; i = i->next)
+ memset(i->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS);
+ return 0;
+}
+
+static int clear_fw_chain(struct ip_chain *chainptr)
+{
+ struct ip_fwkernel *i= chainptr->chain;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ chainptr->chain=NULL;
+
+ while (i) {
+ struct ip_fwkernel *tmp = i->next;
+ if (i->branch)
+ i->branch->refcount--;
+ kfree(i);
+ i = tmp;
+ }
+ return 0;
+}
+
+static int replace_in_chain(struct ip_chain *chainptr,
+ struct ip_fwkernel *frwl,
+ __u32 position)
+{
+ struct ip_fwkernel *f = chainptr->chain;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+
+ while (--position && f != NULL) f = f->next;
+ if (f == NULL)
+ return EINVAL;
+
+ if (f->branch) f->branch->refcount--;
+ if (frwl->branch) frwl->branch->refcount++;
+
+ frwl->next = f->next;
+ memcpy(f,frwl,sizeof(struct ip_fwkernel));
+ kfree(frwl);
+ return 0;
+}
+
+static int append_to_chain(struct ip_chain *chainptr, struct ip_fwkernel *rule)
+{
+ struct ip_fwkernel *i;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ /* Special case if no rules already present */
+ if (chainptr->chain == NULL) {
+
+ /* If pointer writes are atomic then turning off
+ * interupts is not necessary. */
+ chainptr->chain = rule;
+ if (rule->branch) rule->branch->refcount++;
+ return 0;
+ }
+
+ /* Find the rule before the end of the chain */
+ for (i = chainptr->chain; i->next; i = i->next);
+ i->next = rule;
+ if (rule->branch) rule->branch->refcount++;
+ return 0;
+}
+
+/* This function inserts a rule at the position of position in the
+ * chain refenced by chainptr. If position is 1 then this rule will
+ * become the new rule one. */
+static int insert_in_chain(struct ip_chain *chainptr,
+ struct ip_fwkernel *frwl,
+ __u32 position)
+{
+ struct ip_fwkernel *f = chainptr->chain;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ /* special case if the position is number 1 */
+ if (position == 1) {
+ frwl->next = chainptr->chain;
+ if (frwl->branch) frwl->branch->refcount++;
+ chainptr->chain = frwl;
+ return 0;
+ }
+ position--;
+ while (--position && f != NULL) f = f->next;
+ if (f == NULL)
+ return EINVAL;
+ if (frwl->branch) frwl->branch->refcount++;
+ frwl->next = f->next;
+
+ f->next = frwl;
+ return 0;
+}
+
+/* This function deletes the a rule from a given rulenum and chain.
+ * With rulenum = 1 is the first rule is deleted. */
+
+static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum)
+{
+ struct ip_fwkernel *i=chainptr->chain,*tmp;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+
+ if (!chainptr->chain)
+ return ENOENT;
+
+ /* Need a special case for the first rule */
+ if (rulenum == 1) {
+ /* store temp to allow for freeing up of memory */
+ tmp = chainptr->chain;
+ if (chainptr->chain->branch) chainptr->chain->branch->refcount--;
+ chainptr->chain = chainptr->chain->next;
+ kfree(tmp); /* free memory that is now unused */
+ } else {
+ rulenum--;
+ while (--rulenum && i->next ) i = i->next;
+ if (!i->next)
+ return ENOENT;
+ tmp = i->next;
+ if (i->next->branch)
+ i->next->branch->refcount--;
+ i->next = i->next->next;
+ kfree(tmp);
+ }
+ return 0;
+}
+
+
+/* This function deletes the a rule from a given rule and chain.
+ * The rule that is deleted is the first occursance of that rule. */
+static int del_rule_from_chain(struct ip_chain *chainptr,
+ struct ip_fwkernel *frwl)
+{
+ struct ip_fwkernel *ltmp,*ftmp = chainptr->chain ;
+ int was_found;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+
+ /* Sure, we should compare marks, but since the `ipfwadm'
+ * script uses it for an unholy hack... well, life is easier
+ * this way. We also mask it out of the flags word. --PR */
+ for (ltmp=NULL, was_found=0;
+ !was_found && ftmp != NULL;
+ ltmp = ftmp,ftmp = ftmp->next) {
+ if (ftmp->ipfw.fw_src.s_addr!=frwl->ipfw.fw_src.s_addr
+ || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr
+ || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr
+ || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr
+#if 0
+ || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg
+#else
+ || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS)
+ != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS))
+#endif
+ || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg
+ || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto
+#if 0
+ || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark
+#endif
+ || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt
+ || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0]
+ || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1]
+ || ftmp->ipfw.fw_dpts[0]!=frwl->ipfw.fw_dpts[0]
+ || ftmp->ipfw.fw_dpts[1]!=frwl->ipfw.fw_dpts[1]
+ || ftmp->ipfw.fw_outputsize!=frwl->ipfw.fw_outputsize) {
+ duprintf("del_rule_from_chain: mismatch:"
+ "src:%u/%u dst:%u/%u smsk:%u/%u dmsk:%u/%u "
+ "flg:%hX/%hX invflg:%hX/%hX proto:%u/%u "
+ "mark:%u/%u "
+ "ports:%hu-%hu/%hu-%hu %hu-%hu/%hu-%hu "
+ "outputsize:%hu-%hu\n",
+ ftmp->ipfw.fw_src.s_addr,
+ frwl->ipfw.fw_src.s_addr,
+ ftmp->ipfw.fw_dst.s_addr,
+ frwl->ipfw.fw_dst.s_addr,
+ ftmp->ipfw.fw_smsk.s_addr,
+ frwl->ipfw.fw_smsk.s_addr,
+ ftmp->ipfw.fw_dmsk.s_addr,
+ frwl->ipfw.fw_dmsk.s_addr,
+ ftmp->ipfw.fw_flg,
+ frwl->ipfw.fw_flg,
+ ftmp->ipfw.fw_invflg,
+ frwl->ipfw.fw_invflg,
+ ftmp->ipfw.fw_proto,
+ frwl->ipfw.fw_proto,
+ ftmp->ipfw.fw_mark,
+ frwl->ipfw.fw_mark,
+ ftmp->ipfw.fw_spts[0],
+ frwl->ipfw.fw_spts[0],
+ ftmp->ipfw.fw_spts[1],
+ frwl->ipfw.fw_spts[1],
+ ftmp->ipfw.fw_dpts[0],
+ frwl->ipfw.fw_dpts[0],
+ ftmp->ipfw.fw_dpts[1],
+ frwl->ipfw.fw_dpts[1],
+ ftmp->ipfw.fw_outputsize,
+ frwl->ipfw.fw_outputsize);
+ continue;
+ }
+
+ if (strncmp(ftmp->ipfw.fw_vianame,
+ frwl->ipfw.fw_vianame,
+ IFNAMSIZ)) {
+ duprintf("del_rule_from_chain: if mismatch: %s/%s\n",
+ ftmp->ipfw.fw_vianame,
+ frwl->ipfw.fw_vianame);
+ continue;
+ }
+ if (ftmp->branch != frwl->branch) {
+ duprintf("del_rule_from_chain: branch mismatch: "
+ "%s/%s\n",
+ ftmp->branch?ftmp->branch->label:"(null)",
+ frwl->branch?frwl->branch->label:"(null)");
+ continue;
+ }
+ if (ftmp->branch == NULL
+ && ftmp->simplebranch != frwl->simplebranch) {
+ duprintf("del_rule_from_chain: simplebranch mismatch: "
+ "%i/%i\n",
+ ftmp->simplebranch, frwl->simplebranch);
+ continue;
+ }
+ was_found = 1;
+ if (ftmp->branch)
+ ftmp->branch->refcount--;
+ if (ltmp)
+ ltmp->next = ftmp->next;
+ else
+ chainptr->chain = ftmp->next;
+ kfree(ftmp);
+ break;
+ }
+
+ if (was_found)
+ return 0;
+ else {
+ duprintf("del_rule_from_chain: no matching rule found\n");
+ return EINVAL;
+ }
+}
+
+/* This function takes the label of a chain and deletes the first
+ * chain with that name. No special cases required for the built in
+ * chains as they have their refcount initilised to 1 so that they are
+ * never deleted. */
+static int del_chain(ip_chainlabel label)
+{
+ struct ip_chain *tmp,*tmp2;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ /* Corner case: return EBUSY not ENOENT for first elem ("input") */
+ if (strcmp(label, ip_fw_chains->label) == 0)
+ return EBUSY;
+
+ for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next)
+ if(strcmp(tmp->next->label,label) == 0)
+ break;
+
+ tmp2 = tmp->next;
+ if (!tmp2)
+ return ENOENT;
+
+ if (tmp2->refcount)
+ return EBUSY;
+
+ if (tmp2->chain)
+ return ENOTEMPTY;
+
+ tmp->next = tmp2->next;
+ kfree(tmp2);
+ return 0;
+}
+
+/* This is a function to initilise a chain. Built in rules start with
+ * refcount = 1 so that they cannot be deleted. User defined rules
+ * start with refcount = 0 so they can be deleted. */
+static struct ip_chain *ip_init_chain(ip_chainlabel name,
+ __u32 ref,
+ int policy)
+{
+ unsigned int i;
+ struct ip_chain *label
+ = kmalloc(SIZEOF_STRUCT_IP_CHAIN, GFP_KERNEL);
+ if (label == NULL)
+ panic("Can't kmalloc for firewall chains.\n");
+ strcpy(label->label,name);
+ label->next = NULL;
+ label->chain = NULL;
+ label->refcount = ref;
+ label->policy = policy;
+ for (i = 0; i < smp_num_cpus*2; i++) {
+ label->reent[i].counters.pcnt = label->reent[i].counters.bcnt
+ = 0;
+ label->reent[i].prevchain = NULL;
+ label->reent[i].prevrule = NULL;
+ }
+
+ return label;
+}
+
+/* This is a function for reating a new chain. The chains is not
+ * created if a chain of the same name already exists */
+static int create_chain(ip_chainlabel label)
+{
+ struct ip_chain *tmp;
+
+ if (!check_label(label))
+ return EINVAL;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next)
+ if (strcmp(tmp->label,label) == 0)
+ return EEXIST;
+
+ if (strcmp(tmp->label,label) == 0)
+ return EEXIST;
+
+ tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is
+ * zero since this is a
+ * user defined chain *
+ * and therefore can be
+ * deleted */
+ return 0;
+}
+
+/* This function simply changes the policy on one of the built in
+ * chains. checking must be done before this is call to ensure that
+ * chainptr is pointing to one of the three possible chains */
+static int change_policy(struct ip_chain *chainptr, int policy)
+{
+ FWC_HAVE_LOCK(fwc_wlocks);
+ chainptr->policy = policy;
+ return 0;
+}
+
+/* This function takes an ip_fwuser and converts it to a ip_fwkernel. It also
+ * performs some checks in the structure. */
+static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno)
+{
+ struct ip_fwkernel *fwkern;
+
+ if ( (fwuser->ipfw.fw_flg & ~IP_FW_F_MASK) != 0 ) {
+ duprintf("convert_ipfw: undefined flag bits set (flags=%x)\n",
+ fwuser->ipfw.fw_flg);
+ *errno = EINVAL;
+ return NULL;
+ }
+
+#ifdef DEBUG_IP_FIREWALL_USER
+ /* These are sanity checks that don't really matter.
+ * We can get rid of these once testing is complete.
+ */
+ if ((fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN)
+ && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO)
+ || fwuser->ipfw.fw_proto != IPPROTO_TCP)) {
+ duprintf("convert_ipfw: TCP SYN flag set but proto != TCP!\n");
+ *errno = EINVAL;
+ return NULL;
+ }
+
+ if (strcmp(fwuser->label, IP_FW_LABEL_REDIRECT) != 0
+ && fwuser->ipfw.fw_redirpt != 0) {
+ duprintf("convert_ipfw: Target not REDIR but redirpt != 0!\n");
+ *errno = EINVAL;
+ return NULL;
+ }
+
+ if ((!(fwuser->ipfw.fw_flg & IP_FW_F_FRAG)
+ && (fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG))
+ || (!(fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN)
+ && (fwuser->ipfw.fw_invflg & IP_FW_INV_SYN))) {
+ duprintf("convert_ipfw: Can't have INV flag if flag unset!\n");
+ *errno = EINVAL;
+ return NULL;
+ }
+
+ if (((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCPT)
+ && fwuser->ipfw.fw_spts[0] == 0
+ && fwuser->ipfw.fw_spts[1] == 0xFFFF)
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTPT)
+ && fwuser->ipfw.fw_dpts[0] == 0
+ && fwuser->ipfw.fw_dpts[1] == 0xFFFF)
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_VIA)
+ && (fwuser->ipfw.fw_vianame)[0] == '\0')
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCIP)
+ && fwuser->ipfw.fw_smsk.s_addr == 0)
+ || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTIP)
+ && fwuser->ipfw.fw_dmsk.s_addr == 0)) {
+ duprintf("convert_ipfw: INV flag makes rule unmatchable!\n");
+ *errno = EINVAL;
+ return NULL;
+ }
+
+ if ((fwuser->ipfw.fw_flg & IP_FW_F_FRAG)
+ && !(fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG)
+ && (fwuser->ipfw.fw_spts[0] != 0
+ || fwuser->ipfw.fw_spts[1] != 0xFFFF
+ || fwuser->ipfw.fw_dpts[0] != 0
+ || fwuser->ipfw.fw_dpts[1] != 0xFFFF
+ || (fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN))) {
+ duprintf("convert_ipfw: Can't test ports or SYN with frag!\n");
+ *errno = EINVAL;
+ return NULL;
+ }
+#endif
+
+ if ((fwuser->ipfw.fw_spts[0] != 0
+ || fwuser->ipfw.fw_spts[1] != 0xFFFF
+ || fwuser->ipfw.fw_dpts[0] != 0
+ || fwuser->ipfw.fw_dpts[1] != 0xFFFF)
+ && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO)
+ || (fwuser->ipfw.fw_proto != IPPROTO_TCP
+ && fwuser->ipfw.fw_proto != IPPROTO_UDP
+ && fwuser->ipfw.fw_proto != IPPROTO_ICMP))) {
+ duprintf("convert_ipfw: Can only test ports for TCP/UDP/ICMP!\n");
+ *errno = EINVAL;
+ return NULL;
+ }
+
+ fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL);
+ if (!fwkern) {
+ duprintf("convert_ipfw: kmalloc failed!\n");
+ *errno = ENOMEM;
+ return NULL;
+ }
+ memcpy(&fwkern->ipfw,&fwuser->ipfw,sizeof(struct ip_fw));
+
+ if (!find_special(fwuser->label, &fwkern->simplebranch)) {
+ fwkern->branch = find_label(fwuser->label);
+ if (!fwkern->branch) {
+ duprintf("convert_ipfw: chain doesn't exist `%s'.\n",
+ fwuser->label);
+ kfree(fwkern);
+ *errno = ENOENT;
+ return NULL;
+ } else if (fwkern->branch == IP_FW_INPUT_CHAIN
+ || fwkern->branch == IP_FW_FORWARD_CHAIN
+ || fwkern->branch == IP_FW_OUTPUT_CHAIN) {
+ duprintf("convert_ipfw: Can't branch to builtin chain `%s'.\n",
+ fwuser->label);
+ kfree(fwkern);
+ *errno = ENOENT;
+ return NULL;
+ }
+ } else
+ fwkern->branch = NULL;
+ memset(fwkern->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS);
+
+ /* Handle empty vianame by making it a wildcard */
+ if ((fwkern->ipfw.fw_vianame)[0] == '\0')
+ fwkern->ipfw.fw_flg |= IP_FW_F_WILDIF;
+
+ fwkern->next = NULL;
+ return fwkern;
+}
+
+int ip_fw_ctl(int cmd, void *m, int len)
+{
+ int ret;
+ struct ip_chain *chain;
+ unsigned long flags;
+
+ FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
+
+ switch (cmd) {
+ case IP_FW_FLUSH:
+ if (len != sizeof(ip_chainlabel) || !check_label(m))
+ ret = EINVAL;
+ else if ((chain = find_label(m)) == NULL)
+ ret = ENOENT;
+ else ret = clear_fw_chain(chain);
+ break;
+
+ case IP_FW_ZERO:
+ if (len != sizeof(ip_chainlabel) || !check_label(m))
+ ret = EINVAL;
+ else if ((chain = find_label(m)) == NULL)
+ ret = ENOENT;
+ else ret = zero_fw_chain(chain);
+ break;
+
+ case IP_FW_CHECK: {
+ struct ip_fwtest *new = m;
+ struct iphdr *ip;
+
+ /* Don't need write lock. */
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+
+ if (len != sizeof(struct ip_fwtest) || !check_label(m))
+ return EINVAL;
+
+ /* Need readlock to do find_label */
+ FWC_READ_LOCK(&ip_fw_lock);
+
+ if ((chain = find_label(new->fwt_label)) == NULL)
+ ret = ENOENT;
+ else {
+ ip = &(new->fwt_packet.fwp_iph);
+
+ if (ip->ihl != sizeof(struct iphdr) / sizeof(int)) {
+ duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n",
+ ip->ihl,
+ sizeof(struct iphdr) / sizeof(int));
+ ret = EINVAL;
+ }
+ else {
+ ret = ip_fw_check(ip, new->fwt_packet.fwp_vianame,
+ NULL, chain,
+ NULL, SLOT_NUMBER(), 1);
+ switch (ret) {
+ case FW_ACCEPT:
+ ret = 0; break;
+ case FW_REDIRECT:
+ ret = ECONNABORTED; break;
+ case FW_MASQUERADE:
+ ret = ECONNRESET; break;
+ case FW_REJECT:
+ ret = ECONNREFUSED; break;
+ /* Hack to help diag; these only get
+ returned when testing. */
+ case FW_SKIP+1:
+ ret = ELOOP; break;
+ case FW_SKIP:
+ ret = ENFILE; break;
+ default: /* FW_BLOCK */
+ ret = ETIMEDOUT; break;
+ }
+ }
+ }
+ FWC_READ_UNLOCK(&ip_fw_lock);
+ return ret;
+ }
+
+ case IP_FW_MASQ_TIMEOUTS: {
+#ifdef CONFIG_IP_MASQUERADE
+ ret = ip_fw_masq_timeouts(m, len);
+#else
+ ret = EINVAL;
+#endif
+ }
+ break;
+
+ case IP_FW_REPLACE: {
+ struct ip_fwkernel *ip_fwkern;
+ struct ip_fwnew *new = m;
+
+ if (len != sizeof(struct ip_fwnew)
+ || !check_label(new->fwn_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwn_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret))
+ != NULL)
+ ret = replace_in_chain(chain, ip_fwkern,
+ new->fwn_rulenum);
+ }
+ break;
+
+ case IP_FW_APPEND: {
+ struct ip_fwchange *new = m;
+ struct ip_fwkernel *ip_fwkern;
+
+ if (len != sizeof(struct ip_fwchange)
+ || !check_label(new->fwc_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwc_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret))
+ != NULL)
+ ret = append_to_chain(chain, ip_fwkern);
+ }
+ break;
+
+ case IP_FW_INSERT: {
+ struct ip_fwkernel *ip_fwkern;
+ struct ip_fwnew *new = m;
+
+ if (len != sizeof(struct ip_fwnew)
+ || !check_label(new->fwn_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwn_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret))
+ != NULL)
+ ret = insert_in_chain(chain, ip_fwkern,
+ new->fwn_rulenum);
+ }
+ break;
+
+ case IP_FW_DELETE: {
+ struct ip_fwchange *new = m;
+ struct ip_fwkernel *ip_fwkern;
+
+ if (len != sizeof(struct ip_fwchange)
+ || !check_label(new->fwc_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwc_label)) == NULL)
+ ret = ENOENT;
+ else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret))
+ != NULL) {
+ ret = del_rule_from_chain(chain, ip_fwkern);
+ kfree(ip_fwkern);
+ }
+ }
+ break;
+
+ case IP_FW_DELETE_NUM: {
+ struct ip_fwdelnum *new = m;
+
+ if (len != sizeof(struct ip_fwdelnum)
+ || !check_label(new->fwd_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwd_label)) == NULL)
+ ret = ENOENT;
+ else ret = del_num_from_chain(chain, new->fwd_rulenum);
+ }
+ break;
+
+ case IP_FW_CREATECHAIN: {
+ if (len != sizeof(ip_chainlabel)) {
+ duprintf("create_chain: bad size %i\n", len);
+ ret = EINVAL;
+ }
+ else ret = create_chain(m);
+ }
+ break;
+
+ case IP_FW_DELETECHAIN: {
+ if (len != sizeof(ip_chainlabel)) {
+ duprintf("delete_chain: bad size %i\n", len);
+ ret = EINVAL;
+ }
+ else ret = del_chain(m);
+ }
+ break;
+
+ case IP_FW_POLICY: {
+ struct ip_fwpolicy *new = m;
+
+ if (len != sizeof(struct ip_fwpolicy)
+ || !check_label(new->fwp_label))
+ ret = EINVAL;
+ else if ((chain = find_label(new->fwp_label)) == NULL)
+ ret = ENOENT;
+ else if (chain != IP_FW_INPUT_CHAIN
+ && chain != IP_FW_FORWARD_CHAIN
+ && chain != IP_FW_OUTPUT_CHAIN) {
+ duprintf("change_policy: can't change policy on user"
+ " defined chain.\n");
+ ret = EINVAL;
+ }
+ else {
+ int pol = FW_SKIP;
+ find_special(new->fwp_policy, &pol);
+
+ switch(pol) {
+ case FW_MASQUERADE:
+ if (chain != IP_FW_FORWARD_CHAIN) {
+ ret = EINVAL;
+ break;
+ }
+ /* Fall thru... */
+ case FW_BLOCK:
+ case FW_ACCEPT:
+ case FW_REJECT:
+ ret = change_policy(chain, pol);
+ break;
+ default:
+ duprintf("change_policy: bad policy `%s'\n",
+ new->fwp_policy);
+ ret = EINVAL;
+ }
+ }
+ break;
+
+ }
+ default:
+ duprintf("ip_fw_ctl: unknown request %d\n",cmd);
+ ret = EINVAL;
+ }
+
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+ return ret;
+}
+
+/* Returns bytes used - doesn't NUL terminate */
+static int dump_rule(char *buffer,
+ const char *chainlabel,
+ const struct ip_fwkernel *rule)
+{
+ int len;
+ unsigned int i;
+ __u64 packets = 0, bytes = 0;
+
+ FWC_HAVE_LOCK(fwc_wlocks);
+ for (i = 0; i < NUM_SLOTS; i++) {
+ packets += rule->counters[i].pcnt;
+ bytes += rule->counters[i].bcnt;
+ }
+
+ len=sprintf(buffer,
+ "%9s " /* Chain name */
+ "%08X/%08X->%08X/%08X " /* Source & Destination IPs */
+ "%.16s " /* Interface */
+ "%X %X " /* fw_flg and fw_invflg fields */
+ "%u " /* Protocol */
+ "%-9u %-9u %-9u %-9u " /* Packet & byte counters */
+ "%u-%u %u-%u " /* Source & Dest port ranges */
+ "A%02X X%02X " /* TOS and and xor masks */
+ "%08X " /* Redirection port */
+ "%u " /* fw_mark field */
+ "%u " /* output size */
+ "%9s\n", /* Target */
+ chainlabel,
+ ntohl(rule->ipfw.fw_src.s_addr),
+ ntohl(rule->ipfw.fw_smsk.s_addr),
+ ntohl(rule->ipfw.fw_dst.s_addr),
+ ntohl(rule->ipfw.fw_dmsk.s_addr),
+ (rule->ipfw.fw_vianame)[0] ? rule->ipfw.fw_vianame : "-",
+ rule->ipfw.fw_flg,
+ rule->ipfw.fw_invflg,
+ rule->ipfw.fw_proto,
+ (__u32)(packets >> 32), (__u32)packets,
+ (__u32)(bytes >> 32), (__u32)bytes,
+ rule->ipfw.fw_spts[0], rule->ipfw.fw_spts[1],
+ rule->ipfw.fw_dpts[0], rule->ipfw.fw_dpts[1],
+ rule->ipfw.fw_tosand, rule->ipfw.fw_tosxor,
+ rule->ipfw.fw_redirpt,
+ rule->ipfw.fw_mark,
+ rule->ipfw.fw_outputsize,
+ branchname(rule->branch,rule->simplebranch));
+
+ duprintf("dump_rule: %i bytes done.\n", len);
+ return len;
+}
+
+/* File offset is actually in records, not bytes. */
+static int ip_chain_procinfo(char *buffer, char **start,
+ off_t offset, int length, int reset)
+{
+ struct ip_chain *i;
+ struct ip_fwkernel *j = ip_fw_chains->chain;
+ unsigned long flags;
+ int len = 0;
+ int last_len = 0;
+ off_t upto = 0;
+
+ duprintf("Offset starts at %lu\n", offset);
+ duprintf("ip_fw_chains is 0x%0lX\n", (unsigned long int)ip_fw_chains);
+
+ /* Need a write lock to lock out ``readers'' which update counters. */
+ FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
+
+ for (i = ip_fw_chains; i; i = i->next) {
+ for (j = i->chain; j; j = j->next) {
+ if (upto == offset) break;
+ duprintf("Skipping rule in chain `%s'\n",
+ i->label);
+ upto++;
+ }
+ if (upto == offset) break;
+ }
+
+ /* Don't init j first time, or once i = NULL */
+ for (; i; (void)((i = i->next) && (j = i->chain))) {
+ duprintf("Dumping chain `%s'\n", i->label);
+ for (; j; j = j->next, upto++, last_len = len)
+ {
+ len += dump_rule(buffer+len, i->label, j);
+ if (len > length) {
+ duprintf("Dumped to %i (past %i). "
+ "Moving back to %i.\n",
+ len, length, last_len);
+ len = last_len;
+ goto outside;
+ }
+ else if (reset)
+ memset(j->counters, 0,
+ sizeof(struct ip_counters)*NUM_SLOTS);
+ }
+ }
+outside:
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+ buffer[len] = '\0';
+
+ duprintf("ip_chain_procinfo: Length = %i (of %i). Offset = %li.\n",
+ len, length, upto);
+ /* `start' hack - see fs/proc/generic.c line ~165 */
+ *start=(char *)((unsigned int)upto-offset);
+ return len;
+}
+
+static int ip_chain_name_procinfo(char *buffer, char **start,
+ off_t offset, int length, int reset)
+{
+ struct ip_chain *i;
+ int len = 0,last_len = 0;
+ off_t pos = 0,begin = 0;
+ unsigned long flags;
+
+ /* Need a write lock to lock out ``readers'' which update counters. */
+ FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags);
+
+ for (i = ip_fw_chains; i; i = i->next)
+ {
+ unsigned int j;
+ __u32 packetsHi = 0, packetsLo = 0, bytesHi = 0, bytesLo = 0;
+
+ for (j = 0; j < NUM_SLOTS; j++) {
+ packetsLo += i->reent[j].counters.pcnt & 0xFFFFFFFF;
+ packetsHi += ((i->reent[j].counters.pcnt >> 32)
+ & 0xFFFFFFFF);
+ bytesLo += i->reent[j].counters.bcnt & 0xFFFFFFFF;
+ bytesHi += ((i->reent[j].counters.bcnt >> 32)
+ & 0xFFFFFFFF);
+ }
+
+ /* print the label and the policy */
+ len+=sprintf(buffer+len,"%s %s %i %u %u %u %u\n",
+ i->label,branchname(NULL, i->policy),i->refcount,
+ packetsHi, packetsLo, bytesHi, bytesLo);
+ pos=begin+len;
+ if(pos<offset) {
+ len=0;
+ begin=pos;
+ }
+ else if(pos>offset+length) {
+ len = last_len;
+ break;
+ }
+
+ last_len = len;
+ }
+ FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags);
+
+ *start = buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ return len;
+}
+
+/*
+ * Interface to the generic firewall chains.
+ */
+int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev,
+ void *phdr, void *arg, struct sk_buff **pskb)
+{
+ return ip_fw_check(phdr, dev->name,
+ arg, IP_FW_INPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
+}
+
+int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev,
+ void *phdr, void *arg, struct sk_buff **pskb)
+{
+ /* Locally generated bogus packets by root. <SIGH>. */
+ if (((struct iphdr *)phdr)->ihl * 4 < sizeof(struct iphdr)
+ || (*pskb)->len < sizeof(struct iphdr))
+ return FW_ACCEPT;
+ return ip_fw_check(phdr, dev->name,
+ arg, IP_FW_OUTPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
+}
+
+int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev,
+ void *phdr, void *arg, struct sk_buff **pskb)
+{
+ return ip_fw_check(phdr, dev->name,
+ arg, IP_FW_FORWARD_CHAIN, *pskb, SLOT_NUMBER(), 0);
+}
+
+struct firewall_ops ipfw_ops=
+{
+ NULL,
+ ipfw_forward_check,
+ ipfw_input_check,
+ ipfw_output_check,
+ PF_INET,
+ 0 /* We don't even allow a fall through so we are last */
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_ipfwchains_chain = {
+ PROC_NET_IPFW_CHAINS, sizeof(IP_FW_PROC_CHAINS)-1,
+ IP_FW_PROC_CHAINS, S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0,
+ 0, &proc_net_inode_operations, ip_chain_procinfo
+};
+
+static struct proc_dir_entry proc_net_ipfwchains_chainnames = {
+ PROC_NET_IPFW_CHAIN_NAMES, sizeof(IP_FW_PROC_CHAIN_NAMES)-1,
+ IP_FW_PROC_CHAIN_NAMES, S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0,
+ 0, &proc_net_inode_operations, ip_chain_name_procinfo
+};
+
+#endif
+
+__initfunc(void ip_fw_init(void))
+{
+#ifdef DEBUG_IP_FIRWALL_LOCKING
+ fwc_wlocks = fwc_rlocks = 0;
+#endif
+
+ IP_FW_INPUT_CHAIN = ip_init_chain(IP_FW_LABEL_INPUT, 1, FW_ACCEPT);
+ IP_FW_FORWARD_CHAIN = ip_init_chain(IP_FW_LABEL_FORWARD, 1, FW_ACCEPT);
+ IP_FW_OUTPUT_CHAIN = ip_init_chain(IP_FW_LABEL_OUTPUT, 1, FW_ACCEPT);
+
+ if(register_firewall(PF_INET,&ipfw_ops)<0)
+ panic("Unable to register IP firewall.\n");
+
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_net_ipfwchains_chain);
+ proc_net_register(&proc_net_ipfwchains_chainnames);
+#endif
+
+#ifdef CONFIG_IP_FIREWALL_NETLINK
+ ipfwsk = netlink_kernel_create(NETLINK_FIREWALL, NULL);
+ if (ipfwsk == NULL)
+ panic("ip_fw_init: cannot initialize netlink\n");
+#endif
+#if defined(DEBUG_IP_FIREWALL) || defined(DEBUG_IP_FIREWALL_USER)
+ printk("Firewall graphs enabled! Untested kernel coming thru. \n");
+#endif
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_gre.c b/pfinet/linux-src/net/ipv4/ip_gre.c
new file mode 100644
index 00000000..4b03c226
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_gre.c
@@ -0,0 +1,1223 @@
+/*
+ * Linux NET3: GRE over IP protocol decoder.
+ *
+ * Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/uaccess.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_arp.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <linux/in6.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/protocol.h>
+#include <net/ipip.h>
+#include <net/arp.h>
+#include <net/checksum.h>
+
+#ifdef CONFIG_IPV6
+#include <net/ipv6.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#endif
+
+/*
+ Problems & solutions
+ --------------------
+
+ 1. The most important issue is detecting local dead loops.
+ They would cause complete host lockup in transmit, which
+ would be "resolved" by stack overflow or, if queueing is enabled,
+ with infinite looping in net_bh.
+
+ We cannot track such dead loops during route installation,
+ it is infeasible task. The most general solutions would be
+ to keep skb->encapsulation counter (sort of local ttl),
+ and silently drop packet when it expires. It is the best
+ solution, but it supposes maintaing new variable in ALL
+ skb, even if no tunneling is used.
+
+ Current solution: t->recursion lock breaks dead loops. It looks
+ like dev->tbusy flag, but I preferred new variable, because
+ the semantics is different. One day, when hard_start_xmit
+ will be multithreaded we will have to use skb->encapsulation.
+
+
+
+ 2. Networking dead loops would not kill routers, but would really
+ kill network. IP hop limit plays role of "t->recursion" in this case,
+ if we copy it from packet being encapsulated to upper header.
+ It is very good solution, but it introduces two problems:
+
+ - Routing protocols, using packets with ttl=1 (OSPF, RIP2),
+ do not work over tunnels.
+ - traceroute does not work. I planned to relay ICMP from tunnel,
+ so that this problem would be solved and traceroute output
+ would even more informative. This idea appeared to be wrong:
+ only Linux complies to rfc1812 now (yes, guys, Linux is the only
+ true router now :-)), all routers (at least, in neighbourhood of mine)
+ return only 8 bytes of payload. It is the end.
+
+ Hence, if we want that OSPF worked or traceroute said something reasonable,
+ we should search for another solution.
+
+ One of them is to parse packet trying to detect inner encapsulation
+ made by our node. It is difficult or even impossible, especially,
+ taking into account fragmentation. TO be short, tt is not solution at all.
+
+ Current solution: The solution was UNEXPECTEDLY SIMPLE.
+ We force DF flag on tunnels with preconfigured hop limit,
+ that is ALL. :-) Well, it does not remove the problem completely,
+ but exponential growth of network traffic is changed to linear
+ (branches, that exceed pmtu are pruned) and tunnel mtu
+ fastly degrades to value <68, where looping stops.
+ Yes, it is not good if there exists a router in the loop,
+ which does not force DF, even when encapsulating packets have DF set.
+ But it is not our problem! Nobody could accuse us, we made
+ all that we could make. Even if it is your gated who injected
+ fatal route to network, even if it were you who configured
+ fatal static route: you are innocent. :-)
+
+
+
+ 3. Really, ipv4/ipip.c, ipv4/ip_gre.c and ipv6/sit.c contain
+ practically identical code. It would be good to glue them
+ together, but it is not very evident, how to make them modular.
+ sit is integral part of IPv6, ipip and gre are naturally modular.
+ We could extract common parts (hash table, ioctl etc)
+ to a separate module (ip_tunnel.c).
+
+ Alexey Kuznetsov.
+ */
+
+static int ipgre_tunnel_init(struct device *dev);
+
+/* Fallback tunnel: no source, no destination, no key, no options */
+
+static int ipgre_fb_tunnel_init(struct device *dev);
+
+static struct device ipgre_fb_tunnel_dev = {
+ NULL, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipgre_fb_tunnel_init,
+};
+
+static struct ip_tunnel ipgre_fb_tunnel = {
+ NULL, &ipgre_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"gre0", }
+};
+
+/* Tunnel hash table */
+
+/*
+ 4 hash tables:
+
+ 3: (remote,local)
+ 2: (remote,*)
+ 1: (*,local)
+ 0: (*,*)
+
+ We require exact key match i.e. if a key is present in packet
+ it will match only tunnel with the same key; if it is not present,
+ it will match only keyless tunnel.
+
+ All keysless packets, if not matched configured keyless tunnels
+ will match fallback tunnel.
+ */
+
+#define HASH_SIZE 16
+#define HASH(addr) ((addr^(addr>>4))&0xF)
+
+static struct ip_tunnel *tunnels[4][HASH_SIZE];
+
+#define tunnels_r_l (tunnels[3])
+#define tunnels_r (tunnels[2])
+#define tunnels_l (tunnels[1])
+#define tunnels_wc (tunnels[0])
+
+/* Given src, dst and key, find approriate for input tunnel. */
+
+static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key)
+{
+ unsigned h0 = HASH(remote);
+ unsigned h1 = HASH(key);
+ struct ip_tunnel *t;
+
+ for (t = tunnels_r_l[h0^h1]; t; t = t->next) {
+ if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
+ if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
+ return t;
+ }
+ }
+ for (t = tunnels_r[h0^h1]; t; t = t->next) {
+ if (remote == t->parms.iph.daddr) {
+ if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
+ return t;
+ }
+ }
+ for (t = tunnels_l[h1]; t; t = t->next) {
+ if (local == t->parms.iph.saddr ||
+ (local == t->parms.iph.daddr && MULTICAST(local))) {
+ if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
+ return t;
+ }
+ }
+ for (t = tunnels_wc[h1]; t; t = t->next) {
+ if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
+ return t;
+ }
+ if (ipgre_fb_tunnel_dev.flags&IFF_UP)
+ return &ipgre_fb_tunnel;
+ return NULL;
+}
+
+static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t)
+{
+ u32 remote = t->parms.iph.daddr;
+ u32 local = t->parms.iph.saddr;
+ u32 key = t->parms.i_key;
+ unsigned h = HASH(key);
+ int prio = 0;
+
+ if (local)
+ prio |= 1;
+ if (remote && !MULTICAST(remote)) {
+ prio |= 2;
+ h ^= HASH(remote);
+ }
+
+ return &tunnels[prio][h];
+}
+
+static void ipgre_tunnel_link(struct ip_tunnel *t)
+{
+ struct ip_tunnel **tp = ipgre_bucket(t);
+
+ t->next = *tp;
+ wmb();
+ *tp = t;
+}
+
+static void ipgre_tunnel_unlink(struct ip_tunnel *t)
+{
+ struct ip_tunnel **tp;
+
+ for (tp = ipgre_bucket(t); *tp; tp = &(*tp)->next) {
+ if (t == *tp) {
+ *tp = t->next;
+ synchronize_bh();
+ break;
+ }
+ }
+}
+
+static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create)
+{
+ u32 remote = parms->iph.daddr;
+ u32 local = parms->iph.saddr;
+ u32 key = parms->i_key;
+ struct ip_tunnel *t, **tp, *nt;
+ struct device *dev;
+ unsigned h = HASH(key);
+ int prio = 0;
+
+ if (local)
+ prio |= 1;
+ if (remote && !MULTICAST(remote)) {
+ prio |= 2;
+ h ^= HASH(remote);
+ }
+ for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {
+ if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
+ if (key == t->parms.i_key)
+ return t;
+ }
+ }
+ if (!create)
+ return NULL;
+
+ MOD_INC_USE_COUNT;
+ dev = kmalloc(sizeof(*dev) + sizeof(*t), GFP_KERNEL);
+ if (dev == NULL) {
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+ memset(dev, 0, sizeof(*dev) + sizeof(*t));
+ dev->priv = (void*)(dev+1);
+ nt = (struct ip_tunnel*)dev->priv;
+ nt->dev = dev;
+ dev->name = nt->parms.name;
+ dev->init = ipgre_tunnel_init;
+ memcpy(&nt->parms, parms, sizeof(*parms));
+ if (dev->name[0] == 0) {
+ int i;
+ for (i=1; i<100; i++) {
+ sprintf(dev->name, "gre%d", i);
+ if (dev_get(dev->name) == NULL)
+ break;
+ }
+ if (i==100)
+ goto failed;
+ memcpy(parms->name, dev->name, IFNAMSIZ);
+ }
+ if (register_netdevice(dev) < 0)
+ goto failed;
+
+ ipgre_tunnel_link(nt);
+ /* Do not decrement MOD_USE_COUNT here. */
+ return nt;
+
+failed:
+ kfree(dev);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+static void ipgre_tunnel_destroy(struct device *dev)
+{
+ ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv);
+
+ if (dev != &ipgre_fb_tunnel_dev) {
+ kfree(dev);
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+
+void ipgre_err(struct sk_buff *skb, unsigned char *dp, int len)
+{
+#ifndef I_WISH_WORLD_WERE_PERFECT
+
+/* It is not :-( All the routers (except for Linux) return only
+ 8 bytes of packet payload. It means, that precise relaying of
+ ICMP in the real Internet is absolutely infeasible.
+
+ Moreover, Cisco "wise men" put GRE key to the third word
+ in GRE header. It makes impossible maintaining even soft state for keyed
+ GRE tunnels with enabled checksum. Tell them "thank you".
+
+ Well, I wonder, rfc1812 was written by Cisco employee,
+ what the hell these idiots break standrads established
+ by themself???
+ */
+
+ struct iphdr *iph = (struct iphdr*)dp;
+ u16 *p = (u16*)(dp+(iph->ihl<<2));
+ int grehlen = (iph->ihl<<2) + 4;
+ int type = skb->h.icmph->type;
+ int code = skb->h.icmph->code;
+ struct ip_tunnel *t;
+ u16 flags;
+
+ flags = p[0];
+ if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
+ if (flags&(GRE_VERSION|GRE_ROUTING))
+ return;
+ if (flags&GRE_KEY) {
+ grehlen += 4;
+ if (flags&GRE_CSUM)
+ grehlen += 4;
+ }
+ }
+
+ /* If only 8 bytes returned, keyed message will be dropped here */
+ if (len < grehlen)
+ return;
+
+ switch (type) {
+ default:
+ case ICMP_PARAMETERPROB:
+ return;
+
+ case ICMP_DEST_UNREACH:
+ switch (code) {
+ case ICMP_SR_FAILED:
+ case ICMP_PORT_UNREACH:
+ /* Impossible event. */
+ return;
+ case ICMP_FRAG_NEEDED:
+ /* Soft state for pmtu is maintained by IP core. */
+ return;
+ default:
+ /* All others are translated to HOST_UNREACH.
+ rfc2003 contains "deep thoughts" about NET_UNREACH,
+ I believe they are just ether pollution. --ANK
+ */
+ break;
+ }
+ break;
+ case ICMP_TIME_EXCEEDED:
+ if (code != ICMP_EXC_TTL)
+ return;
+ break;
+ }
+
+ t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0);
+ if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr))
+ return;
+
+ if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
+ return;
+
+ if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
+ t->err_count++;
+ else
+ t->err_count = 1;
+ t->err_time = jiffies;
+ return;
+#else
+ struct iphdr *iph = (struct iphdr*)dp;
+ struct iphdr *eiph;
+ u16 *p = (u16*)(dp+(iph->ihl<<2));
+ int type = skb->h.icmph->type;
+ int code = skb->h.icmph->code;
+ int rel_type = 0;
+ int rel_code = 0;
+ int rel_info = 0;
+ u16 flags;
+ int grehlen = (iph->ihl<<2) + 4;
+ struct sk_buff *skb2;
+ struct rtable *rt;
+
+ if (p[1] != __constant_htons(ETH_P_IP))
+ return;
+
+ flags = p[0];
+ if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
+ if (flags&(GRE_VERSION|GRE_ROUTING))
+ return;
+ if (flags&GRE_CSUM)
+ grehlen += 4;
+ if (flags&GRE_KEY)
+ grehlen += 4;
+ if (flags&GRE_SEQ)
+ grehlen += 4;
+ }
+ if (len < grehlen + sizeof(struct iphdr))
+ return;
+ eiph = (struct iphdr*)(dp + grehlen);
+
+ switch (type) {
+ default:
+ return;
+ case ICMP_PARAMETERPROB:
+ if (skb->h.icmph->un.gateway < (iph->ihl<<2))
+ return;
+
+ /* So... This guy found something strange INSIDE encapsulated
+ packet. Well, he is fool, but what can we do ?
+ */
+ rel_type = ICMP_PARAMETERPROB;
+ rel_info = skb->h.icmph->un.gateway - grehlen;
+ break;
+
+ case ICMP_DEST_UNREACH:
+ switch (code) {
+ case ICMP_SR_FAILED:
+ case ICMP_PORT_UNREACH:
+ /* Impossible event. */
+ return;
+ case ICMP_FRAG_NEEDED:
+ /* And it is the only really necessary thing :-) */
+ rel_info = ntohs(skb->h.icmph->un.frag.mtu);
+ if (rel_info < grehlen+68)
+ return;
+ rel_info -= grehlen;
+ /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
+ if (rel_info > ntohs(eiph->tot_len))
+ return;
+ break;
+ default:
+ /* All others are translated to HOST_UNREACH.
+ rfc2003 contains "deep thoughts" about NET_UNREACH,
+ I believe, it is just ether pollution. --ANK
+ */
+ rel_type = ICMP_DEST_UNREACH;
+ rel_code = ICMP_HOST_UNREACH;
+ break;
+ }
+ break;
+ case ICMP_TIME_EXCEEDED:
+ if (code != ICMP_EXC_TTL)
+ return;
+ break;
+ }
+
+ /* Prepare fake skb to feed it to icmp_send */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ return;
+ dst_release(skb2->dst);
+ skb2->dst = NULL;
+ skb_pull(skb2, skb->data - (u8*)eiph);
+ skb2->nh.raw = skb2->data;
+
+ /* Try to guess incoming interface */
+ if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) {
+ kfree_skb(skb2);
+ return;
+ }
+ skb2->dev = rt->u.dst.dev;
+
+ /* route "incoming" packet */
+ if (rt->rt_flags&RTCF_LOCAL) {
+ ip_rt_put(rt);
+ rt = NULL;
+ if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) ||
+ rt->u.dst.dev->type != ARPHRD_IPGRE) {
+ ip_rt_put(rt);
+ kfree_skb(skb2);
+ return;
+ }
+ } else {
+ ip_rt_put(rt);
+ if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
+ skb2->dst->dev->type != ARPHRD_IPGRE) {
+ kfree_skb(skb2);
+ return;
+ }
+ }
+
+ /* change mtu on this route */
+ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+ if (rel_info > skb2->dst->pmtu) {
+ kfree_skb(skb2);
+ return;
+ }
+ skb2->dst->pmtu = rel_info;
+ rel_info = htonl(rel_info);
+ } else if (type == ICMP_TIME_EXCEEDED) {
+ struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv;
+ if (t->parms.iph.ttl) {
+ rel_type = ICMP_DEST_UNREACH;
+ rel_code = ICMP_HOST_UNREACH;
+ }
+ }
+
+ icmp_send(skb2, rel_type, rel_code, rel_info);
+ kfree_skb(skb2);
+#endif
+}
+
+int ipgre_rcv(struct sk_buff *skb, unsigned short len)
+{
+ struct iphdr *iph = skb->nh.iph;
+ u8 *h = skb->h.raw;
+ u16 flags = *(u16*)h;
+ u16 csum = 0;
+ u32 key = 0;
+ u32 seqno = 0;
+ struct ip_tunnel *tunnel;
+ int offset = 4;
+
+ if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
+ /* - Version must be 0.
+ - We do not support routing headers.
+ */
+ if (flags&(GRE_VERSION|GRE_ROUTING))
+ goto drop;
+
+ if (flags&GRE_CSUM) {
+ csum = ip_compute_csum(h, len);
+ offset += 4;
+ }
+ if (flags&GRE_KEY) {
+ key = *(u32*)(h + offset);
+ offset += 4;
+ }
+ if (flags&GRE_SEQ) {
+ seqno = ntohl(*(u32*)(h + offset));
+ offset += 4;
+ }
+ }
+
+ if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) {
+ skb->mac.raw = skb->nh.raw;
+ skb->nh.raw = skb_pull(skb, h + offset - skb->data);
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+ skb->ip_summed = 0;
+ skb->protocol = *(u16*)(h + 2);
+ skb->pkt_type = PACKET_HOST;
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+ if (MULTICAST(iph->daddr)) {
+ /* Looped back packet, drop it! */
+ if (((struct rtable*)skb->dst)->key.iif == 0)
+ goto drop;
+ tunnel->stat.multicast++;
+ skb->pkt_type = PACKET_BROADCAST;
+ }
+#endif
+
+ if (((flags&GRE_CSUM) && csum) ||
+ (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
+ tunnel->stat.rx_crc_errors++;
+ tunnel->stat.rx_errors++;
+ goto drop;
+ }
+ if (tunnel->parms.i_flags&GRE_SEQ) {
+ if (!(flags&GRE_SEQ) ||
+ (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
+ tunnel->stat.rx_fifo_errors++;
+ tunnel->stat.rx_errors++;
+ goto drop;
+ }
+ tunnel->i_seqno = seqno + 1;
+ }
+ tunnel->stat.rx_packets++;
+ tunnel->stat.rx_bytes += skb->len;
+ skb->dev = tunnel->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ netif_rx(skb);
+ return(0);
+ }
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
+
+drop:
+ kfree_skb(skb);
+ return(0);
+}
+
+static int ipgre_tunnel_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
+ struct net_device_stats *stats = &tunnel->stat;
+ struct iphdr *old_iph = skb->nh.iph;
+ struct iphdr *tiph;
+ u8 tos;
+ u16 df;
+ struct rtable *rt; /* Route to the other host */
+ struct device *tdev; /* Device to other host */
+ struct iphdr *iph; /* Our new IP header */
+ int max_headroom; /* The extra header space needed */
+ int gre_hlen;
+ u32 dst;
+ int mtu;
+
+ if (tunnel->recursion++) {
+ tunnel->stat.collisions++;
+ goto tx_error;
+ }
+
+ if (dev->hard_header) {
+ gre_hlen = 0;
+ tiph = (struct iphdr*)skb->data;
+ } else {
+ gre_hlen = tunnel->hlen;
+ tiph = &tunnel->parms.iph;
+ }
+
+ if ((dst = tiph->daddr) == 0) {
+ /* NBMA tunnel */
+
+ if (skb->dst == NULL) {
+ tunnel->stat.tx_fifo_errors++;
+ goto tx_error;
+ }
+
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ rt = (struct rtable*)skb->dst;
+ if ((dst = rt->rt_gateway) == 0)
+ goto tx_error_icmp;
+ }
+#ifdef CONFIG_IPV6
+ else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+ struct in6_addr *addr6;
+ int addr_type;
+ struct neighbour *neigh = skb->dst->neighbour;
+
+ if (neigh == NULL)
+ goto tx_error;
+
+ addr6 = (struct in6_addr*)&neigh->primary_key;
+ addr_type = ipv6_addr_type(addr6);
+
+ if (addr_type == IPV6_ADDR_ANY) {
+ addr6 = &skb->nh.ipv6h->daddr;
+ addr_type = ipv6_addr_type(addr6);
+ }
+
+ if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
+ goto tx_error_icmp;
+
+ dst = addr6->s6_addr32[3];
+ }
+#endif
+ else
+ goto tx_error;
+ }
+
+ tos = tiph->tos;
+ if (tos&1) {
+ if (skb->protocol == __constant_htons(ETH_P_IP))
+ tos = old_iph->tos;
+ tos &= ~1;
+ }
+
+ if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
+ tunnel->stat.tx_carrier_errors++;
+ goto tx_error;
+ }
+ tdev = rt->u.dst.dev;
+
+ if (tdev == dev) {
+ ip_rt_put(rt);
+ tunnel->stat.collisions++;
+ goto tx_error;
+ }
+
+ df = tiph->frag_off;
+ mtu = rt->u.dst.pmtu - tunnel->hlen;
+
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ if (skb->dst && mtu < skb->dst->pmtu && mtu >= 68)
+ skb->dst->pmtu = mtu;
+
+ df |= (old_iph->frag_off&__constant_htons(IP_DF));
+
+ if ((old_iph->frag_off&__constant_htons(IP_DF)) &&
+ mtu < ntohs(old_iph->tot_len)) {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+ }
+#ifdef CONFIG_IPV6
+ else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+ struct rt6_info *rt6 = (struct rt6_info*)skb->dst;
+
+ if (rt6 && mtu < rt6->u.dst.pmtu && mtu >= IPV6_MIN_MTU) {
+ if ((tunnel->parms.iph.daddr && !MULTICAST(tunnel->parms.iph.daddr)) ||
+ rt6->rt6i_dst.plen == 128) {
+ rt6->rt6i_flags |= RTF_MODIFIED;
+ skb->dst->pmtu = mtu;
+ }
+ }
+
+ if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) {
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+ }
+#endif
+
+ if (tunnel->err_count > 0) {
+ if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
+ tunnel->err_count--;
+
+ dst_link_failure(skb);
+ } else
+ tunnel->err_count = 0;
+ }
+
+ skb->h.raw = skb->nh.raw;
+
+ max_headroom = ((tdev->hard_header_len+15)&~15)+ gre_hlen;
+
+ if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+ struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+ if (!new_skb) {
+ ip_rt_put(rt);
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ tunnel->recursion--;
+ return 0;
+ }
+ if (skb->sk)
+ skb_set_owner_w(new_skb, skb->sk);
+ dev_kfree_skb(skb);
+ skb = new_skb;
+ }
+
+ skb->nh.raw = skb_push(skb, gre_hlen);
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+
+ /*
+ * Push down and install the IPIP header.
+ */
+
+ iph = skb->nh.iph;
+ iph->version = 4;
+ iph->ihl = sizeof(struct iphdr) >> 2;
+ iph->frag_off = df;
+ iph->protocol = IPPROTO_GRE;
+ iph->tos = tos;
+ iph->daddr = rt->rt_dst;
+ iph->saddr = rt->rt_src;
+
+ if ((iph->ttl = tiph->ttl) == 0) {
+ if (skb->protocol == __constant_htons(ETH_P_IP))
+ iph->ttl = old_iph->ttl;
+#ifdef CONFIG_IPV6
+ else if (skb->protocol == __constant_htons(ETH_P_IPV6))
+ iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit;
+#endif
+ else
+ iph->ttl = ip_statistics.IpDefaultTTL;
+ }
+
+ ((u16*)(iph+1))[0] = tunnel->parms.o_flags;
+ ((u16*)(iph+1))[1] = skb->protocol;
+
+ if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
+ u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4);
+
+ if (tunnel->parms.o_flags&GRE_SEQ) {
+ ++tunnel->o_seqno;
+ *ptr = htonl(tunnel->o_seqno);
+ ptr--;
+ }
+ if (tunnel->parms.o_flags&GRE_KEY) {
+ *ptr = tunnel->parms.o_key;
+ ptr--;
+ }
+ if (tunnel->parms.o_flags&GRE_CSUM) {
+ *ptr = 0;
+ *(__u16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
+ }
+ }
+
+ iph->tot_len = htons(skb->len);
+ iph->id = htons(ip_id_count++);
+ ip_send_check(iph);
+
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ ip_send(skb);
+ tunnel->recursion--;
+ return 0;
+
+tx_error_icmp:
+ dst_link_failure(skb);
+
+tx_error:
+ stats->tx_errors++;
+ dev_kfree_skb(skb);
+ tunnel->recursion--;
+ return 0;
+}
+
+static int
+ipgre_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
+{
+ int err = 0;
+ struct ip_tunnel_parm p;
+ struct ip_tunnel *t;
+
+ MOD_INC_USE_COUNT;
+
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ t = NULL;
+ if (dev == &ipgre_fb_tunnel_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
+ err = -EFAULT;
+ break;
+ }
+ t = ipgre_tunnel_locate(&p, 0);
+ }
+ if (t == NULL)
+ t = (struct ip_tunnel*)dev->priv;
+ memcpy(&p, &t->parms, sizeof(p));
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+ err = -EFAULT;
+ break;
+
+ case SIOCADDTUNNEL:
+ case SIOCCHGTUNNEL:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ goto done;
+
+ err = -EFAULT;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ goto done;
+
+ err = -EINVAL;
+ if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
+ p.iph.ihl != 5 || (p.iph.frag_off&__constant_htons(~IP_DF)) ||
+ ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
+ goto done;
+ if (p.iph.ttl)
+ p.iph.frag_off |= __constant_htons(IP_DF);
+
+ if (!(p.i_flags&GRE_KEY))
+ p.i_key = 0;
+ if (!(p.o_flags&GRE_KEY))
+ p.o_key = 0;
+
+ t = ipgre_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
+
+ if (dev != &ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL &&
+ t != &ipgre_fb_tunnel) {
+ if (t != NULL) {
+ if (t->dev != dev) {
+ err = -EEXIST;
+ break;
+ }
+ } else {
+ unsigned nflags=0;
+
+ t = (struct ip_tunnel*)dev->priv;
+
+ if (MULTICAST(p.iph.daddr))
+ nflags = IFF_BROADCAST;
+ else if (p.iph.daddr)
+ nflags = IFF_POINTOPOINT;
+
+ if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
+ err = -EINVAL;
+ break;
+ }
+ start_bh_atomic();
+ ipgre_tunnel_unlink(t);
+ t->parms.iph.saddr = p.iph.saddr;
+ t->parms.iph.daddr = p.iph.daddr;
+ t->parms.i_key = p.i_key;
+ t->parms.o_key = p.o_key;
+ memcpy(dev->dev_addr, &p.iph.saddr, 4);
+ memcpy(dev->broadcast, &p.iph.daddr, 4);
+ ipgre_tunnel_link(t);
+ end_bh_atomic();
+ netdev_state_change(dev);
+ }
+ }
+
+ if (t) {
+ err = 0;
+ if (cmd == SIOCCHGTUNNEL) {
+ t->parms.iph.ttl = p.iph.ttl;
+ t->parms.iph.tos = p.iph.tos;
+ t->parms.iph.frag_off = p.iph.frag_off;
+ }
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
+ err = -EFAULT;
+ } else
+ err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+ break;
+
+ case SIOCDELTUNNEL:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ goto done;
+
+ if (dev == &ipgre_fb_tunnel_dev) {
+ err = -EFAULT;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ goto done;
+ err = -ENOENT;
+ if ((t = ipgre_tunnel_locate(&p, 0)) == NULL)
+ goto done;
+ err = -EPERM;
+ if (t == &ipgre_fb_tunnel)
+ goto done;
+ }
+ err = unregister_netdevice(dev);
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+done:
+ MOD_DEC_USE_COUNT;
+ return err;
+}
+
+static struct net_device_stats *ipgre_tunnel_get_stats(struct device *dev)
+{
+ return &(((struct ip_tunnel*)dev->priv)->stat);
+}
+
+static int ipgre_tunnel_change_mtu(struct device *dev, int new_mtu)
+{
+ struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
+ if (new_mtu < 68 || new_mtu > 0xFFF8 - tunnel->hlen)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+/* Nice toy. Unfortunately, useless in real life :-)
+ It allows to construct virtual multiprotocol broadcast "LAN"
+ over the Internet, provided multicast routing is tuned.
+
+
+ I have no idea was this bicycle invented before me,
+ so that I had to set ARPHRD_IPGRE to a random value.
+ I have an impression, that Cisco could make something similar,
+ but this feature is apparently missing in IOS<=11.2(8).
+
+ I set up 10.66.66/24 and fec0:6666:6666::0/96 as virtual networks
+ with broadcast 224.66.66.66. If you have access to mbone, play with me :-)
+
+ ping -t 255 224.66.66.66
+
+ If nobody answers, mbone does not work.
+
+ ip tunnel add Universe mode gre remote 224.66.66.66 local <Your_real_addr> ttl 255
+ ip addr add 10.66.66.<somewhat>/24 dev Universe
+ ifconfig Universe up
+ ifconfig Universe add fe80::<Your_real_addr>/10
+ ifconfig Universe add fec0:6666:6666::<Your_real_addr>/96
+ ftp 10.66.66.66
+ ...
+ ftp fec0:6666:6666::193.233.7.65
+ ...
+
+ */
+
+static int ipgre_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+ void *daddr, void *saddr, unsigned len)
+{
+ struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
+ struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
+ u16 *p = (u16*)(iph+1);
+
+ memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
+ p[0] = t->parms.o_flags;
+ p[1] = htons(type);
+
+ /*
+ * Set the source hardware address.
+ */
+
+ if (saddr)
+ memcpy(&iph->saddr, saddr, 4);
+
+ if (daddr) {
+ memcpy(&iph->daddr, daddr, 4);
+ return t->hlen;
+ }
+ if (iph->daddr && !MULTICAST(iph->daddr))
+ return t->hlen;
+
+ return -t->hlen;
+}
+
+static int ipgre_open(struct device *dev)
+{
+ struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
+
+ MOD_INC_USE_COUNT;
+ if (MULTICAST(t->parms.iph.daddr)) {
+ struct rtable *rt;
+ if (ip_route_output(&rt, t->parms.iph.daddr,
+ t->parms.iph.saddr, RT_TOS(t->parms.iph.tos),
+ t->parms.link)) {
+ MOD_DEC_USE_COUNT;
+ return -EADDRNOTAVAIL;
+ }
+ dev = rt->u.dst.dev;
+ ip_rt_put(rt);
+ if (dev->ip_ptr == NULL) {
+ MOD_DEC_USE_COUNT;
+ return -EADDRNOTAVAIL;
+ }
+ t->mlink = dev->ifindex;
+ ip_mc_inc_group(dev->ip_ptr, t->parms.iph.daddr);
+ }
+ return 0;
+}
+
+static int ipgre_close(struct device *dev)
+{
+ struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
+ if (MULTICAST(t->parms.iph.daddr) && t->mlink) {
+ dev = dev_get_by_index(t->mlink);
+ if (dev && dev->ip_ptr)
+ ip_mc_dec_group(dev->ip_ptr, t->parms.iph.daddr);
+ }
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+#endif
+
+static void ipgre_tunnel_init_gen(struct device *dev)
+{
+ struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
+
+ dev->destructor = ipgre_tunnel_destroy;
+ dev->hard_start_xmit = ipgre_tunnel_xmit;
+ dev->get_stats = ipgre_tunnel_get_stats;
+ dev->do_ioctl = ipgre_tunnel_ioctl;
+ dev->change_mtu = ipgre_tunnel_change_mtu;
+
+ dev_init_buffers(dev);
+
+ dev->type = ARPHRD_IPGRE;
+ dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
+ dev->mtu = 1500 - sizeof(struct iphdr) - 4;
+ dev->flags = IFF_NOARP;
+ dev->iflink = 0;
+ dev->addr_len = 4;
+ memcpy(dev->dev_addr, &t->parms.iph.saddr, 4);
+ memcpy(dev->broadcast, &t->parms.iph.daddr, 4);
+}
+
+static int ipgre_tunnel_init(struct device *dev)
+{
+ struct device *tdev = NULL;
+ struct ip_tunnel *tunnel;
+ struct iphdr *iph;
+ int hlen = LL_MAX_HEADER;
+ int mtu = 1500;
+ int addend = sizeof(struct iphdr) + 4;
+
+ tunnel = (struct ip_tunnel*)dev->priv;
+ iph = &tunnel->parms.iph;
+
+ ipgre_tunnel_init_gen(dev);
+
+ /* Guess output device to choose reasonable mtu and hard_header_len */
+
+ if (iph->daddr) {
+ struct rtable *rt;
+ if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) {
+ tdev = rt->u.dst.dev;
+ ip_rt_put(rt);
+ }
+
+ dev->flags |= IFF_POINTOPOINT;
+
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+ if (MULTICAST(iph->daddr)) {
+ if (!iph->saddr)
+ return -EINVAL;
+ dev->flags = IFF_BROADCAST;
+ dev->hard_header = ipgre_header;
+ dev->open = ipgre_open;
+ dev->stop = ipgre_close;
+ }
+#endif
+ }
+
+ if (!tdev && tunnel->parms.link)
+ tdev = dev_get_by_index(tunnel->parms.link);
+
+ if (tdev) {
+ hlen = tdev->hard_header_len;
+ mtu = tdev->mtu;
+ }
+ dev->iflink = tunnel->parms.link;
+
+ /* Precalculate GRE options length */
+ if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
+ if (tunnel->parms.o_flags&GRE_CSUM)
+ addend += 4;
+ if (tunnel->parms.o_flags&GRE_KEY)
+ addend += 4;
+ if (tunnel->parms.o_flags&GRE_SEQ)
+ addend += 4;
+ }
+ dev->hard_header_len = hlen + addend;
+ dev->mtu = mtu - addend;
+ tunnel->hlen = addend;
+ return 0;
+}
+
+#ifdef MODULE
+static int ipgre_fb_tunnel_open(struct device *dev)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int ipgre_fb_tunnel_close(struct device *dev)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+#endif
+
+__initfunc(int ipgre_fb_tunnel_init(struct device *dev))
+{
+ struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
+ struct iphdr *iph;
+
+ ipgre_tunnel_init_gen(dev);
+#ifdef MODULE
+ dev->open = ipgre_fb_tunnel_open;
+ dev->stop = ipgre_fb_tunnel_close;
+#endif
+
+ iph = &ipgre_fb_tunnel.parms.iph;
+ iph->version = 4;
+ iph->protocol = IPPROTO_GRE;
+ iph->ihl = 5;
+ tunnel->hlen = sizeof(struct iphdr) + 4;
+
+ tunnels_wc[0] = &ipgre_fb_tunnel;
+ return 0;
+}
+
+
+static struct inet_protocol ipgre_protocol = {
+ ipgre_rcv, /* GRE handler */
+ ipgre_err, /* TUNNEL error control */
+ 0, /* next */
+ IPPROTO_GRE, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "GRE" /* name */
+};
+
+
+/*
+ * And now the modules code and kernel interface.
+ */
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int ipgre_init(void))
+#endif
+{
+ printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
+
+ ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel;
+ ipgre_fb_tunnel_dev.name = ipgre_fb_tunnel.parms.name;
+#ifdef MODULE
+ register_netdev(&ipgre_fb_tunnel_dev);
+#else
+ register_netdevice(&ipgre_fb_tunnel_dev);
+#endif
+
+ inet_add_protocol(&ipgre_protocol);
+ return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+ if ( inet_del_protocol(&ipgre_protocol) < 0 )
+ printk(KERN_INFO "ipgre close: can't remove protocol\n");
+
+ unregister_netdev(&ipgre_fb_tunnel_dev);
+}
+
+#endif
diff --git a/pfinet/linux-src/net/ipv4/ip_input.c b/pfinet/linux-src/net/ipv4/ip_input.c
new file mode 100644
index 00000000..545f093c
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_input.c
@@ -0,0 +1,551 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * The Internet Protocol (IP) module.
+ *
+ * Version: $Id: ip_input.c,v 1.37 1999/04/22 10:38:36 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <Alan.Cox@linux.org>
+ * Richard Underwood
+ * Stefan Becker, <stefanb@yello.ping.de>
+ * Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *
+ *
+ * Fixes:
+ * Alan Cox : Commented a couple of minor bits of surplus code
+ * Alan Cox : Undefining IP_FORWARD doesn't include the code
+ * (just stops a compiler warning).
+ * Alan Cox : Frames with >=MAX_ROUTE record routes, strict routes or loose routes
+ * are junked rather than corrupting things.
+ * Alan Cox : Frames to bad broadcast subnets are dumped
+ * We used to process them non broadcast and
+ * boy could that cause havoc.
+ * Alan Cox : ip_forward sets the free flag on the
+ * new frame it queues. Still crap because
+ * it copies the frame but at least it
+ * doesn't eat memory too.
+ * Alan Cox : Generic queue code and memory fixes.
+ * Fred Van Kempen : IP fragment support (borrowed from NET2E)
+ * Gerhard Koerting: Forward fragmented frames correctly.
+ * Gerhard Koerting: Fixes to my fix of the above 8-).
+ * Gerhard Koerting: IP interface addressing fix.
+ * Linus Torvalds : More robustness checks
+ * Alan Cox : Even more checks: Still not as robust as it ought to be
+ * Alan Cox : Save IP header pointer for later
+ * Alan Cox : ip option setting
+ * Alan Cox : Use ip_tos/ip_ttl settings
+ * Alan Cox : Fragmentation bogosity removed
+ * (Thanks to Mark.Bush@prg.ox.ac.uk)
+ * Dmitry Gorodchanin : Send of a raw packet crash fix.
+ * Alan Cox : Silly ip bug when an overlength
+ * fragment turns up. Now frees the
+ * queue.
+ * Linus Torvalds/ : Memory leakage on fragmentation
+ * Alan Cox : handling.
+ * Gerhard Koerting: Forwarding uses IP priority hints
+ * Teemu Rantanen : Fragment problems.
+ * Alan Cox : General cleanup, comments and reformat
+ * Alan Cox : SNMP statistics
+ * Alan Cox : BSD address rule semantics. Also see
+ * UDP as there is a nasty checksum issue
+ * if you do things the wrong way.
+ * Alan Cox : Always defrag, moved IP_FORWARD to the config.in file
+ * Alan Cox : IP options adjust sk->priority.
+ * Pedro Roque : Fix mtu/length error in ip_forward.
+ * Alan Cox : Avoid ip_chk_addr when possible.
+ * Richard Underwood : IP multicasting.
+ * Alan Cox : Cleaned up multicast handlers.
+ * Alan Cox : RAW sockets demultiplex in the BSD style.
+ * Gunther Mayer : Fix the SNMP reporting typo
+ * Alan Cox : Always in group 224.0.0.1
+ * Pauline Middelink : Fast ip_checksum update when forwarding
+ * Masquerading support.
+ * Alan Cox : Multicast loopback error for 224.0.0.1
+ * Alan Cox : IP_MULTICAST_LOOP option.
+ * Alan Cox : Use notifiers.
+ * Bjorn Ekwall : Removed ip_csum (from slhc.c too)
+ * Bjorn Ekwall : Moved ip_fast_csum to ip.h (inline!)
+ * Stefan Becker : Send out ICMP HOST REDIRECT
+ * Arnt Gulbrandsen : ip_build_xmit
+ * Alan Cox : Per socket routing cache
+ * Alan Cox : Fixed routing cache, added header cache.
+ * Alan Cox : Loopback didn't work right in original ip_build_xmit - fixed it.
+ * Alan Cox : Only send ICMP_REDIRECT if src/dest are the same net.
+ * Alan Cox : Incoming IP option handling.
+ * Alan Cox : Set saddr on raw output frames as per BSD.
+ * Alan Cox : Stopped broadcast source route explosions.
+ * Alan Cox : Can disable source routing
+ * Takeshi Sone : Masquerading didn't work.
+ * Dave Bonn,Alan Cox : Faster IP forwarding whenever possible.
+ * Alan Cox : Memory leaks, tramples, misc debugging.
+ * Alan Cox : Fixed multicast (by popular demand 8))
+ * Alan Cox : Fixed forwarding (by even more popular demand 8))
+ * Alan Cox : Fixed SNMP statistics [I think]
+ * Gerhard Koerting : IP fragmentation forwarding fix
+ * Alan Cox : Device lock against page fault.
+ * Alan Cox : IP_HDRINCL facility.
+ * Werner Almesberger : Zero fragment bug
+ * Alan Cox : RAW IP frame length bug
+ * Alan Cox : Outgoing firewall on build_xmit
+ * A.N.Kuznetsov : IP_OPTIONS support throughout the kernel
+ * Alan Cox : Multicast routing hooks
+ * Jos Vos : Do accounting *before* call_in_firewall
+ * Willy Konynenberg : Transparent proxying support
+ * Stephan Uphoff : Check IP header length field
+ *
+ *
+ *
+ * To Fix:
+ * IP fragmentation wants rewriting cleanly. The RFC815 algorithm is much more efficient
+ * and could be made very efficient with the addition of some virtual memory hacks to permit
+ * the allocation of a buffer that can then be 'grown' by twiddling page tables.
+ * Output fragmentation wants updating along with the buffer management to use a single
+ * interleaved copy algorithm so that fragmenting has a one copy overhead. Actual packet
+ * output should probably do its own fragmentation at the UDP/RAW layer. TCP shouldn't cause
+ * fragmentation anyway.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/config.h>
+
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <net/snmp.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#include <net/icmp.h>
+#include <net/raw.h>
+#include <net/checksum.h>
+#include <linux/ip_fw.h>
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
+#include <linux/firewall.h>
+#include <linux/mroute.h>
+#include <linux/netlink.h>
+
+/*
+ * SNMP management statistics
+ */
+
+struct ip_mib ip_statistics={2,IPDEFTTL,}; /* Forwarding=No, Default TTL=64 */
+
+int sysctl_ip_always_defrag = 0;
+
+/*
+ * Handle the issuing of an ioctl() request
+ * for the ip device. This is scheduled to
+ * disappear
+ */
+
+int ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+ switch(cmd)
+ {
+ default:
+ return(-EINVAL);
+ }
+}
+
+/*
+ * 0 - deliver
+ * 1 - block
+ */
+static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
+{
+ int type;
+
+ type = skb->h.icmph->type;
+ if (type < 32)
+ return test_bit(type, &sk->tp_pinfo.tp_raw4.filter);
+
+ /* Do not block unknown ICMP types */
+ return 0;
+}
+
+/*
+ * Process Router Attention IP option
+ */
+int ip_call_ra_chain(struct sk_buff *skb)
+{
+ struct ip_ra_chain *ra;
+ u8 protocol = skb->nh.iph->protocol;
+ struct sock *last = NULL;
+
+ for (ra = ip_ra_chain; ra; ra = ra->next) {
+ struct sock *sk = ra->sk;
+ if (sk && sk->num == protocol) {
+ if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+ skb = ip_defrag(skb);
+ if (skb == NULL)
+ return 1;
+ }
+ if (last) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2)
+ raw_rcv(last, skb2);
+ }
+ last = sk;
+ }
+ }
+
+ if (last) {
+ raw_rcv(last, skb);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Deliver IP Packets to the higher protocol layers.
+ */
+int ip_local_deliver(struct sk_buff *skb)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct inet_protocol *ipprot;
+ struct sock *raw_sk=NULL;
+ unsigned char hash;
+ int flag = 0;
+
+ /*
+ * Reassemble IP fragments.
+ */
+
+ if (sysctl_ip_always_defrag == 0 &&
+ (iph->frag_off & htons(IP_MF|IP_OFFSET))) {
+ skb = ip_defrag(skb);
+ if (!skb)
+ return 0;
+ iph = skb->nh.iph;
+ }
+
+#ifdef CONFIG_IP_MASQUERADE
+ /*
+ * Do we need to de-masquerade this packet?
+ */
+ {
+ int ret;
+ /*
+ * Some masq modules can re-inject packets if
+ * bad configured.
+ */
+
+ if((IPCB(skb)->flags&IPSKB_MASQUERADED)) {
+ printk(KERN_DEBUG "ip_input(): demasq recursion detected. Check masq modules configuration\n");
+ kfree_skb(skb);
+ return 0;
+ }
+
+ ret = ip_fw_demasquerade(&skb);
+ if (ret < 0) {
+ kfree_skb(skb);
+ return 0;
+ }
+
+ if (ret) {
+ iph=skb->nh.iph;
+ IPCB(skb)->flags |= IPSKB_MASQUERADED;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev)) {
+ kfree_skb(skb);
+ return 0;
+ }
+ return skb->dst->input(skb);
+ }
+ }
+#endif
+
+ /*
+ * Point into the IP datagram, just past the header.
+ */
+
+ skb->h.raw = skb->nh.raw + iph->ihl*4;
+
+ /*
+ * Deliver to raw sockets. This is fun as to avoid copies we want to make no
+ * surplus copies.
+ *
+ * RFC 1122: SHOULD pass TOS value up to the transport layer.
+ * -> It does. And not only TOS, but all IP header.
+ */
+
+ /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
+ hash = iph->protocol & (MAX_INET_PROTOS - 1);
+
+ /*
+ * If there maybe a raw socket we must check - if not we don't care less
+ */
+
+ if((raw_sk = raw_v4_htable[hash]) != NULL) {
+ struct sock *sknext = NULL;
+ struct sk_buff *skb1;
+ raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex);
+ if(raw_sk) { /* Any raw sockets */
+ do {
+ /* Find the next */
+ sknext = raw_v4_lookup(raw_sk->next, iph->protocol,
+ iph->saddr, iph->daddr, skb->dev->ifindex);
+ if (iph->protocol != IPPROTO_ICMP || !icmp_filter(raw_sk, skb)) {
+ if (sknext == NULL)
+ break;
+ skb1 = skb_clone(skb, GFP_ATOMIC);
+ if(skb1)
+ {
+ raw_rcv(raw_sk, skb1);
+ }
+ }
+ raw_sk = sknext;
+ } while(raw_sk!=NULL);
+
+ /* Here either raw_sk is the last raw socket, or NULL if
+ * none. We deliver to the last raw socket AFTER the
+ * protocol checks as it avoids a surplus copy.
+ */
+ }
+ }
+
+ /*
+ * skb->h.raw now points at the protocol beyond the IP header.
+ */
+
+ for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next)
+ {
+ struct sk_buff *skb2;
+
+ if (ipprot->protocol != iph->protocol)
+ continue;
+ /*
+ * See if we need to make a copy of it. This will
+ * only be set if more than one protocol wants it.
+ * and then not for the last one. If there is a pending
+ * raw delivery wait for that
+ */
+
+ if (ipprot->copy || raw_sk)
+ {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if(skb2==NULL)
+ continue;
+ }
+ else
+ {
+ skb2 = skb;
+ }
+ flag = 1;
+
+ /*
+ * Pass on the datagram to each protocol that wants it,
+ * based on the datagram protocol. We should really
+ * check the protocol handler's return values here...
+ */
+
+ ipprot->handler(skb2, ntohs(iph->tot_len) - (iph->ihl * 4));
+ }
+
+ /*
+ * All protocols checked.
+ * If this packet was a broadcast, we may *not* reply to it, since that
+ * causes (proven, grin) ARP storms and a leakage of memory (i.e. all
+ * ICMP reply messages get queued up for transmission...)
+ */
+
+ if(raw_sk!=NULL) /* Shift to last raw user */
+ {
+ raw_rcv(raw_sk, skb);
+
+ }
+ else if (!flag) /* Free and report errors */
+ {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
+ kfree_skb(skb);
+ }
+
+ return(0);
+}
+
+/*
+ * Main IP Receive routine.
+ */
+int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+ struct iphdr *iph = skb->nh.iph;
+#ifdef CONFIG_FIREWALL
+ int fwres;
+ u16 rport;
+#endif /* CONFIG_FIREWALL */
+
+ /*
+ * When the interface is in promisc. mode, drop all the crap
+ * that it receives, do not try to analyse it.
+ */
+ if (skb->pkt_type == PACKET_OTHERHOST)
+ goto drop;
+
+ ip_statistics.IpInReceives++;
+
+ /*
+ * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
+ *
+ * Is the datagram acceptable?
+ *
+ * 1. Length at least the size of an ip header
+ * 2. Version of 4
+ * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
+ * 4. Doesn't have a bogus length
+ */
+
+ if (skb->len < sizeof(struct iphdr))
+ goto inhdr_error;
+
+ if (skb->len < (iph->ihl << 2))
+ goto inhdr_error;
+
+ if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+ goto inhdr_error;
+
+ {
+ __u32 len = ntohs(iph->tot_len);
+ if (skb->len < len)
+ goto inhdr_error;
+
+ if (len < (iph->ihl << 2))
+ goto inhdr_error;
+
+ /*
+ * Our transport medium may have padded the buffer out. Now we know it
+ * is IP we can trim to the true length of the frame.
+ * Note this now means skb->len holds ntohs(iph->tot_len).
+ */
+
+ __skb_trim(skb, len);
+ }
+
+ /* Won't send ICMP reply, since skb->dst == NULL. --RR */
+ if (sysctl_ip_always_defrag != 0 &&
+ iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+ skb = ip_defrag(skb);
+ if (!skb)
+ return 0;
+ iph = skb->nh.iph;
+ ip_send_check(iph);
+ }
+
+#ifdef CONFIG_FIREWALL
+ /*
+ * See if the firewall wants to dispose of the packet.
+ *
+ * We can't do ICMP reply or local delivery before routing,
+ * so we delay those decisions until after route. --RR
+ */
+ fwres = call_in_firewall(PF_INET, dev, iph, &rport, &skb);
+ if (fwres < FW_ACCEPT && fwres != FW_REJECT)
+ goto drop;
+ iph = skb->nh.iph;
+#endif /* CONFIG_FIREWALL */
+
+ /*
+ * Initialise the virtual path cache for the packet. It describes
+ * how the packet travels inside Linux networking.
+ */
+ if (skb->dst == NULL) {
+ if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
+ goto drop;
+#ifdef CONFIG_CPU_IS_SLOW
+ if (net_cpu_congestion > 10 && !(iph->tos&IPTOS_RELIABILITY) &&
+ IPTOS_PREC(iph->tos) < IPTOS_PREC_INTERNETCONTROL) {
+ goto drop;
+ }
+#endif
+ }
+
+#ifdef CONFIG_NET_CLS_ROUTE
+ if (skb->dst->tclassid) {
+ u32 idx = skb->dst->tclassid;
+ ip_rt_acct[idx&0xFF].o_packets++;
+ ip_rt_acct[idx&0xFF].o_bytes+=skb->len;
+ ip_rt_acct[(idx>>16)&0xFF].i_packets++;
+ ip_rt_acct[(idx>>16)&0xFF].i_bytes+=skb->len;
+ }
+#endif
+
+ if (iph->ihl > 5) {
+ struct ip_options *opt;
+
+ /* It looks as overkill, because not all
+ IP options require packet mangling.
+ But it is the easiest for now, especially taking
+ into account that combination of IP options
+ and running sniffer is extremely rare condition.
+ --ANK (980813)
+ */
+
+ skb = skb_cow(skb, skb_headroom(skb));
+ if (skb == NULL)
+ return 0;
+ iph = skb->nh.iph;
+
+ skb->ip_summed = 0;
+ if (ip_options_compile(NULL, skb))
+ goto inhdr_error;
+
+ opt = &(IPCB(skb)->opt);
+ if (opt->srr) {
+ struct in_device *in_dev = dev->ip_ptr;
+ if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev)) {
+ if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
+ printk(KERN_INFO "source route option %d.%d.%d.%d -> %d.%d.%d.%d\n",
+ NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+ goto drop;
+ }
+ if (ip_options_rcv_srr(skb))
+ goto drop;
+ }
+ }
+
+#ifdef CONFIG_FIREWALL
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (fwres == FW_REDIRECT && (IPCB(skb)->redirport = rport) != 0)
+ return ip_local_deliver(skb);
+#endif /* CONFIG_IP_TRANSPARENT_PROXY */
+
+ if (fwres == FW_REJECT) {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+ goto drop;
+ }
+#endif /* CONFIG_FIREWALL */
+
+ return skb->dst->input(skb);
+
+inhdr_error:
+ ip_statistics.IpInHdrErrors++;
+drop:
+ kfree_skb(skb);
+ return(0);
+}
+
diff --git a/pfinet/linux-src/net/ipv4/ip_masq.c b/pfinet/linux-src/net/ipv4/ip_masq.c
new file mode 100644
index 00000000..8f00409f
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq.c
@@ -0,0 +1,2570 @@
+/*
+ *
+ * Masquerading functionality
+ *
+ * Copyright (c) 1994 Pauline Middelink
+ *
+ * $Id: ip_masq.c,v 1.34.2.2 1999/08/07 10:56:28 davem Exp $
+ *
+ *
+ * See ip_fw.c for original log
+ *
+ * Fixes:
+ * Joseph Gooch : Modified ip_fw_masquerade() to do a ip_route_output()
+ * (help by Dan Drown) : to choose the proper local address.
+ * (and Alexey) :
+ * Juan Jose Ciarlante : Modularized application masquerading (see ip_masq_app.c)
+ * Juan Jose Ciarlante : New struct ip_masq_seq that holds output/input delta seq.
+ * Juan Jose Ciarlante : Added hashed lookup by proto,maddr,mport and proto,saddr,sport
+ * Juan Jose Ciarlante : Fixed deadlock if free ports get exhausted
+ * Juan Jose Ciarlante : Added NO_ADDR status flag.
+ * Richard Lynch : Added IP Autoforward
+ * Nigel Metheringham : Added ICMP handling for demasquerade
+ * Nigel Metheringham : Checksum checking of masqueraded data
+ * Nigel Metheringham : Better handling of timeouts of TCP conns
+ * Delian Delchev : Added support for ICMP requests and replys
+ * Nigel Metheringham : ICMP in ICMP handling, tidy ups, bug fixes, made ICMP optional
+ * Juan Jose Ciarlante : re-assign maddr if no packet received from outside
+ * Juan Jose Ciarlante : ported to 2.1 tree
+ * Juan Jose Ciarlante : reworked control connections
+ * Steven Clarke : Added Port Forwarding
+ * Juan Jose Ciarlante : Just ONE ip_masq_new (!)
+ * Juan Jose Ciarlante : IP masq modules support
+ * Juan Jose Ciarlante : don't go into search loop if mport specified
+ * Juan Jose Ciarlante : locking
+ * Steven Clarke : IP_MASQ_S_xx state design
+ * Juan Jose Ciarlante : IP_MASQ_S state implementation
+ * Juan Jose Ciarlante : xx_get() clears timer, _put() inserts it
+ * Juan Jose Ciarlante : create /proc/net/ip_masq/
+ * Juan Jose Ciarlante : reworked checksums (save payload csum if possible)
+ * Juan Jose Ciarlante : added missing ip_fw_masquerade checksum
+ * Juan Jose Ciarlante : csum savings
+ * Juan Jose Ciarlante : added user-space tunnel creation/del, etc
+ * Juan Jose Ciarlante : (last) moved to ip_masq_user runtime module
+ * Juan Jose Ciarlante : user timeout handling again
+ * Juan Jose Ciarlante : make new modules support optional
+ * Juan Jose Ciarlante : u-space context => locks reworked
+ * Juan Jose Ciarlante : fixed stupid SMP locking bug
+ * Juan Jose Ciarlante : fixed "tap"ing in demasq path by copy-on-w
+ * Juan Jose Ciarlante : make masq_proto_doff() robust against fake sized/corrupted packets
+ * Kai Bankett : do not toss other IP protos in proto_doff()
+ * Dan Kegel : pointed correct NAT behavior for UDP streams
+ * Julian Anastasov : use daddr and dport as hash keys
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/inet.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/checksum.h>
+#include <net/ip_masq.h>
+
+#ifdef CONFIG_IP_MASQUERADE_MOD
+#include <net/ip_masq_mod.h>
+#endif
+
+#include <linux/sysctl.h>
+#include <linux/ip_fw.h>
+#include <linux/ip_masq.h>
+
+int sysctl_ip_masq_debug = 0;
+
+/*
+ * Exported wrapper
+ */
+int ip_masq_get_debug_level(void)
+{
+ return sysctl_ip_masq_debug;
+}
+
+struct ip_masq_hook *ip_masq_user_hook = NULL;
+
+/*
+ * Timeout table[state]
+ */
+/* static int masq_timeout_table[IP_MASQ_S_LAST+1] = { */
+static struct ip_masq_timeout_table masq_timeout_table = {
+ ATOMIC_INIT(0), /* refcnt */
+ 0, /* scale */
+ {
+ 30*60*HZ, /* IP_MASQ_S_NONE, */
+ 15*60*HZ, /* IP_MASQ_S_ESTABLISHED, */
+ 2*60*HZ, /* IP_MASQ_S_SYN_SENT, */
+ 1*60*HZ, /* IP_MASQ_S_SYN_RECV, */
+ 2*60*HZ, /* IP_MASQ_S_FIN_WAIT, */
+ 2*60*HZ, /* IP_MASQ_S_TIME_WAIT, */
+ 10*HZ, /* IP_MASQ_S_CLOSE, */
+ 60*HZ, /* IP_MASQ_S_CLOSE_WAIT, */
+ 30*HZ, /* IP_MASQ_S_LAST_ACK, */
+ 2*60*HZ, /* IP_MASQ_S_LISTEN, */
+ 5*60*HZ, /* IP_MASQ_S_UDP, */
+ 1*60*HZ, /* IP_MASQ_S_ICMP, */
+ 2*HZ,/* IP_MASQ_S_LAST */
+ }, /* timeout */
+};
+
+#define MASQUERADE_EXPIRE_RETRY masq_timeout_table.timeout[IP_MASQ_S_TIME_WAIT]
+
+static const char * state_name_table[IP_MASQ_S_LAST+1] = {
+ "NONE", /* IP_MASQ_S_NONE, */
+ "ESTABLISHED", /* IP_MASQ_S_ESTABLISHED, */
+ "SYN_SENT", /* IP_MASQ_S_SYN_SENT, */
+ "SYN_RECV", /* IP_MASQ_S_SYN_RECV, */
+ "FIN_WAIT", /* IP_MASQ_S_FIN_WAIT, */
+ "TIME_WAIT", /* IP_MASQ_S_TIME_WAIT, */
+ "CLOSE", /* IP_MASQ_S_CLOSE, */
+ "CLOSE_WAIT", /* IP_MASQ_S_CLOSE_WAIT, */
+ "LAST_ACK", /* IP_MASQ_S_LAST_ACK, */
+ "LISTEN", /* IP_MASQ_S_LISTEN, */
+ "UDP", /* IP_MASQ_S_UDP, */
+ "ICMP", /* IP_MASQ_S_ICMP, */
+ "BUG!", /* IP_MASQ_S_LAST */
+};
+
+#define mNO IP_MASQ_S_NONE
+#define mES IP_MASQ_S_ESTABLISHED
+#define mSS IP_MASQ_S_SYN_SENT
+#define mSR IP_MASQ_S_SYN_RECV
+#define mFW IP_MASQ_S_FIN_WAIT
+#define mTW IP_MASQ_S_TIME_WAIT
+#define mCL IP_MASQ_S_CLOSE
+#define mCW IP_MASQ_S_CLOSE_WAIT
+#define mLA IP_MASQ_S_LAST_ACK
+#define mLI IP_MASQ_S_LISTEN
+
+struct masq_tcp_states_t {
+ int next_state[IP_MASQ_S_LAST]; /* should be _LAST_TCP */
+};
+
+const char * ip_masq_state_name(int state)
+{
+ if (state >= IP_MASQ_S_LAST)
+ return "ERR!";
+ return state_name_table[state];
+}
+
+struct masq_tcp_states_t masq_tcp_states [] = {
+/* INPUT */
+/* mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI */
+/*syn*/ {{mSR, mES, mES, mSR, mSR, mSR, mSR, mSR, mSR, mSR }},
+/*fin*/ {{mCL, mCW, mSS, mTW, mTW, mTW, mCL, mCW, mLA, mLI }},
+/*ack*/ {{mCL, mES, mSS, mSR, mFW, mTW, mCL, mCW, mCL, mLI }},
+/*rst*/ {{mCL, mCL, mCL, mSR, mCL, mCL, mCL, mCL, mLA, mLI }},
+
+/* OUTPUT */
+/* mNO, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mLI */
+/*syn*/ {{mSS, mES, mSS, mES, mSS, mSS, mSS, mSS, mSS, mLI }},
+/*fin*/ {{mTW, mFW, mSS, mTW, mFW, mTW, mCL, mTW, mLA, mLI }},
+/*ack*/ {{mES, mES, mSS, mSR, mFW, mTW, mCL, mCW, mLA, mES }},
+/*rst*/ {{mCL, mCL, mSS, mCL, mCL, mTW, mCL, mCL, mCL, mCL }},
+};
+
+static __inline__ int masq_tcp_state_idx(struct tcphdr *th, int output)
+{
+ /*
+ * [0-3]: input states, [4-7]: output.
+ */
+ if (output)
+ output=4;
+
+ if (th->rst)
+ return output+3;
+ if (th->syn)
+ return output+0;
+ if (th->fin)
+ return output+1;
+ if (th->ack)
+ return output+2;
+ return -1;
+}
+
+
+
+static int masq_set_state_timeout(struct ip_masq *ms, int state)
+{
+ struct ip_masq_timeout_table *mstim = ms->timeout_table;
+ int scale;
+
+ /*
+ * Use default timeout table if no specific for this entry
+ */
+ if (!mstim)
+ mstim = &masq_timeout_table;
+
+ ms->timeout = mstim->timeout[ms->state=state];
+ scale = mstim->scale;
+
+ if (scale<0)
+ ms->timeout >>= -scale;
+ else if (scale > 0)
+ ms->timeout <<= scale;
+
+ return state;
+}
+
+static int masq_tcp_state(struct ip_masq *ms, int output, struct tcphdr *th)
+{
+ int state_idx;
+ int new_state = IP_MASQ_S_CLOSE;
+
+ if ((state_idx = masq_tcp_state_idx(th, output)) < 0) {
+ IP_MASQ_DEBUG(1, "masq_state_idx(%d)=%d!!!\n",
+ output, state_idx);
+ goto tcp_state_out;
+ }
+
+ new_state = masq_tcp_states[state_idx].next_state[ms->state];
+
+tcp_state_out:
+ if (new_state!=ms->state)
+ IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08lX:%04X-%08lX:%04X state: %s->%s\n",
+ masq_proto_name(ms->protocol),
+ output? "output" : "input ",
+ th->syn? 'S' : '.',
+ th->fin? 'F' : '.',
+ th->ack? 'A' : '.',
+ th->rst? 'R' : '.',
+ ntohl(ms->saddr), ntohs(ms->sport),
+ ntohl(ms->daddr), ntohs(ms->dport),
+ ip_masq_state_name(ms->state),
+ ip_masq_state_name(new_state));
+ return masq_set_state_timeout(ms, new_state);
+}
+
+
+/*
+ * Handle state transitions
+ */
+static int masq_set_state(struct ip_masq *ms, int output, struct iphdr *iph, void *tp)
+{
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ return masq_set_state_timeout(ms, IP_MASQ_S_ICMP);
+ case IPPROTO_UDP:
+ return masq_set_state_timeout(ms, IP_MASQ_S_UDP);
+ case IPPROTO_TCP:
+ return masq_tcp_state(ms, output, tp);
+ }
+ return -1;
+}
+
+/*
+ * Set LISTEN timeout. (ip_masq_put will setup timer)
+ */
+int ip_masq_listen(struct ip_masq *ms)
+{
+ masq_set_state_timeout(ms, IP_MASQ_S_LISTEN);
+ return ms->timeout;
+}
+
+/*
+ * Dynamic address rewriting
+ */
+extern int sysctl_ip_dynaddr;
+
+/*
+ * Lookup lock
+ */
+rwlock_t __ip_masq_lock = RW_LOCK_UNLOCKED;
+
+/*
+ * Implement IP packet masquerading
+ */
+
+/*
+ * Converts an ICMP reply code into the equivalent request code
+ */
+static __inline__ const __u8 icmp_type_request(__u8 type)
+{
+ switch (type)
+ {
+ case ICMP_ECHOREPLY: return ICMP_ECHO; break;
+ case ICMP_TIMESTAMPREPLY: return ICMP_TIMESTAMP; break;
+ case ICMP_INFO_REPLY: return ICMP_INFO_REQUEST; break;
+ case ICMP_ADDRESSREPLY: return ICMP_ADDRESS; break;
+ default: return (255); break;
+ }
+}
+
+/*
+ * Helper macros - attempt to make code clearer!
+ */
+
+/* ID used in ICMP lookups */
+#define icmp_id(icmph) ((icmph->un).echo.id)
+/* (port) hash value using in ICMP lookups for requests */
+#define icmp_hv_req(icmph) ((__u16)(icmph->code+(__u16)(icmph->type<<8)))
+/* (port) hash value using in ICMP lookups for replies */
+#define icmp_hv_rep(icmph) ((__u16)(icmph->code+(__u16)(icmp_type_request(icmph->type)<<8)))
+
+/*
+ * Last masq_port number in use.
+ * Will cycle in MASQ_PORT boundaries.
+ */
+static __u16 masq_port = PORT_MASQ_BEGIN;
+static spinlock_t masq_port_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * free ports counters (UDP & TCP)
+ *
+ * Their value is _less_ or _equal_ to actual free ports:
+ * same masq port, diff masq addr (firewall iface address) allocated
+ * entries are accounted but their actually don't eat a more than 1 port.
+ *
+ * Greater values could lower MASQ_EXPIRATION setting as a way to
+ * manage 'masq_entries resource'.
+ *
+ * By default we will reuse masq.port iff (output) connection
+ * (5-upla) if not duplicated.
+ * This may break midentd and others ...
+ */
+
+#ifdef CONFIG_IP_MASQ_NREUSE
+#define PORT_MASQ_MUL 1
+#else
+#define PORT_MASQ_MUL 10
+#endif
+
+/*
+ * At the moment, hardcore in sync with masq_proto_num
+ */
+atomic_t ip_masq_free_ports[3] = {
+ ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* UDP */
+ ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* TCP */
+ ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* ICMP */
+};
+
+/*
+ * Counts entries that have been requested with specific mport.
+ * Used for incoming packets to "relax" input rule (port in MASQ range).
+ */
+atomic_t mport_count = ATOMIC_INIT(0);
+
+EXPORT_SYMBOL(ip_masq_get_debug_level);
+EXPORT_SYMBOL(ip_masq_new);
+EXPORT_SYMBOL(ip_masq_listen);
+EXPORT_SYMBOL(ip_masq_free_ports);
+EXPORT_SYMBOL(ip_masq_out_get);
+EXPORT_SYMBOL(ip_masq_in_get);
+EXPORT_SYMBOL(ip_masq_put);
+EXPORT_SYMBOL(ip_masq_control_add);
+EXPORT_SYMBOL(ip_masq_control_del);
+EXPORT_SYMBOL(ip_masq_control_get);
+EXPORT_SYMBOL(ip_masq_user_hook);
+EXPORT_SYMBOL(ip_masq_state_name);
+EXPORT_SYMBOL(ip_masq_select_addr);
+EXPORT_SYMBOL(__ip_masq_lock);
+EXPORT_SYMBOL(ip_masq_m_table);
+EXPORT_SYMBOL(ip_masq_s_table);
+EXPORT_SYMBOL(ip_masq_d_table);
+
+/*
+ * 3 ip_masq hash double linked tables:
+ * 2 for input m{addr,port} and output s{addr,port} pkts lookups.
+ * 1 for extra modules support (daddr)
+ */
+
+#define IP_MASQ_NTABLES 3
+
+struct list_head ip_masq_m_table[IP_MASQ_TAB_SIZE];
+struct list_head ip_masq_s_table[IP_MASQ_TAB_SIZE];
+struct list_head ip_masq_d_table[IP_MASQ_TAB_SIZE];
+
+/*
+ * timeouts
+ */
+
+#if 000 /* FIXED timeout handling */
+static struct ip_fw_masq ip_masq_dummy = {
+ MASQUERADE_EXPIRE_TCP,
+ MASQUERADE_EXPIRE_TCP_FIN,
+ MASQUERADE_EXPIRE_UDP
+};
+
+EXPORT_SYMBOL(ip_masq_expire);
+struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;
+#endif
+
+/*
+ * These flags enable non-strict d{addr,port} checks
+ * Given that both (in/out) lookup tables are hashed
+ * by m{addr,port} and s{addr,port} this is quite easy
+ */
+
+#define MASQ_DADDR_PASS (IP_MASQ_F_NO_DADDR|IP_MASQ_F_DLOOSE)
+#define MASQ_DPORT_PASS (IP_MASQ_F_NO_DPORT|IP_MASQ_F_DLOOSE)
+
+/*
+ * By default enable dest loose semantics
+ */
+#define CONFIG_IP_MASQ_LOOSE_DEFAULT 1
+
+
+/*
+ * Set masq expiration (deletion) and adds timer,
+ * if timeout==0 cancel expiration.
+ * Warning: it does not check/delete previous timer!
+ */
+
+static void __ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
+{
+ if (tout) {
+ ms->timer.expires = jiffies+tout;
+ add_timer(&ms->timer);
+ } else {
+ del_timer(&ms->timer);
+ }
+}
+
+
+/*
+ * Returns hash value
+ */
+
+static __inline__ unsigned
+ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port)
+{
+ return (proto^ntohl(addr)^ntohs(port)) & (IP_MASQ_TAB_SIZE-1);
+}
+
+/*
+ * Hashes ip_masq by its proto,addrs,ports.
+ * should be called with locked tables.
+ * returns bool success.
+ */
+
+static int ip_masq_hash(struct ip_masq *ms)
+{
+ unsigned hash;
+
+ if (ms->flags & IP_MASQ_F_HASHED) {
+ IP_MASQ_ERR( "ip_masq_hash(): request for already hashed, called from %p\n",
+ __builtin_return_address(0));
+ return 0;
+ }
+ atomic_add(IP_MASQ_NTABLES, &ms->refcnt);
+
+ if ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |
+ IP_MASQ_F_SIMPLE_HASH)) == 0)
+ /*
+ * Hash by proto,m{addr,port},d{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol,
+ ms->maddr^ms->daddr, ms->mport^ms->dport);
+ else
+ /*
+ * Hash by proto,m{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
+
+ list_add(&ms->m_list, &ip_masq_m_table[hash]);
+
+ if ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |
+ IP_MASQ_F_NO_SADDR | IP_MASQ_F_NO_SPORT |
+ IP_MASQ_F_SIMPLE_HASH)) == 0)
+ /*
+ * Hash by proto,s{addr,port},d{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol,
+ ms->saddr^ms->daddr, ms->sport^ms->dport);
+ else
+ /*
+ * Hash by proto,s{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
+
+ list_add(&ms->s_list, &ip_masq_s_table[hash]);
+
+ /*
+ * Hash by proto,d{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol, ms->daddr, ms->dport);
+ list_add(&ms->d_list, &ip_masq_d_table[hash]);
+
+
+ ms->flags |= IP_MASQ_F_HASHED;
+ return 1;
+}
+
+/*
+ * UNhashes ip_masq from ip_masq_[ms]_tables.
+ * should be called with locked tables.
+ * returns bool success.
+ */
+
+static int ip_masq_unhash(struct ip_masq *ms)
+{
+ if (!(ms->flags & IP_MASQ_F_HASHED)) {
+ IP_MASQ_ERR( "ip_masq_unhash(): request for unhash flagged, called from %p\n",
+ __builtin_return_address(0));
+ return 0;
+ }
+ list_del(&ms->m_list);
+ list_del(&ms->s_list);
+ list_del(&ms->d_list);
+
+ atomic_sub(IP_MASQ_NTABLES, &ms->refcnt);
+
+ ms->flags &= ~IP_MASQ_F_HASHED;
+ return 1;
+}
+
+/*
+ * Returns ip_masq associated with supplied parameters, either
+ * broken out of the ip/tcp headers or directly supplied for those
+ * pathological protocols with address/port in the data stream
+ * (ftp, irc). addresses and ports are in network order.
+ * called for pkts coming from OUTside-to-INside the firewall.
+ *
+ * s_addr, s_port: pkt source address (foreign host)
+ * d_addr, d_port: pkt dest address (firewall)
+ *
+ * NB. Cannot check destination address, just for the incoming port.
+ * reason: archie.doc.ac.uk has 6 interfaces, you send to
+ * phoenix and get a reply from any other interface(==dst)!
+ *
+ * [Only for UDP] - AC
+ *
+ * Caller must lock tables
+ */
+
+static struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ unsigned hash;
+ struct ip_masq *ms = NULL;
+ struct list_head *l,*e;
+
+ hash = ip_masq_hash_key(protocol, d_addr^s_addr, d_port^s_port);
+
+ l = &ip_masq_m_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, m_list);
+ if (s_port==ms->dport && s_addr==ms->daddr &&
+ d_port==ms->mport && protocol==ms->protocol &&
+ d_addr==ms->maddr &&
+ ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS)) == 0)
+ ) {
+ IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+ }
+
+ hash = ip_masq_hash_key(protocol, d_addr, d_port);
+
+ l = &ip_masq_m_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, m_list);
+ if (protocol==ms->protocol &&
+ (d_addr==ms->maddr && d_port==ms->mport) &&
+ (s_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
+ (s_port==ms->dport || ms->flags & MASQ_DPORT_PASS)
+ ) {
+ IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+ }
+ IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX fail\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ ms = NULL;
+out:
+ return ms;
+}
+
+/*
+ * Returns ip_masq associated with supplied parameters, either
+ * broken out of the ip/tcp headers or directly supplied for those
+ * pathological protocols with address/port in the data stream
+ * (ftp, irc). addresses and ports are in network order.
+ * called for pkts coming from inside-to-OUTside the firewall.
+ *
+ * Normally we know the source address and port but for some protocols
+ * (e.g. ftp PASV) we do not know the source port initially. Alas the
+ * hash is keyed on source port so if the first lookup fails then try again
+ * with a zero port, this time only looking at entries marked "no source
+ * port".
+ *
+ * Caller must lock tables
+ */
+
+static struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ unsigned hash;
+ struct ip_masq *ms = NULL;
+ struct list_head *l,*e;
+
+ /*
+ * Check for "full" addressed entries
+ */
+ hash = ip_masq_hash_key(protocol, s_addr^d_addr, s_port^d_port);
+
+ l = &ip_masq_s_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, s_list);
+ if (d_addr==ms->daddr && d_port==ms->dport &&
+ s_addr==ms->saddr && s_port==ms->sport &&
+ protocol==ms->protocol &&
+ ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |
+ IP_MASQ_F_NO_SADDR | IP_MASQ_F_NO_SPORT)) == 0)
+ ) {
+ IP_MASQ_DEBUG(2, "lk/out0 %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+
+ }
+
+ hash = ip_masq_hash_key(protocol, s_addr, s_port);
+
+ l = &ip_masq_s_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, s_list);
+ if (protocol == ms->protocol &&
+ s_addr == ms->saddr && s_port == ms->sport &&
+ (d_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
+ (d_port==ms->dport || ms->flags & MASQ_DPORT_PASS)
+ ) {
+ IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+
+ }
+
+ /*
+ * Check for NO_SPORT entries
+ */
+ hash = ip_masq_hash_key(protocol, s_addr, 0);
+ l = &ip_masq_s_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, s_list);
+ if (ms->flags & IP_MASQ_F_NO_SPORT &&
+ protocol == ms->protocol &&
+ s_addr == ms->saddr &&
+ (d_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
+ (d_port==ms->dport || ms->flags & MASQ_DPORT_PASS)
+ ) {
+ IP_MASQ_DEBUG(2, "lk/out2 %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+ }
+ IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX fail\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ ms = NULL;
+out:
+ return ms;
+}
+
+#ifdef CONFIG_IP_MASQ_NREUSE
+/*
+ * Returns ip_masq for given proto,m_addr,m_port.
+ * called by allocation routine to find an unused m_port.
+ *
+ * Caller must lock tables
+ */
+
+static struct ip_masq * __ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)
+{
+ unsigned hash;
+ struct ip_masq *ms = NULL;
+
+ hash = ip_masq_hash_key(protocol, m_addr, m_port);
+
+ for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
+ if ( protocol==ms->protocol &&
+ (m_addr==ms->maddr && m_port==ms->mport)) {
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+ }
+
+out:
+ return ms;
+}
+#endif
+
+struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ struct ip_masq *ms;
+
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_out_get(protocol, s_addr, s_port, d_addr, d_port);
+ read_unlock(&__ip_masq_lock);
+
+ if (ms)
+ __ip_masq_set_expire(ms, 0);
+ return ms;
+}
+
+struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ struct ip_masq *ms;
+
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_in_get(protocol, s_addr, s_port, d_addr, d_port);
+ read_unlock(&__ip_masq_lock);
+
+ if (ms)
+ __ip_masq_set_expire(ms, 0);
+ return ms;
+}
+
+static __inline__ void __ip_masq_put(struct ip_masq *ms)
+{
+ atomic_dec(&ms->refcnt);
+}
+
+void ip_masq_put(struct ip_masq *ms)
+{
+ /*
+ * Decrement refcnt
+ */
+ __ip_masq_put(ms);
+
+ /*
+ * if refcnt==IP_MASQ_NTABLES
+ */
+ if (atomic_read(&ms->refcnt)==IP_MASQ_NTABLES) {
+ __ip_masq_set_expire(ms, ms->timeout);
+ } else {
+ IP_MASQ_DEBUG(0, "did not set timer with refcnt=%d, called from %p\n",
+ atomic_read(&ms->refcnt),
+ __builtin_return_address(0));
+ }
+}
+
+extern int sysctl_ip_always_defrag;
+
+static void masq_expire(unsigned long data)
+{
+ struct ip_masq *ms = (struct ip_masq *)data;
+ ms->timeout = MASQUERADE_EXPIRE_RETRY;
+
+ /*
+ * hey, I'm using it
+ */
+ atomic_inc(&ms->refcnt);
+
+ IP_MASQ_DEBUG(1, "Masqueraded %s %08lX:%04X expired\n",
+ masq_proto_name(ms->protocol),
+ ntohl(ms->saddr),ntohs(ms->sport));
+
+ write_lock(&__ip_masq_lock);
+
+#if 0000
+ /*
+ * Already locked, do bounce ...
+ */
+ if (ip_masq_nlocks(&__ip_masq_lock) != 1) {
+ goto masq_expire_later;
+ }
+
+#endif
+ /*
+ * do I control anybody?
+ */
+ if (atomic_read(&ms->n_control))
+ goto masq_expire_later;
+
+ /*
+ * does anybody controls me?
+ */
+
+ if (ms->control)
+ ip_masq_control_del(ms);
+
+ if (ip_masq_unhash(ms)) {
+ if (ms->flags&IP_MASQ_F_MPORT) {
+ atomic_dec(&mport_count);
+ } else {
+ atomic_inc(ip_masq_free_ports + masq_proto_num(ms->protocol));
+ }
+ ip_masq_unbind_app(ms);
+ }
+
+ /*
+ * refcnt==1 implies I'm the only one referrer
+ */
+ if (atomic_read(&ms->refcnt) == 1) {
+ kfree_s(ms,sizeof(*ms));
+ sysctl_ip_always_defrag--;
+ MOD_DEC_USE_COUNT;
+ goto masq_expire_out;
+ }
+
+masq_expire_later:
+ IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X masq.refcnt-1=%d masq.n_control=%d\n",
+ masq_proto_name(ms->protocol),
+ ntohl(ms->saddr), ntohs(ms->sport),
+ ntohl(ms->daddr), ntohs(ms->dport),
+ atomic_read(&ms->refcnt)-1,
+ atomic_read(&ms->n_control));
+
+ ip_masq_put(ms);
+
+masq_expire_out:
+ write_unlock(&__ip_masq_lock);
+}
+
+static __u16 get_next_mport(void)
+{
+ __u16 mport;
+
+ spin_lock_irq(&masq_port_lock);
+ /*
+ * Try the next available port number
+ */
+ mport = htons(masq_port++);
+ if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
+
+ spin_unlock_irq(&masq_port_lock);
+ return mport;
+}
+
+/*
+ * Create a new masquerade list entry, also allocate an
+ * unused mport, keeping the portnumber between the
+ * given boundaries MASQ_BEGIN and MASQ_END.
+ *
+ * Be careful, it can be called from u-space
+ */
+
+struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
+{
+ struct ip_masq *ms, *mst;
+ int ports_tried;
+ atomic_t *free_ports_p = NULL;
+ static int n_fails = 0;
+ int prio;
+
+
+ if (masq_proto_num(proto)!=-1 && mport == 0) {
+ free_ports_p = ip_masq_free_ports + masq_proto_num(proto);
+
+ if (atomic_read(free_ports_p) == 0) {
+ if (++n_fails < 5)
+ IP_MASQ_ERR( "ip_masq_new(proto=%s): no free ports.\n",
+ masq_proto_name(proto));
+ return NULL;
+ }
+ }
+
+ prio = (mflags&IP_MASQ_F_USER) ? GFP_KERNEL : GFP_ATOMIC;
+
+ ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), prio);
+ if (ms == NULL) {
+ if (++n_fails < 5)
+ IP_MASQ_ERR("ip_masq_new(proto=%s): no memory available.\n",
+ masq_proto_name(proto));
+ return NULL;
+ }
+ MOD_INC_USE_COUNT;
+ sysctl_ip_always_defrag++;
+ memset(ms, 0, sizeof(*ms));
+ INIT_LIST_HEAD(&ms->s_list);
+ INIT_LIST_HEAD(&ms->m_list);
+ INIT_LIST_HEAD(&ms->d_list);
+ init_timer(&ms->timer);
+ ms->timer.data = (unsigned long)ms;
+ ms->timer.function = masq_expire;
+ ms->protocol = proto;
+ ms->saddr = saddr;
+ ms->sport = sport;
+ ms->daddr = daddr;
+ ms->dport = dport;
+ ms->flags = mflags;
+ ms->app_data = NULL;
+ ms->control = NULL;
+
+ atomic_set(&ms->n_control,0);
+ atomic_set(&ms->refcnt,0);
+
+ if (proto == IPPROTO_UDP && !mport)
+#ifdef CONFIG_IP_MASQ_LOOSE_DEFAULT
+ /*
+ * Flag this tunnel as "dest loose"
+ *
+ */
+ ms->flags |= IP_MASQ_F_DLOOSE;
+#else
+ ms->flags |= IP_MASQ_F_NO_DADDR;
+#endif
+
+
+ /* get masq address from rif */
+ ms->maddr = maddr;
+
+ /*
+ * This flag will allow masq. addr (ms->maddr)
+ * to follow forwarding interface address.
+ */
+ ms->flags |= IP_MASQ_F_NO_REPLY;
+
+ /*
+ * We want a specific mport. Be careful.
+ */
+ if (masq_proto_num(proto) == -1 || mport) {
+ ms->mport = mport;
+
+ /*
+ * Check 5-upla uniqueness
+ */
+ if (mflags & IP_MASQ_F_USER)
+ write_lock_bh(&__ip_masq_lock);
+ else
+ write_lock(&__ip_masq_lock);
+
+ mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
+ if (mst==NULL) {
+ ms->flags |= IP_MASQ_F_MPORT;
+
+ atomic_inc(&mport_count);
+ ip_masq_hash(ms);
+
+ if (mflags & IP_MASQ_F_USER)
+ write_unlock_bh(&__ip_masq_lock);
+ else
+ write_unlock(&__ip_masq_lock);
+
+ ip_masq_bind_app(ms);
+ atomic_inc(&ms->refcnt);
+ masq_set_state_timeout(ms, IP_MASQ_S_NONE);
+ return ms;
+ }
+ if (mflags & IP_MASQ_F_USER)
+ write_unlock_bh(&__ip_masq_lock);
+ else
+ write_unlock(&__ip_masq_lock);
+
+ __ip_masq_put(mst);
+
+ IP_MASQ_ERR( "Already used connection: %s, %d.%d.%d.%d:%d => %d.%d.%d.%d:%d, called from %p\n",
+ masq_proto_name(proto),
+ NIPQUAD(maddr), ntohs(mport),
+ NIPQUAD(daddr), ntohs(dport),
+ __builtin_return_address(0));
+
+
+ goto mport_nono;
+ }
+
+
+ for (ports_tried = 0;
+ (atomic_read(free_ports_p) && (ports_tried <= (PORT_MASQ_END - PORT_MASQ_BEGIN)));
+ ports_tried++){
+
+ mport = ms->mport = get_next_mport();
+ /*
+ * lookup to find out if this connection is used.
+ */
+
+ if (mflags & IP_MASQ_F_USER)
+ write_lock_bh(&__ip_masq_lock);
+ else
+ write_lock(&__ip_masq_lock);
+
+#ifdef CONFIG_IP_MASQ_NREUSE
+ mst = __ip_masq_getbym(proto, maddr, mport);
+#else
+ mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
+#endif
+ if (mst == NULL) {
+
+ if (atomic_read(free_ports_p) == 0) {
+ if (mflags & IP_MASQ_F_USER)
+ write_unlock_bh(&__ip_masq_lock);
+ else
+ write_unlock(&__ip_masq_lock);
+
+ break;
+ }
+ atomic_dec(free_ports_p);
+ ip_masq_hash(ms);
+
+ if (mflags & IP_MASQ_F_USER)
+ write_unlock_bh(&__ip_masq_lock);
+ else
+ write_unlock(&__ip_masq_lock);
+
+ ip_masq_bind_app(ms);
+ n_fails = 0;
+ atomic_inc(&ms->refcnt);
+ masq_set_state_timeout(ms, IP_MASQ_S_NONE);
+ return ms;
+ }
+ if (mflags & IP_MASQ_F_USER)
+ write_unlock_bh(&__ip_masq_lock);
+ else
+ write_unlock(&__ip_masq_lock);
+
+ __ip_masq_put(mst);
+ }
+
+ if (++n_fails < 5)
+ IP_MASQ_ERR( "ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",
+ masq_proto_name(ms->protocol),
+ atomic_read(free_ports_p));
+mport_nono:
+ kfree_s(ms, sizeof(*ms));
+
+ sysctl_ip_always_defrag--;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+/*
+ * Get transport protocol data offset, check against size
+ * return:
+ * 0 if other IP proto
+ * -1 if error
+ */
+static __inline__ int proto_doff(unsigned proto, char *th, unsigned size)
+{
+ int ret = -1;
+ switch (proto) {
+ case IPPROTO_ICMP:
+ if (size >= sizeof(struct icmphdr))
+ ret = sizeof(struct icmphdr);
+ break;
+ case IPPROTO_UDP:
+ if (size >= sizeof(struct udphdr))
+ ret = sizeof(struct udphdr);
+ break;
+ case IPPROTO_TCP:
+ /*
+ * Is this case, this check _also_ avoids
+ * touching an invalid pointer if
+ * size is invalid
+ */
+ if (size >= sizeof(struct tcphdr)) {
+ ret = ((struct tcphdr*)th)->doff << 2;
+ if (ret > size) {
+ ret = -1 ;
+ }
+ }
+
+ break;
+ default:
+ /* Other proto: nothing to say, by now :) */
+ ret = 0;
+ }
+ if (ret < 0)
+ IP_MASQ_DEBUG(0, "mess proto_doff for proto=%d, size =%d\n",
+ proto, size);
+ return ret;
+}
+
+int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ union ip_masq_tphdr h;
+ struct ip_masq *ms;
+ int size;
+
+ /*
+ * doff holds transport protocol data offset
+ * csum holds its checksum
+ * csum_ok says if csum is valid
+ */
+ int doff = 0;
+ int csum = 0;
+ int csum_ok = 0;
+
+ /*
+ * We can only masquerade protocols with ports... and hack some ICMPs
+ */
+
+ h.raw = (char*) iph + iph->ihl * 4;
+ size = ntohs(iph->tot_len) - (iph->ihl * 4);
+
+
+ doff = proto_doff(iph->protocol, h.raw, size);
+ if (doff <= 0) {
+ /*
+ * Output path: do not pass other IP protos nor
+ * invalid packets.
+ */
+ return -1;
+ }
+
+ /* Lets determine our maddr now, shall we? */
+ if (maddr == 0) {
+ struct rtable *rt;
+ struct rtable *skb_rt = (struct rtable*)skb->dst;
+ struct device *skb_dev = skb_rt->u.dst.dev;
+
+ if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos)|RTO_CONN, skb_dev?skb_dev->ifindex:0)) {
+ /* Fallback on old method */
+ /* This really shouldn't happen... */
+ maddr = inet_select_addr(skb_dev, skb_rt->rt_gateway, RT_SCOPE_UNIVERSE);
+ } else {
+ /* Route lookup succeeded */
+ maddr = rt->rt_src;
+ ip_rt_put(rt);
+ }
+ }
+
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ return(ip_fw_masq_icmp(skb_p, maddr));
+ case IPPROTO_UDP:
+ if (h.uh->check == 0)
+ /* No UDP checksum */
+ break;
+ case IPPROTO_TCP:
+ /* Make sure packet is in the masq range */
+ IP_MASQ_DEBUG(3, "O-pkt: %s size=%d\n",
+ masq_proto_name(iph->protocol),
+ size);
+
+#ifdef CONFIG_IP_MASQ_DEBUG
+ if (ip_masq_get_debug_level() > 3) {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+#endif
+ /* Check that the checksum is OK */
+ switch (skb->ip_summed)
+ {
+ case CHECKSUM_NONE:
+ {
+ csum = csum_partial(h.raw + doff, size - doff, 0);
+ IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n",
+ masq_proto_name(iph->protocol),
+ csum);
+
+ skb->csum = csum_partial(h.raw , doff, csum);
+ }
+ case CHECKSUM_HW:
+ if (csum_tcpudp_magic(iph->saddr, iph->daddr,
+ size, iph->protocol, skb->csum))
+ {
+ IP_MASQ_DEBUG(0, "Outgoing failed %s checksum from %d.%d.%d.%d (size=%d)!\n",
+ masq_proto_name(iph->protocol),
+ NIPQUAD(iph->saddr),
+ size);
+ return -1;
+ }
+ default:
+ /* CHECKSUM_UNNECESSARY */
+ }
+ break;
+ default:
+ return -1;
+ }
+ /*
+ * Now hunt the list to see if we have an old entry
+ */
+
+ /* h.raw = (char*) iph + iph->ihl * 4; */
+
+ IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n",
+ masq_proto_name(iph->protocol),
+ ntohl(iph->saddr), ntohs(h.portp[0]),
+ ntohl(iph->daddr), ntohs(h.portp[1]));
+
+ ms = ip_masq_out_get_iph(iph);
+ if (ms!=NULL) {
+
+ /*
+ * If sysctl !=0 and no pkt has been received yet
+ * in this tunnel and routing iface address has changed...
+ * "You are welcome, diald".
+ */
+ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {
+
+ if (sysctl_ip_dynaddr > 1) {
+ IP_MASQ_INFO( "ip_fw_masquerade(): change masq.addr from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(ms->maddr),NIPQUAD(maddr));
+ }
+
+ write_lock(&__ip_masq_lock);
+
+ ip_masq_unhash(ms);
+ ms->maddr = maddr;
+ ip_masq_hash(ms);
+
+ write_unlock(&__ip_masq_lock);
+ }
+
+ /*
+ * Set sport if not defined yet (e.g. ftp PASV). Because
+ * masq entries are hashed on sport, unhash with old value
+ * and hash with new.
+ */
+
+ if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) {
+
+ write_lock(&__ip_masq_lock);
+
+ ip_masq_unhash(ms);
+ ms->flags &= ~IP_MASQ_F_NO_SPORT;
+ ms->sport = h.portp[0];
+ ip_masq_hash(ms); /* hash on new sport */
+
+ write_unlock(&__ip_masq_lock);
+
+ IP_MASQ_DEBUG(1, "ip_fw_masquerade(): filled sport=%d\n",
+ ntohs(ms->sport));
+ }
+ if (ms->flags & IP_MASQ_F_DLOOSE) {
+ /*
+ * update dest loose values
+ */
+ ms->dport = h.portp[1];
+ ms->daddr = iph->daddr;
+ }
+ } else {
+ /*
+ * Nope, not found, create a new entry for it
+ */
+
+#ifdef CONFIG_IP_MASQUERADE_MOD
+ if (!(ms = ip_masq_mod_out_create(skb, iph, maddr)))
+#endif
+ ms = ip_masq_new(iph->protocol,
+ maddr, 0,
+ iph->saddr, h.portp[0],
+ iph->daddr, h.portp[1],
+ 0);
+ if (ms == NULL)
+ return -1;
+ }
+
+ /*
+ * Call module's output update hook
+ */
+
+#ifdef CONFIG_IP_MASQUERADE_MOD
+ ip_masq_mod_out_update(skb, iph, ms);
+#endif
+
+ /*
+ * Change the fragments origin
+ */
+
+ size = skb->len - (h.raw - skb->nh.raw);
+
+ /*
+ * Set iph addr and port from ip_masq obj.
+ */
+ iph->saddr = ms->maddr;
+ h.portp[0] = ms->mport;
+
+ /*
+ * Invalidate csum saving if tunnel has masq helper
+ */
+
+ if (ms->app)
+ csum_ok = 0;
+
+ /*
+ * Attempt ip_masq_app call.
+ * will fix ip_masq and iph seq stuff
+ */
+ if (ip_masq_app_pkt_out(ms, skb_p, maddr) != 0)
+ {
+ /*
+ * skb has possibly changed, update pointers.
+ */
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ h.raw = (char*) iph + iph->ihl *4;
+ size = skb->len - (h.raw - skb->nh.raw);
+ /* doff should have not changed */
+ }
+
+ /*
+ * Adjust packet accordingly to protocol
+ */
+
+ /*
+ * Transport's payload partial csum
+ */
+
+ if (!csum_ok) {
+ csum = csum_partial(h.raw + doff, size - doff, 0);
+ }
+ skb->csum = csum;
+
+ IP_MASQ_DEBUG(3, "O-pkt: %s size=%d O-datacsum=%d\n",
+ masq_proto_name(iph->protocol),
+ size,
+ csum);
+
+ /*
+ * Protocol csum
+ */
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ h.th->check = 0;
+ h.th->check=csum_tcpudp_magic(iph->saddr, iph->daddr,
+ size, iph->protocol,
+ csum_partial(h.raw , doff, csum));
+ IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n",
+ masq_proto_name(iph->protocol),
+ h.th->check,
+ (char*) & (h.th->check) - (char*) h.raw);
+
+ break;
+ case IPPROTO_UDP:
+ h.uh->check = 0;
+ h.uh->check=csum_tcpudp_magic(iph->saddr, iph->daddr,
+ size, iph->protocol,
+ csum_partial(h.raw , doff, csum));
+ if (h.uh->check == 0)
+ h.uh->check = 0xFFFF;
+ IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n",
+ masq_proto_name(iph->protocol),
+ h.uh->check,
+ (char*) &(h.uh->check)- (char*) h.raw);
+ break;
+ }
+ ip_send_check(iph);
+
+ IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n",
+ ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));
+
+ masq_set_state(ms, 1, iph, h.portp);
+ ip_masq_put(ms);
+
+ return 0;
+ }
+
+/*
+ * Restore original addresses and ports in the original IP
+ * datagram if the failing packet has been [de]masqueraded.
+ * This is ugly in the extreme. We no longer have the original
+ * packet so we have to reconstruct it from the failing packet
+ * plus data in the masq tables. The resulting "original data"
+ * should be good enough to tell the sender which session to
+ * throttle. Relies on far too much knowledge of masq internals,
+ * there ought to be a better way - KAO 990303.
+ *
+ * Moved here from icmp.c - JJC.
+ * Already known: type == ICMP_DEST_UNREACH, IPSKB_MASQUERADED
+ * skb->nh.iph points to original header.
+ *
+ * Must try both OUT and IN tables; we could add a flag
+ * ala IPSKB_MASQUERADED to avoid 2nd tables lookup, but this is VERY
+ * unlike because routing makes mtu decision before reaching
+ * ip_fw_masquerade().
+ *
+ */
+int ip_fw_unmasq_icmp(struct sk_buff *skb) {
+ struct ip_masq *ms;
+ struct iphdr *iph = skb->nh.iph;
+ __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+
+ /*
+ * Always called from _bh context: use read_[un]lock()
+ */
+
+ /*
+ * Peek "out" table, this packet has bounced:
+ * out->in(frag_needed!)->OUT[icmp]
+ *
+ * iph->daddr is IN host
+ * iph->saddr is OUT host
+ */
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_out_get(iph->protocol,
+ iph->daddr, portp[1],
+ iph->saddr, portp[0]);
+ read_unlock(&__ip_masq_lock);
+ if (ms) {
+ IP_MASQ_DEBUG(1, "Incoming frag_need rewrited from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(iph->daddr), NIPQUAD(ms->maddr));
+ iph->daddr = ms->maddr;
+ portp[1] = ms->mport;
+ __ip_masq_put(ms);
+ return 1;
+ }
+ /*
+ * Peek "in" table
+ * in->out(frag_needed!)->IN[icmp]
+ *
+ * iph->daddr is OUT host
+ * iph->saddr is MASQ host
+ *
+ */
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_in_get(iph->protocol,
+ iph->daddr, portp[1],
+ iph->saddr, portp[0]);
+ read_unlock(&__ip_masq_lock);
+ if (ms) {
+ IP_MASQ_DEBUG(1, "Outgoing frag_need rewrited from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(iph->saddr), NIPQUAD(ms->saddr));
+ iph->saddr = ms->saddr;
+ portp[0] = ms->sport;
+ __ip_masq_put(ms);
+ return 1;
+ }
+ return 0;
+
+}
+/*
+ * Handle ICMP messages in forward direction.
+ * Find any that might be relevant, check against existing connections,
+ * forward to masqueraded host if relevant.
+ * Currently handles error types - unreachable, quench, ttl exceeded
+ */
+
+int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+ struct iphdr *ciph; /* The ip header contained within the ICMP */
+ __u16 *pptr; /* port numbers from TCP/UDP contained header */
+ struct ip_masq *ms;
+ unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4);
+
+ IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %lX -> %lX\n",
+ icmph->type, ntohs(icmp_id(icmph)),
+ ntohl(iph->saddr), ntohl(iph->daddr));
+
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if ((icmph->type == ICMP_ECHO ) ||
+ (icmph->type == ICMP_TIMESTAMP ) ||
+ (icmph->type == ICMP_INFO_REQUEST ) ||
+ (icmph->type == ICMP_ADDRESS )) {
+
+ IP_MASQ_DEBUG(2, "icmp request rcv %lX->%lX id %d type %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type);
+
+ ms = ip_masq_out_get(iph->protocol,
+ iph->saddr,
+ icmp_id(icmph),
+ iph->daddr,
+ icmp_hv_req(icmph));
+ if (ms == NULL) {
+ ms = ip_masq_new(iph->protocol,
+ maddr, 0,
+ iph->saddr, icmp_id(icmph),
+ iph->daddr, icmp_hv_req(icmph),
+ 0);
+ if (ms == NULL)
+ return (-1);
+ IP_MASQ_DEBUG(1, "Created new icmp entry\n");
+ }
+ /* Rewrite source address */
+
+ /*
+ * If sysctl !=0 and no pkt has been received yet
+ * in this tunnel and routing iface address has changed...
+ * "You are welcome, diald".
+ */
+ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && maddr != ms->maddr) {
+
+ if (sysctl_ip_dynaddr > 1) {
+ IP_MASQ_INFO( "ip_fw_masq_icmp(): change masq.addr %d.%d.%d.%d to %d.%d.%d.%d",
+ NIPQUAD(ms->maddr), NIPQUAD(maddr));
+ }
+
+ write_lock(&__ip_masq_lock);
+
+ ip_masq_unhash(ms);
+ ms->maddr = maddr;
+ ip_masq_hash(ms);
+
+ write_unlock(&__ip_masq_lock);
+ }
+
+ iph->saddr = ms->maddr;
+ ip_send_check(iph);
+ /* Rewrite port (id) */
+ (icmph->un).echo.id = ms->mport;
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *)icmph, len);
+
+ IP_MASQ_DEBUG(2, "icmp request rwt %lX->%lX id %d type %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type);
+
+ masq_set_state(ms, 1, iph, icmph);
+ ip_masq_put(ms);
+
+ return 1;
+ }
+#endif
+
+ /*
+ * Work through seeing if this is for us.
+ * These checks are supposed to be in an order that
+ * means easy things are checked first to speed up
+ * processing.... however this means that some
+ * packets will manage to get a long way down this
+ * stack and then be rejected, but thats life
+ */
+ if ((icmph->type != ICMP_DEST_UNREACH) &&
+ (icmph->type != ICMP_SOURCE_QUENCH) &&
+ (icmph->type != ICMP_TIME_EXCEEDED))
+ return 0;
+
+ /* Now find the contained IP header */
+ ciph = (struct iphdr *) (icmph + 1);
+
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if (ciph->protocol == IPPROTO_ICMP) {
+ /*
+ * This section handles ICMP errors for ICMP packets
+ */
+ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph +
+ (ciph->ihl<<2));
+
+
+ IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_out_get(ciph->protocol,
+ ciph->daddr,
+ icmp_id(cicmph),
+ ciph->saddr,
+ icmp_hv_rep(cicmph));
+ read_unlock(&__ip_masq_lock);
+
+ if (ms == NULL)
+ return 0;
+
+ /* Now we do real damage to this packet...! */
+ /* First change the source IP address, and recalc checksum */
+ iph->saddr = ms->maddr;
+ ip_send_check(iph);
+
+ /* Now change the *dest* address in the contained IP */
+ ciph->daddr = ms->maddr;
+ __ip_masq_put(ms);
+
+ ip_send_check(ciph);
+
+ /* Change the ID to the masqed one! */
+ (cicmph->un).echo.id = ms->mport;
+
+ /* And finally the ICMP checksum */
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+ IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ return 1;
+ }
+#endif /* CONFIG_IP_MASQUERADE_ICMP */
+
+ /* We are only interested ICMPs generated from TCP or UDP packets */
+ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
+ return 0;
+
+ /*
+ * Find the ports involved - this packet was
+ * incoming so the ports are right way round
+ * (but reversed relative to outer IP header!)
+ */
+ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+#if 0
+ if (ntohs(pptr[1]) < PORT_MASQ_BEGIN ||
+ ntohs(pptr[1]) > PORT_MASQ_END)
+ return 0;
+#endif
+
+ /* Ensure the checksum is correct */
+ if (ip_compute_csum((unsigned char *) icmph, len))
+ {
+ /* Failed checksum! */
+ IP_MASQ_DEBUG(0, "forward ICMP: failed checksum from %d.%d.%d.%d!\n",
+ NIPQUAD(iph->saddr));
+ return(-1);
+ }
+
+
+ IP_MASQ_DEBUG(2, "Handling forward ICMP for %08lX:%04X -> %08lX:%04X\n",
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[1]));
+
+
+#if 0
+ /* This is pretty much what __ip_masq_in_get_iph() does */
+ ms = __ip_masq_in_get(ciph->protocol, ciph->saddr, pptr[0], ciph->daddr, pptr[1]);
+#endif
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_out_get(ciph->protocol,
+ ciph->daddr,
+ pptr[1],
+ ciph->saddr,
+ pptr[0]);
+ read_unlock(&__ip_masq_lock);
+
+ if (ms == NULL)
+ return 0;
+
+ /* Now we do real damage to this packet...! */
+ /* First change the source IP address, and recalc checksum */
+ iph->saddr = ms->maddr;
+ ip_send_check(iph);
+
+ /* Now change the *dest* address in the contained IP */
+ ciph->daddr = ms->maddr;
+ ip_send_check(ciph);
+
+ /* the TCP/UDP dest port - cannot redo check */
+ pptr[1] = ms->mport;
+ __ip_masq_put(ms);
+
+ /* And finally the ICMP checksum */
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+ IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08lX:%04X -> %08lX:%04X\n",
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[1]));
+
+
+ return 1;
+}
+
+
+/*
+ * Own skb_cow() beast, tweaked for rewriting commonly
+ * used pointers in masq code
+ */
+static struct sk_buff * masq_skb_cow(struct sk_buff **skb_p,
+ struct iphdr **iph_p, unsigned char **t_p) {
+ struct sk_buff *skb=(*skb_p);
+ if (skb_cloned(skb)) {
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (skb) {
+ /*
+ * skb changed, update other pointers
+ */
+ struct iphdr *iph = skb->nh.iph;
+ kfree_skb(*skb_p);
+ *skb_p = skb;
+ *iph_p = iph;
+ *t_p = (char*) iph + iph->ihl * 4;
+ }
+ }
+ return skb;
+}
+
+/*
+ * Handle ICMP messages in reverse (demasquerade) direction.
+ * Find any that might be relevant, check against existing connections,
+ * forward to masqueraded host if relevant.
+ * Currently handles error types - unreachable, quench, ttl exceeded
+ */
+
+int ip_fw_demasq_icmp(struct sk_buff **skb_p)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+ struct iphdr *ciph; /* The ip header contained within the ICMP */
+ __u16 *pptr; /* port numbers from TCP/UDP contained header */
+ struct ip_masq *ms;
+ unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4);
+
+
+ IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %lX -> %lX\n",
+ icmph->type, ntohs(icmp_id(icmph)),
+ ntohl(iph->saddr), ntohl(iph->daddr));
+
+
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if ((icmph->type == ICMP_ECHOREPLY) ||
+ (icmph->type == ICMP_TIMESTAMPREPLY) ||
+ (icmph->type == ICMP_INFO_REPLY) ||
+ (icmph->type == ICMP_ADDRESSREPLY)) {
+
+ IP_MASQ_DEBUG(2, "icmp reply rcv %lX->%lX id %d type %d, req %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type,
+ icmp_type_request(icmph->type));
+
+ ms = ip_masq_in_get(iph->protocol,
+ iph->saddr,
+ icmp_hv_rep(icmph),
+ iph->daddr,
+ icmp_id(icmph));
+ if (ms == NULL)
+ return 0;
+
+ /*
+ * got reply, so clear flag
+ */
+ ms->flags &= ~IP_MASQ_F_NO_REPLY;
+
+ if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) {
+ ip_masq_put(ms);
+ return -1;
+ }
+
+ /* Reset source address */
+ iph->daddr = ms->saddr;
+ /* Redo IP header checksum */
+ ip_send_check(iph);
+ /* Set ID to fake port number */
+ (icmph->un).echo.id = ms->sport;
+ /* Reset ICMP checksum and set expiry */
+ icmph->checksum=0;
+ icmph->checksum=ip_compute_csum((unsigned char *)icmph,len);
+
+
+
+ IP_MASQ_DEBUG(2, "icmp reply rwt %lX->%lX id %d type %d\n",
+ ntohl(iph->saddr),
+ ntohl(iph->daddr),
+ ntohs(icmp_id(icmph)),
+ icmph->type);
+
+ masq_set_state(ms, 0, iph, icmph);
+ ip_masq_put(ms);
+
+ return 1;
+ } else {
+#endif
+ if ((icmph->type != ICMP_DEST_UNREACH) &&
+ (icmph->type != ICMP_SOURCE_QUENCH) &&
+ (icmph->type != ICMP_TIME_EXCEEDED))
+ return 0;
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ }
+#endif
+ /*
+ * If we get here we have an ICMP error of one of the above 3 types
+ * Now find the contained IP header
+ */
+
+ ciph = (struct iphdr *) (icmph + 1);
+
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+ if (ciph->protocol == IPPROTO_ICMP) {
+ /*
+ * This section handles ICMP errors for ICMP packets
+ *
+ * First get a new ICMP header structure out of the IP packet
+ */
+ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph +
+ (ciph->ihl<<2));
+
+
+ IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_in_get(ciph->protocol,
+ ciph->daddr,
+ icmp_hv_req(cicmph),
+ ciph->saddr,
+ icmp_id(cicmph));
+ read_unlock(&__ip_masq_lock);
+
+ if (ms == NULL)
+ return 0;
+
+ if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) {
+ __ip_masq_put(ms);
+ return -1;
+ }
+ ciph = (struct iphdr *) (icmph + 1);
+ cicmph = (struct icmphdr *)((char *)ciph +
+ (ciph->ihl<<2));
+ /* Now we do real damage to this packet...! */
+ /* First change the dest IP address, and recalc checksum */
+ iph->daddr = ms->saddr;
+ ip_send_check(iph);
+
+ /* Now change the *source* address in the contained IP */
+ ciph->saddr = ms->saddr;
+ ip_send_check(ciph);
+
+ /* Change the ID to the original one! */
+ (cicmph->un).echo.id = ms->sport;
+ __ip_masq_put(ms);
+
+ /* And finally the ICMP checksum */
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+ IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %lX->%lX id %d type %d\n",
+ ntohl(ciph->saddr),
+ ntohl(ciph->daddr),
+ ntohs(icmp_id(cicmph)),
+ cicmph->type);
+
+ return 1;
+ }
+#endif /* CONFIG_IP_MASQUERADE_ICMP */
+
+ /* We are only interested ICMPs generated from TCP or UDP packets */
+ if ((ciph->protocol != IPPROTO_UDP) &&
+ (ciph->protocol != IPPROTO_TCP))
+ return 0;
+
+ /*
+ * Find the ports involved - remember this packet was
+ * *outgoing* so the ports are reversed (and addresses)
+ */
+ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+ if (ntohs(pptr[0]) < PORT_MASQ_BEGIN ||
+ ntohs(pptr[0]) > PORT_MASQ_END)
+ return 0;
+
+ /* Ensure the checksum is correct */
+ if (ip_compute_csum((unsigned char *) icmph, len))
+ {
+ /* Failed checksum! */
+ IP_MASQ_ERR( "reverse ICMP: failed checksum from %d.%d.%d.%d!\n",
+ NIPQUAD(iph->saddr));
+ return(-1);
+ }
+
+
+ IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08lX:%04X -> %08lX:%04X\n",
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[1]));
+
+
+ /* This is pretty much what __ip_masq_in_get_iph() does, except params are wrong way round */
+ read_lock(&__ip_masq_lock);
+ ms = __ip_masq_in_get(ciph->protocol,
+ ciph->daddr,
+ pptr[1],
+ ciph->saddr,
+ pptr[0]);
+ read_unlock(&__ip_masq_lock);
+
+ if (ms == NULL)
+ return 0;
+
+ if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) {
+ __ip_masq_put(ms);
+ return -1;
+ }
+ ciph = (struct iphdr *) (icmph + 1);
+ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+
+ /* Now we do real damage to this packet...! */
+ /* First change the dest IP address, and recalc checksum */
+ iph->daddr = ms->saddr;
+ ip_send_check(iph);
+
+ /* Now change the *source* address in the contained IP */
+ ciph->saddr = ms->saddr;
+ ip_send_check(ciph);
+
+ /* the TCP/UDP source port - cannot redo check */
+ pptr[0] = ms->sport;
+ __ip_masq_put(ms);
+
+ /* And finally the ICMP checksum */
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
+
+
+ IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08lX:%04X -> %08lX:%04X\n",
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[1]));
+
+
+ return 1;
+}
+
+ /*
+ * Check if it's an masqueraded port, look it up,
+ * and send it on its way...
+ *
+ * Better not have many hosts using the designated portrange
+ * as 'normal' ports, or you'll be spending many time in
+ * this function.
+ */
+
+int ip_fw_demasquerade(struct sk_buff **skb_p)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ union ip_masq_tphdr h;
+ struct ip_masq *ms;
+ unsigned short size;
+ int doff = 0;
+ int csum = 0;
+ int csum_ok = 0;
+ __u32 maddr;
+
+ /*
+ * Big tappo: only PACKET_HOST (nor loopback neither mcasts)
+ * ... don't know why 1st test DOES NOT include 2nd (?)
+ */
+
+ if (skb->pkt_type != PACKET_HOST || skb->dev == &loopback_dev) {
+ IP_MASQ_DEBUG(2, "ip_fw_demasquerade(): packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
+ skb->pkt_type,
+ iph->protocol,
+ NIPQUAD(iph->daddr));
+ return 0;
+ }
+
+ h.raw = (char*) iph + iph->ihl * 4;
+
+ /*
+ * IP payload size
+ */
+ size = ntohs(iph->tot_len) - (iph->ihl * 4);
+
+ doff = proto_doff(iph->protocol, h.raw, size);
+
+ switch (doff) {
+ case 0:
+ /*
+ * Input path: other IP protos Ok, will
+ * reach local sockets path.
+ */
+ return 0;
+ case -1:
+ IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n");
+ return -1;
+ }
+
+ maddr = iph->daddr;
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ return(ip_fw_demasq_icmp(skb_p));
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ /*
+ * Make sure packet is in the masq range
+ * ... or some mod-ule relaxes input range
+ * ... or there is still some `special' mport opened
+ */
+ if ((ntohs(h.portp[1]) < PORT_MASQ_BEGIN
+ || ntohs(h.portp[1]) > PORT_MASQ_END)
+#ifdef CONFIG_IP_MASQUERADE_MOD
+ && (ip_masq_mod_in_rule(skb, iph) != 1)
+#endif
+ && atomic_read(&mport_count) == 0 )
+ return 0;
+
+ /* Check that the checksum is OK */
+ if ((iph->protocol == IPPROTO_UDP) && (h.uh->check == 0))
+ /* No UDP checksum */
+ break;
+#ifdef CONFIG_IP_MASQ_DEBUG
+ if (ip_masq_get_debug_level() > 3) {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+#endif
+
+ switch (skb->ip_summed)
+ {
+ case CHECKSUM_NONE:
+ csum = csum_partial(h.raw + doff, size - doff, 0);
+ csum_ok++;
+ skb->csum = csum_partial(h.raw , doff, csum);
+
+ case CHECKSUM_HW:
+ if (csum_tcpudp_magic(iph->saddr, iph->daddr,
+ size, iph->protocol, skb->csum))
+ {
+ IP_MASQ_DEBUG(0, "Incoming failed %s checksum from %d.%d.%d.%d (size=%d)!\n",
+ masq_proto_name(iph->protocol),
+ NIPQUAD(iph->saddr),
+ size);
+ return -1;
+ }
+ default:
+ /* CHECKSUM_UNNECESSARY */
+ }
+ break;
+ default:
+ return 0;
+ }
+
+
+
+ IP_MASQ_DEBUG(2, "Incoming %s %08lX:%04X -> %08lX:%04X\n",
+ masq_proto_name(iph->protocol),
+ ntohl(iph->saddr), ntohs(h.portp[0]),
+ ntohl(iph->daddr), ntohs(h.portp[1]));
+
+ /*
+ * reroute to original host:port if found...
+ */
+
+ ms = ip_masq_in_get_iph(iph);
+
+ /*
+ * Give additional modules a chance to create an entry
+ */
+#ifdef CONFIG_IP_MASQUERADE_MOD
+ if (!ms)
+ ms = ip_masq_mod_in_create(skb, iph, maddr);
+
+ /*
+ * Call module's input update hook
+ */
+ ip_masq_mod_in_update(skb, iph, ms);
+#endif
+
+
+ if (ms != NULL)
+ {
+
+ /*
+ * got reply, so clear flag
+ */
+ ms->flags &= ~IP_MASQ_F_NO_REPLY;
+
+ /*
+ * Set daddr,dport if not defined yet
+ * and tunnel is not setup as "dest loose"
+ */
+
+ if (ms->flags & IP_MASQ_F_DLOOSE) {
+ /*
+ * update dest loose values
+ */
+ ms->dport = h.portp[0];
+ ms->daddr = iph->saddr;
+ } else {
+ if ( ms->flags & IP_MASQ_F_NO_DPORT ) { /* && ms->protocol == IPPROTO_TCP ) { */
+
+ write_lock(&__ip_masq_lock);
+
+ ip_masq_unhash(ms);
+ ms->flags &= ~IP_MASQ_F_NO_DPORT;
+ ms->dport = h.portp[0];
+ ip_masq_hash(ms); /* hash on new dport */
+
+ write_unlock(&__ip_masq_lock);
+
+ IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled dport=%d\n",
+ ntohs(ms->dport));
+
+ }
+ if (ms->flags & IP_MASQ_F_NO_DADDR ) { /* && ms->protocol == IPPROTO_TCP) { */
+
+ write_lock(&__ip_masq_lock);
+
+ ip_masq_unhash(ms);
+ ms->flags &= ~IP_MASQ_F_NO_DADDR;
+ ms->daddr = iph->saddr;
+ ip_masq_hash(ms); /* hash on new daddr */
+
+ write_unlock(&__ip_masq_lock);
+
+ IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%lX\n",
+ ntohl(ms->daddr));
+
+ }
+ }
+ if ((skb=masq_skb_cow(skb_p, &iph, &h.raw)) == NULL) {
+ ip_masq_put(ms);
+ return -1;
+ }
+ iph->daddr = ms->saddr;
+ h.portp[1] = ms->sport;
+
+ /*
+ * Invalidate csum saving if tunnel has masq helper
+ */
+
+ if (ms->app)
+ csum_ok = 0;
+
+ /*
+ * Attempt ip_masq_app call.
+ * will fix ip_masq and iph ack_seq stuff
+ */
+
+ if (ip_masq_app_pkt_in(ms, skb_p, maddr) != 0)
+ {
+ /*
+ * skb has changed, update pointers.
+ */
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ h.raw = (char*) iph + iph->ihl*4;
+ size = ntohs(iph->tot_len) - (iph->ihl * 4);
+ }
+
+ /*
+ * Yug! adjust UDP/TCP checksums
+ */
+
+ /*
+ * Transport's payload partial csum
+ */
+
+ if (!csum_ok) {
+ csum = csum_partial(h.raw + doff, size - doff, 0);
+ }
+ skb->csum = csum;
+
+ /*
+ * Protocol csum
+ */
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ h.th->check = 0;
+ h.th->check=csum_tcpudp_magic(iph->saddr, iph->daddr,
+ size, iph->protocol,
+ csum_partial(h.raw , doff, csum));
+ break;
+ case IPPROTO_UDP:
+ h.uh->check = 0;
+ h.uh->check=csum_tcpudp_magic(iph->saddr, iph->daddr,
+ size, iph->protocol,
+ csum_partial(h.raw , doff, csum));
+ if (h.uh->check == 0)
+ h.uh->check = 0xFFFF;
+ break;
+ }
+ ip_send_check(iph);
+
+ IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(h.portp[1]));
+
+ masq_set_state (ms, 0, iph, h.portp);
+ ip_masq_put(ms);
+
+ return 1;
+ }
+
+ /* sorry, all this trouble for a no-hit :) */
+ return 0;
+}
+
+
+void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms)
+{
+ if (ms->control) {
+ IP_MASQ_ERR( "request control ADD for already controlled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->saddr),ntohs(ms->sport),
+ NIPQUAD(ms->daddr),ntohs(ms->dport));
+ ip_masq_control_del(ms);
+ }
+ IP_MASQ_DEBUG(1, "ADDing control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->daddr),ntohs(ms->dport),
+ NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport));
+ ms->control = ctl_ms;
+ atomic_inc(&ctl_ms->n_control);
+}
+
+void ip_masq_control_del(struct ip_masq *ms)
+{
+ struct ip_masq *ctl_ms = ms->control;
+ if (!ctl_ms) {
+ IP_MASQ_ERR( "request control DEL for uncontrolled: %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->saddr),ntohs(ms->sport),
+ NIPQUAD(ms->daddr),ntohs(ms->dport));
+ return;
+ }
+ IP_MASQ_DEBUG(1, "DELeting control for: ms.dst=%d.%d.%d.%d:%d ctl_ms.dst=%d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->daddr),ntohs(ms->dport),
+ NIPQUAD(ctl_ms->daddr),ntohs(ctl_ms->dport));
+ ms->control = NULL;
+ if (atomic_read(&ctl_ms->n_control) == 0) {
+ IP_MASQ_ERR( "BUG control DEL with n=0 : %d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
+ NIPQUAD(ms->saddr),ntohs(ms->sport),
+ NIPQUAD(ms->daddr),ntohs(ms->dport));
+ return;
+
+ }
+ atomic_dec(&ctl_ms->n_control);
+}
+
+struct ip_masq * ip_masq_control_get(struct ip_masq *ms)
+{
+ return ms->control;
+}
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * /proc/net entries
+ * From userspace
+ */
+static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
+ int length, int unused)
+{
+ off_t pos=0, begin;
+ struct ip_masq *ms;
+ char temp[129];
+ int idx = 0;
+ int len=0;
+ struct list_head *l,*e;
+
+ if (offset < 128)
+ {
+ sprintf(temp,
+ "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=%d,%d,%d)",
+ atomic_read(ip_masq_free_ports),
+ atomic_read(ip_masq_free_ports+1),
+ atomic_read(ip_masq_free_ports+2));
+ len = sprintf(buffer, "%-127s\n", temp);
+ }
+ pos = 128;
+
+ for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+ {
+ /*
+ * Lock is actually only need in next loop
+ * we are called from uspace: must stop bh.
+ */
+ read_lock_bh(&__ip_masq_lock);
+
+ l = &ip_masq_m_table[idx];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, m_list);
+ pos += 128;
+ if (pos <= offset) {
+ len = 0;
+ continue;
+ }
+
+ /*
+ * We have locked the tables, no need to del/add timers
+ * nor cli() 8)
+ */
+
+ sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu",
+ masq_proto_name(ms->protocol),
+ ntohl(ms->saddr), ntohs(ms->sport),
+ ntohl(ms->daddr), ntohs(ms->dport),
+ ntohs(ms->mport),
+ ms->out_seq.init_seq,
+ ms->out_seq.delta,
+ ms->out_seq.previous_delta,
+ ms->timer.expires-jiffies);
+ len += sprintf(buffer+len, "%-127s\n", temp);
+
+ if(len >= length) {
+
+ read_unlock_bh(&__ip_masq_lock);
+ goto done;
+ }
+ }
+ read_unlock_bh(&__ip_masq_lock);
+
+ }
+done:
+
+
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+ if(len>length)
+ len = length;
+ return len;
+}
+
+#endif
+
+/*
+ * Timeouts handling by ipfwadm/ipchains
+ * From ip_fw.c
+ */
+
+int ip_fw_masq_timeouts(void *m, int len)
+{
+ struct ip_fw_masq *masq;
+ int ret = EINVAL;
+
+ if (len != sizeof(struct ip_fw_masq)) {
+ IP_MASQ_DEBUG(1, "ip_fw_masq_timeouts: length %d, expected %d\n",
+ len, sizeof(struct ip_fw_masq));
+ } else {
+ masq = (struct ip_fw_masq *)m;
+ if (masq->tcp_timeout)
+ masq_timeout_table.timeout[IP_MASQ_S_ESTABLISHED]
+ = masq->tcp_timeout;
+
+ if (masq->tcp_fin_timeout)
+ masq_timeout_table.timeout[IP_MASQ_S_FIN_WAIT]
+ = masq->tcp_fin_timeout;
+
+ if (masq->udp_timeout)
+ masq_timeout_table.timeout[IP_MASQ_S_UDP]
+ = masq->udp_timeout;
+ ret = 0;
+ }
+ return ret;
+}
+/*
+ * Module autoloading stuff
+ */
+
+static int ip_masq_user_check_hook(void) {
+#ifdef CONFIG_KMOD
+ if (ip_masq_user_hook == NULL) {
+ IP_MASQ_DEBUG(1, "About to request \"ip_masq_user\" module\n");
+ request_module("ip_masq_user");
+ }
+#endif /* CONFIG_KMOD */
+ return (ip_masq_user_hook != NULL);
+}
+
+/*
+ * user module hook- info
+ */
+static int ip_masq_user_info(char *buffer, char **start, off_t offset,
+ int len, int *eof, void *data)
+{
+ int ret = -ENOPKG;
+ if (ip_masq_user_check_hook()) {
+ ret = ip_masq_user_hook->info(buffer, start, offset, len, (int) data);
+ }
+ return ret;
+}
+
+/*
+ * user module hook- entry mgmt
+ */
+static int ip_masq_user_ctl(int optname, void *arg, int arglen)
+{
+ int ret = -ENOPKG;
+ if (ip_masq_user_check_hook()) {
+ ret = ip_masq_user_hook->ctl(optname, arg, arglen);
+ }
+ return ret;
+}
+
+/*
+ * Control from ip_sockglue
+ * MAIN ENTRY point from userspace (apart from /proc *info entries)
+ * Returns errno
+ */
+int ip_masq_uctl(int optname, char * optval , int optlen)
+{
+ struct ip_masq_ctl masq_ctl;
+ int ret = -EINVAL;
+
+ if(optlen>sizeof(masq_ctl))
+ return -EINVAL;
+
+ if(copy_from_user(&masq_ctl,optval,optlen))
+ return -EFAULT;
+
+ IP_MASQ_DEBUG(1,"ip_masq_ctl(optname=%d, optlen=%d, target=%d, cmd=%d)\n",
+ optname, optlen, masq_ctl.m_target, masq_ctl.m_cmd);
+
+ switch (masq_ctl.m_target) {
+ case IP_MASQ_TARGET_USER:
+ ret = ip_masq_user_ctl(optname, &masq_ctl, optlen);
+ break;
+#ifdef CONFIG_IP_MASQUERADE_MOD
+ case IP_MASQ_TARGET_MOD:
+ ret = ip_masq_mod_ctl(optname, &masq_ctl, optlen);
+ break;
+#endif
+ }
+
+ /*
+ * If ret>0, copy to user space
+ */
+
+ if (ret > 0 && ret <= sizeof (masq_ctl)) {
+ if (copy_to_user(optval, &masq_ctl, ret) )
+ return -EFAULT;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_net_ip_masq = NULL;
+
+#ifdef MODULE
+static void ip_masq_proc_count(struct inode *inode, int fill)
+{
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+}
+#endif
+
+int ip_masq_proc_register(struct proc_dir_entry *ent)
+{
+ if (!proc_net_ip_masq) return -1;
+ IP_MASQ_DEBUG(1, "registering \"/proc/net/ip_masq/%s\" entry\n",
+ ent->name);
+ return proc_register(proc_net_ip_masq, ent);
+}
+void ip_masq_proc_unregister(struct proc_dir_entry *ent)
+{
+ if (!proc_net_ip_masq) return;
+ IP_MASQ_DEBUG(1, "unregistering \"/proc/net/ip_masq/%s\" entry\n",
+ ent->name);
+ proc_unregister(proc_net_ip_masq, ent->low_ino);
+}
+
+
+__initfunc(static void masq_proc_init(void))
+{
+ IP_MASQ_DEBUG(1,"registering /proc/net/ip_masq\n");
+ if (!proc_net_ip_masq) {
+ struct proc_dir_entry *ent;
+ ent = create_proc_entry("net/ip_masq", S_IFDIR, 0);
+ if (ent) {
+#ifdef MODULE
+ ent->fill_inode = ip_masq_proc_count;
+#endif
+ proc_net_ip_masq = ent;
+ } else {
+ IP_MASQ_ERR("Could not create \"/proc/net/ip_masq\" entry\n");
+ }
+ }
+}
+#endif /* CONFIG_PROC_FS */
+/*
+ * Wrapper over inet_select_addr()
+ */
+u32 ip_masq_select_addr(struct device *dev, u32 dst, int scope)
+{
+ return inet_select_addr(dev, dst, scope);
+}
+
+/*
+ * Initialize ip masquerading
+ */
+__initfunc(int ip_masq_init(void))
+{
+ int idx;
+ for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) {
+ INIT_LIST_HEAD(&ip_masq_s_table[idx]);
+ INIT_LIST_HEAD(&ip_masq_m_table[idx]);
+ INIT_LIST_HEAD(&ip_masq_d_table[idx]);
+ }
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&(struct proc_dir_entry) {
+ PROC_NET_IPMSQHST, 13, "ip_masquerade",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ ip_msqhst_procinfo
+ });
+ masq_proc_init();
+
+ ip_masq_proc_register(&(struct proc_dir_entry) {
+ 0, 3, "tcp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ NULL, /* get_info */
+ NULL, /* fill_inode */
+ NULL, NULL, NULL,
+ (char *) IPPROTO_TCP,
+ ip_masq_user_info
+ });
+ ip_masq_proc_register(&(struct proc_dir_entry) {
+ 0, 3, "udp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ NULL, /* get_info */
+ NULL, /* fill_inode */
+ NULL, NULL, NULL,
+ (char *) IPPROTO_UDP,
+ ip_masq_user_info
+ });
+ ip_masq_proc_register(&(struct proc_dir_entry) {
+ 0, 4, "icmp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ NULL, /* get_info */
+ NULL, /* fill_inode */
+ NULL, NULL, NULL,
+ (char *) IPPROTO_ICMP,
+ ip_masq_user_info
+ });
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
+ ip_autofw_init();
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPPORTFW
+ ip_portfw_init();
+#endif
+#ifdef CONFIG_IP_MASQUERADE_MFW
+ ip_mfw_init();
+#endif
+ ip_masq_app_init();
+
+ return 0;
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_app.c b/pfinet/linux-src/net/ipv4/ip_masq_app.c
new file mode 100644
index 00000000..84e059fa
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_app.c
@@ -0,0 +1,603 @@
+/*
+ * IP_MASQ_APP application masquerading module
+ *
+ *
+ * $Id: ip_masq_app.c,v 1.16 1998/08/29 23:51:14 davem Exp $
+ *
+ * Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ * JJC : Implemented also input pkt hook
+ * Miquel van Smoorenburg : Copy more stuff when resizing skb
+ *
+ *
+ * FIXME:
+ * - ip_masq_skb_replace(): use same skb if space available.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <net/ip_masq.h>
+
+#define IP_MASQ_APP_TAB_SIZE 16 /* must be power of 2 */
+
+#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1))
+#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port )
+#define IP_MASQ_APP_PORT(type) ( type & 0xffff )
+#define IP_MASQ_APP_PROTO(type) ( (type>>16) & 0x00ff )
+
+
+EXPORT_SYMBOL(register_ip_masq_app);
+EXPORT_SYMBOL(unregister_ip_masq_app);
+EXPORT_SYMBOL(ip_masq_skb_replace);
+
+/*
+ * will hold masq app. hashed list heads
+ */
+
+struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE];
+
+/*
+ * ip_masq_app registration routine
+ * port: host byte order.
+ */
+
+int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port)
+{
+ unsigned long flags;
+ unsigned hash;
+ if (!mapp) {
+ IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n");
+ return -EINVAL;
+ }
+ mapp->type = IP_MASQ_APP_TYPE(proto, port);
+ mapp->n_attach = 0;
+ hash = IP_MASQ_APP_HASH(proto, port);
+
+ save_flags(flags);
+ cli();
+ mapp->next = ip_masq_app_base[hash];
+ ip_masq_app_base[hash] = mapp;
+ restore_flags(flags);
+
+ return 0;
+}
+
+/*
+ * ip_masq_app unreg. routine.
+ */
+
+int unregister_ip_masq_app(struct ip_masq_app *mapp)
+{
+ struct ip_masq_app **mapp_p;
+ unsigned hash;
+ unsigned long flags;
+ if (!mapp) {
+ IP_MASQ_ERR("unregister_ip_masq_app(): NULL arg\n");
+ return -EINVAL;
+ }
+ /*
+ * only allow unregistration if it has no attachments
+ */
+ if (mapp->n_attach) {
+ IP_MASQ_ERR("unregister_ip_masq_app(): has %d attachments. failed\n",
+ mapp->n_attach);
+ return -EINVAL;
+ }
+ hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type));
+
+ save_flags(flags);
+ cli();
+ for (mapp_p = &ip_masq_app_base[hash]; *mapp_p ; mapp_p = &(*mapp_p)->next)
+ if (mapp == (*mapp_p)) {
+ *mapp_p = mapp->next;
+ restore_flags(flags);
+ return 0;
+ }
+
+ restore_flags(flags);
+ IP_MASQ_ERR("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
+ masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type));
+ return -EINVAL;
+}
+
+/*
+ * get ip_masq_app object by its proto and port (net byte order).
+ */
+
+struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port)
+{
+ struct ip_masq_app *mapp;
+ unsigned hash;
+ unsigned type;
+
+ port = ntohs(port);
+ type = IP_MASQ_APP_TYPE(proto,port);
+ hash = IP_MASQ_APP_HASH(proto,port);
+ for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) {
+ if (type == mapp->type) return mapp;
+ }
+ return NULL;
+}
+
+/*
+ * ip_masq_app object binding related funcs.
+ */
+
+/*
+ * change ip_masq_app object's number of bindings
+ */
+
+static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta)
+{
+ unsigned long flags;
+ int n_at;
+ if (!mapp) return -1;
+ save_flags(flags);
+ cli();
+ n_at = mapp->n_attach + delta;
+ if (n_at < 0) {
+ restore_flags(flags);
+ IP_MASQ_ERR("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
+ masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
+ IP_MASQ_APP_PORT(mapp->type));
+ return -1;
+ }
+ mapp->n_attach = n_at;
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Bind ip_masq to its ip_masq_app based on proto and dport ALREADY
+ * set in ip_masq struct. Also calls constructor.
+ */
+
+struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
+{
+ struct ip_masq_app * mapp;
+
+ if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
+ return NULL;
+
+ mapp = ip_masq_app_get(ms->protocol, ms->dport);
+
+#if 0000
+/* #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW */
+ if (mapp == NULL)
+ mapp = ip_masq_app_get(ms->protocol, ms->sport);
+/* #endif */
+#endif
+
+ if (mapp != NULL) {
+ /*
+ * don't allow binding if already bound
+ */
+
+ if (ms->app != NULL) {
+ IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n");
+ return ms->app;
+ }
+
+ ms->app = mapp;
+ if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms);
+ ip_masq_app_bind_chg(mapp, +1);
+ }
+ return mapp;
+}
+
+/*
+ * Unbind ms from type object and call ms destructor (does not kfree()).
+ */
+
+int ip_masq_unbind_app(struct ip_masq *ms)
+{
+ struct ip_masq_app * mapp;
+ mapp = ms->app;
+
+ if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
+ return 0;
+
+ if (mapp != NULL) {
+ if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms);
+ ms->app = NULL;
+ ip_masq_app_bind_chg(mapp, -1);
+ }
+ return (mapp != NULL);
+}
+
+/*
+ * Fixes th->seq based on ip_masq_seq info.
+ */
+
+static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
+{
+ __u32 seq;
+
+ seq = ntohl(th->seq);
+
+ /*
+ * Adjust seq with delta-offset for all packets after
+ * the most recent resized pkt seq and with previous_delta offset
+ * for all packets before most recent resized pkt seq.
+ */
+
+ if (ms_seq->delta || ms_seq->previous_delta) {
+ if(after(seq,ms_seq->init_seq) ) {
+ th->seq = htonl(seq + ms_seq->delta);
+ IP_MASQ_DEBUG(1, "masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
+ } else {
+ th->seq = htonl(seq + ms_seq->previous_delta);
+ IP_MASQ_DEBUG(1, "masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
+ }
+ }
+
+
+}
+
+/*
+ * Fixes th->ack_seq based on ip_masq_seq info.
+ */
+
+static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
+{
+ __u32 ack_seq;
+
+ ack_seq=ntohl(th->ack_seq);
+
+ /*
+ * Adjust ack_seq with delta-offset for
+ * the packets AFTER most recent resized pkt has caused a shift
+ * for packets before most recent resized pkt, use previous_delta
+ */
+
+ if (ms_seq->delta || ms_seq->previous_delta) {
+ if(after(ack_seq,ms_seq->init_seq)) {
+ th->ack_seq = htonl(ack_seq-ms_seq->delta);
+ IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
+
+ } else {
+ th->ack_seq = htonl(ack_seq-ms_seq->previous_delta);
+ IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
+ }
+ }
+
+}
+
+/*
+ * Updates ip_masq_seq if pkt has been resized
+ * Assumes already checked proto==IPPROTO_TCP and diff!=0.
+ */
+
+static __inline__ void masq_seq_update(struct ip_masq *ms, struct ip_masq_seq *ms_seq, unsigned mflag, __u32 seq, int diff)
+{
+ /* if (diff == 0) return; */
+
+ if ( !(ms->flags & mflag) || after(seq, ms_seq->init_seq))
+ {
+ ms_seq->previous_delta=ms_seq->delta;
+ ms_seq->delta+=diff;
+ ms_seq->init_seq=seq;
+ ms->flags |= mflag;
+ }
+}
+
+/*
+ * Output pkt hook. Will call bound ip_masq_app specific function
+ * called by ip_fw_masquerade(), assumes previously checked ms!=NULL
+ * returns (new - old) skb->len diff.
+ */
+
+int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct ip_masq_app * mapp;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ int diff;
+ __u32 seq;
+
+ /*
+ * check if application masquerading is bound to
+ * this ip_masq.
+ * assumes that once an ip_masq is bound,
+ * it will not be unbound during its life.
+ */
+
+ if ( (mapp = ms->app) == NULL)
+ return 0;
+
+ iph = (*skb_p)->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+
+ /*
+ * Remember seq number in case this pkt gets resized
+ */
+
+ seq = ntohl(th->seq);
+
+ /*
+ * Fix seq stuff if flagged as so.
+ */
+
+ if (ms->protocol == IPPROTO_TCP) {
+ if (ms->flags & IP_MASQ_F_OUT_SEQ)
+ masq_fix_seq(&ms->out_seq, th);
+ if (ms->flags & IP_MASQ_F_IN_SEQ)
+ masq_fix_ack_seq(&ms->in_seq, th);
+ }
+
+ /*
+ * Call private output hook function
+ */
+
+ if ( mapp->pkt_out == NULL )
+ return 0;
+
+ diff = mapp->pkt_out(mapp, ms, skb_p, maddr);
+
+ /*
+ * Update ip_masq seq stuff if len has changed.
+ */
+
+ if (diff != 0 && ms->protocol == IPPROTO_TCP)
+ masq_seq_update(ms, &ms->out_seq, IP_MASQ_F_OUT_SEQ, seq, diff);
+
+ return diff;
+}
+
+/*
+ * Input pkt hook. Will call bound ip_masq_app specific function
+ * called by ip_fw_demasquerade(), assumes previously checked ms!=NULL.
+ * returns (new - old) skb->len diff.
+ */
+
+int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct ip_masq_app * mapp;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ int diff;
+ __u32 seq;
+
+ /*
+ * check if application masquerading is bound to
+ * this ip_masq.
+ * assumes that once an ip_masq is bound,
+ * it will not be unbound during its life.
+ */
+
+ if ( (mapp = ms->app) == NULL)
+ return 0;
+
+ iph = (*skb_p)->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+
+ /*
+ * Remember seq number in case this pkt gets resized
+ */
+
+ seq = ntohl(th->seq);
+
+ /*
+ * Fix seq stuff if flagged as so.
+ */
+
+ if (ms->protocol == IPPROTO_TCP) {
+ if (ms->flags & IP_MASQ_F_IN_SEQ)
+ masq_fix_seq(&ms->in_seq, th);
+ if (ms->flags & IP_MASQ_F_OUT_SEQ)
+ masq_fix_ack_seq(&ms->out_seq, th);
+ }
+
+ /*
+ * Call private input hook function
+ */
+
+ if ( mapp->pkt_in == NULL )
+ return 0;
+
+ diff = mapp->pkt_in(mapp, ms, skb_p, maddr);
+
+ /*
+ * Update ip_masq seq stuff if len has changed.
+ */
+
+ if (diff != 0 && ms->protocol == IPPROTO_TCP)
+ masq_seq_update(ms, &ms->in_seq, IP_MASQ_F_IN_SEQ, seq, diff);
+
+ return diff;
+}
+
+/*
+ * /proc/ip_masq_app entry function
+ */
+
+int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ off_t pos=0, begin=0;
+ int len=0;
+ struct ip_masq_app * mapp;
+ unsigned idx;
+
+ if (offset < 40)
+ len=sprintf(buffer,"%-39s\n", "prot port n_attach name");
+ pos = 40;
+
+ for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
+ for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
+ /*
+ * If you change the length of this sprintf, then all
+ * the length calculations need fixing too!
+ * Line length = 40 (3 + 2 + 7 + 1 + 7 + 1 + 2 + 17)
+ */
+ pos += 40;
+ if (pos < offset)
+ continue;
+
+ len += sprintf(buffer+len, "%-3s %-7u %-7d %-17s\n",
+ masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
+ IP_MASQ_APP_PORT(mapp->type), mapp->n_attach,
+ mapp->name);
+
+ if(len >= length)
+ goto done;
+ }
+done:
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+ if (len > length)
+ len = length;
+ return len;
+}
+
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_ip_masq_app = {
+ PROC_NET_IP_MASQ_APP, 3, "app",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ ip_masq_app_getinfo
+};
+#endif
+
+/*
+ * Initialization routine
+ */
+
+__initfunc(int ip_masq_app_init(void))
+{
+#ifdef CONFIG_PROC_FS
+ ip_masq_proc_register(&proc_net_ip_masq_app);
+#endif
+ return 0;
+}
+
+/*
+ * Replace a segment (of skb->data) with a new one.
+ * FIXME: Should re-use same skb if space available, this could
+ * be done if n_len < o_len, unless some extra space
+ * were already allocated at driver level :P .
+ */
+
+static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
+{
+ int maxsize, diff, o_offset;
+ struct sk_buff *n_skb;
+ int offset;
+
+ maxsize = skb->truesize;
+
+ diff = n_len - o_len;
+ o_offset = o_buf - (char*) skb->data;
+
+ if (maxsize <= n_len) {
+ if (diff != 0) {
+ memcpy(skb->data + o_offset + n_len,o_buf + o_len,
+ skb->len - (o_offset + o_len));
+ }
+
+ memcpy(skb->data + o_offset, n_buf, n_len);
+
+ n_skb = skb;
+ skb->len = n_len;
+ skb->end = skb->head+n_len;
+ } else {
+ /*
+ * Sizes differ, make a copy.
+ *
+ * FIXME: move this to core/sbuff.c:skb_grow()
+ */
+
+ n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
+ if (n_skb == NULL) {
+ IP_MASQ_ERR("skb_replace(): no room left (from %p)\n",
+ __builtin_return_address(0));
+ return skb;
+
+ }
+ skb_reserve(n_skb, MAX_HEADER);
+ skb_put(n_skb, skb->len + diff);
+
+ /*
+ * Copy as much data from the old skb as possible. Even
+ * though we're only forwarding packets, we need stuff
+ * like skb->protocol (PPP driver wants it).
+ */
+ offset = n_skb->data - skb->data;
+ n_skb->nh.raw = skb->nh.raw + offset;
+ n_skb->h.raw = skb->h.raw + offset;
+ n_skb->dev = skb->dev;
+ n_skb->mac.raw = skb->mac.raw + offset;
+ n_skb->pkt_type = skb->pkt_type;
+ n_skb->protocol = skb->protocol;
+ n_skb->ip_summed = skb->ip_summed;
+ n_skb->dst = dst_clone(skb->dst);
+
+ /*
+ * Copy pkt in new buffer
+ */
+
+ memcpy(n_skb->data, skb->data, o_offset);
+ memcpy(n_skb->data + o_offset, n_buf, n_len);
+ memcpy(n_skb->data + o_offset + n_len, o_buf + o_len,
+ skb->len - (o_offset + o_len) );
+
+ /*
+ * Problem, how to replace the new skb with old one,
+ * preferably inplace
+ */
+
+ kfree_skb(skb);
+ }
+ return n_skb;
+}
+
+/*
+ * calls skb_replace() and update ip header if new skb was allocated
+ */
+
+struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
+{
+ int diff;
+ struct sk_buff *n_skb;
+ unsigned skb_len;
+
+ diff = n_len - o_len;
+ n_skb = skb_replace(skb, pri, o_buf, o_len, n_buf, n_len);
+ skb_len = skb->len;
+
+ if (diff)
+ {
+ struct iphdr *iph;
+ IP_MASQ_DEBUG(1, "masq_skb_replace(): pkt resized for %d bytes (len=%d)\n", diff, skb->len);
+ /*
+ * update ip header
+ */
+ iph = n_skb->nh.iph;
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ iph->tot_len = htons(skb_len + diff);
+ }
+ return n_skb;
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_autofw.c b/pfinet/linux-src/net/ipv4/ip_masq_autofw.c
new file mode 100644
index 00000000..30301441
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_autofw.c
@@ -0,0 +1,448 @@
+/*
+ * IP_MASQ_AUTOFW auto forwarding module
+ *
+ *
+ * $Id: ip_masq_autofw.c,v 1.3.2.1 1999/08/13 18:26:20 davem Exp $
+ *
+ * Author: Richard Lynch
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Fixes:
+ * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c
+ * Juan Jose Ciarlante : modularized
+ * Juan Jose Ciarlante : use GFP_KERNEL when creating entries
+ * Juan Jose Ciarlante : call del_timer() when freeing entries (!)
+ * FIXME:
+ * - implement refcnt
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/if.h>
+#include <linux/init.h>
+#include <linux/ip_fw.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/ip_masq.h>
+
+#define IP_AUTOFW_EXPIRE 15*HZ
+
+/* WARNING: bitwise equal to ip_autofw_user in linux/ip_masq.h */
+struct ip_autofw {
+ struct ip_autofw * next;
+ __u16 type;
+ __u16 low;
+ __u16 hidden;
+ __u16 high;
+ __u16 visible;
+ __u16 protocol;
+ __u32 lastcontact;
+ __u32 where;
+ __u16 ctlproto;
+ __u16 ctlport;
+ __u16 flags;
+ struct timer_list timer;
+};
+
+/*
+ * Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+/*
+ * Auto-forwarding table
+ */
+
+static struct ip_autofw * ip_autofw_hosts = NULL;
+static struct ip_masq_mod * mmod_self = NULL;
+
+/*
+ * Check if a masq entry should be created for a packet
+ */
+
+static __inline__ struct ip_autofw * ip_autofw_check_range (__u32 where, __u16 port, __u16 protocol, int reqact)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af) {
+ if (af->type==IP_FWD_RANGE &&
+ port>=af->low &&
+ port<=af->high &&
+ protocol==af->protocol &&
+
+ /*
+ * It's ok to create masq entries after
+ * the timeout if we're in insecure mode
+ */
+ (af->flags & IP_AUTOFW_ACTIVE || !reqact || !(af->flags & IP_AUTOFW_SECURE)) &&
+ (!(af->flags & IP_AUTOFW_SECURE) || af->lastcontact==where || !reqact))
+ return(af);
+ af=af->next;
+ }
+ return(NULL);
+}
+
+static __inline__ struct ip_autofw * ip_autofw_check_port (__u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af)
+ {
+ if (af->type==IP_FWD_PORT && port==af->visible && protocol==af->protocol)
+ return(af);
+ af=af->next;
+ }
+ return(NULL);
+}
+
+static __inline__ struct ip_autofw * ip_autofw_check_direct (__u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af)
+ {
+ if (af->type==IP_FWD_DIRECT && af->low<=port && af->high>=port)
+ return(af);
+ af=af->next;
+ }
+ return(NULL);
+}
+
+static __inline__ void ip_autofw_update_out (__u32 who, __u32 where, __u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_hosts;
+ port=ntohs(port);
+ while (af)
+ {
+ if (af->type==IP_FWD_RANGE && af->ctlport==port && af->ctlproto==protocol)
+ {
+ if (af->flags & IP_AUTOFW_USETIME)
+ {
+ mod_timer(&af->timer,
+ jiffies+IP_AUTOFW_EXPIRE);
+ }
+ af->flags|=IP_AUTOFW_ACTIVE;
+ af->lastcontact=where;
+ af->where=who;
+ }
+ af=af->next;
+ }
+}
+
+#if 0
+static __inline__ void ip_autofw_update_in (__u32 where, __u16 port, __u16 protocol)
+{
+ struct ip_autofw *af;
+ af=ip_autofw_check_range(where, port,protocol);
+ if (af)
+ {
+ mod_timer(&af->timer, jiffies+IP_AUTOFW_EXPIRE);
+ }
+}
+#endif
+
+
+static __inline__ void ip_autofw_expire(unsigned long data)
+{
+ struct ip_autofw * af;
+ af=(struct ip_autofw *) data;
+ af->flags &= ~IP_AUTOFW_ACTIVE;
+ af->timer.expires=0;
+ af->lastcontact=0;
+ if (af->flags & IP_AUTOFW_SECURE)
+ af->where=0;
+}
+
+
+
+static __inline__ int ip_autofw_add(struct ip_autofw_user * af)
+{
+ struct ip_autofw * newaf;
+ newaf = kmalloc( sizeof(struct ip_autofw), GFP_KERNEL );
+ if ( newaf == NULL )
+ {
+ printk("ip_autofw_add: malloc said no\n");
+ return( ENOMEM );
+ }
+
+ init_timer(&newaf->timer);
+ MOD_INC_USE_COUNT;
+
+ memcpy(newaf, af, sizeof(struct ip_autofw_user));
+ newaf->timer.data = (unsigned long) newaf;
+ newaf->timer.function = ip_autofw_expire;
+ newaf->timer.expires = 0;
+ newaf->lastcontact=0;
+ newaf->next=ip_autofw_hosts;
+ ip_autofw_hosts=newaf;
+ ip_masq_mod_inc_nent(mmod_self);
+ return(0);
+}
+
+static __inline__ int ip_autofw_del(struct ip_autofw_user * af)
+{
+ struct ip_autofw ** af_p, *curr;
+
+ for (af_p=&ip_autofw_hosts, curr=*af_p; (curr=*af_p); af_p = &(*af_p)->next) {
+ if (af->type == curr->type &&
+ af->low == curr->low &&
+ af->high == curr->high &&
+ af->hidden == curr->hidden &&
+ af->visible == curr->visible &&
+ af->protocol == curr->protocol &&
+ af->where == curr->where &&
+ af->ctlproto == curr->ctlproto &&
+ af->ctlport == curr->ctlport)
+ {
+ ip_masq_mod_dec_nent(mmod_self);
+ *af_p = curr->next;
+ if (af->flags&IP_AUTOFW_ACTIVE)
+ del_timer(&curr->timer);
+ kfree_s(curr,sizeof(struct ip_autofw));
+ MOD_DEC_USE_COUNT;
+ return 0;
+ }
+ curr=curr->next;
+ }
+ return EINVAL;
+}
+
+static __inline__ int ip_autofw_flush(void)
+{
+ struct ip_autofw * af;
+
+ while (ip_autofw_hosts)
+ {
+ af=ip_autofw_hosts;
+ ip_masq_mod_dec_nent(mmod_self);
+ ip_autofw_hosts=ip_autofw_hosts->next;
+ if (af->flags&IP_AUTOFW_ACTIVE)
+ del_timer(&af->timer);
+ kfree_s(af,sizeof(struct ip_autofw));
+ MOD_DEC_USE_COUNT;
+ }
+ return(0);
+}
+
+/*
+ * Methods for registered object
+ */
+
+static int autofw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+ struct ip_autofw_user *af = &mctl->u.autofw_user;
+
+ switch (mctl->m_cmd) {
+ case IP_MASQ_CMD_ADD:
+ case IP_MASQ_CMD_INSERT:
+ if (optlen<sizeof(*af))
+ return EINVAL;
+ return ip_autofw_add(af);
+ case IP_MASQ_CMD_DEL:
+ if (optlen<sizeof(*af))
+ return EINVAL;
+ return ip_autofw_del(af);
+ case IP_MASQ_CMD_FLUSH:
+ return ip_autofw_flush();
+
+ }
+ return EINVAL;
+}
+
+
+static int autofw_out_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ /*
+ * Update any ipautofw entries ...
+ */
+
+ ip_autofw_update_out(iph->saddr, iph->daddr, portp[1], iph->protocol);
+ return IP_MASQ_MOD_NOP;
+}
+
+static struct ip_masq * autofw_out_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ /*
+ * If the source port is supposed to match the masq port, then
+ * make it so
+ */
+
+ if (ip_autofw_check_direct(portp[1],iph->protocol)) {
+ return ip_masq_new(iph->protocol,
+ maddr, portp[0],
+ iph->saddr, portp[0],
+ iph->daddr, portp[1],
+ 0);
+ }
+ return NULL;
+}
+
+#if 0
+static int autofw_in_update(const struct sk_buff *skb, const struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ ip_autofw_update_in(iph->saddr, portp[1], iph->protocol);
+ return IP_MASQ_MOD_NOP;
+}
+#endif
+
+static int autofw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ return (ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0)
+ || ip_autofw_check_direct(portp[1], iph->protocol)
+ || ip_autofw_check_port(portp[1], iph->protocol));
+}
+
+static struct ip_masq * autofw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ struct ip_autofw *af;
+
+ if ((af=ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0))) {
+ IP_MASQ_DEBUG(1-debug, "autofw_check_range HIT\n");
+ return ip_masq_new(iph->protocol,
+ maddr, portp[1],
+ af->where, portp[1],
+ iph->saddr, portp[0],
+ 0);
+ }
+ if ((af=ip_autofw_check_port(portp[1], iph->protocol)) ) {
+ IP_MASQ_DEBUG(1-debug, "autofw_check_port HIT\n");
+ return ip_masq_new(iph->protocol,
+ maddr, htons(af->visible),
+ af->where, htons(af->hidden),
+ iph->saddr, portp[0],
+ 0);
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_PROC_FS
+static int autofw_procinfo(char *buffer, char **start, off_t offset,
+ int length, int unused)
+{
+ off_t pos=0, begin=0;
+ struct ip_autofw * af;
+ int len=0;
+
+ len=sprintf(buffer,"Type Prot Low High Vis Hid Where Last CPto CPrt Timer Flags\n");
+
+ for(af = ip_autofw_hosts; af ; af = af->next)
+ {
+ len+=sprintf(buffer+len,"%4X %4X %04X-%04X/%04X %04X %08lX %08lX %04X %04X %6lu %4X\n",
+ af->type,
+ af->protocol,
+ af->low,
+ af->high,
+ af->visible,
+ af->hidden,
+ ntohl(af->where),
+ ntohl(af->lastcontact),
+ af->ctlproto,
+ af->ctlport,
+ (af->timer.expires<jiffies ? 0 : af->timer.expires-jiffies),
+ af->flags);
+
+ pos=begin+len;
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ break;
+ }
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ return len;
+}
+
+static struct proc_dir_entry autofw_proc_entry = {
+ 0, 0, NULL,
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ autofw_procinfo
+};
+
+#define proc_ent &autofw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+
+#define autofw_in_update NULL
+#define autofw_out_rule NULL
+#define autofw_mod_init NULL
+#define autofw_mod_done NULL
+
+static struct ip_masq_mod autofw_mod = {
+ NULL, /* next */
+ NULL, /* next_reg */
+ "autofw", /* name */
+ ATOMIC_INIT(0), /* nent */
+ ATOMIC_INIT(0), /* refcnt */
+ proc_ent,
+ autofw_ctl,
+ autofw_mod_init,
+ autofw_mod_done,
+ autofw_in_rule,
+ autofw_in_update,
+ autofw_in_create,
+ autofw_out_rule,
+ autofw_out_update,
+ autofw_out_create,
+};
+
+__initfunc(int ip_autofw_init(void))
+{
+ return register_ip_masq_mod ((mmod_self=&autofw_mod));
+}
+
+int ip_autofw_done(void)
+{
+ return unregister_ip_masq_mod(&autofw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_autofw_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_autofw_done() != 0)
+ printk(KERN_INFO "ip_autofw_done(): can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_cuseeme.c b/pfinet/linux-src/net/ipv4/ip_masq_cuseeme.c
new file mode 100644
index 00000000..9b412baf
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_cuseeme.c
@@ -0,0 +1,264 @@
+/*
+ * IP_MASQ_FTP CUSeeMe masquerading module
+ *
+ *
+ * Version: @(#)$Id: ip_masq_cuseeme.c,v 1.4 1998/10/06 04:48:57 davem Exp $
+ *
+ * Author: Richard Lynch
+ *
+ *
+ * Fixes:
+ * Richard Lynch : Updated patch to conform to new module
+ * specifications
+ * Nigel Metheringham : Multiple port support
+ * Michael Owings : Fixed broken init code
+ * Added code to update inbound
+ * packets with correct local addresses.
+ * Fixes audio and "chat" problems
+ * Thanx to the CU-SeeMe Consortium for
+ * technical docs
+ * Steven Clarke : Small changes for 2.1
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/udp.h>
+
+/* #define IP_MASQ_NDEBUG */
+#include <net/ip_masq.h>
+
+#pragma pack(1)
+/* CU-SeeMe Data Header */
+typedef struct {
+ u_short dest_family;
+ u_short dest_port;
+ u_long dest_addr;
+ short family;
+ u_short port;
+ u_long addr;
+ u_long seq;
+ u_short msg;
+ u_short data_type;
+ u_short packet_len;
+} cu_header;
+
+/* Open Continue Header */
+typedef struct {
+ cu_header cu_head;
+ u_short client_count; /* Number of client info structs */
+ u_long seq_no;
+ char user_name[20];
+ char stuff[4]; /* flags, version stuff, etc */
+}oc_header;
+
+/* client info structures */
+typedef struct {
+ u_long address; /* Client address */
+ char stuff[8]; /* Flags, pruning bitfield, packet counts etc */
+} client_info;
+#pragma pack()
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {7648}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+
+static int
+masq_cuseeme_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+masq_cuseeme_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+int
+masq_cuseeme_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+ cu_header *cu_head;
+ char *data=(char *)&uh[1];
+
+ if (skb->len - ((unsigned char *) data - skb->h.raw) >= sizeof(cu_header))
+ {
+ cu_head = (cu_header *) data;
+ /* cu_head->port = ms->mport; */
+ if( cu_head->addr )
+ cu_head->addr = (u_long) maddr;
+ if(ntohs(cu_head->data_type) == 257)
+ IP_MASQ_DEBUG(1-debug, "Sending talk packet!\n");
+ }
+ return 0;
+}
+
+int
+masq_cuseeme_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->nh.iph;
+ struct udphdr *uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+ cu_header *cu_head;
+ oc_header *oc;
+ client_info *ci;
+ char *data=(char *)&uh[1];
+ u_short len = skb->len - ((unsigned char *) data - skb->h.raw);
+ int i, off;
+
+ if (len >= sizeof(cu_header))
+ {
+ cu_head = (cu_header *) data;
+ if(cu_head->dest_addr) /* Correct destination address */
+ cu_head->dest_addr = (u_long) ms->saddr;
+ if(ntohs(cu_head->data_type)==101 && len > sizeof(oc_header))
+ {
+ oc = (oc_header * ) data;
+ /* Spin (grovel) thru client_info structs till we find our own */
+ off=sizeof(oc_header);
+ for(i=0;
+ (i < oc->client_count && off+sizeof(client_info) <= len);
+ i++)
+ {
+ ci=(client_info *)(data+off);
+ if(ci->address==(u_long) maddr)
+ {
+ /* Update w/ our real ip address and exit */
+ ci->address = (u_long) ms->saddr;
+ break;
+ }
+ else
+ off+=sizeof(client_info);
+ }
+ }
+ }
+ return 0;
+}
+
+struct ip_masq_app ip_masq_cuseeme = {
+ NULL, /* next */
+ "cuseeme",
+ 0, /* type */
+ 0, /* n_attach */
+ masq_cuseeme_init_1, /* ip_masq_init_1 */
+ masq_cuseeme_done_1, /* ip_masq_done_1 */
+ masq_cuseeme_out, /* pkt_out */
+ masq_cuseeme_in /* pkt_in */
+};
+
+
+/*
+ * ip_masq_cuseeme initialization
+ */
+
+__initfunc(int ip_masq_cuseeme_init(void))
+{
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_cuseeme, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_UDP,
+ ports[i]))) {
+ return j;
+ }
+#if DEBUG_CONFIG_IP_MASQ_CUSEEME
+ IP_MASQ_DEBUG(1-debug, "CuSeeMe: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+#endif
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ip_masq_cuseeme fin.
+ */
+
+int ip_masq_cuseeme_done(void)
+{
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "CuSeeMe: unloaded support on port[%d] = %d\n", i, ports[i]);
+ }
+ }
+ }
+ return k;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_cuseeme_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_cuseeme_done() != 0)
+ IP_MASQ_DEBUG(1-debug, "ip_masq_cuseeme: can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_ftp.c b/pfinet/linux-src/net/ipv4/ip_masq_ftp.c
new file mode 100644
index 00000000..35d1f544
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_ftp.c
@@ -0,0 +1,393 @@
+/*
+ * IP_MASQ_FTP ftp masquerading module
+ *
+ *
+ * Version: @(#)ip_masq_ftp.c 0.04 02/05/96
+ *
+ * Author: Wouter Gadeyne
+ *
+ *
+ * Fixes:
+ * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands
+ * Juan Jose Ciarlante : Code moved and adapted from ip_fw.c
+ * Keith Owens : Add keep alive for ftp control channel
+ * Nigel Metheringham : Added multiple port support
+ * Juan Jose Ciarlante : Use control_add() for ftp control chan
+ * Juan Jose Ciarlante : Litl bits for 2.1
+ * Juan Jose Ciarlante : use ip_masq_listen()
+ * Juan Jose Ciarlante : use private app_data for own flag(s)
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+
+/* #define IP_MASQ_NDEBUG */
+#include <net/ip_masq.h>
+
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {21}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+
+/* Dummy variable */
+static int masq_ftp_pasv;
+
+static int
+masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+masq_ftp_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+int
+masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *p, *data, *data_limit;
+ unsigned char p1,p2,p3,p4,p5,p6;
+ __u32 from;
+ __u16 port;
+ struct ip_masq *n_ms;
+ char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
+ unsigned buf_len;
+ int diff;
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ data_limit = skb->h.raw + skb->len - 18;
+ if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0))
+ ms->app_data = &masq_ftp_pasv;
+
+ while (data < data_limit)
+ {
+ if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5))
+ {
+ data ++;
+ continue;
+ }
+ p = data+5;
+ p1 = simple_strtoul(data+5,&data,10);
+ if (*data!=',')
+ continue;
+ p2 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p3 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p4 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p5 = simple_strtoul(data+1,&data,10);
+ if (*data!=',')
+ continue;
+ p6 = simple_strtoul(data+1,&data,10);
+ if (*data!='\r' && *data!='\n')
+ continue;
+
+ from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
+ port = (p5<<8) | p6;
+
+ IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port);
+
+ /*
+ * Now update or create an masquerade entry for it
+ */
+
+ IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0);
+
+ n_ms = ip_masq_out_get(iph->protocol,
+ htonl(from), htons(port),
+ iph->daddr, 0);
+ if (!n_ms) {
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, 0,
+ htonl(from), htons(port),
+ iph->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+
+ if (n_ms==NULL)
+ return 0;
+ ip_masq_control_add(n_ms, ms);
+ }
+
+ /*
+ * Replace the old PORT with the new one
+ */
+ from = ntohl(n_ms->maddr);
+ port = ntohs(n_ms->mport);
+ sprintf(buf,"%d,%d,%d,%d,%d,%d",
+ from>>24&255,from>>16&255,from>>8&255,from&255,
+ port>>8&255,port&255);
+ buf_len = strlen(buf);
+
+ IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port);
+
+ /*
+ * Calculate required delta-offset to keep TCP happy
+ */
+
+ diff = buf_len - (data-p);
+
+ /*
+ * No shift.
+ */
+
+ if (diff==0) {
+ /*
+ * simple case, just replace the old PORT cmd
+ */
+ memcpy(p,buf,buf_len);
+ } else {
+
+ *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
+ }
+ /*
+ * Move tunnel to listen state
+ */
+ ip_masq_listen(n_ms);
+ ip_masq_put(n_ms);
+
+ return diff;
+
+ }
+ return 0;
+
+}
+
+/*
+ * Look at incoming ftp packets to catch the response to a PASV command. When
+ * we see one we build a masquerading entry for the client address, client port
+ * 0 (unknown at the moment), the server address and the server port. Mark the
+ * current masquerade entry as a control channel and point the new entry at the
+ * control entry. All this work just for ftp keepalive across masquerading.
+ *
+ * The incoming packet should be something like
+ * "227 Entering Passive Mode (xxx,xxx,xxx,xxx,ppp,ppp)".
+ * xxx,xxx,xxx,xxx is the server address, ppp,ppp is the server port number.
+ * ncftp 2.3.0 cheats by skipping the leading number then going 22 bytes into
+ * the data so we do the same. If it's good enough for ncftp then it's good
+ * enough for me.
+ *
+ * In this case, the client is the source machine being masqueraded, the server
+ * is the destination for ftp requests. It all depends on your point of view ...
+ */
+
+int
+masq_ftp_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *data, *data_limit;
+ unsigned char p1,p2,p3,p4,p5,p6;
+ __u32 to;
+ __u16 port;
+ struct ip_masq *n_ms;
+
+ if (ms->app_data != &masq_ftp_pasv)
+ return 0; /* quick exit if no outstanding PASV */
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+ data_limit = skb->h.raw + skb->len;
+
+ while (data < data_limit && *data != ' ')
+ ++data;
+ while (data < data_limit && *data == ' ')
+ ++data;
+ data += 22;
+ if (data >= data_limit || *data != '(')
+ return 0;
+ p1 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p2 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p3 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p4 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p5 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ',')
+ return 0;
+ p6 = simple_strtoul(data+1, &data, 10);
+ if (data >= data_limit || *data != ')')
+ return 0;
+
+ to = (p1<<24) | (p2<<16) | (p3<<8) | p4;
+ port = (p5<<8) | p6;
+
+ /*
+ * Now update or create an masquerade entry for it
+ */
+ IP_MASQ_DEBUG(1-debug, "PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port);
+
+ n_ms = ip_masq_out_get(iph->protocol,
+ ms->saddr, 0,
+ htonl(to), htons(port));
+ if (!n_ms) {
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, 0,
+ ms->saddr, 0,
+ htonl(to), htons(port),
+ IP_MASQ_F_NO_SPORT);
+
+ if (n_ms==NULL)
+ return 0;
+ ip_masq_control_add(n_ms, ms);
+ }
+
+#if 0 /* v0.12 state processing */
+
+ /*
+ * keep for a bit longer than tcp_fin, client may not issue open
+ * to server port before tcp_fin_timeout.
+ */
+ n_ms->timeout = ip_masq_expire->tcp_fin_timeout*3;
+#endif
+ ms->app_data = NULL;
+ ip_masq_put(n_ms);
+
+ return 0; /* no diff required for incoming packets, thank goodness */
+}
+
+struct ip_masq_app ip_masq_ftp = {
+ NULL, /* next */
+ "ftp", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_ftp_init_1, /* ip_masq_init_1 */
+ masq_ftp_done_1, /* ip_masq_done_1 */
+ masq_ftp_out, /* pkt_out */
+ masq_ftp_in, /* pkt_in */
+};
+
+/*
+ * ip_masq_ftp initialization
+ */
+
+__initfunc(int ip_masq_ftp_init(void))
+{
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_ftp, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug, "Ftp: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ip_masq_ftp fin.
+ */
+
+int ip_masq_ftp_done(void)
+{
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "Ftp: unloaded support on port[%d] = %d\n",
+ i, ports[i]);
+ }
+ }
+ }
+ return k;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_ftp_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_ftp_done() != 0)
+ printk(KERN_INFO "ip_masq_ftp: can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_irc.c b/pfinet/linux-src/net/ipv4/ip_masq_irc.c
new file mode 100644
index 00000000..e52a5720
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_irc.c
@@ -0,0 +1,345 @@
+/*
+ * IP_MASQ_IRC irc masquerading module
+ *
+ *
+ * Version: @(#)ip_masq_irc.c 0.04 99/06/19
+ *
+ * Author: Juan Jose Ciarlante
+ *
+ * Additions:
+ * - recognize a few non-irc-II DCC requests (Oliver Wagner)
+ * DCC MOVE (AmIRC/DCC.MOVE; SEND with resuming)
+ * DCC SCHAT (AmIRC IDEA encrypted CHAT)
+ * DCC TSEND (AmIRC/PIRCH SEND without ACKs)
+ * Fixes:
+ * Juan Jose Ciarlante : set NO_DADDR flag in ip_masq_new()
+ * Nigel Metheringham : Added multiple port support
+ * Juan Jose Ciarlante : litl bits for 2.1
+ * Oliver Wagner : more IRC cmds processing
+ * <winmute@lucifer.gv.kotnet.org>
+ * Juan Jose Ciarlante : put new ms entry to listen()
+ * Scottie Shore : added support for clients that add extra args
+ * <sshore@escape.ca>
+ *
+ * FIXME:
+ * - detect also previous "PRIVMSG" string ?.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+int ports[MAX_MASQ_APP_PORTS] = {6667}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+/*
+ * Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+
+
+/*
+ * List of supported DCC protocols
+ */
+
+#define NUM_DCCPROTO 5
+
+struct dccproto
+{
+ char *match;
+ int matchlen;
+};
+
+struct dccproto dccprotos[NUM_DCCPROTO] = {
+ { "SEND ", 5 },
+ { "CHAT ", 5 },
+ { "MOVE ", 5 },
+ { "TSEND ", 6 },
+ { "SCHAT ", 6 }
+};
+#define MAXMATCHLEN 6
+
+static int
+masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int
+masq_irc_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+int
+masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *data, *data_limit;
+ __u32 s_addr;
+ __u16 s_port;
+ struct ip_masq *n_ms;
+ char buf[20]; /* "m_addr m_port" (dec base)*/
+ unsigned buf_len;
+ int diff;
+ char *dcc_p, *addr_beg_p, *addr_end_p;
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ /*
+ * Hunt irc DCC string, the _shortest_:
+ *
+ * strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
+ * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
+ * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
+ * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
+ * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
+ * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
+ * P: bound port (min 1 d )
+ * F: filename (min 1 d )
+ * S: size (min 1 d )
+ * 0x01, \n: terminators
+ */
+
+ data_limit = skb->h.raw + skb->len;
+
+ while (data < (data_limit - ( 22 + MAXMATCHLEN ) ) )
+ {
+ int i;
+ if (memcmp(data,"\1DCC ",5)) {
+ data ++;
+ continue;
+ }
+
+ dcc_p = data;
+ data += 5; /* point to DCC cmd */
+
+ for(i=0; i<NUM_DCCPROTO; i++)
+ {
+ /*
+ * go through the table and hunt a match string
+ */
+
+ if( memcmp(data, dccprotos[i].match, dccprotos[i].matchlen ) == 0 )
+ {
+ data += dccprotos[i].matchlen;
+
+ /*
+ * skip next string.
+ */
+
+ while( *data++ != ' ')
+
+ /*
+ * must still parse, at least, "AAAAAAAA P\1\n",
+ * 12 bytes left.
+ */
+ if (data > (data_limit-12)) return 0;
+
+
+ addr_beg_p = data;
+
+ /*
+ * client bound address in dec base
+ */
+
+ s_addr = simple_strtoul(data,&data,10);
+ if (*data++ !=' ')
+ continue;
+
+ /*
+ * client bound port in dec base
+ */
+
+ s_port = simple_strtoul(data,&data,10);
+ addr_end_p = data;
+
+ /*
+ * Now create an masquerade entry for it
+ * must set NO_DPORT and NO_DADDR because
+ * connection is requested by another client.
+ */
+
+ n_ms = ip_masq_new(IPPROTO_TCP,
+ maddr, 0,
+ htonl(s_addr),htons(s_port),
+ 0, 0,
+ IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+ if (n_ms==NULL)
+ return 0;
+
+ /*
+ * Replace the old "address port" with the new one
+ */
+
+ buf_len = sprintf(buf,"%lu %u",
+ ntohl(n_ms->maddr),ntohs(n_ms->mport));
+
+ /*
+ * Calculate required delta-offset to keep TCP happy
+ */
+
+ diff = buf_len - (addr_end_p-addr_beg_p);
+
+ *addr_beg_p = '\0';
+ IP_MASQ_DEBUG(1-debug, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
+
+ /*
+ * No shift.
+ */
+
+ if (diff==0) {
+ /*
+ * simple case, just copy.
+ */
+ memcpy(addr_beg_p,buf,buf_len);
+ } else {
+
+ *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+ addr_beg_p, addr_end_p-addr_beg_p,
+ buf, buf_len);
+ }
+ ip_masq_listen(n_ms);
+ ip_masq_put(n_ms);
+ return diff;
+ }
+ }
+ }
+ return 0;
+
+}
+
+/*
+ * Main irc object
+ * You need 1 object per port in case you need
+ * to offer also other used irc ports (6665,6666,etc),
+ * they will share methods but they need own space for
+ * data.
+ */
+
+struct ip_masq_app ip_masq_irc = {
+ NULL, /* next */
+ "irc", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_irc_init_1, /* init_1 */
+ masq_irc_done_1, /* done_1 */
+ masq_irc_out, /* pkt_out */
+ NULL /* pkt_in */
+};
+
+/*
+ * ip_masq_irc initialization
+ */
+
+__initfunc(int ip_masq_irc_init(void))
+{
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_irc, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug,
+ "Irc: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ip_masq_irc fin.
+ */
+
+int ip_masq_irc_done(void)
+{
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "Irc: unloaded support on port[%d] = %d\n",
+ i, ports[i]);
+ }
+ }
+ }
+ return k;
+}
+
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_irc_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_irc_done() != 0)
+ printk(KERN_INFO "ip_masq_irc: can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_mfw.c b/pfinet/linux-src/net/ipv4/ip_masq_mfw.c
new file mode 100644
index 00000000..d28f610a
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_mfw.c
@@ -0,0 +1,770 @@
+/*
+ * IP_MASQ_MARKFW masquerading module
+ *
+ * Does (reverse-masq) forwarding based on skb->fwmark value
+ *
+ * $Id: ip_masq_mfw.c,v 1.3.2.3 1999/09/22 16:33:26 davem Exp $
+ *
+ * Author: Juan Jose Ciarlante <jjciarla@raiz.uncu.edu.ar>
+ * based on Steven Clarke's portfw
+ *
+ * Fixes:
+ * JuanJo Ciarlante: added u-space sched support
+ * JuanJo Ciarlante: if rport==0, use packet dest port *grin*
+ * JuanJo Ciarlante: fixed tcp syn&&!ack creation
+ *
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <net/ip.h>
+#include <linux/ip_fw.h>
+#include <linux/ip_masq.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/softirq.h>
+#include <asm/spinlock.h>
+#include <asm/atomic.h>
+
+static struct ip_masq_mod *mmod_self = NULL;
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+/*
+ * Lists structure:
+ * There is a "main" linked list with entries hashed
+ * by fwmark value (struct ip_masq_mfw, the "m-entries").
+ *
+ * Each of this m-entry holds a double linked list
+ * of "forward-to" hosts (struct ip_masq_mfw_host, the "m.host"),
+ * the round-robin scheduling takes place by rotating m.host entries
+ * "inside" its m-entry.
+ */
+
+/*
+ * Each forwarded host (addr:port) is stored here
+ */
+struct ip_masq_mfw_host {
+ struct list_head list;
+ __u32 addr;
+ __u16 port;
+ __u16 pad0;
+ __u32 fwmark;
+ int pref;
+ atomic_t pref_cnt;
+};
+
+#define IP_MASQ_MFW_HSIZE 16
+/*
+ * This entries are indexed by fwmark,
+ * they hold a list of forwarded addr:port
+ */
+
+struct ip_masq_mfw {
+ struct ip_masq_mfw *next; /* linked list */
+ __u32 fwmark; /* key: firewall mark */
+ struct list_head hosts; /* list of forward-to hosts */
+ atomic_t nhosts; /* number of "" */
+ rwlock_t lock;
+};
+
+
+static struct semaphore mfw_sema = MUTEX;
+static rwlock_t mfw_lock = RW_LOCK_UNLOCKED;
+
+static struct ip_masq_mfw *ip_masq_mfw_table[IP_MASQ_MFW_HSIZE];
+
+static __inline__ int mfw_hash_val(int fwmark)
+{
+ return fwmark & 0x0f;
+}
+
+/*
+ * Get m-entry by "fwmark"
+ * Caller must lock tables.
+ */
+
+static struct ip_masq_mfw *__mfw_get(int fwmark)
+{
+ struct ip_masq_mfw* mfw;
+ int hash = mfw_hash_val(fwmark);
+
+ for (mfw=ip_masq_mfw_table[hash];mfw;mfw=mfw->next) {
+ if (mfw->fwmark==fwmark) {
+ goto out;
+ }
+ }
+out:
+ return mfw;
+}
+
+/*
+ * Links m-entry.
+ * Caller should have checked if already present for same fwmark
+ *
+ * Caller must lock tables.
+ */
+static int __mfw_add(struct ip_masq_mfw *mfw)
+{
+ int fwmark = mfw->fwmark;
+ int hash = mfw_hash_val(fwmark);
+
+ mfw->next = ip_masq_mfw_table[hash];
+ ip_masq_mfw_table[hash] = mfw;
+ ip_masq_mod_inc_nent(mmod_self);
+
+ return 0;
+}
+
+/*
+ * Creates a m-entry (doesn't link it)
+ */
+
+static struct ip_masq_mfw * mfw_new(int fwmark)
+{
+ struct ip_masq_mfw *mfw;
+
+ mfw = kmalloc(sizeof(*mfw), GFP_KERNEL);
+ if (mfw == NULL)
+ goto out;
+
+ MOD_INC_USE_COUNT;
+ memset(mfw, 0, sizeof(*mfw));
+ mfw->fwmark = fwmark;
+ mfw->lock = RW_LOCK_UNLOCKED;
+
+ INIT_LIST_HEAD(&mfw->hosts);
+out:
+ return mfw;
+}
+
+static void mfw_host_to_user(struct ip_masq_mfw_host *h, struct ip_mfw_user *mu)
+{
+ mu->raddr = h->addr;
+ mu->rport = h->port;
+ mu->fwmark = h->fwmark;
+ mu->pref = h->pref;
+}
+
+/*
+ * Creates a m.host (doesn't link it in a m-entry)
+ */
+static struct ip_masq_mfw_host * mfw_host_new(struct ip_mfw_user *mu)
+{
+ struct ip_masq_mfw_host * mfw_host;
+ mfw_host = kmalloc(sizeof (*mfw_host), GFP_KERNEL);
+ if (!mfw_host)
+ return NULL;
+
+ MOD_INC_USE_COUNT;
+ memset(mfw_host, 0, sizeof(*mfw_host));
+ mfw_host->addr = mu->raddr;
+ mfw_host->port = mu->rport;
+ mfw_host->fwmark = mu->fwmark;
+ mfw_host->pref = mu->pref;
+ atomic_set(&mfw_host->pref_cnt, mu->pref);
+
+ return mfw_host;
+}
+
+/*
+ * Create AND link m.host to m-entry.
+ * It locks m.lock.
+ */
+static int mfw_addhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu, int attail)
+{
+ struct ip_masq_mfw_host *mfw_host;
+
+ mfw_host = mfw_host_new(mu);
+ if (!mfw_host)
+ return -ENOMEM;
+
+ write_lock_bh(&mfw->lock);
+ list_add(&mfw_host->list, attail? mfw->hosts.prev : &mfw->hosts);
+ atomic_inc(&mfw->nhosts);
+ write_unlock_bh(&mfw->lock);
+
+ return 0;
+}
+
+/*
+ * Unlink AND destroy m.host(s) from m-entry.
+ * Wildcard (nul host or addr) ok.
+ * It uses m.lock.
+ */
+static int mfw_delhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu)
+{
+
+ struct list_head *l,*e;
+ struct ip_masq_mfw_host *h;
+ int n_del = 0;
+ l = &mfw->hosts;
+
+ write_lock_bh(&mfw->lock);
+ for (e=l->next; e!=l; e=e->next)
+ {
+ h = list_entry(e, struct ip_masq_mfw_host, list);
+ if ((!mu->raddr || h->addr == mu->raddr) &&
+ (!mu->rport || h->port == mu->rport)) {
+ /* HIT */
+ atomic_dec(&mfw->nhosts);
+ e = h->list.prev;
+ list_del(&h->list);
+ kfree_s(h, sizeof(*h));
+ MOD_DEC_USE_COUNT;
+ n_del++;
+ }
+
+ }
+ write_unlock_bh(&mfw->lock);
+ return n_del? 0 : -ESRCH;
+}
+
+/*
+ * Changes m.host parameters
+ * Wildcards ok
+ *
+ * Caller must lock tables.
+ */
+static int __mfw_edithost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu)
+{
+
+ struct list_head *l,*e;
+ struct ip_masq_mfw_host *h;
+ int n_edit = 0;
+ l = &mfw->hosts;
+
+ for (e=l->next; e!=l; e=e->next)
+ {
+ h = list_entry(e, struct ip_masq_mfw_host, list);
+ if ((!mu->raddr || h->addr == mu->raddr) &&
+ (!mu->rport || h->port == mu->rport)) {
+ /* HIT */
+ h->pref = mu->pref;
+ atomic_set(&h->pref_cnt, mu->pref);
+ n_edit++;
+ }
+
+ }
+ return n_edit? 0 : -ESRCH;
+}
+
+/*
+ * Destroys m-entry.
+ * Caller must have checked that it doesn't hold any m.host(s)
+ */
+static void mfw_destroy(struct ip_masq_mfw *mfw)
+{
+ kfree_s(mfw, sizeof(*mfw));
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Unlink m-entry.
+ *
+ * Caller must lock tables.
+ */
+static int __mfw_del(struct ip_masq_mfw *mfw)
+{
+ struct ip_masq_mfw **mfw_p;
+ int ret = -EINVAL;
+
+
+ for(mfw_p=&ip_masq_mfw_table[mfw_hash_val(mfw->fwmark)];
+ *mfw_p;
+ mfw_p = &((*mfw_p)->next))
+ {
+ if (mfw==(*mfw_p)) {
+ *mfw_p = mfw->next;
+ ip_masq_mod_dec_nent(mmod_self);
+ ret = 0;
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+/*
+ * Crude m.host scheduler
+ * This interface could be exported to allow playing with
+ * other sched policies.
+ *
+ * Caller must lock m-entry.
+ */
+static struct ip_masq_mfw_host * __mfw_sched(struct ip_masq_mfw *mfw, int force)
+{
+ struct ip_masq_mfw_host *h = NULL;
+
+ if (atomic_read(&mfw->nhosts) == 0)
+ goto out;
+
+ /*
+ * Here resides actual sched policy:
+ * When pref_cnt touches 0, entry gets shifted to tail and
+ * its pref_cnt reloaded from h->pref (actual value
+ * passed from u-space).
+ *
+ * Exception is pref==0: avoid scheduling.
+ */
+
+ h = list_entry(mfw->hosts.next, struct ip_masq_mfw_host, list);
+
+ if (atomic_read(&mfw->nhosts) <= 1)
+ goto out;
+
+ if ((h->pref && atomic_dec_and_test(&h->pref_cnt)) || force) {
+ atomic_set(&h->pref_cnt, h->pref);
+ list_del(&h->list);
+ list_add(&h->list, mfw->hosts.prev);
+ }
+out:
+ return h;
+}
+
+/*
+ * Main lookup routine.
+ * HITs fwmark and schedules m.host entries if required
+ */
+static struct ip_masq_mfw_host * mfw_lookup(int fwmark)
+{
+ struct ip_masq_mfw *mfw;
+ struct ip_masq_mfw_host *h = NULL;
+
+ read_lock(&mfw_lock);
+ mfw = __mfw_get(fwmark);
+
+ if (mfw) {
+ write_lock(&mfw->lock);
+ h = __mfw_sched(mfw, 0);
+ write_unlock(&mfw->lock);
+ }
+
+ read_unlock(&mfw_lock);
+ return h;
+}
+
+#ifdef CONFIG_PROC_FS
+static int mfw_procinfo(char *buffer, char **start, off_t offset,
+ int length, int dummy)
+{
+ struct ip_masq_mfw *mfw;
+ struct ip_masq_mfw_host *h;
+ struct list_head *l,*e;
+ off_t pos=0, begin;
+ char temp[129];
+ int idx = 0;
+ int len=0;
+
+ MOD_INC_USE_COUNT;
+
+ IP_MASQ_DEBUG(1-debug, "Entered mfw_info\n");
+
+ if (offset < 64)
+ {
+ sprintf(temp, "FwMark > RAddr RPort PrCnt Pref");
+ len = sprintf(buffer, "%-63s\n", temp);
+ }
+ pos = 64;
+
+ for(idx = 0; idx < IP_MASQ_MFW_HSIZE; idx++)
+ {
+ read_lock(&mfw_lock);
+ for(mfw = ip_masq_mfw_table[idx]; mfw ; mfw = mfw->next)
+ {
+ read_lock_bh(&mfw->lock);
+ l=&mfw->hosts;
+
+ for(e=l->next;l!=e;e=e->next) {
+ h = list_entry(e, struct ip_masq_mfw_host, list);
+ pos += 64;
+ if (pos <= offset) {
+ len = 0;
+ continue;
+ }
+
+ sprintf(temp,"0x%x > %08lX %5u %5d %5d",
+ h->fwmark,
+ ntohl(h->addr), ntohs(h->port),
+ atomic_read(&h->pref_cnt), h->pref);
+ len += sprintf(buffer+len, "%-63s\n", temp);
+
+ if(len >= length) {
+ read_unlock_bh(&mfw->lock);
+ read_unlock(&mfw_lock);
+ goto done;
+ }
+ }
+ read_unlock_bh(&mfw->lock);
+ }
+ read_unlock(&mfw_lock);
+ }
+
+done:
+
+ if (len) {
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+ }
+ if(len>length)
+ len = length;
+ MOD_DEC_USE_COUNT;
+ return len;
+}
+static struct proc_dir_entry mfw_proc_entry = {
+/* 0, 0, NULL", */
+ 0, 3, "mfw",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ mfw_procinfo
+};
+
+#define proc_ent &mfw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+
+static void mfw_flush(void)
+{
+ struct ip_masq_mfw *mfw, *local_table[IP_MASQ_MFW_HSIZE];
+ struct ip_masq_mfw_host *h;
+ struct ip_masq_mfw *mfw_next;
+ int idx;
+ struct list_head *l,*e;
+
+ write_lock_bh(&mfw_lock);
+ memcpy(local_table, ip_masq_mfw_table, sizeof ip_masq_mfw_table);
+ memset(ip_masq_mfw_table, 0, sizeof ip_masq_mfw_table);
+ write_unlock_bh(&mfw_lock);
+
+ /*
+ * For every hash table row ...
+ */
+ for(idx=0;idx<IP_MASQ_MFW_HSIZE;idx++) {
+
+ /*
+ * For every m-entry in row ...
+ */
+ for(mfw=local_table[idx];mfw;mfw=mfw_next) {
+ /*
+ * For every m.host in m-entry ...
+ */
+ l=&mfw->hosts;
+ while((e=l->next) != l) {
+ h = list_entry(e, struct ip_masq_mfw_host, list);
+ atomic_dec(&mfw->nhosts);
+ list_del(&h->list);
+ kfree_s(h, sizeof(*h));
+ MOD_DEC_USE_COUNT;
+ }
+
+ if (atomic_read(&mfw->nhosts)) {
+ IP_MASQ_ERR("mfw_flush(): after flushing row nhosts=%d\n",
+ atomic_read(&mfw->nhosts));
+ }
+ mfw_next = mfw->next;
+ kfree_s(mfw, sizeof(*mfw));
+ MOD_DEC_USE_COUNT;
+ ip_masq_mod_dec_nent(mmod_self);
+ }
+ }
+}
+
+/*
+ * User space control entry point
+ */
+static int mfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+ struct ip_mfw_user *mu = &mctl->u.mfw_user;
+ struct ip_masq_mfw *mfw;
+ int ret = EINVAL;
+ int arglen = optlen - IP_MASQ_CTL_BSIZE;
+ int cmd;
+
+
+ IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
+ arglen,
+ sizeof (*mu),
+ optlen,
+ sizeof (*mctl));
+
+ /*
+ * checks ...
+ */
+ if (arglen != sizeof(*mu) && optlen != sizeof(*mctl))
+ return -EINVAL;
+
+ /*
+ * Don't trust the lusers - plenty of error checking!
+ */
+ cmd = mctl->m_cmd;
+ IP_MASQ_DEBUG(1-debug, "ip_masq_mfw_ctl(cmd=%d, fwmark=%d)\n",
+ cmd, mu->fwmark);
+
+
+ switch(cmd) {
+ case IP_MASQ_CMD_NONE:
+ return 0;
+ case IP_MASQ_CMD_FLUSH:
+ break;
+ case IP_MASQ_CMD_ADD:
+ case IP_MASQ_CMD_INSERT:
+ case IP_MASQ_CMD_SET:
+ if (mu->fwmark == 0) {
+ IP_MASQ_DEBUG(1-debug, "invalid fwmark==0\n");
+ return -EINVAL;
+ }
+ if (mu->pref < 0) {
+ IP_MASQ_DEBUG(1-debug, "invalid pref==%d\n",
+ mu->pref);
+ return -EINVAL;
+ }
+ break;
+ }
+
+
+ ret = -EINVAL;
+
+ switch(cmd) {
+ case IP_MASQ_CMD_ADD:
+ case IP_MASQ_CMD_INSERT:
+ if (!mu->raddr) {
+ IP_MASQ_DEBUG(0-debug, "ip_masq_mfw_ctl(ADD): invalid redirect 0x%x:%d\n",
+ mu->raddr, mu->rport);
+ goto out;
+ }
+
+ /*
+ * Cannot just use mfw_lock because below
+ * are allocations that can sleep; so
+ * to assure "new entry" atomic creation
+ * I use a semaphore.
+ *
+ */
+ down(&mfw_sema);
+
+ read_lock(&mfw_lock);
+ mfw = __mfw_get(mu->fwmark);
+ read_unlock(&mfw_lock);
+
+ /*
+ * If first host, create m-entry
+ */
+ if (mfw == NULL) {
+ mfw = mfw_new(mu->fwmark);
+ if (mfw == NULL)
+ ret = -ENOMEM;
+ }
+
+ if (mfw) {
+ /*
+ * Put m.host in m-entry.
+ */
+ ret = mfw_addhost(mfw, mu, cmd == IP_MASQ_CMD_ADD);
+
+ /*
+ * If first host, link m-entry to hash table.
+ * Already protected by global lock.
+ */
+ if (ret == 0 && atomic_read(&mfw->nhosts) == 1) {
+ write_lock_bh(&mfw_lock);
+ __mfw_add(mfw);
+ write_unlock_bh(&mfw_lock);
+ }
+ if (atomic_read(&mfw->nhosts) == 0) {
+ mfw_destroy(mfw);
+ }
+ }
+
+ up(&mfw_sema);
+
+ break;
+
+ case IP_MASQ_CMD_DEL:
+ down(&mfw_sema);
+
+ read_lock(&mfw_lock);
+ mfw = __mfw_get(mu->fwmark);
+ read_unlock(&mfw_lock);
+
+ if (mfw) {
+ ret = mfw_delhost(mfw, mu);
+
+ /*
+ * Last lease will free
+ * XXX check logic XXX
+ */
+ if (atomic_read(&mfw->nhosts) == 0) {
+ write_lock_bh(&mfw_lock);
+ __mfw_del(mfw);
+ write_unlock_bh(&mfw_lock);
+ mfw_destroy(mfw);
+ }
+ } else
+ ret = -ESRCH;
+
+ up(&mfw_sema);
+ break;
+ case IP_MASQ_CMD_FLUSH:
+
+ down(&mfw_sema);
+ mfw_flush();
+ up(&mfw_sema);
+ ret = 0;
+ break;
+ case IP_MASQ_CMD_SET:
+ /*
+ * No need to semaphorize here, main list is not
+ * modified.
+ */
+ read_lock(&mfw_lock);
+
+ mfw = __mfw_get(mu->fwmark);
+ if (mfw) {
+ write_lock_bh(&mfw->lock);
+
+ if (mu->flags & IP_MASQ_MFW_SCHED) {
+ struct ip_masq_mfw_host *h;
+ if ((h=__mfw_sched(mfw, 1))) {
+ mfw_host_to_user(h, mu);
+ ret = 0;
+ }
+ } else {
+ ret = __mfw_edithost(mfw, mu);
+ }
+
+ write_unlock_bh(&mfw->lock);
+ }
+
+ read_unlock(&mfw_lock);
+ break;
+ }
+out:
+
+ return ret;
+}
+
+/*
+ * Module stubs called from ip_masq core module
+ */
+
+/*
+ * Input rule stub, called very early for each incoming packet,
+ * to see if this module has "interest" in packet.
+ */
+static int mfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
+{
+ int val;
+ read_lock(&mfw_lock);
+ val = ( __mfw_get(skb->fwmark) != 0);
+ read_unlock(&mfw_lock);
+ return val;
+}
+
+/*
+ * Input-create stub, called to allow "custom" masq creation
+ */
+static struct ip_masq * mfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
+{
+ union ip_masq_tphdr tph;
+ struct ip_masq *ms = NULL;
+ struct ip_masq_mfw_host *h = NULL;
+
+ tph.raw = (char*) iph + iph->ihl * 4;
+
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ /*
+ * Only open TCP tunnel if SYN+!ACK packet
+ */
+ if (!tph.th->syn || tph.th->ack)
+ return NULL;
+ case IPPROTO_UDP:
+ break;
+ default:
+ return NULL;
+ }
+
+ /*
+ * If no entry exists in the masquerading table
+ * and the port is involved
+ * in port forwarding, create a new masq entry
+ */
+
+ if ((h=mfw_lookup(skb->fwmark))) {
+ ms = ip_masq_new(iph->protocol,
+ iph->daddr, tph.portp[1],
+ /* if no redir-port, use packet dest port */
+ h->addr, h->port? h->port : tph.portp[1],
+ iph->saddr, tph.portp[0],
+ 0);
+
+ if (ms != NULL)
+ ip_masq_listen(ms);
+ }
+ return ms;
+}
+
+
+#define mfw_in_update NULL
+#define mfw_out_rule NULL
+#define mfw_out_create NULL
+#define mfw_out_update NULL
+
+static struct ip_masq_mod mfw_mod = {
+ NULL, /* next */
+ NULL, /* next_reg */
+ "mfw", /* name */
+ ATOMIC_INIT(0), /* nent */
+ ATOMIC_INIT(0), /* refcnt */
+ proc_ent,
+ mfw_ctl,
+ NULL, /* masq_mod_init */
+ NULL, /* masq_mod_done */
+ mfw_in_rule,
+ mfw_in_update,
+ mfw_in_create,
+ mfw_out_rule,
+ mfw_out_update,
+ mfw_out_create,
+};
+
+
+__initfunc(int ip_mfw_init(void))
+{
+ return register_ip_masq_mod ((mmod_self=&mfw_mod));
+}
+
+int ip_mfw_done(void)
+{
+ return unregister_ip_masq_mod(&mfw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_mfw_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_mfw_done() != 0)
+ printk(KERN_INFO "can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_mod.c b/pfinet/linux-src/net/ipv4/ip_masq_mod.c
new file mode 100644
index 00000000..b99502f3
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_mod.c
@@ -0,0 +1,322 @@
+/*
+ * IP_MASQ_MOD masq modules support
+ *
+ *
+ * Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ * $Id: ip_masq_mod.c,v 1.5.2.1 1999/07/02 10:10:03 davem Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ * Cyrus Durgin: fixed kerneld stuff for kmod.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+
+#include <linux/ip_masq.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+EXPORT_SYMBOL(register_ip_masq_mod);
+EXPORT_SYMBOL(unregister_ip_masq_mod);
+EXPORT_SYMBOL(ip_masq_mod_lkp_link);
+EXPORT_SYMBOL(ip_masq_mod_lkp_unlink);
+
+static spinlock_t masq_mod_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Base pointer for registered modules
+ */
+struct ip_masq_mod * ip_masq_mod_reg_base = NULL;
+
+/*
+ * Base pointer for lookup (subset of above, a module could be
+ * registered, but it could have no active rule); will avoid
+ * unnecessary lookups.
+ */
+struct ip_masq_mod * ip_masq_mod_lkp_base = NULL;
+
+int ip_masq_mod_register_proc(struct ip_masq_mod *mmod)
+{
+#ifdef CONFIG_PROC_FS
+ int ret;
+
+ struct proc_dir_entry *ent = mmod->mmod_proc_ent;
+
+ if (!ent)
+ return 0;
+ if (!ent->name) {
+ ent->name = mmod->mmod_name;
+ ent->namelen = strlen (mmod->mmod_name);
+ }
+ ret = ip_masq_proc_register(ent);
+ if (ret) mmod->mmod_proc_ent = NULL;
+
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+void ip_masq_mod_unregister_proc(struct ip_masq_mod *mmod)
+{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent = mmod->mmod_proc_ent;
+ if (!ent)
+ return;
+ ip_masq_proc_unregister(ent);
+#endif
+}
+
+/*
+ * Link/unlink object for lookups
+ */
+
+int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod)
+{
+ struct ip_masq_mod **mmod_p;
+
+ write_lock_bh(&masq_mod_lock);
+
+ for (mmod_p = &ip_masq_mod_lkp_base; *mmod_p ; mmod_p = &(*mmod_p)->next)
+ if (mmod == (*mmod_p)) {
+ *mmod_p = mmod->next;
+ mmod->next = NULL;
+ write_unlock_bh(&masq_mod_lock);
+ return 0;
+ }
+
+ write_unlock_bh(&masq_mod_lock);
+ return -EINVAL;
+}
+
+int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod)
+{
+ write_lock_bh(&masq_mod_lock);
+
+ mmod->next = ip_masq_mod_lkp_base;
+ ip_masq_mod_lkp_base=mmod;
+
+ write_unlock_bh(&masq_mod_lock);
+ return 0;
+}
+
+int register_ip_masq_mod(struct ip_masq_mod *mmod)
+{
+ if (!mmod) {
+ IP_MASQ_ERR("register_ip_masq_mod(): NULL arg\n");
+ return -EINVAL;
+ }
+ if (!mmod->mmod_name) {
+ IP_MASQ_ERR("register_ip_masq_mod(): NULL mmod_name\n");
+ return -EINVAL;
+ }
+ ip_masq_mod_register_proc(mmod);
+
+ mmod->next_reg = ip_masq_mod_reg_base;
+ ip_masq_mod_reg_base=mmod;
+
+ return 0;
+}
+
+int unregister_ip_masq_mod(struct ip_masq_mod *mmod)
+{
+ struct ip_masq_mod **mmod_p;
+
+ if (!mmod) {
+ IP_MASQ_ERR( "unregister_ip_masq_mod(): NULL arg\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Only allow unregistration if it is not referenced
+ */
+ if (atomic_read(&mmod->refcnt)) {
+ IP_MASQ_ERR( "unregister_ip_masq_mod(): is in use by %d guys. failed\n",
+ atomic_read(&mmod->refcnt));
+ return -EINVAL;
+ }
+
+ /*
+ * Must be already unlinked from lookup list
+ */
+ if (mmod->next) {
+ IP_MASQ_WARNING("MASQ: unregistering \"%s\" while in lookup list.fixed.",
+ mmod->mmod_name);
+ ip_masq_mod_lkp_unlink(mmod);
+ }
+
+ for (mmod_p = &ip_masq_mod_reg_base; *mmod_p ; mmod_p = &(*mmod_p)->next_reg)
+ if (mmod == (*mmod_p)) {
+ ip_masq_mod_unregister_proc(mmod);
+ *mmod_p = mmod->next_reg;
+ return 0;
+ }
+
+ IP_MASQ_ERR("unregister_ip_masq_mod(%s): not linked \n", mmod->mmod_name);
+ return -EINVAL;
+}
+
+int ip_masq_mod_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
+{
+ struct ip_masq_mod *mmod;
+ int ret = IP_MASQ_MOD_NOP;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_in_rule) continue;
+ switch (ret=mmod->mmod_in_rule(skb, iph)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ case IP_MASQ_MOD_REJECT:
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+int ip_masq_mod_out_rule(const struct sk_buff *skb, const struct iphdr *iph)
+{
+ struct ip_masq_mod *mmod;
+ int ret = IP_MASQ_MOD_NOP;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_out_rule) continue;
+ switch (ret=mmod->mmod_out_rule(skb, iph)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ case IP_MASQ_MOD_REJECT:
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+struct ip_masq * ip_masq_mod_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
+{
+ struct ip_masq_mod *mmod;
+ struct ip_masq *ms = NULL;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_in_create) continue;
+ if ((ms=mmod->mmod_in_create(skb, iph, maddr))) {
+ goto out;
+ }
+ }
+out:
+ return ms;
+}
+
+struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
+{
+ struct ip_masq_mod *mmod;
+ struct ip_masq *ms = NULL;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_out_create) continue;
+ if ((ms=mmod->mmod_out_create(skb, iph, maddr))) {
+ goto out;
+ }
+ }
+out:
+ return ms;
+}
+
+int ip_masq_mod_in_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
+{
+ struct ip_masq_mod *mmod;
+ int ret = IP_MASQ_MOD_NOP;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_in_update) continue;
+ switch (ret=mmod->mmod_in_update(skb, iph, ms)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ case IP_MASQ_MOD_REJECT:
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+int ip_masq_mod_out_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
+{
+ struct ip_masq_mod *mmod;
+ int ret = IP_MASQ_MOD_NOP;
+
+ for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
+ if (!mmod->mmod_out_update) continue;
+ switch (ret=mmod->mmod_out_update(skb, iph, ms)) {
+ case IP_MASQ_MOD_NOP:
+ continue;
+ case IP_MASQ_MOD_ACCEPT:
+ case IP_MASQ_MOD_REJECT:
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
+{
+ struct ip_masq_mod * mmod;
+
+ IP_MASQ_DEBUG(1, "searching mmod_name \"%s\"\n", mmod_name);
+
+ for (mmod=ip_masq_mod_reg_base; mmod ; mmod=mmod->next_reg) {
+ if (mmod->mmod_ctl && *(mmod_name)
+ && (strcmp(mmod_name, mmod->mmod_name)==0)) {
+ /* HIT */
+ return mmod;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Module control entry
+ */
+int ip_masq_mod_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+ struct ip_masq_mod * mmod;
+#ifdef CONFIG_KMOD
+ char kmod_name[IP_MASQ_TNAME_MAX+8];
+#endif
+ /* tappo */
+ mctl->m_tname[IP_MASQ_TNAME_MAX-1] = 0;
+
+ mmod = ip_masq_mod_getbyname(mctl->m_tname);
+ if (mmod)
+ return mmod->mmod_ctl(optname, mctl, optlen);
+#ifdef CONFIG_KMOD
+ sprintf(kmod_name,"ip_masq_%s", mctl->m_tname);
+
+ IP_MASQ_DEBUG(1, "About to request \"%s\" module\n", kmod_name);
+
+ /*
+ * Let sleep for a while ...
+ */
+ request_module(kmod_name);
+ mmod = ip_masq_mod_getbyname(mctl->m_tname);
+ if (mmod)
+ return mmod->mmod_ctl(optname, mctl, optlen);
+#endif
+ return ESRCH;
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_portfw.c b/pfinet/linux-src/net/ipv4/ip_masq_portfw.c
new file mode 100644
index 00000000..c4b1ef4c
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_portfw.c
@@ -0,0 +1,509 @@
+/*
+ * IP_MASQ_PORTFW masquerading module
+ *
+ *
+ * $Id: ip_masq_portfw.c,v 1.3.2.2 1999/08/13 18:26:29 davem Exp $
+ *
+ * Author: Steven Clarke <steven.clarke@monmouth.demon.co.uk>
+ *
+ * Fixes:
+ * Juan Jose Ciarlante : created this new file from ip_masq.c and ip_fw.c
+ * Juan Jose Ciarlante : modularized
+ * Juan Jose Ciarlante : use GFP_KERNEL
+ * Juan Jose Ciarlante : locking
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <net/ip.h>
+#include <linux/ip_fw.h>
+#include <linux/ip_masq.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#define IP_PORTFW_PORT_MIN 1
+#define IP_PORTFW_PORT_MAX 60999
+
+struct ip_portfw {
+ struct list_head list;
+ __u32 laddr, raddr;
+ __u16 lport, rport;
+ atomic_t pref_cnt; /* pref "counter" down to 0 */
+ int pref; /* user set pref */
+};
+
+static struct ip_masq_mod *mmod_self = NULL;
+/*
+ * Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+/*
+ * Lock
+ */
+static rwlock_t portfw_lock = RW_LOCK_UNLOCKED;
+
+static struct list_head portfw_list[2];
+static __inline__ int portfw_idx(int protocol)
+{
+ return (protocol==IPPROTO_TCP);
+}
+
+/*
+ *
+ * Delete forwarding entry(s):
+ * called from _DEL, u-space.
+ * . "relaxed" match, except for lport
+ *
+ */
+
+static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr)
+{
+ int prot = portfw_idx(protocol);
+ struct ip_portfw *n;
+ struct list_head *entry;
+ struct list_head *list = &portfw_list[prot];
+ int nent;
+
+ nent = atomic_read(&mmod_self->mmod_nent);
+
+ write_lock_bh(&portfw_lock);
+
+ for (entry=list->next;entry != list;entry = entry->next) {
+ n = list_entry(entry, struct ip_portfw, list);
+ if (n->lport == lport &&
+ (!laddr || n->laddr == laddr) &&
+ (!raddr || n->raddr == raddr) &&
+ (!rport || n->rport == rport)) {
+ entry = n->list.prev;
+ list_del(&n->list);
+ ip_masq_mod_dec_nent(mmod_self);
+ kfree_s(n, sizeof(struct ip_portfw));
+ MOD_DEC_USE_COUNT;
+ }
+ }
+ write_unlock_bh(&portfw_lock);
+
+ return nent==atomic_read(&mmod_self->mmod_nent)? ESRCH : 0;
+}
+
+/*
+ * Flush tables
+ * called from _FLUSH, u-space.
+ */
+static __inline__ void ip_portfw_flush(void)
+{
+ int prot;
+ struct list_head *l;
+ struct list_head *e;
+ struct ip_portfw *n;
+
+ write_lock_bh(&portfw_lock);
+
+ for (prot = 0; prot < 2;prot++) {
+ l = &portfw_list[prot];
+ while((e=l->next) != l) {
+ ip_masq_mod_dec_nent(mmod_self);
+ n = list_entry (e, struct ip_portfw, list);
+ list_del(e);
+ kfree_s(n, sizeof (*n));
+ MOD_DEC_USE_COUNT;
+ }
+ }
+
+ write_unlock_bh(&portfw_lock);
+}
+
+/*
+ * Lookup routine for lport,laddr match
+ * must be called with locked tables
+ */
+static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p)
+{
+ int prot = portfw_idx(protocol);
+
+ struct ip_portfw *n = NULL;
+ struct list_head *l, *e;
+
+ l = &portfw_list[prot];
+
+ for (e=l->next;e!=l;e=e->next) {
+ n = list_entry(e, struct ip_portfw, list);
+ if (lport == n->lport && laddr == n->laddr) {
+ /* Please be nice, don't pass only a NULL dport */
+ if (daddr_p) {
+ *daddr_p = n->raddr;
+ *dport_p = n->rport;
+ }
+
+ goto out;
+ }
+ }
+ n = NULL;
+out:
+ return n;
+}
+
+/*
+ * Edit routine for lport,[laddr], [raddr], [rport] match
+ * By now, only called from u-space
+ */
+static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
+{
+ int prot = portfw_idx(protocol);
+
+ struct ip_portfw *n = NULL;
+ struct list_head *l, *e;
+ int count = 0;
+
+
+ read_lock_bh(&portfw_lock);
+
+ l = &portfw_list[prot];
+
+ for (e=l->next;e!=l;e=e->next) {
+ n = list_entry(e, struct ip_portfw, list);
+ if (lport == n->lport &&
+ (!laddr || laddr == n->laddr) &&
+ (!rport || rport == n->rport) &&
+ (!raddr || raddr == n->raddr)) {
+ n->pref = pref;
+ atomic_set(&n->pref_cnt, pref);
+ count++;
+ }
+ }
+
+ read_unlock_bh(&portfw_lock);
+
+ return count;
+}
+
+/*
+ * Add/edit en entry
+ * called from _ADD, u-space.
+ * must return 0 or +errno
+ */
+static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)
+{
+ struct ip_portfw *npf;
+ int prot = portfw_idx(protocol);
+
+ if (pref <= 0)
+ return EINVAL;
+
+ if (ip_portfw_edit(protocol, lport, laddr, rport, raddr, pref)) {
+ /*
+ * Edit ok ...
+ */
+ return 0;
+ }
+
+ /* may block ... */
+ npf = (struct ip_portfw*) kmalloc(sizeof(struct ip_portfw), GFP_KERNEL);
+
+ if (!npf)
+ return ENOMEM;
+
+ MOD_INC_USE_COUNT;
+ memset(npf, 0, sizeof(*npf));
+
+ npf->laddr = laddr;
+ npf->lport = lport;
+ npf->rport = rport;
+ npf->raddr = raddr;
+ npf->pref = pref;
+
+ atomic_set(&npf->pref_cnt, npf->pref);
+ INIT_LIST_HEAD(&npf->list);
+
+ write_lock_bh(&portfw_lock);
+
+ /*
+ * Add at head
+ */
+ list_add(&npf->list, &portfw_list[prot]);
+
+ write_unlock_bh(&portfw_lock);
+
+ ip_masq_mod_inc_nent(mmod_self);
+ return 0;
+}
+
+
+
+static __inline__ int portfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+ struct ip_portfw_user *mm = &mctl->u.portfw_user;
+ int ret = EINVAL;
+ int arglen = optlen - IP_MASQ_CTL_BSIZE;
+ int cmd;
+
+
+ IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
+ arglen,
+ sizeof (*mm),
+ optlen,
+ sizeof (*mctl));
+
+ /*
+ * Yes, I'm a bad guy ...
+ */
+ if (arglen != sizeof(*mm) && optlen != sizeof(*mctl))
+ return EINVAL;
+
+ /*
+ * Don't trust the lusers - plenty of error checking!
+ */
+ cmd = mctl->m_cmd;
+ IP_MASQ_DEBUG(1-debug, "ip_masq_portfw_ctl(cmd=%d)\n", cmd);
+
+
+ switch (cmd) {
+ case IP_MASQ_CMD_NONE:
+ return 0;
+ case IP_MASQ_CMD_FLUSH:
+ break;
+ default:
+ if (htons(mm->lport) < IP_PORTFW_PORT_MIN || htons(mm->lport) > IP_PORTFW_PORT_MAX)
+ return EINVAL;
+
+ if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP)
+ return EINVAL;
+ }
+
+ switch(cmd) {
+ case IP_MASQ_CMD_ADD:
+ ret = ip_portfw_add(mm->protocol,
+ mm->lport, mm->laddr,
+ mm->rport, mm->raddr,
+ mm->pref);
+ break;
+
+ case IP_MASQ_CMD_DEL:
+ ret = ip_portfw_del(mm->protocol,
+ mm->lport, mm->laddr,
+ mm->rport, mm->raddr);
+ break;
+ case IP_MASQ_CMD_FLUSH:
+ ip_portfw_flush();
+ ret = 0;
+ break;
+ }
+
+
+ return ret;
+}
+
+
+
+
+#ifdef CONFIG_PROC_FS
+
+static int portfw_procinfo(char *buffer, char **start, off_t offset,
+ int length, int unused)
+{
+ off_t pos=0, begin;
+ struct ip_portfw *pf;
+ struct list_head *l, *e;
+ char temp[65];
+ int ind;
+ int len=0;
+
+
+ if (offset < 64)
+ {
+ sprintf(temp, "Prot LAddr LPort > RAddr RPort PrCnt Pref");
+ len = sprintf(buffer, "%-63s\n", temp);
+ }
+ pos = 64;
+
+ read_lock_bh(&portfw_lock);
+
+ for(ind = 0; ind < 2; ind++)
+ {
+ l = &portfw_list[ind];
+ for (e=l->next; e!=l; e=e->next)
+ {
+ pf = list_entry(e, struct ip_portfw, list);
+ pos += 64;
+ if (pos <= offset) {
+ len = 0;
+ continue;
+ }
+
+ sprintf(temp,"%s %08lX %5u > %08lX %5u %5d %5d",
+ ind ? "TCP" : "UDP",
+ ntohl(pf->laddr), ntohs(pf->lport),
+ ntohl(pf->raddr), ntohs(pf->rport),
+ atomic_read(&pf->pref_cnt), pf->pref);
+ len += sprintf(buffer+len, "%-63s\n", temp);
+
+ if (len >= length)
+ goto done;
+ }
+ }
+done:
+ read_unlock_bh(&portfw_lock);
+
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+ if(len>length)
+ len = length;
+ return len;
+}
+
+static struct proc_dir_entry portfw_proc_entry = {
+/* 0, 0, NULL", */
+ 0, 6, "portfw", /* Just for compatibility, for now ... */
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ portfw_procinfo
+};
+
+#define proc_ent &portfw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+static int portfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
+{
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+#ifdef CONFIG_IP_MASQ_DEBUG
+ struct rtable *rt = (struct rtable *)skb->dst;
+#endif
+ struct ip_portfw *pfw;
+
+ IP_MASQ_DEBUG(2, "portfw_in_rule(): skb:= dev=%s (index=%d), rt_iif=%d, rt_flags=0x%x rt_dev___=%s daddr=%d.%d.%d.%d dport=%d\n",
+ skb->dev->name, skb->dev->ifindex, rt->rt_iif, rt->rt_flags,
+ rt->u.dst.dev->name,
+ NIPQUAD(iph->daddr), ntohs(portp[1]));
+
+ read_lock(&portfw_lock);
+ pfw = ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL);
+ read_unlock(&portfw_lock);
+ return (pfw!=0);
+}
+
+static struct ip_masq * portfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
+{
+ /*
+ * If no entry exists in the masquerading table
+ * and the port is involved
+ * in port forwarding, create a new masq entry
+ */
+
+ __u32 raddr;
+ __u16 rport;
+ const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ struct ip_masq *ms = NULL;
+ struct ip_portfw *pf;
+
+ /*
+ * Lock for writing.
+ */
+ write_lock(&portfw_lock);
+
+ if ((pf=ip_portfw_lookup(iph->protocol,
+ portp[1], iph->daddr,
+ &raddr, &rport))) {
+ ms = ip_masq_new(iph->protocol,
+ iph->daddr, portp[1],
+ raddr, rport,
+ iph->saddr, portp[0],
+ 0);
+ if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1
+ /* || ip_masq_nlocks(&portfw_lock) != 1 */ )
+ /*
+ * Maybe later...
+ */
+ goto out;
+
+ ip_masq_listen(ms);
+
+ /*
+ * Entry created, lock==1.
+ * if pref_cnt == 0, move
+ * entry at _tail_.
+ * This is a simple load balance scheduling
+ */
+
+ if (atomic_dec_and_test(&pf->pref_cnt)) {
+
+ atomic_set(&pf->pref_cnt, pf->pref);
+ list_del(&pf->list);
+ list_add(&pf->list,
+ portfw_list[portfw_idx(iph->protocol)].prev);
+
+ }
+ }
+out:
+ write_unlock(&portfw_lock);
+ return ms;
+}
+
+#define portfw_in_update NULL
+#define portfw_out_rule NULL
+#define portfw_out_create NULL
+#define portfw_out_update NULL
+
+static struct ip_masq_mod portfw_mod = {
+ NULL, /* next */
+ NULL, /* next_reg */
+ "portfw", /* name */
+ ATOMIC_INIT(0), /* nent */
+ ATOMIC_INIT(0), /* refcnt */
+ proc_ent,
+ portfw_ctl,
+ NULL, /* masq_mod_init */
+ NULL, /* masq_mod_done */
+ portfw_in_rule,
+ portfw_in_update,
+ portfw_in_create,
+ portfw_out_rule,
+ portfw_out_update,
+ portfw_out_create,
+};
+
+
+
+__initfunc(int ip_portfw_init(void))
+{
+ INIT_LIST_HEAD(&portfw_list[0]);
+ INIT_LIST_HEAD(&portfw_list[1]);
+ return register_ip_masq_mod ((mmod_self=&portfw_mod));
+}
+
+int ip_portfw_done(void)
+{
+ return unregister_ip_masq_mod(&portfw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_portfw_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_portfw_done() != 0)
+ printk(KERN_INFO "ip_portfw_done(): can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_quake.c b/pfinet/linux-src/net/ipv4/ip_masq_quake.c
new file mode 100644
index 00000000..646348d1
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_quake.c
@@ -0,0 +1,322 @@
+/*
+ * IP_MASQ_QUAKE quake masquerading module
+ *
+ *
+ * Version: @(#)ip_masq_quake.c 0.02 22/02/97
+ *
+ * Author: Harald Hoyer mailto:HarryH@Royal.Net
+ *
+ *
+ * Fixes:
+ * Harald Hoyer : Unofficial Quake Specs found at
+ * http://www.gamers.org/dEngine/quake/spec/
+ * Harald Hoyer : Check for QUAKE-STRING
+ * Juan Jose Ciarlante : litl bits for 2.1
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/udp.h>
+#include <net/ip_masq.h>
+
+#define DEBUG_CONFIG_IP_MASQ_QUAKE 0
+
+typedef struct
+{
+ __u16 type; // (Little Endian) Type of message.
+ __u16 length; // (Little Endian) Length of message, header included.
+ char message[0]; // The contents of the message.
+} QUAKEHEADER;
+
+struct quake_priv_data {
+ /* Have we seen a client connect message */
+ signed char cl_connect;
+};
+
+static int
+masq_quake_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ if ((ms->app_data = kmalloc(sizeof(struct quake_priv_data),
+ GFP_ATOMIC)) == NULL)
+ printk(KERN_INFO "Quake: No memory for application data\n");
+ else
+ {
+ struct quake_priv_data *priv =
+ (struct quake_priv_data *)ms->app_data;
+ priv->cl_connect = 0;
+ }
+ return 0;
+}
+
+static int
+masq_quake_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ if (ms->app_data)
+ kfree_s(ms->app_data, sizeof(struct quake_priv_data));
+ return 0;
+}
+
+int
+masq_quake_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct udphdr *uh;
+ QUAKEHEADER *qh;
+ __u16 udp_port;
+ char *data;
+ unsigned char code;
+ struct quake_priv_data *priv = (struct quake_priv_data *)ms->app_data;
+
+ if(priv->cl_connect == -1)
+ return 0;
+
+ skb = *skb_p;
+
+ iph = skb->nh.iph;
+ uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+
+ /* Check for length */
+ if(ntohs(uh->len) < 5)
+ return 0;
+
+ qh = (QUAKEHEADER *)&uh[1];
+
+ if(qh->type != 0x0080)
+ return 0;
+
+
+ code = qh->message[0];
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_in: code = %d \n", (int)code);
+#endif
+
+ switch(code) {
+ case 0x01:
+ /* Connection Request */
+
+ if(ntohs(qh->length) < 0x0c) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_in: length < 0xc \n");
+#endif
+ return 0;
+ }
+
+ data = &qh->message[1];
+
+ /* Check for stomping string */
+ if(memcmp(data,"QUAKE\0\3",7)) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: memcmp failed \n");
+#endif
+ return 0;
+ }
+ else {
+ priv->cl_connect = 1;
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: memcmp ok \n");
+#endif
+ }
+ break;
+
+ case 0x81:
+ /* Accept Connection */
+ if((ntohs(qh->length) < 0x09) || (priv->cl_connect == 0))
+ return 0;
+ data = &qh->message[1];
+
+ memcpy(&udp_port, data, 2);
+
+ ms->dport = htons(udp_port);
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_in: in_rewrote UDP port %d \n", udp_port);
+#endif
+ priv->cl_connect = -1;
+
+ break;
+ }
+
+ return 0;
+}
+
+int
+masq_quake_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct udphdr *uh;
+ QUAKEHEADER *qh;
+ __u16 udp_port;
+ char *data;
+ unsigned char code;
+ struct ip_masq *n_ms;
+ struct quake_priv_data *priv = (struct quake_priv_data *)ms->app_data;
+
+ if(priv->cl_connect == -1)
+ return 0;
+
+ skb = *skb_p;
+
+ iph = skb->nh.iph;
+ uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+
+ /* Check for length */
+ if(ntohs(uh->len) < 5)
+ return 0;
+
+ qh = (QUAKEHEADER *)&uh[1];
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: qh->type = %d \n", (int)qh->type);
+#endif
+
+ if(qh->type != 0x0080)
+ return 0;
+
+ code = qh->message[0];
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: code = %d \n", (int)code);
+#endif
+
+ switch(code) {
+ case 0x01:
+ /* Connection Request */
+
+ if(ntohs(qh->length) < 0x0c) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: length < 0xc \n");
+#endif
+ return 0;
+ }
+
+ data = &qh->message[1];
+
+ /* Check for stomping string */
+ if(memcmp(data,"QUAKE\0\3",7)) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: memcmp failed \n");
+#endif
+ return 0;
+ }
+ else {
+ priv->cl_connect = 1;
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: memcmp ok \n");
+#endif
+ }
+ break;
+
+ case 0x81:
+ /* Accept Connection */
+ if((ntohs(qh->length) < 0x09) || (priv->cl_connect == 0))
+ return 0;
+
+ data = &qh->message[1];
+
+ memcpy(&udp_port, data, 2);
+
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, htons(udp_port),
+ ms->daddr, ms->dport,
+ 0);
+
+ if (n_ms==NULL)
+ return 0;
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+ printk("Quake_out: out_rewrote UDP port %d -> %d\n",
+ udp_port, ntohs(n_ms->mport));
+#endif
+ udp_port = ntohs(n_ms->mport);
+ memcpy(data, &udp_port, 2);
+
+ ip_masq_listen(n_ms);
+ ip_masq_control_add(n_ms, ms);
+ ip_masq_put(n_ms);
+
+ break;
+ }
+
+ return 0;
+}
+
+struct ip_masq_app ip_masq_quake = {
+ NULL, /* next */
+ "Quake_26", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_quake_init_1, /* ip_masq_init_1 */
+ masq_quake_done_1, /* ip_masq_done_1 */
+ masq_quake_out, /* pkt_out */
+ masq_quake_in /* pkt_in */
+};
+struct ip_masq_app ip_masq_quakenew = {
+ NULL, /* next */
+ "Quake_27", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_quake_init_1, /* ip_masq_init_1 */
+ masq_quake_done_1, /* ip_masq_done_1 */
+ masq_quake_out, /* pkt_out */
+ masq_quake_in /* pkt_in */
+};
+
+/*
+ * ip_masq_quake initialization
+ */
+
+__initfunc(int ip_masq_quake_init(void))
+{
+ return (register_ip_masq_app(&ip_masq_quake, IPPROTO_UDP, 26000) +
+ register_ip_masq_app(&ip_masq_quakenew, IPPROTO_UDP, 27000));
+}
+
+/*
+ * ip_masq_quake fin.
+ */
+
+int ip_masq_quake_done(void)
+{
+ return (unregister_ip_masq_app(&ip_masq_quake) +
+ unregister_ip_masq_app(&ip_masq_quakenew));
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_quake_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_quake_done() != 0)
+ printk("ip_masq_quake: can't remove module");
+}
+
+#endif /* MODULE */
+
+
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_raudio.c b/pfinet/linux-src/net/ipv4/ip_masq_raudio.c
new file mode 100644
index 00000000..ee3e276b
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_raudio.c
@@ -0,0 +1,578 @@
+/*
+ * IP_MASQ_RAUDIO - Real Audio masquerading module
+ *
+ *
+ * Version: @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $
+ *
+ * Author: Nigel Metheringham
+ * Real Time Streaming code by Progressive Networks
+ * [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
+ * [Real Audio information taken from Progressive Networks firewall docs]
+ * [Kudos to Progressive Networks for making the protocol specs available]
+ *
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Limitations
+ * The IP Masquerading proxies at present do not have access to a processed
+ * data stream. Hence for a protocol like the Real Audio control protocol,
+ * which depends on knowing where you are in the data stream, you either
+ * to keep a *lot* of state in your proxy, or you cheat and simplify the
+ * problem [needless to say I did the latter].
+ *
+ * This proxy only handles data in the first packet. Everything else is
+ * passed transparently. This means it should work under all normal
+ * circumstances, but it could be fooled by new data formats or a
+ * malicious application!
+ *
+ * At present the "first packet" is defined as a packet starting with
+ * the protocol ID string - "PNA".
+ * When the link is up there appears to be enough control data
+ * crossing the control link to keep it open even if a long audio
+ * piece is playing.
+ *
+ * The Robust UDP support added in RealAudio 3.0 is supported, but due
+ * to servers/clients not making great use of this has not been greatly
+ * tested. RealVideo (as used in the Real client version 4.0beta1) is
+ * supported but again is not greatly tested (bandwidth requirements
+ * appear to exceed that available at the sites supporting the protocol).
+ *
+ * Multiple Port Support
+ * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
+ * with the port numbers being defined at module load time. The module
+ * uses the symbol "ports" to define a list of monitored ports, which can
+ * be specified on the insmod command line as
+ * ports=x1,x2,x3...
+ * where x[n] are integer port numbers. This option can be put into
+ * /etc/conf.modules (or /etc/modules.conf depending on your config)
+ * where modload will pick it up should you use modload to load your
+ * modules.
+ *
+ * Fixes:
+ * Juan Jose Ciarlante : Use control_add() for control chan
+ * 10/15/97 - Modifications to allow masquerading of RTSP connections as
+ * well as PNA, which can potentially exist on the same port.
+ * Joe Rumsey <ogre@real.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+/*
+#ifndef DEBUG_CONFIG_IP_MASQ_RAUDIO
+#define DEBUG_CONFIG_IP_MASQ_RAUDIO 0
+#endif
+*/
+
+#define TOLOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 'a') : (c))
+#define ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
+
+struct raudio_priv_data {
+ /* Associated data connection - setup but not used at present */
+ struct ip_masq *data_conn;
+ /* UDP Error correction connection - setup but not used at present */
+ struct ip_masq *error_conn;
+ /* Have we seen and performed setup */
+ short seen_start;
+ short is_rtsp;
+};
+
+int
+masq_rtsp_out (struct ip_masq_app *mapp,
+ struct ip_masq *ms,
+ struct sk_buff **skb_p,
+ __u32 maddr);
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+int ports[MAX_MASQ_APP_PORTS] = {554, 7070, 0}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+
+
+static int
+masq_raudio_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ if ((ms->app_data = kmalloc(sizeof(struct raudio_priv_data),
+ GFP_ATOMIC)) == NULL)
+ printk(KERN_INFO "RealAudio: No memory for application data\n");
+ else
+ {
+ struct raudio_priv_data *priv =
+ (struct raudio_priv_data *)ms->app_data;
+ priv->seen_start = 0;
+ priv->data_conn = NULL;
+ priv->error_conn = NULL;
+ priv->is_rtsp = 0;
+ }
+ return 0;
+}
+
+static int
+masq_raudio_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ if (ms->app_data)
+ kfree_s(ms->app_data, sizeof(struct raudio_priv_data));
+ return 0;
+}
+
+int
+masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *p, *data, *data_limit;
+ struct ip_masq *n_ms;
+ unsigned short version, msg_id, msg_len, udp_port;
+ struct raudio_priv_data *priv =
+ (struct raudio_priv_data *)ms->app_data;
+
+ /* Everything running correctly already */
+ if (priv && priv->seen_start)
+ return 0;
+
+ if(priv && priv->is_rtsp)
+ return masq_rtsp_out(mapp, ms, skb_p, maddr);
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ data_limit = skb->h.raw + skb->len;
+
+ if(memcmp(data, "OPTIONS", 7) == 0 ||
+ memcmp(data, "DESCRIBE", 8) == 0)
+ {
+ IP_MASQ_DEBUG(1-debug, "RealAudio: Detected RTSP connection\n");
+ /* This is an RTSP client */
+ if(priv)
+ priv->is_rtsp = 1;
+ return masq_rtsp_out(mapp, ms, skb_p, maddr);
+ }
+
+ /* Check to see if this is the first packet with protocol ID */
+ if (memcmp(data, "PNA", 3)) {
+ IP_MASQ_DEBUG(1-debug, "RealAudio: not initial protocol packet - ignored\n");
+ return(0);
+ }
+ data += 3;
+ memcpy(&version, data, 2);
+
+ IP_MASQ_DEBUG(1-debug, "RealAudio: initial seen - protocol version %d\n",
+ ntohs(version));
+ if (priv)
+ priv->seen_start = 1;
+
+ if (ntohs(version) >= 256)
+ {
+ printk(KERN_INFO "RealAudio: version (%d) not supported\n",
+ ntohs(version));
+ return 0;
+ }
+
+ data += 2;
+ while (data+4 < data_limit) {
+ memcpy(&msg_id, data, 2);
+ data += 2;
+ memcpy(&msg_len, data, 2);
+ data += 2;
+ if (ntohs(msg_id) == 0) {
+ /* The zero tag indicates the end of options */
+ IP_MASQ_DEBUG(1-debug, "RealAudio: packet end tag seen\n");
+ return 0;
+ }
+ IP_MASQ_DEBUG(1-debug, "RealAudio: msg %d - %d byte\n",
+ ntohs(msg_id), ntohs(msg_len));
+ if (ntohs(msg_id) == 0) {
+ /* The zero tag indicates the end of options */
+ return 0;
+ }
+ p = data;
+ data += ntohs(msg_len);
+ if (data > data_limit)
+ {
+ printk(KERN_INFO "RealAudio: Packet too short for data\n");
+ return 0;
+ }
+ if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) {
+ /*
+ * MsgId == 1
+ * Audio UDP data port on client
+ *
+ * MsgId == 7
+ * Robust UDP error correction port number on client
+ *
+ * Since these messages are treated just the same, they
+ * are bundled together here....
+ */
+ memcpy(&udp_port, p, 2);
+
+ /*
+ * Sometimes a server sends a message 7 with a zero UDP port
+ * Rather than do anything with this, just ignore it!
+ */
+ if (udp_port == 0)
+ continue;
+
+
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, udp_port,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+
+ if (n_ms==NULL)
+ return 0;
+
+ ip_masq_listen(n_ms);
+ ip_masq_control_add(n_ms, ms);
+
+ memcpy(p, &(n_ms->mport), 2);
+ IP_MASQ_DEBUG(1-debug, "RealAudio: rewrote UDP port %d -> %d in msg %d\n",
+ ntohs(udp_port), ntohs(n_ms->mport), ntohs(msg_id));
+
+ /* Make ref in application data to data connection */
+ if (priv) {
+ if (ntohs(msg_id) == 1)
+ priv->data_conn = n_ms;
+ else
+ priv->error_conn = n_ms;
+ }
+
+ ip_masq_put(n_ms);
+ }
+ }
+ return 0;
+}
+
+/*
+ * masq_rtsp_out
+ *
+ *
+ */
+int
+masq_rtsp_out (struct ip_masq_app *mapp,
+ struct ip_masq *ms,
+ struct sk_buff **skb_p,
+ __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *data, *data_limit;
+ struct ip_masq *n_ms, *n_ms2;
+ unsigned short udp_port;
+ struct raudio_priv_data *priv =
+ (struct raudio_priv_data *)ms->app_data;
+ const char* srch = "transport:";
+ const char* srchpos = srch;
+ const char* srchend = srch + strlen(srch);
+ int state = 0;
+ char firstport[6];
+ int firstportpos = 0;
+ char secondport[6];
+ int secondportpos = 0;
+ char *portstart = NULL, *portend = NULL;
+ int diff;
+
+ /* Everything running correctly already */
+ if (priv && priv->seen_start)
+ return 0;
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ data_limit = skb->h.raw + skb->len;
+
+ firstport[0] = 0;
+ secondport[0] = 0;
+
+ while(data < data_limit && state >= 0)
+ {
+ switch(state)
+ {
+ case 0:
+ case 1:
+ if(TOLOWER(*data) == *srchpos)
+ {
+ srchpos++;
+ if(srchpos == srchend)
+ {
+ IP_MASQ_DEBUG(1-debug, "Found string %s in message\n",
+ srch);
+ state++;
+ if(state == 1)
+ {
+ srch = "client_port";
+ srchpos = srch;
+ srchend = srch + strlen(srch);
+ }
+ }
+ }
+ else
+ {
+ srchpos = srch;
+ }
+ break;
+ case 2:
+ if(*data == '=')
+ state = 3;
+ break;
+ case 3:
+ if(ISDIGIT(*data))
+ {
+ portstart = data;
+ firstportpos = 0;
+ firstport[firstportpos++] = *data;
+ state = 4;
+ }
+ break;
+ case 4:
+ if(*data == '-')
+ {
+ state = 5;
+ }
+ else if(*data == ';')
+ {
+ portend = data - 1;
+ firstport[firstportpos] = 0;
+ state = -1;
+ }
+ else if(ISDIGIT(*data))
+ {
+ firstport[firstportpos++] = *data;
+ }
+ else if(*data != ' ' && *data != '\t')
+ {
+ /* This is a badly formed RTSP message, let's bail out */
+ IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
+ return 0;
+ }
+ break;
+ case 5:
+ if(ISDIGIT(*data))
+ {
+ secondportpos = 0;
+ secondport[secondportpos++] = *data;
+ state = 6;
+ }
+ else if(*data == ';')
+ {
+ portend = data - 1;
+ secondport[secondportpos] = 0;
+ state = -1;
+ }
+ break;
+ case 6:
+ if(*data == ';')
+ {
+ portend = data - 1;
+ secondport[secondportpos] = 0;
+ state = -1;
+ }
+ else if(ISDIGIT(*data))
+ {
+ secondport[secondportpos++] = *data;
+ }
+ else if(*data != ' ' && *data != '\t')
+ {
+ /* This is a badly formed RTSP message, let's bail out */
+ IP_MASQ_DEBUG(1-debug, "Badly formed RTSP Message\n");
+ return 0;
+ }
+ break;
+ }
+ data++;
+ }
+
+ if(state >= 0)
+ return 0;
+
+ if(firstportpos > 0)
+ {
+ char newbuf[12]; /* xxxxx-xxxxx\0 */
+ char* tmpptr;
+
+ udp_port = htons(simple_strtoul(firstport, &tmpptr, 10));
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, udp_port,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+ if (n_ms==NULL)
+ return 0;
+
+ ip_masq_listen(n_ms);
+ ip_masq_control_add(n_ms, ms);
+
+ if(secondportpos > 0)
+ {
+ udp_port = htons(simple_strtoul(secondport, &tmpptr, 10));
+ n_ms2 = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, udp_port,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+ if (n_ms2==NULL) {
+ ip_masq_put(n_ms);
+ return 0;
+ }
+
+ ip_masq_listen(n_ms2);
+ ip_masq_control_add(n_ms2, ms);
+ sprintf(newbuf, "%d-%d", ntohs(n_ms->mport),
+ ntohs(n_ms2->mport));
+ }
+ else
+ {
+ sprintf(newbuf, "%d", ntohs(n_ms->mport));
+ n_ms2 = NULL;
+ }
+ *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+ portstart, portend - portstart + 1,
+ newbuf, strlen(newbuf));
+ IP_MASQ_DEBUG(1-debug, "RTSP: rewrote client_port to %s\n", newbuf);
+ diff = strlen(newbuf) - (portend - portstart);
+ }
+ else
+ {
+ return 0;
+ }
+
+ if(priv)
+ {
+ priv->seen_start = 1;
+ if(n_ms)
+ priv->data_conn = n_ms;
+ if(n_ms2)
+ priv->error_conn = n_ms2;
+ }
+ /*
+ * Release tunnels
+ */
+
+ if (n_ms)
+ ip_masq_put(n_ms);
+
+ if (n_ms2)
+ ip_masq_put(n_ms2);
+
+ return diff;
+}
+
+struct ip_masq_app ip_masq_raudio = {
+ NULL, /* next */
+ "RealAudio", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_raudio_init_1, /* ip_masq_init_1 */
+ masq_raudio_done_1, /* ip_masq_done_1 */
+ masq_raudio_out, /* pkt_out */
+ NULL /* pkt_in */
+};
+
+/*
+ * ip_masq_raudio initialization
+ */
+
+__initfunc(int ip_masq_raudio_init(void))
+{
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_raudio, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n",
+ i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ip_masq_raudio fin.
+ */
+
+int ip_masq_raudio_done(void)
+{
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug, "RealAudio: unloaded support on port[%d] = %d\n",
+ i, ports[i]);
+ }
+ }
+ }
+ return k;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_raudio_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_raudio_done() != 0)
+ printk(KERN_INFO "ip_masq_raudio: can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_user.c b/pfinet/linux-src/net/ipv4/ip_masq_user.c
new file mode 100644
index 00000000..848cbfe8
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_user.c
@@ -0,0 +1,473 @@
+/*
+ * IP_MASQ_USER user space control module
+ *
+ *
+ * $Id: ip_masq_user.c,v 1.1.2.3 1999/11/16 06:33:51 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/inet.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/checksum.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/sysctl.h>
+#include <linux/ip_fw.h>
+
+#include <linux/ip_masq.h>
+
+/*
+ * Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+/*
+static int check_5uple (struct ip_masq_user *ums) {
+ return 0;
+}
+*/
+static void masq_user_k2u(const struct ip_masq *ms, struct ip_masq_user *ums)
+{
+ ums->protocol = ms->protocol;
+ ums->daddr = ms->daddr;
+ ums->dport = ms->dport;
+ ums->maddr = ms->maddr;
+ ums->mport = ms->mport;
+ ums->saddr = ms->saddr;
+ ums->sport = ms->sport;
+ ums->timeout = ms->timeout;
+}
+
+
+static int ip_masq_user_maddr(struct ip_masq_user *ums)
+{
+ struct device *dev;
+ struct rtable *rt;
+ int ret = -EINVAL;
+ u32 rt_daddr, rt_saddr;
+ u32 tos;
+
+ /*
+ * Did specify masq address.
+ */
+ if (ums->maddr)
+ return 0;
+
+ /*
+ * Select address to use for routing query
+ */
+
+ rt_daddr = ums->rt_daddr? ums->rt_daddr : ums->daddr;
+ rt_saddr = ums->rt_saddr? ums->rt_saddr : ums->saddr;
+
+
+ /*
+ * No address for routing, cannot continue
+ */
+ if (rt_daddr == 0) {
+ IP_MASQ_DEBUG(1-debug, "cannot setup maddr with daddr=%lX, rt_addr=%lX\n",
+ ntohl(ums->daddr), ntohl(ums->rt_daddr));
+ return -EINVAL;
+ }
+
+ /*
+ * Find out rt device
+ */
+
+ rt_saddr = 0;
+ tos = RT_TOS(ums->ip_tos) | RTO_CONN;
+
+ if ((ret=ip_route_output(&rt, rt_daddr, rt_saddr, tos, 0 /* dev */))) {
+ IP_MASQ_DEBUG(0-debug, "could not setup maddr for routing daddr=%lX, saddr=%lX\n",
+ ntohl(rt_daddr), ntohl(rt_saddr));
+ return ret;
+ }
+ dev = rt->u.dst.dev;
+ ums->maddr = rt->rt_src; /* Per Alexey */
+
+ IP_MASQ_DEBUG(1-debug, "did setup maddr=%lX\n", ntohl(ums->maddr));
+ ip_rt_put(rt);
+ return 0;
+}
+
+/*
+ * Create new entry (from uspace)
+ */
+static int ip_masq_user_new(struct ip_masq_user *ums)
+{
+ struct ip_masq *ms = NULL;
+ unsigned mflags = 0;
+ int ret;
+
+ if (masq_proto_num (ums->protocol) == -1) {
+ return EPROTONOSUPPORT;
+ }
+
+ if (ums->dport == 0) {
+ ums->flags |= IP_MASQ_USER_F_LISTEN;
+ }
+
+ if (ums->flags | IP_MASQ_USER_F_LISTEN) {
+ if ((ums->saddr == 0) || (ums->sport == 0)) {
+ return EINVAL;
+ }
+ mflags |= (IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+
+ }
+
+ if ((ret = ip_masq_user_maddr(ums)) < 0) {
+ return -ret;
+ }
+
+ mflags |= IP_MASQ_F_USER;
+ ms = ip_masq_new(ums->protocol,
+ ums->maddr, ums->mport,
+ ums->saddr, ums->sport,
+ ums->daddr, ums->dport,
+ mflags);
+
+ if (ms == NULL) {
+ /*
+ * FIXME: ip_masq_new() should return errno
+ */
+ return EBUSY;
+ }
+
+ /*
+ * Setup timeouts for this new entry
+ */
+
+ if (ums->timeout) {
+ ms->timeout = ums->timeout;
+ } else if (ums->flags | IP_MASQ_USER_F_LISTEN) {
+ ip_masq_listen(ms);
+ }
+
+ masq_user_k2u(ms, ums);
+ ip_masq_put(ms);
+ return 0;
+}
+
+/*
+ * Delete existing entry
+ */
+static int ip_masq_user_del(struct ip_masq_user *ums)
+{
+ struct ip_masq *ms=NULL;
+
+ if (masq_proto_num (ums->protocol) == -1) {
+ return EPROTONOSUPPORT;
+ }
+ start_bh_atomic();
+ if (ums->mport && ums->maddr) {
+ ms = ip_masq_in_get(ums->protocol,
+ ums->daddr, ums->dport,
+ ums->maddr, ums->mport);
+ end_bh_atomic();
+ } else if (ums->sport && ums->saddr) {
+ ms = ip_masq_out_get(ums->protocol,
+ ums->saddr, ums->sport,
+ ums->daddr, ums->dport);
+ end_bh_atomic();
+ } else
+ return EINVAL;
+
+ if (ms == NULL) {
+ return ESRCH;
+ }
+
+ /*
+ * got (locked) entry, setup almost tiny timeout :) and
+ * give away
+ *
+ * FIXME: should use something better than S_CLOSE
+ */
+ ms->timeout = IP_MASQ_S_CLOSE;
+
+ masq_user_k2u(ms, ums);
+ ip_masq_put(ms);
+ return 0;
+}
+
+static struct ip_masq * ip_masq_user_locked_get (struct ip_masq_user *ums, int *err)
+{
+ struct ip_masq *ms=NULL;
+ if (masq_proto_num (ums->protocol) == -1) {
+ *err = EPROTONOSUPPORT;
+ }
+
+ start_bh_atomic();
+ if (ums->mport && ums->maddr) {
+ ms = ip_masq_in_get(ums->protocol,
+ ums->daddr, ums->dport,
+ ums->maddr, ums->mport);
+ end_bh_atomic();
+ } else if (ums->sport && ums->saddr) {
+ ms = ip_masq_out_get(ums->protocol,
+ ums->saddr, ums->sport,
+ ums->daddr, ums->dport);
+ end_bh_atomic();
+ } else
+ *err = EINVAL;
+
+ if (ms == NULL) *err = ESRCH;
+ return ms;
+}
+
+/*
+ * Get existing entry (complete full tunnel info)
+ */
+static int ip_masq_user_get(struct ip_masq_user *ums)
+{
+ struct ip_masq *ms=NULL;
+ int err;
+
+ ms = ip_masq_user_locked_get(ums, &err);
+ if (ms == NULL)
+ return err;
+
+ masq_user_k2u(ms, ums);
+
+ ip_masq_put(ms);
+ return 0;
+}
+
+/*
+ * Set (some, valid) entry parameters
+ */
+static int ip_masq_user_set(struct ip_masq_user *ums)
+{
+ struct ip_masq *ms = NULL;
+ int err;
+
+ ms = ip_masq_user_locked_get(ums, &err);
+ if (ms == NULL)
+ return err;
+
+ /*
+ * FIXME: must allow selecting what you want to set
+ */
+ ms->timeout = ums->timeout;
+
+ masq_user_k2u(ms, ums);
+
+ ip_masq_put(ms);
+ return 0;
+}
+
+
+/*
+ * Entry point
+ * ret value:
+ * <0 err
+ * ==0 ok
+ * >0 ok, copy to user
+ */
+static int ip_masq_user_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+ struct ip_masq_user *ums = &mctl->u.user;
+ int ret = EINVAL;
+ int arglen = optlen - IP_MASQ_CTL_BSIZE;
+ int cmd;
+
+ IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
+ arglen,
+ sizeof (*ums),
+ optlen,
+ sizeof (*mctl));
+
+ /*
+ * Yes, I'm a bad guy ...
+ */
+ if (arglen != sizeof(*ums) && optlen != sizeof(*mctl))
+ return EINVAL;
+
+ MOD_INC_USE_COUNT;
+
+ /*
+ * Don't trust the lusers - plenty of error checking!
+ */
+ cmd = mctl->m_cmd;
+ IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(cmd=%d)\n", cmd);
+
+ switch (mctl->m_cmd) {
+ case IP_MASQ_CMD_ADD:
+ case IP_MASQ_CMD_INSERT:
+ ret = ip_masq_user_new(ums);
+ break;
+ case IP_MASQ_CMD_DEL:
+ ret = ip_masq_user_del(ums);
+ break;
+ case IP_MASQ_CMD_SET:
+ ret = ip_masq_user_set(ums);
+ break;
+ case IP_MASQ_CMD_GET:
+ ret = ip_masq_user_get(ums);
+ break;
+ }
+
+ /*
+ * For all of the above, return masq tunnel info
+ */
+
+ ret = -ret;
+
+ if (ret == 0) {
+ ret = sizeof (*ums) + IP_MASQ_CTL_BSIZE;
+ IP_MASQ_DEBUG(1-debug, "will return %d bytes to user\n", ret);
+ }
+
+ MOD_DEC_USE_COUNT;
+ return ret;
+}
+
+
+#ifdef CONFIG_PROC_FS
+static int ip_masq_user_info(char *buffer, char **start, off_t offset,
+ int length, int proto)
+{
+ off_t pos=0, begin;
+ struct ip_masq *ms;
+ char temp[129];
+ int idx = 0;
+ int col;
+ int len=0;
+ int magic_control;
+ struct list_head *l,*e;
+
+ MOD_INC_USE_COUNT;
+
+ IP_MASQ_DEBUG(1-debug, "Entered user_info with proto=%d\n", proto);
+
+ if (offset < 128)
+ {
+ sprintf(temp,
+ "Prot SrcIP SPrt DstIP DPrt MAddr MPrt State Flgs Ref Ctl Expires HRow HCol (free=%d,%d,%d)",
+ atomic_read(ip_masq_free_ports),
+ atomic_read(ip_masq_free_ports+1),
+ atomic_read(ip_masq_free_ports+2));
+ len = sprintf(buffer, "%-127s\n", temp);
+ }
+ pos = 128;
+
+ for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+ {
+ /*
+ * Lock is actually only need in next loop
+ * we are called from uspace: must stop bh.
+ */
+ col=0;
+ read_lock_bh(&__ip_masq_lock);
+ l = &ip_masq_m_table[idx];
+ for (e=l->next; e!=l; e=e->next) {
+ col++;
+ ms = list_entry(e, struct ip_masq, m_list);
+ if (ms->protocol != proto) {
+ continue;
+ }
+
+ pos += 128;
+ if (pos <= offset) {
+ len = 0;
+ continue;
+ }
+
+ /*
+ * We have locked the tables, no need to del/add timers
+ * nor cli() 8)
+ */
+
+
+ magic_control = atomic_read(&ms->n_control);
+ if (!magic_control && ms->control) magic_control = -1;
+ sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3X %4d %3d %7lu %4d %4d",
+ masq_proto_name(ms->protocol),
+ ntohl(ms->saddr), ntohs(ms->sport),
+ ntohl(ms->daddr), ntohs(ms->dport),
+ ntohl(ms->maddr), ntohs(ms->mport),
+ ip_masq_state_name(ms->state),
+ ms->flags,
+ atomic_read(&ms->refcnt),
+ magic_control,
+ (ms->timer.expires-jiffies)/HZ,
+ idx, col);
+ len += sprintf(buffer+len, "%-127s\n", temp);
+
+ if(len >= length) {
+ read_unlock_bh(&__ip_masq_lock);
+ goto done;
+ }
+ }
+ read_unlock_bh(&__ip_masq_lock);
+ }
+
+done:
+
+ if (len) {
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
+ }
+ if(len>length)
+ len = length;
+ MOD_DEC_USE_COUNT;
+ return len;
+}
+#else
+#define ip_masq_user_info NULL
+#endif
+
+static struct ip_masq_hook ip_masq_user = {
+ ip_masq_user_ctl,
+ ip_masq_user_info
+};
+
+int ip_masq_user_init(void)
+{
+ if (ip_masq_user_hook != NULL)
+ return -EEXIST;
+ ip_masq_user_hook = &ip_masq_user;
+ return 0;
+}
+
+int ip_masq_user_done(void)
+{
+ if (ip_masq_user_hook == NULL)
+ return ENOENT;
+ ip_masq_user_hook = NULL;
+ return 0;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+int init_module(void)
+{
+ if (ip_masq_user_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_user_done() != 0)
+ printk(KERN_INFO "ip_masq_user_done(): can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_masq_vdolive.c b/pfinet/linux-src/net/ipv4/ip_masq_vdolive.c
new file mode 100644
index 00000000..4724e3b9
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_masq_vdolive.c
@@ -0,0 +1,294 @@
+/*
+ * IP_MASQ_VDOLIVE - VDO Live masquerading module
+ *
+ *
+ * Version: @(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $
+ *
+ * Author: Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
+ * PLAnet Online Ltd
+ *
+ * Fixes: Minor changes for 2.1 by
+ * Steven Clarke <Steven.Clarke@ThePlanet.Net>, Planet Online Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Thanks:
+ * Thank you to VDOnet Corporation for allowing me access to
+ * a protocol description without an NDA. This means that
+ * this module can be distributed as source - a great help!
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+struct vdolive_priv_data {
+ /* Ports used */
+ unsigned short origport;
+ unsigned short masqport;
+ /* State of decode */
+ unsigned short state;
+};
+
+/*
+ * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
+ * First port is set to the default port.
+ */
+static int ports[MAX_MASQ_APP_PORTS] = {7000}; /* I rely on the trailing items being set to zero */
+struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+
+/*
+ * Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+
+static int
+masq_vdolive_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ if ((ms->app_data = kmalloc(sizeof(struct vdolive_priv_data),
+ GFP_ATOMIC)) == NULL)
+ IP_MASQ_DEBUG(1-debug, "VDOlive: No memory for application data\n");
+ else
+ {
+ struct vdolive_priv_data *priv =
+ (struct vdolive_priv_data *)ms->app_data;
+ priv->origport = 0;
+ priv->masqport = 0;
+ priv->state = 0;
+ }
+ return 0;
+}
+
+static int
+masq_vdolive_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ if (ms->app_data)
+ kfree_s(ms->app_data, sizeof(struct vdolive_priv_data));
+ return 0;
+}
+
+int
+masq_vdolive_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *data, *data_limit;
+ unsigned int tagval; /* This should be a 32 bit quantity */
+ struct ip_masq *n_ms;
+ struct vdolive_priv_data *priv =
+ (struct vdolive_priv_data *)ms->app_data;
+
+ /* This doesn't work at all if no priv data was allocated on startup */
+ if (!priv)
+ return 0;
+
+ /* Everything running correctly already */
+ if (priv->state == 3)
+ return 0;
+
+ skb = *skb_p;
+ iph = skb->nh.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ data_limit = skb->h.raw + skb->len;
+
+ if (data+8 > data_limit) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: packet too short for ID %p %p\n", data, data_limit);
+ return 0;
+ }
+ memcpy(&tagval, data+4, 4);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
+
+ /* Check for leading packet ID */
+ if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
+ return 0;
+ }
+
+
+ /* Check packet is long enough for data - ignore if not */
+ if ((ntohl(tagval) == 6) && (data+36 > data_limit)) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet too short %p %p\n", data, data_limit);
+ return 0;
+ } else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) {
+ IP_MASQ_DEBUG(1-debug,"VDOlive: secondary packet too short %p %p\n", data, data_limit);
+ return 0;
+ }
+
+ /* Adjust data pointers */
+ /*
+ * I could check the complete protocol version tag
+ * in here however I am just going to look for the
+ * "VDO Live" tag in the hope that this part will
+ * remain constant even if the version changes
+ */
+ if (ntohl(tagval) == 6) {
+ data += 24;
+ IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet found\n");
+ } else {
+ data += 8;
+ IP_MASQ_DEBUG(1-debug, "VDOlive: secondary packet found\n");
+ }
+
+ if (memcmp(data, "VDO Live", 8) != 0) {
+ IP_MASQ_DEBUG(1-debug,"VDOlive: did not find tag\n");
+ return 0;
+ }
+ /*
+ * The port number is the next word after the tag.
+ * VDOlive encodes all of these values
+ * in 32 bit words, so in this case I am
+ * skipping the first 2 bytes of the next
+ * word to get to the relevant 16 bits
+ */
+ data += 10;
+
+ /*
+ * If we have not seen the port already,
+ * set the masquerading tunnel up
+ */
+ if (!priv->origport) {
+ memcpy(&priv->origport, data, 2);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: found port %d\n", ntohs(priv->origport));
+
+ /* Open up a tunnel */
+ n_ms = ip_masq_new(IPPROTO_UDP,
+ maddr, 0,
+ ms->saddr, priv->origport,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+
+ if (n_ms==NULL) {
+ ip_masq_put(n_ms);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport);
+ /* Leave state as unset */
+ priv->origport = 0;
+ return 0;
+ }
+ ip_masq_listen(n_ms);
+
+ ip_masq_put(ms);
+ priv->masqport = n_ms->mport;
+ } else if (memcmp(data, &(priv->origport), 2)) {
+ IP_MASQ_DEBUG(1-debug, "VDOlive: ports do not match\n");
+ /* Write the port in anyhow!!! */
+ }
+
+ /*
+ * Write masq port into packet
+ */
+ memcpy(data, &(priv->masqport), 2);
+ IP_MASQ_DEBUG(1-debug, "VDOlive: rewrote port %d to %d, server %08X\n", ntohs(priv->origport), ntohs(priv->masqport), ms->saddr);
+
+ /*
+ * Set state bit to make which bit has been done
+ */
+
+ priv->state |= (ntohl(tagval) == 6) ? 1 : 2;
+
+ return 0;
+}
+
+
+struct ip_masq_app ip_masq_vdolive = {
+ NULL, /* next */
+ "VDOlive", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_vdolive_init_1, /* ip_masq_init_1 */
+ masq_vdolive_done_1, /* ip_masq_done_1 */
+ masq_vdolive_out, /* pkt_out */
+ NULL /* pkt_in */
+};
+
+/*
+ * ip_masq_vdolive initialization
+ */
+
+__initfunc(int ip_masq_vdolive_init(void))
+{
+ int i, j;
+
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (ports[i]) {
+ if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
+ GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+ memcpy(masq_incarnations[i], &ip_masq_vdolive, sizeof(struct ip_masq_app));
+ if ((j = register_ip_masq_app(masq_incarnations[i],
+ IPPROTO_TCP,
+ ports[i]))) {
+ return j;
+ }
+ IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n", i, ports[i]);
+ } else {
+ /* To be safe, force the incarnation table entry to NULL */
+ masq_incarnations[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ip_masq_vdolive fin.
+ */
+
+int ip_masq_vdolive_done(void)
+{
+ int i, j, k;
+
+ k=0;
+ for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+ if (masq_incarnations[i]) {
+ if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+ k = j;
+ } else {
+ kfree(masq_incarnations[i]);
+ masq_incarnations[i] = NULL;
+ IP_MASQ_DEBUG(1-debug,"VDOlive: unloaded support on port[%d] = %d\n", i, ports[i]);
+ }
+ }
+ }
+ return k;
+}
+
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (ip_masq_vdolive_init() != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_vdolive_done() != 0)
+ IP_MASQ_DEBUG(1-debug, "ip_masq_vdolive: can't remove module");
+}
+
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv4/ip_nat_dumb.c b/pfinet/linux-src/net/ipv4/ip_nat_dumb.c
new file mode 100644
index 00000000..5a1c6d75
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_nat_dumb.c
@@ -0,0 +1,158 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Dumb Network Address Translation.
+ *
+ * Version: $Id: ip_nat_dumb.c,v 1.8 1999/03/21 05:22:40 davem Exp $
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ * Rani Assaf : A zero checksum is a special case
+ * only in UDP
+ * Rani Assaf : Added ICMP messages rewriting
+ * Rani Assaf : Repaired wrong changes, made by ANK.
+ *
+ *
+ * NOTE: It is just working model of real NAT.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/firewall.h>
+#include <linux/ip_fw.h>
+#include <net/checksum.h>
+#include <linux/route.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+
+
+int
+ip_do_nat(struct sk_buff *skb)
+{
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct iphdr *iph = skb->nh.iph;
+ u32 odaddr = iph->daddr;
+ u32 osaddr = iph->saddr;
+ u16 check;
+
+ IPCB(skb)->flags |= IPSKB_TRANSLATED;
+
+ /* Rewrite IP header */
+ iph->daddr = rt->rt_dst_map;
+ iph->saddr = rt->rt_src_map;
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+ /* If it is the first fragment, rewrite protocol headers */
+
+ if (!(iph->frag_off & htons(IP_OFFSET))) {
+ u16 *cksum;
+
+ switch(iph->protocol) {
+ case IPPROTO_TCP:
+ cksum = (u16*)&((struct tcphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
+ if ((u8*)(cksum+1) > skb->tail)
+ goto truncated;
+ check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~(*cksum));
+ *cksum = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
+ break;
+ case IPPROTO_UDP:
+ cksum = (u16*)&((struct udphdr*)(((char*)iph) + (iph->ihl<<2)))->check;
+ if ((u8*)(cksum+1) > skb->tail)
+ goto truncated;
+ if ((check = *cksum) != 0) {
+ check = csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 0, ~check);
+ check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0, ~check);
+ *cksum = check ? : 0xFFFF;
+ }
+ break;
+ case IPPROTO_ICMP:
+ {
+ struct icmphdr *icmph = (struct icmphdr*)((char*)iph + (iph->ihl<<2));
+ struct iphdr *ciph;
+ u32 idaddr, isaddr;
+ int updated;
+
+ if ((icmph->type != ICMP_DEST_UNREACH) &&
+ (icmph->type != ICMP_TIME_EXCEEDED) &&
+ (icmph->type != ICMP_PARAMETERPROB))
+ break;
+
+ ciph = (struct iphdr *) (icmph + 1);
+
+ if ((u8*)(ciph+1) > skb->tail)
+ goto truncated;
+
+ isaddr = ciph->saddr;
+ idaddr = ciph->daddr;
+ updated = 0;
+
+ if (rt->rt_flags&RTCF_DNAT && ciph->saddr == odaddr) {
+ ciph->saddr = iph->daddr;
+ updated = 1;
+ }
+ if (rt->rt_flags&RTCF_SNAT) {
+ if (ciph->daddr != osaddr) {
+ struct fib_result res;
+ struct rt_key key;
+ unsigned flags = 0;
+
+ key.src = ciph->daddr;
+ key.dst = ciph->saddr;
+ key.iif = skb->dev->ifindex;
+ key.oif = 0;
+#ifdef CONFIG_IP_ROUTE_TOS
+ key.tos = RT_TOS(ciph->tos);
+#endif
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ key.fwmark = 0;
+#endif
+ /* Use fib_lookup() until we get our own
+ * hash table of NATed hosts -- Rani
+ */
+ if (fib_lookup(&key, &res) == 0 && res.r) {
+ ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
+ if (ciph->daddr != idaddr)
+ updated = 1;
+ }
+ } else {
+ ciph->daddr = iph->saddr;
+ updated = 1;
+ }
+ }
+ if (updated) {
+ cksum = &icmph->checksum;
+ /* Using tcpudp primitive. Why not? */
+ check = csum_tcpudp_magic(ciph->saddr, ciph->daddr, 0, 0, ~(*cksum));
+ *cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0, ~check);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return 0;
+
+truncated:
+ return -EINVAL;
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_options.c b/pfinet/linux-src/net/ipv4/ip_options.c
new file mode 100644
index 00000000..ec21054d
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_options.c
@@ -0,0 +1,620 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * The options processing module for ip.c
+ *
+ * Version: $Id: ip_options.c,v 1.16.2.1 1999/06/02 04:06:19 davem Exp $
+ *
+ * Authors: A.N.Kuznetsov
+ *
+ */
+
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+
+/*
+ * Write options to IP header, record destination address to
+ * source route option, address of outgoing interface
+ * (we should already know it, so that this function is allowed be
+ * called only after routing decision) and timestamp,
+ * if we originate this datagram.
+ *
+ * daddr is real destination address, next hop is recorded in IP header.
+ * saddr is address of outgoing interface.
+ */
+
+void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
+ u32 daddr, struct rtable *rt, int is_frag)
+{
+ unsigned char * iph = skb->nh.raw;
+
+ memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));
+ memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);
+ opt = &(IPCB(skb)->opt);
+ opt->is_data = 0;
+
+ if (opt->srr)
+ memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4);
+
+ if (!is_frag) {
+ if (opt->rr_needaddr)
+ ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt);
+ if (opt->ts_needaddr)
+ ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt);
+ if (opt->ts_needtime) {
+ struct timeval tv;
+ __u32 midtime;
+ do_gettimeofday(&tv);
+ midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+ memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
+ }
+ return;
+ }
+ if (opt->rr) {
+ memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]);
+ opt->rr = 0;
+ opt->rr_needaddr = 0;
+ }
+ if (opt->ts) {
+ memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]);
+ opt->ts = 0;
+ opt->ts_needaddr = opt->ts_needtime = 0;
+ }
+}
+
+/*
+ * Provided (sopt, skb) points to received options,
+ * build in dopt compiled option set appropriate for answering.
+ * i.e. invert SRR option, copy anothers,
+ * and grab room in RR/TS options.
+ *
+ * NOTE: dopt cannot point to skb.
+ */
+
+int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
+{
+ struct ip_options *sopt;
+ unsigned char *sptr, *dptr;
+ int soffset, doffset;
+ int optlen;
+ u32 daddr;
+
+ memset(dopt, 0, sizeof(struct ip_options));
+
+ dopt->is_data = 1;
+
+ sopt = &(IPCB(skb)->opt);
+
+ if (sopt->optlen == 0) {
+ dopt->optlen = 0;
+ return 0;
+ }
+
+ sptr = skb->nh.raw;
+ dptr = dopt->__data;
+
+ if (skb->dst)
+ daddr = ((struct rtable*)skb->dst)->rt_spec_dst;
+ else
+ daddr = skb->nh.iph->daddr;
+
+ if (sopt->rr) {
+ optlen = sptr[sopt->rr+1];
+ soffset = sptr[sopt->rr+2];
+ dopt->rr = dopt->optlen + sizeof(struct iphdr);
+ memcpy(dptr, sptr+sopt->rr, optlen);
+ if (sopt->rr_needaddr && soffset <= optlen) {
+ if (soffset + 3 > optlen)
+ return -EINVAL;
+ dptr[2] = soffset + 4;
+ dopt->rr_needaddr = 1;
+ }
+ dptr += optlen;
+ dopt->optlen += optlen;
+ }
+ if (sopt->ts) {
+ optlen = sptr[sopt->ts+1];
+ soffset = sptr[sopt->ts+2];
+ dopt->ts = dopt->optlen + sizeof(struct iphdr);
+ memcpy(dptr, sptr+sopt->ts, optlen);
+ if (soffset <= optlen) {
+ if (sopt->ts_needaddr) {
+ if (soffset + 3 > optlen)
+ return -EINVAL;
+ dopt->ts_needaddr = 1;
+ soffset += 4;
+ }
+ if (sopt->ts_needtime) {
+ if (soffset + 3 > optlen)
+ return -EINVAL;
+ if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) {
+ dopt->ts_needtime = 1;
+ soffset += 4;
+ } else {
+ dopt->ts_needtime = 0;
+
+ if (soffset + 8 <= optlen) {
+ __u32 addr;
+
+ memcpy(&addr, sptr+soffset-1, 4);
+ if (inet_addr_type(addr) != RTN_LOCAL) {
+ dopt->ts_needtime = 1;
+ soffset += 8;
+ }
+ }
+ }
+ }
+ dptr[2] = soffset;
+ }
+ dptr += optlen;
+ dopt->optlen += optlen;
+ }
+ if (sopt->srr) {
+ unsigned char * start = sptr+sopt->srr;
+ u32 faddr;
+
+ optlen = start[1];
+ soffset = start[2];
+ doffset = 0;
+ if (soffset > optlen)
+ soffset = optlen + 1;
+ soffset -= 4;
+ if (soffset > 3) {
+ memcpy(&faddr, &start[soffset-1], 4);
+ for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4)
+ memcpy(&dptr[doffset-1], &start[soffset-1], 4);
+ /*
+ * RFC1812 requires to fix illegal source routes.
+ */
+ if (memcmp(&skb->nh.iph->saddr, &start[soffset+3], 4) == 0)
+ doffset -= 4;
+ }
+ if (doffset > 3) {
+ memcpy(&start[doffset-1], &daddr, 4);
+ dopt->faddr = faddr;
+ dptr[0] = start[0];
+ dptr[1] = doffset+3;
+ dptr[2] = 4;
+ dptr += doffset+3;
+ dopt->srr = dopt->optlen + sizeof(struct iphdr);
+ dopt->optlen += doffset+3;
+ dopt->is_strictroute = sopt->is_strictroute;
+ }
+ }
+ while (dopt->optlen & 3) {
+ *dptr++ = IPOPT_END;
+ dopt->optlen++;
+ }
+ return 0;
+}
+
+/*
+ * Options "fragmenting", just fill options not
+ * allowed in fragments with NOOPs.
+ * Simple and stupid 8), but the most efficient way.
+ */
+
+void ip_options_fragment(struct sk_buff * skb)
+{
+ unsigned char * optptr = skb->nh.raw;
+ struct ip_options * opt = &(IPCB(skb)->opt);
+ int l = opt->optlen;
+ int optlen;
+
+ while (l > 0) {
+ switch (*optptr) {
+ case IPOPT_END:
+ return;
+ case IPOPT_NOOP:
+ l--;
+ optptr++;
+ continue;
+ }
+ optlen = optptr[1];
+ if (optlen<2 || optlen>l)
+ return;
+ if (!IPOPT_COPIED(*optptr))
+ memset(optptr, IPOPT_NOOP, optlen);
+ l -= optlen;
+ optptr += optlen;
+ }
+ opt->ts = 0;
+ opt->rr = 0;
+ opt->rr_needaddr = 0;
+ opt->ts_needaddr = 0;
+ opt->ts_needtime = 0;
+ return;
+}
+
+/*
+ * Verify options and fill pointers in struct options.
+ * Caller should clear *opt, and set opt->data.
+ * If opt == NULL, then skb->data should point to IP header.
+ */
+
+int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
+{
+ int l;
+ unsigned char * iph;
+ unsigned char * optptr;
+ int optlen;
+ unsigned char * pp_ptr = NULL;
+ struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL;
+
+ if (!opt) {
+ opt = &(IPCB(skb)->opt);
+ memset(opt, 0, sizeof(struct ip_options));
+ iph = skb->nh.raw;
+ opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr);
+ optptr = iph + sizeof(struct iphdr);
+ opt->is_data = 0;
+ } else {
+ optptr = opt->is_data ? opt->__data : (unsigned char*)&(skb->nh.iph[1]);
+ iph = optptr - sizeof(struct iphdr);
+ }
+
+ for (l = opt->optlen; l > 0; ) {
+ switch (*optptr) {
+ case IPOPT_END:
+ for (optptr++, l--; l>0; l--) {
+ if (*optptr != IPOPT_END) {
+ *optptr = IPOPT_END;
+ opt->is_changed = 1;
+ }
+ }
+ goto eol;
+ case IPOPT_NOOP:
+ l--;
+ optptr++;
+ continue;
+ }
+ optlen = optptr[1];
+ if (optlen<2 || optlen>l) {
+ pp_ptr = optptr;
+ goto error;
+ }
+ switch (*optptr) {
+ case IPOPT_SSRR:
+ case IPOPT_LSRR:
+ if (optlen < 3) {
+ pp_ptr = optptr + 1;
+ goto error;
+ }
+ if (optptr[2] < 4) {
+ pp_ptr = optptr + 2;
+ goto error;
+ }
+ /* NB: cf RFC-1812 5.2.4.1 */
+ if (opt->srr) {
+ pp_ptr = optptr;
+ goto error;
+ }
+ if (!skb) {
+ if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) {
+ pp_ptr = optptr + 1;
+ goto error;
+ }
+ memcpy(&opt->faddr, &optptr[3], 4);
+ if (optlen > 7)
+ memmove(&optptr[3], &optptr[7], optlen-7);
+ }
+ opt->is_strictroute = (optptr[0] == IPOPT_SSRR);
+ opt->srr = optptr - iph;
+ break;
+ case IPOPT_RR:
+ if (opt->rr) {
+ pp_ptr = optptr;
+ goto error;
+ }
+ if (optlen < 3) {
+ pp_ptr = optptr + 1;
+ goto error;
+ }
+ if (optptr[2] < 4) {
+ pp_ptr = optptr + 2;
+ goto error;
+ }
+ if (optptr[2] <= optlen) {
+ if (optptr[2]+3 > optlen) {
+ pp_ptr = optptr + 2;
+ goto error;
+ }
+ if (skb) {
+ memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
+ opt->is_changed = 1;
+ }
+ optptr[2] += 4;
+ opt->rr_needaddr = 1;
+ }
+ opt->rr = optptr - iph;
+ break;
+ case IPOPT_TIMESTAMP:
+ if (opt->ts) {
+ pp_ptr = optptr;
+ goto error;
+ }
+ if (optlen < 4) {
+ pp_ptr = optptr + 1;
+ goto error;
+ }
+ if (optptr[2] < 5) {
+ pp_ptr = optptr + 2;
+ goto error;
+ }
+ if (optptr[2] <= optlen) {
+ __u32 * timeptr = NULL;
+ if (optptr[2]+3 > optptr[1]) {
+ pp_ptr = optptr + 2;
+ goto error;
+ }
+ switch (optptr[3]&0xF) {
+ case IPOPT_TS_TSONLY:
+ opt->ts = optptr - iph;
+ if (skb)
+ timeptr = (__u32*)&optptr[optptr[2]-1];
+ opt->ts_needtime = 1;
+ optptr[2] += 4;
+ break;
+ case IPOPT_TS_TSANDADDR:
+ if (optptr[2]+7 > optptr[1]) {
+ pp_ptr = optptr + 2;
+ goto error;
+ }
+ opt->ts = optptr - iph;
+ if (skb) {
+ memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
+ timeptr = (__u32*)&optptr[optptr[2]+3];
+ }
+ opt->ts_needaddr = 1;
+ opt->ts_needtime = 1;
+ optptr[2] += 8;
+ break;
+ case IPOPT_TS_PRESPEC:
+ if (optptr[2]+7 > optptr[1]) {
+ pp_ptr = optptr + 2;
+ goto error;
+ }
+ opt->ts = optptr - iph;
+ {
+ u32 addr;
+ memcpy(&addr, &optptr[optptr[2]-1], 4);
+ if (inet_addr_type(addr) == RTN_UNICAST)
+ break;
+ if (skb)
+ timeptr = (__u32*)&optptr[optptr[2]+3];
+ }
+ opt->ts_needtime = 1;
+ optptr[2] += 8;
+ break;
+ default:
+ if (!skb && !capable(CAP_NET_RAW)) {
+ pp_ptr = optptr + 3;
+ goto error;
+ }
+ break;
+ }
+ if (timeptr) {
+ struct timeval tv;
+ __u32 midtime;
+ do_gettimeofday(&tv);
+ midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+ memcpy(timeptr, &midtime, sizeof(__u32));
+ opt->is_changed = 1;
+ }
+ } else {
+ unsigned overflow = optptr[3]>>4;
+ if (overflow == 15) {
+ pp_ptr = optptr + 3;
+ goto error;
+ }
+ opt->ts = optptr - iph;
+ if (skb) {
+ optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4);
+ opt->is_changed = 1;
+ }
+ }
+ break;
+ case IPOPT_RA:
+ if (optlen < 4) {
+ pp_ptr = optptr + 1;
+ goto error;
+ }
+ if (optptr[2] == 0 && optptr[3] == 0)
+ opt->router_alert = optptr - iph;
+ break;
+ case IPOPT_SEC:
+ case IPOPT_SID:
+ default:
+ if (!skb && !capable(CAP_NET_RAW)) {
+ pp_ptr = optptr;
+ goto error;
+ }
+ break;
+ }
+ l -= optlen;
+ optptr += optlen;
+ }
+
+eol:
+ if (!pp_ptr)
+ return 0;
+
+error:
+ if (skb) {
+ icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24));
+ }
+ return -EINVAL;
+}
+
+
+/*
+ * Undo all the changes done by ip_options_compile().
+ */
+
+void ip_options_undo(struct ip_options * opt)
+{
+ if (opt->srr) {
+ unsigned char * optptr = opt->__data+opt->srr-sizeof(struct iphdr);
+ memmove(optptr+7, optptr+3, optptr[1]-7);
+ memcpy(optptr+3, &opt->faddr, 4);
+ }
+ if (opt->rr_needaddr) {
+ unsigned char * optptr = opt->__data+opt->rr-sizeof(struct iphdr);
+ optptr[2] -= 4;
+ memset(&optptr[optptr[2]-1], 0, 4);
+ }
+ if (opt->ts) {
+ unsigned char * optptr = opt->__data+opt->ts-sizeof(struct iphdr);
+ if (opt->ts_needtime) {
+ optptr[2] -= 4;
+ memset(&optptr[optptr[2]-1], 0, 4);
+ if ((optptr[3]&0xF) == IPOPT_TS_PRESPEC)
+ optptr[2] -= 4;
+ }
+ if (opt->ts_needaddr) {
+ optptr[2] -= 4;
+ memset(&optptr[optptr[2]-1], 0, 4);
+ }
+ }
+}
+
+int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, int user)
+{
+ struct ip_options *opt;
+ size_t opt_size = sizeof(struct ip_options)+((optlen+3)&~3);
+
+ opt = kmalloc(opt_size, GFP_KERNEL);
+ if (!opt)
+ return -ENOMEM;
+ memset(opt, 0, sizeof(struct ip_options));
+ if (optlen) {
+ if (user) {
+ if (copy_from_user(opt->__data, data, optlen)) {
+ kfree_s(opt, opt_size);
+ return -EFAULT;
+ }
+ } else
+ memcpy(opt->__data, data, optlen);
+ }
+ while (optlen & 3)
+ opt->__data[optlen++] = IPOPT_END;
+ opt->optlen = optlen;
+ opt->is_data = 1;
+ opt->is_setbyuser = 1;
+ if (optlen && ip_options_compile(opt, NULL)) {
+ kfree_s(opt, opt_size);
+ return -EINVAL;
+ }
+ *optp = opt;
+ return 0;
+}
+
+void ip_forward_options(struct sk_buff *skb)
+{
+ struct ip_options * opt = &(IPCB(skb)->opt);
+ unsigned char * optptr;
+ struct rtable *rt = (struct rtable*)skb->dst;
+ unsigned char *raw = skb->nh.raw;
+
+ if (opt->rr_needaddr) {
+ optptr = (unsigned char *)raw + opt->rr;
+ ip_rt_get_source(&optptr[optptr[2]-5], rt);
+ opt->is_changed = 1;
+ }
+ if (opt->srr_is_hit) {
+ int srrptr, srrspace;
+
+ optptr = raw + opt->srr;
+
+ for ( srrptr=optptr[2], srrspace = optptr[1];
+ srrptr <= srrspace;
+ srrptr += 4
+ ) {
+ if (srrptr + 3 > srrspace)
+ break;
+ if (memcmp(&rt->rt_dst, &optptr[srrptr-1], 4) == 0)
+ break;
+ }
+ if (srrptr + 3 <= srrspace) {
+ opt->is_changed = 1;
+ ip_rt_get_source(&optptr[srrptr-1], rt);
+ skb->nh.iph->daddr = rt->rt_dst;
+ optptr[2] = srrptr+4;
+ } else
+ printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n");
+ if (opt->ts_needaddr) {
+ optptr = raw + opt->ts;
+ ip_rt_get_source(&optptr[optptr[2]-9], rt);
+ opt->is_changed = 1;
+ }
+ }
+ if (opt->is_changed) {
+ opt->is_changed = 0;
+ ip_send_check(skb->nh.iph);
+ }
+}
+
+int ip_options_rcv_srr(struct sk_buff *skb)
+{
+ struct ip_options *opt = &(IPCB(skb)->opt);
+ int srrspace, srrptr;
+ u32 nexthop;
+ struct iphdr *iph = skb->nh.iph;
+ unsigned char * optptr = skb->nh.raw + opt->srr;
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtable *rt2;
+ int err;
+
+ if (!opt->srr)
+ return 0;
+
+ if (skb->pkt_type != PACKET_HOST)
+ return -EINVAL;
+ if (rt->rt_type == RTN_UNICAST) {
+ if (!opt->is_strictroute)
+ return 0;
+ icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24));
+ return -EINVAL;
+ }
+ if (rt->rt_type != RTN_LOCAL)
+ return -EINVAL;
+
+ for (srrptr=optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) {
+ if (srrptr + 3 > srrspace) {
+ icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24));
+ return -EINVAL;
+ }
+ memcpy(&nexthop, &optptr[srrptr-1], 4);
+
+ rt = (struct rtable*)skb->dst;
+ skb->dst = NULL;
+ err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
+ rt2 = (struct rtable*)skb->dst;
+ if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
+ ip_rt_put(rt2);
+ skb->dst = &rt->u.dst;
+ return -EINVAL;
+ }
+ ip_rt_put(rt);
+ if (rt2->rt_type != RTN_LOCAL)
+ break;
+ /* Superfast 8) loopback forward */
+ memcpy(&iph->daddr, &optptr[srrptr-1], 4);
+ opt->is_changed = 1;
+ }
+ if (srrptr <= srrspace) {
+ opt->srr_is_hit = 1;
+ opt->is_changed = 1;
+ }
+ return 0;
+}
diff --git a/pfinet/linux-src/net/ipv4/ip_output.c b/pfinet/linux-src/net/ipv4/ip_output.c
new file mode 100644
index 00000000..d85ba6b5
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_output.c
@@ -0,0 +1,992 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * The Internet Protocol (IP) output module.
+ *
+ * Version: $Id: ip_output.c,v 1.67.2.1 1999/09/07 02:25:23 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <Alan.Cox@linux.org>
+ * Richard Underwood
+ * Stefan Becker, <stefanb@yello.ping.de>
+ * Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *
+ * See ip_input.c for original log
+ *
+ * Fixes:
+ * Alan Cox : Missing nonblock feature in ip_build_xmit.
+ * Mike Kilburn : htons() missing in ip_build_xmit.
+ * Bradford Johnson: Fix faulty handling of some frames when
+ * no route is found.
+ * Alexander Demenshin: Missing sk/skb free in ip_queue_xmit
+ * (in case if packet not accepted by
+ * output firewall rules)
+ * Mike McLagan : Routing by source
+ * Alexey Kuznetsov: use new route cache
+ * Andi Kleen: Fix broken PMTU recovery and remove
+ * some redundant tests.
+ * Vitaly E. Lavrov : Transparent proxy revived after year coma.
+ * Andi Kleen : Replace ip_reply with ip_send_reply.
+ * Andi Kleen : Split fast and slow ip_build_xmit path
+ * for decreased register pressure on x86
+ * and more readibility.
+ * Marc Boucher : When call_out_firewall returns FW_QUEUE,
+ * silently drop skb instead of failing with -EPERM.
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/config.h>
+
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+
+#include <net/snmp.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/route.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/arp.h>
+#include <net/icmp.h>
+#include <net/raw.h>
+#include <net/checksum.h>
+#include <linux/igmp.h>
+#include <linux/ip_fw.h>
+#include <linux/firewall.h>
+#include <linux/mroute.h>
+#include <linux/netlink.h>
+
+/*
+ * Shall we try to damage output packets if routing dev changes?
+ */
+
+int sysctl_ip_dynaddr = 0;
+
+
+int ip_id_count = 0;
+
+/* Generate a checksum for an outgoing IP datagram. */
+__inline__ void ip_send_check(struct iphdr *iph)
+{
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+}
+
+/*
+ * Add an ip header to a skbuff and send it out.
+ */
+void ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
+ u32 saddr, u32 daddr, struct ip_options *opt)
+{
+ struct rtable *rt = (struct rtable *)skb->dst;
+ struct iphdr *iph;
+ struct device *dev;
+
+ /* Build the IP header. */
+ if (opt)
+ iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen);
+ else
+ iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr));
+
+ iph->version = 4;
+ iph->ihl = 5;
+ iph->tos = sk->ip_tos;
+ iph->frag_off = 0;
+ if (ip_dont_fragment(sk, &rt->u.dst))
+ iph->frag_off |= htons(IP_DF);
+ iph->ttl = sk->ip_ttl;
+ iph->daddr = rt->rt_dst;
+ iph->saddr = rt->rt_src;
+ iph->protocol = sk->protocol;
+ iph->tot_len = htons(skb->len);
+ iph->id = htons(ip_id_count++);
+ skb->nh.iph = iph;
+
+ if (opt && opt->optlen) {
+ iph->ihl += opt->optlen>>2;
+ ip_options_build(skb, opt, daddr, rt, 0);
+ }
+
+ dev = rt->u.dst.dev;
+
+#ifdef CONFIG_FIREWALL
+ /* Now we have no better mechanism to notify about error. */
+ switch (call_out_firewall(PF_INET, dev, iph, NULL, &skb)) {
+ case FW_REJECT:
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+ /* Fall thru... */
+ case FW_BLOCK:
+ case FW_QUEUE:
+ kfree_skb(skb);
+ return;
+ }
+#endif
+
+ ip_send_check(iph);
+
+ /* Send it out. */
+ skb->dst->output(skb);
+ return;
+}
+
+int __ip_finish_output(struct sk_buff *skb)
+{
+ return ip_finish_output(skb);
+}
+
+int ip_mc_output(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct device *dev = rt->u.dst.dev;
+
+ /*
+ * If the indicated interface is up and running, send the packet.
+ */
+
+ ip_statistics.IpOutRequests++;
+#ifdef CONFIG_IP_ROUTE_NAT
+ if (rt->rt_flags & RTCF_NAT)
+ ip_do_nat(skb);
+#endif
+
+ skb->dev = dev;
+ skb->protocol = __constant_htons(ETH_P_IP);
+
+ /*
+ * Multicasts are looped back for other local users
+ */
+
+ if (rt->rt_flags&RTCF_MULTICAST && (!sk || sk->ip_mc_loop)) {
+#ifdef CONFIG_IP_MROUTE
+ /* Small optimization: do not loopback not local frames,
+ which returned after forwarding; they will be dropped
+ by ip_mr_input in any case.
+ Note, that local frames are looped back to be delivered
+ to local recipients.
+
+ This check is duplicated in ip_mr_input at the moment.
+ */
+ if ((rt->rt_flags&RTCF_LOCAL) || !(IPCB(skb)->flags&IPSKB_FORWARDED))
+#endif
+ dev_loopback_xmit(skb);
+
+ /* Multicasts with ttl 0 must not go beyond the host */
+
+ if (skb->nh.iph->ttl == 0) {
+ kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ if (rt->rt_flags&RTCF_BROADCAST)
+ dev_loopback_xmit(skb);
+
+ return ip_finish_output(skb);
+}
+
+int ip_output(struct sk_buff *skb)
+{
+#ifdef CONFIG_IP_ROUTE_NAT
+ struct rtable *rt = (struct rtable*)skb->dst;
+#endif
+
+ ip_statistics.IpOutRequests++;
+
+#ifdef CONFIG_IP_ROUTE_NAT
+ if (rt->rt_flags&RTCF_NAT)
+ ip_do_nat(skb);
+#endif
+
+ return ip_finish_output(skb);
+}
+
+/* Queues a packet to be sent, and starts the transmitter if necessary.
+ * This routine also needs to put in the total length and compute the
+ * checksum. We use to do this in two stages, ip_build_header() then
+ * this, but that scheme created a mess when routes disappeared etc.
+ * So we do it all here, and the TCP send engine has been changed to
+ * match. (No more unroutable FIN disasters, etc. wheee...) This will
+ * most likely make other reliable transport layers above IP easier
+ * to implement under Linux.
+ */
+void ip_queue_xmit(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+ struct ip_options *opt = sk->opt;
+ struct rtable *rt;
+ struct device *dev;
+ struct iphdr *iph;
+ unsigned int tot_len;
+
+ /* Make sure we can route this packet. */
+ rt = (struct rtable *) sk->dst_cache;
+ if(rt == NULL || rt->u.dst.obsolete) {
+ u32 daddr;
+
+ sk->dst_cache = NULL;
+ ip_rt_put(rt);
+
+ /* Use correct destination address if we have options. */
+ daddr = sk->daddr;
+ if(opt && opt->srr)
+ daddr = opt->faddr;
+
+ /* If this fails, retransmit mechanism of transport layer will
+ * keep trying until route appears or the connection times itself
+ * out.
+ */
+ if(ip_route_output(&rt, daddr, sk->saddr,
+ RT_TOS(sk->ip_tos) | RTO_CONN | sk->localroute,
+ sk->bound_dev_if))
+ goto drop;
+ sk->dst_cache = &rt->u.dst;
+ }
+ if(opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
+ goto no_route;
+
+ /* We have a route, so grab a reference. */
+ skb->dst = dst_clone(sk->dst_cache);
+
+ /* OK, we know where to send it, allocate and build IP header. */
+ iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
+ iph->version = 4;
+ iph->ihl = 5;
+ iph->tos = sk->ip_tos;
+ iph->frag_off = 0;
+ iph->ttl = sk->ip_ttl;
+ iph->daddr = rt->rt_dst;
+ iph->saddr = rt->rt_src;
+ iph->protocol = sk->protocol;
+ skb->nh.iph = iph;
+ /* Transport layer set skb->h.foo itself. */
+
+ if(opt && opt->optlen) {
+ iph->ihl += opt->optlen >> 2;
+ ip_options_build(skb, opt, sk->daddr, rt, 0);
+ }
+
+ tot_len = skb->len;
+ iph->tot_len = htons(tot_len);
+ iph->id = htons(ip_id_count++);
+
+ dev = rt->u.dst.dev;
+
+#ifdef CONFIG_FIREWALL
+ /* Now we have no better mechanism to notify about error. */
+ switch (call_out_firewall(PF_INET, dev, iph, NULL, &skb)) {
+ case FW_REJECT:
+ start_bh_atomic();
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+ end_bh_atomic();
+ /* Fall thru... */
+ case FW_BLOCK:
+ case FW_QUEUE:
+ goto drop;
+ }
+#endif
+
+ /* This can happen when the transport layer has segments queued
+ * with a cached route, and by the time we get here things are
+ * re-routed to a device with a different MTU than the original
+ * device. Sick, but we must cover it.
+ */
+ if (skb_headroom(skb) < dev->hard_header_len && dev->hard_header) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_realloc_headroom(skb, (dev->hard_header_len + 15) & ~15);
+ kfree_skb(skb);
+ if (skb2 == NULL)
+ return;
+ if (sk)
+ skb_set_owner_w(skb2, sk);
+ skb = skb2;
+ iph = skb->nh.iph;
+ }
+
+ /* Do we need to fragment. Again this is inefficient. We
+ * need to somehow lock the original buffer and use bits of it.
+ */
+ if (tot_len > rt->u.dst.pmtu)
+ goto fragment;
+
+ if (ip_dont_fragment(sk, &rt->u.dst))
+ iph->frag_off |= __constant_htons(IP_DF);
+
+ /* Add an IP checksum. */
+ ip_send_check(iph);
+
+ skb->priority = sk->priority;
+ skb->dst->output(skb);
+ return;
+
+fragment:
+ if (ip_dont_fragment(sk, &rt->u.dst) &&
+ tot_len > (iph->ihl<<2) + sizeof(struct tcphdr)+16) {
+ /* Reject packet ONLY if TCP might fragment
+ it itself, if were careful enough.
+ Test is not precise (f.e. it does not take sacks
+ into account). Actually, tcp should make it. --ANK (980801)
+ */
+ iph->frag_off |= __constant_htons(IP_DF);
+ NETDEBUG(printk(KERN_DEBUG "sending pkt_too_big to self\n"));
+
+ /* icmp_send is not reenterable, so that bh_atomic... --ANK */
+ start_bh_atomic();
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+ htonl(rt->u.dst.pmtu));
+ end_bh_atomic();
+ goto drop;
+ }
+ ip_fragment(skb, skb->dst->output);
+ return;
+
+no_route:
+ sk->dst_cache = NULL;
+ ip_rt_put(rt);
+ ip_statistics.IpOutNoRoutes++;
+ /* Fall through... */
+drop:
+ kfree_skb(skb);
+}
+
+/*
+ * Build and send a packet, with as little as one copy
+ *
+ * Doesn't care much about ip options... option length can be
+ * different for fragment at 0 and other fragments.
+ *
+ * Note that the fragment at the highest offset is sent first,
+ * so the getfrag routine can fill in the TCP/UDP checksum header
+ * field in the last fragment it sends... actually it also helps
+ * the reassemblers, they can put most packets in at the head of
+ * the fragment queue, and they know the total size in advance. This
+ * last feature will measurably improve the Linux fragment handler one
+ * day.
+ *
+ * The callback has five args, an arbitrary pointer (copy of frag),
+ * the source IP address (may depend on the routing table), the
+ * destination address (char *), the offset to copy from, and the
+ * length to be copied.
+ */
+
+int ip_build_xmit_slow(struct sock *sk,
+ int getfrag (const void *,
+ char *,
+ unsigned int,
+ unsigned int),
+ const void *frag,
+ unsigned length,
+ struct ipcm_cookie *ipc,
+ struct rtable *rt,
+ int flags)
+{
+ unsigned int fraglen, maxfraglen, fragheaderlen;
+ int err;
+ int offset, mf;
+ int mtu;
+ unsigned short id;
+
+ int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
+ int nfrags=0;
+ struct ip_options *opt = ipc->opt;
+ int df = 0;
+
+ mtu = rt->u.dst.pmtu;
+ if (ip_dont_fragment(sk, &rt->u.dst))
+ df = htons(IP_DF);
+
+ length -= sizeof(struct iphdr);
+
+ if (opt) {
+ fragheaderlen = sizeof(struct iphdr) + opt->optlen;
+ maxfraglen = ((mtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheaderlen;
+ } else {
+ fragheaderlen = sizeof(struct iphdr);
+
+ /*
+ * Fragheaderlen is the size of 'overhead' on each buffer. Now work
+ * out the size of the frames to send.
+ */
+
+ maxfraglen = ((mtu-sizeof(struct iphdr)) & ~7) + fragheaderlen;
+ }
+
+ if (length + fragheaderlen > 0xFFFF) {
+ ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
+ return -EMSGSIZE;
+ }
+
+ /*
+ * Start at the end of the frame by handling the remainder.
+ */
+
+ offset = length - (length % (maxfraglen - fragheaderlen));
+
+ /*
+ * Amount of memory to allocate for final fragment.
+ */
+
+ fraglen = length - offset + fragheaderlen;
+
+ if (length-offset==0) {
+ fraglen = maxfraglen;
+ offset -= maxfraglen-fragheaderlen;
+ }
+
+
+ /*
+ * The last fragment will not have MF (more fragments) set.
+ */
+
+ mf = 0;
+
+ /*
+ * Don't fragment packets for path mtu discovery.
+ */
+
+ if (offset > 0 && df) {
+ ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
+ return(-EMSGSIZE);
+ }
+
+ /*
+ * Lock the device lists.
+ */
+
+ dev_lock_list();
+
+ /*
+ * Get an identifier
+ */
+
+ id = htons(ip_id_count++);
+
+ /*
+ * Begin outputting the bytes.
+ */
+
+ do {
+ char *data;
+ struct sk_buff * skb;
+
+ /*
+ * Get the memory we require with some space left for alignment.
+ */
+
+ skb = sock_alloc_send_skb(sk, fraglen+hh_len+15, 0, flags&MSG_DONTWAIT, &err);
+ if (skb == NULL)
+ goto error;
+
+ /*
+ * Fill in the control structures
+ */
+
+ skb->priority = sk->priority;
+ skb->dst = dst_clone(&rt->u.dst);
+ skb_reserve(skb, hh_len);
+
+ /*
+ * Find where to start putting bytes.
+ */
+
+ data = skb_put(skb, fraglen);
+ skb->nh.iph = (struct iphdr *)data;
+
+ /*
+ * Only write IP header onto non-raw packets
+ */
+
+ {
+ struct iphdr *iph = (struct iphdr *)data;
+
+ iph->version = 4;
+ iph->ihl = 5;
+ if (opt) {
+ iph->ihl += opt->optlen>>2;
+ ip_options_build(skb, opt,
+ ipc->addr, rt, offset);
+ }
+ iph->tos = sk->ip_tos;
+ iph->tot_len = htons(fraglen - fragheaderlen + iph->ihl*4);
+ iph->id = id;
+ iph->frag_off = htons(offset>>3);
+ iph->frag_off |= mf|df;
+ if (rt->rt_type == RTN_MULTICAST)
+ iph->ttl = sk->ip_mc_ttl;
+ else
+ iph->ttl = sk->ip_ttl;
+ iph->protocol = sk->protocol;
+ iph->check = 0;
+ iph->saddr = rt->rt_src;
+ iph->daddr = rt->rt_dst;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ data += iph->ihl*4;
+
+ /*
+ * Any further fragments will have MF set.
+ */
+
+ mf = htons(IP_MF);
+ }
+
+ /*
+ * User data callback
+ */
+
+ if (getfrag(frag, data, offset, fraglen-fragheaderlen)) {
+ err = -EFAULT;
+ kfree_skb(skb);
+ goto error;
+ }
+
+ offset -= (maxfraglen-fragheaderlen);
+ fraglen = maxfraglen;
+
+ nfrags++;
+
+#ifdef CONFIG_FIREWALL
+ switch (call_out_firewall(PF_INET, rt->u.dst.dev, skb->nh.iph, NULL, &skb)) {
+ case FW_QUEUE:
+ kfree_skb(skb);
+ continue;
+ case FW_BLOCK:
+ case FW_REJECT:
+ kfree_skb(skb);
+ err = -EPERM;
+ goto error;
+ }
+#endif
+
+ err = -ENETDOWN;
+ if (rt->u.dst.output(skb))
+ goto error;
+ } while (offset >= 0);
+
+ if (nfrags>1)
+ ip_statistics.IpFragCreates += nfrags;
+ dev_unlock_list();
+ return 0;
+
+error:
+ ip_statistics.IpOutDiscards++;
+ if (nfrags>1)
+ ip_statistics.IpFragCreates += nfrags;
+ dev_unlock_list();
+ return err;
+}
+
+
+/*
+ * Fast path for unfragmented packets.
+ */
+int ip_build_xmit(struct sock *sk,
+ int getfrag (const void *,
+ char *,
+ unsigned int,
+ unsigned int),
+ const void *frag,
+ unsigned length,
+ struct ipcm_cookie *ipc,
+ struct rtable *rt,
+ int flags)
+{
+ int err;
+ struct sk_buff *skb;
+ int df;
+ struct iphdr *iph;
+
+ /*
+ * Try the simple case first. This leaves fragmented frames, and by
+ * choice RAW frames within 20 bytes of maximum size(rare) to the long path
+ */
+
+ if (!sk->ip_hdrincl) {
+ length += sizeof(struct iphdr);
+
+ /*
+ * Check for slow path.
+ */
+ if (length > rt->u.dst.pmtu || ipc->opt != NULL)
+ return ip_build_xmit_slow(sk,getfrag,frag,length,ipc,rt,flags);
+ } else {
+ if (length > rt->u.dst.dev->mtu) {
+ ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, rt->u.dst.dev->mtu);
+ return -EMSGSIZE;
+ }
+ }
+
+ /*
+ * Do path mtu discovery if needed.
+ */
+ df = 0;
+ if (ip_dont_fragment(sk, &rt->u.dst))
+ df = htons(IP_DF);
+
+ /*
+ * Fast path for unfragmented frames without options.
+ */
+ {
+ int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
+
+ skb = sock_alloc_send_skb(sk, length+hh_len+15,
+ 0, flags&MSG_DONTWAIT, &err);
+ if(skb==NULL)
+ goto error;
+ skb_reserve(skb, hh_len);
+ }
+
+ skb->priority = sk->priority;
+ skb->dst = dst_clone(&rt->u.dst);
+
+ skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length);
+
+ dev_lock_list();
+
+ if(!sk->ip_hdrincl) {
+ iph->version=4;
+ iph->ihl=5;
+ iph->tos=sk->ip_tos;
+ iph->tot_len = htons(length);
+ iph->id=htons(ip_id_count++);
+ iph->frag_off = df;
+ iph->ttl=sk->ip_mc_ttl;
+ if (rt->rt_type != RTN_MULTICAST)
+ iph->ttl=sk->ip_ttl;
+ iph->protocol=sk->protocol;
+ iph->saddr=rt->rt_src;
+ iph->daddr=rt->rt_dst;
+ iph->check=0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ err = getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4);
+ }
+ else
+ err = getfrag(frag, (void *)iph, 0, length);
+
+ dev_unlock_list();
+
+ if (err)
+ goto error_fault;
+
+#ifdef CONFIG_FIREWALL
+ switch (call_out_firewall(PF_INET, rt->u.dst.dev, iph, NULL, &skb)) {
+ case FW_QUEUE:
+ kfree_skb(skb);
+ return 0;
+ case FW_BLOCK:
+ case FW_REJECT:
+ kfree_skb(skb);
+ err = -EPERM;
+ goto error;
+ }
+#endif
+
+ return rt->u.dst.output(skb);
+
+error_fault:
+ err = -EFAULT;
+ kfree_skb(skb);
+error:
+ ip_statistics.IpOutDiscards++;
+ return err;
+}
+
+
+
+/*
+ * This IP datagram is too large to be sent in one piece. Break it up into
+ * smaller pieces (each of size equal to IP header plus
+ * a block of the data of the original IP data part) that will yet fit in a
+ * single device frame, and queue such a frame for sending.
+ *
+ * Yes this is inefficient, feel free to submit a quicker one.
+ */
+
+void ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+{
+ struct iphdr *iph;
+ unsigned char *raw;
+ unsigned char *ptr;
+ struct device *dev;
+ struct sk_buff *skb2;
+ unsigned int mtu, hlen, left, len;
+ int offset;
+ int not_last_frag;
+ struct rtable *rt = (struct rtable*)skb->dst;
+
+ dev = rt->u.dst.dev;
+
+ /*
+ * Point into the IP datagram header.
+ */
+
+ raw = skb->nh.raw;
+ iph = (struct iphdr*)raw;
+
+ /*
+ * Setup starting values.
+ */
+
+ hlen = iph->ihl * 4;
+ left = ntohs(iph->tot_len) - hlen; /* Space per frame */
+ mtu = rt->u.dst.pmtu - hlen; /* Size of data space */
+ ptr = raw + hlen; /* Where to start from */
+
+ /*
+ * The protocol doesn't seem to say what to do in the case that the
+ * frame + options doesn't fit the mtu. As it used to fall down dead
+ * in this case we were fortunate it didn't happen
+ *
+ * It is impossible, because mtu>=68. --ANK (980801)
+ */
+
+#ifdef CONFIG_NET_PARANOIA
+ if (mtu<8)
+ goto fail;
+#endif
+
+ /*
+ * Fragment the datagram.
+ */
+
+ offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3;
+ not_last_frag = iph->frag_off & htons(IP_MF);
+
+ /*
+ * Keep copying data until we run out.
+ */
+
+ while(left > 0) {
+ len = left;
+ /* IF: it doesn't fit, use 'mtu' - the data space left */
+ if (len > mtu)
+ len = mtu;
+ /* IF: we are not sending up to and including the packet end
+ then align the next start on an eight byte boundary */
+ if (len < left) {
+ len &= ~7;
+ }
+ /*
+ * Allocate buffer.
+ */
+
+ if ((skb2 = alloc_skb(len+hlen+dev->hard_header_len+15,GFP_ATOMIC)) == NULL) {
+ NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n"));
+ goto fail;
+ }
+
+ /*
+ * Set up data on packet
+ */
+
+ skb2->pkt_type = skb->pkt_type;
+ skb2->priority = skb->priority;
+ skb_reserve(skb2, (dev->hard_header_len+15)&~15);
+ skb_put(skb2, len + hlen);
+ skb2->nh.raw = skb2->data;
+ skb2->h.raw = skb2->data + hlen;
+
+ /*
+ * Charge the memory for the fragment to any owner
+ * it might possess
+ */
+
+ if (skb->sk)
+ skb_set_owner_w(skb2, skb->sk);
+ skb2->dst = dst_clone(skb->dst);
+
+ /*
+ * Copy the packet header into the new buffer.
+ */
+
+ memcpy(skb2->nh.raw, raw, hlen);
+
+ /*
+ * Copy a block of the IP datagram.
+ */
+ memcpy(skb2->h.raw, ptr, len);
+ left -= len;
+
+ /*
+ * Fill in the new header fields.
+ */
+ iph = skb2->nh.iph;
+ iph->frag_off = htons((offset >> 3));
+
+ /* ANK: dirty, but effective trick. Upgrade options only if
+ * the segment to be fragmented was THE FIRST (otherwise,
+ * options are already fixed) and make it ONCE
+ * on the initial skb, so that all the following fragments
+ * will inherit fixed options.
+ */
+ if (offset == 0)
+ ip_options_fragment(skb);
+
+ /*
+ * Added AC : If we are fragmenting a fragment that's not the
+ * last fragment then keep MF on each bit
+ */
+ if (left > 0 || not_last_frag)
+ iph->frag_off |= htons(IP_MF);
+ ptr += len;
+ offset += len;
+
+ /*
+ * Put this fragment into the sending queue.
+ */
+
+ ip_statistics.IpFragCreates++;
+
+ iph->tot_len = htons(len + hlen);
+
+ ip_send_check(iph);
+
+ output(skb2);
+ }
+ kfree_skb(skb);
+ ip_statistics.IpFragOKs++;
+ return;
+
+fail:
+ kfree_skb(skb);
+ ip_statistics.IpFragFails++;
+}
+
+/*
+ * Fetch data from kernel space and fill in checksum if needed.
+ */
+static int ip_reply_glue_bits(const void *dptr, char *to, unsigned int offset,
+ unsigned int fraglen)
+{
+ struct ip_reply_arg *dp = (struct ip_reply_arg*)dptr;
+ u16 *pktp = (u16 *)to;
+ struct iovec *iov;
+ int len;
+ int hdrflag = 1;
+
+ iov = &dp->iov[0];
+ if (offset >= iov->iov_len) {
+ offset -= iov->iov_len;
+ iov++;
+ hdrflag = 0;
+ }
+ len = iov->iov_len - offset;
+ if (fraglen > len) { /* overlapping. */
+ dp->csum = csum_partial_copy_nocheck(iov->iov_base+offset, to, len,
+ dp->csum);
+ offset = 0;
+ fraglen -= len;
+ to += len;
+ iov++;
+ }
+
+ dp->csum = csum_partial_copy_nocheck(iov->iov_base+offset, to, fraglen,
+ dp->csum);
+
+ if (hdrflag && dp->csumoffset)
+ *(pktp + dp->csumoffset) = csum_fold(dp->csum); /* fill in checksum */
+ return 0;
+}
+
+/*
+ * Generic function to send a packet as reply to another packet.
+ * Used to send TCP resets so far. ICMP should use this function too.
+ *
+ * Should run single threaded per socket because it uses the sock
+ * structure to pass arguments.
+ */
+void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
+ unsigned int len)
+{
+ struct {
+ struct ip_options opt;
+ char data[40];
+ } replyopts;
+ struct ipcm_cookie ipc;
+ u32 daddr;
+ struct rtable *rt = (struct rtable*)skb->dst;
+
+ if (ip_options_echo(&replyopts.opt, skb))
+ return;
+
+ sk->ip_tos = skb->nh.iph->tos;
+ sk->priority = skb->priority;
+ sk->protocol = skb->nh.iph->protocol;
+
+ daddr = ipc.addr = rt->rt_src;
+ ipc.opt = &replyopts.opt;
+
+ if (ipc.opt->srr)
+ daddr = replyopts.opt.faddr;
+ if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
+ return;
+
+ /* And let IP do all the hard work. */
+ ip_build_xmit(sk, ip_reply_glue_bits, arg, len, &ipc, rt, MSG_DONTWAIT);
+ ip_rt_put(rt);
+}
+
+/*
+ * IP protocol layer initialiser
+ */
+
+static struct packet_type ip_packet_type =
+{
+ __constant_htons(ETH_P_IP),
+ NULL, /* All devices */
+ ip_rcv,
+ NULL,
+ NULL,
+};
+
+
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IP_MULTICAST
+static struct proc_dir_entry proc_net_igmp = {
+ PROC_NET_IGMP, 4, "igmp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ ip_mc_procinfo
+};
+#endif
+#endif
+
+/*
+ * IP registers the packet type and then calls the subprotocol initialisers
+ */
+
+__initfunc(void ip_init(void))
+{
+ dev_add_pack(&ip_packet_type);
+
+ ip_rt_init();
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IP_MULTICAST
+ proc_net_register(&proc_net_igmp);
+#endif
+#endif
+}
+
diff --git a/pfinet/linux-src/net/ipv4/ip_sockglue.c b/pfinet/linux-src/net/ipv4/ip_sockglue.c
new file mode 100644
index 00000000..369a6770
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ip_sockglue.c
@@ -0,0 +1,739 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * The IP to API glue.
+ *
+ * Version: $Id: ip_sockglue.c,v 1.42 1999/04/22 10:07:34 davem Exp $
+ *
+ * Authors: see ip.c
+ *
+ * Fixes:
+ * Many : Split from ip.c , see ip.c for history.
+ * Martin Mares : TOS setting fixed.
+ * Alan Cox : Fixed a couple of oopses in Martin's
+ * TOS tweaks.
+ * Mike McLagan : Routing by source
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/igmp.h>
+#include <linux/firewall.h>
+#include <linux/ip_fw.h>
+#include <linux/route.h>
+#include <linux/mroute.h>
+#include <net/route.h>
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <net/transp_v6.h>
+#endif
+
+#ifdef CONFIG_IP_MASQUERADE
+#include <linux/ip_masq.h>
+#endif
+
+#include <linux/errqueue.h>
+#include <asm/uaccess.h>
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+#define IP_CMSG_PKTINFO 1
+#define IP_CMSG_TTL 2
+#define IP_CMSG_TOS 4
+#define IP_CMSG_RECVOPTS 8
+#define IP_CMSG_RETOPTS 16
+
+/*
+ * SOL_IP control messages.
+ */
+
+static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
+{
+ struct in_pktinfo info;
+ struct rtable *rt = (struct rtable *)skb->dst;
+
+ info.ipi_addr.s_addr = skb->nh.iph->daddr;
+ if (rt) {
+ info.ipi_ifindex = rt->rt_iif;
+ info.ipi_spec_dst.s_addr = rt->rt_spec_dst;
+ } else {
+ info.ipi_ifindex = 0;
+ info.ipi_spec_dst.s_addr = 0;
+ }
+
+ put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
+}
+
+static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
+{
+ int ttl = skb->nh.iph->ttl;
+ put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl);
+}
+
+static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
+{
+ put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos);
+}
+
+static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
+{
+ if (IPCB(skb)->opt.optlen == 0)
+ return;
+
+ put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen, skb->nh.iph+1);
+}
+
+
+void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
+{
+ unsigned char optbuf[sizeof(struct ip_options) + 40];
+ struct ip_options * opt = (struct ip_options*)optbuf;
+
+ if (IPCB(skb)->opt.optlen == 0)
+ return;
+
+ if (ip_options_echo(opt, skb)) {
+ msg->msg_flags |= MSG_CTRUNC;
+ return;
+ }
+ ip_options_undo(opt);
+
+ put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
+}
+
+
+void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
+{
+ unsigned flags = skb->sk->ip_cmsg_flags;
+
+ /* Ordered by supposed usage frequency */
+ if (flags & 1)
+ ip_cmsg_recv_pktinfo(msg, skb);
+ if ((flags>>=1) == 0)
+ return;
+
+ if (flags & 1)
+ ip_cmsg_recv_ttl(msg, skb);
+ if ((flags>>=1) == 0)
+ return;
+
+ if (flags & 1)
+ ip_cmsg_recv_tos(msg, skb);
+ if ((flags>>=1) == 0)
+ return;
+
+ if (flags & 1)
+ ip_cmsg_recv_opts(msg, skb);
+ if ((flags>>=1) == 0)
+ return;
+
+ if (flags & 1)
+ ip_cmsg_recv_retopts(msg, skb);
+}
+
+int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
+{
+ int err;
+ struct cmsghdr *cmsg;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
+ (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
+ + cmsg->cmsg_len) > msg->msg_controllen) {
+ return -EINVAL;
+ }
+ if (cmsg->cmsg_level != SOL_IP)
+ continue;
+ switch (cmsg->cmsg_type) {
+ case IP_RETOPTS:
+ err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
+ err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40, 0);
+ if (err)
+ return err;
+ break;
+ case IP_PKTINFO:
+ {
+ struct in_pktinfo *info;
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
+ return -EINVAL;
+ info = (struct in_pktinfo *)CMSG_DATA(cmsg);
+ ipc->oif = info->ipi_ifindex;
+ ipc->addr = info->ipi_spec_dst.s_addr;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+
+/* Special input handler for packets catched by router alert option.
+ They are selected only by protocol field, and then processed likely
+ local ones; but only if someone wants them! Otherwise, router
+ not running rsvpd will kill RSVP.
+
+ It is user level problem, what it will make with them.
+ I have no idea, how it will masquearde or NAT them (it is joke, joke :-)),
+ but receiver should be enough clever f.e. to forward mtrace requests,
+ sent to multicast group to reach destination designated router.
+ */
+struct ip_ra_chain *ip_ra_chain;
+
+int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *))
+{
+ struct ip_ra_chain *ra, *new_ra, **rap;
+
+ if (sk->type != SOCK_RAW || sk->num == IPPROTO_RAW)
+ return -EINVAL;
+
+ new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+
+ for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+ if (ra->sk == sk) {
+ if (on) {
+ if (new_ra)
+ kfree(new_ra);
+ return -EADDRINUSE;
+ }
+ *rap = ra->next;
+ synchronize_bh();
+
+ if (ra->destructor)
+ ra->destructor(sk);
+ kfree(ra);
+ return 0;
+ }
+ }
+ if (new_ra == NULL)
+ return -ENOBUFS;
+ new_ra->sk = sk;
+ new_ra->destructor = destructor;
+
+ new_ra->next = ra;
+ wmb();
+ *rap = new_ra;
+
+ return 0;
+}
+
+void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+ u16 port, u32 info, u8 *payload)
+{
+ struct sock_exterr_skb *serr;
+
+ if (!sk->ip_recverr)
+ return;
+
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ serr = SKB_EXT_ERR(skb);
+ serr->ee.ee_errno = err;
+ serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
+ serr->ee.ee_type = skb->h.icmph->type;
+ serr->ee.ee_code = skb->h.icmph->code;
+ serr->ee.ee_pad = 0;
+ serr->ee.ee_info = info;
+ serr->ee.ee_data = 0;
+ serr->addr_offset = (u8*)&(((struct iphdr*)(skb->h.icmph+1))->daddr) - skb->nh.raw;
+ serr->port = port;
+
+ skb->h.raw = payload;
+ skb_pull(skb, payload - skb->data);
+
+ if (sock_queue_err_skb(sk, skb))
+ kfree_skb(skb);
+}
+
+void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
+{
+ struct sock_exterr_skb *serr;
+ struct iphdr *iph;
+ struct sk_buff *skb;
+
+ if (!sk->ip_recverr)
+ return;
+
+ skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ iph = (struct iphdr*)skb_put(skb, sizeof(struct iphdr));
+ skb->nh.iph = iph;
+ iph->daddr = daddr;
+
+ serr = SKB_EXT_ERR(skb);
+ serr->ee.ee_errno = err;
+ serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
+ serr->ee.ee_type = 0;
+ serr->ee.ee_code = 0;
+ serr->ee.ee_pad = 0;
+ serr->ee.ee_info = info;
+ serr->ee.ee_data = 0;
+ serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
+ serr->port = port;
+
+ skb->h.raw = skb->tail;
+ skb_pull(skb, skb->tail - skb->data);
+
+ if (sock_queue_err_skb(sk, skb))
+ kfree_skb(skb);
+}
+
+/*
+ * Handle MSG_ERRQUEUE
+ */
+int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct sock_exterr_skb *serr;
+ struct sk_buff *skb, *skb2;
+ struct sockaddr_in *sin;
+ struct {
+ struct sock_extended_err ee;
+ struct sockaddr_in offender;
+ } errhdr;
+ int err;
+ int copied;
+
+ err = -EAGAIN;
+ skb = skb_dequeue(&sk->error_queue);
+ if (skb == NULL)
+ goto out;
+
+ copied = skb->len;
+ if (copied > len) {
+ msg->msg_flags |= MSG_TRUNC;
+ copied = len;
+ }
+ err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+ if (err)
+ goto out_free_skb;
+
+ serr = SKB_EXT_ERR(skb);
+
+ sin = (struct sockaddr_in *)msg->msg_name;
+ if (sin) {
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
+ sin->sin_port = serr->port;
+ }
+
+ memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
+ sin = &errhdr.offender;
+ sin->sin_family = AF_UNSPEC;
+ if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = skb->nh.iph->saddr;
+ if (sk->ip_cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+ }
+
+ put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);
+
+ /* Now we could try to dump offended packet options */
+
+ msg->msg_flags |= MSG_ERRQUEUE;
+ err = copied;
+
+ /* Reset and regenerate socket error */
+ sk->err = 0;
+ if ((skb2 = skb_peek(&sk->error_queue)) != NULL) {
+ sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+ sk->error_report(sk);
+ }
+
+out_free_skb:
+ kfree_skb(skb);
+out:
+ return err;
+}
+
+
+/*
+ * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
+ * an IP socket.
+ *
+ * We implement IP_TOS (type of service), IP_TTL (time to live).
+ */
+
+int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
+{
+ int val=0,err;
+#if defined(CONFIG_IP_FIREWALL)
+ char tmp_fw[MAX(sizeof(struct ip_fwtest),sizeof(struct ip_fwnew))];
+#endif
+ if(optlen>=sizeof(int)) {
+ if(get_user(val, (int *) optval))
+ return -EFAULT;
+ } else if(optlen>=sizeof(char)) {
+ unsigned char ucval;
+ if(get_user(ucval, (unsigned char *) optval))
+ return -EFAULT;
+ val = (int)ucval;
+ }
+ /* If optlen==0, it is equivalent to val == 0 */
+
+ if(level!=SOL_IP)
+ return -ENOPROTOOPT;
+#ifdef CONFIG_IP_MROUTE
+ if(optname>=MRT_BASE && optname <=MRT_BASE+10)
+ {
+ return ip_mroute_setsockopt(sk,optname,optval,optlen);
+ }
+#endif
+
+ switch(optname)
+ {
+ case IP_OPTIONS:
+ {
+ struct ip_options * opt = NULL;
+ if (optlen > 40 || optlen < 0)
+ return -EINVAL;
+ err = ip_options_get(&opt, optval, optlen, 1);
+ if (err)
+ return err;
+ lock_sock(sk);
+ if (sk->type == SOCK_STREAM) {
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ if (sk->family == PF_INET ||
+ ((tcp_connected(sk->state) || sk->state == TCP_SYN_SENT)
+ && sk->daddr != LOOPBACK4_IPV6)) {
+#endif
+ if (opt)
+ tp->ext_header_len = opt->optlen;
+ tcp_sync_mss(sk, tp->pmtu_cookie);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ }
+#endif
+ }
+ opt = xchg(&sk->opt, opt);
+ release_sock(sk);
+ if (opt)
+ kfree_s(opt, sizeof(struct ip_options) + opt->optlen);
+ return 0;
+ }
+ case IP_PKTINFO:
+ if (val)
+ sk->ip_cmsg_flags |= IP_CMSG_PKTINFO;
+ else
+ sk->ip_cmsg_flags &= ~IP_CMSG_PKTINFO;
+ return 0;
+ case IP_RECVTTL:
+ if (val)
+ sk->ip_cmsg_flags |= IP_CMSG_TTL;
+ else
+ sk->ip_cmsg_flags &= ~IP_CMSG_TTL;
+ return 0;
+ case IP_RECVTOS:
+ if (val)
+ sk->ip_cmsg_flags |= IP_CMSG_TOS;
+ else
+ sk->ip_cmsg_flags &= ~IP_CMSG_TOS;
+ return 0;
+ case IP_RECVOPTS:
+ if (val)
+ sk->ip_cmsg_flags |= IP_CMSG_RECVOPTS;
+ else
+ sk->ip_cmsg_flags &= ~IP_CMSG_RECVOPTS;
+ return 0;
+ case IP_RETOPTS:
+ if (val)
+ sk->ip_cmsg_flags |= IP_CMSG_RETOPTS;
+ else
+ sk->ip_cmsg_flags &= ~IP_CMSG_RETOPTS;
+ return 0;
+ case IP_TOS: /* This sets both TOS and Precedence */
+ /* Reject setting of unused bits */
+ if (val & ~(IPTOS_TOS_MASK|IPTOS_PREC_MASK))
+ return -EINVAL;
+ if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP &&
+ !capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sk->ip_tos != val) {
+ lock_sock(sk);
+ sk->ip_tos=val;
+ sk->priority = rt_tos2priority(val);
+ dst_release(xchg(&sk->dst_cache, NULL));
+ release_sock(sk);
+ }
+ return 0;
+ case IP_TTL:
+ if (optlen<1)
+ return -EINVAL;
+ if(val==-1)
+ val = ip_statistics.IpDefaultTTL;
+ if(val<1||val>255)
+ return -EINVAL;
+ sk->ip_ttl=val;
+ return 0;
+ case IP_HDRINCL:
+ if(sk->type!=SOCK_RAW)
+ return -ENOPROTOOPT;
+ sk->ip_hdrincl=val?1:0;
+ return 0;
+ case IP_MTU_DISCOVER:
+ if (val<0 || val>2)
+ return -EINVAL;
+ sk->ip_pmtudisc = val;
+ return 0;
+ case IP_RECVERR:
+ sk->ip_recverr = !!val;
+ if (!val)
+ skb_queue_purge(&sk->error_queue);
+ return 0;
+ case IP_MULTICAST_TTL:
+ if (optlen<1)
+ return -EINVAL;
+ if (val==-1)
+ val = 1;
+ if (val < 0 || val > 255)
+ return -EINVAL;
+ sk->ip_mc_ttl=val;
+ return 0;
+ case IP_MULTICAST_LOOP:
+ if (optlen<1)
+ return -EINVAL;
+ sk->ip_mc_loop = val ? 1 : 0;
+ return 0;
+ case IP_MULTICAST_IF:
+ {
+ struct ip_mreqn mreq;
+ struct device *dev = NULL;
+
+ /*
+ * Check the arguments are allowable
+ */
+
+ if (optlen >= sizeof(struct ip_mreqn)) {
+ if (copy_from_user(&mreq,optval,sizeof(mreq)))
+ return -EFAULT;
+ } else {
+ memset(&mreq, 0, sizeof(mreq));
+ if (optlen >= sizeof(struct in_addr) &&
+ copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
+ return -EFAULT;
+ }
+
+ if (!mreq.imr_ifindex) {
+ if (mreq.imr_address.s_addr == INADDR_ANY) {
+ sk->ip_mc_index = 0;
+ sk->ip_mc_addr = 0;
+ return 0;
+ }
+ dev = ip_dev_find(mreq.imr_address.s_addr);
+ } else
+ dev = dev_get_by_index(mreq.imr_ifindex);
+
+ if (!dev)
+ return -EADDRNOTAVAIL;
+
+ if (sk->bound_dev_if && dev->ifindex != sk->bound_dev_if)
+ return -EINVAL;
+
+ sk->ip_mc_index = mreq.imr_ifindex;
+ sk->ip_mc_addr = mreq.imr_address.s_addr;
+ return 0;
+ }
+
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ {
+ struct ip_mreqn mreq;
+
+ if (optlen < sizeof(struct ip_mreq))
+ return -EINVAL;
+ if (optlen >= sizeof(struct ip_mreqn)) {
+ if(copy_from_user(&mreq,optval,sizeof(mreq)))
+ return -EFAULT;
+ } else {
+ memset(&mreq, 0, sizeof(mreq));
+ if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
+ return -EFAULT;
+ }
+
+ if (optname == IP_ADD_MEMBERSHIP)
+ return ip_mc_join_group(sk,&mreq);
+ else
+ return ip_mc_leave_group(sk,&mreq);
+ }
+ case IP_ROUTER_ALERT:
+ return ip_ra_control(sk, val ? 1 : 0, NULL);
+
+#ifdef CONFIG_IP_FIREWALL
+ case IP_FW_MASQ_TIMEOUTS:
+ case IP_FW_APPEND:
+ case IP_FW_REPLACE:
+ case IP_FW_DELETE:
+ case IP_FW_DELETE_NUM:
+ case IP_FW_INSERT:
+ case IP_FW_FLUSH:
+ case IP_FW_ZERO:
+ case IP_FW_CHECK:
+ case IP_FW_CREATECHAIN:
+ case IP_FW_DELETECHAIN:
+ case IP_FW_POLICY:
+ if(!capable(CAP_NET_ADMIN))
+ return -EACCES;
+ if(optlen>sizeof(tmp_fw) || optlen<1)
+ return -EINVAL;
+ if(copy_from_user(&tmp_fw,optval,optlen))
+ return -EFAULT;
+ err=ip_fw_ctl(optname, &tmp_fw,optlen);
+ return -err; /* -0 is 0 after all */
+#endif /* CONFIG_IP_FIREWALL */
+#ifdef CONFIG_IP_MASQUERADE
+ case IP_FW_MASQ_CTL:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if(optlen<1)
+ return -EINVAL;
+ err=ip_masq_uctl(optname, optval ,optlen);
+ return err;
+
+#endif
+ default:
+ return(-ENOPROTOOPT);
+ }
+}
+
+/*
+ * Get the options. Note for future reference. The GET of IP options gets the
+ * _received_ ones. The set sets the _sent_ ones.
+ */
+
+int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
+{
+ int val;
+ int len;
+
+ if(level!=SOL_IP)
+ return -EOPNOTSUPP;
+
+#ifdef CONFIG_IP_MROUTE
+ if(optname>=MRT_BASE && optname <=MRT_BASE+10)
+ {
+ return ip_mroute_getsockopt(sk,optname,optval,optlen);
+ }
+#endif
+
+ if(get_user(len,optlen))
+ return -EFAULT;
+
+ switch(optname)
+ {
+ case IP_OPTIONS:
+ {
+ unsigned char optbuf[sizeof(struct ip_options)+40];
+ struct ip_options * opt = (struct ip_options*)optbuf;
+ lock_sock(sk);
+ opt->optlen = 0;
+ if (sk->opt)
+ memcpy(optbuf, sk->opt, sizeof(struct ip_options)+sk->opt->optlen);
+ release_sock(sk);
+ if (opt->optlen == 0)
+ return put_user(0, optlen);
+
+ ip_options_undo(opt);
+
+ len=min(len, opt->optlen);
+ if(put_user(len, optlen))
+ return -EFAULT;
+ if(copy_to_user(optval, opt->__data, len))
+ return -EFAULT;
+ return 0;
+ }
+ case IP_PKTINFO:
+ val = (sk->ip_cmsg_flags & IP_CMSG_PKTINFO) != 0;
+ break;
+ case IP_RECVTTL:
+ val = (sk->ip_cmsg_flags & IP_CMSG_TTL) != 0;
+ break;
+ case IP_RECVTOS:
+ val = (sk->ip_cmsg_flags & IP_CMSG_TOS) != 0;
+ break;
+ case IP_RECVOPTS:
+ val = (sk->ip_cmsg_flags & IP_CMSG_RECVOPTS) != 0;
+ break;
+ case IP_RETOPTS:
+ val = (sk->ip_cmsg_flags & IP_CMSG_RETOPTS) != 0;
+ break;
+ case IP_TOS:
+ val=sk->ip_tos;
+ break;
+ case IP_TTL:
+ val=sk->ip_ttl;
+ break;
+ case IP_HDRINCL:
+ val=sk->ip_hdrincl;
+ break;
+ case IP_MTU_DISCOVER:
+ val=sk->ip_pmtudisc;
+ break;
+ case IP_MTU:
+ val = 0;
+ lock_sock(sk);
+ if (sk->dst_cache)
+ val = sk->dst_cache->pmtu;
+ release_sock(sk);
+ if (!val)
+ return -ENOTCONN;
+ break;
+ case IP_RECVERR:
+ val=sk->ip_recverr;
+ break;
+ case IP_MULTICAST_TTL:
+ val=sk->ip_mc_ttl;
+ break;
+ case IP_MULTICAST_LOOP:
+ val=sk->ip_mc_loop;
+ break;
+ case IP_MULTICAST_IF:
+ {
+ struct ip_mreqn mreq;
+ len = min(len,sizeof(struct ip_mreqn));
+ if(put_user(len, optlen))
+ return -EFAULT;
+ mreq.imr_ifindex = sk->ip_mc_index;
+ mreq.imr_address.s_addr = sk->ip_mc_addr;
+ mreq.imr_multiaddr.s_addr = 0;
+ if(copy_to_user((void *)optval, &mreq, len))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ return(-ENOPROTOOPT);
+ }
+
+ if (len < sizeof(int) && len > 0 && val>=0 && val<255) {
+ unsigned char ucval = (unsigned char)val;
+ len = 1;
+ if(put_user(len, optlen))
+ return -EFAULT;
+ if(copy_to_user(optval,&ucval,1))
+ return -EFAULT;
+ } else {
+ len=min(sizeof(int),len);
+ if(put_user(len, optlen))
+ return -EFAULT;
+ if(copy_to_user(optval,&val,len))
+ return -EFAULT;
+ }
+ return 0;
+}
diff --git a/pfinet/linux-src/net/ipv4/ipconfig.c b/pfinet/linux-src/net/ipv4/ipconfig.c
new file mode 100644
index 00000000..bb95824c
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ipconfig.c
@@ -0,0 +1,970 @@
+/*
+ * $Id: ipconfig.c,v 1.20.2.1 1999/06/28 11:33:27 davem Exp $
+ *
+ * Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
+ * information to configure own IP address and routes.
+ *
+ * Copyright (C) 1996--1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *
+ * Derived from network configuration code in fs/nfs/nfsroot.c,
+ * originally Copyright (C) 1995, 1996 Gero Kuhlmann and me.
+ *
+ * BOOTP rewritten to construct and analyse packets itself instead
+ * of misusing the IP layer. num_bugs_causing_wrong_arp_replies--;
+ * -- MJ, December 1998
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/utsname.h>
+#include <linux/in.h>
+#include <linux/if.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/socket.h>
+#include <linux/route.h>
+#include <linux/udp.h>
+#include <net/arp.h>
+#include <net/ip.h>
+#include <net/ipconfig.h>
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+
+/* Define this to allow debugging output */
+#undef IPCONFIG_DEBUG
+
+#ifdef IPCONFIG_DEBUG
+#define DBG(x) printk x
+#else
+#define DBG(x) do { } while(0)
+#endif
+
+/* Define the timeout for waiting for a RARP/BOOTP reply */
+#define CONF_BASE_TIMEOUT (HZ*5) /* Initial timeout: 5 seconds */
+#define CONF_RETRIES 10 /* 10 retries */
+#define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */
+#define CONF_TIMEOUT_MULT *5/4 /* Rate of timeout growth */
+#define CONF_TIMEOUT_MAX (HZ*30) /* Maximum allowed timeout */
+
+/* IP configuration */
+static char user_dev_name[IFNAMSIZ] __initdata = { 0, };/* Name of user-selected boot device */
+u32 ic_myaddr __initdata = INADDR_NONE; /* My IP address */
+u32 ic_servaddr __initdata = INADDR_NONE; /* Server IP address */
+u32 ic_gateway __initdata = INADDR_NONE; /* Gateway IP address */
+u32 ic_netmask __initdata = INADDR_NONE; /* Netmask for local subnet */
+int ic_enable __initdata = 1; /* Automatic IP configuration enabled */
+int ic_host_name_set __initdata = 0; /* Host name configured manually */
+int ic_set_manually __initdata = 0; /* IPconfig parameters set manually */
+
+u32 root_server_addr __initdata = INADDR_NONE; /* Address of boot server */
+u8 root_server_path[256] __initdata = { 0, }; /* Path to mount as root */
+
+#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
+
+#define CONFIG_IP_PNP_DYNAMIC
+
+static int ic_proto_enabled __initdata = 0 /* Protocols enabled */
+#ifdef CONFIG_IP_PNP_BOOTP
+ | IC_BOOTP
+#endif
+#ifdef CONFIG_IP_PNP_RARP
+ | IC_RARP
+#endif
+ ;
+static int ic_got_reply __initdata = 0; /* Protocol(s) we got reply from */
+
+#else
+
+static int ic_proto_enabled __initdata = 0;
+
+#endif
+
+static int ic_proto_have_if __initdata = 0;
+
+/*
+ * Network devices
+ */
+
+struct ic_device {
+ struct ic_device *next;
+ struct device *dev;
+ unsigned short flags;
+ int able;
+};
+
+static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
+static struct device *ic_dev __initdata = NULL; /* Selected device */
+
+static int __init ic_open_devs(void)
+{
+ struct ic_device *d, **last;
+ struct device *dev;
+ unsigned short oflags;
+
+ last = &ic_first_dev;
+ for (dev = dev_base; dev; dev = dev->next)
+ if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
+ (!(dev->flags & IFF_LOOPBACK) &&
+ (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
+ strncmp(dev->name, "dummy", 5))) {
+ int able = 0;
+ if (dev->mtu >= 364)
+ able |= IC_BOOTP;
+ else
+ printk(KERN_WARNING "BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu);
+ if (!(dev->flags & IFF_NOARP))
+ able |= IC_RARP;
+ able &= ic_proto_enabled;
+ if (ic_proto_enabled && !able)
+ continue;
+ oflags = dev->flags;
+ if (dev_change_flags(dev, oflags | IFF_UP) < 0) {
+ printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name);
+ continue;
+ }
+ if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL)))
+ return -1;
+ d->dev = dev;
+ *last = d;
+ last = &d->next;
+ d->flags = oflags;
+ d->able = able;
+ ic_proto_have_if |= able;
+ DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able));
+ }
+ *last = NULL;
+
+ if (!ic_first_dev) {
+ if (user_dev_name[0])
+ printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name);
+ else
+ printk(KERN_ERR "IP-Config: No network devices available.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void __init ic_close_devs(void)
+{
+ struct ic_device *d, *next;
+ struct device *dev;
+
+ next = ic_first_dev;
+ while ((d = next)) {
+ next = d->next;
+ dev = d->dev;
+ if (dev != ic_dev) {
+ DBG(("IP-Config: Downing %s\n", dev->name));
+ dev_change_flags(dev, d->flags);
+ }
+ kfree_s(d, sizeof(struct ic_device));
+ }
+}
+
+/*
+ * Interface to various network functions.
+ */
+
+static inline void
+set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port)
+{
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr;
+ sin->sin_port = port;
+}
+
+static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg)
+{
+ int res;
+
+ mm_segment_t oldfs = get_fs();
+ set_fs(get_ds());
+ res = devinet_ioctl(cmd, arg);
+ set_fs(oldfs);
+ return res;
+}
+
+static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg)
+{
+ int res;
+
+ mm_segment_t oldfs = get_fs();
+ set_fs(get_ds());
+ res = ip_rt_ioctl(cmd, arg);
+ set_fs(oldfs);
+ return res;
+}
+
+/*
+ * Set up interface addresses and routes.
+ */
+
+static int __init ic_setup_if(void)
+{
+ struct ifreq ir;
+ struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr;
+ int err;
+
+ memset(&ir, 0, sizeof(ir));
+ strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->name);
+ set_sockaddr(sin, ic_myaddr, 0);
+ if ((err = ic_dev_ioctl(SIOCSIFADDR, &ir)) < 0) {
+ printk(KERN_ERR "IP-Config: Unable to set interface address (%d).\n", err);
+ return -1;
+ }
+ set_sockaddr(sin, ic_netmask, 0);
+ if ((err = ic_dev_ioctl(SIOCSIFNETMASK, &ir)) < 0) {
+ printk(KERN_ERR "IP-Config: Unable to set interface netmask (%d).\n", err);
+ return -1;
+ }
+ set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0);
+ if ((err = ic_dev_ioctl(SIOCSIFBRDADDR, &ir)) < 0) {
+ printk(KERN_ERR "IP-Config: Unable to set interface broadcast address (%d).\n", err);
+ return -1;
+ }
+ return 0;
+}
+
+static int __init ic_setup_routes(void)
+{
+ /* No need to setup device routes, only the default route... */
+
+ if (ic_gateway != INADDR_NONE) {
+ struct rtentry rm;
+ int err;
+
+ memset(&rm, 0, sizeof(rm));
+ if ((ic_gateway ^ ic_myaddr) & ic_netmask) {
+ printk(KERN_ERR "IP-Config: Gateway not on directly connected network.\n");
+ return -1;
+ }
+ set_sockaddr((struct sockaddr_in *) &rm.rt_dst, 0, 0);
+ set_sockaddr((struct sockaddr_in *) &rm.rt_genmask, 0, 0);
+ set_sockaddr((struct sockaddr_in *) &rm.rt_gateway, ic_gateway, 0);
+ rm.rt_flags = RTF_UP | RTF_GATEWAY;
+ if ((err = ic_route_ioctl(SIOCADDRT, &rm)) < 0) {
+ printk(KERN_ERR "IP-Config: Cannot add default route (%d).\n", err);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Fill in default values for all missing parameters.
+ */
+
+static int __init ic_defaults(void)
+{
+ /*
+ * At this point we have no userspace running so need not
+ * claim locks on system_utsname
+ */
+
+ if (!ic_host_name_set)
+ strcpy(system_utsname.nodename, in_ntoa(ic_myaddr));
+
+ if (root_server_addr == INADDR_NONE)
+ root_server_addr = ic_servaddr;
+
+ if (ic_netmask == INADDR_NONE) {
+ if (IN_CLASSA(ntohl(ic_myaddr)))
+ ic_netmask = htonl(IN_CLASSA_NET);
+ else if (IN_CLASSB(ntohl(ic_myaddr)))
+ ic_netmask = htonl(IN_CLASSB_NET);
+ else if (IN_CLASSC(ntohl(ic_myaddr)))
+ ic_netmask = htonl(IN_CLASSC_NET);
+ else {
+ printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr);
+ return -1;
+ }
+ printk("IP-Config: Guessing netmask %s\n", in_ntoa(ic_netmask));
+ }
+
+ return 0;
+}
+
+/*
+ * RARP support.
+ */
+
+#ifdef CONFIG_IP_PNP_RARP
+
+static int ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
+
+static struct packet_type rarp_packet_type __initdata = {
+ __constant_htons(ETH_P_RARP),
+ NULL, /* Listen to all devices */
+ ic_rarp_recv,
+ NULL,
+ NULL
+};
+
+static inline void ic_rarp_init(void)
+{
+ dev_add_pack(&rarp_packet_type);
+}
+
+static inline void ic_rarp_cleanup(void)
+{
+ dev_remove_pack(&rarp_packet_type);
+}
+
+/*
+ * Process received RARP packet.
+ */
+static int __init
+ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+ struct arphdr *rarp = (struct arphdr *)skb->h.raw;
+ unsigned char *rarp_ptr = (unsigned char *) (rarp + 1);
+ unsigned long sip, tip;
+ unsigned char *sha, *tha; /* s for "source", t for "target" */
+
+ /* If we already have a reply, just drop the packet */
+ if (ic_got_reply)
+ goto drop;
+
+ /* If this test doesn't pass, it's not IP, or we should ignore it anyway */
+ if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
+ goto drop;
+
+ /* If it's not a RARP reply, delete it. */
+ if (rarp->ar_op != htons(ARPOP_RREPLY))
+ goto drop;
+
+ /* If it's not Ethernet, delete it. */
+ if (rarp->ar_pro != htons(ETH_P_IP))
+ goto drop;
+
+ /* Extract variable-width fields */
+ sha = rarp_ptr;
+ rarp_ptr += dev->addr_len;
+ memcpy(&sip, rarp_ptr, 4);
+ rarp_ptr += 4;
+ tha = rarp_ptr;
+ rarp_ptr += dev->addr_len;
+ memcpy(&tip, rarp_ptr, 4);
+
+ /* Discard packets which are not meant for us. */
+ if (memcmp(tha, dev->dev_addr, dev->addr_len))
+ goto drop;
+
+ /* Discard packets which are not from specified server. */
+ if (ic_servaddr != INADDR_NONE && ic_servaddr != sip)
+ goto drop;
+
+ /* Victory! The packet is what we were looking for! */
+ if (!ic_got_reply) {
+ ic_got_reply = IC_RARP;
+ ic_dev = dev;
+ if (ic_myaddr == INADDR_NONE)
+ ic_myaddr = tip;
+ ic_servaddr = sip;
+ }
+
+ /* And throw the packet out... */
+drop:
+ kfree_skb(skb);
+ return 0;
+}
+
+
+/*
+ * Send RARP request packet over all devices which allow RARP.
+ */
+static void __init ic_rarp_send(void)
+{
+ struct ic_device *d;
+
+ for (d=ic_first_dev; d; d=d->next)
+ if (d->able & IC_RARP) {
+ struct device *dev = d->dev;
+ arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
+ dev->dev_addr, dev->dev_addr);
+ }
+}
+
+#endif
+
+/*
+ * BOOTP support.
+ */
+
+#ifdef CONFIG_IP_PNP_BOOTP
+
+struct bootp_pkt { /* BOOTP packet format */
+ struct iphdr iph; /* IP header */
+ struct udphdr udph; /* UDP header */
+ u8 op; /* 1=request, 2=reply */
+ u8 htype; /* HW address type */
+ u8 hlen; /* HW address length */
+ u8 hops; /* Used only by gateways */
+ u32 xid; /* Transaction ID */
+ u16 secs; /* Seconds since we started */
+ u16 flags; /* Just what it says */
+ u32 client_ip; /* Client's IP address if known */
+ u32 your_ip; /* Assigned IP address */
+ u32 server_ip; /* Server's IP address */
+ u32 relay_ip; /* IP address of BOOTP relay */
+ u8 hw_addr[16]; /* Client's HW address */
+ u8 serv_name[64]; /* Server host name */
+ u8 boot_file[128]; /* Name of boot file */
+ u8 vendor_area[128]; /* Area for extensions */
+};
+
+#define BOOTP_REQUEST 1
+#define BOOTP_REPLY 2
+
+static u32 ic_bootp_xid;
+
+static int ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
+
+static struct packet_type bootp_packet_type __initdata = {
+ __constant_htons(ETH_P_IP),
+ NULL, /* Listen to all devices */
+ ic_bootp_recv,
+ NULL,
+ NULL
+};
+
+
+/*
+ * Initialize BOOTP extension fields in the request.
+ */
+static void __init ic_bootp_init_ext(u8 *e)
+{
+ *e++ = 99; /* RFC1048 Magic Cookie */
+ *e++ = 130;
+ *e++ = 83;
+ *e++ = 99;
+ *e++ = 1; /* Subnet mask request */
+ *e++ = 4;
+ e += 4;
+ *e++ = 3; /* Default gateway request */
+ *e++ = 4;
+ e += 4;
+ *e++ = 12; /* Host name request */
+ *e++ = 32;
+ e += 32;
+ *e++ = 40; /* NIS Domain name request */
+ *e++ = 32;
+ e += 32;
+ *e++ = 17; /* Boot path */
+ *e++ = 32;
+ e += 32;
+ *e = 255; /* End of the list */
+}
+
+
+/*
+ * Initialize the BOOTP mechanism.
+ */
+static inline void ic_bootp_init(void)
+{
+ get_random_bytes(&ic_bootp_xid, sizeof(u32));
+ DBG(("BOOTP: XID=%08x\n", ic_bootp_xid));
+ dev_add_pack(&bootp_packet_type);
+}
+
+
+/*
+ * BOOTP cleanup.
+ */
+static inline void ic_bootp_cleanup(void)
+{
+ dev_remove_pack(&bootp_packet_type);
+}
+
+
+/*
+ * Send BOOTP request to single interface.
+ */
+static void __init ic_bootp_send_if(struct ic_device *d, u32 jiffies)
+{
+ struct device *dev = d->dev;
+ struct sk_buff *skb;
+ struct bootp_pkt *b;
+ int hh_len = (dev->hard_header_len + 15) & ~15;
+ struct iphdr *h;
+
+ /* Allocate packet */
+ skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);
+ if (!skb)
+ return;
+ skb_reserve(skb, hh_len);
+ b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
+ memset(b, 0, sizeof(struct bootp_pkt));
+
+ /* Construct IP header */
+ skb->nh.iph = h = &b->iph;
+ h->version = 4;
+ h->ihl = 5;
+ h->tot_len = htons(sizeof(struct bootp_pkt));
+ h->frag_off = htons(IP_DF);
+ h->ttl = 64;
+ h->protocol = IPPROTO_UDP;
+ h->daddr = INADDR_BROADCAST;
+ h->check = ip_fast_csum((unsigned char *) h, h->ihl);
+
+ /* Construct UDP header */
+ b->udph.source = htons(68);
+ b->udph.dest = htons(67);
+ b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
+ /* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
+
+ /* Construct BOOTP header */
+ b->op = BOOTP_REQUEST;
+ b->htype = dev->type;
+ b->hlen = dev->addr_len;
+ memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
+ b->secs = htons(jiffies / HZ);
+ b->xid = ic_bootp_xid;
+ ic_bootp_init_ext(b->vendor_area);
+
+ /* Chain packet down the line... */
+ skb->dev = dev;
+ skb->protocol = __constant_htons(ETH_P_IP);
+ if ((dev->hard_header &&
+ dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) ||
+ dev_queue_xmit(skb) < 0)
+ printk("E");
+}
+
+
+/*
+ * Send BOOTP requests to all interfaces.
+ */
+static void __init ic_bootp_send(u32 jiffies)
+{
+ struct ic_device *d;
+
+ for(d=ic_first_dev; d; d=d->next)
+ if (d->able & IC_BOOTP)
+ ic_bootp_send_if(d, jiffies);
+}
+
+
+/*
+ * Copy BOOTP-supplied string if not already set.
+ */
+static int __init ic_bootp_string(char *dest, char *src, int len, int max)
+{
+ if (!len)
+ return 0;
+ if (len > max-1)
+ len = max-1;
+ strncpy(dest, src, len);
+ dest[len] = '\0';
+ return 1;
+}
+
+
+/*
+ * Process BOOTP extension.
+ */
+static void __init ic_do_bootp_ext(u8 *ext)
+{
+#ifdef IPCONFIG_DEBUG
+ u8 *c;
+
+ printk("BOOTP: Got extension %02x",*ext);
+ for(c=ext+2; c<ext+2+ext[1]; c++)
+ printk(" %02x", *c);
+ printk("\n");
+#endif
+
+ switch (*ext++) {
+ case 1: /* Subnet mask */
+ if (ic_netmask == INADDR_NONE)
+ memcpy(&ic_netmask, ext+1, 4);
+ break;
+ case 3: /* Default gateway */
+ if (ic_gateway == INADDR_NONE)
+ memcpy(&ic_gateway, ext+1, 4);
+ break;
+ case 12: /* Host name */
+ ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
+ ic_host_name_set = 1;
+ break;
+ case 40: /* NIS Domain name */
+ ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
+ break;
+ case 17: /* Root path */
+ if (!root_server_path[0])
+ ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path));
+ break;
+ }
+}
+
+
+/*
+ * Receive BOOTP reply.
+ */
+static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+ struct bootp_pkt *b = (struct bootp_pkt *) skb->nh.iph;
+ struct iphdr *h = &b->iph;
+ int len;
+
+ /* If we already have a reply, just drop the packet */
+ if (ic_got_reply)
+ goto drop;
+
+ /* Check whether it's a BOOTP packet */
+ if (skb->pkt_type == PACKET_OTHERHOST ||
+ skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) ||
+ h->ihl != 5 ||
+ h->version != 4 ||
+ ip_fast_csum((char *) h, h->ihl) != 0 ||
+ skb->len < ntohs(h->tot_len) ||
+ h->protocol != IPPROTO_UDP ||
+ b->udph.source != htons(67) ||
+ b->udph.dest != htons(68) ||
+ ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
+ goto drop;
+
+ /* Fragments are not supported */
+ if (h->frag_off & htons(IP_OFFSET|IP_MF)) {
+ printk(KERN_ERR "BOOTP: Ignoring fragmented reply.\n");
+ goto drop;
+ }
+
+ /* Is it a reply to our BOOTP request? */
+ len = ntohs(b->udph.len) - sizeof(struct udphdr);
+ if (len < 300 || /* See RFC 951:2.1 */
+ b->op != BOOTP_REPLY ||
+ b->xid != ic_bootp_xid) {
+ printk("?");
+ goto drop;
+ }
+
+ /* Extract basic fields */
+ ic_myaddr = b->your_ip;
+ ic_servaddr = b->server_ip;
+ ic_got_reply = IC_BOOTP;
+ ic_dev = dev;
+
+ /* Parse extensions */
+ if (b->vendor_area[0] == 99 && /* Check magic cookie */
+ b->vendor_area[1] == 130 &&
+ b->vendor_area[2] == 83 &&
+ b->vendor_area[3] == 99) {
+ u8 *ext = &b->vendor_area[4];
+ u8 *end = (u8 *) b + ntohs(b->iph.tot_len);
+ while (ext < end && *ext != 0xff) {
+ if (*ext == 0) /* Padding */
+ ext++;
+ else {
+ u8 *opt = ext;
+ ext += ext[1] + 2;
+ if (ext <= end)
+ ic_do_bootp_ext(opt);
+ }
+ }
+ }
+
+ if (ic_gateway == INADDR_NONE && b->relay_ip)
+ ic_gateway = b->relay_ip;
+
+drop:
+ kfree_skb(skb);
+ return 0;
+}
+
+
+#endif
+
+
+/*
+ * Dynamic IP configuration -- BOOTP and RARP.
+ */
+
+#ifdef CONFIG_IP_PNP_DYNAMIC
+
+static int __init ic_dynamic(void)
+{
+ int retries;
+ unsigned long timeout, jiff;
+ unsigned long start_jiffies;
+ int do_rarp = ic_proto_have_if & IC_RARP;
+ int do_bootp = ic_proto_have_if & IC_BOOTP;
+
+ /*
+ * If neither BOOTP nor RARP was selected, return with an error. This
+ * routine gets only called when some pieces of information are mis-
+ * sing, and without BOOTP and RARP we are not able to get that in-
+ * formation.
+ */
+ if (!ic_proto_enabled) {
+ printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
+ return -1;
+ }
+
+#ifdef CONFIG_IP_PNP_BOOTP
+ if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP)
+ printk(KERN_ERR "BOOTP: No suitable device found.\n");
+#endif
+
+#ifdef CONFIG_IP_PNP_RARP
+ if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP)
+ printk(KERN_ERR "RARP: No suitable device found.\n");
+#endif
+
+ if (!ic_proto_have_if)
+ /* Error message already printed */
+ return -1;
+
+ /*
+ * Setup RARP and BOOTP protocols
+ */
+#ifdef CONFIG_IP_PNP_RARP
+ if (do_rarp)
+ ic_rarp_init();
+#endif
+#ifdef CONFIG_IP_PNP_BOOTP
+ if (do_bootp)
+ ic_bootp_init();
+#endif
+
+ /*
+ * Send requests and wait, until we get an answer. This loop
+ * seems to be a terrible waste of CPU time, but actually there is
+ * only one process running at all, so we don't need to use any
+ * scheduler functions.
+ * [Actually we could now, but the nothing else running note still
+ * applies.. - AC]
+ */
+ printk(KERN_NOTICE "Sending %s%s%s requests...",
+ do_bootp ? "BOOTP" : "",
+ do_bootp && do_rarp ? " and " : "",
+ do_rarp ? "RARP" : "");
+ start_jiffies = jiffies;
+ retries = CONF_RETRIES;
+ get_random_bytes(&timeout, sizeof(timeout));
+ timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
+ for(;;) {
+#ifdef CONFIG_IP_PNP_BOOTP
+ if (do_bootp)
+ ic_bootp_send(jiffies - start_jiffies);
+#endif
+#ifdef CONFIG_IP_PNP_RARP
+ if (do_rarp)
+ ic_rarp_send();
+#endif
+ printk(".");
+ jiff = jiffies + timeout;
+ while (jiffies < jiff && !ic_got_reply)
+ ;
+ if (ic_got_reply) {
+ printk(" OK\n");
+ break;
+ }
+ if (! --retries) {
+ printk(" timed out!\n");
+ break;
+ }
+ timeout = timeout CONF_TIMEOUT_MULT;
+ if (timeout > CONF_TIMEOUT_MAX)
+ timeout = CONF_TIMEOUT_MAX;
+ }
+
+#ifdef CONFIG_IP_PNP_RARP
+ if (do_rarp)
+ ic_rarp_cleanup();
+#endif
+#ifdef CONFIG_IP_PNP_BOOTP
+ if (do_bootp)
+ ic_bootp_cleanup();
+#endif
+
+ if (!ic_got_reply)
+ return -1;
+
+ printk("IP-Config: Got %s answer from %s, ",
+ (ic_got_reply & IC_BOOTP) ? "BOOTP" : "RARP",
+ in_ntoa(ic_servaddr));
+ printk("my address is %s\n", in_ntoa(ic_myaddr));
+
+ return 0;
+}
+
+#endif
+
+/*
+ * IP Autoconfig dispatcher.
+ */
+
+int __init ip_auto_config(void)
+{
+ if (!ic_enable)
+ return 0;
+
+ DBG(("IP-Config: Entered.\n"));
+
+ /* Setup all network devices */
+ if (ic_open_devs() < 0)
+ return -1;
+
+ /*
+ * If the config information is insufficient (e.g., our IP address or
+ * IP address of the boot server is missing or we have multiple network
+ * interfaces and no default was set), use BOOTP or RARP to get the
+ * missing values.
+ */
+ if (ic_myaddr == INADDR_NONE ||
+#ifdef CONFIG_ROOT_NFS
+ (root_server_addr == INADDR_NONE && ic_servaddr == INADDR_NONE) ||
+#endif
+ ic_first_dev->next) {
+#ifdef CONFIG_IP_PNP_DYNAMIC
+ if (ic_dynamic() < 0) {
+ printk(KERN_ERR "IP-Config: Auto-configuration of network failed.\n");
+ ic_close_devs();
+ return -1;
+ }
+#else
+ printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
+ ic_close_devs();
+ return -1;
+#endif
+ } else {
+ ic_dev = ic_first_dev->dev; /* Device selected manually or only one device -> use it */
+ }
+
+ /*
+ * Use defaults wherever applicable.
+ */
+ if (ic_defaults() < 0)
+ return -1;
+
+ /*
+ * Close all network devices except the device we've
+ * autoconfigured and set up routes.
+ */
+ ic_close_devs();
+ if (ic_setup_if() < 0 || ic_setup_routes() < 0)
+ return -1;
+
+ DBG(("IP-Config: device=%s, local=%08x, server=%08x, boot=%08x, gw=%08x, mask=%08x\n",
+ ic_dev->name, ic_myaddr, ic_servaddr, root_server_addr, ic_gateway, ic_netmask));
+ DBG(("IP-Config: host=%s, domain=%s, path=`%s'\n", system_utsname.nodename,
+ system_utsname.domainname, root_server_path));
+ return 0;
+}
+
+/*
+ * Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
+ * command line parameter. It consists of option fields separated by colons in
+ * the following order:
+ *
+ * <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<bootp|rarp>
+ *
+ * Any of the fields can be empty which means to use a default value:
+ * <client-ip> - address given by BOOTP or RARP
+ * <server-ip> - address of host returning BOOTP or RARP packet
+ * <gw-ip> - none, or the address returned by BOOTP
+ * <netmask> - automatically determined from <client-ip>, or the
+ * one returned by BOOTP
+ * <host name> - <client-ip> in ASCII notation, or the name returned
+ * by BOOTP
+ * <device> - use all available devices
+ * <bootp|rarp|both|off> - use both protocols to determine my own address
+ */
+static int __init ic_proto_name(char *name)
+{
+ if (!strcmp(name, "off")) {
+ ic_proto_enabled = 0;
+ return 1;
+ }
+#ifdef CONFIG_IP_PNP_BOOTP
+ else if (!strcmp(name, "bootp")) {
+ ic_proto_enabled &= ~IC_RARP;
+ return 1;
+ }
+#endif
+#ifdef CONFIG_IP_PNP_RARP
+ else if (!strcmp(name, "rarp")) {
+ ic_proto_enabled &= ~IC_BOOTP;
+ return 1;
+ }
+#endif
+#ifdef CONFIG_IP_PNP_DYNAMIC
+ else if (!strcmp(name, "both")) {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+void __init ip_auto_config_setup(char *addrs, int *ints)
+{
+ char *cp, *ip, *dp;
+ int num = 0;
+
+ ic_set_manually = 1;
+ if (!strcmp(addrs, "off")) {
+ ic_enable = 0;
+ return;
+ }
+ if (ic_proto_name(addrs))
+ return;
+
+ /* Parse the whole string */
+ ip = addrs;
+ while (ip && *ip) {
+ if ((cp = strchr(ip, ':')))
+ *cp++ = '\0';
+ if (strlen(ip) > 0) {
+ DBG(("IP-Config: Parameter #%d: `%s'\n", num, ip));
+ switch (num) {
+ case 0:
+ if ((ic_myaddr = in_aton(ip)) == INADDR_ANY)
+ ic_myaddr = INADDR_NONE;
+ break;
+ case 1:
+ if ((ic_servaddr = in_aton(ip)) == INADDR_ANY)
+ ic_servaddr = INADDR_NONE;
+ break;
+ case 2:
+ if ((ic_gateway = in_aton(ip)) == INADDR_ANY)
+ ic_gateway = INADDR_NONE;
+ break;
+ case 3:
+ if ((ic_netmask = in_aton(ip)) == INADDR_ANY)
+ ic_netmask = INADDR_NONE;
+ break;
+ case 4:
+ if ((dp = strchr(ip, '.'))) {
+ *dp++ = '\0';
+ strncpy(system_utsname.domainname, dp, __NEW_UTS_LEN);
+ system_utsname.domainname[__NEW_UTS_LEN] = '\0';
+ }
+ strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
+ system_utsname.nodename[__NEW_UTS_LEN] = '\0';
+ ic_host_name_set = 1;
+ break;
+ case 5:
+ strncpy(user_dev_name, ip, IFNAMSIZ);
+ user_dev_name[IFNAMSIZ-1] = '\0';
+ break;
+ case 6:
+ ic_proto_name(ip);
+ break;
+ }
+ }
+ ip = cp;
+ num++;
+ }
+}
diff --git a/pfinet/linux-src/net/ipv4/ipip.c b/pfinet/linux-src/net/ipv4/ipip.c
new file mode 100644
index 00000000..119d7567
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ipip.c
@@ -0,0 +1,870 @@
+/*
+ * Linux NET3: IP/IP protocol decoder.
+ *
+ * Version: $Id: ipip.c,v 1.26 1999/03/25 10:04:32 davem Exp $
+ *
+ * Authors:
+ * Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
+ *
+ * Fixes:
+ * Alan Cox : Merged and made usable non modular (its so tiny its silly as
+ * a module taking up 2 pages).
+ * Alan Cox : Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph)
+ * to keep ip_forward happy.
+ * Alan Cox : More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8).
+ * Kai Schulte : Fixed #defines for IP_FIREWALL->FIREWALL
+ * David Woodhouse : Perform some basic ICMP handling.
+ * IPIP Routing without decapsulation.
+ * Carlos Picoto : GRE over IP support
+ * Alexey Kuznetsov: Reworked. Really, now it is truncated version of ipv4/ip_gre.c.
+ * I do not want to merge them together.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+/* tunnel.c: an IP tunnel driver
+
+ The purpose of this driver is to provide an IP tunnel through
+ which you can tunnel network traffic transparently across subnets.
+
+ This was written by looking at Nick Holloway's dummy driver
+ Thanks for the great code!
+
+ -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
+
+ Minor tweaks:
+ Cleaned up the code a little and added some pre-1.3.0 tweaks.
+ dev->hard_header/hard_header_len changed to use no headers.
+ Comments/bracketing tweaked.
+ Made the tunnels use dev->name not tunnel: when error reporting.
+ Added tx_dropped stat
+
+ -Alan Cox (Alan.Cox@linux.org) 21 March 95
+
+ Reworked:
+ Changed to tunnel to destination gateway in addition to the
+ tunnel's pointopoint address
+ Almost completely rewritten
+ Note: There is currently no firewall or ICMP handling done.
+
+ -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96
+
+*/
+
+/* Things I wish I had known when writing the tunnel driver:
+
+ When the tunnel_xmit() function is called, the skb contains the
+ packet to be sent (plus a great deal of extra info), and dev
+ contains the tunnel device that _we_ are.
+
+ When we are passed a packet, we are expected to fill in the
+ source address with our source IP address.
+
+ What is the proper way to allocate, copy and free a buffer?
+ After you allocate it, it is a "0 length" chunk of memory
+ starting at zero. If you want to add headers to the buffer
+ later, you'll have to call "skb_reserve(skb, amount)" with
+ the amount of memory you want reserved. Then, you call
+ "skb_put(skb, amount)" with the amount of space you want in
+ the buffer. skb_put() returns a pointer to the top (#0) of
+ that buffer. skb->len is set to the amount of space you have
+ "allocated" with skb_put(). You can then write up to skb->len
+ bytes to that buffer. If you need more, you can call skb_put()
+ again with the additional amount of space you need. You can
+ find out how much more space you can allocate by calling
+ "skb_tailroom(skb)".
+ Now, to add header space, call "skb_push(skb, header_len)".
+ This creates space at the beginning of the buffer and returns
+ a pointer to this new space. If later you need to strip a
+ header from a buffer, call "skb_pull(skb, header_len)".
+ skb_headroom() will return how much space is left at the top
+ of the buffer (before the main data). Remember, this headroom
+ space must be reserved before the skb_put() function is called.
+ */
+
+/*
+ This version of net/ipv4/ipip.c is cloned of net/ipv4/ip_gre.c
+
+ For comments look at net/ipv4/ip_gre.c --ANK
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/uaccess.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_arp.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/protocol.h>
+#include <net/ipip.h>
+
+#define HASH_SIZE 16
+#define HASH(addr) ((addr^(addr>>4))&0xF)
+
+static int ipip_fb_tunnel_init(struct device *dev);
+static int ipip_tunnel_init(struct device *dev);
+
+static struct device ipip_fb_tunnel_dev = {
+ NULL, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip_fb_tunnel_init,
+};
+
+static struct ip_tunnel ipip_fb_tunnel = {
+ NULL, &ipip_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"tunl0", }
+};
+
+static struct ip_tunnel *tunnels_r_l[HASH_SIZE];
+static struct ip_tunnel *tunnels_r[HASH_SIZE];
+static struct ip_tunnel *tunnels_l[HASH_SIZE];
+static struct ip_tunnel *tunnels_wc[1];
+static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l };
+
+static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local)
+{
+ unsigned h0 = HASH(remote);
+ unsigned h1 = HASH(local);
+ struct ip_tunnel *t;
+
+ for (t = tunnels_r_l[h0^h1]; t; t = t->next) {
+ if (local == t->parms.iph.saddr &&
+ remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
+ return t;
+ }
+ for (t = tunnels_r[h0]; t; t = t->next) {
+ if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
+ return t;
+ }
+ for (t = tunnels_l[h1]; t; t = t->next) {
+ if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
+ return t;
+ }
+ if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP))
+ return t;
+ return NULL;
+}
+
+static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t)
+{
+ u32 remote = t->parms.iph.daddr;
+ u32 local = t->parms.iph.saddr;
+ unsigned h = 0;
+ int prio = 0;
+
+ if (remote) {
+ prio |= 2;
+ h ^= HASH(remote);
+ }
+ if (local) {
+ prio |= 1;
+ h ^= HASH(local);
+ }
+ return &tunnels[prio][h];
+}
+
+
+static void ipip_tunnel_unlink(struct ip_tunnel *t)
+{
+ struct ip_tunnel **tp;
+
+ for (tp = ipip_bucket(t); *tp; tp = &(*tp)->next) {
+ if (t == *tp) {
+ *tp = t->next;
+ synchronize_bh();
+ break;
+ }
+ }
+}
+
+static void ipip_tunnel_link(struct ip_tunnel *t)
+{
+ struct ip_tunnel **tp = ipip_bucket(t);
+
+ t->next = *tp;
+ wmb();
+ *tp = t;
+}
+
+struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create)
+{
+ u32 remote = parms->iph.daddr;
+ u32 local = parms->iph.saddr;
+ struct ip_tunnel *t, **tp, *nt;
+ struct device *dev;
+ unsigned h = 0;
+ int prio = 0;
+
+ if (remote) {
+ prio |= 2;
+ h ^= HASH(remote);
+ }
+ if (local) {
+ prio |= 1;
+ h ^= HASH(local);
+ }
+ for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {
+ if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
+ return t;
+ }
+ if (!create)
+ return NULL;
+
+ MOD_INC_USE_COUNT;
+ dev = kmalloc(sizeof(*dev) + sizeof(*t), GFP_KERNEL);
+ if (dev == NULL) {
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+ memset(dev, 0, sizeof(*dev) + sizeof(*t));
+ dev->priv = (void*)(dev+1);
+ nt = (struct ip_tunnel*)dev->priv;
+ nt->dev = dev;
+ dev->name = nt->parms.name;
+ dev->init = ipip_tunnel_init;
+ memcpy(&nt->parms, parms, sizeof(*parms));
+ if (dev->name[0] == 0) {
+ int i;
+ for (i=1; i<100; i++) {
+ sprintf(dev->name, "tunl%d", i);
+ if (dev_get(dev->name) == NULL)
+ break;
+ }
+ if (i==100)
+ goto failed;
+ memcpy(parms->name, dev->name, IFNAMSIZ);
+ }
+ if (register_netdevice(dev) < 0)
+ goto failed;
+
+ ipip_tunnel_link(nt);
+ /* Do not decrement MOD_USE_COUNT here. */
+ return nt;
+
+failed:
+ kfree(dev);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+
+static void ipip_tunnel_destroy(struct device *dev)
+{
+ if (dev == &ipip_fb_tunnel_dev) {
+ tunnels_wc[0] = NULL;
+ synchronize_bh();
+ } else {
+ ipip_tunnel_unlink((struct ip_tunnel*)dev->priv);
+ kfree(dev);
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+void ipip_err(struct sk_buff *skb, unsigned char *dp, int len)
+{
+#ifndef I_WISH_WORLD_WERE_PERFECT
+
+/* It is not :-( All the routers (except for Linux) return only
+ 8 bytes of packet payload. It means, that precise relaying of
+ ICMP in the real Internet is absolutely infeasible.
+ */
+ struct iphdr *iph = (struct iphdr*)dp;
+ int type = skb->h.icmph->type;
+ int code = skb->h.icmph->code;
+ struct ip_tunnel *t;
+
+ if (len < sizeof(struct iphdr))
+ return;
+
+ switch (type) {
+ default:
+ case ICMP_PARAMETERPROB:
+ return;
+
+ case ICMP_DEST_UNREACH:
+ switch (code) {
+ case ICMP_SR_FAILED:
+ case ICMP_PORT_UNREACH:
+ /* Impossible event. */
+ return;
+ case ICMP_FRAG_NEEDED:
+ /* Soft state for pmtu is maintained by IP core. */
+ return;
+ default:
+ /* All others are translated to HOST_UNREACH.
+ rfc2003 contains "deep thoughts" about NET_UNREACH,
+ I believe they are just ether pollution. --ANK
+ */
+ break;
+ }
+ break;
+ case ICMP_TIME_EXCEEDED:
+ if (code != ICMP_EXC_TTL)
+ return;
+ break;
+ }
+
+ t = ipip_tunnel_lookup(iph->daddr, iph->saddr);
+ if (t == NULL || t->parms.iph.daddr == 0)
+ return;
+ if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
+ return;
+
+ if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
+ t->err_count++;
+ else
+ t->err_count = 1;
+ t->err_time = jiffies;
+ return;
+#else
+ struct iphdr *iph = (struct iphdr*)dp;
+ int hlen = iph->ihl<<2;
+ struct iphdr *eiph;
+ int type = skb->h.icmph->type;
+ int code = skb->h.icmph->code;
+ int rel_type = 0;
+ int rel_code = 0;
+ int rel_info = 0;
+ struct sk_buff *skb2;
+ struct rtable *rt;
+
+ if (len < hlen + sizeof(struct iphdr))
+ return;
+ eiph = (struct iphdr*)(dp + hlen);
+
+ switch (type) {
+ default:
+ return;
+ case ICMP_PARAMETERPROB:
+ if (skb->h.icmph->un.gateway < hlen)
+ return;
+
+ /* So... This guy found something strange INSIDE encapsulated
+ packet. Well, he is fool, but what can we do ?
+ */
+ rel_type = ICMP_PARAMETERPROB;
+ rel_info = skb->h.icmph->un.gateway - hlen;
+ break;
+
+ case ICMP_DEST_UNREACH:
+ switch (code) {
+ case ICMP_SR_FAILED:
+ case ICMP_PORT_UNREACH:
+ /* Impossible event. */
+ return;
+ case ICMP_FRAG_NEEDED:
+ /* And it is the only really necessary thing :-) */
+ rel_info = ntohs(skb->h.icmph->un.frag.mtu);
+ if (rel_info < hlen+68)
+ return;
+ rel_info -= hlen;
+ /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
+ if (rel_info > ntohs(eiph->tot_len))
+ return;
+ break;
+ default:
+ /* All others are translated to HOST_UNREACH.
+ rfc2003 contains "deep thoughts" about NET_UNREACH,
+ I believe, it is just ether pollution. --ANK
+ */
+ rel_type = ICMP_DEST_UNREACH;
+ rel_code = ICMP_HOST_UNREACH;
+ break;
+ }
+ break;
+ case ICMP_TIME_EXCEEDED:
+ if (code != ICMP_EXC_TTL)
+ return;
+ break;
+ }
+
+ /* Prepare fake skb to feed it to icmp_send */
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2 == NULL)
+ return;
+ dst_release(skb2->dst);
+ skb2->dst = NULL;
+ skb_pull(skb2, skb->data - (u8*)eiph);
+ skb2->nh.raw = skb2->data;
+
+ /* Try to guess incoming interface */
+ if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) {
+ kfree_skb(skb2);
+ return;
+ }
+ skb2->dev = rt->u.dst.dev;
+
+ /* route "incoming" packet */
+ if (rt->rt_flags&RTCF_LOCAL) {
+ ip_rt_put(rt);
+ rt = NULL;
+ if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) ||
+ rt->u.dst.dev->type != ARPHRD_IPGRE) {
+ ip_rt_put(rt);
+ kfree_skb(skb2);
+ return;
+ }
+ } else {
+ ip_rt_put(rt);
+ if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
+ skb2->dst->dev->type != ARPHRD_IPGRE) {
+ kfree_skb(skb2);
+ return;
+ }
+ }
+
+ /* change mtu on this route */
+ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
+ if (rel_info > skb2->dst->pmtu) {
+ kfree_skb(skb2);
+ return;
+ }
+ skb2->dst->pmtu = rel_info;
+ rel_info = htonl(rel_info);
+ } else if (type == ICMP_TIME_EXCEEDED) {
+ struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv;
+ if (t->parms.iph.ttl) {
+ rel_type = ICMP_DEST_UNREACH;
+ rel_code = ICMP_HOST_UNREACH;
+ }
+ }
+
+ icmp_send(skb2, rel_type, rel_code, rel_info);
+ kfree_skb(skb2);
+ return;
+#endif
+}
+
+int ipip_rcv(struct sk_buff *skb, unsigned short len)
+{
+ struct iphdr *iph;
+ struct ip_tunnel *tunnel;
+
+ iph = skb->nh.iph;
+ skb->mac.raw = skb->nh.raw;
+ skb->nh.raw = skb_pull(skb, skb->h.raw - skb->data);
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+ skb->protocol = __constant_htons(ETH_P_IP);
+ skb->ip_summed = 0;
+ skb->pkt_type = PACKET_HOST;
+
+ if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
+ tunnel->stat.rx_packets++;
+ tunnel->stat.rx_bytes += skb->len;
+ skb->dev = tunnel->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ netif_rx(skb);
+ return 0;
+ }
+
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
+ kfree_skb(skb);
+ return 0;
+}
+
+/*
+ * This function assumes it is being called from dev_queue_xmit()
+ * and that skb is filled properly by that function.
+ */
+
+static int ipip_tunnel_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
+ struct net_device_stats *stats = &tunnel->stat;
+ struct iphdr *tiph = &tunnel->parms.iph;
+ u8 tos = tunnel->parms.iph.tos;
+ u16 df = tiph->frag_off;
+ struct rtable *rt; /* Route to the other host */
+ struct device *tdev; /* Device to other host */
+ struct iphdr *old_iph = skb->nh.iph;
+ struct iphdr *iph; /* Our new IP header */
+ int max_headroom; /* The extra header space needed */
+ u32 dst = tiph->daddr;
+ int mtu;
+
+ if (tunnel->recursion++) {
+ tunnel->stat.collisions++;
+ goto tx_error;
+ }
+
+ if (skb->protocol != __constant_htons(ETH_P_IP))
+ goto tx_error;
+
+ if (tos&1)
+ tos = old_iph->tos;
+
+ if (!dst) {
+ /* NBMA tunnel */
+ if ((rt = (struct rtable*)skb->dst) == NULL) {
+ tunnel->stat.tx_fifo_errors++;
+ goto tx_error;
+ }
+ if ((dst = rt->rt_gateway) == 0)
+ goto tx_error_icmp;
+ }
+
+ if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
+ tunnel->stat.tx_carrier_errors++;
+ goto tx_error_icmp;
+ }
+ tdev = rt->u.dst.dev;
+
+ if (tdev == dev) {
+ ip_rt_put(rt);
+ tunnel->stat.collisions++;
+ goto tx_error;
+ }
+
+ mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+ if (mtu < 68) {
+ tunnel->stat.collisions++;
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+ if (skb->dst && mtu < skb->dst->pmtu)
+ skb->dst->pmtu = mtu;
+
+ df |= (old_iph->frag_off&__constant_htons(IP_DF));
+
+ if ((old_iph->frag_off&__constant_htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+
+ if (tunnel->err_count > 0) {
+ if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
+ tunnel->err_count--;
+ dst_link_failure(skb);
+ } else
+ tunnel->err_count = 0;
+ }
+
+ skb->h.raw = skb->nh.raw;
+
+ /*
+ * Okay, now see if we can stuff it in the buffer as-is.
+ */
+ max_headroom = (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr));
+
+ if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+ struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+ if (!new_skb) {
+ ip_rt_put(rt);
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ tunnel->recursion--;
+ return 0;
+ }
+ if (skb->sk)
+ skb_set_owner_w(new_skb, skb->sk);
+ dev_kfree_skb(skb);
+ skb = new_skb;
+ }
+
+ skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+
+ /*
+ * Push down and install the IPIP header.
+ */
+
+ iph = skb->nh.iph;
+ iph->version = 4;
+ iph->ihl = sizeof(struct iphdr)>>2;
+ iph->frag_off = df;
+ iph->protocol = IPPROTO_IPIP;
+ iph->tos = tos;
+ iph->daddr = rt->rt_dst;
+ iph->saddr = rt->rt_src;
+
+ if ((iph->ttl = tiph->ttl) == 0)
+ iph->ttl = old_iph->ttl;
+
+ iph->tot_len = htons(skb->len);
+ iph->id = htons(ip_id_count++);
+ ip_send_check(iph);
+
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ ip_send(skb);
+ tunnel->recursion--;
+ return 0;
+
+tx_error_icmp:
+ dst_link_failure(skb);
+tx_error:
+ stats->tx_errors++;
+ dev_kfree_skb(skb);
+ tunnel->recursion--;
+ return 0;
+}
+
+static int
+ipip_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
+{
+ int err = 0;
+ struct ip_tunnel_parm p;
+ struct ip_tunnel *t;
+
+ MOD_INC_USE_COUNT;
+
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ t = NULL;
+ if (dev == &ipip_fb_tunnel_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
+ err = -EFAULT;
+ break;
+ }
+ t = ipip_tunnel_locate(&p, 0);
+ }
+ if (t == NULL)
+ t = (struct ip_tunnel*)dev->priv;
+ memcpy(&p, &t->parms, sizeof(p));
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+ err = -EFAULT;
+ break;
+
+ case SIOCADDTUNNEL:
+ case SIOCCHGTUNNEL:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ goto done;
+
+ err = -EFAULT;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ goto done;
+
+ err = -EINVAL;
+ if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
+ p.iph.ihl != 5 || (p.iph.frag_off&__constant_htons(~IP_DF)))
+ goto done;
+ if (p.iph.ttl)
+ p.iph.frag_off |= __constant_htons(IP_DF);
+
+ t = ipip_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
+
+ if (dev != &ipip_fb_tunnel_dev && cmd == SIOCCHGTUNNEL &&
+ t != &ipip_fb_tunnel) {
+ if (t != NULL) {
+ if (t->dev != dev) {
+ err = -EEXIST;
+ break;
+ }
+ } else {
+ if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) ||
+ (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) {
+ err = -EINVAL;
+ break;
+ }
+ t = (struct ip_tunnel*)dev->priv;
+ start_bh_atomic();
+ ipip_tunnel_unlink(t);
+ t->parms.iph.saddr = p.iph.saddr;
+ t->parms.iph.daddr = p.iph.daddr;
+ memcpy(dev->dev_addr, &p.iph.saddr, 4);
+ memcpy(dev->broadcast, &p.iph.daddr, 4);
+ ipip_tunnel_link(t);
+ end_bh_atomic();
+ netdev_state_change(dev);
+ }
+ }
+
+ if (t) {
+ err = 0;
+ if (cmd == SIOCCHGTUNNEL) {
+ t->parms.iph.ttl = p.iph.ttl;
+ t->parms.iph.tos = p.iph.tos;
+ t->parms.iph.frag_off = p.iph.frag_off;
+ }
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
+ err = -EFAULT;
+ } else
+ err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+ break;
+
+ case SIOCDELTUNNEL:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ goto done;
+
+ if (dev == &ipip_fb_tunnel_dev) {
+ err = -EFAULT;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ goto done;
+ err = -ENOENT;
+ if ((t = ipip_tunnel_locate(&p, 0)) == NULL)
+ goto done;
+ err = -EPERM;
+ if (t == &ipip_fb_tunnel)
+ goto done;
+ }
+ err = unregister_netdevice(dev);
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+done:
+ MOD_DEC_USE_COUNT;
+ return err;
+}
+
+static struct net_device_stats *ipip_tunnel_get_stats(struct device *dev)
+{
+ return &(((struct ip_tunnel*)dev->priv)->stat);
+}
+
+static int ipip_tunnel_change_mtu(struct device *dev, int new_mtu)
+{
+ if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static void ipip_tunnel_init_gen(struct device *dev)
+{
+ struct ip_tunnel *t = (struct ip_tunnel*)dev->priv;
+
+ dev->destructor = ipip_tunnel_destroy;
+ dev->hard_start_xmit = ipip_tunnel_xmit;
+ dev->get_stats = ipip_tunnel_get_stats;
+ dev->do_ioctl = ipip_tunnel_ioctl;
+ dev->change_mtu = ipip_tunnel_change_mtu;
+
+ dev_init_buffers(dev);
+
+ dev->type = ARPHRD_TUNNEL;
+ dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
+ dev->mtu = 1500 - sizeof(struct iphdr);
+ dev->flags = IFF_NOARP;
+ dev->iflink = 0;
+ dev->addr_len = 4;
+ memcpy(dev->dev_addr, &t->parms.iph.saddr, 4);
+ memcpy(dev->broadcast, &t->parms.iph.daddr, 4);
+}
+
+static int ipip_tunnel_init(struct device *dev)
+{
+ struct device *tdev = NULL;
+ struct ip_tunnel *tunnel;
+ struct iphdr *iph;
+
+ tunnel = (struct ip_tunnel*)dev->priv;
+ iph = &tunnel->parms.iph;
+
+ ipip_tunnel_init_gen(dev);
+
+ if (iph->daddr) {
+ struct rtable *rt;
+ if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) {
+ tdev = rt->u.dst.dev;
+ ip_rt_put(rt);
+ }
+ dev->flags |= IFF_POINTOPOINT;
+ }
+
+ if (!tdev && tunnel->parms.link)
+ tdev = dev_get_by_index(tunnel->parms.link);
+
+ if (tdev) {
+ dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
+ dev->mtu = tdev->mtu - sizeof(struct iphdr);
+ }
+ dev->iflink = tunnel->parms.link;
+
+ return 0;
+}
+
+#ifdef MODULE
+static int ipip_fb_tunnel_open(struct device *dev)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int ipip_fb_tunnel_close(struct device *dev)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+#endif
+
+__initfunc(int ipip_fb_tunnel_init(struct device *dev))
+{
+ struct iphdr *iph;
+
+ ipip_tunnel_init_gen(dev);
+#ifdef MODULE
+ dev->open = ipip_fb_tunnel_open;
+ dev->stop = ipip_fb_tunnel_close;
+#endif
+
+ iph = &ipip_fb_tunnel.parms.iph;
+ iph->version = 4;
+ iph->protocol = IPPROTO_IPIP;
+ iph->ihl = 5;
+
+ tunnels_wc[0] = &ipip_fb_tunnel;
+ return 0;
+}
+
+static struct inet_protocol ipip_protocol = {
+ ipip_rcv, /* IPIP handler */
+ ipip_err, /* TUNNEL error control */
+ 0, /* next */
+ IPPROTO_IPIP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "IPIP" /* name */
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int ipip_init(void))
+#endif
+{
+ printk(KERN_INFO "IPv4 over IPv4 tunneling driver\n");
+
+ ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel;
+ ipip_fb_tunnel_dev.name = ipip_fb_tunnel.parms.name;
+#ifdef MODULE
+ register_netdev(&ipip_fb_tunnel_dev);
+#else
+ register_netdevice(&ipip_fb_tunnel_dev);
+#endif
+
+ inet_add_protocol(&ipip_protocol);
+ return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+ if ( inet_del_protocol(&ipip_protocol) < 0 )
+ printk(KERN_INFO "ipip close: can't remove protocol\n");
+
+ unregister_netdevice(&ipip_fb_tunnel_dev);
+}
+
+#endif
diff --git a/pfinet/linux-src/net/ipv4/ipmr.c b/pfinet/linux-src/net/ipv4/ipmr.c
new file mode 100644
index 00000000..cd51cd9a
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/ipmr.c
@@ -0,0 +1,1609 @@
+/*
+ * IP multicast routing support for mrouted 3.6/3.8
+ *
+ * (c) 1995 Alan Cox, <alan@redhat.com>
+ * Linux Consultancy and Custom Driver Development
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Version: $Id: ipmr.c,v 1.40.2.2 1999/06/20 21:27:44 davem Exp $
+ *
+ * Fixes:
+ * Michael Chastain : Incorrect size of copying.
+ * Alan Cox : Added the cache manager code
+ * Alan Cox : Fixed the clone/copy bug and device race.
+ * Mike McLagan : Routing by source
+ * Malcolm Beattie : Buffer handling fixes.
+ * Alexey Kuznetsov : Double buffer free and other fixes.
+ * SVR Anand : Fixed several multicast bugs and problems.
+ * Alexey Kuznetsov : Status, optimisations and more.
+ * Brad Parker : Better behaviour on mrouted upcall
+ * overflow.
+ * Carlos Picoto : PIMv1 Support
+ * Pavlin Ivanov Radoslavov: PIMv2 Registers must checksum only PIM header
+ * Relax this requrement to work with older peers.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/proc_fs.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <linux/notifier.h>
+#include <linux/if_arp.h>
+#include <linux/ip_fw.h>
+#include <linux/firewall.h>
+#include <net/ipip.h>
+#include <net/checksum.h>
+
+#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
+#define CONFIG_IP_PIMSM 1
+#endif
+
+/*
+ * Multicast router control variables
+ */
+
+static struct vif_device vif_table[MAXVIFS]; /* Devices */
+static unsigned long vifc_map; /* Active device map */
+static int maxvif;
+int mroute_do_assert = 0; /* Set in PIM assert */
+int mroute_do_pim = 0;
+static struct mfc_cache *mfc_cache_array[MFC_LINES]; /* Forwarding cache */
+int cache_resolve_queue_len = 0; /* Size of unresolved */
+
+static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
+static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
+static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
+
+extern struct inet_protocol pim_protocol;
+
+static
+struct device *ipmr_new_tunnel(struct vifctl *v)
+{
+ struct device *dev = NULL;
+
+ rtnl_lock();
+ dev = dev_get("tunl0");
+
+ if (dev) {
+ int err;
+ struct ifreq ifr;
+ mm_segment_t oldfs;
+ struct ip_tunnel_parm p;
+ struct in_device *in_dev;
+
+ memset(&p, 0, sizeof(p));
+ p.iph.daddr = v->vifc_rmt_addr.s_addr;
+ p.iph.saddr = v->vifc_lcl_addr.s_addr;
+ p.iph.version = 4;
+ p.iph.ihl = 5;
+ p.iph.protocol = IPPROTO_IPIP;
+ sprintf(p.name, "dvmrp%d", v->vifc_vifi);
+ ifr.ifr_ifru.ifru_data = (void*)&p;
+
+ oldfs = get_fs(); set_fs(KERNEL_DS);
+ err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
+ set_fs(oldfs);
+
+ if (err == 0 && (dev = dev_get(p.name)) != NULL) {
+ dev->flags |= IFF_MULTICAST;
+
+ in_dev = dev->ip_ptr;
+ if (in_dev == NULL && (in_dev = inetdev_init(dev)) == NULL)
+ goto failure;
+ in_dev->cnf.rp_filter = 0;
+
+ if (dev_open(dev))
+ goto failure;
+ }
+ }
+ rtnl_unlock();
+ return dev;
+
+failure:
+ unregister_netdevice(dev);
+ rtnl_unlock();
+ return NULL;
+}
+
+#ifdef CONFIG_IP_PIMSM
+
+static int reg_vif_num = -1;
+static struct device * reg_dev;
+
+static int reg_vif_xmit(struct sk_buff *skb, struct device *dev)
+{
+ ((struct net_device_stats*)dev->priv)->tx_bytes += skb->len;
+ ((struct net_device_stats*)dev->priv)->tx_packets++;
+ ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT);
+ kfree_skb(skb);
+ return 0;
+}
+
+static struct net_device_stats *reg_vif_get_stats(struct device *dev)
+{
+ return (struct net_device_stats*)dev->priv;
+}
+
+static
+struct device *ipmr_reg_vif(struct vifctl *v)
+{
+ struct device *dev;
+ struct in_device *in_dev;
+ int size;
+
+ size = sizeof(*dev) + IFNAMSIZ + sizeof(struct net_device_stats);
+ dev = kmalloc(size, GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ memset(dev, 0, size);
+
+ dev->priv = dev + 1;
+ dev->name = dev->priv + sizeof(struct net_device_stats);
+
+ strcpy(dev->name, "pimreg");
+
+ dev->type = ARPHRD_PIMREG;
+ dev->mtu = 1500 - sizeof(struct iphdr) - 8;
+ dev->flags = IFF_NOARP;
+ dev->hard_start_xmit = reg_vif_xmit;
+ dev->get_stats = reg_vif_get_stats;
+
+ rtnl_lock();
+
+ if (register_netdevice(dev)) {
+ rtnl_unlock();
+ kfree(dev);
+ return NULL;
+ }
+ dev->iflink = 0;
+
+ if ((in_dev = inetdev_init(dev)) == NULL)
+ goto failure;
+
+ in_dev->cnf.rp_filter = 0;
+
+ if (dev_open(dev))
+ goto failure;
+
+ rtnl_unlock();
+ reg_dev = dev;
+ return dev;
+
+failure:
+ unregister_netdevice(dev);
+ rtnl_unlock();
+ kfree(dev);
+ return NULL;
+}
+#endif
+
+/*
+ * Delete a VIF entry
+ */
+
+static int vif_delete(int vifi)
+{
+ struct vif_device *v;
+ struct device *dev;
+ struct in_device *in_dev;
+
+ if (vifi < 0 || vifi >= maxvif || !(vifc_map&(1<<vifi)))
+ return -EADDRNOTAVAIL;
+
+ v = &vif_table[vifi];
+
+ dev = v->dev;
+ v->dev = NULL;
+ vifc_map &= ~(1<<vifi);
+
+ if ((in_dev = dev->ip_ptr) != NULL)
+ in_dev->cnf.mc_forwarding = 0;
+
+ dev_set_allmulti(dev, -1);
+ ip_rt_multicast_event(in_dev);
+
+ if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) {
+#ifdef CONFIG_IP_PIMSM
+ if (vifi == reg_vif_num) {
+ reg_vif_num = -1;
+ reg_dev = NULL;
+ }
+#endif
+ unregister_netdevice(dev);
+ if (v->flags&VIFF_REGISTER)
+ kfree(dev);
+ }
+
+ if (vifi+1 == maxvif) {
+ int tmp;
+ for (tmp=vifi-1; tmp>=0; tmp--) {
+ if (vifc_map&(1<<tmp))
+ break;
+ }
+ maxvif = tmp+1;
+ }
+ return 0;
+}
+
+static void ipmr_update_threshoulds(struct mfc_cache *cache, unsigned char *ttls)
+{
+ int vifi;
+
+ start_bh_atomic();
+
+ cache->mfc_minvif = MAXVIFS;
+ cache->mfc_maxvif = 0;
+ memset(cache->mfc_ttls, 255, MAXVIFS);
+
+ for (vifi=0; vifi<maxvif; vifi++) {
+ if (vifc_map&(1<<vifi) && ttls[vifi] && ttls[vifi] < 255) {
+ cache->mfc_ttls[vifi] = ttls[vifi];
+ if (cache->mfc_minvif > vifi)
+ cache->mfc_minvif = vifi;
+ if (cache->mfc_maxvif <= vifi)
+ cache->mfc_maxvif = vifi + 1;
+ }
+ }
+ end_bh_atomic();
+}
+
+/*
+ * Delete a multicast route cache entry
+ */
+
+static void ipmr_cache_delete(struct mfc_cache *cache)
+{
+ struct sk_buff *skb;
+ int line;
+ struct mfc_cache **cp;
+
+ /*
+ * Find the right cache line
+ */
+
+ line=MFC_HASH(cache->mfc_mcastgrp,cache->mfc_origin);
+ cp=&(mfc_cache_array[line]);
+
+ if(cache->mfc_flags&MFC_QUEUED)
+ del_timer(&cache->mfc_timer);
+
+ /*
+ * Unlink the buffer
+ */
+
+ while(*cp!=NULL)
+ {
+ if(*cp==cache)
+ {
+ *cp=cache->next;
+ break;
+ }
+ cp=&((*cp)->next);
+ }
+
+ /*
+ * Free the buffer. If it is a pending resolution
+ * clean up the other resources.
+ */
+
+ if(cache->mfc_flags&MFC_QUEUED)
+ {
+ cache_resolve_queue_len--;
+ while((skb=skb_dequeue(&cache->mfc_unresolved))) {
+#ifdef CONFIG_RTNETLINK
+ if (skb->nh.iph->version == 0) {
+ struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
+ nlh->nlmsg_type = NLMSG_ERROR;
+ nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ skb_trim(skb, nlh->nlmsg_len);
+ ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
+ netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
+ } else
+#endif
+ kfree_skb(skb);
+ }
+ }
+ kfree_s(cache,sizeof(cache));
+}
+
+/*
+ * Cache expiry timer
+ */
+
+static void ipmr_cache_timer(unsigned long data)
+{
+ struct mfc_cache *cache=(struct mfc_cache *)data;
+ ipmr_cache_delete(cache);
+}
+
+/*
+ * Insert a multicast cache entry
+ */
+
+static void ipmr_cache_insert(struct mfc_cache *c)
+{
+ int line=MFC_HASH(c->mfc_mcastgrp,c->mfc_origin);
+ c->next=mfc_cache_array[line];
+ mfc_cache_array[line]=c;
+}
+
+/*
+ * Find a multicast cache entry
+ */
+
+struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp)
+{
+ int line=MFC_HASH(mcastgrp,origin);
+ struct mfc_cache *cache;
+
+ cache=mfc_cache_array[line];
+ while(cache!=NULL)
+ {
+ if(cache->mfc_origin==origin && cache->mfc_mcastgrp==mcastgrp)
+ return cache;
+ cache=cache->next;
+ }
+ return NULL;
+}
+
+/*
+ * Allocate a multicast cache entry
+ */
+
+static struct mfc_cache *ipmr_cache_alloc(int priority)
+{
+ struct mfc_cache *c=(struct mfc_cache *)kmalloc(sizeof(struct mfc_cache), priority);
+ if(c==NULL)
+ return NULL;
+ memset(c, 0, sizeof(*c));
+ skb_queue_head_init(&c->mfc_unresolved);
+ init_timer(&c->mfc_timer);
+ c->mfc_timer.data=(long)c;
+ c->mfc_timer.function=ipmr_cache_timer;
+ c->mfc_minvif = MAXVIFS;
+ return c;
+}
+
+/*
+ * A cache entry has gone into a resolved state from queued
+ */
+
+static void ipmr_cache_resolve(struct mfc_cache *cache)
+{
+ struct sk_buff *skb;
+
+ start_bh_atomic();
+
+ /*
+ * Kill the queue entry timer.
+ */
+
+ del_timer(&cache->mfc_timer);
+
+ if (cache->mfc_flags&MFC_QUEUED) {
+ cache->mfc_flags&=~MFC_QUEUED;
+ cache_resolve_queue_len--;
+ }
+
+ end_bh_atomic();
+
+ /*
+ * Play the pending entries through our router
+ */
+ while((skb=skb_dequeue(&cache->mfc_unresolved))) {
+#ifdef CONFIG_RTNETLINK
+ if (skb->nh.iph->version == 0) {
+ int err;
+ struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
+
+ if (ipmr_fill_mroute(skb, cache, NLMSG_DATA(nlh)) > 0) {
+ nlh->nlmsg_len = skb->tail - (u8*)nlh;
+ } else {
+ nlh->nlmsg_type = NLMSG_ERROR;
+ nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ skb_trim(skb, nlh->nlmsg_len);
+ ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE;
+ }
+ err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
+ } else
+#endif
+ ip_mr_forward(skb, cache, 0);
+ }
+}
+
+/*
+ * Bounce a cache query up to mrouted. We could use netlink for this but mrouted
+ * expects the following bizarre scheme..
+ */
+
+static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
+{
+ struct sk_buff *skb;
+ int ihl = pkt->nh.iph->ihl<<2;
+ struct igmphdr *igmp;
+ struct igmpmsg *msg;
+ int ret;
+
+ if (mroute_socket==NULL)
+ return -EINVAL;
+
+#ifdef CONFIG_IP_PIMSM
+ if (assert == IGMPMSG_WHOLEPKT)
+ skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
+ else
+#endif
+ skb = alloc_skb(128, GFP_ATOMIC);
+
+ if(!skb)
+ return -ENOBUFS;
+
+#ifdef CONFIG_IP_PIMSM
+ if (assert == IGMPMSG_WHOLEPKT) {
+ /* Ugly, but we have no choice with this interface.
+ Duplicate old header, fix ihl, length etc.
+ And all this only to mangle msg->im_msgtype and
+ to set msg->im_mbz to "mbz" :-)
+ */
+ msg = (struct igmpmsg*)skb_push(skb, sizeof(struct iphdr));
+ skb->nh.raw = skb->h.raw = (u8*)msg;
+ memcpy(msg, pkt->nh.raw, sizeof(struct iphdr));
+ msg->im_msgtype = IGMPMSG_WHOLEPKT;
+ msg->im_mbz = 0;
+ msg->im_vif = reg_vif_num;
+ skb->nh.iph->ihl = sizeof(struct iphdr) >> 2;
+ skb->nh.iph->tot_len = htons(ntohs(pkt->nh.iph->tot_len) + sizeof(struct iphdr));
+ } else
+#endif
+ {
+
+ /*
+ * Copy the IP header
+ */
+
+ skb->nh.iph = (struct iphdr *)skb_put(skb, ihl);
+ memcpy(skb->data,pkt->data,ihl);
+ skb->nh.iph->protocol = 0; /* Flag to the kernel this is a route add */
+ msg = (struct igmpmsg*)skb->nh.iph;
+ msg->im_vif = vifi;
+ skb->dst = dst_clone(pkt->dst);
+
+ /*
+ * Add our header
+ */
+
+ igmp=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr));
+ igmp->type =
+ msg->im_msgtype = assert;
+ igmp->code = 0;
+ skb->nh.iph->tot_len=htons(skb->len); /* Fix the length */
+ skb->h.raw = skb->nh.raw;
+ }
+
+ /*
+ * Deliver to mrouted
+ */
+ if ((ret=sock_queue_rcv_skb(mroute_socket,skb))<0) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
+ kfree_skb(skb);
+ }
+
+ return ret;
+}
+
+/*
+ * Queue a packet for resolution
+ */
+
+static int ipmr_cache_unresolved(struct mfc_cache *cache, vifi_t vifi, struct sk_buff *skb)
+{
+ if(cache==NULL)
+ {
+ /*
+ * Create a new entry if allowable
+ */
+ if(cache_resolve_queue_len>=10 || (cache=ipmr_cache_alloc(GFP_ATOMIC))==NULL)
+ {
+ kfree_skb(skb);
+ return -ENOBUFS;
+ }
+ /*
+ * Fill in the new cache entry
+ */
+ cache->mfc_parent=ALL_VIFS;
+ cache->mfc_origin=skb->nh.iph->saddr;
+ cache->mfc_mcastgrp=skb->nh.iph->daddr;
+ cache->mfc_flags=MFC_QUEUED;
+ /*
+ * Link to the unresolved list
+ */
+ ipmr_cache_insert(cache);
+ cache_resolve_queue_len++;
+ /*
+ * Fire off the expiry timer
+ */
+ cache->mfc_timer.expires=jiffies+10*HZ;
+ add_timer(&cache->mfc_timer);
+ /*
+ * Reflect first query at mrouted.
+ */
+ if(mroute_socket)
+ {
+ /* If the report failed throw the cache entry
+ out - Brad Parker
+
+ OK, OK, Brad. Only do not forget to free skb
+ and return :-) --ANK
+ */
+ if (ipmr_cache_report(skb, vifi, IGMPMSG_NOCACHE)<0) {
+ ipmr_cache_delete(cache);
+ kfree_skb(skb);
+ return -ENOBUFS;
+ }
+ }
+ }
+ /*
+ * See if we can append the packet
+ */
+ if(cache->mfc_queuelen>3)
+ {
+ kfree_skb(skb);
+ return -ENOBUFS;
+ }
+ cache->mfc_queuelen++;
+ skb_queue_tail(&cache->mfc_unresolved,skb);
+ return 0;
+}
+
+/*
+ * MFC cache manipulation by user space mroute daemon
+ */
+
+int ipmr_mfc_modify(int action, struct mfcctl *mfc)
+{
+ struct mfc_cache *cache;
+
+ if(!MULTICAST(mfc->mfcc_mcastgrp.s_addr))
+ return -EINVAL;
+ /*
+ * Find the cache line
+ */
+
+ start_bh_atomic();
+
+ cache=ipmr_cache_find(mfc->mfcc_origin.s_addr,mfc->mfcc_mcastgrp.s_addr);
+
+ /*
+ * Delete an entry
+ */
+ if(action==MRT_DEL_MFC)
+ {
+ if(cache)
+ {
+ ipmr_cache_delete(cache);
+ end_bh_atomic();
+ return 0;
+ }
+ end_bh_atomic();
+ return -ENOENT;
+ }
+ if(cache)
+ {
+
+ /*
+ * Update the cache, see if it frees a pending queue
+ */
+
+ cache->mfc_flags|=MFC_RESOLVED;
+ cache->mfc_parent=mfc->mfcc_parent;
+ ipmr_update_threshoulds(cache, mfc->mfcc_ttls);
+
+ /*
+ * Check to see if we resolved a queued list. If so we
+ * need to send on the frames and tidy up.
+ */
+
+ if(cache->mfc_flags&MFC_QUEUED)
+ ipmr_cache_resolve(cache); /* Unhook & send the frames */
+ end_bh_atomic();
+ return 0;
+ }
+
+ /*
+ * Unsolicited update - that's ok, add anyway.
+ */
+
+
+ cache=ipmr_cache_alloc(GFP_ATOMIC);
+ if(cache==NULL)
+ {
+ end_bh_atomic();
+ return -ENOMEM;
+ }
+ cache->mfc_flags=MFC_RESOLVED;
+ cache->mfc_origin=mfc->mfcc_origin.s_addr;
+ cache->mfc_mcastgrp=mfc->mfcc_mcastgrp.s_addr;
+ cache->mfc_parent=mfc->mfcc_parent;
+ ipmr_update_threshoulds(cache, mfc->mfcc_ttls);
+ ipmr_cache_insert(cache);
+ end_bh_atomic();
+ return 0;
+}
+
+static void mrtsock_destruct(struct sock *sk)
+{
+ if (sk == mroute_socket) {
+ ipv4_devconf.mc_forwarding = 0;
+
+ mroute_socket=NULL;
+ synchronize_bh();
+
+ mroute_close(sk);
+ }
+}
+
+/*
+ * Socket options and virtual interface manipulation. The whole
+ * virtual interface system is a complete heap, but unfortunately
+ * that's how BSD mrouted happens to think. Maybe one day with a proper
+ * MOSPF/PIM router set up we can clean this up.
+ */
+
+int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
+{
+ struct vifctl vif;
+ struct mfcctl mfc;
+
+ if(optname!=MRT_INIT)
+ {
+ if(sk!=mroute_socket)
+ return -EACCES;
+ }
+
+ switch(optname)
+ {
+ case MRT_INIT:
+ if(sk->type!=SOCK_RAW || sk->num!=IPPROTO_IGMP)
+ return -EOPNOTSUPP;
+ if(optlen!=sizeof(int))
+ return -ENOPROTOOPT;
+ {
+ int opt;
+ if (get_user(opt,(int *)optval))
+ return -EFAULT;
+ if (opt != 1)
+ return -ENOPROTOOPT;
+ }
+ if(mroute_socket)
+ return -EADDRINUSE;
+ mroute_socket=sk;
+ ipv4_devconf.mc_forwarding = 1;
+ if (ip_ra_control(sk, 1, mrtsock_destruct) == 0)
+ return 0;
+ mrtsock_destruct(sk);
+ return -EADDRINUSE;
+ case MRT_DONE:
+ return ip_ra_control(sk, 0, NULL);
+ case MRT_ADD_VIF:
+ case MRT_DEL_VIF:
+ if(optlen!=sizeof(vif))
+ return -EINVAL;
+ if (copy_from_user(&vif,optval,sizeof(vif)))
+ return -EFAULT;
+ if(vif.vifc_vifi >= MAXVIFS)
+ return -ENFILE;
+ if(optname==MRT_ADD_VIF)
+ {
+ struct vif_device *v=&vif_table[vif.vifc_vifi];
+ struct device *dev;
+ struct in_device *in_dev;
+
+ /* Is vif busy ? */
+ if (vifc_map&(1<<vif.vifc_vifi))
+ return -EADDRINUSE;
+
+ switch (vif.vifc_flags) {
+#ifdef CONFIG_IP_PIMSM
+ case VIFF_REGISTER:
+
+ /*
+ * Special Purpose VIF in PIM
+ * All the packets will be sent to the daemon
+ */
+ if (reg_vif_num >= 0)
+ return -EADDRINUSE;
+ reg_vif_num = vif.vifc_vifi;
+ dev = ipmr_reg_vif(&vif);
+ if (!dev) {
+ reg_vif_num = -1;
+ return -ENOBUFS;
+ }
+ break;
+#endif
+ case VIFF_TUNNEL:
+ dev = ipmr_new_tunnel(&vif);
+ if (!dev)
+ return -ENOBUFS;
+ break;
+ case 0:
+ dev=ip_dev_find(vif.vifc_lcl_addr.s_addr);
+ if (!dev)
+ return -EADDRNOTAVAIL;
+ break;
+ default:
+#if 0
+ printk(KERN_DEBUG "ipmr_add_vif: flags %02x\n", vif.vifc_flags);
+#endif
+ return -EINVAL;
+ }
+
+ if ((in_dev = dev->ip_ptr) == NULL)
+ return -EADDRNOTAVAIL;
+ if (in_dev->cnf.mc_forwarding)
+ return -EADDRINUSE;
+ in_dev->cnf.mc_forwarding = 1;
+ dev_set_allmulti(dev, +1);
+ ip_rt_multicast_event(in_dev);
+
+ /*
+ * Fill in the VIF structures
+ */
+ start_bh_atomic();
+ v->rate_limit=vif.vifc_rate_limit;
+ v->local=vif.vifc_lcl_addr.s_addr;
+ v->remote=vif.vifc_rmt_addr.s_addr;
+ v->flags=vif.vifc_flags;
+ v->threshold=vif.vifc_threshold;
+ v->dev=dev;
+ v->bytes_in = 0;
+ v->bytes_out = 0;
+ v->pkt_in = 0;
+ v->pkt_out = 0;
+ v->link = dev->ifindex;
+ if (vif.vifc_flags&(VIFF_TUNNEL|VIFF_REGISTER))
+ v->link = dev->iflink;
+ vifc_map|=(1<<vif.vifc_vifi);
+ if (vif.vifc_vifi+1 > maxvif)
+ maxvif = vif.vifc_vifi+1;
+ end_bh_atomic();
+ return 0;
+ } else {
+ int ret;
+ rtnl_lock();
+ ret = vif_delete(vif.vifc_vifi);
+ rtnl_unlock();
+ return ret;
+ }
+
+ /*
+ * Manipulate the forwarding caches. These live
+ * in a sort of kernel/user symbiosis.
+ */
+ case MRT_ADD_MFC:
+ case MRT_DEL_MFC:
+ if(optlen!=sizeof(mfc))
+ return -EINVAL;
+ if (copy_from_user(&mfc,optval, sizeof(mfc)))
+ return -EFAULT;
+ return ipmr_mfc_modify(optname, &mfc);
+ /*
+ * Control PIM assert.
+ */
+ case MRT_ASSERT:
+ {
+ int v;
+ if(get_user(v,(int *)optval))
+ return -EFAULT;
+ mroute_do_assert=(v)?1:0;
+ return 0;
+ }
+#ifdef CONFIG_IP_PIMSM
+ case MRT_PIM:
+ {
+ int v;
+ if(get_user(v,(int *)optval))
+ return -EFAULT;
+ v = (v)?1:0;
+ if (v != mroute_do_pim) {
+ mroute_do_pim = v;
+ mroute_do_assert = v;
+#ifdef CONFIG_IP_PIMSM_V2
+ if (mroute_do_pim)
+ inet_add_protocol(&pim_protocol);
+ else
+ inet_del_protocol(&pim_protocol);
+#endif
+ }
+ return 0;
+ }
+#endif
+ /*
+ * Spurious command, or MRT_VERSION which you cannot
+ * set.
+ */
+ default:
+ return -ENOPROTOOPT;
+ }
+}
+
+/*
+ * Getsock opt support for the multicast routing system.
+ */
+
+int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen)
+{
+ int olr;
+ int val;
+
+ if(sk!=mroute_socket)
+ return -EACCES;
+ if(optname!=MRT_VERSION &&
+#ifdef CONFIG_IP_PIMSM
+ optname!=MRT_PIM &&
+#endif
+ optname!=MRT_ASSERT)
+ return -ENOPROTOOPT;
+
+ if(get_user(olr, optlen))
+ return -EFAULT;
+
+ olr=min(olr,sizeof(int));
+ if(put_user(olr,optlen))
+ return -EFAULT;
+ if(optname==MRT_VERSION)
+ val=0x0305;
+#ifdef CONFIG_IP_PIMSM
+ else if(optname==MRT_PIM)
+ val=mroute_do_pim;
+#endif
+ else
+ val=mroute_do_assert;
+ if(copy_to_user(optval,&val,olr))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * The IP multicast ioctl support routines.
+ */
+
+int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+ struct sioc_sg_req sr;
+ struct sioc_vif_req vr;
+ struct vif_device *vif;
+ struct mfc_cache *c;
+
+ switch(cmd)
+ {
+ case SIOCGETVIFCNT:
+ if (copy_from_user(&vr,(void *)arg,sizeof(vr)))
+ return -EFAULT;
+ if(vr.vifi>=maxvif)
+ return -EINVAL;
+ vif=&vif_table[vr.vifi];
+ if(vifc_map&(1<<vr.vifi))
+ {
+ vr.icount=vif->pkt_in;
+ vr.ocount=vif->pkt_out;
+ vr.ibytes=vif->bytes_in;
+ vr.obytes=vif->bytes_out;
+ if (copy_to_user((void *)arg,&vr,sizeof(vr)))
+ return -EFAULT;
+ return 0;
+ }
+ return -EADDRNOTAVAIL;
+ case SIOCGETSGCNT:
+ if (copy_from_user(&sr,(void *)arg,sizeof(sr)))
+ return -EFAULT;
+ for (c = mfc_cache_array[MFC_HASH(sr.grp.s_addr, sr.src.s_addr)];
+ c; c = c->next) {
+ if (sr.grp.s_addr == c->mfc_mcastgrp &&
+ sr.src.s_addr == c->mfc_origin) {
+ sr.pktcnt = c->mfc_pkt;
+ sr.bytecnt = c->mfc_bytes;
+ sr.wrong_if = c->mfc_wrong_if;
+ if (copy_to_user((void *)arg,&sr,sizeof(sr)))
+ return -EFAULT;
+ return 0;
+ }
+ }
+ return -EADDRNOTAVAIL;
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+/*
+ * Close the multicast socket, and clear the vif tables etc
+ */
+
+void mroute_close(struct sock *sk)
+{
+ int i;
+
+ /*
+ * Shut down all active vif entries
+ */
+ rtnl_lock();
+ for(i=0; i<maxvif; i++)
+ vif_delete(i);
+ rtnl_unlock();
+
+ /*
+ * Wipe the cache
+ */
+ for(i=0;i<MFC_LINES;i++)
+ {
+ start_bh_atomic();
+ while(mfc_cache_array[i]!=NULL)
+ ipmr_cache_delete(mfc_cache_array[i]);
+ end_bh_atomic();
+ }
+}
+
+static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct vif_device *v;
+ int ct;
+ if (event != NETDEV_UNREGISTER)
+ return NOTIFY_DONE;
+ v=&vif_table[0];
+ for(ct=0;ct<maxvif;ct++) {
+ if (vifc_map&(1<<ct) && v->dev==ptr)
+ vif_delete(ct);
+ v++;
+ }
+ return NOTIFY_DONE;
+}
+
+
+static struct notifier_block ip_mr_notifier={
+ ipmr_device_event,
+ NULL,
+ 0
+};
+
+/*
+ * Encapsulate a packet by attaching a valid IPIP header to it.
+ * This avoids tunnel drivers and other mess and gives us the speed so
+ * important for multicast video.
+ */
+
+static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr)
+{
+ struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr));
+
+ iph->version = 4;
+ iph->tos = skb->nh.iph->tos;
+ iph->ttl = skb->nh.iph->ttl;
+ iph->frag_off = 0;
+ iph->daddr = daddr;
+ iph->saddr = saddr;
+ iph->protocol = IPPROTO_IPIP;
+ iph->ihl = 5;
+ iph->tot_len = htons(skb->len);
+ iph->id = htons(ip_id_count++);
+ ip_send_check(iph);
+
+ skb->h.ipiph = skb->nh.iph;
+ skb->nh.iph = iph;
+}
+
+/*
+ * Processing handlers for ipmr_forward
+ */
+
+static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c,
+ int vifi, int last)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct vif_device *vif = &vif_table[vifi];
+ struct device *dev;
+ struct rtable *rt;
+ int encap = 0;
+ struct sk_buff *skb2;
+
+#ifdef CONFIG_IP_PIMSM
+ if (vif->flags & VIFF_REGISTER) {
+ vif->pkt_out++;
+ vif->bytes_out+=skb->len;
+ ((struct net_device_stats*)vif->dev->priv)->tx_bytes += skb->len;
+ ((struct net_device_stats*)vif->dev->priv)->tx_packets++;
+ ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT);
+ return;
+ }
+#endif
+
+ if (vif->flags&VIFF_TUNNEL) {
+ if (ip_route_output(&rt, vif->remote, vif->local, RT_TOS(iph->tos), vif->link))
+ return;
+ encap = sizeof(struct iphdr);
+ } else {
+ if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), vif->link))
+ return;
+ }
+
+ dev = rt->u.dst.dev;
+
+ if (skb->len+encap > rt->u.dst.pmtu && (ntohs(iph->frag_off) & IP_DF)) {
+ /* Do not fragment multicasts. Alas, IPv4 does not
+ allow to send ICMP, so that packets will disappear
+ to blackhole.
+ */
+
+ ip_statistics.IpFragFails++;
+ ip_rt_put(rt);
+ return;
+ }
+
+ encap += dev->hard_header_len;
+
+ if (skb_headroom(skb) < encap || skb_cloned(skb) || !last)
+ skb2 = skb_realloc_headroom(skb, (encap + 15)&~15);
+ else if (atomic_read(&skb->users) != 1)
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ else {
+ atomic_inc(&skb->users);
+ skb2 = skb;
+ }
+
+ if (skb2 == NULL) {
+ ip_rt_put(rt);
+ return;
+ }
+
+ vif->pkt_out++;
+ vif->bytes_out+=skb->len;
+
+ dst_release(skb2->dst);
+ skb2->dst = &rt->u.dst;
+ iph = skb2->nh.iph;
+ ip_decrease_ttl(iph);
+
+#ifdef CONFIG_FIREWALL
+ if (call_fw_firewall(PF_INET, vif->dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) {
+ kfree_skb(skb2);
+ return;
+ }
+ if (call_out_firewall(PF_INET, vif->dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) {
+ kfree_skb(skb2);
+ return;
+ }
+#endif
+ if (vif->flags & VIFF_TUNNEL) {
+ ip_encap(skb2, vif->local, vif->remote);
+#ifdef CONFIG_FIREWALL
+ /* Double output firewalling on tunnels: one is on tunnel
+ another one is on real device.
+ */
+ if (call_out_firewall(PF_INET, dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) {
+ kfree_skb(skb2);
+ return;
+ }
+#endif
+ ((struct ip_tunnel *)vif->dev->priv)->stat.tx_packets++;
+ ((struct ip_tunnel *)vif->dev->priv)->stat.tx_bytes+=skb2->len;
+ }
+
+ IPCB(skb2)->flags |= IPSKB_FORWARDED;
+
+
+ /*
+ * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
+ * not only before forwarding, but after forwarding on all output
+ * interfaces. It is clear, if mrouter runs a multicasting
+ * program, it should receive packets not depending to what interface
+ * program is joined.
+ * If we will not make it, the program will have to join on all
+ * interfaces. On the other hand, multihoming host (or router, but
+ * not mrouter) cannot join to more than one interface - it will
+ * result in receiving multiple packets.
+ */
+ if (skb2->len <= rt->u.dst.pmtu)
+ skb2->dst->output(skb2);
+ else
+ ip_fragment(skb2, skb2->dst->output);
+}
+
+int ipmr_find_vif(struct device *dev)
+{
+ int ct;
+ for (ct=0; ct<maxvif; ct++) {
+ if (vifc_map&(1<<ct) && vif_table[ct].dev == dev)
+ return ct;
+ }
+ return ALL_VIFS;
+}
+
+/* "local" means that we should preserve one skb (for local delivery) */
+
+int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
+{
+ int psend = -1;
+ int vif, ct;
+
+ vif = cache->mfc_parent;
+ cache->mfc_pkt++;
+ cache->mfc_bytes += skb->len;
+
+ /*
+ * Wrong interface: drop packet and (maybe) send PIM assert.
+ */
+ if (vif_table[vif].dev != skb->dev) {
+ int true_vifi;
+
+ if (((struct rtable*)skb->dst)->key.iif == 0) {
+ /* It is our own packet, looped back.
+ Very complicated situation...
+
+ The best workaround until routing daemons will be
+ fixed is not to redistribute packet, if it was
+ send through wrong interface. It means, that
+ multicast applications WILL NOT work for
+ (S,G), which have default multicast route pointing
+ to wrong oif. In any case, it is not a good
+ idea to use multicasting applications on router.
+ */
+ goto dont_forward;
+ }
+
+ cache->mfc_wrong_if++;
+ true_vifi = ipmr_find_vif(skb->dev);
+
+ if (true_vifi < MAXVIFS && mroute_do_assert &&
+ /* pimsm uses asserts, when switching from RPT to SPT,
+ so that we cannot check that packet arrived on an oif.
+ It is bad, but otherwise we would need to move pretty
+ large chunk of pimd to kernel. Ough... --ANK
+ */
+ (mroute_do_pim || cache->mfc_ttls[true_vifi] < 255) &&
+ jiffies - cache->mfc_last_assert > MFC_ASSERT_THRESH) {
+ cache->mfc_last_assert = jiffies;
+ ipmr_cache_report(skb, true_vifi, IGMPMSG_WRONGVIF);
+ }
+ goto dont_forward;
+ }
+
+ vif_table[vif].pkt_in++;
+ vif_table[vif].bytes_in+=skb->len;
+
+ /*
+ * Forward the frame
+ */
+ for (ct = cache->mfc_maxvif-1; ct >= cache->mfc_minvif; ct--) {
+ if (skb->nh.iph->ttl > cache->mfc_ttls[ct]) {
+ if (psend != -1)
+ ipmr_queue_xmit(skb, cache, psend, 0);
+ psend=ct;
+ }
+ }
+ if (psend != -1)
+ ipmr_queue_xmit(skb, cache, psend, !local);
+
+dont_forward:
+ if (!local)
+ kfree_skb(skb);
+ return 0;
+}
+
+
+/*
+ * Multicast packets for forwarding arrive here
+ */
+
+int ip_mr_input(struct sk_buff *skb)
+{
+ struct mfc_cache *cache;
+ int local = ((struct rtable*)skb->dst)->rt_flags&RTCF_LOCAL;
+
+ /* Packet is looped back after forward, it should not be
+ forwarded second time, but still can be delivered locally.
+ */
+ if (IPCB(skb)->flags&IPSKB_FORWARDED)
+ goto dont_forward;
+
+ if (!local) {
+ if (IPCB(skb)->opt.router_alert) {
+ if (ip_call_ra_chain(skb))
+ return 0;
+ } else if (skb->nh.iph->protocol == IPPROTO_IGMP && mroute_socket) {
+ /* IGMPv1 (and broken IGMPv2 implementations sort of
+ Cisco IOS <= 11.2(8)) do not put router alert
+ option to IGMP packets destined to routable
+ groups. It is very bad, because it means
+ that we can forward NO IGMP messages.
+ */
+ raw_rcv(mroute_socket, skb);
+ return 0;
+ }
+ }
+
+ cache = ipmr_cache_find(skb->nh.iph->saddr, skb->nh.iph->daddr);
+
+ /*
+ * No usable cache entry
+ */
+
+ if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) {
+ int vif;
+
+ if (local) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ ip_local_deliver(skb);
+ if (skb2 == NULL)
+ return -ENOBUFS;
+ skb = skb2;
+ }
+
+ vif = ipmr_find_vif(skb->dev);
+ if (vif != ALL_VIFS) {
+ ipmr_cache_unresolved(cache, vif, skb);
+ return -EAGAIN;
+ }
+ kfree_skb(skb);
+ return 0;
+ }
+
+ ip_mr_forward(skb, cache, local);
+
+ if (local)
+ return ip_local_deliver(skb);
+ return 0;
+
+dont_forward:
+ if (local)
+ return ip_local_deliver(skb);
+ kfree_skb(skb);
+ return 0;
+}
+
+#ifdef CONFIG_IP_PIMSM_V1
+/*
+ * Handle IGMP messages of PIMv1
+ */
+
+int pim_rcv_v1(struct sk_buff * skb, unsigned short len)
+{
+ struct igmphdr *pim = (struct igmphdr*)skb->h.raw;
+ struct iphdr *encap;
+
+ if (!mroute_do_pim ||
+ len < sizeof(*pim) + sizeof(*encap) ||
+ pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER ||
+ reg_dev == NULL) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ encap = (struct iphdr*)(skb->h.raw + sizeof(struct igmphdr));
+ /*
+ Check that:
+ a. packet is really destinted to a multicast group
+ b. packet is not a NULL-REGISTER
+ c. packet is not truncated
+ */
+ if (!MULTICAST(encap->daddr) ||
+ ntohs(encap->tot_len) == 0 ||
+ ntohs(encap->tot_len) + sizeof(*pim) > len) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ skb->mac.raw = skb->nh.raw;
+ skb_pull(skb, (u8*)encap - skb->data);
+ skb->nh.iph = (struct iphdr *)skb->data;
+ skb->dev = reg_dev;
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+ skb->protocol = __constant_htons(ETH_P_IP);
+ skb->ip_summed = 0;
+ skb->pkt_type = PACKET_HOST;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len;
+ ((struct net_device_stats*)reg_dev->priv)->rx_packets++;
+ netif_rx(skb);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_IP_PIMSM_V2
+int pim_rcv(struct sk_buff * skb, unsigned short len)
+{
+ struct pimreghdr *pim = (struct pimreghdr*)skb->h.raw;
+ struct iphdr *encap;
+
+ if (len < sizeof(*pim) + sizeof(*encap) ||
+ pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
+ (pim->flags&PIM_NULL_REGISTER) ||
+ reg_dev == NULL ||
+ (ip_compute_csum((void *)pim, sizeof(*pim)) &&
+ ip_compute_csum((void *)pim, len))) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ /* check if the inner packet is destined to mcast group */
+ encap = (struct iphdr*)(skb->h.raw + sizeof(struct pimreghdr));
+ if (!MULTICAST(encap->daddr) ||
+ ntohs(encap->tot_len) == 0 ||
+ ntohs(encap->tot_len) + sizeof(*pim) > len) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ skb->mac.raw = skb->nh.raw;
+ skb_pull(skb, (u8*)encap - skb->data);
+ skb->nh.iph = (struct iphdr *)skb->data;
+ skb->dev = reg_dev;
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+ skb->protocol = __constant_htons(ETH_P_IP);
+ skb->ip_summed = 0;
+ skb->pkt_type = PACKET_HOST;
+ dst_release(skb->dst);
+ ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len;
+ ((struct net_device_stats*)reg_dev->priv)->rx_packets++;
+ skb->dst = NULL;
+ netif_rx(skb);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_RTNETLINK
+
+static int
+ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
+{
+ int ct;
+ struct rtnexthop *nhp;
+ struct device *dev = vif_table[c->mfc_parent].dev;
+ u8 *b = skb->tail;
+ struct rtattr *mp_head;
+
+ if (dev)
+ RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex);
+
+ mp_head = (struct rtattr*)skb_put(skb, RTA_LENGTH(0));
+
+ for (ct = c->mfc_minvif; ct < c->mfc_maxvif; ct++) {
+ if (c->mfc_ttls[ct] < 255) {
+ if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
+ goto rtattr_failure;
+ nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
+ nhp->rtnh_flags = 0;
+ nhp->rtnh_hops = c->mfc_ttls[ct];
+ nhp->rtnh_ifindex = vif_table[ct].dev->ifindex;
+ nhp->rtnh_len = sizeof(*nhp);
+ }
+ }
+ mp_head->rta_type = RTA_MULTIPATH;
+ mp_head->rta_len = skb->tail - (u8*)mp_head;
+ rtm->rtm_type = RTN_MULTICAST;
+ return 1;
+
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -EMSGSIZE;
+}
+
+int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
+{
+ struct mfc_cache *cache;
+ struct rtable *rt = (struct rtable*)skb->dst;
+
+ start_bh_atomic();
+ cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
+ if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) {
+ struct device *dev;
+ int vif;
+ int err;
+
+ if (nowait) {
+ end_bh_atomic();
+ return -EAGAIN;
+ }
+
+ dev = skb->dev;
+ if (dev == NULL || (vif = ipmr_find_vif(dev)) == ALL_VIFS) {
+ end_bh_atomic();
+ return -ENODEV;
+ }
+ skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
+ skb->nh.iph->ihl = sizeof(struct iphdr)>>2;
+ skb->nh.iph->saddr = rt->rt_src;
+ skb->nh.iph->daddr = rt->rt_dst;
+ skb->nh.iph->version = 0;
+ err = ipmr_cache_unresolved(cache, vif, skb);
+ end_bh_atomic();
+ return err;
+ }
+ /* Resolved cache entry is not changed by net bh,
+ so that we are allowed to enable it.
+ */
+ end_bh_atomic();
+
+ if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
+ cache->mfc_flags |= MFC_NOTIFY;
+ return ipmr_fill_mroute(skb, cache, rtm);
+}
+#endif
+
+/*
+ * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
+ */
+
+int ipmr_vif_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ struct vif_device *vif;
+ int len=0;
+ off_t pos=0;
+ off_t begin=0;
+ int size;
+ int ct;
+
+ len += sprintf(buffer,
+ "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
+ pos=len;
+
+ for (ct=0;ct<maxvif;ct++)
+ {
+ char *name = "none";
+ vif=&vif_table[ct];
+ if(!(vifc_map&(1<<ct)))
+ continue;
+ if (vif->dev)
+ name = vif->dev->name;
+ size = sprintf(buffer+len, "%2d %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
+ ct, name, vif->bytes_in, vif->pkt_in, vif->bytes_out, vif->pkt_out,
+ vif->flags, vif->local, vif->remote);
+ len+=size;
+ pos+=size;
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ break;
+ }
+
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ return len;
+}
+
+int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ struct mfc_cache *mfc;
+ int len=0;
+ off_t pos=0;
+ off_t begin=0;
+ int size;
+ int ct;
+
+ len += sprintf(buffer,
+ "Group Origin Iif Pkts Bytes Wrong Oifs\n");
+ pos=len;
+
+ for (ct=0;ct<MFC_LINES;ct++)
+ {
+ start_bh_atomic();
+ mfc=mfc_cache_array[ct];
+ while(mfc!=NULL)
+ {
+ int n;
+
+ /*
+ * Interface forwarding map
+ */
+ size = sprintf(buffer+len, "%08lX %08lX %-3d %8ld %8ld %8ld",
+ (unsigned long)mfc->mfc_mcastgrp,
+ (unsigned long)mfc->mfc_origin,
+ mfc->mfc_parent == ALL_VIFS ? -1 : mfc->mfc_parent,
+ (mfc->mfc_flags & MFC_QUEUED) ? mfc->mfc_unresolved.qlen : mfc->mfc_pkt,
+ mfc->mfc_bytes,
+ mfc->mfc_wrong_if);
+ for(n=mfc->mfc_minvif;n<mfc->mfc_maxvif;n++)
+ {
+ if(vifc_map&(1<<n) && mfc->mfc_ttls[n] < 255)
+ size += sprintf(buffer+len+size, " %2d:%-3d", n, mfc->mfc_ttls[n]);
+ }
+ size += sprintf(buffer+len+size, "\n");
+ len+=size;
+ pos+=size;
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ {
+ end_bh_atomic();
+ goto done;
+ }
+ mfc=mfc->next;
+ }
+ end_bh_atomic();
+ }
+done:
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ if (len < 0) {
+ len = 0;
+ }
+ return len;
+}
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_ipmr_vif = {
+ PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ ipmr_vif_info
+};
+static struct proc_dir_entry proc_net_ipmr_mfc = {
+ PROC_NET_IPMR_MFC, 11 ,"ip_mr_cache",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ ipmr_mfc_info
+};
+#endif
+
+#ifdef CONFIG_IP_PIMSM_V2
+struct inet_protocol pim_protocol =
+{
+ pim_rcv, /* PIM handler */
+ NULL, /* PIM error control */
+ NULL, /* next */
+ IPPROTO_PIM, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "PIM" /* name */
+};
+#endif
+
+
+/*
+ * Setup for IP multicast routing
+ */
+
+__initfunc(void ip_mr_init(void))
+{
+ printk(KERN_INFO "Linux IP multicast router 0.06 plus PIM-SM\n");
+ register_netdevice_notifier(&ip_mr_notifier);
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_net_ipmr_vif);
+ proc_net_register(&proc_net_ipmr_mfc);
+#endif
+}
diff --git a/pfinet/linux-inet/proc.c b/pfinet/linux-src/net/ipv4/proc.c
index aec473a2..1640a056 100644
--- a/pfinet/linux-inet/proc.c
+++ b/pfinet/linux-src/net/ipv4/proc.c
@@ -7,7 +7,7 @@
* PROC file system. It is mainly used for debugging and
* statistics.
*
- * Version: @(#)proc.c 1.0.5 05/27/93
+ * Version: $Id: proc.c,v 1.34 1999/02/08 11:20:34 davem Exp $
*
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -21,6 +21,11 @@
* Alan Cox : Make /proc safer.
* Erik Schoenfelder : /proc/net/snmp
* Alan Cox : Handle dead sockets properly.
+ * Gerhard Koerting : Show both timers
+ * Alan Cox : Allow inode to be NULL (kernel socket)
+ * Andi Kleen : Add support for open_requests and
+ * split functions for more readibility.
+ * Andi Kleen : Add support for /proc/net/netstat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,7 +33,6 @@
* 2 of the License, or (at your option) any later version.
*/
#include <asm/system.h>
-#include <linux/autoconf.h>
#include <linux/sched.h>
#include <linux/socket.h>
#include <linux/net.h>
@@ -37,14 +41,116 @@
#include <linux/param.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
-#include "ip.h"
-#include "icmp.h"
-#include "protocol.h"
-#include "tcp.h"
-#include "udp.h"
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/udp.h>
#include <linux/skbuff.h>
-#include "sock.h"
-#include "raw.h"
+#include <net/sock.h>
+#include <net/raw.h>
+
+/* Format a single open_request into tmpbuf. */
+static inline void get__openreq(struct sock *sk, struct open_request *req,
+ char *tmpbuf,
+ int i)
+{
+ sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
+ i,
+ (long unsigned int)req->af.v4_req.loc_addr,
+ ntohs(sk->sport),
+ (long unsigned int)req->af.v4_req.rmt_addr,
+ ntohs(req->rmt_port),
+ TCP_SYN_RECV,
+ 0,0, /* could print option size, but that is af dependent. */
+ 1, /* timers active (only the expire timer) */
+ (unsigned long)(req->expires - jiffies),
+ req->retrans,
+ sk->socket ? sk->socket->inode->i_uid : 0,
+ 0, /* non standard timer */
+ 0 /* open_requests have no inode */
+ );
+}
+
+/* Format a single socket into tmpbuf. */
+static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
+{
+ unsigned long dest, src;
+ unsigned short destp, srcp;
+ int timer_active, timer_active1, timer_active2;
+ int tw_bucket = 0;
+ unsigned long timer_expires;
+ struct tcp_opt *tp = &sp->tp_pinfo.af_tcp;
+
+ dest = sp->daddr;
+ src = sp->rcv_saddr;
+ destp = sp->dport;
+ srcp = sp->sport;
+
+ /* FIXME: The fact that retransmit_timer occurs as a field
+ * in two different parts of the socket structure is,
+ * to say the least, confusing. This code now uses the
+ * right retransmit_timer variable, but I'm not sure
+ * the rest of the timer stuff is still correct.
+ * In particular I'm not sure what the timeout value
+ * is suppose to reflect (as opposed to tm->when). -- erics
+ */
+
+ destp = ntohs(destp);
+ srcp = ntohs(srcp);
+ if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
+ extern int tcp_tw_death_row_slot;
+ struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
+ int slot_dist;
+
+ tw_bucket = 1;
+ timer_active1 = timer_active2 = 0;
+ timer_active = 3;
+ slot_dist = tw->death_slot;
+ if(slot_dist > tcp_tw_death_row_slot)
+ slot_dist = (TCP_TWKILL_SLOTS - slot_dist) + tcp_tw_death_row_slot;
+ else
+ slot_dist = tcp_tw_death_row_slot - slot_dist;
+ timer_expires = jiffies + (slot_dist * TCP_TWKILL_PERIOD);
+ } else {
+ timer_active1 = del_timer(&tp->retransmit_timer);
+ timer_active2 = del_timer(&sp->timer);
+ if (!timer_active1) tp->retransmit_timer.expires=0;
+ if (!timer_active2) sp->timer.expires=0;
+ timer_active = 0;
+ timer_expires = (unsigned) -1;
+ }
+ if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
+ timer_active = 1;
+ timer_expires = tp->retransmit_timer.expires;
+ }
+ if (timer_active2 && sp->timer.expires < timer_expires) {
+ timer_active = 2;
+ timer_expires = sp->timer.expires;
+ }
+ if(timer_active == 0)
+ timer_expires = jiffies;
+ sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+ i, src, srcp, dest, destp, sp->state,
+ (tw_bucket ?
+ 0 :
+ (format == 0) ?
+ tp->write_seq-tp->snd_una : atomic_read(&sp->wmem_alloc)),
+ (tw_bucket ?
+ 0 :
+ (format == 0) ?
+ tp->rcv_nxt-tp->copied_seq: atomic_read(&sp->rmem_alloc)),
+ timer_active, timer_expires-jiffies,
+ (tw_bucket ? 0 : tp->retransmits),
+ (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
+ (!tw_bucket && timer_active) ? sp->timeout : 0,
+ (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
+
+ if (timer_active1) add_timer(&tp->retransmit_timer);
+ if (timer_active2) add_timer(&sp->timer);
+}
/*
* Get__netinfo returns the length of that string.
@@ -52,129 +158,113 @@
* KNOWN BUGS
* As in get_unix_netinfo, the buffer might be too small. If this
* happens, get__netinfo returns only part of the available infos.
+ *
+ * Assumes that buffer length is a multiply of 128 - if not it will
+ * write past the end.
*/
static int
get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
{
- struct sock **s_array;
- struct sock *sp;
- int i;
- int timer_active;
- unsigned long dest, src;
- unsigned short destp, srcp;
- int len=0;
+ struct sock *sp, *next;
+ int len=0, i = 0;
off_t pos=0;
- off_t begin=0;
+ off_t begin;
+ char tmpbuf[129];
- s_array = pro->sock_array;
- len+=sprintf(buffer, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n");
-/*
- * This was very pretty but didn't work when a socket is destroyed at the wrong moment
- * (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing
- * with timers we just concede defeat and cli().
- */
- for(i = 0; i < SOCK_ARRAY_SIZE; i++)
- {
- cli();
- sp = s_array[i];
- while(sp != NULL)
- {
- dest = sp->daddr;
- src = sp->saddr;
- destp = sp->dummy_th.dest;
- srcp = sp->dummy_th.source;
+ if (offset < 128)
+ len += sprintf(buffer, "%-127s\n",
+ " sl local_address rem_address st tx_queue "
+ "rx_queue tr tm->when retrnsmt uid timeout inode");
+ pos = 128;
+ SOCKHASH_LOCK();
+ sp = pro->sklist_next;
+ while(sp != (struct sock *)pro) {
+ if (format == 0 && sp->state == TCP_LISTEN) {
+ struct open_request *req;
- /* Since we are Little Endian we need to swap the bytes :-( */
- destp = ntohs(destp);
- srcp = ntohs(srcp);
- timer_active = del_timer(&sp->timer);
- if (!timer_active)
- sp->timer.expires = 0;
- len+=sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d %d\n",
- i, src, srcp, dest, destp, sp->state,
- format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc,
- format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
- timer_active, sp->timer.expires, (unsigned) sp->retransmits,
- sp->socket?SOCK_INODE(sp->socket)->i_uid:0,
- timer_active?sp->timeout:0);
- if (timer_active)
- add_timer(&sp->timer);
- /*
- * All sockets with (port mod SOCK_ARRAY_SIZE) = i
- * are kept in sock_array[i], so we must follow the
- * 'next' link to get them all.
- */
- sp = sp->next;
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
+ for (req = sp->tp_pinfo.af_tcp.syn_wait_queue; req;
+ i++, req = req->dl_next) {
+ if (req->sk)
+ continue;
+ pos += 128;
+ if (pos < offset)
+ continue;
+ get__openreq(sp, req, tmpbuf, i);
+ len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+ if(len >= length)
+ goto out;
}
- if(pos>offset+length)
- break;
}
- sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up
- before this will clear before we jump back and cli, so it's not as bad as it looks */
- if(pos>offset+length)
+
+ pos += 128;
+ if (pos < offset)
+ goto next;
+
+ get__sock(sp, tmpbuf, i, format);
+
+ len += sprintf(buffer+len, "%-127s\n", tmpbuf);
+ if(len >= length)
break;
+ next:
+ next = sp->sklist_next;
+ sp = next;
+ i++;
}
- *start=buffer+(offset-begin);
- len-=(offset-begin);
+out:
+ SOCKHASH_UNLOCK();
+
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
if(len>length)
- len=length;
+ len = length;
+ if (len<0)
+ len = 0;
return len;
}
-
-int tcp_get_info(char *buffer, char **start, off_t offset, int length)
+int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
return get__netinfo(&tcp_prot, buffer,0, start, offset, length);
}
-
-int udp_get_info(char *buffer, char **start, off_t offset, int length)
+int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
return get__netinfo(&udp_prot, buffer,1, start, offset, length);
}
-
-int raw_get_info(char *buffer, char **start, off_t offset, int length)
+int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
return get__netinfo(&raw_prot, buffer,1, start, offset, length);
}
-
/*
* Report socket allocation statistics [mea@utu.fi]
*/
-int afinet_get_info(char *buffer, char **start, off_t offset, int length)
+int afinet_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
/* From net/socket.c */
extern int socket_get_info(char *, char **, off_t, int);
-#ifndef _HURD_
- extern struct proto packet_prot;
- int len = socket_get_info(buffer,start,offset,length);
-#else
- int len = 0;
-#endif
+ int len = socket_get_info(buffer,start,offset,length);
- len += sprintf(buffer+len,"SOCK_ARRAY_SIZE=%d\n",SOCK_ARRAY_SIZE);
len += sprintf(buffer+len,"TCP: inuse %d highest %d\n",
tcp_prot.inuse, tcp_prot.highestinuse);
len += sprintf(buffer+len,"UDP: inuse %d highest %d\n",
udp_prot.inuse, udp_prot.highestinuse);
len += sprintf(buffer+len,"RAW: inuse %d highest %d\n",
raw_prot.inuse, raw_prot.highestinuse);
-#ifndef _HURD_
- len += sprintf(buffer+len,"PAC: inuse %d highest %d\n",
- packet_prot.inuse, packet_prot.highestinuse);
-#endif
+ if (offset >= len)
+ {
+ *start = buffer;
+ return 0;
+ }
*start = buffer + offset;
len -= offset;
if (len > length)
len = length;
+ if (len < 0)
+ len = 0;
return len;
}
@@ -183,7 +273,7 @@ int afinet_get_info(char *buffer, char **start, off_t offset, int length)
* Called from the PROCfs module. This outputs /proc/net/snmp.
*/
-int snmp_get_info(char *buffer, char **start, off_t offset, int length)
+int snmp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
extern struct tcp_mib tcp_statistics;
extern struct udp_mib udp_statistics;
@@ -224,14 +314,15 @@ int snmp_get_info(char *buffer, char **start, off_t offset, int length)
icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps);
len += sprintf (buffer + len,
- "Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs\n"
- "Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
+ "Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
+ "Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin,
tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn,
tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens,
tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets,
tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs,
- tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs);
+ tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs,
+ tcp_statistics.TcpInErrs, tcp_statistics.TcpOutRsts);
len += sprintf (buffer + len,
"Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n",
@@ -252,6 +343,45 @@ int snmp_get_info(char *buffer, char **start, off_t offset, int length)
len -= offset;
if (len > length)
len = length;
+ if (len < 0)
+ len = 0;
return len;
}
+/*
+ * Output /proc/net/netstat
+ */
+
+int netstat_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ extern struct linux_mib net_statistics;
+ int len;
+
+ len = sprintf(buffer,
+ "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
+ " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
+ " OutOfWindowIcmps LockDroppedIcmps\n"
+ "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
+ net_statistics.SyncookiesSent,
+ net_statistics.SyncookiesRecv,
+ net_statistics.SyncookiesFailed,
+ net_statistics.EmbryonicRsts,
+ net_statistics.PruneCalled,
+ net_statistics.RcvPruned,
+ net_statistics.OfoPruned,
+ net_statistics.OutOfWindowIcmps,
+ net_statistics.LockDroppedIcmps);
+
+ if (offset >= len)
+ {
+ *start = buffer;
+ return 0;
+ }
+ *start = buffer + offset;
+ len -= offset;
+ if (len > length)
+ len = length;
+ if (len < 0)
+ len = 0;
+ return len;
+}
diff --git a/pfinet/linux-src/net/ipv4/protocol.c b/pfinet/linux-src/net/ipv4/protocol.c
new file mode 100644
index 00000000..b47480be
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/protocol.c
@@ -0,0 +1,211 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * INET protocol dispatch tables.
+ *
+ * Version: $Id: protocol.c,v 1.9 1997/10/29 20:27:34 kuznet Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * Fixes:
+ * Alan Cox : Ahah! udp icmp errors don't work because
+ * udp_err is never called!
+ * Alan Cox : Added new fields for init and ready for
+ * proper fragmentation (_NO_ 4K limits!)
+ * Richard Colella : Hang on hash collision
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/ipip.h>
+#include <linux/igmp.h>
+
+#define IPPROTO_PREVIOUS NULL
+
+#ifdef CONFIG_IP_MULTICAST
+
+static struct inet_protocol igmp_protocol =
+{
+ igmp_rcv, /* IGMP handler */
+ NULL, /* IGMP error control */
+ IPPROTO_PREVIOUS, /* next */
+ IPPROTO_IGMP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "IGMP" /* name */
+};
+
+#undef IPPROTO_PREVIOUS
+#define IPPROTO_PREVIOUS &igmp_protocol
+
+#endif
+
+static struct inet_protocol tcp_protocol =
+{
+ tcp_v4_rcv, /* TCP handler */
+ tcp_v4_err, /* TCP error control */
+ IPPROTO_PREVIOUS,
+ IPPROTO_TCP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "TCP" /* name */
+};
+
+#undef IPPROTO_PREVIOUS
+#define IPPROTO_PREVIOUS &tcp_protocol
+
+static struct inet_protocol udp_protocol =
+{
+ udp_rcv, /* UDP handler */
+ udp_err, /* UDP error control */
+ IPPROTO_PREVIOUS, /* next */
+ IPPROTO_UDP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "UDP" /* name */
+};
+
+#undef IPPROTO_PREVIOUS
+#define IPPROTO_PREVIOUS &udp_protocol
+
+
+static struct inet_protocol icmp_protocol =
+{
+ icmp_rcv, /* ICMP handler */
+ NULL, /* ICMP error control */
+ IPPROTO_PREVIOUS, /* next */
+ IPPROTO_ICMP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "ICMP" /* name */
+};
+
+#undef IPPROTO_PREVIOUS
+#define IPPROTO_PREVIOUS &icmp_protocol
+
+
+struct inet_protocol *inet_protocol_base = IPPROTO_PREVIOUS;
+
+struct inet_protocol *inet_protos[MAX_INET_PROTOS] =
+{
+ NULL
+};
+
+
+/*
+ * Find a protocol in the protocol tables given its
+ * IP type.
+ */
+
+struct inet_protocol *inet_get_protocol(unsigned char prot)
+{
+ unsigned char hash;
+ struct inet_protocol *p;
+
+ hash = prot & (MAX_INET_PROTOS - 1);
+ for (p = inet_protos[hash] ; p != NULL; p=p->next)
+ {
+ if (p->protocol == prot)
+ return((struct inet_protocol *) p);
+ }
+ return(NULL);
+}
+
+/*
+ * Add a protocol handler to the hash tables
+ */
+
+void inet_add_protocol(struct inet_protocol *prot)
+{
+ unsigned char hash;
+ struct inet_protocol *p2;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ prot ->next = inet_protos[hash];
+ inet_protos[hash] = prot;
+ prot->copy = 0;
+
+ /*
+ * Set the copy bit if we need to.
+ */
+
+ p2 = (struct inet_protocol *) prot->next;
+ while(p2 != NULL)
+ {
+ if (p2->protocol == prot->protocol)
+ {
+ prot->copy = 1;
+ break;
+ }
+ p2 = (struct inet_protocol *) p2->next;
+ }
+}
+
+/*
+ * Remove a protocol from the hash tables.
+ */
+
+int inet_del_protocol(struct inet_protocol *prot)
+{
+ struct inet_protocol *p;
+ struct inet_protocol *lp = NULL;
+ unsigned char hash;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ if (prot == inet_protos[hash])
+ {
+ inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
+ return(0);
+ }
+
+ p = (struct inet_protocol *) inet_protos[hash];
+ while(p != NULL)
+ {
+ /*
+ * We have to worry if the protocol being deleted is
+ * the last one on the list, then we may need to reset
+ * someone's copied bit.
+ */
+ if (p->next != NULL && p->next == prot)
+ {
+ /*
+ * if we are the last one with this protocol and
+ * there is a previous one, reset its copy bit.
+ */
+ if (p->copy == 0 && lp != NULL)
+ lp->copy = 0;
+ p->next = prot->next;
+ return(0);
+ }
+ if (p->next != NULL && p->next->protocol == prot->protocol)
+ lp = p;
+
+ p = (struct inet_protocol *) p->next;
+ }
+ return(-1);
+}
diff --git a/pfinet/linux-inet/rarp.c b/pfinet/linux-src/net/ipv4/rarp.c
index 72924bb2..7f7c7e3f 100644
--- a/pfinet/linux-inet/rarp.c
+++ b/pfinet/linux-src/net/ipv4/rarp.c
@@ -3,9 +3,11 @@
* Copyright (C) 1994 by Ross Martin
* Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche
*
+ * $Id: rarp.c,v 1.25 1998/06/19 13:22:34 davem Exp $
+ *
* This module implements the Reverse Address Resolution Protocol
* (RARP, RFC 903), which is used to convert low level addresses such
- * as ethernet addresses into high level addresses such as IP addresses.
+ * as Ethernet addresses into high level addresses such as IP addresses.
* The most common use of RARP is as a means for a diskless workstation
* to discover its IP address during a network boot.
*
@@ -17,7 +19,7 @@
*** unless you have all the rest to boot the box from it.
**
*
- * Currently, only ethernet address -> IP address is likely to work.
+ * Currently, only Ethernet address -> IP address is likely to work.
* (Is RARP ever used for anything else?)
*
* This code is free software; you can redistribute it and/or
@@ -25,38 +27,49 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * Fixes
+ * Alan Cox : Rarp delete on device down needed as
+ * reported by Walter Wolfgang.
+ * Mike McLagan : Routing by source
+ *
*/
+#include <linux/module.h>
+
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/config.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/errno.h>
+#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/in.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <stdarg.h>
#include <linux/inet.h>
-#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "tcp.h"
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
#include <linux/skbuff.h>
-#include "sock.h"
-#include "arp.h"
-#include "rarp.h"
-#ifdef CONFIG_AX25
-#include "ax25.h"
+#include <net/sock.h>
+#include <net/arp.h>
+#include <net/rarp.h>
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+#include <net/ax25.h>
#endif
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
-#ifdef CONFIG_INET_RARP
+extern int (*rarp_ioctl_hook)(unsigned int,void*);
/*
* This structure defines the RARP mapping cache. As long as we make
@@ -75,6 +88,7 @@ struct rarp_table
struct rarp_table *rarp_tables = NULL;
+static int rarp_rcv(struct sk_buff *, struct device *, struct packet_type *);
static struct packet_type rarp_packet_type =
{
@@ -85,18 +99,8 @@ static struct packet_type rarp_packet_type =
NULL
};
-static initflag = 1;
-
-/*
- * Called once when data first added to rarp cache with ioctl.
- */
+static int initflag = 1;
-static void rarp_init (void)
-{
- /* Register the packet type */
- rarp_packet_type.type=htons(ETH_P_RARP);
- dev_add_pack(&rarp_packet_type);
-}
/*
* Release the memory for this entry.
@@ -105,6 +109,7 @@ static void rarp_init (void)
static inline void rarp_release_entry(struct rarp_table *entry)
{
kfree_s(entry, sizeof(struct rarp_table));
+ MOD_DEC_USE_COUNT;
return;
}
@@ -117,22 +122,87 @@ static void rarp_destroy(unsigned long ip_addr)
struct rarp_table *entry;
struct rarp_table **pentry;
- cli();
+ start_bh_atomic();
pentry = &rarp_tables;
while ((entry = *pentry) != NULL)
{
if (entry->ip == ip_addr)
{
*pentry = entry->next;
- sti();
+ end_bh_atomic();
rarp_release_entry(entry);
return;
}
pentry = &entry->next;
}
- sti();
+ end_bh_atomic();
}
+/*
+ * Flush a device.
+ */
+
+static void rarp_destroy_dev(struct device *dev)
+{
+ struct rarp_table *entry;
+ struct rarp_table **pentry;
+
+ start_bh_atomic();
+ pentry = &rarp_tables;
+ while ((entry = *pentry) != NULL)
+ {
+ if (entry->dev == dev)
+ {
+ *pentry = entry->next;
+ rarp_release_entry(entry);
+ }
+ else
+ pentry = &entry->next;
+ }
+ end_bh_atomic();
+}
+
+static int rarp_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ if(event!=NETDEV_DOWN)
+ return NOTIFY_DONE;
+ rarp_destroy_dev((struct device *)ptr);
+ return NOTIFY_DONE;
+}
+
+/*
+ * Called once when data first added to rarp cache with ioctl.
+ */
+
+static struct notifier_block rarp_dev_notifier={
+ rarp_device_event,
+ NULL,
+ 0
+};
+
+static int rarp_pkt_inited=0;
+
+static void rarp_init_pkt (void)
+{
+ /* Register the packet type */
+ rarp_packet_type.type=htons(ETH_P_RARP);
+ dev_add_pack(&rarp_packet_type);
+ register_netdevice_notifier(&rarp_dev_notifier);
+ rarp_pkt_inited=1;
+}
+
+#ifdef MODULE
+
+static void rarp_end_pkt(void)
+{
+ if(!rarp_pkt_inited)
+ return;
+ dev_remove_pack(&rarp_packet_type);
+ unregister_netdevice_notifier(&rarp_dev_notifier);
+ rarp_pkt_inited=0;
+}
+
+#endif
/*
* Receive an arp request by the device layer. Maybe it should be
@@ -140,25 +210,26 @@ static void rarp_destroy(unsigned long ip_addr)
* "overhead" time isn't that high...
*/
-int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+static int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
/*
* We shouldn't use this type conversion. Check later.
*/
- struct arphdr *rarp = (struct arphdr *)skb->h.raw;
- unsigned char *rarp_ptr = (unsigned char *)(rarp+1);
+ struct arphdr *rarp = (struct arphdr *) skb->data;
+ unsigned char *rarp_ptr = skb_pull(skb,sizeof(struct arphdr));
struct rarp_table *entry;
+ struct in_device *in_dev = dev->ip_ptr;
long sip,tip;
unsigned char *sha,*tha; /* s for "source", t for "target" */
-
+
/*
* If this test doesn't pass, it's not IP, or we should ignore it anyway
*/
if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)
- || dev->flags&IFF_NOARP)
+ || dev->flags&IFF_NOARP || !in_dev || !in_dev->ifa_list)
{
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return 0;
}
@@ -167,7 +238,7 @@ int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
*/
if (rarp->ar_op != htons(ARPOP_RREQUEST))
{
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return 0;
}
@@ -176,18 +247,18 @@ int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
*/
if (
-#ifdef CONFIG_AX25
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
(rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) ||
#endif
(rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25)
|| rarp->ar_pln != 4)
{
- /*
- * This packet is not for us. Remove it.
- */
- kfree_skb(skb, FREE_READ);
- return 0;
-}
+ /*
+ * This packet is not for us. Remove it.
+ */
+ kfree_skb(skb);
+ return 0;
+ }
/*
* Extract variable width fields
@@ -205,7 +276,6 @@ int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* Process entry. Use tha for table lookup according to RFC903.
*/
- cli();
for (entry = rarp_tables; entry != NULL; entry = entry->next)
if (!memcmp(entry->ha, tha, rarp->ar_hln))
break;
@@ -213,15 +283,12 @@ int rarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
if (entry != NULL)
{
sip=entry->ip;
- sti();
- arp_send(ARPOP_RREPLY, ETH_P_RARP, sip, dev, dev->pa_addr, sha,
- dev->dev_addr);
+ arp_send(ARPOP_RREPLY, ETH_P_RARP, sip, dev, in_dev->ifa_list->ifa_address, sha,
+ dev->dev_addr, sha);
}
- else
- sti();
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb);
return 0;
}
@@ -238,9 +305,13 @@ static int rarp_req_set(struct arpreq *req)
int htype, hlen;
unsigned long ip;
struct rtable *rt;
+ struct device * dev;
+ int err;
- memcpy_fromfs(&r, req, sizeof(r));
-
+ err = copy_from_user(&r, req, sizeof(r));
+ if (err)
+ return -EFAULT;
+
/*
* We only understand about IP addresses...
*/
@@ -254,7 +325,7 @@ static int rarp_req_set(struct arpreq *req)
htype = ARPHRD_ETHER;
hlen = ETH_ALEN;
break;
-#ifdef CONFIG_AX25
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
case ARPHRD_AX25:
htype = ARPHRD_AX25;
hlen = 7;
@@ -268,7 +339,7 @@ static int rarp_req_set(struct arpreq *req)
ip = si->sin_addr.s_addr;
if (ip == 0)
{
- printk("RARP: SETRARP: requested PA is 0.0.0.0 !\n");
+ printk(KERN_DEBUG "RARP: SETRARP: requested PA is 0.0.0.0 !\n");
return -EINVAL;
}
@@ -276,15 +347,19 @@ static int rarp_req_set(struct arpreq *req)
* Is it reachable directly ?
*/
- rt = ip_rt_route(ip, NULL, NULL);
- if (rt == NULL)
- return -ENETUNREACH;
+ err = ip_route_output(&rt, ip, 0, 1, 0);
+ if (err)
+ return err;
+ if (rt->rt_flags&(RTCF_LOCAL|RTCF_BROADCAST|RTCF_MULTICAST|RTCF_DNAT)) {
+ ip_rt_put(rt);
+ return -EINVAL;
+ }
+ dev = rt->u.dst.dev;
/*
* Is there an existing entry for this address? Find out...
*/
- cli();
for (entry = rarp_tables; entry != NULL; entry = entry->next)
if (entry->ip == ip)
break;
@@ -299,26 +374,30 @@ static int rarp_req_set(struct arpreq *req)
GFP_ATOMIC);
if (entry == NULL)
{
- sti();
return -ENOMEM;
}
- if(initflag)
+ if (initflag)
{
- rarp_init();
+ rarp_init_pkt();
initflag=0;
}
+ /* Block interrupts until table modification is finished */
+
+ cli();
entry->next = rarp_tables;
rarp_tables = entry;
}
-
+ cli();
entry->ip = ip;
entry->hlen = hlen;
entry->htype = htype;
memcpy(&entry->ha, &r.arp_ha.sa_data, hlen);
- entry->dev = rt->rt_dev;
+ entry->dev = dev;
+ sti();
- sti();
+ /* Don't unlink if we have entries to serve. */
+ MOD_INC_USE_COUNT;
return 0;
}
@@ -334,13 +413,16 @@ static int rarp_req_get(struct arpreq *req)
struct rarp_table *entry;
struct sockaddr_in *si;
unsigned long ip;
-
+ int err;
+
/*
* We only understand about IP addresses...
*/
- memcpy_fromfs(&r, req, sizeof(r));
-
+ err = copy_from_user(&r, req, sizeof(r));
+ if (err)
+ return -EFAULT;
+
if (r.arp_pa.sa_family != AF_INET)
return -EPFNOSUPPORT;
@@ -351,14 +433,12 @@ static int rarp_req_get(struct arpreq *req)
si = (struct sockaddr_in *) &r.arp_pa;
ip = si->sin_addr.s_addr;
- cli();
for (entry = rarp_tables; entry != NULL; entry = entry->next)
if (entry->ip == ip)
break;
if (entry == NULL)
{
- sti();
return -ENXIO;
}
@@ -368,14 +448,12 @@ static int rarp_req_get(struct arpreq *req)
memcpy(r.arp_ha.sa_data, &entry->ha, entry->hlen);
r.arp_ha.sa_family = entry->htype;
- sti();
/*
* Copy the information back
*/
- memcpy_tofs(req, &r, sizeof(r));
- return 0;
+ return copy_to_user(req, &r, sizeof(r)) ? -EFAULT : 0;
}
@@ -394,10 +472,9 @@ int rarp_ioctl(unsigned int cmd, void *arg)
case SIOCDRARP:
if (!suser())
return -EPERM;
- err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
- if(err)
- return err;
- memcpy_fromfs(&r, arg, sizeof(r));
+ err = copy_from_user(&r, arg, sizeof(r));
+ if (err)
+ return -EFAULT;
if (r.arp_pa.sa_family != AF_INET)
return -EPFNOSUPPORT;
si = (struct sockaddr_in *) &r.arp_pa;
@@ -405,16 +482,11 @@ int rarp_ioctl(unsigned int cmd, void *arg)
return 0;
case SIOCGRARP:
- err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq));
- if(err)
- return err;
+
return rarp_req_get((struct arpreq *)arg);
case SIOCSRARP:
if (!suser())
return -EPERM;
- err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
- if(err)
- return err;
return rarp_req_set((struct arpreq *)arg);
default:
return -EINVAL;
@@ -424,7 +496,8 @@ int rarp_ioctl(unsigned int cmd, void *arg)
return 0;
}
-int rarp_get_info(char *buffer, char **start, off_t offset, int length)
+#ifdef CONFIG_PROC_FS
+int rarp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
int len=0;
off_t begin=0;
@@ -433,7 +506,7 @@ int rarp_get_info(char *buffer, char **start, off_t offset, int length)
struct rarp_table *entry;
char ipbuffer[20];
unsigned long netip;
- if(initflag)
+ if (initflag)
{
size = sprintf(buffer,"RARP disabled until entries added to cache.\n");
pos+=size;
@@ -446,7 +519,6 @@ int rarp_get_info(char *buffer, char **start, off_t offset, int length)
pos+=size;
len+=size;
- cli();
for(entry=rarp_tables; entry!=NULL; entry=entry->next)
{
netip=htonl(entry->ip); /* switch to network order */
@@ -478,14 +550,57 @@ int rarp_get_info(char *buffer, char **start, off_t offset, int length)
if(pos>offset+length)
break;
}
- sti();
}
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len=length; /* Ending slop */
+ *start = buffer+(offset-begin); /* Start of wanted data */
+ len -= (offset-begin); /* Start slop */
+ if (len>length)
+ len = length; /* Ending slop */
return len;
}
+struct proc_dir_entry proc_net_rarp = {
+ PROC_NET_RARP, 4, "rarp",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ rarp_get_info
+};
+#endif
+
+__initfunc(void
+rarp_init(void))
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_net_rarp);
+#endif
+ rarp_ioctl_hook = rarp_ioctl;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ rarp_init();
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ struct rarp_table *rt, *rt_next;
+#ifdef CONFIG_PROC_FS
+ proc_net_unregister(PROC_NET_RARP);
+#endif
+ rarp_ioctl_hook = NULL;
+ cli();
+ /* Destroy the RARP-table */
+ rt = rarp_tables;
+ rarp_tables = NULL;
+ sti();
+ /* ... and free it. */
+ for ( ; rt != NULL; rt = rt_next) {
+ rt_next = rt->next;
+ rarp_release_entry(rt);
+ }
+ rarp_end_pkt();
+}
#endif
diff --git a/pfinet/linux-src/net/ipv4/raw.c b/pfinet/linux-src/net/ipv4/raw.c
new file mode 100644
index 00000000..a0aaa82e
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/raw.c
@@ -0,0 +1,573 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * RAW - implementation of IP "raw" sockets.
+ *
+ * Version: $Id: raw.c,v 1.39.2.1 1999/06/20 20:14:50 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * Fixes:
+ * Alan Cox : verify_area() fixed up
+ * Alan Cox : ICMP error handling
+ * Alan Cox : EMSGSIZE if you send too big a packet
+ * Alan Cox : Now uses generic datagrams and shared skbuff
+ * library. No more peek crashes, no more backlogs
+ * Alan Cox : Checks sk->broadcast.
+ * Alan Cox : Uses skb_free_datagram/skb_copy_datagram
+ * Alan Cox : Raw passes ip options too
+ * Alan Cox : Setsocketopt added
+ * Alan Cox : Fixed error return for broadcasts
+ * Alan Cox : Removed wake_up calls
+ * Alan Cox : Use ttl/tos
+ * Alan Cox : Cleaned up old debugging
+ * Alan Cox : Use new kernel side addresses
+ * Arnt Gulbrandsen : Fixed MSG_DONTROUTE in raw sockets.
+ * Alan Cox : BSD style RAW socket demultiplexing.
+ * Alan Cox : Beginnings of mrouted support.
+ * Alan Cox : Added IP_HDRINCL option.
+ * Alan Cox : Skip broadcast check if BSDism set.
+ * David S. Miller : New socket lookup architecture.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/fcntl.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/mroute.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/raw.h>
+#include <net/checksum.h>
+
+#ifdef CONFIG_IP_MROUTE
+struct sock *mroute_socket=NULL;
+#endif
+
+struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
+
+static void raw_v4_hash(struct sock *sk)
+{
+ struct sock **skp = &raw_v4_htable[sk->num & (RAWV4_HTABLE_SIZE - 1)];
+
+ SOCKHASH_LOCK();
+ if ((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+ SOCKHASH_UNLOCK();
+}
+
+static void raw_v4_unhash(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if (sk->pprev) {
+ if (sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ }
+ SOCKHASH_UNLOCK();
+}
+
+/* Grumble... icmp and ip_input want to get at this... */
+struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
+ unsigned long raddr, unsigned long laddr, int dif)
+{
+ struct sock *s = sk;
+
+ SOCKHASH_LOCK();
+ for(s = sk; s; s = s->next) {
+ if((s->num == num) &&
+ !(s->dead && (s->state == TCP_CLOSE)) &&
+ !(s->daddr && s->daddr != raddr) &&
+ !(s->rcv_saddr && s->rcv_saddr != laddr) &&
+ !(s->bound_dev_if && s->bound_dev_if != dif))
+ break; /* gotcha */
+ }
+ SOCKHASH_UNLOCK();
+ return s;
+}
+
+void raw_err (struct sock *sk, struct sk_buff *skb)
+{
+ int type = skb->h.icmph->type;
+ int code = skb->h.icmph->code;
+ u32 info = 0;
+ int err = 0;
+ int harderr = 0;
+
+ /* Report error on raw socket, if:
+ 1. User requested ip_recverr.
+ 2. Socket is connected (otherwise the error indication
+ is useless without ip_recverr and error is hard.
+ */
+ if (!sk->ip_recverr && sk->state != TCP_ESTABLISHED)
+ return;
+
+ switch (type) {
+ default:
+ case ICMP_TIME_EXCEEDED:
+ err = EHOSTUNREACH;
+ break;
+ case ICMP_SOURCE_QUENCH:
+ return;
+ case ICMP_PARAMETERPROB:
+ err = EPROTO;
+ info = ntohl(skb->h.icmph->un.gateway)>>24;
+ harderr = 1;
+ break;
+ case ICMP_DEST_UNREACH:
+ err = EHOSTUNREACH;
+ if (code > NR_ICMP_UNREACH)
+ break;
+ err = icmp_err_convert[code].errno;
+ harderr = icmp_err_convert[code].fatal;
+ if (code == ICMP_FRAG_NEEDED) {
+ harderr = (sk->ip_pmtudisc != IP_PMTUDISC_DONT);
+ err = EMSGSIZE;
+ info = ntohs(skb->h.icmph->un.frag.mtu);
+ }
+ }
+
+ if (sk->ip_recverr)
+ ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1));
+
+ if (sk->ip_recverr || harderr) {
+ sk->err = err;
+ sk->error_report(sk);
+ }
+}
+
+static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
+{
+ /* Charge it to the socket. */
+
+ if (sock_queue_rcv_skb(sk,skb)<0)
+ {
+ ip_statistics.IpInDiscards++;
+ kfree_skb(skb);
+ return -1;
+ }
+
+ ip_statistics.IpInDelivers++;
+ return 0;
+}
+
+/*
+ * This should be the easiest of all, all we do is
+ * copy it into a buffer. All demultiplexing is done
+ * in ip.c
+ */
+
+int raw_rcv(struct sock *sk, struct sk_buff *skb)
+{
+ /* Now we need to copy this into memory. */
+ skb_trim(skb, ntohs(skb->nh.iph->tot_len));
+
+ skb->h.raw = skb->nh.raw;
+
+ raw_rcv_skb(sk, skb);
+ return 0;
+}
+
+struct rawfakehdr
+{
+ struct iovec *iov;
+ u32 saddr;
+};
+
+/*
+ * Send a RAW IP packet.
+ */
+
+/*
+ * Callback support is trivial for SOCK_RAW
+ */
+
+static int raw_getfrag(const void *p, char *to, unsigned int offset, unsigned int fraglen)
+{
+ struct rawfakehdr *rfh = (struct rawfakehdr *) p;
+ return memcpy_fromiovecend(to, rfh->iov, offset, fraglen);
+}
+
+/*
+ * IPPROTO_RAW needs extra work.
+ */
+
+static int raw_getrawfrag(const void *p, char *to, unsigned int offset, unsigned int fraglen)
+{
+ struct rawfakehdr *rfh = (struct rawfakehdr *) p;
+
+ if (memcpy_fromiovecend(to, rfh->iov, offset, fraglen))
+ return -EFAULT;
+
+ if (offset==0) {
+ struct iphdr *iph = (struct iphdr *)to;
+ if (!iph->saddr)
+ iph->saddr = rfh->saddr;
+ iph->check=0;
+ iph->tot_len=htons(fraglen); /* This is right as you can't frag
+ RAW packets */
+ /*
+ * Deliberate breach of modularity to keep
+ * ip_build_xmit clean (well less messy).
+ */
+ if (!iph->id)
+ iph->id = htons(ip_id_count++);
+ iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl);
+ }
+ return 0;
+}
+
+static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct ipcm_cookie ipc;
+ struct rawfakehdr rfh;
+ struct rtable *rt = NULL;
+ int free = 0;
+ u32 daddr;
+ u8 tos;
+ int err;
+
+ /* This check is ONLY to check for arithmetic overflow
+ on integer(!) len. Not more! Real check will be made
+ in ip_build_xmit --ANK
+
+ BTW socket.c -> af_*.c -> ... make multiple
+ invalid conversions size_t -> int. We MUST repair it f.e.
+ by replacing all of them with size_t and revise all
+ the places sort of len += sizeof(struct iphdr)
+ If len was ULONG_MAX-10 it would be cathastrophe --ANK
+ */
+
+ if (len < 0 || len > 0xFFFF)
+ return -EMSGSIZE;
+
+ /*
+ * Check the flags.
+ */
+
+ if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */
+ return -EOPNOTSUPP;
+
+ if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
+ return(-EINVAL);
+
+ /*
+ * Get and verify the address.
+ */
+
+ if (msg->msg_namelen) {
+ struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name;
+ if (msg->msg_namelen < sizeof(*usin))
+ return(-EINVAL);
+ if (usin->sin_family != AF_INET) {
+ static int complained;
+ if (!complained++)
+ printk(KERN_INFO "%s forgot to set AF_INET in raw sendmsg. Fix it!\n", current->comm);
+ if (usin->sin_family)
+ return -EINVAL;
+ }
+ daddr = usin->sin_addr.s_addr;
+ /* ANK: I did not forget to get protocol from port field.
+ * I just do not know, who uses this weirdness.
+ * IP_HDRINCL is much more convenient.
+ */
+ } else {
+ if (sk->state != TCP_ESTABLISHED)
+ return(-EINVAL);
+ daddr = sk->daddr;
+ }
+
+ ipc.addr = sk->saddr;
+ ipc.opt = NULL;
+ ipc.oif = sk->bound_dev_if;
+
+ if (msg->msg_controllen) {
+ int tmp = ip_cmsg_send(msg, &ipc);
+ if (tmp)
+ return tmp;
+ if (ipc.opt)
+ free=1;
+ }
+
+ rfh.saddr = ipc.addr;
+ ipc.addr = daddr;
+
+ if (!ipc.opt)
+ ipc.opt = sk->opt;
+
+ if (ipc.opt) {
+ err = -EINVAL;
+ /* Linux does not mangle headers on raw sockets,
+ * so that IP options + IP_HDRINCL is non-sense.
+ */
+ if (sk->ip_hdrincl)
+ goto done;
+ if (ipc.opt->srr) {
+ if (!daddr)
+ goto done;
+ daddr = ipc.opt->faddr;
+ }
+ }
+ tos = RT_TOS(sk->ip_tos) | sk->localroute;
+ if (msg->msg_flags&MSG_DONTROUTE)
+ tos |= RTO_ONLINK;
+
+ if (MULTICAST(daddr)) {
+ if (!ipc.oif)
+ ipc.oif = sk->ip_mc_index;
+ if (!rfh.saddr)
+ rfh.saddr = sk->ip_mc_addr;
+ }
+
+ err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif);
+
+ if (err)
+ goto done;
+
+ err = -EACCES;
+ if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast)
+ goto done;
+
+ rfh.iov = msg->msg_iov;
+ rfh.saddr = rt->rt_src;
+ if (!ipc.addr)
+ ipc.addr = rt->rt_dst;
+ err=ip_build_xmit(sk, sk->ip_hdrincl ? raw_getrawfrag : raw_getfrag,
+ &rfh, len, &ipc, rt, msg->msg_flags);
+
+done:
+ if (free)
+ kfree(ipc.opt);
+ ip_rt_put(rt);
+
+ return err<0 ? err : len;
+}
+
+static void raw_close(struct sock *sk, long timeout)
+{
+ /* Observation: when raw_close is called, processes have
+ no access to socket anymore. But net still has.
+ Step one, detach it from networking:
+
+ A. Remove from hash tables.
+ */
+ sk->state = TCP_CLOSE;
+ raw_v4_unhash(sk);
+ /*
+ B. Raw sockets may have direct kernel references. Kill them.
+ */
+ ip_ra_control(sk, 0, NULL);
+
+ /* In this point socket cannot receive new packets anymore */
+
+
+ /* But we still have packets pending on receive
+ queue and probably, our own packets waiting in device queues.
+ sock_destroy will drain receive queue, but transmitted
+ packets will delay socket destruction.
+ Set sk->dead=1 in order to prevent wakeups, when these
+ packet will be freed.
+ */
+ sk->dead=1;
+ destroy_sock(sk);
+
+ /* That's all. No races here. */
+}
+
+/* This gets rid of all the nasties in af_inet. -DaveM */
+static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
+ int chk_addr_ret;
+
+ if((sk->state != TCP_CLOSE) || (addr_len < sizeof(struct sockaddr_in)))
+ return -EINVAL;
+ chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
+ if(addr->sin_addr.s_addr != 0 && chk_addr_ret != RTN_LOCAL &&
+ chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) {
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /* Superuser may bind to any address to allow transparent proxying. */
+ if(chk_addr_ret != RTN_UNICAST || !capable(CAP_NET_ADMIN))
+#endif
+ return -EADDRNOTAVAIL;
+ }
+ sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
+ if(chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
+ sk->saddr = 0; /* Use device */
+ dst_release(xchg(&sk->dst_cache, NULL));
+ return 0;
+}
+
+/*
+ * This should be easy, if there is something there
+ * we return it, otherwise we block.
+ */
+
+int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len,
+ int noblock, int flags,int *addr_len)
+{
+ int copied=0;
+ struct sk_buff *skb;
+ int err;
+ struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name;
+
+ if (flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ if (addr_len)
+ *addr_len=sizeof(*sin);
+
+ if (flags & MSG_ERRQUEUE)
+ return ip_recv_error(sk, msg, len);
+
+ skb=skb_recv_datagram(sk,flags,noblock,&err);
+ if(skb==NULL)
+ return err;
+
+ copied = skb->len;
+ if (len < copied)
+ {
+ msg->msg_flags |= MSG_TRUNC;
+ copied = len;
+ }
+
+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ if (err)
+ goto done;
+
+ sk->stamp=skb->stamp;
+
+ /* Copy the address. */
+ if (sin) {
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = skb->nh.iph->saddr;
+ }
+ if (sk->ip_cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+done:
+ skb_free_datagram(sk, skb);
+ return (err ? : copied);
+}
+
+static int raw_init(struct sock *sk)
+{
+ struct raw_opt *tp = &(sk->tp_pinfo.tp_raw4);
+ if (sk->num == IPPROTO_ICMP)
+ memset(&tp->filter, 0, sizeof(tp->filter));
+ return 0;
+}
+
+static int raw_seticmpfilter(struct sock *sk, char *optval, int optlen)
+{
+ if (optlen > sizeof(struct icmp_filter))
+ optlen = sizeof(struct icmp_filter);
+ if (copy_from_user(&sk->tp_pinfo.tp_raw4.filter, optval, optlen))
+ return -EFAULT;
+ return 0;
+}
+
+static int raw_geticmpfilter(struct sock *sk, char *optval, int *optlen)
+{
+ int len;
+
+ if (get_user(len,optlen))
+ return -EFAULT;
+ if (len > sizeof(struct icmp_filter))
+ len = sizeof(struct icmp_filter);
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &sk->tp_pinfo.tp_raw4.filter, len))
+ return -EFAULT;
+ return 0;
+}
+
+static int raw_setsockopt(struct sock *sk, int level, int optname,
+ char *optval, int optlen)
+{
+ if (level != SOL_RAW)
+ return ip_setsockopt(sk, level, optname, optval, optlen);
+
+ switch (optname) {
+ case ICMP_FILTER:
+ if (sk->num != IPPROTO_ICMP)
+ return -EOPNOTSUPP;
+ return raw_seticmpfilter(sk, optval, optlen);
+ };
+
+ return -ENOPROTOOPT;
+}
+
+static int raw_getsockopt(struct sock *sk, int level, int optname,
+ char *optval, int *optlen)
+{
+ if (level != SOL_RAW)
+ return ip_getsockopt(sk, level, optname, optval, optlen);
+
+ switch (optname) {
+ case ICMP_FILTER:
+ if (sk->num != IPPROTO_ICMP)
+ return -EOPNOTSUPP;
+ return raw_geticmpfilter(sk, optval, optlen);
+ };
+
+ return -ENOPROTOOPT;
+}
+
+struct proto raw_prot = {
+ (struct sock *)&raw_prot, /* sklist_next */
+ (struct sock *)&raw_prot, /* sklist_prev */
+ raw_close, /* close */
+ udp_connect, /* connect */
+ NULL, /* accept */
+ NULL, /* retransmit */
+ NULL, /* write_wakeup */
+ NULL, /* read_wakeup */
+ datagram_poll, /* poll */
+#ifdef CONFIG_IP_MROUTE
+ ipmr_ioctl, /* ioctl */
+#else
+ NULL, /* ioctl */
+#endif
+ raw_init, /* init */
+ NULL, /* destroy */
+ NULL, /* shutdown */
+ raw_setsockopt, /* setsockopt */
+ raw_getsockopt, /* getsockopt */
+ raw_sendmsg, /* sendmsg */
+ raw_recvmsg, /* recvmsg */
+ raw_bind, /* bind */
+ raw_rcv_skb, /* backlog_rcv */
+ raw_v4_hash, /* hash */
+ raw_v4_unhash, /* unhash */
+ NULL, /* get_port */
+ 128, /* max_header */
+ 0, /* retransmits */
+ "RAW", /* name */
+ 0, /* inuse */
+ 0 /* highestinuse */
+};
diff --git a/pfinet/linux-src/net/ipv4/route.c b/pfinet/linux-src/net/ipv4/route.c
new file mode 100644
index 00000000..f4e61b95
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/route.c
@@ -0,0 +1,2050 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * ROUTE - implementation of the IP router.
+ *
+ * Version: $Id: route.c,v 1.67.2.4 1999/11/16 02:28:43 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Linus Torvalds, <Linus.Torvalds@helsinki.fi>
+ * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Fixes:
+ * Alan Cox : Verify area fixes.
+ * Alan Cox : cli() protects routing changes
+ * Rui Oliveira : ICMP routing table updates
+ * (rco@di.uminho.pt) Routing table insertion and update
+ * Linus Torvalds : Rewrote bits to be sensible
+ * Alan Cox : Added BSD route gw semantics
+ * Alan Cox : Super /proc >4K
+ * Alan Cox : MTU in route table
+ * Alan Cox : MSS actually. Also added the window
+ * clamper.
+ * Sam Lantinga : Fixed route matching in rt_del()
+ * Alan Cox : Routing cache support.
+ * Alan Cox : Removed compatibility cruft.
+ * Alan Cox : RTF_REJECT support.
+ * Alan Cox : TCP irtt support.
+ * Jonathan Naylor : Added Metric support.
+ * Miquel van Smoorenburg : BSD API fixes.
+ * Miquel van Smoorenburg : Metrics.
+ * Alan Cox : Use __u32 properly
+ * Alan Cox : Aligned routing errors more closely with BSD
+ * our system is still very different.
+ * Alan Cox : Faster /proc handling
+ * Alexey Kuznetsov : Massive rework to support tree based routing,
+ * routing caches and better behaviour.
+ *
+ * Olaf Erb : irtt wasn't being copied right.
+ * Bjorn Ekwall : Kerneld route support.
+ * Alan Cox : Multicast fixed (I hope)
+ * Pavel Krauz : Limited broadcast fixed
+ * Mike McLagan : Routing by source
+ * Alexey Kuznetsov : End of old history. Splitted to fib.c and
+ * route.c and rewritten from scratch.
+ * Andi Kleen : Load-limit warning messages.
+ * Vitaly E. Lavrov : Transparent proxy revived after year coma.
+ * Vitaly E. Lavrov : Race condition in ip_route_input_slow.
+ * Tobias Ringstrom : Uninitialized res.type in ip_route_output_slow.
+ * Vladimir V. Ivanov : IP rule info (flowid) is really useful.
+ * Marc Boucher : routing by fwmark
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/pkt_sched.h>
+#include <linux/mroute.h>
+#include <net/protocol.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/sock.h>
+#include <net/ip_fib.h>
+#include <net/arp.h>
+#include <net/tcp.h>
+#include <net/icmp.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+
+#define IP_MAX_MTU 0xFFF0
+
+#define RT_GC_TIMEOUT (300*HZ)
+
+int ip_rt_min_delay = 2*HZ;
+int ip_rt_max_delay = 10*HZ;
+int ip_rt_gc_thresh = RT_HASH_DIVISOR;
+int ip_rt_max_size = RT_HASH_DIVISOR*16;
+int ip_rt_gc_timeout = RT_GC_TIMEOUT;
+int ip_rt_gc_interval = 60*HZ;
+int ip_rt_gc_min_interval = 5*HZ;
+int ip_rt_redirect_number = 9;
+int ip_rt_redirect_load = HZ/50;
+int ip_rt_redirect_silence = ((HZ/50) << (9+1));
+int ip_rt_error_cost = HZ;
+int ip_rt_error_burst = 5*HZ;
+int ip_rt_gc_elasticity = 8;
+int ip_rt_mtu_expires = 10*60*HZ;
+
+static unsigned long rt_deadline = 0;
+
+#define RTprint(a...) printk(KERN_DEBUG a)
+
+static void rt_run_flush(unsigned long dummy);
+
+static struct timer_list rt_flush_timer =
+ { NULL, NULL, 0, 0L, rt_run_flush };
+static struct timer_list rt_periodic_timer =
+ { NULL, NULL, 0, 0L, NULL };
+
+/*
+ * Interface to generic destination cache.
+ */
+
+static struct dst_entry * ipv4_dst_check(struct dst_entry * dst, u32);
+static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst,
+ struct sk_buff *);
+static struct dst_entry * ipv4_negative_advice(struct dst_entry *);
+static void ipv4_link_failure(struct sk_buff *skb);
+static int rt_garbage_collect(void);
+
+
+struct dst_ops ipv4_dst_ops =
+{
+ AF_INET,
+ __constant_htons(ETH_P_IP),
+ RT_HASH_DIVISOR,
+
+ rt_garbage_collect,
+ ipv4_dst_check,
+ ipv4_dst_reroute,
+ NULL,
+ ipv4_negative_advice,
+ ipv4_link_failure,
+};
+
+__u8 ip_tos2prio[16] = {
+ TC_PRIO_BESTEFFORT,
+ TC_PRIO_FILLER,
+ TC_PRIO_BESTEFFORT,
+ TC_PRIO_FILLER,
+ TC_PRIO_BULK,
+ TC_PRIO_FILLER,
+ TC_PRIO_BULK,
+ TC_PRIO_FILLER,
+ TC_PRIO_INTERACTIVE,
+ TC_PRIO_FILLER,
+ TC_PRIO_INTERACTIVE,
+ TC_PRIO_FILLER,
+ TC_PRIO_INTERACTIVE_BULK,
+ TC_PRIO_FILLER,
+ TC_PRIO_INTERACTIVE_BULK,
+ TC_PRIO_FILLER
+};
+
+
+/*
+ * Route cache.
+ */
+
+struct rtable *rt_hash_table[RT_HASH_DIVISOR];
+
+static int rt_intern_hash(unsigned hash, struct rtable * rth, struct rtable ** res);
+
+static __inline__ unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos)
+{
+ unsigned hash = ((daddr&0xF0F0F0F0)>>4)|((daddr&0x0F0F0F0F)<<4);
+ hash = hash^saddr^tos;
+ hash = hash^(hash>>16);
+ return (hash^(hash>>8)) & 0xFF;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int rt_cache_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int len=0;
+ off_t pos=0;
+ char temp[129];
+ struct rtable *r;
+ int i;
+
+ pos = 128;
+
+ if (offset<128) {
+ sprintf(buffer,"%-127s\n", "Iface\tDestination\tGateway \tFlags\t\tRefCnt\tUse\tMetric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\tHHUptod\tSpecDst");
+ len = 128;
+ }
+
+
+ start_bh_atomic();
+
+ for (i = 0; i<RT_HASH_DIVISOR; i++) {
+ for (r = rt_hash_table[i]; r; r = r->u.rt_next) {
+ /*
+ * Spin through entries until we are ready
+ */
+ pos += 128;
+
+ if (pos <= offset) {
+ len = 0;
+ continue;
+ }
+ sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X",
+ r->u.dst.dev ? r->u.dst.dev->name : "*",
+ (unsigned long)r->rt_dst,
+ (unsigned long)r->rt_gateway,
+ r->rt_flags,
+ atomic_read(&r->u.dst.use),
+ atomic_read(&r->u.dst.refcnt),
+ 0,
+ (unsigned long)r->rt_src, (int)r->u.dst.pmtu,
+ r->u.dst.window,
+ (int)r->u.dst.rtt, r->key.tos,
+ r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
+ r->u.dst.hh ? (r->u.dst.hh->hh_output == dev_queue_xmit) : 0,
+ r->rt_spec_dst);
+ sprintf(buffer+len,"%-127s\n",temp);
+ len += 128;
+ if (pos >= offset+length)
+ goto done;
+ }
+ }
+
+done:
+ end_bh_atomic();
+
+ *start = buffer+len-(pos-offset);
+ len = pos-offset;
+ if (len>length)
+ len = length;
+ return len;
+}
+#endif
+
+static __inline__ void rt_free(struct rtable *rt)
+{
+ dst_free(&rt->u.dst);
+}
+
+static __inline__ void rt_drop(struct rtable *rt)
+{
+ ip_rt_put(rt);
+ dst_free(&rt->u.dst);
+}
+
+static __inline__ int rt_fast_clean(struct rtable *rth)
+{
+ /* Kill broadcast/multicast entries very aggresively, if they
+ collide in hash table with more useful entries */
+ return ((rth->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
+ && rth->key.iif && rth->u.rt_next);
+}
+
+static __inline__ int rt_valuable(struct rtable *rth)
+{
+ return ((rth->rt_flags&(RTCF_REDIRECTED|RTCF_NOTIFY))
+ || rth->u.dst.expires);
+}
+
+static __inline__ int rt_may_expire(struct rtable *rth, int tmo1, int tmo2)
+{
+ int age;
+
+ if (atomic_read(&rth->u.dst.use))
+ return 0;
+
+ if (rth->u.dst.expires && (long)(rth->u.dst.expires - jiffies) <= 0)
+ return 1;
+
+ age = jiffies - rth->u.dst.lastuse;
+ if (age <= tmo1 && !rt_fast_clean(rth))
+ return 0;
+ if (age <= tmo2 && rt_valuable(rth))
+ return 0;
+ return 1;
+}
+
+static void rt_check_expire(unsigned long dummy)
+{
+ int i;
+ static int rover;
+ struct rtable *rth, **rthp;
+ unsigned long now = jiffies;
+
+ for (i=0; i<RT_HASH_DIVISOR/5; i++) {
+ unsigned tmo = ip_rt_gc_timeout;
+
+ rover = (rover + 1) & (RT_HASH_DIVISOR-1);
+ rthp = &rt_hash_table[rover];
+
+ while ((rth = *rthp) != NULL) {
+ if (rth->u.dst.expires) {
+ /* Entrie is expired even if it is in use */
+ if ((long)(now - rth->u.dst.expires) <= 0) {
+ tmo >>= 1;
+ rthp = &rth->u.rt_next;
+ continue;
+ }
+ } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) {
+ tmo >>= 1;
+ rthp = &rth->u.rt_next;
+ continue;
+ }
+
+ /*
+ * Cleanup aged off entries.
+ */
+ *rthp = rth->u.rt_next;
+ rt_free(rth);
+ }
+
+ /* Fallback loop breaker. */
+ if ((jiffies - now) > 0)
+ break;
+ }
+ rt_periodic_timer.expires = now + ip_rt_gc_interval;
+ add_timer(&rt_periodic_timer);
+}
+
+static void rt_run_flush(unsigned long dummy)
+{
+ int i;
+ struct rtable * rth, * next;
+
+ rt_deadline = 0;
+
+ start_bh_atomic();
+ for (i=0; i<RT_HASH_DIVISOR; i++) {
+ if ((rth = xchg(&rt_hash_table[i], NULL)) == NULL)
+ continue;
+ end_bh_atomic();
+
+ for (; rth; rth=next) {
+ next = rth->u.rt_next;
+ rth->u.rt_next = NULL;
+ rt_free(rth);
+ }
+
+ start_bh_atomic();
+ }
+ end_bh_atomic();
+}
+
+void rt_cache_flush(int delay)
+{
+ unsigned long now = jiffies;
+ int user_mode = !in_interrupt();
+
+ if (delay < 0)
+ delay = ip_rt_min_delay;
+
+ start_bh_atomic();
+
+ if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
+ long tmo = (long)(rt_deadline - now);
+
+ /* If flush timer is already running
+ and flush request is not immediate (delay > 0):
+
+ if deadline is not achieved, prolongate timer to "delay",
+ otherwise fire it at deadline time.
+ */
+
+ if (user_mode && tmo < ip_rt_max_delay-ip_rt_min_delay)
+ tmo = 0;
+
+ if (delay > tmo)
+ delay = tmo;
+ }
+
+ if (delay <= 0) {
+ end_bh_atomic();
+ rt_run_flush(0);
+ return;
+ }
+
+ if (rt_deadline == 0)
+ rt_deadline = now + ip_rt_max_delay;
+
+ rt_flush_timer.expires = now + delay;
+ add_timer(&rt_flush_timer);
+ end_bh_atomic();
+}
+
+/*
+ Short description of GC goals.
+
+ We want to build algorithm, which will keep routing cache
+ at some equilibrium point, when number of aged off entries
+ is kept approximately equal to newly generated ones.
+
+ Current expiration strength is variable "expire".
+ We try to adjust it dynamically, so that if networking
+ is idle expires is large enough to keep enough of warm entries,
+ and when load increases it reduces to limit cache size.
+ */
+
+static int rt_garbage_collect(void)
+{
+ static unsigned expire = RT_GC_TIMEOUT;
+ static unsigned long last_gc;
+ static int rover;
+ static int equilibrium;
+ struct rtable *rth, **rthp;
+ unsigned long now = jiffies;
+ int goal;
+
+ /*
+ * Garbage collection is pretty expensive,
+ * do not make it too frequently.
+ */
+ if (now - last_gc < ip_rt_gc_min_interval &&
+ atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
+ return 0;
+
+ /* Calculate number of entries, which we want to expire now. */
+ goal = atomic_read(&ipv4_dst_ops.entries) - RT_HASH_DIVISOR*ip_rt_gc_elasticity;
+ if (goal <= 0) {
+ if (equilibrium < ipv4_dst_ops.gc_thresh)
+ equilibrium = ipv4_dst_ops.gc_thresh;
+ goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
+ if (goal > 0) {
+ equilibrium += min(goal/2, RT_HASH_DIVISOR);
+ goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
+ }
+ } else {
+ /* We are in dangerous area. Try to reduce cache really
+ * aggressively.
+ */
+ goal = max(goal/2, RT_HASH_DIVISOR);
+ equilibrium = atomic_read(&ipv4_dst_ops.entries) - goal;
+ }
+
+ if (now - last_gc >= ip_rt_gc_min_interval)
+ last_gc = now;
+
+ if (goal <= 0) {
+ equilibrium += goal;
+ goto work_done;
+ }
+
+ do {
+ int i, k;
+
+ start_bh_atomic();
+ for (i=0, k=rover; i<RT_HASH_DIVISOR; i++) {
+ unsigned tmo = expire;
+
+ k = (k + 1) & (RT_HASH_DIVISOR-1);
+ rthp = &rt_hash_table[k];
+ while ((rth = *rthp) != NULL) {
+ if (!rt_may_expire(rth, tmo, expire)) {
+ tmo >>= 1;
+ rthp = &rth->u.rt_next;
+ continue;
+ }
+ *rthp = rth->u.rt_next;
+ rth->u.rt_next = NULL;
+ rt_free(rth);
+ goal--;
+ }
+ if (goal <= 0)
+ break;
+ }
+ rover = k;
+ end_bh_atomic();
+
+ if (goal <= 0)
+ goto work_done;
+
+ /* Goal is not achieved. We stop process if:
+
+ - if expire reduced to zero. Otherwise, expire is halfed.
+ - if table is not full.
+ - if we are called from interrupt.
+ - jiffies check is just fallback/debug loop breaker.
+ We will not spin here for long time in any case.
+ */
+
+ if (expire == 0)
+ break;
+
+ expire >>= 1;
+#if RT_CACHE_DEBUG >= 2
+ printk(KERN_DEBUG "expire>> %u %d %d %d\n", expire, atomic_read(&ipv4_dst_ops.entries), goal, i);
+#endif
+
+ if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
+ return 0;
+ } while (!in_interrupt() && jiffies - now < 1);
+
+ if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
+ return 0;
+ if (net_ratelimit())
+ printk("dst cache overflow\n");
+ return 1;
+
+work_done:
+ expire += ip_rt_gc_min_interval;
+ if (expire > ip_rt_gc_timeout ||
+ atomic_read(&ipv4_dst_ops.entries) < ipv4_dst_ops.gc_thresh)
+ expire = ip_rt_gc_timeout;
+#if RT_CACHE_DEBUG >= 2
+ printk(KERN_DEBUG "expire++ %u %d %d %d\n", expire, atomic_read(&ipv4_dst_ops.entries), goal, rover);
+#endif
+ return 0;
+}
+
+static int rt_intern_hash(unsigned hash, struct rtable * rt, struct rtable ** rp)
+{
+ struct rtable *rth, **rthp;
+ unsigned long now = jiffies;
+ int attempts = !in_interrupt();
+
+restart:
+ start_bh_atomic();
+
+ rthp = &rt_hash_table[hash];
+
+ while ((rth = *rthp) != NULL) {
+ if (memcmp(&rth->key, &rt->key, sizeof(rt->key)) == 0) {
+ /* Put it first */
+ *rthp = rth->u.rt_next;
+ rth->u.rt_next = rt_hash_table[hash];
+ rt_hash_table[hash] = rth;
+
+ atomic_inc(&rth->u.dst.refcnt);
+ atomic_inc(&rth->u.dst.use);
+ rth->u.dst.lastuse = now;
+ end_bh_atomic();
+
+ rt_drop(rt);
+ *rp = rth;
+ return 0;
+ }
+
+ rthp = &rth->u.rt_next;
+ }
+
+ /* Try to bind route to arp only if it is output
+ route or unicast forwarding path.
+ */
+ if (rt->rt_type == RTN_UNICAST || rt->key.iif == 0) {
+ if (!arp_bind_neighbour(&rt->u.dst)) {
+ end_bh_atomic();
+
+ /* Neighbour tables are full and nothing
+ can be released. Try to shrink route cache,
+ it is most likely it holds some neighbour records.
+ */
+ if (attempts-- > 0) {
+ int saved_elasticity = ip_rt_gc_elasticity;
+ int saved_int = ip_rt_gc_min_interval;
+ ip_rt_gc_elasticity = 1;
+ ip_rt_gc_min_interval = 0;
+ rt_garbage_collect();
+ ip_rt_gc_min_interval = saved_int;
+ ip_rt_gc_elasticity = saved_elasticity;
+ goto restart;
+ }
+
+ rt_drop(rt);
+ if (net_ratelimit())
+ printk("neighbour table overflow\n");
+ return -ENOBUFS;
+ }
+ }
+
+ rt->u.rt_next = rt_hash_table[hash];
+#if RT_CACHE_DEBUG >= 2
+ if (rt->u.rt_next) {
+ struct rtable * trt;
+ printk("rt_cache @%02x: %08x", hash, rt->rt_dst);
+ for (trt=rt->u.rt_next; trt; trt=trt->u.rt_next)
+ printk(" . %08x", trt->rt_dst);
+ printk("\n");
+ }
+#endif
+ rt_hash_table[hash] = rt;
+ end_bh_atomic();
+ *rp = rt;
+ return 0;
+}
+
+static void rt_del(unsigned hash, struct rtable *rt)
+{
+ struct rtable **rthp;
+
+ start_bh_atomic();
+ ip_rt_put(rt);
+ for (rthp = &rt_hash_table[hash]; *rthp; rthp = &(*rthp)->u.rt_next) {
+ if (*rthp == rt) {
+ *rthp = rt->u.rt_next;
+ rt_free(rt);
+ break;
+ }
+ }
+ end_bh_atomic();
+}
+
+void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
+ u32 saddr, u8 tos, struct device *dev)
+{
+ int i, k;
+ struct in_device *in_dev = dev->ip_ptr;
+ struct rtable *rth, **rthp;
+ u32 skeys[2] = { saddr, 0 };
+ int ikeys[2] = { dev->ifindex, 0 };
+
+ tos &= IPTOS_TOS_MASK;
+
+ if (!in_dev)
+ return;
+
+ if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev)
+ || MULTICAST(new_gw) || BADCLASS(new_gw) || ZERONET(new_gw))
+ goto reject_redirect;
+
+ if (!IN_DEV_SHARED_MEDIA(in_dev)) {
+ if (!inet_addr_onlink(in_dev, new_gw, old_gw))
+ goto reject_redirect;
+ if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev))
+ goto reject_redirect;
+ } else {
+ if (inet_addr_type(new_gw) != RTN_UNICAST)
+ goto reject_redirect;
+ }
+
+ for (i=0; i<2; i++) {
+ for (k=0; k<2; k++) {
+ unsigned hash = rt_hash_code(daddr, skeys[i]^(ikeys[k]<<5), tos);
+
+ rthp=&rt_hash_table[hash];
+
+ while ( (rth = *rthp) != NULL) {
+ struct rtable *rt;
+
+ if (rth->key.dst != daddr ||
+ rth->key.src != skeys[i] ||
+ rth->key.tos != tos ||
+ rth->key.oif != ikeys[k] ||
+ rth->key.iif != 0) {
+ rthp = &rth->u.rt_next;
+ continue;
+ }
+
+ if (rth->rt_dst != daddr ||
+ rth->rt_src != saddr ||
+ rth->u.dst.error ||
+ rth->rt_gateway != old_gw ||
+ rth->u.dst.dev != dev)
+ break;
+
+ dst_clone(&rth->u.dst);
+
+ rt = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
+ if (rt == NULL) {
+ ip_rt_put(rth);
+ return;
+ }
+
+ /*
+ * Copy all the information.
+ */
+ *rt = *rth;
+ atomic_set(&rt->u.dst.refcnt, 1);
+ atomic_set(&rt->u.dst.use, 1);
+ rt->u.dst.lastuse = jiffies;
+ rt->u.dst.neighbour = NULL;
+ rt->u.dst.hh = NULL;
+ rt->u.dst.obsolete = 0;
+
+ rt->rt_flags |= RTCF_REDIRECTED;
+
+ /* Gateway is different ... */
+ rt->rt_gateway = new_gw;
+
+ /* Redirect received -> path was valid */
+ dst_confirm(&rth->u.dst);
+
+ if (!arp_bind_neighbour(&rt->u.dst) ||
+ !(rt->u.dst.neighbour->nud_state&NUD_VALID)) {
+ if (rt->u.dst.neighbour)
+ neigh_event_send(rt->u.dst.neighbour, NULL);
+ ip_rt_put(rth);
+ rt_drop(rt);
+ break;
+ }
+
+ rt_del(hash, rth);
+
+ if (!rt_intern_hash(hash, rt, &rt))
+ ip_rt_put(rt);
+ break;
+ }
+ }
+ }
+ return;
+
+reject_redirect:
+#ifdef CONFIG_IP_ROUTE_VERBOSE
+ if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
+ printk(KERN_INFO "Redirect from %X/%s to %X ignored."
+ "Path = %X -> %X, tos %02x\n",
+ ntohl(old_gw), dev->name, ntohl(new_gw),
+ ntohl(saddr), ntohl(daddr), tos);
+#else
+ ; /* Do nothing. */
+#endif
+}
+
+static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
+{
+ struct rtable *rt = (struct rtable*)dst;
+
+ if (rt != NULL) {
+ if (dst->obsolete) {
+ ip_rt_put(rt);
+ return NULL;
+ }
+ if ((rt->rt_flags&RTCF_REDIRECTED) || rt->u.dst.expires) {
+ unsigned hash = rt_hash_code(rt->key.dst, rt->key.src^(rt->key.oif<<5), rt->key.tos);
+#if RT_CACHE_DEBUG >= 1
+ printk(KERN_DEBUG "ip_rt_advice: redirect to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos);
+#endif
+ rt_del(hash, rt);
+ return NULL;
+ }
+ }
+ return dst;
+}
+
+/*
+ * Algorithm:
+ * 1. The first ip_rt_redirect_number redirects are sent
+ * with exponential backoff, then we stop sending them at all,
+ * assuming that the host ignores our redirects.
+ * 2. If we did not see packets requiring redirects
+ * during ip_rt_redirect_silence, we assume that the host
+ * forgot redirected route and start to send redirects again.
+ *
+ * This algorithm is much cheaper and more intelligent than dumb load limiting
+ * in icmp.c.
+ *
+ * NOTE. Do not forget to inhibit load limiting for redirects (redundant)
+ * and "frag. need" (breaks PMTU discovery) in icmp.c.
+ */
+
+void ip_rt_send_redirect(struct sk_buff *skb)
+{
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct in_device *in_dev = (struct in_device*)rt->u.dst.dev->ip_ptr;
+
+ if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev))
+ return;
+
+ /* No redirected packets during ip_rt_redirect_silence;
+ * reset the algorithm.
+ */
+ if (jiffies - rt->u.dst.rate_last > ip_rt_redirect_silence)
+ rt->u.dst.rate_tokens = 0;
+
+ /* Too many ignored redirects; do not send anything
+ * set u.dst.rate_last to the last seen redirected packet.
+ */
+ if (rt->u.dst.rate_tokens >= ip_rt_redirect_number) {
+ rt->u.dst.rate_last = jiffies;
+ return;
+ }
+
+ /* Check for load limit; set rate_last to the latest sent
+ * redirect.
+ */
+ if (jiffies - rt->u.dst.rate_last > (ip_rt_redirect_load<<rt->u.dst.rate_tokens)) {
+ icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
+ rt->u.dst.rate_last = jiffies;
+ ++rt->u.dst.rate_tokens;
+#ifdef CONFIG_IP_ROUTE_VERBOSE
+ if (IN_DEV_LOG_MARTIANS(in_dev) &&
+ rt->u.dst.rate_tokens == ip_rt_redirect_number && net_ratelimit())
+ printk(KERN_WARNING "host %08x/if%d ignores redirects for %08x to %08x.\n",
+ rt->rt_src, rt->rt_iif, rt->rt_dst, rt->rt_gateway);
+#endif
+ }
+}
+
+static int ip_error(struct sk_buff *skb)
+{
+ struct rtable *rt = (struct rtable*)skb->dst;
+ unsigned long now;
+ int code;
+
+ switch (rt->u.dst.error) {
+ case EINVAL:
+ default:
+ kfree_skb(skb);
+ return 0;
+ case EHOSTUNREACH:
+ code = ICMP_HOST_UNREACH;
+ break;
+ case ENETUNREACH:
+ code = ICMP_NET_UNREACH;
+ break;
+ case EACCES:
+ code = ICMP_PKT_FILTERED;
+ break;
+ }
+
+ now = jiffies;
+ if ((rt->u.dst.rate_tokens += (now - rt->u.dst.rate_last)) > ip_rt_error_burst)
+ rt->u.dst.rate_tokens = ip_rt_error_burst;
+ rt->u.dst.rate_last = now;
+ if (rt->u.dst.rate_tokens >= ip_rt_error_cost) {
+ rt->u.dst.rate_tokens -= ip_rt_error_cost;
+ icmp_send(skb, ICMP_DEST_UNREACH, code, 0);
+ }
+
+ kfree_skb(skb);
+ return 0;
+}
+
+/*
+ * The last two values are not from the RFC but
+ * are needed for AMPRnet AX.25 paths.
+ */
+
+static unsigned short mtu_plateau[] =
+{32000, 17914, 8166, 4352, 2002, 1492, 576, 296, 216, 128 };
+
+static __inline__ unsigned short guess_mtu(unsigned short old_mtu)
+{
+ int i;
+
+ for (i = 0; i < sizeof(mtu_plateau)/sizeof(mtu_plateau[0]); i++)
+ if (old_mtu > mtu_plateau[i])
+ return mtu_plateau[i];
+ return 68;
+}
+
+unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
+{
+ int i;
+ unsigned short old_mtu = ntohs(iph->tot_len);
+ struct rtable *rth;
+ u32 skeys[2] = { iph->saddr, 0, };
+ u32 daddr = iph->daddr;
+ u8 tos = iph->tos & IPTOS_TOS_MASK;
+ unsigned short est_mtu = 0;
+
+ if (ipv4_config.no_pmtu_disc)
+ return 0;
+
+ for (i=0; i<2; i++) {
+ unsigned hash = rt_hash_code(daddr, skeys[i], tos);
+
+ for (rth = rt_hash_table[hash]; rth; rth = rth->u.rt_next) {
+ if (rth->key.dst == daddr &&
+ rth->key.src == skeys[i] &&
+ rth->rt_dst == daddr &&
+ rth->rt_src == iph->saddr &&
+ rth->key.tos == tos &&
+ rth->key.iif == 0 &&
+ !(rth->u.dst.mxlock&(1<<RTAX_MTU))) {
+ unsigned short mtu = new_mtu;
+
+ if (new_mtu < 68 || new_mtu >= old_mtu) {
+
+ /* BSD 4.2 compatibility hack :-( */
+ if (mtu == 0 && old_mtu >= rth->u.dst.pmtu &&
+ old_mtu >= 68 + (iph->ihl<<2))
+ old_mtu -= iph->ihl<<2;
+
+ mtu = guess_mtu(old_mtu);
+ }
+ if (mtu <= rth->u.dst.pmtu) {
+ if (mtu < rth->u.dst.pmtu) {
+ dst_confirm(&rth->u.dst);
+ rth->u.dst.pmtu = mtu;
+ dst_set_expires(&rth->u.dst, ip_rt_mtu_expires);
+ }
+ est_mtu = mtu;
+ }
+ }
+ }
+ }
+ return est_mtu ? : new_mtu;
+}
+
+void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu)
+{
+ if (dst->pmtu > mtu && mtu >= 68 &&
+ !(dst->mxlock&(1<<RTAX_MTU))) {
+ dst->pmtu = mtu;
+ dst_set_expires(dst, ip_rt_mtu_expires);
+ }
+}
+
+static struct dst_entry * ipv4_dst_check(struct dst_entry * dst, u32 cookie)
+{
+ dst_release(dst);
+ return NULL;
+}
+
+static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst,
+ struct sk_buff *skb)
+{
+ return NULL;
+}
+
+static void ipv4_link_failure(struct sk_buff *skb)
+{
+ struct rtable *rt;
+
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
+
+ rt = (struct rtable *) skb->dst;
+ if (rt)
+ dst_set_expires(&rt->u.dst, 0);
+}
+
+static int ip_rt_bug(struct sk_buff *skb)
+{
+ printk(KERN_DEBUG "ip_rt_bug: %08x -> %08x, %s\n", skb->nh.iph->saddr,
+ skb->nh.iph->daddr, skb->dev ? skb->dev->name : "?");
+ kfree_skb(skb);
+ return 0;
+}
+
+/*
+ We do not cache source address of outgoing interface,
+ because it is used only by IP RR, TS and SRR options,
+ so that it out of fast path.
+
+ BTW remember: "addr" is allowed to be not aligned
+ in IP options!
+ */
+
+void ip_rt_get_source(u8 *addr, struct rtable *rt)
+{
+ u32 src;
+ struct fib_result res;
+
+ if (rt->key.iif == 0)
+ src = rt->rt_src;
+ else if (fib_lookup(&rt->key, &res) == 0 && res.type != RTN_NAT)
+ src = FIB_RES_PREFSRC(res);
+ else
+ src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+ memcpy(addr, &src, 4);
+}
+
+#ifdef CONFIG_NET_CLS_ROUTE
+static void set_class_tag(struct rtable *rt, u32 tag)
+{
+ if (!(rt->u.dst.tclassid&0xFFFF))
+ rt->u.dst.tclassid |= tag&0xFFFF;
+ if (!(rt->u.dst.tclassid&0xFFFF0000))
+ rt->u.dst.tclassid |= tag&0xFFFF0000;
+}
+#endif
+
+static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
+{
+ struct fib_info *fi = res->fi;
+
+ if (fi) {
+ if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
+ rt->rt_gateway = FIB_RES_GW(*res);
+ rt->u.dst.mxlock = fi->fib_metrics[RTAX_LOCK-1];
+ rt->u.dst.pmtu = fi->fib_mtu;
+ if (fi->fib_mtu == 0) {
+ rt->u.dst.pmtu = rt->u.dst.dev->mtu;
+ if (rt->u.dst.pmtu > IP_MAX_MTU)
+ rt->u.dst.pmtu = IP_MAX_MTU;
+ if (rt->u.dst.pmtu < 68)
+ rt->u.dst.pmtu = 68;
+ if (rt->u.dst.mxlock&(1<<RTAX_MTU) &&
+ rt->rt_gateway != rt->rt_dst &&
+ rt->u.dst.pmtu > 576)
+ rt->u.dst.pmtu = 576;
+ }
+ rt->u.dst.window= fi->fib_window ? : 0;
+ rt->u.dst.rtt = fi->fib_rtt ? : TCP_TIMEOUT_INIT;
+#ifdef CONFIG_NET_CLS_ROUTE
+ rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
+#endif
+ } else {
+ rt->u.dst.pmtu = rt->u.dst.dev->mtu;
+ if (rt->u.dst.pmtu > IP_MAX_MTU)
+ rt->u.dst.pmtu = IP_MAX_MTU;
+ if (rt->u.dst.pmtu < 68)
+ rt->u.dst.pmtu = 68;
+ rt->u.dst.window= 0;
+ rt->u.dst.rtt = TCP_TIMEOUT_INIT;
+ }
+#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ set_class_tag(rt, fib_rules_tclass(res));
+#endif
+ set_class_tag(rt, itag);
+#endif
+ rt->rt_type = res->type;
+}
+
+static int
+ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
+ u8 tos, struct device *dev, int our)
+{
+ unsigned hash;
+ struct rtable *rth;
+ u32 spec_dst;
+ struct in_device *in_dev = dev->ip_ptr;
+ u32 itag = 0;
+
+ /* Primary sanity checks. */
+
+ if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr) ||
+ in_dev == NULL || skb->protocol != __constant_htons(ETH_P_IP))
+ return -EINVAL;
+
+ if (ZERONET(saddr)) {
+ if (!LOCAL_MCAST(daddr))
+ return -EINVAL;
+ spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
+ } else if (fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag) < 0)
+ return -EINVAL;
+
+ rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
+ if (!rth)
+ return -ENOBUFS;
+
+ rth->u.dst.output= ip_rt_bug;
+
+ atomic_set(&rth->u.dst.use, 1);
+ rth->key.dst = daddr;
+ rth->rt_dst = daddr;
+ rth->key.tos = tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->key.fwmark = skb->fwmark;
+#endif
+ rth->key.src = saddr;
+ rth->rt_src = saddr;
+#ifdef CONFIG_IP_ROUTE_NAT
+ rth->rt_dst_map = daddr;
+ rth->rt_src_map = saddr;
+#endif
+#ifdef CONFIG_NET_CLS_ROUTE
+ rth->u.dst.tclassid = itag;
+#endif
+ rth->rt_iif =
+ rth->key.iif = dev->ifindex;
+ rth->u.dst.dev = &loopback_dev;
+ rth->key.oif = 0;
+ rth->rt_gateway = daddr;
+ rth->rt_spec_dst= spec_dst;
+ rth->rt_type = RTN_MULTICAST;
+ rth->rt_flags = RTCF_MULTICAST;
+ if (our) {
+ rth->u.dst.input= ip_local_deliver;
+ rth->rt_flags |= RTCF_LOCAL;
+ }
+
+#ifdef CONFIG_IP_MROUTE
+ if (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))
+ rth->u.dst.input = ip_mr_input;
+#endif
+
+ hash = rt_hash_code(daddr, saddr^(dev->ifindex<<5), tos);
+ return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+}
+
+/*
+ * NOTE. We drop all the packets that has local source
+ * addresses, because every properly looped back packet
+ * must have correct destination already attached by output routine.
+ *
+ * Such approach solves two big problems:
+ * 1. Not simplex devices are handled properly.
+ * 2. IP spoofing attempts are filtered with 100% of guarantee.
+ */
+
+int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
+ u8 tos, struct device *dev)
+{
+ struct rt_key key;
+ struct fib_result res;
+ struct in_device *in_dev = dev->ip_ptr;
+ struct in_device *out_dev;
+ unsigned flags = 0;
+ u32 itag = 0;
+ struct rtable * rth;
+ unsigned hash;
+ u32 spec_dst;
+ int err = -EINVAL;
+
+ /*
+ * IP on this device is disabled.
+ */
+
+ if (!in_dev)
+ return -EINVAL;
+
+ key.dst = daddr;
+ key.src = saddr;
+ key.tos = tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ key.fwmark = skb->fwmark;
+#endif
+ key.iif = dev->ifindex;
+ key.oif = 0;
+ key.scope = RT_SCOPE_UNIVERSE;
+
+ hash = rt_hash_code(daddr, saddr^(key.iif<<5), tos);
+
+ /* Check for the most weird martians, which can be not detected
+ by fib_lookup.
+ */
+
+ if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr))
+ goto martian_source;
+
+ if (daddr == 0xFFFFFFFF || (saddr == 0 && daddr == 0))
+ goto brd_input;
+
+ /* Accept zero addresses only to limited broadcast;
+ * I even do not know to fix it or not. Waiting for complains :-)
+ */
+ if (ZERONET(saddr))
+ goto martian_source;
+
+ if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
+ goto martian_destination;
+
+ /*
+ * Now we are ready to route packet.
+ */
+ if ((err = fib_lookup(&key, &res))) {
+ if (!IN_DEV_FORWARD(in_dev))
+ return -EINVAL;
+ goto no_route;
+ }
+
+#ifdef CONFIG_IP_ROUTE_NAT
+ /* Policy is applied before mapping destination,
+ but rerouting after map should be made with old source.
+ */
+
+ if (1) {
+ u32 src_map = saddr;
+ if (res.r)
+ src_map = fib_rules_policy(saddr, &res, &flags);
+
+ if (res.type == RTN_NAT) {
+ key.dst = fib_rules_map_destination(daddr, &res);
+ if (fib_lookup(&key, &res) || res.type != RTN_UNICAST)
+ return -EINVAL;
+ flags |= RTCF_DNAT;
+ }
+ key.src = src_map;
+ }
+#endif
+
+ if (res.type == RTN_BROADCAST)
+ goto brd_input;
+
+ if (res.type == RTN_LOCAL) {
+ int result;
+ result = fib_validate_source(saddr, daddr, tos, loopback_dev.ifindex,
+ dev, &spec_dst, &itag);
+ if (result < 0)
+ goto martian_source;
+ if (result)
+ flags |= RTCF_DIRECTSRC;
+ spec_dst = daddr;
+ goto local_input;
+ }
+
+ if (!IN_DEV_FORWARD(in_dev))
+ return -EINVAL;
+ if (res.type != RTN_UNICAST)
+ goto martian_destination;
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (res.fi->fib_nhs > 1 && key.oif == 0)
+ fib_select_multipath(&key, &res);
+#endif
+ out_dev = FIB_RES_DEV(res)->ip_ptr;
+ if (out_dev == NULL) {
+ if (net_ratelimit())
+ printk(KERN_CRIT "Bug in ip_route_input_slow(). Please, report\n");
+ return -EINVAL;
+ }
+
+ err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev, &spec_dst, &itag);
+ if (err < 0)
+ goto martian_source;
+
+ if (err)
+ flags |= RTCF_DIRECTSRC;
+
+ if (out_dev == in_dev && err && !(flags&(RTCF_NAT|RTCF_MASQ)) &&
+ (IN_DEV_SHARED_MEDIA(out_dev)
+ || inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
+ flags |= RTCF_DOREDIRECT;
+
+ if (skb->protocol != __constant_htons(ETH_P_IP)) {
+ /* Not IP (i.e. ARP). Do not create route, if it is
+ * invalid for proxy arp. DNAT routes are always valid.
+ */
+ if (out_dev == in_dev && !(flags&RTCF_DNAT))
+ return -EINVAL;
+ }
+
+ rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
+ if (!rth)
+ return -ENOBUFS;
+
+ atomic_set(&rth->u.dst.use, 1);
+ rth->key.dst = daddr;
+ rth->rt_dst = daddr;
+ rth->key.tos = tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->key.fwmark = skb->fwmark;
+#endif
+ rth->key.src = saddr;
+ rth->rt_src = saddr;
+ rth->rt_gateway = daddr;
+#ifdef CONFIG_IP_ROUTE_NAT
+ rth->rt_src_map = key.src;
+ rth->rt_dst_map = key.dst;
+ if (flags&RTCF_DNAT)
+ rth->rt_gateway = key.dst;
+#endif
+ rth->rt_iif =
+ rth->key.iif = dev->ifindex;
+ rth->u.dst.dev = out_dev->dev;
+ rth->key.oif = 0;
+ rth->rt_spec_dst= spec_dst;
+
+ rth->u.dst.input = ip_forward;
+ rth->u.dst.output = ip_output;
+
+ rt_set_nexthop(rth, &res, itag);
+
+ rth->rt_flags = flags;
+
+#ifdef CONFIG_NET_FASTROUTE
+ if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) {
+ struct device *odev = rth->u.dst.dev;
+ if (odev != dev &&
+ dev->accept_fastpath &&
+ odev->mtu >= dev->mtu &&
+ dev->accept_fastpath(dev, &rth->u.dst) == 0)
+ rth->rt_flags |= RTCF_FAST;
+ }
+#endif
+
+ return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+
+brd_input:
+ if (skb->protocol != __constant_htons(ETH_P_IP))
+ return -EINVAL;
+
+ if (ZERONET(saddr)) {
+ spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
+ } else {
+ err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag);
+ if (err < 0)
+ goto martian_source;
+ if (err)
+ flags |= RTCF_DIRECTSRC;
+ }
+ flags |= RTCF_BROADCAST;
+ res.type = RTN_BROADCAST;
+
+local_input:
+ rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
+ if (!rth)
+ return -ENOBUFS;
+
+ rth->u.dst.output= ip_rt_bug;
+
+ atomic_set(&rth->u.dst.use, 1);
+ rth->key.dst = daddr;
+ rth->rt_dst = daddr;
+ rth->key.tos = tos;
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->key.fwmark = skb->fwmark;
+#endif
+ rth->key.src = saddr;
+ rth->rt_src = saddr;
+#ifdef CONFIG_IP_ROUTE_NAT
+ rth->rt_dst_map = key.dst;
+ rth->rt_src_map = key.src;
+#endif
+#ifdef CONFIG_NET_CLS_ROUTE
+ rth->u.dst.tclassid = itag;
+#endif
+ rth->rt_iif =
+ rth->key.iif = dev->ifindex;
+ rth->u.dst.dev = &loopback_dev;
+ rth->key.oif = 0;
+ rth->rt_gateway = daddr;
+ rth->rt_spec_dst= spec_dst;
+ rth->u.dst.input= ip_local_deliver;
+ rth->rt_flags = flags|RTCF_LOCAL;
+ if (res.type == RTN_UNREACHABLE) {
+ rth->u.dst.input= ip_error;
+ rth->u.dst.error= -err;
+ rth->rt_flags &= ~RTCF_LOCAL;
+ }
+ rth->rt_type = res.type;
+ return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+
+no_route:
+ spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
+ res.type = RTN_UNREACHABLE;
+ goto local_input;
+
+ /*
+ * Do not cache martian addresses: they should be logged (RFC1812)
+ */
+martian_destination:
+#ifdef CONFIG_IP_ROUTE_VERBOSE
+ if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
+ printk(KERN_WARNING "martian destination %08x from %08x, dev %s\n", daddr, saddr, dev->name);
+#endif
+ return -EINVAL;
+
+martian_source:
+#ifdef CONFIG_IP_ROUTE_VERBOSE
+ if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) {
+ /*
+ * RFC1812 recommenadtion, if source is martian,
+ * the only hint is MAC header.
+ */
+ printk(KERN_WARNING "martian source %08x for %08x, dev %s\n", saddr, daddr, dev->name);
+ if (dev->hard_header_len) {
+ int i;
+ unsigned char *p = skb->mac.raw;
+ printk(KERN_WARNING "ll header:");
+ for (i=0; i<dev->hard_header_len; i++, p++)
+ printk(" %02x", *p);
+ printk("\n");
+ }
+ }
+#endif
+ return -EINVAL;
+}
+
+int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
+ u8 tos, struct device *dev)
+{
+ struct rtable * rth;
+ unsigned hash;
+ int iif = dev->ifindex;
+
+ tos &= IPTOS_TOS_MASK;
+ hash = rt_hash_code(daddr, saddr^(iif<<5), tos);
+
+ for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) {
+ if (rth->key.dst == daddr &&
+ rth->key.src == saddr &&
+ rth->key.iif == iif &&
+ rth->key.oif == 0 &&
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->key.fwmark == skb->fwmark &&
+#endif
+ rth->key.tos == tos) {
+ rth->u.dst.lastuse = jiffies;
+ atomic_inc(&rth->u.dst.use);
+ atomic_inc(&rth->u.dst.refcnt);
+ skb->dst = (struct dst_entry*)rth;
+ return 0;
+ }
+ }
+
+ /* Multicast recognition logic is moved from route cache to here.
+ The problem was that too many Ethernet cards have broken/missing
+ hardware multicast filters :-( As result the host on multicasting
+ network acquires a lot of useless route cache entries, sort of
+ SDR messages from all the world. Now we try to get rid of them.
+ Really, provided software IP multicast filter is organized
+ reasonably (at least, hashed), it does not result in a slowdown
+ comparing with route cache reject entries.
+ Note, that multicast routers are not affected, because
+ route cache entry is created eventually.
+ */
+ if (MULTICAST(daddr)) {
+ int our = ip_check_mc(dev, daddr);
+ if (!our
+#ifdef CONFIG_IP_MROUTE
+ && (LOCAL_MCAST(daddr) || !dev->ip_ptr ||
+ !IN_DEV_MFORWARD((struct in_device*)dev->ip_ptr))
+#endif
+ ) return -EINVAL;
+ return ip_route_input_mc(skb, daddr, saddr, tos, dev, our);
+ }
+ return ip_route_input_slow(skb, daddr, saddr, tos, dev);
+}
+
+/*
+ * Major route resolver routine.
+ */
+
+int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
+{
+ struct rt_key key;
+ struct fib_result res;
+ unsigned flags = 0;
+ struct rtable *rth;
+ struct device *dev_out = NULL;
+ unsigned hash;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ u32 nochecksrc = (tos & RTO_TPROXY);
+#endif
+
+ tos &= IPTOS_TOS_MASK|RTO_ONLINK;
+ key.dst = daddr;
+ key.src = saddr;
+ key.tos = tos&IPTOS_TOS_MASK;
+ key.iif = loopback_dev.ifindex;
+ key.oif = oif;
+ key.scope = (tos&RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
+ res.fi = NULL;
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+ res.r = NULL;
+#endif
+
+ if (saddr) {
+ if (MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr))
+ return -EINVAL;
+
+ /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
+ dev_out = ip_dev_find(saddr);
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /* If address is not local, test for transparent proxy flag;
+ if address is local --- clear the flag.
+ */
+ if (dev_out == NULL) {
+ if (nochecksrc == 0 || inet_addr_type(saddr) != RTN_UNICAST)
+ return -EINVAL;
+ flags |= RTCF_TPROXY;
+ }
+#else
+ if (dev_out == NULL)
+ return -EINVAL;
+#endif
+
+ /* I removed check for oif == dev_out->oif here.
+ It was wrong by three reasons:
+ 1. ip_dev_find(saddr) can return wrong iface, if saddr is
+ assigned to multiple interfaces.
+ 2. Moreover, we are allowed to send packets with saddr
+ of another iface. --ANK
+ */
+
+ if (oif == 0 &&
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ dev_out &&
+#endif
+ (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) {
+ /* Special hack: user can direct multicasts
+ and limited broadcast via necessary interface
+ without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
+ This hack is not just for fun, it allows
+ vic,vat and friends to work.
+ They bind socket to loopback, set ttl to zero
+ and expect that it will work.
+ From the viewpoint of routing cache they are broken,
+ because we are not allowed to build multicast path
+ with loopback source addr (look, routing cache
+ cannot know, that ttl is zero, so that packet
+ will not leave this host and route is valid).
+ Luckily, this hack is good workaround.
+ */
+
+ key.oif = dev_out->ifindex;
+ goto make_route;
+ }
+ dev_out = NULL;
+ }
+ if (oif) {
+ dev_out = dev_get_by_index(oif);
+ if (dev_out == NULL)
+ return -ENODEV;
+ if (dev_out->ip_ptr == NULL)
+ return -ENODEV; /* Wrong error code */
+
+ if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) {
+ if (!key.src)
+ key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
+ goto make_route;
+ }
+ if (!key.src) {
+ if (MULTICAST(daddr))
+ key.src = inet_select_addr(dev_out, 0, key.scope);
+ else if (!daddr)
+ key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
+ }
+ }
+
+ if (!key.dst) {
+ key.dst = key.src;
+ if (!key.dst)
+ key.dst = key.src = htonl(INADDR_LOOPBACK);
+ dev_out = &loopback_dev;
+ key.oif = loopback_dev.ifindex;
+ res.type = RTN_LOCAL;
+ flags |= RTCF_LOCAL;
+ goto make_route;
+ }
+
+ if (fib_lookup(&key, &res)) {
+ res.fi = NULL;
+ if (oif) {
+ /* Apparently, routing tables are wrong. Assume,
+ that the destination is on link.
+
+ WHY? DW.
+ Because we are allowed to send to iface
+ even if it has NO routes and NO assigned
+ addresses. When oif is specified, routing
+ tables are looked up with only one purpose:
+ to catch if destination is gatewayed, rather than
+ direct. Moreover, if MSG_DONTROUTE is set,
+ we send packet, ignoring both routing tables
+ and ifaddr state. --ANK
+
+
+ We could make it even if oif is unknown,
+ likely IPv6, but we do not.
+ */
+
+ if (key.src == 0)
+ key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
+ res.type = RTN_UNICAST;
+ goto make_route;
+ }
+ return -ENETUNREACH;
+ }
+
+ if (res.type == RTN_NAT)
+ return -EINVAL;
+
+ if (res.type == RTN_LOCAL) {
+ if (!key.src)
+ key.src = key.dst;
+ dev_out = &loopback_dev;
+ key.oif = dev_out->ifindex;
+ res.fi = NULL;
+ flags |= RTCF_LOCAL;
+ goto make_route;
+ }
+
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (res.fi->fib_nhs > 1 && key.oif == 0)
+ fib_select_multipath(&key, &res);
+ else
+#endif
+ if (res.prefixlen==0 && res.type == RTN_UNICAST && key.oif == 0)
+ fib_select_default(&key, &res);
+
+ if (!key.src)
+ key.src = FIB_RES_PREFSRC(res);
+
+ dev_out = FIB_RES_DEV(res);
+ key.oif = dev_out->ifindex;
+
+make_route:
+ if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK))
+ return -EINVAL;
+
+ if (key.dst == 0xFFFFFFFF)
+ res.type = RTN_BROADCAST;
+ else if (MULTICAST(key.dst))
+ res.type = RTN_MULTICAST;
+ else if (BADCLASS(key.dst) || ZERONET(key.dst))
+ return -EINVAL;
+
+ if (dev_out->flags&IFF_LOOPBACK)
+ flags |= RTCF_LOCAL;
+
+ if (res.type == RTN_BROADCAST) {
+ flags |= RTCF_BROADCAST|RTCF_LOCAL;
+ res.fi = NULL;
+ } else if (res.type == RTN_MULTICAST) {
+ flags |= RTCF_MULTICAST|RTCF_LOCAL;
+ if (!ip_check_mc(dev_out, daddr))
+ flags &= ~RTCF_LOCAL;
+ /* If multicast route do not exist use
+ default one, but do not gateway in this case.
+ Yes, it is hack.
+ */
+ if (res.fi && res.prefixlen < 4)
+ res.fi = NULL;
+ }
+
+ rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
+ if (!rth)
+ return -ENOBUFS;
+
+ atomic_set(&rth->u.dst.use, 1);
+ rth->key.dst = daddr;
+ rth->key.tos = tos;
+ rth->key.src = saddr;
+ rth->key.iif = 0;
+ rth->key.oif = oif;
+ rth->rt_dst = key.dst;
+ rth->rt_src = key.src;
+#ifdef CONFIG_IP_ROUTE_NAT
+ rth->rt_dst_map = key.dst;
+ rth->rt_src_map = key.src;
+#endif
+ rth->rt_iif = oif ? : dev_out->ifindex;
+ rth->u.dst.dev = dev_out;
+ rth->rt_gateway = key.dst;
+ rth->rt_spec_dst= key.src;
+
+ rth->u.dst.output=ip_output;
+
+ if (flags&RTCF_LOCAL) {
+ rth->u.dst.input = ip_local_deliver;
+ rth->rt_spec_dst = key.dst;
+ }
+ if (flags&(RTCF_BROADCAST|RTCF_MULTICAST)) {
+ rth->rt_spec_dst = key.src;
+ if (flags&RTCF_LOCAL && !(dev_out->flags&IFF_LOOPBACK))
+ rth->u.dst.output = ip_mc_output;
+#ifdef CONFIG_IP_MROUTE
+ if (res.type == RTN_MULTICAST && dev_out->ip_ptr) {
+ struct in_device *in_dev = dev_out->ip_ptr;
+ if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(daddr)) {
+ rth->u.dst.input = ip_mr_input;
+ rth->u.dst.output = ip_mc_output;
+ }
+ }
+#endif
+ }
+
+ rt_set_nexthop(rth, &res, 0);
+
+ rth->rt_flags = flags;
+
+ hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
+ return rt_intern_hash(hash, rth, rp);
+}
+
+int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
+{
+ unsigned hash;
+ struct rtable *rth;
+
+ hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
+
+ start_bh_atomic();
+ for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) {
+ if (rth->key.dst == daddr &&
+ rth->key.src == saddr &&
+ rth->key.iif == 0 &&
+ rth->key.oif == oif &&
+#ifndef CONFIG_IP_TRANSPARENT_PROXY
+ rth->key.tos == tos
+#else
+ !((rth->key.tos^tos)&(IPTOS_TOS_MASK|RTO_ONLINK)) &&
+ ((tos&RTO_TPROXY) || !(rth->rt_flags&RTCF_TPROXY))
+#endif
+ ) {
+ rth->u.dst.lastuse = jiffies;
+ atomic_inc(&rth->u.dst.use);
+ atomic_inc(&rth->u.dst.refcnt);
+ end_bh_atomic();
+ *rp = rth;
+ return 0;
+ }
+ }
+ end_bh_atomic();
+
+ return ip_route_output_slow(rp, daddr, saddr, tos, oif);
+}
+
+#ifdef CONFIG_RTNETLINK
+
+static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait)
+{
+ struct rtable *rt = (struct rtable*)skb->dst;
+ struct rtmsg *r;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+ struct rta_cacheinfo ci;
+#ifdef CONFIG_IP_MROUTE
+ struct rtattr *eptr;
+#endif
+ struct rtattr *mx;
+
+ nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r));
+ r = NLMSG_DATA(nlh);
+ nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
+ r->rtm_family = AF_INET;
+ r->rtm_dst_len = 32;
+ r->rtm_src_len = 0;
+ r->rtm_tos = rt->key.tos;
+ r->rtm_table = RT_TABLE_MAIN;
+ r->rtm_type = rt->rt_type;
+ r->rtm_scope = RT_SCOPE_UNIVERSE;
+ r->rtm_protocol = RTPROT_UNSPEC;
+ r->rtm_flags = (rt->rt_flags&~0xFFFF) | RTM_F_CLONED;
+ if (rt->rt_flags & RTCF_NOTIFY)
+ r->rtm_flags |= RTM_F_NOTIFY;
+ RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
+ if (rt->key.src) {
+ r->rtm_src_len = 32;
+ RTA_PUT(skb, RTA_SRC, 4, &rt->key.src);
+ }
+ if (rt->u.dst.dev)
+ RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
+#ifdef CONFIG_NET_CLS_ROUTE
+ if (rt->u.dst.tclassid)
+ RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid);
+#endif
+ if (rt->key.iif)
+ RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
+ else if (rt->rt_src != rt->key.src)
+ RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
+ if (rt->rt_dst != rt->rt_gateway)
+ RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
+ mx = (struct rtattr*)skb->tail;
+ RTA_PUT(skb, RTA_METRICS, 0, NULL);
+ if (rt->u.dst.mxlock)
+ RTA_PUT(skb, RTAX_LOCK, sizeof(unsigned), &rt->u.dst.mxlock);
+ if (rt->u.dst.pmtu)
+ RTA_PUT(skb, RTAX_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
+ if (rt->u.dst.window)
+ RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window);
+ if (rt->u.dst.rtt)
+ RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt);
+ mx->rta_len = skb->tail - (u8*)mx;
+ if (mx->rta_len == RTA_LENGTH(0))
+ skb_trim(skb, (u8*)mx - skb->data);
+ ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
+ ci.rta_used = atomic_read(&rt->u.dst.refcnt);
+ ci.rta_clntref = atomic_read(&rt->u.dst.use);
+ if (rt->u.dst.expires)
+ ci.rta_expires = rt->u.dst.expires - jiffies;
+ else
+ ci.rta_expires = 0;
+ ci.rta_error = rt->u.dst.error;
+#ifdef CONFIG_IP_MROUTE
+ eptr = (struct rtattr*)skb->tail;
+#endif
+ RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
+ if (rt->key.iif) {
+#ifdef CONFIG_IP_MROUTE
+ u32 dst = rt->rt_dst;
+
+ if (MULTICAST(dst) && !LOCAL_MCAST(dst) && ipv4_devconf.mc_forwarding) {
+ int err = ipmr_get_route(skb, r, nowait);
+ if (err <= 0) {
+ if (!nowait) {
+ if (err == 0)
+ return 0;
+ goto nlmsg_failure;
+ } else {
+ if (err == -EMSGSIZE)
+ goto nlmsg_failure;
+ ((struct rta_cacheinfo*)RTA_DATA(eptr))->rta_error = err;
+ }
+ }
+ } else
+#endif
+ {
+ RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->key.iif);
+ }
+ }
+
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct rtmsg *rtm = NLMSG_DATA(nlh);
+ struct rtable *rt = NULL;
+ u32 dst = 0;
+ u32 src = 0;
+ int iif = 0;
+ int err;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (skb == NULL)
+ return -ENOBUFS;
+
+ /* Reserve room for dummy headers, this skb can pass
+ through good chunk of routing engine.
+ */
+ skb->mac.raw = skb->data;
+ skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
+
+ if (rta[RTA_SRC-1])
+ memcpy(&src, RTA_DATA(rta[RTA_SRC-1]), 4);
+ if (rta[RTA_DST-1])
+ memcpy(&dst, RTA_DATA(rta[RTA_DST-1]), 4);
+ if (rta[RTA_IIF-1])
+ memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+
+ if (iif) {
+ struct device *dev;
+ dev = dev_get_by_index(iif);
+ if (!dev)
+ return -ENODEV;
+ skb->protocol = __constant_htons(ETH_P_IP);
+ skb->dev = dev;
+ start_bh_atomic();
+ err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
+ end_bh_atomic();
+ rt = (struct rtable*)skb->dst;
+ if (!err && rt->u.dst.error)
+ err = -rt->u.dst.error;
+ } else {
+ int oif = 0;
+ if (rta[RTA_OIF-1])
+ memcpy(&oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
+ err = ip_route_output(&rt, dst, src, rtm->rtm_tos, oif);
+ }
+ if (err) {
+ kfree_skb(skb);
+ return err;
+ }
+
+ skb->dst = &rt->u.dst;
+ if (rtm->rtm_flags & RTM_F_NOTIFY)
+ rt->rt_flags |= RTCF_NOTIFY;
+
+ NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+
+ err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0);
+ if (err == 0)
+ return 0;
+ if (err < 0)
+ return -EMSGSIZE;
+
+ err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+
+int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct rtable *rt;
+ int h, s_h;
+ int idx, s_idx;
+
+ s_h = cb->args[0];
+ s_idx = idx = cb->args[1];
+ for (h=0; h < RT_HASH_DIVISOR; h++) {
+ if (h < s_h) continue;
+ if (h > s_h)
+ s_idx = 0;
+ start_bh_atomic();
+ for (rt = rt_hash_table[h], idx = 0; rt; rt = rt->u.rt_next, idx++) {
+ if (idx < s_idx)
+ continue;
+ skb->dst = dst_clone(&rt->u.dst);
+ if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) {
+ dst_release(xchg(&skb->dst, NULL));
+ end_bh_atomic();
+ goto done;
+ }
+ dst_release(xchg(&skb->dst, NULL));
+ }
+ end_bh_atomic();
+ }
+
+done:
+ cb->args[0] = h;
+ cb->args[1] = idx;
+ return skb->len;
+}
+
+#endif /* CONFIG_RTNETLINK */
+
+void ip_rt_multicast_event(struct in_device *in_dev)
+{
+ rt_cache_flush(0);
+}
+
+
+
+#ifdef CONFIG_SYSCTL
+
+static int flush_delay;
+
+static
+int ipv4_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp)
+{
+ if (write) {
+ proc_dointvec(ctl, write, filp, buffer, lenp);
+ rt_cache_flush(flush_delay);
+ return 0;
+ } else
+ return -EINVAL;
+}
+
+static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen,
+ void **context)
+{
+ int delay;
+ if (newlen != sizeof(int))
+ return -EINVAL;
+ if (get_user(delay,(int *)newval))
+ return -EFAULT;
+ rt_cache_flush(delay);
+ return 0;
+}
+
+ctl_table ipv4_route_table[] = {
+ {NET_IPV4_ROUTE_FLUSH, "flush",
+ &flush_delay, sizeof(int), 0644, NULL,
+ &ipv4_sysctl_rtcache_flush, &ipv4_sysctl_rtcache_flush_strategy },
+ {NET_IPV4_ROUTE_MIN_DELAY, "min_delay",
+ &ip_rt_min_delay, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_ROUTE_MAX_DELAY, "max_delay",
+ &ip_rt_max_delay, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_ROUTE_GC_THRESH, "gc_thresh",
+ &ipv4_dst_ops.gc_thresh, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_MAX_SIZE, "max_size",
+ &ip_rt_max_size, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_GC_MIN_INTERVAL, "gc_min_interval",
+ &ip_rt_gc_min_interval, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_ROUTE_GC_TIMEOUT, "gc_timeout",
+ &ip_rt_gc_timeout, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_ROUTE_GC_INTERVAL, "gc_interval",
+ &ip_rt_gc_interval, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_ROUTE_REDIRECT_LOAD, "redirect_load",
+ &ip_rt_redirect_load, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_REDIRECT_NUMBER, "redirect_number",
+ &ip_rt_redirect_number, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_REDIRECT_SILENCE, "redirect_silence",
+ &ip_rt_redirect_silence, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_ERROR_COST, "error_cost",
+ &ip_rt_error_cost, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_ERROR_BURST, "error_burst",
+ &ip_rt_error_burst, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_GC_ELASTICITY, "gc_elasticity",
+ &ip_rt_gc_elasticity, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ROUTE_MTU_EXPIRES, "mtu_expires",
+ &ip_rt_mtu_expires, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {0}
+};
+#endif
+
+#ifdef CONFIG_NET_CLS_ROUTE
+struct ip_rt_acct ip_rt_acct[256];
+
+#ifdef CONFIG_PROC_FS
+static int ip_rt_acct_read(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
+{
+ *start=buffer;
+
+ if (offset + length > sizeof(ip_rt_acct)) {
+ length = sizeof(ip_rt_acct) - offset;
+ *eof = 1;
+ }
+ if (length > 0) {
+ start_bh_atomic();
+ memcpy(buffer, ((u8*)&ip_rt_acct)+offset, length);
+ end_bh_atomic();
+ return length;
+ }
+ return 0;
+}
+#endif
+#endif
+
+
+__initfunc(void ip_rt_init(void))
+{
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_NET_CLS_ROUTE
+ struct proc_dir_entry *ent;
+#endif
+#endif
+ devinet_init();
+ ip_fib_init();
+ rt_periodic_timer.function = rt_check_expire;
+ /* All the timers, started at system startup tend
+ to synchronize. Perturb it a bit.
+ */
+ rt_periodic_timer.expires = jiffies + net_random()%ip_rt_gc_interval
+ + ip_rt_gc_interval;
+ add_timer(&rt_periodic_timer);
+
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&(struct proc_dir_entry) {
+ PROC_NET_RTCACHE, 8, "rt_cache",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ rt_cache_get_info
+ });
+#ifdef CONFIG_NET_CLS_ROUTE
+ ent = create_proc_entry("net/rt_acct", 0, 0);
+ ent->read_proc = ip_rt_acct_read;
+#endif
+#endif
+}
diff --git a/pfinet/linux-src/net/ipv4/syncookies.c b/pfinet/linux-src/net/ipv4/syncookies.c
new file mode 100644
index 00000000..62884aae
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/syncookies.c
@@ -0,0 +1,203 @@
+/*
+ * Syncookies implementation for the Linux kernel
+ *
+ * Copyright (C) 1997 Andi Kleen
+ * Based on ideas by D.J.Bernstein and Eric Schenk.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * $Id: syncookies.c,v 1.7.2.3 1999/12/07 03:11:07 davem Exp $
+ *
+ * Missing: IPv6 support.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_SYN_COOKIES)
+#include <linux/tcp.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <net/tcp.h>
+
+extern int sysctl_tcp_syncookies;
+
+static unsigned long tcp_lastsynq_overflow;
+
+/*
+ * This table has to be sorted and terminated with (__u16)-1.
+ * XXX generate a better table.
+ * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ */
+static __u16 const msstab[] = {
+ 64-1,
+ 256-1,
+ 512-1,
+ 536-1,
+ 1024-1,
+ 1440-1,
+ 1460-1,
+ 4312-1,
+ (__u16)-1
+};
+/* The number doesn't include the -1 terminator */
+#define NUM_MSS (sizeof(msstab)/sizeof(msstab[0]) - 1)
+
+/*
+ * Generate a syncookie. mssp points to the mss, which is returned
+ * rounded down to the value encoded in the cookie.
+ */
+__u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
+ __u16 *mssp)
+{
+ int mssind;
+ const __u16 mss = *mssp;
+
+ tcp_lastsynq_overflow = jiffies;
+ /* XXX sort msstab[] by probability? Binary search? */
+ for (mssind = 0; mss > msstab[mssind+1]; mssind++)
+ ;
+ *mssp = msstab[mssind]+1;
+
+ net_statistics.SyncookiesSent++;
+
+ return secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->h.th->source, skb->h.th->dest,
+ ntohl(skb->h.th->seq),
+ jiffies / (HZ*60), mssind);
+}
+
+/*
+ * This (misnamed) value is the age of syncookie which is permitted.
+ * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
+ * sysctl_tcp_retries1. It's a rather complicated formula (exponential
+ * backoff) to compute at runtime so it's currently hardcoded here.
+ */
+#define COUNTER_TRIES 4
+/*
+ * Check if a ack sequence number is a valid syncookie.
+ * Return the decoded mss if it is, or 0 if not.
+ */
+static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
+{
+ __u32 seq;
+ __u32 mssind;
+
+ if ((jiffies - tcp_lastsynq_overflow) > TCP_TIMEOUT_INIT)
+ return 0;
+
+ seq = ntohl(skb->h.th->seq)-1;
+ mssind = check_tcp_syn_cookie(cookie,
+ skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->h.th->source, skb->h.th->dest,
+ seq, jiffies/(HZ*60), COUNTER_TRIES);
+
+ return mssind < NUM_MSS ? msstab[mssind]+1 : 0;
+}
+
+extern struct or_calltable or_ipv4;
+
+static inline struct sock *
+get_cookie_sock(struct sock *sk, struct sk_buff *skb, struct open_request *req,
+ struct dst_entry *dst)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ sk = tp->af_specific->syn_recv_sock(sk, skb, req, dst);
+ req->sk = sk;
+
+ /* Queue up for accept() */
+ tcp_synq_queue(tp, req);
+
+ return sk;
+}
+
+struct sock *
+cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt)
+{
+ __u32 cookie = ntohl(skb->h.th->ack_seq)-1;
+ struct open_request *req;
+ int mss;
+ struct rtable *rt;
+ __u8 rcv_wscale;
+
+ if (!sysctl_tcp_syncookies)
+ return sk;
+ if (!skb->h.th->ack)
+ return sk;
+
+ mss = cookie_check(skb, cookie);
+ if (mss == 0) {
+ net_statistics.SyncookiesFailed++;
+ return sk;
+ }
+
+ net_statistics.SyncookiesRecv++;
+
+ req = tcp_openreq_alloc();
+ if (req == NULL)
+ return NULL;
+
+ req->rcv_isn = htonl(skb->h.th->seq)-1;
+ req->snt_isn = cookie;
+ req->mss = mss;
+ req->rmt_port = skb->h.th->source;
+ req->af.v4_req.loc_addr = skb->nh.iph->daddr;
+ req->af.v4_req.rmt_addr = skb->nh.iph->saddr;
+ req->class = &or_ipv4; /* for safety */
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ req->lcl_port = skb->h.th->dest;
+#endif
+
+ req->af.v4_req.opt = NULL;
+
+ /* We throwed the options of the initial SYN away, so we hope
+ * the ACK carries the same options again (see RFC1122 4.2.3.8)
+ */
+ if (opt && opt->optlen) {
+ int opt_size = sizeof(struct ip_options) + opt->optlen;
+
+ req->af.v4_req.opt = kmalloc(opt_size, GFP_ATOMIC);
+ if (req->af.v4_req.opt) {
+ if (ip_options_echo(req->af.v4_req.opt, skb)) {
+ kfree_s(req->af.v4_req.opt, opt_size);
+ req->af.v4_req.opt = NULL;
+ }
+ }
+ }
+
+ req->snd_wscale = req->rcv_wscale = req->tstamp_ok = 0;
+ req->wscale_ok = 0;
+ req->expires = 0UL;
+ req->retrans = 0;
+
+ /*
+ * We need to lookup the route here to get at the correct
+ * window size. We should better make sure that the window size
+ * hasn't changed since we received the original syn, but I see
+ * no easy way to do this.
+ */
+ if (ip_route_output(&rt,
+ opt &&
+ opt->srr ? opt->faddr : req->af.v4_req.rmt_addr,
+ req->af.v4_req.loc_addr,
+ sk->ip_tos | RTO_CONN,
+ 0)) {
+ if (req->af.v4_req.opt)
+ kfree(req->af.v4_req.opt);
+ tcp_openreq_free(req);
+ return NULL;
+ }
+
+ /* Try to redo what tcp_v4_send_synack did. */
+ req->window_clamp = rt->u.dst.window;
+ tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
+ &req->rcv_wnd, &req->window_clamp,
+ 0, &rcv_wscale);
+ req->rcv_wscale = rcv_wscale;
+
+ return get_cookie_sock(sk, skb, req, &rt->u.dst);
+}
+
+#endif
diff --git a/pfinet/linux-src/net/ipv4/sysctl_net_ipv4.c b/pfinet/linux-src/net/ipv4/sysctl_net_ipv4.c
new file mode 100644
index 00000000..235b36d1
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/sysctl_net_ipv4.c
@@ -0,0 +1,210 @@
+/*
+ * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
+ *
+ * $Id: sysctl_net_ipv4.c,v 1.38.2.2 1999/09/22 16:33:30 davem Exp $
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <linux/config.h>
+#include <net/snmp.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/tcp.h>
+
+/*
+ * TCP configuration parameters
+ */
+
+#define TCP_PMTU_DISC 0x00000001 /* perform PMTU discovery */
+#define TCP_CONG_AVOID 0x00000002 /* congestion avoidance algorithm */
+#define TCP_DELAY_ACKS 0x00000003 /* delayed ack stategy */
+
+#if 0
+static int boolean_min = 0;
+static int boolean_max = 1;
+#endif
+
+/* From icmp.c */
+extern int sysctl_icmp_echo_ignore_all;
+extern int sysctl_icmp_echo_ignore_broadcasts;
+extern int sysctl_icmp_ignore_bogus_error_responses;
+
+/* From ip_fragment.c */
+extern int sysctl_ipfrag_low_thresh;
+extern int sysctl_ipfrag_high_thresh;
+extern int sysctl_ipfrag_time;
+
+/* From ip_output.c */
+extern int sysctl_ip_dynaddr;
+
+/* From ip_input.c */
+extern int sysctl_ip_always_defrag;
+
+/* From ip_masq.c */
+extern int sysctl_ip_masq_debug;
+
+extern int sysctl_tcp_timestamps;
+extern int sysctl_tcp_window_scaling;
+extern int sysctl_tcp_sack;
+extern int sysctl_tcp_retrans_collapse;
+extern int sysctl_tcp_keepalive_time;
+extern int sysctl_tcp_keepalive_probes;
+extern int sysctl_tcp_max_ka_probes;
+extern int sysctl_tcp_retries1;
+extern int sysctl_tcp_retries2;
+extern int sysctl_tcp_fin_timeout;
+extern int sysctl_tcp_syncookies;
+extern int sysctl_tcp_syn_retries;
+extern int sysctl_tcp_stdurg;
+extern int sysctl_tcp_rfc1337;
+extern int sysctl_tcp_syn_taildrop;
+extern int sysctl_max_syn_backlog;
+
+/* From icmp.c */
+extern int sysctl_icmp_destunreach_time;
+extern int sysctl_icmp_timeexceed_time;
+extern int sysctl_icmp_paramprob_time;
+extern int sysctl_icmp_echoreply_time;
+
+/* From igmp.c */
+extern int sysctl_igmp_max_memberships;
+
+int tcp_retr1_max = 255;
+
+struct ipv4_config ipv4_config;
+
+extern ctl_table ipv4_route_table[];
+
+#ifdef CONFIG_SYSCTL
+
+static
+int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp)
+{
+ int val = ipv4_devconf.forwarding;
+ int ret;
+
+ ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+ if (write && ipv4_devconf.forwarding != val)
+ inet_forward_change();
+
+ return ret;
+}
+
+static int ipv4_sysctl_forward_strategy(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen,
+ void **context)
+{
+ int new;
+ if (newlen != sizeof(int))
+ return -EINVAL;
+ if (get_user(new,(int *)newval))
+ return -EFAULT;
+ if (new != ipv4_devconf.forwarding)
+ inet_forward_change();
+ return 0; /* caller does change again and handles handles oldval */
+}
+
+ctl_table ipv4_table[] = {
+ {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps",
+ &sysctl_tcp_timestamps, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_TCP_WINDOW_SCALING, "tcp_window_scaling",
+ &sysctl_tcp_window_scaling, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_TCP_SACK, "tcp_sack",
+ &sysctl_tcp_sack, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_TCP_RETRANS_COLLAPSE, "tcp_retrans_collapse",
+ &sysctl_tcp_retrans_collapse, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_FORWARD, "ip_forward",
+ &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
+ &ipv4_sysctl_forward,&ipv4_sysctl_forward_strategy},
+ {NET_IPV4_DEFAULT_TTL, "ip_default_ttl",
+ &ip_statistics.IpDefaultTTL, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_AUTOCONFIG, "ip_autoconfig",
+ &ipv4_config.autoconfig, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_NO_PMTU_DISC, "ip_no_pmtu_disc",
+ &ipv4_config.no_pmtu_disc, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_TCP_SYN_RETRIES, "tcp_syn_retries",
+ &sysctl_tcp_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh",
+ &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
+ &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_DYNADDR, "ip_dynaddr",
+ &sysctl_ip_dynaddr, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_ALWAYS_DEFRAG, "ip_always_defrag",
+ &sysctl_ip_always_defrag, sizeof(int), 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_IP_MASQUERADE
+ {NET_IPV4_IP_MASQ_DEBUG, "ip_masq_debug",
+ &sysctl_ip_masq_debug, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+ {NET_IPV4_IPFRAG_TIME, "ipfrag_time",
+ &sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies,
+ &sysctl_jiffies},
+ {NET_IPV4_TCP_MAX_KA_PROBES, "tcp_max_ka_probes",
+ &sysctl_tcp_max_ka_probes, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_TCP_KEEPALIVE_TIME, "tcp_keepalive_time",
+ &sysctl_tcp_keepalive_time, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes",
+ &sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_TCP_RETRIES1, "tcp_retries1",
+ &sysctl_tcp_retries1, sizeof(int), 0644, NULL, &proc_dointvec_minmax,
+ &sysctl_intvec, NULL, NULL, &tcp_retr1_max},
+ {NET_IPV4_TCP_RETRIES2, "tcp_retries2",
+ &sysctl_tcp_retries2, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_TCP_FIN_TIMEOUT, "tcp_fin_timeout",
+ &sysctl_tcp_fin_timeout, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+#ifdef CONFIG_SYN_COOKIES
+ {NET_TCP_SYNCOOKIES, "tcp_syncookies",
+ &sysctl_tcp_syncookies, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+ {NET_TCP_STDURG, "tcp_stdurg", &sysctl_tcp_stdurg,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_TCP_RFC1337, "tcp_rfc1337", &sysctl_tcp_rfc1337,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_TCP_MAX_SYN_BACKLOG, "tcp_max_syn_backlog", &sysctl_max_syn_backlog,
+ sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_LOCAL_PORT_RANGE, "ip_local_port_range",
+ &sysctl_local_port_range, sizeof(sysctl_local_port_range), 0644,
+ NULL, &proc_dointvec},
+ {NET_IPV4_ICMP_ECHO_IGNORE_ALL, "icmp_echo_ignore_all",
+ &sysctl_icmp_echo_ignore_all, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, "icmp_echo_ignore_broadcasts",
+ &sysctl_icmp_echo_ignore_broadcasts, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, "icmp_ignore_bogus_error_responses",
+ &sysctl_icmp_ignore_bogus_error_responses, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV4_ICMP_DESTUNREACH_RATE, "icmp_destunreach_rate",
+ &sysctl_icmp_destunreach_time, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_ICMP_TIMEEXCEED_RATE, "icmp_timeexceed_rate",
+ &sysctl_icmp_timeexceed_time, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_ICMP_PARAMPROB_RATE, "icmp_paramprob_rate",
+ &sysctl_icmp_paramprob_time, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_ICMP_ECHOREPLY_RATE, "icmp_echoreply_rate",
+ &sysctl_icmp_echoreply_time, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_ROUTE, "route", NULL, 0, 0555, ipv4_route_table},
+#ifdef CONFIG_IP_MULTICAST
+ {NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships",
+ &sysctl_igmp_max_memberships, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+ {0}
+};
+
+#endif /* CONFIG_SYSCTL */
diff --git a/pfinet/linux-src/net/ipv4/tcp.c b/pfinet/linux-src/net/ipv4/tcp.c
new file mode 100644
index 00000000..8cde3854
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/tcp.c
@@ -0,0 +1,1886 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Implementation of the Transmission Control Protocol(TCP).
+ *
+ * Version: $Id: tcp.c,v 1.140.2.5 1999/09/23 19:21:16 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ * Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
+ * Linus Torvalds, <torvalds@cs.helsinki.fi>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Matthew Dillon, <dillon@apollo.west.oic.com>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Jorge Cwik, <jorge@laser.satlink.net>
+ *
+ * Fixes:
+ * Alan Cox : Numerous verify_area() calls
+ * Alan Cox : Set the ACK bit on a reset
+ * Alan Cox : Stopped it crashing if it closed while
+ * sk->inuse=1 and was trying to connect
+ * (tcp_err()).
+ * Alan Cox : All icmp error handling was broken
+ * pointers passed where wrong and the
+ * socket was looked up backwards. Nobody
+ * tested any icmp error code obviously.
+ * Alan Cox : tcp_err() now handled properly. It
+ * wakes people on errors. poll
+ * behaves and the icmp error race
+ * has gone by moving it into sock.c
+ * Alan Cox : tcp_send_reset() fixed to work for
+ * everything not just packets for
+ * unknown sockets.
+ * Alan Cox : tcp option processing.
+ * Alan Cox : Reset tweaked (still not 100%) [Had
+ * syn rule wrong]
+ * Herp Rosmanith : More reset fixes
+ * Alan Cox : No longer acks invalid rst frames.
+ * Acking any kind of RST is right out.
+ * Alan Cox : Sets an ignore me flag on an rst
+ * receive otherwise odd bits of prattle
+ * escape still
+ * Alan Cox : Fixed another acking RST frame bug.
+ * Should stop LAN workplace lockups.
+ * Alan Cox : Some tidyups using the new skb list
+ * facilities
+ * Alan Cox : sk->keepopen now seems to work
+ * Alan Cox : Pulls options out correctly on accepts
+ * Alan Cox : Fixed assorted sk->rqueue->next errors
+ * Alan Cox : PSH doesn't end a TCP read. Switched a
+ * bit to skb ops.
+ * Alan Cox : Tidied tcp_data to avoid a potential
+ * nasty.
+ * Alan Cox : Added some better commenting, as the
+ * tcp is hard to follow
+ * Alan Cox : Removed incorrect check for 20 * psh
+ * Michael O'Reilly : ack < copied bug fix.
+ * Johannes Stille : Misc tcp fixes (not all in yet).
+ * Alan Cox : FIN with no memory -> CRASH
+ * Alan Cox : Added socket option proto entries.
+ * Also added awareness of them to accept.
+ * Alan Cox : Added TCP options (SOL_TCP)
+ * Alan Cox : Switched wakeup calls to callbacks,
+ * so the kernel can layer network
+ * sockets.
+ * Alan Cox : Use ip_tos/ip_ttl settings.
+ * Alan Cox : Handle FIN (more) properly (we hope).
+ * Alan Cox : RST frames sent on unsynchronised
+ * state ack error.
+ * Alan Cox : Put in missing check for SYN bit.
+ * Alan Cox : Added tcp_select_window() aka NET2E
+ * window non shrink trick.
+ * Alan Cox : Added a couple of small NET2E timer
+ * fixes
+ * Charles Hedrick : TCP fixes
+ * Toomas Tamm : TCP window fixes
+ * Alan Cox : Small URG fix to rlogin ^C ack fight
+ * Charles Hedrick : Rewrote most of it to actually work
+ * Linus : Rewrote tcp_read() and URG handling
+ * completely
+ * Gerhard Koerting: Fixed some missing timer handling
+ * Matthew Dillon : Reworked TCP machine states as per RFC
+ * Gerhard Koerting: PC/TCP workarounds
+ * Adam Caldwell : Assorted timer/timing errors
+ * Matthew Dillon : Fixed another RST bug
+ * Alan Cox : Move to kernel side addressing changes.
+ * Alan Cox : Beginning work on TCP fastpathing
+ * (not yet usable)
+ * Arnt Gulbrandsen: Turbocharged tcp_check() routine.
+ * Alan Cox : TCP fast path debugging
+ * Alan Cox : Window clamping
+ * Michael Riepe : Bug in tcp_check()
+ * Matt Dillon : More TCP improvements and RST bug fixes
+ * Matt Dillon : Yet more small nasties remove from the
+ * TCP code (Be very nice to this man if
+ * tcp finally works 100%) 8)
+ * Alan Cox : BSD accept semantics.
+ * Alan Cox : Reset on closedown bug.
+ * Peter De Schrijver : ENOTCONN check missing in tcp_sendto().
+ * Michael Pall : Handle poll() after URG properly in
+ * all cases.
+ * Michael Pall : Undo the last fix in tcp_read_urg()
+ * (multi URG PUSH broke rlogin).
+ * Michael Pall : Fix the multi URG PUSH problem in
+ * tcp_readable(), poll() after URG
+ * works now.
+ * Michael Pall : recv(...,MSG_OOB) never blocks in the
+ * BSD api.
+ * Alan Cox : Changed the semantics of sk->socket to
+ * fix a race and a signal problem with
+ * accept() and async I/O.
+ * Alan Cox : Relaxed the rules on tcp_sendto().
+ * Yury Shevchuk : Really fixed accept() blocking problem.
+ * Craig I. Hagan : Allow for BSD compatible TIME_WAIT for
+ * clients/servers which listen in on
+ * fixed ports.
+ * Alan Cox : Cleaned the above up and shrank it to
+ * a sensible code size.
+ * Alan Cox : Self connect lockup fix.
+ * Alan Cox : No connect to multicast.
+ * Ross Biro : Close unaccepted children on master
+ * socket close.
+ * Alan Cox : Reset tracing code.
+ * Alan Cox : Spurious resets on shutdown.
+ * Alan Cox : Giant 15 minute/60 second timer error
+ * Alan Cox : Small whoops in polling before an
+ * accept.
+ * Alan Cox : Kept the state trace facility since
+ * it's handy for debugging.
+ * Alan Cox : More reset handler fixes.
+ * Alan Cox : Started rewriting the code based on
+ * the RFC's for other useful protocol
+ * references see: Comer, KA9Q NOS, and
+ * for a reference on the difference
+ * between specifications and how BSD
+ * works see the 4.4lite source.
+ * A.N.Kuznetsov : Don't time wait on completion of tidy
+ * close.
+ * Linus Torvalds : Fin/Shutdown & copied_seq changes.
+ * Linus Torvalds : Fixed BSD port reuse to work first syn
+ * Alan Cox : Reimplemented timers as per the RFC
+ * and using multiple timers for sanity.
+ * Alan Cox : Small bug fixes, and a lot of new
+ * comments.
+ * Alan Cox : Fixed dual reader crash by locking
+ * the buffers (much like datagram.c)
+ * Alan Cox : Fixed stuck sockets in probe. A probe
+ * now gets fed up of retrying without
+ * (even a no space) answer.
+ * Alan Cox : Extracted closing code better
+ * Alan Cox : Fixed the closing state machine to
+ * resemble the RFC.
+ * Alan Cox : More 'per spec' fixes.
+ * Jorge Cwik : Even faster checksumming.
+ * Alan Cox : tcp_data() doesn't ack illegal PSH
+ * only frames. At least one pc tcp stack
+ * generates them.
+ * Alan Cox : Cache last socket.
+ * Alan Cox : Per route irtt.
+ * Matt Day : poll()->select() match BSD precisely on error
+ * Alan Cox : New buffers
+ * Marc Tamsky : Various sk->prot->retransmits and
+ * sk->retransmits misupdating fixed.
+ * Fixed tcp_write_timeout: stuck close,
+ * and TCP syn retries gets used now.
+ * Mark Yarvis : In tcp_read_wakeup(), don't send an
+ * ack if state is TCP_CLOSED.
+ * Alan Cox : Look up device on a retransmit - routes may
+ * change. Doesn't yet cope with MSS shrink right
+ * but its a start!
+ * Marc Tamsky : Closing in closing fixes.
+ * Mike Shaver : RFC1122 verifications.
+ * Alan Cox : rcv_saddr errors.
+ * Alan Cox : Block double connect().
+ * Alan Cox : Small hooks for enSKIP.
+ * Alexey Kuznetsov: Path MTU discovery.
+ * Alan Cox : Support soft errors.
+ * Alan Cox : Fix MTU discovery pathological case
+ * when the remote claims no mtu!
+ * Marc Tamsky : TCP_CLOSE fix.
+ * Colin (G3TNE) : Send a reset on syn ack replies in
+ * window but wrong (fixes NT lpd problems)
+ * Pedro Roque : Better TCP window handling, delayed ack.
+ * Joerg Reuter : No modification of locked buffers in
+ * tcp_do_retransmit()
+ * Eric Schenk : Changed receiver side silly window
+ * avoidance algorithm to BSD style
+ * algorithm. This doubles throughput
+ * against machines running Solaris,
+ * and seems to result in general
+ * improvement.
+ * Stefan Magdalinski : adjusted tcp_readable() to fix FIONREAD
+ * Willy Konynenberg : Transparent proxying support.
+ * Mike McLagan : Routing by source
+ * Keith Owens : Do proper merging with partial SKB's in
+ * tcp_do_sendmsg to avoid burstiness.
+ * Eric Schenk : Fix fast close down bug with
+ * shutdown() followed by close().
+ * Andi Kleen : Make poll agree with SIGIO
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or(at your option) any later version.
+ *
+ * Description of States:
+ *
+ * TCP_SYN_SENT sent a connection request, waiting for ack
+ *
+ * TCP_SYN_RECV received a connection request, sent ack,
+ * waiting for final ack in three-way handshake.
+ *
+ * TCP_ESTABLISHED connection established
+ *
+ * TCP_FIN_WAIT1 our side has shutdown, waiting to complete
+ * transmission of remaining buffered data
+ *
+ * TCP_FIN_WAIT2 all buffered data sent, waiting for remote
+ * to shutdown
+ *
+ * TCP_CLOSING both sides have shutdown but we still have
+ * data we have to finish sending
+ *
+ * TCP_TIME_WAIT timeout to catch resent junk before entering
+ * closed, can only be entered from FIN_WAIT2
+ * or CLOSING. Required because the other end
+ * may not have gotten our last ACK causing it
+ * to retransmit the data packet (which we ignore)
+ *
+ * TCP_CLOSE_WAIT remote side has shutdown and is waiting for
+ * us to finish writing our data and to shutdown
+ * (we have to close() to move on to LAST_ACK)
+ *
+ * TCP_LAST_ACK out side has shutdown after remote has
+ * shutdown. There may still be data in our
+ * buffer that we have to finish sending
+ *
+ * TCP_CLOSE socket is finished
+ */
+
+/*
+ * RFC1122 status:
+ * NOTE: I'm not going to be doing comments in the code for this one except
+ * for violations and the like. tcp.c is just too big... If I say something
+ * "does?" or "doesn't?", it means I'm not sure, and will have to hash it out
+ * with Alan. -- MS 950903
+ * [Note: Most of the TCP code has been rewriten/redesigned since this
+ * RFC1122 check. It is probably not correct anymore. It should be redone
+ * before 2.2. -AK]
+ *
+ * Use of PSH (4.2.2.2)
+ * MAY aggregate data sent without the PSH flag. (does)
+ * MAY queue data received without the PSH flag. (does)
+ * SHOULD collapse successive PSH flags when it packetizes data. (doesn't)
+ * MAY implement PSH on send calls. (doesn't, thus:)
+ * MUST NOT buffer data indefinitely (doesn't [1 second])
+ * MUST set PSH on last segment (does)
+ * MAY pass received PSH to application layer (doesn't)
+ * SHOULD send maximum-sized segment whenever possible. (almost always does)
+ *
+ * Window Size (4.2.2.3, 4.2.2.16)
+ * MUST treat window size as an unsigned number (does)
+ * SHOULD treat window size as a 32-bit number (does not)
+ * MUST NOT shrink window once it is offered (does not normally)
+ *
+ * Urgent Pointer (4.2.2.4)
+ * **MUST point urgent pointer to last byte of urgent data (not right
+ * after). (doesn't, to be like BSD. That's configurable, but defaults
+ * to off)
+ * MUST inform application layer asynchronously of incoming urgent
+ * data. (does)
+ * MUST provide application with means of determining the amount of
+ * urgent data pending. (does)
+ * **MUST support urgent data sequence of arbitrary length. (doesn't, but
+ * it's sort of tricky to fix, as urg_ptr is a 16-bit quantity)
+ * [Follows BSD 1 byte of urgent data]
+ *
+ * TCP Options (4.2.2.5)
+ * MUST be able to receive TCP options in any segment. (does)
+ * MUST ignore unsupported options (does)
+ *
+ * Maximum Segment Size Option (4.2.2.6)
+ * MUST implement both sending and receiving MSS. (does, but currently
+ * only uses the smaller of both of them)
+ * SHOULD send an MSS with every SYN where receive MSS != 536 (MAY send
+ * it always). (does, even when MSS == 536, which is legal)
+ * MUST assume MSS == 536 if no MSS received at connection setup (does)
+ * MUST calculate "effective send MSS" correctly:
+ * min(physical_MTU, remote_MSS+20) - sizeof(tcphdr) - sizeof(ipopts)
+ * (does - but allows operator override)
+ *
+ * TCP Checksum (4.2.2.7)
+ * MUST generate and check TCP checksum. (does)
+ *
+ * Initial Sequence Number Selection (4.2.2.8)
+ * MUST use the RFC 793 clock selection mechanism. (doesn't, but it's
+ * OK: RFC 793 specifies a 250KHz clock, while we use 1MHz, which is
+ * necessary for 10Mbps networks - and harder than BSD to spoof!
+ * With syncookies we don't)
+ *
+ * Simultaneous Open Attempts (4.2.2.10)
+ * MUST support simultaneous open attempts (does)
+ *
+ * Recovery from Old Duplicate SYN (4.2.2.11)
+ * MUST keep track of active vs. passive open (does)
+ *
+ * RST segment (4.2.2.12)
+ * SHOULD allow an RST segment to contain data (does, but doesn't do
+ * anything with it, which is standard)
+ *
+ * Closing a Connection (4.2.2.13)
+ * MUST inform application of whether connection was closed by RST or
+ * normal close. (does)
+ * MAY allow "half-duplex" close (treat connection as closed for the
+ * local app, even before handshake is done). (does)
+ * MUST linger in TIME_WAIT for 2 * MSL (does)
+ *
+ * Retransmission Timeout (4.2.2.15)
+ * MUST implement Jacobson's slow start and congestion avoidance
+ * stuff. (does)
+ *
+ * Probing Zero Windows (4.2.2.17)
+ * MUST support probing of zero windows. (does)
+ * MAY keep offered window closed indefinitely. (does)
+ * MUST allow remote window to stay closed indefinitely. (does)
+ *
+ * Passive Open Calls (4.2.2.18)
+ * MUST NOT let new passive open affect other connections. (doesn't)
+ * MUST support passive opens (LISTENs) concurrently. (does)
+ *
+ * Time to Live (4.2.2.19)
+ * MUST make TCP TTL configurable. (does - IP_TTL option)
+ *
+ * Event Processing (4.2.2.20)
+ * SHOULD queue out-of-order segments. (does)
+ * MUST aggregate ACK segments whenever possible. (does but badly)
+ *
+ * Retransmission Timeout Calculation (4.2.3.1)
+ * MUST implement Karn's algorithm and Jacobson's algorithm for RTO
+ * calculation. (does, or at least explains them in the comments 8*b)
+ * SHOULD initialize RTO to 0 and RTT to 3. (does)
+ *
+ * When to Send an ACK Segment (4.2.3.2)
+ * SHOULD implement delayed ACK. (does)
+ * MUST keep ACK delay < 0.5 sec. (does)
+ *
+ * When to Send a Window Update (4.2.3.3)
+ * MUST implement receiver-side SWS. (does)
+ *
+ * When to Send Data (4.2.3.4)
+ * MUST implement sender-side SWS. (does)
+ * SHOULD implement Nagle algorithm. (does)
+ *
+ * TCP Connection Failures (4.2.3.5)
+ * MUST handle excessive retransmissions "properly" (see the RFC). (does)
+ * SHOULD inform application layer of soft errors. (does)
+ *
+ * TCP Keep-Alives (4.2.3.6)
+ * MAY provide keep-alives. (does)
+ * MUST make keep-alives configurable on a per-connection basis. (does)
+ * MUST default to no keep-alives. (does)
+ * MUST make keep-alive interval configurable. (does)
+ * MUST make default keep-alive interval > 2 hours. (does)
+ * MUST NOT interpret failure to ACK keep-alive packet as dead
+ * connection. (doesn't)
+ * SHOULD send keep-alive with no data. (does)
+ *
+ * TCP Multihoming (4.2.3.7)
+ * MUST get source address from IP layer before sending first
+ * SYN. (does)
+ * MUST use same local address for all segments of a connection. (does)
+ *
+ * IP Options (4.2.3.8)
+ * MUST ignore unsupported IP options. (does)
+ * MAY support Time Stamp and Record Route. (does)
+ * MUST allow application to specify a source route. (does)
+ * MUST allow received Source Route option to set route for all future
+ * segments on this connection. (does not (security issues))
+ *
+ * ICMP messages (4.2.3.9)
+ * MUST act on ICMP errors. (does)
+ * MUST slow transmission upon receipt of a Source Quench. (doesn't anymore
+ * because that is deprecated now by the IETF, can be turned on)
+ * MUST NOT abort connection upon receipt of soft Destination
+ * Unreachables (0, 1, 5), Time Exceededs and Parameter
+ * Problems. (doesn't)
+ * SHOULD report soft Destination Unreachables etc. to the
+ * application. (does, except during SYN_RECV and may drop messages
+ * in some rare cases before accept() - ICMP is unreliable)
+ * SHOULD abort connection upon receipt of hard Destination Unreachable
+ * messages (2, 3, 4). (does, but see above)
+ *
+ * Remote Address Validation (4.2.3.10)
+ * MUST reject as an error OPEN for invalid remote IP address. (does)
+ * MUST ignore SYN with invalid source address. (does)
+ * MUST silently discard incoming SYN for broadcast/multicast
+ * address. (does)
+ *
+ * Asynchronous Reports (4.2.4.1)
+ * MUST provide mechanism for reporting soft errors to application
+ * layer. (does)
+ *
+ * Type of Service (4.2.4.2)
+ * MUST allow application layer to set Type of Service. (does IP_TOS)
+ *
+ * (Whew. -- MS 950903)
+ * (Updated by AK, but not complete yet.)
+ **/
+
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#include <net/icmp.h>
+#include <net/tcp.h>
+
+#include <asm/uaccess.h>
+
+int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
+
+struct tcp_mib tcp_statistics;
+
+kmem_cache_t *tcp_openreq_cachep;
+kmem_cache_t *tcp_bucket_cachep;
+kmem_cache_t *tcp_timewait_cachep;
+
+/*
+ * Find someone to 'accept'. Must be called with
+ * the socket locked or with interrupts disabled
+ */
+
+static struct open_request *tcp_find_established(struct tcp_opt *tp,
+ struct open_request **prevp)
+{
+ struct open_request *req = tp->syn_wait_queue;
+ struct open_request *prev = (struct open_request *)&tp->syn_wait_queue;
+ while(req) {
+ if (req->sk &&
+ ((1 << req->sk->state) &
+ ~(TCPF_SYN_SENT|TCPF_SYN_RECV)))
+ break;
+ prev = req;
+ req = req->dl_next;
+ }
+ *prevp = prev;
+ return req;
+}
+
+/*
+ * Walk down the receive queue counting readable data.
+ *
+ * Must be called with the socket lock held.
+ */
+
+static int tcp_readable(struct sock *sk)
+{
+ unsigned long counted;
+ unsigned long amount;
+ struct sk_buff *skb;
+ int sum;
+
+ SOCK_DEBUG(sk, "tcp_readable: %p - ",sk);
+
+ skb = skb_peek(&sk->receive_queue);
+ if (skb == NULL) {
+ SOCK_DEBUG(sk, "empty\n");
+ return(0);
+ }
+
+ counted = sk->tp_pinfo.af_tcp.copied_seq; /* Where we are at the moment */
+ amount = 0;
+
+ /* Do until a push or until we are out of data. */
+ do {
+ /* Found a hole so stops here. */
+ if (before(counted, TCP_SKB_CB(skb)->seq)) /* should not happen */
+ break;
+
+ /* Length - header but start from where we are up to
+ * avoid overlaps.
+ */
+ sum = skb->len - (counted - TCP_SKB_CB(skb)->seq);
+ if (sum >= 0) {
+ /* Add it up, move on. */
+ amount += sum;
+ counted += sum;
+ if (skb->h.th->syn)
+ counted++;
+ }
+
+ /* Don't count urg data ... but do it in the right place!
+ * Consider: "old_data (ptr is here) URG PUSH data"
+ * The old code would stop at the first push because
+ * it counted the urg (amount==1) and then does amount--
+ * *after* the loop. This means tcp_readable() always
+ * returned zero if any URG PUSH was in the queue, even
+ * though there was normal data available. If we subtract
+ * the urg data right here, we even get it to work for more
+ * than one URG PUSH skb without normal data.
+ * This means that poll() finally works now with urg data
+ * in the queue. Note that rlogin was never affected
+ * because it doesn't use poll(); it uses two processes
+ * and a blocking read(). And the queue scan in tcp_read()
+ * was correct. Mike <pall@rz.uni-karlsruhe.de>
+ */
+
+ /* Don't count urg data. */
+ if (skb->h.th->urg)
+ amount--;
+#if 0
+ if (amount && skb->h.th->psh) break;
+#endif
+ skb = skb->next;
+ } while(skb != (struct sk_buff *)&sk->receive_queue);
+
+ SOCK_DEBUG(sk, "got %lu bytes.\n",amount);
+ return(amount);
+}
+
+/*
+ * LISTEN is a special case for poll..
+ */
+static unsigned int tcp_listen_poll(struct sock *sk, poll_table *wait)
+{
+ struct open_request *req, *dummy;
+
+ lock_sock(sk);
+ req = tcp_find_established(&sk->tp_pinfo.af_tcp, &dummy);
+ release_sock(sk);
+ if (req)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+/*
+ * Compute minimal free write space needed to queue new packets.
+ */
+#define tcp_min_write_space(__sk) \
+ (atomic_read(&(__sk)->wmem_alloc) / 2)
+
+/*
+ * Wait for a TCP event.
+ *
+ * Note that we don't need to lock the socket, as the upper poll layers
+ * take care of normal races (between the test and the event) and we don't
+ * go look at any of the socket buffers directly.
+ */
+unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
+{
+ unsigned int mask;
+ struct sock *sk = sock->sk;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ poll_wait(file, sk->sleep, wait);
+ if (sk->state == TCP_LISTEN)
+ return tcp_listen_poll(sk, wait);
+
+ mask = 0;
+ if (sk->err)
+ mask = POLLERR;
+
+ /*
+ * POLLHUP is certainly not done right. But poll() doesn't
+ * have a notion of HUP in just one direction, and for a
+ * socket the read side is more interesting.
+ *
+ * Some poll() documentation says that POLLHUP is incompatible
+ * with the POLLOUT/POLLWR flags, so somebody should check this
+ * all. But careful, it tends to be safer to return too many
+ * bits than too few, and you can easily break real applications
+ * if you don't tell them that something has hung up!
+ *
+ * Check-me.
+ */
+ if (sk->shutdown & RCV_SHUTDOWN)
+ mask |= POLLHUP;
+
+ /* Connected? */
+ if ((1 << sk->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
+ if ((tp->rcv_nxt != tp->copied_seq) &&
+ (tp->urg_seq != tp->copied_seq ||
+ tp->rcv_nxt != tp->copied_seq+1 ||
+ sk->urginline || !tp->urg_data))
+ mask |= POLLIN | POLLRDNORM;
+
+ if (!(sk->shutdown & SEND_SHUTDOWN)) {
+ if (sock_wspace(sk) >= tcp_min_write_space(sk)) {
+ mask |= POLLOUT | POLLWRNORM;
+ } else { /* send SIGIO later */
+ sk->socket->flags |= SO_NOSPACE;
+ }
+ }
+
+ if (tp->urg_data & URG_VALID)
+ mask |= POLLPRI;
+ }
+ return mask;
+}
+
+/*
+ * Socket write_space callback.
+ * This (or rather the sock_wake_async) should agree with poll.
+ */
+void tcp_write_space(struct sock *sk)
+{
+ if (sk->dead)
+ return;
+
+ wake_up_interruptible(sk->sleep);
+ if (sock_wspace(sk) >=
+ tcp_min_write_space(sk))
+ sock_wake_async(sk->socket, 2);
+}
+
+
+#ifdef _HURD_
+
+#define tcp_ioctl 0
+
+error_t
+tcp_tiocinq(struct sock *sk, mach_msg_type_number_t *amount)
+{
+ if (sk->state == TCP_LISTEN)
+ return EINVAL;
+ lock_sock(sk);
+ *amount = tcp_readable(sk);
+ release_sock(sk);
+ return 0;
+}
+
+#else
+
+int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+ int answ;
+
+ switch(cmd) {
+ case TIOCINQ:
+#ifdef FIXME /* FIXME: */
+ case FIONREAD:
+#endif
+ if (sk->state == TCP_LISTEN)
+ return(-EINVAL);
+ lock_sock(sk);
+ answ = tcp_readable(sk);
+ release_sock(sk);
+ break;
+ case SIOCATMARK:
+ {
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ answ = tp->urg_data && tp->urg_seq == tp->copied_seq;
+ break;
+ }
+ case TIOCOUTQ:
+ if (sk->state == TCP_LISTEN)
+ return(-EINVAL);
+ answ = sock_wspace(sk);
+ break;
+ default:
+ return(-ENOIOCTLCMD);
+ };
+
+ return put_user(answ, (int *)arg);
+}
+
+#endif
+
+/*
+ * Wait for a socket to get into the connected state
+ *
+ * Note: must be called with the socket locked.
+ */
+static int wait_for_tcp_connect(struct sock * sk, int flags)
+{
+ struct task_struct *tsk = current;
+ struct wait_queue wait = { tsk, NULL };
+
+ while((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
+ if(sk->err)
+ return sock_error(sk);
+ if((1 << sk->state) &
+ ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
+ if(sk->keepopen && !(flags&MSG_NOSIGNAL))
+ send_sig(SIGPIPE, tsk, 0);
+ return -EPIPE;
+ }
+ if(flags & MSG_DONTWAIT)
+ return -EAGAIN;
+ if(signal_pending(tsk))
+ return -ERESTARTSYS;
+
+ tsk->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(sk->sleep, &wait);
+ release_sock(sk);
+
+ if (((1 << sk->state) & ~(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT)) &&
+ sk->err == 0)
+ schedule();
+
+ tsk->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+ lock_sock(sk);
+ }
+ return 0;
+}
+
+static inline int tcp_memory_free(struct sock *sk)
+{
+ return atomic_read(&sk->wmem_alloc) < sk->sndbuf;
+}
+
+/*
+ * Wait for more memory for a socket
+ */
+static void wait_for_tcp_memory(struct sock * sk)
+{
+ release_sock(sk);
+ if (!tcp_memory_free(sk)) {
+ struct wait_queue wait = { current, NULL };
+
+ sk->socket->flags &= ~SO_NOSPACE;
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ if (signal_pending(current))
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ if (tcp_memory_free(sk))
+ break;
+ if (sk->shutdown & SEND_SHUTDOWN)
+ break;
+ if (sk->err)
+ break;
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+ }
+ lock_sock(sk);
+}
+
+/*
+ * Wait for a buffer.
+ */
+static int wait_for_buffer(struct sock *sk)
+{
+ struct wait_queue wait = { current, NULL };
+
+ release_sock(sk);
+ add_wait_queue(sk->sleep, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+ lock_sock(sk);
+ return 0;
+}
+
+/* When all user supplied data has been queued set the PSH bit */
+#define PSH_NEEDED (seglen == 0 && iovlen == 0)
+
+/*
+ * This routine copies from a user buffer into a socket,
+ * and starts the transmit system.
+ *
+ * Note: must be called with the socket locked.
+ */
+
+int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg)
+{
+ struct iovec *iov;
+ struct tcp_opt *tp;
+ struct sk_buff *skb;
+ int iovlen, flags;
+ int mss_now;
+ int err, copied;
+
+ lock_sock(sk);
+
+ err = 0;
+ tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Wait for a connection to finish. */
+ flags = msg->msg_flags;
+ if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
+ if((err = wait_for_tcp_connect(sk, flags)) != 0)
+ goto out;
+
+ /* This should be in poll */
+ sk->socket->flags &= ~SO_NOSPACE; /* clear SIGIO XXX */
+
+ mss_now = tcp_current_mss(sk);
+
+ /* Ok commence sending. */
+ iovlen = msg->msg_iovlen;
+ iov = msg->msg_iov;
+ copied = 0;
+
+ while(--iovlen >= 0) {
+ int seglen=iov->iov_len;
+ unsigned char * from=iov->iov_base;
+
+ iov++;
+
+ while(seglen > 0) {
+ int copy, tmp, queue_it, psh;
+
+ if (err)
+ goto do_fault2;
+
+ /* Stop on errors. */
+ if (sk->err)
+ goto do_sock_err;
+
+ /* Make sure that we are established. */
+ if (sk->shutdown & SEND_SHUTDOWN)
+ goto do_shutdown;
+
+ /* Now we need to check if we have a half
+ * built packet we can tack some data onto.
+ */
+ if (tp->send_head && !(flags & MSG_OOB)) {
+ skb = sk->write_queue.prev;
+ copy = skb->len;
+ /* If the remote does SWS avoidance we should
+ * queue the best we can if not we should in
+ * fact send multiple packets...
+ * A method for detecting this would be most
+ * welcome.
+ */
+ if (skb_tailroom(skb) > 0 &&
+ (mss_now - copy) > 0 &&
+ tp->snd_nxt < TCP_SKB_CB(skb)->end_seq) {
+ int last_byte_was_odd = (copy % 4);
+
+ /*
+ * Check for parallel writers sleeping in user access.
+ */
+ if (tp->partial_writers++ > 0) {
+ wait_for_buffer(sk);
+ tp->partial_writers--;
+ continue;
+ }
+
+ copy = mss_now - copy;
+ if(copy > skb_tailroom(skb))
+ copy = skb_tailroom(skb);
+ if(copy > seglen)
+ copy = seglen;
+
+ if(last_byte_was_odd) {
+ if(copy_from_user(skb_put(skb, copy),
+ from, copy))
+ err = -EFAULT;
+ skb->csum = csum_partial(skb->data,
+ skb->len, 0);
+ } else {
+ skb->csum =
+ csum_and_copy_from_user(
+ from, skb_put(skb, copy),
+ copy, skb->csum, &err);
+ }
+
+ /*
+ * FIXME: the *_user functions should
+ * return how much data was
+ * copied before the fault
+ * occurred and then a partial
+ * packet with this data should
+ * be sent. Unfortunately
+ * csum_and_copy_from_user doesn't
+ * return this information.
+ * ATM it might send partly zeroed
+ * data in this case.
+ */
+ tp->write_seq += copy;
+ TCP_SKB_CB(skb)->end_seq += copy;
+ from += copy;
+ copied += copy;
+ seglen -= copy;
+ if (PSH_NEEDED)
+ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
+
+ if (--tp->partial_writers > 0)
+ wake_up_interruptible(sk->sleep);
+
+ continue;
+ }
+ }
+
+ /* We also need to worry about the window. If
+ * window < 1/2 the maximum window we've seen
+ * from this host, don't use it. This is
+ * sender side silly window prevention, as
+ * specified in RFC1122. (Note that this is
+ * different than earlier versions of SWS
+ * prevention, e.g. RFC813.). What we
+ * actually do is use the whole MSS. Since
+ * the results in the right edge of the packet
+ * being outside the window, it will be queued
+ * for later rather than sent.
+ */
+ psh = 0;
+ copy = tp->snd_wnd - (tp->snd_nxt - tp->snd_una);
+ if(copy > (tp->max_window >> 1)) {
+ copy = min(copy, mss_now);
+ psh = 1;
+ } else {
+ copy = mss_now;
+ }
+ if(copy > seglen)
+ copy = seglen;
+
+ /* Determine how large of a buffer to allocate. */
+ tmp = MAX_HEADER + sk->prot->max_header;
+ if (copy < min(mss_now, tp->max_window >> 1) &&
+ !(flags & MSG_OOB)) {
+ tmp += min(mss_now, tp->max_window);
+
+ /* What is happening here is that we want to
+ * tack on later members of the users iovec
+ * if possible into a single frame. When we
+ * leave this loop our caller checks to see if
+ * we can send queued frames onto the wire.
+ * See tcp_v[46]_sendmsg() for this.
+ */
+ queue_it = 1;
+ } else {
+ tmp += copy;
+ queue_it = 0;
+ }
+ skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
+
+ /* If we didn't get any memory, we need to sleep. */
+ if (skb == NULL) {
+ sk->socket->flags |= SO_NOSPACE;
+ if (flags&MSG_DONTWAIT) {
+ err = -EAGAIN;
+ goto do_interrupted;
+ }
+ if (signal_pending(current)) {
+ err = -ERESTARTSYS;
+ goto do_interrupted;
+ }
+ tcp_push_pending_frames(sk, tp);
+ wait_for_tcp_memory(sk);
+
+ /* If SACK's were formed or PMTU events happened,
+ * we must find out about it.
+ */
+ mss_now = tcp_current_mss(sk);
+ continue;
+ }
+
+ seglen -= copy;
+
+ /* Prepare control bits for TCP header creation engine. */
+ TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK |
+ ((PSH_NEEDED || psh) ?
+ TCPCB_FLAG_PSH : 0));
+ TCP_SKB_CB(skb)->sacked = 0;
+ if (flags & MSG_OOB) {
+ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_URG;
+ TCP_SKB_CB(skb)->urg_ptr = copy;
+ } else
+ TCP_SKB_CB(skb)->urg_ptr = 0;
+
+ /* TCP data bytes are SKB_PUT() on top, later
+ * TCP+IP+DEV headers are SKB_PUSH()'d beneath.
+ * Reserve header space and checksum the data.
+ */
+ skb_reserve(skb, MAX_HEADER + sk->prot->max_header);
+ skb->csum = csum_and_copy_from_user(from,
+ skb_put(skb, copy), copy, 0, &err);
+
+ if (err)
+ goto do_fault;
+
+ from += copy;
+ copied += copy;
+
+ TCP_SKB_CB(skb)->seq = tp->write_seq;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + copy;
+
+ /* This advances tp->write_seq for us. */
+ tcp_send_skb(sk, skb, queue_it);
+ }
+ }
+ sk->err = 0;
+ err = copied;
+ goto out;
+
+do_sock_err:
+ if(copied)
+ err = copied;
+ else
+ err = sock_error(sk);
+ goto out;
+do_shutdown:
+ if(copied)
+ err = copied;
+ else {
+ if (!(flags&MSG_NOSIGNAL))
+ send_sig(SIGPIPE, current, 0);
+ err = -EPIPE;
+ }
+ goto out;
+do_interrupted:
+ if(copied)
+ err = copied;
+ goto out;
+do_fault:
+ kfree_skb(skb);
+do_fault2:
+ err = -EFAULT;
+out:
+ tcp_push_pending_frames(sk, tp);
+ release_sock(sk);
+ return err;
+}
+
+#undef PSH_NEEDED
+
+/*
+ * Send an ack if one is backlogged at this point. Ought to merge
+ * this with tcp_send_ack().
+ * This is called for delayed acks also.
+ */
+
+void tcp_read_wakeup(struct sock *sk)
+{
+ /* If we're closed, don't send an ack, or we'll get a RST
+ * from the closed destination.
+ */
+ if (sk->state != TCP_CLOSE)
+ tcp_send_ack(sk);
+}
+
+/*
+ * Handle reading urgent data. BSD has very simple semantics for
+ * this, no blocking and very strange errors 8)
+ */
+
+static int tcp_recv_urg(struct sock * sk, int nonblock,
+ struct msghdr *msg, int len, int flags,
+ int *addr_len)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* No URG data to read. */
+ if (sk->urginline || !tp->urg_data || tp->urg_data == URG_READ)
+ return -EINVAL; /* Yes this is right ! */
+
+ if (sk->err)
+ return sock_error(sk);
+
+ if (sk->done)
+ return -ENOTCONN;
+
+ if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) {
+ sk->done = 1;
+ return 0;
+ }
+
+ lock_sock(sk);
+ if (tp->urg_data & URG_VALID) {
+ int err = 0;
+ char c = tp->urg_data;
+
+ if (!(flags & MSG_PEEK))
+ tp->urg_data = URG_READ;
+
+ if(msg->msg_name)
+ tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)
+ msg->msg_name);
+
+ if(addr_len)
+ *addr_len = tp->af_specific->sockaddr_len;
+
+ /* Read urgent data. */
+ msg->msg_flags|=MSG_OOB;
+ release_sock(sk);
+
+ if(len>0)
+ {
+ err = memcpy_toiovec(msg->msg_iov, &c, 1);
+ /* N.B. already set above ... */
+ msg->msg_flags|=MSG_OOB;
+ }
+ else
+ msg->msg_flags|=MSG_TRUNC;
+
+ /* N.B. Is this right?? If len == 0 we didn't read any data */
+ return err ? -EFAULT : 1;
+ }
+ release_sock(sk);
+
+ /* Fixed the recv(..., MSG_OOB) behaviour. BSD docs and
+ * the available implementations agree in this case:
+ * this call should never block, independent of the
+ * blocking state of the socket.
+ * Mike <pall@rz.uni-karlsruhe.de>
+ */
+ return -EAGAIN;
+}
+
+/*
+ * Release a skb if it is no longer needed. This routine
+ * must be called with interrupts disabled or with the
+ * socket locked so that the sk_buff queue operation is ok.
+ */
+
+static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb)
+{
+ __skb_unlink(skb, &sk->receive_queue);
+ kfree_skb(skb);
+}
+
+/* Clean up the receive buffer for full frames taken by the user,
+ * then send an ACK if necessary. COPIED is the number of bytes
+ * tcp_recvmsg has given to the user so far, it speeds up the
+ * calculation of whether or not we must ACK for the sake of
+ * a window update.
+ */
+static void cleanup_rbuf(struct sock *sk, int copied)
+{
+ struct sk_buff *skb;
+
+ /* NOTE! The socket must be locked, so that we don't get
+ * a messed-up receive queue.
+ */
+ while ((skb=skb_peek(&sk->receive_queue)) != NULL) {
+ if (!skb->used || atomic_read(&skb->users) > 1)
+ break;
+ tcp_eat_skb(sk, skb);
+ }
+
+ /* We send an ACK if we can now advertise a non-zero window
+ * which has been raised "significantly".
+ */
+ if(copied > 0) {
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ __u32 rcv_window_now = tcp_receive_window(tp);
+ __u32 new_window = __tcp_select_window(sk);
+
+ /* We won't be raising the window any further than
+ * the window-clamp allows. Our window selection
+ * also keeps things a nice multiple of MSS. These
+ * checks are necessary to prevent spurious ACKs
+ * which don't advertize a larger window.
+ */
+ if((new_window && (new_window >= rcv_window_now * 2)) &&
+ ((rcv_window_now + tp->mss_cache) <= tp->window_clamp))
+ tcp_read_wakeup(sk);
+ }
+}
+
+
+/*
+ * This routine copies from a sock struct into the user buffer.
+ */
+
+int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
+ int len, int nonblock, int flags, int *addr_len)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct wait_queue wait = { current, NULL };
+ int copied = 0;
+ u32 peek_seq;
+ volatile u32 *seq; /* So gcc doesn't overoptimise */
+ unsigned long used;
+ int err = 0;
+ int target = 1; /* Read at least this many bytes */
+
+ if (sk->err)
+ return sock_error(sk);
+
+ if (sk->state == TCP_LISTEN)
+ return -ENOTCONN;
+
+ /* Urgent data needs to be handled specially. */
+ if (flags & MSG_OOB)
+ return tcp_recv_urg(sk, nonblock, msg, len, flags, addr_len);
+
+ /* Copying sequence to update. This is volatile to handle
+ * the multi-reader case neatly (memcpy_to/fromfs might be
+ * inline and thus not flush cached variables otherwise).
+ */
+ peek_seq = tp->copied_seq;
+ seq = &tp->copied_seq;
+ if (flags & MSG_PEEK)
+ seq = &peek_seq;
+
+ /* Handle the POSIX bogosity MSG_WAITALL. */
+ if (flags & MSG_WAITALL)
+ target=len;
+
+ add_wait_queue(sk->sleep, &wait);
+ lock_sock(sk);
+
+ /*
+ * BUG BUG BUG
+ * This violates 1003.1g compliance. We must wait for
+ * data to exist even if we read none!
+ */
+
+ while (len > 0) {
+ struct sk_buff * skb;
+ u32 offset;
+
+ /* Are we at urgent data? Stop if we have read anything. */
+ if (copied && tp->urg_data && tp->urg_seq == *seq)
+ break;
+
+ /* We need to check signals first, to get correct SIGURG
+ * handling. FIXME: Need to check this doesn't impact 1003.1g
+ * and move it down to the bottom of the loop
+ */
+ if (signal_pending(current)) {
+ if (copied)
+ break;
+ copied = -ERESTARTSYS;
+ if (nonblock)
+ copied = -EAGAIN;
+ break;
+ }
+
+ /* Next get a buffer. */
+ current->state = TASK_INTERRUPTIBLE;
+
+ skb = skb_peek(&sk->receive_queue);
+ do {
+ if (!skb)
+ break;
+
+ /* Now that we have two receive queues this
+ * shouldn't happen.
+ */
+ if (before(*seq, TCP_SKB_CB(skb)->seq)) {
+ printk(KERN_INFO "recvmsg bug: copied %X seq %X\n",
+ *seq, TCP_SKB_CB(skb)->seq);
+ break;
+ }
+ offset = *seq - TCP_SKB_CB(skb)->seq;
+ if (skb->h.th->syn)
+ offset--;
+ if (offset < skb->len)
+ goto found_ok_skb;
+ if (skb->h.th->fin)
+ goto found_fin_ok;
+ if (!(flags & MSG_PEEK))
+ skb->used = 1;
+ skb = skb->next;
+ } while (skb != (struct sk_buff *)&sk->receive_queue);
+
+ if (copied >= target)
+ break;
+
+ /*
+ These three lines and clause if (sk->state == TCP_CLOSE)
+ are unlikely to be correct, if target > 1.
+ I DO NOT FIX IT, because I have no idea, what
+ POSIX prescribes to make here. Probably, it really
+ wants to lose data 8), if not all target is received.
+ --ANK
+ */
+ if (sk->err && !(flags&MSG_PEEK)) {
+ copied = sock_error(sk);
+ break;
+ }
+
+ if (sk->shutdown & RCV_SHUTDOWN) {
+ sk->done = 1;
+ break;
+ }
+
+ if (sk->state == TCP_CLOSE) {
+ if (!sk->done) {
+ sk->done = 1;
+ break;
+ }
+ copied = -ENOTCONN;
+ break;
+ }
+
+ if (nonblock) {
+ copied = -EAGAIN;
+ break;
+ }
+
+ cleanup_rbuf(sk, copied);
+ release_sock(sk);
+ sk->socket->flags |= SO_WAITDATA;
+ schedule();
+ sk->socket->flags &= ~SO_WAITDATA;
+ lock_sock(sk);
+ continue;
+
+ found_ok_skb:
+ /* Lock the buffer. We can be fairly relaxed as
+ * an interrupt will never steal a buffer we are
+ * using unless I've missed something serious in
+ * tcp_data.
+ */
+ atomic_inc(&skb->users);
+
+ /* Ok so how much can we use? */
+ used = skb->len - offset;
+ if (len < used)
+ used = len;
+
+ /* Do we have urgent data here? */
+ if (tp->urg_data) {
+ u32 urg_offset = tp->urg_seq - *seq;
+ if (urg_offset < used) {
+ if (!urg_offset) {
+ if (!sk->urginline) {
+ ++*seq;
+ offset++;
+ used--;
+ }
+ } else
+ used = urg_offset;
+ }
+ }
+
+ /* Copy it - We _MUST_ update *seq first so that we
+ * don't ever double read when we have dual readers
+ */
+ *seq += used;
+
+ /* This memcpy_toiovec can sleep. If it sleeps and we
+ * do a second read it relies on the skb->users to avoid
+ * a crash when cleanup_rbuf() gets called.
+ */
+ err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
+ if (err) {
+ /* Exception. Bailout! */
+ atomic_dec(&skb->users);
+ copied = -EFAULT;
+ break;
+ }
+
+ copied += used;
+ len -= used;
+
+ /* We now will not sleep again until we are finished
+ * with skb. Sorry if you are doing the SMP port
+ * but you'll just have to fix it neatly ;)
+ */
+ atomic_dec(&skb->users);
+
+ if (after(tp->copied_seq,tp->urg_seq))
+ tp->urg_data = 0;
+ if (used + offset < skb->len)
+ continue;
+
+ /* Process the FIN. We may also need to handle PSH
+ * here and make it break out of MSG_WAITALL.
+ */
+ if (skb->h.th->fin)
+ goto found_fin_ok;
+ if (flags & MSG_PEEK)
+ continue;
+ skb->used = 1;
+ if (atomic_read(&skb->users) == 1)
+ tcp_eat_skb(sk, skb);
+ continue;
+
+ found_fin_ok:
+ ++*seq;
+ if (flags & MSG_PEEK)
+ break;
+
+ /* All is done. */
+ skb->used = 1;
+ sk->shutdown |= RCV_SHUTDOWN;
+ break;
+ }
+
+ if(copied >= 0 && msg->msg_name) {
+ tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)
+ msg->msg_name);
+ if(addr_len)
+ *addr_len = tp->af_specific->sockaddr_len;
+ }
+
+ remove_wait_queue(sk->sleep, &wait);
+ current->state = TASK_RUNNING;
+
+ /* Clean up data we have read: This will do ACK frames. */
+ cleanup_rbuf(sk, copied);
+ release_sock(sk);
+ return copied;
+}
+
+/*
+ * Check whether to renew the timer.
+ */
+static inline void tcp_check_fin_timer(struct sock *sk)
+{
+ if (sk->state == TCP_FIN_WAIT2 && !sk->timer.prev)
+ tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+}
+
+/*
+ * State processing on a close. This implements the state shift for
+ * sending our FIN frame. Note that we only send a FIN for some
+ * states. A shutdown() may have already sent the FIN, or we may be
+ * closed.
+ */
+
+static unsigned char new_state[16] = {
+ /* current state: new state: action: */
+ /* (Invalid) */ TCP_CLOSE,
+ /* TCP_ESTABLISHED */ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
+ /* TCP_SYN_SENT */ TCP_CLOSE,
+ /* TCP_SYN_RECV */ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
+ /* TCP_FIN_WAIT1 */ TCP_FIN_WAIT1,
+ /* TCP_FIN_WAIT2 */ TCP_FIN_WAIT2,
+ /* TCP_TIME_WAIT */ TCP_CLOSE,
+ /* TCP_CLOSE */ TCP_CLOSE,
+ /* TCP_CLOSE_WAIT */ TCP_LAST_ACK | TCP_ACTION_FIN,
+ /* TCP_LAST_ACK */ TCP_LAST_ACK,
+ /* TCP_LISTEN */ TCP_CLOSE,
+ /* TCP_CLOSING */ TCP_CLOSING,
+};
+
+static int tcp_close_state(struct sock *sk, int dead)
+{
+ int next = (int) new_state[sk->state];
+ int ns = (next & TCP_STATE_MASK);
+
+ tcp_set_state(sk, ns);
+
+ /* This is a (useful) BSD violating of the RFC. There is a
+ * problem with TCP as specified in that the other end could
+ * keep a socket open forever with no application left this end.
+ * We use a 3 minute timeout (about the same as BSD) then kill
+ * our end. If they send after that then tough - BUT: long enough
+ * that we won't make the old 4*rto = almost no time - whoops
+ * reset mistake.
+ */
+ if (dead)
+ tcp_check_fin_timer(sk);
+
+ return (next & TCP_ACTION_FIN);
+}
+
+/*
+ * Shutdown the sending side of a connection. Much like close except
+ * that we don't receive shut down or set sk->dead.
+ */
+
+void tcp_shutdown(struct sock *sk, int how)
+{
+ /* We need to grab some memory, and put together a FIN,
+ * and then put it into the queue to be sent.
+ * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92.
+ */
+ if (!(how & SEND_SHUTDOWN))
+ return;
+
+ /* If we've already sent a FIN, or it's a closed state, skip this. */
+ if ((1 << sk->state) &
+ (TCPF_ESTABLISHED|TCPF_SYN_SENT|TCPF_SYN_RECV|TCPF_CLOSE_WAIT)) {
+ lock_sock(sk);
+
+ /* Clear out any half completed packets. FIN if needed. */
+ if (tcp_close_state(sk,0))
+ tcp_send_fin(sk);
+
+ release_sock(sk);
+ }
+}
+
+
+/*
+ * Return 1 if we still have things to send in our buffers.
+ */
+
+static inline int closing(struct sock * sk)
+{
+ return ((1 << sk->state) & (TCPF_FIN_WAIT1|TCPF_CLOSING|TCPF_LAST_ACK));
+}
+
+/*
+ * This routine closes sockets which have been at least partially
+ * opened, but not yet accepted. Currently it is only called by
+ * tcp_close, and timeout mirrors the value there.
+ */
+
+static void tcp_close_pending (struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct open_request *req = tp->syn_wait_queue;
+
+ while(req) {
+ struct open_request *iter;
+
+ if (req->sk)
+ tcp_close(req->sk, 0);
+
+ iter = req;
+ req = req->dl_next;
+
+ (*iter->class->destructor)(iter);
+ tcp_dec_slow_timer(TCP_SLT_SYNACK);
+ sk->ack_backlog--;
+ tcp_openreq_free(iter);
+ }
+
+ tcp_synq_init(tp);
+}
+
+void tcp_close(struct sock *sk, long timeout)
+{
+ struct sk_buff *skb;
+ int data_was_unread = 0;
+
+ /*
+ * Check whether the socket is locked ... supposedly
+ * it's impossible to tcp_close() a locked socket.
+ */
+ if (atomic_read(&sk->sock_readers))
+ printk("tcp_close: socket already locked!\n");
+
+ /* We need to grab some memory, and put together a FIN,
+ * and then put it into the queue to be sent.
+ */
+ lock_sock(sk);
+ if(sk->state == TCP_LISTEN) {
+ /* Special case. */
+ tcp_set_state(sk, TCP_CLOSE);
+ tcp_close_pending(sk);
+ release_sock(sk);
+ sk->dead = 1;
+ return;
+ }
+
+ /* It is questionable, what the role of this is now.
+ * In any event either it should be removed, or
+ * increment of SLT_KEEPALIVE be done, this is causing
+ * big problems. For now I comment it out. -DaveM
+ */
+ /* sk->keepopen = 1; */
+ sk->shutdown = SHUTDOWN_MASK;
+
+ if (!sk->dead)
+ sk->state_change(sk);
+
+ /* We need to flush the recv. buffs. We do this only on the
+ * descriptor close, not protocol-sourced closes, because the
+ * reader process may not have drained the data yet!
+ */
+ while((skb=__skb_dequeue(&sk->receive_queue))!=NULL) {
+ u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin;
+ data_was_unread += len;
+ kfree_skb(skb);
+ }
+
+ /* As outlined in draft-ietf-tcpimpl-prob-03.txt, section
+ * 3.10, we send a RST here because data was lost. To
+ * witness the awful effects of the old behavior of always
+ * doing a FIN, run an older 2.1.x kernel or 2.0.x, start
+ * a bulk GET in an FTP client, suspend the process, wait
+ * for the client to advertise a zero window, then kill -9
+ * the FTP client, wheee... Note: timeout is always zero
+ * in such a case.
+ */
+ if(data_was_unread != 0) {
+ /* Unread data was tossed, zap the connection. */
+ tcp_set_state(sk, TCP_CLOSE);
+ tcp_send_active_reset(sk);
+ } else if (tcp_close_state(sk,1)) {
+ /* We FIN if the application ate all the data before
+ * zapping the connection.
+ */
+ tcp_send_fin(sk);
+ }
+
+ if (timeout) {
+ struct task_struct *tsk = current;
+ struct wait_queue wait = { tsk, NULL };
+
+ add_wait_queue(sk->sleep, &wait);
+ release_sock(sk);
+
+ while (1) {
+ tsk->state = TASK_INTERRUPTIBLE;
+ if (!closing(sk))
+ break;
+ timeout = schedule_timeout(timeout);
+ if (signal_pending(tsk) || !timeout)
+ break;
+ }
+
+ tsk->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+
+ lock_sock(sk);
+ }
+
+ /* Now that the socket is dead, if we are in the FIN_WAIT2 state
+ * we may need to set up a timer.
+ */
+ tcp_check_fin_timer(sk);
+
+ release_sock(sk);
+ sk->dead = 1;
+}
+
+/*
+ * Wait for an incoming connection, avoid race
+ * conditions. This must be called with the socket locked.
+ */
+static struct open_request * wait_for_connect(struct sock * sk,
+ struct open_request **pprev)
+{
+ struct wait_queue wait = { current, NULL };
+ struct open_request *req;
+
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ release_sock(sk);
+ schedule();
+ lock_sock(sk);
+ req = tcp_find_established(&(sk->tp_pinfo.af_tcp), pprev);
+ if (req)
+ break;
+ if (signal_pending(current))
+ break;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+ return req;
+}
+
+/*
+ * This will accept the next outstanding connection.
+ *
+ * Be careful about race conditions here - this is subtle.
+ */
+
+struct sock *tcp_accept(struct sock *sk, int flags)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct open_request *req, *prev;
+ struct sock *newsk = NULL;
+ int error;
+
+ lock_sock(sk);
+
+ /* We need to make sure that this socket is listening,
+ * and that it has something pending.
+ */
+ error = EINVAL;
+ if (sk->state != TCP_LISTEN)
+ goto out;
+
+ /* Find already established connection */
+ req = tcp_find_established(tp, &prev);
+ if (!req) {
+ /* If this is a non blocking socket don't sleep */
+ error = EAGAIN;
+ if (flags & O_NONBLOCK)
+ goto out;
+
+ error = ERESTARTSYS;
+ req = wait_for_connect(sk, &prev);
+ if (!req)
+ goto out;
+ }
+
+ tcp_synq_unlink(tp, req, prev);
+ newsk = req->sk;
+ req->class->destructor(req);
+ tcp_openreq_free(req);
+ sk->ack_backlog--;
+ if(sk->keepopen)
+ tcp_inc_slow_timer(TCP_SLT_KEEPALIVE);
+
+ release_sock(sk);
+ return newsk;
+
+out:
+ /* sk should be in LISTEN state, thus accept can use sk->err for
+ * internal purposes without stomping one anyone's feed.
+ */
+ sk->err = error;
+ release_sock(sk);
+ return newsk;
+}
+
+/*
+ * Socket option code for TCP.
+ */
+
+int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval,
+ int optlen)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int val;
+
+ if (level != SOL_TCP)
+ return tp->af_specific->setsockopt(sk, level, optname,
+ optval, optlen);
+
+ if(optlen<sizeof(int))
+ return -EINVAL;
+
+ if (get_user(val, (int *)optval))
+ return -EFAULT;
+
+ switch(optname) {
+ case TCP_MAXSEG:
+ /* values greater than interface MTU won't take effect. however at
+ * the point when this call is done we typically don't yet know
+ * which interface is going to be used
+ */
+ if(val < 1 || val > MAX_WINDOW)
+ return -EINVAL;
+ tp->user_mss = val;
+ return 0;
+
+ case TCP_NODELAY:
+ /* You cannot try to use this and TCP_CORK in
+ * tandem, so let the user know.
+ */
+ if (sk->nonagle == 2)
+ return -EINVAL;
+ sk->nonagle = (val == 0) ? 0 : 1;
+ return 0;
+
+ case TCP_CORK:
+ /* When set indicates to always queue non-full frames.
+ * Later the user clears this option and we transmit
+ * any pending partial frames in the queue. This is
+ * meant to be used alongside sendfile() to get properly
+ * filled frames when the user (for example) must write
+ * out headers with a write() call first and then use
+ * sendfile to send out the data parts.
+ *
+ * You cannot try to use TCP_NODELAY and this mechanism
+ * at the same time, so let the user know.
+ */
+ if (sk->nonagle == 1)
+ return -EINVAL;
+ if (val != 0) {
+ sk->nonagle = 2;
+ } else {
+ sk->nonagle = 0;
+
+ lock_sock(sk);
+ tcp_push_pending_frames(sk, tp);
+ release_sock(sk);
+ }
+ return 0;
+
+ default:
+ return -ENOPROTOOPT;
+ };
+}
+
+int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval,
+ int *optlen)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int val, len;
+
+ if(level != SOL_TCP)
+ return tp->af_specific->getsockopt(sk, level, optname,
+ optval, optlen);
+
+ if(get_user(len,optlen))
+ return -EFAULT;
+
+ len = min(len, sizeof(int));
+
+ switch(optname) {
+ case TCP_MAXSEG:
+ val = tp->user_mss;
+ break;
+ case TCP_NODELAY:
+ val = (sk->nonagle == 1);
+ break;
+ case TCP_CORK:
+ val = (sk->nonagle == 2);
+ break;
+ default:
+ return -ENOPROTOOPT;
+ };
+
+ if(put_user(len, optlen))
+ return -EFAULT;
+ if(copy_to_user(optval, &val,len))
+ return -EFAULT;
+ return 0;
+}
+
+void tcp_set_keepalive(struct sock *sk, int val)
+{
+ if (!sk->keepopen && val)
+ tcp_inc_slow_timer(TCP_SLT_KEEPALIVE);
+ else if (sk->keepopen && !val)
+ tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
+}
+
+extern void __skb_cb_too_small_for_tcp(int, int);
+
+void __init tcp_init(void)
+{
+ struct sk_buff *skb = NULL;
+ unsigned long goal;
+ int order;
+
+ if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
+ __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
+ sizeof(skb->cb));
+
+ tcp_openreq_cachep = kmem_cache_create("tcp_open_request",
+ sizeof(struct open_request),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if(!tcp_openreq_cachep)
+ panic("tcp_init: Cannot alloc open_request cache.");
+
+ tcp_bucket_cachep = kmem_cache_create("tcp_bind_bucket",
+ sizeof(struct tcp_bind_bucket),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if(!tcp_bucket_cachep)
+ panic("tcp_init: Cannot alloc tcp_bind_bucket cache.");
+
+ tcp_timewait_cachep = kmem_cache_create("tcp_tw_bucket",
+ sizeof(struct tcp_tw_bucket),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if(!tcp_timewait_cachep)
+ panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
+
+ /* Size and allocate TCP hash tables. */
+ goal = num_physpages >> (20 - PAGE_SHIFT);
+ for (order = 0; (1UL << order) < goal; order++)
+ ;
+ do {
+ tcp_ehash_size = (1UL << order) * PAGE_SIZE /
+ sizeof(struct sock *);
+ tcp_ehash = (struct sock **)
+ __get_free_pages(GFP_ATOMIC, order);
+ } while (tcp_ehash == NULL && --order >= 0);
+
+ if (!tcp_ehash)
+ panic("Failed to allocate TCP established hash table\n");
+ memset(tcp_ehash, 0, tcp_ehash_size * sizeof(struct sock *));
+
+ goal = (((1UL << order) * PAGE_SIZE) / sizeof(struct tcp_bind_bucket *));
+ if (goal > (64 * 1024)) {
+ /* Don't size the bind-hash larger than the port
+ * space, that is just silly.
+ */
+ goal = (((64 * 1024) * sizeof(struct tcp_bind_bucket *)) / PAGE_SIZE);
+ for (order = 0; (1UL << order) < goal; order++)
+ ;
+ }
+
+ do {
+ tcp_bhash_size = (1UL << order) * PAGE_SIZE /
+ sizeof(struct tcp_bind_bucket *);
+ tcp_bhash = (struct tcp_bind_bucket **)
+ __get_free_pages(GFP_ATOMIC, order);
+ } while (tcp_bhash == NULL && --order >= 0);
+
+ if (!tcp_bhash)
+ panic("Failed to allocate TCP bind hash table\n");
+ memset(tcp_bhash, 0, tcp_bhash_size * sizeof(struct tcp_bind_bucket *));
+
+ printk("TCP: Hash tables configured (ehash %d bhash %d)\n",
+ tcp_ehash_size, tcp_bhash_size);
+}
diff --git a/pfinet/linux-src/net/ipv4/tcp_input.c b/pfinet/linux-src/net/ipv4/tcp_input.c
new file mode 100644
index 00000000..e84eaf43
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/tcp_input.c
@@ -0,0 +1,2432 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Implementation of the Transmission Control Protocol(TCP).
+ *
+ * Version: $Id: tcp_input.c,v 1.164.2.8 1999/09/23 19:21:23 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ * Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
+ * Linus Torvalds, <torvalds@cs.helsinki.fi>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Matthew Dillon, <dillon@apollo.west.oic.com>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Jorge Cwik, <jorge@laser.satlink.net>
+ */
+
+/*
+ * Changes:
+ * Pedro Roque : Fast Retransmit/Recovery.
+ * Two receive queues.
+ * Retransmit queue handled by TCP.
+ * Better retransmit timer handling.
+ * New congestion avoidance.
+ * Header prediction.
+ * Variable renaming.
+ *
+ * Eric : Fast Retransmit.
+ * Randy Scott : MSS option defines.
+ * Eric Schenk : Fixes to slow start algorithm.
+ * Eric Schenk : Yet another double ACK bug.
+ * Eric Schenk : Delayed ACK bug fixes.
+ * Eric Schenk : Floyd style fast retrans war avoidance.
+ * David S. Miller : Don't allow zero congestion window.
+ * Eric Schenk : Fix retransmitter so that it sends
+ * next packet on ack of previous packet.
+ * Andi Kleen : Moved open_request checking here
+ * and process RSTs for open_requests.
+ * Andi Kleen : Better prune_queue, and other fixes.
+ * Andrey Savochkin: Fix RTT measurements in the presnce of
+ * timestamps.
+ * Andrey Savochkin: Check sequence numbers correctly when
+ * removing SACKs due to in sequence incoming
+ * data segments.
+ * Andi Kleen: Make sure we never ack data there is not
+ * enough room for. Also make this condition
+ * a fatal error if it might still happen.
+ * Andi Kleen: Add tcp_measure_rcv_mss to make
+ * connections with MSS<min(MTU,ann. MSS)
+ * work without delayed acks.
+ * Andi Kleen: Process packets with PSH set in the
+ * fast path.
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <net/tcp.h>
+#include <linux/ipsec.h>
+
+#ifdef CONFIG_SYSCTL
+#define SYNC_INIT 0 /* let the user enable it */
+#else
+#define SYNC_INIT 1
+#endif
+
+extern int sysctl_tcp_fin_timeout;
+
+/* These are on by default so the code paths get tested.
+ * For the final 2.2 this may be undone at our discretion. -DaveM
+ */
+int sysctl_tcp_timestamps = 1;
+int sysctl_tcp_window_scaling = 1;
+int sysctl_tcp_sack = 1;
+
+int sysctl_tcp_syncookies = SYNC_INIT;
+int sysctl_tcp_stdurg;
+int sysctl_tcp_rfc1337;
+
+static int prune_queue(struct sock *sk);
+
+/* There is something which you must keep in mind when you analyze the
+ * behavior of the tp->ato delayed ack timeout interval. When a
+ * connection starts up, we want to ack as quickly as possible. The
+ * problem is that "good" TCP's do slow start at the beginning of data
+ * transmission. The means that until we send the first few ACK's the
+ * sender will sit on his end and only queue most of his data, because
+ * he can only send snd_cwnd unacked packets at any given time. For
+ * each ACK we send, he increments snd_cwnd and transmits more of his
+ * queue. -DaveM
+ */
+static void tcp_delack_estimator(struct tcp_opt *tp)
+{
+ if(tp->ato == 0) {
+ tp->lrcvtime = tcp_time_stamp;
+
+ /* Help sender leave slow start quickly,
+ * and also makes sure we do not take this
+ * branch ever again for this connection.
+ */
+ tp->ato = 1;
+ tcp_enter_quickack_mode(tp);
+ } else {
+ int m = tcp_time_stamp - tp->lrcvtime;
+
+ tp->lrcvtime = tcp_time_stamp;
+ if(m <= 0)
+ m = 1;
+ if(m > tp->rto)
+ tp->ato = tp->rto;
+ else {
+ /* This funny shift makes sure we
+ * clear the "quick ack mode" bit.
+ */
+ tp->ato = ((tp->ato << 1) >> 2) + m;
+ }
+ }
+}
+
+/*
+ * Remember to send an ACK later.
+ */
+static __inline__ void tcp_remember_ack(struct tcp_opt *tp, struct tcphdr *th,
+ struct sk_buff *skb)
+{
+ tp->delayed_acks++;
+
+ /* Tiny-grams with PSH set artificially deflate our
+ * ato measurement, but with a lower bound.
+ */
+ if(th->psh && (skb->len < (tp->mss_cache >> 1))) {
+ /* Preserve the quickack state. */
+ if((tp->ato & 0x7fffffff) > HZ/50)
+ tp->ato = ((tp->ato & 0x80000000) |
+ (HZ/50));
+ }
+}
+
+/* Called to compute a smoothed rtt estimate. The data fed to this
+ * routine either comes from timestamps, or from segments that were
+ * known _not_ to have been retransmitted [see Karn/Partridge
+ * Proceedings SIGCOMM 87]. The algorithm is from the SIGCOMM 88
+ * piece by Van Jacobson.
+ * NOTE: the next three routines used to be one big routine.
+ * To save cycles in the RFC 1323 implementation it was better to break
+ * it up into three procedures. -- erics
+ */
+
+static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
+{
+ long m = mrtt; /* RTT */
+
+ /* The following amusing code comes from Jacobson's
+ * article in SIGCOMM '88. Note that rtt and mdev
+ * are scaled versions of rtt and mean deviation.
+ * This is designed to be as fast as possible
+ * m stands for "measurement".
+ *
+ * On a 1990 paper the rto value is changed to:
+ * RTO = rtt + 4 * mdev
+ */
+ if(m == 0)
+ m = 1;
+ if (tp->srtt != 0) {
+ m -= (tp->srtt >> 3); /* m is now error in rtt est */
+ tp->srtt += m; /* rtt = 7/8 rtt + 1/8 new */
+ if (m < 0)
+ m = -m; /* m is now abs(error) */
+ m -= (tp->mdev >> 2); /* similar update on mdev */
+ tp->mdev += m; /* mdev = 3/4 mdev + 1/4 new */
+ } else {
+ /* no previous measure. */
+ tp->srtt = m<<3; /* take the measured time to be rtt */
+ tp->mdev = m<<2; /* make sure rto = 3*rtt */
+ }
+}
+
+/* Calculate rto without backoff. This is the second half of Van Jacobson's
+ * routine referred to above.
+ */
+
+static __inline__ void tcp_set_rto(struct tcp_opt *tp)
+{
+ tp->rto = (tp->srtt >> 3) + tp->mdev;
+ tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1));
+}
+
+
+/* Keep the rto between HZ/5 and 120*HZ. 120*HZ is the upper bound
+ * on packet lifetime in the internet. We need the HZ/5 lower
+ * bound to behave correctly against BSD stacks with a fixed
+ * delayed ack.
+ * FIXME: It's not entirely clear this lower bound is the best
+ * way to avoid the problem. Is it possible to drop the lower
+ * bound and still avoid trouble with BSD stacks? Perhaps
+ * some modification to the RTO calculation that takes delayed
+ * ack bias into account? This needs serious thought. -- erics
+ */
+static __inline__ void tcp_bound_rto(struct tcp_opt *tp)
+{
+ if (tp->rto > 120*HZ)
+ tp->rto = 120*HZ;
+ if (tp->rto < HZ/5)
+ tp->rto = HZ/5;
+}
+
+/* WARNING: this must not be called if tp->saw_timestamp was false. */
+extern __inline__ void tcp_replace_ts_recent(struct sock *sk, struct tcp_opt *tp,
+ __u32 start_seq, __u32 end_seq)
+{
+ /* It is start_seq <= last_ack_seq combined
+ with in window check. If start_seq<=last_ack_seq<=rcv_nxt,
+ then segment is in window if end_seq>=rcv_nxt.
+ */
+ if (!after(start_seq, tp->last_ack_sent) &&
+ !before(end_seq, tp->rcv_nxt)) {
+ /* PAWS bug workaround wrt. ACK frames, the PAWS discard
+ * extra check below makes sure this can only happen
+ * for pure ACK frames. -DaveM
+ *
+ * Plus: expired timestamps.
+ *
+ * Plus: resets failing PAWS.
+ */
+ if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0) {
+ tp->ts_recent = tp->rcv_tsval;
+ tp->ts_recent_stamp = tcp_time_stamp;
+ }
+ }
+}
+
+#define PAWS_24DAYS (HZ * 60 * 60 * 24 * 24)
+
+extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct tcphdr *th, unsigned len)
+{
+ return ((s32)(tp->rcv_tsval - tp->ts_recent) < 0 &&
+ (s32)(tcp_time_stamp - tp->ts_recent_stamp) < PAWS_24DAYS &&
+ /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM */
+ len != (th->doff * 4));
+}
+
+
+static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
+{
+ u32 end_window = tp->rcv_wup + tp->rcv_wnd;
+
+ if (tp->rcv_wnd &&
+ after(end_seq, tp->rcv_nxt) &&
+ before(seq, end_window))
+ return 1;
+ if (seq != end_window)
+ return 0;
+ return (seq == end_seq);
+}
+
+/* This functions checks to see if the tcp header is actually acceptable. */
+extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
+{
+ if (seq == tp->rcv_nxt)
+ return (tp->rcv_wnd || (end_seq == seq));
+
+ return __tcp_sequence(tp, seq, end_seq);
+}
+
+/* When we get a reset we do this. */
+static void tcp_reset(struct sock *sk)
+{
+ sk->zapped = 1;
+
+ /* We want the right error as BSD sees it (and indeed as we do). */
+ switch (sk->state) {
+ case TCP_SYN_SENT:
+ sk->err = ECONNREFUSED;
+ break;
+ case TCP_CLOSE_WAIT:
+ sk->err = EPIPE;
+ break;
+ default:
+ sk->err = ECONNRESET;
+ };
+ tcp_set_state(sk, TCP_CLOSE);
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ sk->state_change(sk);
+}
+
+/* This tags the retransmission queue when SACKs arrive. */
+static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp, int nsacks)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int i = nsacks;
+
+ while(i--) {
+ struct sk_buff *skb = skb_peek(&sk->write_queue);
+ __u32 start_seq = ntohl(sp->start_seq);
+ __u32 end_seq = ntohl(sp->end_seq);
+ int fack_count = 0;
+
+ while((skb != NULL) &&
+ (skb != tp->send_head) &&
+ (skb != (struct sk_buff *)&sk->write_queue)) {
+ /* The retransmission queue is always in order, so
+ * we can short-circuit the walk early.
+ */
+ if(after(TCP_SKB_CB(skb)->seq, end_seq))
+ break;
+
+ /* We play conservative, we don't allow SACKS to partially
+ * tag a sequence space.
+ */
+ fack_count++;
+ if(!after(start_seq, TCP_SKB_CB(skb)->seq) &&
+ !before(end_seq, TCP_SKB_CB(skb)->end_seq)) {
+ /* If this was a retransmitted frame, account for it. */
+ if((TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) &&
+ tp->retrans_out)
+ tp->retrans_out--;
+ TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
+
+ /* RULE: All new SACKs will either decrease retrans_out
+ * or advance fackets_out.
+ */
+ if(fack_count > tp->fackets_out)
+ tp->fackets_out = fack_count;
+ }
+ skb = skb->next;
+ }
+ sp++; /* Move on to the next SACK block. */
+ }
+}
+
+/* Look for tcp options. Normally only called on SYN and SYNACK packets.
+ * But, this can also be called on packets in the established flow when
+ * the fast version below fails.
+ */
+void tcp_parse_options(struct sock *sk, struct tcphdr *th, struct tcp_opt *tp, int no_fancy)
+{
+ unsigned char *ptr;
+ int length=(th->doff*4)-sizeof(struct tcphdr);
+ int saw_mss = 0;
+
+ ptr = (unsigned char *)(th + 1);
+ tp->saw_tstamp = 0;
+
+ while(length>0) {
+ int opcode=*ptr++;
+ int opsize;
+
+ switch (opcode) {
+ case TCPOPT_EOL:
+ return;
+ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
+ length--;
+ continue;
+ default:
+ opsize=*ptr++;
+ if (opsize < 2) /* "silly options" */
+ return;
+ if (opsize > length)
+ break; /* don't parse partial options */
+ switch(opcode) {
+ case TCPOPT_MSS:
+ if(opsize==TCPOLEN_MSS && th->syn) {
+ u16 in_mss = ntohs(*(__u16 *)ptr);
+ if (in_mss == 0)
+ in_mss = 536;
+ if (tp->mss_clamp > in_mss)
+ tp->mss_clamp = in_mss;
+ saw_mss = 1;
+ }
+ break;
+ case TCPOPT_WINDOW:
+ if(opsize==TCPOLEN_WINDOW && th->syn)
+ if (!no_fancy && sysctl_tcp_window_scaling) {
+ tp->wscale_ok = 1;
+ tp->snd_wscale = *(__u8 *)ptr;
+ if(tp->snd_wscale > 14) {
+ if(net_ratelimit())
+ printk("tcp_parse_options: Illegal window "
+ "scaling value %d >14 received.",
+ tp->snd_wscale);
+ tp->snd_wscale = 14;
+ }
+ }
+ break;
+ case TCPOPT_TIMESTAMP:
+ if(opsize==TCPOLEN_TIMESTAMP) {
+ if (sysctl_tcp_timestamps && !no_fancy) {
+ tp->tstamp_ok = 1;
+ tp->saw_tstamp = 1;
+ tp->rcv_tsval = ntohl(*(__u32 *)ptr);
+ tp->rcv_tsecr = ntohl(*(__u32 *)(ptr+4));
+ }
+ }
+ break;
+ case TCPOPT_SACK_PERM:
+ if(opsize==TCPOLEN_SACK_PERM && th->syn) {
+ if (sysctl_tcp_sack && !no_fancy) {
+ tp->sack_ok = 1;
+ tp->num_sacks = 0;
+ }
+ }
+ break;
+
+ case TCPOPT_SACK:
+ if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
+ sysctl_tcp_sack && (sk != NULL) && !th->syn) {
+ int sack_bytes = opsize - TCPOLEN_SACK_BASE;
+
+ if(!(sack_bytes % TCPOLEN_SACK_PERBLOCK)) {
+ int num_sacks = sack_bytes >> 3;
+ struct tcp_sack_block *sackp;
+
+ sackp = (struct tcp_sack_block *)ptr;
+ tcp_sacktag_write_queue(sk, sackp, num_sacks);
+ }
+ }
+ };
+ ptr+=opsize-2;
+ length-=opsize;
+ };
+ }
+ if(th->syn && saw_mss == 0)
+ tp->mss_clamp = 536;
+}
+
+/* Fast parse options. This hopes to only see timestamps.
+ * If it is wrong it falls back on tcp_parse_options().
+ */
+static __inline__ int tcp_fast_parse_options(struct sock *sk, struct tcphdr *th, struct tcp_opt *tp)
+{
+ /* If we didn't send out any options ignore them all. */
+ if (tp->tcp_header_len == sizeof(struct tcphdr))
+ return 0;
+ if (th->doff == sizeof(struct tcphdr)>>2) {
+ tp->saw_tstamp = 0;
+ return 0;
+ } else if (th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
+ __u32 *ptr = (__u32 *)(th + 1);
+ if (*ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+ | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+ tp->saw_tstamp = 1;
+ tp->rcv_tsval = ntohl(*++ptr);
+ tp->rcv_tsecr = ntohl(*++ptr);
+ return 1;
+ }
+ }
+ tcp_parse_options(sk, th, tp, 0);
+ return 1;
+}
+
+#define FLAG_DATA 0x01 /* Incoming frame contained data. */
+#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
+#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */
+#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */
+
+static __inline__ void clear_fast_retransmit(struct tcp_opt *tp)
+{
+ if (tp->dup_acks > 3)
+ tp->snd_cwnd = (tp->snd_ssthresh);
+
+ tp->dup_acks = 0;
+}
+
+/* NOTE: This code assumes that tp->dup_acks gets cleared when a
+ * retransmit timer fires.
+ */
+static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Note: If not_dup is set this implies we got a
+ * data carrying packet or a window update.
+ * This carries no new information about possible
+ * lost packets, so we have to ignore it for the purposes
+ * of counting duplicate acks. Ideally this does not imply we
+ * should stop our fast retransmit phase, more acks may come
+ * later without data to help us. Unfortunately this would make
+ * the code below much more complex. For now if I see such
+ * a packet I clear the fast retransmit phase.
+ */
+ if (ack == tp->snd_una && tp->packets_out && (not_dup == 0)) {
+ /* This is the standard reno style fast retransmit branch. */
+
+ /* 1. When the third duplicate ack is received, set ssthresh
+ * to one half the current congestion window, but no less
+ * than two segments. Retransmit the missing segment.
+ */
+ if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
+ tp->dup_acks++;
+ if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
+ tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+ tp->snd_cwnd = (tp->snd_ssthresh + 3);
+ tp->high_seq = tp->snd_nxt;
+ if(!tp->fackets_out)
+ tcp_retransmit_skb(sk,
+ skb_peek(&sk->write_queue));
+ else
+ tcp_fack_retransmit(sk);
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ }
+ } else if (++tp->dup_acks > 3) {
+ /* 2. Each time another duplicate ACK arrives, increment
+ * cwnd by the segment size. [...] Transmit a packet...
+ *
+ * Packet transmission will be done on normal flow processing
+ * since we're not in "retransmit mode". We do not use
+ * duplicate ACKs to artificially inflate the congestion
+ * window when doing FACK.
+ */
+ if(!tp->fackets_out) {
+ tp->snd_cwnd++;
+ } else {
+ /* Fill any further holes which may have
+ * appeared.
+ *
+ * We may want to change this to run every
+ * further multiple-of-3 dup ack increments,
+ * to be more robust against out-of-order
+ * packet delivery. -DaveM
+ */
+ tcp_fack_retransmit(sk);
+ }
+ }
+ } else if (tp->high_seq != 0) {
+ /* In this branch we deal with clearing the Floyd style
+ * block on duplicate fast retransmits, and if requested
+ * we do Hoe style secondary fast retransmits.
+ */
+ if (!before(ack, tp->high_seq) || (not_dup & FLAG_DATA) != 0) {
+ /* Once we have acked all the packets up to high_seq
+ * we are done this fast retransmit phase.
+ * Alternatively data arrived. In this case we
+ * Have to abort the fast retransmit attempt.
+ * Note that we do want to accept a window
+ * update since this is expected with Hoe's algorithm.
+ */
+ clear_fast_retransmit(tp);
+
+ /* After we have cleared up to high_seq we can
+ * clear the Floyd style block.
+ */
+ if (!before(ack, tp->high_seq)) {
+ tp->high_seq = 0;
+ tp->fackets_out = 0;
+ }
+ } else if (tp->dup_acks >= 3) {
+ if (!tp->fackets_out) {
+ /* Hoe Style. We didn't ack the whole
+ * window. Take this as a cue that
+ * another packet was lost and retransmit it.
+ * Don't muck with the congestion window here.
+ * Note that we have to be careful not to
+ * act if this was a window update and it
+ * didn't ack new data, since this does
+ * not indicate a packet left the system.
+ * We can test this by just checking
+ * if ack changed from snd_una, since
+ * the only way to get here without advancing
+ * from snd_una is if this was a window update.
+ */
+ if (ack != tp->snd_una && before(ack, tp->high_seq)) {
+ tcp_retransmit_skb(sk,
+ skb_peek(&sk->write_queue));
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ }
+ } else {
+ /* FACK style, fill any remaining holes in
+ * receiver's queue.
+ */
+ tcp_fack_retransmit(sk);
+ }
+ }
+ }
+}
+
+/* This is Jacobson's slow start and congestion avoidance.
+ * SIGCOMM '88, p. 328.
+ */
+static __inline__ void tcp_cong_avoid(struct tcp_opt *tp)
+{
+ if (tp->snd_cwnd <= tp->snd_ssthresh) {
+ /* In "safe" area, increase. */
+ tp->snd_cwnd++;
+ } else {
+ /* In dangerous area, increase slowly.
+ * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
+ */
+ if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
+ tp->snd_cwnd++;
+ tp->snd_cwnd_cnt=0;
+ } else
+ tp->snd_cwnd_cnt++;
+ }
+}
+
+/* Remove acknowledged frames from the retransmission queue. */
+static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
+ __u32 *seq, __u32 *seq_rtt)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb;
+ __u32 now = tcp_time_stamp;
+ int acked = 0;
+
+ /* If we are retransmitting, and this ACK clears up to
+ * the retransmit head, or further, then clear our state.
+ */
+ if (tp->retrans_head != NULL &&
+ !before(ack, TCP_SKB_CB(tp->retrans_head)->end_seq))
+ tp->retrans_head = NULL;
+
+ while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head)) {
+ struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
+ __u8 sacked = scb->sacked;
+
+ /* If our packet is before the ack sequence we can
+ * discard it as it's confirmed to have arrived at
+ * the other end.
+ */
+ if (after(scb->end_seq, ack))
+ break;
+
+ /* Initial outgoing SYN's get put onto the write_queue
+ * just like anything else we transmit. It is not
+ * true data, and if we misinform our callers that
+ * this ACK acks real data, we will erroneously exit
+ * connection startup slow start one packet too
+ * quickly. This is severely frowned upon behavior.
+ */
+ if((sacked & TCPCB_SACKED_RETRANS) && tp->retrans_out)
+ tp->retrans_out--;
+ if(!(scb->flags & TCPCB_FLAG_SYN)) {
+ acked |= FLAG_DATA_ACKED;
+ if(sacked & TCPCB_SACKED_RETRANS)
+ acked |= FLAG_RETRANS_DATA_ACKED;
+ if(tp->fackets_out)
+ tp->fackets_out--;
+ } else {
+ /* This is pure paranoia. */
+ tp->retrans_head = NULL;
+ }
+ tp->packets_out--;
+ *seq = scb->seq;
+ *seq_rtt = now - scb->when;
+ __skb_unlink(skb, skb->list);
+ kfree_skb(skb);
+ }
+ return acked;
+}
+
+static void tcp_ack_probe(struct sock *sk, __u32 ack)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Our probe was answered. */
+ tp->probes_out = 0;
+
+ /* Was it a usable window open? */
+
+ /* should always be non-null */
+ if (tp->send_head != NULL &&
+ !before (ack + tp->snd_wnd, TCP_SKB_CB(tp->send_head)->end_seq)) {
+ tp->backoff = 0;
+ tp->pending = 0;
+ tcp_clear_xmit_timer(sk, TIME_PROBE0);
+ } else {
+ tcp_reset_xmit_timer(sk, TIME_PROBE0,
+ min(tp->rto << tp->backoff, 120*HZ));
+ }
+}
+
+/* Should we open up the congestion window? */
+static __inline__ int should_advance_cwnd(struct tcp_opt *tp, int flag)
+{
+ /* Data must have been acked. */
+ if ((flag & FLAG_DATA_ACKED) == 0)
+ return 0;
+
+ /* Some of the data acked was retransmitted somehow? */
+ if ((flag & FLAG_RETRANS_DATA_ACKED) != 0) {
+ /* We advance in all cases except during
+ * non-FACK fast retransmit/recovery.
+ */
+ if (tp->fackets_out != 0 ||
+ tp->retransmits != 0)
+ return 1;
+
+ /* Non-FACK fast retransmit does it's own
+ * congestion window management, don't get
+ * in the way.
+ */
+ return 0;
+ }
+
+ /* New non-retransmitted data acked, always advance. */
+ return 1;
+}
+
+/* Read draft-ietf-tcplw-high-performance before mucking
+ * with this code. (Superceeds RFC1323)
+ */
+static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
+ u32 seq, u32 ack, int flag)
+{
+ __u32 seq_rtt;
+
+ /* RTTM Rule: A TSecr value received in a segment is used to
+ * update the averaged RTT measurement only if the segment
+ * acknowledges some new data, i.e., only if it advances the
+ * left edge of the send window.
+ *
+ * See draft-ietf-tcplw-high-performance-00, section 3.3.
+ * 1998/04/10 Andrey V. Savochkin <saw@msu.ru>
+ */
+ if (!(flag & FLAG_DATA_ACKED))
+ return;
+
+ seq_rtt = tcp_time_stamp - tp->rcv_tsecr;
+ tcp_rtt_estimator(tp, seq_rtt);
+ if (tp->retransmits) {
+ if (tp->packets_out == 0) {
+ tp->retransmits = 0;
+ tp->fackets_out = 0;
+ tp->retrans_out = 0;
+ tp->backoff = 0;
+ tcp_set_rto(tp);
+ } else {
+ /* Still retransmitting, use backoff */
+ tcp_set_rto(tp);
+ tp->rto = tp->rto << tp->backoff;
+ }
+ } else {
+ tcp_set_rto(tp);
+ }
+
+ tcp_bound_rto(tp);
+}
+
+static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
+{
+ struct sk_buff *skb = skb_peek(&sk->write_queue);
+
+ /* Some data was ACK'd, if still retransmitting (due to a
+ * timeout), resend more of the retransmit queue. The
+ * congestion window is handled properly by that code.
+ */
+ if (tp->retransmits) {
+ tcp_xmit_retransmit_queue(sk);
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ } else {
+ __u32 when = tp->rto - (tcp_time_stamp - TCP_SKB_CB(skb)->when);
+ if ((__s32)when < 0)
+ when = 1;
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, when);
+ }
+}
+
+/* This routine deals with incoming acks, but not outgoing ones. */
+static int tcp_ack(struct sock *sk, struct tcphdr *th,
+ u32 ack_seq, u32 ack, int len)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int flag = 0;
+ u32 seq = 0;
+ u32 seq_rtt = 0;
+
+ if(sk->zapped)
+ return(1); /* Dead, can't ack any more so why bother */
+
+ if (tp->pending == TIME_KEEPOPEN)
+ tp->probes_out = 0;
+
+ tp->rcv_tstamp = tcp_time_stamp;
+
+ /* If the ack is newer than sent or older than previous acks
+ * then we can probably ignore it.
+ */
+ if (after(ack, tp->snd_nxt) || before(ack, tp->snd_una))
+ goto uninteresting_ack;
+
+ /* If there is data set flag 1 */
+ if (len != th->doff*4) {
+ flag |= FLAG_DATA;
+ tcp_delack_estimator(tp);
+ }
+
+ /* Update our send window. */
+
+ /* This is the window update code as per RFC 793
+ * snd_wl{1,2} are used to prevent unordered
+ * segments from shrinking the window
+ */
+ if (before(tp->snd_wl1, ack_seq) ||
+ (tp->snd_wl1 == ack_seq && !after(tp->snd_wl2, ack))) {
+ u32 nwin = ntohs(th->window) << tp->snd_wscale;
+
+ if ((tp->snd_wl2 != ack) || (nwin > tp->snd_wnd)) {
+ flag |= FLAG_WIN_UPDATE;
+ tp->snd_wnd = nwin;
+
+ tp->snd_wl1 = ack_seq;
+ tp->snd_wl2 = ack;
+
+ if (nwin > tp->max_window)
+ tp->max_window = nwin;
+ }
+ }
+
+ /* We passed data and got it acked, remove any soft error
+ * log. Something worked...
+ */
+ sk->err_soft = 0;
+
+ /* If this ack opens up a zero window, clear backoff. It was
+ * being used to time the probes, and is probably far higher than
+ * it needs to be for normal retransmission.
+ */
+ if (tp->pending == TIME_PROBE0)
+ tcp_ack_probe(sk, ack);
+
+ /* See if we can take anything off of the retransmit queue. */
+ flag |= tcp_clean_rtx_queue(sk, ack, &seq, &seq_rtt);
+
+ /* We must do this here, before code below clears out important
+ * state contained in tp->fackets_out and tp->retransmits. -DaveM
+ */
+ if (should_advance_cwnd(tp, flag))
+ tcp_cong_avoid(tp);
+
+ /* If we have a timestamp, we always do rtt estimates. */
+ if (tp->saw_tstamp) {
+ tcp_ack_saw_tstamp(sk, tp, seq, ack, flag);
+ } else {
+ /* If we were retransmiting don't count rtt estimate. */
+ if (tp->retransmits) {
+ if (tp->packets_out == 0) {
+ tp->retransmits = 0;
+ tp->fackets_out = 0;
+ tp->retrans_out = 0;
+ }
+ } else {
+ /* We don't have a timestamp. Can only use
+ * packets that are not retransmitted to determine
+ * rtt estimates. Also, we must not reset the
+ * backoff for rto until we get a non-retransmitted
+ * packet. This allows us to deal with a situation
+ * where the network delay has increased suddenly.
+ * I.e. Karn's algorithm. (SIGCOMM '87, p5.)
+ */
+ if (flag & FLAG_DATA_ACKED) {
+ if(!(flag & FLAG_RETRANS_DATA_ACKED)) {
+ tp->backoff = 0;
+ tcp_rtt_estimator(tp, seq_rtt);
+ tcp_set_rto(tp);
+ tcp_bound_rto(tp);
+ }
+ }
+ }
+ }
+
+ if (tp->packets_out) {
+ if (flag & FLAG_DATA_ACKED)
+ tcp_ack_packets_out(sk, tp);
+ } else {
+ tcp_clear_xmit_timer(sk, TIME_RETRANS);
+ }
+
+ flag &= (FLAG_DATA | FLAG_WIN_UPDATE);
+ if ((ack == tp->snd_una && tp->packets_out && flag == 0) ||
+ (tp->high_seq != 0)) {
+ tcp_fast_retrans(sk, ack, flag);
+ } else {
+ /* Clear any aborted fast retransmit starts. */
+ tp->dup_acks = 0;
+ }
+ /* It is not a brain fart, I thought a bit now. 8)
+ *
+ * Forward progress is indicated, if:
+ * 1. the ack acknowledges new data.
+ * 2. or the ack is duplicate, but it is caused by new segment
+ * arrival. This case is filtered by:
+ * - it contains no data, syn or fin.
+ * - it does not update window.
+ * 3. or new SACK. It is difficult to check, so that we ignore it.
+ *
+ * Forward progress is also indicated by arrival new data,
+ * which was caused by window open from our side. This case is more
+ * difficult and it is made (alas, incorrectly) in tcp_data_queue().
+ * --ANK (990513)
+ */
+ if (ack != tp->snd_una || (flag == 0 && !th->fin))
+ dst_confirm(sk->dst_cache);
+
+ /* Remember the highest ack received. */
+ tp->snd_una = ack;
+ return 1;
+
+uninteresting_ack:
+ SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt);
+ return 0;
+}
+
+/* New-style handling of TIME_WAIT sockets. */
+extern void tcp_tw_schedule(struct tcp_tw_bucket *tw);
+extern void tcp_tw_reschedule(struct tcp_tw_bucket *tw);
+extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw);
+
+void tcp_timewait_kill(struct tcp_tw_bucket *tw)
+{
+ struct tcp_bind_bucket *tb = tw->tb;
+
+ /* Disassociate with bind bucket. */
+ if(tw->bind_next)
+ tw->bind_next->bind_pprev = tw->bind_pprev;
+ *(tw->bind_pprev) = tw->bind_next;
+ if (tb->owners == NULL) {
+ if (tb->next)
+ tb->next->pprev = tb->pprev;
+ *(tb->pprev) = tb->next;
+ kmem_cache_free(tcp_bucket_cachep, tb);
+ }
+
+ /* Unlink from established hashes. */
+ if(tw->next)
+ tw->next->pprev = tw->pprev;
+ *tw->pprev = tw->next;
+
+ /* We decremented the prot->inuse count when we entered TIME_WAIT
+ * and the sock from which this came was destroyed.
+ */
+ tw->sklist_next->sklist_prev = tw->sklist_prev;
+ tw->sklist_prev->sklist_next = tw->sklist_next;
+
+ /* Ok, now free it up. */
+ kmem_cache_free(tcp_timewait_cachep, tw);
+}
+
+/* We come here as a special case from the AF specific TCP input processing,
+ * and the SKB has no owner. Essentially handling this is very simple,
+ * we just keep silently eating rx'd packets, acking them if necessary,
+ * until none show up for the entire timeout period.
+ *
+ * Return 0, TCP_TW_ACK, TCP_TW_RST
+ */
+enum tcp_tw_status
+tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
+ struct tcphdr *th, unsigned len)
+{
+ /* RFC 1122:
+ * "When a connection is [...] on TIME-WAIT state [...]
+ * [a TCP] MAY accept a new SYN from the remote TCP to
+ * reopen the connection directly, if it:
+ *
+ * (1) assigns its initial sequence number for the new
+ * connection to be larger than the largest sequence
+ * number it used on the previous connection incarnation,
+ * and
+ *
+ * (2) returns to TIME-WAIT state if the SYN turns out
+ * to be an old duplicate".
+ */
+ if(th->syn && !th->rst && after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) {
+ struct sock *sk;
+ struct tcp_func *af_specific = tw->af_specific;
+ __u32 isn;
+
+ isn = tw->snd_nxt + 128000;
+ if(isn == 0)
+ isn++;
+ tcp_tw_deschedule(tw);
+ tcp_timewait_kill(tw);
+ sk = af_specific->get_sock(skb, th);
+ if(sk == NULL ||
+ !ipsec_sk_policy(sk,skb) ||
+ atomic_read(&sk->sock_readers) != 0)
+ return 0;
+ skb_set_owner_r(skb, sk);
+ af_specific = sk->tp_pinfo.af_tcp.af_specific;
+ if(af_specific->conn_request(sk, skb, isn) < 0)
+ return TCP_TW_RST; /* Toss a reset back. */
+ return 0; /* Discard the frame. */
+ }
+
+ /* Check RST or SYN */
+ if(th->rst || th->syn) {
+ /* This is TIME_WAIT assassination, in two flavors.
+ * Oh well... nobody has a sufficient solution to this
+ * protocol bug yet.
+ */
+ if(sysctl_tcp_rfc1337 == 0) {
+ tcp_tw_deschedule(tw);
+ tcp_timewait_kill(tw);
+ }
+ if(!th->rst)
+ return TCP_TW_RST; /* toss a reset back */
+ return 0;
+ } else {
+ /* In this case we must reset the TIMEWAIT timer. */
+ if(th->ack)
+ tcp_tw_reschedule(tw);
+ }
+ /* Ack old packets if necessary */
+ if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) &&
+ (th->doff * 4) > len)
+ return TCP_TW_ACK;
+ return 0;
+}
+
+/* Enter the time wait state. This is always called from BH
+ * context. Essentially we whip up a timewait bucket, copy the
+ * relevant info into it from the SK, and mess with hash chains
+ * and list linkage.
+ */
+static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
+{
+ struct sock **head, *sktw;
+
+ /* Step 1: Remove SK from established hash. */
+ if(sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ tcp_reg_zap(sk);
+
+ /* Step 2: Put TW into bind hash where SK was. */
+ tw->tb = (struct tcp_bind_bucket *)sk->prev;
+ if((tw->bind_next = sk->bind_next) != NULL)
+ sk->bind_next->bind_pprev = &tw->bind_next;
+ tw->bind_pprev = sk->bind_pprev;
+ *sk->bind_pprev = (struct sock *)tw;
+ sk->prev = NULL;
+
+ /* Step 3: Same for the protocol sklist. */
+ (tw->sklist_next = sk->sklist_next)->sklist_prev = (struct sock *)tw;
+ (tw->sklist_prev = sk->sklist_prev)->sklist_next = (struct sock *)tw;
+ sk->sklist_next = NULL;
+ sk->prot->inuse--;
+
+ /* Step 4: Hash TW into TIMEWAIT half of established hash table. */
+ head = &tcp_ehash[sk->hashent + (tcp_ehash_size/2)];
+ sktw = (struct sock *)tw;
+ if((sktw->next = *head) != NULL)
+ (*head)->pprev = &sktw->next;
+ *head = sktw;
+ sktw->pprev = head;
+}
+
+void tcp_time_wait(struct sock *sk)
+{
+ struct tcp_tw_bucket *tw;
+
+ tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC);
+ if(tw != NULL) {
+ /* Give us an identity. */
+ tw->daddr = sk->daddr;
+ tw->rcv_saddr = sk->rcv_saddr;
+ tw->bound_dev_if= sk->bound_dev_if;
+ tw->num = sk->num;
+ tw->state = TCP_TIME_WAIT;
+ tw->sport = sk->sport;
+ tw->dport = sk->dport;
+ tw->family = sk->family;
+ tw->reuse = sk->reuse;
+ tw->rcv_nxt = sk->tp_pinfo.af_tcp.rcv_nxt;
+ tw->snd_nxt = sk->tp_pinfo.af_tcp.snd_nxt;
+ tw->window = tcp_select_window(sk);
+ tw->af_specific = sk->tp_pinfo.af_tcp.af_specific;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ if(tw->family == PF_INET6) {
+ memcpy(&tw->v6_daddr,
+ &sk->net_pinfo.af_inet6.daddr,
+ sizeof(struct in6_addr));
+ memcpy(&tw->v6_rcv_saddr,
+ &sk->net_pinfo.af_inet6.rcv_saddr,
+ sizeof(struct in6_addr));
+ }
+#endif
+ /* Linkage updates. */
+ tcp_tw_hashdance(sk, tw);
+
+ /* Get the TIME_WAIT timeout firing. */
+ tcp_tw_schedule(tw);
+
+ /* CLOSE the SK. */
+ if(sk->state == TCP_ESTABLISHED)
+ tcp_statistics.TcpCurrEstab--;
+ sk->state = TCP_CLOSE;
+ net_reset_timer(sk, TIME_DONE,
+ min(sk->tp_pinfo.af_tcp.srtt * 2, TCP_DONE_TIME));
+ } else {
+ /* Sorry, we're out of memory, just CLOSE this
+ * socket up. We've got bigger problems than
+ * non-graceful socket closings.
+ */
+ tcp_set_state(sk, TCP_CLOSE);
+ }
+
+ /* Prevent rcvmsg/sndmsg calls, and wake people up. */
+ sk->shutdown = SHUTDOWN_MASK;
+ if(!sk->dead)
+ sk->state_change(sk);
+}
+
+/*
+ * Process the FIN bit. This now behaves as it is supposed to work
+ * and the FIN takes effect when it is validly part of sequence
+ * space. Not before when we get holes.
+ *
+ * If we are ESTABLISHED, a received fin moves us to CLOSE-WAIT
+ * (and thence onto LAST-ACK and finally, CLOSE, we never enter
+ * TIME-WAIT)
+ *
+ * If we are in FINWAIT-1, a received FIN indicates simultaneous
+ * close and we go into CLOSING (and later onto TIME-WAIT)
+ *
+ * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
+ */
+
+static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
+{
+ sk->tp_pinfo.af_tcp.fin_seq = TCP_SKB_CB(skb)->end_seq;
+
+ tcp_send_ack(sk);
+
+ if (!sk->dead) {
+ sk->state_change(sk);
+ sock_wake_async(sk->socket, 1);
+ }
+
+ switch(sk->state) {
+ case TCP_SYN_RECV:
+ case TCP_ESTABLISHED:
+ /* Move to CLOSE_WAIT */
+ tcp_set_state(sk, TCP_CLOSE_WAIT);
+ if (th->rst)
+ sk->shutdown = SHUTDOWN_MASK;
+ break;
+
+ case TCP_CLOSE_WAIT:
+ case TCP_CLOSING:
+ /* Received a retransmission of the FIN, do
+ * nothing.
+ */
+ break;
+ case TCP_LAST_ACK:
+ /* RFC793: Remain in the LAST-ACK state. */
+ break;
+
+ case TCP_FIN_WAIT1:
+ /* This case occurs when a simultaneous close
+ * happens, we must ack the received FIN and
+ * enter the CLOSING state.
+ *
+ * This causes a WRITE timeout, which will either
+ * move on to TIME_WAIT when we timeout, or resend
+ * the FIN properly (maybe we get rid of that annoying
+ * FIN lost hang). The TIME_WRITE code is already
+ * correct for handling this timeout.
+ */
+ tcp_set_state(sk, TCP_CLOSING);
+ break;
+ case TCP_FIN_WAIT2:
+ /* Received a FIN -- send ACK and enter TIME_WAIT. */
+ tcp_time_wait(sk);
+ break;
+ default:
+ /* Only TCP_LISTEN and TCP_CLOSE are left, in these
+ * cases we should never reach this piece of code.
+ */
+ printk("tcp_fin: Impossible, sk->state=%d\n", sk->state);
+ break;
+ };
+}
+
+/* These routines update the SACK block as out-of-order packets arrive or
+ * in-order packets close up the sequence space.
+ */
+static void tcp_sack_maybe_coalesce(struct tcp_opt *tp, struct tcp_sack_block *sp)
+{
+ int this_sack, num_sacks = tp->num_sacks;
+ struct tcp_sack_block *swalk = &tp->selective_acks[0];
+
+ /* If more than one SACK block, see if the recent change to SP eats into
+ * or hits the sequence space of other SACK blocks, if so coalesce.
+ */
+ if(num_sacks != 1) {
+ for(this_sack = 0; this_sack < num_sacks; this_sack++, swalk++) {
+ if(swalk == sp)
+ continue;
+
+ /* First case, bottom of SP moves into top of the
+ * sequence space of SWALK.
+ */
+ if(between(sp->start_seq, swalk->start_seq, swalk->end_seq)) {
+ sp->start_seq = swalk->start_seq;
+ goto coalesce;
+ }
+ /* Second case, top of SP moves into bottom of the
+ * sequence space of SWALK.
+ */
+ if(between(sp->end_seq, swalk->start_seq, swalk->end_seq)) {
+ sp->end_seq = swalk->end_seq;
+ goto coalesce;
+ }
+ }
+ }
+ /* SP is the only SACK, or no coalescing cases found. */
+ return;
+
+coalesce:
+ /* Zap SWALK, by moving every further SACK up by one slot.
+ * Decrease num_sacks.
+ */
+ for(; this_sack < num_sacks-1; this_sack++, swalk++) {
+ struct tcp_sack_block *next = (swalk + 1);
+ swalk->start_seq = next->start_seq;
+ swalk->end_seq = next->end_seq;
+ }
+ tp->num_sacks--;
+}
+
+static __inline__ void tcp_sack_swap(struct tcp_sack_block *sack1, struct tcp_sack_block *sack2)
+{
+ __u32 tmp;
+
+ tmp = sack1->start_seq;
+ sack1->start_seq = sack2->start_seq;
+ sack2->start_seq = tmp;
+
+ tmp = sack1->end_seq;
+ sack1->end_seq = sack2->end_seq;
+ sack2->end_seq = tmp;
+}
+
+static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct tcp_sack_block *sp = &tp->selective_acks[0];
+ int cur_sacks = tp->num_sacks;
+
+ if (!cur_sacks)
+ goto new_sack;
+
+ /* Optimize for the common case, new ofo frames arrive
+ * "in order". ;-) This also satisfies the requirements
+ * of RFC2018 about ordering of SACKs.
+ */
+ if(sp->end_seq == TCP_SKB_CB(skb)->seq) {
+ sp->end_seq = TCP_SKB_CB(skb)->end_seq;
+ tcp_sack_maybe_coalesce(tp, sp);
+ } else if(sp->start_seq == TCP_SKB_CB(skb)->end_seq) {
+ /* Re-ordered arrival, in this case, can be optimized
+ * as well.
+ */
+ sp->start_seq = TCP_SKB_CB(skb)->seq;
+ tcp_sack_maybe_coalesce(tp, sp);
+ } else {
+ struct tcp_sack_block *swap = sp + 1;
+ int this_sack, max_sacks = (tp->tstamp_ok ? 3 : 4);
+
+ /* Oh well, we have to move things around.
+ * Try to find a SACK we can tack this onto.
+ */
+
+ for(this_sack = 1; this_sack < cur_sacks; this_sack++, swap++) {
+ if((swap->end_seq == TCP_SKB_CB(skb)->seq) ||
+ (swap->start_seq == TCP_SKB_CB(skb)->end_seq)) {
+ if(swap->end_seq == TCP_SKB_CB(skb)->seq)
+ swap->end_seq = TCP_SKB_CB(skb)->end_seq;
+ else
+ swap->start_seq = TCP_SKB_CB(skb)->seq;
+ tcp_sack_swap(sp, swap);
+ tcp_sack_maybe_coalesce(tp, sp);
+ return;
+ }
+ }
+
+ /* Could not find an adjacent existing SACK, build a new one,
+ * put it at the front, and shift everyone else down. We
+ * always know there is at least one SACK present already here.
+ *
+ * If the sack array is full, forget about the last one.
+ */
+ if (cur_sacks >= max_sacks) {
+ cur_sacks--;
+ tp->num_sacks--;
+ }
+ while(cur_sacks >= 1) {
+ struct tcp_sack_block *this = &tp->selective_acks[cur_sacks];
+ struct tcp_sack_block *prev = (this - 1);
+ this->start_seq = prev->start_seq;
+ this->end_seq = prev->end_seq;
+ cur_sacks--;
+ }
+
+ new_sack:
+ /* Build the new head SACK, and we're done. */
+ sp->start_seq = TCP_SKB_CB(skb)->seq;
+ sp->end_seq = TCP_SKB_CB(skb)->end_seq;
+ tp->num_sacks++;
+ }
+}
+
+static void tcp_sack_remove_skb(struct tcp_opt *tp, struct sk_buff *skb)
+{
+ struct tcp_sack_block *sp = &tp->selective_acks[0];
+ int num_sacks = tp->num_sacks;
+ int this_sack;
+
+ /* This is an in order data segment _or_ an out-of-order SKB being
+ * moved to the receive queue, so we know this removed SKB will eat
+ * from the front of a SACK.
+ */
+ for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
+ /* Check if the start of the sack is covered by skb. */
+ if(!before(sp->start_seq, TCP_SKB_CB(skb)->seq) &&
+ before(sp->start_seq, TCP_SKB_CB(skb)->end_seq))
+ break;
+ }
+
+ /* This should only happen if so many SACKs get built that some get
+ * pushed out before we get here, or we eat some in sequence packets
+ * which are before the first SACK block.
+ */
+ if(this_sack >= num_sacks)
+ return;
+
+ sp->start_seq = TCP_SKB_CB(skb)->end_seq;
+ if(!before(sp->start_seq, sp->end_seq)) {
+ /* Zap this SACK, by moving forward any other SACKS. */
+ for(this_sack += 1; this_sack < num_sacks; this_sack++, sp++) {
+ struct tcp_sack_block *next = (sp + 1);
+ sp->start_seq = next->start_seq;
+ sp->end_seq = next->end_seq;
+ }
+ tp->num_sacks--;
+ }
+}
+
+static void tcp_sack_extend(struct tcp_opt *tp, struct sk_buff *old_skb, struct sk_buff *new_skb)
+{
+ struct tcp_sack_block *sp = &tp->selective_acks[0];
+ int num_sacks = tp->num_sacks;
+ int this_sack;
+
+ for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
+ if(sp->end_seq == TCP_SKB_CB(old_skb)->end_seq)
+ break;
+ }
+ if(this_sack >= num_sacks)
+ return;
+ sp->end_seq = TCP_SKB_CB(new_skb)->end_seq;
+}
+
+/* This one checks to see if we can put data from the
+ * out_of_order queue into the receive_queue.
+ */
+static void tcp_ofo_queue(struct sock *sk)
+{
+ struct sk_buff *skb;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ while ((skb = skb_peek(&tp->out_of_order_queue))) {
+ if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
+ break;
+
+ if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
+ SOCK_DEBUG(sk, "ofo packet was already received \n");
+ __skb_unlink(skb, skb->list);
+ kfree_skb(skb);
+ continue;
+ }
+ SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n",
+ tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->end_seq);
+
+ if(tp->sack_ok)
+ tcp_sack_remove_skb(tp, skb);
+ __skb_unlink(skb, skb->list);
+ __skb_queue_tail(&sk->receive_queue, skb);
+ tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+ if(skb->h.th->fin)
+ tcp_fin(skb, sk, skb->h.th);
+ }
+}
+
+static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
+{
+ struct sk_buff *skb1;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Queue data for delivery to the user.
+ * Packets in sequence go to the receive queue.
+ * Out of sequence packets to the out_of_order_queue.
+ */
+ if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
+ /* Ok. In sequence. */
+ queue_and_out:
+ dst_confirm(sk->dst_cache);
+ __skb_queue_tail(&sk->receive_queue, skb);
+ tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+ if(skb->h.th->fin) {
+ tcp_fin(skb, sk, skb->h.th);
+ } else {
+ tcp_remember_ack(tp, skb->h.th, skb);
+ }
+ /* This may have eaten into a SACK block. */
+ if(tp->sack_ok && tp->num_sacks)
+ tcp_sack_remove_skb(tp, skb);
+ tcp_ofo_queue(sk);
+
+ /* Turn on fast path. */
+ if (skb_queue_len(&tp->out_of_order_queue) == 0)
+ tp->pred_flags = htonl(((tp->tcp_header_len >> 2) << 28) |
+ (0x10 << 16) |
+ tp->snd_wnd);
+ return;
+ }
+
+ /* An old packet, either a retransmit or some packet got lost. */
+ if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
+ /* A retransmit, 2nd most common case. Force an imediate ack. */
+ SOCK_DEBUG(sk, "retransmit received: seq %X\n", TCP_SKB_CB(skb)->seq);
+ tcp_enter_quickack_mode(tp);
+ kfree_skb(skb);
+ return;
+ }
+
+ if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
+ /* Partial packet, seq < rcv_next < end_seq */
+ SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n",
+ tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->end_seq);
+
+ goto queue_and_out;
+ }
+
+ /* Ok. This is an out_of_order segment, force an ack. */
+ tp->delayed_acks++;
+ tcp_enter_quickack_mode(tp);
+
+ /* Disable header prediction. */
+ tp->pred_flags = 0;
+
+ SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
+ tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
+
+ if (skb_peek(&tp->out_of_order_queue) == NULL) {
+ /* Initial out of order segment, build 1 SACK. */
+ if(tp->sack_ok) {
+ tp->num_sacks = 1;
+ tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq;
+ tp->selective_acks[0].end_seq = TCP_SKB_CB(skb)->end_seq;
+ }
+ __skb_queue_head(&tp->out_of_order_queue,skb);
+ } else {
+ for(skb1=tp->out_of_order_queue.prev; ; skb1 = skb1->prev) {
+ /* Already there. */
+ if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb1)->seq) {
+ if (skb->len >= skb1->len) {
+ if(tp->sack_ok)
+ tcp_sack_extend(tp, skb1, skb);
+ __skb_append(skb1, skb);
+ __skb_unlink(skb1, skb1->list);
+ kfree_skb(skb1);
+ } else {
+ /* A duplicate, smaller than what is in the
+ * out-of-order queue right now, toss it.
+ */
+ kfree_skb(skb);
+ }
+ break;
+ }
+
+ if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb1)->seq)) {
+ __skb_append(skb1, skb);
+ if(tp->sack_ok)
+ tcp_sack_new_ofo_skb(sk, skb);
+ break;
+ }
+
+ /* See if we've hit the start. If so insert. */
+ if (skb1 == skb_peek(&tp->out_of_order_queue)) {
+ __skb_queue_head(&tp->out_of_order_queue,skb);
+ if(tp->sack_ok)
+ tcp_sack_new_ofo_skb(sk, skb);
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+ * This routine handles the data. If there is room in the buffer,
+ * it will be have already been moved into it. If there is no
+ * room, then we will just have to discard the packet.
+ */
+
+static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
+{
+ struct tcphdr *th;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ th = skb->h.th;
+ skb_pull(skb, th->doff*4);
+ skb_trim(skb, len - (th->doff*4));
+
+ if (skb->len == 0 && !th->fin)
+ return(0);
+
+ /*
+ * If our receive queue has grown past its limits shrink it.
+ * Make sure to do this before moving snd_nxt, otherwise
+ * data might be acked for that we don't have enough room.
+ */
+ if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) {
+ if (prune_queue(sk) < 0) {
+ /* Still not enough room. That can happen when
+ * skb->true_size differs significantly from skb->len.
+ */
+ return 0;
+ }
+ }
+
+ tcp_data_queue(sk, skb);
+
+ if (before(tp->rcv_nxt, tp->copied_seq)) {
+ printk(KERN_DEBUG "*** tcp.c:tcp_data bug acked < copied\n");
+ tp->rcv_nxt = tp->copied_seq;
+ }
+
+ /* Above, tcp_data_queue() increments delayed_acks appropriately.
+ * Now tell the user we may have some data.
+ */
+ if (!sk->dead) {
+ sk->data_ready(sk,0);
+ }
+ return(1);
+}
+
+static void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
+ tcp_packets_in_flight(tp) < tp->snd_cwnd) {
+ /* Put more data onto the wire. */
+ tcp_write_xmit(sk);
+ } else if (tp->packets_out == 0 && !tp->pending) {
+ /* Start probing the receivers window. */
+ tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
+ }
+}
+
+static __inline__ void tcp_data_snd_check(struct sock *sk)
+{
+ struct sk_buff *skb = sk->tp_pinfo.af_tcp.send_head;
+
+ if (skb != NULL)
+ __tcp_data_snd_check(sk, skb);
+}
+
+/*
+ * Adapt the MSS value used to make delayed ack decision to the
+ * real world.
+ */
+static __inline__ void tcp_measure_rcv_mss(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ unsigned int len = skb->len, lss;
+
+ if (len > tp->rcv_mss)
+ tp->rcv_mss = len;
+ lss = tp->last_seg_size;
+ tp->last_seg_size = 0;
+ if (len >= 536) {
+ if (len == lss)
+ tp->rcv_mss = len;
+ tp->last_seg_size = len;
+ }
+}
+
+/*
+ * Check if sending an ack is needed.
+ */
+static __inline__ void __tcp_ack_snd_check(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* This also takes care of updating the window.
+ * This if statement needs to be simplified.
+ *
+ * Rules for delaying an ack:
+ * - delay time <= 0.5 HZ
+ * - we don't have a window update to send
+ * - must send at least every 2 full sized packets
+ * - must send an ACK if we have any out of order data
+ *
+ * With an extra heuristic to handle loss of packet
+ * situations and also helping the sender leave slow
+ * start in an expediant manner.
+ */
+
+ /* Two full frames received or... */
+ if (((tp->rcv_nxt - tp->rcv_wup) >= tp->rcv_mss * MAX_DELAY_ACK) ||
+ /* We will update the window "significantly" or... */
+ tcp_raise_window(sk) ||
+ /* We entered "quick ACK" mode or... */
+ tcp_in_quickack_mode(tp) ||
+ /* We have out of order data */
+ (skb_peek(&tp->out_of_order_queue) != NULL)) {
+ /* Then ack it now */
+ tcp_send_ack(sk);
+ } else {
+ /* Else, send delayed ack. */
+ tcp_send_delayed_ack(tp, HZ/2);
+ }
+}
+
+static __inline__ void tcp_ack_snd_check(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ if (tp->delayed_acks == 0) {
+ /* We sent a data segment already. */
+ return;
+ }
+ __tcp_ack_snd_check(sk);
+}
+
+
+/*
+ * This routine is only called when we have urgent data
+ * signalled. Its the 'slow' part of tcp_urg. It could be
+ * moved inline now as tcp_urg is only called from one
+ * place. We handle URGent data wrong. We have to - as
+ * BSD still doesn't use the correction from RFC961.
+ * For 1003.1g we should support a new option TCP_STDURG to permit
+ * either form (or just set the sysctl tcp_stdurg).
+ */
+
+static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ u32 ptr = ntohs(th->urg_ptr);
+
+ if (ptr && !sysctl_tcp_stdurg)
+ ptr--;
+ ptr += ntohl(th->seq);
+
+ /* Ignore urgent data that we've already seen and read. */
+ if (after(tp->copied_seq, ptr))
+ return;
+
+ /* Do we already have a newer (or duplicate) urgent pointer? */
+ if (tp->urg_data && !after(ptr, tp->urg_seq))
+ return;
+
+ /* Tell the world about our new urgent pointer. */
+ if (sk->proc != 0) {
+ if (sk->proc > 0)
+ kill_proc(sk->proc, SIGURG, 1);
+ else
+ kill_pg(-sk->proc, SIGURG, 1);
+ }
+
+ /* We may be adding urgent data when the last byte read was
+ * urgent. To do this requires some care. We cannot just ignore
+ * tp->copied_seq since we would read the last urgent byte again
+ * as data, nor can we alter copied_seq until this data arrives
+ * or we break the sematics of SIOCATMARK (and thus sockatmark())
+ */
+ if (tp->urg_seq == tp->copied_seq)
+ tp->copied_seq++; /* Move the copied sequence on correctly */
+ tp->urg_data = URG_NOTYET;
+ tp->urg_seq = ptr;
+
+ /* Disable header prediction. */
+ tp->pred_flags = 0;
+}
+
+/* This is the 'fast' part of urgent handling. */
+static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Check if we get a new urgent pointer - normally not. */
+ if (th->urg)
+ tcp_check_urg(sk,th);
+
+ /* Do we wait for any urgent data? - normally not... */
+ if (tp->urg_data == URG_NOTYET) {
+ u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4);
+
+ /* Is the urgent pointer pointing into this packet? */
+ if (ptr < len) {
+ tp->urg_data = URG_VALID | *(ptr + (unsigned char *) th);
+ if (!sk->dead)
+ sk->data_ready(sk,0);
+ }
+ }
+}
+
+/* Clean the out_of_order queue if we can, trying to get
+ * the socket within its memory limits again.
+ *
+ * Return less than zero if we should start dropping frames
+ * until the socket owning process reads some of the data
+ * to stabilize the situation.
+ */
+static int prune_queue(struct sock *sk)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct sk_buff * skb;
+
+ SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq);
+
+ net_statistics.PruneCalled++;
+
+ /* First, purge the out_of_order queue. */
+ skb = __skb_dequeue_tail(&tp->out_of_order_queue);
+ if(skb != NULL) {
+ /* Free it all. */
+ do { net_statistics.OfoPruned += skb->len;
+ kfree_skb(skb);
+ skb = __skb_dequeue_tail(&tp->out_of_order_queue);
+ } while(skb != NULL);
+
+ /* Reset SACK state. A conforming SACK implementation will
+ * do the same at a timeout based retransmit. When a connection
+ * is in a sad state like this, we care only about integrity
+ * of the connection not performance.
+ */
+ if(tp->sack_ok)
+ tp->num_sacks = 0;
+ }
+
+ /* If we are really being abused, tell the caller to silently
+ * drop receive data on the floor. It will get retransmitted
+ * and hopefully then we'll have sufficient space.
+ *
+ * We used to try to purge the in-order packets too, but that
+ * turns out to be deadly and fraught with races. Consider:
+ *
+ * 1) If we acked the data, we absolutely cannot drop the
+ * packet. This data would then never be retransmitted.
+ * 2) It is possible, with a proper sequence of events involving
+ * delayed acks and backlog queue handling, to have the user
+ * read the data before it gets acked. The previous code
+ * here got this wrong, and it lead to data corruption.
+ * 3) Too much state changes happen when the FIN arrives, so once
+ * we've seen that we can't remove any in-order data safely.
+ *
+ * The net result is that removing in-order receive data is too
+ * complex for anyones sanity. So we don't do it anymore. But
+ * if we are really having our buffer space abused we stop accepting
+ * new receive data.
+ */
+ if(atomic_read(&sk->rmem_alloc) < (sk->rcvbuf << 1))
+ return 0;
+
+ /* Massive buffer overcommit. */
+ return -1;
+}
+
+/*
+ * TCP receive function for the ESTABLISHED state.
+ *
+ * It is split into a fast path and a slow path. The fast path is
+ * disabled when:
+ * - A zero window was announced from us - zero window probing
+ * is only handled properly in the slow path.
+ * - Out of order segments arrived.
+ * - Urgent data is expected.
+ * - There is no buffer space left
+ * - Unexpected TCP flags/window values/header lengths are received
+ * (detected by checking the TCP header against pred_flags)
+ * - Data is sent in both directions. Fast path only supports pure senders
+ * or pure receivers (this means either the sequence number or the ack
+ * value must stay constant)
+ *
+ * When these conditions are not satisfied it drops into a standard
+ * receive procedure patterned after RFC793 to handle all cases.
+ * The first three cases are guaranteed by proper pred_flags setting,
+ * the rest is checked inline. Fast processing is turned on in
+ * tcp_data_queue when everything is OK.
+ */
+int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
+ struct tcphdr *th, unsigned len)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int queued;
+ u32 flg;
+
+ /*
+ * Header prediction.
+ * The code follows the one in the famous
+ * "30 instruction TCP receive" Van Jacobson mail.
+ *
+ * Van's trick is to deposit buffers into socket queue
+ * on a device interrupt, to call tcp_recv function
+ * on the receive process context and checksum and copy
+ * the buffer to user space. smart...
+ *
+ * Our current scheme is not silly either but we take the
+ * extra cost of the net_bh soft interrupt processing...
+ * We do checksum and copy also but from device to kernel.
+ */
+
+ /*
+ * RFC1323: H1. Apply PAWS check first.
+ */
+ if (tcp_fast_parse_options(sk, th, tp)) {
+ if (tp->saw_tstamp) {
+ if (tcp_paws_discard(tp, th, len)) {
+ tcp_statistics.TcpInErrs++;
+ if (!th->rst) {
+ tcp_send_ack(sk);
+ goto discard;
+ }
+ }
+ tcp_replace_ts_recent(sk, tp,
+ TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->end_seq);
+ }
+ }
+
+ flg = *(((u32 *)th) + 3) & ~htonl(0xFC8 << 16);
+
+ /* pred_flags is 0xS?10 << 16 + snd_wnd
+ * if header_predition is to be made
+ * 'S' will always be tp->tcp_header_len >> 2
+ * '?' will be 0 else it will be !0
+ * (when there are holes in the receive
+ * space for instance)
+ * PSH flag is ignored.
+ */
+
+ if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
+ if (len <= th->doff*4) {
+ /* Bulk data transfer: sender */
+ if (len == th->doff*4) {
+ tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->ack_seq, len);
+ kfree_skb(skb);
+ tcp_data_snd_check(sk);
+ return 0;
+ } else { /* Header too small */
+ tcp_statistics.TcpInErrs++;
+ goto discard;
+ }
+ } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una &&
+ atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) {
+ /* Bulk data transfer: receiver */
+ __skb_pull(skb,th->doff*4);
+
+ tcp_measure_rcv_mss(sk, skb);
+
+ /* DO NOT notify forward progress here.
+ * It saves dozen of CPU instructions in fast path. --ANK
+ */
+ __skb_queue_tail(&sk->receive_queue, skb);
+ tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+
+ /* FIN bit check is not done since if FIN is set in
+ * this frame, the pred_flags won't match up. -DaveM
+ */
+ sk->data_ready(sk, 0);
+ tcp_delack_estimator(tp);
+
+ tcp_remember_ack(tp, th, skb);
+
+ __tcp_ack_snd_check(sk);
+ return 0;
+ }
+ }
+
+ /*
+ * Standard slow path.
+ */
+
+ if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
+ /* RFC793, page 37: "In all states except SYN-SENT, all reset
+ * (RST) segments are validated by checking their SEQ-fields."
+ * And page 69: "If an incoming segment is not acceptable,
+ * an acknowledgment should be sent in reply (unless the RST bit
+ * is set, if so drop the segment and return)".
+ */
+ if (th->rst)
+ goto discard;
+ if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
+ SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
+ TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
+ tp->rcv_wup, tp->rcv_wnd);
+ }
+ tcp_send_ack(sk);
+ goto discard;
+ }
+
+ if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
+ SOCK_DEBUG(sk, "syn in established state\n");
+ tcp_statistics.TcpInErrs++;
+ tcp_reset(sk);
+ return 1;
+ }
+
+ if(th->rst) {
+ tcp_reset(sk);
+ goto discard;
+ }
+
+ if(th->ack)
+ tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len);
+
+ /* Process urgent data. */
+ tcp_urg(sk, th, len);
+
+ /* step 7: process the segment text */
+ queued = tcp_data(skb, sk, len);
+
+ /* This must be after tcp_data() does the skb_pull() to
+ * remove the header size from skb->len.
+ *
+ * Dave!!! Phrase above (and all about rcv_mss) has
+ * nothing to do with reality. rcv_mss must measure TOTAL
+ * size, including sacks, IP options etc. Hence, measure_rcv_mss
+ * must occur before pulling etc, otherwise it will flap
+ * like hell. Even putting it before tcp_data is wrong,
+ * it should use skb->tail - skb->nh.raw instead.
+ * --ANK (980805)
+ *
+ * BTW I broke it. Now all TCP options are handled equally
+ * in mss_clamp calculations (i.e. ignored, rfc1122),
+ * and mss_cache does include all of them (i.e. tstamps)
+ * except for sacks, to calculate effective mss faster.
+ * --ANK (980805)
+ */
+ tcp_measure_rcv_mss(sk, skb);
+
+ /* Be careful, tcp_data() may have put this into TIME_WAIT. */
+ if(sk->state != TCP_CLOSE) {
+ tcp_data_snd_check(sk);
+ tcp_ack_snd_check(sk);
+ }
+
+ if (!queued) {
+ discard:
+ kfree_skb(skb);
+ }
+
+ return 0;
+}
+
+/*
+ * Process an incoming SYN or SYN-ACK for SYN_RECV sockets represented
+ * as an open_request.
+ */
+
+struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+ struct open_request *req)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ u32 flg;
+
+ /* assumption: the socket is not in use.
+ * as we checked the user count on tcp_rcv and we're
+ * running from a soft interrupt.
+ */
+
+ /* Check for syn retransmission */
+ flg = *(((u32 *)skb->h.th) + 3);
+
+ flg &= __constant_htonl(0x00170000);
+ /* Only SYN set? */
+ if (flg == __constant_htonl(0x00020000)) {
+ if (TCP_SKB_CB(skb)->seq == req->rcv_isn) {
+ /* retransmited syn.
+ */
+ req->class->rtx_syn_ack(sk, req);
+ return NULL;
+ } else {
+ return sk; /* Pass new SYN to the listen socket. */
+ }
+ }
+
+ /* We know it's an ACK here */
+ if (req->sk) {
+ /* socket already created but not
+ * yet accepted()...
+ */
+ sk = req->sk;
+ } else {
+ /* In theory the packet could be for a cookie, but
+ * TIME_WAIT should guard us against this.
+ * XXX: Nevertheless check for cookies?
+ * This sequence number check is done again later,
+ * but we do it here to prevent syn flood attackers
+ * from creating big SYN_RECV sockets.
+ */
+ if (!between(TCP_SKB_CB(skb)->ack_seq, req->snt_isn, req->snt_isn+1) ||
+ !between(TCP_SKB_CB(skb)->seq, req->rcv_isn,
+ req->rcv_isn+1+req->rcv_wnd)) {
+ req->class->send_reset(skb);
+ return NULL;
+ }
+
+ sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
+ tcp_dec_slow_timer(TCP_SLT_SYNACK);
+ if (sk == NULL)
+ return NULL;
+
+ req->expires = 0UL;
+ req->sk = sk;
+ }
+ skb_orphan(skb);
+ skb_set_owner_r(skb, sk);
+ return sk;
+}
+
+/*
+ * This function implements the receiving procedure of RFC 793 for
+ * all states except ESTABLISHED and TIME_WAIT.
+ * It's called from both tcp_v4_rcv and tcp_v6_rcv and should be
+ * address independent.
+ */
+
+int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
+ struct tcphdr *th, unsigned len)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ int queued = 0;
+
+ switch (sk->state) {
+ case TCP_CLOSE:
+ /* When state == CLOSED, hash lookup always fails.
+ *
+ * But, there is a back door, the backlog queue.
+ * If we have a sequence of packets in the backlog
+ * during __release_sock() which have a sequence such
+ * that:
+ * packet X causes entry to TCP_CLOSE state
+ * ...
+ * packet X + N has FIN bit set
+ *
+ * We report a (luckily) harmless error in this case.
+ * The issue is that backlog queue processing bypasses
+ * any hash lookups (we know which socket packets are for).
+ * The correct behavior here is what 2.0.x did, since
+ * a TCP_CLOSE socket does not exist. Drop the frame
+ * and send a RST back to the other end.
+ */
+ return 1;
+
+ case TCP_LISTEN:
+ /* These use the socket TOS..
+ * might want to be the received TOS
+ */
+ if(th->ack)
+ return 1;
+
+ if(th->syn) {
+ if(tp->af_specific->conn_request(sk, skb, 0) < 0)
+ return 1;
+
+ /* Now we have several options: In theory there is
+ * nothing else in the frame. KA9Q has an option to
+ * send data with the syn, BSD accepts data with the
+ * syn up to the [to be] advertised window and
+ * Solaris 2.1 gives you a protocol error. For now
+ * we just ignore it, that fits the spec precisely
+ * and avoids incompatibilities. It would be nice in
+ * future to drop through and process the data.
+ *
+ * Now that TTCP is starting to be used we ought to
+ * queue this data.
+ * But, this leaves one open to an easy denial of
+ * service attack, and SYN cookies can't defend
+ * against this problem. So, we drop the data
+ * in the interest of security over speed.
+ */
+ goto discard;
+ }
+
+ goto discard;
+ break;
+
+ case TCP_SYN_SENT:
+ /* SYN sent means we have to look for a suitable ack and
+ * either reset for bad matches or go to connected.
+ * The SYN_SENT case is unusual and should
+ * not be in line code. [AC]
+ */
+ if(th->ack) {
+ /* rfc793:
+ * "If the state is SYN-SENT then
+ * first check the ACK bit
+ * If the ACK bit is set
+ * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
+ * a reset (unless the RST bit is set, if so drop
+ * the segment and return)"
+ *
+ * I cite this place to emphasize one essential
+ * detail, this check is different of one
+ * in established state: SND.UNA <= SEG.ACK <= SND.NXT.
+ * SEG_ACK == SND.UNA == ISS is invalid in SYN-SENT,
+ * because we have no previous data sent before SYN.
+ * --ANK(990513)
+ *
+ * We do not send data with SYN, so that RFC-correct
+ * test reduces to:
+ */
+ if (sk->zapped ||
+ TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
+ return 1;
+
+ /* Now ACK is acceptable.
+ *
+ * "If the RST bit is set
+ * If the ACK was acceptable then signal the user "error:
+ * connection reset", drop the segment, enter CLOSED state,
+ * delete TCB, and return."
+ */
+
+ if (th->rst) {
+ tcp_reset(sk);
+ goto discard;
+ }
+
+ /* rfc793:
+ * "fifth, if neither of the SYN or RST bits is set then
+ * drop the segment and return."
+ *
+ * See note below!
+ * --ANK(990513)
+ */
+
+ if (!th->syn)
+ goto discard;
+
+ /* rfc793:
+ * "If the SYN bit is on ...
+ * are acceptable then ...
+ * (our SYN has been ACKed), change the connection
+ * state to ESTABLISHED..."
+ *
+ * Do you see? SYN-less ACKs in SYN-SENT state are
+ * completely ignored.
+ *
+ * The bug causing stalled SYN-SENT sockets
+ * was here: tcp_ack advanced snd_una and canceled
+ * retransmit timer, so that bare ACK received
+ * in SYN-SENT state (even with invalid ack==ISS,
+ * because tcp_ack check is too weak for SYN-SENT)
+ * causes moving socket to invalid semi-SYN-SENT,
+ * semi-ESTABLISHED state and connection hangs.
+ *
+ * There exist buggy stacks, which really send
+ * such ACKs: f.e. 202.226.91.94 (okigate.oki.co.jp)
+ * Actually, if this host did not try to get something
+ * from ftp.inr.ac.ru I'd never find this bug 8)
+ *
+ * --ANK (990514)
+ */
+
+ tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+ tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->ack_seq, len);
+
+ /* Ok.. it's good. Set up sequence numbers and
+ * move to established.
+ */
+ tp->rcv_nxt = TCP_SKB_CB(skb)->seq+1;
+ tp->rcv_wup = TCP_SKB_CB(skb)->seq+1;
+
+ /* RFC1323: The window in SYN & SYN/ACK segments is
+ * never scaled.
+ */
+ tp->snd_wnd = htons(th->window);
+ tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+ tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+ tp->fin_seq = TCP_SKB_CB(skb)->seq;
+
+ tcp_set_state(sk, TCP_ESTABLISHED);
+ tcp_parse_options(sk, th, tp, 0);
+
+ if (tp->wscale_ok == 0) {
+ tp->snd_wscale = tp->rcv_wscale = 0;
+ tp->window_clamp = min(tp->window_clamp,65535);
+ }
+
+ if (tp->tstamp_ok) {
+ tp->tcp_header_len =
+ sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+ } else
+ tp->tcp_header_len = sizeof(struct tcphdr);
+ if (tp->saw_tstamp) {
+ tp->ts_recent = tp->rcv_tsval;
+ tp->ts_recent_stamp = tcp_time_stamp;
+ }
+
+ /* Can't be earlier, doff would be wrong. */
+ tcp_send_ack(sk);
+
+ sk->dport = th->source;
+ tp->copied_seq = tp->rcv_nxt;
+
+ if(!sk->dead) {
+ sk->state_change(sk);
+ sock_wake_async(sk->socket, 0);
+ }
+ } else {
+ if(th->syn && !th->rst) {
+ /* The previous version of the code
+ * checked for "connecting to self"
+ * here. that check is done now in
+ * tcp_connect.
+ */
+ tcp_set_state(sk, TCP_SYN_RECV);
+ tcp_parse_options(sk, th, tp, 0);
+ if (tp->saw_tstamp) {
+ tp->ts_recent = tp->rcv_tsval;
+ tp->ts_recent_stamp = tcp_time_stamp;
+ }
+
+ tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+ tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
+
+ /* RFC1323: The window in SYN & SYN/ACK segments is
+ * never scaled.
+ */
+ tp->snd_wnd = htons(th->window);
+ tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+
+ tcp_send_synack(sk);
+ } else
+ break;
+ }
+
+ /* tp->tcp_header_len and tp->mss_clamp
+ probably changed, synchronize mss.
+ */
+ tcp_sync_mss(sk, tp->pmtu_cookie);
+ tp->rcv_mss = tp->mss_cache;
+
+ if (sk->state == TCP_SYN_RECV)
+ goto discard;
+
+ goto step6;
+ }
+
+ /* Parse the tcp_options present on this header.
+ * By this point we really only expect timestamps.
+ * Note that this really has to be here and not later for PAWS
+ * (RFC1323) to work.
+ */
+ if (tcp_fast_parse_options(sk, th, tp)) {
+ /* NOTE: assumes saw_tstamp is never set if we didn't
+ * negotiate the option. tcp_fast_parse_options() must
+ * guarantee this.
+ */
+ if (tp->saw_tstamp) {
+ if (tcp_paws_discard(tp, th, len)) {
+ tcp_statistics.TcpInErrs++;
+ if (!th->rst) {
+ tcp_send_ack(sk);
+ goto discard;
+ }
+ }
+ tcp_replace_ts_recent(sk, tp,
+ TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->end_seq);
+ }
+ }
+
+ /* The silly FIN test here is necessary to see an advancing ACK in
+ * retransmitted FIN frames properly. Consider the following sequence:
+ *
+ * host1 --> host2 FIN XSEQ:XSEQ(0) ack YSEQ
+ * host2 --> host1 FIN YSEQ:YSEQ(0) ack XSEQ
+ * host1 --> host2 XSEQ:XSEQ(0) ack YSEQ+1
+ * host2 --> host1 FIN YSEQ:YSEQ(0) ack XSEQ+1 (fails tcp_sequence test)
+ *
+ * At this point the connection will deadlock with host1 believing
+ * that his FIN is never ACK'd, and thus it will retransmit it's FIN
+ * forever. The following fix is from Taral (taral@taral.net).
+ */
+
+ /* step 1: check sequence number */
+ if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq) &&
+ !(th->fin && TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)) {
+ if (!th->rst) {
+ tcp_send_ack(sk);
+ }
+ goto discard;
+ }
+
+ /* step 2: check RST bit */
+ if(th->rst) {
+ tcp_reset(sk);
+ goto discard;
+ }
+
+ /* step 3: check security and precedence [ignored] */
+
+ /* step 4:
+ *
+ * Check for a SYN, and ensure it matches the SYN we were
+ * first sent. We have to handle the rather unusual (but valid)
+ * sequence that KA9Q derived products may generate of
+ *
+ * SYN
+ * SYN|ACK Data
+ * ACK (lost)
+ * SYN|ACK Data + More Data
+ * .. we must ACK not RST...
+ *
+ * We keep syn_seq as the sequence space occupied by the
+ * original syn.
+ */
+
+ if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
+ tcp_reset(sk);
+ return 1;
+ }
+
+ /* step 5: check the ACK field */
+ if (th->ack) {
+ int acceptable = tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
+ TCP_SKB_CB(skb)->ack_seq, len);
+
+ switch(sk->state) {
+ case TCP_SYN_RECV:
+ if (acceptable) {
+ tcp_set_state(sk, TCP_ESTABLISHED);
+ sk->dport = th->source;
+ tp->copied_seq = tp->rcv_nxt;
+
+ if(!sk->dead)
+ sk->state_change(sk);
+
+ tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
+ tp->snd_wnd = htons(th->window) << tp->snd_wscale;
+ tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+ tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+
+ } else {
+ SOCK_DEBUG(sk, "bad ack\n");
+ return 1;
+ }
+ break;
+
+ case TCP_FIN_WAIT1:
+ if (tp->snd_una == tp->write_seq) {
+ sk->shutdown |= SEND_SHUTDOWN;
+ tcp_set_state(sk, TCP_FIN_WAIT2);
+ if (!sk->dead)
+ sk->state_change(sk);
+ else
+ tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
+ }
+ break;
+
+ case TCP_CLOSING:
+ if (tp->snd_una == tp->write_seq) {
+ tcp_time_wait(sk);
+ goto discard;
+ }
+ break;
+
+ case TCP_LAST_ACK:
+ if (tp->snd_una == tp->write_seq) {
+ sk->shutdown = SHUTDOWN_MASK;
+ tcp_set_state(sk,TCP_CLOSE);
+ if (!sk->dead)
+ sk->state_change(sk);
+ goto discard;
+ }
+ break;
+ }
+ } else
+ goto discard;
+
+step6:
+ /* step 6: check the URG bit */
+ tcp_urg(sk, th, len);
+
+ /* step 7: process the segment text */
+ switch (sk->state) {
+ case TCP_CLOSE_WAIT:
+ case TCP_CLOSING:
+ if (!before(TCP_SKB_CB(skb)->seq, tp->fin_seq))
+ break;
+
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ /* RFC 793 says to queue data in these states,
+ * RFC 1122 says we MUST send a reset.
+ * BSD 4.4 also does reset.
+ */
+ if ((sk->shutdown & RCV_SHUTDOWN) && sk->dead) {
+ if (after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
+ tcp_reset(sk);
+ return 1;
+ }
+ }
+
+ case TCP_ESTABLISHED:
+ queued = tcp_data(skb, sk, len);
+
+ /* This must be after tcp_data() does the skb_pull() to
+ * remove the header size from skb->len.
+ */
+ tcp_measure_rcv_mss(sk, skb);
+ break;
+ }
+
+ tcp_data_snd_check(sk);
+ tcp_ack_snd_check(sk);
+
+ if (!queued) {
+discard:
+ kfree_skb(skb);
+ }
+ return 0;
+}
diff --git a/pfinet/linux-src/net/ipv4/tcp_ipv4.c b/pfinet/linux-src/net/ipv4/tcp_ipv4.c
new file mode 100644
index 00000000..99194238
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/tcp_ipv4.c
@@ -0,0 +1,2052 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Implementation of the Transmission Control Protocol(TCP).
+ *
+ * Version: $Id: tcp_ipv4.c,v 1.175.2.13 1999/11/16 06:33:53 davem Exp $
+ *
+ * IPv4 specific functions
+ *
+ *
+ * code split from:
+ * linux/ipv4/tcp.c
+ * linux/ipv4/tcp_input.c
+ * linux/ipv4/tcp_output.c
+ *
+ * See tcp.c for author information
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Changes:
+ * David S. Miller : New socket lookup architecture.
+ * This code is dedicated to John Dyson.
+ * David S. Miller : Change semantics of established hash,
+ * half is devoted to TIME_WAIT sockets
+ * and the rest go in the other half.
+ * Andi Kleen : Add support for syncookies and fixed
+ * some bugs: ip options weren't passed to
+ * the TCP layer, missed a check for an ACK bit.
+ * Andi Kleen : Implemented fast path mtu discovery.
+ * Fixed many serious bugs in the
+ * open_request handling and moved
+ * most of it into the af independent code.
+ * Added tail drop and some other bugfixes.
+ * Added new listen sematics.
+ * Mike McLagan : Routing by source
+ * Juan Jose Ciarlante: ip_dynaddr bits
+ * Andi Kleen: various fixes.
+ * Vitaly E. Lavrov : Transparent proxy revived after year coma.
+ * Andi Kleen : Fix new listen.
+ * Andi Kleen : Fix accept error reporting.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/ipsec.h>
+
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+
+#include <asm/segment.h>
+
+#include <linux/inet.h>
+#include <linux/stddef.h>
+
+extern int sysctl_tcp_timestamps;
+extern int sysctl_tcp_window_scaling;
+extern int sysctl_tcp_sack;
+extern int sysctl_tcp_syncookies;
+extern int sysctl_ip_dynaddr;
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
+
+/* Check TCP sequence numbers in ICMP packets. */
+#define ICMP_MIN_LENGTH 8
+
+/* Socket used for sending RSTs */
+struct inode tcp_inode;
+struct socket *tcp_socket=&tcp_inode.u.socket_i;
+
+static void tcp_v4_send_reset(struct sk_buff *skb);
+
+void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
+ struct sk_buff *skb);
+
+/* This is for sockets with full identity only. Sockets here will always
+ * be without wildcards and will have the following invariant:
+ * TCP_ESTABLISHED <= sk->state < TCP_CLOSE
+ *
+ * First half of the table is for sockets not in TIME_WAIT, second half
+ * is for TIME_WAIT sockets only.
+ */
+unsigned int tcp_ehash_size;
+struct sock **tcp_ehash;
+
+/* Ok, let's try this, I give up, we do need a local binding
+ * TCP hash as well as the others for fast bind/connect.
+ */
+unsigned int tcp_bhash_size;
+struct tcp_bind_bucket **tcp_bhash;
+
+/* All sockets in TCP_LISTEN state will be in here. This is the only table
+ * where wildcard'd TCP sockets can exist. Hash function here is just local
+ * port number.
+ */
+struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
+
+/* Register cache. */
+struct sock *tcp_regs[TCP_NUM_REGS];
+
+/*
+ * This array holds the first and last local port number.
+ * For high-usage systems, use sysctl to change this to
+ * 32768-61000
+ */
+int sysctl_local_port_range[2] = { 1024, 4999 };
+int tcp_port_rover = (1024 - 1);
+
+static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
+ __u32 faddr, __u16 fport)
+{
+ return ((laddr ^ lport) ^ (faddr ^ fport)) & ((tcp_ehash_size/2) - 1);
+}
+
+static __inline__ int tcp_sk_hashfn(struct sock *sk)
+{
+ __u32 laddr = sk->rcv_saddr;
+ __u16 lport = sk->num;
+ __u32 faddr = sk->daddr;
+ __u16 fport = sk->dport;
+
+ return tcp_hashfn(laddr, lport, faddr, fport);
+}
+
+/* Allocate and initialize a new TCP local port bind bucket.
+ * Always runs inside the socket hashing lock.
+ */
+struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
+{
+ struct tcp_bind_bucket *tb;
+
+ tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC);
+ if(tb != NULL) {
+ struct tcp_bind_bucket **head =
+ &tcp_bhash[tcp_bhashfn(snum)];
+ tb->port = snum;
+ tb->fastreuse = 0;
+ tb->owners = NULL;
+ if((tb->next = *head) != NULL)
+ tb->next->pprev = &tb->next;
+ *head = tb;
+ tb->pprev = head;
+ }
+ return tb;
+}
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+/* Ensure that the bound bucket for the port exists.
+ * Return 0 and bump bucket reference count on success.
+ *
+ * Must run in a BH atomic section.
+ */
+static __inline__ int __tcp_bucket_check(unsigned short snum)
+{
+ struct tcp_bind_bucket *tb;
+
+ tb = tcp_bhash[tcp_bhashfn(snum)];
+ for( ; (tb && (tb->port != snum)); tb = tb->next)
+ ;
+ if (tb == NULL) {
+ if ((tb = tcp_bucket_create(snum)) == NULL)
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child)
+{
+ struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *)sk->prev;
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (child->num != sk->num) {
+ unsigned short snum = child->num;
+ for(tb = tcp_bhash[tcp_bhashfn(snum)];
+ tb && tb->port != snum;
+ tb = tb->next)
+ ;
+ if (tb == NULL)
+ tb = (struct tcp_bind_bucket *)sk->prev;
+ }
+#endif
+ if ((child->bind_next = tb->owners) != NULL)
+ tb->owners->bind_pprev = &child->bind_next;
+ tb->owners = child;
+ child->bind_pprev = &tb->owners;
+ child->prev = (struct sock *) tb;
+}
+
+__inline__ void tcp_inherit_port(struct sock *sk, struct sock *child)
+{
+ SOCKHASH_LOCK();
+ __tcp_inherit_port(sk, child);
+ SOCKHASH_UNLOCK();
+}
+
+/* Obtain a reference to a local port for the given sock,
+ * if snum is zero it means select any available local port.
+ */
+static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
+{
+ struct tcp_bind_bucket *tb;
+
+ SOCKHASH_LOCK();
+ if (snum == 0) {
+ int rover = tcp_port_rover;
+ int low = sysctl_local_port_range[0];
+ int high = sysctl_local_port_range[1];
+ int remaining = (high - low) + 1;
+
+ do { rover++;
+ if ((rover < low) || (rover > high))
+ rover = low;
+ tb = tcp_bhash[tcp_bhashfn(rover)];
+ for ( ; tb; tb = tb->next)
+ if (tb->port == rover)
+ goto next;
+ break;
+ next:
+ ; /* Do nothing. */
+ } while (--remaining > 0);
+ tcp_port_rover = rover;
+
+ /* Exhausted local port range during search? */
+ if (remaining <= 0)
+ goto fail;
+
+ /* OK, here is the one we will use. */
+ snum = rover;
+ tb = NULL;
+ } else {
+ for (tb = tcp_bhash[tcp_bhashfn(snum)];
+ tb != NULL;
+ tb = tb->next)
+ if (tb->port == snum)
+ break;
+ }
+ if (tb != NULL && tb->owners != NULL) {
+ if (tb->fastreuse != 0 && sk->reuse != 0) {
+ goto success;
+ } else {
+ struct sock *sk2 = tb->owners;
+ int sk_reuse = sk->reuse;
+
+ for( ; sk2 != NULL; sk2 = sk2->bind_next) {
+ if (sk->bound_dev_if == sk2->bound_dev_if) {
+ if (!sk_reuse ||
+ !sk2->reuse ||
+ sk2->state == TCP_LISTEN) {
+ if (!sk2->rcv_saddr ||
+ !sk->rcv_saddr ||
+ (sk2->rcv_saddr == sk->rcv_saddr))
+ break;
+ }
+ }
+ }
+ /* If we found a conflict, fail. */
+ if (sk2 != NULL)
+ goto fail;
+ }
+ }
+ if (tb == NULL &&
+ (tb = tcp_bucket_create(snum)) == NULL)
+ goto fail;
+ if (tb->owners == NULL) {
+ if (sk->reuse && sk->state != TCP_LISTEN)
+ tb->fastreuse = 1;
+ else
+ tb->fastreuse = 0;
+ } else if (tb->fastreuse &&
+ ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
+ tb->fastreuse = 0;
+success:
+ sk->num = snum;
+ if ((sk->bind_next = tb->owners) != NULL)
+ tb->owners->bind_pprev = &sk->bind_next;
+ tb->owners = sk;
+ sk->bind_pprev = &tb->owners;
+ sk->prev = (struct sock *) tb;
+
+ SOCKHASH_UNLOCK();
+ return 0;
+
+fail:
+ SOCKHASH_UNLOCK();
+ return 1;
+}
+
+/* Get rid of any references to a local port held by the
+ * given sock.
+ */
+__inline__ void __tcp_put_port(struct sock *sk)
+{
+ struct tcp_bind_bucket *tb;
+
+ tb = (struct tcp_bind_bucket *) sk->prev;
+ if (sk->bind_next)
+ sk->bind_next->bind_pprev = sk->bind_pprev;
+ *(sk->bind_pprev) = sk->bind_next;
+ sk->prev = NULL;
+ if (tb->owners == NULL) {
+ if (tb->next)
+ tb->next->pprev = tb->pprev;
+ *(tb->pprev) = tb->next;
+ kmem_cache_free(tcp_bucket_cachep, tb);
+ }
+}
+
+void tcp_put_port(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ __tcp_put_port(sk);
+ SOCKHASH_UNLOCK();
+}
+
+static __inline__ void __tcp_v4_hash(struct sock *sk)
+{
+ struct sock **skp;
+
+ if(sk->state == TCP_LISTEN)
+ skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+ else
+ skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
+
+ if((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+}
+
+static void tcp_v4_hash(struct sock *sk)
+{
+ if (sk->state != TCP_CLOSE) {
+ SOCKHASH_LOCK();
+ __tcp_v4_hash(sk);
+ SOCKHASH_UNLOCK();
+ }
+}
+
+static void tcp_v4_unhash(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if(sk->pprev) {
+ if(sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ tcp_reg_zap(sk);
+ __tcp_put_port(sk);
+ }
+ SOCKHASH_UNLOCK();
+}
+
+/* Don't inline this cruft. Here are some nice properties to
+ * exploit here. The BSD API does not allow a listening TCP
+ * to specify the remote port nor the remote address for the
+ * connection. So always assume those are both wildcarded
+ * during the search since they can never be otherwise.
+ */
+static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int dif)
+{
+ struct sock *sk;
+ struct sock *result = NULL;
+ int score, hiscore;
+
+ hiscore=0;
+ for(sk = tcp_listening_hash[tcp_lhashfn(hnum)]; sk; sk = sk->next) {
+ if(sk->num == hnum) {
+ __u32 rcv_saddr = sk->rcv_saddr;
+
+ score = 1;
+ if(rcv_saddr) {
+ if (rcv_saddr != daddr)
+ continue;
+ score++;
+ }
+ if (sk->bound_dev_if) {
+ if (sk->bound_dev_if != dif)
+ continue;
+ score++;
+ }
+ if (score == 3)
+ return sk;
+ if (score > hiscore) {
+ hiscore = score;
+ result = sk;
+ }
+ }
+ }
+ return result;
+}
+
+/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
+ * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ * It is assumed that this code only gets called from within NET_BH.
+ */
+static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
+ u32 saddr, u16 sport,
+ u32 daddr, u16 dport, int dif)
+{
+ TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
+ __u16 hnum = ntohs(dport);
+ __u32 ports = TCP_COMBINED_PORTS(sport, hnum);
+ struct sock *sk;
+ int hash;
+
+ /* Check TCP register quick cache first. */
+ sk = TCP_RHASH(sport);
+ if(sk && TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
+ goto hit;
+
+ /* Optimize here for direct hit, only listening connections can
+ * have wildcards anyways.
+ */
+ hash = tcp_hashfn(daddr, hnum, saddr, sport);
+ for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
+ if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) {
+ if (sk->state == TCP_ESTABLISHED)
+ TCP_RHASH(sport) = sk;
+ goto hit; /* You sunk my battleship! */
+ }
+ }
+ /* Must check for a TIME_WAIT'er before going to listener hash. */
+ for(sk = tcp_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next)
+ if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
+ goto hit;
+ sk = tcp_v4_lookup_listener(daddr, hnum, dif);
+hit:
+ return sk;
+}
+
+__inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
+{
+ return __tcp_v4_lookup(0, saddr, sport, daddr, dport, dif);
+}
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+/* Cleaned up a little and adapted to new bind bucket scheme.
+ * Oddly, this should increase performance here for
+ * transparent proxy, as tests within the inner loop have
+ * been eliminated. -DaveM
+ */
+static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
+ unsigned short rnum, unsigned long laddr,
+ struct device *dev, unsigned short pnum,
+ int dif)
+{
+ struct sock *s, *result = NULL;
+ int badness = -1;
+ u32 paddr = 0;
+ unsigned short hnum = ntohs(num);
+ unsigned short hpnum = ntohs(pnum);
+ int firstpass = 1;
+
+ if(dev && dev->ip_ptr) {
+ struct in_device *idev = dev->ip_ptr;
+
+ if(idev->ifa_list)
+ paddr = idev->ifa_list->ifa_local;
+ }
+
+ /* This code must run only from NET_BH. */
+ {
+ struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hnum)];
+ for( ; (tb && tb->port != hnum); tb = tb->next)
+ ;
+ if(tb == NULL)
+ goto next;
+ s = tb->owners;
+ }
+pass2:
+ for(; s; s = s->bind_next) {
+ int score = 0;
+ if(s->rcv_saddr) {
+ if((s->num != hpnum || s->rcv_saddr != paddr) &&
+ (s->num != hnum || s->rcv_saddr != laddr))
+ continue;
+ score++;
+ }
+ if(s->daddr) {
+ if(s->daddr != raddr)
+ continue;
+ score++;
+ }
+ if(s->dport) {
+ if(s->dport != rnum)
+ continue;
+ score++;
+ }
+ if(s->bound_dev_if) {
+ if(s->bound_dev_if != dif)
+ continue;
+ score++;
+ }
+ if(score == 4 && s->num == hnum) {
+ result = s;
+ goto gotit;
+ } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
+ result = s;
+ badness = score;
+ }
+ }
+next:
+ if(firstpass--) {
+ struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hpnum)];
+ for( ; (tb && tb->port != hpnum); tb = tb->next)
+ ;
+ if(tb) {
+ s = tb->owners;
+ goto pass2;
+ }
+ }
+gotit:
+ return result;
+}
+#endif /* CONFIG_IP_TRANSPARENT_PROXY */
+
+static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
+{
+ return secure_tcp_sequence_number(skb->nh.iph->daddr,
+ skb->nh.iph->saddr,
+ skb->h.th->dest,
+ skb->h.th->source);
+}
+
+/* Check that a TCP address is unique, don't allow multiple
+ * connects to/from the same address. Actually we can optimize
+ * quite a bit, since the socket about to connect is still
+ * in TCP_CLOSE, a tcp_bind_bucket for the local port he will
+ * use will exist, with a NULL owners list. So check for that.
+ * The good_socknum and verify_bind scheme we use makes this
+ * work.
+ */
+static int tcp_v4_unique_address(struct sock *sk)
+{
+ struct tcp_bind_bucket *tb;
+ unsigned short snum = sk->num;
+ int retval = 1;
+
+ /* Freeze the hash while we snoop around. */
+ SOCKHASH_LOCK();
+ tb = tcp_bhash[tcp_bhashfn(snum)];
+ for(; tb; tb = tb->next) {
+ if(tb->port == snum && tb->owners != NULL) {
+ /* Almost certainly the re-use port case, search the real hashes
+ * so it actually scales.
+ */
+ sk = __tcp_v4_lookup(NULL, sk->daddr, sk->dport,
+ sk->rcv_saddr, htons(snum),
+ sk->bound_dev_if);
+ if((sk != NULL) && (sk->state != TCP_LISTEN))
+ retval = 0;
+ break;
+ }
+ }
+ SOCKHASH_UNLOCK();
+ return retval;
+}
+
+/* This will initiate an outgoing connection. */
+int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+ struct sk_buff *buff;
+ struct rtable *rt;
+ u32 daddr, nexthop;
+ int tmp;
+
+ if (sk->state != TCP_CLOSE)
+ return(-EISCONN);
+
+ /* Don't allow a double connect. */
+ if (sk->daddr)
+ return -EINVAL;
+
+ if (addr_len < sizeof(struct sockaddr_in))
+ return(-EINVAL);
+
+ if (usin->sin_family != AF_INET) {
+ static int complained;
+ if (usin->sin_family)
+ return(-EAFNOSUPPORT);
+ if (!complained++)
+ printk(KERN_DEBUG "%s forgot to set AF_INET in %s\n", current->comm, __FUNCTION__);
+ }
+
+ nexthop = daddr = usin->sin_addr.s_addr;
+ if (sk->opt && sk->opt->srr) {
+ if (daddr == 0)
+ return -EINVAL;
+ nexthop = sk->opt->faddr;
+ }
+
+ tmp = ip_route_connect(&rt, nexthop, sk->saddr,
+ RT_TOS(sk->ip_tos)|RTO_CONN|sk->localroute, sk->bound_dev_if);
+ if (tmp < 0)
+ return tmp;
+
+ if (rt->rt_flags&(RTCF_MULTICAST|RTCF_BROADCAST)) {
+ ip_rt_put(rt);
+ return -ENETUNREACH;
+ }
+
+ dst_release(xchg(&sk->dst_cache, &rt->u.dst));
+
+ buff = sock_wmalloc(sk, (MAX_HEADER + sk->prot->max_header),
+ 0, GFP_KERNEL);
+
+ if (buff == NULL)
+ return -ENOBUFS;
+
+ /* Socket has no identity, so lock_sock() is useless. Also
+ * since state==TCP_CLOSE (checked above) the socket cannot
+ * possibly be in the hashes. TCP hash locking is only
+ * needed while checking quickly for a unique address.
+ * However, the socket does need to be (and is) locked
+ * in tcp_connect().
+ * Perhaps this addresses all of ANK's concerns. 8-) -DaveM
+ */
+ sk->dport = usin->sin_port;
+ sk->daddr = rt->rt_dst;
+ if (sk->opt && sk->opt->srr)
+ sk->daddr = daddr;
+ if (!sk->saddr)
+ sk->saddr = rt->rt_src;
+ sk->rcv_saddr = sk->saddr;
+
+ if (!tcp_v4_unique_address(sk)) {
+ kfree_skb(buff);
+ sk->daddr = 0;
+ return -EADDRNOTAVAIL;
+ }
+
+ tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
+ sk->sport, usin->sin_port);
+
+ tp->ext_header_len = 0;
+ if (sk->opt)
+ tp->ext_header_len = sk->opt->optlen;
+
+ /* Reset mss clamp */
+ tp->mss_clamp = ~0;
+
+ if (!ip_dont_fragment(sk, &rt->u.dst) &&
+ rt->u.dst.pmtu > 576 && rt->rt_dst != rt->rt_gateway) {
+ /* Clamp mss at maximum of 536 and user_mss.
+ Probably, user ordered to override tiny segment size
+ in gatewayed case.
+ */
+ tp->mss_clamp = max(tp->user_mss, 536);
+ }
+
+ tcp_connect(sk, buff, rt->u.dst.pmtu);
+ return 0;
+}
+
+static int tcp_v4_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+{
+ int retval = -EINVAL;
+
+ /* Do sanity checking for sendmsg/sendto/send. */
+ if (msg->msg_flags & ~(MSG_OOB|MSG_DONTROUTE|MSG_DONTWAIT|MSG_NOSIGNAL))
+ goto out;
+ if (msg->msg_name) {
+ struct sockaddr_in *addr=(struct sockaddr_in *)msg->msg_name;
+
+ if (msg->msg_namelen < sizeof(*addr))
+ goto out;
+ if (addr->sin_family && addr->sin_family != AF_INET)
+ goto out;
+ retval = -ENOTCONN;
+ if(sk->state == TCP_CLOSE)
+ goto out;
+ retval = -EISCONN;
+ if (addr->sin_port != sk->dport)
+ goto out;
+ if (addr->sin_addr.s_addr != sk->daddr)
+ goto out;
+ }
+ retval = tcp_do_sendmsg(sk, msg);
+
+out:
+ return retval;
+}
+
+
+/*
+ * Do a linear search in the socket open_request list.
+ * This should be replaced with a global hash table.
+ */
+static struct open_request *tcp_v4_search_req(struct tcp_opt *tp,
+ struct iphdr *iph,
+ struct tcphdr *th,
+ struct open_request **prevp)
+{
+ struct open_request *req, *prev;
+ __u16 rport = th->source;
+
+ /* assumption: the socket is not in use.
+ * as we checked the user count on tcp_rcv and we're
+ * running from a soft interrupt.
+ */
+ prev = (struct open_request *) (&tp->syn_wait_queue);
+ for (req = prev->dl_next; req; req = req->dl_next) {
+ if (req->af.v4_req.rmt_addr == iph->saddr &&
+ req->af.v4_req.loc_addr == iph->daddr &&
+ req->rmt_port == rport
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ && req->lcl_port == th->dest
+#endif
+ ) {
+ *prevp = prev;
+ return req;
+ }
+ prev = req;
+ }
+ return NULL;
+}
+
+
+/*
+ * This routine does path mtu discovery as defined in RFC1191.
+ */
+static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip, unsigned mtu)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ if (atomic_read(&sk->sock_readers))
+ return;
+
+ /* Don't interested in TCP_LISTEN and open_requests (SYN-ACKs
+ * send out by Linux are always <576bytes so they should go through
+ * unfragmented).
+ */
+ if (sk->state == TCP_LISTEN)
+ return;
+
+ /* We don't check in the destentry if pmtu discovery is forbidden
+ * on this route. We just assume that no packet_to_big packets
+ * are send back when pmtu discovery is not active.
+ * There is a small race when the user changes this flag in the
+ * route, but I think that's acceptable.
+ */
+ if (sk->dst_cache == NULL)
+ return;
+ ip_rt_update_pmtu(sk->dst_cache, mtu);
+ if (sk->ip_pmtudisc != IP_PMTUDISC_DONT &&
+ tp->pmtu_cookie > sk->dst_cache->pmtu) {
+ tcp_sync_mss(sk, sk->dst_cache->pmtu);
+
+ /* Resend the TCP packet because it's
+ * clear that the old packet has been
+ * dropped. This is the new "fast" path mtu
+ * discovery.
+ */
+ tcp_simple_retransmit(sk);
+ } /* else let the usual retransmit timer handle it */
+}
+
+/*
+ * This routine is called by the ICMP module when it gets some
+ * sort of error condition. If err < 0 then the socket should
+ * be closed and the error returned to the user. If err > 0
+ * it's just the icmp type << 8 | icmp code. After adjustment
+ * header points to the first 8 bytes of the tcp header. We need
+ * to find the appropriate port.
+ *
+ * The locking strategy used here is very "optimistic". When
+ * someone else accesses the socket the ICMP is just dropped
+ * and for some paths there is no check at all.
+ * A more general error queue to queue errors for later handling
+ * is probably better.
+ *
+ * sk->err and sk->err_soft should be atomic_t.
+ */
+
+void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
+{
+ struct iphdr *iph = (struct iphdr*)dp;
+ struct tcphdr *th;
+ struct tcp_opt *tp;
+ int type = skb->h.icmph->type;
+ int code = skb->h.icmph->code;
+#if ICMP_MIN_LENGTH < 14
+ int no_flags = 0;
+#else
+#define no_flags 0
+#endif
+ struct sock *sk;
+ __u32 seq;
+ int err;
+
+ if (len < (iph->ihl << 2) + ICMP_MIN_LENGTH) {
+ icmp_statistics.IcmpInErrors++;
+ return;
+ }
+#if ICMP_MIN_LENGTH < 14
+ if (len < (iph->ihl << 2) + 14)
+ no_flags = 1;
+#endif
+
+ th = (struct tcphdr*)(dp+(iph->ihl<<2));
+
+ sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex);
+ if (sk == NULL || sk->state == TCP_TIME_WAIT) {
+ icmp_statistics.IcmpInErrors++;
+ return;
+ }
+
+ tp = &sk->tp_pinfo.af_tcp;
+ seq = ntohl(th->seq);
+ if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) {
+ net_statistics.OutOfWindowIcmps++;
+ return;
+ }
+
+ switch (type) {
+ case ICMP_SOURCE_QUENCH:
+#ifndef OLD_SOURCE_QUENCH /* This is deprecated */
+ tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+ tp->snd_cwnd = tp->snd_ssthresh;
+ tp->snd_cwnd_cnt = 0;
+ tp->high_seq = tp->snd_nxt;
+#endif
+ return;
+ case ICMP_PARAMETERPROB:
+ err = EPROTO;
+ break;
+ case ICMP_DEST_UNREACH:
+ if (code > NR_ICMP_UNREACH)
+ return;
+
+ if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
+ do_pmtu_discovery(sk, iph, ntohs(skb->h.icmph->un.frag.mtu));
+ return;
+ }
+
+ err = icmp_err_convert[code].errno;
+ break;
+ case ICMP_TIME_EXCEEDED:
+ err = EHOSTUNREACH;
+ break;
+ default:
+ return;
+ }
+
+ switch (sk->state) {
+ struct open_request *req, *prev;
+ case TCP_LISTEN:
+ /* Prevent race conditions with accept() -
+ * ICMP is unreliable.
+ */
+ if (atomic_read(&sk->sock_readers)) {
+ net_statistics.LockDroppedIcmps++;
+ /* If too many ICMPs get dropped on busy
+ * servers this needs to be solved differently.
+ */
+ return;
+ }
+
+ /* The final ACK of the handshake should be already
+ * handled in the new socket context, not here.
+ * Strictly speaking - an ICMP error for the final
+ * ACK should set the opening flag, but that is too
+ * complicated right now.
+ */
+ if (!no_flags && !th->syn && !th->ack)
+ return;
+
+ req = tcp_v4_search_req(tp, iph, th, &prev);
+ if (!req)
+ return;
+ if (seq != req->snt_isn) {
+ net_statistics.OutOfWindowIcmps++;
+ return;
+ }
+ if (req->sk) {
+ /*
+ * Already in ESTABLISHED and a big socket is created,
+ * set error code there.
+ * The error will _not_ be reported in the accept(),
+ * but only with the next operation on the socket after
+ * accept.
+ */
+ sk = req->sk;
+ } else {
+ /*
+ * Still in SYN_RECV, just remove it silently.
+ * There is no good way to pass the error to the newly
+ * created socket, and POSIX does not want network
+ * errors returned from accept().
+ */
+ tp->syn_backlog--;
+ tcp_synq_unlink(tp, req, prev);
+ req->class->destructor(req);
+ tcp_openreq_free(req);
+ return;
+ }
+ break;
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV: /* Cannot happen */
+ if (!no_flags && !th->syn)
+ return;
+ tcp_statistics.TcpAttemptFails++;
+ sk->err = err;
+ sk->zapped = 1;
+ mb();
+ sk->error_report(sk);
+ return;
+ }
+
+ /* If we've already connected we will keep trying
+ * until we time out, or the user gives up.
+ *
+ * rfc1122 4.2.3.9 allows to consider as hard errors
+ * only PROTO_UNREACH and PORT_UNREACH (well, FRAG_FAILED too,
+ * but it is obsoleted by pmtu discovery).
+ *
+ * Note, that in modern internet, where routing is unreliable
+ * and in each dark corner broken firewalls sit, sending random
+ * errors ordered by their masters even this two messages finally lose
+ * their original sense (even Linux sends invalid PORT_UNREACHs)
+ *
+ * Now we are in compliance with RFCs.
+ * --ANK (980905)
+ */
+
+ if (sk->ip_recverr) {
+ /* This code isn't serialized with the socket code */
+ /* ANK (980927) ... which is harmless now,
+ sk->err's may be safely lost.
+ */
+ sk->err = err;
+ mb();
+ sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
+ } else { /* Only an error on timeout */
+ sk->err_soft = err;
+ mb();
+ }
+}
+
+/* This routine computes an IPv4 TCP checksum. */
+void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
+ struct sk_buff *skb)
+{
+ th->check = 0;
+ th->check = tcp_v4_check(th, len, sk->saddr, sk->daddr,
+ csum_partial((char *)th, th->doff<<2, skb->csum));
+}
+
+/*
+ * This routine will send an RST to the other tcp.
+ *
+ * Someone asks: why I NEVER use socket parameters (TOS, TTL etc.)
+ * for reset.
+ * Answer: if a packet caused RST, it is not for a socket
+ * existing in our system, if it is matched to a socket,
+ * it is just duplicate segment or bug in other side's TCP.
+ * So that we build reply only basing on parameters
+ * arrived with segment.
+ * Exception: precedence violation. We do not implement it in any case.
+ */
+
+static void tcp_v4_send_reset(struct sk_buff *skb)
+{
+ struct tcphdr *th = skb->h.th;
+ struct tcphdr rth;
+ struct ip_reply_arg arg;
+
+ /* Never send a reset in response to a reset. */
+ if (th->rst)
+ return;
+
+ if (((struct rtable*)skb->dst)->rt_type != RTN_LOCAL) {
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (((struct rtable*)skb->dst)->rt_type == RTN_UNICAST)
+ icmp_send(skb, ICMP_DEST_UNREACH,
+ ICMP_PORT_UNREACH, 0);
+#endif
+ return;
+ }
+
+ /* Swap the send and the receive. */
+ memset(&rth, 0, sizeof(struct tcphdr));
+ rth.dest = th->source;
+ rth.source = th->dest;
+ rth.doff = sizeof(struct tcphdr)/4;
+ rth.rst = 1;
+
+ if (th->ack) {
+ rth.seq = th->ack_seq;
+ } else {
+ rth.ack = 1;
+ rth.ack_seq = th->syn ? htonl(ntohl(th->seq)+1) : th->seq;
+ }
+
+ memset(&arg, 0, sizeof arg);
+ arg.iov[0].iov_base = (unsigned char *)&rth;
+ arg.iov[0].iov_len = sizeof rth;
+ arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,
+ skb->nh.iph->saddr, /*XXX*/
+ sizeof(struct tcphdr),
+ IPPROTO_TCP,
+ 0);
+ arg.n_iov = 1;
+ arg.csumoffset = offsetof(struct tcphdr, check) / 2;
+
+ ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
+
+ tcp_statistics.TcpOutSegs++;
+ tcp_statistics.TcpOutRsts++;
+}
+
+/*
+ * Send an ACK for a socket less packet (needed for time wait)
+ *
+ * FIXME: Does not echo timestamps yet.
+ *
+ * Assumes that the caller did basic address and flag checks.
+ */
+static void tcp_v4_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack, __u16 window)
+{
+ struct tcphdr *th = skb->h.th;
+ struct tcphdr rth;
+ struct ip_reply_arg arg;
+
+ /* Swap the send and the receive. */
+ memset(&rth, 0, sizeof(struct tcphdr));
+ rth.dest = th->source;
+ rth.source = th->dest;
+ rth.doff = sizeof(struct tcphdr)/4;
+
+ rth.seq = seq;
+ rth.ack_seq = ack;
+ rth.ack = 1;
+
+ rth.window = htons(window);
+
+ memset(&arg, 0, sizeof arg);
+ arg.iov[0].iov_base = (unsigned char *)&rth;
+ arg.iov[0].iov_len = sizeof rth;
+ arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,
+ skb->nh.iph->saddr, /*XXX*/
+ sizeof(struct tcphdr),
+ IPPROTO_TCP,
+ 0);
+ arg.n_iov = 1;
+ arg.csumoffset = offsetof(struct tcphdr, check) / 2;
+
+ ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
+
+ tcp_statistics.TcpOutSegs++;
+}
+
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+
+/*
+ Seems, I never wrote nothing more stupid.
+ I hope Gods will forgive me, but I cannot forgive myself 8)
+ --ANK (981001)
+ */
+
+static struct sock *tcp_v4_search_proxy_openreq(struct sk_buff *skb)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
+ struct sock *sk;
+ int i;
+
+ for (i=0; i<TCP_LHTABLE_SIZE; i++) {
+ for(sk = tcp_listening_hash[i]; sk; sk = sk->next) {
+ struct open_request *dummy;
+ if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, iph,
+ th, &dummy) &&
+ (!sk->bound_dev_if ||
+ sk->bound_dev_if == skb->dev->ifindex))
+ return sk;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Check whether a received TCP packet might be for one of our
+ * connections.
+ */
+
+int tcp_chkaddr(struct sk_buff *skb)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
+ struct sock *sk;
+
+ sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr,
+ th->dest, skb->dev->ifindex);
+
+ if (!sk)
+ return tcp_v4_search_proxy_openreq(skb) != NULL;
+
+ if (sk->state == TCP_LISTEN) {
+ struct open_request *dummy;
+ if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, skb->nh.iph,
+ th, &dummy) &&
+ (!sk->bound_dev_if ||
+ sk->bound_dev_if == skb->dev->ifindex))
+ return 1;
+ }
+
+ /* 0 means accept all LOCAL addresses here, not all the world... */
+
+ if (sk->rcv_saddr == 0)
+ return 0;
+
+ return 1;
+}
+#endif
+
+/*
+ * Send a SYN-ACK after having received an ACK.
+ * This still operates on a open_request only, not on a big
+ * socket.
+ */
+static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
+{
+ struct rtable *rt;
+ struct ip_options *opt;
+ struct sk_buff * skb;
+ int mss;
+
+ /* First, grab a route. */
+ opt = req->af.v4_req.opt;
+ if(ip_route_output(&rt, ((opt && opt->srr) ?
+ opt->faddr :
+ req->af.v4_req.rmt_addr),
+ req->af.v4_req.loc_addr,
+ RT_TOS(sk->ip_tos) | RTO_CONN | sk->localroute,
+ sk->bound_dev_if)) {
+ ip_statistics.IpOutNoRoutes++;
+ return;
+ }
+ if(opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) {
+ ip_rt_put(rt);
+ ip_statistics.IpOutNoRoutes++;
+ return;
+ }
+
+ mss = rt->u.dst.pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
+
+ skb = tcp_make_synack(sk, &rt->u.dst, req, mss);
+ if (skb) {
+ struct tcphdr *th = skb->h.th;
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ th->source = req->lcl_port; /* LVE */
+#endif
+
+ th->check = tcp_v4_check(th, skb->len,
+ req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr,
+ csum_partial((char *)th, skb->len, skb->csum));
+
+ ip_build_and_send_pkt(skb, sk, req->af.v4_req.loc_addr,
+ req->af.v4_req.rmt_addr, req->af.v4_req.opt);
+ }
+ ip_rt_put(rt);
+}
+
+/*
+ * IPv4 open_request destructor.
+ */
+static void tcp_v4_or_free(struct open_request *req)
+{
+ if(!req->sk && req->af.v4_req.opt)
+ kfree_s(req->af.v4_req.opt, optlength(req->af.v4_req.opt));
+}
+
+static inline void syn_flood_warning(struct sk_buff *skb)
+{
+ static unsigned long warntime;
+
+ if (jiffies - warntime > HZ*60) {
+ warntime = jiffies;
+ printk(KERN_INFO
+ "possible SYN flooding on port %d. Sending cookies.\n",
+ ntohs(skb->h.th->dest));
+ }
+}
+
+/*
+ * Save and compile IPv4 options into the open_request if needed.
+ */
+static inline struct ip_options *
+tcp_v4_save_options(struct sock *sk, struct sk_buff *skb)
+{
+ struct ip_options *opt = &(IPCB(skb)->opt);
+ struct ip_options *dopt = NULL;
+
+ if (opt && opt->optlen) {
+ int opt_size = optlength(opt);
+ dopt = kmalloc(opt_size, GFP_ATOMIC);
+ if (dopt) {
+ if (ip_options_echo(dopt, skb)) {
+ kfree_s(dopt, opt_size);
+ dopt = NULL;
+ }
+ }
+ }
+ return dopt;
+}
+
+/*
+ * Maximum number of SYN_RECV sockets in queue per LISTEN socket.
+ * One SYN_RECV socket costs about 80bytes on a 32bit machine.
+ * It would be better to replace it with a global counter for all sockets
+ * but then some measure against one socket starving all other sockets
+ * would be needed.
+ */
+int sysctl_max_syn_backlog = 128;
+
+struct or_calltable or_ipv4 = {
+ tcp_v4_send_synack,
+ tcp_v4_or_free,
+ tcp_v4_send_reset
+};
+
+#define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */
+#define BACKLOGMAX(sk) sysctl_max_syn_backlog
+
+int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, __u32 isn)
+{
+ struct tcp_opt tp;
+ struct open_request *req;
+ struct tcphdr *th = skb->h.th;
+ __u32 saddr = skb->nh.iph->saddr;
+ __u32 daddr = skb->nh.iph->daddr;
+#ifdef CONFIG_SYN_COOKIES
+ int want_cookie = 0;
+#else
+#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
+#endif
+
+ /* If the socket is dead, don't accept the connection. */
+ if (sk->dead)
+ goto dead;
+
+ /* Never answer to SYNs send to broadcast or multicast */
+ if (((struct rtable *)skb->dst)->rt_flags &
+ (RTCF_BROADCAST|RTCF_MULTICAST))
+ goto drop;
+
+ /* XXX: Check against a global syn pool counter. */
+ if (BACKLOG(sk) > BACKLOGMAX(sk)) {
+#ifdef CONFIG_SYN_COOKIES
+ if (sysctl_tcp_syncookies) {
+ syn_flood_warning(skb);
+ want_cookie = 1;
+ } else
+#endif
+ goto drop;
+ } else {
+ if (isn == 0)
+ isn = tcp_v4_init_sequence(sk, skb);
+ BACKLOG(sk)++;
+ }
+
+ req = tcp_openreq_alloc();
+ if (req == NULL) {
+ goto dropbacklog;
+ }
+
+ req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */
+
+ req->rcv_isn = TCP_SKB_CB(skb)->seq;
+ tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+
+ tp.mss_clamp = 65535;
+ tcp_parse_options(NULL, th, &tp, want_cookie);
+ if (tp.mss_clamp == 65535)
+ tp.mss_clamp = 576 - sizeof(struct iphdr) - sizeof(struct iphdr);
+
+ if (sk->tp_pinfo.af_tcp.user_mss && sk->tp_pinfo.af_tcp.user_mss < tp.mss_clamp)
+ tp.mss_clamp = sk->tp_pinfo.af_tcp.user_mss;
+ req->mss = tp.mss_clamp;
+
+ if (tp.saw_tstamp)
+ req->ts_recent = tp.rcv_tsval;
+ req->tstamp_ok = tp.tstamp_ok;
+ req->sack_ok = tp.sack_ok;
+ req->snd_wscale = tp.snd_wscale;
+ req->wscale_ok = tp.wscale_ok;
+ req->rmt_port = th->source;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ req->lcl_port = th->dest ; /* LVE */
+#endif
+ req->af.v4_req.loc_addr = daddr;
+ req->af.v4_req.rmt_addr = saddr;
+
+ /* Note that we ignore the isn passed from the TIME_WAIT
+ * state here. That's the price we pay for cookies.
+ */
+ if (want_cookie)
+ isn = cookie_v4_init_sequence(sk, skb, &req->mss);
+
+ req->snt_isn = isn;
+
+ req->af.v4_req.opt = tcp_v4_save_options(sk, skb);
+
+ req->class = &or_ipv4;
+ req->retrans = 0;
+ req->sk = NULL;
+
+ tcp_v4_send_synack(sk, req);
+
+ if (want_cookie) {
+ if (req->af.v4_req.opt)
+ kfree(req->af.v4_req.opt);
+ tcp_v4_or_free(req);
+ tcp_openreq_free(req);
+ } else {
+ req->expires = jiffies + TCP_TIMEOUT_INIT;
+ tcp_inc_slow_timer(TCP_SLT_SYNACK);
+ tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);
+ }
+
+ return 0;
+
+dead:
+ SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk);
+ tcp_statistics.TcpAttemptFails++;
+ return -ENOTCONN; /* send reset */
+
+dropbacklog:
+ if (!want_cookie)
+ BACKLOG(sk)--;
+drop:
+ tcp_statistics.TcpAttemptFails++;
+ return 0;
+}
+
+/* This is not only more efficient than what we used to do, it eliminates
+ * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM
+ *
+ * This function wants to be moved to a common for IPv[46] file. --ANK
+ */
+struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, struct sk_buff *skb)
+{
+ struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0);
+
+ if(newsk != NULL) {
+ struct tcp_opt *newtp;
+#ifdef CONFIG_FILTER
+ struct sk_filter *filter;
+#endif
+
+ memcpy(newsk, sk, sizeof(*newsk));
+ newsk->sklist_next = NULL;
+ newsk->state = TCP_SYN_RECV;
+
+ /* Clone the TCP header template */
+ newsk->dport = req->rmt_port;
+
+ atomic_set(&newsk->sock_readers, 0);
+ atomic_set(&newsk->rmem_alloc, 0);
+ skb_queue_head_init(&newsk->receive_queue);
+ atomic_set(&newsk->wmem_alloc, 0);
+ skb_queue_head_init(&newsk->write_queue);
+ atomic_set(&newsk->omem_alloc, 0);
+
+ newsk->done = 0;
+ newsk->proc = 0;
+ skb_queue_head_init(&newsk->back_log);
+ skb_queue_head_init(&newsk->error_queue);
+#ifdef CONFIG_FILTER
+ if ((filter = newsk->filter) != NULL)
+ sk_filter_charge(newsk, filter);
+#endif
+
+ /* Now setup tcp_opt */
+ newtp = &(newsk->tp_pinfo.af_tcp);
+ newtp->pred_flags = 0;
+ newtp->rcv_nxt = req->rcv_isn + 1;
+ newtp->snd_nxt = req->snt_isn + 1;
+ newtp->snd_una = req->snt_isn + 1;
+ newtp->srtt = 0;
+ newtp->ato = 0;
+ newtp->snd_wl1 = req->rcv_isn;
+ newtp->snd_wl2 = req->snt_isn;
+
+ /* RFC1323: The window in SYN & SYN/ACK segments
+ * is never scaled.
+ */
+ newtp->snd_wnd = ntohs(skb->h.th->window);
+
+ newtp->max_window = newtp->snd_wnd;
+ newtp->pending = 0;
+ newtp->retransmits = 0;
+ newtp->last_ack_sent = req->rcv_isn + 1;
+ newtp->backoff = 0;
+ newtp->mdev = TCP_TIMEOUT_INIT;
+
+ /* So many TCP implementations out there (incorrectly) count the
+ * initial SYN frame in their delayed-ACK and congestion control
+ * algorithms that we must have the following bandaid to talk
+ * efficiently to them. -DaveM
+ */
+ newtp->snd_cwnd = 2;
+
+ newtp->rto = TCP_TIMEOUT_INIT;
+ newtp->packets_out = 0;
+ newtp->fackets_out = 0;
+ newtp->retrans_out = 0;
+ newtp->high_seq = 0;
+ newtp->snd_ssthresh = 0x7fffffff;
+ newtp->snd_cwnd_cnt = 0;
+ newtp->dup_acks = 0;
+ newtp->delayed_acks = 0;
+ init_timer(&newtp->retransmit_timer);
+ newtp->retransmit_timer.function = &tcp_retransmit_timer;
+ newtp->retransmit_timer.data = (unsigned long) newsk;
+ init_timer(&newtp->delack_timer);
+ newtp->delack_timer.function = &tcp_delack_timer;
+ newtp->delack_timer.data = (unsigned long) newsk;
+ skb_queue_head_init(&newtp->out_of_order_queue);
+ newtp->send_head = newtp->retrans_head = NULL;
+ newtp->rcv_wup = req->rcv_isn + 1;
+ newtp->write_seq = req->snt_isn + 1;
+ newtp->copied_seq = req->rcv_isn + 1;
+
+ newtp->saw_tstamp = 0;
+ newtp->mss_clamp = req->mss;
+
+ init_timer(&newtp->probe_timer);
+ newtp->probe_timer.function = &tcp_probe_timer;
+ newtp->probe_timer.data = (unsigned long) newsk;
+ newtp->probes_out = 0;
+ newtp->syn_seq = req->rcv_isn;
+ newtp->fin_seq = req->rcv_isn;
+ newtp->urg_data = 0;
+ tcp_synq_init(newtp);
+ newtp->syn_backlog = 0;
+ if (skb->len >= 536)
+ newtp->last_seg_size = skb->len;
+
+ /* Back to base struct sock members. */
+ newsk->err = 0;
+ newsk->ack_backlog = 0;
+ newsk->max_ack_backlog = SOMAXCONN;
+ newsk->priority = 0;
+
+ /* IP layer stuff */
+ newsk->timeout = 0;
+ init_timer(&newsk->timer);
+ newsk->timer.function = &net_timer;
+ newsk->timer.data = (unsigned long) newsk;
+ newsk->socket = NULL;
+
+ newtp->tstamp_ok = req->tstamp_ok;
+ if((newtp->sack_ok = req->sack_ok) != 0)
+ newtp->num_sacks = 0;
+ newtp->window_clamp = req->window_clamp;
+ newtp->rcv_wnd = req->rcv_wnd;
+ newtp->wscale_ok = req->wscale_ok;
+ if (newtp->wscale_ok) {
+ newtp->snd_wscale = req->snd_wscale;
+ newtp->rcv_wscale = req->rcv_wscale;
+ } else {
+ newtp->snd_wscale = newtp->rcv_wscale = 0;
+ newtp->window_clamp = min(newtp->window_clamp,65535);
+ }
+ if (newtp->tstamp_ok) {
+ newtp->ts_recent = req->ts_recent;
+ newtp->ts_recent_stamp = tcp_time_stamp;
+ newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
+ } else {
+ newtp->tcp_header_len = sizeof(struct tcphdr);
+ }
+ }
+ return newsk;
+}
+
+/*
+ * The three way handshake has completed - we got a valid synack -
+ * now create the new socket.
+ */
+struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ struct open_request *req,
+ struct dst_entry *dst)
+{
+ struct ip_options *opt = req->af.v4_req.opt;
+ struct tcp_opt *newtp;
+ struct sock *newsk;
+
+ if (sk->ack_backlog > sk->max_ack_backlog)
+ goto exit; /* head drop */
+ if (dst == NULL) {
+ struct rtable *rt;
+
+ if (ip_route_output(&rt,
+ opt && opt->srr ? opt->faddr : req->af.v4_req.rmt_addr,
+ req->af.v4_req.loc_addr, sk->ip_tos|RTO_CONN, 0))
+ return NULL;
+ dst = &rt->u.dst;
+ }
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ /* The new socket created for transparent proxy may fall
+ * into a non-existed bind bucket because sk->num != newsk->num.
+ * Ensure existence of the bucket now. The placement of the check
+ * later will require to destroy just created newsk in the case of fail.
+ * 1998/04/22 Andrey V. Savochkin <saw@msu.ru>
+ */
+ if (__tcp_bucket_check(ntohs(skb->h.th->dest)))
+ goto exit;
+#endif
+
+ newsk = tcp_create_openreq_child(sk, req, skb);
+ if (!newsk)
+ goto exit;
+
+ sk->tp_pinfo.af_tcp.syn_backlog--;
+ sk->ack_backlog++;
+
+ newsk->dst_cache = dst;
+
+ newtp = &(newsk->tp_pinfo.af_tcp);
+ newsk->daddr = req->af.v4_req.rmt_addr;
+ newsk->saddr = req->af.v4_req.loc_addr;
+ newsk->rcv_saddr = req->af.v4_req.loc_addr;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ newsk->num = ntohs(skb->h.th->dest);
+ newsk->sport = req->lcl_port;
+#endif
+ newsk->opt = req->af.v4_req.opt;
+ newtp->ext_header_len = 0;
+ if (newsk->opt)
+ newtp->ext_header_len = newsk->opt->optlen;
+
+ tcp_sync_mss(newsk, dst->pmtu);
+ newtp->rcv_mss = newtp->mss_clamp;
+
+ /* It would be better to use newtp->mss_clamp here */
+ if (newsk->rcvbuf < (3 * newtp->pmtu_cookie))
+ newsk->rcvbuf = min ((3 * newtp->pmtu_cookie), sysctl_rmem_max);
+ if (newsk->sndbuf < (3 * newtp->pmtu_cookie))
+ newsk->sndbuf = min ((3 * newtp->pmtu_cookie), sysctl_wmem_max);
+
+ /* We run in BH processing itself or within a BH atomic
+ * sequence (backlog) so no locking is needed.
+ */
+ __tcp_v4_hash(newsk);
+ __tcp_inherit_port(sk, newsk);
+ __add_to_prot_sklist(newsk);
+
+ sk->data_ready(sk, 0); /* Deliver SIGIO */
+
+ return newsk;
+
+exit:
+ dst_release(dst);
+ return NULL;
+}
+
+static void tcp_v4_rst_req(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct open_request *req, *prev;
+
+ req = tcp_v4_search_req(tp,skb->nh.iph, skb->h.th, &prev);
+ if (!req)
+ return;
+ /* Sequence number check required by RFC793 */
+ if (before(TCP_SKB_CB(skb)->seq, req->rcv_isn) ||
+ after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1))
+ return;
+ tcp_synq_unlink(tp, req, prev);
+ if (req->sk)
+ sk->ack_backlog--;
+ else
+ tp->syn_backlog--;
+ req->class->destructor(req);
+ tcp_openreq_free(req);
+
+ net_statistics.EmbryonicRsts++;
+}
+
+/* Check for embryonic sockets (open_requests) We check packets with
+ * only the SYN bit set against the open_request queue too: This
+ * increases connection latency a bit, but is required to detect
+ * retransmitted SYNs.
+ */
+static inline struct sock *tcp_v4_hnd_req(struct sock *sk,struct sk_buff *skb)
+{
+ struct tcphdr *th = skb->h.th;
+ u32 flg = ((u32 *)th)[3];
+
+ /* Check for RST */
+ if (flg & __constant_htonl(0x00040000)) {
+ tcp_v4_rst_req(sk, skb);
+ return NULL;
+ }
+
+ /* Check for SYN|ACK */
+ if (flg & __constant_htonl(0x00120000)) {
+ struct open_request *req, *dummy;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Find possible connection requests. */
+ req = tcp_v4_search_req(tp, skb->nh.iph, th, &dummy);
+ if (req) {
+ sk = tcp_check_req(sk, skb, req);
+ }
+#ifdef CONFIG_SYN_COOKIES
+ else if ((flg & __constant_htonl(0x00120000))==__constant_htonl(0x00100000))
+ {
+ sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));
+ }
+#endif
+ }
+ return sk;
+}
+
+int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
+{
+#ifdef CONFIG_FILTER
+ struct sk_filter *filter = sk->filter;
+ if (filter && sk_filter(skb, filter))
+ goto discard;
+#endif /* CONFIG_FILTER */
+
+ /*
+ * This doesn't check if the socket has enough room for the packet.
+ * Either process the packet _without_ queueing it and then free it,
+ * or do the check later.
+ */
+ skb_set_owner_r(skb, sk);
+
+ if (sk->state == TCP_ESTABLISHED) { /* Fast path */
+ if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
+ goto reset;
+ return 0;
+ }
+
+
+ if (sk->state == TCP_LISTEN) {
+ struct sock *nsk;
+
+ nsk = tcp_v4_hnd_req(sk, skb);
+ if (!nsk)
+ goto discard;
+
+ /*
+ * Queue it on the new socket if the new socket is active,
+ * otherwise we just shortcircuit this and continue with
+ * the new socket..
+ */
+ if (atomic_read(&nsk->sock_readers)) {
+ skb_orphan(skb);
+ __skb_queue_tail(&nsk->back_log, skb);
+ return 0;
+ }
+ sk = nsk;
+ }
+
+ if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
+ goto reset;
+ return 0;
+
+reset:
+ tcp_v4_send_reset(skb);
+discard:
+ kfree_skb(skb);
+ /* Be careful here. If this function gets more complicated and
+ * gcc suffers from register pressure on the x86, sk (in %ebx)
+ * might be destroyed here. This current version compiles correctly,
+ * but you have been warned.
+ */
+ return 0;
+}
+
+/*
+ * From tcp_input.c
+ */
+
+int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
+{
+ struct tcphdr *th;
+ struct sock *sk;
+
+ if (skb->pkt_type!=PACKET_HOST)
+ goto discard_it;
+
+ th = skb->h.th;
+
+ /* Pull up the IP header. */
+ __skb_pull(skb, skb->h.raw - skb->data);
+
+ /* Count it even if it's bad */
+ tcp_statistics.TcpInSegs++;
+
+ len = skb->len;
+ if (len < sizeof(struct tcphdr))
+ goto bad_packet;
+
+ /* Try to use the device checksum if provided. */
+ switch (skb->ip_summed) {
+ case CHECKSUM_NONE:
+ skb->csum = csum_partial((char *)th, len, 0);
+ case CHECKSUM_HW:
+ if (tcp_v4_check(th,len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) {
+ NETDEBUG(printk(KERN_DEBUG "TCPv4 bad checksum "
+ "from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, "
+ "len=%d/%d/%d\n",
+ NIPQUAD(skb->nh.iph->saddr),
+ ntohs(th->source),
+ NIPQUAD(skb->nh.iph->daddr),
+ ntohs(th->dest),
+ len, skb->len,
+ ntohs(skb->nh.iph->tot_len)));
+ bad_packet:
+ tcp_statistics.TcpInErrs++;
+ goto discard_it;
+ }
+ default:
+ ; /* CHECKSUM_UNNECESSARY */
+ }
+
+ if((th->doff * 4) < sizeof(struct tcphdr) ||
+ len < (th->doff * 4))
+ goto bad_packet;
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (IPCB(skb)->redirport)
+ sk = tcp_v4_proxy_lookup(th->dest, skb->nh.iph->saddr, th->source,
+ skb->nh.iph->daddr, skb->dev,
+ IPCB(skb)->redirport, skb->dev->ifindex);
+ else {
+#endif
+ sk = __tcp_v4_lookup(th, skb->nh.iph->saddr, th->source,
+ skb->nh.iph->daddr, th->dest, skb->dev->ifindex);
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (!sk)
+ sk = tcp_v4_search_proxy_openreq(skb);
+ }
+#endif
+ if (!sk)
+ goto no_tcp_socket;
+ if(!ipsec_sk_policy(sk,skb))
+ goto discard_it;
+
+ TCP_SKB_CB(skb)->seq = ntohl(th->seq);
+ TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
+ len - th->doff*4);
+ TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
+
+ skb->used = 0;
+
+ if (sk->state == TCP_TIME_WAIT)
+ goto do_time_wait;
+ if (!atomic_read(&sk->sock_readers))
+ return tcp_v4_do_rcv(sk, skb);
+
+ __skb_queue_tail(&sk->back_log, skb);
+ return 0;
+
+no_tcp_socket:
+ tcp_v4_send_reset(skb);
+
+discard_it:
+ /* Discard frame. */
+ kfree_skb(skb);
+ return 0;
+
+do_time_wait:
+ /* Sorry for the ugly switch. 2.3 will have a better solution. */
+ switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
+ skb, th, skb->len)) {
+ case TCP_TW_ACK:
+ tcp_v4_send_ack(skb,
+ ((struct tcp_tw_bucket *)sk)->snd_nxt,
+ ((struct tcp_tw_bucket *)sk)->rcv_nxt,
+ ((struct tcp_tw_bucket *)sk)->window);
+ goto discard_it;
+ case TCP_TW_RST:
+ goto no_tcp_socket;
+ default:
+ goto discard_it;
+ }
+}
+
+static void __tcp_v4_rehash(struct sock *sk)
+{
+ struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
+
+ SOCKHASH_LOCK();
+ if(sk->pprev) {
+ if(sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ tcp_reg_zap(sk);
+ }
+ if((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+ SOCKHASH_UNLOCK();
+}
+
+int tcp_v4_rebuild_header(struct sock *sk)
+{
+ struct rtable *rt = (struct rtable *)sk->dst_cache;
+ __u32 new_saddr;
+ int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT;
+
+ if(rt == NULL)
+ return 0;
+
+ /* Force route checking if want_rewrite.
+ * The idea is good, the implementation is disguisting.
+ * Well, if I made bind on this socket, you cannot randomly ovewrite
+ * its source address. --ANK
+ */
+ if (want_rewrite) {
+ int tmp;
+ struct rtable *new_rt;
+ __u32 old_saddr = rt->rt_src;
+
+ /* Query new route using another rt buffer */
+ tmp = ip_route_connect(&new_rt, rt->rt_dst, 0,
+ RT_TOS(sk->ip_tos)|sk->localroute,
+ sk->bound_dev_if);
+
+ /* Only useful if different source addrs */
+ if (tmp == 0) {
+ /*
+ * Only useful if different source addrs
+ */
+ if (new_rt->rt_src != old_saddr ) {
+ dst_release(sk->dst_cache);
+ sk->dst_cache = &new_rt->u.dst;
+ rt = new_rt;
+ goto do_rewrite;
+ }
+ dst_release(&new_rt->u.dst);
+ }
+ }
+ if (rt->u.dst.obsolete) {
+ int err;
+ err = ip_route_output(&rt, rt->rt_dst, rt->rt_src, rt->key.tos|RTO_CONN, rt->key.oif);
+ if (err) {
+ sk->err_soft=-err;
+ sk->error_report(sk);
+ return -1;
+ }
+ dst_release(xchg(&sk->dst_cache, &rt->u.dst));
+ }
+
+ return 0;
+
+do_rewrite:
+ new_saddr = rt->rt_src;
+
+ /* Ouch!, this should not happen. */
+ if (!sk->saddr || !sk->rcv_saddr) {
+ printk(KERN_WARNING "tcp_v4_rebuild_header(): not valid sock addrs: "
+ "saddr=%08X rcv_saddr=%08X\n",
+ ntohl(sk->saddr),
+ ntohl(sk->rcv_saddr));
+ return 0;
+ }
+
+ if (new_saddr != sk->saddr) {
+ if (sysctl_ip_dynaddr > 1) {
+ printk(KERN_INFO "tcp_v4_rebuild_header(): shifting sk->saddr "
+ "from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(sk->saddr),
+ NIPQUAD(new_saddr));
+ }
+
+ sk->saddr = new_saddr;
+ sk->rcv_saddr = new_saddr;
+
+ /* XXX The only one ugly spot where we need to
+ * XXX really change the sockets identity after
+ * XXX it has entered the hashes. -DaveM
+ */
+ __tcp_v4_rehash(sk);
+ }
+
+ return 0;
+}
+
+static struct sock * tcp_v4_get_sock(struct sk_buff *skb, struct tcphdr *th)
+{
+ return tcp_v4_lookup(skb->nh.iph->saddr, th->source,
+ skb->nh.iph->daddr, th->dest, skb->dev->ifindex);
+}
+
+static void v4_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *) uaddr;
+
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = sk->daddr;
+ sin->sin_port = sk->dport;
+}
+
+struct tcp_func ipv4_specific = {
+ ip_queue_xmit,
+ tcp_v4_send_check,
+ tcp_v4_rebuild_header,
+ tcp_v4_conn_request,
+ tcp_v4_syn_recv_sock,
+ tcp_v4_get_sock,
+ sizeof(struct iphdr),
+
+ ip_setsockopt,
+ ip_getsockopt,
+ v4_addr2sockaddr,
+ sizeof(struct sockaddr_in)
+};
+
+/* NOTE: A lot of things set to zero explicitly by call to
+ * sk_alloc() so need not be done here.
+ */
+static int tcp_v4_init_sock(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ skb_queue_head_init(&tp->out_of_order_queue);
+ tcp_init_xmit_timers(sk);
+
+ tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/
+ tp->mdev = TCP_TIMEOUT_INIT;
+ tp->mss_clamp = ~0;
+
+ /* So many TCP implementations out there (incorrectly) count the
+ * initial SYN frame in their delayed-ACK and congestion control
+ * algorithms that we must have the following bandaid to talk
+ * efficiently to them. -DaveM
+ */
+ tp->snd_cwnd = 2;
+
+ /* See draft-stevens-tcpca-spec-01 for discussion of the
+ * initialization of these values.
+ */
+ tp->snd_cwnd_cnt = 0;
+ tp->snd_ssthresh = 0x7fffffff; /* Infinity */
+
+ sk->state = TCP_CLOSE;
+ sk->max_ack_backlog = SOMAXCONN;
+ tp->rcv_mss = 536;
+
+ sk->write_space = tcp_write_space;
+
+ /* Init SYN queue. */
+ tcp_synq_init(tp);
+
+ sk->tp_pinfo.af_tcp.af_specific = &ipv4_specific;
+
+ return 0;
+}
+
+static int tcp_v4_destroy_sock(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb;
+
+ tcp_clear_xmit_timers(sk);
+
+ if (sk->keepopen)
+ tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
+
+ /* Cleanup up the write buffer. */
+ while((skb = __skb_dequeue(&sk->write_queue)) != NULL)
+ kfree_skb(skb);
+
+ /* Cleans up our, hopefuly empty, out_of_order_queue. */
+ while((skb = __skb_dequeue(&tp->out_of_order_queue)) != NULL)
+ kfree_skb(skb);
+
+ /* Clean up a referenced TCP bind bucket, this only happens if a
+ * port is allocated for a socket, but it never fully connects.
+ */
+ if(sk->prev != NULL)
+ tcp_put_port(sk);
+
+ return 0;
+}
+
+struct proto tcp_prot = {
+ (struct sock *)&tcp_prot, /* sklist_next */
+ (struct sock *)&tcp_prot, /* sklist_prev */
+ tcp_close, /* close */
+ tcp_v4_connect, /* connect */
+ tcp_accept, /* accept */
+ NULL, /* retransmit */
+ tcp_write_wakeup, /* write_wakeup */
+ tcp_read_wakeup, /* read_wakeup */
+ tcp_poll, /* poll */
+ tcp_ioctl, /* ioctl */
+ tcp_v4_init_sock, /* init */
+ tcp_v4_destroy_sock, /* destroy */
+ tcp_shutdown, /* shutdown */
+ tcp_setsockopt, /* setsockopt */
+ tcp_getsockopt, /* getsockopt */
+ tcp_v4_sendmsg, /* sendmsg */
+ tcp_recvmsg, /* recvmsg */
+ NULL, /* bind */
+ tcp_v4_do_rcv, /* backlog_rcv */
+ tcp_v4_hash, /* hash */
+ tcp_v4_unhash, /* unhash */
+ tcp_v4_get_port, /* get_port */
+ 128, /* max_header */
+ 0, /* retransmits */
+ "TCP", /* name */
+ 0, /* inuse */
+ 0 /* highestinuse */
+};
+
+
+
+__initfunc(void tcp_v4_init(struct net_proto_family *ops))
+{
+ int err;
+
+ tcp_inode.i_mode = S_IFSOCK;
+ tcp_inode.i_sock = 1;
+ tcp_inode.i_uid = 0;
+ tcp_inode.i_gid = 0;
+
+ tcp_socket->inode = &tcp_inode;
+ tcp_socket->state = SS_UNCONNECTED;
+ tcp_socket->type=SOCK_RAW;
+
+ if ((err=ops->create(tcp_socket, IPPROTO_TCP))<0)
+ panic("Failed to create the TCP control socket.\n");
+ tcp_socket->sk->allocation=GFP_ATOMIC;
+ tcp_socket->sk->num = 256; /* Don't receive any data */
+ tcp_socket->sk->ip_ttl = MAXTTL;
+}
diff --git a/pfinet/linux-src/net/ipv4/tcp_output.c b/pfinet/linux-src/net/ipv4/tcp_output.c
new file mode 100644
index 00000000..9ea4b7ad
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/tcp_output.c
@@ -0,0 +1,1143 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Implementation of the Transmission Control Protocol(TCP).
+ *
+ * Version: $Id: tcp_output.c,v 1.108.2.1 1999/05/14 23:07:36 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ * Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
+ * Linus Torvalds, <torvalds@cs.helsinki.fi>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Matthew Dillon, <dillon@apollo.west.oic.com>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Jorge Cwik, <jorge@laser.satlink.net>
+ */
+
+/*
+ * Changes: Pedro Roque : Retransmit queue handled by TCP.
+ * : Fragmentation on mtu decrease
+ * : Segment collapse on retransmit
+ * : AF independence
+ *
+ * Linus Torvalds : send_delayed_ack
+ * David S. Miller : Charge memory using the right skb
+ * during syn/ack processing.
+ * David S. Miller : Output engine completely rewritten.
+ * Andrea Arcangeli: SYNACK carry ts_recent in tsecr.
+ *
+ */
+
+#include <net/tcp.h>
+
+extern int sysctl_tcp_timestamps;
+extern int sysctl_tcp_window_scaling;
+extern int sysctl_tcp_sack;
+
+/* People can turn this off for buggy TCP's found in printers etc. */
+int sysctl_tcp_retrans_collapse = 1;
+
+/* Get rid of any delayed acks, we sent one already.. */
+static __inline__ void clear_delayed_acks(struct sock * sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ tp->delayed_acks = 0;
+ if(tcp_in_quickack_mode(tp))
+ tcp_exit_quickack_mode(tp);
+ tcp_clear_xmit_timer(sk, TIME_DACK);
+}
+
+static __inline__ void update_send_head(struct sock *sk)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ tp->send_head = tp->send_head->next;
+ if (tp->send_head == (struct sk_buff *) &sk->write_queue)
+ tp->send_head = NULL;
+}
+
+/* This routine actually transmits TCP packets queued in by
+ * tcp_do_sendmsg(). This is used by both the initial
+ * transmission and possible later retransmissions.
+ * All SKB's seen here are completely headerless. It is our
+ * job to build the TCP header, and pass the packet down to
+ * IP so it can do the same plus pass the packet off to the
+ * device.
+ *
+ * We are working here with either a clone of the original
+ * SKB, or a fresh unique copy made by the retransmit engine.
+ */
+void tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
+{
+ if(skb != NULL) {
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
+ int tcp_header_size = tp->tcp_header_len;
+ struct tcphdr *th;
+ int sysctl_flags;
+
+#define SYSCTL_FLAG_TSTAMPS 0x1
+#define SYSCTL_FLAG_WSCALE 0x2
+#define SYSCTL_FLAG_SACK 0x4
+
+ sysctl_flags = 0;
+ if(tcb->flags & TCPCB_FLAG_SYN) {
+ tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS;
+ if(sysctl_tcp_timestamps) {
+ tcp_header_size += TCPOLEN_TSTAMP_ALIGNED;
+ sysctl_flags |= SYSCTL_FLAG_TSTAMPS;
+ }
+ if(sysctl_tcp_window_scaling) {
+ tcp_header_size += TCPOLEN_WSCALE_ALIGNED;
+ sysctl_flags |= SYSCTL_FLAG_WSCALE;
+ }
+ if(sysctl_tcp_sack) {
+ sysctl_flags |= SYSCTL_FLAG_SACK;
+ if(!(sysctl_flags & SYSCTL_FLAG_TSTAMPS))
+ tcp_header_size += TCPOLEN_SACKPERM_ALIGNED;
+ }
+ } else if(tp->sack_ok && tp->num_sacks) {
+ /* A SACK is 2 pad bytes, a 2 byte header, plus
+ * 2 32-bit sequence numbers for each SACK block.
+ */
+ tcp_header_size += (TCPOLEN_SACK_BASE_ALIGNED +
+ (tp->num_sacks * TCPOLEN_SACK_PERBLOCK));
+ }
+ th = (struct tcphdr *) skb_push(skb, tcp_header_size);
+ skb->h.th = th;
+ skb_set_owner_w(skb, sk);
+
+ /* Build TCP header and checksum it. */
+ th->source = sk->sport;
+ th->dest = sk->dport;
+ th->seq = htonl(TCP_SKB_CB(skb)->seq);
+ th->ack_seq = htonl(tp->rcv_nxt);
+ th->doff = (tcp_header_size >> 2);
+ th->res1 = 0;
+ *(((__u8 *)th) + 13) = tcb->flags;
+ if(!(tcb->flags & TCPCB_FLAG_SYN))
+ th->window = htons(tcp_select_window(sk));
+ th->check = 0;
+ th->urg_ptr = ntohs(tcb->urg_ptr);
+ if(tcb->flags & TCPCB_FLAG_SYN) {
+ /* RFC1323: The window in SYN & SYN/ACK segments
+ * is never scaled.
+ */
+ th->window = htons(tp->rcv_wnd);
+ tcp_syn_build_options((__u32 *)(th + 1), tp->mss_clamp,
+ (sysctl_flags & SYSCTL_FLAG_TSTAMPS),
+ (sysctl_flags & SYSCTL_FLAG_SACK),
+ (sysctl_flags & SYSCTL_FLAG_WSCALE),
+ tp->rcv_wscale,
+ TCP_SKB_CB(skb)->when,
+ tp->ts_recent);
+ } else {
+ tcp_build_and_update_options((__u32 *)(th + 1),
+ tp, TCP_SKB_CB(skb)->when);
+ }
+ tp->af_specific->send_check(sk, th, skb->len, skb);
+
+ clear_delayed_acks(sk);
+ tp->last_ack_sent = tp->rcv_nxt;
+ tcp_statistics.TcpOutSegs++;
+ tp->af_specific->queue_xmit(skb);
+ }
+#undef SYSCTL_FLAG_TSTAMPS
+#undef SYSCTL_FLAG_WSCALE
+#undef SYSCTL_FLAG_SACK
+}
+
+/* This is the main buffer sending routine. We queue the buffer
+ * and decide whether to queue or transmit now.
+ */
+void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Advance write_seq and place onto the write_queue. */
+ tp->write_seq += (TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq);
+ __skb_queue_tail(&sk->write_queue, skb);
+
+ if (!force_queue && tp->send_head == NULL && tcp_snd_test(sk, skb)) {
+ /* Send it out now. */
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
+ tp->packets_out++;
+ tcp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL));
+ if(!tcp_timer_is_set(sk, TIME_RETRANS))
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ } else {
+ /* Queue it, remembering where we must start sending. */
+ if (tp->send_head == NULL)
+ tp->send_head = skb;
+ if (!force_queue && tp->packets_out == 0 && !tp->pending) {
+ tp->pending = TIME_PROBE0;
+ tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
+ }
+ }
+}
+
+/* Function to create two new TCP segments. Shrinks the given segment
+ * to the specified size and appends a new segment with the rest of the
+ * packet to the list. This won't be called frequently, I hope.
+ * Remember, these are still headerless SKBs at this point.
+ */
+static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
+{
+ struct sk_buff *buff;
+ int nsize = skb->len - len;
+ u16 flags;
+
+ /* Get a new skb... force flag on. */
+ buff = sock_wmalloc(sk,
+ (nsize + MAX_HEADER + sk->prot->max_header),
+ 1, GFP_ATOMIC);
+ if (buff == NULL)
+ return -1; /* We'll just try again later. */
+
+ /* Reserve space for headers. */
+ skb_reserve(buff, MAX_HEADER + sk->prot->max_header);
+
+ /* Correct the sequence numbers. */
+ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len;
+ TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq;
+
+ /* PSH and FIN should only be set in the second packet. */
+ flags = TCP_SKB_CB(skb)->flags;
+ TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN | TCPCB_FLAG_PSH);
+ if(flags & TCPCB_FLAG_URG) {
+ u16 old_urg_ptr = TCP_SKB_CB(skb)->urg_ptr;
+
+ /* Urgent data is always a pain in the ass. */
+ if(old_urg_ptr > len) {
+ TCP_SKB_CB(skb)->flags &= ~(TCPCB_FLAG_URG);
+ TCP_SKB_CB(skb)->urg_ptr = 0;
+ TCP_SKB_CB(buff)->urg_ptr = old_urg_ptr - len;
+ } else {
+ flags &= ~(TCPCB_FLAG_URG);
+ }
+ }
+ if(!(flags & TCPCB_FLAG_URG))
+ TCP_SKB_CB(buff)->urg_ptr = 0;
+ TCP_SKB_CB(buff)->flags = flags;
+ TCP_SKB_CB(buff)->sacked = 0;
+
+ /* Copy and checksum data tail into the new buffer. */
+ buff->csum = csum_partial_copy(skb->data + len, skb_put(buff, nsize),
+ nsize, 0);
+
+ /* This takes care of the FIN sequence number too. */
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
+ skb_trim(skb, len);
+
+ /* Rechecksum original buffer. */
+ skb->csum = csum_partial(skb->data, skb->len, 0);
+
+ /* Looks stupid, but our code really uses when of
+ * skbs, which it never sent before. --ANK
+ */
+ TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
+
+ /* Link BUFF into the send queue. */
+ __skb_append(skb, buff);
+
+ return 0;
+}
+
+/* This function synchronize snd mss to current pmtu/exthdr set.
+
+ tp->user_mss is mss set by user by TCP_MAXSEG. It does NOT counts
+ for TCP options, but includes only bare TCP header.
+
+ tp->mss_clamp is mss negotiated at connection setup.
+ It is minimum of user_mss and mss received with SYN.
+ It also does not include TCP options.
+
+ tp->pmtu_cookie is last pmtu, seen by this function.
+
+ tp->mss_cache is current effective sending mss, including
+ all tcp options except for SACKs. It is evaluated,
+ taking into account current pmtu, but never exceeds
+ tp->mss_clamp.
+
+ NOTE1. rfc1122 clearly states that advertised MSS
+ DOES NOT include either tcp or ip options.
+
+ NOTE2. tp->pmtu_cookie and tp->mss_cache are READ ONLY outside
+ this function. --ANK (980731)
+ */
+
+int tcp_sync_mss(struct sock *sk, u32 pmtu)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ int mss_now;
+
+ /* Calculate base mss without TCP options:
+ It is MMS_S - sizeof(tcphdr) of rfc1122
+ */
+ mss_now = pmtu - tp->af_specific->net_header_len - sizeof(struct tcphdr);
+
+ /* Clamp it (mss_clamp does not include tcp options) */
+ if (mss_now > tp->mss_clamp)
+ mss_now = tp->mss_clamp;
+
+ /* Now subtract TCP options size, not including SACKs */
+ mss_now -= tp->tcp_header_len - sizeof(struct tcphdr);
+
+ /* Now subtract optional transport overhead */
+ mss_now -= tp->ext_header_len;
+
+ /* It we got too small (or even negative) value,
+ clamp it by 8 from below. Why 8 ?
+ Well, it could be 1 with the same success,
+ but if IP accepted segment of length 1,
+ it would love 8 even more 8) --ANK (980731)
+ */
+ if (mss_now < 8)
+ mss_now = 8;
+
+ /* And store cached results */
+ tp->pmtu_cookie = pmtu;
+ tp->mss_cache = mss_now;
+ return mss_now;
+}
+
+
+/* This routine writes packets to the network. It advances the
+ * send_head. This happens as incoming acks open up the remote
+ * window for us.
+ */
+void tcp_write_xmit(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ unsigned int mss_now;
+
+ /* Account for SACKS, we may need to fragment due to this.
+ * It is just like the real MSS changing on us midstream.
+ * We also handle things correctly when the user adds some
+ * IP options mid-stream. Silly to do, but cover it.
+ */
+ mss_now = tcp_current_mss(sk);
+
+ /* If we are zapped, the bytes will have to remain here.
+ * In time closedown will empty the write queue and all
+ * will be happy.
+ */
+ if(!sk->zapped) {
+ struct sk_buff *skb;
+ int sent_pkts = 0;
+
+ /* Anything on the transmit queue that fits the window can
+ * be added providing we are:
+ *
+ * a) following SWS avoidance [and Nagle algorithm]
+ * b) not exceeding our congestion window.
+ * c) not retransmitting [Nagle]
+ */
+ while((skb = tp->send_head) && tcp_snd_test(sk, skb)) {
+ if (skb->len > mss_now) {
+ if (tcp_fragment(sk, skb, mss_now))
+ break;
+ }
+
+ /* Advance the send_head. This one is going out. */
+ update_send_head(sk);
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
+ tp->packets_out++;
+ tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
+ sent_pkts = 1;
+ }
+
+ /* If we sent anything, make sure the retransmit
+ * timer is active.
+ */
+ if (sent_pkts && !tcp_timer_is_set(sk, TIME_RETRANS))
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ }
+}
+
+/* This function returns the amount that we can raise the
+ * usable window based on the following constraints
+ *
+ * 1. The window can never be shrunk once it is offered (RFC 793)
+ * 2. We limit memory per socket
+ *
+ * RFC 1122:
+ * "the suggested [SWS] avoidance algorithm for the receiver is to keep
+ * RECV.NEXT + RCV.WIN fixed until:
+ * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
+ *
+ * i.e. don't raise the right edge of the window until you can raise
+ * it at least MSS bytes.
+ *
+ * Unfortunately, the recommended algorithm breaks header prediction,
+ * since header prediction assumes th->window stays fixed.
+ *
+ * Strictly speaking, keeping th->window fixed violates the receiver
+ * side SWS prevention criteria. The problem is that under this rule
+ * a stream of single byte packets will cause the right side of the
+ * window to always advance by a single byte.
+ *
+ * Of course, if the sender implements sender side SWS prevention
+ * then this will not be a problem.
+ *
+ * BSD seems to make the following compromise:
+ *
+ * If the free space is less than the 1/4 of the maximum
+ * space available and the free space is less than 1/2 mss,
+ * then set the window to 0.
+ * Otherwise, just prevent the window from shrinking
+ * and from being larger than the largest representable value.
+ *
+ * This prevents incremental opening of the window in the regime
+ * where TCP is limited by the speed of the reader side taking
+ * data out of the TCP receive queue. It does nothing about
+ * those cases where the window is constrained on the sender side
+ * because the pipeline is full.
+ *
+ * BSD also seems to "accidentally" limit itself to windows that are a
+ * multiple of MSS, at least until the free space gets quite small.
+ * This would appear to be a side effect of the mbuf implementation.
+ * Combining these two algorithms results in the observed behavior
+ * of having a fixed window size at almost all times.
+ *
+ * Below we obtain similar behavior by forcing the offered window to
+ * a multiple of the mss when it is feasible to do so.
+ *
+ * Note, we don't "adjust" for TIMESTAMP or SACK option bytes.
+ */
+u32 __tcp_select_window(struct sock *sk)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ unsigned int mss = tp->mss_cache;
+ int free_space;
+ u32 window;
+
+ /* Sometimes free_space can be < 0. */
+ free_space = (sk->rcvbuf - atomic_read(&sk->rmem_alloc)) / 2;
+ if (tp->window_clamp) {
+ if (free_space > ((int) tp->window_clamp))
+ free_space = tp->window_clamp;
+ mss = min(tp->window_clamp, mss);
+ } else {
+ printk("tcp_select_window: tp->window_clamp == 0.\n");
+ }
+
+ if (mss < 1) {
+ mss = 1;
+ printk("tcp_select_window: sk->mss fell to 0.\n");
+ }
+
+ if ((free_space < (sk->rcvbuf/4)) && (free_space < ((int) (mss/2)))) {
+ window = 0;
+ tp->pred_flags = 0;
+ } else {
+ /* Get the largest window that is a nice multiple of mss.
+ * Window clamp already applied above.
+ * If our current window offering is within 1 mss of the
+ * free space we just keep it. This prevents the divide
+ * and multiply from happening most of the time.
+ * We also don't do any window rounding when the free space
+ * is too small.
+ */
+ window = tp->rcv_wnd;
+ if ((((int) window) <= (free_space - ((int) mss))) ||
+ (((int) window) > free_space))
+ window = (((unsigned int) free_space)/mss)*mss;
+ }
+ return window;
+}
+
+/* Attempt to collapse two adjacent SKB's during retransmission. */
+static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int mss_now)
+{
+ struct sk_buff *next_skb = skb->next;
+
+ /* The first test we must make is that neither of these two
+ * SKB's are still referenced by someone else.
+ */
+ if(!skb_cloned(skb) && !skb_cloned(next_skb)) {
+ int skb_size = skb->len, next_skb_size = next_skb->len;
+ u16 flags = TCP_SKB_CB(skb)->flags;
+
+ /* Punt if the first SKB has URG set. */
+ if(flags & TCPCB_FLAG_URG)
+ return;
+
+ /* Also punt if next skb has been SACK'd. */
+ if(TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_ACKED)
+ return;
+
+ /* Punt if not enough space exists in the first SKB for
+ * the data in the second, or the total combined payload
+ * would exceed the MSS.
+ */
+ if ((next_skb_size > skb_tailroom(skb)) ||
+ ((skb_size + next_skb_size) > mss_now))
+ return;
+
+ /* Ok. We will be able to collapse the packet. */
+ __skb_unlink(next_skb, next_skb->list);
+
+ if(skb->len % 4) {
+ /* Must copy and rechecksum all data. */
+ memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
+ skb->csum = csum_partial(skb->data, skb->len, 0);
+ } else {
+ /* Optimize, actually we could also combine next_skb->csum
+ * to skb->csum using a single add w/carry operation too.
+ */
+ skb->csum = csum_partial_copy(next_skb->data,
+ skb_put(skb, next_skb_size),
+ next_skb_size, skb->csum);
+ }
+
+ /* Update sequence range on original skb. */
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq;
+
+ /* Merge over control information. */
+ flags |= TCP_SKB_CB(next_skb)->flags; /* This moves PSH/FIN etc. over */
+ if(flags & TCPCB_FLAG_URG) {
+ u16 urgptr = TCP_SKB_CB(next_skb)->urg_ptr;
+ TCP_SKB_CB(skb)->urg_ptr = urgptr + skb_size;
+ }
+ TCP_SKB_CB(skb)->flags = flags;
+
+ /* All done, get rid of second SKB and account for it so
+ * packet counting does not break.
+ */
+ kfree_skb(next_skb);
+ sk->tp_pinfo.af_tcp.packets_out--;
+ }
+}
+
+/* Do a simple retransmit without using the backoff mechanisms in
+ * tcp_timer. This is used for path mtu discovery.
+ * The socket is already locked here.
+ */
+void tcp_simple_retransmit(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb, *old_next_skb;
+ unsigned int mss = tcp_current_mss(sk);
+
+ /* Don't muck with the congestion window here. */
+ tp->dup_acks = 0;
+ tp->high_seq = tp->snd_nxt;
+ tp->retrans_head = NULL;
+
+ /* Input control flow will see that this was retransmitted
+ * and not use it for RTT calculation in the absence of
+ * the timestamp option.
+ */
+ for (old_next_skb = skb = skb_peek(&sk->write_queue);
+ ((skb != tp->send_head) &&
+ (skb != (struct sk_buff *)&sk->write_queue));
+ skb = skb->next) {
+ int resend_skb = 0;
+
+ /* Our goal is to push out the packets which we
+ * sent already, but are being chopped up now to
+ * account for the PMTU information we have.
+ *
+ * As we resend the queue, packets are fragmented
+ * into two pieces, and when we try to send the
+ * second piece it may be collapsed together with
+ * a subsequent packet, and so on. -DaveM
+ */
+ if (old_next_skb != skb || skb->len > mss)
+ resend_skb = 1;
+ old_next_skb = skb->next;
+ if (resend_skb != 0)
+ tcp_retransmit_skb(sk, skb);
+ }
+}
+
+static __inline__ void update_retrans_head(struct sock *sk)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ tp->retrans_head = tp->retrans_head->next;
+ if((tp->retrans_head == tp->send_head) ||
+ (tp->retrans_head == (struct sk_buff *) &sk->write_queue)) {
+ tp->retrans_head = NULL;
+ tp->rexmt_done = 1;
+ }
+}
+
+/* This retransmits one SKB. Policy decisions and retransmit queue
+ * state updates are done by the caller. Returns non-zero if an
+ * error occurred which prevented the send.
+ */
+int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ unsigned int cur_mss = tcp_current_mss(sk);
+
+ if(skb->len > cur_mss) {
+ if(tcp_fragment(sk, skb, cur_mss))
+ return 1; /* We'll try again later. */
+
+ /* New SKB created, account for it. */
+ tp->packets_out++;
+ }
+
+ /* Collapse two adjacent packets if worthwhile and we can. */
+ if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&
+ (skb->len < (cur_mss >> 1)) &&
+ (skb->next != tp->send_head) &&
+ (skb->next != (struct sk_buff *)&sk->write_queue) &&
+ (sysctl_tcp_retrans_collapse != 0))
+ tcp_retrans_try_collapse(sk, skb, cur_mss);
+
+ if(tp->af_specific->rebuild_header(sk))
+ return 1; /* Routing failure or similar. */
+
+ /* Some Solaris stacks overoptimize and ignore the FIN on a
+ * retransmit when old data is attached. So strip it off
+ * since it is cheap to do so and saves bytes on the network.
+ */
+ if(skb->len > 0 &&
+ (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
+ tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
+ TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
+ skb_trim(skb, 0);
+ skb->csum = 0;
+ }
+
+ /* Ok, we're gonna send it out, update state. */
+ TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_RETRANS;
+ tp->retrans_out++;
+
+ /* Make a copy, if the first transmission SKB clone we made
+ * is still in somebody's hands, else make a clone.
+ */
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ if(skb_cloned(skb))
+ skb = skb_copy(skb, GFP_ATOMIC);
+ else
+ skb = skb_clone(skb, GFP_ATOMIC);
+
+ tcp_transmit_skb(sk, skb);
+
+ /* Update global TCP statistics and return success. */
+ sk->prot->retransmits++;
+ tcp_statistics.TcpRetransSegs++;
+
+ return 0;
+}
+
+/* This gets called after a retransmit timeout, and the initially
+ * retransmitted data is acknowledged. It tries to continue
+ * resending the rest of the retransmit queue, until either
+ * we've sent it all or the congestion window limit is reached.
+ * If doing SACK, the first ACK which comes back for a timeout
+ * based retransmit packet might feed us FACK information again.
+ * If so, we use it to avoid unnecessarily retransmissions.
+ */
+void tcp_xmit_retransmit_queue(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb;
+
+ if (tp->retrans_head == NULL &&
+ tp->rexmt_done == 0)
+ tp->retrans_head = skb_peek(&sk->write_queue);
+ if (tp->retrans_head == tp->send_head)
+ tp->retrans_head = NULL;
+
+ /* Each time, advance the retrans_head if we got
+ * a packet out or we skipped one because it was
+ * SACK'd. -DaveM
+ */
+ while ((skb = tp->retrans_head) != NULL) {
+ /* If it has been ack'd by a SACK block, we don't
+ * retransmit it.
+ */
+ if(!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
+ /* Send it out, punt if error occurred. */
+ if(tcp_retransmit_skb(sk, skb))
+ break;
+
+ update_retrans_head(sk);
+
+ /* Stop retransmitting if we've hit the congestion
+ * window limit.
+ */
+ if (tp->retrans_out >= tp->snd_cwnd)
+ break;
+ } else {
+ update_retrans_head(sk);
+ }
+ }
+}
+
+/* Using FACK information, retransmit all missing frames at the receiver
+ * up to the forward most SACK'd packet (tp->fackets_out) if the packet
+ * has not been retransmitted already.
+ */
+void tcp_fack_retransmit(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb = skb_peek(&sk->write_queue);
+ int packet_cnt = 0;
+
+ while((skb != NULL) &&
+ (skb != tp->send_head) &&
+ (skb != (struct sk_buff *)&sk->write_queue)) {
+ __u8 sacked = TCP_SKB_CB(skb)->sacked;
+
+ if(sacked & (TCPCB_SACKED_ACKED | TCPCB_SACKED_RETRANS))
+ goto next_packet;
+
+ /* Ok, retransmit it. */
+ if(tcp_retransmit_skb(sk, skb))
+ break;
+
+ if(tcp_packets_in_flight(tp) >= tp->snd_cwnd)
+ break;
+next_packet:
+ packet_cnt++;
+ if(packet_cnt >= tp->fackets_out)
+ break;
+ skb = skb->next;
+ }
+}
+
+/* Send a fin. The caller locks the socket for us. This cannot be
+ * allowed to fail queueing a FIN frame under any circumstances.
+ */
+void tcp_send_fin(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb = skb_peek_tail(&sk->write_queue);
+ unsigned int mss_now;
+
+ /* Optimization, tack on the FIN if we have a queue of
+ * unsent frames. But be careful about outgoing SACKS
+ * and IP options.
+ */
+ mss_now = tcp_current_mss(sk);
+
+ if((tp->send_head != NULL) && (skb->len < mss_now)) {
+ /* tcp_write_xmit() takes care of the rest. */
+ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
+ TCP_SKB_CB(skb)->end_seq++;
+ tp->write_seq++;
+
+ /* Special case to avoid Nagle bogosity. If this
+ * segment is the last segment, and it was queued
+ * due to Nagle/SWS-avoidance, send it out now.
+ */
+ if(tp->send_head == skb &&
+ !sk->nonagle &&
+ skb->len < (tp->mss_cache >> 1) &&
+ tp->packets_out &&
+ !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG)) {
+ update_send_head(sk);
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
+ tp->packets_out++;
+ tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
+ if(!tcp_timer_is_set(sk, TIME_RETRANS))
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ }
+ } else {
+ /* Socket is locked, keep trying until memory is available. */
+ do {
+ skb = sock_wmalloc(sk,
+ (MAX_HEADER +
+ sk->prot->max_header),
+ 1, GFP_KERNEL);
+ } while (skb == NULL);
+
+ /* Reserve space for headers and prepare control bits. */
+ skb_reserve(skb, MAX_HEADER + sk->prot->max_header);
+ skb->csum = 0;
+ TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
+ TCP_SKB_CB(skb)->sacked = 0;
+ TCP_SKB_CB(skb)->urg_ptr = 0;
+
+ /* FIN eats a sequence byte, write_seq advanced by tcp_send_skb(). */
+ TCP_SKB_CB(skb)->seq = tp->write_seq;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
+ tcp_send_skb(sk, skb, 0);
+ }
+}
+
+/* We get here when a process closes a file descriptor (either due to
+ * an explicit close() or as a byproduct of exit()'ing) and there
+ * was unread data in the receive queue. This behavior is recommended
+ * by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM
+ */
+void tcp_send_active_reset(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb;
+
+ /* NOTE: No TCP options attached and we never retransmit this. */
+ skb = alloc_skb(MAX_HEADER + sk->prot->max_header, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ /* Reserve space for headers and prepare control bits. */
+ skb_reserve(skb, MAX_HEADER + sk->prot->max_header);
+ skb->csum = 0;
+ TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
+ TCP_SKB_CB(skb)->sacked = 0;
+ TCP_SKB_CB(skb)->urg_ptr = 0;
+
+ /* Send it off. */
+ TCP_SKB_CB(skb)->seq = tp->write_seq;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq;
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tcp_transmit_skb(sk, skb);
+}
+
+/* WARNING: This routine must only be called when we have already sent
+ * a SYN packet that crossed the incoming SYN that caused this routine
+ * to get called. If this assumption fails then the initial rcv_wnd
+ * and rcv_wscale values will not be correct.
+ */
+int tcp_send_synack(struct sock *sk)
+{
+ struct tcp_opt* tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff* skb;
+
+ skb = sock_wmalloc(sk, (MAX_HEADER + sk->prot->max_header),
+ 1, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ /* Reserve space for headers and prepare control bits. */
+ skb_reserve(skb, MAX_HEADER + sk->prot->max_header);
+ skb->csum = 0;
+ TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_SYN);
+ TCP_SKB_CB(skb)->sacked = 0;
+ TCP_SKB_CB(skb)->urg_ptr = 0;
+
+ /* SYN eats a sequence byte. */
+ TCP_SKB_CB(skb)->seq = tp->snd_una;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
+ __skb_queue_tail(&sk->write_queue, skb);
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tp->packets_out++;
+ tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
+ return 0;
+}
+
+/*
+ * Prepare a SYN-ACK.
+ */
+struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
+ struct open_request *req, int mss)
+{
+ struct tcphdr *th;
+ int tcp_header_size;
+ struct sk_buff *skb;
+
+ skb = sock_wmalloc(sk, MAX_HEADER + sk->prot->max_header, 1, GFP_ATOMIC);
+ if (skb == NULL)
+ return NULL;
+
+ /* Reserve space for headers. */
+ skb_reserve(skb, MAX_HEADER + sk->prot->max_header);
+
+ skb->dst = dst_clone(dst);
+
+ /* Don't offer more than they did.
+ * This way we don't have to memorize who said what.
+ * FIXME: maybe this should be changed for better performance
+ * with syncookies.
+ */
+ req->mss = min(mss, req->mss);
+ if (req->mss < 8) {
+ printk(KERN_DEBUG "initial req->mss below 8\n");
+ req->mss = 8;
+ }
+
+ tcp_header_size = (sizeof(struct tcphdr) + TCPOLEN_MSS +
+ (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) +
+ (req->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) +
+ /* SACK_PERM is in the place of NOP NOP of TS */
+ ((req->sack_ok && !req->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0));
+ skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size);
+
+ memset(th, 0, sizeof(struct tcphdr));
+ th->syn = 1;
+ th->ack = 1;
+ th->source = sk->sport;
+ th->dest = req->rmt_port;
+ TCP_SKB_CB(skb)->seq = req->snt_isn;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
+ th->seq = htonl(TCP_SKB_CB(skb)->seq);
+ th->ack_seq = htonl(req->rcv_isn + 1);
+ if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
+ __u8 rcv_wscale;
+ /* Set this up on the first call only */
+ req->window_clamp = skb->dst->window;
+ tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
+ &req->rcv_wnd,
+ &req->window_clamp,
+ req->wscale_ok,
+ &rcv_wscale);
+ req->rcv_wscale = rcv_wscale;
+ }
+
+ /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
+ th->window = htons(req->rcv_wnd);
+
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tcp_syn_build_options((__u32 *)(th + 1), req->mss, req->tstamp_ok,
+ req->sack_ok, req->wscale_ok, req->rcv_wscale,
+ TCP_SKB_CB(skb)->when,
+ req->ts_recent);
+
+ skb->csum = 0;
+ th->doff = (tcp_header_size >> 2);
+ tcp_statistics.TcpOutSegs++;
+ return skb;
+}
+
+void tcp_connect(struct sock *sk, struct sk_buff *buff, int mtu)
+{
+ struct dst_entry *dst = sk->dst_cache;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Reserve space for headers. */
+ skb_reserve(buff, MAX_HEADER + sk->prot->max_header);
+
+ tp->snd_wnd = 0;
+ tp->snd_wl1 = 0;
+ tp->snd_wl2 = tp->write_seq;
+ tp->snd_una = tp->write_seq;
+ tp->rcv_nxt = 0;
+
+ sk->err = 0;
+
+ /* We'll fix this up when we get a response from the other end.
+ * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
+ */
+ tp->tcp_header_len = sizeof(struct tcphdr) +
+ (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0);
+
+ /* If user gave his TCP_MAXSEG, record it to clamp */
+ if (tp->user_mss)
+ tp->mss_clamp = tp->user_mss;
+ tcp_sync_mss(sk, mtu);
+
+ /* Now unpleasant action: if initial pmtu is too low
+ set lower clamp. I am not sure that it is good.
+ To be more exact, I do not think that clamping at value, which
+ is apparently transient and may improve in future is good idea.
+ It would be better to wait until peer will returns its MSS
+ (probably 65535 too) and now advertise something sort of 65535
+ or at least first hop device mtu. Is it clear, what I mean?
+ We should tell peer what maximal mss we expect to RECEIVE,
+ it has nothing to do with pmtu.
+ I am afraid someone will be confused by such huge value.
+ --ANK (980731)
+ */
+ if (tp->mss_cache + tp->tcp_header_len - sizeof(struct tcphdr) < tp->mss_clamp )
+ tp->mss_clamp = tp->mss_cache + tp->tcp_header_len - sizeof(struct tcphdr);
+
+ TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
+ TCP_SKB_CB(buff)->sacked = 0;
+ TCP_SKB_CB(buff)->urg_ptr = 0;
+ buff->csum = 0;
+ TCP_SKB_CB(buff)->seq = tp->write_seq++;
+ TCP_SKB_CB(buff)->end_seq = tp->write_seq;
+ tp->snd_nxt = TCP_SKB_CB(buff)->end_seq;
+
+ tp->window_clamp = dst->window;
+ tcp_select_initial_window(sock_rspace(sk)/2,tp->mss_clamp,
+ &tp->rcv_wnd,
+ &tp->window_clamp,
+ sysctl_tcp_window_scaling,
+ &tp->rcv_wscale);
+ /* Ok, now lock the socket before we make it visible to
+ * the incoming packet engine.
+ */
+ lock_sock(sk);
+
+ /* Socket identity change complete, no longer
+ * in TCP_CLOSE, so enter ourselves into the
+ * hash tables.
+ */
+ tcp_set_state(sk,TCP_SYN_SENT);
+ sk->prot->hash(sk);
+
+ tp->rto = dst->rtt;
+ tcp_init_xmit_timers(sk);
+ tp->retransmits = 0;
+ tp->fackets_out = 0;
+ tp->retrans_out = 0;
+
+ /* Send it off. */
+ __skb_queue_tail(&sk->write_queue, buff);
+ TCP_SKB_CB(buff)->when = tcp_time_stamp;
+ tp->packets_out++;
+ tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL));
+ tcp_statistics.TcpActiveOpens++;
+
+ /* Timer for repeating the SYN until an answer. */
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+
+ /* Now, it is safe to release the socket. */
+ release_sock(sk);
+}
+
+/* Send out a delayed ack, the caller does the policy checking
+ * to see if we should even be here. See tcp_input.c:tcp_ack_snd_check()
+ * for details.
+ */
+void tcp_send_delayed_ack(struct tcp_opt *tp, int max_timeout)
+{
+ unsigned long timeout;
+
+ /* Stay within the limit we were given */
+ timeout = tp->ato;
+ if (timeout > max_timeout)
+ timeout = max_timeout;
+ timeout += jiffies;
+
+ /* Use new timeout only if there wasn't a older one earlier. */
+ if (!tp->delack_timer.prev) {
+ tp->delack_timer.expires = timeout;
+ add_timer(&tp->delack_timer);
+ } else {
+ if (time_before(timeout, tp->delack_timer.expires))
+ mod_timer(&tp->delack_timer, timeout);
+ }
+}
+
+/* This routine sends an ack and also updates the window. */
+void tcp_send_ack(struct sock *sk)
+{
+ /* If we have been reset, we may not send again. */
+ if(!sk->zapped) {
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *buff;
+
+ /* We are not putting this on the write queue, so
+ * tcp_transmit_skb() will set the ownership to this
+ * sock.
+ */
+ buff = alloc_skb(MAX_HEADER + sk->prot->max_header, GFP_ATOMIC);
+ if (buff == NULL) {
+ /* Force it to send an ack. We don't have to do this
+ * (ACK is unreliable) but it's much better use of
+ * bandwidth on slow links to send a spare ack than
+ * resend packets.
+ *
+ * This is the one possible way that we can delay an
+ * ACK and have tp->ato indicate that we are in
+ * quick ack mode, so clear it.
+ */
+ if(tcp_in_quickack_mode(tp))
+ tcp_exit_quickack_mode(tp);
+ tcp_send_delayed_ack(tp, HZ/2);
+ return;
+ }
+
+ /* Reserve space for headers and prepare control bits. */
+ skb_reserve(buff, MAX_HEADER + sk->prot->max_header);
+ buff->csum = 0;
+ TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK;
+ TCP_SKB_CB(buff)->sacked = 0;
+ TCP_SKB_CB(buff)->urg_ptr = 0;
+
+ /* Send it off, this clears delayed acks for us. */
+ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tp->snd_nxt;
+ TCP_SKB_CB(buff)->when = tcp_time_stamp;
+ tcp_transmit_skb(sk, buff);
+ }
+}
+
+/* This routine sends a packet with an out of date sequence
+ * number. It assumes the other end will try to ack it.
+ */
+void tcp_write_wakeup(struct sock *sk)
+{
+ /* After a valid reset we can send no more. */
+ if (!sk->zapped) {
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb;
+
+ /* Write data can still be transmitted/retransmitted in the
+ * following states. If any other state is encountered, return.
+ * [listen/close will never occur here anyway]
+ */
+ if ((1 << sk->state) &
+ ~(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT1|
+ TCPF_LAST_ACK|TCPF_CLOSING))
+ return;
+
+ if (before(tp->snd_nxt, tp->snd_una + tp->snd_wnd) &&
+ ((skb = tp->send_head) != NULL)) {
+ unsigned long win_size;
+
+ /* We are probing the opening of a window
+ * but the window size is != 0
+ * must have been a result SWS avoidance ( sender )
+ */
+ win_size = tp->snd_wnd - (tp->snd_nxt - tp->snd_una);
+ if (win_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq) {
+ if (tcp_fragment(sk, skb, win_size))
+ return; /* Let a retransmit get it. */
+ }
+ update_send_head(sk);
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
+ tp->packets_out++;
+ tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
+ if (!tcp_timer_is_set(sk, TIME_RETRANS))
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ } else {
+ /* We don't queue it, tcp_transmit_skb() sets ownership. */
+ skb = alloc_skb(MAX_HEADER + sk->prot->max_header,
+ GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+
+ /* Reserve space for headers and set control bits. */
+ skb_reserve(skb, MAX_HEADER + sk->prot->max_header);
+ skb->csum = 0;
+ TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
+ TCP_SKB_CB(skb)->sacked = 0;
+ TCP_SKB_CB(skb)->urg_ptr = 0;
+
+ /* Use a previous sequence. This should cause the other
+ * end to send an ack. Don't queue or clone SKB, just
+ * send it.
+ */
+ TCP_SKB_CB(skb)->seq = tp->snd_nxt - 1;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq;
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+ tcp_transmit_skb(sk, skb);
+ }
+ }
+}
+
+/* A window probe timeout has occurred. If window is not closed send
+ * a partial packet else a zero probe.
+ */
+void tcp_send_probe0(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ tcp_write_wakeup(sk);
+ tp->pending = TIME_PROBE0;
+ tp->backoff++;
+ tp->probes_out++;
+ tcp_reset_xmit_timer (sk, TIME_PROBE0,
+ min(tp->rto << tp->backoff, 120*HZ));
+}
diff --git a/pfinet/linux-src/net/ipv4/tcp_timer.c b/pfinet/linux-src/net/ipv4/tcp_timer.c
new file mode 100644
index 00000000..7529a441
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/tcp_timer.c
@@ -0,0 +1,595 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Implementation of the Transmission Control Protocol(TCP).
+ *
+ * Version: $Id: tcp_timer.c,v 1.62.2.4 1999/09/23 19:21:39 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Mark Evans, <evansmp@uhura.aston.ac.uk>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ * Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
+ * Linus Torvalds, <torvalds@cs.helsinki.fi>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Matthew Dillon, <dillon@apollo.west.oic.com>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Jorge Cwik, <jorge@laser.satlink.net>
+ */
+
+#include <net/tcp.h>
+
+int sysctl_tcp_syn_retries = TCP_SYN_RETRIES;
+int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME;
+int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES;
+int sysctl_tcp_retries1 = TCP_RETR1;
+int sysctl_tcp_retries2 = TCP_RETR2;
+
+static void tcp_sltimer_handler(unsigned long);
+static void tcp_syn_recv_timer(unsigned long);
+static void tcp_keepalive(unsigned long data);
+static void tcp_twkill(unsigned long);
+
+struct timer_list tcp_slow_timer = {
+ NULL, NULL,
+ 0, 0,
+ tcp_sltimer_handler,
+};
+
+
+struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = {
+ {ATOMIC_INIT(0), TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK */
+ {ATOMIC_INIT(0), TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive}, /* KEEPALIVE */
+ {ATOMIC_INIT(0), TCP_TWKILL_PERIOD, 0, tcp_twkill} /* TWKILL */
+};
+
+const char timer_bug_msg[] = KERN_DEBUG "tcpbug: unknown timer value\n";
+
+/*
+ * Using different timers for retransmit, delayed acks and probes
+ * We may wish use just one timer maintaining a list of expire jiffies
+ * to optimize.
+ */
+
+void tcp_init_xmit_timers(struct sock *sk)
+{
+ init_timer(&sk->tp_pinfo.af_tcp.retransmit_timer);
+ sk->tp_pinfo.af_tcp.retransmit_timer.function=&tcp_retransmit_timer;
+ sk->tp_pinfo.af_tcp.retransmit_timer.data = (unsigned long) sk;
+
+ init_timer(&sk->tp_pinfo.af_tcp.delack_timer);
+ sk->tp_pinfo.af_tcp.delack_timer.function=&tcp_delack_timer;
+ sk->tp_pinfo.af_tcp.delack_timer.data = (unsigned long) sk;
+
+ init_timer(&sk->tp_pinfo.af_tcp.probe_timer);
+ sk->tp_pinfo.af_tcp.probe_timer.function=&tcp_probe_timer;
+ sk->tp_pinfo.af_tcp.probe_timer.data = (unsigned long) sk;
+}
+
+/*
+ * Reset the retransmission timer
+ */
+
+void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long when)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ switch (what) {
+ case TIME_RETRANS:
+ /* When seting the transmit timer the probe timer
+ * should not be set.
+ * The delayed ack timer can be set if we are changing the
+ * retransmit timer when removing acked frames.
+ */
+ if(tp->probe_timer.prev)
+ del_timer(&tp->probe_timer);
+ mod_timer(&tp->retransmit_timer, jiffies+when);
+ break;
+
+ case TIME_DACK:
+ mod_timer(&tp->delack_timer, jiffies+when);
+ break;
+
+ case TIME_PROBE0:
+ mod_timer(&tp->probe_timer, jiffies+when);
+ break;
+
+ case TIME_WRITE:
+ printk(KERN_DEBUG "bug: tcp_reset_xmit_timer TIME_WRITE\n");
+ break;
+
+ default:
+ printk(KERN_DEBUG "bug: unknown timer value\n");
+ };
+}
+
+void tcp_clear_xmit_timers(struct sock *sk)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ if(tp->retransmit_timer.prev)
+ del_timer(&tp->retransmit_timer);
+ if(tp->delack_timer.prev)
+ del_timer(&tp->delack_timer);
+ if(tp->probe_timer.prev)
+ del_timer(&tp->probe_timer);
+}
+
+static int tcp_write_err(struct sock *sk, int force)
+{
+ sk->err = sk->err_soft ? sk->err_soft : ETIMEDOUT;
+ sk->error_report(sk);
+
+ tcp_clear_xmit_timers(sk);
+
+ /* Time wait the socket. */
+ if (!force && ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING))) {
+ tcp_time_wait(sk);
+ } else {
+ /* Clean up time. */
+ tcp_set_state(sk, TCP_CLOSE);
+ return 0;
+ }
+ return 1;
+}
+
+/* A write timeout has occurred. Process the after effects. */
+static int tcp_write_timeout(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ /* Look for a 'soft' timeout. */
+ if ((sk->state == TCP_ESTABLISHED &&
+ tp->retransmits && (tp->retransmits % TCP_QUICK_TRIES) == 0) ||
+ (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) {
+ dst_negative_advice(&sk->dst_cache);
+ }
+
+ /* Have we tried to SYN too many times (repent repent 8)) */
+ if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {
+ tcp_write_err(sk, 1);
+ /* Don't FIN, we got nothing back */
+ return 0;
+ }
+
+ /* Has it gone just too far? */
+ if (tp->retransmits > sysctl_tcp_retries2)
+ return tcp_write_err(sk, 0);
+
+ return 1;
+}
+
+void tcp_delack_timer(unsigned long data)
+{
+ struct sock *sk = (struct sock*)data;
+
+ if(!sk->zapped &&
+ sk->tp_pinfo.af_tcp.delayed_acks &&
+ sk->state != TCP_CLOSE) {
+ /* If socket is currently locked, defer the ACK. */
+ if (!atomic_read(&sk->sock_readers))
+ tcp_send_ack(sk);
+ else
+ tcp_send_delayed_ack(&(sk->tp_pinfo.af_tcp), HZ/10);
+ }
+}
+
+void tcp_probe_timer(unsigned long data)
+{
+ struct sock *sk = (struct sock*)data;
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ if(sk->zapped)
+ return;
+
+ if (atomic_read(&sk->sock_readers)) {
+ /* Try again later. */
+ tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ/5);
+ return;
+ }
+
+ /* *WARNING* RFC 1122 forbids this
+ * It doesn't AFAIK, because we kill the retransmit timer -AK
+ * FIXME: We ought not to do it, Solaris 2.5 actually has fixing
+ * this behaviour in Solaris down as a bug fix. [AC]
+ */
+ if (tp->probes_out > sysctl_tcp_retries2) {
+ if(sk->err_soft)
+ sk->err = sk->err_soft;
+ else
+ sk->err = ETIMEDOUT;
+ sk->error_report(sk);
+
+ if ((1<<sk->state) & (TCPF_FIN_WAIT1|TCPF_FIN_WAIT2|TCPF_CLOSING)) {
+ /* Time wait the socket. */
+ tcp_time_wait(sk);
+ } else {
+ /* Clean up time. */
+ tcp_set_state(sk, TCP_CLOSE);
+ }
+ } else {
+ /* Only send another probe if we didn't close things up. */
+ tcp_send_probe0(sk);
+ }
+}
+
+static __inline__ int tcp_keepopen_proc(struct sock *sk)
+{
+ int res = 0;
+
+ if ((1<<sk->state) & (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT2)) {
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+
+ if (elapsed >= sysctl_tcp_keepalive_time) {
+ if (tp->probes_out > sysctl_tcp_keepalive_probes) {
+ if(sk->err_soft)
+ sk->err = sk->err_soft;
+ else
+ sk->err = ETIMEDOUT;
+
+ tcp_set_state(sk, TCP_CLOSE);
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ sk->state_change(sk);
+ } else {
+ tp->probes_out++;
+ tp->pending = TIME_KEEPOPEN;
+ tcp_write_wakeup(sk);
+ res = 1;
+ }
+ }
+ }
+ return res;
+}
+
+/* Kill off TIME_WAIT sockets once their lifetime has expired. */
+int tcp_tw_death_row_slot = 0;
+static struct tcp_tw_bucket *tcp_tw_death_row[TCP_TWKILL_SLOTS] =
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+
+extern void tcp_timewait_kill(struct tcp_tw_bucket *tw);
+
+static void tcp_twkill(unsigned long data)
+{
+ struct tcp_tw_bucket *tw;
+ int killed = 0;
+
+ tw = tcp_tw_death_row[tcp_tw_death_row_slot];
+ tcp_tw_death_row[tcp_tw_death_row_slot] = NULL;
+ while(tw != NULL) {
+ struct tcp_tw_bucket *next = tw->next_death;
+
+ tcp_timewait_kill(tw);
+ killed++;
+ tw = next;
+ }
+ if(killed != 0) {
+ struct tcp_sl_timer *slt = (struct tcp_sl_timer *)data;
+ atomic_sub(killed, &slt->count);
+ }
+ tcp_tw_death_row_slot =
+ ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1));
+}
+
+/* These are always called from BH context. See callers in
+ * tcp_input.c to verify this.
+ */
+void tcp_tw_schedule(struct tcp_tw_bucket *tw)
+{
+ int slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+ struct tcp_tw_bucket **tpp = &tcp_tw_death_row[slot];
+
+ if((tw->next_death = *tpp) != NULL)
+ (*tpp)->pprev_death = &tw->next_death;
+ *tpp = tw;
+ tw->pprev_death = tpp;
+
+ tw->death_slot = slot;
+
+ tcp_inc_slow_timer(TCP_SLT_TWKILL);
+}
+
+/* Happens rarely if at all, no care about scalability here. */
+void tcp_tw_reschedule(struct tcp_tw_bucket *tw)
+{
+ struct tcp_tw_bucket **tpp;
+ int slot;
+
+ if(tw->next_death)
+ tw->next_death->pprev_death = tw->pprev_death;
+ *tw->pprev_death = tw->next_death;
+ tw->pprev_death = NULL;
+
+ slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+ tpp = &tcp_tw_death_row[slot];
+ if((tw->next_death = *tpp) != NULL)
+ (*tpp)->pprev_death = &tw->next_death;
+ *tpp = tw;
+ tw->pprev_death = tpp;
+
+ tw->death_slot = slot;
+ /* Timer was incremented when we first entered the table. */
+}
+
+/* This is for handling early-kills of TIME_WAIT sockets. */
+void tcp_tw_deschedule(struct tcp_tw_bucket *tw)
+{
+ if(tw->next_death)
+ tw->next_death->pprev_death = tw->pprev_death;
+ *tw->pprev_death = tw->next_death;
+ tw->pprev_death = NULL;
+ tcp_dec_slow_timer(TCP_SLT_TWKILL);
+}
+
+/*
+ * Check all sockets for keepalive timer
+ * Called every 75 seconds
+ * This timer is started by af_inet init routine and is constantly
+ * running.
+ *
+ * It might be better to maintain a count of sockets that need it using
+ * setsockopt/tcp_destroy_sk and only set the timer when needed.
+ */
+
+/*
+ * don't send over 5 keepopens at a time to avoid burstiness
+ * on big servers [AC]
+ */
+#define MAX_KA_PROBES 5
+
+int sysctl_tcp_max_ka_probes = MAX_KA_PROBES;
+
+/* Keepopen's are only valid for "established" TCP's, nicely our listener
+ * hash gets rid of most of the useless testing, so we run through a couple
+ * of the established hash chains each clock tick. -DaveM
+ *
+ * And now, even more magic... TIME_WAIT TCP's cannot have keepalive probes
+ * going off for them, so we only need check the first half of the established
+ * hash table, even less testing under heavy load.
+ *
+ * I _really_ would rather do this by adding a new timer_struct to struct sock,
+ * and this way only those who set the keepalive option will get the overhead.
+ * The idea is you set it for 2 hours when the sock is first connected, when it
+ * does fire off (if at all, most sockets die earlier) you check for the keepalive
+ * option and also if the sock has been idle long enough to start probing.
+ */
+static void tcp_keepalive(unsigned long data)
+{
+ static int chain_start = 0;
+ int count = 0;
+ int i;
+
+ for(i = chain_start; i < (chain_start + ((tcp_ehash_size/2) >> 2)); i++) {
+ struct sock *sk = tcp_ehash[i];
+ while(sk) {
+ if(!atomic_read(&sk->sock_readers) && sk->keepopen) {
+ count += tcp_keepopen_proc(sk);
+ if(count == sysctl_tcp_max_ka_probes)
+ goto out;
+ }
+ sk = sk->next;
+ }
+ }
+out:
+ chain_start = ((chain_start + ((tcp_ehash_size/2)>>2)) &
+ ((tcp_ehash_size/2) - 1));
+}
+
+/*
+ * The TCP retransmit timer. This lacks a few small details.
+ *
+ * 1. An initial rtt timeout on the probe0 should cause what we can
+ * of the first write queue buffer to be split and sent.
+ * 2. On a 'major timeout' as defined by RFC1122 we shouldn't report
+ * ETIMEDOUT if we know an additional 'soft' error caused this.
+ * tcp_err should save a 'soft error' for us.
+ * [Unless someone has broken it then it does, except for one 2.0
+ * broken case of a send when the route/device is directly unreachable,
+ * and we error but should retry! - FIXME] [AC]
+ */
+
+void tcp_retransmit_timer(unsigned long data)
+{
+ struct sock *sk = (struct sock*)data;
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ /* We are reset. We will send no more retransmits. */
+ if(sk->zapped) {
+ tcp_clear_xmit_timer(sk, TIME_RETRANS);
+ return;
+ }
+
+ if (atomic_read(&sk->sock_readers)) {
+ /* Try again later */
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, HZ/20);
+ return;
+ }
+
+ /* Clear delay ack timer. */
+ tcp_clear_xmit_timer(sk, TIME_DACK);
+
+ /* RFC 2018, clear all 'sacked' flags in retransmission queue,
+ * the sender may have dropped out of order frames and we must
+ * send them out should this timer fire on us.
+ */
+ if(tp->sack_ok) {
+ struct sk_buff *skb = skb_peek(&sk->write_queue);
+
+ while((skb != NULL) &&
+ (skb != tp->send_head) &&
+ (skb != (struct sk_buff *)&sk->write_queue)) {
+ TCP_SKB_CB(skb)->sacked &=
+ ~(TCPCB_SACKED_ACKED | TCPCB_SACKED_RETRANS);
+ skb = skb->next;
+ }
+ }
+
+ /* Retransmission. */
+ tp->retrans_head = NULL;
+ tp->rexmt_done = 0;
+ tp->fackets_out = 0;
+ tp->retrans_out = 0;
+ if (tp->retransmits == 0) {
+ /* Remember window where we lost:
+ * "one half of the current window but at least 2 segments"
+ *
+ * Here "current window" means the effective one, which
+ * means it must be an accurate representation of our current
+ * sending rate _and_ the snd_wnd.
+ */
+ tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+ tp->snd_cwnd_cnt = 0;
+ tp->snd_cwnd = 1;
+ }
+
+ tp->retransmits++;
+
+ tp->dup_acks = 0;
+ tp->high_seq = tp->snd_nxt;
+ tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+
+ /* Increase the timeout each time we retransmit. Note that
+ * we do not increase the rtt estimate. rto is initialized
+ * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests
+ * that doubling rto each time is the least we can get away with.
+ * In KA9Q, Karn uses this for the first few times, and then
+ * goes to quadratic. netBSD doubles, but only goes up to *64,
+ * and clamps at 1 to 64 sec afterwards. Note that 120 sec is
+ * defined in the protocol as the maximum possible RTT. I guess
+ * we'll have to use something other than TCP to talk to the
+ * University of Mars.
+ *
+ * PAWS allows us longer timeouts and large windows, so once
+ * implemented ftp to mars will work nicely. We will have to fix
+ * the 120 second clamps though!
+ */
+ tp->backoff++;
+ tp->rto = min(tp->rto << 1, 120*HZ);
+ tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+
+ tcp_write_timeout(sk);
+}
+
+/*
+ * Slow timer for SYN-RECV sockets
+ */
+
+/* This now scales very nicely. -DaveM */
+static void tcp_syn_recv_timer(unsigned long data)
+{
+ struct sock *sk;
+ unsigned long now = jiffies;
+ int i;
+
+ for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
+ sk = tcp_listening_hash[i];
+
+ while(sk) {
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+
+ /* TCP_LISTEN is implied. */
+ if (!atomic_read(&sk->sock_readers) && tp->syn_wait_queue) {
+ struct open_request *prev = (struct open_request *)(&tp->syn_wait_queue);
+ struct open_request *req = tp->syn_wait_queue;
+ do {
+ struct open_request *conn;
+
+ conn = req;
+ req = req->dl_next;
+
+ if (conn->sk ||
+ ((long)(now - conn->expires)) <= 0) {
+ prev = conn;
+ continue;
+ }
+
+ tcp_synq_unlink(tp, conn, prev);
+ if (conn->retrans >= sysctl_tcp_retries1) {
+#ifdef TCP_DEBUG
+ printk(KERN_DEBUG "syn_recv: "
+ "too many retransmits\n");
+#endif
+ (*conn->class->destructor)(conn);
+ tcp_dec_slow_timer(TCP_SLT_SYNACK);
+ tp->syn_backlog--;
+ tcp_openreq_free(conn);
+
+ if (!tp->syn_wait_queue)
+ break;
+ } else {
+ unsigned long timeo;
+ struct open_request *op;
+
+ (*conn->class->rtx_syn_ack)(sk, conn);
+
+ conn->retrans++;
+#ifdef TCP_DEBUG
+ printk(KERN_DEBUG "syn_ack rtx %d\n",
+ conn->retrans);
+#endif
+ timeo = min((TCP_TIMEOUT_INIT
+ << conn->retrans),
+ 120*HZ);
+ conn->expires = now + timeo;
+ op = prev->dl_next;
+ tcp_synq_queue(tp, conn);
+ if (op != prev->dl_next)
+ prev = prev->dl_next;
+ }
+ /* old prev still valid here */
+ } while (req);
+ }
+ sk = sk->next;
+ }
+ }
+}
+
+void tcp_sltimer_handler(unsigned long data)
+{
+ struct tcp_sl_timer *slt = tcp_slt_array;
+ unsigned long next = ~0UL;
+ unsigned long now = jiffies;
+ int i;
+
+ for (i=0; i < TCP_SLT_MAX; i++, slt++) {
+ if (atomic_read(&slt->count)) {
+ long trigger;
+
+ trigger = slt->period - ((long)(now - slt->last));
+
+ if (trigger <= 0) {
+ (*slt->handler)((unsigned long) slt);
+ slt->last = now;
+ trigger = slt->period;
+ }
+
+ /* Only reschedule if some events remain. */
+ if (atomic_read(&slt->count))
+ next = min(next, trigger);
+ }
+ }
+ if (next != ~0UL)
+ mod_timer(&tcp_slow_timer, (now + next));
+}
+
+void __tcp_inc_slow_timer(struct tcp_sl_timer *slt)
+{
+ unsigned long now = jiffies;
+ unsigned long when;
+
+ slt->last = now;
+
+ when = now + slt->period;
+
+ if (tcp_slow_timer.prev) {
+ if ((long)(tcp_slow_timer.expires - when) >= 0)
+ mod_timer(&tcp_slow_timer, when);
+ } else {
+ tcp_slow_timer.expires = when;
+ add_timer(&tcp_slow_timer);
+ }
+}
diff --git a/pfinet/linux-src/net/ipv4/timer.c b/pfinet/linux-src/net/ipv4/timer.c
new file mode 100644
index 00000000..3821a7c4
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/timer.c
@@ -0,0 +1,127 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * TIMER - implementation of software timers for IP.
+ *
+ * Version: $Id: timer.c,v 1.15 1999/02/22 13:54:29 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ * Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
+ * Florian La Roche, <flla@stud.uni-sb.de>
+ *
+ * Fixes:
+ * Alan Cox : To avoid destroying a wait queue as we use it
+ * we defer destruction until the destroy timer goes
+ * off.
+ * Alan Cox : Destroy socket doesn't write a status value to the
+ * socket buffer _AFTER_ freeing it! Also sock ensures
+ * the socket will get removed BEFORE this is called
+ * otherwise if the timer TIME_DESTROY occurs inside
+ * of inet_bh() with this socket being handled it goes
+ * BOOM! Have to stop timer going off if net_bh is
+ * active or the destroy causes crashes.
+ * Alan Cox : Cleaned up unused code.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <linux/interrupt.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/arp.h>
+
+void net_delete_timer (struct sock *t)
+{
+ if(t->timer.prev)
+ del_timer (&t->timer);
+ t->timeout = 0;
+}
+
+void net_reset_timer (struct sock *t, int timeout, unsigned long len)
+{
+ t->timeout = timeout;
+ mod_timer(&t->timer, jiffies+len);
+}
+
+/* Now we will only be called whenever we need to do
+ * something, but we must be sure to process all of the
+ * sockets that need it.
+ */
+void net_timer (unsigned long data)
+{
+ struct sock *sk = (struct sock*)data;
+ int why = sk->timeout;
+
+ /* Only process if socket is not in use. */
+ if (atomic_read(&sk->sock_readers)) {
+ /* Try again later. */
+ mod_timer(&sk->timer, jiffies+HZ/20);
+ return;
+ }
+
+ /* Always see if we need to send an ack. */
+ if (sk->tp_pinfo.af_tcp.delayed_acks && !sk->zapped) {
+ sk->prot->read_wakeup (sk);
+ if (!sk->dead)
+ sk->data_ready(sk,0);
+ }
+
+ /* Now we need to figure out why the socket was on the timer. */
+ switch (why) {
+ case TIME_DONE:
+ /* If the socket hasn't been closed off, re-try a bit later. */
+ if (!sk->dead) {
+ net_reset_timer(sk, TIME_DONE, TCP_DONE_TIME);
+ break;
+ }
+
+ if (sk->state != TCP_CLOSE) {
+ printk (KERN_DEBUG "non CLOSE socket in time_done\n");
+ break;
+ }
+ destroy_sock (sk);
+ break;
+
+ case TIME_DESTROY:
+ /* We've waited for a while for all the memory associated with
+ * the socket to be freed.
+ */
+ destroy_sock(sk);
+ break;
+
+ case TIME_CLOSE:
+ /* We've waited long enough, close the socket. */
+ tcp_set_state(sk, TCP_CLOSE);
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ sk->state_change(sk);
+ net_reset_timer (sk, TIME_DONE, TCP_DONE_TIME);
+ break;
+
+ default:
+ /* I want to see these... */
+ printk ("net_timer: timer expired - reason %d is unknown\n", why);
+ break;
+ }
+}
+
diff --git a/pfinet/linux-src/net/ipv4/udp.c b/pfinet/linux-src/net/ipv4/udp.c
new file mode 100644
index 00000000..1ceb43e4
--- /dev/null
+++ b/pfinet/linux-src/net/ipv4/udp.c
@@ -0,0 +1,1200 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * The User Datagram Protocol (UDP).
+ *
+ * Version: $Id: udp.c,v 1.66.2.3 1999/08/07 10:56:36 davem Exp $
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Alan Cox, <Alan.Cox@linux.org>
+ *
+ * Fixes:
+ * Alan Cox : verify_area() calls
+ * Alan Cox : stopped close while in use off icmp
+ * messages. Not a fix but a botch that
+ * for udp at least is 'valid'.
+ * Alan Cox : Fixed icmp handling properly
+ * Alan Cox : Correct error for oversized datagrams
+ * Alan Cox : Tidied select() semantics.
+ * Alan Cox : udp_err() fixed properly, also now
+ * select and read wake correctly on errors
+ * Alan Cox : udp_send verify_area moved to avoid mem leak
+ * Alan Cox : UDP can count its memory
+ * Alan Cox : send to an unknown connection causes
+ * an ECONNREFUSED off the icmp, but
+ * does NOT close.
+ * Alan Cox : Switched to new sk_buff handlers. No more backlog!
+ * Alan Cox : Using generic datagram code. Even smaller and the PEEK
+ * bug no longer crashes it.
+ * Fred Van Kempen : Net2e support for sk->broadcast.
+ * Alan Cox : Uses skb_free_datagram
+ * Alan Cox : Added get/set sockopt support.
+ * Alan Cox : Broadcasting without option set returns EACCES.
+ * Alan Cox : No wakeup calls. Instead we now use the callbacks.
+ * Alan Cox : Use ip_tos and ip_ttl
+ * Alan Cox : SNMP Mibs
+ * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support.
+ * Matt Dillon : UDP length checks.
+ * Alan Cox : Smarter af_inet used properly.
+ * Alan Cox : Use new kernel side addressing.
+ * Alan Cox : Incorrect return on truncated datagram receive.
+ * Arnt Gulbrandsen : New udp_send and stuff
+ * Alan Cox : Cache last socket
+ * Alan Cox : Route cache
+ * Jon Peatfield : Minor efficiency fix to sendto().
+ * Mike Shaver : RFC1122 checks.
+ * Alan Cox : Nonblocking error fix.
+ * Willy Konynenberg : Transparent proxying support.
+ * Mike McLagan : Routing by source
+ * David S. Miller : New socket lookup architecture.
+ * Last socket cache retained as it
+ * does have a high hit rate.
+ * Olaf Kirch : Don't linearise iovec on sendmsg.
+ * Andi Kleen : Some cleanups, cache destination entry
+ * for connect.
+ * Vitaly E. Lavrov : Transparent proxy revived after year coma.
+ * Melvin Smith : Check msg_name not msg_namelen in sendto(),
+ * return ENOTCONN for unconnected sockets (POSIX)
+ * Janos Farkas : don't deliver multi/broadcasts to a different
+ * bound-to-device socket
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* RFC1122 Status:
+ 4.1.3.1 (Ports):
+ SHOULD send ICMP_PORT_UNREACHABLE in response to datagrams to
+ an un-listened port. (OK)
+ 4.1.3.2 (IP Options)
+ MUST pass IP options from IP -> application (OK)
+ MUST allow application to specify IP options (OK)
+ 4.1.3.3 (ICMP Messages)
+ MUST pass ICMP error messages to application (OK -- except when SO_BSDCOMPAT is set)
+ 4.1.3.4 (UDP Checksums)
+ MUST provide facility for checksumming (OK)
+ MAY allow application to control checksumming (OK)
+ MUST default to checksumming on (OK)
+ MUST discard silently datagrams with bad csums (OK, except during debugging)
+ 4.1.3.5 (UDP Multihoming)
+ MUST allow application to specify source address (OK)
+ SHOULD be able to communicate the chosen src addr up to application
+ when application doesn't choose (DOES - use recvmsg cmsgs)
+ 4.1.3.6 (Invalid Addresses)
+ MUST discard invalid source addresses (OK -- done in the new routing code)
+ MUST only send datagrams with one of our addresses (OK)
+*/
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <net/snmp.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/udp.h>
+#include <net/icmp.h>
+#include <net/route.h>
+#include <net/checksum.h>
+
+/*
+ * Snmp MIB for the UDP layer
+ */
+
+struct udp_mib udp_statistics;
+
+struct sock *udp_hash[UDP_HTABLE_SIZE];
+
+/* Shared by v4/v6 udp. */
+int udp_port_rover = 0;
+
+static int udp_v4_get_port(struct sock *sk, unsigned short snum)
+{
+ SOCKHASH_LOCK();
+ if (snum == 0) {
+ int best_size_so_far, best, result, i;
+
+ if (udp_port_rover > sysctl_local_port_range[1] ||
+ udp_port_rover < sysctl_local_port_range[0])
+ udp_port_rover = sysctl_local_port_range[0];
+ best_size_so_far = 32767;
+ best = result = udp_port_rover;
+ for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+ struct sock *sk;
+ int size;
+
+ sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+ if (!sk) {
+ if (result > sysctl_local_port_range[1])
+ result = sysctl_local_port_range[0] +
+ ((result - sysctl_local_port_range[0]) &
+ (UDP_HTABLE_SIZE - 1));
+ goto gotit;
+ }
+ size = 0;
+ do {
+ if (++size >= best_size_so_far)
+ goto next;
+ } while ((sk = sk->next) != NULL);
+ best_size_so_far = size;
+ best = result;
+ next:
+ ; /* Do nothing. */
+ }
+ result = best;
+ for(;; result += UDP_HTABLE_SIZE) {
+ if (result > sysctl_local_port_range[1])
+ result = sysctl_local_port_range[0]
+ + ((result - sysctl_local_port_range[0]) &
+ (UDP_HTABLE_SIZE - 1));
+ if (!udp_lport_inuse(result))
+ break;
+ }
+gotit:
+ udp_port_rover = snum = result;
+ } else {
+ struct sock *sk2;
+
+ for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
+ sk2 != NULL;
+ sk2 = sk2->next) {
+ if (sk2->num == snum &&
+ sk2 != sk &&
+ sk2->bound_dev_if == sk->bound_dev_if &&
+ (!sk2->rcv_saddr ||
+ !sk->rcv_saddr ||
+ sk2->rcv_saddr == sk->rcv_saddr) &&
+ (!sk2->reuse || !sk->reuse))
+ goto fail;
+ }
+ }
+ sk->num = snum;
+ SOCKHASH_UNLOCK();
+ return 0;
+
+fail:
+ SOCKHASH_UNLOCK();
+ return 1;
+}
+
+/* Last hit UDP socket cache, this is ipv4 specific so make it static. */
+static u32 uh_cache_saddr, uh_cache_daddr;
+static u16 uh_cache_dport, uh_cache_sport;
+static struct sock *uh_cache_sk = NULL;
+
+static void udp_v4_hash(struct sock *sk)
+{
+ struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)];
+
+ SOCKHASH_LOCK();
+ if ((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+ SOCKHASH_UNLOCK();
+}
+
+static void udp_v4_unhash(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if (sk->pprev) {
+ if (sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ if(uh_cache_sk == sk)
+ uh_cache_sk = NULL;
+ }
+ SOCKHASH_UNLOCK();
+}
+
+/* UDP is nearly always wildcards out the wazoo, it makes no sense to try
+ * harder than this here plus the last hit cache. -DaveM
+ */
+struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
+{
+ struct sock *sk, *result = NULL;
+ unsigned short hnum = ntohs(dport);
+ int badness = -1;
+
+ for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
+ if((sk->num == hnum) && !(sk->dead && (sk->state == TCP_CLOSE))) {
+ int score = 0;
+ if(sk->rcv_saddr) {
+ if(sk->rcv_saddr != daddr)
+ continue;
+ score++;
+ }
+ if(sk->daddr) {
+ if(sk->daddr != saddr)
+ continue;
+ score++;
+ }
+ if(sk->dport) {
+ if(sk->dport != sport)
+ continue;
+ score++;
+ }
+ if(sk->bound_dev_if) {
+ if(sk->bound_dev_if != dif)
+ continue;
+ score++;
+ }
+ if(score == 4) {
+ result = sk;
+ break;
+ } else if(score > badness) {
+ result = sk;
+ badness = score;
+ }
+ }
+ }
+ return result;
+}
+
+__inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
+{
+ struct sock *sk;
+
+ if(!dif && uh_cache_sk &&
+ uh_cache_saddr == saddr &&
+ uh_cache_sport == sport &&
+ uh_cache_dport == dport &&
+ uh_cache_daddr == daddr)
+ return uh_cache_sk;
+
+ sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif);
+ if(!dif) {
+ uh_cache_sk = sk;
+ uh_cache_saddr = saddr;
+ uh_cache_daddr = daddr;
+ uh_cache_sport = sport;
+ uh_cache_dport = dport;
+ }
+ return sk;
+}
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+#define secondlist(hpnum, sk, fpass) \
+({ struct sock *s1; if(!(sk) && (fpass)--) \
+ s1 = udp_hash[(hpnum) & (UDP_HTABLE_SIZE - 1)]; \
+ else \
+ s1 = (sk); \
+ s1; \
+})
+
+#define udp_v4_proxy_loop_init(hnum, hpnum, sk, fpass) \
+ secondlist((hpnum), udp_hash[(hnum)&(UDP_HTABLE_SIZE-1)],(fpass))
+
+#define udp_v4_proxy_loop_next(hnum, hpnum, sk, fpass) \
+ secondlist((hpnum),(sk)->next,(fpass))
+
+static struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
+ unsigned short rnum, unsigned long laddr,
+ struct device *dev, unsigned short pnum,
+ int dif)
+{
+ struct sock *s, *result = NULL;
+ int badness = -1;
+ u32 paddr = 0;
+ unsigned short hnum = ntohs(num);
+ unsigned short hpnum = ntohs(pnum);
+ int firstpass = 1;
+
+ if(dev && dev->ip_ptr) {
+ struct in_device *idev = dev->ip_ptr;
+
+ if(idev->ifa_list)
+ paddr = idev->ifa_list->ifa_local;
+ }
+
+ SOCKHASH_LOCK();
+ for(s = udp_v4_proxy_loop_init(hnum, hpnum, s, firstpass);
+ s != NULL;
+ s = udp_v4_proxy_loop_next(hnum, hpnum, s, firstpass)) {
+ if(s->num == hnum || s->num == hpnum) {
+ int score = 0;
+ if(s->dead && (s->state == TCP_CLOSE))
+ continue;
+ if(s->rcv_saddr) {
+ if((s->num != hpnum || s->rcv_saddr != paddr) &&
+ (s->num != hnum || s->rcv_saddr != laddr))
+ continue;
+ score++;
+ }
+ if(s->daddr) {
+ if(s->daddr != raddr)
+ continue;
+ score++;
+ }
+ if(s->dport) {
+ if(s->dport != rnum)
+ continue;
+ score++;
+ }
+ if(s->bound_dev_if) {
+ if(s->bound_dev_if != dif)
+ continue;
+ score++;
+ }
+ if(score == 4 && s->num == hnum) {
+ result = s;
+ break;
+ } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
+ result = s;
+ badness = score;
+ }
+ }
+ }
+ SOCKHASH_UNLOCK();
+ return result;
+}
+
+#undef secondlist
+#undef udp_v4_proxy_loop_init
+#undef udp_v4_proxy_loop_next
+
+#endif
+
+static inline struct sock *udp_v4_mcast_next(struct sock *sk,
+ unsigned short num,
+ unsigned long raddr,
+ unsigned short rnum,
+ unsigned long laddr,
+ int dif)
+{
+ struct sock *s = sk;
+ unsigned short hnum = ntohs(num);
+ for(; s; s = s->next) {
+ if ((s->num != hnum) ||
+ (s->dead && (s->state == TCP_CLOSE)) ||
+ (s->daddr && s->daddr!=raddr) ||
+ (s->dport != rnum && s->dport != 0) ||
+ (s->rcv_saddr && s->rcv_saddr != laddr) ||
+ (s->bound_dev_if && s->bound_dev_if != dif))
+ continue;
+ break;
+ }
+ return s;
+}
+
+/*
+ * This routine is called by the ICMP module when it gets some
+ * sort of error condition. If err < 0 then the socket should
+ * be closed and the error returned to the user. If err > 0
+ * it's just the icmp type << 8 | icmp code.
+ * Header points to the ip header of the error packet. We move
+ * on past this. Then (as it used to claim before adjustment)
+ * header points to the first 8 bytes of the udp header. We need
+ * to find the appropriate port.
+ */
+
+void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
+{
+ struct iphdr *iph = (struct iphdr*)dp;
+ struct udphdr *uh = (struct udphdr*)(dp+(iph->ihl<<2));
+ int type = skb->h.icmph->type;
+ int code = skb->h.icmph->code;
+ struct sock *sk;
+ int harderr;
+ u32 info;
+ int err;
+
+ if (len < (iph->ihl<<2)+sizeof(struct udphdr)) {
+ icmp_statistics.IcmpInErrors++;
+ return;
+ }
+
+ sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex);
+ if (sk == NULL) {
+ icmp_statistics.IcmpInErrors++;
+ return; /* No socket for error */
+ }
+
+ err = 0;
+ info = 0;
+ harderr = 0;
+
+ switch (type) {
+ default:
+ case ICMP_TIME_EXCEEDED:
+ err = EHOSTUNREACH;
+ break;
+ case ICMP_SOURCE_QUENCH:
+ return;
+ case ICMP_PARAMETERPROB:
+ err = EPROTO;
+ info = ntohl(skb->h.icmph->un.gateway)>>24;
+ harderr = 1;
+ break;
+ case ICMP_DEST_UNREACH:
+ if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+ if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
+ err = EMSGSIZE;
+ info = ntohs(skb->h.icmph->un.frag.mtu);
+ harderr = 1;
+ break;
+ }
+ return;
+ }
+ err = EHOSTUNREACH;
+ if (code <= NR_ICMP_UNREACH) {
+ harderr = icmp_err_convert[code].fatal;
+ err = icmp_err_convert[code].errno;
+ }
+ break;
+ }
+
+ /*
+ * Various people wanted BSD UDP semantics. Well they've come
+ * back out because they slow down response to stuff like dead
+ * or unreachable name servers and they screw term users something
+ * chronic. Oh and it violates RFC1122. So basically fix your
+ * client code people.
+ */
+
+ /*
+ * RFC1122: OK. Passes ICMP errors back to application, as per
+ * 4.1.3.3. After the comment above, that should be no surprise.
+ */
+
+ if (!harderr && !sk->ip_recverr)
+ return;
+
+ /*
+ * 4.x BSD compatibility item. Break RFC1122 to
+ * get BSD socket semantics.
+ */
+ if(sk->bsdism && sk->state!=TCP_ESTABLISHED)
+ return;
+
+ if (sk->ip_recverr)
+ ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1));
+ sk->err = err;
+ sk->error_report(sk);
+}
+
+
+static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
+{
+ return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
+}
+
+struct udpfakehdr
+{
+ struct udphdr uh;
+ u32 saddr;
+ u32 daddr;
+ struct iovec *iov;
+ u32 wcheck;
+};
+
+/*
+ * Copy and checksum a UDP packet from user space into a buffer. We still have
+ * to do the planning to get ip_build_xmit to spot direct transfer to network
+ * card and provide an additional callback mode for direct user->board I/O
+ * transfers. That one will be fun.
+ */
+
+static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen)
+{
+ struct udpfakehdr *ufh = (struct udpfakehdr *)p;
+ if (offset==0) {
+ if (csum_partial_copy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset,
+ fraglen-sizeof(struct udphdr), &ufh->wcheck))
+ return -EFAULT;
+ ufh->wcheck = csum_partial((char *)ufh, sizeof(struct udphdr),
+ ufh->wcheck);
+ ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr,
+ ntohs(ufh->uh.len),
+ IPPROTO_UDP, ufh->wcheck);
+ if (ufh->uh.check == 0)
+ ufh->uh.check = -1;
+ memcpy(to, ufh, sizeof(struct udphdr));
+ return 0;
+ }
+ if (csum_partial_copy_fromiovecend(to, ufh->iov, offset-sizeof(struct udphdr),
+ fraglen, &ufh->wcheck))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * Unchecksummed UDP is sufficiently critical to stuff like ATM video conferencing
+ * that we use two routines for this for speed. Probably we ought to have a
+ * CONFIG_FAST_NET set for >10Mb/second boards to activate this sort of coding.
+ * Timing needed to verify if this is a valid decision.
+ */
+
+static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen)
+{
+ struct udpfakehdr *ufh = (struct udpfakehdr *)p;
+
+ if (offset==0) {
+ memcpy(to, ufh, sizeof(struct udphdr));
+ return memcpy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset,
+ fraglen-sizeof(struct udphdr));
+ }
+ return memcpy_fromiovecend(to, ufh->iov, offset-sizeof(struct udphdr),
+ fraglen);
+}
+
+int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+{
+ int ulen = len + sizeof(struct udphdr);
+ struct ipcm_cookie ipc;
+ struct udpfakehdr ufh;
+ struct rtable *rt = NULL;
+ int free = 0;
+ int connected = 0;
+ u32 daddr;
+ u8 tos;
+ int err;
+
+ /* This check is ONLY to check for arithmetic overflow
+ on integer(!) len. Not more! Real check will be made
+ in ip_build_xmit --ANK
+
+ BTW socket.c -> af_*.c -> ... make multiple
+ invalid conversions size_t -> int. We MUST repair it f.e.
+ by replacing all of them with size_t and revise all
+ the places sort of len += sizeof(struct iphdr)
+ If len was ULONG_MAX-10 it would be cathastrophe --ANK
+ */
+
+ if (len < 0 || len > 0xFFFF)
+ return -EMSGSIZE;
+
+ /*
+ * Check the flags.
+ */
+
+ if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */
+ return -EOPNOTSUPP;
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_PROXY|MSG_NOSIGNAL))
+ return -EINVAL;
+ if ((msg->msg_flags&MSG_PROXY) && !capable(CAP_NET_ADMIN))
+ return -EPERM;
+#else
+ if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_NOSIGNAL))
+ return -EINVAL;
+#endif
+
+ /*
+ * Get and verify the address.
+ */
+
+ if (msg->msg_name) {
+ struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
+ if (msg->msg_namelen < sizeof(*usin))
+ return(-EINVAL);
+ if (usin->sin_family != AF_INET) {
+ static int complained;
+ if (!complained++)
+ printk(KERN_WARNING "%s forgot to set AF_INET in udp sendmsg. Fix it!\n", current->comm);
+ if (usin->sin_family)
+ return -EINVAL;
+ }
+ ufh.daddr = usin->sin_addr.s_addr;
+ ufh.uh.dest = usin->sin_port;
+ if (ufh.uh.dest == 0)
+ return -EINVAL;
+ } else {
+ if (sk->state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+ ufh.daddr = sk->daddr;
+ ufh.uh.dest = sk->dport;
+ /* Open fast path for connected socket.
+ Route will not be used, if at least one option is set.
+ */
+ connected = 1;
+ }
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (msg->msg_flags&MSG_PROXY) {
+ /*
+ * We map the first 8 bytes of a second sockaddr_in
+ * into the last 8 (unused) bytes of a sockaddr_in.
+ */
+ struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name;
+ from = (struct sockaddr_in *)&from->sin_zero;
+ if (from->sin_family != AF_INET)
+ return -EINVAL;
+ ipc.addr = from->sin_addr.s_addr;
+ ufh.uh.source = from->sin_port;
+ if (ipc.addr == 0)
+ ipc.addr = sk->saddr;
+ connected = 0;
+ } else
+#endif
+ {
+ ipc.addr = sk->saddr;
+ ufh.uh.source = sk->sport;
+ }
+
+ ipc.opt = NULL;
+ ipc.oif = sk->bound_dev_if;
+ if (msg->msg_controllen) {
+ err = ip_cmsg_send(msg, &ipc);
+ if (err)
+ return err;
+ if (ipc.opt)
+ free = 1;
+ connected = 0;
+ }
+ if (!ipc.opt)
+ ipc.opt = sk->opt;
+
+ ufh.saddr = ipc.addr;
+ ipc.addr = daddr = ufh.daddr;
+
+ if (ipc.opt && ipc.opt->srr) {
+ if (!daddr)
+ return -EINVAL;
+ daddr = ipc.opt->faddr;
+ connected = 0;
+ }
+ tos = RT_TOS(sk->ip_tos);
+ if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) ||
+ (ipc.opt && ipc.opt->is_strictroute)) {
+ tos |= RTO_ONLINK;
+ connected = 0;
+ }
+
+ if (MULTICAST(daddr)) {
+ if (!ipc.oif)
+ ipc.oif = sk->ip_mc_index;
+ if (!ufh.saddr)
+ ufh.saddr = sk->ip_mc_addr;
+ connected = 0;
+ }
+
+ if (connected && sk->dst_cache) {
+ rt = (struct rtable*)sk->dst_cache;
+ if (rt->u.dst.obsolete) {
+ sk->dst_cache = NULL;
+ dst_release(&rt->u.dst);
+ rt = NULL;
+ } else
+ dst_clone(&rt->u.dst);
+ }
+
+ if (rt == NULL) {
+ err = ip_route_output(&rt, daddr, ufh.saddr,
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ (msg->msg_flags&MSG_PROXY ? RTO_TPROXY : 0) |
+#endif
+ tos, ipc.oif);
+ if (err)
+ goto out;
+
+ err = -EACCES;
+ if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast)
+ goto out;
+ if (connected && sk->dst_cache == NULL)
+ sk->dst_cache = dst_clone(&rt->u.dst);
+ }
+
+ ufh.saddr = rt->rt_src;
+ if (!ipc.addr)
+ ufh.daddr = ipc.addr = rt->rt_dst;
+ ufh.uh.len = htons(ulen);
+ ufh.uh.check = 0;
+ ufh.iov = msg->msg_iov;
+ ufh.wcheck = 0;
+
+ /* RFC1122: OK. Provides the checksumming facility (MUST) as per */
+ /* 4.1.3.4. It's configurable by the application via setsockopt() */
+ /* (MAY) and it defaults to on (MUST). */
+
+ err = ip_build_xmit(sk,sk->no_check ? udp_getfrag_nosum : udp_getfrag,
+ &ufh, ulen, &ipc, rt, msg->msg_flags);
+
+out:
+ ip_rt_put(rt);
+ if (free)
+ kfree(ipc.opt);
+ if (!err) {
+ udp_statistics.UdpOutDatagrams++;
+ return len;
+ }
+ return err;
+}
+
+#ifdef _HURD_
+
+#define udp_ioctl 0
+
+#else
+
+/*
+ * IOCTL requests applicable to the UDP protocol
+ */
+
+int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+ switch(cmd)
+ {
+ case TIOCOUTQ:
+ {
+ unsigned long amount;
+
+ amount = sock_wspace(sk);
+ return put_user(amount, (int *)arg);
+ }
+
+ case TIOCINQ:
+ {
+ struct sk_buff *skb;
+ unsigned long amount;
+
+ amount = 0;
+ /* N.B. Is this interrupt safe??
+ -> Yes. Interrupts do not remove skbs. --ANK (980725)
+ */
+ skb = skb_peek(&sk->receive_queue);
+ if (skb != NULL) {
+ /*
+ * We will only return the amount
+ * of this packet since that is all
+ * that will be read.
+ */
+ amount = skb->len - sizeof(struct udphdr);
+ }
+ return put_user(amount, (int *)arg);
+ }
+
+ default:
+ return(-ENOIOCTLCMD);
+ }
+ return(0);
+}
+
+#endif
+
+#ifndef HAVE_CSUM_COPY_USER
+#undef CONFIG_UDP_DELAY_CSUM
+#endif
+
+/*
+ * This should be easy, if there is something there we
+ * return it, otherwise we block.
+ */
+
+int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
+ int noblock, int flags, int *addr_len)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
+ struct sk_buff *skb;
+ int copied, err;
+
+ if (flags & MSG_ERRQUEUE)
+ return ip_recv_error(sk, msg, len);
+
+ /*
+ * From here the generic datagram does a lot of the work. Come
+ * the finished NET3, it will do _ALL_ the work!
+ */
+
+ skb = skb_recv_datagram(sk, flags, noblock, &err);
+ if (!skb)
+ goto out;
+
+ copied = skb->len - sizeof(struct udphdr);
+ if (copied > len) {
+ copied = len;
+ msg->msg_flags |= MSG_TRUNC;
+ }
+
+#ifndef CONFIG_UDP_DELAY_CSUM
+ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
+ copied);
+#else
+ if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
+ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
+ copied);
+ } else if (copied > msg->msg_iov[0].iov_len || (msg->msg_flags&MSG_TRUNC)) {
+ if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)))
+ goto csum_copy_err;
+ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
+ copied);
+ } else {
+ unsigned int csum;
+
+ err = 0;
+ csum = csum_partial(skb->h.raw, sizeof(struct udphdr), skb->csum);
+ csum = csum_and_copy_to_user((char*)&skb->h.uh[1], msg->msg_iov[0].iov_base,
+ copied, csum, &err);
+ if (err)
+ goto out_free;
+ if ((unsigned short)csum_fold(csum))
+ goto csum_copy_err;
+ }
+#endif
+ if (err)
+ goto out_free;
+ sk->stamp=skb->stamp;
+
+ /* Copy the address. */
+ if (sin)
+ {
+ /*
+ * Check any passed addresses
+ */
+ if (addr_len)
+ *addr_len=sizeof(*sin);
+
+ sin->sin_family = AF_INET;
+ sin->sin_port = skb->h.uh->source;
+ sin->sin_addr.s_addr = skb->nh.iph->saddr;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (flags&MSG_PROXY)
+ {
+ /*
+ * We map the first 8 bytes of a second sockaddr_in
+ * into the last 8 (unused) bytes of a sockaddr_in.
+ * This _is_ ugly, but it's the only way to do it
+ * easily, without adding system calls.
+ */
+ struct sockaddr_in *sinto =
+ (struct sockaddr_in *) sin->sin_zero;
+
+ sinto->sin_family = AF_INET;
+ sinto->sin_port = skb->h.uh->dest;
+ sinto->sin_addr.s_addr = skb->nh.iph->daddr;
+ }
+#endif
+ }
+ if (sk->ip_cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+ err = copied;
+
+out_free:
+ skb_free_datagram(sk, skb);
+out:
+ return err;
+
+#ifdef CONFIG_UDP_DELAY_CSUM
+csum_copy_err:
+ udp_statistics.UdpInErrors++;
+ skb_free_datagram(sk, skb);
+
+ /*
+ * Error for blocking case is chosen to masquerade
+ * as some normal condition.
+ */
+ return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+#endif
+}
+
+int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+ struct rtable *rt;
+ int err;
+
+
+ if (addr_len < sizeof(*usin))
+ return(-EINVAL);
+
+ /*
+ * 1003.1g - break association.
+ */
+
+ if (usin->sin_family==AF_UNSPEC)
+ {
+ sk->saddr=INADDR_ANY;
+ sk->rcv_saddr=INADDR_ANY;
+ sk->daddr=INADDR_ANY;
+ sk->state = TCP_CLOSE;
+ if(uh_cache_sk == sk)
+ uh_cache_sk = NULL;
+ return 0;
+ }
+
+ if (usin->sin_family && usin->sin_family != AF_INET)
+ return(-EAFNOSUPPORT);
+
+ dst_release(xchg(&sk->dst_cache, NULL));
+
+ err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
+ sk->ip_tos|sk->localroute, sk->bound_dev_if);
+ if (err)
+ return err;
+ if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {
+ ip_rt_put(rt);
+ return -EACCES;
+ }
+ if(!sk->saddr)
+ sk->saddr = rt->rt_src; /* Update source address */
+ if(!sk->rcv_saddr)
+ sk->rcv_saddr = rt->rt_src;
+ sk->daddr = rt->rt_dst;
+ sk->dport = usin->sin_port;
+ sk->state = TCP_ESTABLISHED;
+
+ if(uh_cache_sk == sk)
+ uh_cache_sk = NULL;
+
+ sk->dst_cache = &rt->u.dst;
+ return(0);
+}
+
+
+static void udp_close(struct sock *sk, long timeout)
+{
+ /* See for explanation: raw_close in ipv4/raw.c */
+ sk->state = TCP_CLOSE;
+ udp_v4_unhash(sk);
+ sk->dead = 1;
+ destroy_sock(sk);
+}
+
+static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+{
+ /*
+ * Charge it to the socket, dropping if the queue is full.
+ */
+
+#if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM)
+ if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
+ if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
+ udp_statistics.UdpInErrors++;
+ ip_statistics.IpInDiscards++;
+ ip_statistics.IpInDelivers--;
+ kfree_skb(skb);
+ return -1;
+ }
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+#endif
+
+ if (sock_queue_rcv_skb(sk,skb)<0) {
+ udp_statistics.UdpInErrors++;
+ ip_statistics.IpInDiscards++;
+ ip_statistics.IpInDelivers--;
+ kfree_skb(skb);
+ return -1;
+ }
+ udp_statistics.UdpInDatagrams++;
+ return 0;
+}
+
+
+static inline void udp_deliver(struct sock *sk, struct sk_buff *skb)
+{
+ udp_queue_rcv_skb(sk, skb);
+}
+
+/*
+ * Multicasts and broadcasts go to each listener.
+ *
+ * Note: called only from the BH handler context,
+ * so we don't need to lock the hashes.
+ */
+static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
+ u32 saddr, u32 daddr)
+{
+ struct sock *sk;
+ int dif;
+
+ sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
+ dif = skb->dev->ifindex;
+ sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr, dif);
+ if (sk) {
+ struct sock *sknext = NULL;
+
+ do {
+ struct sk_buff *skb1 = skb;
+
+ sknext = udp_v4_mcast_next(sk->next, uh->dest, saddr,
+ uh->source, daddr, dif);
+ if(sknext)
+ skb1 = skb_clone(skb, GFP_ATOMIC);
+
+ if(skb1)
+ udp_deliver(sk, skb1);
+ sk = sknext;
+ } while(sknext);
+ } else
+ kfree_skb(skb);
+ return 0;
+}
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+/*
+ * Check whether a received UDP packet might be for one of our
+ * sockets.
+ */
+
+int udp_chkaddr(struct sk_buff *skb)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct udphdr *uh = (struct udphdr *)(skb->nh.raw + iph->ihl*4);
+ struct sock *sk;
+
+ sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev->ifindex);
+ if (!sk)
+ return 0;
+
+ /* 0 means accept all LOCAL addresses here, not all the world... */
+ if (sk->rcv_saddr == 0)
+ return 0;
+
+ return 1;
+}
+#endif
+
+/*
+ * All we need to do is get the socket, and then do a checksum.
+ */
+
+int udp_rcv(struct sk_buff *skb, unsigned short len)
+{
+ struct sock *sk;
+ struct udphdr *uh;
+ unsigned short ulen;
+ struct rtable *rt = (struct rtable*)skb->dst;
+ u32 saddr = skb->nh.iph->saddr;
+ u32 daddr = skb->nh.iph->daddr;
+
+ /*
+ * First time through the loop.. Do all the setup stuff
+ * (including finding out the socket we go to etc)
+ */
+
+ /*
+ * Get the header.
+ */
+
+ uh = skb->h.uh;
+ __skb_pull(skb, skb->h.raw - skb->data);
+
+ ip_statistics.IpInDelivers++;
+
+ /*
+ * Validate the packet and the UDP length.
+ */
+
+ ulen = ntohs(uh->len);
+
+ if (ulen > len || ulen < sizeof(*uh)) {
+ NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
+ udp_statistics.UdpInErrors++;
+ kfree_skb(skb);
+ return(0);
+ }
+ skb_trim(skb, ulen);
+
+#ifndef CONFIG_UDP_DELAY_CSUM
+ if (uh->check &&
+ (((skb->ip_summed==CHECKSUM_HW)&&udp_check(uh,ulen,saddr,daddr,skb->csum)) ||
+ ((skb->ip_summed==CHECKSUM_NONE) &&
+ (udp_check(uh,ulen,saddr,daddr, csum_partial((char*)uh, ulen, 0))))))
+ goto csum_error;
+#else
+ if (uh->check==0)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else if (skb->ip_summed==CHECKSUM_HW) {
+ if (udp_check(uh,ulen,saddr,daddr,skb->csum))
+ goto csum_error;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+ skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
+#endif
+
+ if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
+ return udp_v4_mcast_deliver(skb, uh, saddr, daddr);
+
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (IPCB(skb)->redirport)
+ sk = udp_v4_proxy_lookup(uh->dest, saddr, uh->source,
+ daddr, skb->dev, IPCB(skb)->redirport,
+ skb->dev->ifindex);
+ else
+#endif
+ sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);
+
+ if (sk == NULL) {
+#ifdef CONFIG_UDP_DELAY_CSUM
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
+ (unsigned short)csum_fold(csum_partial((char*)uh, ulen, skb->csum)))
+ goto csum_error;
+#endif
+ udp_statistics.UdpNoPorts++;
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+ /*
+ * Hmm. We got an UDP broadcast to a port to which we
+ * don't wanna listen. Ignore it.
+ */
+ kfree_skb(skb);
+ return(0);
+ }
+ udp_deliver(sk, skb);
+ return 0;
+
+csum_error:
+ /*
+ * RFC1122: OK. Discards the bad packet silently (as far as
+ * the network is concerned, anyway) as per 4.1.3.4 (MUST).
+ */
+ NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
+ NIPQUAD(saddr),
+ ntohs(uh->source),
+ NIPQUAD(daddr),
+ ntohs(uh->dest),
+ ulen));
+ udp_statistics.UdpInErrors++;
+ kfree_skb(skb);
+ return(0);
+}
+
+struct proto udp_prot = {
+ (struct sock *)&udp_prot, /* sklist_next */
+ (struct sock *)&udp_prot, /* sklist_prev */
+ udp_close, /* close */
+ udp_connect, /* connect */
+ NULL, /* accept */
+ NULL, /* retransmit */
+ NULL, /* write_wakeup */
+ NULL, /* read_wakeup */
+ datagram_poll, /* poll */
+ udp_ioctl, /* ioctl */
+ NULL, /* init */
+ NULL, /* destroy */
+ NULL, /* shutdown */
+ ip_setsockopt, /* setsockopt */
+ ip_getsockopt, /* getsockopt */
+ udp_sendmsg, /* sendmsg */
+ udp_recvmsg, /* recvmsg */
+ NULL, /* bind */
+ udp_queue_rcv_skb, /* backlog_rcv */
+ udp_v4_hash, /* hash */
+ udp_v4_unhash, /* unhash */
+ udp_v4_get_port, /* good_socknum */
+ 128, /* max_header */
+ 0, /* retransmits */
+ "UDP", /* name */
+ 0, /* inuse */
+ 0 /* highestinuse */
+};
diff --git a/pfinet/linux-inet/utils.c b/pfinet/linux-src/net/ipv4/utils.c
index 60bbb9f8..ce74ade2 100644
--- a/pfinet/linux-inet/utils.c
+++ b/pfinet/linux-src/net/ipv4/utils.c
@@ -6,14 +6,14 @@
* Various kernel-resident INET utility functions; mainly
* for format conversion and debugging output.
*
- * Version: @(#)utils.c 1.0.7 05/18/93
+ * Version: $Id: utils.c,v 1.6 1997/12/13 21:53:03 kuznet Exp $
*
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* Fixes:
* Alan Cox : verify_area check.
* Alan Cox : removed old debugging.
- *
+ * Andi Kleen : add net_ratelimit()
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -21,7 +21,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -36,9 +36,9 @@
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include "ip.h"
-#include "protocol.h"
-#include "tcp.h"
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
#include <linux/skbuff.h>
@@ -46,7 +46,7 @@
* Display an IP address in readable format.
*/
-char *in_ntoa(unsigned long in)
+char *in_ntoa(__u32 in)
{
static char buff[18];
char *p;
@@ -62,7 +62,7 @@ char *in_ntoa(unsigned long in)
* Convert an ASCII string to binary IP.
*/
-unsigned long in_aton(char *str)
+__u32 in_aton(const char *str)
{
unsigned long l;
unsigned int val;
diff --git a/pfinet/linux-src/net/ipv6/addrconf.c b/pfinet/linux-src/net/ipv6/addrconf.c
new file mode 100644
index 00000000..d392b3fd
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/addrconf.c
@@ -0,0 +1,1964 @@
+/*
+ * IPv6 Address [auto]configuration
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: addrconf.c,v 1.4 2009/02/24 01:21:14 sthibaul Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Changes:
+ *
+ * Janos Farkas : delete timer on ifdown
+ * <chexum@bankinf.banki.hu>
+ * Andi Kleen : kill doube kfree on module
+ * unload.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/inetdevice.h>
+#include <linux/init.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+#include <linux/delay.h>
+
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/uaccess.h>
+
+/* Set to 3 to get tracing... */
+#define ACONF_DEBUG 2
+
+#if ACONF_DEBUG >= 3
+#define ADBG(x) printk x
+#else
+#define ADBG(x)
+#endif
+
+#ifdef CONFIG_SYSCTL
+static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p);
+static void addrconf_sysctl_unregister(struct ipv6_devconf *p);
+#endif
+
+/*
+ * Configured unicast address list
+ */
+static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE];
+
+/*
+ * AF_INET6 device list
+ */
+static struct inet6_dev *inet6_dev_lst[IN6_ADDR_HSIZE];
+
+static atomic_t addr_list_lock = ATOMIC_INIT(0);
+
+void addrconf_verify(unsigned long);
+
+static struct timer_list addr_chk_timer = {
+ NULL, NULL,
+ 0, 0, addrconf_verify
+};
+
+/* These locks protect only against address deletions,
+ but not against address adds or status updates.
+ It is OK. The only race is when address is selected,
+ which becomes invalid immediately after selection.
+ It is harmless, because this address could be already invalid
+ several usecs ago.
+
+ Its important, that:
+
+ 1. The result of inet6_add_addr() is used only inside lock
+ or from bh_atomic context.
+
+ 2. inet6_get_lladdr() is used only from bh protected context.
+
+ 3. The result of ipv6_chk_addr() is not used outside of bh protected context.
+ */
+
+static __inline__ void addrconf_lock(void)
+{
+ atomic_inc(&addr_list_lock);
+ synchronize_bh();
+}
+
+static __inline__ void addrconf_unlock(void)
+{
+ atomic_dec(&addr_list_lock);
+}
+
+static int addrconf_ifdown(struct device *dev, int how);
+
+static void addrconf_dad_start(struct inet6_ifaddr *ifp);
+static void addrconf_dad_timer(unsigned long data);
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
+static void addrconf_rs_timer(unsigned long data);
+static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
+
+struct ipv6_devconf ipv6_devconf =
+{
+ 0, /* forwarding */
+ IPV6_DEFAULT_HOPLIMIT, /* hop limit */
+ IPV6_MIN_MTU, /* mtu */
+ 1, /* accept RAs */
+ 1, /* accept redirects */
+ 1, /* autoconfiguration */
+ 1, /* dad transmits */
+ MAX_RTR_SOLICITATIONS, /* router solicits */
+ RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
+ MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */
+};
+
+static struct ipv6_devconf ipv6_devconf_dflt =
+{
+ 0, /* forwarding */
+ IPV6_DEFAULT_HOPLIMIT, /* hop limit */
+ IPV6_MIN_MTU, /* mtu */
+ 1, /* accept RAs */
+ 1, /* accept redirects */
+ 1, /* autoconfiguration */
+ 1, /* dad transmits */
+ MAX_RTR_SOLICITATIONS, /* router solicits */
+ RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
+ MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */
+};
+
+int ipv6_addr_type(struct in6_addr *addr)
+{
+ u32 st;
+
+ st = addr->s6_addr32[0];
+
+ /* Consider all addresses with the first three bits different of
+ 000 and 111 as unicasts.
+ */
+ if ((st & __constant_htonl(0xE0000000)) != __constant_htonl(0x00000000) &&
+ (st & __constant_htonl(0xE0000000)) != __constant_htonl(0xE0000000))
+ return IPV6_ADDR_UNICAST;
+
+ if ((st & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000)) {
+ int type = IPV6_ADDR_MULTICAST;
+
+ switch((st & __constant_htonl(0x00FF0000))) {
+ case __constant_htonl(0x00010000):
+ type |= IPV6_ADDR_LOOPBACK;
+ break;
+
+ case __constant_htonl(0x00020000):
+ type |= IPV6_ADDR_LINKLOCAL;
+ break;
+
+ case __constant_htonl(0x00050000):
+ type |= IPV6_ADDR_SITELOCAL;
+ break;
+ };
+ return type;
+ }
+
+ if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFE800000))
+ return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST);
+
+ if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFEC00000))
+ return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST);
+
+ if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
+ if (addr->s6_addr32[2] == 0) {
+ if (addr->__in6_u.__u6_addr32[3] == 0)
+ return IPV6_ADDR_ANY;
+
+ if (addr->s6_addr32[3] == __constant_htonl(0x00000001))
+ return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST);
+
+ return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST);
+ }
+
+ if (addr->s6_addr32[2] == __constant_htonl(0x0000ffff))
+ return IPV6_ADDR_MAPPED;
+ }
+
+ return IPV6_ADDR_RESERVED;
+}
+
+static struct inet6_dev * ipv6_add_dev(struct device *dev)
+{
+ struct inet6_dev *ndev, **bptr, *iter;
+ int hash;
+
+ if (dev->mtu < IPV6_MIN_MTU)
+ return NULL;
+
+ ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL);
+
+ if (ndev) {
+ memset(ndev, 0, sizeof(struct inet6_dev));
+
+ ndev->dev = dev;
+ memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
+ ndev->cnf.mtu6 = dev->mtu;
+ ndev->cnf.sysctl = NULL;
+ ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
+ if (ndev->nd_parms == NULL) {
+ kfree(ndev);
+ return NULL;
+ }
+#ifdef CONFIG_SYSCTL
+ neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
+ addrconf_sysctl_register(ndev, &ndev->cnf);
+#endif
+ hash = ipv6_devindex_hash(dev->ifindex);
+ bptr = &inet6_dev_lst[hash];
+ iter = *bptr;
+
+ for (; iter; iter = iter->next)
+ bptr = &iter->next;
+
+ *bptr = ndev;
+
+ }
+ return ndev;
+}
+
+#ifndef _HURD_
+static
+#endif
+struct inet6_dev * ipv6_find_idev(struct device *dev)
+{
+ struct inet6_dev *idev;
+
+ if ((idev = ipv6_get_idev(dev)) == NULL) {
+ idev = ipv6_add_dev(dev);
+ if (idev == NULL)
+ return NULL;
+ if (dev->flags&IFF_UP)
+ ipv6_mc_up(idev);
+ }
+ return idev;
+}
+
+static void addrconf_forward_change(struct inet6_dev *idev)
+{
+ int i;
+
+ if (idev)
+ return;
+
+ for (i = 0; i < IN6_ADDR_HSIZE; i++) {
+ for (idev = inet6_dev_lst[i]; idev; idev = idev->next)
+ idev->cnf.forwarding = ipv6_devconf.forwarding;
+ }
+}
+
+struct inet6_dev * ipv6_get_idev(struct device *dev)
+{
+ struct inet6_dev *idev;
+ int hash;
+
+ hash = ipv6_devindex_hash(dev->ifindex);
+
+ for (idev = inet6_dev_lst[hash]; idev; idev = idev->next) {
+ if (idev->dev == dev)
+ return idev;
+ }
+ return NULL;
+}
+
+static struct inet6_ifaddr *
+ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int scope)
+{
+ struct inet6_ifaddr *ifa;
+ int hash;
+
+ ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
+
+ if (ifa == NULL) {
+ ADBG(("ipv6_add_addr: malloc failed\n"));
+ return NULL;
+ }
+
+ memset(ifa, 0, sizeof(struct inet6_ifaddr));
+ memcpy(&ifa->addr, addr, sizeof(struct in6_addr));
+
+ init_timer(&ifa->timer);
+ ifa->timer.data = (unsigned long) ifa;
+ ifa->scope = scope;
+ ifa->idev = idev;
+
+ /* Add to list. */
+ hash = ipv6_addr_hash(addr);
+
+ ifa->lst_next = inet6_addr_lst[hash];
+ inet6_addr_lst[hash] = ifa;
+
+ /* Add to inet6_dev unicast addr list. */
+ ifa->if_next = idev->addr_list;
+ idev->addr_list = ifa;
+
+ return ifa;
+}
+
+static void ipv6_del_addr(struct inet6_ifaddr *ifp)
+{
+ struct inet6_ifaddr *iter, **back;
+ int hash;
+
+ if (atomic_read(&addr_list_lock)) {
+ ifp->flags |= ADDR_INVALID;
+ ipv6_ifa_notify(RTM_DELADDR, ifp);
+ return;
+ }
+
+ hash = ipv6_addr_hash(&ifp->addr);
+
+ iter = inet6_addr_lst[hash];
+ back = &inet6_addr_lst[hash];
+
+ for (; iter; iter = iter->lst_next) {
+ if (iter == ifp) {
+ *back = ifp->lst_next;
+ synchronize_bh();
+
+ ifp->lst_next = NULL;
+ break;
+ }
+ back = &(iter->lst_next);
+ }
+
+ iter = ifp->idev->addr_list;
+ back = &ifp->idev->addr_list;
+
+ for (; iter; iter = iter->if_next) {
+ if (iter == ifp) {
+ *back = ifp->if_next;
+ synchronize_bh();
+
+ ifp->if_next = NULL;
+ break;
+ }
+ back = &(iter->if_next);
+ }
+
+ ipv6_ifa_notify(RTM_DELADDR, ifp);
+ del_timer(&ifp->timer);
+
+ kfree(ifp);
+}
+
+/*
+ * Choose an appropriate source address
+ * should do:
+ * i) get an address with an appropriate scope
+ * ii) see if there is a specific route for the destination and use
+ * an address of the attached interface
+ * iii) don't use deprecated addresses
+ */
+int ipv6_get_saddr(struct dst_entry *dst,
+ struct in6_addr *daddr, struct in6_addr *saddr)
+{
+ int scope;
+ struct inet6_ifaddr *ifp = NULL;
+ struct inet6_ifaddr *match = NULL;
+ struct device *dev = NULL;
+ struct rt6_info *rt;
+ int err;
+ int i;
+
+ rt = (struct rt6_info *) dst;
+ if (rt)
+ dev = rt->rt6i_dev;
+
+ addrconf_lock();
+
+ scope = ipv6_addr_scope(daddr);
+ if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
+ /*
+ * route for the "all destinations on link" rule
+ * when no routers are present
+ */
+ scope = IFA_LINK;
+ }
+
+ /*
+ * known dev
+ * search dev and walk through dev addresses
+ */
+
+ if (dev) {
+ struct inet6_dev *idev;
+ int hash;
+
+ if (dev->flags & IFF_LOOPBACK)
+ scope = IFA_HOST;
+
+ hash = ipv6_devindex_hash(dev->ifindex);
+ for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) {
+ if (idev->dev == dev) {
+ for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+ if (ifp->scope == scope) {
+ if (!(ifp->flags & (ADDR_STATUS|DAD_STATUS)))
+ goto out;
+
+ if (!(ifp->flags & (ADDR_INVALID|DAD_STATUS)))
+ match = ifp;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (scope == IFA_LINK)
+ goto out;
+
+ /*
+ * dev == NULL or search failed for specified dev
+ */
+
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
+ if (ifp->scope == scope) {
+ if (!(ifp->flags & (ADDR_STATUS|DAD_STATUS)))
+ goto out;
+
+ if (!(ifp->flags & (ADDR_INVALID|DAD_STATUS)))
+ match = ifp;
+ }
+ }
+ }
+
+out:
+ if (ifp == NULL)
+ ifp = match;
+
+ err = -ENETUNREACH;
+ if (ifp) {
+ memcpy(saddr, &ifp->addr, sizeof(struct in6_addr));
+ err = 0;
+ }
+ addrconf_unlock();
+ return err;
+}
+
+struct inet6_ifaddr * ipv6_get_lladdr(struct device *dev)
+{
+ struct inet6_ifaddr *ifp = NULL;
+ struct inet6_dev *idev;
+
+ if ((idev = ipv6_get_idev(dev)) != NULL) {
+ addrconf_lock();
+ for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+ if (ifp->scope == IFA_LINK)
+ break;
+ }
+ addrconf_unlock();
+ }
+ return ifp;
+}
+
+/*
+ * Retrieve the ifaddr struct from an v6 address
+ * Called from ipv6_rcv to check if the address belongs
+ * to the host.
+ */
+
+struct inet6_ifaddr * ipv6_chk_addr(struct in6_addr *addr, struct device *dev, int nd)
+{
+ struct inet6_ifaddr * ifp;
+ u8 hash;
+ unsigned flags = 0;
+
+ if (!nd)
+ flags |= DAD_STATUS|ADDR_INVALID;
+
+ addrconf_lock();
+
+ hash = ipv6_addr_hash(addr);
+ for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+ if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && !(ifp->flags&flags)) {
+ if (dev == NULL || ifp->idev->dev == dev ||
+ !(ifp->scope&(IFA_LINK|IFA_HOST)))
+ break;
+ }
+ }
+
+ addrconf_unlock();
+ return ifp;
+}
+
+void addrconf_dad_failure(struct inet6_ifaddr *ifp)
+{
+ printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
+ del_timer(&ifp->timer);
+ ipv6_del_addr(ifp);
+}
+
+
+/* Join to solicited addr multicast group. */
+
+static void addrconf_join_solict(struct device *dev, struct in6_addr *addr)
+{
+ struct in6_addr maddr;
+
+ if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))
+ return;
+
+#ifndef CONFIG_IPV6_NO_PB
+ addrconf_addr_solict_mult_old(addr, &maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+#endif
+#ifdef CONFIG_IPV6_EUI64
+ addrconf_addr_solict_mult_new(addr, &maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+#endif
+}
+
+static void addrconf_leave_solict(struct device *dev, struct in6_addr *addr)
+{
+ struct in6_addr maddr;
+
+ if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))
+ return;
+
+#ifndef CONFIG_IPV6_NO_PB
+ addrconf_addr_solict_mult_old(addr, &maddr);
+ ipv6_dev_mc_dec(dev, &maddr);
+#endif
+#ifdef CONFIG_IPV6_EUI64
+ addrconf_addr_solict_mult_new(addr, &maddr);
+ ipv6_dev_mc_dec(dev, &maddr);
+#endif
+}
+
+
+#ifdef CONFIG_IPV6_EUI64
+static int ipv6_generate_eui64(u8 *eui, struct device *dev)
+{
+ switch (dev->type) {
+ case ARPHRD_ETHER:
+ if (dev->addr_len != ETH_ALEN)
+ return -1;
+ memcpy(eui, dev->dev_addr, 3);
+ memcpy(eui + 5, dev->dev_addr+3, 3);
+ eui[3] = 0xFF;
+ eui[4] = 0xFE;
+ eui[0] ^= 2;
+ return 0;
+ }
+ return -1;
+}
+
+static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
+{
+ int err = -1;
+ struct inet6_ifaddr *ifp;
+
+ for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+ if (ifp->scope == IFA_LINK && !(ifp->flags&(ADDR_STATUS|DAD_STATUS))) {
+ memcpy(eui, ifp->addr.s6_addr+8, 8);
+ err = 0;
+ break;
+ }
+ }
+ return err;
+}
+#endif
+
+/*
+ * Add prefix route.
+ */
+
+static void
+addrconf_prefix_route(struct in6_addr *pfx, int plen, struct device *dev,
+ unsigned long expires, unsigned flags)
+{
+ struct in6_rtmsg rtmsg;
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+ memcpy(&rtmsg.rtmsg_dst, pfx, sizeof(struct in6_addr));
+ rtmsg.rtmsg_dst_len = plen;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+ rtmsg.rtmsg_info = expires;
+ rtmsg.rtmsg_flags = RTF_UP|flags;
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+
+ /* Prevent useless cloning on PtP SIT.
+ This thing is done here expecting that the whole
+ class of non-broadcast devices need not cloning.
+ */
+ if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
+ rtmsg.rtmsg_flags |= RTF_NONEXTHOP;
+
+ ip6_route_add(&rtmsg);
+}
+
+/* Create "default" multicast route to the interface */
+
+static void addrconf_add_mroute(struct device *dev)
+{
+ struct in6_rtmsg rtmsg;
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+ ipv6_addr_set(&rtmsg.rtmsg_dst,
+ __constant_htonl(0xFF000000), 0, 0, 0);
+ rtmsg.rtmsg_dst_len = 8;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+ rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF;
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+ ip6_route_add(&rtmsg);
+}
+
+static void sit_route_add(struct device *dev)
+{
+ struct in6_rtmsg rtmsg;
+
+ memset(&rtmsg, 0, sizeof(rtmsg));
+
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+
+ /* prefix length - 96 bytes "::d.d.d.d" */
+ rtmsg.rtmsg_dst_len = 96;
+ rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP;
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+
+ ip6_route_add(&rtmsg);
+}
+
+static void addrconf_add_lroute(struct device *dev)
+{
+ struct in6_addr addr;
+
+ ipv6_addr_set(&addr, __constant_htonl(0xFE800000), 0, 0, 0);
+ addrconf_prefix_route(&addr, 10, dev, 0, RTF_ADDRCONF);
+}
+
+static struct inet6_dev *addrconf_add_dev(struct device *dev)
+{
+ struct inet6_dev *idev;
+
+ if ((idev = ipv6_find_idev(dev)) == NULL)
+ return NULL;
+
+ /* Add default multicast route */
+ addrconf_add_mroute(dev);
+
+ /* Add link local route */
+ addrconf_add_lroute(dev);
+ return idev;
+}
+
+void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
+{
+ struct prefix_info *pinfo;
+ struct rt6_info *rt;
+ __u32 valid_lft;
+ __u32 prefered_lft;
+ int addr_type;
+ unsigned long rt_expires;
+ struct inet6_dev *in6_dev = ipv6_get_idev(dev);
+
+ if (in6_dev == NULL) {
+ printk(KERN_DEBUG "addrconf: device %s not configured\n", dev->name);
+ return;
+ }
+
+ pinfo = (struct prefix_info *) opt;
+
+ if (len < sizeof(struct prefix_info)) {
+ ADBG(("addrconf: prefix option too short\n"));
+ return;
+ }
+
+ /*
+ * Validation checks ([ADDRCONF], page 19)
+ */
+
+ addr_type = ipv6_addr_type(&pinfo->prefix);
+
+ if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL))
+ return;
+
+ valid_lft = ntohl(pinfo->valid);
+ prefered_lft = ntohl(pinfo->prefered);
+
+ if (prefered_lft > valid_lft) {
+ printk(KERN_WARNING "addrconf: prefix option has invalid lifetime\n");
+ return;
+ }
+
+ /*
+ * Two things going on here:
+ * 1) Add routes for on-link prefixes
+ * 2) Configure prefixes with the auto flag set
+ */
+
+ /* Avoid arithemtic overflow. Really, we could
+ save rt_expires in seconds, likely valid_lft,
+ but it would require division in fib gc, that it
+ not good.
+ */
+ if (valid_lft >= 0x7FFFFFFF/HZ)
+ rt_expires = 0;
+ else
+ rt_expires = jiffies + valid_lft * HZ;
+
+ rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1);
+
+ if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (rt->rt6i_flags&RTF_EXPIRES) {
+ if (pinfo->onlink == 0 || valid_lft == 0) {
+ ip6_del_rt(rt);
+ } else {
+ rt->rt6i_expires = rt_expires;
+ }
+ }
+ } else if (pinfo->onlink && valid_lft) {
+ addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
+ dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES);
+ }
+ if (rt)
+ dst_release(&rt->u.dst);
+
+ /* Try to figure out our local address for this prefix */
+
+ if (pinfo->autoconf && in6_dev->cnf.autoconf) {
+ struct inet6_ifaddr * ifp;
+ struct in6_addr addr;
+ int plen;
+
+ plen = pinfo->prefix_len >> 3;
+
+#ifdef CONFIG_IPV6_EUI64
+ if (pinfo->prefix_len == 64) {
+ memcpy(&addr, &pinfo->prefix, 8);
+ if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&
+ ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev))
+ return;
+ goto ok;
+ }
+#endif
+#ifndef CONFIG_IPV6_NO_PB
+ if (pinfo->prefix_len == ((sizeof(struct in6_addr) - dev->addr_len)<<3)) {
+ memcpy(&addr, &pinfo->prefix, plen);
+ memcpy(addr.s6_addr + plen, dev->dev_addr,
+ dev->addr_len);
+ goto ok;
+ }
+#endif
+ printk(KERN_DEBUG "IPv6 addrconf: prefix with wrong length %d\n", pinfo->prefix_len);
+ return;
+
+ok:
+ ifp = ipv6_chk_addr(&addr, dev, 1);
+
+ if ((ifp == NULL || (ifp->flags&ADDR_INVALID)) && valid_lft) {
+
+ if (ifp == NULL)
+ ifp = ipv6_add_addr(in6_dev, &addr, addr_type & IPV6_ADDR_SCOPE_MASK);
+
+ if (ifp == NULL)
+ return;
+
+ ifp->prefix_len = pinfo->prefix_len;
+
+ addrconf_dad_start(ifp);
+ }
+
+ if (ifp && valid_lft == 0) {
+ ipv6_del_addr(ifp);
+ ifp = NULL;
+ }
+
+ if (ifp) {
+ int event = 0;
+ ifp->valid_lft = valid_lft;
+ ifp->prefered_lft = prefered_lft;
+ ifp->tstamp = jiffies;
+ if (ifp->flags & ADDR_INVALID)
+ event = RTM_NEWADDR;
+ ifp->flags &= ~(ADDR_DEPRECATED|ADDR_INVALID);
+ ipv6_ifa_notify(event, ifp);
+ }
+ }
+}
+
+#ifndef _HURD_
+/*
+ * Set destination address.
+ * Special case for SIT interfaces where we create a new "virtual"
+ * device.
+ */
+int addrconf_set_dstaddr(void *arg)
+{
+ struct in6_ifreq ireq;
+ struct device *dev;
+ int err = -EINVAL;
+
+ rtnl_lock();
+
+ err = -EFAULT;
+ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
+ goto err_exit;
+
+ dev = dev_get_by_index(ireq.ifr6_ifindex);
+
+ err = -ENODEV;
+ if (dev == NULL)
+ goto err_exit;
+
+ if (dev->type == ARPHRD_SIT) {
+ struct ifreq ifr;
+ mm_segment_t oldfs;
+ struct ip_tunnel_parm p;
+
+ err = -EADDRNOTAVAIL;
+ if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))
+ goto err_exit;
+
+ memset(&p, 0, sizeof(p));
+ p.iph.daddr = ireq.ifr6_addr.s6_addr32[3];
+ p.iph.saddr = 0;
+ p.iph.version = 4;
+ p.iph.ihl = 5;
+ p.iph.protocol = IPPROTO_IPV6;
+ p.iph.ttl = 64;
+ ifr.ifr_ifru.ifru_data = (void*)&p;
+
+ oldfs = get_fs(); set_fs(KERNEL_DS);
+ err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
+ set_fs(oldfs);
+
+ if (err == 0) {
+ err = -ENOBUFS;
+ if ((dev = dev_get(p.name)) == NULL)
+ goto err_exit;
+ err = dev_open(dev);
+ }
+ }
+
+err_exit:
+ rtnl_unlock();
+ return err;
+}
+#endif /* not _HURD_ */
+
+/*
+ * Manual configuration of address on an interface
+ */
+#ifndef _HURD_
+static
+#endif
+int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
+{
+ struct inet6_ifaddr *ifp;
+ struct inet6_dev *idev;
+ struct device *dev;
+ int scope;
+
+ if ((dev = dev_get_by_index(ifindex)) == NULL)
+ return -ENODEV;
+
+ if (!(dev->flags&IFF_UP))
+ return -ENETDOWN;
+
+ if ((idev = addrconf_add_dev(dev)) == NULL)
+ return -ENOBUFS;
+
+ scope = ipv6_addr_scope(pfx);
+
+ addrconf_lock();
+ if ((ifp = ipv6_add_addr(idev, pfx, scope)) != NULL) {
+ ifp->prefix_len = plen;
+ ifp->flags |= ADDR_PERMANENT;
+ addrconf_dad_start(ifp);
+ addrconf_unlock();
+ return 0;
+ }
+ addrconf_unlock();
+
+ return -ENOBUFS;
+}
+
+#ifndef _HURD_
+static
+#endif
+int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen)
+{
+ struct inet6_ifaddr *ifp;
+ struct inet6_dev *idev;
+ struct device *dev;
+
+ if ((dev = dev_get_by_index(ifindex)) == NULL)
+ return -ENODEV;
+
+ if ((idev = ipv6_get_idev(dev)) == NULL)
+ return -ENXIO;
+
+ start_bh_atomic();
+ for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) {
+ if (ifp->prefix_len == plen &&
+ (!memcmp(pfx, &ifp->addr, sizeof(struct in6_addr)))) {
+ ipv6_del_addr(ifp);
+ end_bh_atomic();
+
+ /* If the last address is deleted administratively,
+ disable IPv6 on this interface.
+ */
+ if (idev->addr_list == NULL)
+ addrconf_ifdown(idev->dev, 1);
+ return 0;
+ }
+ }
+ end_bh_atomic();
+ return -EADDRNOTAVAIL;
+}
+
+
+#ifndef _HURD_
+int addrconf_add_ifaddr(void *arg)
+{
+ struct in6_ifreq ireq;
+ int err;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
+ return -EFAULT;
+
+ rtnl_lock();
+ err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
+ rtnl_unlock();
+ return err;
+}
+#endif /* not _HURD_ */
+
+#ifndef _HURD_
+int addrconf_del_ifaddr(void *arg)
+{
+ struct in6_ifreq ireq;
+ int err;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
+ return -EFAULT;
+
+ rtnl_lock();
+ err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
+ rtnl_unlock();
+ return err;
+}
+#endif /* not _HURD_ */
+
+static void sit_add_v4_addrs(struct inet6_dev *idev)
+{
+ struct inet6_ifaddr * ifp;
+ struct in6_addr addr;
+ struct device *dev;
+ int scope;
+
+ memset(&addr, 0, sizeof(struct in6_addr));
+ memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4);
+
+ if (idev->dev->flags&IFF_POINTOPOINT) {
+ addr.s6_addr32[0] = __constant_htonl(0xfe800000);
+ scope = IFA_LINK;
+ } else {
+ scope = IPV6_ADDR_COMPATv4;
+ }
+
+ if (addr.s6_addr32[3]) {
+ addrconf_lock();
+ ifp = ipv6_add_addr(idev, &addr, scope);
+ if (ifp) {
+ ifp->flags |= ADDR_PERMANENT;
+ ifp->prefix_len = 128;
+ ipv6_ifa_notify(RTM_NEWADDR, ifp);
+ }
+ addrconf_unlock();
+ return;
+ }
+
+ for (dev = dev_base; dev != NULL; dev = dev->next) {
+ if (dev->ip_ptr && (dev->flags & IFF_UP)) {
+ struct in_device * in_dev = dev->ip_ptr;
+ struct in_ifaddr * ifa;
+
+ int flag = scope;
+
+ for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
+ addr.s6_addr32[3] = ifa->ifa_local;
+
+ if (ifa->ifa_scope == RT_SCOPE_LINK)
+ continue;
+ if (ifa->ifa_scope >= RT_SCOPE_HOST) {
+ if (idev->dev->flags&IFF_POINTOPOINT)
+ continue;
+ flag |= IFA_HOST;
+ }
+
+ addrconf_lock();
+ ifp = ipv6_add_addr(idev, &addr, flag);
+ if (ifp) {
+ if (idev->dev->flags&IFF_POINTOPOINT)
+ ifp->prefix_len = 10;
+ else
+ ifp->prefix_len = 96;
+ ifp->flags |= ADDR_PERMANENT;
+ ipv6_ifa_notify(RTM_NEWADDR, ifp);
+ }
+ addrconf_unlock();
+ }
+ }
+ }
+}
+
+static void init_loopback(struct device *dev)
+{
+ struct in6_addr addr;
+ struct inet6_dev *idev;
+ struct inet6_ifaddr * ifp;
+
+ /* ::1 */
+
+ memset(&addr, 0, sizeof(struct in6_addr));
+ addr.s6_addr[15] = 1;
+
+ if ((idev = ipv6_find_idev(dev)) == NULL) {
+ printk(KERN_DEBUG "init loopback: add_dev failed\n");
+ return;
+ }
+
+ addrconf_lock();
+ ifp = ipv6_add_addr(idev, &addr, IFA_HOST);
+
+ if (ifp) {
+ ifp->flags |= ADDR_PERMANENT;
+ ifp->prefix_len = 128;
+ ipv6_ifa_notify(RTM_NEWADDR, ifp);
+ }
+ addrconf_unlock();
+}
+
+static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
+{
+ struct inet6_ifaddr * ifp;
+
+ addrconf_lock();
+ ifp = ipv6_add_addr(idev, addr, IFA_LINK);
+ if (ifp) {
+ ifp->flags = ADDR_PERMANENT;
+ ifp->prefix_len = 10;
+ addrconf_dad_start(ifp);
+ }
+ addrconf_unlock();
+}
+
+static void addrconf_dev_config(struct device *dev)
+{
+ struct in6_addr addr;
+ struct inet6_dev * idev;
+
+ if (dev->type != ARPHRD_ETHER) {
+ /* Alas, we support only Ethernet autoconfiguration. */
+ return;
+ }
+
+ idev = addrconf_add_dev(dev);
+ if (idev == NULL)
+ return;
+
+#ifdef CONFIG_IPV6_EUI64
+ memset(&addr, 0, sizeof(struct in6_addr));
+
+ addr.s6_addr[0] = 0xFE;
+ addr.s6_addr[1] = 0x80;
+
+ if (ipv6_generate_eui64(addr.s6_addr + 8, dev) == 0)
+ addrconf_add_linklocal(idev, &addr);
+#endif
+
+#ifndef CONFIG_IPV6_NO_PB
+ memset(&addr, 0, sizeof(struct in6_addr));
+
+ addr.s6_addr[0] = 0xFE;
+ addr.s6_addr[1] = 0x80;
+
+ memcpy(addr.s6_addr + (sizeof(struct in6_addr) - dev->addr_len),
+ dev->dev_addr, dev->addr_len);
+ addrconf_add_linklocal(idev, &addr);
+#endif
+}
+
+static void addrconf_sit_config(struct device *dev)
+{
+ struct inet6_dev *idev;
+
+ /*
+ * Configure the tunnel with one of our IPv4
+ * addresses... we should configure all of
+ * our v4 addrs in the tunnel
+ */
+
+ if ((idev = ipv6_find_idev(dev)) == NULL) {
+ printk(KERN_DEBUG "init sit: add_dev failed\n");
+ return;
+ }
+
+ sit_add_v4_addrs(idev);
+
+ if (dev->flags&IFF_POINTOPOINT) {
+ addrconf_add_mroute(dev);
+ addrconf_add_lroute(dev);
+ } else
+ sit_route_add(dev);
+}
+
+
+int addrconf_notify(struct notifier_block *this, unsigned long event,
+ void * data)
+{
+ struct device *dev;
+
+ dev = (struct device *) data;
+
+ switch(event) {
+ case NETDEV_UP:
+ switch(dev->type) {
+ case ARPHRD_SIT:
+ addrconf_sit_config(dev);
+ break;
+
+ case ARPHRD_LOOPBACK:
+ init_loopback(dev);
+ break;
+
+ default:
+ addrconf_dev_config(dev);
+ break;
+ };
+
+#ifdef CONFIG_IPV6_NETLINK
+ rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);
+#endif
+ break;
+
+ case NETDEV_CHANGEMTU:
+ if (dev->mtu >= IPV6_MIN_MTU) {
+ struct inet6_dev *idev;
+
+ if ((idev = ipv6_get_idev(dev)) == NULL)
+ break;
+ idev->cnf.mtu6 = dev->mtu;
+ rt6_mtu_change(dev, dev->mtu);
+ break;
+ }
+
+ /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */
+
+ case NETDEV_DOWN:
+ case NETDEV_UNREGISTER:
+ /*
+ * Remove all addresses from this interface.
+ */
+ if (addrconf_ifdown(dev, event != NETDEV_DOWN) == 0) {
+#ifdef CONFIG_IPV6_NETLINK
+ rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);
+#endif
+ }
+
+ break;
+ case NETDEV_CHANGE:
+ break;
+ };
+
+ return NOTIFY_OK;
+}
+
+static int addrconf_ifdown(struct device *dev, int how)
+{
+ struct inet6_dev *idev, **bidev;
+ struct inet6_ifaddr *ifa, **bifa;
+ int i, hash;
+
+ rt6_ifdown(dev);
+ neigh_ifdown(&nd_tbl, dev);
+
+ idev = ipv6_get_idev(dev);
+ if (idev == NULL)
+ return -ENODEV;
+
+ start_bh_atomic();
+
+ /* Discard address list */
+
+ idev->addr_list = NULL;
+
+ /*
+ * Clean addresses hash table
+ */
+
+ for (i=0; i<16; i++) {
+ bifa = &inet6_addr_lst[i];
+
+ while ((ifa = *bifa) != NULL) {
+ if (ifa->idev == idev) {
+ *bifa = ifa->lst_next;
+ del_timer(&ifa->timer);
+ ipv6_ifa_notify(RTM_DELADDR, ifa);
+ kfree(ifa);
+ continue;
+ }
+ bifa = &ifa->lst_next;
+ }
+ }
+
+ /* Discard multicast list */
+
+ if (how == 1)
+ ipv6_mc_destroy_dev(idev);
+ else
+ ipv6_mc_down(idev);
+
+ /* Delete device from device hash table (if unregistered) */
+
+ if (how == 1) {
+ hash = ipv6_devindex_hash(dev->ifindex);
+
+ for (bidev = &inet6_dev_lst[hash]; (idev=*bidev) != NULL; bidev = &idev->next) {
+ if (idev->dev == dev) {
+ *bidev = idev->next;
+ neigh_parms_release(&nd_tbl, idev->nd_parms);
+#ifdef CONFIG_SYSCTL
+ addrconf_sysctl_unregister(&idev->cnf);
+#endif
+ kfree(idev);
+ break;
+ }
+ }
+ }
+ end_bh_atomic();
+ return 0;
+}
+
+
+static void addrconf_rs_timer(unsigned long data)
+{
+ struct inet6_ifaddr *ifp;
+
+ ifp = (struct inet6_ifaddr *) data;
+
+ if (ifp->idev->cnf.forwarding)
+ return;
+
+ if (ifp->idev->if_flags & IF_RA_RCVD) {
+ /*
+ * Announcement received after solicitation
+ * was sent
+ */
+ return;
+ }
+
+ if (ifp->probes++ <= ifp->idev->cnf.rtr_solicits) {
+ struct in6_addr all_routers;
+
+ ipv6_addr_all_routers(&all_routers);
+
+ ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers);
+
+ ifp->timer.function = addrconf_rs_timer;
+ ifp->timer.expires = (jiffies +
+ ifp->idev->cnf.rtr_solicit_interval);
+ add_timer(&ifp->timer);
+ } else {
+ struct in6_rtmsg rtmsg;
+
+ printk(KERN_DEBUG "%s: no IPv6 routers present\n",
+ ifp->idev->dev->name);
+
+ memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+ rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+ rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF |
+ RTF_DEFAULT | RTF_UP);
+
+ rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
+
+ ip6_route_add(&rtmsg);
+ }
+}
+
+/*
+ * Duplicate Address Detection
+ */
+static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+{
+ struct device *dev;
+ unsigned long rand_num;
+
+ dev = ifp->idev->dev;
+
+ addrconf_join_solict(dev, &ifp->addr);
+
+ if (ifp->prefix_len != 128 && (ifp->flags&ADDR_PERMANENT))
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, RTF_ADDRCONF);
+
+ if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
+ start_bh_atomic();
+ ifp->flags &= ~DAD_INCOMPLETE;
+ addrconf_dad_completed(ifp);
+ end_bh_atomic();
+ return;
+ }
+
+ net_srandom(ifp->addr.s6_addr32[3]);
+
+ ifp->probes = ifp->idev->cnf.dad_transmits;
+ ifp->flags |= DAD_INCOMPLETE;
+
+ rand_num = net_random() % ifp->idev->cnf.rtr_solicit_delay;
+
+ ifp->timer.function = addrconf_dad_timer;
+ ifp->timer.expires = jiffies + rand_num;
+
+ add_timer(&ifp->timer);
+}
+
+static void addrconf_dad_timer(unsigned long data)
+{
+ struct inet6_ifaddr *ifp;
+ struct in6_addr unspec;
+ struct in6_addr mcaddr;
+
+ ifp = (struct inet6_ifaddr *) data;
+
+ if (ifp->probes == 0) {
+ /*
+ * DAD was successful
+ */
+
+ ifp->flags &= ~DAD_INCOMPLETE;
+ addrconf_dad_completed(ifp);
+ return;
+ }
+
+ ifp->probes--;
+
+ /* send a neighbour solicitation for our addr */
+ memset(&unspec, 0, sizeof(unspec));
+#ifdef CONFIG_IPV6_EUI64
+ addrconf_addr_solict_mult_new(&ifp->addr, &mcaddr);
+ ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);
+#endif
+#ifndef CONFIG_IPV6_NO_PB
+ addrconf_addr_solict_mult_old(&ifp->addr, &mcaddr);
+ ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);
+#endif
+
+ ifp->timer.expires = jiffies + ifp->idev->cnf.rtr_solicit_interval;
+ add_timer(&ifp->timer);
+}
+
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
+{
+ struct device * dev = ifp->idev->dev;
+
+ /*
+ * Configure the address for reception. Now it is valid.
+ */
+
+ ipv6_ifa_notify(RTM_NEWADDR, ifp);
+
+ /* If added prefix is link local and forwarding is off,
+ start sending router solicitations.
+ */
+
+ if (ifp->idev->cnf.forwarding == 0 &&
+ (dev->flags&IFF_LOOPBACK) == 0 &&
+ (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
+ struct in6_addr all_routers;
+
+ ipv6_addr_all_routers(&all_routers);
+
+ /*
+ * If a host as already performed a random delay
+ * [...] as part of DAD [...] there is no need
+ * to delay again before sending the first RS
+ */
+ ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers);
+
+ ifp->probes = 1;
+ ifp->timer.function = addrconf_rs_timer;
+ ifp->timer.expires = (jiffies +
+ ifp->idev->cnf.rtr_solicit_interval);
+ ifp->idev->if_flags |= IF_RS_SENT;
+ add_timer(&ifp->timer);
+ }
+}
+
+#ifdef CONFIG_PROC_FS
+static int iface_proc_info(char *buffer, char **start, off_t offset,
+ int length, int dummy)
+{
+ struct inet6_ifaddr *ifp;
+ int i;
+ int len = 0;
+ off_t pos=0;
+ off_t begin=0;
+
+ addrconf_lock();
+
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
+ int j;
+
+ for (j=0; j<16; j++) {
+ sprintf(buffer + len, "%02x",
+ ifp->addr.s6_addr[j]);
+ len += 2;
+ }
+
+ len += sprintf(buffer + len,
+ " %02x %02x %02x %02x %8s\n",
+ ifp->idev->dev->ifindex,
+ ifp->prefix_len,
+ ifp->scope,
+ ifp->flags,
+ ifp->idev->dev->name);
+ pos=begin+len;
+ if(pos<offset) {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ goto done;
+ }
+ }
+
+done:
+ addrconf_unlock();
+
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ if(len<0)
+ len=0;
+ return len;
+}
+
+struct proc_dir_entry iface_proc_entry =
+{
+ 0, 8, "if_inet6",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, NULL,
+ &iface_proc_info
+};
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * Periodic address status verification
+ */
+
+void addrconf_verify(unsigned long foo)
+{
+ struct inet6_ifaddr *ifp;
+ unsigned long now = jiffies;
+ int i;
+
+ if (atomic_read(&addr_list_lock)) {
+ addr_chk_timer.expires = jiffies + 1*HZ;
+ add_timer(&addr_chk_timer);
+ return;
+ }
+
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (ifp=inet6_addr_lst[i]; ifp;) {
+ if (ifp->flags & ADDR_INVALID) {
+ struct inet6_ifaddr *bp = ifp;
+ ifp= ifp->lst_next;
+ ipv6_del_addr(bp);
+ continue;
+ }
+ if (!(ifp->flags & ADDR_PERMANENT)) {
+ struct inet6_ifaddr *bp;
+ unsigned long age;
+
+ age = (now - ifp->tstamp) / HZ;
+
+ bp = ifp;
+ ifp= ifp->lst_next;
+
+ if (age > bp->valid_lft)
+ ipv6_del_addr(bp);
+ else if (age > bp->prefered_lft) {
+ bp->flags |= ADDR_DEPRECATED;
+ ipv6_ifa_notify(0, bp);
+ }
+
+ continue;
+ }
+ ifp = ifp->lst_next;
+ }
+ }
+
+ addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
+ add_timer(&addr_chk_timer);
+}
+
+#ifdef CONFIG_RTNETLINK
+
+static int
+inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+ struct in6_addr *pfx;
+
+ pfx = NULL;
+ if (rta[IFA_ADDRESS-1]) {
+ if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx))
+ return -EINVAL;
+ pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
+ }
+ if (rta[IFA_LOCAL-1]) {
+ if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+ return -EINVAL;
+ pfx = RTA_DATA(rta[IFA_LOCAL-1]);
+ }
+ if (pfx == NULL)
+ return -EINVAL;
+
+ return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+}
+
+static int
+inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+ struct in6_addr *pfx;
+
+ pfx = NULL;
+ if (rta[IFA_ADDRESS-1]) {
+ if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx))
+ return -EINVAL;
+ pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
+ }
+ if (rta[IFA_LOCAL-1]) {
+ if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+ return -EINVAL;
+ pfx = RTA_DATA(rta[IFA_LOCAL-1]);
+ }
+ if (pfx == NULL)
+ return -EINVAL;
+
+ return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+}
+
+static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
+ u32 pid, u32 seq, int event)
+{
+ struct ifaddrmsg *ifm;
+ struct nlmsghdr *nlh;
+ struct ifa_cacheinfo ci;
+ unsigned char *b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
+ ifm = NLMSG_DATA(nlh);
+ ifm->ifa_family = AF_INET6;
+ ifm->ifa_prefixlen = ifa->prefix_len;
+ ifm->ifa_flags = ifa->flags & ~ADDR_INVALID;
+ ifm->ifa_scope = RT_SCOPE_UNIVERSE;
+ if (ifa->scope&IFA_HOST)
+ ifm->ifa_scope = RT_SCOPE_HOST;
+ else if (ifa->scope&IFA_LINK)
+ ifm->ifa_scope = RT_SCOPE_LINK;
+ else if (ifa->scope&IFA_SITE)
+ ifm->ifa_scope = RT_SCOPE_SITE;
+ ifm->ifa_index = ifa->idev->dev->ifindex;
+ RTA_PUT(skb, IFA_ADDRESS, 16, &ifa->addr);
+ if (!(ifa->flags&IFA_F_PERMANENT)) {
+ ci.ifa_prefered = ifa->prefered_lft;
+ ci.ifa_valid = ifa->valid_lft;
+ if (ci.ifa_prefered != 0xFFFFFFFF) {
+ long tval = (jiffies - ifa->tstamp)/HZ;
+ ci.ifa_prefered -= tval;
+ if (ci.ifa_valid != 0xFFFFFFFF)
+ ci.ifa_valid -= tval;
+ }
+ RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);
+ }
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx, ip_idx;
+ int s_idx, s_ip_idx;
+ struct inet6_ifaddr *ifa;
+
+ s_idx = cb->args[0];
+ s_ip_idx = ip_idx = cb->args[1];
+
+ for (idx=0; idx < IN6_ADDR_HSIZE; idx++) {
+ if (idx < s_idx)
+ continue;
+ if (idx > s_idx)
+ s_ip_idx = 0;
+ start_bh_atomic();
+ for (ifa=inet6_addr_lst[idx], ip_idx = 0; ifa;
+ ifa = ifa->lst_next, ip_idx++) {
+ if (ip_idx < s_ip_idx)
+ continue;
+ if (inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) {
+ end_bh_atomic();
+ goto done;
+ }
+ }
+ end_bh_atomic();
+ }
+done:
+ cb->args[0] = idx;
+ cb->args[1] = ip_idx;
+
+ return skb->len;
+}
+
+static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
+{
+ struct sk_buff *skb;
+ int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128);
+
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb) {
+ netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, ENOBUFS);
+ return;
+ }
+ if (inet6_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
+ kfree_skb(skb);
+ netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, EINVAL);
+ return;
+ }
+ NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_IFADDR;
+ netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_IFADDR, GFP_ATOMIC);
+}
+
+static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
+{
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+ { NULL, NULL, },
+
+ { inet6_rtm_newaddr, NULL, },
+ { inet6_rtm_deladdr, NULL, },
+ { NULL, inet6_dump_ifaddr, },
+ { NULL, NULL, },
+
+ { inet6_rtm_newroute, NULL, },
+ { inet6_rtm_delroute, NULL, },
+ { inet6_rtm_getroute, inet6_dump_fib, },
+ { NULL, NULL, },
+};
+#endif
+
+static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
+{
+#ifdef CONFIG_RTNETLINK
+ inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
+#endif
+ switch (event) {
+ case RTM_NEWADDR:
+ ip6_rt_addr_add(&ifp->addr, ifp->idev->dev);
+ break;
+ case RTM_DELADDR:
+ start_bh_atomic();
+ addrconf_leave_solict(ifp->idev->dev, &ifp->addr);
+ if (ipv6_chk_addr(&ifp->addr, ifp->idev->dev, 0) == NULL)
+ ip6_rt_addr_del(&ifp->addr, ifp->idev->dev);
+ end_bh_atomic();
+ break;
+ }
+}
+
+#ifdef CONFIG_SYSCTL
+
+static
+int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp)
+{
+ int *valp = ctl->data;
+ int val = *valp;
+ int ret;
+
+ ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+ if (write && *valp != val && valp != &ipv6_devconf_dflt.forwarding) {
+ struct inet6_dev *idev = NULL;
+
+ if (valp != &ipv6_devconf.forwarding) {
+ struct device *dev = dev_get_by_index(ctl->ctl_name);
+ if (dev)
+ idev = ipv6_get_idev(dev);
+ if (idev == NULL)
+ return ret;
+ } else
+ ipv6_devconf_dflt.forwarding = ipv6_devconf.forwarding;
+
+ addrconf_forward_change(idev);
+
+ if (*valp) {
+ start_bh_atomic();
+ rt6_purge_dflt_routers(0);
+ end_bh_atomic();
+ }
+ }
+
+ return ret;
+}
+
+static struct addrconf_sysctl_table
+{
+ struct ctl_table_header *sysctl_header;
+ ctl_table addrconf_vars[11];
+ ctl_table addrconf_dev[2];
+ ctl_table addrconf_conf_dir[2];
+ ctl_table addrconf_proto_dir[2];
+ ctl_table addrconf_root_dir[2];
+} addrconf_sysctl = {
+ NULL,
+ {{NET_IPV6_FORWARDING, "forwarding",
+ &ipv6_devconf.forwarding, sizeof(int), 0644, NULL,
+ &addrconf_sysctl_forward},
+
+ {NET_IPV6_HOP_LIMIT, "hop_limit",
+ &ipv6_devconf.hop_limit, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+
+ {NET_IPV6_MTU, "mtu",
+ &ipv6_devconf.mtu6, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+
+ {NET_IPV6_ACCEPT_RA, "accept_ra",
+ &ipv6_devconf.accept_ra, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+
+ {NET_IPV6_ACCEPT_REDIRECTS, "accept_redirects",
+ &ipv6_devconf.accept_redirects, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+
+ {NET_IPV6_AUTOCONF, "autoconf",
+ &ipv6_devconf.autoconf, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+
+ {NET_IPV6_DAD_TRANSMITS, "dad_transmits",
+ &ipv6_devconf.dad_transmits, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+
+ {NET_IPV6_RTR_SOLICITS, "router_solicitations",
+ &ipv6_devconf.rtr_solicits, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+
+ {NET_IPV6_RTR_SOLICIT_INTERVAL, "router_solicitation_interval",
+ &ipv6_devconf.rtr_solicit_interval, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+
+ {NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay",
+ &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+
+ {0}},
+
+ {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, addrconf_sysctl.addrconf_vars},{0}},
+ {{NET_IPV6_CONF, "conf", NULL, 0, 0555, addrconf_sysctl.addrconf_dev},{0}},
+ {{NET_IPV6, "ipv6", NULL, 0, 0555, addrconf_sysctl.addrconf_conf_dir},{0}},
+ {{CTL_NET, "net", NULL, 0, 0555, addrconf_sysctl.addrconf_proto_dir},{0}}
+};
+
+static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p)
+{
+ int i;
+ struct device *dev = idev ? idev->dev : NULL;
+ struct addrconf_sysctl_table *t;
+
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return;
+ memcpy(t, &addrconf_sysctl, sizeof(*t));
+ for (i=0; i<sizeof(t->addrconf_vars)/sizeof(t->addrconf_vars[0])-1; i++) {
+ t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
+ t->addrconf_vars[i].de = NULL;
+ }
+ if (dev) {
+ t->addrconf_dev[0].procname = dev->name;
+ t->addrconf_dev[0].ctl_name = dev->ifindex;
+ } else {
+ t->addrconf_dev[0].procname = "default";
+ t->addrconf_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
+ }
+ t->addrconf_dev[0].child = t->addrconf_vars;
+ t->addrconf_dev[0].de = NULL;
+ t->addrconf_conf_dir[0].child = t->addrconf_dev;
+ t->addrconf_conf_dir[0].de = NULL;
+ t->addrconf_proto_dir[0].child = t->addrconf_conf_dir;
+ t->addrconf_proto_dir[0].de = NULL;
+ t->addrconf_root_dir[0].child = t->addrconf_proto_dir;
+ t->addrconf_root_dir[0].de = NULL;
+
+ t->sysctl_header = register_sysctl_table(t->addrconf_root_dir, 0);
+ if (t->sysctl_header == NULL)
+ kfree(t);
+ else
+ p->sysctl = t;
+}
+
+static void addrconf_sysctl_unregister(struct ipv6_devconf *p)
+{
+ if (p->sysctl) {
+ struct addrconf_sysctl_table *t = p->sysctl;
+ p->sysctl = NULL;
+ unregister_sysctl_table(t->sysctl_header);
+ kfree(t);
+ }
+}
+
+
+#endif
+
+/*
+ * Init / cleanup code
+ */
+
+__initfunc(void addrconf_init(void))
+{
+#ifdef MODULE
+ struct device *dev;
+
+ /* This takes sense only during module load. */
+
+ for (dev = dev_base; dev; dev = dev->next) {
+ if (!(dev->flags&IFF_UP))
+ continue;
+
+ switch (dev->type) {
+ case ARPHRD_LOOPBACK:
+ init_loopback(dev);
+ break;
+ case ARPHRD_ETHER:
+ addrconf_dev_config(dev);
+ break;
+ default:
+ /* Ignore all other */
+ }
+ }
+#endif
+
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&iface_proc_entry);
+#endif
+
+ addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
+ add_timer(&addr_chk_timer);
+#ifdef CONFIG_RTNETLINK
+ rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
+#endif
+#ifdef CONFIG_SYSCTL
+ addrconf_sysctl.sysctl_header =
+ register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0);
+ addrconf_sysctl_register(NULL, &ipv6_devconf_dflt);
+#endif
+}
+
+#ifdef MODULE
+void addrconf_cleanup(void)
+{
+ struct inet6_dev *idev;
+ struct inet6_ifaddr *ifa;
+ int i;
+
+#ifdef CONFIG_RTNETLINK
+ rtnetlink_links[PF_INET6] = NULL;
+#endif
+#ifdef CONFIG_SYSCTL
+ addrconf_sysctl_unregister(&ipv6_devconf_dflt);
+ addrconf_sysctl_unregister(&ipv6_devconf);
+#endif
+
+ del_timer(&addr_chk_timer);
+
+ /*
+ * clean dev list.
+ */
+
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ struct inet6_dev *next;
+ for (idev = inet6_dev_lst[i]; idev; idev = next) {
+ next = idev->next;
+ addrconf_ifdown(idev->dev, 1);
+ }
+ }
+
+ start_bh_atomic();
+ /*
+ * clean addr_list
+ */
+
+ for (i=0; i < IN6_ADDR_HSIZE; i++) {
+ for (ifa=inet6_addr_lst[i]; ifa; ) {
+ struct inet6_ifaddr *bifa;
+
+ bifa = ifa;
+ ifa = ifa->lst_next;
+ printk(KERN_DEBUG "bug: IPv6 address leakage detected: ifa=%p\n", bifa);
+ /* Do not free it; something is wrong.
+ Now we can investigate it with debugger.
+ */
+ }
+ }
+ end_bh_atomic();
+
+#ifdef CONFIG_PROC_FS
+ proc_net_unregister(iface_proc_entry.low_ino);
+#endif
+}
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv6/af_inet6.c b/pfinet/linux-src/net/ipv6/af_inet6.c
new file mode 100644
index 00000000..ca428188
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/af_inet6.c
@@ -0,0 +1,642 @@
+/*
+ * PF_INET6 socket protocol family
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Adapted from linux/net/ipv4/af_inet.c
+ *
+ * $Id: af_inet6.c,v 1.3 2007/10/13 01:43:00 stesie Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/icmpv6.h>
+
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/udp.h>
+#include <net/tcp.h>
+#include <net/ipip.h>
+#include <net/protocol.h>
+#include <net/inet_common.h>
+#include <net/transp_v6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#ifdef MODULE
+static int unloadable = 0; /* XX: Turn to one when all is ok within the
+ module for allowing unload */
+#endif
+
+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Cast of dozens");
+MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
+MODULE_PARM(unloadable, "i");
+#endif
+
+extern struct proto_ops inet6_stream_ops;
+extern struct proto_ops inet6_dgram_ops;
+
+/* IPv6 procfs goodies... */
+
+#ifdef CONFIG_PROC_FS
+extern int raw6_get_info(char *, char **, off_t, int, int);
+extern int tcp6_get_info(char *, char **, off_t, int, int);
+extern int udp6_get_info(char *, char **, off_t, int, int);
+extern int afinet6_get_info(char *, char **, off_t, int, int);
+extern int afinet6_get_snmp(char *, char **, off_t, int, int);
+#endif
+
+#ifdef CONFIG_SYSCTL
+extern void ipv6_sysctl_register(void);
+extern void ipv6_sysctl_unregister(void);
+#endif
+
+static int inet6_create(struct socket *sock, int protocol)
+{
+ struct sock *sk;
+ struct proto *prot;
+
+ sk = sk_alloc(PF_INET6, GFP_KERNEL, 1);
+ if (sk == NULL)
+ goto do_oom;
+
+ if(sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET) {
+ if (protocol && protocol != IPPROTO_TCP)
+ goto free_and_noproto;
+ protocol = IPPROTO_TCP;
+ prot = &tcpv6_prot;
+ sock->ops = &inet6_stream_ops;
+ } else if(sock->type == SOCK_DGRAM) {
+ if (protocol && protocol != IPPROTO_UDP)
+ goto free_and_noproto;
+ protocol = IPPROTO_UDP;
+ sk->no_check = UDP_NO_CHECK;
+ prot=&udpv6_prot;
+ sock->ops = &inet6_dgram_ops;
+ } else if(sock->type == SOCK_RAW) {
+ if (!capable(CAP_NET_RAW))
+ goto free_and_badperm;
+ if (!protocol)
+ goto free_and_noproto;
+ prot = &rawv6_prot;
+ sock->ops = &inet6_dgram_ops;
+ sk->reuse = 1;
+ sk->num = protocol;
+ } else {
+ goto free_and_badtype;
+ }
+
+ sock_init_data(sock, sk);
+
+ sk->destruct = NULL;
+ sk->zapped = 0;
+ sk->family = PF_INET6;
+ sk->protocol = protocol;
+
+ sk->prot = prot;
+ sk->backlog_rcv = prot->backlog_rcv;
+
+ sk->timer.data = (unsigned long)sk;
+ sk->timer.function = &net_timer;
+
+ sk->net_pinfo.af_inet6.hop_limit = -1;
+ sk->net_pinfo.af_inet6.mcast_hops = -1;
+ sk->net_pinfo.af_inet6.mc_loop = 1;
+ sk->net_pinfo.af_inet6.pmtudisc = IPV6_PMTUDISC_WANT;
+
+ /* Init the ipv4 part of the socket since we can have sockets
+ * using v6 API for ipv4.
+ */
+ sk->ip_ttl = 64;
+
+ sk->ip_mc_loop = 1;
+ sk->ip_mc_ttl = 1;
+ sk->ip_mc_index = 0;
+ sk->ip_mc_list = NULL;
+
+ if (sk->type==SOCK_RAW && protocol==IPPROTO_RAW)
+ sk->ip_hdrincl=1;
+
+ if (sk->num) {
+ /* It assumes that any protocol which allows
+ * the user to assign a number at socket
+ * creation time automatically shares.
+ */
+ sk->sport = ntohs(sk->num);
+ sk->prot->hash(sk);
+ add_to_prot_sklist(sk);
+ }
+
+ if (sk->prot->init) {
+ int err = sk->prot->init(sk);
+ if (err != 0) {
+ destroy_sock(sk);
+ return(err);
+ }
+ }
+ MOD_INC_USE_COUNT;
+ return(0);
+
+free_and_badtype:
+ sk_free(sk);
+ return -ESOCKTNOSUPPORT;
+free_and_badperm:
+ sk_free(sk);
+ return -EPERM;
+free_and_noproto:
+ sk_free(sk);
+ return -EPROTONOSUPPORT;
+do_oom:
+ return -ENOBUFS;
+}
+
+
+/* bind for INET6 API */
+static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_in6 *addr=(struct sockaddr_in6 *)uaddr;
+ struct sock *sk = sock->sk;
+ __u32 v4addr = 0;
+ unsigned short snum;
+ int addr_type = 0;
+
+ /* If the socket has its own bind function then use it. */
+ if(sk->prot->bind)
+ return sk->prot->bind(sk, uaddr, addr_len);
+
+ /* Check these errors (active socket, bad address length, double bind). */
+ if ((sk->state != TCP_CLOSE) ||
+ (addr_len < sizeof(struct sockaddr_in6)) ||
+ (sk->num != 0))
+ return -EINVAL;
+
+ addr_type = ipv6_addr_type(&addr->sin6_addr);
+ if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM)
+ return(-EINVAL);
+
+ /* Check if the address belongs to the host. */
+ if (addr_type == IPV6_ADDR_MAPPED) {
+ v4addr = addr->sin6_addr.s6_addr32[3];
+ if (inet_addr_type(v4addr) != RTN_LOCAL)
+ return(-EADDRNOTAVAIL);
+ } else {
+ if (addr_type != IPV6_ADDR_ANY) {
+ struct net_device *dev = NULL;
+
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ addr->sin6_scope_id) {
+ /* Override any existing binding,
+ if another one is supplied
+ by user. */
+ sk->bound_dev_if = addr->sin6_scope_id;
+ }
+
+ /* Binding to link-local address requires
+ an interface */
+ if (!sk->bound_dev_if)
+ return(-EINVAL);
+ dev = dev_get_by_index(sk->bound_dev_if);
+ if (!dev)
+ return(-ENODEV);
+ }
+
+ /* ipv4 addr of the socket is invalid. Only the
+ * unpecified and mapped address have a v4 equivalent.
+ */
+ v4addr = LOOPBACK4_IPV6;
+ if (!(addr_type & IPV6_ADDR_MULTICAST)) {
+ if (ipv6_chk_addr(&addr->sin6_addr, NULL, 0) == NULL)
+ return(-EADDRNOTAVAIL);
+ }
+ }
+ }
+
+ sk->rcv_saddr = v4addr;
+ sk->saddr = v4addr;
+
+ memcpy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr,
+ sizeof(struct in6_addr));
+
+ if (!(addr_type & IPV6_ADDR_MULTICAST))
+ memcpy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr,
+ sizeof(struct in6_addr));
+
+ snum = ntohs(addr->sin6_port);
+ if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+ return(-EACCES);
+
+ /* Make sure we are allowed to bind here. */
+ if(sk->prot->get_port(sk, snum) != 0)
+ return -EADDRINUSE;
+
+ sk->sport = ntohs(sk->num);
+ sk->dport = 0;
+ sk->daddr = 0;
+ sk->prot->hash(sk);
+ add_to_prot_sklist(sk);
+
+ return(0);
+}
+
+static int inet6_release(struct socket *sock, struct socket *peer)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk == NULL)
+ return -EINVAL;
+
+ /* Free mc lists */
+ ipv6_sock_mc_close(sk);
+
+ /* Huh! MOD_DEC_USE_COUNT was here :-(
+ It is impossible by two reasons: socket destroy
+ may be delayed and inet_release may sleep and
+ return to nowhere then. It should be moved to
+ inet6_destroy_sock(), but we have no explicit constructor :-(
+ --ANK (980802)
+ */
+ MOD_DEC_USE_COUNT;
+ return inet_release(sock, peer);
+}
+
+int inet6_destroy_sock(struct sock *sk)
+{
+ struct sk_buff *skb;
+ struct ipv6_txoptions *opt;
+
+ /*
+ * Release destination entry
+ */
+
+ dst_release(xchg(&sk->dst_cache,NULL));
+
+ /* Release rx options */
+
+ if ((skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, NULL)) != NULL)
+ kfree_skb(skb);
+
+ /* Free flowlabels */
+ fl6_free_socklist(sk);
+
+ /* Free tx options */
+
+ if ((opt = xchg(&sk->net_pinfo.af_inet6.opt, NULL)) != NULL)
+ sock_kfree_s(sk, opt, opt->tot_len);
+
+ return 0;
+}
+
+/*
+ * This does both peername and sockname.
+ */
+
+static int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
+ int *uaddr_len, int peer)
+{
+ struct sockaddr_in6 *sin=(struct sockaddr_in6 *)uaddr;
+ struct sock *sk;
+
+ sin->sin6_family = AF_INET6;
+ sin->sin6_flowinfo = 0;
+ sin->sin6_scope_id = 0;
+
+ sk = sock->sk;
+ if (peer) {
+ if (!tcp_connected(sk->state))
+ return(-ENOTCONN);
+ sin->sin6_port = sk->dport;
+ memcpy(&sin->sin6_addr, &sk->net_pinfo.af_inet6.daddr,
+ sizeof(struct in6_addr));
+ if (sk->net_pinfo.af_inet6.sndflow)
+ sin->sin6_flowinfo = sk->net_pinfo.af_inet6.flow_label;
+ } else {
+ if (ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_ANY)
+ memcpy(&sin->sin6_addr,
+ &sk->net_pinfo.af_inet6.saddr,
+ sizeof(struct in6_addr));
+ else
+ memcpy(&sin->sin6_addr,
+ &sk->net_pinfo.af_inet6.rcv_saddr,
+ sizeof(struct in6_addr));
+
+ sin->sin6_port = sk->sport;
+ }
+ if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin->sin6_scope_id = sk->bound_dev_if;
+ *uaddr_len = sizeof(*sin);
+ return(0);
+}
+
+#ifdef _HURD_
+#define inet6_ioctl 0
+#else
+
+static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ struct sock *sk = sock->sk;
+ int err = -EINVAL;
+ int pid;
+
+ switch(cmd)
+ {
+ case FIOSETOWN:
+ case SIOCSPGRP:
+ err = get_user(pid, (int *) arg);
+ if(err)
+ return err;
+
+ /* see sock_no_fcntl */
+ if (current->pid != pid && current->pgrp != -pid &&
+ !capable(CAP_NET_ADMIN))
+ return -EPERM;
+ sk->proc = pid;
+ return(0);
+ case FIOGETOWN:
+ case SIOCGPGRP:
+ err = put_user(sk->proc,(int *)arg);
+ if(err)
+ return err;
+ return(0);
+ case SIOCGSTAMP:
+ if(sk->stamp.tv_sec==0)
+ return -ENOENT;
+ err = copy_to_user((void *)arg, &sk->stamp,
+ sizeof(struct timeval));
+ if (err)
+ return -EFAULT;
+ return 0;
+
+ case SIOCADDRT:
+ case SIOCDELRT:
+
+ return(ipv6_route_ioctl(cmd,(void *)arg));
+
+ case SIOCSIFADDR:
+ return addrconf_add_ifaddr((void *) arg);
+ case SIOCDIFADDR:
+ return addrconf_del_ifaddr((void *) arg);
+ case SIOCSIFDSTADDR:
+ return addrconf_set_dstaddr((void *) arg);
+ default:
+ if ((cmd >= SIOCDEVPRIVATE) &&
+ (cmd <= (SIOCDEVPRIVATE + 15)))
+ return(dev_ioctl(cmd,(void *) arg));
+
+ if(sk->prot->ioctl==0 || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD)
+ return(dev_ioctl(cmd,(void *) arg));
+ return err;
+ }
+ /*NOTREACHED*/
+ return(0);
+}
+
+#endif /* not _HURD_ */
+
+struct proto_ops inet6_stream_ops = {
+ PF_INET6,
+
+ sock_no_dup,
+ inet6_release,
+ inet6_bind,
+ inet_stream_connect, /* ok */
+ sock_no_socketpair, /* a do nothing */
+ inet_accept, /* ok */
+ inet6_getname,
+ inet_poll, /* ok */
+ inet6_ioctl, /* must change */
+ inet_listen, /* ok */
+ inet_shutdown, /* ok */
+ inet_setsockopt, /* ok */
+ inet_getsockopt, /* ok */
+ sock_no_fcntl, /* ok */
+ inet_sendmsg, /* ok */
+ inet_recvmsg /* ok */
+};
+
+struct proto_ops inet6_dgram_ops = {
+ PF_INET6,
+
+ sock_no_dup,
+ inet6_release,
+ inet6_bind,
+ inet_dgram_connect, /* ok */
+ sock_no_socketpair, /* a do nothing */
+ inet_accept, /* ok */
+ inet6_getname,
+ datagram_poll, /* ok */
+ inet6_ioctl, /* must change */
+ sock_no_listen, /* ok */
+ inet_shutdown, /* ok */
+ inet_setsockopt, /* ok */
+ inet_getsockopt, /* ok */
+ sock_no_fcntl, /* ok */
+ inet_sendmsg, /* ok */
+ inet_recvmsg /* ok */
+};
+
+struct net_proto_family inet6_family_ops = {
+ PF_INET6,
+ inet6_create
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_raw6 = {
+ PROC_NET_RAW6, 4, "raw6",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ raw6_get_info
+};
+static struct proc_dir_entry proc_net_tcp6 = {
+ PROC_NET_TCP6, 4, "tcp6",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ tcp6_get_info
+};
+static struct proc_dir_entry proc_net_udp6 = {
+ PROC_NET_RAW6, 4, "udp6",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ udp6_get_info
+};
+static struct proc_dir_entry proc_net_sockstat6 = {
+ PROC_NET_SOCKSTAT6, 9, "sockstat6",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ afinet6_get_info
+};
+static struct proc_dir_entry proc_net_snmp6 = {
+ PROC_NET_SNMP6, 5, "snmp6",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ afinet6_get_snmp
+};
+#endif /* CONFIG_PROC_FS */
+
+#ifdef MODULE
+int ipv6_unload(void)
+{
+ if (!unloadable) return 1;
+ /* We keep internally 3 raw sockets */
+ return atomic_read(&(__this_module.uc.usecount)) - 3;
+}
+#endif
+
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+extern void ipv6_sysctl_register(void);
+extern void ipv6_sysctl_unregister(void);
+#endif
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(void inet6_proto_init(struct net_proto *pro))
+#endif
+{
+ struct sk_buff *dummy_skb;
+ int err;
+
+#ifdef MODULE
+ if (!mod_member_present(&__this_module, can_unload))
+ return -EINVAL;
+
+ __this_module.can_unload = &ipv6_unload;
+#endif
+
+ printk(KERN_INFO "IPv6 v0.8 for NET4.0\n");
+
+ if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb))
+ {
+ printk(KERN_CRIT "inet6_proto_init: size fault\n");
+#ifdef MODULE
+ return -EINVAL;
+#else
+ return;
+#endif
+ }
+
+ /*
+ * ipngwg API draft makes clear that the correct semantics
+ * for TCP and UDP is to consider one TCP and UDP instance
+ * in a host available by both INET and INET6 APIs and
+ * able to communicate via both network protocols.
+ */
+
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+ ipv6_sysctl_register();
+#endif
+ err = icmpv6_init(&inet6_family_ops);
+ if (err)
+ goto icmp_fail;
+ err = ndisc_init(&inet6_family_ops);
+ if (err)
+ goto ndisc_fail;
+ err = igmp6_init(&inet6_family_ops);
+ if (err)
+ goto igmp_fail;
+ ipv6_netdev_notif_init();
+ ipv6_packet_init();
+ ip6_route_init();
+ ip6_flowlabel_init();
+ addrconf_init();
+#ifndef _HURD_
+ sit_init();
+#endif
+
+ /* Init v6 transport protocols. */
+ udpv6_init();
+ tcpv6_init();
+
+ /* Create /proc/foo6 entries. */
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_net_raw6);
+ proc_net_register(&proc_net_tcp6);
+ proc_net_register(&proc_net_udp6);
+ proc_net_register(&proc_net_sockstat6);
+ proc_net_register(&proc_net_snmp6);
+#endif
+
+ /* Now the userspace is allowed to create INET6 sockets. */
+ (void) sock_register(&inet6_family_ops);
+
+#ifdef MODULE
+ return 0;
+#else
+ return;
+#endif
+
+igmp_fail:
+ ndisc_cleanup();
+ndisc_fail:
+ icmpv6_cleanup();
+icmp_fail:
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+ ipv6_sysctl_unregister();
+#endif
+#ifdef MODULE
+ return err;
+#else
+ return;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ /* First of all disallow new sockets creation. */
+ sock_unregister(PF_INET6);
+#ifdef CONFIG_PROC_FS
+ proc_net_unregister(proc_net_raw6.low_ino);
+ proc_net_unregister(proc_net_tcp6.low_ino);
+ proc_net_unregister(proc_net_udp6.low_ino);
+ proc_net_unregister(proc_net_sockstat6.low_ino);
+ proc_net_unregister(proc_net_snmp6.low_ino);
+#endif
+ /* Cleanup code parts. */
+ sit_cleanup();
+ ipv6_netdev_notif_cleanup();
+ ip6_flowlabel_cleanup();
+ addrconf_cleanup();
+ ip6_route_cleanup();
+ ipv6_packet_cleanup();
+ igmp6_cleanup();
+ ndisc_cleanup();
+ icmpv6_cleanup();
+#ifdef CONFIG_SYSCTL
+ ipv6_sysctl_unregister();
+#endif
+}
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv6/datagram_ipv6.c b/pfinet/linux-src/net/ipv6/datagram_ipv6.c
new file mode 100644
index 00000000..1ed33de8
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/datagram_ipv6.c
@@ -0,0 +1,434 @@
+/*
+ * common UDP/RAW code
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: datagram_ipv6.c,v 1.2 2007/10/13 01:43:00 stesie Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <linux/route.h>
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <net/transp_v6.h>
+
+#include <linux/errqueue.h>
+#include <asm/uaccess.h>
+
+void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
+ u16 port, u32 info, u8 *payload)
+{
+ struct icmp6hdr *icmph = (struct icmp6hdr *)skb->h.raw;
+ struct sock_exterr_skb *serr;
+
+ if (!sk->net_pinfo.af_inet6.recverr)
+ return;
+
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ serr = SKB_EXT_ERR(skb);
+ serr->ee.ee_errno = err;
+ serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6;
+ serr->ee.ee_type = icmph->icmp6_type;
+ serr->ee.ee_code = icmph->icmp6_code;
+ serr->ee.ee_pad = 0;
+ serr->ee.ee_info = info;
+ serr->ee.ee_data = 0;
+ serr->addr_offset = (u8*)&(((struct ipv6hdr*)(icmph+1))->daddr) - skb->nh.raw;
+ serr->port = port;
+
+ skb->h.raw = payload;
+ skb_pull(skb, payload - skb->data);
+
+ if (sock_queue_err_skb(sk, skb))
+ kfree_skb(skb);
+}
+
+void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
+{
+ struct sock_exterr_skb *serr;
+ struct ipv6hdr *iph;
+ struct sk_buff *skb;
+
+ if (!sk->net_pinfo.af_inet6.recverr)
+ return;
+
+ skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ iph = (struct ipv6hdr*)skb_put(skb, sizeof(struct ipv6hdr));
+ skb->nh.ipv6h = iph;
+ memcpy(&iph->daddr, fl->fl6_dst, 16);
+
+ serr = SKB_EXT_ERR(skb);
+ serr->ee.ee_errno = err;
+ serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
+ serr->ee.ee_type = 0;
+ serr->ee.ee_code = 0;
+ serr->ee.ee_pad = 0;
+ serr->ee.ee_info = info;
+ serr->ee.ee_data = 0;
+ serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
+ serr->port = fl->uli_u.ports.dport;
+
+ skb->h.raw = skb->tail;
+ skb_pull(skb, skb->tail - skb->data);
+
+ if (sock_queue_err_skb(sk, skb))
+ kfree_skb(skb);
+}
+
+/*
+ * Handle MSG_ERRQUEUE
+ */
+int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct sock_exterr_skb *serr;
+ struct sk_buff *skb, *skb2;
+ struct sockaddr_in6 *sin;
+ struct {
+ struct sock_extended_err ee;
+ struct sockaddr_in6 offender;
+ } errhdr;
+ int err;
+ int copied;
+
+ err = -EAGAIN;
+ skb = skb_dequeue(&sk->error_queue);
+ if (skb == NULL)
+ goto out;
+
+ copied = skb->len;
+ if (copied > len) {
+ msg->msg_flags |= MSG_TRUNC;
+ copied = len;
+ }
+ err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+ if (err)
+ goto out_free_skb;
+
+ serr = SKB_EXT_ERR(skb);
+
+ sin = (struct sockaddr_in6 *)msg->msg_name;
+ if (sin) {
+ sin->sin6_family = AF_INET6;
+ sin->sin6_flowinfo = 0;
+ sin->sin6_port = serr->port;
+ sin->sin6_scope_id = 0;
+ if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
+ memcpy(&sin->sin6_addr, skb->nh.raw + serr->addr_offset, 16);
+ if (sk->net_pinfo.af_inet6.sndflow)
+ sin->sin6_flowinfo = *(u32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
+ if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin->sin6_scope_id =
+ ((struct inet6_skb_parm *) skb->cb)->iif;
+ } else
+ ipv6_addr_set(&sin->sin6_addr, 0, 0,
+ __constant_htonl(0xffff),
+ *(u32*)(skb->nh.raw + serr->addr_offset));
+ }
+
+ memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
+ sin = &errhdr.offender;
+ sin->sin6_family = AF_UNSPEC;
+ if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
+ sin->sin6_family = AF_INET6;
+ sin->sin6_flowinfo = 0;
+ sin->sin6_scope_id = 0;
+ if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
+ memcpy(&sin->sin6_addr, &skb->nh.ipv6h->saddr, 16);
+ if (sk->net_pinfo.af_inet6.rxopt.all)
+ datagram_recv_ctl(sk, msg, skb);
+ if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin->sin6_scope_id =
+ ((struct inet6_skb_parm *) skb->cb)->iif;
+ } else {
+ ipv6_addr_set(&sin->sin6_addr, 0, 0,
+ __constant_htonl(0xffff),
+ skb->nh.iph->saddr);
+ if (sk->ip_cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+ }
+ }
+
+ put_cmsg(msg, SOL_IPV6, IPV6_RECVERR, sizeof(errhdr), &errhdr);
+
+ /* Now we could try to dump offended packet options */
+
+ msg->msg_flags |= MSG_ERRQUEUE;
+ err = copied;
+
+ /* Reset and regenerate socket error */
+ sk->err = 0;
+ if ((skb2 = skb_peek(&sk->error_queue)) != NULL) {
+ sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+ sk->error_report(sk);
+ }
+
+out_free_skb:
+ kfree_skb(skb);
+out:
+ return err;
+}
+
+
+
+int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+
+ if (np->rxopt.bits.rxinfo) {
+ struct in6_pktinfo src_info;
+
+ src_info.ipi6_ifindex = opt->iif;
+ ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr);
+ put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
+ }
+
+ if (np->rxopt.bits.rxhlim) {
+ int hlim = skb->nh.ipv6h->hop_limit;
+ put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
+ }
+
+ if (np->rxopt.bits.rxflow && (*(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
+ u32 flowinfo = *(u32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
+ put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
+ }
+ if (np->rxopt.bits.hopopts && opt->hop) {
+ u8 *ptr = skb->nh.raw + opt->hop;
+ put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
+ }
+ if (np->rxopt.bits.dstopts && opt->dst0) {
+ u8 *ptr = skb->nh.raw + opt->dst0;
+ put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr);
+ }
+ if (np->rxopt.bits.srcrt && opt->srcrt) {
+ struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(skb->nh.raw + opt->srcrt);
+ put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, (rthdr->hdrlen+1) << 3, rthdr);
+ }
+ if (np->rxopt.bits.authhdr && opt->auth) {
+ u8 *ptr = skb->nh.raw + opt->auth;
+ put_cmsg(msg, SOL_IPV6, IPV6_AUTHHDR, (ptr[1]+1)<<2, ptr);
+ }
+ if (np->rxopt.bits.dstopts && opt->dst1) {
+ u8 *ptr = skb->nh.raw + opt->dst1;
+ put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, (ptr[1]+1)<<3, ptr);
+ }
+ return 0;
+}
+
+int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
+ struct ipv6_txoptions *opt,
+ int *hlimit)
+{
+ struct in6_pktinfo *src_info;
+ struct cmsghdr *cmsg;
+ struct ipv6_rt_hdr *rthdr;
+ struct ipv6_opt_hdr *hdr;
+ int len;
+ int err = 0;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+
+ if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
+ (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
+ + cmsg->cmsg_len) > msg->msg_controllen) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ if (cmsg->cmsg_level != SOL_IPV6)
+ continue;
+
+ switch (cmsg->cmsg_type) {
+ case IPV6_PKTINFO:
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+
+ if (src_info->ipi6_ifindex) {
+ if (fl->oif && src_info->ipi6_ifindex != fl->oif)
+ return -EINVAL;
+ fl->oif = src_info->ipi6_ifindex;
+ }
+
+ if (!ipv6_addr_any(&src_info->ipi6_addr)) {
+ struct inet6_ifaddr *ifp;
+
+ ifp = ipv6_chk_addr(&src_info->ipi6_addr, NULL, 0);
+
+ if (ifp == NULL) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ fl->fl6_src = &src_info->ipi6_addr;
+ }
+
+ break;
+
+ case IPV6_FLOWINFO:
+ if (cmsg->cmsg_len < CMSG_LEN(4)) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) {
+ if ((fl->fl6_flowlabel^*(u32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+ }
+ fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(u32 *)CMSG_DATA(cmsg);
+ break;
+
+ case IPV6_HOPOPTS:
+ if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);
+ len = ((hdr->hdrlen + 1) << 3);
+ if (cmsg->cmsg_len < CMSG_LEN(len)) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+ if (!capable(CAP_NET_RAW)) {
+ err = -EPERM;
+ goto exit_f;
+ }
+ opt->opt_nflen += len;
+ opt->hopopt = hdr;
+ break;
+
+ case IPV6_DSTOPTS:
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);
+ len = ((hdr->hdrlen + 1) << 3);
+ if (cmsg->cmsg_len < CMSG_LEN(len)) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+ if (!capable(CAP_NET_RAW)) {
+ err = -EPERM;
+ goto exit_f;
+ }
+ if (opt->dst1opt) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+ opt->opt_flen += len;
+ opt->dst1opt = hdr;
+ break;
+
+ case IPV6_AUTHHDR:
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);
+ len = ((hdr->hdrlen + 2) << 2);
+ if (cmsg->cmsg_len < CMSG_LEN(len)) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+ if (len & ~7) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+ opt->opt_flen += len;
+ opt->auth = hdr;
+ break;
+
+ case IPV6_RTHDR:
+ if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);
+
+ /*
+ * TYPE 0
+ */
+ if (rthdr->type) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ len = ((rthdr->hdrlen + 1) << 3);
+
+ if (cmsg->cmsg_len < CMSG_LEN(len)) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ /* segments left must also match */
+ if ((rthdr->hdrlen >> 1) != rthdr->segments_left) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ opt->opt_nflen += len;
+ opt->srcrt = rthdr;
+
+ if (opt->dst1opt) {
+ int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);
+
+ opt->opt_nflen += dsthdrlen;
+ opt->dst0opt = opt->dst1opt;
+ opt->dst1opt = NULL;
+ opt->opt_flen -= dsthdrlen;
+ }
+
+ break;
+
+ case IPV6_HOPLIMIT:
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
+ *hlimit = *(int *)CMSG_DATA(cmsg);
+ break;
+
+ default:
+ printk(KERN_DEBUG "invalid cmsg type: %d\n", cmsg->cmsg_type);
+ err = -EINVAL;
+ break;
+ };
+ }
+
+exit_f:
+ return err;
+}
diff --git a/pfinet/linux-src/net/ipv6/exthdrs.c b/pfinet/linux-src/net/ipv6/exthdrs.c
new file mode 100644
index 00000000..a3d3dfe7
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/exthdrs.c
@@ -0,0 +1,771 @@
+/*
+ * Extension Header handling for IPv6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Andi Kleen <ak@muc.de>
+ * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ *
+ * $Id: exthdrs.c,v 1.1 2007/10/08 21:12:30 stesie Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+#include <asm/uaccess.h>
+
+/*
+ * Parsing inbound headers.
+ *
+ * Parsing function "func" returns pointer to the place,
+ * where next nexthdr value is stored or NULL, if parsing
+ * failed. It should also update skb->h.
+ */
+
+struct hdrtype_proc
+{
+ int type;
+ u8* (*func) (struct sk_buff **, u8 *ptr);
+};
+
+/*
+ * Parsing tlv encoded headers.
+ *
+ * Parsing function "func" returns 1, if parsing succeed
+ * and 0, if it failed.
+ * It MUST NOT touch skb->h.
+ */
+
+struct tlvtype_proc
+{
+ int type;
+ int (*func) (struct sk_buff *, __u8 *ptr);
+};
+
+/*********************
+ Generic functions
+ *********************/
+
+/* An unknown option is detected, decide what to do */
+
+int ip6_tlvopt_unknown(struct sk_buff *skb, u8 *opt)
+{
+ switch ((opt[0] & 0xC0) >> 6) {
+ case 0: /* ignore */
+ return 1;
+
+ case 1: /* drop packet */
+ break;
+
+ case 3: /* Send ICMP if not a multicast address and drop packet */
+ /* Actually, it is redundant check. icmp_send
+ will recheck in any case.
+ */
+ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
+ break;
+ case 2: /* send ICMP PARM PROB regardless and drop packet */
+ icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, opt);
+ return 0;
+ };
+
+ kfree_skb(skb);
+ return 0;
+}
+
+/* Parse tlv encoded option header (hop-by-hop or destination) */
+
+static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
+ __u8 *nhptr)
+{
+ struct tlvtype_proc *curr;
+ u8 *ptr = skb->h.raw;
+ int len = ((ptr[1]+1)<<3) - 2;
+
+ ptr += 2;
+
+ if (skb->tail - (ptr + len) < 0) {
+ kfree_skb(skb);
+ return 0;
+ }
+
+ while (len > 0) {
+ int optlen = ptr[1]+2;
+
+ switch (ptr[0]) {
+ case IPV6_TLV_PAD0:
+ optlen = 1;
+ break;
+
+ case IPV6_TLV_PADN:
+ break;
+
+ default: /* Other TLV code so scan list */
+ for (curr=procs; curr->type >= 0; curr++) {
+ if (curr->type == ptr[0]) {
+ if (curr->func(skb, ptr) == 0)
+ return 0;
+ break;
+ }
+ }
+ if (curr->type < 0) {
+ if (ip6_tlvopt_unknown(skb, ptr) == 0)
+ return 0;
+ }
+ break;
+ }
+ ptr += optlen;
+ len -= optlen;
+ }
+ if (len == 0)
+ return 1;
+ kfree_skb(skb);
+ return 0;
+}
+
+/*****************************
+ Destination options header.
+ *****************************/
+
+struct tlvtype_proc tlvprocdestopt_lst[] = {
+ /* No destination options are defined now */
+ {-1, NULL}
+};
+
+static u8 *ipv6_dest_opt(struct sk_buff **skb_ptr, u8 *nhptr)
+{
+ struct sk_buff *skb=*skb_ptr;
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+ struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
+
+ opt->dst1 = (u8*)hdr - skb->nh.raw;
+
+ if (ip6_parse_tlv(tlvprocdestopt_lst, skb, nhptr)) {
+ skb->h.raw += ((hdr->hdrlen+1)<<3);
+ return &hdr->nexthdr;
+ }
+
+ return NULL;
+}
+
+/********************************
+ NONE header. No data in packet.
+ ********************************/
+
+static u8 *ipv6_nodata(struct sk_buff **skb_ptr, u8 *nhptr)
+{
+ kfree_skb(*skb_ptr);
+ return NULL;
+}
+
+/********************************
+ Routing header.
+ ********************************/
+
+static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr)
+{
+ struct sk_buff *skb = *skb_ptr;
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+ struct in6_addr *addr;
+ struct in6_addr daddr;
+ int addr_type;
+ int n, i;
+
+ struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw;
+ struct rt0_hdr *rthdr;
+
+ if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) {
+ ipv6_statistics.Ip6InHdrErrors++;
+ kfree_skb(skb);
+ return NULL;
+ }
+
+looped_back:
+ if (hdr->segments_left == 0) {
+ opt->srcrt = (u8*)hdr - skb->nh.raw;
+ skb->h.raw += (hdr->hdrlen + 1) << 3;
+ opt->dst0 = opt->dst1;
+ opt->dst1 = 0;
+ return &hdr->nexthdr;
+ }
+
+ if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01) {
+ u8 *pos = (u8*) hdr;
+
+ if (hdr->type != IPV6_SRCRT_TYPE_0)
+ pos += 2;
+ else
+ pos += 1;
+
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, pos);
+ return NULL;
+ }
+
+ /*
+ * This is the routing header forwarding algorithm from
+ * RFC 1883, page 17.
+ */
+
+ n = hdr->hdrlen >> 1;
+
+ if (hdr->segments_left > n) {
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, &hdr->segments_left);
+ return NULL;
+ }
+
+ /* We are about to mangle packet header. Be careful!
+ Do not damage packets queued somewhere.
+ */
+ if (skb_cloned(skb)) {
+ struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
+ kfree_skb(skb);
+ if (skb2 == NULL)
+ return NULL;
+ *skb_ptr = skb = skb2;
+ opt = (struct inet6_skb_parm *)skb2->cb;
+ hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
+ }
+
+ i = n - --hdr->segments_left;
+
+ rthdr = (struct rt0_hdr *) hdr;
+ addr = rthdr->addr;
+ addr += i - 1;
+
+ addr_type = ipv6_addr_type(addr);
+
+ if (addr_type == IPV6_ADDR_MULTICAST) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ ipv6_addr_copy(&daddr, addr);
+ ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
+ ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
+
+ dst_release(xchg(&skb->dst, NULL));
+ ip6_route_input(skb);
+ if (skb->dst->error) {
+ skb->dst->input(skb);
+ return NULL;
+ }
+ if (skb->dst->dev->flags&IFF_LOOPBACK) {
+ if (skb->nh.ipv6h->hop_limit <= 1) {
+ icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
+ 0, skb->dev);
+ kfree_skb(skb);
+ return NULL;
+ }
+ skb->nh.ipv6h->hop_limit--;
+ goto looped_back;
+ }
+
+ skb->dst->input(skb);
+ return NULL;
+}
+
+/*
+ This function inverts received rthdr.
+ NOTE: specs allow to make it automatically only if
+ packet authenticated.
+
+ I will not discuss it here (though, I am really pissed off at
+ this stupid requirement making rthdr idea useless)
+
+ Actually, it creates severe problems for us.
+ Embrionic requests has no associated sockets,
+ so that user have no control over it and
+ cannot not only to set reply options, but
+ even to know, that someone wants to connect
+ without success. :-(
+
+ For now we need to test the engine, so that I created
+ temporary (or permanent) backdoor.
+ If listening socket set IPV6_RTHDR to 2, then we invert header.
+ --ANK (980729)
+ */
+
+struct ipv6_txoptions *
+ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
+{
+ /* Received rthdr:
+
+ [ H1 -> H2 -> ... H_prev ] daddr=ME
+
+ Inverted result:
+ [ H_prev -> ... -> H1 ] daddr =sender
+
+ Note, that IP output engine will rewrire this rthdr
+ by rotating it left by one addr.
+ */
+
+ int n, i;
+ struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
+ struct rt0_hdr *irthdr;
+ struct ipv6_txoptions *opt;
+ int hdrlen = ipv6_optlen(hdr);
+
+ if (hdr->segments_left ||
+ hdr->type != IPV6_SRCRT_TYPE_0 ||
+ hdr->hdrlen & 0x01)
+ return NULL;
+
+ n = hdr->hdrlen >> 1;
+ opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
+ if (opt == NULL)
+ return NULL;
+ memset(opt, 0, sizeof(*opt));
+ opt->tot_len = sizeof(*opt) + hdrlen;
+ opt->srcrt = (void*)(opt+1);
+ opt->opt_nflen = hdrlen;
+
+ memcpy(opt->srcrt, hdr, sizeof(*hdr));
+ irthdr = (struct rt0_hdr*)opt->srcrt;
+ /* Obsolete field, MBZ, when originated by us */
+ irthdr->bitmap = 0;
+ opt->srcrt->segments_left = n;
+ for (i=0; i<n; i++)
+ memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
+ return opt;
+}
+
+/********************************
+ AUTH header.
+ ********************************/
+
+/*
+ rfc1826 said, that if a host does not implement AUTH header
+ it MAY ignore it. We use this hole 8)
+
+ Actually, now we can implement OSPFv6 without kernel IPsec.
+ Authentication for poors may be done in user space with the same success.
+
+ Yes, it means, that we allow application to send/receive
+ raw authentication header. Apparently, we suppose, that it knows
+ what it does and calculates authentication data correctly.
+ Certainly, it is possible only for udp and raw sockets, but not for tcp.
+
+ AUTH header has 4byte granular length, which kills all the idea
+ behind AUTOMATIC 64bit alignment of IPv6. Now we will loose
+ cpu ticks, checking that sender did not something stupid
+ and opt->hdrlen is even. Shit! --ANK (980730)
+ */
+
+static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr)
+{
+ struct sk_buff *skb=*skb_ptr;
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+ struct ipv6_opt_hdr *hdr = (struct ipv6_opt_hdr *)skb->h.raw;
+ int len = (hdr->hdrlen+2)<<2;
+
+ if (len&7)
+ return NULL;
+ opt->auth = (u8*)hdr - skb->nh.raw;
+ if (skb->h.raw + len > skb->tail)
+ return NULL;
+ skb->h.raw += len;
+ return &hdr->nexthdr;
+}
+
+/* This list MUST NOT contain entry for NEXTHDR_HOP.
+ It is parsed immediately after packet received
+ and if it occurs somewhere in another place we must
+ generate error.
+ */
+
+struct hdrtype_proc hdrproc_lst[] = {
+ {NEXTHDR_FRAGMENT, ipv6_reassembly},
+ {NEXTHDR_ROUTING, ipv6_routing_header},
+ {NEXTHDR_DEST, ipv6_dest_opt},
+ {NEXTHDR_NONE, ipv6_nodata},
+ {NEXTHDR_AUTH, ipv6_auth_hdr},
+ /*
+ {NEXTHDR_ESP, ipv6_esp_hdr},
+ */
+ {-1, NULL}
+};
+
+u8 *ipv6_parse_exthdrs(struct sk_buff **skb_in, u8 *nhptr)
+{
+ struct hdrtype_proc *hdrt;
+ u8 nexthdr = *nhptr;
+
+restart:
+ for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
+ if (hdrt->type == nexthdr) {
+ if ((nhptr = hdrt->func(skb_in, nhptr)) != NULL) {
+ nexthdr = *nhptr;
+ goto restart;
+ }
+ return NULL;
+ }
+ }
+ return nhptr;
+}
+
+
+/**********************************
+ Hop-by-hop options.
+ **********************************/
+
+/* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
+
+static int ipv6_hop_ra(struct sk_buff *skb, u8 *ptr)
+{
+ if (ptr[1] == 2) {
+ ((struct inet6_skb_parm*)skb->cb)->ra = ptr - skb->nh.raw;
+ return 1;
+ }
+ if (net_ratelimit())
+ printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", ptr[1]);
+ kfree_skb(skb);
+ return 0;
+}
+
+/* Jumbo payload */
+
+static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr)
+{
+ u32 pkt_len;
+
+ if (ptr[1] != 4 || ((ptr-skb->nh.raw)&3) != 2) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", ptr[1]);
+ goto drop;
+ }
+
+ pkt_len = ntohl(*(u32*)(ptr+2));
+ if (pkt_len < 0x10000) {
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr+2);
+ return 0;
+ }
+ if (skb->nh.ipv6h->payload_len) {
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr);
+ return 0;
+ }
+
+ if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
+ ipv6_statistics.Ip6InTruncatedPkts++;
+ goto drop;
+ }
+ skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+ return 1;
+
+drop:
+ kfree_skb(skb);
+ return 0;
+}
+
+struct tlvtype_proc tlvprochopopt_lst[] = {
+ {IPV6_TLV_ROUTERALERT, ipv6_hop_ra},
+ {IPV6_TLV_JUMBO, ipv6_hop_jumbo},
+ {-1, NULL}
+};
+
+u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr)
+{
+ ((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr);
+ if (ip6_parse_tlv(tlvprochopopt_lst, skb, nhptr))
+ return nhptr+((nhptr[1]+1)<<3);
+ return NULL;
+}
+
+/*
+ * Creating outbound headers.
+ *
+ * "build" functions work when skb is filled from head to tail (datagram)
+ * "push" functions work when headers are added from tail to head (tcp)
+ *
+ * In both cases we assume, that caller reserved enough room
+ * for headers.
+ */
+
+u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
+ struct ipv6_rt_hdr *opt, struct in6_addr *addr)
+{
+ struct rt0_hdr *phdr, *ihdr;
+ int hops;
+
+ ihdr = (struct rt0_hdr *) opt;
+
+ phdr = (struct rt0_hdr *) skb_put(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
+ memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
+
+ hops = ihdr->rt_hdr.hdrlen >> 1;
+
+ if (hops > 1)
+ memcpy(phdr->addr, ihdr->addr + 1,
+ (hops - 1) * sizeof(struct in6_addr));
+
+ ipv6_addr_copy(phdr->addr + (hops - 1), addr);
+
+ phdr->rt_hdr.nexthdr = *prev_hdr;
+ *prev_hdr = NEXTHDR_ROUTING;
+ return &phdr->rt_hdr.nexthdr;
+}
+
+static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
+{
+ struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
+
+ memcpy(h, opt, ipv6_optlen(opt));
+ h->nexthdr = *prev_hdr;
+ *prev_hdr = type;
+ return &h->nexthdr;
+}
+
+static u8 *ipv6_build_authhdr(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_opt_hdr *opt)
+{
+ struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, (opt->hdrlen+2)<<2);
+
+ memcpy(h, opt, (opt->hdrlen+2)<<2);
+ h->nexthdr = *prev_hdr;
+ *prev_hdr = NEXTHDR_AUTH;
+ return &h->nexthdr;
+}
+
+
+u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
+ struct in6_addr *daddr, u32 jumbolen)
+{
+ struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
+
+ if (opt && opt->hopopt)
+ prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
+
+ if (jumbolen) {
+ u8 *jumboopt = (u8 *)skb_put(skb, 8);
+
+ if (opt && opt->hopopt) {
+ *jumboopt++ = IPV6_TLV_PADN;
+ *jumboopt++ = 0;
+ h->hdrlen++;
+ } else {
+ h = (struct ipv6_opt_hdr *)jumboopt;
+ h->nexthdr = *prev_hdr;
+ h->hdrlen = 0;
+ jumboopt += 2;
+ *prev_hdr = NEXTHDR_HOP;
+ prev_hdr = &h->nexthdr;
+ }
+ jumboopt[0] = IPV6_TLV_JUMBO;
+ jumboopt[1] = 4;
+ *(u32*)(jumboopt+2) = htonl(jumbolen);
+ }
+ if (opt) {
+ if (opt->dst0opt)
+ prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
+ if (opt->srcrt)
+ prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
+ }
+ return prev_hdr;
+}
+
+u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
+{
+ if (opt->auth)
+ prev_hdr = ipv6_build_authhdr(skb, prev_hdr, opt->auth);
+ if (opt->dst1opt)
+ prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt);
+ return prev_hdr;
+}
+
+static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
+ struct ipv6_rt_hdr *opt,
+ struct in6_addr **addr_p)
+{
+ struct rt0_hdr *phdr, *ihdr;
+ int hops;
+
+ ihdr = (struct rt0_hdr *) opt;
+
+ phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
+ memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
+
+ hops = ihdr->rt_hdr.hdrlen >> 1;
+
+ if (hops > 1)
+ memcpy(phdr->addr, ihdr->addr + 1,
+ (hops - 1) * sizeof(struct in6_addr));
+
+ ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
+ *addr_p = ihdr->addr;
+
+ phdr->rt_hdr.nexthdr = *proto;
+ *proto = NEXTHDR_ROUTING;
+}
+
+static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
+{
+ struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
+
+ memcpy(h, opt, ipv6_optlen(opt));
+ h->nexthdr = *proto;
+ *proto = type;
+}
+
+static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr *opt)
+{
+ struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, (opt->hdrlen+2)<<2);
+
+ memcpy(h, opt, (opt->hdrlen+2)<<2);
+ h->nexthdr = *proto;
+ *proto = NEXTHDR_AUTH;
+}
+
+void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
+ u8 *proto,
+ struct in6_addr **daddr)
+{
+ if (opt->srcrt)
+ ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
+ if (opt->dst0opt)
+ ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
+ if (opt->hopopt)
+ ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
+}
+
+void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
+{
+ if (opt->dst1opt)
+ ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
+ if (opt->auth)
+ ipv6_push_authhdr(skb, proto, opt->auth);
+}
+
+struct ipv6_txoptions *
+ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
+{
+ struct ipv6_txoptions *opt2;
+
+ opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
+ if (opt2) {
+ long dif = (char*)opt2 - (char*)opt;
+ memcpy(opt2, opt, opt->tot_len);
+ if (opt2->hopopt)
+ *((char**)&opt2->hopopt) += dif;
+ if (opt2->dst0opt)
+ *((char**)&opt2->dst0opt) += dif;
+ if (opt2->dst1opt)
+ *((char**)&opt2->dst1opt) += dif;
+ if (opt2->auth)
+ *((char**)&opt2->auth) += dif;
+ if (opt2->srcrt)
+ *((char**)&opt2->srcrt) += dif;
+ }
+ return opt2;
+}
+
+
+/*
+ * find out if nexthdr is a well-known extension header or a protocol
+ */
+
+static __inline__ int ipv6_ext_hdr(u8 nexthdr)
+{
+ /*
+ * find out if nexthdr is an extension header or a protocol
+ */
+ return ( (nexthdr == NEXTHDR_HOP) ||
+ (nexthdr == NEXTHDR_ROUTING) ||
+ (nexthdr == NEXTHDR_FRAGMENT) ||
+ (nexthdr == NEXTHDR_AUTH) ||
+ (nexthdr == NEXTHDR_NONE) ||
+ (nexthdr == NEXTHDR_DEST) );
+}
+
+/*
+ * Skip any extension headers. This is used by the ICMP module.
+ *
+ * Note that strictly speaking this conflicts with RFC1883 4.0:
+ * ...The contents and semantics of each extension header determine whether
+ * or not to proceed to the next header. Therefore, extension headers must
+ * be processed strictly in the order they appear in the packet; a
+ * receiver must not, for example, scan through a packet looking for a
+ * particular kind of extension header and process that header prior to
+ * processing all preceding ones.
+ *
+ * We do exactly this. This is a protocol bug. We can't decide after a
+ * seeing an unknown discard-with-error flavour TLV option if it's a
+ * ICMP error message or not (errors should never be send in reply to
+ * ICMP error messages).
+ *
+ * But I see no other way to do this. This might need to be reexamined
+ * when Linux implements ESP (and maybe AUTH) headers.
+ * --AK
+ *
+ * This function parses (probably truncated) exthdr set "hdr"
+ * of length "len". "nexthdrp" initially points to some place,
+ * where type of the first header can be found.
+ *
+ * It skips all well-known exthdrs, and returns pointer to the start
+ * of unparsable area i.e. the first header with unknown type.
+ * If it is not NULL *nexthdr is updated by type/protocol of this header.
+ *
+ * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
+ * - it may return pointer pointing beyond end of packet,
+ * if the last recognized header is truncated in the middle.
+ * - if packet is truncated, so that all parsed headers are skipped,
+ * it returns NULL.
+ * - First fragment header is skipped, not-first ones
+ * are considered as unparsable.
+ * - ESP is unparsable for now and considered like
+ * normal payload protocol.
+ * - Note also special handling of AUTH header. Thanks to IPsec wizards.
+ *
+ * --ANK (980726)
+ */
+
+u8 *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, u8 *nexthdrp, int len)
+{
+ u8 nexthdr = *nexthdrp;
+
+ while (ipv6_ext_hdr(nexthdr)) {
+ int hdrlen;
+
+ if (len < sizeof(struct ipv6_opt_hdr))
+ return NULL;
+ if (nexthdr == NEXTHDR_NONE)
+ return NULL;
+ if (nexthdr == NEXTHDR_FRAGMENT) {
+ struct frag_hdr *fhdr = (struct frag_hdr *) hdr;
+ if (ntohs(fhdr->frag_off) & ~0x7)
+ break;
+ hdrlen = 8;
+ } else if (nexthdr == NEXTHDR_AUTH)
+ hdrlen = (hdr->hdrlen+2)<<2;
+ else
+ hdrlen = ipv6_optlen(hdr);
+
+ nexthdr = hdr->nexthdr;
+ hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen);
+ len -= hdrlen;
+ }
+
+ *nexthdrp = nexthdr;
+ return (u8*)hdr;
+}
+
diff --git a/pfinet/linux-src/net/ipv6/icmpv6.c b/pfinet/linux-src/net/ipv6/icmpv6.c
new file mode 100644
index 00000000..9d701764
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/icmpv6.c
@@ -0,0 +1,676 @@
+/*
+ * Internet Control Message Protocol (ICMPv6)
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: icmpv6.c,v 1.3 2009/02/24 01:21:16 sthibaul Exp $
+ *
+ * Based on net/ipv4/icmp.c
+ *
+ * RFC 1885
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Changes:
+ *
+ * Andi Kleen : exception handling
+ * Andi Kleen add rate limits. never reply to a icmp.
+ * add more length checks and other fixes.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/icmpv6.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+
+#include <net/ipv6.h>
+#include <net/checksum.h>
+#include <net/protocol.h>
+#include <net/raw.h>
+#include <net/rawv6.h>
+#include <net/transp_v6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/icmp.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+struct icmpv6_mib icmpv6_statistics;
+
+/*
+ * ICMP socket for flow control.
+ */
+
+struct socket *icmpv6_socket;
+
+int icmpv6_rcv(struct sk_buff *skb, unsigned long len);
+
+static struct inet6_protocol icmpv6_protocol =
+{
+ icmpv6_rcv, /* handler */
+ NULL, /* error control */
+ NULL, /* next */
+ IPPROTO_ICMPV6, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "ICMPv6" /* name */
+};
+
+struct icmpv6_msg {
+ struct icmp6hdr icmph;
+ __u8 *data;
+ struct in6_addr *daddr;
+ int len;
+ __u32 csum;
+};
+
+
+
+/*
+ * getfrag callback
+ */
+
+static int icmpv6_getfrag(const void *data, struct in6_addr *saddr,
+ char *buff, unsigned int offset, unsigned int len)
+{
+ struct icmpv6_msg *msg = (struct icmpv6_msg *) data;
+ struct icmp6hdr *icmph;
+ __u32 csum;
+
+ /*
+ * in theory offset must be 0 since we never send more
+ * than IPV6_MIN_MTU bytes on an error or more than the path mtu
+ * on an echo reply. (those are the rules on RFC 1883)
+ *
+ * Luckily, this statement is obsolete after
+ * draft-ietf-ipngwg-icmp-v2-00 --ANK (980730)
+ */
+
+ if (offset) {
+ csum = csum_partial_copy((void *) msg->data +
+ offset - sizeof(struct icmp6hdr),
+ buff, len, msg->csum);
+ msg->csum = csum;
+ return 0;
+ }
+
+ csum = csum_partial_copy((void *) &msg->icmph, buff,
+ sizeof(struct icmp6hdr), msg->csum);
+
+ csum = csum_partial_copy((void *) msg->data,
+ buff + sizeof(struct icmp6hdr),
+ len - sizeof(struct icmp6hdr), csum);
+
+ icmph = (struct icmp6hdr *) buff;
+
+ icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
+ IPPROTO_ICMPV6, csum);
+ return 0;
+}
+
+
+/*
+ * Slightly more convenient version of icmpv6_send.
+ */
+void icmpv6_param_prob(struct sk_buff *skb, int code, void *pos)
+{
+ int offset = (u8*)pos - (u8*)skb->nh.ipv6h;
+
+ icmpv6_send(skb, ICMPV6_PARAMPROB, code, offset, skb->dev);
+ kfree_skb(skb);
+}
+
+/*
+ * Figure out, may we reply to this packet with icmp error.
+ *
+ * We do not reply, if:
+ * - it was icmp error message.
+ * - it is truncated, so that it is known, that protocol is ICMPV6
+ * (i.e. in the middle of some exthdr)
+ * - it is not the first fragment. BTW IPv6 specs say nothing about
+ * this case, but it is clear, that our reply would be useless
+ * for sender.
+ *
+ * --ANK (980726)
+ */
+
+static int is_ineligible(struct ipv6hdr *hdr, int len)
+{
+ u8 *ptr;
+ __u8 nexthdr = hdr->nexthdr;
+
+ if (len < (int)sizeof(*hdr))
+ return 1;
+
+ ptr = ipv6_skip_exthdr((struct ipv6_opt_hdr *)(hdr+1), &nexthdr, len - sizeof(*hdr));
+ if (!ptr)
+ return 0;
+ if (nexthdr == IPPROTO_ICMPV6) {
+ struct icmp6hdr *ihdr = (struct icmp6hdr *)ptr;
+ return (ptr - (u8*)hdr) > len || !(ihdr->icmp6_type & 0x80);
+ }
+ return nexthdr == NEXTHDR_FRAGMENT;
+}
+
+int sysctl_icmpv6_time = 1*HZ;
+
+/*
+ * Check the ICMP output rate limit
+ */
+static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
+ struct flowi *fl)
+{
+ struct dst_entry *dst;
+ int res = 0;
+
+ /* Informational messages are not limited. */
+ if (type & 0x80)
+ return 1;
+
+ /* Do not limit pmtu discovery, it would break it. */
+ if (type == ICMPV6_PKT_TOOBIG)
+ return 1;
+
+ /*
+ * Look up the output route.
+ * XXX: perhaps the expire for routing entries cloned by
+ * this lookup should be more aggressive (not longer than timeout).
+ */
+ dst = ip6_route_output(sk, fl);
+ if (dst->error) {
+ ipv6_statistics.Ip6OutNoRoutes++;
+ } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
+ res = 1;
+ } else {
+ struct rt6_info *rt = (struct rt6_info *)dst;
+ int tmo = sysctl_icmpv6_time;
+
+ /* Give more bandwidth to wider prefixes. */
+ if (rt->rt6i_dst.plen < 128)
+ tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
+
+ res = xrlim_allow(dst, tmo);
+ }
+ dst_release(dst);
+ return res;
+}
+
+/*
+ * an inline helper for the "simple" if statement below
+ * checks if parameter problem report is caused by an
+ * unrecognized IPv6 option that has the Option Type
+ * highest-order two bits set to 10
+ */
+
+static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
+{
+ u8 *buff = skb->nh.raw;
+
+ return ( ( *(buff + offset) & 0xC0 ) == 0x80 );
+}
+
+/*
+ * Send an ICMP message in response to a packet in error
+ */
+
+void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
+ struct device *dev)
+{
+ struct ipv6hdr *hdr = skb->nh.ipv6h;
+ struct sock *sk = icmpv6_socket->sk;
+ struct in6_addr *saddr = NULL;
+ int iif = 0;
+ struct icmpv6_msg msg;
+ struct flowi fl;
+ int addr_type = 0;
+ int len;
+
+ /*
+ * sanity check pointer in case of parameter problem
+ */
+
+ if (type == ICMPV6_PARAMPROB &&
+ (info > (skb->tail - ((unsigned char *) hdr)))) {
+ printk(KERN_DEBUG "icmpv6_send: bug! pointer > skb\n");
+ return;
+ }
+
+ /*
+ * Make sure we respect the rules
+ * i.e. RFC 1885 2.4(e)
+ * Rule (e.1) is enforced by not using icmpv6_send
+ * in any code that processes icmp errors.
+ */
+
+ addr_type = ipv6_addr_type(&hdr->daddr);
+
+ if (ipv6_chk_addr(&hdr->daddr, skb->dev, 0))
+ saddr = &hdr->daddr;
+
+ /*
+ * Dest addr check
+ */
+
+ if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {
+ if (type != ICMPV6_PKT_TOOBIG &&
+ !(type == ICMPV6_PARAMPROB &&
+ code == ICMPV6_UNK_OPTION &&
+ (opt_unrec(skb, info))))
+ return;
+
+ saddr = NULL;
+ }
+
+ addr_type = ipv6_addr_type(&hdr->saddr);
+
+ /*
+ * Source addr check
+ */
+
+ if (addr_type & IPV6_ADDR_LINKLOCAL)
+ iif = skb->dev->ifindex;
+
+ /*
+ * Must not send if we know that source is Anycast also.
+ * for now we don't know that.
+ */
+ if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
+ printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");
+ return;
+ }
+
+ /*
+ * Never answer to a ICMP packet.
+ */
+ if (is_ineligible(hdr, (u8*)skb->tail - (u8*)hdr)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "icmpv6_send: no reply to icmp error/fragment\n");
+ return;
+ }
+
+ fl.proto = IPPROTO_ICMPV6;
+ fl.nl_u.ip6_u.daddr = &hdr->saddr;
+ fl.nl_u.ip6_u.saddr = saddr;
+ fl.oif = iif;
+ fl.fl6_flowlabel = 0;
+ fl.uli_u.icmpt.type = type;
+ fl.uli_u.icmpt.code = code;
+
+ if (!icmpv6_xrlim_allow(sk, type, &fl))
+ return;
+
+ /*
+ * ok. kick it. checksum will be provided by the
+ * getfrag_t callback.
+ */
+
+ msg.icmph.icmp6_type = type;
+ msg.icmph.icmp6_code = code;
+ msg.icmph.icmp6_cksum = 0;
+ msg.icmph.icmp6_pointer = htonl(info);
+
+ msg.data = skb->nh.raw;
+ msg.csum = 0;
+ msg.daddr = &hdr->saddr;
+
+ len = min((skb->tail - ((unsigned char *) hdr)) + sizeof(struct icmp6hdr),
+ IPV6_MIN_MTU - sizeof(struct ipv6hdr));
+
+ if (len < 0) {
+ printk(KERN_DEBUG "icmp: len problem\n");
+ return;
+ }
+
+ msg.len = len;
+
+ ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
+ MSG_DONTWAIT);
+ if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
+ (&icmpv6_statistics.Icmp6OutDestUnreachs)[type-1]++;
+ icmpv6_statistics.Icmp6OutMsgs++;
+}
+
+static void icmpv6_echo_reply(struct sk_buff *skb)
+{
+ struct sock *sk = icmpv6_socket->sk;
+ struct ipv6hdr *hdr = skb->nh.ipv6h;
+ struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
+ struct in6_addr *saddr;
+ struct icmpv6_msg msg;
+ struct flowi fl;
+ unsigned char *data;
+ int len;
+
+ data = (char *) (icmph + 1);
+
+ saddr = &hdr->daddr;
+
+ if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST)
+ saddr = NULL;
+
+ len = skb->tail - data;
+ len += sizeof(struct icmp6hdr);
+
+ msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
+ msg.icmph.icmp6_code = 0;
+ msg.icmph.icmp6_cksum = 0;
+ msg.icmph.icmp6_identifier = icmph->icmp6_identifier;
+ msg.icmph.icmp6_sequence = icmph->icmp6_sequence;
+
+ msg.data = data;
+ msg.csum = 0;
+ msg.len = len;
+ msg.daddr = &hdr->saddr;
+
+ fl.proto = IPPROTO_ICMPV6;
+ fl.nl_u.ip6_u.daddr = &hdr->saddr;
+ fl.nl_u.ip6_u.saddr = saddr;
+ fl.oif = skb->dev->ifindex;
+ fl.fl6_flowlabel = 0;
+ fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
+ fl.uli_u.icmpt.code = 0;
+
+ ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
+ MSG_DONTWAIT);
+ icmpv6_statistics.Icmp6OutEchoReplies++;
+ icmpv6_statistics.Icmp6OutMsgs++;
+}
+
+static void icmpv6_notify(struct sk_buff *skb,
+ int type, int code, u32 info, unsigned char *buff, int len)
+{
+ struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+ struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+ struct ipv6hdr *hdr = (struct ipv6hdr *) buff;
+ struct inet6_protocol *ipprot;
+ struct sock *sk;
+ u8 *pb;
+ int hash;
+ u8 nexthdr;
+
+ nexthdr = hdr->nexthdr;
+
+ len -= sizeof(struct ipv6hdr);
+ if (len < 0)
+ return;
+
+ /* now skip over extension headers */
+ pb = ipv6_skip_exthdr((struct ipv6_opt_hdr *) (hdr + 1), &nexthdr, len);
+ if (!pb)
+ return;
+
+ /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
+ Without this we will not able f.e. to make source routed
+ pmtu discovery.
+ Corresponding argument (opt) to notifiers is already added.
+ --ANK (980726)
+ */
+
+ hash = nexthdr & (MAX_INET_PROTOS - 1);
+
+ for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
+ ipprot != NULL;
+ ipprot=(struct inet6_protocol *)ipprot->next) {
+ if (ipprot->protocol != nexthdr)
+ continue;
+
+ if (ipprot->err_handler)
+ ipprot->err_handler(skb, hdr, NULL, type, code, pb, info);
+ }
+
+ sk = raw_v6_htable[hash];
+
+ if (sk == NULL)
+ return;
+
+ while((sk = raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
+ rawv6_err(sk, skb, hdr, NULL, type, code, pb, info);
+ sk = sk->next;
+ }
+}
+
+/*
+ * Handle icmp messages
+ */
+
+int icmpv6_rcv(struct sk_buff *skb, unsigned long len)
+{
+ struct device *dev = skb->dev;
+ struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+ struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+ struct ipv6hdr *orig_hdr;
+ struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw;
+ int ulen;
+ int type;
+
+ icmpv6_statistics.Icmp6InMsgs++;
+
+ if (len < sizeof(struct icmp6hdr))
+ goto discard_it;
+
+ /* Perform checksum. */
+ switch (skb->ip_summed) {
+ case CHECKSUM_NONE:
+ skb->csum = csum_partial((char *)hdr, len, 0);
+ case CHECKSUM_HW:
+ if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6,
+ skb->csum)) {
+ printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+ ntohs(saddr->__in6_u.__u6_addr16[0]),
+ ntohs(saddr->__in6_u.__u6_addr16[1]),
+ ntohs(saddr->__in6_u.__u6_addr16[2]),
+ ntohs(saddr->__in6_u.__u6_addr16[3]),
+ ntohs(saddr->__in6_u.__u6_addr16[4]),
+ ntohs(saddr->__in6_u.__u6_addr16[5]),
+ ntohs(saddr->__in6_u.__u6_addr16[6]),
+ ntohs(saddr->__in6_u.__u6_addr16[7]),
+ ntohs(daddr->__in6_u.__u6_addr16[0]),
+ ntohs(daddr->__in6_u.__u6_addr16[1]),
+ ntohs(daddr->__in6_u.__u6_addr16[2]),
+ ntohs(daddr->__in6_u.__u6_addr16[3]),
+ ntohs(daddr->__in6_u.__u6_addr16[4]),
+ ntohs(daddr->__in6_u.__u6_addr16[5]),
+ ntohs(daddr->__in6_u.__u6_addr16[6]),
+ ntohs(daddr->__in6_u.__u6_addr16[7]));
+ goto discard_it;
+ }
+ default:
+ /* CHECKSUM_UNNECESSARY */
+ break;
+ };
+
+ /*
+ * length of original packet carried in skb
+ */
+ ulen = skb->tail - (unsigned char *) (hdr + 1);
+
+ type = hdr->icmp6_type;
+
+ if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
+ (&icmpv6_statistics.Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++;
+ else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT)
+ (&icmpv6_statistics.Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++;
+
+ switch (type) {
+
+ case ICMPV6_ECHO_REQUEST:
+ icmpv6_echo_reply(skb);
+ break;
+
+ case ICMPV6_ECHO_REPLY:
+ /* we coulnd't care less */
+ break;
+
+ case ICMPV6_PKT_TOOBIG:
+ /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
+ standard destination cache. Seems, only "advanced"
+ destination cache will allow to solve this problem
+ --ANK (980726)
+ */
+ orig_hdr = (struct ipv6hdr *) (hdr + 1);
+ if (ulen >= sizeof(struct ipv6hdr))
+ rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
+ ntohl(hdr->icmp6_mtu));
+
+ /*
+ * Drop through to notify
+ */
+
+ case ICMPV6_DEST_UNREACH:
+ case ICMPV6_TIME_EXCEED:
+ case ICMPV6_PARAMPROB:
+ icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu,
+ (char *) (hdr + 1), ulen);
+ break;
+
+ case NDISC_ROUTER_SOLICITATION:
+ case NDISC_ROUTER_ADVERTISEMENT:
+ case NDISC_NEIGHBOUR_SOLICITATION:
+ case NDISC_NEIGHBOUR_ADVERTISEMENT:
+ case NDISC_REDIRECT:
+ ndisc_rcv(skb, len);
+ break;
+
+ case ICMPV6_MGM_QUERY:
+ igmp6_event_query(skb, hdr, len);
+ break;
+
+ case ICMPV6_MGM_REPORT:
+ igmp6_event_report(skb, hdr, len);
+ break;
+
+ case ICMPV6_MGM_REDUCTION:
+ break;
+
+ default:
+ if (net_ratelimit())
+ printk(KERN_DEBUG "icmpv6: msg of unknown type\n");
+
+ /* informational */
+ if (type & 0x80)
+ break;
+
+ /*
+ * error of unknown type.
+ * must pass to upper level
+ */
+
+ icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu,
+ (char *) (hdr + 1), ulen);
+ };
+ kfree_skb(skb);
+ return 0;
+
+discard_it:
+ icmpv6_statistics.Icmp6InErrors++;
+ kfree_skb(skb);
+ return 0;
+}
+
+int __init icmpv6_init(struct net_proto_family *ops)
+{
+ struct sock *sk;
+ int err;
+
+ icmpv6_socket = sock_alloc();
+ if (icmpv6_socket == NULL) {
+ printk(KERN_ERR
+ "Failed to create the ICMP6 control socket.\n");
+ return -1;
+ }
+#ifndef _HURD_
+ icmpv6_socket->inode->i_uid = 0;
+ icmpv6_socket->inode->i_gid = 0;
+#endif
+ icmpv6_socket->type = SOCK_RAW;
+
+ if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) {
+ printk(KERN_ERR
+ "Failed to initialize the ICMP6 control socket (err %d).\n",
+ err);
+ sock_release(icmpv6_socket);
+ icmpv6_socket = NULL; /* for safety */
+ return err;
+ }
+
+ sk = icmpv6_socket->sk;
+ sk->allocation = GFP_ATOMIC;
+ sk->num = 256; /* Don't receive any data */
+
+ inet6_add_protocol(&icmpv6_protocol);
+
+ return 0;
+}
+
+void icmpv6_cleanup(void)
+{
+ sock_release(icmpv6_socket);
+ icmpv6_socket = NULL; /* For safety. */
+ inet6_del_protocol(&icmpv6_protocol);
+}
+
+static struct icmp6_err {
+ int err;
+ int fatal;
+} tab_unreach[] = {
+ { ENETUNREACH, 0}, /* NOROUTE */
+ { EACCES, 1}, /* ADM_PROHIBITED */
+ { EHOSTUNREACH, 0}, /* Was NOT_NEIGHBOUR, now reserved */
+ { EHOSTUNREACH, 0}, /* ADDR_UNREACH */
+ { ECONNREFUSED, 1}, /* PORT_UNREACH */
+};
+
+int icmpv6_err_convert(int type, int code, int *err)
+{
+ int fatal = 0;
+
+ *err = EPROTO;
+
+ switch (type) {
+ case ICMPV6_DEST_UNREACH:
+ fatal = 1;
+ if (code <= ICMPV6_PORT_UNREACH) {
+ *err = tab_unreach[code].err;
+ fatal = tab_unreach[code].fatal;
+ }
+ break;
+
+ case ICMPV6_PKT_TOOBIG:
+ *err = EMSGSIZE;
+ break;
+
+ case ICMPV6_PARAMPROB:
+ *err = EPROTO;
+ fatal = 1;
+ break;
+
+ case ICMPV6_TIME_EXCEED:
+ *err = EHOSTUNREACH;
+ break;
+ };
+
+ return fatal;
+}
diff --git a/pfinet/linux-src/net/ipv6/ip6_fib.c b/pfinet/linux-src/net/ipv6/ip6_fib.c
new file mode 100644
index 00000000..9468c023
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/ip6_fib.c
@@ -0,0 +1,1205 @@
+/*
+ * Linux INET6 implementation
+ * Forwarding Information Database
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: ip6_fib.c,v 1.2 2007/10/08 21:59:10 stesie Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+
+#define RT6_DEBUG 2
+#undef CONFIG_IPV6_SUBTREES
+
+#if RT6_DEBUG >= 1
+#define BUG_TRAP(x) ({ if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):%s\n", __LINE__, __FUNCTION__); } })
+#else
+#define BUG_TRAP(x) do { ; } while (0)
+#endif
+
+#if RT6_DEBUG >= 3
+#define RT6_TRACE(x...) printk(KERN_DEBUG x)
+#else
+#define RT6_TRACE(x...) do { ; } while (0)
+#endif
+
+struct rt6_statistics rt6_stats;
+
+enum fib_walk_state_t
+{
+#ifdef CONFIG_IPV6_SUBTREES
+ FWS_S,
+#endif
+ FWS_L,
+ FWS_R,
+ FWS_C,
+ FWS_U
+};
+
+struct fib6_cleaner_t
+{
+ struct fib6_walker_t w;
+ int (*func)(struct rt6_info *, void *arg);
+ void *arg;
+};
+
+#ifdef CONFIG_IPV6_SUBTREES
+#define FWS_INIT FWS_S
+#define SUBTREE(fn) ((fn)->subtree)
+#else
+#define FWS_INIT FWS_L
+#define SUBTREE(fn) NULL
+#endif
+
+static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
+static void fib6_repair_tree(struct fib6_node *fn);
+
+/*
+ * A routing update causes an increase of the serial number on the
+ * afected subtree. This allows for cached routes to be asynchronously
+ * tested when modifications are made to the destination cache as a
+ * result of redirects, path MTU changes, etc.
+ */
+
+static __u32 rt_sernum = 0;
+
+static struct timer_list ip6_fib_timer = {
+ NULL, NULL,
+ 0,
+ ~0UL,
+ fib6_run_gc
+};
+
+struct fib6_walker_t fib6_walker_list = {
+ &fib6_walker_list, &fib6_walker_list,
+};
+
+#define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next)
+
+static __inline__ u32 fib6_new_sernum(void)
+{
+ u32 n = ++rt_sernum;
+ if ((__s32)n <= 0)
+ rt_sernum = n = 1;
+ return n;
+}
+
+/*
+ * Auxiliary address test functions for the radix tree.
+ *
+ * These assume a 32bit processor (although it will work on
+ * 64bit processors)
+ */
+
+/*
+ * compare "prefix length" bits of an address
+ */
+
+static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
+{
+ __u32 *a1 = token1;
+ __u32 *a2 = token2;
+ int pdw;
+ int pbi;
+
+ pdw = prefixlen >> 5; /* num of whole __u32 in prefix */
+ pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */
+
+ if (pdw)
+ if (memcmp(a1, a2, pdw << 2))
+ return 0;
+
+ if (pbi) {
+ __u32 mask;
+
+ mask = htonl((0xffffffff) << (32 - pbi));
+
+ if ((a1[pdw] ^ a2[pdw]) & mask)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * test bit
+ */
+
+static __inline__ int addr_bit_set(void *token, int fn_bit)
+{
+ __u32 *addr = token;
+
+ return htonl(1 << ((~fn_bit)&0x1F)) & addr[fn_bit>>5];
+}
+
+/*
+ * find the first different bit between two addresses
+ * length of address must be a multiple of 32bits
+ */
+
+static __inline__ int addr_diff(void *token1, void *token2, int addrlen)
+{
+ __u32 *a1 = token1;
+ __u32 *a2 = token2;
+ int i;
+
+ addrlen >>= 2;
+
+ for (i = 0; i < addrlen; i++) {
+ __u32 xb;
+
+ xb = a1[i] ^ a2[i];
+
+ if (xb) {
+ int j = 31;
+
+ xb = ntohl(xb);
+
+ while (test_bit(j, &xb) == 0)
+ j--;
+
+ return (i * 32 + 31 - j);
+ }
+ }
+
+ /*
+ * we should *never* get to this point since that
+ * would mean the addrs are equal
+ *
+ * However, we do get to it 8) And exacly, when
+ * addresses are equal 8)
+ *
+ * ip route add 1111::/128 via ...
+ * ip route add 1111::/64 via ...
+ * and we are here.
+ *
+ * Ideally, this function should stop comparison
+ * at prefix length. It does not, but it is still OK,
+ * if returned value is greater than prefix length.
+ * --ANK (980803)
+ */
+
+ return addrlen<<5;
+}
+
+static __inline__ struct fib6_node * node_alloc(void)
+{
+ struct fib6_node *fn;
+
+ if ((fn = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC)) != NULL) {
+ memset(fn, 0, sizeof(struct fib6_node));
+ rt6_stats.fib_nodes++;
+ }
+
+ return fn;
+}
+
+static __inline__ void node_free(struct fib6_node * fn)
+{
+ rt6_stats.fib_nodes--;
+ kfree(fn);
+}
+
+static __inline__ void rt6_release(struct rt6_info *rt)
+{
+ if (atomic_dec_and_test(&rt->rt6i_ref))
+ dst_free(&rt->u.dst);
+}
+
+
+/*
+ * Routing Table
+ *
+ * return the appropriate node for a routing tree "add" operation
+ * by either creating and inserting or by returning an existing
+ * node.
+ */
+
+static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
+ int addrlen, int plen,
+ int offset)
+{
+ struct fib6_node *fn, *in, *ln;
+ struct fib6_node *pn = NULL;
+ struct rt6key *key;
+ int bit;
+ int dir = 0;
+ __u32 sernum = fib6_new_sernum();
+
+ RT6_TRACE("fib6_add_1\n");
+
+ /* insert node in tree */
+
+ fn = root;
+
+ if (plen == 0)
+ return fn;
+
+ do {
+ key = (struct rt6key *)((u8 *)fn->leaf + offset);
+
+ /*
+ * Prefix match
+ */
+ if (plen < fn->fn_bit ||
+ !addr_match(&key->addr, addr, fn->fn_bit))
+ goto insert_above;
+
+ /*
+ * Exact match ?
+ */
+
+ if (plen == fn->fn_bit) {
+ /* clean up an intermediate node */
+ if ((fn->fn_flags & RTN_RTINFO) == 0) {
+ rt6_release(fn->leaf);
+ fn->leaf = NULL;
+ }
+
+ fn->fn_sernum = sernum;
+
+ return fn;
+ }
+
+ /*
+ * We have more bits to go
+ */
+
+ /* Try to walk down on tree. */
+ fn->fn_sernum = sernum;
+ dir = addr_bit_set(addr, fn->fn_bit);
+ pn = fn;
+ fn = dir ? fn->right: fn->left;
+ } while (fn);
+
+ /*
+ * We wlaked to the bottom of tree.
+ * Create new leaf node without children.
+ */
+
+ ln = node_alloc();
+
+ if (ln == NULL)
+ return NULL;
+ ln->fn_bit = plen;
+
+ ln->parent = pn;
+ ln->fn_sernum = sernum;
+
+ if (dir)
+ pn->right = ln;
+ else
+ pn->left = ln;
+
+ return ln;
+
+
+insert_above:
+ /*
+ * split since we don't have a common prefix anymore or
+ * we have a less significant route.
+ * we've to insert an intermediate node on the list
+ * this new node will point to the one we need to create
+ * and the current
+ */
+
+ pn = fn->parent;
+
+ /* find 1st bit in difference between the 2 addrs.
+
+ See comment in addr_diff: bit may be an invalid value,
+ but if it is >= plen, the value is ignored in any case.
+ */
+
+ bit = addr_diff(addr, &key->addr, addrlen);
+
+ /*
+ * (intermediate)[in]
+ * / \
+ * (new leaf node)[ln] (old node)[fn]
+ */
+ if (plen > bit) {
+ in = node_alloc();
+ ln = node_alloc();
+
+ if (in == NULL || ln == NULL) {
+ if (in)
+ node_free(in);
+ if (ln)
+ node_free(ln);
+ return NULL;
+ }
+
+ /*
+ * new intermediate node.
+ * RTN_RTINFO will
+ * be off since that an address that chooses one of
+ * the branches would not match less specific routes
+ * in the other branch
+ */
+
+ in->fn_bit = bit;
+
+ in->parent = pn;
+ in->leaf = fn->leaf;
+ atomic_inc(&in->leaf->rt6i_ref);
+
+ in->fn_sernum = sernum;
+
+ /* update parent pointer */
+ if (dir)
+ pn->right = in;
+ else
+ pn->left = in;
+
+ ln->fn_bit = plen;
+
+ ln->parent = in;
+ fn->parent = in;
+
+ ln->fn_sernum = sernum;
+
+ if (addr_bit_set(addr, bit)) {
+ in->right = ln;
+ in->left = fn;
+ } else {
+ in->left = ln;
+ in->right = fn;
+ }
+ } else { /* plen <= bit */
+
+ /*
+ * (new leaf node)[ln]
+ * / \
+ * (old node)[fn] NULL
+ */
+
+ ln = node_alloc();
+
+ if (ln == NULL)
+ return NULL;
+
+ ln->fn_bit = plen;
+
+ ln->parent = pn;
+
+ ln->fn_sernum = sernum;
+
+ if (dir)
+ pn->right = ln;
+ else
+ pn->left = ln;
+
+ if (addr_bit_set(&key->addr, plen))
+ ln->right = fn;
+ else
+ ln->left = fn;
+
+ fn->parent = ln;
+ }
+ return ln;
+}
+
+/*
+ * Insert routing information in a node.
+ */
+
+static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
+{
+ struct rt6_info *iter = NULL;
+ struct rt6_info **ins;
+
+ ins = &fn->leaf;
+
+ for (iter = fn->leaf; iter; iter=iter->u.next) {
+ /*
+ * Search for duplicates
+ */
+
+ if (iter->rt6i_metric == rt->rt6i_metric) {
+ /*
+ * Same priority level
+ */
+
+ if ((iter->rt6i_dev == rt->rt6i_dev) &&
+ (iter->rt6i_flowr == rt->rt6i_flowr) &&
+ (ipv6_addr_cmp(&iter->rt6i_gateway,
+ &rt->rt6i_gateway) == 0)) {
+ if (!(iter->rt6i_flags&RTF_EXPIRES))
+ return -EEXIST;
+ iter->rt6i_expires = rt->rt6i_expires;
+ if (!(rt->rt6i_flags&RTF_EXPIRES)) {
+ iter->rt6i_flags &= ~RTF_EXPIRES;
+ iter->rt6i_expires = 0;
+ }
+ return -EEXIST;
+ }
+ }
+
+ if (iter->rt6i_metric > rt->rt6i_metric)
+ break;
+
+ ins = &iter->u.next;
+ }
+
+ /*
+ * insert node
+ */
+
+ rt->u.next = iter;
+ *ins = rt;
+ rt->rt6i_node = fn;
+ atomic_inc(&rt->rt6i_ref);
+#ifdef CONFIG_RTNETLINK
+ inet6_rt_notify(RTM_NEWROUTE, rt);
+#endif
+ rt6_stats.fib_rt_entries++;
+
+ if ((fn->fn_flags & RTN_RTINFO) == 0) {
+ rt6_stats.fib_route_nodes++;
+ fn->fn_flags |= RTN_RTINFO;
+ }
+
+ return 0;
+}
+
+static __inline__ void fib6_start_gc(struct rt6_info *rt)
+{
+ if (ip6_fib_timer.expires == 0 &&
+ (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) {
+ del_timer(&ip6_fib_timer);
+ ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval;
+ add_timer(&ip6_fib_timer);
+ }
+}
+
+/*
+ * Add routing information to the routing tree.
+ * <destination addr>/<source addr>
+ * with source addr info in sub-trees
+ */
+
+int fib6_add(struct fib6_node *root, struct rt6_info *rt)
+{
+ struct fib6_node *fn;
+ int err = -ENOMEM;
+
+ fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
+ rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
+
+ if (fn == NULL)
+ return -ENOMEM;
+
+#ifdef CONFIG_IPV6_SUBTREES
+ if (rt->rt6i_src.plen) {
+ struct fib6_node *sn;
+
+ if (fn->subtree == NULL) {
+ struct fib6_node *sfn;
+
+ /*
+ * Create subtree.
+ *
+ * fn[main tree]
+ * |
+ * sfn[subtree root]
+ * \
+ * sn[new leaf node]
+ */
+
+ /* Create subtree root node */
+ sfn = node_alloc();
+ if (sfn == NULL)
+ goto st_failure;
+
+ sfn->leaf = &ip6_null_entry;
+ atomic_inc(&ip6_null_entry.rt6i_ref);
+ sfn->fn_flags = RTN_ROOT;
+ sfn->fn_sernum = fib6_new_sernum();
+
+ /* Now add the first leaf node to new subtree */
+
+ sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
+ sizeof(struct in6_addr), rt->rt6i_src.plen,
+ (u8*) &rt->rt6i_src - (u8*) rt);
+
+ if (sn == NULL) {
+ /* If it is failed, discard just allocated
+ root, and then (in st_failure) stale node
+ in main tree.
+ */
+ node_free(sfn);
+ goto st_failure;
+ }
+
+ /* Now link new subtree to main tree */
+ sfn->parent = fn;
+ fn->subtree = sfn;
+ if (fn->leaf == NULL) {
+ fn->leaf = rt;
+ atomic_inc(&rt->rt6i_ref);
+ }
+ } else {
+ sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
+ sizeof(struct in6_addr), rt->rt6i_src.plen,
+ (u8*) &rt->rt6i_src - (u8*) rt);
+
+ if (sn == NULL)
+ goto st_failure;
+ }
+
+ fn = sn;
+ }
+#endif
+
+ err = fib6_add_rt2node(fn, rt);
+
+ if (err == 0) {
+ fib6_start_gc(rt);
+ if (!(rt->rt6i_flags&RTF_CACHE))
+ fib6_prune_clones(fn, rt);
+ }
+
+ if (err)
+ dst_free(&rt->u.dst);
+ return err;
+
+#ifdef CONFIG_IPV6_SUBTREES
+ /* Subtree creation failed, probably main tree node
+ is orphan. If it is, shot it.
+ */
+st_failure:
+ if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT))
+ fib_repair_tree(fn);
+ dst_free(&rt->u.dst);
+ return err;
+#endif
+}
+
+/*
+ * Routing tree lookup
+ *
+ */
+
+struct lookup_args {
+ int offset; /* key offset on rt6_info */
+ struct in6_addr *addr; /* search key */
+};
+
+static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
+ struct lookup_args *args)
+{
+ struct fib6_node *fn;
+ int dir;
+
+ /*
+ * Descend on a tree
+ */
+
+ fn = root;
+
+ for (;;) {
+ struct fib6_node *next;
+
+ dir = addr_bit_set(args->addr, fn->fn_bit);
+
+ next = dir ? fn->right : fn->left;
+
+ if (next) {
+ fn = next;
+ continue;
+ }
+
+ break;
+ }
+
+ while ((fn->fn_flags & RTN_ROOT) == 0) {
+#ifdef CONFIG_IPV6_SUBTREES
+ if (fn->subtree) {
+ struct fib6_node *st;
+ struct lookup_args *narg;
+
+ narg = args + 1;
+
+ if (narg->addr) {
+ st = fib6_lookup_1(fn->subtree, narg);
+
+ if (!(st->fn_flags & RTN_ROOT))
+ {
+ return st;
+ }
+ }
+ }
+#endif
+
+ if (fn->fn_flags & RTN_RTINFO) {
+ struct rt6key *key;
+
+ key = (struct rt6key *) ((u8 *) fn->leaf +
+ args->offset);
+
+ if (addr_match(&key->addr, args->addr, key->plen))
+ return fn;
+ }
+
+ fn = fn->parent;
+ }
+
+ return NULL;
+}
+
+struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr,
+ struct in6_addr *saddr)
+{
+ struct lookup_args args[2];
+ struct rt6_info *rt = NULL;
+ struct fib6_node *fn;
+
+ args[0].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
+ args[0].addr = daddr;
+
+#ifdef CONFIG_IPV6_SUBTREES
+ args[1].offset = (u8*) &rt->rt6i_src - (u8*) rt;
+ args[1].addr = saddr;
+#endif
+
+ fn = fib6_lookup_1(root, args);
+
+ if (fn == NULL)
+ fn = root;
+
+ return fn;
+}
+
+/*
+ * Get node with sepciafied destination prefix (and source prefix,
+ * if subtrees are used)
+ */
+
+
+static struct fib6_node * fib6_locate_1(struct fib6_node *root,
+ struct in6_addr *addr,
+ int plen, int offset)
+{
+ struct fib6_node *fn;
+
+ for (fn = root; fn ; ) {
+ struct rt6key *key = (struct rt6key *)((u8 *)fn->leaf + offset);
+
+ /*
+ * Prefix match
+ */
+ if (plen < fn->fn_bit ||
+ !addr_match(&key->addr, addr, fn->fn_bit))
+ return NULL;
+
+ if (plen == fn->fn_bit)
+ return fn;
+
+ /*
+ * We have more bits to go
+ */
+ if (addr_bit_set(addr, fn->fn_bit))
+ fn = fn->right;
+ else
+ fn = fn->left;
+ }
+ return NULL;
+}
+
+struct fib6_node * fib6_locate(struct fib6_node *root,
+ struct in6_addr *daddr, int dst_len,
+ struct in6_addr *saddr, int src_len)
+{
+ struct rt6_info *rt = NULL;
+ struct fib6_node *fn;
+
+ fn = fib6_locate_1(root, daddr, dst_len,
+ (u8*) &rt->rt6i_dst - (u8*) rt);
+
+#ifdef CONFIG_IPV6_SUBTREES
+ if (src_len) {
+ BUG_TRAP(saddr!=NULL);
+ if (fn != NULL)
+ fn = fn->subtree;
+ if (fn)
+ fn = fib6_locate_1(fn, saddr, src_len,
+ (u8*) &rt->rt6i_src - (u8*) rt);
+ }
+#endif
+
+ if (fn && fn->fn_flags&RTN_RTINFO)
+ return fn;
+
+ return NULL;
+}
+
+
+/*
+ * Deletion
+ *
+ */
+
+static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
+{
+ if (fn->fn_flags&RTN_ROOT)
+ return &ip6_null_entry;
+
+ while(fn) {
+ if(fn->left)
+ return fn->left->leaf;
+
+ if(fn->right)
+ return fn->right->leaf;
+
+ fn = SUBTREE(fn);
+ }
+ return NULL;
+}
+
+/*
+ * Called to trim the tree of intermediate nodes when possible. "fn"
+ * is the node we want to try and remove.
+ */
+
+static void fib6_repair_tree(struct fib6_node *fn)
+{
+ int children;
+ int nstate;
+ struct fib6_node *child, *pn;
+ struct fib6_walker_t *w;
+ int iter = 0;
+
+ for (;;) {
+ RT6_TRACE("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter);
+ iter++;
+
+ BUG_TRAP(!(fn->fn_flags&RTN_RTINFO));
+ BUG_TRAP(!(fn->fn_flags&RTN_TL_ROOT));
+ BUG_TRAP(fn->leaf==NULL);
+
+ children = 0;
+ child = NULL;
+ if (fn->right) child = fn->right, children |= 1;
+ if (fn->left) child = fn->left, children |= 2;
+
+ if (children == 3 || SUBTREE(fn)
+#ifdef CONFIG_IPV6_SUBTREES
+ /* Subtree root (i.e. fn) may have one child */
+ || (children && fn->fn_flags&RTN_ROOT)
+#endif
+ ) {
+ fn->leaf = fib6_find_prefix(fn);
+#if RT6_DEBUG >= 2
+ if (fn->leaf==NULL) {
+ BUG_TRAP(fn->leaf);
+ fn->leaf = &ip6_null_entry;
+ }
+#endif
+ atomic_inc(&fn->leaf->rt6i_ref);
+ return;
+ }
+
+ pn = fn->parent;
+#ifdef CONFIG_IPV6_SUBTREES
+ if (SUBTREE(pn) == fn) {
+ BUG_TRAP(fn->fn_flags&RTN_ROOT);
+ SUBTREE(pn) = NULL;
+ nstate = FWS_L;
+ } else {
+ BUG_TRAP(!(fn->fn_flags&RTN_ROOT));
+#endif
+ if (pn->right == fn) pn->right = child;
+ else if (pn->left == fn) pn->left = child;
+#if RT6_DEBUG >= 2
+ else BUG_TRAP(0);
+#endif
+ if (child)
+ child->parent = pn;
+ nstate = FWS_R;
+#ifdef CONFIG_IPV6_SUBTREES
+ }
+#endif
+
+ FOR_WALKERS(w) {
+ if (child == NULL) {
+ if (w->root == fn) {
+ w->root = w->node = NULL;
+ RT6_TRACE("W %p adjusted by delroot 1\n", w);
+ } else if (w->node == fn) {
+ RT6_TRACE("W %p adjusted by delnode 1, s=%d/%d\n", w, w->state, nstate);
+ w->node = pn;
+ w->state = nstate;
+ }
+ } else {
+ if (w->root == fn) {
+ w->root = child;
+ RT6_TRACE("W %p adjusted by delroot 2\n", w);
+ }
+ if (w->node == fn) {
+ w->node = child;
+ if (children&2) {
+ RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
+ w->state = w->state>=FWS_R ? FWS_U : FWS_INIT;
+ } else {
+ RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
+ w->state = w->state>=FWS_C ? FWS_U : FWS_INIT;
+ }
+ }
+ }
+ }
+
+ node_free(fn);
+ if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn))
+ return;
+
+ rt6_release(pn->leaf);
+ pn->leaf = NULL;
+ fn = pn;
+ }
+}
+
+static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp)
+{
+ struct fib6_walker_t *w;
+ struct rt6_info *rt = *rtp;
+
+ RT6_TRACE("fib6_del_route\n");
+
+ /* Unlink it */
+ *rtp = rt->u.next;
+ rt->rt6i_node = NULL;
+ rt6_stats.fib_rt_entries--;
+
+ /* Adjust walkers */
+ FOR_WALKERS(w) {
+ if (w->state == FWS_C && w->leaf == rt) {
+ RT6_TRACE("walker %p adjusted by delroute\n", w);
+ w->leaf = rt->u.next;
+ if (w->leaf == NULL)
+ w->state = FWS_U;
+ }
+ }
+
+ rt->u.next = NULL;
+
+ /* If it was last route, expunge its radix tree node */
+ if (fn->leaf == NULL) {
+ fn->fn_flags &= ~RTN_RTINFO;
+ rt6_stats.fib_route_nodes--;
+ fib6_repair_tree(fn);
+ }
+
+#ifdef CONFIG_RTNETLINK
+ inet6_rt_notify(RTM_DELROUTE, rt);
+#endif
+ rt6_release(rt);
+}
+
+int fib6_del(struct rt6_info *rt)
+{
+ struct fib6_node *fn = rt->rt6i_node;
+ struct rt6_info **rtp;
+
+#if RT6_DEBUG >= 2
+ if (rt->u.dst.obsolete>0) {
+ BUG_TRAP(rt->u.dst.obsolete>0);
+ return -EFAULT;
+ }
+#endif
+ if (fn == NULL || rt == &ip6_null_entry)
+ return -ENOENT;
+
+ BUG_TRAP(fn->fn_flags&RTN_RTINFO);
+
+ if (!(rt->rt6i_flags&RTF_CACHE))
+ fib6_prune_clones(fn, rt);
+
+ /*
+ * Walk the leaf entries looking for ourself
+ */
+
+ for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) {
+ if (*rtp == rt) {
+ fib6_del_route(fn, rtp);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/*
+ * Tree transversal function.
+ *
+ * Certainly, it is not interrupt safe.
+ * However, it is internally reenterable wrt itself and fib6_add/fib6_del.
+ * It means, that we can modify tree during walking
+ * and use this function for garbage collection, clone pruning,
+ * cleaning tree when a device goes down etc. etc.
+ *
+ * It guarantees that every node will be traversed,
+ * and that it will be traversed only once.
+ *
+ * Callback function w->func may return:
+ * 0 -> continue walking.
+ * positive value -> walking is suspended (used by tree dumps,
+ * and probably by gc, if it will be split to several slices)
+ * negative value -> terminate walking.
+ *
+ * The function itself returns:
+ * 0 -> walk is complete.
+ * >0 -> walk is incomplete (i.e. suspended)
+ * <0 -> walk is terminated by an error.
+ */
+
+int fib6_walk_continue(struct fib6_walker_t *w)
+{
+ struct fib6_node *fn, *pn;
+
+ for (;;) {
+ fn = w->node;
+ if (fn == NULL)
+ return 0;
+
+ if (w->prune && fn != w->root &&
+ fn->fn_flags&RTN_RTINFO && w->state < FWS_C) {
+ w->state = FWS_C;
+ w->leaf = fn->leaf;
+ }
+ switch (w->state) {
+#ifdef CONFIG_IPV6_SUBTREES
+ case FWS_S:
+ if (SUBTREE(fn)) {
+ w->node = SUBTREE(fn);
+ continue;
+ }
+ w->state = FWS_L;
+#endif
+ case FWS_L:
+ if (fn->left) {
+ w->node = fn->left;
+ w->state = FWS_INIT;
+ continue;
+ }
+ w->state = FWS_R;
+ case FWS_R:
+ if (fn->right) {
+ w->node = fn->right;
+ w->state = FWS_INIT;
+ continue;
+ }
+ w->state = FWS_C;
+ w->leaf = fn->leaf;
+ case FWS_C:
+ if (w->leaf && fn->fn_flags&RTN_RTINFO) {
+ int err = w->func(w);
+ if (err)
+ return err;
+ continue;
+ }
+ w->state = FWS_U;
+ case FWS_U:
+ if (fn == w->root)
+ return 0;
+ pn = fn->parent;
+ w->node = pn;
+#ifdef CONFIG_IPV6_SUBTREES
+ if (SUBTREE(pn) == fn) {
+ BUG_TRAP(fn->fn_flags&RTN_ROOT);
+ w->state = FWS_L;
+ continue;
+ }
+#endif
+ if (pn->left == fn) {
+ w->state = FWS_R;
+ continue;
+ }
+ if (pn->right == fn) {
+ w->state = FWS_C;
+ w->leaf = w->node->leaf;
+ continue;
+ }
+#if RT6_DEBUG >= 2
+ BUG_TRAP(0);
+#endif
+ }
+ }
+}
+
+int fib6_walk(struct fib6_walker_t *w)
+{
+ int res;
+
+ w->state = FWS_INIT;
+ w->node = w->root;
+
+ fib6_walker_link(w);
+ res = fib6_walk_continue(w);
+ if (res <= 0)
+ fib6_walker_unlink(w);
+ return res;
+}
+
+static int fib6_clean_node(struct fib6_walker_t *w)
+{
+ int res;
+ struct rt6_info *rt;
+ struct fib6_cleaner_t *c = (struct fib6_cleaner_t*)w;
+
+ for (rt = w->leaf; rt; rt = rt->u.next) {
+ res = c->func(rt, c->arg);
+ if (res < 0) {
+ w->leaf = rt;
+ res = fib6_del(rt);
+ if (res) {
+#if RT6_DEBUG >= 2
+ printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
+#endif
+ continue;
+ }
+ return 0;
+ }
+ BUG_TRAP(res==0);
+ }
+ w->leaf = rt;
+ return 0;
+}
+
+/*
+ * Convenient frontend to tree walker.
+ *
+ * func is called on each route.
+ * It may return -1 -> delete this route.
+ * 0 -> continue walking
+ *
+ * prune==1 -> only immediate children of node (certainly,
+ * ignoring pure split nodes) will be scanned.
+ */
+
+void fib6_clean_tree(struct fib6_node *root,
+ int (*func)(struct rt6_info *, void *arg),
+ int prune, void *arg)
+{
+ struct fib6_cleaner_t c;
+
+ c.w.root = root;
+ c.w.func = fib6_clean_node;
+ c.w.prune = prune;
+ c.func = func;
+ c.arg = arg;
+
+ start_bh_atomic();
+ fib6_walk(&c.w);
+ end_bh_atomic();
+}
+
+static int fib6_prune_clone(struct rt6_info *rt, void *arg)
+{
+ if (rt->rt6i_flags & RTF_CACHE) {
+ RT6_TRACE("pruning clone %p\n", rt);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt)
+{
+ fib6_clean_tree(fn, fib6_prune_clone, 1, rt);
+}
+
+/*
+ * Garbage collection
+ */
+
+static struct fib6_gc_args
+{
+ int timeout;
+ int more;
+} gc_args;
+
+static int fib6_age(struct rt6_info *rt, void *arg)
+{
+ unsigned long now = jiffies;
+
+ /* Age clones. Note, that clones are aged out
+ only if they are not in use now.
+ */
+
+ if (rt->rt6i_flags & RTF_CACHE) {
+ if (atomic_read(&rt->u.dst.use) == 0 &&
+ (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) {
+ RT6_TRACE("aging clone %p\n", rt);
+ return -1;
+ }
+ gc_args.more++;
+ }
+
+ /*
+ * check addrconf expiration here.
+ * They are expired even if they are in use.
+ */
+
+ if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) {
+ if ((long)(now - rt->rt6i_expires) > 0) {
+ RT6_TRACE("expiring %p\n", rt);
+ return -1;
+ }
+ gc_args.more++;
+ }
+
+ return 0;
+}
+
+void fib6_run_gc(unsigned long dummy)
+{
+ if (dummy != ~0UL)
+ gc_args.timeout = (int)dummy;
+ else
+ gc_args.timeout = ip6_rt_gc_interval;
+
+ gc_args.more = 0;
+
+ fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL);
+
+ del_timer(&ip6_fib_timer);
+
+ ip6_fib_timer.expires = 0;
+ if (gc_args.more) {
+ ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval;
+ add_timer(&ip6_fib_timer);
+ }
+}
+
+#ifdef MODULE
+void fib6_gc_cleanup(void)
+{
+ del_timer(&ip6_fib_timer);
+}
+#endif
+
+
diff --git a/pfinet/linux-src/net/ipv6/ip6_flowlabel.c b/pfinet/linux-src/net/ipv6/ip6_flowlabel.c
new file mode 100644
index 00000000..4a34b878
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/ip6_flowlabel.c
@@ -0,0 +1,627 @@
+/*
+ * ip6_flowlabel.c IPv6 flowlabel manager.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/route.h>
+#include <linux/proc_fs.h>
+
+#include <net/sock.h>
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/protocol.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/rawv6.h>
+#include <net/icmp.h>
+#include <net/transp_v6.h>
+
+#include <asm/uaccess.h>
+
+#define FL_MIN_LINGER 6 /* Minimal linger. It is set to 6sec specified
+ in old IPv6 RFC. Well, it was reasonable value.
+ */
+#define FL_MAX_LINGER 60 /* Maximal linger timeout */
+
+/* FL hash table */
+
+#define FL_MAX_PER_SOCK 32
+#define FL_MAX_SIZE 4096
+#define FL_HASH_MASK 255
+#define FL_HASH(l) (ntohl(l)&FL_HASH_MASK)
+
+static atomic_t fl_size = ATOMIC_INIT(0);
+static struct ip6_flowlabel *fl_ht[FL_HASH_MASK+1];
+
+static struct timer_list ip6_fl_gc_timer;
+
+/* FL hash table lock: it protects only of GC */
+
+static atomic_t ip6_fl_lock = ATOMIC_INIT(0);
+
+static __inline__ void fl_lock(void)
+{
+ atomic_inc(&ip6_fl_lock);
+ synchronize_bh();
+}
+
+static __inline__ void fl_unlock(void)
+{
+ atomic_dec(&ip6_fl_lock);
+}
+
+static struct ip6_flowlabel * fl_lookup(u32 label)
+{
+ struct ip6_flowlabel *fl;
+
+ fl_lock();
+ for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) {
+ if (fl->label == label) {
+ atomic_inc(&fl->users);
+ break;
+ }
+ }
+ fl_unlock();
+ return fl;
+}
+
+static void fl_free(struct ip6_flowlabel *fl)
+{
+ if (fl->opt)
+ kfree(fl->opt);
+ kfree(fl);
+}
+
+static void fl_release(struct ip6_flowlabel *fl)
+{
+ fl_lock();
+ fl->lastuse = jiffies;
+ if (atomic_dec_and_test(&fl->users)) {
+ unsigned long ttd = fl->lastuse + fl->linger;
+ if ((long)(ttd - fl->expires) > 0)
+ fl->expires = ttd;
+ ttd = fl->expires;
+ if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
+ struct ipv6_txoptions *opt = fl->opt;
+ fl->opt = NULL;
+ kfree(opt);
+ }
+ if (!del_timer(&ip6_fl_gc_timer) ||
+ (long)(ip6_fl_gc_timer.expires - ttd) > 0)
+ ip6_fl_gc_timer.expires = ttd;
+ add_timer(&ip6_fl_gc_timer);
+ }
+ fl_unlock();
+}
+
+static void ip6_fl_gc(unsigned long dummy)
+{
+ int i;
+ unsigned long now = jiffies;
+ unsigned long sched = 0;
+
+ if (atomic_read(&ip6_fl_lock)) {
+ ip6_fl_gc_timer.expires = now + HZ/10;
+ add_timer(&ip6_fl_gc_timer);
+ return;
+ }
+
+ for (i=0; i<=FL_HASH_MASK; i++) {
+ struct ip6_flowlabel *fl, **flp;
+ flp = &fl_ht[i];
+ while ((fl=*flp) != NULL) {
+ if (atomic_read(&fl->users) == 0) {
+ unsigned long ttd = fl->lastuse + fl->linger;
+ if ((long)(ttd - fl->expires) > 0)
+ fl->expires = ttd;
+ ttd = fl->expires;
+ if ((long)(now - ttd) >= 0) {
+ *flp = fl->next;
+ fl_free(fl);
+ atomic_dec(&fl_size);
+ continue;
+ }
+ if (!sched || (long)(ttd - sched) < 0)
+ sched = ttd;
+ }
+ flp = &fl->next;
+ }
+ }
+ if (!sched && atomic_read(&fl_size))
+ sched = now + FL_MAX_LINGER;
+ if (sched) {
+ ip6_fl_gc_timer.expires = sched;
+ add_timer(&ip6_fl_gc_timer);
+ }
+}
+
+static int fl_intern(struct ip6_flowlabel *fl, __u32 label)
+{
+ fl->label = label & IPV6_FLOWLABEL_MASK;
+
+ fl_lock();
+ if (label == 0) {
+ for (;;) {
+ fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK;
+ if (fl->label) {
+ struct ip6_flowlabel *lfl;
+ lfl = fl_lookup(fl->label);
+ if (lfl == NULL)
+ break;
+ fl_release(lfl);
+ }
+ }
+ }
+
+ fl->lastuse = jiffies;
+ fl->next = fl_ht[FL_HASH(fl->label)];
+ fl_ht[FL_HASH(fl->label)] = fl;
+ atomic_inc(&fl_size);
+ fl_unlock();
+ return 0;
+}
+
+
+
+/* Socket flowlabel lists */
+
+struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, u32 label)
+{
+ struct ipv6_fl_socklist *sfl;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+
+ label &= IPV6_FLOWLABEL_MASK;
+
+ for (sfl=np->ipv6_fl_list; sfl; sfl = sfl->next) {
+ struct ip6_flowlabel *fl = sfl->fl;
+ if (fl->label == label) {
+ fl->lastuse = jiffies;
+ atomic_inc(&fl->users);
+ return fl;
+ }
+ }
+ return NULL;
+}
+
+void fl6_free_socklist(struct sock *sk)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct ipv6_fl_socklist *sfl;
+
+ while ((sfl = np->ipv6_fl_list) != NULL) {
+ np->ipv6_fl_list = sfl->next;
+ fl_release(sfl->fl);
+ kfree(sfl);
+ }
+}
+
+/* Service routines */
+
+
+/*
+ It is the only difficult place. flowlabel enforces equal headers
+ before and including routing header, however user may supply options
+ following rthdr.
+ */
+
+struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
+ struct ip6_flowlabel * fl,
+ struct ipv6_txoptions * fopt)
+{
+ struct ipv6_txoptions * fl_opt = fl->opt;
+
+ if (fopt == NULL || fopt->opt_flen == 0)
+ return fl_opt;
+
+ if (fl_opt != NULL) {
+ opt_space->hopopt = fl_opt->hopopt;
+ opt_space->dst0opt = fl_opt->dst0opt;
+ opt_space->srcrt = fl_opt->srcrt;
+ opt_space->opt_nflen = fl_opt->opt_nflen;
+ } else {
+ if (fopt->opt_nflen == 0)
+ return fopt;
+ opt_space->hopopt = NULL;
+ opt_space->dst0opt = NULL;
+ opt_space->srcrt = NULL;
+ opt_space->opt_nflen = 0;
+ }
+ opt_space->dst1opt = fopt->dst1opt;
+ opt_space->auth = fopt->auth;
+ opt_space->opt_flen = fopt->opt_flen;
+ return opt_space;
+}
+
+static __u32 check_linger(__u16 ttl)
+{
+ if (ttl < FL_MIN_LINGER)
+ return FL_MIN_LINGER*HZ;
+ if (ttl > FL_MAX_LINGER && !capable(CAP_NET_ADMIN))
+ return 0;
+ return ttl*HZ;
+}
+
+static int fl6_renew(struct ip6_flowlabel *fl, unsigned linger, unsigned expires)
+{
+ linger = check_linger(linger);
+ if (!linger)
+ return -EPERM;
+ expires = check_linger(expires);
+ if (!expires)
+ return -EPERM;
+ fl->lastuse = jiffies;
+ if (fl->linger < linger)
+ fl->linger = linger;
+ if (expires < fl->linger)
+ expires = fl->linger;
+ if ((long)(fl->expires - (fl->lastuse+expires)) < 0)
+ fl->expires = fl->lastuse + expires;
+ return 0;
+}
+
+static struct ip6_flowlabel *
+fl_create(struct in6_flowlabel_req *freq, char *optval, int optlen, int *err_p)
+{
+ struct ip6_flowlabel *fl;
+ int olen;
+ int addr_type;
+ int err;
+
+ err = -ENOMEM;
+ fl = kmalloc(sizeof(*fl), GFP_KERNEL);
+ if (fl == NULL)
+ goto done;
+ memset(fl, 0, sizeof(*fl));
+
+ olen = optlen - CMSG_ALIGN(sizeof(*freq));
+ if (olen > 0) {
+ struct msghdr msg;
+ struct flowi flowi;
+ int junk;
+
+ err = -ENOMEM;
+ fl->opt = kmalloc(sizeof(*fl->opt) + olen, GFP_KERNEL);
+ if (fl->opt == NULL)
+ goto done;
+
+ memset(fl->opt, 0, sizeof(*fl->opt));
+ fl->opt->tot_len = sizeof(*fl->opt) + olen;
+ err = -EFAULT;
+ if (copy_from_user(fl->opt+1, optval+CMSG_ALIGN(sizeof(*freq)), olen))
+ goto done;
+
+ msg.msg_controllen = olen;
+ msg.msg_control = (void*)(fl->opt+1);
+ flowi.oif = 0;
+
+ err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk);
+ if (err)
+ goto done;
+ err = -EINVAL;
+ if (fl->opt->opt_flen)
+ goto done;
+ if (fl->opt->opt_nflen == 0) {
+ kfree(fl->opt);
+ fl->opt = NULL;
+ }
+ }
+
+ fl->expires = jiffies;
+ err = fl6_renew(fl, freq->flr_linger, freq->flr_expires);
+ if (err)
+ goto done;
+ fl->share = freq->flr_share;
+ addr_type = ipv6_addr_type(&freq->flr_dst);
+ if ((addr_type&IPV6_ADDR_MAPPED)
+ || addr_type == IPV6_ADDR_ANY)
+ goto done;
+ ipv6_addr_copy(&fl->dst, &freq->flr_dst);
+ atomic_set(&fl->users, 1);
+ switch (fl->share) {
+ case IPV6_FL_S_EXCL:
+ case IPV6_FL_S_ANY:
+ break;
+ case IPV6_FL_S_PROCESS:
+ fl->owner = current->pid;
+ break;
+ case IPV6_FL_S_USER:
+#ifdef _HURD_
+ /* FIXME
+ * Which euid shall be assigned? Where to get it,
+ * `struct task_struct' doesn't have a `euid'.
+ */
+#else
+ fl->owner = current->euid;
+ break;
+#endif
+ default:
+ err = -EINVAL;
+ goto done;
+ }
+ return fl;
+
+done:
+ if (fl)
+ fl_free(fl);
+ *err_p = err;
+ return NULL;
+}
+
+static int mem_check(struct sock *sk)
+{
+ struct ipv6_fl_socklist *sfl;
+ int room = FL_MAX_SIZE - atomic_read(&fl_size);
+ int count = 0;
+
+ if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK)
+ return 0;
+
+ for (sfl = sk->net_pinfo.af_inet6.ipv6_fl_list; sfl; sfl = sfl->next)
+ count++;
+
+ if (room <= 0 ||
+ ((count >= FL_MAX_PER_SOCK ||
+ (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4)
+ && !capable(CAP_NET_ADMIN)))
+ return -ENOBUFS;
+
+ return 0;
+}
+
+static int ipv6_hdr_cmp(struct ipv6_opt_hdr *h1, struct ipv6_opt_hdr *h2)
+{
+ if (h1 == h2)
+ return 0;
+ if (h1 == NULL || h2 == NULL)
+ return 1;
+ if (h1->hdrlen != h2->hdrlen)
+ return 1;
+ return memcmp(h1+1, h2+1, ((h1->hdrlen+1)<<3) - sizeof(*h1));
+}
+
+static int ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2)
+{
+ if (o1 == o2)
+ return 0;
+ if (o1 == NULL || o2 == NULL)
+ return 1;
+ if (o1->opt_nflen != o2->opt_nflen)
+ return 1;
+ if (ipv6_hdr_cmp(o1->hopopt, o2->hopopt))
+ return 1;
+ if (ipv6_hdr_cmp(o1->dst0opt, o2->dst0opt))
+ return 1;
+ if (ipv6_hdr_cmp((struct ipv6_opt_hdr *)o1->srcrt, (struct ipv6_opt_hdr *)o2->srcrt))
+ return 1;
+ return 0;
+}
+
+int ipv6_flowlabel_opt(struct sock *sk, char *optval, int optlen)
+{
+ int err;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct in6_flowlabel_req freq;
+ struct ipv6_fl_socklist *sfl1=NULL;
+ struct ipv6_fl_socklist *sfl, **sflp;
+ struct ip6_flowlabel *fl;
+
+ if (optlen < sizeof(freq))
+ return -EINVAL;
+
+ if (copy_from_user(&freq, optval, sizeof(freq)))
+ return -EFAULT;
+
+ switch (freq.flr_action) {
+ case IPV6_FL_A_PUT:
+ for (sflp = &np->ipv6_fl_list; (sfl=*sflp)!=NULL; sflp = &sfl->next) {
+ if (sfl->fl->label == freq.flr_label) {
+ if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK))
+ np->flow_label &= ~IPV6_FLOWLABEL_MASK;
+ *sflp = sfl->next;
+ synchronize_bh();
+ fl_release(sfl->fl);
+ kfree(sfl);
+ return 0;
+ }
+ }
+ return -ESRCH;
+
+ case IPV6_FL_A_RENEW:
+ for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) {
+ if (sfl->fl->label == freq.flr_label)
+ return fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires);
+ }
+ if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) {
+ fl = fl_lookup(freq.flr_label);
+ if (fl) {
+ err = fl6_renew(fl, freq.flr_linger, freq.flr_expires);
+ fl_release(fl);
+ return err;
+ }
+ }
+ return -ESRCH;
+
+ case IPV6_FL_A_GET:
+ if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
+ return -EINVAL;
+
+ fl = fl_create(&freq, optval, optlen, &err);
+ if (fl == NULL)
+ return err;
+ sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
+
+ if (freq.flr_label) {
+ struct ip6_flowlabel *fl1 = NULL;
+
+ err = -EEXIST;
+ for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) {
+ if (sfl->fl->label == freq.flr_label) {
+ if (freq.flr_flags&IPV6_FL_F_EXCL)
+ goto done;
+ fl1 = sfl->fl;
+ atomic_inc(&fl->users);
+ break;
+ }
+ }
+
+ if (fl1 == NULL)
+ fl1 = fl_lookup(freq.flr_label);
+ if (fl1) {
+ err = -EEXIST;
+ if (freq.flr_flags&IPV6_FL_F_EXCL)
+ goto release;
+ err = -EPERM;
+ if (fl1->share == IPV6_FL_S_EXCL ||
+ fl1->share != fl->share ||
+ fl1->owner != fl->owner)
+ goto release;
+
+ err = -EINVAL;
+ if (ipv6_addr_cmp(&fl1->dst, &fl->dst) ||
+ ipv6_opt_cmp(fl1->opt, fl->opt))
+ goto release;
+
+ err = -ENOMEM;
+ if (sfl1 == NULL)
+ goto release;
+ if (fl->linger > fl1->linger)
+ fl1->linger = fl->linger;
+ if ((long)(fl->expires - fl1->expires) > 0)
+ fl1->expires = fl->expires;
+ sfl1->fl = fl1;
+ sfl1->next = np->ipv6_fl_list;
+ np->ipv6_fl_list = sfl1;
+ synchronize_bh();
+ fl_free(fl);
+ return 0;
+
+release:
+ fl_release(fl1);
+ goto done;
+ }
+ }
+ err = -ENOENT;
+ if (!(freq.flr_flags&IPV6_FL_F_CREATE))
+ goto done;
+
+ err = -ENOMEM;
+ if (sfl1 == NULL || (err = mem_check(sk)) != 0)
+ goto done;
+
+ err = fl_intern(fl, freq.flr_label);
+ if (err)
+ goto done;
+
+ /* Do not check for fault */
+ if (!freq.flr_label)
+ copy_to_user(optval + ((u8*)&freq.flr_label - (u8*)&freq), &fl->label, sizeof(fl->label));
+
+ sfl1->fl = fl;
+ sfl1->next = np->ipv6_fl_list;
+ np->ipv6_fl_list = sfl1;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+
+done:
+ if (fl)
+ fl_free(fl);
+ if (sfl1)
+ kfree(sfl1);
+ return err;
+}
+
+#ifdef CONFIG_PROC_FS
+
+
+static int ip6_fl_read_proc(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
+{
+ off_t pos=0;
+ off_t begin=0;
+ int len=0;
+ int i, k;
+ struct ip6_flowlabel *fl;
+
+ len+= sprintf(buffer,"Label S Owner Users Linger Expires "
+ "Dst Opt\n");
+
+ fl_lock();
+ for (i=0; i<=FL_HASH_MASK; i++) {
+ for (fl = fl_ht[i]; fl; fl = fl->next) {
+ len+=sprintf(buffer+len,"%05X %-1d %-6d %-6d %-6d %-8ld ",
+ (unsigned)ntohl(fl->label),
+ fl->share,
+ (unsigned)fl->owner,
+ atomic_read(&fl->users),
+ fl->linger/HZ,
+ (long)(fl->expires - jiffies)/HZ);
+
+ for (k=0; k<16; k++)
+ len+=sprintf(buffer+len, "%02x", fl->dst.s6_addr[k]);
+ buffer[len++]=' ';
+ len+=sprintf(buffer+len, "%-4d", fl->opt ? fl->opt->opt_nflen : 0);
+ buffer[len++]='\n';
+
+ pos=begin+len;
+ if(pos<offset) {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ goto done;
+ }
+ }
+ *eof = 1;
+
+done:
+ fl_unlock();
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ if(len<0)
+ len=0;
+ return len;
+}
+#endif
+
+
+void ip6_flowlabel_init()
+{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent;
+#endif
+
+ init_timer(&ip6_fl_gc_timer);
+ ip6_fl_gc_timer.function = ip6_fl_gc;
+#ifdef CONFIG_PROC_FS
+ ent = create_proc_entry("net/ip6_flowlabel", 0, 0);
+ ent->read_proc = ip6_fl_read_proc;
+#endif
+}
+
+void ip6_flowlabel_cleanup()
+{
+ del_timer(&ip6_fl_gc_timer);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("net/ip6_flowlabel", 0);
+#endif
+}
diff --git a/pfinet/linux-src/net/ipv6/ip6_input.c b/pfinet/linux-src/net/ipv6/ip6_input.c
new file mode 100644
index 00000000..c4a51831
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/ip6_input.c
@@ -0,0 +1,284 @@
+/*
+ * IPv6 input
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Ian P. Morris <I.P.Morris@soton.ac.uk>
+ *
+ * $Id: ip6_input.c,v 1.1 2007/10/08 21:12:30 stesie Exp $
+ *
+ * Based in linux/net/ipv4/ip_input.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+
+int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+ struct ipv6hdr *hdr;
+ u32 pkt_len;
+
+ if (skb->pkt_type == PACKET_OTHERHOST)
+ goto drop;
+
+ ipv6_statistics.Ip6InReceives++;
+
+ /* Store incoming device index. When the packet will
+ be queued, we cannot refer to skb->dev anymore.
+ */
+ ((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex;
+
+ hdr = skb->nh.ipv6h;
+
+ if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6)
+ goto err;
+
+ pkt_len = ntohs(hdr->payload_len);
+
+ /* pkt_len may be zero if Jumbo payload option is present */
+ if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
+ if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
+ goto truncated;
+ skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+ }
+
+ if (hdr->nexthdr == NEXTHDR_HOP) {
+ skb->h.raw = (u8*)(hdr+1);
+ if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) {
+ ipv6_statistics.Ip6InHdrErrors++;
+ return 0;
+ }
+ }
+
+ if (skb->dst == NULL)
+ ip6_route_input(skb);
+
+ return skb->dst->input(skb);
+
+truncated:
+ ipv6_statistics.Ip6InTruncatedPkts++;
+err:
+ ipv6_statistics.Ip6InHdrErrors++;
+drop:
+ kfree_skb(skb);
+ return 0;
+}
+
+/*
+ * 0 - deliver
+ * 1 - block
+ */
+static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
+{
+ struct icmp6hdr *icmph;
+ struct raw6_opt *opt;
+
+ opt = &sk->tp_pinfo.tp_raw;
+ icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1);
+ return test_bit(icmph->icmp6_type, &opt->filter);
+}
+
+/*
+ * demultiplex raw sockets.
+ * (should consider queueing the skb in the sock receive_queue
+ * without calling rawv6.c)
+ */
+static struct sock * ipv6_raw_deliver(struct sk_buff *skb,
+ int nexthdr, unsigned long len)
+{
+ struct in6_addr *saddr;
+ struct in6_addr *daddr;
+ struct sock *sk, *sk2;
+ __u8 hash;
+
+ saddr = &skb->nh.ipv6h->saddr;
+ daddr = saddr + 1;
+
+ hash = nexthdr & (MAX_INET_PROTOS - 1);
+
+ sk = raw_v6_htable[hash];
+
+ /*
+ * The first socket found will be delivered after
+ * delivery to transport protocols.
+ */
+
+ if (sk == NULL)
+ return NULL;
+
+ sk = raw_v6_lookup(sk, nexthdr, daddr, saddr);
+
+ if (sk) {
+ sk2 = sk;
+
+ while ((sk2 = raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
+ struct sk_buff *buff;
+
+ if (nexthdr == IPPROTO_ICMPV6 &&
+ icmpv6_filter(sk2, skb))
+ continue;
+
+ buff = skb_clone(skb, GFP_ATOMIC);
+ if (buff)
+ rawv6_rcv(sk2, buff, len);
+ }
+ }
+
+ if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
+ sk = NULL;
+
+ return sk;
+}
+
+/*
+ * Deliver the packet to the host
+ */
+
+int ip6_input(struct sk_buff *skb)
+{
+ struct ipv6hdr *hdr = skb->nh.ipv6h;
+ struct inet6_protocol *ipprot;
+ struct sock *raw_sk;
+ __u8 *nhptr;
+ int nexthdr;
+ int found = 0;
+ u8 hash;
+ int len;
+
+ skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
+
+ /*
+ * Parse extension headers
+ */
+
+ nexthdr = hdr->nexthdr;
+ nhptr = &hdr->nexthdr;
+
+ /* Skip hop-by-hop options, they are already parsed. */
+ if (nexthdr == NEXTHDR_HOP) {
+ nhptr = (u8*)(hdr+1);
+ nexthdr = *nhptr;
+ skb->h.raw += (nhptr[1]+1)<<3;
+ }
+
+ /* This check is sort of optimization.
+ It would be stupid to detect for optional headers,
+ which are missing with probability of 200%
+ */
+ if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
+ nhptr = ipv6_parse_exthdrs(&skb, nhptr);
+ if (nhptr == NULL)
+ return 0;
+ nexthdr = *nhptr;
+ hdr = skb->nh.ipv6h;
+ }
+ len = skb->tail - skb->h.raw;
+
+ raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
+
+ hash = nexthdr & (MAX_INET_PROTOS - 1);
+ for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
+ ipprot != NULL;
+ ipprot = (struct inet6_protocol *) ipprot->next) {
+ struct sk_buff *buff = skb;
+
+ if (ipprot->protocol != nexthdr)
+ continue;
+
+ if (ipprot->copy || raw_sk)
+ buff = skb_clone(skb, GFP_ATOMIC);
+ /* buff == NULL ?????? */
+ ipprot->handler(buff, len);
+ found = 1;
+ }
+
+ if (raw_sk) {
+ rawv6_rcv(raw_sk, skb, len);
+ found = 1;
+ }
+
+ /*
+ * not found: send ICMP parameter problem back
+ */
+ if (!found) {
+ ipv6_statistics.Ip6InUnknownProtos++;
+ icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr);
+ }
+
+ return 0;
+}
+
+int ip6_mc_input(struct sk_buff *skb)
+{
+ struct ipv6hdr *hdr;
+ int deliver = 0;
+ int discard = 1;
+
+ ipv6_statistics.Ip6InMcastPkts++;
+
+ hdr = skb->nh.ipv6h;
+ if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr))
+ deliver = 1;
+
+ /*
+ * IPv6 multicast router mode isn't currently supported.
+ */
+#if 0
+ if (ipv6_config.multicast_route) {
+ int addr_type;
+
+ addr_type = ipv6_addr_type(&hdr->daddr);
+
+ if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) {
+ struct sk_buff *skb2;
+ struct dst_entry *dst;
+
+ dst = skb->dst;
+
+ if (deliver) {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ } else {
+ discard = 0;
+ skb2 = skb;
+ }
+
+ dst->output(skb2);
+ }
+ }
+#endif
+
+ if (deliver) {
+ discard = 0;
+ ip6_input(skb);
+ }
+
+ if (discard)
+ kfree_skb(skb);
+
+ return 0;
+}
diff --git a/pfinet/linux-src/net/ipv6/ip6_output.c b/pfinet/linux-src/net/ipv6/ip6_output.c
new file mode 100644
index 00000000..e06ad59a
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/ip6_output.c
@@ -0,0 +1,720 @@
+/*
+ * IPv6 output functions
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: ip6_output.c,v 1.1 2007/10/08 21:12:30 stesie Exp $
+ *
+ * Based on linux/net/ipv4/ip_output.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ * A.N.Kuznetsov : airthmetics in fragmentation.
+ * extension headers are implemented.
+ * route changes now work.
+ * ip6_forward does not confuse sniffers.
+ * etc.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/route.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/protocol.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/rawv6.h>
+#include <net/icmp.h>
+
+static u32 ipv6_fragmentation_id = 1;
+
+int ip6_output(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb->dst;
+ struct device *dev = dst->dev;
+ struct hh_cache *hh = dst->hh;
+
+ skb->protocol = __constant_htons(ETH_P_IPV6);
+ skb->dev = dev;
+
+ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
+ if (!(dev->flags&IFF_LOOPBACK) &&
+ (skb->sk == NULL || skb->sk->net_pinfo.af_inet6.mc_loop) &&
+ ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr)) {
+ /* Do not check for IFF_ALLMULTI; multicast routing
+ is not supported in any case.
+ */
+ dev_loopback_xmit(skb);
+
+ if (skb->nh.ipv6h->hop_limit == 0) {
+ kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ ipv6_statistics.Ip6OutMcastPkts++;
+ }
+
+ if (hh) {
+#ifdef __alpha__
+ /* Alpha has disguisting memcpy. Help it. */
+ u64 *aligned_hdr = (u64*)(skb->data - 16);
+ u64 *aligned_hdr0 = hh->hh_data;
+ read_lock_irq(&hh->hh_lock);
+ aligned_hdr[0] = aligned_hdr0[0];
+ aligned_hdr[1] = aligned_hdr0[1];
+#else
+ read_lock_irq(&hh->hh_lock);
+ memcpy(skb->data - 16, hh->hh_data, 16);
+#endif
+ read_unlock_irq(&hh->hh_lock);
+ skb_push(skb, dev->hard_header_len);
+ return hh->hh_output(skb);
+ } else if (dst->neighbour)
+ return dst->neighbour->output(skb);
+
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+/*
+ * xmit an sk_buff (used by TCP)
+ */
+
+int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+ struct ipv6_txoptions *opt)
+{
+ struct ipv6_pinfo * np = sk ? &sk->net_pinfo.af_inet6 : NULL;
+ struct in6_addr *first_hop = fl->nl_u.ip6_u.daddr;
+ struct dst_entry *dst = skb->dst;
+ struct ipv6hdr *hdr;
+ u8 proto = fl->proto;
+ int seg_len = skb->len;
+ int hlimit;
+
+ if (opt) {
+ int head_room;
+
+ /* First: exthdrs may take lots of space (~8K for now)
+ MAX_HEADER is not enough.
+ */
+ head_room = opt->opt_nflen + opt->opt_flen;
+ seg_len += head_room;
+ head_room += sizeof(struct ipv6hdr) + ((dst->dev->hard_header_len + 15)&~15);
+
+ if (skb_headroom(skb) < head_room) {
+ struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
+ kfree(skb);
+ skb = skb2;
+ if (skb == NULL)
+ return -ENOBUFS;
+ if (sk)
+ skb_set_owner_w(skb, sk);
+ }
+ if (opt->opt_flen)
+ ipv6_push_frag_opts(skb, opt, &proto);
+ if (opt->opt_nflen)
+ ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
+ }
+
+ hdr = skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, sizeof(struct ipv6hdr));
+
+ /*
+ * Fill in the IPv6 header
+ */
+
+ *(u32*)hdr = __constant_htonl(0x60000000) | fl->fl6_flowlabel;
+ hlimit = -1;
+ if (np)
+ hlimit = np->hop_limit;
+ if (hlimit < 0)
+ hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit;
+
+ hdr->payload_len = htons(seg_len);
+ hdr->nexthdr = proto;
+ hdr->hop_limit = hlimit;
+
+ ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
+ ipv6_addr_copy(&hdr->daddr, first_hop);
+
+ if (skb->len <= dst->pmtu) {
+ ipv6_statistics.Ip6OutRequests++;
+ dst->output(skb);
+ return 0;
+ }
+
+ printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
+ start_bh_atomic();
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
+ end_bh_atomic();
+ kfree_skb(skb);
+ return -EMSGSIZE;
+}
+
+/*
+ * To avoid extra problems ND packets are send through this
+ * routine. It's code duplication but I really want to avoid
+ * extra checks since ipv6_build_header is used by TCP (which
+ * is for us performace critical)
+ */
+
+int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct device *dev,
+ struct in6_addr *saddr, struct in6_addr *daddr,
+ int proto, int len)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct ipv6hdr *hdr;
+ int totlen;
+
+ skb->protocol = __constant_htons(ETH_P_IPV6);
+ skb->dev = dev;
+
+ totlen = len + sizeof(struct ipv6hdr);
+
+ hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
+ skb->nh.ipv6h = hdr;
+
+ *(u32*)hdr = htonl(0x60000000);
+
+ hdr->payload_len = htons(len);
+ hdr->nexthdr = proto;
+ hdr->hop_limit = np->hop_limit;
+
+ ipv6_addr_copy(&hdr->saddr, saddr);
+ ipv6_addr_copy(&hdr->daddr, daddr);
+
+ return 0;
+}
+
+static struct ipv6hdr * ip6_bld_1(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+ int hlimit, unsigned pktlength)
+{
+ struct ipv6hdr *hdr;
+
+ skb->nh.raw = skb_put(skb, sizeof(struct ipv6hdr));
+ hdr = skb->nh.ipv6h;
+
+ *(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000);
+
+ hdr->payload_len = htons(pktlength - sizeof(struct ipv6hdr));
+ hdr->hop_limit = hlimit;
+ hdr->nexthdr = fl->proto;
+
+ ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
+ ipv6_addr_copy(&hdr->daddr, fl->nl_u.ip6_u.daddr);
+ return hdr;
+}
+
+static __inline__ u8 * ipv6_build_fraghdr(struct sk_buff *skb, u8* prev_hdr, unsigned offset)
+{
+ struct frag_hdr *fhdr;
+
+ fhdr = (struct frag_hdr *) skb_put(skb, sizeof(struct frag_hdr));
+
+ fhdr->nexthdr = *prev_hdr;
+ *prev_hdr = NEXTHDR_FRAGMENT;
+ prev_hdr = &fhdr->nexthdr;
+
+ fhdr->reserved = 0;
+ fhdr->frag_off = htons(offset);
+ fhdr->identification = ipv6_fragmentation_id++;
+ return &fhdr->nexthdr;
+}
+
+static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
+ const void *data, struct dst_entry *dst,
+ struct flowi *fl, struct ipv6_txoptions *opt,
+ struct in6_addr *final_dst,
+ int hlimit, int flags, unsigned length, int mtu)
+{
+ struct ipv6hdr *hdr;
+ struct sk_buff *last_skb;
+ u8 *prev_hdr;
+ int unfrag_len;
+ int frag_len;
+ int last_len;
+ int nfrags;
+ int fhdr_dist;
+ int frag_off;
+ int data_off;
+ int err;
+
+ /*
+ * Fragmentation
+ *
+ * Extension header order:
+ * Hop-by-hop -> Dest0 -> Routing -> Fragment -> Auth -> Dest1 -> rest (...)
+ *
+ * We must build the non-fragmented part that
+ * will be in every packet... this also means
+ * that other extension headers (Dest, Auth, etc)
+ * must be considered in the data to be fragmented
+ */
+
+ unfrag_len = sizeof(struct ipv6hdr) + sizeof(struct frag_hdr);
+ last_len = length;
+
+ if (opt) {
+ unfrag_len += opt->opt_nflen;
+ last_len += opt->opt_flen;
+ }
+
+ /*
+ * Length of fragmented part on every packet but
+ * the last must be an:
+ * "integer multiple of 8 octects".
+ */
+
+ frag_len = (mtu - unfrag_len) & ~0x7;
+
+ /* Unfragmentable part exceeds mtu. */
+ if (frag_len <= 0) {
+ ipv6_local_error(sk, EMSGSIZE, fl, mtu);
+ return -EMSGSIZE;
+ }
+
+ nfrags = last_len / frag_len;
+
+ /*
+ * We must send from end to start because of
+ * UDP/ICMP checksums. We do a funny trick:
+ * fill the last skb first with the fixed
+ * header (and its data) and then use it
+ * to create the following segments and send it
+ * in the end. If the peer is checking the M_flag
+ * to trigger the reassembly code then this
+ * might be a good idea.
+ */
+
+ frag_off = nfrags * frag_len;
+ last_len -= frag_off;
+
+ if (last_len == 0) {
+ last_len = frag_len;
+ frag_off -= frag_len;
+ nfrags--;
+ }
+ data_off = frag_off;
+
+ /* And it is implementation problem: for now we assume, that
+ all the exthdrs will fit to the first fragment.
+ */
+ if (opt) {
+ if (frag_len < opt->opt_flen) {
+ ipv6_local_error(sk, EMSGSIZE, fl, mtu);
+ return -EMSGSIZE;
+ }
+ data_off = frag_off - opt->opt_flen;
+ }
+
+ last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len +
+ dst->dev->hard_header_len + 15,
+ 0, flags & MSG_DONTWAIT, &err);
+
+ if (last_skb == NULL)
+ return err;
+
+ last_skb->dst = dst_clone(dst);
+
+ skb_reserve(last_skb, (dst->dev->hard_header_len + 15) & ~15);
+
+ hdr = ip6_bld_1(sk, last_skb, fl, hlimit, frag_len+unfrag_len);
+ prev_hdr = &hdr->nexthdr;
+
+ if (opt && opt->opt_nflen)
+ prev_hdr = ipv6_build_nfrag_opts(last_skb, prev_hdr, opt, final_dst, 0);
+
+ prev_hdr = ipv6_build_fraghdr(last_skb, prev_hdr, frag_off);
+ fhdr_dist = prev_hdr - last_skb->data;
+
+ err = getfrag(data, &hdr->saddr, last_skb->tail, data_off, last_len);
+
+ if (!err) {
+ while (nfrags--) {
+ struct sk_buff *skb;
+
+ struct frag_hdr *fhdr2;
+
+ skb = skb_copy(last_skb, sk->allocation);
+
+ if (skb == NULL) {
+ ipv6_statistics.Ip6FragFails++;
+ kfree_skb(last_skb);
+ return -ENOMEM;
+ }
+
+ frag_off -= frag_len;
+ data_off -= frag_len;
+
+ fhdr2 = (struct frag_hdr *) (skb->data + fhdr_dist);
+
+ /* more flag on */
+ fhdr2->frag_off = htons(frag_off | 1);
+
+ /* Write fragmentable exthdrs to the first chunk */
+ if (nfrags == 0 && opt && opt->opt_flen) {
+ ipv6_build_frag_opts(skb, &fhdr2->nexthdr, opt);
+ frag_len -= opt->opt_flen;
+ data_off = 0;
+ }
+
+ err = getfrag(data, &hdr->saddr,skb_put(skb, frag_len),
+ data_off, frag_len);
+
+ if (err) {
+ kfree_skb(skb);
+ break;
+ }
+
+ ipv6_statistics.Ip6FragCreates++;
+ ipv6_statistics.Ip6OutRequests++;
+ dst->output(skb);
+ }
+ }
+
+ if (err) {
+ ipv6_statistics.Ip6FragFails++;
+ kfree_skb(last_skb);
+ return -EFAULT;
+ }
+
+ hdr->payload_len = htons(unfrag_len + last_len - sizeof(struct ipv6hdr));
+
+ /*
+ * update last_skb to reflect the getfrag we did
+ * on start.
+ */
+
+ skb_put(last_skb, last_len);
+
+ ipv6_statistics.Ip6FragCreates++;
+ ipv6_statistics.Ip6FragOKs++;
+ ipv6_statistics.Ip6OutRequests++;
+ dst->output(last_skb);
+
+ return 0;
+}
+
+int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
+ struct flowi *fl, unsigned length,
+ struct ipv6_txoptions *opt, int hlimit, int flags)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct in6_addr *final_dst = NULL;
+ struct dst_entry *dst;
+ int err = 0;
+ unsigned int pktlength, jumbolen, mtu;
+ struct in6_addr saddr;
+
+ if (opt && opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+ final_dst = fl->fl6_dst;
+ fl->fl6_dst = rt0->addr;
+ }
+
+ if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))
+ fl->oif = np->mcast_oif;
+
+ dst = NULL;
+ if (sk->dst_cache) {
+ dst = dst_check(&sk->dst_cache, np->dst_cookie);
+ if (dst) {
+ struct rt6_info *rt = (struct rt6_info*)dst_clone(dst);
+
+ /* Yes, checking route validity in not connected
+ case is not very simple. Take into account,
+ that we do not support routing by source, TOS,
+ and MSG_DONTROUTE --ANK (980726)
+
+ 1. If route was host route, check that
+ cached destination is current.
+ If it is network route, we still may
+ check its validity using saved pointer
+ to the last used address: daddr_cache.
+ We do not want to save whole address now,
+ (because main consumer of this service
+ is tcp, which has not this problem),
+ so that the last trick works only on connected
+ sockets.
+ 2. oif also should be the same.
+ */
+ if (((rt->rt6i_dst.plen != 128 ||
+ ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))
+ && (np->daddr_cache == NULL ||
+ ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))
+ || (fl->oif && fl->oif != dst->dev->ifindex)) {
+ dst_release(dst);
+ dst = NULL;
+ }
+ }
+ }
+
+ if (dst == NULL)
+ dst = ip6_route_output(sk, fl);
+
+ if (dst->error) {
+ ipv6_statistics.Ip6OutNoRoutes++;
+ dst_release(dst);
+ return -ENETUNREACH;
+ }
+
+ if (fl->fl6_src == NULL) {
+ err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);
+
+ if (err) {
+#if IP6_DEBUG >= 2
+ printk(KERN_DEBUG "ip6_build_xmit: "
+ "no available source address\n");
+#endif
+ goto out;
+ }
+ fl->fl6_src = &saddr;
+ }
+ pktlength = length;
+
+ if (hlimit < 0) {
+ if (ipv6_addr_is_multicast(fl->fl6_dst))
+ hlimit = np->mcast_hops;
+ else
+ hlimit = np->hop_limit;
+ if (hlimit < 0)
+ hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit;
+ }
+
+ jumbolen = 0;
+
+ if (!sk->ip_hdrincl) {
+ pktlength += sizeof(struct ipv6hdr);
+ if (opt)
+ pktlength += opt->opt_flen + opt->opt_nflen;
+
+ if (pktlength > 0xFFFF + sizeof(struct ipv6hdr)) {
+ /* Jumbo datagram.
+ It is assumed, that in the case of sk->ip_hdrincl
+ jumbo option is supplied by user.
+ */
+ pktlength += 8;
+ jumbolen = pktlength - sizeof(struct ipv6hdr);
+ }
+ }
+
+ mtu = dst->pmtu;
+ if (np->frag_size < mtu) {
+ if (np->frag_size)
+ mtu = np->frag_size;
+ else if (np->pmtudisc == IPV6_PMTUDISC_DONT)
+ mtu = IPV6_MIN_MTU;
+ }
+
+ /* Critical arithmetic overflow check.
+ FIXME: may gcc optimize it out? --ANK (980726)
+ */
+ if (pktlength < length) {
+ ipv6_local_error(sk, EMSGSIZE, fl, mtu);
+ err = -EMSGSIZE;
+ goto out;
+ }
+
+ if (pktlength <= mtu) {
+ struct sk_buff *skb;
+ struct ipv6hdr *hdr;
+ struct device *dev = dst->dev;
+
+ skb = sock_alloc_send_skb(sk, pktlength + 15 +
+ dev->hard_header_len, 0,
+ flags & MSG_DONTWAIT, &err);
+
+ if (skb == NULL) {
+ ipv6_statistics.Ip6OutDiscards++;
+ goto out;
+ }
+
+ skb->dst = dst_clone(dst);
+
+ skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+
+ hdr = (struct ipv6hdr *) skb->tail;
+ skb->nh.ipv6h = hdr;
+
+ if (!sk->ip_hdrincl) {
+ ip6_bld_1(sk, skb, fl, hlimit,
+ jumbolen ? sizeof(struct ipv6hdr) : pktlength);
+
+ if (opt || jumbolen) {
+ u8 *prev_hdr = &hdr->nexthdr;
+ prev_hdr = ipv6_build_nfrag_opts(skb, prev_hdr, opt, final_dst, jumbolen);
+ if (opt && opt->opt_flen)
+ ipv6_build_frag_opts(skb, prev_hdr, opt);
+ }
+ }
+
+ skb_put(skb, length);
+ err = getfrag(data, &hdr->saddr,
+ ((char *) hdr) + (pktlength - length),
+ 0, length);
+
+ if (!err) {
+ ipv6_statistics.Ip6OutRequests++;
+ dst->output(skb);
+ } else {
+ err = -EFAULT;
+ kfree_skb(skb);
+ }
+ } else {
+ if (sk->ip_hdrincl || jumbolen ||
+ np->pmtudisc == IPV6_PMTUDISC_DO) {
+ ipv6_local_error(sk, EMSGSIZE, fl, mtu);
+ err = -EMSGSIZE;
+ goto out;
+ }
+
+ err = ip6_frag_xmit(sk, getfrag, data, dst, fl, opt, final_dst, hlimit,
+ flags, length, mtu);
+ }
+
+ /*
+ * cleanup
+ */
+out:
+ ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
+ return err;
+}
+
+int ip6_call_ra_chain(struct sk_buff *skb, int sel)
+{
+ struct ip6_ra_chain *ra;
+ struct sock *last = NULL;
+
+ for (ra = ip6_ra_chain; ra; ra = ra->next) {
+ struct sock *sk = ra->sk;
+ if (sk && ra->sel == sel) {
+ if (last) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2)
+ rawv6_rcv(last, skb2, skb2->len);
+ }
+ last = sk;
+ }
+ }
+
+ if (last) {
+ rawv6_rcv(last, skb, skb->len);
+ return 1;
+ }
+ return 0;
+}
+
+int ip6_forward(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb->dst;
+ struct ipv6hdr *hdr = skb->nh.ipv6h;
+ struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb;
+
+ if (ipv6_devconf.forwarding == 0 && opt->srcrt == 0)
+ goto drop;
+
+ /*
+ * We DO NOT make any processing on
+ * RA packets, pushing them to user level AS IS
+ * without ane WARRANTY that application will be able
+ * to interpret them. The reason is that we
+ * cannot make anything clever here.
+ *
+ * We are not end-node, so that if packet contains
+ * AH/ESP, we cannot make anything.
+ * Defragmentation also would be mistake, RA packets
+ * cannot be fragmented, because there is no warranty
+ * that different fragments will go along one path. --ANK
+ */
+ if (opt->ra) {
+ u8 *ptr = skb->nh.raw + opt->ra;
+ if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3]))
+ return 0;
+ }
+
+ /*
+ * check and decrement ttl
+ */
+ if (hdr->hop_limit <= 1) {
+ /* Force OUTPUT device used as source address */
+ skb->dev = dst->dev;
+ icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
+ 0, skb->dev);
+
+ kfree_skb(skb);
+ return -ETIMEDOUT;
+ }
+
+ /* IPv6 specs say nothing about it, but it is clear that we cannot
+ send redirects to source routed frames.
+ */
+ if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0) {
+ struct in6_addr *target = NULL;
+ struct rt6_info *rt;
+ struct neighbour *n = dst->neighbour;
+
+ /*
+ * incoming and outgoing devices are the same
+ * send a redirect.
+ */
+
+ rt = (struct rt6_info *) dst;
+ if ((rt->rt6i_flags & RTF_GATEWAY))
+ target = (struct in6_addr*)&n->primary_key;
+ else
+ target = &hdr->daddr;
+
+ /* Limit redirects both by destination (here)
+ and by source (inside ndisc_send_redirect)
+ */
+ if (xrlim_allow(dst, 1*HZ))
+ ndisc_send_redirect(skb, n, target);
+ } else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK
+ |IPV6_ADDR_LINKLOCAL)) {
+ /* This check is security critical. */
+ goto drop;
+ }
+
+ if (skb->len > dst->pmtu) {
+ /* Again, force OUTPUT device used as source address */
+ skb->dev = dst->dev;
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
+ ipv6_statistics.Ip6InTooBigErrors++;
+ kfree_skb(skb);
+ return -EMSGSIZE;
+ }
+
+ if ((skb = skb_cow(skb, dst->dev->hard_header_len)) == NULL)
+ return 0;
+
+ hdr = skb->nh.ipv6h;
+
+ /* Mangling hops number delayed to point after skb COW */
+
+ hdr->hop_limit--;
+
+ ipv6_statistics.Ip6OutForwDatagrams++;
+ return dst->output(skb);
+
+drop:
+ ipv6_statistics.Ip6InAddrErrors++;
+ kfree_skb(skb);
+ return -EINVAL;
+}
diff --git a/pfinet/linux-src/net/ipv6/ipv6_sockglue.c b/pfinet/linux-src/net/ipv6/ipv6_sockglue.c
new file mode 100644
index 00000000..6a48d1be
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/ipv6_sockglue.c
@@ -0,0 +1,439 @@
+/*
+ * IPv6 BSD socket options interface
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Based on linux/net/ipv4/ip_sockglue.c
+ *
+ * $Id: ipv6_sockglue.c,v 1.1 2007/10/08 21:12:30 stesie Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * FIXME: Make the setsockopt code POSIX compliant: That is
+ *
+ * o Return -EINVAL for setsockopt of short lengths
+ * o Truncate getsockopt returns
+ * o Return an optlen of the truncated length if need be
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/inet_common.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+#include <asm/uaccess.h>
+
+struct ipv6_mib ipv6_statistics={0, };
+struct packet_type ipv6_packet_type =
+{
+ __constant_htons(ETH_P_IPV6),
+ NULL, /* All devices */
+ ipv6_rcv,
+ NULL,
+ NULL
+};
+
+/*
+ * addrconf module should be notifyed of a device going up
+ */
+static struct notifier_block ipv6_dev_notf = {
+ addrconf_notify,
+ NULL,
+ 0
+};
+
+struct ip6_ra_chain *ip6_ra_chain;
+
+int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
+{
+ struct ip6_ra_chain *ra, *new_ra, **rap;
+
+ /* RA packet may be delivered ONLY to IPPROTO_RAW socket */
+ if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW)
+ return -EINVAL;
+
+ new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+
+ for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+ if (ra->sk == sk) {
+ if (sel>=0) {
+ if (new_ra)
+ kfree(new_ra);
+ return -EADDRINUSE;
+ }
+
+ *rap = ra->next;
+ synchronize_bh();
+
+ if (ra->destructor)
+ ra->destructor(sk);
+ kfree(ra);
+ return 0;
+ }
+ }
+ if (new_ra == NULL)
+ return -ENOBUFS;
+ new_ra->sk = sk;
+ new_ra->sel = sel;
+ new_ra->destructor = destructor;
+ start_bh_atomic();
+ new_ra->next = ra;
+ *rap = new_ra;
+ end_bh_atomic();
+ return 0;
+}
+
+
+int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
+ int optlen)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ int val, valbool;
+ int retv = -ENOPROTOOPT;
+
+ if(level==SOL_IP && sk->type != SOCK_RAW)
+ return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+
+ if(level!=SOL_IPV6)
+ goto out;
+
+ if (optval == NULL)
+ val=0;
+ else if (get_user(val, (int *) optval))
+ return -EFAULT;
+
+ valbool = (val!=0);
+
+ switch (optname) {
+
+ case IPV6_ADDRFORM:
+ if (val == PF_INET) {
+ struct ipv6_txoptions *opt;
+ struct sk_buff *pktopt;
+
+ if (sk->protocol != IPPROTO_UDP &&
+ sk->protocol != IPPROTO_TCP)
+ goto out;
+
+ lock_sock(sk);
+ if (sk->state != TCP_ESTABLISHED) {
+ retv = ENOTCONN;
+ goto addrform_done;
+ }
+
+ if (!(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
+ retv = -EADDRNOTAVAIL;
+ goto addrform_done;
+ }
+
+ fl6_free_socklist(sk);
+ ipv6_sock_mc_close(sk);
+
+ if (sk->protocol == IPPROTO_TCP) {
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ sk->prot = &tcp_prot;
+ tp->af_specific = &ipv4_specific;
+ sk->socket->ops = &inet_stream_ops;
+ sk->family = PF_INET;
+ tcp_sync_mss(sk, tp->pmtu_cookie);
+ } else {
+ sk->prot = &udp_prot;
+ sk->socket->ops = &inet_dgram_ops;
+ }
+ opt = xchg(&np->opt, NULL);
+ if (opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+ pktopt = xchg(&np->pktoptions, NULL);
+ if (pktopt)
+ kfree_skb(pktopt);
+ retv = 0;
+
+addrform_done:
+ release_sock(sk);
+ } else {
+ retv = -EINVAL;
+ }
+ break;
+
+ case IPV6_PKTINFO:
+ np->rxopt.bits.rxinfo = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_HOPLIMIT:
+ np->rxopt.bits.rxhlim = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_RTHDR:
+ retv = -EINVAL;
+ if (val >= 0 && val <= 2) {
+ np->rxopt.bits.srcrt = val;
+ retv = 0;
+ }
+ break;
+
+ case IPV6_HOPOPTS:
+ np->rxopt.bits.hopopts = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_AUTHHDR:
+ np->rxopt.bits.authhdr = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_DSTOPTS:
+ np->rxopt.bits.dstopts = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_FLOWINFO:
+ np->rxopt.bits.rxflow = valbool;
+ return 0;
+
+ case IPV6_PKTOPTIONS:
+ {
+ struct ipv6_txoptions *opt = NULL;
+ struct msghdr msg;
+ struct flowi fl;
+ int junk;
+
+ fl.fl6_flowlabel = 0;
+ fl.oif = sk->bound_dev_if;
+
+ if (optlen == 0)
+ goto update;
+
+ opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
+ retv = -ENOBUFS;
+ if (opt == NULL)
+ break;
+
+ memset(opt, 0, sizeof(*opt));
+ opt->tot_len = sizeof(*opt) + optlen;
+ retv = -EFAULT;
+ if (copy_from_user(opt+1, optval, optlen))
+ goto done;
+
+ msg.msg_controllen = optlen;
+ msg.msg_control = (void*)(opt+1);
+
+ retv = datagram_send_ctl(&msg, &fl, opt, &junk);
+ if (retv)
+ goto done;
+update:
+ retv = 0;
+ start_bh_atomic();
+ if (opt && sk->type == SOCK_STREAM) {
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ if ((tcp_connected(sk->state) || sk->state == TCP_SYN_SENT)
+ && sk->daddr != LOOPBACK4_IPV6) {
+ tp->ext_header_len = opt->opt_flen + opt->opt_nflen;
+ tcp_sync_mss(sk, tp->pmtu_cookie);
+ }
+ }
+ opt = xchg(&np->opt, opt);
+ dst_release(xchg(&sk->dst_cache, NULL));
+ end_bh_atomic();
+
+done:
+ if (opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+ break;
+ }
+ case IPV6_UNICAST_HOPS:
+ if (val > 255 || val < -1)
+ retv = -EINVAL;
+ else {
+ np->hop_limit = val;
+ retv = 0;
+ }
+ break;
+
+ case IPV6_MULTICAST_HOPS:
+ if (val > 255 || val < -1)
+ retv = -EINVAL;
+ else {
+ np->mcast_hops = val;
+ retv = 0;
+ }
+ break;
+
+ case IPV6_MULTICAST_LOOP:
+ np->mc_loop = valbool;
+ retv = 0;
+ break;
+
+ case IPV6_MULTICAST_IF:
+ if (sk->bound_dev_if && sk->bound_dev_if != val) {
+ retv = -EINVAL;
+ break;
+ }
+ if (dev_get_by_index(val) == NULL) {
+ retv = -ENODEV;
+ break;
+ }
+ np->mcast_oif = val;
+ retv = 0;
+ break;
+ case IPV6_ADD_MEMBERSHIP:
+ case IPV6_DROP_MEMBERSHIP:
+ {
+ struct ipv6_mreq mreq;
+
+ if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
+ return -EFAULT;
+
+ if (optname == IPV6_ADD_MEMBERSHIP)
+ retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
+ else
+ retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
+ break;
+ }
+ case IPV6_ROUTER_ALERT:
+ retv = ip6_ra_control(sk, val, NULL);
+ break;
+ case IPV6_MTU_DISCOVER:
+ if (val<0 || val>2)
+ return -EINVAL;
+ np->pmtudisc = val;
+ return 0;
+ case IPV6_MTU:
+ if (val && val < IPV6_MIN_MTU)
+ return -EINVAL;
+ np->frag_size = val;
+ return 0;
+ case IPV6_RECVERR:
+ np->recverr = valbool;
+ if (!val)
+ skb_queue_purge(&sk->error_queue);
+ return 0;
+ case IPV6_FLOWINFO_SEND:
+ np->sndflow = valbool;
+ return 0;
+ case IPV6_FLOWLABEL_MGR:
+ return ipv6_flowlabel_opt(sk, optval, optlen);
+ };
+
+out:
+ return retv;
+}
+
+int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
+ int *optlen)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ int len;
+ int val;
+
+ if(level==SOL_IP && sk->type != SOCK_RAW)
+ return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+ if(level!=SOL_IPV6)
+ return -ENOPROTOOPT;
+ if (get_user(len, optlen))
+ return -EFAULT;
+ switch (optname) {
+ case IPV6_PKTOPTIONS:
+ {
+ struct msghdr msg;
+ struct sk_buff *skb;
+
+ start_bh_atomic();
+ skb = np->pktoptions;
+ if (skb)
+ atomic_inc(&skb->users);
+ end_bh_atomic();
+
+ if (skb) {
+ int err;
+
+ msg.msg_control = optval;
+ msg.msg_controllen = len;
+ msg.msg_flags = 0;
+ err = datagram_recv_ctl(sk, &msg, skb);
+ kfree_skb(skb);
+ if (err)
+ return err;
+ len -= msg.msg_controllen;
+ } else
+ len = 0;
+ return put_user(len, optlen);
+ }
+ case IP_MTU:
+ val = 0;
+ lock_sock(sk);
+ if (sk->dst_cache)
+ val = sk->dst_cache->pmtu;
+ release_sock(sk);
+ if (!val)
+ return -ENOTCONN;
+ break;
+ default:
+ return -EINVAL;
+ }
+ len=min(sizeof(int),len);
+ if(put_user(len, optlen))
+ return -EFAULT;
+ if(copy_to_user(optval,&val,len))
+ return -EFAULT;
+ return 0;
+}
+
+#if defined(MODULE) && defined(CONFIG_SYSCTL)
+
+/*
+ * sysctl registration functions defined in sysctl_net_ipv6.c
+ */
+
+extern void ipv6_sysctl_register(void);
+extern void ipv6_sysctl_unregister(void);
+#endif
+
+__initfunc(void ipv6_packet_init(void))
+{
+ dev_add_pack(&ipv6_packet_type);
+}
+
+__initfunc(void ipv6_netdev_notif_init(void))
+{
+ register_netdevice_notifier(&ipv6_dev_notf);
+}
+
+#ifdef MODULE
+void ipv6_packet_cleanup(void)
+{
+ dev_remove_pack(&ipv6_packet_type);
+}
+
+void ipv6_netdev_notif_cleanup(void)
+{
+ unregister_netdevice_notifier(&ipv6_dev_notf);
+}
+#endif
diff --git a/pfinet/linux-src/net/ipv6/mcast.c b/pfinet/linux-src/net/ipv6/mcast.c
new file mode 100644
index 00000000..87e9e909
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/mcast.c
@@ -0,0 +1,711 @@
+/*
+ * Multicast support for IPv6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: mcast.c,v 1.2 2007/10/08 21:59:10 stesie Exp $
+ *
+ * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/if_inet6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+
+#include <net/checksum.h>
+
+/* Set to 3 to get tracing... */
+#define MCAST_DEBUG 2
+
+#if MCAST_DEBUG >= 3
+#define MDBG(x) printk x
+#else
+#define MDBG(x)
+#endif
+
+static struct socket *igmp6_socket;
+
+static void igmp6_join_group(struct ifmcaddr6 *ma);
+static void igmp6_leave_group(struct ifmcaddr6 *ma);
+void igmp6_timer_handler(unsigned long data);
+
+#define IGMP6_UNSOLICITED_IVAL (10*HZ)
+
+/*
+ * Hash list of configured multicast addresses
+ */
+static struct ifmcaddr6 *inet6_mcast_lst[IN6_ADDR_HSIZE];
+
+/*
+ * socket join on multicast group
+ */
+
+int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
+{
+ struct device *dev = NULL;
+ struct ipv6_mc_socklist *mc_lst;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ int err;
+
+ if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST))
+ return -EINVAL;
+
+ mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
+
+ if (mc_lst == NULL)
+ return -ENOMEM;
+
+ mc_lst->next = NULL;
+ memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr));
+ mc_lst->ifindex = ifindex;
+
+ if (ifindex == 0) {
+ struct rt6_info *rt;
+ rt = rt6_lookup(addr, NULL, 0, 0);
+ if (rt) {
+ dev = rt->rt6i_dev;
+ dst_release(&rt->u.dst);
+ }
+ } else
+ dev = dev_get_by_index(ifindex);
+
+ if (dev == NULL) {
+ sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
+ return -ENODEV;
+ }
+
+ /*
+ * now add/increase the group membership on the device
+ */
+
+ err = ipv6_dev_mc_inc(dev, addr);
+
+ if (err) {
+ sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
+ return err;
+ }
+
+ mc_lst->next = np->ipv6_mc_list;
+ np->ipv6_mc_list = mc_lst;
+
+ return 0;
+}
+
+/*
+ * socket leave on multicast group
+ */
+int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct ipv6_mc_socklist *mc_lst, **lnk;
+
+ for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
+ if (mc_lst->ifindex == ifindex &&
+ ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {
+ struct device *dev;
+
+ *lnk = mc_lst->next;
+ synchronize_bh();
+
+ if ((dev = dev_get_by_index(ifindex)) != NULL)
+ ipv6_dev_mc_dec(dev, &mc_lst->addr);
+ sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+void ipv6_sock_mc_close(struct sock *sk)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct ipv6_mc_socklist *mc_lst;
+
+ while ((mc_lst = np->ipv6_mc_list) != NULL) {
+ struct device *dev = dev_get_by_index(mc_lst->ifindex);
+
+ if (dev)
+ ipv6_dev_mc_dec(dev, &mc_lst->addr);
+
+ np->ipv6_mc_list = mc_lst->next;
+ sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
+ }
+}
+
+static int igmp6_group_added(struct ifmcaddr6 *mc)
+{
+ char buf[MAX_ADDR_LEN];
+
+ if (!(mc->mca_flags&MAF_LOADED)) {
+ mc->mca_flags |= MAF_LOADED;
+ if (ndisc_mc_map(&mc->mca_addr, buf, mc->dev, 0) == 0)
+ dev_mc_add(mc->dev, buf, mc->dev->addr_len, 0);
+ }
+
+ if (mc->dev->flags&IFF_UP)
+ igmp6_join_group(mc);
+ return 0;
+}
+
+static int igmp6_group_dropped(struct ifmcaddr6 *mc)
+{
+ char buf[MAX_ADDR_LEN];
+
+ if (mc->mca_flags&MAF_LOADED) {
+ mc->mca_flags &= ~MAF_LOADED;
+ if (ndisc_mc_map(&mc->mca_addr, buf, mc->dev, 0) == 0)
+ dev_mc_delete(mc->dev, buf, mc->dev->addr_len, 0);
+ }
+
+ if (mc->dev->flags&IFF_UP)
+ igmp6_leave_group(mc);
+ return 0;
+}
+
+
+/*
+ * device multicast group inc (add if not found)
+ */
+int ipv6_dev_mc_inc(struct device *dev, struct in6_addr *addr)
+{
+ struct ifmcaddr6 *mc;
+ struct inet6_dev *idev;
+ int hash;
+
+ idev = ipv6_get_idev(dev);
+
+ if (idev == NULL)
+ return -EINVAL;
+
+ hash = ipv6_addr_hash(addr);
+
+ for (mc = inet6_mcast_lst[hash]; mc; mc = mc->next) {
+ if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0 && mc->dev == dev) {
+ atomic_inc(&mc->mca_users);
+ return 0;
+ }
+ }
+
+ /*
+ * not found: create a new one.
+ */
+
+ mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
+
+ if (mc == NULL)
+ return -ENOMEM;
+
+ memset(mc, 0, sizeof(struct ifmcaddr6));
+ mc->mca_timer.function = igmp6_timer_handler;
+ mc->mca_timer.data = (unsigned long) mc;
+
+ memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
+ mc->dev = dev;
+ atomic_set(&mc->mca_users, 1);
+
+ mc->next = inet6_mcast_lst[hash];
+ inet6_mcast_lst[hash] = mc;
+
+ mc->if_next = idev->mc_list;
+ idev->mc_list = mc;
+
+ igmp6_group_added(mc);
+
+ return 0;
+}
+
+static void ipv6_mca_remove(struct device *dev, struct ifmcaddr6 *ma)
+{
+ struct inet6_dev *idev;
+
+ idev = ipv6_get_idev(dev);
+
+ if (idev) {
+ struct ifmcaddr6 *iter, **lnk;
+
+ for (lnk = &idev->mc_list; (iter = *lnk) != NULL; lnk = &iter->if_next) {
+ if (iter == ma) {
+ *lnk = iter->if_next;
+ synchronize_bh();
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * device multicast group del
+ */
+int ipv6_dev_mc_dec(struct device *dev, struct in6_addr *addr)
+{
+ struct ifmcaddr6 *ma, **lnk;
+ int hash;
+
+ hash = ipv6_addr_hash(addr);
+
+ for (lnk = &inet6_mcast_lst[hash]; (ma=*lnk) != NULL; lnk = &ma->next) {
+ if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0 && ma->dev == dev) {
+ if (atomic_dec_and_test(&ma->mca_users)) {
+ igmp6_group_dropped(ma);
+
+ *lnk = ma->next;
+ synchronize_bh();
+
+ ipv6_mca_remove(dev, ma);
+ kfree(ma);
+ }
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/*
+ * check if the interface/address pair is valid
+ */
+int ipv6_chk_mcast_addr(struct device *dev, struct in6_addr *addr)
+{
+ struct ifmcaddr6 *mc;
+ int hash;
+
+ hash = ipv6_addr_hash(addr);
+
+ for (mc = inet6_mcast_lst[hash]; mc; mc=mc->next) {
+ if (mc->dev == dev && ipv6_addr_cmp(&mc->mca_addr, addr) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * IGMP handling (alias multicast ICMPv6 messages)
+ */
+
+static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
+{
+ unsigned long delay = resptime;
+
+ /* Do not start timer for addresses with link/host scope */
+ if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))
+ return;
+
+ if (del_timer(&ma->mca_timer))
+ delay = ma->mca_timer.expires - jiffies;
+
+ if (delay >= resptime) {
+ if (resptime)
+ delay = net_random() % resptime;
+ else
+ delay = 1;
+ }
+
+ ma->mca_flags |= MAF_TIMER_RUNNING;
+ ma->mca_timer.expires = jiffies + delay;
+ add_timer(&ma->mca_timer);
+}
+
+int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
+{
+ struct ifmcaddr6 *ma;
+ struct in6_addr *addrp;
+ unsigned long resptime;
+
+ if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
+ return -EINVAL;
+
+ /* Drop queries with not link local source */
+ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
+ return -EINVAL;
+
+ resptime = ntohs(hdr->icmp6_maxdelay);
+ /* Translate milliseconds to jiffies */
+ resptime = (resptime<<10)/(1024000/HZ);
+
+ addrp = (struct in6_addr *) (hdr + 1);
+
+ if (ipv6_addr_any(addrp)) {
+ struct inet6_dev *idev;
+
+ idev = ipv6_get_idev(skb->dev);
+
+ if (idev == NULL)
+ return 0;
+
+ for (ma = idev->mc_list; ma; ma=ma->if_next)
+ igmp6_group_queried(ma, resptime);
+ } else {
+ int hash = ipv6_addr_hash(addrp);
+
+ for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) {
+ if (ma->dev == skb->dev &&
+ ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
+ igmp6_group_queried(ma, resptime);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
+{
+ struct ifmcaddr6 *ma;
+ struct in6_addr *addrp;
+ struct device *dev;
+ int hash;
+
+ /* Our own report looped back. Ignore it. */
+ if (skb->pkt_type == PACKET_LOOPBACK)
+ return 0;
+
+ if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
+ return -EINVAL;
+
+ /* Drop reports with not link local source */
+ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
+ return -EINVAL;
+
+ addrp = (struct in6_addr *) (hdr + 1);
+
+ dev = skb->dev;
+
+ /*
+ * Cancel the timer for this group
+ */
+
+ hash = ipv6_addr_hash(addrp);
+
+ for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) {
+ if ((ma->dev == dev) && ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
+ if (ma->mca_flags & MAF_TIMER_RUNNING) {
+ del_timer(&ma->mca_timer);
+ ma->mca_flags &= ~MAF_TIMER_RUNNING;
+ }
+
+ ma->mca_flags &= ~MAF_LAST_REPORTER;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void igmp6_send(struct in6_addr *addr, struct device *dev, int type)
+{
+ struct sock *sk = igmp6_socket->sk;
+ struct sk_buff *skb;
+ struct icmp6hdr *hdr;
+ struct inet6_ifaddr *ifp;
+ struct in6_addr *snd_addr;
+ struct in6_addr *addrp;
+ struct in6_addr all_routers;
+ int err, len, payload_len, full_len;
+ u8 ra[8] = { IPPROTO_ICMPV6, 0,
+ IPV6_TLV_ROUTERALERT, 0, 0, 0,
+ IPV6_TLV_PADN, 0 };
+
+ snd_addr = addr;
+ if (type == ICMPV6_MGM_REDUCTION) {
+ snd_addr = &all_routers;
+ ipv6_addr_all_routers(&all_routers);
+ }
+
+ len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+ payload_len = len + sizeof(ra);
+ full_len = sizeof(struct ipv6hdr) + payload_len;
+
+ skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, 0, &err);
+
+ if (skb == NULL)
+ return;
+
+ skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+ if (dev->hard_header) {
+ unsigned char ha[MAX_ADDR_LEN];
+ ndisc_mc_map(snd_addr, ha, dev, 1);
+ dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len);
+ }
+
+ ifp = ipv6_get_lladdr(dev);
+
+ if (ifp == NULL) {
+#if MCAST_DEBUG >= 1
+ printk(KERN_DEBUG "igmp6: %s no linklocal address\n",
+ dev->name);
+#endif
+ return;
+ }
+
+ ip6_nd_hdr(sk, skb, dev, &ifp->addr, snd_addr, NEXTHDR_HOP, payload_len);
+
+ memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
+
+ hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
+ memset(hdr, 0, sizeof(struct icmp6hdr));
+ hdr->icmp6_type = type;
+
+ addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
+ ipv6_addr_copy(addrp, addr);
+
+ hdr->icmp6_cksum = csum_ipv6_magic(&ifp->addr, snd_addr, len,
+ IPPROTO_ICMPV6,
+ csum_partial((__u8 *) hdr, len, 0));
+
+ dev_queue_xmit(skb);
+ if (type == ICMPV6_MGM_REDUCTION)
+ icmpv6_statistics.Icmp6OutGroupMembReductions++;
+ else
+ icmpv6_statistics.Icmp6OutGroupMembResponses++;
+ icmpv6_statistics.Icmp6OutMsgs++;
+}
+
+static void igmp6_join_group(struct ifmcaddr6 *ma)
+{
+ unsigned long delay;
+ int addr_type;
+
+ addr_type = ipv6_addr_type(&ma->mca_addr);
+
+ if ((addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK)))
+ return;
+
+ start_bh_atomic();
+ igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT);
+
+ delay = net_random() % IGMP6_UNSOLICITED_IVAL;
+ if (del_timer(&ma->mca_timer))
+ delay = ma->mca_timer.expires - jiffies;
+
+ ma->mca_timer.expires = jiffies + delay;
+
+ add_timer(&ma->mca_timer);
+ ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
+ end_bh_atomic();
+}
+
+static void igmp6_leave_group(struct ifmcaddr6 *ma)
+{
+ int addr_type;
+
+ addr_type = ipv6_addr_type(&ma->mca_addr);
+
+ if ((addr_type & IPV6_ADDR_LINKLOCAL))
+ return;
+
+ start_bh_atomic();
+ if (ma->mca_flags & MAF_LAST_REPORTER)
+ igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REDUCTION);
+
+ if (ma->mca_flags & MAF_TIMER_RUNNING)
+ del_timer(&ma->mca_timer);
+ end_bh_atomic();
+}
+
+void igmp6_timer_handler(unsigned long data)
+{
+ struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
+
+ ma->mca_flags |= MAF_LAST_REPORTER;
+ igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT);
+ ma->mca_flags &= ~MAF_TIMER_RUNNING;
+}
+
+/* Device going down */
+
+void ipv6_mc_down(struct inet6_dev *idev)
+{
+ struct ifmcaddr6 *i;
+ struct in6_addr maddr;
+
+ /* Withdraw multicast list */
+
+ for (i = idev->mc_list; i; i=i->if_next)
+ igmp6_group_dropped(i);
+
+ /* Delete all-nodes address. */
+
+ ipv6_addr_all_nodes(&maddr);
+ ipv6_dev_mc_dec(idev->dev, &maddr);
+}
+
+/* Device going up */
+
+void ipv6_mc_up(struct inet6_dev *idev)
+{
+ struct ifmcaddr6 *i;
+ struct in6_addr maddr;
+
+ /* Add all-nodes address. */
+
+ ipv6_addr_all_nodes(&maddr);
+ ipv6_dev_mc_inc(idev->dev, &maddr);
+
+ /* Install multicast list, except for all-nodes (already installed) */
+
+ for (i = idev->mc_list; i; i=i->if_next)
+ igmp6_group_added(i);
+}
+
+/*
+ * Device is about to be destroyed: clean up.
+ */
+
+void ipv6_mc_destroy_dev(struct inet6_dev *idev)
+{
+ int hash;
+ struct ifmcaddr6 *i, **lnk;
+
+ while ((i = idev->mc_list) != NULL) {
+ idev->mc_list = i->if_next;
+
+ hash = ipv6_addr_hash(&i->mca_addr);
+
+ for (lnk = &inet6_mcast_lst[hash]; *lnk; lnk = &(*lnk)->next) {
+ if (*lnk == i) {
+ *lnk = i->next;
+ synchronize_bh();
+ break;
+ }
+ }
+ igmp6_group_dropped(i);
+ kfree(i);
+ }
+}
+
+#ifdef CONFIG_PROC_FS
+static int igmp6_read_proc(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
+{
+ off_t pos=0, begin=0;
+ struct ifmcaddr6 *im;
+ int len=0;
+ struct device *dev;
+
+ for (dev = dev_base; dev; dev = dev->next) {
+ struct inet6_dev *idev;
+
+ if ((idev = ipv6_get_idev(dev)) == NULL)
+ continue;
+
+ for (im = idev->mc_list; im; im = im->if_next) {
+ int i;
+
+ len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
+
+ for (i=0; i<16; i++)
+ len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]);
+
+ len+=sprintf(buffer+len,
+ " %5d %08X %ld\n",
+ atomic_read(&im->mca_users),
+ im->mca_flags,
+ (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);
+
+ pos=begin+len;
+ if (pos < offset) {
+ len=0;
+ begin=pos;
+ }
+ if (pos > offset+length)
+ goto done;
+ }
+ }
+ *eof = 1;
+
+done:
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ if (len<0)
+ len=0;
+ return len;
+}
+#endif
+
+__initfunc(int igmp6_init(struct net_proto_family *ops))
+{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent;
+#endif
+ struct sock *sk;
+ int err;
+
+ igmp6_socket = sock_alloc();
+ if (igmp6_socket == NULL) {
+ printk(KERN_ERR
+ "Failed to create the IGMP6 control socket.\n");
+ return -1;
+ }
+#ifndef _HURD_
+ igmp6_socket->inode->i_uid = 0;
+ igmp6_socket->inode->i_gid = 0;
+#endif
+ igmp6_socket->type = SOCK_RAW;
+
+ if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) {
+ printk(KERN_DEBUG
+ "Failed to initialize the IGMP6 control socket (err %d).\n",
+ err);
+ sock_release(igmp6_socket);
+ igmp6_socket = NULL; /* For safety. */
+ return err;
+ }
+
+ sk = igmp6_socket->sk;
+ sk->allocation = GFP_ATOMIC;
+ sk->num = 256; /* Don't receive any data */
+
+ sk->net_pinfo.af_inet6.hop_limit = 1;
+#ifdef CONFIG_PROC_FS
+ ent = create_proc_entry("net/igmp6", 0, 0);
+ ent->read_proc = igmp6_read_proc;
+#endif
+
+ return 0;
+}
+
+#ifdef MODULE
+void igmp6_cleanup(void)
+{
+ sock_release(igmp6_socket);
+ igmp6_socket = NULL; /* for safety */
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("net/igmp6", 0);
+#endif
+}
+#endif
diff --git a/pfinet/linux-src/net/ipv6/ndisc.c b/pfinet/linux-src/net/ipv6/ndisc.c
new file mode 100644
index 00000000..61f950d2
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/ndisc.c
@@ -0,0 +1,1217 @@
+/*
+ * Neighbour Discovery for IPv6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ * Mike Shaver <shaver@ingenia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Changes:
+ *
+ * Lars Fenneberg : fixed MTU setting on receipt
+ * of an RA.
+ *
+ * Janos Farkas : kmalloc failure checks
+ * Alexey Kuznetsov : state machine reworked
+ * and moved to net/core.
+ */
+
+/* Set to 3 to get tracing... */
+#define ND_DEBUG 1
+
+#define ND_PRINTK(x...) printk(KERN_DEBUG x)
+#define ND_NOPRINTK(x...) do { ; } while(0)
+#define ND_PRINTK0 ND_PRINTK
+#define ND_PRINTK1 ND_NOPRINTK
+#define ND_PRINTK2 ND_NOPRINTK
+#if ND_DEBUG >= 1
+#undef ND_PRINTK1
+#define ND_PRINTK1 ND_PRINTK
+#endif
+#if ND_DEBUG >= 2
+#undef ND_PRINTK2
+#define ND_PRINTK2 ND_PRINTK
+#endif
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/route.h>
+#include <linux/init.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+
+#include <linux/if_arp.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/icmp.h>
+
+#include <net/checksum.h>
+#include <linux/proc_fs.h>
+
+static struct socket *ndisc_socket;
+
+static int ndisc_constructor(struct neighbour *neigh);
+static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
+static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb);
+static int pndisc_constructor(struct pneigh_entry *n);
+static void pndisc_destructor(struct pneigh_entry *n);
+static void pndisc_redo(struct sk_buff *skb);
+
+static struct neigh_ops ndisc_generic_ops =
+{
+ AF_INET6,
+ NULL,
+ ndisc_solicit,
+ ndisc_error_report,
+ neigh_resolve_output,
+ neigh_connected_output,
+ dev_queue_xmit,
+ dev_queue_xmit
+};
+
+static struct neigh_ops ndisc_hh_ops =
+{
+ AF_INET6,
+ NULL,
+ ndisc_solicit,
+ ndisc_error_report,
+ neigh_resolve_output,
+ neigh_resolve_output,
+ dev_queue_xmit,
+ dev_queue_xmit
+};
+
+
+static struct neigh_ops ndisc_direct_ops =
+{
+ AF_INET6,
+ NULL,
+ NULL,
+ NULL,
+ dev_queue_xmit,
+ dev_queue_xmit,
+ dev_queue_xmit,
+ dev_queue_xmit
+};
+
+struct neigh_table nd_tbl =
+{
+ NULL,
+ AF_INET6,
+ sizeof(struct neighbour) + sizeof(struct in6_addr),
+ sizeof(struct in6_addr),
+ ndisc_constructor,
+ pndisc_constructor,
+ pndisc_destructor,
+ pndisc_redo,
+ { NULL, NULL, &nd_tbl, 0, NULL, NULL,
+ 30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 0 },
+ 30*HZ, 128, 512, 1024,
+};
+
+#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
+
+static u8 *ndisc_fill_option(u8 *opt, int type, void *data, int data_len)
+{
+ int space = NDISC_OPT_SPACE(data_len);
+
+ opt[0] = type;
+ opt[1] = space>>3;
+ memcpy(opt+2, data, data_len);
+ data_len += 2;
+ opt += data_len;
+ if ((space -= data_len) > 0)
+ memset(opt, 0, space);
+ return opt + space;
+}
+
+int ndisc_mc_map(struct in6_addr *addr, char *buf, struct device *dev, int dir)
+{
+ switch (dev->type) {
+ case ARPHRD_ETHER:
+ case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */
+ case ARPHRD_FDDI:
+ ipv6_eth_mc_map(addr, buf);
+ return 0;
+ default:
+ if (dir) {
+ memcpy(buf, dev->broadcast, dev->addr_len);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int ndisc_constructor(struct neighbour *neigh)
+{
+ struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
+ struct device *dev = neigh->dev;
+ struct inet6_dev *in6_dev = ipv6_get_idev(dev);
+ int addr_type;
+
+ if (in6_dev == NULL)
+ return -EINVAL;
+
+ addr_type = ipv6_addr_type(addr);
+ if (in6_dev->nd_parms)
+ neigh->parms = in6_dev->nd_parms;
+
+ if (addr_type&IPV6_ADDR_MULTICAST)
+ neigh->type = RTN_MULTICAST;
+ else
+ neigh->type = RTN_UNICAST;
+ if (dev->hard_header == NULL) {
+ neigh->nud_state = NUD_NOARP;
+ neigh->ops = &ndisc_direct_ops;
+ neigh->output = neigh->ops->queue_xmit;
+ } else {
+ if (addr_type&IPV6_ADDR_MULTICAST) {
+ neigh->nud_state = NUD_NOARP;
+ ndisc_mc_map(addr, neigh->ha, dev, 1);
+ } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
+ neigh->nud_state = NUD_NOARP;
+ memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
+ if (dev->flags&IFF_LOOPBACK)
+ neigh->type = RTN_LOCAL;
+ } else if (dev->flags&IFF_POINTOPOINT) {
+ neigh->nud_state = NUD_NOARP;
+ memcpy(neigh->ha, dev->broadcast, dev->addr_len);
+ }
+ if (dev->hard_header_cache)
+ neigh->ops = &ndisc_hh_ops;
+ else
+ neigh->ops = &ndisc_generic_ops;
+ if (neigh->nud_state&NUD_VALID)
+ neigh->output = neigh->ops->connected_output;
+ else
+ neigh->output = neigh->ops->output;
+ }
+
+ return 0;
+}
+
+static int pndisc_constructor(struct pneigh_entry *n)
+{
+ struct in6_addr *addr = (struct in6_addr*)&n->key;
+ struct in6_addr maddr;
+ struct device *dev = n->dev;
+
+ if (dev == NULL || ipv6_get_idev(dev) == NULL)
+ return -EINVAL;
+#ifndef CONFIG_IPV6_NO_PB
+ addrconf_addr_solict_mult_old(addr, &maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+#endif
+#ifdef CONFIG_IPV6_EUI64
+ addrconf_addr_solict_mult_new(addr, &maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+#endif
+ return 0;
+}
+
+static void pndisc_destructor(struct pneigh_entry *n)
+{
+ struct in6_addr *addr = (struct in6_addr*)&n->key;
+ struct in6_addr maddr;
+ struct device *dev = n->dev;
+
+ if (dev == NULL || ipv6_get_idev(dev) == NULL)
+ return;
+#ifndef CONFIG_IPV6_NO_PB
+ addrconf_addr_solict_mult_old(addr, &maddr);
+ ipv6_dev_mc_dec(dev, &maddr);
+#endif
+#ifdef CONFIG_IPV6_EUI64
+ addrconf_addr_solict_mult_new(addr, &maddr);
+ ipv6_dev_mc_dec(dev, &maddr);
+#endif
+}
+
+
+
+static int
+ndisc_build_ll_hdr(struct sk_buff *skb, struct device *dev,
+ struct in6_addr *daddr, struct neighbour *neigh, int len)
+{
+ unsigned char ha[MAX_ADDR_LEN];
+ unsigned char *h_dest = NULL;
+
+ skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+
+ if (dev->hard_header) {
+ if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {
+ ndisc_mc_map(daddr, ha, dev, 1);
+ h_dest = ha;
+ } else if (neigh) {
+ h_dest = neigh->ha;
+ } else {
+ neigh = neigh_lookup(&nd_tbl, daddr, dev);
+ if (neigh) {
+ if (neigh->nud_state&NUD_VALID) {
+ memcpy(ha, neigh->ha, dev->addr_len);
+ h_dest = ha;
+ }
+ neigh_release(neigh);
+ }
+ }
+
+ if (dev->hard_header(skb, dev, ETH_P_IPV6, h_dest, NULL, len) < 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Send a Neighbour Advertisement
+ */
+
+void ndisc_send_na(struct device *dev, struct neighbour *neigh,
+ struct in6_addr *daddr, struct in6_addr *solicited_addr,
+ int router, int solicited, int override, int inc_opt)
+{
+ struct sock *sk = ndisc_socket->sk;
+ struct nd_msg *msg;
+ int len;
+ struct sk_buff *skb;
+ int err;
+
+ len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+
+ if (inc_opt) {
+ if (dev->addr_len)
+ len += NDISC_OPT_SPACE(dev->addr_len);
+ else
+ inc_opt = 0;
+ }
+
+ skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+ 0, 0, &err);
+
+ if (skb == NULL) {
+ ND_PRINTK1("send_na: alloc skb failed\n");
+ return;
+ }
+
+ if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
+ kfree_skb(skb);
+ return;
+ }
+
+ ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len);
+
+ msg = (struct nd_msg *) skb_put(skb, len);
+
+ msg->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+ msg->icmph.icmp6_code = 0;
+ msg->icmph.icmp6_cksum = 0;
+
+ msg->icmph.icmp6_unused = 0;
+ msg->icmph.icmp6_router = router;
+ msg->icmph.icmp6_solicited = solicited;
+ msg->icmph.icmp6_override = !!override;
+
+ /* Set the target address. */
+ ipv6_addr_copy(&msg->target, solicited_addr);
+
+ if (inc_opt)
+ ndisc_fill_option((void*)&msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
+
+ /* checksum */
+ msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len,
+ IPPROTO_ICMPV6,
+ csum_partial((__u8 *) msg,
+ len, 0));
+
+ dev_queue_xmit(skb);
+
+ icmpv6_statistics.Icmp6OutNeighborAdvertisements++;
+ icmpv6_statistics.Icmp6OutMsgs++;
+}
+
+void ndisc_send_ns(struct device *dev, struct neighbour *neigh,
+ struct in6_addr *solicit,
+ struct in6_addr *daddr, struct in6_addr *saddr)
+{
+ struct sock *sk = ndisc_socket->sk;
+ struct sk_buff *skb;
+ struct nd_msg *msg;
+ int len;
+ int err;
+
+ len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+ if (dev->addr_len)
+ len += NDISC_OPT_SPACE(dev->addr_len);
+
+ skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+ 0, 0, &err);
+ if (skb == NULL) {
+ ND_PRINTK1("send_ns: alloc skb failed\n");
+ return;
+ }
+
+ if (saddr == NULL) {
+ struct inet6_ifaddr *ifa;
+
+ /* use link local address */
+ ifa = ipv6_get_lladdr(dev);
+
+ if (ifa)
+ saddr = &ifa->addr;
+ }
+
+ if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
+ kfree_skb(skb);
+ return;
+ }
+
+ ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
+
+ msg = (struct nd_msg *)skb_put(skb, len);
+ msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;
+ msg->icmph.icmp6_code = 0;
+ msg->icmph.icmp6_cksum = 0;
+ msg->icmph.icmp6_unused = 0;
+
+ /* Set the target address. */
+ ipv6_addr_copy(&msg->target, solicit);
+
+ if (dev->addr_len)
+ ndisc_fill_option((void*)&msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
+
+ /* checksum */
+ msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+ daddr, len,
+ IPPROTO_ICMPV6,
+ csum_partial((__u8 *) msg,
+ len, 0));
+ /* send it! */
+ dev_queue_xmit(skb);
+
+ icmpv6_statistics.Icmp6OutNeighborSolicits++;
+ icmpv6_statistics.Icmp6OutMsgs++;
+}
+
+void ndisc_send_rs(struct device *dev, struct in6_addr *saddr,
+ struct in6_addr *daddr)
+{
+ struct sock *sk = ndisc_socket->sk;
+ struct sk_buff *skb;
+ struct icmp6hdr *hdr;
+ __u8 * opt;
+ int len;
+ int err;
+
+ len = sizeof(struct icmp6hdr);
+ if (dev->addr_len)
+ len += NDISC_OPT_SPACE(dev->addr_len);
+
+ skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+ 0, 0, &err);
+ if (skb == NULL) {
+ ND_PRINTK1("send_ns: alloc skb failed\n");
+ return;
+ }
+
+ if (ndisc_build_ll_hdr(skb, dev, daddr, NULL, len) == 0) {
+ kfree_skb(skb);
+ return;
+ }
+
+ ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
+
+ hdr = (struct icmp6hdr *) skb_put(skb, len);
+ hdr->icmp6_type = NDISC_ROUTER_SOLICITATION;
+ hdr->icmp6_code = 0;
+ hdr->icmp6_cksum = 0;
+ hdr->icmp6_unused = 0;
+
+ opt = (u8*) (hdr + 1);
+
+ if (dev->addr_len)
+ ndisc_fill_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
+
+ /* checksum */
+ hdr->icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len,
+ IPPROTO_ICMPV6,
+ csum_partial((__u8 *) hdr, len, 0));
+
+ /* send it! */
+ dev_queue_xmit(skb);
+
+ icmpv6_statistics.Icmp6OutRouterSolicits++;
+ icmpv6_statistics.Icmp6OutMsgs++;
+}
+
+
+static u8 * ndisc_find_option(u8 *opt, int opt_len, int len, int option)
+{
+ while (opt_len <= len) {
+ int l = opt[1]<<3;
+
+ if (opt[0] == option && l >= opt_len)
+ return opt + 2;
+
+ if (l == 0) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ndisc: option has 0 len\n");
+ return NULL;
+ }
+
+ opt += l;
+ len -= l;
+ }
+ return NULL;
+}
+
+
+static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
+{
+ /*
+ * "The sender MUST return an ICMP
+ * destination unreachable"
+ */
+ dst_link_failure(skb);
+ kfree_skb(skb);
+}
+
+static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
+{
+ struct in6_addr *saddr = NULL;
+ struct in6_addr mcaddr;
+ struct device *dev = neigh->dev;
+ struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
+ int probes = neigh->probes;
+
+ if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 0))
+ saddr = &skb->nh.ipv6h->saddr;
+
+ if ((probes -= neigh->parms->ucast_probes) < 0) {
+ if (!(neigh->nud_state&NUD_VALID))
+ ND_PRINTK1("trying to ucast probe in NUD_INVALID\n");
+ ndisc_send_ns(dev, neigh, target, target, saddr);
+ } else if ((probes -= neigh->parms->app_probes) < 0) {
+#ifdef CONFIG_ARPD
+ neigh_app_ns(neigh);
+#endif
+ } else {
+#ifdef CONFIG_IPV6_EUI64
+ addrconf_addr_solict_mult_new(target, &mcaddr);
+ ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
+#endif
+#ifndef CONFIG_IPV6_NO_PB
+ addrconf_addr_solict_mult_old(target, &mcaddr);
+ ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
+#endif
+ }
+}
+
+
+static void ndisc_update(struct neighbour *neigh, u8* opt, int len, int type)
+{
+ opt = ndisc_find_option(opt, neigh->dev->addr_len+2, len, type);
+ neigh_update(neigh, opt, NUD_STALE, 1, 1);
+}
+
+static void ndisc_router_discovery(struct sk_buff *skb)
+{
+ struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
+ struct neighbour *neigh;
+ struct inet6_dev *in6_dev;
+ struct rt6_info *rt;
+ int lifetime;
+ int optlen;
+
+ __u8 * opt = (__u8 *)(ra_msg + 1);
+
+ optlen = (skb->tail - skb->h.raw) - sizeof(struct ra_msg);
+
+ if (skb->nh.ipv6h->hop_limit != 255) {
+ printk(KERN_INFO
+ "NDISC: fake router advertisement received\n");
+ return;
+ }
+
+ /*
+ * set the RA_RECV flag in the interface
+ */
+
+ in6_dev = ipv6_get_idev(skb->dev);
+ if (in6_dev == NULL) {
+ ND_PRINTK1("RA: can't find in6 device\n");
+ return;
+ }
+ if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
+ return;
+
+ if (in6_dev->if_flags & IF_RS_SENT) {
+ /*
+ * flag that an RA was received after an RS was sent
+ * out on this interface.
+ */
+ in6_dev->if_flags |= IF_RA_RCVD;
+ }
+
+ lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
+
+ rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+
+ if (rt && lifetime == 0) {
+ ip6_del_rt(rt);
+ dst_release(&rt->u.dst);
+ rt = NULL;
+ }
+
+ if (rt == NULL && lifetime) {
+ ND_PRINTK2("ndisc_rdisc: adding default router\n");
+
+ rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+ if (rt == NULL) {
+ ND_PRINTK1("route_add failed\n");
+ return;
+ }
+
+ neigh = rt->rt6i_nexthop;
+ if (neigh == NULL) {
+ ND_PRINTK1("nd: add default router: null neighbour\n");
+ dst_release(&rt->u.dst);
+ return;
+ }
+ neigh->flags |= NTF_ROUTER;
+
+ /*
+ * If we where using an "all destinations on link" route
+ * delete it
+ */
+
+ rt6_purge_dflt_routers(RTF_ALLONLINK);
+ }
+
+ if (rt)
+ rt->rt6i_expires = jiffies + (HZ * lifetime);
+
+ if (ra_msg->icmph.icmp6_hop_limit)
+ in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+
+ /*
+ * Update Reachable Time and Retrans Timer
+ */
+
+ if (in6_dev->nd_parms) {
+ if (ra_msg->retrans_timer)
+ in6_dev->nd_parms->retrans_time = (ntohl(ra_msg->retrans_timer)*HZ)/1000;
+
+ if (ra_msg->reachable_time) {
+ __u32 rtime = (ntohl(ra_msg->reachable_time)*HZ)/1000;
+
+ if (rtime != in6_dev->nd_parms->base_reachable_time) {
+ in6_dev->nd_parms->base_reachable_time = rtime;
+ in6_dev->nd_parms->gc_staletime = 3 * rtime;
+ in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
+ }
+ }
+ }
+
+ /*
+ * Process options.
+ */
+
+ while (optlen > 0) {
+ int len = (opt[1] << 3);
+
+ if (len == 0) {
+ ND_PRINTK0("RA: opt has 0 len\n");
+ break;
+ }
+
+ switch(*opt) {
+ case ND_OPT_SOURCE_LL_ADDR:
+
+ if (rt == NULL)
+ break;
+
+ if ((neigh = rt->rt6i_nexthop) != NULL &&
+ skb->dev->addr_len + 2 >= len)
+ neigh_update(neigh, opt+2, NUD_STALE, 1, 1);
+ break;
+
+ case ND_OPT_PREFIX_INFO:
+ addrconf_prefix_rcv(skb->dev, opt, len);
+ break;
+
+ case ND_OPT_MTU:
+ {
+ int mtu;
+
+ mtu = htonl(*(__u32 *)(opt+4));
+
+ if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
+ ND_PRINTK0("NDISC: router "
+ "announcement with mtu = %d\n",
+ mtu);
+ break;
+ }
+
+ if (in6_dev->cnf.mtu6 != mtu) {
+ in6_dev->cnf.mtu6 = mtu;
+
+ if (rt)
+ rt->u.dst.pmtu = mtu;
+
+ rt6_mtu_change(skb->dev, mtu);
+ }
+ }
+ break;
+
+ case ND_OPT_TARGET_LL_ADDR:
+ case ND_OPT_REDIRECT_HDR:
+ ND_PRINTK0("got illegal option with RA");
+ break;
+ default:
+ ND_PRINTK0("unknown option in RA\n");
+ };
+ optlen -= len;
+ opt += len;
+ }
+ if (rt)
+ dst_release(&rt->u.dst);
+}
+
+static void ndisc_redirect_rcv(struct sk_buff *skb)
+{
+ struct inet6_dev *in6_dev;
+ struct icmp6hdr *icmph;
+ struct in6_addr *dest;
+ struct in6_addr *target; /* new first hop to destination */
+ struct neighbour *neigh;
+ int on_link = 0;
+ int optlen;
+
+ if (skb->nh.ipv6h->hop_limit != 255) {
+ printk(KERN_WARNING "NDISC: fake ICMP redirect received\n");
+ return;
+ }
+
+ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+ printk(KERN_WARNING "ICMP redirect: source address is not linklocal\n");
+ return;
+ }
+
+ optlen = skb->tail - skb->h.raw;
+ optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+
+ if (optlen < 0) {
+ printk(KERN_WARNING "ICMP redirect: packet too small\n");
+ return;
+ }
+
+ icmph = (struct icmp6hdr *) skb->h.raw;
+ target = (struct in6_addr *) (icmph + 1);
+ dest = target + 1;
+
+ if (ipv6_addr_type(dest) & IPV6_ADDR_MULTICAST) {
+ printk(KERN_WARNING "ICMP redirect for multicast addr\n");
+ return;
+ }
+
+ if (ipv6_addr_cmp(dest, target) == 0) {
+ on_link = 1;
+ } else if (!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
+ printk(KERN_WARNING "ICMP redirect: target address is not linklocal\n");
+ return;
+ }
+
+ in6_dev = ipv6_get_idev(skb->dev);
+ if (!in6_dev || in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
+ return;
+
+ /* passed validation tests */
+
+ /*
+ We install redirect only if nexthop state is valid.
+ */
+
+ neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
+ if (neigh) {
+ ndisc_update(neigh, (u8*)(dest + 1), optlen, ND_OPT_TARGET_LL_ADDR);
+ if (neigh->nud_state&NUD_VALID)
+ rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, on_link);
+ else
+ __neigh_event_send(neigh, NULL);
+ neigh_release(neigh);
+ }
+}
+
+void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
+ struct in6_addr *target)
+{
+ struct sock *sk = ndisc_socket->sk;
+ int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+ struct sk_buff *buff;
+ struct inet6_ifaddr *ifp;
+ struct icmp6hdr *icmph;
+ struct in6_addr *addrp;
+ struct device *dev;
+ struct rt6_info *rt;
+ u8 *opt;
+ int rd_len;
+ int err;
+ int hlen;
+
+ dev = skb->dev;
+ rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1);
+
+ if (rt == NULL)
+ return;
+
+ if (rt->rt6i_flags & RTF_GATEWAY) {
+ ND_PRINTK1("ndisc_send_redirect: not a neighbour\n");
+ dst_release(&rt->u.dst);
+ return;
+ }
+ if (!xrlim_allow(&rt->u.dst, 1*HZ)) {
+ dst_release(&rt->u.dst);
+ return;
+ }
+ dst_release(&rt->u.dst);
+
+ if (dev->addr_len) {
+ if (neigh->nud_state&NUD_VALID) {
+ len += NDISC_OPT_SPACE(dev->addr_len);
+ } else {
+ /* If nexthop is not valid, do not redirect!
+ We will make it later, when will be sure,
+ that it is alive.
+ */
+ return;
+ }
+ }
+
+ rd_len = min(IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8);
+ rd_len &= ~0x7;
+ len += rd_len;
+
+ ifp = ipv6_get_lladdr(dev);
+
+ if (ifp == NULL) {
+ ND_PRINTK1("redirect: no link_local addr for dev\n");
+ return;
+ }
+
+ buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+ 0, 0, &err);
+ if (buff == NULL) {
+ ND_PRINTK1("ndisc_send_redirect: alloc_skb failed\n");
+ return;
+ }
+
+ hlen = 0;
+
+ if (ndisc_build_ll_hdr(buff, dev, &skb->nh.ipv6h->saddr, NULL, len) == 0) {
+ kfree_skb(buff);
+ return;
+ }
+
+ ip6_nd_hdr(sk, buff, dev, &ifp->addr, &skb->nh.ipv6h->saddr,
+ IPPROTO_ICMPV6, len);
+
+ icmph = (struct icmp6hdr *) skb_put(buff, len);
+
+ memset(icmph, 0, sizeof(struct icmp6hdr));
+ icmph->icmp6_type = NDISC_REDIRECT;
+
+ /*
+ * copy target and destination addresses
+ */
+
+ addrp = (struct in6_addr *)(icmph + 1);
+ ipv6_addr_copy(addrp, target);
+ addrp++;
+ ipv6_addr_copy(addrp, &skb->nh.ipv6h->daddr);
+
+ opt = (u8*) (addrp + 1);
+
+ /*
+ * include target_address option
+ */
+
+ if (dev->addr_len)
+ opt = ndisc_fill_option(opt, ND_OPT_TARGET_LL_ADDR, neigh->ha, dev->addr_len);
+
+ /*
+ * build redirect option and copy skb over to the new packet.
+ */
+
+ memset(opt, 0, 8);
+ *(opt++) = ND_OPT_REDIRECT_HDR;
+ *(opt++) = (rd_len >> 3);
+ opt += 6;
+
+ memcpy(opt, skb->nh.ipv6h, rd_len - 8);
+
+ icmph->icmp6_cksum = csum_ipv6_magic(&ifp->addr, &skb->nh.ipv6h->saddr,
+ len, IPPROTO_ICMPV6,
+ csum_partial((u8 *) icmph, len, 0));
+
+ dev_queue_xmit(buff);
+
+ icmpv6_statistics.Icmp6OutRedirects++;
+ icmpv6_statistics.Icmp6OutMsgs++;
+}
+
+static __inline__ struct neighbour *
+ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb)
+{
+ u8 *opt;
+
+ opt = skb->h.raw;
+ opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+ opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR);
+
+ return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev);
+}
+
+static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb)
+{
+ struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
+ u8 *opt;
+
+ opt = skb->h.raw;
+ opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+ opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_TARGET_LL_ADDR);
+
+ return neigh_update(neigh, opt,
+ msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
+ msg->icmph.icmp6_override, 1);
+}
+
+static void pndisc_redo(struct sk_buff *skb)
+{
+ ndisc_rcv(skb, skb->len);
+ kfree_skb(skb);
+}
+
+int ndisc_rcv(struct sk_buff *skb, unsigned long len)
+{
+ struct device *dev = skb->dev;
+ struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+ struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+ struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
+ struct neighbour *neigh;
+ struct inet6_ifaddr *ifp;
+
+ switch (msg->icmph.icmp6_type) {
+ case NDISC_NEIGHBOUR_SOLICITATION:
+ if ((ifp = ipv6_chk_addr(&msg->target, dev, 1)) != NULL) {
+ int addr_type = ipv6_addr_type(saddr);
+
+ if (ifp->flags & ADDR_INVALID)
+ return 0;
+ if (ifp->flags & DAD_INCOMPLETE) {
+ /* Address is tentative. If the source
+ is unspecified address, it is someone
+ does DAD, otherwise we ignore solicitations
+ until DAD timer expires.
+ */
+ if (addr_type == IPV6_ADDR_ANY)
+ addrconf_dad_failure(ifp);
+ return 0;
+ }
+
+ if (addr_type == IPV6_ADDR_ANY) {
+ struct in6_addr maddr;
+
+ ipv6_addr_all_nodes(&maddr);
+ ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
+ ifp->idev->cnf.forwarding, 0, 1, 1);
+ return 0;
+ }
+
+ if (addr_type & IPV6_ADDR_UNICAST) {
+ int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+
+ if (inc)
+ nd_tbl.stats.rcv_probes_mcast++;
+ else
+ nd_tbl.stats.rcv_probes_ucast++;
+
+ /*
+ * update / create cache entry
+ * for the source adddress
+ */
+
+ neigh = ndisc_recv_ns(saddr, skb);
+
+ if (neigh) {
+ ndisc_send_na(dev, neigh, saddr, &ifp->addr,
+ ifp->idev->cnf.forwarding, 1, inc, inc);
+ neigh_release(neigh);
+ }
+ }
+ } else {
+ struct inet6_dev *in6_dev = ipv6_get_idev(dev);
+ int addr_type = ipv6_addr_type(saddr);
+
+ if (in6_dev && in6_dev->cnf.forwarding &&
+ (addr_type & IPV6_ADDR_UNICAST) &&
+ pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
+ int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+
+ if (skb->stamp.tv_sec == 0 ||
+ skb->pkt_type == PACKET_HOST ||
+ inc == 0 ||
+ in6_dev->nd_parms->proxy_delay == 0) {
+ if (inc)
+ nd_tbl.stats.rcv_probes_mcast++;
+ else
+ nd_tbl.stats.rcv_probes_ucast++;
+
+ neigh = ndisc_recv_ns(saddr, skb);
+
+ if (neigh) {
+ ndisc_send_na(dev, neigh, saddr, &msg->target,
+ 0, 1, 0, inc);
+ neigh_release(neigh);
+ }
+ } else {
+ /* Hack. It will be freed upon exit from
+ ndisc_rcv
+ */
+ atomic_inc(&skb->users);
+ pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, skb);
+ return 0;
+ }
+ }
+ }
+ return 0;
+
+ case NDISC_NEIGHBOUR_ADVERTISEMENT:
+ if ((ipv6_addr_type(saddr)&IPV6_ADDR_MULTICAST) &&
+ msg->icmph.icmp6_solicited) {
+ ND_PRINTK0("NDISC: solicited NA is multicasted\n");
+ return 0;
+ }
+ /* BUG! Target can be link-local on ANOTHER interface. Fixed. */
+ if ((ifp = ipv6_chk_addr(&msg->target, dev, 1))) {
+ if (ifp->flags & ADDR_INVALID)
+ return 0;
+ if (ifp->flags & DAD_INCOMPLETE) {
+ addrconf_dad_failure(ifp);
+ return 0;
+ }
+ /* What should we make now? The advertisement
+ is invalid, but ndisc specs say nothing
+ about it. It could be misconfiguration, or
+ an smart proxy agent tries to help us :-)
+ */
+ ND_PRINTK0("%s: someone avertise our address!\n",
+ ifp->idev->dev->name);
+ return 0;
+ }
+ neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 0);
+
+ if (neigh) {
+ if (neigh->flags & NTF_ROUTER) {
+ if (msg->icmph.icmp6_router == 0) {
+ /*
+ * Change: router to host
+ */
+ struct rt6_info *rt;
+ rt = rt6_get_dflt_router(saddr, skb->dev);
+ if (rt) {
+ /* It is safe only because
+ we aer in BH */
+ dst_release(&rt->u.dst);
+ ip6_del_rt(rt);
+ }
+ }
+ } else {
+ if (msg->icmph.icmp6_router)
+ neigh->flags |= NTF_ROUTER;
+ }
+
+ ndisc_recv_na(neigh, skb);
+ neigh_release(neigh);
+ }
+ break;
+
+ case NDISC_ROUTER_ADVERTISEMENT:
+ ndisc_router_discovery(skb);
+ break;
+
+ case NDISC_REDIRECT:
+ ndisc_redirect_rcv(skb);
+ break;
+ };
+
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+#ifndef CONFIG_RTNETLINK
+int ndisc_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int len=0;
+ off_t pos=0;
+ int size;
+ unsigned long now = jiffies;
+ int i;
+
+ neigh_table_lock(&nd_tbl);
+
+ for (i = 0; i <= NEIGH_HASHMASK; i++) {
+ struct neighbour *neigh;
+
+ for (neigh = nd_tbl.hash_buckets[i]; neigh; neigh = neigh->next) {
+ int j;
+
+ size = 0;
+ for (j=0; j<16; j++) {
+ sprintf(buffer+len+size, "%02x", neigh->primary_key[j]);
+ size += 2;
+ }
+
+ size += sprintf(buffer+len+size,
+ " %02x %02x %02x %02x %08lx %08lx %08x %04x %04x %04x %8s ", i,
+ 128,
+ neigh->type,
+ neigh->nud_state,
+ now - neigh->used,
+ now - neigh->confirmed,
+ neigh->parms->reachable_time,
+ neigh->parms->gc_staletime,
+ atomic_read(&neigh->refcnt),
+ neigh->flags | (!neigh->hh ? 0 : (neigh->hh->hh_output==dev_queue_xmit ? 4 : 2)),
+ neigh->dev->name);
+
+ if ((neigh->nud_state&NUD_VALID) && neigh->dev->addr_len) {
+ for (j=0; j < neigh->dev->addr_len; j++) {
+ sprintf(buffer+len+size, "%02x", neigh->ha[j]);
+ size += 2;
+ }
+ } else {
+ size += sprintf(buffer+len+size, "000000000000");
+ }
+ size += sprintf(buffer+len+size, "\n");
+ len += size;
+ pos += size;
+
+ if (pos <= offset)
+ len=0;
+ if (pos >= offset+length)
+ goto done;
+ }
+ }
+
+done:
+ neigh_table_unlock(&nd_tbl);
+
+ *start = buffer+len-(pos-offset); /* Start of wanted data */
+ len = pos-offset; /* Start slop */
+ if (len>length)
+ len = length; /* Ending slop */
+ if (len<0)
+ len = 0;
+ return len;
+}
+
+struct proc_dir_entry ndisc_proc_entry =
+{
+ PROC_NET_NDISC, 5, "ndisc",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, NULL,
+ &ndisc_get_info
+};
+#endif
+#endif /* CONFIG_PROC_FS */
+
+
+
+__initfunc(int ndisc_init(struct net_proto_family *ops))
+{
+ struct sock *sk;
+ int err;
+
+ ndisc_socket = sock_alloc();
+ if (ndisc_socket == NULL) {
+ printk(KERN_ERR
+ "Failed to create the NDISC control socket.\n");
+ return -1;
+ }
+#ifndef _HURD_
+ ndisc_socket->inode->i_uid = 0;
+ ndisc_socket->inode->i_gid = 0;
+#endif
+ ndisc_socket->type = SOCK_RAW;
+
+ if((err = ops->create(ndisc_socket, IPPROTO_ICMPV6)) < 0) {
+ printk(KERN_DEBUG
+ "Failed to initializee the NDISC control socket (err %d).\n",
+ err);
+ sock_release(ndisc_socket);
+ ndisc_socket = NULL; /* For safety. */
+ return err;
+ }
+
+ sk = ndisc_socket->sk;
+ sk->allocation = GFP_ATOMIC;
+ sk->net_pinfo.af_inet6.hop_limit = 255;
+ /* Do not loopback ndisc messages */
+ sk->net_pinfo.af_inet6.mc_loop = 0;
+ sk->num = 256;
+
+ /*
+ * Initialize the neighbour table
+ */
+
+ neigh_table_init(&nd_tbl);
+
+#ifdef CONFIG_PROC_FS
+#ifndef CONFIG_RTNETLINK
+ proc_net_register(&ndisc_proc_entry);
+#endif
+#endif
+#ifdef CONFIG_SYSCTL
+ neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
+#endif
+
+ return 0;
+}
+
+void ndisc_cleanup(void)
+{
+#ifdef CONFIG_PROC_FS
+#ifndef CONFIG_RTNETLINK
+ proc_net_unregister(ndisc_proc_entry.low_ino);
+#endif
+#endif
+ neigh_table_clear(&nd_tbl);
+ sock_release(ndisc_socket);
+ ndisc_socket = NULL; /* For safety. */
+}
diff --git a/pfinet/linux-src/net/ipv6/protocol_ipv6.c b/pfinet/linux-src/net/ipv6/protocol_ipv6.c
new file mode 100644
index 00000000..ad871914
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/protocol_ipv6.c
@@ -0,0 +1,117 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * PF_INET6 protocol dispatch tables.
+ *
+ * Version: $Id: protocol_ipv6.c,v 1.1 2007/10/08 21:12:31 stesie Exp $
+ *
+ * Authors: Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+
+struct inet6_protocol *inet6_protocol_base = NULL;
+struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] =
+{
+ NULL
+};
+
+
+struct inet6_protocol *inet6_get_protocol(unsigned char prot)
+{
+ unsigned char hash;
+ struct inet6_protocol *p;
+
+ hash = prot & (MAX_INET_PROTOS - 1);
+ for (p = inet6_protos[hash] ; p != NULL; p=p->next) {
+ if (p->protocol == prot)
+ return((struct inet6_protocol *) p);
+ }
+ return(NULL);
+}
+
+void inet6_add_protocol(struct inet6_protocol *prot)
+{
+ unsigned char hash;
+ struct inet6_protocol *p2;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ prot->next = inet6_protos[hash];
+ inet6_protos[hash] = prot;
+ prot->copy = 0;
+
+ /*
+ * Set the copy bit if we need to.
+ */
+
+ p2 = (struct inet6_protocol *) prot->next;
+ while(p2 != NULL) {
+ if (p2->protocol == prot->protocol) {
+ prot->copy = 1;
+ break;
+ }
+ p2 = (struct inet6_protocol *) p2->next;
+ }
+}
+
+/*
+ * Remove a protocol from the hash tables.
+ */
+
+int inet6_del_protocol(struct inet6_protocol *prot)
+{
+ struct inet6_protocol *p;
+ struct inet6_protocol *lp = NULL;
+ unsigned char hash;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ if (prot == inet6_protos[hash]) {
+ inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next;
+ return(0);
+ }
+
+ p = (struct inet6_protocol *) inet6_protos[hash];
+ while(p != NULL) {
+ /*
+ * We have to worry if the protocol being deleted is
+ * the last one on the list, then we may need to reset
+ * someone's copied bit.
+ */
+ if (p->next != NULL && p->next == prot) {
+ /*
+ * if we are the last one with this protocol and
+ * there is a previous one, reset its copy bit.
+ */
+ if (p->copy == 0 && lp != NULL)
+ lp->copy = 0;
+ p->next = prot->next;
+ return(0);
+ }
+ if (p->next != NULL && p->next->protocol == prot->protocol)
+ lp = p;
+
+ p = (struct inet6_protocol *) p->next;
+ }
+ return(-1);
+}
diff --git a/pfinet/linux-src/net/ipv6/raw_ipv6.c b/pfinet/linux-src/net/ipv6/raw_ipv6.c
new file mode 100644
index 00000000..64bc247c
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/raw_ipv6.c
@@ -0,0 +1,691 @@
+/*
+ * RAW sockets for IPv6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Adapted from linux/net/ipv4/raw.c
+ *
+ * $Id: raw_ipv6.c,v 1.2 2007/10/13 01:43:00 stesie Exp $
+ *
+ * Fixes:
+ * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/icmpv6.h>
+#include <asm/uaccess.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/protocol.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/transp_v6.h>
+
+#include <net/rawv6.h>
+
+#include <asm/uaccess.h>
+
+struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
+
+static void raw_v6_hash(struct sock *sk)
+{
+ struct sock **skp = &raw_v6_htable[sk->num & (RAWV6_HTABLE_SIZE - 1)];
+
+ SOCKHASH_LOCK();
+ if ((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+ SOCKHASH_UNLOCK();
+}
+
+static void raw_v6_unhash(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if (sk->pprev) {
+ if (sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ }
+ SOCKHASH_UNLOCK();
+}
+
+static __inline__ int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
+{
+ struct ipv6_mc_socklist *mc;
+
+ for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
+ if (ipv6_addr_cmp(&mc->addr, addr) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Grumble... icmp and ip_input want to get at this... */
+struct sock *raw_v6_lookup(struct sock *sk, unsigned short num,
+ struct in6_addr *loc_addr, struct in6_addr *rmt_addr)
+{
+ struct sock *s = sk;
+ int addr_type = ipv6_addr_type(loc_addr);
+
+ for(s = sk; s; s = s->next) {
+ if((s->num == num) &&
+ !(s->dead && (s->state == TCP_CLOSE))) {
+ struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;
+
+ if (!ipv6_addr_any(&np->daddr) &&
+ ipv6_addr_cmp(&np->daddr, rmt_addr))
+ continue;
+
+ if (!ipv6_addr_any(&np->rcv_saddr)) {
+ if (ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)
+ return(s);
+ if ((addr_type & IPV6_ADDR_MULTICAST) &&
+ inet6_mc_check(s, loc_addr))
+ return (s);
+ continue;
+ }
+ return(s);
+ }
+ }
+ return NULL;
+}
+
+/* This cleans up af_inet6 a bit. -DaveM */
+static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
+ __u32 v4addr = 0;
+ int addr_type;
+
+ /* Check these errors. */
+ if (sk->state != TCP_CLOSE || (addr_len < sizeof(struct sockaddr_in6)))
+ return -EINVAL;
+
+ addr_type = ipv6_addr_type(&addr->sin6_addr);
+
+ /* Check if the address belongs to the host. */
+ if (addr_type == IPV6_ADDR_MAPPED) {
+ /* Raw sockets are IPv6 only */
+ return(-EADDRNOTAVAIL);
+ } else {
+ if (addr_type != IPV6_ADDR_ANY) {
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ addr->sin6_scope_id) {
+ /* Override any existing binding,
+ * if another one is supplied by user.
+ */
+ sk->bound_dev_if =
+ addr->sin6_scope_id;
+ }
+
+ /* Binding to link-local address requires
+ an interface */
+ if (!sk->bound_dev_if)
+ return(-EINVAL);
+
+ if (!dev_get_by_index(sk->bound_dev_if))
+ return(-ENODEV);
+ }
+
+ /* ipv4 addr of the socket is invalid. Only the
+ * unpecified and mapped address have a v4 equivalent.
+ */
+ v4addr = LOOPBACK4_IPV6;
+ if (!(addr_type & IPV6_ADDR_MULTICAST)) {
+ if (ipv6_chk_addr(&addr->sin6_addr, NULL, 0) == NULL)
+ return(-EADDRNOTAVAIL);
+ }
+ }
+ }
+
+ sk->rcv_saddr = v4addr;
+ sk->saddr = v4addr;
+ memcpy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr,
+ sizeof(struct in6_addr));
+ if (!(addr_type & IPV6_ADDR_MULTICAST))
+ memcpy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr,
+ sizeof(struct in6_addr));
+ return 0;
+}
+
+void rawv6_err(struct sock *sk, struct sk_buff *skb, struct ipv6hdr *hdr,
+ struct inet6_skb_parm *opt,
+ int type, int code, unsigned char *buff, u32 info)
+{
+ int err;
+ int harderr;
+
+ if (buff > skb->tail)
+ return;
+
+ /* Report error on raw socket, if:
+ 1. User requested recverr.
+ 2. Socket is connected (otherwise the error indication
+ is useless without recverr and error is hard.
+ */
+ if (!sk->net_pinfo.af_inet6.recverr && sk->state != TCP_ESTABLISHED)
+ return;
+
+ harderr = icmpv6_err_convert(type, code, &err);
+ if (type == ICMPV6_PKT_TOOBIG)
+ harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO);
+
+ if (sk->net_pinfo.af_inet6.recverr)
+ ipv6_icmp_error(sk, skb, err, 0, ntohl(info), buff);
+
+ if (sk->net_pinfo.af_inet6.recverr || harderr) {
+ sk->err = err;
+ sk->error_report(sk);
+ }
+}
+
+static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
+{
+ /* Charge it to the socket. */
+ if (sock_queue_rcv_skb(sk,skb)<0) {
+ ipv6_statistics.Ip6InDiscards++;
+ kfree_skb(skb);
+ return 0;
+ }
+
+ ipv6_statistics.Ip6InDelivers++;
+ return 0;
+}
+
+/*
+ * This is next to useless...
+ * if we demultiplex in network layer we don't need the extra call
+ * just to queue the skb...
+ * maybe we could have the network decide uppon a hint if it
+ * should call raw_rcv for demultiplexing
+ */
+int rawv6_rcv(struct sock *sk, struct sk_buff *skb, unsigned long len)
+{
+ if (sk->ip_hdrincl)
+ skb->h.raw = skb->nh.raw;
+
+ rawv6_rcv_skb(sk, skb);
+ return 0;
+}
+
+
+/*
+ * This should be easy, if there is something there
+ * we return it, otherwise we block.
+ */
+
+int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
+ int noblock, int flags, int *addr_len)
+{
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)msg->msg_name;
+ struct sk_buff *skb;
+ int copied, err;
+
+ if (flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ if (addr_len)
+ *addr_len=sizeof(*sin6);
+
+ if (flags & MSG_ERRQUEUE)
+ return ipv6_recv_error(sk, msg, len);
+
+ skb = skb_recv_datagram(sk, flags, noblock, &err);
+ if (!skb)
+ goto out;
+
+ copied = skb->tail - skb->h.raw;
+ if (copied > len) {
+ copied = len;
+ msg->msg_flags |= MSG_TRUNC;
+ }
+
+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ sk->stamp=skb->stamp;
+ if (err)
+ goto out_free;
+
+ /* Copy the address. */
+ if (sin6) {
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
+ sizeof(struct in6_addr));
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin6->sin6_scope_id =
+ ((struct inet6_skb_parm *) skb->cb)->iif;
+ }
+
+ if (sk->net_pinfo.af_inet6.rxopt.all)
+ datagram_recv_ctl(sk, msg, skb);
+ err = copied;
+
+out_free:
+ skb_free_datagram(sk, skb);
+out:
+ return err;
+}
+
+/*
+ * Sending...
+ */
+
+struct rawv6_fakehdr {
+ struct iovec *iov;
+ struct sock *sk;
+ __u32 len;
+ __u32 cksum;
+ __u32 proto;
+ struct in6_addr *daddr;
+};
+
+static int rawv6_getfrag(const void *data, struct in6_addr *saddr,
+ char *buff, unsigned int offset, unsigned int len)
+{
+ struct iovec *iov = (struct iovec *) data;
+
+ return memcpy_fromiovecend(buff, iov, offset, len);
+}
+
+static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,
+ char *buff, unsigned int offset,
+ unsigned int len)
+{
+ struct rawv6_fakehdr *hdr = (struct rawv6_fakehdr *) data;
+
+ if (csum_partial_copy_fromiovecend(buff, hdr->iov, offset,
+ len, &hdr->cksum))
+ return -EFAULT;
+
+ if (offset == 0) {
+ struct sock *sk;
+ struct raw6_opt *opt;
+ struct in6_addr *daddr;
+
+ sk = hdr->sk;
+ opt = &sk->tp_pinfo.tp_raw;
+
+ if (hdr->daddr)
+ daddr = hdr->daddr;
+ else
+ daddr = addr + 1;
+
+ hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len,
+ hdr->proto, hdr->cksum);
+
+ if (opt->offset + 1 < len) {
+ __u16 *csum;
+
+ csum = (__u16 *) (buff + opt->offset);
+ if (*csum) {
+ /* in case cksum was not initialized */
+ __u32 sum = hdr->cksum;
+ sum += *csum;
+ *csum = hdr->cksum = (sum + (sum>>16));
+ } else {
+ *csum = hdr->cksum;
+ }
+ } else {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "icmp: cksum offset too big\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+
+static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct ipv6_txoptions opt_space;
+ struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct ipv6_txoptions *opt = NULL;
+ struct ip6_flowlabel *flowlabel = NULL;
+ struct flowi fl;
+ int addr_len = msg->msg_namelen;
+ struct in6_addr *daddr;
+ struct raw6_opt *raw_opt;
+ int hlimit = -1;
+ u16 proto;
+ int err;
+
+ /* Rough check on arithmetic overflow,
+ better check is made in ip6_build_xmit
+ */
+ if (len < 0)
+ return -EMSGSIZE;
+
+ /* Mirror BSD error message compatibility */
+ if (msg->msg_flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
+ return(-EINVAL);
+ /*
+ * Get and verify the address.
+ */
+
+ fl.fl6_flowlabel = 0;
+
+ if (sin6) {
+ if (addr_len < sizeof(struct sockaddr_in6))
+ return(-EINVAL);
+
+ if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
+ return(-EINVAL);
+
+ /* port is the proto value [0..255] carried in nexthdr */
+ proto = ntohs(sin6->sin6_port);
+
+ if (!proto)
+ proto = sk->num;
+
+ if (proto > 255)
+ return(-EINVAL);
+
+ daddr = &sin6->sin6_addr;
+ if (np->sndflow) {
+ fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ daddr = &flowlabel->dst;
+ }
+ }
+
+
+ /* Otherwise it will be difficult to maintain sk->dst_cache. */
+ if (sk->state == TCP_ESTABLISHED &&
+ !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
+ daddr = &sk->net_pinfo.af_inet6.daddr;
+
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ sin6->sin6_scope_id &&
+ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+ fl.oif = sin6->sin6_scope_id;
+ } else {
+ if (sk->state != TCP_ESTABLISHED)
+ return(-EINVAL);
+
+ proto = sk->num;
+ daddr = &(sk->net_pinfo.af_inet6.daddr);
+ fl.fl6_flowlabel = np->flow_label;
+ }
+
+ if (ipv6_addr_any(daddr)) {
+ /*
+ * unspecfied destination address
+ * treated as error... is this correct ?
+ */
+ return(-EINVAL);
+ }
+
+ fl.oif = sk->bound_dev_if;
+ fl.fl6_src = NULL;
+
+ if (msg->msg_controllen) {
+ opt = &opt_space;
+ memset(opt, 0, sizeof(struct ipv6_txoptions));
+
+ err = datagram_send_ctl(msg, &fl, opt, &hlimit);
+ if (err < 0) {
+ fl6_sock_release(flowlabel);
+ return err;
+ }
+ if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ }
+ if (!(opt->opt_nflen|opt->opt_flen))
+ opt = NULL;
+ }
+ if (opt == NULL)
+ opt = np->opt;
+ if (flowlabel)
+ opt = fl6_merge_options(&opt_space, flowlabel, opt);
+
+ raw_opt = &sk->tp_pinfo.tp_raw;
+
+ fl.proto = proto;
+ fl.fl6_dst = daddr;
+ fl.uli_u.icmpt.type = 0;
+ fl.uli_u.icmpt.code = 0;
+
+ if (raw_opt->checksum) {
+ struct rawv6_fakehdr hdr;
+
+ hdr.iov = msg->msg_iov;
+ hdr.sk = sk;
+ hdr.len = len;
+ hdr.cksum = 0;
+ hdr.proto = proto;
+
+ if (opt && opt->srcrt)
+ hdr.daddr = daddr;
+ else
+ hdr.daddr = NULL;
+
+ err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
+ opt, hlimit, msg->msg_flags);
+ } else {
+ err = ip6_build_xmit(sk, rawv6_getfrag, msg->msg_iov, &fl, len,
+ opt, hlimit, msg->msg_flags);
+ }
+
+ fl6_sock_release(flowlabel);
+
+ return err<0?err:len;
+}
+
+static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
+ char *optval, int optlen)
+{
+ switch (optname) {
+ case ICMPV6_FILTER:
+ if (optlen > sizeof(struct icmp6_filter))
+ optlen = sizeof(struct icmp6_filter);
+ if (copy_from_user(&sk->tp_pinfo.tp_raw.filter, optval, optlen))
+ return -EFAULT;
+ return 0;
+ default:
+ return -ENOPROTOOPT;
+ };
+
+ return 0;
+}
+
+static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
+ char *optval, int *optlen)
+{
+ int len;
+
+ switch (optname) {
+ case ICMPV6_FILTER:
+ if (get_user(len, optlen))
+ return -EFAULT;
+ if (len > sizeof(struct icmp6_filter))
+ len = sizeof(struct icmp6_filter);
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &sk->tp_pinfo.tp_raw.filter, len))
+ return -EFAULT;
+ return 0;
+ default:
+ return -ENOPROTOOPT;
+ };
+
+ return 0;
+}
+
+
+static int rawv6_setsockopt(struct sock *sk, int level, int optname,
+ char *optval, int optlen)
+{
+ struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
+ int val;
+
+ switch(level) {
+ case SOL_RAW:
+ break;
+
+ case SOL_ICMPV6:
+ if (sk->num != IPPROTO_ICMPV6)
+ return -EOPNOTSUPP;
+ return rawv6_seticmpfilter(sk, level, optname, optval,
+ optlen);
+ case SOL_IPV6:
+ if (optname == IPV6_CHECKSUM)
+ break;
+ default:
+ return ipv6_setsockopt(sk, level, optname, optval,
+ optlen);
+ };
+
+ if (get_user(val, (int *)optval))
+ return -EFAULT;
+
+ switch (optname) {
+ case IPV6_CHECKSUM:
+ /* You may get strange result with a positive odd offset;
+ RFC2292bis agrees with me. */
+ if (val > 0 && (val&1))
+ return(-EINVAL);
+ if (val < 0) {
+ opt->checksum = 0;
+ } else {
+ opt->checksum = 1;
+ opt->offset = val;
+ }
+
+ return 0;
+ break;
+
+ default:
+ return(-ENOPROTOOPT);
+ }
+}
+
+static int rawv6_getsockopt(struct sock *sk, int level, int optname,
+ char *optval, int *optlen)
+{
+ struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
+ int val, len;
+
+ switch(level) {
+ case SOL_RAW:
+ break;
+
+ case SOL_ICMPV6:
+ if (sk->num != IPPROTO_ICMPV6)
+ return -EOPNOTSUPP;
+ return rawv6_geticmpfilter(sk, level, optname, optval,
+ optlen);
+ case SOL_IPV6:
+ if (optname == IPV6_CHECKSUM)
+ break;
+ default:
+ return ipv6_getsockopt(sk, level, optname, optval,
+ optlen);
+ };
+
+ if (get_user(len,optlen))
+ return -EFAULT;
+
+ switch (optname) {
+ case IPV6_CHECKSUM:
+ if (opt->checksum == 0)
+ val = -1;
+ else
+ val = opt->offset;
+
+ default:
+ return -ENOPROTOOPT;
+ }
+
+ len=min(sizeof(int),len);
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval,&val,len))
+ return -EFAULT;
+ return 0;
+}
+
+
+static void rawv6_close(struct sock *sk, long timeout)
+{
+ /* See for explanation: raw_close in ipv4/raw.c */
+ sk->state = TCP_CLOSE;
+ raw_v6_unhash(sk);
+ if (sk->num == IPPROTO_RAW)
+ ip6_ra_control(sk, -1, NULL);
+ sk->dead = 1;
+ destroy_sock(sk);
+}
+
+static int rawv6_init_sk(struct sock *sk)
+{
+ if (sk->num == IPPROTO_ICMPV6){
+ struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
+ opt->checksum = 1;
+ opt->offset = 2;
+ }
+ return(0);
+}
+
+struct proto rawv6_prot = {
+ (struct sock *)&rawv6_prot, /* sklist_next */
+ (struct sock *)&rawv6_prot, /* sklist_prev */
+ rawv6_close, /* close */
+ udpv6_connect, /* connect */
+ NULL, /* accept */
+ NULL, /* retransmit */
+ NULL, /* write_wakeup */
+ NULL, /* read_wakeup */
+ datagram_poll, /* poll */
+ NULL, /* ioctl */
+ rawv6_init_sk, /* init */
+ inet6_destroy_sock, /* destroy */
+ NULL, /* shutdown */
+ rawv6_setsockopt, /* setsockopt */
+ rawv6_getsockopt, /* getsockopt */
+ rawv6_sendmsg, /* sendmsg */
+ rawv6_recvmsg, /* recvmsg */
+ rawv6_bind, /* bind */
+ rawv6_rcv_skb, /* backlog_rcv */
+ raw_v6_hash, /* hash */
+ raw_v6_unhash, /* unhash */
+ NULL, /* get_port */
+ 128, /* max_header */
+ 0, /* retransmits */
+ "RAW", /* name */
+ 0, /* inuse */
+ 0 /* highestinuse */
+};
diff --git a/pfinet/linux-src/net/ipv6/reassembly.c b/pfinet/linux-src/net/ipv6/reassembly.c
new file mode 100644
index 00000000..3e1575dd
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/reassembly.c
@@ -0,0 +1,492 @@
+/*
+ * IPv6 fragment reassembly
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: reassembly.c,v 1.1 2007/10/08 21:12:31 stesie Exp $
+ *
+ * Based on: net/ipv4/ip_fragment.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * Fixes:
+ * Andi Kleen Make it work with multiple hosts.
+ * More RFC compliance.
+ */
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+
+int sysctl_ip6frag_high_thresh = 256*1024;
+int sysctl_ip6frag_low_thresh = 192*1024;
+int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT;
+
+atomic_t ip6_frag_mem = ATOMIC_INIT(0);
+
+struct ipv6_frag {
+ __u16 offset;
+ __u16 len;
+ struct sk_buff *skb;
+
+ struct frag_hdr *fhdr;
+
+ struct ipv6_frag *next;
+};
+
+/*
+ * Equivalent of ipv4 struct ipq
+ */
+
+struct frag_queue {
+
+ struct frag_queue *next;
+ struct frag_queue *prev;
+
+ __u32 id; /* fragment id */
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+ struct timer_list timer; /* expire timer */
+ struct ipv6_frag *fragments;
+ struct device *dev;
+ int iif;
+ __u8 last_in; /* has first/last segment arrived? */
+#define FIRST_IN 2
+#define LAST_IN 1
+ __u8 nexthdr;
+ __u16 nhoffset;
+};
+
+static struct frag_queue ipv6_frag_queue = {
+ &ipv6_frag_queue, &ipv6_frag_queue,
+ 0, {{{0}}}, {{{0}}},
+ {0}, NULL, NULL,
+ 0, 0, 0, 0
+};
+
+/* Memory Tracking Functions. */
+extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
+{
+ atomic_sub(skb->truesize, &ip6_frag_mem);
+ kfree_skb(skb);
+}
+
+extern __inline__ void frag_kfree_s(void *ptr, int len)
+{
+ atomic_sub(len, &ip6_frag_mem);
+ kfree(ptr);
+}
+
+extern __inline__ void *frag_kmalloc(int size, int pri)
+{
+ void *vp = kmalloc(size, pri);
+
+ if(!vp)
+ return NULL;
+ atomic_add(size, &ip6_frag_mem);
+ return vp;
+}
+
+
+static void create_frag_entry(struct sk_buff *skb,
+ __u8 *nhptr,
+ struct frag_hdr *fhdr);
+static u8 * reasm_frag(struct frag_queue *fq,
+ struct sk_buff **skb_in);
+
+static void reasm_queue(struct frag_queue *fq,
+ struct sk_buff *skb,
+ struct frag_hdr *fhdr,
+ u8 *nhptr);
+
+static void fq_free(struct frag_queue *fq);
+
+static void frag_prune(void)
+{
+ struct frag_queue *fq;
+
+ while ((fq = ipv6_frag_queue.next) != &ipv6_frag_queue) {
+ ipv6_statistics.Ip6ReasmFails++;
+ fq_free(fq);
+ if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh)
+ return;
+ }
+ if (atomic_read(&ip6_frag_mem))
+ printk(KERN_DEBUG "IPv6 frag_prune: memleak\n");
+ atomic_set(&ip6_frag_mem, 0);
+}
+
+
+u8* ipv6_reassembly(struct sk_buff **skbp, __u8 *nhptr)
+{
+ struct sk_buff *skb = *skbp;
+ struct frag_hdr *fhdr = (struct frag_hdr *) (skb->h.raw);
+ struct frag_queue *fq;
+ struct ipv6hdr *hdr;
+
+ hdr = skb->nh.ipv6h;
+
+ ipv6_statistics.Ip6ReasmReqds++;
+
+ /* Jumbo payload inhibits frag. header */
+ if (hdr->payload_len==0) {
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw);
+ return NULL;
+ }
+ if ((u8 *)(fhdr+1) > skb->tail) {
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw);
+ return NULL;
+ }
+ if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
+ frag_prune();
+
+ for (fq = ipv6_frag_queue.next; fq != &ipv6_frag_queue; fq = fq->next) {
+ if (fq->id == fhdr->identification &&
+ !ipv6_addr_cmp(&hdr->saddr, &fq->saddr) &&
+ !ipv6_addr_cmp(&hdr->daddr, &fq->daddr)) {
+
+ reasm_queue(fq, skb, fhdr, nhptr);
+
+ if (fq->last_in == (FIRST_IN|LAST_IN))
+ return reasm_frag(fq, skbp);
+
+ return NULL;
+ }
+ }
+
+ create_frag_entry(skb, nhptr, fhdr);
+
+ return NULL;
+}
+
+
+static void fq_free(struct frag_queue *fq)
+{
+ struct ipv6_frag *fp, *back;
+
+ del_timer(&fq->timer);
+
+ for (fp = fq->fragments; fp; ) {
+ frag_kfree_skb(fp->skb);
+ back = fp;
+ fp=fp->next;
+ frag_kfree_s(back, sizeof(*back));
+ }
+
+ fq->prev->next = fq->next;
+ fq->next->prev = fq->prev;
+
+ fq->prev = fq->next = NULL;
+
+ frag_kfree_s(fq, sizeof(*fq));
+}
+
+static void frag_expire(unsigned long data)
+{
+ struct frag_queue *fq;
+ struct ipv6_frag *frag;
+
+ fq = (struct frag_queue *) data;
+
+ frag = fq->fragments;
+
+ ipv6_statistics.Ip6ReasmTimeout++;
+ ipv6_statistics.Ip6ReasmFails++;
+
+ if (frag == NULL) {
+ printk(KERN_DEBUG "invalid fragment queue\n");
+ return;
+ }
+
+ /* Send error only if the first segment arrived.
+ (fixed --ANK (980728))
+ */
+ if (fq->last_in&FIRST_IN) {
+ struct device *dev = dev_get_by_index(fq->iif);
+
+ /*
+ But use as source device on which LAST ARRIVED
+ segment was received. And do not use fq->dev
+ pointer directly, device might already disappeared.
+ */
+ if (dev) {
+ frag->skb->dev = dev;
+ icmpv6_send(frag->skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0,
+ dev);
+ }
+ }
+
+ fq_free(fq);
+}
+
+
+static void create_frag_entry(struct sk_buff *skb,
+ __u8 *nhptr,
+ struct frag_hdr *fhdr)
+{
+ struct frag_queue *fq;
+ struct ipv6hdr *hdr;
+
+ fq = (struct frag_queue *) frag_kmalloc(sizeof(struct frag_queue),
+ GFP_ATOMIC);
+
+ if (fq == NULL) {
+ ipv6_statistics.Ip6ReasmFails++;
+ kfree_skb(skb);
+ return;
+ }
+
+ memset(fq, 0, sizeof(struct frag_queue));
+
+ fq->id = fhdr->identification;
+
+ hdr = skb->nh.ipv6h;
+ ipv6_addr_copy(&fq->saddr, &hdr->saddr);
+ ipv6_addr_copy(&fq->daddr, &hdr->daddr);
+
+ /* init_timer has been done by the memset */
+ fq->timer.function = frag_expire;
+ fq->timer.data = (long) fq;
+ fq->timer.expires = jiffies + sysctl_ip6frag_time;
+
+ reasm_queue(fq, skb, fhdr, nhptr);
+
+ if (fq->fragments) {
+ fq->prev = ipv6_frag_queue.prev;
+ fq->next = &ipv6_frag_queue;
+ fq->prev->next = fq;
+ ipv6_frag_queue.prev = fq;
+
+ add_timer(&fq->timer);
+ } else
+ frag_kfree_s(fq, sizeof(*fq));
+}
+
+
+/*
+ * We queue the packet even if it's the last.
+ * It's a trade off. This allows the reassembly
+ * code to be simpler (=faster) and of the
+ * steps we do for queueing the only unnecessary
+ * one it's the kmalloc for a struct ipv6_frag.
+ * Feel free to try other alternatives...
+ */
+
+static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb,
+ struct frag_hdr *fhdr, u8 *nhptr)
+{
+ struct ipv6_frag *nfp, *fp, **bptr;
+
+ nfp = (struct ipv6_frag *) frag_kmalloc(sizeof(struct ipv6_frag),
+ GFP_ATOMIC);
+
+ if (nfp == NULL) {
+ kfree_skb(skb);
+ return;
+ }
+
+ nfp->offset = ntohs(fhdr->frag_off) & ~0x7;
+ nfp->len = (ntohs(skb->nh.ipv6h->payload_len) -
+ ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
+
+ if ((u32)nfp->offset + (u32)nfp->len >= 65536) {
+ icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off);
+ goto err;
+ }
+ if (fhdr->frag_off & __constant_htons(0x0001)) {
+ /* Check if the fragment is rounded to 8 bytes.
+ * Required by the RFC.
+ * ... and would break our defragmentation algorithm 8)
+ */
+ if (nfp->len & 0x7) {
+ printk(KERN_DEBUG "fragment not rounded to 8bytes\n");
+
+ /*
+ It is not in specs, but I see no reasons
+ to send an error in this case. --ANK
+ */
+ if (nfp->offset == 0)
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+ &skb->nh.ipv6h->payload_len);
+ goto err;
+ }
+ }
+
+ nfp->skb = skb;
+ nfp->fhdr = fhdr;
+ nfp->next = NULL;
+
+ bptr = &fq->fragments;
+
+ for (fp = fq->fragments; fp; fp=fp->next) {
+ if (nfp->offset <= fp->offset)
+ break;
+ bptr = &fp->next;
+ }
+ if (fp && fp->offset == nfp->offset) {
+ if (nfp->len != fp->len) {
+ printk(KERN_DEBUG "reasm_queue: dup with wrong len\n");
+ }
+
+ /* duplicate. discard it. */
+ goto err;
+ }
+
+ atomic_add(skb->truesize, &ip6_frag_mem);
+
+ /* All the checks are done, fragment is acepted.
+ Only now we are allowed to update reassembly data!
+ (fixed --ANK (980728))
+ */
+
+ /* iif always set to one of the last arrived segment */
+ fq->dev = skb->dev;
+ fq->iif = skb->dev->ifindex;
+
+ /* Last fragment */
+ if ((fhdr->frag_off & __constant_htons(0x0001)) == 0)
+ fq->last_in |= LAST_IN;
+
+ /* First fragment.
+ nexthdr and nhptr are get from the first fragment.
+ Moreover, nexthdr is UNDEFINED for all the fragments but the
+ first one.
+ (fixed --ANK (980728))
+ */
+ if (nfp->offset == 0) {
+ fq->nexthdr = fhdr->nexthdr;
+ fq->last_in |= FIRST_IN;
+ fq->nhoffset = nhptr - skb->nh.raw;
+ }
+
+ *bptr = nfp;
+ nfp->next = fp;
+ return;
+
+err:
+ frag_kfree_s(nfp, sizeof(*nfp));
+ kfree_skb(skb);
+}
+
+/*
+ * check if this fragment completes the packet
+ * returns true on success
+ */
+static u8* reasm_frag(struct frag_queue *fq, struct sk_buff **skb_in)
+{
+ struct ipv6_frag *fp;
+ struct ipv6_frag *head = fq->fragments;
+ struct ipv6_frag *tail = NULL;
+ struct sk_buff *skb;
+ __u32 offset = 0;
+ __u32 payload_len;
+ __u16 unfrag_len;
+ __u16 copy;
+ u8 *nhptr;
+
+ for(fp = head; fp; fp=fp->next) {
+ if (offset != fp->offset)
+ return NULL;
+
+ offset += fp->len;
+ tail = fp;
+ }
+
+ /*
+ * we know the m_flag arrived and we have a queue,
+ * starting from 0, without gaps.
+ * this means we have all fragments.
+ */
+
+ /* Unfragmented part is taken from the first segment.
+ (fixed --ANK (980728))
+ */
+ unfrag_len = (u8 *) (head->fhdr) - (u8 *) (head->skb->nh.ipv6h + 1);
+
+ payload_len = (unfrag_len + tail->offset +
+ (tail->skb->tail - (__u8 *) (tail->fhdr + 1)));
+
+ if (payload_len > 65535) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "reasm_frag: payload len = %d\n", payload_len);
+ ipv6_statistics.Ip6ReasmFails++;
+ fq_free(fq);
+ return NULL;
+ }
+
+ if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "reasm_frag: no memory for reassembly\n");
+ ipv6_statistics.Ip6ReasmFails++;
+ fq_free(fq);
+ return NULL;
+ }
+
+ copy = unfrag_len + sizeof(struct ipv6hdr);
+
+ skb->nh.ipv6h = (struct ipv6hdr *) skb->data;
+ skb->dev = fq->dev;
+ skb->protocol = __constant_htons(ETH_P_IPV6);
+ skb->pkt_type = head->skb->pkt_type;
+ memcpy(skb->cb, head->skb->cb, sizeof(skb->cb));
+ skb->dst = dst_clone(head->skb->dst);
+
+ memcpy(skb_put(skb, copy), head->skb->nh.ipv6h, copy);
+ nhptr = skb->nh.raw + fq->nhoffset;
+ *nhptr = fq->nexthdr;
+
+ skb->h.raw = skb->tail;
+
+ skb->nh.ipv6h->payload_len = ntohs(payload_len);
+
+ *skb_in = skb;
+
+ /*
+ * FIXME: If we don't have a checksum we ought to be able
+ * to defragment and checksum in this pass. [AC]
+ * Note that we don't really know yet whether the protocol
+ * needs checksums at all. It might still be a good idea. -AK
+ */
+ for(fp = fq->fragments; fp; ) {
+ struct ipv6_frag *back;
+
+ memcpy(skb_put(skb, fp->len), (__u8*)(fp->fhdr + 1), fp->len);
+ frag_kfree_skb(fp->skb);
+ back = fp;
+ fp=fp->next;
+ frag_kfree_s(back, sizeof(*back));
+ }
+
+ del_timer(&fq->timer);
+ fq->prev->next = fq->next;
+ fq->next->prev = fq->prev;
+ fq->prev = fq->next = NULL;
+
+ frag_kfree_s(fq, sizeof(*fq));
+
+ ipv6_statistics.Ip6ReasmOKs++;
+ return nhptr;
+}
diff --git a/pfinet/linux-src/net/ipv6/route_ipv6.c b/pfinet/linux-src/net/ipv6/route_ipv6.c
new file mode 100644
index 00000000..5f79a226
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/route_ipv6.c
@@ -0,0 +1,1974 @@
+/*
+ * Linux INET6 implementation
+ * FIB front-end.
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: route_ipv6.c,v 1.2 2007/10/08 21:59:10 stesie Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/init.h>
+#include <linux/netlink.h>
+#include <linux/if_arp.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <net/snmp.h>
+#include <net/ipv6.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <net/tcp.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+
+#undef CONFIG_RT6_POLICY
+
+/* Set to 3 to get tracing. */
+#define RT6_DEBUG 2
+
+#if RT6_DEBUG >= 3
+#define RDBG(x) printk x
+#define RT6_TRACE(x...) printk(KERN_DEBUG x)
+#else
+#define RDBG(x)
+#define RT6_TRACE(x...) do { ; } while (0)
+#endif
+
+#if RT6_DEBUG >= 1
+#define BUG_TRAP(x) ({ if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } })
+#else
+#define BUG_TRAP(x) do { ; } while (0)
+#endif
+
+
+int ip6_rt_max_size = 4096;
+int ip6_rt_gc_min_interval = 5*HZ;
+int ip6_rt_gc_timeout = 60*HZ;
+int ip6_rt_gc_interval = 30*HZ;
+int ip6_rt_gc_elasticity = 9;
+int ip6_rt_mtu_expires = 10*60*HZ;
+
+static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);
+static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
+static struct dst_entry *ip6_dst_reroute(struct dst_entry *dst,
+ struct sk_buff *skb);
+static struct dst_entry *ip6_negative_advice(struct dst_entry *);
+static int ip6_dst_gc(void);
+
+static int ip6_pkt_discard(struct sk_buff *skb);
+static void ip6_link_failure(struct sk_buff *skb);
+
+struct dst_ops ip6_dst_ops = {
+ AF_INET6,
+ __constant_htons(ETH_P_IPV6),
+ 1024,
+
+ ip6_dst_gc,
+ ip6_dst_check,
+ ip6_dst_reroute,
+ NULL,
+ ip6_negative_advice,
+ ip6_link_failure,
+};
+
+struct rt6_info ip6_null_entry = {
+ {{NULL, ATOMIC_INIT(1), ATOMIC_INIT(1), &loopback_dev,
+ -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ -ENETUNREACH, NULL, NULL,
+ ip6_pkt_discard, ip6_pkt_discard,
+#ifdef CONFIG_NET_CLS_ROUTE
+ 0,
+#endif
+ &ip6_dst_ops}},
+ NULL, {{{0}}}, RTF_REJECT|RTF_NONEXTHOP, ~0U,
+ 255, ATOMIC_INIT(1), {NULL}, {{{{0}}}, 0}, {{{{0}}}, 0}
+};
+
+struct fib6_node ip6_routing_table = {
+ NULL, NULL, NULL, NULL,
+ &ip6_null_entry,
+ 0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0
+};
+
+#ifdef CONFIG_RT6_POLICY
+int ip6_rt_policy = 0;
+
+struct pol_chain *rt6_pol_list = NULL;
+
+
+static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb);
+static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk);
+
+static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,
+ struct in6_addr *daddr,
+ struct in6_addr *saddr,
+ struct fl_acc_args *args);
+
+#else
+#define ip6_rt_policy (0)
+#endif
+
+/*
+ * Route lookup
+ */
+
+static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
+ int oif,
+ int strict)
+{
+ struct rt6_info *local = NULL;
+ struct rt6_info *sprt;
+
+ if (oif) {
+ for (sprt = rt; sprt; sprt = sprt->u.next) {
+ struct device *dev = sprt->rt6i_dev;
+ if (dev->ifindex == oif)
+ return sprt;
+ if (dev->flags&IFF_LOOPBACK)
+ local = sprt;
+ }
+
+ if (local)
+ return local;
+
+ if (strict)
+ return &ip6_null_entry;
+ }
+ return rt;
+}
+
+/*
+ * pointer to the last default router chosen
+ */
+static struct rt6_info *rt6_dflt_pointer = NULL;
+
+static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif)
+{
+ struct rt6_info *match = NULL;
+ struct rt6_info *sprt;
+ int mpri = 0;
+
+ for (sprt = rt; sprt; sprt = sprt->u.next) {
+ struct neighbour *neigh;
+
+ RDBG(("sprt(%p): ", sprt));
+ if ((neigh = sprt->rt6i_nexthop)) {
+ int m = -1;
+
+ RDBG(("nxthop(%p,%d) ", neigh, neigh->nud_state));
+ switch (neigh->nud_state) {
+ case NUD_REACHABLE:
+ RDBG(("NUD_REACHABLE "));
+ if (sprt != rt6_dflt_pointer) {
+ rt = sprt;
+ RDBG(("sprt!=dflt_ptr -> %p\n",
+ sprt));
+ goto out;
+ }
+ RDBG(("m=2, "));
+ m = 2;
+ break;
+
+ case NUD_DELAY:
+ RDBG(("NUD_DELAY, m=1, "));
+ m = 1;
+ break;
+
+ case NUD_STALE:
+ RDBG(("NUD_STALE, m=1, "));
+ m = 1;
+ break;
+ };
+
+ if (oif && sprt->rt6i_dev->ifindex == oif) {
+ m += 2;
+ }
+
+ if (m >= mpri) {
+ RDBG(("m>=mpri setmatch, "));
+ mpri = m;
+ match = sprt;
+ }
+ }
+ }
+
+ if (match) {
+ RDBG(("match, set rt, "));
+ rt = match;
+ } else {
+ /*
+ * No default routers are known to be reachable.
+ * SHOULD round robin
+ */
+ RDBG(("!match, trying rt6_dflt_pointer, "));
+ if (rt6_dflt_pointer) {
+ struct rt6_info *next;
+
+ if ((next = rt6_dflt_pointer->u.next) &&
+ next->u.dst.error == 0)
+ rt = next;
+ }
+ }
+
+out:
+ rt6_dflt_pointer = rt;
+ RDBG(("returning %p, dflt_ptr set\n", rt));
+ return rt;
+}
+
+struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
+ int oif, int strict)
+{
+ struct fib6_node *fn;
+ struct rt6_info *rt;
+
+ start_bh_atomic();
+ fn = fib6_lookup(&ip6_routing_table, daddr, saddr);
+ rt = rt6_device_match(fn->leaf, oif, strict);
+ atomic_inc(&rt->u.dst.use);
+ atomic_inc(&rt->u.dst.refcnt);
+ end_bh_atomic();
+
+ rt->u.dst.lastuse = jiffies;
+ if (rt->u.dst.error == 0)
+ return rt;
+ dst_release(&rt->u.dst);
+ return NULL;
+}
+
+static int rt6_ins(struct rt6_info *rt)
+{
+ int err;
+
+ start_bh_atomic();
+ err = fib6_add(&ip6_routing_table, rt);
+ end_bh_atomic();
+
+ return err;
+}
+
+static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
+ struct in6_addr *saddr)
+{
+ int err;
+ struct rt6_info *rt;
+
+ /*
+ * Clone the route.
+ */
+
+ rt = ip6_rt_copy(ort);
+
+ if (rt) {
+ ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
+
+ if (!(rt->rt6i_flags&RTF_GATEWAY))
+ ipv6_addr_copy(&rt->rt6i_gateway, daddr);
+
+ rt->rt6i_dst.plen = 128;
+ rt->rt6i_flags |= RTF_CACHE;
+
+#ifdef CONFIG_IPV6_SUBTREES
+ if (rt->rt6i_src.plen && saddr) {
+ ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
+ rt->rt6i_src.plen = 128;
+ }
+#endif
+
+ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
+
+ dst_clone(&rt->u.dst);
+ err = rt6_ins(rt);
+ if (err == 0)
+ return rt;
+ rt->u.dst.error = err;
+ return rt;
+ }
+ dst_clone(&ip6_null_entry.u.dst);
+ return &ip6_null_entry;
+}
+
+#ifdef CONFIG_RT6_POLICY
+static __inline__ struct rt6_info *rt6_flow_lookup_in(struct rt6_info *rt,
+ struct sk_buff *skb)
+{
+ struct in6_addr *daddr, *saddr;
+ struct fl_acc_args arg;
+
+ arg.type = FL_ARG_FORWARD;
+ arg.fl_u.skb = skb;
+
+ saddr = &skb->nh.ipv6h->saddr;
+ daddr = &skb->nh.ipv6h->daddr;
+
+ return rt6_flow_lookup(rt, daddr, saddr, &arg);
+}
+
+static __inline__ struct rt6_info *rt6_flow_lookup_out(struct rt6_info *rt,
+ struct sock *sk,
+ struct flowi *fl)
+{
+ struct fl_acc_args arg;
+
+ arg.type = FL_ARG_ORIGIN;
+ arg.fl_u.fl_o.sk = sk;
+ arg.fl_u.fl_o.flow = fl;
+
+ return rt6_flow_lookup(rt, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr,
+ &arg);
+}
+
+#endif
+
+#define BACKTRACK() \
+if (rt == &ip6_null_entry && strict) { \
+ while ((fn = fn->parent) != NULL) { \
+ if (fn->fn_flags & RTN_ROOT) { \
+ dst_clone(&rt->u.dst); \
+ goto out; \
+ } \
+ if (fn->fn_flags & RTN_RTINFO) \
+ goto restart; \
+ } \
+}
+
+
+void ip6_route_input(struct sk_buff *skb)
+{
+ struct fib6_node *fn;
+ struct rt6_info *rt;
+ int strict;
+
+ strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
+
+ fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,
+ &skb->nh.ipv6h->saddr);
+
+restart:
+ rt = fn->leaf;
+
+ if ((rt->rt6i_flags & RTF_CACHE)) {
+ if (ip6_rt_policy == 0) {
+ rt = rt6_device_match(rt, skb->dev->ifindex, strict);
+ BACKTRACK();
+ dst_clone(&rt->u.dst);
+ goto out;
+ }
+
+#ifdef CONFIG_RT6_POLICY
+ if ((rt->rt6i_flags & RTF_FLOW)) {
+ struct rt6_info *sprt;
+
+ for (sprt = rt; sprt; sprt = sprt->u.next) {
+ if (rt6_flow_match_in(sprt, skb)) {
+ rt = sprt;
+ dst_clone(&rt->u.dst);
+ goto out;
+ }
+ }
+ }
+#endif
+ }
+
+ rt = rt6_device_match(rt, skb->dev->ifindex, 0);
+ BACKTRACK();
+
+ if (ip6_rt_policy == 0) {
+ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
+ rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
+ &skb->nh.ipv6h->saddr);
+ goto out;
+ }
+ dst_clone(&rt->u.dst);
+ } else {
+#ifdef CONFIG_RT6_POLICY
+ rt = rt6_flow_lookup_in(rt, skb);
+#else
+ /* NEVER REACHED */
+#endif
+ }
+
+out:
+ rt->u.dst.lastuse = jiffies;
+ atomic_inc(&rt->u.dst.refcnt);
+ skb->dst = (struct dst_entry *) rt;
+}
+
+struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
+{
+ struct fib6_node *fn;
+ struct rt6_info *rt;
+ int strict;
+
+ strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
+
+ start_bh_atomic();
+ fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
+ fl->nl_u.ip6_u.saddr);
+
+restart:
+ rt = fn->leaf;
+
+ if ((rt->rt6i_flags & RTF_CACHE)) {
+ if (ip6_rt_policy == 0) {
+ rt = rt6_device_match(rt, fl->oif, strict);
+ BACKTRACK();
+ dst_clone(&rt->u.dst);
+ goto out;
+ }
+
+#ifdef CONFIG_RT6_POLICY
+ if ((rt->rt6i_flags & RTF_FLOW)) {
+ struct rt6_info *sprt;
+
+ for (sprt = rt; sprt; sprt = sprt->u.next) {
+ if (rt6_flow_match_out(sprt, sk)) {
+ rt = sprt;
+ dst_clone(&rt->u.dst);
+ goto out;
+ }
+ }
+ }
+#endif
+ }
+ if (rt->rt6i_flags & RTF_DEFAULT) {
+ if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
+ rt = rt6_best_dflt(rt, fl->oif);
+ } else {
+ rt = rt6_device_match(rt, fl->oif, strict);
+ BACKTRACK();
+ }
+
+ if (ip6_rt_policy == 0) {
+ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
+ rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
+ fl->nl_u.ip6_u.saddr);
+ goto out;
+ }
+ dst_clone(&rt->u.dst);
+ } else {
+#ifdef CONFIG_RT6_POLICY
+ rt = rt6_flow_lookup_out(rt, sk, fl);
+#else
+ /* NEVER REACHED */
+#endif
+ }
+
+out:
+ rt->u.dst.lastuse = jiffies;
+ atomic_inc(&rt->u.dst.refcnt);
+ end_bh_atomic();
+ return &rt->u.dst;
+}
+
+
+/*
+ * Destination cache support functions
+ */
+
+static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
+{
+ struct rt6_info *rt;
+
+ rt = (struct rt6_info *) dst;
+
+ if (rt && rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie))
+ return dst;
+
+ dst_release(dst);
+ return NULL;
+}
+
+static struct dst_entry *ip6_dst_reroute(struct dst_entry *dst, struct sk_buff *skb)
+{
+ /*
+ * FIXME
+ */
+ RDBG(("ip6_dst_reroute(%p,%p)[%p] (AIEEE)\n", dst, skb,
+ __builtin_return_address(0)));
+ return NULL;
+}
+
+static struct dst_entry *ip6_negative_advice(struct dst_entry *dst)
+{
+ struct rt6_info *rt = (struct rt6_info *) dst;
+
+ if (rt) {
+ if (rt->rt6i_flags & RTF_CACHE)
+ ip6_del_rt(rt);
+ dst_release(dst);
+ }
+ return NULL;
+}
+
+static void ip6_link_failure(struct sk_buff *skb)
+{
+ struct rt6_info *rt;
+
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
+
+ rt = (struct rt6_info *) skb->dst;
+ if (rt) {
+ if (rt->rt6i_flags&RTF_CACHE) {
+ dst_set_expires(&rt->u.dst, 0);
+ rt->rt6i_flags |= RTF_EXPIRES;
+ } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
+ rt->rt6i_node->fn_sernum = -1;
+ }
+}
+
+static int ip6_dst_gc()
+{
+ static unsigned expire = 30*HZ;
+ static unsigned long last_gc;
+ unsigned long now = jiffies;
+
+ start_bh_atomic();
+ if ((long)(now - last_gc) < ip6_rt_gc_min_interval)
+ goto out;
+
+ expire++;
+ fib6_run_gc(expire);
+ last_gc = now;
+ if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh)
+ expire = ip6_rt_gc_timeout>>1;
+
+out:
+ expire -= expire>>ip6_rt_gc_elasticity;
+ end_bh_atomic();
+ return (atomic_read(&ip6_dst_ops.entries) > ip6_rt_max_size);
+}
+
+/* Clean host part of a prefix. Not necessary in radix tree,
+ but results in cleaner routing tables.
+
+ Remove it only when all the things will work!
+ */
+
+static void ipv6_wash_prefix(struct in6_addr *pfx, int plen)
+{
+ int b = plen&0x7;
+ int o = (plen + 7)>>3;
+
+ if (o < 16)
+ memset(pfx->s6_addr + o, 0, 16 - o);
+ if (b != 0)
+ pfx->s6_addr[plen>>3] &= (0xFF<<(8-b));
+}
+
+static int ipv6_get_mtu(struct device *dev)
+{
+ struct inet6_dev *idev;
+
+ idev = ipv6_get_idev(dev);
+ if (idev)
+ return idev->cnf.mtu6;
+ else
+ return IPV6_MIN_MTU;
+}
+
+static int ipv6_get_hoplimit(struct device *dev)
+{
+ struct inet6_dev *idev;
+
+ idev = ipv6_get_idev(dev);
+ if (idev)
+ return idev->cnf.hop_limit;
+ else
+ return ipv6_devconf.hop_limit;
+}
+
+/*
+ *
+ */
+
+int ip6_route_add(struct in6_rtmsg *rtmsg)
+{
+ int err;
+ struct rt6_info *rt;
+ struct device *dev = NULL;
+ int addr_type;
+
+ if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128)
+ return -EINVAL;
+#ifndef CONFIG_IPV6_SUBTREES
+ if (rtmsg->rtmsg_src_len)
+ return -EINVAL;
+#endif
+ if (rtmsg->rtmsg_metric == 0)
+ rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;
+
+ rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops);
+
+ if (rt == NULL)
+ return -ENOMEM;
+
+ rt->u.dst.obsolete = -1;
+ rt->rt6i_expires = rtmsg->rtmsg_info;
+
+ addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst);
+
+ if (addr_type & IPV6_ADDR_MULTICAST)
+ rt->u.dst.input = ip6_mc_input;
+ else
+ rt->u.dst.input = ip6_forward;
+
+ rt->u.dst.output = ip6_output;
+
+ if (rtmsg->rtmsg_ifindex) {
+ dev = dev_get_by_index(rtmsg->rtmsg_ifindex);
+ err = -ENODEV;
+ if (dev == NULL)
+ goto out;
+ }
+
+ ipv6_addr_copy(&rt->rt6i_dst.addr, &rtmsg->rtmsg_dst);
+ rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;
+ ipv6_wash_prefix(&rt->rt6i_dst.addr, rt->rt6i_dst.plen);
+
+#ifdef CONFIG_IPV6_SUBTREES
+ ipv6_addr_copy(&rt->rt6i_src.addr, &rtmsg->rtmsg_src);
+ rt->rt6i_src.plen = rtmsg->rtmsg_src_len;
+ ipv6_wash_prefix(&rt->rt6i_src.addr, rt->rt6i_src.plen);
+#endif
+
+ rt->rt6i_metric = rtmsg->rtmsg_metric;
+
+ /* We cannot add true routes via loopback here,
+ they would result in kernel looping; promote them to reject routes
+ */
+ if ((rtmsg->rtmsg_flags&RTF_REJECT) ||
+ (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
+ dev = &loopback_dev;
+ rt->u.dst.output = ip6_pkt_discard;
+ rt->u.dst.input = ip6_pkt_discard;
+ rt->u.dst.error = -ENETUNREACH;
+ rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
+ goto install_route;
+ }
+
+ if (rtmsg->rtmsg_flags & RTF_GATEWAY) {
+ struct in6_addr *gw_addr;
+ int gwa_type;
+
+ gw_addr = &rtmsg->rtmsg_gateway;
+ ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway);
+ gwa_type = ipv6_addr_type(gw_addr);
+
+ if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
+ struct rt6_info *grt;
+
+ /* IPv6 strictly inhibits using not link-local
+ addresses as nexthop address.
+ Otherwise, router will not able to send redirects.
+ It is very good, but in some (rare!) curcumstances
+ (SIT, PtP, NBMA NOARP links) it is handy to allow
+ some exceptions. --ANK
+ */
+ err = -EINVAL;
+ if (!(gwa_type&IPV6_ADDR_UNICAST))
+ goto out;
+
+ grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);
+
+ err = -EHOSTUNREACH;
+ if (grt == NULL)
+ goto out;
+ if (!(grt->rt6i_flags&RTF_GATEWAY))
+ err = 0;
+ dev = grt->rt6i_dev;
+ dst_release(&grt->u.dst);
+
+ if (err)
+ goto out;
+ }
+ err = -EINVAL;
+ if (dev == NULL || (dev->flags&IFF_LOOPBACK))
+ goto out;
+ }
+
+ err = -ENODEV;
+ if (dev == NULL)
+ goto out;
+
+ if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) {
+ rt->rt6i_nexthop = ndisc_get_neigh(dev, &rt->rt6i_gateway);
+ err = -ENOMEM;
+ if (rt->rt6i_nexthop == NULL)
+ goto out;
+ }
+
+ if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
+ rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS;
+ else
+ rt->rt6i_hoplimit = ipv6_get_hoplimit(dev);
+ rt->rt6i_flags = rtmsg->rtmsg_flags;
+
+install_route:
+ rt->u.dst.pmtu = ipv6_get_mtu(dev);
+ rt->u.dst.rtt = TCP_TIMEOUT_INIT;
+ rt->rt6i_dev = dev;
+ return rt6_ins(rt);
+
+out:
+ dst_free((struct dst_entry *) rt);
+ return err;
+}
+
+int ip6_del_rt(struct rt6_info *rt)
+{
+ int err;
+
+ start_bh_atomic();
+ rt6_dflt_pointer = NULL;
+ err = fib6_del(rt);
+ end_bh_atomic();
+
+ return err;
+}
+
+int ip6_route_del(struct in6_rtmsg *rtmsg)
+{
+ struct fib6_node *fn;
+ struct rt6_info *rt;
+ int err = -ESRCH;
+
+ start_bh_atomic();
+
+ fn = fib6_locate(&ip6_routing_table,
+ &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len,
+ &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);
+
+ if (fn) {
+ for (rt = fn->leaf; rt; rt = rt->u.next) {
+ if (rtmsg->rtmsg_ifindex &&
+ (rt->rt6i_dev == NULL ||
+ rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex))
+ continue;
+ if (rtmsg->rtmsg_flags&RTF_GATEWAY &&
+ ipv6_addr_cmp(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway))
+ continue;
+ if (rtmsg->rtmsg_metric &&
+ rtmsg->rtmsg_metric != rt->rt6i_metric)
+ continue;
+ err = ip6_del_rt(rt);
+ break;
+ }
+ }
+ end_bh_atomic();
+
+ return err;
+}
+
+#ifdef CONFIG_IPV6_NETLINK
+/*
+ * NETLINK interface
+ * routing socket moral equivalent
+ */
+
+static int rt6_msgrcv(int unit, struct sk_buff *skb)
+{
+ int count = 0;
+ struct in6_rtmsg *rtmsg;
+ int err;
+
+ rtnl_lock();
+ while (skb->len) {
+ if (skb->len < sizeof(struct in6_rtmsg)) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ rtmsg = (struct in6_rtmsg *) skb->data;
+ skb_pull(skb, sizeof(struct in6_rtmsg));
+ count += sizeof(struct in6_rtmsg);
+
+ switch (rtmsg->rtmsg_type) {
+ case RTMSG_NEWROUTE:
+ err = ip6_route_add(rtmsg);
+ break;
+ case RTMSG_DELROUTE:
+ err = ip6_route_del(rtmsg);
+ break;
+ default:
+ count = -EINVAL;
+ goto out;
+ };
+ }
+
+out:
+ rtnl_unlock();
+ kfree_skb(skb);
+ return count;
+}
+
+static void rt6_sndrtmsg(struct in6_rtmsg *rtmsg)
+{
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+
+ memcpy(skb_put(skb, sizeof(struct in6_rtmsg)), &rtmsg,
+ sizeof(struct in6_rtmsg));
+
+ if (netlink_post(NETLINK_ROUTE6, skb))
+ kfree_skb(skb);
+}
+
+void rt6_sndmsg(int type, struct in6_addr *dst, struct in6_addr *src,
+ struct in6_addr *gw, struct device *dev,
+ int dstlen, int srclen, int metric, __u32 flags)
+{
+ struct sk_buff *skb;
+ struct in6_rtmsg *msg;
+
+ skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+
+ msg = (struct in6_rtmsg *) skb_put(skb, sizeof(struct in6_rtmsg));
+
+ memset(msg, 0, sizeof(struct in6_rtmsg));
+
+ msg->rtmsg_type = type;
+
+ if (dst)
+ ipv6_addr_copy(&msg->rtmsg_dst, dst);
+
+ if (src) {
+ ipv6_addr_copy(&msg->rtmsg_src, src);
+ msg->rtmsg_src_len = srclen;
+ }
+
+ if (gw)
+ ipv6_addr_copy(&msg->rtmsg_gateway, gw);
+
+ msg->rtmsg_dst_len = dstlen;
+ msg->rtmsg_metric = metric;
+
+ if (dev)
+ msg->rtmsg_ifindex = dev->ifindex;
+
+ msg->rtmsg_flags = flags;
+
+ if (netlink_post(NETLINK_ROUTE6, skb))
+ kfree_skb(skb);
+}
+#endif /* CONFIG_IPV6_NETLINK */
+
+/*
+ * Handle redirects
+ */
+void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
+ struct neighbour *neigh, int on_link)
+{
+ struct rt6_info *rt, *nrt;
+
+ /* Locate old route to this destination. */
+ rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
+
+ if (rt == NULL)
+ return;
+
+ if (neigh->dev != rt->rt6i_dev)
+ goto out;
+
+ /* Redirect received -> path was valid.
+ Look, redirects are sent only in response to data packets,
+ so that this nexthop apparently is reachable. --ANK
+ */
+ dst_confirm(&rt->u.dst);
+
+ /* Duplicate redirect: silently ignore. */
+ if (neigh == rt->u.dst.neighbour)
+ goto out;
+
+ /* Current route is on-link; redirect is always invalid.
+
+ Seems, previous statement is not true. It could
+ be node, which looks for us as on-link (f.e. proxy ndisc)
+ But then router serving it might decide, that we should
+ know truth 8)8) --ANK (980726).
+ */
+ if (!(rt->rt6i_flags&RTF_GATEWAY))
+ goto out;
+
+#if !defined(CONFIG_IPV6_EUI64) || defined(CONFIG_IPV6_NO_PB)
+ /*
+ * During transition gateways have more than
+ * one link local address. Certainly, it is violation
+ * of basic principles, but it is temparary.
+ */
+ /*
+ * RFC 1970 specifies that redirects should only be
+ * accepted if they come from the nexthop to the target.
+ * Due to the way default routers are chosen, this notion
+ * is a bit fuzzy and one might need to check all default
+ * routers.
+ */
+
+ if (ipv6_addr_cmp(saddr, &rt->rt6i_gateway)) {
+ if (rt->rt6i_flags & RTF_DEFAULT) {
+ struct rt6_info *rt1;
+
+ for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) {
+ if (!ipv6_addr_cmp(saddr, &rt1->rt6i_gateway)) {
+ dst_clone(&rt1->u.dst);
+ dst_release(&rt->u.dst);
+ rt = rt1;
+ goto source_ok;
+ }
+ }
+ }
+ if (net_ratelimit())
+ printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
+ "for redirect target\n");
+ goto out;
+ }
+
+source_ok:
+#endif
+
+ /*
+ * We have finally decided to accept it.
+ */
+
+ nrt = ip6_rt_copy(rt);
+ if (nrt == NULL)
+ goto out;
+
+ nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
+ if (on_link)
+ nrt->rt6i_flags &= ~RTF_GATEWAY;
+
+ ipv6_addr_copy(&nrt->rt6i_dst.addr, dest);
+ nrt->rt6i_dst.plen = 128;
+
+ ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
+ nrt->rt6i_nexthop = neigh_clone(neigh);
+ /* Reset pmtu, it may be better */
+ nrt->u.dst.pmtu = ipv6_get_mtu(neigh->dev);
+ nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev);
+
+ if (rt6_ins(nrt))
+ goto out;
+
+ /* Sic! rt6_redirect is called by bh, so that it is allowed */
+ dst_release(&rt->u.dst);
+ if (rt->rt6i_flags&RTF_CACHE)
+ ip6_del_rt(rt);
+ return;
+
+out:
+ dst_release(&rt->u.dst);
+ return;
+}
+
+/*
+ * Handle ICMP "packet too big" messages
+ * i.e. Path MTU discovery
+ */
+
+void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
+ struct device *dev, u32 pmtu)
+{
+ struct rt6_info *rt, *nrt;
+
+ if (pmtu < IPV6_MIN_MTU) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n",
+ pmtu);
+ return;
+ }
+
+ rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
+
+ if (rt == NULL)
+ return;
+
+ if (pmtu >= rt->u.dst.pmtu)
+ goto out;
+
+ /* New mtu received -> path was valid.
+ They are sent only in response to data packets,
+ so that this nexthop apparently is reachable. --ANK
+ */
+ dst_confirm(&rt->u.dst);
+
+ /* Host route. If it is static, it would be better
+ not to override it, but add new one, so that
+ when cache entry will expire old pmtu
+ would return automatically.
+ */
+ if (rt->rt6i_flags & RTF_CACHE) {
+ rt->u.dst.pmtu = pmtu;
+ dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
+ rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
+ goto out;
+ }
+
+ /* Network route.
+ Two cases are possible:
+ 1. It is connected route. Action: COW
+ 2. It is gatewayed route or NONEXTHOP route. Action: clone it.
+ */
+ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
+ nrt = rt6_cow(rt, daddr, saddr);
+ if (!nrt->u.dst.error) {
+ nrt->u.dst.pmtu = pmtu;
+ dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
+ nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
+ dst_release(&nrt->u.dst);
+ }
+ } else {
+ nrt = ip6_rt_copy(rt);
+ if (nrt == NULL)
+ goto out;
+ ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
+ nrt->rt6i_dst.plen = 128;
+ nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
+ dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
+ nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
+ nrt->u.dst.pmtu = pmtu;
+ rt6_ins(nrt);
+ }
+
+out:
+ dst_release(&rt->u.dst);
+}
+
+/*
+ * Misc support functions
+ */
+
+static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
+{
+ struct rt6_info *rt;
+
+ rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops);
+
+ if (rt) {
+ rt->u.dst.input = ort->u.dst.input;
+ rt->u.dst.output = ort->u.dst.output;
+
+ rt->u.dst.pmtu = ort->u.dst.pmtu;
+ rt->u.dst.rtt = ort->u.dst.rtt;
+ rt->u.dst.window = ort->u.dst.window;
+ rt->u.dst.mxlock = ort->u.dst.mxlock;
+ rt->u.dst.dev = ort->u.dst.dev;
+ rt->u.dst.lastuse = jiffies;
+ rt->rt6i_hoplimit = ort->rt6i_hoplimit;
+ rt->rt6i_expires = 0;
+
+ ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
+ rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;
+ rt->rt6i_metric = 0;
+
+ memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
+#ifdef CONFIG_IPV6_SUBTREES
+ memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
+#endif
+ }
+ return rt;
+}
+
+struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct device *dev)
+{
+ struct rt6_info *rt;
+ struct fib6_node *fn;
+
+ fn = &ip6_routing_table;
+
+ start_bh_atomic();
+ for (rt = fn->leaf; rt; rt=rt->u.next) {
+ if (dev == rt->rt6i_dev &&
+ ipv6_addr_cmp(&rt->rt6i_gateway, addr) == 0)
+ break;
+ }
+ if (rt)
+ dst_clone(&rt->u.dst);
+ end_bh_atomic();
+ return rt;
+}
+
+struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
+ struct device *dev)
+{
+ struct in6_rtmsg rtmsg;
+
+ memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
+ rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+ ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
+ rtmsg.rtmsg_metric = 1024;
+ rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP;
+
+ rtmsg.rtmsg_ifindex = dev->ifindex;
+
+ ip6_route_add(&rtmsg);
+ return rt6_get_dflt_router(gwaddr, dev);
+}
+
+void rt6_purge_dflt_routers(int last_resort)
+{
+ struct rt6_info *rt;
+ u32 flags;
+
+ if (last_resort)
+ flags = RTF_ALLONLINK;
+ else
+ flags = RTF_DEFAULT | RTF_ADDRCONF;
+
+restart:
+ rt6_dflt_pointer = NULL;
+
+ for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) {
+ if (rt->rt6i_flags & flags) {
+ ip6_del_rt(rt);
+ goto restart;
+ }
+ }
+}
+
+#ifndef _HURD_
+int ipv6_route_ioctl(unsigned int cmd, void *arg)
+{
+ struct in6_rtmsg rtmsg;
+ int err;
+
+ RDBG(("ipv6_route_ioctl(%d,%p)\n", cmd, arg));
+ switch(cmd) {
+ case SIOCADDRT: /* Add a route */
+ case SIOCDELRT: /* Delete a route */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ err = copy_from_user(&rtmsg, arg,
+ sizeof(struct in6_rtmsg));
+ if (err)
+ return -EFAULT;
+
+ rtnl_lock();
+ switch (cmd) {
+ case SIOCADDRT:
+ err = ip6_route_add(&rtmsg);
+ break;
+ case SIOCDELRT:
+ err = ip6_route_del(&rtmsg);
+ break;
+ default:
+ err = -EINVAL;
+ };
+ rtnl_unlock();
+
+#ifdef CONFIG_IPV6_NETLINK
+ if (err == 0)
+ rt6_sndrtmsg(&rtmsg);
+#endif
+ return err;
+ };
+
+ return -EINVAL;
+}
+#endif /* not _HURD_ */
+
+/*
+ * Drop the packet on the floor
+ */
+
+int ip6_pkt_discard(struct sk_buff *skb)
+{
+ ipv6_statistics.Ip6OutNoRoutes++;
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
+ kfree_skb(skb);
+ return 0;
+}
+
+/*
+ * Add address
+ */
+
+int ip6_rt_addr_add(struct in6_addr *addr, struct device *dev)
+{
+ struct rt6_info *rt;
+
+ rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops);
+ if (rt == NULL)
+ return -ENOMEM;
+
+ rt->u.dst.input = ip6_input;
+ rt->u.dst.output = ip6_output;
+ rt->rt6i_dev = dev_get("lo");
+ rt->u.dst.rtt = TCP_TIMEOUT_INIT;
+ rt->u.dst.pmtu = ipv6_get_mtu(rt->rt6i_dev);
+ rt->rt6i_hoplimit = ipv6_get_hoplimit(rt->rt6i_dev);
+ rt->u.dst.obsolete = -1;
+
+ rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
+ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
+ if (rt->rt6i_nexthop == NULL) {
+ dst_free((struct dst_entry *) rt);
+ return -ENOMEM;
+ }
+
+ ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+ rt->rt6i_dst.plen = 128;
+ rt6_ins(rt);
+
+ return 0;
+}
+
+/* Delete address. Warning: you should check that this address
+ disappeared before calling this function.
+ */
+
+int ip6_rt_addr_del(struct in6_addr *addr, struct device *dev)
+{
+ struct rt6_info *rt;
+ int err = -ENOENT;
+
+ rt = rt6_lookup(addr, NULL, loopback_dev.ifindex, 1);
+ if (rt) {
+ if (rt->rt6i_dst.plen == 128)
+ err= ip6_del_rt(rt);
+ dst_release(&rt->u.dst);
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_RT6_POLICY
+
+static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb)
+{
+ struct flow_filter *frule;
+ struct pkt_filter *filter;
+ int res = 1;
+
+ if ((frule = rt->rt6i_filter) == NULL)
+ goto out;
+
+ if (frule->type != FLR_INPUT) {
+ res = 0;
+ goto out;
+ }
+
+ for (filter = frule->u.filter; filter; filter = filter->next) {
+ __u32 *word;
+
+ word = (__u32 *) skb->h.raw;
+ word += filter->offset;
+
+ if ((*word ^ filter->value) & filter->mask) {
+ res = 0;
+ break;
+ }
+ }
+
+out:
+ return res;
+}
+
+static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk)
+{
+ struct flow_filter *frule;
+ int res = 1;
+
+ if ((frule = rt->rt6i_filter) == NULL)
+ goto out;
+
+ if (frule->type != FLR_INPUT) {
+ res = 0;
+ goto out;
+ }
+
+ if (frule->u.sk != sk)
+ res = 0;
+out:
+ return res;
+}
+
+static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,
+ struct in6_addr *daddr,
+ struct in6_addr *saddr,
+ struct fl_acc_args *args)
+{
+ struct flow_rule *frule;
+ struct rt6_info *nrt = NULL;
+ struct pol_chain *pol;
+
+ for (pol = rt6_pol_list; pol; pol = pol->next) {
+ struct fib6_node *fn;
+ struct rt6_info *sprt;
+
+ fn = fib6_lookup(pol->rules, daddr, saddr);
+
+ do {
+ for (sprt = fn->leaf; sprt; sprt=sprt->u.next) {
+ int res;
+
+ frule = sprt->rt6i_flowr;
+#if RT6_DEBUG >= 2
+ if (frule == NULL) {
+ printk(KERN_DEBUG "NULL flowr\n");
+ goto error;
+ }
+#endif
+ res = frule->ops->accept(rt, sprt, args, &nrt);
+
+ switch (res) {
+ case FLOWR_SELECT:
+ goto found;
+ case FLOWR_CLEAR:
+ goto next_policy;
+ case FLOWR_NODECISION:
+ break;
+ default:
+ goto error;
+ };
+ }
+
+ fn = fn->parent;
+
+ } while ((fn->fn_flags & RTN_TL_ROOT) == 0);
+
+ next_policy:
+ }
+
+error:
+ dst_clone(&ip6_null_entry.u.dst);
+ return &ip6_null_entry;
+
+found:
+ if (nrt == NULL)
+ goto error;
+
+ nrt->rt6i_flags |= RTF_CACHE;
+ dst_clone(&nrt->u.dst);
+ err = rt6_ins(nrt);
+ if (err)
+ nrt->u.dst.error = err;
+ return nrt;
+}
+#endif
+
+static int fib6_ifdown(struct rt6_info *rt, void *arg)
+{
+ if (((void*)rt->rt6i_dev == arg || arg == NULL) &&
+ rt != &ip6_null_entry) {
+ RT6_TRACE("deleted by ifdown %p\n", rt);
+ return -1;
+ }
+ return 0;
+}
+
+void rt6_ifdown(struct device *dev)
+{
+ fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev);
+}
+
+struct rt6_mtu_change_arg
+{
+ struct device *dev;
+ unsigned mtu;
+};
+
+static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
+{
+ struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
+
+ /* In IPv6 pmtu discovery is not optional,
+ so that RTAX_MTU lock cannot dissable it.
+ We still use this lock to block changes
+ caused by addrconf/ndisc.
+ */
+ if (rt->rt6i_dev == arg->dev &&
+ !(rt->u.dst.mxlock&(1<<RTAX_MTU)))
+ rt->u.dst.pmtu = arg->mtu;
+ return 0;
+}
+
+void rt6_mtu_change(struct device *dev, unsigned mtu)
+{
+ struct rt6_mtu_change_arg arg;
+
+ arg.dev = dev;
+ arg.mtu = mtu;
+ fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg);
+}
+
+#ifdef CONFIG_RTNETLINK
+
+static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta,
+ struct in6_rtmsg *rtmsg)
+{
+ memset(rtmsg, 0, sizeof(*rtmsg));
+
+ rtmsg->rtmsg_dst_len = r->rtm_dst_len;
+ rtmsg->rtmsg_src_len = r->rtm_src_len;
+ rtmsg->rtmsg_flags = RTF_UP;
+ if (r->rtm_type == RTN_UNREACHABLE)
+ rtmsg->rtmsg_flags |= RTF_REJECT;
+
+ if (rta[RTA_GATEWAY-1]) {
+ if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16))
+ return -EINVAL;
+ memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16);
+ rtmsg->rtmsg_flags |= RTF_GATEWAY;
+ }
+ if (rta[RTA_DST-1]) {
+ if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3))
+ return -EINVAL;
+ memcpy(&rtmsg->rtmsg_dst, RTA_DATA(rta[RTA_DST-1]), ((r->rtm_dst_len+7)>>3));
+ }
+ if (rta[RTA_SRC-1]) {
+ if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3))
+ return -EINVAL;
+ memcpy(&rtmsg->rtmsg_src, RTA_DATA(rta[RTA_SRC-1]), ((r->rtm_src_len+7)>>3));
+ }
+ if (rta[RTA_OIF-1]) {
+ if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int)))
+ return -EINVAL;
+ memcpy(&rtmsg->rtmsg_ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
+ }
+ if (rta[RTA_PRIORITY-1]) {
+ if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4))
+ return -EINVAL;
+ memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
+ }
+ return 0;
+}
+
+int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct rtmsg *r = NLMSG_DATA(nlh);
+ struct in6_rtmsg rtmsg;
+
+ if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
+ return -EINVAL;
+ return ip6_route_del(&rtmsg);
+}
+
+int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct rtmsg *r = NLMSG_DATA(nlh);
+ struct in6_rtmsg rtmsg;
+
+ if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
+ return -EINVAL;
+ return ip6_route_add(&rtmsg);
+}
+
+struct rt6_rtnl_dump_arg
+{
+ struct sk_buff *skb;
+ struct netlink_callback *cb;
+};
+
+static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
+ struct in6_addr *dst,
+ struct in6_addr *src,
+ int iif,
+ int type, u32 pid, u32 seq)
+{
+ struct rtmsg *rtm;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+ struct rtattr *mx;
+ struct rta_cacheinfo ci;
+
+ nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*rtm));
+ rtm = NLMSG_DATA(nlh);
+ rtm->rtm_family = AF_INET6;
+ rtm->rtm_dst_len = rt->rt6i_dst.plen;
+ rtm->rtm_src_len = rt->rt6i_src.plen;
+ rtm->rtm_tos = 0;
+ rtm->rtm_table = RT_TABLE_MAIN;
+ if (rt->rt6i_flags&RTF_REJECT)
+ rtm->rtm_type = RTN_UNREACHABLE;
+ else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK))
+ rtm->rtm_type = RTN_LOCAL;
+ else
+ rtm->rtm_type = RTN_UNICAST;
+ rtm->rtm_flags = 0;
+ rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+ rtm->rtm_protocol = RTPROT_BOOT;
+ if (rt->rt6i_flags&RTF_DYNAMIC)
+ rtm->rtm_protocol = RTPROT_REDIRECT;
+ else if (rt->rt6i_flags&(RTF_ADDRCONF|RTF_ALLONLINK))
+ rtm->rtm_protocol = RTPROT_KERNEL;
+ else if (rt->rt6i_flags&RTF_DEFAULT)
+ rtm->rtm_protocol = RTPROT_RA;
+
+ if (rt->rt6i_flags&RTF_CACHE)
+ rtm->rtm_flags |= RTM_F_CLONED;
+
+ if (dst) {
+ RTA_PUT(skb, RTA_DST, 16, dst);
+ rtm->rtm_dst_len = 128;
+ } else if (rtm->rtm_dst_len)
+ RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr);
+#ifdef CONFIG_IPV6_SUBTREES
+ if (src) {
+ RTA_PUT(skb, RTA_SRC, 16, src);
+ rtm->rtm_src_len = 128;
+ } else if (rtm->rtm_src_len)
+ RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr);
+#endif
+ if (iif)
+ RTA_PUT(skb, RTA_IIF, 4, &iif);
+ else if (dst) {
+ struct in6_addr saddr_buf;
+ if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf))
+ RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
+ }
+ mx = (struct rtattr*)skb->tail;
+ RTA_PUT(skb, RTA_METRICS, 0, NULL);
+ if (rt->u.dst.mxlock)
+ RTA_PUT(skb, RTAX_LOCK, sizeof(unsigned), &rt->u.dst.mxlock);
+ if (rt->u.dst.pmtu)
+ RTA_PUT(skb, RTAX_MTU, sizeof(unsigned), &rt->u.dst.pmtu);
+ if (rt->u.dst.window)
+ RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window);
+ if (rt->u.dst.rtt)
+ RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt);
+ mx->rta_len = skb->tail - (u8*)mx;
+ if (mx->rta_len == RTA_LENGTH(0))
+ skb_trim(skb, (u8*)mx - skb->data);
+ if (rt->u.dst.neighbour)
+ RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key);
+ if (rt->u.dst.dev)
+ RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->rt6i_dev->ifindex);
+ RTA_PUT(skb, RTA_PRIORITY, 4, &rt->rt6i_metric);
+ ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
+ if (rt->rt6i_expires)
+ ci.rta_expires = rt->rt6i_expires - jiffies;
+ else
+ ci.rta_expires = 0;
+ ci.rta_used = atomic_read(&rt->u.dst.refcnt);
+ ci.rta_clntref = atomic_read(&rt->u.dst.use);
+ ci.rta_error = rt->u.dst.error;
+ RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+static int rt6_dump_route(struct rt6_info *rt, void *p_arg)
+{
+ struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
+
+ return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
+ NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq);
+}
+
+static int fib6_dump_node(struct fib6_walker_t *w)
+{
+ int res;
+ struct rt6_info *rt;
+
+ for (rt = w->leaf; rt; rt = rt->u.next) {
+ res = rt6_dump_route(rt, w->args);
+ if (res < 0) {
+ /* Frame is full, suspend walking */
+ w->leaf = rt;
+ return 1;
+ }
+ BUG_TRAP(res!=0);
+ }
+ w->leaf = NULL;
+ return 0;
+}
+
+static int fib6_dump_done(struct netlink_callback *cb)
+{
+ struct fib6_walker_t *w = (void*)cb->args[0];
+
+ if (w) {
+ cb->args[0] = 0;
+ start_bh_atomic();
+ fib6_walker_unlink(w);
+ end_bh_atomic();
+ kfree(w);
+ }
+ if (cb->args[1]) {
+ cb->done = (void*)cb->args[1];
+ cb->args[1] = 0;
+ }
+ return cb->done(cb);
+}
+
+int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct rt6_rtnl_dump_arg arg;
+ struct fib6_walker_t *w;
+ int res;
+
+ arg.skb = skb;
+ arg.cb = cb;
+
+ w = (void*)cb->args[0];
+ if (w == NULL) {
+ /* New dump:
+ *
+ * 1. hook callback destructor.
+ */
+ cb->args[1] = (long)cb->done;
+ cb->done = fib6_dump_done;
+
+ /*
+ * 2. allocate and initialize walker.
+ */
+ w = kmalloc(sizeof(*w), GFP_KERNEL);
+ if (w == NULL)
+ return -ENOMEM;
+ RT6_TRACE("dump<%p", w);
+ memset(w, 0, sizeof(*w));
+ w->root = &ip6_routing_table;
+ w->func = fib6_dump_node;
+ w->args = &arg;
+ cb->args[0] = (long)w;
+ start_bh_atomic();
+ res = fib6_walk(w);
+ end_bh_atomic();
+ } else {
+ w->args = &arg;
+ start_bh_atomic();
+ res = fib6_walk_continue(w);
+ end_bh_atomic();
+ }
+#if RT6_DEBUG >= 3
+ if (res <= 0 && skb->len == 0)
+ RT6_TRACE("%p>dump end\n", w);
+#endif
+ /* res < 0 is an error. (really, impossible)
+ res == 0 means that dump is complete, but skb still can contain data.
+ res > 0 dump is not complete, but frame is full.
+ */
+ return res < 0 ? res : skb->len;
+}
+
+int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+{
+ struct rtattr **rta = arg;
+ int iif = 0;
+ int err;
+ struct sk_buff *skb;
+ struct flowi fl;
+ struct rt6_info *rt;
+
+ skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (skb == NULL)
+ return -ENOBUFS;
+
+ /* Reserve room for dummy headers, this skb can pass
+ through good chunk of routing engine.
+ */
+ skb->mac.raw = skb->data;
+ skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
+
+ fl.proto = 0;
+ fl.nl_u.ip6_u.daddr = NULL;
+ fl.nl_u.ip6_u.saddr = NULL;
+ fl.uli_u.icmpt.type = 0;
+ fl.uli_u.icmpt.code = 0;
+ if (rta[RTA_SRC-1])
+ fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]);
+ if (rta[RTA_DST-1])
+ fl.nl_u.ip6_u.daddr = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]);
+
+ if (rta[RTA_IIF-1])
+ memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+
+ if (iif) {
+ struct device *dev;
+ dev = dev_get_by_index(iif);
+ if (!dev)
+ return -ENODEV;
+ }
+
+ fl.oif = 0;
+ if (rta[RTA_OIF-1])
+ memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
+
+ rt = (struct rt6_info*)ip6_route_output(NULL, &fl);
+
+ skb->dst = &rt->u.dst;
+
+ NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+ err = rt6_fill_node(skb, rt,
+ fl.nl_u.ip6_u.daddr,
+ fl.nl_u.ip6_u.saddr,
+ iif,
+ RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq);
+ if (err < 0)
+ return -EMSGSIZE;
+
+ err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+void inet6_rt_notify(int event, struct rt6_info *rt)
+{
+ struct sk_buff *skb;
+ int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
+
+ skb = alloc_skb(size, gfp_any());
+ if (!skb) {
+ netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
+ return;
+ }
+ if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0) < 0) {
+ kfree_skb(skb);
+ netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
+ return;
+ }
+ NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_ROUTE;
+ netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_ROUTE, gfp_any());
+}
+
+#endif
+
+/*
+ * /proc
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#define RT6_INFO_LEN (32 + 4 + 32 + 4 + 32 + 40 + 5 + 1)
+
+struct rt6_proc_arg
+{
+ char *buffer;
+ int offset;
+ int length;
+ int skip;
+ int len;
+};
+
+static int rt6_info_route(struct rt6_info *rt, void *p_arg)
+{
+ struct rt6_proc_arg *arg = (struct rt6_proc_arg *) p_arg;
+ int i;
+
+ if (arg->skip < arg->offset / RT6_INFO_LEN) {
+ arg->skip++;
+ return 0;
+ }
+
+ if (arg->len >= arg->length)
+ return 0;
+
+ for (i=0; i<16; i++) {
+ sprintf(arg->buffer + arg->len, "%02x",
+ rt->rt6i_dst.addr.s6_addr[i]);
+ arg->len += 2;
+ }
+ arg->len += sprintf(arg->buffer + arg->len, " %02x ",
+ rt->rt6i_dst.plen);
+
+#ifdef CONFIG_IPV6_SUBTREES
+ for (i=0; i<16; i++) {
+ sprintf(arg->buffer + arg->len, "%02x",
+ rt->rt6i_src.addr.s6_addr[i]);
+ arg->len += 2;
+ }
+ arg->len += sprintf(arg->buffer + arg->len, " %02x ",
+ rt->rt6i_src.plen);
+#else
+ sprintf(arg->buffer + arg->len,
+ "00000000000000000000000000000000 00 ");
+ arg->len += 36;
+#endif
+
+ if (rt->rt6i_nexthop) {
+ for (i=0; i<16; i++) {
+ sprintf(arg->buffer + arg->len, "%02x",
+ rt->rt6i_nexthop->primary_key[i]);
+ arg->len += 2;
+ }
+ } else {
+ sprintf(arg->buffer + arg->len,
+ "00000000000000000000000000000000");
+ arg->len += 32;
+ }
+ arg->len += sprintf(arg->buffer + arg->len,
+ " %08x %08x %08x %08x %8s\n",
+ rt->rt6i_metric, atomic_read(&rt->u.dst.use),
+ atomic_read(&rt->u.dst.refcnt), rt->rt6i_flags,
+ rt->rt6i_dev ? rt->rt6i_dev->name : "");
+ return 0;
+}
+
+static int rt6_proc_info(char *buffer, char **start, off_t offset, int length,
+ int dummy)
+{
+ struct rt6_proc_arg arg;
+ arg.buffer = buffer;
+ arg.offset = offset;
+ arg.length = length;
+ arg.skip = 0;
+ arg.len = 0;
+
+ fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg);
+
+ *start = buffer;
+ if (offset)
+ *start += offset % RT6_INFO_LEN;
+
+ arg.len -= offset % RT6_INFO_LEN;
+
+ if (arg.len > length)
+ arg.len = length;
+ if (arg.len < 0)
+ arg.len = 0;
+
+ return arg.len;
+}
+
+extern struct rt6_statistics rt6_stats;
+
+static int rt6_proc_stats(char *buffer, char **start, off_t offset, int length,
+ int dummy)
+{
+ int len;
+
+ len = sprintf(buffer, "%04x %04x %04x %04x %04x %04x\n",
+ rt6_stats.fib_nodes, rt6_stats.fib_route_nodes,
+ rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries,
+ rt6_stats.fib_rt_cache,
+ atomic_read(&ip6_dst_ops.entries));
+
+ len -= offset;
+
+ if (len > length)
+ len = length;
+ if(len < 0)
+ len = 0;
+
+ *start = buffer + offset;
+
+ return len;
+}
+
+static struct proc_dir_entry proc_rt6_info = {
+ PROC_NET_RT6, 10, "ipv6_route",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ rt6_proc_info
+};
+static struct proc_dir_entry proc_rt6_stats = {
+ PROC_NET_RT6_STATS, 9, "rt6_stats",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, &proc_net_inode_operations,
+ rt6_proc_stats
+};
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_SYSCTL
+
+static int flush_delay;
+
+static
+int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp)
+{
+ if (write) {
+ proc_dointvec(ctl, write, filp, buffer, lenp);
+ if (flush_delay < 0)
+ flush_delay = 0;
+ start_bh_atomic();
+ fib6_run_gc((unsigned long)flush_delay);
+ end_bh_atomic();
+ return 0;
+ } else
+ return -EINVAL;
+}
+
+ctl_table ipv6_route_table[] = {
+ {NET_IPV6_ROUTE_FLUSH, "flush",
+ &flush_delay, sizeof(int), 0644, NULL,
+ &ipv6_sysctl_rtcache_flush},
+ {NET_IPV6_ROUTE_GC_THRESH, "gc_thresh",
+ &ip6_dst_ops.gc_thresh, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV6_ROUTE_MAX_SIZE, "max_size",
+ &ip6_rt_max_size, sizeof(int), 0644, NULL,
+ &proc_dointvec},
+ {NET_IPV6_ROUTE_GC_MIN_INTERVAL, "gc_min_interval",
+ &ip6_rt_gc_min_interval, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_IPV6_ROUTE_GC_TIMEOUT, "gc_timeout",
+ &ip6_rt_gc_timeout, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_IPV6_ROUTE_GC_INTERVAL, "gc_interval",
+ &ip6_rt_gc_interval, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_IPV6_ROUTE_GC_ELASTICITY, "gc_elasticity",
+ &ip6_rt_gc_elasticity, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {NET_IPV6_ROUTE_MTU_EXPIRES, "mtu_expires",
+ &ip6_rt_mtu_expires, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies},
+ {0}
+};
+
+#endif
+
+
+__initfunc(void ip6_route_init(void))
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_register(&proc_rt6_info);
+ proc_net_register(&proc_rt6_stats);
+#endif
+#ifdef CONFIG_IPV6_NETLINK
+ netlink_attach(NETLINK_ROUTE6, rt6_msgrcv);
+#endif
+}
+
+#ifdef MODULE
+void ip6_route_cleanup(void)
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_unregister(PROC_NET_RT6);
+ proc_net_unregister(PROC_NET_RT6_STATS);
+#endif
+#ifdef CONFIG_IPV6_NETLINK
+ netlink_detach(NETLINK_ROUTE6);
+#endif
+ rt6_ifdown(NULL);
+ fib6_gc_cleanup();
+}
+#endif /* MODULE */
diff --git a/pfinet/linux-src/net/ipv6/tcp_ipv6.c b/pfinet/linux-src/net/ipv6/tcp_ipv6.c
new file mode 100644
index 00000000..c761e76c
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/tcp_ipv6.c
@@ -0,0 +1,1767 @@
+/*
+ * TCP over IPv6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * $Id: tcp_ipv6.c,v 1.3 2007/10/13 01:43:00 stesie Exp $
+ *
+ * Based on:
+ * linux/net/ipv4/tcp.c
+ * linux/net/ipv4/tcp_input.c
+ * linux/net/ipv4/tcp_output.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/init.h>
+
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <linux/random.h>
+
+#include <net/tcp.h>
+#include <net/ndisc.h>
+#include <net/ipv6.h>
+#include <net/transp_v6.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+
+#include <asm/uaccess.h>
+
+extern int sysctl_max_syn_backlog;
+
+static void tcp_v6_send_reset(struct sk_buff *skb);
+static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len,
+ struct sk_buff *skb);
+
+static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
+static void tcp_v6_xmit(struct sk_buff *skb);
+static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
+ struct ipv6hdr *ip6h,
+ struct tcphdr *th,
+ int iif,
+ struct open_request **prevp);
+
+static struct tcp_func ipv6_mapped;
+static struct tcp_func ipv6_specific;
+
+/* I have no idea if this is a good hash for v6 or not. -DaveM */
+static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport,
+ struct in6_addr *faddr, u16 fport)
+{
+ int hashent = (lport ^ fport);
+
+ hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
+ return (hashent & ((tcp_ehash_size/2) - 1));
+}
+
+static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
+{
+ struct in6_addr *laddr = &sk->net_pinfo.af_inet6.rcv_saddr;
+ struct in6_addr *faddr = &sk->net_pinfo.af_inet6.daddr;
+ __u16 lport = sk->num;
+ __u16 fport = sk->dport;
+ return tcp_v6_hashfn(laddr, lport, faddr, fport);
+}
+
+/* Grrr, addr_type already calculated by caller, but I don't want
+ * to add some silly "cookie" argument to this method just for that.
+ * But it doesn't matter, the recalculation is in the rarest path
+ * this function ever takes.
+ */
+static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
+{
+ struct tcp_bind_bucket *tb;
+
+ SOCKHASH_LOCK();
+ if (snum == 0) {
+ int rover = tcp_port_rover;
+ int low = sysctl_local_port_range[0];
+ int high = sysctl_local_port_range[1];
+ int remaining = (high - low) + 1;
+
+ do { rover++;
+ if ((rover < low) || (rover > high))
+ rover = low;
+ tb = tcp_bhash[tcp_bhashfn(rover)];
+ for ( ; tb; tb = tb->next)
+ if (tb->port == rover)
+ goto next;
+ break;
+
+ next:
+ (void) 0;
+
+ } while (--remaining > 0);
+ tcp_port_rover = rover;
+
+ /* Exhausted local port range during search? */
+ if (remaining <= 0)
+ goto fail;
+
+ /* OK, here is the one we will use. */
+ snum = rover;
+ tb = NULL;
+ } else {
+ for (tb = tcp_bhash[tcp_bhashfn(snum)];
+ tb != NULL;
+ tb = tb->next)
+ if (tb->port == snum)
+ break;
+ }
+ if (tb != NULL && tb->owners != NULL) {
+ if (tb->fastreuse != 0 && sk->reuse != 0) {
+ goto success;
+ } else {
+ struct sock *sk2 = tb->owners;
+ int sk_reuse = sk->reuse;
+ int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
+
+ for( ; sk2 != NULL; sk2 = sk2->bind_next) {
+ if (sk->bound_dev_if == sk2->bound_dev_if) {
+ if (!sk_reuse ||
+ !sk2->reuse ||
+ sk2->state == TCP_LISTEN) {
+ /* NOTE: IPv6 tw bucket have different format */
+ if (!sk2->rcv_saddr ||
+ addr_type == IPV6_ADDR_ANY ||
+ !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+ sk2->state != TCP_TIME_WAIT ?
+ &sk2->net_pinfo.af_inet6.rcv_saddr :
+ &((struct tcp_tw_bucket*)sk)->v6_rcv_saddr))
+ break;
+ }
+ }
+ }
+ /* If we found a conflict, fail. */
+ if (sk2 != NULL)
+ goto fail;
+ }
+ }
+ if (tb == NULL &&
+ (tb = tcp_bucket_create(snum)) == NULL)
+ goto fail;
+ if (tb->owners == NULL) {
+ if (sk->reuse && sk->state != TCP_LISTEN)
+ tb->fastreuse = 1;
+ else
+ tb->fastreuse = 0;
+ } else if (tb->fastreuse &&
+ ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
+ tb->fastreuse = 0;
+
+success:
+ sk->num = snum;
+ if ((sk->bind_next = tb->owners) != NULL)
+ tb->owners->bind_pprev = &sk->bind_next;
+ tb->owners = sk;
+ sk->bind_pprev = &tb->owners;
+ sk->prev = (struct sock *) tb;
+
+ SOCKHASH_UNLOCK();
+ return 0;
+
+fail:
+ SOCKHASH_UNLOCK();
+ return 1;
+}
+
+static void tcp_v6_hash(struct sock *sk)
+{
+ if(sk->state != TCP_CLOSE) {
+ struct sock **skp;
+
+ /* Well, I know that it is ugly...
+ * All this ->prot, ->af_specific etc. need LARGE cleanup --ANK
+ */
+ if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) {
+ tcp_prot.hash(sk);
+ return;
+ }
+
+ if(sk->state == TCP_LISTEN)
+ skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+ else
+ skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+
+ SOCKHASH_LOCK();
+ if((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+ SOCKHASH_UNLOCK();
+ }
+}
+
+static void tcp_v6_unhash(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if(sk->pprev) {
+ if(sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ tcp_reg_zap(sk);
+ __tcp_put_port(sk);
+ }
+ SOCKHASH_UNLOCK();
+}
+
+static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned short hnum, int dif)
+{
+ struct sock *sk;
+ struct sock *result = NULL;
+ int score, hiscore;
+
+ hiscore=0;
+ sk = tcp_listening_hash[tcp_lhashfn(hnum)];
+ for(; sk; sk = sk->next) {
+ if((sk->num == hnum) && (sk->family == PF_INET6)) {
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+
+ score = 1;
+ if(!ipv6_addr_any(&np->rcv_saddr)) {
+ if(ipv6_addr_cmp(&np->rcv_saddr, daddr))
+ continue;
+ score++;
+ }
+ if (sk->bound_dev_if) {
+ if (sk->bound_dev_if != dif)
+ continue;
+ score++;
+ }
+ if (score == 3)
+ return sk;
+ if (score > hiscore) {
+ hiscore = score;
+ result = sk;
+ }
+ }
+ }
+ return result;
+}
+
+/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
+ * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ * It is assumed that this code only gets called from within NET_BH.
+ */
+static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
+ struct in6_addr *saddr, u16 sport,
+ struct in6_addr *daddr, u16 dport,
+ int dif)
+{
+ struct sock *sk;
+ __u16 hnum = ntohs(dport);
+ __u32 ports = TCP_COMBINED_PORTS(sport, hnum);
+ int hash;
+
+ /* Check TCP register quick cache first. */
+ sk = TCP_RHASH(sport);
+ if(sk && TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif))
+ goto hit;
+
+ /* Optimize here for direct hit, only listening connections can
+ * have wildcards anyways.
+ */
+ hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
+ for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
+ /* For IPV6 do the cheaper port and family tests first. */
+ if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) {
+ if (sk->state == TCP_ESTABLISHED)
+ TCP_RHASH(sport) = sk;
+ goto hit; /* You sunk my battleship! */
+ }
+ }
+ /* Must check for a TIME_WAIT'er before going to listener hash. */
+ for(sk = tcp_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next) {
+ if(*((__u32 *)&(sk->dport)) == ports &&
+ sk->family == PF_INET6) {
+ struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
+ if(!ipv6_addr_cmp(&tw->v6_daddr, saddr) &&
+ !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr) &&
+ (!sk->bound_dev_if || sk->bound_dev_if == dif))
+ goto hit;
+ }
+ }
+ sk = tcp_v6_lookup_listener(daddr, hnum, dif);
+hit:
+ return sk;
+}
+
+#define tcp_v6_lookup(sa, sp, da, dp, dif) __tcp_v6_lookup((0),(sa),(sp),(da),(dp),(dif))
+
+static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
+ struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ unsigned long base)
+{
+ return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
+}
+
+static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
+{
+ __u32 si;
+ __u32 di;
+
+ if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+ si = skb->nh.ipv6h->saddr.s6_addr32[3];
+ di = skb->nh.ipv6h->daddr.s6_addr32[3];
+ } else {
+ si = skb->nh.iph->saddr;
+ di = skb->nh.iph->daddr;
+ }
+
+ return secure_tcp_sequence_number(di, si,
+ skb->h.th->dest,
+ skb->h.th->source);
+}
+
+static int tcp_v6_unique_address(struct sock *sk)
+{
+ struct tcp_bind_bucket *tb;
+ unsigned short snum = sk->num;
+ int retval = 1;
+
+ /* Freeze the hash while we snoop around. */
+ SOCKHASH_LOCK();
+ tb = tcp_bhash[tcp_bhashfn(snum)];
+ for(; tb; tb = tb->next) {
+ if(tb->port == snum && tb->owners != NULL) {
+ /* Almost certainly the re-use port case, search the real hashes
+ * so it actually scales. (we hope that all ipv6 ftp servers will
+ * use passive ftp, I just cover this case for completeness)
+ */
+ sk = __tcp_v6_lookup(NULL, &sk->net_pinfo.af_inet6.daddr,
+ sk->dport,
+ &sk->net_pinfo.af_inet6.rcv_saddr,
+ htons(snum),
+ sk->bound_dev_if);
+ if((sk != NULL) && (sk->state != TCP_LISTEN))
+ retval = 0;
+ break;
+ }
+ }
+ SOCKHASH_UNLOCK();
+ return retval;
+}
+
+static __inline__ int tcp_v6_iif(struct sk_buff *skb)
+{
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+ return opt->iif;
+}
+
+static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
+ int addr_len)
+{
+ struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct in6_addr *saddr = NULL;
+ struct in6_addr saddr_buf;
+ struct flowi fl;
+ struct dst_entry *dst;
+ struct sk_buff *buff;
+ int addr_type;
+ int err;
+
+ if (sk->state != TCP_CLOSE)
+ return(-EISCONN);
+
+ /*
+ * Don't allow a double connect.
+ */
+
+ if(!ipv6_addr_any(&np->daddr))
+ return -EINVAL;
+
+ if (addr_len < sizeof(struct sockaddr_in6))
+ return(-EINVAL);
+
+ if (usin->sin6_family && usin->sin6_family != AF_INET6)
+ return(-EAFNOSUPPORT);
+
+ fl.fl6_flowlabel = 0;
+ if (np->sndflow) {
+ fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+ struct ip6_flowlabel *flowlabel;
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
+ fl6_sock_release(flowlabel);
+ }
+ }
+
+ /*
+ * connect() to INADDR_ANY means loopback (BSD'ism).
+ */
+
+ if(ipv6_addr_any(&usin->sin6_addr))
+ usin->sin6_addr.s6_addr[15] = 0x1;
+
+ addr_type = ipv6_addr_type(&usin->sin6_addr);
+
+ if(addr_type & IPV6_ADDR_MULTICAST)
+ return -ENETUNREACH;
+
+ if (addr_type&IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ usin->sin6_scope_id) {
+ /* If interface is set while binding, indices
+ * must coincide.
+ */
+ if (sk->bound_dev_if &&
+ sk->bound_dev_if != usin->sin6_scope_id)
+ return -EINVAL;
+
+ sk->bound_dev_if = usin->sin6_scope_id;
+ }
+
+ /* Connect to link-local address requires an interface */
+ if (!sk->bound_dev_if)
+ return -EINVAL;
+ }
+
+ /*
+ * connect to self not allowed
+ */
+
+ if (ipv6_addr_cmp(&usin->sin6_addr, &np->saddr) == 0 &&
+ usin->sin6_port == sk->sport)
+ return (-EINVAL);
+
+ memcpy(&np->daddr, &usin->sin6_addr, sizeof(struct in6_addr));
+ np->flow_label = fl.fl6_flowlabel;
+
+ /*
+ * TCP over IPv4
+ */
+
+ if (addr_type == IPV6_ADDR_MAPPED) {
+ u32 exthdrlen = tp->ext_header_len;
+ struct sockaddr_in sin;
+
+ SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = usin->sin6_port;
+ sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
+
+ sk->tp_pinfo.af_tcp.af_specific = &ipv6_mapped;
+ sk->backlog_rcv = tcp_v4_do_rcv;
+
+ err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
+
+ if (err) {
+ tp->ext_header_len = exthdrlen;
+ sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
+ sk->backlog_rcv = tcp_v6_do_rcv;
+ goto failure;
+ } else {
+ ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF),
+ sk->saddr);
+ ipv6_addr_set(&np->rcv_saddr, 0, 0, __constant_htonl(0x0000FFFF),
+ sk->rcv_saddr);
+ }
+
+ return err;
+ }
+
+ if (!ipv6_addr_any(&np->rcv_saddr))
+ saddr = &np->rcv_saddr;
+
+ fl.proto = IPPROTO_TCP;
+ fl.fl6_dst = &np->daddr;
+ fl.fl6_src = saddr;
+ fl.oif = sk->bound_dev_if;
+ fl.uli_u.ports.dport = usin->sin6_port;
+ fl.uli_u.ports.sport = sk->sport;
+
+ if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+ fl.nl_u.ip6_u.daddr = rt0->addr;
+ }
+
+ dst = ip6_route_output(sk, &fl);
+
+ if ((err = dst->error) != 0) {
+ dst_release(dst);
+ goto failure;
+ }
+
+ if (fl.oif == 0 && addr_type&IPV6_ADDR_LINKLOCAL) {
+ /* Ough! This guy tries to connect to link local
+ * address and did not specify interface.
+ * Actually we should kick him out, but
+ * we will be patient :) --ANK
+ */
+ sk->bound_dev_if = dst->dev->ifindex;
+ }
+
+ ip6_dst_store(sk, dst, NULL);
+
+ if (saddr == NULL) {
+ err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
+ if (err)
+ goto failure;
+
+ saddr = &saddr_buf;
+ }
+
+ /* set the source address */
+ ipv6_addr_copy(&np->rcv_saddr, saddr);
+ ipv6_addr_copy(&np->saddr, saddr);
+
+ tp->ext_header_len = 0;
+ if (np->opt)
+ tp->ext_header_len = np->opt->opt_flen+np->opt->opt_nflen;
+ /* Reset mss clamp */
+ tp->mss_clamp = ~0;
+
+ err = -ENOBUFS;
+ buff = sock_wmalloc(sk, (MAX_HEADER + sk->prot->max_header),
+ 0, GFP_KERNEL);
+
+ if (buff == NULL)
+ goto failure;
+
+ sk->dport = usin->sin6_port;
+
+ if (!tcp_v6_unique_address(sk)) {
+ kfree_skb(buff);
+ err = -EADDRNOTAVAIL;
+ goto failure;
+ }
+
+ /*
+ * Init variables
+ */
+
+ tp->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3],
+ np->daddr.s6_addr32[3],
+ sk->sport, sk->dport);
+
+ tcp_connect(sk, buff, dst->pmtu);
+
+ return 0;
+
+failure:
+ dst_release(xchg(&sk->dst_cache, NULL));
+ memset(&np->daddr, 0, sizeof(struct in6_addr));
+ sk->daddr = 0;
+ return err;
+}
+
+static int tcp_v6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ int retval = -EINVAL;
+
+ /*
+ * Do sanity checking for sendmsg/sendto/send
+ */
+
+ if (msg->msg_flags & ~(MSG_OOB|MSG_DONTROUTE|MSG_DONTWAIT|MSG_NOSIGNAL))
+ goto out;
+ if (msg->msg_name) {
+ struct sockaddr_in6 *addr=(struct sockaddr_in6 *)msg->msg_name;
+
+ if (msg->msg_namelen < sizeof(*addr))
+ goto out;
+
+ if (addr->sin6_family && addr->sin6_family != AF_INET6)
+ goto out;
+ retval = -ENOTCONN;
+
+ if(sk->state == TCP_CLOSE)
+ goto out;
+ retval = -EISCONN;
+ if (addr->sin6_port != sk->dport)
+ goto out;
+ if (ipv6_addr_cmp(&addr->sin6_addr, &np->daddr))
+ goto out;
+ if (np->sndflow && np->flow_label != (addr->sin6_flowinfo&IPV6_FLOWINFO_MASK))
+ goto out;
+ }
+
+ retval = tcp_do_sendmsg(sk, msg);
+
+out:
+ return retval;
+}
+
+void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
+ struct inet6_skb_parm *opt,
+ int type, int code, unsigned char *header, __u32 info)
+{
+ struct in6_addr *saddr = &hdr->saddr;
+ struct in6_addr *daddr = &hdr->daddr;
+ struct tcphdr *th = (struct tcphdr *)header;
+ struct ipv6_pinfo *np;
+ struct sock *sk;
+ int err;
+ struct tcp_opt *tp;
+ __u32 seq;
+
+ if (header + 8 > skb->tail)
+ return;
+
+ sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex);
+
+ if (sk == NULL || sk->state == TCP_TIME_WAIT) {
+ /* XXX: Update ICMP error count */
+ return;
+ }
+
+ tp = &sk->tp_pinfo.af_tcp;
+ seq = ntohl(th->seq);
+ if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) {
+ net_statistics.OutOfWindowIcmps++;
+ return;
+ }
+
+ np = &sk->net_pinfo.af_inet6;
+ if (type == ICMPV6_PKT_TOOBIG) {
+ struct dst_entry *dst = NULL;
+
+ if (atomic_read(&sk->sock_readers))
+ return;
+
+ if (sk->state == TCP_LISTEN)
+ return;
+
+ /* icmp should have updated the destination cache entry */
+ if (sk->dst_cache)
+ dst = dst_check(&sk->dst_cache, np->dst_cookie);
+
+ if (dst == NULL) {
+ struct flowi fl;
+
+ /* BUGGG_FUTURE: Again, it is not clear how
+ to handle rthdr case. Ignore this complexity
+ for now.
+ */
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = &np->saddr;
+ fl.oif = sk->bound_dev_if;
+ fl.uli_u.ports.dport = sk->dport;
+ fl.uli_u.ports.sport = sk->sport;
+
+ dst = ip6_route_output(sk, &fl);
+ } else
+ dst = dst_clone(dst);
+
+ if (dst->error) {
+ sk->err_soft = -dst->error;
+ } else if (tp->pmtu_cookie > dst->pmtu) {
+ tcp_sync_mss(sk, dst->pmtu);
+ tcp_simple_retransmit(sk);
+ } /* else let the usual retransmit timer handle it */
+ dst_release(dst);
+ return;
+ }
+
+ icmpv6_err_convert(type, code, &err);
+
+ /* Might be for an open_request */
+ switch (sk->state) {
+ struct open_request *req, *prev;
+ struct ipv6hdr hd;
+ case TCP_LISTEN:
+ if (atomic_read(&sk->sock_readers)) {
+ net_statistics.LockDroppedIcmps++;
+ /* If too many ICMPs get dropped on busy
+ * servers this needs to be solved differently.
+ */
+ return;
+ }
+
+ /* Grrrr - fix this later. */
+ ipv6_addr_copy(&hd.saddr, saddr);
+ ipv6_addr_copy(&hd.daddr, daddr);
+ req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev);
+ if (!req)
+ return;
+ if (seq != req->snt_isn) {
+ net_statistics.OutOfWindowIcmps++;
+ return;
+ }
+ if (req->sk) {
+ sk = req->sk; /* report error in accept */
+ } else {
+ tp->syn_backlog--;
+ tcp_synq_unlink(tp, req, prev);
+ req->class->destructor(req);
+ tcp_openreq_free(req);
+ }
+ /* FALL THROUGH */
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV: /* Cannot happen */
+ tcp_statistics.TcpAttemptFails++;
+ sk->err = err;
+ sk->zapped = 1;
+ mb();
+ sk->error_report(sk);
+ return;
+ }
+
+ if (np->recverr) {
+ /* This code isn't serialized with the socket code */
+ /* ANK (980927) ... which is harmless now,
+ sk->err's may be safely lost.
+ */
+ sk->err = err;
+ mb();
+ sk->error_report(sk);
+ } else {
+ sk->err_soft = err;
+ mb();
+ }
+}
+
+
+static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
+{
+ struct sk_buff * skb;
+ struct dst_entry *dst;
+ struct ipv6_txoptions *opt = NULL;
+ struct flowi fl;
+ int mss;
+
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr;
+ fl.nl_u.ip6_u.saddr = &req->af.v6_req.loc_addr;
+ fl.fl6_flowlabel = 0;
+ fl.oif = req->af.v6_req.iif;
+ fl.uli_u.ports.dport = req->rmt_port;
+ fl.uli_u.ports.sport = sk->sport;
+
+ opt = sk->net_pinfo.af_inet6.opt;
+ if (opt == NULL &&
+ sk->net_pinfo.af_inet6.rxopt.bits.srcrt == 2 &&
+ req->af.v6_req.pktopts) {
+ struct sk_buff *pktopts = req->af.v6_req.pktopts;
+ struct inet6_skb_parm *rxopt = (struct inet6_skb_parm *)pktopts->cb;
+ if (rxopt->srcrt)
+ opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt));
+ }
+
+ if (opt && opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+ fl.nl_u.ip6_u.daddr = rt0->addr;
+ }
+
+ dst = ip6_route_output(sk, &fl);
+ if (dst->error)
+ goto done;
+
+ mss = dst->pmtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr);
+
+ skb = tcp_make_synack(sk, dst, req, mss);
+ if (skb) {
+ struct tcphdr *th = skb->h.th;
+
+ th->check = tcp_v6_check(th, skb->len,
+ &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
+ csum_partial((char *)th, skb->len, skb->csum));
+
+ fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr;
+ ip6_xmit(sk, skb, &fl, opt);
+ }
+
+done:
+ dst_release(dst);
+ if (opt && opt != sk->net_pinfo.af_inet6.opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+}
+
+static void tcp_v6_or_free(struct open_request *req)
+{
+ if (req->af.v6_req.pktopts) {
+ kfree_skb(req->af.v6_req.pktopts);
+ req->af.v6_req.pktopts = NULL;
+ }
+}
+
+static struct or_calltable or_ipv6 = {
+ tcp_v6_send_synack,
+ tcp_v6_or_free,
+ tcp_v6_send_reset
+};
+
+static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
+{
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+
+ if (sk->net_pinfo.af_inet6.rxopt.all) {
+ if ((opt->hop && sk->net_pinfo.af_inet6.rxopt.bits.hopopts) ||
+ ((IPV6_FLOWINFO_MASK&*(u32*)skb->nh.raw) &&
+ sk->net_pinfo.af_inet6.rxopt.bits.rxflow) ||
+ (opt->srcrt && sk->net_pinfo.af_inet6.rxopt.bits.srcrt) ||
+ ((opt->dst1 || opt->dst0) && sk->net_pinfo.af_inet6.rxopt.bits.dstopts))
+ return 1;
+ }
+ return 0;
+}
+
+
+#define BACKLOG(sk) ((sk)->tp_pinfo.af_tcp.syn_backlog) /* lvalue! */
+#define BACKLOGMAX(sk) sysctl_max_syn_backlog
+
+/* FIXME: this is substantially similar to the ipv4 code.
+ * Can some kind of merge be done? -- erics
+ */
+static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, __u32 isn)
+{
+ struct tcp_opt tp;
+ struct open_request *req;
+
+ /* If the socket is dead, don't accept the connection. */
+ if (sk->dead) {
+ SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n", sk);
+ tcp_statistics.TcpAttemptFails++;
+ return -ENOTCONN;
+ }
+
+ if (skb->protocol == __constant_htons(ETH_P_IP))
+ return tcp_v4_conn_request(sk, skb, isn);
+
+ /* FIXME: do the same check for anycast */
+ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
+ goto drop;
+
+ if (isn == 0)
+ isn = tcp_v6_init_sequence(sk,skb);
+
+ /*
+ * There are no SYN attacks on IPv6, yet...
+ */
+ if (BACKLOG(sk) >= BACKLOGMAX(sk)) {
+ (void)(net_ratelimit() &&
+ printk(KERN_INFO "droping syn ack:%d max:%d\n",
+ BACKLOG(sk), BACKLOGMAX(sk)));
+ goto drop;
+ }
+
+ req = tcp_openreq_alloc();
+ if (req == NULL) {
+ goto drop;
+ }
+
+ BACKLOG(sk)++;
+
+ req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */
+
+ req->rcv_isn = TCP_SKB_CB(skb)->seq;
+ req->snt_isn = isn;
+ tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+ tp.mss_clamp = 65535;
+ tcp_parse_options(NULL, skb->h.th, &tp, 0);
+ if (tp.mss_clamp == 65535)
+ tp.mss_clamp = 576 - sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ if (sk->tp_pinfo.af_tcp.user_mss && sk->tp_pinfo.af_tcp.user_mss < tp.mss_clamp)
+ tp.mss_clamp = sk->tp_pinfo.af_tcp.user_mss;
+
+ req->mss = tp.mss_clamp;
+ if (tp.saw_tstamp)
+ req->ts_recent = tp.rcv_tsval;
+ req->tstamp_ok = tp.tstamp_ok;
+ req->sack_ok = tp.sack_ok;
+ req->snd_wscale = tp.snd_wscale;
+ req->wscale_ok = tp.wscale_ok;
+ req->rmt_port = skb->h.th->source;
+ ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr);
+ ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr);
+ req->af.v6_req.pktopts = NULL;
+ if (ipv6_opt_accepted(sk, skb)) {
+ atomic_inc(&skb->users);
+ req->af.v6_req.pktopts = skb;
+ }
+ req->af.v6_req.iif = sk->bound_dev_if;
+
+ /* So that link locals have meaning */
+ if (!sk->bound_dev_if && ipv6_addr_type(&req->af.v6_req.rmt_addr)&IPV6_ADDR_LINKLOCAL)
+ req->af.v6_req.iif = tcp_v6_iif(skb);
+
+ req->class = &or_ipv6;
+ req->retrans = 0;
+ req->sk = NULL;
+
+ tcp_v6_send_synack(sk, req);
+
+ req->expires = jiffies + TCP_TIMEOUT_INIT;
+ tcp_inc_slow_timer(TCP_SLT_SYNACK);
+ tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);
+
+ return 0;
+
+drop:
+ tcp_statistics.TcpAttemptFails++;
+ return 0; /* don't send reset */
+}
+
+static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len,
+ struct sk_buff *skb)
+{
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ th->check = 0;
+
+ th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
+ csum_partial((char *)th, th->doff<<2,
+ skb->csum));
+}
+
+static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+ struct open_request *req,
+ struct dst_entry *dst)
+{
+ struct ipv6_pinfo *np;
+ struct flowi fl;
+ struct tcp_opt *newtp;
+ struct sock *newsk;
+ struct ipv6_txoptions *opt;
+
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ /*
+ * v6 mapped
+ */
+
+ newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst);
+
+ if (newsk == NULL)
+ return NULL;
+
+ np = &newsk->net_pinfo.af_inet6;
+
+ ipv6_addr_set(&np->daddr, 0, 0, __constant_htonl(0x0000FFFF),
+ newsk->daddr);
+
+ ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF),
+ newsk->saddr);
+
+ ipv6_addr_copy(&np->rcv_saddr, &np->saddr);
+
+ newsk->tp_pinfo.af_tcp.af_specific = &ipv6_mapped;
+ newsk->backlog_rcv = tcp_v4_do_rcv;
+ newsk->net_pinfo.af_inet6.pktoptions = NULL;
+ newsk->net_pinfo.af_inet6.opt = NULL;
+
+ /* It is tricky place. Until this moment IPv4 tcp
+ worked with IPv6 af_tcp.af_specific.
+ Sync it now.
+ */
+ tcp_sync_mss(newsk, newsk->tp_pinfo.af_tcp.pmtu_cookie);
+
+ return newsk;
+ }
+
+ opt = sk->net_pinfo.af_inet6.opt;
+
+ if (sk->ack_backlog > sk->max_ack_backlog)
+ goto out;
+
+ if (sk->net_pinfo.af_inet6.rxopt.bits.srcrt == 2 &&
+ opt == NULL && req->af.v6_req.pktopts) {
+ struct inet6_skb_parm *rxopt = (struct inet6_skb_parm *)req->af.v6_req.pktopts->cb;
+ if (rxopt->srcrt)
+ opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(req->af.v6_req.pktopts->nh.raw+rxopt->srcrt));
+ }
+
+ if (dst == NULL) {
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr;
+ if (opt && opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+ fl.nl_u.ip6_u.daddr = rt0->addr;
+ }
+ fl.nl_u.ip6_u.saddr = &req->af.v6_req.loc_addr;
+ fl.fl6_flowlabel = 0;
+ fl.oif = sk->bound_dev_if;
+ fl.uli_u.ports.dport = req->rmt_port;
+ fl.uli_u.ports.sport = sk->sport;
+
+ dst = ip6_route_output(sk, &fl);
+ }
+
+ if (dst->error)
+ goto out;
+
+ sk->tp_pinfo.af_tcp.syn_backlog--;
+ sk->ack_backlog++;
+
+ newsk = tcp_create_openreq_child(sk, req, skb);
+ if (newsk == NULL)
+ goto out;
+
+ ip6_dst_store(newsk, dst, NULL);
+
+ newtp = &(newsk->tp_pinfo.af_tcp);
+
+ np = &newsk->net_pinfo.af_inet6;
+ ipv6_addr_copy(&np->daddr, &req->af.v6_req.rmt_addr);
+ ipv6_addr_copy(&np->saddr, &req->af.v6_req.loc_addr);
+ ipv6_addr_copy(&np->rcv_saddr, &req->af.v6_req.loc_addr);
+ newsk->bound_dev_if = req->af.v6_req.iif;
+
+ /* Now IPv6 options...
+
+ First: no IPv4 options.
+ */
+ newsk->opt = NULL;
+
+ /* Clone RX bits */
+ np->rxopt.all = sk->net_pinfo.af_inet6.rxopt.all;
+
+ /* Clone pktoptions received with SYN */
+ np->pktoptions = req->af.v6_req.pktopts;
+ if (np->pktoptions)
+ atomic_inc(&np->pktoptions->users);
+ np->opt = NULL;
+
+ /* Clone native IPv6 options from listening socket (if any)
+
+ Yes, keeping reference count would be much more clever,
+ but we make one more one thing there: reattach optmem
+ to newsk.
+ */
+ if (opt) {
+ np->opt = ipv6_dup_options(newsk, opt);
+ if (opt != sk->net_pinfo.af_inet6.opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+ }
+
+ newtp->ext_header_len = 0;
+ if (np->opt)
+ newtp->ext_header_len = np->opt->opt_nflen + np->opt->opt_flen;
+
+ tcp_sync_mss(newsk, dst->pmtu);
+ newtp->rcv_mss = newtp->mss_clamp;
+
+ newsk->daddr = LOOPBACK4_IPV6;
+ newsk->saddr = LOOPBACK4_IPV6;
+ newsk->rcv_saddr= LOOPBACK4_IPV6;
+
+ newsk->prot->hash(newsk);
+ tcp_inherit_port(sk, newsk);
+ add_to_prot_sklist(newsk);
+ sk->data_ready(sk, 0); /* Deliver SIGIO */
+
+ return newsk;
+
+out:
+ if (opt && opt != sk->net_pinfo.af_inet6.opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+ dst_release(dst);
+ return NULL;
+}
+
+static void tcp_v6_send_reset(struct sk_buff *skb)
+{
+ struct tcphdr *th = skb->h.th, *t1;
+ struct sk_buff *buff;
+ struct flowi fl;
+
+ if (th->rst)
+ return;
+
+ if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
+ return;
+
+ /*
+ * We need to grab some memory, and put together an RST,
+ * and then put it into the queue to be sent.
+ */
+
+ buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC);
+ if (buff == NULL)
+ return;
+
+ skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr));
+
+ t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
+
+ /* Swap the send and the receive. */
+ memset(t1, 0, sizeof(*t1));
+ t1->dest = th->source;
+ t1->source = th->dest;
+ t1->doff = sizeof(*t1)/4;
+ t1->rst = 1;
+
+ if(th->ack) {
+ t1->seq = th->ack_seq;
+ } else {
+ t1->ack = 1;
+ if(!th->syn)
+ t1->ack_seq = th->seq;
+ else
+ t1->ack_seq = htonl(ntohl(th->seq)+1);
+ }
+
+ buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
+
+ fl.nl_u.ip6_u.daddr = &skb->nh.ipv6h->saddr;
+ fl.nl_u.ip6_u.saddr = &skb->nh.ipv6h->daddr;
+ fl.fl6_flowlabel = 0;
+
+ t1->check = csum_ipv6_magic(fl.nl_u.ip6_u.saddr,
+ fl.nl_u.ip6_u.daddr,
+ sizeof(*t1), IPPROTO_TCP,
+ buff->csum);
+
+ fl.proto = IPPROTO_TCP;
+ fl.oif = tcp_v6_iif(skb);
+ fl.uli_u.ports.dport = t1->dest;
+ fl.uli_u.ports.sport = t1->source;
+
+ /* sk = NULL, but it is safe for now. RST socket required. */
+ buff->dst = ip6_route_output(NULL, &fl);
+
+ if (buff->dst->error == 0) {
+ ip6_xmit(NULL, buff, &fl, NULL);
+ tcp_statistics.TcpOutSegs++;
+ tcp_statistics.TcpOutRsts++;
+ return;
+ }
+
+ kfree_skb(buff);
+}
+
+static void tcp_v6_send_ack(struct sk_buff *skb, __u32 seq, __u32 ack, __u16 window)
+{
+ struct tcphdr *th = skb->h.th, *t1;
+ struct sk_buff *buff;
+ struct flowi fl;
+
+ buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC);
+ if (buff == NULL)
+ return;
+
+ skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr));
+
+ t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
+
+ /* Swap the send and the receive. */
+ memset(t1, 0, sizeof(*t1));
+ t1->dest = th->source;
+ t1->source = th->dest;
+ t1->doff = sizeof(*t1)/4;
+ t1->ack = 1;
+ t1->seq = seq;
+ t1->ack_seq = ack;
+
+ t1->window = htons(window);
+
+ buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
+
+ fl.nl_u.ip6_u.daddr = &skb->nh.ipv6h->saddr;
+ fl.nl_u.ip6_u.saddr = &skb->nh.ipv6h->daddr;
+ fl.fl6_flowlabel = 0;
+
+ t1->check = csum_ipv6_magic(fl.nl_u.ip6_u.saddr,
+ fl.nl_u.ip6_u.daddr,
+ sizeof(*t1), IPPROTO_TCP,
+ buff->csum);
+
+ fl.proto = IPPROTO_TCP;
+ fl.oif = tcp_v6_iif(skb);
+ fl.uli_u.ports.dport = t1->dest;
+ fl.uli_u.ports.sport = t1->source;
+
+ /* sk = NULL, but it is safe for now. static socket required. */
+ buff->dst = ip6_route_output(NULL, &fl);
+
+ if (buff->dst->error == 0) {
+ ip6_xmit(NULL, buff, &fl, NULL);
+ tcp_statistics.TcpOutSegs++;
+ return;
+ }
+
+ kfree_skb(buff);
+}
+
+static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
+ struct ipv6hdr *ip6h,
+ struct tcphdr *th,
+ int iif,
+ struct open_request **prevp)
+{
+ struct open_request *req, *prev;
+ __u16 rport = th->source;
+
+ /* assumption: the socket is not in use.
+ * as we checked the user count on tcp_rcv and we're
+ * running from a soft interrupt.
+ */
+ prev = (struct open_request *) (&tp->syn_wait_queue);
+ for (req = prev->dl_next; req; req = req->dl_next) {
+ if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) &&
+ !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) &&
+ req->rmt_port == rport &&
+ (!req->af.v6_req.iif || req->af.v6_req.iif == iif)) {
+ *prevp = prev;
+ return req;
+ }
+ prev = req;
+ }
+ return NULL;
+}
+
+static void tcp_v6_rst_req(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ struct open_request *req, *prev;
+
+ req = tcp_v6_search_req(tp,skb->nh.ipv6h,skb->h.th,tcp_v6_iif(skb),&prev);
+ if (!req)
+ return;
+ /* Sequence number check required by RFC793 */
+ if (before(TCP_SKB_CB(skb)->seq, req->rcv_isn) ||
+ after(TCP_SKB_CB(skb)->seq, req->rcv_isn+1))
+ return;
+ if(req->sk)
+ sk->ack_backlog--;
+ else
+ tp->syn_backlog--;
+ tcp_synq_unlink(tp, req, prev);
+ req->class->destructor(req);
+ tcp_openreq_free(req);
+ net_statistics.EmbryonicRsts++;
+}
+
+static inline struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcphdr *th = skb->h.th;
+ u32 flg = ((u32 *)th)[3];
+
+ /* Check for RST */
+ if (flg & __constant_htonl(0x00040000)) {
+ tcp_v6_rst_req(sk, skb);
+ return NULL;
+ }
+
+ /* Check SYN|ACK */
+ if (flg & __constant_htonl(0x00120000)) {
+ struct open_request *req, *dummy;
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &dummy);
+ if (req) {
+ sk = tcp_check_req(sk, skb, req);
+ }
+#if 0 /*def CONFIG_SYN_COOKIES */
+ else {
+ sk = cookie_v6_check(sk, skb);
+ }
+#endif
+ }
+ return sk;
+}
+
+static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
+{
+#ifdef CONFIG_FILTER
+ struct sk_filter *filter;
+#endif
+ int users = 0;
+
+ /* Imagine: socket is IPv6. IPv4 packet arrives,
+ goes to IPv4 receive handler and backlogged.
+ From backlog it always goes here. Kerboom...
+ Fortunately, tcp_rcv_established and rcv_established
+ handle them correctly, but it is not case with
+ tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK
+ */
+
+ if (skb->protocol == __constant_htons(ETH_P_IP))
+ return tcp_v4_do_rcv(sk, skb);
+
+#ifdef CONFIG_FILTER
+ filter = sk->filter;
+ if (filter && sk_filter(skb, filter))
+ goto discard;
+#endif /* CONFIG_FILTER */
+
+ /*
+ * socket locking is here for SMP purposes as backlog rcv
+ * is currently called with bh processing disabled.
+ */
+
+ ipv6_statistics.Ip6InDelivers++;
+
+ /*
+ * This doesn't check if the socket has enough room for the packet.
+ * Either process the packet _without_ queueing it and then free it,
+ * or do the check later.
+ */
+ skb_set_owner_r(skb, sk);
+
+ /* Do Stevens' IPV6_PKTOPTIONS.
+
+ Yes, guys, it is the only place in our code, where we
+ may make it not affecting IPv4.
+ The rest of code is protocol independent,
+ and I do not like idea to uglify IPv4.
+
+ Actually, all the idea behind IPV6_PKTOPTIONS
+ looks not very well thought. For now we latch
+ options, received in the last packet, enqueued
+ by tcp. Feel free to propose better solution.
+ --ANK (980728)
+ */
+ if (sk->net_pinfo.af_inet6.rxopt.all) {
+ users = atomic_read(&skb->users);
+ atomic_inc(&skb->users);
+ }
+
+ if (sk->state == TCP_ESTABLISHED) { /* Fast path */
+ if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
+ goto reset;
+ if (users)
+ goto ipv6_pktoptions;
+ return 0;
+ }
+
+ if (sk->state == TCP_LISTEN) {
+ struct sock *nsk;
+
+ nsk = tcp_v6_hnd_req(sk, skb);
+ if (!nsk)
+ goto discard;
+
+ /*
+ * Queue it on the new socket if the new socket is active,
+ * otherwise we just shortcircuit this and continue with
+ * the new socket..
+ */
+ if (atomic_read(&nsk->sock_readers)) {
+ skb_orphan(skb);
+ __skb_queue_tail(&nsk->back_log, skb);
+ return 0;
+ }
+ sk = nsk;
+ }
+
+ if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
+ goto reset;
+ if (users)
+ goto ipv6_pktoptions;
+ return 0;
+
+reset:
+ tcp_v6_send_reset(skb);
+discard:
+ if (users)
+ kfree_skb(skb);
+ kfree_skb(skb);
+ return 0;
+
+ipv6_pktoptions:
+ /* Do you ask, what is it?
+
+ 1. skb was enqueued by tcp.
+ 2. skb is added to tail of read queue, rather than out of order.
+ 3. socket is not in passive state.
+ 4. Finally, it really contains options, which user wants to receive.
+ */
+ if (atomic_read(&skb->users) > users &&
+ TCP_SKB_CB(skb)->end_seq == sk->tp_pinfo.af_tcp.rcv_nxt &&
+ !((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN))) {
+ if (ipv6_opt_accepted(sk, skb)) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ kfree_skb(skb);
+ skb = NULL;
+ if (skb2) {
+ skb_set_owner_r(skb2, sk);
+ skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, skb2);
+ }
+ } else {
+ kfree_skb(skb);
+ skb = xchg(&sk->net_pinfo.af_inet6.pktoptions, NULL);
+ }
+ }
+
+ if (skb)
+ kfree_skb(skb);
+ return 0;
+}
+
+int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
+{
+ struct tcphdr *th;
+ struct sock *sk;
+ struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+ struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+
+ th = skb->h.th;
+
+ if (skb->pkt_type != PACKET_HOST)
+ goto discard_it;
+
+ /*
+ * Pull up the IP header.
+ */
+
+ __skb_pull(skb, skb->h.raw - skb->data);
+
+ /*
+ * Count it even if it's bad.
+ */
+
+ tcp_statistics.TcpInSegs++;
+
+ len = skb->len;
+ if (len < sizeof(struct tcphdr))
+ goto bad_packet;
+
+ /*
+ * Try to use the device checksum if provided.
+ */
+
+ switch (skb->ip_summed) {
+ case CHECKSUM_NONE:
+ skb->csum = csum_partial((char *)th, len, 0);
+ case CHECKSUM_HW:
+ if (tcp_v6_check(th,len,saddr,daddr,skb->csum)) {
+ printk(KERN_DEBUG "tcp csum failed\n");
+ bad_packet:
+ tcp_statistics.TcpInErrs++;
+ goto discard_it;
+ }
+ default:
+ /* CHECKSUM_UNNECESSARY */
+ break;
+ };
+
+ if((th->doff * 4) < sizeof(struct tcphdr) ||
+ len < (th->doff * 4))
+ goto bad_packet;
+
+ sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
+
+ if (!sk)
+ goto no_tcp_socket;
+
+ TCP_SKB_CB(skb)->seq = ntohl(th->seq);
+ TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
+ len - th->doff*4);
+ TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
+ skb->used = 0;
+ if(sk->state == TCP_TIME_WAIT)
+ goto do_time_wait;
+
+ if (!atomic_read(&sk->sock_readers))
+ return tcp_v6_do_rcv(sk, skb);
+
+ __skb_queue_tail(&sk->back_log, skb);
+ return(0);
+
+no_tcp_socket:
+ tcp_v6_send_reset(skb);
+
+discard_it:
+
+ /*
+ * Discard frame
+ */
+
+ kfree_skb(skb);
+ return 0;
+
+do_time_wait:
+ switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
+ skb, th, skb->len)) {
+ case TCP_TW_ACK:
+ tcp_v6_send_ack(skb,
+ ((struct tcp_tw_bucket *)sk)->snd_nxt,
+ ((struct tcp_tw_bucket *)sk)->rcv_nxt,
+ ((struct tcp_tw_bucket *)sk)->window);
+ goto discard_it;
+ case TCP_TW_RST:
+ goto no_tcp_socket;
+ default:
+ goto discard_it;
+ }
+}
+
+static int tcp_v6_rebuild_header(struct sock *sk)
+{
+ struct dst_entry *dst = NULL;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+
+ if (sk->dst_cache)
+ dst = dst_check(&sk->dst_cache, np->dst_cookie);
+
+ if (dst == NULL) {
+ struct flowi fl;
+
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = &np->saddr;
+ fl.fl6_flowlabel = np->flow_label;
+ fl.oif = sk->bound_dev_if;
+ fl.uli_u.ports.dport = sk->dport;
+ fl.uli_u.ports.sport = sk->sport;
+
+ if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+ fl.nl_u.ip6_u.daddr = rt0->addr;
+ }
+
+
+ dst = ip6_route_output(sk, &fl);
+
+ if (dst->error) {
+ dst_release(dst);
+ return dst->error;
+ }
+
+ ip6_dst_store(sk, dst, NULL);
+ }
+
+ return dst->error;
+}
+
+static struct sock * tcp_v6_get_sock(struct sk_buff *skb, struct tcphdr *th)
+{
+ struct in6_addr *saddr;
+ struct in6_addr *daddr;
+
+ if (skb->protocol == __constant_htons(ETH_P_IP))
+ return ipv4_specific.get_sock(skb, th);
+
+ saddr = &skb->nh.ipv6h->saddr;
+ daddr = &skb->nh.ipv6h->daddr;
+ return tcp_v6_lookup(saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
+}
+
+static void tcp_v6_xmit(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+ struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;
+ struct flowi fl;
+ struct dst_entry *dst = sk->dst_cache;
+
+ fl.proto = IPPROTO_TCP;
+ fl.fl6_dst = &np->daddr;
+ fl.fl6_src = &np->saddr;
+ fl.fl6_flowlabel = np->flow_label;
+ fl.oif = sk->bound_dev_if;
+ fl.uli_u.ports.sport = sk->sport;
+ fl.uli_u.ports.dport = sk->dport;
+
+ if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+ fl.nl_u.ip6_u.daddr = rt0->addr;
+ }
+
+ if (sk->dst_cache)
+ dst = dst_check(&sk->dst_cache, np->dst_cookie);
+
+ if (dst == NULL) {
+ dst = ip6_route_output(sk, &fl);
+
+ if (dst->error) {
+ sk->err_soft = -dst->error;
+ dst_release(dst);
+ return;
+ }
+
+ ip6_dst_store(sk, dst, NULL);
+ }
+
+ skb->dst = dst_clone(dst);
+
+ /* Restore final destination back after routing done */
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+
+ ip6_xmit(sk, skb, &fl, np->opt);
+}
+
+static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
+{
+ struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
+
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, &np->daddr, sizeof(struct in6_addr));
+ sin6->sin6_port = sk->dport;
+ /* We do not store received flowlabel for TCP */
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ if (sk->bound_dev_if &&
+ ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin6->sin6_scope_id = sk->bound_dev_if;
+}
+
+static struct tcp_func ipv6_specific = {
+ tcp_v6_xmit,
+ tcp_v6_send_check,
+ tcp_v6_rebuild_header,
+ tcp_v6_conn_request,
+ tcp_v6_syn_recv_sock,
+ tcp_v6_get_sock,
+ sizeof(struct ipv6hdr),
+
+ ipv6_setsockopt,
+ ipv6_getsockopt,
+ v6_addr2sockaddr,
+ sizeof(struct sockaddr_in6)
+};
+
+/*
+ * TCP over IPv4 via INET6 API
+ */
+
+static struct tcp_func ipv6_mapped = {
+ ip_queue_xmit,
+ tcp_v4_send_check,
+ tcp_v4_rebuild_header,
+ tcp_v6_conn_request,
+ tcp_v6_syn_recv_sock,
+ tcp_v6_get_sock,
+ sizeof(struct iphdr),
+
+ ipv6_setsockopt,
+ ipv6_getsockopt,
+ v6_addr2sockaddr,
+ sizeof(struct sockaddr_in6)
+};
+
+/* NOTE: A lot of things set to zero explicitly by call to
+ * sk_alloc() so need not be done here.
+ */
+static int tcp_v6_init_sock(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+
+ skb_queue_head_init(&tp->out_of_order_queue);
+ tcp_init_xmit_timers(sk);
+
+ tp->rto = TCP_TIMEOUT_INIT; /*TCP_WRITE_TIME*/
+ tp->mdev = TCP_TIMEOUT_INIT;
+ tp->mss_clamp = ~0;
+
+ /* So many TCP implementations out there (incorrectly) count the
+ * initial SYN frame in their delayed-ACK and congestion control
+ * algorithms that we must have the following bandaid to talk
+ * efficiently to them. -DaveM
+ */
+ tp->snd_cwnd = 2;
+
+ /* See draft-stevens-tcpca-spec-01 for discussion of the
+ * initialization of these values.
+ */
+ tp->snd_cwnd_cnt = 0;
+ tp->snd_ssthresh = 0x7fffffff;
+
+ sk->state = TCP_CLOSE;
+ sk->max_ack_backlog = SOMAXCONN;
+ tp->rcv_mss = 536;
+
+ /* Init SYN queue. */
+ tcp_synq_init(tp);
+
+ sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
+
+ sk->write_space = tcp_write_space;
+
+ return 0;
+}
+
+static int tcp_v6_destroy_sock(struct sock *sk)
+{
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ struct sk_buff *skb;
+
+ tcp_clear_xmit_timers(sk);
+
+ if (sk->keepopen)
+ tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
+
+ /*
+ * Cleanup up the write buffer.
+ */
+
+ while((skb = __skb_dequeue(&sk->write_queue)) != NULL)
+ kfree_skb(skb);
+
+ /*
+ * Cleans up our, hopefuly empty, out_of_order_queue
+ */
+
+ while((skb = __skb_dequeue(&tp->out_of_order_queue)) != NULL)
+ kfree_skb(skb);
+
+ /* Clean up a locked TCP bind bucket, this only happens if a
+ * port is allocated for a socket, but it never fully connects.
+ */
+ if(sk->prev != NULL)
+ tcp_put_port(sk);
+
+ return inet6_destroy_sock(sk);
+}
+
+struct proto tcpv6_prot = {
+ (struct sock *)&tcpv6_prot, /* sklist_next */
+ (struct sock *)&tcpv6_prot, /* sklist_prev */
+ tcp_close, /* close */
+ tcp_v6_connect, /* connect */
+ tcp_accept, /* accept */
+ NULL, /* retransmit */
+ tcp_write_wakeup, /* write_wakeup */
+ tcp_read_wakeup, /* read_wakeup */
+ tcp_poll, /* poll */
+ tcp_ioctl, /* ioctl */
+ tcp_v6_init_sock, /* init */
+ tcp_v6_destroy_sock, /* destroy */
+ tcp_shutdown, /* shutdown */
+ tcp_setsockopt, /* setsockopt */
+ tcp_getsockopt, /* getsockopt */
+ tcp_v6_sendmsg, /* sendmsg */
+ tcp_recvmsg, /* recvmsg */
+ NULL, /* bind */
+ tcp_v6_do_rcv, /* backlog_rcv */
+ tcp_v6_hash, /* hash */
+ tcp_v6_unhash, /* unhash */
+ tcp_v6_get_port, /* get_port */
+ 128, /* max_header */
+ 0, /* retransmits */
+ "TCPv6", /* name */
+ 0, /* inuse */
+ 0 /* highestinuse */
+};
+
+static struct inet6_protocol tcpv6_protocol =
+{
+ tcp_v6_rcv, /* TCP handler */
+ tcp_v6_err, /* TCP error control */
+ NULL, /* next */
+ IPPROTO_TCP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "TCPv6" /* name */
+};
+
+__initfunc(void tcpv6_init(void))
+{
+ /* register inet6 protocol */
+ inet6_add_protocol(&tcpv6_protocol);
+}
diff --git a/pfinet/linux-src/net/ipv6/udp_ipv6.c b/pfinet/linux-src/net/ipv6/udp_ipv6.c
new file mode 100644
index 00000000..f6968ae4
--- /dev/null
+++ b/pfinet/linux-src/net/ipv6/udp_ipv6.c
@@ -0,0 +1,967 @@
+/*
+ * UDP over IPv6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Based on linux/ipv4/udp.c
+ *
+ * $Id: udp_ipv6.c,v 1.3 2007/10/13 01:43:00 stesie Exp $
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/ip.h>
+#include <net/udp.h>
+
+#include <net/checksum.h>
+
+struct udp_mib udp_stats_in6;
+
+/* Grrr, addr_type already calculated by caller, but I don't want
+ * to add some silly "cookie" argument to this method just for that.
+ */
+static int udp_v6_get_port(struct sock *sk, unsigned short snum)
+{
+ SOCKHASH_LOCK();
+ if (snum == 0) {
+ int best_size_so_far, best, result, i;
+
+ if (udp_port_rover > sysctl_local_port_range[1] ||
+ udp_port_rover < sysctl_local_port_range[0])
+ udp_port_rover = sysctl_local_port_range[0];
+ best_size_so_far = 32767;
+ best = result = udp_port_rover;
+ for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
+ struct sock *sk;
+ int size;
+
+ sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
+ if (!sk) {
+ if (result > sysctl_local_port_range[1])
+ result = sysctl_local_port_range[0] +
+ ((result - sysctl_local_port_range[0]) &
+ (UDP_HTABLE_SIZE - 1));
+ goto gotit;
+ }
+ size = 0;
+ do {
+ if (++size >= best_size_so_far)
+ goto next;
+ } while ((sk = sk->next) != NULL);
+ best_size_so_far = size;
+ best = result;
+
+ next:
+ (void) 0;
+ }
+ result = best;
+ for(;; result += UDP_HTABLE_SIZE) {
+ if (result > sysctl_local_port_range[1])
+ result = sysctl_local_port_range[0]
+ + ((result - sysctl_local_port_range[0]) &
+ (UDP_HTABLE_SIZE - 1));
+ if (!udp_lport_inuse(result))
+ break;
+ }
+gotit:
+ udp_port_rover = snum = result;
+ } else {
+ struct sock *sk2;
+ int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
+
+ for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
+ sk2 != NULL;
+ sk2 = sk2->next) {
+ if (sk2->num == snum &&
+ sk2 != sk &&
+ sk2->bound_dev_if == sk->bound_dev_if &&
+ (!sk2->rcv_saddr ||
+ addr_type == IPV6_ADDR_ANY ||
+ !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+ &sk2->net_pinfo.af_inet6.rcv_saddr)) &&
+ (!sk2->reuse || !sk->reuse))
+ goto fail;
+ }
+ }
+
+ sk->num = snum;
+ SOCKHASH_UNLOCK();
+ return 0;
+
+fail:
+ SOCKHASH_UNLOCK();
+ return 1;
+}
+
+static void udp_v6_hash(struct sock *sk)
+{
+ struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)];
+
+ SOCKHASH_LOCK();
+ if ((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+ SOCKHASH_UNLOCK();
+}
+
+static void udp_v6_unhash(struct sock *sk)
+{
+ SOCKHASH_LOCK();
+ if (sk->pprev) {
+ if (sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ }
+ SOCKHASH_UNLOCK();
+}
+
+static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
+ struct in6_addr *daddr, u16 dport, int dif)
+{
+ struct sock *sk, *result = NULL;
+ unsigned short hnum = ntohs(dport);
+ int badness = -1;
+
+ for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
+ if((sk->num == hnum) &&
+ (sk->family == PF_INET6) &&
+ !(sk->dead && (sk->state == TCP_CLOSE))) {
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ int score = 0;
+ if(sk->dport) {
+ if(sk->dport != sport)
+ continue;
+ score++;
+ }
+ if(!ipv6_addr_any(&np->rcv_saddr)) {
+ if(ipv6_addr_cmp(&np->rcv_saddr, daddr))
+ continue;
+ score++;
+ }
+ if(!ipv6_addr_any(&np->daddr)) {
+ if(ipv6_addr_cmp(&np->daddr, saddr))
+ continue;
+ score++;
+ }
+ if(sk->bound_dev_if) {
+ if(sk->bound_dev_if != dif)
+ continue;
+ score++;
+ }
+ if(score == 4) {
+ result = sk;
+ break;
+ } else if(score > badness) {
+ result = sk;
+ badness = score;
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ *
+ */
+
+int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct in6_addr *daddr;
+ struct in6_addr saddr;
+ struct dst_entry *dst;
+ struct flowi fl;
+ struct ip6_flowlabel *flowlabel = NULL;
+ int addr_type;
+ int err;
+
+ if (usin->sin6_family == AF_INET) {
+ err = udp_connect(sk, uaddr, addr_len);
+ goto ipv4_connected;
+ }
+
+ if (usin->sin6_family == AF_UNSPEC) {
+ udp_connect(sk, uaddr, addr_len);
+ ipv6_addr_set(&np->daddr, 0, 0, 0, 0);
+ ipv6_addr_set(&np->saddr, 0, 0, 0, 0);
+ ipv6_addr_set(&np->rcv_saddr, 0, 0, 0, 0);
+ return 0;
+ }
+
+ if (addr_len < sizeof(*usin))
+ return(-EINVAL);
+
+ if (usin->sin6_family && usin->sin6_family != AF_INET6)
+ return(-EAFNOSUPPORT);
+
+ fl.fl6_flowlabel = 0;
+ if (np->sndflow) {
+ fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
+ }
+ }
+
+ addr_type = ipv6_addr_type(&usin->sin6_addr);
+
+ if (addr_type == IPV6_ADDR_ANY) {
+ /*
+ * connect to self
+ */
+ usin->sin6_addr.s6_addr[15] = 0x01;
+ }
+
+ daddr = &usin->sin6_addr;
+
+ if (addr_type == IPV6_ADDR_MAPPED) {
+ struct sockaddr_in sin;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = daddr->s6_addr32[3];
+ sin.sin_port = usin->sin6_port;
+
+ err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
+
+ipv4_connected:
+ if (err < 0)
+ return err;
+
+ ipv6_addr_set(&np->daddr, 0, 0,
+ __constant_htonl(0x0000ffff),
+ sk->daddr);
+
+ if(ipv6_addr_any(&np->saddr)) {
+ ipv6_addr_set(&np->saddr, 0, 0,
+ __constant_htonl(0x0000ffff),
+ sk->saddr);
+
+ }
+
+ if(ipv6_addr_any(&np->rcv_saddr)) {
+ ipv6_addr_set(&np->rcv_saddr, 0, 0,
+ __constant_htonl(0x0000ffff),
+ sk->rcv_saddr);
+ }
+ return 0;
+ }
+
+ if (addr_type&IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ usin->sin6_scope_id) {
+ if (sk->bound_dev_if &&
+ sk->bound_dev_if != usin->sin6_scope_id)
+ return(-EINVAL);
+
+ sk->bound_dev_if = usin->sin6_scope_id;
+ if (!sk->bound_dev_if &&
+ (addr_type & IPV6_ADDR_MULTICAST))
+ fl.oif = np->mcast_oif;
+ }
+
+ /* Connect to link-local address requires an interface */
+ if (!sk->bound_dev_if)
+ return(-EINVAL);
+ }
+
+ ipv6_addr_copy(&np->daddr, daddr);
+ np->flow_label = fl.fl6_flowlabel;
+
+ sk->dport = usin->sin6_port;
+
+ /*
+ * Check for a route to destination an obtain the
+ * destination cache for it.
+ */
+
+ fl.proto = IPPROTO_UDP;
+ fl.fl6_dst = &np->daddr;
+ fl.fl6_src = &saddr;
+ fl.oif = sk->bound_dev_if;
+ fl.uli_u.ports.dport = sk->dport;
+ fl.uli_u.ports.sport = sk->sport;
+
+ if (flowlabel) {
+ if (flowlabel->opt && flowlabel->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
+ fl.fl6_dst = rt0->addr;
+ }
+ } else if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+ fl.fl6_dst = rt0->addr;
+ }
+
+ dst = ip6_route_output(sk, &fl);
+
+ if ((err = dst->error) != 0) {
+ dst_release(dst);
+ fl6_sock_release(flowlabel);
+ return err;
+ }
+
+ ip6_dst_store(sk, dst, fl.fl6_dst);
+
+ /* get the source adddress used in the appropriate device */
+
+ err = ipv6_get_saddr(dst, daddr, &saddr);
+
+ if (err == 0) {
+ if(ipv6_addr_any(&np->saddr))
+ ipv6_addr_copy(&np->saddr, &saddr);
+
+ if(ipv6_addr_any(&np->rcv_saddr)) {
+ ipv6_addr_copy(&np->rcv_saddr, &saddr);
+ sk->rcv_saddr = 0xffffffff;
+ }
+ sk->state = TCP_ESTABLISHED;
+ }
+ fl6_sock_release(flowlabel);
+
+ return err;
+}
+
+static void udpv6_close(struct sock *sk, long timeout)
+{
+ /* See for explanation: raw_close in ipv4/raw.c */
+ sk->state = TCP_CLOSE;
+ udp_v6_unhash(sk);
+ sk->dead = 1;
+ destroy_sock(sk);
+}
+
+#ifndef HAVE_CSUM_COPY_USER
+#undef CONFIG_UDP_DELAY_CSUM
+#endif
+
+/*
+ * This should be easy, if there is something there we
+ * return it, otherwise we block.
+ */
+
+int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
+ int noblock, int flags, int *addr_len)
+{
+ struct sk_buff *skb;
+ int copied, err;
+
+ if (addr_len)
+ *addr_len=sizeof(struct sockaddr_in6);
+
+ if (flags & MSG_ERRQUEUE)
+ return ipv6_recv_error(sk, msg, len);
+
+ skb = skb_recv_datagram(sk, flags, noblock, &err);
+ if (!skb)
+ goto out;
+
+ copied = skb->len - sizeof(struct udphdr);
+ if (copied > len) {
+ copied = len;
+ msg->msg_flags |= MSG_TRUNC;
+ }
+
+#ifndef CONFIG_UDP_DELAY_CSUM
+ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
+ msg->msg_iov, copied);
+#else
+ if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
+ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
+ copied);
+ } else if (copied > msg->msg_iov[0].iov_len || (msg->msg_flags&MSG_TRUNC)) {
+ if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
+ /* Error for blocking case is chosen to masquerade
+ as some normal condition.
+ */
+ err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+ udp_stats_in6.UdpInErrors++;
+ goto out_free;
+ }
+ err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
+ copied);
+ } else {
+ unsigned int csum = csum_partial(skb->h.raw, sizeof(struct udphdr), skb->csum);
+
+ err = 0;
+ csum = csum_and_copy_to_user((char*)&skb->h.uh[1], msg->msg_iov[0].iov_base, copied, csum, &err);
+ if (err)
+ goto out_free;
+ if ((unsigned short)csum_fold(csum)) {
+ /* Error for blocking case is chosen to masquerade
+ as some normal condition.
+ */
+ err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+ udp_stats_in6.UdpInErrors++;
+ goto out_free;
+ }
+ }
+#endif
+ if (err)
+ goto out_free;
+
+ sk->stamp=skb->stamp;
+
+ /* Copy the address. */
+ if (msg->msg_name) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *) msg->msg_name;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = skb->h.uh->source;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ ipv6_addr_set(&sin6->sin6_addr, 0, 0,
+ __constant_htonl(0xffff), skb->nh.iph->saddr);
+ if (sk->ip_cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+ } else {
+ memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
+ sizeof(struct in6_addr));
+ if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin6->sin6_scope_id =
+ ((struct inet6_skb_parm *) skb->cb)->iif;
+
+ if (sk->net_pinfo.af_inet6.rxopt.all)
+ datagram_recv_ctl(sk, msg, skb);
+ }
+ }
+ err = copied;
+
+out_free:
+ skb_free_datagram(sk, skb);
+out:
+ return err;
+}
+
+void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
+ struct inet6_skb_parm *opt,
+ int type, int code, unsigned char *buff, __u32 info)
+{
+ struct device *dev = skb->dev;
+ struct in6_addr *saddr = &hdr->saddr;
+ struct in6_addr *daddr = &hdr->daddr;
+ struct sock *sk;
+ struct udphdr *uh;
+ int err;
+
+ if (buff + sizeof(struct udphdr) > skb->tail)
+ return;
+
+ uh = (struct udphdr *) buff;
+
+ sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex);
+
+ if (sk == NULL)
+ return;
+
+ if (!icmpv6_err_convert(type, code, &err) &&
+ !sk->net_pinfo.af_inet6.recverr)
+ return;
+
+ if (sk->bsdism && sk->state!=TCP_ESTABLISHED)
+ return;
+
+ if (sk->net_pinfo.af_inet6.recverr)
+ ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
+
+ sk->err = err;
+ sk->error_report(sk);
+}
+
+static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+{
+#if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM)
+ if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
+ if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
+ udp_stats_in6.UdpInErrors++;
+ ipv6_statistics.Ip6InDiscards++;
+ kfree_skb(skb);
+ return 0;
+ }
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+#endif
+ if (sock_queue_rcv_skb(sk,skb)<0) {
+ udp_stats_in6.UdpInErrors++;
+ ipv6_statistics.Ip6InDiscards++;
+ kfree_skb(skb);
+ return 0;
+ }
+ ipv6_statistics.Ip6InDelivers++;
+ udp_stats_in6.UdpInDatagrams++;
+ return 0;
+}
+
+static __inline__ int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
+{
+ struct ipv6_mc_socklist *mc;
+
+ for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
+ if (ipv6_addr_cmp(&mc->addr, addr) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct sock *udp_v6_mcast_next(struct sock *sk,
+ u16 loc_port, struct in6_addr *loc_addr,
+ u16 rmt_port, struct in6_addr *rmt_addr,
+ int dif)
+{
+ struct sock *s = sk;
+ unsigned short num = ntohs(loc_port);
+ for(; s; s = s->next) {
+ if((s->num == num) &&
+ !(s->dead && (s->state == TCP_CLOSE))) {
+ struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;
+ if(s->dport) {
+ if(s->dport != rmt_port)
+ continue;
+ }
+ if(!ipv6_addr_any(&np->daddr) &&
+ ipv6_addr_cmp(&np->daddr, rmt_addr))
+ continue;
+
+ if (s->bound_dev_if && s->bound_dev_if != dif)
+ continue;
+
+ if(!ipv6_addr_any(&np->rcv_saddr)) {
+ if(ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)
+ return s;
+ }
+ if(!inet6_mc_check(s, loc_addr))
+ continue;
+ return s;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Note: called only from the BH handler context,
+ * so we don't need to lock the hashes.
+ */
+static void udpv6_mcast_deliver(struct udphdr *uh,
+ struct in6_addr *saddr, struct in6_addr *daddr,
+ struct sk_buff *skb)
+{
+ struct sock *sk, *sk2;
+ struct sk_buff *buff;
+ int dif;
+
+ sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
+ dif = skb->dev->ifindex;
+ sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
+ if (!sk)
+ goto free_skb;
+
+ buff = NULL;
+ sk2 = sk;
+ while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr,
+ uh->source, daddr, dif))) {
+ if (!buff) {
+ buff = skb_clone(skb, GFP_ATOMIC);
+ if (!buff)
+ continue;
+ }
+ if (sock_queue_rcv_skb(sk2, buff) >= 0)
+ buff = NULL;
+ }
+ if (buff)
+ kfree_skb(buff);
+ if (sock_queue_rcv_skb(sk, skb) < 0) {
+free_skb:
+ kfree_skb(skb);
+ }
+}
+
+int udpv6_rcv(struct sk_buff *skb, unsigned long len)
+{
+ struct sock *sk;
+ struct udphdr *uh;
+ struct device *dev = skb->dev;
+ struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+ struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+ u32 ulen;
+
+ uh = skb->h.uh;
+ __skb_pull(skb, skb->h.raw - skb->data);
+
+ ulen = ntohs(uh->len);
+
+ /* Check for jumbo payload */
+ if (ulen == 0 && skb->nh.ipv6h->payload_len == 0)
+ ulen = len;
+
+ if (ulen > len || len < sizeof(*uh)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len);
+ udp_stats_in6.UdpInErrors++;
+ kfree_skb(skb);
+ return(0);
+ }
+
+ if (uh->check == 0) {
+ /* IPv6 draft-v2 section 8.1 says that we SHOULD log
+ this error. Well, it is reasonable.
+ */
+ if (net_ratelimit())
+ printk(KERN_INFO "IPv6: udp checksum is 0\n");
+ goto discard;
+ }
+
+ skb_trim(skb, ulen);
+
+#ifndef CONFIG_UDP_DELAY_CSUM
+ switch (skb->ip_summed) {
+ case CHECKSUM_NONE:
+ skb->csum = csum_partial((char*)uh, ulen, 0);
+ case CHECKSUM_HW:
+ if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) {
+ printk(KERN_DEBUG "IPv6: udp checksum error\n");
+ goto discard;
+ }
+ };
+#else
+ if (skb->ip_summed==CHECKSUM_HW) {
+ if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum))
+ goto discard;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+ skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0);
+#endif
+
+ len = ulen;
+
+ /*
+ * Multicast receive code
+ */
+ if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {
+ udpv6_mcast_deliver(uh, saddr, daddr, skb);
+ return 0;
+ }
+
+ /* Unicast */
+
+ /*
+ * check socket cache ... must talk to Alan about his plans
+ * for sock caches... i'll skip this for now.
+ */
+
+ sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex);
+
+ if (sk == NULL) {
+#ifdef CONFIG_UDP_DELAY_CSUM
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
+ (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum)))
+ goto discard;
+#endif
+ udp_stats_in6.UdpNoPorts++;
+
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
+
+ kfree_skb(skb);
+ return(0);
+ }
+
+ /* deliver */
+
+ udpv6_queue_rcv_skb(sk, skb);
+
+ return(0);
+
+discard:
+ udp_stats_in6.UdpInErrors++;
+ kfree_skb(skb);
+ return(0);
+}
+
+/*
+ * Sending
+ */
+
+struct udpv6fakehdr
+{
+ struct udphdr uh;
+ struct iovec *iov;
+ __u32 wcheck;
+ __u32 pl_len;
+ struct in6_addr *daddr;
+};
+
+/*
+ * with checksum
+ */
+
+static int udpv6_getfrag(const void *data, struct in6_addr *addr,
+ char *buff, unsigned int offset, unsigned int len)
+{
+ struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data;
+ char *dst;
+ int final = 0;
+ int clen = len;
+
+ dst = buff;
+
+ if (offset) {
+ offset -= sizeof(struct udphdr);
+ } else {
+ dst += sizeof(struct udphdr);
+ final = 1;
+ clen -= sizeof(struct udphdr);
+ }
+
+ if (csum_partial_copy_fromiovecend(dst, udh->iov, offset,
+ clen, &udh->wcheck))
+ return -EFAULT;
+
+ if (final) {
+ struct in6_addr *daddr;
+
+ udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr),
+ udh->wcheck);
+
+ if (udh->daddr) {
+ daddr = udh->daddr;
+ } else {
+ /*
+ * use packet destination address
+ * this should improve cache locality
+ */
+ daddr = addr + 1;
+ }
+ udh->uh.check = csum_ipv6_magic(addr, daddr,
+ udh->pl_len, IPPROTO_UDP,
+ udh->wcheck);
+ if (udh->uh.check == 0)
+ udh->uh.check = -1;
+
+ memcpy(buff, udh, sizeof(struct udphdr));
+ }
+ return 0;
+}
+
+static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
+{
+ struct ipv6_txoptions opt_space;
+ struct udpv6fakehdr udh;
+ struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
+ struct ipv6_txoptions *opt = NULL;
+ struct ip6_flowlabel *flowlabel = NULL;
+ struct flowi fl;
+ int addr_len = msg->msg_namelen;
+ struct in6_addr *daddr;
+ int len = ulen + sizeof(struct udphdr);
+ int addr_type;
+ int hlimit = -1;
+
+ int err;
+
+ /* Rough check on arithmetic overflow,
+ better check is made in ip6_build_xmit
+ */
+ if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr))
+ return -EMSGSIZE;
+
+ if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
+ return(-EINVAL);
+
+ fl.fl6_flowlabel = 0;
+
+ if (sin6) {
+ if (sin6->sin6_family == AF_INET)
+ return udp_sendmsg(sk, msg, ulen);
+
+ if (addr_len < sizeof(*sin6))
+ return(-EINVAL);
+
+ if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
+ return(-EINVAL);
+
+ if (sin6->sin6_port == 0)
+ return(-EINVAL);
+
+ udh.uh.dest = sin6->sin6_port;
+ daddr = &sin6->sin6_addr;
+
+ if (np->sndflow) {
+ fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ daddr = &flowlabel->dst;
+ }
+ }
+
+ /* Otherwise it will be difficult to maintain sk->dst_cache. */
+ if (sk->state == TCP_ESTABLISHED &&
+ !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
+ daddr = &sk->net_pinfo.af_inet6.daddr;
+
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ sin6->sin6_scope_id &&
+ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+ fl.oif = sin6->sin6_scope_id;
+ } else {
+ if (sk->state != TCP_ESTABLISHED)
+ return(-ENOTCONN);
+
+ udh.uh.dest = sk->dport;
+ daddr = &sk->net_pinfo.af_inet6.daddr;
+ fl.fl6_flowlabel = np->flow_label;
+ }
+
+ addr_type = ipv6_addr_type(daddr);
+
+ if (addr_type == IPV6_ADDR_MAPPED) {
+ struct sockaddr_in sin;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = daddr->s6_addr32[3];
+ sin.sin_port = udh.uh.dest;
+ msg->msg_name = (struct sockaddr *)(&sin);
+ msg->msg_namelen = sizeof(sin);
+ fl6_sock_release(flowlabel);
+
+ return udp_sendmsg(sk, msg, ulen);
+ }
+
+ udh.daddr = NULL;
+ fl.oif = sk->bound_dev_if;
+ fl.fl6_src = NULL;
+
+ if (msg->msg_controllen) {
+ opt = &opt_space;
+ memset(opt, 0, sizeof(struct ipv6_txoptions));
+
+ err = datagram_send_ctl(msg, &fl, opt, &hlimit);
+ if (err < 0) {
+ fl6_sock_release(flowlabel);
+ return err;
+ }
+ if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ }
+ if (!(opt->opt_nflen|opt->opt_flen))
+ opt = NULL;
+ }
+ if (opt == NULL)
+ opt = np->opt;
+ if (flowlabel)
+ opt = fl6_merge_options(&opt_space, flowlabel, opt);
+ if (opt && opt->srcrt)
+ udh.daddr = daddr;
+
+ udh.uh.source = sk->sport;
+ udh.uh.len = len < 0x10000 ? htons(len) : 0;
+ udh.uh.check = 0;
+ udh.iov = msg->msg_iov;
+ udh.wcheck = 0;
+ udh.pl_len = len;
+
+ fl.proto = IPPROTO_UDP;
+ fl.fl6_dst = daddr;
+ fl.uli_u.ports.dport = udh.uh.dest;
+ fl.uli_u.ports.sport = udh.uh.source;
+
+ err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
+ msg->msg_flags);
+
+ fl6_sock_release(flowlabel);
+
+ if (err < 0)
+ return err;
+
+ udp_stats_in6.UdpOutDatagrams++;
+ return ulen;
+}
+
+static struct inet6_protocol udpv6_protocol =
+{
+ udpv6_rcv, /* UDP handler */
+ udpv6_err, /* UDP error control */
+ NULL, /* next */
+ IPPROTO_UDP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "UDPv6" /* name */
+};
+
+#ifdef _HURD_
+#define udp_ioctl 0
+#endif
+
+struct proto udpv6_prot = {
+ (struct sock *)&udpv6_prot, /* sklist_next */
+ (struct sock *)&udpv6_prot, /* sklist_prev */
+ udpv6_close, /* close */
+ udpv6_connect, /* connect */
+ NULL, /* accept */
+ NULL, /* retransmit */
+ NULL, /* write_wakeup */
+ NULL, /* read_wakeup */
+ datagram_poll, /* poll */
+ udp_ioctl, /* ioctl */
+ NULL, /* init */
+ inet6_destroy_sock, /* destroy */
+ NULL, /* shutdown */
+ ipv6_setsockopt, /* setsockopt */
+ ipv6_getsockopt, /* getsockopt */
+ udpv6_sendmsg, /* sendmsg */
+ udpv6_recvmsg, /* recvmsg */
+ NULL, /* bind */
+ udpv6_queue_rcv_skb, /* backlog_rcv */
+ udp_v6_hash, /* hash */
+ udp_v6_unhash, /* unhash */
+ udp_v6_get_port, /* get_port */
+ 128, /* max_header */
+ 0, /* retransmits */
+ "UDP", /* name */
+ 0, /* inuse */
+ 0 /* highestinuse */
+};
+
+void __init udpv6_init(void)
+{
+ inet6_add_protocol(&udpv6_protocol);
+}
diff --git a/pfinet/linux/errno.h b/pfinet/linux/errno.h
deleted file mode 100644
index 7dab9bab..00000000
--- a/pfinet/linux/errno.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _HACK_ERRNO_H
-#define _HACK_ERRNO_H
-
-#include <errno.h>
-
-#define ERESTARTSYS EINTR
-
-#endif
diff --git a/pfinet/linux/if_ether.h b/pfinet/linux/if_ether.h
deleted file mode 100644
index b87b1785..00000000
--- a/pfinet/linux/if_ether.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Global definitions for the Ethernet IEEE 802.3 interface.
- *
- * Version: @(#)if_ether.h 1.0.1a 02/08/94
- *
- * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Donald Becker, <becker@super.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _LINUX_IF_ETHER_H
-#define _LINUX_IF_ETHER_H
-
-
-/* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
- and FCS/CRC (frame check sequence). */
-#define ETH_ALEN 6 /* Octets in one ethernet addr */
-#define ETH_HLEN 14 /* Total octets in header. */
-#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
-#define ETH_DATA_LEN 1500 /* Max. octets in payload */
-#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
-
-
-/* These are the defined Ethernet Protocol ID's. */
-#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
-#define ETH_P_ECHO 0x0200 /* Ethernet Echo packet */
-#define ETH_P_PUP 0x0400 /* Xerox PUP packet */
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_ARP 0x0806 /* Address Resolution packet */
-#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
-#define ETH_P_X25 0x0805 /* CCITT X.25 */
-#define ETH_P_ATALK 0x809B /* Appletalk DDP */
-#define ETH_P_IPX 0x8137 /* IPX over DIX */
-#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
-#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
-#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
-#define ETH_P_802_2 0x0004 /* 802.2 frames */
-#define ETH_P_SNAP 0x0005 /* Internal only */
-/* This is an Ethernet frame header. */
-struct ethhdr {
- unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
- unsigned char h_source[ETH_ALEN]; /* source ether addr */
- unsigned short h_proto; /* packet type ID field */
-};
-
-/* Ethernet statistics collection data. */
-struct enet_statistics{
- int rx_packets; /* total packets received */
- int tx_packets; /* total packets transmitted */
- int rx_errors; /* bad packets received */
- int tx_errors; /* packet transmit problems */
- int rx_dropped; /* no space in linux buffers */
- int tx_dropped; /* no space available in linux */
- int multicast; /* multicast packets received */
- int collisions;
-
- /* detailed rx_errors: */
- int rx_length_errors;
- int rx_over_errors; /* receiver ring buff overflow */
- int rx_crc_errors; /* recved pkt with crc error */
- int rx_frame_errors; /* recv'd frame alignment error */
- int rx_fifo_errors; /* recv'r fifo overrun */
- int rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
- int tx_aborted_errors;
- int tx_carrier_errors;
- int tx_fifo_errors;
- int tx_heartbeat_errors;
- int tx_window_errors;
-};
-
-#endif /* _LINUX_IF_ETHER_H */
diff --git a/pfinet/linux/igmp.h b/pfinet/linux/igmp.h
deleted file mode 100644
index 6ca7e019..00000000
--- a/pfinet/linux/igmp.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Linux NET3: Internet Gateway Management Protocol [IGMP]
- *
- * Authors:
- * Alan Cox <Alan.Cox@linux.org>
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_IGMP_H
-#define _LINUX_IGMP_H
-
-/*
- * IGMP protocol structures
- */
-
-struct igmphdr
-{
- unsigned char type;
- unsigned char unused;
- unsigned short csum;
- unsigned long group;
-};
-
-#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */
-#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */
-#define IGMP_HOST_LEAVE_MESSAGE 0x17 /* An extra BSD seems to send */
-
- /* 224.0.0.1 */
-#define IGMP_ALL_HOSTS htonl(0xE0000001L)
-
-/*
- * struct for keeping the multicast list in
- */
-
-#ifdef __KERNEL__
-struct ip_mc_socklist
-{
- unsigned long multiaddr[IP_MAX_MEMBERSHIPS]; /* This is a speed trade off */
- struct device *multidev[IP_MAX_MEMBERSHIPS];
-};
-
-struct ip_mc_list
-{
- struct device *interface;
- unsigned long multiaddr;
- struct ip_mc_list *next;
- struct timer_list timer;
- int tm_running;
- int users;
-};
-
-extern struct ip_mc_list *ip_mc_head;
-
-
-extern int igmp_rcv(struct sk_buff *, struct device *, struct options *, unsigned long, unsigned short,
- unsigned long, int , struct inet_protocol *);
-extern void ip_mc_drop_device(struct device *dev);
-extern int ip_mc_join_group(struct sock *sk, struct device *dev, unsigned long addr);
-extern int ip_mc_leave_group(struct sock *sk, struct device *dev,unsigned long addr);
-extern void ip_mc_drop_socket(struct sock *sk);
-#endif
-#endif
diff --git a/pfinet/linux/in.h b/pfinet/linux/in.h
deleted file mode 100644
index 260020a6..00000000
--- a/pfinet/linux/in.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <netinet/in.h>
diff --git a/pfinet/linux/inet.h b/pfinet/linux/inet.h
deleted file mode 100644
index 27aa5521..00000000
--- a/pfinet/linux/inet.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _HACK_INET_H_
-#define _HACK_INET_H_
-
-char *in_ntoa (u_long);
-
-#endif
diff --git a/pfinet/linux/interrupt.h b/pfinet/linux/interrupt.h
deleted file mode 100644
index 01f11a8c..00000000
--- a/pfinet/linux/interrupt.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _HACK_INTERRUPT_H_
-#define _HACK_INTERRUPT_H_
-
-#include <linux/netdevice.h>
-#include "pfinet.h"
-
-#define NET_BH 1
-
-extern void mark_bh (int);
-
-#endif
diff --git a/pfinet/linux/ip.h b/pfinet/linux/ip.h
deleted file mode 100644
index bcc1bdea..00000000
--- a/pfinet/linux/ip.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the IP protocol.
- *
- * Version: @(#)ip.h 1.0.2 04/28/93
- *
- * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _LINUX_IP_H
-#define _LINUX_IP_H
-
-
-#define IPOPT_END 0
-#define IPOPT_NOOP 1
-#define IPOPT_SEC 130
-#define IPOPT_LSRR 131
-#define IPOPT_SSRR 137
-#define IPOPT_RR 7
-#define IPOPT_SID 136
-#define IPOPT_TIMESTAMP 68
-
-
-#define MAXTTL 255
-
-struct timestamp {
- __u8 len;
- __u8 ptr;
- union {
-#if defined(__i386__)
- __u8 flags:4,
- overflow:4;
-#elif defined(__mc68000__)
- __u8 overflow:4,
- flags:4;
-#elif defined(__MIPSEL__)
- __u8 flags:4,
- overflow:4;
-#elif defined(__MIPSEB__)
- __u8 overflow:4,
- flags:4;
-#elif defined(__alpha__)
- __u8 flags:4,
- overflow:4;
-#elif defined(__sparc__)
- __u8 overflow:4,
- flags:4;
-#else
-#error "Adjust this structure to match your CPU"
-#endif
- __u8 full_char;
- } x;
- __u32 data[9];
-};
-
-
-#define MAX_ROUTE 16
-
-struct route {
- char route_size;
- char pointer;
- unsigned long route[MAX_ROUTE];
-};
-
-
-struct options {
- struct route record_route;
- struct route loose_route;
- struct route strict_route;
- struct timestamp tstamp;
- unsigned short security;
- unsigned short compartment;
- unsigned short handling;
- unsigned short stream;
- unsigned tcc;
-};
-
-
-struct iphdr {
-#if defined(__i386__)
- __u8 ihl:4,
- version:4;
-#elif defined (__mc68000__)
- __u8 version:4,
- ihl:4;
-#elif defined(__MIPSEL__)
- __u8 ihl:4,
- version:4;
-#elif defined(__MIPSEB__)
- __u8 version:4,
- ihl:4;
-#elif defined(__alpha__)
- __u8 ihl:4,
- version:4;
-#elif defined (__sparc__)
- __u8 version:4,
- ihl:4;
-#else
-#error "Adjust this structure to match your CPU"
-#endif
- __u8 tos;
- __u16 tot_len;
- __u16 id;
- __u16 frag_off;
- __u8 ttl;
- __u8 protocol;
- __u16 check;
- __u32 saddr;
- __u32 daddr;
- /*The options start here. */
-};
-
-
-#endif /* _LINUX_IP_H */
diff --git a/pfinet/linux/ip_fw.h b/pfinet/linux/ip_fw.h
deleted file mode 100644
index f80cccbf..00000000
--- a/pfinet/linux/ip_fw.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * IP firewalling code. This is taken from 4.4BSD. Please note the
- * copyright message below. As per the GPL it must be maintained
- * and the licenses thus do not conflict. While this port is subject
- * to the GPL I also place my modifications under the original
- * license in recognition of the original copyright.
- *
- * Ported from BSD to Linux,
- * Alan Cox 22/Nov/1994.
- * Merged and included the FreeBSD-Current changes at Ugen's request
- * (but hey it's a lot cleaner now). Ugen would prefer in some ways
- * we waited for his final product but since Linux 1.2.0 is about to
- * appear it's not practical - Read: It works, it's not clean but please
- * don't consider it to be his standard of finished work.
- * Alan.
- *
- * All the real work was done by .....
- */
-
-/*
- * Copyright (c) 1993 Daniel Boulet
- * Copyright (c) 1994 Ugen J.S.Antsilevich
- *
- * Redistribution and use in source forms, with and without modification,
- * are permitted provided that this entire comment appears intact.
- *
- * Redistribution in binary form may occur without any restrictions.
- * Obviously, it would be nice if you gave credit where credit is due
- * but requiring it would be too onerous.
- *
- * This software is provided ``AS IS'' without any warranties of any kind.
- */
-
-/*
- * Format of an IP firewall descriptor
- *
- * src, dst, src_mask, dst_mask are always stored in network byte order.
- * flags and num_*_ports are stored in host byte order (of course).
- * Port numbers are stored in HOST byte order.
- */
-
-#ifndef _IP_FW_H
-#define _IP_FW_H
-
-struct ip_fw
-{
- struct ip_fw *fw_next; /* Next firewall on chain */
- struct in_addr fw_src, fw_dst; /* Source and destination IP addr */
- struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */
- struct in_addr fw_via; /* IP address of interface "via" */
- unsigned short fw_flg; /* Flags word */
- unsigned short fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */
- /* in ports array (dst ports follow */
- /* src ports; max of 10 ports in all; */
- /* count of 0 means match all ports) */
-#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */
- unsigned short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */
- unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */
-};
-
-/*
- * Values for "flags" field .
- */
-
-#define IP_FW_F_ALL 0x000 /* This is a universal packet firewall*/
-#define IP_FW_F_TCP 0x001 /* This is a TCP packet firewall */
-#define IP_FW_F_UDP 0x002 /* This is a UDP packet firewall */
-#define IP_FW_F_ICMP 0x003 /* This is a ICMP packet firewall */
-#define IP_FW_F_KIND 0x003 /* Mask to isolate firewall kind */
-#define IP_FW_F_ACCEPT 0x004 /* This is an accept firewall (as *
- * opposed to a deny firewall)*
- * */
-#define IP_FW_F_SRNG 0x008 /* The first two src ports are a min *
- * and max range (stored in host byte *
- * order). *
- * */
-#define IP_FW_F_DRNG 0x010 /* The first two dst ports are a min *
- * and max range (stored in host byte *
- * order). *
- * (ports[0] <= port <= ports[1]) *
- * */
-#define IP_FW_F_PRN 0x020 /* In verbose mode print this firewall*/
-#define IP_FW_F_BIDIR 0x040 /* For bidirectional firewalls */
-#define IP_FW_F_TCPSYN 0x080 /* For tcp packets-check SYN only */
-#define IP_FW_F_ICMPRPL 0x100 /* Send back icmp unreachable packet */
-#define IP_FW_F_MASK 0x1FF /* All possible flag bits mask */
-
-/*
- * New IP firewall options for [gs]etsockopt at the RAW IP level.
- * Unlike BSD Linux inherits IP options so you don't have to use
- * a raw socket for this. Instead we check rights in the calls.
- */
-
-#define IP_FW_BASE_CTL 64
-
-#define IP_FW_ADD_BLK (IP_FW_BASE_CTL)
-#define IP_FW_ADD_FWD (IP_FW_BASE_CTL+1)
-#define IP_FW_CHK_BLK (IP_FW_BASE_CTL+2)
-#define IP_FW_CHK_FWD (IP_FW_BASE_CTL+3)
-#define IP_FW_DEL_BLK (IP_FW_BASE_CTL+4)
-#define IP_FW_DEL_FWD (IP_FW_BASE_CTL+5)
-#define IP_FW_FLUSH_BLK (IP_FW_BASE_CTL+6)
-#define IP_FW_FLUSH_FWD (IP_FW_BASE_CTL+7)
-#define IP_FW_ZERO_BLK (IP_FW_BASE_CTL+8)
-#define IP_FW_ZERO_FWD (IP_FW_BASE_CTL+9)
-#define IP_FW_POLICY_BLK (IP_FW_BASE_CTL+10)
-#define IP_FW_POLICY_FWD (IP_FW_BASE_CTL+11)
-
-#define IP_ACCT_ADD (IP_FW_BASE_CTL+16)
-#define IP_ACCT_DEL (IP_FW_BASE_CTL+17)
-#define IP_ACCT_FLUSH (IP_FW_BASE_CTL+18)
-#define IP_ACCT_ZERO (IP_FW_BASE_CTL+19)
-
-struct ip_fwpkt
-{
- struct iphdr fwp_iph; /* IP header */
- union {
- struct tcphdr fwp_tcph; /* TCP header or */
- struct udphdr fwp_udph; /* UDP header */
- } fwp_protoh;
- struct in_addr fwp_via; /* interface address */
-};
-
-/*
- * Main firewall chains definitions and global var's definitions.
- */
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-
-#ifdef CONFIG_IP_FIREWALL
-extern struct ip_fw *ip_fw_blk_chain;
-extern struct ip_fw *ip_fw_fwd_chain;
-extern int ip_fw_blk_policy;
-extern int ip_fw_fwd_policy;
-extern int ip_fw_ctl(int, void *, int);
-#endif
-#ifdef CONFIG_IP_ACCT
-extern struct ip_fw *ip_acct_chain;
-extern void ip_acct_cnt(struct iphdr *, struct device *, struct ip_fw *);
-extern int ip_acct_ctl(int, void *, int);
-#endif
-extern int ip_fw_chk(struct iphdr *, struct device *rif,struct ip_fw *, int, int);
-#endif /* KERNEL */
-
-#endif /* _IP_FW_H */
diff --git a/pfinet/linux/kernel.h b/pfinet/linux/kernel.h
deleted file mode 100644
index dcd5acf3..00000000
--- a/pfinet/linux/kernel.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _HACK_KERNEL_H
-#define _HACK_KERNEL_H
-
-#include <stdio.h>
-#include <linux/sched.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#define printk printf
-
-extern inline int
-getname (const char *name, char **newp)
-{
- *newp = malloc (strlen (name) + 1);
- strcpy (*newp, name);
- return 0;
-}
-
-extern inline void
-putname (char *p)
-{
- free (p);
-}
-
-/* These two functions are used only to send SIGURG. But I can't
- find any SIGIO code at all. So we'll just punt on that; clearly
- Linux is missing the point. SIGURG should only be sent for
- sockets that have explicitly requested it. */
-extern inline int
-kill_proc (int pid, int signo, int priv)
-{
- assert (signo == SIGURG);
- return 0;
-}
-
-extern inline int
-kill_pg (int pgrp, int signo, int priv)
-{
- assert (signo == SIGURG);
- return 0;
-}
-
-
-#endif
diff --git a/pfinet/linux/malloc.h b/pfinet/linux/malloc.h
deleted file mode 100644
index 06930659..00000000
--- a/pfinet/linux/malloc.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _HACK_MALLOC_H_
-#define _HACK_MALLOC_H_
-
-#include <linux/mm.h>
-
-#define kfree_s(a,b) (free (a))
-#define kfree(a) (free (a))
-#define kmalloc(a,b) (malloc (a))
-
-#endif
diff --git a/pfinet/linux/mm.h b/pfinet/linux/mm.h
deleted file mode 100644
index 0fb18a59..00000000
--- a/pfinet/linux/mm.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _HACK_MM_H_
-#define _HACK_MM_H_
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-/* All memory addresses are presumptively valid, because they are
- all internal. */
-#define verify_area(a,b,c) 0
-
-#define VERIFY_READ 0
-#define VERIFY_WRITE 0
-#define GFP_ATOMIC 0
-#define GFP_KERNEL 0
-
-#endif
diff --git a/pfinet/linux/netdevice.h b/pfinet/linux/netdevice.h
deleted file mode 100644
index dcca542d..00000000
--- a/pfinet/linux/netdevice.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the Interfaces handler.
- *
- * Version: @(#)dev.h 1.0.10 08/12/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- * Donald J. Becker, <becker@super.org>
- * Alan Cox, <A.Cox@swansea.ac.uk>
- * Bjorn Ekwall. <bj0rn@blox.se>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Moved to /usr/include/linux for NET3
- */
-#ifndef _LINUX_NETDEVICE_H
-#define _LINUX_NETDEVICE_H
-
-#include <linux/if.h>
-#include <linux/if_ether.h>
-#include <linux/skbuff.h>
-
-/* for future expansion when we will have different priorities. */
-#define DEV_NUMBUFFS 3
-#define MAX_ADDR_LEN 7
-#define MAX_HEADER 18
-
-#define IS_MYADDR 1 /* address is (one of) our own */
-#define IS_LOOPBACK 2 /* address is for LOOPBACK */
-#define IS_BROADCAST 3 /* address is a valid broadcast */
-#define IS_INVBCAST 4 /* Wrong netmask bcast not for us (unused)*/
-#define IS_MULTICAST 5 /* Multicast IP address */
-
-/*
- * We tag these structures with multicasts.
- */
-
-struct dev_mc_list
-{
- struct dev_mc_list *next;
- char dmi_addr[MAX_ADDR_LEN];
- unsigned short dmi_addrlen;
- unsigned short dmi_users;
-};
-
-/*
- * The DEVICE structure.
- * Actually, this whole structure is a big mistake. It mixes I/O
- * data with strictly "high-level" data, and it has to know about
- * almost every data structure used in the INET module.
- */
-struct device
-{
-
- /*
- * This is the first field of the "visible" part of this structure
- * (i.e. as seen by users in the "Space.c" file). It is the name
- * the interface.
- */
- char *name;
-
- /* I/O specific fields - FIXME: Merge these and struct ifmap into one */
- unsigned long rmem_end; /* shmem "recv" end */
- unsigned long rmem_start; /* shmem "recv" start */
- unsigned long mem_end; /* sahared mem end */
- unsigned long mem_start; /* shared mem start */
- unsigned long base_addr; /* device I/O address */
- unsigned char irq; /* device IRQ number */
-
- /* Low-level status flags. */
- volatile unsigned char start, /* start an operation */
- tbusy, /* transmitter busy */
- interrupt; /* interrupt arrived */
-
- struct device *next;
-
- /* The device initialization function. Called only once. */
- int (*init)(struct device *dev);
-
- /* Some hardware also needs these fields, but they are not part of the
- usual set specified in Space.c. */
- unsigned char if_port; /* Selectable AUI, TP,..*/
- unsigned char dma; /* DMA channel */
-
- struct enet_statistics* (*get_stats)(struct device *dev);
-
- /*
- * This marks the end of the "visible" part of the structure. All
- * fields hereafter are internal to the system, and may change at
- * will (read: may be cleaned up at will).
- */
-
- /* These may be needed for future network-power-down code. */
- unsigned long trans_start; /* Time (in jiffies) of last Tx */
- unsigned long last_rx; /* Time of last Rx */
-
- unsigned short flags; /* interface flags (a la BSD) */
- unsigned short family; /* address family ID (AF_INET) */
- unsigned short metric; /* routing metric (not used) */
- unsigned short mtu; /* interface MTU value */
- unsigned short type; /* interface hardware type */
- unsigned short hard_header_len; /* hardware hdr length */
- void *priv; /* pointer to private data */
-
- /* Interface address info. */
- unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
- unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */
- unsigned char addr_len; /* hardware address length */
- unsigned long pa_addr; /* protocol address */
- unsigned long pa_brdaddr; /* protocol broadcast addr */
- unsigned long pa_dstaddr; /* protocol P-P other side addr */
- unsigned long pa_mask; /* protocol netmask */
- unsigned short pa_alen; /* protocol address length */
-
- struct dev_mc_list *mc_list; /* Multicast mac addresses */
- int mc_count; /* Number of installed mcasts */
-
- struct ip_mc_list *ip_mc_list; /* IP multicast filter chain */
-
- /* For load balancing driver pair support */
-
- unsigned long pkt_queue; /* Packets queued */
- struct device *slave; /* Slave device */
-
-
- /* Pointer to the interface buffers. */
- struct sk_buff_head buffs[DEV_NUMBUFFS];
-
- /* Pointers to interface service routines. */
- int (*open)(struct device *dev);
- int (*stop)(struct device *dev);
- int (*hard_start_xmit) (struct sk_buff *skb,
- struct device *dev);
- int (*hard_header) (unsigned char *buff,
- struct device *dev,
- unsigned short type,
- void *daddr,
- void *saddr,
- unsigned len,
- struct sk_buff *skb);
- int (*rebuild_header)(void *eth, struct device *dev,
- unsigned long raddr, struct sk_buff *skb);
- unsigned short (*type_trans) (struct sk_buff *skb,
- struct device *dev);
-#define HAVE_MULTICAST
- void (*set_multicast_list)(struct device *dev,
- int num_addrs, void *addrs);
-#define HAVE_SET_MAC_ADDR
- int (*set_mac_address)(struct device *dev, void *addr);
-#define HAVE_PRIVATE_IOCTL
- int (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd);
-#define HAVE_SET_CONFIG
- int (*set_config)(struct device *dev, struct ifmap *map);
-
-};
-
-
-struct packet_type {
- unsigned short type; /* This is really htons(ether_type). */
- struct device * dev;
- int (*func) (struct sk_buff *, struct device *,
- struct packet_type *);
- void *data;
- struct packet_type *next;
-};
-
-
-#ifdef __KERNEL__
-
-#include <linux/notifier.h>
-
-/* Used by dev_rint */
-#define IN_SKBUFF 1
-
-extern volatile char in_bh;
-
-extern struct device loopback_dev;
-extern struct device *dev_base;
-extern struct packet_type *ptype_base;
-
-
-extern int ip_addr_match(unsigned long addr1, unsigned long addr2);
-extern int ip_chk_addr(unsigned long addr);
-extern struct device *ip_dev_check(unsigned long daddr);
-extern unsigned long ip_my_addr(void);
-extern unsigned long ip_get_mask(unsigned long addr);
-
-extern void dev_add_pack(struct packet_type *pt);
-extern void dev_remove_pack(struct packet_type *pt);
-extern struct device *dev_get(char *name);
-extern int dev_open(struct device *dev);
-extern int dev_close(struct device *dev);
-extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev,
- int pri);
-#define HAVE_NETIF_RX 1
-extern void netif_rx(struct sk_buff *skb);
-/* The old interface to netif_rx(). */
-extern int dev_rint(unsigned char *buff, long len, int flags,
- struct device * dev);
-extern void dev_transmit(void);
-extern int in_net_bh(void);
-extern void net_bh(void *tmp);
-extern void dev_tint(struct device *dev);
-extern int dev_get_info(char *buffer, char **start, off_t offset, int length);
-extern int dev_ioctl(unsigned int cmd, void *);
-
-extern void dev_init(void);
-
-/* These functions live elsewhere (drivers/net/net_init.c, but related) */
-
-extern void ether_setup(struct device *dev);
-extern int ether_config(struct device *dev, struct ifmap *map);
-/* Support for loadable net-drivers */
-extern int register_netdev(struct device *dev);
-extern void unregister_netdev(struct device *dev);
-extern int register_netdevice_notifier(struct notifier_block *nb);
-extern int unregister_netdevice_notifier(struct notifier_block *nb);
-/* Functions used for multicast support */
-extern void dev_mc_upload(struct device *dev);
-extern void dev_mc_delete(struct device *dev, void *addr, int alen, int all);
-extern void dev_mc_add(struct device *dev, void *addr, int alen, int newonly);
-extern void dev_mc_discard(struct device *dev);
-/* This is the wrong place but it'll do for the moment */
-extern void ip_mc_allhost(struct device *dev);
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_DEV_H */
diff --git a/pfinet/linux/route.h b/pfinet/linux/route.h
deleted file mode 100644
index 3cadd206..00000000
--- a/pfinet/linux/route.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Global definitions for the IP router interface.
- *
- * Version: @(#)route.h 1.0.3 05/27/93
- *
- * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _LINUX_ROUTE_H
-#define _LINUX_ROUTE_H
-
-#include <linux/if.h>
-
-
-/* This structure gets passed by the SIOCADDRTOLD and SIOCDELRTOLD calls. */
-
-struct old_rtentry {
- unsigned long rt_genmask;
- struct sockaddr rt_dst;
- struct sockaddr rt_gateway;
- short rt_flags;
- short rt_refcnt;
- unsigned long rt_use;
- char *rt_dev;
-};
-
-/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */
-struct rtentry {
- unsigned long rt_hash; /* hash key for lookups */
- struct sockaddr rt_dst; /* target address */
- struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
- struct sockaddr rt_genmask; /* target network mask (IP) */
- short rt_flags;
- short rt_refcnt;
- unsigned long rt_use;
- struct ifnet *rt_ifp;
- short rt_metric; /* +1 for binary compatibility! */
- char *rt_dev; /* forcing the device at add */
- unsigned long rt_mss; /* per route MTU/Window */
- unsigned long rt_window; /* Window clamping */
-};
-
-
-#define RTF_UP 0x0001 /* route usable */
-#define RTF_GATEWAY 0x0002 /* destination is a gateway */
-#define RTF_HOST 0x0004 /* host entry (net otherwise) */
-#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
-#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
-#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
-#define RTF_MSS 0x0040 /* specific MSS for this route */
-#define RTF_WINDOW 0x0080 /* per route window clamping */
-
-/*
- * REMOVE THESE BY 1.2.0 !!!!!!!!!!!!!!!!!
- */
-
-#define RTF_MTU RTF_MSS
-#define rt_mtu rt_mss
-
-#endif /* _LINUX_ROUTE_H */
diff --git a/pfinet/linux/sched.h b/pfinet/linux/sched.h
deleted file mode 100644
index 08358dd5..00000000
--- a/pfinet/linux/sched.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef _HACK_SCHED_H
-#define _HACK_SCHED_H
-
-#include <linux/wait.h>
-#include <sys/signal.h>
-#include <hurd/hurd_types.h>
-#include <linux/kernel.h>
-#include <linux/net.h>
-#include <sys/time.h>
-#include "mapped-time.h"
-#include <assert.h>
-#include <mach.h>
-#include <asm/system.h>
-
-#define jiffies (fetch_jiffies ())
-extern struct task_struct *current;
-extern struct task_struct current_contents;
-
-struct task_struct
-{
- uid_t pgrp, pid;
- int flags;
- int timeout;
- int signal;
- int blocked;
- int state;
- int isroot;
-};
-
-/* FLAGS in task_struct's. */
-#define PF_EXITING 1
-/* STATE in task_struct's. */
-#define TASK_INTERRUPTIBLE 1
-#define TASK_RUNNING 2
-
-extern inline int
-suser ()
-{
- return current->isroot;
-};
-
-void wake_up_interruptible (struct wait_queue **);
-void interruptible_sleep_on (struct wait_queue **);
-
-void select_wait (struct wait_queue **, select_table *);
-
-void schedule (void);
-
-#define SEL_IN SELECT_READ
-#define SEL_OUT SELECT_WRITE
-#define SEL_EX SELECT_URG
-
-/* This function is used only to send SIGPIPE to the current
- task. In all such cases, EPIPE is returned anyhow. In the
- Hurd, servers are not responsible for SIGPIPE; the library
- does that itself upon receiving EPIPE. So we can just
- NOP such calls. */
-extern inline int
-send_sig (u_long signo, struct task_struct *task, int priv)
-{
- assert (signo == SIGPIPE);
- assert (task == current);
- return 0;
-}
-
-int fetch_current_time (void);
-struct timeval fetch_xtime (void);
-
-#define xtime (fetch_xtime ())
-#define CURRENT_TIME (xtime.tv_sec)
-
-static struct timeval _xtime_buf;
-
-extern inline struct timeval
-fetch_xtime ()
-{
- fill_timeval (&_xtime_buf);
- return _xtime_buf;
-}
-
-#endif
diff --git a/pfinet/linux/skbuff.h b/pfinet/linux/skbuff.h
deleted file mode 100644
index 817f89d7..00000000
--- a/pfinet/linux/skbuff.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Definitions for the 'struct sk_buff' memory handlers.
- *
- * Authors:
- * Alan Cox, <gw4pts@gw4pts.ampr.org>
- * Florian La Roche, <rzsfl@rz.uni-sb.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_SKBUFF_H
-#define _LINUX_SKBUFF_H
-#include <linux/malloc.h>
-#include <linux/wait.h>
-#include <linux/time.h>
-#include <linux/config.h>
-
-#undef CONFIG_SKB_CHECK
-
-#define HAVE_ALLOC_SKB /* For the drivers to know */
-
-
-#define FREE_READ 1
-#define FREE_WRITE 0
-
-
-struct sk_buff_head {
- struct sk_buff * volatile next;
- struct sk_buff * volatile prev;
-#if CONFIG_SKB_CHECK
- int magic_debug_cookie;
-#endif
-};
-
-
-struct sk_buff {
- struct sk_buff * volatile next;
- struct sk_buff * volatile prev;
-#if CONFIG_SKB_CHECK
- int magic_debug_cookie;
-#endif
- struct sk_buff * volatile link3;
- struct sock *sk;
- volatile unsigned long when; /* used to compute rtt's */
- struct timeval stamp;
- struct device *dev;
- struct sk_buff *mem_addr;
- union {
- struct tcphdr *th;
- struct ethhdr *eth;
- struct iphdr *iph;
- struct udphdr *uh;
- unsigned char *raw;
- unsigned long seq;
- } h;
- struct iphdr *ip_hdr; /* For IPPROTO_RAW */
- unsigned long mem_len;
- unsigned long len;
- unsigned long fraglen;
- struct sk_buff *fraglist; /* Fragment list */
- unsigned long truesize;
- unsigned long saddr;
- unsigned long daddr;
- unsigned long raddr; /* next hop addr */
- volatile char acked,
- used,
- free,
- arp;
- unsigned char tries,lock,localroute,pkt_type;
-#define PACKET_HOST 0 /* To us */
-#define PACKET_BROADCAST 1
-#define PACKET_MULTICAST 2
-#define PACKET_OTHERHOST 3 /* Unmatched promiscuous */
- unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
- unsigned short pkt_class; /* For drivers that need to cache the packet type with the skbuff (new PPP) */
-#ifdef CONFIG_SLAVE_BALANCING
- unsigned short in_dev_queue;
-#endif
- unsigned long padding[0];
- unsigned char data[0];
-};
-
-#define SK_WMEM_MAX 32767
-#define SK_RMEM_MAX 32767
-
-#ifdef CONFIG_SKB_CHECK
-#define SK_FREED_SKB 0x0DE2C0DE
-#define SK_GOOD_SKB 0xDEC0DED1
-#define SK_HEAD_SKB 0x12231298
-#endif
-
-#ifdef __KERNEL__
-/*
- * Handling routines are only of interest to the kernel
- */
-
-#include <asm/system.h>
-
-#if 0
-extern void print_skb(struct sk_buff *);
-#endif
-extern void kfree_skb(struct sk_buff *skb, int rw);
-extern void skb_queue_head_init(struct sk_buff_head *list);
-extern void skb_queue_head(struct sk_buff_head *list,struct sk_buff *buf);
-extern void skb_queue_tail(struct sk_buff_head *list,struct sk_buff *buf);
-extern struct sk_buff * skb_dequeue(struct sk_buff_head *list);
-extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk);
-extern void skb_append(struct sk_buff *old,struct sk_buff *newsk);
-extern void skb_unlink(struct sk_buff *buf);
-extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list);
-extern struct sk_buff * alloc_skb(unsigned int size, int priority);
-extern void kfree_skbmem(struct sk_buff *skb, unsigned size);
-extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority);
-extern void skb_device_lock(struct sk_buff *skb);
-extern void skb_device_unlock(struct sk_buff *skb);
-extern void dev_kfree_skb(struct sk_buff *skb, int mode);
-extern int skb_device_locked(struct sk_buff *skb);
-/*
- * Peek an sk_buff. Unlike most other operations you _MUST_
- * be careful with this one. A peek leaves the buffer on the
- * list and someone else may run off with it. For an interrupt
- * type system cli() peek the buffer copy the data and sti();
- */
-static __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
-{
- struct sk_buff *list = (struct sk_buff *)list_;
- return (list->next != list)? list->next : NULL;
-}
-
-#if CONFIG_SKB_CHECK
-extern int skb_check(struct sk_buff *skb,int,int, char *);
-#define IS_SKB(skb) skb_check((skb), 0, __LINE__,__FILE__)
-#define IS_SKB_HEAD(skb) skb_check((skb), 1, __LINE__,__FILE__)
-#else
-#define IS_SKB(skb)
-#define IS_SKB_HEAD(skb)
-
-extern __inline__ void skb_queue_head_init(struct sk_buff_head *list)
-{
- list->prev = (struct sk_buff *)list;
- list->next = (struct sk_buff *)list;
-}
-
-/*
- * Insert an sk_buff at the start of a list.
- */
-
-extern __inline__ void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk)
-{
- unsigned long flags;
- struct sk_buff *list = (struct sk_buff *)list_;
-
- save_flags(flags);
- cli();
- newsk->next = list->next;
- newsk->prev = list;
- newsk->next->prev = newsk;
- newsk->prev->next = newsk;
- restore_flags(flags);
-}
-
-/*
- * Insert an sk_buff at the end of a list.
- */
-
-extern __inline__ void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
-{
- unsigned long flags;
- struct sk_buff *list = (struct sk_buff *)list_;
-
- save_flags(flags);
- cli();
-
- newsk->next = list;
- newsk->prev = list->prev;
-
- newsk->next->prev = newsk;
- newsk->prev->next = newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Remove an sk_buff from a list. This routine is also interrupt safe
- * so you can grab read and free buffers as another process adds them.
- */
-
-extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list_)
-{
- long flags;
- struct sk_buff *result;
- struct sk_buff *list = (struct sk_buff *)list_;
-
- save_flags(flags);
- cli();
-
- result = list->next;
- if (result == list) {
- restore_flags(flags);
- return NULL;
- }
-
- result->next->prev = list;
- list->next = result->next;
-
- result->next = NULL;
- result->prev = NULL;
-
- restore_flags(flags);
-
- return result;
-}
-
-/*
- * Insert a packet before another one in a list.
- */
-
-extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- newsk->next = old;
- newsk->prev = old->prev;
- old->prev = newsk;
- newsk->prev->next = newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Place a packet after a given packet in a list.
- */
-
-extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- newsk->prev = old;
- newsk->next = old->next;
- newsk->next->prev = newsk;
- old->next = newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Remove an sk_buff from its list. Works even without knowing the list it
- * is sitting on, which can be handy at times. It also means that THE LIST
- * MUST EXIST when you unlink. Thus a list must have its contents unlinked
- * _FIRST_.
- */
-
-extern __inline__ void skb_unlink(struct sk_buff *skb)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- if(skb->prev && skb->next)
- {
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
- skb->next = NULL;
- skb->prev = NULL;
- }
- restore_flags(flags);
-}
-
-#endif
-
-extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
-extern int datagram_select(struct sock *sk, int sel_type, select_table *wait);
-extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
-extern void skb_free_datagram(struct sk_buff *skb);
-
-#endif /* __KERNEL__ */
-#endif /* _LINUX_SKBUFF_H */
diff --git a/pfinet/linux/socket.h b/pfinet/linux/socket.h
deleted file mode 100644
index 22dd05ce..00000000
--- a/pfinet/linux/socket.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _HACK_SOCKET_H_
-#define _HACK_SOCKET_H_
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#define IP_MAX_MEMBERSHIPS 10
-
-#define IPTOS_LOWDELAY 0x10
-#define IPTOS_THROUGHPUT 0x08
-#define IPTOS_RELIABILITY 0x04
-
-#define SOPRI_INTERACTIVE 0
-#define SOPRI_NORMAL 1
-#define SOPRI_BACKGROUND 2
-
-#define SOL_IP IPPROTO_IP
-#define SOL_TCP IPPROTO_TCP
-
-/* TCP options */
-#define TCP_NODELAY 1
-#define TCP_MAXSEG 2
-
-#define SO_NO_CHECK 11
-#define SO_PRIORITY 12
-
-#endif
diff --git a/pfinet/linux/time.h b/pfinet/linux/time.h
deleted file mode 100644
index 9b6b9904..00000000
--- a/pfinet/linux/time.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _HACK_TIME_H_
-#define _HACK_TIME_H_
-
-#include <sys/time.h>
-#include "mapped-time.h"
-
-extern inline void
-do_gettimeofday (struct timeval *tp)
-{
- fill_timeval (tp);
-}
-
-#endif
diff --git a/pfinet/linux/types.h b/pfinet/linux/types.h
deleted file mode 100644
index c978fb07..00000000
--- a/pfinet/linux/types.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _HACK_TYPES_H
-#define _HACK_TYPES_H
-
-#include <sys/types.h>
-typedef unsigned char __u8;
-typedef unsigned short __u16;
-typedef unsigned long __u32;
-
-/* Hackery */
-struct inode
-{
- uid_t i_uid;
-};
-
-
-#endif
diff --git a/pfinet/linux/wait.h b/pfinet/linux/wait.h
deleted file mode 100644
index 15759ad2..00000000
--- a/pfinet/linux/wait.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _HACK_WAIT_H_
-#define _HACK_WAIT_H_
-
-#include <cthreads.h>
-
-struct wait_queue
-{
- struct condition c;
-};
-
-struct select_table_elt
-{
- struct condition *dependent_condition;
- struct select_table_elt *next;
-};
-
-typedef struct select_table_struct
-{
- struct condition master_condition;
- struct select_table_elt *head;
-} select_table;
-
-#endif
diff --git a/pfinet/loopback.c b/pfinet/loopback.c
new file mode 100644
index 00000000..068cf3c8
--- /dev/null
+++ b/pfinet/loopback.c
@@ -0,0 +1,130 @@
+/* Loopback "device" for pfinet
+ Copyright (C) 1996,98,2000 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "pfinet.h"
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/if_ether.h> /* For the statistics structure. */
+#include <linux/if_arp.h> /* For ARPHRD_ETHER */
+
+#define LOOPBACK_MTU (vm_page_size - 172)
+
+/*
+ * The higher levels take care of making this non-reentrant (it's
+ * called with bh's disabled).
+ */
+static int loopback_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
+
+ /*
+ * Take this out if the debug says its ok
+ */
+
+ if (skb == NULL || dev == NULL)
+ printk(KERN_DEBUG "loopback fed NULL data - splat\n");
+
+ /*
+ * Optimise so buffers with skb->free=1 are not copied but
+ * instead are lobbed from tx queue to rx queue
+ */
+
+ if(atomic_read(&skb->users) != 1)
+ {
+ struct sk_buff *skb2=skb;
+ skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */
+ if(skb==NULL) {
+ kfree_skb(skb2);
+ return 0;
+ }
+ kfree_skb(skb2);
+ }
+ else
+ skb_orphan(skb);
+
+ skb->protocol=eth_type_trans(skb,dev);
+ skb->dev=dev;
+#ifndef LOOPBACK_MUST_CHECKSUM
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+#endif
+ netif_rx(skb);
+
+ stats->rx_bytes+=skb->len;
+ stats->tx_bytes+=skb->len;
+ stats->rx_packets++;
+ stats->tx_packets++;
+
+ return(0);
+}
+
+static struct net_device_stats *get_stats(struct device *dev)
+{
+ return (struct net_device_stats *)dev->priv;
+}
+
+static int loopback_open(struct device *dev)
+{
+ dev->flags|=IFF_LOOPBACK;
+ return 0;
+}
+
+/* Initialize the rest of the LOOPBACK device. */
+static int loopback_init(struct device *dev)
+{
+ dev->mtu = LOOPBACK_MTU;
+ dev->tbusy = 0;
+ dev->hard_start_xmit = loopback_xmit;
+ dev->hard_header = eth_header;
+ dev->hard_header_cache = eth_header_cache;
+ dev->header_cache_update= eth_header_cache_update;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_LOOPBACK; /* 0x0001 */
+ dev->rebuild_header = eth_rebuild_header;
+ dev->open = loopback_open;
+ dev->flags = IFF_LOOPBACK;
+ dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct net_device_stats));
+ dev->get_stats = get_stats;
+
+ /*
+ * Fill in the generic fields of the device structure.
+ */
+
+ dev_init_buffers(dev);
+
+ return(0);
+}
+
+
+struct device loopback_dev = { name: "lo", init: &loopback_init, };
+
+/* It is important magic that this is the first thing on the list. */
+struct device *dev_base = &loopback_dev;
diff --git a/pfinet/main.c b/pfinet/main.c
index 0df713e4..1357b037 100644
--- a/pfinet/main.c
+++ b/pfinet/main.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,99,2000,02,07 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -26,20 +26,48 @@
#include <argp.h>
#include <hurd/startup.h>
#include <string.h>
+#include <fcntl.h>
+#include <version.h>
+
+/* Include Hurd's errno.h file, but don't include glue-include/hurd/errno.h,
+ since it #undef's the errno macro. */
+#define _HACK_ERRNO_H
+#include <errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/inet.h>
+
+static void pfinet_activate_ipv6 (void);
+
+/* devinet.c */
+extern error_t configure_device (struct device *dev,
+ uint32_t addr, uint32_t netmask,
+ uint32_t peer, uint32_t broadcast);
+
+/* addrconf.c */
+extern int addrconf_notify(struct notifier_block *this, unsigned long event,
+ void * data);
int trivfs_fstype = FSTYPE_MISC;
int trivfs_fsid;
-int trivfs_support_read = 0;
-int trivfs_support_write = 0;
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
int trivfs_support_exec = 0;
-int trivfs_allow_open = 0;
-struct port_class *trivfs_protid_portclasses[1];
-int trivfs_protid_nportclasses = 1;
-struct port_class *trivfs_cntl_portclasses[1];
-int trivfs_cntl_nportclasses = 1;
+int trivfs_allow_open = O_READ | O_WRITE;
+
+struct port_class *trivfs_protid_portclasses[2];
+int trivfs_protid_nportclasses = 2;
+
+struct port_class *trivfs_cntl_portclasses[2];
+int trivfs_cntl_nportclasses = 2;
+
+/* Which portclass to install on the bootstrap port, default to IPv4. */
+int pfinet_bootstrap_portclass = PORTCLASS_INET;
struct port_class *shutdown_notify_class;
+const char *argp_program_version = STANDARD_HURD_VERSION (pfinet);
+
/* Option parser. */
extern struct argp pfinet_argp;
@@ -47,14 +75,34 @@ int
pfinet_demuxer (mach_msg_header_t *inp,
mach_msg_header_t *outp)
{
+ struct port_info *pi;
extern int io_server (mach_msg_header_t *, mach_msg_header_t *);
extern int socket_server (mach_msg_header_t *, mach_msg_header_t *);
extern int startup_notify_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int pfinet_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int iioctl_server (mach_msg_header_t *, mach_msg_header_t *);
- return (io_server (inp, outp)
- || socket_server (inp, outp)
- || trivfs_demuxer (inp, outp)
- || startup_notify_server (inp, outp));
+ /* We have several classes in one bucket, which need to be demuxed
+ differently. */
+ pi = ports_lookup_port(pfinet_bucket, inp->msgh_local_port, socketport_class);
+
+ if (pi)
+ {
+ ports_port_deref (pi);
+
+ return (io_server (inp, outp)
+ || socket_server (inp, outp)
+ || pfinet_server (inp, outp)
+ || iioctl_server (inp, outp)
+ || trivfs_demuxer (inp, outp)
+ || startup_notify_server (inp, outp));
+ }
+ else
+ return (socket_server (inp, outp)
+ || pfinet_server (inp, outp)
+ || iioctl_server (inp, outp)
+ || trivfs_demuxer (inp, outp)
+ || startup_notify_server (inp, outp));
}
/* The system is going down; destroy all the extant port rights. That
@@ -64,35 +112,18 @@ S_startup_dosync (mach_port_t handle)
{
struct port_info *inpi = ports_lookup_port (pfinet_bucket, handle,
shutdown_notify_class);
- error_t
- do1 (void *port)
- {
- struct port_info *pi = port;
-
- if (pi->class == socketport_class)
- ports_destroy_right (pi);
- return 0;
- }
if (!inpi)
return EOPNOTSUPP;
- ports_bucket_iterate (pfinet_bucket, do1);
+ ports_class_iterate (socketport_class, ports_destroy_right);
return 0;
}
void
sigterm_handler (int signo)
{
- error_t
- do1 (void *port)
- {
- struct port_info *pi = port;
- if (pi->class == socketport_class)
- ports_destroy_right (pi);
- return 0;
- }
- ports_bucket_iterate (pfinet_bucket, do1);
+ ports_class_iterate (socketport_class, ports_destroy_right);
sleep (10);
signal (SIGTERM, SIG_DFL);
raise (SIGTERM);
@@ -105,7 +136,7 @@ arrange_shutdown_notification ()
mach_port_t initport, notify;
process_t procserver;
struct port_info *pi;
-
+
shutdown_notify_class = ports_create_class (0, 0);
signal (SIGTERM, sigterm_handler);
@@ -113,88 +144,113 @@ arrange_shutdown_notification ()
/* Arrange to get notified when the system goes down,
but if we fail for some reason, just silently give up. No big deal. */
- err = ports_create_port (shutdown_notify_class, pfinet_bucket,
+ err = ports_create_port (shutdown_notify_class, pfinet_bucket,
sizeof (struct port_info), &pi);
if (err)
return;
-
+
procserver = getproc ();
if (!procserver)
return;
-
+
err = proc_getmsgport (procserver, 1, &initport);
mach_port_deallocate (mach_task_self (), procserver);
if (err)
return;
-
- notify = ports_get_right (pi);
+
+ notify = ports_get_send_right (pi);
ports_port_deref (pi);
- startup_request_notification (initport, notify,
- MACH_MSG_TYPE_MAKE_SEND,
+ startup_request_notification (initport, notify,
+ MACH_MSG_TYPE_MAKE_SEND,
program_invocation_short_name);
+ mach_port_deallocate (mach_task_self (), notify);
mach_port_deallocate (mach_task_self (), initport);
}
-static char *already_open = 0;
-/* Return an open device called NAME. If NMAE is 0, and there is a single
- active device, it is returned, otherwise an error.
- XXX hacky single-interface version. */
+/* Return an open device called NAME. If NAME is 0, and there is a single
+ active device, it is returned, otherwise an error. */
error_t
find_device (char *name, struct device **device)
{
- if (already_open)
- if (!name || strcmp (already_open, (*device)->name) == 0)
+ struct device *dev = dev_base;
+
+ /* Skip loopback interface. */
+ assert (dev);
+ dev = dev->next;
+
+ if (!name)
+ {
+ if (dev)
+ {
+ if (dev->next)
+ return EBUSY; /* XXXACK */
+ else
+ {
+ *device = dev;
+ return 0;
+ }
+ }
+ else
+ return ENXIO; /* XXX */
+ }
+
+ for (; dev; dev = dev->next)
+ if (strcmp (dev->name, name) == 0)
{
- *device = &ether_dev;
+ *device = dev;
return 0;
}
- else
- return EBUSY; /* XXXACK */
- else if (! name)
- return ENXIO; /* XXX */
-
- name = already_open = strdup (name);
- setup_ethernet_device (name);
-
- /* Default mask is 255.255.255.0. XXX should be class dependent. */
- {
- char addr[4] = {255, 255, 255, 0};
- ether_dev.pa_mask = *(u_long *)addr;
- }
+ if (strncmp(name, "tun", 3) == 0)
+ setup_tunnel_device (name, device);
+ else if (strncmp(name, "dummy", 5) == 0)
+ setup_dummy_device (name, device);
+ else
+ setup_ethernet_device (name, device);
/* Turn on device. */
- dev_open (&ether_dev);
-
- *device = &ether_dev;
+ dev_open (*device);
return 0;
}
/* Call FUN with each active device. If a call to FUN returns a
non-zero value, this function will return immediately. Otherwise 0 is
- returned.
- XXX hacky single-interface version. */
+ returned. */
error_t
enumerate_devices (error_t (*fun) (struct device *dev))
{
- if (already_open)
- return (*fun) (&ether_dev);
- else
- return 0;
+ error_t err;
+ struct device *dev = dev_base;
+
+ /* Skip loopback device. */
+ assert (dev);
+ dev = dev->next;
+
+ for (; dev; dev = dev->next)
+ {
+ err = (*fun) (dev);
+ if (err)
+ return err;
+ }
+
+ return 0;
}
+extern void sk_init (void), skb_init (void);
+extern int net_dev_init (void);
+extern void inet6_proto_init (struct net_proto *pro);
+
int
main (int argc,
char **argv)
{
error_t err;
mach_port_t bootstrap;
+ struct stat st;
pfinet_bucket = ports_create_bucket ();
- trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0);
- trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0);
addrport_class = ports_create_class (clean_addrport, 0);
socketport_class = ports_create_class (clean_socketport, 0);
trivfs_fsid = getpid ();
@@ -203,34 +259,169 @@ main (int argc,
/* Generic initialization */
- init_devices ();
init_time ();
+ ethernet_initialize ();
+ cthread_detach (cthread_fork (net_bh_worker, 0));
+
+ __mutex_lock (&global_lock);
+
+ prepare_current (1); /* Set up to call into Linux initialization. */
+ sk_init ();
+#ifdef SLAB_SKB
+ skb_init ();
+#endif
inet_proto_init (0);
- arrange_shutdown_notification ();
+ /* This initializes the Linux network device layer, including
+ initializing each device on the `dev_base' list. For us,
+ that means just loopback_dev, which will get fully initialized now.
+ After this, we can use `register_netdevice' for new interfaces. */
+ net_dev_init ();
+
+ /* ifconfig lo up 127.0.0.1 netmask 0xff000000 */
+ configure_device (&loopback_dev,
+ htonl (INADDR_LOOPBACK), htonl (IN_CLASSA_NET),
+ htonl (INADDR_NONE), htonl (INADDR_NONE));
- /* Parse options. */
+ __mutex_unlock (&global_lock);
+
+ /* Parse options. When successful, this configures the interfaces
+ before returning; to do so, it will acquire the global_lock.
+ (And when not successful, it never returns.) */
argp_parse (&pfinet_argp, argc, argv, 0,0,0);
- /* Talk to parent and link us in. */
task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error (1, 0, "Must be started as a translator");
- err = trivfs_startup (bootstrap, 0,
- trivfs_cntl_portclasses[0], pfinet_bucket,
- trivfs_protid_portclasses[0], pfinet_bucket, 0);
- if (err)
- error (1, errno, "contacting parent");
+ pfinet_owner = pfinet_group = 0;
+
+ if (bootstrap != MACH_PORT_NULL) {
+ /* Create portclass to install on the bootstrap port. */
+ if(trivfs_protid_portclasses[pfinet_bootstrap_portclass]
+ != MACH_PORT_NULL)
+ error(1, 0, "No portclass left to assign to bootstrap port");
+
+#ifdef CONFIG_IPV6
+ if (pfinet_bootstrap_portclass == PORTCLASS_INET6)
+ pfinet_activate_ipv6 ();
+#endif
+
+ trivfs_protid_portclasses[pfinet_bootstrap_portclass] =
+ ports_create_class (trivfs_clean_protid, 0);
+ trivfs_cntl_portclasses[pfinet_bootstrap_portclass] =
+ ports_create_class (trivfs_clean_cntl, 0);
+
+ /* Talk to parent and link us in. */
+ err = trivfs_startup (bootstrap, 0,
+ trivfs_cntl_portclasses[pfinet_bootstrap_portclass],
+ pfinet_bucket, trivfs_protid_portclasses
+ [pfinet_bootstrap_portclass], pfinet_bucket,
+ &pfinetctl);
+
+ if (err)
+ error (1, err, "contacting parent");
+
+ /* Initialize status from underlying node. */
+ err = io_stat (pfinetctl->underlying, &st);
+ if (! err)
+ {
+ pfinet_owner = st.st_uid;
+ pfinet_group = st.st_gid;
+ }
+ }
+ else { /* no bootstrap port. */
+ int i;
+ /* Check that at least one portclass has been bound,
+ error out otherwise. */
+ for (i = 0; i < trivfs_protid_nportclasses; i ++)
+ if (trivfs_protid_portclasses[i] != MACH_PORT_NULL)
+ break;
+
+ if (i == trivfs_protid_nportclasses)
+ error (1, 0, "should be started as a translator.\n");
+ }
+
+ /* Ask init to tell us when the system is going down,
+ so we can try to be friendly to our correspondents on the network. */
+ arrange_shutdown_notification ();
/* Launch */
ports_manage_port_operations_multithread (pfinet_bucket,
pfinet_demuxer,
- 0, 0, 1, 0);
+ 0, 0, 0);
return 0;
}
+#ifdef CONFIG_IPV6
+static void
+pfinet_activate_ipv6 (void)
+{
+ inet6_proto_init (0);
+
+ /* Since we're registering the protocol after the devices have been
+ initialized, we need to care for the linking by ourselves. */
+ struct device *dev = dev_base;
+
+ if (dev)
+ do
+ {
+ if (!(dev->flags & IFF_UP))
+ continue;
+
+ addrconf_notify (NULL, NETDEV_REGISTER, dev);
+ addrconf_notify (NULL, NETDEV_UP, dev);
+ }
+ while ((dev = dev->next));
+}
+#endif /* CONFIG_IPV6 */
+
+void
+pfinet_bind (int portclass, const char *name)
+{
+ struct trivfs_control *cntl;
+ error_t err = 0;
+ mach_port_t right;
+ file_t file = file_name_lookup (name, O_CREAT|O_NOTRANS, 0666);
+
+ if (file == MACH_PORT_NULL)
+ err = errno;
+
+ if (! err) {
+ if (trivfs_protid_portclasses[portclass] != MACH_PORT_NULL)
+ error (1, 0, "Cannot bind one protocol to multiple nodes.\n");
+
+#ifdef CONFIG_IPV6
+ if (portclass == PORTCLASS_INET6)
+ pfinet_activate_ipv6 ();
+#endif
+
+ trivfs_protid_portclasses[portclass] =
+ ports_create_class (trivfs_clean_protid, 0);
+ trivfs_cntl_portclasses[portclass] =
+ ports_create_class (trivfs_clean_cntl, 0);
+
+ err = trivfs_create_control (file, trivfs_cntl_portclasses[portclass],
+ pfinet_bucket,
+ trivfs_protid_portclasses[portclass],
+ pfinet_bucket, &cntl);
+ }
+
+ if (! err)
+ {
+ right = ports_get_send_right (cntl);
+ err = file_set_translator (file, 0, FS_TRANS_EXCL | FS_TRANS_SET,
+ 0, 0, 0, right, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
+ }
+
+ if (err)
+ error (1, err, "%s", name);
+
+ ports_port_deref (cntl);
+
+}
+
+
void
trivfs_modify_stat (struct trivfs_protid *cred,
struct stat *st)
@@ -240,5 +431,30 @@ trivfs_modify_stat (struct trivfs_protid *cred,
error_t
trivfs_goaway (struct trivfs_control *cntl, int flags)
{
- return EBUSY;
+ if (flags & FSYS_GOAWAY_FORCE)
+ exit (0);
+ else
+ {
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]);
+ ports_inhibit_class_rpcs (socketport_class);
+
+ if (ports_count_class (socketport_class) != 0)
+ {
+ /* We won't go away, so start things going again... */
+ ports_enable_class (socketport_class);
+ ports_resume_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_protid_portclasses[0]);
+
+ return EBUSY;
+ }
+
+ /* There are no sockets, so we can die without breaking anybody
+ too badly. We don't let user ports on the /servers/socket/2
+ file keep us alive because those get cached in every process
+ that ever makes a PF_INET socket, libc copes with getting
+ MACH_SEND_INVALID_DEST and looking up the new translator. */
+ exit (0);
+ }
}
diff --git a/pfinet/mapped-time.h b/pfinet/mapped-time.h
index 2877f386..bcbfc6d4 100644
--- a/pfinet/mapped-time.h
+++ b/pfinet/mapped-time.h
@@ -1,6 +1,8 @@
#ifndef _MAPPED_TIME_H_
#define _MAPPED_TIME_H_
+#include <maptime.h>
+
#define HZ 100
extern volatile struct mapped_time_value *mapped_time;
@@ -12,30 +14,15 @@ read_mapped_secs ()
return mapped_time->seconds;
}
-extern inline void
-fill_timeval (struct timeval *tp)
-{
- do
- {
- tp->tv_sec = mapped_time->seconds;
- tp->tv_usec = mapped_time->microseconds;
- }
- while (tp->tv_sec != mapped_time->check_seconds);
-}
-
extern inline int
fetch_jiffies ()
{
- int secs, usecs;
+ struct timeval tv;
long long j;
- do
- {
- secs = mapped_time->seconds;
- usecs = mapped_time->microseconds;
- }
- while (secs != mapped_time->check_seconds);
-
- j = (long long) secs * HZ + ((long long) usecs * HZ) / 1000000;
+
+ maptime_read (mapped_time, &tv);
+
+ j = (long long) tv.tv_sec * HZ + ((long long) tv.tv_usec * HZ) / 1000000;
return j - root_jiffies;
}
diff --git a/pfinet/misc.c b/pfinet/misc.c
index 6eb96b89..08b19e9b 100644
--- a/pfinet/misc.c
+++ b/pfinet/misc.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,2000 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,56 +20,45 @@
#include "pfinet.h"
#include <string.h>
+#include <stddef.h>
+
+#include <linux/socket.h>
+#include <linux/net.h>
-/* Create a sock_user structure, initialized from SOCK and ISROOT.
- If NOINSTALL is set, don't put it in the portset. */
-struct sock_user *
-make_sock_user (struct socket *sock, int isroot, int noinstall)
-{
- struct sock_user *user;
-
- if (noinstall)
- errno = ports_create_port_noinstall (socketport_class, pfinet_bucket,
- sizeof (struct sock_user), &user);
- else
- errno = ports_create_port (socketport_class, pfinet_bucket,
- sizeof (struct sock_user), &user);
- if (errno)
- return 0;
-
- user->isroot = isroot;
- user->sock = sock;
- sock->refcnt++;
- return user;
-}
/* Create a sockaddr port. Fill in *ADDR and *ADDRTYPE accordingly.
- The address should come from SOCK; PEER is 0 if we want this socket's
+ The address should come from SOCK; PEER is 0 if we want this socket's
name and 1 if we want the peer's name. */
error_t
-make_sockaddr_port (struct socket *sock,
+make_sockaddr_port (struct socket *sock,
int peer,
mach_port_t *addr,
mach_msg_type_name_t *addrtype)
{
- char buf[128];
- int buflen = 128;
+ union { struct sockaddr_storage storage; struct sockaddr sa; } buf;
+ int buflen = sizeof buf;
error_t err;
struct sock_addr *addrstruct;
- err = (*sock->ops->getname) (sock, (struct sockaddr *)buf, &buflen, peer);
+ err = (*sock->ops->getname) (sock, &buf.sa, &buflen, peer);
if (err)
- return err;
-
+ return -err;
+
err = ports_create_port (addrport_class, pfinet_bucket,
- sizeof (struct sock_addr) + buflen, &addrstruct);
- if (err)
- return err;
- addrstruct->len = buflen;
- bcopy (buf, addrstruct->address, buflen);
- *addr = ports_get_right (addrstruct);
- *addrtype = MACH_MSG_TYPE_MAKE_SEND;
+ (offsetof (struct sock_addr, address)
+ + buflen), &addrstruct);
+ if (!err)
+ {
+ addrstruct->address.sa_family = buf.sa.sa_family;
+ addrstruct->address.sa_len = buflen;
+ memcpy (addrstruct->address.sa_data, buf.sa.sa_data,
+ buflen - offsetof (struct sockaddr, sa_data));
+ *addr = ports_get_right (addrstruct);
+ *addrtype = MACH_MSG_TYPE_MAKE_SEND;
+ }
+
ports_port_deref (addrstruct);
+
return 0;
}
@@ -104,86 +93,3 @@ void
clean_addrport (void *arg)
{
}
-
-/* Release the reference on the referenced socket. */
-void
-clean_socketport (void *arg)
-{
- struct sock_user *user = arg;
-
- mutex_lock (&global_lock);
-
- user->sock->refcnt--;
- if (user->sock->refcnt == 0)
- sock_release (user->sock);
-
- mutex_unlock (&global_lock);
-}
-
-struct socket *
-sock_alloc (void)
-{
- struct socket *sock;
- struct wait_queue *wait, **waitp;
-
- sock = malloc (sizeof (struct wait_queue)
- + sizeof (struct wait_queue *)
- + sizeof (struct socket));
- wait = (void *)sock + sizeof (struct socket);
- waitp = (void *)wait + sizeof (struct wait_queue);
-
- bzero (sock, sizeof (struct socket));
- sock->identity = MACH_PORT_NULL;
- sock->state = SS_UNCONNECTED;
- sock->wait = waitp;
-
- condition_init (&wait->c);
-
- *waitp = wait;
-
- return sock;
-}
-
-static inline void sock_release_peer(struct socket *peer)
-{
- peer->state = SS_DISCONNECTING;
- wake_up_interruptible(peer->wait);
- sock_wake_async(peer, 1);
-}
-
-void
-sock_release (struct socket *sock)
-{
- int oldstate;
- struct socket *peersock, *nextsock;
-
- if ((oldstate = sock->state) != SS_UNCONNECTED)
- sock->state = SS_DISCONNECTING;
-
- /*
- * Wake up anyone waiting for connections.
- */
-
- for (peersock = sock->iconn; peersock; peersock = nextsock)
- {
- nextsock = peersock->next;
- sock_release_peer(peersock);
- }
-
- /*
- * Wake up anyone we're connected to. First, we release the
- * protocol, to give it a chance to flush data, etc.
- */
-
- peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL;
- if (sock->ops)
- (*sock->ops->release) (sock, peersock);
- if (peersock)
- sock_release_peer(peersock);
-
- if (sock->identity != MACH_PORT_NULL)
- mach_port_destroy (mach_task_self (), sock->identity);
- free (sock);
-}
-
-
diff --git a/pfinet/mutations.h b/pfinet/mutations.h
index 8c0df887..f63ad9b9 100644
--- a/pfinet/mutations.h
+++ b/pfinet/mutations.h
@@ -1,4 +1,4 @@
-/*
+/*
Copyright (C) 1995 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
diff --git a/pfinet/options.c b/pfinet/options.c
index b84230fb..21a35c61 100644
--- a/pfinet/options.c
+++ b/pfinet/options.c
@@ -1,8 +1,8 @@
/* Pfinet option parsing
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2000, 2001, 2006, 2007 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -25,14 +25,41 @@
#include <hurd.h>
#include <argp.h>
#include <argz.h>
+#include <error.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "pfinet.h"
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/ip.h>
+#include <linux/route.h>
+#include <linux/rtnetlink.h>
+#include <net/route.h>
+#include <net/sock.h>
+#include <net/ip_fib.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
/* Our interface to the set of devices. */
extern error_t find_device (char *name, struct device **device);
extern error_t enumerate_devices (error_t (*fun) (struct device *dev));
+
+/* devinet.c */
+extern error_t configure_device (struct device *dev, uint32_t addr,
+ uint32_t netmask, uint32_t peer,
+ uint32_t broadcast);
+extern void inquire_device (struct device *dev, uint32_t *addr,
+ uint32_t *netmask, uint32_t *peer,
+ uint32_t *broadcast);
+
+/* addrconf.c */
+extern struct inet6_dev *ipv6_find_idev (struct device *dev);
+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);
+
/* Pfinet options. Used for both startup and runtime. */
static const struct argp_option options[] =
@@ -41,7 +68,14 @@ static const struct argp_option options[] =
{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"},
+#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"},
+#endif
{"shutdown", 's', 0, 0, "Shut it down"},
{0}
};
@@ -56,8 +90,14 @@ struct parse_interface
/* The network interface in question. */
struct device *device;
- /* New values to apply to it. */
- unsigned long address, netmask, gateway;
+ /* New values to apply to it. (IPv4) */
+ uint32_t address, netmask, peer, gateway;
+
+#ifdef CONFIG_IPV6
+ /* New IPv6 configuration to apply. */
+ struct inet6_ifaddr address6;
+ struct in6_addr gateway6;
+#endif
};
/* Used to hold data during argument parsing. */
@@ -88,9 +128,29 @@ parse_hook_add_interface (struct parse_hook *h)
h->curint->device = 0;
h->curint->address = INADDR_NONE;
h->curint->netmask = INADDR_NONE;
+ h->curint->peer = INADDR_NONE;
h->curint->gateway = INADDR_NONE;
+
+#ifdef CONFIG_IPV6
+ memset (&h->curint->address6, 0, sizeof (struct inet6_ifaddr));
+ memset (&h->curint->gateway6, 0, sizeof (struct in6_addr));
+#endif
+
return 0;
}
+
+#ifdef CONFIG_IPV6
+static struct rt6_info *
+ipv6_get_dflt_router (void)
+{
+ struct in6_addr daddr = { 0 };
+
+ struct fib6_node *fib = fib6_lookup
+ (&ip6_routing_table, &daddr, NULL);
+ return fib->leaf;
+}
+#endif /* CONFIG_IPV6 */
+
static error_t
parse_opt (int opt, char *arg, struct argp_state *state)
@@ -117,6 +177,7 @@ parse_opt (int opt, char *arg, struct argp_state *state)
/* Parse STR and return the corresponding internet address. If STR is not
a valid internet address, signal an error mentioned TYPE. */
+#undef ADDR
#define ADDR(str, type) \
({ unsigned long addr = inet_addr (str); \
if (addr == INADDR_NONE) PERR (EINVAL, "Malformed %s", type); \
@@ -125,6 +186,11 @@ parse_opt (int opt, char *arg, struct argp_state *state)
switch (opt)
{
struct parse_interface *in;
+ uint32_t gateway;
+#ifdef CONFIG_IPV6
+ struct parse_interface *gw6_in;
+ char *ptr;
+#endif
case 'i':
/* An interface. */
@@ -154,25 +220,73 @@ parse_opt (int opt, char *arg, struct argp_state *state)
break;
case 'a':
- h->curint->address = ADDR (arg, "address");
+ 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",
+ FAIL (EINVAL, 1, 0,
+ "%s: Cannot set interface address to multicast address",
arg);
- else
+ else
FAIL (EINVAL, 1, 0,
"%s: Illegal or undefined network address", arg);
}
break;
case 'm':
h->curint->netmask = ADDR (arg, "netmask"); break;
+ case 'p':
+ h->curint->peer = ADDR (arg, "peer"); break;
case 'g':
h->curint->gateway = ADDR (arg, "gateway"); break;
+ case '4':
+ pfinet_bind (PORTCLASS_INET, arg);
+
+ /* Install IPv6 port class on bootstrap port. */
+ pfinet_bootstrap_portclass = PORTCLASS_INET6;
+ break;
+
+#ifdef CONFIG_IPV6
+ case '6':
+ pfinet_bind (PORTCLASS_INET6, arg);
+ break;
+
+ case 'A':
+ 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);
+ }
+
+ 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);
+ break;
+
+ case 'G':
+ 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);
+ break;
+#endif /* CONFIG_IPV6 */
+
case ARGP_KEY_INIT:
/* Initialize our parsing state. */
h = malloc (sizeof (struct parse_hook));
@@ -201,57 +315,171 @@ parse_opt (int opt, char *arg, struct argp_state *state)
if (err)
FAIL (err, 13, 0, "No default interface");
}
-
+#if 0 /* XXX what does this mean??? */
/* Check for bogus option combinations. */
for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
if (in->netmask != INADDR_NONE
&& in->address == INADDR_NONE && in->device->pa_addr == 0)
/* Specifying a netmask for an address-less interface is a no-no. */
FAIL (EDESTADDRREQ, 14, 0, "Cannot set netmask");
+#endif
- /* Successfully finished parsing, return a result. */
+ gateway = INADDR_NONE;
+#ifdef CONFIG_IPV6
+ gw6_in = NULL;
+#endif
for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
{
- struct device *dev = in->device;
- if (in->address != INADDR_NONE || in->netmask != INADDR_NONE)
+ if (in->gateway != INADDR_NONE)
{
- if (dev->pa_addr != 0)
- /* There's already an address, delete the old entry. */
- ip_rt_del (dev->pa_addr & dev->pa_mask, dev);
+ if (gateway != INADDR_NONE)
+ FAIL (err, 15, 0, "Cannot have multiple default gateways");
+ gateway = in->gateway;
+ in->gateway = INADDR_NONE;
+ }
+
+#ifdef CONFIG_IPV6
+ if (!IN6_IS_ADDR_UNSPECIFIED (&in->gateway6))
+ {
+ if (gw6_in != NULL)
+ FAIL (err, 15, 0, "Cannot have multiple IPv6 "
+ "default gateways");
+ gw6_in = in;
+ }
+#endif
+ }
+ /* Successfully finished parsing, return a result. */
+
+ __mutex_lock (&global_lock);
- if (in->address != INADDR_NONE)
- dev->pa_addr = in->address;
+ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
+ {
+#ifdef CONFIG_IPV6
+ struct inet6_dev *idev = NULL;
+ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL
+ && in->device)
+ idev = ipv6_find_idev(in->device);
+#endif
- if (in->netmask != INADDR_NONE)
- dev->pa_mask = in->netmask;
- else
+ if (in->address != INADDR_NONE || in->netmask != INADDR_NONE)
+ {
+ err = configure_device (in->device, in->address, in->netmask,
+ in->peer, INADDR_NONE);
+ if (err)
{
- if (IN_CLASSA (ntohl (dev->pa_addr)))
- dev->pa_mask = htonl (IN_CLASSA_NET);
- else if (IN_CLASSB (ntohl (dev->pa_addr)))
- dev->pa_mask = htonl (IN_CLASSB_NET);
- else if (IN_CLASSC (ntohl (dev->pa_addr)))
- dev->pa_mask = htonl (IN_CLASSC_NET);
- else
- abort ();
+ __mutex_unlock (&global_lock);
+ FAIL (err, 16, 0, "cannot configure interface");
}
+ }
- dev->family = AF_INET;
- dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+#ifdef CONFIG_IPV6
+ if (!idev)
+ 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;
- ip_rt_add (0, dev->pa_addr & dev->pa_mask, dev->pa_mask,
- 0, dev, 0, 0);
+ 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 (in->gateway != INADDR_NONE)
+
+ 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);
+ }
+#endif /* CONFIG_IPV6 */
+ }
+
+ /* Set the default gateway. This code is cobbled together from what
+ the SIOCADDRT ioctl code does, and from the apparent functionality
+ of the "netlink" layer from perusing a little. */
+ {
+ struct kern_rta rta;
+ struct
+ {
+ struct nlmsghdr nlh;
+ struct rtmsg rtm;
+ } req;
+ struct fib_table *tb;
+
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = 0;
+ req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm);
+
+ bzero (&req.rtm, sizeof req.rtm);
+ bzero (&rta, 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)
+ {
+ /* 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;
+ }
+ }
+ else
+ {
+ /* Add a default route, replacing any existing one. */
+ 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);
+ err = (!tb ? ENOBUFS
+ : - (*tb->tb_insert) (tb, &req.rtm, &rta, &req.nlh, 0));
+ if (err)
+ {
+ __mutex_unlock (&global_lock);
+ FAIL (err, 17, 0, "cannot set default gateway");
+ }
+ }
+ }
+
+ /* Set IPv6 default router. */
+#ifdef CONFIG_IPV6
+ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL)
+ {
+ struct rt6_info *rt6i = ipv6_get_dflt_router ();
+
+ if (!gw6_in || rt6i->rt6i_dev != gw6_in->device
+ || !IN6_ARE_ADDR_EQUAL (&rt6i->rt6i_gateway, &gw6_in->gateway6))
{
- ip_rt_del (0, dev);
- ip_rt_add (RTF_GATEWAY, 0, 0, in->gateway, dev, 0, 0);
+ rt6_purge_dflt_routers (0);
+ if (gw6_in)
+ rt6_add_dflt_router (&gw6_in->gateway6, gw6_in->device);
}
}
+#endif
+
+ __mutex_unlock (&global_lock);
+
/* Fall through to free hook. */
case ARGP_KEY_ERROR:
- /* Parsing error occured, free everything. */
+ /* Parsing error occurred, free everything. */
free_hook:
free (h->interfaces);
free (h);
@@ -270,11 +498,16 @@ pfinet_argp = { options, parse_opt, 0, doc };
struct argp *trivfs_runtime_argp = &pfinet_argp;
error_t
-trivfs_get_options (struct trivfs_control *fsys, char **argz, size_t *argz_len)
+trivfs_append_args (struct trivfs_control *fsys, char **argz, size_t *argz_len)
{
error_t add_dev_opts (struct device *dev)
{
error_t err = 0;
+ uint32_t addr, mask, peer, broad;
+ struct rt_key key = { 0 };
+ struct fib_result res;
+
+ inquire_device (dev, &addr, &mask, &peer, &broad);
#define ADD_OPT(fmt, args...) \
do { char buf[100]; \
@@ -287,19 +520,52 @@ trivfs_get_options (struct trivfs_control *fsys, char **argz, size_t *argz_len)
ADD_OPT ("--%s=%s", name, inet_ntoa (i)); } while (0)
ADD_OPT ("--interface=%s", dev->name);
- if (dev->pa_addr != 0)
- ADD_ADDR_OPT ("address", dev->pa_addr);
- if (dev->pa_mask != 0)
- ADD_ADDR_OPT ("netmask", dev->pa_mask);
+ if (addr != INADDR_NONE)
+ ADD_ADDR_OPT ("address", addr);
+ if (mask != INADDR_NONE)
+ 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))
+ ADD_ADDR_OPT ("gateway", FIB_RES_GW (res));
+
+#undef ADD_ADDR_OPT
+
+#ifdef CONFIG_IPV6
+ struct inet6_dev *idev = NULL;
+
+ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL)
+ idev = ipv6_find_idev(dev);
+
+ if (idev)
+ {
+ struct inet6_ifaddr *ifa = idev->addr_list;
+ static char addr_buf[INET6_ADDRSTRLEN];
+
+ /* Push all IPv6 addresses assigned to the interface. */
+ do
+ {
+ inet_ntop (AF_INET6, &ifa->addr, addr_buf, INET6_ADDRSTRLEN);
+ ADD_OPT ("--address6=%s/%d", addr_buf, ifa->prefix_len);
+ }
+ while ((ifa = ifa->if_next));
+
+ /* Last not least push --gateway6 option. */
+ struct rt6_info *rt6i = ipv6_get_dflt_router ();
+ if(rt6i->rt6i_dev == dev)
+ {
+ inet_ntop (AF_INET6, &rt6i->rt6i_gateway, addr_buf,
+ INET6_ADDRSTRLEN);
+ ADD_OPT ("--gateway6=%s", addr_buf);
+ }
+ }
+#endif /* CONFIG_IPV6 */
- /* XXX how do we figure out the default gateway? */
#undef ADD_OPT
return err;
}
- *argz = 0;
- *argz_len = 0;
-
return enumerate_devices (add_dev_opts);
}
diff --git a/pfinet/pfinet-ops.c b/pfinet/pfinet-ops.c
new file mode 100644
index 00000000..8e251020
--- /dev/null
+++ b/pfinet/pfinet-ops.c
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "pfinet.h"
+
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+
+#include "pfinet_S.h"
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <mach/notify.h>
+#include <sys/mman.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+extern int dev_ifconf(char *arg);
+
+/* Return the list of devices in the format provided by SIOCGIFCONF
+ in IFR, but don't return more then AMOUNT bytes. If AMOUNT is
+ negative, there is no limit. */
+error_t
+S_pfinet_siocgifconf (io_t port,
+ vm_size_t amount,
+ char **ifr,
+ mach_msg_type_number_t *len)
+{
+ error_t err = 0;
+ struct ifconf ifc;
+
+ __mutex_lock (&global_lock);
+ if (amount == (vm_size_t) -1)
+ {
+ /* Get the needed buffer length. */
+ ifc.ifc_buf = NULL;
+ ifc.ifc_len = 0;
+ err = dev_ifconf ((char *) &ifc);
+ if (err)
+ {
+ __mutex_unlock (&global_lock);
+ return -err;
+ }
+ amount = ifc.ifc_len;
+ }
+ else
+ ifc.ifc_len = amount;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*len < amount)
+ ifc.ifc_buf = (char *) mmap (0, amount, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ else
+ ifc.ifc_buf = *ifr;
+ err = dev_ifconf ((char *) &ifc);
+ }
+
+ if (err)
+ {
+ *len = 0;
+ if (ifc.ifc_buf != *ifr)
+ munmap (ifc.ifc_buf, amount);
+ }
+ else
+ {
+ *len = ifc.ifc_len;
+ *ifr = ifc.ifc_buf;
+ }
+
+ __mutex_unlock (&global_lock);
+ return err;
+}
diff --git a/pfinet/pfinet.h b/pfinet/pfinet.h
index 966a4e8d..050ba6f7 100644
--- a/pfinet/pfinet.h
+++ b/pfinet/pfinet.h
@@ -1,5 +1,7 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1999, 2000, 2002, 2007
+ Free Software Foundation, Inc.
+
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -23,17 +25,12 @@
#include <device/device.h>
#include <hurd/ports.h>
-#include <linux/netdevice.h>
#include <hurd/trivfs.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
-extern device_t master_device;
-
-void incoming_net_packet (void);
-
-extern struct proto_ops *proto_ops;
-
-struct mutex global_lock;
-struct mutex packet_queue_lock;
+extern struct mutex global_lock;
+extern struct mutex net_bh_lock;
struct port_bucket *pfinet_bucket;
struct port_class *addrport_class;
@@ -41,7 +38,8 @@ struct port_class *socketport_class;
mach_port_t fsys_identity;
-extern struct device ether_dev;
+extern struct device *dev_base;
+extern struct device loopback_dev;
/* A port on SOCK. Multiple sock_user's can point to the same socket. */
struct sock_user
@@ -55,23 +53,35 @@ struct sock_user
struct sock_addr
{
struct port_info pi;
- size_t len;
- struct sockaddr address[0];
+ struct sockaddr address;
};
+/* Trivfs control structure for pfinet. */
+struct trivfs_control *pfinetctl;
+
+/* Owner of the underlying node. */
+uid_t pfinet_owner;
+
+/* Group of the underlying node. */
+uid_t pfinet_group;
+
+void ethernet_initialize (void);
int ethernet_demuxer (mach_msg_header_t *, mach_msg_header_t *);
-void setup_ethernet_device (char *);
-void become_task_protid (struct trivfs_protid *);
-void become_task (struct sock_user *);
-struct sock_user *make_sock_user (struct socket *, int, int);
-error_t make_sockaddr_port (struct socket *, int,
+int ethernet_change_flags (struct device *, short);
+void setup_ethernet_device (char *, struct device **);
+void setup_dummy_device (char *, struct device **);
+void setup_tunnel_device (char *, struct device **);
+struct sock_user *make_sock_user (struct socket *, int, int, int);
+error_t make_sockaddr_port (struct socket *, int,
mach_port_t *, mach_msg_type_name_t *);
void init_devices (void);
+any_t net_bh_worker (any_t);
void init_time (void);
-void inet_proto_init (struct net_proto *);
-void ip_rt_add (short, u_long, u_long, u_long, struct device *,
+void ip_rt_add (short, u_long, u_long, u_long, struct device *,
u_short, u_long);
-int tcp_readable (struct sock *);
+void ip_rt_del (u_long, struct device *);
+struct sock;
+error_t tcp_tiocinq (struct sock *sk, mach_msg_type_number_t *amount);
struct sock_user *begin_using_socket_port (socket_t);
@@ -84,6 +94,23 @@ void clean_socketport (void *);
/* MiG bogosity */
typedef struct sock_user *sock_user_t;
typedef struct sock_addr *sock_addr_t;
-typedef struct trivfs_protid *trivfs_protid_t;
+
+/* pfinet6 port classes. */
+enum {
+ PORTCLASS_INET,
+ PORTCLASS_INET6,
+};
+
+extern struct port_class *trivfs_protid_portclasses[];
+extern int trivfs_protid_nportclasses;
+
+extern struct port_class *trivfs_cntl_portclasses[2];
+extern int trivfs_cntl_nportclasses;
+
+/* Which portclass to install on the bootstrap port. */
+extern int pfinet_bootstrap_portclass;
+
+/* Install portclass on node NAME. */
+void pfinet_bind (int portclass, const char *name);
#endif
diff --git a/pfinet/sched.c b/pfinet/sched.c
index 41059b3f..37e4ecbd 100644
--- a/pfinet/sched.c
+++ b/pfinet/sched.c
@@ -1,6 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/*
+ Copyright (C) 1995,96,2000,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -18,38 +17,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+#include "pfinet.h"
+
#include <asm/system.h>
#include <linux/sched.h>
-#include "pfinet.h"
+#include <linux/interrupt.h>
struct mutex global_lock = MUTEX_INITIALIZER;
-struct mutex packet_queue_lock = MUTEX_INITIALIZER;
+struct mutex net_bh_lock = MUTEX_INITIALIZER;
+struct condition net_bh_wakeup = CONDITION_INITIALIZER;
-struct task_struct current_contents;
-struct task_struct *current = &current_contents;
-
-void
-interruptible_sleep_on (struct wait_queue **p)
-{
- int cancel;
-
- cancel = hurd_condition_wait (&(*p)->c, &global_lock);
- if (cancel)
- current->signal = 1;
-}
-
-void
-wake_up_interruptible (struct wait_queue **p)
-{
- /* tcp.c uses an unitialized wait queue; don't bomb
- if we see it. */
- if (*p)
- condition_broadcast (&(*p)->c);
-}
+struct task_struct current_contents; /* zeros are right default values */
/* Wake up the owner of the SOCK. If HOW is zero, then just
- send SIGIO. If HOW is one, then send SIGIO only if the
+ send SIGIO. If HOW is one, then send SIGIO only if the
SO_WAITDATA flag is off. If HOW is two, then send SIGIO
only if the SO_NOSPACE flag is on, and also clear it. */
int
@@ -60,28 +42,30 @@ sock_wake_async (struct socket *sock, int how)
}
-/* Set the contents of current appropriately for an RPC being undertaken
- by USER. */
-void
-become_task (struct sock_user *user)
-{
- /* These fields are not really used currently. */
- current->pgrp = current->pid = 0;
-
- current->flags = 0;
- current->timeout = 0;
- current->signal = current->blocked = 0;
- current->state = TASK_RUNNING;
- current->isroot = user->isroot;
-}
-
-void
-become_task_protid (struct trivfs_protid *protid)
+/* This function is the "net_bh worker thread".
+ The packet receiver thread calls net/core/dev.c::netif_rx with a packet;
+ netif_rx either drops the packet, or enqueues it and wakes us up
+ via mark_bh which is really condition_broadcast on net_bh_wakeup.
+ The packet receiver thread holds net_bh_lock while calling netif_rx.
+ We wake up and take global_lock, which locks out RPC service threads.
+ We then also take net_bh_lock running net_bh.
+ Thus, only this thread running net_bh locks out the packet receiver
+ thread (which takes only net_bh_lock while calling netif_rx), so packets
+ are quickly moved from the Mach port's message queue to the `backlog'
+ queue, or dropped, without synchronizing with RPC service threads.
+ (The RPC service threads lock out the running of net_bh, but not
+ the queuing/dropping of packets in netif_rx.) */
+any_t
+net_bh_worker (any_t arg)
{
- current->pgrp = current->pid = 0;
- current->flags = 0;
- current->timeout = 0;
- current->signal = current->blocked = 0;
- current->state = TASK_RUNNING;
- current->isroot = protid->isroot;
+ __mutex_lock (&net_bh_lock);
+ while (1)
+ {
+ condition_wait (&net_bh_wakeup, &net_bh_lock);
+ __mutex_lock (&global_lock);
+ net_bh ();
+ __mutex_unlock (&global_lock);
+ }
+ /*NOTREACHED*/
+ return 0;
}
diff --git a/pfinet/socket-ops.c b/pfinet/socket-ops.c
index 691dccfc..b4172dc4 100644
--- a/pfinet/socket-ops.c
+++ b/pfinet/socket-ops.c
@@ -1,5 +1,5 @@
/* Interface functions for the socket.defs interface.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,99,2000,02,07 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,13 +18,22 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+#include <sys/stat.h>
#include <hurd/trivfs.h>
#include <string.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <hurd/fshelp.h>
#include "pfinet.h"
#include "socket_S.h"
-
+#include <linux/sched.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
+
error_t
S_socket_create (struct trivfs_protid *master,
int sock_type,
@@ -35,40 +44,60 @@ S_socket_create (struct trivfs_protid *master,
struct sock_user *user;
struct socket *sock;
error_t err;
-
+ int isroot;
+
if (!master)
return EOPNOTSUPP;
/* Don't allow bogus SOCK_PACKET here. */
- if ((sock_type != SOCK_STREAM
- && sock_type != SOCK_DGRAM
- && sock_type != SOCK_SEQPACKET
- && sock_type != SOCK_RAW)
- || protocol < 0)
- return EINVAL;
-
- mutex_lock (&global_lock);
+ if (sock_type != SOCK_STREAM
+ && sock_type != SOCK_DGRAM
+ && sock_type != SOCK_SEQPACKET
+ && sock_type != SOCK_RAW)
+ return EPROTOTYPE;
+
+ if (protocol < 0)
+ return EPROTONOSUPPORT;
+
+ __mutex_lock (&global_lock);
become_task_protid (master);
sock = sock_alloc ();
-
+
sock->type = sock_type;
- sock->ops = proto_ops;
-
- err = - (*sock->ops->create) (sock, protocol);
+
+ isroot = master->isroot;
+ if (!isroot)
+ {
+ struct stat st;
+
+ /* XXX */
+ st.st_uid = pfinet_owner;
+ st.st_gid = pfinet_group;
+
+ err = fshelp_isowner (&st, master->user);
+ if (! err)
+ isroot = 1;
+ }
+
+ if (master->pi.class == trivfs_protid_portclasses[PORTCLASS_INET])
+ err = - (*net_families[PF_INET]->create) (sock, protocol);
+ else
+ err = - (*net_families[PF_INET6]->create) (sock, protocol);
+
if (err)
sock_release (sock);
else
{
- user = make_sock_user (sock, master->isroot, 0);
+ user = make_sock_user (sock, isroot, 0, 1);
*port = ports_get_right (user);
*porttype = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (user);
}
-
- mutex_unlock (&global_lock);
+
+ __mutex_unlock (&global_lock);
return err;
}
@@ -78,26 +107,17 @@ S_socket_create (struct trivfs_protid *master,
error_t
S_socket_listen (struct sock_user *user, int queue_limit)
{
+ error_t err;
+
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+ __mutex_lock (&global_lock);
become_task (user);
-
- if (user->sock->state == SS_UNCONNECTED)
- {
- if (user->sock->ops && user->sock->ops->listen)
- (*user->sock->ops->listen) (user->sock, queue_limit);
- user->sock->flags |= SO_ACCEPTCON;
- mutex_unlock (&global_lock);
- return 0;
- }
- else
- {
- mutex_unlock (&global_lock);
- return EINVAL;
- }
+ err = - (*user->sock->ops->listen) (user->sock, queue_limit);
+ __mutex_unlock (&global_lock);
+
+ return err;
}
error_t
@@ -113,48 +133,44 @@ S_socket_accept (struct sock_user *user,
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
- become_task (user);
-
sock = user->sock;
- newsock = 0;
- err = 0;
- if ((sock->state != SS_UNCONNECTED)
- || (!(sock->flags & SO_ACCEPTCON)))
- err = EINVAL;
- else if (!(newsock = sock_alloc ()))
+ __mutex_lock (&global_lock);
+
+ become_task (user);
+
+ newsock = sock_alloc ();
+ if (!newsock)
err = ENOMEM;
-
- if (err)
- goto out;
+ else
+ {
+ newsock->type = sock->type;
+
+ err = - (*sock->ops->dup) (newsock, sock);
+ if (!err)
+ err = - (*sock->ops->accept) (sock, newsock, sock->flags);
+
+ if (!err)
+ /* In Linux there is a race here with the socket closing before the
+ ops->getname call we do in make_sockaddr_port. Since we still
+ have the world locked, this shouldn't be an issue for us. */
+ err = make_sockaddr_port (newsock, 1, addr_port, addr_port_type);
+
+ if (!err)
+ {
+ newuser = make_sock_user (newsock, user->isroot, 0, 1);
+ *new_port = ports_get_right (newuser);
+ *new_port_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newuser);
+ }
+
+ if (err)
+ sock_release (newsock);
+ }
+
+ __mutex_unlock (&global_lock);
- newsock->type = sock->type;
- newsock->ops = sock->ops;
-
- err = - (*sock->ops->dup) (newsock, sock);
- if (err)
- goto out;
-
- err = - (*sock->ops->accept) (sock, newsock, sock->userflags);
- if (err)
- goto out;
-
- err = make_sockaddr_port (newsock, 1, addr_port, addr_port_type);
- if (err)
- goto out;
-
- newuser = make_sock_user (newsock, user->isroot, 0);
- *new_port = ports_get_right (newuser);
- *new_port_type = MACH_MSG_TYPE_MAKE_SEND;
- ports_port_deref (newuser);
-
- out:
- if (err && newsock)
- sock_release (newsock);
- mutex_unlock (&global_lock);
return err;
}
@@ -167,29 +183,18 @@ S_socket_connect (struct sock_user *user,
if (!user || !addr)
return EOPNOTSUPP;
-
+
sock = user->sock;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
become_task (user);
- err = 0;
-
- if (sock->state == SS_CONNECTED
- && sock->type != SOCK_DGRAM)
- err = EISCONN;
- else if (sock->state != SS_UNCONNECTED
- && sock->state != SS_CONNECTING
- && sock->state != SS_CONNECTED)
- err = EINVAL;
-
- if (!err)
- err = - (*sock->ops->connect) (sock, addr->address, addr->len,
- sock->userflags);
-
- mutex_unlock (&global_lock);
-
+ err = - (*sock->ops->connect) (sock, &addr->address, addr->address.sa_len,
+ sock->flags);
+
+ __mutex_unlock (&global_lock);
+
/* MiG should do this for us, but it doesn't. */
if (!err)
mach_port_deallocate (mach_task_self (), addr->pi.port_right);
@@ -202,15 +207,18 @@ S_socket_bind (struct sock_user *user,
struct sock_addr *addr)
{
error_t err;
-
+
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+ if (! addr)
+ return EADDRNOTAVAIL;
+
+ __mutex_lock (&global_lock);
become_task (user);
- err = - (*user->sock->ops->bind) (user->sock, addr->address, addr->len);
- mutex_unlock (&global_lock);
-
+ err = - (*user->sock->ops->bind) (user->sock,
+ &addr->address, addr->address.sa_len);
+ __mutex_unlock (&global_lock);
+
/* MiG should do this for us, but it doesn't. */
if (!err)
mach_port_deallocate (mach_task_self (), addr->pi.port_right);
@@ -225,11 +233,11 @@ S_socket_name (struct sock_user *user,
{
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
become_task (user);
make_sockaddr_port (user->sock, 0, addr_port, addr_port_name);
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
return 0;
}
@@ -242,12 +250,12 @@ S_socket_peername (struct sock_user *user,
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
become_task (user);
err = make_sockaddr_port (user->sock, 1, addr_port, addr_port_name);
- mutex_unlock (&global_lock);
-
+ __mutex_unlock (&global_lock);
+
return err;
}
@@ -256,11 +264,11 @@ S_socket_connect2 (struct sock_user *user1,
struct sock_user *user2)
{
error_t err;
-
+
if (!user1 || !user2)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
become_task (user1);
@@ -271,16 +279,8 @@ S_socket_connect2 (struct sock_user *user1,
err = EISCONN;
else
err = - (*user1->sock->ops->socketpair) (user1->sock, user2->sock);
-
- if (!err)
- {
- user1->sock->conn = user2->sock;
- user2->sock->conn = user1->sock;
- user1->sock->state = SS_CONNECTED;
- user2->sock->state = SS_CONNECTED;
- }
-
- mutex_unlock (&global_lock);
+
+ __mutex_unlock (&global_lock);
/* MiG should do this for us, but it doesn't. */
if (!err)
@@ -297,23 +297,31 @@ S_socket_create_address (mach_port_t server,
mach_port_t *addr_port,
mach_msg_type_name_t *addr_port_type)
{
- struct sock_addr *addr;
error_t err;
-
- if (sockaddr_type != AF_INET)
+ struct sock_addr *addrstruct;
+ const struct sockaddr *const sa = (void *) data;
+
+ if (sockaddr_type != AF_INET && sockaddr_type != AF_INET6
+ && sockaddr_type != AF_UNSPEC)
return EAFNOSUPPORT;
-
- err = ports_create_port (addrport_class, pfinet_bucket,
- sizeof (struct sock_addr) + data_len, &addr);
+ if (sa->sa_family != sockaddr_type
+ || data_len < offsetof (struct sockaddr, sa_data))
+ return EINVAL;
+
+ err = ports_create_port (addrport_class, pfinet_bucket,
+ (offsetof (struct sock_addr, address)
+ + data_len), &addrstruct);
if (err)
return err;
-
- addr->len = data_len;
- bcopy (data, addr->address, data_len);
-
- *addr_port = ports_get_right (addr);
+
+ memcpy (&addrstruct->address, data, data_len);
+
+ /* BSD does not require incoming sa_len to be set, so we don't either. */
+ addrstruct->address.sa_len = data_len;
+
+ *addr_port = ports_get_right (addrstruct);
*addr_port_type = MACH_MSG_TYPE_MAKE_SEND;
- ports_port_deref (addr);
+ ports_port_deref (addrstruct);
return 0;
}
@@ -334,12 +342,13 @@ S_socket_whatis_address (struct sock_addr *addr,
{
if (!addr)
return EOPNOTSUPP;
-
- *type = AF_INET;
- if (*datalen < addr->len)
- vm_allocate (mach_task_self (), (vm_address_t *) data, addr->len, 1);
- bcopy (addr->address, *data, addr->len);
- *datalen = addr->len;
+
+ *type = addr->address.sa_family;
+ if (*datalen < addr->address.sa_len)
+ *data = mmap (0, addr->address.sa_len,
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ *datalen = addr->address.sa_len;
+ memcpy (*data, &addr->address, addr->address.sa_len);
return 0;
}
@@ -349,15 +358,15 @@ S_socket_shutdown (struct sock_user *user,
int direction)
{
error_t err;
-
+
if (!user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ __mutex_lock (&global_lock);
become_task (user);
err = - (*user->sock->ops->shutdown) (user->sock, direction);
- mutex_unlock (&global_lock);
-
+ __mutex_unlock (&global_lock);
+
return err;
}
@@ -366,9 +375,28 @@ S_socket_getopt (struct sock_user *user,
int level,
int option,
char **data,
- u_int *datalen)
+ size_t *datalen)
{
- return EOPNOTSUPP;
+ error_t err;
+
+ if (! user)
+ return EOPNOTSUPP;
+
+ __mutex_lock (&global_lock);
+ become_task (user);
+
+ int len = *datalen;
+ err = - (level == SOL_SOCKET ? sock_getsockopt
+ : *user->sock->ops->getsockopt)
+ (user->sock, level, option, *data, &len);
+ *datalen = len;
+
+ __mutex_unlock (&global_lock);
+
+ /* XXX option data not properly typed, needs byte-swapping for netmsgserver.
+ Most options are ints, some like IP_OPTIONS are bytesex-neutral. */
+
+ return err;
}
error_t
@@ -376,20 +404,24 @@ S_socket_setopt (struct sock_user *user,
int level,
int option,
char *data,
- u_int datalen)
+ size_t datalen)
{
error_t err;
if (! user)
return EOPNOTSUPP;
-
- mutex_lock (&global_lock);
+
+ /* XXX option data not properly typed, needs byte-swapping for netmsgserver.
+ Most options are ints, some like IP_OPTIONS are bytesex-neutral. */
+
+ __mutex_lock (&global_lock);
become_task (user);
- err =
- - (user->sock->ops->setsockopt)(user->sock, level, option, data, datalen);
+ err = - (level == SOL_SOCKET ? sock_setsockopt
+ : *user->sock->ops->setsockopt)
+ (user->sock, level, option, data, datalen);
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
return err;
}
@@ -399,38 +431,36 @@ S_socket_send (struct sock_user *user,
struct sock_addr *addr,
int flags,
char *data,
- u_int datalen,
+ size_t datalen,
mach_port_t *ports,
- u_int nports,
+ size_t nports,
char *control,
- u_int controllen,
+ size_t controllen,
mach_msg_type_number_t *amount)
{
int sent;
-
+ struct iovec iov = { data, datalen };
+ struct msghdr m = { msg_name: addr ? &addr->address : 0,
+ msg_namelen: addr ? addr->address.sa_len : 0,
+ msg_flags: flags,
+ msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 };
+
if (!user)
return EOPNOTSUPP;
-
+
/* Don't do this yet, it's too bizarre to think about right now. */
if (nports != 0 || controllen != 0)
return EINVAL;
-
- mutex_lock (&global_lock);
+ __mutex_lock (&global_lock);
become_task (user);
-
- if (addr)
- sent = (*user->sock->ops->sendto) (user->sock, data, datalen,
- user->sock->userflags, flags,
- addr->address, addr->len);
- else
- sent = (*user->sock->ops->send) (user->sock, data, datalen,
- user->sock->userflags, flags);
-
- mutex_unlock (&global_lock);
-
+ if (user->sock->flags & O_NONBLOCK)
+ m.msg_flags |= MSG_DONTWAIT;
+ sent = (*user->sock->ops->sendmsg) (user->sock, &m, datalen, 0);
+ __mutex_unlock (&global_lock);
+
/* MiG should do this for us, but it doesn't. */
- if (sent >= 0)
+ if (addr && sent >= 0)
mach_port_deallocate (mach_task_self (), addr->pi.port_right);
if (sent >= 0)
@@ -448,59 +478,67 @@ S_socket_recv (struct sock_user *user,
mach_msg_type_name_t *addrporttype,
int flags,
char **data,
- u_int *datalen,
+ size_t *datalen,
mach_port_t **ports,
mach_msg_type_name_t *portstype,
- u_int *nports,
+ size_t *nports,
char **control,
- u_int *controllen,
+ size_t *controllen,
int *outflags,
mach_msg_type_number_t amount)
{
- int recvd;
- char addr[128];
- size_t addrlen = sizeof addr;
- int didalloc = 0;
+ error_t err;
+ union { struct sockaddr_storage storage; struct sockaddr sa; } addr;
+ int alloced = 0;
+ struct iovec iov;
+ struct msghdr m = { msg_name: &addr.sa, msg_namelen: sizeof addr,
+ msg_controllen: 0, msg_iov: &iov, msg_iovlen: 1 };
if (!user)
return EOPNOTSUPP;
-
- /* For unused recvmsg interface */
- *nports = 0;
- *portstype = MACH_MSG_TYPE_COPY_SEND;
- *controllen = 0;
- *outflags = 0;
-
- /* Instead of this, we should peek at the socket and only allocate
- as much as necessary. */
- if (*datalen < amount)
+
+ /* Instead of this, we should peek and the socket and only
+ allocate as much as necessary. */
+ if (amount > *datalen)
{
- vm_allocate (mach_task_self (), (vm_address_t *) data, amount, 1);
- didalloc = 1;
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ /* Should check whether errno is indeed ENOMEM --
+ but this can't be done in a straightforward way,
+ because the glue headers #undef errno. */
+ return ENOMEM;
+ alloced = 1;
}
-
- mutex_lock (&global_lock);
- become_task (user);
-
- recvd = (*user->sock->ops->recvfrom) (user->sock, *data, amount, 0, flags,
- (struct sockaddr *)addr, &addrlen);
-
- mutex_unlock (&global_lock);
- if (recvd < 0)
- return (error_t)-recvd;
+ iov.iov_base = *data;
+ iov.iov_len = amount;
- *datalen = recvd;
+ __mutex_lock (&global_lock);
+ become_task (user);
+ if (user->sock->flags & O_NONBLOCK)
+ flags |= MSG_DONTWAIT;
+ err = (*user->sock->ops->recvmsg) (user->sock, &m, amount, flags, 0);
+ __mutex_unlock (&global_lock);
- if (didalloc && round_page (*datalen) < round_page (amount))
- vm_deallocate (mach_task_self (),
- (vm_address_t) (*data + round_page (*datalen)),
- round_page (amount) - round_page (*datalen));
+ if (err < 0)
+ err = -err;
+ else
+ {
+ *datalen = err;
+ if (alloced && round_page (*datalen) < round_page (amount))
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
+ err = S_socket_create_address (0, addr.sa.sa_family,
+ (void *) &addr.sa, m.msg_namelen,
+ addrport, addrporttype);
+ if (err && alloced)
+ munmap (*data, *datalen);
+
+ *outflags = m.msg_flags;
+ *nports = 0;
+ *portstype = MACH_MSG_TYPE_COPY_SEND;
+ *controllen = 0;
+ }
-
- S_socket_create_address (0, AF_INET, addr, addrlen, addrport,
- addrporttype);
-
- return 0;
+ return err;
}
-
diff --git a/pfinet/socket.c b/pfinet/socket.c
index 7cbc0e9f..d56c1794 100644
--- a/pfinet/socket.c
+++ b/pfinet/socket.c
@@ -1,6 +1,5 @@
-/*
- Copyright (C) 1995 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/*
+ Copyright (C) 1995,2000,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -18,18 +17,110 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include <linux/net.h>
#include <assert.h>
#include "pfinet.h"
-struct proto_ops *proto_ops;
+#include <linux/socket.h>
+#include <linux/net.h>
+
+#ifndef NPROTO
+#define NPROTO (PF_INET + 1)
+#endif
+struct net_proto_family *net_families[NPROTO];
/* Notice that a protocol family is live; this only works for inet here. */
int
-sock_register (int family, struct proto_ops *ops)
+sock_register (struct net_proto_family *fam)
{
- assert (family == PF_INET);
- proto_ops = ops;
+ assert (fam->family < NPROTO);
+ net_families[fam->family] = fam;
return 0;
}
+
+struct socket *
+sock_alloc (void)
+{
+ static ino_t nextino; /* locked by global_lock */
+ struct socket *sock;
+ struct condition *c;
+
+ sock = malloc (sizeof *sock + sizeof (struct condition));
+ if (!sock)
+ return 0;
+ c = (void *) &sock[1];
+ condition_init (c);
+ bzero (sock, sizeof *sock);
+ sock->state = SS_UNCONNECTED;
+ sock->identity = MACH_PORT_NULL;
+ sock->refcnt = 1;
+ sock->wait = (void *) c;
+
+ if (nextino == 0)
+ nextino = 2;
+ sock->st_ino = nextino++;
+
+ return sock;
+}
+
+/* Create a sock_user structure, initialized from SOCK and ISROOT.
+ If NOINSTALL is set, don't put it in the portset.
+ We increment SOCK->refcnt iff CONSUME is zero. */
+struct sock_user *
+make_sock_user (struct socket *sock, int isroot, int noinstall, int consume)
+{
+ error_t err;
+ struct sock_user *user;
+
+ assert (sock->refcnt != 0);
+
+ if (noinstall)
+ err = ports_create_port_noinstall (socketport_class, pfinet_bucket,
+ sizeof (struct sock_user), &user);
+ else
+ err = ports_create_port (socketport_class, pfinet_bucket,
+ sizeof (struct sock_user), &user);
+ if (err)
+ return 0;
+
+ /* We maintain a reference count in `struct socket' (a member not
+ in the original Linux structure), because there can be multiple
+ ports (struct sock_user, aka protids) pointing to the same socket.
+ The socket lives until all the ports die. */
+ if (! consume)
+ ++sock->refcnt;
+ user->isroot = isroot;
+ user->sock = sock;
+ return user;
+}
+
+/* This is called from the port cleanup function below, and on
+ a newly allocated socket when something went wrong in its creation. */
+void
+sock_release (struct socket *sock)
+{
+ if (--sock->refcnt != 0)
+ return;
+
+ if (sock->state != SS_UNCONNECTED)
+ sock->state = SS_DISCONNECTING;
+
+ if (sock->ops)
+ sock->ops->release(sock, NULL);
+
+ if (sock->identity != MACH_PORT_NULL)
+ mach_port_destroy (mach_task_self (), sock->identity);
+
+ free (sock);
+}
+
+/* Release the reference on the referenced socket. */
+void
+clean_socketport (void *arg)
+{
+ struct sock_user *const user = arg;
+
+ __mutex_lock (&global_lock);
+ sock_release (user->sock);
+ __mutex_unlock (&global_lock);
+}
diff --git a/pfinet/stubs.c b/pfinet/stubs.c
new file mode 100644
index 00000000..cdb8a6de
--- /dev/null
+++ b/pfinet/stubs.c
@@ -0,0 +1,73 @@
+/* Stub functions replacing things called from the Linux code
+ Copyright (C) 2000,02 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "pfinet.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+
+int qdisc_restart(struct device *dev)
+{
+ return 0;
+}
+
+void qdisc_run_queues(void)
+{
+}
+
+struct Qdisc_head qdisc_head;
+struct Qdisc qdisc_stub;
+
+void
+dev_init_scheduler (struct device *dev)
+{
+ dev->qdisc = &qdisc_stub;
+}
+void dev_shutdown (struct device *)
+ __attribute__ ((alias ("dev_init_scheduler")));
+void dev_activate (struct device *)
+ __attribute__ ((alias ("dev_init_scheduler")));
+void dev_deactivate (struct device *)
+ __attribute__ ((alias ("dev_init_scheduler")));
+void tcp_ioctl () __attribute__ ((alias ("dev_init_scheduler")));
+
+/* This isn't quite a stub, but it's not quite right either. */
+__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
+ __u16 sport, __u16 dport)
+{
+ static u32 tcp_iss;
+ static time_t last;
+ struct timeval now;
+
+ do_gettimeofday (&now);
+
+ if (now.tv_sec - last > 300)
+ {
+ last = now.tv_sec;
+ srandom (getpid () ^ now.tv_sec ^ now.tv_usec);
+ tcp_iss = random ();
+ }
+
+ return tcp_iss + (now.tv_sec * 1000000) + now.tv_usec;
+}
diff --git a/pfinet/timer-emul.c b/pfinet/timer-emul.c
index 6a7ab537..6eb20bc4 100644
--- a/pfinet/timer-emul.c
+++ b/pfinet/timer-emul.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,2000,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@
#include <linux/timer.h>
#include <asm/system.h>
#include <linux/sched.h>
+#include <error.h>
#include <string.h>
#include "pfinet.h"
@@ -40,7 +41,7 @@ timer_function (int this_is_a_pointless_variable_with_a_rather_long_name)
timer_thread = mach_thread_self ();
- mutex_lock (&global_lock);
+ __mutex_lock (&global_lock);
while (1)
{
int jiff = jiffies;
@@ -52,13 +53,13 @@ timer_function (int this_is_a_pointless_variable_with_a_rather_long_name)
else
wait = ((timers->expires - jiff) * 1000) / HZ;
- mutex_unlock (&global_lock);
+ __mutex_unlock (&global_lock);
mach_msg (NULL, (MACH_RCV_MSG | MACH_RCV_INTERRUPT
| (wait == -1 ? 0 : MACH_RCV_TIMEOUT)),
0, 0, recv, wait, MACH_PORT_NULL);
- mutex_lock (&global_lock);
+ __mutex_lock (&global_lock);
while (timers->expires < jiffies)
{
@@ -68,14 +69,16 @@ timer_function (int this_is_a_pointless_variable_with_a_rather_long_name)
timers = timers->next;
if (timers)
- timers->prevp = &timers;
+ timers->prev = &timers;
tp->next = 0;
- tp->prevp = 0;
+ tp->prev = 0;
(*tp->function) (tp->data);
}
}
+
+ return 0;
}
@@ -84,21 +87,19 @@ add_timer (struct timer_list *timer)
{
struct timer_list **tp;
- timer->expires += jiffies;
-
for (tp = &timers; *tp; tp = &(*tp)->next)
if ((*tp)->expires > timer->expires)
{
timer->next = *tp;
- timer->next->prevp = &timer->next;
- timer->prevp = tp;
+ timer->next->prev = &timer->next;
+ timer->prev = tp;
*tp = timer;
break;
}
if (!*tp)
{
timer->next = 0;
- timer->prevp = tp;
+ timer->prev = tp;
*tp = timer;
}
@@ -121,14 +122,14 @@ add_timer (struct timer_list *timer)
int
del_timer (struct timer_list *timer)
{
- if (timer->prevp)
+ if (timer->prev)
{
- *timer->prevp = timer->next;
+ *timer->prev = timer->next;
if (timer->next)
- timer->next->prevp = timer->prevp;
+ timer->next->prev = timer->prev;
timer->next = 0;
- timer->prevp = 0;
+ timer->prev = 0;
return 1;
}
else
@@ -136,6 +137,16 @@ del_timer (struct timer_list *timer)
}
void
+mod_timer (struct timer_list *timer, unsigned long expires)
+{
+ /* Should optimize this. */
+ del_timer (timer);
+ timer->expires = expires;
+ add_timer (timer);
+}
+
+
+void
init_timer (struct timer_list *timer)
{
bzero (timer, sizeof (struct timer_list));
@@ -144,24 +155,17 @@ init_timer (struct timer_list *timer)
void
init_time ()
{
- device_t timedev;
- memory_object_t timeobj;
+ error_t err;
struct timeval tp;
- device_open (master_device, 0, "time", &timedev);
- device_map (timedev, VM_PROT_READ, 0, sizeof (mapped_time_value_t),
- &timeobj, 0);
- vm_map (mach_task_self (), (vm_address_t *)&mapped_time,
- sizeof (mapped_time_value_t), 0, 1, timeobj, 0, 0,
- VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
- mach_port_deallocate (mach_task_self (), timedev);
- mach_port_deallocate (mach_task_self (), timeobj);
+ err = maptime_map (0, 0, &mapped_time);
+ if (err)
+ error (2, err, "cannot map time device");
- fill_timeval (&tp);
+ maptime_read (mapped_time, &tp);
root_jiffies = (long long) tp.tv_sec * HZ
+ ((long long) tp.tv_usec * HZ) / 1000000;
cthread_detach (cthread_fork ((cthread_fn_t) timer_function, 0));
}
-
diff --git a/pfinet/tunnel.c b/pfinet/tunnel.c
new file mode 100644
index 00000000..ec96861a
--- /dev/null
+++ b/pfinet/tunnel.c
@@ -0,0 +1,635 @@
+/*
+ Copyright (C) 1995,96,98,99,2000,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "pfinet.h"
+
+#include <hurd.h>
+#include <cthreads.h>
+#include <fcntl.h>
+#include <device/device.h>
+#include <device/net_status.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <error.h>
+#include <errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+
+struct port_class *tunnel_cntlclass;
+struct port_class *tunnel_class;
+
+struct tunnel_device
+{
+ struct tunnel_device *next;
+ struct trivfs_control *cntl;
+ char *devname;
+ file_t underlying;
+ struct iouser *user;
+ struct sk_buff_head xq; /* Transmit queue. */
+ struct condition wait; /* For read and select. */
+ struct condition select_alert; /* For read and select. */
+ struct mutex lock; /* For read and select. */
+ int read_blocked; /* For read and select. */
+ struct device dev;
+ struct net_device_stats stats;
+};
+
+
+/* Linked list of all tunnel devices. */
+struct tunnel_device *tunnel_dev;
+
+
+struct net_device_stats *
+tunnel_get_stats (struct device *dev)
+{
+ struct tunnel_device *tdev = (struct tunnel_device *) dev->priv;
+
+ assert (tdev);
+
+ return &tdev->stats;
+}
+
+int
+tunnel_stop (struct device *dev)
+{
+ struct tunnel_device *tdev = (struct tunnel_device *) dev->priv;
+ struct sk_buff *skb;
+
+ assert (tdev);
+
+ while ((skb = skb_dequeue (&tdev->xq)) != 0)
+ dev_kfree_skb(skb);
+
+ /* Call those only if removing the device completely. */
+ /* free (tdev->devname); */
+ /* XXX??? mach_port_deallocate (mach_task_self, tdev->underlying) */
+ return 0;
+}
+
+void
+tunnel_set_multi (struct device *dev)
+{
+}
+
+void
+tunnel_initialize (void)
+{
+}
+
+int
+tunnel_open (struct device *dev)
+{
+ struct tunnel_device *tdev = (struct tunnel_device *) dev->priv;
+
+ assert (tdev);
+
+ skb_queue_head_init(&tdev->xq);
+
+ return 0;
+}
+
+/* Transmit an ethernet frame */
+int
+tunnel_xmit (struct sk_buff *skb, struct device *dev)
+{
+ struct tunnel_device *tdev = (struct tunnel_device *) dev->priv;
+
+ assert (tdev);
+
+ __mutex_lock (&tdev->lock);
+
+ /* Avoid unlimited growth. */
+ if (skb_queue_len(&tdev->xq) > 128)
+ {
+ struct sk_buff *skb;
+
+ skb = skb_dequeue(&tdev->xq);
+ dev_kfree_skb(skb);
+ }
+
+ /* Queue it for processing. */
+ skb_queue_tail(&tdev->xq, skb);
+
+ if (tdev->read_blocked)
+ {
+ tdev->read_blocked = 0;
+ condition_broadcast (&tdev->wait);
+ }
+
+ __mutex_unlock (&tdev->lock);
+
+ return 0;
+}
+
+void
+setup_tunnel_device (char *name, struct device **device)
+{
+ error_t err;
+ struct tunnel_device *tdev;
+ struct device *dev;
+
+ /* Do global initialization before setting up first tunnel device. */
+ if (!tunnel_dev)
+ {
+ trivfs_add_control_port_class (&tunnel_cntlclass);
+ trivfs_add_protid_port_class (&tunnel_class);
+ }
+
+ tdev = calloc (1, sizeof (struct tunnel_device));
+ if (!tdev)
+ error (2, ENOMEM, "%s", name);
+ tdev->next = tunnel_dev;
+ tunnel_dev = tdev;
+
+ *device = dev = &tdev->dev;
+
+ dev->name = strdup (name);
+
+ dev->priv = tdev;
+ dev->get_stats = tunnel_get_stats;
+
+ /* Functions. These ones are the true "hardware layer" in Linux. */
+ dev->open = tunnel_open;
+ dev->stop = tunnel_stop;
+ dev->hard_start_xmit = tunnel_xmit;
+ dev->set_multicast_list = tunnel_set_multi;
+
+ /* These are the ones set by drivers/net/ppp_generic.c::ppp_net_init. */
+ dev->hard_header = 0;
+ dev->hard_header_len = 0;
+ dev->mtu = PPP_MTU;
+ dev->addr_len = 0;
+ dev->tx_queue_len = 3;
+ dev->type = ARPHRD_PPP;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+
+ dev_init_buffers (dev);
+
+ /* Setting up the translator at /dev/tunX. */
+ asprintf (&tdev->devname, "/dev/%s", tdev->dev.name);
+ tdev->underlying = file_name_lookup (tdev->devname, O_CREAT|O_NOTRANS, 0664);
+
+ if (tdev->underlying == MACH_PORT_NULL)
+ error (2, /* XXX */ 1, "%s", tdev->dev.name);
+
+ err = trivfs_create_control (tdev->underlying, tunnel_cntlclass,
+ pfinet_bucket, tunnel_class, pfinet_bucket,
+ &tdev->cntl);
+ tdev->cntl->hook = tdev;
+
+ if (! err)
+ {
+ mach_port_t right = ports_get_send_right (tdev->cntl);
+ err = file_set_translator (tdev->underlying, 0, FS_TRANS_EXCL
+ | FS_TRANS_SET, 0, 0, 0, right,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
+ }
+
+ if (err)
+ error (2, err, "%s", tdev->dev.name);
+
+ __mutex_init (&tdev->lock);
+ condition_init (&tdev->wait);
+ condition_init (&tdev->select_alert);
+ condition_implies (&tdev->wait, &tdev->select_alert);
+
+ /* This call adds the device to the `dev_base' chain,
+ initializes its `ifindex' member (which matters!),
+ and tells the protocol stacks about the device. */
+ err = - register_netdevice (dev);
+ assert_perror (err);
+}
+
+/* If a new open with read and/or write permissions is requested,
+ restrict to exclusive usage. */
+static error_t
+check_open_hook (struct trivfs_control *cntl,
+ struct iouser *user,
+ int flags)
+{
+ struct tunnel_device *tdev;
+
+ for (tdev = tunnel_dev; tdev; tdev = tdev->next)
+ if (tdev->cntl == cntl)
+ break;
+
+ if (tdev && flags != O_NORW)
+ {
+ if (tdev->user)
+ return EBUSY;
+ else
+ tdev->user = user;
+ }
+ return 0;
+}
+
+/* When a protid is destroyed, check if it is the current user.
+ If yes, release the interface for other users. */
+static void
+pi_destroy_hook (struct trivfs_protid *cred)
+{
+ struct tunnel_device *tdev;
+
+ if (cred->pi.class != tunnel_class)
+ return;
+
+ tdev = (struct tunnel_device *) cred->po->cntl->hook;
+
+ if (tdev->user == cred->user)
+ tdev->user = 0;
+}
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_check_open_hook)(struct trivfs_control *,
+ struct iouser *, int)
+ = check_open_hook;
+
+/* If this variable is set, it is called every time a protid structure
+ is about to be destroyed. */
+void (*trivfs_protid_destroy_hook) (struct trivfs_protid *) = pi_destroy_hook;
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, size_t amount)
+{
+ struct tunnel_device *tdev;
+ struct sk_buff *skb;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ tdev = (struct tunnel_device *) cred->po->cntl->hook;
+
+ __mutex_lock (&tdev->lock);
+
+ while (skb_queue_len(&tdev->xq) == 0)
+ {
+ if (cred->po->openmodes & O_NONBLOCK)
+ {
+ __mutex_unlock (&tdev->lock);
+ return EWOULDBLOCK;
+ }
+
+ tdev->read_blocked = 1;
+ if (hurd_condition_wait (&tdev->wait, &tdev->lock))
+ {
+ __mutex_unlock (&tdev->lock);
+ return EINTR;
+ }
+ /* See term/users.c for possible race? */
+ }
+
+ skb = skb_dequeue (&tdev->xq);
+ assert(skb);
+
+ if (skb->len < amount)
+ amount = skb->len;
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ {
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ {
+ dev_kfree_skb (skb);
+ __mutex_unlock (&tdev->lock);
+ return ENOMEM;
+ }
+ }
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, skb->data, amount);
+ }
+ *data_len = amount;
+ dev_kfree_skb (skb);
+
+ /* Set atime, see term/users.c */
+
+ __mutex_unlock (&tdev->lock);
+
+ return 0;
+}
+
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they receive more than one write when not prepared for it. */
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ char *data,
+ mach_msg_type_number_t datalen,
+ off_t offset,
+ mach_msg_type_number_t *amount)
+{
+ struct tunnel_device *tdev;
+ struct sk_buff *skb;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_WRITE))
+ return EBADF;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ tdev = (struct tunnel_device *) cred->po->cntl->hook;
+
+ __mutex_lock (&tdev->lock);
+
+ __mutex_lock (&net_bh_lock);
+ skb = alloc_skb (datalen, GFP_ATOMIC);
+ skb->len = datalen;
+ skb->dev = &tdev->dev;
+
+ bcopy (data, skb->data, datalen);
+
+ /* Drop it on the queue. */
+ skb->mac.raw = skb->data;
+ skb->protocol = htons (ETH_P_IP);
+ netif_rx (skb);
+ __mutex_unlock (&net_bh_lock);
+
+ *amount = datalen;
+
+ __mutex_unlock (&tdev->lock);
+ return 0;
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+kern_return_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_msg_type_number_t *amount)
+{
+ struct tunnel_device *tdev;
+ struct sk_buff *skb;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ tdev = (struct tunnel_device *) cred->po->cntl->hook;
+
+ __mutex_lock (&tdev->lock);
+
+ /* XXX: Now return the length of the next entry in the queue.
+ From the BSD manual:
+ The tunnel device, normally /dev/tunN, is exclusive-open (it cannot be
+ opened if it is already open) and is restricted to the super-user. A
+ read() call will return an error (EHOSTDOWN) if the interface is not
+ ``ready'' address has been set (which means that the control device is
+ open and the interface's). Once the interface is ready, read() will re-
+ turn a packet if one is available; if not, it will either block until one
+ is or return EWOULDBLOCK, depending on whether non-blocking I/O has been
+ enabled. If the packet is longer than is allowed for in the buffer
+ passed to read(), the extra data will be silently dropped.
+ */
+
+ skb = skb_dequeue(&tdev->xq);
+ if (skb)
+ {
+ *amount = skb->len;
+ skb_queue_head(&tdev->xq, skb);
+ }
+ else
+ *amount = 0;
+
+ __mutex_unlock (&tdev->lock);
+
+ return 0;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int *type)
+{
+ struct tunnel_device *tdev;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ tdev = (struct tunnel_device *) cred->po->cntl->hook;
+
+ /* We only deal with SELECT_READ here. */
+ *type &= SELECT_READ;
+
+ if (*type == 0)
+ return 0;
+
+ __mutex_lock (&tdev->lock);
+
+ while (1)
+ {
+ if (skb_queue_len (&tdev->xq) != 0)
+ {
+ *type = SELECT_READ;
+ __mutex_unlock (&tdev->lock);
+ return 0;
+ }
+
+ ports_interrupt_self_on_port_death (cred, reply);
+ tdev->read_blocked = 1;
+ if (hurd_condition_wait (&tdev->select_alert, &tdev->lock))
+ {
+ *type = 0;
+ __mutex_unlock (&tdev->lock);
+ return EINTR;
+ }
+ }
+}
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return ESPIPE;
+}
+
+/* Change the size of the file. If the size increases, new blocks are
+ zero-filled. After successful return, it is safe to reference mapped
+ areas of the file up to NEW_SIZE. */
+error_t
+trivfs_S_file_set_size (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return size == 0 ? 0 : EINVAL;
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return 0;
+}
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ *owner = 0;
+ return 0;
+}
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
+
+/* Return objects mapping the data underlying this memory object. If
+ the object can be read then memobjrd will be provided; if the
+ object can be written then memobjwr will be provided. For objects
+ where read data and write data are the same, these objects will be
+ equal, otherwise they will be disjoint. Servers are permitted to
+ implement io_map but not io_map_cntl. Some objects do not provide
+ mapping; they will set none of the ports and return an error. Such
+ objects can still be accessed by io_read and io_write. */
+error_t
+trivfs_S_io_map (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (cred->pi.class != tunnel_class)
+ return EOPNOTSUPP;
+
+ return EINVAL;
+}
diff --git a/pflocal/ChangeLog b/pflocal/ChangeLog
deleted file mode 100644
index 5b2d5b36..00000000
--- a/pflocal/ChangeLog
+++ /dev/null
@@ -1,248 +0,0 @@
-Tue Jul 23 19:44:29 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sock.c (sock_create): Remove NEXT_SOCK_ID.
-
-Sat Jul 13 20:20:55 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io.c (S_io_reauthenticate): Repeat sock_create_port and
- auth_server_authenticate for as long as we get EINTR.
-
-Sun Jul 7 21:30:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io.c (S_io_reauthenticate): Don't use unsafe MOVE_SEND in call
- to auth_server_authenticate.
-
-Mon Jul 1 18:45:35 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sock.c (sock_create): Initialize ID field to MACH_PORT_NULL.
-
-Thu Jun 27 17:58:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (LCLHDRS): Add sserver.h.
-
-Thu Jun 20 16:33:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (pflocal): Depend on ../libfshelp/libfshelp.a.
-
-Wed May 15 20:27:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sock.c (sock_free): Destroy SOCK's id port if necessary.
-
-Tue May 14 14:05:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (S_io_identity): New function.
- * sock.h (struct sock): Make the id field a receive right, not an int.
-
-Thu May 9 20:20:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * io.c (S_io_reauthenticate): Use new auth_server_authenticate
- protocol.
-
-Thu May 9 12:14:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (S_io_select): Remove TAG arg.
-
-Mon Apr 15 12:52:32 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (MIGSFLAGS): Look for mig-mutate.h in $(srcdir).
-
-Fri Jan 26 16:46:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * socket.c (S_socket_recv): Test for MSG_OOB in IN_FLAGS, not FLAGS.
- Return EINVAL if we get MSG_OOB, not EOPNOTSUPP.
-
-Thu Jan 25 17:34:50 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sock.c (sock_create_port, addr_create): Use ports_create_port
- instead of ports_allocate_port.
- * pflocal.c (trivfs_goaway): Handle errors from
- ports_inhibit_bucket_rpcs.
- (thread_cancel): Function deleted.
-
-Tue Jan 23 21:31:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * socket.c (S_socket_connect): Handle connectionless protocols
- correctly.
-
- * socket.c (S_socket_send): Allow DEST_ADDR to be null if the
- socket is connected.
-
- * sock.c (sock_bind): Don't change SOCK's ref count if we're
- returning an error.
-
-Thu Jan 4 15:44:13 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (S_io_select): Reworked to avoid calling
- ports_interrupt_self_on_port_death() if there's data immediately
- available. Also, don't block if we can return EOF/EPIPE.
-
-Thu Dec 28 13:46:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (S_io_select): Use handy macro to avoid unthinkable line break.
-
-Tue Dec 26 17:30:18 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * io.c (S_io_select): Add reply port parameter, and request
- notification if it dies.
- * mig-mutate.h (IO_SELECT_REPLY_PORT): New def.
-
-Mon Nov 13 14:03:03 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * socket.c (S_socket_bind, S_socket_connect): Drop ADDR's send right.
-
-Thu Nov 9 13:18:44 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * socket.c (S_socket_connect): Drop our reference to ADDR.
-
-Sun Nov 5 10:01:15 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pf.c (S_socket_create_address): Removing BINDING argument.
-
- * pflocal.c (main): Add FLAGS argument to trivfs_startup call.
-
-Tue Sep 19 14:07:24 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * io.c (S_io_pathconf): New function.
- (S_io_set_all_openmodes, S_io_set_some_openmodes,
- S_io_clear_some_openmodes): The user specifies O_NONBLOCK, not
- SOCK_NONBLOCK.
- (S_io_get_openmodes): Always return O_APPEND.
-
-Wed Sep 6 11:53:48 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * sserver.c (sock_demuxer): Use ports_interrupt_server and
- ports_notify_server instead of our own version.
- (do_mach_notify_no_senders, do_mach_notify_port_deleted,
- do_mach_notify_msg_accepted, do_mach_notify_port_destroyed,
- do_mach_notify_port_deleted, do_mach_notify_send_once,
- do_mach_notify_dead_name): Functions deleted.
- * io.c (S_interrupt_operation): Function deleted.
- * Makefile (MIGSTUBS): Remove notifyServer.o and interruptServer.o.
-
- * io.c (S_io_read, S_io_readable): Don't return EPIPE on EOF.
-
-Tue Sep 5 14:22:18 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * io.c (S_io_stat): Only attempt to use the read pipe if it exists.
-
-Thu Aug 31 16:31:18 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * io.c (S_io_select): Change the way selects are done, now that
- writes can block.
- (S_io_write): Pass in the new NOBLOCK parameter to pipe_write.
- * socket.c (S_socket_send): Pass in the new NOBLOCK parameter to
- pipe_send.
-
-Tue Aug 29 14:33:14 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * io.c (S_io_select): Use pipe_select instead of pipe_wait.
-
- * connq.c (struct connq): Remove interrupt_seq_num field.
- (connq_listen): Use hurd_condition_wait to detect interrupts
- instead of previous ad-hoc mechanism.
- (connq_interrupt, connq_interrupt_sock): Functions deleted.
- * connq.h (connq_interrupt, connq_interrupt_sock): Decls deleted.
- * io.c (S_interrupt_operation): Use ports_interrupt_rpc to
- interrupt waiting threads.
-
- * sock.c (sock_acquire_read_pipe, sock_acquire_write_pipe):
- `aquire' -> `acquire'.
- * socket.c (S_socket_send, S_socket_recv): Ditto.
- * sock.h: Ditto.
-
-Tue Aug 29 14:30:59 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * io.c (S_io_select): Fix typo in masking off SELECT_URG.
- Don't check open modes and return EBADF.
-
-Thu Aug 24 10:35:58 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (pflocal): Put all dependencies here.
- (OBJS): Remove error.o.
- (HURDLIBS): Removed.
- Removed all rules dealing with error.o.
-
-Mon Aug 21 16:37:32 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pflocal.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
-
-Fri Aug 11 15:33:28 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * sock.h (struct sock): Store the pipe class in a separate field,
- as READ_PIPE is no longer always defined.
- * sock.c (sock_create, sock_connect): Set/use the PIPE_CLASS field.
- (sock_connect, sock_aquire_write_pipe): Use pipe_aquire_writer
- instead of pipe_aquire.
- (sock_aquire_read_pipe): Use pipe_aquire_reader instead of
- pipe_aquire. Handle the case where there is no read pipe (in
- which case return EPIPE).
- (sock_shutdown): Make shutting down the read half just like the
- write half -- the pipe goes away...
- (sock_create): Don't bump the read pipe ref count ourself.
- (sock_free): Use sock_shutdown to trash the read pipe too.
-
- * socket.c
- (S_socket_recv): Use pipe_release_reader instead of pipe_release.
- (S_socket_send): Use pipe_release_writer instead of pipe_release.
- (S_socket_recv): Reflect EPIPE as EOF.
-
- * io.c (S_io_read, S_interrupt_operation, S_io_readable, S_io_select):
- Use pipe_release_reader instead of pipe_release.
- (S_io_write): Use pipe_release_writer instead of pipe_release.
- (S_io_readable, S_io_read): Reflect EPIPE as EOF.
-
-Mon Jul 31 13:59:15 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * connq.c (connq_compress): New function.
- (connq_interrupt_sock): Use connq_compress to compress the queue.
-
-Sun Jul 30 10:30:24 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * connq.c (connq_interrupt_sock): Reset CQ's tail to the end of
- the compressed queue.
-
-Sat Jul 29 00:00:57 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * socket.c (S_socket_send): Only free SOURCE_ADDR if the send
- fails, as otherwise it's consumed; also free all the ports in
- PORTS if the send fails.
-
- * io.c (S_interrupt_operation): Allow socket trying to connect to
- be interrupted.
- * connq.c (connq_interrupt_sock): New function.
- * socket.c (S_socket_connect): Use the CONNECT_QUEUE field to
- allow only a single connection attempt at once.
- Check for already-connected sockets here instead of waiting for
- the final rendezvous.
- * connq.h (connq_interrupt_sock): New declaration.
-
- * connq.c (connq_listen, connq_connect, connq_interrupt,
- connq_set_length): Reverse the roles of the HEAD and TAIL fields,
- and make sure they're used correctly.
- (qprev): Deleted function.
-
- * sock.h (struct sock, all uses changed): Add the CONNECT_QUEUE
- field, and rename the CONNQ field to LISTEN_QUEUE.
- * sock.c (sock_create): Initialize the CONNECT_QUEUE field and
- rename CONNQ to LISTEN_QUEUE.
-
- * connq.c (connq_set_length): When shrinking the queue, actually
- do so, and don't leak memory.
-
- * socket.c (S_socket_connect): Return ECONNREFUSED when trying to
- connect to a non-existant address, instead of EADDRNOTAVAIL.
-
- * connq.c (struct connq): Add the INTERRUPT_SEQ_NUM field, used to
- detect interupts.
- (connq_listen): Detect when we get interrupted, and return EINTR.
- (connq_interrupt): New function.
- * connq.h (connq_interrupt): New declaration.
- * io.c (S_interrupt_operation): Call connq_interrupt when appropiate.
-
- * connq.c (connq_connect): Initialize REQ before using it.
- (connq_request_init): Swap the arguments.
- (connq_listen): Don't lock the accepted request just to get its sock.
-
- * socket.c (S_socket_connect): Actually use the connq operations
- to connect, like the listening socket is expecting, instead of
- connecting directly to it.
diff --git a/pflocal/Makefile b/pflocal/Makefile
index 5ab1a86e..7258e587 100644
--- a/pflocal/Makefile
+++ b/pflocal/Makefile
@@ -1,6 +1,6 @@
# Makefile for pflocal
#
-# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+# Copyright (C) 1995, 1996, 2000 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
@@ -26,9 +26,8 @@ LCLHDRS = connq.h sock.h mig-decls.h mig-mutate.h sserver.h
MIGSTUBS = ioServer.o socketServer.o
OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+HURDLIBS = pipe trivfs iohelp fshelp threads ports ihash shouldbeinlibc
MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
-pflocal: $(OBJS) ../libpipe/libpipe.a ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libthreads/libthreads.a ../libihash/libihash.a ../libshouldbeinlibc/libshouldbeinlibc.a
-
include ../Makeconf
diff --git a/pflocal/connq.c b/pflocal/connq.c
index 5efeb5d2..d4103840 100644
--- a/pflocal/connq.c
+++ b/pflocal/connq.c
@@ -1,8 +1,8 @@
/* Listen queue functions
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,2001 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <cthreads.h>
+#include <assert.h>
#include "connq.h"
@@ -108,6 +109,20 @@ connq_create (struct connq **cq)
*cq = new;
return 0;
}
+
+/* Destroy a queue. */
+void
+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);
+ free (cq);
+}
/* ---------------------------------------------------------------- */
@@ -117,14 +132,17 @@ connq_create (struct connq **cq)
to allow the requesting thread to continue. If NOBLOCK is true,
EWOULDBLOCK is returned when there are no immediate connections
available. */
-error_t
+error_t
connq_listen (struct connq *cq, int noblock,
struct connq_request **req, struct sock **sock)
{
mutex_lock (&cq->lock);
if (noblock && cq->head == cq->tail)
- return EWOULDBLOCK;
+ {
+ mutex_unlock (&cq->lock);
+ return EWOULDBLOCK;
+ }
cq->num_listeners++;
@@ -132,7 +150,7 @@ connq_listen (struct connq *cq, int noblock,
if (hurd_condition_wait (&cq->listeners, &cq->lock))
{
cq->num_listeners--;
- mutex_unlock (&cq->lock);
+ mutex_unlock (&cq->lock);
return EINTR;
}
@@ -149,7 +167,7 @@ connq_listen (struct connq *cq, int noblock,
mutex_unlock (&cq->lock);
- return 0;
+ return 0;
}
/* Return the error code ERR to the thread that made the listen request REQ,
@@ -211,6 +229,7 @@ connq_connect (struct connq *cq, int noblock, struct sock *sock)
return err;
}
+#if 0
/* `Compresses' CQ, by removing any NULL entries. CQ should be locked. */
static void
connq_compress (struct connq *cq)
@@ -231,10 +250,11 @@ connq_compress (struct connq *cq)
/* Move back tail to only include what we kept in the queue. */
cq->tail = comp_tail;
}
+#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. */
-error_t
+error_t
connq_set_length (struct connq *cq, int length)
{
mutex_lock (&cq->lock);
diff --git a/pflocal/connq.h b/pflocal/connq.h
index 8486eb17..1039bff9 100644
--- a/pflocal/connq.h
+++ b/pflocal/connq.h
@@ -33,6 +33,9 @@ struct sock;
is already listening (change this with connq_set_length). */
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
diff --git a/pflocal/io.c b/pflocal/io.c
index 02dfbd40..36221a66 100644
--- a/pflocal/io.c
+++ b/pflocal/io.c
@@ -1,8 +1,9 @@
/* Socket I/O operations
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998, 1999, 2000, 2002, 2007
+ Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,6 +24,7 @@
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <hurd.h> /* for getauth() */
#include <hurd/hurd_types.h>
@@ -104,7 +106,7 @@ S_io_write (struct sock_user *user,
{
err = pipe_write (pipe, user->sock->flags & SOCK_NONBLOCK,
source_addr, data, data_len, amount);
- if (source_addr)
+ if (err && source_addr)
ports_port_deref (source_addr);
}
@@ -117,7 +119,7 @@ S_io_write (struct sock_user *user,
/* Tell how much data can be read from the object without blocking for
a "long time" (this should be the same meaning of "long time" used
by the nonblocking flag. */
-error_t
+error_t
S_io_readable (struct sock_user *user, mach_msg_type_number_t *amount)
{
error_t err;
@@ -196,17 +198,19 @@ S_io_select (struct sock_user *user,
*select_type &= SELECT_READ;
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)
- /* 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);
- }
+ {
+ /* 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)
+ /* 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);
+ }
+ }
}
else
/* Sock is a normal read/write socket. */
@@ -270,10 +274,10 @@ S_io_stat (struct sock_user *user, struct stat *st)
struct sock *sock;
struct pipe *rpipe, *wpipe;
- void copy_time (time_value_t *from, time_t *to_sec, unsigned long *to_usec)
+ void copy_time (time_value_t *from, time_t *to_sec, unsigned long *to_nsec)
{
*to_sec = from->seconds;
- *to_usec = from->microseconds;
+ *to_nsec = from->microseconds * 1000;
}
if (!user)
@@ -284,7 +288,7 @@ S_io_stat (struct sock_user *user, struct stat *st)
bzero (st, sizeof (struct stat));
st->st_fstype = FSTYPE_SOCKET;
- st->st_mode = S_IFSOCK;
+ st->st_mode = sock->mode;
st->st_fsid = getpid ();
st->st_ino = sock->id;
/* As we try to be clever with large transfers, ask for them. */
@@ -298,7 +302,7 @@ S_io_stat (struct sock_user *user, struct stat *st)
if (rpipe)
{
mutex_lock (&rpipe->lock);
- copy_time (&rpipe->read_time, &st->st_atime, &st->st_atime_usec);
+ copy_time (&rpipe->read_time, &st->st_atim.tv_sec, &st->st_atim.tv_nsec);
/* This seems useful. */
st->st_size = pipe_readable (rpipe, 1);
mutex_unlock (&rpipe->lock);
@@ -307,11 +311,11 @@ S_io_stat (struct sock_user *user, struct stat *st)
if (wpipe)
{
mutex_lock (&wpipe->lock);
- copy_time (&wpipe->write_time, &st->st_mtime, &st->st_mtime_usec);
+ copy_time (&wpipe->write_time, &st->st_mtim.tv_sec, &st->st_mtim.tv_nsec);
mutex_unlock (&wpipe->lock);
}
- copy_time (&sock->change_time, &st->st_ctime, &st->st_ctime_usec);
+ copy_time (&sock->change_time, &st->st_ctim.tv_sec, &st->st_ctim.tv_nsec);
mutex_unlock (&sock->lock);
@@ -389,8 +393,8 @@ S_io_reauthenticate (struct sock_user *user, mach_port_t rendezvous)
uid_t *uids = uids_buf, *aux_uids = aux_uids_buf;
gid_t gids_buf[NIDS], aux_gids_buf[NIDS];
gid_t *gids = gids_buf, *aux_gids = aux_gids_buf;
- unsigned num_uids = NIDS, num_aux_uids = NIDS;
- unsigned num_gids = NIDS, num_aux_gids = NIDS;
+ size_t num_uids = NIDS, num_aux_uids = NIDS;
+ size_t num_gids = NIDS, num_aux_gids = NIDS;
if (!user)
return EOPNOTSUPP;
@@ -402,14 +406,14 @@ S_io_reauthenticate (struct sock_user *user, mach_port_t rendezvous)
return err;
auth_server = getauth ();
- err = mach_port_insert_right (mach_task_self (), new_user_port,
+ err = mach_port_insert_right (mach_task_self (), new_user_port,
new_user_port, MACH_MSG_TYPE_MAKE_SEND);
assert_perror (err);
do
err =
- auth_server_authenticate (auth_server,
+ auth_server_authenticate (auth_server,
rendezvous, MACH_MSG_TYPE_COPY_SEND,
- new_user_port, MACH_MSG_TYPE_COPY_SEND,
+ new_user_port, MACH_MSG_TYPE_COPY_SEND,
&uids, &num_uids, &aux_uids, &num_aux_uids,
&gids, &num_gids, &aux_gids, &num_aux_gids);
while (err == EINTR);
@@ -420,7 +424,7 @@ S_io_reauthenticate (struct sock_user *user, mach_port_t rendezvous)
/* Throw away the ids we went through all that trouble to get... */
#define TRASH_IDS(ids, buf, num) \
if (buf != ids) \
- vm_deallocate (mach_task_self (), (vm_address_t)ids, num * sizeof (uid_t));
+ munmap (ids, num * sizeof (uid_t));
TRASH_IDS (uids, uids_buf, num_uids);
TRASH_IDS (gids, gids_buf, num_gids);
@@ -434,8 +438,8 @@ error_t
S_io_restrict_auth (struct sock_user *user,
mach_port_t *new_port,
mach_msg_type_name_t *new_port_type,
- uid_t *uids, unsigned num_uids,
- uid_t *gids, unsigned num_gids)
+ uid_t *uids, size_t num_uids,
+ uid_t *gids, size_t num_gids)
{
if (!user)
return EOPNOTSUPP;
@@ -466,7 +470,7 @@ error_t
S_io_identity (struct sock_user *user,
mach_port_t *id, mach_msg_type_name_t *id_type,
mach_port_t *fsys_id, mach_msg_type_name_t *fsys_id_type,
- int *fileno)
+ ino_t *fileno)
{
static mach_port_t server_id = MACH_PORT_NULL;
error_t err = 0;
@@ -508,10 +512,17 @@ S_io_identity (struct sock_user *user,
return err;
}
+
/* Stubs for currently unsupported rpcs. */
error_t
+S_io_revoke (struct sock_user *user)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
S_io_async(struct sock_user *user,
mach_port_t notify_port,
mach_port_t *async_id_port,
@@ -526,7 +537,7 @@ S_io_mod_owner(struct sock_user *user, pid_t owner)
return EOPNOTSUPP;
}
-error_t
+error_t
S_io_get_owner(struct sock_user *user, pid_t *owner)
{
return EOPNOTSUPP;
diff --git a/pflocal/mig-decls.h b/pflocal/mig-decls.h
index fe4aefdf..983de9d1 100644
--- a/pflocal/mig-decls.h
+++ b/pflocal/mig-decls.h
@@ -1,8 +1,8 @@
/* Type decls for mig-produced server stubs
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995,2001 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -30,26 +30,26 @@
typedef struct sock_user *sock_user_t;
typedef struct addr *addr_t;
-extern inline
-sock_user_t begin_using_sock_user_port(mach_port_t port)
+static inline sock_user_t __attribute__ ((unused))
+begin_using_sock_user_port(mach_port_t port)
{
return (sock_user_t)ports_lookup_port (0, port, sock_user_port_class);
}
-extern inline void
+static inline void __attribute__ ((unused))
end_using_sock_user_port (sock_user_t sock_user)
{
if (sock_user != NULL)
ports_port_deref (sock_user);
}
-extern inline
-addr_t begin_using_addr_port(mach_port_t port)
+static inline addr_t __attribute__ ((unused))
+begin_using_addr_port(mach_port_t port)
{
return (addr_t)ports_lookup_port (0, port, addr_port_class);
}
-extern inline void
+static inline void __attribute__ ((unused))
end_using_addr_port (addr_t addr)
{
if (addr != NULL)
diff --git a/pflocal/pf.c b/pflocal/pf.c
index d404743d..55824d41 100644
--- a/pflocal/pf.c
+++ b/pflocal/pf.c
@@ -1,6 +1,6 @@
/* Protocol family operations
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1999, 2000, 2008 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -18,8 +18,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <stddef.h>
#include <sys/socket.h>
-
#include <hurd/pipe.h>
#include "sock.h"
@@ -36,9 +36,25 @@ S_socket_create (mach_port_t pf,
error_t err;
struct sock *sock;
struct pipe_class *pipe_class;
-
- if (protocol != 0)
- return EPROTONOSUPPORT;
+ mode_t mode;
+
+ /* We have a set of `magic' protocols that allow the user to choose
+ the file type of the socket. The primary application is to make
+ sockets that pretend to be a FIFO, for the implementations of
+ pipes. */
+ switch (protocol)
+ {
+ case 0:
+ mode = S_IFSOCK;
+ break;
+ case S_IFCHR:
+ case S_IFSOCK:
+ case S_IFIFO:
+ mode = protocol;
+ break;
+ default:
+ return EPROTONOSUPPORT;
+ }
switch (sock_type)
{
@@ -49,10 +65,10 @@ S_socket_create (mach_port_t pf,
case SOCK_SEQPACKET:
pipe_class = seqpack_pipe_class; break;
default:
- return ESOCKTNOSUPPORT;
+ return EPROTOTYPE;
}
- err = sock_create (pipe_class, &sock);
+ err = sock_create (pipe_class, mode, &sock);
if (!err)
{
err = sock_create_port (sock, port);
@@ -92,14 +108,33 @@ S_socket_fabricate_address (mach_port_t pf,
*addr_port = ports_get_right (addr);
*addr_port_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (addr);
return 0;
}
+/* Implement socket_whatis_address as described in <hurd/socket.defs>.
+ Since we cannot tell what our address is, return an empty string as
+ the file name. This is primarily for the implementation of accept
+ and recvfrom. The functions getsockname and getpeername remain
+ unsupported for the local namespace. */
error_t
S_socket_whatis_address (struct addr *addr,
int *sockaddr_type,
char **sockaddr, size_t *sockaddr_len)
{
- return EOPNOTSUPP;
+ socklen_t addr_len = (offsetof (struct sockaddr, sa_data) + 1);
+
+ if (! addr)
+ return EOPNOTSUPP;
+
+ *sockaddr_type = AF_LOCAL;
+ if (*sockaddr_len < addr_len)
+ *sockaddr = mmap (0, addr_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ ((struct sockaddr *) *sockaddr)->sa_len = addr_len;
+ ((struct sockaddr *) *sockaddr)->sa_family = *sockaddr_type;
+ ((struct sockaddr *) *sockaddr)->sa_data[0] = 0;
+ *sockaddr_len = addr_len;
+
+ return 0;
}
diff --git a/pflocal/pflocal.c b/pflocal/pflocal.c
index 27148bd6..7a4e8d91 100644
--- a/pflocal/pflocal.c
+++ b/pflocal/pflocal.c
@@ -1,6 +1,6 @@
/* A server for local sockets, of type PF_LOCAL
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -55,7 +55,9 @@ pf_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
return socket_server (inp, outp) || trivfs_demuxer (inp, outp);
}
-void main(int argc, char *argv[])
+
+int
+main(int argc, char *argv[])
{
error_t err;
mach_port_t bootstrap;
@@ -69,7 +71,7 @@ void main(int argc, char *argv[])
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
error(2, 0, "Must be started as a translator");
-
+
pf_port_bucket = ports_create_bucket ();
trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0);
@@ -93,10 +95,10 @@ void main(int argc, char *argv[])
do
ports_manage_port_operations_multithread (pf_port_bucket,
pf_demuxer,
- 30*1000, 5*60*1000, 0, 0);
+ 30*1000, 5*60*1000, 0);
while (sock_global_shutdown () != 0);
- exit(0);
+ return 0;
}
void
diff --git a/pflocal/sock.c b/pflocal/sock.c
index 350c7de8..292e4290 100644
--- a/pflocal/sock.c
+++ b/pflocal/sock.c
@@ -1,8 +1,7 @@
/* Sock functions
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,2000,01,02, 2005 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <string.h> /* For bzero() */
+#include <string.h> /* For memset() */
#include <cthreads.h>
@@ -26,6 +25,7 @@
#include "sock.h"
#include "sserver.h"
+#include "connq.h"
/* ---------------------------------------------------------------- */
@@ -94,7 +94,7 @@ sock_acquire_write_pipe (struct sock *sock, struct pipe **pipe)
/* Return a new socket with the given pipe class in SOCK. */
error_t
-sock_create (struct pipe_class *pipe_class, struct sock **sock)
+sock_create (struct pipe_class *pipe_class, mode_t mode, struct sock **sock)
{
error_t err;
struct sock *new = malloc (sizeof (struct sock));
@@ -116,12 +116,13 @@ sock_create (struct pipe_class *pipe_class, struct sock **sock)
new->refs = 0;
new->flags = 0;
new->write_pipe = NULL;
+ new->mode = mode;
new->id = MACH_PORT_NULL;
new->listen_queue = NULL;
new->connect_queue = NULL;
new->pipe_class = pipe_class;
new->addr = NULL;
- bzero (&new->change_time, sizeof (new->change_time));
+ memset (&new->change_time, 0, sizeof (new->change_time));
mutex_init (&new->lock);
*sock = new;
@@ -135,6 +136,8 @@ sock_free (struct sock *sock)
sock_shutdown (sock, SOCK_SHUTDOWN_READ | SOCK_SHUTDOWN_WRITE);
if (sock->id != MACH_PORT_NULL)
mach_port_destroy (mach_task_self (), sock->id);
+ if (sock->listen_queue)
+ connq_destroy (sock->listen_queue);
free (sock);
}
@@ -155,7 +158,7 @@ _sock_norefs (struct sock *sock)
error_t
sock_clone (struct sock *template, struct sock **sock)
{
- error_t err = sock_create (template->pipe_class, sock);
+ error_t err = sock_create (template->pipe_class, template->mode, sock);
if (err)
return err;
@@ -444,6 +447,8 @@ void
sock_shutdown (struct sock *sock, unsigned flags)
{
unsigned old_flags;
+ struct pipe *read_pipe = NULL;
+ struct pipe *write_pipe = NULL;
mutex_lock (&sock->lock);
@@ -451,36 +456,25 @@ sock_shutdown (struct sock *sock, unsigned flags)
sock->flags |= flags;
if (flags & SOCK_SHUTDOWN_READ && !(old_flags & SOCK_SHUTDOWN_READ))
- /* Shutdown the read half. */
{
- struct pipe *pipe = sock->read_pipe;
- if (pipe != NULL)
- {
- sock->read_pipe = NULL;
- /* Unlock SOCK here, as we may subsequently wake up other threads. */
- mutex_unlock (&sock->lock);
- pipe_remove_reader (pipe);
- }
- else
- mutex_unlock (&sock->lock);
+ /* Shutdown the read half. */
+ read_pipe = sock->read_pipe;
+ sock->read_pipe = NULL;
}
-
if (flags & SOCK_SHUTDOWN_WRITE && !(old_flags & SOCK_SHUTDOWN_WRITE))
- /* Shutdown the write half. */
{
- struct pipe *pipe = sock->write_pipe;
- if (pipe != NULL)
- {
- sock->write_pipe = NULL;
- /* Unlock SOCK here, as we may subsequently wake up other threads. */
- mutex_unlock (&sock->lock);
- pipe_remove_writer (pipe);
- }
- else
- mutex_unlock (&sock->lock);
+ /* Shutdown the write half. */
+ write_pipe = sock->write_pipe;
+ sock->write_pipe = NULL;
}
- else
- mutex_unlock (&sock->lock);
+
+ /* Unlock SOCK here, as we may subsequently wake up other threads. */
+ mutex_unlock (&sock->lock);
+
+ if (read_pipe)
+ pipe_remove_reader (read_pipe);
+ if (write_pipe)
+ pipe_remove_writer (write_pipe);
}
/* ---------------------------------------------------------------- */
diff --git a/pflocal/sock.h b/pflocal/sock.h
index f09e5ca8..6bad8af8 100644
--- a/pflocal/sock.h
+++ b/pflocal/sock.h
@@ -1,8 +1,8 @@
/* Internal sockets
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,99,2000,01 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,13 +23,15 @@
#include <assert.h>
#include <cthreads.h> /* For mutexes */
+#include <sys/mman.h>
+#include <sys/types.h>
#include <hurd/ports.h>
struct pipe;
struct pipe_class;
-/* A port on SOCK. Multiple sock_user's can point to the same socket. */
+/* A port on SOCK. Multiple sock_user's can point to the same socket. */
struct sock_user
{
struct port_info pi;
@@ -59,6 +61,10 @@ struct sock
/* Last time the socket got frobbed. */
time_value_t change_time;
+ /* File mode as reported by stat. Usually this is S_ISOCK, but it
+ should be S_IFIFO for sockets (ab)used in a pipe. */
+ mode_t mode;
+
/* This socket's local address. Note that we don't hold any references on
ADDR, and depend on the addr zeroing our pointer if it goes away (which
is ok, as we can then just make up another address if necessary, and no
@@ -99,7 +105,8 @@ error_t sock_acquire_write_pipe (struct sock *sock, struct pipe **pipe);
error_t sock_connect (struct sock *sock1, struct sock *sock2);
/* Return a new socket with the given pipe class in SOCK. */
-error_t sock_create (struct pipe_class *pipe_class, struct sock **sock);
+error_t sock_create (struct pipe_class *pipe_class, mode_t mode,
+ struct sock **sock);
/* Free SOCK, assuming there are no more handle on it. */
void sock_free (struct sock *sock);
@@ -108,7 +115,7 @@ void sock_free (struct sock *sock);
void _sock_norefs (struct sock *sock);
/* Remove a reference from SOCK, possibly freeing it. */
-extern inline void
+static inline void __attribute__ ((unused))
sock_deref (struct sock *sock)
{
mutex_lock (&sock->lock);
diff --git a/pflocal/socket.c b/pflocal/socket.c
index 0bc72066..2684a723 100644
--- a/pflocal/socket.c
+++ b/pflocal/socket.c
@@ -1,6 +1,6 @@
/* Socket-specific operations
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2008, 2010 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -37,6 +37,8 @@ S_socket_connect2 (struct sock_user *user1, struct sock_user *user2)
return EOPNOTSUPP;
err = sock_connect (user1->sock, user2->sock);
+ if (!err && user1->sock->pipe_class->flags & PIPE_CLASS_CONNECTIONLESS)
+ err = sock_connect (user2->sock, user1->sock);
/* Since USER2 isn't in the receiver position in the rpc, we get a send
right for it (although we only use the receive right with the same
@@ -245,6 +247,7 @@ S_socket_name (struct sock_user *user,
*addr_port = ports_get_right (addr);
*addr_port_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (addr);
return 0;
}
@@ -308,7 +311,7 @@ S_socket_send (struct sock_user *user, struct addr *dest_addr, int flags,
if (dest_sock)
/* Grab the destination socket's read pipe directly, and stuff data
into it. This is not quite the usage sock_acquire_read_pipe was
- intended for, but it will work, as the only inappropiate errors
+ intended for, but it will work, as the only inappropriate errors
occur on a broken pipe, which shouldn't be possible with the sort of
sockets with which we can use socket_send... XXXX */
err = sock_acquire_read_pipe (dest_sock, &pipe);
@@ -322,7 +325,10 @@ S_socket_send (struct sock_user *user, struct addr *dest_addr, int flags,
source_addr, data, data_len,
control, control_len, ports, num_ports,
amount);
- pipe_release_writer (pipe);
+ if (dest_sock)
+ pipe_release_reader (pipe);
+ else
+ pipe_release_writer (pipe);
}
if (err)
@@ -391,7 +397,7 @@ S_socket_recv (struct sock_user *user,
/* Setup mach ports for return. */
{
*addr_type = MACH_MSG_TYPE_MAKE_SEND;
- *ports_type = MACH_MSG_TYPE_MAKE_SEND;
+ *ports_type = MACH_MSG_TYPE_COPY_SEND;
if (source_addr)
{
*addr = ports_get_right (source_addr);
@@ -407,19 +413,58 @@ S_socket_recv (struct sock_user *user,
return err;
}
-/* Stubs for currently unsupported rpcs. */
-
error_t
S_socket_getopt (struct sock_user *user,
int level, int opt,
char **value, size_t *value_len)
{
- return EOPNOTSUPP;
+ int ret = 0;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ mutex_lock (&user->sock->lock);
+ switch (level)
+ {
+ case SOL_SOCKET:
+ switch (opt)
+ {
+ case SO_TYPE:
+ assert (*value_len >= sizeof (int));
+ *(int *)*value = user->sock->pipe_class->sock_type;
+ *value_len = sizeof (int);
+ break;
+ default:
+ ret = ENOPROTOOPT;
+ break;
+ }
+ break;
+ default:
+ ret = ENOPROTOOPT;
+ break;
+ }
+ mutex_unlock (&user->sock->lock);
+
+ return ret;
}
error_t
S_socket_setopt (struct sock_user *user,
int level, int opt, char *value, size_t value_len)
{
- return EOPNOTSUPP;
+ int ret = 0;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ mutex_lock (&user->sock->lock);
+ switch (level)
+ {
+ default:
+ ret = ENOPROTOOPT;
+ break;
+ }
+ mutex_unlock (&user->sock->lock);
+
+ return ret;
}
diff --git a/pflocal/sserver.c b/pflocal/sserver.c
index af0f0c1e..7e00b323 100644
--- a/pflocal/sserver.c
+++ b/pflocal/sserver.c
@@ -1,6 +1,6 @@
/* Server for socket ops
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -52,8 +52,7 @@ handle_sock_requests ()
{
ports_enable_bucket (sock_port_bucket);
ports_manage_port_operations_multithread (sock_port_bucket, sock_demuxer,
- 30*1000, 2*60*1000,
- 1, MACH_PORT_NULL);
+ 30*1000, 2*60*1000, 0);
}
/* The last service thread is about to exist; make this known. */
diff --git a/proc/ChangeLog b/proc/ChangeLog
deleted file mode 100644
index 0b5159c4..00000000
--- a/proc/ChangeLog
+++ /dev/null
@@ -1,867 +0,0 @@
-Sun Jul 28 22:57:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (get_string_array): Correctly adjust NEWSIZE when
- reallocating to add very long strings.
-
-Sat Jul 20 10:08:05 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * msg.c (S_proc_getmsgport): Deal with PID dying while we're waiting.
-
-Fri Jul 19 18:22:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * msg.c (S_proc_setmsgport): Bother to request DEAD_NAME
- notification on new message port being installed.
-
-Thu Jul 18 13:23:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * msg.c (S_proc_setmsgport): Use MOVE_SEND, not COPY_SEND, to
- return the old message port to the caller.
-
- * mgt.c (S_proc_handle_exceptions): Release newly created reference
- on E when we are done with it.
- (S_proc_child): Deallocate our ref on childt once we know we will
- return success.
- (S_proc_reassign): Likewise for NEWT.
-
- * main.c (main): Don't wire proc anymore. It's not necessary or
- useful.
-
-Thu Jul 18 04:15:49 1996 Roland McGrath <roland@baalperazim.frob.com>
-
- * mgt.c (add_tasks): Fix vm_deallocate call to use mach_task_self ()
- instead of mach_host_self ().
-
-Tue Jul 16 11:34:34 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wait.c (EWOULDBLOCK): Define to work around new libc bug.
-
-Sun Jul 7 21:04:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reauthenticate): Don't use unsafe MOVE_SEND in
- user-side interruptible RPC.
-
-Wed Jul 3 14:44:00 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (process_has_exited): When reparenting children to init,
- if one of them is dead, alert init.
-
-Fri Jun 28 11:54:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * proc.h (check_owner): Return true any time PROC1 has root.
-
-Thu May 30 19:11:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pgrp.c (S_proc_getsidport): MAKE_SEND_ONCE -> MAKE_SEND.
-
-Wed May 29 11:35:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Get rid of temp hack for strnlen.
-
-Fri May 24 15:50:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Set PI->exitstatus and PI->sigcode.
-
- * mgt.c (process_has_exited): Don't call alert_parent if P->p_task
- is null (which happens only if this is the stub process in
- proc_reassign). This because the parent is uninvolved in the
- death of stubp.
-
-Wed May 22 17:47:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * stubs.c (send_signal): Send sigcode in message.
-
- * msg.c (S_proc_setmsgport): Add OLDMSGPORT_TYPE param.
-
-Tue May 14 22:50:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * proc.h (check_owner): New inline function.
- * info.c (S_proc_pid2task, S_proc_pid2proc): Use check_owner.
-
-Sun May 12 13:22:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (PI_FETCH_THREAD_DETAILS): New macro.
- (S_proc_getprocinfo): Only allocate thread detail storage if we're
- actually returning thread details (a lone PI_FETCH_THREADS simply
- means "number of threads"). React to errors somewhat more gracefully.
-
- * info.c (S_proc_getprocinfo): Add comment.
-
-Fri May 10 16:32:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (S_proc_get_tty): New function.
-
-Fri May 10 09:26:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (S_proc_exception_raise): Fetch sigcode from correctly
- named member of HSD.
-
-Thu May 9 19:13:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reauthenticate): Use new authentication
- interface.
-
- * mgt.c (S_proc_setowner): Expect and interpret new CLEAR parm.
-
- * info.c (S_proc_getprocinfo): FLAGS is now an in-out parameter.
-
- * proc.h (struct proc): Add p_sigcode.
- * wait.c (S_proc_wait): New parm SIGCODE; return p_sigcode in it.
- (S_proc_mark_stop): New parm SIGCODE; record it.
- (S_proc_mark_exit): Likewise.
- (alert_parent): Set P->p_sigcode if process is dying irregularly.
- * mgt.c (S_proc_exception_raise): Set P->p_sigcode; use new
- _hurd_exception2signal args.
-
-Mon May 6 14:23:11 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * proc.h (OUR_VERSION): Upgrade to 0.0.
-
-Tue Apr 30 16:48:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Release GLOBAL_LOCK around time
- consuming bits, and more importantly, potential calls to P's
- msgport, which can block.
- Fix test when appending to WAITS.
-
-Mon Apr 29 16:58:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Install temporary hack so things at
- least compile. Turned on thread_waits code.
-
-Mon Apr 15 13:51:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (process_has_exited): Clear p->p_waited.
-
-Fri Mar 29 09:38:28 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wait.c (S_proc_wait): When looking for a specific pid, use
- pid_find_allow_zombie, not ordinary pid_find.
-
- * mgt.c (S_proc_reassign): Use new ports_transfer_right call
- instead of claim/install sequence; the latter has leaves the port
- out of any hash table for a time, which produces a race with
- incoming messages.
-
-Thu Mar 28 09:21:16 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reassign): Make send once right directly from
- value in P->p_pi, don't use ports_get_right.
-
- * mgt.c (process_has_exited): Inhibit this call from happening
- twice.
-
- * info.c (S_proc_pid2task): Return MACH_PORT_NULL for a zombie.
- (S_proc_pid2proc): Likewise.
-
- * Makefile (mutated_ourmsg_U.h): New target.
- * mgt.c: Include mutated_ourmsg_U.h instead of ourmsg_U.h.
- * pgrp.c: Likewise.
-
- * wait.c: Don't include ourmsg_U.h or process_reply_U.h.
- * msg.c: Don't include process_reply_U.h.
-
- * msg.c (S_proc_getmsgport): Allow call to be made for dead
- processes; they'll return null. Thank you, Mr. Posix.
- * mgt.c (process_has_exited): Null out P->p_msgport and drop
- reference.
-
- * wait.c (S_proc_wait): Return EOPNOTSUPP if RPC destination is
- not a valid process.
- (S_proc_mark_stop): Likewise.
- (S_proc_mark_exit): Likewise.
- (S_proc_mark_cont): Likewise.
- (S_proc_mark_traced): Likewise.
- (S_proc_mod_stopchild): Likewise.
- * msg.c (S_proc_setmsgport): Likewise.
- (S_proc_getmsgport): Likewise.
- * pgrp.c (S_proc_setsid): Likewise.
- (S_proc_getsidport): Likewise.
- (S_proc_setpgrp): Likewise.
- (S_proc_mark_exec): Likewise.
- * mgt.c (S_proc_reauthenticate): Likewise.
- (S_proc_child): Likewise.
- (S_proc_reassign): Likewise.
- (S_proc_setowner): Likewise.
- (S_proc_getpids): Likewise.
- (S_proc_set_arg_locations): Likewise.
- (S_proc_dostop): Likewise.
- * info.c (S_proc_pid2task): Likewise.
- (S_proc_proc2task): Likewise.
- (S_proc_pid2proc): Likewise.
- (S_proc_make_login_coll): Likewise.
- (S_proc_setlogin): Likewise.
- (S_proc_getlogin): Likewise.
- * host.c (S_proc_sethostid): Likewise.
- (S_proc_sethostname): Likewise.
- (S_proc_getprivports): Likewise.
- (S_proc_setexecdata): Likewise.
-
- * proc.h (process_drop): New (inline) function.
- * hash.c (reqport_find): Only deallocate newly found reference
- if process is dead.
- * Makefile (MIGSTUBS): Delete process_replyUser.c.
- (MIGSFLAGS): Provide new definition.
- * msg.c (S_proc_setmsgport): Spawn thread to tickle init instead
- of sending reply here.
- (tickle_init): New function.
-
-Mon Mar 25 17:02:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (proc): Add libshouldbeinlibc.a.
- * main.c: Include <wire.h>.
- (main): Use wire_task_self instead of doing it ourselves.
-
-Thu Mar 21 11:59:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wait.c (S_proc_wait) [child_ready]: Flip test of waited flag.
- * mgt.c (new_proc): Oops, reinstall code to request dead name
- notification on the task port.
-
-Wed Mar 20 10:41:01 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pgrp.c (S_proc_setpgrp): Delete bletcherous hack from July 22,
- 1995.
-
- -- All these changes get rid of zombies and integrate them
- into the regular process tables. --
- * proc.h (struct zombie): Delete type.
- (zombie_list): Delete variable.
- * hash.c (pid_find): Return 0 if process is dead.
- (task_find): Likewise.
- (task_find_nocreate): Likewise.
- (pidfree): Don't call zombie_check_pid. Call
- pid_find_allow_zombie instead of pid_find.
- (pid_find_allow_zombie): New function.
- (prociterate): Don't call FUN for dead processes.
- * mgt.c (new_proc): Initialize P->p_dead.
- (process_has_exited): Don't call reparent_zombies. Set P->p_dead.
- Don't remove from hash tables here, delete ref to task port or
- remove from parent's list of children (now in
- complete_exit). Don't remove from pgrp here.
- (complete_exit): New function.
- * wait.c (alert_parent): Don't create zombie.
- (reparent_zombies): Delete function.
- (S_proc_wait): Don't scan zombie list; check dead children at the
- same time as stopped children. When completing wait on a dead
- child, call complete_exit after we've finished work.
- (zombie_check_pid): Delete function.
- * proc.h (complete_exit): Provide prototype.
-
- -- All these changes make proc multithreaded
- and use the ports library in the usual fashion
- (well, almost the usual fashion) --
- * Makefile (proc): Mention ../libports/libports.a.
- * hash.c (porthash, exchash): Delete variables.
- (reqport_find): Use ports library instead of porthash.
- (add_proc_to_hash): Don't add to porthash.
- (remove_proc_from_hash): Don't remove from porthash.
- (exc_find, remove_exc_from_hash): Delete functions.
- * mgt.c (new_proc): Allocate new proc structure with
- ports_create_port. Don't frob P->p_reqport.
- (process_has_exited): Don't frob P->p_reqport, cal
- ports_destry_right instead.
- * proc.h (proc_bucket, proc_class): New variables.
- (request_portset): Delete variable.
- * proc.h (struct proc): Delete members `p_reqport' and
- p_porthashloc. Add member `p_pi'.
- * Makefile (MIGSFLAGS): Delete variable.
- * proc.h (global_lock): New variable.
- * main.c (global_lock): Provide definition.
- (message_demuxer): Lock global_lock around work.
- (main): Initialize proc_bucket and proc_class instead of
- request_portset. Initialize generic_port through ports
- library calls. Fetch startup procserver port through ports
- library instead of reading p_reqport. Initialize exc_class.
- * mgt.c (S_proc_reauthenticate) Likewise.
-
- * proc.h: Include <hurd/ports.h> and <cthreads.h>.
- * info.c (S_proc_task2proc): Use ports_get_right instead
- of p_reqport.
- (S_proc_pid2proc): Likewise.
- * proc.h (exc_port_class): New variable.
- (struct exc): Add member `pi'. Remove member `excport'.
- * mgt.c (S_proc_handle_exceptions): Allocate using
- ports library.
- (S_proc_exception_raise): Use ports library to manage
- structure.
- (exc_clean): New function.
-
-
-***
-
- -- All these changes switch to using condition variables
- for wakeup instead of explicit block code --
- * mgt.c (new_proc): Initialize P->p_wakeup.
- * wait.c (waiting_parent_cares): Delete function.
- * Makefile (MIGSTUBS): Delete interruptServer.o.
- * main.c (message_demuxer): Remove call to interrupt_server.
- Add call to ports_interrupt_server.
- * wait.c: Don't include "interrupt_S.h".
- (alent_parent): Unconditionally enqueue zombie.
- (S_interrupt_operation): Delete function.
- (abort_wait): Delete function.
- * msg.c (abort_getmsgport): Delete function.
- * wait.c (alert_parent): Use condition_broadcast instead of
- continuation stuff.
- (reparent_zombies): Likewise.
- (S_proc_mark_stop): Likewise.
- * msg.c (check_message_return): Likewise.
- (check_message_dying): Likewise.
- * wait.c (S_proc_wait): Use condition_wait instead of continuation
- stuff; never return EBUSY.
- * msg.c (S_proc_getmsgport): Likewise.
- * proc.h (struct proc): New member `p_wakeup'. Delete member
- `p_continuation'.
-
-
-
-Mon Feb 12 14:13:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Fail reasonably for #ifdef'd-out
- thread waits code.
-
-Fri Feb 9 15:45:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Support returning wait strings.
-
-Fri Feb 9 15:19:14 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * mgt.c (S_proc_exception_raise): Rewritten.
- (S_proc_handle_exceptions): Don't set E->replyport.
- (S_proc_exception_raise_reply): Function removed.
- * main.c (message_demuxer): Don't call proc_excrepl_server.
- * proc_excrepl.defs: File removed.
- * Makefile (DIST_FILES): Remove proc_excrepl.defs.
- (MIGSTUBS): Remove its objects.
- * proc_exc.defs: Add msgoption arg.
- Use integer_t where appropriate.
- * notify.c (do_mach_notify_no_senders): Don't use E->replyport.
- * proc.h (struct exc): Removed useless members `replyport',
- `replyporttype'.
-
-Wed Dec 20 17:29:13 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reassign): Have notifications sent to the correct
- request port.
- Once we've given STUBP's request port to P, don't leave it in
- STUBP, so process_has_exited() doesn't dealloc it.
-
- * pgrp.c (S_proc_getsidport): Add and use new arg sessport_type.
-
-Wed Dec 20 13:31:01 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (new_proc): Don't set P->p_noowner for processes 0 and 1.
-
-Wed Dec 20 13:09:04 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * info.c (get_vector): Rewritten without arbitrary limits.
-
-Tue Dec 19 18:14:30 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pgrp.c (free_session): Correctly get rid of the receive right
- we're holding.
- (S_proc_getsidport): Return errors.
-
-Tue Dec 19 13:58:59 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * info.c (get_string_array): Fix stupid bug in copying to newly
- allocated space.
-
-Tue Dec 19 13:17:46 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reauthenticate): Reverse miles' last change.
-
-Mon Dec 18 19:56:03 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reauthenticate): Don't return 0 for the new port.
-
-Tue Nov 21 13:50:30 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wait.c (S_interrupt_operation): Include new seqno parameter.
-
-Tue Nov 14 13:15:55 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wait.c (S_proc_wait): `p->msgportwait' ==> `p->p_msgportwait'
- typo fix.
-
-Thu Nov 9 13:01:28 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * msg.c (S_proc_setmsgport): Only do the RPC reply by hand for
- init. Also, return the correct port in that by-hand reply.
-
- * msg.c (S_proc_getmsgport): Also return EBUSY if P->waiting,
- because both share the same memory in the proc structure.
- * wait.c (S_proc_wait): Likewise, mutatis mutandis.
-
-Wed Nov 8 13:10:27 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Don't attempt msg_report_wait if
- P->p_msgport is not valid.
-
- * info.c (S_proc_getprocinfo): Inhibit PI_FETCH_THREAD_WAITS for
- now.
-
-Tue Nov 7 19:49:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Calculate the size of the returned
- structure correctly.
-
-Sun Nov 5 02:05:10 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * proc.h: Include <sys/resource.h>.
-
- * info.c (S_proc_getprocinfo): Add NOISE and NOISE_LEN args.
- Fix various typos. Initialize ERR.
-
-Tue Oct 31 14:19:04 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * wait.c (struct zombie): Deleted; now in proc.h.
- (zombie_list): Likewise.
- * proc.h (struct zombie): New type.
- (zombie_list): New variable.
-
- * info.c (S_proc_getprocinfo): Implement all the rest of the PI
- flags except PI_ZOMBIE.
-
-Mon Oct 30 16:22:49 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): Support new FETCH flags; support
- new msg_report_wait call; improve organization.
-
- * info.c (S_proc_getprocenv): Removed #ifdef notyet; fixed args to
- get_string_array.
-
-Sat Sep 16 12:57:31 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ourmsg.defs: New file.
- * Makefile (DIST_FILES): Added ourmsg.defs.
- (ourmsg_U.h ourmsgUser.c, ourmsg.defs): Targets removed.
-
-Thu Aug 24 10:38:58 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (MIGSTUBS): New variable.
- (OBJS): Get the mig stubs from $(MIGSTUBS).
-
-Wed Aug 23 14:25:30 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (proc): Put all dependencies here.
- (HURDLIBS, REMHDRS): Removed.
- (OBJS): Calculate the appropiate bits from $(SRCS).
-
-Sat Jul 22 15:04:52 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * wait.c (zombie_check_pid): Examine Z->pgrp too.
-
- * pgrp.c (S_proc_setpgrp): Install bletcherous hack.
-
-Thu Jul 6 15:41:22 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * hash.c: "ihash.h" -> <hurd/ihash.h>.
-
- * Makefile (ourmsg_U.h ourmsgUser.c): Use local ourmsg.defs
- instead of include file directly.
- (ourmsg.defs): New target.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Tue Jun 27 12:02:47 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * mgt.c (S_proc_dostop): Remove assigments from inside if tests.
-
-Tue Jun 6 13:24:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Removed ihash.o and primes.o.
- (CPPFLAGS): Deleted addition of -I../lib.
- (vpath): Deleted spec.
- (REMHDRS): Added ../libihash/ihash.h.
- (HURDLIBS): Added libihash.
-
-Wed Apr 26 14:32:19 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * wait.c (S_proc_wait): Use `waiter_cares', not
- `waiting_parent_cares' in zombie check.
-
-Tue Apr 18 09:30:13 1995 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * wait.c (reparent_zombies): Send SIGCHLD signal to init.
-
- * wait.c (S_proc_wait): Don't return ESRCH; return ECHILD.
-
-Wed Apr 12 14:36:30 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Omit primes.c (it's moved to the lib dir).
-
-Thu Apr 6 14:29:06 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * info.c (S_proc_getprocinfo): New var `tp'. Bother to set
- PI->logincollection.
-
-Wed Apr 5 20:32:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * wait.c (waiter_cares, waiting_parent_cares): New functions.
- (alert_parent, reparent_zombies, S_proc_wait, S_proc_mark_stop):
- Use them.
-
-Tue Apr 4 14:36:36 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * main.c (main): Wire text and data segment on startup to avoid
- failure mode during non-standalone pseudo-crash.
-
-Tue Mar 14 11:55:00 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * hash.c (addhash, findhash): Moved to ihash.c (which is has a more
- generic interface) and renamed ihash_add & ihash_find; all callers
- changed. Other changes: struct htable becomes struct ihash, and
- all routines that previously deleted things explicitly use
- ihash_locp_remove instead.
-
-Thu Jan 19 02:01:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * pgrp.c (S_proc_setpgrp): Use nowait_msg_proc_newids instead of
- nowait_proc_newids.
- * mgt.c (S_proc_child): Likewise.
-
-Tue Jan 17 17:48:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * mgt.c (check_uid): Return true if P has root.
-
- * proc.h (struct proc): Make `argv' and `envp' members
- `vm_address_t'.
-
-Thu Nov 3 12:13:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * mgt.c (S_proc_getallpids): Don't dereference PIDS in call
- to vm_allocate.
-
- * info.c (S_proc_getprocinfo): Don't take address of PIARRAY
- in call to vm_allocate. Dereference PIARRAY in call to
- vm_deallocate.
-
-Fri Oct 14 04:54:46 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * mgt.c (new_proc): Don't assume MACH_PORT_NULL is zero.
- (genpid): Deal with all pids between STAR_OVER and WRAP_AROUND
- being used.
-
-Mon Oct 10 14:23:00 1994 Jim Blandy <jimb@geech.gnu.ai.mit.edu>
-
- * primes.c (nextprime): Doc fix.
-
-Mon Oct 10 02:18:02 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * host.c (rebuild_uname): If all the server versions after [0]
- (the microkernel) match, merge them all into one "Hurd-VERSION"
- element in the uname version string.
-
-Sun Oct 2 20:36:57 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * host.c (S_proc_sethostname): Don't write off end of
- uname_info.nodename.
- (rebuild_uname): Rewritten.
- (initialize_version_info): Write Mach version info as first
- element of server_versions.
- (machversion): Variable removed.
-
-Sat Sep 10 11:37:32 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * mgt.c (make_ids): Copy from UIDS and GIDS into newly allocated
- space, not vice versa.
-
-Wed Aug 31 11:03:13 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reassign): Rather than getting a new request port,
- preserve STUBP's request port. This is more convenient for
- users (and equally good security), and it's what the protocol spec
- says anyway.
-
-Tue Aug 30 12:44:37 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * primes.c: Replaced file with new version from Jim Blandy
- (jimb@gnu.ai.mit.edu), David Carlton (carlton@math.mit.edu).
-
- * proc.h (check_dead_execdata_notify): Add prototype.
-
-Mon Aug 29 12:53:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reauthenticate): Use new authentication protocol.
-
-Tue Aug 23 11:41:26 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * pgrp.c (S_proc_setpgrp): If we don't actually change the pgrp,
- still send proc_newids; the library depends on always getting it.
-
-Mon Aug 22 17:09:21 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * wait.c (S_proc_mark_stop): Removed now meaningless assert.
-
- * info.c (S_proc_getloginpids): Compute size in realloc correctly.
-
-Mon Aug 22 13:29:21 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * wait.c (S_proc_mod_stopchild): Negate VALUE; sense of
- p_nostopcld flag is opposite of flag value described in process.defs.
-
-Fri Aug 19 10:21:57 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * pgrp.c (S_proc_getpgrppids): Understand PGID of zero as meaning
- caller's pgrp.
-
- * mgt.c (S_proc_child): Check CHILDP->p_msgport against
- MACH_PORT_NULL explicitly.
-
- * pgrp.c (join_pgrp): If pg->pg_orphcnt has significantly changed,
- then notify all the processes in the pgrp.
- (leave_pgrp): Only send newids message if ip->p_msgport is set.
- * mgt.c (S_proc_child): Becase join_pgrp now always sends
- newids; don't do it here if we called join_pgrp.
-
-Fri Aug 19 04:53:04 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * pgrp.c (leave_pgrp): Fix swapped args to nowait_proc_newids.
- (join_pgrp): Call nowait_proc_newids to notify the process.
-
-Thu Aug 18 10:40:13 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * mgt.c (S_proc_reauthenticate): Use MACH_MSG_TYPE_MAKE_SEND
- to create a send right from P->p_reqport.
-
- * main.c (main): Removed var `authhandle'. Use global
- `authserver' instead.
-
-Wed Aug 17 14:02:31 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * host.c (init_stdarrays): Removed function.
- (S_proc_execdata_notify): Never call init_stdarrays.
- Only call exec_setexecdata if std_port_array is set.
- (S_proc_getexecdata): Return error if there is no std_port_array.
-
-Mon Aug 15 16:12:22 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * host.c (check_dead_execdata_notify): New function.
- * notify.c (do_mach_notify_dead_name): For notifications sent
- to GENERIC_PORT, call check_dead_execdata_notify.
- * main.c (main): Create GENERIC_PORT and put it in
- REQUEST_PORTSET.
-
- * host.c (init_stdarrays): New function.
- (S_proc_execdata_notify): Call init_stdarrays the first time.
- (S_proc_getexecdata): Likewise.
-
- * host.c: Include <hurd.h> for various frobs. Include
- <unistd.h> for getpid.
-
-Fri Jul 22 11:01:53 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
- * wait.c: Include "ourmsg_U.h" instead of "msg.h".
- Include "process_reply_U.h" instead of "process_reply.h".
- Include "process_S.h" instead of "proc_S.h".
- * mgt.c: Include "proc_exc_U.h" instead of "proc_exc.h".
- Include "proc_excrepl_U.h" insted of "proc_excrepl.h".
- Include "ourmsg_U.h" instead of "msg.h".
- Include "process_S.h" instead of "proc_S.h".
- * pgrp.c: Include "process_S.h" instead of "proc_S.h".
- Include "ourmsg_U.h" instead of "msg.h".
- * msg.c: Include "process_reply_U.h" instead of "process_reply.h".
- * host.c: Include "process_S.h" instead of "proc_S.h".
- * info.c: Likewise.
-
-Wed Jul 20 16:18:31 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * wait.c (alert_parent): Delete unused variable `err'.
-
-Tue Jul 19 12:45:43 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (proc): Don't use variable $(link) anymore.
-
-Mon Jul 11 14:32:17 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * pgrp.c (leave_pgrp): When pulling process off of pgrp list,
- mutate *both* links.
- (free_pgrp): When pulling pgrp off of session list, mutate
- *both* links.
-
-Tue Jul 5 14:23:21 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (TAGSLIBS, TAGSHDRS): New variables.
-
-Fri Jul 1 10:57:07 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * stubs.c (send_signal): Rewrote to be machine independent
- and cleaner.
-
-Thu Jun 30 14:05:21 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * stubs.c: New file.
- * wait.c (alert_parent): Call send_signal instead of nowait_sig_post.
- (S_proc_mark_stop): Likewise.
- * pgrp.c (leave_pgrp): Likewise.
- * proc.h (send_signal): New prototype.
- * Makefile (OBJS): Added stubs.o.
- (SRCS): Added stubs.c.
- (LIBS): New var to get cthreads library.
-
- * wait.c (alert_parent): Eliminate pointless assert with confusingly
- incorrect comment.
-
- * hash.c (findhash): If we find a slot with ID matching the
- one we're looking for, but it has been deleted, then return
- 0 rather than HASH_DEL.
-
- * wait.c (S_proc_wait, reparent_zombies, alert_parent): Use
- macros WAIT_ANY and WAIT_MYPGRP instead of magic values -1
- and 0.
-
- * wait.c (S_proc_wait): Implement correct interpretation of PID
- argument: -1 means any child; 0 means child in the same pgrp.
- [Incorrect semantics were in loop to search zombies, and loop
- looking for stopped children]
- (reparent_zombies): Likewise. [Incorrect semantics were in
- PID check before returning startup_proc's wait.]
- (alert_parent): Likewise. [Incorrect semantics were in
- PID check before returning P->p_parent's wait.]
-
- * wait.c (S_proc_wait): Only return wait on stopped child if
- it passes the PID test.
-
- * pgrp.c (S_proc_setpgrp): Don't do process group change if we are
- changing into our own process group.
- * mgt.c (S_proc_child): Likewise.
-
- * pgrp.c (S_proc_setpgrp): When PID is zero, act on calling
- process; when PGID is zero, use pid of affected process.
- (S_proc_setpgrp): EPERM check should succeed if pgid is the
- affected process's *pid*, not pgrp.
-
-Thu Jun 30 08:40:35 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * mgt.c (S_proc_dostop): Use the proper allocation for task_threads.
- Check for errors. Deallocate the send right from CONTTHREAD too.
-
- * wait.c (alert_parent): Send SIGCHLD to the parent.
-
-Tue Jun 28 18:12:43 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * primes.c: Include <assert.h>.
- (nextprime): Use calloc instead of alloca, bzero. P might be
- bigger than will fit on the stack. Assert non-null return
- from calloc and realloc.
-
-Tue Jun 28 13:57:08 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * main.c (main): Set priority of proc server to 2 so that we
- get more CPU than ordinary programs.
-
-Fri Jun 24 17:29:55 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * hash.c (struct htable): New member `locps'.
- (addhash): Store LOCP into hash table for use during rehash.
- During rehash, then provide correct LOCP parm for old elements.
- Allocate and free HT->locps as appropriate.
-
-Fri Jun 24 04:15:16 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * mgt.c (S_proc_setprocargs): Renamed to S_proc_set_arg_locations.
- (S_proc_get_arg_locations): New function.
-
-Mon Jun 20 15:07:00 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (install): Use $(INSTALL_BIN) instead of cp.
-
-Fri Jun 17 13:00:27 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * mgt.c (S_proc_child): Reverse Roland's change of June 11.
-
-Sat Jun 11 11:20:16 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * mgt.c (S_proc_child): Inherit the argv and envp values from the
- parent.
-
-Fri May 27 16:03:53 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * primes.c: Doc fix, with appreciation to Jim Blandy.
-
-Fri May 13 16:58:13 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * info.c (S_proc_getprocinfo): Only scan through the threads
- if task_info succeeds.
-
- * info.c (S_proc_getprocinfo): Behave properly if one of the
- threads has died in between the call to task_threads and the
- calls to thread_info (just pretend it never existed).
-
- * info.c (get_string, get_vector, S_proc_getprocinfo): If the task
- has died (there's a race between pending requests and processing
- of dead-name notifications) then convert MACH_SEND_INVALID_DEST to
- ESRCH.
-
-Thu May 12 00:59:03 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * main.c (main): Take three args. Store ARGV and ENVP in SELF_PROC.
-
- * info.c (S_proc_getprocargs): Remove `#ifdef notyet's.
- (get_string, get_vector, get_string_array): Functions exposed.
- (get_string_array): Set BP before the loop. Use a for loop that
- iterates over elts in VECTOR. Fix check of LEN to reallocate buffer.
- (S_proc_getprocargs): Cast BUF to vm_address_t * for get_string_array.
- (get_vector): Fix pointer arithmetic; break out of loop when done.
- Check for error from malloc.
- (get_string): Use memchr for scanning. Check for error from
- malloc. Pass READLEN correctly to vm_deallocate.
-
- * msg.c (S_proc_setmsgport): Take new reply port args.
- Send reply before trying startup_essential_task.
- Include <hurd/startup.h> to declare startup_essential_task.
-
- * cpu-types.c: New file.
- * Makefile (SRCS, OBJS): Add it.
- * host.c: Include <stdio.h> for sprintf.
- (rebuild_uname): Removed unused variable J.
- (S_proc_register_version): Fix arg types.
- Use master_host_port, not host_priv.
- Remove unused variable J.
- (server_versions): Fix syntax errors in struct definition.
- (S_proc_uname): Fixed type of first arg.
- (rebuild_uname): Fix typo.
- (initialize_version_info): Cast args to host_info.
- (initialize_version_info): Allocate space for machversion.
-
-Mon May 9 14:32:37 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * mgt.c (new_proc): Regard init as having a dead message
- port initially.
-
- * msg.c (S_proc_setmsgport): When init chimes in, tell it
- we are essential.
-
- * proc.h (OUR_VERSION, OUR_SERVER_NAME): New macros.
- * host.c (uname_info, machversion, server_versions,
- nserver_versions, server_version_nalloc): New variables.
- (S_proc_register_version, rebuild_uname, initialize_version_info,
- S_proc_uname): New functions.
- (S_proc_sethostname): Also set uname_info.nodename.
- * main.c (main): Call initialize_version_info.
-
-Fri May 6 13:00:36 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * host.c (S_proc_gethostname): If HOSTNAME is null, return
- an empty hostname instead of crashing.
- (S_proc_gethostname): Test buffer length properly; allocate
- space for the null too.
-
- * mgt.c (process_has_exited): delete unused variable LAST.
- * msg.c (check_message_return): delete unused variables I,
- MSGPORTS, and CP. Changed type of second arg to `void *'
- so that the function type is appropriate for the first arg
- to prociterate.
- (check_message_dying): delete unused variable I.
-
- * wait.c, host.c, info.c, mgt.c, notify.c, pgrp.c: Changed MiG
- server stubs' return types from error_t to kern_return_t; the
- types are incompatible right now.
-
-Thu May 5 07:50:24 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile: Change uses of $(headers) to $(includedir).
-
diff --git a/proc/Makefile b/proc/Makefile
index b666c4f7..a1159700 100644
--- a/proc/Makefile
+++ b/proc/Makefile
@@ -31,9 +31,7 @@ MIGSFLAGS="-DPROCESS_INTRAN=pstruct_t reqport_find (process_t)" \
MIGSTUBS = processServer.o notifyServer.o \
ourmsgUser.o proc_excUser.o proc_excServer.o
OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
-
-proc: $(OBJS) ../libthreads/libthreads.a ../libihash/libihash.a \
- ../libports/libports.a ../libshouldbeinlibc/libshouldbeinlibc.a
+HURDLIBS=threads ihash ports shouldbeinlibc
include ../Makeconf
diff --git a/proc/cpu-types.c b/proc/cpu-types.c
index f15387c7..7bcaa928 100644
--- a/proc/cpu-types.c
+++ b/proc/cpu-types.c
@@ -21,6 +21,18 @@ const char *const mach_cpu_types[] =
[CPU_TYPE_SPARC] = "sparc",
[CPU_TYPE_I860] = "i860",
[CPU_TYPE_ALPHA] = "alpha",
+#ifdef CPU_TYPE_I486
+ [CPU_TYPE_I486] = "i486",
+#endif
+#ifdef CPU_TYPE_PENTIUM
+ [CPU_TYPE_PENTIUM] = "i586",
+#endif
+#ifdef CPU_TYPE_PENTIUMPRO
+ [CPU_TYPE_PENTIUMPRO] = "i686",
+#endif
+#ifdef CPU_TYPE_POWERPC
+ [CPU_TYPE_POWERPC] = "powerpc",
+#endif
};
const char *const mach_cpu_subtypes[][32] =
@@ -67,14 +79,24 @@ const char *const mach_cpu_subtypes[][32] =
[CPU_SUBTYPE_MMAX_XPC] = "MMAX_XPC",
[CPU_SUBTYPE_PC532] = "PC532",
},
- [CPU_TYPE_I386] =
- {
- [CPU_SUBTYPE_AT386] = "AT386",
- [CPU_SUBTYPE_EXL] = "EXL",
- [CPU_SUBTYPE_iPSC386] = "iPSC386",
- [CPU_SUBTYPE_SYMMETRY] = "SYMMETRY",
- [CPU_SUBTYPE_PS2] = "PS2",
- },
+#define Ix86_SUBTYPES \
+ { \
+ [CPU_SUBTYPE_AT386] = "AT386", \
+ [CPU_SUBTYPE_EXL] = "EXL", \
+ [CPU_SUBTYPE_iPSC386] = "iPSC386", \
+ [CPU_SUBTYPE_SYMMETRY] = "SYMMETRY", \
+ [CPU_SUBTYPE_PS2] = "PS2", \
+ }
+ [CPU_TYPE_I386] = Ix86_SUBTYPES,
+#ifdef CPU_TYPE_I486
+ [CPU_TYPE_I486] = Ix86_SUBTYPES,
+#endif
+#ifdef CPU_TYPE_PENTIUM
+ [CPU_TYPE_PENTIUM] = Ix86_SUBTYPES,
+#endif
+#ifdef CPU_TYPE_PENTIUMPRO
+ [CPU_TYPE_PENTIUMPRO] = Ix86_SUBTYPES,
+#endif
[CPU_TYPE_MIPS] =
{
[CPU_SUBTYPE_MIPS_R2300] = "R2300",
diff --git a/proc/hash.c b/proc/hash.c
index 85eb7c5d..ed670a16 100644
--- a/proc/hash.c
+++ b/proc/hash.c
@@ -1,5 +1,5 @@
/* Hash table functions
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation
This file is part of the GNU Hurd.
@@ -20,6 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Michael I. Bushnell. */
#include <mach.h>
+#include <stddef.h>
#include <sys/types.h>
#include <hurd/hurd_types.h>
#include <string.h>
@@ -29,15 +30,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "proc.h"
#include <hurd/ihash.h>
-static struct ihash pghash, pidhash, taskhash, sidhash;
+static struct hurd_ihash pghash
+ = HURD_IHASH_INITIALIZER (offsetof (struct pgrp, pg_hashloc));
+static struct hurd_ihash pidhash
+ = HURD_IHASH_INITIALIZER (offsetof (struct proc, p_pidhashloc));
+static struct hurd_ihash taskhash
+ = HURD_IHASH_INITIALIZER (offsetof (struct proc, p_taskhashloc));
+static struct hurd_ihash sidhash
+ = HURD_IHASH_INITIALIZER (offsetof (struct session, s_hashloc));
+
/* Find the process corresponding to a given pid. */
struct proc *
pid_find (pid_t pid)
{
struct proc *p;
- p = ihash_find (&pidhash, pid);
- return p->p_dead ? 0 : p;
+ p = hurd_ihash_find (&pidhash, pid);
+ return (!p || p->p_dead) ? 0 : p;
}
/* Find the process corresponding to a given pid. Return it even if
@@ -45,7 +54,7 @@ pid_find (pid_t pid)
struct proc *
pid_find_allow_zombie (pid_t pid)
{
- return ihash_find (&pidhash, pid);
+ return hurd_ihash_find (&pidhash, pid);
}
/* Find the process corresponding to a given task. */
@@ -53,8 +62,8 @@ struct proc *
task_find (task_t task)
{
struct proc *p;
- p = ihash_find (&taskhash, task) ? : add_tasks (task);
- return p->p_dead ? 0 : p;
+ p = hurd_ihash_find (&taskhash, task) ? : add_tasks (task);
+ return (!p || p->p_dead) ? 0 : p;
}
/* Find the process corresponding to a given task, but
@@ -63,8 +72,8 @@ struct proc *
task_find_nocreate (task_t task)
{
struct proc *p;
- p = ihash_find (&taskhash, task);
- return p->p_dead ? 0 : p;
+ p = hurd_ihash_find (&taskhash, task);
+ return (!p || p->p_dead) ? 0 : p;
}
/* Find the process corresponding to a given request port. */
@@ -75,65 +84,65 @@ reqport_find (mach_port_t reqport)
p = ports_lookup_port (proc_bucket, reqport, proc_class);
if (p && p->p_dead)
ports_port_deref (p);
- return p->p_dead ? 0 : p;
+ return (!p || p->p_dead) ? 0 : p;
}
/* Find the process group corresponding to a given pgid. */
struct pgrp *
pgrp_find (pid_t pgid)
{
- return ihash_find (&pghash, pgid);
+ return hurd_ihash_find (&pghash, pgid);
}
/* Find the session corresponding to a given sid. */
struct session *
session_find (pid_t sid)
{
- return ihash_find (&sidhash, sid);
+ return hurd_ihash_find (&sidhash, sid);
}
/* Add a new process to the various hash tables. */
void
add_proc_to_hash (struct proc *p)
{
- ihash_add (&pidhash, p->p_pid, p, &p->p_pidhashloc);
- ihash_add (&taskhash, p->p_task, p, &p->p_taskhashloc);
+ hurd_ihash_add (&pidhash, p->p_pid, p);
+ hurd_ihash_add (&taskhash, p->p_task, p);
}
/* Add a new process group to the various hash tables. */
void
add_pgrp_to_hash (struct pgrp *pg)
{
- ihash_add (&pghash, pg->pg_pgid, pg, &pg->pg_hashloc);
+ hurd_ihash_add (&pghash, pg->pg_pgid, pg);
}
/* Add a new session to the various hash tables. */
void
add_session_to_hash (struct session *s)
{
- ihash_add (&sidhash, s->s_sid, s, &s->s_hashloc);
+ hurd_ihash_add (&sidhash, s->s_sid, s);
}
/* Remove a process group from the various hash tables. */
void
remove_pgrp_from_hash (struct pgrp *pg)
{
- ihash_locp_remove(0, pg->pg_hashloc);
+ hurd_ihash_locp_remove (&pghash, pg->pg_hashloc);
}
/* Remove a process from the various hash tables. */
void
remove_proc_from_hash (struct proc *p)
{
- ihash_locp_remove(0, p->p_pidhashloc);
- ihash_locp_remove(0, p->p_taskhashloc);
+ hurd_ihash_locp_remove (&pidhash, p->p_pidhashloc);
+ hurd_ihash_locp_remove (&taskhash, p->p_taskhashloc);
}
/* Remove a session from the various hash tables. */
void
remove_session_from_hash (struct session *s)
{
- ihash_locp_remove(0, s->s_hashloc);
+ hurd_ihash_locp_remove (&sidhash, s->s_hashloc);
}
/* Call function FUN of two args for each process. FUN's first arg is
@@ -141,14 +150,12 @@ remove_session_from_hash (struct session *s)
void
prociterate (void (*fun) (struct proc *, void *), void *arg)
{
- error_t thunk(void *value)
+ HURD_IHASH_ITERATE (&pidhash, value)
{
struct proc *p = value;
if (!p->p_dead)
(*fun)(p, arg);
- return 0;
}
- ihash_iterate(&pidhash, thunk);
}
/* Tell if a pid is available for use */
diff --git a/proc/host.c b/proc/host.c
index 3b1e03c8..2b3c4f3c 100644
--- a/proc/host.c
+++ b/proc/host.c
@@ -1,5 +1,5 @@
/* Proc server host management calls
- Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,96,97,2001,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -31,13 +31,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/exec.h>
#include <unistd.h>
#include <assert.h>
+#include <version.h>
+#include <sys/mman.h>
#include "proc.h"
#include "process_S.h"
-static long hostid;
-static char *hostname;
-static int hostnamelen;
static mach_port_t *std_port_array;
static int *std_int_array;
static int n_std_ports, n_std_ints;
@@ -47,93 +46,17 @@ struct server_version
{
char *name;
char *version;
- char *release;
} *server_versions;
int nserver_versions, server_versions_nalloc;
-struct execdata_notify
+struct execdata_notify
{
mach_port_t notify_port;
struct execdata_notify *next;
} *execdata_notifys;
-/* Implement proc_sethostid as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_sethostid (struct proc *p,
- int newhostid)
-{
- if (!p)
- return EOPNOTSUPP;
-
- if (! check_uid (p, 0))
- return EPERM;
-
- hostid = newhostid;
-
- return 0;
-}
-
-/* Implement proc_gethostid as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_gethostid (struct proc *p,
- int *outhostid)
-{
- /* No need to check P here; we don't use it. */
- *outhostid = hostid;
- return 0;
-}
-/* Implement proc_sethostname as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_sethostname (struct proc *p,
- char *newhostname,
- u_int newhostnamelen)
-{
- int len;
- if (!p)
- return EOPNOTSUPP;
-
- if (! check_uid (p, 0))
- return EPERM;
-
- if (hostname)
- free (hostname);
-
- hostname = malloc (newhostnamelen + 1);
- hostnamelen = newhostnamelen;
-
- bcopy (newhostname, hostname, newhostnamelen);
- hostname[newhostnamelen] = '\0';
-
- len = newhostnamelen + 1;
- if (len > sizeof uname_info.nodename)
- len = sizeof uname_info.nodename;
- bcopy (hostname, uname_info.nodename, len);
- uname_info.nodename[sizeof uname_info.nodename - 1] = '\0';
-
- return 0;
-}
-
-/* Implement proc_gethostname as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_gethostname (struct proc *p,
- char **outhostname,
- u_int *outhostnamelen)
-{
- /* No need to check P here; we don't use it. */
-
- if (*outhostnamelen < hostnamelen + 1)
- vm_allocate (mach_task_self (), (vm_address_t *)outhostname,
- hostnamelen + 1, 1);
- *outhostnamelen = hostnamelen + 1;
- if (hostname)
- bcopy (hostname, *outhostname, hostnamelen + 1);
- else
- **outhostname = '\0';
- return 0;
-}
-
-/* Implement proc_getprivports as described in <hurd/proc.defs>. */
+/* Implement proc_getprivports as described in <hurd/process.defs>. */
kern_return_t
S_proc_getprivports (struct proc *p,
mach_port_t *hostpriv,
@@ -141,33 +64,47 @@ S_proc_getprivports (struct proc *p,
{
if (!p)
return EOPNOTSUPP;
-
+
if (! check_uid (p, 0))
return EPERM;
-
+
*hostpriv = master_host_port;
*devpriv = master_device_port;
return 0;
}
-/* Implement proc_setexecdata as described in <hurd/proc.defs>. */
+/* Implement proc_setexecdata as described in <hurd/process.defs>. */
kern_return_t
S_proc_setexecdata (struct proc *p,
mach_port_t *ports,
- u_int nports,
+ size_t nports,
int *ints,
- u_int nints)
+ size_t nints)
{
int i;
struct execdata_notify *n;
-
+ mach_port_t *std_port_array_new;
+ int *std_int_array_new;
+
if (!p)
return EOPNOTSUPP;
-
+
if (!check_uid (p, 0))
return EPERM;
-
+
+ /* Allocate memory up front. */
+ std_port_array_new = malloc (sizeof (mach_port_t) * nports);
+ if (! std_port_array_new)
+ return ENOMEM;
+
+ std_int_array_new = malloc (sizeof (int) * nints);
+ if (! std_int_array_new)
+ {
+ free (std_port_array_new);
+ return ENOMEM;
+ }
+
if (std_port_array)
{
for (i = 0; i < n_std_ports; i++)
@@ -176,75 +113,98 @@ S_proc_setexecdata (struct proc *p,
}
if (std_int_array)
free (std_int_array);
-
- std_port_array = malloc (sizeof (mach_port_t) * nports);
+
+ std_port_array = std_port_array_new;
n_std_ports = nports;
- bcopy (ports, std_port_array, sizeof (mach_port_t) * nports);
-
- std_int_array = malloc (sizeof (int) * nints);
+ memcpy (std_port_array, ports, sizeof (mach_port_t) * nports);
+
+ std_int_array = std_int_array_new;
n_std_ints = nints;
- bcopy (ints, std_int_array, sizeof (int) * nints);
-
+ memcpy (std_int_array, ints, sizeof (int) * nints);
+
for (n = execdata_notifys; n; n = n->next)
exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
n_std_ports, std_int_array, n_std_ints);
-
+
return 0;
}
-/* Implement proc_getexecdata as described in <hurd/proc.defs>. */
-kern_return_t
+/* Implement proc_getexecdata as described in <hurd/process.defs>. */
+kern_return_t
S_proc_getexecdata (struct proc *p,
mach_port_t **ports,
mach_msg_type_name_t *portspoly,
- u_int *nports,
+ size_t *nports,
int **ints,
- u_int *nints)
+ size_t *nints)
{
+ int i;
+ int ports_allocated = 0;
/* No need to check P here; we don't use it. */
- /* XXX memory leak here */
-
if (!std_port_array)
return ENOENT;
if (*nports < n_std_ports)
- *ports = malloc (n_std_ports * sizeof (mach_port_t));
- bcopy (std_port_array, *ports, n_std_ports * sizeof (mach_port_t));
+ {
+ *ports = mmap (0, round_page (n_std_ports * sizeof (mach_port_t)),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*ports == MAP_FAILED)
+ return ENOMEM;
+ ports_allocated = 1;
+ }
+ memcpy (*ports, std_port_array, n_std_ports * sizeof (mach_port_t));
*nports = n_std_ports;
-
+
if (*nints < n_std_ints)
- *ints = malloc (n_std_ints * sizeof (mach_port_t));
- bcopy (std_int_array, *ints, n_std_ints * sizeof (int));
+ {
+ *ints = mmap (0, round_page (n_std_ints * sizeof (int)),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*ints == MAP_FAILED)
+ {
+ if (ports_allocated)
+ munmap (*ports, round_page (n_std_ports * sizeof (mach_port_t)));
+ return ENOMEM;
+ }
+ }
+ memcpy (*ints, std_int_array, n_std_ints * sizeof (int));
*nints = n_std_ints;
+ for (i = 0; i < n_std_ports; i++)
+ mach_port_mod_refs (mach_task_self (), std_port_array[i], MACH_PORT_RIGHT_SEND, 1);
+ *portspoly = MACH_MSG_TYPE_MOVE_SEND;
+
return 0;
}
-/* Implement proc_execdata_notify as described in <hurd/proc.defs>. */
+/* Implement proc_execdata_notify as described in <hurd/process.defs>. */
kern_return_t
S_proc_execdata_notify (struct proc *p,
mach_port_t notify)
{
- struct execdata_notify *n = malloc (sizeof (struct execdata_notify));
+ struct execdata_notify *n;
mach_port_t foo;
/* No need to check P here; we don't use it. */
+ n = malloc (sizeof (struct execdata_notify));
+ if (! n)
+ return ENOMEM;
+
n->notify_port = notify;
n->next = execdata_notifys;
execdata_notifys = n;
- mach_port_request_notification (mach_task_self (), notify,
+ mach_port_request_notification (mach_task_self (), notify,
MACH_NOTIFY_DEAD_NAME, 1,
generic_port, MACH_MSG_TYPE_MAKE_SEND_ONCE,
&foo);
if (foo)
mach_port_deallocate (mach_task_self (), foo);
-
+
if (std_port_array)
- exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
+ exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
n_std_ports, std_int_array, n_std_ints);
return 0;
}
@@ -255,7 +215,7 @@ void
check_dead_execdata_notify (mach_port_t port)
{
struct execdata_notify *en, **prevp;
-
+
for (en = execdata_notifys, prevp = &execdata_notifys; en; en = *prevp)
{
if (en->notify_port == port)
@@ -271,14 +231,17 @@ check_dead_execdata_notify (mach_port_t port)
/* Version information handling.
- A server registers its name, release, and version with
- startup_register_version. The uname version string is composed of all
- the server names and versions. The uname release is composed of the
- differing server releases in order of decreasing popularity (just one if
- they all agree).
+ A server registers its name and version with
+ startup_register_version.
+
+ The uname release is the most popular version number.
+
+ The uname version string is composed of all the server names and
+ versions, omitting special mention of those which match the uname
+ release, plus the kernel version string. */
+
+char *kernel_name, *kernel_version;
- The Hurd release comes from <hurd/hurd_types.h> and
- is compiled into proc as well as the other servers. */
/* Rebuild the uname version string. */
static void
@@ -314,72 +277,58 @@ rebuild_uname (void)
*p++ = '/';
}
- /* Collect all the differing release strings and count how many
+ /* Collect all the differing version strings and count how many
servers use each. */
- struct release
+ struct version
{
- const char *release;
+ const char *version;
unsigned int count;
- } releases[nserver_versions];
- int compare_releases (const void *a, const void *b)
+ } versions[nserver_versions];
+ int compare_versions (const void *a, const void *b)
{
- return (((const struct release *) b)->count -
- ((const struct release *) a)->count);
+ return (((const struct version *) b)->count -
+ ((const struct version *) a)->count);
}
- unsigned int nreleases = 0;
+ unsigned int nversions = 0;
for (i = 0; i < nserver_versions; ++i)
{
- for (j = 0; j < nreleases; ++j)
- if (! strcmp (releases[j].release, server_versions[i].release))
+ for (j = 0; j < nversions; ++j)
+ if (! strcmp (versions[j].version, server_versions[i].version))
{
- ++releases[j].count;
+ ++versions[j].count;
break;
}
- if (j == nreleases)
+ if (j == nversions)
{
- releases[nreleases].release = server_versions[i].release;
- releases[nreleases].count = 1;
- ++nreleases;
+ versions[nversions].version = server_versions[i].version;
+ versions[nversions].count = 1;
+ ++nversions;
}
}
- /* Sort the releases in order of decreasing popularity. */
- qsort (releases, nreleases, sizeof (struct release), compare_releases);
+ /* Sort the versions in order of decreasing popularity. */
+ qsort (versions, nversions, sizeof (struct version), compare_versions);
/* Now build the uname strings. */
- initstr (uname_info.release);
- for (i = 0; i < nreleases; ++i)
- addstr (NULL, releases[i].release);
+ /* release is the most popular version */
+ strcpy (uname_info.release, versions[0].version);
- if (p > end)
-#ifdef notyet
- syslog (LOG_EMERG,
- "_UTSNAME_LENGTH %u too short; inform bug-glibc@prep.ai.mit.edu\n",
- p - end)
-#endif
- ;
- else
- p[-1] = '\0';
- end[-1] = '\0';
+ initstr (uname_info.version);
- for (i = 2; i < nserver_versions; i++)
- if (strcmp (server_versions[i].version, server_versions[1].version))
- break;
+ addstr (kernel_name, kernel_version);
- initstr (uname_info.version);
+ if (versions[0].count > 1)
+ addstr ("Hurd", versions[0].version);
- if (i == nserver_versions)
- {
- /* All the servers after [0] (the microkernel version)
- are the same, so just write one "hurd" version. */
- addstr (server_versions[0].name, server_versions[0].version);
- addstr ("Hurd", server_versions[1].version);
- }
- else
+ /* Now, for any which differ (if there might be any), write it out
+ separately. */
+ if (versions[0].count != nserver_versions)
for (i = 0; i < nserver_versions; i++)
- addstr (server_versions[i].name, server_versions[i].version);
+ if (versions[0].count == 1
+ || strcmp (server_versions[i].version, versions[0].version))
+ addstr (server_versions[i].name, server_versions[i].version);
if (p > end)
#ifdef notyet
@@ -393,52 +342,58 @@ rebuild_uname (void)
end[-1] = '\0';
}
-
void
initialize_version_info (void)
{
extern const char *const mach_cpu_types[];
extern const char *const mach_cpu_subtypes[][32];
- kernel_version_t kernel_version;
+ kernel_version_t kv;
char *p;
struct host_basic_info info;
- unsigned int n = sizeof info;
+ size_t n = sizeof info;
error_t err;
/* Fill in fixed slots sysname and machine. */
strcpy (uname_info.sysname, "GNU");
- err = host_info (mach_host_self (), HOST_BASIC_INFO, (int *) &info, &n);
+ err = host_info (mach_host_self (), HOST_BASIC_INFO,
+ (host_info_t) &info, &n);
assert (! err);
- snprintf (uname_info.machine, sizeof uname_info.machine, "%s/%s",
+ snprintf (uname_info.machine, sizeof uname_info.machine, "%s-%s",
mach_cpu_types[info.cpu_type],
mach_cpu_subtypes[info.cpu_type][info.cpu_subtype]);
/* Notice Mach's and our own version and initialize server version
- varables. */
+ variables. */
server_versions = malloc (sizeof (struct server_version) * 10);
+ assert (server_versions);
server_versions_nalloc = 10;
- err = host_kernel_version (mach_host_self (), kernel_version);
+ err = host_kernel_version (mach_host_self (), kv);
assert (! err);
- p = index (kernel_version, ':');
+ /* Make sure the result is null-terminated, as the kernel doesn't
+ guarantee it. */
+ kv[sizeof (kv) - 1] = '\0';
+ p = index (kv, ':');
if (p)
*p = '\0';
- p = index (kernel_version, ' ');
+ p = index (kv, ' ');
if (p)
*p = '\0';
- server_versions[0].name = strdup (p ? kernel_version : "mach");
- server_versions[0].release = strdup (HURD_RELEASE);
- server_versions[0].version = strdup (p ? p + 1 : kernel_version);
+ kernel_name = strdup (p ? kv : "mach");
+ assert (kernel_name);
+ kernel_version = strdup (p ? p + 1 : kv);
+ assert (kernel_version);
- server_versions[1].name = strdup (OUR_SERVER_NAME);
- server_versions[1].release = strdup (HURD_RELEASE);
- server_versions[1].version = strdup (OUR_VERSION);
+ server_versions[0].name = strdup ("proc");
+ assert (server_versions[0].name);
+ server_versions[0].version = strdup (HURD_VERSION);
+ assert (server_versions[0].version);
- nserver_versions = 2;
+ nserver_versions = 1;
rebuild_uname ();
-
+
uname_info.nodename[0] = '\0';
}
@@ -455,9 +410,10 @@ kern_return_t
S_proc_register_version (pstruct_t server,
mach_port_t credential,
char *name,
- char *release,
+ char *release,
char *version)
{
+ error_t err = 0;
int i;
/* No need to check SERVER here; we don't use it. */
@@ -465,17 +421,19 @@ S_proc_register_version (pstruct_t server,
if (credential != master_host_port)
/* Must be privileged to register for uname. */
return EPERM;
-
+
for (i = 0; i < nserver_versions; i++)
if (!strcmp (name, server_versions[i].name))
{
/* Change this entry. */
free (server_versions[i].version);
- free (server_versions[i].release);
server_versions[i].version = malloc (strlen (version) + 1);
- server_versions[i].release = malloc (strlen (version) + 1);
+ if (! server_versions[i].version)
+ {
+ err = ENOMEM;
+ goto out;
+ }
strcpy (server_versions[i].version, version);
- strcpy (server_versions[i].release, release);
break;
}
if (i == nserver_versions)
@@ -483,23 +441,40 @@ S_proc_register_version (pstruct_t server,
/* Didn't find it; extend. */
if (nserver_versions == server_versions_nalloc)
{
+ void *new = realloc (server_versions,
+ sizeof (struct server_version) *
+ server_versions_nalloc * 2);
+ if (! new)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+
server_versions_nalloc *= 2;
- server_versions = realloc (server_versions,
- sizeof (struct server_version) *
- server_versions_nalloc);
+ server_versions = new;
}
server_versions[nserver_versions].name = malloc (strlen (name) + 1);
- server_versions[nserver_versions].version = malloc (strlen (version)
- + 1);
- server_versions[nserver_versions].release = malloc (strlen (release)
+ if (! server_versions[nserver_versions].name)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+ server_versions[nserver_versions].version = malloc (strlen (version)
+ 1);
+ if (! server_versions[nserver_versions].version)
+ {
+ free (server_versions[nserver_versions].name);
+ err = ENOMEM;
+ goto out;
+ }
strcpy (server_versions[nserver_versions].name, name);
strcpy (server_versions[nserver_versions].version, version);
- strcpy (server_versions[nserver_versions].release, release);
nserver_versions++;
}
-
+
rebuild_uname ();
- mach_port_deallocate (mach_task_self (), credential);
- return 0;
+out:
+ if (!err)
+ mach_port_deallocate (mach_task_self (), credential);
+ return err;
}
diff --git a/proc/info.c b/proc/info.c
index c44bde6a..f35ad166 100644
--- a/proc/info.c
+++ b/proc/info.c
@@ -1,5 +1,5 @@
/* Process information queries
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,95,96,99,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <mach.h>
#include <sys/types.h>
+#include <sys/mman.h>
#include <hurd/hurd_types.h>
#include <stdlib.h>
#include <errno.h>
@@ -32,17 +33,32 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "proc.h"
#include "process_S.h"
-/* Implement S_proc_pid2task as described in <hurd/proc.defs>. */
+
+/* Returns true if PROC1 has `owner' privileges over PROC2 (and can thus get
+ its task port &c). If PROC2 has an owner, then PROC1 must have that uid;
+ otherwise, both must be in the same login collection. */
+static inline int
+check_owner (struct proc *proc1, struct proc *proc2)
+{
+ return
+ proc2->p_noowner
+ ? check_uid (proc1, 0) || proc1->p_login == proc2->p_login
+ : check_uid (proc1, proc2->p_owner);
+}
+
+
+/* Implement S_proc_pid2task as described in <hurd/process.defs>. */
kern_return_t
S_proc_pid2task (struct proc *callerp,
- pid_t pid,
- task_t *t)
+ pid_t pid,
+ task_t *t)
{
- struct proc *p = pid_find_allow_zombie (pid);
+ struct proc *p;
if (!callerp)
return EOPNOTSUPP;
+ p = pid_find_allow_zombie (pid);
if (!p)
return ESRCH;
@@ -55,16 +71,17 @@ S_proc_pid2task (struct proc *callerp,
if (! check_owner (callerp, p))
return EPERM;
+ assert (MACH_PORT_VALID (p->p_task));
*t = p->p_task;
return 0;
}
-/* Implement proc_task2pid as described in <hurd/proc.defs>. */
+/* Implement proc_task2pid as described in <hurd/process.defs>. */
kern_return_t
S_proc_task2pid (struct proc *callerp,
- task_t t,
- pid_t *pid)
+ task_t t,
+ pid_t *pid)
{
struct proc *p = task_find (t);
@@ -78,11 +95,11 @@ S_proc_task2pid (struct proc *callerp,
return 0;
}
-/* Implement proc_task2proc as described in <hurd/proc.defs>. */
+/* Implement proc_task2proc as described in <hurd/process.defs>. */
kern_return_t
S_proc_task2proc (struct proc *callerp,
- task_t t,
- mach_port_t *outproc)
+ task_t t,
+ mach_port_t *outproc)
{
struct proc *p = task_find (t);
@@ -96,10 +113,10 @@ S_proc_task2proc (struct proc *callerp,
return 0;
}
-/* Implement proc_proc2task as described in <hurd/proc.defs>. */
+/* Implement proc_proc2task as described in <hurd/process.defs>. */
kern_return_t
S_proc_proc2task (struct proc *p,
- task_t *t)
+ task_t *t)
{
if (!p)
return EOPNOTSUPP;
@@ -107,17 +124,18 @@ S_proc_proc2task (struct proc *p,
return 0;
}
-/* Implement proc_pid2proc as described in <hurd/proc.defs>. */
+/* Implement proc_pid2proc as described in <hurd/process.defs>. */
kern_return_t
S_proc_pid2proc (struct proc *callerp,
- pid_t pid,
- mach_port_t *outproc)
+ pid_t pid,
+ mach_port_t *outproc)
{
- struct proc *p = pid_find_allow_zombie (pid);
+ struct proc *p;
if (!callerp)
return EOPNOTSUPP;
+ p = pid_find_allow_zombie (pid);
if (!p)
return ESRCH;
@@ -136,18 +154,18 @@ S_proc_pid2proc (struct proc *callerp,
/* Read a string starting at address ADDR in task T; set *STR to point at
- newly malloced storage holding it. */
+ newly malloced storage holding it, and *LEN to its length with null. */
static error_t
get_string (task_t t,
vm_address_t addr,
- char **str)
+ char **str, size_t *len)
{
/* This version assumes that a string is never more than one
page in length. */
vm_address_t readaddr;
vm_address_t data;
- u_int readlen;
+ size_t readlen;
error_t err;
char *c;
@@ -168,15 +186,15 @@ get_string (task_t t,
else
{
c++; /* Include the null. */
- *str = malloc (c - (char *)(data + (addr - readaddr)));
+ *len = c - (char *) (data + (addr - readaddr));
+ *str = malloc (*len);
if (*str == NULL)
err = ENOMEM;
else
- bcopy ((char *)(data + (addr - readaddr)), *str,
- c - (char *)(data + (addr - readaddr)));
+ memcpy (*str, (char *) data + (addr - readaddr), *len);
}
- vm_deallocate (mach_task_self (), data, readlen);
+ munmap ((caddr_t) data, readlen);
return err;
}
@@ -210,8 +228,6 @@ get_vector (task_t task,
if (err)
return err;
- /* XXX fault bad here */
-
/* Scan for a null. */
for (t = (vm_address_t *) (data + (scanned - readaddr));
t < (vm_address_t *) (data + readlen);
@@ -223,15 +239,15 @@ get_vector (task_t task,
if (*vec == NULL)
err = ENOMEM;
else
- bcopy ((char *)(data + (addr - readaddr)), *vec,
+ memcpy (*vec, (char *)(data + (addr - readaddr)),
(char *)t - (char *)(data + (addr - readaddr)));
break;
}
/* If we didn't find the null terminator, then we will loop
to read an additional page. */
- scanned = data + readlen;
- vm_deallocate (mach_task_self (), data, readlen);
+ scanned = readaddr + readlen;
+ munmap ((caddr_t) data, readlen);
} while (!err && *vec == NULL);
return err;
@@ -243,7 +259,7 @@ static error_t
get_string_array (task_t t,
vm_address_t loc,
vm_address_t *buf,
- u_int *buflen)
+ size_t *buflen)
{
char *bp;
int *vector, *vp;
@@ -258,62 +274,65 @@ get_string_array (task_t t,
for (vp = vector; *vp; ++vp)
{
char *string;
- int len;
+ size_t len;
- err = get_string (t, *vp, &string);
+ err = get_string (t, *vp, &string, &len);
if (err)
{
free (vector);
if (*buf != origbuf)
- vm_deallocate (mach_task_self (), *buf, *buflen);
+ munmap ((caddr_t) *buf, *buflen);
return err;
}
- len = strlen (string) + 1;
- if (len > *(char **)buf + *buflen - bp)
+ if (len > (char *) *buf + *buflen - bp)
{
- vm_address_t newbuf;
- vm_size_t prev_len = bp - *(char **)buf;
+ char *newbuf;
+ vm_size_t prev_len = bp - (char *) *buf;
vm_size_t newsize = *buflen * 2;
if (newsize < prev_len + len)
- newsize = prev_len + len;
+ /* Since we will mmap whole pages anyway,
+ notice how much space we really have. */
+ newsize = round_page (prev_len + len);
- err = vm_allocate (mach_task_self (), &newbuf, newsize, 1);
- if (err)
+ newbuf = mmap (0, newsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (newbuf == MAP_FAILED)
{
+ err = errno;
free (string);
free (vector);
if (*buf != origbuf)
- vm_deallocate (mach_task_self (), *buf, *buflen);
+ munmap ((caddr_t) *buf, *buflen);
return err;
}
- bcopy (*(char **) buf, (char *) newbuf, prev_len);
- bp = (char *)newbuf + prev_len;
+ memcpy (newbuf, (char *) *buf, prev_len);
+ bp = newbuf + prev_len;
if (*buf != origbuf)
- vm_deallocate (mach_task_self (), *buf, *buflen);
+ munmap ((caddr_t) *buf, *buflen);
- *buf = newbuf;
+ *buf = (vm_address_t) newbuf;
*buflen = newsize;
}
- bcopy (string, bp, len);
+ memcpy (bp, string, len);
bp += len;
free (string);
}
+
free (vector);
*buflen = bp - (char *) *buf;
return 0;
}
-/* Implement proc_getprocargs as described in <hurd/proc.defs>. */
+/* Implement proc_getprocargs as described in <hurd/process.defs>. */
kern_return_t
S_proc_getprocargs (struct proc *callerp,
pid_t pid,
char **buf,
- u_int *buflen)
+ size_t *buflen)
{
struct proc *p = pid_find (pid);
@@ -325,12 +344,12 @@ S_proc_getprocargs (struct proc *callerp,
return get_string_array (p->p_task, p->p_argv, (vm_address_t *) buf, buflen);
}
-/* Implement proc_getprocenv as described in <hurd/proc.defs>. */
+/* Implement proc_getprocenv as described in <hurd/process.defs>. */
kern_return_t
S_proc_getprocenv (struct proc *callerp,
pid_t pid,
char **buf,
- u_int *buflen)
+ size_t *buflen)
{
struct proc *p = pid_find (pid);
@@ -346,18 +365,18 @@ S_proc_getprocenv (struct proc *callerp,
#define PI_FETCH_THREAD_DETAILS \
(PI_FETCH_THREAD_SCHED | PI_FETCH_THREAD_BASIC | PI_FETCH_THREAD_WAITS)
-/* Implement proc_getprocinfo as described in <hurd/proc.defs>. */
+/* Implement proc_getprocinfo as described in <hurd/process.defs>. */
kern_return_t
S_proc_getprocinfo (struct proc *callerp,
pid_t pid,
int *flags,
int **piarray,
- u_int *piarraylen,
+ size_t *piarraylen,
char **waits, mach_msg_type_number_t *waits_len)
{
struct proc *p = pid_find (pid);
struct procinfo *pi;
- int nthreads;
+ size_t nthreads;
thread_t *thds;
error_t err = 0;
size_t structsize;
@@ -365,7 +384,7 @@ S_proc_getprocinfo (struct proc *callerp,
int pi_alloced = 0, waits_alloced = 0;
/* The amount of WAITS we've filled in so far. */
mach_msg_type_number_t waits_used = 0;
- u_int tkcount, thcount;
+ size_t tkcount, thcount;
struct proc *tp;
task_t task; /* P's task port. */
mach_port_t msgport; /* P's msgport, or MACH_PORT_NULL if none. */
@@ -376,7 +395,9 @@ S_proc_getprocinfo (struct proc *callerp,
return ESRCH;
task = p->p_task;
- msgport = p->p_deadmsg ? MACH_PORT_NULL : p->p_msgport;
+
+ check_msgport_death (p);
+ msgport = p->p_msgport;
if (*flags & PI_FETCH_THREAD_DETAILS)
*flags |= PI_FETCH_THREADS;
@@ -398,7 +419,18 @@ S_proc_getprocinfo (struct proc *callerp,
if (structsize / sizeof (int) > *piarraylen)
{
- vm_allocate (mach_task_self (), (vm_address_t *)piarray, structsize, 1);
+ *piarray = mmap (0, structsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*piarray == MAP_FAILED)
+ {
+ err = errno;
+ if (*flags & PI_FETCH_THREADS)
+ {
+ for (i = 0; i < nthreads; i++)
+ mach_port_deallocate (mach_task_self (), thds[i]);
+ munmap (thds, nthreads * sizeof (thread_t));
+ }
+ return err;
+ }
pi_alloced = 1;
}
*piarraylen = structsize / sizeof (int);
@@ -424,7 +456,7 @@ S_proc_getprocinfo (struct proc *callerp,
assert (tp);
pi->logincollection = tp->p_pid;
if (p->p_dead || p->p_stopped)
- {
+ {
pi->exitstatus = p->p_status;
pi->sigcode = p->p_sigcode;
}
@@ -440,9 +472,37 @@ S_proc_getprocinfo (struct proc *callerp,
if (*flags & PI_FETCH_TASKINFO)
{
tkcount = TASK_BASIC_INFO_COUNT;
- err = task_info (task, TASK_BASIC_INFO, (int *)&pi->taskinfo, &tkcount);
+ err = task_info (task, TASK_BASIC_INFO,
+ (task_info_t) &pi->taskinfo, &tkcount);
if (err == MACH_SEND_INVALID_DEST)
err = ESRCH;
+#ifdef TASK_SCHED_TIMESHARE_INFO
+ if (!err)
+ {
+ tkcount = TASK_SCHED_TIMESHARE_INFO_COUNT;
+ err = task_info (task, TASK_SCHED_TIMESHARE_INFO,
+ (int *)&pi->timeshare_base_info, &tkcount);
+ if (err == KERN_INVALID_POLICY)
+ {
+ pi->timeshare_base_info.base_priority = -1;
+ err = 0;
+ }
+ }
+#endif
+ }
+ if (*flags & PI_FETCH_TASKEVENTS)
+ {
+ tkcount = TASK_EVENTS_INFO_COUNT;
+ err = task_info (task, TASK_EVENTS_INFO,
+ (task_info_t) &pi->taskevents, &tkcount);
+ if (err == MACH_SEND_INVALID_DEST)
+ err = ESRCH;
+ if (err)
+ {
+ /* Something screwy, give up on this bit of info. */
+ *flags &= ~PI_FETCH_TASKEVENTS;
+ err = 0;
+ }
}
for (i = 0; i < nthreads; i++)
@@ -453,7 +513,7 @@ S_proc_getprocinfo (struct proc *callerp,
{
thcount = THREAD_BASIC_INFO_COUNT;
err = thread_info (thds[i], THREAD_BASIC_INFO,
- (int *)&pi->threadinfos[i].pis_bi,
+ (thread_info_t) &pi->threadinfos[i].pis_bi,
&thcount);
if (err == MACH_SEND_INVALID_DEST)
{
@@ -473,7 +533,7 @@ S_proc_getprocinfo (struct proc *callerp,
{
thcount = THREAD_SCHED_INFO_COUNT;
err = thread_info (thds[i], THREAD_SCHED_INFO,
- (int *)&pi->threadinfos[i].pis_si,
+ (thread_info_t) &pi->threadinfos[i].pis_si,
&thcount);
if (err == MACH_SEND_INVALID_DEST)
{
@@ -482,15 +542,15 @@ S_proc_getprocinfo (struct proc *callerp,
continue;
}
if (err)
- /* Something screwy, give up o nthis bit of info. */
+ /* Something screwy, give up on this bit of info. */
{
*flags &= ~PI_FETCH_THREAD_SCHED;
err = 0;
}
}
- /* Note that there are thread wait entries only for threads not marked
- dead. */
+ /* Note that there are thread wait entries only for those threads
+ not marked dead. */
if (*flags & PI_FETCH_THREAD_WAITS)
{
@@ -517,18 +577,18 @@ S_proc_getprocinfo (struct proc *callerp,
mach_msg_type_number_t new_len =
round_page (waits_used + desc_len + 1);
- err = vm_allocate (mach_task_self (),
- (vm_address_t *)&new_waits, new_len,1);
+ new_waits = mmap (0, new_len, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ err = (new_waits == MAP_FAILED) ? errno : 0;
if (err)
/* Just don't return any more waits information. */
*flags &= ~PI_FETCH_THREAD_WAITS;
else
{
if (waits_used > 0)
- bcopy (*waits, new_waits, waits_used);
+ memcpy (new_waits, *waits, waits_used);
if (*waits_len > 0 && waits_alloced)
- vm_deallocate (mach_task_self (),
- (vm_address_t)*waits, *waits_len);
+ munmap (*waits, *waits_len);
*waits = new_waits;
*waits_len = new_len;
waits_alloced = 1;
@@ -538,7 +598,7 @@ S_proc_getprocinfo (struct proc *callerp,
if (waits_used + desc_len + 1 <= *waits_len)
/* Append DESC to WAITS. */
{
- bcopy (desc, *waits + waits_used, desc_len);
+ memcpy (*waits + waits_used, desc, desc_len);
waits_used += desc_len;
(*waits)[waits_used++] = '\0';
}
@@ -549,14 +609,11 @@ S_proc_getprocinfo (struct proc *callerp,
}
if (*flags & PI_FETCH_THREADS)
- {
- vm_deallocate (mach_task_self (),
- (vm_address_t)thds, nthreads * sizeof (thread_t));
- }
+ munmap (thds, nthreads * sizeof (thread_t));
if (err && pi_alloced)
- vm_deallocate (mach_task_self (), (u_int) *piarray, structsize);
+ munmap (*piarray, structsize);
if (err && waits_alloced)
- vm_deallocate (mach_task_self (), (vm_address_t)*waits, *waits_len);
+ munmap (*waits, *waits_len);
else
*waits_len = waits_used;
@@ -602,8 +659,9 @@ kern_return_t
S_proc_getloginpids (struct proc *callerp,
pid_t id,
pid_t **pids,
- u_int *npids)
+ size_t *npids)
{
+ error_t err = 0;
struct proc *l = pid_find (id);
struct proc *p;
struct proc **tail, **new, **parray;
@@ -618,6 +676,9 @@ S_proc_getloginpids (struct proc *callerp,
/* Simple breadth first search of the children of L. */
parraysize = 50;
parray = malloc (sizeof (struct proc *) * parraysize);
+ if (! parray)
+ return ENOMEM;
+
parray[0] = l;
for (tail = parray, new = &parray[1]; tail != new; tail++)
{
@@ -630,6 +691,12 @@ S_proc_getloginpids (struct proc *callerp,
struct proc **newparray;
newparray = realloc (parray, ((parraysize *= 2)
* sizeof (struct proc *)));
+ if (! newparray)
+ {
+ free (parray);
+ return ENOMEM;
+ }
+
tail = newparray + (tail - parray);
new = newparray + (new - parray);
parray = newparray;
@@ -639,19 +706,28 @@ S_proc_getloginpids (struct proc *callerp,
}
if (*npids < new - parray)
- vm_allocate (mach_task_self (), (vm_address_t *) pids,
- (new - parray) * sizeof (pid_t), 1);
- *npids = new - parray;
- for (i = 0; i < *npids; i++)
- (*pids)[i] = parray[i]->p_pid;
+ {
+ *pids = mmap (0, (new - parray) * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (*pids == MAP_FAILED)
+ err = errno;
+ }
+
+ if (! err)
+ {
+ *npids = new - parray;
+ for (i = 0; i < *npids; i++)
+ (*pids)[i] = parray[i]->p_pid;
+ }
+
free (parray);
- return 0;
+ return err;
}
-/* Implement proc_setlogin as described in <hurd/proc.defs>. */
+/* Implement proc_setlogin as described in <hurd/process.defs>. */
kern_return_t
S_proc_setlogin (struct proc *p,
- char *login)
+ char *login)
{
struct login *l;
@@ -662,6 +738,9 @@ S_proc_setlogin (struct proc *p,
return EPERM;
l = malloc (sizeof (struct login) + strlen (login) + 1);
+ if (! l)
+ return ENOMEM;
+
l->l_refcnt = 1;
strcpy (l->l_name, login);
if (!--p->p_login->l_refcnt)
@@ -670,10 +749,10 @@ S_proc_setlogin (struct proc *p,
return 0;
}
-/* Implement proc_getlogin as described in <hurd/proc.defs>. */
+/* Implement proc_getlogin as described in <hurd/process.defs>. */
kern_return_t
S_proc_getlogin (struct proc *p,
- char *login)
+ char *login)
{
if (!p)
return EOPNOTSUPP;
@@ -681,10 +760,42 @@ S_proc_getlogin (struct proc *p,
return 0;
}
-/* Implement proc_get_tty as described in <hurd/proc.defs>. */
+/* Implement proc_get_tty as described in <hurd/process.defs>. */
kern_return_t
S_proc_get_tty (struct proc *p, pid_t pid,
mach_port_t *tty, mach_msg_type_name_t *tty_type)
{
return EOPNOTSUPP; /* XXX */
}
+
+/* Implement proc_getnports as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_getnports (struct proc *callerp,
+ pid_t pid,
+ mach_msg_type_number_t *nports)
+{
+ struct proc *p = pid_find (pid);
+ mach_port_array_t names;
+ mach_msg_type_number_t ncount;
+ mach_port_type_array_t types;
+ mach_msg_type_number_t tcount;
+ error_t err = 0;
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ if (!p)
+ return ESRCH;
+
+ err = mach_port_names (p->p_task, &names, &ncount, &types, &tcount);
+ if (err == KERN_INVALID_TASK)
+ err = ESRCH;
+
+ if (!err) {
+ *nports = ncount;
+
+ munmap (names, ncount * sizeof (mach_port_t));
+ munmap (types, tcount * sizeof (mach_port_type_t));
+ }
+
+ return err;
+}
diff --git a/proc/main.c b/proc/main.c
index 1292cea0..f2cdfdf5 100644
--- a/proc/main.c
+++ b/proc/main.c
@@ -1,5 +1,5 @@
/* Initialization of the proc server
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993,94,95,96,97,99,2000,01 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -23,11 +23,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/hurd_types.h>
#include <hurd.h>
#include <hurd/startup.h>
+#include <device/device.h>
#include <assert.h>
-#include <wire.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
#include "proc.h"
+const char *argp_program_version = STANDARD_HURD_VERSION (proc);
+
int
message_demuxer (mach_msg_header_t *inp,
mach_msg_header_t *outp)
@@ -56,64 +61,79 @@ main (int argc, char **argv, char **envp)
mach_port_t pset, psetcntl;
void *genport;
process_t startup_port;
- volatile int hold = 0;
-
- while (hold);
-
+ struct argp argp = { 0, 0, 0, "Hurd process server" };
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
initialize_version_info ();
- task_get_bootstrap_port (mach_task_self (), &boot);
+ err = task_get_bootstrap_port (mach_task_self (), &boot);
+ assert_perror (err);
+ if (boot == MACH_PORT_NULL)
+ error (2, 0, "proc server can only be run by init during boot");
proc_bucket = ports_create_bucket ();
proc_class = ports_create_class (0, 0);
generic_port_class = ports_create_class (0, 0);
exc_class = ports_create_class (exc_clean, 0);
- ports_create_port (generic_port_class, proc_bucket,
+ ports_create_port (generic_port_class, proc_bucket,
sizeof (struct port_info), &genport);
generic_port = ports_get_right (genport);
- /* new_proc depends on these assignments which must occur in this order. */
- self_proc = new_proc (mach_task_self ()); /* proc 0 is the procserver */
- startup_proc = new_proc (MACH_PORT_NULL); /* proc 1 is init */
+ /* Create the initial proc object for init (PID 1). */
+ startup_proc = create_startup_proc ();
+
+ /* Create our own proc object (we are PID 0). */
+ self_proc = allocate_proc (mach_task_self ());
+ assert (self_proc);
+
+ complete_proc (self_proc, 0);
- startup_port = ports_get_right (startup_proc);
- mach_port_insert_right (mach_task_self (), startup_port,
- startup_port, MACH_MSG_TYPE_MAKE_SEND);
+ startup_port = ports_get_send_right (startup_proc);
err = startup_procinit (boot, startup_port, &startup_proc->p_task,
&authserver, &master_host_port, &master_device_port);
- assert (!err);
+ assert_perror (err);
mach_port_deallocate (mach_task_self (), startup_port);
mach_port_mod_refs (mach_task_self (), authserver, MACH_PORT_RIGHT_SEND, 1);
_hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
mach_port_deallocate (mach_task_self (), boot);
- add_proc_to_hash (self_proc);
- add_proc_to_hash (startup_proc);
+ proc_death_notify (startup_proc);
+ add_proc_to_hash (startup_proc); /* Now that we have the task port. */
/* Set our own argv and envp locations. */
- self_proc->p_argv = (int) argv;
- self_proc->p_envp = (int) envp;
+ self_proc->p_argv = (vm_address_t) argv;
+ self_proc->p_envp = (vm_address_t) envp;
/* Give ourselves good scheduling performance, because we are so
important. */
err = thread_get_assignment (mach_thread_self (), &pset);
- assert (!err);
+ assert_perror (err);
err = host_processor_set_priv (master_host_port, pset, &psetcntl);
- assert (!err);
+ assert_perror (err);
thread_max_priority (mach_thread_self (), psetcntl, 0);
- assert (!err);
+ assert_perror (err);
err = task_priority (mach_task_self (), 2, 1);
- assert (!err);
+ assert_perror (err);
mach_port_deallocate (mach_task_self (), pset);
mach_port_deallocate (mach_task_self (), psetcntl);
-/* wire_task_self (); */
+ {
+ /* Get our stderr set up to print on the console, in case we have
+ to panic or something. */
+ mach_port_t cons;
+ error_t err;
+ err = device_open (master_device_port, D_READ|D_WRITE, "console", &cons);
+ assert_perror (err);
+ stdin = mach_open_devstream (cons, "r");
+ stdout = stderr = mach_open_devstream (cons, "w");
+ mach_port_deallocate (mach_task_self (), cons);
+ }
while (1)
ports_manage_port_operations_multithread (proc_bucket,
message_demuxer,
- 0, 0, 0, 0);
+ 0, 0, 0);
}
diff --git a/proc/mgt.c b/proc/mgt.c
index e8af38d4..1180c700 100644
--- a/proc/mgt.c
+++ b/proc/mgt.c
@@ -1,5 +1,5 @@
/* Process management
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <mach.h>
#include <sys/types.h>
+#include <sys/mman.h>
#include <errno.h>
#include <hurd/hurd_types.h>
#include <stdlib.h>
@@ -41,29 +42,34 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Create a new id structure with the given genuine uids and gids. */
static inline struct ids *
-make_ids (uid_t *uids, int nuids, uid_t *gids, int ngids)
+make_ids (const uid_t *uids, size_t nuids)
{
struct ids *i;
- i = malloc (sizeof (struct ids));
+ i = malloc (sizeof (struct ids) + sizeof (uid_t) * nuids);;
+ if (! i)
+ return NULL;
+
i->i_nuids = nuids;
- i->i_ngids = ngids;
- i->i_uids = malloc (sizeof (uid_t) * nuids);
- i->i_gids = malloc (sizeof (uid_t) * ngids);
i->i_refcnt = 1;
- memcpy (i->i_uids, uids, sizeof (uid_t) * nuids);
- memcpy (i->i_gids, gids, sizeof (uid_t) * ngids);
+ memcpy (&i->i_uids, uids, sizeof (uid_t) * nuids);
return i;
}
+static inline void
+ids_ref (struct ids *i)
+{
+ i->i_refcnt ++;
+}
+
/* Free an id structure. */
static inline void
-free_ids (struct ids *i)
+ids_rele (struct ids *i)
{
- free (i->i_uids);
- free (i->i_gids);
- free (i);
+ i->i_refcnt --;
+ if (i->i_refcnt == 0)
+ free (i);
}
/* Tell if process P has uid UID, or has root. */
@@ -77,15 +83,14 @@ check_uid (struct proc *p, uid_t uid)
return 0;
}
-
-/* Implement proc_reathenticate as described in <hurd/proc.defs>. */
+/* Implement proc_reathenticate as described in <hurd/process.defs>. */
kern_return_t
S_proc_reauthenticate (struct proc *p, mach_port_t rendport)
{
error_t err;
uid_t gubuf[50], aubuf[50], ggbuf[50], agbuf[50];
uid_t *gen_uids, *aux_uids, *gen_gids, *aux_gids;
- u_int ngen_uids, naux_uids, ngen_gids, naux_gids;
+ size_t ngen_uids, naux_uids, ngen_gids, naux_gids;
if (!p)
return EOPNOTSUPP;
@@ -95,10 +100,13 @@ S_proc_reauthenticate (struct proc *p, mach_port_t rendport)
gen_gids = ggbuf;
aux_gids = agbuf;
- ngen_uids = naux_uids = 50;
- ngen_gids = naux_gids = 50;
-
+ ngen_uids = sizeof (gubuf) / sizeof (uid_t);
+ naux_uids = sizeof (aubuf) / sizeof (uid_t);
+ ngen_gids = sizeof (ggbuf) / sizeof (uid_t);
+ naux_gids = sizeof (agbuf) / sizeof (uid_t);
+ /* Release the global lock while blocking on the auth server and client. */
+ mutex_unlock (&global_lock);
err = auth_server_authenticate (authserver,
rendport, MACH_MSG_TYPE_COPY_SEND,
MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND,
@@ -106,40 +114,48 @@ S_proc_reauthenticate (struct proc *p, mach_port_t rendport)
&aux_uids, &naux_uids,
&gen_gids, &ngen_gids,
&aux_gids, &naux_gids);
+ mutex_lock (&global_lock);
+
if (err)
return err;
- mach_port_deallocate (mach_task_self (), rendport);
- if (!--p->p_id->i_refcnt)
- free_ids (p->p_id);
- p->p_id = make_ids (gen_uids, ngen_uids, gen_gids, ngen_gids);
+ if (p->p_dead)
+ /* The process died while we had the lock released.
+ Its p_id field is no longer valid and we shouldn't touch it. */
+ err = EAGAIN;
+ else
+ {
+ ids_rele (p->p_id);
+ p->p_id = make_ids (gen_uids, ngen_uids);
+ if (! p->p_id)
+ err = ENOMEM;
+ }
if (gen_uids != gubuf)
- vm_deallocate (mach_task_self (), (u_int) gen_uids,
- ngen_uids * sizeof (uid_t));
+ munmap (gen_uids, ngen_uids * sizeof (uid_t));
if (aux_uids != aubuf)
- vm_deallocate (mach_task_self (), (u_int) aux_uids,
- naux_uids * sizeof (uid_t));
+ munmap (aux_uids, naux_uids * sizeof (uid_t));
if (gen_gids != ggbuf)
- vm_deallocate (mach_task_self (), (u_int) gen_gids,
- ngen_gids * sizeof (uid_t));
+ munmap (gen_gids, ngen_gids * sizeof (uid_t));
if (aux_gids != agbuf)
- vm_deallocate (mach_task_self (), (u_int) aux_gids,
- naux_gids * sizeof (uid_t));
+ munmap (aux_gids, naux_gids * sizeof (uid_t));
- return 0;
+ if (!err)
+ mach_port_deallocate (mach_task_self (), rendport);
+ return err;
}
-/* Implement proc_child as described in <hurd/proc.defs>. */
+/* Implement proc_child as described in <hurd/process.defs>. */
kern_return_t
S_proc_child (struct proc *parentp,
task_t childt)
{
- struct proc *childp = task_find (childt);
+ struct proc *childp;
if (!parentp)
return EOPNOTSUPP;
+ childp = task_find (childt);
if (!childp)
return ESRCH;
@@ -160,10 +176,9 @@ S_proc_child (struct proc *parentp,
childp->p_owner = parentp->p_owner;
childp->p_noowner = parentp->p_noowner;
- if (!--childp->p_id->i_refcnt)
- free_ids (childp->p_id);
+ ids_rele (childp->p_id);
+ ids_ref (parentp->p_id);
childp->p_id = parentp->p_id;
- childp->p_id->i_refcnt++;
/* Process hierarchy. Remove from our current location
and place us under our new parent. Sanity check to make sure
@@ -197,17 +212,17 @@ S_proc_child (struct proc *parentp,
return 0;
}
-/* Implement proc_reassign as described in <hurd/proc.defs>. */
+/* Implement proc_reassign as described in <hurd/process.defs>. */
kern_return_t
S_proc_reassign (struct proc *p,
task_t newt)
{
- struct proc *stubp = task_find (newt);
- mach_port_t foo;
+ struct proc *stubp;
if (!p)
return EOPNOTSUPP;
+ stubp = task_find (newt);
if (!stubp)
return ESRCH;
@@ -219,20 +234,12 @@ S_proc_reassign (struct proc *p,
remove_proc_from_hash (p);
task_terminate (p->p_task);
- mach_port_deallocate (mach_task_self (), p->p_task);
+ mach_port_destroy (mach_task_self (), p->p_task);
p->p_task = stubp->p_task;
- /* For security, we need use the request port from STUBP */
+ /* For security, we need to use the request port from STUBP */
ports_transfer_right (p, stubp);
- /* Redirect the task-death notification to the new receive right. */
- mach_port_request_notification (mach_task_self (), p->p_task,
- MACH_NOTIFY_DEAD_NAME, 1,
- p->p_pi.port_right,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
- if (foo)
- mach_port_deallocate (mach_task_self (), foo);
-
/* Enqueued messages might refer to the old task port, so
destroy them. */
if (p->p_msgport != MACH_PORT_NULL)
@@ -247,7 +254,7 @@ S_proc_reassign (struct proc *p,
p->p_envp = stubp->p_envp;
/* Destroy stubp */
- stubp->p_task = 0; /* block deallocation */
+ stubp->p_task = MACH_PORT_NULL;/* block deallocation */
process_has_exited (stubp);
stubp->p_waited = 1; /* fake out complete_exit */
complete_exit (stubp);
@@ -257,7 +264,7 @@ S_proc_reassign (struct proc *p,
return 0;
}
-/* Implement proc_setowner as described in <hurd/proc.defs>. */
+/* Implement proc_setowner as described in <hurd/process.defs>. */
kern_return_t
S_proc_setowner (struct proc *p,
uid_t owner,
@@ -280,7 +287,7 @@ S_proc_setowner (struct proc *p,
return 0;
}
-/* Implement proc_getpids as described in <hurd/proc.defs>. */
+/* Implement proc_getpids as described in <hurd/process.defs>. */
kern_return_t
S_proc_getpids (struct proc *p,
pid_t *pid,
@@ -295,7 +302,7 @@ S_proc_getpids (struct proc *p,
return 0;
}
-/* Implement proc_set_arg_locations as described in <hurd/proc.defs>. */
+/* Implement proc_set_arg_locations as described in <hurd/process.defs>. */
kern_return_t
S_proc_set_arg_locations (struct proc *p,
vm_address_t argv,
@@ -308,7 +315,7 @@ S_proc_set_arg_locations (struct proc *p,
return 0;
}
-/* Implement proc_get_arg_locations as described in <hurd/proc.defs>. */
+/* Implement proc_get_arg_locations as described in <hurd/process.defs>. */
kern_return_t
S_proc_get_arg_locations (struct proc *p,
vm_address_t *argv,
@@ -319,13 +326,14 @@ S_proc_get_arg_locations (struct proc *p,
return 0;
}
-/* Implement proc_dostop as described in <hurd/proc.defs>. */
+/* Implement proc_dostop as described in <hurd/process.defs>. */
kern_return_t
S_proc_dostop (struct proc *p,
thread_t contthread)
{
thread_t threadbuf[2], *threads = threadbuf;
- unsigned int nthreads = 2, i;
+ size_t nthreads = sizeof (threadbuf) / sizeof (thread_t);
+ int i;
error_t err;
if (!p)
@@ -336,16 +344,21 @@ S_proc_dostop (struct proc *p,
return err;
err = task_threads (p->p_task, &threads, &nthreads);
if (err)
- return err;
+ {
+ task_resume (p->p_task);
+ return err;
+ }
+ /* We can not compare the thread ports with CONTTHREAD, as CONTTHREAD
+ might be a proxy port (for example in rpctrace). For this reason
+ we suspend all threads and then resume CONTTHREAD. */
for (i = 0; i < nthreads; i++)
{
if (threads[i] != contthread)
- err = thread_suspend (threads[i]);
+ thread_suspend (threads[i]);
mach_port_deallocate (mach_task_self (), threads[i]);
}
if (threads != threadbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) threads,
- nthreads * sizeof (thread_t));
+ munmap (threads, nthreads * sizeof (thread_t));
err = task_resume (p->p_task);
if (err)
return err;
@@ -372,7 +385,7 @@ S_proc_handle_exceptions (struct proc *p,
mach_msg_type_number_t statecnt)
{
struct exc *e;
- error_t err;
+ error_t err;
/* No need to check P here; we don't use it. */
@@ -385,7 +398,7 @@ S_proc_handle_exceptions (struct proc *p,
e->forwardport = forwardport;
e->flavor = flavor;
e->statecnt = statecnt;
- bcopy (new_state, e->thread_state, statecnt * sizeof (natural_t));
+ memcpy (e->thread_state, new_state, statecnt * sizeof (natural_t));
ports_port_deref (e);
return 0;
}
@@ -399,9 +412,9 @@ S_proc_exception_raise (mach_port_t excport,
mach_msg_type_name_t reply_type,
mach_port_t thread,
mach_port_t task,
- int exception,
- int code,
- int subcode)
+ integer_t exception,
+ integer_t code,
+ integer_t subcode)
{
error_t err;
struct proc *p;
@@ -421,8 +434,6 @@ S_proc_exception_raise (mach_port_t excport,
err = proc_exception_raise (e->forwardport,
reply, reply_type, MACH_SEND_NOTIFY,
thread, task, exception, code, subcode);
- mach_port_deallocate (mach_task_self (), thread);
- mach_port_deallocate (mach_task_self (), task);
switch (err)
{
@@ -435,19 +446,21 @@ S_proc_exception_raise (mach_port_t excport,
dequeue that message. */
err = thread_set_state (thread, e->flavor, e->thread_state, e->statecnt);
ports_port_deref (e);
+ mach_port_deallocate (mach_task_self (), thread);
+ mach_port_deallocate (mach_task_self (), task);
return MIG_NO_REPLY;
default:
/* Some unexpected error in forwarding the message. */
/* FALLTHROUGH */
- case MACH_SEND_INVALID_NOTIFY:
- /* The port's queue is full, meaning the thread didn't receive
+ case MACH_SEND_NOTIFY_IN_PROGRESS:
+ /* The port's queue is full; this means the thread didn't receive
the exception message we forwarded last time it faulted.
Declare that signal thread hopeless and the task crashed. */
/* Translate the exception code into a signal number
- and mark the process has dying that way. */
+ and mark the process as having died that way. */
hsd.exc = exception;
hsd.exc_code = code;
hsd.exc_subcode = subcode;
@@ -456,20 +469,46 @@ S_proc_exception_raise (mach_port_t excport,
p->p_status = W_EXITCODE (0, signo);
p->p_sigcode = hsd.code;
- /* Nuke the task; we will get a notification message and report it
- died with SIGNO. */
+ /* Nuke the task; we will get a notification message and report that
+ it died with SIGNO. */
task_terminate (task);
ports_port_deref (e);
- return 0;
+
+ /* In the MACH_SEND_NOTIFY_IN_PROGRESS case, the kernel did a
+ pseudo-receive of the RPC request message that may have added user
+ refs to these send rights. But we have lost track because the MiG
+ stub did not save the message buffer that was modified by the
+ pseudo-receive.
+
+ Fortunately, we can be sure that we don't need the THREAD send
+ right for anything since this task is now dead; there would be a
+ potential race here with another exception_raise message arriving
+ with the same thread, but we expect that this won't happen since
+ the thread will still be waiting for our reply. XXX We have no
+ secure knowledge that this is really from the kernel, so a
+ malicious user could confuse us and induce a race where we clobber
+ another port put on the THREAD name after the destroy; also, a
+ user just doing thread_set_state et al could arrange that we get a
+ second legitimate exception_raise for the same thread and have the
+ first race mentioned above!
+
+ There are all manner of race problems if we destroy the TASK
+ right. Fortunately, since we've terminated the task we know that
+ we will shortly be getting a dead-name notifiction and that will
+ call mach_port_destroy in TASK when it is safe to do so. */
+
+ mach_port_destroy (mach_task_self (), thread);
+
+ return MIG_NO_REPLY;
}
}
-/* Implement proc_getallpids as described in <hurd/proc.defs>. */
+/* Implement proc_getallpids as described in <hurd/process.defs>. */
kern_return_t
S_proc_getallpids (struct proc *p,
pid_t **pids,
- u_int *pidslen)
+ size_t *pidslen)
{
int nprocs;
pid_t *loc;
@@ -491,8 +530,12 @@ S_proc_getallpids (struct proc *p,
prociterate (count_up, &nprocs);
if (nprocs > *pidslen)
- vm_allocate (mach_task_self (), (vm_address_t *) pids,
- nprocs * sizeof (pid_t), 1);
+ {
+ *pids = mmap (0, nprocs * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (*pids == MAP_FAILED)
+ return ENOMEM;
+ }
loc = *pids;
prociterate (store_pid, &loc);
@@ -500,141 +543,151 @@ S_proc_getallpids (struct proc *p,
*pidslen = nprocs;
return 0;
}
-
+
/* Create a process for TASK, which is not otherwise known to us.
- The task will be placed as a child of init and in init's pgrp. */
+ The PID/parentage/job-control fields are not yet filled in,
+ and the proc is not entered into any hash table. */
struct proc *
-new_proc (task_t task)
+allocate_proc (task_t task)
{
+ error_t err;
struct proc *p;
- mach_port_t foo;
-
- /* Because these have a reference count of one before starting,
- they can never be freed, so we're safe. */
- static struct login *nulllogin;
- static struct ids nullids = {0, 0, 0, 0, 1};
-
- if (!nulllogin)
- {
- nulllogin = malloc (sizeof (struct login) + 7);
- nulllogin->l_refcnt = 1;
- strcpy (nulllogin->l_name, "<none>");
- }
/* Pid 0 is us; pid 1 is init. We handle those here specially;
all other processes inherit from init here (though proc_child
will move them to their actual parent usually). */
- ports_create_port (proc_class, proc_bucket, sizeof (struct proc), &p);
+ err = ports_create_port (proc_class, proc_bucket, sizeof (struct proc), &p);
+ if (err)
+ return NULL;
- p->p_pid = genpid ();
+ memset (&p->p_pi + 1, 0, sizeof *p - sizeof p->p_pi);
p->p_task = task;
+ p->p_msgport = MACH_PORT_NULL;
- mach_port_request_notification (mach_task_self (), p->p_task,
- MACH_NOTIFY_DEAD_NAME, 1, p->p_pi.port_right,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
- if (foo != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), foo);
+ condition_init (&p->p_wakeup);
- switch (p->p_pid)
- {
- case 0:
- p->p_login = malloc (sizeof (struct login) + 5);
- p->p_login->l_refcnt = 1;
- strcpy (p->p_login->l_name, "root");
- break;
+ return p;
+}
- case 1:
- p->p_login = self_proc->p_login;
- p->p_login->l_refcnt++;
- break;
+/* Allocate and initialize the proc structure for init (PID 1),
+ the original parent of all other procs. */
+struct proc *
+create_startup_proc (void)
+{
+ static const uid_t zero;
+ struct proc *p;
+ const char *rootsname = "root";
- default:
- p->p_login = nulllogin;
- p->p_login->l_refcnt++;
- }
+ p = allocate_proc (MACH_PORT_NULL);
+ assert (p);
- p->p_owner = 0;
+ p->p_pid = 1;
- if (p->p_pid == 0)
- {
- uid_t foo = 0;
- p->p_id = make_ids (&foo, 1, &foo, 1);
- p->p_parent = p;
- p->p_sib = 0;
- p->p_prevsib = &p->p_ochild;
- p->p_ochild = p;
- p->p_loginleader = 1;
- p->p_parentset = 1;
- p->p_noowner = 0;
- }
- else if (p->p_pid == 1)
- {
- p->p_id = self_proc->p_id;
- p->p_id->i_refcnt++;
- p->p_parent = self_proc;
-
- p->p_sib = self_proc->p_ochild;
- p->p_prevsib = &self_proc->p_ochild;
- if (p->p_sib)
- p->p_sib->p_prevsib = &p->p_sib;
- self_proc->p_ochild = p;
- p->p_loginleader = 1;
- p->p_ochild = 0;
- p->p_parentset = 1;
- p->p_noowner = 0;
- }
- else
- {
- p->p_id = &nullids;
- p->p_id->i_refcnt++;
-
- /* Our parent is init for now */
- p->p_parent = startup_proc;
-
- p->p_sib = startup_proc->p_ochild;
- p->p_prevsib = &startup_proc->p_ochild;
- if (p->p_sib)
- p->p_sib->p_prevsib = &p->p_sib;
- startup_proc->p_ochild = p;
- p->p_loginleader = 0;
- p->p_ochild = 0;
- p->p_parentset = 0;
- p->p_noowner = 1;
- }
+ p->p_parent = p;
+ p->p_sib = 0;
+ p->p_prevsib = &p->p_ochild;
+ p->p_ochild = p;
+ p->p_parentset = 1;
- if (p->p_pid < 2)
- boot_setsid (p);
- else
- p->p_pgrp = startup_proc->p_pgrp;
+ p->p_deadmsg = 1; /* Force initial "re-"fetch of msgport. */
- p->p_msgport = MACH_PORT_NULL;
+ p->p_noowner = 0;
+ p->p_id = make_ids (&zero, 1);
+ assert (p->p_id);
- condition_init (&p->p_wakeup);
+ p->p_loginleader = 1;
+ p->p_login = malloc (sizeof (struct login) + strlen (rootsname) + 1);
+ assert (p->p_login);
- p->p_argv = p->p_envp = p->p_status = 0;
+ p->p_login->l_refcnt = 1;
+ strcpy (p->p_login->l_name, rootsname);
- p->p_exec = 0;
- p->p_stopped = 0;
- p->p_waited = 0;
- p->p_exiting = 0;
- p->p_waiting = 0;
- p->p_traced = 0;
- p->p_nostopcld = 0;
- p->p_deadmsg = (p->p_pid == 1);
- p->p_checkmsghangs = 0;
- p->p_msgportwait = 0;
- p->p_dead = 0;
-
- if (p->p_pid > 1)
+ boot_setsid (p);
+
+ return p;
+}
+
+/* Request a dead-name notification for P's task port. */
+
+void
+proc_death_notify (struct proc *p)
+{
+ error_t err;
+ mach_port_t old;
+
+ err = mach_port_request_notification (mach_task_self (), p->p_task,
+ MACH_NOTIFY_DEAD_NAME, 1,
+ p->p_pi.port_right,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old);
+ assert_perror (err);
+
+ if (old != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), old);
+}
+
+/* Complete a new process that has been allocated but not entirely initialized.
+ This gets called for every process except startup_proc (PID 1). */
+void
+complete_proc (struct proc *p, pid_t pid)
+{
+ /* Because these have a reference count of one before starting,
+ they can never be freed, so we're safe. */
+ static struct login *nulllogin;
+ static struct ids nullids = { i_refcnt : 1, i_nuids : 0};
+ const char nullsname [] = "<none>";
+
+ if (!nulllogin)
{
- add_proc_to_hash (p);
- join_pgrp (p);
+ nulllogin = malloc (sizeof (struct login) + sizeof (nullsname) + 1);
+ nulllogin->l_refcnt = 1;
+ strcpy (nulllogin->l_name, nullsname);
}
- return p;
+ p->p_pid = pid;
+
+ ids_ref (&nullids);
+ p->p_id = &nullids;
+
+ p->p_login = nulllogin;
+ p->p_login->l_refcnt++;
+
+ /* Our parent is init for now. */
+ p->p_parent = startup_proc;
+
+ p->p_sib = startup_proc->p_ochild;
+ p->p_prevsib = &startup_proc->p_ochild;
+ if (p->p_sib)
+ p->p_sib->p_prevsib = &p->p_sib;
+ startup_proc->p_ochild = p;
+ p->p_loginleader = 0;
+ p->p_ochild = 0;
+ p->p_parentset = 0;
+
+ p->p_noowner = 1;
+
+ p->p_pgrp = startup_proc->p_pgrp;
+
+ proc_death_notify (p);
+ add_proc_to_hash (p);
+ join_pgrp (p);
}
+
+/* Create a process for TASK, which is not otherwise known to us
+ and initialize it in the usual ways. */
+static struct proc *
+new_proc (task_t task)
+{
+ struct proc *p;
+
+ p = allocate_proc (task);
+ if (p)
+ complete_proc (p, genpid ());
+ return p;
+}
+
/* The task associated with process P has died. Drop most state,
and then record us as dead. Our parent will eventually complete the
deallocation. */
@@ -657,20 +710,19 @@ process_has_exited (struct proc *p)
prociterate ((void (*) (struct proc *, void *))check_message_dying, p);
- /* Nuke external send rights and the (possible) associated reference */
+ /* Nuke external send rights and the (possible) associated reference. */
ports_destroy_right (p);
if (!--p->p_login->l_refcnt)
free (p->p_login);
- if (!--p->p_id->i_refcnt)
- free_ids (p->p_id);
+ ids_rele (p->p_id);
/* Reparent our children to init by attaching the head and tail
- of our list onto init's. */
+ of our list onto init's. */
if (p->p_ochild)
{
- struct proc *tp; /* will point to the last one */
+ struct proc *tp; /* will point to the last one. */
int isdead = 0;
/* first tell them their parent is changing */
@@ -690,7 +742,7 @@ process_has_exited (struct proc *p)
!tp->p_pgrp->pg_orphcnt);
tp->p_parent = startup_proc;
- /* And now nappend the lists. */
+ /* And now append the lists. */
tp->p_sib = startup_proc->p_ochild;
if (tp->p_sib)
tp->p_sib->p_prevsib = &tp->p_sib;
@@ -707,6 +759,9 @@ process_has_exited (struct proc *p)
condition_broadcast (&p->p_wakeup);
p->p_dead = 1;
+
+ /* Cancel any outstanding RPCs done on behalf of the dying process. */
+ ports_interrupt_rpcs (p);
}
void
@@ -717,7 +772,7 @@ complete_exit (struct proc *p)
remove_proc_from_hash (p);
if (p->p_task != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), p->p_task);
+ mach_port_destroy (mach_task_self (), p->p_task);
/* Remove us from our parent's list of children. */
if (p->p_sib)
@@ -740,7 +795,7 @@ struct proc *
add_tasks (task_t task)
{
mach_port_t *psets;
- u_int npsets;
+ size_t npsets;
int i;
struct proc *foundp = 0;
@@ -749,7 +804,7 @@ add_tasks (task_t task)
{
mach_port_t psetpriv;
mach_port_t *tasks;
- u_int ntasks;
+ size_t ntasks;
int j;
if (!foundp)
@@ -759,6 +814,12 @@ add_tasks (task_t task)
for (j = 0; j < ntasks; j++)
{
int set = 0;
+
+ /* The kernel can deliver us an array with null slots in the
+ middle, e.g. if a task died during the call. */
+ if (! MACH_PORT_VALID (tasks[j]))
+ continue;
+
if (!foundp)
{
struct proc *p = task_find_nocreate (tasks[j]);
@@ -773,19 +834,16 @@ add_tasks (task_t task)
if (!set)
mach_port_deallocate (mach_task_self (), tasks[j]);
}
- vm_deallocate (mach_task_self (), (vm_address_t) tasks,
- ntasks * sizeof (task_t));
+ munmap (tasks, ntasks * sizeof (task_t));
mach_port_deallocate (mach_task_self (), psetpriv);
}
mach_port_deallocate (mach_task_self (), psets[i]);
}
- vm_deallocate (mach_task_self (), (vm_address_t) psets,
- npsets * sizeof (mach_port_t));
+ munmap (psets, npsets * sizeof (mach_port_t));
return foundp;
}
-/* Allocate a new pid. The first two times this is called it must return
- 0 and 1 in order; after that it must simply return an unused pid.
+/* Allocate a new unused PID.
(Unused means it is neither the pid nor pgrp of any relevant data.) */
int
genpid ()
@@ -795,24 +853,16 @@ genpid ()
static int nextpid = 0;
static int wrap = WRAP_AROUND;
- int wrapped = 0;
-
- while (!pidfree (nextpid))
+ while (nextpid < wrap && !pidfree (nextpid))
+ ++nextpid;
+ if (nextpid >= wrap)
{
- ++nextpid;
- if (nextpid > wrap)
- {
- if (wrapped)
- {
- wrap *= 2;
- wrapped = 0;
- }
- else
- {
- nextpid = START_OVER;
- wrapped = 1;
- }
- }
+ nextpid = START_OVER;
+ while (!pidfree (nextpid))
+ nextpid++;
+
+ while (nextpid > wrap)
+ wrap *= 2;
}
return nextpid++;
diff --git a/proc/msg.c b/proc/msg.c
index fe173b68..ff1dbc54 100644
--- a/proc/msg.c
+++ b/proc/msg.c
@@ -1,5 +1,5 @@
/* Message port manipulations
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1999, 2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -50,7 +50,6 @@ S_proc_setmsgport (struct proc *p,
mach_port_t *oldmsgport,
mach_msg_type_name_t *oldmsgport_type)
{
- mach_port_t foo;
if (!p)
return EOPNOTSUPP;
@@ -63,12 +62,6 @@ S_proc_setmsgport (struct proc *p,
prociterate (check_message_return, p);
p->p_checkmsghangs = 0;
- mach_port_request_notification (mach_task_self (), msgport,
- MACH_NOTIFY_DEAD_NAME, 1, p->p_pi.port_right,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
- if (foo)
- mach_port_deallocate (mach_task_self (), foo);
-
if (p == startup_proc)
/* Init is single threaded, so we can't delay our reply for
the essential task RPC; spawn a thread to do it. */
@@ -89,6 +82,32 @@ check_message_dying (struct proc *p, struct proc *dyingp)
}
}
+/* Check if the message port of process P has died. Return nonzero if
+ this has indeed happened. */
+int
+check_msgport_death (struct proc *p)
+{
+ /* Only check if the message port passed away, if we know that it
+ was ever alive. */
+ if (p->p_msgport != MACH_PORT_NULL)
+ {
+ mach_port_type_t type;
+ error_t err;
+
+ err = mach_port_type (mach_task_self (), p->p_msgport, &type);
+ if (err || (type & MACH_PORT_TYPE_DEAD_NAME))
+ {
+ /* The port appears to be dead; throw it away. */
+ mach_port_deallocate (mach_task_self (), p->p_msgport);
+ p->p_msgport = MACH_PORT_NULL;
+ p->p_deadmsg = 1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
error_t
S_proc_getmsgport (struct proc *callerp,
mach_port_t reply_port,
@@ -97,11 +116,14 @@ S_proc_getmsgport (struct proc *callerp,
mach_port_t *msgport)
{
int cancel;
- struct proc *p = pid_find_allow_zombie (pid);
+ struct proc *p;
if (!callerp)
return EOPNOTSUPP;
-
+
+ p = pid_find_allow_zombie (pid);
+
+restart:
while (p && p->p_deadmsg && !p->p_dead)
{
callerp->p_msgportwait = 1;
@@ -119,15 +141,10 @@ S_proc_getmsgport (struct proc *callerp,
if (!p)
return ESRCH;
+ if (check_msgport_death (p))
+ goto restart;
+
*msgport = p->p_msgport;
- return 0;
-}
-void
-message_port_dead (struct proc *p)
-{
- mach_port_deallocate (mach_task_self (), p->p_msgport);
- p->p_msgport = MACH_PORT_NULL;
- p->p_deadmsg = 1;
+ return 0;
}
-
diff --git a/proc/notify.c b/proc/notify.c
index 9d48d945..5a112b07 100644
--- a/proc/notify.c
+++ b/proc/notify.c
@@ -1,5 +1,5 @@
/* Handle notifications
- Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1996, 1999 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -44,6 +44,7 @@ do_mach_notify_dead_name (mach_port_t notify,
if (notify == generic_port)
{
check_dead_execdata_notify (deadport);
+ mach_port_deallocate (mach_task_self (), deadport);
return 0;
}
@@ -52,16 +53,11 @@ do_mach_notify_dead_name (mach_port_t notify,
if (!p)
return EOPNOTSUPP;
- if (p->p_msgport == deadport)
- {
- message_port_dead (p);
- ports_port_deref (p);
- return 0;
- }
- else if (p->p_task == deadport)
+ if (p->p_task == deadport)
{
process_has_exited (p);
ports_port_deref (p);
+ mach_port_deallocate (mach_task_self (), deadport);
return 0;
}
else
diff --git a/proc/pgrp.c b/proc/pgrp.c
index 224f7e52..2d6ca93a 100644
--- a/proc/pgrp.c
+++ b/proc/pgrp.c
@@ -1,5 +1,5 @@
-/* Session and process group manipulation
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+/* Session and process group manipulation
+ Copyright (C) 1992,93,94,95,96,99,2001,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -25,6 +25,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/errno.h>
#include <stdlib.h>
#include <signal.h>
+#include <assert.h>
#include "proc.h"
#include "process_S.h"
@@ -37,19 +38,22 @@ new_pgrp (pid_t pgid,
struct session *sess)
{
struct pgrp *pg;
-
+
pg = malloc (sizeof (struct pgrp));
+ if (! pg)
+ return NULL;
+
pg->pg_plist = 0;
pg->pg_pgid = pgid;
pg->pg_orphcnt = 0;
-
+
pg->pg_session = sess;
pg->pg_next = sess->s_pgrps;
if (pg->pg_next)
pg->pg_next->pg_prevp = &pg->pg_next;
sess->s_pgrps = pg;
pg->pg_prevp = &sess->s_pgrps;
-
+
add_pgrp_to_hash (pg);
return pg;
}
@@ -59,14 +63,17 @@ static inline struct session *
new_session (struct proc *p)
{
struct session *sess;
-
+
sess = malloc (sizeof (struct session));
+ if (! sess)
+ return NULL;
+
sess->s_sid = p->p_pid;
sess->s_pgrps = 0;
sess->s_sessionid = MACH_PORT_NULL;
add_session_to_hash (sess);
-
+
return sess;
}
@@ -93,21 +100,21 @@ free_pgrp (struct pgrp *pg)
remove_pgrp_from_hash (pg);
free (pg);
}
-
-/* Implement proc_setsid as described in <hurd/proc.defs>. */
+
+/* Implement proc_setsid as described in <hurd/process.defs>. */
kern_return_t
S_proc_setsid (struct proc *p)
{
struct session *sess;
-
+
if (!p)
return EOPNOTSUPP;
-
+
if (p->p_pgrp->pg_pgid == p->p_pid || pgrp_find (p->p_pid))
return EPERM;
-
+
leave_pgrp (p);
-
+
sess = new_session (p);
p->p_pgrp= new_pgrp (p->p_pid, sess);
join_pgrp (p);
@@ -120,14 +127,15 @@ void
boot_setsid (struct proc *p)
{
struct session *sess;
-
+
sess = new_session (p);
p->p_pgrp = new_pgrp (p->p_pid, sess);
+ assert (p->p_pgrp);
join_pgrp (p);
return;
}
-/* Implement proc_getsid as described in <hurd/proc.defs>. */
+/* Implement proc_getsid as described in <hurd/process.defs>. */
kern_return_t
S_proc_getsid (struct proc *callerp,
pid_t pid,
@@ -143,12 +151,12 @@ S_proc_getsid (struct proc *callerp,
return 0;
}
-/* Implement proc_getsessionpids as described in <hurd/proc.defs>. */
+/* Implement proc_getsessionpids as described in <hurd/process.defs>. */
kern_return_t
S_proc_getsessionpids (struct proc *callerp,
pid_t sid,
pid_t **pids,
- u_int *npidsp)
+ size_t *npidsp)
{
int count;
struct pgrp *pg;
@@ -156,13 +164,13 @@ S_proc_getsessionpids (struct proc *callerp,
struct session *s;
pid_t *pp = *pids;
u_int npids = *npidsp;
-
+
/* No need to check CALLERP; we don't use it. */
s = session_find (sid);
if (!s)
return ESRCH;
-
+
count = 0;
for (pg = s->s_pgrps; pg; pg = pg->pg_next)
for (p = pg->pg_plist; p; p = p->p_gnext)
@@ -170,12 +178,15 @@ S_proc_getsessionpids (struct proc *callerp,
if (++count <= npids)
*pp++ = p->p_pid;
}
-
+
if (count > npids)
/* They didn't all fit */
{
- vm_allocate (mach_task_self (), (vm_address_t *)pids,
- count * sizeof (pid_t), 1);
+ *pids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (*pids == MAP_FAILED)
+ return errno;
+
pp = *pids;
for (pg = s->s_pgrps; pg; pg = pg->pg_next)
for (p = pg->pg_plist; p; p = p->p_gnext)
@@ -192,14 +203,14 @@ kern_return_t
S_proc_getsessionpgids (struct proc *callerp,
pid_t sid,
pid_t **pgids,
- u_int *npgidsp)
+ size_t *npgidsp)
{
int count;
struct pgrp *pg;
struct session *s;
pid_t *pp = *pgids;
int npgids = *npgidsp;
-
+
/* No need to check CALLERP; we don't use it. */
s = session_find (sid);
@@ -210,12 +221,15 @@ S_proc_getsessionpgids (struct proc *callerp,
for (pg = s->s_pgrps; pg; pg = pg->pg_next)
if (++count <= npgids)
*pp++ = pg->pg_pgid;
-
+
if (count > npgids)
/* They didn't all fit. */
{
- vm_allocate (mach_task_self (), (vm_address_t *)pgids,
- count * sizeof (pid_t), 1);
+ *pgids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (*pgids == MAP_FAILED)
+ return errno;
+
pp = *pgids;
for (pg = s->s_pgrps; pg; pg = pg->pg_next)
*pp++ = pg->pg_pgid;
@@ -230,14 +244,14 @@ kern_return_t
S_proc_getpgrppids (struct proc *callerp,
pid_t pgid,
pid_t **pids,
- u_int *npidsp)
+ size_t *npidsp)
{
struct proc *p;
struct pgrp *pg;
pid_t *pp = *pids;
unsigned int npids = *npidsp, count;
-
+
/* No need to check CALLERP; we don't use it. */
if (pgid == 0)
@@ -253,12 +267,15 @@ S_proc_getpgrppids (struct proc *callerp,
for (p = pg->pg_plist; p; p = p->p_gnext)
if (++count <= npids)
*pp++ = p->p_pid;
-
+
if (count > npids)
/* They didn't all fit. */
{
- vm_allocate (mach_task_self (), (vm_address_t *)pids,
- count * sizeof (pid_t), 1);
+ *pids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (*pids == MAP_FAILED)
+ return errno;
+
pp = *pids;
for (p = pg->pg_plist; p; p = p->p_gnext)
*pp++ = p->p_pid;
@@ -268,13 +285,13 @@ S_proc_getpgrppids (struct proc *callerp,
return 0;
}
-/* Implement proc_getsidport as described in <hurd/proc.defs>. */
+/* Implement proc_getsidport as described in <hurd/process.defs>. */
kern_return_t
S_proc_getsidport (struct proc *p,
mach_port_t *sessport, mach_msg_type_name_t *sessport_type)
{
error_t err = 0;
-
+
if (!p)
return EOPNOTSUPP;
@@ -291,7 +308,7 @@ S_proc_getsidport (struct proc *p,
return err;
}
-/* Implement proc_setpgrp as described in <hurd/proc.defs>. */
+/* Implement proc_setpgrp as described in <hurd/process.defs>. */
kern_return_t
S_proc_setpgrp (struct proc *callerp,
pid_t pid,
@@ -299,7 +316,7 @@ S_proc_setpgrp (struct proc *callerp,
{
struct proc *p;
struct pgrp *pg;
-
+
if (!callerp)
return EOPNOTSUPP;
@@ -307,10 +324,10 @@ S_proc_setpgrp (struct proc *callerp,
if (!p || (p != callerp && p->p_parent != callerp))
return ESRCH;
-
+
if (p->p_parent == callerp && p->p_exec)
return EACCES;
-
+
if (!pgid)
pgid = p->p_pid;
pg = pgrp_find (pgid);
@@ -320,7 +337,7 @@ S_proc_setpgrp (struct proc *callerp,
|| ((pgid != p->p_pid
&& (!pg || pg->pg_session != callerp->p_pgrp->pg_session))))
return EPERM;
-
+
if (p->p_pgrp != pg)
{
leave_pgrp (p);
@@ -330,11 +347,11 @@ S_proc_setpgrp (struct proc *callerp,
else
nowait_msg_proc_newids (p->p_msgport, p->p_task, p->p_parent->p_pid,
pg->pg_pgid, !pg->pg_orphcnt);
-
+
return 0;
}
-/* Implement proc_getpgrp as described in <hurd/proc.defs>. */
+/* Implement proc_getpgrp as described in <hurd/process.defs>. */
kern_return_t
S_proc_getpgrp (struct proc *callerp,
pid_t pid,
@@ -343,17 +360,17 @@ S_proc_getpgrp (struct proc *callerp,
struct proc *p = pid_find (pid);
/* No need to check CALLERP; we don't use it. */
-
+
if (!p)
return ESRCH;
-
+
if (p->p_pgrp)
*pgid = p->p_pgrp->pg_pgid;
-
+
return 0;
}
-/* Implement proc_mark_exec as described in <hurd/proc.defs>. */
+/* Implement proc_mark_exec as described in <hurd/process.defs>. */
kern_return_t
S_proc_mark_exec (struct proc *p)
{
@@ -375,7 +392,7 @@ leave_pgrp (struct proc *p)
*p->p_gprevp = p->p_gnext;
if (p->p_gnext)
p->p_gnext->p_gprevp = p->p_gprevp;
-
+
/* If we were the last member of our pgrp, free it */
if (!pg->pg_plist)
free_pgrp (pg);
@@ -387,7 +404,7 @@ leave_pgrp (struct proc *p)
an orphaned process group -- do the orphaning gook */
struct proc *ip;
int dosignal = 0;
-
+
for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
{
if (ip->p_stopped)
@@ -418,7 +435,7 @@ join_pgrp (struct proc *p)
if (pg->pg_plist)
pg->pg_plist->p_gprevp = &p->p_gnext;
pg->pg_plist = p;
-
+
origorphcnt = !!pg->pg_orphcnt;
if (p->p_parent->p_pgrp != pg
&& p->p_parent->p_pgrp->pg_session == pg->pg_session)
diff --git a/proc/primes.c b/proc/primes.c
deleted file mode 100644
index d0fc4d0c..00000000
--- a/proc/primes.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Prime number generation
- Copyright (C) 1994 Free Software Foundation
-
- 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. */
-
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <assert.h>
-
-#define BITS_PER_UNSIGNED (8 * sizeof (unsigned))
-#define SQRT_INT_MAX (1 << (BITS_PER_UNSIGNED / 2))
-
-/* Return the next prime greater than or equal to N. */
-int
-nextprime (unsigned n)
-{
- /* Among other things, We guarantee that, for all i (0 <= i < primes_len),
- primes[i] is a prime,
- next_multiple[i] is a multiple of primes[i],
- next_multiple[i] > primes[primes_len - 1],
- next_multiple[i] is not a multiple of two unless primes[i] == 2, and
- next_multiple[i] is the smallest such value. */
- static unsigned *primes, *next_multiple;
- static int primes_len;
- static int primes_size;
- static unsigned next_sieve; /* always even */
- unsigned max_prime;
-
- if (! primes)
- {
- primes_size = 128;
- primes = (unsigned *) malloc (primes_size * sizeof (*primes));
- next_multiple = (unsigned *) malloc (primes_size
- * sizeof (*next_multiple));
-
- primes[0] = 2; next_multiple[0] = 6;
- primes[1] = 3; next_multiple[1] = 9;
- primes[2] = 5; next_multiple[2] = 15;
- primes_len = 3;
-
- next_sieve = primes[primes_len - 1] + 1;
- }
-
- if (n <= primes[0])
- return primes[0];
-
- while (n > (max_prime = primes[primes_len - 1]))
- {
- /* primes doesn't contain any prime large enough. Sieve from
- max_prime + 1 to 2 * max_prime, looking for more primes. */
- unsigned start = next_sieve;
- unsigned end = start + max_prime + 1;
- char *sieve = (char *) alloca ((end - start) * sizeof (*sieve));
- int i;
-
- assert (sieve);
-
- bzero (sieve, (end - start) * sizeof (*sieve));
-
- /* Make the sieve indexed by prime number, rather than
- distance-from-start-to-the-prime-number. When we're done,
- sieve[P] will be zero iff P is prime.
-
- ANSI C doesn't define what this means. Fuck them. */
- sieve -= start;
-
- /* Set sieve[i] for all composites i, start <= i < end.
- Ignore multiples of 2. */
- for (i = 1; i < primes_len; i++)
- {
- unsigned twice_prime = 2 * primes[i];
- unsigned multiple;
-
- for (multiple = next_multiple[i];
- multiple < end;
- multiple += twice_prime)
- sieve[multiple] = 1;
- next_multiple[i] = multiple;
- }
-
- for (i = start + 1; i < end; i += 2)
- if (! sieve[i])
- {
- if (primes_len >= primes_size)
- {
- primes_size *= 2;
- primes = (int *) realloc (primes,
- primes_size * sizeof (*primes));
- next_multiple
- = (int *) realloc (next_multiple,
- primes_size * sizeof (*next_multiple));
- }
- primes[primes_len] = i;
- if (i >= SQRT_INT_MAX)
- next_multiple[primes_len] = INT_MAX;
- else
- next_multiple[primes_len] = i * i;
- primes_len++;
- }
-
- next_sieve = end;
- }
-
- /* Now we have at least one prime >= n. Find the smallest such. */
- {
- int bottom = 0;
- int top = primes_len;
-
- while (bottom < top)
- {
- int mid = (bottom + top) / 2;
-
- if (primes[mid] < n)
- bottom = mid + 1;
- else
- top = mid;
- }
-
- return primes[top];
- }
-}
-
diff --git a/proc/proc.h b/proc/proc.h
index 30886487..7943e0be 100644
--- a/proc/proc.h
+++ b/proc/proc.h
@@ -1,5 +1,5 @@
/* Process server definitions
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2000,01 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -23,7 +23,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define PROC_H_INCLUDED
#include <sys/resource.h>
+#include <sys/mman.h>
#include <hurd/ports.h>
+#include <hurd/ihash.h>
#include <cthreads.h>
struct proc
@@ -34,8 +36,8 @@ struct proc
struct proc *p_gnext, **p_gprevp; /* process group */
/* Hash table pointers that point here */
- void **p_pidhashloc; /* by pid */
- void **p_taskhashloc; /* by task port */
+ hurd_ihash_locp_t p_pidhashloc; /* by pid */
+ hurd_ihash_locp_t p_taskhashloc; /* by task port */
/* Identification of this process */
task_t p_task;
@@ -64,28 +66,31 @@ struct proc
vm_address_t p_argv, p_envp;
int p_status; /* to return via wait */
int p_sigcode;
-
- int p_exec:1; /* has called proc_mark_exec */
- int p_stopped:1; /* has called proc_mark_stop */
- int p_waited:1; /* stop has been reported to parent */
- int p_exiting:1; /* has called proc_mark_exit */
- int p_waiting:1; /* blocked in wait */
- int p_traced:1; /* has called proc_mark_traced */
- int p_nostopcld:1; /* has called proc_mark_nostopchild */
- int p_parentset:1; /* has had a parent set with proc_child */
- int p_deadmsg:1; /* hang on requests for a message port */
- int p_checkmsghangs:1; /* someone is currently hanging on us */
- int p_msgportwait:1; /* blocked in getmsgport */
- int p_noowner:1; /* has no owner known */
- int p_loginleader:1; /* leader of login collection */
- int p_dead:1; /* process is dead */
+ struct rusage p_rusage; /* my usage if I'm dead, to return via wait */
+
+ struct rusage p_child_rusage; /* accumulates p_rusage of all dead children */
+
+ unsigned int p_exec:1; /* has called proc_mark_exec */
+ unsigned int p_stopped:1; /* has called proc_mark_stop */
+ unsigned int p_waited:1; /* stop has been reported to parent */
+ unsigned int p_exiting:1; /* has called proc_mark_exit */
+ unsigned int p_waiting:1; /* blocked in wait */
+ unsigned int p_traced:1; /* has called proc_mark_traced */
+ unsigned int p_nostopcld:1; /* has called proc_mark_nostopchild */
+ unsigned int p_parentset:1; /* has had a parent set with proc_child */
+ unsigned int p_deadmsg:1; /* hang on requests for a message port */
+ unsigned int p_checkmsghangs:1; /* someone is currently hanging on us */
+ unsigned int p_msgportwait:1; /* blocked in getmsgport */
+ unsigned int p_noowner:1; /* has no owner known */
+ unsigned int p_loginleader:1; /* leader of login collection */
+ unsigned int p_dead:1; /* process is dead */
};
typedef struct proc *pstruct_t;
struct pgrp
{
- void **pg_hashloc;
+ hurd_ihash_locp_t pg_hashloc;
struct proc *pg_plist; /* member processes */
struct pgrp *pg_next, **pg_prevp; /* list of pgrps in session */
pid_t pg_pgid;
@@ -95,7 +100,7 @@ struct pgrp
struct session
{
- void **s_hashloc;
+ hurd_ihash_locp_t s_hashloc;
pid_t s_sid;
struct pgrp *s_pgrps; /* list of member pgrps */
mach_port_t s_sessionid; /* receive right */
@@ -109,10 +114,9 @@ struct login
struct ids
{
- int i_nuids, i_ngids;
- uid_t *i_uids;
- gid_t *i_gids;
int i_refcnt;
+ int i_nuids;
+ uid_t i_uids[0];
};
/* Structure for an exception port we are listening on. */
@@ -143,11 +147,7 @@ mach_port_t generic_port; /* messages not related to a specific proc */
struct mutex global_lock;
-/* Our name for version system */
-#define OUR_SERVER_NAME "proc"
-#define OUR_VERSION "0.0"
-
-extern inline void
+static inline void __attribute__ ((unused))
process_drop (struct proc *p)
{
if (p)
@@ -156,7 +156,6 @@ process_drop (struct proc *p)
/* Forward declarations */
void complete_wait (struct proc *, int);
-int nextprime (int);
int check_uid (struct proc *, uid_t);
void addalltasks (void);
void prociterate (void (*)(struct proc *, void *), void *);
@@ -169,7 +168,7 @@ int genpid ();
void abort_getmsgport (struct proc *);
int zombie_check_pid (pid_t);
void check_message_dying (struct proc *, struct proc *);
-void message_port_dead (struct proc *);
+int check_msgport_death (struct proc *);
void check_dead_execdata_notify (mach_port_t);
void add_proc_to_hash (struct proc *);
@@ -194,7 +193,10 @@ void exc_clean (void *);
struct proc *add_tasks (task_t);
int pidfree (pid_t);
-struct proc *new_proc (task_t);
+struct proc *create_startup_proc (void);
+struct proc *allocate_proc (task_t);
+void proc_death_notify (struct proc *);
+void complete_proc (struct proc *, pid_t);
void leave_pgrp (struct proc *);
void join_pgrp (struct proc *);
@@ -208,17 +210,6 @@ void complete_exit (struct proc *);
void initialize_version_info (void);
void send_signal (mach_port_t, int, mach_port_t);
-
-/* Returns true if PROC1 has `owner' privileges over PROC2 (and can thus get
- its task port &c). If PROC2 has an owner, then PROC1 must have that uid;
- otherwise, both must be in the same login collection. */
-extern inline int
-check_owner (struct proc *proc1, struct proc *proc2)
-{
- return
- proc2->p_noowner
- ? check_uid (proc1, 0) || proc1->p_login == proc2->p_login
- : check_uid (proc1, proc2->p_owner);
-}
+
#endif
diff --git a/proc/stubs.c b/proc/stubs.c
index d43f2ea5..de3a9b11 100644
--- a/proc/stubs.c
+++ b/proc/stubs.c
@@ -1,5 +1,5 @@
/* By-hand stubs for some RPC calls
- Copyright (C) 1994, 1996 Free Software Foundation
+ Copyright (C) 1994,96,99,2000 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
@@ -20,28 +20,55 @@
#include <hurd/hurd_types.h>
#include <mach/message.h>
#include <string.h>
+#include <assert.h>
#include "proc.h"
/* From hurd/msg.defs: */
#define RPCID_SIG_POST 23000
-struct msg_spec
+
+struct msg_sig_post_request
{
- int len;
- void *contents;
+ mach_msg_header_t head;
+ mach_msg_type_t signaltype;
+ int signal;
+ mach_msg_type_t sigcode_type;
+ natural_t sigcode;
+ mach_msg_type_t refporttype;
+ mach_port_t refport;
};
-/* Send the Mach message indicated by msg_spec; call cthread_exit
+/* Send the Mach message indicated by msg_spec. call cthread_exit
when it has been delivered. */
-static void
-blocking_message_send (struct msg_spec *message)
+static any_t
+blocking_message_send (any_t arg)
{
- cthread_wire ();
- mach_msg ((mach_msg_header_t *)message->contents, MACH_SEND_MSG,
- message->len, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL);
- cthread_exit (0);
+ struct msg_sig_post_request *const req = arg;
+ error_t err;
+
+ err = mach_msg (&req->head, MACH_SEND_MSG, sizeof *req, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+ switch (err)
+ {
+ /* These are the codes that mean a pseudo-receive modified
+ the message buffer and we might need to clean up the send rights.
+ None of them should be possible in our usage. */
+ case MACH_SEND_TIMED_OUT:
+ case MACH_SEND_INTERRUPTED:
+ case MACH_SEND_INVALID_NOTIFY:
+ case MACH_SEND_NO_NOTIFY:
+ case MACH_SEND_NOTIFY_IN_PROGRESS:
+ assert_perror (err);
+ break;
+
+ default: /* Other errors are safe to ignore. */
+ break;
+ }
+
+
+ return 0;
}
/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't
@@ -53,84 +80,89 @@ send_signal (mach_port_t msgport,
{
error_t err;
- static struct
+ /* This message buffer might be modified by mach_msg in some error cases,
+ so we cannot safely use a shared static buffer. */
+ struct msg_sig_post_request message =
+ {
{
- mach_msg_header_t head;
- mach_msg_type_t signaltype;
- int signal;
- mach_msg_type_t sigcode_type;
- natural_t sigcode;
- mach_msg_type_t refporttype;
- mach_port_t refport;
- }
- message =
+ /* Message header: */
+ (MACH_MSGH_BITS_COMPLEX
+ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */
+ sizeof message, /* msgh_size */
+ msgport, /* msgh_remote_port */
+ MACH_PORT_NULL, /* msgh_local_port */
+ 0, /* msgh_seqno */
+ RPCID_SIG_POST, /* msgh_id */
+ },
{
- {
- /* Message header: */
- (MACH_MSGH_BITS_COMPLEX
- | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
- MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */
- sizeof message, /* msgh_size */
- 0, /* msgh_remote_port */
- MACH_PORT_NULL, /* msgh_local_port */
- 0, /* msgh_seqno */
- RPCID_SIG_POST, /* msgh_id */
- },
- {
- /* Type descriptor for signo */
- MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
- 32, /* msgt_size */
- 1, /* msgt_number */
- 1, /* msgt_inline */
- 0, /* msgt_longform */
- 0, /* msgt_deallocate */
- 0, /* msgt_unused */
- },
- /* Signal number */
- 0,
- /* Type descriptor for sigcode */
- {
- MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
- 32, /* msgt_size */
- 1, /* msgt_number */
- 1, /* msgt_inline */
- 0, /* msgt_longform */
- 0, /* msgt_deallocate */
- 0, /* msgt_unused */
- },
- /* Sigcode */
- 0,
- {
- /* Type descriptor for refport */
- MACH_MSG_TYPE_COPY_SEND, /* msgt_name */
- 32, /* msgt_size */
- 1, /* msgt_number */
- 1, /* msgt_unline */
- 0, /* msgt_longform */
- 0, /* msgt_deallocate */
- 0, /* msgt_unused */
- },
- /* Reference port */
- MACH_PORT_NULL,
- };
-
- message.head.msgh_remote_port = msgport;
- message.signal = signal;
- message.refport = refport;
-
- err = mach_msg((mach_msg_header_t *)&message,
- MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0,
- MACH_PORT_NULL, 0, MACH_PORT_NULL);
-
- if (err == MACH_SEND_TIMEOUT)
+ /* Type descriptor for signo */
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Signal number */
+ signal,
+ /* Type descriptor for sigcode */
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Sigcode */
+ 0,
{
- struct msg_spec *msg_spec = malloc (sizeof (struct msg_spec));
-
- msg_spec->len = sizeof message;
- msg_spec->contents = malloc (sizeof message);
- bcopy (&message, msg_spec->contents, sizeof message);
-
- cthread_detach (cthread_fork ((cthread_fn_t) blocking_message_send,
- msg_spec));
+ /* Type descriptor for refport */
+ MACH_MSG_TYPE_COPY_SEND, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ refport
+ };
+
+ err = mach_msg ((mach_msg_header_t *)&message,
+ MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0,
+ MACH_PORT_NULL, 0, MACH_PORT_NULL);
+ switch (err)
+ {
+ case MACH_SEND_TIMED_OUT:
+ /* The send could not complete immediately, and we do not want to
+ block. We'll fork off another thread to do the blocking send.
+ The message buffer was modified by a pseudo-receive operation, so
+ we need to copy its modified contents into a malloc'd buffer. */
+ {
+ struct msg_sig_post_request *copy = malloc (sizeof *copy);
+ if (copy)
+ {
+ memcpy (copy, &message, sizeof message);
+ cthread_detach (cthread_fork (blocking_message_send, copy));
+ }
+ break;
+ }
+
+ /* These are the other codes that mean a pseudo-receive modified
+ the message buffer and we might need to clean up the send rights.
+ None of them should be possible in our usage. */
+ case MACH_SEND_INTERRUPTED:
+ case MACH_SEND_INVALID_NOTIFY:
+ case MACH_SEND_NO_NOTIFY:
+ case MACH_SEND_NOTIFY_IN_PROGRESS:
+ assert_perror (err);
+ break;
+
+ default: /* Other errors are safe to ignore. */
+ break;
}
}
diff --git a/proc/wait.c b/proc/wait.c
index 60ec58ff..6fc94e83 100644
--- a/proc/wait.c
+++ b/proc/wait.c
@@ -1,5 +1,5 @@
/* Implementation of wait
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 2001 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,6 +19,8 @@
#include <sys/types.h>
#include <hurd/hurd_types.h>
#include <sys/resource.h>
+#include <sys/time.h>
+#include <mach/task_info.h>
#include "proc.h"
@@ -32,7 +34,95 @@
#include "process_S.h"
#include <mach/mig_errors.h>
-#define EWOULDBLOCK EAGAIN /* XXX */
+static inline void
+rusage_add (struct rusage *acc, const struct rusage *b)
+{
+ timeradd (&acc->ru_utime, &b->ru_utime, &acc->ru_utime);
+ timeradd (&acc->ru_stime, &b->ru_stime, &acc->ru_stime);
+
+ /* Check <bits/resource.h> definition of `struct rusage'
+ to make sure this gets all the fields. */
+ acc->ru_maxrss += b->ru_maxrss;
+ acc->ru_ixrss += b->ru_ixrss;
+ acc->ru_idrss += b->ru_idrss;
+ acc->ru_isrss += b->ru_isrss;
+ acc->ru_minflt += b->ru_minflt;
+ acc->ru_majflt += b->ru_majflt;
+ acc->ru_nswap += b->ru_nswap;
+ acc->ru_inblock += b->ru_inblock;
+ acc->ru_oublock += b->ru_oublock;
+ acc->ru_msgsnd += b->ru_msgsnd;
+ acc->ru_msgrcv += b->ru_msgrcv;
+ acc->ru_nsignals += b->ru_nsignals;
+ acc->ru_nvcsw += b->ru_nvcsw;
+ acc->ru_nivcsw += b->ru_nivcsw;
+}
+
+/* XXX This is real half-assed.
+
+ We want to collect usage statistics from dead processes to return to its
+ parent for its proc_wait calls and its aggregate child statistics.
+
+ The microkernel provides no access to this information once the task is
+ terminated. So the best we can do is take a sample at some time while
+ the task is still alive but not too long before it dies. Our results
+ are always inaccurate, because they don't account for the final part of
+ the task's lifetime. But perhaps it's better than nothing at all.
+
+ The obvious place to take this sample is in proc_mark_exit, which in
+ normal circumstances a task is calling immediately before terminating
+ itself. So in the best of cases, our data omits only the interval in
+ which our RPC returns to the task and it calls task_terminate. We could
+ take samples in other places just to have something rather than nothing
+ if the task dies unexpectedly (e.g. SIGKILL); but it may not be worthwhile
+ since the end result is never going to be accurate anyway.
+
+ The only way to get correct results is by adding some microkernel
+ feature to report the task statistics data post-mortem. */
+
+void
+sample_rusage (struct proc *p)
+{
+ struct task_basic_info bi;
+ struct task_events_info ei;
+ struct task_thread_times_info tti;
+ mach_msg_type_number_t count;
+ error_t err;
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info (p->p_task, TASK_BASIC_INFO,
+ (task_info_t) &bi, &count);
+ if (err)
+ memset (&bi, 0, sizeof bi);
+
+ count = TASK_EVENTS_INFO_COUNT;
+ err = task_info (p->p_task, TASK_EVENTS_INFO,
+ (task_info_t) &ei, &count);
+ if (err)
+ memset (&ei, 0, sizeof ei);
+
+ count = TASK_THREAD_TIMES_INFO_COUNT;
+ err = task_info (p->p_task, TASK_THREAD_TIMES_INFO,
+ (task_info_t) &tti, &count);
+ if (err)
+ memset (&tti, 0, sizeof tti);
+
+ time_value_add (&bi.user_time, &tti.user_time);
+ time_value_add (&bi.system_time, &tti.system_time);
+
+ memset (&p->p_rusage, 0, sizeof (struct rusage));
+
+ p->p_rusage.ru_utime.tv_sec = bi.user_time.seconds;
+ p->p_rusage.ru_utime.tv_usec = bi.user_time.microseconds;
+ p->p_rusage.ru_stime.tv_sec = bi.system_time.seconds;
+ p->p_rusage.ru_stime.tv_usec = bi.system_time.microseconds;
+
+ /* These statistics map only approximately. */
+ p->p_rusage.ru_majflt = ei.pageins;
+ p->p_rusage.ru_minflt = ei.faults - ei.pageins;
+ p->p_rusage.ru_msgsnd = ei.messages_sent; /* Mach IPC, not SysV IPC */
+ p->p_rusage.ru_msgrcv = ei.messages_received; /* ditto */
+}
/* Return nonzero if a `waitpid' on WAIT_PID by a process
in MYPGRP cares about the death of PID/PGRP. */
@@ -46,11 +136,14 @@ waiter_cares (pid_t wait_pid, pid_t mypgrp,
(wait_pid == WAIT_MYPGRP && pgrp == mypgrp));
}
-/* A process is dying. Send SIGCHLD to the parent. Wake the parent
-if it is waiting for us to exit. */
+/* A process is dying. Send SIGCHLD to the parent.
+ Wake the parent if it is waiting for us to exit. */
void
alert_parent (struct proc *p)
{
+ /* We accumulate the aggregate usage stats of all our dead children. */
+ rusage_add (&p->p_parent->p_child_rusage, &p->p_rusage);
+
send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task);
if (!p->p_exiting)
@@ -78,73 +171,59 @@ S_proc_wait (struct proc *p,
pid_t *pid_status)
{
int cancel;
-
- int child_ready (struct proc *child)
+
+ int reap (struct proc *child)
{
- if (child->p_waited)
+ if (child->p_waited
+ || (!child->p_dead
+ && (!child->p_stopped
+ || !(child->p_traced || (options & WUNTRACED)))))
return 0;
+ child->p_waited = 1;
+ *status = child->p_status;
+ *sigcode = child->p_sigcode;
+ *ru = child->p_rusage; /* all zeros if !p_dead */
+ *pid_status = child->p_pid;
if (child->p_dead)
- return 1;
- if (!child->p_stopped)
- return 0;
- if (child->p_traced || (options & WUNTRACED))
- return 1;
- return 0;
+ complete_exit (child);
+ return 1;
}
if (!p)
return EOPNOTSUPP;
-
+
start_over:
/* See if we can satisfy the request with a stopped
child; also check for invalid arguments here. */
- if (!p->p_ochild)
+ if (!p->p_ochild)
return ECHILD;
-
+
if (pid > 0)
{
struct proc *child = pid_find_allow_zombie (pid);
if (!child || child->p_parent != p)
return ECHILD;
- if (child_ready (child))
- {
- child->p_waited = 1;
- *status = child->p_status;
- *sigcode = child->p_sigcode;
- if (child->p_dead)
- complete_exit (child);
- bzero (ru, sizeof (struct rusage));
- *pid_status = pid;
- return 0;
- }
+ if (reap (child))
+ return 0;
}
else
{
struct proc *child;
int had_a_match = pid == 0;
-
+
for (child = p->p_ochild; child; child = child->p_sib)
if (waiter_cares (pid, p->p_pgrp->pg_pgid,
child->p_pid, child->p_pgrp->pg_pgid))
{
+ if (reap (child))
+ return 0;
had_a_match = 1;
- if (child_ready (child))
- {
- child->p_waited = 1;
- *status = child->p_status;
- *sigcode = child->p_sigcode;
- *pid_status = child->p_pid;
- if (child->p_dead)
- complete_exit (child);
- bzero (ru, sizeof (struct rusage));
- return 0;
- }
}
if (!had_a_match)
return ECHILD;
}
-
+
if (options & WNOHANG)
return EWOULDBLOCK;
@@ -157,7 +236,7 @@ S_proc_wait (struct proc *p,
goto start_over;
}
-/* Implement proc_mark_stop as described in <hurd/proc.defs>. */
+/* Implement proc_mark_stop as described in <hurd/process.defs>. */
kern_return_t
S_proc_mark_stop (struct proc *p,
int signo,
@@ -170,20 +249,20 @@ S_proc_mark_stop (struct proc *p,
p->p_status = W_STOPCODE (signo);
p->p_sigcode = sigcode;
p->p_waited = 0;
-
+
if (p->p_parent->p_waiting)
{
condition_broadcast (&p->p_parent->p_wakeup);
p->p_parent->p_waiting = 0;
}
-
+
if (!p->p_parent->p_nostopcld)
send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task);
return 0;
}
-/* Implement proc_mark_exit as described in <hurd/proc.defs>. */
+/* Implement proc_mark_exit as described in <hurd/process.defs>. */
kern_return_t
S_proc_mark_exit (struct proc *p,
int status,
@@ -191,17 +270,22 @@ S_proc_mark_exit (struct proc *p,
{
if (!p)
return EOPNOTSUPP;
-
+
if (WIFSTOPPED (status))
return EINVAL;
-
+
+ sample_rusage (p); /* See comments above sample_rusage. */
+
+ if (p->p_exiting)
+ return EBUSY;
+
p->p_exiting = 1;
p->p_status = status;
p->p_sigcode = sigcode;
return 0;
}
-/* Implement proc_mark_cont as described in <hurd/proc.defs>. */
+/* Implement proc_mark_cont as described in <hurd/process.defs>. */
kern_return_t
S_proc_mark_cont (struct proc *p)
{
@@ -211,7 +295,7 @@ S_proc_mark_cont (struct proc *p)
return 0;
}
-/* Implement proc_mark_traced as described in <hurd/proc.defs>. */
+/* Implement proc_mark_traced as described in <hurd/process.defs>. */
kern_return_t
S_proc_mark_traced (struct proc *p)
{
@@ -221,7 +305,7 @@ S_proc_mark_traced (struct proc *p)
return 0;
}
-/* Implement proc_mark_nostopchild as described in <hurd/proc.defs>. */
+/* Implement proc_mark_nostopchild as described in <hurd/process.defs>. */
kern_return_t
S_proc_mod_stopchild (struct proc *p,
int value)
@@ -232,4 +316,3 @@ S_proc_mod_stopchild (struct proc *p,
p->p_nostopcld = ! value;
return 0;
}
-
diff --git a/release/=announce-0.0 b/release/=announce-0.0
index 08d610ac..7aa1fa9f 100644
--- a/release/=announce-0.0
+++ b/release/=announce-0.0
@@ -6,17 +6,23 @@ anonymous FTP from prep.ai.mit.edu [18.159.0.42] in the file
This file contains complete source code for the following:
-Hurd servers: auth, crash, devio, devport, exec, ext2fs, fifo, fwd,
-ifsock, init, magic, new-fifo, nfs, null, pfinet, pflocal, proc,
-symlink, term, ufs.
+Hurd servers:
+
+ auth, crash, devio, devport, exec, ext2fs, fifo, fwd, ifsock, init,
+ magic, new-fifo, nfs, null, pfinet, pflocal, proc, symlink, term,
+ ufs.
-Hurd libraries: diskfs, fshelp, ihash, iohelp, netfs, pager, pipe,
-ports, ps, shouldbeinlibc, store, threads, trivfs.
+Hurd libraries:
+
+ diskfs, fshelp, ihash, iohelp, netfs, pager, pipe, ports, ps,
+ shouldbeinlibc, store, threads, trivfs.
-Hurd utilities, etc: boot, shd, ps, settrans, showtrans, sync, su,
-mount, fsysopts, storeinfo, login, w, uptime, hurdids, loginpr, sush,
-vmstat, portinfo, devprobe, reboot, halt, fsck, fsck.ufs, mkfs.ufs,
-clri.ufs, stati.ufs, getty, rc.
+Hurd utilities and other programs:
+
+ boot, shd, ps, settrans, showtrans, sync, su, mount, fsysopts,
+ storeinfo, login, w, uptime, hurdids, loginpr, sush, vmstat,
+ portinfo, devprobe, reboot, halt, fsck, fsck.ufs, mkfs.ufs, clri.ufs,
+ stati.ufs, getty, rc.
------
@@ -46,12 +52,12 @@ This release may be fetched by anonymous FTP from prep.ai.mit.edu
In that directory, you should find the following files:
-README
-SOURCES
-INSTALL-binary
-grub-boot.image (about 1.4 MB, not compressed)
-gnu-0.0.tar.gz (about 56.9 MB compressed)
-gnu-0.0-stripped.tar.gz (about 26.2 MB compressed)
+ README
+ SOURCES
+ INSTALL-binary
+ grub-boot.image (about 1.4 MB, not compressed)
+ gnu-0.0.tar.gz (about 56.9 MB compressed)
+ gnu-0.0-stripped.tar.gz (about 26.2 MB compressed)
SOURCES contains a complete list describing the sources for the
binaries found in the image. INSTALL-binary contains complete
@@ -78,13 +84,13 @@ in order to complete part of the installation instructions.
The following free software packages are found in this release:
-autoconf, automake, bash, bc, binutils, bison, cpio, cvs, diffutils,
-doschk, e2fsprogs, ed, emacs, fileutils, findutils, flex, from, gawk,
-gcal, gcc, gdb, gdbm, gettext, glibc, gmp, gperf, grep, grub, gzip,
-hello, hurd, indent, inetutils, less, mach, make, m4, miscfiles,
-ncurses, nethack, nvi, patch, ptx, rcs, readline, recode, sed,
-serverboot, sharutils, shellutils, tar, termcap, termutils, texinfo,
-textutils, time, wdiff.
+ autoconf, automake, bash, bc, binutils, bison, cpio, cvs, diffutils,
+ doschk, e2fsprogs, ed, emacs, fileutils, findutils, flex, from, gawk,
+ gcal, gcc, gdb, gdbm, gettext, glibc, gmp, gperf, grep, grub, gzip,
+ hello, hurd, indent, inetutils, less, mach, make, m4, miscfiles,
+ ncurses, nethack, nvi, patch, ptx, rcs, readline, recode, sed,
+ serverboot, sharutils, shellutils, tar, termcap, termutils, texinfo,
+ textutils, time, wdiff.
------
@@ -95,11 +101,10 @@ Here are md5sum checksums for the files mentioned in this message:
b5f888bab3eb193fe97a00a141324c9d INSTALL-binary
345dcd826747d7b11fc78f4db162d75b README
1a5744bb4ed3448045fa6d24153d65fe SOURCES
-
-
-
+f7b1bc428bc4ee29977a5b28f5762092 gnu-0.0-stripped.tar.gz
+24554c58e5c89f295176e17d21dbae8e gnu-0.0.tar.gz
8338c619d860b71bc4128c9c0fd39d63 grub-boot.image
-
+1fd18ccc4c81d051b83d28b13dc07ee2 hurd-0.0.tar.gz
-----
diff --git a/release/=announce-0.1 b/release/=announce-0.1
new file mode 100644
index 00000000..b33af968
--- /dev/null
+++ b/release/=announce-0.1
@@ -0,0 +1,70 @@
+
+
+I am pleased to announce version 0.1 of the GNU Hurd, available via
+anonymous FTP from prep.ai.mit.edu [18.159.0.42] in the file
+/pub/gnu/hurd-0.1.tar.gz (about 1.2 MB compressed). There is also a
+patch file of diffs from the 0.0 release in
+/pub/gnu/hurd-0.0-0.1-diff.gz (about 75 KB compressed).
+
+(The GNU Hurd, plus Mach, is a kernel, not an operating system. The
+GNU operating system, like the Unix operating system, consists of many
+components, including kernel, libraries, compilers, assembler, shell,
+parser generators, utilities, window system, editors, text formatters,
+and so on. The GNU project set out a decade ago to develop this
+system, and we've been writing various components of it ever since.)
+
+This release contains many bug fixes from version 0.0. Many thanks to
+all the people who are helping find bugs!
+
+The best way you can help find bugs is to try and compile and use on
+the Hurd as many programs as you can find and find out where bugs
+still exist. There are also unimplemented features, and your reports
+will help us to prioritize which things we work on.
+
+Brief description of important news:
+
+ This release contains several new utilities:
+ * e2os
+ which modifies the "creator OS" field of an ext2fs filesystem
+ * nfsd
+ which implements an NFS server. It's still relatively untested,
+ so people are invited to use it for non-critical things and
+ report on successes and failures.
+ * vminfo
+ prints the virtual memory map of a process
+
+ This release contains one new shared library, `hurdbugaddr' which is
+ only used internally to various Hurd servers and utilities.
+
+ Problems in version 0.1 that prevented ext2fs from working correctly
+ have all been fixed, and the source files that were accidentally
+ missing from 0.0 have been added.
+
+For more detailed news, see the NEWS file in the distribution.
+
+There is no binary release corresponding to this source release. A
+new binary release will probably be made together with the next source
+release.
+
+This release contains complete source code for the following:
+
+Hurd servers:
+
+ auth, crash, devio, devport, exec, ext2fs, fifo, fwd, ifsock, init,
+ magic, new-fifo, nfs, null, pfinet, pflocal, proc, symlink, term,
+ ufs.
+
+Hurd libraries:
+
+ diskfs, fshelp, ihash, iohelp, netfs, pager, pipe, ports, ps,
+ shouldbeinlibc, store, threads, trivfs, hurdbugaddr.
+
+Hurd utilities and other programs:
+
+ boot, shd, ps, settrans, showtrans, sync, su, mount, fsysopts,
+ storeinfo, login, w, uptime, hurdids, loginpr, sush, vmstat,
+ portinfo, devprobe, reboot, halt, fsck, fsck.ufs, mkfs.ufs, clri.ufs,
+ stati.ufs, getty, rc, e2os, vminfo, nfsd.
+
+
+Thomas Bushnell, n/BSG
diff --git a/release/=announce-0.2 b/release/=announce-0.2
new file mode 100644
index 00000000..2d67687a
--- /dev/null
+++ b/release/=announce-0.2
@@ -0,0 +1,62 @@
+I am pleased to announce version 0.2 of the GNU Hurd, available via
+anonymous FTP from prep.ai.mit.edu [18.159.0.42] in the file
+/pub/gnu/hurd-0.2.tar.gz (about 1.37 MB compressed).
+
+(The GNU Hurd, plus Mach, is a kernel, not an operating system. The
+GNU operating system, like the Unix operating system, consists of many
+components, including kernel, libraries, compilers, assembler, shell,
+parser generators, utilities, window system, editors, text formatters,
+and so on. The GNU project set out a decade ago to develop this
+system, and we've been writing various components of it ever since.)
+
+This release contains many bug fixes from version 0.1. Many thanks to
+all the people who are helping find bugs!
+
+The best way you can help find bugs is to try and compile and use on
+the Hurd as many programs as you can find and find out where bugs
+still exist. There are also unimplemented features, and your reports
+will help us to prioritize which things we work on.
+
+The system is vastly more reliable than it has been in the past.
+
+One important addition:
+
+ New programs addauth, rmauth, unsu, su, and setauth modify the uid
+ sets of running programs. Using addauth you can add root to your
+ emacs, write a file, and then use rmauth to take the uid back. (Of
+ course, passwords are required when necessary.) New program `ids'
+ will tell you what all the user ids are that a program has. Note
+ that in the Hurd a program can have several user ids all at once,
+ just like Unix supports having several group ids. Now that you can
+ dynamically change the ids of running programs, system
+ administration (among other things) becomes much easier.
+
+For more detailed news, see the NEWS file in the distribution.
+
+This release contains complete source code for the following:
+
+Hurd servers:
+
+ auth, crash, devport, exec, ext2fs, fifo, fwd, ifsock, init,
+ magic, new-fifo, nfs, null, pfinet, pflocal, proc, symlink, term,
+ ufs, storeio, firmlink.
+
+Hurd libraries:
+
+ diskfs, fshelp, ihash, iohelp, netfs, pager, pipe, ports, ps,
+ shouldbeinlibc, store, threads, trivfs, hurdbugaddr, ftpconn
+
+Hurd utilities and other programs:
+
+ boot, shd, ps, settrans, showtrans, sync, su, mount, fsysopts,
+ storeinfo, login, w, uptime, ids, sush, vmstat, portinfo, devprobe,
+ reboot, halt, fsck, fsck.ufs, mkfs.ufs, clri.ufs, stati.ufs, getty,
+ rc, e2os, vminfo, nfsd, mail.local, serverboot, MAKEDEV, loginpr,
+ addauth, rmauth, unsu, setauth, ftpcp, ftpdir.
+
+We are also making a complete GNU 0.2 binary release, which will
+include Hurd 0.2, glibc 2.0.4, gnumach 1.1.2, and many other
+programs. This binary release is announced separately.
+
+
+Thomas Bushnell, n/BSG
diff --git a/release/ChangeLog b/release/ChangeLog
deleted file mode 100644
index 5bea60d1..00000000
--- a/release/ChangeLog
+++ /dev/null
@@ -1,110 +0,0 @@
-Mon Aug 5 11:44:30 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * SETUP: Put `r' before BOOT_DEV in call to INSTALL-GRUB-MBR.
- Repair syntax of test to see if BOOT_DEV is valid.
-
- * Makefile (dist-links): Use correct pathnames for `ln' commands;
- use -f. Repair touch command to avoid {}.
-
-Wed Jul 31 13:15:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * install-stripped (copy/copyattrs): New function.
- (copy/plaincopy, copy/objcopy, copy): Use copyattrs.
-
- * Makefile (install-tools): Copy from the right place. Make the
- installed install-stripped executable.
-
-Tue Jul 30 12:05:54 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * INSTALL-binary: Don't make stupid claims about avoiding use of
- cylinder zero.
-
-Mon Jul 29 14:47:53 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * checklist: Add cc to the list of symlinks to check.
-
-Thu Jul 25 23:22:47 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * checklist: Add vmstat to the list of setuid programs.
-
-Thu Jul 18 18:27:14 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * SETUP: Install grub with INSTALL-GRUB-MBR if desired.
-
- * INSTALL-GRUB-MBR: Fix quoting in last echo.
-
-Wed Jul 17 00:17:05 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * INSTALL-binary: Yet more changes.
-
-Tue Jul 16 23:41:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (dist-files): boot-menu.grub -> menu.lst.
- (install-dist): Likewise; also put it in /boot/grub and don't
- bother with link in /etc.
- * menu.lst: Renamed from boot-menu.grub.
-
-Mon Jul 15 17:18:05 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * INSTALL-binary: Many changes.
-
- * boot-menu.grub: Rewritten; much nicer now.
-
-Mon Jul 15 15:58:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * INSTALL-GRUB-MBR: Only read first block of disk as mbr.
- "in)" -> "in".
-
- (INSTALL-GRUB-MBR): New file.
- * Makefile (dist-files): Add INSTALL-GRUB-MBR.
- (install-dist): Install INSTALL-GRUB-MBR.
-
-Sun Jul 14 20:21:12 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * servers.boot: That's STATIC ufs.
-
-Sat Jul 13 18:06:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * SETUP: Make ptys too.
-
- * SETUP: Setup /servers/crash too.
-
- * COPYING.LIB: New file.
- * Makefile (install-dist): Install COPYING.LIB and COPYING.
- Fix commands to install most everything from $(srcdir).
-
- * boot-menu.grub: New file.
- * servers.boot: New file.
- * Makefile (dist-files): Add servers.boot and boot-menu.grub.
- (install-dist): Install servers.boot and boot-menu.grub.
- (dist-links): Create $(dist-root)/boot.
-
- * INSTALL-binary: Various changes.
-
-Fri Jul 12 15:18:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * install-stripped (makelocalhardlink): Only do cleverness if TO
- already exists. If it's not there, just make the link.
-
-Tue Jul 9 20:10:21 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * INSTALL-binary: Changed.
-
-Tue Jul 9 18:03:45 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * INSTALL-binary: Various changes.
-
- * Makefile (install-dist): Depend on dist-links.
- (dist-links): New target.
-
- * SETUP: Put pflocal on /servers/socket/local (which will be a
- link to /servers/socket/1).
-
- * SETUP: Set root writable before doing anything else; offer to
- reboot the system when through.
-
-Mon Jul 8 17:47:58 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * INSTALL-binary: Various changes.
-
-
diff --git a/release/INSTALL-GRUB-MBR b/release/INSTALL-GRUB-MBR
deleted file mode 100644
index ce15ea77..00000000
--- a/release/INSTALL-GRUB-MBR
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-# Install grub stage1 as the MBR, copying the dos partition table from the
-# existing MBR.
-
-DEV="$1"
-
-if [ ! "$DEV" -o ! -w "$DEV" ]; then
- echo 2>&1 "Usage: $0 DEVICE"
- exit 1
-fi
-
-case "$DEV" in
- *r?d[0-9])
- ;;
- *)
- echo "The device $DEV doesn't seem to be a whole-disk raw device; continue? [n] "
- read C
- case "$C" in
- [Yy]*)
- ;;
- *)
- echo 2>&1 "$0: Aborting";
- exit 2
- ;;
- esac
- ;;
-esac
-
-cd /tmp
-
-dd if="$DEV" of=mbr bs=512 count=1 \
-&& cp /boot/grub/stage1_ffs stage1 \
-&& dd if=mbr of=stage1 conv=notrunc bs=1 seek=446 skip=446 count=64 \
-&& dd if=stage1 of="$DEV" bs=512 count=1 \
-|| { echo 2>&1 "$0: Install failed!" ; exit 5 ; }
-
-rm mbr stage1
-
-echo "$0: /boot/grub/stage1_ffs installed in MBR"
-echo "$0: Don't forget to use the grub \`install=' command to install stage2"
diff --git a/release/INSTALL-binary b/release/INSTALL-binary
index e3416437..d13beb8c 100644
--- a/release/INSTALL-binary
+++ b/release/INSTALL-binary
@@ -1,6 +1,6 @@
-*- Text -*-
Instructions for bootstrapping the Hurd from binary images (i386).
-GNU Version 0.0
+GNU Version 0.2
This is the Hurd. Welcome.
@@ -15,10 +15,9 @@ Library General Public when distributing this binary snapshot. See
licenses.
If you have noticed that these steps are rather long and a bit too
-complex, you are right. But we didn't want to delay the release just
-in order to make the installation prettier. You can rest assured,
-however: Making it prettier and easier is one of our more important
-priorities.
+complex, you are right. One of our upcoming tasks is to develop a
+convenient package mechanism and more streamlined installation
+procedure.
Bug reports for programs in this distribution should be sent to the
maintainer of the program. For a complete list of which mailing lists
@@ -36,9 +35,6 @@ In addition, bug reports or requests for help in using the system as a
connected whole (as opposed to for particular programs) should be sent
to the hurd mailing lists.
-If any of these mailing address should fail, send your message to
-`tower@gnu.ai.mit.edu' and ask him to forward it properly.
-
STEP I:
@@ -50,10 +46,7 @@ file onto a fresh floppy with the command:
This is your `grub boot floppy', referred to below.
Unpack the binary distribution onto a fresh disk partition, which
-needs to be BSD FFS format. We have not prepared instructions for
-setting up the system from an existing Linux-based system because of
-time pressures. But all the tools and pieces should work for the more
-stalwart souls to try it.
+needs to be BSD FFS format or Linux ext2fs format.
Start with a system already running BSD:
@@ -66,15 +59,31 @@ Start with a system already running BSD:
entire Hurd image into it. Make sure you do this as root, and
remember to give tar the `p' option.
-If you do not have a system running BSD, you can install using the
-NetBSD boot floppies:
+Start with a system already running a GNU/Linux system:
+
+ Again, we suggest using a fresh disk. But you can also use an
+ existing partition. Make it big enough to hold the entire Hurd
+ binary image, and then some. Make sure you have a partition for
+ swap too. Extract the binary image onto the new partition using
+ tar; make sure you sue the `p' option to tar.
+
+ You need to set the "owning OS" field for this filesystem to "hurd";
+ otherwise you will not be able to use Hurd-related extensions on
+ it. (And using those extensions is required on the root
+ filesystem.) Run the command `e2os DEVICE hurd' after the
+ filesystem is unmounted in order to accomplish this.
+
+If you do not have a system running BSD or a GNU/Linux system, you can
+install using the NetBSD boot floppies. To do this, you do NOT need
+to install NetBSD; you will just be using their boot floppies
+briefly.
Unpack the entire Hurd image somewhere accessible by NFS. Then see
the instruction subroutine in this file labelled `Installing from
NetBSD boot floppies' and follow them.
-We plan to have our own boot floppies soon, which will make this all a
-fair bit easier.
+We plan to have our own boot floppies, which will make this all a fair
+bit easier.
@@ -91,6 +100,11 @@ name (this is a mach partition name), or comment out the line if you
don't want paging. Note that you don't have to do anything to
initialize swap partitions, unlike Linux.
+If your filesystem is an ext2fs filesystem (if you are starting with a
+system already running a GNU/Linux system, for example), then you also
+should change the reference to /hurd/ufs.static into a reference to
+/hurd/ext2fs.static.
+
(If you did STEP I using NetBSD boot floppies, then this file should
be /mnt/boot/servers.boot.)
@@ -126,17 +140,12 @@ and you may notice that pipes don't work.
In order to set up the translators for this to be a fully functional
Hurd system, say
- /bin/sh /SETUP disk
-
-where `disk' is the name of the disk to install the boot block on,
-without partition name, for example `sd0' or `hd0'. (If you give no
-arg, it will ask you for the device to install the boot block on in
-case you forgot. If you really don't want a boot block, just hit RET
-when it asks.)
+ /bin/sh /SETUP
This will set up some initial translators so that the system runs
-normally, and then offer to reboot the system. When it comes back up,
-boot it single-user again, so that you can do step V.
+normally, and then offer to reboot the system. When you get to the
+GRUB menu, do step V.
+
NOTE: Do NOT RUN BSD FSCK on a Hurd FFS!
@@ -157,10 +166,11 @@ NOTE: Do NOT RUN BSD FSCK on a Hurd FFS!
STEP V:
-Now boot from the floppy again. This time, select the "grub install"
-option. (If your disk isn't known as hd0 to grub, then you will need
-to edit the commands accordingly.) Reset your PC and take the floppy
-disk out of the drive. The hard disk should now boot successfully.
+Now boot from the floppy again. This time, select the option to
+install grub from the floppy. (If your disk isn't known as hd0 to
+grub, then you will need to edit the commands accordingly.) Reset
+your PC and take the floppy disk out of the drive. The hard disk
+should now boot successfully.
Select the single-user boot menu option, and proceed to STEP VI.
@@ -185,10 +195,8 @@ Say `./MAKEDEV dev1 dev2 dev3 ...'.
Supported devices are:
o any hard disk device you have; you must specify both unit number *and*
- partition. Something like `sd0a' or `rd1f' is called for. Unit
- number without any partition names the entire disk. (SETUP has
- already created a device for the entire disk holding your boot
- block, if you gave it that information.)
+ partition. Something like `sd0a' or `hd1f' is called for. Unit
+ number without any partition names the entire disk.
o floppy disk drives, give something like `fd0' or `fd1'.
o hardwired terminals, something like `com0' or `com1'.
@@ -223,25 +231,20 @@ nameserver to work properly.
You can mount a partition (say hd0a) by saying:
- settrans /mnt /hurd/ufs /dev/rhd0a
+ settrans /mnt /hurd/ufs /dev/hd0a
-The name `/dev/rhd0a' must have been created using `./MAKEDEV hd0a' in
+The name `/dev/hd0a' must have been created using `./MAKEDEV hd0a' in
the /dev directory.
(This is equivalent to Unixy `mount /dev/hd0a /mnt'.)
-
-(Note that you are using the *RAW* device here. In theory, it's
-irrelevant [and this is really only being used to get a name in a
-clever but strange way], but there are minor bugs in the non-raw
-versions, so don't try and use them.)
If it's a Linux ext2 format disk, just do
- settrans /mnt /hurd/ext2fs /dev/rhd0a
+ settrans /mnt /hurd/ext2fs /dev/hd0a
You can make it readonly thus:
- settrans /mnt /hurd/ufs -r /dev/rhd0a
+ settrans /mnt /hurd/ufs -r /dev/hd0a
For more information on settrans, see the end of this file.
@@ -261,7 +264,7 @@ automatically fscked, you'll have to make entries in /etc/fstab (see
A temporary mount (which lasts only until the filesystem program is
killed or the system is rebooted) can be accomplished by giving the -a
-option to settrans thus: `settrans -a /mnt /hurd/ufs /dev/rsd0a'.
+option to settrans thus: `settrans -a /mnt /hurd/ufs /dev/sd0a'.
(Note the placement of this option, as an arg to settrans, is
different from the -r options you might give to the filesystem.)
`showtrans' does not display these temporary mounts.
@@ -295,6 +298,16 @@ Edit resolv.conf to provide for name service appropriate to your
location.
+*** build a smaller kernel
+
+As an optional step, you can build a smaller kernel. The distributed
+kernel is quite large, because it includes a great many device
+drivers. If you fetch the gnumach distribution, you can build a
+kernel with only the device drivers you actually need. This will make
+bootstrapping faster, and also take less memory when the system is
+running, and result in a faster system in general.
+
+
Once you've completed these steps, you can reboot the system multi
user. Enjoy!
@@ -385,7 +398,7 @@ Subroutine: Installing from NetBSD boot floppies
If you do not have a system running BSD, the NetBSD 2-floppy install
set contains enough tools to make a new filesystem using newfs and
copy to it from nfs. You can fetch these floppies from ftp.netbsd.org
-in the directory /pub/NetBSD/arch/i386/floppies. The NetBSD install
+in the directory /pub/NetBSD/NetBSD-1.1/floppies. The NetBSD install
script will start automatically when you boot from the floppies, and
we suggest you use it in order to partition and set up your disk.
@@ -403,7 +416,7 @@ because your nfs server probably has more convenient editors than the
NetBSD boot floppies. The boot floppies have only ed.
A. Fetch the netbsd boot floppies from
- ftp://ftp.netbsd.org/pub/NetBSD/arch/i386/floppies. Put the
+ ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-1.1/i386/floppies. Put the
images onto floppy disks using the instructions found on the FTP
site.
@@ -449,8 +462,8 @@ K. Initialize the network with `ifconfig DEV MY-ADDR'. DEV was
if you want to see those messages again. (Sometimes ifconfig
says that something is "offline". Ignore it.)
-L. Mount the NFS server partition with the conveniente command
- `mount SERVER-ADDR:SERVER-DIR /mnt2'.
+L. Mount the NFS server partition with the convenient command
+ `mount -o -P SERVER-ADDR:SERVER-DIR /mnt2'.
M. Copy the Hurd onto your disk with the command
(cd /mnt2; tar cf - .) | (cd mnt; tar xfpv -)
diff --git a/release/Makefile b/release/Makefile
index 038c8974..e5d94e18 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -1,5 +1,5 @@
# Makefile for Hurd release tools
-# Copyright (C) 1996 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
# Written by Michael I. Bushnell, p/BSG.
#
# This file is part of the GNU Hurd.
@@ -22,13 +22,16 @@ dir := release
makemode := misc
# Files that go into the root of binary distributions
-dist-files = INSTALL-binary dist-README SETUP INSTALL-GRUB-MBR servers.boot \
- menu.lst COPYING.LIB SOURCES.0.0
+dist-files = INSTALL-binary dist-README SETUP servers.boot bfloppy.boot \
+ menu.lst COPYING.LIB SOURCES.0.2
-# Tools for making images
-tool-files = tool-Makefile install-stripped
+# Files describing the contents of boot floppies
+floppy-copy = bfloppy.copy bfloppy-special.copy rfloppy.copy rfloppy-special.copy \
+ bfloppy1.copy bfloppy1-special.copy bfloppy2.copy bfloppy2-special.copy
-DIST_FILES = README $(dist-files) $(tool-files)
+scripts = mkfsimage.sh mksmallso.sh mkemptyso.sh
+
+DIST_FILES = README $(dist-files) $(floppy-copy) $(scripts)
include ../Makeconf
@@ -37,25 +40,46 @@ install-dist: dist-links
cp $(srcdir)/INSTALL-binary $(dist-root)/
cp $(srcdir)/dist-README $(dist-root)/README
cp $(srcdir)/SETUP $(dist-root)/SETUP
- cp $(srcdir)/SOURCES.0.0 $(dist-root)/SOURCES
- cp $(srcdir)/INSTALL-GRUB-MBR $(dist-root)/INSTALL-GRUB-MBR
+ cp $(srcdir)/SOURCES.0.2 $(dist-root)/SOURCES
cp $(srcdir)/servers.boot $(dist-root)/boot/servers.boot
cp $(srcdir)/menu.lst $(dist-root)/boot/grub/menu.lst
cp $(top_srcdir)/COPYING $(dist-root)/share/misc/COPYING
cp $(srcdir)/COPYING.LIB $(dist-root)/share/misc/COPYING.LIB
dist-links:
- mkdir -p $(dist-root)/boot
+ mkdir -p $(dist-root)/boot/grub
mkdir -p $(dist-root)/servers/socket
+ mkdir -p $(dist-root)/share/misc
touch $(dist-root)/servers/socket/1
touch $(dist-root)/servers/socket/2
ln -f $(dist-root)/servers/socket/1 $(dist-root)/servers/socket/local
ln -f $(dist-root)/servers/socket/2 $(dist-root)/servers/socket/inet
+ touch $(dist-root)/servers/exec
endif
-ifneq ($(tool-root),)
-install-tools:
- cp $(srcdir)/install-stripped $(tool-root)/
- chmod +x $(tool-root)/install-stripped
- cp $(srcdir)/tool-Makefile $(tool-root)/Makefile
+# Where to get files for the floppies from.
+bfloppy-src=$(firstword $(dist-root) /)
+
+# Boot floppies we generate
+boot-floppies = bfloppy1.ext2 bfloppy2.ext2 bfloppy.ext2 rfloppy.ext2.gz
+
+boot-floppies: $(boot-floppies)
+
+%.ext2.gz:
+ ./mkfsimage $@ --compress --owner=root.wheel \
+ $(bfloppy-src) --copy-rules=$(srcdir)/$*.copy \
+ $(srcdir) --copy-rules=$(srcdir)/$*-special.copy
+%.ext2:
+ ./mkfsimage $@ --owner=root.wheel \
+ $(bfloppy-src) --copy-rules=$(srcdir)/$*.copy \
+ $(srcdir) --copy-rules=$(srcdir)/$*-special.copy
+
+# floppy dependencies
+ifneq ($(no_deps),t)
+-include $(patsubst %,%.f_d, $(boot-floppies))
+
+%.ext2.f_d %.ext2.gz.f_d: mkfsimage
+ ./mkfsimage $(patsubst %.f_d,%,$@) --dependencies=$@ \
+ $(bfloppy-src) --copy-rules=$(srcdir)/$*.copy \
+ $(srcdir) --copy-rules=$(srcdir)/$*-special.copy
endif
diff --git a/release/SETUP b/release/SETUP
index 56da063e..9860f03a 100644
--- a/release/SETUP
+++ b/release/SETUP
@@ -1,20 +1,22 @@
#!/bin/bash
# Setup critical hurd translators
-BOOT_DEV="$1"
-if [ ! "$BOOT_DEV" ]; then
- echo "No device to install a boot loader was specified."
- echo "Here are some possible devices to use:"
- /bin/devprobe sd0 hd0 sd1 hd1
- echo -n "Boot device? [none] "
- read BOOT_DEV
-fi
-
-if [ "$BOOT_DEV" ]; then
- if /bin/devprobe -s "$BOOT_DEV"; then true; else
- echo 2>&1 "$0: $BOOT_DEV: No such device known"; exit 1
- fi
-fi
+PATH=/bin:/sbin
+
+# BOOT_DEV="$1"
+# if [ ! "$BOOT_DEV" ]; then
+# echo "No device to install a boot loader was specified."
+# echo "Here are some possible devices to use:"
+# /bin/devprobe sd0 hd0 sd1 hd1
+# echo -n "Boot device? [none] "
+# read BOOT_DEV
+# fi
+#
+# if [ "$BOOT_DEV" ]; then
+# if /bin/devprobe -s "$BOOT_DEV"; then true; else
+# echo 2>&1 "$0: $BOOT_DEV: No such device known"; exit 1
+# fi
+# fi
set -v
@@ -24,6 +26,7 @@ fsysopts / --writable
# Set up standard passive translators
/bin/settrans -c /servers/socket/local /hurd/pflocal
/bin/settrans -c /servers/crash /hurd/crash
+/bin/settrans -c /servers/password /hurd/password
# Setup crucial devices
cd /dev
@@ -31,14 +34,14 @@ cd /dev
set +v
-if test "$BOOT_DEV" && /bin/sh ./MAKEDEV "$BOOT_DEV"; then
- echo -n "Install grub as main boot record on $BOOT_DEV? [y] "
- read yn
- case "$yn" in
- "" | "[yY]*")
- /bin/sh /INSTALL-GRUB-MBR /dev/r$BOOT_DEV;;
- esac
-fi
+# if test "$BOOT_DEV" && /bin/sh ./MAKEDEV "$BOOT_DEV"; then
+# echo -n "Install grub as main boot record on $BOOT_DEV? [y] "
+# read yn
+# case "$yn" in
+# "" | "[yY]*")
+# /bin/sh /INSTALL-GRUB-MBR /dev/$BOOT_DEV;;
+# esac
+# fi
echo 'Hit ^C now for shell prompt or RET to reboot'
read response
diff --git a/release/SOURCES.0.0 b/release/SOURCES.0.0
index e75c176b..673f8dd1 100644
--- a/release/SOURCES.0.0
+++ b/release/SOURCES.0.0
@@ -2,7 +2,7 @@ Sources for binaries in Hurd version 0.0.
The following packages were built from the sources of the indicated
-version in ftp://prep.gnu.ai.edu/pub.gnu according to the provided
+version in ftp://prep.gnu.ai.edu/pub/gnu according to the provided
instructions without modification:
autoconf (2.10)
@@ -107,5 +107,5 @@ sh-utils (1.12m from alpha.gnu.ai.mit.edu)
[ copy libc's time/strftime.c into lib/strftime.c to fix a date bug. ]
make (3.74.5 from alpha.gnu.ai.mit.edu; unmodified)
gdb (Modified from Cygnus snapshot of 960526)
-mach4 (UK22, slighly hacked) [already includes `serverboot' program.]
+mach4 (UK22, slightly hacked) [already includes `serverboot' program.]
libc (1.93, with modifications)
diff --git a/release/SOURCES.0.2 b/release/SOURCES.0.2
new file mode 100644
index 00000000..4f50de84
--- /dev/null
+++ b/release/SOURCES.0.2
@@ -0,0 +1,110 @@
+Sources for binaries in GNU version 0.2.
+
+Typical configure line is
+
+../../src/foo-NN/configure --prefix= --cache-file=../config.cache i486-gnu
+
+autoconf (2.12)
+automake (1.0) (useless w/out perl)
+bash (2.0)
+bc (1.04)
+binutils (2.8.1)
+bison (1.25)
+cpio (2.4.2)
+cvs (1.9)
+ [ inhibit use of libc getopt by defining _LIBC in lib/getopt.c
+ and lib/getopt1.c immediately before it is tested. ]
+diffutils (2.7)
+doschk (1.1)
+e2fsprogs (1.08)
+ed (0.2)
+emacs (19.34b)
+emacs lisp manual (19-2.4.2)
+fileutils (3.16)
+findutils (4.1)
+ [ Comment out basename in find/defs.h and find/util.c.
+ Define _GNU_SOURCE at front of find/pred.c.
+ Define ARG_MAX to be 20480 before its first use. ]
+flex (2.5.4)
+from (special source)
+g77 (0.5.19.1)
+gawk (3.0.3)
+gcal (2.10)
+gcc (2.7.2.2) (includes patches from g77 0.5.19.1)
+gdb (gdb-gnu-5 special!)
+ [ texinfo subdir fails, so finish make by doing `make all-gdb'
+ gdb installs as `i486-gnu-gdb' by default, so perhaps just copy
+ by hand ]
+gettext (0.10)
+glibc (2.0.4)
+gmp (2.0.2)
+gnuchess (4.0.pl77) [ in src/Makefile, use 'prefix=' ]
+gnumach (1.1.3)
+gnugo (1.2)
+grep (2.0)
+grub (0.4)
+gzip (1.2.4)
+ [ Comment out basename in gzip.h and util.c. ]
+hello (1.3)
+hurd (0.2)
+indent (1.9.1)
+inetutils (1.3a)
+less (332)
+libg++ (2.7.2)
+lynx (2.7)
+ [ Set defaults appropriately for GNU in userdefs.h. ]
+ [ In WWW/Library/Implementation/HTTCP.c add #ifndef __GNU__ around
+ the sys_errlist test and #ifdef __GNU__ around the strerror case
+ in HTInetStatus. ]
+
+m4 (1.4)
+make (3.75) [ use latest getloadavg ]
+miscfiles (1.1)
+ncurses (1.9.9g)
+nethack (3.2.2)
+ [ In include/config.h:
+ define COMPRESS as "/bin/gzip"
+ define COMPRESS_EXTENSION as ".gz"
+ define HACKDIR as "/games/lib/nethackdir"
+ define SCORE_ON_BOTL
+
+ In include/unixconf.h:
+ define POSIX_JOB_CONTROL and POSIX_TYPES.
+
+ In include/system.h:
+ comment out declaration of random.
+
+ In src/Makefile: Change -O to -O2 in CFLAGS and add -g.
+ Use -lncurses for WINTTYLIB
+
+ In util/Makefile: Change -O to -O2 in CFLAGS and add -g.
+ Use bison for YACC and flex for LEX.
+
+ In Makefile: Change GAMEGRP to games.
+ Change GAMEDIR to /games/lib/$(GAME)dir.
+ Change SHELLDIR to /games.
+ ]
+nvi (1.71)
+patch (2.2) [ Comment out basename in backupfile.c. ]
+perl (5.003)
+ptx (0.4)
+readline (2.0)
+rcs (5.7)
+recode (3.4)
+sed (2.05) [ Change sed.c to include <errno.h> and also use
+ strerror instead sys_errlist in read_file(). ]
+sendmail (8.8.5) [ with special! patch ]
+sh-utils (1.16) [ use latest getloadavg.c ]
+sharutils (4.2)
+tar (1.12)
+termutils (2.0)
+texinfo (3.9)
+ [ Omit OCRNL from the expression in which it occurs in
+ info/terminal.c.
+ In util/install-info.c, replace guts of my_strerror with a call to
+ strerror. ]
+textutils (1.22)
+time (1.7)
+wdiff (0.5)
+
+
diff --git a/release/bfloppy-special.copy b/release/bfloppy-special.copy
new file mode 100644
index 00000000..69ae66d7
--- /dev/null
+++ b/release/bfloppy-special.copy
@@ -0,0 +1 @@
+rename boot/servers.boot copy bfloppy.boot
diff --git a/release/bfloppy.boot b/release/bfloppy.boot
new file mode 100644
index 00000000..3766920b
--- /dev/null
+++ b/release/bfloppy.boot
@@ -0,0 +1,14 @@
+# Boot script file for booting GNU Hurd from a boot floppy. Each line
+# specifies a file to be loaded by the boot loader (the first word), and
+# actions to be done with it.
+
+# First, the bootstrap filesystem. It needs several ports as arguments,
+# as well as the user flags from the boot loader.
+/hurd/ufs.static.gz --bootflags=${boot-args} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -Tgunzip:device ${root-device} $(task-create) $(prompt-task-resume)
+
+# Now the exec server; to load the dynamically-linked exec server program,
+# we have the boot loader in fact load and run ld.so, which in turn
+# loads and runs /hurd/exec. This task is created, and its task port saved
+# in ${exec-task} to be passed to the fs above, but it is left suspended;
+# the fs will resume the exec task once it is ready.
+/lib/ld.so.1.gz /hurd/exec $(exec-task=task-create)
diff --git a/release/bfloppy.copy b/release/bfloppy.copy
new file mode 100644
index 00000000..eb2796fb
--- /dev/null
+++ b/release/bfloppy.copy
@@ -0,0 +1,11 @@
+mkdir boot
+mkdir hurd
+mkdir lib
+mkdir boot/grub
+gzip objcopy boot/gnumach
+gzip objcopy boot/serverboot
+gzip objcopy lib/ld.so.1
+gzip objcopy hurd/ext2fs.static
+copy boot/grub/menu.lst
+copy boot/grub/stage1
+copy boot/grub/stage2
diff --git a/release/bfloppy1-special.copy b/release/bfloppy1-special.copy
new file mode 100644
index 00000000..c92545e1
--- /dev/null
+++ b/release/bfloppy1-special.copy
@@ -0,0 +1 @@
+rename boot/grub/menu.lst copy bfloppy1.grub
diff --git a/release/bfloppy1.copy b/release/bfloppy1.copy
new file mode 100644
index 00000000..312fe70c
--- /dev/null
+++ b/release/bfloppy1.copy
@@ -0,0 +1,7 @@
+mkdir boot
+mkdir boot/grub
+gzip objcopy boot/gnumach
+gzip objcopy boot/serverboot
+copy boot/grub/stage1
+copy boot/grub/stage2
+copy boot/grub/ffs_stage1_5
diff --git a/release/bfloppy1.grub b/release/bfloppy1.grub
new file mode 100644
index 00000000..1c7cd56d
--- /dev/null
+++ b/release/bfloppy1.grub
@@ -0,0 +1,29 @@
+# This is the amount grub waits before booting the default entry
+timeout= 5
+
+# Tell which entry to boot by default. Note that this is origin zero
+# from the beginning of the file.
+default= 0
+
+# Note that to GRUB, all hard disks are `hd' and all floppy disks are `fd'.
+# To Mach, SCSI disks are `sd' and IDE type disks are `hd'. Use
+# GRUB names in the `root' command and prefixing filenames. Use a
+# Mach name as the `root' arg for the kernel, and whenever running the Hurd.
+
+
+# These two entries are for SCSI disks
+# Entry 0:
+title= fd0
+root= (fd0)
+kernel= /boot/gnumach.gz root=fd0
+module= /boot/serverboot.gz
+pause= Insert boot-floppy #2 and hit RETURN...
+
+# Installation steps for GRUB hard disk boot blocks
+# Entry 4:
+title= Install grub from floppy onto hard disk
+install= (fd0)+1 (hd0) (hd0,a)/boot/grub/stage2 0x8000 p
+
+# Entry 5:
+title= Reinstall grub from hard disk to itself
+install= (hd0)/boot/grub/stage1 (hd0) (hd0,a)/boot/grub/stage2 0x8000 p
diff --git a/release/bfloppy2-special.copy b/release/bfloppy2-special.copy
new file mode 100644
index 00000000..f5c3d761
--- /dev/null
+++ b/release/bfloppy2-special.copy
@@ -0,0 +1,2 @@
+mkdir boot
+rename boot/servers.boot copy bfloppy2.boot
diff --git a/release/bfloppy2.boot b/release/bfloppy2.boot
new file mode 100644
index 00000000..943d76d4
--- /dev/null
+++ b/release/bfloppy2.boot
@@ -0,0 +1,14 @@
+# Boot script file for booting GNU Hurd from a boot floppy. Each line
+# specifies a file to be loaded by the boot loader (the first word), and
+# actions to be done with it.
+
+# First, the bootstrap filesystem. It needs several ports as arguments,
+# as well as the user flags from the boot loader.
+/hurd/ext2fs.static --sync=2 --bootflags=${boot-args} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -Tgunzip:device ${root-device} $(task-create) $(prompt-task-resume)
+
+# Now the exec server; to load the dynamically-linked exec server program,
+# we have the boot loader in fact load and run ld.so, which in turn
+# loads and runs /hurd/exec. This task is created, and its task port saved
+# in ${exec-task} to be passed to the fs above, but it is left suspended;
+# the fs will resume the exec task once it is ready.
+/lib/ld.so.1 /hurd/exec $(exec-task=task-create)
diff --git a/release/bfloppy2.copy b/release/bfloppy2.copy
new file mode 100644
index 00000000..78c9f95b
--- /dev/null
+++ b/release/bfloppy2.copy
@@ -0,0 +1,4 @@
+mkdir hurd
+mkdir lib
+objcopy lib/ld.so.1
+objcopy hurd/ext2fs.static
diff --git a/release/checklist b/release/checklist
index 2f5c7e7c..2e27a4b3 100644
--- a/release/checklist
+++ b/release/checklist
@@ -1,21 +1,61 @@
-Checklist for Hurd releases.
+Order for building binary distribution:
+
+1) Make tools on build machine
+* Build/install libc and header files from mach and hurd.
+* Build/install gcc (just LANGUAGES=c)
+* Build/install binutils.
+
+2) Make everything for release; install both on build machine and dist dir.
+* Build/install binutils again (now using new as and ld).
+* Build/install gcc again. (only one stage necessary).
+* Build/install libc again.
+* Build/install everything else.
+
+See `release-steps' for Hurd source release steps.
+
+Checklist for binary image filesystems
* Symlinks in /bin; esp. sh, awk, more, cc.
+* Symlink /lib/libtermcap.a -> /lib/libncurses.a, termcap_g.a,
+ curses_g.a, curses.a.
+* Symlink /lib/ld.so -> /lib/ld.so.1.
+* Symlink . -> /usr.
+* Make sure directories exist: /tmp, /var/run.
+* Touch /var/log/wtmp.
+* Check all symlinks to make sure they don't reference /gd4.
+* Don't use absolute symlinks--make them all relative.
* Build some static fileutils: ls, ln, cp, mv, chmod.
-* Make sure /i486-gnu contains hard links, not copies.
+* Make damn sure that we are only distributing the md5 libcrypt.
+* Make sure /include/obstack.h is from libc and not binutils.
+* Make sure there is no /include/i386.
+* Make sure there is no /i486-gnu.
* Make sure we are using Hurd versions of su and uptime, not sh-utils.
* Make sure we are using Hurd fsck, not e2fs.
* Make install-dist from release dir.
* Make sure there is only a stubby resolv.conf in the distribution.
* Make sure /etc/fstab has no active members
* Make sure nethack is clean
-o Source code for Hurd and libc must be released.
-* Make sure everything listed in SOURCES is on prep.
+* Make sure localtime is Factory
+* Source code for Hurd and libc must be released.
* Remove .stamp files from binary tree.
* Chown everything root.wheel, mode 755/644.
+* /tmp is 1777.
* Chown /games games.games.
* Check permissions on set[gu]id files in binary tree.
- (login, ps, w, vmstat, rsh, rlogin, games/lib/nethack/nethack)
+ (login, su, addauth, setauth, ids, ps, w, vmstat, vminfo, rsh, rlogin,
+ games/lib/nethack/nethack)
* Check each directory for bogus cruft files.
-* Especially delete .bash_history, .gnunfs*, and .stamp files.
-o Verify installation on bare machine.
+* Especially delete .bash_history, .gnunfs*, and .stamp files, *~, *.rej
+* Verify installation on bare machine.
+* Make sure everything listed in SOURCES is on prep.
+* Install release
+* Post announcement
+
+
+FSF Hurd machines need in addition to the INSTALL-binary installation:
+
+* our NFS translators
+* our kernel
+* sendmail.cf, /etc/aliases
+* /home/* symlinks
+* /etc/syslog.conf
diff --git a/release/dist-README b/release/dist-README
index 2ad479ca..afad66cf 100644
--- a/release/dist-README
+++ b/release/dist-README
@@ -2,7 +2,7 @@
This is the Hurd. Welcome.
-This is the complete GNU system, version 0.0.
+This is the complete GNU system, version 0.2.
This directory contains i386 binaries for the Hurd and various
programs built to run under it.
@@ -32,9 +32,6 @@ In addition, bug reports or requests for help in using the system as a
connected whole (as opposed to for particular programs) should be sent
to the hurd mailing lists.
-If any of these mailing address should fail, send your message to
-`tower@gnu.ai.mit.edu' and ask him to forward it properly.
-
The GNU system is free software. See the files /share/misc/COPYING
and /share/misc/COPYING.LIB.
diff --git a/release/menu.lst b/release/menu.lst
index 7686778a..00807dec 100644
--- a/release/menu.lst
+++ b/release/menu.lst
@@ -14,34 +14,37 @@ default= 0
# These two entries are for SCSI disks
# Entry 0:
title= hurd (sd0a multi-user)
-root= hd(0,a)
-kernel= /boot/kernel root=sd0a
+root= (hd0,a)
+kernel= /boot/gnumach root=sd0a
module= /boot/serverboot
# Entry 1:
title= hurd (sd0a single-user)
-root= hd(0,a)
-kernel= /boot/kernel root=sd0a -s
+root= (hd0,a)
+kernel= /boot/gnumach root=sd0a -s
module= /boot/serverboot
# These two entries are for RLL/IDE/ST-506/etc. disks
# Entry 2:
title= hurd (hd0a multi-user)
-root= hd(0,a)
-kernel= /boot/kernel root=hd0a
+root= (hd0,a)
+kernel= /boot/gnumach root=hd0a
module= /boot/serverboot
# Entry 3:
title= hurd (hd0a single-user)
-root= hd(0,a)
-kernel= /boot/kernel root=hd0a -s
+root= (hd0,a)
+kernel= /boot/gnumach root=hd0a -s
module= /boot/serverboot
-# Installation step for GRUB hard disk boot blocks
+# Installation steps for GRUB hard disk boot blocks
# Entry 4:
-title= grub install
-root= hd(0)
-install=hd(0,a)/boot/grub/stage2
+title= Install grub from floppy onto hard disk
+install= (fd0)+1 (hd0) (hd0,a)/boot/grub/stage2 0x8000 p
+
+# Entry 5:
+title= Reinstall grub from hard disk to itself
+install= (hd0)/boot/grub/stage1 (hd0) (hd0,a)/boot/grub/stage2 0x8000 p
diff --git a/release/mkemptyso.sh b/release/mkemptyso.sh
new file mode 100755
index 00000000..0260a48e
--- /dev/null
+++ b/release/mkemptyso.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# args: $1 -- destination .so file
+SO=$1
+GCC=${GCC-i386-gnu-gcc}
+$GCC -nostdlib -shared -fPIC -x c /dev/null -Wl,-soname=`basename $SO` -o $SO
diff --git a/release/mkfsimage.sh b/release/mkfsimage.sh
new file mode 100644
index 00000000..07b142f0
--- /dev/null
+++ b/release/mkfsimage.sh
@@ -0,0 +1,412 @@
+#!/bin/sh
+# Make a filesystem image
+#
+# Copyright (C) 1997 Free Software Foundation, Inc.
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+#
+
+USAGE="\
+Usage: $0 [OPTION...] IMAGE-FILE SRC..."
+TRY="Try "\`"$0 --help' for more information"
+
+MAX_SIZE=1440 # size of floppy
+MIN_SIZE=500 # avoid lossage for compressed filesystems
+
+OWNER="`id -un`.`id -gn`"
+
+unset IMAGE SRCS COMPRESS SCRIPTS QUIET GEN_DEPS
+declare -a SRCS SCRIPTS
+
+NUM_SRCS=0
+NUM_SCRIPTS=0
+
+while :; do
+ case "$1" in
+ --compress) COMPRESS=yes; shift 1;;
+ --fstype=*) FSTYPE="`echo "$1" | sed 's/^--fstype=//'`"; shift 1;;
+ --fstype) FSTYPE="$2"; shift 2;;
+ --mkfs=*) MKFS="`echo "$1" | sed 's/^--mkfs=//'`"; shift 1;;
+ --mkfs) MKFS="$2"; shift 2;;
+ --fstrans=*) FSTRANS="`echo "$1" | sed 's/^--fstrans=//'`"; shift 1;;
+ --fstrans) FSTRANS="$2"; shift 2;;
+ --owner=*) OWNER="`echo "$1" | sed 's/^--owner=//'`"; shift 1;;
+ --owner) OWNER="$2"; shift 2;;
+ --max-size=*) MAX_SIZE="`echo "$1" | sed 's/^--max-size=//'`"; shift 1;;
+ --max-size) MAX_SIZE="$2"; shift 2;;
+ --quiet|-q|-s) QUIET=yes; shift 1;;
+ --copy=*|--copy-rules=*) SCRIPTS[NUM_SCRIPTS]="`echo "$1" | sed 's/^--[-a-z]*=//'`"; let NUM_SCRIPTS+=1; shift 1;;
+ --copy|--copy-rules) SCRIPTS[NUM_SCRIPTS]="$2"; let NUM_SCRIPTS+=1; shift 2;;
+ --dependencies=*) GEN_DEPS="`echo "$1" | sed 's/^--[-a-z]*=//'`"; shift 1;;
+ --dependencies) GEN_DEPS="$2"; shift 2;;
+
+ --version)
+ echo "STANDARD_HURD_VERSION_mkfsimage_"; exit 0;;
+ --help)
+ echo "$USAGE"
+ echo "Make a file-system image IMAGE-FILE from the files in SRC..."
+ echo ''
+ echo "\
+ --copy-rules=FILE Copy files in a manner described by FILE
+
+ --compress Compress the final image
+ --owner=USER[.GROUP] Make files owned by USER & GROUP (default "\`"$OWNER')
+ --max-size=KBYTES Maximum size of final image (default $MAX_SIZE)
+ --dependencies=DEPS Generate a make dependency rule into DEPS and exit
+
+ --fstype=TYPE Type of filesystem (TYPE may be "\`"ext2' or "\`"ufs')
+ --mkfs=PROGRAM Program to make an empty filesystem image
+ --fstrans=PROGRAM File system translator program
+
+ --help Display this help and exit
+ --version Output version information and exit
+
+If multiple SRCs are specified, then each occurrence of --files pertains only to
+the corresponding SRC.
+
+Each FILE named in a --copy-rules option contains lines of the form:
+
+ [gzip] [rename TARGET] COPY-OP NAME
+
+and says to copy NAME from the source tree to the destination, using the
+method specified by COPY-OP. A preceding "\`"rename TARGET"\'" says to give
+NAME a different name in the target tree, and a preceding "\`"gzip"\'" says
+to compress the result (appending .gz to the name). COPY-OP may be one of the
+following:
+
+ copy -- A plain copy, preserving symlinks
+ objcopy -- Copy using objcopy to strip any unneeded symbols
+ copytrans -- Copy a translator
+
+ touch -- Create an empty file in the destination, ignoring the source
+ mkdir -- Create an empty directory in the destination, ignoring the source
+ makedev -- Create the given device in the destination, ignoring the source
+ settrans -- Set a translator with the given arguments
+
+If both --mkfs and --fstrans are specified, no filesystem type need be given.
+If --fstype is not specified, an attempt is made to guess it based on the
+extension of IMAGE-FILE."
+ exit 0;;
+ -*)
+ echo 1>&2 "$0: $1: Unknown option"
+ echo 1>&2 "$TRY"
+ exit 64;;
+ '')
+ break;;
+ *)
+ case "${IMAGE+set}" in
+ set) SRCS[NUM_SRCS]="$1"; let 'NUM_SRCS += 1';;
+ *) IMAGE="$1";;
+ esac
+ shift
+ esac
+done
+
+case "${IMAGE+set}${SRCS[*]+set}" in
+ setset) ;;
+ *)
+ echo 1>&2 "$USAGE"
+ echo 1>&2 "$TRY"
+ exit 64;
+esac
+
+# Choose format
+if [ "${MKFS+set}" != set -o "${MKFS+set}" != set ]; then
+ if [ "${FSTYPE+set}" != set ]; then
+ case "$IMAGE" in
+ *.ext2|*.ext2.gz) FSTYPE=ext2;;
+ *.ufs|*.ext2.gz) FSTYPE=ufs;;
+ *) echo 1>&2 "$0: $IMAGE: Unknown filesystem type"; exit 1;;
+ esac
+ fi
+
+ case "$FSTYPE" in
+ ext2) MKFS="/sbin/mkfs.ext2 -ohurd"; MKFS_Q="-q"; FSTRANS=/hurd/ext2fs;;
+ ufs) MKFS="/sbin/mkfs.ufs --tracks=1 --sectors=80"; FSTRANS=/hurd/ufs;;
+ *) echo 1>&2 "$0: $IMAGE: Unknown filesystem type"; exit 1;;
+ esac
+fi
+
+case "$QUIET" in
+ yes) MKFS_Q="${MKFS_Q} >/dev/null"; ECHO=:;;
+ *) MKFS_Q=''; ECHO=echo;;
+esac
+export ECHO MKFS_Q
+
+case "$IMAGE" in *.gz) COMPRESS=yes;; esac
+
+IMAGE_TMP="${IMAGE}.new"
+IMAGE_GZIP_TMP="${IMAGE}.new.gz"
+MNT="/tmp/,mkfsimage-$$.mnt"
+ERROUT="/tmp/,mkfsimage-$$.errout"
+STAGE="/tmp/,mkfsimage-$$.stage"
+TRANS_LIST="/tmp/,mkfsimage-$$.trans"
+
+# Extra blocks that will be used by translators
+TRANS_BLOCKS=0
+
+if [ "$GEN_DEPS" ]; then
+ GEN_DEPS_TMP="$GEN_DEPS.new"
+ echo "$GEN_DEPS: ${SCRIPTS[*]}" >> "$GEN_DEPS_TMP"
+ echo "$IMAGE: \\" >> "$GEN_DEPS_TMP"
+fi
+
+trap "settrans 2>/dev/null -a $MNT; rm -rf $MNT $IMAGE_TMP $IMAGE_GZIP_TMP $ERROUT $STAGE $TRANS_LIST $GEN_DEPS_TMP" 0 1 2 3 15
+
+if [ ${#SRCS[@]} = 1 -a ${#SCRIPTS[@]} = 0 ]; then
+ # No staging directory
+ TREE="$1"
+else
+ # Multiple source trees, or selective copying -- copy using a staging directory.
+ # We record any translators in a file ($TRANS_LIST) for later, since we copy
+ # the staging dir to the final dir using tar, and it can't handle translators.
+
+ mkdir $STAGE || exit $?
+
+ SRC_NUM=0
+ while [ $SRC_NUM -lt ${#SRCS[@]} ]; do
+ SRC="${SRCS[SRC_NUM]}"
+ SCRIPT="${SCRIPTS[SRC_NUM]}"
+ let SRC_NUM+=1
+
+ if [ ! -d "$SRC" ]; then
+ echo 1>&2 "$0: $SRC: No such directory"
+ exit 24
+ fi
+ case "$SRC" in
+ /) PFX="/";;
+ *) PFX="$SRC/";;
+ esac
+
+ if [ ! "$GEN_DEPS" ]; then
+ eval $ECHO "'# Copying files from $SRC into staging directory $STAGE...'"
+ fi
+
+ if [ x"${SCRIPT}" != x ]; then
+ eval $ECHO "'# Using copy script $SCRIPT'"
+ (
+ if [ x"$SCRIPT" != x- ]; then
+ if [ ! -r "$SCRIPT" ]; then
+ echo 1>&2 "$0: $SCRIPT: No such file"
+ exit 25
+ fi
+ exec <"$SCRIPT"
+ fi
+
+ test "$GEN_DEPS" && echo " $SCRIPT \\" >> "$GEN_DEPS_TMP"
+
+ while read -a args; do
+ case $args in
+ gzip) gzip=yes; unset args[0]; args=(${args[@]});;
+ *) gzip=no;;
+ esac
+ case $args in
+ rename) dst="${args[1]}"; unset args[0] args[1]; args=(${args[@]});;
+ *) unset dst;;
+ esac
+
+ op="${args[0]}"
+ src="${args[1]}"
+
+ if echo "$src" | grep -q "[?*[]"; then
+ # For wildcards, use the most recent file matching that pattern
+ src="`(cd $SRC; ls -t1 $src | head -1)`"
+ fi
+
+ case ${dst+set} in
+ set)
+ # Destination patterns match files in the source tree (What
+ # else could we use? This may be useful for files that exist
+ # in the source, but which we want to use a different version
+ # of for this filesystem).
+ if echo "$dst" | grep -q "[?*[]"; then
+ dst="`(cd $SRC; ls -t1 $dst | head -1)`"
+ fi;;
+ *)
+ dst="$src";;
+ esac
+
+ # Pop op & src off of args
+ set -- "${args[@]}"; shift 2; unset args; args=("$@")
+
+ if [ "$GEN_DEPS" ]; then
+ case $op in
+ copy|objcopy)
+ echo " ${PFX}$src \\" >> "$GEN_DEPS_TMP";;
+ esac
+ continue
+ fi
+
+ case $op in
+ copy)
+ eval $ECHO "'cp -d ${PFX}$src $STAGE/$dst'"
+ cp -d ${PFX}$src $STAGE/$dst
+ ;;
+ objcopy)
+ eval $ECHO "'objcopy --strip-unneeded ${PFX}$src $STAGE/$dst'"
+ objcopy --strip-unneeded "${PFX}$src" "$STAGE/$dst"
+ ;;
+ symlink)
+ if echo "$args" | grep -q "[?*[]"; then
+ # symlink expansion is in the source tree, in the same
+ # directory as the file itself.
+ args="`(cd $PFX`dirname $dst`; ls -t1 $args | head -1)`"
+ fi
+ eval $ECHO "'ln -s $args $STAGE/$dst'"
+ ln -s $args $STAGE/$dst
+ ;;
+ mkdir)
+ eval $ECHO "'mkdir $STAGE/$dst'"
+ mkdir "$STAGE/$dst"
+ ;;
+ touch)
+ eval $ECHO "'touch $STAGE/$dst'"
+ touch "$STAGE/$dst"
+ ;;
+
+ makedev|settrans|copytrans)
+ # delay translators until later, as tar can't copy them.
+
+ case $op in
+ settrans|copytrans)
+ # We create the node on which translators will be put so
+ # that the owner gets set correctly; this isn't necessary for
+ # device because MAKEDEV does all the work needed, and doing so
+ # would cause problems with device names that are really
+ # categories.
+ touch "$STAGE/$dst";;
+ esac
+
+ # Accunt for space used by the translator block
+ TRANS_BLOCKS=$(($TRANS_BLOCKS + 1))
+
+ # Record the desired operation for a later pass
+ echo "$op $dst $src ${args[*]}" >> $TRANS_LIST
+ ;;
+
+ ''|'#')
+ ;;
+ *)
+ echo 1>&2 "$0: $op: Unknown operation"
+ ;;
+ esac
+
+ case $gzip in yes)
+ eval $ECHO "'gzip -v9 $STAGE/$dst'"
+ gzip -v9 "$STAGE/$dst";;
+ esac
+ done
+ ) || exit $?
+ else
+ eval $ECHO "'# Copying all files using tar'"
+ (cd $SRC; tar cf - .) | (cd $STAGE; tar -x --same-owner -p -f -)
+ fi
+ done
+ TREE="$STAGE"
+fi
+
+if [ "$GEN_DEPS" ]; then
+ echo "" >> "$GEN_DEPS_TMP" && mv "$GEN_DEPS_TMP" "$GEN_DEPS"
+ exit 0
+fi
+
+eval $ECHO "'# Changing file owners to $OWNER'"
+chown -R "$OWNER" $TREE
+
+# Size of source tree, plus 5% for overhead
+TREE_SIZE=$((($TRANS_BLOCKS + `du -s "$TREE" | sed 's/^\([0-9]*\).*/\1/'`) * 105 / 100))
+
+if [ "${COMPRESS-no}" = yes ]; then
+ # Add 10% to the filesystem size to leave some breathing room.
+ # Since unused filesystem space compresses very well, this shouldn't add
+ # much to the final size.
+ SIZE=$(($TREE_SIZE * 110 / 100))
+ test $SIZE -lt $MIN_SIZE && SIZE=$MIN_SIZE
+else
+ if [ $TREE_SIZE -gt $MAX_SIZE ]; then
+ echo 1>&2 "$0: $TREE: Too big (${TREE_SIZE}k) to fit in ${MAX_SIZE}k"
+ exit 10
+ fi
+ SIZE=$(($TREE_SIZE * 110 / 100))
+ test $SIZE -lt $MIN_SIZE && SIZE=$MIN_SIZE
+ test $SIZE -gt $MAX_SIZE && SIZE=$MAX_SIZE
+fi
+
+eval $ECHO "'# Zeroing disk image...'"
+rm -f $IMAGE_TMP
+if ! dd if=/dev/zero of=$IMAGE_TMP bs=${SIZE}k count=1 2>$ERROUT; then
+ sed -n "s@^dd:@$0@p" < $ERROUT 1>&2
+ exit 11
+fi
+
+eval $ECHO "'# Making filesystem...'"
+eval "$MKFS $MKFS_Q '$IMAGE_TMP'" || exit 12
+settrans -ac $MNT $FSTRANS $IMAGE_TMP || exit 13
+
+eval $ECHO "'# Copying $TREE into filesystem...'"
+(cd $TREE; tar cf - .) | (cd $MNT; tar -x --same-owner -p -f -)
+
+if [ -r "$TRANS_LIST" ]; then
+ # create any delayed translators
+ eval $ECHO "'# Creating translators...'"
+ cat "$TRANS_LIST" |
+ while read -a args; do
+ op="${args[0]}"
+ dst="${args[1]}"
+ src="${args[2]}"
+ set -- "${args[@]}"; shift 3; unset args; args=("$@")
+
+ case $op in
+ copytrans)
+ tr="`showtrans "${PFX}$src"`"
+ eval $ECHO "'settrans $MNT/$dst $tr'"
+ settrans "$MNT/$dst" $tr
+ ;;
+ settrans)
+ eval $ECHO "'settrans $MNT/$dst ${args[*]}'"
+ settrans "$MNT/$dst" "${args[@]}"
+ ;;
+ makedev)
+ dd="/`dirname $dst`"
+ eval $ECHO "'/sbin/MAKEDEV --devdir=$dd $MNT/$dst'"
+ /sbin/MAKEDEV --devdir=$dd "$MNT/$dst"
+ ;;
+ esac
+ done
+fi
+
+settrans -a $MNT
+
+case "$COMPRESS" in
+ yes)
+ case "$QUIET" in
+ yes)
+ gzip -9 $IMAGE_TMP
+ ;;
+ *)
+ eval $ECHO "'# Compressing disk image...'"
+ gzip -v9 $IMAGE_TMP 2>&1 | sed "s@$IMAGE_TMP\.gz@$IMAGE@g"
+ ;;
+ esac
+ mv $IMAGE_GZIP_TMP $IMAGE
+ ;;
+ *)
+ mv $IMAGE_TMP $IMAGE
+ ;;
+esac
+
+exit 0
diff --git a/release/mksmallso.sh b/release/mksmallso.sh
new file mode 100755
index 00000000..2f147bd0
--- /dev/null
+++ b/release/mksmallso.sh
@@ -0,0 +1,48 @@
+# Usage:
+# $1 : Destination merged, stripped, small shared library
+# $2 : lib*_pic.a files from which to produce the final small library
+# $3 : .so files that this library should depend on
+# ${4:$} : executables and shared libraries whos dependencies we care about
+
+while :; do
+ case "$1" in
+ -*) LDARGS="$1"; shift;;
+ *) break;;
+ esac
+done
+
+MERGED_SO="$1"; shift
+PIC_LIBS="$1"; shift
+DEPS="$1"; shift
+
+GCC=${GCC-gcc}
+LD=${LD-ld}
+OBJDUMP=${OBJDUMP-objdump}
+OBJCOPY=${OBJCOPY-objcopy}
+
+DEP_FLAGS_FILE=/tmp/,depflags.$$
+NEED_DSYMS_FILE=/tmp/,need.dyn.syms.$$
+HAVE_DSYMS_FILE=/tmp/,have.dyn.syms.$$
+MERGED_PIC_LIB=/tmp/,libmerged_pic.a.$$
+
+#trap "rm -f $DEP_FLAGS_FILE $MERGED_PIC_LIB $NEED_DSYMS_FILE $HAVE_DSYMS_FILE" 0
+
+
+$OBJDUMP --dynamic-syms "$@" 2>/dev/null \
+ | sed -n 's/^.*\*UND\*.* \([^ ]*\)$/\1/p' \
+ | sort -u > $NEED_DSYMS_FILE
+
+# 00000000 w F .text 00000000 syscall_device_write_request
+# 00000000 g F .text 0000056c __strtoq_internal
+$OBJDUMP --syms $PIC_LIBS 2>/dev/null \
+ | sed -n 's/^........ \(g \| w\) .. .* [0-9a-f]....... \([^ ]*\)$/\2/p' \
+ | sort -u > $HAVE_DSYMS_FILE
+
+# This had better be gnu diff...
+diff --unchanged-l='%L' --old-l= --new-l= $NEED_DSYMS_FILE $HAVE_DSYMS_FILE \
+ | sed 's/^/-u/' > $DEP_FLAGS_FILE
+
+$GCC $LDARGS -nostdlib -nostartfiles -shared -Wl,-soname=`basename $MERGED_SO` `cat $DEP_FLAGS_FILE` \
+ -o $MERGED_SO.uns $PIC_LIBS $DEPS \
+&& $OBJCOPY --strip-debug $MERGED_SO.uns $MERGED_SO \
+&& rm -f $MERGED_SO.uns
diff --git a/release/release-steps b/release/release-steps
new file mode 100644
index 00000000..5303017b
--- /dev/null
+++ b/release/release-steps
@@ -0,0 +1,8 @@
+
+Make tar file.
+Test compilation.
+Update README, including version number.
+Update INSTALL, including version number.
+Update NEWS.
+Write release announcement.
+README and release announcement should mention list of platforms.
diff --git a/release/rfloppy-special.copy b/release/rfloppy-special.copy
new file mode 100644
index 00000000..cf7ef22a
--- /dev/null
+++ b/release/rfloppy-special.copy
@@ -0,0 +1,3 @@
+rename etc/passwd copy rfloppy.passwd
+rename etc/group copy rfloppy.group
+rename etc/nsswitch.conf copy rfloppy.nss
diff --git a/release/rfloppy.copy b/release/rfloppy.copy
new file mode 100644
index 00000000..55beef92
--- /dev/null
+++ b/release/rfloppy.copy
@@ -0,0 +1,175 @@
+# Files on the hurd boot floppy root disk
+
+mkdir bin
+mkdir boot
+mkdir dev
+mkdir etc
+mkdir hurd
+mkdir lib
+mkdir sbin
+mkdir servers
+mkdir tmp
+mkdir mnt
+
+copy etc/protocols
+copy etc/services
+
+objcopy bin/bash
+objcopy bin/cat
+objcopy bin/chmod
+objcopy bin/chown
+objcopy bin/cp
+objcopy bin/dd
+objcopy bin/ed
+objcopy bin/devprobe
+objcopy bin/fsysopts
+objcopy bin/ftp
+objcopy bin/gzip
+objcopy bin/ln
+objcopy bin/ls
+objcopy bin/mv
+objcopy bin/rm
+objcopy bin/settrans
+objcopy bin/showtrans
+objcopy bin/sync
+copy bin/sh
+objcopy bin/tar
+objcopy bin/vmstat
+
+objcopy hurd/auth
+objcopy hurd/exec
+objcopy hurd/init
+objcopy hurd/nfs
+objcopy hurd/pfinet
+objcopy hurd/proc
+objcopy hurd/term
+objcopy hurd/ext2fs
+objcopy hurd/magic
+objcopy hurd/null
+objcopy hurd/pflocal
+objcopy hurd/storeio
+objcopy hurd/ufs
+
+copy sbin/MAKEDEV
+objcopy sbin/halt
+objcopy sbin/mkfs.ext2
+objcopy sbin/mkfs.ufs
+objcopy sbin/reboot
+objcopy sbin/fdisk
+objcopy sbin/swapon
+
+touch servers/exec
+mkdir servers/socket
+settrans servers/socket/1 /hurd/pflocal
+symlink servers/socket/local servers/socket/1
+touch servers/socket/2
+symlink servers/socket/inet servers/socket/2
+
+copy lib/ld.so
+objcopy lib/ld.so.1
+objcopy lib/libc-*.so
+copy lib/libc.so
+copy lib/libc.so.*
+copy lib/libcrypt.so
+copy lib/libcrypt.so.*
+objcopy lib/libcrypt-*.so
+copy lib/libdb.so
+copy lib/libdb.so.*
+objcopy lib/libdb-*.so
+copy lib/libdl.so
+copy lib/libdl.so.*
+objcopy lib/libdl-*.so
+objcopy lib/libdiskfs.so
+objcopy lib/libfshelp.so
+objcopy lib/libhurdbugaddr.so
+copy lib/libhurduser.so
+copy lib/libhurduser.so.*
+objcopy lib/libhurduser-*.so
+objcopy lib/libihash.so
+objcopy lib/libiohelp.so
+copy lib/libm.so
+copy lib/libm.so.*
+objcopy lib/libm-*.so
+copy lib/libmachuser.so
+copy lib/libmachuser.so.*
+objcopy lib/libmachuser-*.so
+objcopy lib/libnetfs.so
+copy lib/libnss_dns.so
+copy lib/libnss_dns.so.*
+objcopy lib/libnss_dns-*.so
+copy lib/libnss_files.so
+copy lib/libnss_files.so.*
+objcopy lib/libnss_files-*.so
+objcopy lib/libpager.so
+objcopy lib/libpipe.so
+objcopy lib/libports.so
+copy lib/libresolv.so
+copy lib/libresolv.so.*
+objcopy lib/libresolv-*.so
+objcopy lib/libshouldbeinlibc.so
+objcopy lib/libstore.so
+objcopy lib/libthreads.so
+objcopy lib/libtrivfs.so
+copy lib/libutil.so
+copy lib/libutil.so.*
+objcopy lib/libutil-*.so
+
+copy dev/MAKEDEV
+makedev dev/std
+makedev dev/fd0
+makedev dev/hd0
+makedev dev/hd0a
+makedev dev/hd0b
+makedev dev/hd0c
+makedev dev/hd0d
+makedev dev/hd0e
+makedev dev/hd0f
+makedev dev/hd0g
+makedev dev/hd0s1
+makedev dev/hd0s2
+makedev dev/hd0s3
+makedev dev/hd0s4
+makedev dev/hd0s5
+makedev dev/hd0s6
+makedev dev/hd1
+makedev dev/hd1a
+makedev dev/hd1b
+makedev dev/hd1c
+makedev dev/hd1d
+makedev dev/hd1e
+makedev dev/hd1f
+makedev dev/hd1g
+makedev dev/hd1s1
+makedev dev/hd1s2
+makedev dev/hd1s3
+makedev dev/hd1s4
+makedev dev/hd1s5
+makedev dev/hd1s6
+makedev dev/sd0
+makedev dev/sd0a
+makedev dev/sd0b
+makedev dev/sd0c
+makedev dev/sd0d
+makedev dev/sd0e
+makedev dev/sd0f
+makedev dev/sd0g
+makedev dev/sd0s1
+makedev dev/sd0s2
+makedev dev/sd0s3
+makedev dev/sd0s4
+makedev dev/sd0s5
+makedev dev/sd0s6
+makedev dev/sd1
+makedev dev/sd1a
+makedev dev/sd1b
+makedev dev/sd1c
+makedev dev/sd1d
+makedev dev/sd1e
+makedev dev/sd1f
+makedev dev/sd1g
+makedev dev/sd1s1
+makedev dev/sd1s2
+makedev dev/sd1s3
+makedev dev/sd1s4
+makedev dev/sd1s5
+makedev dev/sd1s6
diff --git a/release/rfloppy.group b/release/rfloppy.group
new file mode 100644
index 00000000..47b7278c
--- /dev/null
+++ b/release/rfloppy.group
@@ -0,0 +1 @@
+wheel::0:root
diff --git a/release/rfloppy.nss b/release/rfloppy.nss
new file mode 100644
index 00000000..31447c2a
--- /dev/null
+++ b/release/rfloppy.nss
@@ -0,0 +1,19 @@
+# /etc/nsswitch.conf
+#
+# Don't use name services that we can't provide (specifically, nis & db)
+#
+
+# defaults for hosts & networks are ok
+
+passwd: files
+group: files
+shadow: files
+aliases: files
+
+protocols: files
+services: files
+ethers: files
+rpc: files
+publickey: files
+
+netgroup: files
diff --git a/release/rfloppy.passwd b/release/rfloppy.passwd
new file mode 100644
index 00000000..a799e8f6
--- /dev/null
+++ b/release/rfloppy.passwd
@@ -0,0 +1 @@
+root::0:0:Lord of the Files:/:/bin/bash
diff --git a/release/servers.boot b/release/servers.boot
index 91beb152..9ba7f6a4 100644
--- a/release/servers.boot
+++ b/release/servers.boot
@@ -3,14 +3,12 @@
# First, the bootstrap filesystem. It needs several ports as arguments,
# as well as the user flags from the boot loader.
-/hurd/ufs.static --bootflags=${boot-args} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} --machdev ${root-device} $(task-create) $(task-resume)
+/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)
+
# Now the exec server; to load the dynamically-linked exec server program,
# we have the boot loader in fact load and run ld.so, which in turn
# loads and runs /hurd/exec. This task is created, and its task port saved
-# in ${exec-task} to be passed to the fs above, but it is left suspended;
+# in ${exec-task} to be passed to the fs above, but it is left suspended;
# the fs will resume the exec task once it is ready.
-/lib/ld.so /hurd/exec $(exec-task=task-create)
-
-# default pager
-/dev/sd0b $(add-paging-file) $(default-pager)
+/lib/ld.so.1 /hurd/exec $(exec-task=task-create)
diff --git a/release/tool-Makefile b/release/tool-Makefile
index 375042e4..6a23b95a 100644
--- a/release/tool-Makefile
+++ b/release/tool-Makefile
@@ -1,27 +1,38 @@
# Makefile for hurd image frobnication.
-export GNUTARGET=elf32-i386
-export OBJCOPY=i386-gnu-objcopy
+export OBJCOPY=objcopy
-BF=bfloppy-image
-RF=rfloppy-image
+# Where we get programs from
+image-dir=/
+# Where we get libc
+libc-obj-dir = /gd4/hurd-native/build/glibc
-bfloppy-files = $(bfloppy-bootfs:%=hurd/%) $(bfloppy-bootprogs:%=boot/%) \
+smallso-LDFLAGS = -Wl,-rpath-link=/lib
+
+BF=bfloppy
+RF=rfloppy
+
+bfloppy-files = $(bfloppy-bootfs:%=hurd/%) $(bfloppy-bootprogs:%=boot/%.gz) \
lib/ld.so boot/servers.boot
bfloppy-bootfs = ufs
-bfloppy-bootprogs = kernel bootstrap
+bfloppy-bootprogs = gnumach serverboot
-$(BF)/boot/servers.boot: hurd-image/boot/floppy.boot
- -rm -f $@
+$(BF)/boot/servers.boot: bfloppy.boot
+ @-rm -f $@
@test -d $(@D) || mkdir -p $(@D)
cp $< $@
-$(BF)/%/: hurd-image/%/
+$(BF)/%/: $(image-dir)/%/
test -d $@ || mkdir -p $@
-$(BF)/%: hurd-image/%
- -rm -f $@
+$(addsuffix .gz, $(addprefix $(BF)/boot/, $(bfloppy-bootprogs))): \
+ $(BF)/boot/%.gz: $(image-dir)/boot/%
+ @-rm -f $@
@test -d $(@D) || mkdir -p $(@D)
- ln $< $@ || cp $< $@
+ $(OBJCOPY) --strip-unneeded $< | gzip -9 > $@
+$(BF)/%: $(image-dir)/%
+ @-rm -f $@
+ @test -d $(@D) || mkdir -p $(@D)
+ $(OBJCOPY) --strip-unneeded $< $@
$(BF): $(bfloppy-files:%=$(BF)/%)
$(BF).tar: $(bfloppy-files:%=$(BF)/%)
@@ -29,96 +40,54 @@ $(BF).tar: $(bfloppy-files:%=$(BF)/%)
cd $(BF); tar covf ../$@ $(^:$(BF)/%=%)
rfloppy-files = $(rfloppy-hurd:%=hurd/%) $(rfloppy-progs:%=bin/%) \
+ $(rfloppy-sprogs:%=sbin/%) \
$(rfloppy-solib:%=lib/%.so) hurd/exec \
lib/libc.so lib/libhurduser.so lib/libmachuser.so \
servers/exec servers/socket/1 \
- README tmp/ dev/MAKEDEV
-rfloppy-hurd = auth devio null init proc term
-rfloppy-progs = sh ls cat settrans # mkfs
+ README tmp/ mnt/ dev/MAKEDEV
+rfloppy-hurd = auth storeio null init proc term pfinet nfs ufs ext2fs
+rfloppy-progs = bash ls cat settrans
+rfloppy-sprogs = mkfs.ufs mkfs.ext2
rfloppy-solib = libtrivfs libthreads libshouldbeinlibc libports \
- libpager libioserver libihash libfshelp ld
-
-libc-satisfies = $(rfloppy-hurd:%=hurd/%) $(rfloppy-progs:%=bin/%) $(rfloppy-solib:%=lib/%.so)
-
-libc-obj-dir = /gd4/gnu/libc/i386
-smallso-LDFLAGS = -Wl,-rpath-link=/lib
+ libpager libiohelp libstore libihash libfshelp libnetfs ld
-libc-USERS =
-libc-DEPS =
+libc-satisfies = $(rfloppy-hurd:%=hurd/%) $(rfloppy-progs:%=bin/%) $(rfloppy-sprogs:%=sbin/%) $(rfloppy-solib:%=lib/%.so)
-$(RF)/lib/libc.so: hurd-image/lib/libc.so hurd-image/lib/libhurduser.so hurd-image/lib/libmachuser.so $(libc-satisfies:%=hurd-image/%)
+$(RF)/lib/libc.so: $(image-dir)/lib/libc.so $(image-dir)/lib/libhurduser.so $(image-dir)/lib/libmachuser.so $(libc-satisfies:%=$(image-dir)/%)
mksmallso $(smallso-LDFLAGS) \
- $@ $(libc-obj-dir)/libc_pic.a '-Lhurd-image/lib -lhurduser -lmachuser' \
+ $@ $(libc-obj-dir)/libc_pic.a '-L$(image-dir)/lib -lhurduser -lmachuser' \
$(filter-out $(firstword $^),$^)
-$(RF)/lib/libhurduser.so: $(RF)/lib/libc.so $(libc-satisfies:%=hurd-image/%)
- mksmallso $(smallso-LDFLAGS) $@ $(libc-obj-dir)/libhurduser_pic.a -Lhurd-image/lib -lmachuser $(filter-out $(firstword $^),$^)
+$(RF)/lib/libhurduser.so: $(RF)/lib/libc.so $(libc-satisfies:%=$(image-dir)/%)
+ mksmallso $(smallso-LDFLAGS) $@ $(libc-obj-dir)/hurd/libhurduser_pic.a -L$(image-dir)/lib -lmachuser $(filter-out $(firstword $^),$^)
-$(RF)/lib/libmachuser.so: $(RF)/lib/libc.so $(RF)/lib/libhurduser.so $(libc-satisfies:%=hurd-image/%)
- mksmallso $(smallso-LDFLAGS) $@ $(libc-obj-dir)/libmachuser_pic.a '' $(filter-out $(firstword $^),$^)
+$(RF)/lib/libmachuser.so: $(RF)/lib/libc.so $(RF)/lib/libhurduser.so $(libc-satisfies:%=$(image-dir)/%)
+ mksmallso $(smallso-LDFLAGS) $@ $(libc-obj-dir)/mach/libmachuser_pic.a '' $(filter-out $(firstword $^),$^)
-$(addprefix $(RF)/,$(rfloppy-hurd:%=hurd/%) $(rfloppy-progs:%=bin/%)): \
- $(RF)/%: hurd-image/%
+$(RF)/bin/%: $(image-dir)/bin/%
+ @-rm -f $@
@test -d $(@D) || mkdir -p $(@D)
- gzip -9v -c $< > $@.new
- chmod 555 $@.new
- mv -f $@.new $@
-
-$(RF)/%/: hurd-image/%/
- test -d $@ || mkdir -p $@
-$(RF)/%: hurd-image/%
- -rm -f $@
+ $(OBJCOPY) --strip-unneeded $< $@
+$(RF)/sbin/%: $(image-dir)/sbin/%
+ @-rm -f $@
@test -d $(@D) || mkdir -p $(@D)
- ln $< $@ || cp $< $@
+ $(OBJCOPY) --strip-unneeded $< $@
+$(RF)/hurd/%: $(image-dir)/hurd/%
+ @-rm -f $@
+ @test -d $(@D) || mkdir -p $(@D)
+ $(OBJCOPY) --strip-unneeded $< $@
+$(RF)/servers/%:
+ @test -d $(@D) || mkdir -p $(@D)
+ touch $@
+$(RF)/%/: $(image-dir)/%/
+ test -d $@ || mkdir -p $@
$(RF): $(rfloppy-files:%=$(RF)/%)
$(RF).tar: $(rfloppy-files:%=$(RF)/%)
rm -f $@
cd $(RF); tar covf ../$@ $(^:$(RF)/%=%)
-MOUNT_POINT = /mnt
-VND = vnd0
-VND_DEV = /dev/${VND}a
-VND_RDEV = /dev/r${VND}a
-MDEC = /usr/mdec
-
-floppy%-image.fs: /tmp/floppy%-image.fs; cp -f $< $@
-
-/tmp/floppy%-image.fs: floppy%-image.tar
- dd if=/dev/zero of=$@.new bs=10k count=144
- vnconfig -v -c ${VND_DEV} $@.new
- disklabel -w -B -b ${MDEC}/fdboot -s ${MDEC}/bootfd ${VND} floppy3
- newfs -O -m 0 -o space -i 5120 -c 80 ${VND_RDEV} floppy3
- mount ${VND_DEV} ${MOUNT_POINT}
- tar -f $< -C ${MOUNT_POINT} -xv
- df -i ${MOUNT_POINT}
- umount ${MOUNT_POINT}
- vnconfig -u ${VND_DEV} $@.new
- mv -f $@.new $@
-
-hurd-image.tar: hurd-image hurd-image.stamp
- tar cof $@ $<
-
-%.gz: %
- gzip -9v -c $< > $@.new
- mv -f $@.new $@
-
-%:: %.gz
- gunzip -c $< > $@.new
- mv -f $@.new $@
-
-
-instdirs := $(patsubst ../hurdinst/%,%,\
- $(filter-out ../hurdinst,\
- $(shell find ../hurdinst -type d -print \
- | sort -r)))
-
-hurd-image/%/.stamp: ../hurdinst/%
- @./install-stripped -N $@ $< $(@D)
- @echo $< `date` > $@
- @echo updated $(@D)/
-hurd-image.stamp: $(instdirs:%=hurd-image/%/.stamp); touch $@
-hurd-image: hurd-image.stamp
-
-
- \ No newline at end of file
+bfloppy.%: $(bfloppy-files:%=$(BF)/%)
+ mkfsimage -q $@ $(BF)
+rfloppy.%.gz: $(rfloppy-files:%=$(RF)/%)
+ mkfsimage --compress -q $@ $(RF)
diff --git a/storeio/Makefile b/storeio/Makefile
new file mode 100644
index 00000000..f027ebd4
--- /dev/null
+++ b/storeio/Makefile
@@ -0,0 +1,29 @@
+# Makefile for storeio
+#
+# Copyright (C) 1995, 1996, 1997, 2000 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 := storeio
+makemode := server
+
+target = storeio
+SRCS = dev.c storeio.c open.c pager.c io.c
+LCLHDRS = dev.h open.h
+
+OBJS = $(SRCS:.c=.o)
+HURDLIBS = trivfs pager fshelp iohelp store threads ports ihash shouldbeinlibc
+
+include ../Makeconf
diff --git a/storeio/dev.c b/storeio/dev.c
new file mode 100644
index 00000000..31b084f9
--- /dev/null
+++ b/storeio/dev.c
@@ -0,0 +1,473 @@
+/* store `device' I/O
+
+ Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2008
+ Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <assert.h>
+#include <string.h>
+#include <hurd/pager.h>
+#include <hurd/store.h>
+#include <sys/mman.h>
+
+#include "dev.h"
+
+/* These functions deal with the buffer used for doing non-block-aligned I/O. */
+
+static inline int
+dev_buf_is_active (struct dev *dev)
+{
+ return dev->buf_offs >= 0;
+}
+
+/* Invalidate DEV's buffer, writing it to disk if necessary. */
+static error_t
+dev_buf_discard (struct dev *dev)
+{
+ if (dev_buf_is_active (dev))
+ {
+ if (dev->buf_dirty)
+ {
+ size_t amount;
+ struct store *store = dev->store;
+ error_t err =
+ store_write (store, dev->buf_offs >> store->log2_block_size,
+ dev->buf, store->block_size, &amount);
+ if (!err && amount < store->block_size)
+ err = EIO;
+ if (err)
+ return err;
+ dev->buf_dirty = 0;
+ }
+ dev->buf_offs = -1;
+ }
+ return 0;
+}
+
+/* Make DEV's buffer active, reading the block from DEV's store which
+ contains OFFS. */
+static error_t
+dev_buf_fill (struct dev *dev, off_t offs)
+{
+ error_t err;
+ unsigned block_mask = dev->block_mask;
+ void *buf = dev->buf;
+ struct store *store = dev->store;
+ size_t buf_len = store->block_size;
+
+ if (dev_buf_is_active (dev))
+ {
+ if ((dev->buf_offs & ~block_mask) == (offs & ~block_mask))
+ return 0; /* Correct block alredy in buffer. */
+ else
+ {
+ err = dev_buf_discard (dev);
+ if (err)
+ return err;
+ }
+ }
+
+ err = store_read (store, offs >> store->log2_block_size, store->block_size,
+ &buf, &buf_len);
+ if (err)
+ return err;
+
+ if (buf != dev->buf)
+ {
+ munmap (dev->buf, store->block_size);
+ dev->buf = buf;
+ }
+
+ dev->buf_offs = offs & ~block_mask;
+
+ return 0;
+}
+
+/* Do an in-buffer partial-block I/O operation. */
+static error_t
+dev_buf_rw (struct dev *dev, size_t buf_offs, size_t *io_offs, size_t *len,
+ error_t (*const buf_rw) (size_t buf_offs,
+ size_t io_offs, size_t len))
+{
+ size_t block_size = dev->store->block_size;
+
+ assert (dev_buf_is_active (dev));
+
+ if (buf_offs + *len >= block_size)
+ /* Only part of BUF lies within the buffer (or everything up
+ to the end of the block, in which case we want to flush
+ the buffer anyway). */
+ {
+ size_t buf_len = block_size - buf_offs;
+ error_t err = (*buf_rw) (buf_offs, *io_offs, buf_len);
+ if (err)
+ return err;
+ *io_offs += buf_len;
+ *len -= buf_len;
+ return dev_buf_discard (dev);
+ }
+ else
+ /* All I/O is within the block. */
+ {
+ error_t err = (*buf_rw) (buf_offs, *io_offs, *len);
+ if (err)
+ return err;
+ *io_offs += *len;
+ *len = 0;
+ return 0;
+ }
+}
+
+/* Called with DEV->lock held. Try to open the store underlying DEV. */
+error_t
+dev_open (struct dev *dev)
+{
+ error_t err;
+ const int flags = ((dev->readonly ? STORE_READONLY : 0)
+ | (dev->no_fileio ? STORE_NO_FILEIO : 0));
+
+ assert (dev->store == 0);
+
+ if (dev->store_name == 0)
+ {
+ /* This means we had no store arguments.
+ We are to operate on our underlying node. */
+ err = store_create (storeio_fsys->underlying, flags, 0, &dev->store);
+ }
+ else
+ /* Open based on the previously parsed store arguments. */
+ err = store_parsed_open (dev->store_name, flags, &dev->store);
+ if (err)
+ return err;
+
+ /* Inactivate the store, it will be activated at first access.
+ We ignore possible EINVAL here . XXX Pass STORE_INACTIVE to
+ store_create/store_parsed_open instead when libstore is fixed
+ to support this. */
+ store_set_flags (dev->store, STORE_INACTIVE);
+
+ dev->buf = mmap (0, dev->store->block_size, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (dev->buf == MAP_FAILED)
+ {
+ store_free (dev->store);
+ dev->store = 0;
+ return ENOMEM;
+ }
+
+ if (!dev->inhibit_cache)
+ {
+ dev->buf_offs = -1;
+ rwlock_init (&dev->io_lock);
+ dev->block_mask = (1 << dev->store->log2_block_size) - 1;
+ dev->pager = 0;
+ mutex_init (&dev->pager_lock);
+ }
+
+ return 0;
+}
+
+/* Shut down the store underlying DEV and free any resources it consumes.
+ DEV itself remains intact so that dev_open can be called again.
+ This should be called with DEV->lock held. */
+void
+dev_close (struct dev *dev)
+{
+ assert (dev->store);
+
+ if (!dev->inhibit_cache)
+ {
+ if (dev->pager != NULL)
+ pager_shutdown (dev->pager);
+
+ dev_buf_discard (dev);
+
+ munmap (dev->buf, dev->store->block_size);
+ }
+
+ store_free (dev->store);
+ dev->store = 0;
+}
+
+/* Try and write out any pending writes to DEV. If WAIT is true, will wait
+ for any paging activity to cease. */
+error_t
+dev_sync(struct dev *dev, int wait)
+{
+ error_t err;
+
+ if (dev->inhibit_cache)
+ return 0;
+
+ /* Sync any paged backing store. */
+ if (dev->pager != NULL)
+ pager_sync (dev->pager, wait);
+
+ rwlock_writer_lock (&dev->io_lock);
+ err = dev_buf_discard (dev);
+ rwlock_writer_unlock (&dev->io_lock);
+
+ return err;
+}
+
+/* Takes care of buffering I/O to/from DEV for a transfer at position OFFS,
+ length LEN; the amount of I/O successfully done is returned in AMOUNT.
+ BUF_RW is called to do I/O that's entirely inside DEV's internal buffer,
+ and RAW_RW to do I/O directly to DEV's store. */
+static inline error_t
+buffered_rw (struct dev *dev, off_t offs, size_t len, size_t *amount,
+ error_t (* const buf_rw) (size_t buf_offs,
+ size_t io_offs, size_t len),
+ error_t (* const raw_rw) (off_t offs,
+ size_t io_offs, size_t len,
+ size_t *amount))
+{
+ error_t err = 0;
+ unsigned block_mask = dev->block_mask;
+ unsigned block_size = dev->store->block_size;
+ size_t io_offs = 0; /* Offset within this I/O operation. */
+ unsigned block_offs = offs & block_mask; /* Offset within a block. */
+
+ rwlock_writer_lock (&dev->io_lock);
+
+ if (block_offs != 0)
+ /* The start of the I/O isn't block aligned. */
+ {
+ err = dev_buf_fill (dev, offs);
+ if (! err)
+ err = dev_buf_rw (dev, block_offs, &io_offs, &len, buf_rw);
+ }
+
+ if (!err && len > 0)
+ /* Now the I/O should be block aligned. */
+ {
+ if (len >= block_size)
+ {
+ size_t amount;
+ err = dev_buf_discard (dev);
+ if (! err)
+ err =
+ (*raw_rw) (offs + io_offs, io_offs, len & ~block_mask, &amount);
+ if (! err)
+ {
+ io_offs += amount;
+ len -= amount;
+ }
+ }
+ if (len > 0 && len < block_size)
+ /* All full blocks were written successfully, so write
+ the tail end into the buffer. */
+ {
+ err = dev_buf_fill (dev, offs + io_offs);
+ if (! err)
+ err = dev_buf_rw (dev, 0, &io_offs, &len, buf_rw);
+ }
+ }
+
+ if (! err)
+ *amount = io_offs;
+
+ rwlock_writer_unlock (&dev->io_lock);
+
+ return err;
+}
+
+/* Takes care of buffering I/O to/from DEV for a transfer at position OFFS,
+ length LEN, and direction DIR. BUF_RW is called to do I/O to/from data
+ buffered in DEV, and RAW_RW to do I/O directly to DEV's store. */
+static inline error_t
+dev_rw (struct dev *dev, off_t offs, size_t len, size_t *amount,
+ error_t (* const buf_rw) (size_t buf_offs,
+ size_t io_offs, size_t len),
+ error_t (* const raw_rw) (off_t offs,
+ size_t io_offs, size_t len,
+ size_t *amount))
+{
+ error_t err;
+ unsigned block_mask = dev->block_mask;
+
+ if (offs < 0 || offs > dev->store->size)
+ return EINVAL;
+ else if (offs + len > dev->store->size)
+ len = dev->store->size - offs;
+
+ rwlock_reader_lock (&dev->io_lock);
+ if (dev_buf_is_active (dev)
+ || (offs & block_mask) != 0 || (len & block_mask) != 0)
+ /* Some non-aligned I/O has been done, or is needed, so we need to deal
+ with DEV's buffer, which means getting an exclusive lock. */
+ {
+ /* Acquire a writer lock instead of a reader lock. Note that other
+ writers may have acquired the lock by the time we get it. */
+ rwlock_reader_unlock (&dev->io_lock);
+ err = buffered_rw (dev, offs, len, amount, buf_rw, raw_rw);
+ }
+ else
+ /* Only block-aligned I/O is being done, so things are easy. */
+ {
+ err = (*raw_rw) (offs, 0, len, amount);
+ rwlock_reader_unlock (&dev->io_lock);
+ }
+
+ return err;
+}
+
+/* Write LEN bytes from BUF to DEV, returning the amount actually written in
+ AMOUNT. If successful, 0 is returned, otherwise an error code is
+ returned. */
+error_t
+dev_write (struct dev *dev, off_t offs, void *buf, size_t len,
+ size_t *amount)
+{
+ error_t buf_write (size_t buf_offs, size_t io_offs, size_t len)
+ {
+ bcopy (buf + io_offs, dev->buf + buf_offs, len);
+ dev->buf_dirty = 1;
+ return 0;
+ }
+ error_t raw_write (off_t offs, size_t io_offs, size_t len, size_t *amount)
+ {
+ struct store *store = dev->store;
+ return
+ store_write (store, offs >> store->log2_block_size,
+ buf + io_offs, len, amount);
+ }
+
+ if (dev->inhibit_cache)
+ {
+ /* Under --no-cache, we permit only whole-block writes.
+ Note that in this case we handle non-power-of-two block sizes. */
+
+ struct store *store = dev->store;
+
+ if (store->block_size == 0)
+ /* We don't know the block size, so let the device enforce it. */
+ return store_write (dev->store, offs, buf, len, amount);
+
+ if ((offs & (store->block_size - 1)) != 0
+ || (len & (store->block_size - 1)) != 0)
+ /* Not whole blocks. No can do. */
+ return EINVAL; /* EIO? */
+
+ /* Do a direct write to the store. */
+ return store_write (dev->store, offs << store->log2_block_size,
+ buf, len, amount);
+ }
+
+ return dev_rw (dev, offs, len, amount, buf_write, raw_write);
+}
+
+/* Read up to WHOLE_AMOUNT bytes from DEV, returned in BUF and LEN in the
+ with the usual mach memory result semantics. If successful, 0 is
+ returned, otherwise an error code is returned. */
+error_t
+dev_read (struct dev *dev, off_t offs, size_t whole_amount,
+ void **buf, size_t *len)
+{
+ error_t err;
+ int allocated_buf = 0;
+ error_t ensure_buf ()
+ {
+ if (*len < whole_amount)
+ {
+ void *new = mmap (0, whole_amount, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (new == (void *) -1)
+ return errno;
+ *buf = new;
+ allocated_buf = 1;
+ }
+ return 0;
+ }
+ error_t buf_read (size_t buf_offs, size_t io_offs, size_t len)
+ {
+ error_t err = ensure_buf ();
+ if (! err)
+ bcopy (dev->buf + buf_offs, *buf + io_offs, len);
+ return err;
+ }
+ error_t raw_read (off_t offs, size_t io_offs, size_t len, size_t *amount)
+ {
+ struct store *store = dev->store;
+ off_t addr = offs >> store->log2_block_size;
+ if (len == whole_amount)
+ /* Just return whatever the device does. */
+ return store_read (store, addr, len, buf, amount);
+ else
+ /* This read is returning less than the whole request, so we allocate
+ a buffer big enough to hold everything, in case we have to
+ coalesce multiple reads into a single return buffer. */
+ {
+ error_t err = ensure_buf ();
+ if (! err)
+ {
+ void *_req_buf = *buf + io_offs, *req_buf = _req_buf;
+ size_t req_len = len;
+ err = store_read (store, addr, len, &req_buf, &req_len);
+ if (! err)
+ {
+ if (req_buf != _req_buf)
+ /* Copy from wherever the read put it. */
+ {
+ bcopy (req_buf, _req_buf, req_len);
+ munmap (req_buf, req_len);
+ }
+ *amount = req_len;
+ }
+ }
+ return err;
+ }
+ }
+
+ if (dev->store->size > 0 && offs == dev->store->size)
+ {
+ /* Reading end of file. */
+ *len = 0;
+ return 0;
+ }
+
+ if (dev->inhibit_cache)
+ {
+ /* Under --no-cache, we permit only whole-block reads.
+ Note that in this case we handle non-power-of-two block sizes.
+ We could, that is, but libstore won't have it (see libstore/make.c).
+ If the device does not report a block size, we let any attempt
+ through on the assumption the device will enforce its own limits. */
+
+ struct store *store = dev->store;
+
+ if (store->block_size == 0)
+ /* We don't know the block size, so let the device enforce it. */
+ return store_read (dev->store, offs, whole_amount, buf, len);
+
+ if ((offs & (store->block_size - 1)) != 0
+ || (whole_amount & (store->block_size - 1)) != 0)
+ /* Not whole blocks. No can do. */
+ return EINVAL;
+
+ /* Do a direct read from the store. */
+ return store_read (dev->store, offs << store->log2_block_size,
+ whole_amount, buf, len);
+ }
+
+ err = dev_rw (dev, offs, whole_amount, len, buf_read, raw_read);
+ if (err && allocated_buf)
+ munmap (*buf, whole_amount);
+
+ return err;
+}
diff --git a/storeio/dev.h b/storeio/dev.h
new file mode 100644
index 00000000..23924ca5
--- /dev/null
+++ b/storeio/dev.h
@@ -0,0 +1,127 @@
+/* store `device' I/O
+
+ Copyright (C) 1995,96,97,99,2000,2001 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __DEV_H__
+#define __DEV_H__
+
+#include <mach.h>
+#include <device/device.h>
+#include <rwlock.h>
+#include <hurd/store.h>
+#include <hurd/trivfs.h>
+
+extern struct trivfs_control *storeio_fsys;
+
+/* Information about backend store, which we presumptively call a "device". */
+struct dev
+{
+ /* The argument specification that we use to open the store. */
+ struct store_parsed *store_name;
+
+ /* The device to which we're doing io. This is null when the
+ device is closed, in which case we will open from `store_name'. */
+ struct store *store;
+
+ int readonly; /* Nonzero if user gave --readonly flag. */
+ int enforced; /* Nonzero if user gave --enforced flag. */
+ int no_fileio; /* Nonzero if user gave --no-fileio flag. */
+ dev_t rdev; /* A unixy device number for st_rdev. */
+
+ /* The current owner of the open device. For terminals, this affects
+ controlling terminal behavior (see term_become_ctty). For all objects
+ this affects old-style async IO. Negative values represent pgrps. This
+ has nothing to do with the owner of a file (as returned by io_stat, and
+ as used for various permission checks by filesystems). An owner of 0
+ indicates that there is no owner. */
+ pid_t owner;
+
+ /* The number of active opens. */
+ int nperopens;
+
+ /* This lock protects `store', `owner' and `nperopens'. The other
+ members never change after creation, except for those locked by
+ io_lock (below). */
+ struct mutex lock;
+
+ /* Nonzero iff the --no-cache flag was given.
+ If this is set, the remaining members are not used at all
+ and don't need to be initialized or cleaned up. */
+ int inhibit_cache;
+
+ /* A bitmask corresponding to the part of an offset that lies within a
+ device block. */
+ unsigned block_mask;
+
+ /* Lock to arbitrate I/O through this device. Block I/O can occur in
+ parallel, and requires only a reader-lock.
+ Non-block I/O is always serialized, and requires a writer-lock. */
+ struct rwlock io_lock;
+
+ /* Non-block I/O is buffered through BUF. BUF_OFFS is the device offset
+ corresponding to the start of BUF (which holds one block); if it is -1,
+ then BUF is inactive. */
+ void *buf;
+ off_t buf_offs;
+ int buf_dirty;
+
+ struct pager *pager;
+ struct mutex pager_lock;
+};
+
+static inline int
+dev_is_readonly (const struct dev *dev)
+{
+ return dev->readonly || (dev->store && (dev->store->flags & STORE_READONLY));
+}
+
+/* Called with DEV->lock held. Try to open the store underlying DEV. */
+error_t dev_open (struct dev *dev);
+
+/* Shut down the store underlying DEV and free any resources it consumes.
+ DEV itself remains intact so that dev_open can be called again.
+ This should be called with DEV->lock held. */
+void dev_close (struct dev *dev);
+
+/* Returns in MEMOBJ the port for a memory object backed by the storage on
+ DEV. Returns 0 or the error code if an error occurred. */
+error_t dev_get_memory_object(struct dev *dev, vm_prot_t prot,
+ memory_object_t *memobj);
+
+/* Try to stop all paging activity on DEV, returning true if we were
+ successful. If NOSYNC is true, then we won't write back any (kernel)
+ cached pages to the device. */
+int dev_stop_paging (struct dev *dev, int nosync);
+
+/* Try and write out any pending writes to DEV. If WAIT is true, will wait
+ for any paging activity to cease. */
+error_t dev_sync (struct dev *dev, int wait);
+
+/* Write LEN bytes from BUF to DEV, returning the amount actually written in
+ AMOUNT. If successful, 0 is returned, otherwise an error code is
+ returned. */
+error_t dev_write (struct dev *dev, off_t offs, void *buf, size_t len,
+ size_t *amount);
+
+/* Read up to AMOUNT bytes from DEV, returned in BUF and LEN in the with the
+ usual mach memory result semantics. If successful, 0 is returned,
+ otherwise an error code is returned. */
+error_t dev_read (struct dev *dev, off_t offs, size_t amount,
+ void **buf, size_t *len);
+
+#endif /* !__DEV_H__ */
diff --git a/devio/io.c b/storeio/io.c
index 61f655d2..508df77a 100644
--- a/devio/io.c
+++ b/storeio/io.c
@@ -1,8 +1,7 @@
-/* Implements the hurd io interface to devio.
+/* The hurd io interface to storeio
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,99,2000,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -18,18 +17,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-#include <hurd.h>
-#include <hurd/ports.h>
#include <hurd/trivfs.h>
#include <stdio.h>
#include <fcntl.h>
#include "open.h"
#include "dev.h"
-#include "iostate.h"
-/* ---------------------------------------------------------------- */
-
/* Return objects mapping the data underlying this memory object. If
the object can be read then memobjrd will be provided; if the
object can be written then memobjwr will be provided. For objects
@@ -38,173 +32,159 @@
implement io_map but not io_map_cntl. Some objects do not provide
mapping; they will set none of the ports and return an error. Such
objects can still be accessed by io_read and io_write. */
-kern_return_t
-trivfs_S_io_map(struct trivfs_protid *cred,
- memory_object_t *rdobj,
- mach_msg_type_name_t *rdtype,
- memory_object_t *wrobj,
- mach_msg_type_name_t *wrtype)
+error_t
+trivfs_S_io_map (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ memory_object_t *rd_obj, mach_msg_type_name_t *rd_type,
+ memory_object_t *wr_obj, mach_msg_type_name_t *wr_type)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & (O_READ|O_WRITE)))
+ return EBADF;
else
{
mach_port_t memobj;
+ int flags = cred->po->openmodes;
+ vm_prot_t prot =
+ ((flags & O_READ) ? VM_PROT_READ : 0)
+ | ((flags & O_WRITE) ? VM_PROT_WRITE : 0);
struct open *open = (struct open *)cred->po->hook;
- error_t err = dev_get_memory_object(open->dev, &memobj);
+ error_t err = dev_get_memory_object (open->dev, prot, &memobj);
if (!err)
{
- if (cred->po->openmodes & O_READ)
- {
- *rdobj = memobj;
- *rdtype = MACH_MSG_TYPE_MOVE_SEND;
- }
+ if (flags & O_READ)
+ *rd_obj = memobj;
else
- *rdobj = MACH_PORT_NULL;
-
- if (cred->po->openmodes & O_WRITE)
- {
- *wrobj = memobj;
- *wrtype = MACH_MSG_TYPE_MOVE_SEND;
- }
+ *rd_obj = MACH_PORT_NULL;
+ if (flags & O_WRITE)
+ *wr_obj = memobj;
else
- *wrobj = MACH_PORT_NULL;
+ *wr_obj = MACH_PORT_NULL;
+
+ if ((flags & (O_READ|O_WRITE)) == (O_READ|O_WRITE)
+ && memobj != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (), memobj,
+ MACH_PORT_RIGHT_SEND, 1);
}
+ *rd_type = *wr_type = MACH_MSG_TYPE_MOVE_SEND;
+
return err;
}
}
-/* ---------------------------------------------------------------- */
-
/* Read data from an IO object. If offset if -1, read from the object
maintained file pointer. If the object is not seekable, offset is
- ignored. The amount desired to be read is in AMT. */
-kern_return_t
-trivfs_S_io_read(struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
- vm_address_t *data,
- mach_msg_type_number_t *datalen,
- off_t offs,
- mach_msg_type_number_t amt)
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
- else if (!(cred->po->openmodes & O_READ))
+ else if (! (cred->po->openmodes & O_READ))
return EBADF;
else
- return open_read((struct open *)cred->po->hook, data, datalen, amt, offs);
+ return open_read ((struct open *)cred->po->hook,
+ offs, amount, (void **)data, data_len);
}
-
-/* ---------------------------------------------------------------- */
/* Tell how much data can be read from the object without blocking for
a "long time" (this should be the same meaning of "long time" used
by the nonblocking flag. */
-kern_return_t
+error_t
trivfs_S_io_readable (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
mach_msg_type_number_t *amount)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
- else if (!(cred->po->openmodes & O_READ))
- return EINVAL;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
else
{
struct open *open = (struct open *)cred->po->hook;
- struct dev *dev = open->dev;
- vm_offset_t location = open_get_io_state(open)->location;
- *amount = dev->size - location;
+ *amount = open->dev->store->size - open->offs;
return 0;
}
}
-
-/* ---------------------------------------------------------------- */
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they recevie more than one write when not prepared for it. */
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char *data, mach_msg_type_number_t data_len,
+ loff_t offs, mach_msg_type_number_t *amount)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_WRITE))
+ return EBADF;
+ else
+ return open_write ((struct open *)cred->po->hook,
+ offs, (void *)data, data_len, amount);
+}
+
/* Change current read/write offset */
-kern_return_t
+error_t
trivfs_S_io_seek (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
off_t offs, int whence, off_t *new_offs)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
return open_seek ((struct open *)cred->po->hook, offs, whence, new_offs);
}
-
-/* ---------------------------------------------------------------- */
/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
Block until one of the indicated types of i/o can be done "quickly", and
return the types that are then available. */
-kern_return_t
+error_t
trivfs_S_io_select (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
int *type)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
- else if (((*type & SELECT_READ) && !(cred->po->openmodes & O_READ))
- || ((*type & SELECT_WRITE) && !(cred->po->openmodes & O_WRITE)))
- return EBADF;
- else
- *type &= ~SELECT_URG;
+ *type &= ~SELECT_URG;
return 0;
}
-
-/* ---------------------------------------------------------------- */
-
-/* Write data to an IO object. If offset is -1, write at the object
- maintained file pointer. If the object is not seekable, offset is
- ignored. The amount successfully written is returned in amount. A
- given user should not have more than one outstanding io_write on an
- object at a time; servers implement congestion control by delaying
- responses to io_write. Servers may drop data (returning ENOBUFS)
- if they recevie more than one write when not prepared for it. */
-kern_return_t
-trivfs_S_io_write (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
- vm_address_t data, mach_msg_type_number_t datalen,
- off_t offs, mach_msg_type_number_t *amt)
-{
- if (!cred)
- return EOPNOTSUPP;
- else if (!(cred->po->openmodes & O_WRITE))
- return EBADF;
- else
- return open_write((struct open *)cred->po->hook, data, datalen, amt, offs);
-}
-
-/* ---------------------------------------------------------------- */
/* Truncate file. */
-kern_return_t
+error_t
trivfs_S_file_set_size (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
off_t size)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
return 0;
}
-/* ---------------------------------------------------------------- */
/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
will tell you which of O_READ, O_WRITE, and O_EXEC the object can
- be used for. The O_ASYNC bit affects icky async I/O; good async
+ be used for. The O_ASYNC bit affects icky async I/O; good async
I/O is done through io_async which is orthogonal to these calls. */
-kern_return_t
+error_t
trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
int *bits)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
{
@@ -214,89 +194,85 @@ trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
}
error_t
-trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t replytype,
- int mode)
+trivfs_S_io_set_all_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int mode)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
return 0;
}
-kern_return_t
+error_t
trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
mach_port_t reply,
- mach_msg_type_name_t replytype,
+ mach_msg_type_name_t reply_type,
int bits)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
return 0;
}
-kern_return_t
+error_t
trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
mach_port_t reply,
- mach_msg_type_name_t replytype,
+ mach_msg_type_name_t reply_type,
int bits)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
return 0;
}
-/* ---------------------------------------------------------------- */
/* Get/set the owner of the IO object. For terminals, this affects
controlling terminal behavior (see term_become_ctty). For all
objects this affects old-style async IO. Negative values represent
pgrps. This has nothing to do with the owner of a file (as
returned by io_stat, and as used for various permission checks by
filesystems). An owner of 0 indicates that there is no owner. */
-
-kern_return_t
+error_t
trivfs_S_io_get_owner (struct trivfs_protid *cred,
mach_port_t reply,
- mach_msg_type_name_t replytype,
+ mach_msg_type_name_t reply_type,
pid_t *owner)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
{
struct open *open = (struct open *)cred->po->hook;
- *owner = open->dev->owner;
+ *owner = open->dev->owner; /* atomic word fetch */
return 0;
}
}
-kern_return_t
+error_t
trivfs_S_io_mod_owner (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
pid_t owner)
{
- if (!cred)
+ if (! cred)
return EOPNOTSUPP;
else
{
struct open *open = (struct open *)cred->po->hook;
- open->dev->owner = owner;
+ open->dev->owner = owner; /* atomic word store */
return 0;
}
}
-
-/* ---------------------------------------------------------------- */
/* File syncing operations; these all do the same thing, sync the underlying
device. */
-kern_return_t
+error_t
trivfs_S_file_sync (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
- int wait)
+ int wait, int omit_metadata)
{
if (cred)
return dev_sync (((struct open *)cred->po->hook)->dev, wait);
@@ -304,12 +280,12 @@ trivfs_S_file_sync (struct trivfs_protid *cred,
return EOPNOTSUPP;
}
-kern_return_t
+error_t
trivfs_S_file_syncfs (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
int wait, int dochildren)
{
- if (!cred)
+ if (cred)
return dev_sync (((struct open *)cred->po->hook)->dev, wait);
else
return EOPNOTSUPP;
@@ -327,70 +303,63 @@ trivfs_S_file_get_storage_info (struct trivfs_protid *cred,
mach_msg_type_number_t *num_offsets,
char **data, mach_msg_type_number_t *data_len)
{
- error_t err = 0;
+ *ports_type = MACH_MSG_TYPE_COPY_SEND;
- if (!cred)
- err = EOPNOTSUPP;
+ if (! cred || ! cred->po->hook)
+ return EOPNOTSUPP;
else
{
- /* True when we've allocated memory for the corresponding vector. */
- int al_ports = 0, al_ints = 0, al_offsets = 0, al_data = 0;
+ error_t err;
+ struct dev *dev = ((struct open *)cred->po->hook)->dev;
+ struct store *store = dev->store;
-#define ENSURE_MEM(v, vl, alp, num) \
- if (!err && *vl < num) \
- { \
- err = vm_allocate (mach_task_self (), \
- (vm_address_t *)v, num * sizeof (**v), 1); \
- if (! err) \
- { \
- *vl = num; \
- alp = 1; \
- } \
- }
-
- ENSURE_MEM (ports, num_ports, al_ports, 1);
- ENSURE_MEM (ints, num_ints, al_ints, 6);
- ENSURE_MEM (offsets, num_offsets, al_offsets, 2);
- ENSURE_MEM (data, data_len, al_data, 1);
-
- if (! err)
+ if (dev->enforced && !(store->flags & STORE_ENFORCED))
{
- struct dev *dev = ((struct open *)cred->po->hook)->dev;
- (*ints)[0] = STORAGE_DEVICE; /* type */
- (*ints)[1] = 0; /* flags */
- (*ints)[2] = dev->dev_block_size; /* block_size */
- (*ints)[3] = 1; /* num_runs */
- (*ints)[4] = strlen (dev->name) + 1; /* name_len */
- (*ints)[5] = 0; /* misc_len */
- *num_ints = 6;
-
- (*offsets)[0] = 0;
- (*offsets)[1] = dev->size / dev->dev_block_size;
- *num_offsets = 2;
-
- strcpy (*data, dev->name);
- *data_len = strlen (dev->name) + 1;
+ /* The --enforced switch tells us not to let anyone
+ get at the device, no matter how trustable they are. */
+ size_t name_len = (store->name ? strlen (store->name) + 1 : 0);
+ int i;
+ *num_ports = 0;
+ i = 0;
+ (*ints)[i++] = STORAGE_OTHER;
+ (*ints)[i++] = store->flags;
+ (*ints)[i++] = store->block_size;
+ (*ints)[i++] = 1; /* num_runs */
+ (*ints)[i++] = name_len;
+ (*ints)[i++] = 0; /* misc_len */
+ *num_ints = i;
+ i = 0;
+ (*offsets)[i++] = 0;
+ (*offsets)[i++] = store->size;
+ *num_offsets = i;
+ if (store->name)
+ memcpy (*data, store->name, name_len);
+ *data_len = name_len;
+ return 0;
+ }
- if (cred->isroot)
- (*ports)[0] = dev->port;
- else
- (*ports)[0] = MACH_PORT_NULL;
- *num_ports = 1;
- *ports_type = MACH_MSG_TYPE_COPY_SEND;
+ if (!cred->isroot
+ && !store_is_securely_returnable (store, cred->po->openmodes))
+ {
+ struct store *clone;
+ err = store_clone (store, &clone);
+ if (! err)
+ {
+ err = store_set_flags (clone, STORE_INACTIVE);
+ if (err == EINVAL)
+ err = EACCES;
+ else
+ err = store_return (clone,
+ ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+ store_free (clone);
+ }
}
else
- /* Some memory allocation failed (not bloody likely). */
- {
-#define DISCARD_MEM(v, vl, alp) \
- if (alp) \
- vm_deallocate (mach_task_self (), (vm_address_t)*v, *vl * sizeof (**v));
+ err = store_return (store,
+ ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
- DISCARD_MEM (ports, num_ports, al_ports);
- DISCARD_MEM (ints, num_ints, al_ints);
- DISCARD_MEM (offsets, num_offsets, al_offsets);
- DISCARD_MEM (data, data_len, al_data);
- }
+ return err;
}
-
- return err;
}
diff --git a/storeio/open.c b/storeio/open.c
new file mode 100644
index 00000000..805115ce
--- /dev/null
+++ b/storeio/open.c
@@ -0,0 +1,127 @@
+/* Per-open information for storeio
+
+ Copyright (C) 1995, 1996, 2006 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <hurd.h>
+#include <stdio.h>
+
+#include "open.h"
+#include "dev.h"
+
+/* Returns a new per-open structure for the device DEV in OPEN. If an error
+ occurs, the error-code is returned, otherwise 0. */
+error_t
+open_create (struct dev *dev, struct open **open)
+{
+ *open = malloc (sizeof (struct open));
+ if (*open == NULL)
+ return ENOMEM;
+
+ (*open)->dev = dev;
+ (*open)->offs = 0;
+ mutex_init (&(*open)->lock);
+
+ return 0;
+}
+
+/* Free OPEN and any resources it holds. */
+void
+open_free (struct open *open)
+{
+ free (open);
+}
+
+/* Writes up to LEN bytes from BUF to OPEN's device at device offset OFFS
+ (which may be ignored if the device doesn't support random access),
+ and returns the number of bytes written in AMOUNT. If no error occurs,
+ zero is returned, otherwise the error code is returned. */
+error_t
+open_write (struct open *open, off_t offs, void *buf, size_t len,
+ vm_size_t *amount)
+{
+ error_t err;
+ if (offs < 0)
+ /* Use OPEN's offset. */
+ {
+ mutex_lock (&open->lock);
+ err = dev_write (open->dev, open->offs, buf, len, amount);
+ if (! err)
+ open->offs += *amount;
+ mutex_unlock (&open->lock);
+ }
+ else
+ err = dev_write (open->dev, offs, buf, len, amount);
+ return err;
+}
+
+/* Reads up to AMOUNT bytes from the device into BUF and LEN using the
+ standard mach out-array convention. If no error occurs, zero is returned,
+ otherwise the error code is returned. */
+error_t
+open_read (struct open *open, off_t offs, size_t amount,
+ void **buf, vm_size_t *len)
+{
+ error_t err;
+ if (offs < 0)
+ /* Use OPEN's offset. */
+ {
+ mutex_lock (&open->lock);
+ err = dev_read (open->dev, open->offs, amount, buf, len);
+ if (! err)
+ open->offs += *len;
+ mutex_unlock (&open->lock);
+ }
+ else
+ err = dev_read (open->dev, offs, amount, buf, len);
+ return err;
+}
+
+/* Set OPEN's location to OFFS, interpreted according to WHENCE as by seek.
+ The new absolute location is returned in NEW_OFFS (and may not be the same
+ as OFFS). If no error occurs, zero is returned, otherwise the error code
+ is returned. */
+error_t
+open_seek (struct open *open, off_t offs, int whence, off_t *new_offs)
+{
+ error_t err = 0;
+
+ mutex_lock (&open->lock);
+
+ switch (whence)
+ {
+ case SEEK_CUR:
+ offs += open->offs;
+ goto check;
+ case SEEK_END:
+ offs += open->dev->store->size;
+ case SEEK_SET:
+ check:
+ if (offs >= 0)
+ {
+ *new_offs = open->offs = offs;
+ break;
+ }
+ default:
+ err = EINVAL;
+ }
+
+ mutex_unlock (&open->lock);
+
+ return err;
+}
diff --git a/devio/open.h b/storeio/open.h
index 80763585..cbac2a37 100644
--- a/devio/open.h
+++ b/storeio/open.h
@@ -1,6 +1,6 @@
-/* Per-open information for devio.
+/* Per-open information for storeio
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -21,48 +21,43 @@
#ifndef __OPEN_H__
#define __OPEN_H__
-#include "iostate.h"
+#include "dev.h"
/* ---------------------------------------------------------------- */
/* A structure describing a particular i/o stream on this device. */
struct open
{
- /* Current state of our output stream -- location and the buffer used to do
- buffered i/o. */
- struct io_state io_state;
-
- /* The memory window we're using to do i/o. This may be NULL, indicating
- we're not doing buffered random access i/o. */
- struct window *window;
-
/* The device that this an open on. */
struct dev *dev;
+
+ /* The per-open offset used for I/O operations that don't specify an
+ explicit offset. */
+ off_t offs;
+
+ /* A lock used to control write access to OFFS. */
+ struct mutex lock;
};
/* Returns a new per-open structure for the device DEV in OPEN. If an error
occurs, the error-code is returned, otherwise 0. */
-error_t open_create(struct dev *dev, struct open **open);
+error_t open_create (struct dev *dev, struct open **open);
/* Free OPEN and any resources it holds. */
-void open_free(struct open *open);
-
-/* Returns the appropiate io_state object for OPEN (which may be either
- per-open or a per-device depending on the device). */
-struct io_state *open_get_io_state(struct open *open);
+void open_free (struct open *open);
/* Writes up to LEN bytes from BUF to OPEN's device at device offset OFFS
(which may be ignored if the device doesn't support random access),
and returns the number of bytes written in AMOUNT. If no error occurs,
zero is returned, otherwise the error code is returned. */
-error_t open_write(struct open *open, vm_address_t buf, vm_size_t len,
- vm_size_t *amount, off_t offs);
+error_t open_write (struct open *open, off_t offs, void *buf, size_t len,
+ size_t *amount);
/* Reads up to AMOUNT bytes from the device into BUF and BUF_LEN using the
standard mach out-array convention. If no error occurs, zero is returned,
otherwise the error code is returned. */
-error_t open_read(struct open *open, vm_address_t *buf, vm_size_t *buf_len,
- vm_size_t amount, off_t offs);
+error_t open_read (struct open *open, off_t offs, size_t amount,
+ void **buf, size_t *buf_len);
/* Set OPEN's location to OFFS, interpreted according to WHENCE as by seek.
The new absolute location is returned in NEW_OFFS (and may not be the same
diff --git a/storeio/pager.c b/storeio/pager.c
new file mode 100644
index 00000000..1fb1d07e
--- /dev/null
+++ b/storeio/pager.c
@@ -0,0 +1,265 @@
+/* Paging interface for storeio devices
+
+ Copyright (C) 1995,96,97,99,2002 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <hurd.h>
+#include <hurd/pager.h>
+#include <assert.h>
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "dev.h"
+
+/* ---------------------------------------------------------------- */
+/* Pager library callbacks; see <hurd/pager.h> for more info. */
+
+/* For pager PAGER, read one page from offset PAGE. Set *BUF to be the
+ address of the page, and set *WRITE_LOCK if the page must be provided
+ read-only. The only permissible error returns are EIO, EDQUOT, and
+ ENOSPC. */
+error_t
+pager_read_page (struct user_pager_info *upi,
+ vm_offset_t page, vm_address_t *buf, int *writelock)
+{
+ error_t err;
+ size_t read = 0; /* bytes actually read */
+ int want = vm_page_size; /* bytes we want to read */
+ struct dev *dev = (struct dev *)upi;
+ struct store *store = dev->store;
+
+ if (page + want > store->size)
+ /* Read a partial page if necessary to avoid reading off the end. */
+ want = store->size - page;
+
+ err = dev_read (dev, page, want, (void **)buf, &read);
+
+ if (!err && want < vm_page_size)
+ /* Zero anything we didn't read. Allocation only happens in page-size
+ multiples, so we know we can write there. */
+ memset ((char *)*buf + want, '\0', vm_page_size - want);
+
+ *writelock = (store->flags & STORE_READONLY);
+
+ if (err || read < want)
+ return EIO;
+ else
+ return 0;
+}
+
+/* For pager PAGER, synchronously write one page from BUF to offset PAGE. In
+ addition, vm_deallocate (or equivalent) BUF. The only permissible error
+ returns are EIO, EDQUOT, and ENOSPC. */
+error_t
+pager_write_page (struct user_pager_info *upi,
+ vm_offset_t page, vm_address_t buf)
+{
+ struct dev *dev = (struct dev *)upi;
+ struct store *store = dev->store;
+
+ if (store->flags & STORE_READONLY)
+ return EROFS;
+ else
+ {
+ error_t err;
+ size_t written;
+ int want = vm_page_size;
+
+ if (page + want > store->size)
+ /* Write a partial page if necessary to avoid reading off the end. */
+ want = store->size - page;
+
+ err = dev_write (dev, page, (char *)buf, want, &written);
+
+ munmap ((caddr_t) buf, vm_page_size);
+
+ if (err || written < want)
+ return EIO;
+ else
+ return 0;
+ }
+}
+
+/* A page should be made writable. */
+error_t
+pager_unlock_page (struct user_pager_info *upi, vm_offset_t address)
+{
+ struct dev *dev = (struct dev *)upi;
+
+ if (dev->store->flags & STORE_READONLY)
+ return EROFS;
+ else
+ return 0;
+}
+
+/* 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. */
+error_t
+pager_report_extent (struct user_pager_info *upi,
+ vm_address_t *offset, vm_size_t *size)
+{
+ *offset = 0;
+ *size = ((struct dev *)upi)->store->size;
+ return 0;
+}
+
+/* This is called when a pager is being deallocated after all extant send
+ rights have been destroyed. */
+void
+pager_clear_user_data (struct user_pager_info *upi)
+{
+ struct dev *dev = (struct dev *)upi;
+ mutex_lock (&dev->pager_lock);
+ dev->pager = 0;
+ mutex_unlock (&dev->pager_lock);
+}
+
+static struct port_bucket *pager_port_bucket = 0;
+
+/* A top-level function for the paging thread that just services paging
+ requests. */
+static void
+service_paging_requests (any_t arg)
+{
+ for (;;)
+ ports_manage_port_operations_multithread (pager_port_bucket,
+ pager_demuxer,
+ 1000 * 30, 1000 * 60 * 5, 0);
+}
+
+/* Initialize paging for this device. */
+static void
+init_dev_paging ()
+{
+ if (! pager_port_bucket)
+ {
+ static struct mutex pager_global_lock = MUTEX_INITIALIZER;
+
+ mutex_lock (&pager_global_lock);
+ if (pager_port_bucket == NULL)
+ {
+ pager_port_bucket = ports_create_bucket ();
+
+ /* Make a thread to service paging requests. */
+ cthread_detach (cthread_fork ((cthread_fn_t)service_paging_requests,
+ (any_t)0));
+ }
+ mutex_unlock (&pager_global_lock);
+ }
+}
+
+void
+pager_dropweak (struct user_pager_info *upi __attribute__ ((unused)))
+{
+}
+
+/* Try to stop all paging activity on DEV, returning true if we were
+ successful. If NOSYNC is true, then we won't write back any (kernel)
+ cached pages to the device. */
+int
+dev_stop_paging (struct dev *dev, int nosync)
+{
+ size_t num_pagers = (pager_port_bucket ?
+ ports_count_bucket (pager_port_bucket) : 0);
+
+ if (num_pagers > 0 && !nosync)
+ {
+ error_t block_cache (void *arg)
+ {
+ struct pager *p = arg;
+ pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_DELAY, 1);
+ return 0;
+ }
+ error_t enable_cache (void *arg)
+ {
+ struct pager *p = arg;
+ pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_DELAY, 0);
+ return 0;
+ }
+
+ /* Loop through the pagers and turn off caching one by one,
+ synchronously. That should cause termination of each pager. */
+ ports_bucket_iterate (pager_port_bucket, block_cache);
+
+ /* Give it a second; the kernel doesn't actually shutdown
+ immediately. XXX */
+ sleep (1);
+
+ num_pagers = ports_count_bucket (pager_port_bucket);
+ if (num_pagers > 0)
+ /* Darn, there are actual honest users. Turn caching back on,
+ and return failure. */
+ ports_bucket_iterate (pager_port_bucket, enable_cache);
+ }
+
+ return num_pagers == 0;
+}
+
+/* Returns in MEMOBJ the port for a memory object backed by the storage on
+ DEV. Returns 0 or the error code if an error occurred. */
+error_t
+dev_get_memory_object (struct dev *dev, vm_prot_t prot, memory_object_t *memobj)
+{
+ error_t err = store_map (dev->store, prot, memobj);
+
+ if (err == EOPNOTSUPP && !dev->inhibit_cache)
+ {
+ int created = 0;
+
+ init_dev_paging ();
+
+ mutex_lock (&dev->pager_lock);
+
+ if (dev->pager == NULL)
+ {
+ dev->pager =
+ pager_create ((struct user_pager_info *)dev, pager_port_bucket,
+ 1, MEMORY_OBJECT_COPY_DELAY);
+ if (dev->pager == NULL)
+ {
+ mutex_unlock (&dev->pager_lock);
+ return errno;
+ }
+ created = 1;
+ }
+
+ *memobj = pager_get_port (dev->pager);
+
+ if (*memobj == MACH_PORT_NULL)
+ /* Pager is currently being destroyed, try again. */
+ {
+ dev->pager = 0;
+ mutex_unlock (&dev->pager_lock);
+ return dev_get_memory_object (dev, prot, memobj);
+ }
+ else
+ err =
+ mach_port_insert_right (mach_task_self (),
+ *memobj, *memobj, MACH_MSG_TYPE_MAKE_SEND);
+
+ if (created)
+ ports_port_deref (dev->pager);
+
+ mutex_unlock (&dev->pager_lock);
+ }
+
+ return err;
+}
diff --git a/storeio/storeio.c b/storeio/storeio.c
new file mode 100644
index 00000000..a88c8e43
--- /dev/null
+++ b/storeio/storeio.c
@@ -0,0 +1,425 @@
+/* A translator for doing I/O to stores
+
+ Copyright (C) 1995,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <error.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <argz.h>
+
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <version.h>
+
+#include "open.h"
+#include "dev.h"
+
+static struct argp_option options[] =
+{
+ {"readonly", 'r', 0, 0,"Disallow writing"},
+ {"writable", 'w', 0, 0,"Allow writing"},
+ {"no-cache", 'c', 0, 0,"Never cache data--user io does direct device io"},
+ {"no-file-io", 'F', 0, 0,"Never perform io via plain file io RPCs"},
+ {"no-fileio", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"enforced", 'e', 0, 0,"Never reveal underlying devices, even to root"},
+ {"rdev", 'n', "ID", 0,
+ "The stat rdev number for this node; may be either a"
+ " single integer, or of the form MAJOR,MINOR"},
+ {0}
+};
+static const char doc[] = "Translator for devices and other stores";
+
+const char *argp_program_version = STANDARD_HURD_VERSION (storeio);
+
+/* Desired store parameters specified by the user. */
+struct storeio_argp_params
+{
+ struct store_argp_params store_params; /* Filled in by store_argp parser. */
+ struct dev *dev; /* We fill in its flag members. */
+};
+
+/* Parse a single option. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct storeio_argp_params *params = state->input;
+
+ switch (key)
+ {
+
+ case 'r': params->dev->readonly = 1; break;
+ case 'w': params->dev->readonly = 0; break;
+
+ case 'c': params->dev->inhibit_cache = 1; break;
+ case 'e': params->dev->enforced = 1; break;
+ case 'F': params->dev->no_fileio = 1; break;
+
+ case 'n':
+ {
+ char *start = arg, *end;
+ dev_t rdev;
+
+ rdev = strtoul (start, &end, 0);
+ if (*end == ',')
+ /* MAJOR,MINOR form */
+ {
+ start = end + 1;
+ rdev = makedev (rdev, strtoul (start, &end, 0));
+ }
+
+ if (end == start || *end != '\0')
+ {
+ argp_error (state, "%s: Invalid argument to --rdev", arg);
+ return EINVAL;
+ }
+
+ params->dev->rdev = rdev;
+ }
+ break;
+
+ case ARGP_KEY_INIT:
+ /* Now store_argp's parser will get to initialize its state.
+ The default_type member is our input parameter to it. */
+ bzero (&params->store_params, sizeof params->store_params);
+ params->store_params.default_type = "device";
+ params->store_params.store_optional = 1;
+ state->child_inputs[0] = &params->store_params;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ params->dev->store_name = params->store_params.result;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static const struct argp_child argp_kids[] = { { &store_argp }, {0} };
+static const struct argp argp = { options, parse_opt, 0, doc, argp_kids };
+
+struct trivfs_control *storeio_fsys;
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct dev device;
+ struct storeio_argp_params params;
+
+ bzero (&device, sizeof device);
+ mutex_init (&device.lock);
+
+ params.dev = &device;
+ argp_parse (&argp, argc, argv, 0, 0, &params);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (2, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &storeio_fsys);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ storeio_fsys->hook = &device;
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (storeio_fsys->pi.bucket,
+ trivfs_demuxer,
+ 30*1000, 5*60*1000, 0);
+
+ return 0;
+}
+
+error_t
+trivfs_append_args (struct trivfs_control *trivfs_control,
+ char **argz, size_t *argz_len)
+{
+ struct dev *const dev = trivfs_control->hook;
+ error_t err = 0;
+
+ if (dev->rdev != (dev_t) 0)
+ {
+ char buf[40];
+ snprintf (buf, sizeof buf, "--rdev=%d,%d",
+ major (dev->rdev), minor (dev->rdev));
+ err = argz_add (argz, argz_len, buf);
+ }
+
+ if (!err && dev->inhibit_cache)
+ err = argz_add (argz, argz_len, "--no-cache");
+
+ if (!err && dev->enforced)
+ err = argz_add (argz, argz_len, "--enforced");
+
+ if (!err && dev->no_fileio)
+ err = argz_add (argz, argz_len, "--no-file-io");
+
+ if (! err)
+ err = argz_add (argz, argz_len,
+ dev->readonly ? "--readonly" : "--writable");
+
+ if (! err)
+ err = store_parsed_append_args (dev->store_name, argz, argz_len);
+
+ return err;
+}
+
+/* Called whenever a new lookup is done of our node. The only reason we
+ set this hook is to duplicate the check done normally done against
+ trivfs_allow_open in trivfs_S_fsys_getroot, but looking at the
+ per-device state. This gets checked again in check_open_hook, but this
+ hook runs before a little but more overhead gets incurred. In the
+ success case, we just return EAGAIN to have trivfs_S_fsys_getroot
+ continue with its generic processing. */
+static error_t
+getroot_hook (struct trivfs_control *cntl,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type)
+{
+ struct dev *const dev = cntl->hook;
+ return (dev_is_readonly (dev) && (flags & O_WRITE)) ? EROFS : EAGAIN;
+}
+
+/* Called whenever someone tries to open our node (even for a stat). We
+ delay opening the kernel device until this point, as we can usefully
+ return errors from here. */
+static error_t
+check_open_hook (struct trivfs_control *trivfs_control,
+ struct iouser *user,
+ int flags)
+{
+ struct dev *const dev = trivfs_control->hook;
+ error_t err = 0;
+
+ if (!err && dev_is_readonly (dev) && (flags & O_WRITE))
+ return EROFS;
+
+ mutex_lock (&dev->lock);
+ if (dev->store == NULL)
+ {
+ /* Try and open the store. */
+ err = dev_open (dev);
+ if (err && (flags & (O_READ|O_WRITE)) == 0)
+ /* If we're not opening for read or write, then just ignore the
+ error, as this allows stat to work correctly. XXX */
+ err = 0;
+ }
+ mutex_unlock (&dev->lock);
+
+ return err;
+}
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+ error_t err = 0;
+ struct dev *const dev = peropen->cntl->hook;
+
+ if (dev->store)
+ {
+ mutex_lock (&dev->lock);
+ if (dev->nperopens++ == 0)
+ err = store_clear_flags (dev->store, STORE_INACTIVE);
+ mutex_unlock (&dev->lock);
+ if (!err)
+ err = open_create (dev, (struct open **)&peropen->hook);
+ }
+ return err;
+}
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+ struct dev *const dev = peropen->cntl->hook;
+
+ if (peropen->hook)
+ {
+ mutex_lock (&dev->lock);
+ if (--dev->nperopens == 0)
+ store_set_flags (dev->store, STORE_INACTIVE);
+ mutex_unlock (&dev->lock);
+ open_free (peropen->hook);
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ | O_WRITE;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ struct dev *const dev = cred->po->cntl->hook;
+ struct open *open = cred->po->hook;
+
+ st->st_mode &= ~S_IFMT;
+
+ if (open)
+ /* An open device. */
+ {
+ struct store *store = open->dev->store;
+ store_offset_t size = store->size;
+
+ if (store->block_size > 1)
+ st->st_blksize = store->block_size;
+
+ st->st_size = size;
+ st->st_mode |= ((dev->inhibit_cache || store->block_size == 1)
+ ? S_IFCHR : S_IFBLK);
+ }
+ else
+ /* Try and do things without an open device... */
+ {
+ st->st_blksize = 0;
+ st->st_size = 0;
+
+ st->st_mode |= dev->inhibit_cache ? S_IFCHR : S_IFBLK;
+ }
+
+ st->st_rdev = dev->rdev;
+ if (dev_is_readonly (dev))
+ st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ struct dev *const device = fsys->hook;
+ error_t err;
+ int force = (flags & FSYS_GOAWAY_FORCE);
+ int nosync = (flags & FSYS_GOAWAY_NOSYNC);
+ struct port_class *root_port_class = fsys->protid_class;
+
+ mutex_lock (&device->lock);
+
+ if (device->store == NULL)
+ /* The device is not actually open.
+ XXX note that exitting here nukes non-io users, like someone
+ in the middle of a stat who will get SIGLOST or something. */
+ exit (0);
+
+ /* Wait until all pending rpcs are done. */
+ err = ports_inhibit_class_rpcs (root_port_class);
+ if (err == EINTR || (err && !force))
+ {
+ mutex_unlock (&device->lock);
+ return err;
+ }
+
+ if (force && nosync)
+ /* Exit with extreme prejudice. */
+ exit (0);
+
+ if (!force && ports_count_class (root_port_class) > 0)
+ /* Still users, so don't exit. */
+ goto busy;
+
+ if (! nosync)
+ /* Sync the device here, if necessary, so that closing it won't result in
+ any I/O (which could get hung up trying to use one of our pagers). */
+ dev_sync (device, 1);
+
+ /* devpager_shutdown may sync the pagers as side-effect (if NOSYNC is 0),
+ so we put that first in this test. */
+ if (dev_stop_paging (device, nosync) || force)
+ /* Bye-bye. */
+ {
+ if (! nosync)
+ /* If NOSYNC is true, we don't close DEV, as that could cause data to
+ be written back. */
+ dev_close (device);
+ exit (0);
+ }
+
+ busy:
+ /* Allow normal operations to proceed. */
+ ports_enable_class (root_port_class);
+ ports_resume_class_rpcs (root_port_class);
+ mutex_unlock (&device->lock);
+
+ /* Complain that there are still users. */
+ return EBUSY;
+}
+
+/* If this variable is set, it is called by trivfs_S_fsys_getroot before any
+ other processing takes place; if the return value is EAGAIN, normal trivfs
+ getroot processing continues, otherwise the rpc returns with that return
+ value. */
+error_t (*trivfs_getroot_hook) (struct trivfs_control *cntl,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type)
+ = getroot_hook;
+
+/* If this variable is set, it is called every time an open happens.
+ USER and FLAGS are from the open; CNTL identifies the
+ node being opened. This call need not check permissions on the underlying
+ node. If the open call should block, then return EWOULDBLOCK. Other
+ errors are immediately reflected to the user. If O_NONBLOCK
+ is not set in FLAGS and EWOULDBLOCK is returned, then call
+ trivfs_complete_open when all pending open requests for this
+ file can complete. */
+error_t (*trivfs_check_open_hook)(struct trivfs_control *trivfs_control,
+ struct iouser *user,
+ int flags)
+ = check_open_hook;
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+ is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+/* Sync this filesystem. */
+kern_return_t
+trivfs_S_fsys_syncfs (struct trivfs_control *cntl,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ int wait, int dochildren)
+{
+ struct dev *dev = cntl->hook;
+ if (dev)
+ return dev_sync (dev, wait);
+ else
+ return 0;
+}
diff --git a/sutils/ChangeLog b/sutils/ChangeLog
deleted file mode 100644
index 7d8ca832..00000000
--- a/sutils/ChangeLog
+++ /dev/null
@@ -1,60 +0,0 @@
-Thu Aug 1 16:29:31 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * clookup.c (file_name_lookup_carefully/lookup): When appending
- TAIL to RETRY_NAME, use strcpy instead of strcat.
-
-Sat Jul 6 19:55:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsck.c: (argp_program_version): New variable.
-
-Wed Jul 3 14:22:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fstab.c (fstab_add_fs): Don't SEGV if COPY is 0.
-
-Thu Jun 27 00:01:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsck.c (fsck): Fsck pass 0 if not in automatic mode. Respect
- `noauto' option in automatic mode.
- (main): Set FSCK_F_AUTO flag if in automatic mode.
- (FSCK_F_AUTO): New macro.
- (fs_start_fsck): When deciding to use a flags arg, mask flags
- against an explicit list of valid ones.
-
-Tue Jun 25 18:39:44 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsck.c (main, options): Add --writable/-w option.
- (FSCK_F_WRITABLE): New macro.
- (struct fsck): Rename WAS_READONLY field to MAKE_WRITABLE.
- (fscks_start_fsck): Change to set make_writable field instead of
- was_readonly.
- (fsck_cleanup): Change RESTORE_WRITABLE to MAKE_WRITABLE.
- (fscks_wait): Likewise.
-
-Thu Jun 20 14:08:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsck.c (fsck): Wait for fscks to finish.
- * fstab.c (fstypes_create): Copy SEARCH_FMTS contents into NEW.
- (fs_set_mntent): Don't keep old fsys fields if the mnt_dir is changed.
- (fstab_add_mntent): Initialize fields in FS with non-zero values.
- (_fs_check_mounted): The root is always mounted.
-
-Wed Jun 19 10:44:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fstab.c (fs_set_readonly, fs_remount): If fsys_set_options
- returns EINVAL, return EOPNOTSUPP instead.
- (fs_set_readonly): Use fsys_set_readonly.
- (fs_remount): Use fsys_remount.
- (fs_readonly): Use fsys_get_readonly.
- (_fs_check_mounted): Use file_name_lookup_carefully.
- * clookup.c: New file.
- * fsck.c (_debug): New variable.
- (debug, fs_debug): New macros.
- (fs_start_fsck, fscks_start_fsck, fsck_cleanup, fscks_wait, fsck, main):
- Add debugging noise.
- (main): Use FSTAB_PATH instead of _PATH_MNTTAB.
- (args_doc): Fix.
-
-Tue Jun 18 22:56:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsck.c (options): Rename `--max-parallel' to `--parallel'.
-
diff --git a/sutils/MAKEDEV.sh b/sutils/MAKEDEV.sh
new file mode 100644
index 00000000..4277b052
--- /dev/null
+++ b/sutils/MAKEDEV.sh
@@ -0,0 +1,204 @@
+#!/bin/sh
+#
+# Make standard devices
+#
+
+PATH=/bin:/usr/bin
+
+ECHO=: # Change to "echo" to echo commands.
+EXEC="" # Change to ":" to suppress command execution.
+DEVDIR=`pwd` # Reset below by -D/--devdir command line option.
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "\
+Usage: $0 [OPTION...] DEVNAME...
+Make filesystem nodes for accessing standard system devices
+
+ -D, --devdir=DIR Use DIR when a device node name must be
+ embedded in a translator; default is the cwd
+ -n, --dry-run Don't actually execute any commands
+ -v, --verbose Show what commands are executed to make the devices
+ -?, --help Give this help list
+ --usage Give a short usage message
+ -V, --version Print program version"
+ exit 0;;
+ --devdir) DEVDIR="$2"; shift 2;;
+ --devdir=*) DEVDIR="`echo "$1" | sed 's/^--devdir=//'`"; shift 1;;
+ -D) DEVDIR="$2"; shift 2;;
+ -D*) DEVDIR="`echo "$1" | sed 's/^-D//'`"; shift 1;;
+ --verbose|-v) ECHO=echo; shift;;
+ --dry-run|-n) EXEC=:; shift;;
+ -nv|-vn) ECHO=echo; EXEC=:; shift;;
+ --usage)
+ echo "Usage: $0 [-V?] [-D DIR] [--help] [--usage] [--version] [--devdir=DIR] DEVNAME..."
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_MAKEDEV_"; exit 0;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+case "$#" in 0)
+ echo 1>&2 "Usage: $0 [OPTION...] DEVNAME..."
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information"
+ exit 1;;
+esac
+
+cmd() {
+ eval $ECHO "$@"
+ eval $EXEC "$@"
+}
+
+st() {
+ local NODE="$1"
+ local OWNER="$2"
+ local PERM="$3"
+ shift 3
+ if cmd settrans -cg "$NODE"; then
+ cmd chown "$OWNER" "$NODE"
+ cmd chmod "$PERM" "$NODE"
+ cmd settrans "$NODE" "$@"
+ fi
+}
+
+lose() {
+ local line
+ for line; do
+ echo 1>&2 "$0: $line"
+ done
+ exit 1
+}
+
+mkdev() {
+ local I
+ for I; do
+ case $I in
+ /* | */*)
+ lose "Device names cannot contain directories" \
+ "Change to target directory and run $0 from there."
+ ;;
+
+ std)
+ mkdev console tty null zero full fd time mem klog shm
+ ;;
+ console|com[0-9])
+ st $I root 600 /hurd/term ${DEVDIR}/$I device $I;;
+ vcs)
+ st $I root 600 /hurd/console;;
+ tty[1-9][0-9]|tty[1-9])
+ st $I root 600 /hurd/term ${DEVDIR}/$I hurdio \
+ ${DEVDIR}/vcs/`echo $I | sed -e s/tty//`/console;;
+ lpr[0-9])
+ st $I root 660 /hurd/streamio "$I";;
+ null)
+ st $I root 666 /hurd/null;;
+ full)
+ st $I root 666 /hurd/null --full;;
+ zero)
+ st $I root 666 /hurd/storeio -Tzero;;
+ tty)
+ st $I root 666 /hurd/magic tty;;
+ fd)
+ st $I root 666 /hurd/magic --directory fd
+ cmd ln -f -s fd/0 stdin
+ cmd ln -f -s fd/1 stdout
+ cmd ln -f -s fd/2 stderr
+ ;;
+ 'time')
+ st $I root 644 /hurd/storeio --no-cache time ;;
+ mem)
+ st $I root 660 /hurd/storeio --no-cache mem ;;
+ klog)
+ st $I root 660 /hurd/streamio kmsg;;
+ # ptys
+ [pt]ty[pqrstuvwxyzPQRS]?)
+ # Make one pty, both the master and slave halves.
+ 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 \
+ pty-slave ${DEVDIR}/pty$id
+ ;;
+ [pt]ty[pqrstuvwxyzPQRS])
+ # Make a bunch of ptys.
+ local n
+ for n in 0 1 2 3 4 5 6 7 8 9 \
+ a b c d e f g h i j k l m n o p q r s t u v; do
+ mkdev ${I}${n}
+ done
+ ;;
+
+ fd*|mt*)
+ st $I root 640 /hurd/storeio $I
+ ;;
+
+ [hrsc]d*)
+ local n="${I#?d}"
+ local major="${n%%[!0-9]*}"
+ if [ -z "$major" ]; then
+ lose "$I: Invalid device name: must supply a device number"
+ fi
+ local minor="${n##$major}"
+ case "$minor" in
+ '') ;; # Whole disk
+ [a-z]) ;; # BSD partition syntax, no slice syntax
+ s[1-9]*) # Slice syntax.
+ local slicestuff="${minor#s}"
+ local slice="${slicestuff%%[!0-9]*}"
+ local rest="${slicestuff##$slice}"
+ case "$slice" in
+ [1-9] | [1-9][0-9]) ;;
+ *)
+ lose "$I: Invalid slice number \`$slice'"
+ ;;
+ esac
+ case "$rest" in
+ '') ;; # Whole slice
+ [a-z]) ;; # BSD partition after slice
+ *)
+ lose "$I: Invalid partition \`$rest'"
+ ;;
+ esac
+ ;;
+ *)
+ lose "$I: Invalid slice or partition syntax"
+ ;;
+ esac
+
+ # The device name passed all syntax checks, so finally use it!
+ st $I root 640 /hurd/storeio $I
+ ;;
+
+ # /dev/shm is used by the POSIX.1 shm_open call in libc.
+ # We don't want the underlying node to be written by randoms,
+ # but the filesystem presented should be writable by anyone
+ # and have the sticky bit set so others' files can't be removed.
+ # tmpfs requires an arbitrary size limitation here. To be like
+ # Linux, we tell tmpfs to set the size to half the physical RAM
+ # in the machine.
+ shm)
+ st $I root 644 /hurd/tmpfs --mode=1777 50%
+ ;;
+
+ # Linux compatibility
+ loop*)
+ # In Linux an inactive "/dev/loopN" device acts like /dev/null.
+ # The `losetup' script changes the translator to "activate" the device.
+ st $I root 640 /hurd/null
+ ;;
+
+ *)
+ lose "$I: Unknown device name"
+ ;;
+ esac
+ done
+}
+
+mkdev "$@"
diff --git a/sutils/Makefile b/sutils/Makefile
index 388bea29..b2383579 100644
--- a/sutils/Makefile
+++ b/sutils/Makefile
@@ -1,6 +1,6 @@
-# Makefile for sutils
-#
-# Copyright (C) 1996 Free Software Foundation
+# Makefile for sutils
+#
+# Copyright (C) 1996,97,99,2000,2010 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
@@ -20,17 +20,25 @@
dir := sutils
makemode := utilities
-targets = reboot halt fsck
-SRCS = reboot.c halt.c fsck.c fstab.c clookup.c
+progs = reboot halt fsck swapon swapoff
+scripts = e2os MAKEDEV losetup
+targets = $(special-targets) $(progs)
+special-targets = $(scripts)
installationdir = $(sbindir)
+SRCS = $(progs:=.c) clookup.c fstab.c update.c $(scripts:=.sh)
+LCLHDRS = fstab.h
-OBJS = $(SRCS:.c=.o)
+OBJS = $(progs:=.c)
+HURDLIBS = store shouldbeinlibc
include ../Makeconf
-fsck: fstab.o clookup.o ../libshouldbeinlibc/libshouldbeinlibc.a
-
-%: %.sh
- cp $< $@
+fsck: fstab.o clookup.o
+swapon swapoff: ../libstore/libstore.a default_pagerUser.o
+$(progs): %: %.o ../libshouldbeinlibc/libshouldbeinlibc.a
-$(filter-out $(special-targets), $(targets)): %: %.o
+install: $(prefix)/dev $(prefix)/dev/MAKEDEV
+$(prefix)/dev/MAKEDEV:
+ ln -s ../sbin/MAKEDEV $@
+$(prefix)/dev:
+ @$(MKINSTALLDIRS) $@
diff --git a/sutils/clookup.c b/sutils/clookup.c
index e39ddd64..0107799c 100644
--- a/sutils/clookup.c
+++ b/sutils/clookup.c
@@ -1,6 +1,6 @@
/* Careful filename lookup
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -25,18 +25,18 @@
#include <string.h>
#include <errno.h>
#include <fcntl.h>
+#include <sys/mman.h>
#include <hurd.h>
#include <hurd/lookup.h>
#include <hurd/id.h>
#include <hurd/fsys.h>
-extern int __getuids (int num, gid_t *buf); /* XXX */
/* This function is like file_name_lookup, but tries hard to avoid starting
any passive translators. If a node with an unstarted passive translator
is encountered, ENXIO is returned in ERRNO; other errors are as for
file_name_lookup. Note that checking for an active translator currently
- requires fetching the control port, which is a priveleged operation. */
+ requires fetching the control port, which is a privileged operation. */
file_t
file_name_lookup_carefully (const char *name, int flags, mode_t mode)
{
@@ -94,8 +94,7 @@ file_name_lookup_carefully (const char *name, int flags, mode_t mode)
if (ptrans != _ptrans)
/* Deallocate out-of-line memory from file_get_translator. */
- vm_deallocate (mach_task_self (),
- (vm_address_t)ptrans, ptrans_len);
+ munmap (ptrans, ptrans_len);
err = file_get_translator_cntl (*node, &fsys);
if (! err)
@@ -107,10 +106,11 @@ file_name_lookup_carefully (const char *name, int flags, mode_t mode)
{
file_t old_node = *node;
err = fsys_getroot (fsys,
- unauth_dir, MACH_MSG_TYPE_MOVE_SEND,
+ unauth_dir, MACH_MSG_TYPE_COPY_SEND,
uids, num_uids, gids, num_gids,
flags & ~O_NOTRANS, retry,
retry_name, node);
+ mach_port_deallocate (mach_task_self (), unauth_dir);
if (! err)
mach_port_deallocate (mach_task_self (), old_node);
}
@@ -143,11 +143,11 @@ file_name_lookup_carefully (const char *name, int flags, mode_t mode)
}
/* Fetch uids for use with fsys_getroot. */
- num_uids = __getuids (0, 0);
+ num_uids = geteuids (0, 0);
if (num_uids < 0)
return errno;
uids = alloca (num_uids * sizeof (uid_t));
- num_uids = __getuids (num_uids, uids);
+ num_uids = geteuids (num_uids, uids);
if (num_uids < 0)
return errno;
@@ -159,11 +159,11 @@ file_name_lookup_carefully (const char *name, int flags, mode_t mode)
num_gids = getgroups (num_gids, gids);
if (num_gids < 0)
return errno;
-
+
/* Look things up ... */
- err = __hurd_file_name_lookup (&_hurd_ports_use, &__getdport, lookup,
- name, flags, mode & ~_hurd_umask,
- &node);
+ err = hurd_file_name_lookup (&_hurd_ports_use, &getdport, lookup,
+ name, flags, mode & ~getumask (),
+ &node);
return err ? (__hurd_fail (err), MACH_PORT_NULL) : node;
}
diff --git a/sutils/e2os.sh b/sutils/e2os.sh
new file mode 100755
index 00000000..60c9e017
--- /dev/null
+++ b/sutils/e2os.sh
@@ -0,0 +1,153 @@
+#!/bin/sh
+# Set/get the `creator_os' field of an ext2fs partition
+#
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+#
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# 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.
+#
+
+USAGE="Usage: $0 DEVICE [OS]"
+
+DD=${DD-/bin/dd}
+OD=${OD-/bin/od}
+SED=${SED-/bin/sed}
+AWK=${AWK-/bin/gawk}
+
+# Hack to allow this script to work well under linux too.
+test ! -x "$OD" -a -x /usr/bin/od && OD=/usr/bin/od
+test ! -x "$AWK" -a -x /usr/bin/gawk && AWK=/usr/bin/gawk
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "$USAGE"
+ echo "Get or set the creator_os parameter of an ext2fs partition."
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ exit 0;;
+ --usage)
+ echo "Usage: $0 [-V?] [--help] [--usage] [--version] DEVICE [OS]"
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_e2os_"; exit 0;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+case "$#" in 1 | 2) ;; # ok
+ *) echo 1>&2 "$USAGE"
+ echo 1>&2 "Try \`--help' for more information";
+ exit 1;;
+esac
+
+DEVICE="$1"; shift
+OS="$1"
+
+# Superblock fields (format is "BYTE_OFFS SIZE")
+SB_MAGIC="56 2"
+SB_OS="72 4"
+# Ext2fs magic numbers
+MAGIC_EXT2=ef53
+MAGIC_EXT2_OLD=ef53
+# Symbolic names for os types we know about
+OS_LINUX=0
+OS_HURD=1
+OS_MASIX=2
+OS_FREEBSD=3
+OS_LITES=4
+
+# Superblock
+SB=/tmp/,e2os-sb.$$
+
+# We have to store error output in a file so that we can filter it (for all
+# unix's stressing of pipelines, /bin/sh sure works hard to prevent you using
+# them).
+ERRS=/tmp/,e2os-errs.$$
+
+trap "/bin/rm -f $SB $ERRS" 0
+
+# Read the superblock
+$DD 2>"$ERRS" if="$DEVICE" of="$SB" bs=1k skip=1 count=1 \
+|| { $SED 1>&2 "s;^$DD:;$0:;" "$ERRS"; exit 2; }
+
+# Extract a word of SZ bytes from byte offset POS in the superblock
+# Optional arg FMT is what format to use (x = hex, d = decimal)
+sbget ()
+{
+ local pos="$1" sz="$2" fmt="${3-d}"
+ pos=$(($pos / $sz))
+ $DD 2>/dev/null if="$SB" bs="$sz" skip="$pos" count=1 \
+ | $OD -An -t"$fmt$sz" \
+ | $SED 's;^[ 0]*\(.\);\1;'
+}
+
+# Set a word of SZ bytes at byte offset POS in the superblock to VAL
+sbset ()
+{
+ local pos="$1" sz="$2" val="$3"
+ pos=$(($pos / $sz))
+ echo "$val" \
+ | $AWK '{ n=$1+0; printf ("%c%c%c%c", n, n/256, n/(2^16), n/(2^24)); }' \
+ | $DD 2>/dev/null of="$SB" bs="$sz" seek="$pos" count=1 conv=notrunc
+}
+
+# Check the magic number
+magic="`sbget $SB_MAGIC x`"
+case "$magic" in
+ $MAGIC_EXT2) ;; # ok
+ $MAGIC_EXT2_OLD) echo "$0: $DEVICE: Old-format ext2 filesystem"; exit 3;;
+ *) echo "$0: $DEVICE: Not an ext2 filesystem (magic = 0x$magic)"; exit 4;;
+esac
+
+if test "$OS"; then
+ # Set the os field
+ case "$OS" in
+ linux) OS=$OS_LINUX;;
+ hurd) OS=$OS_HURD;;
+ masix) OS=$OS_MASIX;;
+ freebsd) OS=$OS_FREEBSD;;
+ lites) OS=$OS_LITES;;
+ "*[!0-9]*")
+ echo 1>&2 "$0: $OS: Unknown ext2 creator_os value"; exit 5;;
+ esac
+
+ # Frob the superlock
+ sbset $SB_OS "$OS"
+
+ # Write the superblock
+ $DD 2>"$ERRS" if="$SB" of="$DEVICE" bs=1k seek=1 count=1 conv=notrunc \
+ || { $SED 1>&2 "s;^$DD:;$0:;" "$ERRS"; exit 6; }
+else
+ # Print the os field.
+ OS="`sbget $SB_OS`"
+ case "$OS" in
+ "") exit 2;;
+ $OS_LINUX) OS=linux;;
+ $OS_HURD) OS=hurd;;
+ $OS_MASIX) OS=masix;;
+ $OS_FREEBSD) OS=freebsd;;
+ $OS_LITES) OS=lites;;
+ esac
+ echo "$OS"
+fi
diff --git a/sutils/fsck.c b/sutils/fsck.c
index ec2628ba..1ab9caa5 100644
--- a/sutils/fsck.c
+++ b/sutils/fsck.c
@@ -1,8 +1,8 @@
/* Hurd-aware fsck wrapper
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 97, 98, 99 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This file is part of the GNU Hurd.
@@ -28,7 +28,7 @@
-n Automatically answer no to all questions
-f Check even if clean
-s Only print diagostic messages
-
+
They should also return exit-status codes as following:
0 Filesystem was clean
@@ -41,7 +41,7 @@
Although it knows something about the hurd, this fsck still uses
/etc/fstab, and is generally not very integrated. That will have to wait
- until the appropiate mechanisms for doing so are decided. */
+ until the appropriate mechanisms for doing so are decided. */
#include <stdlib.h>
#include <string.h>
@@ -51,10 +51,12 @@
#include <argp.h>
#include <argz.h>
#include <assert.h>
+#include <version.h>
#include "fstab.h"
-char *argp_program_version = "fsck 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (fsck);
+
/* for debugging */
static int _debug = 0;
@@ -93,6 +95,7 @@ static int _debug = 0;
#define FSCK_F_VERBOSE 0x100
#define FSCK_F_WRITABLE 0x200 /* Make writable after fscking. */
#define FSCK_F_AUTO 0x400 /* Do all filesystems in fstab. */
+#define FSCK_F_DRYRUN 0x800 /* Don't actually do anything. */
static int got_sigquit = 0, got_sigint = 0;
@@ -110,7 +113,7 @@ struct fsck
{
struct fs *fs; /* Filesystem being fscked. */
int pid; /* Pid for process. */
- int make_writable :1; /* Make writable after fscking if possible. */
+ int make_writable; /* Make writable after fscking if possible. */
struct fsck *next, **self;
};
@@ -155,6 +158,17 @@ fs_start_fsck (struct fs *fs, int flags)
*argp++ = fs->mntent.mnt_fsname;
*argp = 0;
+ if (flags & FSCK_F_DRYRUN)
+ {
+ char *argz;
+ size_t argz_len;
+ argz_create (argv, &argz, &argz_len);
+ argz_stringify (argz, argz_len, ' ');
+ puts (argz);
+ free (argz);
+ return 0;
+ }
+
pid = fork ();
if (pid < 0)
{
@@ -209,7 +223,7 @@ fscks_start_fsck (struct fscks *fscks, struct fs *fs)
fs_debug (fs, "Checking mounted state");
err = fs_mounted (fs, &mounted);
CK (err, "%s: Cannot check mounted state", fs->mntent.mnt_dir);
-
+
if (mounted)
{
int readonly;
@@ -218,6 +232,16 @@ fscks_start_fsck (struct fscks *fscks, struct fs *fs)
err = fs_readonly (fs, &readonly);
CK (err, "%s: Cannot check readonly state", fs->mntent.mnt_dir);
+ if (fscks->flags & FSCK_F_DRYRUN)
+ {
+ if (! readonly)
+ {
+ printf ("%s: writable filesystem %s would be made read-only\n",
+ program_invocation_name, fs->mntent.mnt_dir);
+ readonly = 1;
+ }
+ }
+
if (! readonly)
{
fs_debug (fs, "Making readonly");
@@ -272,7 +296,10 @@ fsck_cleanup (struct fsck *fsck, int remount, int make_writable)
error_t err = 0;
struct fs *fs = fsck->fs;
- *fsck->self = fsck->next; /* Remove from chain. */
+ /* Remove from chain. */
+ *fsck->self = fsck->next;
+ if (fsck->next)
+ fsck->next->self = fsck->self;
fs_debug (fs, "Cleaning up after fsck (remount = %d, make_writable = %d)",
remount, make_writable);
@@ -322,7 +349,7 @@ fscks_wait (struct fscks *fscks)
debug ("Waiting...");
- do
+ do
pid = wait (&wstatus);
while (pid < 0 && errno == EINTR);
@@ -387,20 +414,18 @@ fsck (struct fstab *fstab, int flags, int max_parallel)
summary_status = status;
}
- /* Do in pass order; if in automatic mode, we skip pass 0. */
- for (pass = autom ? 1 : 0; pass >= 0; pass = fstab_next_pass (fstab, pass))
+ /* Do in pass order; pass 0 is never run, it is reserved for "off". */
+ for (pass = 1; pass > 0; pass = fstab_next_pass (fstab, pass))
/* Submit all filesystems in the given pass, up to MAX_PARALLEL at a
time. There should currently be no fscks running. */
{
debug ("Pass %d", pass);
- /* Do pass 0 filesystems one at a time. */
- fscks.free_slots = (pass == 0 ? 1 : max_parallel);
+ fscks.free_slots = max_parallel;
/* Try and fsck every filesystem in this pass. */
for (fs = fstab->entries; fs; fs = fs->next)
- if (fs->mntent.mnt_passno == pass
- && !(autom && hasmntopt (&fs->mntent, "noauto")))
+ if (fs->mntent.mnt_passno == pass)
/* FS is applicable for this pass. */
{
struct fstype *type;
@@ -421,8 +446,11 @@ fsck (struct fstab *fstab, int flags, int max_parallel)
merge_status (fscks_wait (&fscks));
merge_status (fscks_start_fsck (&fscks, fs));
}
- else
+ else if (autom)
fs_debug (fs, "Not fsckable");
+ else
+ error (0, 0, "%s: %s: Not a fsckable filesystem type",
+ fs->mntent.mnt_dir, fs->mntent.mnt_type);
}
/* Now wait for them all to finish. */
@@ -433,48 +461,44 @@ fsck (struct fstab *fstab, int flags, int max_parallel)
return summary_status;
}
-static const struct argp_option
-options[] =
+static const struct argp_option options[] =
{
{"preen", 'p', 0, 0, "Terse automatic mode", 1},
{"yes", 'y', 0, 0, "Automatically answer yes to all questions"},
{"no", 'n', 0, 0, "Automatically answer no to all questions"},
- {"fstab", 't', "FILE", 0, "File to use instead of " _PATH_MNTTAB},
{"parallel", 'l', "NUM", 0, "Limit the number of parallel checks to NUM"},
{"verbose", 'v', 0, 0, "Print informational messages"},
{"writable", 'w', 0, 0,
"Make RW filesystems writable after fscking, if possible"},
{"debug", 'D', 0, OPTION_HIDDEN },
- {"search-fmts",'S', "FMTS", 0,
- "`:' separated list of formats to use for finding fsck programs"},
- {0, 0, 0, 0, "In --preen mode, the following also apply:", 2},
{"force", 'f', 0, 0, "Check even if clean"},
- {"silent", 's', 0, 0, "Only print diagostic messages"},
+
+ {"dry-run", 'N', 0, 0, "Don't check, just show what would be done"},
+ {0, 0, 0, 0, "In --preen mode, the following also apply:", 2},
+ {"silent", 's', 0, 0, "Print only diagnostic messages"},
{"quiet", 'q', 0, OPTION_ALIAS | OPTION_HIDDEN },
{0, 0}
};
-static const char *args_doc = "[ DEVICE|FSYS... ]";
-static const char *doc = 0;
+static const char doc[] = "Filesystem consistency check and repair";
+static const char args_doc[] = "[ DEVICE|FSYS... ]";
+
int
main (int argc, char **argv)
{
- error_t err;
- struct fstab *fstab, *check;
- struct fstypes *types;
+ struct fstab *check;
int status; /* exit status */
int flags = 0;
- char *names = 0;
- size_t names_len = 0;
- char *search_fmts = FSCK_SEARCH_FMTS;
- size_t search_fmts_len = sizeof FSCK_SEARCH_FMTS;
- char *fstab_path = _PATH_MNTTAB;
int max_parallel = -1; /* -1 => use default */
error_t parse_opt (int key, char *arg, struct argp_state *state)
{
+ struct fstab_argp_params *params = state->input;
switch (key)
{
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = params; /* pass down to fstab_argp parser */
+ break;
case 'p': flags |= FSCK_F_PREEN; break;
case 'y': flags |= FSCK_F_YES; break;
case 'n': flags |= FSCK_F_NO; break;
@@ -482,79 +506,49 @@ main (int argc, char **argv)
case 's': flags |= FSCK_F_SILENT; break;
case 'v': flags |= FSCK_F_VERBOSE; break;
case 'w': flags |= FSCK_F_WRITABLE; break;
- case 't': fstab_path = arg; break;
+ case 'N': flags |= FSCK_F_DRYRUN; break;
case 'D': _debug = 1; break;
case 'l':
max_parallel = atoi (arg);
- if (! max_parallel)
- argp_error (state, "%s: Invalid value for --max-parellel", arg);
- break;
- case 'S':
- argz_create_sep (arg, ':', &search_fmts, &search_fmts_len);
+ if (max_parallel < 1)
+ argp_error (state, "%s: Invalid value for --max-parallel", arg);
break;
- case ARGP_KEY_ARG:
- err = argz_add (&names, &names_len, arg);
- if (err)
- argp_failure (state, 100, ENOMEM, "%s", arg);
+ case ARGP_KEY_NO_ARGS:
+ if (flags & FSCK_F_PREEN)
+ params->do_all = 1;
+ else if (!params->do_all)
+ {
+ argp_usage (state);
+ return EINVAL;
+ }
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
- struct argp argp = {options, parse_opt, args_doc, doc};
-
- argp_parse (&argp, argc, argv, 0, 0, 0);
-
- err = fstypes_create (search_fmts, search_fmts_len, &types);
- if (err)
- error (102, err, "fstypes_create");
-
- err = fstab_create (types, &fstab);
- if (err)
- error (101, err, "fstab_create");
-
- debug ("Reading %s...", fstab_path);
- err = fstab_read (fstab, fstab_path);
- if (err)
- error (103, err, "%s", fstab_path);
+ static const struct argp_child kids[] =
+ { { &fstab_argp, 0,
+ "Filesystem selection (default is all in " _PATH_MNTTAB "):", 2 },
+ { 0 } };
+ struct argp argp = { options, parse_opt, args_doc, doc, kids };
+ struct fstab_argp_params fstab_params;
- if (names)
- /* Fsck specified filesystems; also look at /var/run/mtab. */
- {
- char *name;
-
- debug ("Reading %s...", _PATH_MOUNTED);
- err = fstab_read (fstab, _PATH_MOUNTED);
- if (err && err != ENOENT)
- error (104, err, "%s", _PATH_MOUNTED);
+ argp_parse (&argp, argc, argv, 0, 0, &fstab_params);
- err = fstab_create (types, &check);
- if (err)
- error (105, err, "fstab_create");
+ check = fstab_argp_create (&fstab_params,
+ FSCK_SEARCH_FMTS, sizeof FSCK_SEARCH_FMTS);
+ if (fstab_params.do_all)
+ flags |= FSCK_F_AUTO;
- for (name = names; name; name = argz_next (names, names_len, name))
- {
- struct fs *fs = fstab_find (fstab, name);
- if (! fs)
- error (106, 0, "%s: Unknown device or filesystem", name);
- fs_debug (fs, "Adding to checked filesystems");
- fstab_add_fs (check, fs, 0);
- }
- }
- else
- /* Fsck everything in /etc/fstab. */
+ if (max_parallel <= 0)
{
- check = fstab;
- flags |= FSCK_F_AUTO;
+ if (flags & FSCK_F_PREEN)
+ max_parallel = 100; /* In preen mode, do lots in parallel. */
+ else
+ max_parallel = 1; /* Do one at a time to keep output rational. */
}
- if (max_parallel <= 0)
- if (flags & FSCK_F_PREEN)
- max_parallel = 100; /* In preen mode, do lots in parallel. */
- else
- max_parallel = 1; /* Do one at a time to keep output rational. */
-
/* If the user send a SIGQUIT (usually ^\), then do all checks, but
regardless of their outcome, return a status that will cause the
automatic reboot to stop after fscking is complete. */
diff --git a/sutils/fstab.c b/sutils/fstab.c
index 6c8e0f81..b66e5195 100644
--- a/sutils/fstab.c
+++ b/sutils/fstab.c
@@ -1,6 +1,6 @@
/* Fstab filesystem frobbing
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -27,6 +27,8 @@
#include <fcntl.h>
#include <error.h>
#include <argz.h>
+#include <argp.h>
+#include <fnmatch.h>
#include <hurd/fsys.h>
@@ -34,7 +36,7 @@
extern error_t fsys_set_readonly (fsys_t fsys, int readonly);
extern error_t fsys_get_readonly (fsys_t fsys, int *readonly);
-extern error_t fsys_remount (fsys_t fsys);
+extern error_t fsys_update (fsys_t fsys);
extern file_t file_name_lookup_carefully (const char *file,
int flags, mode_t mode);
@@ -66,7 +68,7 @@ fstab_free (struct fstab *fstab)
/* Return a new fstypes structure in TYPES. SEARCH_FMTS is copied. */
error_t
-fstypes_create (char *search_fmts, size_t search_fmts_len,
+fstypes_create (const char *search_fmts, size_t search_fmts_len,
struct fstypes **types)
{
struct fstypes *new = malloc (sizeof (struct fstypes));
@@ -94,11 +96,12 @@ fstypes_create (char *search_fmts, size_t search_fmts_len,
one is found, it is added to TYPES, otherwise an new entry is created
with a NULL PROGRAM field. */
error_t
-fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
+fstypes_get (struct fstypes *types, const char *name, struct fstype **fstype)
{
char *fmts, *fmt;
size_t fmts_len;
struct fstype *type;
+ char *program = 0;
for (type = types->entries; type; type = type->next)
if (strcasecmp (type->name, name) == 0)
@@ -108,14 +111,6 @@ fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
}
/* No existing entry, make a new one. */
- type = malloc (sizeof (struct fstype));
- if (! type)
- return ENOMEM;
-
- type->name = strdup (name);
- type->program = 0;
- type->next = types->entries;
- types->entries = type;
fmts = types->program_search_fmts;
fmts_len = types->program_search_fmts_len;
@@ -123,7 +118,6 @@ fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
{
int fd;
- char *program;
asprintf (&program, fmt, name);
fd = open (program, O_EXEC);
@@ -144,23 +138,109 @@ fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
close (fd);
if (rv < 0)
- return errno;
-
- if (stat.st_mode & S_IXUSR)
- /* Yup execute bit is set. This must a program... */
{
- type->program = program;
- break;
+ free (program);
+ return errno;
}
+
+ if (stat.st_mode & S_IXUSR)
+ /* Yup execute bit is set. This must be a program... */
+ break;
+
+ free (program);
}
+
+ program = 0;
+ }
+
+ type = malloc (sizeof (struct fstype));
+ if (! type)
+ {
+ free (program);
+ return ENOMEM;
}
+ type->name = strdup (name);
+ if (type->name == 0)
+ {
+ free (type);
+ return ENOMEM;
+ }
+ type->program = program;
+ type->next = types->entries;
+ types->entries = type;
+
+ *fstype = type;
+
return 0;
}
+
+#if 0
+/* XXX nice idea, but not that useful since scanf's %s always eats all
+ non-ws, and it seems a bit overkill to convert it to a .+ regexp match */
+error_t
+fstypes_find_program (struct fstypes *types, const char *program,
+ struct fstype **fstype)
+{
+ char *fmts, *fmt;
+ size_t fmts_len;
+ struct fstype *type;
+ char *typename;
+
+ /* First see if a known type matches this program. */
+ for (type = types->entries; type; type = type->next)
+ if (type->program && !strcmp (type->program, program))
+ {
+ *fstype = type;
+ return 0;
+ }
+
+ /* No existing entry, see if we can make a new one. */
+
+ typename = alloca (strlen (program) + 1);
+
+ fmts = types->program_search_fmts;
+ fmts_len = types->program_search_fmts_len;
+ for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
+ /* XXX this only works for trailing %s */
+ if (sscanf (program, fmt, typename) == 1)
+ {
+ /* This format matches the program and yields the type name.
+ Create a new entry for this type. */
+
+ type = malloc (sizeof (struct fstype));
+ if (! type)
+ return ENOMEM;
+ type->name = strdup (typename);
+ if (type->name == 0)
+ {
+ free (type);
+ return ENOMEM;
+ }
+ type->program = strdup (program);
+ if (type->program == 0)
+ {
+ free (type->name);
+ free (type);
+ return ENOMEM;
+ }
+ type->next = types->entries;
+ types->entries = type;
+
+ *fstype = type;
+ return 0;
+ }
+
+ /* We could find no program search format that could have yielded this
+ program name. */
+ *fstype = 0;
+ return 0;
+}
+#endif
/* Copy MNTENT into FS, copying component strings as well. */
error_t
-fs_set_mntent (struct fs *fs, struct mntent *mntent)
+fs_set_mntent (struct fs *fs, const struct mntent *mntent)
{
char *end;
size_t needed = 0;
@@ -180,7 +260,8 @@ fs_set_mntent (struct fs *fs, struct mntent *mntent)
if (! fs->storage)
return ENOMEM;
- if (strcmp (fs->mntent.mnt_dir, mntent->mnt_dir) != 0)
+ if (!fs->mntent.mnt_dir || !mntent->mnt_dir
+ || strcmp (fs->mntent.mnt_dir, mntent->mnt_dir) != 0)
{
fs->mounted = fs->readonly = -1;
if (fs->fsys != MACH_PORT_NULL)
@@ -194,20 +275,28 @@ fs_set_mntent (struct fs *fs, struct mntent *mntent)
/* Copy each mntent field from MNTENT into FS's version. */
end = fs->storage;
#define STORE(field) \
- fs->mntent.field = end; end = stpcpy (end, mntent->field) + 1
+ if (mntent->field) \
+ { \
+ fs->mntent.field = end; \
+ end = stpcpy (end, mntent->field) + 1; \
+ } \
+ else \
+ fs->mntent.field = 0;
STORE (mnt_fsname);
STORE (mnt_dir);
STORE (mnt_type);
STORE (mnt_opts);
#undef STORE
- if (fs->type && strcasecmp (fs->type->name, mntent->mnt_type) != 0)
+ if (fs->type
+ && (!mntent->mnt_type
+ || strcasecmp (fs->type->name, mntent->mnt_type) != 0))
fs->type = 0; /* Type is different. */
return 0;
}
-/* Returns an fstype for FS in TYPE, trying to fillin FS's type field if
+/* Returns an fstype for FS in TYPE, trying to fill in FS's type field if
necessary. */
error_t
fs_type (struct fs *fs, struct fstype **type)
@@ -257,7 +346,7 @@ _fs_check_mounted (struct fs *fs)
the mntent, but oh well, nothing we can do about that.] */
{
err = file_get_translator_cntl (mount_point, &fs->fsys);
- if (err == EINVAL || err == EOPNOTSUPP)
+ if (err == EINVAL || err == EOPNOTSUPP || err == ENXIO)
/* Either the mount point doesn't exist, or wasn't mounted. */
{
fs->fsys = MACH_PORT_NULL;
@@ -318,10 +407,12 @@ fs_readonly (struct fs *fs, int *readonly)
err = fs_fsys (fs, &fsys);
if (! err)
- if (fsys == MACH_PORT_NULL)
- fs->readonly = 1;
- else
- err = fsys_get_readonly (fsys, &fs->readonly);
+ {
+ if (fsys == MACH_PORT_NULL)
+ fs->readonly = 1;
+ else
+ err = fsys_get_readonly (fsys, &fs->readonly);
+ }
}
if (!err && readonly)
@@ -354,7 +445,7 @@ fs_set_readonly (struct fs *fs, int readonly)
return err;
}
-/* If FS is currently mounted tell lit to remount the device. XXX If FS is
+/* If FS is currently mounted tell it to remount the device. XXX If FS is
not mounted at all, then nothing is done. */
error_t
fs_remount (struct fs *fs)
@@ -362,14 +453,14 @@ fs_remount (struct fs *fs)
fsys_t fsys;
error_t err = fs_fsys (fs, &fsys);
if (!err && fsys != MACH_PORT_NULL) /* XXX What to do if not mounted? */
- err = fsys_remount (fsys);
+ err = fsys_update (fsys);
return err;
}
/* Returns the FS entry in FSTAB with the device field NAME (there can only
be one such entry). */
inline struct fs *
-fstab_find_device (struct fstab *fstab, char *name)
+fstab_find_device (const struct fstab *fstab, const char *name)
{
struct fs *fs;
for (fs = fstab->entries; fs; fs = fs->next)
@@ -381,9 +472,20 @@ fstab_find_device (struct fstab *fstab, char *name)
/* Returns the FS entry in FSTAB with the mount point NAME (there can only
be one such entry). */
inline struct fs *
-fstab_find_mount (struct fstab *fstab, char *name)
+fstab_find_mount (const struct fstab *fstab, const char *name)
{
struct fs *fs;
+
+ /* Don't count "none" or "-" as matching any other mount point.
+ It is canonical to use "none" for swap partitions, and multiple
+ such do not in fact conflict with each other. Likewise, the
+ special device name "ignore" is used for things that should not
+ be processed automatically. */
+ if (!strcmp (name, "-")
+ || !strcmp (name, "none")
+ || !strcmp (name, "ignore"))
+ return 0;
+
for (fs = fstab->entries; fs; fs = fs->next)
if (strcmp (fs->mntent.mnt_dir, name) == 0)
return fs;
@@ -393,9 +495,31 @@ fstab_find_mount (struct fstab *fstab, char *name)
/* Returns the FS entry in FSTAB with the device or mount point NAME (there
can only be one such entry). */
inline struct fs *
-fstab_find (struct fstab *fstab, char *name)
+fstab_find (const struct fstab *fstab, const char *name)
{
- return fstab_find_device (fstab, name) ?: fstab_find_mount (fstab, name);
+ struct fs *ret;
+ const char *real_name;
+
+ ret = fstab_find_device (fstab, name);
+ if (ret)
+ return ret;
+
+ ret = fstab_find_mount (fstab, name);
+ if (ret)
+ return ret;
+
+ real_name = realpath (name, NULL);
+
+ ret = fstab_find_device (fstab, real_name);
+ if (ret) {
+ free (real_name);
+ return ret;
+ }
+
+ ret = fstab_find_mount (fstab, real_name);
+ free (real_name);
+
+ return ret;
}
/* Cons FS onto the beginning of FSTAB's entry list. */
@@ -426,7 +550,7 @@ fs_free (struct fs *fs)
conflict (in either the device or mount point). If RESULT is non-zero, the
new entry is returne in it. */
error_t
-fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
+fstab_add_mntent (struct fstab *const fstab, const struct mntent *mntent,
struct fs **result)
{
int new = 0; /* True if we didn't overwrite an old entry. */
@@ -441,7 +565,7 @@ fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
fs = mounted_fs;
mounted_fs = 0;
}
-
+
if (! fs)
/* No old entry, make a new one. */
{
@@ -462,15 +586,17 @@ fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
err = fs_set_mntent (fs, mntent);
if (new)
- if (! err)
- _fstab_add (fstab, fs);
- else if (fs)
- free (fs);
+ {
+ if (! err)
+ _fstab_add (fstab, fs);
+ else if (fs)
+ free (fs);
+ }
- if (!err && mounted_fs)
+ if (!err && mounted_fs && mounted_fs != fs)
/* Get rid of the conflicting entry MOUNTED_FS. */
fs_free (mounted_fs);
-
+
if (!err && result)
*result = fs;
@@ -481,7 +607,7 @@ fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
DST. If DST & SRC have different TYPES fields, EINVAL is returned. If
COPY is non-zero, the copy is returned in it. */
error_t
-fstab_add_fs (struct fstab *dst, struct fs *fs, struct fs **copy)
+fstab_add_fs (struct fstab *dst, const struct fs *fs, struct fs **copy)
{
error_t err;
struct fs *new;
@@ -525,7 +651,7 @@ fstab_merge (struct fstab *dst, struct fstab *src)
if (old_fs)
fs_free (old_fs);
}
-
+
/* Now that we know there are no conflicts, steal all SRC's entries and
cons them onto DST. */
for (fs = src->entries; fs; fs = fs->next)
@@ -540,7 +666,7 @@ fstab_merge (struct fstab *dst, struct fstab *src)
/* Reads fstab-format entries into FSTAB from the file NAME. Any entries
duplicating one already in FS_LIST supersede the existing entry. */
error_t
-fstab_read (struct fstab *fstab, char *name)
+fstab_read (struct fstab *fstab, const char *name)
{
error_t err;
/* Used to hold entries from the file, before merging with FSTAB at the
@@ -583,7 +709,7 @@ fstab_read (struct fstab *fstab, char *name)
/* Return the next pass number that applies to any filesystem in FSTAB that
is greater than PASS, or -1 if there isn't any. */
-int fstab_next_pass (struct fstab *fstab, int pass)
+int fstab_next_pass (const struct fstab *fstab, int pass)
{
int next_pass = -1;
struct fs *fs;
@@ -597,3 +723,262 @@ int fstab_next_pass (struct fstab *fstab, int pass)
}
return next_pass;
}
+
+
+static const struct argp_option options[] =
+{
+ {"all", 'a', 0, 0, "Do all filesystems in " _PATH_MNTTAB},
+ {0, 'A', 0, OPTION_ALIAS },
+ {"fstab", 'F', "FILE", 0, "File to use instead of " _PATH_MNTTAB},
+ {"fstype", 't', "TYPE", 0, "Do only filesystems of given type(s)"},
+ {"exclude-root",'R',0, 0,
+ "Exclude root (/) filesystem from " _PATH_MNTTAB " list"},
+ {"exclude", 'X', "PATTERN", 0, "Exclude directories matching PATTERN"},
+
+ {"search-fmts",'S', "FMTS", 0,
+ "`:' separated list of formats to use for finding"
+ " filesystem-specific programs"},
+
+ {0, 0}
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ error_t err;
+ struct fstab_argp_params *params = state->input;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize our parsing state. */
+ if (! params)
+ return EINVAL; /* Need at least a way to return a result. */
+ bzero (params, sizeof *params);
+ break;
+
+ case 'A':
+ case 'a':
+ params->do_all = 1;
+ break;
+
+ case 'F':
+ params->fstab_path = arg;
+ break;
+
+ case 'S':
+ argz_create_sep (arg, ':',
+ &params->program_search_fmts,
+ &params->program_search_fmts_len);
+ break;
+
+ case 'R':
+ arg = "/";
+ /* FALLTHROUGH */
+ case 'X':
+ err = argz_add (&params->exclude, &params->exclude_len, arg);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+ case 't':
+ err = argz_add_sep (&params->types, &params->types_len, arg, ',');
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case ARGP_KEY_ARG:
+ err = argz_add (&params->names, &params->names_len, arg);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case ARGP_KEY_END:
+ /* Check for bogus combinations of arguments. */
+ if (params->names)
+ {
+ if (params->do_all)
+ argp_error (state, "filesystem arguments not allowed with --all");
+ if (params->exclude)
+ argp_error (state,
+ "--exclude not allowed with filesystem arguments");
+ if (params->types)
+ argp_error (state,
+ "--fstype not allowed with filesystem arguments");
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+const struct argp fstab_argp = {options, parse_opt, 0, 0};
+
+struct fstab *
+fstab_argp_create (struct fstab_argp_params *params,
+ const char *default_search_fmts,
+ size_t default_search_fmts_len)
+{
+ error_t err;
+ struct fstab *fstab, *check;
+ struct fstypes *types;
+
+ if (params->fstab_path == 0)
+ params->fstab_path = _PATH_MNTTAB;
+ if (params->program_search_fmts == 0)
+ {
+ params->program_search_fmts = (char *) default_search_fmts;
+ params->program_search_fmts_len = default_search_fmts_len;
+ }
+
+ err = fstypes_create (params->program_search_fmts,
+ params->program_search_fmts_len,
+ &types);
+ if (err)
+ error (102, err, "fstypes_create");
+
+ err = fstab_create (types, &fstab);
+ if (err)
+ error (101, err, "fstab_create");
+
+ err = fstab_read (fstab, params->fstab_path);
+ if (err)
+ error (103, err, "%s", params->fstab_path);
+
+ if (params->names)
+ {
+ /* Process specified filesystems; also look at /var/run/mtab. */
+ const char *name;
+
+ err = fstab_read (fstab, _PATH_MOUNTED);
+ if (err && err != ENOENT)
+ error (104, err, "%s", _PATH_MOUNTED);
+
+ err = fstab_create (types, &check);
+ if (err)
+ error (105, err, "fstab_create");
+
+ for (name = params->names; name; name = argz_next (params->names,
+ params->names_len,
+ name))
+ {
+ struct fs *fs = fstab_find (fstab, name);
+ if (! fs)
+ error (106, 0, "%s: Unknown device or filesystem", name);
+ fstab_add_fs (check, fs, 0);
+ }
+
+ /* fstab_free (fstab); XXX */
+ }
+ else
+ {
+ /* Process everything in /etc/fstab. */
+
+ if (params->exclude == 0 && params->types == 0)
+ check = fstab;
+ else
+ {
+ struct fs *fs;
+ const char *tn;
+ unsigned int nonexclude_types;
+
+ err = fstab_create (types, &check);
+ if (err)
+ error (105, err, "fstab_create");
+
+ /* For each excluded type (i.e. `-t notype'), clobber the
+ fstype entry's program with an empty string to mark it. */
+ nonexclude_types = 0;
+ for (tn = params->types; tn;
+ tn = argz_next (params->types, params->types_len, tn))
+ {
+ if (!strncasecmp (tn, "no", 2))
+ {
+ struct fstype *type;
+ err = fstypes_get (types, &tn[2], &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ free (type->program);
+ type->program = strdup ("");
+ }
+ else
+ ++nonexclude_types;
+ }
+
+ if (nonexclude_types != 0)
+ {
+ const char *tn;
+ struct fstypes *wanttypes;
+
+ /* We will copy the types we want to include into a fresh
+ list in WANTTYPES. Since we specify no search formats,
+ `fstypes_get' applied to WANTTYPES can only create
+ elements with a null `program' field. */
+ err = fstypes_create (0, 0, &wanttypes);
+ if (err)
+ error (102, err, "fstypes_create");
+
+ for (tn = params->types; tn;
+ tn = argz_next (params->types, params->types_len, tn))
+ if (strncasecmp (tn, "no", 2))
+ {
+ struct fstype *type;
+ err = fstypes_get (types, tn, &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ if (type->program == 0)
+ error (0, 0,
+ "requested filesystem type `%s' unknown", tn);
+ else
+ {
+ struct fstype *newtype = malloc (sizeof *newtype);
+ newtype->name = strdup (type->name);
+ newtype->program = strdup (type->program);
+ newtype->next = wanttypes->entries;
+ wanttypes->entries = newtype;
+ }
+ }
+
+ /* fstypes_free (types); */
+ types = wanttypes;
+ }
+
+ for (fs = fstab->entries; fs; fs = fs->next)
+ {
+ const char *ptn;
+ struct fstype *type;
+
+ err = fs_type (fs, &type);
+ if (err || nonexclude_types)
+ {
+ err = fstypes_get (types, fs->mntent.mnt_type, &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ if (params->types != 0)
+ continue;
+ }
+ if (nonexclude_types && type->program == 0)
+ continue; /* Freshly created, was not in WANTTYPES. */
+ if (type->program != 0 && type->program[0] == '\0')
+ continue; /* This type is marked as excluded. */
+
+ for (ptn = params->exclude; ptn;
+ ptn = argz_next (params->exclude, params->exclude_len, ptn))
+ if (fnmatch (ptn, fs->mntent.mnt_dir, 0) == 0)
+ break;
+ if (ptn) /* An exclude pattern matched. */
+ continue;
+
+ err = fstab_add_fs (check, fs, 0);
+ if (err)
+ error (107, err, "fstab_add_fs");
+ }
+
+ /* fstab_free (fstab); XXX */
+ }
+ }
+
+ return check;
+}
diff --git a/sutils/fstab.h b/sutils/fstab.h
index b8616185..ddd1656c 100644
--- a/sutils/fstab.h
+++ b/sutils/fstab.h
@@ -1,6 +1,6 @@
/* Fstab filesystem frobbing
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -28,7 +28,7 @@
struct fs
{
- struct fstab *fstab; /* Containg fstab. */
+ struct fstab *fstab; /* Containing fstab. */
struct mntent mntent; /* Mount entry from fstab file. */
char *storage; /* Storage for strings in MNTENT. */
struct fstype *type; /* Only set if fs_type called. */
@@ -70,20 +70,21 @@ error_t fstab_create (struct fstypes *types, struct fstab **fstab);
void fstab_free (struct fstab *fstab);
/* Return a new fstypes structure in TYPES. SEARCH_FMTS is copied. */
-error_t fstypes_create (char *search_fmts, size_t search_fmts_len,
+error_t fstypes_create (const char *search_fmts, size_t search_fmts_len,
struct fstypes **types);
/* Return an fstype entry in TYPES called NAME, in FSTYPE. If there is no
- existing entry, an attempt to find a fsck program with the given type,
- using the alternatives in the FSCK_SEARCH_FMTS field in TYPES. If
- one is found, it is added to TYPES, otherwise an new entry is created
- with a NULL PROGRAM field. */
-error_t fstypes_get (struct fstypes *types, char *name, struct fstype **fstype);
+ existing entry, an attempt to find a program with the given type,
+ using the alternatives in the PROGRAM_SEARCH_FMTS field in TYPES. If
+ one is found, it is added to TYPES, otherwise a new entry is created
+ with a null PROGRAM field. */
+error_t fstypes_get (struct fstypes *types,
+ const char *name, struct fstype **fstype);
/* Copy MNTENT into FS, copying component strings as well. */
-error_t fs_set_mntent (struct fs *fs, struct mntent *mntent);
+error_t fs_set_mntent (struct fs *fs, const struct mntent *mntent);
-/* Returns an fstype for FS in TYPE, trying to fillin FS's type field if
+/* Returns an fstype for FS in TYPE, trying to fill in FS's type field if
necessary. */
error_t fs_type (struct fs *fs, struct fstype **type);
@@ -106,7 +107,7 @@ error_t fs_readonly (struct fs *fs, int *readonly);
is not mounted at all, then nothing is done. */
error_t fs_set_readonly (struct fs *fs, int readonly);
-/* If FS is currently mounted tell lit to remount the device. XXX If FS is
+/* If FS is currently mounted tell it to remount the device. XXX If FS is
not mounted at all, then nothing is done. */
error_t fs_remount (struct fs *fs);
@@ -115,26 +116,27 @@ void fs_free (struct fs *fs);
/* Returns the FS entry in FSTAB with the device field NAME (there can only
be one such entry). */
-struct fs *fstab_find_device (struct fstab *fstab, char *name);
+struct fs *fstab_find_device (const struct fstab *fstab, const char *name);
/* Returns the FS entry in FSTAB with the mount point NAME (there can only
be one such entry). */
-struct fs *fstab_find_mount (struct fstab *fstab, char *name);
+struct fs *fstab_find_mount (const struct fstab *fstab, const char *name);
/* Returns the FS entry in FSTAB with the device or mount point NAME (there
can only be one such entry). */
-struct fs *fstab_find (struct fstab *fstab, char *name);
+struct fs *fstab_find (const struct fstab *fstab, const char *name);
/* Add an entry for MNTENT to FSTAB, removing any existing entries that
conflict (in either the device or mount point). If RESULT is non-zero, the
- new entry is returne in it. */
-error_t fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
+ new entry is returned in it. */
+error_t fstab_add_mntent (struct fstab *fstab, const struct mntent *mntent,
struct fs **result);
/* Copy the entry FS (which should belong to another fstab than DST) into
DST. If DST & SRC have different TYPES fields, EINVAL is returned. If
COPY is non-zero, the copy is returned in it. */
-error_t fstab_add_fs (struct fstab *dst, struct fs *fs, struct fs **copy);
+error_t fstab_add_fs (struct fstab *dst, const struct fs *fs,
+ struct fs **copy);
/* Merge SRC into DST, as if by calling fstab_add_fs on DST with every
entry in SRC, and then deallocating SRC. If DST & SRC have different
@@ -143,10 +145,34 @@ error_t fstab_merge (struct fstab *dst, struct fstab *src);
/* Reads fstab-format entries into FSTAB from the file NAME. Any entries
duplicating one already in FS_LIST supersede the existing entry. */
-error_t fstab_read (struct fstab *fstab, char *name);
+error_t fstab_read (struct fstab *fstab, const char *name);
/* Return the next pass number that applies to any filesystem in FSTAB that
is greater than PASS, or -1 if there isn't any. */
-int fstab_next_pass (struct fstab *fstab, int pass);
+int fstab_next_pass (const struct fstab *fstab, int pass);
+
+
+struct argp;
+extern const struct argp fstab_argp;
+struct fstab_argp_params
+{
+ char *fstab_path;
+ char *program_search_fmts;
+ size_t program_search_fmts_len;
+
+ int do_all;
+ char *types;
+ size_t types_len;
+ char *exclude;
+ size_t exclude_len;
+
+ char *names;
+ size_t names_len;
+};
+
+struct fstab *fstab_argp_create (struct fstab_argp_params *params,
+ const char *default_search_fmts,
+ size_t default_search_fmts_len);
+
#endif /* __FSTAB_H__ */
diff --git a/sutils/halt.c b/sutils/halt.c
index 2d9c1a18..08f754c4 100644
--- a/sutils/halt.c
+++ b/sutils/halt.c
@@ -1,5 +1,5 @@
/* Halt the system
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1996, 1997, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -22,11 +22,19 @@
#include <sys/reboot.h>
#include <unistd.h>
#include <stdio.h>
+#include <argp.h>
+#include <error.h>
+#include <hurd.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (halt);
int
-main (void)
+main (int argc, char *argv[])
{
+ struct argp argp = {0, 0, 0, "Halt the system"};
+ argp_parse (&argp, argc, argv, 0, 0, 0);
reboot (RB_HALT);
- perror ("reboot");
+ error (1, errno, "reboot");
return 1;
}
diff --git a/sutils/losetup.sh b/sutils/losetup.sh
new file mode 100644
index 00000000..85734571
--- /dev/null
+++ b/sutils/losetup.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# This script is roughly compatible with the Linux `losetup' utility.
+# The Hurd's `storeio' translator provides the equivalent functionality
+# (and a whole lot more), and of course works on any old file you want
+# to translate, not just magical "/dev/loopN" device files.
+#
+
+PATH=/bin
+
+usage() {
+ echo >&2 ...
+ exit 1
+}
+
+offset=0
+while [ $# -gt 0 ]; do
+ case "$arg" in
+ -d)
+ [ $# -eq 2 ] || usage
+ exec settrans -g -- "$2" /hurd/null
+ ;;
+ -e)
+ echo >&2 "$0: encryption not supported"
+ exit 3
+ ;;
+ -o)
+ [ $# -gt 1 ] || usage
+ offset="$1"
+ shift
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+[ $# -eq 2 ] || usage
+device="$1"
+file="$2"
+
+# If the device name is "/dev/loopN", then create it if necessary. (?)
+create=
+case "$device" in
+'/dev/loop[0-9]*') ;; # smarty pants
+/dev/loop[0-9]*) create=--create ;;
+esac
+
+type='-Tfile '
+if [ "$offset" != 0 ]; then
+ blksz=`storeinfo -B -- "$file"`
+ if [ $[ $offset % $blksz ] -ne 0 ]; then
+ echo >&2 "$0: offset $offset is not a multiple of device block size $blksz"
+ exit 1
+ fi
+ type="-Tremap $[ $offset / $blksz ]+:file:"
+fi
+
+exec settrans $create -gap -- "${device}" /hurd/storeio ${type}"${file}"
diff --git a/sutils/reboot.c b/sutils/reboot.c
index 7844ba06..54b9b99c 100644
--- a/sutils/reboot.c
+++ b/sutils/reboot.c
@@ -1,5 +1,5 @@
/* Reboot the system
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1996, 1997, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -22,15 +22,19 @@
#include <sys/reboot.h>
#include <unistd.h>
#include <stdio.h>
+#include <argp.h>
+#include <error.h>
+#include <hurd.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (reboot);
int
-main (void)
+main (int argc, char *argv[])
{
+ struct argp argp = {0, 0, 0, "Reboot the system"};
+ argp_parse (&argp, argc, argv, 0, 0, 0);
reboot (0);
- perror ("reboot");
+ error (1, errno, "reboot");
return 1;
}
-
-
-
-
diff --git a/sutils/swapoff.c b/sutils/swapoff.c
new file mode 100644
index 00000000..42521257
--- /dev/null
+++ b/sutils/swapoff.c
@@ -0,0 +1,2 @@
+#define SWAPOFF
+#include "swapon.c"
diff --git a/sutils/swapon.c b/sutils/swapon.c
new file mode 100644
index 00000000..c0c773bd
--- /dev/null
+++ b/sutils/swapon.c
@@ -0,0 +1,536 @@
+/* Add/remove paging devices
+
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2007
+ Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <argp.h>
+#include <error.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <hurd/store.h>
+#include <hurd/paths.h>
+#include <version.h>
+#include <mntent.h>
+#include "default_pager_U.h"
+
+#ifdef SWAPOFF
+const char *argp_program_version = STANDARD_HURD_VERSION (swapoff);
+#else
+const char *argp_program_version = STANDARD_HURD_VERSION (swapon);
+#endif
+
+static int ignore_signature, require_signature, quiet;
+
+static struct argp_option options[] =
+{
+ {"standard", 'a', 0, 0,
+ "Use all devices marked as `swap' in " _PATH_MNTTAB},
+ {"no-signature",'n', 0, 0,
+ "Do not check for a Linux swap signature page"},
+ {"require-signature", 's', 0, 0,
+ "Require a Linux swap signature page"},
+ {"silent", 'q', 0, 0, "Print only diagnostic messages"},
+ {"quiet", 'q', 0, OPTION_ALIAS | OPTION_HIDDEN },
+ {0, 0}
+};
+static char *args_doc = "DEVICE...";
+
+static char *doc =
+#ifdef SWAPOFF
+ "Stop paging on DEVICE..."
+ "\vUnless overridden, a swap space signature is not considered when deciding"
+ " whether to remove a paging device or not."
+#else
+ "Start paging onto DEVICE..."
+ "\vUnless overridden, only devices with a valid (Linux) swap space signature"
+ " are considered when deciding whether to add a paging device or not."
+#endif
+;
+
+#define verbose(fmt, arg...) \
+ if (quiet_now) ((void)0); else error (0, 0, fmt ,##arg)
+#define inform_2_0(fmt, arg...) \
+ verbose ("%s: Linux 2.0 swap signature, " fmt, name ,##arg)
+#define inform_2_2(fmt, arg...) \
+ verbose ("%s: Linux 2.2 swap signature v1, %zuk swap-space" fmt, \
+ name, freepages * (LINUX_PAGE_SIZE / 1024) ,##arg)
+
+
+/* Examine the store in *STOREP to see if it has a Linux-compatible
+ swap signature page as created by the Linux `mkswap' utility. If
+ we find such a signature, it indicates some subset of the store
+ that should actually be used for paging; return zero after
+ consuming *STOREP and replacing it by using store_remap to get just
+ the indicated subset (unless NO_REMAP is nonzero). If we get an
+ error reading the store, or find a signature but have some problem
+ with it, return some error code. If the store has no signature at
+ all, and if --require-signature was given, then that is an error.
+ This function prints diagnostics for all those errors. Otherwise
+ (the store has no signature) we return EFTYPE and print nothing. */
+
+static error_t
+check_signature (const char *name, struct store **storep, int no_remap,
+ int quiet_now)
+{
+ struct store *const store = *storep;
+
+#define LINUX_PAGE_SIZE 4096 /* size of pages in Linux swap partitions */
+#define LINUX_PAGE_SHIFT 12
+
+ /* RUNS points to latest run (highest value of start). Each time we
+ remove a bad page from the set, we either adjust the latest run or add
+ a new one and point RUNS at it. */
+
+ struct run
+ {
+ struct run *next;
+ size_t start, limit; /* in units of LINUX_PAGE_SIZE */
+ };
+
+ size_t freepages = store->size / LINUX_PAGE_SIZE;
+ struct run first_run = { NULL, 0, freepages }, *runs = &first_run;
+ size_t nruns = 1;
+ /* This is always called with increasing page numbers. */
+#define BAD_PAGE(pageno) \
+ ({ \
+ size_t page = (pageno); \
+ if (page == runs->start) \
+ runs->start = page + 1; \
+ else \
+ { \
+ runs->next = alloca (sizeof *runs); \
+ runs->next->start = page + 1; \
+ runs->next->limit = runs->limit; \
+ runs->limit = page; \
+ ++nruns; \
+ } \
+ })
+
+ /* Read the first page, which contains the signature. */
+ void *buf = 0;
+ size_t len = 0;
+ error_t err = store_read (store, 0, LINUX_PAGE_SIZE, &buf, &len);
+ if (err)
+ {
+ error (0, err, "%s: cannot read Linux swap signature page", name);
+ return err;
+ }
+ if (len < LINUX_PAGE_SIZE)
+ {
+ error (0, 0, "%s: short read %zu reading Linux swap signature page",
+ name, len);
+ return EINVAL;
+ }
+
+ quiet_now |= quiet;
+
+ /* Check for Linux 2.0 format. */
+ if (!memcmp ("SWAP-SPACE", buf + LINUX_PAGE_SIZE-10, 10))
+ {
+ /* The partition's first page has a Linux swap signature.
+ This means the beginning of the page contains a bitmap
+ of good pages, and all others are bad. */
+ size_t i, bad, max;
+ int waste;
+
+ /* The first page, and the pages corresponding to the bits
+ occupied by the signature in the final 10 bytes of the page,
+ are always unavailable ("bad"). */
+ *(uint32_t *) buf &= ~(u_int32_t) 1;
+ memset (buf + LINUX_PAGE_SIZE-10, 0, 10);
+
+ max = LINUX_PAGE_SIZE / sizeof (uint32_t);
+ if (max > (store->size + 31) / 32)
+ max = (store->size + 31) / 32;
+
+ /* Search the page for zero bits, which indicate unusable pages. */
+ bad = 0;
+ for (i = 0; i < max; ++i)
+ {
+ size_t p = i*32;
+ uint32_t bm = ~((uint32_t *) buf)[i];
+ while (bm != 0) /* inverted so unusable pages are one bits */
+ {
+ /* Find the first bit set in this word. */
+ int bit = ffs (bm);
+ bm >>= bit; /* Next time look at the rest of the word. */
+ p += bit - 1; /* Corresponding page. */
+ if (p >= runs->limit)
+ break;
+ ++bad;
+ BAD_PAGE (p);
+ }
+ }
+ freepages -= bad;
+
+ --bad; /* Don't complain about first page. */
+ waste = (store->size >> LINUX_PAGE_SHIFT) - (8 * (LINUX_PAGE_SIZE-10));
+
+ if (waste > 0)
+ {
+ /* The wasted pages were already marked "bad". */
+ bad -= waste;
+ if (bad > 0)
+ inform_2_0 ("%zdk swap-space (%zdk bad, %dk wasted at end)",
+ freepages * (LINUX_PAGE_SIZE / 1024),
+ bad * (LINUX_PAGE_SIZE / 1024),
+ waste * (LINUX_PAGE_SIZE / 1024));
+ else
+ inform_2_0 ("%zdk swap-space (%dk wasted at end)",
+ freepages * (LINUX_PAGE_SIZE / 1024),
+ waste * (LINUX_PAGE_SIZE / 1024));
+ }
+ else if (bad > 0)
+ inform_2_0 ("%zdk swap-space (excludes %zdk marked bad)",
+ freepages * (LINUX_PAGE_SIZE / 1024),
+ bad * (LINUX_PAGE_SIZE / 1024));
+ else
+ inform_2_0 ("%zdk swap-space", freepages * (LINUX_PAGE_SIZE / 1024));
+ }
+ /* Check for Linux 2.2 format. */
+ else if (!memcmp ("SWAPSPACE2", buf + LINUX_PAGE_SIZE-10, 10))
+ {
+ struct
+ {
+ u_int8_t bootbits[1024];
+ u_int32_t version;
+ u_int32_t last_page;
+ u_int32_t nr_badpages;
+ u_int32_t padding[125];
+ u_int32_t badpages[1];
+ } *hdr = buf;
+
+ ++first_run.start; /* first page unusable */
+ --freepages;
+
+ switch (hdr->version)
+ {
+ default:
+ error (0, 0,
+ "%s: Linux 2.2 swap signature with unknown version %u",
+ name, hdr->version);
+ munmap (buf, len);
+ if (require_signature)
+ {
+ error (0, 0, "%s: will not use without valid signature page",
+ name);
+ return EINVAL;
+ }
+ error (0, 0, "WARNING: ignoring unrecognized signature page");
+ return EFTYPE;
+
+ case 1:
+ {
+ unsigned int waste, i;
+ if (hdr->last_page >= first_run.limit)
+ {
+ error (0, 0,
+ "%s: signature says %uk, partition has only %uk!",
+ name,
+ hdr->last_page * (LINUX_PAGE_SIZE / 1024),
+ (unsigned int) (store->size / 1024));
+ waste = 0;
+ }
+ else
+ {
+ waste = first_run.limit + 1 - hdr->last_page;
+ freepages = first_run.limit - first_run.start;
+ first_run.limit = hdr->last_page + 1;
+ }
+ for (i = 0; i < hdr->nr_badpages; ++i)
+ {
+ BAD_PAGE (hdr->badpages[i]);
+ --freepages;
+ }
+
+ {
+ size_t badk = hdr->nr_badpages * (LINUX_PAGE_SIZE / 1024);
+ size_t wastek = waste * (LINUX_PAGE_SIZE / 1024);
+ if (badk && wastek)
+ inform_2_2 ("\
+ (excludes %zuk marked bad and %zuk at end of partition)",
+ badk, wastek);
+ else if (badk)
+ inform_2_2 (" (excludes %zuk marked bad)", badk);
+ else if (wastek)
+ inform_2_2 (" (excludes %zuk at end of partition)", wastek);
+ else
+ inform_2_2 ("");
+ }
+ }
+ }
+ }
+ /* There does not appear to be any signature page here. */
+ else if (require_signature)
+ {
+ error (0, 0, "%s: will not use without Linux swap signature", name);
+ return EINVAL;
+ }
+ else
+ /* We use this error code to tell our caller that we found nothing. */
+ return EFTYPE;
+
+ /* Now that we have collected the runs of LINUX_PAGE_SIZE we will use,
+ convert those into store_run's in the store's block size. */
+ {
+ const int scale = LINUX_PAGE_SHIFT - store->log2_block_size;
+ struct store_run store_runs[nruns];
+ size_t i = 0;
+ struct run *r = &first_run;
+ do
+ {
+ struct store_run *sr = &store_runs[i++];
+ sr->start = (store_offset_t) r->start << scale;
+ sr->length = (r->limit - r->start) << scale;
+ do
+ r = r->next;
+ while (r != 0 && r->start == r->limit); /* skip empty runs */
+ } while (r != 0);
+
+ /* Give us a new store that uses only the good pages. */
+ return store_remap (store, store_runs, i, storep);
+ }
+}
+
+
+/* Process a single argument file. */
+
+static int
+swaponoff (const char *file, int add)
+{
+ error_t err;
+ struct store *store;
+ static mach_port_t def_pager = MACH_PORT_NULL;
+ static mach_port_t dev_master = MACH_PORT_NULL;
+ static int old_protocol;
+ int quiet_now = 0;
+
+ try_again:
+ err = store_open (file, 0, 0, &store);
+ if (err)
+ {
+ error (0, err, "%s", file);
+ return err;
+ }
+
+ /* Let's see what we've got. */
+ if (old_protocol)
+ {
+ /* The default pager only lets us give a whole partition, and
+ it will read the signature page (but not insist on it). */
+ if (! (store->flags & STORE_ENFORCED))
+ {
+ error (0, 0, "%s: Can only page to the entire device", file);
+ return EINVAL;
+ }
+ /* If we want to require the signature, we can check that it is
+ actually there even though we won't be the one interpreting it. */
+ if (require_signature
+ && check_signature (file, &store, 1, quiet_now) != 0)
+ return EINVAL;
+ }
+ else if (ignore_signature)
+ verbose ("%s: %uk swap space",
+ file, (unsigned int) (store->size / 1024));
+ else
+ {
+ /* Adjust the store according to the Linux signature. */
+ err = check_signature (file, &store, 0, 0);
+ if (err == EFTYPE)
+ verbose ("%s: %uk swap space (no Linux signature page)",
+ file, (unsigned int) (store->size / 1024));
+ else if (err)
+ {
+ store_free (store);
+ return err;
+ }
+ /* Otherwise check_signature printed something out. */
+ }
+
+ if (store->class != &store_device_class)
+ {
+ error (0, 0, "%s: Can't get underlying device", file);
+ store_free (store);
+ return EINVAL;
+ }
+
+ if (def_pager == MACH_PORT_NULL)
+ {
+ mach_port_t host;
+
+ err = get_privileged_ports (&host, &dev_master);
+ if (err == EPERM)
+ {
+ /* We are not root, so try opening the /servers node. */
+ def_pager = file_name_lookup (_SERVERS_DEFPAGER, O_WRITE, 0);
+ if (def_pager == MACH_PORT_NULL)
+ {
+ error (11, errno, _SERVERS_DEFPAGER);
+ return 0;
+ }
+ }
+ else
+ {
+ if (err)
+ error (12, err, "Cannot get privileged ports");
+
+ err = vm_set_default_memory_manager (host, &def_pager);
+ mach_port_deallocate (mach_task_self (), host);
+ if (err)
+ error (13, err, "Cannot get default pager port");
+ if (def_pager == MACH_PORT_NULL)
+ error (14, 0, "No default pager (memory manager) is running!");
+ }
+ }
+
+ if (old_protocol)
+ {
+ /* The default pager does not support the new protocol.
+ We tried it in a previous call (below) and got MIG_BAD_ID. */
+ char pname[sizeof "/dev/" + strlen (store->name) + 1];
+ strcpy (stpcpy (pname, "/dev/"), store->name);
+ err = default_pager_paging_file (def_pager, dev_master, pname, add);
+ }
+ else
+ {
+ /* Try the new protocol, which will take our list of runs. */
+ recnum_t runs[store->num_runs * 2];
+ size_t i, j;
+ for (i = j = 0; i < store->num_runs; ++i)
+ {
+ runs[j++] = store->runs[i].start;
+ runs[j++] = store->runs[i].length;
+ }
+ err = default_pager_paging_storage (def_pager, store->port,
+ runs, j, store->name, add);
+ if (err == MIG_BAD_ID)
+ {
+ /* The default pager does not support the new protocol.
+ We'll do the whole thing over again, since we have
+ different requirements now. */
+ old_protocol = 1;
+ store_free (store);
+ if (! ignore_signature)
+ error (0, 0, "\
+default pager uses old protocol, does its own signature checking");
+ quiet_now = 1;
+ goto try_again;
+ }
+ }
+
+ store_free (store);
+
+ if (err)
+ error (0, err, "%s", file);
+
+ return err;
+}
+
+#undef inform_2_0
+#undef inform_2_2
+#undef verbose
+
+static int do_all;
+
+int
+main (int argc, char *argv[])
+{
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'a':
+ do_all = 1;
+ break;
+
+ case 'n':
+ ignore_signature = 1;
+ break;
+
+ case 's':
+ require_signature = 1;
+ ignore_signature = 0;
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+#ifdef SWAPOFF
+#define ONOFF 0
+#else
+#define ONOFF 1
+#endif
+ swaponoff (arg, ONOFF);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ /* See the documentation string DOC. */
+#ifdef SWAPOFF
+ ignore_signature = 1;
+ require_signature = 0;
+#else
+ ignore_signature = 0;
+ require_signature = 1;
+#endif
+
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ if (do_all)
+ {
+ struct mntent *me;
+ FILE *f;
+
+ f = setmntent (_PATH_MNTTAB, "r");
+ if (f == NULL)
+ error (1, errno, "Cannot read %s", _PATH_MNTTAB);
+ else
+ {
+ int done = 0, err = 0;
+ while ((me = getmntent (f)) != NULL)
+ if (!strcmp (me->mnt_type, MNTTYPE_SWAP))
+ {
+ done = 1;
+
+ err |= swaponoff (me->mnt_fsname, ONOFF);
+ }
+ if (done == 0)
+ error (2, 0, "No swap partitions found in %s", _PATH_MNTTAB);
+ else if (err)
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/sutils/update.c b/sutils/update.c
index 0342824f..c1f4e982 100644
--- a/sutils/update.c
+++ b/sutils/update.c
@@ -1,5 +1,5 @@
/* Periodically call sync.
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -41,10 +41,7 @@ main (int argc, char **argv)
}
if (daemon (0, 0))
- {
- perror ("daemon");
- exit (1);
- }
+ error (1, errno, "daemon");
for (;;)
{
diff --git a/tasks b/tasks
index 7223e0f4..871bde17 100644
--- a/tasks
+++ b/tasks
@@ -1,95 +1,87 @@
-GNU Hurd Task List Version 1.15. Last updated 13 July 1996.
+GNU Hurd Task List Version 1.23. Last updated 25 April 2006.
If you would like to work on one of these, please contact
-mib@gnu.ai.mit.edu. It's important that you let me know what's being
-worked on, because someone else might also be interested, and you
-should coordinate work.
+bug-hurd@gnu.org. It's important that you let us know what's being
+worked on, because someone else might also be interested, and we should
+coordinate work.
Items that we want done with more priority are marked with !!!.
+Some of these items might be outdated. If someone feels like triaging
+this list, please go ahead.
+
+These days, we tend to use the Savannah task tracker,
+<URL:http://savannah.gnu.org/task/?group=hurd>.
+
General system work
* Compile all the free programs you can find to help us fix bugs in
the system, and to submit necessary ports to the maintainers of
- those programs. A good place to start is the list in SOURCES under
- the heading `Give up'.
-
- * See how much of X compiles.
+ those programs.
* Do whatever magic is necessary for Perl to take advantage of all
the nifty Hurd features that Unix doesn't have.
-
-Mach 3.0 Work
+GNU Mach Work
-If you plan to work on the microkernel, you should be on the mailing list
-for the University of Utah's Mach4 distribution; that is the microkernel
-distribution that GNU will use. To get on the mailing list, send mail to
-mach4-users-request@schirf.cs.utah.edu. You should discuss proposed
-microkernel work there as well as with mib@gnu.ai.mit.edu.
+Please discuss proposed microkernel work with thomas@gnu.org.
-!!!
- * Mach 3.0 needs many new device drivers for popular PC devices.
- Shantanu Goel at Utah is doing work in this area; coordinate with him.
+ * Integrate stream device support so that the X server works
+ out-of-the-box.
!!!
- * A replacement for MiG that understood C .h files.
- Utah is working on a new IDL compiler; coordinate with them.
-
- * Bootstrap tools and documentation to help people set up Mach 3.0
- machines if they already have Linux; if they already have Net BSD;
- if they don't have anything. (See Utah Lites dist.)
+ * Mach serial drivers support only a small subset of the
+ available possibilities in the Posix c_cflag termios field. Fix
+ this, by adding a new device_set_status call that sets the whole
+ thing and not just the old limited possibilities.
!!!
- * Mach 3.0 needs to provide support for task virtual timers similar
- in functionality to the Unix ITIMER_PROF and ITIMER_VIRTUAL timers.
+ * A replacement for MiG that understands C .h files.
!!!
- * Mach 3.0 needs to provide a way for users to do statistical PC
- profiling similar to the Unix profil system call.
+ * Mach needs to provide support for task virtual timers similar
+ in functionality to the Unix ITIMER_PROF and ITIMER_VIRTUAL timers.
!!!
- * Mach 3.0 needs to make switches from MEMORY_OBJECT_COPY_DELAY to
+ * Mach needs to make switches from MEMORY_OBJECT_COPY_DELAY to
MEMORY_OBJECT_COPY_NONE have the effect of immediately completing any
delayed copies.
- * Mach 3.0 needs a facility to automatically send task and thread
+ * Mach needs a facility to automatically send task and thread
status on task/thread exit to a port that can only be changed by
a privileged user; this would be used to implement process
accounting.
- * Mach 3.0 needs a facility to find out what task is the parent of
+ * Mach needs a facility to find out what task is the parent of
a given task.
- * Mach 3.0 needs a facility to find out which pages of a task's
+ * Mach needs a facility to find out which pages of a task's
address space are in core to implement Unix's mincore call.
- * Mach 3.0 needs a facility to do msync.
+ * Mach needs a facility to do msync.
- * Utah Mach needs the OSF vm_remap call.
+ * GNU Mach needs the OSF Mach vm_remap call.
- * Mach 3.0 needs a replacement for MEMORY_OBJECT_COPY_CALL that
- works at least for the cases needed in ordinary files. (Write mib if
- you want to know what the problem is and some ideas about how to
- solve it.)
+ * Mach needs a replacement for MEMORY_OBJECT_COPY_CALL that
+ works at least for the cases needed in ordinary files. (Write
+ thomas if you want to know what the problem is and some ideas about
+ how to solve it.)
!!!
- * Mach 3.0 needs proxy memory objects. (mib can tell you what these
- are and why they are important.)
+ * Mach needs proxy memory objects. (thomas can tell you what
+ these are and why they are important.)
- * Mach 3.0 needs a way to do per-task resource counters that are
+ * Mach needs a way to do per-task resource counters that are
accessible to servers called by the task.
- * Mach 3.0 should keep a timestamp of the creation of each task.
-
- * Mach 3.0 needs facilities to implement resource limits of various sorts.
+ * Mach needs facilities to implement resource limits of various sorts.
- * Mach 3.0 needs a way to have a thread's CPU time statistics
+ * Mach needs a way to have a thread's CPU time statistics
include time spent by servers on its behalf. [This has been done
- for the migrating-threads version of Mach; talk to mib before starting
+ for the migrating-threads version of Mach; talk to thomas before starting
work on it.]
* Of course, free ports are always necessary to machines that don't
@@ -98,17 +90,11 @@ microkernel work there as well as with mib@gnu.ai.mit.edu.
* Much work can be done doing research in how to improve Mach VM
performance and timesharing scheduling policy.
-!!!
- * We need a good malloc for multi-threaded programs that uses
- vm_allocate. It should probably be based on the current GNU malloc,
- as well as merge the mmalloc interfaces used by some existing GNU
- packages.
-
- * Mach 3.0 needs facilities to get a list of all the devices which
+ * Mach needs facilities to get a list of all the devices which
can be device_open'd, as well as to get the type of a device.
* A way to have the kernel send a message on some designated port
- everytime a new task is started.
+ every time a new task is started.
* OSF has enhanced the exception_raise protocol to include thread_state
information. This code should be merged into the kernel; OSF people
@@ -117,14 +103,18 @@ microkernel work there as well as with mib@gnu.ai.mit.edu.
* Implement TASK_EVENTS_INFO.
- * Add a timestamp for task and thread creation to the relevant info
- structures (and make sure it works for the kernel task and threads).
+ * Add an anonymous swap allocation statistic to the task info structure.
-Hurd work (these are brief descriptions; mib can give more information):
+Hurd work (these are brief descriptions; thomas can give more information):
+
+ * Make the thread timeout in libports/manage-multithread.c work.
+
+ * Make thread death in C threads really free resources.
!!!
- * An RPC trace program to aid debugging. Ask roland for more info.
+ * An RPC trace program to aid debugging. Look at utils/rpctrace.c
+ for starters and ask roland for more info.
* Programs that use utmp need to be changed to use /utmp and utmp.defs.
@@ -134,7 +124,12 @@ Hurd work (these are brief descriptions; mib can give more information):
!!!
* We need some existing shell programs changed to do Hurd things:
- like id, su, ls, tar, cpio, etc.
+ like ls, tar, cpio, etc. Some of this work has already been
+ done, but more is still needed.
+
+!!!
+ * Extend bash to call shell functions when various Hurdish async
+ events happen.
* Handy shell programs to send msgport msgs, and change default init
ports and ints.
@@ -144,26 +139,25 @@ Hurd work (these are brief descriptions; mib can give more information):
* A system for write, send, talkd and so forth to bleep users;
this should be integrated with the utmp replacement above.
- * X. (Porting XFree86 should not be hard.)
-
* A filesystem for /tmp that uses virtual memory instead of disk.
(Roland has some ideas about this.)
* Filesystem implementations (using libdiskfs) for other popular
formats. Importantly, MSDOS FAT format.
-
- * Transparent FTP translator.
+ * A fancy terminal driver that uses readline and supports
+ detach/attach, color, and virtual consoles.
- * A fancy terminal driver that uses readline and supports detach/attach.
+!!!
+ * A PPP interface. This will require some restructuring of pfinet.
* A notepad program to hold and keep track of ports for shell scripts.
-C library work. See roland@gnu.ai.mit.edu if you are interested in working
+C library work. See roland@gnu.org if you are interested in working
on anything in the C library.
* Useful response to SIGINFO.
- * Better integration with cthreads.
+ * Get pthreads working and integrated.
diff --git a/term/ChangeLog b/term/ChangeLog
deleted file mode 100644
index a4831628..00000000
--- a/term/ChangeLog
+++ /dev/null
@@ -1,405 +0,0 @@
-Mon Jul 29 02:46:12 1996 Roland McGrath <roland@baalperazim.frob.com>
-
- * munge.c (input_character): In LAST_LNEXT case, jump to `alldone'
- after putting the char on the queue.
-
-Fri Jul 19 23:46:39 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c (trivfs_S_file_access): Implement locally always
- returning all access. Eventually, this needs to do the right
- thing when trivfs wises up wrt modes.
-
-Tue Jul 16 20:49:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c (trivfs_S_io_read): Bother to set atime when
- appropriate.
-
- * users.c (trivfs_modify_stat): Fill in st->st_mode, st->st_uid,
- and st->st_gid ourselves.
- (trivfs_S_file_chown): New routine, to override trivfs default.
- (trivfs_S_file_chmod): Likewise.
- * main.c (main): Initialize term_owner, term_group, and term_mode.
- * term.h (term_owner, term_group, term_mode): New variables.
-
-Thu Jun 20 16:45:57 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * devio.c (devio_abandon_physical_output): Don't do anything if
- carrier is off.
-
-Thu Jun 20 16:26:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (OBJS): Add ../libfshelp/libfshelp.a.
-
-Sat May 11 01:18:41 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * iomux.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
-
-Fri May 10 09:27:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c: Include <stdio.h>.
-
- * users.c (init_users): Order args correctly in call to
- ports_create_port.
-
-Thu May 9 19:32:50 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c (call_asyncs): Provide sigcode arg in call to
- nowait_msg_sig_post.
-
- * users.c (init_users): Use new ports_create_port.
- * devio.c (device_open_reply): Likewise.
-
-Thu Apr 25 16:04:17 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ptyio.c (pty_open_hook): Don't do increment of nptyperopens
- here.
- (pty_po_create_hook): Increment nptyperopens here, but only if this is
- for O_READ or O_WRITE.
- (pty_po_destroy_hook): Only do decrement if this was for O_READ or
- O_WRITE.
- * users.c (open_hook): Don't circumvent pty_open_hook, not even
- when FLAGS is clear.
-
-Wed Apr 24 09:24:29 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * users.c (call_asyncs): Add DIR argument; all callers changed.
- * term.h: Include <fcntl.h>.
-
- * users.c (call_asyncs): Remove FORCE argument; all callers changed.
- * term.h (enqueue_internal): Go back to only using call_asyncs
- when inputq becomes non-empty.
- (SUPPRESS_ASYNC): Flag removed.
-
-Tue Apr 23 17:44:25 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * term.h (enqueue_internal): Use call_asyncs on every character.
- (SUPPRESS_ASYNC): New flag.
- * users.c (po_create_hook, trivfs_S_io_set_some_openmodes,
- trivfs_S_io_set_all_openmodes): If setting ICKY_ASYNC, then use
- call_asyncs.
- (call_asyncs): New argument, FORCE, which use. All callers changed.
- (init_users): Give our self send rights to the async id ports, since
- hurd_sig_post uses COPY_SEND.
- (trivfs_S_io_get_icky_async_id): Renamed from ..._get_async_icky.
- (trivfs_S_file_set_size, trivfs_S_io_seek,
- trivfs_S_io_get_icky_async_id, trivfs_S_io_async): Add reply port args.
-
- * users.c (num_icky_async_peropens): New variable.
- (po_create_hook, po_destroy_hook, trivfs_S_io_set_all_openmodes,
- trivfs_S_io_set_some_openmodes, trivfs_S_io_clear_some_openmodes): Use
- it to enable ICKY_ASYNC to be turned off.
-
-Tue Apr 23 14:26:22 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c (call_asyncs): Delete local decl; no longer static.
- * term.h (dequeue_quote): If this is the outputq, send SIGIO as
- appropriate with call_asyncs.
- (enqueue_internal): If this is the inputq, send SIGIO as appropriate
- with call_asyncs.
- (call_asyncs): Add decl.
-
-Mon Apr 22 14:55:20 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * devio.c (real_speed_to_bogus_speed): EXTB should be 38400, not
- 24800.
-
-Tue Apr 2 16:18:09 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ptyio.c (pty_po_create_hook): Don't do anything here.
- (pty_open_hook): Increment nptyperopens here.
-
-Wed Mar 27 11:51:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * users.c (trivfs_S_io_read): Call call_asyncs *before* we release
- GLOBAL_LOCK.
- (pi_destroy_hook): Leak the hook for now, to try and catch a bug. XXX
-
- * ptyio.c (pty_io_read): Block using hurd_condition_wait instead
- of condition_wait.
-
-Sat Feb 24 13:56:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ptyio.c (ptyio_init): This can't be a constructor because it
- frobs INPUTQ, which is assigned in main.
- * main.c (main): Call ptyio_init if appropriate.
- * term.h: Declare ptyio_init.
-
-Wed Feb 14 14:02:54 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * users.c (trivfs_S_io_set_all_openmodes,
- trivfs_S_io_set_some_openmodes): Set ICKY_ASYNC in TERMFLAGS if
- O_ASYNC is set in BITS.
-
-Thu Jan 25 22:54:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Use trivfs_startup & trivfs_create_port instead
- of trivfs_handle_port.
- * devio.c (devio_assert_dtr): Use ports_create_port instead of
- ports_allocate_port.
-
-Thu Jan 18 11:50:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c (report_carrier_off): Flush queues when carrier turns
- off.
-
-Tue Dec 26 16:58:55 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * users.c (trivfs_S_io_select): Ask for notification if our reply
- port dies. Pass REPLY to pty_io_select().
- * ptyio.c (pty_io_select): Add new reply port parameter, and ask
- for notification if it dies.
- * term.h (pty_io_select): Add new reply port parameter.
-
-Fri Dec 22 14:34:38 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Set PEERCNTL to &PTYCTL if we're a slave, not 0.
-
-Wed Dec 20 13:56:09 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * users.c (S_term_get_nodename, S_term_set_nodename): Get the node
- name from our cred->po->cntl->hook rather than NODENAME.
- * main.c (main): Put the nodename on ourcntl->hook rather than
- NODENAME, and also put our peer's nodname on peercntl->hook.
- * term.h (nodename): Variable removed.
-
- * ptyio.c (ptyopen, nptyperopens, pktnostop, output_stopped):
- Initialize to 0.
-
-Tue Dec 19 19:57:53 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c (trivfs_S_io_read): After a block on the input queue,
- don't go back and check the input queue if there is a signal in
- progress; wait for the signal to complete first.
- (send_signal): Release global_lock around signal RPC. Call
- report_sig_start and report_sig_end around signal RPC.
- (call_asyncs): Likewise.
- (report_sig_start, report_sig_end): New functions.
- (sigs_in_progress, input_sig_wait, input_sig_wakeup): New variables.
-
-Thu Dec 14 12:48:08 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ptyio.c (pty_io_read): When copying TIOCPKT_DATA; account for
- size correctly.
-
- * ptyio.c (pty_io_write): Always tell the user everything was
- written.
-
-Wed Dec 13 19:32:52 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ptyio.c (pty_io_write): Keep track of how mount we wrote.
-
-Tue Dec 12 13:53:40 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * ptyio.c (ptyio_init): Make this a constructor function.
-
- * ptyio.c (pty_open_hook, pty_po_create_hook,
- pty_po_destroy_hook): New functions.
- (ptyopen, nptyperopens): New variables.
- * term.h (pty_open_hook, pty_po_create_hook, pty_po_destroy_hook):
- New declarations.
- * users.c (open_hook): If this is the pty, then call pty specific
- function.
- (po_create_hook): Likewise.
- (po_destroy_hook): Likewise.
- (pi_create_hook): Don't do anything for pty.
- (pi_destroy_hook): Likewise.
-
- * users.c (open_hook): Don't require carrier for opens that don't
- want to read or write.
-
- * users.c (S_tioctl_tiocgpgrp): Omit bogus extra attempt to lock
- global_lock.
-
- * users.c (S_term_get_bottom_type): Return TERM_ON_MASTERPTY when
- appropriate.
-
- * main.c (main): Set BOTTOM.
-
-Tue Dec 5 15:30:36 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c (main): Totally rework arg parsing and translator
- linkage. No longer support being started s a shell program. Now
- support pty's, though no attempt is made to deal nicely with the
- node collision problem.
-
-Mon Dec 4 20:09:21 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * term.h (pty_cntl_class, ptyctl): New variables.
- * main.c (main): Initialize pty_class, pty_cntl_class,
- trivfs_protid_portclasses[1], and trivfs_cntl_portclasses[1].
- (trivfs_protid_portclasses): Increase size to 2.
- (trivfs_cntl_portclasses): Likewise.
- (trivfs_protid_nportclasses): Increase initialization to 2.
- (trivfs_cntl_nportclasses): Likewise.
-
- * ptyio.c: Include <unistd.h>.
- (ptyio_set_bits): If the stop char state has changed, dinkle the
- stop bits in the control_byte accordingly.
-
- * term.h: Include <hurd/trivfs.h> and <sys/types.h>.
- (pty_io_write, pty_io_read, pty_io_readable, pty_io_select): New
- declarations.
- * ptyio.c: Include <fcntl.h>.
- (pty_io_read): Add CRED arg.
- (pty_io_write): Likewise.
- (pty_io_select): Likewise.
- * users.c (trivfs_S_io_write): If this is a pty master, call pty
- routine to do the work.
- (trivfs_S_io_read): Likewise.
- (trivfs_S_io_readable): Likewise.
- (trivfs_S_io_select): Likewise.
- (S_tioctl_tiocmodg): Accept both pty and tty ports.
- (S_tioctl_tiocmods): Likewise.
- (S_tioctl_tiocexcl): Likewise.
- (S_tioctl_tiocnxcl): Likewise.
- (S_tioctl_tiocflush): Likewise.
- (S_tioctl_tiocgeta): Likewise.
- (set_state): Likewise.
- (S_tioctl_tiocgetd): Likewise.
- (S_tioctl_tiocsetd): Likewise.
- (S_tioctl_tiocdrain): Likewise.
- (S_tioctl_tiocswinsz): Likewise.
- (S_tioctl_tiocgwinsz): Likewise.
- (S_tioctl_tiocmget): Likewise.
- (S_tioctl_tiocmset): Likewise.
- (S_tioctl_tiocmbic): Likewise.
- (S_tioctl_tiocmbis): Likewise.
- (S_tioctl_tiocstart): Likewise.
- (S_tioctl_tiocstop): Likewise.
- (S_tioctl_tiocsti): Likewise.
- (S_tioctl_tiocoutq): Likewise.
- (S_tioctl_tiocspgrp): Likewise.
- (S_tioctl_tiocgpgrp): Likewise.
- (S_tioctl_tioccdtr): Likewise.
- (S_tioctl_tiocsdtr): Likewise.
- (S_tioctl_tioccbrk): Likewise.
- (S_tioctl_tiocsbrk): Likewise.
- (set_state): If this op is being done on the pty master, then
- flush output before beginning work.
-
-Fri Dec 1 14:08:44 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * users.c (trivfs_S_interrupt_operation): Delete function.
-
- * users.c (S_tioctl_tiocdrain): Free reference on CRED before
- returning.
-
- * munge.c (input_character): Skip much processing if
- external_processing is on.
- (output_character): Don't do tab expansion of external_processing
- is on.
- (echo_p): Never echo if external_processing is on.
- * users.c (set_state): Make EXTPROC bit read only. When
- external_processing, call set_bits even if CIGNORE.
- (S_tioctl_tiocext): Deleted function.
- * term.h (external_processing): New variable.
-
- * users.c (trivfs_S_io_readable): If remote_input_mode, then don't
- include extra final character as input.
- trivfs_S_io_read): If remote_input_mode, copy characters without
- interpretation; treat last character left in queue as junk.
- (S_tioctl_tiocremote): Deleted function.
- * term.h (remote_input_mode): New variable.
-
- * users.c (S_tioctl_tiocsig, S_tioctl_tiocpkt,
- S_tioctl_tiocucntl): Deleted functions.
-
- * term.h (ptyio_bottom, pty_class): New variables.
- * Makefile (SRCS): Added ptyio.c.
- * ptyio.c: New file.
-
- * term.h (struct bottomhalf): New member `notice_input_flushed'.
- * devio.c (devio_notice_input_flushed): New function.
- (devio_bottom): Add devio_notice_input_flushed.
- * users.c (po_destroy_hook): Call notice_input_flushed after
- flushing input queues.
- (S_tioctl_tiocflush): Likewise.
- (set_state): Likewise.
-
- * munge.c (input_character) [VSTOP]: Suspend physical output after
- setting flag.
- * term.h (struct bottomhalf): New member `suspend_physical_output'.
- * users.c (S_tioctl_tiocstart): Start output after clearing
- USER_OUTPUT_SUSP.
- (S_tioctl_tiocstop): Suspend physical output after setting flag.
- * devio.c (devio_start_output): Honor USER_OUTPUT_SUSP flag.
- Restart output if USER_OUTPUT_SUSP flag off and output_stopped true.
- (output_stopped): New variable.
- (devio_suspend_physical_output): New function.
- (devio_bottom): Add devio_suspend_physical_output.
-
- * users.c (trivfs_S_io_select): Return EINTR if we are cancelled.
-
- * munge.c (reprint_line): C-r is CHAR_DC2, not DC3.
- * term.h (CHAR_DC3): Correct value is '\023'.
- (CHAR_DC1, CHAR_DC2): New macros.
-
-Thu Nov 30 15:50:01 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * devio.c (start_output): Add devio_ prefix; declare static.
- All callers changed.
- (set_break): Likewise.
- (clear_break): Likewise.
- (abandon_physical_output): Likewise.
- (pending_output_size): Likewise.
- (assert_dtr): Likewise.
- (desert_dtr): Likewise.
- (set_bits): Likewise.
- (mdmctl): Likewise.
- (mdmstate): Likewise.
- (devio_bottom): New variable.
- * term.h (struct bottomhalf): New type.
- (bottom, devio_bottom): New variables.
- (start_output, set_break, clear_break, abandon_physical_output,
- pending_output_size, assert_dtr, desert_dtr, set_bits, mdmctl,
- mdmstate): Deleted declarations.
-
- * devio.c (ports_do_mach_notify_send_once): New function.
-
-Sun Nov 5 02:07:56 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Add flags arg to fsys_startup call.
-
-Sat Sep 23 00:48:17 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * term.h: Include errno.h.
-
-Mon Sep 18 14:51:40 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * users.c (trivfs_S_file_set_size): Renamed from
- trivfs_S_file_truncate.
-
-Sat Sep 16 13:03:40 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Added ourmsg.defs.
- (ourmsg_U.h ourmsgUser.c, ourmsg.defs): Targets removed.
-
-Thu Sep 7 13:08:55 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * users.c (trivfs_S_io_write): Start pending output before
- blocking.
-
-Fri Sep 1 09:51:11 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * munge.c (input_character): Clear input queues correctly for
- VINTR/VQUIT, VSUSP, and input queue full.
-
- * users.c (init_users): New function.
- * main.c (main): Call init_users.
- * term.h (init_users): New decl.
-
- * users.c (open_hook): Turn on NO_OWNER for fresh opens.
- * main.c (main): Assert NO_OWNER in initial state.
-
- * term.h (output_psize): Delete decl.
- (write_character): New decl.
- * munge.c (output_character): Don't set echo_qsize or echo_pstart
- here.
- (write_character): New function.
- (echo_char): Use write_character for closing '/' of hderase.
- (output_psize): New decl.
- * users.c (trivfs_S_io_write): Use write_character instead of
- output_character.
- * main.c (main): Don't initialize output_psize.
-
-
diff --git a/term/Makefile b/term/Makefile
index 8d224f9e..e13763a1 100644
--- a/term/Makefile
+++ b/term/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+#
+# Copyright (C) 1995,96,97,99, 2000, 2002 Free Software Foundation, Inc.
# Written by Michael I. Bushnell, p/BSG.
#
# This file is part of the GNU Hurd.
@@ -22,10 +22,13 @@ dir := term
makemode := server
target = term
-SRCS = devio.c munge.c users.c main.c ptyio.c
+SRCS = devio.c munge.c users.c main.c ptyio.c hurdio.c xinl.c
LCLHDRS = term.h
DIST_FILES = ourmsg.defs
-OBJS = $(subst .c,.o,$(SRCS)) termServer.o device_replyServer.o tioctlServer.o ourmsgUser.o ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a ../libthreads/libthreads.a
+HURDLIBS = trivfs fshelp iohelp threads ports ihash shouldbeinlibc
+OBJS = $(subst .c,.o,$(SRCS)) termServer.o device_replyServer.o tioctlServer.o ourmsgUser.o
include ../Makeconf
+
+device_replyServer-CPPFLAGS = -DTypeCheck=0 -Wno-unused # XXX
diff --git a/term/devio.c b/term/devio.c
index e8f7f0b6..38eb996c 100644
--- a/term/devio.c
+++ b/term/devio.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,98,99,2000,01,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -18,15 +18,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
-#include "term.h"
-#include <device/device.h>
-#include <device/device_request.h>
-#include <hurd/ports.h>
-#include <string.h>
-#include <sys/types.h>
-#include <hurd.h>
-#include <stdio.h>
+/* Avoid defenition of the baud rates from <ternios.h> at a later time. */
+#include <termios.h>
+/* And undefine the baud rates to avoid warnings from
+ <device/tty_status.h>. */
#undef B50
#undef B75
#undef B110
@@ -40,9 +36,28 @@
#undef B2400
#undef B4800
#undef B9600
+#undef B19200
+#undef B38400
+#undef B57600
+#undef B115200
#undef EXTA
#undef EXTB
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+
+#include <device/device.h>
+#include <device/device_request.h>
#include <device/tty_status.h>
+#include <cthreads.h>
+
+#include <hurd.h>
+#include <hurd/ports.h>
+
+#include "term.h"
+
/* This flag is set if there is an outstanding device_write. */
static int output_pending;
@@ -50,8 +65,13 @@ static int output_pending;
/* This flag is set if there is an outstanding device_read. */
static int input_pending;
-/* This flag is set if there is an outstanding device_open. */
-static int open_pending;
+/* Tell the status of any pending open */
+static enum
+{
+ NOTPENDING, /* no open is pending */
+ INITIAL, /* initial open of device pending */
+ FAKE, /* open pending to block on dtr */
+} open_pending;
static char pending_output[IO_INBAND_MAX];
static int npending_output;
@@ -73,24 +93,49 @@ static device_t device_master;
static int output_stopped;
+/* XXX Mask that omits high bits we are currently not supposed to pass
+ through. */
+static int char_size_mask_xxx = 0xff;
+
/* Forward */
-static void devio_desert_dtr ();
+static error_t devio_desert_dtr ();
+static error_t
+devio_init (void)
+{
+ mach_port_t host_priv;
+ error_t err;
+ err = get_privileged_ports (&host_priv, &device_master);
+ if (err)
+ return err;
+ mach_port_deallocate (mach_task_self (), host_priv);
+ if (!phys_reply_class)
+ phys_reply_class = ports_create_class (0, 0);
+ return 0;
+}
-static void init_devio (void) __attribute__ ((constructor));
-static void
-init_devio ()
+static error_t
+devio_fini (void)
{
- mach_port_t host_priv;
- errno = get_privileged_ports (&host_priv, &device_master);
- if (errno)
+ if (phys_reply_pi)
{
- perror ("Getting priviliged ports");
- exit (1);
+ mach_port_deallocate (mach_task_self (), phys_reply);
+ phys_reply = MACH_PORT_NULL;
+ ports_port_deref (phys_reply_pi);
+ phys_reply_pi = 0;
}
- mach_port_deallocate (mach_task_self (), host_priv);
- phys_reply_class = ports_create_class (0, 0);
+ if (phys_reply_writes_pi)
+ {
+ mach_port_deallocate (mach_task_self (), phys_reply_writes);
+ phys_reply_writes = MACH_PORT_NULL;
+ ports_port_deref (phys_reply_writes_pi);
+ phys_reply_writes_pi = 0;
+ }
+ mach_port_deallocate (mach_task_self (), phys_device);
+ mach_port_deallocate (mach_task_self (), device_master);
+ device_master = MACH_PORT_NULL;
+ return 0;
}
/* XXX Convert a real speed to a bogus Mach speed. Return
@@ -148,6 +193,16 @@ real_speed_to_bogus_speed (int rspeed, int *bspeed)
case 38400:
*bspeed = EXTB;
break;
+#ifdef B57600
+ case 57600:
+ *bspeed = B57600;
+ break;
+#endif
+#ifdef B115200
+ case 115200:
+ *bspeed = B115200;
+ break;
+#endif
default:
return -1;
}
@@ -193,22 +248,30 @@ bogus_speed_to_real_speed (int bspeed)
return 19200;
case EXTB:
return 38400;
+#ifdef B57600
+ case B57600:
+ return 57600;
+#endif
+#ifdef B115200
+ case B115200:
+ return 115200;
+#endif
}
}
/* If there are characters on the output queue and no
pending output requests, then send them. */
-static void
+static error_t
devio_start_output ()
{
char *cp;
int size;
error_t err;
-
+
size = qsize (outputq);
if (!size || output_pending || (termflags & USER_OUTPUT_SUSP))
- return;
+ return 0;
if (output_stopped)
{
@@ -224,10 +287,10 @@ devio_start_output ()
cp = pending_output + npending_output;
npending_output += size;
-
+
while (size--)
*cp++ = dequeue (outputq);
-
+
/* Submit all the outstanding characters to the device. */
/* The D_NOWAIT flag does not, in fact, prevent blocks. Instead,
it merely causes D_WOULD_BLOCK errors when carrier is down...
@@ -239,6 +302,7 @@ devio_start_output ()
devio_desert_dtr ();
else if (!err)
output_pending = 1;
+ return 0;
}
error_t
@@ -250,9 +314,9 @@ device_write_reply_inband (mach_port_t replypt,
return EOPNOTSUPP;
mutex_lock (&global_lock);
-
+
output_pending = 0;
-
+
if (return_code == 0)
{
if (amount >= npending_output)
@@ -274,7 +338,7 @@ device_write_reply_inband (mach_port_t replypt,
devio_desert_dtr ();
else
devio_start_output ();
-
+
mutex_unlock (&global_lock);
return 0;
}
@@ -290,15 +354,21 @@ device_read_reply_inband (mach_port_t replypt,
if (replypt != phys_reply)
return EOPNOTSUPP;
-
+
mutex_lock (&global_lock);
-
+
input_pending = 0;
-
+
if (!error_code && (termstate.c_cflag & CREAD))
for (i = 0; i < datalen; i++)
{
- flush = input_character (data[i]);
+ int c = data[i];
+
+ /* XXX Mach only supports 8-bit channels; this munges things
+ to account for the reality. */
+ c &= char_size_mask_xxx;
+
+ flush = input_character (c);
if (flush)
break;
}
@@ -313,29 +383,31 @@ device_read_reply_inband (mach_port_t replypt,
D_WOULD_BLOCK errors when carrier drops. */
err = device_read_request_inband (phys_device, phys_reply, D_NOWAIT,
0, vm_page_size);
-
+
if (err)
devio_desert_dtr ();
- else
+ else
input_pending = 1;
mutex_unlock (&global_lock);
return 0;
}
-static void
+static error_t
devio_set_break ()
{
device_set_status (phys_device, TTY_SET_BREAK, 0, 0);
+ return 0;
}
-static void
+static error_t
devio_clear_break ()
{
device_set_status (phys_device, TTY_CLEAR_BREAK, 0, 0);
+ return 0;
}
-static void
+static error_t
devio_abandon_physical_output ()
{
int val = D_WRITE;
@@ -343,20 +415,19 @@ devio_abandon_physical_output ()
/* If this variable is clear, then carrier is gone, so we
have nothing to do. */
if (!phys_reply_writes_pi)
- return;
-
+ return 0;
+
mach_port_deallocate (mach_task_self (), phys_reply_writes);
ports_reallocate_port (phys_reply_writes_pi);
- phys_reply_writes = ports_get_right (phys_reply_writes_pi);
- mach_port_insert_right (mach_task_self (), phys_reply_writes,
- phys_reply_writes, MACH_MSG_TYPE_MAKE_SEND);
+ phys_reply_writes = ports_get_send_right (phys_reply_writes_pi);
device_set_status (phys_device, TTY_FLUSH, &val, TTY_FLUSH_COUNT);
npending_output = 0;
output_pending = 0;
+ return 0;
}
-static void
+static error_t
devio_suspend_physical_output ()
{
if (!output_stopped)
@@ -364,11 +435,13 @@ devio_suspend_physical_output ()
device_set_status (phys_device, TTY_STOP, 0, 0);
output_stopped = 1;
}
+ return 0;
}
-static void
+static error_t
devio_notice_input_flushed ()
{
+ return 0;
}
static int
@@ -379,33 +452,19 @@ devio_pending_output_size ()
return npending_output;
}
-static void
-devio_desert_dtr ()
-{
- /* This will work, because we set the TF_HUPCLS bit earlier. */
- device_close (phys_device);
- mach_port_deallocate (mach_task_self (), phys_device);
- phys_device = MACH_PORT_NULL;
-
- mach_port_deallocate (mach_task_self (), phys_reply);
- mach_port_deallocate (mach_task_self (), phys_reply_writes);
- phys_reply = phys_reply_writes = MACH_PORT_NULL;
-
- ports_port_deref (phys_reply_pi);
- ports_port_deref (phys_reply_writes_pi);
- phys_reply_pi = phys_reply_writes_pi = 0;
-
- report_carrier_off ();
-}
-
+/* Do this the first time the device is to be opened */
static error_t
-devio_assert_dtr ()
+initial_open ()
{
error_t err;
-
- if (open_pending || (phys_device != MACH_PORT_NULL))
+
+ assert (open_pending != FAKE);
+
+ /* Nothing to do */
+ if (open_pending == INITIAL)
return 0;
-
+
+ assert (phys_device == MACH_PORT_NULL);
assert (phys_reply == MACH_PORT_NULL);
assert (phys_reply_pi == 0);
@@ -414,12 +473,10 @@ devio_assert_dtr ()
if (err)
return err;
- phys_reply = ports_get_right (phys_reply_pi);
- mach_port_insert_right (mach_task_self (), phys_reply, phys_reply,
- MACH_MSG_TYPE_MAKE_SEND);
+ phys_reply = ports_get_send_right (phys_reply_pi);
err = device_open_request (device_master, phys_reply,
- D_READ|D_WRITE, pterm_name);
+ D_READ|D_WRITE, tty_arg);
if (err)
{
mach_port_deallocate (mach_task_self (), phys_reply);
@@ -427,120 +484,197 @@ devio_assert_dtr ()
ports_port_deref (phys_reply_pi);
phys_reply_pi = 0;
}
+ else
+ open_pending = INITIAL;
+
return err;
}
+static error_t
+devio_desert_dtr ()
+{
+ int bits;
+
+ /* Turn off DTR. */
+ bits = TM_HUP;
+ device_set_status (phys_device, TTY_MODEM,
+ (dev_status_t) &bits, TTY_MODEM_COUNT);
+
+ report_carrier_off ();
+ return 0;
+}
+
+static error_t
+devio_assert_dtr ()
+{
+ error_t err;
+
+ /* The first time is special. */
+ if (phys_device == MACH_PORT_NULL)
+ return initial_open ();
+
+ /* Schedule a fake open to wait for DTR, unless one is already
+ happening. */
+ assert (open_pending != INITIAL);
+ if (open_pending == FAKE)
+ return 0;
+
+ err = device_open_request (device_master, phys_reply,
+ D_READ|D_WRITE, tty_arg);
+
+ if (err)
+ return err;
+
+ open_pending = FAKE;
+ return 0;
+}
+
kern_return_t
device_open_reply (mach_port_t replyport,
int returncode,
mach_port_t device)
{
struct tty_status ttystat;
- int count = TTY_STATUS_COUNT;
- error_t err;
+ size_t count = TTY_STATUS_COUNT;
+ error_t err = 0;
if (replyport != phys_reply)
return EOPNOTSUPP;
mutex_lock (&global_lock);
- open_pending = 0;
-
+ assert (open_pending != NOTPENDING);
+
if (returncode != 0)
{
- /* Bogus. */
- report_carrier_on ();
- report_carrier_off ();
-
+ report_carrier_error (returncode);
+
mach_port_deallocate (mach_task_self (), phys_reply);
phys_reply = MACH_PORT_NULL;
ports_port_deref (phys_reply_pi);
phys_reply_pi = 0;
+
+ open_pending = NOTPENDING;
mutex_unlock (&global_lock);
return 0;
}
- assert (phys_device == MACH_PORT_NULL);
- assert (phys_reply_writes == MACH_PORT_NULL);
- assert (phys_reply_writes_pi == 0);
- phys_device = device;
- errno = ports_create_port (phys_reply_class, term_bucket,
- sizeof (struct port_info),
- &phys_reply_writes_pi);
- if (errno)
- return errno;
- phys_reply_writes = ports_get_right (phys_reply_writes_pi);
- mach_port_insert_right (mach_task_self (), phys_reply_writes,
- phys_reply_writes, MACH_MSG_TYPE_MAKE_SEND);
+ if (open_pending == INITIAL)
+ {
+ /* Special handling for the first open */
+
+ assert (phys_device == MACH_PORT_NULL);
+ assert (phys_reply_writes == MACH_PORT_NULL);
+ assert (phys_reply_writes_pi == 0);
+ phys_device = device;
+ err = ports_create_port (phys_reply_class, term_bucket,
+ sizeof (struct port_info),
+ &phys_reply_writes_pi);
+ if (err)
+ {
+ open_pending = NOTPENDING;
+ mutex_unlock (&global_lock);
+ return err;
+ }
+ phys_reply_writes = ports_get_send_right (phys_reply_writes_pi);
+
+ /* Schedule our first read */
+ err = device_read_request_inband (phys_device, phys_reply, D_NOWAIT,
+ 0, vm_page_size);
+
+ input_pending = 1;
+ }
+ else
+ {
+ /* This was a fake open, only for the sake of assert DTR. */
+ device_close (device);
+ mach_port_deallocate (mach_task_self (), device);
+ }
device_get_status (phys_device, TTY_STATUS,
(dev_status_t)&ttystat, &count);
ttystat.tt_breakc = 0;
ttystat.tt_flags = TF_ANYP | TF_LITOUT | TF_NOHANG | TF_HUPCLS;
- device_set_status (phys_device, TTY_STATUS,
+ device_set_status (phys_device, TTY_STATUS,
(dev_status_t)&ttystat, TTY_STATUS_COUNT);
- err = device_read_request_inband (phys_device, phys_reply, D_NOWAIT,
- 0, vm_page_size);
-
- input_pending = 1;
report_carrier_on ();
if (err)
devio_desert_dtr ();
+ open_pending = NOTPENDING;
mutex_unlock (&global_lock);
return 0;
-}
+}
-/* Adjust physical state on the basis of the terminal state.
+/* Adjust physical state on the basis of the terminal state.
Where it isn't possible, mutate terminal state to match
reality. */
-static void
-devio_set_bits ()
+static error_t
+devio_set_bits (struct termios *state)
{
- struct tty_status ttystat;
- int cnt = TTY_STATUS_COUNT;
+ if (!(state->c_cflag & CIGNORE) && phys_device != MACH_PORT_NULL)
+ {
+ struct tty_status ttystat;
+ size_t cnt = TTY_STATUS_COUNT;
+
+ /* Find the current state. */
+ device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt);
+ if (state->__ispeed)
+ real_speed_to_bogus_speed (state->__ispeed, &ttystat.tt_ispeed);
+ if (state->__ospeed)
+ real_speed_to_bogus_speed (state->__ospeed, &ttystat.tt_ospeed);
+
+ /* Try and set it. */
+ device_set_status (phys_device, TTY_STATUS,
+ (dev_status_t) &ttystat, TTY_STATUS_COUNT);
+
+ /* And now make termstate match reality. */
+ cnt = TTY_STATUS_COUNT;
+ device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt);
+ state->__ispeed = bogus_speed_to_real_speed (ttystat.tt_ispeed);
+ state->__ospeed = bogus_speed_to_real_speed (ttystat.tt_ospeed);
+
+ /* Mach forces us to use the normal stop bit convention:
+ two bits at 110 bps; 1 bit otherwise. */
+ if (state->__ispeed == 110)
+ state->c_cflag |= CSTOPB;
+ else
+ state->c_cflag &= ~CSTOPB;
- assert (!(termstate.c_cflag & CIGNORE));
+ /* Figure out how to munge input, since we are unable to actually
+ affect what the hardware does. */
+ switch (state->c_cflag & CSIZE)
+ {
+ case CS5:
+ char_size_mask_xxx = 0x1f;
+ break;
- if (phys_device == MACH_PORT_NULL)
- return;
-
- /* Find the current state. */
- device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt);
- if (termstate.__ispeed)
- real_speed_to_bogus_speed (termstate.__ispeed, &ttystat.tt_ispeed);
- if (termstate.__ospeed)
- real_speed_to_bogus_speed (termstate.__ospeed, &ttystat.tt_ospeed);
-
- /* Try and set it. */
- device_set_status (phys_device, TTY_STATUS,
- (dev_status_t) &ttystat, TTY_STATUS_COUNT);
-
- /* And now make termstate match reality. */
- cnt = TTY_STATUS_COUNT;
- device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, &cnt);
- termstate.__ispeed = bogus_speed_to_real_speed (ttystat.tt_ispeed);
- termstate.__ospeed = bogus_speed_to_real_speed (ttystat.tt_ospeed);
-
- /* Mach forces us to use the normal stop bit convention:
- two bits at 110 bps; 1 bit otherwise. */
- if (termstate.__ispeed == 110)
- termstate.c_cflag |= CSTOPB;
- else
- termstate.c_cflag &= ~CSTOPB;
-
- /* Mach only supports 8 bit channels. So wark the CSIZE to conform. */
- termstate.c_cflag = ((termstate.c_cflag & ~CSIZE)
- | ((termstate.c_cflag & PARENB) ? CS7 : CS8));
+ case CS6:
+ char_size_mask_xxx = 0x3f;
+ break;
+
+ case CS7:
+ char_size_mask_xxx = 0x7f;
+ break;
+
+ case CS8:
+ default:
+ char_size_mask_xxx = 0xff;
+ break;
+ }
+ if (state->c_cflag & PARENB)
+ char_size_mask_xxx |= 0x80;
+ }
+ return 0;
}
-
-static void
+
+static error_t
devio_mdmctl (int how, int bits)
{
int oldbits, newbits;
- int cnt;
+ size_t cnt;
if ((how == MDMCTL_BIS) || (how == MDMCTL_BIC))
{
cnt = TTY_MODEM_COUNT;
@@ -556,24 +690,27 @@ devio_mdmctl (int how, int bits)
newbits = (oldbits &= ~bits);
else
newbits = bits;
-
- device_set_status (phys_device, TTY_MODEM,
+
+ device_set_status (phys_device, TTY_MODEM,
(dev_status_t) &newbits, TTY_MODEM_COUNT);
+
+ return 0;
}
-static int
-devio_mdmstate ()
+static error_t
+devio_mdmstate (int *state)
{
- int bits, cnt;
-
- cnt = TTY_MODEM_COUNT;
+ int bits;
+ size_t cnt = TTY_MODEM_COUNT;
device_get_status (phys_device, TTY_MODEM, (dev_status_t) &bits, &cnt);
- if (cnt != TTY_MODEM_COUNT)
- return 0;
+ if (cnt == TTY_MODEM_COUNT)
+ *state = bits;
else
- return bits;
+ *state = 0;
+ return 0;
}
+
/* Unused stubs */
kern_return_t
device_read_reply (mach_port_t port,
@@ -596,9 +733,9 @@ error_t
ports_do_mach_notify_send_once (mach_port_t notify)
{
error_t err;
-
+
mutex_lock (&global_lock);
-
+
if (notify == phys_reply_writes)
{
err = 0;
@@ -615,7 +752,7 @@ ports_do_mach_notify_send_once (mach_port_t notify)
/* end xxx */
input_pending = 0;
-
+
err = device_read_request_inband (phys_device, phys_reply,
D_NOWAIT, 0, vm_page_size);
if (err)
@@ -623,13 +760,13 @@ ports_do_mach_notify_send_once (mach_port_t notify)
else
input_pending = 1;
}
- else if (open_pending)
+ else if (open_pending != NOTPENDING)
{
- open_pending = 0;
+ open_pending = NOTPENDING;
report_carrier_on ();
report_carrier_off ();
-
+
mach_port_deallocate (mach_task_self (), phys_reply);
phys_reply = MACH_PORT_NULL;
ports_port_deref (phys_reply_pi);
@@ -639,14 +776,18 @@ ports_do_mach_notify_send_once (mach_port_t notify)
}
else
err = EOPNOTSUPP;
-
+
mutex_unlock (&global_lock);
return err;
}
-struct bottomhalf devio_bottom =
+const struct bottomhalf devio_bottom =
{
+ TERM_ON_MACHDEV,
+ devio_init,
+ devio_fini,
+ NULL,
devio_start_output,
devio_set_break,
devio_clear_break,
@@ -660,6 +801,3 @@ struct bottomhalf devio_bottom =
devio_mdmctl,
devio_mdmstate,
};
-
-
-
diff --git a/term/hurdio.c b/term/hurdio.c
new file mode 100644
index 00000000..ef34740b
--- /dev/null
+++ b/term/hurdio.c
@@ -0,0 +1,628 @@
+/*
+ Copyright (C) 1995,96,98,99,2000,01,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Handle carrier dropped (at least EIO errors in read, write) correctly. */
+
+#include <termios.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+
+#include <cthreads.h>
+
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/io.h>
+#include <hurd/tioctl.h>
+
+#include "term.h"
+
+
+/* The thread asserting the DTR and performing all reads. Only
+ different from MACH_PORT_NULL if thread is live and blocked. */
+thread_t reader_thread = MACH_PORT_NULL;
+
+/* The Hurd file_t representing the terminal. If this is not
+ MACH_PORT_NULL, it has the additional meaning that the DTR is
+ asserted. */
+static file_t ioport = MACH_PORT_NULL;
+
+/* Each bit represents a supported tioctl call in the underlying node.
+ If we detect that a tioctl is not supported, we clear the bit in
+ tioc_caps (which is initialized at every open). */
+#define TIOC_CAP_OUTQ 0x001
+#define TIOC_CAP_START 0x002
+#define TIOC_CAP_STOP 0x004
+#define TIOC_CAP_FLUSH 0x008
+#define TIOC_CAP_CBRK 0x010
+#define TIOC_CAP_SBRK 0x020
+#define TIOC_CAP_MODG 0x040
+#define TIOC_CAP_MODS 0x080
+#define TIOC_CAP_GETA 0x100
+#define TIOC_CAP_SETA 0x200
+#define TIOC_CAP_GWINSZ 0x400
+unsigned int tioc_caps;
+
+/* The thread performing all writes. Only different from
+ MACH_PORT_NULL if thread is live and blocked. */
+thread_t writer_thread = MACH_PORT_NULL;
+
+/* This flag is set if the output was suspended. */
+static int output_stopped;
+static struct condition hurdio_writer_condition;
+
+/* Hold the amount of bytes that are currently in the progress of
+ being written. May be set to zero while you hold the global lock
+ to drain the pending output buffer. */
+size_t npending_output;
+
+/* True if we should assert the dtr. */
+int assert_dtr;
+static struct condition hurdio_assert_dtr_condition;
+
+
+/* Forward */
+static error_t hurdio_desert_dtr ();
+static any_t hurdio_reader_loop (any_t arg);
+static any_t hurdio_writer_loop (any_t arg);
+static error_t hurdio_set_bits (struct termios *state);
+
+
+static error_t
+hurdio_init (void)
+{
+ condition_init (&hurdio_writer_condition);
+ condition_init (&hurdio_assert_dtr_condition);
+
+ cthread_detach (cthread_fork (hurdio_reader_loop, 0));
+ cthread_detach (cthread_fork (hurdio_writer_loop, 0));
+ return 0;
+}
+
+static error_t
+hurdio_fini (void)
+{
+ hurdio_desert_dtr ();
+ writer_thread = MACH_PORT_NULL;
+ /* XXX destroy reader thread too */
+ return 0;
+}
+
+static error_t
+hurdio_gwinsz (struct winsize *size)
+{
+ if (tioc_caps & TIOC_CAP_GWINSZ)
+ {
+ error_t err = tioctl_tiocgwinsz (ioport, size);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ {
+ tioc_caps &= ~TIOC_CAP_GWINSZ;
+ err = EOPNOTSUPP;
+ }
+ return err;
+ }
+ return EOPNOTSUPP;
+}
+
+
+/* Assert the DTR if necessary. Must be called with global lock held. */
+static void
+wait_for_dtr (void)
+{
+ while (!assert_dtr)
+ hurd_condition_wait (&hurdio_assert_dtr_condition, &global_lock);
+ assert_dtr = 0;
+
+ if (tty_arg == 0)
+ ioport = termctl->underlying;
+ else
+ {
+ /* Open the file in blocking mode, so that the carrier is
+ established as well. */
+ ioport = file_name_lookup (tty_arg, O_READ|O_WRITE, 0);
+ if (ioport == MACH_PORT_NULL)
+ {
+ report_carrier_error (errno);
+ return;
+ }
+ }
+
+
+ error_t err;
+ struct termios state = termstate;
+
+ /* Assume that we have a full blown terminal initially. */
+ tioc_caps = ~0;
+
+ /* Set terminal in raw mode etc. */
+ err = hurdio_set_bits (&state);
+ if (err)
+ report_carrier_error (err);
+ else
+ {
+ termstate = state;
+
+ /* Signal that we have a carrier. */
+ report_carrier_on ();
+
+ /* Signal that the writer thread should resume its work. */
+ condition_broadcast (&hurdio_writer_condition);
+ }
+}
+
+
+/* Read and enqueue input characters. Is also responsible to assert
+ the DTR if necessary. */
+static any_t
+hurdio_reader_loop (any_t arg)
+{
+ /* XXX The input buffer has 256 bytes. */
+#define BUFFER_SIZE 256
+ char buffer[BUFFER_SIZE];
+ char *data;
+ size_t datalen;
+ error_t err;
+
+ mutex_lock (&global_lock);
+ reader_thread = mach_thread_self ();
+
+ while (1)
+ {
+ /* We can only start when the DTR has been asserted. */
+ while (ioport == MACH_PORT_NULL)
+ wait_for_dtr ();
+ mutex_unlock (&global_lock);
+
+ data = buffer;
+ datalen = BUFFER_SIZE;
+
+ err = io_read (ioport, &data, &datalen, -1, BUFFER_SIZE);
+
+ mutex_lock (&global_lock);
+ /* Error or EOF can mean the carrier has been dropped. */
+ if (err || !datalen)
+ hurdio_desert_dtr ();
+ else
+ {
+ if (termstate.c_cflag & CREAD)
+ {
+ int i;
+
+ for (i = 0; i < datalen; i++)
+ if (input_character (data[i]))
+ break;
+ }
+
+ if (data != buffer)
+ vm_deallocate (mach_task_self(), (vm_address_t) data, datalen);
+ }
+ }
+#undef BUFFER_SIZE
+
+ return 0;
+}
+
+
+/* Output characters. */
+static any_t
+hurdio_writer_loop (any_t arg)
+{
+ /* XXX The output buffer has 256 bytes. */
+#define BUFFER_SIZE 256
+ char *bufp;
+ char pending_output[BUFFER_SIZE];
+ size_t amount;
+ error_t err;
+ int size;
+ int npending_output_copy;
+ mach_port_t ioport_copy;
+
+ mutex_lock (&global_lock);
+ writer_thread = mach_thread_self ();
+
+ while (1)
+ {
+ while (writer_thread != MACH_PORT_NULL
+ && (ioport == MACH_PORT_NULL || !qsize (outputq)
+ || output_stopped))
+ hurd_condition_wait (&hurdio_writer_condition, &global_lock);
+ if (writer_thread == MACH_PORT_NULL) /* A sign to die. */
+ return 0;
+
+ /* Copy characters onto PENDING_OUTPUT, not bothering
+ those already there. */
+ size = qsize (outputq);
+
+ if (size + npending_output > BUFFER_SIZE)
+ size = BUFFER_SIZE - npending_output;
+
+ bufp = pending_output + npending_output;
+ npending_output += size;
+ /* We need to save these values, as otherwise there are races
+ with hurdio_abandon_physical_output or hurdio_desert_dtr,
+ which might overwrite the static variables. */
+ npending_output_copy = npending_output;
+ ioport_copy = ioport;
+ mach_port_mod_refs (mach_task_self (), ioport_copy,
+ MACH_PORT_RIGHT_SEND, 1);
+
+ while (size--)
+ *bufp++ = dequeue (outputq);
+
+ /* Submit all the outstanding characters to the I/O port. */
+ mutex_unlock (&global_lock);
+ err = io_write (ioport_copy, pending_output, npending_output_copy,
+ -1, &amount);
+ mutex_lock (&global_lock);
+
+ mach_port_mod_refs (mach_task_self (), ioport_copy,
+ MACH_PORT_RIGHT_SEND, -1);
+ if (err)
+ hurdio_desert_dtr ();
+ else
+ {
+ /* Note that npending_output might be set to null in the
+ meantime by hurdio_abandon_physical_output. */
+ if (amount >= npending_output)
+ {
+ npending_output = 0;
+ condition_broadcast (outputq->wait);
+ }
+ else
+ {
+ /* Copy the characters that didn't get output
+ to the front of the array. */
+ npending_output -= amount;
+ memmove (pending_output, pending_output + amount,
+ npending_output);
+ }
+ }
+ }
+#undef BUFFER_SIZE
+
+ return 0;
+}
+
+
+/* If there are characters on the output queue, then send them. Is
+ called with global lock held. */
+static error_t
+hurdio_start_output ()
+{
+ /* If the output was suspended earlier and not anymore, we have to
+ tell the underlying port to resume it. */
+ if (output_stopped && !(termflags & USER_OUTPUT_SUSP))
+ {
+ if (tioc_caps & TIOC_CAP_START)
+ {
+ error_t err = tioctl_tiocstart (ioport);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_START;
+ }
+ output_stopped = 0;
+ }
+ condition_broadcast (&hurdio_writer_condition);
+ return 0;
+}
+
+
+/* Stop carrier on the line. Is called with global lock held. */
+static error_t
+hurdio_set_break ()
+{
+ if (tioc_caps & TIOC_CAP_SBRK)
+ {
+ error_t err = tioctl_tiocsbrk (ioport);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_SBRK;
+ else if (err)
+ return err;
+ }
+ return 0;
+}
+
+
+/* Reassert carrier on the line. Is called with global lock held. */
+static error_t
+hurdio_clear_break ()
+{
+ if (tioc_caps & TIOC_CAP_CBRK)
+ {
+ error_t err = tioctl_tioccbrk (ioport);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_CBRK;
+ else if (err)
+ return err;
+ }
+ return 0;
+}
+
+
+/* This is called when output queues are being flushed. But there may
+ be pending output which is sitting in a device buffer or other
+ place lower down than the terminal's output queue; so this is
+ called to flush whatever other such things may be going on. Is
+ called with global lock held. */
+static error_t
+hurdio_abandon_physical_output ()
+{
+ if (tioc_caps & TIOC_CAP_FLUSH)
+ {
+ error_t err = tioctl_tiocflush (ioport, O_WRITE);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_FLUSH;
+ else if (err)
+ return err;
+ }
+
+ /* Make sure that an incomplete write will not be finished.
+ hurdio_writer_loop must take care that meddling with
+ npending_output here does not introduce any races. */
+ npending_output = 0;
+ return 0;
+}
+
+
+/* Tell the underlying port to suspend all pending output, and stop
+ output in the bottom handler as well. Is called with the global
+ lock held. */
+static error_t
+hurdio_suspend_physical_output ()
+{
+ if (!output_stopped)
+ {
+ if (tioc_caps & TIOC_CAP_STOP)
+ {
+ error_t err = tioctl_tiocstop (ioport);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_STOP;
+ else if (err)
+ return err;
+ }
+ output_stopped = 1;
+ }
+ return 0;
+}
+
+/* This is called to notify the bottom half when an input flush has
+ occurred. It is necessary to support pty packet mode. */
+static error_t
+hurdio_notice_input_flushed ()
+{
+ if (tioc_caps & TIOC_CAP_FLUSH)
+ {
+ error_t err = tioctl_tiocflush (ioport, O_READ);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_FLUSH;
+ else if (err)
+ return err;
+ }
+ return 0;
+}
+
+
+/* Determine the number of bytes of output pending. */
+static int
+hurdio_pending_output_size ()
+{
+ int queue_size = 0;
+
+ if (tioc_caps & TIOC_CAP_OUTQ)
+ {
+ error_t err = tioctl_tiocoutq (ioport, &queue_size);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_OUTQ;
+ else if (err)
+ queue_size = 0;
+ }
+ /* We can not get the correct number, so let's try a guess. */
+ return queue_size + npending_output;
+}
+
+
+/* Desert the DTR. Is called with global lock held. */
+static error_t
+hurdio_desert_dtr ()
+{
+ if (writer_thread != MACH_PORT_NULL)
+ hurd_thread_cancel (writer_thread);
+ if (reader_thread != MACH_PORT_NULL)
+ hurd_thread_cancel (reader_thread);
+ if (ioport != MACH_PORT_NULL && tty_arg)
+ {
+ mach_port_deallocate (mach_task_self (), ioport);
+ ioport = MACH_PORT_NULL;
+ }
+ /* If we are called after hurdio_assert_dtr before the reader thread
+ had a chance to wake up and open the port, we can prevent it from
+ doing so by clearing this flag. */
+ assert_dtr = 0;
+ report_carrier_off ();
+ return 0;
+}
+
+
+static error_t
+hurdio_assert_dtr ()
+{
+ if (ioport == MACH_PORT_NULL)
+ {
+ assert_dtr = 1;
+ condition_signal (&hurdio_assert_dtr_condition);
+ }
+
+ return 0;
+}
+
+
+/* Adjust physical state on the basis of the terminal state.
+ Where it isn't possible, mutate terminal state to match
+ reality. */
+static error_t
+hurdio_set_bits (struct termios *state)
+{
+ error_t err;
+ struct termios ttystat;
+ /* This structure equals how the Hurd tioctl_tiocgeta/seta split up
+ a termios structure into RPC arguments. */
+ struct hurd_termios
+ {
+ modes_t modes;
+ ccs_t ccs;
+ speeds_t speeds;
+ } *hurd_ttystat = (struct hurd_termios *) &ttystat;
+
+ if (!(state->c_cflag & CIGNORE) && ioport != MACH_PORT_NULL)
+ {
+
+ /* If we can not get the terminal state, it doesn't make sense
+ to attempt to change it. Even if we could change it we
+ wouldn't know what changes took effect. */
+ if (!(tioc_caps & TIOC_CAP_GETA))
+ /* XXX Maybe return an error here, but then we must do the
+ right thing in users.c. */
+ return 0;
+
+ err = tioctl_tiocgeta (ioport, hurd_ttystat->modes,
+ hurd_ttystat->ccs, hurd_ttystat->speeds);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ {
+ tioc_caps &= ~TIOC_CAP_GETA;
+ /* XXX Maybe return an error here, but then we must do the
+ right thing in users.c. */
+ return 0;
+ }
+ else if (err)
+ return err;
+
+ /* If possible, change the state. Otherwise we will just make
+ termstate match reality below. */
+ if (tioc_caps & TIOC_CAP_SETA)
+ {
+ if (state->__ispeed)
+ hurd_ttystat->speeds[0] = state->__ispeed;
+ if (state->__ospeed)
+ hurd_ttystat->speeds[1] = state->__ospeed;
+ cfmakeraw (&ttystat);
+ ttystat.c_cflag = state->c_cflag &~ HUPCL;
+
+ err = tioctl_tiocseta (ioport, hurd_ttystat->modes,
+ hurd_ttystat->ccs, hurd_ttystat->speeds);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_SETA;
+ else if (err)
+ return err;
+
+ /* Refetch the terminal state. */
+ err = tioctl_tiocgeta (ioport, hurd_ttystat->modes,
+ hurd_ttystat->ccs, hurd_ttystat->speeds);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_GETA;
+ else if (err)
+ return err;
+ }
+
+ /* And now make termstate match reality. */
+ *state = ttystat;
+ }
+
+ return 0;
+}
+
+/* Diddle the modem control bits. If HOW is MDMCTL_BIC, the bits set
+ in BITS should be cleared. If HOW is MDMCTL_BIS, the bits in BITS
+ should be set. Otherwise, bits that are set in BITS should be set,
+ and the others cleared. */
+static error_t
+hurdio_mdmctl (int how, int bits)
+{
+ error_t err;
+ int oldbits, newbits;
+
+ if (tioc_caps & TIOC_CAP_MODS)
+ {
+ if ((how == MDMCTL_BIS) || (how == MDMCTL_BIC))
+ {
+ if (tioc_caps & TIOC_CAP_MODG)
+ {
+ error_t err = tioctl_tiocmodg (ioport, &oldbits);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_MODG;
+ else if (err)
+ return err;
+ }
+ }
+
+ if (how == MDMCTL_BIS)
+ newbits = (oldbits | bits);
+ else if (how == MDMCTL_BIC)
+ newbits = (oldbits &= ~bits);
+ else
+ newbits = bits;
+
+ err = tioctl_tiocmods (ioport, oldbits);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_MODS;
+ else if (err)
+ return err;
+ }
+ return 0;
+}
+
+
+static int
+hurdio_mdmstate ()
+{
+ int oldbits;
+
+ if (tioc_caps & TIOC_CAP_MODG)
+ {
+ error_t err = tioctl_tiocmodg (ioport, &oldbits);
+ if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+ tioc_caps &= ~TIOC_CAP_MODG;
+ else if (err)
+ return 0; /* XXX What else can we do? */
+ }
+ return 0;
+}
+
+
+
+const struct bottomhalf hurdio_bottom =
+{
+ TERM_ON_HURDIO,
+ hurdio_init,
+ hurdio_fini,
+ hurdio_gwinsz,
+ hurdio_start_output,
+ hurdio_set_break,
+ hurdio_clear_break,
+ hurdio_abandon_physical_output,
+ hurdio_suspend_physical_output,
+ hurdio_pending_output_size,
+ hurdio_notice_input_flushed,
+ hurdio_assert_dtr,
+ hurdio_desert_dtr,
+ hurdio_set_bits,
+ hurdio_mdmctl,
+ hurdio_mdmstate,
+};
diff --git a/term/main.c b/term/main.c
index d0702e83..405e7cd8 100644
--- a/term/main.c
+++ b/term/main.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/* main.c - A translator that emulates a terminal.
+ Copyright (C) 1995,96,97,2000,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -23,21 +23,40 @@
#include <fcntl.h>
#include <hurd/trivfs.h>
#include <stdio.h>
+#include <argp.h>
#include <hurd/fsys.h>
#include <string.h>
+#include <error.h>
+#include <inttypes.h>
+#include <argz.h>
+
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (term);
int trivfs_fstype = FSTYPE_TERM;
-int trivfs_fsid = 0; /* pid?? */
+int trivfs_fsid = 0;
int trivfs_support_read = 1;
int trivfs_support_write = 1;
int trivfs_support_exec = 0;
int trivfs_allow_open = O_READ|O_WRITE;
-struct port_class *trivfs_protid_portclasses[2];
-struct port_class *trivfs_cntl_portclasses[2];
-int trivfs_protid_nportclasses = 2;
-int trivfs_cntl_nportclasses = 2;
+enum tty_type { T_NONE = 0, T_DEVICE, T_HURDIO, T_PTYMASTER, T_PTYSLAVE };
+static const char *const tty_type_names[] =
+{
+ [T_DEVICE] = "device",
+ [T_HURDIO] = "hurdio",
+ [T_PTYMASTER] = "pty-master",
+ [T_PTYSLAVE] = "pty-slave",
+};
+
+
+/* The argument line options. */
+char *tty_name;
+enum tty_type tty_type;
+char *tty_arg;
+dev_t rdev;
int
demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
@@ -52,41 +71,248 @@ demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
|| device_reply_server (inp, outp));
}
+static struct argp_option options[] =
+{
+ {"rdev", 'n', "ID", 0,
+ "The stat rdev number for this node; may be either a"
+ " single integer, or of the form MAJOR,MINOR"},
+ {"name", 'N', "NAME", 0,
+ "The name of this node, to be returned by term_get_nodename."},
+ {"type", 'T', "TYPE", 0,
+ "Backend type, see below. This determines the meaning of the argument."},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ struct
+ {
+ dev_t rdev;
+ int rdev_set;
+ enum tty_type type;
+ char *name;
+ char *arg;
+ } *const v = state->hook;
+
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+
+ case ARGP_KEY_INIT:
+ state->hook = calloc (1, sizeof *v);
+ break;
+ case ARGP_KEY_FINI:
+ free (v);
+ state->hook = 0;
+ break;
+
+ case 'n':
+ {
+ char *start = arg;
+ char *end;
+
+ v->rdev = strtoumax (start, &end, 0);
+ if (*end == ',')
+ {
+ /* MAJOR,MINOR form. */
+ start = end;
+ v->rdev = (rdev << 8) + strtoul (start, &end, 0);
+ }
+
+ if (end == start || *end != '\0')
+ {
+ argp_error (state, "%s: Invalid argument to --rdev", arg);
+ return EINVAL;
+ }
+
+ v->rdev_set = 1;
+ }
+ break;
+
+ case 'N':
+ v->name = arg;
+ break;
+
+ case ARGP_KEY_ARG:
+ if (!v->name && state->input == 0)
+ v->name = arg;
+ else if (!v->type && state->input == 0)
+ {
+ case 'T':
+ if (!strcmp (arg, "device"))
+ v->type = T_DEVICE;
+ else if (!strcmp (arg, "hurdio"))
+ v->type = T_HURDIO;
+ else if (!strcmp (arg, "pty-master"))
+ v->type = T_PTYMASTER;
+ else if (!strcmp (arg, "pty-slave"))
+ v->type = T_PTYSLAVE;
+ else
+ {
+ argp_error (state, "Invalid terminal type");
+ return EINVAL;
+ }
+ }
+ else if (!v->arg)
+ v->arg = arg;
+ else
+ {
+ argp_error (state, "Too many arguments");
+ return EINVAL;
+ }
+ break;
+
+ case ARGP_KEY_END:
+ if ((v->type && v->type != T_HURDIO && v->arg == 0)
+ || (state->input == 0 && v->name == 0))
+ {
+ argp_error (state, "Too few arguments");
+ return EINVAL;
+ }
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ /* Apply the values we've collected. */
+ if (v->rdev_set)
+ rdev = v->rdev;
+ if (v->name)
+ {
+ free (tty_name);
+ tty_name = strdup (v->name);
+ }
+ if (state->input == 0) /* This is startup time. */
+ {
+ tty_type = v->type ?: T_HURDIO;
+ tty_arg = v->arg ? strdup (v->arg) : 0;
+ }
+ else if (v->type || v->arg)
+ {
+ /* Dynamic backend switch. */
+ if (!v->type)
+ v->type = T_HURDIO;
+ switch (v->type)
+ {
+ case T_PTYMASTER:
+ case T_PTYSLAVE:
+ /* Cannot dynamically switch to pty flavors. */
+ return EINVAL;
+ default:
+ break;
+ }
+ switch (tty_type)
+ {
+ case T_PTYMASTER:
+ case T_PTYSLAVE:
+ /* Cannot dynamically switch from pty flavors either. */
+ return EINVAL;
+ default:
+ break;
+ }
+
+ mutex_lock (&global_lock);
+ (*bottom->fini) ();
+
+ tty_type = v->type;
+ switch (tty_type)
+ {
+ case T_DEVICE:
+ bottom = &devio_bottom;
+ break;
+ case T_HURDIO:
+ bottom = &hurdio_bottom;
+ break;
+ default:
+ assert (! "impossible type");
+ break;
+ }
+ free (tty_arg);
+ tty_arg = strdup (v->arg);
+ error_t err = (*bottom->init) ();
+ if (err == 0 && (termflags & TTY_OPEN))
+ err = (*bottom->assert_dtr) ();
+ mutex_unlock (&global_lock);
+ return err;
+ }
+ break;
+
+ case ARGP_KEY_ERROR:
+ break;
+ }
+ return 0;
+}
+
+static struct argp term_argp =
+ { options, parse_opt, "NAME TYPE ARG",
+ "A translator that implements POSIX termios discipline.\v"
+ "Possible values for TYPE:\n"
+ " device Use Mach device ARG for underlying i/o.\n"
+ " hurdio Use file ARG for i/o, underlying node if no ARG.\n"
+ " pty-master Master for slave at ARG.\n"\
+ " pty-slave Slave for master at ARG.\n"\
+ "\n"
+ "The default type is `hurdio', so no arguments uses the underlying node.\n"
+ "The filename of the node that the translator is attached to should be\n"
+ "supplied in NAME.\n"
+ };
+
+struct argp *trivfs_runtime_argp = &term_argp;
+
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err = 0;
+
+ if (rdev)
+ {
+ char buf[64];
+ snprintf (buf, sizeof buf, "--rdev=%#jx", (uintmax_t)rdev);
+ err = argz_add (argz, argz_len, buf);
+ }
+
+ if (!err && tty_name)
+ err = argz_add (argz, argz_len, "--name")
+ ?: argz_add (argz, argz_len, tty_name);
+
+ if (!err && tty_type != T_HURDIO)
+ err = argz_add (argz, argz_len, "--type")
+ ?: argz_add (argz, argz_len, tty_type_names[tty_type]);
+
+ if (!err && tty_arg)
+ err = argz_add (argz, argz_len, tty_arg);
+
+ return err;
+}
+
int
main (int argc, char **argv)
{
struct port_class *ourclass, *ourcntlclass;
struct port_class *peerclass, *peercntlclass;
struct trivfs_control **ourcntl, **peercntl;
- mach_port_t bootstrap;
- enum {T_DEVICE, T_PTYMASTER, T_PTYSLAVE} type;
+ mach_port_t bootstrap, right;
+ struct stat st;
+ error_t err;
+ int openmode;
term_bucket = ports_create_bucket ();
-
- tty_cntl_class = ports_create_class (trivfs_clean_cntl, 0);
- pty_cntl_class = ports_create_class (trivfs_clean_cntl, 0);
- tty_class = ports_create_class (trivfs_clean_protid, 0);
- pty_class = ports_create_class (trivfs_clean_protid, 0);
+
+ trivfs_add_control_port_class (&tty_cntl_class);
+ trivfs_add_control_port_class (&pty_cntl_class);
+ trivfs_add_protid_port_class (&tty_class);
+ trivfs_add_protid_port_class (&pty_class);
+
cttyid_class = ports_create_class (0, 0);
-
- trivfs_protid_portclasses[0] = tty_class;
- trivfs_protid_portclasses[1] = pty_class;
- trivfs_cntl_portclasses[0] = tty_cntl_class;
- trivfs_cntl_portclasses[1] = pty_cntl_class;
init_users ();
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
-
- if (argc != 4)
- {
- fprintf (stderr, "Usage: term ttyname type arg\n");
- exit (1);
- }
+ argp_parse (&term_argp, argc, argv, 0, 0, 0);
- if (!strcmp (argv[2], "device"))
+ switch (tty_type)
{
- type = T_DEVICE;
+ case T_DEVICE:
bottom = &devio_bottom;
ourclass = tty_class;
ourcntlclass = tty_cntl_class;
@@ -94,11 +320,26 @@ main (int argc, char **argv)
peerclass = 0;
peercntlclass = 0;
peercntl = 0;
- pterm_name = argv[3];
- }
- else if (!strcmp (argv[2], "pty-master"))
- {
- type = T_PTYMASTER;
+ openmode = 0;
+ break;
+
+ case T_HURDIO:
+ bottom = &hurdio_bottom;
+ ourclass = tty_class;
+ ourcntlclass = tty_cntl_class;
+ ourcntl = &termctl;
+ peerclass = 0;
+ peercntlclass = 0;
+ peercntl = 0;
+
+ /* We don't want to have a writable peropen on the underlying node
+ when we'll never use it. Ideally, we shouldn't open one until we
+ do need it, in case it has an affect on the underlying node (like
+ keeping DTR high and such). */
+ openmode = O_RDWR;
+ break;
+
+ case T_PTYMASTER:
bottom = &ptyio_bottom;
ourclass = pty_class;
ourcntlclass = pty_cntl_class;
@@ -106,10 +347,10 @@ main (int argc, char **argv)
peerclass = tty_class;
peercntlclass = tty_cntl_class;
peercntl = &termctl;
- }
- else if (!strcmp (argv[2], "pty-slave"))
- {
- type = T_PTYSLAVE;
+ openmode = 0;
+ break;
+
+ case T_PTYSLAVE:
bottom = &ptyio_bottom;
ourclass = tty_class;
ourcntlclass = tty_cntl_class;
@@ -117,85 +358,96 @@ main (int argc, char **argv)
peerclass = pty_class;
peercntlclass = pty_cntl_class;
peercntl = &ptyctl;
+ openmode = 0;
+ break;
+
+ default:
+ /* Should not happen. */
+ error (1, 0, "Unknown terminal type");
+ /*NOTREACHED*/
+ return 1;
}
- else
- {
- fprintf (stderr,
- "Allowable types are device, pty-master, and pty-slave.\n");
- exit (1);
- }
-
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+
if (bootstrap == MACH_PORT_NULL)
- {
- fprintf (stderr, "Must be started as a translator\n");
- exit (1);
- }
+ error (1, 0, "Must be started as a translator");
- /* Set our node */
- errno = trivfs_startup (bootstrap, 0,
- ourcntlclass, term_bucket, ourclass, term_bucket,
- ourcntl);
- if (errno)
- {
- perror ("Starting translator");
- exit (1);
- }
+ /* Set our node. */
+ err = trivfs_startup (bootstrap, openmode,
+ ourcntlclass, term_bucket, ourclass, term_bucket,
+ ourcntl);
+ if (err)
+ error (1, err, "Starting translator");
/* For ptys, the nodename depends on which half is used. For now just use
the hook to store the nodename. */
- (*ourcntl)->hook = argv[1];
+ (*ourcntl)->hook = tty_name;
- /* Set peer */
+ /* Set peer. */
if (peerclass)
{
- char *peer_name = argv[3];
+ char *peer_name = tty_arg;
file_t file = file_name_lookup (peer_name, O_CREAT|O_NOTRANS, 0666);
- if (file != MACH_PORT_NULL)
- errno = 0;
-
- if (! errno)
- errno = trivfs_create_control (file, peercntlclass, term_bucket,
- peerclass, term_bucket, peercntl);
- if (! errno)
- errno = file_set_translator (file, 0, FS_TRANS_EXCL | FS_TRANS_SET,
- 0, 0, 0,
- ports_get_right (*peercntl),
- MACH_MSG_TYPE_MAKE_SEND);
+ if (file == MACH_PORT_NULL)
+ err = errno;
- if (errno)
+ if (! err)
+ err = trivfs_create_control (file, peercntlclass, term_bucket,
+ peerclass, term_bucket, peercntl);
+ if (! err)
{
- perror (peer_name);
- exit (1);
+ right = ports_get_send_right (*peercntl);
+ err = file_set_translator (file, 0, FS_TRANS_EXCL | FS_TRANS_SET,
+ 0, 0, 0, right, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), right);
}
+ if (err)
+ error (1, err, "%s", peer_name);
+
(*peercntl)->hook = peer_name;
ports_port_deref (*peercntl);
}
- bzero (&termstate, sizeof (termstate));
+ memset (&termstate, 0, sizeof (termstate));
termflags = NO_CARRIER | NO_OWNER;
mutex_init (&global_lock);
- term_owner = term_group = 0;
- term_mode = (bottom == &ptyio_bottom ? 0666 : 0600) | S_IFCHR;
+ /* Initialize status from underlying node. */
+ err = io_stat ((*ourcntl)->underlying, &st);
+ if (err)
+ {
+ /* We cannot stat the underlying node. Fallback to the defaults. */
+ term_owner = term_group = 0;
+ term_mode = (bottom == &ptyio_bottom ? DEFFILEMODE : S_IRUSR | S_IWUSR);
+ }
+ else
+ {
+ term_owner = st.st_uid;
+ term_group = st.st_gid;
+ term_mode = (st.st_mode & ACCESSPERMS);
+ }
+ term_mode |= S_IFCHR | S_IROOT;
- inputq = create_queue (256, 100, 300);
- rawq = create_queue (256, 100, 300);
- outputq = create_queue (256, 100, 300);
-
- if (bottom == &ptyio_bottom)
- ptyio_init ();
+ inputq = create_queue (256, QUEUE_LOWAT, QUEUE_HIWAT);
+
+ rawq = create_queue (256, QUEUE_LOWAT, QUEUE_HIWAT);
+
+ outputq = create_queue (256, QUEUE_LOWAT, QUEUE_HIWAT);
+
+ err = (*bottom->init) ();
+ if (err)
+ error (1, err, "Initializing bottom handler");
condition_init (&carrier_alert);
condition_init (&select_alert);
condition_implies (inputq->wait, &select_alert);
condition_implies (outputq->wait, &select_alert);
- /* Launch */
- ports_manage_port_operations_multithread (term_bucket, demuxer, 0, 0,
- 0, MACH_PORT_NULL);
+ /* Launch. */
+ ports_manage_port_operations_multithread (term_bucket, demuxer, 0, 0, 0);
return 0;
-}
-
+}
diff --git a/term/munge.c b/term/munge.c
index 03ea9106..660a99bd 100644
--- a/term/munge.c
+++ b/term/munge.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1999, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -49,7 +49,11 @@ poutput (int c)
else if (c == '\r')
output_psize = 0;
else if (c == '\t')
- output_psize += (output_psize + 8) % 8;
+ {
+ output_psize++;
+ while (output_psize % 8)
+ output_psize++;
+ }
else if (c == '\b')
output_psize--;
@@ -131,7 +135,7 @@ output_width (int c, int loc)
int n = loc + 1;
while (n % 8)
n++;
- return n;
+ return n - loc;
}
if ((c >= ' ') && (c < '\177'))
return 1;
@@ -229,7 +233,7 @@ echo_char (char c, int hderase, int quoted)
if (echo_double (c, quoted))
{
output_character ('^');
- output_character (c + ('A' - CHAR_SOH));
+ output_character (c ^ CTRL_BIT);
}
else
output_character (c);
@@ -401,8 +405,10 @@ input_character (int c)
else
{
drop_output ();
+ poutput (cc[VDISCARD]);
termflags |= FLUSH_OUTPUT;
}
+ goto alldone;
}
}
@@ -446,13 +452,13 @@ input_character (int c)
{
if (CCEQ (cc[VSTOP], c))
{
- termflags |= USER_OUTPUT_SUSP;
- (*bottom->suspend_physical_output) ();
-
- if (!(CCEQ(cc[VSTART], c))) /* toggle if VSTART == VSTOP */
- /* Alldone code always turns off USER_OUTPUT_SUSP. */
+ if (CCEQ(cc[VSTART], c) && (termflags & USER_OUTPUT_SUSP))
+ /* Toggle if VSTART == VSTOP. Alldone code always turns
+ off USER_OUTPUT_SUSP. */
goto alldone;
+ termflags |= USER_OUTPUT_SUSP;
+ (*bottom->suspend_physical_output) ();
return flush;
}
if (CCEQ (cc[VSTART], c))
@@ -576,7 +582,7 @@ input_character (int c)
echo_char (c, 0, 0);
if (CCEQ (cc[VEOF], c) && (lflag & ECHO))
{
- /* Special bizzare echo processing for VEOF character. */
+ /* Special bizarre echo processing for VEOF character. */
int n;
n = echo_double (c, 0) ? 2 : output_width (c, output_psize);
while (n--)
@@ -636,7 +642,7 @@ input_break ()
enqueue_quote (qp, '\0');
}
-/* Called when a character is recived with a framing error. */
+/* Called when a character is received with a framing error. */
void
input_framing_error (int c)
{
@@ -675,20 +681,24 @@ rescan_inputq ()
n = qsize (inputq);
buf = alloca (n * sizeof (quoted_char));
- bcopy (inputq->cs, buf, n * sizeof (quoted_char));
+ memcpy (buf, inputq->cs, n * sizeof (quoted_char));
clear_queue (inputq);
for (i = 0; i < n; i++)
input_character (unquote_char (buf[i]));
}
-void
+
+error_t
drop_output ()
{
- clear_queue (outputq);
- (*bottom->abandon_physical_output) ();
+ error_t err = (*bottom->abandon_physical_output) ();
+ if (!err)
+ clear_queue (outputq);
+ return err;
}
+
error_t
drain_output ()
{
@@ -709,12 +719,16 @@ create_queue (int size, int lowat, int hiwat)
struct queue *q;
q = malloc (sizeof (struct queue) + size * sizeof (quoted_char));
+ assert (q);
+
q->susp = 0;
q->lowat = lowat;
q->hiwat = hiwat;
q->cs = q->ce = q->array;
q->arraylen = size;
q->wait = malloc (sizeof (struct condition));
+ assert (q->wait);
+
condition_init (q->wait);
return q;
}
diff --git a/term/ptyio.c b/term/ptyio.c
index 22c46407..9c1509ff 100644
--- a/term/ptyio.c
+++ b/term/ptyio.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995, 1996, 1999, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -19,12 +19,12 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <sys/ioctl.h>
-#include <hurd/hurd_types.h>
#include <string.h>
#include <hurd/ports.h>
#include <unistd.h>
#include <fcntl.h>
#include "term.h"
+#include "tioctl_S.h"
/* Set if we need a wakeup when tty output has been done */
static int pty_read_blocked = 0;
@@ -55,22 +55,22 @@ static int ptyopen = 0;
static int nptyperopens = 0;
-void
-ptyio_init ()
+static error_t
+ptyio_init (void)
{
condition_implies (inputq->wait, &pty_select_wakeup);
condition_implies (&pty_read_wakeup, &pty_select_wakeup);
+ return 0;
}
-
+
error_t
pty_open_hook (struct trivfs_control *cntl,
- uid_t *uids, u_int nuids,
- uid_t *gids, u_int ngids,
+ struct iouser *user,
int flags)
{
if ((flags & (O_READ|O_WRITE)) == 0)
return 0;
-
+
mutex_lock (&global_lock);
if (ptyopen)
@@ -78,9 +78,18 @@ pty_open_hook (struct trivfs_control *cntl,
mutex_unlock (&global_lock);
return EBUSY;
}
-
+
ptyopen = 1;
+
+ /* Re-initialize pty state. */
+ external_processing = 0;
+ packet_mode = 0;
+ user_ioctl_mode = 0;
+ control_byte = 0;
+ pktnostop = 0;
+
mutex_unlock (&global_lock);
+
return 0;
}
@@ -129,7 +138,7 @@ wake_reader ()
/* Lower half for tty node */
-static void
+static error_t
ptyio_start_output ()
{
if (packet_mode && output_stopped && (!(termflags & USER_OUTPUT_SUSP)))
@@ -139,9 +148,10 @@ ptyio_start_output ()
output_stopped = 0;
}
wake_reader ();
+ return 0;
}
-static void
+static error_t
ptyio_abandon_physical_output ()
{
if (packet_mode)
@@ -149,9 +159,10 @@ ptyio_abandon_physical_output ()
control_byte |= TIOCPKT_FLUSHWRITE;
wake_reader ();
}
+ return 0;
}
-static void
+static error_t
ptyio_suspend_physical_output ()
{
if (packet_mode)
@@ -161,16 +172,17 @@ ptyio_suspend_physical_output ()
output_stopped = 1;
wake_reader ();
}
+ return 0;
}
-static int
+static int
ptyio_pending_output_size ()
{
/* We don't maintain any pending output buffer separate from the outputq. */
return 0;
}
-static void
+static error_t
ptyio_notice_input_flushed ()
{
if (packet_mode)
@@ -178,76 +190,94 @@ ptyio_notice_input_flushed ()
control_byte |= TIOCPKT_FLUSHREAD;
wake_reader ();
}
+ return 0;
}
-static error_t
+static error_t
ptyio_assert_dtr ()
{
dtr_on = 1;
return 0;
}
-static void
+static error_t
ptyio_desert_dtr ()
{
dtr_on = 0;
wake_reader ();
+ return 0;
}
-static void
-ptyio_set_bits ()
+static error_t
+ptyio_set_bits (struct termios *state)
{
- int stop;
-
- if (packet_mode && external_processing)
+ if (packet_mode)
{
- control_byte |= TIOCPKT_IOCTL;
+ int wakeup = 0;
+ int stop = ((state->c_iflag & IXON)
+ && CCEQ (state->c_cc[VSTOP], CHAR_DC3)
+ && CCEQ (state->c_cc[VSTART], CHAR_DC1));
+
+ if (external_processing)
+ {
+ control_byte |= TIOCPKT_IOCTL;
+ wakeup = 1;
+ }
- stop = ((termstate.c_iflag & IXON)
- && CCEQ (termstate.c_cc[VSTOP], CHAR_DC3)
- && CCEQ (termstate.c_cc[VSTART], CHAR_DC1));
if (pktnostop && stop)
{
pktnostop = 0;
control_byte |= TIOCPKT_DOSTOP;
control_byte &= ~TIOCPKT_NOSTOP;
+ wakeup = 1;
}
else if (!pktnostop && !stop)
{
pktnostop = 1;
control_byte |= TIOCPKT_NOSTOP;
control_byte &= ~TIOCPKT_DOSTOP;
+ wakeup = 1;
}
- wake_reader ();
+ if (wakeup)
+ wake_reader ();
}
+ return 0;
}
/* These do nothing. In BSD the associated ioctls get errors, but
I'd rather just ignore them. */
-static void
+static error_t
ptyio_set_break ()
{
+ return 0;
}
-static void
+static error_t
ptyio_clear_break ()
{
+ return 0;
}
-static void
+static error_t
ptyio_mdmctl (int a, int b)
{
+ return 0;
}
-static int
-ptyio_mdmstate ()
+static error_t
+ptyio_mdmstate (int *state)
{
+ *state = 0;
return 0;
}
-struct bottomhalf ptyio_bottom =
+const struct bottomhalf ptyio_bottom =
{
+ TERM_ON_MASTERPTY,
+ ptyio_init,
+ NULL, /* fini */
+ NULL, /* gwinsz */
ptyio_start_output,
ptyio_set_break,
ptyio_clear_break,
@@ -275,9 +305,9 @@ pty_io_read (struct trivfs_protid *cred,
mach_msg_type_number_t amount)
{
int size;
-
+
mutex_lock (&global_lock);
-
+
if ((cred->po->openmodes & O_READ) == 0)
{
mutex_unlock (&global_lock);
@@ -285,8 +315,14 @@ pty_io_read (struct trivfs_protid *cred,
}
while (!control_byte
+ && (termflags & TTY_OPEN)
&& (!qsize (outputq) || (termflags & USER_OUTPUT_SUSP)))
{
+ if (cred->po->openmodes & O_NONBLOCK)
+ {
+ mutex_unlock (&global_lock);
+ return EWOULDBLOCK;
+ }
pty_read_blocked = 1;
if (hurd_condition_wait (&pty_read_wakeup, &global_lock))
{
@@ -294,7 +330,7 @@ pty_io_read (struct trivfs_protid *cred,
return EINTR;
}
}
-
+
if (control_byte)
{
size = 1;
@@ -307,18 +343,18 @@ pty_io_read (struct trivfs_protid *cred,
if (packet_mode || user_ioctl_mode)
size++;
}
-
+
if (size > amount)
size = amount;
if (size > *datalen)
- vm_allocate (mach_task_self (), (vm_address_t *) data, size, 1);
+ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
*datalen = size;
if (control_byte)
{
**data = control_byte;
if (packet_mode && (control_byte & TIOCPKT_IOCTL))
- bcopy (&termstate, *data + 1, size - 1);
+ memcpy (*data + 1, &termstate, size - 1);
control_byte = 0;
}
else
@@ -338,7 +374,7 @@ pty_io_read (struct trivfs_protid *cred,
return 0;
}
-
+
/* Validation has already been done by trivfs_S_io_write. */
error_t
pty_io_write (struct trivfs_protid *cred,
@@ -350,7 +386,7 @@ pty_io_write (struct trivfs_protid *cred,
int cancel = 0;
mutex_lock (&global_lock);
-
+
if ((cred->po->openmodes & O_WRITE) == 0)
{
mutex_unlock (&global_lock);
@@ -361,7 +397,14 @@ pty_io_write (struct trivfs_protid *cred,
{
/* Wait for the queue to be empty */
while (qsize (inputq) && !cancel)
- cancel = hurd_condition_wait (inputq->wait, &global_lock);
+ {
+ if (cred->po->openmodes & O_NONBLOCK)
+ {
+ mutex_unlock (&global_lock);
+ return EWOULDBLOCK;
+ }
+ cancel = hurd_condition_wait (inputq->wait, &global_lock);
+ }
if (cancel)
{
mutex_unlock (&global_lock);
@@ -370,7 +413,7 @@ pty_io_write (struct trivfs_protid *cred,
for (i = 0; i < datalen; i++)
enqueue (&inputq, data[i]);
-
+
/* Extra garbage charater */
enqueue (&inputq, 0);
}
@@ -398,7 +441,7 @@ pty_io_write (struct trivfs_protid *cred,
/* Validation has already been done by trivfs_S_io_readable */
error_t
-pty_io_readable (int *amt)
+pty_io_readable (size_t *amt)
{
mutex_lock (&global_lock);
if (control_byte)
@@ -416,10 +459,10 @@ pty_io_readable (int *amt)
/* Validation has already been done by trivfs_S_io_select. */
error_t
pty_io_select (struct trivfs_protid *cred, mach_port_t reply,
- int *type, int *idtag)
+ int *type)
{
int avail = 0;
-
+
if (*type == 0)
return 0;
@@ -427,7 +470,8 @@ pty_io_select (struct trivfs_protid *cred, mach_port_t reply,
while (1)
{
- if ((*type & SELECT_READ) && (control_byte || qsize (outputq)))
+ if ((*type & SELECT_READ)
+ && (control_byte || qsize (outputq) || !(termflags & TTY_OPEN)))
avail |= SELECT_READ;
if ((*type & SELECT_URG) && control_byte)
@@ -435,7 +479,7 @@ pty_io_select (struct trivfs_protid *cred, mach_port_t reply,
if ((*type & SELECT_WRITE) && (!remote_input_mode || !qsize (inputq)))
avail |= SELECT_WRITE;
-
+
if (avail)
{
*type = avail;
@@ -463,13 +507,18 @@ S_tioctl_tiocsig (io_t port,
port, pty_class);
if (!cred)
return EOPNOTSUPP;
-
+
+ mutex_lock (&global_lock);
+
drop_output ();
clear_queue (inputq);
clear_queue (rawq);
ptyio_notice_input_flushed ();
send_signal (sig);
+
+ mutex_unlock (&global_lock);
ports_port_deref (cred);
+
return 0;
}
@@ -478,12 +527,14 @@ S_tioctl_tiocpkt (io_t port,
int mode)
{
error_t err;
-
+
struct trivfs_protid *cred = ports_lookup_port (term_bucket,
port, pty_class);
if (!cred)
return EOPNOTSUPP;
-
+
+ mutex_lock (&global_lock);
+
if (!!mode == !!packet_mode)
err = 0;
else if (mode && user_ioctl_mode)
@@ -494,7 +545,10 @@ S_tioctl_tiocpkt (io_t port,
control_byte = 0;
err = 0;
}
+
+ mutex_unlock (&global_lock);
ports_port_deref (cred);
+
return err;
}
@@ -503,12 +557,14 @@ S_tioctl_tiocucntl (io_t port,
int mode)
{
error_t err;
-
+
struct trivfs_protid *cred = ports_lookup_port (term_bucket,
port, pty_class);
if (!cred)
return EOPNOTSUPP;
-
+
+ mutex_lock (&global_lock);
+
if (!!mode == !!user_ioctl_mode)
err = 0;
else if (mode && packet_mode)
@@ -519,7 +575,10 @@ S_tioctl_tiocucntl (io_t port,
control_byte = 0;
err = 0;
}
+
+ mutex_unlock (&global_lock);
ports_port_deref (cred);
+
return err;
}
@@ -529,7 +588,7 @@ S_tioctl_tiocremote (io_t port,
{
struct trivfs_protid *cred = ports_lookup_port (term_bucket,
port, pty_class);
-
+
if (!cred)
return EOPNOTSUPP;
@@ -552,7 +611,7 @@ S_tioctl_tiocext (io_t port,
port, pty_class);
if (!cred)
return EOPNOTSUPP;
-
+
mutex_lock (&global_lock);
if (mode && !external_processing)
{
diff --git a/term/term.h b/term/term.h
index 954fb73c..81d0efee 100644
--- a/term/term.h
+++ b/term/term.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,98,99, 2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -23,7 +23,16 @@
#include <errno.h>
#include <hurd/trivfs.h>
#include <sys/types.h>
+#include <sys/mman.h>
#include <fcntl.h>
+#include <features.h>
+#include <hurd/hurd_types.h>
+
+#ifdef TERM_DEFINE_EI
+#define TERM_EI
+#else
+#define TERM_EI __extern_inline
+#endif
#undef MDMBUF
#undef ECHO
@@ -33,16 +42,26 @@
#undef NOFLSH
#include <termios.h>
-#define CHAR_SOH '\001' /* C-a */
#define CHAR_EOT '\004' /* C-d */
#define CHAR_DC1 '\021' /* C-q */
#define CHAR_DC2 '\022' /* C-r */
#define CHAR_DC3 '\023' /* C-s */
#define CHAR_USER_QUOTE '\377' /* break quoting, etc. */
+/* This bit specifies control */
+#define CTRL_BIT 0x40
+
/* XXX These belong in <termios.h> */
+#ifdef IUCLC
+#define ILCASE IUCLC
+#else
#define ILCASE (1 << 14)
+#endif
+#ifdef OLCUC
+#define OLCASE OLCUC
+#else
#define OLCASE (1 << 9)
+#endif
#define OTILDE (1 << 10)
/* used in mdmctl device call */
@@ -68,6 +87,13 @@ long termflags;
#define NO_OWNER 0x00000200 /* there is no foreground_id */
#define ICKY_ASYNC 0x00000400 /* some user has set O_ASYNC */
+/* Use a high watermark that allows about as much input as once as
+ other operating systems do. Using something just a bit smaller
+ than a power of 2 helps to make maximum use of the buffer and avoid
+ reallocation for just a few bytes. */
+#define QUEUE_LOWAT 200
+#define QUEUE_HIWAT 8100
+
/* Global lock */
struct mutex global_lock;
@@ -101,9 +127,6 @@ struct trivfs_control *termctl;
/* Trivfs control structure for the pty */
struct trivfs_control *ptyctl;
-/* Mach device name for this terminal */
-char *pterm_name;
-
/* The queues we use */
struct queue *inputq, *rawq, *outputq;
@@ -123,25 +146,33 @@ uid_t term_group;
mode_t term_mode;
+/* XXX Including <sys/ioctl.h> or <hurd/ioctl_types.h> leads to "ECHO
+ undeclared" errors in munge.c or users.c. */
+struct winsize;
+
/* Functions a bottom half defines */
struct bottomhalf
{
- void (*start_output) (void);
- void (*set_break) (void);
- void (*clear_break) (void);
- void (*abandon_physical_output) (void);
- void (*suspend_physical_output) (void);
+ enum term_bottom_type type;
+ error_t (*init) (void);
+ error_t (*fini) (void);
+ error_t (*gwinsz) (struct winsize *size);
+ error_t (*start_output) (void);
+ error_t (*set_break) (void);
+ error_t (*clear_break) (void);
+ error_t (*abandon_physical_output) (void);
+ error_t (*suspend_physical_output) (void);
int (*pending_output_size) (void);
- void (*notice_input_flushed) (void);
+ error_t (*notice_input_flushed) (void);
error_t (*assert_dtr) (void);
- void (*desert_dtr) (void);
- void (*set_bits) (void);
- void (*mdmctl) (int, int);
- int (*mdmstate) (void);
+ error_t (*desert_dtr) (void);
+ error_t (*set_bits) (struct termios *state);
+ error_t (*mdmctl) (int how, int bits);
+ error_t (*mdmstate) (int *state);
};
-struct bottomhalf *bottom;
-extern struct bottomhalf devio_bottom, ptyio_bottom;
+const struct bottomhalf *bottom;
+extern const struct bottomhalf devio_bottom, hurdio_bottom, ptyio_bottom;
/* Character queues */
@@ -160,38 +191,53 @@ struct queue
struct queue *create_queue (int size, int lowat, int hiwat);
+extern int qsize (struct queue *q);
+extern int qavail (struct queue *q);
+extern void clear_queue (struct queue *q);
+extern quoted_char dequeue_quote (struct queue *q);
+extern char dequeue (struct queue *q);
+extern void enqueue_internal (struct queue **qp, quoted_char c);
+extern void enqueue (struct queue **qp, char c);
+extern void enqueue_quote (struct queue **qp, char c);
+extern char unquote_char (quoted_char c);
+extern int char_quoted_p (quoted_char c);
+extern short queue_erase (struct queue *q);
+
+#if defined(__USE_EXTERN_INLINES) || defined(TERM_DEFINE_EI)
/* Return the number of characters in Q. */
-extern inline int
+TERM_EI int
qsize (struct queue *q)
{
return q->ce - q->cs;
}
/* Return nonzero if characters can be added to Q. */
-extern inline int
+TERM_EI int
qavail (struct queue *q)
{
return !q->susp;
}
/* Flush all the characters from Q. */
-extern inline int
+TERM_EI void
clear_queue (struct queue *q)
{
q->susp = 0;
q->cs = q->ce = q->array;
condition_broadcast (q->wait);
}
+#endif /* Use extern inlines. */
/* Should be below, but inlines need it. */
void call_asyncs (int dir);
+#if defined(__USE_EXTERN_INLINES) || defined(TERM_DEFINE_EI)
/* Return the next character off Q; leave the quoting bit on. */
-extern inline quoted_char
+TERM_EI quoted_char
dequeue_quote (struct queue *q)
{
int beep = 0;
-
+
assert (qsize (q));
if (q->susp && (qsize (q) < q->lowat))
{
@@ -210,23 +256,25 @@ dequeue_quote (struct queue *q)
}
/* Return the next character off Q. */
-extern inline char
+TERM_EI char
dequeue (struct queue *q)
{
return dequeue_quote (q) & ~QUEUE_QUOTE_MARK;
}
+#endif /* Use extern inlines. */
struct queue *reallocate_queue (struct queue *);
+#if defined(__USE_EXTERN_INLINES) || defined(TERM_DEFINE_EI)
/* Add C to *QP. */
-extern inline void
+TERM_EI void
enqueue_internal (struct queue **qp, quoted_char c)
{
struct queue *q = *qp;
if (q->ce - q->array == q->arraylen)
q = *qp = reallocate_queue (q);
-
+
*q->ce++ = c;
if (qsize (q) == 1)
@@ -241,28 +289,28 @@ enqueue_internal (struct queue **qp, quoted_char c)
}
/* Add C to *QP. */
-extern inline void
+TERM_EI void
enqueue (struct queue **qp, char c)
{
enqueue_internal (qp, c);
}
/* Add C to *QP, marking it with a quote. */
-extern inline void
+TERM_EI void
enqueue_quote (struct queue **qp, char c)
{
enqueue_internal (qp, c | QUEUE_QUOTE_MARK);
-}
+}
/* Return the unquoted version of a quoted_char. */
-extern inline char
+TERM_EI char
unquote_char (quoted_char c)
{
return c & ~QUEUE_QUOTE_MARK;
}
/* Tell if a quoted_char is actually quoted. */
-extern inline int
+TERM_EI int
char_quoted_p (quoted_char c)
{
return c & QUEUE_QUOTE_MARK;
@@ -270,12 +318,12 @@ char_quoted_p (quoted_char c)
/* Remove the most recently enqueue character from Q; leaving
the quote mark on. */
-extern inline short
+TERM_EI short
queue_erase (struct queue *q)
{
short answer;
int beep = 0;
-
+
assert (qsize (q));
answer = *--q->ce;
if (q->susp && (qsize (q) < q->lowat))
@@ -289,16 +337,18 @@ queue_erase (struct queue *q)
condition_broadcast (q->wait);
return answer;
}
+#endif /* Use extern inlines. */
/* Functions devio is supposed to call */
int input_character (int);
void report_carrier_on (void);
void report_carrier_off (void);
+void report_carrier_error (error_t);
/* Other decls */
-void drop_output (void);
+error_t drop_output (void);
void send_signal (int);
error_t drain_output ();
void output_character (int);
@@ -307,18 +357,17 @@ void rescan_inputq (void);
void write_character (int);
void init_users (void);
-/* Call this before using ptyio_bottom. */
-void ptyio_init (void);
+extern char *tty_arg;
+extern dev_t rdev;
/* kludge--these are pty versions of trivfs_S_io_* functions called by
the real functions in users.c to do work for ptys. */
-error_t pty_io_write (struct trivfs_protid *, char *,
+error_t pty_io_write (struct trivfs_protid *, char *,
mach_msg_type_number_t, mach_msg_type_number_t *);
-error_t pty_io_read (struct trivfs_protid *, char **,
+error_t pty_io_read (struct trivfs_protid *, char **,
mach_msg_type_number_t *, mach_msg_type_number_t);
-error_t pty_io_readable (int *);
-error_t pty_io_select (struct trivfs_protid *, mach_port_t, int *, int *);
-error_t pty_open_hook (struct trivfs_control *, uid_t *, u_int, uid_t *,
- u_int, int);
+error_t pty_io_readable (size_t *);
+error_t pty_io_select (struct trivfs_protid *, mach_port_t, int *);
+error_t pty_open_hook (struct trivfs_control *, struct iouser *, int);
error_t pty_po_create_hook (struct trivfs_peropen *);
error_t pty_po_destroy_hook (struct trivfs_peropen *);
diff --git a/term/users.c b/term/users.c
index 5a72b755..4ec2b810 100644
--- a/term/users.c
+++ b/term/users.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1995,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -28,6 +28,9 @@
#include <cthreads.h>
#include <hurd.h>
#include <stdio.h>
+#include <hurd/iohelp.h>
+#include <hurd/fshelp.h>
+#include <error.h>
#include "ourmsg_U.h"
@@ -45,10 +48,10 @@
#define TTYDEFCHARS
#include <sys/ttydefaults.h>
-/* Count of active opens */
+/* Count of active opens. */
int nperopens;
-/* io_async requests */
+/* io_async requests. */
struct async_req
{
mach_port_t notify;
@@ -70,25 +73,26 @@ static int sigs_in_progress;
static struct condition input_sig_wait = CONDITION_INITIALIZER;
static int input_sig_wakeup;
-/* Attach this on the hook of any protid that is a ctty. */
+static error_t carrier_error;
+
+/* Attach this on the hook of any protid that is a ctty. */
struct protid_hook
{
int refcnt;
- pid_t pid, pgrp;
+ pid_t pid, pgrp, sid;
};
void
init_users ()
{
- errno = ports_create_port (cttyid_class, term_bucket,
- sizeof (struct port_info), &cttyid);
- if (errno)
- {
- perror ("Allocating cttyid");
- exit (1);
- }
+ error_t err;
+
+ err = ports_create_port (cttyid_class, term_bucket,
+ sizeof (struct port_info), &cttyid);
+ if (err)
+ error (1, err, "Allocating cttyid");
- mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
&async_icky_id);
/* Add a send right, since hurd_sig_post needs one. */
mach_port_insert_right (mach_task_self (),
@@ -100,19 +104,46 @@ init_users ()
mach_port_insert_right (mach_task_self (),
async_id, async_id, MACH_MSG_TYPE_MAKE_SEND);
}
-
+
+
+static error_t
+check_access_hook (struct trivfs_control *cntl,
+ struct iouser *user,
+ mach_port_t realnode,
+ int *allowed)
+{
+ struct stat st;
+
+ mutex_lock (&global_lock);
+
+ st.st_uid = term_owner;
+ st.st_gid = term_group;
+ st.st_mode = term_mode;
+
+ *allowed = 0;
+ if (fshelp_access (&st, S_IREAD, user) == 0)
+ *allowed |= O_READ;
+ if (fshelp_access (&st, S_IWRITE, user) == 0)
+ *allowed |= O_WRITE;
+
+ mutex_unlock (&global_lock);
+ return 0;
+}
+error_t (*trivfs_check_access_hook) (struct trivfs_control *, struct iouser *,
+ mach_port_t, int *)
+ = check_access_hook;
static error_t
open_hook (struct trivfs_control *cntl,
- uid_t *uids, u_int nuids,
- uid_t *gids, u_int ngids,
+ struct iouser *user,
int flags)
{
+ static int open_count = 0; /* XXX debugging */
int cancel = 0;
error_t err;
-
+
if (cntl == ptyctl)
- return pty_open_hook (cntl, uids, nuids, gids, ngids, flags);
+ return pty_open_hook (cntl, user, flags);
if ((flags & (O_READ|O_WRITE)) == 0)
return 0;
@@ -121,30 +152,40 @@ open_hook (struct trivfs_control *cntl,
if (!(termflags & TTY_OPEN))
{
- bzero (&termstate, sizeof termstate);
+ memset (&termstate, 0, sizeof termstate);
/* This is different from BSD: we don't turn on ISTRIP,
and we use CS8 rather than CS7|PARENB. */
termstate.c_iflag |= BRKINT | ICRNL | IMAXBEL | IXON | IXANY;
termstate.c_oflag |= OPOST | ONLCR | OXTABS;
- termstate.c_lflag |= (ECHO | ICANON | ISIG | IEXTEN
+ termstate.c_lflag |= (ECHO | ICANON | ISIG | IEXTEN
| ECHOE|ECHOKE|ECHOCTL);
termstate.c_cflag |= CREAD | CS8 | HUPCL;
-
- bcopy (ttydefchars, termstate.c_cc, NCCS);
+
+ memcpy (termstate.c_cc, ttydefchars, NCCS);
+
+ memset (&window_size, 0, sizeof window_size);
termflags |= NO_OWNER;
}
- else if (termflags & EXCL_USE)
+ else
{
- mutex_unlock (&global_lock);
- return EBUSY;
+ assert (open_count > 0); /* XXX debugging */
+
+ if (termflags & EXCL_USE)
+ {
+ mutex_unlock (&global_lock);
+ return EBUSY;
+ }
}
- /* Wait for carrier to turn on. */
- while (((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL))
- && !(flags & O_NONBLOCK)
- && !cancel)
+ open_count++; /* XXX debugging */
+
+ /* XXX debugging */
+ assert (! (termstate.c_oflag & OTILDE));
+
+ /* Assert DTR if necessary. */
+ if (termflags & NO_CARRIER)
{
err = (*bottom->assert_dtr) ();
if (err)
@@ -152,30 +193,42 @@ open_hook (struct trivfs_control *cntl,
mutex_unlock (&global_lock);
return err;
}
- cancel = hurd_condition_wait (&carrier_alert, &global_lock);
- }
-
- if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL))
- {
- mutex_unlock (&global_lock);
- return EWOULDBLOCK;
}
+
+ /* Wait for carrier to turn on. */
+ while (((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL))
+ && !(flags & O_NONBLOCK)
+ && !cancel)
+ cancel = hurd_condition_wait (&carrier_alert, &global_lock);
+
if (cancel)
{
mutex_unlock (&global_lock);
return EINTR;
}
-
- termflags |= TTY_OPEN;
- if (!(termstate.c_cflag & CIGNORE))
- (*bottom->set_bits) ();
+ err = carrier_error;
+ carrier_error = 0;
+
+ if (!err)
+ {
+ struct termios state = termstate;
+ err = (*bottom->set_bits) (&state);
+ if (!err)
+ {
+ termstate = state;
+ termflags |= TTY_OPEN;
+ }
+
+ if (bottom->gwinsz)
+ (*bottom->gwinsz) (&window_size);
+ }
mutex_unlock (&global_lock);
- return 0;
+ return err;
}
-error_t (*trivfs_check_open_hook) (struct trivfs_control *, uid_t *,
- u_int, uid_t *, u_int, int)
+error_t (*trivfs_check_open_hook) (struct trivfs_control *,
+ struct iouser *, int)
= open_hook;
static error_t
@@ -183,12 +236,12 @@ pi_create_hook (struct trivfs_protid *cred)
{
if (cred->pi.class == pty_class)
return 0;
-
+
mutex_lock (&global_lock);
if (cred->hook)
((struct protid_hook *)cred->hook)->refcnt++;
mutex_unlock (&global_lock);
-
+
return 0;
}
error_t (*trivfs_protid_create_hook) (struct trivfs_protid *) = pi_create_hook;
@@ -232,7 +285,7 @@ po_create_hook (struct trivfs_peropen *po)
error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *) =
po_create_hook;
-static void
+static void
po_destroy_hook (struct trivfs_peropen *po)
{
if (po->cntl == ptyctl)
@@ -247,7 +300,7 @@ po_destroy_hook (struct trivfs_peropen *po)
termflags &= ~ICKY_ASYNC;
nperopens--;
- if (!nperopens)
+ if (!nperopens && (termflags & TTY_OPEN))
{
/* Empty queues */
clear_queue (inputq);
@@ -255,7 +308,7 @@ po_destroy_hook (struct trivfs_peropen *po)
(*bottom->notice_input_flushed) ();
drain_output ();
-
+
/* Possibly drop carrier */
if ((termstate.c_cflag & HUPCL) || (termflags & NO_CARRIER))
(*bottom->desert_dtr) ();
@@ -265,22 +318,22 @@ po_destroy_hook (struct trivfs_peropen *po)
mutex_unlock (&global_lock);
}
-void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *)
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *)
= po_destroy_hook;
-/* Tell if CRED can do foreground terminal operations */
+/* Tell if CRED can do foreground terminal operations. */
static inline int
fg_p (struct trivfs_protid *cred)
{
struct protid_hook *hook = cred->hook;
-
+
if (!hook || (termflags & NO_OWNER))
return 1;
-
+
if (hook->pid == foreground_id
|| hook->pgrp == -foreground_id)
return 1;
-
+
return 0;
}
@@ -291,13 +344,13 @@ trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
st->st_fstype = FSTYPE_TERM;
st->st_fsid = getpid ();
st->st_ino = 0;
- st->st_mode &= ~S_IFMT;
+ st->st_rdev = rdev;
st->st_mode = term_mode;
st->st_uid = term_owner;
st->st_gid = term_group;
}
-/* Implement term_getctty as described in <hurd/term.defs>. */
+/* Implement term_getctty as described in <hurd/term.defs>. */
kern_return_t
S_term_getctty (mach_port_t arg,
mach_port_t *id,
@@ -306,7 +359,7 @@ S_term_getctty (mach_port_t arg,
struct trivfs_protid *cred = ports_lookup_port (term_bucket,
arg, tty_class);
error_t err;
-
+
if (!cred)
return EOPNOTSUPP;
@@ -325,7 +378,7 @@ S_term_getctty (mach_port_t arg,
return err;
}
-/* Implement termctty_open_terminal as described in <hurd/term.defs>. */
+/* Implement termctty_open_terminal as described in <hurd/term.defs>. */
kern_return_t
S_termctty_open_terminal (mach_port_t arg,
int flags,
@@ -334,6 +387,7 @@ S_termctty_open_terminal (mach_port_t arg,
{
error_t err;
mach_port_t new_realnode;
+ struct iouser *user;
struct trivfs_protid *newcred;
struct port_info *pi = ports_lookup_port (term_bucket, arg, cttyid_class);
@@ -346,7 +400,9 @@ S_termctty_open_terminal (mach_port_t arg,
if (!err)
{
- err = trivfs_open (termctl, 0, 0, 0, 0, flags, new_realnode, &newcred);
+ err = iohelp_create_empty_iouser (&user);
+ if (! err)
+ err = trivfs_open (termctl, user, flags, new_realnode, &newcred);
if (!err)
{
*result = ports_get_right (newcred);
@@ -359,21 +415,27 @@ S_termctty_open_terminal (mach_port_t arg,
return err;
}
-/* Implement term_become_ctty as described in <hurd/term.defs>. */
+/* Implement term_become_ctty as described in <hurd/term.defs>. */
kern_return_t
S_term_open_ctty (mach_port_t arg,
- pid_t pid,
- pid_t pgrp,
- mach_port_t *newpt,
- mach_msg_type_name_t *newpttype)
+ pid_t pid,
+ pid_t pgrp,
+ mach_port_t *newpt,
+ mach_msg_type_name_t *newpttype)
{
error_t err;
struct trivfs_protid *newcred;
struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class);
-
+
if (!cred)
return EOPNOTSUPP;
+ if (pid <= 0 || pgrp <= 0)
+ {
+ ports_port_deref (cred);
+ return EINVAL;
+ }
+
mutex_lock (&global_lock);
if (!cred->po->openmodes & (O_READ|O_WRITE))
@@ -392,10 +454,11 @@ S_term_open_ctty (mach_port_t arg,
hook->pid = pid;
hook->pgrp = pgrp;
+ hook->sid = getsid (pid);
hook->refcnt = 1;
if (newcred->hook)
- /* We inherited CRED's hook, get rid of our ref to it. */
+ /* We inherited CRED's hook, get rid of our ref to it. */
pi_destroy_hook (newcred);
newcred->hook = hook;
@@ -405,14 +468,14 @@ S_term_open_ctty (mach_port_t arg,
ports_port_deref (newcred);
}
}
-
+
ports_port_deref (cred);
return err;
}
/* Implement chown locally; don't pass the value down to the
- underlying node. */
+ underlying node. */
error_t
trivfs_S_file_chown (struct trivfs_protid *cred,
mach_port_t reply,
@@ -420,129 +483,101 @@ trivfs_S_file_chown (struct trivfs_protid *cred,
uid_t uid,
gid_t gid)
{
- int i;
- int noticed_uid;
-
- /* This routine is flawed in several ways; it needs to
- be rewritted once the idvec handling stuff can do
- permission checks. */
+ struct stat st;
+ error_t err;
if (!cred)
return EOPNOTSUPP;
- noticed_uid = 0;
mutex_lock (&global_lock);
- for (i = 0; i < cred->nuids; i++)
+
+ /* XXX */
+ st.st_uid = term_owner;
+ st.st_gid = term_group;
+
+ if (!cred->isroot)
{
- if (cred->uids[i] == uid)
- noticed_uid = 1;
- if (cred->uids[i] == 0 || cred->uids[i] == term_owner)
+ err = fshelp_isowner (&st, cred->user);
+ if (err)
+ goto out;
+
+ if ((uid != (uid_t) -1 && !idvec_contains (cred->user->uids, uid))
+ || (gid != (gid_t) -1 && !idvec_contains (cred->user->gids, gid)))
{
- /* Make sure UID is legitimate */
- if (!cred->isroot && !noticed_uid && term_owner != uid)
- {
- /* Continue scanning UIDS */
- for (i++; i < cred->nuids; i++)
- if (cred->uids[i] == uid)
- noticed_uid = 1;
- if (!noticed_uid)
- {
- mutex_unlock (&global_lock);
- return EPERM;
- }
- }
-
- /* Make sure GID is legitimate */
- for (i = 0; i < cred->ngids || cred->isroot; i++)
- if (cred->isroot || cred->gids[i] == gid)
- {
- /* Make the change */
- term_owner = uid;
- term_group = gid;
- mutex_unlock (&global_lock);
- return 0;
- }
-
- /* Not legitimate */
- break;
+ err = EPERM;
+ goto out;
}
}
+ /* Make the change */
+ if (uid != (uid_t) -1)
+ term_owner = uid;
+ if (gid != (gid_t) -1)
+ term_group = gid;
+ err = 0;
+
+out:
mutex_unlock (&global_lock);
- return EPERM;
+ return err;
}
-/* Implement chmod locally */
+/* Implement chmod locally. */
error_t
trivfs_S_file_chmod (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t reply_type,
mode_t mode)
{
- int i;
-
+ error_t err;
+ struct stat st;
+
if (!cred)
return EOPNOTSUPP;
-
+
mutex_lock (&global_lock);
- for (i = 0; i < cred->nuids; i++)
- if (cred->isroot || cred->uids[i] == term_owner)
- {
- if (!cred->isroot)
- {
- mode &= S_ISVTX;
-
- for (i = 0; i < cred->nuids; i++)
- if (cred->uids[i] == term_owner)
- break;
- if (i == cred->nuids)
- mode &= ~S_ISUID;
-
- for (i = 0; i < cred->ngids; i++)
- if (cred->gids[i] == term_group)
- break;
- if (i == cred->nuids)
- mode &= ~S_ISGID;
- }
-
- term_mode = (mode | S_IFCHR);
- mutex_unlock (&global_lock);
- return 0;
- }
- mutex_unlock (&global_lock);
- return EPERM;
-}
+ if (!cred->isroot)
+ {
+ /* XXX */
+ st.st_uid = term_owner;
+ st.st_gid = term_group;
+ err = fshelp_isowner (&st, cred->user);
+ if (err)
+ goto out;
-error_t
-trivfs_S_file_access (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- int *allowed)
-{
- if (!cred)
- return EOPNOTSUPP;
-
- /* XXX Do the right thing eventually. */
- *allowed = O_READ | O_WRITE;
- return 0;
+ mode &= ~S_ISVTX;
+
+ if (!idvec_contains (cred->user->uids, term_owner))
+ mode &= ~S_ISUID;
+
+ if (!idvec_contains (cred->user->gids, term_group))
+ mode &= ~S_ISUID;
+ }
+
+ term_mode = ((mode & ~S_IFMT & ~S_ITRANS & ~S_ISPARE) | S_IFCHR | S_IROOT);
+ err = 0;
+
+out:
+ mutex_unlock (&global_lock);
+ return err;
}
-/* Called for user writes to the terminal as described
- in <hurd/io.defs>. */
+/* Called for user writes to the terminal as described in
+ <hurd/io.defs>. */
error_t
trivfs_S_io_write (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
char *data,
- u_int datalen,
- off_t offset,
- int *amt)
+ size_t datalen,
+ loff_t offset,
+ size_t *amt)
{
int i;
int cancel;
-
+ error_t err = 0;
+
if (!cred)
return EOPNOTSUPP;
@@ -558,18 +593,18 @@ trivfs_S_io_write (struct trivfs_protid *cred,
mutex_unlock (&global_lock);
return EBADF;
}
-
+
if ((termstate.c_lflag & TOSTOP) && !fg_p (cred))
{
mutex_unlock (&global_lock);
return EBACKGROUND;
}
-
+
if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL))
{
mutex_unlock (&global_lock);
return EIO;
-
+
}
cancel = 0;
@@ -577,9 +612,14 @@ trivfs_S_io_write (struct trivfs_protid *cred,
{
while (!qavail (outputq) && !cancel)
{
- (*bottom->start_output) ();
- if (!qavail (outputq))
- cancel = hurd_condition_wait (outputq->wait, &global_lock);
+ err = (*bottom->start_output) ();
+ if (err)
+ cancel = 1;
+ else
+ {
+ if (!qavail (outputq))
+ cancel = hurd_condition_wait (outputq->wait, &global_lock);
+ }
}
if (cancel)
break;
@@ -589,7 +629,8 @@ trivfs_S_io_write (struct trivfs_protid *cred,
*amt = i;
- (*bottom->start_output) ();
+ if (!err && datalen)
+ (*bottom->start_output) ();
trivfs_set_mtime (termctl);
@@ -597,18 +638,18 @@ trivfs_S_io_write (struct trivfs_protid *cred,
mutex_unlock (&global_lock);
- return ((cancel && datalen && !*amt) ? EINTR : 0);
+ return ((cancel && datalen && !*amt) ? (err ?: EINTR) : 0);
}
-/* Called for user reads from the terminal. */
+/* Called for user reads from the terminal. */
error_t
trivfs_S_io_read (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
char **data,
- u_int *datalen,
- off_t offset,
- int amount)
+ size_t *datalen,
+ loff_t offset,
+ size_t amount)
{
int cancel;
int i, max;
@@ -622,13 +663,13 @@ trivfs_S_io_read (struct trivfs_protid *cred,
return pty_io_read (cred, data, datalen, amount);
mutex_lock (&global_lock);
-
+
if ((cred->po->openmodes & O_READ) == 0)
{
mutex_unlock (&global_lock);
return EBADF;
}
-
+
if (!fg_p (cred))
{
mutex_unlock (&global_lock);
@@ -637,14 +678,14 @@ trivfs_S_io_read (struct trivfs_protid *cred,
while (!qsize (inputq))
{
- if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL))
+ if ((termflags & NO_CARRIER) && !(termstate.c_cflag & CLOCAL) || !amount)
{
/* Return EOF, Posix.1 7.1.1.10. */
mutex_unlock (&global_lock);
*datalen = 0;
return 0;
}
-
+
if (cred->po->openmodes & O_NONBLOCK)
{
mutex_unlock (&global_lock);
@@ -687,14 +728,14 @@ trivfs_S_io_read (struct trivfs_protid *cred,
max = (amount < avail) ? amount : avail;
if (max > *datalen)
- vm_allocate (mach_task_self (), (vm_address_t *)data, max, 1);
-
+ *data = mmap (0, max, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+
cancel = 0;
cp = *data;
for (i = 0; i < max; i++)
{
char c = dequeue (inputq);
-
+
if (remote_input_mode)
*cp++ = c;
else
@@ -703,7 +744,7 @@ trivfs_S_io_read (struct trivfs_protid *cred,
if (!(termstate.c_lflag & ICANON)
|| !CCEQ (termstate.c_cc[VEOF], c))
*cp++ = c;
-
+
/* If this is a break character, then finish now. */
if ((termstate.c_lflag & ICANON)
&& (c == '\n'
@@ -711,14 +752,14 @@ trivfs_S_io_read (struct trivfs_protid *cred,
|| CCEQ (termstate.c_cc[VEOL], c)
|| CCEQ (termstate.c_cc[VEOL2], c)))
break;
-
+
/* If this is the delayed suspend character, then signal now. */
if ((termstate.c_lflag & ISIG)
&& CCEQ (termstate.c_cc[VDSUSP], c))
{
/* The CANCEL flag is being used here to tell the return
below to make sure we don't signal EOF on a VDUSP that
- happens at the front of a line. */
+ happens at the front of a line. */
send_signal (SIGTSTP);
cancel = 1;
break;
@@ -731,7 +772,7 @@ trivfs_S_io_read (struct trivfs_protid *cred,
*datalen = cp - *data;
- /* If we really read something, set atime */
+ /* If we really read something, set atime. */
if (*datalen || !cancel)
trivfs_set_atime (termctl);
@@ -743,10 +784,50 @@ trivfs_S_io_read (struct trivfs_protid *cred,
}
error_t
+trivfs_S_io_pathconf (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int name,
+ int *val)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ switch (name)
+ {
+ case _PC_LINK_MAX:
+ case _PC_NAME_MAX:
+ case _PC_PATH_MAX:
+ case _PC_PIPE_BUF:
+ case _PC_NO_TRUNC:
+ default:
+ return io_pathconf (cred->realnode, name, val);
+
+ case _PC_MAX_CANON:
+ *val = rawq->hiwat;
+ return 0;
+
+ case _PC_MAX_INPUT:
+ *val = inputq->hiwat;
+ return 0;
+
+ case _PC_CHOWN_RESTRICTED:
+ /* We implement this locally, remember... */
+ *val = 1;
+ return 0;
+
+ case _PC_VDISABLE:
+ *val = _POSIX_VDISABLE;
+ return 0;
+ }
+}
+
+
+error_t
trivfs_S_io_readable (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t replytype,
- int *amt)
+ size_t *amt)
{
if (!cred)
return EOPNOTSUPP;
@@ -756,7 +837,10 @@ trivfs_S_io_readable (struct trivfs_protid *cred,
mutex_lock (&global_lock);
if ((cred->po->openmodes & O_READ) == 0)
- return EBADF;
+ {
+ mutex_unlock (&global_lock);
+ return EBADF;
+ }
*amt = qsize (inputq);
if (remote_input_mode && *amt)
--*amt;
@@ -765,12 +849,64 @@ trivfs_S_io_readable (struct trivfs_protid *cred,
return 0;
}
+error_t
+trivfs_S_io_revoke (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype)
+{
+ struct stat st;
+
+ error_t iterator_function (void *port)
+ {
+ struct trivfs_protid *user = port;
+
+ if (user != cred)
+ ports_destroy_right (user);
+ return 0;
+ }
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ if (!cred->isroot)
+ {
+ error_t err;
+
+ /* XXX */
+ st.st_uid = term_owner;
+ st.st_gid = term_group;
+
+ err = fshelp_isowner (&st, cred->user);
+ if (err)
+ {
+ mutex_unlock (&global_lock);
+ return err;
+ }
+ }
+
+ mutex_unlock (&global_lock);
+
+ ports_inhibit_bucket_rpcs (term_bucket);
+ ports_class_iterate (cred->pi.class, iterator_function);
+ ports_resume_bucket_rpcs (term_bucket);
+
+ return 0;
+}
+
+
+
+
+
/* TIOCMODG ioctl -- Get modem state */
kern_return_t
S_tioctl_tiocmodg (io_t port,
int *state)
{
struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0);
+ error_t err = 0;
+
if (!cred)
return EOPNOTSUPP;
@@ -782,11 +918,11 @@ S_tioctl_tiocmodg (io_t port,
}
mutex_lock (&global_lock);
- *state = (*bottom->mdmstate) ();
+ err = (*bottom->mdmstate) (state);
mutex_unlock (&global_lock);
-
+
ports_port_deref (cred);
- return 0;
+ return err;
}
/* TIOCMODS ioctl -- Set modem state */
@@ -811,11 +947,8 @@ S_tioctl_tiocmods (io_t port,
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->mdmctl) (MDMCTL_SET, state);
- err = 0;
- }
-
+ err = (*bottom->mdmctl) (MDMCTL_SET, state);
+
mutex_unlock (&global_lock);
ports_port_deref (cred);
@@ -859,7 +992,7 @@ S_tioctl_tiocnxcl (io_t port)
{
struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0);
error_t err;
-
+
if (!cred)
return EOPNOTSUPP;
@@ -890,8 +1023,8 @@ S_tioctl_tiocflush (io_t port,
int flags)
{
struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0);
+ error_t err = 0;
- error_t err;
if (!cred)
return EOPNOTSUPP;
@@ -903,7 +1036,7 @@ S_tioctl_tiocflush (io_t port,
}
mutex_lock (&global_lock);
-
+
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
@@ -913,21 +1046,19 @@ S_tioctl_tiocflush (io_t port,
if (flags & O_READ)
{
- clear_queue (inputq);
(*bottom->notice_input_flushed) ();
+ clear_queue (inputq);
}
- if (flags & O_WRITE)
- drop_output ();
-
- err = 0;
+ if (!err && (flags & O_WRITE))
+ err = drop_output ();
}
mutex_unlock (&global_lock);
ports_port_deref (cred);
return err;
}
-
+
/* TIOCGETA ioctl -- Get termios state */
kern_return_t
S_tioctl_tiocgeta (io_t port,
@@ -952,7 +1083,7 @@ S_tioctl_tiocgeta (io_t port,
modes[1] = termstate.c_oflag;
modes[2] = termstate.c_cflag;
modes[3] = termstate.c_lflag;
- bcopy (termstate.c_cc, ccs, NCCS);
+ memcpy (ccs, termstate.c_cc, NCCS);
speeds[0] = termstate.__ispeed;
speeds[1] = termstate.__ospeed;
mutex_unlock (&global_lock);
@@ -972,7 +1103,7 @@ set_state (io_t port,
{
struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0);
error_t err;
- int oldlflag;
+ struct termios state;
if (!cred)
return EOPNOTSUPP;
@@ -985,73 +1116,75 @@ set_state (io_t port,
}
mutex_lock (&global_lock);
-
+
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
- err = EBADF;
+ err = EBADF;
else if (!fg_p (cred))
err = EBACKGROUND;
- else
+ else
{
if (cred->pi.class == pty_class)
{
+ err = (*bottom->abandon_physical_output) ();
+ if (err)
+ goto leave;
clear_queue (outputq);
- (*bottom->abandon_physical_output) ();
}
if (draino)
{
err = drain_output ();
if (err)
- {
- mutex_unlock (&global_lock);
- ports_port_deref (cred);
- return err;
- }
+ goto leave;
}
-
+
if (flushi)
{
- clear_queue (inputq);
(*bottom->notice_input_flushed) ();
+ clear_queue (inputq);
}
- oldlflag = termstate.c_lflag;
- termstate.c_iflag = modes[0];
- termstate.c_oflag = modes[1];
- termstate.c_cflag = modes[2];
- termstate.c_lflag = modes[3];
- bcopy (ccs, termstate.c_cc, NCCS);
- termstate.__ispeed = speeds[0];
- termstate.__ospeed = speeds[1];
+ state = termstate;
+ state.c_iflag = modes[0];
+ state.c_oflag = modes[1];
+ state.c_cflag = modes[2];
+ state.c_lflag = modes[3];
+ memcpy (state.c_cc, ccs, NCCS);
+ state.__ispeed = speeds[0];
+ state.__ospeed = speeds[1];
if (external_processing)
- termstate.c_lflag |= EXTPROC;
+ state.c_lflag |= EXTPROC;
else
- termstate.c_lflag &= ~EXTPROC;
+ state.c_lflag &= ~EXTPROC;
- if (external_processing || !(termstate.c_cflag & CIGNORE))
- (*bottom->set_bits) ();
- if (oldlflag & ICANON)
- {
- if (!(termstate.c_lflag & ICANON))
- copy_rawq ();
- }
- else
+ err = (*bottom->set_bits) (&state);
+ if (!err)
{
- if (termstate.c_lflag & ICANON)
- rescan_inputq ();
+ int oldlflag = termstate.c_lflag;
+
+ termstate = state;
+ if (oldlflag & ICANON)
+ {
+ if (!(termstate.c_lflag & ICANON))
+ copy_rawq ();
+ }
+ else
+ {
+ if (termstate.c_lflag & ICANON)
+ rescan_inputq ();
+ }
}
err = 0;
}
-
- mutex_unlock (&global_lock);
+ leave:
+ mutex_unlock (&global_lock);
ports_port_deref (cred);
return err;
}
-
/* TIOCSETA -- Set termios state */
kern_return_t
S_tioctl_tiocseta (io_t port,
@@ -1128,7 +1261,7 @@ S_tioctl_tiocsetd (io_t port,
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
mutex_unlock (&global_lock);
-
+
if (disc != 0)
err = ENXIO;
else
@@ -1144,7 +1277,7 @@ S_tioctl_tiocdrain (io_t port)
{
struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0);
error_t err;
-
+
if (!cred)
return EOPNOTSUPP;
@@ -1162,7 +1295,7 @@ S_tioctl_tiocdrain (io_t port)
ports_port_deref (cred);
return EBADF;
}
-
+
err = drain_output ();
mutex_unlock (&global_lock);
ports_port_deref (cred);
@@ -1187,9 +1320,8 @@ S_tioctl_tiocswinsz (io_t port,
return EOPNOTSUPP;
}
-
mutex_lock (&global_lock);
-
+
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
@@ -1197,10 +1329,11 @@ S_tioctl_tiocswinsz (io_t port,
ports_port_deref (cred);
- if (!err && (size.ws_row - window_size.ws_row +
- size.ws_col - window_size.ws_col +
- size.ws_xpixel - window_size.ws_xpixel +
- size.ws_ypixel - window_size.ws_ypixel) != 0)
+ if (! err
+ && (size.ws_row != window_size.ws_row
+ || size.ws_col != window_size.ws_col
+ || size.ws_xpixel != window_size.ws_xpixel
+ || size.ws_ypixel != window_size.ws_ypixel))
{
/* The size is actually changing. Record the new size and notify the
process group. */
@@ -1212,7 +1345,7 @@ S_tioctl_tiocswinsz (io_t port,
return err;
}
-/* TIOCGWINSZ -- Fetch window size */
+/* TIOCGWINSZ -- Fetch window size */
kern_return_t
S_tioctl_tiocgwinsz (io_t port,
struct winsize *size)
@@ -1243,6 +1376,7 @@ S_tioctl_tiocmget (io_t port,
int *bits)
{
struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0);
+ error_t err = 0;
if (!cred)
return EOPNOTSUPP;
@@ -1255,13 +1389,13 @@ S_tioctl_tiocmget (io_t port,
}
mutex_lock (&global_lock);
- *bits = (*bottom->mdmstate) ();
+ err = (*bottom->mdmstate) (bits);
mutex_unlock (&global_lock);
-
+
ports_port_deref (cred);
- return 0;
+ return err;
}
-
+
/* TIOCMSET -- Set all modem bits */
kern_return_t
S_tioctl_tiocmset (io_t port,
@@ -1284,16 +1418,13 @@ S_tioctl_tiocmset (io_t port,
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->mdmctl) (MDMCTL_SET, bits);
- err = 0;
- }
-
+ err = (*bottom->mdmctl) (MDMCTL_SET, bits);
+
mutex_unlock (&global_lock);
ports_port_deref (cred);
return err;
}
-
+
/* TIOCMBIC -- Clear some modem bits */
kern_return_t
S_tioctl_tiocmbic (io_t port,
@@ -1316,10 +1447,7 @@ S_tioctl_tiocmbic (io_t port,
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->mdmctl) (MDMCTL_BIC, bits);
- err = 0;
- }
+ err = (*bottom->mdmctl) (MDMCTL_BIC, bits);
mutex_unlock (&global_lock);
ports_port_deref (cred);
@@ -1349,10 +1477,7 @@ S_tioctl_tiocmbis (io_t port,
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->mdmctl) (MDMCTL_BIS, bits);
- err = 0;
- }
+ err = (*bottom->mdmctl) (MDMCTL_BIS, bits);
mutex_unlock (&global_lock);
ports_port_deref (cred);
return err;
@@ -1381,9 +1506,12 @@ S_tioctl_tiocstart (io_t port)
err = EBADF;
else
{
+ int old_termflags = termflags;
+
termflags &= ~USER_OUTPUT_SUSP;
- (*bottom->start_output) ();
- err = 0;
+ err = (*bottom->start_output) ();
+ if (err)
+ termflags = old_termflags;
}
mutex_unlock (&global_lock);
@@ -1408,21 +1536,23 @@ S_tioctl_tiocstop (io_t port)
return EOPNOTSUPP;
}
mutex_lock (&global_lock);
-
+
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
{
+ int old_termflags = termflags;
termflags |= USER_OUTPUT_SUSP;
- (*bottom->suspend_physical_output) ();
- err = 0;
+ err = (*bottom->suspend_physical_output) ();
+ if (err)
+ termflags = old_termflags;
}
mutex_unlock (&global_lock);
-
+
ports_port_deref (cred);
return err;
}
-
+
/* TIOCSTI -- Simulate terminal input */
kern_return_t
S_tioctl_tiocsti (io_t port,
@@ -1455,7 +1585,7 @@ S_tioctl_tiocsti (io_t port,
err = 0;
}
mutex_unlock (&global_lock);
-
+
ports_port_deref (cred);
return err;
}
@@ -1488,7 +1618,7 @@ S_tioctl_tiocoutq (io_t port,
err = 0;
}
mutex_unlock (&global_lock);
-
+
ports_port_deref (cred);
return err;
}
@@ -1521,11 +1651,11 @@ S_tioctl_tiocspgrp (io_t port,
err = 0;
}
mutex_unlock (&global_lock);
-
+
ports_port_deref (cred);
return err;
}
-
+
/* TIOCGPGRP --- fetch pgrp of terminal */
kern_return_t
S_tioctl_tiocgpgrp (io_t port,
@@ -1579,16 +1709,13 @@ S_tioctl_tioccdtr (io_t port)
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->mdmctl) (MDMCTL_BIC, TIOCM_DTR);
- err = 0;
- }
+ err = (*bottom->mdmctl) (MDMCTL_BIC, TIOCM_DTR);
mutex_unlock (&global_lock);
ports_port_deref (cred);
return err;
}
-
+
/* TIOCSDTR -- set DTR */
kern_return_t
S_tioctl_tiocsdtr (io_t port)
@@ -1610,10 +1737,7 @@ S_tioctl_tiocsdtr (io_t port)
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->mdmctl) (MDMCTL_BIS, TIOCM_DTR);
- err = 0;
- }
+ err = (*bottom->mdmctl) (MDMCTL_BIS, TIOCM_DTR);
mutex_unlock (&global_lock);
ports_port_deref (cred);
@@ -1641,10 +1765,7 @@ S_tioctl_tioccbrk (io_t port)
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->clear_break) ();
- err = 0;
- }
+ err = (*bottom->clear_break) ();
mutex_unlock (&global_lock);
ports_port_deref (cred);
@@ -1672,10 +1793,7 @@ S_tioctl_tiocsbrk (io_t port)
if (!(cred->po->openmodes & (O_READ|O_WRITE)))
err = EBADF;
else
- {
- (*bottom->set_break) ();
- err = 0;
- }
+ err = (*bottom->set_break) ();
mutex_unlock (&global_lock);
ports_port_deref (cred);
@@ -1781,7 +1899,7 @@ trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
mutex_unlock (&global_lock);
return 0;
}
-
+
error_t
trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
mach_port_t reply,
@@ -1887,57 +2005,50 @@ error_t
trivfs_S_io_select (struct trivfs_protid *cred,
mach_port_t reply,
mach_msg_type_name_t reply_type,
- int *type,
- int *idtag)
+ int *type)
{
- int available;
-
if (!cred)
return EOPNOTSUPP;
if (cred->pi.class == pty_class)
- return pty_io_select (cred, reply, type, idtag);
+ return pty_io_select (cred, reply, type);
- /* We don't deal with SELECT_URG here. */
- if (*type & ~(SELECT_READ | SELECT_WRITE))
- return EINVAL;
-
- available = 0;
- if (*type == 0)
- return 0;
+ if ((cred->po->openmodes & O_READ) == 0)
+ *type &= ~SELECT_READ;
+ if ((cred->po->openmodes & O_WRITE) == 0)
+ *type &= ~SELECT_WRITE;
mutex_lock (&global_lock);
-
+
while (1)
{
+ int available = 0;
if ((*type & SELECT_READ) && qsize (inputq))
available |= SELECT_READ;
if ((*type & SELECT_WRITE) && qavail (outputq))
available |= SELECT_WRITE;
- if (available)
+ if (available == 0)
{
- *type = available;
- mutex_unlock (&global_lock);
- return 0;
+ ports_interrupt_self_on_port_death (cred, reply);
+ if (hurd_condition_wait (&select_alert, &global_lock) == 0)
+ continue;
}
- ports_interrupt_self_on_port_death (cred, reply);
- if (hurd_condition_wait (&select_alert, &global_lock))
- {
- *type = 0;
- mutex_unlock (&global_lock);
- return EINTR;
- }
+ *type = available;
+ mutex_unlock (&global_lock);
+ return available ? 0 : EINTR;
}
}
kern_return_t
-trivfs_S_io_map (struct trivfs_protid *cred,
- mach_port_t *rdobj,
- mach_msg_type_name_t *rdtype,
- mach_port_t *wrobj,
- mach_msg_type_name_t *wrtype)
+trivfs_S_io_map (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replyPoly,
+ mach_port_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ mach_port_t *wrobj,
+ mach_msg_type_name_t *wrtype)
{
return EOPNOTSUPP;
}
@@ -1976,7 +2087,7 @@ call_asyncs (int dir)
&& (!(dir & O_WRITE) && qavail (outputq) == 0))
/* Output isn't possible in the desired directions. */
return;
-
+
if ((termflags & ICKY_ASYNC) && !(termflags & NO_OWNER))
{
report_sig_start ();
@@ -1985,7 +2096,7 @@ call_asyncs (int dir)
mutex_lock (&global_lock);
report_sig_end ();
}
-
+
for (ar = async_requests, prevp = &async_requests;
ar;
ar = nxt)
@@ -2012,9 +2123,7 @@ send_signal (int signo)
if (!(termflags & NO_OWNER))
{
- right = ports_get_right (cttyid);
- mach_port_insert_right (mach_task_self (), right, right,
- MACH_MSG_TYPE_MAKE_SEND);
+ right = ports_get_send_right (cttyid);
report_sig_start ();
mutex_unlock (&global_lock);
hurd_sig_post (foreground_id, signo, right);
@@ -2042,6 +2151,13 @@ report_carrier_on ()
condition_broadcast (&carrier_alert);
}
+void
+report_carrier_error (error_t err)
+{
+ carrier_error = err;
+ condition_broadcast (&carrier_alert);
+}
+
kern_return_t
S_term_get_nodename (io_t arg,
char *name)
@@ -2050,8 +2166,14 @@ S_term_get_nodename (io_t arg,
tty_class);
if (!cred)
return EOPNOTSUPP;
-
- strcpy (name, (char *)cred->po->cntl->hook ?: "");
+
+ if (!cred->po->cntl->hook)
+ {
+ ports_port_deref (cred);
+ return ENOENT;
+ }
+
+ strcpy (name, (char *)cred->po->cntl->hook);
ports_port_deref (cred);
return 0;
@@ -2065,10 +2187,10 @@ S_term_set_nodename (io_t arg,
struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, tty_class);
if (!cred)
return EOPNOTSUPP;
-
+
if (strcmp (name, (char *)cred->po->cntl->hook) != 0)
err = EINVAL;
-
+
ports_port_deref (cred);
return err;
}
@@ -2077,7 +2199,7 @@ kern_return_t
S_term_set_filenode (io_t arg,
file_t filenode)
{
- struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
tty_class);
if (!cred)
return EOPNOTSUPP;
@@ -2087,19 +2209,44 @@ S_term_set_filenode (io_t arg,
}
kern_return_t
+S_term_get_peername (io_t arg,
+ char *name)
+{
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg, 0);
+ struct trivfs_control *peer;
+
+ if (!cred || (cred->pi.class != tty_class && cred->pi.class != pty_class))
+ {
+ if (cred)
+ ports_port_deref (cred);
+ return EOPNOTSUPP;
+ }
+
+ peer = (cred->pi.class == tty_class) ? ptyctl : termctl;
+
+ if (bottom != &ptyio_bottom || !peer->hook)
+ {
+ ports_port_deref (cred);
+ return ENOENT;
+ }
+
+ strcpy (name, (char *) peer->hook);
+ ports_port_deref (cred);
+
+ return 0;
+}
+
+kern_return_t
S_term_get_bottom_type (io_t arg,
int *ttype)
{
- struct trivfs_protid *cred = ports_lookup_port (term_bucket,
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket,
arg, tty_class);
if (!cred)
return EOPNOTSUPP;
ports_port_deref (cred);
- if (bottom == &devio_bottom)
- *ttype = TERM_ON_MACHDEV;
- else
- *ttype = TERM_ON_MASTERPTY;
+ *ttype = bottom->type;
return 0;
}
@@ -2107,7 +2254,7 @@ kern_return_t
S_term_on_machdev (io_t arg,
device_t machdev)
{
- struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
+ struct trivfs_protid *cred = ports_lookup_port (term_bucket, arg,
tty_class);
if (!cred)
return EOPNOTSUPP;
diff --git a/term/xinl.c b/term/xinl.c
new file mode 100644
index 00000000..3695faa5
--- /dev/null
+++ b/term/xinl.c
@@ -0,0 +1,2 @@
+#define TERM_DEFINE_EI
+#include "term.h"
diff --git a/tmpfs/Makefile b/tmpfs/Makefile
new file mode 100644
index 00000000..18293771
--- /dev/null
+++ b/tmpfs/Makefile
@@ -0,0 +1,29 @@
+# Makefile for tmpfs
+#
+# Copyright (C) 2000,01,02 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 := tmpfs
+makemode := server
+
+target = tmpfs
+SRCS = tmpfs.c node.c dir.c pager-stubs.c
+OBJS = $(SRCS:.c=.o) default_pagerUser.o
+LCLHDRS = tmpfs.h
+# XXX The shared libdiskfs requires libstore even though we don't use it here.
+HURDLIBS = diskfs pager iohelp fshelp store threads ports ihash shouldbeinlibc
+
+include ../Makeconf
diff --git a/tmpfs/dir.c b/tmpfs/dir.c
new file mode 100644
index 00000000..4a0a60b5
--- /dev/null
+++ b/tmpfs/dir.c
@@ -0,0 +1,307 @@
+/* Directories for tmpfs.
+ Copyright (C) 2000,01,02 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "tmpfs.h"
+#include <stdlib.h>
+
+error_t
+diskfs_init_dir (struct node *dp, struct node *pdp, struct protid *cred)
+{
+ dp->dn->u.dir.dotdot = pdp->dn;
+ dp->dn->u.dir.entries = 0;
+
+ /* Increase hardlink count for parent directory */
+ pdp->dn_stat.st_nlink++;
+ /* Take '.' directory into account */
+ dp->dn_stat.st_nlink++;
+
+ return 0;
+}
+
+error_t
+diskfs_clear_directory (struct node *dp, struct node *pdp,
+ struct protid *cred)
+{
+ if (dp->dn->u.dir.entries != 0)
+ return ENOTEMPTY;
+ assert (dp->dn_stat.st_size == 0);
+ assert (dp->dn->u.dir.dotdot == pdp->dn);
+
+ /* Decrease hardlink count for parent directory */
+ pdp->dn_stat.st_nlink--;
+ /* Take '.' directory into account */
+ dp->dn_stat.st_nlink--;
+
+ return 0;
+}
+
+int
+diskfs_dirempty (struct node *dp, struct protid *cred)
+{
+ return dp->dn->u.dir.entries == 0;
+}
+
+error_t
+diskfs_get_directs (struct node *dp, int entry, int n,
+ char **data, size_t *datacnt,
+ vm_size_t bufsiz, int *amt)
+{
+ struct tmpfs_dirent *d;
+ struct dirent *entp;
+ int i;
+
+ if (bufsiz == 0)
+ bufsiz = dp->dn_stat.st_size
+ + 2 * ((offsetof (struct dirent, d_name[3]) + 7) & ~7);
+ if (bufsiz > *datacnt)
+ {
+ *data = mmap (0, bufsiz, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ return ENOMEM;
+ }
+
+ /* We always synthesize the first two entries (. and ..) on the fly. */
+ entp = (struct dirent *) *data;
+ i = 0;
+ if (i++ >= entry)
+ {
+ entp->d_fileno = dp->dn_stat.st_ino;
+ entp->d_type = DT_DIR;
+ entp->d_namlen = 1;
+ entp->d_name[0] = '.';
+ entp->d_name[1] = '\0';
+ entp->d_reclen = (&entp->d_name[2] - (char *) entp + 7) & ~7;
+ entp = (void *) entp + entp->d_reclen;
+ }
+ if (i++ >= entry)
+ {
+ if (dp->dn->u.dir.dotdot == 0)
+ {
+ assert (dp == diskfs_root_node);
+ /* Use something not zero and not an st_ino value for any node in
+ this filesystem. Since we use pointer values, 2 will never
+ be a valid number. */
+ entp->d_fileno = 2;
+ }
+ else
+ entp->d_fileno = (ino_t) (uintptr_t) dp->dn->u.dir.dotdot;
+ entp->d_type = DT_DIR;
+ entp->d_namlen = 2;
+ entp->d_name[0] = '.';
+ entp->d_name[1] = '.';
+ entp->d_name[2] = '\0';
+ entp->d_reclen = (&entp->d_name[3] - (char *) entp + 7) & ~7;
+ entp = (void *) entp + entp->d_reclen;
+ }
+
+ /* Skip ahead to the desired entry. */
+ for (d = dp->dn->u.dir.entries; i < entry && d != 0; d = d->next)
+ ++i;
+
+ if (i < entry)
+ {
+ assert (d == 0);
+ *datacnt = 0;
+ *amt = 0;
+ return 0;
+ }
+
+ /* Now fill in the buffer with real entries. */
+ for (; d != 0; d = d->next, i++)
+ {
+ size_t rlen = (offsetof (struct dirent, d_name[1]) + d->namelen + 7) & ~7;
+ if (rlen + (char *) entp - *data > bufsiz || (n >= 0 && i > n))
+ break;
+ entp->d_fileno = (ino_t) (uintptr_t) d->dn;
+ entp->d_type = DT_UNKNOWN;
+ entp->d_namlen = d->namelen;
+ memcpy (entp->d_name, d->name, d->namelen + 1);
+ entp->d_reclen = rlen;
+ entp = (void *) entp + rlen;
+ }
+
+ *datacnt = (char *) entp - *data;
+ *amt = i - entry;
+
+ return 0;
+}
+
+
+struct dirstat
+{
+ struct tmpfs_dirent **prevp;
+};
+const size_t diskfs_dirstat_size = sizeof (struct dirstat);
+
+void
+diskfs_null_dirstat (struct dirstat *ds)
+{
+ ds->prevp = 0;
+}
+
+error_t
+diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
+{
+ /* No need to clear the pointers. */
+ return 0;
+}
+
+error_t
+diskfs_lookup_hard (struct node *dp,
+ const char *name, enum lookup_type type,
+ struct node **np, struct dirstat *ds,
+ struct protid *cred)
+{
+ const size_t namelen = strlen (name);
+ struct tmpfs_dirent *d, **prevp;
+
+ if (type == REMOVE || type == RENAME)
+ assert (np);
+
+ if (namelen == 1 && name[0] == '.')
+ {
+ if (np != 0)
+ {
+ *np = dp;
+ diskfs_nref (dp);
+ }
+ return 0;
+ }
+ if (namelen == 2 && name[0] == '.' && name[1] == '.')
+ {
+ struct disknode *dddn = dp->dn->u.dir.dotdot;
+ error_t err;
+
+ assert (np != 0);
+ if (dddn == 0) /* root directory */
+ return EAGAIN;
+
+ if (type == (REMOVE|SPEC_DOTDOT) || type == (RENAME|SPEC_DOTDOT))
+ {
+ *np = *dddn->hprevp;
+ assert (*np);
+ assert ((*np)->dn == dddn);
+ assert (*dddn->hprevp == *np);
+ return 0;
+ }
+ else
+ {
+ mutex_unlock (&dp->lock);
+ err = diskfs_cached_lookup ((ino_t) (intptr_t) dddn, np);
+
+ if (type == (LOOKUP|SPEC_DOTDOT))
+ diskfs_nrele (dp);
+ else
+ mutex_lock (&dp->lock);
+
+ if (err)
+ *np = 0;
+
+ return err;
+ }
+ }
+
+ for (d = *(prevp = &dp->dn->u.dir.entries); d != 0;
+ d = *(prevp = &d->next))
+ if (d->namelen == namelen && !memcmp (d->name, name, namelen))
+ {
+ if (ds)
+ ds->prevp = prevp;
+
+ if (np)
+ return diskfs_cached_lookup ((ino_t) (uintptr_t) d->dn, np);
+ else
+ return 0;
+ }
+
+ if (ds)
+ ds->prevp = prevp;
+ if (np)
+ *np = 0;
+ return ENOENT;
+}
+
+
+error_t
+diskfs_direnter_hard (struct node *dp, const char *name,
+ struct node *np, struct dirstat *ds,
+ struct protid *cred)
+{
+ const size_t namelen = strlen (name);
+ const size_t entsize
+ = (offsetof (struct dirent, d_name[1]) + namelen + 7) & ~7;
+ struct tmpfs_dirent *new;
+
+ if (round_page (tmpfs_space_used + entsize) / vm_page_size
+ > tmpfs_page_limit)
+ return ENOSPC;
+
+ new = malloc (offsetof (struct tmpfs_dirent, name) + namelen + 1);
+ if (new == 0)
+ return ENOSPC;
+
+ new->next = 0;
+ new->dn = np->dn;
+ new->namelen = namelen;
+ memcpy (new->name, name, namelen + 1);
+ *ds->prevp = new;
+
+ dp->dn_stat.st_size += entsize;
+ adjust_used (entsize);
+
+ dp->dn_stat.st_blocks = ((sizeof *dp->dn + dp->dn->translen
+ + dp->dn_stat.st_size + 511)
+ / 512);
+ return 0;
+}
+
+error_t
+diskfs_dirrewrite_hard (struct node *dp, struct node *np,
+ struct dirstat *ds)
+{
+ (*ds->prevp)->dn = np->dn;
+ return 0;
+}
+
+error_t
+diskfs_dirremove_hard (struct node *dp, struct dirstat *ds)
+{
+ struct tmpfs_dirent *d = *ds->prevp;
+ const size_t entsize
+ = (offsetof (struct dirent, d_name[1]) + d->namelen + 7) & ~7;
+
+ *ds->prevp = d->next;
+
+ if (dp->dirmod_reqs != 0)
+ diskfs_notice_dirchange (dp, DIR_CHANGED_UNLINK, d->name);
+
+ free (d);
+
+ adjust_used (-entsize);
+ dp->dn_stat.st_size -= entsize;
+ dp->dn_stat.st_blocks = ((sizeof *dp->dn + dp->dn->translen
+ + dp->dn_stat.st_size + 511)
+ / 512);
+
+ return 0;
+}
diff --git a/tmpfs/node.c b/tmpfs/node.c
new file mode 100644
index 00000000..bce15370
--- /dev/null
+++ b/tmpfs/node.c
@@ -0,0 +1,590 @@
+/* Node state and file contents for tmpfs.
+ Copyright (C) 2000,01,02 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "tmpfs.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <hurd/hurd_types.h>
+#include <hurd/store.h>
+#include "default_pager_U.h"
+
+unsigned int num_files;
+static unsigned int gen;
+
+struct node *all_nodes;
+
+error_t
+diskfs_alloc_node (struct node *dp, mode_t mode, struct node **npp)
+{
+ struct disknode *dn;
+
+ dn = calloc (1, sizeof *dn);
+ if (dn == 0)
+ return ENOSPC;
+ spin_lock (&diskfs_node_refcnt_lock);
+ if (round_page (tmpfs_space_used + sizeof *dn) / vm_page_size
+ > tmpfs_page_limit)
+ {
+ spin_unlock (&diskfs_node_refcnt_lock);
+ free (dn);
+ return ENOSPC;
+ }
+ dn->gen = gen++;
+ ++num_files;
+ tmpfs_space_used += sizeof *dn;
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ dn->type = IFTODT (mode & S_IFMT);
+ return diskfs_cached_lookup ((ino_t) (uintptr_t) dn, npp);
+}
+
+void
+diskfs_free_node (struct node *np, mode_t mode)
+{
+ switch (np->dn->type)
+ {
+ case DT_REG:
+ if (np->dn->u.reg.memobj != MACH_PORT_NULL) {
+ vm_deallocate (mach_task_self (), np->dn->u.reg.memref, 4096);
+ mach_port_deallocate (mach_task_self (), np->dn->u.reg.memobj);
+ }
+ break;
+ case DT_DIR:
+ assert (np->dn->u.dir.entries == 0);
+ break;
+ case DT_LNK:
+ free (np->dn->u.lnk);
+ break;
+ }
+ *np->dn->hprevp = np->dn->hnext;
+ if (np->dn->hnext != 0)
+ np->dn->hnext->dn->hprevp = np->dn->hprevp;
+ free (np->dn);
+ np->dn = 0;
+
+ --num_files;
+ tmpfs_space_used -= sizeof *np->dn;
+}
+
+void
+diskfs_node_norefs (struct node *np)
+{
+ if (np->dn != 0)
+ {
+ /* We don't bother to do this in diskfs_write_disknode, since it only
+ ever matters here. The node state goes back into the `struct
+ disknode' while it has no associated diskfs node. */
+
+ np->dn->size = np->dn_stat.st_size;
+ np->dn->mode = np->dn_stat.st_mode;
+ np->dn->nlink = np->dn_stat.st_nlink;
+ np->dn->uid = np->dn_stat.st_uid;
+ np->dn->author = np->dn_stat.st_author;
+ np->dn->gid = np->dn_stat.st_gid;
+ np->dn->atime = np->dn_stat.st_atim;
+ np->dn->mtime = np->dn_stat.st_mtim;
+ np->dn->ctime = np->dn_stat.st_ctim;
+ np->dn->flags = np->dn_stat.st_flags;
+
+ switch (np->dn->type)
+ {
+ case DT_REG:
+ assert (np->allocsize % vm_page_size == 0);
+ np->dn->u.reg.allocpages = np->allocsize / vm_page_size;
+ break;
+ case DT_CHR:
+ case DT_BLK:
+ np->dn->u.chr = np->dn_stat.st_rdev;
+ break;
+ }
+
+ /* Remove this node from the cache list rooted at `all_nodes'. */
+ *np->dn->hprevp = np->dn->hnext;
+ if (np->dn->hnext != 0)
+ np->dn->hnext->dn->hprevp = np->dn->hprevp;
+ np->dn->hnext = 0;
+ np->dn->hprevp = 0;
+ }
+
+ free (np);
+}
+
+static void
+recompute_blocks (struct node *np)
+{
+ struct disknode *const dn = np->dn;
+ struct stat *const st = &np->dn_stat;
+
+ st->st_blocks = sizeof *dn + dn->translen;
+ switch (dn->type)
+ {
+ case DT_REG:
+ np->allocsize = dn->u.reg.allocpages * vm_page_size;
+ st->st_blocks += np->allocsize;
+ break;
+ case DT_LNK:
+ st->st_blocks += st->st_size + 1;
+ break;
+ case DT_CHR:
+ case DT_BLK:
+ st->st_rdev = dn->u.chr;
+ break;
+ case DT_DIR:
+ st->st_blocks += dn->size;
+ break;
+ }
+ st->st_blocks = (st->st_blocks + 511) / 512;
+}
+
+/* Fetch inode INUM, set *NPP to the node structure;
+ gain one user reference and lock the node. */
+error_t
+diskfs_cached_lookup (ino_t inum, struct node **npp)
+{
+ struct disknode *dn = (void *) (uintptr_t) inum;
+ struct node *np;
+
+ assert (npp);
+
+ if (dn->hprevp != 0) /* There is already a node. */
+ {
+ np = *dn->hprevp;
+ assert (np->dn == dn);
+ assert (*dn->hprevp == np);
+
+ diskfs_nref (np);
+ }
+ else
+ /* Create the new node. */
+ {
+ struct stat *st;
+
+ np = diskfs_make_node (dn);
+ np->cache_id = (ino_t) (uintptr_t) dn;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+ dn->hnext = all_nodes;
+ if (dn->hnext)
+ dn->hnext->dn->hprevp = &dn->hnext;
+ dn->hprevp = &all_nodes;
+ all_nodes = np;
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ st = &np->dn_stat;
+ memset (st, 0, sizeof *st);
+ st->st_fstype = FSTYPE_MEMFS;
+ st->st_fsid = getpid ();
+ st->st_blksize = vm_page_size;
+
+ st->st_ino = (ino_t) (uintptr_t) dn;
+ st->st_gen = dn->gen;
+
+ st->st_size = dn->size;
+ st->st_mode = dn->mode;
+ st->st_nlink = dn->nlink;
+ st->st_uid = dn->uid;
+ st->st_author = dn->author;
+ st->st_gid = dn->gid;
+ st->st_atim = dn->atime;
+ st->st_mtim = dn->mtime;
+ st->st_ctim = dn->ctime;
+ st->st_flags = dn->flags;
+
+ st->st_rdev = 0;
+ np->allocsize = 0;
+ recompute_blocks (np);
+ }
+
+ mutex_lock (&np->lock);
+ *npp = np;
+ return 0;
+}
+
+error_t
+diskfs_node_iterate (error_t (*fun) (struct node *))
+{
+ error_t err = 0;
+ unsigned int num_nodes = 0;
+ struct node *node, **node_list, **p;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+
+ /* We must copy everything from the hash table into another data structure
+ to avoid running into any problems with the hash-table being modified
+ during processing (normally we delegate access to hash-table with
+ diskfs_node_refcnt_lock, but we can't hold this while locking the
+ individual node locks). */
+
+ for (node = all_nodes; node != 0; node = node->dn->hnext)
+ num_nodes++;
+
+ p = node_list = alloca (num_nodes * sizeof (struct node *));
+ for (node = all_nodes; node != 0; node = node->dn->hnext)
+ {
+ *p++ = node;
+ node->references++;
+ }
+
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ p = node_list;
+ while (num_nodes-- > 0)
+ {
+ node = *p++;
+ if (!err)
+ {
+ mutex_lock (&node->lock);
+ err = (*fun) (node);
+ mutex_unlock (&node->lock);
+ }
+ diskfs_nrele (node);
+ }
+
+ return err;
+}
+
+/* The user must define this function. Node NP has some light
+ references, but has just lost its last hard references. Take steps
+ so that if any light references can be freed, they are. NP is locked
+ as is the pager refcount lock. This function will be called after
+ diskfs_lost_hardrefs. */
+void
+diskfs_try_dropping_softrefs (struct node *np)
+{
+}
+
+/* The user must define this funcction. Node NP has some light
+ references but has just lost its last hard reference. NP is locked. */
+void
+diskfs_lost_hardrefs (struct node *np)
+{
+}
+
+/* The user must define this function. Node NP has just acquired
+ a hard reference where it had none previously. It is thus now
+ OK again to have light references without real users. NP is
+ locked. */
+void
+diskfs_new_hardrefs (struct node *np)
+{
+}
+
+
+
+error_t
+diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
+{
+ *namelen = np->dn->translen;
+ if (*namelen == 0)
+ return 0;
+ *namep = malloc (*namelen);
+ if (*namep == 0)
+ return ENOMEM;
+ memcpy (*namep, np->dn->trans, *namelen);
+ return 0;
+}
+
+error_t
+diskfs_set_translator (struct node *np,
+ const char *name, u_int namelen,
+ struct protid *cred)
+{
+ char *new;
+ if (namelen == 0)
+ {
+ free (np->dn->trans);
+ new = 0;
+ np->dn_stat.st_mode &= ~S_IPTRANS;
+ }
+ else
+ {
+ new = realloc (np->dn->trans, namelen);
+ if (new == 0)
+ return ENOSPC;
+ memcpy (new, name, namelen);
+ np->dn_stat.st_mode |= S_IPTRANS;
+ }
+ adjust_used (namelen - np->dn->translen);
+ np->dn->trans = new;
+ np->dn->translen = namelen;
+ recompute_blocks (np);
+ return 0;
+}
+
+static error_t
+create_symlink_hook (struct node *np, const char *target)
+{
+ assert (np->dn->u.lnk == 0);
+ np->dn_stat.st_size = strlen (target);
+ if (np->dn_stat.st_size > 0)
+ {
+ const size_t size = np->dn_stat.st_size + 1;
+ np->dn->u.lnk = malloc (size);
+ if (np->dn->u.lnk == 0)
+ return ENOSPC;
+ memcpy (np->dn->u.lnk, target, size);
+ np->dn->type = DT_LNK;
+ adjust_used (size);
+ recompute_blocks (np);
+ }
+ return 0;
+}
+error_t (*diskfs_create_symlink_hook)(struct node *np, const char *target)
+ = create_symlink_hook;
+
+static error_t
+read_symlink_hook (struct node *np, char *target)
+{
+ memcpy (target, np->dn->u.lnk, np->dn_stat.st_size + 1);
+ return 0;
+}
+error_t (*diskfs_read_symlink_hook)(struct node *np, char *target)
+ = read_symlink_hook;
+
+void
+diskfs_write_disknode (struct node *np, int wait)
+{
+}
+
+void
+diskfs_file_update (struct node *np, int wait)
+{
+ diskfs_node_update (np, wait);
+}
+
+error_t
+diskfs_node_reload (struct node *node)
+{
+ return 0;
+}
+
+
+/* The user must define this function. Truncate locked node NP to be SIZE
+ bytes long. (If NP is already less than or equal to SIZE bytes
+ long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
+ is set) then this should clear the symlink, even if
+ diskfs_create_symlink_hook stores the link target elsewhere. */
+error_t
+diskfs_truncate (struct node *np, off_t size)
+{
+ if (np->dn->type == DT_LNK)
+ {
+ free (np->dn->u.lnk);
+ adjust_used (size - np->dn_stat.st_size);
+ np->dn->u.lnk = 0;
+ np->dn_stat.st_size = size;
+ return 0;
+ }
+
+ if (np->allocsize <= size)
+ return 0;
+
+ assert (np->dn->type == DT_REG);
+
+ if (default_pager == MACH_PORT_NULL)
+ return EIO;
+
+ np->dn_stat.st_size = size;
+
+ off_t set_size = size;
+ size = round_page (size);
+
+ if (np->dn->u.reg.memobj != MACH_PORT_NULL)
+ {
+ error_t err = default_pager_object_set_size (np->dn->u.reg.memobj, set_size);
+ if (err == MIG_BAD_ID)
+ /* This is an old default pager. We have no way to truncate the
+ memory object. Note that the behavior here will be wrong in
+ two ways: user accesses past the end won't fault; and, more
+ importantly, later growing the file won't zero the contents
+ past the size we just supposedly truncated to. For proper
+ behavior, use a new default pager. */
+ return 0;
+ if (err)
+ return err;
+ }
+ /* Otherwise it never had any real contents. */
+
+ adjust_used (size - np->allocsize);
+ np->dn_stat.st_blocks += (size - np->allocsize) / 512;
+ np->allocsize = size;
+
+ return 0;
+}
+
+/* The user must define this function. Grow the disk allocated to locked node
+ NP to be at least SIZE bytes, and set NP->allocsize to the actual
+ allocated size. (If the allocated size is already SIZE bytes, do
+ nothing.) CRED identifies the user responsible for the call. */
+error_t
+diskfs_grow (struct node *np, off_t size, struct protid *cred)
+{
+ assert (np->dn->type == DT_REG);
+
+ if (np->allocsize >= size)
+ return 0;
+
+ off_t set_size = size;
+ size = round_page (size);
+ if (round_page (tmpfs_space_used + size - np->allocsize)
+ / vm_page_size > tmpfs_page_limit)
+ return ENOSPC;
+
+ if (default_pager == MACH_PORT_NULL)
+ return EIO;
+
+ if (np->dn->u.reg.memobj != MACH_PORT_NULL)
+ {
+ /* Increase the limit the memory object will allow to be accessed. */
+ error_t err = default_pager_object_set_size (np->dn->u.reg.memobj, set_size);
+ if (err == MIG_BAD_ID) /* Old default pager, never limited it. */
+ err = 0;
+ if (err)
+ return err;
+ }
+
+ adjust_used (size - np->allocsize);
+ np->dn_stat.st_blocks += (size - np->allocsize) / 512;
+ np->allocsize = size;
+ return 0;
+}
+
+mach_port_t
+diskfs_get_filemap (struct node *np, vm_prot_t prot)
+{
+ error_t err;
+
+ if (np->dn->type != DT_REG)
+ {
+ errno = EOPNOTSUPP; /* ? */
+ return MACH_PORT_NULL;
+ }
+
+ if (default_pager == MACH_PORT_NULL)
+ {
+ errno = EIO;
+ return MACH_PORT_NULL;
+ }
+
+ /* We don't bother to create the memory object until the first time we
+ need it (i.e. first mapping or i/o). This way we might have a clue
+ what size it's going to be beforehand, so we can tell the default
+ pager how big to make its bitmaps. This is just an optimization for
+ the default pager; the memory object can be expanded at any time just
+ by accessing more of it. (It also optimizes the case of empty files
+ so we might never make a memory object at all.) */
+ if (np->dn->u.reg.memobj == MACH_PORT_NULL)
+ {
+ error_t err = default_pager_object_create (default_pager,
+ &np->dn->u.reg.memobj,
+ np->allocsize);
+ if (err)
+ {
+ errno = err;
+ return MACH_PORT_NULL;
+ }
+ assert (np->dn->u.reg.memobj != MACH_PORT_NULL);
+
+ /* XXX we need to keep a reference to the object, or GNU Mach
+ will terminate it when we release the map. */
+ vm_map (mach_task_self (), &np->dn->u.reg.memref, 4096, 0, 1,
+ np->dn->u.reg.memobj, 0, 0, VM_PROT_NONE, VM_PROT_NONE,
+ VM_INHERIT_NONE);
+ assert_perror (err);
+ }
+
+ /* XXX always writable */
+
+ /* Add a reference for each call, the caller will deallocate it. */
+ err = mach_port_mod_refs (mach_task_self (), np->dn->u.reg.memobj,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+
+ return np->dn->u.reg.memobj;
+}
+
+/* The user must define this function. Return a `struct pager *' suitable
+ for use as an argument to diskfs_register_memory_fault_area that
+ refers to the pager returned by diskfs_get_filemap for node NP.
+ NP is locked. */
+struct pager *
+diskfs_get_filemap_pager_struct (struct node *np)
+{
+ return 0;
+}
+
+/* We have no pager of our own, so there is no need to worry about
+ users of it, or to shut it down. */
+int
+diskfs_pager_users ()
+{
+ return 0;
+}
+void
+diskfs_shutdown_pager ()
+{
+}
+
+/* The purpose of this is to decide that it's ok to make the fs read-only.
+ Turning a temporary filesystem read-only seem pretty useless. */
+vm_prot_t
+diskfs_max_user_pager_prot ()
+{
+ return VM_PROT_READ; /* Probable lie that lets us go read-only. */
+}
+
+error_t
+diskfs_S_file_get_storage_info (struct protid *cred,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
+{
+ mach_port_t memobj = diskfs_get_filemap (cred->po->np, VM_PROT_ALL);
+ if (memobj == MACH_PORT_NULL)
+ return errno;
+
+ assert (*num_ports >= 1); /* mig always gives us some */
+ *num_ports = 1;
+ *ports_type = MACH_MSG_TYPE_MOVE_SEND;
+ (*ports)[0]
+ = (cred->po->openstat & O_RDWR) == O_RDWR ? memobj : MACH_PORT_NULL;
+
+ assert (*num_offsets >= 2); /* mig always gives us some */
+ *num_offsets = 2;
+ (*offsets)[0] = 0;
+ (*offsets)[1] = cred->po->np->dn_stat.st_size;
+
+ assert (*num_ints >= 6); /* mig always gives us some */
+ *num_ints = 6;
+ (*ints)[0] = STORAGE_MEMORY;
+ (*ints)[1] = (cred->po->openstat & O_WRITE) ? 0 : STORE_READONLY;
+ (*ints)[2] = 1; /* block size */
+ (*ints)[3] = 1; /* 1 run in offsets list */
+ (*ints)[4] = 0; /* name len */
+ (*ints)[5] = 0; /* misc len */
+
+ *data_len = 0;
+
+ return 0;
+}
diff --git a/tmpfs/pager-stubs.c b/tmpfs/pager-stubs.c
new file mode 100644
index 00000000..25d70fe2
--- /dev/null
+++ b/tmpfs/pager-stubs.c
@@ -0,0 +1,88 @@
+/* stupid stub functions never called, needed because libdiskfs uses libpager
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <hurd/pager.h>
+#include <stdlib.h>
+
+/* The user must define this function. For pager PAGER, read one
+ page from offset PAGE. Set *BUF to be the address of the page,
+ and set *WRITE_LOCK if the page must be provided read-only.
+ The only permissible error returns are EIO, EDQUOT, and ENOSPC. */
+error_t
+pager_read_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t *buf,
+ int *write_lock)
+{
+ abort();
+ return EIEIO;
+}
+
+/* The user must define this function. For pager PAGER, synchronously
+ write one page from BUF to offset PAGE. In addition, mfree
+ (or equivalent) BUF. The only permissible error returns are EIO,
+ EDQUOT, and ENOSPC. */
+error_t
+pager_write_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t buf)
+{
+ abort();
+ return EIEIO;
+}
+
+/* The user must define this function. A page should be made writable. */
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t address)
+{
+ abort();
+ return EIEIO;
+}
+
+/* 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. */
+error_t
+pager_report_extent (struct user_pager_info *pager,
+ vm_address_t *offset,
+ vm_size_t *size)
+{
+ abort();
+ return EIEIO;
+}
+
+/* The user must define this function. This is called when a pager is
+ being deallocated after all extant send rights have been destroyed. */
+void
+pager_clear_user_data (struct user_pager_info *pager)
+{
+ abort();
+}
+
+/* The use must define this function. This will be called when the ports
+ library wants to drop weak references. The pager library creates no
+ weak references itself. If the user doesn't either, then it's OK for
+ this function to do nothing. */
+void
+pager_dropweak (struct user_pager_info *p)
+{
+ abort();
+}
diff --git a/tmpfs/tmpfs.c b/tmpfs/tmpfs.c
new file mode 100644
index 00000000..b72459fe
--- /dev/null
+++ b/tmpfs/tmpfs.c
@@ -0,0 +1,402 @@
+/* Main program and global state for tmpfs.
+ Copyright (C) 2000,01,02 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <argp.h>
+#include <argz.h>
+#include <string.h>
+#include <inttypes.h>
+#include <error.h>
+
+#include "tmpfs.h"
+#include <limits.h>
+#include <version.h>
+#include <fcntl.h>
+#include <hurd.h>
+#include <hurd/paths.h>
+
+char *diskfs_server_name = "tmpfs";
+char *diskfs_server_version = HURD_VERSION;
+char *diskfs_extra_version = "GNU Hurd";
+char *diskfs_disk_name = "swap";
+
+/* We ain't got to show you no stinkin' sync'ing. */
+int diskfs_default_sync_interval = 0;
+
+/* We must supply some claimed limits, though we don't impose any new ones. */
+int diskfs_link_max = (1ULL << (sizeof (nlink_t) * CHAR_BIT)) - 1;
+int diskfs_name_max = 255; /* dirent d_namlen limit */
+int diskfs_maxsymlinks = 8;
+
+/* Yeah, baby, we do it all! */
+int diskfs_shortcut_symlink = 1;
+int diskfs_shortcut_chrdev = 1;
+int diskfs_shortcut_blkdev = 1;
+int diskfs_shortcut_fifo = 1;
+int diskfs_shortcut_ifsock = 1;
+
+struct node *diskfs_root_node;
+mach_port_t default_pager;
+
+off_t tmpfs_page_limit, tmpfs_space_used;
+mode_t tmpfs_root_mode = -1;
+
+error_t
+diskfs_set_statfs (struct statfs *st)
+{
+ fsblkcnt_t pages;
+
+ st->f_type = FSTYPE_MEMFS;
+ st->f_fsid = getpid ();
+
+ st->f_bsize = vm_page_size;
+ st->f_blocks = tmpfs_page_limit;
+
+ spin_lock (&diskfs_node_refcnt_lock);
+ st->f_files = num_files;
+ pages = round_page (tmpfs_space_used) / vm_page_size;
+ spin_unlock (&diskfs_node_refcnt_lock);
+
+ st->f_bfree = pages < tmpfs_page_limit ? tmpfs_page_limit - pages : 0;
+ st->f_bavail = st->f_bfree;
+ st->f_ffree = st->f_bavail / sizeof (struct disknode); /* Well, sort of. */
+
+ return 0;
+}
+
+
+error_t
+diskfs_set_hypermetadata (int wait, int clean)
+{
+ /* All the state always just lives in core, so we have nothing to do. */
+ return 0;
+}
+
+void
+diskfs_sync_everything (int wait)
+{
+}
+
+error_t
+diskfs_reload_global_state ()
+{
+ return 0;
+}
+
+int diskfs_synchronous = 0;
+
+static const struct argp_option options[] =
+{
+ {"mode", 'm', "MODE", 0, "Permissions (octal) for root directory"},
+ {NULL,}
+};
+
+struct option_values
+{
+ off_t size;
+ mode_t mode;
+};
+
+/* Parse a command line option. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ /* We save our parsed values in this structure, hung off STATE->hook.
+ Only after parsing all options successfully will we use these values. */
+ struct option_values *values = state->hook;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input;
+ values = malloc (sizeof *values);
+ if (values == 0)
+ return ENOMEM;
+ state->hook = values;
+ values->size = 0;
+ values->mode = -1;
+ break;
+ case ARGP_KEY_FINI:
+ free (values);
+ state->hook = 0;
+ break;
+
+ case 'm': /* --mode=OCTAL */
+ {
+ char *end = NULL;
+ mode_t mode = strtoul (arg, &end, 8);
+ if (end == NULL || end == arg)
+ {
+ argp_error (state, "argument must be an octal number");
+ return EINVAL;
+ }
+ if (mode & S_IFMT)
+ {
+ argp_error (state, "invalid bits in mode");
+ return EINVAL;
+ }
+ values->mode = mode;
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_error (state, "must supply maximum size");
+ return EINVAL;
+
+ case ARGP_KEY_ARGS:
+ if (state->argv[state->next + 1] != 0)
+ {
+ argp_error (state, "too many arguments");
+ return EINVAL;
+ }
+ else
+ {
+ char *end = NULL;
+ intmax_t size = strtoimax (state->argv[state->next], &end, 0);
+ if (end == NULL || end == arg)
+ {
+ argp_error (state, "argument must be a number");
+ return EINVAL;
+ }
+ if (size < 0)
+ {
+ argp_error (state, "negative size not meaningful");
+ return EINVAL;
+ }
+ switch (*end)
+ {
+ case 'g':
+ case 'G':
+ size <<= 10;
+ case 'm':
+ case 'M':
+ size <<= 10;
+ case 'k':
+ case 'K':
+ size <<= 10;
+ break;
+ case '%':
+ {
+ /* Set as a percentage of the machine's physical memory. */
+ struct vm_statistics vmstats;
+ error_t err = vm_statistics (mach_task_self (), &vmstats);
+ if (err)
+ {
+ argp_error (state, "cannot find total physical memory: %s",
+ strerror (err));
+ return err;
+ }
+ size = round_page ((((vmstats.free_count
+ + vmstats.active_count
+ + vmstats.inactive_count
+ + vmstats.wire_count)
+ * vm_page_size)
+ * size + 99) / 100);
+ break;
+ }
+ }
+ size = (off_t) size;
+ if (size < 0)
+ {
+ argp_error (state, "size too large");
+ return EINVAL;
+ }
+ values->size = size;
+ }
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ /* All options parse successfully, so implement ours if possible. */
+ tmpfs_page_limit = values->size / vm_page_size;
+ tmpfs_root_mode = values->mode;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Override the standard diskfs routine so we can add our own output. */
+error_t
+diskfs_append_args (char **argz, size_t *argz_len)
+{
+ error_t err;
+
+ /* Get the standard things. */
+ err = diskfs_append_std_options (argz, argz_len);
+
+ if (!err)
+ {
+ off_t lim = tmpfs_page_limit * vm_page_size;
+ char buf[100], sfx;
+#define S(n, c) if ((lim & ((1 << n) - 1)) == 0) sfx = c, lim >>= n
+ S (30, 'G'); else S (20, 'M'); else S (10, 'K'); else sfx = '\0';
+#undef S
+ snprintf (buf, sizeof buf, "%Ld%c", lim, sfx);
+ err = argz_add (argz, argz_len, buf);
+ }
+
+ return err;
+}
+
+/* Handling of operations for the ports in diskfs_port_bucket, calling
+ * demuxer for each incoming message */
+static any_t
+diskfs_thread_function (any_t demuxer)
+{
+ error_t err;
+
+ do
+ {
+ ports_manage_port_operations_multithread (diskfs_port_bucket,
+ (ports_demuxer_type) demuxer,
+ 0,
+ 0,
+ 0);
+ err = diskfs_shutdown (0);
+ }
+ while (err);
+
+ exit (0);
+ /* NOTREACHED */
+ return (any_t) 0;
+}
+
+
+/* Add our startup arguments to the standard diskfs set. */
+static const struct argp_child startup_children[] =
+ {{&diskfs_startup_argp}, {0}};
+static struct argp startup_argp = {options, parse_opt, "MAX-BYTES", "\
+\v\
+MAX-BYTES may be followed by k or K for kilobytes,\n\
+m or M for megabytes, g or G for gigabytes.",
+ startup_children};
+
+/* Similarly at runtime. */
+static const struct argp_child runtime_children[] =
+ {{&diskfs_std_runtime_argp}, {0}};
+static struct argp runtime_argp = {0, parse_opt, 0, 0, runtime_children};
+
+struct argp *diskfs_runtime_argp = (struct argp *)&runtime_argp;
+
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap, realnode, host_priv;
+ struct stat st;
+
+ err = argp_parse (&startup_argp, argc, argv, ARGP_IN_ORDER, NULL, NULL);
+ assert_perror (err);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (2, 0, "Must be started as a translator");
+
+ /* Get our port to the default pager. Without that,
+ we have no place to put file contents. */
+ err = get_privileged_ports (&host_priv, NULL);
+ if (err == EPERM)
+ {
+ default_pager = file_name_lookup (_SERVERS_DEFPAGER, O_EXEC, 0);
+ if (default_pager == MACH_PORT_NULL)
+ error (0, errno, _SERVERS_DEFPAGER);
+ }
+ else if (err)
+ error (0, err, "Cannot get host privileged port");
+ else
+ {
+ err = vm_set_default_memory_manager (host_priv, &default_pager);
+ mach_port_deallocate (mach_task_self (), host_priv);
+ if (err)
+ error (0, err, "Cannot get default pager port");
+ }
+ if (default_pager == MACH_PORT_NULL)
+ error (0, 0, "files cannot have contents with no default pager port");
+
+ /* Initialize the diskfs library. Must come before any other diskfs call. */
+ err = diskfs_init_diskfs ();
+ if (err)
+ error (4, err, "init");
+
+ err = diskfs_alloc_node (0, S_IFDIR, &diskfs_root_node);
+ if (err)
+ error (4, err, "cannot create root directory");
+
+ /* Like diskfs_spawn_first_thread. But do it manually, without timeout */
+ cthread_detach (cthread_fork ((cthread_fn_t) diskfs_thread_function,
+ (any_t) diskfs_demuxer));
+
+ /* Now that we are all set up to handle requests, and diskfs_root_node is
+ set properly, it is safe to export our fsys control port to the
+ outside world. */
+ realnode = diskfs_startup_diskfs (bootstrap, 0);
+ diskfs_root_node->dn_stat.st_mode = S_IFDIR;
+
+ /* Propagate permissions, owner, etc. from underlying node to
+ the root directory of the new (empty) filesystem. */
+ err = io_stat (realnode, &st);
+ if (err)
+ {
+ error (0, err, "cannot stat underlying node");
+ if (tmpfs_root_mode == -1)
+ diskfs_root_node->dn_stat.st_mode |= 0777 | S_ISVTX;
+ else
+ diskfs_root_node->dn_stat.st_mode |= tmpfs_root_mode;
+ diskfs_root_node->dn_set_ctime = 1;
+ diskfs_root_node->dn_set_mtime = 1;
+ diskfs_root_node->dn_set_atime = 1;
+ }
+ else
+ {
+ if (tmpfs_root_mode == -1)
+ {
+ diskfs_root_node->dn_stat.st_mode |= st.st_mode &~ S_IFMT;
+ if (S_ISREG (st.st_mode) && (st.st_mode & 0111) == 0)
+ /* There are no execute bits set, as by default on a plain file.
+ For the virtual directory, set execute bits where read bits are
+ set on the underlying plain file. */
+ diskfs_root_node->dn_stat.st_mode |= (st.st_mode & 0444) >> 2;
+ }
+ else
+ diskfs_root_node->dn_stat.st_mode |= tmpfs_root_mode;
+ diskfs_root_node->dn_stat.st_uid = st.st_uid;
+ diskfs_root_node->dn_stat.st_author = st.st_author;
+ diskfs_root_node->dn_stat.st_gid = st.st_gid;
+ diskfs_root_node->dn_stat.st_atim = st.st_atim;
+ diskfs_root_node->dn_stat.st_mtim = st.st_mtim;
+ diskfs_root_node->dn_stat.st_ctim = st.st_ctim;
+ diskfs_root_node->dn_stat.st_flags = st.st_flags;
+ }
+ diskfs_root_node->dn_stat.st_mode &= ~S_ITRANS;
+ diskfs_root_node->dn_stat.st_mode |= S_IROOT;
+ diskfs_root_node->dn_stat.st_nlink = 2;
+
+ /* We must keep the REALNODE send right to remain the active
+ translator for the underlying node. */
+
+ mutex_unlock (&diskfs_root_node->lock);
+
+ /* and so we die, leaving others to do the real work. */
+ cthread_exit (0);
+ /* NOTREACHED */
+ return 0;
+}
diff --git a/tmpfs/tmpfs.h b/tmpfs/tmpfs.h
new file mode 100644
index 00000000..3cb31e6b
--- /dev/null
+++ b/tmpfs/tmpfs.h
@@ -0,0 +1,85 @@
+/* Private data structures for tmpfs.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _tmpfs_h
+#define _tmpfs_h 1
+
+#include <hurd/diskfs.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdint.h>
+
+struct disknode
+{
+ uint_fast8_t type; /* DT_REG et al */
+
+ unsigned int gen;
+ off_t size;
+ mode_t mode;
+ nlink_t nlink;
+ uid_t uid, author;
+ gid_t gid;
+ struct timespec atime, mtime, ctime;
+ unsigned int flags;
+
+ char *trans;
+ size_t translen;
+
+ union
+ {
+ char *lnk; /* malloc'd symlink target */
+ struct
+ {
+ mach_port_t memobj;
+ vm_address_t memref;
+ unsigned int allocpages; /* largest size while memobj was live */
+ } reg;
+ struct
+ {
+ struct tmpfs_dirent *entries;
+ struct disknode *dotdot;
+ } dir;
+ dev_t chr, blk;
+ } u;
+
+ struct node *hnext, **hprevp;
+};
+
+struct tmpfs_dirent
+{
+ struct tmpfs_dirent *next;
+ struct disknode *dn;
+ uint8_t namelen;
+ char name[0];
+};
+
+extern unsigned int num_files;
+extern off_t tmpfs_page_limit, tmpfs_space_used;
+
+extern mach_port_t default_pager;
+
+static inline void
+adjust_used (off_t change)
+{
+ spin_lock (&diskfs_node_refcnt_lock);
+ tmpfs_space_used += change;
+ spin_unlock (&diskfs_node_refcnt_lock);
+}
+
+#endif
diff --git a/trans/ChangeLog b/trans/ChangeLog
deleted file mode 100644
index 475cd839..00000000
--- a/trans/ChangeLog
+++ /dev/null
@@ -1,324 +0,0 @@
-Fri Jul 12 23:02:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * crash.c (stop_pgrp): Fetch pgrp using correct call.
-
-Mon Jul 8 13:52:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * crash.c (stop_pgrp): Don't do anything if ORPHANED.
-
-Mon Jul 8 08:54:05 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
-
- * crash.c (stop_pgrp): Take second arg CTTYID. Fetch each pgrp
- member's msgpor and send msg_sig_post with that as refport instead of
- calling POSIX.1 kill function like a bonehead.
- (S_crash_dump_task): Pass CTTY_ID arg through to stop_pgrp.
-
-Sun Jul 7 22:43:23 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * crash.c (stop_pgrp): New function.
- (S_crash_dump_task): Call stop_pgrp.
-
- * Makefile (fwd): Depend on libports.
-
-Mon Jul 1 16:09:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (crash): New target.
- * Makefile (SRCS): Added crash.c.
- * crash.c: Moved here from ../exec.
- (S_crash_dump_task): New args EXC, CODE, SUBCODE, CTTY_ID.
- Supply SIGCODE arg to proc_mark_stop.
- (signal_crasher): New arg SIGCODE, supply to proc_mark_exit. All
- callers changed.
- (S_msg_sig_post_untraced): Supply C->sigcode to proc_mark_stop.
- (S_crash_dump_task): Drop arg TARGET.
- (dump_core): Likewise; all callers changed.
- (struct crasher): Delete member `target'.
- (S_msg_describe_ports): New function.
-
-Thu Jun 20 16:28:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (null ifsock fifo new-fifo devport): Depend on
- ../libfshelp/libfshelp.a.
-
-Wed May 29 10:31:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devport.c (trivfs_S_file_get_storage_info): Implement new interface.
-
-Sat May 11 01:19:21 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * new-fifo.c (fifo_trans_parse_args): Use ARGP_ERR_UNKNOWN instead
- of EINVAL.
-
-Tue Apr 30 09:58:47 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (all): Delete target.
- (include ../Makeconf): *Before* all dependences.
- ($(targets)): Each program depends on its associated .o.
-
-Mon Apr 15 12:50:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * new-fifo.c (fifo_trans_parse_args): Supply missing arg to
- argp_parse.
-
-Sun Mar 31 13:26:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets): Add devport.
- (SRCS): Add devport.c.
- Add devport as a target to various dependency rules.
-
-Wed Feb 7 17:51:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fifo.c (trivfs_S_file_set_size): Add #!$@&* reply port args.
- * new-fifo.c (trivfs_S_file_set_size): Likewise.
-
-Mon Jan 29 09:53:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fifo.c (close_hook): Also disconnect ACTIVE_FIFO if the laster
- writer is going away and there were no readers.
- (open_hook): Unbreak a new read pipe even if not waiting for writers.
-
- * new-fifo.c (fifo_trans_open): Typo.
-
-Sun Jan 28 21:52:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fifo.c (open_hook): Only bother to do anything if O_READ | O_WRITE.
- * new-fifo.c (fifo_trans_open): Likewise.
- When O_NONBLOCK is set, just don't block if possible, instead of
- of returning EWOULDBLOCK.
- (trivfs_S_io_select): The pipe is on CRED->po->hook, not CRED->hook.
- (trivfs_modify_stat): Zero the returned size if there's no pipe.
-
-Sat Jan 27 19:30:25 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fifo.c (open_hook): When O_NONBLOCK is set, just don't block if
- possible, instead of of returning EWOULDBLOCK.
- Only set PO->hook if O_READ or O_WRITE is set.
- (trivfs_S_io_select): The pipe is on CRED->po->hook, not CRED->hook.
- (trivfs_modify_stat): Zero the returned size if there's no pipe.
-
-Thu Jan 25 18:34:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fifo.c (trivfs_goaway): Handle errors from ports_inhibit_bucket_rpcs.
- * new-fifo.c (trivfs_goaway): Likewise.
- Call ports_interrupt_rpcs instead of ports_interrupt_rpc.
-
-Tue Jan 16 14:18:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * new-fifo.c (trivfs_S_io_select): Request interruption if the
- reply-port dies.
- Don't block if there's an error immediately available.
- * fifo.c (trivfs_S_io_select): Ditto.
-
-Mon Nov 6 12:39:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * magic.c (S_fsys_get_options): New function.
- * symlink.c (S_fsys_get_options): New function.
-
-Sun Nov 5 01:56:20 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ifsock.c (main): Add flags argument to trivfs_startup call.
- * null.c (main): Ditto.
- * fifo.c (main): Ditto.
- * new-fifo.c (fifo_trans_start): Ditto.
- * symlink.c (main): Add flags argument to fsys_startup call.
- (S_fsys_startup): Add FLAGS arg.
- * magic.c (main): Add flags argument to fsys_startup call.
- (S_fsys_startup): Add FLAGS arg.
-
-Sat Oct 7 23:41:02 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * symlink.c (S_fsys_getpriv): Add new extra args.
- * magic.c (S_fsys_getpriv): Ditto.
-
-Mon Sep 18 14:54:55 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fifo.c (trivfs_S_file_set_size): Renamed from trivfs_S_file_truncate;
- Return EINVAL if the new size isn't 0.
- * new-fifo.c (trivfs_S_file_truncate): Ditto.
- * null.c (trivfs_S_file_set_size): Renamed from trivfs_S_file_truncate.
-
-Fri Sep 8 12:27:35 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fifo.c, new-fifo.c (open_hook): Block for read only when there's
- really someone reading already, or until there's a writer.
- (open_hook): Use the WAIT macro to block.
- * fifo.c (wait_for_writer): New variable.
- (main): Set WAIT_FOR_WRITER with WAIT_FOR_READER.
- * new-fifo.c (struct fifo_trans): Added wait_for_writer field.
- Delete standalone field. Add some comments.
- (fifo_trans_create): Propagate and set the wait_for_writer field.
- (fifo_trans_parse_args): Set the wait_for_writer field.
-
- * fifo.c (trivfs_modify_stat): Only return pipe info if there's a pipe.
- (close_hook): Don't die if there's no pipe.
- * new-fifo.c (trivfs_modify_stat): Only return pipe info if
- there's a pipe.
- (fifo_trans_close): Don't die if there's no pipe.
-
-Thu Aug 31 19:16:25 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fifo.c (trivfs_S_io_select): Use pipe_pair_select.
- (trivfs_S_io_write): Pass in the NOBLOCK parameter to pipe_write.
-
-Wed Aug 30 12:14:58 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * fifo.c (trivfs_goaway): Implement correctly.
- (main): When we time out, don't exit unless there are no opens.
- (main): Add timeouts.
- (port_bucket): Now a local variable in main.
- (trivfs_S_io_select): Implement correctly.
-
-Tue Aug 29 17:31:45 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * fifo.c (open_hook): Use hurd_condition_wait to detect interrupts.
-
-Thu Aug 24 10:41:31 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (all): New target.
- (symlink, magic, ifsock, fifo, null): Put all dependencies in
- these targets.
- (null-HURDLIBS, ifsock-HURDLIBS, fifo-HURDLIBS): Removed.
- Get rid of rules dealing with error.o
-
-Wed Aug 23 13:11:18 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * magic.c (S_fsys_forward): New function.
- * symlink.c (S_fsys_forward): New function.
- * bogus-fifo.c (S_fsys_forward): New function.
-
-Tue Aug 22 10:48:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Add libshouldbeinlibc (everyone uses it).
- (symlink, magic, fifo, null, ifsock): Remove error.o.
- Get rid of rules dealing with error.o.
-
- * fifo.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
- (trivfs_modify_stat): Give the size of the fifo now that we've got
- a handle on it.
-
-Mon Aug 21 14:43:46 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * null.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
- * ifsock.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
-
- * fifo.c (open_hook): Use condition_broadcast instead of
- condition_signal on active_fifo_changed, as all waiters need be
- notified of changes.
-
-Tue Jul 25 13:53:30 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fifo.c: New file.
- (main): Don't pass in the MACH_RCV_TIMEOUT flag with a zero timeout.
- * Makefile (SRCS): Add fifo.c.
- (targets): Add fifo.
- (fifo): New target.
-
-Thu Jul 6 15:42:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (OBJS): New var.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Wed Jul 5 21:17:34 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (ifsock-HURDLIBS, null-HURDLIBS): New vars.
- (null, ifsock): Fix dependencies.
-
-Wed Jun 28 15:07:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * null.c (PT_CTL, PT_NODE): Deleted macros.
- (trivfs_protid_porttypes, trivfs_cntl_porttypes,
- trivfs_protid_nporttypes, trivfs_cntl_nporttypes): Deleted vars.
- (trivfs_protid_portclasses, trivfs_cntl_portclasses,
- trivfs_protid_nportclasses, trivfs_cntl_nportclasses): New vars.
- (control_class, node_class, port_bucket): New vars.
- (main): Initialize control_class, node_class, port_bucket,
- trivfs_protid_portclasses, and trivfs_cntl_portclasses.
- (ports_cleanroutines): Delete initialization.
- (main): Convert to new trivfs interface.
- (trivfs_goaway): Likewise.
- (main): Convert to new ports interface.
- (ports_demuxer, ports_notice_idle, ports_no_live_ports,
- ports_no_hard_ports): Deleted functions.
-
- * Makefile (ifsock): Add dependency on libihash.
- (null): Likewise.
-
- * ifsock.c (PT_CTL, PT_NODE): Deleted macros.
- (ports_cleanroutines): Deleted var.
- (ports_notice_idle, ports_no_live_ports, ports_no_hard_ports):
- Deleted functions.
- (control_class, node_class, port_bucket): New vars.
- (trivfs_protid_porttypes, trivfs_cntl_porttypes,
- trivfs_protid_nporttypes, trivfs_cntl_nporttypes): Deleted vars.
- (trivfs_protid_portclasses, trivfs_cntl_portclasses,
- trivfs_protid_nportclasses, trivfs_cntl_nportclasses): New vars.
- (main): Initialize control_class, node_class, port_bucket,
- trivfs-protid_portclasses, and trivfs_cntl_portclasses.
- (main): Use new trivfs interface.
- (trivfs_goaway): Likewise.
- (main): Use new ports interface.
- (S_ifsock_getsockaddr): Likewise.
- (demuxer): Renamed from ports_demuxer.
- (demuxer): Declare ifsock_server.
-
-Fri May 12 19:07:54 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * magic.c (S_fsys_set_options, S_fsys_mod_readonly): Change from
- mod_readonly to set_options.
- * symlink.c (S_fsys_set_options, S_fsys_mod_readonly): Ditto.
-
-Thu May 11 13:36:28 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * null.c (trivfs_modify_stat): Make st_blksize really large.
-
-Mon Apr 10 20:38:49 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * null.c (trivfs_S_file_truncate): Always return 0, so O_TRUNC works.
-
-Sun Apr 9 00:26:07 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * null.c (main): Use trivfs_startup() instead of doing things manually.
- Get rid of _libports_initialize() [it gets called automatically].
- * ifsock.c (main): Ditto; also, use error() to print error messages.
-
-Mon Apr 3 16:39:33 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * null.c (trivfs_modify_stat): Return more useful values for the
- st_blksize and st_fstype fields.
-
-Fri Mar 31 12:20:48 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * null.c (main): Move the check for the bootstrap port after the
- args check, so that users can run it from the shell to get a usage
- message.
-
- * magic.c (main): Don't deallocate our right to the underlying
- disk node, so we don't get garbage collected prematurely. Also
- move the check for the bootstrap port after the args check, so
- that users can run it from the shell to get a usage message.
-
-Wed Mar 29 19:30:33 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * magic.c: New file: Translator to return F_RETRY_MAGIC strings.
- * null.c: New file: Translator for /dev/null & /dev/zero.
- * Makefile: Add support for the magic and null servers.
-
-Wed Aug 31 11:08:10 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * symlink.c (S_fsys_mod_readonly, S_fsys_syncfs): New functions.
-
-Tue Aug 30 16:42:29 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * ifsock.c (main): Call file_name_lookup instead af path_lookup.
-
-Tue Aug 16 11:38:26 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (symlink, symlink.o): New targets.
- Change to be type `servers.'.
-
-Fri Jul 22 15:15:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
-
diff --git a/trans/Makefile b/trans/Makefile
index 3ba15844..4e6a22dd 100644
--- a/trans/Makefile
+++ b/trans/Makefile
@@ -1,5 +1,6 @@
-#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2006, 2007,
+# 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
@@ -18,22 +19,36 @@
dir := trans
makemode := servers
-targets = symlink ifsock magic null fifo new-fifo fwd devport crash
-SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c devport.c \
- crash.c
-OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o
+targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
+ password hello hello-mt streamio fakeroot proxy-defpager
+SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
+ crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
+ 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 \
+ device_replyServer.o elfcore.o
+HURDLIBS = threads ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
+password-LDLIBS = $(LIBCRYPT)
include ../Makeconf
-symlink magic: fsysServer.o
+vpath elfcore.c $(top_srcdir)/exec
+
+symlink: fsysServer.o
ifsock: ifsockServer.o
-crash: crashServer.o crash_replyUser.o msgServer.o
+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
-crash: ../libports/libports.a ../libtrivfs/libtrivfs.a ../libthreads/libthreads.a ../libfshelp/libfshelp.a
+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
-fwd new-fifo: ../libfshelp/libfshelp.a ../libports/libports.a
-null ifsock fifo new-fifo devport: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a
+fwd: ../libfshelp/libfshelp.a ../libports/libports.a
+hello-mt magic null ifsock fifo new-fifo firmlink: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libthreads/libthreads.a ../libports/libports.a ../libihash/libihash.a
+magic: ../libiohelp/libiohelp.a
+hello: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a
+fakeroot: ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a ../libiohelp/libiohelp.a ../libthreads/libthreads.a ../libports/libports.a ../libihash/libihash.a
$(targets): ../libshouldbeinlibc/libshouldbeinlibc.a
-fwd null ifsock fifo new-fifo devport: ../libthreads/libthreads.a
$(targets): %: %.o
diff --git a/trans/bogus-fifo.c b/trans/bogus-fifo.c
index 3151dcc8..acad6e4b 100644
--- a/trans/bogus-fifo.c
+++ b/trans/bogus-fifo.c
@@ -55,6 +55,7 @@ main (int argc, char **argv)
/* Reply to our parent */
mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &fsys);
err = fsys_startup (bootstrap, fsys, MACH_MSG_TYPE_MAKE_SEND, &realnode);
+ mach_port_deallocate (mach_task_self (), bootstrap);
if (err)
error(1, err, "starting translator");
diff --git a/trans/crash.c b/trans/crash.c
index 5947cb26..4a59d450 100644
--- a/trans/crash.c
+++ b/trans/crash.c
@@ -1,5 +1,8 @@
/* GNU Hurd standard crash dump server.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ Copyright (C) 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2006, 2007
+ Free Software Foundation, Inc.
+
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -23,12 +26,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/trivfs.h>
#include <sys/wait.h>
#include <error.h>
+#include <argp.h>
+#include <argz.h>
+#include <sys/mman.h>
+
+#include <version.h>
#include "crash_S.h"
#include "crash_reply_U.h"
#include "msg_S.h"
+const char *argp_program_version = STANDARD_HURD_VERSION (crash);
+
process_t procserver; /* Our proc port, for easy access. */
/* Port bucket we service requests on. */
@@ -49,6 +59,23 @@ int trivfs_cntl_nportclasses = 1;
struct trivfs_control *fsys;
+enum crash_action
+{
+ crash_unspecified,
+ crash_suspend,
+ crash_kill,
+ crash_corefile
+};
+#define CRASH_DEFAULT crash_suspend
+#define CRASH_ORPHANS_DEFAULT crash_corefile
+
+static enum crash_action crash_how, crash_orphans_how;
+
+
+/* This is defined in ../exec/elfcore.c, or we could have
+ different implementations for other formats. */
+extern error_t dump_core (task_t task, file_t file, off_t corelimit,
+ int signo, long int sigcode, int sigerror);
/* This data structure describes a crashing task which we have suspended.
This is attached to a receive right we have set as the process's message
@@ -67,6 +94,7 @@ struct crasher
task_t task;
file_t core_file;
+ off_t core_limit;
int signo, sigcode, sigerror;
mach_port_t original_msgport; /* Restore on resume. */
@@ -100,7 +128,7 @@ stop_pgrp (process_t userproc, mach_port_t cttyid)
err = proc_getpgrppids (userproc, pgrp, &pids, &numpids);
if (err)
return;
-
+
for (i = 0; i < numpids; i++)
if (pids[i] != pid)
{
@@ -111,7 +139,7 @@ stop_pgrp (process_t userproc, mach_port_t cttyid)
mach_port_deallocate (mach_task_self (), msgport);
}
if (pids != pids_)
- vm_deallocate (mach_task_self (), (vm_address_t) pids, numpids);
+ munmap (pids, numpids);
}
@@ -119,25 +147,48 @@ kern_return_t
S_crash_dump_task (mach_port_t port,
mach_port_t reply_port, mach_msg_type_name_t reply_type,
task_t task, file_t core_file,
- int signo, int sigcode, int sigerror,
+ int signo, integer_t sigcode, int sigerror,
natural_t exc, natural_t code, natural_t subcode,
mach_port_t ctty_id)
-
{
error_t err;
struct trivfs_protid *cred;
- mach_port_t user_proc;
+ mach_port_t user_proc = MACH_PORT_NULL;
+ enum crash_action how;
cred = ports_lookup_port (port_bucket, port, trivfs_protid_portclasses[0]);
if (! cred)
return EOPNOTSUPP;
- /* Suspend the task first thing before being twiddling it. */
- err = task_suspend (task);
-
- if (! err)
+ how = crash_how;
+ if (crash_how != crash_orphans_how)
{
+ /* We must ascertain if this is an orphan before deciding what to do. */
err = proc_task2proc (procserver, task, &user_proc);
+ if (!err)
+ {
+ pid_t pid, ppid;
+ int orphan;
+ err = proc_getpids (user_proc, &pid, &ppid, &orphan);
+ if (!err && orphan)
+ how = crash_orphans_how;
+ }
+ }
+
+ switch (how)
+ {
+ default: /* NOTREACHED */
+ err = EGRATUITOUS;
+ break;
+
+ case crash_suspend:
+ /* Suspend the task first thing before being twiddling it. */
+ err = task_suspend (task);
+ if (err)
+ break;
+
+ if (user_proc != MACH_PORT_NULL)
+ err = proc_task2proc (procserver, task, &user_proc);
if (! err)
{
struct crasher *c;
@@ -152,9 +203,7 @@ S_crash_dump_task (mach_port_t port,
/* Install our port as the crasher's msgport.
We will wait for signals to resume (crash) it. */
- msgport = ports_get_right (c);
- mach_port_insert_right (mach_task_self (), msgport,
- msgport, MACH_MSG_TYPE_MAKE_SEND);
+ msgport = ports_get_send_right (c);
err = proc_setmsgport (user_proc, msgport, &c->original_msgport);
mach_port_deallocate (mach_task_self (), msgport);
@@ -169,6 +218,7 @@ S_crash_dump_task (mach_port_t port,
c->task = task;
c->core_file = core_file;
+ c->core_limit = (off_t) -1; /* XXX should core limit in RPC */
c->signo = signo;
c->sigcode = sigcode;
c->sigerror = sigerror;
@@ -179,7 +229,40 @@ S_crash_dump_task (mach_port_t port,
}
if (err != MIG_NO_REPLY)
task_resume (task);
+ break;
+
+ case crash_corefile:
+ err = task_suspend (task);
+ if (!err)
+ {
+ err = dump_core (task, core_file,
+ (off_t) -1, /* XXX should get core limit in RPC */
+ signo, sigcode, sigerror);
+ task_resume (task);
+ }
+ break;
+
+ case crash_kill:
+ {
+ if (user_proc != MACH_PORT_NULL)
+ err = 0;
+ else
+ err = proc_task2proc (procserver, task, &user_proc);
+ if (!err)
+ err = proc_mark_exit (user_proc, W_EXITCODE (0, signo), sigcode);
+ err = task_terminate (task);
+ if (!err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ mach_port_deallocate (mach_task_self (), core_file);
+ mach_port_deallocate (mach_task_self (), ctty_id);
+ }
+ }
}
+
+ if (user_proc != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), user_proc);
+
ports_port_deref (cred);
return err;
}
@@ -294,13 +377,6 @@ S_msg_sig_post_untraced (mach_port_t port,
return err;
}
-error_t
-dump_core (task_t task, file_t core_file,
- int signo, long int sigcode, int sigerror)
-{
- return ENOSYS; /* XXX */
-}
-
/* This gets called when the receive right for a crasher message port dies. */
void
@@ -319,7 +395,7 @@ dead_crasher (void *ptr)
{
/* C->proc was cleared in S_msg_sig_post as a marker that
this crasher should get a core dump when we clean him up. */
- error_t err = dump_core (c->task, c->core_file,
+ error_t err = dump_core (c->task, c->core_file, c->core_limit,
c->signo, c->sigcode, c->sigerror);
/* Now reply to the crasher's original RPC which started this whole
party. He should now report his own death (with core dump iff ERR
@@ -358,6 +434,109 @@ dead_crasher (void *ptr)
}
+static const struct argp_option options[] =
+{
+ {0,0,0,0,"These options specify the disposition of a crashing process:", 1},
+ {"action", 'a', "ACTION", 0, "Action taken on crashing processes", 1},
+ {"orphan-action", 'O', "ACTION", 0, "Action taken on crashing orphans", 1},
+
+ {0,0,0,0,"These options are synonyms for --action=OPTION:", 2},
+ {"suspend", 's', 0, 0, "Suspend the process", 2},
+ {"kill", 'k', 0, 0, "Kill the process", 2},
+ {"core-file", 'c', 0, 0, "Dump a core file", 2},
+ {"dump-core", 0, 0, OPTION_ALIAS },
+ {0}
+};
+static const char doc[] =
+"Server to handle crashing tasks and dump core files or equivalent.\v"
+"The ACTION values can be `suspend', `kill', or `core-file'.\n\n"
+"If `--orphan-action' is not specified, the `--action' value is used for "
+"orphans. The default is `--action=suspend --orphan-action=core-file'.";
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ error_t parse_action (enum crash_action *how)
+ {
+ if (!strcmp (arg, "suspend"))
+ *how = crash_suspend;
+ else if (!strcmp (arg, "kill"))
+ *how = crash_kill;
+ else if (!strcmp (arg, "core-file"))
+ *how = crash_corefile;
+ else
+ {
+ argp_error (state,
+ "action must be one of: suspend, kill, core-file");
+ return EINVAL;
+ }
+ return 0;
+ }
+
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'a':
+ return parse_action (&crash_how);
+ case 'O':
+ return parse_action (&crash_orphans_how);
+
+ case 's': crash_how = crash_suspend; break;
+ case 'k': crash_how = crash_kill; break;
+ case 'c': crash_how = crash_corefile; break;
+
+ case ARGP_KEY_SUCCESS:
+ if (crash_orphans_how == crash_unspecified)
+ crash_orphans_how = (crash_how == crash_unspecified
+ ? CRASH_ORPHANS_DEFAULT : crash_how);
+ if (crash_how == crash_unspecified)
+ crash_how = CRASH_DEFAULT;
+ break;
+ }
+ return 0;
+}
+
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+ const char *opt;
+
+ switch (crash_how)
+ {
+ case crash_suspend: opt = "--action=suspend"; break;
+ case crash_kill: opt = "--action=kill"; break;
+ case crash_corefile: opt = "--action=core-file"; break;
+ default:
+ return EGRATUITOUS;
+ }
+ err = argz_add (argz, argz_len, opt);
+
+ if (!err)
+ {
+ switch (crash_orphans_how)
+ {
+ case crash_suspend: opt = "--orphan-action=suspend"; break;
+ case crash_kill: opt = "--orphan-action=kill"; break;
+ case crash_corefile: opt = "--orphan-action=core-file"; break;
+ default:
+ return EGRATUITOUS;
+ }
+ err = argz_add (argz, argz_len, opt);
+ }
+
+ return err;
+}
+
+struct argp crash_argp = { options, parse_opt, 0, doc };
+struct argp *trivfs_runtime_argp = &crash_argp;
+
static int
crash_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
@@ -375,6 +554,7 @@ main (int argc, char **argv)
error_t err;
mach_port_t bootstrap;
+ argp_parse (&crash_argp, argc, argv, 0,0,0);
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
@@ -402,7 +582,7 @@ main (int argc, char **argv)
ports_manage_port_operations_multithread (port_bucket, crash_demuxer,
10 * 1000, /* idle thread */
10 * 60 * 1000, /* idle server */
- 0, MACH_PORT_NULL);
+ 0);
/* That returns when 10 minutes pass without an RPC. Try shutting down
as if sent fsys_goaway; if we have any users who need us to stay
around, this returns EBUSY and we loop to service more RPCs. */
@@ -414,7 +594,6 @@ main (int argc, char **argv)
void
trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
{
- st->st_fstype = FSTYPE_MISC;
}
error_t
@@ -598,9 +777,6 @@ S_msg_set_env_variable (mach_port_t process,
boolean_t replace)
{ return EBUSY; }
kern_return_t
-S_msg_startup_dosync (mach_port_t process)
-{ return EBUSY; }
-kern_return_t
S_msg_get_exec_flags (mach_port_t process, mach_port_t refport, int *flags)
{ return EBUSY; }
kern_return_t
@@ -615,7 +791,7 @@ S_msg_clear_some_exec_flags (mach_port_t process, mach_port_t refport,
{ return EBUSY; }
error_t
S_msg_report_wait (mach_port_t process, thread_t thread,
- string_t desc, int *rpc)
+ string_t desc, mach_msg_id_t *rpc)
{ return EBUSY; }
error_t
S_msg_describe_ports (mach_port_t msgport, mach_port_t refport,
diff --git a/trans/devport.c b/trans/devport.c
deleted file mode 100644
index a6dfe7f8..00000000
--- a/trans/devport.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* A really stupid translator allowing a user to get a device port
-
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <error.h>
-#include <string.h>
-
-#include <hurd.h>
-#include <hurd/ports.h>
-#include <hurd/trivfs.h>
-#include <hurd/fsys.h>
-
-#include <device/device.h>
-
-static mach_port_t device_master = MACH_PORT_NULL;
-static char *device_name = 0;
-
-struct port_class *trivfs_protid_portclasses[1];
-struct port_class *trivfs_cntl_portclasses[1];
-int trivfs_protid_nportclasses = 1;
-int trivfs_cntl_nportclasses = 1;
-
-void
-main (int argc, char **argv)
-{
- error_t err;
- mach_port_t bootstrap;
- struct port_class *control_class;
- struct port_class *node_class;
- struct port_bucket *port_bucket;
-
- control_class = ports_create_class (trivfs_clean_cntl, 0);
- node_class = ports_create_class (trivfs_clean_protid, 0);
- port_bucket = ports_create_bucket ();
- trivfs_protid_portclasses[0] = node_class;
- trivfs_cntl_portclasses[0] = control_class;
-
- if (argc != 2)
- {
- fprintf (stderr, "Usage: %s DEVICE-NAME", program_invocation_name);
- exit(1);
- }
-
- device_name = argv[1];
-
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error (1, 0, "must be started as a translator");
-
- err = get_privileged_ports (0, &device_master);
- if (err)
- error (2, err, "Can't get device master port");
-
- /* Reply to our parent */
- err = trivfs_startup (bootstrap, 0, control_class, port_bucket,
- node_class, port_bucket, NULL);
- if (err)
- error (3, err, "Contacting parent");
-
- /* Launch. */
- ports_manage_port_operations_one_thread (port_bucket, trivfs_demuxer, 0);
-
- exit(0);
-}
-
-/* Trivfs hooks */
-
-int trivfs_fstype = FSTYPE_DEV;
-int trivfs_fsid = 0;
-
-int trivfs_support_read = 0;
-int trivfs_support_write = 0;
-int trivfs_support_exec = 0;
-
-int trivfs_allow_open = 0;
-
-void
-trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
-{
- st->st_size = 0;
- st->st_blocks = 0;
- st->st_mode &= ~S_IFMT;
- st->st_mode |= S_IFCHR;
-}
-
-error_t
-trivfs_goaway (struct trivfs_control *fsys, int flags)
-{
- exit (0);
-}
-
-error_t
-trivfs_S_file_get_storage_info (struct trivfs_protid *cred,
- mach_port_t reply,
- mach_msg_type_name_t reply_type,
- mach_port_t **ports,
- mach_msg_type_name_t *ports_type,
- mach_msg_type_number_t *num_ports,
- int **ints, mach_msg_type_number_t *num_ints,
- off_t **offsets,
- mach_msg_type_number_t *num_offsets,
- char **data, mach_msg_type_number_t *data_len)
-{
- error_t err = 0;
-
- if (!cred)
- err = EOPNOTSUPP;
- else
- {
- /* True when we've allocated memory for the corresponding vector. */
- int al_ports = 0, al_ints = 0, al_offsets = 0, al_data = 0;
- size_t name_len = strlen (device_name) + 1;
-
-#define ENSURE_MEM(v, vl, alp, num) \
- if (!err && *vl < num) \
- { \
- err = vm_allocate (mach_task_self (), \
- (vm_address_t *)v, num * sizeof (**v), 1); \
- if (! err) \
- { \
- *vl = num; \
- alp = 1; \
- } \
- }
-
- ENSURE_MEM (ports, num_ports, al_ports, 1);
- ENSURE_MEM (ints, num_ints, al_ints, 6);
- ENSURE_MEM (offsets, num_offsets, al_offsets, 0);
- ENSURE_MEM (data, data_len, al_data, name_len);
-
- if (! err)
- err = device_open (device_master, 0, device_name, *ports);
-
- if (! err)
- {
- (*ints)[0] = STORAGE_DEVICE; /* type */
- (*ints)[1] = 0; /* flags */
- (*ints)[2] = 0; /* block_size */
- (*ints)[3] = 0; /* num_runs */
- (*ints)[4] = name_len; /* name_len */
- (*ints)[5] = 0; /* misc_len */
- *num_ints = 6;
-
- strcpy (*data, device_name);
- *data_len = name_len;
-
- *num_ports = 1;
- *ports_type = MACH_MSG_TYPE_MOVE_SEND;
-
- *num_offsets = 0;
- }
- else
- /* Some memory allocation failed (not bloody likely). */
- {
-#define DISCARD_MEM(v, vl, alp) \
- if (alp) \
- vm_deallocate (mach_task_self (), (vm_address_t)*v, *vl * sizeof (**v));
-
- DISCARD_MEM (ports, num_ports, al_ports);
- DISCARD_MEM (ints, num_ints, al_ints);
- DISCARD_MEM (offsets, num_offsets, al_offsets);
- DISCARD_MEM (data, data_len, al_data);
- }
- }
-
- return err;
-}
diff --git a/trans/fakeroot.c b/trans/fakeroot.c
new file mode 100644
index 00000000..c1102343
--- /dev/null
+++ b/trans/fakeroot.c
@@ -0,0 +1,925 @@
+/* fakeroot -- a translator for faking actions that aren't really permitted
+ Copyright (C) 2002, 2003, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <hurd/netfs.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <cthreads.h>
+#include <hurd/ihash.h>
+#include <hurd/paths.h>
+
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (fakeroot);
+
+char *netfs_server_name = "fakeroot";
+char *netfs_server_version = HURD_VERSION;
+int netfs_maxsymlinks = 16; /* arbitrary */
+
+static auth_t fakeroot_auth_port;
+
+struct netnode
+{
+ hurd_ihash_locp_t idport_locp;/* easy removal pointer in idport ihash */
+ mach_port_t idport; /* port from io_identity */
+ int openmodes; /* O_READ | O_WRITE | O_EXEC */
+ file_t file; /* port on real file */
+
+ unsigned int faked;
+};
+
+#define FAKE_UID (1 << 0)
+#define FAKE_GID (1 << 1)
+#define FAKE_AUTHOR (1 << 2)
+#define FAKE_MODE (1 << 3)
+#define FAKE_REFERENCE (1 << 4) /* got node_norefs with st_nlink > 0 */
+
+struct mutex idport_ihash_lock = MUTEX_INITIALIZER;
+struct hurd_ihash idport_ihash
+ = HURD_IHASH_INITIALIZER (offsetof (struct netnode, idport_locp));
+
+
+/* Make a new virtual node. Always consumes the ports. */
+static error_t
+new_node (file_t file, mach_port_t idport, int locked, int openmodes,
+ struct node **np)
+{
+ error_t err;
+ struct netnode *nn = calloc (1, sizeof *nn);
+ if (nn == 0)
+ {
+ mach_port_deallocate (mach_task_self (), file);
+ if (idport != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), idport);
+ if (locked)
+ mutex_unlock (&idport_ihash_lock);
+ return ENOMEM;
+ }
+ nn->file = file;
+ nn->openmodes = openmodes;
+ if (idport != MACH_PORT_NULL)
+ nn->idport = idport;
+ else
+ {
+ ino_t fileno;
+ mach_port_t fsidport;
+ assert (!locked);
+ err = io_identity (file, &nn->idport, &fsidport, &fileno);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), file);
+ free (nn);
+ return err;
+ }
+ }
+ *np = netfs_make_node (nn);
+ if (*np == 0)
+ {
+ if (locked)
+ mutex_unlock (&idport_ihash_lock);
+ err = ENOMEM;
+ }
+ else
+ {
+ if (!locked)
+ mutex_lock (&idport_ihash_lock);
+ err = hurd_ihash_add (&idport_ihash, nn->idport, *np);
+ if (!err)
+ netfs_nref (*np); /* Return a reference to the caller. */
+ mutex_unlock (&idport_ihash_lock);
+ }
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), nn->idport);
+ mach_port_deallocate (mach_task_self (), file);
+ free (nn);
+ }
+ return err;
+}
+
+/* Node NP has no more references; free all its associated storage. */
+void
+netfs_node_norefs (struct node *np)
+{
+ if (np->nn->faked != 0
+ && netfs_validate_stat (np, 0) == 0 && np->nn_stat.st_nlink > 0)
+ {
+ /* The real node still exists and we have faked some attributes.
+ We must keep our node alive in core to retain those values.
+ XXX
+ For now, we will leak the node if it gets deleted later.
+ That will keep the underlying file alive with st_nlink=0
+ until this fakeroot filesystem dies. One easy solution
+ would be to scan nodes with references=1 for st_nlink=0
+ at some convenient time, periodically or in syncfs. */
+ if ((np->nn->faked & FAKE_REFERENCE) == 0)
+ {
+ np->nn->faked |= FAKE_REFERENCE;
+ ++np->references;
+ }
+ mutex_unlock (&np->lock);
+ return;
+ }
+
+ spin_unlock (&netfs_node_refcnt_lock); /* Avoid deadlock. */
+ mutex_lock (&idport_ihash_lock);
+ spin_lock (&netfs_node_refcnt_lock);
+ /* Previous holder of this lock might have just got a reference. */
+ if (np->references > 0)
+ {
+ mutex_unlock (&idport_ihash_lock);
+ return;
+ }
+ hurd_ihash_locp_remove (&idport_ihash, np->nn->idport_locp);
+ mutex_unlock (&idport_ihash_lock);
+ mach_port_deallocate (mach_task_self (), np->nn->file);
+ mach_port_deallocate (mach_task_self (), np->nn->idport);
+ free (np->nn);
+ free (np);
+}
+
+/* Given an existing node, make sure it has NEWMODES in its openmodes.
+ If not null, FILE is a port with those openmodes. */
+static error_t
+check_openmodes (struct netnode *nn, int newmodes, file_t file)
+{
+ error_t err = 0;
+
+ if (newmodes &~ nn->openmodes)
+ {
+ /* The user wants openmodes we haven't tried before. */
+
+ if (file != MACH_PORT_NULL && (nn->openmodes & ~newmodes))
+ {
+ /* Intersecting sets.
+ We need yet another new peropen on this node. */
+ mach_port_deallocate (mach_task_self (), file);
+ file = MACH_PORT_NULL;
+ }
+ if (file == MACH_PORT_NULL);
+ {
+ enum retry_type bad_retry;
+ char bad_retryname[1024]; /* XXX */
+ err = dir_lookup (nn->file, "", nn->openmodes | newmodes, 0,
+ &bad_retry, bad_retryname, &file);
+ if (!err && (bad_retry != FS_RETRY_NORMAL
+ || bad_retryname[0] != '\0'))
+ {
+ mach_port_deallocate (mach_task_self (), file);
+ err = EGRATUITOUS;
+ }
+ }
+ if (! err)
+ {
+ /* The new port has more openmodes than
+ the old one. We can just use it now. */
+ mach_port_deallocate (mach_task_self (), nn->file);
+ nn->file = file;
+ nn->openmodes = newmodes;
+ }
+ }
+ else if (file != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), file);
+
+ return err;
+}
+
+/* This is called by netfs_S_fsys_getroot. */
+error_t
+netfs_check_open_permissions (struct iouser *user, struct node *np,
+ int flags, int newnode)
+{
+ return check_openmodes (np->nn, flags & (O_RDWR|O_EXEC), MACH_PORT_NULL);
+}
+
+error_t
+netfs_S_dir_lookup (struct protid *diruser,
+ char *filename,
+ int flags,
+ mode_t mode,
+ retry_type *do_retry,
+ char *retry_name,
+ mach_port_t *retry_port,
+ mach_msg_type_name_t *retry_port_type)
+{
+ struct node *dnp, *np;
+ error_t err;
+ struct protid *newpi;
+ struct iouser *user;
+ mach_port_t file;
+ mach_port_t idport, fsidport;
+ ino_t fileno;
+
+ if (!diruser)
+ return EOPNOTSUPP;
+
+ dnp = diruser->po->np;
+ err = dir_lookup (dnp->nn->file, filename,
+ flags & (O_NOLINK|O_RDWR|O_EXEC|O_CREAT|O_EXCL|O_NONBLOCK),
+ mode, do_retry, retry_name, &file);
+ if (err)
+ return err;
+
+ switch (*do_retry)
+ {
+ case FS_RETRY_REAUTH:
+ {
+ mach_port_t ref = mach_reply_port ();
+ err = io_reauthenticate (file, ref, MACH_MSG_TYPE_MAKE_SEND);
+ if (! err)
+ {
+ mach_port_deallocate (mach_task_self (), file);
+ err = auth_user_authenticate (fakeroot_auth_port, ref,
+ MACH_MSG_TYPE_MAKE_SEND,
+ retry_port);
+ }
+ mach_port_destroy (mach_task_self (), ref);
+ if (err)
+ return err;
+ }
+ *do_retry = FS_RETRY_NORMAL;
+ /*FALLTHROUGH*/
+
+ case FS_RETRY_NORMAL:
+ case FS_RETRY_MAGICAL:
+ default:
+ if (file == MACH_PORT_NULL)
+ {
+ *retry_port = MACH_PORT_NULL;
+ *retry_port_type = MACH_MSG_TYPE_COPY_SEND;
+ return 0;
+ }
+ break;
+ }
+
+ /* We have a new port to an underlying node.
+ Find or make our corresponding virtual node. */
+
+ np = 0;
+ err = io_identity (file, &idport, &fsidport, &fileno);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ else
+ {
+ mach_port_deallocate (mach_task_self (), fsidport);
+ if (fsidport == netfs_fsys_identity)
+ {
+ /* Talking to ourselves! We just looked up one of our
+ own nodes. Find the node and return it. */
+ struct protid *cred
+ = ports_lookup_port (netfs_port_bucket, file,
+ netfs_protid_class);
+ mach_port_deallocate (mach_task_self (), idport);
+ mach_port_deallocate (mach_task_self (), file);
+ if (cred == 0)
+ return EGRATUITOUS;
+ np = cred->po->np;
+ netfs_nref (np);
+ ports_port_deref (cred);
+ }
+ else
+ {
+ mutex_lock (&idport_ihash_lock);
+ np = hurd_ihash_find (&idport_ihash, idport);
+ if (np != 0)
+ {
+ /* We already know about this node. */
+ mach_port_deallocate (mach_task_self (), idport);
+ mutex_lock (&np->lock);
+ err = check_openmodes (np->nn, (flags & (O_RDWR|O_EXEC)), file);
+ if (!err)
+ netfs_nref (np);
+ mutex_unlock (&np->lock);
+ mutex_unlock (&idport_ihash_lock);
+ }
+ else
+ err = new_node (file, idport, 1, flags, &np);
+ }
+ }
+ if (err)
+ return err;
+
+ if (retry_name[0] == '\0' && *do_retry == FS_RETRY_NORMAL)
+ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK);
+ else
+ flags = 0;
+
+ err = iohelp_dup_iouser (&user, diruser->user);
+ if (!err)
+ {
+ newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po),
+ user);
+ if (! newpi)
+ {
+ iohelp_free_iouser (user);
+ err = errno;
+ }
+ else
+ {
+ *retry_port = ports_get_right (newpi);
+ *retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newpi);
+ }
+ }
+
+ netfs_nrele (np);
+ return err;
+}
+
+/* These callbacks are used only by the standard netfs_S_dir_lookup,
+ which we do not use. But the shared library requires us to define them. */
+error_t
+netfs_attempt_lookup (struct iouser *user, struct node *dir,
+ char *name, struct node **np)
+{
+ assert (! "should not be here");
+ return EIEIO;
+}
+
+error_t
+netfs_attempt_create_file (struct iouser *user, struct node *dir,
+ char *name, mode_t mode, struct node **np)
+{
+ assert (! "should not be here");
+ return EIEIO;
+}
+
+/* Make sure that NP->nn_stat is filled with the most current information.
+ CRED identifies the user responsible for the operation. NP is locked. */
+error_t
+netfs_validate_stat (struct node *np, struct iouser *cred)
+{
+ struct stat st;
+ error_t err = io_stat (np->nn->file, &st);
+ if (err)
+ return err;
+
+ if (np->nn->faked & FAKE_UID)
+ st.st_uid = np->nn_stat.st_uid;
+ if (np->nn->faked & FAKE_GID)
+ st.st_gid = np->nn_stat.st_gid;
+ if (np->nn->faked & FAKE_AUTHOR)
+ st.st_author = np->nn_stat.st_author;
+ if (np->nn->faked & FAKE_MODE)
+ st.st_mode = np->nn_stat.st_mode;
+
+ np->nn_stat = st;
+ np->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0;
+
+ return 0;
+}
+
+error_t
+netfs_attempt_chown (struct iouser *cred, struct node *np,
+ uid_t uid, uid_t gid)
+{
+ if (uid != -1)
+ {
+ np->nn->faked |= FAKE_UID;
+ np->nn_stat.st_uid = uid;
+ }
+ if (gid != -1)
+ {
+ np->nn->faked |= FAKE_GID;
+ np->nn_stat.st_gid = gid;
+ }
+ return 0;
+}
+
+error_t
+netfs_attempt_chauthor (struct iouser *cred, struct node *np, uid_t author)
+{
+ np->nn->faked |= FAKE_AUTHOR;
+ np->nn_stat.st_author = author;
+ return 0;
+}
+
+/* Return the mode that the real underlying file should have if the
+ fake mode is being set to MODE. We always give ourselves read and
+ write permission so that we can open the file as root would be able
+ to. We give ourselves execute permission iff any execute bit is
+ set in the fake mode. */
+static inline mode_t
+real_from_fake_mode (mode_t mode)
+{
+ return mode | S_IREAD | S_IWRITE | (((mode << 3) | (mode << 6)) & S_IEXEC);
+}
+
+/* This should attempt a chmod call for the user specified by CRED on
+ locked 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 *np, mode_t mode)
+{
+ if ((mode & S_IFMT) == 0)
+ mode |= np->nn_stat.st_mode & S_IFMT;
+ if ((mode & S_IFMT) != (np->nn_stat.st_mode & S_IFMT))
+ return EOPNOTSUPP;
+ if (((mode | (mode << 3) | (mode << 6))
+ ^ (np->nn_stat.st_mode | (np->nn_stat.st_mode << 3)
+ | (np->nn_stat.st_mode << 6)))
+ & S_IEXEC)
+ {
+ /* We are changing the executable bit, so this is not all fake. We
+ don't bother with error checking since the fake mode change should
+ always succeed--worst case a later open will get EACCES. */
+ (void) file_chmod (np->nn->file, real_from_fake_mode (mode));
+ }
+ np->nn->faked |= FAKE_MODE;
+ np->nn_stat.st_mode = mode;
+ return 0;
+}
+
+/* The user must define this function. Attempt to turn locked node NP
+ (user CRED) into a symlink with target NAME. */
+error_t
+netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name)
+{
+ int namelen = strlen (name) + 1;
+ char trans[sizeof _HURD_SYMLINK + namelen];
+ memcpy (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK);
+ memcpy (&trans[sizeof _HURD_SYMLINK], name, namelen);
+ return file_set_translator (np->nn->file,
+ FS_TRANS_EXCL|FS_TRANS_SET,
+ FS_TRANS_EXCL|FS_TRANS_SET, 0,
+ trans, sizeof trans,
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
+}
+
+error_t
+netfs_attempt_mkdev (struct iouser *cred, struct node *np,
+ mode_t type, dev_t indexes)
+{
+ char *trans = 0;
+ int translen = asprintf (&trans, "%s%c%d%c%d",
+ S_ISCHR (type) ? _HURD_CHRDEV : _HURD_BLKDEV,
+ '\0', major (indexes), '\0', minor (indexes));
+ if (trans == 0)
+ return ENOMEM;
+ else
+ {
+ error_t err = file_set_translator (np->nn->file,
+ FS_TRANS_EXCL|FS_TRANS_SET,
+ FS_TRANS_EXCL|FS_TRANS_SET, 0,
+ trans, translen + 1,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_COPY_SEND);
+ free (trans);
+ return err;
+ }
+}
+
+error_t
+netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags)
+{
+ return file_chflags (np->nn->file, flags);
+}
+
+error_t
+netfs_attempt_utimes (struct iouser *cred, struct node *np,
+ struct timespec *atime, struct timespec *mtime)
+{
+ union tv
+ {
+ struct timeval tv;
+ time_value_t tvt;
+ };
+ union tv a, m;
+ if (atime)
+ {
+ TIMESPEC_TO_TIMEVAL (&a.tv, atime);
+ }
+ else
+ a.tv.tv_sec = a.tv.tv_usec = -1;
+ if (mtime)
+ {
+ TIMESPEC_TO_TIMEVAL (&m.tv, mtime);
+ }
+ else
+ m.tv.tv_sec = m.tv.tv_usec = -1;
+
+ return file_utimes (np->nn->file, a.tvt, m.tvt);
+}
+
+error_t
+netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size)
+{
+ return file_set_size (np->nn->file, size);
+}
+
+error_t
+netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st)
+{
+ return file_statfs (np->nn->file, st);
+}
+
+error_t
+netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
+{
+ return file_sync (np->nn->file, wait, 0);
+}
+
+error_t
+netfs_attempt_syncfs (struct iouser *cred, int wait)
+{
+ return 0;
+}
+
+error_t
+netfs_attempt_mkdir (struct iouser *user, struct node *dir,
+ char *name, mode_t mode)
+{
+ return dir_mkdir (dir->nn->file, name, mode | S_IRWXU);
+}
+
+
+/* XXX
+ Removing a node should mark the netnode so that it is GC'd when
+ it has no hard refs.
+ */
+
+error_t
+netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
+{
+ return dir_unlink (dir->nn->file, name);
+}
+
+error_t
+netfs_attempt_rename (struct iouser *user, struct node *fromdir,
+ char *fromname, struct node *todir,
+ char *toname, int excl)
+{
+ return dir_rename (fromdir->nn->file, fromname,
+ todir->nn->file, toname, excl);
+}
+
+error_t
+netfs_attempt_rmdir (struct iouser *user,
+ struct node *dir, char *name)
+{
+ return dir_rmdir (dir->nn->file, name);
+}
+
+error_t
+netfs_attempt_link (struct iouser *user, struct node *dir,
+ struct node *file, char *name, int excl)
+{
+ return dir_link (dir->nn->file, file->nn->file, name, excl);
+}
+
+error_t
+netfs_attempt_mkfile (struct iouser *user, struct node *dir,
+ mode_t mode, struct node **np)
+{
+ file_t newfile;
+ error_t err = dir_mkfile (dir->nn->file, O_RDWR|O_EXEC,
+ real_from_fake_mode (mode), &newfile);
+ mutex_unlock (&dir->lock);
+ if (err == 0)
+ err = new_node (newfile, MACH_PORT_NULL, 0, O_RDWR|O_EXEC, np);
+ return err;
+}
+
+error_t
+netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf)
+{
+ char transbuf[sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1];
+ char *trans = transbuf;
+ size_t translen = sizeof transbuf;
+ error_t err = file_get_translator (np->nn->file, &trans, &translen);
+ if (err == 0)
+ {
+ if (translen < sizeof _HURD_SYMLINK
+ || memcmp (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK) != 0)
+ err = EINVAL;
+ else
+ {
+ assert (translen <= sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1);
+ memcpy (buf, &trans[sizeof _HURD_SYMLINK],
+ translen - sizeof _HURD_SYMLINK);
+ }
+ if (trans != transbuf)
+ munmap (trans, translen);
+ }
+ return err;
+}
+
+error_t
+netfs_attempt_read (struct iouser *cred, struct node *np,
+ off_t offset, size_t *len, void *data)
+{
+ char *buf = data;
+ error_t err = io_read (np->nn->file, &buf, len, offset, *len);
+ if (err == 0 && buf != data)
+ {
+ memcpy (data, buf, *len);
+ munmap (buf, *len);
+ }
+ return err;
+}
+
+error_t
+netfs_attempt_write (struct iouser *cred, struct node *np,
+ off_t offset, size_t *len, void *data)
+{
+ return io_write (np->nn->file, data, *len, offset, len);
+}
+
+error_t
+netfs_report_access (struct iouser *cred, struct node *np, int *types)
+{
+ *types = O_RDWR|O_EXEC;
+ return 0;
+}
+
+error_t
+netfs_get_dirents (struct iouser *cred, struct node *dir,
+ int entry, int nentries, char **data,
+ mach_msg_type_number_t *datacnt,
+ vm_size_t bufsize, int *amt)
+{
+ return dir_readdir (dir->nn->file, data, datacnt,
+ entry, nentries, bufsize, amt);
+}
+
+error_t
+netfs_file_get_storage_info (struct iouser *cred,
+ struct node *np,
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints,
+ mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data,
+ mach_msg_type_number_t *data_len)
+{
+ *ports_type = MACH_MSG_TYPE_MOVE_SEND;
+ return file_get_storage_info (np->nn->file,
+ ports, num_ports,
+ ints, num_ints,
+ offsets, num_offsets,
+ data, data_len);
+}
+
+kern_return_t
+netfs_S_file_exec (struct protid *user,
+ task_t task,
+ int flags,
+ char *argv,
+ size_t argvlen,
+ char *envp,
+ size_t envplen,
+ mach_port_t *fds,
+ size_t fdslen,
+ mach_port_t *portarray,
+ size_t portarraylen,
+ int *intarray,
+ size_t intarraylen,
+ mach_port_t *deallocnames,
+ size_t deallocnameslen,
+ mach_port_t *destroynames,
+ size_t destroynameslen)
+{
+ error_t err;
+ file_t file;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ mutex_lock (&user->po->np->lock);
+ err = check_openmodes (user->po->np->nn, O_EXEC, MACH_PORT_NULL);
+ file = user->po->np->nn->file;
+ if (!err)
+ err = mach_port_mod_refs (mach_task_self (),
+ file, MACH_PORT_RIGHT_SEND, 1);
+ mutex_unlock (&user->po->np->lock);
+
+ if (!err)
+ {
+ /* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to
+ retry an interrupted call that would have consumed the rights. */
+ err = file_exec (user->po->np->nn->file, task, flags, argv, argvlen,
+ envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
+ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
+ intarray, intarraylen, deallocnames, deallocnameslen,
+ destroynames, destroynameslen);
+ mach_port_deallocate (mach_task_self (), file);
+ }
+
+ if (err == 0)
+ {
+ size_t i;
+ mach_port_deallocate (mach_task_self (), task);
+ for (i = 0; i < fdslen; ++i)
+ mach_port_deallocate (mach_task_self (), fds[i]);
+ for (i = 0; i < portarraylen; ++i)
+ mach_port_deallocate (mach_task_self (), portarray[i]);
+ }
+ return err;
+}
+
+error_t
+netfs_S_io_map (struct protid *user,
+ mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype,
+ mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+ *rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND;
+
+ mutex_lock (&user->po->np->lock);
+ err = io_map (user->po->np->nn->file, rdobj, wrobj);
+ mutex_unlock (&user->po->np->lock);
+ return err;
+}
+
+error_t
+netfs_S_io_map_cntl (struct protid *user,
+ mach_port_t *obj,
+ mach_msg_type_name_t *objtype)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+ *objtype = MACH_MSG_TYPE_MOVE_SEND;
+
+ mutex_lock (&user->po->np->lock);
+ err = io_map_cntl (user->po->np->nn->file, obj);
+ mutex_unlock (&user->po->np->lock);
+ return err;
+}
+
+#define NETFS_S_SIMPLE(name) \
+error_t \
+netfs_S_##name (struct protid *user) \
+{ \
+ error_t err; \
+ \
+ if (!user) \
+ return EOPNOTSUPP; \
+ \
+ mutex_lock (&user->po->np->lock); \
+ err = name (user->po->np->nn->file); \
+ mutex_unlock (&user->po->np->lock); \
+ return err; \
+}
+
+NETFS_S_SIMPLE (io_get_conch)
+NETFS_S_SIMPLE (io_release_conch)
+NETFS_S_SIMPLE (io_eofnotify)
+NETFS_S_SIMPLE (io_readnotify)
+NETFS_S_SIMPLE (io_readsleep)
+NETFS_S_SIMPLE (io_sigio)
+
+error_t
+netfs_S_io_prenotify (struct protid *user,
+ vm_offset_t start, vm_offset_t stop)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ mutex_lock (&user->po->np->lock);
+ err = io_prenotify (user->po->np->nn->file, start, stop);
+ mutex_unlock (&user->po->np->lock);
+ return err;
+}
+
+error_t
+netfs_S_io_postnotify (struct protid *user,
+ vm_offset_t start, vm_offset_t stop)
+{
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ mutex_lock (&user->po->np->lock);
+ err = io_postnotify (user->po->np->nn->file, start, stop);
+ mutex_unlock (&user->po->np->lock);
+ return err;
+}
+
+/* This overrides the library's definition. */
+int
+netfs_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ int netfs_fs_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_io_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_ifsock_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ if (netfs_io_server (inp, outp)
+ || netfs_fs_server (inp, outp)
+ || ports_notify_server (inp, outp)
+ || netfs_fsys_server (inp, outp)
+ /* XXX we should intercept interrupt_operation and do
+ the ports_S_interrupt_operation work as well as
+ sending an interrupt_operation to the underlying file.
+ */
+ || ports_interrupt_server (inp, outp))
+ return 1;
+ else
+ {
+ /* We didn't recognize the message ID, so pass the message through
+ unchanged to the underlying file. */
+ struct protid *cred = ports_lookup_port (netfs_port_bucket,
+ inp->msgh_local_port,
+ netfs_protid_class);
+ if (cred == 0)
+ /* This must be an unknown message on our fsys control port. */
+ return 0;
+ else
+ {
+ error_t err;
+ assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits)
+ == MACH_MSG_TYPE_MOVE_SEND);
+ inp->msgh_bits = (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
+ MACH_MSGH_BITS_REMOTE (inp->msgh_bits));
+ inp->msgh_local_port = inp->msgh_remote_port; /* reply port */
+ inp->msgh_remote_port = cred->po->np->nn->file;
+ err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ assert_perror (err); /* XXX should synthesize reply */
+ ports_port_deref (cred);
+ return 1;
+ }
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+
+ struct argp argp = { NULL, NULL, NULL, "\
+A translator for faking privileged access to an underlying filesystem.\v\
+This translator appears to give transparent access to the underlying \
+directory node. However, all accesses are made using the credentials \
+of the translator regardless of the client and the translator fakes \
+success for chown and chmod operations that only root could actually do, \
+reporting the faked IDs and modes in later stat calls, and allows \
+any user to open nodes regardless of permissions as is done for root." };
+
+ /* Parse our command line arguments (all none of them). */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ fakeroot_auth_port = getauth ();
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ netfs_init ();
+
+ /* Get our underlying node (we presume it's a directory) and use
+ that to make the root node of the filesystem. */
+ err = new_node (netfs_startup (bootstrap, O_READ), MACH_PORT_NULL, 0, O_READ,
+ &netfs_root_node);
+ if (err)
+ error (5, err, "Cannot create root node");
+
+ err = netfs_validate_stat (netfs_root_node, 0);
+ if (err)
+ error (6, err, "Cannot stat underlying node");
+
+ netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS | S_IATRANS);
+ netfs_root_node->nn_stat.st_mode |= S_IROOT;
+ netfs_root_node->nn->faked |= FAKE_MODE;
+
+ netfs_server_loop (); /* Never returns. */
+
+ /*NOTREACHED*/
+ return 0;
+}
diff --git a/trans/fifo.c b/trans/fifo.c
index 8ce5916a..39043acd 100644
--- a/trans/fifo.c
+++ b/trans/fifo.c
@@ -1,8 +1,7 @@
/* A translator for fifos
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,12 +18,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
-#include <getopt.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <fcntl.h>
+#include <argp.h>
#include <cthreads.h>
#include <hurd.h>
@@ -33,6 +33,8 @@
#include <hurd/fsys.h>
#include <hurd/pipe.h>
+#include <version.h>
+
/* Global options. These defaults are the standard ones, I think... */
int wait_for_reader = 1, wait_for_writer = 1;
int one_reader = 1;
@@ -48,106 +50,65 @@ struct mutex active_fifo_lock;
/* Signal this when ACTIVE_FIFO may have changed. */
struct condition active_fifo_changed;
-/* ---------------------------------------------------------------- */
+const char *argp_program_version = STANDARD_HURD_VERSION (fifo);
-#define USAGE "Usage: %s [OPTION...]\n"
+static struct argp_option options[] =
+{
+ { "multiple-readers", 'm', 0, 0, "Allow multiple simultaneous readers" },
+ { "noblock", 'n', 0, 0, "Don't block on open" },
+ { "dgram", 'd', 0, 0, "Reads reflect write record boundaries" },
+ { 0 }
+};
-static void
-usage(int status)
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
{
- if (status != 0)
- fprintf(stderr, "Try `%s --help' for more information.\n",
- program_invocation_name);
- else
+ switch (key)
{
- printf(USAGE, program_invocation_name);
- printf("\
-\n\
- -r, --multiple-readers Allow multiple simultaneous readers\n\
- -n, --noblock Don't block on open\n\
- -d, --dgram Reads reflect write record boundaries\n\
- --help Give this usage message\n\
-");
+ case 'm': one_reader = 0; break;
+ case 'n': wait_for_reader = wait_for_writer = 0; break;
+ case 'd': fifo_pipe_class = seqpack_pipe_class; break;
+ default: return ARGP_ERR_UNKNOWN;
}
-
- exit(status);
+ return 0;
}
-#define SHORT_OPTIONS "&"
-
-static struct option options[] =
-{
- {"multiple-readers", no_argument, 0, 'r'},
- {"noblock", no_argument, 0, 'n'},
- {"dgram", no_argument, 0, 'd'},
- {"help", no_argument, 0, '&'},
- {0, 0, 0, 0}
+static const struct argp argp = {
+ options, parse_opt, 0, "Translator for fifos."
};
-/* ---------------------------------------------------------------- */
-
-struct port_class *trivfs_protid_portclasses[1];
-struct port_class *trivfs_cntl_portclasses[1];
-int trivfs_protid_nportclasses = 1;
-int trivfs_cntl_nportclasses = 1;
-
-void
+int
main (int argc, char **argv)
{
- int opt;
error_t err;
mach_port_t bootstrap;
- struct port_bucket *port_bucket;
- struct port_class *fifo_port_class, *fsys_port_class;
+ struct trivfs_control *fsys;
fifo_pipe_class = stream_pipe_class;
- while ((opt = getopt_long(argc, argv, SHORT_OPTIONS, options, 0)) != EOF)
- switch (opt)
- {
- case 'r': one_reader = 0; break;
- case 'n': wait_for_reader = wait_for_writer = 0; break;
- case 'd': fifo_pipe_class = seqpack_pipe_class;
- case '&': usage(0);
- default: usage(1);
- }
-
- if (argc != 1)
- {
- fprintf(stderr, "Usage: %s", program_invocation_name);
- exit(1);
- }
-
- port_bucket = ports_create_bucket ();
- fifo_port_class = ports_create_class (trivfs_clean_protid, 0);
- fsys_port_class = ports_create_class (trivfs_clean_cntl, 0);
-
- trivfs_protid_portclasses[0] = fifo_port_class;
- trivfs_cntl_portclasses[0] = fsys_port_class;
+ argp_parse (&argp, argc, argv, 0, 0, 0);
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
- error(1, 0, "must be started as a translator");
+ error (1, 0, "must be started as a translator");
/* Reply to our parent */
- err = trivfs_startup(bootstrap, 0,
- fsys_port_class, port_bucket,
- fifo_port_class, port_bucket,
- NULL);
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
if (err)
- error(3, err, "Contacting parent");
+ error (3, err, "Contacting parent");
/* Launch. */
do
{
- ports_enable_class (fifo_port_class);
- ports_manage_port_operations_multithread (port_bucket,
+ ports_enable_class (fsys->protid_class);
+ ports_manage_port_operations_multithread (fsys->pi.bucket,
trivfs_demuxer,
- 30*1000, 5*60*1000, 0, 0);
+ 30*1000, 5*60*1000, 0);
}
- while (ports_count_class (fifo_port_class) > 0);
+ while (ports_count_class (fsys->protid_class) > 0);
- exit(0);
+ return 0;
}
/* ---------------------------------------------------------------- */
@@ -163,15 +124,17 @@ open_hook (struct trivfs_peropen *po)
mutex_lock (&active_fifo_lock);
/* Wait until the active fifo has changed so that CONDITION is true. */
-#define WAIT(condition, noblock_err) \
- while (!err && !(condition)) \
- if (flags & O_NONBLOCK) \
- { \
- err = noblock_err; \
- break; \
- } \
- else if (hurd_condition_wait (&active_fifo_changed, &active_fifo_lock)) \
- err = EINTR;
+#define WAIT(condition, noblock_err) \
+ while (!err && !(condition)) \
+ { \
+ if (flags & O_NONBLOCK) \
+ { \
+ err = noblock_err; \
+ break; \
+ } \
+ else if (hurd_condition_wait (&active_fifo_changed, &active_fifo_lock)) \
+ err = EINTR; \
+ }
if (flags & O_READ)
/* When opening for read, what we do depends on what mode this server
@@ -354,13 +317,14 @@ trivfs_goaway (struct trivfs_control *cntl, int flags)
mapping; they will set none of the ports and return an error. Such
objects can still be accessed by io_read and io_write. */
error_t
-trivfs_S_io_map(struct trivfs_protid *cred,
- memory_object_t *rdobj,
- mach_msg_type_name_t *rdtype,
- memory_object_t *wrobj,
- mach_msg_type_name_t *wrtype)
+trivfs_S_io_map (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
{
- return EINVAL;
+ return EOPNOTSUPP;
}
/* ---------------------------------------------------------------- */
@@ -443,7 +407,7 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
error_t
trivfs_S_io_select (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
- int *select_type, int *tag)
+ int *select_type)
{
struct pipe *pipe;
error_t err = 0;
@@ -455,26 +419,30 @@ trivfs_S_io_select (struct trivfs_protid *cred,
pipe = cred->po->hook;
if (*select_type & SELECT_READ)
- if (cred->po->openmodes & O_READ)
- {
- mutex_lock (&pipe->lock);
- if (pipe_wait_readable (pipe, 1, 1) != EWOULDBLOCK)
- ready |= SELECT_READ; /* Data immediately readable (or error). */
- mutex_unlock (&pipe->lock);
- }
- else
- ready |= SELECT_READ; /* Error immediately available... */
+ {
+ if (cred->po->openmodes & O_READ)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_readable (pipe, 1, 1) != EWOULDBLOCK)
+ ready |= SELECT_READ; /* Data immediately readable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_READ; /* Error immediately available... */
+ }
if (*select_type & SELECT_WRITE)
- if (cred->po->openmodes & O_WRITE)
- {
- mutex_lock (&pipe->lock);
- if (pipe_wait_writable (pipe, 1) != EWOULDBLOCK)
- ready |= SELECT_WRITE; /* Data immediately writable (or error). */
- mutex_unlock (&pipe->lock);
- }
- else
- ready |= SELECT_WRITE; /* Error immediately available... */
+ {
+ if (cred->po->openmodes & O_WRITE)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_writable (pipe, 1) != EWOULDBLOCK)
+ ready |= SELECT_WRITE; /* Data immediately writable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_WRITE; /* Error immediately available... */
+ }
if (ready)
*select_type = ready;
@@ -539,7 +507,7 @@ trivfs_S_file_set_size (struct trivfs_protid *cred,
/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
will tell you which of O_READ, O_WRITE, and O_EXEC the object can
- be used for. The O_ASYNC bit affects icky async I/O; good async
+ be used for. The O_ASYNC bit affects icky async I/O; good async
I/O is done through io_async which is orthogonal to these calls. */
error_t
diff --git a/trans/firmlink.c b/trans/firmlink.c
new file mode 100644
index 00000000..087e19d0
--- /dev/null
+++ b/trans/firmlink.c
@@ -0,0 +1,277 @@
+/* A translator for `firmlinks'
+
+ Copyright (C) 1997,98,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+#include <sys/mman.h>
+
+#include <hurd/trivfs.h>
+
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (firmlink);
+
+static const struct argp_option options[] =
+{
+ { 0 }
+};
+
+static const char args_doc[] = "TARGET";
+static const char doc[] = "A translator for firmlinks."
+"\vA firmlink is sort of half-way between a symbolic link and a hard link:"
+"\n"
+"\nLike a symbolic link, it is `by name', and contains no actual reference to"
+" the target. However, the lookup returns a node which will redirect parent"
+" lookups so that attempts to find the cwd that go through the link will"
+" reflect the link name, not the target name. The target referenced by the"
+" firmlink is looked up in the namespace of the translator, not the client.";
+
+/* Link parameters. */
+static char *target = 0; /* What we translate too. */
+
+/* Parse a single option/argument. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ if (key == ARGP_KEY_ARG && state->arg_num == 0)
+ target = arg;
+ else if (key == ARGP_KEY_ARG || key == ARGP_KEY_NO_ARGS)
+ argp_usage (state);
+ else
+ return ARGP_ERR_UNKNOWN;
+ return 0;
+}
+
+static struct argp argp = { options, parse_opt, args_doc, doc };
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* Parse our options... */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (2, err, "Contacting parent");
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
+ 2 * 60 * 1000, 0, 0);
+
+ return 0;
+}
+
+/* Return in LINK the node that TARGET_NAME resolves to, with its parent
+ replaced by PARENT. FLAGS are the flags to open TARGET_NAME with. */
+static error_t
+firmlink (mach_port_t parent, const char *target_name, int flags,
+ mach_port_t *link)
+{
+ error_t err;
+ file_t authed_link;
+ file_t target = file_name_lookup (target_name, flags & ~O_CREAT, 0);
+
+ if (target == MACH_PORT_NULL)
+ return errno;
+
+ err = file_reparent (target, parent, &authed_link);
+ mach_port_deallocate (mach_task_self (), target);
+ mach_port_deallocate (mach_task_self (), parent);
+
+ if (! err)
+ {
+ err = io_restrict_auth (authed_link, link, 0, 0, 0, 0);
+ mach_port_deallocate (mach_task_self (), authed_link);
+ }
+
+ return err;
+}
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ;
+
+/* Return the root node of our file system: A firmlink to TARGET, unless
+ TARGET doesn't exist, in which case we return a symlink-like node. */
+static error_t
+getroot (struct trivfs_control *cntl,
+ mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type)
+{
+ error_t err = firmlink (dotdot, target, flags, node);
+
+ if (err == ENOENT)
+ /* No target? Act like a link. */
+ return EAGAIN;
+
+ if (! err)
+ {
+ *node_type = MACH_MSG_TYPE_MOVE_SEND;
+ *do_retry = FS_RETRY_REAUTH;
+ retry_name[0] = '\0';
+ }
+
+ return err;
+}
+
+/* Called by trivfs_S_fsys_getroot before any other processing takes place;
+ if the return value is EAGAIN, normal trivfs getroot processing continues,
+ otherwise the rpc returns with that return value. */
+error_t (*trivfs_getroot_hook) () = getroot;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_size = strlen (target);
+ st->st_blocks = 0;
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFLNK;
+}
+
+/* Shutdown the filesystem. */
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ error_t err;
+ int force = (flags & FSYS_GOAWAY_FORCE);
+ struct port_bucket *bucket = ((struct port_info *)cntl)->bucket;
+
+ err = ports_inhibit_bucket_rpcs (bucket);
+ if (err == EINTR || (err && !force))
+ return err;
+
+ if (ports_count_class (cntl->protid_class) > 0 && !force)
+ /* Still some opens, and we're not being forced to go away, so don't. */
+ {
+ ports_enable_class (cntl->protid_class);
+ ports_resume_bucket_rpcs (bucket);
+ return EBUSY;
+ }
+
+ exit (0);
+}
+
+/* We store the file offset in po->hook (ick!) */
+
+/* Read data from an IO object. If offset if -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ error_t err = 0;
+
+ if (! cred)
+ err = EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ err = EBADF;
+ else
+ {
+ size_t max = strlen (target);
+ intptr_t start = offs >= 0 ? offs : (intptr_t)cred->po->hook;
+ if (start < 0)
+ return EINVAL;
+ if (start + amount > max)
+ amount = max - start;
+ if (amount > *data_len)
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = (*data == MAP_FAILED) ? errno : 0;
+ if (!err && amount > 0)
+ {
+ memcpy (*data, target + start, amount);
+ if (offs < 0)
+ cred->po->hook = (void *)(start + amount); /* Update PO offset. */
+ }
+ *data_len = amount;
+ }
+
+ return err;
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_msg_type_number_t *amount)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+ else if ((intptr_t)cred->po->hook < 0)
+ return EINVAL;
+ else
+ *amount = strlen (target) - (intptr_t)cred->po->hook;
+ return 0;
+}
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offset, int whence, off_t *new_offset)
+{
+ return EOPNOTSUPP;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *type)
+{
+ return EOPNOTSUPP;
+}
diff --git a/trans/fwd.c b/trans/fwd.c
index 6b90d333..f30aad1a 100644
--- a/trans/fwd.c
+++ b/trans/fwd.c
@@ -4,7 +4,7 @@
and forward the request to the server if they find one, otherwise doing
the translation themselves.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1998, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -26,7 +26,7 @@
#include <stdio.h>
#include <hurd/fshelp.h>
-void
+int
main (int argc, char **argv)
{
error_t err;
@@ -34,18 +34,18 @@ main (int argc, char **argv)
if (argc < 2 || *argv[1] == '-')
{
- fprintf(stderr, "Usage: %s SERVER [TRANS_NAME [TRANS_ARG...]]",
- program_invocation_name);
- exit(1);
+ fprintf (stderr, "Usage: %s SERVER [TRANS_NAME [TRANS_ARG...]]\n",
+ program_invocation_name);
+ return 1;
}
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
- error(2, 0, "must be started as a translator");
+ error (2, 0, "must be started as a translator");
err = fshelp_delegate_translation (argv[1], bootstrap, argv + 2);
if (err)
error (3, err, "%s", argv[1]);
- exit (0);
+ return 0;
}
diff --git a/trans/hello-mt.c b/trans/hello-mt.c
new file mode 100644
index 00000000..b933cfde
--- /dev/null
+++ b/trans/hello-mt.c
@@ -0,0 +1,331 @@
+/* hello-mt.c - A trivial single-file translator, multithreaded version
+ Copyright (C) 1998,99,2001,02,2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#define _GNU_SOURCE 1
+
+#include <hurd/trivfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <cthreads.h>
+#include <rwlock.h>
+
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (hello-mt);
+
+/* The message we return when we are read. */
+static const char hello[] = "Hello, world!\n";
+static char *contents = (char *) hello;
+static size_t contents_len = sizeof hello - 1;
+
+/* This lock protects access to contents and contents_len. */
+static struct rwlock contents_lock;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+/* NOTE: This example is not robust: it is possible to trigger some
+ assertion failures because we don't implement the following:
+
+ $ cd /src/hurd/libtrivfs
+ $ grep -l 'assert.*!trivfs_support_read' *.c |
+ xargs grep '^trivfs_S_' | sed 's/^[^:]*:\([^ ]*\).*$/\1/'
+ trivfs_S_io_get_openmodes
+ trivfs_S_io_clear_some_openmodes
+ trivfs_S_io_set_some_openmodes
+ trivfs_S_io_set_all_openmodes
+ trivfs_S_io_readable
+ trivfs_S_io_select
+ $
+
+ For that reason, you should run this as an active translator
+ `settrans -ac testnode /path/to/thello' so that you can see the
+ error messages when they appear. */
+
+/* A hook for us to keep track of the file descriptor state. */
+struct open
+{
+ struct mutex lock;
+ off_t offs;
+};
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ /* Mark the node as a read-only plain file. */
+ st->st_mode &= ~(S_IFMT | ALLPERMS);
+ st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
+ st->st_size = contents_len; /* No need to lock for reading one word. */
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ exit (0);
+}
+
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+ struct open *op = malloc (sizeof (struct open));
+ if (op == NULL)
+ return ENOMEM;
+
+ /* Initialize the offset. */
+ op->offs = 0;
+ mutex_init (&op->lock);
+ peropen->hook = op;
+ return 0;
+}
+
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+ struct open *op = peropen->hook;
+
+ mutex_clear (&op->lock);
+ free (op);
+}
+
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ struct open *op;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ op = cred->po->hook;
+
+ mutex_lock (&op->lock);
+
+ /* Get the offset. */
+ if (offs == -1)
+ offs = op->offs;
+
+ rwlock_reader_lock (&contents_lock);
+
+ /* Prune the amount they want to read. */
+ if (offs > contents_len)
+ offs = contents_len;
+ if (offs + amount > contents_len)
+ amount = contents_len - offs;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ {
+ mutex_unlock (&op->lock);
+ rwlock_reader_unlock (&contents_lock);
+ return ENOMEM;
+ }
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, contents + offs, amount);
+
+ /* Update the saved offset. */
+ op->offs += amount;
+ }
+
+ mutex_unlock (&op->lock);
+
+ rwlock_reader_unlock (&contents_lock);
+
+ *data_len = amount;
+ return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ struct open *op;
+ error_t err = 0;
+ if (! cred)
+ return EOPNOTSUPP;
+
+ op = cred->po->hook;
+
+ mutex_lock (&op->lock);
+
+ switch (whence)
+ {
+ case SEEK_CUR:
+ offs += op->offs;
+ goto check;
+ case SEEK_END:
+ offs += contents_len;
+ case SEEK_SET:
+ check:
+ if (offs >= 0)
+ {
+ *new_offs = op->offs = offs;
+ break;
+ }
+ default:
+ err = EINVAL;
+ }
+
+ mutex_unlock (&op->lock);
+
+ return err;
+}
+
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+ is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+
+/* Options processing. We accept the same options on the command line
+ and from fsys_set_options. */
+
+static const struct argp_option options[] =
+{
+ {"contents", 'c', "STRING", 0, "Specify the contents of the virtual file"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'c':
+ {
+ char *new = strdup (arg);
+ if (new == NULL)
+ return ENOMEM;
+ rwlock_writer_lock (&contents_lock);
+ if (contents != hello)
+ free (contents);
+ contents = new;
+ contents_len = strlen (new);
+ rwlock_writer_unlock (&contents_lock);
+ break;
+ }
+ }
+ return 0;
+}
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+ char *opt;
+
+ rwlock_reader_lock (&contents_lock);
+ err = asprintf (&opt, "--contents=%s", contents) < 0 ? ENOMEM : 0;
+ rwlock_reader_unlock (&contents_lock);
+
+ if (!err)
+ {
+ err = argz_add (argz, argz_len, opt);
+ free (opt);
+ }
+
+ return err;
+}
+
+static struct argp hello_argp =
+{ options, parse_opt, 0,
+ "A multi-threaded translator providing a warm greeting." };
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &hello_argp;
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* Initialize the lock that will protect CONTENTS and CONTENTS_LEN.
+ We must do this before argp_parse, because parse_opt (above) will
+ use the lock. */
+ rwlock_init (&contents_lock);
+
+ /* We use the same argp for options available at startup
+ as for options we'll accept in an fsys_set_options RPC. */
+ argp_parse (&hello_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
+ 10 * 1000, /* idle thread */
+ 10 * 60 * 1000, /* idle server */
+ 0);
+
+ return 0;
+}
diff --git a/trans/hello.c b/trans/hello.c
new file mode 100644
index 00000000..c49feeb2
--- /dev/null
+++ b/trans/hello.c
@@ -0,0 +1,291 @@
+/* hello.c - A trivial single-file translator
+ Copyright (C) 1998,1999,2001,02,2006 Free Software Foundation, Inc.
+ Gordon Matzigkeit <gord@fig.org>, 1999
+ 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 */
+
+#define _GNU_SOURCE 1
+
+#include <hurd/trivfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (hello);
+
+/* The message we return when we are read. */
+static const char hello[] = "Hello, world!\n";
+static char *contents = (char *) hello;
+static size_t contents_len = sizeof hello - 1;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+/* NOTE: This example is not robust: it is possible to trigger some
+ assertion failures because we don't implement the following:
+
+ $ cd /src/hurd/libtrivfs
+ $ grep -l 'assert.*!trivfs_support_read' *.c |
+ xargs grep '^trivfs_S_' | sed 's/^[^:]*:\([^ ]*\).*$/\1/'
+ trivfs_S_io_get_openmodes
+ trivfs_S_io_clear_some_openmodes
+ trivfs_S_io_set_some_openmodes
+ trivfs_S_io_set_all_openmodes
+ trivfs_S_io_readable
+ trivfs_S_io_select
+ $
+
+ For that reason, you should run this as an active translator
+ `settrans -ac testnode /path/to/thello' so that you can see the
+ error messages when they appear. */
+
+/* A hook for us to keep track of the file descriptor state. */
+struct open
+{
+ off_t offs;
+};
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ /* Mark the node as a read-only plain file. */
+ st->st_mode &= ~(S_IFMT | ALLPERMS);
+ st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
+ st->st_size = contents_len;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ exit (0);
+}
+
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+ struct open *op = malloc (sizeof (struct open));
+ if (op == NULL)
+ return ENOMEM;
+
+ /* Initialize the offset. */
+ op->offs = 0;
+ peropen->hook = op;
+ return 0;
+}
+
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+ free (peropen->hook);
+}
+
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ struct open *op;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ /* Get the offset. */
+ op = cred->po->hook;
+ if (offs == -1)
+ offs = op->offs;
+
+ /* Prune the amount they want to read. */
+ if (offs > contents_len)
+ offs = contents_len;
+ if (offs + amount > contents_len)
+ amount = contents_len - offs;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ {
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*data == MAP_FAILED)
+ return ENOMEM;
+ }
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, contents + offs, amount);
+
+ /* Update the saved offset. */
+ op->offs += amount;
+ }
+
+ *data_len = amount;
+ return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ struct open *op;
+ error_t err = 0;
+ if (! cred)
+ return EOPNOTSUPP;
+
+ op = cred->po->hook;
+ switch (whence)
+ {
+ case SEEK_CUR:
+ offs += op->offs;
+ goto check;
+ case SEEK_END:
+ offs += contents_len;
+ case SEEK_SET:
+ check:
+ if (offs >= 0)
+ {
+ *new_offs = op->offs = offs;
+ break;
+ }
+ default:
+ err = EINVAL;
+ }
+
+ return err;
+}
+
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+ is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+
+/* Options processing. We accept the same options on the command line
+ and from fsys_set_options. */
+
+static const struct argp_option options[] =
+{
+ {"contents", 'c', "STRING", 0, "Specify the contents of the virtual file"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'c':
+ {
+ char *new = strdup (arg);
+ if (new == NULL)
+ return ENOMEM;
+ if (contents != hello)
+ free (contents);
+ contents = new;
+ contents_len = strlen (new);
+ break;
+ }
+ }
+ return 0;
+}
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+ char *opt;
+
+ if (asprintf (&opt, "--contents=%s", contents) < 0)
+ return ENOMEM;
+
+ err = argz_add (argz, argz_len, opt);
+
+ free (opt);
+
+ return err;
+}
+
+static struct argp hello_argp =
+{ options, parse_opt, 0, "A translator providing a warm greeting." };
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &hello_argp;
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* We use the same argp for options available at startup
+ as for options we'll accept in an fsys_set_options RPC. */
+ argp_parse (&hello_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer, 0);
+
+ return 0;
+}
diff --git a/trans/ifsock.c b/trans/ifsock.c
index 2e53ea96..092bb40d 100644
--- a/trans/ifsock.c
+++ b/trans/ifsock.c
@@ -1,5 +1,5 @@
/* Server for S_IFSOCK nodes
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994, 1995, 2001, 02, 2006 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,11 +23,27 @@
#include <hurd/socket.h>
#include <hurd/fsys.h>
#include <stdio.h>
+#include <stdlib.h>
#include <error.h>
#include <fcntl.h>
+#include <argp.h>
+
+#include <sys/cdefs.h>
+#ifndef __XSTRING /* Could / should (?) be provided by glibc. */
+#define __XSTRING(x) __STRING(x) /* Expand x, then stringify. */
+#endif
+
+#include <version.h>
#include "ifsock_S.h"
+const char *argp_program_version = STANDARD_HURD_VERSION (ifsock);
+
+static const char doc[] = "A translator to provide Unix domain sockets."
+"\vThis translator acts as a hook for Unix domain sockets."
+" The pflocal translator on " _SERVERS_SOCKET "/" __XSTRING(PF_LOCAL)
+" implements the sockets.";
+
mach_port_t address_port;
struct port_class *control_class;
@@ -62,6 +78,9 @@ main (int argc, char **argv)
mach_port_t pflocal;
mach_port_t bootstrap;
char buf[512];
+ const struct argp argp = { 0, 0, 0, doc };
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
control_class = ports_create_class (trivfs_clean_cntl, 0);
node_class = ports_create_class (trivfs_clean_protid, 0);
@@ -72,10 +91,11 @@ main (int argc, char **argv)
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
error(1, 0, "Must be started as a translator");
-
+
/* Reply to our parent */
err = trivfs_startup (bootstrap, 0, control_class, port_bucket,
node_class, port_bucket, NULL);
+ mach_port_deallocate (mach_task_self (), bootstrap);
if (err)
error(2, err, "Contacting parent");
@@ -87,8 +107,8 @@ main (int argc, char **argv)
address_port = MACH_PORT_NULL;
else
{
- errno = socket_fabricate_address (pflocal, AF_LOCAL, &address_port);
- if (errno)
+ err = socket_fabricate_address (pflocal, AF_LOCAL, &address_port);
+ if (err)
address_port = MACH_PORT_NULL;
mach_port_deallocate (mach_task_self (), pflocal);
}
@@ -97,7 +117,7 @@ main (int argc, char **argv)
ports_manage_port_operations_one_thread (port_bucket, demuxer, 0);
return 0;
}
-
+
void
trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
{
@@ -114,18 +134,18 @@ error_t
S_ifsock_getsockaddr (file_t sockfile,
mach_port_t *address)
{
- struct trivfs_protid *cred = ports_lookup_port (port_bucket, sockfile,
+ struct trivfs_protid *cred = ports_lookup_port (port_bucket, sockfile,
node_class);
int perms;
error_t err;
-
+
if (!cred)
return EOPNOTSUPP;
-
+
err = file_check_access (cred->realnode, &perms);
if (!err && !(perms & O_READ))
err = EACCES;
-
+
if (!err)
*address = address_port;
ports_port_deref (cred);
diff --git a/trans/magic.c b/trans/magic.c
index 952a5c28..1a8427ce 100644
--- a/trans/magic.c
+++ b/trans/magic.c
@@ -1,8 +1,6 @@
/* A translator for returning FS_RETRY_MAGIC strings.
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1999,2001,02, 03 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
@@ -19,138 +17,549 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd/fshelp.h>
+#include <hurd/fsys.h>
+#include <version.h>
+
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
#include <error.h>
-#include <hurd/fsys.h>
-#include "fsys_S.h"
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <argp.h>
+#include <argz.h>
+#include <assert.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (magic);
+
+/* This structure has all the state about one filesystem.
+ It hangs off trivfs_control->hook. */
+struct magic
+{
+ /* We chain all filesystems together so we can tell easily when they are
+ all unused. */
+ struct trivfs_control *next;
+
+ /* The magic string we return for lookups. */
+ char *magic;
+
+ int directory; /* --directory flag */
+
+ /* Pre-fab contents of dummy directory for dir_readdir.
+ Set up only under --directory. */
+ void *dirbuf;
+ size_t dirbufsize;
+
+ unsigned int nusers; /* Count of users, only with --directory. */
+};
+
+static inline void
+free_magic (struct magic *m)
+{
+ free (m->magic);
+ if (m->dirbuf)
+ munmap (m->dirbuf, m->dirbufsize);
+ free (m);
+}
+
+static struct trivfs_control *all_fsys;
-/* ---------------------------------------------------------------- */
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
-extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
-/* The magic string we return for lookups. */
-static char *magic = NULL;
+int trivfs_allow_open = O_READ;
void
-main (int argc, char **argv)
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
{
- error_t err;
- mach_port_t bootstrap, control, realnode;
-
- if (argc != 2 || *argv[1] == '-')
- {
- fprintf(stderr, "Usage: %s MAGIC", program_invocation_name);
- exit(-1);
- }
+ struct magic *const m = cred->po->cntl->hook;
- magic = argv[1];
-
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error(3, 0, "Must be started as a translator");
+ st->st_size = m->dirbufsize;
+ st->st_blocks = getpagesize () / S_BLKSIZE;
- /* Reply to our parent */
- mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &control);
- err =
- fsys_startup (bootstrap, 0, control, MACH_MSG_TYPE_MAKE_SEND, &realnode);
- if (err)
- error(1, err, "starting translator");
+ st->st_mode = ((st->st_mode & ~S_IFMT & ~ALLPERMS)
+ | S_IFDIR | S_IXUSR|S_IXGRP|S_IXOTH
+ | (st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH)));
+}
- /* Launch */
- while (1)
- {
- /* The timeout here is 10 minutes */
- err = mach_msg_server_timeout (fsys_server, 0, control,
- MACH_RCV_TIMEOUT, 1000 * 60 * 10);
- if (err == MACH_RCV_TIMED_OUT)
- exit (0);
- }
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ struct magic *const m = fsys->hook;
+
+ /* We are single-threaded, so no fancy stuff is needed here. */
+
+ if (m->nusers > 0 && !(flags & FSYS_GOAWAY_FORCE))
+ return EBUSY;
+
+ /* No more communication with the parent filesystem.
+ This running RPC should now be the only ref keeping FSYS alive. */
+ ports_destroy_right (fsys);
+ return 0;
+}
+
+
+/* Clean pointers in a struct trivfs_control when its last reference
+ vanishes before it's freed. This overrides the libtrivfs version
+ so we can clean up our hook data. */
+void
+trivfs_clean_cntl (void *arg)
+{
+ struct trivfs_control *cntl = arg;
+ struct magic *const m = cntl->hook;
+
+ /* Remove us from the list of all filesystems. */
+ struct trivfs_control **lastp = &all_fsys;
+ while (*lastp != cntl)
+ lastp = &((struct magic *) (*lastp)->hook)->next;
+ *lastp = m->next;
+
+ if (all_fsys == 0)
+ /* Nothing more to do in this life. */
+ exit (0);
+
+ mach_port_destroy (mach_task_self (), cntl->filesys_id);
+ mach_port_destroy (mach_task_self (), cntl->file_id);
+ mach_port_deallocate (mach_task_self (), cntl->underlying);
+
+ free_magic (m);
}
-/* ---------------------------------------------------------------- */
+/* This hook is used when running without --directory;
+ it circumvents basically all the trivfs machinery. */
-error_t
-S_fsys_getroot (mach_port_t fsys_t,
- mach_port_t dotdotnode,
- uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
- int flags,
- retry_type *do_retry, char *retry_name,
- mach_port_t *ret, mach_msg_type_name_t *rettype)
-{
- strcpy(retry_name, magic);
+static error_t
+magic_getroot (struct trivfs_control *cntl,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type)
+{
+ error_t err;
+ struct magic *const m = cntl->hook;
+
+ if (m->directory)
+ return EAGAIN; /* Do normal trivfs getroot processing. */
+
+ strcpy (retry_name, m->magic);
*do_retry = FS_RETRY_MAGICAL;
- *ret = MACH_PORT_NULL;
- *rettype = MACH_MSG_TYPE_COPY_SEND;
+ *node = MACH_PORT_NULL;
+ *node_type = MACH_MSG_TYPE_COPY_SEND;
+
+ err = mach_port_deallocate (mach_task_self (), dotdot);
+ assert_perror (err);
+
return 0;
}
-error_t
-S_fsys_startup (mach_port_t bootstrap,
- int flags, mach_port_t control,
- mach_port_t *real, mach_msg_type_name_t *real_type)
+/* This hook is used when running with --directory, when
+ we do use all the normal trivfs machinery. We just use
+ the normal trivfs open, but then stash the DOTDOT port
+ in the trivfs_peropen. */
+
+static error_t
+magic_open (struct trivfs_control *cntl,
+ struct iouser *user,
+ mach_port_t dotdot,
+ int flags,
+ mach_port_t realnode,
+ struct trivfs_protid **cred)
{
- return EOPNOTSUPP;
+ error_t err = trivfs_open (cntl, user, flags, realnode, cred);
+ if (!err)
+ {
+ /* We consume the reference for DOTDOT. */
+ (*cred)->po->hook = (void *) dotdot;
+ struct magic *const m = cntl->hook;
+ m->nusers++;
+ }
+ return err;
}
-error_t
-S_fsys_goaway (mach_port_t control,
- int flags)
+static void
+magic_peropen_destroy (struct trivfs_peropen *po)
{
- exit (0);
+ mach_port_deallocate (mach_task_self (), (mach_port_t) po->hook);
}
-error_t
-S_fsys_syncfs (mach_port_t control,
- int wait,
- int recurse)
+
+/* We have this hook only for simple tracking of the live user ports. */
+static void
+magic_protid_destroy (struct trivfs_protid *cred)
{
- return 0;
+ struct magic *const m = cred->po->cntl->hook;
+ m->nusers--;
}
+
+/* Do a directory lookup. */
+
error_t
-S_fsys_set_options (mach_port_t control,
- char *data, mach_msg_type_number_t len,
- int do_children)
+trivfs_S_dir_lookup (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char *name,
+ int flags,
+ mode_t mode,
+ retry_type *retry_type,
+ char *retry_name,
+ mach_port_t *retrypt,
+ mach_msg_type_name_t *retrypt_type)
{
- return EOPNOTSUPP;
+ int perms;
+ error_t err;
+ struct trivfs_protid *newcred;
+ mach_port_t dotdot;
+ struct iouser *user;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (name[0] != '\0')
+ {
+ struct magic *const m = cred->po->cntl->hook;
+
+ if (!m->directory)
+ return ENOTDIR;
+
+ /* We have a real lookup in the dummy directory.
+ Handle `.' and `..' specially, and anything else
+ gets redirected to the magical retry. */
+
+ while (*name == '/')
+ ++name;
+ while (!strncmp (name, "./", 2))
+ {
+ name += 2;
+ while (*name == '/')
+ ++name;
+ }
+
+ if (!strcmp (name, "..") || !strncmp (name, "../", 3))
+ {
+ name += 2;
+ while (*name == '/')
+ ++name;
+ strcpy (retry_name, name);
+ *retry_type = FS_RETRY_REAUTH;
+ *retrypt = (mach_port_t) cred->po->hook;
+ *retrypt_type = MACH_MSG_TYPE_COPY_SEND;
+ return 0;
+ }
+ else if (name[0] != '\0' && strcmp (name, "."))
+ {
+ if (m->magic == 0)
+ strcpy (retry_name, name);
+ else
+ {
+ char *p = stpcpy (retry_name, m->magic);
+ *p++ = '/';
+ strcpy (p, name);
+ }
+ *retry_type = FS_RETRY_MAGICAL;
+ *retrypt = MACH_PORT_NULL;
+ *retrypt_type = MACH_MSG_TYPE_COPY_SEND;
+ return 0;
+ }
+ }
+
+ /* This is a null-pathname "reopen" call; do the right thing. */
+
+ /* Burn off flags we don't actually implement */
+ flags &= O_HURD;
+ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS);
+
+ /* Validate permissions */
+ if (! trivfs_check_access_hook)
+ file_check_access (cred->realnode, &perms);
+ else
+ (*trivfs_check_access_hook) (cred->po->cntl, cred->user,
+ cred->realnode, &perms);
+ if ((flags & (O_READ|O_WRITE|O_EXEC) & perms)
+ != (flags & (O_READ|O_WRITE|O_EXEC)))
+ return EACCES;
+
+ /* Execute the open */
+
+ dotdot = (mach_port_t) cred->po->hook;
+ err = iohelp_dup_iouser (&user, cred->user);
+ if (err)
+ return err;
+ err = magic_open (cred->po->cntl, user, dotdot, flags,
+ cred->realnode, &newcred);
+ if (err)
+ {
+ iohelp_free_iouser (user);
+ return err;
+ }
+ err = mach_port_mod_refs (mach_task_self (), dotdot,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ err = mach_port_mod_refs (mach_task_self (), cred->realnode,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+
+ *retry_type = FS_RETRY_NORMAL;
+ *retry_name = '\0';
+ *retrypt = ports_get_right (newcred);
+ *retrypt_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newcred);
+ return 0;
}
error_t
-S_fsys_get_options (mach_port_t control,
- char **data, mach_msg_type_number_t *len)
+trivfs_S_dir_readdir (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data,
+ size_t *datalen,
+ boolean_t *data_dealloc,
+ int entry,
+ int nentries,
+ vm_size_t bufsiz,
+ int *amount)
{
- return EOPNOTSUPP;
+ if (!cred)
+ return EOPNOTSUPP;
+
+ struct magic *const m = cred->po->cntl->hook;
+
+ if (entry > 0)
+ {
+ void *p;
+ int i;
+ i = 0;
+ for (p = m->dirbuf; p < m->dirbuf + m->dirbufsize;
+ p += ((struct dirent *) p)->d_reclen)
+ if (i++ == entry)
+ break;
+ *data = p;
+ *datalen = m->dirbuf + m->dirbufsize - p;
+ *amount = 2 - entry;
+ }
+ else
+ {
+ *data = m->dirbuf;
+ *datalen = m->dirbufsize;
+ *amount = 2;
+ }
+
+ *data_dealloc = 0;
+ return 0;
}
-error_t
-S_fsys_getfile (mach_port_t control,
- uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
- char *handle, u_int handllen,
- mach_port_t *pt, mach_msg_type_name_t *pttype)
+
+#include <hurd/paths.h>
+#define _SERVERS_MAGIC _SERVERS "magic"
+
+/* To whom should we try to delegate on startup? */
+static const char *delegate = _SERVERS_MAGIC;
+
+static const struct argp_option options[] =
{
- return EOPNOTSUPP;
+ {"directory", 'd', 0, 0, "Provide virtual (empty) directory node"},
+ {"use-server", 'U', "NAME", 0,
+ "Delegate to server NAME instead of " _SERVERS_MAGIC},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ struct magic *const m = state->input;
+
+ switch (opt)
+ {
+ case 'U':
+ /* This is only valid for the startup options, not delegates. */
+ if (all_fsys != 0)
+ return EINVAL;
+ delegate = arg;
+ return 0;
+
+ case 'd':
+ case ARGP_KEY_NO_ARGS:
+ m->directory = 1;
+ return 0;
+
+ case ARGP_KEY_ARG:
+ if (m->magic != 0)
+ {
+ argp_usage (state);
+ return EINVAL;
+ }
+ m->magic = strdup (arg);
+ return m->magic == 0 ? ENOMEM : 0;
+
+ case ARGP_KEY_SUCCESS:
+ if (m->directory)
+ {
+ inline struct dirent *add (struct dirent *d, const char *name)
+ {
+ d->d_fileno = 2; /* random */
+ d->d_type = DT_DIR;
+ d->d_namlen = strlen (name);
+ strcpy (d->d_name, name);
+ d->d_name[d->d_namlen] = '\0';
+ d->d_reclen = &d->d_name[d->d_namlen + 1] - (char *) d;
+ d->d_reclen = ((d->d_reclen + __alignof (struct dirent) - 1)
+ & ~(__alignof (struct dirent) - 1));
+ return (struct dirent *) ((char *) d + d->d_reclen);
+ }
+ struct dirent *d;
+ m->dirbuf = mmap (0, getpagesize (), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ d = add (m->dirbuf, ".");
+ d = add (d, "..");
+ m->dirbufsize = (char *) d - (char *) m->dirbuf;
+ }
+ return 0;
+ }
+
+ return ARGP_ERR_UNKNOWN;
}
error_t
-S_fsys_getpriv (mach_port_t control,
- mach_port_t *host_priv, mach_msg_type_name_t *host_priv_type,
- mach_port_t *dev_master, mach_msg_type_name_t *dev_master_type,
- task_t *fs_task, mach_msg_type_name_t *fs_task_type)
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
{
- return EOPNOTSUPP;
+ struct magic *const m = fsys->hook;
+ return ((m->directory ? argz_add (argz, argz_len, "--directory") : 0)
+ ?: (m->magic ? argz_add (argz, argz_len, m->magic) : 0));
}
-error_t
-S_fsys_init (mach_port_t control,
- mach_port_t reply, mach_msg_type_name_t replytype,
- mach_port_t proc, auth_t auth)
+static struct argp argp =
+ {
+ options, parse_opt, "MAGIC",
+ "A translator that returns the magic retry result MAGIC."
+ };
+
+int
+main (int argc, char **argv)
{
- return EOPNOTSUPP;
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ struct magic *m = calloc (1, sizeof *m);
+
+ argp_parse (&argp, argc, argv, 0, 0, m);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ if (delegate != 0)
+ {
+ /* First, try to have the canonical server sitting on /servers/magic
+ take over for us. */
+ err = fshelp_delegate_translation (delegate, bootstrap, argv);
+ if (err == 0)
+ return 0;
+ }
+
+ /* Nope, we are doing it ourselves. */
+
+ trivfs_getroot_hook = &magic_getroot;
+ trivfs_open_hook = &magic_open;
+ trivfs_protid_destroy_hook = &magic_protid_destroy;
+ if (m->directory)
+ trivfs_peropen_destroy_hook = &magic_peropen_destroy;
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "Contacting parent");
+ fsys->hook = m;
+ all_fsys = fsys;
+
+ /* Launch. */
+ while (1)
+ {
+ ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer,
+ 10 * 60 * 1000);
+
+ /* That returns when 10 minutes pass without an RPC. Try shutting down
+ as if sent fsys_goaway; if we have any users who need us to stay
+ around, this returns EBUSY and we loop to service more RPCs. */
+
+ struct trivfs_control *fs = all_fsys;
+ do
+ {
+ struct magic *const m = fs->hook;
+ struct trivfs_control *const next = m->next;
+ trivfs_goaway (fs, 0);
+ fs = next;
+ } while (fs != 0);
+ }
+
+ return 0;
}
+
+/* Handle delegated filesystems. */
error_t
-S_fsys_forward (mach_port_t server, mach_port_t requestor,
- char *argz, size_t argz_len)
+trivfs_S_fsys_forward (mach_port_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ mach_port_t requestor,
+ char *argz, size_t argz_len)
{
- return EOPNOTSUPP;
+ struct trivfs_protid *cred
+ = ports_lookup_port (all_fsys->pi.bucket, server,
+ trivfs_protid_portclasses[0]);
+ if (!cred)
+ return EOPNOTSUPP;
+ ports_port_deref (cred);
+
+ /* Allocate a new structure for parameters, and parse the arguments
+ to fill it in. */
+ struct magic *m = calloc (1, sizeof *m);
+ if (!m)
+ return ENOMEM;
+
+ int argc = argz_count (argz, argz_len);
+ char *argv[argc + 1];
+ argz_extract (argz, argz_len, argv);
+ error_t err = argp_parse (&argp, argc, argv,
+ ARGP_NO_ERRS | ARGP_NO_HELP, 0, m);
+ if (err)
+ {
+ free_magic (m);
+ return err;
+ }
+
+ /* Now we are ready to start up the filesystem. Contact the parent. */
+ struct trivfs_control *fsys;
+ err = trivfs_startup (requestor, 0,
+ trivfs_cntl_portclasses[0], all_fsys->pi.bucket,
+ trivfs_protid_portclasses[0], all_fsys->pi.bucket,
+ &fsys);
+ if (err)
+ {
+ free_magic (m);
+ return err;
+ }
+ mach_port_deallocate (mach_task_self (), requestor);
+
+ /* The new filesystem is all hooked up.
+ Put it on the list of all filesystems we are serving. */
+ m->next = all_fsys;
+ fsys->hook = m;
+ all_fsys = fsys;
+
+ return 0;
}
diff --git a/trans/new-fifo.c b/trans/new-fifo.c
index 150121f6..5306deed 100644
--- a/trans/new-fifo.c
+++ b/trans/new-fifo.c
@@ -1,8 +1,7 @@
/* A translator for fifos
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,2000,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -37,8 +36,12 @@
#include <hurd/pipe.h>
#include <hurd/paths.h>
+#include <version.h>
+
#define DEFAULT_SERVER _SERVERS "fifo";
+const char *argp_program_version = STANDARD_HURD_VERSION (new-fifo);
+
struct port_bucket *port_bucket;
struct port_class *fifo_port_class, *server_port_class, *fsys_port_class;
@@ -165,18 +168,18 @@ fifo_trans_parse_args (struct fifo_trans *trans, int argc, char **argv,
}
return 0;
}
- struct argp argp = {options, parse_opt};
+ struct argp argp = {options, parse_opt, 0, "A translator for fifos." };
return argp_parse (&argp, argc, argv, print_errs ? 0 : ARGP_SILENT, 0, 0);
}
/* ---------------------------------------------------------------- */
-struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_protid_portclasses[2];
struct port_class *trivfs_cntl_portclasses[1];
-int trivfs_protid_nportclasses = 1;
+int trivfs_protid_nportclasses = 2;
int trivfs_cntl_nportclasses = 1;
-void
+int
main (int argc, char **argv)
{
error_t err;
@@ -226,11 +229,11 @@ main (int argc, char **argv)
ports_enable_class (fifo_port_class);
ports_manage_port_operations_multithread (port_bucket,
trivfs_demuxer,
- 30*1000, 5*60*1000, 0, 0);
+ 30*1000, 5*60*1000, 0);
}
while (ports_count_class (fifo_port_class) > 0);
- exit (0);
+ return 0;
}
/* ---------------------------------------------------------------- */
@@ -245,16 +248,18 @@ fifo_trans_open (struct fifo_trans *trans, int flags, void **hook)
mutex_lock (&trans->active_fifo_lock);
/* Wait until the active fifo has changed so that CONDITION is true. */
-#define WAIT(condition, noblock_err) \
- while (!err && !(condition)) \
- if (flags & O_NONBLOCK) \
- { \
- err = noblock_err; \
- break; \
- } \
- else if (hurd_condition_wait (&trans->active_fifo_changed, \
- &trans->active_fifo_lock)) \
- err = EINTR;
+#define WAIT(condition, noblock_err) \
+ while (!err && !(condition)) \
+ { \
+ if (flags & O_NONBLOCK) \
+ { \
+ err = noblock_err; \
+ break; \
+ } \
+ else if (hurd_condition_wait (&trans->active_fifo_changed, \
+ &trans->active_fifo_lock)) \
+ err = EINTR; \
+ }
if (flags & O_READ)
/* When opening for read, what we do depends on what mode this server
@@ -497,13 +502,14 @@ trivfs_goaway (struct trivfs_control *fsys, int flags)
mapping; they will set none of the ports and return an error. Such
objects can still be accessed by io_read and io_write. */
error_t
-trivfs_S_io_map(struct trivfs_protid *cred,
- memory_object_t *rdobj,
- mach_msg_type_name_t *rdtype,
- memory_object_t *wrobj,
- mach_msg_type_name_t *wrtype)
+trivfs_S_io_map (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
{
- return EINVAL;
+ return EOPNOTSUPP;
}
/* ---------------------------------------------------------------- */
@@ -588,7 +594,7 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
error_t
trivfs_S_io_select (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t reply_type,
- int *select_type, int *tag)
+ int *select_type)
{
struct pipe *pipe;
error_t err = 0;
@@ -600,26 +606,30 @@ trivfs_S_io_select (struct trivfs_protid *cred,
pipe = cred->po->hook;
if (*select_type & SELECT_READ)
- if (cred->po->openmodes & O_READ)
- {
- mutex_lock (&pipe->lock);
- if (pipe_wait_readable (pipe, 1, 1) != EWOULDBLOCK)
- ready |= SELECT_READ; /* Data immediately readable (or error). */
- mutex_unlock (&pipe->lock);
- }
- else
- ready |= SELECT_READ; /* Error immediately available... */
+ {
+ if (cred->po->openmodes & O_READ)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_readable (pipe, 1, 1) != EWOULDBLOCK)
+ ready |= SELECT_READ; /* Data immediately readable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_READ; /* Error immediately available... */
+ }
if (*select_type & SELECT_WRITE)
- if (cred->po->openmodes & O_WRITE)
- {
- mutex_lock (&pipe->lock);
- if (pipe_wait_writable (pipe, 1) != EWOULDBLOCK)
- ready |= SELECT_WRITE; /* Data immediately writable (or error). */
- mutex_unlock (&pipe->lock);
- }
- else
- ready |= SELECT_WRITE; /* Error immediately available... */
+ {
+ if (cred->po->openmodes & O_WRITE)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_writable (pipe, 1) != EWOULDBLOCK)
+ ready |= SELECT_WRITE; /* Data immediately writable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_WRITE; /* Error immediately available... */
+ }
if (ready)
*select_type = ready;
@@ -681,7 +691,7 @@ trivfs_S_file_set_size (struct trivfs_protid *cred,
/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
will tell you which of O_READ, O_WRITE, and O_EXEC the object can
- be used for. The O_ASYNC bit affects icky async I/O; good async
+ be used for. The O_ASYNC bit affects icky async I/O; good async
I/O is done through io_async which is orthogonal to these calls. */
error_t
diff --git a/trans/null.c b/trans/null.c
index f972d4a1..9673a758 100644
--- a/trans/null.c
+++ b/trans/null.c
@@ -1,8 +1,7 @@
/* A translator for providing endless empty space and immediate eof.
- Copyright (C) 1995 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,99,2001,02,03 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,67 +21,70 @@
#include <hurd/ports.h>
#include <hurd/trivfs.h>
#include <hurd/fsys.h>
+#include <version.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
+#include <argp.h>
-/* ---------------------------------------------------------------- */
+const char *argp_program_version = STANDARD_HURD_VERSION (null);
-struct port_class *control_class;
-struct port_class *node_class;
-struct port_bucket *port_bucket;
+/* Error code to return for write attempts.
+ If zero, they succeed in writing to the bitbucket. */
+static error_t write_error_code;
-struct port_class *trivfs_protid_portclasses[1];
-struct port_class *trivfs_cntl_portclasses[1];
-int trivfs_protid_nportclasses = 1;
-int trivfs_cntl_nportclasses = 1;
+static const struct argp_option options[] =
+{
+ {"full", 'f', 0, 0, "Cause writes to fail as if to a full disk"},
+ {0}
+};
-/* If true, then reading from this device will yield an endless stream of
- zeros instead of immediate EOF. This also makes it mappable. */
-static int provide_zeros = 0;
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ case 'f':
+ write_error_code = ENOSPC;
+ return 0;
+ }
+ return ARGP_ERR_UNKNOWN;
+}
-void
+static const struct argp argp =
+{ options, parse_opt, 0, "Endless sink and null source" };
+
+int
main (int argc, char **argv)
{
error_t err;
mach_port_t bootstrap;
-
- control_class = ports_create_class (trivfs_clean_cntl, 0);
- node_class = ports_create_class (trivfs_clean_protid, 0);
- port_bucket = ports_create_bucket ();
- trivfs_protid_portclasses[0] = node_class;
- trivfs_cntl_portclasses[0] = control_class;
+ struct trivfs_control *fsys;
- if (argc == 2 &&
- (strcmp(argv[1], "-z") == 0 || strcmp(argv[1], "--zero") == 0))
- provide_zeros = 1;
- else if (argc != 1)
- {
- fprintf(stderr, "Usage: %s [-z|--zero]", program_invocation_name);
- exit(1);
- }
+ argp_parse (&argp, argc, argv, 0, 0, 0);
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
- error(1, 0, "must be started as a translator");
+ error(1, 0, "Must be started as a translator");
/* Reply to our parent */
- err = trivfs_startup(bootstrap, 0, control_class, port_bucket,
- node_class, port_bucket, NULL);
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
if (err)
error(3, err, "Contacting parent");
/* Launch. */
- ports_manage_port_operations_one_thread (port_bucket, trivfs_demuxer, 0);
+ ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
+ 2 * 60 * 1000, 0, 0);
- exit(0);
+ return 0;
}
-/* ---------------------------------------------------------------- */
/* Trivfs hooks */
int trivfs_fstype = FSTYPE_DEV;
@@ -109,11 +111,9 @@ trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
error_t
trivfs_goaway (struct trivfs_control *fsys, int flags)
{
- exit(0);
+ exit (0);
}
-/* ---------------------------------------------------------------- */
-
/* Return objects mapping the data underlying this memory object. If
the object can be read then memobjrd will be provided; if the
object can be written then memobjwr will be provided. For objects
@@ -123,50 +123,38 @@ trivfs_goaway (struct trivfs_control *fsys, int flags)
mapping; they will set none of the ports and return an error. Such
objects can still be accessed by io_read and io_write. */
kern_return_t
-trivfs_S_io_map(struct trivfs_protid *cred,
- memory_object_t *rdobj,
- mach_msg_type_name_t *rdtype,
- memory_object_t *wrobj,
- mach_msg_type_name_t *wrtype)
+trivfs_S_io_map (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
{
- return EINVAL; /* XXX should work! */
+ return EOPNOTSUPP; /* XXX should work! */
}
-/* ---------------------------------------------------------------- */
-
/* Read data from an IO object. If offset if -1, read from the object
maintained file pointer. If the object is not seekable, offset is
ignored. The amount desired to be read is in AMT. */
kern_return_t
trivfs_S_io_read(struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t replytype,
- vm_address_t *data,
+ char **data,
mach_msg_type_number_t *datalen,
- off_t offs,
+ loff_t offs,
mach_msg_type_number_t amt)
{
- error_t err = 0;
-
if (!cred)
- err = EOPNOTSUPP;
+ return EOPNOTSUPP;
else if (!(cred->po->openmodes & O_READ))
- err = EBADF;
- else if (provide_zeros)
+ return EBADF;
+ else
{
- if (amt > *datalen)
- err = vm_allocate(mach_task_self(), data, amt, 1);
- else
- bzero((void *)*data, amt);
- *datalen = amt;
+ *datalen = 0;
+ return 0;
}
- else
- *datalen = 0;
-
- return 0;
}
-/* ---------------------------------------------------------------- */
-
/* Tell how much data can be read from the object without blocking for
a "long time" (this should be the same meaning of "long time" used
by the nonblocking flag. */
@@ -179,15 +167,11 @@ trivfs_S_io_readable (struct trivfs_protid *cred,
return EOPNOTSUPP;
else if (!(cred->po->openmodes & O_READ))
return EINVAL;
- else if (provide_zeros)
- *amount = INT_MAX;
else
*amount = 0;
return 0;
}
-/* ---------------------------------------------------------------- */
-
/* Change current read/write offset */
kern_return_t
trivfs_S_io_seek (struct trivfs_protid *cred,
@@ -200,8 +184,6 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
return 0;
}
-/* ---------------------------------------------------------------- */
-
/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
Block until one of the indicated types of i/o can be done "quickly", and
return the types that are then available. ID_TAG is returned as passed; it
@@ -210,7 +192,7 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
kern_return_t
trivfs_S_io_select (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t replytype,
- int *type, int *tag)
+ int *type)
{
if (!cred)
return EOPNOTSUPP;
@@ -222,8 +204,6 @@ trivfs_S_io_select (struct trivfs_protid *cred,
return 0;
}
-/* ---------------------------------------------------------------- */
-
/* Write data to an IO object. If offset is -1, write at the object
maintained file pointer. If the object is not seekable, offset is
ignored. The amount successfully written is returned in amount. A
@@ -234,31 +214,30 @@ trivfs_S_io_select (struct trivfs_protid *cred,
kern_return_t
trivfs_S_io_write (struct trivfs_protid *cred,
mach_port_t reply, mach_msg_type_name_t replytype,
- vm_address_t data, mach_msg_type_number_t datalen,
- off_t offs, mach_msg_type_number_t *amt)
+ char *data, mach_msg_type_number_t datalen,
+ loff_t offs, mach_msg_type_number_t *amt)
{
if (!cred)
return EOPNOTSUPP;
else if (!(cred->po->openmodes & O_WRITE))
return EBADF;
*amt = datalen;
- return 0;
+ return write_error_code;
}
-/* ---------------------------------------------------------------- */
-
/* Truncate file. */
kern_return_t
-trivfs_S_file_set_size (struct trivfs_protid *cred, off_t size)
+trivfs_S_file_set_size (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ loff_t size)
{
return 0;
}
-/* ---------------------------------------------------------------- */
/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
will tell you which of O_READ, O_WRITE, and O_EXEC the object can
- be used for. The O_ASYNC bit affects icky async I/O; good async
+ be used for. The O_ASYNC bit affects icky async I/O; good async
I/O is done through io_async which is orthogonal to these calls. */
kern_return_t
@@ -311,7 +290,6 @@ trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
return 0;
}
-/* ---------------------------------------------------------------- */
/* Get/set the owner of the IO object. For terminals, this affects
controlling terminal behavior (see term_become_ctty). For all
objects this affects old-style async IO. Negative values represent
diff --git a/trans/password.c b/trans/password.c
new file mode 100644
index 00000000..6f15a9e8
--- /dev/null
+++ b/trans/password.c
@@ -0,0 +1,224 @@
+/* Hurd standard password server.
+ Copyright (C) 1999 Free Software Foundation
+ Written by Mark Kettenis.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <argp.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hurd.h>
+#include <hurd/auth.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+
+#include <ugids.h>
+#include <version.h>
+
+#include "password_S.h"
+
+
+const char *argp_program_version = STANDARD_HURD_VERSION (password);
+
+/* Port bucket we service requests on. */
+struct port_bucket *port_bucket;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = 0;
+
+struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_protid_nportclasses = 1;
+int trivfs_cntl_nportclasses = 1;
+
+
+static int
+password_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int password_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ return password_server (inp, outp) || trivfs_demuxer (inp, outp);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ const struct argp argp = { 0, 0, 0, "Hurd standard password server." };
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "must be started as a translator");
+
+ port_bucket = ports_create_bucket ();
+ trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0);
+ trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0);
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, 0,
+ trivfs_cntl_portclasses[0], port_bucket,
+ trivfs_protid_portclasses[0], port_bucket,
+ &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "Contacting parent");
+
+ /* Launch. */
+ do
+ ports_manage_port_operations_multithread (port_bucket, password_demuxer,
+ 2 * 60 * 1000,
+ 10 * 60 * 1000,
+ 0);
+ /* That returns when 10 minutes pass without an RPC. Try shutting down
+ as if sent fsys_goaway; if we have any users who need us to stay
+ around, this returns EBUSY and we loop to service more RPCs. */
+ while (trivfs_goaway (fsys, 0));
+
+ return 0;
+}
+
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ int count;
+
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]);
+
+ /* Are there any extant user ports for the /servers/password file? */
+ count = ports_count_class (trivfs_protid_portclasses[0]);
+ if (count > 0 && !(flags & FSYS_GOAWAY_FORCE))
+ {
+ /* We won't go away, so start things going again... */
+ ports_enable_class (trivfs_protid_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_protid_portclasses[0]);
+
+ return EBUSY;
+ }
+
+ exit (0);
+}
+
+
+/* Implement password_check_user as described in <hurd/password.defs>. */
+kern_return_t
+S_password_check_user (io_t server, uid_t user, char *pw,
+ mach_port_t *port, mach_msg_type_name_t *port_type)
+{
+ struct trivfs_protid *cred;
+ struct ugids ugids = UGIDS_INIT;
+ auth_t auth;
+ error_t err;
+
+ char *getpass (const char *prompt, uid_t id, int is_group,
+ void *pwd_or_group, void *hook)
+ {
+ assert (! is_group && id == user);
+ return strdup (pw);
+ }
+
+ cred = ports_lookup_port (port_bucket, server, trivfs_protid_portclasses[0]);
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* Verify password. */
+ err = ugids_add_user (&ugids, user, 1);
+ if (!err)
+ err = ugids_verify (&ugids, 0, 0, getpass, 0, 0, 0);
+
+ if (!err)
+ {
+ auth = getauth ();
+ err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ ugids.eff_uids.ids, ugids.eff_uids.num,
+ ugids.avail_uids.ids, ugids.avail_uids.num,
+ ugids.eff_gids.ids, ugids.eff_gids.num,
+ ugids.avail_gids.ids, ugids.avail_gids.num,
+ port);
+ mach_port_deallocate (mach_task_self (), auth);
+ *port_type = MACH_MSG_TYPE_MOVE_SEND;
+ }
+
+ ugids_fini (&ugids);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* Implement password_check_group as described in <hurd/password.defs>. */
+kern_return_t
+S_password_check_group (io_t server, uid_t group, char *pw,
+ mach_port_t *port, mach_msg_type_name_t *port_type)
+{
+ struct trivfs_protid *cred;
+ struct ugids ugids = UGIDS_INIT;
+ auth_t auth;
+ error_t err;
+
+ char *getpass (const char *prompt, uid_t id, int is_group,
+ void *pwd_or_group, void *hook)
+ {
+ assert (is_group && id == group);
+ return strdup (pw);
+ }
+
+ cred = ports_lookup_port (port_bucket, server, trivfs_protid_portclasses[0]);
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* Verify password. */
+ err = ugids_add_gid (&ugids, group, 1);
+ if (!err)
+ err = ugids_verify (&ugids, 0, 0, getpass, 0, 0, 0);
+
+ if (!err)
+ {
+ auth = getauth ();
+ err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ ugids.eff_uids.ids, ugids.eff_uids.num,
+ ugids.avail_uids.ids, ugids.avail_uids.num,
+ ugids.eff_gids.ids, ugids.eff_gids.num,
+ ugids.avail_gids.ids, ugids.avail_gids.num,
+ port);
+ mach_port_deallocate (mach_task_self (), auth);
+ *port_type = MACH_MSG_TYPE_MOVE_SEND;
+ }
+
+ ugids_fini (&ugids);
+
+ ports_port_deref (cred);
+ return err;
+}
diff --git a/trans/proxy-defpager.c b/trans/proxy-defpager.c
new file mode 100644
index 00000000..0a5ab65e
--- /dev/null
+++ b/trans/proxy-defpager.c
@@ -0,0 +1,278 @@
+/* A translator for providing access to Mach default_pager.defs control calls
+
+ Copyright (C) 2002, 2007 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. */
+
+#include <hurd/trivfs.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+#include <hurd/paths.h>
+
+#include "default_pager_S.h"
+#include "default_pager_U.h"
+
+static mach_port_t real_defpager, dev_master;
+
+static error_t
+allowed (mach_port_t port, int mode)
+{
+ struct trivfs_protid *cred = ports_lookup_port
+ (0, port, trivfs_protid_portclasses[0]);
+ if (!cred)
+ return MIG_BAD_ID;
+ error_t result = (cred->po->openmodes & mode) ? 0 : EACCES;
+ ports_port_deref (cred);
+ return result;
+}
+
+kern_return_t
+S_default_pager_object_create (mach_port_t default_pager,
+ memory_object_t *memory_object,
+ vm_size_t object_size)
+{
+ return allowed (default_pager, O_EXEC)
+ ?: default_pager_object_create (real_defpager, memory_object, object_size);
+}
+
+kern_return_t
+S_default_pager_info (mach_port_t default_pager, default_pager_info_t *info)
+{
+ return allowed (default_pager, O_READ)
+ ?: default_pager_info (real_defpager, info);
+}
+
+kern_return_t
+S_default_pager_objects (mach_port_t default_pager,
+ default_pager_object_array_t *objects,
+ mach_msg_type_number_t *objectsCnt,
+ mach_port_array_t *ports,
+ mach_msg_type_number_t *portsCnt)
+{
+ return allowed (default_pager, O_WRITE)
+ ?: default_pager_objects (real_defpager,
+ objects, objectsCnt, ports, portsCnt);
+}
+
+kern_return_t
+S_default_pager_object_pages (mach_port_t default_pager,
+ mach_port_t memory_object,
+ default_pager_page_array_t *pages,
+ mach_msg_type_number_t *pagesCnt)
+{
+ return allowed (default_pager, O_WRITE)
+ ?: default_pager_object_pages (real_defpager, memory_object,
+ pages, pagesCnt);
+}
+
+
+kern_return_t
+S_default_pager_paging_file (mach_port_t default_pager,
+ mach_port_t master_device_port,
+ default_pager_filename_t filename,
+ boolean_t add)
+{
+ return allowed (default_pager, O_WRITE)
+ ?: default_pager_paging_file (real_defpager, dev_master, filename, add)
+ ?: mach_port_deallocate (mach_task_self (), master_device_port);
+}
+
+kern_return_t
+S_default_pager_paging_storage (mach_port_t default_pager,
+ mach_port_t device,
+ recnum_t *runs, mach_msg_type_number_t nruns,
+ default_pager_filename_t name,
+ boolean_t add)
+{
+ return allowed (default_pager, O_WRITE)
+ ?: default_pager_paging_storage (real_defpager, dev_master,
+ runs, nruns, name, add)
+ ?: mach_port_deallocate (mach_task_self (), device);
+}
+
+kern_return_t
+S_default_pager_object_set_size (mach_port_t memory_object,
+ mach_port_seqno_t seqno,
+ vm_size_t object_size_limit)
+{
+ /* This is sent to an object, not the control port. */
+ return MIG_BAD_ID;
+}
+
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 1;
+
+int trivfs_allow_open = O_READ | O_WRITE | O_EXEC;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_blksize = vm_page_size * 256; /* Make transfers LARRRRRGE */
+
+ st->st_size = 0;
+ st->st_blocks = 0;
+
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFCHR;
+}
+
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ exit (0);
+}
+
+kern_return_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ char **data,
+ mach_msg_type_number_t *datalen,
+ loff_t offs,
+ mach_msg_type_number_t amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return EIO;
+}
+
+kern_return_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ char *data, mach_msg_type_number_t datalen,
+ loff_t offs, mach_msg_type_number_t *amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return EIO;
+}
+
+kern_return_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ {
+ *bits = cred->po->openmodes;
+ return 0;
+ }
+}
+
+error_t
+trivfs_S_io_set_all_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+const char *argp_program_version = STANDARD_HURD_VERSION (proxy-defpager);
+
+static const struct argp argp =
+{doc: "\
+Access to control interfaces of Mach default pager.\n\
+This translator should normally be set on " _SERVERS_DEFPAGER "."};
+
+int
+proxy_defpager_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ extern int default_pager_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return default_pager_server (inp, outp)
+ || trivfs_demuxer (inp, outp);
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ mach_port_t host_priv;
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ err = get_privileged_ports (&host_priv, &dev_master);
+ if (err)
+ error (2, err, "cannot get privileged ports");
+ real_defpager = MACH_PORT_NULL;
+ err = vm_set_default_memory_manager (host_priv, &real_defpager);
+ mach_port_deallocate (mach_task_self (), host_priv);
+ if (err)
+ error (3, err, "vm_set_default_memory_manager");
+ if (real_defpager == MACH_PORT_NULL)
+ error (1, 0, "no default memory manager set!");
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ trivfs_fsid = getpid ();
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (4, err, "Contacting parent");
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket,
+ proxy_defpager_demuxer,
+ 2 * 60 * 1000, 0, 0);
+
+ return 0;
+}
diff --git a/trans/streamio.c b/trans/streamio.c
new file mode 100644
index 00000000..c563c03c
--- /dev/null
+++ b/trans/streamio.c
@@ -0,0 +1,1161 @@
+/* A translator for handling stream devices.
+
+ Copyright (C) 2001,02 Free Software Foundation, Inc.
+
+ Written by OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
+
+ 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. */
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+
+#include <mach.h>
+#include <device/device.h>
+#include <device/device_request.h>
+
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <version.h>
+
+/* The global lock */
+struct mutex global_lock;
+
+/* Wakeup when device_open is finished */
+struct condition open_alert;
+
+/* Wakeup for select */
+struct condition select_alert;
+
+/* Bucket for all out ports */
+struct port_bucket *streamdev_bucket;
+
+/* The buffers we use */
+struct buffer *input_buffer, *output_buffer;
+
+
+/* Information about a buffer. */
+struct buffer
+{
+ /* Point to the head of the buffer. */
+ char *head;
+ /* Point to the tail of the buffer. */
+ char *tail;
+ /* The buffer array size. */
+ size_t size;
+ /* Wakeup when the buffer is not empty or not full. */
+ struct condition *wait;
+ /* The buffer. */
+ char buf[0];
+};
+
+/* Create a new buffer structure with SIZE, returning the pointer. */
+static inline struct buffer *
+create_buffer (size_t size)
+{
+ struct buffer *new = malloc (sizeof (struct buffer) + size);
+ assert (new);
+ new->head = new->tail = new->buf;
+ new->size = size;
+ new->wait = malloc (sizeof (struct condition));
+ assert (new->wait);
+ condition_init (new->wait);
+ return new;
+}
+
+/* Return the size of B. */
+static inline size_t
+buffer_size (struct buffer *b)
+{
+ return b->tail - b->head;
+}
+
+/* Return how much characters can be read from B. */
+static inline size_t
+buffer_readable (struct buffer *b)
+{
+ return buffer_size (b);
+}
+
+/* Return how much characters can be written to B. */
+static inline size_t
+buffer_writable (struct buffer *b)
+{
+ return b->size - buffer_size (b);
+}
+
+/* Flush B. */
+static inline void
+clear_buffer (struct buffer *b)
+{
+ if (b == 0)
+ return;
+ b->head = b->tail = b->buf;
+ condition_broadcast (b->wait);
+}
+
+/* Read up to LEN bytes from B to DATA, returning the amount actually read. */
+static inline size_t
+buffer_read (struct buffer *b, void *data, size_t len)
+{
+ size_t max = buffer_size (b);
+
+ if (len > max)
+ len = max;
+
+ memcpy (data, b->head, len);
+ b->head += len;
+
+ if (b->head > b->buf + b->size / 2)
+ {
+ size_t size = buffer_size (b);
+
+ memmove (b->buf, b->head, size);
+ b->head = b->buf;
+ b->tail = b->buf + size;
+ }
+
+ condition_broadcast (b->wait);
+ return len;
+}
+
+/* Write LEN bytes from DATA to B, returning the amount actually written. */
+static inline size_t
+buffer_write (struct buffer *b, void *data, size_t len)
+{
+ size_t size = buffer_writable (b);
+
+ if (len > size)
+ len = size;
+
+ memcpy (b->tail, data, len);
+ b->tail += len;
+
+ condition_broadcast (b->wait);
+ return len;
+}
+
+
+/* Open a new device structure for the device NAME with MODE. If an error
+ occurs, the error code is returned, otherwise 0. */
+error_t dev_open (const char *name, dev_mode_t mode);
+
+/* Check if the device is already opened. */
+int dev_already_opened (void);
+
+/* Close the device. */
+void dev_close (void);
+
+/* Read up to AMOUNT bytes, returned in BUF and LEN. If NOWAIT is non-zero
+ and the buffer is empty, then returns EWOULDBLOCK. If an error occurs,
+ the error code is returned, otherwise 0. */
+error_t dev_read (size_t amount, void **buf, size_t *len, int nowait);
+
+/* Return current readable size in AMOUNT. If an error occurs, the error
+ code is returned, otherwise 0. */
+error_t dev_readable (size_t *amount);
+
+/* Write LEN bytes from BUF, returning the amount actually written
+ in AMOUNT. If NOWAIT is non-zero and the buffer is full, then returns
+ EWOULDBLOCK. If an error occurs, the error code is returned,
+ otherwise 0. */
+error_t dev_write (void *buf, size_t len, size_t *amount, int nowait);
+
+/* Try and write out any pending writes to the device. If WAIT is non-zero,
+ will wait for any activity to cease. */
+error_t dev_sync (int wait);
+
+
+
+static struct argp_option options[] =
+{
+ {"rdev", 'n', "ID", 0,
+ "The stat rdev number for this node; may be either a"
+ " single integer, or of the form MAJOR,MINOR"},
+ {"readonly", 'r', 0, 0, "Disallow writing"},
+ {"rdonly", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"ro", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"writable", 'w', 0, 0, "Allow writing"},
+ {"rdwr", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"rw", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"writeonly", 'W',0, 0, "Disallow reading"},
+ {"wronly", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {0}
+};
+
+static const char args_doc[] = "DEVICE";
+static const char doc[] = "Translator for stream devices.";
+
+const char *argp_program_version = STANDARD_HURD_VERSION (streamio);
+
+
+static char *stream_name;
+static int rdev;
+static int nperopens;
+
+/* Parse a single option. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'r':
+ trivfs_allow_open = O_READ;
+ break;
+ case 'w':
+ trivfs_allow_open = O_RDWR;
+ break;
+ case 'W':
+ trivfs_allow_open = O_WRITE;
+ break;
+
+ case 'n':
+ {
+ char *start = arg;
+ char *end;
+
+ rdev = strtoul (start, &end, 0);
+ if (*end == ',')
+ /* MAJOR,MINOR form */
+ {
+ start = end + 1;
+ rdev = (rdev << 8) + strtoul (start, &end, 0);
+ }
+
+ if (end == start || *end != '\0')
+ {
+ argp_error (state, "%s: Invalid argument to --rdev", arg);
+ return EINVAL;
+ }
+ }
+ break;
+
+ case ARGP_KEY_ARG:
+ stream_name = arg;
+ break;
+
+ case ARGP_KEY_END:
+ if (stream_name == 0)
+ argp_usage (state);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static const struct argp argp = { options, parse_opt, args_doc, doc };
+
+
+int
+demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int device_reply_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (trivfs_demuxer (inp, outp)
+ || device_reply_server (inp, outp));
+}
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (2, 0, "Must be started as a translator");
+
+ streamdev_bucket = ports_create_bucket ();
+
+ err = trivfs_startup (bootstrap, 0,
+ 0, streamdev_bucket, 0, streamdev_bucket,
+ &fsys);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ mutex_init (&global_lock);
+
+ condition_init (&open_alert);
+ condition_init (&select_alert);
+
+ if (trivfs_allow_open & O_READ)
+ {
+ input_buffer = create_buffer (256);
+ condition_implies (input_buffer->wait, &select_alert);
+ }
+ if (trivfs_allow_open & O_WRITE)
+ {
+ output_buffer = create_buffer (256);
+ condition_implies (output_buffer->wait, &select_alert);
+ }
+
+ /* Launch */
+ ports_manage_port_operations_multithread (streamdev_bucket, demuxer,
+ 0, 0, 0);
+
+ return 0;
+}
+
+
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ | O_WRITE;
+
+static error_t
+open_hook (struct trivfs_control *cntl, struct iouser *user, int flags)
+{
+ error_t err;
+ dev_mode_t mode;
+
+ if (flags & O_WRITE & ~trivfs_allow_open)
+ return EROFS;
+ if (flags & O_READ & ~trivfs_allow_open)
+ return EIO;
+
+ if ((flags & (O_READ|O_WRITE)) == 0)
+ return 0;
+
+ /* XXX */
+ if (flags & O_ASYNC)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ mode = 0;
+ if (flags & O_READ)
+ mode |= D_READ;
+ if (flags & O_WRITE)
+ mode |= D_WRITE;
+
+ if (!dev_already_opened ())
+ {
+ err = dev_open (stream_name, mode);
+ if (err)
+ {
+ mutex_unlock (&global_lock);
+ return err;
+ }
+
+ if (!(flags & O_NONBLOCK))
+ {
+ if (hurd_condition_wait (&open_alert, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+
+ if (!dev_already_opened ())
+ {
+ mutex_unlock (&global_lock);
+ return ENODEV;
+ }
+ }
+ }
+
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t (*trivfs_check_open_hook) (struct trivfs_control *,
+ struct iouser *, int)
+ = open_hook;
+
+static error_t
+po_create_hook (struct trivfs_peropen *po)
+{
+ mutex_lock (&global_lock);
+ nperopens++;
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *) =
+ po_create_hook;
+
+static void
+po_destroy_hook (struct trivfs_peropen *po)
+{
+ mutex_lock (&global_lock);
+ nperopens--;
+ if (!nperopens)
+ {
+ if (dev_already_opened ())
+ {
+ clear_buffer (input_buffer);
+ dev_close ();
+ }
+ }
+ mutex_unlock (&global_lock);
+}
+
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *)
+ = po_destroy_hook;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_blksize = vm_page_size;
+ st->st_size = 0;
+
+ st->st_rdev = rdev;
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFCHR;
+ if ((trivfs_allow_open & O_READ) == 0)
+ st->st_mode &= ~(S_IRUSR | S_IRGRP | S_IROTH);
+ if ((trivfs_allow_open & O_WRITE) == 0)
+ st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ error_t err;
+ int force = (flags & FSYS_GOAWAY_FORCE);
+ int nosync = (flags & FSYS_GOAWAY_NOSYNC);
+ struct port_class *root_port_class = fsys->protid_class;
+
+ mutex_lock (&global_lock);
+
+ if (!dev_already_opened ())
+ exit (0);
+
+ err = ports_inhibit_class_rpcs (root_port_class);
+ if (err == EINTR || (err && !force))
+ {
+ mutex_unlock (&global_lock);
+ return err;
+ }
+
+ if (force && nosync)
+ exit (0);
+
+ if (!force && ports_count_class (root_port_class) > 0)
+ goto busy;
+
+ if (!nosync)
+ dev_close ();
+ exit (0);
+
+ busy:
+ ports_enable_class (root_port_class);
+ ports_resume_class_rpcs (root_port_class);
+ mutex_unlock (&global_lock);
+
+ return EBUSY;
+}
+
+
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, mach_msg_type_number_t *data_len,
+ loff_t offs, mach_msg_type_number_t amount)
+{
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (!(cred->po->openmodes & O_READ))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+ err = dev_read (amount, (void **)data, data_len, cred->po->openmodes & O_NONBLOCK);
+ mutex_unlock (&global_lock);
+ return err;
+}
+
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_msg_type_number_t *amount)
+{
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (!(cred->po->openmodes & O_READ))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+ err = dev_readable (amount);
+ mutex_unlock (&global_lock);
+ return err;
+}
+
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char *data, mach_msg_type_number_t data_len,
+ loff_t offs, mach_msg_type_number_t *amount)
+{
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (!(cred->po->openmodes & O_WRITE))
+ return EBADF;
+
+ mutex_lock (&global_lock);
+ err = dev_write ((void *)data, data_len, amount, cred->po->openmodes & O_NONBLOCK);
+ mutex_unlock (&global_lock);
+ return err;
+}
+
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return ESPIPE;
+}
+
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *type)
+{
+ int available;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (!(cred->po->openmodes & O_WRITE) && (*type & SELECT_WRITE))
+ return EBADF;
+
+ *type &= SELECT_READ | SELECT_WRITE;
+
+ if (*type == 0)
+ return 0;
+
+ available = 0;
+
+ while (1)
+ {
+ mutex_lock (&global_lock);
+ if ((*type & SELECT_READ) && buffer_readable (input_buffer))
+ available |= SELECT_READ;
+ if (output_buffer)
+ {
+ if ((*type & SELECT_WRITE) && buffer_writable (output_buffer))
+ available |= SELECT_WRITE;
+ }
+
+ if (available)
+ {
+ *type = available;
+ mutex_unlock (&global_lock);
+ return 0;
+ }
+
+ if (cred->po->openmodes & O_NONBLOCK)
+ {
+ mutex_unlock (&global_lock);
+ return EWOULDBLOCK;
+ }
+
+ ports_interrupt_self_on_port_death (cred, reply);
+ if (hurd_condition_wait (&select_alert, &global_lock))
+ {
+ *type = 0;
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ }
+}
+
+error_t
+trivfs_S_file_set_size (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_WRITE))
+ return EBADF;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *bits)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else
+ {
+ *bits = cred->po->openmodes;
+ return 0;
+ }
+}
+
+error_t
+trivfs_S_io_set_all_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int mode)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_file_sync (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int wait, int omit_metadata)
+{
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ err = dev_sync (wait);
+ mutex_unlock (&global_lock);
+ return err;
+}
+
+error_t
+trivfs_S_file_syncfs (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int wait, int dochildren)
+{
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ err = dev_sync (wait);
+ mutex_unlock (&global_lock);
+ return err;
+}
+
+
+/* This flag is set if there is an outstanding device_write. */
+static int output_pending;
+
+/* This flag is set if there is an outstanding device_read. */
+static int input_pending;
+
+/* This flag is set if there is an outstanding device_open. */
+static int open_pending;
+
+static char pending_output[IO_INBAND_MAX];
+static int npending_output;
+
+/* This flag is set if EOF is returned. */
+static int eof;
+
+/* The error number. */
+static error_t err;
+
+static struct port_class *phys_reply_class;
+
+/* The Mach device_t representing the stream. */
+static device_t phys_device = MACH_PORT_NULL;
+
+/* The ports we get replies on for device calls. */
+static mach_port_t phys_reply_writes = MACH_PORT_NULL;
+static mach_port_t phys_reply = MACH_PORT_NULL;
+
+/* The port-info structures. */
+static struct port_info *phys_reply_writes_pi;
+static struct port_info *phys_reply_pi;
+
+static device_t device_master;
+
+/* The block size and whole size of the device. */
+static size_t dev_blksize;
+static size_t dev_size;
+
+
+/* Open a new device structure for the device NAME with MODE. If an error
+ occurs, the error code is returned, otherwise 0. */
+/* Be careful that the global lock is already locked. */
+error_t
+dev_open (const char *name, dev_mode_t mode)
+{
+ if (open_pending || (phys_device != MACH_PORT_NULL))
+ return 0;
+
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ return err;
+
+ phys_reply_class = ports_create_class (0, 0);
+ err = ports_create_port (phys_reply_class, streamdev_bucket,
+ sizeof (struct port_info), &phys_reply_pi);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), device_master);
+ return err;
+ }
+
+ phys_reply = ports_get_right (phys_reply_pi);
+ mach_port_insert_right (mach_task_self (), phys_reply, phys_reply,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+ if (output_buffer)
+ {
+ err = ports_create_port (phys_reply_class, streamdev_bucket,
+ sizeof (struct port_info),
+ &phys_reply_writes_pi);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), phys_reply);
+ phys_reply = MACH_PORT_NULL;
+ ports_port_deref (phys_reply_pi);
+ phys_reply_pi = 0;
+ mach_port_deallocate (mach_task_self (), device_master);
+ return err;
+ }
+
+ phys_reply_writes = ports_get_right (phys_reply_writes_pi);
+ mach_port_insert_right (mach_task_self (), phys_reply_writes,
+ phys_reply_writes, MACH_MSG_TYPE_MAKE_SEND);
+ }
+
+ err = device_open_request (device_master, phys_reply, mode, name);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), phys_reply);
+ phys_reply = MACH_PORT_NULL;
+ ports_port_deref (phys_reply_pi);
+ phys_reply_pi = 0;
+ if (output_buffer)
+ {
+ mach_port_deallocate (mach_task_self (), phys_reply_writes);
+ phys_reply_writes = MACH_PORT_NULL;
+ ports_port_deref (phys_reply_writes_pi);
+ phys_reply_writes_pi = 0;
+ }
+ mach_port_deallocate (mach_task_self (), device_master);
+ return err;
+ }
+
+ open_pending = 1;
+ return 0;
+}
+
+kern_return_t
+device_open_reply (mach_port_t reply, int returncode, mach_port_t device)
+{
+ int sizes[DEV_GET_SIZE_COUNT];
+ size_t sizes_len = DEV_GET_SIZE_COUNT;
+ int amount;
+
+ if (reply != phys_reply)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ open_pending = 0;
+ condition_broadcast (&open_alert);
+
+ if (returncode != 0)
+ {
+ dev_close ();
+ mutex_unlock (&global_lock);
+ return 0;
+ }
+
+ phys_device = device;
+ eof = 0;
+
+ /* Get the block size and the whole size. */
+ err = device_get_status (device, DEV_GET_SIZE, sizes, &sizes_len);
+ if (err == D_INVALID_OPERATION)
+ {
+ /* XXX Assume that the block size is 1 and the whole size is 0. */
+ dev_blksize = 1;
+ dev_size = 0;
+ err = 0;
+ }
+ else if (err == 0)
+ {
+ assert (sizes_len == DEV_GET_SIZE_COUNT);
+
+ dev_blksize = sizes[DEV_GET_SIZE_RECORD_SIZE];
+ dev_size = sizes[DEV_GET_SIZE_DEVICE_SIZE];
+
+ assert (dev_blksize && dev_blksize <= IO_INBAND_MAX);
+ }
+ else
+ {
+ dev_close ();
+ mutex_unlock (&global_lock);
+ return 0;
+ }
+
+ amount = vm_page_size;
+ if (dev_blksize != 1)
+ amount = amount / dev_blksize * dev_blksize;
+
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+/* Check if the device is already opened. */
+/* Be careful that the global lock is already locked. */
+int
+dev_already_opened (void)
+{
+ return (phys_device != MACH_PORT_NULL);
+}
+
+/* Close the device. */
+/* Be careful that the global lock is already locked. */
+void
+dev_close (void)
+{
+ /* Sync all pending writes. */
+ dev_sync (1);
+
+ device_close (phys_device);
+ mach_port_deallocate (mach_task_self (), phys_device);
+ phys_device = MACH_PORT_NULL;
+
+ mach_port_deallocate (mach_task_self (), phys_reply);
+ phys_reply = MACH_PORT_NULL;
+ ports_port_deref (phys_reply_pi);
+ phys_reply_pi = 0;
+ clear_buffer (input_buffer);
+ input_pending = 0;
+
+ if (output_buffer)
+ {
+ mach_port_deallocate (mach_task_self (), phys_reply_writes);
+ phys_reply_writes = MACH_PORT_NULL;
+ ports_port_deref (phys_reply_writes_pi);
+ phys_reply_writes_pi = 0;
+ clear_buffer (output_buffer);
+ npending_output = 0;
+ output_pending = 0;
+ }
+}
+
+/* Be careful that the global lock is already locked. */
+static error_t
+start_input (int nowait)
+{
+ int size;
+ error_t err;
+ size_t amount;
+
+ size = buffer_writable (input_buffer);
+
+ if (size < dev_blksize || input_pending)
+ return 0;
+
+ amount = vm_page_size;
+ if (dev_blksize != 1)
+ amount = amount / dev_blksize * dev_blksize;
+
+ err = device_read_request_inband (phys_device, phys_reply,
+ nowait? D_NOWAIT : 0,
+ 0, amount);
+ if (err == D_WOULD_BLOCK)
+ err = 0;
+ if (err)
+ dev_close ();
+ else
+ input_pending = 1;
+
+ return err;
+}
+
+/* Read up to AMOUNT bytes, returned in BUF and LEN. If NOWAIT is non-zero
+ and the buffer is empty, then returns EWOULDBLOCK. If an error occurs,
+ the error code is returned, otherwise 0. */
+/* Be careful that the global lock is already locked. */
+error_t
+dev_read (size_t amount, void **buf, size_t *len, int nowait)
+{
+ size_t max, avail;
+
+ if (err)
+ return err;
+
+ while (!buffer_readable (input_buffer))
+ {
+ err = start_input (nowait);
+ if (err)
+ return err;
+
+ if (eof)
+ {
+ *len = 0;
+ return 0;
+ }
+
+ if (nowait)
+ return EWOULDBLOCK;
+
+ if (hurd_condition_wait (input_buffer->wait, &global_lock))
+ return EINTR;
+ }
+
+ avail = buffer_size (input_buffer);
+ max = (amount < avail) ? amount : avail;
+ if (max > *len)
+ vm_allocate (mach_task_self (), (vm_address_t *)buf, max, 1);
+
+ *len = buffer_read (input_buffer, *buf, max);
+ assert (*len == max);
+
+ err = start_input (nowait);
+ return err;
+}
+
+error_t
+device_read_reply_inband (mach_port_t reply, error_t errorcode,
+ char *data, u_int datalen)
+{
+ if (reply != phys_reply)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ input_pending = 0;
+ err = errorcode;
+ if (!err)
+ {
+ if (datalen == 0)
+ {
+ eof = 1;
+ dev_close ();
+ mutex_unlock (&global_lock);
+ return 0;
+ }
+
+ while (datalen)
+ {
+ size_t nwritten;
+
+ while (!buffer_writable (input_buffer))
+ condition_wait (input_buffer->wait, &global_lock);
+
+ nwritten = buffer_write (input_buffer, data, datalen);
+ data += nwritten;
+ datalen -= nwritten;
+ condition_broadcast (input_buffer->wait);
+ }
+ }
+ else
+ {
+ dev_close ();
+ mutex_unlock (&global_lock);
+ return 0;
+ }
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+/* Return current readable size in AMOUNT. If an error occurs, the error
+ code is returned, otherwise 0. */
+/* Be careful that the global lock is already locked. */
+error_t
+dev_readable (size_t *amount)
+{
+ *amount = buffer_size (input_buffer);
+ return 0;
+}
+
+/* Be careful that the global lock is already locked. */
+static error_t
+start_output (int nowait)
+{
+ int size;
+
+ assert (output_buffer);
+
+ size = buffer_size (output_buffer);
+
+ if (size < dev_blksize || output_pending)
+ return 0;
+
+ if (size + npending_output > IO_INBAND_MAX)
+ size = IO_INBAND_MAX - npending_output;
+
+ if (dev_blksize != 1)
+ size = size / dev_blksize * dev_blksize;
+
+ buffer_read (output_buffer, pending_output + npending_output, size);
+ npending_output += size;
+
+ err = device_write_request_inband (phys_device, phys_reply_writes,
+ nowait? D_NOWAIT : 0,
+ 0, pending_output, npending_output);
+ if (err == D_WOULD_BLOCK)
+ err = 0;
+ if (err)
+ dev_close ();
+ else
+ output_pending = 1;
+
+ return err;
+}
+
+/* Write LEN bytes from BUF, returning the amount actually written
+ in AMOUNT. If NOWAIT is non-zero and the buffer is full, then returns
+ EWOULDBLOCK. If an error occurs, the error code is returned,
+ otherwise 0. */
+/* Be careful that the global lock is already locked. */
+error_t
+dev_write (void *buf, size_t len, size_t *amount, int nowait)
+{
+ if (err)
+ return err;
+
+ while (!buffer_writable (output_buffer))
+ {
+ err = start_output (nowait);
+ if (err)
+ return err;
+
+ if (nowait)
+ return EWOULDBLOCK;
+
+ if (hurd_condition_wait (output_buffer->wait, &global_lock))
+ return EINTR;
+ }
+
+ *amount = buffer_write (output_buffer, buf, len);
+ err = start_output (nowait);
+
+ return err;
+}
+
+error_t
+device_write_reply_inband (mach_port_t reply, error_t returncode, int amount)
+{
+ if (reply != phys_reply_writes)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+
+ output_pending = 0;
+
+ if (!returncode)
+ {
+ if (amount >= npending_output)
+ {
+ npending_output = 0;
+ condition_broadcast (output_buffer->wait);
+ }
+ else
+ {
+ npending_output -= amount;
+ memmove (pending_output, pending_output + amount, npending_output);
+ }
+ }
+ else
+ dev_close ();
+
+ mutex_unlock (&global_lock);
+ return 0;
+}
+
+/* Try and write out any pending writes to the device. If WAIT is non-zero,
+ will wait for any activity to cease. */
+/* Be careful that the global lock is already locked. */
+error_t
+dev_sync (int wait)
+{
+ if (err)
+ return err;
+
+ if (!output_buffer || phys_device == MACH_PORT_NULL)
+ return 0;
+
+ while (buffer_readable (output_buffer) >= dev_blksize)
+ {
+ err = start_output (! wait);
+ if (err)
+ return err;
+
+ if (!wait)
+ return 0;
+
+ if (hurd_condition_wait (output_buffer->wait, &global_lock))
+ return EINTR;
+ }
+
+ /* XXX: When the size of output_buffer is non-zero and less than
+ DEV_BLKSIZE, the rest will be ignored or discarded. */
+ return 0;
+}
+
+/* Unused stubs. */
+kern_return_t
+device_read_reply (mach_port_t reply, kern_return_t returncode,
+ io_buf_ptr_t data, mach_msg_type_number_t amount)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+device_write_reply (mach_port_t reply, kern_return_t returncode, int amount)
+{
+ return EOPNOTSUPP;
+}
diff --git a/trans/symlink.c b/trans/symlink.c
index d8495f8b..03b51003 100644
--- a/trans/symlink.c
+++ b/trans/symlink.c
@@ -1,5 +1,5 @@
/* Translator for S_IFLNK nodes
- Copyright (C) 1994 Free Software Foundation
+ Copyright (C) 1994, 2000, 2001, 2002 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,8 +17,14 @@
#include <hurd.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <argp.h>
#include <hurd/fsys.h>
#include <fcntl.h>
+#include <errno.h>
+#include <error.h>
+#include <version.h>
#include "fsys_S.h"
mach_port_t realnode;
@@ -31,37 +37,64 @@ char *linktarget;
extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+const char *argp_program_version = STANDARD_HURD_VERSION (symlink);
+
+static const struct argp_option options[] =
+ {
+ { 0 }
+ };
+
+static const char args_doc[] = "TARGET";
+static const char doc[] = "A translator for symlinks."
+"\vA symlink is an alias for another node in the filesystem."
+"\n"
+"\nA symbolic link refers to its target `by name', and contains no actual"
+" reference to the target. The target referenced by the symlink is"
+" looked up in the namespace of the client.";
+
+/* Parse a single option/argument. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ if (key == ARGP_KEY_ARG && state->arg_num == 0)
+ linktarget = arg;
+ else if (key == ARGP_KEY_ARG || key == ARGP_KEY_NO_ARGS)
+ argp_usage (state);
+ else
+ return ARGP_ERR_UNKNOWN;
+ return 0;
+}
+
+static struct argp argp = { options, parse_opt, args_doc, doc };
+
+
int
main (int argc, char **argv)
{
mach_port_t bootstrap;
mach_port_t control;
- error_t error;
-
+ error_t err;
+
+ /* Parse our options... */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
task_get_bootstrap_port (mach_task_self (), &bootstrap);
if (bootstrap == MACH_PORT_NULL)
- {
- fprintf (stderr, "%s must be started as a translator\n", argv[0]);
- exit (1);
- }
-
- if (argc != 2)
- {
- fprintf (stderr, "Usage: %s link-target\n", argv[0]);
- exit (1);
- }
+ error (1, 0, "Must be started as a translator");
linktarget = argv[1];
/* Reply to our parent */
mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &control);
- error =
- fsys_startup (bootstrap, 0, control, MACH_MSG_TYPE_MAKE_SEND, &realnode);
- if (error)
- {
- perror ("Starting up translator");
- exit (1);
- }
+ mach_port_insert_right (mach_task_self (), control, control,
+ MACH_MSG_TYPE_MAKE_SEND);
+ err =
+ fsys_startup (bootstrap, 0, control, MACH_MSG_TYPE_COPY_SEND, &realnode);
+ mach_port_deallocate (mach_task_self (), control);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (1, err, "Starting up translator");
+
io_restrict_auth (realnode, &realnodenoauth, 0, 0, 0, 0);
mach_port_deallocate (mach_task_self (), realnode);
@@ -69,9 +102,9 @@ main (int argc, char **argv)
while (1)
{
/* The timeout here is 10 minutes */
- error = mach_msg_server_timeout (fsys_server, 0, control,
- MACH_RCV_TIMEOUT, 1000 * 60 * 10);
- if (error == MACH_RCV_TIMED_OUT)
+ err = mach_msg_server_timeout (fsys_server, 0, control,
+ MACH_RCV_TIMEOUT, 1000 * 60 * 10);
+ if (err == MACH_RCV_TIMED_OUT)
exit (0);
}
}
@@ -79,10 +112,8 @@ main (int argc, char **argv)
error_t
S_fsys_getroot (mach_port_t fsys_t,
mach_port_t dotdotnode,
- uid_t *uids,
- u_int nuids,
- uid_t *gids,
- u_int ngids,
+ uid_t *uids, size_t nuids,
+ uid_t *gids, size_t ngids,
int flags,
retry_type *do_retry,
char *retry_name,
@@ -126,8 +157,7 @@ S_fsys_startup (mach_port_t bootstrap, int flags, mach_port_t control,
}
error_t
-S_fsys_goaway (mach_port_t control,
- int flags)
+S_fsys_goaway (mach_port_t control, int flags)
{
exit (0);
}
@@ -157,12 +187,9 @@ S_fsys_get_options (mach_port_t control,
error_t
S_fsys_getfile (mach_port_t control,
- uid_t *uids,
- u_int nuids,
- uid_t *gids,
- u_int ngids,
- char *handle,
- u_int handllen,
+ uid_t *uids, size_t nuids,
+ uid_t *gids, size_t ngids,
+ char *handle, size_t handllen,
mach_port_t *pt,
mach_msg_type_name_t *pttype)
{
diff --git a/ufs-fsck/ChangeLog b/ufs-fsck/ChangeLog
deleted file mode 100644
index 8fcde4b2..00000000
--- a/ufs-fsck/ChangeLog
+++ /dev/null
@@ -1,256 +0,0 @@
-Tue Jul 23 19:32:09 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (allocino): `struct timespec' now uses a field prefix
- of `tv_'.
- * utilities.c (pinode): Likewise.
-
-Thu Jul 18 14:55:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass2.c (pass2): If an entire directory block is null, allow
- preen to patch it into a normal empty directory entry.
-
-Sat Jul 6 19:59:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (argp_program_version): New variable.
- <hurd.h>: New include.
-
-Mon Jul 1 12:55:48 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass2.c (pass2): Don't skip empty directories in `.' and `..'
- correctness check; we don't clear them the way BSD does, so we
- want `.' and `..' to get created for us. Also handle `.' before
- `..' so that they get created in the usual order for empty
- directories.
-
- * dir.c (makeentry): After successful directory expansion, write
- out modified directory inode.
-
- * pass4.c (pass4): If a reconnect fails while we are preening,
- give up.
-
-Mon Jun 24 10:19:39 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * utilities.c (errexit, punt): Exit with status 8 for catastrophic
- failures.
-
-Thu May 23 14:12:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass2.c (pass2): Don't clear all node types in directories, just
- clear those that are wrong.
-
-Tue May 14 16:49:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pass2.c (pass2): Fix up test in preen case.
-
-Tue May 14 15:29:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass2.c (pass2): Handle directory entry type fields better for
- Hurd.
-
-Sat May 11 01:07:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
-
-Thu May 9 20:12:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass1b.c (pass1b): Bother to initialize NUMBER.
-
-Fri May 3 00:48:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (nice_size, show_stats): New functions.
- (main): Use show_stats.
-
-Wed May 1 13:59:06 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Shorten summary message so that it fits on one line.
- * utilities.c (no_preen): New function.
- (problem, warning, pinode): Use it.
- (warning): Don't flush all pending problems, just our own.
- * dir.c (linkup): Consistently put quotes around filenames.
-
- * main.c (preen, num_files): New variables.
- (main): Implement clean-bit checking in preen mode, and print
- summary statistics.
- (main, options): Add --force & --silent options.
- * pass1.c (pass1): Increment NUM_FILES.
- When clearing inode due to bad blocks, continue.
- * inode.c (allocino, freeino): Frob NUM_FILES.
- * fsck.h (force): New declaration.
- * pass5.c (pass5): Vary clean msg depending on whether FSMODIFIED.
- * setup.c (setup): Use error to print error msgs.
- <error.h>, <errno.h>: New includes.
-
- * utilities.c (problem, warning, pextend, pfail): New functions.
- (pinode, pfix, reply): Use new problem recording stuff.
- (push_problem, resolve_problem, flush_problems): New functions.
- (struct problem): New type.
- (problems, free_problems): New variables.
- (retch, punt): New functions.
- * fsck.h (problem, warning, pextend, pfail): New declarations.
- (pinode): Update declaration.
- * dir.c (validdir, makeentry, linkup): Use new printing functions.
- * pass1.c (pass1): Likewise.
- * pass1b.c (pass1b): Likewise.
- * pass2.c (pass2): Likewise.
- * pass3.c (pass3): Likewise.
- * pass4.c (pass4): Likewise.
- * pass5.c (pass5): Likewise.
- * setup.c (setup): Likewise.
-
-Tue Apr 30 19:06:42 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pass5.c (pass5): Be sure to call pwarn before pfix.
- * main.c (main): Don't print large obnoxious banner if PREEN.
-
-Fri Apr 26 16:20:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * inode.c (allocino): Parenthesize test correctly.
-
- * fsck.h (swab_disk): Define as constant zero.
-
- * pass5.c (pass5): If not marked clean, but now it is, then offer
- to mark it clean.
- * utilities.c (reply): Set fix_denied anytime we return 0.
- * fsck.h (fix_denied): New variable.
-
-Wed Apr 24 13:32:39 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass1.c (pass1): Don't print block numbers as we go anymore.
-
-Tue Apr 23 10:11:49 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass5.c (pass5): Correctly track contig summaries even though
- they aren't used by the filesystem; we still need to preserve the
- format.
-
-Mon Apr 15 12:51:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (vpath tables.c): Find ufs directory in $(top_srcdir).
-
-Tue Apr 2 09:00:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pass1.c (pass1): Print mode correctly in unknown file type case.
- Recognize inode type IFSOCK too.
-
-Mon Mar 18 19:48:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Pass new arg to argp_parse. Use argp_usage correctly.
-
-Thu Oct 19 17:45:12 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Exit with a non-zero status if we fixed anything.
- Use argp to parse options.
- (options): Converted to argp format.
- (args_doc): New variable.
- (USAGE, usage, SHORT_OPTIONS): Removed.
- Include <argp.h> instead of <getopt.h>.
- * Makefile ($(target)): Depend on libshouldbeinlibc.a.
-
-Fri Sep 22 16:55:03 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * utilities.c (pfix): New function.
- (pfatal, pwarn, errexit): Print DEVICE_NAME too if in preen mode.
- * fsck.h: Declare DEVICE_NAME.
- * setup.c (setup): Set DEVICE_NAME.
- * pass1.c, pass2.c, pass3.c, pass4.c, pass5.c (pass1, pass2,
- pass3, pass4, pass5): Call pfix instead of printf.
- * pass1.c (pass1): Only print progress report if not in preen mode.
- * main.c (main): Only print section headers if not in preen mode.
-
-Wed Sep 20 09:11:59 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * utilities.c (pinode): Take a message & args to print as well.
- * fsck.h: Change declaration of pinode.
- * pass2.c (pass2): Use changed pinode.
- * pass3.c (pass3): Use changed pinode.
- * pass4.c (pass4): Use changed pinode.
-
-Tue Sep 19 15:37:02 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pass1.c (pass1): Change the extent of DBWARN & IBWARN so that
- they actually work.
- * pass2.c (pass2): Adjust our record of link counts when we
- add/change dir entries; also print error messages when we can't.
- * pass4.c (pass4): If an unlinked file can't be reconnected, offer
- to clear it. Once a reconnect attempt fails, don't try again.
- * dir.c (linkup): Print the value of LFNAME rather than `lost+found'.
- (searchdir, changeino): Fix backward compare.
- (linkup): Don't fail when makeentry succeeds.
- (searchdir): Make searchdir return zero if there's an error
- during the search.
- (linkup): Print appropiate error messages if searchdir fails.
- (validdir): Get rid of extra newlines in error messages --
- everyone who calls this routine prints extra information if it
- fails, which should immediately follow.
- * main.c (main): Use getopt to parse command line options.
- (usage): New function.
- (options): New variable.
- (lfname, lfmode): Variables moved here from setup.c.
- (lfname): Made into a char* so that we can change it.
- (lfmode): Get rid of IFDIR; it's added when necessary.
- * fsck.h: Change LFNAME to char*.
- * setup.c (lfname, lfmode): Variables moved to main.c.
-
-Sat Sep 9 12:12:59 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (target): Changed to `fsck.ufs'.
- (installationdir): New variable, install into $(sbindir).
-
-Thu Jul 6 15:33:46 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * fsck.h (lookup_directory): New decl.
-
- * pass1.c (pass1): Remove assignment from if test.
- * utilities.c (pinode): Likewise.
-
- * Makefile (tables.o): Delete rule.
- (vpath tables.c): Tell where to find tables.c.
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Thu Nov 3 17:19:03 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (dir): Changed to fsck.
- (target): Changed to fsck.
-
-Wed Nov 2 14:39:13 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * pass2.c (pass2): Use DIRECT_NAMLEN instead of d_namlen
- throughout.
- * dir.c (searchdir): Likewise.
- (changeino): Likewise.
- (makeentry): Likewise.
-
-Mon Oct 17 16:07:56 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (inode_iterate): FN takes new third arg.
- Keep track of new var `offset' and pass it to FN.
- * pass2.c (pass2/checkdirblock): New third arg.
- Only scan DIRBLKSIZ chunks to the total size of the file.
- * dir.c (searchdir/checkdirblock): Likewise.
- (changeino/checkdirblock): Likewise.
- (makeentry/checkdirblock): Likewise.
- * pass1.c (pass1/checkblock): New third arg (ignored).
- * pass1b.c (pass1b/checkblock): Likewise.
-
- * inode.c (inode_iterate): Compute MAXB correctly.
-
- * utilities.c (getinode): Multiple ino_to_fsbo by
- sizeof (struct dinode).
- (write_inode): Likewise.
- (getinode): Inode buffer needs to be a full block, not a
- fragment.
-
-Fri Oct 14 21:07:09 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * utilities.c (lastifrag): New variable.
- (getinode): Use lastifrag instead of buf; Only I/O new block
- if lastifrag isn't what we want.
- (write_inode): Likewise.
-
-Fri Oct 14 17:44:59 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * setup.c (setup): Test ISCHR, not ISDIR.
- Fix NCYL against NCG * CPG test.
- Bother to set MAXFSBLOCK, MAXINO, and DIRECT_SYMLINK_EXTENSION.
diff --git a/ufs-fsck/Makefile b/ufs-fsck/Makefile
index f68fe52a..a484428e 100644
--- a/ufs-fsck/Makefile
+++ b/ufs-fsck/Makefile
@@ -18,7 +18,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-dir := fsck
+dir := ufs-fsck
makemode := utility
SRCS = dir.c main.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
@@ -27,9 +27,9 @@ OBJS = $(subst .c,.o,$(SRCS)) tables.o
LCLHDRS = fsck.h
target = fsck.ufs
installationdir = $(sbindir)
+HURDLIBS=shouldbeinlibc
-vpath tables.c $(top_srcdir)/ufs
+include ../Makeconf
-$(target): ../libshouldbeinlibc/libshouldbeinlibc.a
+vpath tables.c $(top_srcdir)/ufs
-include ../Makeconf
diff --git a/ufs-fsck/dir.c b/ufs-fsck/dir.c
index d4f05858..85757b16 100644
--- a/ufs-fsck/dir.c
+++ b/ufs-fsck/dir.c
@@ -1,5 +1,5 @@
/* Directory management subroutines
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,96,99,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -28,19 +28,19 @@ record_directory (struct dinode *dp, ino_t number)
{
u_int blks;
struct dirinfo *dnp;
-
+
blks = howmany (dp->di_size, sblock->fs_bsize);
if (blks > NDADDR)
- blks = NDADDR * NIADDR;
+ blks = NDADDR + NIADDR;
blks *= sizeof (daddr_t);
dnp = malloc (sizeof (struct dirinfo) + blks);
-
+
dnp->i_number = number;
dnp->i_parent = dnp->i_dotdot = 0;
dnp->i_isize = dp->di_size;
dnp->i_numblks = blks;
bcopy (dp->di_db, dnp->i_blks, blks);
-
+
if (dirarrayused == dirarraysize)
{
if (dirarraysize == 0)
@@ -68,12 +68,12 @@ struct dirinfo *
lookup_directory (ino_t ino)
{
int i;
-
+
for (i = 0; i < dirarrayused; i++)
if (dirarray[i]->i_number == ino)
return dirarray[i];
-
- errexit ("Cannot find chached directory I=%d\n", ino);
+
+ errexit ("Cannot find cached directory I=%Ld\n", ino);
}
/* Check to see if DIR is really a readable directory; if it
@@ -87,23 +87,23 @@ validdir (ino_t dir, char *action)
case DIRECTORY:
case DIRECTORY|DIR_REF:
return 1;
-
+
case UNALLOC:
- warning (1, "CANNOT %s I=%d; NOT ALLOCATED", action, dir);
+ warning (1, "CANNOT %s I=%Ld; NOT ALLOCATED", action, dir);
return 0;
-
+
case BADDIR:
- warning (1, "CANNOT %s I=%d; BAD BLOCKS", action, dir);
+ warning (1, "CANNOT %s I=%Ld; BAD BLOCKS", action, dir);
return 0;
-
+
case REG:
- warning (1, "CANNOT %s I=%d; NOT DIRECTORY", action, dir);
+ warning (1, "CANNOT %s I=%Ld; NOT DIRECTORY", action, dir);
return 0;
default:
errexit ("ILLEGAL STATE");
}
-}
+}
/* Search directory DIR for name NAME. If NAME is found, then
set *INO to the inode of the entry; otherwise clear INO. Returns 1 if all
@@ -114,7 +114,7 @@ searchdir (ino_t dir, char *name, ino_t *ino)
struct dinode dino;
int len;
- /* Scan through one directory block and see if it
+ /* Scan through one directory block and see if it
contains NAME. */
void
check1block (void *buf)
@@ -147,7 +147,7 @@ searchdir (ino_t dir, char *name, ino_t *ino)
{
void *buf = alloca (nfrags * sblock->fs_fsize);
void *bufp;
-
+
readblock (fsbtodb (sblock, bno), buf, nfrags * sblock->fs_fsize);
for (bufp = buf;
bufp - buf < nfrags * sblock->fs_fsize
@@ -160,7 +160,7 @@ searchdir (ino_t dir, char *name, ino_t *ino)
}
return 1;
}
-
+
*ino = 0;
if (!validdir (dir, "READ"))
@@ -220,7 +220,7 @@ changeino (ino_t dir, char *name, ino_t ino)
{
void *buf = alloca (nfrags * sblock->fs_fsize);
void *bufp;
-
+
readblock (fsbtodb (sblock, bno), buf, nfrags * sblock->fs_fsize);
for (bufp = buf;
bufp - buf < nfrags * sblock->fs_fsize
@@ -236,10 +236,10 @@ changeino (ino_t dir, char *name, ino_t ino)
}
return 1;
}
-
+
if (!validdir (dir, "REWRITE"))
return 0;
-
+
getinode (dir, &dino);
len = strlen (name);
madechange = 0;
@@ -254,7 +254,7 @@ expanddir (struct dinode *dp)
{
daddr_t lastbn, newblk;
char *cp, buf[sblock->fs_bsize];
-
+
lastbn = lblkno (sblock, dp->di_size);
if (blkoff (sblock, dp->di_size) && lastbn >= NDADDR - 1)
return 0;
@@ -264,24 +264,24 @@ expanddir (struct dinode *dp)
return 0;
else if (!blkoff (sblock, dp->di_size) && dp->di_db[lastbn])
return 0;
-
+
newblk = allocblk (sblock->fs_frag);
if (!newblk)
return 0;
-
+
if (blkoff (sblock, dp->di_size))
dp->di_db[lastbn + 1] = dp->di_db[lastbn];
dp->di_db[lastbn] = newblk;
dp->di_size += sblock->fs_bsize;
dp->di_blocks += sblock->fs_bsize / DEV_BSIZE;
-
+
for (cp = buf; cp < buf + sblock->fs_bsize; cp += DIRBLKSIZ)
{
struct directory_entry *dir = (struct directory_entry *) cp;
dir->d_ino = 0;
dir->d_reclen = DIRBLKSIZ;
}
-
+
writeblock (fsbtodb (sblock, newblk), buf, sblock->fs_bsize);
return 1;
}
@@ -297,10 +297,10 @@ makeentry (ino_t dir, ino_t ino, char *name)
struct dinode dino;
int needed;
int madeentry;
-
+
/* Read a directory block and see if it contains room for the
new entry. If so, add it and return 1; otherwise return 0. */
- int
+ int
check1block (void *buf)
{
struct directory_entry *dp;
@@ -341,7 +341,7 @@ makeentry (ino_t dir, ino_t ino, char *name)
}
}
return 0;
- }
+ }
/* Read part of a directory and look to see if it
contains NAME. Return 1 if we should keep looking
@@ -351,7 +351,7 @@ makeentry (ino_t dir, ino_t ino, char *name)
{
void *buf = alloca (nfrags * sblock->fs_fsize);
void *bufp;
-
+
readblock (fsbtodb (sblock, bno), buf, nfrags * sblock->fs_fsize);
for (bufp = buf;
bufp - buf < nfrags * sblock->fs_fsize
@@ -367,10 +367,10 @@ makeentry (ino_t dir, ino_t ino, char *name)
}
return 1;
}
-
+
if (!validdir (dir, "MODIFY"))
return 0;
-
+
getinode (dir, &dino);
len = strlen (name);
needed = DIRSIZ (len);
@@ -379,7 +379,7 @@ makeentry (ino_t dir, ino_t ino, char *name)
if (!madeentry)
{
/* Attempt to expand the directory. */
- problem (0, "NO SPACE LEFT IN DIR INO=%d", dir);
+ problem (0, "NO SPACE LEFT IN DIR INO=%Ld", dir);
if (preen || reply ("EXPAND"))
{
if (expanddir (&dino))
@@ -408,7 +408,7 @@ allocdir (ino_t parent, ino_t request, mode_t mode)
ino_t ino;
mode |= IFDIR;
-
+
ino = allocino (request, mode);
if (!ino)
return 0;
@@ -416,11 +416,11 @@ allocdir (ino_t parent, ino_t request, mode_t mode)
goto bad;
if (!makeentry (ino, parent, ".."))
goto bad;
-
+
linkfound[ino]++;
linkfound[parent]++;
return ino;
-
+
bad:
freeino (ino);
return 0;
@@ -471,16 +471,16 @@ linkup (ino_t ino, ino_t parent)
}
}
}
-
+
getinode (lfdir, &lfdino);
if ((lfdino.di_model & IFMT) != IFDIR)
{
ino_t oldlfdir;
-
+
problem (1, "`%s' IS NOT A DIRECTORY", lfname);
if (! reply ("REALLOCATE"))
return 0;
-
+
oldlfdir = lfdir;
lfdir = allocdir (ROOTINO, 0, lfmode);
@@ -494,20 +494,20 @@ linkup (ino_t ino, ino_t parent)
warning (1, "SORRY, CANNOT CREATE `%s' DIRECTORY", lfname);
return 0;
}
-
+
/* One less link to the old one */
linkfound[oldlfdir]--;
-
+
getinode (lfdir, &lfdino);
}
-
+
if (inodestate[lfdir] != DIRECTORY && inodestate[lfdir] != (DIRECTORY|DIR_REF))
{
warning (1, "SORRY. `%s' DIRECTORY NOT ALLOCATED", lfname);
return 0;
}
- asprintf (&tempname, "#%d", ino);
+ asprintf (&tempname, "#%Ld", ino);
search_failed = !searchdir (lfdir, tempname, &foo);
while (foo)
{
@@ -519,8 +519,8 @@ linkup (ino_t ino, ino_t parent)
}
if (search_failed)
{
- free (tempname);
warning (1, "FAILURE SEARCHING FOR `%s' IN `%s'", tempname, lfname);
+ free (tempname);
return 0;
}
if (!makeentry (lfdir, ino, tempname))
@@ -531,7 +531,7 @@ linkup (ino_t ino, ino_t parent)
}
free (tempname);
linkfound[ino]++;
-
+
if (parent != -1)
{
/* Reset `..' in ino */
@@ -539,7 +539,7 @@ linkup (ino_t ino, ino_t parent)
{
if (!changeino (ino, "..", lfdir))
{
- warning (1, "CANNOT ADJUST `..' LINK I=%u", ino);
+ warning (1, "CANNOT ADJUST `..' LINK I=%Ld", ino);
return 0;
}
/* Forget about link to old parent */
@@ -547,21 +547,21 @@ linkup (ino_t ino, ino_t parent)
}
else if (!makeentry (ino, lfdir, ".."))
{
- warning (1, "CANNOT CREAT `..' LINK I=%u", ino);
+ warning (1, "CANNOT CREAT `..' LINK I=%Ld", ino);
return 0;
}
-
+
/* Account for link to lost+found; update inode directly
here to avoid confusing warning later. */
linkfound[lfdir]++;
linkcount[lfdir]++;
lfdino.di_nlink++;
write_inode (lfdir, &lfdino);
-
+
if (parent)
- warning (0, "DIR I=%u CONNECTED; PARENT WAS I=%u", ino, parent);
+ warning (0, "DIR I=%Ld CONNECTED; PARENT WAS I=%Ld", ino, parent);
else
- warning (0, "DIR I=%u CONNECTED", ino);
+ warning (0, "DIR I=%Ld CONNECTED", ino);
}
return 1;
}
diff --git a/ufs-fsck/fsck.h b/ufs-fsck/fsck.h
index 7d55bea6..4a5dabf5 100644
--- a/ufs-fsck/fsck.h
+++ b/ufs-fsck/fsck.h
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1994,95,96,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -59,7 +59,7 @@ char *blockmap;
extern char *device_name;
-/* Command line flags */
+/* Command line flags */
int nowrite; /* all questions fail */
int noquery; /* all questions succeed */
@@ -81,7 +81,7 @@ struct dirinfo
ino_t i_parent; /* inode entry of parent */
ino_t i_dotdot; /* inode number of `..' */
ino_t i_dot; /* inode number of `.' */
- ino_t i_isize; /* size of inode */
+ u_int i_isize; /* size of inode */
u_int i_numblks; /* size of block array in bytes */
daddr_t i_blks[0]; /* array of inode block addresses */
};
@@ -121,10 +121,10 @@ extern int fix_denied;
extern int fsmodified;
-extern int lfdir;
+extern ino_t lfdir;
/* Total number of files found on the partition. */
-extern daddr_t num_files;
+extern long num_files;
extern mode_t lfmode;
extern char *lfname;
@@ -145,7 +145,7 @@ extern char *lfname;
#define DI_MODE(dp) (((dp)->di_modeh << 16) | (dp)->di_model)
-
+
int setup (char *);
void pass1 (), pass1b (), pass2 (), pass3 (), pass4 (), pass5 ();
diff --git a/ufs-fsck/main.c b/ufs-fsck/main.c
index b5af2d88..34c32a67 100644
--- a/ufs-fsck/main.c
+++ b/ufs-fsck/main.c
@@ -1,5 +1,5 @@
/* Main program for GNU fsck
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -21,10 +21,11 @@
#include <errno.h>
#include <argp.h>
#include <hurd.h>
+#include <version.h>
#include "fsck.h"
-char *argp_program_version = "fsck.ufs 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (fsck.ufs);
char *lfname = "lost+found";
mode_t lfmode = 0755;
diff --git a/ufs-fsck/pass1.c b/ufs-fsck/pass1.c
index 066f4649..bd41cc62 100644
--- a/ufs-fsck/pass1.c
+++ b/ufs-fsck/pass1.c
@@ -1,5 +1,5 @@
/* Pass one of GNU fsck -- count blocks and verify inodes
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -24,7 +24,7 @@
static struct dinode zino;
-/* Find all the blocks in use by files and filesystem reserved blocks.
+/* Find all the blocks in use by files and filesystem reserved blocks.
Set them in the global block map. For each file, if a block is found
allocated twice, then record the block and inode in DUPLIST.
Initialize INODESTATE, LINKCOUNT, and TYPEMAP. */
@@ -52,7 +52,7 @@ pass1 ()
node. Increment NBLOCKS by the number of data blocks held.
Set BLKERROR if this block is invalid.
Return RET_GOOD, RET_BAD, RET_STOP if the block is good,
- bad, or if we should entirely stop checking blocks in this
+ bad, or if we should entirely stop checking blocks in this
inode. */
int
checkblock (daddr_t bno, int nfrags, off_t offset)
@@ -69,10 +69,10 @@ pass1 ()
blkerror = 1;
wasbad = 1;
if (nblkrngerrors == 0)
- warning (0, "I=%d HAS BAD BLOCKS", number);
+ warning (0, "I=%Ld HAS BAD BLOCKS", number);
if (nblkrngerrors++ > MAXBAD)
{
- problem (0, "EXCESSIVE BAD BLKS I=%d", number);
+ problem (0, "EXCESSIVE BAD BLKS I=%Ld", number);
if (preen || reply ("SKIP"))
{
pfail ("SKIPPING");
@@ -93,12 +93,12 @@ pass1 ()
{
blkerror = 1;
if (nblkduperrors == 0)
- warning (0, "I=%d HAS DUPLICATE BLOCKS", number);
+ warning (0, "I=%Ld HAS DUPLICATE BLOCKS", number);
warning (0, "DUPLICATE BLOCK %ld", bno);
wasbad = 1;
if (nblkduperrors++ > MAXBAD)
{
- problem (0, "EXCESSIVE DUP BLKS I=%d", number);
+ problem (0, "EXCESSIVE DUP BLKS I=%Ld", number);
if (preen || reply ("SKIP"))
{
pfail ("SKIPPING");
@@ -128,16 +128,16 @@ pass1 ()
}
return wasbad ? RET_BAD : RET_GOOD;
}
-
+
/* Account for blocks used by meta data */
for (cg = 0; cg < sblock->fs_ncg; cg++)
{
daddr_t firstdata, firstcgblock, bno;
-
+
/* Each cylinder group past the first reserves data
from its cylinder group copy to (but not including)
- the first datablock.
+ the first datablock.
The first, however, reserves from the very front of the
cylinder group (thus including the boot block), and it also
@@ -155,7 +155,7 @@ pass1 ()
for (bno = firstcgblock; bno < firstdata; bno++)
setbmap (bno);
}
-
+
/* Loop through each inode, doing initial checks */
for (number = 0, cg = 0; cg < sblock->fs_ncg; cg++)
for (i = 0; i < sblock->fs_ipg; i++, number++)
@@ -165,15 +165,15 @@ pass1 ()
int dbwarn = 0, ibwarn = 0;
/* if (!preen && !(number % 10000))
- printf ("I=%d\n", number); */
+ printf ("I=%Ld\n", number); */
if (number < ROOTINO)
continue;
-
+
getinode (number, dp);
mode = DI_MODE (dp);
type = mode & IFMT;
-
+
/* If the node is not allocated, then make sure it's
properly clear */
if (type == 0)
@@ -184,7 +184,7 @@ pass1 ()
|| DI_MODE (dp)
|| dp->di_size)
{
- problem (0, "PARTIALLY ALLOCATED INODE I=%d", number);
+ problem (0, "PARTIALLY ALLOCATED INODE I=%Ld", number);
if (preen || reply ("CLEAR"))
{
clear_inode (number, dp);
@@ -196,15 +196,15 @@ pass1 ()
else
{
/* Node is allocated. */
-
+
/* Check to see if we think the node should be cleared */
/* Verify size for basic validity */
holdallblocks = 0;
-
+
if (dp->di_size + sblock->fs_bsize - 1 < dp->di_size)
{
- problem (1, "OVERFLOW IN FILE SIZE I=%d (SIZE == %lld)", number,
+ problem (1, "OVERFLOW IN FILE SIZE I=%Ld (SIZE == %lld)", number,
dp->di_size);
if (reply ("CLEAR"))
{
@@ -213,12 +213,12 @@ pass1 ()
continue;
}
inodestate[number] = UNALLOC;
- warning (0, "WILL TREAT ANY BLOCKS HELD BY I=%d AS ALLOCATED",
+ warning (0, "WILL TREAT ANY BLOCKS HELD BY I=%Ld AS ALLOCATED",
number);
holdallblocks = 1;
}
- /* Decode type and set NDB
+ /* Decode type and set NDB
also set inodestate correctly. */
inodestate[number] = REG;
switch (type)
@@ -227,19 +227,19 @@ pass1 ()
case IFCHR:
ndb = 1;
break;
-
+
case IFIFO:
case IFSOCK:
ndb = 0;
break;
-
+
case IFLNK:
if (sblock->fs_maxsymlinklen != -1)
{
/* Check to see if this is a fastlink. The
old fast link format has fs_maxsymlinklen
of zero and di_blocks zero; the new format has
- fs_maxsymlinklen set and we ignore di_blocks.
+ fs_maxsymlinklen set and we ignore di_blocks.
So check for either. */
if ((sblock->fs_maxsymlinklen
&& dp->di_size < sblock->fs_maxsymlinklen)
@@ -262,16 +262,16 @@ pass1 ()
else
ndb = howmany (dp->di_size, sblock->fs_bsize);
break;
-
+
case IFDIR:
inodestate[number] = DIRECTORY;
/* Fall through */
case IFREG:
ndb = howmany (dp->di_size, sblock->fs_bsize);
break;
-
+
default:
- problem (1, "UNKNOWN FILE TYPE I=%d (MODE=%ol)", number, mode);
+ problem (1, "UNKNOWN FILE TYPE I=%Ld (MODE=%ol)", number, mode);
if (reply ("CLEAR"))
{
clear_inode (number, dp);
@@ -280,14 +280,14 @@ pass1 ()
}
inodestate[number] = UNALLOC;
holdallblocks = 1;
- warning (0, "WILL TREAT ANY BLOCKS HELD BY I=%d "
+ warning (0, "WILL TREAT ANY BLOCKS HELD BY I=%Ld "
"AS ALLOCATED", number);
ndb = 0;
}
if (ndb < 0)
{
- problem (1, "BAD FILE SIZE I= %d (SIZE == %lld)", number,
+ problem (1, "BAD FILE SIZE I= %Ld (SIZE == %lld)", number,
dp->di_size);
if (reply ("CLEAR"))
{
@@ -296,7 +296,7 @@ pass1 ()
continue;
}
inodestate[number] = UNALLOC;
- warning (0, "WILL TREAT ANY BLOCKS HELD BY I=%d AS ALLOCATED",
+ warning (0, "WILL TREAT ANY BLOCKS HELD BY I=%Ld AS ALLOCATED",
number);
holdallblocks = 1;
}
@@ -308,10 +308,10 @@ pass1 ()
if (!holdallblocks)
{
if (dp->di_size
- && (type == IFBLK || type == IFCHR
+ && (type == IFBLK || type == IFCHR
|| type == IFSOCK || type == IFIFO))
{
- problem (1, "SPECIAL NODE I=%d (MODE=%ol) HAS SIZE %lld",
+ problem (1, "SPECIAL NODE I=%Ld (MODE=%ol) HAS SIZE %lld",
number, mode, dp->di_size);
if (reply ("TRUNCATE"))
{
@@ -319,10 +319,10 @@ pass1 ()
write_inode (number, dp);
}
}
-
+
/* If we haven't set NDB speciall above, then it is set from
the file size correctly by the size check. */
-
+
/* Check all the direct and indirect blocks that are past the
amount necessary to be zero. */
for (lbn = ndb; lbn < NDADDR; lbn++)
@@ -332,7 +332,7 @@ pass1 ()
if (!dbwarn)
{
dbwarn = 1;
- problem (0, "INODE I=%d HAS EXTRA DIRECT BLOCKS",
+ problem (0, "INODE I=%Ld HAS EXTRA DIRECT BLOCKS",
number);
if (preen || reply ("DEALLOCATE"))
{
@@ -357,7 +357,7 @@ pass1 ()
if (ibwarn)
{
ibwarn = 1;
- problem (0, "INODE I=%d HAS EXTRA INDIRECT BLOCKS",
+ problem (0, "INODE I=%Ld HAS EXTRA INDIRECT BLOCKS",
number);
if (preen || reply ("DEALLOCATE"))
{
@@ -373,7 +373,7 @@ pass1 ()
write_inode (number, dp);
}
}
-
+
/* If this node is really allocated (as opposed to something
that we should clear but the user won't) then set LINKCOUNT
and TYPEMAP entries. */
@@ -397,7 +397,7 @@ pass1 ()
warning (1, "DUPLICATE or BAD BLOCKS");
else
{
- problem (0, "I=%d has ", number);
+ problem (0, "I=%Ld has ", number);
if (nblkduperrors)
{
pextend ("%d DUPLICATE BLOCKS", nblkduperrors);
@@ -418,7 +418,7 @@ pass1 ()
}
else if (dp->di_blocks != nblocks)
{
- problem (0, "INCORRECT BLOCK COUNT I=%d (%ld should be %d)",
+ problem (0, "INCORRECT BLOCK COUNT I=%Ld (%ld should be %d)",
number, dp->di_blocks, nblocks);
if (preen || reply ("CORRECT"))
{
@@ -435,5 +435,3 @@ pass1 ()
}
}
}
-
-
diff --git a/ufs-fsck/pass1b.c b/ufs-fsck/pass1b.c
index 0cf50a17..4da86974 100644
--- a/ufs-fsck/pass1b.c
+++ b/ufs-fsck/pass1b.c
@@ -1,5 +1,5 @@
/* Pass 1b of fsck -- scan inodes for references to duplicate blocks
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,96,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -31,7 +31,7 @@ pass1b ()
struct dups *duphead = duplist;
/* Check each block of file DP; if the block is in the dup block
- list then add it to the dup block list under this file.
+ list then add it to the dup block list under this file.
Return RET_GOOD or RET_BAD if the block is
good or bad, respectively. */
int
@@ -39,7 +39,7 @@ pass1b ()
{
struct dups *dlp;
int hadbad = 0;
-
+
for (; nfrags > 0; bno++, nfrags--)
{
if (check_range (bno, 1))
@@ -76,7 +76,7 @@ pass1b ()
allblock_iterate (dp, checkblock);
if (dupblk)
{
- problem (1, "I=%d HAS %d DUPLICATE BLOCKS", number, dupblk);
+ problem (1, "I=%Ld HAS %d DUPLICATE BLOCKS", number, dupblk);
if (reply ("CLEAR"))
{
clear_inode (number, dp);
@@ -88,5 +88,3 @@ pass1b ()
}
}
}
-
-
diff --git a/ufs-fsck/pass2.c b/ufs-fsck/pass2.c
index db63abd7..d95929ef 100644
--- a/ufs-fsck/pass2.c
+++ b/ufs-fsck/pass2.c
@@ -1,5 +1,5 @@
/* Pass 2 of GNU fsck -- examine all directories for validity
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,96,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "fsck.h"
+#include <assert.h>
/* Verify root inode's allocation and check all directories for
viability. Set DIRSORTED array fully and check to make sure
@@ -69,7 +70,7 @@ pass2 ()
for (bp = (char *)buf; bp < (char *)buf + DIRBLKSIZ; bp++)
if (*bp)
goto reclen_problem;
-
+
problem (0, "NULL BLOCK IN DIRECTORY");
if (preen || reply ("PATCH"))
{
@@ -82,7 +83,7 @@ pass2 ()
else
return mod;
}
-
+
reclen_problem:
problem (1, "BAD RECLEN IN DIRECTORY");
if (reply ("SALVAGE"))
@@ -97,7 +98,7 @@ pass2 ()
/* But give up regardless */
return mod;
}
-
+
/* Check INO */
if (dp->d_ino > maxino)
{
@@ -112,7 +113,7 @@ pass2 ()
if (!dp->d_ino)
continue;
-
+
/* Check INO */
if (inodestate[dp->d_ino] == UNALLOC)
{
@@ -137,7 +138,7 @@ pass2 ()
dp->d_ino = 0;
mod = 1;
}
- }
+ }
else
{
/* Check for illegal characters */
@@ -164,7 +165,7 @@ pass2 ()
}
}
}
-
+
if (!dp->d_ino)
continue;
@@ -180,10 +181,10 @@ pass2 ()
mod = 1;
}
}
-
+
/* Here we should check for duplicate directory entries;
that's too much trouble right now. */
-
+
/* Account for the inode in the linkfound map */
if (inodestate[dp->d_ino] != UNALLOC)
linkfound[dp->d_ino]++;
@@ -204,7 +205,7 @@ pass2 ()
{
problem (0, "EXTRANEOUS LINK `%s' TO DIR I=%ld",
dp->d_name, dp->d_ino);
- pextend (" FOUND IN DIR I=%d", dnp->i_number);
+ pextend (" FOUND IN DIR I=%Ld", dnp->i_number);
if (preen || reply ("REMOVE"))
{
dp->d_ino = 0;
@@ -233,9 +234,9 @@ pass2 ()
readblock (fsbtodb (sblock, bno), buf, nfrags * sblock->fs_fsize);
rewrite = 0;
- for (bufp = buf;
+ for (bufp = buf;
bufp - buf < nfrags * sblock->fs_fsize
- && offset + (bufp - buf) + DIRBLKSIZ <= dnp->i_isize;
+ && offset + (bufp - buf) + DIRBLKSIZ <= dnp->i_isize;
bufp += DIRBLKSIZ)
{
if (check1block (bufp))
@@ -250,7 +251,7 @@ pass2 ()
{
default:
errexit ("BAD STATE %d FOR ROOT INODE", (int) (inodestate[ROOTINO]));
-
+
case DIRECTORY:
break;
@@ -261,7 +262,7 @@ pass2 ()
if (allocdir (ROOTINO, ROOTINO, 0755) != ROOTINO)
errexit ("CANNOT ALLOCATE ROOT INODE");
break;
-
+
case REG:
problem (1, "ROOT INODE NOT DIRECTORY");
if (reply ("REALLOCATE"))
@@ -269,7 +270,7 @@ pass2 ()
if (allocdir (ROOTINO, ROOTINO, 0755) != ROOTINO)
errexit ("CANNOT ALLOCATE ROOT INODE");
break;
-
+
case BADDIR:
problem (1, "DUPLICATE or BAD BLOCKS IN ROOT INODE");
if (reply ("REALLOCATE"))
@@ -282,20 +283,20 @@ pass2 ()
errexit ("ABORTING");
break;
}
-
+
/* Sort inpsort */
qsort (dirsorted, dirarrayused, sizeof (struct dirinfo *), sortfunc);
-
+
/* Check basic integrity of each directory */
for (nd = 0; nd < dirarrayused; nd++)
{
dnp = dirsorted[nd];
-
+
if (dnp->i_isize == 0)
continue;
if (dnp->i_isize % DIRBLKSIZ)
{
- problem (0, "DIRECTORY INO=%d: LENGTH %d NOT MULTIPLE OF %d",
+ problem (0, "DIRECTORY INO=%Ld: LENGTH %d NOT MULTIPLE OF %d",
dnp->i_number, dnp->i_isize, DIRBLKSIZ);
if (preen || reply ("ADJUST"))
{
@@ -307,11 +308,12 @@ pass2 ()
}
bzero (&dino, sizeof (struct dinode));
dino.di_size = dnp->i_isize;
+ assert (dnp->i_numblks <= (NDADDR + NIADDR) * sizeof (daddr_t));
bcopy (dnp->i_blks, dino.di_db, dnp->i_numblks);
-
+
datablocks_iterate (&dino, checkdirblock);
}
-
+
/* At this point for each directory:
If this directory is an entry in another directory, then i_parent is
@@ -321,12 +323,12 @@ pass2 ()
for (nd = 0; nd < dirarrayused; nd++)
{
dnp = dirsorted[nd];
-
+
/* Root is considered to be its own parent even though it isn't
listed. */
if (dnp->i_number == ROOTINO && !dnp->i_parent)
dnp->i_parent = ROOTINO;
-
+
/* Check `.' to make sure it exists and is correct */
if (dnp->i_dot == 0)
{
@@ -395,5 +397,4 @@ pass2 ()
}
}
}
-}
-
+}
diff --git a/ufs-fsck/pass5.c b/ufs-fsck/pass5.c
index 7ea7aeed..cb426a7d 100644
--- a/ufs-fsck/pass5.c
+++ b/ufs-fsck/pass5.c
@@ -1,5 +1,5 @@
/* Pass 5 of GNU fsck -- check allocation maps and summaries
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,96,2001 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -23,7 +23,7 @@
/* From ../ufs/subr.c: */
/*
- * Update the frsum fields to reflect addition or deletion
+ * Update the frsum fields to reflect addition or deletion
* of some frags.
*/
static void
@@ -87,7 +87,7 @@ pass5 ()
sbcsums = alloca (fragroundup (sblock, sblock->fs_cssize));
- readblock (fsbtodb (sblock, sblock->fs_csaddr), sbcsums,
+ readblock (fsbtodb (sblock, sblock->fs_csaddr), sbcsums,
fragroundup (sblock, sblock->fs_cssize));
/* Construct a CG structure; initialize everything that's the same
@@ -105,37 +105,37 @@ pass5 ()
savednrpos = sblock->fs_nrpos;
sblock->fs_nrpos = 8;
break;
-
+
case FS_DYNAMICPOSTBLFMT:
/* Set fields unique to new cg structure */
newcg->cg_btotoff = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
newcg->cg_boff = newcg->cg_btotoff + sblock->fs_cpg * sizeof (long);
newcg->cg_iusedoff = newcg->cg_boff + (sblock->fs_cpg
- * sblock->fs_nrpos
+ * sblock->fs_nrpos
* sizeof (short));
newcg->cg_freeoff = newcg->cg_iusedoff + howmany (sblock->fs_ipg, NBBY);
if (sblock->fs_contigsumsize <= 0)
{
- newcg->cg_nextfreeoff =
+ newcg->cg_nextfreeoff =
(newcg->cg_freeoff
+ howmany (sblock->fs_cpg * sblock->fs_spc / NSPF (sblock),
NBBY));
}
else
{
- newcg->cg_clustersumoff =
+ newcg->cg_clustersumoff =
(newcg->cg_freeoff
+ howmany (sblock->fs_cpg * sblock->fs_spc / NSPF (sblock), NBBY)
- sizeof (long));
- newcg->cg_clustersumoff =
+ newcg->cg_clustersumoff =
roundup (newcg->cg_clustersumoff, sizeof (long));
- newcg->cg_clusteroff =
- (newcg->cg_clustersumoff
+ newcg->cg_clusteroff =
+ (newcg->cg_clustersumoff
+ (sblock->fs_contigsumsize + 1) * sizeof (long));
- newcg->cg_nextfreeoff =
- (newcg->cg_clusteroff
- + howmany (sblock->fs_cpg * sblock->fs_spc / NSPB (sblock),
+ newcg->cg_nextfreeoff =
+ (newcg->cg_clusteroff
+ + howmany (sblock->fs_cpg * sblock->fs_spc / NSPB (sblock),
NBBY));
}
@@ -150,32 +150,32 @@ pass5 ()
default:
errexit ("UNKNOWN POSTBL FORMAT");
}
-
+
bzero (&cstotal, sizeof (struct csum));
/* Mark fragments past the end of the filesystem as used. */
j = blknum (sblock, sblock->fs_size + sblock->fs_frag - 1);
for (i = sblock->fs_size; i < j; i++)
setbmap (i);
-
+
/* Now walk through the cylinder groups, checking each one. */
for (c = 0; c < sblock->fs_ncg; c++)
{
int dbase, dmax;
-
+
/* Read the cylinder group structure */
readblock (fsbtodb (sblock, cgtod (sblock, c)), cg, sblock->fs_cgsize);
writecg = 0;
-
+
if (!cg_chkmagic (cg))
warning (1, "CG %d: BAD MAGIC NUMBER", c);
-
+
/* Compute first and last data block addresses in this group */
dbase = cgbase (sblock, c);
dmax = dbase + sblock->fs_fpg;
if (dmax > sblock->fs_size)
dmax = sblock->fs_size;
-
+
/* Initialize newcg fully; values from cg for those
we can't check. */
newcg->cg_time = cg->cg_time;
@@ -230,7 +230,7 @@ pass5 ()
pfix ("FIXED");
}
}
-
+
/* Zero the block maps and summary areas */
bzero (&newcg->cg_frsum[0], sizeof newcg->cg_frsum);
bzero (&cg_blktot (newcg)[0], sumsize + mapsize);
@@ -267,8 +267,8 @@ pass5 ()
setbit (cg_inosused (newcg), i);
newcg->cg_cs.cs_nifree--;
}
-
- /* Walk through each data block, accounting for it in
+
+ /* Walk through each data block, accounting for it in
the block map and in newcg->cg_cs. */
/* In this look, D is the block number and I is the
block number relative to this CG. */
@@ -277,7 +277,7 @@ pass5 ()
d += sblock->fs_frag, i += sblock->fs_frag)
{
int frags = 0;
-
+
/* Set each free frag of this block in the block map;
count how many frags were free. */
for (j = 0; j < sblock->fs_frag; j++)
@@ -287,8 +287,8 @@ pass5 ()
setbit (cg_blksfree (newcg), i + j);
frags++;
}
-
- /* If all the frags were free, then count this as
+
+ /* If all the frags were free, then count this as
a free block too. */
if (frags == sblock->fs_frag)
{
@@ -308,7 +308,7 @@ pass5 ()
ffs_fragacct (sblock, blk, newcg->cg_frsum, 1);
}
}
-
+
if (sblock->fs_contigsumsize > 0)
{
long *sump = cg_clustersum (newcg);
@@ -316,7 +316,7 @@ pass5 ()
int map = *mapp++;
int bit = 1;
int run = 0;
-
+
for (i = 0; i < newcg->cg_nclusterblks; i++)
{
if ((map & bit) != 0)
@@ -363,7 +363,7 @@ pass5 ()
pfix ("FIXED");
}
}
-
+
/* Check inode and block maps */
if (bcmp (cg_inosused (newcg), cg_inosused (cg), mapsize))
{
@@ -375,7 +375,7 @@ pass5 ()
pfix ("FIXED");
}
}
-
+
if (bcmp (&cg_blktot(newcg)[0], &cg_blktot(cg)[0], sumsize))
{
problem (0, "SUMMARY INFORMATION FOR CG %d BAD", c);
@@ -386,7 +386,7 @@ pass5 ()
pfix ("FIXED");
}
}
-
+
if (bcmp (newcg, cg, basesize))
{
problem (0, "CYLINDER GROUP %d BAD", c);
@@ -399,14 +399,14 @@ pass5 ()
}
if (writecg)
- writeblock (fsbtodb (sblock, cgtod (sblock, c)),
+ writeblock (fsbtodb (sblock, cgtod (sblock, c)),
cg, sblock->fs_cgsize);
}
-
+
/* Restore nrpos */
if (sblock->fs_postblformat == FS_42POSTBLFMT)
sblock->fs_nrpos = savednrpos;
-
+
if (bcmp (&cstotal, &sblock->fs_cstotal, sizeof (struct csum)))
{
problem (0, "TOTAL FREE BLK COUNTS WRONG IN SUPERBLOCK");
@@ -430,21 +430,21 @@ pass5 ()
pfix ("MARKED CLEAN");
}
}
-
+
if (writesb)
writeblock (SBLOCK, sblock, SBSIZE);
if (writecsum)
{
+ const int cssize = fragroundup (sblock, sblock->fs_cssize);
struct csum *test;
-
- writeblock (fsbtodb (sblock, sblock->fs_csaddr), sbcsums,
+
+ writeblock (fsbtodb (sblock, sblock->fs_csaddr), sbcsums,
fragroundup (sblock, sblock->fs_cssize));
- test = alloca (fragroundup (sblock, sblock->fs_cssize));
- readblock (fsbtodb (sblock, sblock->fs_csaddr), test,
- fragroundup (sblock, sblock->fs_cssize));
- if (bcmp (test, sbcsums, fragroundup (sblock, sblock->fs_cssize)))
+ test = alloca (cssize);
+ readblock (fsbtodb (sblock, sblock->fs_csaddr), test, cssize);
+ if (bcmp (test, sbcsums, cssize))
warning (0, "CSUM WRITE INCONSISTENT");
}
}
diff --git a/ufs-fsck/setup.c b/ufs-fsck/setup.c
index d40cf70b..9433bd68 100644
--- a/ufs-fsck/setup.c
+++ b/ufs-fsck/setup.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+/*
+ Copyright (C) 1994,96,99,2002 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -42,7 +42,7 @@ int fix_denied = 0;
int fsmodified = 0;
-int lfdir;
+ino_t lfdir;
/* Get ready to run on device with pathname DEV. */
int
@@ -51,7 +51,7 @@ setup (char *dev)
struct stat st;
int changedsb;
size_t bmapsize;
-
+
device_name = dev;
if (stat (dev, &st) == -1)
@@ -59,9 +59,9 @@ setup (char *dev)
error (0, errno, "%s", dev);
return 0;
}
- if (!S_ISCHR (st.st_mode))
+ if (!S_ISCHR (st.st_mode) && !S_ISBLK (st.st_mode))
{
- problem (1, "%s is not a character device", dev);
+ problem (1, "%s is not a character or block device", dev);
if (! reply ("CONTINUE"))
return 0;
}
@@ -88,7 +88,7 @@ setup (char *dev)
if (preen == 0)
printf ("\n");
-
+
lfdir = 0;
/* We don't do the alternate superblock stuff here (yet). */
@@ -171,10 +171,10 @@ setup (char *dev)
sblock->fs_qfmask = ~sblock->fs_fmask;
newinofmt = 0;
}
-
+
if (changedsb)
writeblock (SBLOCK, sblock, SBSIZE);
-
+
/* Constants */
maxfsblock = sblock->fs_size;
maxino = sblock->fs_ncg * sblock->fs_ipg;
@@ -189,6 +189,3 @@ setup (char *dev)
linkfound = calloc (maxino + 1, sizeof (nlink_t));
return 1;
}
-
-
-
diff --git a/ufs-fsck/utilities.c b/ufs-fsck/utilities.c
index 4c515f61..14705f84 100644
--- a/ufs-fsck/utilities.c
+++ b/ufs-fsck/utilities.c
@@ -1,5 +1,5 @@
/* Miscellaneous functions for fsck
- Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1994,95,96,99,2001,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell.
This file is part of the GNU Hurd.
@@ -25,6 +25,7 @@
#include <stdarg.h>
#include <pwd.h>
#include <error.h>
+#include <time.h>
static void retch (char *reason);
@@ -61,12 +62,12 @@ getinode (ino_t ino, struct dinode *di)
if (!lastifrag)
lastifrag = malloc (sblock->fs_bsize);
-
+
iblk = ino_to_fsba (sblock, ino);
if (iblk != lastifragaddr)
readblock (fsbtodb (sblock, iblk), lastifrag, sblock->fs_bsize);
lastifragaddr = iblk;
- bcopy (lastifrag + ino_to_fsbo (sblock, ino) * sizeof (struct dinode),
+ bcopy (lastifrag + ino_to_fsbo (sblock, ino) * sizeof (struct dinode),
di, sizeof (struct dinode));
}
@@ -75,7 +76,7 @@ void
write_inode (ino_t ino, struct dinode *di)
{
daddr_t iblk;
-
+
iblk = ino_to_fsba (sblock, ino);
if (iblk != lastifragaddr)
readblock (fsbtodb (sblock, iblk), lastifrag, sblock->fs_bsize);
@@ -101,10 +102,10 @@ allocblk (int nfrags)
{
daddr_t i;
int j, k;
-
+
if (nfrags <= 0 || nfrags > sblock->fs_frag)
return 0;
-
+
/* Examine each block of the filesystem. */
for (i = 0; i < maxfsblock - sblock->fs_frag; i += sblock->fs_frag)
{
@@ -115,7 +116,7 @@ allocblk (int nfrags)
for (k = 0; k < nfrags; k++)
if (testbmap (i + j + k))
break;
-
+
/* If one of the frags was allocated... */
if (k < nfrags)
{
@@ -123,7 +124,7 @@ allocblk (int nfrags)
j += k;
continue;
}
-
+
/* It's free (at address i + j) */
/* Mark the frags allocated in our map */
@@ -136,16 +137,16 @@ allocblk (int nfrags)
return 0;
}
-/* Check if a block starting at BLK and extending for CNT
+/* Check if a block starting at BLK and extending for CNT
fragments is out of range; if it is, then return 1; otherwise return 0. */
int
check_range (daddr_t blk, int cnt)
{
int c;
-
+
if ((unsigned)(blk + cnt) > maxfsblock)
return 1;
-
+
c = dtog (sblock, blk);
if (blk < cgdmin (sblock, c))
{
@@ -157,9 +158,9 @@ check_range (daddr_t blk, int cnt)
if (blk + cnt > cgbase (sblock, c + 1))
return 1;
}
-
+
return 0;
-}
+}
struct problem {
char *desc;
@@ -236,7 +237,7 @@ flush_problems ()
{
fail (problems)->prev = free_problems;
free_problems = problems;
- }
+ }
}
/* Like printf, but exit after printing. */
@@ -269,14 +270,14 @@ retch (char *reason)
static void
punt (char *msg)
{
- problem (0, msg);
+ problem (0, "%s", msg);
flush_problems ();
exit (8);
}
/* If SEVERE is true, and we're in preen mode, then things are too hair to
fix automatically, so tell the user to do it himself and punt. */
-static void
+static void
no_preen (int severe)
{
if (severe && preen)
@@ -295,7 +296,7 @@ problem (int severe, char *fmt, ...)
va_start (args, fmt);
push_problem (fmt, args);
va_end (args);
-
+
no_preen (severe);
}
@@ -322,6 +323,7 @@ pextend (char *fmt, ...)
strcpy (concat + strlen (concat), more);
prob->desc = concat;
+ free (more);
}
/* Like problem, but as if immediately followed by pfail. */
@@ -353,7 +355,7 @@ pinode (int severe, ino_t ino, char *fmt, ...)
}
if (ino < ROOTINO || ino > maxino)
- pextend (" (BOGUS INODE) I=%d", ino);
+ pextend (" (BOGUS INODE) I=%Ld", ino);
else
{
char *p;
@@ -362,7 +364,7 @@ pinode (int severe, ino_t ino, char *fmt, ...)
getinode (ino, &dino);
- pextend (" %s I=%d", (DI_MODE (&dino) & IFMT) == IFDIR ? "DIR" : "FILE",
+ pextend (" %s I=%Ld", (DI_MODE (&dino) & IFMT) == IFDIR ? "DIR" : "FILE",
ino);
pw = getpwuid (dino.di_uid);
@@ -370,7 +372,7 @@ pinode (int severe, ino_t ino, char *fmt, ...)
pextend (" O=%s", pw->pw_name);
else
pextend (" O=%lu", dino.di_uid);
-
+
pextend (" M=0%o", DI_MODE (&dino));
pextend (" SZ=%llu", dino.di_size);
p = ctime (&dino.di_mtime.tv_sec);
@@ -406,7 +408,7 @@ reply (char *question)
{
int persevere;
char c;
-
+
if (preen)
retch ("Got to reply() in preen mode");
@@ -448,6 +450,6 @@ reply (char *question)
{
fix_denied = 1;
return 0;
- }
+ }
}
}
diff --git a/ufs-utils/ChangeLog b/ufs-utils/ChangeLog
deleted file mode 100644
index 9883880d..00000000
--- a/ufs-utils/ChangeLog
+++ /dev/null
@@ -1,109 +0,0 @@
-Tue Jul 23 19:34:58 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * mkfs.c (fsinit): `struct timespec' now uses a field prefix of `tv_'.
- * stati.c (timespec_rep): Likewise.
-
-Fri Jun 21 02:12:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dlabel.c (fd_get_device): Supply new args to store_create.
-
-Sat May 11 01:20:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * mkfs.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
-
-Fri May 10 15:50:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * dlabel.c (fd_get_device): Update to use libstore.
- <hurd/store.h>: New include.
- * Makefile (mkfs.ufs): Depend on ../libstore/libstore.a.
-
-Tue Apr 30 10:06:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (include ../Makeconf): BEFORE dependencies.
- (all): Delete target.
- ($(targets)): Each target depends on its associated .o.
-
-Wed Apr 3 16:31:13 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * mkfs.c (main): In `Can't get disklabel' error message, specify
- which flag the user can use to supply the needed information.
- (mkfs): Fiddle with info message.
-
-Sun Mar 31 14:34:28 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * stati.c (mode_rep): Prefix octal number with `0'.
-
-Fri Mar 29 11:56:52 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * stati.c (main): Print mode & {in,}direct blocks too.
- (mode_rep): New function.
- (timespec_rep): P shouldn't be static.
-
- * mkfs.c (main): Argp interface changes.
-
-Wed Mar 13 18:30:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * mkfs.c (options, args_doc, doc): New variables for option parsing.
- (struct amark): New type.
- (amarks_add, amarks_contains): New functions.
- (default_disklabel): New variable.
- (main): Most arguments are now options (and optional). Allow many
- more parameters to be specified. Consult the disk label for some
- defaults.
- (most functions): Add explicit return type declarations. Fix
- printf format specifications. Get rid of #ifdefs for MFS.
- (started, malloc, realloc, calloc, free): Functions removed.
- (mfs, membase): Variables removed.
- <stddef.h>, <stdlib.h>, <argp.h>, <assert.h>, <error.h>,
- <string.h>: New includes
- * dlabel.c: New file.
- * Makefile (SRCS): Add dlabel.c.
- (mkfs.ufs): New target.
-
-Tue Feb 27 14:52:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * clri.c: Move here from ../utils.
-
- [Entire directory renamed to `ufs-utils' from `newfs']
-
-Sat Sep 9 12:17:11 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (target): Changed to `mkfs.ufs'.
- (installationdir): New variable, install into $(sbindir).
-
-Thu Nov 24 18:39:30 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * mkfs.c: Protect all mfs code with #ifdef MFS.
-
-Wed Oct 12 12:59:01 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * mkfs.c (main): MAXCONTIG should be zero because we don't
- do clustering.
-
-Fri Sep 9 09:45:23 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * mkfs.c: Include <sys/stat.h> and <fcntl.h>.
- (main): New function. Punt newfs.c for now.
- * Makefile (SRCS, OBJS): Comment out uses of newfs.c.
- (target): Build mkfs, not newfs.
-
- * newfs.c (mopts): Comment out.
- (mntflags): Comment out.
- (main): Omit check for `mfs'. Omit var `partition'.
- (main) [case 'o']: Comment out mfs specific code.
- (main): Comment out check for already-mounted partition.
- (main): Comment out MFS specific open of FSI.
-
- * mkfs.c (fsinit): Use DI_MODE to read mode from NODE, and
- set di_model and di_modeh instead of di_mode.
- (mkfs): Don't set fields in *PP.
-
- * newfs.c: Include ufs header files with "../ufs/foo.h" instead of
- <ufs/ufs/foo.h>. Don't include <sys/disklabel.h>, <sys/mount.h>,
- or "mntopts.h".
-
-Thu Sep 8 15:52:05 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * mkfs.c: Include ufs header files with "../ufs/foo.h" instead of
- <ufs/ufs/foo.h>. Don't include <sys/disklabel.h>.
-
diff --git a/ufs-utils/Makefile b/ufs-utils/Makefile
index b27b76c4..df22440e 100644
--- a/ufs-utils/Makefile
+++ b/ufs-utils/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 1994, 1996 Free Software Foundation
+# Copyright (C) 1994, 1996, 2008 Free Software Foundation
# Written by Michael I. Bushnell.
#
# This file is part of the GNU Hurd.
@@ -27,6 +27,7 @@ SRCS = mkfs.c clri.c stati.c dlabel.c
installationdir = $(sbindir)
OBJS = $(SRCS:.c=.o)
+HURDLIBS = store shouldbeinlibc
include ../Makeconf
diff --git a/ufs-utils/dlabel.c b/ufs-utils/dlabel.c
index e3678310..355cb3f6 100644
--- a/ufs-utils/dlabel.c
+++ b/ufs-utils/dlabel.c
@@ -1,8 +1,8 @@
/* Get the disklabel from a device node
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,99,2001 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,9 +23,15 @@
#include <mach.h>
#include <string.h>
#include <device/device.h>
-#include <mach/sa/sys/ioctl.h> /* Ick */
#include <device/disk_status.h>
#include <hurd/store.h>
+
+/* XXX Ick. */
+#define IOCPARM_MASK 0x1fff/* parameter length, at most 13 bits */
+#define IOC_OUT 0x40000000/* copy out parameters */
+#define _IOC(inout,group,num,len) \
+ (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
+#define _IOR(g,n,t) _IOC(IOC_OUT,(g), (n), sizeof(t))
static error_t
fd_get_device (int fd, device_t *device)
@@ -37,10 +43,10 @@ fd_get_device (int fd, device_t *device)
if (node == MACH_PORT_NULL)
return errno;
- err = store_create (node, 0, 0, &store);
+ err = store_create (node, 0, 0, &store); /* consumes NODE on success */
if (! err)
{
- if (store->class != STORAGE_DEVICE
+ if (store->class->id != STORAGE_DEVICE
/* In addition to requiring a device, we also want the *whole*
device -- one contiguous run starting at 0. */
|| store->num_runs != 1
@@ -57,8 +63,8 @@ fd_get_device (int fd, device_t *device)
}
store_free (store);
}
-
- mach_port_deallocate (mach_task_self (), node);
+ else
+ mach_port_deallocate (mach_task_self (), node);
return err;
}
diff --git a/ufs-utils/mkfs.c b/ufs-utils/mkfs.c
index 43093b9b..aef3ea92 100644
--- a/ufs-utils/mkfs.c
+++ b/ufs-utils/mkfs.c
@@ -33,7 +33,7 @@
#ifndef lint
/*static char sccsid[] = "from: @(#)mkfs.c 8.3 (Berkeley) 2/3/94";*/
-static char *rcsid = "$Id: mkfs.c,v 1.13 1996/07/23 23:37:21 miles Exp $";
+static char *rcsid = "$Id: mkfs.c,v 1.22 2006/03/14 23:27:50 tschwinge Exp $";
#endif /* not lint */
#include <unistd.h>
@@ -54,6 +54,7 @@ static char *rcsid = "$Id: mkfs.c,v 1.13 1996/07/23 23:37:21 miles Exp $";
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
+#include <version.h>
#include <device/device_types.h>
#include <device/disk_status.h>
@@ -62,7 +63,7 @@ static char *rcsid = "$Id: mkfs.c,v 1.13 1996/07/23 23:37:21 miles Exp $";
/* Begin misc additions for GNU Hurd */
-/* For GNU Hurd: the ufs DIRSIZ macro is different than the BSD
+/* For GNU Hurd: the ufs DIRSIZ macro is different than the BSD
4.4 version that mkfs expects. So we provide here the BSD version. */
#undef DIRSIZ
#if (BYTE_ORDER == LITTLE_ENDIAN)
@@ -89,6 +90,7 @@ static char *rcsid = "$Id: mkfs.c,v 1.13 1996/07/23 23:37:21 miles Exp $";
#ifndef STANDALONE
#include <a.out.h>
#include <stdio.h>
+#include <time.h>
#endif
/*
@@ -163,7 +165,7 @@ struct dinode zino[MAXBSIZE / sizeof(struct dinode)];
int fsi, fso;
daddr_t alloc();
-char *argp_program_version = "mkfs.ufs 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (mkfs.ufs);
#define _STRINGIFY(arg) #arg
#define STRINGIFY(arg) _STRINGIFY (arg)
@@ -173,22 +175,22 @@ static const struct argp_option options[] = {
{"just-print", 'N', 0, 0,
"Just print the file system parameters that would be used"},
{"old-format", 'O', 0, 0, "Create a 4.3BSD format filesystem"},
- {"max-contig", 'a', "BLOCKS", 0,
+ {"max-contig", 'a', "BLOCKS", 0,
"The maximum number of contiguous blocks that will be laid out before"
" forcing a rotational delay; the default is no limit"},
{"block-size", 'b', "BYTES", 0, "The block size of the file system"},
{"group-cylinders", 'c', "N", 0,
"The number of cylinders per cylinder group; the default 16"},
- {"rot-delay", 'd', "MSEC", 0,
+ {"rot-delay", 'd', "MSEC", 0,
"The expected time to service a transfer completion interrupt and"
" initiate a new transfer on the same disk; the default is 0"},
- {"max-bpg", 'e', "BLOCKS", 0,
+ {"max-bpg", 'e', "BLOCKS", 0,
"Maximum number of blocks any single file can allocate out of a cylinder"
" group before it is forced to begin allocating blocks from another"
" cylinder group; the default is about one quarter of the total blocks"
" in a cylinder group"},
{"frag-size", 'f', "BYTES", 0, "The fragment size"},
- {"inode-density", 'i', "BYTES", 0,
+ {"inode-density", 'i', "BYTES", 0,
"The density of inodes in the file system, in bytes of data space per"
" inode; the default is one inode per 4 filesystem frags"},
{"minfree", 'm', "PERCENT", 0,
@@ -210,7 +212,7 @@ static const struct argp_option options[] = {
{"tracks", 't', "N", 0, "The number of tracks/cylinder"},
{"sectors", 'u', "N", 0,
"The number of sectors per track (does not include sectors reserved for"
- " bad block replacement"},
+ " bad block replacement"},
{"spare-sectors", 'p', "N", 0,
"Spare sectors (for bad sector replacement) at the end of each track"},
{"cyl-spare-sectors", 'x', "N", 0,
@@ -219,7 +221,7 @@ static const struct argp_option options[] = {
{0, 0}
};
static char *args_doc = "DEVICE";
-static char *doc = 0;
+static char *doc = "Write a ufs filesystem image onto DEVICE.";
struct amark { void *addr; struct amark *next; };
@@ -260,7 +262,7 @@ char *device = 0;
#define deverr(code, err, fmt, args...) \
error (code, err, "%s: " fmt, device , ##args)
-void
+int
main (int argc, char **argv)
{
int fdo, fdi;
@@ -276,11 +278,9 @@ main (int argc, char **argv)
{
case 'N': Nflag = 1; break;
case 'O': Oflag = 1; break;
-
- /* Mark &VAR as being a uparam, and return a lvalue for VAR. */
-#define UP(var) (amarks_add (&uparams, &var), var)
- /* Record an integer uparam into VAR. */
-#define UP_INT(var) { int _i = atoi (arg); UP (var) = _i; }
+
+/* Mark &VAR as being a uparam, and set VAR. */
+#define UP_INT(var) { amarks_add (&uparams, &var); var = atoi (arg); }
case 'a': UP_INT (maxcontig); break;
case 'b': UP_INT (bsize); break;
@@ -301,7 +301,7 @@ main (int argc, char **argv)
case 'p': UP_INT (nspares); break;
case 'x': UP_INT (ncspares); break;
- case 'o':
+ case 'o':
amarks_add (&uparams, &opt);
if (strcmp (arg, "time") == 0)
opt = FS_OPTTIME;
@@ -412,7 +412,7 @@ main (int argc, char **argv)
nphyssectors = nsectors + nspares;
secpercyl = nsectors * ntracks;
-
+
DEFAULT (rpm, DL_INT (0, d_rpm));
DEFAULT (interleave, DL_INT (0, d_interleave));
DEFAULT (trackskew, DL_SECS (0, d_trackskew));
@@ -421,7 +421,7 @@ main (int argc, char **argv)
DEFAULT (fsize, 1024);
DEFAULT (bsize, 8192);
-
+
DEFAULT (cpg, 16);
DEFAULT (minfree, MINFREE);
DEFAULT (opt, DEFAULTOPT);
@@ -438,7 +438,7 @@ main (int argc, char **argv)
mkfs (0, device, fdi, fdo);
- exit (0);
+ return 0;
}
void
@@ -655,7 +655,7 @@ mkfs(pp, fsys, fi, fo)
}
else
exit(23);
- /*
+ /*
* Calculate the number of cylinders per group
*/
sblock.fs_cpg = cpg;
@@ -862,6 +862,7 @@ next:
sblock.fs_cstotal.cs_nffree = 0;
sblock.fs_fmod = 0;
sblock.fs_ronly = 0;
+ sblock.fs_clean = 1;
/*
* Dump out summary information about file system.
@@ -903,7 +904,7 @@ next:
sblock.fs_cssize - i < sblock.fs_bsize ?
sblock.fs_cssize - i : sblock.fs_bsize,
((char *)fscs) + i);
- /*
+ /*
* Write out the duplicate super blocks
*/
for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
@@ -961,7 +962,7 @@ initcg(cylno, utime)
acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag;
acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_link);
acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(long);
- acg.cg_iusedoff = acg.cg_boff +
+ acg.cg_iusedoff = acg.cg_boff +
sblock.fs_cpg * sblock.fs_nrpos * sizeof(short);
acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
if (sblock.fs_contigsumsize <= 0) {
@@ -1155,6 +1156,14 @@ fsinit(utime)
node.di_model = IFDIR | UMASK;
node.di_modeh = 0;
node.di_nlink = PREDEFDIR;
+
+ /* Set the uid/gid to non-root if run by a non-root user. This
+ is what mke2fs does in e2fsprogs-1.18 (actually it uses the
+ real IDs iff geteuid()!=0, but that is just wrong). */
+ node.di_uid = geteuid();
+ if (node.di_uid != 0)
+ node.di_gid = getegid();
+
if (Oflag)
node.di_size = makedir((struct directory_entry *)oroot_dir, PREDEFDIR);
else
@@ -1268,7 +1277,7 @@ iput(ip, ino)
sblock.fs_cstotal.cs_nifree--;
fscs[0].cs_nifree--;
if (ino >= sblock.fs_ipg * sblock.fs_ncg)
- deverr (32, 0, "fsinit: inode value out of range (%d)", ino);
+ deverr (32, 0, "fsinit: inode value out of range (%Ld)", ino);
d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
rdfs(d, sblock.fs_bsize, buf);
buf[ino_to_fsbo(&sblock, ino)] = *ip;
diff --git a/ufs-utils/stati.c b/ufs-utils/stati.c
index 2c0147d0..ba545bf2 100644
--- a/ufs-utils/stati.c
+++ b/ufs-utils/stati.c
@@ -61,6 +61,7 @@ static char sccsid[] __attribute__ ((unused));
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
+#include <time.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
@@ -94,7 +95,7 @@ mode_rep (unsigned short mode)
case S_IFIFO: *p++ = 'f'; break;
default: *p++ = '?';
}
-
+
add_perms (0, S_ISUID);
add_perms (3, S_ISGID);
add_perms (6, 0);
diff --git a/ufs/ChangeLog b/ufs/ChangeLog
deleted file mode 100644
index 2ccd6c11..00000000
--- a/ufs/ChangeLog
+++ /dev/null
@@ -1,1591 +0,0 @@
-Tue Jul 23 15:58:28 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (write_node, read_disknode): `struct timespec' now uses
- a field prefix of `tv_'.
-
-Sat Jul 6 16:14:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (ufs_version): Variable removed.
-
-Sat Jul 6 12:45:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * inode.c (read_disknode): Don't set allocsize based on st->size
- for kludged symlinks.
-
- * sizes.c (diskfs_truncate): Call record_poke after truncating a
- kludged symlink.
-
-Wed Jul 3 13:27:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c: Include <argz.h>.
- (startup_parents, runtime_parents): Declare const.
-
-Tue Jun 25 14:02:02 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (diskfs_get_options): Include `--compat=' in options.
-
-Mon Jun 24 16:59:12 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.c (diskfs_lookup_hard): Use diskfs_check_readonly instead of
- diskfs_readonly.
- (diskfs_dirempty): Likewise.
-
- * dir.c (diskfs_lookup_hard): Use diskfs_check_readonly instead of
- diskfs_readonly.
- (diskfs_dirempty): Likewise.
- * inode.c (diskfs_cached_lookup): Likewise.
- (read_symlink_hook): Likewise.
- * sizes.c (diskfs_truncate): Call diskfs_check_readonly.
- (diskfs_grow): Likewise.
- * hyper.c (diskfs_set_hypermetadata): If CLEAN is not set, make
- sure we clear the clean bit on disk. Always call sync_disk (with
- appropriate WAIT).
- (diskfs_readonly_changed): Don't do set_hypermetadata here.
- (copy_sblock): Don't track clean state here.
-
- * pager.c (diskfs_shutdown_pager): Don't shutdown DISKPAGER ever,
- just sync it instead.
-
-Sat Jun 22 17:45:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (diskfs_get_options): New function.
- (options): Make const.
-
-Fri Jun 21 01:32:09 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (parse_opt): Handle runtime invalid selection of 4.2 mode.
- Save select mode until we're done to correctly deal with external
- errors at runtime.
- (startup_parents, startup_argp, runtime_parents, runtime_argp):
- New variables.
- (main): Argp vars made global.
- (argp_parents): diskfs_device_startup_argp -->
- &diskfs_std_device_startup_argp.
-
-Sat Jun 15 13:57:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (options): New variable.
- (parse_opt): New function.
- (main): Parse ufs-specific options too.
- <string.h>: New include.
-
-Fri May 10 09:29:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_statfs): Fix one reference to old name of ST
- member.
-
-Thu May 9 11:54:13 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (ufs.static ufs): s/ioserver/iohelp/g
- * ufs.h: ioserver.h -> iohelp.h.
-
- * inode.c (diskfs_set_statfs): Use and fill in new statfs
- structure.
-
-Mon May 6 14:23:54 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * main.c (ufs_version): Upgrade to 0.0.
-
-Fri May 3 09:15:33 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * sizes.c (block_extended): Rewrite code that moves pages
- to be more efficient, and not deadlock too, using unlocked
- pagein permission feature (read "hack"). Return value
- now indicates whether we expect a sync.
- (diskfs_grow): If a call to block_extended returns nonzero,
- then sync the file before returning.
- * pager.c (diskfs_get_filemap): Initialize
- UPI->allow_unlocked_pagein and UPI->unlocked_pagein_length.
- (unlocked_pagein_lock): New variable.
- (find_address): New parameter `isread'; all callers changed.
- If ISREAD and we are in the unlocked pagein region, don't
- attempt to acquire NP->dn->allocptrlock.
- * ufs.h (struct user_pager_info): New members
- `allow_unlocked_pagein' and `unlocked_pagein_length'.
- (unlocked_pagein_lock): New variable.
-
-Thu May 2 10:56:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * sizes.c (offer_data): Offer pages at ADDR each time through the
- loop, not the same page over and over.
- (block_extended): When moving data, sync in-core pager both before
- reading from disk and after providing data to kernel.
- (diskfs_grow): Always call block_extended or offer_data before
- adjusting block pointer.
-
-Tue Apr 30 13:38:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * sizes.c (diskfs_grow): In last offer_data, don't offer a block
- number as an address.
-
-Fri Apr 26 15:35:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (makemode): Now `servers'.
- (targets): Renamed from `target'; now include ufs.static.
- (ufs.static-LDFLAGS): Renamed from `LDFLAGS'.
- (ufs.static): Depend on same things as `ufs'.
- (include ../Makeconf): Must come before dependency information.
-
-Wed Apr 24 14:05:48 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.h (DIRECT_NAMLEN) [! LITTLE_ENDIAN]: Deal correctly with the
- case where it was written on a little endian machine without the
- extension.
- (DIRECT_NAMLEN) [LITTLE_ENDIAN]: Deal with case correctly where it
- was written without the extension on a big endian machine.
- * dir.c (dirscanblock): Use read/write_disk_entry when reading or
- writing fields from directory entries.
- (diskfs_direnter_hard): Likewise.
- (diskfs_dirremove_hard): Likewise.
- (diskfs_dirrewrite_hard): Likewise.
- (diskfs_get_directs): Likewise.
- (diskfs_dirempty): Likewise.
- (count_dirents): Likewise.
-
-Tue Apr 23 11:28:42 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.c (diskfs_dirempty): node_update -> diskfs_node_update.
-
- * hyper.c (swab_sblock, swab_csums): New functions.
- (get_hypermetadata): If this is a swapped filesystem, set swab_disk.
- Also swap csum and sblock after reading them.
- (diskfs_set_hypermetadata): If swab_disk, swap the csums back before
- writing them.
- (copy_sblock): If swab_disk, swap the sblock before writing it.
- * ufs.h (swab_disk): New variable.
- (swab_short, swab_long, swab_long_long): New functions.
- (read_disk_entry, write_disk_entry): New macros.
- * alloc.c (ffs_realloccg): Use read/write_disk_entry when
- reading/writing on-disk inode fields.
- * bmap.c (fetch_indir_spec): Likewise.
- * inode.c (read_disknode): Likewise.
- (write_node): Likewise.
- (diskfs_set_translator): Likewise.
- (diskfs_get_translator): Likewise.
- (diskfs_S_file_get_storage_info): Likewise.
- * sizes.c (diskfs_truncate): Likewise.
- (diskfs_grow): Likewise.
- * pager.c (pager_unlock_page): Likewise.
- * bmap.c (fetch_indir_spec): Use read/write_disk_entry when
- reading/writing on-disk indirect blocks.
- * sizes.c (diskfs_truncate): Likewise.
- (indir_release): Likewise.
- (diskfs_grow): Likewise.
- * pager.c (pager_unlock_page): Likewise.
- * alloc.c: Include <string.h>
- (ffs_blkpref): Use read_disk_entry when reading from BAP array.
- (swab_cg, read_cg, release_cg): New functions.
- (ffs_fragextend, ffs_alloccg, ffs_nodealloccg, ffs_blkfree,
- diskfs_free_node): Use new cg access functions.
-
-Thu Apr 18 14:50:30 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * sizes.c (diskfs_grow): New variable `pagerpt'.
- (offer_zeroes, block_extended): New functions.
- (diskfs_grow): In initializing newly allocated data disk blocks with
- zeroes, use less aggressive offer_zeroes instead of immediate
- synchronous writes. After ffs_realloccg succeeds, use
- block_extended to handle the magic. Get rid of old poke calls.
- * alloc.c (ffs_realloccg): If we are allocating a new block, don't
- actually free the old one here.
- * sizes.c (diskfs_grow): New variable `pagerpt'.
- (offer_zeroes, block_extended): New functions.
- (diskfs_grow): In initializing newly allocated data disk blocks
- with zeroes, use less aggressive offer_zeroes instead of immediate
- synchronous writes. After ffs_realloccg succeeds, use
- block_extended to handle the magic. Get rid of old poke calls.
-
-Tue Apr 16 15:20:07 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.c (diskfs_lookup_hard): Set atime appropriately, and sync
- the new atime if we are running synchronously (!).
- (diskfs_dirempty): Likewise.
- (diskfs_direnter_hard): Set mtime appropriately.
- (diskfs_dirremove_hard): Likewise.
- (diskfs_dirrewrite_hard): Likewise.
-
- * inode.c (diskfs_write_disknode): Only do sync if WAIT is set.
-
-Thu Apr 4 16:39:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_cached_lookup): Intialize NP->cache_id *after*
- NP exists.
-
-Wed Apr 3 16:03:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * inode.c (diskfs_cached_lookup): Renamed from `iget'. All
- callers changed. Initialize NP->cache_id.
-
-Fri Mar 29 16:52:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * sizes.c (diskfs_truncate): Cast DI->di_shortlink to correct type
- before adding a character count to it.
-
-Mon Mar 25 13:08:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.c (diskfs_null_dirstat): New function.
-
-Fri Mar 22 23:43:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (read_symlink_hook): Only set NP's atime if !readonly.
-
-Wed Mar 20 14:36:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.c (diskfs_lookup_hard): Don't do initial or final permission
- checking here.
- * dir.c (diskfs_dirrewrite_hard): Renamed from diskfs_dirrewrite.
- No longer call modification tracking routines.
- (diskfs_dirremove_hard): Renamed from diskfs_dirremove. No longer call
- modification tracking routines.
- (diskfs_direnter_hard): Renamed from diskfs_direnter. No longer call
- modification tracking routines.
- (diskfs_lookup_hard): Renamed from diskfs_lookup.
-
-Mon Mar 18 19:50:41 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Pass new arg to argp_parse.
-
-Mon Mar 18 12:33:06 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pager.c (diskfs_max_user_pager_prot) [add_pager_max_prot]:
- (a == b) ? 1 : 0 ====> (a == b).
-
-Fri Feb 23 15:27:05 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * hyper.c (get_hypermetadata): Use diskfs_device_arg in unclean msgs.
-
-Wed Feb 21 05:57:12 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * hyper.c: Implement proper handling of the filesystem `clean bit'.
- (ufs_clean): New variable.
- (get_hypermetadata): Set it from the fs_clean flag. If not clean,
- complain and force read-only. Complain when ignoring COMPAT_BSD42.
- (diskfs_set_hypermetadata): Set the clean flag in the superblock
- when CLEAN and fs was clean to start with.
- (copy_sblock): Remove bogus clean flag frobnication.
-
-Fri Feb 16 17:05:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Check error return from diskfs_init_diskfs.
-
-Sat Jan 6 11:50:14 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ufs.h (diskpager, diskpagerport, disk_image): Variables removed.
- Include <hurd/diskfs-pager.h> instead.
- (sync_disk_blocks): Use `disk_pager' in place of `diskpager->p'.
- * pager.c (diskfs_shutdown_pager, diskfs_sync_everything): Use
- `disk_pager' in place of `diskpager->p'.
- (create_disk_pager): Rewritten using disk_pager_setup.
- * pokeloc.c (sync_disk): Use `disk_pager' in place of `diskpager->p'.
- * sizes.c (indir_release): Likewise.
- * main.c (diskfs_reload_global_state): Likewise.
-
-Thu Jan 4 19:10:11 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * main.c (main): Don't map disk image here; create_disk_pager now
- does it.
-
- * hyper.c (get_hypermetadata, copy_sblock): Don't put
- diskfs_catch_exception () inside assert, bonehead! Use
- assert_perror on a variable of its result.
-
-Mon Jan 1 16:38:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * pager.c (pager_unlock_page): When allocating block in direct
- array, clear it synchronously just like we do when it goes in the
- indirect array.
-
-Thu Nov 9 14:01:30 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * dir.c (struct dirstat): New member `nbytes'.
- (dirscanblock): If DS->type is COMPRESS, still look
- for TAKE/SHRINK possibilities. Also, if it's COMPRESS,
- still look to see if the current block can be compressed
- with fewer byte copies.
-
-Sun Nov 5 02:08:38 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Add flags arg to diskfs_startup_diskfs call.
-
-Sat Nov 4 20:01:58 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_S_file_get_storage_info): Add FLAGS argument.
-
-Thu Oct 19 12:50:11 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pager.c (diskfs_max_user_pager_prot): Return what we discovered,
- instead of 1.
-
- * dir.c (diskfs_lookup, diskfs_dirempty): Give diskfs_get_filemap
- a protection arg.
- * sizes.c (diskfs_truncate, diskfs_grow): Ditto.
-
- * hyper.c (diskfs_readonly_changed): Give the 2nd arg to
- vm_protect an appropiate type.
-
- * pager.c (diskfs_max_user_pager_prot): Stop iterating early if poss.
-
-Wed Oct 18 16:28:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ufs.h (struct user_pager_info): Add max_prot field.
- * pager.c (diskfs_get_filemap): Add PROT parameter, & use it.
- (diskfs_pager_users): Split out block_caching & enable_caching.
- (block_caching, enable_caching): New function.
- (diskfs_max_user_pager_prot): New function.
-
- * main.c (main): Always include VM_PROT_WRITE in max prot.
- * hyper.c (diskfs_readonly_changed): Change the protection of
- DISK_IMAGE to reflect the new state. Clear SBLOCK_DIRTY if readonly.
-
- * inode.c (read_disknode): Bother to set the allocsize field.
-
- * ufs.h (struct rwlock): Structure deleted.
- (rwlock_init, rwlock_reader_unlock, rwlock_reader_lock,
- rwlock_writer_lock, rwlock_writer_unlock): Functions deleted.
-
-
-Tue Oct 17 14:49:43 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_node_reload): New function.
- (iget): Move allocsize setting into read_disknode.
- * pager.c (flush_node_pager): New function.
- * ufs.h (zeroblock, sblock, csum): Declare extern.
- (flush_node_pager, flush_pokes): New declarations.
- * pokeloc.c (flush_pokes): New function.
- * hyper.c (diskfs_readonly_changed): New function.
- (get_hypermetadata): Move compat_mode futzing & disk size
- validation here from main.
- (zeroblock, sblock, csum): Define (were common).
- (get_hypermetadata): Only allocate SBLOCK if not already done.
- Deallocate any old ZEROBLOCK and CSUM storage.
- (diskfs_readonly_changed): New function.
- * main.c (main): Move stuff into get_hypermetadata.
- Writable init code moved to diskfs_readonly_changed.
- (diskfs_reload_global_state): New function.
-
-Fri Oct 13 15:03:37 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (main): Use new handy diskfs routines and get rid of
- tons of junk. Main should be almost all ufs-specific now.
- (USAGE, usage, SHORT_OPTS, long_opts, parse_opt, trans_parse_arg): RIP.
- (printf_lock): Initialize.
-
-Thu Oct 12 18:48:04 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * pager.c (pager_unlock_page, pager_write_page, pager_read_page):
- Use diskfs_device_{read,write}_sync instead of dev_{read,write}_sync.
- * hyper.c (diskfs_set_hypermetadata): Ditto.
- * sizes.c (diskfs_grow): Ditto.
- * pager.c (pager_report_extent): Calculate the pager size.
- * ufs.h (dev_read_sync, dev_write_sync, dev_write, diskpagersize):
- Decls removed.
-
- * Makefile (SRCS): Remove devio.c.
- * ufs.h (ufs_device, ufs_device_name): Variables removed.
- * inode.c (diskfs_S_file_get_storage_info): Use DISKFS_DEVICE
- instead of UFS_DEVICE, and DISKFS_DEVICE_NAME instead of
- UFS_DEVICE_NAME.
-
-Sat Oct 7 20:47:56 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * main.c (diskfs_init_completed): Function deleted (now in libdiskfs).
- (thread_cancel): Function deleted.
-
-Fri Oct 6 17:30:23 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_S_file_get_storage_info): Change type of
- ADDRESSES to off_t **, and add the BLOCK_SIZE parameter.
-
-Wed Oct 4 17:21:33 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_statfs): fsys_stb_bsize -> fsys_stb_iosize.
- fsys_stb_fsize -> fsys_stb_bsize.
-
- * main.c (parse_opt): Rearrange slightly.
-
-Tue Sep 26 11:54:35 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * inode.c: Include <netinet/in.h>.
- (diskfs_S_file_get_storage_info): New function.
- * main.c (main): Delete var `devname'. Use `ufs_device_name'
- throughout instead.
- * ufs.h (ufs_device_name): New var.
-
-Fri Sep 22 13:22:42 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * hyper.c (get_hypermetadata): Use %Zd format for result of sizeof.
-
-Tue Sep 19 13:41:46 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (LDFLAGS): New variable.
-
-Wed Sep 13 12:30:23 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * dir.c (diskfs_lookup): Don't attempt to lock NP if NPP is not
- set. Don't even set NP if NPP is not set; use INUM as "lookup
- succeeded flag" instead. Lookups for REMOVE and RENAME now *must*
- set NPP.
-
-Wed Sep 6 11:01:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * pager.c (diskfs_pager_users): Ignore the disk pager when seeing
- if there are any active pagers.
-
-Mon Aug 28 17:07:36 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (ufs): Depend on ../libshouldbeinlibc/libshouldbeinlibc.a.
-
-Fri Aug 25 17:14:09 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu>
-
- * sizes.c (diskfs_truncate): When freeing direct blocks mentioned
- in a single indirect block, or single indirect blocks mentioned in
- a double, only call the free routine (ffs_blkfree or
- indir_release, respectively) if the block is actually allocated.
-
-Wed Aug 23 12:24:07 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (ufs): Add explicit dependencies.
- (HURDLIBS, LDFLAGS, REMHDRS): Removed.
- Rules associated with ../lib removed.
-
-Fri Jul 21 17:48:12 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * pager.c (diskfs_get_filemap): Drop initial reference created by
- pager_create.
-
- * pager.c (diskfs_get_filemap): Avoid race with simultaneous
- termination by looping until we win.
- (pager_clear_user_data): Only clear UPI->np->dn->fileinfo if it
- still points to us.
-
-Mon Jul 17 14:35:25 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * pager.c (thread_function): Don't have any global timeout here;
- we don't use it anyhow.
-
-Thu Jul 6 15:42:52 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Mon Jun 26 20:17:42 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * pager.c: Include <unistd.h>.
- (diskfs_pager_users): New function.
-
-Thu Jun 22 11:41:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * pager.c (thread_function): Move thread_function to be non-local,
- of course, because it needs to live even after create_disk_pager
- returns.
-
- * main.c (thread_cancel): New function (HACK).
-
- * Makefile (HURDLIBS): Add libihash.
-
- * main.c (main): Have main thread exit when done instead of
- calling a diskfs function.
-
-Wed Jun 21 12:20:01 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * ufs.h (user_pager_info): Removed members next and prevp.
- * pager.c (pager_clear_user_data): Don't maintain pager linked
- list.
- (diskfs_get_filemap): Don't maintain pager linked list.
- (pager_dropweak): New function.
- (pager_traverse): Delete function.
- (diskfs_shutdown_pager): Use ports_bucket_iterate instead of
- pager_traverse.
- (diskfs_sync_everything): Likewise.
-
- * pager.c (pager_bucket): New variable.
- (create_disk_pager): Provide pager_bucket in call to pager_create.
- (diskfs_get_filemap): Likewise.
- (diskfs_file_update): Use ports reference calls directly instead
- of pager wrappers.
- (drop_pager_softrefs): Likewise.
- (allow_pager_softrefs): Likewise.
- (pager_traverse): Likewise.
- (create_disk_pager): Initialize pager_bucket here and fork off
- service thread for pager ports.
-
- * sizes.c (diskfs_truncate): Likewise.
-
- * dir.c (diskfs_lookup): Provide initialization for BUFLEN.
- (diskfs_direnter): Move assignment out of if test.
-
-Tue Jun 20 11:48:06 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * sizes.c (diskfs_grow): Provide initialization of POKE_OFF.
- * alloc.c (ffs_realloccg): Remove assignment from if tests.
- * sizes.c (diskfs_truncate): Likewise.
- * bmap.c (fetch_indir_spec): Likewise.
-
-Mon Jun 19 21:17:21 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * inode.c (diskfs_node_iterate): New function.
- (write_all_disknodes): Use it.
-
-Wed Jun 14 16:18:55 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * inode.c (diskfs_get_translator): Conform to new memory usage
- semantic.
-
-Sat May 20 00:17:30 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * main.c (trans_parse_args): Use options_parse &
- diskfs_standard_startup_options to parse our translator options.
- (usage): New function.
- (parse_opt): New function.
-
- * Makefile (CPPFLAGS): Add -I../lib, to get include lib include files,
- and $(CPPFLAGS-$(notdir $<)) to get file-specific cpp options.
- Add a vpath for %.c to ../lib, so we can use source files from there.
-
-Mon May 15 13:14:48 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * pager.c (pager_clear_user_data): Doc fix.
-
-Sat May 13 05:04:11 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Remove exec_server_image.o.
- (exec_server_image.o): Rule removed.
-
-Mon May 8 08:43:43 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * dir.c (diskfs_lookup): When looping back to try_again: because
- we're looking up "..", be sure and trash the mapping we made of
- the directory's pager -- otherwise the reference to the pager
- never gets dropped and we can never free the node.
-
- * dir.c (diskfs_lookup): ds->type was being compared to LOOKING, which
- value it can never have. Compare ds->stat against LOOKING instead.
-
- * pager.c (pager_clear_user_data): Don't die when called on the
- disk pager.
-
- * inode.c (write_all_disknodes): Fix typo `alloc' --> `alloca'.
-
-Tue May 2 11:59:09 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * pager.c (pager_clear_user_data): Acquire pagerlistlock around
- modifications to UPI->next/prevp list structure.
-
-Fri Apr 28 19:02:05 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (write_all_disknodes): We have to really lock the nodes
- around the calls to diskfs_set_node_times and write_node; this in
- turn forces us to have real refereces.
-
-Thu Apr 13 16:36:57 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * main.c (main): Don't abort if a std file descriptor is already open.
-
-Tue Apr 4 20:08:25 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_translator): When freeing passive
- translator, account for blocks freed in NP->dn_stat.st_blocks.
-
-Fri Mar 31 13:43:27 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * sizes.c (diskfs_truncate): Don't acquire writer lock on
- NP->dn->allocptrlock until after forcing delayed copies through;
- otherwise the pageins will deadlock attempting to get a reader
- lock to service them. This is safe, because we only need
- NP->allocsize here, and that can't change as long as we hold
- NP->lock.
-
-Mon Mar 20 13:58:44 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * consts.c (diskfs_synchronous): New variable.
-
-Fri Mar 17 14:31:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * alloc.c (ffs_clusteracct): Make static.
- (alloc_sync): New function.
- (ffs_alloc): Call alloc_sync.
- (ffs_realloccg): Likewise.
- (diskfs_alloc_node): Likewise.
- (ffs_blkfree): Likewise.
- (diskfs_free_node): Likewise.
-
-Sat Jan 28 14:59:26 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * Makefile (OBJS): Remove reference to libc's devstream.o.
-
-Fri Nov 11 11:45:38 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * hyper.c (diskfs_set_hypermetadata): Always use dev_write_sync to
- avoid device_write bug that says you can't modify the buffer until
- device_write returns. Also remember to deallocate BUF.
-
-Thu Nov 10 13:27:09 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * main.c (main): Issue decent prompt.
-
- * hyper.c (diskfs_set_hypermetadata): Copy CSUM into a
- page-aligned page-sized buffer for disk write to avoid inane
- kernel bug.
-
-Wed Nov 9 05:43:14 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * main.c (main): Behave more reasonably if we can't open DEVNAME.
-
-Tue Nov 8 00:03:20 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * pager.c (pager_write_page): Use %p for printing PAGER.
-
- * ufs.h: Declare copy_sblock.
-
-Wed Nov 2 16:06:10 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * hyper.c (copy_sblock): Don't copy csum here.
- (diskfs_set_hypermetadata): Write csum directly to disk here.
-
-Thu Oct 27 20:58:08 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * dir.c (diskfs_lookup): diskfs_get_filemap returns a send right,
- so don't create an additional one here.
- (diskfs_dirempty): Likewise.
- * sizes.c (diskfs_truncate): Likewise.
- (diskfs_grow): Likewise.
-
-Tue Oct 25 12:49:41 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * hyper.c (copy_sblock): Call record_poke for csum and superblock
- after modifying them.
-
- * pager.c (diskfs_shutdown_pager): Call copy_sblock.
- (diskfs_sync_everything): Likewise.
-
- * alloc.c (ffs_fragextend): Call record_poke for CG after
- modifying it. Also set CSUM_DIRTY and SBLOCK_DIRTY.
- (ffs_alloccg): Likewise.
- (ffs_alloccgblk): Likewise.
- (ffs_nodealloccg): Likewise.
- (ffs_blkfree): Likewise.
- (diskfs_free_node): Likewise.
-
-Fri Oct 7 01:32:56 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * main.c (diskfs_init_completed): Don't call _hurd_proc_init.
- (saved_argv): Variable removed.
- (main): Don't set saved_argv. Pass ARGV to diskfs_start_bootstrap.
-
-Wed Oct 5 22:18:46 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * inode.c (read_disknode): If we are the bootstrap filesystem,
- then getpid changes once proc starts up. So only call getpid
- once, thus not allowing st_dev values to mysteriously change.
-
-Wed Oct 5 12:56:53 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * alloc.c (diskfs_alloc_node): Abort if free inode has
- translator attached.
-
-Tue Oct 4 18:33:35 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * pager.c (pager_unlock_page): Call diskfs_catch_exception.
-
-Tue Oct 4 00:16:04 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (diskfs_lost_hardrefs): Comment out body.
- * ufs.h (node2pagelock): New variable.
- * pager.c (node2pagelock): Initialize.
- (diskfs_get_filemap): Don't let node hold a reference to the pager.
- (pager_clear_user_data): Acquire node2pagelock and clear
- the node's reference to the pager.
- (diskfs_file_update): Hold node2pagelock for reference
- of NP->dn->fileinfo.
- (drop_pager_softrefs): Likewise.
- (allow_pager_softrefs): Likewise.
- (diskfs_get_filemap): Likewise.
- * sizes.c (diskfs_truncate): Likewise.
-
- * Makefile (SRCS): Added pokeloc.c.
-
-Mon Oct 3 15:03:38 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * sizes.c (diskfs_truncate): Rewritten.
-
- * bmap.c (fetch_indir_spec): Initialize OFFSET values to -2,
- meaning that the entry is not needed. If LBN is negative,
- then don't set values for the data block.
-
- * inode.c (write_node): Call record_poke after writing
- dinode.
- (create_symlink_hook): Likewise.
- (diskfs_set_translator): Likewise.
- * pager.c (pager_unlock_page): Likewise.
- * sizes.c (diskfs_truncate): Likewise.
- * pager.c (pager_unlock_page): Call record_poke after writing
- indirect block.
- * sizes.c (diskfs_grow): Likewise.
- (diskfs_grow): Likewise.
- * pager.c (diskfs_sync_everything) [sync_one]: If this is the
- disk pager, call sync_disk instead.
- * pokeloc.c: New file.
-
-Fri Sep 30 11:25:36 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * dir.h: Delete DT_* definitions; they are now in <dirent.h>.
- * dir.c (diskfs_get_directs): Set USERP->d_type as DT_UNKNOWN.
- When the bugs in the type fields are fixed (dealing with
- multiple links and mode changes) then this can actually return
- the value.
-
-Thu Sep 29 17:16:58 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * main.c (main): Test getpid()>0 to decide we are a normal
- translator instead of the boot fs. Fetch bootstrap port after
- possibly calling diskfs_parse_bootargs, not before.
-
-Tue Sep 27 15:24:58 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * sizes.c (diskfs_grow) [computation of newallocsize]: Last block
- number is one less than the total number of blocks.
-
-Tue Sep 27 11:58:44 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * bmap.c (fetch_indir_spec): Single indirect block pointer is
- in the INDIR_SINGLE slot, not the INDIR_DOUBLE slot.
-
-Mon Sep 26 20:47:30 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (SRCS): Added bmap.c.
-
- * main.c (main): Don't call pager_init.
-
- * inode.c (diskfs_get_translator): Repair to read translator
- correctly.
-
- * sizes.c (diskfs_grow): Compute block numbers in a more clean
- (and confidently correct) fashion.
- (diskfs_truncate): Set NP->allocsize from a properly rounded
- value.
-
-Mon Sep 26 12:50:38 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * inode.c (diskfs_lost_hardrefs): "Know" that a pager starts
- with a portinfo; we don't actually have access to the pager
- struct here.
-
-Fri Sep 23 14:21:55 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- [ Continuing yesterday's changes. ]
- * ufs.h (struct dirty_indir): New type.
- (struct disknode): New member `dirty'.
- * inode.c (iget): Initialize DN->dirty.
- * bmap.c (mark_indir_dirty): New function.
- * pager.c (pager_unlock_page): Call mark_indir_dirty before
- writing into indirect blocks.
- (diskfs_file_update): Sync indirect blocks here.
- (pager_traverse): Simplify; do FILE_DATA and diskpager.
- (pager_init): Removed function.
- (create_disk_pager): New function.
- * sizes.c: Completely rewritten.
- * main.c (main): Spawn first thread sooner so we can
- map and look at the disk image.
- * hyper.c (get_hypermetadata): Moved firewall asserts
- here from pager_init.
-
-Thu Sep 22 11:28:46 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- [This long series of changes deletes the DINODE, CG, SINDIR,
- and DINDIR pagers and adds a new pager type DISK.]
- * ufs.h (struct disknode) Removed DINLOCK, SINLOCK, and
- SININFO members. New member ALLOCPTRLOCK renamed from DATALOCK.
- Removed SINLOC, DINLOC, SINLOCLEN, and DINLOCLEN.
- (struct user_pager_info) [enum pager_type]: Removed types
- DINODE, CG, SINDIR and DINDIR; added type DISK.
- (dinpager, dinodepager, cgpager): Deleted vars.
- (diskpager): New var.
- (dinmaplock, sinmaplock, pagernplock): Deleted vars.
- (sblock_dirty, csum_dirty, cgs, dinodes): Deleted vars.
- (fsaddr): New macro.
- (dino, indir_block, cg_locate): New inline functions.
- (sync_disk_blocks, sync_dinode): New inline functions.
- (struct iblock_spec): New type.
- * pager.c (dinport, dinodeport, cgport, sinlist): Deleted vars.
- (filepagerlist): Renamed from filelist.
- (pagernplock): Deleted variable.
- (find_address): Removed switch; support only DISK and FILE_DATA.
- (pager_report_extent): Likewise.
- (pager_unlock_page): Removed switch. Return without comment for
- DISK; allocate indirect blocks as necessary right here for
- FILE_DATA.
- (sin_map, sin_remap, sin_unmap, din_map, din_unmap): Deleted
- functions.
- (indir_alloc, sync_dinode): Deleted functions.
- (enqueue_pager, dequeue_pager): Deleted functions.
- (diskfs_file_update): No longer lock pagernplock; nothing
- to do with sininfo.
- (drop_pager_softrefs): Likewise.
- (allow_pager_softrefs): Likewise.
- (diskfs_get_filemap): Put pager on filepagerlist right here
- instead of through pager_enqueue.
- (pager_clear_user_data): Likewise, mutatis mutandis.
- * main.c (main): Call create_disk_pager and then map the
- entire disk into disk_image.
- * hyper.c (get_hypermetadata): Use bcopy instead of dev_read_sync.
- (diskfs_set_hypermetadata): NOP out function.
- (copy_sblock): New function, substance of code is from old
- diskfs_set_hypermetadata.
- * inode.c (iget): Don't initialize deleted disknode fields.
- (diskfs_node_norefs): Don't verify that deleted disknode
- fields are not set.
- (read_disknode): Get dinode from DINO, not DINODES array.
- (write_node): Likewise.
- (create_symlink_hook): Likewise.
- (read_symlink_hook): Likewise.
- (diskfs_set_translator): Likewise.
- (diskfs_get_translator): Likewise.
- (diskfs_node_translated): Likewise.
- * alloc.c (ffs_realloccg): Likewise.
- (ffs_fragextend): Use cg_locate instead of cgs array.
- (ffs_alloccg): Likewise.
- (ffs_nodealloccg): Likewise.
- (ffs_blkfree): Likewise.
- (diskfs_free_node): Likewise.
- * inode.c (diskfs_set_translator): Use bcopy and sync_disk_blocks
- instead of dev_write_sync.
- (diskfs_get_translator): Likewise, mutatis mutandis.
- (read_disknode): Initialize NP->istranslated.
- (diskfs_set_translator): Set/clear NP->istranslated as appropriate.
- (diskfs_node_translated): Removed function.
- * bmap.c: New file.
-
- [This improves the RWLOCK mechanism and makes it more
- orthogonal. It should probably be moved into a library.]
- * ufs.h (struct rwlock): Added MASTER and WAKEUP members.
- (struct disknode): Removed RWLOCK_MASTER and RWLOCK_WAKEUP
- fields.
- (rwlock_reader_lock): Ommitted arg DN; use new MASTER and WAKEUP
- members inside LOCK instead.
- (rwlock_writer_lock): Likewise.
- (rwlock_reader_unlock): Likewise.
- (rwlock_init): Initialize new MASTER and WAKEUP fields.
- * inode.c (iget): Don't deal with RWLOCK_MASTER and RWLOCK_WAKEUP.
- * pager.c (find_address): Deleted arg DNP. Only pass one
- arg to rwlock functions.
- (pager_read_page): Deleted var DN; only pass one arg to rwlock
- functions.
- (pager_write_page): Likewise.
-
-Wed Sep 21 00:26:25 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * pager.c (allow_pager_softrefs): Unlock PAGERNPLOCK when
- we're done with it.
- (sin_map): Hold PAGERNPLOCK all the way until we're done
- with the sininfo pointer.
- (pagernplock): No longer static.
- * ufs.h (pagernplock): Declare here.
-
- * sizes.c (diskfs_grow): Don't call diskfs_file_update here.
- This was done to prevent too much dirty data from accumulating
- and then overwhelming the pager later. But that's really the
- pager's responsibility.
-
- * ufs.h (struct disknode): New members `dinloclen' and `sinloclen'.
- * inode.c (iget): Initialize DN->dinloclen and DN->sinloclen.
- (diskfs_node_norefs): Verify that DN->dinloclen and DN->sinloclen
- are both zero.
- * pager.c (find_address) [SINDIR]: Verify that reference is
- within bounds of NP->dn->dinloc.
- (pager_unlock_page) [SINDIR]: Likewise.
- (din_map): Set NP->dn->dinloclen.
- (din_unmap): Clear NP->dn->dinloclen.
- (find_address) [FILE_DATA]: Verify that reference is within
- bounds of NP->dn->sinloc.
- (pager_unlock_page) [FILE_DATE]: Likewise.
- (sin_map): Set NP->dn->sinloclen.
- (sin_remap): Reset NP->dn->sinloclen.
- (sin_unmap): Clean NP->dn->sinloclen.
-
- * pager.c (pager_write_page): Flush stdout after printf.
- (pager_unlock_page) [FILE_DATA]: Likewise.
-
- * sizes.c (diskfs_truncate): In all references to sinloc and
- dinloc arrays, verify that references are within allocated bounds.
- (diskfs_grow): Likewise.
- (sindir_drop): Likewise.
-
- * pager.c: Create new mapping with extent NEWSIZE, not SIZE (which
- was the old size of the mapping).
-
-Tue Sep 20 15:51:35 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * pager.c (pager_report_extent) [SINDIR]: Remove erroneous extra
- division by block size.
- (sin_remap): Likewise.
-
-Mon Sep 19 17:34:11 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * inode.c (create_symlink_hook): Write assert test correctly.
-
- * dir.c (diskfs_direnter) [EXTEND]: Reference file size only
- *once*; don't rely on the behavior if diskfs_grow vis a vis
- file size.
-
-Fri Sep 16 10:29:42 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * dir.c (dirscanblock): Compute offset correctly for mangled
- entry notice.
-
- * dir.c (diskfs_direnter) [EXTEND]: Reference file size only
- once before calling diskfs_grow in case diskfs_grow actually
- increases the size.
-
- * inode.c (diskfs_set_statfs): Set fsid from getpid.
- (read_disknode): Likewise.
-
- * dir.h (struct directory_entry): Renamed from struct direct.
- * dir.c: All uses of struct direct changed to use
- struct directory_entry.
- (diskfs_get_directs): New var `userp'. Copy from *ENTRYP into
- it (set at DATAP) more cleanly.
-
-Mon Sep 12 11:30:48 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * hyper.c (diskfs_set_hypermetadata): Don't frob clean and dirty
- bits if we are readonly.
-
-Sat Sep 10 11:41:06 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * main.c (main): When started up as a passive translator,
- open fds 0, 1, and 2 on /dev/console for debugging messages.
- Call diskfs_init_diskfs with no args; after warp_root, call
- diskfs_startup_diskfs on BOOTSTRAP. Compare BOOTSTRAP to
- MACH_PORT_NULL instead of zero.
-
-Fri Sep 9 13:02:33 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * main.c (trans_parse_args): Fix and enable.
-
-Tue Sep 6 11:29:55 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * inode.c (iget): Remove old assert test that checked for bad
- inode block allocations.
-
-Thu Sep 1 11:39:12 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * tables.c: Don't include "ufs.h"; include <sys/types.h>. Then
- this file can be used unmodified by fsck.
-
-Tue Aug 30 13:36:37 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_translator): ffs_blkfree doesn't have
- a return value.
-
-Mon Aug 29 12:49:17 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (diskfs_set_translator): If NAMELEN is zero, then
- make the node have no translator.
-
-Fri Aug 26 12:28:20 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * inode.c (read_disknode): 4.4 fsck sometimes sets the author
- field to -1 to mean "ignore old uid location"; take that to mean
- "author == uid".
- (diskfs_set_translator): If we are allocating a new block for
- the translator, then account for it in st_blocks.
-
-Thu Aug 18 12:41:12 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Use short version.
-
- * alloc.c (diskfs_alloc_node): Bother to set *NPP before
- returning.
-
-Tue Aug 16 10:48:04 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (LDFLAGS): New variable.
-
-Fri Aug 5 15:51:09 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * dir.c (diskfs_direnter) [EXTEND]: Crash if the entry won't
- fit in the new block.
- (diskfs_lookup): Return ENAMETOOLONG if the name is bigger than
- MAXNAMLEN.
-
- * dir.c (diskfs_get_directs): Set USERD->d_reclen correctly.
-
-Fri Jul 22 15:12:35 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten in accord with new scheme.
-
-Wed Jul 20 13:28:38 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * main.c (main): Don't set diskfs_dotdot_file.
-
-Tue Jul 19 21:51:54 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * ufs.h: Removed defns of u_quad_t, quad_t; now in <sys/types.h>.
- Removed defn of struct timespec; now in <sys/time.h>.
-
-Tue Jul 19 12:47:31 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * main.c (main): Deleted var `diskfs_dotdot_file'.
- (trans_parse_args): Don't set diskfs_dotdot_file; don't expect
- dotdot from fsys_getroot.
-
- * Makefile (LDFLAGS): Moved to rule for `ufs' and commented out.
- (ufs): Don't use variable $(link) anymore.
-
-Mon Jul 18 14:55:17 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir.c (diskfs_get_directs): Return data to user in old format.
- Add new code for new format, maintaining compatibility correctly,
- but comment it out until the library is ready.
-
- * hyper.c (diskfs_set_hypermetadata): If we presumed to
- set new values of fs_maxfilesize, fs_qbmask, and fs_qfmask,
- then restore the originals before writing out the superblock.
-
- * pager.c (diskfs_get_filemap): Test should be S_ISLNK, not
- S_ISSOCK.
-
- * hyper.c (get_hypermetadata): Set new constants in filesystems
- which don't have them yet.
- (get_hypermetadata): Cast MAXSYMLINKLEN to long to avoid
- converting sblock->fs_maxsymlinklen into an unsigned.
-
- * subr.c (scanc, skipc): New functions.
- (ffs_setblock): Use assert instead of panic.
-
- * inode.c (read_disknode): Set old stat structure until the header
- file gets changed.
-
-Fri Jul 15 12:07:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * sizes.c: Include <string.h> for bzero.
- * fs.h (blksize): Comment out dblksize macro. In blksize
- macro, use NP->allocsize instead of IP->i_size.
-
- * dinode.h (INDIR_SINGLE, INDIR_DOUBLE, INDIR_TRIPLE): New macros.
-
- * inode.c (read_disknode, write_node): Use new stat and dinode
- fields for times.
-
- * ufs.h: Change `nextgennumber' to be `u_long' instead of int.
- Change prototypes of some alloc.c functions.
- * alloc.c (ffs_alloc): Declare to return error_t.
- (ffs_realloccg): Likewise.
- (ffs_hashalloc, ffs_alloccg, ffs_fragextend, ffs_alloccg,
- ffs_dirpref, ffs_nodealloccg, ffs_allccgblk, ffs_mapsearch,
- ffs_clusteracct): Provide forward declarations.
- (ffs_realloccg): Use printf instead of log.
- Make BPREF volatile for setjmp safety.
- (diskfs_alloc_node): Use diskfs global variable instead of TIME.
- (ffs_nodealloccg): Likewise.
- (ffs_blkfree): Likewise.
- (diskfs_free_node): Likewise.
- (ffs_blkfree, ffs_clusteracct): Declare as void.
- (ffs_alloccg, ffs_nodealloccg): Declare as u_long.
-
- * ufs.h: Change prototypes of some subr.c functions.
- * subr.c (ffs_isblock): Use assert instead of panic.
- (ffs_clrblock): Likewise.
-
- * hyper.c: Include "dinode.h".
-
- * dinode.h (LINK_MAX): New macro, from BSD sys/sys/syslimits.h.
- * fs.h (MAXBSIZE, MAXFRAG): New macros, from BSD sys/sys/param.h.
-
- * hyper.c (get_hypermetadata): Provide first arg in call to
- fsbtodb.
- (diskfs_set_hypermetadata): Likewise.
- * inode.c (diskfs_set_translator): Likewise.
- (diskfs_get_translator): Likewise.
- * pager.c (find_address): Likewise.
- (indir_alloc): Likewise.
- * inode.c (iget): Provide first arg in call to lblkno.
- * sizes.c (diskfs_truncate): Likewise.
- * pager.c (find_address): Likewise.
- * sizes.c (diskfs_grow): Likewise.
- * inode.c (iget): Provide first arg in call to fragroundup.
- * sizes.c (diskfs_trucate): Likewise.
- * sizes.c (diskfs_grow): Likewise.
- * inode.c (iget): Provide first arg in call to blkroundup.
- * pager.c (pager_unlock_page): Likewise.
- * sizes.c (diskfs_truncate): Likewise.
- * sizes.c (diskfs_grow): Likewise.
- * pager.c (find_address): Provide first arg in call to cgtod.
- * pager.c (find_address): Provide first arg in call to cgimin.
- * pager.c (find_address): Provide first arg in call to blktofrags.
- * pager.c (find_address): Provide first arg in call to blkoff.
- * sizes.c (diskfs_truncate): Likewise.
- * sizes.c (diskfs_grow): Likewise.
- * sizes.c (diskfs_truncate): Provide first arg in call to blksize.
- * sizes.c (diskfs_grow): Likewise.
- * sizes.c (diskfs_truncate): Provide first arg in call to numfrags.
-
- * ufs.h: Added temporary declarations of `u_quad_t', `quad_t', and
- `struct timespec'.
-
- * pager.c (diskfs_get_filemap): Make sure that this is
- a kind of node that can be validly read.
-
- * inode.c (create_symlink_hook): Renamed from symlink_hook.
- (read_symlink_hook): New function.
- (diskfs_read_symlink_hook): Initialize.
-
-Thu Jul 14 12:23:45 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * alloc.c: New from 4.4 BSD; BSD version `8.8 2/21/94'.
- Remove old includes; include "ufs.h", "fs.h", "dinode.h",
- and <stdio.h>. Replace panics with asserts and comment out
- uprintfs. Use prototypes throughout. Replace calls
- to ffs_fserr with printf.
- (alloclock): New variable.
- (ffs_alloc): Variable struct inode *IP is now struct node *NP;
- refer to it appropriately. Initialize FS to sblock.
- Lock alloclock around actual allocation steps. Reverse order
- of BNP and CRED arguments; declare CRED as a protid and use
- accordingly. Permit CRED to be null.
- (ffs_realloccg): Variable struct inode *IP is now struct node *NP;
- refer to it accordingly. Comment out U*x buffer management code.
- Lock alloclock around actual allocation steps. Initialize FS
- from sblock. Declare CRED as a protid and use it accordingly.
- Change BUF arg to PBN (physical block number); return new block
- there.
- (ffs_reallocblks): Comment out.
- (diskfs_alloc_node): Renamed from ialloc. Initialize FS from
- sblock. Use calling sequence from <hurd/diskfs.h>. Acquire
- alloclock aroud actual allocation steps. Deleted vars
- `pip', `pvp' (use dir instead). Use iget instead of VFS_VGET.
- Var struct inode *IP now struct node *NP. Lock gennumberlock
- around frobbing of nextgennumber.
- (ffs_blkpref): Arg struct inode *ip is now struct node *np;
- refer to it accordingly. Initialize FS to sblock. Lock
- alloclock during actual work. Use csum instead of fs_cs macro.
- (ffs_hashalloc): Arg struct inode *IP is now struct node *NP;
- use it accordingly. Initialize FS from sblock.
- (ffs_fragextend): Arg struct inode *IP is now struct node *NP;
- use it accordingly. Initialize FS from sblock. Initialize
- CGP from cgs array; don't use bread. Comment out calls to brelse
- and bdwrite. Set CGP->time from diskfs global var. Use csum
- instead of fs_cs macro.
- (ffs_alloccg): Arg struct inode *IP is now struct node *NP.
- Initialize FS from sblock. Initialize CGP from cgs array;
- don't use bread. Comment out calls to brelse and bdwrite.
- Set CGP->time from diskfs global var. Use csum instead of
- fs_cs macro.
- (ffs_nodealloccg): Arg struct inode *IP is now struct node *NP.
- Initialize FS from sblock. Initialize CGP from cgs array;
- don't use bread. Comment out calls to brelse and bdwrite. Use
- csum instead of fs_cs macro.
- (ffs_blkfree): Arg struct inode *IP is now struct node *NP.
- Initialize FS from sblock. Initialize CGP from cgs array;
- don't use bread. Comment out calls to brelse and bdwrite. Use
- csum instead of fs_cs macro.
- (diskfs_free_node): Renamed from ffs_vfree. Use calling
- sequence from <hurd/diskfs.h>. Initialize FS from sblock.
- Deleted vars pip,pvp (use NP instead). Initialize CGP from
- cgs array; don't use bread. Comment out calls to brelse and
- bdwrite. Use csum instead of fs_cs macro.
- (ffs_fserr): Commented out.
- (ffs_dirpref): Use csum instead of fs_cs macro.
-
- * ufs.h (ffs_alloc): Renamed from alloc; all callers changed.
- (ffs_blkfree): New arg NP; renamed from blkfree; all callers changed.
- (ffs_blkpref): Renamed from blkpref; all callers changed.
- (ffs_realloocg): Rename from realloccg; all callers changed.
-
- * fs.h: New from 4.4 BSD; BSD version `8.7 4/19/94'.
- (fs_cs): Don't use fs_csp; use global csum instead.
-
- * subr.c: New from 4.4 BSD; BSD version `8.2 9/21/93'.
- Remove old includes. Include "ufs.h" and "fs.h".
- (ffs_blkatoff, ffs_checkoverlap): Comment out.
-
- * tables.c: New from 4.4 BSD; BSD version `8.1 6/11/93'.
- Don't include <param.h>; do include "ufs.h" and "fs.h".
-
- * dinode.h: New from 4.4 BSD; BSD version `8.3 1/21/94'.
- Remove oldids/inum union; replace with author.
- Renamed di_mode to be di_model; allocated di_modeh from spare.
- Allocate di_trans from spare.
- (di_inumber): Remove macro.
- * inode.c (read_disknode): Fetch uid and gid from new (long)
- fields in dinode unless we are the old inode format, in which
- case fetch them from the old fields.
- (write_node): Only set new uid and gid fields if we are not
- COMPAT_BSD4. Set old fields if the superblock says to.
- (symlink_hook): New function.
- (diskfs_create_symlink_hook): Initialize.
- * sizes.c (diskfs_truncate): Deal with truncation of short
- symlink properly.
-
- * dir.h: New from 4.4 BSD; BSD version `8.2 1/21/94'.
- Substitute our version of DIRSIZ which uses the namelen.
- Comment out declarations of struct dirtemplate and struct
- odirtemplate.
- (DIRECT_TYPE, DIRECT_NAMLEN): New macros.
- * ufs.h (direct_symlink_extension): New variable.
- * hyper.c (get_hypermetadata): Set direct_symlink_extension.
- * dir.c (dirscanblock): Use DIRECT_NAMLEN instead of d_namlen.
- (diskfs_direnter): Likewise.
- (diskfs_dirempty): Likewise.
- (diskfs_get_directs): Likewise.
- (diskfs_direnter): Set d_type field of new slot if
- direct_symlink_extension is set.
- (diskfs_dirrewrite): Likewise.
-
- * ufs.h (compat_mode): New variable.
- * main.c (main): Set compat_mode to zero if we are the bootstrap
- filesystem.
- * inode.c (diskfs_set_translator): Return error if compat_mode
- is set.
- (write_node): Don't set GNU dinode field extensions unless
- compat_mode is COMPAT_GNU.
-
-Mon Jul 11 18:14:26 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir.c (diskfs_get_directs): When copying entries into DATAP,
- set the d_reclen parameter of the copy to the minimum length
- (because that's all we use) rather than the size that it had
- in the directory itself.
-
-Wed Jul 6 14:41:48 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir.c (dirscanblock): In main loop, initialize PREVOFF
- to zero, not BLOCKADDR. Otherwise, the wrong value is
- stored into DS->prevoff and then diskfs_dirremove crashes.
-
-Tue Jul 5 14:07:38 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dinode.h: Include <endian.h> before test of BYTE_ORDER.
-
- * Makefile (TAGSLIBS): New variable.
-
-Tue Jun 21 13:45:04 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir.c (diskfs_direnter): Update dirents of DP, not NP.
-
-Mon Jun 20 16:43:48 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * dir.c (diskfs_direnter) [case SHRINK]: NEW should be set to
- OLDNEEDED past DS->entry, not to the start of the next entry.
-
- * dir.c (diskfs_direnter) [case EXTEND]: Cast in assignment
- to NEW needs proper scope.
-
- * inode.c (diskfs_node_norefs): Free dirents list of structure
- being deallocated. Also add assert checks to make sure other
- state is already clean.
-
-Thu Jun 16 11:38:17 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * dir.c (diskfs_dirempty): Map directory contents ourselves
- instead of using diskfs_node_rdwr.
- (struct dirstat): New structure to cache mapping between
- lookup and commit operation and avoid use of diskfs_node_rdwr.
- (diskfs_lookup): Map directory ourselves. Keep mapping in
- DS if DS is nonzero and we might use it in direnter, dirremove,
- or dirrewrite. Deallocate mapped buffer if we return some
- error (other than ENOENT), or if DS is zero, or if there is
- no possible commit operation to follow. When setting DS->stat
- to EXTEND, do it the new way.
- (dirscanblock): Changed BLKOFF to be virtual address of mapped
- block and renamed it BLKADDR. New arg IDX. Use mapped block
- instead of calling diskfs_node_rdwr. Set DS according to the new
- rules.
- (diskfs_direnter): Interpret new dirstat format.
- (diskfs_dirremove): Likewise.
- (diskfs_dirrewrite): Likewise.
- (diskfs_drop_dirstat): Deallocate cached mapping here.
-
- * dir.c (dirscanblock): When we find the node for type CREATE,
- invalidate DS by setting type to LOOKUP, not LOOKING.
-
- * dir.c (diskfs_direnter, diskfs_dirremove, diskfs_dirrewrite):
- Call diskfs_notice_dirchange when appropriate.
-
- * dir.c (diskfs_get_directs): Deal properly with case where
- BUFSIZ==0 and where NENTRIES==-1.
-
-Wed Jun 15 16:40:12 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * main.c (main): Check device sector size and media size
- on startup.
-
-Tue Jun 14 14:41:17 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * ufs.h (struct disknode) [dirents]: New member.
- * inode.c (iget): Initialize DN->dirents.
- * dir.c (diskfs_direnter, diskfs_dirremove): Keep track
- of dirents member.
- (dirscanblock): New var `nentries'; use it to count the
- number of directory entries in this block and set it if
- we end up scanning the entire block.
- (count_dirents): New function.
- (diskfs_get_directs): New function.
-
-Mon Jun 13 13:50:00 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * ufs.h (sinmaplock, dinmaplock): New global vars.
- * inode.c (inode_init): Initialize sinmaplock and dinmaplock.
- * pager.c (find_address, pager_unlock_page): Protect use
- if dinloc array with dinmaplock.
- (din_map, din_unmap): Doc fix.
- (find_address, pager_unlock_page): Protect use of sinloc array
- with sinmaplock.
- (sin_map, sin_remap, sin_unmap): Doc fix.
- (pager_clear_user_data): Acquire sinmaplock and dinmaplock
- instead of NP->dn->datalock and NP->dn->sinlock respectively.
-
- * sizes.c (diskfs_truncate, diskfs_grow): Protect use of sinloc
- and sindir mapping functions with sinmaplock.
- (sindir_drop): Protect use of dinloc and dindir mapping functions
- with dinmaplock.
-
- * ufs.h (struct rwlock): New type.
- (struct disknode) [dinlock, sinlock, datalock]: Use read-write lock.
- Change comments so that these don't lock dinloc and sinloc anymore.
- [rwlock_master, rwlock_wakeup]: New members.
- (rwlock_reader_lock, rwlock_writer_lock, rwlock_reader_unlock,
- rwlock_writer_unlock, rwlock_init): New functions.
- * inode.c (iget): Initialize DN->rwlock_master and
- DN->rwlock_wakeup. Change initialization of DN->dinlock,
- DN->sinlock, and DN->datalock to use rwlock_init.
- * pager.c (find_address): Lock NP->dn->dinlock, NP->dn->sinlock,
- and NP->dn->datalock with rwlock_reader_lock. Change type of
- parameter NPLOCK to be a read-write lock. New parm DNP. Callers
- changed.
- (pager_read_page, pager_write_page): Change type of NPLOCK to be
- read-write lock; call rwlock_reader_unlock instead of
- mutex_unlock. New variable DN.
- (pager_unlock_page): Use rwlock_writer_lock to lock
- NP->dn->dinlock, NP->dn->sinlock, and NP->dn->datalock.
- * sizes.c (diskfs_truncate, diskfs_grow): Change locks of DATALOCK
- field to use rwlock_writer_{un,}lock.
- (sindir_drop): Ditto for SINLOCK field.
- (dindir_drop): Ditto for DINLOCK field.
-
-Mon Jun 6 19:23:26 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * sizes.c (diskfs_grow): After realloccg, zero new data (which I'm
- not sure is really necessary, but until I figure it out, this is
- safest). Also poke old data (the latter only if the block has
- moved)--otherwise the kernel won't know to page it out to the new
- location.
- (poke_pages): When poking, be careful not to actually change the data.
- LEN should be end - start, not start - end.
-
-Fri Jun 3 12:37:27 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * inode.c (iget): When we find the node in the table, acquire the
- mutex *after* incrementing NP->references and unlocking
- diskfs_node_refcnt_lock; otherwise we can deadlock against
- diskfs_nput.
-
-Thu Jun 2 12:16:09 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * ufs.h (sblock_dirty, csum_dirty, alloclock): New global variables.
- * alloc.c (alloclock): Remove static keyword..
- * alloc.c (realloccg): Set sblock_dirty after changing sblock.
- (blkpref): Likewise.
- (fragextend): Likewise.
- (alloccg): Likewise.
- (alloccgblk): Likewise.
- (ialloccg): Likewise.
- (blkfree): Likewise.
- (diskfs_free_node): Likewise.
- * hyper.c (diskfs_set_hypermetadata): Likewise.
- * alloc.c (fragextend): Set csum_dirty after changi csum.
- (alloccg): Likewise.
- (alloccgblk): Likewise.
- (ialloccg): Likewise.
- (blkfree): Likewise.
- (diskfs_free_node): Likewise.
- * hyper.c (diskfs_set_hypermetadata): Acquire alloclock while
- writing hypermetadata. Only write csum and sblock if
- csum_dirty or sblock_dirty, respectively, is set, and then
- clear it after starting the write.
-
- * main.c (main): Likewise.
-
- * sizes.c (diskfs_truncate): Don't turn off caching; the new
- light reference system takes care of this.
- * pager.c (diskfs_get_filemap): No longer necessary to turn
- on caching here, because truncate no longer turns it off.
-
- * inode.c (diskfs_lost_hardrefs, diskfs_new_hardrefs): New functions.
- * pager.c (drop_pager_softrefs, allow_pager_softrefs): New functions.
- (sin_map): Use diskfs_nref_light, not diskfs_nref.
- (diskfs_get_filemap): Use diskfs_nref_light, not diskfs_nref.
- (pager_clear_user_data): Use diskfs_nrele_light, not diskfs_nrele.
- * ufs.h (drop_pager_softrefs, allow_pager_softrefs): New
- declarations.
-
-Wed Jun 1 13:35:11 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * sizes.c (diskfs_truncate): After calling sin_unmap, turn
- off caching on the sininfo pager so that it gets freed promptly
- (there's generally no value in keeping it around because there
- is no live fileinfo pager).
- * pager.c (diskfs_get_filemap): Make sure we turn caching back on
- here, however, if we start using the file pager.
-
- * pager.c (sin_map): When np->dn->sininfo is set, we have
- to insert a valid send right after fetching the receive name.
-
- * pager.c (sin_unmap, din_unmap): New functions.
- (pager_clear_user_data): Call sin_unmap and din_unmap
- instead of doing it right here.
-
- * sizes.c (diskfs_truncate): Call sin_unmap instead of
- doing it right here.
- (sindir_drop): Call din_unmap instead of doing it right
- here. Also, call it always, not just when wo do dindir_drop.
-
- * sizes.c (diskfs_grow): After alloc into sindir area,
- unmap it if we don't have an active data pager.
- * ufs.h (sin_unmap, din_unmap): New declarations.
-
- * sizes.c (diskfs_grow): In computing OSIZE in the realloc
- case of lbn < NDADDR, deal correctly with the case where
- np->allocsize is already an integral number of blocks.
-
- * sizes.c (diskfs_grow): Compute SIZE correctly.
-
- * alloc.c (alloc, realloccg, blkfree): When checking validity
- of size arguments, also make sure the size isn't zero.
-
- * alloc.c (diskfs_alloc_node): Lock ALLOCLOCK before checking
- sblock->fs_cstotal.cs_nifree.
-
-Tue May 31 18:47:42 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
-
- * ufs.h (DONT_CACHE_MEMORY_OBJECTS): Define it.
-
- * dir.c (diskfs_direnter: case TAKE): Assert that OLD->d_reclen >=
- NEEDED, not that it is strictly >.
-
-Tue May 31 11:10:28 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * sizes.c (diskfs_grow): Call diskfs_node_update (but don't wait)
- after successful completion to prevent old data from hanging around
- too long and getting flushed all at once from the kernel.
-
- * sizes.c (diskfs_grow): Change SIZE to be the size of the last
- block allocated. Delete variable NSIZE; use SIZE instead.
-
-Fri May 27 13:15:26 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * sizes.c (diskfs_truncate): Set NP->dn_stat_dirty after each
- modification of NP->dn_stat.
-
- * sizes.c (diskfs_truncate): Compute new value of NP->allocsize
- correctly.
-
- * inode.c (iget): Set NP->allocsize to be the *actual* allocsize.
-
-Thu May 26 11:51:45 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * sizes.c (diskfs_truncate): In blkfree loop of blocks past
- NDADDR, subtract NDADDR from idx to index correctly into
- sinloc array. Start this loop with idx not less than NDADDR.
- (diskfs_truncate): If olastblock == NDADDR, then we also
- need to truncate blocks (one) mapped by single indirect blocks.
- (diskfs_truncate): New variable `first2free'. Use in place
- of older losing calculations involving lastblock.
- (sindir_drop): Rename parameters to be FIRST and LAST. Change
- interpretation of FIRST by one to correspond with changed call
- in diskfs_truncate.
-
- * pager.c (sin_remap): When computing NEWSIZE, round up to
- a page boundary, thus mimicing the SINDIR computation in
- pager_report_extent properly.
-
- * pager.c (pager_unlock_page) [case SINDIR; vblkno == 0]: Read
- from ....di_ib[INDIR_SINGLE] rather than invalid data before
- NP->dn->dinloc.
-
- * alloc.c (alloc) [nospace]: Unlock alloclock.
- (realloccg): Unlock alloclock before jumping to nospace.
- (blkpref) [!(lbn < NDADDR)]: Unlock alloclock before returning
- success.
-
- * sizes.c (diskfs_grow): When allocing a block past NDADDR, the
- tbl arg to blkpref is the table of direct block pointers
- NP->dn->sinloc, not the table of indirect block pointers
- ...->di_ib.
-
- * sizes.c (diskfs_grow): When writing into the SINDIR area, call
- sin_map instead of sin_remap if the sindir isn't already mapped.
- Also set np->allocsize *before* calling sin_map, but *after*
- calling sin_remap, to meet the requirements of those separate
- routines.
-
- * sizes.c (diskfs_grow): If END isn't bigger than NP->allocsize,
- then don't try and do anything. In computation of LBN and the
- first use of NB, round up to block boundary correctly. Don't
- attempt to realloc an old block if the size is 0 (in which case
- NB is -1 and unsigned comparison rules might foul things up).
-
-Mon May 23 13:18:33 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * Makefile (ufs): Give -n in the proper order to rsh.
-
- * main.c: Include <hurd/startup.h>.
-
- * ufs.h (DONT_CACHE_MEMORY_OBJECTS): New compilation flag.
- * pager.c (pager_report_attributes): Deleted function.
- (MAY_CACHE): New macro; more useful form for using
- DONT_CACHE_MEMORY_OBJECTS.
- (sin_map, pager_init, diskfs_get_filemap): Provide new
- args in calls to pager_create.
- * sizes.c (MAY_CACHE): New macro; more useful form for
- using DONT_CACHE_MEMORY_OBJECTS.
- (diskfs_truncate): Use MAY_CACHE in calls to pager_change_attributes.
-
-Fri May 20 18:52:41 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * sizes.c (diskfs_truncate): Force any delayed copies of the
- vanishing region to be taken immediately before stopping, and
- prevent any new delayed copies from being made until we are done
- manipulating things.
- (poke_pages): New function.
- * pager.c (pager_report_attributes): New function.
-
-Wed May 18 15:51:40 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * alloc.c (alloc, realloccg, diskfs_alloc_node, alloccgblk,
- blkfree, diskfs_free_node, mapsearch): Added helpful strings to
- asserts.
- (realloccg): Split up assert.
-
-Tue May 17 13:26:22 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * main.c (main): Delete unused variable PROC.
-
-Mon May 16 15:32:07 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
-
- * alloc.c (realloccg): When fragextend succeeds, bother to set
- *PBN.
-
- * sizes.c (diskfs_grow): In fragment growth case, NSIZE should
- not be the amount to hold SIZE (SIZE is the amount the file is
- growing by), but rather the old size of the fragment plus the
- SIZE.
-
- * dir.c (diskfs_direnter case COMPRESS): Rewrite loop to deal
- properly with the case where from and to overlap.
-
-Mon May 9 16:51:44 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * main.c (ufs_version): New variable.
- (save_argv): New variable.
- (main): Set save_argv.
- (diskfs_init_completed): New function.
-
-Thu May 5 19:06:54 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
-
- * Makefile (exec_server_image.o): Use -n when calling rsh.
-
-Thu May 5 07:39:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
-
- * Makefile ($(OBJS)): Use $(includedir) instead of $(headers) in deps.
-
diff --git a/ufs/Makefile b/ufs/Makefile
index d9375989..cf5c40d7 100644
--- a/ufs/Makefile
+++ b/ufs/Makefile
@@ -1,5 +1,6 @@
-
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+# Makefile for ufs
+#
+# Copyright (C) 1994,95,96,99,2000,02 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
@@ -16,18 +17,16 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
dir := ufs
-makemode := servers
+makemode := server
-targets = ufs ufs.static
+target = ufs
SRCS = alloc.c consts.c dir.c hyper.c inode.c main.c pager.c \
- sizes.c subr.c tables.c bmap.c pokeloc.c
+ sizes.c subr.c tables.c bmap.c pokeloc.c xinl.c
LCLHDRS = ufs.h fs.h dinode.h dir.h
OBJS = $(SRCS:.c=.o)
-
-ufs.static-LDFLAGS += -static
+HURDLIBS = diskfs iohelp fshelp store pager threads ports ihash shouldbeinlibc
include ../Makeconf
-ufs.static ufs: $(OBJS) ../libdiskfs/libdiskfs.a ../libports/libports.a ../libpager/libpager.a ../libiohelp/libiohelp.a ../libfshelp/libfshelp.a ../libthreads/libthreads.a ../libihash/libihash.a ../libshouldbeinlibc/libshouldbeinlibc.a
-
+ufs.static: $(boot-store-types:%=../libstore/libstore_%.a)
diff --git a/ufs/alloc.c b/ufs/alloc.c
index 90ce68f5..d8f92255 100644
--- a/ufs/alloc.c
+++ b/ufs/alloc.c
@@ -1,5 +1,5 @@
/* Disk allocation routines
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993,94,95,96,98,2002 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-The GNU Hurd is distributed in the hope that it will be useful,
+The GNU Hurd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -67,7 +67,7 @@ extern u_long nextgennumber;
spin_lock_t alloclock = SPIN_LOCK_INITIALIZER;
/* Forward declarations */
-static u_long ffs_hashalloc (struct node *, int, long, int,
+static u_long ffs_hashalloc (struct node *, int, long, int,
u_long (*)(struct node *, int, daddr_t, int));
static u_long ffs_alloccg (struct node *, int, daddr_t, int);
static daddr_t ffs_fragextend (struct node *, int, long, int, int);
@@ -96,7 +96,7 @@ void
swab_cg (struct cg *cg)
{
int i, j;
-
+
if (swab_long (cg->cg_magic) == CG_MAGIC
|| cg->cg_magic == CG_MAGIC)
{
@@ -125,12 +125,12 @@ swab_cg (struct cg *cg)
/* blktot map */
for (i = 0; i < cg->cg_ncyl; i++)
cg_blktot(cg)[i] = swab_long (cg_blktot(cg)[i]);
-
+
/* blks map */
for (i = 0; i < cg->cg_ncyl; i++)
for (j = 0; j < sblock->fs_nrpos; j++)
cg_blks(sblock, cg, i)[j] = swab_short (cg_blks (sblock, cg, i)[j]);
-
+
for (i = 0; i < sblock->fs_contigsumsize; i++)
cg_clustersum(cg)[i] = swab_long (cg_clustersum(cg)[i]);
@@ -140,11 +140,11 @@ swab_cg (struct cg *cg)
{
/* Old format cylinder group... */
struct ocg *ocg = (struct ocg *) cg;
-
+
if (swab_long (ocg->cg_magic) != CG_MAGIC
&& ocg->cg_magic != CG_MAGIC)
return;
-
+
ocg->cg_time = swab_long (ocg->cg_time);
ocg->cg_cgx = swab_long (ocg->cg_cgx);
ocg->cg_ncyl = swab_short (ocg->cg_ncyl);
@@ -176,7 +176,7 @@ int
read_cg (int cg, struct cg **cgpp)
{
struct cg *diskcg = cg_locate (cg);
-
+
if (swab_disk)
{
*cgpp = malloc (sblock->fs_cgsize);
@@ -205,7 +205,7 @@ release_cg (struct cg *cgp)
/*
* Allocate a block in the file system.
- *
+ *
* The size of the requested block is given, which must be some
* multiple of fs_fsize and <= fs_bsize.
* A preference may be optionally specified. If a preference is given
@@ -215,7 +215,7 @@ release_cg (struct cg *cgp)
* 3) allocate a block in the same cylinder group.
* 4) quadradically rehash into other cylinder groups, until an
* available block is located.
- * If no block preference is given the following heirarchy is used
+ * If no block preference is given the following hierarchy is used
* to allocate a block:
* 1) allocate a block in the cylinder group that contains the
* inode for the file.
@@ -224,7 +224,7 @@ release_cg (struct cg *cgp)
*/
error_t
ffs_alloc(register struct node *np,
- daddr_t lbn,
+ daddr_t lbn,
daddr_t bpref,
int size,
daddr_t *bnp,
@@ -233,7 +233,7 @@ ffs_alloc(register struct node *np,
register struct fs *fs;
daddr_t bno;
int cg;
-
+
*bnp = 0;
fs = sblock;
#ifdef DIAGNOSTIC
@@ -247,7 +247,7 @@ ffs_alloc(register struct node *np,
spin_lock (&alloclock);
if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
goto nospace;
- if (cred && !diskfs_isuid (0, cred)
+ if (cred && !idvec_contains (cred->user->uids, 0)
&& freespace(fs, fs->fs_minfree) <= 0)
goto nospace;
#ifdef QUOTA
@@ -297,7 +297,7 @@ error_t
ffs_realloccg(register struct node *np,
daddr_t lbprev,
volatile daddr_t bpref,
- int osize,
+ int osize,
int nsize,
daddr_t *pbn,
struct protid *cred)
@@ -306,7 +306,7 @@ ffs_realloccg(register struct node *np,
int cg, error;
volatile int request;
daddr_t bprev, bno;
-
+
*pbn = 0;
fs = sblock;
#ifdef DIAGNOSTIC
@@ -322,8 +322,9 @@ ffs_realloccg(register struct node *np,
#endif /* DIAGNOSTIC */
spin_lock (&alloclock);
-
- if (!diskfs_isuid (0, cred) && freespace(fs, fs->fs_minfree) <= 0)
+
+ if (!idvec_contains (cred->user->uids, 0)
+ && freespace(fs, fs->fs_minfree) <= 0)
goto nospace;
error = diskfs_catch_exception ();
if (error)
@@ -377,8 +378,8 @@ ffs_realloccg(register struct node *np,
switch ((int)fs->fs_optim) {
case FS_OPTSPACE:
/*
- * Allocate an exact sized fragment. Although this makes
- * best use of space, we will waste time relocating it if
+ * Allocate an exact sized fragment. Although this makes
+ * best use of space, we will waste time relocating it if
* the file continues to grow. If the fragmentation is
* less than half of the minimum free reserve, we choose
* to begin optimizing for time.
@@ -418,7 +419,7 @@ ffs_realloccg(register struct node *np,
bno = (daddr_t)ffs_hashalloc(np, cg, (long)bpref, request,
(u_long (*)())ffs_alloccg);
if (bno > 0) {
-#if 0 /* Not necessary in GNU Hurd ufs */
+#if 0 /* Not necessary in GNU Hurd ufs */
bp->b_blkno = fsbtodb(fs, bno);
(void) vnode_pager_uncache(ITOV(ip));
#endif
@@ -471,7 +472,7 @@ nospace:
* logical blocks to be made contiguous is given. The allocator attempts
* to find a range of sequential blocks starting as close as possible to
* an fs_rotdelay offset from the end of the allocation for the logical
- * block immediately preceeding the current range. If successful, the
+ * block immediately preceding the current range. If successful, the
* physical block numbers in the buffer pointers and in the inode are
* changed to reflect the new allocation. If unsuccessful, the allocation
* is left unchanged. The success in doing the reallocation is returned.
@@ -584,7 +585,7 @@ ffs_reallocblks(ap)
* Next we must write out the modified inode and indirect blocks.
* For strict correctness, the writes should be synchronous since
* the old block values may have been written to disk. In practise
- * they are almost never written, but if we are concerned about
+ * they are almost never written, but if we are concerned about
* strict correctness, the `doasyncfree' flag should be set to zero.
*
* The test on `doasyncfree' should be changed to test a flag
@@ -630,20 +631,20 @@ fail:
/*
* Allocate an inode in the file system.
- *
+ *
* If allocating a directory, use ffs_dirpref to select the inode.
* If allocating in a directory, the following hierarchy is followed:
* 1) allocate the preferred inode.
* 2) allocate an inode in the same cylinder group.
* 3) quadradically rehash into other cylinder groups, until an
* available inode is located.
- * If no inode preference is given the following heirarchy is used
+ * If no inode preference is given the following hierarchy is used
* to allocate an inode:
* 1) allocate an inode in cylinder group 0.
* 2) quadradically rehash into other cylinder groups, until an
* available inode is located.
*/
-/* This is now the diskfs_alloc_node callback from the diskfs library
+/* This is now the diskfs_alloc_node callback from the diskfs library
(described in <hurd/diskfs.h>). It used to be ffs_valloc in BSD. */
error_t
diskfs_alloc_node (struct node *dir,
@@ -655,7 +656,7 @@ diskfs_alloc_node (struct node *dir,
ino_t ino, ipref;
int cg, error;
int sex;
-
+
fs = sblock;
@@ -682,9 +683,9 @@ diskfs_alloc_node (struct node *dir,
goto noinodes;
error = diskfs_cached_lookup (ino, &np);
assert ("duplicate allocation" && !np->dn_stat.st_mode);
- assert (!np->istranslated);
+ assert (! (np->dn_stat.st_mode & S_IPTRANS));
if (np->dn_stat.st_blocks) {
- printf("free inode %d had %d blocks\n",
+ printf("free inode %Ld had %Ld blocks\n",
ino, np->dn_stat.st_blocks);
np->dn_stat.st_blocks = 0;
np->dn_set_ctime = 1;
@@ -699,7 +700,7 @@ diskfs_alloc_node (struct node *dir,
nextgennumber = sex;
np->dn_stat.st_gen = nextgennumber;
spin_unlock (&gennumberlock);
-
+
*npp = np;
alloc_sync (np);
return (0);
@@ -738,7 +739,7 @@ ffs_dirpref(register struct fs *fs)
* Select the desired position for the next block in a file. The file is
* logically divided into sections. The first section is composed of the
* direct blocks. Each additional section contains fs_maxbpg blocks.
- *
+ *
* If no blocks have been allocated in the first section, the policy is to
* request a block in the same cylinder group as the inode that describes
* the file. If no blocks have been allocated in any other section, the
@@ -752,7 +753,7 @@ ffs_dirpref(register struct fs *fs)
* indirect block, the information on the previous allocation is unavailable;
* here a best guess is made based upon the logical block number being
* allocated.
- *
+ *
* If a section is already partially allocated, the policy is to
* contiguously allocate fs_maxcontig blocks. The end of one of these
* contiguous blocks and the beginning of the next is physically separated
@@ -785,10 +786,10 @@ ffs_blkpref(struct node *np,
*/
if (indx == 0 || bap[indx - 1] == 0)
startcg =
- (ino_to_cg(fs, np->dn->number)
+ (ino_to_cg(fs, np->dn->number)
+ lbn / fs->fs_maxbpg);
else
- startcg = dtog(fs,
+ startcg = dtog(fs,
read_disk_entry (bap[indx - 1])) + 1;
startcg %= fs->fs_ncg;
avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
@@ -891,14 +892,14 @@ ffs_hashalloc(struct node *np,
/*
* Determine whether a fragment can be extended.
*
- * Check to see if the necessary fragments are available, and
+ * Check to see if the necessary fragments are available, and
* if they are, allocate them.
*/
static daddr_t
ffs_fragextend(struct node *np,
int cg,
long bprev,
- int osize,
+ int osize,
int nsize)
{
register struct fs *fs;
@@ -1015,7 +1016,7 @@ ffs_alloccg(struct node *np,
bno = ffs_alloccgblk(fs, cgp, bpref);
/* bdwrite(bp); */
if (releasecg)
- release_cg (cgp);
+ release_cg (cgp);
return (bno);
}
/*
@@ -1029,7 +1030,7 @@ ffs_alloccg(struct node *np,
break;
if (allocsiz == fs->fs_frag) {
/*
- * no fragments were available, so a block will be
+ * no fragments were available, so a block will be
* allocated, and hacked up
*/
if (cgp->cg_cs.cs_nbfree == 0) {
@@ -1048,7 +1049,7 @@ ffs_alloccg(struct node *np,
csum[cg].cs_nffree += i;
fs->fs_fmod = 1;
cgp->cg_frsum[i]++;
-
+
if (releasecg)
release_cg (cgp);
record_poke (cgp, sblock->fs_cgsize);
@@ -1126,7 +1127,7 @@ ffs_alloccgblk(register struct fs *fs,
/*
* Block layout information is not available.
* Leaving bpref unchanged means we take the
- * next available free block following the one
+ * next available free block following the one
* we just allocated. Hopefully this will at
* least hit a track cache on drives of unknown
* geometry (e.g. SCSI).
@@ -1134,7 +1135,7 @@ ffs_alloccgblk(register struct fs *fs,
goto norot;
}
/*
- * check the summary information to see if a block is
+ * check the summary information to see if a block is
* available in the requested cylinder starting at the
* requested rotational position and proceeding around.
*/
@@ -1284,7 +1285,7 @@ fail:
brelse(bp);
return (0);
}
-#endif
+#endif
/*
* Determine whether an inode can be allocated.
@@ -1376,7 +1377,7 @@ gotit:
* Free a block or fragment.
*
* The specified block or fragment is placed back in the
- * free map. If a fragment is deallocated, a possible
+ * free map. If a fragment is deallocated, a possible
* block reassembly is checked.
*/
void
@@ -1394,7 +1395,7 @@ ffs_blkfree(register struct node *np,
assert ((u_int)size <= fs->fs_bsize && !fragoff (fs, size));
cg = dtog(fs, bno);
if ((u_int)bno >= fs->fs_size) {
- printf("bad block %ld, ino %d\n", bno, np->dn->number);
+ printf("bad block %ld, ino %Ld\n", bno, np->dn->number);
/* ffs_fserr(fs, ip->i_uid, "bad block"); */
return;
}
@@ -1408,7 +1409,7 @@ ffs_blkfree(register struct node *np,
cgp = (struct cg *)bp->b_data;
#else
releasecg = read_cg (cg, &cgp);
-#endif
+#endif
if (!cg_chkmagic(cgp)) {
/* brelse(bp); */
if (releasecg)
@@ -1483,7 +1484,7 @@ ffs_blkfree(register struct node *np,
*
* The specified inode is placed back in the free map.
*/
-/* Implement diskfs call back diskfs_free_node (described in
+/* Implement diskfs call back diskfs_free_node (described in
<hurd/diskfs.h>. This was called ffs_vfree in BSD. */
void
diskfs_free_node (struct node *np, mode_t mode)
@@ -1507,17 +1508,17 @@ diskfs_free_node (struct node *np, mode_t mode)
cgp = (struct cg *)bp->b_data;
#else
releasecg = read_cg (cg, &cgp);
-#endif
+#endif
if (!cg_chkmagic(cgp)) {
/* brelse(bp); */
if (releasecg)
- release_cg (cgp);
+ release_cg (cgp);
return;
}
cgp->cg_time = diskfs_mtime->seconds;
ino %= fs->fs_ipg;
if (isclr(cg_inosused(cgp), ino)) {
-/* printf("dev = 0x%x, ino = %d, fs = %s\n",
+/* printf("dev = 0x%x, ino = %Ld, fs = %s\n",
pip->i_dev, ino, fs->fs_fsmnt); */
assert (diskfs_readonly);
}
@@ -1686,7 +1687,7 @@ ffs_clusteracct(struct fs *fs,
#if 0
/*
* Fserr prints the name of a file system with an error diagnostic.
- *
+ *
* The form of the error message is:
* fs: error message
*/
diff --git a/ufs/consts.c b/ufs/consts.c
index 6698c5f4..69221233 100644
--- a/ufs/consts.c
+++ b/ufs/consts.c
@@ -1,5 +1,5 @@
/* Various constants wanted by the diskfs library
- Copyright (C) 1994, 1995 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -16,8 +16,11 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ufs.h"
+#include "dir.h"
+#include <version.h>
int diskfs_link_max = LINK_MAX;
+int diskfs_name_max = MAXNAMLEN;
int diskfs_maxsymlinks = 8;
int diskfs_shortcut_symlink = 1;
int diskfs_shortcut_chrdev = 1;
@@ -25,7 +28,6 @@ int diskfs_shortcut_blkdev = 1;
int diskfs_shortcut_fifo = 1;
int diskfs_shortcut_ifsock = 1;
char *diskfs_server_name = "ufs";
-int diskfs_major_version = 0;
-int diskfs_minor_version = 0;
-int diskfs_edit_version = 0;
+char *diskfs_server_version = HURD_VERSION;
+char *diskfs_extra_version = "GNU Hurd";
int diskfs_synchronous = 0;
diff --git a/ufs/devio.c b/ufs/devio.c
deleted file mode 100644
index 2e5cc332..00000000
--- a/ufs/devio.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Device input and output
- Copyright (C) 1992, 1993, 1994 Free Software Foundation
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Written by Michael I. Bushnell. */
-
-#include "ufs.h"
-#include <device/device.h>
-#include <device/device_request.h>
-
-/* Write disk block ADDR with DATA of LEN bytes, waiting for completion. */
-error_t
-dev_write_sync (daddr_t addr,
- vm_address_t data,
- long len)
-{
- int foo;
- assert (!diskfs_readonly);
- if (device_write (ufs_device, 0, addr, (io_buf_ptr_t) data, len, &foo)
- || foo != len)
- return EIO;
- return 0;
-}
-
-/* Write diskblock ADDR with DATA of LEN bytes; don't bother waiting
- for completion. */
-error_t
-dev_write (daddr_t addr,
- vm_address_t data,
- long len)
-{
- assert (!diskfs_readonly);
- if (device_write_request (ufs_device, MACH_PORT_NULL, 0, addr,
- (io_buf_ptr_t) data, len))
- return EIO;
- return 0;
-}
-
-static int deverr;
-
-/* Read disk block ADDR; put the address of the data in DATA; read LEN
- bytes. Always *DATA should be a full page no matter what. */
-error_t
-dev_read_sync (daddr_t addr,
- vm_address_t *data,
- long len)
-{
- int foo;
- deverr = device_read (ufs_device, 0, addr, len, (io_buf_ptr_t *)data,
- (u_int *)&foo);
- if (deverr || foo != len)
- return EIO;
- return 0;
-}
-
diff --git a/ufs/dir.c b/ufs/dir.c
index d015a6c6..3c5f152a 100644
--- a/ufs/dir.c
+++ b/ufs/dir.c
@@ -1,5 +1,7 @@
/* Directory management routines
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2007
+ 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
@@ -64,8 +66,8 @@ struct dirstat
/* Index of this directory block. */
int idx;
-
- /* For stat COMPRESS, this is the address (inside mapbuf)
+
+ /* For stat COMPRESS, this is the address (inside mapbuf)
of the first direct in the directory block to be compressed. */
/* For stat HERE_TIS, SHRINK, and TAKE, this is the entry referenced. */
struct directory_entry *entry;
@@ -79,24 +81,24 @@ struct dirstat
size_t nbytes;
};
-size_t diskfs_dirstat_size = sizeof (struct dirstat);
+const size_t diskfs_dirstat_size = sizeof (struct dirstat);
/* Initialize DS such that diskfs_drop_dirstat will ignore it. */
-void
+void
diskfs_null_dirstat (struct dirstat *ds)
{
ds->type = LOOKUP;
}
-static error_t
-dirscanblock (vm_address_t blockoff, struct node *dp, int idx, char *name,
- int namelen, enum lookup_type type, struct dirstat *ds,
- ino_t *inum);
+static error_t
+dirscanblock (vm_address_t blockoff, struct node *dp, int idx,
+ const char *name, int namelen, enum lookup_type type,
+ struct dirstat *ds, ino_t *inum);
/* Implement the diskfs_lookup from the diskfs library. See
<hurd/diskfs.h> for the interface specification. */
error_t
-diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
+diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type,
struct node **npp, struct dirstat *ds, struct protid *cred)
{
error_t err;
@@ -111,8 +113,9 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
vm_address_t buf = 0;
vm_size_t buflen = 0;
int blockaddr;
- int idx;
-
+ int idx, lastidx;
+ int looped;
+
if ((type == REMOVE) || (type == RENAME))
assert (npp);
@@ -121,12 +124,16 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
spec_dotdot = type & SPEC_DOTDOT;
type &= ~SPEC_DOTDOT;
-
+
namelen = strlen (name);
if (namelen > MAXNAMLEN)
- return ENAMETOOLONG;
-
+ {
+ if (ds)
+ diskfs_null_dirstat (ds);
+ return ENAMETOOLONG;
+ }
+
try_again:
if (ds)
{
@@ -136,7 +143,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
}
if (buf)
{
- vm_deallocate (mach_task_self (), buf, buflen);
+ munmap ((caddr_t) buf, buflen);
buf = 0;
}
if (ds && (type == CREATE || type == RENAME))
@@ -144,6 +151,10 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
/* Map in the directory contents. */
memobj = diskfs_get_filemap (dp, prot);
+
+ if (memobj == MACH_PORT_NULL)
+ return errno;
+
buf = 0;
/* We allow extra space in case we have to do an EXTEND. */
buflen = round_page (dp->dn_stat.st_size + DIRBLKSIZ);
@@ -152,26 +163,45 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
mach_port_deallocate (mach_task_self (), memobj);
inum = 0;
-
- if (!diskfs_check_readonly ())
- dp->dn_set_atime = 1;
-
- for (blockaddr = buf, idx = 0;
- blockaddr - buf < dp->dn_stat.st_size;
- blockaddr += DIRBLKSIZ, idx++)
+
+ diskfs_set_node_atime (dp);
+
+ /* Start the lookup at DP->dn->dir_idx. */
+ idx = dp->dn->dir_idx;
+ if (idx * DIRBLKSIZ > dp->dn_stat.st_size)
+ idx = 0; /* just in case */
+ blockaddr = buf + idx * DIRBLKSIZ;
+ looped = (idx == 0);
+ lastidx = idx;
+ if (lastidx == 0)
+ lastidx = dp->dn_stat.st_size / DIRBLKSIZ;
+
+ while (!looped || idx < lastidx)
{
err = dirscanblock (blockaddr, dp, idx, name, namelen, type, ds, &inum);
if (!err)
- break;
+ {
+ dp->dn->dir_idx = idx;
+ break;
+ }
if (err != ENOENT)
{
- vm_deallocate (mach_task_self (), buf, buflen);
+ munmap ((caddr_t) buf, buflen);
return err;
}
+
+ blockaddr += DIRBLKSIZ;
+ idx++;
+ if (blockaddr - buf >= dp->dn_stat.st_size && !looped)
+ {
+ /* We've gotten to the end; start back at the beginning */
+ looped = 1;
+ blockaddr = buf;
+ idx = 0;
+ }
}
- if (!diskfs_check_readonly ())
- dp->dn_set_atime = 1;
+ diskfs_set_node_atime (dp);
if (diskfs_synchronous)
diskfs_node_update (dp, 1);
@@ -195,7 +225,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
goto out;
}
}
-
+
/* We are looking up .. */
/* Check to see if this is the root of the filesystem. */
else if (dp->dn->number == 2)
@@ -203,7 +233,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
err = EAGAIN;
goto out;
}
-
+
/* We can't just do diskfs_cached_lookup, because we would then deadlock.
So we do this. Ick. */
else if (retry_dotdot)
@@ -237,11 +267,11 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
retry_dotdot = inum;
goto try_again;
}
-
+
/* Here below are the spec dotdot cases. */
else if (type == RENAME || type == REMOVE)
np = ifind (inum);
-
+
else if (type == LOOKUP)
{
diskfs_nput (dp);
@@ -252,13 +282,13 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
else
assert (0);
}
-
+
if ((type == CREATE || type == RENAME) && !inum && ds && ds->stat == LOOKING)
{
/* We didn't find any room, so mark ds to extend the dir */
ds->type = CREATE;
ds->stat = EXTEND;
- ds->idx = idx;
+ ds->idx = dp->dn_stat.st_size / DIRBLKSIZ;
}
/* Return to the user; if we can't, release the reference
@@ -269,7 +299,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
|| !ds
|| ds->type == LOOKUP)
{
- vm_deallocate (mach_task_self (), buf, buflen);
+ munmap ((caddr_t) buf, buflen);
if (ds)
ds->type = LOOKUP; /* set to be ignored by drop_dirstat */
}
@@ -278,7 +308,7 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
ds->mapbuf = buf;
ds->mapextent = buflen;
}
-
+
if (np)
{
assert (npp);
@@ -312,8 +342,8 @@ diskfs_lookup_hard (struct node *dp, char *name, enum lookup_type type,
diskfs_lookup. If found, set *INUM to the inode number, else
return ENOENT. */
static error_t
-dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
- int namelen, enum lookup_type type,
+dirscanblock (vm_address_t blockaddr, struct node *dp, int idx,
+ const char *name, int namelen, enum lookup_type type,
struct dirstat *ds, ino_t *inum)
{
int nfree = 0;
@@ -325,7 +355,7 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
int looking = 0;
int countcopies = 0;
int consider_compress = 0;
-
+
if (ds && (ds->stat == LOOKING
|| ds->stat == COMPRESS))
{
@@ -339,30 +369,30 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
prevoff = currentoff, currentoff += read_disk_entry (entry->d_reclen))
{
entry = (struct directory_entry *)currentoff;
-
+
if (!entry->d_reclen
|| read_disk_entry (entry->d_reclen) % 4
|| DIRECT_NAMLEN (entry) > MAXNAMLEN
- || (currentoff + read_disk_entry (entry->d_reclen)
+ || (currentoff + read_disk_entry (entry->d_reclen)
> blockaddr + DIRBLKSIZ)
|| entry->d_name[DIRECT_NAMLEN (entry)]
|| DIRSIZ (DIRECT_NAMLEN (entry)) > read_disk_entry (entry->d_reclen)
|| memchr (entry->d_name, '\0', DIRECT_NAMLEN (entry)))
{
- fprintf (stderr, "Bad directory entry: inode: %d offset: %d\n",
+ fprintf (stderr, "Bad directory entry: inode: %Ld offset: %zd\n",
dp->dn->number, currentoff - blockaddr + idx * DIRBLKSIZ);
return ENOENT;
}
-
+
if (looking || countcopies)
{
int thisfree;
-
+
/* Count how much free space this entry has in it. */
if (entry->d_ino == 0)
thisfree = read_disk_entry (entry->d_reclen);
else
- thisfree = (read_disk_entry (entry->d_reclen)
+ thisfree = (read_disk_entry (entry->d_reclen)
- DIRSIZ (DIRECT_NAMLEN (entry)));
/* If this isn't at the front of the block, then it will
@@ -370,9 +400,9 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
number of bytes there too. */
if (countcopies && currentoff != blockaddr)
nbytes += DIRSIZ (DIRECT_NAMLEN (entry));
-
+
if (ds->stat == COMPRESS && nbytes > ds->nbytes)
- /* The previously found compress is better than
+ /* The previously found compress is better than
this one, so don't bother counting any more. */
countcopies = 0;
@@ -389,9 +419,9 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
nfree += thisfree;
if (nfree >= needed)
consider_compress = 1;
- }
+ }
}
-
+
if (entry->d_ino)
nentries++;
@@ -402,7 +432,7 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
break;
}
- if (consider_compress
+ if (consider_compress
&& (ds->type == LOOKING
|| (ds->type == COMPRESS && ds->nbytes > nbytes)))
{
@@ -412,7 +442,7 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
ds->idx = idx;
ds->nbytes = nbytes;
}
-
+
if (currentoff >= blockaddr + DIRBLKSIZ)
{
int i;
@@ -422,9 +452,9 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
down how many entries there were. */
if (!dp->dn->dirents)
{
- dp->dn->dirents = malloc ((dp->dn_stat.st_size / DIRBLKSIZ + 1)
- * sizeof (int));
- for (i = 0; i < dp->dn_stat.st_size/DIRBLKSIZ; i++)
+ dp->dn->dirents = malloc ((dp->dn_stat.st_size / DIRBLKSIZ)
+ * sizeof (int));
+ for (i = 0; i < dp->dn_stat.st_size/DIRBLKSIZ; i++)
dp->dn->dirents[i] = -1;
}
/* Make sure the count is correct if there is one now. */
@@ -434,7 +464,7 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
return ENOENT;
}
-
+
/* We have found the required name. */
if (ds && type == CREATE)
@@ -460,7 +490,7 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name,
the preceding lookup call, and only if that call returned ENOENT. */
error_t
diskfs_direnter_hard(struct node *dp,
- char *name,
+ const char *name,
struct node *np,
struct dirstat *ds,
struct protid *cred)
@@ -470,21 +500,21 @@ diskfs_direnter_hard(struct node *dp,
int needed = DIRSIZ (namelen);
int oldneeded;
vm_address_t fromoff, tooff;
- int totfreed;
+ int totfreed;
error_t err;
- off_t oldsize;
+ size_t oldsize = 0;
assert (ds->type == CREATE);
-
+
dp->dn_set_mtime = 1;
switch (ds->stat)
{
case TAKE:
/* We are supposed to consume this slot. */
- assert (ds->entry->d_ino == 0
+ assert (ds->entry->d_ino == 0
&& read_disk_entry (ds->entry->d_reclen) >= needed);
-
+
write_disk_entry (ds->entry->d_ino, np->dn->number);
DIRECT_NAMLEN (ds->entry) = namelen;
if (direct_symlink_extension)
@@ -492,27 +522,27 @@ diskfs_direnter_hard(struct node *dp,
bcopy (name, ds->entry->d_name, namelen + 1);
break;
-
+
case SHRINK:
/* We are supposed to take the extra space at the end
of this slot. */
oldneeded = DIRSIZ (DIRECT_NAMLEN (ds->entry));
assert (read_disk_entry (ds->entry->d_reclen) - oldneeded >= needed);
-
+
new = (struct directory_entry *) ((vm_address_t) ds->entry + oldneeded);
write_disk_entry (new->d_ino, np->dn->number);
- write_disk_entry (new->d_reclen,
+ write_disk_entry (new->d_reclen,
read_disk_entry (ds->entry->d_reclen) - oldneeded);
DIRECT_NAMLEN (new) = namelen;
if (direct_symlink_extension)
new->d_type = IFTODT (np->dn_stat.st_mode);
bcopy (name, new->d_name, namelen + 1);
-
+
write_disk_entry (ds->entry->d_reclen, oldneeded);
-
+
break;
-
+
case COMPRESS:
/* We are supposed to move all the entries to the
front of the block, giving each the minimum
@@ -540,7 +570,7 @@ diskfs_direnter_hard(struct node *dp,
totfreed = (vm_address_t) ds->entry + DIRBLKSIZ - tooff;
assert (totfreed >= needed);
-
+
new = (struct directory_entry *) tooff;
write_disk_entry (new->d_ino, np->dn->number);
write_disk_entry (new->d_reclen, totfreed);
@@ -553,14 +583,20 @@ diskfs_direnter_hard(struct node *dp,
case EXTEND:
/* Extend the file. */
assert (needed <= DIRBLKSIZ);
-
+
oldsize = dp->dn_stat.st_size;
+ if ((off_t)(oldsize + DIRBLKSIZ) != dp->dn_stat.st_size + DIRBLKSIZ)
+ {
+ /* We can't possibly map the whole directory in. */
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+ return EOVERFLOW;
+ }
while (oldsize + DIRBLKSIZ > dp->allocsize)
{
err = diskfs_grow (dp, oldsize + DIRBLKSIZ, cred);
if (err)
{
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
return err;
}
}
@@ -577,42 +613,49 @@ diskfs_direnter_hard(struct node *dp,
new->d_type = IFTODT (np->dn_stat.st_mode);
bcopy (name, new->d_name, namelen + 1);
break;
-
+
default:
assert (0);
}
dp->dn_set_mtime = 1;
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
-
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+
if (ds->stat != EXTEND)
{
- /* If we are keeping count of this block, then keep the count up
+ /* If we are keeping count of this block, then keep the count up
to date. */
if (dp->dn->dirents && dp->dn->dirents[ds->idx] != -1)
dp->dn->dirents[ds->idx]++;
}
else
{
+ int i;
/* It's cheap, so start a count here even if we aren't counting
anything at all. */
if (dp->dn->dirents)
{
- dp->dn->dirents = realloc (dp->dn->dirents,
- (ds->idx + 1) * sizeof (int));
+ dp->dn->dirents = realloc (dp->dn->dirents,
+ (dp->dn_stat.st_size / DIRBLKSIZ
+ * sizeof (int)));
+ for (i = oldsize / DIRBLKSIZ;
+ i < dp->dn_stat.st_size / DIRBLKSIZ;
+ i++)
+ dp->dn->dirents[i] = -1;
+
dp->dn->dirents[ds->idx] = 1;
}
else
{
- int i;
- dp->dn->dirents = malloc ((ds->idx + 1) * sizeof (int));
- for (i = 0; i < ds->idx; i++)
+ dp->dn->dirents = malloc (dp->dn_stat.st_size / DIRBLKSIZ
+ * sizeof (int));
+ for (i = 0; i < dp->dn_stat.st_size / DIRBLKSIZ; i++)
dp->dn->dirents[i] = -1;
dp->dn->dirents[ds->idx] = 1;
}
}
-
+
diskfs_file_update (dp, 1);
return 0;
@@ -621,7 +664,7 @@ diskfs_direnter_hard(struct node *dp,
/* Following a lookup call for REMOVE, this removes the link from the
directory. DP is the directory being changed and DS is the cached
information returned from lookup. This call is only valid if the
- directory has been locked continously since the call to lookup, and
+ directory has been locked continuously since the call to lookup, and
only if that call succeeded. */
error_t
diskfs_dirremove_hard(struct node *dp,
@@ -629,7 +672,7 @@ diskfs_dirremove_hard(struct node *dp,
{
assert (ds->type == REMOVE);
assert (ds->stat == HERE_TIS);
-
+
dp->dn_set_mtime = 1;
if (ds->preventry == 0)
@@ -638,48 +681,48 @@ diskfs_dirremove_hard(struct node *dp,
{
assert ((vm_address_t) ds->entry - (vm_address_t) ds->preventry
== read_disk_entry (ds->preventry->d_reclen));
- write_disk_entry (ds->preventry->d_reclen,
+ write_disk_entry (ds->preventry->d_reclen,
(read_disk_entry (ds->preventry->d_reclen)
+ read_disk_entry (ds->entry->d_reclen)));
}
dp->dn_set_mtime = 1;
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
/* If we are keeping count of this block, then keep the count up
to date. */
if (dp->dn->dirents && dp->dn->dirents[ds->idx] != -1)
dp->dn->dirents[ds->idx]--;
-
+
diskfs_file_update (dp, 1);
return 0;
}
-
+
/* Following a lookup call for RENAME, this changes the inode number
- on a directory entry. DP is the directory being changed; NP is
- the new node being linked in; DP is the cached information returned
+ on a directory entry. DP is the directory being changed; NP is
+ the new node being linked in; DP is the cached information returned
by lookup. This call is only valid if the directory has been locked
continuously since the call to lookup, and only if that call
succeeded. */
error_t
-diskfs_dirrewrite_hard(struct node *dp,
+diskfs_dirrewrite_hard(struct node *dp,
struct node *np,
struct dirstat *ds)
{
assert (ds->type == RENAME);
assert (ds->stat == HERE_TIS);
-
+
dp->dn_set_mtime = 1;
write_disk_entry (ds->entry->d_ino, np->dn->number);
if (direct_symlink_extension)
ds->entry->d_type = IFTODT (np->dn_stat.st_mode);
dp->dn_set_mtime = 1;
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
-
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
+
diskfs_file_update (dp, 1);
return 0;
@@ -692,23 +735,26 @@ diskfs_dirempty(struct node *dp,
struct protid *cred)
{
struct directory_entry *entry;
- int curoff;
- vm_address_t buf;
+ vm_address_t buf, curoff;
memory_object_t memobj;
error_t err;
memobj = diskfs_get_filemap (dp, VM_PROT_READ);
+
+ if (memobj == MACH_PORT_NULL)
+ /* XXX should reflect error properly */
+ return 0;
+
buf = 0;
-
+
err = vm_map (mach_task_self (), &buf, dp->dn_stat.st_size, 0,
1, memobj, 0, 0, VM_PROT_READ, VM_PROT_READ, 0);
mach_port_deallocate (mach_task_self (), memobj);
assert (!err);
- if (!diskfs_check_readonly ())
- dp->dn_set_atime = 1;
+ diskfs_set_node_atime (dp);
- for (curoff = buf;
+ for (curoff = buf;
curoff < buf + dp->dn_stat.st_size;
curoff += read_disk_entry (entry->d_reclen))
{
@@ -720,19 +766,17 @@ diskfs_dirempty(struct node *dp,
|| (entry->d_name[1] != '.'
&& entry->d_name[1] != '\0')))
{
- vm_deallocate (mach_task_self (), buf, dp->dn_stat.st_size);
- if (!diskfs_check_readonly ())
- dp->dn_set_atime = 1;
+ munmap ((caddr_t) buf, dp->dn_stat.st_size);
+ diskfs_set_node_atime (dp);
if (diskfs_synchronous)
diskfs_node_update (dp, 1);
return 0;
}
}
- if (!diskfs_check_readonly ())
- dp->dn_set_atime = 1;
+ diskfs_set_node_atime (dp);
if (diskfs_synchronous)
diskfs_node_update (dp, 1);
- vm_deallocate (mach_task_self (), buf, dp->dn_stat.st_size);
+ munmap ((caddr_t) buf, dp->dn_stat.st_size);
return 1;
}
@@ -743,7 +787,7 @@ diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
if (ds->type != LOOKUP)
{
assert (ds->mapbuf);
- vm_deallocate (mach_task_self (), ds->mapbuf, ds->mapextent);
+ munmap ((caddr_t) ds->mapbuf, ds->mapextent);
ds->type = LOOKUP;
}
return 0;
@@ -756,7 +800,7 @@ diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
static error_t
count_dirents (struct node *dp, int nb, char *buf)
{
- int amt;
+ size_t amt;
char *offinblk;
struct directory_entry *entry;
int count = 0;
@@ -764,12 +808,12 @@ count_dirents (struct node *dp, int nb, char *buf)
assert (dp->dn->dirents);
assert ((nb + 1) * DIRBLKSIZ <= dp->dn_stat.st_size);
-
+
err = diskfs_node_rdwr (dp, buf, nb * DIRBLKSIZ, DIRBLKSIZ, 0, 0, &amt);
if (err)
return err;
assert (amt == DIRBLKSIZ);
-
+
for (offinblk = buf;
offinblk < buf + DIRBLKSIZ;
offinblk += read_disk_entry (entry->d_reclen))
@@ -778,7 +822,7 @@ count_dirents (struct node *dp, int nb, char *buf)
if (entry->d_ino)
count++;
}
-
+
assert (dp->dn->dirents[nb] == -1 || dp->dn->dirents[nb] == count);
dp->dn->dirents[nb] = count;
return 0;
@@ -787,11 +831,11 @@ count_dirents (struct node *dp, int nb, char *buf)
/* Implement the disikfs_get_directs callback as described in
<hurd/diskfs.h>. */
error_t
-diskfs_get_directs (struct node *dp,
- int entry,
+diskfs_get_directs (struct node *dp,
+ int entry,
int nentries,
char **data,
- u_int *datacnt,
+ size_t *datacnt,
vm_size_t bufsiz,
int *amt)
{
@@ -806,9 +850,9 @@ diskfs_get_directs (struct node *dp,
char *datap;
struct directory_entry *entryp;
int allocsize;
- int checklen;
+ size_t checklen;
struct dirent *userp;
-
+
nblks = dp->dn_stat.st_size/DIRBLKSIZ;
if (!dp->dn->dirents)
@@ -818,15 +862,6 @@ diskfs_get_directs (struct node *dp,
dp->dn->dirents[i] = -1;
}
- /* Allocate enough space to hold the maximum we might return */
- if (!bufsiz || bufsiz > dp->dn_stat.st_size)
- allocsize = round_page (dp->dn_stat.st_size);
- else
- allocsize = round_page (bufsiz);
-
- if (allocsize > *datacnt)
- vm_allocate (mach_task_self (), (vm_address_t *) data, allocsize, 1);
-
/* Scan through the entries to find ENTRY. If we encounter
a -1 in the process then stop to fill it. When we run
off the end, ENTRY is too big. */
@@ -847,17 +882,29 @@ diskfs_get_directs (struct node *dp,
break;
curentry += dp->dn->dirents[blkno];
-
+
bufvalid = 0;
}
-
+
if (blkno == nblks)
{
+ /* We reached the end of the directory without seeing ENTRY.
+ This is treated as an EOF condition, meaning we return
+ success with empty results. */
*datacnt = 0;
*amt = 0;
return 0;
}
+ /* Allocate enough space to hold the maximum we might return */
+ if (!bufsiz || bufsiz > dp->dn_stat.st_size)
+ allocsize = round_page (dp->dn_stat.st_size);
+ else
+ allocsize = round_page (bufsiz);
+
+ if (allocsize > *datacnt)
+ *data = mmap (0, allocsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+
/* Set bufp appropriately */
bufp = buf;
if (curentry != entry)
@@ -873,15 +920,15 @@ diskfs_get_directs (struct node *dp,
assert (checklen == DIRBLKSIZ);
bufvalid = 1;
}
- for (i = 0, bufp = buf;
- i < entry - curentry && bufp - buf < DIRBLKSIZ;
+ for (i = 0, bufp = buf;
+ i < entry - curentry && bufp - buf < DIRBLKSIZ;
(bufp
- += read_disk_entry (((struct directory_entry *)bufp)->d_reclen)),
+ += read_disk_entry (((struct directory_entry *)bufp)->d_reclen)),
i++)
;
/* Make sure we didn't run off the end. */
assert (bufp - buf < DIRBLKSIZ);
- }
+ }
i = 0;
datap = *data;
@@ -893,7 +940,7 @@ diskfs_get_directs (struct node *dp,
{
if (!bufvalid)
{
- err = diskfs_node_rdwr (dp, buf, blkno * DIRBLKSIZ, DIRBLKSIZ,
+ err = diskfs_node_rdwr (dp, buf, blkno * DIRBLKSIZ, DIRBLKSIZ,
0, 0, &checklen);
if (err)
return err;
@@ -924,17 +971,16 @@ diskfs_get_directs (struct node *dp,
bufvalid = 0;
}
}
-
+
/* We've copied all we can. If we allocated our own array
but didn't fill all of it, then free whatever memory we didn't use. */
if (allocsize > *datacnt)
{
if (round_page (datap - *data) < allocsize)
- vm_deallocate (mach_task_self (),
- (vm_address_t) (*data + round_page (datap - *data)),
- allocsize - round_page (datap - *data));
+ munmap (*data + round_page (datap - *data),
+ allocsize - round_page (datap - *data));
}
-
+
/* Set variables for return */
*datacnt = datap - *data;
*amt = i;
diff --git a/ufs/dir.h b/ufs/dir.h
index 2b1e3469..5730ef44 100644
--- a/ufs/dir.h
+++ b/ufs/dir.h
@@ -70,6 +70,7 @@
* dp->d_ino set to 0.
*/
#define DIRBLKSIZ DEV_BSIZE
+#undef MAXNAMLEN
#define MAXNAMLEN 255
/* Don't call this struct DIRECT because the library defines that
@@ -90,13 +91,13 @@ struct directory_entry {
/* Return the namlen from a struct direct, paying attention to whether
this filesystem supports the type extension */
#if (BYTE_ORDER == LITTLE_ENDIAN)
-#define DIRECT_NAMLEN(dp) (direct_symlink_extension || swab_disk \
- ? (dp)->d_namlen \
- : (dp)->d_type)
+#define DIRECT_NAMLEN(dp) (*(direct_symlink_extension || swab_disk \
+ ? &(dp)->d_namlen \
+ : &(dp)->d_type))
#else
-#define DIRECT_NAMLEN(dp) (!direct_symlink_extension && swab_disk \
- ? (dp)->d_type \
- : (dp)->d_namlen)
+#define DIRECT_NAMLEN(dp) (*(!direct_symlink_extension && swab_disk \
+ ? &(dp)->d_type \
+ : &(dp)->d_namlen))
#endif
/*
diff --git a/ufs/hyper.c b/ufs/hyper.c
index e4f58249..ece327a2 100644
--- a/ufs/hyper.c
+++ b/ufs/hyper.c
@@ -1,5 +1,5 @@
/* Fetching and storing the hypermetadata (superblock and cg summary info).
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 95, 96, 97, 98, 1999 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
@@ -19,12 +19,13 @@
#include <string.h>
#include <stdio.h>
#include <error.h>
+#include <hurd/store.h>
static int ufs_clean; /* fs clean before we started writing? */
static int oldformat;
-vm_address_t zeroblock;
+void *zeroblock;
struct fs *sblock;
struct csum *csum;
@@ -33,7 +34,7 @@ void
swab_sblock (struct fs *sblock)
{
int i, j;
-
+
sblock->fs_sblkno = swab_long (sblock->fs_sblkno);
sblock->fs_cblkno = swab_long (sblock->fs_cblkno);
sblock->fs_iblkno = swab_long (sblock->fs_iblkno);
@@ -107,24 +108,24 @@ swab_sblock (struct fs *sblock)
else
for (i = 0; i < sblock->fs_cpc; i++)
for (j = 0; j < sblock->fs_nrpos; j++)
- fs_postbl(sblock, j)[i]
+ fs_postbl(sblock, j)[i]
= swab_short (fs_postbl (sblock, j)[i]);
/* The rot table is all chars */
}
-
+
void
swab_csums (struct csum *csum)
{
int i;
-
+
for (i = 0; i < sblock->fs_ncg; i++)
{
csum[i].cs_ndir = swab_long (csum[i].cs_ndir);
csum[i].cs_nbfree = swab_long (csum[i].cs_nbfree);
csum[i].cs_nifree = swab_long (csum[i].cs_nifree);
csum[i].cs_nffree = swab_long (csum[i].cs_nffree);
- }
+ }
}
void
@@ -137,7 +138,7 @@ get_hypermetadata (void)
/* Free previous values. */
if (zeroblock)
- vm_deallocate (mach_task_self (), zeroblock, sblock->fs_bsize);
+ munmap ((caddr_t) zeroblock, sblock->fs_bsize);
if (csum)
free (csum);
@@ -190,13 +191,13 @@ get_hypermetadata (void)
{
error (0, 0,
"%s: warning: FILESYSTEM NOT UNMOUNTED CLEANLY; PLEASE fsck",
- diskfs_device_arg);
+ diskfs_disk_name);
if (! diskfs_readonly)
{
diskfs_readonly = 1;
error (0, 0,
"%s: MOUNTED READ-ONLY; MUST USE `fsysopts --writable'",
- diskfs_device_arg);
+ diskfs_disk_name);
}
}
@@ -247,18 +248,16 @@ get_hypermetadata (void)
if (swab_disk)
swab_csums (csum);
- if ((diskfs_device_size << diskfs_log2_device_block_size)
- < sblock->fs_size * sblock->fs_fsize)
+ if (store->size < sblock->fs_size * sblock->fs_fsize)
{
fprintf (stderr,
- "Disk size (%ld) less than necessary "
+ "Disk size (%Ld) less than necessary "
"(superblock says we need %ld)\n",
- diskfs_device_size << diskfs_log2_device_block_size,
- sblock->fs_size * sblock->fs_fsize);
+ store->size, sblock->fs_size * sblock->fs_fsize);
exit (1);
}
- vm_allocate (mach_task_self (), &zeroblock, sblock->fs_bsize, 1);
+ zeroblock = mmap (0, sblock->fs_bsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
/* If the filesystem has new features in it, don't pay attention to
the user's request not to use them. */
@@ -276,11 +275,9 @@ get_hypermetadata (void)
taken from ordinary data blocks and might not be an even number
of pages; in that case writing it through the pager would nuke whatever
pages came after it on the disk and were backed by file pagers. */
-void
+error_t
diskfs_set_hypermetadata (int wait, int clean)
{
- vm_address_t buf;
- vm_size_t bufsize;
error_t err;
spin_lock (&alloclock);
@@ -289,21 +286,41 @@ diskfs_set_hypermetadata (int wait, int clean)
{
/* Copy into a page-aligned buffer to avoid bugs in kernel device
code. */
-
- bufsize = round_page (fragroundup (sblock, sblock->fs_cssize));
-
- err = diskfs_device_read_sync (fsbtodb (sblock, sblock->fs_csaddr),
- &buf, bufsize);
- if (!err)
+ void *buf = 0;
+ size_t read = 0;
+ size_t bufsize = round_page (fragroundup (sblock, sblock->fs_cssize));
+
+ err = store_read (store,
+ fsbtodb (sblock, sblock->fs_csaddr)
+ << log2_dev_blocks_per_dev_bsize,
+ bufsize, &buf, &read);
+ if (err)
+ return err;
+ else if (read != bufsize)
+ err = EIO;
+ else
{
- bcopy (csum, (void *) buf, sblock->fs_cssize);
+ size_t wrote;
+ bcopy (csum, buf, sblock->fs_cssize);
if (swab_disk)
swab_csums ((struct csum *)buf);
- diskfs_device_write_sync (fsbtodb (sblock, sblock->fs_csaddr),
- buf, bufsize);
- csum_dirty = 0;
- vm_deallocate (mach_task_self (), buf, bufsize);
+ err = store_write (store,
+ fsbtodb (sblock, sblock->fs_csaddr)
+ << log2_dev_blocks_per_dev_bsize,
+ buf, bufsize, &wrote);
+ if (!err && wrote != bufsize)
+ err = EIO;
}
+
+ munmap (buf, read);
+
+ if (err)
+ {
+ spin_unlock (&alloclock);
+ return err;
+ }
+
+ csum_dirty = 0;
}
if (clean && ufs_clean && !sblock->fs_clean)
@@ -326,6 +343,7 @@ diskfs_set_hypermetadata (int wait, int clean)
copy_sblock ();
sync_disk (wait);
+ return 0;
}
/* Copy the sblock into the disk */
@@ -376,10 +394,9 @@ copy_sblock ()
void
diskfs_readonly_changed (int readonly)
{
- vm_protect (mach_task_self (),
- (vm_address_t)disk_image,
- diskfs_device_size << diskfs_log2_device_block_size,
- 0, VM_PROT_READ | (readonly ? 0 : VM_PROT_WRITE));
+ (*(readonly ? store_set_flags : store_clear_flags)) (store, STORE_READONLY);
+
+ mprotect (disk_image, store->size, PROT_READ | (readonly ? 0 : PROT_WRITE));
if (readonly)
{
diff --git a/ufs/inode.c b/ufs/inode.c
index 640e6b6f..77a45edb 100644
--- a/ufs/inode.c
+++ b/ufs/inode.c
@@ -1,5 +1,7 @@
/* Inode management routines
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2007
+ 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
@@ -20,6 +22,8 @@
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
+#include <fcntl.h>
+#include <hurd/store.h>
#define INOHSZ 512
#if ((INOHSZ&(INOHSZ-1)) == 0)
@@ -42,10 +46,10 @@ inode_init ()
nodehash[n] = 0;
}
-/* Fetch inode INUM, set *NPP to the node structure;
+/* Fetch inode INUM, set *NPP to the node structure;
gain one user reference and lock the node. */
-error_t
-diskfs_cached_lookup (int inum, struct node **npp)
+error_t
+diskfs_cached_lookup (ino_t inum, struct node **npp)
{
struct disknode *dn;
struct node *np;
@@ -68,6 +72,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
dn->number = inum;
dn->dirents = 0;
+ dn->dir_idx = 0;
rwlock_init (&dn->allocptrlock);
dn->dirty = 0;
@@ -85,7 +90,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
spin_unlock (&diskfs_node_refcnt_lock);
err = read_disknode (np);
-
+
if (!diskfs_check_readonly () && !np->dn_stat.st_gen)
{
spin_lock (&gennumberlock);
@@ -95,7 +100,7 @@ diskfs_cached_lookup (int inum, struct node **npp)
spin_unlock (&gennumberlock);
np->dn_set_ctime = 1;
}
-
+
if (err)
return err;
else
@@ -111,13 +116,13 @@ struct node *
ifind (ino_t inum)
{
struct node *np;
-
+
spin_lock (&diskfs_node_refcnt_lock);
for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
{
if (np->dn->number != inum)
continue;
-
+
assert (np->references);
spin_unlock (&diskfs_node_refcnt_lock);
return np;
@@ -127,7 +132,7 @@ ifind (ino_t inum)
/* The last reference to a node has gone away; drop
it from the hash table and clean all state in the dn structure. */
-void
+void
diskfs_node_norefs (struct node *np)
{
*np->dn->hprevp = np->dn->hnext;
@@ -155,7 +160,7 @@ diskfs_lost_hardrefs (struct node *np)
#ifdef notanymore
struct port_info *pi;
struct pager *p;
-
+
/* Check and see if there is a pager which has only
one reference (ours). If so, then drop that reference,
breaking the cycle. The complexity in this routine
@@ -167,17 +172,17 @@ diskfs_lost_hardrefs (struct node *np)
pi = (struct port_info *) np->dn->fileinfo->p;
if (pi->refcnt == 1)
{
-
+
/* The only way to get a new reference to the pager
in this state is to call diskfs_get_filemap; this
can't happen as long as we hold NP locked. So
we can safely unlock _libports_portrefcntlock for
the following call. */
spin_unlock (&_libports_portrefcntlock);
-
+
/* Right now the node is locked with no hard refs;
- this is an anomolous situation. Before messing with
- the reference count on the file pager, we have to
+ this is an anomalous situation. Before messing with
+ the reference count on the file pager, we have to
give ourselves a reference back so that we are really
allowed to hold the lock. Then we can do the
unreference. */
@@ -209,53 +214,41 @@ diskfs_new_hardrefs (struct node *np)
static error_t
read_disknode (struct node *np)
{
- static int fsid, fsidset;
struct stat *st = &np->dn_stat;
struct dinode *di = dino (np->dn->number);
error_t err;
-
+
err = diskfs_catch_exception ();
if (err)
return err;
- np->istranslated = !! di->di_trans;
-
- if (!fsidset)
- {
- fsid = getpid ();
- fsidset = 1;
- }
-
st->st_fstype = FSTYPE_UFS;
- st->st_fsid = fsid;
+ st->st_fsid = getpid (); /* This call is very cheap. */
st->st_ino = np->dn->number;
st->st_gen = read_disk_entry (di->di_gen);
st->st_rdev = read_disk_entry(di->di_rdev);
- st->st_mode = (read_disk_entry (di->di_model)
- | (read_disk_entry (di->di_modeh) << 16));
+ st->st_mode = (((read_disk_entry (di->di_model)
+ | (read_disk_entry (di->di_modeh) << 16))
+ & ~S_ITRANS)
+ | (di->di_trans ? S_IPTRANS : 0));
st->st_nlink = read_disk_entry (di->di_nlink);
st->st_size = read_disk_entry (di->di_size);
-#ifdef notyet
- st->st_atimespec = di->di_atime;
- st->st_mtimespec = di->di_mtime;
- st->st_ctimespec = di->di_ctime;
-#else
- st->st_atime = read_disk_entry (di->di_atime.tv_sec);
- st->st_atime_usec = read_disk_entry (di->di_atime.tv_nsec) / 1000;
- st->st_mtime = read_disk_entry (di->di_mtime.tv_sec);
- st->st_mtime_usec = read_disk_entry (di->di_mtime.tv_nsec) / 1000;
- st->st_ctime = read_disk_entry (di->di_ctime.tv_sec);
- st->st_ctime_usec = read_disk_entry (di->di_ctime.tv_nsec) / 1000;
-#endif
+ st->st_atim.tv_sec = read_disk_entry (di->di_atime.tv_sec);
+ st->st_atim.tv_nsec = read_disk_entry (di->di_atime.tv_nsec);
+ st->st_mtim.tv_sec = read_disk_entry (di->di_mtime.tv_sec);
+ st->st_mtim.tv_nsec = read_disk_entry (di->di_mtime.tv_nsec);
+ st->st_ctim.tv_sec = read_disk_entry (di->di_ctime.tv_sec);
+ st->st_ctim.tv_nsec = read_disk_entry (di->di_ctime.tv_nsec);
st->st_blksize = sblock->fs_bsize;
st->st_blocks = read_disk_entry (di->di_blocks);
st->st_flags = read_disk_entry (di->di_flags);
-
+
if (sblock->fs_inodefmt < FS_44INODEFMT)
{
st->st_uid = read_disk_entry (di->di_ouid);
st->st_gid = read_disk_entry (di->di_ogid);
- st->st_author = 0;
+ st->st_author = st->st_uid;
+ np->author_tracks_uid = 1;
}
else
{
@@ -270,8 +263,8 @@ read_disknode (struct node *np)
if (!S_ISBLK (st->st_mode) && !S_ISCHR (st->st_mode))
st->st_rdev = 0;
- if (S_ISLNK (st->st_mode)
- && direct_symlink_extension
+ if (S_ISLNK (st->st_mode)
+ && direct_symlink_extension
&& st->st_size < sblock->fs_maxsymlinklen)
np->allocsize = 0;
else
@@ -297,14 +290,25 @@ error_t diskfs_node_reload (struct node *node)
return 0;
}
+/* Return 0 if NP's author can be changed to AUTHOR; otherwise return an
+ error code. */
+error_t
+diskfs_validate_author_change (struct node *np, uid_t author)
+{
+ if (compat_mode == COMPAT_GNU)
+ return 0;
+ else
+ /* For non-hurd filesystems, the author & owner are the same. */
+ return (author == np->dn_stat.st_uid) ? 0 : EINVAL;
+}
+
static void
write_node (struct node *np)
{
struct stat *st = &np->dn_stat;
struct dinode *di = dino (np->dn->number);
error_t err;
-
- assert (!np->dn_set_ctime && !np->dn_set_atime && !np->dn_set_mtime);
+
if (np->dn_stat_dirty)
{
assert (!diskfs_readonly);
@@ -312,9 +316,9 @@ write_node (struct node *np)
err = diskfs_catch_exception ();
if (err)
return;
-
+
write_disk_entry (di->di_gen, st->st_gen);
-
+
if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode))
write_disk_entry (di->di_rdev, st->st_rdev);
@@ -323,12 +327,13 @@ write_node (struct node *np)
if (compat_mode == COMPAT_GNU)
{
- write_disk_entry (di->di_model, st->st_mode & 0xffff);
- write_disk_entry (di->di_modeh, (st->st_mode >> 16) & 0xffff);
+ mode_t mode = st->st_mode & ~S_ITRANS;
+ write_disk_entry (di->di_model, mode & 0xffff);
+ write_disk_entry (di->di_modeh, (mode >> 16) & 0xffff);
}
- else
+ else
{
- write_disk_entry (di->di_model, st->st_mode & 0xffff);
+ write_disk_entry (di->di_model, st->st_mode & 0xffff & ~S_ITRANS);
di->di_modeh = 0;
}
@@ -337,7 +342,7 @@ write_node (struct node *np)
write_disk_entry (di->di_uid, st->st_uid);
write_disk_entry (di->di_gid, st->st_gid);
}
-
+
if (sblock->fs_inodefmt < FS_44INODEFMT)
{
write_disk_entry (di->di_ouid, st->st_uid & 0xffff);
@@ -348,49 +353,43 @@ write_node (struct node *np)
write_disk_entry (di->di_nlink, st->st_nlink);
write_disk_entry (di->di_size, st->st_size);
-#ifdef notyet
- di->di_atime = st->st_atimespec;
- di->di_mtime = st->st_mtimespec;
- di->di_ctime = st->st_ctimespec;
-#else
- write_disk_entry (di->di_atime.tv_sec, st->st_atime);
- write_disk_entry (di->di_atime.tv_nsec, st->st_atime_usec * 1000);
- write_disk_entry (di->di_mtime.tv_sec, st->st_mtime);
- write_disk_entry (di->di_mtime.tv_nsec, st->st_mtime_usec * 1000);
- write_disk_entry (di->di_ctime.tv_sec, st->st_ctime);
- write_disk_entry (di->di_ctime.tv_nsec, st->st_ctime_usec * 1000);
-#endif
+ write_disk_entry (di->di_atime.tv_sec, st->st_atim.tv_sec);
+ write_disk_entry (di->di_atime.tv_nsec, st->st_atim.tv_nsec);
+ write_disk_entry (di->di_mtime.tv_sec, st->st_mtim.tv_sec);
+ write_disk_entry (di->di_mtime.tv_nsec, st->st_mtim.tv_nsec);
+ write_disk_entry (di->di_ctime.tv_sec, st->st_ctim.tv_sec);
+ write_disk_entry (di->di_ctime.tv_nsec, st->st_ctim.tv_nsec);
write_disk_entry (di->di_blocks, st->st_blocks);
write_disk_entry (di->di_flags, st->st_flags);
-
+
diskfs_end_catch_exception ();
np->dn_stat_dirty = 0;
record_poke (di, sizeof (struct dinode));
}
-}
+}
/* See if we should create a symlink by writing it directly into
the block pointer array. Returning EINVAL tells diskfs to do it
the usual way. */
static error_t
-create_symlink_hook (struct node *np, char *target)
+create_symlink_hook (struct node *np, const char *target)
{
int len = strlen (target);
error_t err;
struct dinode *di;
-
+
if (!direct_symlink_extension)
return EINVAL;
-
+
assert (compat_mode != COMPAT_BSD42);
if (len >= sblock->fs_maxsymlinklen)
return EINVAL;
-
+
err = diskfs_catch_exception ();
if (err)
return err;
-
+
di = dino (np->dn->number);
bcopy (target, di->di_shortlink, len);
np->dn_stat.st_size = len;
@@ -401,29 +400,28 @@ create_symlink_hook (struct node *np, char *target)
diskfs_end_catch_exception ();
return 0;
}
-error_t (*diskfs_create_symlink_hook)(struct node *, char *)
+error_t (*diskfs_create_symlink_hook)(struct node *, const char *)
= create_symlink_hook;
/* Check if this symlink is stored directly in the block pointer array.
Returning EINVAL tells diskfs to do it the usual way. */
-static error_t
+static error_t
read_symlink_hook (struct node *np,
char *buf)
{
error_t err;
-
- if (!direct_symlink_extension
+
+ if (!direct_symlink_extension
|| np->dn_stat.st_size >= sblock->fs_maxsymlinklen)
return EINVAL;
err = diskfs_catch_exception ();
if (err)
return err;
-
+
bcopy ((dino (np->dn->number))->di_shortlink, buf, np->dn_stat.st_size);
- if (! diskfs_check_readonly ())
- np->dn_set_atime = 1;
+ diskfs_set_node_atime (np);
diskfs_end_catch_exception ();
return 0;
@@ -439,7 +437,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
struct item *i;
error_t err;
int n;
-
+
/* Acquire a reference on all the nodes in the hash table
and enter them into a list on the stack. */
spin_lock (&diskfs_node_refcnt_lock);
@@ -479,10 +477,10 @@ write_all_disknodes ()
write_node (np);
return 0;
}
-
+
diskfs_node_iterate (helper);
}
-
+
void
diskfs_write_disknode (struct node *np, int wait)
{
@@ -497,23 +495,27 @@ error_t
diskfs_set_statfs (struct statfs *st)
{
st->f_type = FSTYPE_UFS;
- st->f_bsize = sblock->fs_bsize;
- st->f_blocks = sblock->fs_dsize * sblock->fs_frag;
+ st->f_bsize = sblock->fs_fsize;
+ st->f_blocks = sblock->fs_dsize;
st->f_bfree = (sblock->fs_cstotal.cs_nbfree * sblock->fs_frag
+ sblock->fs_cstotal.cs_nffree);
st->f_bavail = ((sblock->fs_dsize * (100 - sblock->fs_minfree) / 100)
- (sblock->fs_dsize - st->f_bfree));
+ if (st->f_bfree < ((sblock->fs_dsize * (100 - sblock->fs_minfree) / 100)))
+ st->f_bavail = 0;
st->f_files = sblock->fs_ncg * sblock->fs_ipg - 2; /* not 0 or 1 */
st->f_ffree = sblock->fs_cstotal.cs_nifree;
st->f_fsid = getpid ();
st->f_namelen = 0;
+ st->f_favail = st->f_ffree;
+ st->f_frsize = sblock->fs_fsize;
return 0;
}
/* Implement the diskfs_set_translator callback from the diskfs
library; see <hurd/diskfs.h> for the interface description. */
error_t
-diskfs_set_translator (struct node *np, char *name, u_int namelen,
+diskfs_set_translator (struct node *np, const char *name, u_int namelen,
struct protid *cred)
{
daddr_t blkno;
@@ -530,10 +532,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen,
err = diskfs_catch_exception ();
if (err)
return err;
-
+
di = dino (np->dn->number);
blkno = read_disk_entry (di->di_trans);
-
+
if (namelen && !blkno)
{
/* Allocate block for translator */
@@ -554,10 +556,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen,
di->di_trans = 0;
record_poke (di, sizeof (struct dinode));
np->dn_stat.st_blocks -= btodb (sblock->fs_bsize);
- np->istranslated = 0;
+ np->dn_stat.st_mode &= ~S_IPTRANS;
np->dn_set_ctime = 1;
}
-
+
if (namelen)
{
bcopy (&namelen, buf, sizeof (u_int));
@@ -566,10 +568,10 @@ diskfs_set_translator (struct node *np, char *name, u_int namelen,
bcopy (buf, disk_image + fsaddr (sblock, blkno), sblock->fs_bsize);
sync_disk_blocks (blkno, sblock->fs_bsize, 1);
- np->istranslated = 1;
+ np->dn_stat.st_mode |= S_IPTRANS;
np->dn_set_ctime = 1;
}
-
+
diskfs_end_catch_exception ();
return err;
}
@@ -582,7 +584,7 @@ diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
error_t err;
daddr_t blkno;
u_int datalen;
- void *transloc;
+ const void *transloc;
err = diskfs_catch_exception ();
if (err)
@@ -591,10 +593,17 @@ diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
blkno = read_disk_entry ((dino (np->dn->number))->di_trans);
assert (blkno);
transloc = disk_image + fsaddr (sblock, blkno);
-
+
datalen = *(u_int *)transloc;
- *namep = malloc (datalen);
- bcopy (transloc + sizeof (u_int), *namep, datalen);
+ if (datalen > sblock->fs_bsize - sizeof (u_int))
+ err = EFTYPE;
+ else
+ {
+ *namep = malloc (datalen);
+ if (*namep == NULL)
+ err = ENOMEM;
+ memcpy (*namep, transloc + sizeof (u_int), datalen);
+ }
diskfs_end_catch_exception ();
@@ -619,108 +628,76 @@ diskfs_shutdown_soft_ports ()
offset into inode block holding inode (4 bytes) */
error_t
diskfs_S_file_get_storage_info (struct protid *cred,
- int *class,
- off_t **addresses,
- u_int *naddresses,
- size_t *block_size,
- char *storage_name,
- mach_port_t *storage_port,
- mach_msg_type_name_t *storage_port_type,
- char **storage_data,
- u_int *storage_data_len,
- int *flags)
+ mach_port_t **ports,
+ mach_msg_type_name_t *ports_type,
+ mach_msg_type_number_t *num_ports,
+ int **ints, mach_msg_type_number_t *num_ints,
+ off_t **offsets,
+ mach_msg_type_number_t *num_offsets,
+ char **data, mach_msg_type_number_t *data_len)
{
error_t err;
struct node *np;
- int i;
- struct dinode *di;
- void *cp;
-
+ struct store *file_store;
+ struct store_run runs[NDADDR];
+ size_t num_runs = 0;
+
+ if (! cred)
+ return EOPNOTSUPP;
+
np = cred->po->np;
mutex_lock (&np->lock);
-
+
/* See if this file fits in the direct block pointers. If not, punt
for now. (Reading indir blocks is a pain, and I'm postponing
pain.) XXX */
-
if (np->allocsize > NDADDR * sblock->fs_bsize)
{
mutex_unlock (&np->lock);
return EINVAL;
}
-
- if (*naddresses < NDADDR * 2)
- vm_allocate (mach_task_self (), (vm_address_t *) addresses,
- sizeof (int) * NDADDR * 2, 1);
- else
- bzero (addresses, *naddresses * 2 * sizeof (int));
- *naddresses = NDADDR * 2;
-
- if (*storage_data_len < 4 * sizeof (int))
- vm_allocate (mach_task_self (), (vm_address_t *) storage_data,
- sizeof (int) * 4, 1);
- *storage_data_len = 4 * sizeof (int);
- di = dino (np->dn->number);
-
err = diskfs_catch_exception ();
- if (err)
- {
- mutex_unlock (&np->lock);
- return err;
- }
-
- /* Copy the block pointers */
+ if (! err)
+ if (!direct_symlink_extension
+ || np->dn_stat.st_size >= sblock->fs_maxsymlinklen
+ || !S_ISLNK (np->dn_stat.st_mode))
+ /* Copy the block pointers */
+ {
+ int i;
+ struct store_run *run = runs;
+ struct dinode *di = dino (np->dn->number);
+
+ for (i = 0; i < NDADDR; i++)
+ {
+ store_offset_t start = fsbtodb (sblock, read_disk_entry (di->di_db[i]));
+ store_offset_t length =
+ (((i + 1) * sblock->fs_bsize > np->allocsize)
+ ? np->allocsize - i * sblock->fs_bsize
+ : sblock->fs_bsize);
+ start <<= log2_dev_blocks_per_dev_bsize;
+ length <<= log2_dev_blocks_per_dev_bsize;
+ if (num_runs == 0 || run->start + run->length != start)
+ *run++ = (struct store_run){ start, length };
+ else
+ run->length += length;
+ }
+ }
+ diskfs_end_catch_exception ();
- if (!direct_symlink_extension
- || np->dn_stat.st_size >= sblock->fs_maxsymlinklen
- || !S_ISLNK (np->dn_stat.st_mode))
+ mutex_unlock (&np->lock);
+
+ if (! err)
+ err = store_clone (store, &file_store);
+ if (! err)
{
- for (i = 0; i < NDADDR; i++)
- {
- (*addresses)[2 * i] = fsbtodb (sblock,
- read_disk_entry (di->di_db[i]));
- if ((i + 1) * sblock->fs_bsize > np->allocsize)
- (*addresses)[2 * i + 1] = np->allocsize - i * sblock->fs_bsize;
- else
- (*addresses)[2 * i + 1] = sblock->fs_bsize;
- }
+ err = store_remap (file_store, runs, num_runs, &file_store);
+ if (! err)
+ err = store_return (file_store, ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+ store_free (file_store);
}
+ *ports_type = MACH_MSG_TYPE_COPY_SEND;
- /* Fill in the aux data */
- cp = *storage_data;
-
- *(int *)cp = htonl (np->dn->number);
- cp += sizeof (int);
-
- *(int *)cp = htonl (di->di_trans);
- cp += sizeof (int);
-
- *(int *)cp = htonl (fsbtodb (sblock, ino_to_fsba (sblock, np->dn->number)));
- cp += sizeof (int);
-
- *(int *)cp = htonl (ino_to_fsbo (sblock, np->dn->number)
- * sizeof (struct dinode));
-
-
- diskfs_end_catch_exception ();
-
- *class = STORAGE_DEVICE;
- *flags = 0;
- *block_size = DEV_BSIZE;
-
- if (diskfs_device_name)
- strcpy (storage_name, diskfs_device_name);
-
- if (diskfs_isuid (0, cred))
- *storage_port = diskfs_device;
- else
- *storage_port = MACH_PORT_NULL;
- *storage_port_type = MACH_MSG_TYPE_COPY_SEND;
-
- mutex_unlock (&np->lock);
-
- return 0;
+ return err;
}
-
-
diff --git a/ufs/main.c b/ufs/main.c
index 353a1852..242107f4 100644
--- a/ufs/main.c
+++ b/ufs/main.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994,95,96,97,98,99,2002 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
@@ -26,9 +26,19 @@
#include <stdlib.h>
#include <string.h>
#include <argz.h>
+#include <argp.h>
+#include <hurd/store.h>
struct node *diskfs_root_node;
+struct store *store = 0;
+struct store_parsed *store_parsed = 0;
+
+char *diskfs_disk_name = 0;
+
+/* Number of device blocks per DEV_BSIZE block. */
+unsigned log2_dev_blocks_per_dev_bsize = 0;
+
/* Set diskfs_root_node to the root inode. */
static void
warp_root (void)
@@ -66,7 +76,7 @@ options[] =
{0}
};
-/* Parse a command line option. */
+/* Parse a ufs-specific command line option. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -101,6 +111,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input;
state->hook = (void *)compat_mode; break;
case ARGP_KEY_SUCCESS:
compat_mode = (enum compat_mode)state->hook; break;
@@ -112,37 +123,34 @@ parse_opt (int key, char *arg, struct argp_state *state)
}
/* Add our startup arguments to the standard diskfs set. */
-static const struct argp *startup_parents[] = { &diskfs_std_device_startup_argp, 0};
-static struct argp startup_argp = {options, parse_opt, 0, 0, startup_parents};
+static const struct argp_child startup_children[] =
+ {{&diskfs_store_startup_argp}, {0}};
+static struct argp startup_argp = {options, parse_opt, 0, 0, startup_children};
/* Similarly at runtime. */
-static const struct argp *runtime_parents[] = {&diskfs_std_runtime_argp, 0};
-static struct argp runtime_argp = {options, parse_opt, 0, 0, runtime_parents};
+static const struct argp_child runtime_children[] =
+ {{&diskfs_std_runtime_argp}, {0}};
+static struct argp runtime_argp = {options, parse_opt, 0, 0, runtime_children};
struct argp *diskfs_runtime_argp = (struct argp *)&runtime_argp;
/* Override the standard diskfs routine so we can add our own output. */
error_t
-diskfs_get_options (char **argz, unsigned *argz_len)
+diskfs_append_args (char **argz, size_t *argz_len)
{
error_t err;
- *argz = 0;
- *argz_len = 0;
-
/* Get the standard things. */
err = diskfs_append_std_options (argz, argz_len);
if (!err && compat_mode != COMPAT_GNU)
- {
- err =
- argz_add (argz, argz_len,
- ((compat_mode == COMPAT_BSD42)
- ? "--compat=4.2"
- : "--compat=4.4"));
- if (err)
- free (argz); /* Deallocate what diskfs returned. */
- }
+ err = argz_add (argz, argz_len,
+ ((compat_mode == COMPAT_BSD42)
+ ? "--compat=4.2"
+ : "--compat=4.4"));
+
+ if (! err)
+ err = store_parsed_append_args (store_parsed, argz, argz_len);
return err;
}
@@ -150,55 +158,28 @@ diskfs_get_options (char **argz, unsigned *argz_len)
int
main (int argc, char **argv)
{
- error_t err;
- off_t disk_size;
mach_port_t bootstrap;
- argp_parse (&startup_argp, argc, argv, 0, 0, 0);
-
- /* This must come after the args have been parsed, as this is where the
- host priv ports are set for booting. */
- diskfs_console_stdio ();
+ /* Initialize the diskfs library, parse arguments, and open the store.
+ This starts the first diskfs thread for us. */
+ store = diskfs_init_main (&startup_argp, argc, argv,
+ &store_parsed, &bootstrap);
- if (diskfs_boot_flags)
- {
- /* We are the bootstrap filesystem. */
- bootstrap = MACH_PORT_NULL;
- diskfs_use_mach_device = 1;
- compat_mode = COMPAT_GNU;
- }
- else
- {
- task_get_bootstrap_port (mach_task_self (), &bootstrap);
- if (bootstrap == MACH_PORT_NULL)
- error (2, 0, "Must be started as a translator");
- }
-
- /* Initialize the diskfs library. Must come before any other diskfs call. */
- err = diskfs_init_diskfs ();
- if (err)
- error (4, err, "init");
+ if (store->block_size > DEV_BSIZE)
+ error (4, 0, "%s: Bad device block size %zd (should be <= %d)",
+ diskfs_disk_name, store->block_size, DEV_BSIZE);
+ if (store->size < SBSIZE + SBOFF)
+ error (5, 0, "%s: Disk too small (%Ld bytes)", diskfs_disk_name,
+ store->size);
- err = diskfs_device_open ();
- if (err)
- error (3, err, "%s", diskfs_device_arg);
-
- if (diskfs_device_block_size != DEV_BSIZE)
- error (4, err, "%s: Bad device record size %d (should be %d)",
- diskfs_device_arg, diskfs_device_block_size, DEV_BSIZE);
- if (diskfs_log2_device_block_size == 0)
- error (4, err, "%s: Device block size (%d) not a power of 2",
- diskfs_device_arg, diskfs_device_block_size);
-
- disk_size = diskfs_device_size << diskfs_log2_device_block_size;
- assert (disk_size >= SBSIZE + SBOFF);
+ log2_dev_blocks_per_dev_bsize = 0;
+ while ((1 << log2_dev_blocks_per_dev_bsize) < DEV_BSIZE)
+ log2_dev_blocks_per_dev_bsize++;
+ log2_dev_blocks_per_dev_bsize -= store->log2_block_size;
/* Map the entire disk. */
create_disk_pager ();
- /* Start the first request thread, to handle RPCs and page requests. */
- diskfs_spawn_first_thread ();
-
get_hypermetadata ();
inode_init ();
@@ -211,6 +192,8 @@ main (int argc, char **argv)
outside world. */
diskfs_startup_diskfs (bootstrap, 0);
+ /* SET HOST NAME */
+
/* And this thread is done with its work. */
cthread_exit (0);
@@ -221,7 +204,7 @@ error_t
diskfs_reload_global_state ()
{
flush_pokes ();
- pager_flush (disk_pager, 1);
+ pager_flush (diskfs_disk_pager, 1);
get_hypermetadata ();
return 0;
}
diff --git a/ufs/mapbuf.c b/ufs/mapbuf.c
deleted file mode 100644
index edf432a5..00000000
--- a/ufs/mapbuf.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Cache mappings of the disk
- Copyright (C) 1994 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
-#include "ufs.h"
-
-struct mapbuf *mblist;
-spin_lock_t mblistlock = SPIN_LOCK_INITIALIZER;
-
-struct mapbuf *
-map_region (vm_offset_t diskloc, vm_size_t length)
-{
- struct mapbuf *mb;
-
- /* Check to see if we are already mapping this region */
- spin_lock (&mblistlock);
- for (mb = mblist; mb; mb = mb->next)
- {
-
diff --git a/ufs/pager.c b/ufs/pager.c
index bea290ab..3038932d 100644
--- a/ufs/pager.c
+++ b/ufs/pager.c
@@ -1,5 +1,5 @@
/* Pager for ufs
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,6 +19,7 @@
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
+#include <hurd/store.h>
spin_lock_t node2pagelock = SPIN_LOCK_INITIALIZER;
@@ -32,6 +33,9 @@ spin_lock_t unlocked_pagein_lock = SPIN_LOCK_INITIALIZER;
struct port_bucket *pager_bucket;
+/* Mapped image of the disk. */
+void *disk_image;
+
/* Find the location on disk of page OFFSET in pager UPI. Return the
disk address (in disk block) in *ADDR. If *NPLOCK is set on
return, then release that mutex after I/O on the data has
@@ -117,7 +121,14 @@ find_address (struct user_pager_info *upi,
{
if (*nplock)
rwlock_reader_unlock (*nplock);
- return EIO;
+ if (isread)
+ return EIO;
+ else
+ {
+ *addr = 0;
+ *disksize = 0;
+ return 0;
+ }
}
if (offset + __vm_page_size > np->allocsize)
@@ -161,7 +172,11 @@ pager_read_page (struct user_pager_info *pager,
if (addr)
{
- err = diskfs_device_read_sync (addr, (void *)buf, disksize);
+ size_t read = 0;
+ err = store_read (store, addr << log2_dev_blocks_per_dev_bsize,
+ disksize, (void **)buf, &read);
+ if (read != disksize)
+ err = EIO;
if (!err && disksize != __vm_page_size)
bzero ((void *)(*buf + disksize), __vm_page_size - disksize);
*writelock = 0;
@@ -172,7 +187,8 @@ pager_read_page (struct user_pager_info *pager,
printf ("Write-locked pagein Object %#x\tOffset %#x\n", pager, page);
fflush (stdout);
#endif
- vm_allocate (mach_task_self (), buf, __vm_page_size, 1);
+ *buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
*writelock = 1;
}
@@ -199,15 +215,15 @@ pager_write_page (struct user_pager_info *pager,
return err;
if (addr)
- err = diskfs_device_write_sync (addr, buf, disksize);
- else
{
- printf ("Attempt to write unallocated disk\n.");
- printf ("Object %p\tOffset %#x\n", pager, page);
- fflush (stdout);
- err = 0; /* unallocated disk;
- error would be pointless */
+ size_t wrote;
+ err = store_write (store, addr << log2_dev_blocks_per_dev_bsize,
+ (void *)buf, disksize, &wrote);
+ if (wrote != disksize)
+ err = EIO;
}
+ else
+ err = 0;
if (nplock)
rwlock_reader_unlock (nplock);
@@ -286,6 +302,8 @@ pager_unlock_page (struct user_pager_info *pager,
/* Check to see if this block is allocated. */
if (indirs[0].bno == 0)
{
+ size_t wrote;
+
if (indirs[0].offset == -1)
{
err = ffs_alloc (np, lblkno (sblock, address),
@@ -294,9 +312,17 @@ pager_unlock_page (struct user_pager_info *pager,
sblock->fs_bsize, &bno, 0);
if (err)
goto out;
+
assert (lblkno (sblock, address) < NDADDR);
- diskfs_device_write_sync (fsbtodb (sblock, bno),
- zeroblock, sblock->fs_bsize);
+ err = store_write (store,
+ fsbtodb (sblock, bno)
+ << log2_dev_blocks_per_dev_bsize,
+ zeroblock, sblock->fs_bsize, &wrote);
+ if (!err && wrote != sblock->fs_bsize)
+ err = EIO;
+ if (err)
+ goto out;
+
indirs[0].bno = bno;
write_disk_entry (di->di_db[lblkno (sblock, address)], bno);
record_poke (di, sizeof (struct dinode));
@@ -378,8 +404,14 @@ pager_unlock_page (struct user_pager_info *pager,
if (err)
goto out;
- diskfs_device_write_sync (fsbtodb (sblock, bno),
- zeroblock, sblock->fs_bsize);
+ err = store_write (store,
+ fsbtodb (sblock, bno)
+ << log2_dev_blocks_per_dev_bsize,
+ zeroblock, sblock->fs_bsize, &wrote);
+ if (!err && wrote != sblock->fs_bsize)
+ err = EIO;
+ if (err)
+ goto out;
indirs[0].bno = bno;
write_disk_entry (siblock[indirs[0].offset], bno);
@@ -405,7 +437,7 @@ pager_report_extent (struct user_pager_info *pager,
*offset = 0;
if (pager->type == DISK)
- *size = diskfs_device_size << diskfs_log2_device_block_size;
+ *size = store->size;
else
*size = pager->np->allocsize;
@@ -436,15 +468,6 @@ pager_dropweak (struct user_pager_info *upi __attribute__ ((unused)))
-static void
-thread_function (any_t foo __attribute__ ((unused)))
-{
- for (;;)
- ports_manage_port_operations_multithread (pager_bucket, pager_demuxer,
- 1000 * 60 * 2, 0,
- 1, MACH_PORT_NULL);
-}
-
/* Create the DISK pager. */
void
create_disk_pager (void)
@@ -453,8 +476,10 @@ create_disk_pager (void)
upi->type = DISK;
upi->np = 0;
- disk_pager_setup (upi, MAY_CACHE);
- upi->p = disk_pager;
+ pager_bucket = ports_create_bucket ();
+ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size,
+ &disk_image);
+ upi->p = diskfs_disk_pager;
}
/* This syncs a single file (NP) to disk. Wait for all I/O to complete
@@ -546,6 +571,13 @@ diskfs_get_filemap (struct node *np, vm_prot_t prot)
diskfs_nref_light (np);
upi->p = pager_create (upi, pager_bucket,
MAY_CACHE, MEMORY_OBJECT_COPY_DELAY);
+ if (upi->p == 0)
+ {
+ diskfs_nrele_light (np);
+ free (upi);
+ spin_unlock (&node2pagelock);
+ return MACH_PORT_NULL;
+ }
np->dn->fileinfo = upi;
right = pager_get_port (np->dn->fileinfo->p);
ports_port_deref (np->dn->fileinfo->p);
@@ -743,7 +775,7 @@ diskfs_shutdown_pager ()
{
struct pager *p = arg;
/* Don't ever shut down the disk pager. */
- if (p != disk_pager)
+ if (p != diskfs_disk_pager)
pager_shutdown (p);
return 0;
}
@@ -762,7 +794,7 @@ diskfs_sync_everything (int wait)
{
struct pager *p = arg;
/* Make sure the disk pager is done last. */
- if (p != disk_pager)
+ if (p != diskfs_disk_pager)
pager_sync (p, wait);
return 0;
}
diff --git a/ufs/pokeloc.c b/ufs/pokeloc.c
index d09942e8..267aa106 100644
--- a/ufs/pokeloc.c
+++ b/ufs/pokeloc.c
@@ -75,7 +75,7 @@ sync_disk (int wait)
spin_lock (&pokelistlock);
for (pl = pokelist; pl; pl = tmp)
{
- pager_sync_some (disk_pager, pl->offset, pl->length, wait);
+ pager_sync_some (diskfs_disk_pager, pl->offset, pl->length, wait);
tmp = pl->next;
free (pl);
}
diff --git a/ufs/sizes.c b/ufs/sizes.c
index a0b090d3..58cbfc98 100644
--- a/ufs/sizes.c
+++ b/ufs/sizes.c
@@ -1,5 +1,5 @@
/* File growth and truncation
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999 Free Software Foundation
This file is part of the GNU Hurd.
@@ -82,8 +82,7 @@ diskfs_truncate (struct node *np,
np->allocsize = length; /* temporary */
bsize = blksize (sblock, np, lblkno (sblock, length));
np->allocsize = savesize;
- diskfs_node_rdwr (np, (void *) zeroblock, length,
- bsize - offset, 1, 0, 0);
+ diskfs_node_rdwr (np, zeroblock, length, bsize - offset, 1, 0, 0);
diskfs_file_update (np, 1);
}
@@ -105,10 +104,14 @@ diskfs_truncate (struct node *np,
pager_change_attributes (upi->p, MAY_CACHE,
MEMORY_OBJECT_COPY_NONE, 1);
obj = diskfs_get_filemap (np, VM_PROT_READ | VM_PROT_WRITE);
- poke_pages (obj, round_page (length), round_page (np->allocsize));
- mach_port_deallocate (mach_task_self (), obj);
- pager_flush_some (upi->p, round_page (length),
- np->allocsize - length, 1);
+ if (obj != MACH_PORT_NULL)
+ {
+ /* XXX should cope with errors from diskfs_get_filemap */
+ poke_pages (obj, round_page (length), round_page (np->allocsize));
+ mach_port_deallocate (mach_task_self (), obj);
+ pager_flush_some (upi->p, round_page (length),
+ np->allocsize - length, 1);
+ }
ports_port_deref (upi->p);
}
@@ -321,7 +324,7 @@ indir_release (struct node *np, daddr_t bno, int level)
the block from the kernel's memory, making sure we do it
synchronously--and BEFORE we attach it to the free list
with ffs_blkfree. */
- pager_flush_some (disk_pager, fsaddr (sblock, bno), sblock->fs_bsize, 1);
+ pager_flush_some (diskfs_disk_pager, fsaddr (sblock, bno), sblock->fs_bsize, 1);
/* We should also take this block off the inode's list of
dirty indirect blocks if it's there. */
@@ -389,7 +392,8 @@ block_extended (struct node *np,
don't get paged in from disk. */
if (round_page (old_size) < round_page (new_size))
offer_data (np, lbn * sblock->fs_bsize + round_page (old_size),
- round_page (new_size) - round_page (old_size), zeroblock);
+ round_page (new_size) - round_page (old_size),
+ (vm_address_t)zeroblock);
if (old_pbn != new_pbn)
{
@@ -400,6 +404,11 @@ block_extended (struct node *np,
/* Map in this part of the file */
mapobj = diskfs_get_filemap (np, VM_PROT_WRITE | VM_PROT_READ);
+
+ /* XXX Should cope with errors from diskfs_get_filemap and back
+ out the operation here. */
+ assert (mapobj);
+
err = vm_map (mach_task_self (), &mapaddr, round_page (old_size), 0, 1,
mapobj, lbn * sblock->fs_bsize, 0,
VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE, 0);
@@ -430,7 +439,7 @@ block_extended (struct node *np,
/* Undo mapping */
mach_port_deallocate (mach_task_self (), mapobj);
- vm_deallocate (mach_task_self (), mapaddr, round_page (old_size));
+ munmap ((caddr_t) mapaddr, round_page (old_size));
/* Now it's OK to free the old block */
ffs_blkfree (np, old_pbn, old_size);
@@ -477,6 +486,9 @@ diskfs_grow (struct node *np,
/* This reference will ensure that NP->dn->fileinfo stays allocated. */
pagerpt = diskfs_get_filemap (np, VM_PROT_WRITE|VM_PROT_READ);
+ if (pagerpt == MACH_PORT_NULL)
+ return errno;
+
/* The new last block of the file. */
lbn = lblkno (sblock, end - 1);
@@ -553,7 +565,8 @@ diskfs_grow (struct node *np,
goto out;
- offer_data (np, lbn * sblock->fs_bsize, size, zeroblock);
+ offer_data (np, lbn * sblock->fs_bsize, size,
+ (vm_address_t)zeroblock);
write_disk_entry (di->di_db[lbn], bno);
record_poke (di, sizeof (struct dinode));
np->dn_set_ctime = 1;
@@ -647,7 +660,8 @@ diskfs_grow (struct node *np,
sblock->fs_bsize, &bno, 0);
if (err)
goto out;
- offer_data (np, lbn * sblock->fs_bsize, sblock->fs_bsize, zeroblock);
+ offer_data (np, lbn * sblock->fs_bsize, sblock->fs_bsize,
+ (vm_address_t)zeroblock);
indirs[0].bno = bno;
write_disk_entry (siblock[indirs[0].offset], bno);
record_poke (siblock, sblock->fs_bsize);
@@ -697,7 +711,7 @@ poke_pages (memory_object_t obj,
{
for (poke = addr; poke < addr + len; poke += vm_page_size)
*(volatile int *)poke = *(volatile int *)poke;
- vm_deallocate (mach_task_self (), addr, len);
+ munmap ((caddr_t) addr, len);
}
start += len;
}
diff --git a/ufs/ufs.h b/ufs/ufs.h
index ea13475e..f59784d5 100644
--- a/ufs/ufs.h
+++ b/ufs/ufs.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -17,15 +17,24 @@
#include <mach.h>
#include <hurd.h>
+#include <sys/mman.h>
#include <hurd/ports.h>
#include <hurd/pager.h>
#include <hurd/fshelp.h>
#include <hurd/iohelp.h>
#include <hurd/diskfs.h>
+#include <sys/mman.h>
#include <assert.h>
+#include <features.h>
#include "fs.h"
#include "dinode.h"
+#ifdef UFS_DEFINE_EI
+#define UFS_EI
+#else
+#define UFS_EI __extern_inline
+#endif
+
/* Define this if memory objects should not be cached by the kernel.
Normally, don't define it, but defining it causes a much greater rate
of paging requests, which may be helpful in catching bugs. */
@@ -36,6 +45,8 @@ struct disknode
{
ino_t number;
+ int dir_idx;
+
/* For a directory, this array holds the number of directory entries in
each DIRBLKSIZE piece of the directory. */
int *dirents;
@@ -79,14 +90,22 @@ struct user_pager_info
} type;
struct pager *p;
vm_prot_t max_prot;
-
+
vm_offset_t allow_unlocked_pagein;
vm_size_t unlocked_pagein_length;
};
#include <hurd/diskfs-pager.h>
-extern vm_address_t zeroblock;
+/* The physical media. */
+extern struct store *store;
+/* What the user specified. */
+extern struct store_parsed *store_parsed;
+
+/* Mapped image of the disk. */
+extern void *disk_image;
+
+extern void *zeroblock;
extern struct fs *sblock;
extern struct csum *csum;
@@ -120,6 +139,8 @@ int direct_symlink_extension;
/* If this is set, then the disk is byteswapped from native order. */
int swab_disk;
+/* Number of device blocks per DEV_BSIZE block. */
+unsigned log2_dev_blocks_per_dev_bsize;
/* Handy macros */
#define DEV_BSIZE 512
@@ -136,8 +157,18 @@ int swab_disk;
/* Functions for looking inside disk_image */
+extern struct dinode * dino (ino_t inum);
+extern daddr_t * indir_block (daddr_t bno);
+extern struct cg * cg_locate (int ncg);
+extern void sync_disk_blocks (daddr_t blkno, size_t nbytes, int wait);
+extern void sync_dinode (int inum, int wait);
+extern short swab_short (short arg);
+extern long swab_long (long arg);
+extern long long swab_long_long (long long arg);
+
+#if defined(__USE_EXTERN_INLINES) || defined(UFS_DEFINE_EI)
/* Convert an inode number to the dinode on disk. */
-extern inline struct dinode *
+UFS_EI struct dinode *
dino (ino_t inum)
{
return (struct dinode *)
@@ -147,28 +178,28 @@ dino (ino_t inum)
}
/* Convert a indirect block number to a daddr_t table. */
-extern inline daddr_t *
+UFS_EI daddr_t *
indir_block (daddr_t bno)
{
return (daddr_t *) (disk_image + fsaddr (sblock, bno));
}
/* Convert a cg number to the cylinder group. */
-extern inline struct cg *
+UFS_EI struct cg *
cg_locate (int ncg)
{
return (struct cg *) (disk_image + fsaddr (sblock, cgtod (sblock, ncg)));
}
/* Sync part of the disk */
-extern inline void
+UFS_EI void
sync_disk_blocks (daddr_t blkno, size_t nbytes, int wait)
{
- pager_sync_some (disk_pager, fsaddr (sblock, blkno), nbytes, wait);
+ pager_sync_some (diskfs_disk_pager, fsaddr (sblock, blkno), nbytes, wait);
}
/* Sync an disk inode */
-extern inline void
+UFS_EI void
sync_dinode (int inum, int wait)
{
sync_disk_blocks (ino_to_fsba (sblock, inum), sblock->fs_fsize, wait);
@@ -176,26 +207,27 @@ sync_dinode (int inum, int wait)
/* Functions for byte swapping */
-extern inline short
+UFS_EI short
swab_short (short arg)
{
return (((arg & 0xff) << 8)
| ((arg & 0xff00) >> 8));
}
-extern inline long
+UFS_EI long
swab_long (long arg)
{
return (((long) swab_short (arg & 0xffff) << 16)
| swab_short ((arg & 0xffff0000) >> 16));
}
-extern inline long long
+UFS_EI long long
swab_long_long (long long arg)
{
return (((long long) swab_long (arg & 0xffffffff) << 32)
- | swab_long ((arg & 0xffffffff00000000lL) >> 32));
+ | swab_long ((arg & 0xffffffff00000000LL) >> 32));
}
+#endif /* Use extern inlines. */
/* Return ENTRY, after byteswapping it if necessary */
#define read_disk_entry(entry) \
@@ -211,7 +243,7 @@ swab_long_long (long long arg)
abort (); \
ret; \
})
-
+
/* Execute A = B, but byteswap it along the way if necessary */
#define write_disk_entry(a,b) \
({ \
diff --git a/ufs/xinl.c b/ufs/xinl.c
new file mode 100644
index 00000000..7994a1f7
--- /dev/null
+++ b/ufs/xinl.c
@@ -0,0 +1,2 @@
+#define UFS_DEFINE_EI
+#include "ufs.h"
diff --git a/mkbootfs/Makefile b/usermux/Makefile
index df5af560..c07ae927 100644
--- a/mkbootfs/Makefile
+++ b/usermux/Makefile
@@ -1,5 +1,6 @@
+# Makefile for usermux
#
-# Copyright (C) 1993, 1994 Free Software Foundation
+# Copyright (C) 1997, 2000 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
@@ -15,18 +16,15 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-dir := mkbootfs
-makemode := misc
+dir := usermux
+makemode := server
-SRCS = mkbootfs.c
+target = usermux
-include ../Makeconf
-
-all: mkbootfs
+SRCS = usermux.c mux.c leaf.c node.c stubs.c
+LCLHDRS = usermux.h
-mkbootfs: mkbootfs.c
- rsh $(mighost) -n cd `pwd` \; gcc mkbootfs.c -o mkbootfs
-
-clean:
- rm -f mkbootfs *.o
+OBJS = $(SRCS:.c=.o)
+HURDLIBS = netfs fshelp iohelp threads ports ihash shouldbeinlibc
+include ../Makeconf
diff --git a/usermux/leaf.c b/usermux/leaf.c
new file mode 100644
index 00000000..7f41b187
--- /dev/null
+++ b/usermux/leaf.c
@@ -0,0 +1,152 @@
+/* Usermux leaf node functions
+
+ Copyright (C) 1997,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <argz.h>
+#include <hurd/paths.h>
+
+#include "usermux.h"
+
+/* Read the contents of NODE (a symlink), for USER, into BUF. */
+error_t
+netfs_attempt_readlink (struct iouser *user, struct node *node, char *buf)
+{
+ assert (node->nn->name);
+ /* For symlink nodes, the translator spec just contains the link target. */
+ memcpy (buf, node->nn->trans, node->nn->trans_len);
+ fshelp_touch (&node->nn_stat, TOUCH_ATIME, usermux_maptime);
+ return 0;
+}
+
+/* For locked node NODE with S_IPTRANS set in its mode, look up the name of
+ its translator. Store the name into newly malloced storage, and return it
+ in *ARGZ; set *ARGZ_LEN to the total length.
+
+ For usermux, this creates a new translator string by instantiating the
+ global translator template. */
+error_t
+netfs_get_translator (struct node *node, char **trans, size_t *trans_len)
+{
+ if (! node->nn->name)
+ return EINVAL;
+ else
+ {
+ fshelp_touch (&node->nn_stat, TOUCH_ATIME, usermux_maptime);
+ *trans = 0;
+ *trans_len = 0;
+ if (S_ISLNK (node->nn_stat.st_mode))
+ argz_add (trans, trans_len, _HURD_SYMLINK);
+ return
+ argz_append (trans, trans_len, node->nn->trans, node->nn->trans_len);
+ }
+}
+
+/* Create a new leaf node in MUX, with a name NAME, and return the new node
+ with a single reference in NODE. */
+error_t
+create_user_node (struct usermux *mux, struct usermux_name *name,
+ struct passwd *pw, struct node **node)
+{
+ error_t err;
+ struct node *new;
+ struct netnode *nn = malloc (sizeof (struct netnode));
+
+ if (! nn)
+ return ENOMEM;
+
+ nn->mux = mux;
+ nn->name = name;
+
+ new = netfs_make_node (nn);
+ if (! new)
+ {
+ free (nn);
+ return ENOMEM;
+ }
+
+ new->nn_stat = mux->stat_template;
+
+ new->nn_stat.st_ino = pw->pw_uid + USERMUX_FILENO_UID_OFFSET;
+
+ if (strcmp (mux->trans_template, _HURD_SYMLINK) == 0
+ && mux->trans_template_len == sizeof _HURD_SYMLINK)
+ {
+ err = argz_create_sep (pw->pw_dir, 0, &nn->trans, &nn->trans_len);
+ new->nn_stat.st_mode = (S_IFLNK | 0666);
+ new->nn_stat.st_size = nn->trans_len;
+ }
+ else
+ {
+ unsigned replace_count = 0;
+
+ nn->trans = 0; /* Initialize return value. */
+ nn->trans_len = 0;
+
+ err = argz_append (&nn->trans, &nn->trans_len,
+ mux->trans_template, mux->trans_template_len);
+
+ /* Perform any substitutions. */
+ if (!err && mux->user_pat && *mux->user_pat)
+ err = argz_replace (&nn->trans, &nn->trans_len,
+ mux->user_pat, pw->pw_name,
+ &replace_count);
+ if (!err && mux->home_pat && *mux->home_pat)
+ err = argz_replace (&nn->trans, &nn->trans_len,
+ mux->home_pat, pw->pw_dir,
+ &replace_count);
+ if (!err && mux->uid_pat && *mux->uid_pat)
+ {
+ char uid_buf[10];
+ snprintf (uid_buf, sizeof uid_buf, "%d", pw->pw_uid);
+ err = argz_replace (&nn->trans, &nn->trans_len,
+ mux->uid_pat, uid_buf,
+ &replace_count);
+ }
+
+ if (!err && replace_count == 0)
+ /* Default, if no instances of any pattern occur, is to append the
+ user home dir. */
+ err = argz_add (&nn->trans, &nn->trans_len, pw->pw_dir);
+
+ if (err && nn->trans_len > 0)
+ free (nn->trans);
+
+ new->nn_stat.st_mode = (S_IFREG | S_IPTRANS | 0666);
+ new->nn_stat.st_size = 0;
+ }
+ new->nn_translated = new->nn_stat.st_mode;
+
+ if (err)
+ {
+ free (nn);
+ free (new);
+ return err;
+ }
+
+ fshelp_touch (&new->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ usermux_maptime);
+
+ name->node = new;
+ *node = new;
+
+ return 0;
+}
diff --git a/usermux/mux.c b/usermux/mux.c
new file mode 100644
index 00000000..12da1e14
--- /dev/null
+++ b/usermux/mux.c
@@ -0,0 +1,502 @@
+/* Root usermux node
+
+ Copyright (C) 1997, 1998, 1999, 2000, 2002, 2008
+ Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stddef.h>
+#include <string.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <sys/mman.h>
+
+#include "usermux.h"
+
+/* The granularity with which we allocate space to return our result. */
+#define DIRENTS_CHUNK_SIZE (128*1024)/* Enough for perhaps 8000 names. */
+
+/* The number seconds we cache our directory return value, in seconds. */
+#define DIRENTS_CACHE_TIME 90
+
+/* 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))
+
+static error_t lookup_user (struct usermux *mux, const char *user,
+ struct node **node); /* fwd decl */
+
+/* [root] Directory operations. */
+
+/* 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;
+
+ if (dir->nn->name)
+ err = ENOTDIR;
+ else
+ err = lookup_user (dir->nn->mux, name, node);
+
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, usermux_maptime);
+
+ mutex_unlock (&dir->lock);
+
+ if (! err)
+ mutex_lock (&(*node)->lock);
+
+ return err;
+}
+
+/* Fetch a directory of user entries, as for netfs_get_dirents (that function
+ is actually a wrapper that caches the results for a while). */
+static error_t
+get_dirents (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 = 0;
+
+ if (dir->nn->name)
+ return ENOTDIR;
+
+ /* Start scanning. */
+ setpwent ();
+
+ /* Find the first entry. */
+ while (first_entry-- > 0)
+ if (! getpwent ())
+ {
+ max_entries = 0;
+ break;
+ }
+
+ if (max_entries != 0)
+ {
+ size_t size = (max_data_len == 0 ? DIRENTS_CHUNK_SIZE : max_data_len);
+
+ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = (data != (void *) -1) ? errno : 0;
+
+ if (! err)
+ {
+ struct passwd *pw;
+ char *p = *data;
+ int count = 0;
+ int entry_type =
+ (S_ISLNK (dir->nn->mux->stat_template.st_mode) ? DT_LNK : DT_REG);
+
+ /* See how much space we need for the result. */
+ while ((max_entries == -1 || count < max_entries)
+ && (pw = getpwent ()))
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (pw->pw_name);
+ size_t sz = DIRENT_LEN (name_len);
+
+ if ((p - *data) + sz > size)
+ {
+ if (max_data_len > 0)
+ break;
+ else
+ /* Try to grow our return buffer. */
+ {
+ 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 = pw->pw_uid + USERMUX_FILENO_UID_OFFSET;
+ hdr.d_reclen = sz;
+ hdr.d_type = entry_type;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, pw->pw_name);
+ p += sz;
+
+ count++;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ endpwent ();
+
+ return err;
+}
+
+/* Implement the netfs_get_directs callback as described in
+ <hurd/netfs.h>. */
+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;
+ static time_t cache_timestamp = 0;
+ static struct rwlock cache_lock = RWLOCK_INITIALIZER;
+ static char *cached_data = 0;
+ static mach_msg_type_number_t cached_data_len = 0;
+ static int cached_data_entries = 0;
+ struct timeval tv;
+ char *first;
+ size_t bytes_left, entries_left;
+
+ maptime_read (usermux_maptime, &tv);
+ if (tv.tv_sec > cache_timestamp + DIRENTS_CACHE_TIME)
+ {
+ rwlock_writer_lock (&cache_lock);
+
+ if (cached_data_len > 0)
+ /* Free the old cache. */
+ {
+ munmap (cached_data, cached_data_len);
+ cached_data = 0;
+ cached_data_len = 0;
+ }
+
+ err = get_dirents (dir, 0, -1, &cached_data, &cached_data_len, 0,
+ &cached_data_entries);
+
+ if (! err)
+ cache_timestamp = tv.tv_sec;
+
+ rwlock_writer_unlock (&cache_lock);
+
+ if (err)
+ return err;
+ }
+
+ rwlock_reader_lock (&cache_lock);
+
+ first = cached_data;
+ bytes_left = cached_data_len;
+ entries_left = cached_data_entries;
+
+ while (first_entry > 0)
+ {
+ struct dirent *e = (struct dirent *)first;
+
+ if (entries_left == 0)
+ {
+ rwlock_reader_unlock (&cache_lock);
+ return EINVAL;
+ }
+
+ first += e->d_reclen;
+ bytes_left -= e->d_reclen;
+ entries_left--;
+ }
+
+ if ((max_data_len > 0 && max_data_len < bytes_left)
+ || (max_entries > 0 && max_entries < entries_left))
+ /* If there's some limit on the return value, we can't just use our
+ values representing the whole cache, so we have to explicitly count
+ how much we're going to return. */
+ {
+ char *lim = first;
+ int entries = 0;
+
+ while (entries_left > 0
+ && max_entries > 0
+ && max_data_len > ((struct dirent *)lim)->d_reclen)
+ {
+ size_t reclen = ((struct dirent *)lim)->d_reclen;
+ max_data_len -= reclen;
+ max_entries--;
+ entries++;
+ lim += reclen;
+ }
+
+ bytes_left = (lim - first);
+ entries_left = entries;
+ }
+
+ *data_len = bytes_left;
+ *data_entries = entries_left;
+
+ *data = mmap (0, bytes_left, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = (*data == (void *) -1) ? errno : 0;
+ if (! err)
+ bcopy (cached_data, *data, bytes_left);
+
+ rwlock_reader_unlock (&cache_lock);
+
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, usermux_maptime);
+
+ return err;
+}
+
+/* User lookup. */
+
+/* Free storage allocated consumed by the user mux name NM, but not the node
+ it points to. */
+static void
+free_name (struct usermux_name *nm)
+{
+ free ((char *)nm->name);
+ free (nm);
+}
+
+/* See if there's an existing entry for the name USER, and if so, return its
+ node in NODE with an additional references. True is returned iff the
+ lookup succeeds. If PURGE is true, then any nodes with a null node are
+ removed. */
+static int
+lookup_cached (struct usermux *mux, const char *user, int purge,
+ struct node **node)
+{
+ struct usermux_name *nm = mux->names, **prevl = &mux->names;
+
+ while (nm)
+ {
+ struct usermux_name *next = nm->next;
+
+ if (strcasecmp (user, nm->name) == 0)
+ {
+ spin_lock (&netfs_node_refcnt_lock);
+ if (nm->node)
+ nm->node->references++;
+ spin_unlock (&netfs_node_refcnt_lock);
+
+ if (nm->node)
+ {
+ *node = nm->node;
+ return 1;
+ }
+ }
+
+ if (purge && !nm->node)
+ {
+ *prevl = nm->next;
+ free_name (nm);
+ }
+ else
+ prevl = &nm->next;
+
+ nm = next;
+ }
+
+ return 0;
+}
+
+/* See if there's an existing entry for the name USER, and if so, return its
+ node in NODE, with an additional reference, otherwise, create a new node
+ for the user HE as referred to by USER, and return that instead, with a
+ single reference. The type of node created is either a translator node,
+ if USER refers to the official name of the user, or a symlink node to the
+ official name, if it doesn't. */
+static error_t
+lookup_pwent (struct usermux *mux, const char *user, struct passwd *pw,
+ struct node **node)
+{
+ error_t err;
+ struct usermux_name *nm = malloc (sizeof (struct usermux_name));
+
+ if (! nm)
+ return ENOMEM;
+
+ nm->name = strdup (user);
+ err = create_user_node (mux, nm, pw, node);
+ if (err)
+ {
+ free_name (nm);
+ return err;
+ }
+
+ rwlock_writer_lock (&mux->names_lock);
+ if (lookup_cached (mux, user, 1, node))
+ /* An entry for USER has already been created between the time we last
+ looked and now (which is possible because we didn't lock MUX).
+ Just throw away our version and return the one already in the cache. */
+ {
+ rwlock_writer_unlock (&mux->names_lock);
+ nm->node->nn->name = 0; /* Avoid touching the mux name list. */
+ netfs_nrele (nm->node); /* Free the tentative new node. */
+ free_name (nm); /* And the name it was under. */
+ }
+ else
+ /* Enter NM into MUX's list of names, and return the new node. */
+ {
+ nm->next = mux->names;
+ mux->names = nm;
+ rwlock_writer_unlock (&mux->names_lock);
+ }
+
+ return 0;
+}
+
+/* Lookup the user USER in MUX, and return the resulting node in NODE, with
+ an additional reference, or an error. */
+static error_t
+lookup_user (struct usermux *mux, const char *user, struct node **node)
+{
+ int was_cached;
+ struct passwd _pw, *pw;
+ char pwent_data[2048]; /* XXX what size should this be???? */
+
+ rwlock_reader_lock (&mux->names_lock);
+ was_cached = lookup_cached (mux, user, 0, node);
+ rwlock_reader_unlock (&mux->names_lock);
+
+ if (was_cached)
+ return 0;
+ else
+ {
+ if (getpwnam_r (user, &_pw, pwent_data, sizeof pwent_data, &pw))
+ return ENOENT;
+ if (pw == NULL)
+ return ENOENT;
+ return lookup_pwent (mux, user, pw, node);
+ }
+}
+
+/* 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;
+}
+
+/* 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)
+{
+ if (node->nn->name)
+ return EOPNOTSUPP;
+ else
+ {
+ struct usermux *mux = node->nn->mux;
+ error_t err = file_chown (mux->underlying, uid, gid);
+
+ if (! err)
+ {
+ struct usermux_name *nm;
+
+ /* Change NODE's owner. */
+ mux->stat_template.st_uid = uid;
+ mux->stat_template.st_gid = gid;
+ node->nn_stat.st_uid = uid;
+ node->nn_stat.st_gid = gid;
+
+ /* Change the owner of each leaf node. */
+ rwlock_reader_lock (&mux->names_lock);
+ for (nm = mux->names; nm; nm = nm->next)
+ if (nm->node)
+ {
+ nm->node->nn_stat.st_uid = uid;
+ nm->node->nn_stat.st_gid = gid;
+ }
+ rwlock_reader_unlock (&mux->names_lock);
+
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, usermux_maptime);
+ }
+
+ return err;
+ }
+}
+
+/* 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)
+{
+ if (node->nn->name)
+ return EOPNOTSUPP;
+ else
+ {
+ struct usermux *mux = node->nn->mux;
+ error_t err = file_chauthor (mux->underlying, author);
+
+ if (! err)
+ {
+ struct usermux_name *nm;
+
+ /* Change NODE's owner. */
+ mux->stat_template.st_author = author;
+ node->nn_stat.st_author = author;
+
+ /* Change the owner of each leaf node. */
+ rwlock_reader_lock (&mux->names_lock);
+ for (nm = mux->names; nm; nm = nm->next)
+ if (nm->node)
+ nm->node->nn_stat.st_author = author;
+ rwlock_reader_unlock (&mux->names_lock);
+
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, usermux_maptime);
+ }
+
+ return err;
+ }
+}
+
+/* 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)
+{
+ mode &= ~S_ITRANS;
+ if ((mode & S_IFMT) == 0)
+ mode |= (node->nn_stat.st_mode & S_IFMT);
+ if (node->nn->name || ((mode & S_IFMT) != (node->nn_stat.st_mode & S_IFMT)))
+ return EOPNOTSUPP;
+ else
+ {
+ error_t err = file_chmod (node->nn->mux->underlying, mode & ~S_IFMT);
+ if (! err)
+ {
+ node->nn_stat.st_mode = mode;
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, usermux_maptime);
+ }
+ return err;
+ }
+}
diff --git a/usermux/node.c b/usermux/node.c
new file mode 100644
index 00000000..f4a5f7d7
--- /dev/null
+++ b/usermux/node.c
@@ -0,0 +1,129 @@
+/* General fs node functions
+
+ Copyright (C) 1997, 1999, 2007 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <fcntl.h>
+
+#include "usermux.h"
+
+/* Node maintenance. */
+
+/* Node NP is all done; free all its associated storage. */
+void
+netfs_node_norefs (struct node *node)
+{
+ if (node->nn->name)
+ /* Remove our name's pointer to us; the name itself will eventually be
+ freed by another party. */
+ node->nn->name->node = 0;
+ if (node->nn->trans_len > 0)
+ free (node->nn->trans);
+ free (node->nn);
+ free (node);
+}
+
+/* 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 = 0;
+ mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+/* 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 = 0;
+ if (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 = fshelp_isowner (&node->nn_stat, cred);
+ int flags = TOUCH_CTIME;
+
+ if (! err)
+ {
+ if (mtime)
+ node->nn_stat.st_mtim = *mtime;
+ else
+ flags |= TOUCH_MTIME;
+
+ if (atime)
+ node->nn_stat.st_atim = *atime;
+ else
+ flags |= TOUCH_ATIME;
+
+ fshelp_touch (&node->nn_stat, TOUCH_CTIME, usermux_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)
+{
+ *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 0;
+}
+
+/* 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 0;
+}
+
+/* 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;
+}
diff --git a/usermux/stubs.c b/usermux/stubs.c
new file mode 100644
index 00000000..b1992b02
--- /dev/null
+++ b/usermux/stubs.c
@@ -0,0 +1,143 @@
+/* Stub routines for usermux
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd/netfs.h>
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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)
+{
+ return EOPNOTSUPP;
+}
+
+/* Delete NAME in DIR for USER. */
+error_t
+netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* Attempt to remove directory named NAME in DIR for USER. */
+error_t
+netfs_attempt_rmdir (struct iouser *user,
+ struct node *dir, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/* 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 EOPNOTSUPP;
+}
+
+/* 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)
+{
+ return EOPNOTSUPP;
+}
+
+/* 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)
+{
+ return EOPNOTSUPP;
+}
+
+/* Write to the file NODE for user CRED starting at OFSET 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 EOPNOTSUPP;
+}
diff --git a/libmom/hash-ref.c b/usermux/usermux-xinl.c
index 6c160b1b..fd7661c2 100644
--- a/libmom/hash-ref.c
+++ b/usermux/usermux-xinl.c
@@ -1,7 +1,7 @@
-/* Return a hash key for a mom port
- Copyright (C) 1996 Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
+/* Real definitions for extern inline functions in usermux.h
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
@@ -18,11 +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"
-
-int
-mom_hash_port (struct mom_port_ref *obj)
-{
- return mom_fetch_mach_port (obj);
-}
-
+#define USERMUX_EI
+#undef __OPTIMIZE__
+#define __OPTIMIZE__ 1
+#include "usermux.h"
diff --git a/usermux/usermux.c b/usermux/usermux.c
new file mode 100644
index 00000000..fad923c9
--- /dev/null
+++ b/usermux/usermux.c
@@ -0,0 +1,156 @@
+/* Multiplexing filesystems by user
+
+ Copyright (C) 1997, 2000, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <sys/time.h>
+#include <hurd/paths.h>
+
+#include <version.h>
+
+#include "usermux.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (usermux);
+
+char *netfs_server_name = "usermux";
+char *netfs_server_version = HURD_VERSION;
+int netfs_maxsymlinks = 25;
+
+volatile struct mapped_time_value *usermux_mapped_time;
+
+#define OPT_USER_PAT 1
+#define OPT_HOME_PAT 2
+#define OPT_UID_PAT 3
+
+/* Startup options. */
+static const struct argp_option options[] =
+{
+ { "user-pattern", OPT_USER_PAT, "PAT", 0,
+ "The string to replace in the translator specification with the user name"
+ " (default `${user}')" },
+ { "home-pattern", OPT_HOME_PAT, "PAT", 0,
+ "The string to replace in the translator specification with the user's"
+ " home directory (default `${home}')" },
+ { "uid-pattern", OPT_UID_PAT, "PAT", 0,
+ "The string to replace in the translator specification with the uid"
+ " (default `${uid}')" },
+ { "clear-patterns", 'C', 0, 0,
+ "Reset all patterns to empty; this option may then be followed by options"
+ " to set specific patterns" },
+ { 0 }
+};
+static const char args_doc[] = "[TRANSLATOR [ARG...]]";
+static const char doc[] =
+ "A translator for invoking user-specific translators."
+ "\vThis translator appears like a directory in which user names can be"
+ " looked up, and will start TRANSLATOR to service each resulting node."
+ " If no pattern occurs in the translator specification, the users's"
+ " home directory is appended to it instead; TRANSLATOR defaults to"
+ " " _HURD_SYMLINK ".";
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct stat ul_stat;
+ mach_port_t bootstrap;
+ struct usermux mux =
+ { user_pat: "${user}", home_pat: "${home}", uid_pat: "${uid}" };
+ struct netnode root_nn = { mux: &mux };
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case OPT_USER_PAT: mux.user_pat = arg; break;
+ case OPT_HOME_PAT: mux.home_pat = arg; break;
+ case OPT_UID_PAT: mux.uid_pat = arg; break;
+ case 'C': bzero (&mux, sizeof mux); break;
+
+ case ARGP_KEY_NO_ARGS:
+ bzero (&mux, sizeof mux); /* Default doesn't use them; be careful. */
+ return argz_create_sep (_HURD_SYMLINK, 0,
+ &mux.trans_template, &mux.trans_template_len);
+ case ARGP_KEY_ARGS:
+ /* Steal the entire tail of arg vector for our own use. */
+ return argz_create (state->argv + state->next,
+ &mux.trans_template, &mux.trans_template_len);
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = { options, parse_opt, args_doc, doc };
+
+ /* Parse our command line arguments. */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ netfs_init ();
+
+ /* Create the root node (some attributes initialized below). */
+ netfs_root_node = netfs_make_node (&root_nn);
+ if (! netfs_root_node)
+ error (5, ENOMEM, "Cannot create root node");
+
+ err = maptime_map (0, 0, &usermux_maptime);
+ if (err)
+ error (6, err, "Cannot map time");
+
+ /* Handshake with the party trying to start the translator. */
+ mux.underlying = netfs_startup (bootstrap, 0);
+
+ /* We inherit various attributes from the node underlying this translator. */
+ err = io_stat (mux.underlying, &ul_stat);
+ if (err)
+ error (7, err, "Cannot stat underlying node");
+
+ /* MUX.stat_template contains some fields that are inherited by all nodes
+ we create. */
+ mux.stat_template.st_uid = ul_stat.st_uid;
+ mux.stat_template.st_gid = ul_stat.st_gid;
+ mux.stat_template.st_author = ul_stat.st_author;
+ mux.stat_template.st_fsid = getpid ();
+ mux.stat_template.st_nlink = 1;
+ mux.stat_template.st_fstype = FSTYPE_MISC;
+
+ /* We implement symlinks directly, and everything else as a real
+ translator. */
+ if (strcmp (mux.trans_template, _HURD_SYMLINK) == 0)
+ mux.stat_template.st_mode = S_IFLNK | 0666;
+ else
+ mux.stat_template.st_mode = S_IFREG | S_IPTRANS | 0666;
+
+ /* Initialize the root node's stat information. */
+ netfs_root_node->nn_stat = mux.stat_template;
+ netfs_root_node->nn_stat.st_ino = 2;
+ netfs_root_node->nn_stat.st_mode =
+ S_IFDIR | (ul_stat.st_mode & ~S_IFMT & ~S_ITRANS);
+ netfs_root_node->nn_translated = 0;
+
+ fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ usermux_maptime);
+
+ for (;;) /* ?? */
+ netfs_server_loop ();
+}
diff --git a/usermux/usermux.h b/usermux/usermux.h
new file mode 100644
index 00000000..ff4ca5de
--- /dev/null
+++ b/usermux/usermux.h
@@ -0,0 +1,99 @@
+/* Multiplexing filesystems by user
+
+ Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef __USERMUX_H__
+#define __USERMUX_H__
+
+#include <hurd/netfs.h>
+#include <rwlock.h>
+#include <maptime.h>
+
+struct passwd;
+
+/* Filenos (aka inode numbers) for user nodes are the uid + this. */
+#define USERMUX_FILENO_UID_OFFSET 10
+
+/* Handy source of time. */
+volatile struct mapped_time_value *usermux_maptime;
+
+/* The state associated with a user multiplexer translator. */
+struct usermux
+{
+ /* The user nodes in this mux. */
+ struct usermux_name *names;
+ struct rwlock names_lock;
+
+ /* A template argz, which is used to start each user-specific translator
+ with the user name appropriately added. */
+ char *trans_template;
+ size_t trans_template_len;
+
+ /* What string to replace in TRANS_TEMPLATE with the name of the various
+ user params; if none occur in the template, the user's home dir is
+ appended as an additional argument. */
+ char *user_pat; /* User name */
+ char *home_pat; /* Home directory */
+ char *uid_pat; /* Numeric user id */
+
+ /* Constant fields for user stat entries. */
+ struct stat stat_template;
+
+ /* The file that this translator is sitting on top of; we inherit various
+ characteristics from it. */
+ file_t underlying;
+};
+
+/* The name of a recently looked up user entry. */
+struct usermux_name
+{
+ const char *name; /* Looked up name. */
+
+ /* A filesystem node associated with NAME. */
+ struct node *node;
+
+ struct usermux_name *next;
+};
+
+/* The fs specific storage that libnetfs associates with each filesystem
+ node. */
+struct netnode
+{
+ /* The mux this node belongs to (the node can either be the mux root, or
+ one of the users served by it). */
+ struct usermux *mux;
+
+ /* For mux nodes, 0, and for leaf nodes, the name under which the node was
+ looked up. */
+ struct usermux_name *name;
+
+ /* The translator associated with node, or if its a symlink, just the link
+ target. */
+ char *trans;
+ size_t trans_len;
+};
+
+error_t create_user_node (struct usermux *mux, struct usermux_name *name,
+ struct passwd *pw, struct node **node);
+
+#ifndef USERMUX_EI
+# define USERMUX_EI extern inline
+#endif
+
+#endif /* __USERMUX_H__ */
diff --git a/utils/ChangeLog b/utils/ChangeLog
deleted file mode 100644
index c2222747..00000000
--- a/utils/ChangeLog
+++ /dev/null
@@ -1,1152 +0,0 @@
-Wed Jul 31 14:23:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main/verify_passwd): Use #pragma weak instead of
- __attribute__ ((weak)).
- * su.c (check_password): Likewise.
-
- * login.c (options): Change --inherit-environ to --preserve-environment.
- Change --no-environ to --no-environment-args.
- Change --environ to --envvar and --environ-default to --envvar-default.
- * ps.c (options, main): Change --fmt to --format/-F.
- Change --posix-fmt/-o to --posix-format/-o.
- Change --sort to --sort/-s.
- Change --pgrp to --pgrp/-G.
- Change --login to --login/-L.
- Change --threads/-s to --threads/-T.
- Change --session to --session/-S.
- (OPT_FMT, OPT_SORT, OPT_PGRP, OPT_LOGIN, OPT_SESS): Macros removed.
- * w.c (options, main): Change --fmt to --format/-F.
- Change --sort to --sort/-s.
- (OPT_FMT, OPT_SORT): Macros removed.
-
-Wed Jul 31 14:24:05 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * login.c (main/verify_passwd): Declare crypt weak in a portable
- way.
- * su.c (check_password): Likewise.
-
-Tue Jul 30 14:49:48 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
-
- * login.c (main/verify_passwd): If government is broken, don't use
- crypt.
- * su.c (check_password): Likewise.
-
- * login.c (main/verify_passwd): Provide correct prototype for
- crypt.
- * su.c (check_password): Likewise.
-
-Mon Jul 29 03:22:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (val_t): Make `long long'.
-
-Sun Jul 28 21:13:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (main): Correctly parse the -w/--width option.
-
-Fri Jul 26 12:34:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (enum val_display_type): Add `PAGESZ'.
- `SIZES' -> `SIZE'; all uses updated. Remove BYTES, PAGES, and KBYTES.
- (fields): disp_type of "pagesize" and "swap-pagesize" changed to PAGESZ.
- (val_display_type_is_size): Function removed.
- (struct field): `disp_type' field -> `type'; all used updated.
- (print_val): Add TYPE & SIZE_UNITS arguments; remove HOW & PSIZE.
- (main): Variable user_disp_type removed. Variable size_units added.
- Add SIZE_UNITS macro, remove FDISPTYPE macro.
- Calls to print_val now use new PVAL macro.
- (get_vmstats_field): Just test against a type of SIZE, instead of
- using val_display_type_is_size.
-
-Thu Jul 25 22:36:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (INSTALL-vmstat-ops): New variable.
-
- * vmstat.c (options, main): -k/--kilobytes, -v/--pages, and
- -b/--bytes options added.
- (fields): New struct members initialized. `size',
- `cache-hit-ratio', `swap-size', `swap-active', `swap-free', and
- `swap-pagesize' added.
- (val_t, enum val_display_type, enum field_change_type): New types.
- (val_display_type_is_size, print_val, vm_state_refresh,
- vm_state_get_field, get_vmstats_field, get_size,
- ensure_def_pager_info, get_swap_size, get_swap_free,
- get_swap_page_size, get_swap_active): New functions.
- (struct field): CHANGE_TYPE, DISP_TYPE, STANDARD, and COMPUTE
- fields added. CUM field removed.
- (struct vm_state): New type.
- (main): Changed greatly to use vm_state type & functions, use
- print_val, and support CONST display types nicely.
- (argp_program_version): Version changed to 1.1.
-
-Sun Jul 21 03:00:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsysopts.c (main): Print an error for no args.
- * portinfo.c (main): For no args, use argp_usage.
- (options): Minor fixes.
-
-Sat Jul 20 15:54:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Deleted var (which was `shd.ChangeLog').
- (shd.ChangeLog): Deleted file.
-
-Fri Jul 19 21:09:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options): Rearrange slightly.
-
-Tue Jul 16 21:38:01 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * login.c (main): If chown fails, print error message using errno,
- not -1.
-
-Fri Jul 12 15:49:09 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (dog): Get rid of `Beware of dog' -- it can't ever happen.
- Rename watch_login calls to check_login; don't use return value.
- (check_login): Renamed from watch_login. Change type to void.
- Exit if there's no such process.
-
- * login.c (main): Only start a watchdog timer if in a new login coll.
-
- * login.c (watch_login): New function.
- (dog): Use watch_login. Get rid of wierd rules for root-gone-away.
-
- * Makefile (INSTALL-ps-ops, INSTALL-w-ops): New variables.
-
-Fri Jul 12 14:20:44 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (INSTALL-login-ops): New variable.
-
-Sun Jul 7 21:31:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * settrans.c (main): Don't use unsafe MOVE_SEND in call to
- file_set_translator.
-
-Sat Jul 6 18:06:52 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c, vmstat.c, hurdids.c, fsysopts.c, settrans.c,
- showtrans.c, storeinfo.c, login.c, w.c, ps.c
- (argp_program_version): New variable.
- * vmstat.c <hurd.h>: New include.
-
-Fri Jul 5 22:28:11 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Pass the the basename of TTY to getutline.
-
-Wed Jul 3 14:00:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Don't fill in ut_line or ut_type
- fields in UTMP.
- Fill in the ut_addr field.
-
- * Makefile (settrans): Depend on ../libports/libports.a.
-
-Tue Jul 2 14:54:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (dog): Include all args in the asprintf.
- Put the ARGV message in parens.
-
-Mon Jul 1 13:05:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (kill_login): Don't kill dog.
- (dog): Take new ARGV argument, and record status in it for ps.
- (main): Pass ARGV to dog.
-
- * w.c (_w_specs): Don't use utmp buffer sizes for field widths, as
- they can be very large.
-
- * login.c (add_utmp_entry): Always fill in UTMP.ut_line.
- Set UTMP.ut_type.
-
-Fri Jun 28 15:44:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Increment TTY_FD while searching for a
- TTY.
-
-Mon Jun 24 16:02:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Fix heuristic to decide whether native booted.
-
-Thu Jun 20 14:41:25 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * login.c (main): No need for EXEC_NEWTASK or EXEC_SECURE.
-
- * Makefile (getty): Remove rule.
- (targets): Remove `getty'.
- (SRCS): Remove getty.c.
- * getty.c: Removed file to daemons directory.
-
-Wed Jun 19 14:11:14 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (hurd_file_name_path_lookup): Declaration removed.
- (main: child_lookup): Pass 0 for new LOOKUP arg to
- hurd_file_name_path_lookup.
-
-Mon Jun 17 18:06:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (targets): Add `getty'.
- (SRCS): Add `getty.c'.
- (getty): Depend on -lutil.
-
-Mon Jun 17 10:41:28 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets): Remove reboot & halt.
- (SRCS): Remove reboot.c & halt.c.
- (login): Depend on -lutil instead of grot.
-
-Tue Jun 11 13:43:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (get_utmp_host): Function removed.
- (add_utmp_entry): Get rid of TTY_FD parameter. Don't search for
- the tty unless we need it to get the old host, since login does it
- for us.
- Also use the `existing host' in the case that a new one isn't specified.
- (main): Update call to add_utmp_entry.
-
- * login.c (dog): Don't print stupid message if login session is empty.
- (add_utmp_entry): Use gettimeofday instead of time to get the time.
-
-Wed May 29 11:01:18 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Don't use -z flag to login.
-
-Tue May 28 17:48:12 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Fetch the parent uids before checking their number.
- (dog): Don't kill session if the user logged in!
- Print newline before message.
- (check_owned): Return OWNED, not NOTOWNED.
-
- * ps.c (fmts): Use %sz for vmem format, not %size.
- (spec_abbrevs): Still use `NTH' for field name, just `TH' for title.
- (fmts): Use %nth.
-
-Tue May 21 12:18:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (print_store): Get rid of class-name printing code,
- and use store->class->name. Print all flags.
-
-Tue May 14 09:50:21 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (dog): Use error to print messages. Use pretty time fmting.
- (main): Fork login timeout watchdog before clearing the process owner.
-
- * login.c (main): Only allow real users to make new login collections.
-
-Mon May 13 18:10:43 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (options, main): Remove -z/--no-utmp option.
- (main): Only add utmp entry for session leader.
- Clear process owner if no uids.
- Fork self-destruct timer when appropiate.
- (default_args): Add NOAUTH_TIMEOUT entry.
- (check_owned, kill_login, dog): New functions.
-
-Sun May 12 13:38:34 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.c (psout): When printing result of ps_fmt_creation_error,
- don't pass ERR to error (it should already be in PROBLEM if necessary).
-
-Sat May 11 01:00:39 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (_parse_strlist, parse_strlist, parse_numlist, lookup_user,
- main): Slather on consts, in a misguided attempt to shut up the
- compiler.
-
-Fri May 10 13:53:30 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devprobe.c (parse_opt): Use ARGP_ERR_UNKNOWN instead of EINVAL.
- * showtrans.c (parse_opt): Likewise.
- * portinfo.c (parse_opt): Likewise.
- * ps.c (parse_opt): Likewise.
- * settrans.c (parse_opt): Likewise.
- * login.c (parse_opt): Likewise.
- * hurdids.c (parse_opt): Likewise.
- * fsysopts.c (parse_opt): Likewise.
-
- * showtrans.c (parse_opt): Print a usage msg with no args.
- (options, main): Add --translated/-t option.
-
- * Makefile (storeinfo): Depend on ../libstore/libstore.a.
-
- * settrans.c (main): Remove const cast from first arg to argz_create.
- * fsysopts.c (main): Likewise.
- * login.c (main): Likewise.
- (main): Remove const from decl of USER & ARG.
- (fail): Remove const from decl of VIA.
-
- * ps.c (parse_strlist): Make DEFAULT_FN return a const char *.
-
- * storeinfo.c (print_store): New function.
- (info): Use store_create to make a store and print_store to print it.
- (parse_opt): Print a usage message for no args.
- (options, parse_opt): Add --children option.
-
-Thu May 9 19:46:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * w.c (uptime): Cast arg to localtime appropriately.
-
- * login.c (add_utmp_entry): Declare HOST `char const *'.
- (main) [fail]: Declare VIA `char const *'.
- (main): Declare USER `char const *'.
- Declare ARG `char const *'.
-
- * login.c (main): Provide new third arg to proc_setowner.
-
- * fsysopts.c (main) [parse_opt]: Cast first arg of argz_create
- appropriately.
- * settrans.c (main) [parse_opt]: Likewise.
- * login.c (main) [parse_opt] [case ARGP_KEY_ARG]: Likewise.
- (main): Likewise.
-
- * ps.c (main) [current_tty_name]: Remove `const' keyword to avoid
- type clash.
-
- * ps.c (main) [proc_stat_has_ctty]: Add parentheses around
- assignment used as truth value.
-
-Mon May 6 17:36:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.c (psout): Take a field, not a spec. Honor PS_FMT_FIELD_KEEP.
-
- * w.c (w_user_getter): New function.
- (w_get_user): New function.
- (w_fetch): Implement W_PSTAT_USER.
- (struct w_hook): Add user field.
- (_w_specs): Add "Name" entry.
- (w_get_uname): Renamed from w_get_user.
- (w_uname_getter): Renamed from w_user_getter.
- * ps.c (fmts): Upcase most format strings.
-
-Sun May 5 01:05:54 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.h: New file.
- * ps.c (fmts): Use new field syntax.
- (options): Add -o/--posix-fmt option. -A is an alias.
- "psout.h": New include.
- * w.c (_w_specs): Add precision & keep fields.
- (DEFAULT_FMT_STRING): Use new field syntax.
- "psout.h": New include.
- (main): Update call to psout.
- * psout.c (psout): Add posix_fmt arg.
-
-Thu May 2 00:10:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * psout.c (psout): Use ps_fmt_creation_error to find out in detail
- why ps_fmt_create fails.
-
-Wed May 1 19:53:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (main): Default KILL_ACTIVE to 0.
-
-Tue Apr 30 19:04:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (_w_specs): Use ps_emit_past_time to show login times.
-
-Tue Apr 30 09:47:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
-
- * Makefile (all): Remove target.
- (include ../Makeconf): Place before all dependencies.
- ($(targets)): Each separate target should depend on its own .o.
-
-Tue Apr 23 13:49:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Try to intuit whether this is a native-booted hurd
- system, and if so, don't filtered out non-parented processes.
-
-Wed Apr 10 19:47:45 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * devprobe.c: New file.
- * Makefile (targets): Add devprobe.
- (SRCS): Add devprobe.c.
-
-Mon Apr 8 17:09:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (options, doc): Change meaning of --translate's
- argument, in preparation for other changes.
- (options, main): Add, but don't really implement, --search option.
-
-Fri Mar 29 14:37:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options): Add --exclusive option, change descriptions.
- (main): Rearrange meanings of arguments somewhat.
-
-Thu Mar 28 13:58:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (main): Use new names for functions, and pass stdout.
- (port_info, ports_info, xlated_port_info, xlated_ports_info,
- name_xlator_create, name_xlator_free, name_xlator_xlate):
- Functions removed (renamed and put in libshouldbeinlibc).
-
- * portinfo.c (parse_task): Use strtoul instead of atoi so pid 0 works.
-
-Mon Mar 25 14:19:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (uptime): Correctly calculate uptime.
- (...various...): Use real types instead of old ps typedefs.
- * ps.c (spec_abbrevs): Make const.
- (ps_specs): Make non-const.
- (...various...): Use real types instead of old ps typedefs.
- * psout.c (psout): Use real types instead of old ps typedefs.
-
-Sat Mar 23 01:02:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (uptime): Add a temporary hack to pretend to show uptime.
-
-Mon Mar 18 18:34:51 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Pass new arg to argp_parse.
- * w.c (main): Likewise.
- * storeinfo.c (main): Likewise.
- * fsysopts.c (main): Likewise.
- * hurdids.c (main): Likewise.
- * login.c (main): Likewise.
- * vmstat.c (main): Likewise.
- * showtrans.c (main): Likewise.
- * settrans.c (main): Likewise. Also use argp_usage correctly.
- * portinfo.c (main): Likewise.
-
-Tue Mar 5 14:17:22 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (main): Fix arg order to name_xlator_create.
- (name_xlator_create): Return X in XLATOR.
- (name_xlator_free): Deallocate all ports in X too.
- (main): Use xlated_port_info / xlated_ports_info.
- (xlated_port_info, xlated_ports_info): New functions.
- (struct name_xlator, name_xlator_create, name_xlator_xlate): Don't
- depend on a specified receive/send type for the source being specified.
- (name_xlator_xlate): Take FROM_TYPE arg, & return TO_TYPE.
- (options, main): Get rid of -R/-S options, and add --translate/-t
- option.
-
-Mon Mar 4 15:25:41 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * portinfo.c (struct name_xlator): New structure.
- (name_xlator_create, name_xlator_free, name_xlator_xlate): New funcs.
- (options, main): Add --translate-{receive,send}/-R/-S options.
-
-Fri Mar 1 18:55:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets, SRCS): Add portinfo & portinfo.c.
-
-Tue Feb 27 14:51:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets, SRCS): Remove clri & clri.c.
-
-Mon Feb 26 13:50:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (main): Don't print a newline after `Pausing...' msg.
-
- * ps.c: Include <error.h> instead of "error.h".
- "common.h": Don't include this anymore.
-
-Wed Feb 21 11:47:01 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu>
-
- * w.c (uptime): Use %.2f format for load average numbers.
-
-Mon Feb 19 15:49:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (STRINGIFY): Make work. Is this in a header somewhere?
- (_STRINGIFY): New macro. Ick.
-
- * fsysopts.c (main): Use ARGP_IN_ORDER.
-
-Sat Feb 17 23:47:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * uptime.sh: New file.
- * Makefile (targets, special-targets): Add uptime.
- (SRCS): Add uptime.sh.
-
-Thu Feb 15 15:47:45 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Don't make -a imply -g.
-
- * sush.sh: Change -aBACKUP_SHELL to -aBACKUP_SHELLS.
-
- * login.c (child_lookup): Pass last arg to hurd_file_name_path_lookup.
-
-Wed Feb 14 17:38:31 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * w.c (add_utmp_procs): Correctly add terminal processes using new
- libps functionality.
- (read_utmp_procs): Emit all utmp entries, even the last one.
-
- * ps.c (main): Get rid of totally dead processes/threads.
- (add_pid): Complain about non-existant processes.
- (psout): New declaration.
-
- * ps.c (parse_numlist): Correctly handle NULL hook functions.
- (parse_opt): Deref STATE correctly.
- (main): Update calls to changed proc_stat_list_add_* functions.
-
- * login.c (main): Don't set old SAW_USER_ARG variable.
-
-Tue Feb 13 13:54:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Exec login.
-
- * login.c (main): Deal with the shell args reasonably.
-
- * ps.c (parse_opt): Don't turn quoted args into options.
-
-Mon Feb 12 14:54:38 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options, main): Add --timeout/-t option.
- (main): Pass ARGP_IN_ORDER to argp_parse (it's no longer the
- default), and deal with the fallout.
-
-Wed Feb 7 23:11:10 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Allow switches in the login args naturally.
-
-Mon Feb 5 14:18:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (main, args_doc, doc): Add repeat mode.
- (FVAL): New macro.
-
- * vmstat.c (main): Slightly decrease the space for numbers in the
- verbose output format.
- Twiddle the widths of the terse fields to make sure there's room
- for typical numbers.
-
-Sat Feb 3 01:28:20 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * vmstat.c (fields, options): Make const.
-
- * vmstat.c: New file.
- * Makefile (targets): Add vmstat.
- (SRCS): Add vmstat.c
-
- * login.c (main): Correctly add gids.
- Avoid duplicating the old real id when keeping the old ids.
- Don't ask for a password unnecessarily.
-
-Thu Feb 1 19:15:53 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Don't save the parent ids.
-
- * login.c (main): When the user is specified as the first
- argument, always add it as both effective, real, and saved ids,
- even if there are others already.
-
- * login.c (main): Get the ttyname to chown.
- Only do the chown if NO_LOGIN isn't set.
-
- * settrans.c (options, main): Add --pause option.
-
-Thu Feb 1 16:27:24 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * login.c (main): Chown the terminal.
-
-Tue Jan 30 15:25:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Put LOGNAME in the environ even if it was already.
- (copied_args): Add "USER".
-
-Mon Jan 29 09:52:08 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_utmp_entry): Get rid of declaration for login().
- (main, default_args): Replace the BACKUP_SHELL param with
- BACKUP_SHELLS, which is a list of things to try. The default
- includes both bash and the /bin/sh.
- (main): Try to set the default path using confstr().
-
-Mon Jan 15 12:29:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options, main): Make -g/--goaway only apply to
- active translators.
- (options): Rearrange a bit.
-
-Sun Jan 14 12:45:40 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Call setlogin().
-
-Thu Jan 11 19:30:27 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (options, main): Change the -R/--retry option so that
- the optional argument is an argument to add to those passed to
- login when retrying, and remove all the hardwired arguments
- (except propagating -h/--via).
- (default_args, options, main): Get rid of the -n/--nobody option
- and variables, making it an additional login parameter.
-
- * login.c (default_args): Make the default shell /bin/bash instead of
- _PATH_BSHELL.
- (default_args, default_env): Make the default path just /bin.
-
- * loginpr.sh (user): Pass the appropiate -R options to login.
-
-Wed Jan 10 15:32:19 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Turn on RETRY when the -h option is specified.
-
-Fri Jan 5 15:21:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_canonical_host): Try harder to get the actual host name.
-
-Thu Jan 4 22:37:46 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (add_canonical_host): New function.
- (add_utmp_entry): Use VIA_ADDR instead of VIA in the utmp entry if
- it fits better.
- (add_entry): Function moved out of main.
- (main): Use add_canonical_host() to implement the -h option. Only
- let root specify the login host.
-
- * login.c (main): child_lookup() now takes an additional PATH arg,
- and calls hurd_file_name_path_lookup() instead. Pass a path when
- looking up the shell executable.
-
-Tue Jan 2 01:15:13 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * sush.sh: Instead of giving --su to login, use all the component
- options it stood for. Also use --program-name for nice errors.
-
- * login.c (main): Do all file-name lookups using the target
- authentication, so that login isn't a security hole.
- Rework how password-checking is done somewhat (only ask when necess).
- Call exec_reauth() with SECURE==0 so that it reauths all the ports.
- If setting the real [ug]id, also add it as the `saved id'.
- (cat): Take an io_t port instead of a file descriptor.
- (options, main): Get rid of the -s/--su option, and add -S/--shell-arg.
- (FAILURE_SHELL): Macro deleted.
- (default_args): Add BACKUP_SHELL param.
- (main): Use BACKUP_SHELL instead of FAILURE_SHELL define.
-
-Mon Jan 1 20:51:41 1996 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main): Use exec_reauth() instead of our own.
- (options, main): Add -k/--keep & -s/--su options.
- (options, main): Remove -m/--umask option; use UMASK param instead.
- (main): Get rid of various string vars only used once.
-
-Fri Dec 29 12:16:13 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * loginpr.sh: New program.
- * login.c (main): Add optional shell argument for --retry.
- Add --paranoid/-P option.
-
- * login.c (main): Don't ask for password by name if only one user.
-
-Thu Dec 28 17:41:11 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c (main, options): Add --retry/-R option.
-
- * login.c (main): If -f/--no-passwd is specified, get rid of the
- effect of the login executable being setuid/gid.
- Only set the shell proc's owner to an effective uid.
-
-Sun Dec 24 14:26:18 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Move a bunch of stuff into psout() in psout.c.
- * psout.c: New file.
-
-Sat Dec 23 20:49:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Allow user to use `-' prefix to invert sort as well.
- (main): Use ps_fmt_set_output_width() to set the output width.
-
- * login.c (add_utmp_entry): Only remove a prefix from the tty name
- if it's _PATH_DEV.
-
-Thu Dec 21 11:15:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (spec_abbrevs, ps_specs): New variables.
- (fmts): Get rid of redundant header specifications.
- (fmt_sortrevs): Variable removed.
- (main): Don't allow sorting on field names any more, just spec
- names (prob ok, since most things ps prints are now spec names).
- (main, options): Rename -o flag to -U for posix compat (ick).
-
- * login.c (options): Add --no-utmp/-z option.
- (add_utmp_entry): New function.
- (main): Call add_utmp_entry().
- (main): Ivec routines are now idvec routines.
- Include <idvec.h> instead of <ivec.h>.
- (options): --host/-h is now --via/-h.
- (main): Store the host were logged in from via in VIA, in the
- login parameters instead of the child environment; optionally copy
- it into the environment too.
- (main): Enable EXEC_SECURE.
- * Makefile (libutil-libsubst): New hack.
- (login): Depend on -lutil.
-
- * ps.c (main): Ivec routines are now idvec routines.
- Include <idvec.h> instead of <ivec.h>.
- Use argz functions to store tty_names instead of our own.
-
-Sun Dec 17 00:24:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main, options): If the specified sort field begins with
- `-', reverse the sort.
-
- * ps.c (main): If there is no current uid, don't try to filter with it.
- (FILTER_NOT_LEADER): Renamed from FILTER_NSESSLDR.
- (main): Rename ps_not_leader_filter from ps_not_sess_leader_filter.
-
- * ps.c (main): Use ivec routines instead of ids.
- (make_ids, ids_add, ids_contains): Routines deleted.
- Include <ivec.h>.
-
-Sat Dec 16 22:13:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (options): Reformat doc string for --tty option.
-
- * ps.c (options): Add argument and doc for 'w' option.
- (main): Implement 'w' option.
-
- * login.c: Zillions of changes.
-
-Tue Dec 12 20:16:22 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * login.c: New file.
- * Makefile (SRCS): Add login.c
- (targets): Add login.
- (login): Depends on ../libshouldbelibc/libshouldbelibc.
-
-Wed Dec 6 15:12:15 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsysopts.c (main): Supply the new SEP argument to argz_stringify.
- * showtrans.c (main): Ditto.
-
- * fsysopts.c (main): Change uses of the INDEX field in argp_state
- structures to use NEXT instead.
- * ps.c (main): Ditto.
- * settrans.c (main): Ditto.
- * showtrans.c (main): Ditto. Fix default prefix-printing test.
- * storeinfo.c (main): Ditto.
-
-Mon Dec 4 15:41:06 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (main): Correctly whether to print prefix by default.
- (options): Fix help strings.
-
-Wed Nov 15 19:56:21 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Use new libps stream type.
-
-Tue Nov 14 18:28:20 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Grow TTY_NAMES properly even when it's empty.
-
-Mon Nov 6 12:41:21 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (ids_add): Increase the size of IDS even when 0.
-
- * fsysopts.c (main): Use file_get_fs_options, not fsys_get_options.
- (doc): `filesystem' --> `FILESYS'.
-
-Sat Nov 4 19:56:38 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (print_info): Use the new FLAGS argument to
- file_get_storage_info. Add new storage types.
-
-Wed Nov 1 19:30:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (main): Change to use the new wierd callback
- interface to fshelp_start_translator.
-
- * ps.c (options): Add --not-owner/-O option.
- (id_t, struct ids): New type.
- (make_ids, ids_add, ids_contains): New functions.
- (main): Use a struct ids instead of multiple variables to hold the
- wanted uids list, which renamed to ONLY_UIDS. Add the NOT_UIDS
- list to contain the opposite sense, and use it.
-
- * ps.c (main): Use proc_stat_proc_info instead of proc_stat_info and
- PSTAT_PROC_INFO instead of PSTAT_INFO.
-
-Tue Oct 31 17:57:25 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * fsysopts.c (doc, args_doc): Mention usage without any options.
- (main): If no options are supplied, print existing options.
-
- * ps.c (fmts): Add RPC field to the -l format.
-
-Mon Oct 30 16:24:37 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (options): --all is -e, not -a.
-
-Mon Oct 23 15:17:42 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (options): Change --force/-f to --goaway/-g. Add
- flags for killing translators: --recurse/-r, --force/-f, --nosync/-S.
- (doc): New variable.
- (main): Support new flags. Have some of the options update flag
- words instead of setting variables.
-
- * storeinfo.c (print_info): Calculate total size/blocks correctly.
-
-Fri Oct 20 15:44:45 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * settrans.c (args_doc): New variable.
- (main): Set ARGZ inside of parse_opt.
-
- * fsysopts.c (options): FILE --> FILESYS in help msg.
- (args_doc): OPTION --> FS_OPTION, since the usage message already
- uses OPTION to mean those to fsysopts.
- (doc): New variable; give some common choices for FS_OPTION.
-
-Thu Oct 19 19:07:26 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (parse_enum): Use argp_error.
-
-Thu Oct 12 15:22:24 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (parse_enum): Use ARGP_HELP_STD_ERR.
-
-Wed Oct 11 19:03:19 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * ps.c (main): Use realloc on a variable in main instead of
- alloca, since the storage gets used after parse_opt returns.
-
- * fsysopts.c (main): Use argp_help instead of argp_usage.
-
-Tue Oct 10 15:02:17 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * showtrans.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- (arg_doc, doc): New variables.
- Include <argp.h> not <getopt.h>.
- * fsysopts.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- (arg_doc): New variable.
- Include <argp.h> not <getopt.h>.
- * settrans.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- Include <argp.h> not <getopt.h>.
- * ps.c (options): Converted to argp format.
- (main): Use argp, not getopt.
- (usage, USAGE, SHORT_OPTIONS): Deleted.
- (arg_doc, doc): New variables.
- Include <argp.h> not <getopt.h>.
-
-Fri Oct 6 17:33:01 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * storeinfo.c (print_info): Use the new block_size value returned
- from file_get_storage_info.
-
-Wed Oct 4 18:15:59 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * showtrans.c (usage, options, main): Change -h/--no-header options to
- -p/--prefix and -P/--no-prefix.
- (main): Unless overridden by -p/-P, only print a FILE: prefix when
- there are multiple files on the command line.
-
-Mon Oct 2 19:00:27 1995 Miles Bader <miles@gnu.ai.mit.edu>
-
- * Makefile (targets): Add storeinfo.
- (SRCS): Add storeinfo.c.
-
-Fri Sep 1 11:35:12 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * settrans.c (main): Use fshelp_start_translator instead of
- start_translator from ../lib.
- * Makefile: Get rid of rules related to ../lib.
- (settrans): Depend on libfshelp.a instead of starttrans.o.
-
-Thu Aug 24 10:44:17 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (all): New target.
- (ps, settrans, showtrans, fsysopts): Put all dependencies in these
- targets.
- (settrans-HURDLIBS, showtrans-HURDLIBS, ps-HURDLIBS): Removed.
-
-Tue Aug 22 17:56:09 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (settrans-HURDLIBS, showtrans-HURDLIBS, ps-HURDLIBS):
- Add libshouldbeinlibc.
- (settrans, showtrans, fsysopts, ps): Get rid of things that are
- now in libshouldbeinlibc.
- Get rid of rules dealing with error.o.
-
-Sun Jul 23 15:58:06 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): sh.ChangeLog -> shd.ChangeLog.
-
-Fri Jul 7 19:20:21 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * clri.c (copyright, sccsid): Correct syntax.
-
-Fri Jul 7 18:56:45 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * settrans.c (SHORT_OPTIONS): Remove '?' as getopt usurps it.
- (options, main): Use '&' instead of '?' to mean help.
-
-Thu Jul 6 21:04:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * su.c (main, apply_auth_to_loginid, apply_auth_to_pgrp): Remove
- assignments from inside if tests.
-
- * sync.c (main): Declare return type.
-
- * clri.c (copyright, sccsid): Declare unused.
- (main): Correct format for fourth arg in printf call.
-
- * ps.c (lookup_user): Declare return to be `int' to avoid type
- clash in use as 4th parameter to parse_numlist.
-
- * shd.c (run): Remove assignments from inside if tests.
- (command): Likewise.
-
- * Makefile (special-targets): New var.
- (mount): Provide command.
- (OBJS): New var.
- (shd, su, clri, sync, reboot, halt): List object files here.
-
-Thu Jul 6 16:12:22 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * settrans.c (main): Give an error message instead of dying when
- no filename argument is given.
-
-Thu Jul 6 15:43:15 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile: Removed dependencies that are now automatically
- generated.
-
-Wed Jul 5 21:18:42 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (ps-HURDLIBS): Renamed from HURDLIBS.
- (ps): Fix dependencies.
-
-Mon Jun 26 16:13:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (CPPFLAGS): Put -I../lib back in.
- Put back the vpath for %.c to ../lib.
-
-Tue Jun 6 13:22:52 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (HURDLIBS): Added libihash.
- (CPPFLAGS): Deleted addition of -I../lib.
- (vpath): Deleted spec.
- (ps): Deleted ihash.o and primes.o.
-
-Thu Jun 1 11:33:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile (ps.o, fsysopts.o, showtrans.o, settrans.o): Add
- dependencies on header files.
- (REMHDRS): Define this variable.
-
-Tue May 30 12:17:33 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (SCRS): Removed update.c.
- (targets): Removed update.
-
-Sat May 20 00:51:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * fsysopts.c (main): Check for a missing filesystem name.
- (main): Tweak the error msgs a bit.
-
- * fsysopts.c (options, main): Don't use '?' as the --help key.
-
-Mon May 15 20:31:31 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * Makefile (SRCS, targets): Add fsysopts.
-
-Wed May 3 11:37:39 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main, usage, SHORT_OPTIONS, options): Add the -n flag
- (--nominal-fields), which prevents elision of uninteresting fields.
- Also add elision of uninteresting fields...
-
-Tue May 2 17:22:11 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
-
- * ps.c (fmts): Add the SC (suspend count) field to various output fmts.
- (usage, main, SHORT_OPTIONS): Add the (ignored) -w flag for BSD compat.
- (main): Use the new name for ps_fmt_squash: ps_fmt_squash_flags.
-
-Tue May 2 14:37:07 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * shd.c (reap): Check for ECHILD, not ESRCH.
-
-Wed Apr 26 21:40:57 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * settrans.c (main): Allow options before and immediately after
- the node name to be rearranged by getopt without affecting those
- following the translator name.
-
-Fri Apr 14 10:18:34 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * mount.sh: Move the test for a valid translator to just before we
- use it. Gratuitously change the "unknown" value for type to "".
- Don't use `--' when invoking settrans, as getopt doesn't seem to
- be handling it correctly. Use `usage' not `USAGE'.
-
-Wed Apr 12 14:38:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (DIST_FILES): Omit ps.ChangeLog.
-
-Tue Apr 11 15:21:46 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (targets): Changed `sh' to `shd'.
- (SRCS): Changed `sh.c' to `shd.c'.
- * shd.c: Renamed from `sh.c'.
-
-Mon Apr 10 20:01:20 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Tweak things so that the -t flag works correctly
- for processes whose tty we can't figure out.
-
-Sun Apr 9 14:00:09 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
-
- * su.c (main): Getopt now returns '\001' for non-switch options
- instead of '\0', no doubt to work around an obscure bug in some
- brain-dead system only used by 2 people twice a decade.
-
-Fri Apr 7 11:55:25 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (parse_enum): Renamed from enum_name.
- (main, usage): Add lots of sysvish options, and generalize some
- existing ones to deal with sysvish usage. Make -t & -o work.
-
-Thu Apr 6 11:56:23 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Add the `jobc' (-j) output format from netbsd.
-
-Wed Apr 5 22:10:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): When processes are specified on the command line by PID,
- turn off all filtering so that they don't disappear later. Also
- minor changes in some spec names.
-
-Tue Apr 4 11:32:53 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
-
- * Makefile: Add showtrans & mount, and uncomment-out su.
-
- * settrans.c (main): Get rid of the `show passive translator'
- functionality, as this is now done by showtrans.
-
- * ps.c (main): Make -a imply -g as well, to be compatible with bsd.
- Add the -M (--no-msg-port) switch, which disables all fields that
- would use any process's message port.
-
- * showtrans.c: New file: Show passive translators.
-
- * su.c (apply_auth): Use msg_add_auth & msg_del_auth instead of
- add_auth & del_auth.
- (apply_auth_to_pids, apply_auth_to_loginid, apply_auth_to_pgrp):
- Don't use the IDS variable, it's no longer around; I think AUTH is
- the right thing to replace it with.
-
-Tue Apr 4 01:47:57 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Treat argument without leading - as if it had one,
- unless it's a number.
-
-Mon Mar 20 20:17:04 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
-
- * Makefile (ps): Link in ihash.o, error.o, and primes.o too.
- * Makefile (vpath %.c): New decl.
-
- * ps.c: Include <hurd/ps.h> instead of "ps.h".
- Include <unistd.h>.
- (enum_name): Avoid warning.
- (program_name): New variable.
- (main): Don't set program_invocation_short_name (the library does it
- for us). Do set program_name.
-
- * ps.c: Replace with new version by Miles Bader. See ps.ChangeLog
- for some changes made to the new version before the replacement.
- Old ps.c and ps.ChangeLog are now ps.c.old and ps.ChangeLog.old.
- * Makefile (HURDLIBS): Define, for ps.
- (CPPFLAGS): Define, for ps.
- (ps): Add rule to get library.
-
-Sat Jan 28 15:02:08 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * sh.c (main): Only open /dev/tty if stdin is unreadable.
-
-Wed Nov 16 20:28:40 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * reboot.c: Include unistd.h, stdio.h, not hurd/anything.
- (main): If reboot returns, give error message and return 1.
- * halt.c: Likewise.
-
-Sat Nov 12 21:20:07 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * reboot.c (main): Just use the reboot function.
- * halt.c (main): Likewise.
-
-Fri Nov 11 12:05:38 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * Makefile (targets): Added reboot and halt.
- (SRCS): Added reboot.c and halt.c.
- * reboot.c: New file
- * halt.c: New file.
-
- * ps.c (main): Print in shorter format by default; take -v flag to
- print in longer format.
-
-Wed Nov 9 04:43:54 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * ps.c (time_str): Specify format for decimals correctly.
-
-Wed Nov 9 00:20:09 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * ps.c (time_str): Use %.2d instead of %2d to get 0 pads.
-
-Mon Nov 7 14:15:10 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * ps.c (time_str): Don't use floating point conversion;
- it's buggy.
-
-Wed Nov 2 13:34:56 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * sync.c: New file.
- * Makefile (targets): Added sync.
- (SRCS): Added sync.c.
-
-Thu Oct 27 22:19:29 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * ps.c (main): Also print out a field with the number of threads.
-
-Tue Oct 4 19:40:22 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * clri.c: New file.
- * Makefile (targets): Added clri.
- (SRCS): Added clri.c.
-
-Sat Oct 1 03:44:55 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * update.c: Take optional arg to specify sleep time.
- Use daemon instead of doing its work by hand.
-
-Fri Sep 30 11:53:53 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
-
- * update.c: New file.
- * Makefile (SRCS): Added update.c.
- (targets): Added update.
-
-Sat Sep 10 08:22:34 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * settrans.c (main): Give usage message when given no args.
- Use O_NOTRANS in file name lookup.
- Don't use FS_TRANS_EXCL in file_set_translator.
- If given args "FILE -show", get translator and print it out.
-
-Thu Sep 1 11:50:51 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * settrans.c: New file.
- * Makefile (SRCS): Added settrans.c.
- (targets): Added settrans.
-
-Tue Aug 30 16:40:54 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * sh.c (run): Use file_name_lookup instead of path_lookup.
-
-Tue Aug 23 10:44:16 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile (targets): Comment out `su' until Roland gets it back
- into a usable state.
-
-Mon Aug 22 12:18:09 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * sh.c (main): Open /dev/tty with O_IGNORE_CTTY and fdopen that
- onto stdin/out/err.
-
-Fri Jul 22 12:26:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
-
- * Makefile: Rewritten to use new scheme.
-
diff --git a/utils/Makefile b/utils/Makefile
index ebbc8d06..3f3307f4 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -1,5 +1,5 @@
-#
-# Copyright (C) 1994, 1995, 1996 Free Software Foundation
+#
+# Copyright (C) 1994,95,96,97,98,99,2000,01,02 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
@@ -18,36 +18,66 @@
dir := utils
makemode := utilities
-targets = shd ps settrans showtrans sync su mount fsysopts \
- storeinfo login w uptime hurdids loginpr sush vmstat portinfo \
- devprobe
-special-targets = mount loginpr sush uptime
-SRCS = shd.c ps.c su.c settrans.c sync.c showtrans.c \
- mount.sh fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \
- uptime.sh psout.c hurdids.c vmstat.c portinfo.c devprobe.c
-
-OBJS = $(filter-out loginpr.sh mount.sh sush.sh uptime.sh,$(SRCS:.c=.o))
+targets = shd ps settrans showtrans syncfs fsysopts \
+ storeinfo login w uptime ids loginpr sush vmstat portinfo \
+ devprobe vminfo addauth rmauth unsu setauth ftpcp ftpdir storecat \
+ storeread msgport rpctrace mount gcore fakeauth fakeroot
+special-targets = loginpr sush uptime fakeroot
+SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
+ fsysopts.c storeinfo.c login.c loginpr.sh sush.sh w.c \
+ uptime.sh psout.c ids.c vmstat.c portinfo.c devprobe.c vminfo.c \
+ parse.c frobauth.c frobauth-mod.c setauth.c pids.c nonsugid.c \
+ unsu.c ftpcp.c ftpdir.c storeread.c storecat.c msgport.c \
+ rpctrace.c mount.c gcore.c fakeauth.c fakeroot.sh
+LCLHDRS = psout.h parse.h pids.h frobauth.h
-# This hack to get around ickiness in Makeconf
-libutil-libsubst = -lutil
+OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
+HURDLIBS = ps ihash store fshelp threads ports ftpconn shouldbeinlibc
+login-LDLIBS = -lutil $(LIBCRYPT)
+addauth-LDLIBS = $(LIBCRYPT)
+setauth-LDLIBS = $(LIBCRYPT)
INSTALL-login-ops = -o root -m 4755
+INSTALL-ids-ops = -o root -m 4755
INSTALL-ps-ops = -o root -m 4755
INSTALL-w-ops = -o root -m 4755
-INSTALL-vmstat-ops = -o root -m 4755
include ../Makeconf
-login: -lutil # /gd4/hurdinst/lib/libutil.a # ick ick ick ick
+ps addauth rmauth setauth unsu msgport: parse.o pids.o
+login addauth setauth: nonsugid.o
+addauth rmauth setauth unsu: frobauth.o
+rmauth setauth unsu: frobauth-mod.o
ps w: psout.o ../libps/libps.a ../libihash/libihash.a
-storeinfo: ../libstore/libstore.a
+
+storeinfo storecat storeread: ../libstore/libstore.a
+ftpcp ftpdir: ../libftpconn/libftpconn.a
+
# We must include libthreads because of a bug in the way shared libraries
# work: all libraries that *any* routine in libfshelp uses must be defined.
settrans: ../libfshelp/libfshelp.a ../libports/libports.a ../libthreads/libthreads.a
-ps w hurdids settrans showtrans fsysopts storeinfo login vmstat portinfo \
- devprobe: ../libshouldbeinlibc/libshouldbeinlibc.a
-
-%: %.sh
- cp $< $@
+ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \
+ devprobe vminfo addauth rmauth setauth unsu ftpcp ftpdir storeread \
+ storecat msgport mount: \
+ ../libshouldbeinlibc/libshouldbeinlibc.a
$(filter-out $(special-targets), $(targets)): %: %.o
+
+rpctrace: ../libthreads/libthreads.a \
+ ../libports/libports.a ../libihash/libihash.a
+rpctrace-CPPFLAGS = -DDATADIR=\"${datadir}\"
+
+fakeauth: authServer.o auth_requestUser.o interruptServer.o \
+ ../libthreads/libthreads.a \
+ ../libports/libports.a ../libihash/libihash.a \
+ ../libshouldbeinlibc/libshouldbeinlibc.a
+auth-MIGSFLAGS = -imacros $(srcdir)/../auth/authmutations.h
+fakeauth-CPPFLAGS = -I$(srcdir)/../auth
+authServer-CPPFLAGS = -I$(srcdir)/../auth
+auth_requestUser-CPPFLAGS = -I$(srcdir)/../auth
+
+mount: ../sutils/fstab.o ../sutils/clookup.o \
+ $(foreach L,fshelp ports,../lib$L/lib$L.a)
+../sutils/fstab.o ../sutils/clookup.o: FORCE
+ $(MAKE) -C $(@D) $(@F)
+FORCE:
diff --git a/utils/addauth.c b/utils/addauth.c
new file mode 100644
index 00000000..0932a33f
--- /dev/null
+++ b/utils/addauth.c
@@ -0,0 +1,100 @@
+/* Add authentication to selected processes
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <argp.h>
+#include <idvec.h>
+#include <ugids.h>
+#include <error.h>
+#include <hurd.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (addauth);
+
+static struct argp_child child_argps[] = {{ &frobauth_ea_argp }, { 0 }};
+
+static char doc[] =
+ "Add new user/group ids to the authentication of selected processes";
+
+extern error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids);
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+ error_t err;
+ auth_t auth;
+ char *ids_rep = 0;
+ process_t proc_server = getproc();
+ struct frobauth frobauth = FROBAUTH_INIT;
+ struct idvec have_uids = IDVEC_INIT, have_gids = IDVEC_INIT;
+ struct argp argp = { 0, 0, 0, doc, child_argps };
+
+ frobauth.require_ids = 1;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ /* See what the invoking user is authorized to do. */
+ err = get_nonsugid_ids (&have_uids, &have_gids);
+ if (err)
+ error (52, err, "Cannot get invoking authentication");
+
+ /* Check passwords. */
+ err = ugids_verify_make_auth (&frobauth.ugids, &have_uids, &have_gids, 0, 0,
+ 0, 0, &auth);
+ if (err == EACCES)
+ error (15, 0, "Invalid password");
+ else if (err)
+ error (16, err, "Authentication failure");
+
+ if (frobauth.verbose)
+ /* A string showing which ids we will add. */
+ ids_rep = ugids_rep (&frobauth.ugids, 1, 1, 0, 0, 0);
+
+ /* Add the new authentication to each process. */
+ for (i = 0; i < frobauth.num_pids; i++)
+ {
+ mach_port_t msgport;
+ pid_t pid = frobauth.pids[i];
+ error_t err = proc_getmsgport (proc_server, pid, &msgport);
+
+ if (err)
+ error (0, err, "%d: Cannot get message port", pid);
+ else
+ {
+ if (! frobauth.dry_run)
+ err = msg_add_auth (msgport, auth);
+ if (err)
+ error (0, err, "%d: Cannot add authentication", pid);
+ else if (frobauth.verbose)
+ printf ("%d: Added %s\n", pid, ids_rep);
+ mach_port_deallocate (mach_task_self (), msgport);
+ }
+ }
+
+ return 0;
+}
diff --git a/utils/devprobe.c b/utils/devprobe.c
index e29e1e32..d7020322 100644
--- a/utils/devprobe.c
+++ b/utils/devprobe.c
@@ -1,6 +1,6 @@
/* Check the existence of mach devices
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -20,11 +20,13 @@
#include <stdio.h>
#include <argp.h>
-#include <error.h>
#include <hurd.h>
#include <mach.h>
#include <device/device.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (devprobe);
static const struct argp_option options[] = {
{"silent", 's', 0, 0, "Don't print devices found"},
@@ -33,19 +35,19 @@ static const struct argp_option options[] = {
{0}
};
static const char *args_doc = "DEVNAME...";
-static const char *doc = "The exit status is 0 if any devices were found.";
+static const char *doc = "Test for the existence of mach device DEVNAME..."
+ "\vThe exit status is 0 if any devices were found.";
int
main (int argc, char **argv)
{
- error_t err;
- mach_port_t device_master;
/* Print devices found? (otherwise only exit status matters) */
int print = 1;
/* If printing, print all devices on the command line that are found.
Otherwise, just the first one found is printed. */
int all = 1;
int found_one = 0;
+ mach_port_t device_master = MACH_PORT_NULL;
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
@@ -65,10 +67,19 @@ main (int argc, char **argv)
all = 0; break;
case ARGP_KEY_ARG:
- err = device_open (device_master, 0, arg, &device);
+ if (device_master == MACH_PORT_NULL)
+ {
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ argp_failure (state, 3, err, "Can't get device master port");
+ }
+
+ err = device_open (device_master, D_READ, arg, &device);
if (err == 0)
/* Got it. */
{
+ device_close (device);
+
/* Free the device port we got. */
mach_port_deallocate (mach_task_self (), device);
@@ -84,7 +95,7 @@ main (int argc, char **argv)
}
else if (err != ED_NO_SUCH_DEVICE)
/* Complain about unexpected errors. */
- error (0, err, "%s", arg);
+ argp_failure (state, 0, err, "%s", arg);
break;
default:
@@ -94,10 +105,6 @@ main (int argc, char **argv)
}
const struct argp argp = { options, parse_opt, args_doc, doc };
- err = get_privileged_ports (0, &device_master);
- if (err)
- error (3, err, "Can't get device master port");
-
/* Parse our arguments. */
argp_parse (&argp, argc, argv, 0, 0, 0);
diff --git a/utils/fakeauth.c b/utils/fakeauth.c
new file mode 100644
index 00000000..49fa7f1c
--- /dev/null
+++ b/utils/fakeauth.c
@@ -0,0 +1,434 @@
+/* fakeauth -- proxy auth server to lie to users about what their IDs are
+ Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <hurd.h>
+#include <hurd/auth.h>
+#include <hurd/interrupt.h>
+#include <hurd/ports.h>
+#include <idvec.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <argp.h>
+#include <error.h>
+#include "auth_S.h"
+#include "auth_request_U.h"
+#include "interrupt_S.h"
+
+/* Auth handles are server ports with sets of ids. */
+struct authhandle
+ {
+ struct port_info pi;
+ struct idvec euids, egids, auids, agids;
+ };
+
+struct port_bucket *auth_bucket;
+struct port_class *authhandle_portclass;
+
+/* Create a new auth port. */
+
+static error_t
+create_authhandle (struct authhandle **new)
+{
+ error_t err = ports_create_port (authhandle_portclass, auth_bucket,
+ sizeof **new, new);
+ if (! err)
+ bzero (&(*new)->euids, (void *) &(*new)[1] - (void *) &(*new)->euids);
+ return err;
+}
+
+/* Clean up a dead auth port. */
+
+static void
+destroy_authhandle (void *p)
+{
+ struct authhandle *h = p;
+ idvec_free_contents (&h->euids);
+ idvec_free_contents (&h->egids);
+ idvec_free_contents (&h->auids);
+ idvec_free_contents (&h->agids);
+}
+
+/* Called by server stub functions. */
+
+authhandle_t
+auth_port_to_handle (auth_t auth)
+{
+ return ports_lookup_port (auth_bucket, auth, authhandle_portclass);
+}
+
+/* id management. */
+
+static inline void
+idvec_copyout (struct idvec *idvec, uid_t **ids, size_t *nids)
+{
+ if (idvec->num > *nids)
+ *ids = idvec->ids;
+ else
+ memcpy (*ids, idvec->ids, idvec->num * sizeof *ids);
+ *nids = idvec->num;
+}
+
+#define C(auth, ids) idvec_copyout (&auth->ids, ids, n##ids)
+#define OUTIDS(auth) (C (auth, euids), C (auth, egids), \
+ C (auth, auids), C (auth, agids))
+
+/* Implement auth_getids as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_getids (struct authhandle *auth,
+ uid_t **euids,
+ size_t *neuids,
+ uid_t **auids,
+ size_t *nauids,
+ uid_t **egids,
+ size_t *negids,
+ uid_t **agids,
+ size_t *nagids)
+{
+ if (! auth)
+ return EOPNOTSUPP;
+
+ OUTIDS (auth);
+
+ return 0;
+}
+
+/* Implement auth_makeauth as described in <hurd/auth.defs>. */
+kern_return_t
+S_auth_makeauth (struct authhandle *auth,
+ mach_port_t *authpts, size_t nauths,
+ uid_t *euids, size_t neuids,
+ uid_t *auids, size_t nauids,
+ uid_t *egids, size_t negids,
+ uid_t *agids, size_t nagids,
+ mach_port_t *newhandle)
+{
+ struct authhandle *newauth, *auths[1 + nauths];
+ int hasroot = 0;
+ error_t err;
+ size_t i, j;
+
+ if (!auth)
+ return EOPNOTSUPP;
+
+ auths[0] = auth;
+
+ /* Fetch the auth structures for all the ports passed in. */
+ for (i = 0; i < nauths; i++)
+ auths[i + 1] = auth_port_to_handle (authpts[i]);
+
+ ++nauths;
+
+ /* Verify that the union of the handles passed in either contains euid 0
+ (root), or contains all the requested ids. */
+
+#define isuid(uid, auth) \
+ (idvec_contains (&(auth)->euids, uid) \
+ || idvec_contains (&(auth)->auids, uid))
+#define groupmember(gid, auth) \
+ (idvec_contains (&(auth)->egids, gid) \
+ || idvec_contains (&(auth)->agids, gid))
+#define isroot(auth) isuid (0, auth)
+
+ for (i = 0; i < nauths; i++)
+ if (auths[i] && isroot (auths[i]))
+ {
+ hasroot = 1;
+ break;
+ }
+
+ if (!hasroot)
+ {
+ int has_it;
+
+ for (i = 0; i < neuids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && isuid (euids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+
+ for (i = 0; i < nauids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && isuid (auids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+
+ for (i = 0; i < negids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && groupmember (egids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+
+ for (i = 0; i < nagids; i++)
+ {
+ has_it = 0;
+ for (j = 0; j < nauths; j++)
+ if (auths[j] && groupmember (agids[i], auths[j]))
+ {
+ has_it = 1;
+ break;
+ }
+ if (!has_it)
+ goto eperm;
+ }
+ }
+
+ err = create_authhandle (&newauth);
+
+ /* Create a new handle with the specified ids. */
+
+#define MERGE S (euids); S (egids); S (auids); S (agids);
+#define S(uids) if (!err) err = idvec_merge_ids (&newauth->uids, uids, n##uids)
+
+ MERGE;
+
+#undef S
+
+ if (! err)
+ {
+ for (j = 1; j < nauths; ++j)
+ mach_port_deallocate (mach_task_self (), authpts[j - 1]);
+ *newhandle = ports_get_right (newauth);
+ ports_port_deref (newauth);
+ }
+
+ for (j = 1; j < nauths; j++)
+ if (auths[j])
+ ports_port_deref (auths[j]);
+ return err;
+
+ eperm:
+ for (j = 1; j < nauths; j++)
+ if (auths[j])
+ ports_port_deref (auths[j]);
+ return EPERM;
+}
+
+
+/* This is our original auth port, where we will send all proxied
+ authentication requests. */
+static auth_t real_auth_port;
+
+kern_return_t
+S_auth_user_authenticate (struct authhandle *userauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ mach_port_t rendezvous,
+ mach_port_t *newport,
+ mach_msg_type_name_t *newporttype)
+{
+ if (! userauth)
+ return EOPNOTSUPP;
+
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
+
+ return auth_user_authenticate_request (real_auth_port, reply, reply_type,
+ rendezvous, MACH_MSG_TYPE_MOVE_SEND)
+ ? : MIG_NO_REPLY;
+}
+
+kern_return_t
+S_auth_server_authenticate (struct authhandle *serverauth,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ mach_port_t rendezvous,
+ mach_port_t newport,
+ mach_msg_type_name_t newport_type,
+ uid_t **euids,
+ size_t *neuids,
+ uid_t **auids,
+ size_t *nauids,
+ uid_t **egids,
+ size_t *negids,
+ uid_t **agids,
+ size_t *nagids)
+{
+ if (! serverauth)
+ return EOPNOTSUPP;
+
+ if (rendezvous == MACH_PORT_DEAD) /* Port died in transit. */
+ return EINVAL;
+
+ return auth_server_authenticate_request (real_auth_port,
+ reply, reply_type,
+ rendezvous, MACH_MSG_TYPE_MOVE_SEND,
+ newport, newport_type)
+ ? : MIG_NO_REPLY;
+}
+
+kern_return_t
+S_interrupt_operation (mach_port_t port, mach_port_seqno_t seqno)
+{
+ return interrupt_operation (real_auth_port, 0);
+}
+
+static int
+auth_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int auth_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ extern int interrupt_server (mach_msg_header_t *inp, mach_msg_header_t *);
+ return (auth_server (inp, outp) ||
+ interrupt_server (inp, outp) ||
+ ports_notify_server (inp, outp));
+}
+
+
+static any_t
+handle_auth_requests (any_t ignored)
+{
+ while (1)
+ ports_manage_port_operations_multithread (auth_bucket, auth_demuxer,
+ 30 * 1000, 0, 0);
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct authhandle *firstauth;
+ auth_t authport;
+ pid_t child;
+ int status;
+ int argi;
+
+ /* Parse our options. */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = { 0, parse_opt, "COMMAND...", "\
+Run COMMAND with a fake authentication handle that claims to be root or \
+any arbitrary identity derived from that handle, but in fact is always just \
+a proxy for your real authentication handle. This means that all processes \
+created by the COMMAND will have your privileges, even though it may \
+believe it has restricted them to different identities or no identity at all.\
+" };
+
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &argi, 0);
+
+ auth_bucket = ports_create_bucket ();
+ authhandle_portclass = ports_create_class (&destroy_authhandle, 0);
+
+ /* Create the initial root auth handle. */
+ err = create_authhandle (&firstauth);
+ assert_perror (err);
+ idvec_add (&firstauth->euids, 0);
+ idvec_add (&firstauth->auids, 0);
+ idvec_add (&firstauth->auids, 0);
+ idvec_merge (&firstauth->egids, &firstauth->euids);
+ idvec_merge (&firstauth->agids, &firstauth->auids);
+
+ /* Get a send right for it. */
+ authport = ports_get_right (firstauth);
+ err = mach_port_insert_right (mach_task_self (), authport, authport,
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+ ports_port_deref (firstauth);
+
+ /* Stash our original auth port for later use. */
+ real_auth_port = getauth ();
+
+ /* Start handling auth requests on our fake handles. */
+ cthread_detach (cthread_fork (&handle_auth_requests, (any_t)0));
+
+ /* Now we start faking ourselves out. This will immediately
+ reauthenticate all our descriptors through our proxy auth port.
+ The POSIXoid calls we make below will continue to use the fake
+ port and pass it on to the child. */
+ if (setauth (authport))
+ error (2, errno, "Cannot switch to fake auth handle");
+ mach_port_deallocate (mach_task_self (), authport);
+
+ /* We cannot use fork because it doesn't do the right thing with our send
+ rights that point to our own receive rights, i.e. the new auth port.
+ Since posix_spawn might be implemented with fork (prior to glibc 2.3),
+ we cannot use that simple interface either. We use _hurd_exec
+ directly to effect what posix_spawn does in the simple case. */
+ {
+ task_t newtask;
+ process_t proc;
+ file_t execfile = file_name_lookup (argv[argi], O_EXEC, 0);
+ if (execfile == MACH_PORT_NULL)
+ error (3, errno, "%s", argv[argi]);
+
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &newtask);
+ if (err)
+ error (3, err, "cannot create child task");
+ child = task2pid (newtask);
+ if (child < 0)
+ error (3, errno, "task2pid");
+ proc = getproc ();
+ err = proc_child (proc, newtask);
+ mach_port_deallocate (mach_task_self (), proc);
+ if (err)
+ error (3, err, "proc_child");
+
+ err = _hurd_exec (newtask, execfile, &argv[argi], environ);
+ mach_port_deallocate (mach_task_self (), newtask);
+ mach_port_deallocate (mach_task_self (), execfile);
+ if (err)
+ error (3, err, "cannot execute %s", argv[argi]);
+ }
+
+ if (waitpid (child, &status, 0) != child)
+ error (4, errno, "waitpid on %d", child);
+
+ if (WIFSIGNALED (status))
+ error (WTERMSIG (status) + 128, 0,
+ "%s for child %d", strsignal (WTERMSIG (status)), child);
+ if (WEXITSTATUS (status) != 0)
+ error (WEXITSTATUS (status), 0,
+ "Error %d for child %d", WEXITSTATUS (status), child);
+
+ return 0;
+}
diff --git a/utils/fakeroot.sh b/utils/fakeroot.sh
new file mode 100644
index 00000000..1ace1cf7
--- /dev/null
+++ b/utils/fakeroot.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Execute a command in an environment where it appears to be root.
+#
+# Copyright (C) 2002 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+USAGE="Usage: $0 [OPTION...] [COMMAND...]"
+DOC="Execute COMMAND in an environment where it appears to be root."
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "$USAGE"
+ echo "$DOC"
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ exit 0;;
+ --usage)
+ echo "Usage: $0 [-V?] [--help] [--usage] [--version]"
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_fakeroot_"; exit 0;;
+ --)
+ shift
+ break;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+if [ $# -eq 0 ]; then
+ set -- ${SHELL:-/bin/sh}
+fi
+
+# We exec settrans, which execs the "fakeauth" command in the chroot context.
+# The `pwd` is evaluated here and now, and that result interpreted inside
+# the shell running under fakeauth to chdir there inside the chroot world.
+# That shell then execs our arguments as a command line.
+exec /bin/settrans --chroot \
+ /bin/fakeauth /bin/sh -c "cd `pwd`; $*" \
+ -- / /hurd/fakeroot
diff --git a/utils/frobauth-mod.c b/utils/frobauth-mod.c
new file mode 100644
index 00000000..4464c18c
--- /dev/null
+++ b/utils/frobauth-mod.c
@@ -0,0 +1,162 @@
+/* Modify the current authentication selected processes
+
+ Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <hurd.h>
+#include <error.h>
+
+#include "frobauth.h"
+
+/* For every pid in FROBAUTH, call MODIFY to change its argument UGIDS from
+ the current authentication to what it should be; CHANGE is whatever ids
+ the user specified. AUTHS, of length NUM_AUTHS, should be a vector of
+ auth ports giving whatever additional authentication is needed (besides
+ the process's current authentication). If the user specifies the
+ --verbose flags, PRINT_INFO is called after successfully installing the
+ new authentication in each process, to print a message about what
+ happened. True is returned if no errors occur, although most errors do
+ not cause termination, and error messages are printed for them. */
+error_t
+frobauth_modify (struct frobauth *frobauth,
+ const auth_t *auths, size_t num_auths,
+ error_t (*modify) (struct ugids *ugids,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void (*print_info) (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void *hook)
+{
+ int i;
+ int ok = 1;
+ size_t num_all_auths = num_auths + 1;
+ auth_t all_auths[num_all_auths];
+ pid_t cur_pid = getpid ();
+ process_t proc_server = getproc ();
+
+ bcopy (auths, all_auths, num_auths * sizeof *auths);
+
+ /* Map MODIFY over all pids. */
+ for (i = 0; i < frobauth->num_pids; i++)
+ if (frobauth->pids[i] != cur_pid)
+ {
+ mach_port_t msgport;
+ pid_t pid = frobauth->pids[i];
+ error_t err = proc_getmsgport (proc_server, pid, &msgport);
+
+ if (err)
+ error (0, err, "%d: Cannot get message port", pid);
+ else
+ {
+ task_t task;
+
+ err = proc_pid2task (proc_server, pid, &task);
+ if (err)
+ error (0, err, "%d", pid);
+ else
+ {
+ auth_t old_auth;
+
+ err = msg_get_init_port (msgport, task, INIT_PORT_AUTH,
+ &old_auth);
+ if (err)
+ error (0, err, "%d: Cannot get auth port", pid);
+ else
+ {
+ struct ugids old = UGIDS_INIT;
+
+ err = ugids_merge_auth (&old, old_auth);
+
+ if (err)
+ error (0, err, "%d: Cannot get auth port ids", pid);
+ else
+ {
+ struct ugids new = UGIDS_INIT;
+
+ /* Assume all gids that can be implied by some uid are
+ only present for that reason. */
+ ugids_imply_all (&old);
+
+ err = ugids_set (&new, &old);
+
+ err = (*modify) (&new, &frobauth->ugids, pid, hook);
+ if (err)
+ error (99, err, "%d: Cannot modify ids", pid);
+ else if (! ugids_equal (&new, &old))
+ {
+ if (! frobauth->dry_run)
+ {
+ auth_t new_auth;
+
+ /* Add the PID's old authentication to that
+ supplied by the calller. */
+ all_auths[num_all_auths - 1] = old_auth;
+
+ err = ugids_make_auth (&new,
+ all_auths,
+ num_all_auths,
+ &new_auth);
+ if (err)
+ error (0, err,
+ "%d: Authentication failure", pid);
+ else
+ {
+ err =
+ msg_set_init_port (msgport, task,
+ INIT_PORT_AUTH,
+ new_auth,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (),
+ new_auth);
+ if (err)
+ error (0, err, "%d", pid);
+ }
+
+ }
+
+ if (frobauth->verbose && !err)
+ (*print_info) (&new, &old, &frobauth->ugids,
+ pid, hook);
+
+ }
+ else if (frobauth->verbose)
+ printf ("%d: Nothing changed\n", pid);
+
+ ugids_fini (&new);
+ }
+
+ ugids_fini (&old);
+ mach_port_deallocate (mach_task_self (), old_auth);
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ }
+ mach_port_deallocate (mach_task_self (), msgport);
+ }
+
+ if (err)
+ ok = 0; /* Something didn't work. */
+ }
+
+ return ok;
+}
diff --git a/utils/frobauth.c b/utils/frobauth.c
new file mode 100644
index 00000000..ccb7c3bb
--- /dev/null
+++ b/utils/frobauth.c
@@ -0,0 +1,282 @@
+/* Common interface for auth frobbing utilities
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+/* This file is rather a mess of intertwined argps; it shoud be redone as a
+ single level once argp can handle dynamic option frobbing. XXX */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <hurd.h>
+#include <hurd/process.h>
+
+#include "frobauth.h"
+#include "ugids.h"
+#include "pids.h"
+
+static struct argp common_argp;
+static struct argp fr_ugids_argp;
+
+static const struct argp_option common_options[] =
+{
+ {"verbose", 'v', 0, 0, "Print informational messages"},
+ {"dry-run", 'n', 0, 0, "Don't do anything, just print what would be done"},
+ { 0 }
+};
+static struct argp_child common_child_argps[] =
+{
+ { &pids_argp, 0, "Process selection:" },
+ { 0 }
+};
+
+static const char common_args_doc[] = "USER...";
+static const char common_doc[] =
+ "\vBy default, all processes in the current login collection are selected";
+
+static struct argp_child ugids_child_argps[] =
+{
+ { &ugids_argp, 0, "User/group ids:" },
+ { 0 }
+};
+
+/* An argp on top of the base frobauth argp that provides switchable
+ effective/available ids (XXX this junk should be moved into a single argp
+ [indeed, into ugids_argp] once argp can deal with the init routine
+ frobbing the argp source). */
+static const struct argp_option ea_options[] =
+{
+ {"available", 'a', 0, 0, "USER... specifies available ids"},
+ {"effective", 'e', 0, 0, "USER... specifies effective ids"},
+ { 0 }
+};
+
+static struct argp_child ea_posix_child_argps[] =
+{
+ { &common_argp },
+ { &fr_ugids_argp },
+ { 0 }
+};
+
+static struct argp_child no_ugids_child_argps[] =
+{
+ { &common_argp },
+ { 0 }
+};
+
+/* This holds state information that's only active during parsing. */
+struct frobauth_argp_state
+{
+ struct frobauth *frobauth;
+ struct pids_argp_params pids_argp_params;
+ struct ugids_argp_params ugids_argp_params;
+};
+
+static error_t
+common_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->input;
+ struct frobauth *frobauth = fs->frobauth;
+
+ switch (key)
+ {
+ case 'v':
+ frobauth->verbose = 1; break;
+ case 'n':
+ frobauth->dry_run = 1; break;
+
+ case ARGP_KEY_END:
+ if (frobauth->num_pids == 0)
+ /* No pids specified! By default, do the current login collection. */
+ {
+ pid_t lid;
+ error_t err = proc_getloginid (getproc (), getpid (), &lid);
+
+ if (err)
+ argp_failure (state, 2, err,
+ "Couldn't get current login collection");
+
+ err = add_fn_pids (&frobauth->pids, &frobauth->num_pids,
+ lid, proc_getloginpids);
+ if (err)
+ argp_failure (state, 3, err,
+ "%d: Couldn't get login collection pids", lid);
+
+ return err;
+ }
+ break;
+
+ case ARGP_KEY_INIT:
+ bzero (fs, sizeof *fs);
+ fs->frobauth = frobauth;
+ fs->pids_argp_params.pids = &frobauth->pids;
+ fs->pids_argp_params.num_pids = &frobauth->num_pids;
+ state->child_inputs[0] = &fs->pids_argp_params;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ free (fs);
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+ugids_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->input;
+ struct frobauth *frobauth = fs->frobauth;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ fs->ugids_argp_params.ugids = &frobauth->ugids;
+ fs->ugids_argp_params.parse_user_args = 1;
+ fs->ugids_argp_params.default_user = frobauth->default_user;
+ fs->ugids_argp_params.require_ids = frobauth->require_ids;
+ fs->pids_argp_params.pids = &frobauth->pids;
+ fs->pids_argp_params.num_pids = &frobauth->num_pids;
+
+ state->child_inputs[0] = &fs->ugids_argp_params;
+
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+ea_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case 'a':
+ fs->ugids_argp_params.user_args_are_available = 1;
+ break;
+ case 'e':
+ fs->ugids_argp_params.user_args_are_effective = 1;
+ break;
+
+ case ARGP_KEY_ARG:
+ if (!fs->ugids_argp_params.user_args_are_effective
+ && !fs->ugids_argp_params.user_args_are_available)
+ /* Default to effective. */
+ fs->ugids_argp_params.user_args_are_effective = 1;
+
+ /* Let someone else parse the arg. */
+ return ARGP_ERR_UNKNOWN;
+
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ state->child_inputs[1] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+posix_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ state->child_inputs[1] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static error_t
+no_ugids_parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct frobauth_argp_state *fs = state->hook;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ fs = state->hook = malloc (sizeof (struct frobauth_argp_state));
+ if (! fs)
+ return ENOMEM;
+
+ fs->frobauth = state->input;
+ state->child_inputs[0] = fs; /* Pass our state to the common parser. */
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp common_argp =
+{
+ common_options, common_parse_opt, 0, common_doc, common_child_argps
+};
+static struct argp fr_ugids_argp =
+{
+ 0, ugids_parse_opt, 0, 0, ugids_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as single ids to
+ either the effective or available ids. */
+struct argp frobauth_ea_argp =
+{
+ ea_options, ea_parse_opt, 0, 0, ea_posix_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+struct argp frobauth_posix_argp =
+{
+ 0, posix_parse_opt, 0, 0, ea_posix_child_argps
+};
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+struct argp frobauth_no_ugids_argp =
+{
+ 0, no_ugids_parse_opt, 0, 0, no_ugids_child_argps
+};
diff --git a/utils/frobauth.doc b/utils/frobauth.doc
new file mode 100644
index 00000000..e4d1358f
--- /dev/null
+++ b/utils/frobauth.doc
@@ -0,0 +1,83 @@
+ -- Hurd process authentication frobbing commands --
+
+addauth -- Adds additional authority to selected processes, without changing
+ their identity (unless they previously had none)
+rmauth -- Removes authority
+setauth -- Changes the identity and authority of selected processes
+su -- Changes the identity and authority of selected processes, saving enough
+ authority to later undo the change
+unsu -- Attempts to undo the results of a previous su command
+
+Examples:
+
+As these commands effective existing processes rather than creating
+subshells, the following are all typed to the same shell.
+
+Starting with the ids I get from logging in as miles (the `ids' command shows
+all the ids in the process it was invoked from):
+
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles agids=10,10
+
+Note that first euid/egids is the traditional unix effective uid/gid, and,
+for instance, determines what identity files are created with; the 1st and
+2nd auids/agids are the posix `real' and `saved' ids. Now I add root
+authority:
+
+ (utils) addauth root
+ Password:
+ (utils) ids -tn
+ euids=miles,root egids=10,wheel auids=miles,miles agids=10,10
+
+The main id is still miles, but an effective root id is also present, meaning
+that the process has root privileges. The traditional `id' command hasn't
+yet been changed to print extended hurd ids, so it only knows about the
+additional group:
+
+ (utils) id
+ uid=9427(miles) gid=10 groups=10,0(wheel)
+
+Removing root puts us back where we started:
+
+ (utils) rmauth root
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles agids=10,10
+
+Now if we use su instead, it actually changes our process's identity (but
+note that the old ids are still around as available ids -- this means they
+the only privilege they grant is to become effective ids):
+
+ (utils) su
+ Password:
+ (utils) ids -tn
+ euids=root egids=wheel auids=root,root,miles,miles agids=wheel,wheel,10,10
+ (utils) id
+ uid=0(root) gid=0(wheel) groups=0(wheel)
+
+We can undo the su with unsu:
+
+ (utils) unsu
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles agids=10,10
+
+Now lets su again, to a different user:
+
+ (utils) su thomas
+ Password:
+ (utils) ids -tn
+ euids=thomas egids=11 auids=thomas,thomas,miles,miles agids=11,11,10,10
+
+If we now use another su command, instead of su, we can swap our identity;
+we don't need a password to do this, since the old ids are still there as
+available ids.
+
+ (utils) su miles
+ (utils) ids -tn
+ euids=miles egids=10 auids=miles,miles,thomas,thomas agids=10,10,11,11
+
+Now if we give unsu, we'll become thomas for good (this same effect may be
+had in one step with the `su --no-save' or `setauth' commands):
+
+ (utils) unsu
+ (utils) ids -tn
+ euids=thomas egids=11 auids=thomas,thomas agids=11,11
diff --git a/utils/frobauth.h b/utils/frobauth.h
new file mode 100644
index 00000000..2b9c78f1
--- /dev/null
+++ b/utils/frobauth.h
@@ -0,0 +1,71 @@
+/* Common interface for auth frobbing utilities
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#ifndef __FROBAUTH_H__
+#define __FROBAUTH_H__
+
+#include <sys/types.h>
+#include <ugids.h>
+#include <argp.h>
+
+/* Structure describing which processes to frob, and how to frob them. */
+struct frobauth
+{
+ struct ugids ugids;
+ pid_t *pids;
+ size_t num_pids;
+ int verbose, dry_run; /* User options */
+ uid_t default_user; /* If none specified; -1 means none. */
+ int require_ids; /* If true, require some ids be specified. */
+};
+
+#define FROBAUTH_INIT { UGIDS_INIT, 0, 0, 0, 0, -1 }
+
+/* For every pid in FROBAUTH, call MODIFY to change its argument UGIDS from
+ the current authentication to what it should be; CHANGE is whatever ids
+ the user specified. AUTHS, of length NUM_AUTHS, should be a vector of
+ auth ports giving whatever additional authentication is needed (besides
+ the process's current authentication). If the user specifies the
+ --verbose flags, PRINT_INFO is called after successfully installing the
+ new authentication in each process, to print a message about what
+ happened. True is returned if no errors occur, although most errors do
+ not cause termination, and error messages are printed for them. */
+error_t frobauth_modify (struct frobauth *frobauth,
+ const auth_t *auths, size_t num_auths,
+ error_t (*modify) (struct ugids *ugids,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void (*print_info) (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *change,
+ pid_t pid, void *hook),
+ void *hook);
+
+/* Parse frobauth args/options, where user args are added as single ids to
+ either the effective or available ids. */
+extern struct argp frobauth_ea_argp;
+
+/* Parse frobauth args/options, where user args are added as posix user. */
+extern struct argp frobauth_posix_argp;
+
+/* Parse frobauth args/options, with no user specifications. */
+extern struct argp frobauth_no_ugids_argp;
+
+#endif /* __FROBAUTH_H__ */
diff --git a/utils/fsysopts.c b/utils/fsysopts.c
index 076e2a87..f3458a03 100644
--- a/utils/fsysopts.c
+++ b/utils/fsysopts.c
@@ -1,8 +1,8 @@
/* Set options in a running filesystem
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,2002,2004 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -28,10 +28,11 @@
#include <error.h>
#include <argz.h>
+#include <version.h>
#include <hurd/fsys.h>
-char *argp_program_version = "fsysopts 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (fsysopts);
static struct argp_option options[] =
{
@@ -40,14 +41,15 @@ static struct argp_option options[] =
{0, 0, 0, 0}
};
static char *args_doc = "FILESYS [FS_OPTION...]";
-static char *doc = "The legal values for FS_OPTION depends on FILESYS, but\
- some common ones are: --readonly, --writable, --remount, --sync[=INTERVAL],\
+static char *doc = "Get or set command line options for running translator FILESYS."
+"\vThe legal values for FS_OPTION depends on FILESYS, but\
+ some common ones are: --readonly, --writable, --update, --sync[=INTERVAL],\
and --nosync.\n\nIf no options are supplied, FILESYS's existing options\
are printed";
/* ---------------------------------------------------------------- */
-void
+int
main(int argc, char *argv[])
{
error_t err;
@@ -58,7 +60,7 @@ main(int argc, char *argv[])
/* The filesystem options vector, in '\0' separated format. */
char *argz = 0;
- int argz_len = 0;
+ size_t argz_len = 0;
int deref = 0, recursive = 0;
@@ -122,5 +124,5 @@ main(int argc, char *argv[])
puts (argz);
}
- exit(0);
+ return 0;
}
diff --git a/utils/ftpcp.c b/utils/ftpcp.c
new file mode 100644
index 00000000..67ccb1a0
--- /dev/null
+++ b/utils/ftpcp.c
@@ -0,0 +1,397 @@
+/* Copy a file using the ftp protocol
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <error.h>
+#include <argp.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#include <version.h>
+
+#include <ftpconn.h>
+
+#define COPY_SZ 65536
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ftpcp);
+
+#define OPT_SRC_U -3
+#define OPT_SRC_A -4
+#define OPT_SRC_P -5
+#define OPT_DST_U -6
+#define OPT_DST_A -7
+#define OPT_DST_P -8
+
+
+static struct argp_option options[] =
+{
+ {"user", 'u', "USER",0, "User to login as on both ftp servers"},
+ {"password", 'p', "PWD", 0, "USER's password"},
+ {"account", 'a', "ACCT",0, "Account to login as"},
+ {"src-user", OPT_SRC_U, "USER",0, "User to login as on the src ftp server"},
+ {"src-password",OPT_SRC_P, "PWD", 0, "The src USER's password"},
+ {"src-account", OPT_SRC_A, "ACCT",0, "Account to login as on the source server"},
+ {"dst-user", OPT_DST_U, "USER",0, "User to login as on the dst ftp server"},
+ {"dst-password",OPT_DST_P, "PWD", 0, "The dst USER's password"},
+ {"dst-account", OPT_DST_A, "ACCT",0, "Account to login as on the source server"},
+ {"debug", 'D', 0, 0, "Turn on debugging output for ftp connections"},
+ {0, 0}
+};
+static char *args_doc = "SRC [DST]";
+static char *doc = "Copy file SRC over ftp to DST."
+"\vBoth SRC and DST may have the form HOST:FILE, FILE, or -, where - is"
+" standard input for SRC or standard output for DST, and FILE is a local"
+" file. DST may be a directory, in which case the basename of SRC is"
+" appended to make the actual destination filename.";
+
+/* customization hooks. */
+static struct ftp_conn_hooks conn_hooks = { 0 };
+
+static void
+cntl_debug (struct ftp_conn *conn, int type, const char *txt)
+{
+ char *type_str;
+
+ switch (type)
+ {
+ case FTP_CONN_CNTL_DEBUG_CMD: type_str = ">"; break;
+ case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
+ default: type_str = "?"; break;
+ }
+
+ fprintf (stderr, "%s%s%s\n", (char *)conn->hook ?: "", type_str, txt);
+}
+
+/* Return an ftp connection for the host NAME using PARAMS. If an error
+ occurrs, a message is printed the program exits. If CNAME is non-zero,
+ the host's canonical name, in mallocated storage, is returned in it. */
+struct ftp_conn *
+get_host_conn (char *name, struct ftp_conn_params *params, char **cname)
+{
+ error_t err;
+ struct hostent *he;
+ struct ftp_conn *conn;
+
+ he = gethostbyname (name);
+ if (! he)
+ error (10, 0, "%s: %s", name, hstrerror (h_errno));
+
+ params->addr = malloc (he->h_length);
+ if (! params->addr)
+ error (11, ENOMEM, "%s", name);
+
+ bcopy (he->h_addr_list[0], params->addr, he->h_length);
+ params->addr_len = he->h_length;
+ params->addr_type = he->h_addrtype;
+
+ err = ftp_conn_create (params, &conn_hooks, &conn);
+ if (err)
+ error (12, err, "%s", he->h_name);
+
+ if (cname)
+ *cname = strdup (he->h_name);
+
+ return conn;
+}
+
+static void
+cp (int src, const char *src_name, int dst, const char *dst_name)
+{
+ ssize_t rd;
+ static void *copy_buf = 0;
+
+ if (! copy_buf)
+ {
+ copy_buf = valloc (COPY_SZ);
+ if (! copy_buf)
+ error (13, ENOMEM, "Cannot allocate copy buffer");
+ }
+
+ while ((rd = read (src, copy_buf, COPY_SZ)) > 0)
+ do
+ {
+ int wr = write (dst, copy_buf, rd);
+ if (wr < 0)
+ error (14, errno, "%s", dst_name);
+ rd -= wr;
+ }
+ while (rd > 0);
+
+ if (rd != 0)
+ error (15, errno, "%s", src_name);
+}
+
+struct epoint
+{
+ char *name; /* Name, of the form HOST:FILE, FILE, or -. */
+ char *file; /* If remote, the FILE portion, or 0. */
+ int fd; /* A file descriptor to use. */
+ struct ftp_conn *conn; /* An ftp connection to use. */
+ struct ftp_conn_params params;
+};
+
+static void
+econnect (struct epoint *e, struct ftp_conn_params *def_params, char *name)
+{
+ char *rmt;
+
+ if (! e->name)
+ e->name = "-";
+
+ rmt = strchr (e->name, ':');
+ if (rmt)
+ {
+ error_t err;
+
+ *rmt++ = 0;
+
+ if (! e->params.user)
+ e->params.user = def_params->user;
+ if (! e->params.pass)
+ e->params.pass = def_params->pass;
+ if (! e->params.acct)
+ e->params.acct = def_params->acct;
+
+ e->conn = get_host_conn (e->name, &e->params, &e->name);
+ e->name = realloc (e->name, strlen (e->name) + 1 + strlen (rmt) + 1);
+ if (! e->name)
+ error (22, ENOMEM, "Cannot allocate name storage");
+
+ e->conn->hook = name;
+
+ err = ftp_conn_set_type (e->conn, "I");
+ if (err)
+ error (23, err, "%s: Cannot set connection type to binary",
+ e->name);
+
+ strcat (e->name, ":");
+ strcat (e->name, rmt);
+
+ e->file = rmt;
+ }
+ else if (e->params.user || e->params.pass || e->params.acct)
+ error (20, 0,
+ "%s: Ftp login parameter specified for a local endpoint (%s,%s,%s)",
+ e->name, e->params.user, e->params.pass, e->params.acct);
+ else
+ e->file = strdup (e->name);
+}
+
+static error_t
+eopen_wr (struct epoint *e, int *fd)
+{
+ if (e->conn)
+ return ftp_conn_start_store (e->conn, e->file, fd);
+ else if (strcmp (e->name, "-") == 0)
+ *fd = 1;
+ else
+ {
+ *fd = open (e->name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (*fd < 0)
+ return errno;
+ }
+ return 0;
+}
+
+static error_t
+eopen_rd (struct epoint *e, int *fd)
+{
+ if (e->conn)
+ return ftp_conn_start_retrieve (e->conn, e->file, fd);
+ else if (strcmp (e->name, "-") == 0)
+ *fd = 0;
+ else
+ {
+ *fd = open (e->name, O_RDONLY, 0666);
+ if (*fd < 0)
+ return errno;
+ }
+ return 0;
+}
+
+static void
+efinish (struct epoint *e)
+{
+ if (e->conn)
+ {
+ error_t err = ftp_conn_finish_transfer (e->conn);
+ if (err)
+ error (31, err, "%s", e->name);
+ }
+}
+
+/* Give a name which refers to a directory file, and a name in that
+ directory, this should return in COMPOSITE the composite name referring to
+ that name in that directory, in malloced storage. */
+error_t
+eappend (struct epoint *e,
+ const char *dir, const char *name,
+ char **composite)
+{
+ if (e->conn)
+ return ftp_conn_append_name (e->conn, dir, name, composite);
+ else
+ {
+ char *rval = malloc (strlen (dir) + 1 + strlen (name) + 1);
+
+ if (! rval)
+ return ENOMEM;
+
+ if (dir[0] == '/' && dir[1] == '\0')
+ stpcpy (stpcpy (rval, dir), name);
+ else
+ stpcpy (stpcpy (stpcpy (rval, dir), "/"), name);
+
+ *composite = rval;
+
+ return 0;
+ }
+}
+
+/* If the name of a file COMPOSITE is a composite name (containing both a
+ filename and a directory name), this function will return the name
+ component only in BASE, in malloced storage, otherwise it simply returns a
+ newly malloced copy of COMPOSITE in BASE. */
+error_t
+ebasename (struct epoint *e, const char *composite, char **base)
+{
+ if (e->conn)
+ return ftp_conn_basename (e->conn, composite, base);
+ else
+ {
+ *base = strdup (basename (composite));
+ return 0;
+ }
+}
+
+static void
+append_basename (struct epoint *dst, struct epoint *src)
+{
+ char *bname;
+ error_t err = ebasename (src, src->file, &bname);
+
+ if (err)
+ error (33, err, "%s: Cannot find basename", src->name);
+
+ err = eappend (dst, dst->file, bname, &dst->file);
+ if (err)
+ error (34, err, "%s: Cannot append name component", dst->name);
+
+ err = eappend (dst, dst->name, bname, &dst->name);
+ if (err)
+ error (35, err, "%s: Cannot append name component", dst->name);
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct epoint rd = { 0 }, wr = { 0 };
+ struct ftp_conn_params def_params = { 0 }; /* default params */
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ switch (state->arg_num)
+ {
+ case 0: rd.name = arg; break;
+ case 1: wr.name = arg; break;
+ default: return ARGP_ERR_UNKNOWN;
+ }
+ break;
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+
+ case 'u': def_params.user = arg; break;
+ case 'p': def_params.pass = arg; break;
+ case 'a': def_params.acct = arg; break;
+
+ case OPT_SRC_U: rd.params.user = arg; break;
+ case OPT_SRC_P: rd.params.pass = arg; break;
+ case OPT_SRC_A: rd.params.acct = arg; break;
+
+ case OPT_DST_U: wr.params.user = arg; break;
+ case OPT_DST_P: wr.params.pass = arg; break;
+ case OPT_DST_A: wr.params.acct = arg; break;
+
+ case 'D': conn_hooks.cntl_debug = cntl_debug; break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ econnect (&rd, &def_params, "SRC");
+ econnect (&wr, &def_params, "DST");
+
+ if (rd.conn && wr.conn)
+ /* Both endpoints are remote; directly copy between ftp servers. */
+ {
+ err = ftp_conn_rmt_copy (rd.conn, rd.file, wr.conn, wr.file);
+ if (err == EISDIR)
+ /* The destination name is a directory; try again with the source
+ basename appended. */
+ {
+ append_basename (&wr, &rd);
+ err = ftp_conn_rmt_copy (rd.conn, rd.file, wr.conn, wr.file);
+ }
+ if (err)
+ error (30, err, "Remote copy");
+ }
+ else
+ /* One endpoint is local, so do the copying ourself. */
+ {
+ int rd_fd, wr_fd;
+
+ err = eopen_rd (&rd, &rd_fd);
+ if (err)
+ error (31, err, "%s", rd.name);
+
+ err = eopen_wr (&wr, &wr_fd);
+ if (err == EISDIR)
+ /* The destination name is a directory; try again with the source
+ basename appended. */
+ {
+ append_basename (&wr, &rd);
+ err = eopen_wr (&wr, &wr_fd);
+ }
+ if (err)
+ error (32, err, "%s", wr.name);
+
+ cp (rd_fd, rd.name, wr_fd, wr.name);
+
+ close (rd_fd);
+ close (wr_fd);
+
+ efinish (&rd);
+ efinish (&wr);
+ }
+
+ exit (0);
+}
diff --git a/utils/ftpdir.c b/utils/ftpdir.c
new file mode 100644
index 00000000..4ccb821d
--- /dev/null
+++ b/utils/ftpdir.c
@@ -0,0 +1,329 @@
+/* Get a directory listing using the ftp protocol
+
+ Copyright (C) 1997,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <unistd.h>
+#include <string.h>
+#include <error.h>
+#include <argp.h>
+#include <time.h>
+#include <netdb.h>
+
+#include <version.h>
+
+#include <ftpconn.h>
+
+#define COPY_SZ 65536
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ftpdir);
+
+static struct argp_option options[] =
+{
+ {"user", 'u', "USER",0, "User to login as on ftp server"},
+ {"password", 'p', "PWD", 0, "USER's password"},
+ {"account", 'a', "ACCT",0, "Account to login as"},
+ {"separator",'S', "SEP", 0, "String to separate multiple listings"},
+ {"prefix", 'P', "PFX", 0, "String to proceed listings; the first and second"
+ " occurrences of %s are replace by HOST and DIR"},
+ {"host", 'h', "HOST",0, "Use HOST as a default host"},
+ {"debug", 'D', 0, 0, "Turn on debugging output for ftp connections"},
+ {"intepret", 'i', 0, 0, "Parse the directory output"},
+ {0, 0}
+};
+static char *args_doc = "[([HOST:]DIR | HOST:)...]";
+static char *doc = "Get a directory listing over ftp from HOST:DIR."
+"\vIf HOST is not supplied in an argument any default value set by --host is"
+" used; if DIR is not supplied, the default directory of HOST is used."
+"\nIf multiple DIRs are supplied on the command line, each listing is"
+" prefixed by a newline (or SEP) and a line containing HOST:DIR: (or PFX).";
+
+/* customization hooks. */
+static struct ftp_conn_hooks conn_hooks = { 0 };
+
+static void
+cntl_debug (struct ftp_conn *conn, int type, const char *txt)
+{
+ char *type_str;
+
+ switch (type)
+ {
+ case FTP_CONN_CNTL_DEBUG_CMD: type_str = "."; break;
+ case FTP_CONN_CNTL_DEBUG_REPLY: type_str = "="; break;
+ default: type_str = "?"; break;
+ }
+
+ fprintf (stderr, "%s%s\n", type_str, txt);
+}
+
+struct ftpdir_host
+{
+ char *name;
+ struct ftp_conn_params params;
+ struct ftp_conn *conn;
+ struct ftpdir_host *next;
+};
+
+/* Return an ftp connection for the host NAME using PARAMS, and add an entry
+ for it to *HOSTS. If a connection already exists in HOSTS, it is returned
+ instead of making a new one. If an error occurrs, a message is printed and
+ 0 is returned. */
+static struct ftpdir_host *
+get_host_conn (char *name, struct ftp_conn_params *params,
+ struct ftpdir_host **hosts)
+{
+ error_t err;
+ struct ftpdir_host *h;
+ struct hostent *he;
+
+ for (h = *hosts; h; h = h->next)
+ if (strcmp (h->name, name) == 0)
+ return h;
+
+ he = gethostbyname (name);
+ if (! he)
+ {
+ error (0, 0, "%s: %s", name, hstrerror (h_errno));
+ return 0;
+ }
+
+ for (h = *hosts; h; h = h->next)
+ if (he->h_addrtype == h->params.addr_type
+ && he->h_length == h->params.addr_len
+ && bcmp (he->h_addr_list[0], h->params.addr, he->h_length) == 0)
+ return h;
+
+ h = malloc (sizeof (struct ftpdir_host));
+ if (! h)
+ {
+ error (0, ENOMEM, "%s", name);
+ return 0;
+ }
+
+ h->params = *params;
+ h->params.addr = malloc (he->h_length);
+ h->name = strdup (he->h_name);
+
+ if (!h->name || !h->params.addr)
+ err = ENOMEM;
+ else
+ {
+ bcopy (he->h_addr_list[0], h->params.addr, he->h_length);
+ h->params.addr_len = he->h_length;
+ h->params.addr_type = he->h_addrtype;
+ err = ftp_conn_create (&h->params, &conn_hooks, &h->conn);
+ }
+
+ if (err)
+ {
+ error (0, err, "%s", he->h_name);
+ if (h->name)
+ free (h->name);
+ if (h->params.addr)
+ free (h->params.addr);
+ free (h);
+ return 0;
+ }
+
+ h->next = *hosts;
+ *hosts = h;
+
+ return h;
+}
+
+static int
+ftpdir (char *dir, struct ftpdir_host *host)
+{
+ int data;
+ int rd;
+ error_t err;
+ static void *copy_buf = 0;
+ struct ftp_conn *conn = host->conn;
+ char *host_name = host->name;
+
+ err = ftp_conn_start_dir (conn, dir, &data);
+ if (err)
+ {
+ error (0, err, "%s:%s", host_name, dir);
+ return err;
+ }
+
+ if (! copy_buf)
+ {
+ copy_buf = valloc (COPY_SZ);
+ if (! copy_buf)
+ error (12, ENOMEM, "Cannot allocate copy buffer");
+ }
+
+ while ((rd = read (data, copy_buf, COPY_SZ)) > 0)
+ do
+ {
+ int wr = write (1, copy_buf, rd);
+ if (wr < 0)
+ error (13, errno, "stdout");
+ rd -= wr;
+ }
+ while (rd > 0);
+ if (rd != 0)
+ {
+ error (0, errno, "%s:%s", host_name, dir);
+ return errno;
+ }
+
+ close (data);
+
+ err = ftp_conn_finish_transfer (conn);
+ if (err)
+ {
+ error (0, err, "%s:%s", host_name, dir);
+ return err;
+ }
+
+ return 0;
+}
+
+static error_t
+pdirent (const char *name, const struct stat *st, const char *symlink_target,
+ void *hook)
+{
+ char timebuf[20];
+ strftime (timebuf, sizeof timebuf, "%Y-%m-%d %H:%M", localtime (&st->st_mtime));
+ printf ("%6o %2d %5d %5d %6lld %s %s\n",
+ st->st_mode, st->st_nlink, st->st_uid, st->st_gid, st->st_size,
+ timebuf, name);
+ if (symlink_target)
+ printf (" -> %s\n",
+ symlink_target);
+ return 0;
+}
+
+static error_t
+ftpdir2 (char *dir, struct ftpdir_host *host)
+{
+ error_t err = ftp_conn_get_stats (host->conn, dir, 1, pdirent, 0);
+ if (err == ENOTDIR)
+ err = ftp_conn_get_stats (host->conn, dir, 0, pdirent, 0);
+ if (err)
+ error (0, err, "%s:%s", host->name, dir);
+ return err;
+}
+
+int
+main (int argc, char **argv)
+{
+ struct ftpdir_host *hosts = 0;
+ char *default_host = 0;
+ int interpret = 0;
+ struct ftp_conn_params params = { 0 };
+ char *sep = "\n";
+ char *pfx = "%s:%s:\n";
+ int use_pfx = 0;
+ int errs = 0;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_ARG:
+ {
+ char *host, *dir;
+
+ if (state->next < state->argc)
+ use_pfx = 1; /* Multiple arguments. */
+
+ dir = index (arg, ':');
+ if (dir)
+ {
+ host = arg;
+ *dir++ = '\0';
+ if (*host == '\0')
+ /* An argument of `:' */
+ host = default_host;
+ }
+ else
+ {
+ host = default_host;
+ dir = arg;
+ }
+
+ if (host)
+ {
+ struct ftpdir_host *h = get_host_conn (host, &params, &hosts);
+ if (h)
+ {
+ if (state->arg_num > 0)
+ fputs (sep, stdout);
+ if (use_pfx)
+ printf (pfx, h->name, dir);
+ if ((use_pfx && *pfx) || (state->arg_num > 0 && *sep))
+ fflush (stdout);
+ if (interpret)
+ errs |= ftpdir2 (dir, h);
+ else
+ errs |= ftpdir (dir, h);
+ }
+ errs = 1;
+ }
+ else
+ {
+ error (0, 0, "%s: No default host", arg);
+ errs = 1;
+ }
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (default_host)
+ {
+ struct ftpdir_host *h =
+ get_host_conn (default_host, &params, &hosts);
+ if (h)
+ errs |= ftpdir (0, h);
+ }
+ else
+ {
+ error (0, 0, "No default host");
+ errs = 1;
+ }
+ break;
+
+ return EINVAL;
+
+ case 'u': params.user = arg; break;
+ case 'p': params.pass = arg; break;
+ case 'a': params.acct = arg; break;
+ case 'h': default_host = arg; break;
+ case 'D': conn_hooks.cntl_debug = cntl_debug; break;
+ case 'P': pfx = arg; use_pfx = 1; break;
+ case 'S': sep = arg; break;
+ case 'i': interpret = 1; break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (errs)
+ exit (10);
+ else
+ exit (0);
+}
diff --git a/utils/gcore.c b/utils/gcore.c
new file mode 100644
index 00000000..3d72492c
--- /dev/null
+++ b/utils/gcore.c
@@ -0,0 +1,107 @@
+/* `gcore' program for GNU Hurd: write a core dump from a running process.
+ Copyright (C) 1992,2001,2002 Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <hurd.h>
+#include <hurd/crash.h>
+#include <hurd/paths.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (gcore);
+
+static const struct argp argp =
+{
+ NULL, NULL,
+ "PID...",
+ "Generate a core dump file from a running process"
+ "\vFor each PID, a core dump file \"core.PID\" is written."
+};
+
+int
+main (int argc, char **argv)
+{
+ int status = 0;
+ file_t crashserv;
+ int argi;
+
+ argp_parse (&argp, argc, argv, 0, &argi, 0);
+
+ crashserv = file_name_lookup (_SERVERS_CRASH, 0, 0);
+ if (crashserv == MACH_PORT_NULL)
+ error (1, errno, "cannot reach crash server: %s", _SERVERS_CRASH);
+
+ for (; argi < argc; ++argi)
+ {
+ char *end;
+ pid_t pid;
+ task_t task;
+
+ pid = strtol (argv[argi], &end, 10);
+ if (end == argv[argi] || *end != '\0')
+ {
+ error (0, 0, "cannot parse process ID: %s", argv[argi]);
+ status = 1;
+ continue;
+ }
+
+ task = pid2task ((pid_t) pid);
+ if (task == MACH_PORT_NULL)
+ {
+ error (0, errno, "pid2task: %d", pid);
+ status = 1;
+ }
+ else
+ {
+ file_t file;
+ char *name = 0;
+ asprintf (&name, "core.%d", pid);
+
+ file = file_name_lookup (name, O_WRONLY|O_CREAT,
+ 0600 &~ getumask ());
+ if (file == MACH_PORT_NULL)
+ {
+ error (0, errno, "cannot create %s", name);
+ status = 1;
+ }
+ else
+ {
+ error_t err = crash_dump_task (crashserv, task, file,
+ 0, 0, 0, 0, 0, 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), file);
+ if (err)
+ {
+ (void) remove (name);
+ error (0, err, "crash_dump_task on %d to %s", pid, name);
+ status = 1;
+ }
+ free (name);
+ }
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ }
+
+ return status;
+}
diff --git a/utils/hurdids.c b/utils/hurdids.c
deleted file mode 100644
index 18eb3c41..00000000
--- a/utils/hurdids.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* Show all hurd ids
-
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
-
- 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. */
-
-#include <hurd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <argp.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include <error.h>
-#include <hurd/id.h>
-
-char *argp_program_version = "hurdids 1.0 (GNU " HURD_RELEASE ")";
-
-static struct argp_option options[] =
-{
- {"effective", 'e', 0, 0, "Show effective ids"},
- {"available", 'a', 0, 0, "Show available ids"},
- {"uids", 'u', 0, 0, "Show user ids"},
- {"gids", 'g', 0, 0, "Show group ids"},
- {"names", 'n', 0, 0, "Show names of uids/gids"},
- {"ids", 'i', 0, 0, "Show numeric uids/gids"},
- {0}
-};
-static char *args_doc = 0;
-static char *doc = 0;
-
-/* ---------------------------------------------------------------- */
-
-void
-main(int argc, char *argv[])
-{
- error_t err;
- int show_eff = 0, show_avail = 0, show_uids = 0, show_gids = 0;
- int show_names = 0, show_ids = 0;
-
- /* Parse a command line option. */
- error_t parse_opt (int key, char *arg, struct argp_state *state)
- {
- switch (key)
- {
- case 'e': show_eff = 1; break;
- case 'a': show_avail = 1; break;
- case 'u': show_uids = 1; break;
- case 'g': show_gids = 1; break;
- case 'n': show_names = 1; break;
- case 'i': show_ids = 1; break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
- }
-
- struct argp argp = {options, parse_opt, args_doc, doc};
-
- argp_parse (&argp, argc, argv, 0, 0, 0);
-
- if (! show_eff && ! show_avail)
- show_eff = show_avail = 1;
- if (! show_uids && ! show_gids)
- show_uids = show_gids = 1;
- if (! show_names && ! show_ids)
- show_names = show_ids = 1;
-
- mutex_lock (&_hurd_id.lock);
- err = _hurd_check_ids ();
- mutex_unlock (&_hurd_id.lock);
-
- if (err)
- error (2, err, "Can't update ids");
- else
- {
- typedef typeof (_hurd_id.gen) *ids_t;
- void print_ids (ids_t ids, char *name)
- {
- int i;
-
- if (show_uids)
- {
- if (name && show_gids)
- printf ("%s uids: ", name);
- else if (show_gids)
- printf ("uids: ");
- else if (name)
- printf ("%s: ", name);
-
- for (i = 0; i < ids->nuids; i++)
- {
- uid_t uid = ids->uids[i];
- struct passwd *pw = show_names ? getpwuid (uid) : 0;
- if (i > 0)
- putchar (' ');
- if (pw)
- if (show_ids)
- printf ("%d(%s)", uid, pw->pw_name);
- else
- printf ("%s", pw->pw_name);
- else
- printf ("%d", uid);
- }
- putchar ('\n');
- }
- if (show_gids)
- {
- if (name && show_uids)
- printf ("%s gids: ", name);
- else if (show_uids)
- printf ("gids: ");
- else if (name)
- printf ("%s: ", name);
-
- for (i = 0; i < ids->ngids; i++)
- {
- gid_t gid = ids->gids[i];
- struct group *gr = show_names ? getgrgid (gid) : 0;
- if (i > 0)
- putchar (' ');
- if (gr)
- if (show_ids)
- printf ("%d(%s)", gid, gr->gr_name);
- else
- printf ("%s", gr->gr_name);
- else
- printf ("%d", gid);
- }
- putchar ('\n');
- }
- }
- if (show_eff)
- print_ids (&_hurd_id.gen, show_avail ? "effective" : 0);
- if (show_avail)
- print_ids (&_hurd_id.aux, show_eff ? "available" : 0);
- }
-
- exit(0);
-}
diff --git a/utils/ids.c b/utils/ids.c
new file mode 100644
index 00000000..f8ad22c5
--- /dev/null
+++ b/utils/ids.c
@@ -0,0 +1,196 @@
+/* Show all hurd ids
+
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <argp.h>
+#include <unistd.h>
+#include <error.h>
+#include <ugids.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (ids);
+
+static struct argp_option options[] =
+{
+ {"terse", 't', 0, 0, "Use a shorter one-line output format"},
+ {"effective", 'e', 0, 0, "Show effective ids"},
+ {"available", 'a', 0, 0, "Show available ids"},
+ {"uids", 'u', 0, 0, "Show user ids"},
+ {"gids", 'g', 0, 0, "Show group ids"},
+ {"names", 'n', 0, 0, "Show names of uids/gids"},
+ {"values", 'v', 0, 0, "Show numeric uids/gids"},
+ {0}
+};
+static char *args_doc = "[PID]";
+static char *doc = "Show hurd uids/gids."
+"\vIf PID is suppplied, show ids in that process.";
+
+/* ---------------------------------------------------------------- */
+
+int
+main(int argc, char *argv[])
+{
+ error_t err;
+ task_t task;
+ mach_port_t msgport;
+ int pid = -1;
+ auth_t auth = getauth ();
+ process_t proc = getproc ();
+ struct ugids ugids = UGIDS_INIT;
+ int show_eff = 0, show_avail = 0, show_uids = 0, show_gids = 0, terse = 0;
+ int show_names = 0, show_values = 0;
+
+ /* Print the given id vectors, using NAME for the prompt. */
+ void print_ids (struct idvec *uids, struct idvec *gids, char *name)
+ {
+ if (show_uids)
+ {
+ if (name && show_gids)
+ printf ("%s uids: ", name);
+ else if (show_gids)
+ printf ("uids: ");
+ else if (name)
+ printf ("%s: ", name);
+ printf ("%s\n",
+ idvec_uids_rep (uids, show_values, show_names, " "));
+ }
+ if (show_gids)
+ {
+ if (name && show_uids)
+ printf ("%s gids: ", name);
+ else if (show_uids)
+ printf ("gids: ");
+ else if (name)
+ printf ("%s: ", name);
+ printf ("%s\n", idvec_gids_rep (gids, show_values, show_names, " "));
+ }
+ }
+
+ /* Parse a command line option. */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'e': show_eff = 1; break;
+ case 'a': show_avail = 1; break;
+ case 'u': show_uids = 1; break;
+ case 'g': show_gids = 1; break;
+ case 'n': show_names = 1; break;
+ case 'v': show_values = 1; break;
+ case 't': terse = 1; break;
+ case ARGP_KEY_ARG:
+ if (state->arg_num == 0)
+ {
+ pid = atoi (arg);
+ break;
+ }
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if (!show_eff && !show_avail)
+ show_eff = show_avail = 1;
+ if (!show_uids && !show_gids)
+ show_uids = show_gids = 1;
+ if (!show_names && !show_values)
+ show_names = show_values = 1;
+
+ if (pid < 0)
+ /* We get our parent's authentication instead of our own because this
+ program is usually installed setuid. This should work even if it's
+ not installed setuid, using the auth port as authentication to the
+ msg_get_init_port rpc. */
+ pid = getppid ();
+
+ /* Get a msgport for PID, to which we can send requests. */
+ err = proc_getmsgport (proc, pid, &msgport);
+ if (err)
+ error (5, err, "%d: Cannot get process msgport", pid);
+
+ /* Try to get the task port to use as authentication. */
+ err = proc_pid2task (proc, pid, &task);
+
+ /* Now fetch the auth port; if we couldn't get the task port to use for
+ authentication, we try the (old) auth port instead. */
+ if (err)
+ err = msg_get_init_port (msgport, auth, INIT_PORT_AUTH, &auth);
+ else
+ err = msg_get_init_port (msgport, task, INIT_PORT_AUTH, &auth);
+ if (err)
+ error (6, err, "%d: Cannot get process authentication", pid);
+
+ mach_port_deallocate (mach_task_self (), msgport);
+ mach_port_deallocate (mach_task_self (), task);
+
+ /* Get the ids that AUTH represents. */
+ err = ugids_merge_auth (&ugids, auth);
+ if (err)
+ error (10, err, "Cannot get authentication ids");
+
+ /* Print them. */
+ if (terse)
+ /* Short output format. */
+ {
+ /* Since we use ugids_rep to format the output, just clear any fields
+ we don't want to show. */
+ if (! show_eff)
+ {
+ idvec_clear (&ugids.eff_uids);
+ idvec_clear (&ugids.eff_gids);
+ }
+ if (! show_avail)
+ {
+ idvec_clear (&ugids.avail_uids);
+ idvec_clear (&ugids.avail_gids);
+ }
+ if (! show_uids)
+ {
+ idvec_clear (&ugids.eff_uids);
+ idvec_clear (&ugids.avail_uids);
+ }
+ if (! show_gids)
+ {
+ idvec_clear (&ugids.eff_gids);
+ idvec_clear (&ugids.avail_gids);
+ }
+ printf ("%s\n", ugids_rep (&ugids, show_values, show_names, 0, " ","="));
+ }
+ else
+ /* Long output format */
+ {
+ if (show_eff)
+ print_ids (&ugids.eff_uids, &ugids.eff_gids,
+ show_avail ? "effective" : 0);
+ if (show_avail)
+ print_ids (&ugids.avail_uids, &ugids.avail_gids,
+ show_eff ? "available" : 0);
+ }
+
+ return 0;
+}
diff --git a/utils/login.c b/utils/login.c
index 46f9629b..cad3b1ed 100644
--- a/utils/login.c
+++ b/utils/login.c
@@ -1,8 +1,8 @@
/* Hurdish login
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2002 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -31,6 +31,8 @@
#include <netdb.h>
#include <time.h>
#include <assert.h>
+#include <version.h>
+#include <sys/mman.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -44,13 +46,16 @@
#include <error.h>
#include <timefmt.h>
#include <hurd/lookup.h>
+#include <ugids.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (login);
extern error_t
exec_reauth (auth_t auth, int secure, int must_reauth,
mach_port_t *ports, unsigned num_ports,
mach_port_t *fds, unsigned num_fds);
-
-char *argp_program_version = "login 1.0 (GNU " HURD_RELEASE ")";
+extern error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids);
/* Defaults for various login parameters. */
char *default_args[] = {
@@ -88,26 +93,28 @@ static struct argp_option options[] =
{"arg", 'a', "ARG", 0, "Add login parameter ARG"},
{"arg-default", 'A', "ARG", 0, "Use ARG as a default login parameter"},
{"no-environment-args", 'X', 0, 0, "Don't add the parent environment as default login params"},
- {"user", 'u', "USER", 0, "Add USER to the effective uids"},
- {"avail-user",'U', "USER", 0, "Add USER to the available uids"},
- {"group", 'g', "GROUP", 0, "Add GROUP to the effective groups"},
- {"avail-group",'G',"GROUP", 0, "Add GROUP to the available groups"},
{"no-login", 'L', 0, 0, "Don't modify the shells argv[0] to look"
" like a login shell"},
{"preserve-environment", 'p', 0, 0, "Inherit the parent's environment"},
{"via", 'h', "HOST", 0, "This login is from HOST"},
{"no-passwd", 'f', 0, 0, "Don't ask for passwords"},
{"paranoid", 'P', 0, 0, "Don't admit that a user doesn't exist"},
- {"keep", 'k', 0, 0, "Keep the old available ids, and save the old"
- "effective ids as available ids"},
+ {"save", 's', 0, 0, "Keep the old available ids, and save the old"
+ " effective ids as available ids"},
{"shell-from-args", 'S', 0, 0, "Use the first shell arg as the shell to invoke"},
{"retry", 'R', "ARG", OPTION_ARG_OPTIONAL,
"Re-exec login with no users after non-fatal errors; if ARG is supplied,"
"add it to the list of args passed to login when retrying"},
{0, 0}
};
+static struct argp_child child_argps[] =
+{
+ { &ugids_argp, 0, "Adding individual user/group ids:" },
+ { 0 }
+};
static char *args_doc = "[USER [ARG...]]";
static char *doc =
+"Exec a program with uids and/or the environment changed appropriately.\v"
"To give args to the shell without specifying a user, use - for USER.\n"
"Current login parameters include HOME, SHELL, USER, NAME, and ROOT.";
@@ -133,7 +140,7 @@ cat (mach_port_t node, char *str)
{
write (0, data, data_len);
if (data != buf)
- vm_deallocate (mach_task_self (), (vm_address_t)data, data_len);
+ munmap (data, data_len);
}
}
if (err)
@@ -181,7 +188,9 @@ add_utmp_entry (char *args, unsigned args_len, int inherit_host)
{
struct utmp *old_utmp;
strncpy (utmp.ut_line, basename (tty), sizeof (utmp.ut_line));
+ setutent ();
old_utmp = getutline (&utmp);
+ endutent ();
if (old_utmp)
{
if (! host)
@@ -201,7 +210,7 @@ add_utmp_entry (char *args, unsigned args_len, int inherit_host)
/* Lookup the host HOST, and add entries for VIA (the host name), and
VIA_ADDR (the dotted decimal address) to ARGS & ARGS_LEN. */
static error_t
-add_canonical_host (char **args, unsigned *args_len, char *host)
+add_canonical_host (char **args, size_t *args_len, char *host)
{
struct hostent *he = gethostbyname (host);
@@ -238,7 +247,7 @@ add_canonical_host (char **args, unsigned *args_len, char *host)
/* Add the `=' separated environment entry ENTRY to ENV & ENV_LEN, exiting
with an error message if we can't. */
static void
-add_entry (char **env, unsigned *env_len, char *entry)
+add_entry (char **env, size_t *env_len, char *entry)
{
char *name = strsep (&entry, "=");
error_t err = envz_add (env, env_len, name, entry);
@@ -263,7 +272,7 @@ check_owned (process_t proc_server, pid_t pid, int *owned)
{
*owned = !(pi->state & PI_NOTOWNED);
if (pi != &_pi)
- vm_deallocate (mach_task_self (), (vm_address_t)pi, pi_size);
+ munmap (pi, pi_size);
}
return err;
@@ -288,7 +297,7 @@ kill_login (process_t proc_server, pid_t pid, int sig)
if (pids[i] != self)
kill (pids[i], sig);
if (pids != _pids)
- vm_deallocate (mach_task_self (), (vm_address_t)pids, num_pids);
+ munmap (pids, num_pids);
}
}
while (!err && num_pids > 0);
@@ -359,7 +368,7 @@ dog (time_t timeout, pid_t pid, char **argv)
}
}
-void
+int
main(int argc, char *argv[])
{
int i;
@@ -368,17 +377,15 @@ main(int argc, char *argv[])
char *path;
error_t err = 0;
char *args = 0; /* The login parameters */
- unsigned args_len = 0;
- char *passwd = 0; /* Login parameters from /etc/passwd */
- unsigned passwd_len = 0;
+ size_t args_len = 0;
char *args_defs = 0; /* Defaults for login parameters. */
- unsigned args_defs_len = 0;
+ size_t args_defs_len = 0;
char *env = 0; /* The new environment. */
- unsigned env_len = 0;
+ size_t env_len = 0;
char *env_defs = 0; /* Defaults for the environment. */
- unsigned env_defs_len = 0;
+ size_t env_defs_len = 0;
char *parent_env = 0; /* The environment we got from our parent */
- unsigned parent_env_len = 0;
+ size_t parent_env_len = 0;
int no_environ = 0; /* If false, use the env as default params. */
int no_args = 0; /* If false, put login params in the env. */
int inherit_environ = 0; /* True if we shouldn't clear our env. */
@@ -387,28 +394,24 @@ main(int argc, char *argv[])
int paranoid = 0; /* Admit no knowledge. */
int retry = 0; /* For some failures, exec a login shell. */
char *retry_args = 0; /* Args passed when retrying. */
- unsigned retry_args_len = 0;
+ size_t retry_args_len = 0;
char *shell = 0; /* The shell program to run. */
char *sh_arg0 = 0; /* The shell's argv[0]. */
char *sh_args = 0; /* The args to the shell. */
- unsigned sh_args_len = 0;
+ size_t sh_args_len = 0;
int shell_arg = 0; /* If there are shell args, use the first as
the shell name. */
- struct idvec *eff_uids = make_idvec (); /* The UIDs of the new shell. */
- struct idvec *eff_gids = make_idvec (); /* The EFF_GIDs. */
- struct idvec *avail_uids = make_idvec (); /* The aux UIDs of the new shell. */
- struct idvec *avail_gids = make_idvec (); /* The aux EFF_GIDs. */
- struct idvec *parent_uids = make_idvec (); /* Parent uids, -SETUID. */
- struct idvec *parent_gids = make_idvec (); /* Parent gids, -SETGID. */
+ struct ugids ugids = UGIDS_INIT; /* Authorization of the new shell. */
+ struct ugids_argp_params ugids_argp_params = { &ugids, 0, 0, 0, -1, 0 };
+ struct idvec parent_uids = IDVEC_INIT; /* Parent uids, -SETUID. */
+ struct idvec parent_gids = IDVEC_INIT; /* Parent gids, -SETGID. */
mach_port_t exec; /* The shell executable. */
- mach_port_t cwd; /* The child's CWD. */
mach_port_t root; /* The child's root directory. */
mach_port_t ports[INIT_PORT_MAX]; /* Init ports for the new process. */
int ints[INIT_INT_MAX]; /* Init ints for it. */
mach_port_t fds[3]; /* File descriptors passed. */
mach_port_t auth; /* The new shell's authentication. */
mach_port_t proc_server = getproc ();
- mach_port_t parent_auth = getauth ();
pid_t pid = getpid (), sid;
/* These three functions are to do child-authenticated lookups. See
@@ -437,9 +440,11 @@ main(int argc, char *argv[])
int retry_argc;
char **retry_argv;
char *via = envz_get (args, args_len, "VIA");
- extern void _argp_unlock_xxx (); /* Secret unknown function. */
- error (retry ? 0 : code, err, fmt, str); /* May exit... */
+ if (fmt)
+ error (retry ? 0 : code, err, fmt, str); /* May exit... */
+ else if (! retry)
+ exit (code);
if (via)
envz_add (&retry_args, &retry_args_len, "--via", via);
@@ -450,104 +455,10 @@ main(int argc, char *argv[])
argz_extract (retry_args, retry_args_len, retry_argv);
/* Reinvoke ourselves with no userids or anything; shouldn't return. */
- _argp_unlock_xxx (); /* Hack to get around problems with getopt. */
main (retry_argc, retry_argv);
exit (code); /* But if it does... */
}
- /* Make sure that the parent_[ug]ids are filled in. To make them useful
- for su'ing, each is the avail ids with all effective ids but the first
- appended; this gets rid of the effect of login being suid, and is useful
- as the new process's avail id list (e.g., the real id is right). */
- void need_parent_ids ()
- {
- if (parent_uids->num == 0 && parent_gids->num == 0)
- {
- struct idvec *p_eff_uids = make_idvec ();
- struct idvec *p_eff_gids = make_idvec ();
- if (!p_eff_uids || !p_eff_gids)
- err = ENOMEM;
- if (! err)
- err = idvec_merge_auth (p_eff_uids, parent_uids,
- p_eff_gids, parent_gids,
- parent_auth);
- if (! err)
- {
- idvec_delete (p_eff_uids, 0); /* Counteract setuid. */
- idvec_delete (p_eff_gids, 0);
- err = idvec_merge (parent_uids, p_eff_uids);
- if (! err)
- err = idvec_merge (parent_gids, p_eff_gids);
- }
- if (err)
- error (39, err, "Can't get uids");
- }
- }
-
- /* Returns true if the *caller* of this login program has UID. */
- int parent_has_uid (uid_t uid)
- {
- need_parent_ids ();
- return idvec_contains (parent_uids, uid);
- }
- /* Returns true if the *caller* of this login program has GID. */
- int parent_has_gid (gid_t gid)
- {
- need_parent_ids ();
- return idvec_contains (parent_gids, gid);
- }
- /* Returns the number of parent uids. */
- int count_parent_uids ()
- {
- need_parent_ids ();
- return parent_uids->num;
- }
- /* Returns the number of parent gids. */
- int count_parent_gids ()
- {
- need_parent_ids ();
- return parent_gids->num;
- }
-
- /* Make sure the user should be allowed to do this. */
- void verify_passwd (const char *name, const char *password,
- uid_t id, int is_group)
- {
- extern char *crypt (const char *string, const char salt[2]);
-#pragma weak crypt
- char *prompt, *unencrypted, *encrypted;
-
- if (!password || !*password
- || idvec_contains (is_group ? eff_gids : eff_uids, id)
- || idvec_contains (is_group ? avail_gids : avail_uids, id)
- || (no_passwd
- && (parent_has_uid (0)
- || (is_group ? parent_has_uid (id) : parent_has_gid (id)))))
- return; /* Already got this one. */
-
- if (name)
- asprintf (&prompt, "Password for %s%s:",
- is_group ? "group " : "", name);
- else
- prompt = "Password:";
-
- unencrypted = getpass (prompt);
- if (crypt)
- {
- encrypted = crypt (unencrypted, password);
- /* Paranoia may destroya. */
- memset (unencrypted, 0, strlen (unencrypted));
- }
- else
- encrypted = unencrypted;
-
- if (name)
- free (prompt);
-
- if (strcmp (encrypted, password) != 0)
- fail (50, 0, "Incorrect password", 0);
- }
-
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -581,14 +492,14 @@ main(int argc, char *argv[])
retry = 1;
break;
- case 'k':
- need_parent_ids ();
- idvec_merge (avail_uids, parent_uids);
- idvec_merge (avail_gids, parent_gids);
+ case 's':
+ idvec_merge (&ugids.avail_uids, &parent_uids);
+ idvec_merge (&ugids.avail_gids, &parent_gids);
break;
case ARGP_KEY_ARG:
if (state->arg_num > 0)
+ /* Program arguments. */
{
err = argz_create (state->argv + state->next - 1,
&sh_args, &sh_args_len);
@@ -599,105 +510,32 @@ main(int argc, char *argv[])
}
if (strcmp (arg, "-") == 0)
- arg = 0; /* Just like there weren't any args at all. */
- /* Fall through to deal with adding the user. */
+ /* An explicit no-user-specified (so remaining args can be used
+ to set the program args). */
+ break;
- case 'u':
- case 'U':
- case ARGP_KEY_NO_ARGS:
- {
- /* USER is whom to look up. If it's 0, then we hit the end of
- the sh_args without seeing a user, so we want to add defaults
- values for `nobody'. */
- char *user = arg ?: envz_get (args, args_len, "NOBODY");
- struct passwd *pw =
- isdigit (*user) ? getpwuid (atoi (user)) : getpwnam (user);
- /* True if this is the user arg and there were no user options. */
- int only_user =
- (key == ARGP_KEY_ARG
- && eff_uids->num == 0 && avail_uids->num <= count_parent_uids ()
- && eff_gids->num == 0 && avail_gids->num <= count_parent_gids ());
-
- if (! pw)
- if (! arg)
- /* It was nobody anyway. Just use the defaults. */
- break;
+ if (isdigit (*arg))
+ err = ugids_set_posix_user (&ugids, atoi (arg));
+ else
+ {
+ struct passwd *pw = getpwnam (arg);
+ if (pw)
+ err = ugids_set_posix_user (&ugids, pw->pw_uid);
else if (paranoid)
- /* In paranoid mode, we don't admit we don't know about a
- user, so we just ask for a password we we know the user
- can't supply. */
- verify_passwd (only_user ? 0 : user, "*", -1, 0);
+ /* Add a bogus uid so that password verification will
+ fail. */
+ idvec_add (&ugids.eff_uids, -1);
else
- fail (10, 0, "%s: Unknown user", user);
-
- if (arg)
- /* If it's not nobody, make sure we're authorized. */
- verify_passwd (only_user ? 0 : pw->pw_name, pw->pw_passwd,
- pw->pw_uid, 0);
-
- if (key == 'U')
- /* Add available ids instead of effective ones. */
- {
- idvec_add_new (avail_uids, pw->pw_uid);
- idvec_add_new (avail_gids, pw->pw_gid);
- }
- else
- {
- if (key == ARGP_KEY_ARG || eff_uids->num == 0)
- /* If it's the argument (as opposed to option) specifying a
- user, or the first option user, then we get defaults for
- various things from the password entry. */
- {
- envz_add (&passwd, &passwd_len, "HOME", pw->pw_dir);
- envz_add (&passwd, &passwd_len, "SHELL", pw->pw_shell);
- envz_add (&passwd, &passwd_len, "NAME", pw->pw_gecos);
- envz_add (&passwd, &passwd_len, "USER", pw->pw_name);
- }
- if (arg) /* A real user. */
- if (key == ARGP_KEY_ARG)
- /* The main user arg; add both effective and available
- ids (the available ids twice, for posix compatibility
- -- once for the real id, and again for the saved). */
- {
- /* Updates the real id in IDS to be ID. */
- void update_real (struct idvec *ids, uid_t id)
- {
- if (ids->num == 0
- || !idvec_tail_contains (ids, 1, ids->ids[0]))
- idvec_insert (ids, 0, id);
- else
- ids->ids[0] = id;
- }
-
- /* Effective */
- idvec_insert_only (eff_uids, 0, pw->pw_uid);
- idvec_insert_only (eff_gids, 0, pw->pw_gid);
- /* Real */
- update_real (avail_uids, pw->pw_uid);
- update_real (avail_gids, pw->pw_gid);
- /* Saved */
- idvec_insert_only (avail_uids, 1, pw->pw_uid);
- idvec_insert_only (avail_gids, 1, pw->pw_gid);
- }
- else
- {
- idvec_add_new (eff_uids, pw->pw_uid);
- idvec_add_new (eff_gids, pw->pw_gid);
- }
- }
- }
+ fail (10, 0, "%s: Unknown user", arg);
+ }
+
+ if (err)
+ fail (11, err, "%s: Can't set user!", arg);
+
break;
- case 'g':
- case 'G':
- {
- struct group *gr =
- isdigit (*arg) ? getgrgid (atoi (arg)) : getgrnam (arg);
- if (! gr)
- fail (11, 0, "%s: Unknown group", arg);
- verify_passwd (gr->gr_name, gr->gr_passwd, gr->gr_gid, 1);
- idvec_add_new (key == 'g' ? eff_gids : avail_gids, gr->gr_gid);
- }
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = &ugids_argp_params;
break;
default:
@@ -705,7 +543,7 @@ main(int argc, char *argv[])
}
return 0;
}
- struct argp argp = {options, parse_opt, args_doc, doc};
+ struct argp argp = { options, parse_opt, args_doc, doc, child_argps };
/* Don't allow logins if the nologin file exists. */
node = file_name_lookup (_PATH_NOLOGIN, O_RDONLY, 0);
@@ -736,9 +574,24 @@ main(int argc, char *argv[])
err = argz_create (environ, &parent_env, &parent_env_len);
+ /* Get authentication of our parent, minus any setuid. */
+ get_nonsugid_ids (&parent_uids, &parent_gids);
+
/* Parse our options. */
argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+ /* Check passwords where necessary. If no_passwd is set, then our parent
+ guarantees identity itself (where it is allowed), but otherwise
+ we want every UID fully checked. */
+ err = ugids_verify_make_auth (&ugids,
+ no_passwd ? &parent_uids : 0,
+ no_passwd ? &parent_gids : 0,
+ 0, 0, 0, 0, &auth);
+ if (err == EACCES)
+ fail (5, 0, "Invalid password", 0);
+ else if (err)
+ error (5, err, "Authentication failure");
+
/* Now that we've parsed the command line, put together all these
environments we've gotten from various places. There are two targets:
(1) the login parameters, and (2) the child environment.
@@ -750,37 +603,56 @@ main(int argc, char *argv[])
d) From the user-specified defaults (--arg-default)
e) From last-ditch defaults given by the DEFAULT_* defines above
- The child environment is from:
+ The child environment (constructed later) is from:
a) User specified (--environ)
b) From the login parameters (if --no-args wasn't specified)
c) From the parent environment, if --inherit-environ was specified
d) From the user-specified default env values (--environ-default)
e) From last-ditch defaults given by the DEFAULT_* defines above
*/
-
- /* Merge the login parameters. */
- err = envz_merge (&args, &args_len, passwd, passwd_len, 0);
- if (! err && ! no_environ)
- err = envz_merge (&args, &args_len, parent_env, parent_env_len, 0);
- if (! err)
- err = envz_merge (&args, &args_len, args_defs, args_defs_len, 0);
- if (err)
- error (24, err, "merging parameters");
-
- err =
- auth_makeauth (getauth (), 0, MACH_MSG_TYPE_COPY_SEND, 0,
- eff_uids->ids, eff_uids->num,
- avail_uids->ids, avail_uids->num,
- eff_gids->ids, eff_gids->num,
- avail_gids->ids, avail_gids->num,
- &auth);
- if (err)
- fail (3, err, "Authentication failure", 0);
+ {
+ struct passwd *pw;
+ char *passwd = 0; /* Login parameters from /etc/passwd */
+ size_t passwd_len = 0;
+
+ /* Decide which password entry to get parameters from. */
+ if (ugids.eff_uids.num > 0)
+ pw = getpwuid (ugids.eff_uids.ids[0]); /* Effective uid */
+ else if (ugids.avail_uids.num > 0)
+ pw = getpwuid (ugids.avail_uids.ids[0]); /* Auxiliary uid */
+ else
+ /* No user! Try to used the `not-logged-in' user to set various
+ parameters. */
+ pw = getpwnam (envz_get (args, args_len, "NOBODY")
+ ?: envz_get (args_defs, args_defs_len, "NOBODY")
+ ?: "login");
+
+ if (pw)
+ {
+ envz_add (&passwd, &passwd_len, "HOME", pw->pw_dir);
+ envz_add (&passwd, &passwd_len, "SHELL", pw->pw_shell);
+ envz_add (&passwd, &passwd_len, "NAME", pw->pw_gecos);
+ envz_add (&passwd, &passwd_len, "USER", pw->pw_name);
+ }
+
+ /* Merge the login parameters. */
+ err = envz_merge (&args, &args_len, passwd, passwd_len, 0);
+ if (! err && ! no_environ)
+ err = envz_merge (&args, &args_len, parent_env, parent_env_len, 0);
+ if (! err)
+ err = envz_merge (&args, &args_len, args_defs, args_defs_len, 0);
+ if (err)
+ error (24, err, "merging parameters");
+
+ free (passwd);
+ }
err = proc_getsid (proc_server, pid, &sid);
assert_perror (err); /* This should never fail. */
- if (!no_login && count_parent_uids () != 0)
+ if (!no_login
+ && (parent_uids.num != 0
+ || ugids.eff_uids.num + ugids.avail_uids.num > 0))
/* Make a new login collection (but only for real users). */
{
char *user = envz_get (args, args_len, "USER");
@@ -788,10 +660,10 @@ main(int argc, char *argv[])
setlogin (user);
proc_make_login_coll (proc_server);
- if (eff_uids->num + avail_uids->num == 0)
+ if (ugids.eff_uids.num + ugids.avail_uids.num == 0)
/* We're transiting from having some uids to having none, which means
this is probably a new login session. Unless specified otherwise,
- set a timer to kill this session if it hasn't aquired any ids by
+ set a timer to kill this session if it hasn't acquired any ids by
then. Note that we fork off the timer process before clearing the
process owner: because we're interested in killing unowned
processes, proc's in-same-login-session rule should apply to us
@@ -805,8 +677,8 @@ main(int argc, char *argv[])
}
}
- if (eff_uids->num > 0)
- proc_setowner (proc_server, eff_uids->ids[0], 0);
+ if (ugids.eff_uids.num > 0)
+ proc_setowner (proc_server, ugids.eff_uids.ids[0], 0);
else
proc_setowner (proc_server, 0, 1); /* Clear the owner. */
@@ -821,6 +693,7 @@ main(int argc, char *argv[])
for (i = 0; i < INIT_PORT_MAX; i++)
ports[i] = MACH_PORT_NULL;
ports[INIT_PORT_PROC] = getproc ();
+ ports[INIT_PORT_CTTYID] = getcttyid ();
ports[INIT_PORT_CRDIR] = getcrdir (); /* May be replaced below. */
ports[INIT_PORT_CWDIR] = getcwdir (); /* " */
@@ -829,11 +702,10 @@ main(int argc, char *argv[])
if (err)
error (40, err, "Port reauth failure");
- /* These are the default values for the child's root/cwd. We don't want to
+ /* These are the default values for the child's root. We don't want to
modify PORTS just yet, because we use it to do child-authenticated
lookups. */
root = ports[INIT_PORT_CRDIR];
- cwd = ports[INIT_PORT_CWDIR];
/* Find the shell executable (we copy the name, as ARGS may be changed). */
if (shell_arg && sh_args && *sh_args)
@@ -888,13 +760,15 @@ main(int argc, char *argv[])
arg = envz_get (args, args_len, "HOME");
if (arg && *arg)
{
- cwd = child_lookup (arg, 0, O_RDONLY);
+ mach_port_t cwd = child_lookup (arg, 0, O_RDONLY);
if (cwd == MACH_PORT_NULL)
{
error (0, errno, "%s", arg);
error (0, 0, "Using HOME=/");
envz_add (&args, &args_len, "HOME", "/");
}
+ else
+ ports[INIT_PORT_CWDIR] = cwd;
}
arg = envz_get (args, args_len, "ROOT");
@@ -944,25 +818,24 @@ main(int argc, char *argv[])
if (no_login)
sh_arg0 = shell_base;
+ else if (ugids.eff_uids.num + ugids.avail_uids.num == 0)
+ /* Use a special format for the argv[0] of a login prompt shell,
+ so that `ps' shows something informative in the COMMAND field.
+ This string must begin with a `-', the convention to tell the
+ shell to be a login shell (i.e. run .profile and the like). */
+ err = (asprintf (&sh_arg0, "-login prompt (%s)", shell_base) == -1
+ ? ENOMEM : 0);
else
- {
- sh_arg0 = malloc (strlen (shell_base) + 2);
- if (! sh_arg0)
- err = ENOMEM;
- else
- /* Prepend the name with a `-', as is the odd custom. */
- {
- sh_arg0[0] = '-';
- strcpy (sh_arg0 + 1, shell_base);
- }
- }
+ /* Prepend a `-' to the name, which is the ancient canonical
+ way to tell the shell that it's a login shell. */
+ err = asprintf (&sh_arg0, "-%s", shell_base) == -1 ? ENOMEM : 0;
}
if (! err)
err = argz_insert (&sh_args, &sh_args_len, sh_args, sh_arg0);
if (err)
error (21, err, "Error building shell args");
- /* Maybe output the message of the day. Note that we we the child's
+ /* Maybe output the message of the day. Note that we use the child's
authentication to do it, so that this program can't be used to read
arbitrary files! */
arg = envz_get (args, args_len, "MOTD");
@@ -982,29 +855,28 @@ main(int argc, char *argv[])
}
/* Now that we don't need to use PORTS for lookups anymore, put the correct
- ROOT and CWD in. */
+ ROOT in. */
ports[INIT_PORT_CRDIR] = root;
- ports[INIT_PORT_CWDIR] = cwd;
/* Get rid of any accumulated null entries in env. */
envz_strip (&env, &env_len);
/* No more authentications to fail, so cross our fingers and add our utmp
entry. */
-
+
if (pid == sid)
/* Only add utmp entries for the session leader. */
- add_utmp_entry (args, args_len, !parent_has_uid (0));
+ add_utmp_entry (args, args_len, !idvec_contains (&parent_uids, 0));
- if ((eff_uids->num | eff_gids->num) && !no_login)
+ if ((ugids.eff_uids.num | ugids.eff_gids.num) && !no_login)
{
char *tty = ttyname (0);
if (tty)
{
/* Change the terminal to be owned by the user. */
err = chown (tty,
- eff_uids->num ? eff_uids->ids[0] : -1,
- eff_gids->num ? eff_gids->ids[0] : -1);
+ ugids.eff_uids.num ? ugids.eff_uids.ids[0] : -1,
+ ugids.eff_gids.num ? ugids.eff_gids.ids[0] : -1);
if (err)
error (0, errno, "chown: %s", tty);
}
@@ -1019,5 +891,5 @@ main(int argc, char *argv[])
if (err)
error(5, err, "%s", shell);
- exit(0);
+ return 0;
}
diff --git a/utils/mount.c b/utils/mount.c
new file mode 100644
index 00000000..8b059c23
--- /dev/null
+++ b/utils/mount.c
@@ -0,0 +1,582 @@
+/* Roughly Unix/Linux-compatible `mount' frontend for Hurd translators.
+
+ Copyright (C) 1999, 2004 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "../sutils/fstab.h"
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <hurd/fsys.h>
+#include <hurd/fshelp.h>
+#include <hurd/paths.h>
+
+#define SEARCH_FMTS _HURD "%sfs\0" _HURD "%s"
+#define DEFAULT_FSTYPE "ext2"
+
+static char *fstype = DEFAULT_FSTYPE;
+static char *device, *mountpoint;
+static int verbose;
+static char *options;
+static size_t options_len;
+static mach_msg_timeout_t timeout;
+
+static enum { mount, query } mode;
+static enum { qf_standard, qf_fstab, qf_translator } query_format;
+static struct fstab_argp_params fstab_params;
+
+
+static const struct argp_option argp_opts[] =
+{
+ {"timeout", 'T', "MILLISECONDS", 0, "Timeout for translator startup"},
+ {"format", 'p', "mount|fstab|translator", OPTION_ARG_OPTIONAL,
+ "Output format for query (no filesystem arguments)"},
+ {"options", 'o', "OPTIONS", 0, "A `,' separated list of options"},
+ {"readonly", 'r', 0, 0, "Never write to disk or allow opens for writing"},
+ {"writable", 'w', 0, 0, "Use normal read/write behavior"},
+ {"update", 'u', 0, 0, "Flush any meta-data cached in core"},
+ {"remount", 0, 0, OPTION_ALIAS},
+ {"verbose", 'v', 0, 0, "Give more detailed information"},
+ {0, 0}
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct fstab_argp_params *params = state->input;
+ error_t err;
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = params; /* pass down to fstab_argp parser */
+ break;
+
+#define ARGZ(call) \
+ err = argz_##call; \
+ if (err) \
+ argp_failure (state, 100, ENOMEM, "%s", arg); \
+ break
+ case 'r': ARGZ (add (&options, &options_len, "ro"));
+ case 'w': ARGZ (add (&options, &options_len, "rw"));
+ case 'u': ARGZ (add (&options, &options_len, "update"));
+ case 'o': ARGZ (add_sep (&options, &options_len, arg, ','));
+ case 'v': ++verbose; break;
+#undef ARGZ
+
+ case 'T':
+ {
+ char *end;
+ unsigned long int ms = strtoul (arg, &end, 10);
+ if (end && *end == '\0')
+ timeout = ms;
+ else
+ {
+ argp_error (state,
+ "--timeout needs a numeric argument (milliseconds)");
+ return EINVAL;
+ }
+ }
+ break;
+
+ case 'p':
+ if (arg == 0 || !strcasecmp (arg, "fstab"))
+ query_format = qf_fstab;
+ else if (!strcasecmp (arg, "mount"))
+ query_format = qf_standard;
+ else if (!strcasecmp (arg, "translator")
+ || !strcasecmp (arg, "showtrans"))
+ query_format = qf_translator;
+ else
+ {
+ argp_error (state, "invalid argument to --format");
+ return EINVAL;
+ }
+ break;
+
+ case ARGP_KEY_ARG:
+ if (mountpoint == 0) /* One arg: mountpoint */
+ mountpoint = arg;
+ else if (device == 0) /* Two args: device, mountpoint */
+ {
+ device = mountpoint;
+ mountpoint = arg;
+ }
+ else /* More than two args. */
+ {
+ argp_error (state, "too many arguments");
+ return EINVAL;
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (! params->do_all)
+ {
+ params->do_all = 1;
+ mode = query;
+ }
+ break;
+
+ case ARGP_KEY_END:
+ if (params->do_all && mountpoint)
+ {
+ argp_error (state, "filesystem argument not allowed with --all");
+ return EINVAL;
+ }
+ if (mode == query && options_len != 0)
+ {
+ argp_error (state,
+ "mount options not allowed without filesystem argument");
+ return EINVAL;
+ }
+ if (mountpoint)
+ switch (argz_count (params->types, params->types_len))
+ {
+ default:
+ argp_error (state,
+ "multiple types not allowed with filesystem argument");
+ return EINVAL;
+ case 1:
+ fstype = params->types;
+ params->types = 0;
+ params->types_len = 0;
+ break;
+ case 0:
+ break;
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static const char doc[] = "Start active filesystem translators";
+static const char args_doc[] = "\
+DEVICE\t(in " _PATH_MNTTAB ")\n\
+DIRECTORY\t(in " _PATH_MNTTAB ")\n\
+[-t TYPE] DEVICE DIRECTORY\n\
+-a";
+static const struct argp_child argp_kids[] =
+{ { &fstab_argp, 0,
+ "Filesystem selection (if no explicit filesystem arguments given):", 2 },
+ { 0 } };
+static struct argp argp = { argp_opts, parse_opt, args_doc, doc, argp_kids };
+
+/* Mount one filesystem. */
+static error_t
+do_mount (struct fs *fs, int remount)
+{
+ error_t err;
+ char *fsopts, *o;
+ size_t fsopts_len;
+ char *mntopts;
+ size_t mntopts_len;
+ fsys_t mounted;
+
+ inline void explain (const char *command)
+ {
+ if (verbose)
+ {
+ const char *o;
+ printf ("%s %s", command, fs->mntent.mnt_dir);
+ for (o = fsopts; o; o = argz_next (fsopts, fsopts_len, o))
+ printf (" %s", o);
+ putchar ('\n');
+ }
+ }
+
+ err = fs_fsys (fs, &mounted);
+ if (err)
+ {
+ error (0, err, "cannot determine if %s is already mounted",
+ fs->mntent.mnt_fsname);
+ return err;
+ }
+
+
+ /* Produce an argz of translator option arguments from the
+ given FS's options and the command-line options. */
+
+#define ARGZ(call) \
+ err = argz_##call; \
+ if (err) \
+ error (3, ENOMEM, "collecting mount options"); \
+
+ if (fs->mntent.mnt_opts)
+ {
+ /* Append the fstab options to any specified on the command line. */
+ ARGZ (create_sep (fs->mntent.mnt_opts, ',', &mntopts, &mntopts_len));
+
+ /* Remove the `noauto' option, since it's for us not the filesystem. */
+ for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o))
+ if (!strcmp (o, MNTOPT_NOAUTO))
+ break;
+ if (o)
+ argz_delete (&mntopts, &mntopts_len, o);
+
+ ARGZ (append (&mntopts, &mntopts_len, options, options_len));
+ }
+ else
+ {
+ mntopts = options;
+ mntopts_len = options_len;
+ }
+
+ /* Convert the list of options into a list of switch arguments. */
+ fsopts = 0;
+ fsopts_len = 0;
+ for (o = mntopts; o; o = argz_next (mntopts, mntopts_len, o))
+ if (*o == '-') /* Allow letter opts `-o -r,-E', BSD style. */
+ {
+ ARGZ (add (&fsopts, &fsopts_len, o));
+ }
+ else if (strcmp (o, "defaults") != 0)
+ {
+ /* Prepend `--' to the option to make a long option switch,
+ e.g. `--ro' or `--rsize=1024'. */
+ char arg[2 + strlen (o) + 1];
+ arg[0] = arg[1] = '-';
+ memcpy (&arg[2], o, sizeof arg - 2);
+ ARGZ (add (&fsopts, &fsopts_len, arg));
+ }
+
+ if (mntopts != options)
+ free (mntopts);
+#undef ARGZ
+
+ if (remount)
+ {
+ if (mounted == MACH_PORT_NULL)
+ {
+ error (0, 0, "%s not already mounted", fs->mntent.mnt_fsname);
+ return EBUSY;
+ }
+
+ /* Send an RPC to request the new options, including --update. */
+ explain ("fsysopts");
+ err = fsys_set_options (mounted, fsopts, fsopts_len, 0);
+ if (err)
+ error (0, err, "cannot remount %s", fs->mntent.mnt_fsname);
+ return err;
+ }
+ else
+ {
+ /* Error during file lookup; we use this to avoid duplicating error
+ messages. */
+ error_t open_err = 0;
+ /* The control port for any active translator we start up. */
+ fsys_t active_control;
+ file_t node; /* Port to the underlying node. */
+ struct fstype *type;
+
+ /* The callback to start_translator opens NODE as a side effect. */
+ error_t open_node (int flags,
+ mach_port_t *underlying,
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
+ {
+ node = file_name_lookup (fs->mntent.mnt_dir,
+ flags | O_NOTRANS, 0666);
+ if (node == MACH_PORT_NULL)
+ {
+ open_err = errno;
+ return open_err;
+ }
+
+ *underlying = node;
+ *underlying_type = MACH_MSG_TYPE_COPY_SEND;
+
+ return 0;
+ }
+
+ if (mounted != MACH_PORT_NULL)
+ {
+ error (0, 0, "%s already mounted", fs->mntent.mnt_fsname);
+ return EBUSY;
+ }
+
+ err = fs_type (fs, &type);
+ if (err)
+ {
+ error (0, err, "%s: cannot determine filesystem type",
+ fs->mntent.mnt_fsname);
+ return err;
+ }
+ if (type->program == 0)
+ {
+ error (0, 0, "%s: filesystem type `%s' unknown",
+ fs->mntent.mnt_fsname, type->name);
+ return EFTYPE;
+ }
+
+ /* Stick the translator program name in front of the option switches. */
+ err = argz_insert (&fsopts, &fsopts_len, fsopts, type->program);
+ /* Now stick the device name on the end as the last argument. */
+ if (!err)
+ err = argz_add (&fsopts, &fsopts_len, fs->mntent.mnt_fsname);
+ if (err)
+ error (3, ENOMEM, "collecting mount options");
+
+ /* Now we have a translator command line argz in FSOPTS. */
+
+ explain ("settrans -a");
+ err = fshelp_start_translator (open_node, NULL, fsopts,
+ fsopts, fsopts_len, timeout,
+ &active_control);
+ /* If ERR is due to a problem opening the translated node, we print
+ that name, otherwise, the name of the translator. */
+ if (open_err)
+ error (0, open_err, "cannot mount on %s", fs->mntent.mnt_dir);
+ else if (err)
+ error (0, err, "cannot start translator %s", fsopts);
+ else
+ {
+ err = file_set_translator (node, 0, FS_TRANS_SET|FS_TRANS_EXCL, 0,
+ 0, 0,
+ active_control, MACH_MSG_TYPE_COPY_SEND);
+ if (err == EBUSY)
+ error (0, 0, "%s already mounted on", fs->mntent.mnt_dir);
+ else if (err)
+ error (0, err, "cannot set translator on %s", fs->mntent.mnt_dir);
+ if (err)
+ fsys_goaway (active_control, FSYS_GOAWAY_FORCE);
+ mach_port_deallocate (mach_task_self (), active_control);
+ }
+
+ return err;
+ }
+}
+
+/* Report the state of one filesystem to stdout. */
+static error_t
+do_query (struct fs *fs)
+{
+ error_t err;
+ fsys_t fsys;
+ char _opts[200], *opts = _opts;
+ size_t opts_len = sizeof opts;
+ size_t nopts;
+
+ err = fs_fsys (fs, &fsys);
+ if (err)
+ return err;
+
+ if (fsys == MACH_PORT_NULL)
+ /* This filesystem is not mounted. Nothing to report. */
+ return 0;
+
+ err = fsys_get_options (fsys, &opts, &opts_len);
+ if (err)
+ {
+ error (0, err, "%s: cannot get filesystem options",
+ fs->mntent.mnt_fsname);
+ return err;
+ }
+
+ nopts = argz_count (opts, opts_len);
+ if (nopts == 0)
+ {
+ error (0, 0, "%s: fsys_get_options returned empty string",
+ fs->mntent.mnt_dir);
+ return EGRATUITOUS;
+ }
+
+ if (query_format == qf_translator)
+ {
+ argz_stringify (opts, opts_len, ' ');
+ printf ("%s: %s\n", fs->mntent.mnt_dir, opts);
+ }
+ else
+ {
+ char *argv[nopts];
+ const char *prog, *device;
+
+ inline const char *fsopt_string (const char *opt) /* canonicalize */
+ {
+ if (opt[0] == '-' && opt[1] == '-')
+ {
+ opt += 2;
+ if (!strcmp (opt, "readonly"))
+ return "ro";
+ if (!strcmp (opt, "writable"))
+ return "rw";
+ }
+ else
+ {
+ if (!strcmp (opt, "-r"))
+ return "ro";
+ if (!strcmp (opt, "-w"))
+ return "rw";
+ }
+ return opt;
+ }
+ inline void print_prog (const char *sfx)
+ {
+ if (!strncmp (_HURD, prog, sizeof _HURD - 1))
+ {
+ const char *type = &prog[sizeof _HURD - 1];
+ size_t len = strlen (type);
+ if (!strcmp (&type[len - 2], "fs"))
+ printf ("%.*s%s", (int) (len - 2), type, sfx);
+ else
+ printf ("%s%s", type, sfx);
+ }
+ else
+ printf ("%s%s", prog, sfx);
+ }
+ inline int print_opts (char sep)
+ {
+ char *opt = argz_next (opts, opts_len, prog);
+ if (opt == 0)
+ return 0;
+ fputs (fsopt_string (opt), stdout);
+ while ((opt = argz_next (opts, opts_len, opt)) != 0)
+ printf ("%c%s", sep, fsopt_string (opt));
+ return 1;
+ }
+
+ argz_extract (opts, opts_len, argv);
+ prog = argv[0];
+
+ if (nopts < 2)
+ device = fs->mntent.mnt_fsname;
+ else
+ {
+ static const char type_opt[] = "--store-type=";
+ device = argv[--nopts];
+ opts_len -= strlen (device) + 1;
+ if (!strncmp (type_opt, argv[nopts - 1], sizeof type_opt - 1))
+ {
+ asprintf ((char **) &device, "%s:%s",
+ &argv[nopts - 1][sizeof type_opt - 1], device);
+ opts_len -= strlen (argv[nopts - 1]) + 1;
+ }
+ }
+
+ switch (query_format)
+ {
+ case qf_standard:
+ printf ("%s on %s type ", device, fs->mntent.mnt_dir);
+ print_prog (" (");
+ if (print_opts (','))
+ puts (")");
+ else
+ puts ("defaults)");
+ break;
+
+ case qf_fstab:
+ printf ("%s\t%s\t", device, fs->mntent.mnt_dir);
+ print_prog ("\t");
+ printf ("%s\t%d %d\n",
+ print_opts (',') ? "" : "defaults",
+ fs->mntent.mnt_freq, fs->mntent.mnt_passno);
+ break;
+
+ case qf_translator: /* impossible */
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ unsigned int remount;
+ struct fstab *fstab;
+ struct fs *fs;
+ error_t err;
+
+ argp_parse (&argp, argc, argv, 0, 0, &fstab_params);
+
+ if (!mountpoint && (fstab_params.types == 0
+
+ || !strncasecmp (fstab_params.types, "no", 2)))
+ {
+ /* Always add the type "swap" to the list of types to exclude. */
+ err = argz_add (&fstab_params.types, &fstab_params.types_len,
+ "no"MNTTYPE_SWAP);
+ if (err)
+ error (3, ENOMEM, "parsing arguments");
+ }
+
+ fstab = fstab_argp_create (&fstab_params, SEARCH_FMTS, sizeof SEARCH_FMTS);
+
+ if (device) /* two-argument form */
+ {
+ struct mntent m =
+ {
+ mnt_fsname: device,
+ mnt_dir: mountpoint,
+ mnt_type: fstype,
+ mnt_opts: 0,
+ mnt_freq: 0, mnt_passno: 0
+ };
+ struct fstype *fst;
+
+ err = fstypes_get (fstab->types, fstype, &fst);
+ if (err)
+ error (106, err, "cannot initialize type %s", fstype);
+ if (fst->program == 0)
+ error (2, 0, "filesystem type %s not recognized", fstype);
+
+ err = fstab_add_mntent (fstab, &m, &fs);
+ if (err)
+ error (2, err, "%s", mountpoint);
+ }
+ else if (mountpoint) /* one-argument form */
+ {
+ fs = fstab_find (fstab, mountpoint);
+ if (!fs)
+ error (2, 0, "%s: Unknown device or filesystem", mountpoint);
+ }
+ else
+ fs = 0;
+
+ /* This is a convenient way of checking for any `remount' options. */
+ remount = 0;
+ err = argz_replace (&options, &options_len, "remount", "update", &remount);
+ if (err)
+ error (3, ENOMEM, "collecting mount options");
+
+ if (fs != 0)
+ err = do_mount (fs, remount);
+ else
+ switch (mode)
+ {
+ case mount:
+ for (fs = fstab->entries; fs; fs = fs->next)
+ {
+ if (fstab_params.do_all && hasmntopt (&fs->mntent, MNTOPT_NOAUTO))
+ continue;
+ err |= do_mount (fs, remount);
+ }
+ break;
+
+ case query:
+ for (fs = fstab->entries; fs; fs = fs->next)
+ err |= do_query (fs);
+ break;
+ }
+
+ return err ? 1 : 0;
+}
diff --git a/utils/mount.sh b/utils/mount.sh
deleted file mode 100755
index a403b8d8..00000000
--- a/utils/mount.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/sh
-#
-# A simple version of mount for the hurd
-#
-
-usage="Usage: $0: [ -rnv | -o DEVOPTS | -t TYPE | -f FSTAB ] ( DEVICE NODE | DEVICE | NODE )"
-
-PATH=/bin
-
-default_type=ufs
-type=""
-fstab=/etc/fstab
-exec=true
-echo=false
-
-while :; do
- case $1 in
- -v) echo=true; margs="$margs -v"; shift;;
- -n) exec=false; margs="$margs -n"; shift;;
- -r) targs="$targs -r"; shift;;
- -t) case "$type" in
- ""|"$2") type="$2"; shift 2; margs="$margs -t $type";;
- *) echo 1>&2 $0: "$2": Filesystem type inconsistent with "$type"
- exit 7;;
- esac;;
- -f) fstab=$2; shift 2;;
- -o) targs="$targs $2"; shift 2;;
- -*) echo 1>&2 $0: $1: unknown flag; echo 1>&2 "$usage"; exit 1;;
- *) break;;
- esac
-done
-
-case "$targs" in ?*)
- # We embed quotes so that spaces are preserved in targs later on
- margs="$margs -o \"$targs\""
-esac
-
-case $# in
- 1)
- # Lookup the given single arg in /etc/fstab for the rest of the args
- args=`gawk -f - $fstab <<END
-\\$1 == "$1" || \\$2 == "$1" {
- for (i = 4; i <= NF; i++)
- printf("%s ", \\$i);
- printf("-t %s %s %s", \\$3, \\$1, \\$2);
- exit(0);
-}
-END
-`
- case "$args" in
- "") echo 1>&2 $0: $1: not found in $fstab; exit 3;;
- *) eval $0 $margs $args;;
- esac
- ;;
-
- 2)
- # Do the mount, by putting an active translator on the node
-
- case "$type" in "") type="$default_type";; esac
-
- if [ ! -x /hurd/$type ]; then
- echo 1>&2 $0: $type: unknown filesystem type
- exit 1
- fi
-
- $echo && echo settrans -a $2 /hurd/$type $targs $1
- $exec && settrans -a $2 /hurd/$type $targs $1
- ;;
-
- *)
- echo 1>&2 "$usage"; exit 1
- ;;
-esac
diff --git a/utils/msgport.c b/utils/msgport.c
new file mode 100644
index 00000000..06b7dc37
--- /dev/null
+++ b/utils/msgport.c
@@ -0,0 +1,661 @@
+/* Send messages to selected processes
+
+ Copyright (C) 1998,99,2000,02 Free Software Foundation, Inc.
+ Written by Jose M. Moya <josem@gnu.org>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+#include "pids.h"
+#include <sys/mman.h>
+
+/* From libc (not in hurd.h) */
+char *
+_hurd_canonicalize_directory_name_internal (file_t thisdir,
+ char *buf,
+ size_t size);
+
+const char *argp_program_version = STANDARD_HURD_VERSION (msgport);
+
+static const struct argp_option options[] =
+{
+ {0, 0}
+};
+
+static const char doc[] =
+"Send messages to selected processes";
+
+static const char args_doc[] =
+"";
+
+
+
+/* All command functions match this prototype. */
+typedef error_t (*cmd_func_t) (pid_t pid, mach_port_t msgport,
+ int argc, char *argv[]);
+
+/* One of these is created for each command given in the command line. */
+typedef struct cmd {
+ /* Function to execute for this command */
+ cmd_func_t f;
+
+ /* Array of arguments that will be passed to function F */
+ char **args;
+ size_t num_args;
+} cmd_t;
+
+
+/* Execute command CMD on process PID */
+error_t
+do_cmd (pid_t pid, cmd_t cmd)
+{
+ error_t err;
+ mach_port_t msgport;
+ process_t proc = getproc ();
+
+ /* Get a msgport for PID, to which we can send requests. */
+ err = proc_getmsgport (proc, pid, &msgport);
+ if (err)
+ error (1, err, "%d: Cannot get process msgport", pid);
+
+ err = (*cmd.f) (pid, msgport, cmd.num_args, cmd.args);
+ if (err)
+ error (2, err, "%d: Cannot execute command", pid);
+
+ mach_port_deallocate (mach_task_self (), msgport);
+ return 0;
+}
+
+
+/* All these functions, whose name start with cmd_, execute some
+ commands on the process PID, by sending messages (see msg.defs) to
+ its message port, which is MSGPORT. ARGC and ARGV are as in main.
+ They return zero iff successful. */
+
+/* Print the name and value of the environment variable ARGV[0].
+ Without arguments (ARGC==0), print the names and values of all
+ environment variables. */
+error_t
+cmd_getenv (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+
+ /* Memory will be vm_allocated by msg_get_* if the result does not
+ fit in buf. */
+ char buf[1024], *data = buf;
+ mach_msg_type_number_t len = sizeof (buf);
+
+ if (argc)
+ {
+ err = msg_get_env_variable (msgport, argv[0], &data, &len);
+ if (err)
+ return err;
+ printf ("%d: %s=%s\n", pid, argv[0], data);
+ }
+ else /* get the whole environment */
+ {
+ char *p;
+ err = msg_get_environment (msgport, &data, &len);
+ if (err)
+ return err;
+ for (p=data; p < data + len; p = strchr (p, '\0') + 1)
+ printf ("%d: %s\n", pid, p);
+ }
+ if (data != buf)
+ munmap (data, len);
+ return err;
+}
+
+/* Set environment variable ARGV[0] to the value ARGV[1]. */
+error_t
+cmd_setenv (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_set_env_variable (msgport, task, argv[0], argv[1], 1);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Clear environment. */
+error_t
+cmd_clearenv (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_set_environment (msgport, task, 0, 0);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Convert string STR in flags for file access modes. STR should be a
+ combination of `r', `w' and `x' (for read, write and execute modes
+ respectively). Other chars are ignored. */
+static inline int
+str2flags (const char *str)
+{
+ int flags = 0;
+ while (*str)
+ {
+ switch (*str)
+ {
+ case 'r': flags |= O_RDONLY; break;
+ case 'w': flags |= O_WRONLY|O_CREAT; break;
+ case 'x': flags |= O_EXEC; break;
+ case 'a': flags |= O_APPEND; break;
+ default:
+ /* ignore */
+ break;
+ }
+ ++str;
+ }
+ return flags;
+}
+
+/* Set port associated to file descriptor FD of process PID, whose
+ message port is MSGPORT, to FILE. Used by
+ cmd_{setfd,stdin,stdout,stderr}. */
+error_t
+do_setfd (pid_t pid, mach_port_t msgport, size_t fd, file_t file)
+{
+ error_t err;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_set_fd (msgport, task, fd, file, MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), file);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Set port associated to file descriptor ARGV[0] to the file ARGV[1].
+ File access mode is given by ARGV[2] (see str2flags). If no access
+ mode is given, the default is O_RDONLY. */
+error_t
+cmd_setfd (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "r");
+ file_t file = file_name_lookup (argv[1], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, atoi (argv[0]), file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Set standard input to ARGV[0]. Optionally, ARGV[1] may specify the
+ file access mode (see str2flags). The default is O_RDONLY */
+error_t
+cmd_stdin (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "r");
+ file_t file = file_name_lookup (argv[0], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, STDIN_FILENO, file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Set standard output to ARGV[0]. Optionally, ARGV[1] may specify the
+ file access mode (see str2flags). The default is O_WRONLY */
+error_t
+cmd_stdout (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "w");
+ file_t file = file_name_lookup (argv[0], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, STDOUT_FILENO, file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Set standard error to ARGV[0]. Optionally, ARGV[1] may specify the
+ file access mode (see str2flags). The default is O_RDONLY */
+error_t
+cmd_stderr (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ int flags = str2flags (argc > 2 ? argv[2] : "w");
+ file_t file = file_name_lookup (argv[0], flags, 0666);
+ if (file == MACH_PORT_NULL)
+ return errno;
+ err = do_setfd (pid, msgport, STDERR_FILENO, file);
+ if (err)
+ mach_port_deallocate (mach_task_self (), file);
+ return err;
+}
+
+/* Change current working directory to ARGV[0]. */
+error_t
+cmd_chcwdir (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ dir = file_name_lookup (argv[0], 0, 0);
+ if (dir == MACH_PORT_NULL)
+ return errno;
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), dir);
+ return err;
+ }
+ err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Change current working directory to current root directory. */
+error_t
+cmd_cdroot (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+ }
+ err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Change current root directory to ARGV[0]. */
+error_t
+cmd_chcrdir (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ dir = file_name_lookup (argv[0], 0, 0);
+ if (dir == MACH_PORT_NULL)
+ return errno;
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), dir);
+ return err;
+ }
+ err = msg_set_init_port (msgport, task, INIT_PORT_CRDIR, dir,
+ MACH_MSG_TYPE_COPY_SEND);
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+/* Print current working directory. */
+error_t
+cmd_pwd (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_get_init_port (msgport, task, INIT_PORT_CWDIR, &dir);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+ }
+ printf ("%d: %s\n", pid,
+ _hurd_canonicalize_directory_name_internal(dir, NULL, 0));
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return 0;
+}
+
+/* Print current root directory */
+error_t
+cmd_getroot (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ file_t dir;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir);
+ if (err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+ }
+ printf ("%d: %s\n", pid,
+ _hurd_canonicalize_directory_name_internal(dir, NULL, 0));
+ mach_port_deallocate (mach_task_self (), dir);
+ mach_port_deallocate (mach_task_self (), task);
+ return 0;
+}
+
+/* Change umask to ARGV[0] (octal value). Without arguments, print
+ the value of current umask. */
+error_t
+cmd_umask (pid_t pid, mach_port_t msgport, int argc, char *argv[])
+{
+ error_t err;
+ mode_t umask;
+ task_t task;
+ process_t proc = getproc ();
+
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ return err;
+ if (argc)
+ {
+ umask = strtol(argv[0], 0, 8);
+ err = msg_set_init_int (msgport, task, INIT_UMASK, umask);
+ }
+ else
+ {
+ err = msg_get_init_int (msgport, task, INIT_UMASK, &umask);
+ if (!err)
+ printf ("%d: %03o\n", pid, umask);
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+
+#define OA OPTION_ARG_OPTIONAL
+
+#define CMD_GETENV 1000
+#define CMD_SETENV 1001
+#define CMD_CLRENV 1002
+#define CMD_CHCWDIR 1003
+#define CMD_CHCRDIR 1004
+#define CMD_CDROOT 1005
+#define CMD_UMASK 1006
+#define CMD_SETFD 1007
+#define CMD_STDIN 1008
+#define CMD_STDOUT 1009
+#define CMD_STDERR 1010
+#define CMD_PWD 1011
+#define CMD_GETROOT 1012
+
+/* Params to be passed as the input when parsing CMDS_ARGP. */
+struct cmds_argp_params
+{
+ /* Array to be extended with parsed cmds. */
+ cmd_t **cmds;
+ size_t *num_cmds;
+};
+
+static const struct argp_option cmd_options[] =
+{
+ {"getenv", CMD_GETENV, "VAR", OA, "Get environment variable"},
+ {"printenv", 0, 0, OPTION_ALIAS},
+ {"setenv", CMD_SETENV, "VAR VALUE", 0, "Set environment variable"},
+ {"clearenv", CMD_CLRENV, 0, 0, "Clear environment"},
+ {"pwd", CMD_PWD, 0, 0, "Print current working directory"},
+ {"getcwd", 0, 0, OPTION_ALIAS},
+ {"getroot", CMD_GETROOT,0, 0, "Print current root directory"},
+ {"setfd", CMD_SETFD, "FD FILE [rwxa]", 0, "Change file descriptor"},
+ {"stdin", CMD_STDIN, "FILE [rwxa]", 0, "Change standard input"},
+ {"stdout", CMD_STDOUT, "FILE [rwxa]", 0, "Change standard output"},
+ {"stderr", CMD_STDERR, "FILE [rwxa]", 0, "Change standard error"},
+ {"chdir", CMD_CHCWDIR,"DIR", 0, "Change current working directory"},
+ {"cd", 0, 0, OPTION_ALIAS},
+ {"chroot", CMD_CHCRDIR,"DIR", 0, "Change current root directory"},
+ {"cdroot", CMD_CDROOT, 0, 0, "Change cwd to root directory"},
+ {"umask", CMD_UMASK, "MASK", OA, "Change umask"},
+ {0, 0}
+};
+
+/* Add a new command to the array of commands already parsed
+ reallocating it in malloced memory. FUNC is the command function.
+ MINARGS and MAXARGS are the minimum and maximum number of arguments
+ the parser will accept for this command. Further checking of the
+ arguments should be done in FUNC. ARG is the next argument in the
+ command line (probably the first argument for this command). STATE
+ is the argp parser state as used in parse_cmd_opt. */
+static error_t
+add_cmd (cmd_func_t func, size_t minargs, size_t maxargs,
+ char *arg, struct argp_state *state)
+{
+ cmd_t *cmd;
+ size_t i = 0;
+
+ struct cmds_argp_params *params = state->input;
+ size_t num_cmds = *params->num_cmds + 1;
+ cmd_t *cmds = realloc (*params->cmds, num_cmds * sizeof(cmd_t));
+
+ *params->cmds = cmds;
+ *params->num_cmds = num_cmds;
+
+ cmd = &cmds[num_cmds-1];
+ cmd->f = func;
+ cmd->args = 0;
+ if (maxargs)
+ {
+ cmd->args = malloc (maxargs * sizeof (char *));
+ if (arg)
+ cmd->args[i++] = arg;
+ while (i < maxargs
+ && state->argv[state->next]
+ && state->argv[state->next][0] != '-')
+ cmd->args[i++] = state->argv[state->next++];
+ }
+ if (i < minargs || i > maxargs)
+ argp_usage(state);
+ cmd->num_args = i;
+ return 0;
+}
+
+/* Parse one option/arg for the argp parser cmds_argp (see argp.h). */
+static error_t
+parse_cmd_opt (int key, char *arg, struct argp_state *state)
+{
+ /* A buffer used for rewriting command line arguments without dashes
+ for the parser to understand them. It gets realloced for each
+ successive arg that needs it, on the assumption that args don't
+ get parsed multiple times. */
+ static char *arg_hack_buf = 0;
+ switch (key)
+ {
+ case ARGP_KEY_ARG: /* Non-option argument. */
+ if (!isdigit (*arg) && !state->quoted)
+ {
+ /* Make state->next point to the just parsed argument to
+ re-parse it with 2 dashes prepended. */
+ size_t len = strlen (arg) + 1;
+ arg_hack_buf = realloc (arg_hack_buf, 2 + len);
+ state->argv[--state->next] = arg_hack_buf;
+ state->argv[state->next][0] = '-';
+ state->argv[state->next][1] = '-';
+ memcpy (&state->argv[state->next][2], arg, len);
+ break;
+ }
+ else
+ return ARGP_ERR_UNKNOWN;
+ case CMD_CHCWDIR:
+ add_cmd (&cmd_chcwdir, 0, 1, arg, state);
+ break;
+ case CMD_CHCRDIR:
+ add_cmd (&cmd_chcrdir, 1, 1, arg, state);
+ break;
+ case CMD_CDROOT:
+ add_cmd (&cmd_cdroot, 0, 0, arg, state);
+ break;
+ case CMD_PWD:
+ add_cmd (&cmd_pwd, 0, 0, arg, state);
+ break;
+ case CMD_GETROOT:
+ add_cmd (&cmd_getroot, 0, 0, arg, state);
+ break;
+ case CMD_UMASK:
+ add_cmd (&cmd_umask, 0, 1, arg, state);
+ break;
+ case CMD_GETENV:
+ add_cmd (&cmd_getenv, 0, 1, arg, state);
+ break;
+ case CMD_SETENV:
+ add_cmd (&cmd_setenv, 2, 2, arg, state);
+ break;
+ case CMD_CLRENV:
+ add_cmd (&cmd_clearenv, 0, 0, arg, state);
+ break;
+ case CMD_SETFD:
+ add_cmd (&cmd_setfd, 2, 3, arg, state);
+ break;
+ case CMD_STDIN:
+ add_cmd (&cmd_stdin, 1, 2, arg, state);
+ break;
+ case CMD_STDOUT:
+ add_cmd (&cmd_stdout, 1, 2, arg, state);
+ break;
+ case CMD_STDERR:
+ add_cmd (&cmd_stderr, 1, 2, arg, state);
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Filtering of help output strings for cmds_argp parser. Return a
+ malloced replacement for TEXT as the arguments doc string. See
+ argp.h for details. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ if (key == ARGP_KEY_HELP_ARGS_DOC)
+ return strdup ("CMD [ARG...]");
+
+ return (char *)text;
+}
+
+/* An argp parser for selecting a command (see argp.h). */
+struct argp cmds_argp = { cmd_options, parse_cmd_opt, 0, 0, 0, help_filter };
+
+
+
+int
+main(int argc, char *argv[])
+{
+ cmd_t *cmds = 0;
+ size_t num_cmds = 0;
+ struct cmds_argp_params cmds_argp_params = { &cmds, &num_cmds };
+ pid_t *pids = 0; /* User-specified pids. */
+ size_t num_pids = 0;
+ struct pids_argp_params pids_argp_params = { &pids, &num_pids, 0 };
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ state->child_inputs[0] = &cmds_argp_params;
+ state->child_inputs[1] = &pids_argp_params;
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ if (!num_cmds || !num_pids)
+ argp_usage (state);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+
+ struct argp_child argp_kids[] =
+ { { &cmds_argp, 0,
+ "Commands:", 2},
+ { &pids_argp, 0,
+ "Process selection:", 3},
+ {0} };
+
+ struct argp argp = { options, parse_opt, args_doc, doc, argp_kids };
+
+ error_t err;
+ pid_t cur_pid = getpid ();
+ pid_t pid;
+ cmd_t cmd;
+ size_t i, j;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ for (i = 0; i < num_pids; ++i)
+ {
+ pid = pids[i];
+ if (pid != cur_pid)
+ for (j = 0; j < num_cmds; ++j)
+ {
+ cmd = cmds[j];
+ if ((err = do_cmd (pid, cmd)))
+ error (2, err, "%d: Cannot execute command", pid);
+ }
+ }
+
+ exit (0);
+}
diff --git a/utils/nonsugid.c b/utils/nonsugid.c
new file mode 100644
index 00000000..71cd3d71
--- /dev/null
+++ b/utils/nonsugid.c
@@ -0,0 +1,63 @@
+/* Get our ids, minus any setuid result
+
+ Copyright (C) 1995,96,97,2000 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <errno.h>
+#include <idvec.h>
+#include <hurd.h>
+
+/* Make sure that the [UG]IDS are filled in. To make them useful for
+ su'ing, each is the avail ids with the saved set-ID removed, and all
+ effective ids but the first appended; this gets rid of the effect of
+ being suid, and is useful as a new process's avail id list (e.g., the
+ real id is right). */
+error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids)
+{
+ if (uids->num == 0 && gids->num == 0)
+ {
+ error_t err = 0;
+ static auth_t auth = MACH_PORT_NULL;
+ struct idvec *p_eff_uids = make_idvec ();
+ struct idvec *p_eff_gids = make_idvec ();
+
+ if (!p_eff_uids || !p_eff_gids)
+ err = ENOMEM;
+
+ if (auth == MACH_PORT_NULL)
+ auth = getauth ();
+
+ if (! err)
+ err = idvec_merge_auth (p_eff_uids, uids, p_eff_gids, gids, auth);
+ if (! err)
+ {
+ idvec_delete (p_eff_uids, 0); /* Remove effective ID from setuid. */
+ idvec_delete (p_eff_gids, 0);
+ idvec_delete (uids, 1); /* Remove saved set-ID from setuid. */
+ idvec_delete (gids, 1);
+ if (! err)
+ err = idvec_merge (uids, p_eff_uids);
+ if (! err)
+ err = idvec_merge (gids, p_eff_gids);
+ }
+
+ return err;
+ }
+ else
+ return 0;
+}
diff --git a/utils/old-ps.c b/utils/old-ps.c
deleted file mode 100644
index 5dac7854..00000000
--- a/utils/old-ps.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- Copyright (C) 1994 Free Software Foundation
-
- 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. */
-
-#include <hurd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-
-/* return a string describing the amount of memory SIZE represents. */
-char *
-mem_str (vm_size_t size)
-{
- char *ret = malloc (10);
- char *spec=" KMG";
- int dec = 0;
-
- while (size > 1000)
- {
- dec = size % 1000;
- size /= 1000;
- spec++;
- }
-
- if (size >= 100)
- sprintf (ret, "%d%c", size, *spec);
- else if (size >= 10)
- sprintf (ret, "%d.%d%c", size, dec / 100, *spec);
- else
- sprintf (ret, "%d.%d%c", size, dec / 10, *spec);
-
- return ret;
-}
-
-/* Return a string representing time T. */
-char *
-time_str (time_value_t *t)
-{
- char *ret = malloc (20);
- int centiseconds;
-
- if (t->microseconds >= 1000000)
- {
- t->seconds += t->microseconds / 1000000;
- t->microseconds %= 1000000;
- }
- centiseconds = t->microseconds / (1000000 / 100);
-
- sprintf (ret, "%d:%02d.%02d",
- t->seconds / 60, /* minutes */
- t->seconds % 60, /* seconds */
- centiseconds);
- return ret;
-}
-
-/* Print a string describing the args of proc PID */
-void
-print_args_str (process_t proc, pid_t pid)
-{
- char *args;
- u_int nargs = 0;
- char *p;
- error_t err;
-
- err = proc_getprocargs (proc, pid, &args, &nargs);
- if (err)
- return;
- p = args;
- while (p - args < nargs)
- {
- printf ("%s ", p);
- p = strchr (p, '\0') + 1;
- }
- vm_deallocate (mach_task_self (), (vm_address_t) args, nargs);
-}
-
-/* Very simple PS */
-int
-main (int argc, char **argv)
-{
- process_t proc;
- pid_t pids[20];
- pid_t *pp = pids;
- u_int npids = 20;
- int ind;
- struct thread_basic_info tbi;
- struct thread_sched_info tsi;
- int verbose;
-
-#if 0
- stdout = mach_open_devstream (getdport (1), "w");
-#endif
-
- if (argc > 2 ||
- (argc == 2 && (argv[1][0] != '-' || argv[1][1] != 'v' || argv[1][2])))
- {
- fprintf (stderr, "Usage: %s [-v]\n", argv[0]);
- exit (1);
- }
- verbose = argc == 2;
-
- if (verbose)
- puts ("PID\tUSER\tPP\tPG\tSS\tThds\tVMem\tRSS\tPRI\t%CPU\tUser\tSystem\tArgs");
- else
- puts ("PID\tUSER\tThds\tVMem\tRSS\tUser\tSystem\tArgs");
- proc = getproc ();
- proc_getallpids (proc, &pp, &npids);
- for (ind = 0; ind < npids; ind++)
- {
- int procinfobuf[0];
- struct procinfo *pi = (struct procinfo *) procinfobuf;
- u_int pisize = 0;
- int i;
-
- proc_getprocinfo (proc, pp[ind], (int **)&pi, &pisize);
-
- if (pi->state & PI_NOPARENT)
- continue;
-
- bzero (&tbi, sizeof tbi);
- bzero (&tsi, sizeof tsi);
- for (i = 0; i < pi->nthreads; i++)
- {
- tsi.base_priority += pi->threadinfos[i].pis_si.base_priority;
- tsi.cur_priority += pi->threadinfos[i].pis_si.cur_priority;
- tbi.cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage;
- tbi.user_time.seconds += pi->threadinfos[i].pis_bi.user_time.seconds;
- tbi.user_time.microseconds
- += pi->threadinfos[i].pis_bi.user_time.microseconds;
- tbi.system_time.seconds
- += pi->threadinfos[i].pis_bi.system_time.seconds;
- tbi.system_time.microseconds
- += pi->threadinfos[i].pis_bi.system_time.microseconds;
- }
- tsi.base_priority /= pi->nthreads;
- tsi.cur_priority /= pi->nthreads;
- tbi.user_time.seconds += tbi.user_time.microseconds / 1000000;
- tbi.user_time.microseconds %= 1000000;
- tbi.system_time.seconds += tbi.system_time.microseconds / 1000000;
- tbi.system_time.microseconds %= 1000000;
- if (verbose)
- printf ("%d\t%d\t%d\t%d\t%d\t%d\t%s\t%s\t%d/%d\t%d\t%s\t%s\t",
- pp[ind],
- (pi->state & PI_NOTOWNED) ? -1 : pi->owner,
- pi->ppid,
- pi->pgrp,
- pi->session,
- pi->nthreads,
- mem_str (pi->taskinfo.virtual_size),
- mem_str (pi->taskinfo.resident_size),
- tsi.base_priority,
- tsi.cur_priority,
- tbi.cpu_usage,
- time_str (&tbi.user_time),
- time_str (&tbi.system_time));
- else
- printf ("%d\t%d\t%d\t%s\t%s\t%s\t%s\t",
- pp[ind],
- (pi->state & PI_NOTOWNED) ? -1 : pi->owner,
- pi->nthreads,
- mem_str (pi->taskinfo.virtual_size),
- mem_str (pi->taskinfo.resident_size),
- time_str (&tbi.user_time),
- time_str (&tbi.system_time));
- print_args_str (proc, pp[ind]);
- putchar ('\n');
- }
- return 0;
-}
diff --git a/utils/old-settrans.c b/utils/old-settrans.c
deleted file mode 100644
index 4d1ba167..00000000
--- a/utils/old-settrans.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Set a passive translator on a file
- Copyright (C) 1994 Free Software Foundation, Inc.
- Written by Michael I. Bushnell.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-#include <hurd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <fcntl.h>
-
-int
-main (int argc, char **argv)
-{
- /* This is pretty kludgy for now. */
- mach_port_t file;
-
- char *buf, *bp;
- int buflen;
- int i;
-
- if (argc < 2)
- {
- fprintf (stderr, "\
-Usage: %s FILE TRANSLATOR [ARG ...]\n\
- or: %s FILE -show\n", argv[0], argv[0]);
- exit (1);
- }
-
- /* Use the O_NOTRANS flag so that we replace any existing
- translator rather than piggybacking on top of it. */
- file = file_name_lookup (argv[1], O_NOTRANS, 0);
- if (file == MACH_PORT_NULL)
- {
- perror (argv[1]);
- exit (1);
- }
-
- if (argc == 3 && !strcmp (argv[2], "-show"))
- {
- char buf[1024], *trans = buf;
- unsigned int len = sizeof buf;
- errno = file_get_translator (file, &trans, &len);
- if (errno)
- {
- perror ("file_get_translator");
- exit (1);
- }
- printf ("%s translated by:", argv[1]);
- do
- {
- char *next;
- printf (" %.*s", (int) len, trans);
- next = memchr (trans, '\0', len);
- if (! next)
- {
- printf ("<unterminated>");
- break;
- }
- len -= ++next - trans;
- trans = next;
- } while (len > 0);
- putchar ('\n');
- exit (0);
- }
-
- buflen = 0;
- for (i = 2; i < argc; i++)
- buflen += strlen (argv[i]) + 1;
-
- bp = buf = alloca (buflen);
-
- for (i = 2; i < argc; i++)
- bp = stpcpy (bp, argv[i]) + 1;
-
- errno = file_set_translator (file, FS_TRANS_SET, 0, 0,
- buf, buflen, MACH_PORT_NULL,
- MACH_MSG_TYPE_COPY_SEND);
- if (errno != 0)
- {
- perror ("Setting translator");
- exit (1);
- }
-
- exit (0);
-}
-
-
-
diff --git a/utils/parse.c b/utils/parse.c
new file mode 100644
index 00000000..5334dbda
--- /dev/null
+++ b/utils/parse.c
@@ -0,0 +1,185 @@
+/* Random helpful option parsing functions
+
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <error.h>
+
+#include "parse.h"
+
+/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
+ empty and DEFAULT_ADD_FN isn't NULL, then call DEFAULT_ADD_FN instead. */
+error_t
+_parse_strlist (char *arg,
+ error_t (*add_fn)(const char *str, struct argp_state *state),
+ error_t (*default_add_fn)(struct argp_state *state),
+ const char *type_name, struct argp_state *state)
+{
+ if (arg)
+ while (isspace(*arg))
+ arg++;
+
+ if (arg == NULL || *arg == '\0')
+ if (default_add_fn)
+ return (*default_add_fn)(state);
+ else
+ {
+ argp_error (state, "Empty %s list", type_name);
+ return EINVAL;
+ }
+ else
+ {
+ error_t err = 0;
+ char *end = arg;
+
+ void mark_end()
+ {
+ *end++ = '\0';
+ while (isspace(*end))
+ end++;
+ }
+ error_t parse_element()
+ {
+ char *cur = arg;
+ if (*cur == '\0')
+ {
+ argp_error (state, "Empty element in %s list", type_name);
+ return EINVAL;
+ }
+ arg = end;
+ return (*add_fn)(cur, state);
+ }
+
+ while (*end != '\0' && !err)
+ switch (*end)
+ {
+ case ' ': case '\t':
+ mark_end();
+ if (*end == ',')
+ mark_end();
+ err = parse_element();
+ break;
+ case ',':
+ mark_end();
+ err = parse_element();
+ break;
+ default:
+ end++;
+ }
+
+ if (! err)
+ err = parse_element();
+
+ return err;
+ }
+}
+
+/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
+ empty and DEFAULT_FN isn't NULL, then call ADD_FN on the resutl of calling
+ DEFAULT_FN instead, otherwise signal an error. */
+error_t
+parse_strlist (char *arg,
+ error_t (*add_fn)(const char *str, struct argp_state *state),
+ const char *(*default_fn)(struct argp_state *state),
+ const char *type_name, struct argp_state *state)
+{
+ error_t default_str_add (struct argp_state *state)
+ { return (*add_fn)((*default_fn)(state), state); }
+ return _parse_strlist (arg, add_fn, default_str_add, type_name, state);
+}
+
+/* For each numeric string in the comma-separated list in ARG, call ADD_FN;
+ if ARG is empty and DEFAULT_FN isn't NULL, then call DEF_FN to get a number,
+ and call ADD_FN on that, otherwise signal an error. If any member of the
+ list isn't a number, and LOOKUP_FN isn't NULL, then it is called to return
+ an integer for the string. LOOKUP_FN should signal an error itself it
+ there's some problem parsing the string. */
+error_t
+parse_numlist (char *arg,
+ error_t (*add_fn)(unsigned num, struct argp_state *state),
+ int (*default_fn)(struct argp_state *state),
+ int (*lookup_fn)(const char *str, struct argp_state *state),
+ const char *type_name, struct argp_state *state)
+{
+ error_t default_num_add() { return (*add_fn)((*default_fn)(state), state); }
+ error_t add_num_str(const char *str, struct argp_state *state)
+ {
+ const char *p;
+ for (p = str; *p != '\0'; p++)
+ if (!isdigit(*p))
+ {
+ if (lookup_fn)
+ return (*add_fn)((*lookup_fn)(str, state), state);
+ else
+ {
+ argp_error (state, "%s: Invalid %s", p, type_name);
+ return EINVAL;
+ }
+ return 0;
+ }
+ return (*add_fn) (atoi (str), state);
+ }
+ return _parse_strlist(arg, add_num_str, default_fn ? default_num_add : 0,
+ type_name, state);
+}
+
+/* Return the index of which of a set of strings ARG matches, including
+ non-ambiguous partial matches. CHOICE_FN should be a function that
+ returns the name of the Nth option, or 0 if N is out of range, and KIND
+ should be a string that describes what's being matched, for use in error
+ messages. If ALLOW_MISMATCHES is true, then -1 is returned in the event
+ that ARG matches no entry , otherwise, an error message is printed and the
+ program exits in this event. If ARG is an ambiguous match, an error
+ message is printed and the program exits. */
+int
+parse_enum (const char *arg,
+ const char *(*choice_fn)(unsigned n),
+ const char *kind, int allow_mismatches,
+ struct argp_state *state)
+{
+ const char *choice;
+ int arglen = strlen (arg);
+ int n = 0;
+ int partial_match = -1;
+
+ while ((choice = (*choice_fn)(n)) != NULL)
+ if (strcasecmp (choice, arg) == 0)
+ return n;
+ else
+ {
+ if (strncasecmp (choice, arg, arglen) == 0)
+ {
+ if (partial_match >= 0)
+ {
+ argp_error (state, "%s: Ambiguous %s", arg, kind);
+ return -1;
+ }
+ else
+ partial_match = n;
+ }
+ n++;
+ }
+
+ if (partial_match < 0 && !allow_mismatches)
+ argp_error (state, "%s: Invalid %s", arg, kind);
+
+ return partial_match;
+}
diff --git a/utils/parse.h b/utils/parse.h
new file mode 100644
index 00000000..9b6f31f9
--- /dev/null
+++ b/utils/parse.h
@@ -0,0 +1,63 @@
+/* Random helpful option parsing functions
+
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#ifndef __PARSE_H__
+#define __PARSE_H__
+
+#include <errno.h>
+#include <argp.h>
+
+/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
+ empty and DEFAULT_FN isn't NULL, then call ADD_FN on the resutl of calling
+ DEFAULT_FN instead, otherwise signal an error. */
+extern error_t
+parse_strlist (char *arg,
+ error_t (*add_fn)(const char *str, struct argp_state *state),
+ const char *(*default_fn)(struct argp_state *state),
+ const char *type_name, struct argp_state *state);
+
+/* For each numeric string in the comma-separated list in ARG, call ADD_FN;
+ if ARG is empty and DEFAULT_FN isn't NULL, then call DEF_FN to get a number,
+ and call ADD_FN on that, otherwise signal an error. If any member of the
+ list isn't a number, and LOOKUP_FN isn't NULL, then it is called to return
+ an integer for the string. LOOKUP_FN should signal an error itself it
+ there's some problem parsing the string. */
+extern error_t
+parse_numlist (char *arg,
+ error_t (*add_fn)(unsigned num, struct argp_state *state),
+ int (*default_fn)(struct argp_state *state),
+ int (*lookup_fn)(const char *str, struct argp_state *state),
+ const char *type_name, struct argp_state *state);
+
+/* Return the index of which of a set of strings ARG matches, including
+ non-ambiguous partial matches. CHOICE_FN should be a function that
+ returns the name of the Nth option, or 0 if N is out of range, and KIND
+ should be a string that describes what's being matched, for use in error
+ messages. If ALLOW_MISMATCHES is true, then -1 is returned in the event
+ that ARG matches no entry , otherwise, an error message is printed and the
+ program exits in this event. If ARG is an ambiguous match, an error
+ message is printed and the program exits. */
+extern int
+parse_enum (const char *arg,
+ const char *(*choice_fn)(unsigned n),
+ const char *kind, int allow_mismatches,
+ struct argp_state *state);
+
+#endif /* __PARSE_H__ */
diff --git a/utils/pids.c b/utils/pids.c
new file mode 100644
index 00000000..44cd0b44
--- /dev/null
+++ b/utils/pids.c
@@ -0,0 +1,231 @@
+/* Pid parsing/frobbing
+
+ Copyright (C) 1997,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <argp.h>
+#include <hurd.h>
+#include <hurd/process.h>
+#include <mach.h>
+#include <sys/mman.h>
+
+#include "parse.h"
+#include "pids.h"
+
+static process_t _proc_server = MACH_PORT_NULL;
+
+/* Return this process's proc server. */
+static inline process_t
+proc_server ()
+{
+ if (_proc_server == MACH_PORT_NULL)
+ _proc_server = getproc ();
+ return _proc_server;
+}
+
+/* Add the pids returned in vm_allocated memory by calling PIDS_FN with ID as
+ an argument to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+error_t
+add_fn_pids (pid_t **pids, size_t *num_pids, unsigned id,
+ error_t (*pids_fn)(process_t proc, pid_t id,
+ pid_t **pids, size_t *num_pids))
+{
+ size_t num_new_pids = 25;
+ pid_t _new_pids[num_new_pids], *new_pids = _new_pids;
+ error_t err = (*pids_fn)(proc_server (), id, &new_pids, &num_new_pids);
+
+ if (! err)
+ {
+ size_t new_sz = *num_pids + num_new_pids;
+ pid_t *new = realloc (*pids, new_sz * sizeof (pid_t));
+ if (new)
+ {
+ bcopy (new_pids, new + (*num_pids * sizeof (pid_t)),
+ num_new_pids * sizeof (pid_t));
+ *pids = new;
+ *num_pids = new_sz;
+ }
+ else
+ err = ENOMEM;
+ if (new_pids != _new_pids)
+ munmap (new_pids, num_new_pids * sizeof (pid_t));
+ }
+
+ return err;
+}
+
+/* Add PID to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+error_t
+add_pid (pid_t **pids, size_t *num_pids, pid_t pid)
+{
+ size_t new_sz = *num_pids + 1;
+ pid_t *new = realloc (*pids, new_sz * sizeof (pid_t));
+
+ if (new)
+ {
+ new[new_sz - 1] = pid;
+ *pids = new;
+ *num_pids = new_sz;
+ return 0;
+ }
+ else
+ return ENOMEM;
+}
+
+struct pids_parse_state
+{
+ struct pids_argp_params *params;
+ struct argp_state *state;
+};
+
+/* Returns our session id. */
+static pid_t
+current_sid (struct argp_state *state)
+{
+ pid_t sid = -1;
+ error_t err = proc_getsid (proc_server (), getpid (), &sid);
+ if (err)
+ argp_failure (state, 2, err, "Couldn't get current session id");
+ return sid;
+}
+
+/* Returns our login collection id. */
+static pid_t
+current_lid (struct argp_state *state)
+{
+ pid_t lid = -1;
+ error_t err = proc_getloginid (proc_server (), getpid (), &lid);
+ if (err)
+ argp_failure (state, 2, err, "Couldn't get current login collection");
+ return lid;
+}
+
+/* Add a specific process to be printed out. */
+static error_t
+parse_pid (unsigned pid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err = add_pid (params->pids, params->num_pids, pid);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add process", pid);
+ return err;
+}
+
+/* Print out all process from the given session. */
+static error_t
+parse_sid (unsigned sid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, sid, proc_getsessionpids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add session", sid);
+ return err;
+}
+
+/* Print out all process from the given login collection. */
+static error_t
+parse_lid (unsigned lid, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, lid, proc_getloginpids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add login collection", lid);
+ return err;
+}
+
+/* Print out all process from the given process group. */
+static error_t
+parse_pgrp (unsigned pgrp, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+ error_t err =
+ add_fn_pids (params->pids, params->num_pids, pgrp, proc_getpgrppids);
+ if (err)
+ argp_failure (state, 2, err, "%d: Cannot add process group", pgrp);
+ return err;
+}
+
+#define OA OPTION_ARG_OPTIONAL
+
+/* Options for PIDS_ARGP. */
+static const struct argp_option options[] =
+{
+ {"login", 'L', "LID", OA, "Processes from the login"
+ " collection LID (which defaults that of"
+ " the current process)"},
+ {"lid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"pid", 'p', "PID", 0, "The process PID"},
+ {"pgrp", 'P', "PGRP", 0, "Processes in process group PGRP"},
+ {"session", 'S', "SID", OA, "Processes from the session SID"
+ " (which defaults to that of the"
+ " current process)"},
+ {"sid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {0, 0}
+};
+
+/* Parse one option/arg for PIDS_ARGP. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct pids_argp_params *params = state->input;
+
+ switch (key)
+ {
+ case 'p':
+ return
+ parse_numlist (arg, parse_pid, NULL, NULL, "process id", state);
+ case 'S':
+ return
+ parse_numlist (arg, parse_sid, current_sid, NULL, "session id", state);
+ case 'L':
+ return
+ parse_numlist (arg, parse_lid, current_lid, NULL, "login collection",
+ state);
+ case 'P':
+ return
+ parse_numlist (arg, parse_pgrp, NULL, NULL, "process group", state);
+
+ case ARGP_KEY_ARG:
+ if (params->parse_pid_args)
+ return parse_numlist (arg, parse_pid, NULL, NULL, "process id", state);
+ /* Else fall through */
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+}
+
+/* Filtering of help output strings for PIDS_ARGP. */
+static char *
+help_filter (int key, const char *text, void *input)
+{
+ struct pids_argp_params *params = input;
+
+ /* Describe the optional behavior of parsing normal args as pids. */
+ if (key == ARGP_KEY_HELP_ARGS_DOC && params->parse_pid_args)
+ return strdup ("[PID...]");
+
+ return (char *)text;
+}
+
+/* A parser for selecting a set of pids. */
+struct argp pids_argp = { options, parse_opt, 0, 0, 0, help_filter };
diff --git a/utils/pids.h b/utils/pids.h
new file mode 100644
index 00000000..dcf87e81
--- /dev/null
+++ b/utils/pids.h
@@ -0,0 +1,47 @@
+/* Pid parsing/frobbing
+
+ Copyright (C) 1997,2001 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __PIDS_H__
+#define __PIDS_H__
+
+/* Add the pids returned in vm_allocated memory by calling PIDS_FN with ID as
+ an argument to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+extern error_t add_fn_pids (pid_t **pids, size_t *num_pids, unsigned id,
+ error_t (*pids_fn)(process_t proc, pid_t id,
+ pid_t **pids, size_t *num_pids));
+
+/* Add PID to PIDS and NUM_PIDS, reallocating it in malloced memory. */
+extern error_t add_pid (pid_t **pids, size_t *num_pids, pid_t pid);
+
+/* Params to be passed as the input when parsing PIDS_ARGP. */
+struct pids_argp_params
+{
+ /* Array to be extended with parsed pids. */
+ pid_t **pids;
+ size_t *num_pids;
+
+ /* If true, parse non-option arguments as pids. */
+ int parse_pid_args;
+};
+
+/* A parser for selecting a set of pids. */
+extern struct argp pids_argp;
+
+#endif /* __PIDS_H__ */
diff --git a/utils/portinfo.c b/utils/portinfo.c
index 10f5fe8f..e78c77df 100644
--- a/utils/portinfo.c
+++ b/utils/portinfo.c
@@ -1,6 +1,6 @@
/* Print information about a task's ports
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996,97,98,99, 2000 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -25,6 +25,7 @@
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+#include <version.h>
#include <mach.h>
@@ -34,15 +35,17 @@
#include <portinfo.h>
#include <portxlate.h>
-char *argp_program_version = "portinfo 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (portinfo);
static const struct argp_option options[] = {
{0,0,0,0,0, 1},
{"verbose", 'v', 0, 0, "Give more detailed information"},
{"members", 'm', 0, 0, "Show members of port-sets"},
{"hex-names", 'x', 0, 0, "Show port names in hexadecimal"},
+#if 0 /* XXX implement this */
{"query-process", 'q', 0, 0, "Query the process itself for the identity of"
" the ports in question -- requires the process be in a sane state"},
+#endif
{"hold", '*', 0, OPTION_HIDDEN},
{0,0,0,0, "Selecting which names to show:", 2},
@@ -54,8 +57,10 @@ static const struct argp_option options[] = {
{0,0,0,0, "Translating port names between tasks:", 3},
{"translate", 't', "PID", 0, "Translate port names to process PID"},
+#if 0
{"show-targets", 'h', 0, 0,
"Print a header describing the target process" },
+#endif
{"no-translation-errors", 'E', 0, 0,
"Don't display an error if a specified port can't be translated" },
#if 0
@@ -63,16 +68,18 @@ static const struct argp_option options[] = {
{"target-receive", 'R', 0, 0,
"Only show ports that translate into receive rights"},
{"target-send", 'S', 0, 0,
- "Only show ports that translate into receive rights"},
+ "Only show ports that translate into send rights"},
{"target-send-once",'O', 0, 0,
- "Only show ports that translate into receive rights"},
+ "Only show ports that translate into send-once rights"},
+ "Only show ports that translate into send once rights"},
#endif
{0}
};
static const char *args_doc = "PID [NAME...]";
static const char *doc =
-"If no port NAMEs are given, all ports in process PID are reported (if"
+"Show information about mach ports NAME... (default all ports) in process PID."
+"\vIf no port NAMEs are given, all ports in process PID are reported (if"
" translation is used, then only those common to both processes). NAMEs"
" may be specified in hexadecimal or octal by using a 0x or 0 prefix.";
@@ -96,11 +103,13 @@ parse_task (char *arg)
err = proc_pid2task (proc, pid, &task);
if (err)
error (11, err, "%s", arg);
+ else if (task == MACH_PORT_NULL)
+ error (11, 0, "%s: Process %d is dead and has no task", arg, (int) pid);
return task;
}
-static volatile hold = 0;
+static volatile int hold = 0;
int
main (int argc, char **argv)
@@ -111,6 +120,7 @@ main (int argc, char **argv)
unsigned show = 0; /* what info we print */
mach_port_type_t only = 0, target_only = 0; /* Which names to show */
task_t xlate_task = MACH_PORT_NULL;
+ int no_translation_errors = 0; /* inhibit complaints about bad names */
struct port_name_xlator *xlator = 0;
/* Parse our options... */
@@ -134,6 +144,7 @@ main (int argc, char **argv)
case 't': xlate_task = parse_task (arg); break;
case 'a': search = 1; break;
+ case 'E': no_translation_errors = 1; break;
case '*':
hold = 1;
@@ -189,7 +200,12 @@ main (int argc, char **argv)
else
{
if (xlator)
- err = print_xlated_port_info (name, 0, xlator, show, stdout);
+ {
+ err = print_xlated_port_info (name, 0, xlator,
+ show, stdout);
+ if (err && no_translation_errors)
+ break;
+ }
else
err = print_port_info (name, 0, task, show, stdout);
if (err)
diff --git a/utils/ps.c b/utils/ps.c
index de913f74..992b467d 100644
--- a/utils/ps.c
+++ b/utils/ps.c
@@ -1,8 +1,8 @@
/* Show process information.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2002,2006 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -30,96 +30,78 @@
#include <idvec.h>
#include <ps.h>
#include <error.h>
+#include <version.h>
+
#include "psout.h"
+#include "parse.h"
+#include "pids.h"
-char *argp_program_version = "ps 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (ps);
#define OA OPTION_ARG_OPTIONAL
static const struct argp_option options[] =
{
- {"all-users", 'a', 0, 0, "List other users' processes"},
+ {0,0,0,0, "Output format selection:", 1},
{"format", 'F', "FMT", 0, "Use the output-format FMT; FMT may be"
" `default', `user', `vmem', `long',"
" `jobc', `full', `hurd', `hurd-long',"
" or a custom format-string"},
{"posix-format",'o', "FMT", 0, "Use the posix-style output-format FMT"},
+ {0, 'f', 0, 0, "Use the `full' output-format"},
+ {0, 'j', 0, 0, "Use the `jobc' output-format"},
+ {0, 'l', 0, 0, "Use the `long' output-format"},
+ {0, 'u', 0, 0, "Use the `user' output-format"},
+ {0, 'v', 0, 0, "Use the `vmem' output-format"},
+
+ {0,0,0,0, "Process filtering (by default, other users'"
+ " processes, threads, and process-group leaders are not shown):", 2},
+ {"all-users", 'a', 0, 0, "List other users' processes"},
{0, 'd', 0, 0, "List all processes except process group"
" leaders"},
{"all", 'e', 0, 0, "List all processes"},
{0, 'A', 0, OPTION_ALIAS}, /* Posix option meaning -e */
- {0, 'f', 0, 0, "Use the `full' output-format"},
{0, 'g', 0, 0, "Include session and login leaders"},
- {"no-header", 'H', 0, 0, "Don't print a descriptive header line"},
- {0, 'j', 0, 0, "Use the `jobc' output-format"},
- {0, 'l', 0, 0, "Use the `long' output-format"},
- {"login", 'L', "LID", OA, "Add the processes from the login"
- " collection LID (which defaults that of"
- " the current process)"},
- {"lid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"owner", 'U', "USER", 0, "Show only processes owned by USER"},
+ {"not-owner", 'O', "USER", 0, "Show only processes not owned by USER"},
+ {"no-parent", 'P', 0, 0, "Include processes without parents"},
+ {"threads", 'T', 0, 0, "Show the threads for each process"},
+ {"tty", 't', "TTY", OA, "Only show processes with controlling"
+ " terminal TTY"},
+ {0, 'x', 0, 0, "Include orphaned processes"},
+
+ {0,0,0,0, "Elision of output fields:", 4},
{"no-msg-port",'M', 0, 0, "Don't show info that uses a process's"
" msg port"},
{"nominal-fields",'n', 0, 0, "Don't elide fields containing"
" `uninteresting' data"},
- {"owner", 'U', "USER", 0, "Show only processes owned by USER"},
- {"not-owner", 'O', "USER", 0, "Show only processes not owned by USER"},
- {"pid", 'p', "PID", 0, "List the process PID"},
- {"pgrp", 'G', "PGRP", 0, "List processes in process group PGRP"},
- {"no-parent", 'P', 0, 0, "Include processes without parents"},
{"all-fields", 'Q', 0, 0, "Don't elide unusable fields (normally"
" if there's some reason ps can't print"
" a field for any process, it's removed"
" from the output entirely)"},
+
+ {0,0,0,0, "Output attributes:"},
+ {"no-header", 'H', 0, 0, "Don't print a descriptive header line"},
{"reverse", 'r', 0, 0, "Reverse the order of any sort"},
- {"session", 'S', "SID", OA, "Add the processes from the session SID"
- " (which defaults to the sid of the"
- " current process)"},
- {"sid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
- {"sort", 'S', "FIELD",0, "Sort the output with respect to FIELD,"
+ {"sort", 's', "FIELD",0, "Sort the output with respect to FIELD,"
" backwards if FIELD is prefixed by `-'"},
- {"threads", 'T', 0, 0, "Show the threads for each process"},
- {"tty", 't', "TTY", OA, "Only show processes with controlling"
- " terminal TTY"},
- {0, 'u', 0, 0, "Use the `user' output-format"},
- {0, 'v', 0, 0, "Use the `vmem' output-format"},
+ {"top", 'h', "ENTRIES", OA, "Show the top ENTRIES processes"
+ " (default 10), or if ENTRIES is"
+ " negative, the bottom -ENTRIES"},
+ {"head", 0, 0, OPTION_ALIAS},
+ {"bottom", 'b', "ENTRIES", OA, "Show the bottom ENTRIES processes"
+ " (default 10)"},
+ {"tail", 0, 0, OPTION_ALIAS},
{"width", 'w', "WIDTH",OA, "If WIDTH is given, try to format the"
" output for WIDTH columns, otherwise,"
- " remove the default limit"},
- {0, 'x', 0, 0, "Include orphaned processes"},
+ " remove the default limit"},
{0, 0}
};
-char *args_doc = "[PID...]";
-
-char *doc = "The USER, LID, PID, PGRP, and SID arguments may also be comma \
-separated lists. The System V options -u and -g may be accessed with -O and \
---pgrp.";
-
-int
-parse_enum(char *arg, char **choices, char *kind, int allow_mismatches)
-{
- int arglen = strlen(arg);
- char **p = choices;
- int partial_match = -1;
-
- while (*p != NULL)
- if (strcmp(*p, arg) == 0)
- return p - choices;
- else
- {
- if (strncmp(*p, arg, arglen) == 0)
- if (partial_match >= 0)
- argp_error (0, "%s: Ambiguous %s", arg, kind);
- else
- partial_match = p - choices;
- p++;
- }
-
- if (partial_match < 0 && !allow_mismatches)
- argp_error (0, "%s: Invalid %s", arg, kind);
-
- return partial_match;
-}
+static const char doc[] =
+"Show information about processes PID... (default all `interesting' processes)"
+"\vThe USER, LID, PID, PGRP, and SID arguments may also be comma separated"
+" lists. The System V options -u and -g may be accessed with -O and -G.";
#define FILTER_OWNER 0x01
#define FILTER_NOT_LEADER 0x02
@@ -127,38 +109,36 @@ parse_enum(char *arg, char **choices, char *kind, int allow_mismatches)
#define FILTER_UNORPHANED 0x08
#define FILTER_PARENTED 0x10
-enum procsets
+/* A particular predefined output format. */
+struct output_fmt
{
- PROCSET_ALL, PROCSET_SESSION, PROCSET_LOGIN
+ const char *name;
+ const char *sort_key; /* How this format should be sorted. */
+ const char *fmt; /* The format string. */
};
-char *procset_names[] =
-{"all", "session", "login", 0};
-
-/* The names of various predefined output formats. */
-char *fmt_names[] =
- {"default", "user", "vmem", "long", "jobc", "full", "hurd", "hurd-long",0};
-/* How each of those formats should be sorted; */
-char *fmt_sortkeys[] =
- {"pid", "-cpu","-mem", "pid", "pid", "pid", "pid", "pid"};
-/* and the actual format strings. */
-char *fmts[] =
+
+/* The predefined output formats. */
+struct output_fmt output_fmts[] =
{
- /* default */
- "%^%?user %pid %th %tt %sc %stat %time %command",
- /* user (-u) */
- "%^%user %pid %th %cpu %mem %sz %rss %tt %sc %stat %command",
- /* vmem (-v) */
- "%^%pid %th %stat %sl %pgins %pgflts %cowflts %zfills %sz %rss %cpu %mem %command",
- /* long (-l) */
- "%^%uid %pid %th %ppid %pri %ni %nth %msgi %msgo %sz %rss %sc %wait %stat %tt %time %command",
- /* jobc (-j) */
- "%^%user %pid %th %ppid %pgrp %sess %lcoll %sc %stat %tt %time %command",
- /* full (-f) (from sysv) */
- "%^%-user %pid %ppid %tty %time %command",
- /* hurd */
- "%pid %th %uid %nth %{vsize:Vmem} %rss %{utime:User} %{stime:System} %args",
- /* hurd-long */
- "%pid %th %uid %ppid %pgrp %sess %nth %{vsize:Vmem} %rss %cpu %{utime:User} %{stime:System} %args"
+ { "default", "pid",
+ "%^%?user %pid %th %tt %sc %stat %time %command" },
+ { "user", "-cpu",
+ "%^%user %pid %th %cpu %mem %sz %rss %tt %sc %stat %start %time %command" },
+ { "vmem", "-mem",
+ "%^%pid %th %stat %sl %pgins %pgflts %cowflts %zfills %sz %rss %cpu %mem %command"
+ },
+ { "long", "pid",
+ "%^%uid %pid %th %ppid %pri %ni %nth %msgi %msgo %sz %rss %sc %wait %stat %tt %time %command" },
+ { "jobc", "pid",
+ "%^%user %pid %th %ppid %pgrp %sess %lcoll %sc %stat %tt %time %command" },
+ { "full", "pid",
+ "%^%-user %pid %ppid %tty %time %command" },
+ { "hurd", "pid",
+ "%pid %th %uid %nth %{vsize:Vmem} %rss %{utime:User} %{stime:System} %args"
+ },
+ { "hurd-long", "pid",
+ "%pid %th %uid %ppid %pgrp %sess %nth %{vsize:Vmem} %rss %cpu %{utime:User} %{stime:System} %args"
+ }
};
/* Augment the standard specs with our own abbrevs. */
@@ -172,141 +152,17 @@ spec_abbrevs[] = {
static struct ps_fmt_specs ps_specs =
{ spec_abbrevs, &ps_std_fmt_specs };
-/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
- empty and DEFAULT_ADD_FN isn't NULL, then call DEFAULT_ADD_FN instead. */
-static void
-_parse_strlist (char *arg,
- void (*add_fn)(const char *str), void (*default_add_fn)(),
- const char *type_name)
-{
- if (arg)
- while (isspace(*arg))
- arg++;
-
- if (arg == NULL || *arg == '\0')
- if (default_add_fn)
- (*default_add_fn)();
- else
- error(7, 0, "Empty %s list", type_name);
- else
- {
- char *end = arg;
-
- void mark_end()
- {
- *end++ = '\0';
- while (isspace(*end))
- end++;
- }
- void parse_element()
- {
- if (*arg == '\0')
- error(7, 0, "Empty element in %s list", type_name);
- (*add_fn)(arg);
- arg = end;
- }
-
- while (*end != '\0')
- switch (*end)
- {
- case ' ': case '\t':
- mark_end();
- if (*end == ',')
- mark_end();
- parse_element();
- break;
- case ',':
- mark_end();
- parse_element();
- break;
- default:
- end++;
- }
-
- parse_element();
- }
-}
-
-/* For each string in the comma-separated list in ARG, call ADD_FN; if ARG is
- empty and DEFAULT_FN isn't NULL, then call ADD_FN on the resutl of calling
- DEFAULT_FN instead, otherwise signal an error. */
-static void
-parse_strlist (char *arg,
- void (*add_fn)(const char *str),
- const char *(*default_fn)(),
- const char *type_name)
-{
- void default_str_add() { (*add_fn)((*default_fn)()); }
- _parse_strlist(arg, add_fn, default_str_add, type_name);
-}
-
-/* For each numeric string in the comma-separated list in ARG, call ADD_FN;
- if ARG is empty and DEFAULT_FN isn't NULL, then call DEF_FN to get a number,
- and call ADD_FN on that, otherwise signal an error. If any member of the
- list isn't a number, and LOOKUP_FN isn't NULL, then it is called to return
- an integer for the string. LOOKUP_FN should signal an error itself it
- there's some problem parsing the string. */
-static void
-parse_numlist (char *arg,
- void (*add_fn)(unsigned num),
- int (*default_fn)(),
- int (*lookup_fn)(const char *str),
- const char *type_name)
-{
- void default_num_add() { (*add_fn)((*default_fn)()); }
- void add_num_str(const char *str)
- {
- const char *p;
- for (p = str; *p != '\0'; p++)
- if (!isdigit(*p))
- {
- if (lookup_fn)
- (*add_fn)((*lookup_fn)(str));
- else
- error (7, 0, "%s: Invalid %s", p, type_name);
- return;
- }
- (*add_fn)(atoi(str));
- }
- _parse_strlist(arg, add_num_str, default_fn ? default_num_add : 0,
- type_name);
-}
-
-static process_t proc_server;
-
-/* Returns our session id. */
-static pid_t
-current_sid()
-{
- pid_t sid;
- error_t err = proc_getsid(proc_server, getpid(), &sid);
- if (err)
- error(2, err, "Couldn't get current session id");
- return sid;
-}
-
-/* Returns our login collection id. */
-static pid_t
-current_lid()
-{
- pid_t lid;
- error_t err = proc_getloginid(proc_server, getpid(), &lid);
- if (err)
- error(2, err, "Couldn't get current login collection") ;
- return lid;
-}
-
/* Returns the UID for the user called NAME. */
static int
-lookup_user(const char *name)
+lookup_user (const char *name, struct argp_state *state)
{
struct passwd *pw = getpwnam(name);
if (pw == NULL)
- error(2, 0, "%s: Unknown user", name);
+ argp_failure (state, 2, 0, "%s: Unknown user", name);
return pw->pw_uid;
}
-void
+int
main(int argc, char *argv[])
{
error_t err;
@@ -317,10 +173,10 @@ main(int argc, char *argv[])
char *arg_hack_buf = 0;
struct idvec *only_uids = make_idvec (), *not_uids = make_idvec ();
char *tty_names = 0;
- unsigned num_tty_names = 0;
+ size_t num_tty_names = 0;
struct proc_stat_list *procset;
struct ps_context *context;
- char *fmt_string = "default", *sort_key_name = NULL;
+ const char *fmt_string = "default", *sort_key_name = NULL;
unsigned filter_mask =
FILTER_OWNER | FILTER_NOT_LEADER | FILTER_UNORPHANED | FILTER_PARENTED;
int sort_reverse = FALSE, print_heading = TRUE;
@@ -329,65 +185,26 @@ main(int argc, char *argv[])
int output_width = -1; /* Desired max output size. */
int show_non_hurd_procs = 1; /* Show non-hurd processes. */
int posix_fmt = 0; /* Use a posix_fmt-style format string. */
+ int top = 0; /* Number of entries to output. */
+ pid_t *pids = 0; /* User-specified pids. */
+ size_t num_pids = 0;
+ struct pids_argp_params pids_argp_params = { &pids, &num_pids, 1 };
- /* Add a specific process to be printed out. */
- void add_pid (unsigned pid)
- {
- struct proc_stat *ps;
-
- err = proc_stat_list_add_pid (procset, pid, &ps);
- if (err)
- error (0, err, "%d: Can't add process", pid);
-
- /* See if this process actually exists. */
- proc_stat_set_flags (ps, PSTAT_PROC_INFO);
- if (! proc_stat_has (ps, PSTAT_PROC_INFO))
- /* Give an error message; using ps_alive_filter below will delete the
- entry so it doesn't get output. */
- error (0, 0, "%d: Unknown process", pid);
-
- /* If explicit processes are specified, we probably don't want to
- filter them out later. This implicit turning off of filtering might
- be confusing in the case where a login-collection or session is
- specified along with some pids, but it's probably not worth worrying
- about. */
- filter_mask = 0;
- }
- /* Print out all process from the given session. */
- void add_sid(unsigned sid)
- {
- err = proc_stat_list_add_session (procset, sid, 0, 0);
- if (err)
- error(2, err, "%u: Can't add session", sid);
- }
- /* Print out all process from the given login collection. */
- void add_lid(unsigned lid)
- {
- error_t err = proc_stat_list_add_login_coll (procset, lid, 0, 0);
- if (err)
- error(2, err, "%u: Can't add login collection", lid);
- }
- /* Print out all process from the given process group. */
- void add_pgrp(unsigned pgrp)
- {
- error_t err = proc_stat_list_add_pgrp (procset, pgrp, 0, 0);
- if (err)
- error(2, err, "%u: Can't add process group", pgrp);
- }
-
/* Add a user who's processes should be printed out. */
- void add_uid (uid_t uid)
+ error_t add_uid (uid_t uid, struct argp_state *state)
{
error_t err = idvec_add (only_uids, uid);
if (err)
- error (23, err, "Can't add uid");
+ argp_failure (state, 23, err, "Can't add uid");
+ return err;
}
/* Add a user who's processes should not be printed out. */
- void add_not_uid (uid_t uid)
+ error_t add_not_uid (uid_t uid, struct argp_state *state)
{
error_t err = idvec_add (not_uids, uid);
if (err)
- error (23, err, "Can't add uid");
+ argp_failure (state, 23, err, "Can't add uid");
+ return err;
}
/* Returns TRUE if PS is owned by any of the users in ONLY_UIDS, and none
in NOT_UIDS. */
@@ -403,11 +220,12 @@ main(int argc, char *argv[])
/* Add TTY_NAME to the list for which processes with those controlling
terminals will be printed. */
- void add_tty_name (const char *tty_name)
+ error_t add_tty_name (const char *tty_name, struct argp_state *state)
{
error_t err = argz_add (&tty_names, &num_tty_names, tty_name);
if (err)
- error (8, err, "%s: Can't add tty", tty_name);
+ argp_failure (state, 8, err, "%s: Can't add tty", tty_name);
+ return err;
}
int proc_stat_has_ctty(struct proc_stat *ps)
{
@@ -431,7 +249,7 @@ main(int argc, char *argv[])
}
/* Returns the name of the current controlling terminal. */
- static const char *current_tty_name()
+ const char *current_tty_name()
{
error_t err;
struct ps_tty *tty;
@@ -463,10 +281,9 @@ main(int argc, char *argv[])
memcpy (&state->argv[state->next][1], arg, len);
break;
}
- /* Otherwise, fall through and treat the arg as a process id. */
- case 'p':
- parse_numlist(arg, add_pid, NULL, NULL, "process id");
- break;
+ else
+ /* Let PIDS_ARGP handle it. */
+ return ARGP_ERR_UNKNOWN;
case 'a': filter_mask &= ~FILTER_OWNER; break;
case 'd': filter_mask &= ~(FILTER_OWNER | FILTER_UNORPHANED); break;
@@ -486,6 +303,8 @@ main(int argc, char *argv[])
case 'T': show_threads = TRUE; break;
case 's': sort_key_name = arg; break;
case 'r': sort_reverse = TRUE; break;
+ case 'h': top = arg ? atoi (arg) : 10; break;
+ case 'b': top = -(arg ? atoi (arg) : 10); break;
case 'F': fmt_string = arg; posix_fmt = 0; break;
case 'o': fmt_string = arg; posix_fmt = 1; break;
@@ -494,22 +313,37 @@ main(int argc, char *argv[])
break;
case 't':
- parse_strlist (arg, add_tty_name, current_tty_name, "tty");
- break;
+ return parse_strlist (arg, add_tty_name, current_tty_name, "tty", state);
case 'U':
- parse_numlist (arg, add_uid, NULL, lookup_user, "user");
- break;
+ return parse_numlist (arg, add_uid, NULL, lookup_user, "user", state);
case 'O':
- parse_numlist (arg, add_not_uid, NULL, lookup_user, "user");
- break;
- case 'S':
- parse_numlist(arg, add_sid, current_sid, NULL, "session id");
- break;
- case 'L':
- parse_numlist(arg, add_lid, current_lid, NULL, "login collection");
+ return parse_numlist (arg, add_not_uid, NULL, lookup_user, "user", state);
+
+ case ARGP_KEY_INIT:
+ /* Initialize inputs for child parsers. */
+ state->child_inputs[0] = &pids_argp_params;
break;
- case 'G':
- parse_numlist(arg, add_pgrp, NULL, NULL, "process group");
+
+ case ARGP_KEY_SUCCESS:
+ /* Select an explicit format string if FMT_STRING is a format
+ name. This is done here because parse_enum needs STATE. */
+ {
+ const char *fmt_name (unsigned n)
+ {
+ return
+ n >= (sizeof output_fmts / sizeof *output_fmts)
+ ? 0
+ : output_fmts[n].name;
+ }
+ int fmt_index = parse_enum (fmt_string, fmt_name,
+ "format type", 1, state);
+ if (fmt_index >= 0)
+ {
+ fmt_string = output_fmts[fmt_index].fmt;
+ if (sort_key_name == NULL)
+ sort_key_name = output_fmts[fmt_index].sort_key;
+ }
+ }
break;
default:
@@ -518,46 +352,27 @@ main(int argc, char *argv[])
return 0;
}
- struct argp argp = { options, parse_opt, args_doc, doc};
-
- proc_server = getproc();
+ struct argp_child argp_kids[] =
+ { { &pids_argp, 0,
+ "Process selection (before filtering; default is all processes):", 3},
+ {0} };
+ struct argp argp = { options, parse_opt, 0, doc, argp_kids };
- err = ps_context_create (proc_server, &context);
+ err = ps_context_create (getproc (), &context);
if (err)
error(1, err, "ps_context_create");
- err = proc_stat_list_create(context, &procset);
- if (err)
- error(1, err, "proc_stat_list_create");
-
/* Parse our command line. This shouldn't ever return an error. */
argp_parse (&argp, argc, argv, 0, 0, 0);
- if (only_uids->num == 0 && (filter_mask & FILTER_OWNER))
- /* Restrict the output to only our own processes. */
- {
- int uid = getuid ();
- if (uid >= 0)
- add_uid (uid);
- else
- filter_mask &= ~FILTER_OWNER; /* Must be an anonymous process. */
- }
-
- {
- int fmt_index = parse_enum(fmt_string, fmt_names, "format type", 1);
- if (fmt_index >= 0)
- {
- fmt_string = fmts[fmt_index];
- if (sort_key_name == NULL)
- sort_key_name = fmt_sortkeys[fmt_index];
- }
- }
+ err = proc_stat_list_create(context, &procset);
+ if (err)
+ error(1, err, "proc_stat_list_create");
- if (proc_stat_list_num_procs (procset) == 0)
+ if (num_pids == 0)
+ /* No explicit processes specified. */
{
err = proc_stat_list_add_all (procset, 0, 0);
- if (err)
- error(2, err, "Can't get process list");
/* Try to avoid showing non-hurd processes if this isn't a native-booted
hurd system (because there would be lots of them). Here we use a
@@ -576,10 +391,29 @@ main(int argc, char *argv[])
show_non_hurd_procs = 1;
}
}
+ else
+ /* User-specified processes. */
+ {
+ err = proc_stat_list_add_pids (procset, pids, num_pids, 0);
+ filter_mask = 0; /* Don't mess with them. */
+ }
+
+ if (err)
+ error(2, err, "Can't get process list");
if (no_msg_port)
proc_stat_list_set_flags(procset, PSTAT_NO_MSGPORT);
+ if (only_uids->num == 0 && (filter_mask & FILTER_OWNER))
+ /* Restrict the output to only our own processes. */
+ {
+ int uid = getuid ();
+ if (uid >= 0)
+ add_uid (uid, 0);
+ else
+ filter_mask &= ~FILTER_OWNER; /* Must be an anonymous process. */
+ }
+
/* Filter out any processes that we don't want to show. */
if (only_uids->num || not_uids->num)
proc_stat_list_filter1 (procset, proc_stat_owner_ok,
@@ -606,7 +440,7 @@ main(int argc, char *argv[])
psout (procset, fmt_string, posix_fmt, &ps_specs,
sort_key_name, sort_reverse,
output_width, print_heading,
- squash_bogus_fields, squash_nominal_fields);
+ squash_bogus_fields, squash_nominal_fields, top);
- exit (0);
+ return 0;
}
diff --git a/utils/psout.c b/utils/psout.c
index 7f2b0591..93667b28 100644
--- a/utils/psout.c
+++ b/utils/psout.c
@@ -1,6 +1,6 @@
/* Common output function for ps & w
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -31,7 +31,8 @@ psout (struct proc_stat_list *procs,
char *fmt_string, int posix_fmt, struct ps_fmt_specs *specs,
char *sort_key_name, int sort_reverse,
int output_width, int print_heading,
- int squash_bogus_fields, int squash_nominal_fields)
+ int squash_bogus_fields, int squash_nominal_fields,
+ int top)
{
error_t err;
struct ps_stream *output;
@@ -96,15 +97,17 @@ psout (struct proc_stat_list *procs,
error (5, err, "Can't make output stream");
if (print_heading)
- if (proc_stat_list_num_procs (procs) > 0)
- {
- err = ps_fmt_write_titles (fmt, output);
- if (err)
- error (0, err, "Can't print titles");
- ps_stream_newline (output);
- }
- else
- error (0, 0, "No applicable processes");
+ {
+ if (procs->num_procs > 0)
+ {
+ err = ps_fmt_write_titles (fmt, output);
+ if (err)
+ error (0, err, "Can't print titles");
+ ps_stream_newline (output);
+ }
+ else
+ error (1, 0, "No applicable processes");
+ }
if (output_width)
/* Try and restrict the number of output columns. */
@@ -117,6 +120,23 @@ psout (struct proc_stat_list *procs,
ps_fmt_set_output_width (fmt, output_width);
}
+ if (top)
+ /* Restrict output to the top TOP entries, if TOP is positive, or the
+ bottom -TOP entries, if it is negative. */
+ {
+ int filter (struct proc_stat *ps)
+ {
+ return --top >= 0;
+ }
+ if (top < 0)
+ {
+ top += procs->num_procs;
+ proc_stat_list_filter1 (procs, filter, 0, 1);
+ }
+ else
+ proc_stat_list_filter1 (procs, filter, 0, 0);
+ }
+
/* Finally, output all the processes! */
err = proc_stat_list_fmt (procs, fmt, output);
if (err)
diff --git a/utils/psout.h b/utils/psout.h
index f9c44484..f4469ac4 100644
--- a/utils/psout.h
+++ b/utils/psout.h
@@ -1,6 +1,6 @@
/* Common output function for ps & w
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -23,10 +23,12 @@
#include <ps.h>
-void psout (struct proc_stat_list *procs,
- char *fmt_string, int posix_fmt, struct ps_fmt_specs *specs,
- char *sort_key_name, int sort_reverse,
+void psout (const struct proc_stat_list *procs,
+ const char *fmt_string, int posix_fmt,
+ const struct ps_fmt_specs *specs,
+ const char *sort_key_name, int sort_reverse,
int output_width, int print_heading,
- int squash_bogus_fields, int squash_nominal_fields);
+ int squash_bogus_fields, int squash_nominal_fields,
+ int top);
#endif /* __PSOUT_H__ */
diff --git a/utils/rmauth.c b/utils/rmauth.c
new file mode 100644
index 00000000..4c68cd18
--- /dev/null
+++ b/utils/rmauth.c
@@ -0,0 +1,121 @@
+/* Remove authentication from selected processes
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rmauth);
+
+static const struct argp_option options[] =
+{
+#ifndef UNSU
+ {"save", 's', 0, 0, "Save removed effective ids as available ids"},
+#endif
+ { 0 }
+};
+
+#ifdef UNSU
+static struct argp_child child_argps[] = {{ &frobauth_posix_argp }, { 0 }};
+#else
+static struct argp_child child_argps[] = {{ &frobauth_ea_argp }, { 0 }};
+#endif
+
+static char doc[] =
+ "Remove user/group ids from the authentication of selected processes";
+
+int
+main (int argc, char *argv[])
+{
+ int save = 0; /* save effective ids */
+ struct frobauth frobauth = FROBAUTH_INIT;
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 's': save = 1; break;
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input; break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ /* Modify UGIDS, to be what PID's new authentication should be, UGIDS is
+ what the user specified. */
+ error_t modify (struct ugids *ugids, const struct ugids *remove,
+ pid_t pid, void *hook)
+ {
+ error_t err = 0;
+ struct ugids saved = UGIDS_INIT;
+
+ if (save)
+ ugids_set (&saved, ugids);
+
+ err = ugids_subtract (ugids, remove);
+
+ if (save)
+ {
+ ugids_subtract (&saved, ugids);
+ ugids_save (&saved);
+ ugids_merge (ugids, &saved);
+ }
+
+ return err;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *removed,
+ pid_t pid, void *hook)
+ {
+ char *delta_rep;
+ struct ugids delta = UGIDS_INIT;
+
+ ugids_set (&delta, old);
+ ugids_subtract (&delta, new);
+
+ delta_rep = ugids_rep (&delta, 1, 1, 0, 0, 0);
+ printf ("%d: Removed %s\n", pid, delta_rep);
+
+ free (delta_rep);
+ ugids_fini (&delta);
+ }
+ struct argp argp = { options, parse_opt, 0, doc, child_argps };
+
+#ifdef UNSU
+ frobauth.default_user = 0;
+#endif
+ frobauth.require_ids = 1;
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ if (frobauth_modify (&frobauth, 0, 0, modify, print_info, 0))
+ return 0;
+ else
+ return 1;
+}
diff --git a/utils/rpctrace.c b/utils/rpctrace.c
new file mode 100644
index 00000000..996d4bae
--- /dev/null
+++ b/utils/rpctrace.c
@@ -0,0 +1,1238 @@
+/* Trace RPCs sent to selected ports
+
+ Copyright (C) 1998, 1999, 2001, 2002, 2003, 2005, 2006, 2009, 2011
+ Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/ihash.h>
+#include <mach/message.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <argp.h>
+#include <error.h>
+#include <string.h>
+#include <version.h>
+#include <sys/wait.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <argz.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (rpctrace);
+
+#define STD_MSGIDS_DIR DATADIR "/msgids/"
+
+static unsigned strsize = 80;
+
+#define OPT_NOSTDINC -1
+static const struct argp_option options[] =
+{
+ {"output", 'o', "FILE", 0, "Send trace output to FILE instead of stderr."},
+ {"nostdinc", OPT_NOSTDINC, 0, 0,
+ "Do not search inside the standard system directory, `" STD_MSGIDS_DIR
+ "', for `.msgids' files."},
+ {"rpc-list", 'i', "FILE", 0,
+ "Read FILE for assocations of message ID numbers to names."},
+ {0, 'I', "DIR", 0,
+ "Add the directory DIR to the list of directories to be searched for files "
+ "containing message ID numbers."},
+ {0, 's', "SIZE", 0, "Specify the maximum string size to print (the default is 80)."},
+ {0}
+};
+
+static const char args_doc[] = "COMMAND [ARG...]";
+static const char doc[] = "Trace Mach Remote Procedure Calls.";
+
+/* The msgid_ihash table maps msgh_id values to names. */
+
+struct msgid_info
+{
+ char *name;
+ char *subsystem;
+};
+
+static void
+msgid_ihash_cleanup (void *element, void *arg)
+{
+ struct msgid_info *info = element;
+ free (info->name);
+ free (info->subsystem);
+ free (info);
+}
+
+static struct hurd_ihash msgid_ihash
+ = HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
+
+/* Parse a file of RPC names and message IDs as output by mig's -list
+ option: "subsystem base-id routine n request-id reply-id". Put each
+ request-id value into `msgid_ihash' with the routine name as its value. */
+static void
+parse_msgid_list (const char *filename)
+{
+ FILE *fp;
+ char *buffer = NULL;
+ size_t bufsize = 0;
+ unsigned int lineno = 0;
+ char *name, *subsystem;
+ unsigned int msgid;
+ error_t err;
+
+ fp = fopen (filename, "r");
+ if (fp == 0)
+ {
+ error (2, errno, "%s", filename);
+ return;
+ }
+
+ while (getline (&buffer, &bufsize, fp) > 0)
+ {
+ ++lineno;
+ if (buffer[0] == '#' || buffer[0] == '\0')
+ continue;
+ if (sscanf (buffer, "%as %*u %as %*u %u %*u\n",
+ &subsystem, &name, &msgid) != 3)
+ error (0, 0, "%s:%u: invalid format in RPC list file",
+ filename, lineno);
+ else
+ {
+ struct msgid_info *info = malloc (sizeof *info);
+ if (info == 0)
+ error (1, errno, "malloc");
+ info->name = name;
+ info->subsystem = subsystem;
+ err = hurd_ihash_add (&msgid_ihash, msgid, info);
+ if (err)
+ error (1, err, "hurd_ihash_add");
+ }
+ }
+
+ free (buffer);
+ fclose (fp);
+}
+
+/* Look for a name describing MSGID. We check the table directly, and
+ also check if this looks like the ID of a reply message whose request
+ ID is already in the table. */
+static const struct msgid_info *
+msgid_info (mach_msg_id_t msgid)
+{
+ const struct msgid_info *info = hurd_ihash_find (&msgid_ihash, msgid);
+ if (info == 0 && (msgid / 100) % 2 == 1)
+ {
+ /* This message ID is not in the table, and its number makes it
+ what should be an RPC reply message ID. So look up the message
+ ID of the corresponding RPC request and synthesize a name from
+ that. Then stash that name in the table so the next time the
+ lookup will match directly. */
+ info = hurd_ihash_find (&msgid_ihash, msgid - 100);
+ if (info != 0)
+ {
+ struct msgid_info *reply_info = malloc (sizeof *info);
+ if (reply_info != 0)
+ {
+ reply_info->subsystem = strdup (info->subsystem);
+ reply_info->name = 0;
+ asprintf (&reply_info->name, "%s-reply", info->name);
+ hurd_ihash_add (&msgid_ihash, msgid, reply_info);
+ info = reply_info;
+ }
+ else
+ info = 0;
+ }
+ }
+ return info;
+}
+
+static const char *
+msgid_name (mach_msg_id_t msgid)
+{
+ const struct msgid_info *info = msgid_info (msgid);
+ return info ? info->name : 0;
+}
+
+/* Return true if this message's data should be printed out.
+ For a request message, that means the in parameters.
+ For a reply messages, that means the return code and out parameters. */
+static int
+msgid_display (const struct msgid_info *info)
+{
+ return 1;
+}
+
+/* Return true if we should interpose on this RPC's reply port. If this
+ returns false, we will pass the caller's original reply port through so
+ we never see the reply message at all. */
+static int
+msgid_trace_replies (const struct msgid_info *info)
+{
+ return 1;
+}
+
+/* We keep one of these structures for each port right we are tracing. */
+struct traced_info
+{
+ struct port_info pi;
+
+ mach_port_t forward; /* real port */
+ mach_msg_type_name_t type;
+
+ char *name; /* null or a string describing this */
+
+ union
+ {
+ struct traced_info *nextfree; /* Link when on free list. */
+
+ struct /* For a send right wrapper. */
+ {
+ hurd_ihash_locp_t locp; /* position in the traced_names hash table */
+ } send;
+
+ struct /* For a send-once right wrapper. */
+ {
+ /* We keep track of the send right to which the message containing
+ this send-once right as its reply port was sent, and the msgid of
+ that request. We don't hold a reference to the send right; it is
+ just a hint to indicate a match with a send right on which we just
+ forwarded a message. */
+ mach_port_t sent_to;
+ mach_msg_id_t sent_msgid;
+ } send_once;
+ } u;
+};
+#define INFO_SEND_ONCE(info) ((info)->type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+
+static struct traced_info *freelist;
+
+struct hurd_ihash traced_names
+ = HURD_IHASH_INITIALIZER (offsetof (struct traced_info, u.send.locp));
+struct port_class *traced_class;
+struct port_bucket *traced_bucket;
+FILE *ostream;
+
+/* These are the calls made from the tracing engine into
+ the output formatting code. */
+
+/* Called for a message that does not look like an RPC reply.
+ The header has already been swapped into the sender's view
+ with interposed ports. */
+static void print_request_header (struct traced_info *info,
+ mach_msg_header_t *header);
+
+/* Called for a message that looks like an RPC reply. */
+static void print_reply_header (struct traced_info *info,
+ mig_reply_header_t *header);
+
+/* Called for each data item (which might be an array).
+ Always called after one of the above two. */
+static void print_data (mach_msg_type_name_t type,
+ const void *data,
+ mach_msg_type_number_t nelt,
+ mach_msg_type_number_t eltsize);
+
+/*** Mechanics of tracing messages and interposing on ports ***/
+
+
+/* Create a new wrapper port and do `ports_get_right' on it. */
+static struct traced_info *
+new_send_wrapper (mach_port_t right, mach_port_t *wrapper_right)
+{
+ error_t err;
+ struct traced_info *info;
+
+ /* Use a free send-once wrapper port if we have one. */
+ if (freelist)
+ {
+ info = freelist;
+ freelist = info->u.nextfree;
+ }
+ else
+ {
+ /* Create a new wrapper port that forwards to *RIGHT. */
+ err = ports_create_port (traced_class, traced_bucket,
+ sizeof *info, &info);
+ assert_perror (err);
+ info->name = 0;
+ }
+
+ info->forward = right;
+ info->type = MACH_MSG_TYPE_MOVE_SEND;
+
+ /* Store it in the reverse-lookup hash table, so we can
+ look up this same right again to find the wrapper port.
+ The entry in the hash table holds a weak ref on INFO. */
+ err = hurd_ihash_add (&traced_names, info->forward, info);
+ assert_perror (err);
+ ports_port_ref_weak (info);
+ assert (info->u.send.locp != 0);
+
+ *wrapper_right = ports_get_right (info);
+ ports_port_deref (info);
+
+ return info;
+}
+
+/* Create a new wrapper port and do `ports_get_right' on it. */
+static struct traced_info *
+new_send_once_wrapper (mach_port_t right, mach_port_t *wrapper_right)
+{
+ error_t err;
+ struct traced_info *info;
+
+ /* Use a free send-once wrapper port if we have one. */
+ if (freelist)
+ {
+ info = freelist;
+ freelist = info->u.nextfree;
+ }
+ else
+ {
+ /* Create a new wrapper port that forwards to *RIGHT. */
+ err = ports_create_port (traced_class, traced_bucket,
+ sizeof *info, &info);
+ assert_perror (err);
+ info->name = 0;
+ }
+
+ info->forward = right;
+ info->type = MACH_MSG_TYPE_MOVE_SEND_ONCE;
+
+ /* Send-once rights never compare equal to any other right (even
+ another send-once right), so there is no point in putting them
+ in the reverse-lookup table.
+
+ Since we never make send rights to this port, we don't want to
+ use the normal libports mechanisms (ports_get_right) that are
+ designed for send rights and no-senders notifications.
+ Instead, we hold on to the initial hard ref to INFO until we
+ receive a message on it. The kernel automatically sends a
+ MACH_NOTIFY_SEND_ONCE message if the send-once right dies. */
+
+ *wrapper_right = info->pi.port_right;
+ memset (&info->u.send_once, 0, sizeof info->u.send_once);
+
+ return info;
+}
+
+
+/* This gets called when a wrapper port has no hard refs (send rights),
+ only weak refs. The only weak ref is the one held in the reverse-lookup
+ hash table. */
+static void
+traced_dropweak (void *pi)
+{
+ struct traced_info *const info = pi;
+
+ assert (info->type == MACH_MSG_TYPE_MOVE_SEND);
+ assert (info->u.send.locp);
+
+ /* Remove INFO from the hash table. */
+ hurd_ihash_locp_remove (&traced_names, info->u.send.locp);
+ ports_port_deref_weak (info);
+
+ /* Deallocate the forward port, so the real port also sees no-senders. */
+ mach_port_deallocate (mach_task_self (), info->forward);
+
+ /* There are no rights to this port, so we can reuse it.
+ Add a hard ref and put INFO on the free list. */
+ ports_port_ref (info);
+
+ free (info->name);
+ info->name = 0;
+
+ info->u.nextfree = freelist;
+ freelist = info;
+}
+
+
+/* Rewrite a port right in a message with an appropriate wrapper port. */
+static struct traced_info *
+rewrite_right (mach_port_t *right, mach_msg_type_name_t *type)
+{
+ error_t err;
+ struct traced_info *info;
+
+ /* We can never do anything special with a null or dead port right. */
+ if (!MACH_PORT_VALID (*right))
+ return 0;
+
+ switch (*type)
+ {
+ case MACH_MSG_TYPE_PORT_SEND:
+ /* See if we are already tracing this port. */
+ info = hurd_ihash_find (&traced_names, *right);
+ if (info)
+ {
+ /* We are already tracing this port. We will pass on a right
+ to our existing wrapper port. */
+ *right = ports_get_right (info);
+ *type = MACH_MSG_TYPE_MAKE_SEND;
+ return info;
+ }
+
+ /* See if this is already one of our own wrapper ports. */
+ info = ports_lookup_port (traced_bucket, *right, 0);
+ if (info)
+ {
+ /* This is a send right to one of our own wrapper ports.
+ Instead, send along the original send right. */
+ mach_port_deallocate (mach_task_self (), *right); /* eat msg ref */
+ *right = info->forward;
+ err = mach_port_mod_refs (mach_task_self (), *right,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ ports_port_deref (info);
+ return info;
+ }
+
+ /* We have never seen this port before. Create a new wrapper port
+ and replace the right in the message with a right to it. */
+ *type = MACH_MSG_TYPE_MAKE_SEND;
+ return new_send_wrapper (*right, right);
+
+ case MACH_MSG_TYPE_PORT_SEND_ONCE:
+ /* There is no way to know if this send-once right is to the same
+ receive right as any other send-once or send right we have seen.
+ Fortunately, it doesn't matter, since the recipient of the
+ send-once right we pass along can't tell either. We always just
+ make a new send-once wrapper object, that will trace the one
+ message it receives, and then die. */
+ *type = MACH_MSG_TYPE_MAKE_SEND_ONCE;
+ return new_send_once_wrapper (*right, right);
+
+ case MACH_MSG_TYPE_PORT_RECEIVE:
+ /* We have got a receive right, call it A. We will pass along a
+ different receive right of our own, call it B. We ourselves will
+ receive messages on A, trace them, and forward them on to B.
+
+ If A is the receive right to a send right that we have wrapped,
+ then B must be that wrapper receive right, moved from us to the
+ intended receiver of A--that way it matches previous send rights
+ to A that were sent through and replaced with our wrapper (B).
+ If not, we create a new receive right. */
+ {
+ mach_port_t rr; /* B */
+ char *name;
+
+ info = hurd_ihash_find (&traced_names, *right);
+ if (info)
+ {
+ /* This is a receive right that we have been tracing sends to. */
+ name = info->name;
+ rr = ports_claim_right (info);
+ /* That released the refs on INFO, so it's been freed now. */
+ }
+ else
+ {
+ /* This is a port we know nothing about. */
+ rr = mach_reply_port ();
+ name = 0;
+ }
+
+ /* Create a new wrapper object that receives on this port. */
+ err = ports_import_port (traced_class, traced_bucket,
+ *right, sizeof *info, &info);
+ assert_perror (err);
+ info->name = name;
+ info->type = MACH_MSG_TYPE_MOVE_SEND; /* XXX ? */
+
+ /* Get us a send right that we will forward on. */
+ err = mach_port_insert_right (mach_task_self (), rr, rr,
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+ info->forward = rr;
+
+ err = hurd_ihash_add (&traced_names, info->forward, info);
+ assert_perror (err);
+ ports_port_ref_weak (info);
+
+ /* If there are no extant send rights to this port, then INFO will
+ die right here and release its send right to RR.
+ XXX what to do?
+ */
+ ports_port_deref (info);
+
+ *right = rr;
+ return info;
+ }
+
+ default:
+ assert (!"??? bogus port type from kernel!");
+ }
+ return 0;
+}
+
+static void
+print_contents (mach_msg_header_t *inp,
+ void *msg_buf_ptr)
+{
+ error_t err;
+
+ int first = 1;
+
+ /* Process the message data, wrapping ports and printing data. */
+ while (msg_buf_ptr < (void *) inp + inp->msgh_size)
+ {
+ mach_msg_type_t *const type = msg_buf_ptr;
+ mach_msg_type_long_t *const lt = (void *) type;
+ void *data;
+ mach_msg_type_number_t nelt; /* Number of data items. */
+ mach_msg_type_size_t eltsize; /* Bytes per item. */
+ mach_msg_type_name_t name; /* MACH_MSG_TYPE_* code */
+
+ if (!type->msgt_longform)
+ {
+ name = type->msgt_name;
+ nelt = type->msgt_number;
+ eltsize = type->msgt_size / 8;
+ data = msg_buf_ptr = type + 1;
+ }
+ else
+ {
+ name = lt->msgtl_name;
+ nelt = lt->msgtl_number;
+ eltsize = lt->msgtl_size / 8;
+ data = msg_buf_ptr = lt + 1;
+ }
+
+ if (!type->msgt_inline)
+ {
+ /* This datum is out-of-line, meaning the message actually
+ contains a pointer to a vm_allocate'd region of data. */
+ data = *(void **) data;
+ msg_buf_ptr += sizeof (void *);
+ }
+ else
+ msg_buf_ptr += ((nelt * eltsize + sizeof(natural_t) - 1)
+ & ~(sizeof(natural_t) - 1));
+
+ if (first)
+ first = 0;
+ else
+ putc (' ', ostream);
+
+ /* Note that MACH_MSG_TYPE_PORT_NAME does not indicate a port right.
+ It indicates a port name, i.e. just an integer--and we don't know
+ what task that port name is meaningful in. If it's meaningful in
+ a traced task, then it refers to our intercepting port rather than
+ the original port anyway. */
+ if (MACH_MSG_TYPE_PORT_ANY_RIGHT (name))
+ {
+ /* These are port rights. Translate them into wrappers. */
+ mach_port_t *const portnames = data;
+ mach_msg_type_number_t i;
+ mach_msg_type_name_t newtypes[nelt];
+ int poly;
+ struct traced_info *ti;
+
+ assert (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX);
+ assert (eltsize == sizeof (mach_port_t));
+
+ poly = 0;
+ for (i = 0; i < nelt; ++i)
+ {
+ newtypes[i] = name;
+
+ if (inp->msgh_id == 3215) /* mach_port_insert_right */
+ {
+ /* XXX
+ */
+ fprintf (ostream,
+ "\t\t[%d] = pass through port %d, type %d\n",
+ i, portnames[i], name);
+ continue;
+ }
+
+ ti = rewrite_right (&portnames[i], &newtypes[i]);
+
+ putc ((i == 0 && nelt > 1) ? '{' : ' ', ostream);
+
+ if (portnames[i] == MACH_PORT_NULL)
+ fprintf (ostream, "(null)");
+ else if (portnames[i] == MACH_PORT_DEAD)
+ fprintf (ostream, "(dead)");
+ else
+ {
+ assert (ti);
+ if (ti->name != 0)
+ fprintf (ostream, "%s", ti->name);
+ else
+ fprintf (ostream, "%3u", (unsigned int) portnames[i]);
+ }
+ if (i > 0 && newtypes[i] != newtypes[0])
+ poly = 1;
+ }
+ if (nelt > 1)
+ putc ('}', ostream);
+
+ if (poly)
+ {
+ if (name == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ /* Some of the new rights are MAKE_SEND_ONCE.
+ Turn them all into MOVE_SEND_ONCE. */
+ for (i = 0; i < nelt; ++i)
+ if (newtypes[i] == MACH_MSG_TYPE_MAKE_SEND_ONCE)
+ {
+ err = mach_port_insert_right (mach_task_self (),
+ portnames[i],
+ portnames[i],
+ newtypes[i]);
+ assert_perror (err);
+ }
+ else
+ assert (newtypes[i] == MACH_MSG_TYPE_MOVE_SEND_ONCE);
+ }
+ else
+ {
+ for (i = 0; i < nelt; ++i)
+ switch (newtypes[i])
+ {
+ case MACH_MSG_TYPE_COPY_SEND:
+ err = mach_port_mod_refs (mach_task_self (),
+ portnames[i],
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ break;
+ case MACH_MSG_TYPE_MAKE_SEND:
+ err = mach_port_insert_right (mach_task_self (),
+ portnames[i],
+ portnames[i],
+ newtypes[i]);
+ assert_perror (err);
+ break;
+ default:
+ assert (newtypes[i] == MACH_MSG_TYPE_MOVE_SEND);
+ break;
+ }
+
+ name = MACH_MSG_TYPE_MOVE_SEND;
+ }
+ if (type->msgt_longform)
+ lt->msgtl_name = name;
+ else
+ type->msgt_name = name;
+ }
+ else if (nelt > 0 && newtypes[0] != name)
+ {
+ if (type->msgt_longform)
+ lt->msgtl_name = newtypes[0];
+ else
+ type->msgt_name = newtypes[0];
+ }
+ }
+ else
+ print_data (name, data, nelt, eltsize);
+ }
+}
+
+int
+trace_and_forward (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ const mach_msg_type_t RetCodeType =
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name = */
+ 32, /* msgt_size = */
+ 1, /* msgt_number = */
+ TRUE, /* msgt_inline = */
+ FALSE, /* msgt_longform = */
+ FALSE, /* msgt_deallocate = */
+ 0 /* msgt_unused = */
+ };
+
+ error_t err;
+ const struct msgid_info *msgid;
+ struct traced_info *info;
+ mach_msg_bits_t complex;
+
+ /* Look up our record for the receiving port. There is no need to check
+ the class, because our port bucket only ever contains one class of
+ ports (traced_class). */
+ info = ports_lookup_port (traced_bucket, inp->msgh_local_port, 0);
+ assert (info);
+
+ /* A notification message from the kernel appears to have been sent
+ with a send-once right, even if there have never really been any. */
+ if (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ if (inp->msgh_id == MACH_NOTIFY_DEAD_NAME)
+ {
+ /* If INFO is a send-once wrapper, this could be a forged
+ notification; oh well. XXX */
+
+ const mach_dead_name_notification_t *const n = (void *) inp;
+
+ assert (n->not_port == info->forward);
+ /* Deallocate extra ref allocated by the notification. */
+ mach_port_deallocate (mach_task_self (), n->not_port);
+ ports_destroy_right (info);
+ ports_port_deref (info);
+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+ return 1;
+ }
+ else if (inp->msgh_id == MACH_NOTIFY_NO_SENDERS
+ && !INFO_SEND_ONCE (info))
+ {
+ /* No more senders for a send right we are tracing. Now INFO
+ will die, and we will release the tracee send right so it too
+ can see a no-senders notification. */
+ mach_no_senders_notification_t *n = (void *) inp;
+ ports_no_senders (info, n->not_count);
+ ports_port_deref (info);
+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+ return 1;
+ }
+ }
+
+ assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) == info->type);
+
+ complex = inp->msgh_bits & MACH_MSGH_BITS_COMPLEX;
+
+ msgid = msgid_info (inp->msgh_id);
+
+ /* Swap the header data like a crossover cable. */
+ {
+ mach_msg_type_name_t this_type = MACH_MSGH_BITS_LOCAL (inp->msgh_bits);
+ mach_msg_type_name_t reply_type = MACH_MSGH_BITS_REMOTE (inp->msgh_bits);
+
+ inp->msgh_local_port = inp->msgh_remote_port;
+ if (reply_type && msgid_trace_replies (msgid))
+ {
+ struct traced_info *info;
+ info = rewrite_right (&inp->msgh_local_port, &reply_type);
+ assert (info);
+ if (info->name == 0)
+ {
+ if (msgid == 0)
+ asprintf (&info->name, "reply(%u:%u)",
+ (unsigned int) info->pi.port_right,
+ (unsigned int) inp->msgh_id);
+ else
+ asprintf (&info->name, "reply(%u:%s)",
+ (unsigned int) info->pi.port_right, msgid->name);
+ }
+ if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ info->u.send_once.sent_to = info->pi.port_right;
+ info->u.send_once.sent_msgid = inp->msgh_id;
+ }
+ }
+
+ inp->msgh_remote_port = info->forward;
+ if (this_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ {
+ /* We have a message to forward for a send-once wrapper object.
+ Since each wrapper object only lives for a single message, this
+ one can be reclaimed now. We continue to hold a hard ref to the
+ ports object, but we know that nothing else refers to it now, and
+ we are consuming its `forward' right in the message we send. */
+ free (info->name);
+ info->name = 0;
+ info->u.nextfree = freelist;
+ freelist = info;
+ }
+ else
+ this_type = MACH_MSG_TYPE_COPY_SEND;
+
+ inp->msgh_bits = complex | MACH_MSGH_BITS (this_type, reply_type);
+ }
+
+ /* The message now appears as it would if we were the sender.
+ It is ready to be resent. */
+
+ if (msgid_display (msgid))
+ {
+ if (inp->msgh_local_port == MACH_PORT_NULL
+ && info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE
+ && inp->msgh_size >= sizeof (mig_reply_header_t)
+ && (*(int *) &((mig_reply_header_t *) inp)->RetCodeType
+ == *(int *)&RetCodeType))
+ {
+ /* This sure looks like an RPC reply message. */
+ mig_reply_header_t *rh = (void *) inp;
+ print_reply_header (info, rh);
+ putc (' ', ostream);
+ print_contents (&rh->Head, rh + 1);
+ putc ('\n', ostream);
+ }
+ else
+ {
+ /* Print something about the message header. */
+ print_request_header (info, inp);
+ print_contents (inp, inp + 1);
+ if (inp->msgh_local_port == MACH_PORT_NULL) /* simpleroutine */
+ fprintf (ostream, ");\n");
+ else
+ /* Leave a partial line that will be finished later. */
+ fprintf (ostream, ")");
+ }
+ }
+
+ /* Resend the message to the tracee. */
+ err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+ /* The tracee port died. No doubt we are about to receive the dead-name
+ notification. */
+ /* XXX MAKE_SEND, MAKE_SEND_ONCE rights in msg not handled */
+ mach_msg_destroy (inp);
+ }
+ else
+ assert_perror (err);
+
+ ports_port_deref (info);
+
+ /* We already sent the message, so the server loop shouldn't do it again. */
+ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
+
+ return 1;
+}
+
+/* This function runs in the tracing thread and drives all the tracing. */
+static any_t
+trace_thread_function (void *arg)
+{
+ struct port_bucket *const bucket = arg;
+ ports_manage_port_operations_one_thread (bucket, trace_and_forward, 0);
+ return 0;
+}
+
+/*** Output formatting ***/
+
+#if 0
+struct msg_type
+{
+ const char *name;
+ const char *letter;
+};
+
+static const char *const msg_types[] =
+{
+ [MACH_MSG_TYPE_BIT] = {"bool", "b"},
+ [MACH_MSG_TYPE_INTEGER_16] = {"int16", "h"},
+ [MACH_MSG_TYPE_INTEGER_32] = {"int32", "i"},
+ [MACH_MSG_TYPE_CHAR] = {"char", "c"},
+ [MACH_MSG_TYPE_INTEGER_8] = {"int8", "B"},
+ [MACH_MSG_TYPE_REAL] = {"float", "f"},
+ [MACH_MSG_TYPE_INTEGER_64] = {"int64", "q"},
+ [MACH_MSG_TYPE_STRING] = {"string", "s"},
+ [MACH_MSG_TYPE_MOVE_RECEIVE] = {"move-receive", "R"},
+ [MACH_MSG_TYPE_MOVE_SEND] = {"move-send", "S"},
+ [MACH_MSG_TYPE_MOVE_SEND_ONCE]= {"move-send-once", "O"},
+ [MACH_MSG_TYPE_COPY_SEND] = {"copy-send", "s"},
+ [MACH_MSG_TYPE_MAKE_SEND] = {"make-send", ""},
+ [MACH_MSG_TYPE_MAKE_SEND_ONCE]= {"make-send-once", ""},
+ [MACH_MSG_TYPE_PORT_NAME] = {"port-name", "n"},
+};
+#endif
+
+static mach_port_t expected_reply_port;
+
+static void
+print_request_header (struct traced_info *receiver, mach_msg_header_t *msg)
+{
+ const char *msgname = msgid_name (msg->msgh_id);
+
+ expected_reply_port = msg->msgh_local_port;
+
+ if (receiver->name != 0)
+ fprintf (ostream, "%4s->", receiver->name);
+ else
+ fprintf (ostream, "%4u->", (unsigned int) receiver->pi.port_right);
+
+ if (msgname != 0)
+ fprintf (ostream, "%5s (", msgname);
+ else
+ fprintf (ostream, "%5u (", (unsigned int) msg->msgh_id);
+}
+
+static void
+unfinished_line (void)
+{
+ /* A partial line was printed by print_request_header, but
+ cannot be finished before we print something else.
+ Finish this line with the name of the reply port that
+ will appear in the disconnected reply later on. */
+ fprintf (ostream, " > %4u ...\n", expected_reply_port);
+}
+
+static void
+print_reply_header (struct traced_info *info, mig_reply_header_t *reply)
+{
+ if (info->pi.port_right == expected_reply_port)
+ {
+ /* We have printed a partial line for the request message,
+ and now we have the corresponding reply. */
+ if (reply->Head.msgh_id == info->u.send_once.sent_msgid + 100)
+ fprintf (ostream, " = "); /* normal case */
+ else
+ /* This is not the proper reply message ID. */
+ fprintf (ostream, " =(%u != %u) ",
+ reply->Head.msgh_id,
+ info->u.send_once.sent_msgid + 100);
+ }
+ else
+ {
+ /* This does not match up with the last thing printed. */
+ if (expected_reply_port != MACH_PORT_NULL)
+ /* We don't print anything if the last call was a simpleroutine. */
+ unfinished_line ();
+ if (info->name == 0)
+ /* This was not a reply port in previous message sent
+ through our wrappers. */
+ fprintf (ostream, "reply?%4u",
+ (unsigned int) info->pi.port_right);
+ else
+ fprintf (ostream, "%s%4u",
+ info->name, (unsigned int) info->pi.port_right);
+ if (reply->Head.msgh_id == info->u.send_once.sent_msgid + 100)
+ /* This is a normal reply to a previous request. */
+ fprintf (ostream, " > ");
+ else
+ {
+ /* Weirdo. */
+ const char *msgname = msgid_name (reply->Head.msgh_id);
+ if (msgname == 0)
+ fprintf (ostream, " >(%u) ", reply->Head.msgh_id);
+ else
+ fprintf (ostream, " >(%s) ", msgname);
+ }
+ }
+
+ if (reply->RetCode == 0)
+ fprintf (ostream, "0");
+ else
+ {
+ const char *str = strerror (reply->RetCode);
+ if (str == 0)
+ fprintf (ostream, "%#x", reply->RetCode);
+ else
+ fprintf (ostream, "%#x (%s)", reply->RetCode, str);
+ }
+
+ expected_reply_port = MACH_PORT_NULL;
+}
+
+
+static void
+print_data (mach_msg_type_name_t type,
+ const void *data,
+ mach_msg_type_number_t nelt,
+ mach_msg_type_number_t eltsize)
+{
+ switch (type)
+ {
+ case MACH_MSG_TYPE_PORT_NAME:
+ assert (eltsize == sizeof (mach_port_t));
+ {
+ mach_msg_type_number_t i;
+ fprintf (ostream, "pn{");
+ for (i = 0; i < nelt; ++i)
+ {
+ fprintf (ostream, "%*u", (i > 0) ? 4 : 3,
+ (unsigned int) ((mach_port_t *) data)[i]);
+ }
+ fprintf (ostream, "}");
+ return;
+ }
+
+ case MACH_MSG_TYPE_STRING:
+ case MACH_MSG_TYPE_CHAR:
+ if (nelt > strsize)
+ nelt = strsize;
+ fprintf (ostream, "\"%.*s\"",
+ (int) (nelt * eltsize), (const char *) data);
+ return;
+
+#if 0
+ case MACH_MSG_TYPE_CHAR:
+ if (eltsize == 1)
+ FMT ("'%c'", unsigned char);
+ break;
+#endif
+
+#define FMT(fmt, ctype) do { \
+ mach_msg_type_number_t i; \
+ for (i = 0; i < nelt; ++i) \
+ { \
+ fprintf (ostream, "%s" fmt, \
+ (i == 0 && nelt > 1) ? "{" : i > 0 ? " " : "", \
+ *(const ctype *) data); \
+ data += eltsize; \
+ } \
+ if (nelt > 1) \
+ putc ('}', ostream); \
+ return; \
+ } while (0)
+
+ case MACH_MSG_TYPE_BIT:
+ case MACH_MSG_TYPE_INTEGER_8:
+ case MACH_MSG_TYPE_INTEGER_16:
+ case MACH_MSG_TYPE_INTEGER_32:
+ case MACH_MSG_TYPE_INTEGER_64:
+ switch (eltsize)
+ {
+ case 1: FMT ("%"PRId8, int8_t);
+ case 2: FMT ("%"PRId16, int16_t);
+ case 4: FMT ("%"PRId32, int32_t);
+ case 8: FMT ("%"PRId64, int64_t);
+ }
+ break;
+
+ case MACH_MSG_TYPE_REAL:
+ if (eltsize == sizeof (float))
+ FMT ("%g", float);
+ else if (eltsize == sizeof (double))
+ FMT ("%g", double);
+ else if (eltsize == sizeof (long double))
+ FMT ("%Lg", long double);
+ else
+ abort ();
+ break;
+ }
+
+ /* XXX */
+ fprintf (ostream, "\t%#x (type %d, %d*%d)\n", *(const int *)data, type,
+ nelt, eltsize);
+}
+
+
+/*** Main program and child startup ***/
+
+task_t traced_task;
+
+
+/* Run a child and have it do more or else `execvpe (argv, envp);'. */
+pid_t
+traced_spawn (char **argv, char **envp)
+{
+ error_t err;
+ pid_t pid;
+ mach_port_t task_wrapper;
+ struct traced_info *ti;
+ file_t file = file_name_path_lookup (argv[0], getenv ("PATH"),
+ O_EXEC, 0, 0);
+
+ if (file == MACH_PORT_NULL)
+ error (1, errno, "command not found: %s", argv[0]);
+
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &traced_task);
+ assert_perror (err);
+
+ /* Declare the new task to be our child. This is what a fork does. */
+ err = proc_child (getproc (), traced_task);
+ if (err)
+ error (2, err, "proc_child");
+ pid = task2pid (traced_task);
+ if (pid < 0)
+ error (2, errno, "task2pid");
+
+ /* Create a trace wrapper for the task port. */
+ ti = new_send_wrapper (traced_task, &task_wrapper);/* consumes ref */
+ asprintf (&ti->name, "task%d", (int) pid);
+
+ /* Replace the task's kernel port with the wrapper. When this task calls
+ `mach_task_self ()', it will get our wrapper send right instead of its
+ own real task port. */
+ err = mach_port_insert_right (mach_task_self (), task_wrapper,
+ task_wrapper, MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+ err = task_set_special_port (traced_task, TASK_KERNEL_PORT, task_wrapper);
+ assert_perror (err);
+
+ /* Now actually run the command they told us to trace. We do the exec on
+ the actual task, so the RPCs to map in the program itself do not get
+ traced. Could have an option to use TASK_WRAPPER here instead. */
+ err = _hurd_exec (traced_task, file, argv, envp);
+ if (err)
+ error (2, err, "cannot exec `%s'", argv[0]);
+
+ /* We were keeping this send right alive so that the wrapper object
+ cannot die and hence our TRACED_TASK ref cannot have been released. */
+ mach_port_deallocate (mach_task_self (), task_wrapper);
+
+ return pid;
+}
+
+
+static void
+scan_msgids_dir (char **argz, size_t *argz_len, char *dir, bool append)
+{
+ struct dirent **eps;
+ int n;
+
+ int
+ msgids_file_p (const struct dirent *eps)
+ {
+ if (fnmatch ("*.msgids", eps->d_name, 0) != FNM_NOMATCH)
+ return 1;
+ return 0;
+ }
+
+ n = scandir (dir, &eps, msgids_file_p, NULL);
+ if (n >= 0)
+ {
+ for (int cnt = 0; cnt < n; ++cnt)
+ {
+ char *msgids_file;
+
+ if (asprintf (&msgids_file, "%s/%s", dir, eps[cnt]->d_name) < 0)
+ error (1, errno, "asprintf");
+
+ if (append == TRUE)
+ {
+ if (argz_add (argz, argz_len, msgids_file) != 0)
+ error (1, errno, "argz_add");
+ }
+ else
+ {
+ if (argz_insert (argz, argz_len, *argz, msgids_file) != 0)
+ error (1, errno, "argz_insert");
+ }
+ free (msgids_file);
+ }
+ }
+
+ /* If the directory couldn't be scanned for whatever reason, just ignore
+ it. */
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+ char *msgids_files_argz = NULL;
+ size_t msgids_files_argz_len = 0;
+ bool nostdinc = FALSE;
+ const char *outfile = 0;
+ char **cmd_argv = 0;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'o':
+ outfile = arg;
+ break;
+
+ case OPT_NOSTDINC:
+ nostdinc = TRUE;
+ break;
+
+ case 'i':
+ if (argz_add (&msgids_files_argz, &msgids_files_argz_len,
+ arg) != 0)
+ error (1, errno, "argz_add");
+ break;
+
+ case 'I':
+ scan_msgids_dir (&msgids_files_argz, &msgids_files_argz_len,
+ arg, TRUE);
+ break;
+
+ case 's':
+ strsize = atoi (arg);
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+
+ case ARGP_KEY_ARG:
+ cmd_argv = &state->argv[state->next - 1];
+ state->next = state->argc;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ const struct argp argp = { options, parse_opt, args_doc, doc };
+
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+ /* Insert the files from STD_MSGIDS_DIR at the beginning of the list, so that
+ their content can be overridden by subsequently parsed files. */
+ if (nostdinc == FALSE)
+ scan_msgids_dir (&msgids_files_argz, &msgids_files_argz_len,
+ STD_MSGIDS_DIR, FALSE);
+
+ if (msgids_files_argz != NULL)
+ {
+ char *msgids_file = NULL;
+
+ while ((msgids_file = argz_next (msgids_files_argz,
+ msgids_files_argz_len, msgids_file)))
+ parse_msgid_list (msgids_file);
+
+ free (msgids_files_argz);
+ }
+
+ if (outfile)
+ {
+ ostream = fopen (outfile, "w");
+ if (!ostream)
+ error (1, errno, "%s", outfile);
+ }
+ else
+ ostream = stderr;
+ setlinebuf (ostream);
+
+ traced_bucket = ports_create_bucket ();
+ traced_class = ports_create_class (0, &traced_dropweak);
+
+ hurd_ihash_set_cleanup (&msgid_ihash, msgid_ihash_cleanup, 0);
+
+ /* Spawn a single thread that will receive intercepted messages, print
+ them, and interpose on the ports they carry. The access to the
+ `traced_info' and ihash data structures is all single-threaded,
+ happening only in this new thread. */
+ cthread_detach (cthread_fork (trace_thread_function, traced_bucket));
+
+ /* Run the program on the command line and wait for it to die.
+ The other thread does all the tracing and interposing. */
+ {
+ pid_t child, pid;
+ int status;
+ child = traced_spawn (cmd_argv, envp);
+ pid = waitpid (child, &status, 0);
+ sleep (1); /* XXX gives other thread time to print */
+ if (pid != child)
+ error (1, errno, "waitpid");
+ if (WIFEXITED (status))
+ fprintf (ostream, "Child %d exited with %d\n",
+ pid, WEXITSTATUS (status));
+ else
+ fprintf (ostream, "Child %d %s\n", pid, strsignal (WTERMSIG (status)));
+ }
+
+ return 0;
+}
diff --git a/utils/setauth.c b/utils/setauth.c
new file mode 100644
index 00000000..73f221a0
--- /dev/null
+++ b/utils/setauth.c
@@ -0,0 +1,134 @@
+/* Change the authentication of selected processes
+
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (setauth);
+
+#define OPT_NO_SAVE 1
+
+static const struct argp_option options[] =
+{
+#ifdef SU
+ {"no-save", OPT_NO_SAVE, 0, 0, "Don't save removed effective ids as available ids"},
+#else
+ {"save", 's', 0, 0, "Save removed effective ids as available ids"},
+#endif
+ {"keep", 'k', 0, 0, "Keep old ids in addition to the new ones"},
+ { 0 }
+};
+
+static struct argp_child child_argps[] = {{ &frobauth_posix_argp }, { 0 }};
+
+static char doc[] =
+ "Change the authentication of selected processes";
+
+extern error_t
+get_nonsugid_ids (struct idvec *uids, struct idvec *gids);
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ auth_t auth; /* Authority to make changes. */
+ int save = 0, keep = 0;
+ struct idvec have_uids = IDVEC_INIT, have_gids = IDVEC_INIT;
+ struct frobauth frobauth = FROBAUTH_INIT;
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 's': save = 1; break;
+ case 'k': keep = 1; break;
+ case OPT_NO_SAVE: save = 0; break;
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input; break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ /* Modify UGIDS, to be what PID's new authentication should be, UGIDS is
+ what the user specified. */
+ error_t modify (struct ugids *ugids, const struct ugids *new,
+ pid_t pid, void *hook)
+ {
+ struct ugids old = UGIDS_INIT;
+ ugids_set (&old, ugids);
+
+ ugids_set (ugids, new);
+
+ if (keep)
+ ugids_merge (ugids, &old);
+ if (save)
+ {
+ ugids_save (&old);
+ ugids_merge (ugids, &old);
+ }
+
+ return 0;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *user,
+ pid_t pid, void *hook)
+ {
+ char *new_rep = ugids_rep (new, 1, 1, 0, 0, 0);
+ printf ("%d: Changed auth to %s\n", pid, new_rep);
+ free (new_rep);
+ }
+ struct argp argp = { options, parse_opt, 0, doc, child_argps };
+
+#ifdef SU
+ frobauth.default_user = 0;
+ save = 1; /* Default to saving ids */
+#endif
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ /* See what the invoking user is authorized to do. */
+ err = get_nonsugid_ids (&have_uids, &have_gids);
+ if (err)
+ error (52, err, "Cannot get invoking authentication");
+
+ /* Check passwords. */
+ err = ugids_verify_make_auth (&frobauth.ugids, &have_uids, &have_gids, 0, 0,
+ 0, 0, &auth);
+ if (err == EACCES)
+ error (15, 0, "Invalid password");
+ else if (err)
+ error (16, err, "Authentication failure");
+
+ if (frobauth_modify (&frobauth, &auth, 1, modify, print_info, 0))
+ return 0;
+ else
+ return 1;
+}
diff --git a/utils/settrans.c b/utils/settrans.c
index ff264a5b..a8814016 100644
--- a/utils/settrans.c
+++ b/utils/settrans.c
@@ -1,8 +1,7 @@
/* Set a file's translator.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,14 +22,21 @@
#include <stdlib.h>
#include <string.h>
#include <argp.h>
+#include <error.h>
#include <fcntl.h>
#include <unistd.h>
#include <error.h>
#include <argz.h>
#include <hurd/fshelp.h>
+#include <hurd/process.h>
+#include <version.h>
+
+#include <hurd/lookup.h>
+#include <hurd/fsys.h>
+
-char *argp_program_version = "settrans 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (settrans);
#define DEFAULT_TIMEOUT 60
@@ -39,33 +45,41 @@ char *argp_program_version = "settrans 1.0 (GNU " HURD_RELEASE ")";
static struct argp_option options[] =
{
- {"active", 'a', 0, 0, "Set NODE's active translator", 1},
- {"passive", 'p', 0, 0, "Set NODE's passive translator"},
- {"create", 'c', 0, 0, "Create NODE if it doesn't exist"},
+ {"active", 'a', 0, 0, "Start TRANSLATOR and set it as NODE's active translator" },
+ {"passive", 'p', 0, 0, "Change NODE's passive translator record (default)" },
+ {"create", 'c', 0, 0, "Create NODE if it doesn't exist" },
{"dereference", 'L', 0, 0, "If a translator exists, put the new one on top"},
{"pause", 'P', 0, 0, "When starting an active translator, prompt and"
" wait for a newline on stdin before completing the startup handshake"},
{"timeout", 't',"SEC",0, "Timeout for translator startup, in seconds"
" (default " STRINGIFY (DEFAULT_TIMEOUT) "); 0 means no timeout"},
- {"exclusive", 'x', 0, 0, "Only set the translator if there is none already"},
+ {"exclusive", 'x', 0, 0, "Only set the translator if there is not one already"},
+ {"orphan", 'o', 0, 0, "Disconnect old translator from the filesystem "
+ "(do not ask it to go away)"},
+
+ {"chroot", 'C', 0, 0,
+ "Instead of setting the node's translator, take following arguments up to"
+ " `--' and run that command chroot'd to the translated node."},
{0,0,0,0, "When setting the passive translator, if there's an active translator:"},
- {"goaway", 'g', 0, 0, "Make the active translator go away"},
- {"keep-active", 'k', 0, 0, "Leave the existing active translator running"},
+ {"goaway", 'g', 0, 0, "Ask the active translator to go away"},
+ {"keep-active", 'k', 0, 0, "Leave any existing active translator running"},
- {0,0,0,0, "When an active translator is told to go away:", 2},
+ {0,0,0,0, "When an active translator is told to go away:"},
{"recursive", 'R', 0, 0, "Shutdown its children too"},
- {"force", 'f', 0, 0, "If it doesn't want to die, force it"},
+ {"force", 'f', 0, 0, "Ask it to ignore current users and shutdown "
+ "anyway." },
{"nosync", 'S', 0, 0, "Don't sync it before killing it"},
{0, 0}
};
static char *args_doc = "NODE [TRANSLATOR ARG...]";
-static char *doc = "By default the passive translator is set.";
+static char *doc = "Set the passive/active translator on NODE."
+"\vBy default the passive translator is set.";
/* ---------------------------------------------------------------- */
-void
+int
main(int argc, char *argv[])
{
error_t err;
@@ -76,7 +90,7 @@ main(int argc, char *argv[])
/* The translator's arg vector, in '\0' separated format. */
char *argz = 0;
- int argz_len = 0;
+ size_t argz_len = 0;
/* The control port for any active translator we start up. */
fsys_t active_control = MACH_PORT_NULL;
@@ -88,9 +102,11 @@ main(int argc, char *argv[])
int goaway_flags = 0;
/* Various option flags. */
- int passive = 0, active = 0, keep_active = 0, pause = 0, kill_active = 0;
+ int passive = 0, active = 0, keep_active = 0, pause = 0, kill_active = 0,
+ orphan = 0;
int excl = 0;
int timeout = DEFAULT_TIMEOUT * 1000; /* ms */
+ char **chroot_command = 0;
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
@@ -120,6 +136,32 @@ main(int argc, char *argv[])
case 'g': kill_active = 1; break;
case 'x': excl = 1; break;
case 'P': pause = 1; break;
+ case 'o': orphan = 1; break;
+
+ case 'C':
+ if (chroot_command)
+ {
+ argp_error (state, "--chroot given twice");
+ return EINVAL;
+ }
+ chroot_command = &state->argv[state->next];
+ while (state->next < state->argc)
+ {
+ if (!strcmp (state->argv[state->next], "--"))
+ {
+ state->argv[state->next++] = 0;
+ if (chroot_command[0] == 0)
+ {
+ argp_error (state,
+ "--chroot must be followed by a command");
+ return EINVAL;
+ }
+ return 0;
+ }
+ ++state->next;
+ }
+ argp_error (state, "--chroot command must be terminated with `--'");
+ return EINVAL;
case 'c': lookup_flags |= O_CREAT; break;
case 'L': lookup_flags &= ~O_NOTRANS; break;
@@ -140,49 +182,63 @@ main(int argc, char *argv[])
argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
- if (!active && !passive)
+ if (!active && !passive && !chroot_command)
passive = 1; /* By default, set the passive translator. */
if (passive)
passive_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0);
if (active)
- active_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0);
+ active_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0)
+ | (orphan ? FS_TRANS_ORPHAN : 0);
if (passive && !active)
- /* When setting just the passive, decide what to do with any active. */
- if (kill_active)
- /* Make it go away. */
- active_flags = FS_TRANS_SET;
- else if (! keep_active)
- /* Ensure that there isn't one. */
- active_flags = FS_TRANS_SET | FS_TRANS_EXCL;
-
- if (active && argz_len > 0)
{
+ /* When setting just the passive, decide what to do with any active. */
+ if (kill_active)
+ /* Make it go away. */
+ active_flags = FS_TRANS_SET;
+ else if (! keep_active)
+ /* Ensure that there isn't one. */
+ active_flags = FS_TRANS_SET | FS_TRANS_EXCL;
+ }
+
+ if ((active || chroot_command) && argz_len > 0)
+ {
+ /* Error during file lookup; we use this to avoid duplicating error
+ messages. */
+ error_t open_err = 0;
+
/* The callback to start_translator opens NODE as a side effect. */
error_t open_node (int flags,
mach_port_t *underlying,
- mach_msg_type_name_t *underlying_type)
+ mach_msg_type_name_t *underlying_type,
+ task_t task, void *cookie)
{
if (pause)
{
- fprintf (stderr, "Pausing...");
+ fprintf (stderr, "Translator pid: %d\nPausing...",
+ task2pid (task));
getchar ();
}
node = file_name_lookup (node_name, flags | lookup_flags, 0666);
if (node == MACH_PORT_NULL)
- return errno;
+ {
+ open_err = errno;
+ return open_err;
+ }
*underlying = node;
*underlying_type = MACH_MSG_TYPE_COPY_SEND;
return 0;
}
- err = fshelp_start_translator (open_node, argz, argz, argz_len, timeout,
- &active_control);
+ err = fshelp_start_translator (open_node, NULL, argz, argz, argz_len,
+ timeout, &active_control);
if (err)
- error(4, err, "%s", argz);
+ /* If ERR is due to a problem opening the translated node, we print
+ that name, otherwise, the name of the translator. */
+ error(4, err, "%s", (err == open_err) ? node_name : argz);
}
else
{
@@ -191,13 +247,46 @@ main(int argc, char *argv[])
error(1, errno, "%s", node_name);
}
- err =
- file_set_translator(node,
- passive_flags, active_flags, goaway_flags,
- argz, argz_len,
- active_control, MACH_MSG_TYPE_COPY_SEND);
- if (err)
- error(5, err, "%s", node_name);
+ if (active || passive)
+ {
+ err = file_set_translator (node,
+ passive_flags, active_flags, goaway_flags,
+ argz, argz_len,
+ active_control, MACH_MSG_TYPE_COPY_SEND);
+ if (err)
+ error (5, err, "%s", node_name);
+ }
+
+ if (chroot_command)
+ {
+ /* We will act as the parent filesystem would for a lookup
+ of the active translator's root node, then use this port
+ as our root directory while we exec the command. */
+
+ char retry_name[1024]; /* XXX */
+ retry_type do_retry;
+ mach_port_t root;
+ err = fsys_getroot (active_control,
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND,
+ NULL, 0, NULL, 0, 0, &do_retry, retry_name, &root);
+ mach_port_deallocate (mach_task_self (), active_control);
+ if (err)
+ error (6, err, "fsys_getroot");
+ err = hurd_file_name_lookup_retry (&_hurd_ports_use, &getdport, 0,
+ do_retry, retry_name, 0, 0,
+ &root);
+ if (err)
+ error (6, err, "cannot resolve root port");
+
+ if (setcrdir (root))
+ error (7, errno, "cannot install root port");
+ mach_port_deallocate (mach_task_self (), root);
+ if (chdir ("/"))
+ error (8, errno, "cannot chdir to new root");
+
+ execvp (chroot_command[0], chroot_command);
+ error (8, errno, "cannot execute %s", chroot_command[0]);
+ }
- exit(0);
+ return 0;
}
diff --git a/utils/shd.c b/utils/shd.c
index cb4b0ad0..a1a4b26b 100644
--- a/utils/shd.c
+++ b/utils/shd.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1994, 1995 Free Software Foundation
+/*
+ Copyright (C) 1994,95,99,2002 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,6 +23,7 @@
#include <device/device.h>
#include <unistd.h>
#include <errno.h>
+#include <error.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -44,7 +45,7 @@ reap (pid_t waitfor)
if (pid == -1)
{
if (errno != ECHILD && errno != EWOULDBLOCK)
- perror ("waitpid");
+ error (0, errno, "waitpid");
return;
}
else if (WIFEXITED (status))
@@ -54,7 +55,7 @@ reap (pid_t waitfor)
printf ("PID %d %s\n",
pid, strsignal (WTERMSIG (status)));
else if (WIFSTOPPED (status))
- printf ("PID %d stopped: %s\n",
+ printf ("PID %d stopped: %s\n",
pid, strsignal (WSTOPSIG (status)));
else
printf ("PID %d bizarre status %#x\n", pid, status);
@@ -69,6 +70,7 @@ run (char **argv, int fd0, int fd1)
{
file_t file;
char *program;
+ error_t err;
if (strchr (argv[0], '/') != NULL)
program = argv[0];
@@ -84,18 +86,22 @@ run (char **argv, int fd0, int fd1)
file = file_name_lookup (program, O_EXEC, 0);
if (file == MACH_PORT_NULL)
{
- perror (program);
+ error (0, errno, "%s", program);
return -1;
}
else
{
task_t task;
pid_t pid;
-
- errno = task_create (mach_task_self (), 0, &task);
- if (errno)
+
+ err = task_create (mach_task_self (),
+#ifdef KERN_INVALID_LEDGER
+ NULL, 0, /* OSF Mach */
+#endif
+ 0, &task);
+ if (err)
{
- perror ("task_create");
+ error (0, err, "task_create");
pid = -1;
}
else
@@ -109,12 +115,12 @@ run (char **argv, int fd0, int fd1)
*save = dup (to);
if (*save < 0)
{
- perror ("dup");
+ error (0, errno, "dup");
return -1;
}
if (dup2 (from, to) != to)
{
- perror ("dup2");
+ error (0, errno, "dup2");
return -1;
}
close (from);
@@ -126,7 +132,7 @@ run (char **argv, int fd0, int fd1)
return 0;
if (dup2 (*save, to) != to)
{
- perror ("dup2");
+ error (0, errno, "dup2");
return -1;
}
close (*save);
@@ -135,13 +141,16 @@ run (char **argv, int fd0, int fd1)
pid = task2pid (task);
if (pid == -1)
- perror ("task2pid"), pid = 0;
- errno = proc_child (proc, task);
- if (errno)
- perror ("proc_child");
+ {
+ error (0, errno, "task2pid");
+ pid = 0;
+ }
+ err = proc_child (proc, task);
+ if (err)
+ error (0, err, "proc_child");
if (pause_startup)
{
- printf ("Pausing...");
+ printf ("Pausing (child PID %d)...", pid);
fflush (stdout);
getchar ();
}
@@ -149,25 +158,26 @@ run (char **argv, int fd0, int fd1)
if (movefd (fd0, 0, &save0) ||
movefd (fd1, 1, &save1))
return -1;
-
- errno = _hurd_exec (task, file, argv, environ);
+
+ err = _hurd_exec (task, file, argv, environ);
if (restorefd (fd0, 0, &save0) ||
restorefd (fd1, 1, &save1))
return -1;
- if (errno)
+ if (err)
{
- perror ("_hurd_exec");
- errno = task_terminate (task);
- if (errno)
- perror ("task_terminate");
+ error (0, err, "_hurd_exec");
+ err = task_terminate (task);
+ if (err)
+ error (0, err, "task_terminate");
}
mach_port_deallocate (mach_task_self (), task);
}
mach_port_deallocate (mach_task_self (), file);
+ errno = err;
return pid;
}
}
@@ -183,7 +193,7 @@ command (int argc, char **argv)
bg = !strcmp (argv[argc - 1], "&");
if (bg)
argv[--argc] = NULL;
-
+
start = 0;
for (i = 1; i < argc; ++i)
if (! strcmp (argv[i], "|"))
@@ -192,7 +202,7 @@ command (int argc, char **argv)
argv[i] = NULL;
if (pipe (fds))
{
- perror ("pipe");
+ error (0, errno, "pipe");
return;
}
pid = run (argv + start, fd0, fds[1]);
@@ -213,7 +223,7 @@ command (int argc, char **argv)
int
-main ()
+main (int argc, char *argv[])
{
char *linebuf = NULL;
size_t linebufsize = 0;
@@ -228,15 +238,15 @@ main ()
mach_port_t hostp, masterd;
err = proc_getprivports (proc, &hostp, &masterd);
assert (!err);
-
+
err = device_open (masterd, D_WRITE|D_READ, "console", &outp);
assert (!err);
-
+
stdin = mach_open_devstream (outp, "r");
stdout = stderr = mach_open_devstream (outp, "w+");
}
#endif
-
+
/* Kludge to give boot a port to the auth server. */
exec_init (getdport (0), getauth (),
MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
@@ -266,7 +276,7 @@ main ()
{
if (feof (stdin))
return 0;
- perror ("getline");
+ error (0, errno, "getline");
continue;
}
@@ -321,7 +331,7 @@ main ()
if (argc != 2)
fprintf (stderr, "Usage: cd DIRECTORY\n");
else if (chdir (argv[1]))
- perror ("chdir");
+ error (0, errno, "chdir");
}
else if (!strcmp (argv[0], "exec"))
{
@@ -343,7 +353,7 @@ main ()
if (execv (program, &argv[1]) == 0)
fprintf (stderr, "execv (%s) returned 0!\n", program);
else
- perror ("execv");
+ error (0, errno, "execv");
}
}
else if (!strcmp (argv[0], "setenv"))
@@ -351,7 +361,7 @@ main ()
if (argc != 3)
fprintf (stderr, "Usage: setenv VAR VALUE\n");
else if (setenv (argv[1], argv[2], 1))
- perror ("setenv");
+ error (0, errno, "setenv");
}
else if (!strcmp (argv[0], "fork"))
{
@@ -359,7 +369,7 @@ main ()
switch (pid)
{
case -1:
- perror ("fork");
+ error (0, errno, "fork");
break;
case 0:
printf ("I am the child, PID %d.\n", (int) getpid ());
@@ -377,5 +387,3 @@ main ()
fflush (stderr);
}
}
-
-
diff --git a/utils/showtrans.c b/utils/showtrans.c
index d6acfd9d..aa55f14d 100644
--- a/utils/showtrans.c
+++ b/utils/showtrans.c
@@ -1,8 +1,7 @@
/* Show files' passive translators.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1995,96,97,98,99,2001,02 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,11 +24,13 @@
#include <argp.h>
#include <fcntl.h>
#include <unistd.h>
+#include <version.h>
+#include <sys/mman.h>
#include <error.h>
#include <argz.h>
-char *argp_program_version = "showtrans 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (showtrans);
static struct argp_option options[] =
{
@@ -42,13 +43,13 @@ static struct argp_option options[] =
};
static char *args_doc = "FILE...";
-
-static char *doc = "A FILE argument of `-' prints the translator on the node \
-attached to standard input.";
+static char *doc = "Show the passive translator of FILE..."
+"\vA FILE argument of `-' prints the translator on the node"
+" attached to standard input.";
/* ---------------------------------------------------------------- */
-void
+int
main (int argc, char *argv[])
{
/* The default exit status -- changed to 0 if we find any translators. */
@@ -66,7 +67,7 @@ main (int argc, char *argv[])
else
{
char buf[1024], *trans = buf;
- int trans_len = sizeof (buf);
+ size_t trans_len = sizeof (buf);
error_t err = file_get_translator (node, &trans, &trans_len);
switch (err)
@@ -76,14 +77,15 @@ main (int argc, char *argv[])
argz_stringify (trans, trans_len, ' ');
if (!silent)
- if (print_prefix)
- printf ("%s: %s\n", name, trans);
- else
- puts (trans);
+ {
+ if (print_prefix)
+ printf ("%s: %.*s\n", name, (int) trans_len, trans);
+ else
+ printf ("%.*s\n", (int) trans_len, trans);
+ }
if (trans != buf)
- vm_deallocate (mach_task_self (),
- (vm_address_t)trans, trans_len);
+ munmap (trans, trans_len);
status = 0;
@@ -138,5 +140,5 @@ main (int argc, char *argv[])
argp_parse (&argp, argc, argv, 0, 0, 0);
- exit (status);
+ return status;
}
diff --git a/utils/storecat.c b/utils/storecat.c
new file mode 100644
index 00000000..7f9de491
--- /dev/null
+++ b/utils/storecat.c
@@ -0,0 +1,73 @@
+/* Write a store to stdout
+
+ Copyright (C) 1996, 1997, 2001, 2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <error.h>
+
+#include <hurd/store.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (storecat);
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ struct store *s;
+ char *name;
+ store_offset_t addr;
+ store_offset_t left;
+ const struct argp_child kids[] = { { &store_argp }, { 0 }};
+ struct argp argp =
+ { 0, 0, 0, "Write the contents of a store to stdout", kids };
+ struct store_argp_params p = { 0 };
+
+ argp_parse (&argp, argc, argv, 0, 0, &p);
+ err = store_parsed_name (p.result, &name);
+ if (err)
+ error (2, err, "store_parsed_name");
+
+ err = store_parsed_open (p.result, STORE_READONLY, &s);
+ if (err)
+ error (4, err, "%s", name);
+
+ addr = 0;
+ left = s->size;
+ while (left > 0)
+ {
+ size_t read = left > 1024*1024 ? 1024*1024 : left;
+ char buf[4096];
+ void *data = buf;
+ size_t data_len = sizeof (buf);
+
+ err = store_read (s, addr, read, &data, &data_len);
+ if (err)
+ error (5, err, "%s", name);
+ if (write (1, data, data_len) < 0)
+ error (6, errno, "stdout");
+
+ addr += data_len >> s->log2_block_size;
+ left -= data_len;
+ }
+
+ exit (0);
+}
diff --git a/utils/storeinfo.c b/utils/storeinfo.c
index ba6d0654..a738d50d 100644
--- a/utils/storeinfo.c
+++ b/utils/storeinfo.c
@@ -1,8 +1,8 @@
/* Show where a file exists
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2001,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,22 +25,24 @@
#include <argp.h>
#include <unistd.h>
#include <sys/fcntl.h>
+#include <version.h>
#include <error.h>
#include <hurd/fs.h>
#include <hurd/store.h>
-char *argp_program_version = "storeinfo 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (storeinfo);
static struct argp_option options[] =
{
- {"kind", 'k', 0, 0, "Print the type of store behind FILE"},
+ {"type", 't', 0, 0, "Print the type of store behind FILE"},
+ {"flags", 'f', 0, 0, "Print the flags associated with FILE's store"},
{"name", 'n', 0, 0, "Print the name of the store behind FILE"},
{"blocks", 'b', 0, 0, "Print the number of blocks in FILE"},
{"block-size", 'B', 0, 0, "Print the block size of FILE's store"},
{"size", 's', 0, 0, "Print the size, in bytes, of FILE"},
- {"runs", 'r', 0, 0, "Print the runs of blocks in FILE"},
+ {"block-list", 'l', 0, 0, "Print the blocks that are in FILE"},
{"children", 'c', 0, 0, "If the store has children, show them too"},
{"dereference", 'L', 0, 0, "If FILE is a symbolic link, follow it"},
{"prefix", 'p', 0, 0, "Always print `FILE: ' before info"},
@@ -48,26 +50,28 @@ static struct argp_option options[] =
{0, 0}
};
static char *args_doc = "FILE...";
-static char *doc = "With no FILE arguments, the file attached to standard \
-input is used. The fields to be printed are separated by colons, in this \
-order: PREFIX: KIND: NAME: BLOCK-SIZE: BLOCKS: SIZE: RUNS. If the store is a \
-composite one and --children is specified, children are printed on lines \
-following the main store, indented accordingly. By default, all \
-fields, and children, are printed.";
+static char *doc = "Show information about storage used by FILE..."
+"\vWith no FILE arguments, the file attached to standard"
+" input is used. The fields to be printed are separated by colons, in this"
+" order: PREFIX: TYPE (FLAGS): NAME: BLOCK-SIZE: BLOCKS: SIZE: BLOCK-LIST."
+" If the store is a composite one and --children is specified, children"
+" are printed on lines following the main store, indented accordingly."
+" By default, all fields, and children, are printed.";
/* ---------------------------------------------------------------- */
/* Things we can print about a file's storage. */
#define W_SOURCE 0x01
-#define W_KIND 0x02
+#define W_TYPE 0x02
#define W_NAME 0x04
#define W_BLOCKS 0x08
#define W_BLOCK_SIZE 0x10
#define W_SIZE 0x20
#define W_RUNS 0x40
#define W_CHILDREN 0x80
+#define W_FLAGS 0x100
-#define W_ALL 0xFF
+#define W_ALL 0x1FF
/* Print a line of information (exactly what is determinted by WHAT)
about store to stdout. LEVEL is the desired indentation level. */
@@ -87,7 +91,7 @@ print_store (struct store *store, int level, unsigned what)
putchar (' ');
}
}
- void pstr (char *str, unsigned mask)
+ void pstr (const char *str, unsigned mask)
{
if ((what & mask) == mask)
{
@@ -95,12 +99,20 @@ print_store (struct store *store, int level, unsigned what)
fputs (str ?: "-", stdout);
}
}
- void pint (off_t val, unsigned mask)
+ void psiz (size_t val, unsigned mask)
{
if ((what & mask) == mask)
{
psep ();
- printf ("%ld", val);
+ printf ("%zu", val);
+ }
+ }
+ void poff (store_offset_t val, unsigned mask)
+ {
+ if ((what & mask) == mask)
+ {
+ psep ();
+ printf ("%Ld", val);
}
}
@@ -111,9 +123,9 @@ print_store (struct store *store, int level, unsigned what)
putchar (' ');
}
- pstr (store->class->name,W_KIND);
+ pstr (store->class->name,W_TYPE);
- if (store->flags && (what & W_KIND))
+ if ((store->flags & ~STORE_INACTIVE) && (what & W_FLAGS))
{
int t = 0; /* flags tested */
int f = 1;
@@ -140,20 +152,20 @@ print_store (struct store *store, int level, unsigned what)
pf (STORE_ENFORCED, "enf");
pf (STORAGE_MUTATED, "mut");
- if (store->flags & ~t)
+ if (store->flags & ~(t | STORE_INACTIVE))
/* Leftover flags. */
{
if (! f)
putchar (';');
- printf ("0x%x", store->flags);
+ printf ("0x%x", store->flags & ~(t | STORE_INACTIVE));
}
- putchar ('(');
+ putchar (')');
}
pstr (store->name, W_NAME);
- pint (store->block_size, W_BLOCK_SIZE);
- pint (store->blocks, W_BLOCKS);
- pint (store->size, W_SIZE);
+ psiz (store->block_size, W_BLOCK_SIZE);
+ poff (store->blocks, W_BLOCKS);
+ poff (store->size, W_SIZE);
if (what & W_RUNS)
{
@@ -163,9 +175,10 @@ print_store (struct store *store, int level, unsigned what)
if (i > 0)
putchar (',');
if (store->runs[i].start < 0)
- printf ("[%ld]", store->runs[i].length);
+ /* A hole */
+ printf ("@+%Ld", store->runs[i].length);
else
- printf ("%ld[%ld]", store->runs[i].start, store->runs[i].length);
+ printf ("%Ld+%Ld", store->runs[i].start, store->runs[i].length);
}
}
@@ -177,8 +190,8 @@ print_store (struct store *store, int level, unsigned what)
print_store (store->children[i], level + 1, what);
}
-void
-main(int argc, char *argv[])
+int
+main (int argc, char *argv[])
{
int deref = 0, print_prefix = -1;
unsigned what = 0;
@@ -191,7 +204,7 @@ main(int argc, char *argv[])
struct store *store;
if (file == MACH_PORT_NULL)
- error (3, err, source);
+ error (3, err, "%s", source);
if (print_prefix < 0)
/* By default, only print filename prefixes for multiple files. */
@@ -200,9 +213,14 @@ main(int argc, char *argv[])
if (what == 0)
what = W_ALL;
- err = store_create (file, 0, 0, &store);
+ /* The STORE_NO_FILEIO flag tells it to give us the special
+ "unknown" class instead of an error if it cannot parse the
+ file_get_storage_info results. That will allow us to display
+ what we can from them, i.e. the name that shows at least some
+ of what the unknown data looked like. */
+ err = store_create (file, STORE_INACTIVE|STORE_NO_FILEIO, 0, &store);
if (err)
- error (4, err, source);
+ error (4, err, "%s", source);
print_store (store, 0, what);
store_free (store);
@@ -214,12 +232,13 @@ main(int argc, char *argv[])
case 'p': print_prefix = 1; break;
case 'P': print_prefix = 0; break;
- case 'k': what |= W_KIND; break;
+ case 't': what |= W_TYPE; break;
+ case 'f': what |= W_FLAGS; break;
case 'n': what |= W_NAME; break;
case 'b': what |= W_BLOCKS; break;
case 'B': what |= W_BLOCK_SIZE; break;
case 's': what |= W_SIZE; break;
- case 'r': what |= W_RUNS; break;
+ case 'l': what |= W_RUNS; break;
case 'c': what |= W_CHILDREN; break;
case ARGP_KEY_NO_ARGS:
@@ -245,5 +264,5 @@ main(int argc, char *argv[])
argp_parse (&argp, argc, argv, 0, 0, 0);
- exit(0);
+ return 0;
}
diff --git a/libstore/storeread.c b/utils/storeread.c
index ea012727..df381bec 100644
--- a/libstore/storeread.c
+++ b/utils/storeread.c
@@ -1,32 +1,59 @@
-/* Test program for libstore -- outputs a portion of a store */
+/* Write portions of a store to stdout
+
+ Copyright (C) 1996,97,99,2001,02,03,04 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <argp.h>
#include <error.h>
#include <unistd.h>
#include <hurd.h>
#include <sys/fcntl.h>
+#include <sys/mman.h>
-#include "store.h"
+#include <hurd/store.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (storeread);
struct argp_option options[] = {
{"file", 'f', 0, 0, "Use file IO instead of the raw device"},
{"block-size", 'b', "BYTES", 0, "Set the file block size"},
{0, 0}
};
-char *arg_doc = "FILE [ADDR [LENGTH]]...";
-char *doc = "ADDR is in blocks, and defaults to 0; LENGTH is in bytes, and defaults to the remainder of FILE.";
+const char arg_doc[] = "FILE [ADDR [LENGTH]]...";
+const char doc[] = "Write portions of the contents of a store to stdout"
+"\vADDR is in blocks, and defaults to 0;"
+" LENGTH is in bytes, and defaults to the remainder of FILE.";
int
main (int argc, char **argv)
{
struct store *store = 0;
- off_t addr = -1;
+ store_offset_t addr = -1;
int dumped = 0, use_file_io = 0, block_size = 0;
- void dump (off_t addr, ssize_t len)
+ void dump (store_offset_t addr, ssize_t len)
{
- char buf[4096], *data = buf;
+ char buf[4096];
+ void *data = buf;
size_t data_len = sizeof (buf);
+
+ /* XXX: store->size can be too big for len. */
error_t err =
store_read (store, addr, len < 0 ? store->size : len,
&data, &data_len);
@@ -35,7 +62,7 @@ main (int argc, char **argv)
if (write (1, data, data_len) < 0)
error (6, errno, "stdout");
if (data != buf)
- vm_deallocate (mach_task_self (), (vm_address_t)data, data_len);
+ munmap (data, data_len);
}
error_t parse_opt (int key, char *arg, struct argp_state *state)
@@ -60,19 +87,19 @@ main (int argc, char **argv)
if (! err)
{
struct store_run run = {0, stat.st_size / block_size};
- err = _store_file_create (source, block_size, &run, 1,
+ err = _store_file_create (source, 0, block_size, &run, 1,
&store);
}
}
else
- err = store_file_create (source, &store);
+ err = store_file_create (source, 0, &store);
else
- err = store_create (source, &store);
+ err = store_create (source, 0, 0, &store);
if (err)
- error (err, 3, "%s", arg);
+ error (3, err, "%s", arg);
}
else if (addr < 0)
- addr = atoi (arg);
+ addr = atoll (arg);
else
{
dump (addr, atoi (arg));
@@ -82,6 +109,9 @@ main (int argc, char **argv)
break;
case ARGP_KEY_END:
+ if (!store)
+ argp_usage (state);
+
if (addr >= 0)
dump (addr, -1);
else if (! dumped)
diff --git a/utils/su.c b/utils/su.c
deleted file mode 100644
index de12917e..00000000
--- a/utils/su.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/* `su' for GNU Hurd.
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
- Written by Roland McGrath.
-
-This file is part of the GNU Hurd.
-
-The GNU Hurd is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-The GNU Hurd is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with the GNU Hurd; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Unlike Unix su, this program does not spawn a subshell. Instead, it
- adds or removes (with the -r flag) auth rights to all the processes in
- the current login. Note that the addition and removal of rights to a
- particular process is voluntary; the process doesn't get them unless
- it's listening for the right rpc (which the C library normally does),
- and it doesn't have to release any of the rights it has when requested
- (though the C library does this automatically in most programs).
-
- The -r flag allows you to easily be authorized or not authorized for any
- number of users (uids and gid sets). This program is not intelligent,
- however. The -r flag always removes whatever gids the specified user
- has. If some other user you have obtained authorization for has some of
- the same gids, it will remove them. The C library could be intelligent
- enough to look up the groups of all the uids it has, and make sure it
- has at least those. */
-
-#include <stdlib.h>
-#include <hurd.h>
-#include <pwd.h>
-#include <grp.h>
-#include <termios.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <hurd/msg.h>
-#include <assert.h>
-
-process_t proc; /* Our proc server port. */
-
-/* Command line flags. */
-int remove_ids = 0; /* -r: Remove ids instead of adding them. */
-
-const struct option longopts[] =
- {
- { "remove", 0, 0, 'r' },
- { "uid", 0, 0, 'u' },
- { "gid", 0, 0, 'g' },
- { "loginuser", 0, 0, 'l' },
- { "pid", 0, 0, 'p' },
- { "pgrp", 0, 0, 'G' },
- { "loginid", 0, 0, 'i' },
- { 0, }
- };
-
-struct auth
- {
- unsigned int *ids;
- auth_t authport;
- };
-
-/* These functions return a malloc'd array of ids that can be passed to
- make_auth_handle or used in del_auth messages. They check authorization
- and return NULL on failure. */
-unsigned int *get_uid (const char *user); /* From a named user or UID. */
-unsigned int *get_gid (const char *user); /* From a named group or GID. */
-unsigned int *get_user (const char *user); /* All ids for a named user. */
-
-int apply_auth (struct auth *auth, pid_t, int);
-int apply_auth_to_pids (struct auth *auth, unsigned int, pid_t *, int);
-int apply_auth_to_pgrp (struct auth *auth, pid_t);
-int apply_auth_to_loginid (struct auth *auth, int);
-
-int check_password (const char *name, const char *password);
-
-
-int
-main (int argc, char **argv)
-{
- int c;
- int status;
- enum { user, group, loginuser, loginid, pid, pgrp } mode = loginuser;
- struct auth auth[argc];
- unsigned int authidx = 0, loginidx = 0, pididx = 0, pgrpidx = 0;
- int loginids[argc];
- pid_t pids[argc], pgrps[argc];
- unsigned int i, j;
-
- proc = getproc (); /* Used often. */
-
- while ((c = getopt_long (argc, argv, "--rgulpiG", longopts, NULL)) != EOF)
- switch (c)
- {
- case 'r':
- remove_ids = 1;
- break;
-
- case 'u':
- mode = user;
- break;
- case 'g':
- mode = group;
- break;
- case 'l':
- mode = loginuser;
- break;
- case 'p':
- mode = pid;
- break;
- case 'i':
- mode = loginid;
- break;
- case 'G':
- mode = pgrp;
- break;
-
- case 1: /* Non-option argument. */
- switch (mode)
- {
- case user:
- auth[authidx++].ids = get_uid (optarg);
- break;
- case group:
- auth[authidx++].ids = get_gid (optarg);
- break;
- case loginuser:
- auth[authidx++].ids = get_user (optarg);
- break;
-
- case pid:
- pids[pididx++] = atoi (optarg);
- break;
- case loginid:
- loginids[loginidx++] = atoi (optarg);
- break;
- case pgrp:
- pgrps[pgrpidx++] = atoi (optarg);
- break;
- }
- break;
-
- case '?':
- default:
- fprintf (stderr, "Usage: %s [-r|--remove]\n\
- [-u|--uid UID...] [-g|--gid GID...] [-l|--loginuser USER...]\n\
- [-p|--pid PID...] [-i|--loginid ID...] [-G|--pgrp PGRP...]\n",
- program_invocation_short_name);
- exit (1);
- }
-
- if (authidx == 0)
- /* No ids specified; default is "su root". */
- auth[authidx++].ids = get_user ("root");
-
- if (pididx == 0 && loginidx == 0 && pgrpidx == 0)
- {
- /* No processes specified; default is current login collection. */
- errno = proc_getloginid (proc, getpid (), &loginids[loginidx++]);
- if (errno)
- {
- perror ("proc_getloginid");
- return 1;
- }
- }
-
- status = 0;
-
- if (! remove_ids)
- for (i = 0; i < authidx; ++i)
- {
- struct auth *a = &auth[i];
- errno = auth_makeauth (getauth (), NULL, MACH_MSG_TYPE_COPY_SEND, 0,
- &a->ids[1], a->ids[0], NULL, 0,
- &a->ids[1 + a->ids[0] + 1],
- a->ids[1 + a->ids[0]], NULL, 0, &a->authport);
- if (errno)
- {
- perror ("auth_makeauth");
- status = 1;
- }
- }
-
- for (j = 0; j < authidx; ++j)
- status |= apply_auth_to_pids (&auth[j], pididx, pids, 0);
-
- for (i = 0; i < loginidx; ++i)
- {
- for (j = 0; j < authidx; ++j)
- status |= apply_auth_to_loginid (&auth[j], loginids[i]);
- }
-
- for (i = 0; i < pgrpidx; ++i)
- {
- for (j = 0; j < authidx; ++j)
- status |= apply_auth_to_loginid (&auth[j], pgrps[i]);
- }
-
-
- return status;
-}
-
-/* Turn USER into a list of ids, giving USER's primary uid and gid from the
- passwd file and all the groups that USER appears in in the group file. */
-
-unsigned int *
-get_user (const char *user)
-{
- struct passwd *p;
- unsigned int ngids, *ids;
-
- p = getpwnam (user);
- if (p == NULL)
- {
- fprintf (stderr, "%s: User `%s' not found\n",
- program_invocation_short_name, user);
- return NULL;
- }
-
- if (! check_password (user, p->pw_passwd))
- return NULL;
-
- /* We don't need to change our own gids, but it doesn't really hurt,
- and initgroups does all the work for us. */
- if (initgroups (user, p->pw_gid) < 0)
- {
- perror ("initgroups");
- return NULL;
- }
- ngids = getgroups (0, NULL);
- if ((int) ngids < 0)
- {
- getgroups_lost:
- perror ("getgroups");
- return NULL;
- }
- assert (sizeof (*ids) == sizeof (gid_t));
- ids = malloc ((3 + ngids) * sizeof (*ids));
- ids[0] = 1;
- ids[1] = p->pw_uid;
- ids[2] = getgroups (ngids, &ids[3]);
- if ((int) ids[2] < 0)
- goto getgroups_lost;
-
- return ids;
-}
-
-/* Return an id list containing just the uid of USER. */
-
-unsigned int *
-get_uid (const char *user)
-{
- struct passwd *p;
- unsigned int *ids;
- uid_t uid;
- char *uend;
-
- uid = strtoul (user, &uend, 10);
- if (uend && *uend == '\0')
- {
- if (remove_ids || getuid () == 0)
- /* No need to verify. */
- p = NULL;
- else
- {
- p = getpwuid (uid);
- if (p == NULL)
- {
- fprintf (stderr, "%s: UID %u not found\n",
- program_invocation_short_name, uid);
- return NULL;
- }
- }
- }
- else
- {
- p = getpwnam (user);
- if (p == NULL)
- {
- fprintf (stderr, "%s: User `%s' not found\n",
- program_invocation_short_name, user);
- return NULL;
- }
- }
-
- if (p != NULL && ! check_password (user, p->pw_passwd))
- return NULL;
-
- ids = malloc (3 * sizeof (*ids));
- ids[0] = 1;
- ids[1] = p->pw_uid;
- ids[2] = 0;
-
- return ids;
-}
-
-/* Return an id list containing just the gid of GROUP. */
-
-unsigned int *
-get_gid (const char *group)
-{
- struct group *g;
- unsigned int *ids;
- gid_t gid;
- char *gend;
-
- gid = strtoul (group, &gend, 10);
- if (gend && *gend == '\0')
- {
- if (remove_ids || getuid () == 0)
- /* No need to verify. */
- g = NULL;
- else
- {
- g = getgrgid (gid);
- if (g == NULL)
- {
- fprintf (stderr, "%s: GID %u not found\n",
- program_invocation_short_name, gid);
- return NULL;
- }
- }
- }
- else
- {
- g = getgrnam (group);
- if (g == NULL)
- {
- fprintf (stderr, "%s: Group `%s' not found\n",
- program_invocation_short_name, group);
- return NULL;
- }
- }
-
- if (g != NULL && ! check_password (group, g->gr_passwd))
- return NULL;
-
- ids = malloc (3 * sizeof (*ids));
- ids[0] = 0;
- ids[1] = 1;
- ids[2] = g->gr_gid;
-
- return ids;
-}
-
-/* Add or delete (under -r) the ids indicated by AUTH to/from PID. If
- IGNORE_BAD_PID is nonzero, return success if PID does not exist.
- Returns zero if successful, nonzero on error (after printing message). */
-
-int
-apply_auth (struct auth *auth, pid_t pid, int ignore_bad_pid)
-{
- error_t err;
-
- if (! auth->ids)
- return 0;
-
- err = HURD_MSGPORT_RPC (proc_getmsgport (proc, pid, &msgport),
- proc_pid2task (proc, pid, &refport), 1,
- remove_ids ?
- msg_del_auth (msgport, refport,
- &auth->ids[1], auth->ids[0],
- &auth->ids[1 + auth->ids[0] + 1],
- auth->ids[1 + auth->ids[0]]) :
- msg_add_auth (msgport, auth->authport));
- if (err &&
- (!ignore_bad_pid || (err != ESRCH && err != MIG_SERVER_DIED)))
- {
- fprintf (stderr, "%s: error in %s_auth from PID %d: %s\n",
- program_invocation_short_name,
- remove_ids ? "del" : "add", pid, strerror (err));
- return 1;
- }
- else
- return 0;
-}
-
-int
-apply_auth_to_pids (struct auth *auth, unsigned int npids, pid_t pids[],
- int ignore_bad_pid)
-{
- int status = 0;
- unsigned int i;
-
- for (i = 0; i < npids; ++i)
- status |= apply_auth (auth, pids[i], ignore_bad_pid);
-
- return status;
-}
-
-int
-apply_auth_to_loginid (struct auth *auth, int loginid)
-{
- unsigned int npids = 20;
- pid_t pidbuf[20], *pids = pidbuf;
- int status;
- error_t err;
-
- err = proc_getloginpids (proc, loginid, &pids, &npids);
- if (err)
- {
- fprintf (stderr, "%s: proc_getloginpids failed for loginid %d: %s\n",
- program_invocation_short_name, loginid, strerror (err));
- return 1;
- }
-
- status = apply_auth_to_pids (auth, npids, pids, 1);
-
- if (pids != pidbuf)
- vm_deallocate (mach_task_self (),
- (vm_address_t) pids, npids * sizeof (pid_t));
-
- return status;
-}
-
-int
-apply_auth_to_pgrp (struct auth *auth, pid_t pgrp)
-{
- unsigned int npids = 20;
- pid_t pidbuf[20], *pids = pidbuf;
- int status;
- error_t err;
-
- err = proc_getpgrppids (proc, pgrp, &pids, &npids);
- if (err)
- {
- fprintf (stderr, "%s: proc_getpgrppids failed for pgrp %d: %s\n",
- program_invocation_short_name, pgrp, strerror (err));
- return 1;
- }
-
- status = apply_auth_to_pids (auth, npids, pids, 1);
-
- if (pids != pidbuf)
- vm_deallocate (mach_task_self (),
- (vm_address_t) pids, npids * sizeof (pid_t));
-
- return status;
-}
-
-/* Return 1 if the user gives the correct password matching the encrypted
- string PASSWORD, 0 if not. Return 1 without asking for a password if
- run by uid 0 or if PASSWORD is an empty password, and always under -r.
- Always prints a message before returning 0. */
-int
-check_password (const char *name, const char *password)
-{
- extern char *crypt (const char *string, const char salt[2]);
-#pragma weak crypt
- char *unencrypted, *encrypted;
- static char *prompt = NULL;
-
- if (remove_ids || getuid () == 0 || password == NULL || password[0] == '\0')
- return 1;
-
- asprintf (&prompt, "%s's Password:", name);
- unencrypted = getpass (prompt);
- if (crypt)
- {
- encrypted = crypt (unencrypted, password);
- memset (unencrypted, 0, strlen (unencrypted)); /* Paranoia may destroya. */
- }
- else
- encrypted = unencrypted;
-
- if (!strcmp (encrypted, password))
- return 1;
-
- fprintf (stderr, "%s: Access denied for `%s'\n",
- program_invocation_short_name, name);
- return 0;
-}
diff --git a/utils/sush.sh b/utils/sush.sh
index 034fb6ad..4fccd75e 100644
--- a/utils/sush.sh
+++ b/utils/sush.sh
@@ -1,3 +1,90 @@
#!/bin/sh
-# A unix-like su (one which invokes a sub-shell).
-exec /bin/login --program-name="$0" -pxSLf -aHOME -aMOTD -aUMASK -aBACKUP_SHELLS "$@"
+# A unix-like su (one which invokes a sub-shell).
+#
+# Copyright (C) 1996 Free Software Foundation, Inc.
+#
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+ARGS_DOC="[USER|- [COMMAND [ARG...]]]"
+USAGE="Usage: $0 $ARGS_DOC"
+DOC="Start a new shell, or COMMAND, as USER"
+
+LOGIN=${LOGIN-/bin/login}
+FMT=${FMT-/bin/fmt}
+
+needs_arg=""
+for I; do
+ case $needs_arg in
+ ?*) needs_arg="";;
+ "")
+ case "$I" in
+ -e|-E|-g|-G|-u|-U|--envar|--envva|--env|--en|--e|--envvar-default|--envvar-defaul|--envvar-defau|--envvar-defa|--envvar-def|--envvar-def|--envvar-de|--envvar-d|--envvar-|--group|--grou|--gro|--gr|--g|--avail-group|--avail-grou|--avail-gro|--avail-gr|--avail-g|--user|--use|--us|--u|--avail-user|--avail-use|--avail-us|--avail-u)
+ needs_arg="$I";;
+ -e*|-E*|-g*|-G*|-u*|-U*|--envar=*|--envva=*|--env=*|--en=*|--e=*|--envvar-default=*|--envvar-defaul=*|--envvar-defau=*|--envvar-defa=*|--envvar-def=*|--envvar-def=*|--envvar-de=*|--envvar-d=*|--envvar-=*|--group=*|--grou=*|--gro=*|--gr=*|--g=*|--avail-group=*|--avail-grou=*|--avail-gro=*|--avail-gr=*|--avail-g=*|--user=*|--use=*|--us=*|--u=*|--avail-user=*|--avail-use=*|--avail-us=*|--avail-u=*)
+ :;;
+ --avail-|--avail|--avai|--ava|--av|--a|--avail-=*|--avail=*|--avai=*|--ava=*|--av=*|--a=*)
+ echo 1>&2 "$0: option \`$1' is ambiguous"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ --help|"-?" |--hel|--he|--h)
+ echo "$USAGE"
+ echo "$DOC"
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " -e ENTRY, --envvar=ENTRY Add ENTRY to the environment"
+ echo " -E ENTRY, --envvar-default=ENTRY"
+ echo " Use ENTRY as a default environment variable"
+ echo " -g GROUP, --group=GROUP Add GROUP to the effective groups"
+ echo " -G GROUP, --avail-group=GROUP Add GROUP to the available groups"
+ echo " -u USER, --user=USER Add USER to the effective uids"
+ echo " -U USER, --avail-user=USER Add USER to the available uids"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ echo ""
+ echo "Unlike the traditional unix \`su' command, if USER is not specified,"
+ echo "then the result is *no* user-ids, not uid 0."
+ exit 0;;
+ --usage |--usag|--usa|--us|--u)
+ (echo "Usage: $0 [-V?]"
+ echo " [-e ENTRY] [-E ENTRY] [-g GROUP] [-G GROUP] [-u USER] [-U USER] [--envvar=ENTRY] [--envvar-default=ENTRY] [--group=GROUP] [--avail-group=GROUP][--group=GROUP] [--avail-group=GROUP] [--user=USER] [--avail-user=USER] [--help] [--usage] [--version] $ARGS_DOC") |$FMT -t
+ exit 0;;
+ --version|-V |--versio|--versi|--vers|--ver|--ve|--v)
+ echo "STANDARD_HURD_VERSION_sush_"; exit 0;;
+ -)
+ : ;;
+ --)
+ break;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac;;
+ esac
+done
+
+case "$needs_arg" in ?*)
+ echo 1>&2 "$0: option \`$1' requires an argument"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+esac
+
+exec $LOGIN --program-name="$0" -pxSLf -aHOME -aMOTD -aUMASK -aBACKUP_SHELLS "$@"
diff --git a/utils/syncfs.c b/utils/syncfs.c
new file mode 100644
index 00000000..3434f5c6
--- /dev/null
+++ b/utils/syncfs.c
@@ -0,0 +1,80 @@
+/* syncfs -- User interface to file_syncfs, synchronize filesystems.
+ Copyright (C) 1994, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (sync);
+
+static int synchronous = 0, do_children = 1;
+
+static void
+sync_one (const char *name, file_t port)
+{
+ error_t err = (port == MACH_PORT_NULL ? errno
+ : file_syncfs (port, synchronous, do_children));
+ if (err)
+ error (1, err, "%s", name);
+}
+
+static error_t
+parser (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 's': synchronous = 1; break;
+ case 'c': do_children = 0; break;
+
+ case ARGP_KEY_NO_ARGS:
+ sync_one ("/", getcrdir ());
+ break;
+
+ case ARGP_KEY_ARG:
+ sync_one (arg, file_name_lookup (arg, 0, 0));
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ static struct argp_option options[] =
+ {
+ {"synchronous", 's', 0, 0, "Wait for completion of all disk writes"},
+ {"no-children", 'c', 0, 0, "Do not synchronize child filesystems"},
+ {0}
+ };
+ struct argp argp =
+ {options, parser,
+ "[FILE...]", "Force all pending disk writes to be done immediately"
+ "\vThe filesystem containing each FILE is synchronized, and its child"
+ " filesystems unless --no-children is specified. With no FILE argument"
+ " synchronizes the root filesystem."};
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ return 0;
+}
diff --git a/utils/unsu.c b/utils/unsu.c
new file mode 100644
index 00000000..467cf46f
--- /dev/null
+++ b/utils/unsu.c
@@ -0,0 +1,90 @@
+/* Attempt to undo a previous su
+
+ Copyright (C) 1997,98,2000 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <hurd.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "frobauth.h"
+#include "pids.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (unsu);
+
+static struct argp_child child_argps[] = {{ &frobauth_no_ugids_argp }, { 0 }};
+
+static char doc[] =
+ "Attempt to undo a previous setauth --save"
+ "\vThis command is convenient, but will only correctly undo a limited"
+ " subset of possible setauth commands. It works by simply deleting all"
+ " current effective ids and the first two available ids, and then"
+ " making the first remaining available id the current effective id.";
+
+int
+main (int argc, char *argv[])
+{
+ struct frobauth frobauth = FROBAUTH_INIT;
+
+ /* Modify UGIDS, to be what PID's new authentication should be, NOISE is
+ ignored. */
+ error_t modify (struct ugids *ugids, const struct ugids *noise,
+ pid_t pid, void *hook)
+ {
+ error_t err = 0;
+
+ idvec_clear (&ugids->eff_uids);
+ idvec_clear (&ugids->eff_gids);
+ idvec_clear (&ugids->imp_eff_gids);
+
+ idvec_delete (&ugids->avail_uids, 0);
+ idvec_delete (&ugids->avail_uids, 0);
+
+ idvec_delete (&ugids->avail_gids, 0);
+ idvec_delete (&ugids->avail_gids, 0);
+ idvec_keep (&ugids->imp_avail_gids, &ugids->avail_gids);
+
+ if (ugids->avail_uids.num > 0)
+ err = ugids_set_posix_user (ugids, ugids->avail_uids.ids[0]);
+
+ return err;
+ }
+ void print_info (const struct ugids *new,
+ const struct ugids *old,
+ const struct ugids *removed,
+ pid_t pid, void *hook)
+ {
+ char *new_rep = ugids_rep (new, 1, 1, 0, 0, 0);
+ printf ("%d: Changed auth to %s\n", pid, new_rep);
+ free (new_rep);
+ }
+ struct argp argp = { 0, 0, 0, doc, child_argps };
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&argp, argc, argv, 0, 0, &frobauth);
+
+ if (frobauth_modify (&frobauth, 0, 0, modify, print_info, 0))
+ return 0;
+ else
+ return 1;
+}
diff --git a/utils/uptime.sh b/utils/uptime.sh
index 541996b3..8e52c81b 100644
--- a/utils/uptime.sh
+++ b/utils/uptime.sh
@@ -1,2 +1,62 @@
#!/bin/sh
-/bin/w -u
+# Show system uptime, number of users, and load
+#
+# Copyright (C) 1996 Free Software Foundation, Inc.
+#
+# Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+USAGE="Usage: $0 [OPTION...]"
+DOC="Show system uptime, number of users, and load"
+
+W=${W-/bin/w}
+
+while :; do
+ case "$1" in
+ --help|"-?")
+ echo "$USAGE"
+ echo "$DOC"
+ echo ""
+ echo " -?, --help Give this help list"
+ echo " --usage Give a short usage message"
+ echo " -V, --version Print program version"
+ exit 0;;
+ --usage)
+ echo "Usage: $0 [-V?] [--help] [--usage] [--version]"
+ exit 0;;
+ --version|-V)
+ echo "STANDARD_HURD_VERSION_uptime_"; exit 0;;
+ -*)
+ echo 1>&2 "$0: unrecognized option \`$1'"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+ *)
+ break;;
+ esac
+done
+
+case "$#" in
+ 0) :;;
+ *)
+ echo 1>&2 "$0: too many arguments"
+ echo 1>&2 "Try \`$0 --help' or \`$0 --usage' for more information";
+ exit 1;;
+esac
+
+$W -u
diff --git a/utils/vminfo.c b/utils/vminfo.c
new file mode 100644
index 00000000..6ead677e
--- /dev/null
+++ b/utils/vminfo.c
@@ -0,0 +1,241 @@
+/* Print task vm information
+
+ Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <argp.h>
+#include <error.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <version.h>
+
+#include <mach.h>
+#include <mach/vm_statistics.h>
+#include <mach/default_pager.h>
+#include <hurd.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (vminfo);
+
+static const struct argp_option options[] = {
+ {"verbose", 'v', 0, 0, "Give more detailed information"},
+ {"addresses", 'a', 0, 0, "Print region start addresses"},
+ {"sizes", 's', 0, 0, "Print region sizes"},
+ {"decimal", 'd', 0, 0, "Show number is decimal"},
+ {"holes", 'h', 0, 0, "Show holes between regions explicitly"},
+ {0}
+};
+static const char *args_doc = "PID [ADDR [SIZE]]]";
+static const char *doc = "Show virtual memory regions for process PID"
+"\vIf ADDR, and possibly SIZE, are given only regions enclosing the range"
+" ADDR to ADDR+SIZE are shown (SIZE defaults to 0)."
+"\nIf neither --addresses nor --sizes is specified, both are assumed.";
+
+/* Possible things to show about regions. */
+#define W_ADDRS 0x1
+#define W_SIZES 0x2
+#define W_DETAILS 0x4
+
+static char *
+prot_rep (vm_prot_t prot)
+{
+ if (prot == 0)
+ return "0";
+ else
+ {
+ static char buf[20];
+ char *p = buf;
+ if (prot & VM_PROT_READ)
+ *p++ = 'R';
+ if (prot & VM_PROT_WRITE)
+ *p++ = 'W';
+ if (prot & VM_PROT_EXECUTE)
+ *p++ = 'X';
+ if (prot & ~VM_PROT_ALL)
+ sprintf (p, "+%#x", (prot & ~VM_PROT_ALL));
+ else
+ *p = '\0';
+ return buf;
+ }
+}
+
+static char *
+inh_rep (vm_inherit_t inh)
+{
+ static char buf[20];
+ switch (inh)
+ {
+ case VM_INHERIT_SHARE: return "share";
+ case VM_INHERIT_COPY: return "copy";
+ case VM_INHERIT_NONE: return "none";
+ default:
+ sprintf (buf, "%d", inh);
+ return buf;
+ }
+}
+
+static unsigned
+parse_num (char *arg, unsigned base, struct argp_state *state, char *what)
+{
+ char *arg_end;
+ unsigned long num = strtoul (arg, &arg_end, base);
+ if (*arg == '\0' || *arg_end != '\0')
+ argp_error (state, "%s: Invalid %s", arg, what);
+ return num;
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ int what = 0, hex = 1, holes = 0;
+ vm_offset_t addr = 0, max_addr = ~addr;
+ task_t task;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ pid_t pid;
+ process_t proc;
+
+ case 'a': what |= W_ADDRS; break;
+ case 's': what |= W_SIZES; break;
+ case 'v': what |= W_DETAILS; break;
+ case 'd': hex = 0; break;
+ case 'h': holes = 1; break;
+
+ case ARGP_KEY_ARG:
+ switch (state->arg_num)
+ {
+ case 0: /* PID */
+ pid = parse_num (arg, 10, state, "PID");
+ proc = getproc ();
+ err = proc_pid2task (proc, pid, &task);
+ if (err)
+ argp_failure (state, 11, err, "%s", arg);
+ break;
+ case 1: /* ADDR */
+ addr = max_addr = parse_num (arg, 0, state, "address"); break;
+ case 2: /* SIZE */
+ max_addr = addr + parse_num (arg, 0, state, "size"); break;
+ default:
+ argp_usage (state);
+ }
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ const struct argp argp = { options, parse_opt, args_doc, doc };
+
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ if ((what & ~W_DETAILS) == 0)
+ what = W_ADDRS | W_SIZES | W_DETAILS;
+
+ while (addr <= max_addr)
+ {
+ vm_size_t size;
+ vm_prot_t prot, max_prot;
+ mach_port_t obj;
+ vm_offset_t offs;
+ vm_inherit_t inh;
+ int shared;
+ vm_offset_t hole_addr = addr;
+
+ err =
+ vm_region (task, &addr, &size, &prot, &max_prot, &inh, &shared,
+ &obj, &offs);
+ if (err)
+ {
+ if (err != EKERN_NO_SPACE)
+ error (12, err, "vm_region");
+ break;
+ }
+
+ if (holes && hole_addr != addr)
+ {
+ if ((what & (W_ADDRS|W_SIZES)) == (W_ADDRS|W_SIZES))
+ {
+ if (hex)
+ printf (" [%#zx] (hole)\n", addr - hole_addr);
+ else
+ printf (" [%zd] (hole)\n", addr - hole_addr);
+ }
+ else if ((what & (W_ADDRS|W_SIZES)) == W_SIZES)
+ {
+ if (hex)
+ printf ("%#10zx (hole)\n", addr - hole_addr);
+ else
+ printf ("%10zu (hole)\n", addr - hole_addr);
+ }
+ }
+
+ if ((what & (W_ADDRS|W_SIZES)) == (W_ADDRS|W_SIZES))
+ if (hex)
+ printf ("%#10zx[%#zx]", addr, size);
+ else
+ printf ("%10zu[%zd]", addr, size);
+ else if ((what & (W_ADDRS|W_SIZES)) == W_ADDRS)
+ if (hex)
+ printf ("%#10zx", addr);
+ else
+ printf ("%10zu", addr);
+ else if ((what & (W_ADDRS|W_SIZES)) == W_SIZES)
+ {
+ if (hex)
+ printf ("%#10zx", size);
+ else
+ printf ("%10zu", size);
+ }
+ if (what & W_DETAILS)
+ {
+ printf (" (prot=%s", prot_rep (prot));
+ if (max_prot != prot)
+ printf (", max_prot=%s", prot_rep (max_prot));
+ if (inh != VM_INHERIT_DEFAULT)
+ printf (", inherit=%s", inh_rep (inh));
+ if (shared)
+ printf (", shared");
+ if (obj != MACH_PORT_NULL)
+ printf (", mem_obj=%d", obj);
+ if (offs != 0)
+ {
+ if (hex)
+ printf (", offs=%#zx", offs);
+ else
+ printf (", offs=%zd", offs);
+ }
+ putchar (')');
+ }
+ putchar ('\n');
+
+ addr += size;
+ }
+
+ exit (0);
+}
diff --git a/utils/vmstat.c b/utils/vmstat.c
index c7f7a7af..7d852992 100644
--- a/utils/vmstat.c
+++ b/utils/vmstat.c
@@ -1,8 +1,7 @@
/* Print vm statistics
- Copyright (C) 1996 Free Software Foundation, Inc.
-
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Copyright (C) 1996,97,99,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -25,30 +24,30 @@
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+#include <fcntl.h>
+#include <version.h>
#include <mach.h>
#include <mach/vm_statistics.h>
#include <mach/default_pager.h>
#include <hurd.h>
+#include <hurd/paths.h>
-char *argp_program_version = "vmstat 1.1 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (vmstat);
static const struct argp_option options[] = {
- {"terse", 't', 0, 0, "Use short one-line output format", 1 },
+ {"terse", 't', 0, 0, "Use short one-line output format"},
{"no-header", 'H', 0, 0, "Don't print a descriptive header line"},
{"prefix", 'p', 0, 0, "Always display a description before stats"},
{"no-prefix", 'P', 0, 0, "Never display a description before stats"},
{"pages", 'v', 0, 0, "Display sizes in pages"},
{"kilobytes", 'k', 0, 0, "Display sizes in 1024 byte blocks"},
{"bytes", 'b', 0, 0, "Display sizes in bytes"},
-
- /* A header for all the individual field options. */
- { 0,0,0,0, "Selecting which statistics to show:", 2},
-
{0}
};
static const char *args_doc = "[PERIOD [COUNT [HEADER_INTERVAL]]]";
-static const char *doc = "If PERIOD is supplied, then terse mode is"
+static const char *doc = "Show system virtual memory statistics"
+"\vIf PERIOD is supplied, then terse mode is"
" selected, and the output repeated every PERIOD seconds, with cumulative"
" fields given the difference from the last output. If COUNT is given"
" and non-zero, only that many lines are output. HEADER_INTERVAL"
@@ -61,6 +60,7 @@ static const char *doc = "If PERIOD is supplied, then terse mode is"
than what the system returns values in, as we represent some quantities as
bytes instead of pages)! */
typedef long long val_t;
+#define BADVAL ((val_t) -1LL) /* a good generic value for "couldn't get" */
/* What a given number describes. */
enum val_type
@@ -71,6 +71,31 @@ enum val_type
PCENT, /* Append `%'. */
};
+/* Return the `nominal' width of a field of type TYPE, in units of SIZE_UNITS. */
+static size_t
+val_width (val_t val, enum val_type type, size_t size_units)
+{
+ size_t vwidth (val_t val)
+ {
+ size_t w = 1;
+ if (val < 0)
+ w++, val = -val;
+ while (val > 9)
+ w++, val /= 10;
+ return w;
+ }
+ if (type == PCENT)
+ return vwidth (val) + 1;
+ else if ((type == SIZE || type == PAGESZ) && size_units == 0)
+ return val > 1000 ? 5 : vwidth (val) + 1;
+ else
+ {
+ if ((type == SIZE || type == PAGESZ) && size_units > 0)
+ val /= size_units;
+ return vwidth (val);
+ }
+}
+
/* Print a number of type TYPE. If SIZE_UNITS is non-zero, then values of
type SIZE are divided by that amount and printed without a suffix. FWIDTH
is the width of the field to print it in, right-justified. If SIGN is
@@ -80,13 +105,13 @@ print_val (val_t val, enum val_type type,
size_t size_units, int fwidth, int sign)
{
if (type == PCENT)
- printf (sign ? "%+*d%%" : "%*d%%", fwidth - 1, val);
+ printf (sign ? "%+*lld%%" : "%*lld%%", fwidth - 1, val);
else if ((type == SIZE || type == PAGESZ) && size_units == 0)
{
float fval = val;
char *units = " KMGT", *u = units;
- while (fval > 1024)
+ while (fval >= 10000)
{
fval /= 1024;
u++;
@@ -101,10 +126,14 @@ print_val (val_t val, enum val_type type,
{
if ((type == SIZE || type == PAGESZ) && size_units > 0)
val /= size_units;
- printf (sign ? "%+*d" : "%*d", fwidth, val);
+ printf (sign ? "%+*lld" : "%*lld", fwidth, val);
}
}
+/* Special values for val_t ranges. */
+#define VAL_MAX_MEM -1 /* up to the system memory size */
+#define VAL_MAX_SWAP -2 /* up to the system swap size */
+
/* How this field changes with time. */
enum field_change_type
{
@@ -117,15 +146,15 @@ struct vm_state; /* fwd */
struct field
{
- /* Name of the field; used for the option name. */
+ /* Name of the field. */
char *name;
- /* A descriptive title used for long output format. */
- char *desc;
-
/* Terse header used for the columnar style output. */
char *hdr;
+ /* A description of this field (for user help). */
+ char *doc;
+
/* Type of this field. */
enum field_change_type change_type;
@@ -134,6 +163,9 @@ struct field
user. */
enum val_type type;
+ /* The `maximum value' this field can have -- used for field widths. */
+ val_t max;
+
/* True if we display this field by default (user can always override). */
int standard :1;
@@ -148,7 +180,7 @@ struct field
};
/* State about system vm from which we compute the above defined fields. */
-struct vm_state
+struct vm_state
{
/* General vm statistics. */
struct vm_statistics vmstats;
@@ -167,7 +199,7 @@ vm_state_refresh (struct vm_state *state)
return err;
/* Mark the info as invalid, but leave DEF_PAGER alone. */
- bzero (&state->def_pager_info, sizeof state->def_pager_info);
+ memset (&state->def_pager_info, 0, sizeof state->def_pager_info);
return 0;
}
@@ -198,7 +230,7 @@ vm_state_get_field (struct vm_state *state, const struct field *field)
}
static val_t
-get_cache_hit_ratio (struct vm_state *state, const struct field *field)
+get_memobj_hit_ratio (struct vm_state *state, const struct field *field)
{
return state->vmstats.hits * 100 / state->vmstats.lookups;
}
@@ -215,89 +247,125 @@ ensure_def_pager_info (struct vm_state *state)
mach_port_t host;
err = get_privileged_ports (&host, 0);
- if (err)
+ if (err == EPERM)
{
- error (0, err, "get_privileged_ports");
- return 0;
+ /* We are not root, so try opening the /servers file. */
+ state->def_pager = file_name_lookup (_SERVERS_DEFPAGER, O_READ, 0);
+ if (state->def_pager == MACH_PORT_NULL)
+ {
+ error (0, errno, _SERVERS_DEFPAGER);
+ return 0;
+ }
}
+ if (state->def_pager == MACH_PORT_NULL)
+ {
+ if (err)
+ {
+ error (0, err, "get_privileged_ports");
+ return 0;
+ }
- err = vm_set_default_memory_manager (host, &state->def_pager);
- mach_port_deallocate (mach_task_self (), host);
+ err = vm_set_default_memory_manager (host, &state->def_pager);
+ mach_port_deallocate (mach_task_self (), host);
+
+ if (err)
+ {
+ error (0, err, "vm_set_default_memory_manager");
+ return 0;
+ }
+ }
+ }
- if (err)
+ if (!MACH_PORT_VALID (state->def_pager))
+ {
+ if (state->def_pager == MACH_PORT_NULL)
{
- error (0, err, "vm_set_default_memory_manager");
- return 0;
+ error (0, 0,
+ "No default pager running, so no swap information available");
+ state->def_pager = MACH_PORT_DEAD; /* so we don't try again */
}
+ return 0;
}
err = default_pager_info (state->def_pager, &state->def_pager_info);
if (err)
error (0, err, "default_pager_info");
-
return (err == 0);
}
-static val_t
-get_swap_size (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_total_space : -1;
-}
+#define SWAP_FIELD(getter, expr) \
+ static val_t getter (struct vm_state *state, const struct field *field) \
+ { return ensure_def_pager_info (state) ? (val_t) (expr) : BADVAL; }
-static val_t
-get_swap_free (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_free_space : -1;
-}
-
-static val_t
-get_swap_page_size (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state) ? state->def_pager_info.dpi_page_size : -1;
-}
-
-static val_t
-get_swap_active (struct vm_state *state, const struct field *field)
-{
- return
- ensure_def_pager_info (state)
- ? (state->def_pager_info.dpi_total_space
- - state->def_pager_info.dpi_free_space)
- : -1;
-}
+SWAP_FIELD (get_swap_size, state->def_pager_info.dpi_total_space)
+SWAP_FIELD (get_swap_free, state->def_pager_info.dpi_free_space)
+SWAP_FIELD (get_swap_page_size, state->def_pager_info.dpi_page_size)
+SWAP_FIELD (get_swap_active, (state->def_pager_info.dpi_total_space
+ - state->def_pager_info.dpi_free_space))
/* Returns the byte offset of the field FIELD in a vm_statistics structure. */
#define _F(field_name) offsetof (struct vm_statistics, field_name)
+#define K 1024
+#define M (1024*K)
+#define G (1024LL*M)
+
/* vm_statistics fields we know about. */
static const struct field fields[] =
{
- {"pagesize", "Pagesize", " pgsz", CONST,PAGESZ, 1,_F(pagesize)},
- {"size", "Size", " size", CONST,SIZE, 1,0,get_size},
- {"free", "Free", " free", VARY, SIZE, 1,_F(free_count)},
- {"active", "Active", " actv", VARY, SIZE, 1,_F(active_count)},
- {"inactive", "Inactive", "inact", VARY, SIZE, 1,_F(inactive_count)},
- {"wired", "Wired", "wired", VARY, SIZE, 1,_F(wire_count)},
- {"zero-filled", "Zeroed", "zeroed", CUMUL,SIZE, 1,_F(zero_fill_count)},
- {"reactivated", "Reactivated", "react", CUMUL,SIZE, 1,_F(reactivations)},
- {"pageins", "Pageins", "pgins", CUMUL,SIZE, 1,_F(pageins)},
- {"pageouts", "Pageouts", "pgouts", CUMUL,SIZE, 1,_F(pageouts)},
- {"faults", "Faults", "pfaults",CUMUL,COUNT,1,_F(faults)},
- {"cow-faults", "Cow faults", "cowpfs", CUMUL,COUNT,1,_F(cow_faults)},
- {"cache-lookups","Cache lookups","clkups", CUMUL,COUNT,0,_F(lookups)},
- {"cache-hits", "Cache hits", "chits", CUMUL,COUNT,0,_F(hits)},
- {"cache-hit-ratio","Cache hit ratio","chrat",VARY,PCENT,1,-1,get_cache_hit_ratio},
- {"swap-size", "Swap size", "swsize", CONST,SIZE, 1,0,get_swap_size},
- {"swap-active", "Swap active", "swactv", VARY, SIZE, 0,0,get_swap_active},
- {"swap-free", "Swap free", "swfree", VARY, SIZE, 1,0,get_swap_free},
- {"swap-pagesize","Swap pagesize","swpgsz", CONST,PAGESZ, 0,0,get_swap_page_size},
+ {"pagesize", "pgsz", "System pagesize",
+ CONST, PAGESZ, 16*K, 1, _F (pagesize) },
+ {"size", "size", "Usable physical memory",
+ CONST, SIZE, VAL_MAX_MEM, 1, 0, get_size },
+ {"free", "free", "Unused physical memory",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (free_count) },
+ {"active", "actv", "Physical memory in active use",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (active_count) },
+ {"inactive", "inact", "Physical memory in the inactive queue",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (inactive_count) },
+ {"wired", "wired", "Unpageable physical memory",
+ VARY, SIZE, VAL_MAX_MEM, 1, _F (wire_count) },
+ {"zero filled", "zeroed","Cumulative zero-filled pages",
+ CUMUL, SIZE, 90*G, 1, _F (zero_fill_count) },
+ {"reactivated", "react", "Cumulative reactivated inactive pages",
+ CUMUL, SIZE, 900*M, 1, _F (reactivations) },
+ {"pageins", "pgins", "Cumulative pages paged in",
+ CUMUL, SIZE, 90*G, 1, _F (pageins) },
+ {"pageouts", "pgouts","Cumulative pages paged out",
+ CUMUL, SIZE, 90*G, 1, _F (pageouts) },
+ {"page faults", "pfaults","Cumulative page faults",
+ CUMUL, COUNT, 99999999, 1, _F (faults) },
+ {"cow faults", "cowpfs", "Cumulative copy-on-write page faults",
+ CUMUL, COUNT, 9999999, 1, _F (cow_faults) },
+ {"memobj lookups","lkups","Memory-object lookups",
+ CUMUL, COUNT, 999999, 0, _F (lookups) },
+ {"memobj hits", "hits", "Memory-object lookups with active pagers",
+ CUMUL, COUNT, 999999, 0, _F (hits) },
+ {"memobj hit ratio","hrat","Percentage of memory-object lookups with active pagers",
+ VARY, PCENT, 99, 1, -1, get_memobj_hit_ratio },
+ {"swap size", "swsize", "Size of the default-pager swap area",
+ CONST, SIZE, VAL_MAX_SWAP, 1, 0 ,get_swap_size },
+ {"swap active", "swactv", "Default-pager swap area in use",
+ VARY, SIZE, VAL_MAX_SWAP, 0, 0 ,get_swap_active },
+ {"swap free", "swfree", "Default-pager swap area available for swapping",
+ VARY, SIZE, VAL_MAX_SWAP, 1, 0 ,get_swap_free },
+ {"swap pagesize","swpgsz", "Units used for swapping to the default pager",
+ CONST, PAGESZ, 16*K, 0, 0 ,get_swap_page_size },
{0}
};
#undef _F
+/* Convert a field name to the corresponding user-option. */
+static char *name_to_option (const char *name)
+{
+ char *opt = strdup (name), *p;
+ if (opt)
+ for (p = opt; *p; p++)
+ if (*p == ' ')
+ *p = '-';
+ return opt;
+}
+
int
main (int argc, char **argv)
{
@@ -327,7 +395,7 @@ main (int argc, char **argv)
case 'H': print_heading = 0; break;
case 'b': size_units = 1; break;
case 'v': size_units = -1; break;
- case 'k': size_units = 1024; break;
+ case 'k': size_units = K; break;
case ARGP_KEY_ARG:
terse = 1;
@@ -352,8 +420,9 @@ main (int argc, char **argv)
struct argp_option *field_opts;
int field_opts_size;
struct argp field_argp = { 0, parse_opt };
- const struct argp *parents[] = { &field_argp, 0 };
- const struct argp argp = { options, parse_opt, args_doc, doc, parents };
+ const struct argp_child children[] =
+ {{&field_argp, 0, "Selecting which statistics to show:"}, {0}};
+ const struct argp argp = { options, parse_opt, args_doc, doc, children };
/* See how many fields we know about. */
for (field = fields; field->name; field++)
@@ -362,19 +431,19 @@ main (int argc, char **argv)
/* Construct an options vector for them. */
field_opts_size = ((num_fields + 1) * sizeof (struct argp_option));
field_opts = alloca (field_opts_size);
- bzero (field_opts, field_opts_size);
+ memset (field_opts, 0, field_opts_size);
for (field = fields; field->name; field++)
{
int which = field - fields;
struct argp_option *opt = &field_opts[which];
- opt->name = field->name;
+ opt->name = name_to_option (field->name);
opt->key = -1 - which; /* options are numbered -1 ... -(N - 1). */
- opt->doc = field->desc;
+ opt->doc = field->doc;
opt->group = 2;
}
- /* No need to terminate FIELD_OPTS because the bzero above's done so. */
+ /* No need to terminate FIELD_OPTS because the memset above has done so. */
field_argp.options = field_opts;
@@ -387,10 +456,10 @@ main (int argc, char **argv)
if (field->standard)
output_fields |= (1 << (field - fields));
- /* Returns an appropiate SIZE_UNITS for printing FIELD. */
-#define SIZE_UNITS(field) \
- (size_units >= 0 \
- ? size_units \
+ /* Returns an appropriate SIZE_UNITS for printing FIELD. */
+#define SIZE_UNITS(field) \
+ (size_units >= 0 \
+ ? size_units \
: ((field)->type == PAGESZ ? 0 : state.vmstats.pagesize))
/* Prints SEP if the variable FIRST is 0, otherwise, prints START (if
@@ -399,9 +468,15 @@ main (int argc, char **argv)
(first ? (first = 0, (start && fputs (start, stdout))) : fputs (sep, stdout))
#define PVAL(val, field, width, sign) \
print_val (val, (field)->type, SIZE_UNITS (field), width, sign)
-
+ /* Intuit the likely maximum field width of FIELD. */
+#define FWIDTH(field) \
+ val_width ((field)->max == VAL_MAX_MEM ? get_size (&state, field) \
+ : (field)->max == VAL_MAX_SWAP ? get_swap_size (&state, field) \
+ : (field)->max, \
+ (field)->type, SIZE_UNITS (field))
+
/* Actually fetch the statistics. */
- bzero (&state, sizeof (state)); /* Initialize STATE. */
+ memset (&state, 0, sizeof (state)); /* Initialize STATE. */
err = vm_state_refresh (&state);
if (err)
error (2, err, "vm_state_refresh");
@@ -429,6 +504,9 @@ main (int argc, char **argv)
do
{
+ int num;
+ int fwidths[num_fields];
+
if (first_hdr)
first_hdr = 0;
else
@@ -447,7 +525,7 @@ main (int argc, char **argv)
else
{
PSEP (", ", "(");
- printf ("%s: ", field->desc);
+ printf ("%s: ", field->name);
PVAL (val, field, 0, 0);
}
}
@@ -455,39 +533,62 @@ main (int argc, char **argv)
puts (")");
}
+ /* Calculate field widths. */
+ for (field = fields, num = 0; field->name; field++, num++)
+ if (output_fields & (1 << (field - fields)))
+ {
+ fwidths[num] = FWIDTH (field);
+ if (count != 1 && size_units == 0
+ && field->change_type == CUMUL && field->type == SIZE)
+ /* We may be printing a `+' prefix for field changes, and
+ since this is using the mostly constant-width SIZE
+ notation, individual changes may be the same width as
+ appropriated for absolute values -- so reserver another
+ column for the `+' character. */
+ fwidths[num]++;
+ if (fwidths[num] < strlen (field->hdr))
+ fwidths[num] = strlen (field->hdr);
+ }
+
if (print_heading)
{
- for (field = fields, first = 1; field->name; field++)
+ for (field = fields, num = 0, first = 1; field->name; field++, num++)
if (output_fields & (1 << (field - fields)))
{
PSEP (" ", 0);
- fputs (field->hdr, stdout);
+ fprintf (stdout, "%*s", fwidths[num], field->hdr);
}
putchar ('\n');
}
-
+
prev_state = state;
for (repeats = 0
- ; count && repeats < hdr_interval && count
+ ; count && repeats < hdr_interval
; repeats++, count--)
{
/* Output the fields. */
- for (field = fields, first = 1; field->name; field++)
+ for (field = fields, num = 0, first = 1; field->name; field++, num++)
if (output_fields & (1 << (field - fields)))
{
- int sign = 0;
- int width = strlen (field->hdr);
val_t val = vm_state_get_field (&state, field);
- if (repeats && field->change_type == CUMUL)
+ if (val < 0)
+ /* Couldn't fetch this field, don't try again. */
+ const_fields &= ~(1 << (field - fields));
+ else
{
- sign = 1;
- val -= vm_state_get_field (&prev_state, field);
- }
+ int sign = 0;
- PSEP (" ", 0);
- PVAL (val, field, width, sign);
+ if (repeats && field->change_type == CUMUL)
+ {
+ sign = 1;
+ val -= vm_state_get_field (&prev_state, field);
+ }
+
+ PSEP (" ", 0);
+ PVAL (val, field, fwidths[num], sign);
+ }
}
putchar ('\n');
@@ -507,7 +608,7 @@ main (int argc, char **argv)
else
/* Verbose output. */
{
- int max_desc_width = 0;
+ int max_width = 0;
if (print_prefix < 0)
/* By default, only print a prefix if there are multiple fields. */
@@ -518,23 +619,26 @@ main (int argc, char **argv)
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
- int desc_len = strlen (field->desc);
- if (desc_len > max_desc_width)
- max_desc_width = desc_len;
+ int width = strlen (field->name) + FWIDTH (field);
+ if (width > max_width)
+ max_width = width;
}
for (field = fields; field->name; field++)
if (output_fields & (1 << (field - fields)))
{
val_t val = vm_state_get_field (&state, field);
- int fwidth = 0;
- if (print_prefix)
+ if (val >= 0)
{
- printf ("%s:", field->desc);
- fwidth = max_desc_width + 5 - strlen (field->desc);
+ int fwidth = 0;
+ if (print_prefix)
+ {
+ printf ("%s: ", field->name);
+ fwidth = max_width - strlen (field->name);
+ }
+ PVAL (val, field, fwidth, 0);
+ putchar ('\n');
}
- PVAL (val, field, fwidth, 0);
- putchar ('\n');
}
}
diff --git a/utils/w.c b/utils/w.c
index 0b31385e..37555088 100644
--- a/utils/w.c
+++ b/utils/w.c
@@ -1,8 +1,8 @@
/* Hurdish w
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2001,02 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include <paths.h>
#include <ctype.h>
@@ -29,6 +30,7 @@
#include <pwd.h>
#include <grp.h>
#include <netdb.h>
+#include <version.h>
#include <sys/fcntl.h>
@@ -42,13 +44,13 @@
#include "psout.h"
-#define DEFAULT_FMT_STRING "%^%user %tty %from %login %idle %what"
+#define DEFAULT_FMT_STRING "%^%user %tty %from %login %idle %pid %what"
extern char *canon_host (char *host);
extern char *shared_domain (char *host1, char *host2);
extern char *localhost ();
-char *argp_program_version = "w 1.0 (GNU " HURD_RELEASE ")";
+const char *argp_program_version = STANDARD_HURD_VERSION (w);
#define OA OPTION_ARG_OPTIONAL
@@ -71,7 +73,7 @@ static struct argp_option options[] =
{0, 0}
};
static char *args_doc = "[USER...]";
-static char *doc = 0;
+static char *doc = "Show logged in users and what they are doing";
/* The current time of day. */
static struct timeval now;
@@ -93,6 +95,14 @@ struct w_hook
#define W_PSTAT_LOGIN (PSTAT_USER_BASE << 3)
static ps_flags_t
+w_deps (ps_flags_t flags)
+{
+ if (flags & W_PSTAT_IDLE)
+ flags |= PSTAT_TTY;
+ return flags;
+}
+
+static ps_flags_t
w_fetch (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
{
struct w_hook *hook = ps->hook;
@@ -121,23 +131,34 @@ w_fetch (struct proc_stat *ps, ps_flags_t need, ps_flags_t have)
if (sd)
*sd = '\0';
}
-
- have |= W_PSTAT_HOST;
}
+ have |= W_PSTAT_HOST;
}
if (need & W_PSTAT_IDLE)
{
- struct stat stat;
- struct ps_tty *tty = ps->tty;
-
- hook->idle.tv_usec = 0;
- if (io_stat (tty->port, &stat) == 0)
+ if (have & PSTAT_TTY)
{
- hook->idle.tv_sec = now.tv_sec - stat.st_mtime;
- if (hook->idle.tv_sec > 0)
- have |= W_PSTAT_IDLE;
+ struct stat stat;
+ struct ps_tty *tty = ps->tty;
+
+ hook->idle.tv_usec = 0;
+ if (! tty)
+ {
+ hook->idle.tv_sec = 0;
+ have |= W_PSTAT_IDLE;
+ }
+ else
+ {
+ if (io_stat (tty->port, &stat) == 0)
+ {
+ hook->idle.tv_sec = now.tv_sec - stat.st_atime;
+ have |= W_PSTAT_IDLE;
+ }
+ }
}
+ else if (ps->inapp & PSTAT_TTY)
+ ps->inapp |= W_PSTAT_IDLE;
}
if (need & W_PSTAT_USER)
@@ -204,21 +225,22 @@ w_get_host (struct proc_stat *ps, char **host, unsigned *host_len)
{
struct w_hook *hook = ps->hook;
*host = hook->host;
- *host_len = strlen (*host);
+ *host_len = *host ? strlen (*host) : 0;
}
const struct ps_getter w_host_getter =
{"host", W_PSTAT_HOST, w_get_host};
extern error_t ps_emit_past_time (), ps_emit_string (), ps_emit_minutes ();
extern error_t ps_emit_user_name ();
-extern int ps_cmp_times (), ps_cmp_strings ();
+extern int ps_cmp_times (), ps_cmp_strings (), ps_cmp_unames ();
+extern int ps_nominal_string ();
const struct ps_fmt_spec _w_specs[] =
{
{"User", 0, 8, -1,0, &w_uname_getter,ps_emit_string, ps_cmp_strings},
- {"Name", 0, 20, -1,0, &w_user_getter, ps_emit_user_name,ps_cmp_strings},
+ {"Name", 0, 16, -1,0, &w_user_getter, ps_emit_user_name,ps_cmp_unames,ps_nominal_string},
{"Login","Login@", -7, -1,0,&w_login_getter,ps_emit_past_time,ps_cmp_times},
- {"From", 0, 16, -1,0, &w_host_getter, ps_emit_string, ps_cmp_strings},
- {"Idle", 0, -5, -1,0, &w_idle_getter, ps_emit_minutes,ps_cmp_times},
+ {"From", 0, 14, -1,0, &w_host_getter, ps_emit_string, ps_cmp_strings, ps_nominal_string},
+ {"Idle", 0, -5, -1,PS_FMT_FIELD_COLON_MOD, &w_idle_getter, ps_emit_minutes,ps_cmp_times},
{"What=args"},
{0}
};
@@ -231,7 +253,7 @@ static void
add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
{
/* The tty name, with space for '\0' termination and an
- appropiate prefix. */
+ appropriate prefix. */
char tty[sizeof _PATH_DEV + sizeof u->ut_line];
io_t tty_node;
error_t err;
@@ -239,6 +261,19 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
int pos;
struct proc_stat *ps;
+ switch (u->ut_type)
+ {
+ case LOGIN_PROCESS:
+ case USER_PROCESS:
+ /* These are the types that indicate a user job that we might
+ find processes for. */
+ if (u->ut_name[0] != '\0' && u->ut_line[0] != '\0')
+ break;
+ default:
+ /* This entry is not for a user, skip it. */
+ return;
+ }
+
strncpy (tty, u->ut_line, sizeof u->ut_line);
tty[sizeof u->ut_line] = '\0'; /* Ensure it's '\0' terminated. */
@@ -271,7 +306,7 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
else
{
struct proc_stat **pgrp_procs;
- unsigned num_procs;
+ size_t num_procs;
err = proc_stat_list_add_pgrp (procs, -pid, &pgrp_procs, &num_procs);
if (! err)
@@ -301,62 +336,74 @@ add_utmp_procs (struct proc_stat_list *procs, struct utmp *u)
tty, pid < 0 ? "pgrp" : "pid", pid < 0 ? -pid : pid);
}
-/* Read into PROCS from the utmp file called NAME. */
-static void
-read_utmp_procs (struct proc_stat_list *procs, char *name)
+/* Find the absolute timestamp of when the system was booted.
+ We define "system boot time" as the task creation time of PID 1 (init). */
+
+static error_t
+fetch_boot_time (struct timeval *when)
{
- int rd, fd;
- struct utmp buf[64];
+ struct ps_context *context;
+ struct proc_stat *ps;
+ error_t err;
- fd = open (name, O_RDONLY);
- if (fd < 0)
- error (9, errno, "%s", name);
+ err = ps_context_create (getproc (), &context);
+ if (err)
+ error (2, err, "ps_context_create");
+
+ err = ps_context_find_proc_stat (context, 1, &ps);
+ if (err)
+ error (3, err, "ps_context_find_proc_stat");
- while ((rd = read (fd, buf, sizeof (buf))) > 0)
+ err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC);
+ if (!err && !(ps->flags & PSTAT_TASK_BASIC))
+ err = EGRATUITOUS;
+ if (err)
{
- struct utmp *u = buf;
- while (rd >= sizeof (*u))
- {
- if (*u->ut_name && *u->ut_line)
- /* An active entry. */
- add_utmp_procs (procs, u);
- rd -= sizeof (*u);
- u++;
- }
+ error (0, err, "cannot find boot time");
+ return err;
+ }
+ else
+ {
+ time_value_t *const tv = &proc_stat_task_basic_info (ps)->creation_time;
+ when->tv_sec = tv->seconds;
+ when->tv_usec = tv->microseconds;
}
- close (fd);
+ ps_context_free (context);
+
+ return 0;
}
-
+
static void
uptime (struct proc_stat_list *procs)
{
- struct stat st;
+ error_t err;
+ struct timeval boot_time;
char uptime_rep[20], tod_rep[20];
struct host_load_info *load;
unsigned nusers = 0;
- int maybe_add_user (struct proc_stat *ps) { if (ps->hook) nusers++; return 0; }
+ int maybe_add_user (struct proc_stat *ps)
+ { if (ps->hook) nusers++; return 0; }
proc_stat_list_for_each (procs, maybe_add_user);
- /* Until we get a better way of finding out how long the system's been
- up... XXX */
- if (stat ("/var/run/uptime", &st) != 0)
+ if (fetch_boot_time (&boot_time))
strcpy (uptime_rep, "chuck");
else
{
- struct timeval uptime = { now.tv_sec - st.st_ctime, 0 };
+ struct timeval uptime;
+ timersub (&now, &boot_time, &uptime);
fmt_named_interval (&uptime, 0, uptime_rep, sizeof (uptime_rep));
}
- strftime (tod_rep, sizeof (tod_rep), "%r",
+ strftime (tod_rep, sizeof (tod_rep), "%r",
localtime ((time_t *)&now.tv_sec));
if (tod_rep[0] == '0')
tod_rep[0] = ' '; /* Get rid of bletcherous leading 0. */
- errno = ps_host_load_info (&load);
- if (errno)
- error (0, errno, "ps_host_load_info");
+ err = ps_host_load_info (&load);
+ if (err)
+ error (0, err, "ps_host_load_info");
printf ("%s up %s, %u user%s, load averages: %.2f, %.2f, %.2f\n",
tod_rep, uptime_rep, nusers, nusers == 1 ? "" : "s",
@@ -365,10 +412,11 @@ uptime (struct proc_stat_list *procs)
(double)load->avenrun[2] / (double)LOAD_SCALE);
}
-void
+int
main(int argc, char *argv[])
{
error_t err;
+ struct utmp *ut;
struct ps_context *context;
int output_width = -1;
char *fmt_string = DEFAULT_FMT_STRING, *sort_key_name = NULL;
@@ -378,12 +426,23 @@ main(int argc, char *argv[])
#if 0
char *tty_names = 0;
unsigned num_tty_names = 0;
- struct idvec *only_uids = make_idvec (), *not_uids = make_idvec ();
#endif
- struct ps_user_hooks ps_hooks = { 0, w_fetch, w_cleanup };
+ uid_t *users = 0;
+ size_t num_users = 0;
+ struct ps_user_hooks ps_hooks = { w_deps, w_fetch, w_cleanup };
int has_hook (struct proc_stat *ps) { return ps->hook != 0; }
+ int keep_users (struct proc_stat *ps)
+ {
+ int i;
+ struct w_hook *h = ps->hook;
+ for (i = 0; i < num_users; i++)
+ if (users[i] == h->user->uid)
+ return 1;
+ return 0;
+ }
+
/* Parse our options... */
error_t parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -400,6 +459,19 @@ main(int argc, char *argv[])
case 'w': output_width = arg ? atoi (arg) : 0; break;
case ARGP_KEY_ARG:
+ num_users++;
+ users = realloc (users, num_users * sizeof (*users));
+ if (! users)
+ argp_failure (state, 5, ENOMEM, "%s", arg);
+ else if (isdigit (*arg))
+ users[num_users - 1] = atoi (arg);
+ else
+ {
+ struct passwd *pw = getpwnam (arg);
+ if (! pw)
+ argp_failure (state, 6, 0, "%s: Unknown user", arg);
+ users[num_users - 1] = pw->pw_uid;
+ }
break;
default:
@@ -424,18 +496,25 @@ main(int argc, char *argv[])
/* Parse our options. */
argp_parse (&argp, argc, argv, 0, 0, 0);
- read_utmp_procs (procs, _PATH_UTMP);
+ /* Read the utmp file. */
+ setutent ();
+ while ((ut = getutent ()) != NULL)
+ add_utmp_procs (procs, ut);
+ endutent ();
/* Keep only processes that have our hooks attached. */
proc_stat_list_filter1 (procs, has_hook, 0, 0);
+ if (num_users > 0)
+ proc_stat_list_filter1 (procs, keep_users, W_PSTAT_USER, 0);
+
if (show_uptime)
uptime (procs);
if (show_entries)
psout (procs, fmt_string, 0, &w_specs, sort_key_name, sort_reverse,
output_width, print_heading,
- squash_bogus_fields, squash_nominal_fields);
+ squash_bogus_fields, squash_nominal_fields, 0);
- exit(0);
+ return 0;
}
diff --git a/utils/x.c b/utils/x.c
index 0e4f7e02..e4e272f4 100644
--- a/utils/x.c
+++ b/utils/x.c
@@ -55,8 +55,8 @@ static struct argp_option options[] =
{0, 0}
};
static char *args_doc = "[USER...]";
-static char *doc =
- "A USER specified as an argument adds (or removes) that user's groups as"
+static char *doc = "Modify authentication of existing processes"
+ "\vA USER specified as an argument adds (or removes) that user's groups as"
" well. When removing groups implied by such an argument, the groups to"
" which uids remaining in the process after any we remove are ignored."
"\nUids and groups specified with options are used as-is.";
diff --git a/version.h.in b/version.h.in
new file mode 100644
index 00000000..80e75b52
--- /dev/null
+++ b/version.h.in
@@ -0,0 +1,29 @@
+/* Hurd version
+ Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef HURD_VERSION
+#define HURD_VERSION MASTER_HURD_VERSION
+#endif
+
+/* The standard way to print versions for --version. */
+#define STANDARD_HURD_VERSION(s) \
+ #s " (GNU Hurd) " HURD_VERSION
+#define STANDARD_HURD_VERSION_EXTRA(s, extra) \
+ #s " (GNU Hurd; " extra ") " HURD_VERSION